mirror of
https://github.com/openhwgroup/cva6.git
synced 2025-04-22 13:17:41 -04:00
This reverts commit 969c1518f2
.
This commit is contained in:
parent
969c1518f2
commit
51653c6377
6 changed files with 172 additions and 340 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
// ------------------
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
Loading…
Add table
Add a link
Reference in a new issue