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)
39 # f.write(str(hex(cell))+"="+str(hex(mem[cell]))+"\n")
42 """simulator process for getting memory load requests
49 while True: # wait for dc_valid
57 addr
= (yield wb
.adr
) << 3
59 print (" WB LOOKUP NO entry @ %x, returning zero" % (addr
))
64 store
= (yield wb
.dat_w
)
66 data
= mem
.get(addr
, 0)
67 # note we assume 8-bit sel, here
76 print (" DCACHE set %x mask %x data %x" % (addr
, sel
, res
))
78 data
= mem
.get(addr
, 0)
79 yield wb
.dat_r
.eq(data
)
80 print (" DCACHE get %x data %x" % (addr
, data
))
88 def mmu_lookup(dut
, addr
):
89 mmu
= dut
.submodules
.mmu
92 print("pi_ld", hex(addr
))
93 data
= yield from pi_ld(dut
.submodules
.ldst
.pi
, addr
, 4, msr_pr
=1)
94 print("pi_ld done, data", hex(data
))
96 # original test code kept for reference
97 while not stop: # wait for dc_valid / err
98 print("waiting for mmu")
99 l_done = yield (mmu.l_out.done)
100 l_err = yield (mmu.l_out.err)
101 l_badtree = yield (mmu.l_out.badtree)
102 l_permerr = yield (mmu.l_out.perm_error)
103 l_rc_err = yield (mmu.l_out.rc_error)
104 l_segerr = yield (mmu.l_out.segerr)
105 l_invalid = yield (mmu.l_out.invalid)
106 if (l_done or l_err or l_badtree or
107 l_permerr or l_rc_err or l_segerr or l_invalid):
111 phys_addr
= yield mmu
.d_out
.addr
112 pte
= yield mmu
.d_out
.pte
113 l_done
= yield (mmu
.l_out
.done
)
114 l_err
= yield (mmu
.l_out
.err
)
115 l_badtree
= yield (mmu
.l_out
.badtree
)
116 print ("translated done %d err %d badtree %d addr %x pte %x" % \
117 (l_done
, l_err
, l_badtree
, phys_addr
, pte
))
119 yield mmu
.l_in
.valid
.eq(0)
125 mmu
= dut
.submodules
.mmu
127 yield mmu
.rin
.prtbl
.eq(0x1000000) # set process table
130 # expecting this data to return
131 # 0x1000: 0xdeadbeef01234567,
132 # 0x1008: 0xfeedf00ff001a5a5
137 # TODO mmu_lookup using port interface
139 data
= yield from mmu_lookup(dut
, addr
)
140 assert data
== 0x1234567
142 data
= yield from mmu_lookup(dut
, addr
+8)
143 assert data
== 0xf001a5a5
144 #assert phys_addr == addr # happens to be the same (for this example)
146 data
= yield from mmu_lookup(dut
, addr
+4)
147 assert data
== 0xdeadbeef
149 data
= yield from mmu_lookup(dut
, addr
+8)
150 assert data
== 0xf001a5a5
152 yield from pi_st(dut
.submodules
.ldst
.pi
, addr
+4, 0x10015a5a, 4, msr_pr
=1)
154 data
= yield from mmu_lookup(dut
, addr
+4)
155 assert data
== 0x10015a5a
167 pspec
= TestMemPspec(ldst_ifacetype
='mmu_cache_wb',
170 #disable_cache=True, # hmmm...
176 cmpi
= ConfigMemoryPortInterface(pspec
)
177 m
.submodules
.ldst
= ldst
= cmpi
.pi
178 m
.submodules
.mmu
= mmu
= MMU()
181 l_in
, l_out
= mmu
.l_in
, mmu
.l_out
182 d_in
, d_out
= dcache
.d_in
, dcache
.d_out
183 wb_out
, wb_in
= dcache
.wb_out
, dcache
.wb_in
185 # link mmu and dcache together
186 m
.d
.comb
+= dcache
.m_in
.eq(mmu
.d_out
) # MMUToDCacheType
187 m
.d
.comb
+= mmu
.d_in
.eq(dcache
.m_out
) # DCacheToMMUType
189 # link ldst and MMU together
190 comb
+= l_in
.eq(ldst
.m_out
)
191 comb
+= ldst
.m_in
.eq(l_out
)
198 m
, cmpi
= setup_mmu()
200 # virtual "memory" to use for this test
202 mem
= {0x10000: # PARTITION_TABLE_2
203 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
204 b(0x800000000100000b),
206 0x30000: # RADIX_ROOT_PTE
207 # V = 1 L = 0 NLB = 0x400 NLS = 9
208 b(0x8000000000040009),
210 0x40000: # RADIX_SECOND_LEVEL
211 # V = 1 L = 1 SW = 0 RPN = 0
212 # R = 1 C = 1 ATT = 0 EAA 0x7
213 b(0xc000000000000183),
215 0x1000000: # PROCESS_TABLE_3
216 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
217 b(0x40000000000300ad),
220 0x1000: 0xdeadbeef01234567,
221 0x1008: 0xfeedf00ff001a5a5
229 sim
.add_sync_process(wrap(ldst_sim(m
)))
230 sim
.add_sync_process(wrap(wb_get(cmpi
.wb_bus(), mem
)))
231 with sim
.write_vcd('test_ldst_pi.vcd'):
235 def ldst_sim_misalign(dut
):
236 mmu
= dut
.submodules
.mmu
240 yield mmu
.rin
.prtbl
.eq(0x1000000) # set process table
243 data
= yield from pi_ld(dut
.submodules
.ldst
.pi
, 0x1007, 8, msr_pr
=1)
244 print ("misalign ld data", hex(data
))
250 def test_misalign_mmu():
252 m
, cmpi
= setup_mmu()
254 # virtual "memory" to use for this test
256 mem
= {0x10000: # PARTITION_TABLE_2
257 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
258 b(0x800000000100000b),
260 0x30000: # RADIX_ROOT_PTE
261 # V = 1 L = 0 NLB = 0x400 NLS = 9
262 b(0x8000000000040009),
264 0x40000: # RADIX_SECOND_LEVEL
265 # V = 1 L = 1 SW = 0 RPN = 0
266 # R = 1 C = 1 ATT = 0 EAA 0x7
267 b(0xc000000000000183),
269 0x1000000: # PROCESS_TABLE_3
270 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
271 b(0x40000000000300ad),
274 0x1000: 0xdeadbeef01234567,
275 0x1008: 0xfeedf00ff001a5a5
283 sim
.add_sync_process(wrap(ldst_sim_misalign(m
)))
284 sim
.add_sync_process(wrap(wb_get(cmpi
.wb_bus(), mem
)))
285 with sim
.write_vcd('test_ldst_pi_misalign.vcd'):
289 def ldst_sim_radixmiss(dut
):
290 mmu
= dut
.submodules
.mmu
294 yield mmu
.rin
.prtbl
.eq(1<<40) # set process table
297 data
= yield from pi_ld(dut
.submodules
.ldst
.pi
, 0x10000000, 8, msr_pr
=1)
298 print ("radixmiss ld data", hex(data
))
303 def ldst_sim_dcache_regression(dut
):
304 mmu
= dut
.submodules
.mmu
308 yield mmu
.rin
.prtbl
.eq(0x1000000) # set process table
312 data
= yield from pi_ld(dut
.submodules
.ldst
.pi
, addr
, 8, msr_pr
=1)
313 print ("=== dcache_regression ld data", hex(data
))
314 assert(data
== 0xdeadbeef01234567)
319 def ldst_sim_dcache_random(dut
):
320 mmu
= dut
.submodules
.mmu
321 pi
= dut
.submodules
.ldst
.pi
325 yield mmu
.rin
.prtbl
.eq(0x1000000) # set process table
331 addr
= randint(0, memsize
-1)
332 data
= randint(0, (1<<64)-1)
336 yield from pi_st(pi
, addr
, data
, 8, msr_pr
=1)
339 ld_data
= yield from pi_ld(pi
, addr
, 8, msr_pr
=1)
342 print ("dcache_random values", hex(addr
), hex(data
), hex(ld_data
), eq
)
343 assert(data
==ld_data
) ## investigate why this fails -- really seldom
348 def ldst_sim_dcache_first(dut
): # this test is likely to fail
349 mmu
= dut
.submodules
.mmu
350 pi
= dut
.submodules
.ldst
.pi
354 yield mmu
.rin
.prtbl
.eq(0x1000000) # set process table
359 data
= 0x8c5a3e460d71f0b4
361 # known to fail without bugfix in src/soc/fu/ldst/loadstore.py
362 yield from pi_st(pi
, addr
, data
, 8, msr_pr
=1)
365 ld_data
= yield from pi_ld(pi
, addr
, 8, msr_pr
=1)
368 print ("dcache_first ld data", hex(data
), hex(ld_data
))
370 assert(data
==ld_data
)
375 def test_radixmiss_mmu():
377 m
, cmpi
= setup_mmu()
379 # virtual "memory" to use for this test
381 mem
= {0x10000: # PARTITION_TABLE_2
382 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
383 b(0x800000000100000b),
385 0x30000: # RADIX_ROOT_PTE
386 # V = 1 L = 0 NLB = 0x400 NLS = 9
387 b(0x8000000000040009),
389 0x40000: # RADIX_SECOND_LEVEL
390 # V = 1 L = 1 SW = 0 RPN = 0
391 # R = 1 C = 1 ATT = 0 EAA 0x7
392 b(0xc000000000000183),
394 0x1000000: # PROCESS_TABLE_3
395 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
396 b(0x40000000000300ad),
399 0x1000: 0xdeadbeef01234567,
400 0x1008: 0xfeedf00ff001a5a5
408 sim
.add_sync_process(wrap(ldst_sim_radixmiss(m
)))
409 sim
.add_sync_process(wrap(wb_get(cmpi
.wb_bus(), mem
)))
410 with sim
.write_vcd('test_ldst_pi_radix_miss.vcd'):
413 def test_dcache_regression():
415 m
, cmpi
= setup_mmu()
417 # dcache_load at addr 0
419 0x10000: # PARTITION_TABLE_2
420 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
421 b(0x800000000100000b),
423 0x30000: # RADIX_ROOT_PTE
424 # V = 1 L = 0 NLB = 0x400 NLS = 9
425 b(0x8000000000040009),
427 0x40000: # RADIX_SECOND_LEVEL
428 # V = 1 L = 1 SW = 0 RPN = 0
429 # R = 1 C = 1 ATT = 0 EAA 0x7
430 b(0xc000000000000183),
432 0x1000000: # PROCESS_TABLE_3
433 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
434 b(0x40000000000300ad),
437 0x10000: 0xdeadbeef01234567,
438 0x10008: 0xfeedf00ff001a5a5
445 sim
.add_sync_process(wrap(ldst_sim_dcache_regression(m
)))
446 sim
.add_sync_process(wrap(wb_get(cmpi
.wb_bus(), mem
)))
447 with sim
.write_vcd('test_ldst_pi_radix_miss.vcd'):
450 def test_dcache_random():
452 m
, cmpi
= setup_mmu()
454 # dcache_load at addr 0
456 0x10000: # PARTITION_TABLE_2
457 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
458 b(0x800000000100000b),
460 0x30000: # RADIX_ROOT_PTE
461 # V = 1 L = 0 NLB = 0x400 NLS = 9
462 b(0x8000000000040009),
464 0x40000: # RADIX_SECOND_LEVEL
465 # V = 1 L = 1 SW = 0 RPN = 0
466 # R = 1 C = 1 ATT = 0 EAA 0x7
467 b(0xc000000000000183),
469 0x1000000: # PROCESS_TABLE_3
470 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
471 b(0x40000000000300ad),
478 sim
.add_sync_process(wrap(ldst_sim_dcache_random(m
)))
479 sim
.add_sync_process(wrap(wb_get(cmpi
.wb_bus(), mem
)))
480 with sim
.write_vcd('test_ldst_pi_random.vcd'):
483 def ldst_sim_dcache_random2(dut
, mem
):
484 mmu
= dut
.submodules
.mmu
485 pi
= dut
.submodules
.ldst
.pi
489 yield mmu
.rin
.prtbl
.eq(0x1000000) # set process table
495 ## random values from a failed test
496 #[0x100e0,0xf553b658ba7e1f51,0,0], ## 1
497 #[0x10150,0x12c95a730df1cee7,0,0], ## 2
498 #[0x10080,0x5a921ae06674cd81,0,0], ## 3
499 #[0x100f8,0x4fea5eab80090fa5,0,0], ## 4
500 #[0x10080,0xd481432d17a340be,0,0], ## 5
501 #[0x10060,0x8553fcf29526fb32,0,0], ## 6
502 [0x101d0,0x327c967c8be30ded,0,0], ## 7
503 [0x101e0,0x8f15d8d05d25b151,1,0] ## 8
504 #uncommenting line 7 will cause the original test not to fail
515 print("== write: wb_get")
517 for i
in range(0,c1
):
518 print("before_pi_st")
521 yield from pi_st(pi
, addr
, data
, 8, msr_pr
=1)
524 for i
in range(0,c2
):
525 print("before_pi_ld")
528 print("== read: wb_get")
529 ld_data
= yield from pi_ld(pi
, addr
, 8, msr_pr
=1)
531 #dumpmem(mem,"/tmp/dumpmem"+str(c)+".txt")
535 print ("dcache_random values", hex(addr
), hex(data
), hex(ld_data
), eq
)
536 assert(data
==ld_data
) ## investigate why this fails -- really seldom
541 def test_dcache_random2():
543 m
, cmpi
= setup_mmu()
545 # dcache_load at addr 0
547 0x10000: # PARTITION_TABLE_2
548 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
549 b(0x800000000100000b),
551 0x30000: # RADIX_ROOT_PTE
552 # V = 1 L = 0 NLB = 0x400 NLS = 9
553 b(0x8000000000040009),
555 0x40000: # RADIX_SECOND_LEVEL
556 # V = 1 L = 1 SW = 0 RPN = 0
557 # R = 1 C = 1 ATT = 0 EAA 0x7
558 b(0xc000000000000183),
560 0x1000000: # PROCESS_TABLE_3
561 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
562 b(0x40000000000300ad),
564 ###0x101e0:0x8f15d8d05d25b152 ## flush cache -- then check again
571 sim
.add_sync_process(wrap(ldst_sim_dcache_random2(m
, mem
)))
572 sim
.add_sync_process(wrap(wb_get(cmpi
.wb_bus(), mem
)))
573 with sim
.write_vcd('test_ldst_pi_random2.vcd'):
576 def test_dcache_first():
578 m
, cmpi
= setup_mmu()
580 # dcache_load at addr 0
582 0x10000: # PARTITION_TABLE_2
583 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
584 b(0x800000000100000b),
586 0x30000: # RADIX_ROOT_PTE
587 # V = 1 L = 0 NLB = 0x400 NLS = 9
588 b(0x8000000000040009),
590 0x40000: # RADIX_SECOND_LEVEL
591 # V = 1 L = 1 SW = 0 RPN = 0
592 # R = 1 C = 1 ATT = 0 EAA 0x7
593 b(0xc000000000000183),
595 0x1000000: # PROCESS_TABLE_3
596 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
597 b(0x40000000000300ad),
604 sim
.add_sync_process(wrap(ldst_sim_dcache_first(m
)))
605 sim
.add_sync_process(wrap(wb_get(cmpi
.wb_bus(), mem
)))
606 with sim
.write_vcd('test_ldst_pi_first.vcd'):
609 if __name__
== '__main__':
613 ### tests taken from src/soc/experiment/test/test_dcache.py
614 test_dcache_regression()
616 test_dcache_random() #sometimes fails
617 test_dcache_random2() #reproduce error