From f8b2547e0e2ba8360e5c121de433a9fb021cee5c Mon Sep 17 00:00:00 2001 From: Marno van der Maas Date: Fri, 22 Mar 2024 16:04:40 +0000 Subject: [PATCH] Update lowrisc_ibex to lowrisc/cheriot-ibex@8474cf81 Update code from upstream repository https://github.com/lowrisc/cheriot-ibex.git to revision 8474cf81d0f06fd727d8e66bc356fa18822bbf8d Signed-off-by: Marno van der Maas --- vendor/lowrisc_ibex.lock.hjson | 2 +- vendor/lowrisc_ibex/README.md | 2 +- .../lowrisc_ibex/dv/cheriot/tb/cap_err_gen.sv | 2 +- .../dv/cheriot/tb/cheriot_dv_pkg.sv | 34 + .../dv/cheriot/tb/core_ibex_fcov_if.sv | 44 +- .../dv/cheriot/tb/data_mem_model.sv | 67 +- vendor/lowrisc_ibex/dv/cheriot/tb/dii_if.sv | 4 +- .../dv/cheriot/tb/instr_mem_model.sv | 14 +- vendor/lowrisc_ibex/dv/cheriot/tb/intr_gen.sv | 11 +- .../lowrisc_ibex/dv/cheriot/tb/mem_monitor.sv | 596 ++++++++++++++++++ .../lowrisc_ibex/dv/cheriot/tb/mem_obi_if.sv | 78 ++- .../dv/cheriot/tb/module_dv_ext.sv | 181 +++++- .../dv/cheriot/tb/tb_cheriot_top.sv | 175 ++++- vendor/lowrisc_ibex/dv/cheriot/tb/tb_env.sv | 49 +- .../lowrisc_ibex/dv/cheriot/tb/tbre_bg_gen.sv | 245 +++++++ vendor/lowrisc_ibex/rtl/cheri_decoder.sv | 1 + vendor/lowrisc_ibex/rtl/cheri_ex.sv | 61 +- vendor/lowrisc_ibex/rtl/cheri_pkg.sv | 19 +- vendor/lowrisc_ibex/rtl/cheri_regfile.sv | 11 +- vendor/lowrisc_ibex/rtl/cheri_stkz.sv | 8 +- vendor/lowrisc_ibex/rtl/cheri_tbre.sv | 2 +- vendor/lowrisc_ibex/rtl/ibex_controller.sv | 13 +- vendor/lowrisc_ibex/rtl/ibex_core.sv | 5 +- vendor/lowrisc_ibex/rtl/ibex_cs_registers.sv | 3 - vendor/lowrisc_ibex/rtl/ibex_id_stage.sv | 7 +- .../lowrisc_ibex/rtl/ibex_load_store_unit.sv | 2 +- vendor/lowrisc_ibex/rtl/ibex_top.sv | 2 +- vendor/lowrisc_ibex/rtl/ibex_tracer.sv | 2 +- vendor/lowrisc_ibex/rtl/ibex_tracer_pkg.sv | 1 + 29 files changed, 1456 insertions(+), 185 deletions(-) create mode 100644 vendor/lowrisc_ibex/dv/cheriot/tb/cheriot_dv_pkg.sv create mode 100644 vendor/lowrisc_ibex/dv/cheriot/tb/mem_monitor.sv create mode 100644 vendor/lowrisc_ibex/dv/cheriot/tb/tbre_bg_gen.sv diff --git a/vendor/lowrisc_ibex.lock.hjson b/vendor/lowrisc_ibex.lock.hjson index da3a47b53..41eb1ad2c 100644 --- a/vendor/lowrisc_ibex.lock.hjson +++ b/vendor/lowrisc_ibex.lock.hjson @@ -9,6 +9,6 @@ upstream: { url: https://github.com/lowrisc/cheriot-ibex.git - rev: 22327690d525cc59baf56d32b4856307664039cb + rev: 8474cf81d0f06fd727d8e66bc356fa18822bbf8d } } diff --git a/vendor/lowrisc_ibex/README.md b/vendor/lowrisc_ibex/README.md index 52f016a9a..a85f0faf2 100644 --- a/vendor/lowrisc_ibex/README.md +++ b/vendor/lowrisc_ibex/README.md @@ -88,7 +88,7 @@ Note that the main CPU pipeline, TBRE and STKZ all use the load-store unit to ac ## Backward compatibility -cheriot-ibex provides a backward-compatibility mode which is enabled by setting the input cheri_pmode_i = 1. In this mode, all CheirIoT features are disabled. The cheriot-ibex core is logically equivalent to the non-CHERIoT ibex core and runs unmodified RV32IMC binaries. +cheriot-ibex provides a backward-compatibility mode which is enabled by setting the input cheri_pmode_i = 0. In this mode, all CHERIoT features are disabled. The cheriot-ibex core is logically equivalent to the non-CHERIoT ibex core and runs unmodified RV32IMC binaries. ## Design configuration parameters diff --git a/vendor/lowrisc_ibex/dv/cheriot/tb/cap_err_gen.sv b/vendor/lowrisc_ibex/dv/cheriot/tb/cap_err_gen.sv index b5eafad06..c162df79b 100644 --- a/vendor/lowrisc_ibex/dv/cheriot/tb/cap_err_gen.sv +++ b/vendor/lowrisc_ibex/dv/cheriot/tb/cap_err_gen.sv @@ -140,7 +140,7 @@ module cap_err_gen import ibex_pkg::*; import cheri_pkg::*; ( assign is_rv32_lsu = dut.u_ibex_top.u_ibex_core.g_cheri_ex.u_cheri_ex.rv32_lsu_req_i; assign is_cheri_lsu = cheri_exec_id & (cheri_operator[CLOAD_CAP] | cheri_operator[CSTORE_CAP]); - assign pc_in_isr = (pc_id >= 32'h8000_0000) & (pc_id < 32'h8000_0200); + assign pc_in_isr = dut.u_ibex_top.u_ibex_core.id_stage_i.controller_i.controller_dv_ext_i.cpu_in_isr; assign err_failed = err_active & dut.u_ibex_top.u_ibex_core.g_cheri_ex.u_cheri_ex.lsu_req_o & (~dut.u_ibex_top.u_ibex_core.g_cheri_ex.u_cheri_ex.lsu_cheri_err_o) & diff --git a/vendor/lowrisc_ibex/dv/cheriot/tb/cheriot_dv_pkg.sv b/vendor/lowrisc_ibex/dv/cheriot/tb/cheriot_dv_pkg.sv new file mode 100644 index 000000000..de876b2cc --- /dev/null +++ b/vendor/lowrisc_ibex/dv/cheriot/tb/cheriot_dv_pkg.sv @@ -0,0 +1,34 @@ +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +package cheriot_dv_pkg; + import cheri_pkg::*; + + parameter logic [31:0] DRAMStartAddr = 32'h8000_0000; + parameter logic [31:0] TsMapStartAddr = 32'h8300_0000; + + typedef struct packed { + logic [7:0] flag; + logic is_cap; + logic we; + logic [3:0] be; + logic [29:0] addr32; + logic [32:0] wdata; + logic [32:0] rdata; + logic err; + } mem_cmd_t; + + typedef struct packed { + logic is_cap; + logic we; + logic [1:0] rv32_type; + logic [31:0] addr; + reg_cap_t wcap; + logic [31:0] wdata; + reg_cap_t rcap; + logic [31:0] rdata; + logic err; + } lsu_cmd_t; + +endpackage diff --git a/vendor/lowrisc_ibex/dv/cheriot/tb/core_ibex_fcov_if.sv b/vendor/lowrisc_ibex/dv/cheriot/tb/core_ibex_fcov_if.sv index a7baafa0a..cd195760e 100644 --- a/vendor/lowrisc_ibex/dv/cheriot/tb/core_ibex_fcov_if.sv +++ b/vendor/lowrisc_ibex/dv/cheriot/tb/core_ibex_fcov_if.sv @@ -695,27 +695,26 @@ interface core_ibex_fcov_if import ibex_pkg::*; import cheri_pkg::*; ( // New coverage points // - // ignore_bins ignore = {[16:31]}; // RV32E/CHERIoT, 16 regs only - cp_rs1_addr: coverpoint id_stage_i.rf_raddr_a_o[3:0] iff (id_stage_i.rf_ren_a) { - bins bin0 = {0}; - bins bin1to7 = {[1:7]}; - bins bin8to14 = {[8:14]}; - bins bin15 = {15}; + cp_rs1_addr: coverpoint id_stage_i.rf_raddr_a_o[4:0] iff (id_stage_i.rf_ren_a) { + bins bin0 = {0}; + bins bin1to14 = {[1:14]}; + bins bin15 = {15}; + bins bin16to31 = {[16:31]}; // for CHERIoT negative case } - cp_rs2_addr: coverpoint id_stage_i.rf_raddr_b_o[3:0] iff (id_stage_i.rf_ren_b) { - bins bin0 = {0}; - bins bin1to7 = {[1:7]}; - bins bin8to14 = {[8:14]}; - bins bin15 = {15}; + cp_rs2_addr: coverpoint id_stage_i.rf_raddr_b_o[4:0] iff (id_stage_i.rf_ren_b) { + bins bin0 = {0}; + bins bin1to14 = {[1:14]}; + bins bin15 = {15}; + bins bin16to31 = {[16:31]}; // for CHERIoT negative case } - cp_rd_addr: coverpoint id_stage_i.rf_waddr_id_o[3:0] iff + cp_rd_addr: coverpoint id_stage_i.rf_waddr_id_o[4:0] iff (id_stage_i.rf_we_id_o | g_cheri_ex.u_cheri_ex.cheri_rf_we_o) { - bins bin0 = {0}; - bins bin1to7 = {[1:7]}; - bins bin8to14 = {[8:14]}; - bins bin15 = {15}; + bins bin0 = {0}; + bins bin1to14 = {[1:14]}; + bins bin15 = {15}; + bins bin16to31 = {[16:31]}; // for CHERIoT negative case } // all CHERIoT instructions enumerated @@ -763,7 +762,7 @@ interface core_ibex_fcov_if import ibex_pkg::*; import cheri_pkg::*; ( // bins bin2 = {4'b0011}; // base_cor = 0, top_cor = -1, impossible case bins bin3 = {4'b1100}; // bins bin4 = {4'b1101}; // impossible case - // bins bin5 = {4'b1111}; // impossible case + bins bin5 = {4'b1111}; illegal_bins illegal = default; } @@ -822,7 +821,7 @@ interface core_ibex_fcov_if import ibex_pkg::*; import cheri_pkg::*; ( // bins bin2 = {4'b0011}; bins bin3 = {4'b1100}; // bins bin4 = {4'b1101}; - // bins bin5 = {4'b1111}; + bins bin5 = {4'b1111}; illegal_bins illegal = default; } @@ -942,7 +941,9 @@ interface core_ibex_fcov_if import ibex_pkg::*; import cheri_pkg::*; ( cp_trvk_cond: coverpoint {g_trvk_stage.cheri_trvk_stage_i.trvk_status, g_trvk_stage.cheri_trvk_stage_i.cap_good_q[2], g_trvk_stage.cheri_trvk_stage_i.range_ok_q[2]} iff - (g_trvk_stage.cheri_trvk_stage_i.rf_trvk_en_o); + (g_trvk_stage.cheri_trvk_stage_i.rf_trvk_en_o) { + wildcard ignore_bins ignore = {3'b?0?}; // if cap is not good, revocaton status/rang_ok are don't cares + } cp_trvk_stall: coverpoint id_stage_i.stall_cheri_trvk; @@ -990,6 +991,8 @@ interface core_ibex_fcov_if import ibex_pkg::*; import cheri_pkg::*; ( cheri_tbre_wrapper_i.g_tbre.cheri_tbre_i.tbre_lsu_req_o, cheri_tbre_wrapper_i.g_stkz.cheri_stkz_i.stkz_lsu_req_o}; + cp_tbrewrp_blk1_cancel: coverpoint cheri_tbre_wrapper_i.tbre_wrapper_dv_ext_i.fcov_blk1_cancel; + cp_stkz_sm: coverpoint cheri_tbre_wrapper_i.g_stkz.cheri_stkz_i.stkz_fsm_q { bins good[] = {[0:2]}; illegal_bins bad = default; @@ -1092,7 +1095,8 @@ interface core_ibex_fcov_if import ibex_pkg::*; import cheri_pkg::*; ( // exception_stall_instr_cross: cross cp_ls_pmp_exception, cp_ls_error_exception, cp_ls_cheri_exception, exception_stall_instr_cross: cross cp_ls_exception, - cp_id_instr_category, cp_stall_type_id, instr_unstalled, cp_irq_pending, cp_debug_req { + // cp_id_instr_category, cp_stall_type_id, instr_unstalled, cp_irq_pending, cp_debug_req { // QQQ add cp_debug_req back later + cp_id_instr_category, cp_stall_type_id, instr_unstalled, cp_irq_pending { illegal_bins illegal = // Only Div, Mul, Branch and Jump instructions can see an instruction stall (!binsof(cp_id_instr_category) intersect {InstrCategoryDiv, InstrCategoryMul, diff --git a/vendor/lowrisc_ibex/dv/cheriot/tb/data_mem_model.sv b/vendor/lowrisc_ibex/dv/cheriot/tb/data_mem_model.sv index 41956ad54..81501eafb 100644 --- a/vendor/lowrisc_ibex/dv/cheriot/tb/data_mem_model.sv +++ b/vendor/lowrisc_ibex/dv/cheriot/tb/data_mem_model.sv @@ -5,7 +5,7 @@ // // data interface/memory model // -module data_mem_model ( +module data_mem_model import cheriot_dv_pkg::*; ( input logic clk, input logic rst_n, @@ -14,17 +14,21 @@ module data_mem_model ( input logic [3:0] RESP_WMAX, input logic err_enable, + input logic ignore_stkz, input logic data_req, input logic data_we, input logic [3:0] data_be, + input logic data_is_cap, input logic [31:0] data_addr, input logic [32:0] data_wdata, + input logic [7:0] data_flag, output logic data_gnt, output logic data_rvalid, output logic [32:0] data_rdata, output logic data_err, + output mem_cmd_t data_resp_info, input logic tsmap_cs, input logic [15:0] tsmap_addr, @@ -34,7 +38,8 @@ module data_mem_model ( input logic [63:0] mmreg_coreout, output logic [3:0] err_enable_vec, - output logic [2:0] intr_ack + output logic [2:0] intr_ack, + output logic uart_stop_sim ); localparam int unsigned DRAM_AW = 16; @@ -71,51 +76,45 @@ module data_mem_model ( logic mmreg_sel, mmreg_cs; logic [7:0] mmreg_addr32; - logic data_req_isr; - logic mem_req_isr; + logic [7:0] mem_flag; mem_obi_if #( .DW (33) ) u_mem_obj_if ( - .clk (clk), - .rst_n (rst_n), + .clk_i (clk), + .rst_ni (rst_n), .GNT_WMAX (GNT_WMAX), .RESP_WMAX (RESP_WMAX), .data_req (data_req), - .data_req_isr (data_req_isr), .data_we (data_we), .data_be (data_be), + .data_is_cap (data_is_cap), .data_addr (data_addr), .data_wdata (data_wdata), + .data_flag (data_flag), .data_gnt (data_gnt), .data_rvalid (data_rvalid), .data_rdata (data_rdata), .data_err (data_err), + .data_resp_info (data_resp_info), .mem_cs (mem_cs), .mem_we (mem_we), .mem_be (mem_be), - .mem_req_isr (mem_req_isr), + .mem_flag (mem_flag), .mem_addr32 (mem_addr32), .mem_wdata (mem_wdata), .mem_rdata (mem_rdata), .mem_err (mem_err) ); - // - // Tracking CPU execution of startup/exception handler and - // suppress error injection during the phase - // - - assign data_req_isr = dut.u_ibex_top.u_ibex_core.id_stage_i.instr_executing & - dut.u_ibex_top.u_ibex_core.load_store_unit_i.lsu_req_i & - ~dut.u_ibex_top.u_ibex_core.load_store_unit_i.cur_req_is_tbre & - (dut.u_ibex_top.u_ibex_core.id_stage_i.pc_id_i >= 32'h8000_0000) & - (dut.u_ibex_top.u_ibex_core.id_stage_i.pc_id_i < 32'h8000_0200); // // memory signals (sampled @posedge clk) // logic dram_sel_q, tsram_p0_sel_q, mmreg_sel_q; + logic mem_req_isr, mem_req_stkz; + assign mem_req_stkz = mem_flag[2]; + assign mem_req_isr = mem_flag[0]; assign mem_rdata = dram_sel_q ? dram_rdata : (tsram_p0_sel_q ? {1'b0, tsram_p0_rdata} : (mmreg_sel_q ? {1'b0, mmreg_rdata} : 33'h0)); // mem_err is in themem_cs @@ -125,9 +124,12 @@ module data_mem_model ( // DRAM (data RAM) // starting at 0x8000_0000 // + // don't generate memory access if + // - responds with an error, or + // - accesses from stkz is supposed to be ignored. assign dram_addr32 = mem_addr32[DRAM_AW-1:0]; assign dram_sel = mem_cs & mem_addr32[29] & (mem_addr32[28:DRAM_AW+2] == 0); - assign dram_cs = dram_sel & ~mem_err; + assign dram_cs = dram_sel & ~mem_err & (~mem_req_stkz | ~ignore_stkz); always @(posedge clk, negedge rst_n) begin if (~rst_n) begin @@ -169,8 +171,10 @@ module data_mem_model ( if (~rst_n) begin dram_err_schd <= 1'b0; end else begin - if (dram_sel) - dram_err_schd <= err_enable & ((ERR_RATE == 0) ? 1'b0 : ($urandom()%(2**(8-ERR_RATE))==0)); + if (~err_enable) + dram_err_schd <= 1'b0; + else if (dram_sel) + dram_err_schd <= (ERR_RATE == 0) ? 1'b0 : ($urandom()%(2**(8-ERR_RATE))==0); end end // @@ -214,8 +218,10 @@ module data_mem_model ( if (~rst_n) begin tsram_p0_err_schd <= 1'b0; end else begin - if (tsram_p0_sel) - tsram_p0_err_schd <= err_enable & ((ERR_RATE == 0) ? 1'b0 : ($urandom()%(2**(8-ERR_RATE))==0)); + if (~err_enable) + tsram_p0_err_schd <= 1'b0; + else if (tsram_p0_sel) + tsram_p0_err_schd <= (ERR_RATE == 0) ? 1'b0 : ($urandom()%(2**(8-ERR_RATE))==0); end end @@ -310,4 +316,19 @@ module data_mem_model ( end end + // UART printout + initial begin + uart_stop_sim = 1'b0; + @(posedge rst_n); + + while (1) begin + @(posedge clk); + if (mmreg_cs && mem_we && (mmreg_addr32 == 'h80)) // 0x8380_0200 + if (mem_wdata[7]) + uart_stop_sim = 1'b1; + else + $write("%c", mem_wdata[7:0]); + end + end + endmodule diff --git a/vendor/lowrisc_ibex/dv/cheriot/tb/dii_if.sv b/vendor/lowrisc_ibex/dv/cheriot/tb/dii_if.sv index 826343284..337282131 100644 --- a/vendor/lowrisc_ibex/dv/cheriot/tb/dii_if.sv +++ b/vendor/lowrisc_ibex/dv/cheriot/tb/dii_if.sv @@ -11,7 +11,7 @@ module dii_if ( input logic clk_i, - input logic rstn_i, + input logic rst_ni, // DII generator interface input logic [31:0] dii_insn_0_i, @@ -65,7 +65,7 @@ module dii_if ( int flush_cnt; logic flush_active; - @(posedge rstn_i); + @(posedge rst_ni); hqueue = {}; while (1) begin diff --git a/vendor/lowrisc_ibex/dv/cheriot/tb/instr_mem_model.sv b/vendor/lowrisc_ibex/dv/cheriot/tb/instr_mem_model.sv index a9018912c..d13302f52 100644 --- a/vendor/lowrisc_ibex/dv/cheriot/tb/instr_mem_model.sv +++ b/vendor/lowrisc_ibex/dv/cheriot/tb/instr_mem_model.sv @@ -39,22 +39,26 @@ module instr_mem_model ( mem_obi_if #( .DW (32) ) u_mem_obj_if ( - .clk (clk), - .rst_n (rst_n), + .clk_i (clk), + .rst_ni (rst_n), .GNT_WMAX (GNT_WMAX), .RESP_WMAX (RESP_WMAX), .data_req (instr_req), .data_we (1'b0), .data_be (4'hf), + .data_is_cap (1'b0), .data_addr (instr_addr), .data_wdata (32'h0), + .data_flag (8'h0), .data_gnt (instr_gnt), .data_rvalid (instr_rvalid), .data_rdata (instr_rdata), .data_err (instr_err), + .data_resp_info (), .mem_cs (mem_cs), .mem_we (), .mem_be (), + .mem_flag (), .mem_addr32 (mem_addr32), .mem_wdata (), .mem_rdata (mem_rdata), @@ -83,8 +87,10 @@ module instr_mem_model ( if (~rst_n) begin iram_err_q <= 1'b0; end else begin - if (mem_cs) - iram_err_q <= err_enable & ((ERR_RATE == 0) ? 1'b0 : ($urandom()%(2**(8-ERR_RATE))==0)); + if (~err_enable) + iram_err_q <= 1'b0; + else if (mem_cs) + iram_err_q <= (ERR_RATE == 0) ? 1'b0 : ($urandom()%(2**(8-ERR_RATE))==0); end end diff --git a/vendor/lowrisc_ibex/dv/cheriot/tb/intr_gen.sv b/vendor/lowrisc_ibex/dv/cheriot/tb/intr_gen.sv index ba3730410..272b6a39e 100644 --- a/vendor/lowrisc_ibex/dv/cheriot/tb/intr_gen.sv +++ b/vendor/lowrisc_ibex/dv/cheriot/tb/intr_gen.sv @@ -18,7 +18,8 @@ module intr_gen ( logic [2:0] irq; - assign irq_o = intr_en & irq; // hard gate irq output (otherwise nwait cause delay) + //assign irq_o = intr_en & irq; // hard gate irq output (otherwise nwait cause delay) + assign irq_o = irq; initial begin int nwait; @@ -35,9 +36,11 @@ module intr_gen ( if (intr_en && (INTR_INTVL != 0)) begin nwait = ((rand32 % (2** INTR_INTVL)) + 1) * 10; // wait at least 10 clk cycles repeat (nwait) @(posedge clk); - // irq = rand32[15:0] % 7 + 1; // new interrupt - irq = {2'b00, rand32[0]}; // just do irq_external now. irq_timer causes trouble in sail - //$display ("going irq=1 @%t", $time); + if (intr_en) begin // test intr_en again + // irq = rand32[15:0] % 7 + 1; // new interrupt + irq = {2'b00, rand32[0]}; // just do irq_external now. irq_timer causes trouble in sail + //$display ("going irq=1 @%t", $time); + end end else begin @(posedge clk); end diff --git a/vendor/lowrisc_ibex/dv/cheriot/tb/mem_monitor.sv b/vendor/lowrisc_ibex/dv/cheriot/tb/mem_monitor.sv new file mode 100644 index 000000000..06731fe07 --- /dev/null +++ b/vendor/lowrisc_ibex/dv/cheriot/tb/mem_monitor.sv @@ -0,0 +1,596 @@ +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +`include "dv_fcov_macros.svh" + + +//-------------------------------------------------------------------- +// Memory monitor core +// End-to-end monitoring of data memory transactions +//-------------------------------------------------------------------- +module mem_monitor import cheri_pkg::*; import cheriot_dv_pkg::*; # ( + parameter int unsigned srcID = 0 + ) ( + input logic clk_i, + input logic rst_ni, + + input logic src_lsu_req_valid, + input lsu_cmd_t src_lsu_req, + input logic src_lsu_resp_valid, + input lsu_cmd_t src_lsu_resp, + + // monitor CPU data interface + input logic data_req, + input logic data_we, + input logic [3:0] data_be, + input logic data_is_cap, + input logic [31:0] data_addr, + input logic [32:0] data_wdata, + + input logic data_gnt, + input logic data_rvalid, + input logic [32:0] data_rdata, + input logic data_err, + input mem_cmd_t data_resp_info, + + input logic end_sim_req +); + + // + // Function to convert from LSU commands to actual memory transaction (modeling LSU) + // + typedef struct { + logic[1:0] valid; + mem_cmd_t cmd0; + mem_cmd_t cmd1; + } mem_2cmd_t; + + function automatic mem_2cmd_t lsu2mem_cmd (lsu_cmd_t lsu_cmd); + mem_2cmd_t result; + result.valid = 2'b00; + + if (lsu_cmd.is_cap) begin + result.valid = 2'b11; + + result.cmd0.flag = 8'h0; + result.cmd0.is_cap = 1'b1; + result.cmd0.we = lsu_cmd.we; + result.cmd0.be = 4'hf; + result.cmd0.addr32 = lsu_cmd.addr[31:2] - {31'h0, 1'b1}; // we capture at lsu_req_done (after addr_incr) + result.cmd0.wdata = {lsu_cmd.wcap.valid, lsu_cmd.wdata}; + result.cmd1.flag = 8'h0; + result.cmd1.is_cap = 1'b1; + result.cmd1.we = lsu_cmd.we; + result.cmd1.be = 4'hf; + result.cmd1.addr32 = lsu_cmd.addr[31:2]; + result.cmd1.wdata = reg2memcap_fmt0(lsu_cmd.wcap); // QQQ add fmt1 support later + + end else if (lsu_cmd.rv32_type == 2'b00) begin // full word + logic [63:0] tmp64; + logic [7:0] tmp8; + logic unaligned; + + unaligned = (lsu_cmd.addr[1:0] != 0); + result.valid = unaligned ? 2'b11 : 2'b01; + tmp64 = {lsu_cmd.wdata, lsu_cmd.wdata} << {lsu_cmd.addr[1:0], 3'b000}; + tmp8 = 8'h0f << {lsu_cmd.addr[1:0]}; + + result.cmd0.flag = 8'h0; + result.cmd0.is_cap = 1'b0; + result.cmd0.we = lsu_cmd.we; + result.cmd0.be = tmp8[3:0]; + result.cmd0.addr32 = lsu_cmd.addr[31:2] - {31'h0, unaligned}; // we capture at lsu_req_done (after addr_incr) + result.cmd0.wdata = {1'b0, tmp64[63:32]}; + + result.cmd1.flag = 8'h0; + result.cmd1.is_cap = 1'b0; + result.cmd1.we = lsu_cmd.we; + result.cmd1.be = tmp8[7:4]; + result.cmd1.addr32 = lsu_cmd.addr[31:2]; + result.cmd1.wdata = {1'b0, tmp64[63:32]}; + end else if (lsu_cmd.rv32_type == 2'b01) begin // half word (CPU rv32 only) + logic [7:0] tmp8; + logic unaligned; + + // halfword accesses, ignore wdata here (will be checked by sail) + unaligned = (lsu_cmd.addr[1:0] == 2'b11); + result.valid = unaligned ? 2'b11 : 2'b01; + tmp8 = 8'h03 << {lsu_cmd.addr[1:0]}; + + result.cmd0.flag = 8'h0; + result.cmd0.is_cap = 1'b0; + result.cmd0.we = lsu_cmd.we; + result.cmd0.be = tmp8[3:0]; + result.cmd0.addr32 = lsu_cmd.addr[31:2] - {31'h0, unaligned}; + result.cmd0.wdata = 33'hdead_beef; + + result.cmd1.flag = 8'h0; + result.cmd1.is_cap = 1'b0; + result.cmd1.we = lsu_cmd.we; + result.cmd1.be = tmp8[7:4]; + result.cmd1.addr32 = lsu_cmd.addr[31:2]; + result.cmd1.wdata = 33'hdead_beef; + end else begin // byte (CPU rv32 only) + logic [7:0] tmp8; + + result.valid = 2'b01; + tmp8 = 8'h01 << {lsu_cmd.addr[1:0]}; + + result.cmd0.flag = 8'h0; + result.cmd0.is_cap = 1'b0; + result.cmd0.we = lsu_cmd.we; + result.cmd0.be = tmp8[3:0]; + result.cmd0.addr32 = lsu_cmd.addr[31:2]; + result.cmd0.wdata = {1'b0, lsu_cmd.wdata << {lsu_cmd.addr[1:0], 3'b000}}; + end + + return result; + endfunction + + // check function: return 0 for pass, non-zero for fail + function automatic logic[7:0] check_mem_cmd (mem_cmd_t cmd0, mem_cmd_t cmd1); + logic [7:0] result; + + result = 0; + + if ((cmd0.is_cap != cmd1.is_cap) || (cmd0.we != cmd1.we) || (cmd0.be != cmd1.be)) + result |= 8'h1; + if (cmd0.addr32 != cmd1.addr32) + result |= (8'h1 << 1); + + // QQQ skip wdata check here for now (unaligned/halfword/byte, etc) + //if (cmd0.we && (cmd0.wdata != cmd1.wdata)) + // result |= (8'h1 << 2); + + return result; + endfunction + + // check function: return 0 for pass, non-zero for fail + // return a 8-bit value to help debugging causes + function automatic logic[7:0] check_src_req_cap (lsu_cmd_t req, lsu_cmd_t resp, + mem_cmd_t mem_resp0, mem_cmd_t mem_resp1); + logic [7:0] result; + reg_cap_t mcap; + + result = 0; + + if (resp.err != (mem_resp0.err || mem_resp1.err)) + result |= 8'h1; + if ((~mem_resp0.is_cap) || (mem_resp0.we != req.we) || (mem_resp0.be != 4'hf) || + (mem_resp0.addr32[0]) || (mem_resp0.addr32 != (req.addr[31:2] - 1))) + result |= (8'h1 << 1); + if ((~mem_resp1.is_cap) || (mem_resp1.we != req.we) || (mem_resp1.be != 4'hf) || + (~mem_resp1.addr32[0]) || (mem_resp1.addr32 != (mem_resp0.addr32+1))) + result |= (8'h1 << 2); + + // QQQ let's just do fmt0 for now and add fmt1 later + if (req.we && ((mem_resp0.wdata[31:0] != req.wdata) || mem_resp1.wdata != reg2memcap_fmt0(req.wcap))) + result |= (8'h1 << 3); + if (~req.we && (mem_resp0.rdata[31:0] != resp.rdata)) + result |= (8'h1 << 4); + + mcap = mem2regcap_fmt0(mem_resp1.rdata, mem_resp0.rdata, 0); + if (~req.we && (srcID == 0) && (~resp.err) && // ignore read cap for TBRE and STKZ + ((mcap.valid != resp.rcap.valid) || (mcap.top_cor != resp.rcap.top_cor) || + (mcap.base_cor != resp.rcap.base_cor) || (mcap.exp != resp.rcap.exp) || + (mcap.top != resp.rcap.top) || (mcap.base != resp.rcap.base) || + (mcap.otype != resp.rcap.otype))) + result |= (8'h1 << 5); + + // ignore perms for CPU reads now (clrperm not modeled yet). for TBRE/STKZ don't care + // if (~req.we && (srcID != 0) && (mcap.cperms != resp.rcap.cperms)) + // result |= (8'h1 << 6); + + return result; + endfunction + + // check function: return 0 for pass, non-zero for fail + function automatic logic [7:0] check_src_req_rv32_unaligned (lsu_cmd_t req, lsu_cmd_t resp, + mem_cmd_t mem_resp0, mem_cmd_t mem_resp1); + logic [7:0] result; + + result = 0; + + if (resp.err != (mem_resp0.err || mem_resp1.err)) + result |= 8'h1; + if ((mem_resp0.is_cap) || (mem_resp0.we != req.we) || (mem_resp0.addr32 != (req.addr[31:2] - 1))) + result |= (8'h1 << 1); + if ((mem_resp1.is_cap) || (mem_resp1.we != req.we) || + (mem_resp1.addr32 != (mem_resp0.addr32+1))) + result |= (8'h1 << 2); + + // QQQ add unaligned wdata/rdata check + + return result; + endfunction + + // check function: return 0 for pass, non-zero for fail + function automatic logic [7:0] check_src_req_rv32 (lsu_cmd_t req, lsu_cmd_t resp, mem_cmd_t mem_resp); + logic [7:0] result; + + result = 0; + + if (resp.err != mem_resp.err) + result |= 8'h1; + if ((mem_resp.is_cap) || (mem_resp.we != req.we) || (mem_resp.addr32 != req.addr[31:2])) + result |= (8'h1 << 1); + + if (req.we && (req.rv32_type == 2'b00) && (mem_resp.wdata[31:0] != req.wdata)) + result |= (8'h1 << 2); + if (~req.we && ~resp.err && (req.rv32_type == 2'b00) && (mem_resp.rdata[31:0] != resp.rdata)) + result |= (8'h1 << 3); + // QQQ add byte/hw wdata/rdata check + + return result; + endfunction + + + lsu_cmd_t lsu_req_queue[$], lsu_resp_queue[$]; + mem_cmd_t mem_req_queue[$], mem_resp_queue[$], src_mem_resp_queue[$]; + + logic mem_resp_src_sel; + assign mem_resp_src_sel = data_resp_info.flag[srcID+1]; + + // debug signals just for waveform viewing + logic [31:0] dbg_mem_req_size, dbg_mem_resp_size, dbg_src_mem_resp_size; + logic [31:0] dbg_lsu_req_size, dbg_lsu_resp_size; + + lsu_cmd_t dbg_lsu_req_head, dbg_lsu_resp_head; + mem_cmd_t dbg_mem_req_head, dbg_mem_resp_head, dbg_src_mem_resp_head; + + int unsigned lsu_req_cnt, mem_req_cnt, lsu_resp_cnt, src_mem_resp_cnt; + logic [7:0] check_result_mem, check_result_src; + + logic sim_end; + string mon_str; + + // + // main process (enqueue/dequeue/check) + // + initial begin + mem_2cmd_t tmp_2cmd; + logic is_rv32_unaligned; + + lsu_req_queue = {}; + lsu_resp_queue = {}; + mem_req_queue = {}; + mem_resp_queue = {}; + src_mem_resp_queue = {}; + + lsu_req_cnt = 0; + mem_req_cnt = 0; + lsu_resp_cnt = 0; + src_mem_resp_cnt = 0; + + check_result_mem = 0; + check_result_src = 0; + + @(posedge rst_ni); + + while (1) begin + @(posedge clk_i); + + dbg_mem_req_size = mem_req_queue.size(); + dbg_mem_resp_size = mem_resp_queue.size(); + dbg_src_mem_resp_size = src_mem_resp_queue.size(); + dbg_lsu_req_size = lsu_req_queue.size(); + dbg_lsu_resp_size = lsu_resp_queue.size(); + + // + // generate requests and place in scoreboard at the source side + // + if (src_lsu_req_valid) begin + lsu_req_queue = {lsu_req_queue, src_lsu_req}; + lsu_req_cnt += 1; + + tmp_2cmd = lsu2mem_cmd(src_lsu_req); + if (tmp_2cmd.valid[0]) mem_req_queue = {mem_req_queue, tmp_2cmd.cmd0}; + if (tmp_2cmd.valid[1]) mem_req_queue = {mem_req_queue, tmp_2cmd.cmd1}; + + mem_req_cnt += tmp_2cmd.valid[0]; + mem_req_cnt += tmp_2cmd.valid[1]; + end + + // place the memory resp in an intermediate queue for compare later + if (data_rvalid && mem_resp_src_sel) begin + mem_resp_queue = {mem_resp_queue, data_resp_info}; + end + + // + // comparison at memory interface + // + if ((mem_req_queue.size() > 0) && (mem_resp_queue.size() > 0)) begin + dbg_mem_req_head = mem_req_queue[0]; + dbg_mem_resp_head = mem_resp_queue[0]; + + check_result_mem = check_mem_cmd(mem_req_queue[0], mem_resp_queue[0]); + if (check_result_mem != 0) $error("TB> %s: check failed: mem_req vs mem_resp", mon_str); + + src_mem_resp_queue = {src_mem_resp_queue, mem_resp_queue[0]}; + src_mem_resp_cnt += 1; + + mem_req_queue = mem_req_queue[1:$]; + mem_resp_queue = mem_resp_queue[1:$]; + end + + // place the LSU response in an intermediate queue for compare later + if (src_lsu_resp_valid) begin + lsu_resp_queue = {lsu_resp_queue, src_lsu_resp}; + lsu_resp_cnt += 1; + end + + // + // Final comparison at the source side + // lsu_req vs lsu_resp vs src_mem_resp_queue + if ((lsu_req_queue.size() > 0) && (lsu_resp_queue.size() > 0)) begin + dbg_lsu_req_head = lsu_req_queue[0]; + dbg_lsu_resp_head = lsu_resp_queue[0]; + dbg_src_mem_resp_head = src_mem_resp_queue[0]; + + is_rv32_unaligned = ((lsu_req_queue[0].rv32_type == 2'b00) && + (lsu_req_queue[0].addr[1:0] != 2'b00)) || + ((lsu_req_queue[0].rv32_type == 2'b01) && + (lsu_req_queue[0].addr[1:0] == 2'b11)); + + if (lsu_req_queue[0].is_cap && (src_mem_resp_queue.size() >= 2)) begin + check_result_src = check_src_req_cap(lsu_req_queue[0], lsu_resp_queue[0], + src_mem_resp_queue[0], src_mem_resp_queue[1]); + if (check_result_src != 0) $error("TB> %s: check failed: src req vs resp 1", mon_str); + + lsu_req_queue = lsu_req_queue[1:$]; + lsu_resp_queue = lsu_resp_queue[1:$]; + src_mem_resp_queue = src_mem_resp_queue[2:$]; + end else if (~lsu_req_queue[0].is_cap && is_rv32_unaligned && + (src_mem_resp_queue.size() >= 2)) begin + check_result_src = check_src_req_rv32_unaligned(lsu_req_queue[0], lsu_resp_queue[0], + src_mem_resp_queue[0], src_mem_resp_queue[1]); + if (check_result_src != 0) $error("TB> %s: check failed: src req vs resp 2", mon_str); + + lsu_req_queue = lsu_req_queue[1:$]; + lsu_resp_queue = lsu_resp_queue[1:$]; + src_mem_resp_queue = src_mem_resp_queue[2:$]; + end else if (src_mem_resp_queue.size() > 0) begin + check_result_src = check_src_req_rv32(lsu_req_queue[0], lsu_resp_queue[0], src_mem_resp_queue[0]); + if (check_result_src != 0) $error("TB> %s: check failed: src_req vs resp 3", mon_str); + + lsu_req_queue = lsu_req_queue[1:$]; + lsu_resp_queue = lsu_resp_queue[1:$]; + src_mem_resp_queue = src_mem_resp_queue[1:$]; + end + end + end + end + + // + // print out stats at the end of simulation + // + initial begin + + if (srcID == 0) $sformat(mon_str, "CPU mem mon"); + if (srcID == 1) $sformat(mon_str, "STKZ mem mon"); + if (srcID == 2) $sformat(mon_str, "TBRE mem mon"); + + sim_end = 1'b0; + @(posedge rst_ni); + + while (1) begin + @(posedge clk_i); + if (end_sim_req) begin + $display("TB> %s: counters: lsu_req = %d, lsu_resp = %d, mem_req = %d, src_mem_resp = %d", + mon_str, lsu_req_cnt, lsu_resp_cnt, mem_req_cnt, src_mem_resp_cnt); + $display("TB> %s: pending terms in queues: %d, %d, %d, %d, %d", mon_str, + dbg_mem_req_size, dbg_mem_resp_size, dbg_src_mem_resp_size, dbg_lsu_req_size, + dbg_lsu_resp_size); + if ((lsu_req_cnt != lsu_resp_cnt) || (mem_req_cnt != src_mem_resp_cnt)) + $error("TB> %s: ERROR! memory transactions count mismatch", mon_str); + if ((dbg_mem_req_size != 0) || (dbg_mem_resp_size != 0) || (dbg_src_mem_resp_size != 0) || + (dbg_lsu_req_size != 0) || (dbg_lsu_resp_size != 0)) + $error("TB> %s: ERROR! Unresolved transactions found", mon_str); + end + end + + end + +endmodule + + +//-------------------------------------------------------------------- +// Memory monitor top-level +// +//-------------------------------------------------------------------- +module mem_mon_top import cheri_pkg::*; import cheriot_dv_pkg::*; ( + input logic clk_i, + input logic rst_ni, + + // monitor CPU data interface + input logic data_req, + input logic data_we, + input logic [3:0] data_be, + input logic data_is_cap, + input logic [31:0] data_addr, + input logic [32:0] data_wdata, + + input logic data_gnt, + input logic data_rvalid, + input logic [32:0] data_rdata, + input logic data_err, + input mem_cmd_t data_resp_info, + + output logic [7:0] data_flag, + input logic end_sim_req +); + + `define TBRE_PATH dut.u_ibex_top.u_ibex_core.cheri_tbre_wrapper_i.g_tbre.cheri_tbre_i + `define STKZ_PATH dut.u_ibex_top.u_ibex_core.cheri_tbre_wrapper_i.g_stkz.cheri_stkz_i + `define CPU_EX_PATH dut.u_ibex_top.u_ibex_core.g_cheri_ex.u_cheri_ex + `define CPU_WB_PATH dut.u_ibex_top.u_ibex_core.wb_stage_i + `define CPU_LSU_PATH dut.u_ibex_top.u_ibex_core.load_store_unit_i + logic req_isr; + logic req_cpu, req_tbre, req_stkz; + +// Internal LSU interface checking +// -- counting and tracking transactions (initiator to LSU to memory) - need scoreboard fifos +// -- track errors (memory faults) +// -- track both reqs and responses +// -- protocol checking on instruction interface + + // + // Tracking CPU execution of startup/exception handler and + // suppress error injection during the phase + // + assign req_isr = dut.u_ibex_top.u_ibex_core.id_stage_i.instr_executing & + dut.u_ibex_top.u_ibex_core.load_store_unit_i.lsu_req_i & + ~dut.u_ibex_top.u_ibex_core.load_store_unit_i.cur_req_is_tbre & + dut.u_ibex_top.u_ibex_core.id_stage_i.controller_i.controller_dv_ext_i.cpu_in_isr; + + assign req_cpu = dut.u_ibex_top.u_ibex_core.load_store_unit_i.lsu_req_i & + ~dut.u_ibex_top.u_ibex_core.load_store_unit_i.cur_req_is_tbre; + assign req_tbre = dut.u_ibex_top.u_ibex_core.load_store_unit_i.cur_req_is_tbre & + dut.u_ibex_top.u_ibex_core.cheri_tbre_wrapper_i.g_tbre.cheri_tbre_i.tbre_lsu_req_o & + dut.u_ibex_top.u_ibex_core.cheri_tbre_wrapper_i.mstr_arbit_comb[1]; + assign req_stkz = dut.u_ibex_top.u_ibex_core.load_store_unit_i.cur_req_is_tbre & + dut.u_ibex_top.u_ibex_core.cheri_tbre_wrapper_i.g_stkz.cheri_stkz_i.stkz_lsu_req_o & + dut.u_ibex_top.u_ibex_core.cheri_tbre_wrapper_i.mstr_arbit_comb[0]; + + assign data_flag = {4'h0, req_tbre, req_stkz, req_cpu, req_isr}; + + + lsu_cmd_t cur_cpu_lsu_req, cur_cpu_lsu_resp; + lsu_cmd_t cur_tbre_lsu_req, cur_tbre_lsu_resp; + lsu_cmd_t cur_stkz_lsu_req, cur_stkz_lsu_resp; + + always_comb begin + cur_tbre_lsu_req.is_cap = `TBRE_PATH.tbre_lsu_is_cap_o; + cur_tbre_lsu_req.we = `TBRE_PATH.tbre_lsu_we_o; + cur_tbre_lsu_req.rv32_type = 2'b00; + cur_tbre_lsu_req.addr = `TBRE_PATH.tbre_lsu_addr_o; + cur_tbre_lsu_req.wdata = `TBRE_PATH.tbre_lsu_wdata_o; + cur_tbre_lsu_req.wcap = NULL_REG_CAP; + + cur_tbre_lsu_resp.rdata = `TBRE_PATH.lsu_tbre_raw_lsw_i[31:0]; + cur_tbre_lsu_resp.rcap = NULL_REG_CAP; // don't compare for TBRE + cur_tbre_lsu_resp.err = `TBRE_PATH.lsu_tbre_resp_err_i; + + cur_stkz_lsu_req.is_cap = `STKZ_PATH.stkz_lsu_is_cap_o; + cur_stkz_lsu_req.we = `STKZ_PATH.stkz_lsu_we_o; + cur_stkz_lsu_req.rv32_type = 2'b00; + cur_stkz_lsu_req.addr = `STKZ_PATH.stkz_lsu_addr_o; + cur_stkz_lsu_req.wdata = `STKZ_PATH.stkz_lsu_wdata_o; + cur_stkz_lsu_req.wcap = NULL_REG_CAP; + + cur_stkz_lsu_resp.rdata = 32'h0; + cur_stkz_lsu_resp.rcap = NULL_REG_CAP; + cur_stkz_lsu_resp.err = `STKZ_PATH.lsu_stkz_resp_err_i; + + cur_cpu_lsu_req.is_cap = `CPU_EX_PATH.lsu_is_cap_o; + cur_cpu_lsu_req.we = `CPU_EX_PATH.lsu_we_o; + cur_cpu_lsu_req.rv32_type = `CPU_EX_PATH.lsu_type_o; + cur_cpu_lsu_req.addr = `CPU_EX_PATH.lsu_addr_o; + cur_cpu_lsu_req.wdata = `CPU_EX_PATH.lsu_wdata_o; + cur_cpu_lsu_req.wcap = `CPU_EX_PATH.lsu_wcap_o; + + cur_cpu_lsu_resp.rdata = `CPU_WB_PATH.rf_wdata_lsu_i; + cur_cpu_lsu_resp.rcap = `CPU_WB_PATH.rf_wcap_lsu_i; + cur_cpu_lsu_resp.err = `CPU_WB_PATH.lsu_resp_err_i; + + end + + logic cpu_lsu_req_valid, cpu_lsu_resp_valid; + logic stkz_lsu_req_valid, stkz_lsu_resp_valid; + logic tbre_lsu_req_valid, tbre_lsu_resp_valid; + + assign cpu_lsu_req_valid = `CPU_EX_PATH.lsu_req_done_i & (~`CPU_EX_PATH.lsu_cheri_err_o); + assign cpu_lsu_resp_valid = `CPU_WB_PATH.lsu_resp_valid_i & (~`CPU_LSU_PATH.lsu_err_is_cheri_o); + + assign stkz_lsu_req_valid = `STKZ_PATH.lsu_stkz_req_done_i; + assign stkz_lsu_resp_valid = `STKZ_PATH.lsu_stkz_resp_valid_i; + + assign tbre_lsu_req_valid = `TBRE_PATH.lsu_tbre_req_done_i; + assign tbre_lsu_resp_valid = `TBRE_PATH.lsu_tbre_resp_valid_i; + + + logic [2:0] sim_end_q; + logic end_sim_req_q; + + always @(posedge clk_i, negedge rst_ni) begin + if (~rst_ni) begin + sim_end_q <= 3'h0; + end_sim_req_q <= 1'b0; + end else begin + sim_end_q <= {sim_end_q[1:0], (end_sim_req & ~end_sim_req_q)}; + end_sim_req_q <= end_sim_req; + end + end + + mem_monitor # ( + .srcID (0) + ) u_cpu_mem_monitor ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .src_lsu_req_valid (cpu_lsu_req_valid), + .src_lsu_req (cur_cpu_lsu_req), + .src_lsu_resp_valid (cpu_lsu_resp_valid), + .src_lsu_resp (cur_cpu_lsu_resp), + .data_req (data_req), + .data_we (data_we), + .data_be (data_be), + .data_is_cap (data_is_cap), + .data_addr (data_addr), + .data_wdata (data_wdata), + .data_gnt (data_gnt), + .data_rvalid (data_rvalid), + .data_rdata (data_rdata), + .data_err (data_err), + .data_resp_info (data_resp_info), + .end_sim_req (sim_end_q[0]) + ); + + + mem_monitor # ( + .srcID (1) + ) u_stkz_mem_monitor ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .src_lsu_req_valid (stkz_lsu_req_valid), + .src_lsu_req (cur_stkz_lsu_req), + .src_lsu_resp_valid (stkz_lsu_resp_valid), + .src_lsu_resp (cur_stkz_lsu_resp), + .data_req (data_req), + .data_we (data_we), + .data_be (data_be), + .data_is_cap (data_is_cap), + .data_addr (data_addr), + .data_wdata (data_wdata), + .data_gnt (data_gnt), + .data_rvalid (data_rvalid), + .data_rdata (data_rdata), + .data_err (data_err), + .data_resp_info (data_resp_info), + .end_sim_req (sim_end_q[1]) + ); + + mem_monitor # ( + .srcID (2) + ) u_tbre_mem_monitor ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .src_lsu_req_valid (tbre_lsu_req_valid), + .src_lsu_req (cur_tbre_lsu_req), + .src_lsu_resp_valid (tbre_lsu_resp_valid), + .src_lsu_resp (cur_tbre_lsu_resp), + .data_req (data_req), + .data_we (data_we), + .data_be (data_be), + .data_is_cap (data_is_cap), + .data_addr (data_addr), + .data_wdata (data_wdata), + .data_gnt (data_gnt), + .data_rvalid (data_rvalid), + .data_rdata (data_rdata), + .data_err (data_err), + .data_resp_info (data_resp_info), + .end_sim_req (sim_end_q[2]) + ); + +endmodule diff --git a/vendor/lowrisc_ibex/dv/cheriot/tb/mem_obi_if.sv b/vendor/lowrisc_ibex/dv/cheriot/tb/mem_obi_if.sv index 615f1df1a..dba14f77b 100644 --- a/vendor/lowrisc_ibex/dv/cheriot/tb/mem_obi_if.sv +++ b/vendor/lowrisc_ibex/dv/cheriot/tb/mem_obi_if.sv @@ -4,11 +4,11 @@ // memory model with random gnt/rvalid waits // -module mem_obi_if #( +module mem_obi_if import cheriot_dv_pkg::*; #( parameter int unsigned DW = 32 )( - input logic clk, - input logic rst_n, + input logic clk_i, + input logic rst_ni, input logic [3:0] GNT_WMAX, input logic [3:0] RESP_WMAX, @@ -16,19 +16,21 @@ module mem_obi_if #( input logic data_req, input logic data_we, input logic [3:0] data_be, - input logic data_req_isr, + input logic data_is_cap, input logic [31:0] data_addr, input logic [DW-1:0] data_wdata, + input logic [7:0] data_flag, // sideband signals (flow through) output logic data_gnt, output logic data_rvalid, output logic [DW-1:0] data_rdata, output logic data_err, + output mem_cmd_t data_resp_info, // loopback information for checking output logic mem_cs, output logic mem_we, output logic [3:0] mem_be, - output logic mem_req_isr, + output logic [7:0] mem_flag, output logic [29:0] mem_addr32, output logic [DW-1:0] mem_wdata, input logic [DW-1:0] mem_rdata, @@ -60,14 +62,6 @@ module mem_obi_if #( logic resp_no_wait, resp_wait_done; logic resp_valid; - typedef struct packed { - logic we; - logic [3:0] be; - logic req_isr; - logic [29:0] addr32; - logic [DW-1:0] wdata; - } mem_cmd_t; - mem_cmd_t mem_cmd_fifo[0:7]; mem_cmd_t cur_wr_cmd, cur_rd_cmd; @@ -78,9 +72,10 @@ module mem_obi_if #( assign cmd_fifo_empty = (cmd_wr_ptr_ext == cmd_rd_ptr_ext); assign cmd_avail = cmd_fifo_wr || !cmd_fifo_empty; + assign cur_wr_cmd.is_cap = data_is_cap; assign cur_wr_cmd.we = data_we; assign cur_wr_cmd.be = data_be; - assign cur_wr_cmd.req_isr = data_req_isr; + assign cur_wr_cmd.flag = data_flag; assign cur_wr_cmd.addr32 = data_addr[31:2]; // 32-bit addr assign cur_wr_cmd.wdata = data_wdata; @@ -94,13 +89,13 @@ module mem_obi_if #( assign resp_wait_done = cmd_avail && !resp_idle && (resp_cntr == 1); // - // @negedge clk + // @negedge clk_i // Grant stage to issue grants and enqueue granted-requests // dequeue requests to generate memory read/writes // - always @(negedge clk, negedge rst_n) begin - if (~rst_n) begin + always @(negedge clk_i, negedge rst_ni) begin + if (~rst_ni) begin data_gnt <= 1'b0; gnt_idle <= 1'b1; gnt_waits <= 0; @@ -150,14 +145,14 @@ module mem_obi_if #( end // - // @posedge clk + // @posedge clk_i // Response stage generate output signals // assign data_rdata = mem_rdata & {33{data_rvalid}}; - always @(posedge clk, negedge rst_n) begin - if (~rst_n) begin + always @(posedge clk_i, negedge rst_ni) begin + if (~rst_ni) begin data_rvalid <= 1'b0; data_err <= 1'b0; cmd_rd_ptr_ext <= 0; @@ -174,13 +169,52 @@ module mem_obi_if #( end // - // memory signals (sampled @posedge clk) + // memory signals (sampled @posedge clk_i) // assign mem_cs = resp_valid; assign mem_we = cur_rd_cmd.we; assign mem_be = cur_rd_cmd.be; - assign mem_req_isr = cur_rd_cmd.req_isr; + assign mem_flag = cur_rd_cmd.flag; assign mem_wdata = cur_rd_cmd.wdata; assign mem_addr32 = cur_rd_cmd.addr32; + // + // Interface protocol check + // + logic outstanding_data_req; + logic [7:0] data_ctrl_info; + + assign data_ctrl_info = {data_is_cap, data_we, data_be}; + + always @(posedge clk_i, negedge rst_ni) begin + if (~rst_ni) begin + outstanding_data_req <= 1'b0; + end else begin + if (data_gnt) + outstanding_data_req <= 1'b0; + else if (data_req && ~data_gnt) + outstanding_data_req <= 1'b1; + end + end + + // -- once asserted, req can't go low until req_done + // -- no change in address/control signals within the same request + `ASSERT(obiReqStable1, (data_gnt |-> data_req)); + `ASSERT(obiReqStable2, (outstanding_data_req |-> data_req)); + `ASSERT(obiCtrlStable, (outstanding_data_req |-> $stable(data_ctrl_info))); + `ASSERT(obiWdataStable, ((outstanding_data_req & data_we) |-> ($stable(data_wdata)))); + `ASSERT(obiAddrStable, (outstanding_data_req |-> $stable(data_addr))); + + mem_cmd_t cur_rd_cmd_q; + + always @(posedge clk_i) begin + cur_rd_cmd_q <= cur_rd_cmd; + end + + always_comb begin + data_resp_info = cur_rd_cmd_q; + data_resp_info.rdata = data_rdata; + data_resp_info.err = data_err; + end + endmodule diff --git a/vendor/lowrisc_ibex/dv/cheriot/tb/module_dv_ext.sv b/vendor/lowrisc_ibex/dv/cheriot/tb/module_dv_ext.sv index 456c00de0..1086b9e9a 100644 --- a/vendor/lowrisc_ibex/dv/cheriot/tb/module_dv_ext.sv +++ b/vendor/lowrisc_ibex/dv/cheriot/tb/module_dv_ext.sv @@ -14,6 +14,7 @@ module bindfiles; bind ibex_load_store_unit ibex_lsu_dv_ext lsu_dv_ext_i (.*); bind cheri_ex cheri_ex_dv_ext cheri_ex_dv_ext_i (.*); bind cheri_trvk_stage cheri_trvk_stage_dv_ext trvk_dv_ext_i (.*); + bind cheri_tbre_wrapper cheri_tbre_wrapper_dv_ext tbre_wrapper_dv_ext_i (.*); bind cheri_tbre cheri_tbre_dv_ext tbre_dv_ext_i (.*); bind cheri_stkz cheri_stkz_dv_ext stkz_dv_ext_i (.*); bind ibex_core ibex_core_dv_ext ibex_core_dv_ext_i (.*); @@ -50,7 +51,9 @@ module ibex_id_stage_dv_ext ( input logic rf_ren_b, input logic [4:0] rf_raddr_b_o, input logic cheri_rf_we, - input logic [4:0] rf_waddr_id_o + input logic [4:0] rf_waddr_id_o, + input logic cheri_exec_id_o, + input logic instr_executing ); logic [2:0] fcov_trvk_stall_cause; @@ -59,6 +62,9 @@ module ibex_id_stage_dv_ext ( assign fcov_trvk_stall_cause[1] = rf_ren_b && ~rf_reg_rdy_i[rf_raddr_b_o]; assign fcov_trvk_stall_cause[2] = cheri_rf_we && ~rf_reg_rdy_i[rf_waddr_id_o]; + `ASSERT(IbexExecInclCheri, (cheri_exec_id_o |-> instr_executing)) + + endmodule @@ -76,7 +82,9 @@ module ibex_controller_dv_ext import ibex_pkg::*; ( input logic do_single_step_q, input ctrl_fsm_e ctrl_fsm_cs, input ctrl_fsm_e ctrl_fsm_ns, - input logic flush_id + input logic flush_id, + input logic pc_set_o, + input pc_sel_e pc_mux_o ); `DV_FCOV_SIGNAL(logic, all_debug_req, debug_req_i || debug_mode_q || debug_single_step_i) @@ -94,6 +102,24 @@ module ibex_controller_dv_ext import ibex_pkg::*; ( `DV_FCOV_SIGNAL(logic, debug_req, debug_req_i & ~debug_mode_q) `DV_FCOV_SIGNAL(logic, debug_single_step_taken, do_single_step_d & ~do_single_step_q) + // signal used by testbench to see if CPU is executing an exception/intrrupt handler + logic cpu_in_isr; + + always @(posedge clk_i, negedge rst_ni) begin + if (~rst_ni) begin + cpu_in_isr <= 1'b0; + end else begin + if (((ctrl_fsm_cs == FLUSH) && pc_set_o && (pc_mux_o == PC_EXC)) || + (ctrl_fsm_cs == IRQ_TAKEN)) + cpu_in_isr <= 1'b1; + else if ((ctrl_fsm_cs == FLUSH) && pc_set_o && (pc_mux_o == PC_ERET)) + cpu_in_isr <= 1'b0; + end + + end + + + endmodule @@ -105,7 +131,7 @@ module ibex_lsu_dv_ext import ibex_pkg::*; import cheri_pkg::*; ( input logic rst_ni, input logic lsu_req_i, input logic data_req_o, - input logic addr_incr_req_o, + input logic lsu_addr_incr_req_o, input logic data_rvalid_i, input logic [1:0] lsu_type_i, input logic [1:0] data_offset, @@ -165,7 +191,7 @@ module ibex_lsu_dv_ext import ibex_pkg::*; import cheri_pkg::*; ( `DV_FCOV_SIGNAL(logic, ls_first_req, lsu_req_i & (ls_fsm_cs == IDLE)) `DV_FCOV_SIGNAL(logic, ls_second_req, - (ls_fsm_cs inside {WAIT_RVALID_MIS}) & data_req_o & addr_incr_req_o) + (ls_fsm_cs inside {WAIT_RVALID_MIS}) & data_req_o & lsu_addr_incr_req_o) `DV_FCOV_SIGNAL(logic, ls_mis_pmp_err_1, (ls_fsm_cs inside {WAIT_RVALID_MIS, WAIT_GNT_MIS}) && pmp_err_q) `DV_FCOV_SIGNAL(logic, ls_mis_pmp_err_2, @@ -232,24 +258,35 @@ module cheri_ex_dv_ext import ibex_pkg::*; import cheri_pkg::*; ( input logic cheri_exec_id_i, input logic [35:0] cheri_operator_i, input logic [31:0] pc_id_i, + input logic instr_is_cheri_i, input logic instr_valid_i, input logic csr_op_en_o, input logic csr_access_o, input cheri_csr_op_e csr_op_o, input logic cheri_lsu_req, + input logic is_load_cap, input logic rv32_lsu_req_i, input logic [31:0] rv32_lsu_addr_i, input logic [1:0] rv32_lsu_type_i, + input logic rv32_lsu_sign_ext_i, input logic cheri_lsu_err, + input reg_cap_t cheri_lsu_wcap, input logic rv32_lsu_err, input logic lsu_req_o, input logic lsu_req_done_i, + input logic cpu_lsu_we, + input logic [32:0] cpu_lsu_wdata, + input logic cpu_lsu_is_cap, input logic [31:0] cpu_lsu_addr, - input logic cpu_lsu_we + input logic addr_incr_req_i ); - // assertion: STKZ active won't change in the middle of load/store (thus lsu_req will stay asserted till req_done) - logic outstanding_lsu_req; + logic outstanding_lsu_req; + logic [1:0] cpu_lsu_type; + logic cpu_lsu_sign_ext; + logic [7:0] cpu_lsu_ctrls; + logic [31:0] cheri_lsu_start_addr; + reg_cap_t cpu_lsu_wcap; typedef enum logic [3:0] {ACC_NULL, CAP_RD, CAP_WR, BYTE_RD, BYTE_WR, HW_RD_ALIGNED, HW_RD_UNALIGNED, HW_WR_ALIGNED, HW_WR_UNALIGNED, @@ -257,7 +294,19 @@ module cheri_ex_dv_ext import ibex_pkg::*; import cheri_pkg::*; ( } lsu_acc_type_e; lsu_acc_type_e fcov_cpu_lsu_acc; - + + assign cpu_lsu_sign_ext = (~instr_is_cheri_i) ? rv32_lsu_sign_ext_i : 1'b0; + assign cpu_lsu_type = (~instr_is_cheri_i) ? rv32_lsu_type_i : 2'b00; + assign cpu_lsu_ctrls = {cpu_lsu_we, cpu_lsu_sign_ext, cpu_lsu_is_cap, cpu_lsu_type}; + assign cpu_lsu_wcap = (instr_is_cheri_i) ? cheri_lsu_wcap : NULL_REG_CAP; + + // for rv32 accesses, addresses are formed by using ALU to do (addr_last_q +4 if addr_incr_req) + // when addr_incr_req is owned by tbre, addr_last_q is not related with the EX instruction, there + // the address will be toggling when cpu_lsu_req is active. + assign cheri_lsu_start_addr = instr_is_cheri_i ? (cpu_lsu_addr - {addr_incr_req_i, 2'b00}) : 0; + + // protocol check for CPU-generated lsu requests + // note lsu_req_o and lsu_req_done_i are for CPU request only always @(posedge clk_i, negedge rst_ni) begin if (~rst_ni) begin outstanding_lsu_req <= 1'b0; @@ -268,11 +317,28 @@ module cheri_ex_dv_ext import ibex_pkg::*; import cheri_pkg::*; ( outstanding_lsu_req <= 1'b1; end end - `ASSERT(IbexLsuReqStable, (outstanding_lsu_req) |-> ($stable(pc_id_i) && $stable(instr_valid_i) && - $stable(cpu_lsu_we))) + + // -- once asserted, req can't go low until req_done + // -- no change in address/control signals within the same request + `ASSERT(IbexLsuReqStable1, (lsu_req_done_i |-> lsu_req_o)); + `ASSERT(IbexLsuReqStable2, (outstanding_lsu_req |-> lsu_req_o)); + `ASSERT(IbexLsuCtrlStable, (outstanding_lsu_req |-> $stable(cpu_lsu_ctrls))); + `ASSERT(IbexLsuWdataStable, ((outstanding_lsu_req & cpu_lsu_we) |-> ($stable(cpu_lsu_wdata) && $stable(cpu_lsu_wcap)))); + `ASSERT(IbexLsuAddrStable, (outstanding_lsu_req |-> $stable(cheri_lsu_start_addr))); + // -- ensure PC/instr_execute is aligned with transactions + // -- req & req_done is enclosed in the same instruction always + // -- max 1 req per instruction (unless ~cheriPPLBC when CLC has to read TSMAP via LSU) + `ASSERT(IbexLsuPCStable, (outstanding_lsu_req |-> ($stable(pc_id_i) && $stable(instr_valid_i)))); + + if (u_ibex_core.CheriPPLBC) begin + `ASSERT(IbexLsuReqEpoch, (lsu_req_done_i |-> u_ibex_core.id_stage_i.instr_done)); + end + + // Cheri and RV32 LSU req can't both be active per decoder `ASSERT(IbexLsuReqSrc, !(cheri_lsu_req & rv32_lsu_req_i)) + // QQQ assertion: STKZ active won't change in the middle of load/store (thus lsu_req will stay asserted till req_done) // Functional coverage signals `DV_FCOV_SIGNAL(logic, cpu_lsu_req, cheri_lsu_req | rv32_lsu_req_i); @@ -389,6 +455,60 @@ module cheri_trvk_stage_dv_ext ( endmodule +//////////////////////////////////////////////////////////////// +// cheri_tbre_wrapper +//////////////////////////////////////////////////////////////// + +module cheri_tbre_wrapper_dv_ext ( + input logic clk_i, + input logic rst_ni, + input logic tbre_lsu_req_o, + input logic lsu_tbre_req_done_i, + input logic lsu_tbre_sel_i, + input logic [1:0] mstr_req, + input logic [1:0] mstr_arbit_comb + ); + + // protocol check for CPU-generated lsu requests + // note lsu_req_o and lsu_req_done_i are for CPU request only + logic outstanding_lsu_req; + + always @(posedge clk_i, negedge rst_ni) begin + if (~rst_ni) begin + outstanding_lsu_req <= 1'b0; + end else begin + if (lsu_tbre_req_done_i) + outstanding_lsu_req <= 1'b0; + else if (tbre_lsu_req_o && lsu_tbre_sel_i && ~lsu_tbre_req_done_i) + outstanding_lsu_req <= 1'b1; + end + end + + logic only_blk0_req; + assign only_blk0_req = ~mstr_req[1] & mstr_req[0]; + + `ASSERT(TbreWArbitOnehot, ($onehot0(mstr_arbit_comb))); + `ASSERT(TbreWArbitStable, (outstanding_lsu_req |-> $stable(mstr_arbit_comb))); + + // if only blk0 req presents, always choose blk0 + // -- this is to ensure the arbiter doesn't lock to blk1 if blk1 req is canceled + `ASSERT(TbreOnlyBlk0Req, (only_blk0_req |-> mstr_arbit_comb[0])); + + // make sure we cover the blk1 req canceling corner case + logic [1:0] mstr_arbit_comb_q; + always @(posedge clk_i, negedge rst_ni) begin + if (~rst_ni) begin + mstr_arbit_comb_q <= 2'h0; + end else begin + mstr_arbit_comb_q <= mstr_arbit_comb; + end + end + + logic fcov_blk1_cancel; + assign fcov_blk1_cancel = (mstr_arbit_comb_q == 2'b10) && only_blk0_req && ~lsu_tbre_req_done_i; + +endmodule + //////////////////////////////////////////////////////////////// // cheri_tbre //////////////////////////////////////////////////////////////// @@ -401,8 +521,12 @@ module cheri_tbre_dv_ext ( input logic [2:0] shdw_fifo_ext_wr_ptr, input logic [2:0] fifo_ext_rd_ptr, input logic tbre_lsu_req_o, + input logic lsu_tbre_addr_incr_i, + input logic tbre_lsu_is_cap_o, + input logic tbre_lsu_we_o, input logic lsu_tbre_req_done_i, input logic [31:0] tbre_lsu_addr_o, + input logic [32:0] tbre_lsu_wdata_o, input logic snoop_lsu_req_i, input logic snoop_lsu_req_done_i, input logic snoop_lsu_we_i, @@ -424,7 +548,7 @@ module cheri_tbre_dv_ext ( `ASSERT(lsuReqDoneOneHot, $onehot0({snoop_lsu_req_done_i, lsu_tbre_req_done_i})) `ASSERT(tbreLsuReqDone, lsu_tbre_req_done_i |-> tbre_lsu_req_o ) - `ASSERT(snoopLsuReqDone, snoop_lsu_req_done_i |-> snoop_lsu_req_i ) + `ASSERT(snoopLsuReqDone, snoop_lsu_req_done_i |-> snoop_lsu_req_i) // looking for collision case logic fcov_tbre_fifo_hazard, fcov_tbre_fifo_head_hazard; @@ -472,6 +596,40 @@ module cheri_tbre_dv_ext ( end + // protocol check for CPU-generated lsu requests + // note lsu_req_o and lsu_req_done_i are for CPU request only + logic outstanding_lsu_req; + logic [7:0] tbre_lsu_ctrls; + logic [31:0] tbre_lsu_start_addr; + logic lsu_cur_req_is_tbre; + + assign tbre_lsu_ctrls = {tbre_lsu_is_cap_o, tbre_lsu_we_o}; + assign tbre_lsu_start_addr = tbre_lsu_we_o? tbre_lsu_addr_o : + (tbre_lsu_addr_o - {lsu_tbre_addr_incr_i, 2'b00}); + assign lsu_tbre_sel = cheri_tbre_wrapper_i.lsu_tbre_sel_i; + + + // note in the fcov_tbre_fifo_head_hazard case, TBRE may cancel a store request. + // therefore we need lsu_cur_req_is_tbre to help make decision + always @(posedge clk_i, negedge rst_ni) begin + if (~rst_ni) begin + outstanding_lsu_req <= 1'b0; + end else begin + if (lsu_tbre_req_done_i) + outstanding_lsu_req <= 1'b0; + else if (tbre_lsu_req_o && lsu_tbre_sel && ~lsu_tbre_req_done_i) + outstanding_lsu_req <= 1'b1; + end + end + + // -- once asserted, req can't go low until req_done + // -- no change in address/control signals within the same request + `ASSERT(TbreLsuReqStable1, (lsu_tbre_req_done_i |-> tbre_lsu_req_o)); + `ASSERT(TbreLsuReqStable2, (outstanding_lsu_req |-> tbre_lsu_req_o)); + `ASSERT(TbreLsuCtrlStable, (outstanding_lsu_req |-> $stable(tbre_lsu_ctrls))); + `ASSERT(TbreLsuWdataStable, (outstanding_lsu_req & tbre_lsu_we_o |-> $stable(tbre_lsu_wdata_o))); + `ASSERT(TbreLsuAddrStable, (outstanding_lsu_req |-> $stable(tbre_lsu_start_addr))); + endmodule //////////////////////////////////////////////////////////////// @@ -502,7 +660,6 @@ module cheri_stkz_dv_ext import ibex_pkg::*; import cheri_pkg::*; ( fcov_ztop_wr_type = 2'h3; end - endmodule //////////////////////////////////////////////////////////////// diff --git a/vendor/lowrisc_ibex/dv/cheriot/tb/tb_cheriot_top.sv b/vendor/lowrisc_ibex/dv/cheriot/tb/tb_cheriot_top.sv index 943aba2c7..973bf1d45 100644 --- a/vendor/lowrisc_ibex/dv/cheriot/tb/tb_cheriot_top.sv +++ b/vendor/lowrisc_ibex/dv/cheriot/tb/tb_cheriot_top.sv @@ -7,14 +7,18 @@ import ibex_pkg::*; import cheri_pkg::*; +import cheriot_dv_pkg::*; import prim_ram_1p_pkg::*; module tb_cheriot_top ( input logic clk_i, - input logic rstn_i, + input logic rst_ni, input logic [31:0] dii_insn_i, output logic [31:0] dii_pc_o, - output logic dii_ack_o + output logic dii_ack_o, + output logic uart_stop_sim_o, + input logic end_sim_req_i, + output logic end_sim_ack_o ); logic instr_req; @@ -38,6 +42,9 @@ module tb_cheriot_top ( logic [6:0] data_rdata_intg; logic data_err; logic data_err_enable; + logic data_is_cap; + logic [7:0] data_flag; + mem_cmd_t data_resp_info; logic irq_external; logic irq_software; @@ -45,6 +52,11 @@ module tb_cheriot_top ( logic [2:0] irq_vec, intr_ack; logic intr_enable; + logic tbre_bg_enable, stkz_bg_enable; + logic tbre_bg_active, stkz_bg_active; + logic ignore_stkz; + logic end_mon_flag; + logic cheri_pmode; logic cheri_tsafe_en; @@ -52,8 +64,9 @@ module tb_cheriot_top ( logic [15:0] tsmap_addr; logic [31:0] tsmap_rdata; - logic [127:0] mmreg_corein; + logic [127:0] mmreg_corein, mmreg_corein_0, mmreg_corein_1; logic [63:0] mmreg_coreout; + logic cheri_fatal_err; `ifndef VERILATOR `ifdef CHERI0 @@ -147,7 +160,7 @@ module tb_cheriot_top ( .MMRegDoutW (64) ) dut ( .clk_i (clk_i ), - .rst_ni (rstn_i ), + .rst_ni (rst_ni ), .test_en_i (1'b0 ), .scan_rst_ni (1'b1 ), .ram_cfg_i ('{0, 0} ), @@ -169,6 +182,7 @@ module tb_cheriot_top ( .data_rvalid_i (data_rvalid ), .data_we_o (data_we ), .data_be_o (data_be ), + .data_is_cap_o (data_is_cap ), .data_addr_o (data_addr ), .data_wdata_o (data_wdata), .data_rdata_i (data_rdata), @@ -180,6 +194,7 @@ module tb_cheriot_top ( .tsmap_rdata_intg_i (7'h0), .mmreg_corein_i (mmreg_corein), .mmreg_coreout_o (mmreg_coreout), + .cheri_fatal_err_o (cheri_fatal_err), .irq_software_i (irq_software), .irq_timer_i (irq_timer ), .irq_external_i (irq_external), @@ -192,10 +207,11 @@ module tb_cheriot_top ( .double_fault_seen_o (), .crash_dump_o (), .scramble_req_o (), - .data_wdata_intg_o (), - .data_is_cap_o () + .data_wdata_intg_o () ); + assign mmreg_corein = mmreg_corein_0 | mmreg_corein_1; + assign {irq_timer, irq_software, irq_external} = irq_vec; assign data_rdata_intg = 7'h0; @@ -206,24 +222,37 @@ module tb_cheriot_top ( if (dut.u_ibex_top.alert_major_internal_o | dut.u_ibex_top.alert_major_bus_o | dut.u_ibex_top.alert_minor_o) begin - $display("Alert detected !!!!!!! @%t, major_int = %1b, major_bus = %1b, minor = %1b", $time, + $error("Alert detected !!!!!!! major_int = %1b, major_bus = %1b, minor = %1b", dut.u_ibex_top.alert_major_internal_o, dut.u_ibex_top.alert_major_bus_o, dut.u_ibex_top.alert_minor_o); end end +`ifdef VERILATOR + `define NOWAVE +`endif + // waveform dump -`ifndef VERILATOR +`ifndef NOWAVE + logic wavedump; initial begin - #0 $fsdbDumpfile("tb_cheriot_top.fsdb"); - $fsdbDumpvars(0, "+all", tb_cheriot_top); + int cfg_wavedump, i; + wavedump = 1'b1; + + i = $value$plusargs("WAVE=%d", cfg_wavedump); + if (i == 1) wavedump = (cfg_wavedump !=0); + + if (wavedump) begin + #0 $fsdbDumpfile("tb_cheriot_top.fsdb"); + $fsdbDumpvars(0, "+all", tb_cheriot_top); + end end `endif // push instructions to ID stage dii_if u_dii_if( .clk_i (clk_i), - .rstn_i (rstn_i), + .rst_ni (rst_ni), .dii_insn_0_i (dii_insn_i), .dii_insn_1_i (32'h0), .dii_pc_o (dii_pc_o), @@ -242,15 +271,19 @@ module tb_cheriot_top ( logic [3:0] instr_gnt_wmax, data_gnt_wmax; logic [3:0] instr_resp_wmax, data_resp_wmax; logic [3:0] intr_intvl; + logic [2:0] cap_err_rate; logic cap_err_enable; logic [3:0] err_enable_vec; + logic [3:0] tbre_intvl, stkz_intvl; + int unsigned cfg_instr_err_rate, cfg_data_err_rate; int unsigned cfg_instr_gnt_wmax, cfg_data_gnt_wmax; int unsigned cfg_instr_resp_wmax, cfg_data_resp_wmax; int unsigned cfg_intr_intvl; int unsigned cfg_cap_err_rate; + int unsigned cfg_tbre_intvl, cfg_stkz_intvl; // // simulation init @@ -258,6 +291,15 @@ module tb_cheriot_top ( initial begin int i; + instr_err_enable = 1'b0; + data_err_enable = 1'b0; + intr_enable = 1'b0; + cap_err_enable = 1'b0; + tbre_bg_enable = 1'b0; + stkz_bg_enable = 1'b0; + end_mon_flag = 1'b0; + end_sim_ack_o = 1'b0; + // defaults instr_err_rate = 3'h0; instr_gnt_wmax = 4'h2; @@ -267,6 +309,8 @@ module tb_cheriot_top ( data_resp_wmax = 4'h2; intr_intvl = 4'h0; cap_err_rate = 3'h0; + tbre_intvl = 3'h0; + stkz_intvl = 3'h0; i = $value$plusargs("INSTR_ERR_RATE=%d", cfg_instr_err_rate); if (i == 1) instr_err_rate = cfg_instr_err_rate[2:0]; @@ -288,22 +332,59 @@ module tb_cheriot_top ( i = $value$plusargs("CAP_ERR_RATE=%d", cfg_cap_err_rate); if (i == 1) cap_err_rate = cfg_cap_err_rate[2:0]; - @(posedge rstn_i); - repeat (10) @(posedge clk_i); // wait after the hardware mtvec init + i = $value$plusargs("TBRE_INTVL=%d", cfg_tbre_intvl); + if (i == 1) tbre_intvl = cfg_tbre_intvl[3:0]; + i = $value$plusargs("STKZ_INTVL=%d", cfg_stkz_intvl); + if (i == 1) stkz_intvl = cfg_stkz_intvl[3:0]; + + $display("TB> INSTR_GNTW = %d, INSTR_RESPW = %d, DATA_GNTW = %d, DATA_RESPW = %d", + instr_gnt_wmax, instr_resp_wmax, data_gnt_wmax, data_resp_wmax); + $display("TB> INSTR_ERR_RATE = %d, DATA_ERR_RATE = %d, INTR_INTVL = %d, CAP_ERR_RATE = %d", + instr_err_rate, data_err_rate, intr_intvl, cap_err_rate); + $display("TB> TBRE_INTVL = %d, STKZ_INTVL = %d", tbre_intvl, stkz_intvl); + + @(posedge rst_ni); + repeat (10) @(posedge clk_i); + + while (~end_sim_req_i) begin + @(posedge clk_i); + instr_err_enable = err_enable_vec[0]; + data_err_enable = err_enable_vec[1]; + intr_enable = err_enable_vec[2]; + cap_err_enable = err_enable_vec[3]; + tbre_bg_enable = |err_enable_vec; + stkz_bg_enable = |err_enable_vec; + end + + // end of simulation + @(posedge clk_i); + instr_err_enable = 1'b0; // disable all generators + data_err_enable = 1'b0; + intr_enable = 1'b0; + cap_err_enable = 1'b0; + tbre_bg_enable = 1'b0; + stkz_bg_enable = 1'b0; + + while (tbre_bg_active | stkz_bg_active) @(posedge clk_i); // wait for TBRE done + repeat (200) @(posedge clk_i); // wait for exception/interrupts to settle + + // collect statics and do final check + @(posedge clk_i); + end_mon_flag = 1'b1; + @(posedge clk_i); + end_mon_flag = 1'b0; + + repeat (10) @(posedge clk_i); + end_sim_ack_o = 1'b1; end - assign instr_err_enable = err_enable_vec[0]; - assign data_err_enable = err_enable_vec[1]; - assign intr_enable = err_enable_vec[2]; - assign cap_err_enable = err_enable_vec[3]; - // // RAMs // instr_mem_model u_instr_mem ( .clk (clk_i ), - .rst_n (rstn_i ), + .rst_n (rst_ni ), .ERR_RATE (instr_err_rate), .GNT_WMAX (instr_gnt_wmax), .RESP_WMAX (instr_resp_wmax), @@ -316,29 +397,57 @@ module tb_cheriot_top ( .instr_err (instr_err ) ); + assign ignore_stkz = stkz_bg_enable & (stkz_intvl != 0); + data_mem_model u_data_mem ( .clk (clk_i ), - .rst_n (rstn_i ), + .rst_n (rst_ni ), .ERR_RATE (data_err_rate), .GNT_WMAX (data_gnt_wmax), .RESP_WMAX (data_resp_wmax), .err_enable (data_err_enable), + .ignore_stkz (ignore_stkz), .data_req (data_req ), .data_we (data_we ), .data_be (data_be ), + .data_is_cap (data_is_cap ), .data_addr (data_addr ), .data_wdata (data_wdata ), + .data_flag (data_flag ), // from mem_monitor .data_gnt (data_gnt ), .data_rvalid (data_rvalid ), .data_rdata (data_rdata ), .data_err (data_err ), + .data_resp_info (data_resp_info), // to mem_monitor .tsmap_cs (tsmap_cs), .tsmap_addr (tsmap_addr), .tsmap_rdata (tsmap_rdata), - .mmreg_corein (mmreg_corein), + .mmreg_corein (mmreg_corein_0), .mmreg_coreout (mmreg_coreout), .err_enable_vec (err_enable_vec), - .intr_ack (intr_ack ) + .intr_ack (intr_ack ), + .uart_stop_sim (uart_stop_sim_o) + ); + + // + // memory transaction monitor + // + mem_mon_top u_mem_mon ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + .data_req (data_req ), + .data_we (data_we ), + .data_be (data_be ), + .data_is_cap (data_is_cap ), + .data_addr (data_addr ), + .data_wdata (data_wdata ), + .data_gnt (data_gnt ), + .data_rvalid (data_rvalid ), + .data_rdata (data_rdata ), + .data_err (data_err ), + .data_resp_info (data_resp_info), // to mem_monitor + .data_flag (data_flag ), // from mem_monitor + .end_sim_req (end_mon_flag) ); // @@ -346,7 +455,7 @@ module tb_cheriot_top ( // intr_gen u_intr_gen ( .clk (clk_i ), - .rst_n (rstn_i ), + .rst_n (rst_ni ), .INTR_INTVL (intr_intvl ), .intr_en (intr_enable ), .intr_ack (intr_ack ), @@ -358,12 +467,28 @@ module tb_cheriot_top ( // cap_err_gen u_cap_err_gen ( .clk (clk_i ), - .rst_n (rstn_i ), + .rst_n (rst_ni ), .ERR_RATE (cap_err_rate ), .err_enable (cap_err_enable), - .err_active ( ) + .err_active (), + .err_failed () ); + // + // random TBRE background traffic generation + // + tbre_bg_gen u_tbre_bg_gen ( + .clk (clk_i ), + .rst_n (rst_ni ), + .TBRE_INTVL (tbre_intvl ), + .STKZ_INTVL (stkz_intvl ), + .tbre_bg_en (tbre_bg_enable), + .stkz_bg_en (stkz_bg_enable), + .mmreg_corein (mmreg_corein_1), + .mmreg_coreout (mmreg_coreout ), + .tbre_active (tbre_bg_active), + .stkz_active (stkz_bg_active) + ); endmodule diff --git a/vendor/lowrisc_ibex/dv/cheriot/tb/tb_env.sv b/vendor/lowrisc_ibex/dv/cheriot/tb/tb_env.sv index 6f076bf54..7951a8d29 100644 --- a/vendor/lowrisc_ibex/dv/cheriot/tb/tb_env.sv +++ b/vendor/lowrisc_ibex/dv/cheriot/tb/tb_env.sv @@ -11,13 +11,19 @@ module tb_env; logic [31:0] dii_insn, nxt_instr; logic [31:0] dii_pc; logic dii_ack; + logic uart_stop_sim; + logic end_sim_req; + logic end_sim_ack; tb_cheriot_top u_tb_top ( - .clk_i (clk), - .rstn_i (rst_n), - .dii_insn_i (dii_insn), - .dii_pc_o (dii_pc), - .dii_ack_o (dii_ack) + .clk_i (clk), + .rst_ni (rst_n), + .dii_insn_i (dii_insn), + .dii_pc_o (dii_pc), + .dii_ack_o (dii_ack), + .uart_stop_sim_o (uart_stop_sim), + .end_sim_req_i (end_sim_req), + .end_sim_ack_o (end_sim_ack) ); @@ -85,15 +91,23 @@ module tb_env; initial begin bit cont_flag; + int timeout, cycle_cnt; int i; + timeout = 20*1000*1000; // default timeout + i = $value$plusargs("TEST=%s", test_name); if (i == 0) $sformat(test_name, "hello_world"); + i = $value$plusargs("TIMEOUT=%d", timeout); + + $sformat(vhx_path, "./bin/%s.vhx", test_name); - $display("Loading test %s", test_name); + $display("TB> Loading test %s", test_name); + $display("TB> Test timeout = %d", timeout); + end_sim_req = 1'b0; rst_n = 1'b1; #1; rst_n = 1'b0; @@ -114,13 +128,26 @@ module tb_env; cont_flag = 1; while (cont_flag) begin @(posedge clk); - if (u_tb_top.data_req & u_tb_top.data_gnt & (u_tb_top.data_addr == 32'h83800200)) begin - if (u_tb_top.data_wdata[7]) - cont_flag = 0; - else - $write("%c", u_tb_top.data_wdata[7:0]); + cycle_cnt += 1; + if (cycle_cnt > timeout) begin + cont_flag = 0; + $display("TB> Simulation timed out after %d cycles", cycle_cnt); + end + + if (uart_stop_sim) begin + cont_flag = 0; + $display("TB> Simulation stopped by UART request @ %d cycles", cycle_cnt); end end + + @(posedge clk); + end_sim_req = 1'b1; + + i = 0; + while ((i < 10000) && ~end_sim_ack) begin + @(posedge clk); + i += 1; + end repeat(10) @(posedge clk); $finish; diff --git a/vendor/lowrisc_ibex/dv/cheriot/tb/tbre_bg_gen.sv b/vendor/lowrisc_ibex/dv/cheriot/tb/tbre_bg_gen.sv new file mode 100644 index 000000000..2b4ea5f70 --- /dev/null +++ b/vendor/lowrisc_ibex/dv/cheriot/tb/tbre_bg_gen.sv @@ -0,0 +1,245 @@ +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// +// Random TBRE/STKZ traffic generator +// +module tbre_bg_gen ( + input logic clk, + input logic rst_n, + + input logic [3:0] TBRE_INTVL, // 0 - no TBRE traffic + input logic [3:0] STKZ_INTVL, // 0 - no STKZ traffic + + input logic tbre_bg_en, + input logic stkz_bg_en, + + output logic [127:0] mmreg_corein, + input logic [63:0] mmreg_coreout, + + output logic tbre_active, + output logic stkz_active + ); + + import cheri_pkg::*; + import cheriot_dv_pkg::*; + + // Memory area that TBRE walk-through is limited to + // size_in_bytes and addresss. must be 8-byte aligned + localparam logic [31:0] TBREAddrMin = 32'h8002_0000; + localparam logic [31:0] TBREAddrMax = 32'h8003_fff8; + localparam logic [31:0] TBRELenMin = 32'h10; + localparam logic [31:0] TBRELenMax = 32'h800; + + localparam logic [31:0] STKZAddrMin = 32'h8000_0000; + localparam logic [31:0] STKZAddrMax = 32'h8003_fff8; + localparam logic [31:0] STKZLenMin = 32'h0; + localparam logic [31:0] STKZLenMax = 32'h400; + + // Heap area where caps point to + localparam logic [31:0] TestHeapBase = 32'h8002_0000; + localparam logic [31:0] TestHeapSize = 32'h1000; + + task gen_tbre_dataset(input [31:0] start_addr, input [31:0] end_addr); + begin + int i, base, len; + logic [31:0] rand32; + logic [32:0] tmp0, tmp1; + @(posedge clk); + + // generate data in DRAM to be walked through + base = (start_addr - DRAMStartAddr)/4; + len = (end_addr - start_addr)/8 + 1; // TBRE end addr is inclusive + // $display("tbre dram_start = %8x, len = %8x", dram_start, len); + for (i = 0; i = TestHeapBase+TestHeapSize)) + $error("TB> tbre_bg_gen: check_result ptr ERROR %d", i); + + // clear tags on dw0 when shdw == 1, don't write when shdw == 0 + tsmap_addr = (dw0 - DRAMStartAddr) >> 8; + tsmap_offset = dw0 - DRAMStartAddr; + tsmap_offset = tsmap_offset[7:3]; + if ((u_tb_top.u_data_mem.tsram[tsmap_addr][tsmap_offset] && dw0[32]) || + (~u_tb_top.u_data_mem.tsram[tsmap_addr][tsmap_offset] && (dw0[32]!=dw1[32]))) + $error("TB> tbre_bg_gen: check_result tag ERROR, %x, %x/%x, %x, %x, %x", + i, dw0, dw1, tsmap_addr, tsmap_offset, u_tb_top.u_data_mem.tsram[tsmap_addr]); + + // check dw1 to make sure we didn't overwrite the wrong location + if ((dw1[32] != dw1[31]) || (dw1[30:22] != 9'h15a) || (dw1[21:18] != 0) || + (dw1[17:9] != dw1[8:0]) || (dw0[8:0] != dw1[8:0])) + $error("TB> tbre_bg_gen: check_result dw1 ERROR, %x, %x", dw0, dw1); + end + end + endtask + + // + // Controlling TBRE via mmreg interface + // + logic tbre_stat, tbre_stat_q; + logic [31:0] tbre_start_addr, tbre_end_addr; + logic tbre_go; + + assign mmreg_corein = {63'h0, tbre_go, tbre_end_addr, tbre_start_addr}; + assign tbre_stat = mmreg_coreout[0]; + + initial begin: tbre_stimuli + int nwait, i; + logic [31:0] rand32, tmp32; + + tbre_start_addr = 32'h0; + tbre_end_addr = 32'h0; + tbre_go = 1'b0; + tbre_active = 1'b0; + + + @(posedge rst_n); + + while (1) begin + if (~tbre_bg_en || (TBRE_INTVL == 0)) begin + tbre_active = 1'b0; + @(posedge clk); + end else begin + tbre_active = 1'b1; + @(posedge clk); + + rand32 = $urandom(); + nwait = ((rand32 % (2** TBRE_INTVL)) + 1) * 10; // wait at least 10 clk cycles + repeat (nwait) @(posedge clk); + if (tbre_bg_en) begin + // compute start/end address + rand32 = $urandom(); + tmp32 = rand32 % ((TBREAddrMax - TBREAddrMin - TBRELenMin)/8); + tbre_start_addr = TBREAddrMin + {tmp32[28:0], 3'h0}; + rand32 = $urandom(); + tmp32 = (rand32 % (TBRELenMax - TBRELenMin)) + TBRELenMin; + tbre_end_addr = tbre_start_addr + {tmp32[31:3], 3'h0}; + if (tbre_end_addr > TBREAddrMax) tbre_end_addr = TBREAddrMax; + //$display("tbre start = %8x, end = %8x", tbre_start_addr, tbre_end_addr); + gen_tbre_dataset(tbre_start_addr, tbre_end_addr); // generate input data set for TBRE runs + + tbre_go = 1'b1; + @(posedge clk); + @(posedge clk); + tbre_go = 1'b0; + + while (tbre_stat) @(posedge clk); // wait TBRE hardware done + check_tbre_result(tbre_start_addr, tbre_end_addr); + @(posedge clk); + end // kick TBRE + end // if enable /else + end // while + end + + // + // Controlling STKZ via foring ZTOPC interface + // - when background generation enabled, data_mem_model will ignore the STKZ writes + // therefore we don't have to worry about stkz overwrites memory content and corrupt tests + // + + `define STKZ_PATH dut.u_ibex_top.u_ibex_core.cheri_tbre_wrapper_i.g_stkz.cheri_stkz_i + `define ID_PATH dut.u_ibex_top.u_ibex_core.id_stage_i + + logic stkz_stat; + logic [31:0] stkz_start_addr, stkz_end_addr; + full_cap_t ztop_wfcap; + logic [31:0] ztop_wdata; + logic cpu_instr_done; + + assign stkz_stat = `STKZ_PATH.stkz_active_o; + assign cpu_instr_done = `ID_PATH.instr_done; + + initial begin: stkz_stimuli + int nwait, i; + logic [31:0] rand32, tmp32; + + stkz_start_addr = 32'h0; + stkz_end_addr = 32'h0; + stkz_active = 1'b0; + + + @(posedge rst_n); + + while (1) begin + if (~stkz_bg_en || (STKZ_INTVL == 0)) begin + stkz_active = 1'b0; + @(posedge clk); + end else begin + stkz_active = 1'b1; + @(posedge clk); + + rand32 = $urandom(); + nwait = ((rand32 % (2** STKZ_INTVL)) + 1) * 10; // wait at least 10 clk cycles + repeat (nwait) @(posedge clk); + if (stkz_bg_en) begin + // compute start/end address + rand32 = $urandom(); + tmp32 = rand32 % ((STKZAddrMax - STKZAddrMin - STKZLenMin)/16) + 1; // 1 to 0x4000 (in 16-B granule) + stkz_start_addr = STKZAddrMin + {tmp32[27:0], 4'h0}; + rand32 = $urandom(); + tmp32 = (rand32 % (STKZLenMax - STKZLenMin)) + STKZLenMin; + stkz_end_addr = stkz_start_addr - {tmp32[31:4], 4'h0}; + if (stkz_end_addr < STKZAddrMin) stkz_end_addr = STKZAddrMin; + + //$display("stkz start = %8x, end = %8x", stkz_start_addr, stkz_end_addr); + ztop_wfcap.valid = 1'b1; + ztop_wfcap.top33 = stkz_start_addr; + ztop_wfcap.base32 = stkz_end_addr; + + // don't issue bg ztop write in the middle of a CPU LSU transaction + force `STKZ_PATH.ztop_wr_i = cpu_instr_done; + force `STKZ_PATH.ztop_wfcap_i = ztop_wfcap; + force `STKZ_PATH.ztop_wdata_i = stkz_start_addr; + + @(posedge clk); + while (~cpu_instr_done) @(posedge clk); + + release `STKZ_PATH.ztop_wr_i; + release `STKZ_PATH.ztop_wfcap_i; + release `STKZ_PATH.ztop_wdata_i; + + @(posedge clk); + while (stkz_stat) @(posedge clk); // wait TBRE hardware done + @(posedge clk); + end + end // if enable /else + end // while + end + +endmodule diff --git a/vendor/lowrisc_ibex/rtl/cheri_decoder.sv b/vendor/lowrisc_ibex/rtl/cheri_decoder.sv index aeb1144a6..cf078c8d7 100644 --- a/vendor/lowrisc_ibex/rtl/cheri_decoder.sv +++ b/vendor/lowrisc_ibex/rtl/cheri_decoder.sv @@ -69,6 +69,7 @@ module cheri_decoder import cheri_pkg::*; # ( cheri_operator_o[CGET_PERM] = cheri_opcode_en_i && (func3_op==0) && (func7_op==7'h7f) && (imm5_op==5'h00); cheri_operator_o[CGET_TYPE] = cheri_opcode_en_i && (func3_op==0) && (func7_op==7'h7f) && (imm5_op==5'h01); cheri_operator_o[CGET_BASE] = cheri_opcode_en_i && (func3_op==0) && (func7_op==7'h7f) && (imm5_op==5'h02); + cheri_operator_o[CGET_HIGH] = cheri_opcode_en_i && (func3_op==0) && (func7_op==7'h7f) && (imm5_op==5'h17); cheri_operator_o[CGET_TOP] = cheri_opcode_en_i && (func3_op==0) && (func7_op==7'h7f) && (imm5_op==5'h18); cheri_operator_o[CGET_LEN] = cheri_opcode_en_i && (func3_op==0) && (func7_op==7'h7f) && (imm5_op==5'h03); cheri_operator_o[CGET_TAG] = cheri_opcode_en_i && (func3_op==0) && (func7_op==7'h7f) && (imm5_op==5'h04); diff --git a/vendor/lowrisc_ibex/rtl/cheri_ex.sv b/vendor/lowrisc_ibex/rtl/cheri_ex.sv index 0181bc9b2..fddaf900c 100644 --- a/vendor/lowrisc_ibex/rtl/cheri_ex.sv +++ b/vendor/lowrisc_ibex/rtl/cheri_ex.sv @@ -6,6 +6,7 @@ module cheri_ex import cheri_pkg::*; #( parameter bit WritebackStage = 1'b0, + parameter bit MemCapFmt = 1'b0, parameter int unsigned HeapBase, parameter int unsigned TSMapBase, parameter int unsigned TSMapSize, @@ -72,7 +73,7 @@ module cheri_ex import cheri_pkg::*; #( output logic cheri_ex_err_o, output logic [11:0] cheri_ex_err_info_o, output logic cheri_wb_err_o, - output logic [11:0] cheri_wb_err_info_o, + output logic [15:0] cheri_wb_err_info_o, // lsu interface output logic lsu_req_o, @@ -211,7 +212,7 @@ module cheri_ex import cheri_pkg::*; #( logic [31:0] pc_id_nxt; full_cap_t setaddr1_outcap, setbounds_outcap; - logic [11:0] cheri_wb_err_info_q, cheri_wb_err_info_d; + logic [15:0] cheri_wb_err_info_q, cheri_wb_err_info_d; logic [11:0] cheri_ex_err_info_q, cheri_ex_err_info_d; logic set_bounds_done; @@ -221,6 +222,7 @@ module cheri_ex import cheri_pkg::*; #( logic cpu_lsu_we; logic cpu_lsu_cheri_err, cpu_lsu_is_cap; + logic illegal_scr_addr; // data forwarding for CHERI instructions // - note address 0 is a read-only location per RISC-V @@ -245,7 +247,7 @@ module cheri_ex import cheri_pkg::*; #( // 1st level of operand gating (power-saving) // - gate off the input to reg2full conversion logic // - note rv32 lsu req only use cs1 - // - may need to use dont_tounch gates QQQ + // - may need to use dont_tounch gates assign rf_rcap_a = (instr_is_cheri_i | instr_is_rv32lsu_i) ? rf_rcap_ng_a : NULL_REG_CAP; assign rf_rdata_a = (instr_is_cheri_i | instr_is_rv32lsu_i) ? rf_rdata_ng_a : 32'h0; @@ -366,6 +368,16 @@ module cheri_ex import cheri_pkg::*; #( cheri_rf_we_raw = 1'b1; cheri_ex_valid_raw = 1'b1; end + cheri_operator_i[CGET_HIGH]: + begin + logic [65:0] tmp66; + tmp66 = MemCapFmt ? reg2mem_fmt1(rf_rcap_a, rf_rdata_a) : + {reg2memcap_fmt0(rf_rcap_a), 1'b0, rf_rdata_a[31:0]}; + result_data_o = tmp66[64:33]; + result_cap_o = NULL_REG_CAP; + cheri_rf_we_raw = 1'b1; + cheri_ex_valid_raw = 1'b1; + end (cheri_operator_i[CSEAL] | cheri_operator_i[CUNSEAL]): begin // cd <-- cs1; cd.otyp <-- cs2.otype; cd.sealed <-- val result_data_o = rf_rdata_a; @@ -516,14 +528,16 @@ module cheri_ex import cheri_pkg::*; #( logic [31:0] tmp32; logic is_ztop, is_write; reg_cap_t trcap; + logic instr_fault; is_ztop = (cheri_cs2_dec_i==CHERI_SCR_ZTOPC); is_write = (rf_raddr_a_i != 0); + instr_fault = perm_vio | illegal_scr_addr; - csr_access_o = ~perm_vio; + csr_access_o = ~instr_fault; csr_op_o = CHERI_CSR_RW; - csr_op_en_raw = ~perm_vio && is_write && ~is_ztop; - ztop_wr_raw = ~perm_vio && is_write && is_ztop; + csr_op_en_raw = ~instr_fault && is_write && ~is_ztop; + ztop_wr_raw = ~instr_fault && is_write && is_ztop; csr_addr_o = cheri_cs2_dec_i; if (cheri_cs2_dec_i == CHERI_SCR_MTCC) begin @@ -556,9 +570,9 @@ module cheri_ex import cheri_pkg::*; #( ztop_wfcap_o = NULL_FULL_CAP; ztop_wdata_o = 32'h0; end - cheri_rf_we_raw = ~perm_vio; + cheri_rf_we_raw = ~instr_fault; cheri_ex_valid_raw = 1'b1; - cheri_wb_err_raw = perm_vio; + cheri_wb_err_raw = instr_fault; end (cheri_operator_i[CJALR] | cheri_operator_i[CJAL]): begin // cd <-- pcc; pcc <-- cs1/pc+offset; pcc.address[0] <--'0'; pcc.sealed <--'0' @@ -866,6 +880,7 @@ module cheri_ex import cheri_pkg::*; #( // main permission logic perm_vio_vec = 0; cs2_bad_type = 1'b0; + illegal_scr_addr = 1'b0; // note cseal/unseal/cis_subject doesn't generate exceptions, // so for all exceptions, violations can always be attributed to cs1, thus no need to further split @@ -896,14 +911,13 @@ module cheri_ex import cheri_pkg::*; #( (rf_rdata_b != {28'h0, decode_otype(rf_fullcap_a.otype, rf_fullcap_a.perms[PERM_EX])}) || (~rf_fullcap_b.perms[PERM_US]); end else if (cheri_operator_i[CJALR]) begin - perm_vio_vec[PVIO_TAG] = (~rf_fullcap_a.valid); - perm_vio_vec[PVIO_SEAL] = (is_cap_sealed(rf_fullcap_a) && (~is_cap_sentry(rf_fullcap_a))); + perm_vio_vec[PVIO_TAG] = ~rf_fullcap_a.valid; + perm_vio_vec[PVIO_SEAL] = is_cap_sealed(rf_fullcap_a) && + (~is_cap_sentry(rf_fullcap_a) || (cheri_imm12_i != 0)); perm_vio_vec[PVIO_EX] = ~rf_fullcap_a.perms[PERM_EX]; - perm_vio_vec[PVIO_ALIGN] = (is_cap_sentry(rf_fullcap_a) && (cheri_imm12_i != 0)) || (addr_result[0]); - end else if (cheri_operator_i[CJAL]) begin - perm_vio_vec[PVIO_ALIGN] = addr_result[0]; end else if (cheri_operator_i[CCSR_RW]) begin - perm_vio_vec[PVIO_ASR] = ~pcc_cap_i.perms[PERM_SR] || (csr_addr_o < 27); + perm_vio_vec[PVIO_ASR] = ~pcc_cap_i.perms[PERM_SR]; + illegal_scr_addr = ~debug_mode_i & (csr_addr_o < 27); end else begin perm_vio_vec = 0; end @@ -953,15 +967,22 @@ module cheri_ex import cheri_pkg::*; #( cheri_ex_err_info_d = cheri_ex_err_info_q; // cheri_wb_err_raw is already qualified by instr - if (cheri_operator_i[CCSR_RW] & cheri_wb_err_raw & cheri_exec_id_i) - // cspecialrw traps - cheri_wb_err_info_d = {1'b0, 1'b1, cheri_cs2_dec_i, cheri_err_cause}; + // bit 15:13: reserved + // bit 12: illegal_scr_addr + // bit 11: alignment error (load/store) + // bit 10:0 mtval as defined by CHERIoT arch spec + if (cheri_operator_i[CCSR_RW] & cheri_wb_err_raw & perm_vio & cheri_exec_id_i) + // cspecialrw traps, PERM_SR + cheri_wb_err_info_d = {5'h0, 1'b1, cheri_cs2_dec_i, cheri_err_cause}; + else if (cheri_operator_i[CCSR_RW] & cheri_wb_err_raw & cheri_exec_id_i) + // cspecialrw trap, illegal addr, treated as illegal_insn + cheri_wb_err_info_d = {3'h0, 1'b1, 12'h0}; else if (cheri_wb_err_raw & cheri_exec_id_i) - cheri_wb_err_info_d = {1'b0, 1'b0, rf_raddr_a_i, cheri_err_cause}; + cheri_wb_err_info_d = {5'h0, 1'b0, rf_raddr_a_i, cheri_err_cause}; else if ((is_load_cap | is_store_cap) & cheri_lsu_err & cheri_exec_id_i) - cheri_wb_err_info_d = {ls_addr_misaligned_only, 1'b0, rf_raddr_a_i, cheri_err_cause}; + cheri_wb_err_info_d = {4'h0, ls_addr_misaligned_only, 1'b0, rf_raddr_a_i, cheri_err_cause}; else if (rv32_lsu_req_i & rv32_lsu_err) - cheri_wb_err_info_d = {1'b0, 1'b0, rf_raddr_a_i, rv32_err_cause}; + cheri_wb_err_info_d = {5'h0, 1'b0, rf_raddr_a_i, rv32_err_cause}; else cheri_wb_err_info_d = cheri_wb_err_info_q; end diff --git a/vendor/lowrisc_ibex/rtl/cheri_pkg.sv b/vendor/lowrisc_ibex/rtl/cheri_pkg.sv index 43686dd5c..9ac7d4076 100644 --- a/vendor/lowrisc_ibex/rtl/cheri_pkg.sv +++ b/vendor/lowrisc_ibex/rtl/cheri_pkg.sv @@ -199,20 +199,21 @@ package cheri_pkg; function automatic logic [CPERMS_W-1:0] mask_clcperms (logic [CPERMS_W-1:0] cperms_in, logic [3:0] clrperm, logic valid_in, logic sealed); logic [CPERMS_W-1:0] cperms_out; - logic clr_glg, clr_sdlm; + logic clr_gl, clr_lg, clr_sdlm; - clr_glg = clrperm[0] & valid_in; + clr_gl = clrperm[0] & valid_in; + clr_lg = clrperm[0] & valid_in & ~sealed; clr_sdlm = clrperm[1] & valid_in & ~sealed; // only clear SD/LM if not sealed cperms_out = cperms_in; - cperms_out[5] = cperms_in[5] & ~clr_glg; // GL + cperms_out[5] = cperms_in[5] & ~clr_gl; // GL if (cperms_in[4:3] == 2'b11) begin - cperms_out[0] = cperms_in[0] & ~clr_glg; // LG + cperms_out[0] = cperms_in[0] & ~clr_lg; // LG cperms_out[1] = cperms_in[1] & ~clr_sdlm; // LM cperms_out[4:2] = clr_sdlm ? 3'b101 : cperms_in[4:2]; end else if (cperms_in[4:2] == 3'b101) begin - cperms_out[0] = cperms_in[0] & ~clr_glg; // LG + cperms_out[0] = cperms_in[0] & ~clr_lg; // LG cperms_out[1] = cperms_in[1] & ~clr_sdlm; // LM end else if (cperms_in[4:0] == 5'b10000) begin cperms_out[4:0] = clr_sdlm? 5'h0 : cperms_in[4:0]; // clear SD will results in NULL permission @@ -220,7 +221,7 @@ package cheri_pkg; cperms_out[4] = ~(clr_sdlm & ~cperms_in[1]); // must decode to 5'h0 if both ld/sd are 0. cperms_out[0] = cperms_in[0] & ~clr_sdlm; end else if (cperms_in[4:3] == 2'b01) begin - cperms_out[0] = cperms_in[0] & ~clr_glg; // LG + cperms_out[0] = cperms_in[0] & ~clr_lg; // LG cperms_out[1] = cperms_in[1] & ~clr_sdlm; // LM end @@ -634,7 +635,7 @@ $display("--- set_bounds: b1 = %x, t1 = %x, b2 = %x, t2 = %x", base1, top1, bas sealed = (regcap.otype != OTYPE_UNSEALED); cperms_mem = msw[CPERMS_LO+:CPERMS_W]; - regcap.cperms = mask_clcperms(cperms_mem, clrperm, valid_in, sealed); + regcap.cperms = mask_clcperms(cperms_mem, clrperm, regcap.valid, sealed); addrmi9 = BOT_W'({1'b0, addr33[31:0]} >> regcap.exp); // ignore the tag valid bit tmp4 = update_temp_fields(regcap.top, regcap.base, addrmi9); regcap.top_cor = tmp4[3:2]; @@ -689,7 +690,7 @@ $display("--- set_bounds: b1 = %x, t1 = %x, b2 = %x, t2 = %x", base1, top1, bas // cperms_mem = {lsw[31], msw[31:26]}; cperms_mem = msw[31:26]; - regcap.cperms = mask_clcperms(cperms_mem, clrperm, valid_in, sealed); + regcap.cperms = mask_clcperms(cperms_mem, clrperm, regcap.valid, sealed); regcap.rsvd = lsw[31]; tmp4 = update_temp_fields(regcap.top, regcap.base, addrmi9); @@ -813,7 +814,7 @@ $display("--- set_bounds: b1 = %x, t1 = %x, b2 = %x, t2 = %x", base1, top1, bas CGET_LEN = 6'h03, CGET_TAG = 6'h04, CGET_TOP = 6'h05, -// CGET_OFFSET = 6'h06, + CGET_HIGH = 6'h06, CGET_ADDR = 6'h07, CSEAL = 6'h08, CUNSEAL = 6'h09, diff --git a/vendor/lowrisc_ibex/rtl/cheri_regfile.sv b/vendor/lowrisc_ibex/rtl/cheri_regfile.sv index 219253671..f44cea3ec 100644 --- a/vendor/lowrisc_ibex/rtl/cheri_regfile.sv +++ b/vendor/lowrisc_ibex/rtl/cheri_regfile.sv @@ -149,15 +149,6 @@ module cheri_regfile import cheri_pkg::*; #( if (CheriPPLBC) begin : g_regrdy -// QQQ_09112023 (contention when TRVKBypass=1) -// Note, when 33-bit memory bus is used, trsv and trvk should NEVER point to the same register -// -- trsv_en and trvk_en could active in the same cycle but should be pointing to different registers -// -- since trsv_en can only be asserted by CLC&lsu_req_done. Even in trvk_bypass case, trsv can only -// -- happen 1 cycle later than trvk_en (to the same register) -// However when 65-bit memory is used, trsv and trvk can point to the same register at the same time -// -- here lsu_req/req_done happens at the same time as the bypassed TRVK uninstall the instruction. -// -- to resolve the contention we need to prioritize trsv over trvk when updating the flopped reg_rdy_vec - always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) reg_rdy_vec[0] <= 1'b1; @@ -169,7 +160,7 @@ module cheri_regfile import cheri_pkg::*; #( reg_rdy_vec[i] <= 1'b1; else if (i >= NCAPS) reg_rdy_vec[i] <= 1'b1; - else if (trsv_dec[i] & trsv_en_i) // prioritize trsv to address the corner case in the QQQ_09112023 + else if (trsv_dec[i] & trsv_en_i) // prioritize trsv t reg_rdy_vec[i] <= 1'b0; else if (trvk_dec[i] & trvk_en_i) reg_rdy_vec[i] <= 1'b1; diff --git a/vendor/lowrisc_ibex/rtl/cheri_stkz.sv b/vendor/lowrisc_ibex/rtl/cheri_stkz.sv index 2ab0e0f20..5190f5b4d 100644 --- a/vendor/lowrisc_ibex/rtl/cheri_stkz.sv +++ b/vendor/lowrisc_ibex/rtl/cheri_stkz.sv @@ -74,7 +74,6 @@ module cheri_stkz import cheri_pkg::*; ( assign ztop_wtop33 = ztop_wfcap_i.top33; - // QQQ do we need to check permission as well? assign cmd_new = ztop_wr_i & (cmd_cap_good | cmd_is_null_d); assign cmd_avail = cmd_new || cmd_pending; assign cmd_go_null = cmd_avail & cmd_is_null && (((stkz_fsm_q == STKZ_ACTIVE) && lsu_stkz_req_done_i) || @@ -87,7 +86,8 @@ module cheri_stkz import cheri_pkg::*; ( assign cmd_wcap = cmd_new ? full2regcap(ztop_wfcap_i) : cmd_wcap_q; assign cmd_wbase32 = cmd_new ? ztop_wbase32 : cmd_wbase32_q; - assign cmd_cap_good = ztop_wfcap_i.valid && (ztop_wtop33[32:2] >= ztop_wdata_i[31:2]); + assign cmd_cap_good = ztop_wfcap_i.valid && (ztop_wtop33[32:2] >= ztop_wdata_i[31:2]) && + ztop_wfcap_i.perms[PERM_SD]; assign cmd_is_null_d = (ztop_wfcap_i == NULL_FULL_CAP) && (ztop_wdata_i == 32'h0); assign cmd_n2z = cmd_wcap.valid & (cmd_wdata[31:2] == cmd_wbase32[31:2]); @@ -116,8 +116,8 @@ module cheri_stkz import cheri_pkg::*; ( cmd_wcap_untagged = cmd_wcap; cmd_wcap_untagged.valid = 1'b0; - // QQQ we are doing this in lieu of a full set_address. - // note we only start an zeroization if tag is valid (which means addr >= base) + // we are doing this in lieu of a full set_address. + // note we only start an zeroization if addr > base32 so no need for representability check ztop_rcap_nxt = ztop_rcap; addrmi9 = {stkz_ptrw_nxt, 2'b00} >> ztop_rcap.exp; tmp4 = update_temp_fields(ztop_rcap.top, ztop_rcap.base, addrmi9); diff --git a/vendor/lowrisc_ibex/rtl/cheri_tbre.sv b/vendor/lowrisc_ibex/rtl/cheri_tbre.sv index 530659483..eb5df1730 100644 --- a/vendor/lowrisc_ibex/rtl/cheri_tbre.sv +++ b/vendor/lowrisc_ibex/rtl/cheri_tbre.sv @@ -94,7 +94,7 @@ module cheri_tbre #( assign tbre_ctrl.end_addr = tbre_ctrl_vec_i[63:32]; assign tbre_stat_o = (tbre_fsm_q != TBRE_IDLE); - // QQQ note having resp_valid here improves performance but making timing a bit worse + // note having resp_valid here improves performance but making timing a bit worse // (data_rvalid --> tbre_lsu_req --> core/tbre mux select --> data_wdata_o assign tbre_lsu_req_o = ((tbre_sch_q == SCH_LOAD) | ((tbre_sch_q == SCH_STORE) && store_req_valid)) & (~wait_resp_q | (lsu_tbre_resp_valid_i & ~tbre_ctrl.add1wait)); assign tbre_lsu_is_cap_o = (tbre_sch_q == SCH_LOAD); diff --git a/vendor/lowrisc_ibex/rtl/ibex_controller.sv b/vendor/lowrisc_ibex/rtl/ibex_controller.sv index adf2e1128..0d92dc3c3 100644 --- a/vendor/lowrisc_ibex/rtl/ibex_controller.sv +++ b/vendor/lowrisc_ibex/rtl/ibex_controller.sv @@ -127,7 +127,7 @@ module ibex_controller #( input logic cheri_ex_err_i, input logic cheri_wb_err_i, input logic [11:0] cheri_ex_err_info_i, - input logic [11:0] cheri_wb_err_info_i, + input logic [15:0] cheri_wb_err_info_i, input logic cheri_branch_req_i, input logic [31:0] cheri_branch_target_i ); @@ -725,10 +725,10 @@ module ibex_controller #( if (instr_fetch_cheri_acc_vio_i) begin // tag violation exc_cause_o = EXC_CAUSE_CHERI_FAULT; csr_mtval_o = {21'h0, 1'b1, 5'h0, 5'h2}; // s=1, cap_idx=0 - csr_mepcc_clrtag_o = 1'b1; end else if (instr_fetch_cheri_bound_vio_i) begin // bound violation exc_cause_o = EXC_CAUSE_CHERI_FAULT; csr_mtval_o = {21'h0, 1'b1, 5'h0, 5'h1}; // s=1, cap_idx=0 + csr_mepcc_clrtag_o = 1'b1; end else begin // ext memory error exc_cause_o = EXC_CAUSE_INSTR_ACCESS_FAULT; csr_mtval_o = instr_fetch_err_plus2_i ? (pc_id_i + 32'd2) : pc_id_i; @@ -811,8 +811,13 @@ module ibex_controller #( end cheri_wb_err_prio: begin if (cheri_pmode_i) begin - exc_cause_o = EXC_CAUSE_CHERI_FAULT; - csr_mtval_o = {21'h0, cheri_wb_err_info_i[10:0]}; + if (cheri_wb_err_info_i[12]) begin // illegal SCR addr + exc_cause_o = EXC_CAUSE_ILLEGAL_INSN; + csr_mtval_o = {21'h0, cheri_wb_err_info_i[10:0]}; + end else begin + exc_cause_o = EXC_CAUSE_CHERI_FAULT; + csr_mtval_o = {21'h0, cheri_wb_err_info_i[10:0]}; + end end end diff --git a/vendor/lowrisc_ibex/rtl/ibex_core.sv b/vendor/lowrisc_ibex/rtl/ibex_core.sv index 87fdf66ac..36adc4091 100644 --- a/vendor/lowrisc_ibex/rtl/ibex_core.sv +++ b/vendor/lowrisc_ibex/rtl/ibex_core.sv @@ -428,7 +428,7 @@ module ibex_core import ibex_pkg::*; import cheri_pkg::*; #( logic cheri_ex_err; logic [11:0] cheri_ex_err_info; logic cheri_wb_err; - logic [11:0] cheri_wb_err_info; + logic [15:0] cheri_wb_err_info; /* verilator lint_off UNOPTFLAT */ /* verilator lint_off IMPERFECTSCH */ @@ -875,6 +875,7 @@ module ibex_core import ibex_pkg::*; import cheri_pkg::*; #( if (CHERIoTEn) begin : g_cheri_ex cheri_ex #( .WritebackStage (WritebackStage), + .MemCapFmt (MemCapFmt), .HeapBase (HeapBase), .TSMapBase (TSMapBase), .TSMapSize (TSMapSize), @@ -1005,7 +1006,7 @@ module ibex_core import ibex_pkg::*; import cheri_pkg::*; #( assign cheri_ex_err = 1'b0; assign cheri_ex_err_info = 11'h0; assign cheri_wb_err = 1'b0; - assign cheri_wb_err_info = 11'h0; + assign cheri_wb_err_info = 16'h0; assign lsu_req = rv32_lsu_req; assign lsu_is_cap = 1'b0; diff --git a/vendor/lowrisc_ibex/rtl/ibex_cs_registers.sv b/vendor/lowrisc_ibex/rtl/ibex_cs_registers.sv index ef4bfc090..244352f3a 100644 --- a/vendor/lowrisc_ibex/rtl/ibex_cs_registers.sv +++ b/vendor/lowrisc_ibex/rtl/ibex_cs_registers.sv @@ -1894,9 +1894,6 @@ module ibex_cs_registers import cheri_pkg::*; #( // mepc extended capability assign mepc_en_cheri = cheri_csr_op_en_i && (cheri_csr_addr_i == CHERI_SCR_MEPCC) && (cheri_csr_op_i == CHERI_CSR_RW); - // let's not worry about non-stanard recoverable NMI/mstack for now QQQ - // note we need to do set_address (representability check) when saving pcc_cap to mepc - // otherwise an out-of-bound pcc_cap may cause mepc corruption always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) mepc_cap <= MEPC_RESET_CAP; diff --git a/vendor/lowrisc_ibex/rtl/ibex_id_stage.sv b/vendor/lowrisc_ibex/rtl/ibex_id_stage.sv index 3d6a5b445..dc060a212 100644 --- a/vendor/lowrisc_ibex/rtl/ibex_id_stage.sv +++ b/vendor/lowrisc_ibex/rtl/ibex_id_stage.sv @@ -214,7 +214,7 @@ module ibex_id_stage import cheri_pkg::*; #( input logic cheri_ex_err_i, input logic [11:0] cheri_ex_err_info_i, input logic cheri_wb_err_i, - input logic [11:0] cheri_wb_err_info_i, + input logic [15:0] cheri_wb_err_info_i, input logic cheri_branch_req_i, // from cheri EX input logic [31:0] cheri_branch_target_i ); @@ -728,10 +728,11 @@ module ibex_id_stage import cheri_pkg::*; #( // csv_access_o is set when CSR access instruction is present and is used to compute whether a CSR // access is illegal. A combinational loop would be created if csr_op_en_o was used along (as // asserting it for an illegal csr access would result in a flush that would need to deassert it). + // assign csr_op_en_o = csr_access_o & instr_executing & instr_id_done_o; + // improve timing for CHERIoT mode (instr_id_done has too much logic) assign csr_op_en_o = csr_access_o & instr_executing & - ((CHERIoTEn & cheri_pmode_i) ? instr_first_cycle : instr_id_done_o); -// QQQQQQQ KLIU - this needs to be looked into!!!! + (CHERIoTEn ? instr_first_cycle : instr_id_done_o); assign alu_operator_ex_o = alu_operator; assign alu_operand_a_ex_o = alu_operand_a; diff --git a/vendor/lowrisc_ibex/rtl/ibex_load_store_unit.sv b/vendor/lowrisc_ibex/rtl/ibex_load_store_unit.sv index 82892ee28..77da47433 100644 --- a/vendor/lowrisc_ibex/rtl/ibex_load_store_unit.sv +++ b/vendor/lowrisc_ibex/rtl/ibex_load_store_unit.sv @@ -286,7 +286,7 @@ module ibex_load_store_unit import ibex_pkg::*; import cheri_pkg::*; #( always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin addr_last_q <= '0; - end else if (addr_update) begin + end else if (addr_update & ~cur_req_is_tbre) begin addr_last_q <= addr_last_d; end end diff --git a/vendor/lowrisc_ibex/rtl/ibex_top.sv b/vendor/lowrisc_ibex/rtl/ibex_top.sv index 179353c26..ab0ec3899 100644 --- a/vendor/lowrisc_ibex/rtl/ibex_top.sv +++ b/vendor/lowrisc_ibex/rtl/ibex_top.sv @@ -1064,7 +1064,7 @@ module ibex_top import ibex_pkg::*; import cheri_pkg::*; #( .CheriTBRE (CheriTBRE) ) u_ibex_lockstep ( .clk_i (clk), - .rst_ni (rst_ni), // should use a different reset tree ?? QQQ kliu + .rst_ni (rst_ni), // should use a different reset tree .hart_id_i (hart_id_local), .boot_addr_i (boot_addr_local), diff --git a/vendor/lowrisc_ibex/rtl/ibex_tracer.sv b/vendor/lowrisc_ibex/rtl/ibex_tracer.sv index 00ef8dc5a..64692a6a9 100644 --- a/vendor/lowrisc_ibex/rtl/ibex_tracer.sv +++ b/vendor/lowrisc_ibex/rtl/ibex_tracer.sv @@ -1352,7 +1352,7 @@ module ibex_tracer import cheri_pkg::*; # ( INSN_CHGETTAG: decode_cheri_rd_cs1_insn("CH.cgettag"); INSN_CHGETSEALED: decode_cheri_rd_cs1_insn("CH.cgetseald"); INSN_CHGETADDR: decode_cheri_rd_cs1_insn("CH.cgetaddr"); - INSN_CHGETTOP: decode_cheri_rd_cs1_insn("CH.cgettop"); + INSN_CHGETHIGH: decode_cheri_rd_cs1_insn("CH.cgethigh"); INSN_CHSEAL: decode_cheri_cd_cs1_cs2_insn("CH.cseal"); INSN_CHUNSEAL: decode_cheri_cd_cs1_cs2_insn("CH.cunseal"); diff --git a/vendor/lowrisc_ibex/rtl/ibex_tracer_pkg.sv b/vendor/lowrisc_ibex/rtl/ibex_tracer_pkg.sv index 6b889d3ec..04bfdd723 100644 --- a/vendor/lowrisc_ibex/rtl/ibex_tracer_pkg.sv +++ b/vendor/lowrisc_ibex/rtl/ibex_tracer_pkg.sv @@ -344,6 +344,7 @@ package ibex_tracer_pkg; parameter logic [31:0] INSN_CHGETPERM = {7'h7f, 5'h0, 5'h?, 3'b000, 5'h?, {OPCODE_CHERI} }; parameter logic [31:0] INSN_CHGETTYPE = {7'h7f, 5'h1, 5'h?, 3'b000, 5'h?, {OPCODE_CHERI} }; parameter logic [31:0] INSN_CHGETBASE = {7'h7f, 5'h2, 5'h?, 3'b000, 5'h?, {OPCODE_CHERI} }; + parameter logic [31:0] INSN_CHGETHIGH = {7'h7f, 5'h17, 5'h?, 3'b000, 5'h?, {OPCODE_CHERI} }; parameter logic [31:0] INSN_CHGETTOP = {7'h7f, 5'h18, 5'h?, 3'b000, 5'h?, {OPCODE_CHERI} }; parameter logic [31:0] INSN_CHGETLEN = {7'h7f, 5'h3, 5'h?, 3'b000, 5'h?, {OPCODE_CHERI} }; parameter logic [31:0] INSN_CHGETTAG = {7'h7f, 5'h4, 5'h?, 3'b000, 5'h?, {OPCODE_CHERI} };