aboutsummaryrefslogtreecommitdiff
path: root/rv64cpu/tb/unit/tb_tlb.cc
diff options
context:
space:
mode:
authorRichard Qin <richard.qin.x@gmail.com>2026-11-07 02:59:33 +0800
committerRichard Qin <richard.qin.x@gmail.com>2026-11-07 02:59:33 +0800
commitbc3ec25107314be3cd816c0b669d82338e892806 (patch)
treeff3e69ce6be1218be8bd0dd04e0c75760776d7dc /rv64cpu/tb/unit/tb_tlb.cc
parentc67ba709482821f37d63601b001ac07e6db867b6 (diff)
downloadrcc-project-bc3ec25107314be3cd816c0b669d82338e892806.tar.gz
rcc-project-bc3ec25107314be3cd816c0b669d82338e892806.tar.xz
checkpoint: preserve current RV64 CPU development state
Diffstat (limited to 'rv64cpu/tb/unit/tb_tlb.cc')
-rw-r--r--rv64cpu/tb/unit/tb_tlb.cc421
1 files changed, 56 insertions, 365 deletions
diff --git a/rv64cpu/tb/unit/tb_tlb.cc b/rv64cpu/tb/unit/tb_tlb.cc
index f244fbe..0a57738 100644
--- a/rv64cpu/tb/unit/tb_tlb.cc
+++ b/rv64cpu/tb/unit/tb_tlb.cc
@@ -1,19 +1,3 @@
-// Richard CPU
-// Copyright (C) 2026 Richard Qin
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-
#include <cassert>
#include <cstdint>
#include <iostream>
@@ -25,9 +9,10 @@
namespace {
constexpr uint8_t MODE_BARE = 0;
-constexpr uint8_t MODE_SV32 = 1;
+constexpr uint8_t MODE_SV39 = 8;
constexpr uint8_t MODE_SV48 = 9;
constexpr uint8_t MODE_SV57 = 10;
+constexpr uint8_t MODE_SV64 = 11;
int g_pass_count = 0;
@@ -41,10 +26,6 @@ void check(bool cond, const char* name) {
}
}
-void eval_comb(Vtlb* dut) {
- dut->eval();
-}
-
void tick(Vtlb* dut) {
dut->clk = 0;
dut->eval();
@@ -52,27 +33,11 @@ void tick(Vtlb* dut) {
dut->eval();
}
-uint64_t make_paddr(uint64_t ppn, uint64_t vaddr) {
- return (ppn << 12) | (vaddr & 0xFFFULL);
-}
-
-uint64_t sv48_vpn(uint64_t vaddr) {
- return (vaddr >> 12) & ((1ULL << 36) - 1ULL);
-}
-
-uint64_t sv32_vpn(uint64_t vaddr) {
- return (vaddr >> 12) & ((1ULL << 20) - 1ULL);
-}
-
-uint64_t sv57_vpn(uint64_t vaddr) {
- return (vaddr >> 12) & ((1ULL << 45) - 1ULL);
-}
-
void clear_req(Vtlb* dut) {
dut->req_valid = 0;
dut->req_vaddr = 0;
dut->req_asid = 0;
- dut->req_mode = MODE_SV48;
+ dut->req_mode = MODE_SV39;
dut->req_priv = 1;
dut->req_is_fetch = 0;
dut->req_is_store = 0;
@@ -85,7 +50,7 @@ void clear_refill(Vtlb* dut) {
dut->refill_vpn = 0;
dut->refill_ppn = 0;
dut->refill_level = 0;
- dut->refill_mode = MODE_SV48;
+ dut->refill_mode = MODE_SV39;
dut->refill_asid = 0;
dut->refill_g = 0;
dut->refill_u = 0;
@@ -102,34 +67,7 @@ void clear_flush(Vtlb* dut) {
dut->flush_asid = 0;
dut->flush_vpn_valid = 0;
dut->flush_vpn = 0;
- dut->flush_mode = MODE_SV48;
-}
-
-void apply_flush_all(Vtlb* dut) {
- clear_flush(dut);
- dut->flush_all = 1;
- tick(dut);
- dut->flush_all = 0;
- eval_comb(dut);
-}
-
-void apply_flush_asid(Vtlb* dut, uint16_t asid) {
- clear_flush(dut);
- dut->flush_asid_valid = 1;
- dut->flush_asid = asid;
- tick(dut);
- clear_flush(dut);
- eval_comb(dut);
-}
-
-void apply_flush_vpn(Vtlb* dut, uint64_t vpn, uint8_t mode) {
- clear_flush(dut);
- dut->flush_vpn_valid = 1;
- dut->flush_vpn = vpn;
- dut->flush_mode = mode;
- tick(dut);
- clear_flush(dut);
- eval_comb(dut);
+ dut->flush_mode = MODE_SV39;
}
void reset(Vtlb* dut) {
@@ -140,77 +78,42 @@ void reset(Vtlb* dut) {
tick(dut);
tick(dut);
dut->rst = 0;
- eval_comb(dut);
+ dut->eval();
+}
+
+uint64_t sv39_vpn(uint64_t vaddr) {
+ return (vaddr >> 12) & ((1ULL << 27) - 1ULL);
}
-void do_refill(
- Vtlb* dut,
- uint64_t vpn,
- uint64_t ppn,
- uint8_t level,
- uint8_t mode,
- uint16_t asid,
- bool g,
- bool u,
- bool r,
- bool w,
- bool x,
- bool a,
- bool d
-) {
+void refill(Vtlb* dut, uint64_t vpn, uint64_t ppn, bool r, bool w, bool x, bool a, bool d) {
clear_refill(dut);
dut->refill_valid = 1;
dut->refill_vpn = vpn;
dut->refill_ppn = ppn;
- dut->refill_level = level;
- dut->refill_mode = mode;
- dut->refill_asid = asid;
- dut->refill_g = g;
- dut->refill_u = u;
+ dut->refill_level = 0;
+ dut->refill_mode = MODE_SV39;
+ dut->refill_asid = 1;
dut->refill_r = r;
dut->refill_w = w;
dut->refill_x = x;
dut->refill_a = a;
dut->refill_d = d;
tick(dut);
- dut->refill_valid = 0;
- eval_comb(dut);
-}
-
-void issue_load(Vtlb* dut, uint64_t vaddr, uint16_t asid, uint8_t mode) {
- clear_req(dut);
- dut->req_valid = 1;
- dut->req_vaddr = vaddr;
- dut->req_asid = asid;
- dut->req_mode = mode;
- dut->req_priv = 1; // S mode
- dut->req_is_fetch = 0;
- dut->req_is_store = 0;
- eval_comb(dut);
+ clear_refill(dut);
+ dut->eval();
}
-void issue_req(
- Vtlb* dut,
- uint64_t vaddr,
- uint16_t asid,
- uint8_t mode,
- uint8_t priv,
- bool is_fetch,
- bool is_store,
- bool sum,
- bool mxr
-) {
+void request(Vtlb* dut, uint64_t vaddr, uint8_t mode, bool fetch, bool store, bool mxr = false) {
clear_req(dut);
dut->req_valid = 1;
dut->req_vaddr = vaddr;
- dut->req_asid = asid;
+ dut->req_asid = 1;
dut->req_mode = mode;
- dut->req_priv = priv;
- dut->req_is_fetch = is_fetch;
- dut->req_is_store = is_store;
- dut->req_sum = sum;
+ dut->req_priv = 1;
+ dut->req_is_fetch = fetch;
+ dut->req_is_store = store;
dut->req_mxr = mxr;
- eval_comb(dut);
+ dut->eval();
}
} // namespace
@@ -225,255 +128,43 @@ int main(int argc, char** argv) {
reset(dut);
- // 1) Bare mode bypass
- clear_req(dut);
- dut->req_valid = 1;
- dut->req_mode = MODE_BARE;
- dut->req_vaddr = 0x1234'5678'9ABC'DEF0ULL;
- dut->req_priv = 1;
- eval_comb(dut);
+ request(dut, 0x123456789abcdef0ULL, MODE_BARE, false, false);
check(dut->resp_hit == 1, "Bare_Bypass_Hit");
check(dut->resp_page_fault == 0, "Bare_Bypass_NoFault");
- check(dut->resp_need_ptw == 0, "Bare_Bypass_NoPTW");
- check(dut->resp_paddr == dut->req_vaddr, "Bare_Bypass_PaddrEqualsVaddr");
-
- // 2) Unsupported mode faults
- clear_req(dut);
- dut->req_valid = 1;
- dut->req_mode = 4;
- dut->req_vaddr = 0x8000'0000ULL;
- eval_comb(dut);
- check(dut->resp_page_fault == 1, "UnsupportedMode_PageFault");
-
- // 3) Miss => need PTW
- issue_load(dut, 0x0000'0000'8040'1000ULL, 1, MODE_SV48);
- check(dut->resp_hit == 0, "Miss_NoHit");
- check(dut->resp_need_ptw == 1, "Miss_NeedPTW");
- check(dut->resp_page_fault == 0, "Miss_NoFault");
-
- // 4) Refill then hit
- const uint64_t va1 = 0x0000'0000'8040'1234ULL;
- const uint64_t vpn1 = sv48_vpn(va1);
- const uint64_t ppn1 = 0x12345ULL;
- do_refill(dut, vpn1, ppn1, 0, MODE_SV48, 1, false, false, true, true, false, true, true);
- issue_load(dut, va1, 1, MODE_SV48);
- check(dut->resp_hit == 1, "Refill_Hit");
- check(dut->resp_page_fault == 0, "Refill_NoFault");
- check(dut->resp_paddr == make_paddr(ppn1, va1), "Refill_PaddrMatch");
-
- // 5) ASID mismatch miss when non-global
- issue_load(dut, va1, 2, MODE_SV48);
- check(dut->resp_hit == 0, "AsidMismatch_Miss");
- check(dut->resp_need_ptw == 1, "AsidMismatch_NeedPTW");
-
- // 6) Global entry ignores ASID
- const uint64_t va2 = 0x0000'0000'9000'3456ULL;
- const uint64_t vpn2 = sv48_vpn(va2);
- const uint64_t ppn2 = 0x23456ULL;
- do_refill(dut, vpn2, ppn2, 0, MODE_SV48, 9, true, false, true, false, true, true, true);
- issue_load(dut, va2, 99, MODE_SV48);
- check(dut->resp_hit == 1, "Global_AsidIgnore_Hit");
-
- // 7) Store permission requires W and D
- const uint64_t va3 = 0x0000'0000'A000'2222ULL;
- const uint64_t vpn3 = sv48_vpn(va3);
- do_refill(dut, vpn3, 0x34567ULL, 0, MODE_SV48, 3, false, false, true, true, false, true, false);
- clear_req(dut);
- dut->req_valid = 1;
- dut->req_vaddr = va3;
- dut->req_asid = 3;
- dut->req_mode = MODE_SV48;
- dut->req_priv = 1;
- dut->req_is_store = 1;
- eval_comb(dut);
- check(dut->resp_page_fault == 1, "Store_DBitFault");
-
- // 8) MXR allows load from execute-only page
- const uint64_t va4 = 0x0000'0000'B000'0100ULL;
- const uint64_t vpn4 = sv48_vpn(va4);
- do_refill(dut, vpn4, 0x45678ULL, 0, MODE_SV48, 4, false, false, false, false, true, true, true);
- clear_req(dut);
- dut->req_valid = 1;
- dut->req_vaddr = va4;
- dut->req_asid = 4;
- dut->req_mode = MODE_SV48;
- dut->req_priv = 1;
- dut->req_mxr = 1;
- eval_comb(dut);
- check(dut->resp_hit == 1, "MXR_LoadFromXOnly_Hit");
- check(dut->resp_page_fault == 0, "MXR_LoadFromXOnly_NoFault");
+ check(dut->resp_paddr == 0x123456789abcdef0ULL, "Bare_Bypass_Paddr");
+
+ request(dut, 0x0000000040401000ULL, MODE_SV48, false, false);
+ check(dut->resp_page_fault == 1, "Sv48_Stub_Fault");
+ request(dut, 0x0000000040401000ULL, MODE_SV57, false, false);
+ check(dut->resp_page_fault == 1, "Sv57_Stub_Fault");
+ request(dut, 0x0000000040401000ULL, MODE_SV64, false, false);
+ check(dut->resp_page_fault == 1, "Sv64_Stub_Fault");
+
+ const uint64_t va = 0x0000000040401234ULL;
+ const uint64_t ppn = 0x45670ULL;
+ request(dut, va, MODE_SV39, false, false);
+ check(dut->resp_hit == 0, "Sv39_Miss_NoHit");
+ check(dut->resp_need_ptw == 1, "Sv39_Miss_NeedPTW");
+ check(dut->resp_page_fault == 0, "Sv39_Miss_NoFault");
+
+ refill(dut, sv39_vpn(va), ppn, true, true, false, true, true);
+ request(dut, va, MODE_SV39, false, false);
+ check(dut->resp_hit == 1, "Sv39_Refill_Hit");
+ check(dut->resp_paddr == ((ppn << 12) | (va & 0xfffULL)), "Sv39_Refill_Paddr");
+
+ refill(dut, sv39_vpn(0x0000000040500000ULL), 0x50000ULL, true, true, false, true, false);
+ request(dut, 0x0000000040500000ULL, MODE_SV39, false, true);
+ check(dut->resp_page_fault == 1, "Sv39_Store_D0_Fault");
+
+ refill(dut, sv39_vpn(0x0000000040600000ULL), 0x60000ULL, false, false, true, true, false);
+ request(dut, 0x0000000040600000ULL, MODE_SV39, false, false, true);
+ check(dut->resp_hit == 1, "Sv39_MXR_LoadFromXOnly");
+
+ request(dut, 0x0000008000000000ULL, MODE_SV39, false, false);
+ check(dut->resp_page_fault == 1, "Sv39_NonCanonical_Fault");
- // 9) Superpage match (Sv48 level=1) ignores low VPN[8:0]
- const uint64_t va5a = 0x0000'0000'C123'4000ULL;
- const uint64_t va5b = 0x0000'0000'C123'8ABCULL; // same high VPN, different low VPN bits
- const uint64_t vpn5 = sv48_vpn(va5a);
- do_refill(dut, vpn5, 0x56780ULL, 1, MODE_SV48, 5, false, false, true, true, true, true, true);
- issue_load(dut, va5b, 5, MODE_SV48);
- check(dut->resp_hit == 1, "Superpage_Level1_Hit");
-
- // 10) Flush all invalidates
- apply_flush_all(dut);
- issue_load(dut, va1, 1, MODE_SV48);
- check(dut->resp_hit == 0, "FlushAll_Invalidates");
-
- // 11) Flush by ASID only invalidates matching non-global entries
- const uint64_t va6a = 0x0000'0000'D000'1111ULL;
- const uint64_t va6b = 0x0000'0000'D000'2222ULL;
- do_refill(dut, sv48_vpn(va6a), 0x60100ULL, 0, MODE_SV48, 7, false, false, true, true, false, true, true);
- do_refill(dut, sv48_vpn(va6b), 0x60200ULL, 0, MODE_SV48, 8, false, false, true, true, false, true, true);
- apply_flush_asid(dut, 7);
- issue_load(dut, va6a, 7, MODE_SV48);
- check(dut->resp_hit == 0, "FlushAsid_TargetInvalidated");
- issue_load(dut, va6b, 8, MODE_SV48);
- check(dut->resp_hit == 1, "FlushAsid_OtherAsidPreserved");
-
- // 12) Flush by VPN only invalidates matching VPN in the selected mode
- const uint64_t va7a = 0x0000'0000'E100'0123ULL;
- const uint64_t va7b = 0x0000'0000'E200'0456ULL;
- do_refill(dut, sv48_vpn(va7a), 0x70100ULL, 0, MODE_SV48, 9, false, false, true, true, false, true, true);
- do_refill(dut, sv48_vpn(va7b), 0x70200ULL, 0, MODE_SV48, 9, false, false, true, true, false, true, true);
- apply_flush_vpn(dut, sv48_vpn(va7a), MODE_SV48);
- issue_load(dut, va7a, 9, MODE_SV48);
- check(dut->resp_hit == 0, "FlushVpn_TargetInvalidated");
- issue_load(dut, va7b, 9, MODE_SV48);
- check(dut->resp_hit == 1, "FlushVpn_OtherVpnPreserved");
-
- // 13) Sv32 superpage boundary: level=1 ignores low VPN[9:0]
- const uint64_t va32a = 0x0000000081234000ULL;
- const uint64_t va32b = 0x00000000813FFABCULL;
- do_refill(dut, sv32_vpn(va32a), 0x31000ULL, 1, MODE_SV32, 11, false, false, true, true, false, true, true);
- issue_load(dut, va32b, 11, MODE_SV32);
- check(dut->resp_hit == 1, "Sv32_Superpage_Level1_Hit");
- check(dut->resp_page_fault == 0, "Sv32_Superpage_NoFault");
-
- // 14) Sv57 superpage boundary: level=2 ignores low VPN[17:0]
- const uint64_t va57a = 0x0012'3456'7800'4000ULL;
- const uint64_t va57b = 0x0012'3456'7BFF'8ABCULL;
- do_refill(dut, sv57_vpn(va57a), 0x4A1234ULL, 2, MODE_SV57, 12, false, false, true, true, false, true, true);
- issue_load(dut, va57b, 12, MODE_SV57);
- check(dut->resp_hit == 1, "Sv57_Superpage_Level2_Hit");
- check(dut->resp_page_fault == 0, "Sv57_Superpage_NoFault");
-
- // 15) Flush VPN mode filter: Sv32 flush must not touch Sv48 entry with same low VPN
- const uint64_t va8 = 0x0000'0000'8123'4567ULL;
- const uint64_t vpn32 = sv32_vpn(va8);
- const uint64_t vpn48_same_low = vpn32;
- do_refill(dut, vpn32, 0x81000ULL, 0, MODE_SV32, 13, false, false, true, true, false, true, true);
- do_refill(dut, vpn48_same_low, 0x82000ULL, 0, MODE_SV48, 13, false, false, true, true, false, true, true);
- apply_flush_vpn(dut, vpn32, MODE_SV32);
- issue_load(dut, va8, 13, MODE_SV32);
- check(dut->resp_hit == 0, "FlushVpn_ModeFilter_Sv32Invalidated");
- issue_load(dut, va8, 13, MODE_SV48);
- check(dut->resp_hit == 1, "FlushVpn_ModeFilter_Sv48Preserved");
-
- // 16) S-mode access to U=1 page requires SUM for data access
- const uint64_t va9 = 0x0000'0000'8333'0100ULL;
- do_refill(dut, sv48_vpn(va9), 0x83000ULL, 0, MODE_SV48, 14, false, true, true, true, false, true, true);
- issue_req(dut, va9, 14, MODE_SV48, 1, false, false, false, false);
- check(dut->resp_page_fault == 1, "SUM_SmodeLoadUPage_Sum0_Fault");
- issue_req(dut, va9, 14, MODE_SV48, 1, false, false, true, false);
- check(dut->resp_hit == 1, "SUM_SmodeLoadUPage_Sum1_Hit");
- check(dut->resp_page_fault == 0, "SUM_SmodeLoadUPage_Sum1_NoFault");
-
- // 17) SUM must not allow S-mode instruction fetch from U page
- issue_req(dut, va9, 14, MODE_SV48, 1, true, false, true, false);
- check(dut->resp_page_fault == 1, "SUM_SmodeFetchUPage_AlwaysFault");
-
- // 18) U-mode cannot access U=0 page
- const uint64_t va10 = 0x0000'0000'8444'0200ULL;
- do_refill(dut, sv48_vpn(va10), 0x84000ULL, 0, MODE_SV48, 15, false, false, true, true, true, true, true);
- issue_req(dut, va10, 15, MODE_SV48, 0, false, false, false, false);
- check(dut->resp_page_fault == 1, "Umode_LoadSupervisorPage_Fault");
-
- // 19) U-mode can load U=1 page when permissions allow
- const uint64_t va11 = 0x0000'0000'8555'0300ULL;
- do_refill(dut, sv48_vpn(va11), 0x85000ULL, 0, MODE_SV48, 16, false, true, true, false, false, true, true);
- issue_req(dut, va11, 16, MODE_SV48, 0, false, false, false, false);
- check(dut->resp_hit == 1, "Umode_LoadUserPage_Hit");
- check(dut->resp_page_fault == 0, "Umode_LoadUserPage_NoFault");
-
- // 20) MXR matrix: execute-only page load faults when mxr=0, passes when mxr=1
- const uint64_t va12 = 0x0000'0000'8666'0400ULL;
- do_refill(dut, sv48_vpn(va12), 0x86000ULL, 0, MODE_SV48, 17, false, false, false, false, true, true, true);
- issue_req(dut, va12, 17, MODE_SV48, 1, false, false, false, false);
- check(dut->resp_page_fault == 1, "MXR_LoadXOnly_Mxr0_Fault");
- issue_req(dut, va12, 17, MODE_SV48, 1, false, false, false, true);
- check(dut->resp_hit == 1, "MXR_LoadXOnly_Mxr1_Hit");
- check(dut->resp_page_fault == 0, "MXR_LoadXOnly_Mxr1_NoFault");
-
- // 21) A-bit required for any access type (load/fetch)
- const uint64_t va13 = 0x0000'0000'8777'0500ULL;
- do_refill(dut, sv48_vpn(va13), 0x87000ULL, 0, MODE_SV48, 18, false, false, true, true, true, false, true);
- issue_req(dut, va13, 18, MODE_SV48, 1, false, false, false, false);
- check(dut->resp_page_fault == 1, "ABit_LoadFault_WhenA0");
- issue_req(dut, va13, 18, MODE_SV48, 1, true, false, false, false);
- check(dut->resp_page_fault == 1, "ABit_FetchFault_WhenA0");
-
- // 22) ASID-targeted flush must preserve global entries
- const uint64_t va14 = 0x0000'0000'8888'0600ULL;
- do_refill(dut, sv48_vpn(va14), 0x88000ULL, 0, MODE_SV48, 33, true, false, true, true, false, true, true);
- apply_flush_asid(dut, 33);
- issue_load(dut, va14, 99, MODE_SV48);
- check(dut->resp_hit == 1, "FlushAsid_GlobalPreserved");
-
- // 23) Refill pressure should eventually evict oldest entry (round-robin)
- apply_flush_all(dut);
- const uint64_t va15 = 0x0000'0000'9000'1000ULL;
- do_refill(dut, sv48_vpn(va15), 0x90001ULL, 0, MODE_SV48, 40, false, false, true, true, false, true, true);
- for (int n = 0; n < 32; ++n) {
- const uint64_t va_fill = 0x0000'0001'0000'0000ULL + (static_cast<uint64_t>(n) << 12);
- const uint64_t ppn_fill = 0x91000ULL + static_cast<uint64_t>(n);
- do_refill(dut, sv48_vpn(va_fill), ppn_fill, 0, MODE_SV48, static_cast<uint16_t>(50 + n), false, false, true, true, false, true, true);
- }
- issue_load(dut, va15, 40, MODE_SV48);
- check(dut->resp_hit == 0, "ReplacementPressure_OldestEvicted");
-
- // 24) Newest refill remains accessible after pressure
- const uint64_t va16 = 0x0000'0001'0001'F000ULL;
- do_refill(dut, sv48_vpn(va16), 0xA001FULL, 0, MODE_SV48, 77, false, false, true, true, false, true, true);
- issue_load(dut, va16, 77, MODE_SV48);
- check(dut->resp_hit == 1, "ReplacementPressure_NewestEntryHits");
-
- // 25) flush_vpn should invalidate Sv48 level-1 superpage for any VPN within same range
- apply_flush_all(dut);
- const uint64_t va17_base = 0x0000'0001'2340'0000ULL;
- const uint64_t va17_same_superpage = 0x0000'0001'2341'2ABCULL;
- const uint64_t va17_other_superpage = 0x0000'0001'2440'0555ULL;
- do_refill(dut, sv48_vpn(va17_base), 0xB1000ULL, 1, MODE_SV48, 88, false, false, true, true, false, true, true);
- do_refill(dut, sv48_vpn(va17_other_superpage), 0xB2000ULL, 1, MODE_SV48, 88, false, false, true, true, false, true, true);
- apply_flush_vpn(dut, sv48_vpn(va17_same_superpage), MODE_SV48);
- issue_load(dut, va17_base, 88, MODE_SV48);
- check(dut->resp_hit == 0, "FlushVpn_Sv48L1_SameSuperpageInvalidated");
- issue_load(dut, va17_other_superpage, 88, MODE_SV48);
- check(dut->resp_hit == 1, "FlushVpn_Sv48L1_OtherSuperpagePreserved");
-
- // 26) flush_vpn should invalidate Sv57 level-2 superpage with 18-bit VPN wildcard
- apply_flush_all(dut);
- const uint64_t va18_base = 0x0012'3456'7800'1000ULL;
- const uint64_t va18_same_superpage = 0x0012'3456'7BFF'8FFFULL;
- const uint64_t va18_other_superpage = 0x0012'345A'0000'2000ULL;
- do_refill(dut, sv57_vpn(va18_base), 0xC1234ULL, 2, MODE_SV57, 99, false, false, true, true, false, true, true);
- do_refill(dut, sv57_vpn(va18_other_superpage), 0xC5678ULL, 2, MODE_SV57, 99, false, false, true, true, false, true, true);
- apply_flush_vpn(dut, sv57_vpn(va18_same_superpage), MODE_SV57);
- issue_load(dut, va18_base, 99, MODE_SV57);
- check(dut->resp_hit == 0, "FlushVpn_Sv57L2_SameSuperpageInvalidated");
- issue_load(dut, va18_other_superpage, 99, MODE_SV57);
- check(dut->resp_hit == 1, "FlushVpn_Sv57L2_OtherSuperpagePreserved");
-
- // 27) flush_vpn with exact-page entry must not over-invalidate neighboring pages
- apply_flush_all(dut);
- const uint64_t va19_a = 0x0000'0000'9900'1000ULL;
- const uint64_t va19_b = 0x0000'0000'9900'2000ULL;
- do_refill(dut, sv48_vpn(va19_a), 0xD1000ULL, 0, MODE_SV48, 120, false, false, true, true, false, true, true);
- do_refill(dut, sv48_vpn(va19_b), 0xD2000ULL, 0, MODE_SV48, 120, false, false, true, true, false, true, true);
- apply_flush_vpn(dut, sv48_vpn(va19_a), MODE_SV48);
- issue_load(dut, va19_a, 120, MODE_SV48);
- check(dut->resp_hit == 0, "FlushVpn_Level0_OnlyTargetInvalidated");
- issue_load(dut, va19_b, 120, MODE_SV48);
- check(dut->resp_hit == 1, "FlushVpn_Level0_NeighborPreserved");
-
- std::cout << "\n----------------------------------\n";
- std::cout << "TLB tests passed: " << g_pass_count << "\n";
+ std::cout << "----------------------------------\n";
+ std::cout << "All " << g_pass_count << " TLB tests passed!\n";
std::cout << "----------------------------------\n";
delete dut;