diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 048e753248..16ed6ac36b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -275,7 +275,7 @@ asic-synthesis: - echo $DV_TARGET - source ./verif/sim/setup-env.sh - git clone ${SYNTH_SCRIPT} ${SYNTH_SCRIPT_PATH} -b ${SYNTH_SCRIPT_BRANCH} - - git -C ${SYNTH_SCRIPT_PATH} checkout 1e166766d2c91ca905577cccc70813a2a8bbefc2 + - git -C ${SYNTH_SCRIPT_PATH} checkout cce5ea41 - cp -r ${SYNTH_SCRIPT_PATH}/cva6/ ../ - git apply ${SYNTH_SCRIPT_PATH}/patches/*.patch - echo $SYN_DCSHELL_BASHRC; source $SYN_DCSHELL_BASHRC @@ -546,7 +546,7 @@ simu-gate: - echo $PERIOD - source ./verif/sim/setup-env.sh - git clone ${SYNTH_SCRIPT} ${SYNTH_SCRIPT_PATH} -b ${SYNTH_SCRIPT_BRANCH} - - git -C ${SYNTH_SCRIPT_PATH} checkout 1e166766d2c91ca905577cccc70813a2a8bbefc2 + - git -C ${SYNTH_SCRIPT_PATH} checkout cce5ea41 - cp -r ${SYNTH_SCRIPT_PATH}/cva6/ ../ - git apply ${SYNTH_SCRIPT_PATH}/patches/*.patch - source verif/regress/install-riscv-tests.sh diff --git a/.gitlab-ci/expected_synth.yml b/.gitlab-ci/expected_synth.yml index 98a2aeb83f..969e5e815d 100644 --- a/.gitlab-ci/expected_synth.yml +++ b/.gitlab-ci/expected_synth.yml @@ -1,2 +1,2 @@ cv32a65x: - gates: 178869 + gates: 188627 diff --git a/Flist.ariane b/Flist.ariane index 12b4629404..0edfa8e4f5 100644 --- a/Flist.ariane +++ b/Flist.ariane @@ -160,6 +160,7 @@ vendor/openhwgroup/cvfpu/src/fpnew_rounding.sv vendor/openhwgroup/cvfpu/src/fpnew_top.sv core/pmp/src/pmp.sv core/pmp/src/pmp_entry.sv +core/pmp/src/pmp_data_if.sv common/local/util/instr_tracer.sv core/cvxif_example/cvxif_example_coprocessor.sv core/cvxif_example/instr_decoder.sv diff --git a/core/Flist.cva6 b/core/Flist.cva6 index b54cc3cb1b..cac849e2b7 100644 --- a/core/Flist.cva6 +++ b/core/Flist.cva6 @@ -178,6 +178,7 @@ ${HPDCACHE_DIR}/rtl/src/common/macros/behav/hpdcache_sram_wmask_1rw.sv // NOTE: pmp.sv modified for DSIM (unchanged for other simulators) ${CVA6_REPO_DIR}/core/pmp/src/pmp.sv ${CVA6_REPO_DIR}/core/pmp/src/pmp_entry.sv +${CVA6_REPO_DIR}/core/pmp/src/pmp_data_if.sv // Tracer (behavioral code, not RTL) ${CVA6_REPO_DIR}/common/local/util/instr_tracer.sv diff --git a/core/cva6_mmu/cva6_mmu.sv b/core/cva6_mmu/cva6_mmu.sv index 9afe90c17e..ccb12e9fd8 100644 --- a/core/cva6_mmu/cva6_mmu.sv +++ b/core/cva6_mmu/cva6_mmu.sv @@ -99,8 +99,9 @@ module cva6_mmu output dcache_req_i_t req_port_o, // PMP - input riscv::pmpcfg_t [CVA6Cfg.NrPMPEntries-1:0] pmpcfg_i, - input logic [CVA6Cfg.NrPMPEntries-1:0][CVA6Cfg.PLEN-3:0] pmpaddr_i + + input riscv::pmpcfg_t [CVA6Cfg.NrPMPEntries-1:0] pmpcfg_i, + input logic [CVA6Cfg.NrPMPEntries-1:0][CVA6Cfg.PLEN-3:0] pmpaddr_i ); // memory management, pte for cva6 @@ -353,8 +354,6 @@ module cva6_mmu //----------------------- // Instruction Interface //----------------------- - logic match_any_execute_region; - logic pmp_instr_allow; localparam int PPNWMin = (CVA6Cfg.PPNW - 1 > 29) ? 29 : CVA6Cfg.PPNW - 1; // The instruction interface is a simple request response interface @@ -439,16 +438,6 @@ module cva6_mmu icache_areq_o.fetch_exception.tinst = '0; icache_areq_o.fetch_exception.gva = v_i; end - end else if (!pmp_instr_allow) begin - icache_areq_o.fetch_exception.cause = riscv::INSTR_ACCESS_FAULT; - icache_areq_o.fetch_exception.valid = 1'b1; - if (CVA6Cfg.TvalEn) - icache_areq_o.fetch_exception.tval = CVA6Cfg.XLEN'(icache_areq_i.fetch_vaddr); - if (CVA6Cfg.RVH) begin - icache_areq_o.fetch_exception.tval2 = '0; - icache_areq_o.fetch_exception.tinst = '0; - icache_areq_o.fetch_exception.gva = v_i; - end end end else if (ptw_active && walking_instr) begin // ---------// @@ -479,7 +468,7 @@ module cva6_mmu end else begin icache_areq_o.fetch_exception.cause = riscv::INSTR_ACCESS_FAULT; icache_areq_o.fetch_exception.valid = 1'b1; - if (CVA6Cfg.TvalEn) //To confirm this is the right TVAL + if (CVA6Cfg.TvalEn) //To confirm this is the right TVAL icache_areq_o.fetch_exception.tval = CVA6Cfg.XLEN'(update_vaddr); if (CVA6Cfg.RVH) begin icache_areq_o.fetch_exception.tval2 = '0; @@ -489,48 +478,8 @@ module cva6_mmu end end end - - // if it didn't match any execute region throw an `Instruction Access Fault` - // or: if we are not translating, check PMPs immediately on the paddr - if ((!match_any_execute_region && !ptw_error) || (!(enable_translation_i || enable_g_translation_i) && !pmp_instr_allow)) begin - icache_areq_o.fetch_exception.cause = riscv::INSTR_ACCESS_FAULT; - icache_areq_o.fetch_exception.valid = 1'b1; - if (CVA6Cfg.TvalEn) begin //To confirm this is the right TVAL - if (enable_translation_i || enable_g_translation_i) - icache_areq_o.fetch_exception.tval = CVA6Cfg.XLEN'(update_vaddr); - else - icache_areq_o.fetch_exception.tval=CVA6Cfg.XLEN'(icache_areq_o.fetch_paddr[CVA6Cfg.PLEN-1:(CVA6Cfg.PLEN > CVA6Cfg.VLEN) ? (CVA6Cfg.PLEN - CVA6Cfg.VLEN) : 0]); - end - if (CVA6Cfg.RVH) begin - icache_areq_o.fetch_exception.tval2 = '0; - icache_areq_o.fetch_exception.tinst = '0; - icache_areq_o.fetch_exception.gva = v_i; - end - end end - // check for execute flag on memory - assign match_any_execute_region = config_pkg::is_inside_execute_regions( - CVA6Cfg, {{64 - CVA6Cfg.PLEN{1'b0}}, icache_areq_o.fetch_paddr} - ); - - // Instruction fetch - pmp #( - .CVA6Cfg (CVA6Cfg), //comment for hypervisor extension - .PLEN (CVA6Cfg.PLEN), - .PMP_LEN (CVA6Cfg.PLEN - 2), - .NR_ENTRIES(CVA6Cfg.NrPMPEntries) - // .NR_ENTRIES ( ArianeCfg.NrPMPEntries ) // configuration used in hypervisor extension - ) i_pmp_if ( - .addr_i (icache_areq_o.fetch_paddr), - .priv_lvl_i, - // we will always execute on the instruction fetch port - .access_type_i(riscv::ACCESS_EXEC), - // Configuration - .conf_addr_i (pmpaddr_i), - .conf_i (pmpcfg_i), - .allow_o (pmp_instr_allow) - ); //----------------------- // Data Interface @@ -541,7 +490,6 @@ module cva6_mmu logic hs_ld_st_inst_n, hs_ld_st_inst_q; pte_cva6_t dtlb_pte_n, dtlb_pte_q; pte_cva6_t dtlb_gpte_n, dtlb_gpte_q; - exception_t misaligned_ex_n, misaligned_ex_q; logic lsu_req_n, lsu_req_q; logic lsu_is_store_n, lsu_is_store_q; logic dtlb_hit_n, dtlb_hit_q; @@ -550,28 +498,19 @@ module cva6_mmu // check if we need to do translation or if we are always ready (e.g.: we are not translating anything) assign lsu_dtlb_hit_o = (en_ld_st_translation_i || en_ld_st_g_translation_i) ? dtlb_lu_hit : 1'b1; - // Wires to PMP checks - riscv::pmp_access_t pmp_access_type; - logic pmp_data_allow; - // The data interface is simpler and only consists of a request/response interface always_comb begin : data_interface // save request and DTLB response lsu_vaddr_n = lsu_vaddr_i; lsu_req_n = lsu_req_i; - misaligned_ex_n = misaligned_ex_i; dtlb_pte_n = dtlb_content; dtlb_hit_n = dtlb_lu_hit; lsu_is_store_n = lsu_is_store_i; dtlb_is_page_n = dtlb_is_page; lsu_valid_o = lsu_req_q; - lsu_exception_o = misaligned_ex_q; - pmp_access_type = lsu_is_store_q ? riscv::ACCESS_WRITE : riscv::ACCESS_READ; - - // mute misaligned exceptions if there is no request otherwise they will throw accidental exceptions - misaligned_ex_n.valid = misaligned_ex_i.valid & lsu_req_i; + lsu_exception_o = misaligned_ex_i; // Check if the User flag is set, then we may only access it in supervisor mode // if SUM is enabled @@ -592,7 +531,7 @@ module cva6_mmu lsu_dtlb_ppn_o = (CVA6Cfg.PPNW)'(lsu_vaddr_n[((CVA6Cfg.PLEN > CVA6Cfg.VLEN) ? CVA6Cfg.VLEN -1: CVA6Cfg.PLEN -1 ):12]); // translation is enabled and no misaligned exception occurred - if ((en_ld_st_translation_i || en_ld_st_g_translation_i) && !misaligned_ex_q.valid) begin + if ((en_ld_st_translation_i || en_ld_st_g_translation_i) && !misaligned_ex_i.valid) begin lsu_valid_o = 1'b0; lsu_dtlb_ppn_o = (en_ld_st_g_translation_i && CVA6Cfg.RVH)? dtlb_g_content.ppn :dtlb_content.ppn; @@ -651,19 +590,6 @@ module cva6_mmu lsu_exception_o.tinst = lsu_tinst_q; lsu_exception_o.gva = ld_st_v_i; end - // Check if any PMPs are violated - end else if (!pmp_data_allow) begin - lsu_exception_o.cause = riscv::ST_ACCESS_FAULT; - lsu_exception_o.valid = 1'b1; - if (CVA6Cfg.TvalEn) - lsu_exception_o.tval = { - {CVA6Cfg.XLEN - CVA6Cfg.VLEN{lsu_vaddr_q[CVA6Cfg.VLEN-1]}}, lsu_vaddr_q - }; - if (CVA6Cfg.RVH) begin - lsu_exception_o.tval2 = '0; - lsu_exception_o.tinst = lsu_tinst_q; - lsu_exception_o.gva = ld_st_v_i; - end end // this is a load end else begin @@ -692,19 +618,6 @@ module cva6_mmu lsu_exception_o.tinst = lsu_tinst_q; lsu_exception_o.gva = ld_st_v_i; end - // Check if any PMPs are violated - end else if (!pmp_data_allow) begin - lsu_exception_o.cause = riscv::LD_ACCESS_FAULT; - lsu_exception_o.valid = 1'b1; - if (CVA6Cfg.TvalEn) - lsu_exception_o.tval = { - {CVA6Cfg.XLEN - CVA6Cfg.VLEN{lsu_vaddr_q[CVA6Cfg.VLEN-1]}}, lsu_vaddr_q - }; - if (CVA6Cfg.RVH) begin - lsu_exception_o.tval2 = '0; - lsu_exception_o.tinst = lsu_tinst_q; - lsu_exception_o.gva = ld_st_v_i; - end end end end else @@ -800,50 +713,9 @@ module cva6_mmu end end end - // If translation is not enabled, check the paddr immediately against PMPs - end else if (lsu_req_q && !misaligned_ex_q.valid && !pmp_data_allow) begin - if (lsu_is_store_q) begin - lsu_exception_o.cause = riscv::ST_ACCESS_FAULT; - lsu_exception_o.valid = 1'b1; - if (CVA6Cfg.TvalEn) - lsu_exception_o.tval = CVA6Cfg.XLEN'(lsu_paddr_o[CVA6Cfg.PLEN-1:(CVA6Cfg.PLEN>CVA6Cfg.VLEN)?(CVA6Cfg.PLEN-CVA6Cfg.VLEN) : 0]); - - if (CVA6Cfg.RVH) begin - lsu_exception_o.tval2 = '0; - lsu_exception_o.tinst = lsu_tinst_q; - lsu_exception_o.gva = ld_st_v_i; - end - end else begin - lsu_exception_o.cause = riscv::LD_ACCESS_FAULT; - lsu_exception_o.valid = 1'b1; - if (CVA6Cfg.TvalEn) - lsu_exception_o.tval = CVA6Cfg.XLEN'(lsu_paddr_o[CVA6Cfg.PLEN-1:(CVA6Cfg.PLEN>CVA6Cfg.VLEN)?(CVA6Cfg.PLEN-CVA6Cfg.VLEN) : 0]); - - if (CVA6Cfg.RVH) begin - lsu_exception_o.tval2 = '0; - lsu_exception_o.tinst = lsu_tinst_q; - lsu_exception_o.gva = ld_st_v_i; - end - end end end - // Load/store PMP check - pmp #( - .CVA6Cfg (CVA6Cfg), - .PLEN (CVA6Cfg.PLEN), - .PMP_LEN (CVA6Cfg.PLEN - 2), - .NR_ENTRIES(CVA6Cfg.NrPMPEntries) - ) i_pmp_data ( - .addr_i (lsu_paddr_o), - .priv_lvl_i (ld_st_priv_lvl_i), - .access_type_i(pmp_access_type), - // Configuration - .conf_addr_i (pmpaddr_i), - .conf_i (pmpcfg_i), - .allow_o (pmp_data_allow) - ); - // ---------- // Registers // ---------- @@ -852,7 +724,6 @@ module cva6_mmu lsu_vaddr_q <= '0; lsu_gpaddr_q <= '0; lsu_req_q <= '0; - misaligned_ex_q <= '0; dtlb_pte_q <= '0; dtlb_gpte_q <= '0; dtlb_hit_q <= '0; @@ -861,13 +732,12 @@ module cva6_mmu lsu_tinst_q <= '0; hs_ld_st_inst_q <= '0; end else begin - lsu_vaddr_q <= lsu_vaddr_n; - lsu_req_q <= lsu_req_n; - misaligned_ex_q <= misaligned_ex_n; - dtlb_pte_q <= dtlb_pte_n; - dtlb_hit_q <= dtlb_hit_n; - lsu_is_store_q <= lsu_is_store_n; - dtlb_is_page_q <= dtlb_is_page_n; + lsu_vaddr_q <= lsu_vaddr_n; + lsu_req_q <= lsu_req_n; + dtlb_pte_q <= dtlb_pte_n; + dtlb_hit_q <= dtlb_hit_n; + lsu_is_store_q <= lsu_is_store_n; + dtlb_is_page_q <= dtlb_is_page_n; if (CVA6Cfg.RVH) begin lsu_tinst_q <= lsu_tinst_n; diff --git a/core/load_store_unit.sv b/core/load_store_unit.sv index 04c4e00e07..134b6a3dc1 100644 --- a/core/load_store_unit.sv +++ b/core/load_store_unit.sv @@ -205,32 +205,34 @@ module load_store_unit logic translation_req; logic translation_valid; logic [CVA6Cfg.VLEN-1:0] mmu_vaddr; - logic [CVA6Cfg.PLEN-1:0] mmu_paddr, mmu_vaddr_plen, fetch_vaddr_plen; - logic [ 31:0] mmu_tinst; - logic mmu_hs_ld_st_inst; - logic mmu_hlvx_inst; - exception_t mmu_exception; - logic dtlb_hit; - logic [ CVA6Cfg.PPNW-1:0] dtlb_ppn; - - logic ld_valid; - logic [CVA6Cfg.TRANS_ID_BITS-1:0] ld_trans_id; - logic [ CVA6Cfg.XLEN-1:0] ld_result; - logic st_valid; - logic [CVA6Cfg.TRANS_ID_BITS-1:0] st_trans_id; - logic [ CVA6Cfg.XLEN-1:0] st_result; - - logic [ 11:0] page_offset; - logic page_offset_matches; - - exception_t misaligned_exception; - exception_t ld_ex; - exception_t st_ex; - - logic hs_ld_st_inst; - logic hlvx_inst; - - logic [2:0] enable_translation, en_ld_st_translation, flush_tlb; + logic [CVA6Cfg.PLEN-1:0] mmu_paddr, lsu_paddr; + logic [ 31:0] mmu_tinst; + logic mmu_hs_ld_st_inst; + logic mmu_hlvx_inst; + exception_t mmu_exception; + exception_t pmp_exception; + icache_areq_t pmp_icache_areq_i; + logic pmp_translation_valid; + logic dtlb_hit; + logic [ CVA6Cfg.PPNW-1:0] dtlb_ppn; + + logic ld_valid; + logic [CVA6Cfg.TRANS_ID_BITS-1:0] ld_trans_id; + logic [ CVA6Cfg.XLEN-1:0] ld_result; + logic st_valid; + logic [CVA6Cfg.TRANS_ID_BITS-1:0] st_trans_id; + logic [ CVA6Cfg.XLEN-1:0] st_result; + + logic [ 11:0] page_offset; + logic page_offset_matches; + + exception_t misaligned_exception; + exception_t ld_ex; + exception_t st_ex; + + logic hs_ld_st_inst; + logic hlvx_inst; + logic [1:0] sum, mxr; logic [CVA6Cfg.PPNW-1:0] satp_ppn[2:0]; logic [CVA6Cfg.ASID_WIDTH-1:0] asid[2:0], asid_to_be_flushed[1:0]; @@ -256,12 +258,12 @@ module load_store_unit .clk_i(clk_i), .rst_ni(rst_ni), .flush_i(flush_i), - .enable_translation_i, - .enable_g_translation_i, - .en_ld_st_translation_i, - .en_ld_st_g_translation_i, + .enable_translation_i(enable_translation_i), + .enable_g_translation_i(enable_g_translation_i), + .en_ld_st_translation_i(en_ld_st_translation_i), + .en_ld_st_g_translation_i(en_ld_st_g_translation_i), .icache_areq_i(icache_areq_i), - .icache_areq_o(icache_areq_o), + .icache_areq_o(pmp_icache_areq_i), // misaligned bypass .misaligned_ex_i(misaligned_exception), .lsu_req_i(translation_req), @@ -272,9 +274,9 @@ module load_store_unit .lsu_dtlb_hit_o(dtlb_hit), // send in the same cycle as the request .lsu_dtlb_ppn_o(dtlb_ppn), // send in the same cycle as the request - .lsu_valid_o (translation_valid), - .lsu_paddr_o (mmu_paddr), - .lsu_exception_o(mmu_exception), + .lsu_valid_o (pmp_translation_valid), + .lsu_paddr_o (lsu_paddr), + .lsu_exception_o(pmp_exception), .priv_lvl_i (priv_lvl_i), .v_i, @@ -306,24 +308,38 @@ module load_store_unit .req_port_i(dcache_req_ports_i[0]), .req_port_o(dcache_req_ports_o[0]), + .pmpcfg_i, .pmpaddr_i ); - end else begin : gen_no_mmu - - if (CVA6Cfg.VLEN > CVA6Cfg.PLEN) begin - assign mmu_vaddr_plen = mmu_vaddr[CVA6Cfg.PLEN-1:0]; - assign fetch_vaddr_plen = icache_areq_i.fetch_vaddr[CVA6Cfg.PLEN-1:0]; - end else begin - assign mmu_vaddr_plen = {{{CVA6Cfg.PLEN - CVA6Cfg.VLEN} {1'b0}}, mmu_vaddr}; - assign fetch_vaddr_plen = {{{CVA6Cfg.PLEN - CVA6Cfg.VLEN} {1'b0}}, icache_areq_i.fetch_vaddr}; + // icache request without MMU, virtual and physical address are identical + assign pmp_icache_areq_i.fetch_valid = icache_areq_i.fetch_req; + if (CVA6Cfg.VLEN >= CVA6Cfg.PLEN) begin : gen_virtual_physical_address_instruction_vlen_greater + assign pmp_icache_areq_i.fetch_paddr = icache_areq_i.fetch_vaddr[CVA6Cfg.PLEN-1:0]; + end else begin : gen_virtual_physical_address_instruction_plen_greater + assign pmp_icache_areq_i.fetch_paddr = CVA6Cfg.PLEN'(icache_areq_i.fetch_vaddr); + end + assign pmp_icache_areq_i.fetch_exception = 'h0; + // dcache request without mmu for load or store, + // Delay of 1 cycle to match MMU latency giving the address tag + always_ff @(posedge clk_i or negedge rst_ni) begin + if (~rst_ni) begin + lsu_paddr <= '0; + pmp_exception <= '0; + pmp_translation_valid <= 1'b0; + end else begin + if (CVA6Cfg.VLEN >= CVA6Cfg.PLEN) begin : gen_virtual_physical_address_lsu + lsu_paddr <= mmu_vaddr[CVA6Cfg.PLEN-1:0]; + end else begin + lsu_paddr <= CVA6Cfg.PLEN'(mmu_vaddr); + end + pmp_exception <= misaligned_exception; + pmp_translation_valid <= translation_req; + end end - assign icache_areq_o.fetch_valid = icache_areq_i.fetch_req; - assign icache_areq_o.fetch_paddr = fetch_vaddr_plen; - assign icache_areq_o.fetch_exception = '0; - + // dcache interface of PTW not used assign dcache_req_ports_o[0].address_index = '0; assign dcache_req_ports_o[0].address_tag = '0; assign dcache_req_ports_o[0].data_wdata = '0; @@ -336,22 +352,41 @@ module load_store_unit assign itlb_miss_o = 1'b0; assign dtlb_miss_o = 1'b0; - assign dtlb_ppn = mmu_vaddr_plen[CVA6Cfg.PLEN-1:12]; + assign dtlb_ppn = lsu_paddr[CVA6Cfg.PLEN-1:12]; assign dtlb_hit = 1'b1; - always_ff @(posedge clk_i or negedge rst_ni) begin - if (~rst_ni) begin - mmu_paddr <= '0; - translation_valid <= '0; - mmu_exception <= '0; - end else begin - mmu_paddr <= mmu_vaddr_plen; - translation_valid <= translation_req; - mmu_exception <= misaligned_exception; - end - end end + // ------------------ + // PMP + // ------------------ + + pmp_data_if #( + .CVA6Cfg (CVA6Cfg), + .icache_areq_t(icache_areq_t), + .exception_t (exception_t) + ) i_pmp_data_if ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .icache_areq_i (pmp_icache_areq_i), + .icache_areq_o (icache_areq_o), + .icache_fetch_vaddr_i(icache_areq_i.fetch_vaddr), + .lsu_valid_i (pmp_translation_valid), + .lsu_paddr_i (lsu_paddr), + .lsu_vaddr_i (mmu_vaddr), + .lsu_exception_i (pmp_exception), + .lsu_is_store_i (st_translation_req), + .lsu_valid_o (translation_valid), + .lsu_paddr_o (mmu_paddr), + .lsu_exception_o (mmu_exception), + .priv_lvl_i (priv_lvl_i), + .v_i (v_i), + .ld_st_priv_lvl_i (ld_st_priv_lvl_i), + .ld_st_v_i (ld_st_v_i), + .pmpcfg_i (pmpcfg_i), + .pmpaddr_i (pmpaddr_i) + ); + logic store_buffer_empty; // ------------------ diff --git a/core/pmp/src/pmp.sv b/core/pmp/src/pmp.sv index 5d8264c9be..1d2cf02651 100644 --- a/core/pmp/src/pmp.sv +++ b/core/pmp/src/pmp.sv @@ -23,8 +23,8 @@ module pmp #( input riscv::pmp_access_t access_type_i, input riscv::priv_lvl_t priv_lvl_i, // Configuration - input logic [NR_ENTRIES:0][PMP_LEN-1:0] conf_addr_i, - input riscv::pmpcfg_t [NR_ENTRIES:0] conf_i, + input logic [NR_ENTRIES-1:0][PMP_LEN-1:0] conf_addr_i, + input riscv::pmpcfg_t [NR_ENTRIES-1:0] conf_i, // Output output logic allow_o ); @@ -75,20 +75,4 @@ module pmp #( end end else assign allow_o = 1'b1; - // synthesis translate_off - always_comb begin - logic no_locked; - no_locked = 1'b0; - if (priv_lvl_i == riscv::PRIV_LVL_M) begin - no_locked = 1'b1; - for (int i = 0; i < NR_ENTRIES; i++) begin - if (conf_i[i].locked && conf_i[i].addr_mode != riscv::OFF) begin - no_locked &= 1'b0; - end else no_locked &= 1'b1; - end - if (no_locked == 1'b1) assert (allow_o == 1'b1); - end - end - // synthesis translate_on - endmodule diff --git a/core/pmp/src/pmp_data_if.sv b/core/pmp/src/pmp_data_if.sv new file mode 100644 index 0000000000..2e6c03a11f --- /dev/null +++ b/core/pmp/src/pmp_data_if.sv @@ -0,0 +1,198 @@ +//----------------------------------------------------------------------------- +// Copyright 2024 Robert Bosch GmbH +// +// SPDX-License-Identifier: SHL-0.51 +// +// Original Author: Coralie Allioux - Robert Bosch France SAS +//----------------------------------------------------------------------------- + +module pmp_data_if + import ariane_pkg::*; +#( + parameter config_pkg::cva6_cfg_t CVA6Cfg = config_pkg::cva6_cfg_empty, + parameter type icache_areq_t = logic, + parameter type exception_t = logic +) ( + input logic clk_i, + input logic rst_ni, + // IF interface + input icache_areq_t icache_areq_i, + output icache_areq_t icache_areq_o, + input [CVA6Cfg.VLEN-1:0] icache_fetch_vaddr_i, // virtual address for tval only + // LSU interface + // this is a more minimalistic interface because the actual addressing logic is handled + // in the LSU as we distinguish load and stores, what we do here is simple address translation + input logic lsu_valid_i, // request lsu access + input logic [CVA6Cfg.PLEN-1:0] lsu_paddr_i, // physical address in + input logic [CVA6Cfg.VLEN-1:0] lsu_vaddr_i, // virtual address in, for tval only + input exception_t lsu_exception_i, // lsu exception coming from MMU, or misaligned exception + input logic lsu_is_store_i, // the translation is requested by a store + output logic lsu_valid_o, // translation is valid + output logic [CVA6Cfg.PLEN-1:0] lsu_paddr_o, // translated address + output exception_t lsu_exception_o, // address translation threw an exception + // General control signals + input riscv::priv_lvl_t priv_lvl_i, + input logic v_i, + input riscv::priv_lvl_t ld_st_priv_lvl_i, + input logic ld_st_v_i, + // PMP + input riscv::pmpcfg_t [CVA6Cfg.NrPMPEntries-1:0] pmpcfg_i, + input logic [CVA6Cfg.NrPMPEntries-1:0][CVA6Cfg.PLEN-3:0] pmpaddr_i +); + // virtual address causing the exception + logic [CVA6Cfg.XLEN-1:0] fetch_vaddr_xlen, lsu_vaddr_xlen; + + logic pmp_if_allow; + logic match_any_execute_region; + logic data_allow_o; + + // Wires to PMP checks + riscv::pmp_access_t pmp_access_type; + + logic no_locked_data, no_locked_if; + + // For exception tval reporting, use the virtual address and resize it + if (CVA6Cfg.VLEN >= CVA6Cfg.XLEN) begin + assign lsu_vaddr_xlen = lsu_vaddr_i[CVA6Cfg.XLEN-1:0]; + assign fetch_vaddr_xlen = icache_fetch_vaddr_i[CVA6Cfg.XLEN-1:0]; + end else begin + assign lsu_vaddr_xlen = CVA6Cfg.XLEN'(lsu_vaddr_i); + assign fetch_vaddr_xlen = CVA6Cfg.XLEN'(icache_fetch_vaddr_i); + end + + //----------------------- + // Instruction Interface + //----------------------- + + // check for execute flag on memory + assign match_any_execute_region = config_pkg::is_inside_execute_regions( + CVA6Cfg, {{64 - CVA6Cfg.PLEN{1'b0}}, icache_areq_i.fetch_paddr} + ); + + // As the PMP check is combinatorial, pass the icache_areq directly if no + // exception + always_comb begin : instr_interface + icache_areq_o.fetch_valid = icache_areq_i.fetch_valid; + icache_areq_o.fetch_paddr = icache_areq_i.fetch_paddr; + icache_areq_o.fetch_exception = icache_areq_i.fetch_exception; + + // if it didn't match any execute region throw an `Instruction Access Fault` (PMA) + // or if PMP reject the access + if (!match_any_execute_region || !pmp_if_allow) begin + icache_areq_o.fetch_exception.cause = riscv::INSTR_ACCESS_FAULT; + icache_areq_o.fetch_exception.valid = 1'b1; + // For exception, the virtual address is required for tval, if no MMU is + // instantiated then it will be equal to physical address + if (CVA6Cfg.TvalEn) begin + icache_areq_o.fetch_exception.tval = fetch_vaddr_xlen; + end + if (CVA6Cfg.RVH) begin + icache_areq_o.fetch_exception.tval2 = '0; + icache_areq_o.fetch_exception.tinst = '0; + icache_areq_o.fetch_exception.gva = v_i; + end + end + end + + // Instruction fetch + pmp #( + .CVA6Cfg (CVA6Cfg), + .PLEN (CVA6Cfg.PLEN), + .PMP_LEN (CVA6Cfg.PLEN - 2), + .NR_ENTRIES(CVA6Cfg.NrPMPEntries) + ) i_pmp_if ( + .addr_i (icache_areq_i.fetch_paddr), + .priv_lvl_i (priv_lvl_i), + // we will always execute on the instruction fetch port + .access_type_i(riscv::ACCESS_EXEC), + // Configuration + .conf_addr_i (pmpaddr_i), + .conf_i (pmpcfg_i), + .allow_o (pmp_if_allow) + ); + + //----------------------- + // Data Interface + //----------------------- + always_comb begin : data_interface + // save request and DTLB response + lsu_valid_o = lsu_valid_i; + lsu_paddr_o = lsu_paddr_i; + lsu_exception_o = lsu_exception_i; + pmp_access_type = lsu_is_store_i ? riscv::ACCESS_WRITE : riscv::ACCESS_READ; + + // If translation is not enabled, check the paddr immediately against PMPs + if (lsu_valid_i && !data_allow_o) begin + lsu_exception_o.valid = 1'b1; + + if (CVA6Cfg.TvalEn) begin + lsu_exception_o.tval = lsu_vaddr_xlen; + end + + if (lsu_is_store_i) begin + lsu_exception_o.cause = riscv::ST_ACCESS_FAULT; + end else begin + lsu_exception_o.cause = riscv::LD_ACCESS_FAULT; + end + if (CVA6Cfg.RVH) begin + lsu_exception_o.tval2 = '0; + lsu_exception_o.tinst = '0; + lsu_exception_o.gva = ld_st_v_i; + end + end + end + + // Load/store PMP check + pmp #( + .CVA6Cfg (CVA6Cfg), + .PLEN (CVA6Cfg.PLEN), + .PMP_LEN (CVA6Cfg.PLEN - 2), + .NR_ENTRIES(CVA6Cfg.NrPMPEntries) + ) i_pmp_data ( + .addr_i (lsu_paddr_i), + .priv_lvl_i (ld_st_priv_lvl_i), + .access_type_i(pmp_access_type), + // Configuration + .conf_addr_i (pmpaddr_i), + .conf_i (pmpcfg_i), + .allow_o (data_allow_o) + ); + + // ---------------- + // Assert for PMPs + // ---------------- + + // synthesis translate_off + always_ff @(posedge clk_i or negedge rst_ni) begin + if (~rst_ni) begin + no_locked_data <= 1'b0; + end else begin + if (ld_st_priv_lvl_i == riscv::PRIV_LVL_M) begin + no_locked_data <= 1'b1; + for (int i = 0; i < CVA6Cfg.NrPMPEntries; i++) begin + if (pmpcfg_i[i].locked && pmpcfg_i[i].addr_mode != riscv::OFF) begin + no_locked_data <= no_locked_data & 1'b0; + end else no_locked_data <= no_locked_data & 1'b1; + end + if (no_locked_data == 1'b1) assert (data_allow_o == 1'b1); + end + end + end + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (~rst_ni) begin + no_locked_if <= 1'b0; + end else begin + if (priv_lvl_i == riscv::PRIV_LVL_M) begin + no_locked_if <= 1'b1; + for (int i = 0; i < CVA6Cfg.NrPMPEntries; i++) begin + if (pmpcfg_i[i].locked && pmpcfg_i[i].addr_mode != riscv::OFF) begin + no_locked_if <= no_locked_if & 1'b0; + end else no_locked_if <= no_locked_if & 1'b1; + end + if (no_locked_if == 1'b1) assert (pmp_if_allow == 1'b1); + end + end + end + // synthesis translate_on +endmodule