mirror of
https://github.com/openhwgroup/cva6.git
synced 2025-06-27 17:00:57 -04:00
PTW: Coding style + H-Mode fixes (#2978)
Break-down of #2933 : PTW changes only: walks on intermediate nodes during G-translation do no generate faults if R/D/X bits is not set and request is a store (fixes [BUG] Wrong permission check walking HGATP #2910) walks on intermediate nodes during G-translation do no generate faults if X bits is not set and request is an execute Code style: gather requests to the TLB in a single process instead of scattered signals add more comments --------- Co-authored-by: JeanRochCoulon <jean-roch.coulon@thalesgroup.com>
This commit is contained in:
parent
b484f5f3ee
commit
c76b568bbd
1 changed files with 59 additions and 56 deletions
|
@ -49,9 +49,9 @@ module cva6_ptw
|
|||
input logic ld_st_v_i, // load/store virtualization mode bit
|
||||
input logic hlvx_inst_i, // is a HLVX load/store instruction
|
||||
|
||||
input logic lsu_is_store_i, // this translation was triggered by a store
|
||||
input logic lsu_is_store_i, // this translation was triggered by a store
|
||||
// PTW memory interface
|
||||
input dcache_req_o_t req_port_i,
|
||||
input dcache_req_o_t req_port_i,
|
||||
output dcache_req_i_t req_port_o,
|
||||
|
||||
|
||||
|
@ -74,7 +74,7 @@ module cva6_ptw
|
|||
|
||||
// from CSR file
|
||||
input logic [CVA6Cfg.PPNW-1:0] satp_ppn_i, // ppn from satp
|
||||
input logic [CVA6Cfg.PPNW-1:0] vsatp_ppn_i, // ppn from satp
|
||||
input logic [CVA6Cfg.PPNW-1:0] vsatp_ppn_i, // ppn from vsatp
|
||||
input logic [CVA6Cfg.PPNW-1:0] hgatp_ppn_i, // ppn from hgatp
|
||||
input logic mxr_i,
|
||||
input logic vmxr_i,
|
||||
|
@ -110,6 +110,7 @@ module cva6_ptw
|
|||
state_q, state_d;
|
||||
|
||||
logic [CVA6Cfg.PtLevels-2:0] misaligned_page;
|
||||
logic shared_tlb_update_valid;
|
||||
logic [HYP_EXT:0][CVA6Cfg.PtLevels-2:0] ptw_lvl_n, ptw_lvl_q;
|
||||
|
||||
// define 3 PTW stages to be used in sv39x4. sv32 and sv39 are always in S_STAGE
|
||||
|
@ -163,7 +164,6 @@ module cva6_ptw
|
|||
|
||||
assign gpaddr_base = {pte.ppn[CVA6Cfg.GPPNW-1:0], vaddr_q[11:0]};
|
||||
assign gpaddr[CVA6Cfg.PtLevels-1] = gpaddr_base;
|
||||
assign shared_tlb_update_o.vpn = CVA6Cfg.VpnLen'(vaddr_q[CVA6Cfg.SV+HYP_EXT*2-1:12]);
|
||||
|
||||
genvar z, w;
|
||||
generate
|
||||
|
@ -174,16 +174,16 @@ module cva6_ptw
|
|||
// exception.
|
||||
assign misaligned_page[z] = (ptw_lvl_q[0] == (z)) && (pte.ppn[(CVA6Cfg.VpnLen/CVA6Cfg.PtLevels)*(CVA6Cfg.PtLevels-1-z)-1:0] != '0);
|
||||
|
||||
//record the vaddr corresponding to each level
|
||||
// record the vaddr corresponding to each level
|
||||
for (w = 0; w < HYP_EXT * 2 + 1; w++) begin
|
||||
assign vaddr_lvl[w][z] = w==0 ? vaddr_q[12+((CVA6Cfg.VpnLen/CVA6Cfg.PtLevels)*(CVA6Cfg.PtLevels-z-1))-1:12+((CVA6Cfg.VpnLen/CVA6Cfg.PtLevels)*(CVA6Cfg.PtLevels-z-2))] :
|
||||
w==1 ? gptw_pptr_q[12+((CVA6Cfg.VpnLen/CVA6Cfg.PtLevels)*(CVA6Cfg.PtLevels-z-1))-1:12+((CVA6Cfg.VpnLen/CVA6Cfg.PtLevels)*(CVA6Cfg.PtLevels-z-2))]:
|
||||
gpaddr_q[12+((CVA6Cfg.VpnLen/CVA6Cfg.PtLevels)*(CVA6Cfg.PtLevels-z-1))-1:12+((CVA6Cfg.VpnLen/CVA6Cfg.PtLevels)*(CVA6Cfg.PtLevels-z-2))];
|
||||
assign vaddr_lvl[w][z] = w==0 ? vaddr_q[12+((CVA6Cfg.VpnLen/CVA6Cfg.PtLevels)*(CVA6Cfg.PtLevels-z-1))-1:12+((CVA6Cfg.VpnLen/CVA6Cfg.PtLevels)*(CVA6Cfg.PtLevels-z-2))]:
|
||||
w==1 ? gptw_pptr_q[12+((CVA6Cfg.VpnLen/CVA6Cfg.PtLevels)*(CVA6Cfg.PtLevels-z-1))-1:12+((CVA6Cfg.VpnLen/CVA6Cfg.PtLevels)*(CVA6Cfg.PtLevels-z-2))]:
|
||||
gpaddr_q[12+((CVA6Cfg.VpnLen/CVA6Cfg.PtLevels)*(CVA6Cfg.PtLevels-z-1))-1:12+((CVA6Cfg.VpnLen/CVA6Cfg.PtLevels)*(CVA6Cfg.PtLevels-z-2))];
|
||||
end
|
||||
|
||||
if (CVA6Cfg.RVH) begin
|
||||
assign gpaddr[z][CVA6Cfg.VpnLen-(CVA6Cfg.VpnLen/CVA6Cfg.PtLevels):0]= (ptw_lvl_q[0] == z) ? vaddr_q[CVA6Cfg.VpnLen-(CVA6Cfg.VpnLen/CVA6Cfg.PtLevels):0] : gpaddr_base[CVA6Cfg.VpnLen-(CVA6Cfg.VpnLen/CVA6Cfg.PtLevels):0];
|
||||
assign gpaddr[z][CVA6Cfg.VpnLen:CVA6Cfg.VpnLen-(CVA6Cfg.VpnLen/CVA6Cfg.PtLevels)+1]= (ptw_lvl_q[0] == 0) ? vaddr_q[CVA6Cfg.VpnLen:CVA6Cfg.VpnLen-(CVA6Cfg.VpnLen/CVA6Cfg.PtLevels)+1] : gpaddr_base[CVA6Cfg.VpnLen:CVA6Cfg.VpnLen-(CVA6Cfg.VpnLen/CVA6Cfg.PtLevels)+1];
|
||||
assign gpaddr[z][CVA6Cfg.VpnLen-(CVA6Cfg.VpnLen/CVA6Cfg.PtLevels):0] = (ptw_lvl_q[0] == z) ? vaddr_q[CVA6Cfg.VpnLen-(CVA6Cfg.VpnLen/CVA6Cfg.PtLevels):0] : gpaddr_base[CVA6Cfg.VpnLen-(CVA6Cfg.VpnLen/CVA6Cfg.PtLevels):0];
|
||||
assign gpaddr[z][CVA6Cfg.VpnLen:CVA6Cfg.VpnLen-(CVA6Cfg.VpnLen/CVA6Cfg.PtLevels)+1] = (ptw_lvl_q[0] == 0) ? vaddr_q[CVA6Cfg.VpnLen:CVA6Cfg.VpnLen-(CVA6Cfg.VpnLen/CVA6Cfg.PtLevels)+1] : gpaddr_base[CVA6Cfg.VpnLen:CVA6Cfg.VpnLen-(CVA6Cfg.VpnLen/CVA6Cfg.PtLevels)+1];
|
||||
assign gpaddr[z][CVA6Cfg.GPLEN-1:CVA6Cfg.VpnLen+1] = gpaddr_base[CVA6Cfg.GPLEN-1:CVA6Cfg.VpnLen+1];
|
||||
end
|
||||
|
||||
|
@ -192,14 +192,19 @@ module cva6_ptw
|
|||
endgenerate
|
||||
|
||||
always_comb begin : tlb_update
|
||||
shared_tlb_update_o.valid = shared_tlb_update_valid;
|
||||
|
||||
// update the correct page table level
|
||||
for (int unsigned y = 0; y < HYP_EXT + 1; y++) begin
|
||||
for (int unsigned x = 0; x < CVA6Cfg.PtLevels - 1; x++) begin
|
||||
if((enable_g_translation_i && enable_translation_i) || (en_ld_st_g_translation_i && en_ld_st_translation_i) && CVA6Cfg.RVH) begin
|
||||
shared_tlb_update_o.is_page[x][y] = (ptw_lvl_q[y==HYP_EXT?0 : 1] == x);
|
||||
if(((enable_g_translation_i && enable_translation_i) || (en_ld_st_g_translation_i && en_ld_st_translation_i)) && CVA6Cfg.RVH) begin
|
||||
// VS + G-Translation
|
||||
shared_tlb_update_o.is_page[x][y] = (ptw_lvl_q[y==1?0 : 1] == x);
|
||||
end else if (enable_translation_i || en_ld_st_translation_i || !CVA6Cfg.RVH) begin
|
||||
// non-V, S-Translation
|
||||
shared_tlb_update_o.is_page[x][y] = y == 0 ? (ptw_lvl_q[0] == x) : 1'b0;
|
||||
end else begin
|
||||
// G-Translation
|
||||
shared_tlb_update_o.is_page[x][y] = y != 0 ? (ptw_lvl_q[0] == x) : 1'b0;
|
||||
end
|
||||
end
|
||||
|
@ -207,7 +212,7 @@ module cva6_ptw
|
|||
|
||||
// set the global mapping bit
|
||||
if ((enable_g_translation_i || en_ld_st_g_translation_i) && CVA6Cfg.RVH) begin
|
||||
shared_tlb_update_o.content = gpte_q | (global_mapping_q << 5);
|
||||
shared_tlb_update_o.content = (gpte_q | (global_mapping_q << 5));
|
||||
shared_tlb_update_o.g_content = pte;
|
||||
end else begin
|
||||
shared_tlb_update_o.content = (pte | (global_mapping_q << 5));
|
||||
|
@ -217,6 +222,7 @@ module cva6_ptw
|
|||
// output the correct ASIDs
|
||||
shared_tlb_update_o.asid = tlb_update_asid_q;
|
||||
shared_tlb_update_o.vmid = CVA6Cfg.RVH ? tlb_update_vmid_q : '0;
|
||||
shared_tlb_update_o.vpn = vaddr_q[12+CVA6Cfg.VpnLen-1:12];
|
||||
|
||||
bad_paddr_o = ptw_access_exception_o ? ptw_pptr_q : 'b0;
|
||||
if (CVA6Cfg.RVH)
|
||||
|
@ -276,28 +282,27 @@ module cva6_ptw
|
|||
// - pa.ppn[LEVELS-1:i] = pte.ppn[LEVELS-1:i].
|
||||
always_comb begin : ptw
|
||||
automatic logic [CVA6Cfg.PLEN-1:0] pptr;
|
||||
// automatic logic [CVA6Cfg.GPLEN-1:0] gpaddr;
|
||||
// default assignments
|
||||
// PTW memory interface
|
||||
tag_valid_n = 1'b0;
|
||||
req_port_o.data_req = 1'b0;
|
||||
req_port_o.data_size = 2'(CVA6Cfg.PtLevels);
|
||||
req_port_o.data_we = 1'b0;
|
||||
ptw_error_o = 1'b0;
|
||||
ptw_error_at_g_st_o = 1'b0;
|
||||
ptw_err_at_g_int_st_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;
|
||||
ptw_stage_d = ptw_stage_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'(CVA6Cfg.PtLevels);
|
||||
req_port_o.data_we = 1'b0;
|
||||
ptw_error_o = 1'b0;
|
||||
ptw_error_at_g_st_o = 1'b0;
|
||||
ptw_err_at_g_int_st_o = 1'b0;
|
||||
ptw_access_exception_o = 1'b0;
|
||||
shared_tlb_update_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;
|
||||
ptw_stage_d = ptw_stage_q;
|
||||
global_mapping_n = global_mapping_q;
|
||||
// input registers
|
||||
tlb_update_asid_n = tlb_update_asid_q;
|
||||
vaddr_n = vaddr_q;
|
||||
pptr = ptw_pptr_q;
|
||||
tlb_update_asid_n = tlb_update_asid_q;
|
||||
vaddr_n = vaddr_q;
|
||||
pptr = ptw_pptr_q;
|
||||
|
||||
if (CVA6Cfg.RVH) begin
|
||||
gpaddr_n = gpaddr_q;
|
||||
|
@ -407,8 +412,7 @@ module cva6_ptw
|
|||
// -----------
|
||||
else begin
|
||||
state_d = LATENCY;
|
||||
// it is a valid PTE
|
||||
// if pte.r = 1 or pte.x = 1 it is a valid PTE
|
||||
// it is a valid PTE if pte.r = 1 or pte.x = 1
|
||||
if (pte.r || pte.x) begin
|
||||
if (CVA6Cfg.RVH) begin
|
||||
case (ptw_stage_q)
|
||||
|
@ -421,7 +425,7 @@ module cva6_ptw
|
|||
gpaddr_n = gpaddr[ptw_lvl_q[0]];
|
||||
ptw_pptr_n = {
|
||||
hgatp_ppn_i[CVA6Cfg.PPNW-1:2],
|
||||
gpaddr[ptw_lvl_q[0]][CVA6Cfg.SV+HYP_EXT*2-1:CVA6Cfg.SV-(CVA6Cfg.VpnLen/CVA6Cfg.PtLevels)],
|
||||
gpaddr[ptw_lvl_q[0]][CVA6Cfg.GPLEN-1:CVA6Cfg.SV-(CVA6Cfg.VpnLen/CVA6Cfg.PtLevels)],
|
||||
(CVA6Cfg.PtLevels)'(0)
|
||||
};
|
||||
ptw_lvl_n[0] = '0;
|
||||
|
@ -447,11 +451,12 @@ module cva6_ptw
|
|||
// If page is not executable, we can directly raise an error. This
|
||||
// doesn't put a useless entry into the TLB. The same idea applies
|
||||
// to the access flag since we let the access flag be managed by SW.
|
||||
if (!pte.x || !pte.a) begin
|
||||
if ((!pte.x && (!CVA6Cfg.RVH || ptw_stage_q != G_INTERMED_STAGE)) || !pte.a
|
||||
|| (CVA6Cfg.RVH && ptw_stage_q == G_INTERMED_STAGE && !pte.r)) begin
|
||||
state_d = PROPAGATE_ERROR;
|
||||
if (CVA6Cfg.RVH) ptw_stage_d = ptw_stage_q;
|
||||
end else if (CVA6Cfg.RVH && ((ptw_stage_q == G_FINAL_STAGE) || !enable_g_translation_i) || !CVA6Cfg.RVH)
|
||||
shared_tlb_update_o.valid = 1'b1;
|
||||
end else if ((CVA6Cfg.RVH && ((ptw_stage_q == G_FINAL_STAGE) || !enable_g_translation_i)) || !CVA6Cfg.RVH)
|
||||
shared_tlb_update_valid = 1'b1;
|
||||
|
||||
end else begin
|
||||
// ------------
|
||||
|
@ -462,33 +467,32 @@ module cva6_ptw
|
|||
// If page is not readable (there are no write-only pages)
|
||||
// we can directly raise an error. This doesn't put a useless
|
||||
// entry into the TLB.
|
||||
if (pte.a && ((pte.r && !hlvx_inst_i) || (pte.x && (mxr_i || hlvx_inst_i || (ptw_stage_q == S_STAGE && vmxr_i && ld_st_v_i && CVA6Cfg.RVH))))) begin
|
||||
if (CVA6Cfg.RVH && ((ptw_stage_q == G_FINAL_STAGE) || !en_ld_st_g_translation_i) || !CVA6Cfg.RVH)
|
||||
shared_tlb_update_o.valid = 1'b1;
|
||||
if (
|
||||
(pte.a && ((pte.r && !hlvx_inst_i) || (pte.x && (mxr_i || hlvx_inst_i || (ptw_stage_q == S_STAGE && vmxr_i && ld_st_v_i && CVA6Cfg.RVH)))))
|
||||
// Request is a store: perform some additional checks
|
||||
// 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
|
||||
// g-intermediate nodes however never need write-permission
|
||||
&& (!lsu_is_store_i || (pte.w && pte.d) || (ptw_stage_q == G_INTERMED_STAGE && CVA6Cfg.RVH))
|
||||
) begin
|
||||
if ((CVA6Cfg.RVH && ((ptw_stage_q == G_FINAL_STAGE) || !en_ld_st_g_translation_i)) || !CVA6Cfg.RVH)
|
||||
shared_tlb_update_valid = 1'b1;
|
||||
end else begin
|
||||
state_d = PROPAGATE_ERROR;
|
||||
if (CVA6Cfg.RVH) ptw_stage_d = ptw_stage_q;
|
||||
end
|
||||
// Request is a store: perform some additional checks
|
||||
// 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
|
||||
shared_tlb_update_o.valid = 1'b0;
|
||||
state_d = PROPAGATE_ERROR;
|
||||
if (CVA6Cfg.RVH) ptw_stage_d = ptw_stage_q;
|
||||
end
|
||||
end
|
||||
|
||||
//if there is a misaligned page, propagate error
|
||||
// if there is a misaligned page, propagate error
|
||||
if (|misaligned_page) begin
|
||||
state_d = PROPAGATE_ERROR;
|
||||
if (CVA6Cfg.RVH) ptw_stage_d = ptw_stage_q;
|
||||
shared_tlb_update_o.valid = 1'b0;
|
||||
shared_tlb_update_valid = 1'b0;
|
||||
end
|
||||
|
||||
// check if 63:41 are all zeros
|
||||
if (CVA6Cfg.RVH) begin
|
||||
if (((v_i && is_instr_ptw_q) || (ld_st_v_i && !is_instr_ptw_q)) && ptw_stage_q == S_STAGE && !((|pte.ppn[CVA6Cfg.PPNW-1:CVA6Cfg.GPPNW-1+HYP_EXT]) == 1'b0)) begin
|
||||
if (((v_i && is_instr_ptw_q) || (ld_st_v_i && !is_instr_ptw_q)) && ptw_stage_q == S_STAGE && !((|pte.ppn[CVA6Cfg.PPNW-1:CVA6Cfg.GPPNW]) == 1'b0)) begin
|
||||
state_d = PROPAGATE_ERROR;
|
||||
ptw_stage_d = G_FINAL_STAGE;
|
||||
end
|
||||
|
@ -513,7 +517,6 @@ module cva6_ptw
|
|||
S_STAGE: begin
|
||||
if (CVA6Cfg.RVH && ((is_instr_ptw_q && enable_g_translation_i) || (!is_instr_ptw_q && en_ld_st_g_translation_i))) begin
|
||||
ptw_stage_d = G_INTERMED_STAGE;
|
||||
if (CVA6Cfg.RVH) gpte_d = pte;
|
||||
ptw_lvl_n[HYP_EXT] = ptw_lvl_q[0] + 1;
|
||||
pptr = {pte.ppn, vaddr_lvl[0][ptw_lvl_q[0]], (CVA6Cfg.PtLevels)'(0)};
|
||||
gptw_pptr_n = pptr;
|
||||
|
@ -549,7 +552,7 @@ module cva6_ptw
|
|||
|
||||
// check if 63:41 are all zeros
|
||||
if (CVA6Cfg.RVH) begin
|
||||
if (((v_i && is_instr_ptw_q) || (ld_st_v_i && !is_instr_ptw_q)) && ptw_stage_q == S_STAGE && !((|pte.ppn[CVA6Cfg.PPNW-1:CVA6Cfg.GPPNW-1+HYP_EXT]) == 1'b0)) begin
|
||||
if (((v_i && is_instr_ptw_q) || (ld_st_v_i && !is_instr_ptw_q)) && ptw_stage_q == S_STAGE && !((|pte.ppn[CVA6Cfg.PPNW-1:CVA6Cfg.GPPNW]) == 1'b0)) begin
|
||||
state_d = PROPAGATE_ERROR;
|
||||
ptw_stage_d = ptw_stage_q;
|
||||
end
|
||||
|
@ -557,9 +560,9 @@ module cva6_ptw
|
|||
end
|
||||
end
|
||||
|
||||
// Check if this access was actually allowed from a PMP perspective
|
||||
// check if this access was actually allowed from a PMP perspective
|
||||
if (!allow_access) begin
|
||||
shared_tlb_update_o.valid = 1'b0;
|
||||
shared_tlb_update_valid = 1'b0;
|
||||
// we have to return the failed address in bad_addr
|
||||
ptw_pptr_n = ptw_pptr_q;
|
||||
if (CVA6Cfg.RVH) ptw_stage_d = ptw_stage_q;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue