Skip to content

Commit 7fd4f2d

Browse files
committed
Tests: add integration test for SV32 page-table and TLB
Add a set of small assembly tests that exercise the SV32 page-table walker, SATP enablement and the new TLB code. The tests create a root page table and map a virtual page at 0xC4000000, then exercise several scenarios. The tests verify page-table walker behaviour, SATP switching and TLB caching/flush logic. Tests were written based on the consultation.
1 parent 3c24225 commit 7fd4f2d

File tree

11 files changed

+744
-0
lines changed

11 files changed

+744
-0
lines changed

src/cli/CMakeLists.txt

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,43 @@ add_cli_test(
7777
--asm "${CMAKE_SOURCE_DIR}/tests/cli/modifiers-pcrel/program.S"
7878
EXPECTED_OUTPUT "tests/cli/modifiers-pcrel/stdout.txt"
7979
)
80+
81+
add_cli_test(
82+
NAME virtual_memory_template
83+
ARGS
84+
--asm "${CMAKE_SOURCE_DIR}/tests/cli/virtual_memory/template/program.S"
85+
--dump-registers
86+
EXPECTED_OUTPUT "tests/cli/virtual_memory/template/stdout.txt"
87+
)
88+
89+
add_cli_test(
90+
NAME virtual_memory_dtlb
91+
ARGS
92+
--asm "${CMAKE_SOURCE_DIR}/tests/cli/virtual_memory/dtlb/program.S"
93+
--dump-registers
94+
EXPECTED_OUTPUT "tests/cli/virtual_memory/dtlb/stdout.txt"
95+
)
96+
97+
add_cli_test(
98+
NAME virtual_memory_itlb
99+
ARGS
100+
--asm "${CMAKE_SOURCE_DIR}/tests/cli/virtual_memory/itlb/program.S"
101+
--dump-registers
102+
EXPECTED_OUTPUT "tests/cli/virtual_memory/itlb/stdout.txt"
103+
)
104+
105+
add_cli_test(
106+
NAME virtual_memory_memrw
107+
ARGS
108+
--asm "${CMAKE_SOURCE_DIR}/tests/cli/virtual_memory/memrw/program.S"
109+
--dump-registers
110+
EXPECTED_OUTPUT "tests/cli/virtual_memory/memrw/stdout.txt"
111+
)
112+
113+
add_cli_test(
114+
NAME virtual_memory_exec
115+
ARGS
116+
--asm "${CMAKE_SOURCE_DIR}/tests/cli/virtual_memory/exec/program.S"
117+
--dump-registers
118+
EXPECTED_OUTPUT "tests/cli/virtual_memory/exec/stdout.txt"
119+
)
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
// D-TLB test — map data pages at MAP_VA; write 'A'..'H' to the first byte of eight pages and read/print them.
2+
3+
.globl _start
4+
.option norelax
5+
6+
// Serial port/terminal registers
7+
.equ SERIAL_PORT_BASE, 0xffffc000 // base address of serial port region
8+
.equ SERP_RX_ST_REG_o, 0x0000 // Offset of RX_ST_REG
9+
.equ SERP_RX_DATA_REG_o, 0x0004 // Offset of RX_DATA_REG
10+
.equ SERP_TX_ST_REG_o, 0x0008 // Offset of TX_ST_REG
11+
.equ SERP_TX_ST_REG_READY_m,0x1 // Transmitter can accept next byte
12+
.equ SERP_TX_DATA_REG_o, 0x000c // Offset of TX_DATA_REG
13+
14+
.equ ROOT_PT_PHYS, 0x1000
15+
.equ MAP_VA, 0xC4000000
16+
17+
// PTE flags: 0xCF = 11001111
18+
// bit0 V = 1 (Valid)
19+
// bit1 R = 1 (Readable)
20+
// bit2 W = 1 Writable)
21+
// bit3 X = 1 (Executable)
22+
// bit4 U = 0 (NOT user-accessible)
23+
// bit5 G = 0 (NOT global)
24+
// bit6 A = 1 (Accessed)
25+
// bit7 D = 1 (Dirty)
26+
.equ PTE_FLAGS_FULL, 0xCF
27+
28+
// mstatus MPP manipulation masks (for preparing mret to change privilege)
29+
.equ MSTATUS_MPP_CLEAR, 0x1000 // mask to clear MPP[12] (set bit 12 -> will be cleared via csrrc)
30+
.equ MSTATUS_MPP_SET, 0x800 // mask to set MPP[11] (set bit 11 -> will be set via csrrs)
31+
32+
.equ SATP_ENABLE, 0x80000001 // satp value to enable paging (implementation-specific)
33+
34+
.org 0x00000200
35+
.text
36+
_start:
37+
// t0 = physical address of root page table
38+
li t0, ROOT_PT_PHYS
39+
40+
// t4 = virtual address we want to map (MAP_VA)
41+
li t4, MAP_VA
42+
43+
// Build a leaf PTE value in t1:
44+
// Take VA >> 12 (remove page offset) then shift left 10 to position PPN bits for a PTE,
45+
// then OR in the PTE flags.
46+
srli t1, t4, 12 // t1 = MAP_VA >> 12 (page number)
47+
slli t1, t1, 10 // t1 <<= 10 to position as PPN bits for a PTE entry
48+
li t6, PTE_FLAGS_FULL // t6 = flags
49+
or t1, t1, t6 // t1 = (PPN << 10) | PTE_FLAGS_FULL
50+
51+
// Calculate the root page table entry index for the high VPN (VPN[1]):
52+
// t5 = MAP_VA >> 22 (VPN[1])
53+
// t2 = t5 << 2 (multiply by 4 bytes per PTE to get byte offset)
54+
// t3 = root_pt_phys + offset (address of PTE in root page table)
55+
srli t5, t4, 22
56+
slli t2, t5, 2
57+
add t3, t0, t2
58+
59+
// Store the constructed PTE into the root page table (making a mapping)
60+
sw t1, 0(t3)
61+
fence
62+
63+
// Ensure satp is cleared before setting new value (flush previous translations)
64+
li t0, 0
65+
csrw satp, t0
66+
67+
// Enable the MMU by writing SATP; this switches address translation on
68+
li t0, SATP_ENABLE
69+
csrw satp, t0
70+
fence
71+
72+
// Prepare mstatus MPP so that mret will return to Supervisor mode:
73+
// Clear MPP[12] bit then set MPP[11] bit (resulting MPP=01 => Supervisor).
74+
li t0, MSTATUS_MPP_CLEAR
75+
csrrc zero, mstatus, t0 // clear bit 12 of mstatus.MPP
76+
li t0, MSTATUS_MPP_SET
77+
csrrs zero, mstatus, t0 // set bit 11 of mstatus.MPP
78+
79+
// Set mepc to the virtual address of vm_entry and return from machine mode to
80+
// the prepared privilege level (Supervisor) using mret.
81+
la t0, vm_entry // load address of vm_entry (virtual address after mapping)
82+
csrw mepc, t0
83+
mret
84+
85+
.org 0xC4000000
86+
.text
87+
vm_entry:
88+
li t0, SERIAL_PORT_BASE
89+
la t1, MAP_VA // pointer to start of mapped virtual region
90+
li t2, 0 // page counter
91+
li t3, 8 // number of pages to write/read (A..H)
92+
li t4, 65 // ASCII 'A'
93+
li t5, 0x1000 // page size (4KB)
94+
95+
// write_pages_loop: write one byte (A..H) at the start of each mapped page.
96+
write_pages_loop:
97+
sb t4, 0(t1)
98+
add t1, t1, t5
99+
addi t4, t4, 1
100+
addi t2, t2, 1
101+
blt t2, t3, write_pages_loop
102+
103+
// Reset pointer and counter to read back and print the first byte of each page.
104+
la t1, MAP_VA
105+
li t2, 0
106+
107+
read_print_loop:
108+
lb t6, 0(t1) // load the byte stored at start of current page
109+
110+
// wait_tx: poll transmitter status until ready, then write byte to TX data reg.
111+
wait_tx:
112+
lw t4, SERP_TX_ST_REG_o(t0)
113+
andi t4, t4, SERP_TX_ST_REG_READY_m
114+
beq t4, zero, wait_tx
115+
sw t6, SERP_TX_DATA_REG_o(t0)
116+
117+
add t1, t1, t5
118+
addi t2, t2, 1
119+
blt t2, t3, read_print_loop
120+
121+
ebreak
122+
123+
1: auipc t0, 0
124+
jalr zero, 0(t0)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Machine stopped on BREAK exception.
2+
Machine state report:
3+
PC:0xc4000078
4+
R0:0x00000000 R1:0x00000000 R2:0xbfffff00 R3:0x00000000 R4:0x00000000 R5:0xffffffffffffc000 R6:0xffffffffc4008000 R7:0x00000008 R8:0x00000000 R9:0x00000000 R10:0x00000000 R11:0x00000000 R12:0x00000000 R13:0x00000000 R14:0x00000000 R15:0x00000000 R16:0x00000000 R17:0x00000000 R18:0x00000000 R19:0x00000000 R20:0x00000000 R21:0x00000000 R22:0x00000000 R23:0x00000000 R24:0x00000000 R25:0x00000000 R26:0x00000000 R27:0x00000000 R28:0x00000008 R29:0x00000001 R30:0x00001000 R31:0x00000048
5+
cycle: 0x00000098 mvendorid: 0x00000000 marchid: 0x00000000 mimpid: 0x00000000 mhardid: 0x00000000 mstatus: 0x00000080 misa: 0x40001111 mie: 0x00000000 mtvec: 0x00000000 mscratch: 0x00000000 mepc: 0xc4000074 mcause: 0x00000003 mtval: 0x00000000 mip: 0x00000000 mtinst: 0x00000000 mtval2: 0x00000000 mcycle: 0x00000098 minstret: 0x00000097 sstatus: 0x00000000 stvec: 0x00000000 sscratch: 0x00000000 sepc: 0x00000000 scause: 0x00000000 stval: 0x00000000 satp: 0x80000001
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// Place a tiny function in the mapped virtual page and jump to it (tests X bit).
2+
3+
.globl _start
4+
.option norelax
5+
6+
// Serial port/terminal registers
7+
.equ SERIAL_PORT_BASE, 0xffffc000 // base address of serial port region
8+
.equ SERP_RX_ST_REG_o, 0x0000 // Offset of RX_ST_REG
9+
.equ SERP_RX_DATA_REG_o, 0x0004 // Offset of RX_DATA_REG
10+
.equ SERP_TX_ST_REG_o, 0x0008 // Offset of TX_ST_REG
11+
.equ SERP_TX_ST_REG_READY_m,0x1 // Transmitter can accept next byte
12+
.equ SERP_TX_DATA_REG_o, 0x000c // Offset of TX_DATA_REG
13+
14+
.equ ROOT_PT_PHYS, 0x1000
15+
.equ MAP_VA, 0xC4000000
16+
17+
// PTE flags: 0xCF = 11001111
18+
// bit0 V = 1 (Valid)
19+
// bit1 R = 1 (Readable)
20+
// bit2 W = 1 Writable)
21+
// bit3 X = 1 (Executable)
22+
// bit4 U = 0 (NOT user-accessible)
23+
// bit5 G = 0 (NOT global)
24+
// bit6 A = 1 (Accessed)
25+
// bit7 D = 1 (Dirty)
26+
.equ PTE_FLAGS_FULL, 0xCF
27+
28+
// mstatus MPP manipulation masks (for preparing mret to change privilege)
29+
.equ MSTATUS_MPP_CLEAR, 0x1000 // mask to clear MPP[12] (set bit 12 -> will be cleared via csrrc)
30+
.equ MSTATUS_MPP_SET, 0x800 // mask to set MPP[11] (set bit 11 -> will be set via csrrs)
31+
32+
.equ SATP_ENABLE, 0x80000001 // satp value to enable paging (implementation-specific)
33+
34+
.org 0x00000200
35+
.text
36+
_start:
37+
// t0 = physical address of root page table
38+
li t0, ROOT_PT_PHYS
39+
40+
// t4 = virtual address we want to map (MAP_VA)
41+
li t4, MAP_VA
42+
43+
// Build a leaf PTE value in t1:
44+
// Take VA >> 12 (remove page offset) then shift left 10 to position PPN bits for a PTE,
45+
// then OR in the PTE flags.
46+
srli t1, t4, 12 // t1 = MAP_VA >> 12 (page number)
47+
slli t1, t1, 10 // t1 <<= 10 to position as PPN bits for a PTE entry
48+
li t6, PTE_FLAGS_FULL // t6 = flags
49+
or t1, t1, t6 // t1 = (PPN << 10) | PTE_FLAGS_FULL
50+
51+
// Calculate the root page table entry index for the high VPN (VPN[1]):
52+
// t5 = MAP_VA >> 22 (VPN[1])
53+
// t2 = t5 << 2 (multiply by 4 bytes per PTE to get byte offset)
54+
// t3 = root_pt_phys + offset (address of PTE in root page table)
55+
srli t5, t4, 22
56+
slli t2, t5, 2
57+
add t3, t0, t2
58+
59+
// Store the constructed PTE into the root page table (making a mapping)
60+
sw t1, 0(t3)
61+
fence
62+
63+
// Ensure satp is cleared before setting new value (flush previous translations)
64+
li t0, 0
65+
csrw satp, t0
66+
67+
// Enable the MMU by writing SATP; this switches address translation on
68+
li t0, SATP_ENABLE
69+
csrw satp, t0
70+
fence
71+
72+
// Prepare mstatus MPP so that mret will return to Supervisor mode:
73+
// Clear MPP[12] bit then set MPP[11] bit (resulting MPP=01 => Supervisor).
74+
li t0, MSTATUS_MPP_CLEAR
75+
csrrc zero, mstatus, t0 // clear bit 12 of mstatus.MPP
76+
li t0, MSTATUS_MPP_SET
77+
csrrs zero, mstatus, t0 // set bit 11 of mstatus.MPP
78+
79+
// Set mepc to the virtual address of vm_entry and return from machine mode to
80+
// the prepared privilege level (Supervisor) using mret.
81+
la t0, vm_entry // load address of vm_entry (virtual address after mapping)
82+
csrw mepc, t0
83+
mret
84+
85+
.org 0xC4000000
86+
.text
87+
vm_entry:
88+
li a0, SERIAL_PORT_BASE
89+
90+
// Call the function placed in the same mapped page
91+
la t0, mapped_function
92+
jalr zero, 0(t0)
93+
94+
ebreak
95+
96+
// small function placed in the mapped page
97+
.org 0xC4000100
98+
mapped_function:
99+
li a0, SERIAL_PORT_BASE
100+
li t1, 88
101+
wait_tx:
102+
lw t0, SERP_TX_ST_REG_o(a0)
103+
andi t0, t0, SERP_TX_ST_REG_READY_m
104+
beq t0, zero, wait_tx
105+
sw t1, SERP_TX_DATA_REG_o(a0)
106+
ebreak
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Machine stopped on BREAK exception.
2+
Machine state report:
3+
PC:0xc4000124
4+
R0:0x00000000 R1:0x00000000 R2:0xbfffff00 R3:0x00000000 R4:0x00000000 R5:0x00000001 R6:0x00000058 R7:0x00000c40 R8:0x00000000 R9:0x00000000 R10:0xffffffffffffc000 R11:0x00000000 R12:0x00000000 R13:0x00000000 R14:0x00000000 R15:0x00000000 R16:0x00000000 R17:0x00000000 R18:0x00000000 R19:0x00000000 R20:0x00000000 R21:0x00000000 R22:0x00000000 R23:0x00000000 R24:0x00000000 R25:0x00000000 R26:0x00000000 R27:0x00000000 R28:0x00001c40 R29:0xffffffffc4000000 R30:0x00000310 R31:0x000000cf
5+
cycle: 0x0000002d mvendorid: 0x00000000 marchid: 0x00000000 mimpid: 0x00000000 mhardid: 0x00000000 mstatus: 0x00000080 misa: 0x40001111 mie: 0x00000000 mtvec: 0x00000000 mscratch: 0x00000000 mepc: 0xc4000120 mcause: 0x00000003 mtval: 0x00000000 mip: 0x00000000 mtinst: 0x00000000 mtval2: 0x00000000 mcycle: 0x0000002d minstret: 0x0000002c sstatus: 0x00000000 stvec: 0x00000000 sscratch: 0x00000000 sepc: 0x00000000 scause: 0x00000000 stval: 0x00000000 satp: 0x80000001

0 commit comments

Comments
 (0)