diff options
| author | Richard Qin <richard.qin.x@gmail.com> | 2026-11-07 02:59:33 +0800 |
|---|---|---|
| committer | Richard Qin <richard.qin.x@gmail.com> | 2026-11-07 02:59:33 +0800 |
| commit | bc3ec25107314be3cd816c0b669d82338e892806 (patch) | |
| tree | ff3e69ce6be1218be8bd0dd04e0c75760776d7dc /rv64cpu/tb/unit/tb_tlb.cc | |
| parent | c67ba709482821f37d63601b001ac07e6db867b6 (diff) | |
| download | rcc-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.cc | 421 |
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; |
