mirror of
https://github.com/openhwgroup/cva6.git
synced 2025-04-19 11:54:46 -04:00
Add shared TLB in 32 bits version (#1108)
This commit is contained in:
parent
05846e7156
commit
2c61865b18
8 changed files with 531 additions and 119 deletions
|
@ -168,5 +168,6 @@ ${CVA6_REPO_DIR}/core/mmu_sv39/tlb.sv
|
|||
${CVA6_REPO_DIR}/core/mmu_sv32/cva6_mmu_sv32.sv
|
||||
${CVA6_REPO_DIR}/core/mmu_sv32/cva6_ptw_sv32.sv
|
||||
${CVA6_REPO_DIR}/core/mmu_sv32/cva6_tlb_sv32.sv
|
||||
${CVA6_REPO_DIR}/core/mmu_sv32/cva6_shared_tlb_sv32.sv
|
||||
|
||||
// end of manifest
|
||||
|
|
|
@ -44,8 +44,8 @@ package cva6_config_pkg;
|
|||
localparam CVA6ConfigNrLoadPipeRegs = 1;
|
||||
localparam CVA6ConfigNrStorePipeRegs = 0;
|
||||
|
||||
localparam CVA6ConfigInstrTlbEntries = 16;
|
||||
localparam CVA6ConfigDataTlbEntries = 16;
|
||||
localparam CVA6ConfigInstrTlbEntries = 2;
|
||||
localparam CVA6ConfigDataTlbEntries = 2;
|
||||
|
||||
localparam CVA6ConfigRASDepth = 0;
|
||||
localparam CVA6ConfigBTBEntries = 0;
|
||||
|
|
|
@ -44,8 +44,8 @@ package cva6_config_pkg;
|
|||
localparam CVA6ConfigNrLoadPipeRegs = 1;
|
||||
localparam CVA6ConfigNrStorePipeRegs = 0;
|
||||
|
||||
localparam CVA6ConfigInstrTlbEntries = 16;
|
||||
localparam CVA6ConfigDataTlbEntries = 16;
|
||||
localparam CVA6ConfigInstrTlbEntries = 2;
|
||||
localparam CVA6ConfigDataTlbEntries = 2;
|
||||
|
||||
localparam CVA6ConfigRASDepth = 2;
|
||||
localparam CVA6ConfigBTBEntries = 32;
|
||||
|
|
|
@ -44,8 +44,8 @@ package cva6_config_pkg;
|
|||
localparam CVA6ConfigNrLoadPipeRegs = 1;
|
||||
localparam CVA6ConfigNrStorePipeRegs = 0;
|
||||
|
||||
localparam CVA6ConfigInstrTlbEntries = 16;
|
||||
localparam CVA6ConfigDataTlbEntries = 16;
|
||||
localparam CVA6ConfigInstrTlbEntries = 2;
|
||||
localparam CVA6ConfigDataTlbEntries = 2;
|
||||
|
||||
localparam CVA6ConfigRASDepth = 2;
|
||||
localparam CVA6ConfigBTBEntries = 32;
|
||||
|
|
|
@ -44,8 +44,8 @@ package cva6_config_pkg;
|
|||
localparam CVA6ConfigNrLoadPipeRegs = 1;
|
||||
localparam CVA6ConfigNrStorePipeRegs = 0;
|
||||
|
||||
localparam CVA6ConfigInstrTlbEntries = 16;
|
||||
localparam CVA6ConfigDataTlbEntries = 16;
|
||||
localparam CVA6ConfigInstrTlbEntries = 2;
|
||||
localparam CVA6ConfigDataTlbEntries = 2;
|
||||
|
||||
localparam CVA6ConfigRASDepth = 2;
|
||||
localparam CVA6ConfigBTBEntries = 32;
|
||||
|
|
|
@ -28,8 +28,8 @@
|
|||
|
||||
|
||||
module cva6_mmu_sv32 import ariane_pkg::*; #(
|
||||
parameter int unsigned INSTR_TLB_ENTRIES = 4,
|
||||
parameter int unsigned DATA_TLB_ENTRIES = 4,
|
||||
parameter int unsigned INSTR_TLB_ENTRIES = 2,
|
||||
parameter int unsigned DATA_TLB_ENTRIES = 2,
|
||||
parameter int unsigned ASID_WIDTH = 1,
|
||||
parameter ariane_pkg::ariane_cfg_t ArianeCfg = ariane_pkg::ArianeDefaultConfig
|
||||
) (
|
||||
|
@ -87,7 +87,7 @@ module cva6_mmu_sv32 import ariane_pkg::*; #(
|
|||
logic [riscv::PLEN-1:0] ptw_bad_paddr; // PTW PMP exception bad physical addr
|
||||
|
||||
logic [riscv::VLEN-1:0] update_vaddr;
|
||||
tlb_update_sv32_t update_ptw_itlb, update_ptw_dtlb;
|
||||
tlb_update_sv32_t update_itlb, update_dtlb, update_shared_tlb;
|
||||
|
||||
logic itlb_lu_access;
|
||||
riscv::pte_sv32_t itlb_content;
|
||||
|
@ -99,7 +99,13 @@ module cva6_mmu_sv32 import ariane_pkg::*; #(
|
|||
logic dtlb_is_4M;
|
||||
logic dtlb_lu_hit;
|
||||
|
||||
|
||||
logic shared_tlb_access;
|
||||
logic [riscv::VLEN-1:0] shared_tlb_vaddr;
|
||||
logic shared_tlb_hit;
|
||||
|
||||
logic itlb_req;
|
||||
|
||||
|
||||
// Assignments
|
||||
assign itlb_lu_access = icache_areq_i.fetch_req;
|
||||
assign dtlb_lu_access = lsu_req_i;
|
||||
|
@ -113,7 +119,7 @@ module cva6_mmu_sv32 import ariane_pkg::*; #(
|
|||
.rst_ni ( rst_ni ),
|
||||
.flush_i ( flush_tlb_i ),
|
||||
|
||||
.update_i ( update_ptw_itlb ),
|
||||
.update_i ( update_itlb ),
|
||||
|
||||
.lu_access_i ( itlb_lu_access ),
|
||||
.lu_asid_i ( asid_i ),
|
||||
|
@ -127,58 +133,112 @@ module cva6_mmu_sv32 import ariane_pkg::*; #(
|
|||
);
|
||||
|
||||
cva6_tlb_sv32 #(
|
||||
.TLB_ENTRIES ( DATA_TLB_ENTRIES ),
|
||||
.ASID_WIDTH ( ASID_WIDTH )
|
||||
.TLB_ENTRIES ( DATA_TLB_ENTRIES ),
|
||||
.ASID_WIDTH ( ASID_WIDTH )
|
||||
) i_dtlb (
|
||||
.clk_i ( clk_i ),
|
||||
.rst_ni ( rst_ni ),
|
||||
.flush_i ( flush_tlb_i ),
|
||||
|
||||
.update_i ( update_dtlb ),
|
||||
|
||||
.lu_access_i ( dtlb_lu_access ),
|
||||
.lu_asid_i ( asid_i ),
|
||||
.asid_to_be_flushed_i ( asid_to_be_flushed_i ),
|
||||
.vaddr_to_be_flushed_i ( vaddr_to_be_flushed_i ),
|
||||
.lu_vaddr_i ( lsu_vaddr_i ),
|
||||
.lu_content_o ( dtlb_content ),
|
||||
|
||||
.lu_is_4M_o ( dtlb_is_4M ),
|
||||
.lu_hit_o ( dtlb_lu_hit )
|
||||
);
|
||||
|
||||
cva6_shared_tlb_sv32 #(
|
||||
.SHARED_TLB_DEPTH ( 64 ),
|
||||
.SHARED_TLB_WAYS ( 2 ),
|
||||
.ASID_WIDTH ( ASID_WIDTH )
|
||||
) i_shared_tlb (
|
||||
.clk_i ( clk_i ),
|
||||
.rst_ni ( rst_ni ),
|
||||
.flush_i ( flush_tlb_i ),
|
||||
|
||||
.update_i ( update_ptw_dtlb ),
|
||||
.enable_translation_i ( enable_translation_i ),
|
||||
.en_ld_st_translation_i ( en_ld_st_translation_i),
|
||||
|
||||
.lu_access_i ( dtlb_lu_access ),
|
||||
.lu_asid_i ( asid_i ),
|
||||
.asid_to_be_flushed_i ( asid_to_be_flushed_i ),
|
||||
.vaddr_to_be_flushed_i ( vaddr_to_be_flushed_i ),
|
||||
.lu_vaddr_i ( lsu_vaddr_i ),
|
||||
.lu_content_o ( dtlb_content ),
|
||||
.asid_i (asid_i ),
|
||||
// from TLBs
|
||||
// did we miss?
|
||||
.itlb_access_i ( itlb_lu_access ),
|
||||
.itlb_hit_i ( itlb_lu_hit ),
|
||||
.itlb_vaddr_i ( icache_areq_i.fetch_vaddr ),
|
||||
|
||||
.lu_is_4M_o ( dtlb_is_4M ),
|
||||
.lu_hit_o ( dtlb_lu_hit )
|
||||
.dtlb_access_i ( dtlb_lu_access ),
|
||||
.dtlb_hit_i ( dtlb_lu_hit ),
|
||||
.dtlb_vaddr_i ( lsu_vaddr_i ),
|
||||
|
||||
// to TLBs, update logic
|
||||
.itlb_update_o ( update_itlb ),
|
||||
.dtlb_update_o ( update_dtlb ),
|
||||
|
||||
// Performance counters
|
||||
.itlb_miss_o (itlb_miss_o ),
|
||||
.dtlb_miss_o (dtlb_miss_o ),
|
||||
|
||||
.shared_tlb_access_o ( shared_tlb_access ),
|
||||
.shared_tlb_hit_o ( shared_tlb_hit ),
|
||||
.shared_tlb_vaddr_o ( shared_tlb_vaddr ),
|
||||
|
||||
.itlb_req_o ( itlb_req ),
|
||||
// to update shared tlb
|
||||
.shared_tlb_update_i (update_shared_tlb )
|
||||
);
|
||||
|
||||
|
||||
cva6_ptw_sv32 #(
|
||||
.ASID_WIDTH ( ASID_WIDTH ),
|
||||
.ArianeCfg ( ArianeCfg )
|
||||
) i_ptw (
|
||||
.clk_i ( clk_i ),
|
||||
.rst_ni ( rst_ni ),
|
||||
.flush_i ( flush_i ),
|
||||
|
||||
.ptw_active_o ( ptw_active ),
|
||||
.walking_instr_o ( walking_instr ),
|
||||
.ptw_error_o ( ptw_error ),
|
||||
.ptw_access_exception_o ( ptw_access_exception ),
|
||||
.enable_translation_i ( enable_translation_i ),
|
||||
|
||||
.update_vaddr_o ( update_vaddr ),
|
||||
.itlb_update_o ( update_ptw_itlb ),
|
||||
.dtlb_update_o ( update_ptw_dtlb ),
|
||||
|
||||
.itlb_access_i ( itlb_lu_access ),
|
||||
.itlb_hit_i ( itlb_lu_hit ),
|
||||
.itlb_vaddr_i ( icache_areq_i.fetch_vaddr ),
|
||||
|
||||
.dtlb_access_i ( dtlb_lu_access ),
|
||||
.dtlb_hit_i ( dtlb_lu_hit ),
|
||||
.dtlb_vaddr_i ( lsu_vaddr_i ),
|
||||
|
||||
.lsu_is_store_i ( lsu_is_store_i ),
|
||||
// PTW memory interface
|
||||
.req_port_i ( req_port_i ),
|
||||
.req_port_o ( req_port_o ),
|
||||
.pmpcfg_i,
|
||||
.pmpaddr_i,
|
||||
.bad_paddr_o ( ptw_bad_paddr ),
|
||||
.*
|
||||
);
|
||||
|
||||
// to Shared TLB, update logic
|
||||
.shared_tlb_update_o ( update_shared_tlb ),
|
||||
|
||||
.update_vaddr_o ( update_vaddr ),
|
||||
|
||||
.asid_i ( asid_i ),
|
||||
|
||||
// from shared TLB
|
||||
// did we miss?
|
||||
.shared_tlb_access_i ( shared_tlb_access ),
|
||||
.shared_tlb_hit_i ( shared_tlb_hit ),
|
||||
.shared_tlb_vaddr_i ( shared_tlb_vaddr ),
|
||||
|
||||
.itlb_req_i ( itlb_req ),
|
||||
|
||||
// from CSR file
|
||||
.satp_ppn_i ( satp_ppn_i ), // ppn from satp
|
||||
.mxr_i ( mxr_i ),
|
||||
|
||||
// Performance counters
|
||||
.shared_tlb_miss_o ( ), //open for now
|
||||
|
||||
// PMP
|
||||
.pmpcfg_i ( pmpcfg_i ),
|
||||
.pmpaddr_i ( pmpaddr_i ),
|
||||
.bad_paddr_o ( ptw_bad_paddr )
|
||||
|
||||
);
|
||||
|
||||
// ila_1 i_ila_1 (
|
||||
// .clk(clk_i), // input wire clk
|
||||
|
@ -189,8 +249,8 @@ module cva6_mmu_sv32 import ariane_pkg::*; #(
|
|||
// .probe4(req_port_i.data_rvalid), // input wire [0:0] probe4
|
||||
// .probe5(ptw_error), // input wire [1:0] probe5
|
||||
// .probe6(update_vaddr), // input wire [0:0] probe6
|
||||
// .probe7(update_ptw_itlb.valid), // input wire [0:0] probe7
|
||||
// .probe8(update_ptw_dtlb.valid), // input wire [0:0] probe8
|
||||
// .probe7(update_itlb.valid), // input wire [0:0] probe7
|
||||
// .probe8(update_dtlb.valid), // input wire [0:0] probe8
|
||||
// .probe9(dtlb_lu_access), // input wire [0:0] probe9
|
||||
// .probe10(lsu_vaddr_i), // input wire [0:0] probe10
|
||||
// .probe11(dtlb_lu_hit), // input wire [0:0] probe11
|
||||
|
@ -215,8 +275,7 @@ module cva6_mmu_sv32 import ariane_pkg::*; #(
|
|||
// 2. We got an access error because of insufficient permissions -> throw an access exception
|
||||
icache_areq_o.fetch_exception = '0;
|
||||
// Check whether we are allowed to access this memory region from a fetch perspective
|
||||
iaccess_err = icache_areq_i.fetch_req && enable_translation_i
|
||||
&& (((priv_lvl_i == riscv::PRIV_LVL_U) && ~itlb_content.u)
|
||||
iaccess_err = icache_areq_i.fetch_req && (((priv_lvl_i == riscv::PRIV_LVL_U) && ~itlb_content.u)
|
||||
|| ((priv_lvl_i == riscv::PRIV_LVL_S) && itlb_content.u));
|
||||
|
||||
// MMU enabled: address from TLB, request delayed until hit. Error when TLB
|
||||
|
@ -266,7 +325,7 @@ module cva6_mmu_sv32 import ariane_pkg::*; #(
|
|||
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 && !pmp_instr_allow)) begin
|
||||
if (!match_any_execute_region || (!enable_translation_i && !pmp_instr_allow)) begin
|
||||
icache_areq_o.fetch_exception = {riscv::INSTR_ACCESS_FAULT, icache_areq_o.fetch_paddr[riscv::PLEN-1:2], 1'b1};//to check on wave --> not connected
|
||||
end
|
||||
end
|
||||
|
@ -330,7 +389,7 @@ module cva6_mmu_sv32 import ariane_pkg::*; #(
|
|||
|
||||
// Check if the User flag is set, then we may only access it in supervisor mode
|
||||
// if SUM is enabled
|
||||
daccess_err = en_ld_st_translation_i && (ld_st_priv_lvl_i == riscv::PRIV_LVL_S && !sum_i && dtlb_pte_q.u) || // SUM is not set and we are trying to access a user page in supervisor mode
|
||||
daccess_err = (ld_st_priv_lvl_i == riscv::PRIV_LVL_S && !sum_i && dtlb_pte_q.u) || // SUM is not set and we are trying to access a user page in supervisor mode
|
||||
(ld_st_priv_lvl_i == riscv::PRIV_LVL_U && !dtlb_pte_q.u); // this is not a user page but we are in user mode and trying to access it
|
||||
// translation is enabled and no misaligned exception occurred
|
||||
if (en_ld_st_translation_i && !misaligned_ex_q.valid) begin
|
||||
|
|
|
@ -39,39 +39,34 @@ module cva6_ptw_sv32 import ariane_pkg::*; #(
|
|||
output logic walking_instr_o, // set when walking for TLB
|
||||
output logic ptw_error_o, // set when an error occurred
|
||||
output logic ptw_access_exception_o, // set when an PMP access exception occured
|
||||
input logic enable_translation_i, // CSRs indicate to enable SV32
|
||||
input logic en_ld_st_translation_i, // enable virtual memory translation for load/stores
|
||||
|
||||
input logic lsu_is_store_i, // this translation was triggered by a store
|
||||
// PTW memory interface
|
||||
input dcache_req_o_t req_port_i,
|
||||
output dcache_req_i_t req_port_o,
|
||||
|
||||
|
||||
// to TLBs, update logic
|
||||
output tlb_update_sv32_t itlb_update_o,
|
||||
output tlb_update_sv32_t dtlb_update_o,
|
||||
// to Shared TLB, update logic
|
||||
output tlb_update_sv32_t shared_tlb_update_o,
|
||||
|
||||
output logic [riscv::VLEN-1:0] update_vaddr_o,
|
||||
|
||||
input logic [ASID_WIDTH-1:0] asid_i,
|
||||
// from TLBs
|
||||
// did we miss?
|
||||
input logic itlb_access_i,
|
||||
input logic itlb_hit_i,
|
||||
input logic [riscv::VLEN-1:0] itlb_vaddr_i,
|
||||
|
||||
input logic dtlb_access_i,
|
||||
input logic dtlb_hit_i,
|
||||
input logic [riscv::VLEN-1:0] dtlb_vaddr_i,
|
||||
|
||||
// from shared TLB
|
||||
input logic shared_tlb_access_i,
|
||||
input logic shared_tlb_hit_i,
|
||||
input logic [riscv::VLEN-1:0] shared_tlb_vaddr_i,
|
||||
|
||||
input logic itlb_req_i,
|
||||
|
||||
// from CSR file
|
||||
input logic [riscv::PPNW-1:0] satp_ppn_i, // ppn from satp
|
||||
input logic mxr_i,
|
||||
// Performance counters
|
||||
output logic itlb_miss_o,
|
||||
output logic dtlb_miss_o,
|
||||
// PMP
|
||||
|
||||
// Performance counters
|
||||
output logic shared_tlb_miss_o,
|
||||
|
||||
// PMP
|
||||
input riscv::pmpcfg_t [15:0] pmpcfg_i,
|
||||
input logic [15:0][riscv::PLEN-3:0] pmpaddr_i,
|
||||
output logic [riscv::PLEN-1:0] bad_paddr_o
|
||||
|
@ -92,7 +87,8 @@ module cva6_ptw_sv32 import ariane_pkg::*; #(
|
|||
PTE_LOOKUP,
|
||||
WAIT_RVALID,
|
||||
PROPAGATE_ERROR,
|
||||
PROPAGATE_ACCESS_ERROR
|
||||
PROPAGATE_ACCESS_ERROR,
|
||||
LATENCY
|
||||
} state_q, state_d;
|
||||
|
||||
// SV32 defines two levels of page tables
|
||||
|
@ -116,6 +112,7 @@ module cva6_ptw_sv32 import ariane_pkg::*; #(
|
|||
assign update_vaddr_o = vaddr_q;
|
||||
|
||||
assign ptw_active_o = (state_q != IDLE);
|
||||
//assign walking_instr_o = is_instr_ptw_q;
|
||||
assign walking_instr_o = is_instr_ptw_q;
|
||||
// directly output the correct physical address
|
||||
assign req_port_o.address_index = ptw_pptr_q[DCACHE_INDEX_WIDTH-1:0];
|
||||
|
@ -124,20 +121,18 @@ module cva6_ptw_sv32 import ariane_pkg::*; #(
|
|||
assign req_port_o.kill_req = '0;
|
||||
// we are never going to write with the HPTW
|
||||
assign req_port_o.data_wdata = '0;
|
||||
|
||||
// -----------
|
||||
// TLB Update
|
||||
// Shared TLB Update
|
||||
// -----------
|
||||
assign itlb_update_o.vpn = vaddr_q[riscv::SV-1:12];
|
||||
assign dtlb_update_o.vpn = vaddr_q[riscv::SV-1:12];
|
||||
assign shared_tlb_update_o.vpn = vaddr_q[riscv::SV-1:12];
|
||||
// update the correct page table level
|
||||
assign itlb_update_o.is_4M = (ptw_lvl_q == LVL1);
|
||||
assign dtlb_update_o.is_4M = (ptw_lvl_q == LVL1);
|
||||
assign shared_tlb_update_o.is_4M = (ptw_lvl_q == LVL1);
|
||||
// output the correct ASID
|
||||
assign itlb_update_o.asid = tlb_update_asid_q;
|
||||
assign dtlb_update_o.asid = tlb_update_asid_q;
|
||||
assign shared_tlb_update_o.asid = tlb_update_asid_q;
|
||||
// set the global mapping bit
|
||||
assign itlb_update_o.content = pte | (global_mapping_q << 5);
|
||||
assign dtlb_update_o.content = pte | (global_mapping_q << 5);
|
||||
assign shared_tlb_update_o.content = pte | (global_mapping_q << 5);
|
||||
|
||||
|
||||
assign req_port_o.tag_valid = tag_valid_q;
|
||||
|
||||
|
@ -190,25 +185,23 @@ module cva6_ptw_sv32 import ariane_pkg::*; #(
|
|||
always_comb begin : ptw
|
||||
// default assignments
|
||||
// PTW memory interface
|
||||
tag_valid_n = 1'b0;
|
||||
req_port_o.data_req = 1'b0;
|
||||
req_port_o.data_size = 2'b10;
|
||||
req_port_o.data_we = 1'b0;
|
||||
ptw_error_o = 1'b0;
|
||||
ptw_access_exception_o = 1'b0;
|
||||
itlb_update_o.valid = 1'b0;
|
||||
dtlb_update_o.valid = 1'b0;
|
||||
is_instr_ptw_n = is_instr_ptw_q;
|
||||
ptw_lvl_n = ptw_lvl_q;
|
||||
ptw_pptr_n = ptw_pptr_q;
|
||||
state_d = state_q;
|
||||
global_mapping_n = global_mapping_q;
|
||||
tag_valid_n = 1'b0;
|
||||
req_port_o.data_req = 1'b0;
|
||||
req_port_o.data_size = 2'b10;
|
||||
req_port_o.data_we = 1'b0;
|
||||
ptw_error_o = 1'b0;
|
||||
ptw_access_exception_o = 1'b0;
|
||||
shared_tlb_update_o.valid = 1'b0;
|
||||
is_instr_ptw_n = is_instr_ptw_q;
|
||||
ptw_lvl_n = ptw_lvl_q;
|
||||
ptw_pptr_n = ptw_pptr_q;
|
||||
state_d = state_q;
|
||||
global_mapping_n = global_mapping_q;
|
||||
// input registers
|
||||
tlb_update_asid_n = tlb_update_asid_q;
|
||||
vaddr_n = vaddr_q;
|
||||
tlb_update_asid_n = tlb_update_asid_q;
|
||||
vaddr_n = vaddr_q;
|
||||
|
||||
itlb_miss_o = 1'b0;
|
||||
dtlb_miss_o = 1'b0;
|
||||
shared_tlb_miss_o = 1'b0;
|
||||
|
||||
case (state_q)
|
||||
|
||||
|
@ -217,21 +210,14 @@ module cva6_ptw_sv32 import ariane_pkg::*; #(
|
|||
ptw_lvl_n = LVL1;
|
||||
global_mapping_n = 1'b0;
|
||||
is_instr_ptw_n = 1'b0;
|
||||
// if we got an ITLB miss
|
||||
if (enable_translation_i & itlb_access_i & ~itlb_hit_i & ~dtlb_access_i) begin
|
||||
ptw_pptr_n = {satp_ppn_i, itlb_vaddr_i[riscv::SV-1:22], 2'b0}; // SATP.PPN * PAGESIZE + VPN*PTESIZE = SATP.PPN * 2^(12) + VPN*4
|
||||
is_instr_ptw_n = 1'b1;
|
||||
// if we got a Shared TLB miss
|
||||
if (shared_tlb_access_i & ~shared_tlb_hit_i) begin
|
||||
ptw_pptr_n = {satp_ppn_i, shared_tlb_vaddr_i[riscv::SV-1:22], 2'b0}; // SATP.PPN * PAGESIZE + VPN*PTESIZE = SATP.PPN * 2^(12) + VPN*4
|
||||
is_instr_ptw_n = itlb_req_i;
|
||||
tlb_update_asid_n = asid_i;
|
||||
vaddr_n = itlb_vaddr_i;
|
||||
vaddr_n = shared_tlb_vaddr_i;
|
||||
state_d = WAIT_GRANT;
|
||||
itlb_miss_o = 1'b1;
|
||||
// we got an DTLB miss
|
||||
end else if (en_ld_st_translation_i & dtlb_access_i & ~dtlb_hit_i) begin
|
||||
ptw_pptr_n = {satp_ppn_i, dtlb_vaddr_i[riscv::SV-1:22], 2'b0}; // SATP.PPN * PAGESIZE + VPN*PTESIZE = SATP.PPN * 2^(12) + VPN*4
|
||||
tlb_update_asid_n = asid_i;
|
||||
vaddr_n = dtlb_vaddr_i;
|
||||
state_d = WAIT_GRANT;
|
||||
dtlb_miss_o = 1'b1;
|
||||
shared_tlb_miss_o = 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -264,7 +250,8 @@ module cva6_ptw_sv32 import ariane_pkg::*; #(
|
|||
// Valid PTE
|
||||
// -----------
|
||||
else begin
|
||||
state_d = IDLE;
|
||||
//state_d = IDLE;
|
||||
state_d = LATENCY;
|
||||
// it is a valid PTE
|
||||
// if pte.r = 1 or pte.x = 1 it is a valid PTE
|
||||
if (pte.r || pte.x) begin
|
||||
|
@ -279,7 +266,7 @@ module cva6_ptw_sv32 import ariane_pkg::*; #(
|
|||
if (!pte.x || !pte.a)
|
||||
state_d = PROPAGATE_ERROR;
|
||||
else
|
||||
itlb_update_o.valid = 1'b1;
|
||||
shared_tlb_update_o.valid = 1'b1;
|
||||
|
||||
end else begin
|
||||
// ------------
|
||||
|
@ -291,7 +278,7 @@ module cva6_ptw_sv32 import ariane_pkg::*; #(
|
|||
// we can directly raise an error. This doesn't put a useless
|
||||
// entry into the TLB.
|
||||
if (pte.a && (pte.r || (pte.x && mxr_i))) begin
|
||||
dtlb_update_o.valid = 1'b1;
|
||||
shared_tlb_update_o.valid = 1'b1;
|
||||
end else begin
|
||||
state_d = PROPAGATE_ERROR;
|
||||
end
|
||||
|
@ -299,7 +286,7 @@ module cva6_ptw_sv32 import ariane_pkg::*; #(
|
|||
// If the request was a store and the page is not write-able, raise an error
|
||||
// the same applies if the dirty flag is not set
|
||||
if (lsu_is_store_i && (!pte.w || !pte.d)) begin
|
||||
dtlb_update_o.valid = 1'b0;
|
||||
shared_tlb_update_o.valid = 1'b0;
|
||||
state_d = PROPAGATE_ERROR;
|
||||
end
|
||||
end
|
||||
|
@ -308,8 +295,7 @@ module cva6_ptw_sv32 import ariane_pkg::*; #(
|
|||
// exception.
|
||||
if (ptw_lvl_q == LVL1 && pte.ppn[9:0] != '0) begin
|
||||
state_d = PROPAGATE_ERROR;
|
||||
dtlb_update_o.valid = 1'b0;
|
||||
itlb_update_o.valid = 1'b0;
|
||||
shared_tlb_update_o.valid = 1'b0;
|
||||
end
|
||||
// this is a pointer to the next TLB level
|
||||
end else begin
|
||||
|
@ -332,8 +318,7 @@ module cva6_ptw_sv32 import ariane_pkg::*; #(
|
|||
|
||||
// Check if this access was actually allowed from a PMP perspective
|
||||
if (!allow_access) begin
|
||||
itlb_update_o.valid = 1'b0;
|
||||
dtlb_update_o.valid = 1'b0;
|
||||
shared_tlb_update_o.valid = 1'b0;
|
||||
// we have to return the failed address in bad_addr
|
||||
ptw_pptr_n = ptw_pptr_q;
|
||||
state_d = PROPAGATE_ACCESS_ERROR;
|
||||
|
@ -343,17 +328,20 @@ module cva6_ptw_sv32 import ariane_pkg::*; #(
|
|||
end
|
||||
// Propagate error to MMU/LSU
|
||||
PROPAGATE_ERROR: begin
|
||||
state_d = IDLE;
|
||||
state_d = LATENCY;
|
||||
ptw_error_o = 1'b1;
|
||||
end
|
||||
PROPAGATE_ACCESS_ERROR: begin
|
||||
state_d = IDLE;
|
||||
state_d = LATENCY;
|
||||
ptw_access_exception_o = 1'b1;
|
||||
end
|
||||
// wait for the rvalid before going back to IDLE
|
||||
WAIT_RVALID: begin
|
||||
if (data_rvalid_q)
|
||||
state_d = IDLE;
|
||||
end
|
||||
LATENCY: begin
|
||||
state_d = IDLE;
|
||||
end
|
||||
default: begin
|
||||
state_d = IDLE;
|
||||
|
@ -372,7 +360,7 @@ module cva6_ptw_sv32 import ariane_pkg::*; #(
|
|||
if ((state_q == PTE_LOOKUP && !data_rvalid_q) || ((state_q == WAIT_GRANT) && req_port_i.data_gnt))
|
||||
state_d = WAIT_RVALID;
|
||||
else
|
||||
state_d = IDLE;
|
||||
state_d = LATENCY;
|
||||
end
|
||||
end
|
||||
|
||||
|
|
364
core/mmu_sv32/cva6_shared_tlb_sv32.sv
Normal file
364
core/mmu_sv32/cva6_shared_tlb_sv32.sv
Normal file
|
@ -0,0 +1,364 @@
|
|||
// Copyright (c) 2023 Thales.
|
||||
// Copyright and related rights are licensed under the Solderpad Hardware
|
||||
// License, Version 0.51 (the "License"); you may not use this file except in
|
||||
// compliance with the License. You may obtain a copy of the License at
|
||||
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
|
||||
// or agreed to in writing, software, hardware and materials distributed under
|
||||
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
//
|
||||
// Author: Sebastien Jacq - Thales Research & Technology
|
||||
// Date: 08/03/2023
|
||||
//
|
||||
// Description: N-way associative shared TLB, it allows to reduce the number
|
||||
// of ITLB and DTLB entries.
|
||||
//
|
||||
|
||||
/* verilator lint_off WIDTH */
|
||||
|
||||
module cva6_shared_tlb_sv32 import ariane_pkg::*; #(
|
||||
parameter int SHARED_TLB_DEPTH = 64,
|
||||
parameter int SHARED_TLB_WAYS = 2,
|
||||
parameter int ASID_WIDTH = 1,
|
||||
parameter ariane_pkg::ariane_cfg_t ArianeCfg = ariane_pkg::ArianeDefaultConfig
|
||||
) (
|
||||
input logic clk_i, // Clock
|
||||
input logic rst_ni, // Asynchronous reset active low
|
||||
input logic flush_i,
|
||||
|
||||
input logic enable_translation_i, // CSRs indicate to enable SV32
|
||||
input logic en_ld_st_translation_i, // enable virtual memory translation for load/stores
|
||||
|
||||
input logic [ASID_WIDTH-1:0] asid_i,
|
||||
|
||||
// from TLBs
|
||||
// did we miss?
|
||||
input logic itlb_access_i,
|
||||
input logic itlb_hit_i,
|
||||
input logic [riscv::VLEN-1:0] itlb_vaddr_i,
|
||||
|
||||
input logic dtlb_access_i,
|
||||
input logic dtlb_hit_i,
|
||||
input logic [riscv::VLEN-1:0] dtlb_vaddr_i,
|
||||
|
||||
// to TLBs, update logic
|
||||
output tlb_update_sv32_t itlb_update_o,
|
||||
output tlb_update_sv32_t dtlb_update_o,
|
||||
|
||||
// Performance counters
|
||||
output logic itlb_miss_o,
|
||||
output logic dtlb_miss_o,
|
||||
|
||||
output logic shared_tlb_access_o,
|
||||
output logic shared_tlb_hit_o,
|
||||
output logic [riscv::VLEN-1:0] shared_tlb_vaddr_o,
|
||||
|
||||
output logic itlb_req_o,
|
||||
|
||||
// Update shared TLB in case of miss
|
||||
input tlb_update_sv32_t shared_tlb_update_i
|
||||
|
||||
);
|
||||
|
||||
function logic [SHARED_TLB_WAYS-1:0] shared_tlb_way_bin2oh ( input logic [$clog2(SHARED_TLB_WAYS)-1:0] in);
|
||||
logic [SHARED_TLB_WAYS-1:0] out;
|
||||
out = '0;
|
||||
out[in] = 1'b1;
|
||||
return out;
|
||||
endfunction
|
||||
|
||||
typedef struct packed {
|
||||
logic [8:0] asid; //9 bits wide
|
||||
logic [9:0] vpn1; //10 bits wide
|
||||
logic [9:0] vpn0; //10 bits wide
|
||||
logic is_4M;
|
||||
} shared_tag_t;
|
||||
|
||||
shared_tag_t shared_tag_wr;
|
||||
shared_tag_t [SHARED_TLB_WAYS-1:0] shared_tag_rd;
|
||||
|
||||
logic [SHARED_TLB_DEPTH-1:0][SHARED_TLB_WAYS-1:0] shared_tag_valid_q, shared_tag_valid_d ;
|
||||
|
||||
logic [SHARED_TLB_WAYS-1:0] shared_tag_valid;
|
||||
|
||||
logic [SHARED_TLB_WAYS-1:0] tag_wr_en;
|
||||
logic [$clog2(SHARED_TLB_DEPTH)-1:0] tag_wr_addr;
|
||||
logic [$bits(shared_tag_t)-1:0] tag_wr_data;
|
||||
|
||||
logic [SHARED_TLB_WAYS-1:0] tag_rd_en;
|
||||
logic [$clog2(SHARED_TLB_DEPTH)-1:0] tag_rd_addr;
|
||||
logic [$bits(shared_tag_t)-1:0] tag_rd_data [SHARED_TLB_WAYS-1:0];
|
||||
|
||||
logic [SHARED_TLB_WAYS-1:0] tag_req;
|
||||
logic [SHARED_TLB_WAYS-1:0] tag_we;
|
||||
logic [$clog2(SHARED_TLB_DEPTH)-1:0] tag_addr;
|
||||
|
||||
logic [SHARED_TLB_WAYS-1:0] pte_wr_en;
|
||||
logic [$clog2(SHARED_TLB_DEPTH)-1:0] pte_wr_addr;
|
||||
logic [$bits(riscv::pte_sv32_t)-1:0] pte_wr_data;
|
||||
|
||||
logic [SHARED_TLB_WAYS-1:0] pte_rd_en;
|
||||
logic [$clog2(SHARED_TLB_DEPTH)-1:0] pte_rd_addr;
|
||||
logic [$bits(riscv::pte_sv32_t)-1:0] pte_rd_data [SHARED_TLB_WAYS-1:0];
|
||||
|
||||
logic [SHARED_TLB_WAYS-1:0] pte_req;
|
||||
logic [SHARED_TLB_WAYS-1:0] pte_we;
|
||||
logic [$clog2(SHARED_TLB_DEPTH)-1:0] pte_addr;
|
||||
|
||||
logic [9:0] vpn0_d, vpn1_d, vpn0_q, vpn1_q;
|
||||
|
||||
riscv::pte_sv32_t [SHARED_TLB_WAYS-1:0] pte;
|
||||
|
||||
logic [riscv::VLEN-1-12:0] itlb_vpn_q;
|
||||
logic [riscv::VLEN-1-12:0] dtlb_vpn_q;
|
||||
|
||||
logic [ASID_WIDTH-1:0] tlb_update_asid_q, tlb_update_asid_d;
|
||||
|
||||
logic shared_tlb_access_q, shared_tlb_access_d;
|
||||
logic shared_tlb_hit_d;
|
||||
logic [riscv::VLEN-1:0] shared_tlb_vaddr_q, shared_tlb_vaddr_d;
|
||||
|
||||
logic itlb_req_d, itlb_req_q;
|
||||
logic dtlb_req_d, dtlb_req_q;
|
||||
|
||||
// replacement strategy
|
||||
logic [SHARED_TLB_WAYS-1:0] way_valid;
|
||||
logic update_lfsr; // shift the LFSR
|
||||
logic [$clog2(SHARED_TLB_WAYS)-1:0] inv_way; // first non-valid encountered
|
||||
logic [$clog2(SHARED_TLB_WAYS)-1:0] rnd_way; // random index for replacement
|
||||
logic [$clog2(SHARED_TLB_WAYS)-1:0] repl_way; // way to replace
|
||||
logic [SHARED_TLB_WAYS-1:0] repl_way_oh_d; // way to replace (onehot)
|
||||
logic all_ways_valid; // we need to switch repl strategy since all are valid
|
||||
|
||||
assign shared_tlb_access_o = shared_tlb_access_q;
|
||||
assign shared_tlb_hit_o = shared_tlb_hit_d;
|
||||
assign shared_tlb_vaddr_o = shared_tlb_vaddr_q;
|
||||
|
||||
assign itlb_req_o = itlb_req_q;
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
// tag comparison, hit generation
|
||||
///////////////////////////////////////////////////////
|
||||
always_comb begin : itlb_dtlb_miss
|
||||
itlb_miss_o = 1'b0;
|
||||
dtlb_miss_o = 1'b0;
|
||||
vpn0_d = vpn0_q;
|
||||
vpn1_d = vpn1_q;
|
||||
|
||||
tag_rd_en = '0;
|
||||
pte_rd_en = '0;
|
||||
|
||||
itlb_req_d = 1'b0;
|
||||
dtlb_req_d = 1'b0;
|
||||
|
||||
tlb_update_asid_d = tlb_update_asid_q;
|
||||
|
||||
shared_tlb_access_d = '0;
|
||||
shared_tlb_vaddr_d = shared_tlb_vaddr_q;
|
||||
|
||||
tag_rd_addr = '0;
|
||||
pte_rd_addr = '0;
|
||||
|
||||
// if we got an ITLB miss
|
||||
if (enable_translation_i & itlb_access_i & ~itlb_hit_i & ~dtlb_access_i) begin
|
||||
tag_rd_en = '1;
|
||||
tag_rd_addr = itlb_vaddr_i[12+:$clog2(SHARED_TLB_DEPTH)];
|
||||
pte_rd_en = '1;
|
||||
pte_rd_addr = itlb_vaddr_i[12+:$clog2(SHARED_TLB_DEPTH)];
|
||||
|
||||
vpn0_d = itlb_vaddr_i[21:12];
|
||||
vpn1_d = itlb_vaddr_i[31:22];
|
||||
|
||||
itlb_miss_o = 1'b1;
|
||||
itlb_req_d = 1'b1;
|
||||
|
||||
tlb_update_asid_d = asid_i;
|
||||
|
||||
shared_tlb_access_d = 1'b1;
|
||||
shared_tlb_vaddr_d = itlb_vaddr_i;
|
||||
|
||||
// we got an DTLB miss
|
||||
end else if (en_ld_st_translation_i & dtlb_access_i & ~dtlb_hit_i) begin
|
||||
tag_rd_en = '1;
|
||||
tag_rd_addr = dtlb_vaddr_i[12+:$clog2(SHARED_TLB_DEPTH)];
|
||||
pte_rd_en = '1;
|
||||
pte_rd_addr = dtlb_vaddr_i[12+:$clog2(SHARED_TLB_DEPTH)];
|
||||
|
||||
vpn0_d = dtlb_vaddr_i[21:12];
|
||||
vpn1_d = dtlb_vaddr_i[31:22];
|
||||
|
||||
dtlb_miss_o = 1'b1;
|
||||
dtlb_req_d = 1'b1;
|
||||
|
||||
tlb_update_asid_d = asid_i;
|
||||
|
||||
shared_tlb_access_d = 1'b1;
|
||||
shared_tlb_vaddr_d = dtlb_vaddr_i;
|
||||
end
|
||||
end //itlb_dtlb_miss
|
||||
|
||||
always_comb begin : tag_comparison
|
||||
shared_tlb_hit_d = 1'b0;
|
||||
dtlb_update_o = '0;
|
||||
itlb_update_o = '0;
|
||||
//number of ways
|
||||
for (int unsigned i = 0; i < SHARED_TLB_WAYS; i++) begin
|
||||
if (shared_tag_valid[i] && ((tlb_update_asid_q == shared_tag_rd[i].asid) || pte[i].g) && vpn1_q == shared_tag_rd[i].vpn1) begin
|
||||
if (shared_tag_rd[i].is_4M || vpn0_q == shared_tag_rd[i].vpn0) begin
|
||||
shared_tlb_hit_d = 1'b1;
|
||||
if (itlb_req_q) begin
|
||||
itlb_update_o.valid = 1'b1;
|
||||
itlb_update_o.vpn = itlb_vpn_q;
|
||||
itlb_update_o.is_4M = shared_tag_rd[i].is_4M;
|
||||
itlb_update_o.asid = tlb_update_asid_q;
|
||||
itlb_update_o.content = pte[i];
|
||||
end else if (dtlb_req_q) begin
|
||||
dtlb_update_o.valid = 1'b1;
|
||||
dtlb_update_o.vpn = dtlb_vpn_q;
|
||||
dtlb_update_o.is_4M = shared_tag_rd[i].is_4M;
|
||||
dtlb_update_o.asid = tlb_update_asid_q;
|
||||
dtlb_update_o.content = pte[i];
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end //tag_comparison
|
||||
|
||||
// sequential process
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (~rst_ni) begin
|
||||
itlb_vpn_q <= '0;
|
||||
dtlb_vpn_q <= '0;
|
||||
tlb_update_asid_q <= '0;
|
||||
shared_tlb_access_q <= '0;
|
||||
shared_tlb_vaddr_q <= '0;
|
||||
shared_tag_valid_q <= '0;
|
||||
vpn0_q <= '0;
|
||||
vpn1_q <= '0;
|
||||
itlb_req_q <= '0;
|
||||
dtlb_req_q <= '0;
|
||||
shared_tag_valid <= '0;
|
||||
end else begin
|
||||
itlb_vpn_q <= itlb_vaddr_i[riscv::SV-1:12];
|
||||
dtlb_vpn_q <= dtlb_vaddr_i[riscv::SV-1:12];
|
||||
tlb_update_asid_q <= tlb_update_asid_d;
|
||||
shared_tlb_access_q <= shared_tlb_access_d;
|
||||
shared_tlb_vaddr_q <= shared_tlb_vaddr_d;
|
||||
shared_tag_valid_q <= shared_tag_valid_d;
|
||||
vpn0_q <= vpn0_d;
|
||||
vpn1_q <= vpn1_d;
|
||||
itlb_req_q <= itlb_req_d;
|
||||
dtlb_req_q <= dtlb_req_d;
|
||||
shared_tag_valid <= shared_tag_valid_q[tag_rd_addr];
|
||||
end
|
||||
end
|
||||
|
||||
// ------------------
|
||||
// Update and Flush
|
||||
// ------------------
|
||||
always_comb begin : update_flush
|
||||
shared_tag_valid_d = shared_tag_valid_q;
|
||||
tag_wr_en = '0;
|
||||
pte_wr_en = '0;
|
||||
|
||||
if (flush_i) begin
|
||||
shared_tag_valid_d = '0;
|
||||
end else if (shared_tlb_update_i.valid) begin
|
||||
for (int unsigned i = 0; i < SHARED_TLB_WAYS; i++) begin
|
||||
if (repl_way_oh_d[i]) begin
|
||||
shared_tag_valid_d[shared_tlb_update_i.vpn[$clog2(SHARED_TLB_DEPTH)-1:0]][i] = 1'b1;
|
||||
tag_wr_en[i] = 1'b1;
|
||||
pte_wr_en[i] = 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
end //update_flush
|
||||
|
||||
assign shared_tag_wr.asid = shared_tlb_update_i.asid;
|
||||
assign shared_tag_wr.vpn1 = shared_tlb_update_i.vpn[19:10];
|
||||
assign shared_tag_wr.vpn0 = shared_tlb_update_i.vpn[9:0];
|
||||
assign shared_tag_wr.is_4M = shared_tlb_update_i.is_4M;
|
||||
|
||||
assign tag_wr_addr = shared_tlb_update_i.vpn[$clog2(SHARED_TLB_DEPTH)-1:0];
|
||||
assign tag_wr_data = shared_tag_wr;
|
||||
|
||||
assign pte_wr_addr = shared_tlb_update_i.vpn[$clog2(SHARED_TLB_DEPTH)-1:0];
|
||||
assign pte_wr_data = shared_tlb_update_i.content;
|
||||
|
||||
assign way_valid = shared_tag_valid_q[shared_tlb_update_i.vpn[$clog2(SHARED_TLB_DEPTH)-1:0]];
|
||||
assign repl_way = (all_ways_valid) ? rnd_way : inv_way;
|
||||
assign update_lfsr = shared_tlb_update_i.valid & all_ways_valid;
|
||||
assign repl_way_oh_d = (shared_tlb_update_i.valid) ? shared_tlb_way_bin2oh(repl_way) : '0;
|
||||
|
||||
lzc #(
|
||||
.WIDTH ( SHARED_TLB_WAYS )
|
||||
) i_lzc (
|
||||
.in_i ( ~way_valid ),
|
||||
.cnt_o ( inv_way ),
|
||||
.empty_o ( all_ways_valid )
|
||||
);
|
||||
|
||||
lfsr #(
|
||||
.LfsrWidth ( 8 ),
|
||||
.OutWidth ( $clog2(SHARED_TLB_WAYS))
|
||||
) i_lfsr (
|
||||
.clk_i ( clk_i ),
|
||||
.rst_ni ( rst_ni ),
|
||||
.en_i ( update_lfsr ),
|
||||
.out_o ( rnd_way )
|
||||
);
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
// memory arrays and regs
|
||||
///////////////////////////////////////////////////////
|
||||
|
||||
assign tag_req = tag_wr_en | tag_rd_en;
|
||||
assign tag_we = tag_wr_en;
|
||||
assign tag_addr = tag_wr_en ? tag_wr_addr : tag_rd_addr;
|
||||
|
||||
assign pte_req = pte_wr_en | pte_rd_en;
|
||||
assign pte_we = pte_wr_en;
|
||||
assign pte_addr = pte_wr_en ? pte_wr_addr : pte_rd_addr;
|
||||
|
||||
for (genvar i = 0; i < SHARED_TLB_WAYS; i++) begin : gen_sram
|
||||
// Tag RAM
|
||||
sram #(
|
||||
.DATA_WIDTH ( $bits(shared_tag_t) ),
|
||||
.NUM_WORDS ( SHARED_TLB_DEPTH )
|
||||
) tag_sram (
|
||||
.clk_i ( clk_i ),
|
||||
.rst_ni ( rst_ni ),
|
||||
.req_i ( tag_req[i] ),
|
||||
.we_i ( tag_we[i] ),
|
||||
.addr_i ( tag_addr ),
|
||||
.wuser_i ( '0 ),
|
||||
.wdata_i ( tag_wr_data ),
|
||||
.be_i ( '1 ),
|
||||
.ruser_o ( ),
|
||||
.rdata_o ( tag_rd_data[i] )
|
||||
);
|
||||
|
||||
assign shared_tag_rd[i] = shared_tag_t'(tag_rd_data[i]);
|
||||
|
||||
// PTE RAM
|
||||
sram #(
|
||||
.DATA_WIDTH ( $bits(riscv::pte_sv32_t) ),
|
||||
.NUM_WORDS ( SHARED_TLB_DEPTH )
|
||||
) pte_sram (
|
||||
.clk_i ( clk_i ),
|
||||
.rst_ni ( rst_ni ),
|
||||
.req_i ( pte_req[i] ),
|
||||
.we_i ( pte_we[i] ),
|
||||
.addr_i ( pte_addr ),
|
||||
.wuser_i ( '0 ),
|
||||
.wdata_i ( pte_wr_data ),
|
||||
.be_i ( '1 ),
|
||||
.ruser_o ( ),
|
||||
.rdata_o ( pte_rd_data[i] )
|
||||
);
|
||||
assign pte[i] = riscv::pte_sv32_t'(pte_rd_data[i]);
|
||||
end
|
||||
endmodule
|
||||
|
||||
/* verilator lint_on WIDTH */
|
Loading…
Add table
Reference in a new issue