diff --git a/Flist.ariane b/Flist.ariane index 0edfa8e4f..12b462940 100644 --- a/Flist.ariane +++ b/Flist.ariane @@ -160,7 +160,6 @@ 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 e7e65160e..cde932699 100644 --- a/core/Flist.cva6 +++ b/core/Flist.cva6 @@ -180,7 +180,6 @@ ${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 ccda147d4..364c2ef26 100644 --- a/core/cva6_mmu/cva6_mmu.sv +++ b/core/cva6_mmu/cva6_mmu.sv @@ -99,14 +99,8 @@ module cva6_mmu output dcache_req_i_t req_port_o, // PMP - input logic pmp_data_allow_i, - input logic pmp_instr_allow_i, - input logic match_any_execute_region_i, - input riscv::pmpcfg_t [CVA6Cfg.NrPMPEntries-1:0] pmpcfg_i, - input logic [CVA6Cfg.NrPMPEntries-1:0][CVA6Cfg.PLEN-3:0] pmpaddr_i, - input exception_t pmp_fetch_exception_i, - input exception_t pmp_exception_i, - input exception_t pmp_misaligned_ex_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 @@ -340,6 +334,8 @@ 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 @@ -424,8 +420,16 @@ 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_i) begin - icache_areq_o.fetch_exception = pmp_fetch_exception_i; + 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 // ---------// @@ -469,15 +473,45 @@ module cva6_mmu // 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_i && !ptw_error) || (!(enable_translation_i || enable_g_translation_i) && !pmp_instr_allow_i)) begin - icache_areq_o.fetch_exception = pmp_fetch_exception_i; - if (CVA6Cfg.TvalEn) begin // To confirm this is the right TVAL + 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 @@ -488,6 +522,7 @@ 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; @@ -496,19 +531,28 @@ 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 = pmp_misaligned_ex_i; + 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; // Check if the User flag is set, then we may only access it in supervisor mode // if SUM is enabled @@ -529,7 +573,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) && !pmp_misaligned_ex_i.valid) begin + if ((en_ld_st_translation_i || en_ld_st_g_translation_i) && !misaligned_ex_q.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; @@ -589,8 +633,18 @@ module cva6_mmu lsu_exception_o.gva = ld_st_v_i; end // Check if any PMPs are violated - end else if (!pmp_data_allow_i) begin - lsu_exception_o = pmp_exception_i; + 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 @@ -620,8 +674,18 @@ module cva6_mmu lsu_exception_o.gva = ld_st_v_i; end // Check if any PMPs are violated - end else if (!pmp_data_allow_i) begin - lsu_exception_o = pmp_exception_i; + 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 @@ -718,11 +782,49 @@ module cva6_mmu end end // If translation is not enabled, check the paddr immediately against PMPs - end else if (lsu_req_q && !pmp_misaligned_ex_i.valid && !pmp_data_allow_i) begin - lsu_exception_o = pmp_exception_i; + 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 // ---------- @@ -731,6 +833,7 @@ 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; @@ -739,12 +842,13 @@ 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; - 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; + 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; 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 f20df9c15..c1db6e1d9 100644 --- a/core/load_store_unit.sv +++ b/core/load_store_unit.sv @@ -205,18 +205,11 @@ module load_store_unit logic translation_req; logic translation_valid; logic [CVA6Cfg.VLEN-1:0] mmu_vaddr; - logic [CVA6Cfg.PLEN-1:0] pmp_paddr, mmu_paddr, mmu_vaddr_plen, fetch_vaddr_plen; + 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; - exception_t pmp_exception; - exception_t pmp_misaligned_ex; - icache_areq_t pmp_icache_areq_o; - logic pmp_data_allow; - logic pmp_instr_allow; - logic pmp_translation_valid; - logic match_any_execute_region; logic dtlb_hit; logic [ CVA6Cfg.PPNW-1:0] dtlb_ppn; @@ -290,23 +283,24 @@ module load_store_unit .req_port_i(dcache_req_ports_i[0]), .req_port_o(dcache_req_ports_o[0]), - - .pmp_data_allow_i(pmp_data_allow), - .pmp_instr_allow_i(pmp_instr_allow), - .match_any_execute_region_i(match_any_execute_region), - .pmp_fetch_exception_i(pmp_icache_areq_o.fetch_exception), - .pmp_misaligned_ex_i(pmp_misaligned_ex), - .pmp_exception_i(pmp_exception), .pmpcfg_i, .pmpaddr_i, .* ); + end else begin : gen_no_mmu - assign mmu_exception = pmp_exception; - assign icache_areq_o = pmp_icache_areq_o; - assign translation_valid = pmp_translation_valid; - assign mmu_paddr = pmp_paddr; + 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}; + 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; assign dcache_req_ports_o[0].address_index = '0; assign dcache_req_ports_o[0].address_tag = '0; @@ -320,49 +314,22 @@ module load_store_unit assign itlb_miss_o = 1'b0; assign dtlb_miss_o = 1'b0; - assign dtlb_ppn = pmp_paddr[CVA6Cfg.PLEN-1:12]; + assign dtlb_ppn = mmu_vaddr_plen[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), - .icache_arsp_t(icache_arsp_t), - .exception_t (exception_t) - ) i_pmp_data_if ( - .clk_i (clk_i), - .rst_ni (rst_ni), - .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 (pmp_icache_areq_o), - .misaligned_ex_i (misaligned_exception), - .lsu_req_i (translation_req), - .lsu_vaddr_i (mmu_vaddr), - .lsu_tinst_i(mmu_tinst), - .lsu_is_store_i (st_translation_req), - .lsu_valid_o (pmp_translation_valid), - .lsu_paddr_o (pmp_paddr), - .lsu_exception_o (pmp_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), - .data_allow_o (pmp_data_allow), - .instr_allow_o (pmp_instr_allow), - .match_any_execute_region_o (match_any_execute_region), - .misaligned_ex_o (pmp_misaligned_ex) - ); - logic store_buffer_empty; // ------------------ diff --git a/core/pmp/src/pmp.sv b/core/pmp/src/pmp.sv index 439bf901c..5d8264c9b 100644 --- a/core/pmp/src/pmp.sv +++ b/core/pmp/src/pmp.sv @@ -75,4 +75,20 @@ 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 deleted file mode 100644 index 2c08283ba..000000000 --- a/core/pmp/src/pmp_data_if.sv +++ /dev/null @@ -1,253 +0,0 @@ -//----------------------------------------------------------------------------- -// 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 icache_arsp_t = logic, - parameter type exception_t = logic -) ( - input logic clk_i, - input logic rst_ni, - input logic enable_translation_i, - input logic enable_g_translation_i, - input logic en_ld_st_translation_i, // enable virtual memory translation for load/stores - input logic en_ld_st_g_translation_i, // enable G-Stage translation for load/stores - // IF interface - input icache_arsp_t icache_areq_i, - output icache_areq_t icache_areq_o, - // 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 exception_t misaligned_ex_i, - input logic lsu_req_i, // request address translation - input logic [CVA6Cfg.VLEN-1:0] lsu_vaddr_i, // virtual address in - input logic [31:0] lsu_tinst_i, // transformed instruction in - input logic lsu_is_store_i, // the translation is requested by a store - // Cycle 1 - 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:0] pmpcfg_i, - input logic [CVA6Cfg.NrPMPEntries:0][CVA6Cfg.PLEN-3:0] pmpaddr_i, - output logic data_allow_o, - output logic instr_allow_o, - output logic match_any_execute_region_o, - output exception_t misaligned_ex_o -); - - exception_t misaligned_ex_n, misaligned_ex_q; - logic lsu_req_n, lsu_req_q; - logic lsu_is_store_n, lsu_is_store_q; - - // Wires to PMP checks - riscv::pmp_access_t pmp_access_type; - - logic [CVA6Cfg.PLEN-1:0] mmu_vaddr_plen, fetch_vaddr_plen; - logic [CVA6Cfg.VLEN-1:0] lsu_vaddr_q; - logic [31:0] lsu_tinst_q; - - logic no_locked_data, no_locked_if; - - always_comb begin : vaddr_plen - if (CVA6Cfg.VLEN >= CVA6Cfg.PLEN) begin - mmu_vaddr_plen = lsu_vaddr_q[CVA6Cfg.PLEN-1:0]; - fetch_vaddr_plen = icache_areq_i.fetch_vaddr[CVA6Cfg.PLEN-1:0]; - end else begin - mmu_vaddr_plen = CVA6Cfg.PLEN'(lsu_vaddr_q); - fetch_vaddr_plen = CVA6Cfg.PLEN'(icache_areq_i.fetch_vaddr); - end - end - - assign misaligned_ex_o = misaligned_ex_q; - - //----------------------- - // Instruction Interface - //----------------------- - - // check for execute flag on memory - assign match_any_execute_region_o = config_pkg::is_inside_execute_regions( - CVA6Cfg, {{64 - CVA6Cfg.PLEN{1'b0}}, icache_areq_o.fetch_paddr} - ); - - // The instruction interface is a simple request response interface - always_comb begin : instr_interface - icache_areq_o.fetch_valid = icache_areq_i.fetch_req; - icache_areq_o.fetch_paddr = fetch_vaddr_plen; - icache_areq_o.fetch_exception = '0; - - // 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_o || !instr_allow_o) begin - icache_areq_o.fetch_exception.cause = riscv::INSTR_ACCESS_FAULT; - icache_areq_o.fetch_exception.valid = 1'b1; - - if (CVA6Cfg.TvalEn) begin - if (enable_translation_i || enable_g_translation_i) begin - icache_areq_o.fetch_exception.tval = CVA6Cfg.XLEN'(icache_areq_i.fetch_vaddr); - end else begin - 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 - 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_o.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 (instr_allow_o) - ); - - //----------------------- - // Data Interface - //----------------------- - // The data interface is simpler and only consists of a request/response interface - always_comb begin : data_interface - // save request and DTLB response - lsu_req_n = lsu_req_i; - misaligned_ex_n = misaligned_ex_i; - lsu_is_store_n = lsu_is_store_i; - - lsu_paddr_o = mmu_vaddr_plen; - 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; - - // If translation is not enabled, check the paddr immediately against PMPs - if (lsu_req_q && !misaligned_ex_q.valid && !data_allow_o) begin - lsu_exception_o.valid = 1'b1; - - if (CVA6Cfg.TvalEn) begin - if (en_ld_st_translation_i || en_ld_st_g_translation_i) begin - lsu_exception_o.tval = { - {CVA6Cfg.XLEN - CVA6Cfg.VLEN{lsu_vaddr_q[CVA6Cfg.VLEN-1]}}, lsu_vaddr_q - }; - end else begin - lsu_exception_o.tval = CVA6Cfg.XLEN'(lsu_paddr_o[CVA6Cfg.PLEN-1:(CVA6Cfg.PLEN>CVA6Cfg.VLEN)?(CVA6Cfg.PLEN-CVA6Cfg.VLEN) : 0]); - - end - end - - 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 - - if (lsu_is_store_q) begin - lsu_exception_o.cause = riscv::ST_ACCESS_FAULT; - end else begin - lsu_exception_o.cause = riscv::LD_ACCESS_FAULT; - 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 (data_allow_o) - ); - - // ---------- - // Registers - // ---------- - always_ff @(posedge clk_i or negedge rst_ni) begin - if (~rst_ni) begin - lsu_req_q <= '0; - misaligned_ex_q <= '0; - lsu_is_store_q <= '0; - lsu_vaddr_q <= '0; - lsu_tinst_q <= '0; - end else begin - lsu_req_q <= lsu_req_n; - misaligned_ex_q <= misaligned_ex_n; - lsu_is_store_q <= lsu_is_store_n; - lsu_vaddr_q <= lsu_vaddr_i; - - if (CVA6Cfg.RVH) begin - lsu_tinst_q <= lsu_tinst_i; - end - end - end - - - // ---------------- - // 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 (instr_allow_o == 1'b1); - end - end - end - // synthesis translate_on -endmodule