1 """MMU PortInterface Test
3 quite basic, goes directly to the MMU to assert signals (does not
7 from nmigen
import (C
, Module
, Signal
, Elaboratable
, Mux
, Cat
, Repl
, Signal
)
8 from nmigen
.cli
import main
9 from nmigen
.cli
import rtlil
10 from nmutil
.mask
import Mask
, masked
11 from nmutil
.util
import Display
12 from random
import randint
, seed
15 from nmigen
.back
.pysim
import Simulator
, Delay
, Settle
17 from nmigen
.sim
.cxxsim
import Simulator
, Delay
, Settle
18 from nmutil
.util
import wrap
20 from soc
.config
.test
.test_pi2ls
import pi_ld
, pi_st
, pi_ldst
21 from soc
.config
.test
.test_loadstore
import TestMemPspec
22 from soc
.config
.loadstore
import ConfigMemoryPortInterface
24 from soc
.fu
.ldst
.loadstore
import LoadStore1
25 from soc
.experiment
.mmu
import MMU
27 from nmigen
.compat
.sim
import run_simulation
32 def b(x
): # byte-reverse function
33 return int.from_bytes(x
.to_bytes(8, byteorder
='little'),
34 byteorder
='big', signed
=False)
37 """simulator process for getting memory load requests
44 while True: # wait for dc_valid
52 addr
= (yield wb
.adr
) << 3
54 print (" WB LOOKUP NO entry @ %x, returning zero" % (addr
))
59 store
= (yield wb
.dat_w
)
61 data
= mem
.get(addr
, 0)
62 # note we assume 8-bit sel, here
71 print (" DCACHE set %x mask %x data %x" % (addr
, sel
, res
))
73 data
= mem
.get(addr
, 0)
74 yield wb
.dat_r
.eq(data
)
75 print (" DCACHE get %x data %x" % (addr
, data
))
83 def mmu_lookup(dut
, addr
):
84 mmu
= dut
.submodules
.mmu
87 print("pi_ld", hex(addr
))
88 data
= yield from pi_ld(dut
.submodules
.ldst
.pi
, addr
, 4, msr_pr
=1)
89 print("pi_ld done, data", hex(data
))
91 # original test code kept for reference
92 while not stop: # wait for dc_valid / err
93 print("waiting for mmu")
94 l_done = yield (mmu.l_out.done)
95 l_err = yield (mmu.l_out.err)
96 l_badtree = yield (mmu.l_out.badtree)
97 l_permerr = yield (mmu.l_out.perm_error)
98 l_rc_err = yield (mmu.l_out.rc_error)
99 l_segerr = yield (mmu.l_out.segerr)
100 l_invalid = yield (mmu.l_out.invalid)
101 if (l_done or l_err or l_badtree or
102 l_permerr or l_rc_err or l_segerr or l_invalid):
106 phys_addr
= yield mmu
.d_out
.addr
107 pte
= yield mmu
.d_out
.pte
108 l_done
= yield (mmu
.l_out
.done
)
109 l_err
= yield (mmu
.l_out
.err
)
110 l_badtree
= yield (mmu
.l_out
.badtree
)
111 print ("translated done %d err %d badtree %d addr %x pte %x" % \
112 (l_done
, l_err
, l_badtree
, phys_addr
, pte
))
114 yield mmu
.l_in
.valid
.eq(0)
120 mmu
= dut
.submodules
.mmu
122 yield mmu
.rin
.prtbl
.eq(0x1000000) # set process table
125 # expecting this data to return
126 # 0x1000: 0xdeadbeef01234567,
127 # 0x1008: 0xfeedf00ff001a5a5
132 # TODO mmu_lookup using port interface
134 data
= yield from mmu_lookup(dut
, addr
)
135 assert data
== 0x1234567
137 data
= yield from mmu_lookup(dut
, addr
+8)
138 assert data
== 0xf001a5a5
139 #assert phys_addr == addr # happens to be the same (for this example)
141 data
= yield from mmu_lookup(dut
, addr
+4)
142 assert data
== 0xdeadbeef
144 data
= yield from mmu_lookup(dut
, addr
+8)
145 assert data
== 0xf001a5a5
147 yield from pi_st(dut
.submodules
.ldst
.pi
, addr
+4, 0x10015a5a, 4, msr_pr
=1)
149 data
= yield from mmu_lookup(dut
, addr
+4)
150 assert data
== 0x10015a5a
162 pspec
= TestMemPspec(ldst_ifacetype
='mmu_cache_wb',
165 #disable_cache=True, # hmmm...
171 cmpi
= ConfigMemoryPortInterface(pspec
)
172 m
.submodules
.ldst
= ldst
= cmpi
.pi
173 m
.submodules
.mmu
= mmu
= MMU()
176 l_in
, l_out
= mmu
.l_in
, mmu
.l_out
177 d_in
, d_out
= dcache
.d_in
, dcache
.d_out
178 wb_out
, wb_in
= dcache
.wb_out
, dcache
.wb_in
180 # link mmu and dcache together
181 m
.d
.comb
+= dcache
.m_in
.eq(mmu
.d_out
) # MMUToDCacheType
182 m
.d
.comb
+= mmu
.d_in
.eq(dcache
.m_out
) # DCacheToMMUType
184 # link ldst and MMU together
185 comb
+= l_in
.eq(ldst
.m_out
)
186 comb
+= ldst
.m_in
.eq(l_out
)
193 m
, cmpi
= setup_mmu()
195 # virtual "memory" to use for this test
197 mem
= {0x10000: # PARTITION_TABLE_2
198 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
199 b(0x800000000100000b),
201 0x30000: # RADIX_ROOT_PTE
202 # V = 1 L = 0 NLB = 0x400 NLS = 9
203 b(0x8000000000040009),
205 0x40000: # RADIX_SECOND_LEVEL
206 # V = 1 L = 1 SW = 0 RPN = 0
207 # R = 1 C = 1 ATT = 0 EAA 0x7
208 b(0xc000000000000183),
210 0x1000000: # PROCESS_TABLE_3
211 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
212 b(0x40000000000300ad),
215 0x1000: 0xdeadbeef01234567,
216 0x1008: 0xfeedf00ff001a5a5
224 sim
.add_sync_process(wrap(ldst_sim(m
)))
225 sim
.add_sync_process(wrap(wb_get(cmpi
.wb_bus(), mem
)))
226 with sim
.write_vcd('test_ldst_pi.vcd'):
230 def ldst_sim_misalign(dut
):
231 mmu
= dut
.submodules
.mmu
235 yield mmu
.rin
.prtbl
.eq(0x1000000) # set process table
238 data
= yield from pi_ld(dut
.submodules
.ldst
.pi
, 0x1007, 8, msr_pr
=1)
239 print ("misalign ld data", hex(data
))
245 def test_misalign_mmu():
247 m
, cmpi
= setup_mmu()
249 # virtual "memory" to use for this test
251 mem
= {0x10000: # PARTITION_TABLE_2
252 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
253 b(0x800000000100000b),
255 0x30000: # RADIX_ROOT_PTE
256 # V = 1 L = 0 NLB = 0x400 NLS = 9
257 b(0x8000000000040009),
259 0x40000: # RADIX_SECOND_LEVEL
260 # V = 1 L = 1 SW = 0 RPN = 0
261 # R = 1 C = 1 ATT = 0 EAA 0x7
262 b(0xc000000000000183),
264 0x1000000: # PROCESS_TABLE_3
265 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
266 b(0x40000000000300ad),
269 0x1000: 0xdeadbeef01234567,
270 0x1008: 0xfeedf00ff001a5a5
278 sim
.add_sync_process(wrap(ldst_sim_misalign(m
)))
279 sim
.add_sync_process(wrap(wb_get(cmpi
.wb_bus(), mem
)))
280 with sim
.write_vcd('test_ldst_pi_misalign.vcd'):
284 def ldst_sim_radixmiss(dut
):
285 mmu
= dut
.submodules
.mmu
289 yield mmu
.rin
.prtbl
.eq(1<<40) # set process table
292 data
= yield from pi_ld(dut
.submodules
.ldst
.pi
, 0x10000000, 8, msr_pr
=1)
293 print ("radixmiss ld data", hex(data
))
298 def ldst_sim_dcache_regression(dut
):
299 mmu
= dut
.submodules
.mmu
303 yield mmu
.rin
.prtbl
.eq(0x1000000) # set process table
307 data
= yield from pi_ld(dut
.submodules
.ldst
.pi
, addr
, 8, msr_pr
=1)
308 print ("=== dcache_regression ld data", hex(data
))
309 assert(data
== 0xdeadbeef01234567)
314 def ldst_sim_dcache_random(dut
):
315 mmu
= dut
.submodules
.mmu
316 pi
= dut
.submodules
.ldst
.pi
320 yield mmu
.rin
.prtbl
.eq(0x1000000) # set process table
326 addr
= randint(0, memsize
-1)
327 data
= randint(0, (1<<64)-1)
331 yield from pi_st(pi
, addr
, data
, 8, msr_pr
=1)
334 ld_data
= yield from pi_ld(pi
, addr
, 8, msr_pr
=1)
337 print ("dcache_random random ld data", hex(data
), hex(ld_data
))
339 print("==== data read at random test differs")
340 assert(data
==ld_data
)
345 def ldst_sim_dcache_first(dut
): # this test is likely to fail
346 mmu
= dut
.submodules
.mmu
347 pi
= dut
.submodules
.ldst
.pi
351 yield mmu
.rin
.prtbl
.eq(0x1000000) # set process table
356 data
= 0x8c5a3e460d71f0b4
358 # known to fail without bugfix in src/soc/fu/ldst/loadstore.py
359 yield from pi_st(pi
, addr
, data
, 8, msr_pr
=1)
362 ld_data
= yield from pi_ld(pi
, addr
, 8, msr_pr
=1)
365 print ("dcache_first ld data", hex(data
), hex(ld_data
))
367 assert(data
==ld_data
)
372 def test_radixmiss_mmu():
374 m
, cmpi
= setup_mmu()
376 # virtual "memory" to use for this test
378 mem
= {0x10000: # PARTITION_TABLE_2
379 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
380 b(0x800000000100000b),
382 0x30000: # RADIX_ROOT_PTE
383 # V = 1 L = 0 NLB = 0x400 NLS = 9
384 b(0x8000000000040009),
386 0x40000: # RADIX_SECOND_LEVEL
387 # V = 1 L = 1 SW = 0 RPN = 0
388 # R = 1 C = 1 ATT = 0 EAA 0x7
389 b(0xc000000000000183),
391 0x1000000: # PROCESS_TABLE_3
392 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
393 b(0x40000000000300ad),
396 0x1000: 0xdeadbeef01234567,
397 0x1008: 0xfeedf00ff001a5a5
405 sim
.add_sync_process(wrap(ldst_sim_radixmiss(m
)))
406 sim
.add_sync_process(wrap(wb_get(cmpi
.wb_bus(), mem
)))
407 with sim
.write_vcd('test_ldst_pi_radix_miss.vcd'):
410 def test_dcache_regression():
412 m
, cmpi
= setup_mmu()
414 # dcache_load at addr 0
416 0x10000: # PARTITION_TABLE_2
417 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
418 b(0x800000000100000b),
420 0x30000: # RADIX_ROOT_PTE
421 # V = 1 L = 0 NLB = 0x400 NLS = 9
422 b(0x8000000000040009),
424 0x40000: # RADIX_SECOND_LEVEL
425 # V = 1 L = 1 SW = 0 RPN = 0
426 # R = 1 C = 1 ATT = 0 EAA 0x7
427 b(0xc000000000000183),
429 0x1000000: # PROCESS_TABLE_3
430 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
431 b(0x40000000000300ad),
434 0x10000: 0xdeadbeef01234567,
435 0x10008: 0xfeedf00ff001a5a5
442 sim
.add_sync_process(wrap(ldst_sim_dcache_regression(m
)))
443 sim
.add_sync_process(wrap(wb_get(cmpi
.wb_bus(), mem
)))
444 with sim
.write_vcd('test_ldst_pi_radix_miss.vcd'):
447 def test_dcache_random():
449 m
, cmpi
= setup_mmu()
451 # dcache_load at addr 0
453 0x10000: # PARTITION_TABLE_2
454 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
455 b(0x800000000100000b),
457 0x30000: # RADIX_ROOT_PTE
458 # V = 1 L = 0 NLB = 0x400 NLS = 9
459 b(0x8000000000040009),
461 0x40000: # RADIX_SECOND_LEVEL
462 # V = 1 L = 1 SW = 0 RPN = 0
463 # R = 1 C = 1 ATT = 0 EAA 0x7
464 b(0xc000000000000183),
466 0x1000000: # PROCESS_TABLE_3
467 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
468 b(0x40000000000300ad),
475 sim
.add_sync_process(wrap(ldst_sim_dcache_random(m
)))
476 sim
.add_sync_process(wrap(wb_get(cmpi
.wb_bus(), mem
)))
477 with sim
.write_vcd('test_ldst_pi_random.vcd'):
480 def test_dcache_first():
482 m
, cmpi
= setup_mmu()
484 # dcache_load at addr 0
486 0x10000: # PARTITION_TABLE_2
487 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
488 b(0x800000000100000b),
490 0x30000: # RADIX_ROOT_PTE
491 # V = 1 L = 0 NLB = 0x400 NLS = 9
492 b(0x8000000000040009),
494 0x40000: # RADIX_SECOND_LEVEL
495 # V = 1 L = 1 SW = 0 RPN = 0
496 # R = 1 C = 1 ATT = 0 EAA 0x7
497 b(0xc000000000000183),
499 0x1000000: # PROCESS_TABLE_3
500 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
501 b(0x40000000000300ad),
508 sim
.add_sync_process(wrap(ldst_sim_dcache_first(m
)))
509 sim
.add_sync_process(wrap(wb_get(cmpi
.wb_bus(), mem
)))
510 with sim
.write_vcd('test_ldst_pi_first.vcd'):
513 if __name__
== '__main__':
517 ### tests taken from src/soc/experiment/test/test_dcache.py
518 test_dcache_regression()
520 test_dcache_random() #first access to memory still fails after recent change