Skip to content

Commit 0c2fde5

Browse files
committed
feat: Add support for SVNAPOT extension
1 parent f073404 commit 0c2fde5

26 files changed

+800
-189
lines changed

core/cva6_mmu/cva6_mmu.sv

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,8 @@ module cva6_mmu
106106

107107
// memory management, pte for cva6
108108
localparam type pte_cva6_t = struct packed {
109-
logic [9:0] reserved;
109+
logic n;
110+
logic [8:0] reserved;
110111
logic [CVA6Cfg.PPNW-1:0] ppn; // PPN length for
111112
logic [1:0] rsw;
112113
logic d;
@@ -120,14 +121,15 @@ module cva6_mmu
120121
};
121122

122123
localparam type tlb_update_cva6_t = struct packed {
123-
logic valid;
124+
logic is_napot_64k; // Svnapot: Flag indicating a 64KiB NAPOT page
125+
logic valid;
124126
logic [CVA6Cfg.PtLevels-2:0][HYP_EXT:0] is_page;
125-
logic [CVA6Cfg.VpnLen-1:0] vpn;
126-
logic [CVA6Cfg.ASID_WIDTH-1:0] asid;
127-
logic [CVA6Cfg.VMID_WIDTH-1:0] vmid;
128-
logic [HYP_EXT*2:0] v_st_enbl; // v_i,g-stage enabled, s-stage enabled
129-
pte_cva6_t content;
130-
pte_cva6_t g_content;
127+
logic [CVA6Cfg.VpnLen-1:0] vpn;
128+
logic [CVA6Cfg.ASID_WIDTH-1:0] asid;
129+
logic [CVA6Cfg.VMID_WIDTH-1:0] vmid;
130+
logic [HYP_EXT*2:0] v_st_enbl; // v_i,g-stage enabled, s-stage enabled
131+
pte_cva6_t content;
132+
pte_cva6_t g_content;
131133
};
132134

133135
logic iaccess_err; // insufficient privilege to access this instruction page
@@ -143,7 +145,7 @@ module cva6_mmu
143145
logic ptw_access_exception; // PTW threw an access exception (PMPs)
144146
logic [CVA6Cfg.PLEN-1:0] ptw_bad_paddr; // PTW page fault bad physical addr
145147
logic [CVA6Cfg.GPLEN-1:0] ptw_bad_gpaddr; // PTW guest page fault bad guest physical addr
146-
148+
logic [CVA6Cfg.PPNW-1:0] final_fetch_ppn;
147149
logic [CVA6Cfg.VLEN-1:0] update_vaddr, shared_tlb_vaddr;
148150

149151
tlb_update_cva6_t update_itlb, update_dtlb, update_shared_tlb;
@@ -155,7 +157,6 @@ module cva6_mmu
155157
logic itlb_lu_hit;
156158
logic [ CVA6Cfg.GPLEN-1:0] itlb_gpaddr;
157159
logic [CVA6Cfg.ASID_WIDTH-1:0] itlb_lu_asid;
158-
159160
logic dtlb_lu_access;
160161
pte_cva6_t dtlb_content;
161162
pte_cva6_t dtlb_g_content;
@@ -393,11 +394,8 @@ module cva6_mmu
393394
end
394395

395396
icache_areq_o.fetch_valid = 1'b0;
396-
397-
icache_areq_o.fetch_paddr = {
398-
(enable_g_translation_i && CVA6Cfg.RVH) ? itlb_g_content.ppn : itlb_content.ppn,
399-
icache_areq_i.fetch_vaddr[11:0]
400-
};
397+
final_fetch_ppn = (enable_g_translation_i && CVA6Cfg.RVH)? itlb_g_content.ppn : itlb_content.ppn;
398+
icache_areq_o.fetch_paddr = {final_fetch_ppn, icache_areq_i.fetch_vaddr[11:0]};
401399

402400
if (CVA6Cfg.PtLevels == 3 && itlb_is_page[CVA6Cfg.PtLevels-2]) begin
403401

@@ -498,7 +496,6 @@ module cva6_mmu
498496
logic dtlb_hit_n, dtlb_hit_q;
499497
logic [CVA6Cfg.PtLevels-2:0] dtlb_is_page_n, dtlb_is_page_q;
500498
exception_t misaligned_ex_n, misaligned_ex_q;
501-
502499
// check if we need to do translation or if we are always ready (e.g.: we are not translating anything)
503500
assign lsu_dtlb_hit_o = (en_ld_st_translation_i || en_ld_st_g_translation_i) ? dtlb_lu_hit : 1'b1;
504501

@@ -513,7 +510,6 @@ module cva6_mmu
513510
lsu_is_store_n = lsu_is_store_i;
514511
dtlb_is_page_n = dtlb_is_page;
515512
misaligned_ex_n = misaligned_ex_i;
516-
517513
lsu_valid_o = lsu_req_q;
518514
lsu_exception_o = misaligned_ex_q;
519515

@@ -529,7 +525,6 @@ module cva6_mmu
529525
daccess_err = en_ld_st_translation_i &&
530526
((ld_st_priv_lvl_i == riscv::PRIV_LVL_S && (ld_st_v_i ? !vs_sum_i : !sum_i ) && dtlb_pte_q.u) || // SUM is not set and we are trying to access a user page in supervisor mode
531527
(ld_st_priv_lvl_i == riscv::PRIV_LVL_U && !dtlb_pte_q.u));
532-
533528
if (CVA6Cfg.RVH) begin
534529
lsu_tinst_n = lsu_tinst_i;
535530
hs_ld_st_inst_n = hs_ld_st_inst_i;
@@ -754,7 +749,6 @@ module cva6_mmu
754749
lsu_is_store_q <= lsu_is_store_n;
755750
dtlb_is_page_q <= dtlb_is_page_n;
756751
misaligned_ex_q <= misaligned_ex_n;
757-
758752
if (CVA6Cfg.RVH) begin
759753
lsu_tinst_q <= lsu_tinst_n;
760754
hs_ld_st_inst_q <= hs_ld_st_inst_n;

core/cva6_mmu/cva6_ptw.sv

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,10 @@ module cva6_ptw
9696
pte_cva6_t pte;
9797
// register to perform context switch between stages
9898
pte_cva6_t gpte_q, gpte_d;
99+
100+
//Field for SVNAPOT
101+
logic is_napot_64k;
102+
99103
assign pte = pte_cva6_t'(data_rdata_q);
100104

101105
enum logic [2:0] {
@@ -193,6 +197,7 @@ module cva6_ptw
193197

194198
always_comb begin : tlb_update
195199
shared_tlb_update_o.valid = shared_tlb_update_valid;
200+
shared_tlb_update_o.is_napot_64k = is_napot_64k;
196201

197202
// update the correct page table level
198203
for (int unsigned y = 0; y < HYP_EXT + 1; y++) begin
@@ -293,6 +298,7 @@ module cva6_ptw
293298
ptw_err_at_g_int_st_o = 1'b0;
294299
ptw_access_exception_o = 1'b0;
295300
shared_tlb_update_valid = 1'b0;
301+
is_napot_64k = 1'b0;
296302
is_instr_ptw_n = is_instr_ptw_q;
297303
ptw_lvl_n = ptw_lvl_q;
298304
ptw_pptr_n = ptw_pptr_q;
@@ -398,23 +404,34 @@ module cva6_ptw
398404
PTE_LOOKUP: begin
399405
// we wait for the valid signal
400406
if (data_rvalid_q) begin
401-
402407
// check if the global mapping bit is set
403408
if (pte.g && (ptw_stage_q == S_STAGE || !CVA6Cfg.RVH)) global_mapping_n = 1'b1;
404409

405410
// -------------
406411
// Invalid PTE
407412
// -------------
408413
// If pte.v = 0, or if pte.r = 0 and pte.w = 1, or if pte.reserved !=0 in sv39 and sv39x4, stop and raise a page-fault exception.
409-
if (!pte.v || (!pte.r && pte.w) || (|pte.reserved && CVA6Cfg.XLEN == 64))
414+
if (!pte.v || (!pte.r && pte.w) || (|pte.reserved && CVA6Cfg.XLEN == 64) || (!CVA6Cfg.SvnapotEn && pte.n) || (CVA6Cfg.SvnapotEn && !(pte.r || pte.x) && pte.n))
410415
state_d = PROPAGATE_ERROR;
411416
// -----------
412417
// Valid PTE
413418
// -----------
414419
else begin
415420
state_d = LATENCY;
416-
// it is a valid PTE if pte.r = 1 or pte.x = 1
421+
// it is a valid PTE
422+
// if pte.r = 1 or pte.x = 1 it is a valid leaf PTE
417423
if (pte.r || pte.x) begin
424+
// A 64KiB NAPOT page is identified by the N-bit being set and PPN[3:0] encoding '1000'
425+
if (CVA6Cfg.SvnapotEn && pte.n) begin
426+
// Svnapot: Check if the leaf PTE represents a 64KiB NAPOT page
427+
is_napot_64k = (pte.ppn[3:0] == 4'b1000) && (ptw_lvl_q[0] == 0);
428+
// Svnapot: Any other encoding with the N-bit set is a reserved format and must cause a page fault
429+
// Additionally, fault if N is set on a megapage or gigapage
430+
if (!is_napot_64k) begin
431+
state_d = PROPAGATE_ERROR;
432+
end
433+
end
434+
418435
if (CVA6Cfg.RVH) begin
419436
case (ptw_stage_q)
420437
S_STAGE: begin

core/cva6_mmu/cva6_shared_tlb.sv

Lines changed: 66 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ module cva6_shared_tlb #(
8989
logic [CVA6Cfg.PtLevels+HYP_EXT-1:0][(CVA6Cfg.VpnLen/CVA6Cfg.PtLevels)-1:0] vpn;
9090
logic [CVA6Cfg.PtLevels-2:0][HYP_EXT:0] is_page;
9191
logic [HYP_EXT*2:0] v_st_enbl; // v_i,g-stage enabled, s-stage enabled
92+
logic is_napot_64k; // Svnapot: Flag indicating a 64KiB NAPOT page
9293
} shared_tag_t;
9394

9495
shared_tag_t shared_tag_wr;
@@ -143,6 +144,11 @@ module cva6_shared_tlb #(
143144
logic shared_tlb_hit_d;
144145
logic [CVA6Cfg.VLEN-1:0] shared_tlb_vaddr_q, shared_tlb_vaddr_d;
145146

147+
logic [ CVA6Cfg.VpnLen-1:0] lu_vpn;
148+
logic [SHARED_TLB_WAYS-1:0] vpn0_napot_match;
149+
logic [SHARED_TLB_WAYS-1:0] napot_tag_match;
150+
pte_cva6_t patched_pte;
151+
146152
logic itlb_req_d, itlb_req_q;
147153
logic dtlb_req_d, dtlb_req_q;
148154

@@ -164,39 +170,42 @@ module cva6_shared_tlb #(
164170
assign shared_tlb_vaddr_o = shared_tlb_vaddr_q;
165171
assign itlb_req_o = itlb_req_q;
166172
assign v_st_enbl = {{v_i, g_st_enbl_i, s_st_enbl_i}, {ld_st_v_i, g_ld_st_enbl_i, s_ld_st_enbl_i}};
173+
assign lu_vpn = itlb_req_q ? itlb_vpn_q : dtlb_vpn_q;
167174

168-
genvar i, x;
175+
genvar i_gen, x_gen;
169176
generate
170-
for (i = 0; i < SHARED_TLB_WAYS; i++) begin : gen_match_tlb_ways
177+
for (i_gen = 0; i_gen < SHARED_TLB_WAYS; i_gen++) begin : gen_match_tlb_ways
171178
//identify page_match for all TLB Entries
172-
173-
for (x = 0; x < CVA6Cfg.PtLevels; x++) begin : gen_match
174-
assign page_match[i][x] = x==0 ? 1 :((HYP_EXT==0 || x==(CVA6Cfg.PtLevels-1)) ? // PAGE_MATCH CONTAINS THE MATCH INFORMATION FOR EACH TAG OF is_1G and is_2M in sv39x4. HIGHER LEVEL (Giga page), THEN THERE IS THE Mega page AND AT THE LOWER LEVEL IS ALWAYS 1
175-
&(shared_tag_rd[i].is_page[CVA6Cfg.PtLevels-1-x] | (~v_st_enbl[i_req_q][HYP_EXT:0])):
179+
for (x_gen = 0; x_gen < CVA6Cfg.PtLevels; x_gen++) begin : gen_match
180+
assign page_match[i_gen][x_gen] = x_gen==0 ? 1 :((HYP_EXT==0 || x_gen==(CVA6Cfg.PtLevels-1)) ? // PAGE_MATCH CONTAINS THE MATCH INFORMATION FOR EACH TAG OF is_1G and is_2M in sv39x4. HIGHER LEVEL (Giga page), THEN THERE IS THE Mega page AND AT THE LOWER LEVEL IS ALWAYS 1
181+
&(shared_tag_rd[i_gen].is_page[CVA6Cfg.PtLevels-1-x_gen] | (~v_st_enbl[i_req_q][HYP_EXT:0])):
176182
((&v_st_enbl[i_req_q][HYP_EXT:0]) ?
177-
((shared_tag_rd[i].is_page[CVA6Cfg.PtLevels-1-x][0] && (shared_tag_rd[i].is_page[CVA6Cfg.PtLevels-2-x][HYP_EXT] || shared_tag_rd[i].is_page[CVA6Cfg.PtLevels-1-x][HYP_EXT]))
178-
|| (shared_tag_rd[i].is_page[CVA6Cfg.PtLevels-1-x][HYP_EXT] && (shared_tag_rd[i].is_page[CVA6Cfg.PtLevels-2-x][0] || shared_tag_rd[i].is_page[CVA6Cfg.PtLevels-1-x][0]))):
179-
shared_tag_rd[i].is_page[CVA6Cfg.PtLevels-1-x][0] && v_st_enbl[i_req_q][0] || shared_tag_rd[i].is_page[CVA6Cfg.PtLevels-1-x][HYP_EXT] && v_st_enbl[i_req_q][HYP_EXT]));
183+
((shared_tag_rd[i_gen].is_page[CVA6Cfg.PtLevels-1-x_gen][0] && (shared_tag_rd[i_gen].is_page[CVA6Cfg.PtLevels-2-x_gen][HYP_EXT] || shared_tag_rd[i_gen].is_page[CVA6Cfg.PtLevels-1-x_gen][HYP_EXT]))
184+
|| (shared_tag_rd[i_gen].is_page[CVA6Cfg.PtLevels-1-x_gen][HYP_EXT] && (shared_tag_rd[i_gen].is_page[CVA6Cfg.PtLevels-2-x_gen][0] || shared_tag_rd[i_gen].is_page[CVA6Cfg.PtLevels-1-x_gen][0]))):
185+
shared_tag_rd[i_gen].is_page[CVA6Cfg.PtLevels-1-x_gen][0] && v_st_enbl[i_req_q][0] || shared_tag_rd[i_gen].is_page[CVA6Cfg.PtLevels-1-x_gen][HYP_EXT] && v_st_enbl[i_req_q][HYP_EXT]));
180186

181187
//identify if vpn matches at all PT levels for all TLB entries
182-
assign vpn_match[i][x] = (HYP_EXT==1 && x==(CVA6Cfg.PtLevels-1) && ~v_st_enbl[i_req_q][0]) ? //
183-
vpn_q[x] == shared_tag_rd[i].vpn[x] && vpn_q[x+HYP_EXT][(CVA6Cfg.VpnLen%CVA6Cfg.PtLevels)-HYP_EXT:0] == shared_tag_rd[i].vpn[x+HYP_EXT][(CVA6Cfg.VpnLen%CVA6Cfg.PtLevels)-HYP_EXT:0]: //
184-
vpn_q[x] == shared_tag_rd[i].vpn[x];
188+
assign vpn_match[i_gen][x_gen] = (HYP_EXT==1 && x_gen==(CVA6Cfg.PtLevels-1) && ~v_st_enbl[i_req_q][0]) ? //
189+
vpn_q[x_gen] == shared_tag_rd[i_gen].vpn[x_gen] && vpn_q[x_gen+HYP_EXT][(CVA6Cfg.VpnLen%CVA6Cfg.PtLevels)-HYP_EXT:0] == shared_tag_rd[i_gen].vpn[x_gen+HYP_EXT][(CVA6Cfg.VpnLen%CVA6Cfg.PtLevels)-HYP_EXT:0]: //
190+
vpn_q[x_gen] == shared_tag_rd[i_gen].vpn[x_gen];
185191

186192
//identify if there is a hit at each PT level for all TLB entries
187-
assign level_match[i][x] = &vpn_match[i][CVA6Cfg.PtLevels-1:x] && page_match[i][x];
193+
assign level_match[i_gen][x_gen] = &vpn_match[i_gen][CVA6Cfg.PtLevels-1:x_gen] && page_match[i_gen][x_gen];
188194

189195
end
196+
assign vpn0_napot_match[i_gen] = lu_vpn[(CVA6Cfg.VpnLen/CVA6Cfg.PtLevels)-1 : 4] == shared_tag_rd[i_gen].vpn[0][(CVA6Cfg.VpnLen/CVA6Cfg.PtLevels)-1 : 4];
197+
assign napot_tag_match[i_gen] = (CVA6Cfg.SvnapotEn && shared_tag_rd[i_gen].is_napot_64k) ?
198+
(vpn_match[i_gen][2] && vpn_match[i_gen][1] && vpn0_napot_match[i_gen]) : 1'b0;
190199
end
191200
endgenerate
192201

193-
genvar w;
202+
genvar w_gen;
194203
generate
195-
for (w = 0; w < CVA6Cfg.PtLevels; w++) begin
196-
assign vpn_d[w] = ((|v_st_enbl[1][HYP_EXT:0]) && itlb_access_i && ~itlb_hit_i && ~dtlb_access_i) ? //
197-
itlb_vaddr_i[12+((CVA6Cfg.VpnLen/CVA6Cfg.PtLevels)*(w+1))-1:12+((CVA6Cfg.VpnLen/CVA6Cfg.PtLevels)*w)] : //
204+
for (w_gen = 0; w_gen < CVA6Cfg.PtLevels; w_gen++) begin
205+
assign vpn_d[w_gen] = ((|v_st_enbl[1][HYP_EXT:0]) && itlb_access_i && ~itlb_hit_i && ~dtlb_access_i) ? //
206+
itlb_vaddr_i[12+((CVA6Cfg.VpnLen/CVA6Cfg.PtLevels)*(w_gen+1))-1:12+((CVA6Cfg.VpnLen/CVA6Cfg.PtLevels)*w_gen)] : //
198207
(((|v_st_enbl[0][HYP_EXT:0]) && dtlb_access_i && ~dtlb_hit_i) ? //
199-
dtlb_vaddr_i[12+((CVA6Cfg.VpnLen/CVA6Cfg.PtLevels)*(w+1))-1:12+((CVA6Cfg.VpnLen/CVA6Cfg.PtLevels)*w)] : vpn_q[w]);
208+
dtlb_vaddr_i[12+((CVA6Cfg.VpnLen/CVA6Cfg.PtLevels)*(w_gen+1))-1:12+((CVA6Cfg.VpnLen/CVA6Cfg.PtLevels)*w_gen)] : vpn_q[w_gen]);
200209
end
201210
endgenerate
202211

@@ -270,7 +279,6 @@ module cva6_shared_tlb #(
270279
match_asid = '{default: 0};
271280
match_vmid = CVA6Cfg.RVH ? '{default: 0} : '{default: 1};
272281

273-
274282
if (!CVA6Cfg.UseSharedTlb) begin
275283
if (shared_tlb_update_i.valid) begin
276284
shared_tlb_hit_d = 1'b1;
@@ -283,6 +291,7 @@ module cva6_shared_tlb #(
283291
itlb_update_o.v_st_enbl = v_st_enbl[i_req_q][HYP_EXT*2:0];
284292
itlb_update_o.asid = shared_tlb_update_i.asid;
285293
itlb_update_o.vmid = shared_tlb_update_i.vmid;
294+
itlb_update_o.is_napot_64k = shared_tlb_update_i.is_napot_64k;
286295

287296
end else if (dtlb_req_q) begin
288297
dtlb_update_o.valid = 1'b1;
@@ -293,10 +302,10 @@ module cva6_shared_tlb #(
293302
dtlb_update_o.v_st_enbl = v_st_enbl[i_req_q][HYP_EXT*2:0];
294303
dtlb_update_o.asid = shared_tlb_update_i.asid;
295304
dtlb_update_o.vmid = shared_tlb_update_i.vmid;
305+
dtlb_update_o.is_napot_64k = shared_tlb_update_i.is_napot_64k;
296306
end
297307
end
298308
end else begin
299-
300309
//number of ways
301310
for (int unsigned i = 0; i < SHARED_TLB_WAYS; i++) begin
302311
// first level match, this may be a giga page, check the ASID flags as well
@@ -309,28 +318,35 @@ module cva6_shared_tlb #(
309318

310319
// check if translation is a: S-Stage and G-Stage, S-Stage only or G-Stage only translation and virtualization mode is on/off
311320
match_stage[i] = shared_tag_rd[i].v_st_enbl == v_st_enbl[i_req_q][HYP_EXT*2:0];
312-
313321
if (shared_tag_valid[i] && match_asid[i] && match_vmid[i] && match_stage[i]) begin
314-
if (|level_match[i]) begin
322+
if (|level_match[i] || napot_tag_match[i]) begin
315323
shared_tlb_hit_d = 1'b1;
324+
// Prepare PTE with NAPOT patching if needed
325+
patched_pte = pte[i][0]; // take the S‑stage PTE only
326+
if (shared_tag_rd[i].is_napot_64k && CVA6Cfg.SvnapotEn) begin
327+
// replace PPN[3:0] with vaddr[15:12] (equiv. lu_vpn[3:0])
328+
patched_pte.ppn[3:0] = lu_vpn[3:0];
329+
end
316330
if (itlb_req_q) begin
317331
itlb_update_o.valid = 1'b1;
318332
itlb_update_o.vpn = itlb_vpn_q;
319333
itlb_update_o.is_page = shared_tag_rd[i].is_page;
320-
itlb_update_o.content = pte[i][0];
334+
itlb_update_o.content = patched_pte;
321335
itlb_update_o.g_content = pte[i][HYP_EXT];
322336
itlb_update_o.v_st_enbl = shared_tag_rd[i].v_st_enbl;
323337
itlb_update_o.asid = tlb_update_asid_q;
324338
itlb_update_o.vmid = tlb_update_vmid_q;
339+
itlb_update_o.is_napot_64k = CVA6Cfg.SvnapotEn ? shared_tag_rd[i].is_napot_64k : 1'b0;
325340
end else if (dtlb_req_q) begin
326341
dtlb_update_o.valid = 1'b1;
327342
dtlb_update_o.vpn = dtlb_vpn_q;
328343
dtlb_update_o.is_page = shared_tag_rd[i].is_page;
329-
dtlb_update_o.content = pte[i][0];
344+
dtlb_update_o.content = patched_pte;
330345
dtlb_update_o.g_content = pte[i][HYP_EXT];
331346
dtlb_update_o.v_st_enbl = shared_tag_rd[i].v_st_enbl;
332347
dtlb_update_o.asid = tlb_update_asid_q;
333348
dtlb_update_o.vmid = tlb_update_vmid_q;
349+
dtlb_update_o.is_napot_64k = CVA6Cfg.SvnapotEn ? shared_tag_rd[i].is_napot_64k : 1'b0;
334350
end
335351
end
336352
end
@@ -381,6 +397,21 @@ module cva6_shared_tlb #(
381397
// ------------------
382398
// Update and Flush
383399
// ------------------
400+
401+
logic [CVA6Cfg.VpnLen-1:0] vpn_to_store;
402+
logic [$clog2(CVA6Cfg.SharedTlbDepth)-1:0] vpn_index;
403+
404+
// When storing the VPN in the shared TLB, if NAPOT is used, the lower bits of the VPN are zeroed
405+
// This way, when searching for a match, we can compare the full VPN if NAPOT is not used
406+
// or only the upper bits if NAPOT is used (the lower bits are don't care)
407+
// The actual PPN is stored in the PTE, with the lower bits patched if NAPOT is used
408+
// This is done in the tag comparison logic above
409+
410+
assign vpn_to_store =
411+
(shared_tlb_update_i.is_napot_64k && CVA6Cfg.SvnapotEn)
412+
? {shared_tlb_update_i.vpn[CVA6Cfg.VpnLen-1:4], 4'b0}
413+
: shared_tlb_update_i.vpn;
414+
384415
always_comb begin : update_flush
385416
shared_tag_valid_d = shared_tag_valid_q;
386417
tag_wr_en = '0;
@@ -391,7 +422,7 @@ module cva6_shared_tlb #(
391422
end else if (shared_tlb_update_i.valid) begin
392423
for (int unsigned i = 0; i < SHARED_TLB_WAYS; i++) begin
393424
if (repl_way_oh_d[i]) begin
394-
shared_tag_valid_d[shared_tlb_update_i.vpn[$clog2(CVA6Cfg.SharedTlbDepth)-1:0]][i] = 1'b1;
425+
shared_tag_valid_d[vpn_index][i] = 1'b1;
395426
tag_wr_en[i] = 1'b1;
396427
pte_wr_en[i] = 1'b1;
397428
end
@@ -403,23 +434,26 @@ module cva6_shared_tlb #(
403434
assign shared_tag_wr.vmid = shared_tlb_update_i.vmid;
404435
assign shared_tag_wr.is_page = shared_tlb_update_i.is_page;
405436
assign shared_tag_wr.v_st_enbl = v_st_enbl[i_req_q][HYP_EXT*2:0];
406-
407-
genvar z;
437+
assign shared_tag_wr.is_napot_64k = shared_tlb_update_i.is_napot_64k; // Svnapot: Propagate the NAPOT flag from the update packet into the tag structure to be stored
438+
genvar z_gen;
408439
generate
409-
for (z = 0; z < CVA6Cfg.PtLevels; z++) begin : gen_shared_tag
410-
assign shared_tag_wr.vpn[z] = shared_tlb_update_i.vpn[((CVA6Cfg.VpnLen/CVA6Cfg.PtLevels)*(z+1))-1:((CVA6Cfg.VpnLen/CVA6Cfg.PtLevels)*z)];
440+
for (z_gen = 0; z_gen < CVA6Cfg.PtLevels; z_gen++) begin : gen_shared_tag
441+
assign shared_tag_wr.vpn[z_gen] = vpn_to_store[((CVA6Cfg.VpnLen/CVA6Cfg.PtLevels)*(z_gen+1))-1:((CVA6Cfg.VpnLen/CVA6Cfg.PtLevels)*z_gen)];
411442
end
412443
if (CVA6Cfg.RVH) begin : gen_shared_tag_hyp
413444
//THIS UPDATES THE EXTRA BITS OF VPN IN SV39x4
414-
assign shared_tag_wr.vpn[CVA6Cfg.PtLevels][(CVA6Cfg.VpnLen%CVA6Cfg.PtLevels)-1:0] = shared_tlb_update_i.vpn[CVA6Cfg.VpnLen-1: CVA6Cfg.VpnLen-(CVA6Cfg.VpnLen%CVA6Cfg.PtLevels)];
445+
assign shared_tag_wr.vpn[CVA6Cfg.PtLevels][(CVA6Cfg.VpnLen%CVA6Cfg.PtLevels)-1:0] = vpn_to_store[CVA6Cfg.VpnLen-1: CVA6Cfg.VpnLen-(CVA6Cfg.VpnLen%CVA6Cfg.PtLevels)];
415446
end
416447
endgenerate
417448

418449

419-
assign tag_wr_addr = shared_tlb_update_i.vpn[$clog2(CVA6Cfg.SharedTlbDepth)-1:0];
420450
assign tag_wr_data = shared_tag_wr;
421451

422-
assign pte_wr_addr = shared_tlb_update_i.vpn[$clog2(CVA6Cfg.SharedTlbDepth)-1:0];
452+
// derive the set index from bits [4 +: clog2] of the (possibly masked) VPN
453+
assign vpn_index = shared_tlb_update_i.vpn[$clog2(CVA6Cfg.SharedTlbDepth)-1:0];
454+
// write the new entry into that set
455+
assign tag_wr_addr = vpn_index;
456+
assign pte_wr_addr = vpn_index;
423457

424458
assign pte_wr_data[0] = shared_tlb_update_i.content[CVA6Cfg.XLEN-1:0];
425459
assign pte_wr_data[1] = shared_tlb_update_i.g_content[CVA6Cfg.XLEN-1:0];

0 commit comments

Comments
 (0)