cut down on time by uncommenting data not needed, adding documentation
[soc.git] / src / soc / experiment / test / test_ldst_pi.py
1 """MMU PortInterface Test
2
3 quite basic, goes directly to the MMU to assert signals (does not
4 yet use PortInterface)
5 """
6
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
13
14 if True:
15 from nmigen.back.pysim import Simulator, Delay, Settle
16 else:
17 from nmigen.sim.cxxsim import Simulator, Delay, Settle
18 from nmutil.util import wrap
19
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
23
24 from soc.fu.ldst.loadstore import LoadStore1
25 from soc.experiment.mmu import MMU
26
27 from nmigen.compat.sim import run_simulation
28
29
30 stop = False
31
32 def b(x): # byte-reverse function
33 return int.from_bytes(x.to_bytes(8, byteorder='little'),
34 byteorder='big', signed=False)
35
36 #def dumpmem(mem,fn):
37 # f = open(fn,"w")
38 # for cell in mem:
39 # f.write(str(hex(cell))+"="+str(hex(mem[cell]))+"\n")
40
41 def wb_get(wb, mem):
42 """simulator process for getting memory load requests
43 """
44
45 global stop
46 assert(stop==False)
47
48 while not stop:
49 while True: # wait for dc_valid
50 if stop:
51 return
52 cyc = yield (wb.cyc)
53 stb = yield (wb.stb)
54 if cyc and stb:
55 break
56 yield
57 addr = (yield wb.adr) << 3
58 if addr not in mem:
59 print (" WB LOOKUP NO entry @ %x, returning zero" % (addr))
60
61 # read or write?
62 we = (yield wb.we)
63 if we:
64 store = (yield wb.dat_w)
65 sel = (yield wb.sel)
66 data = mem.get(addr, 0)
67 # note we assume 8-bit sel, here
68 res = 0
69 for i in range(8):
70 mask = 0xff << (i*8)
71 if sel & (1<<i):
72 res |= store & mask
73 else:
74 res |= data & mask
75 mem[addr] = res
76 print (" DCACHE set %x mask %x data %x" % (addr, sel, res))
77 else:
78 data = mem.get(addr, 0)
79 yield wb.dat_r.eq(data)
80 print (" DCACHE get %x data %x" % (addr, data))
81
82 yield wb.ack.eq(1)
83 yield
84 yield wb.ack.eq(0)
85 yield
86
87
88 def mmu_lookup(dut, addr):
89 mmu = dut.submodules.mmu
90 global stop
91
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))
95 """
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):
108 break
109 yield
110 """
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))
118 yield
119 yield mmu.l_in.valid.eq(0)
120
121 return data
122
123
124 def ldst_sim(dut):
125 mmu = dut.submodules.mmu
126 global stop
127 yield mmu.rin.prtbl.eq(0x1000000) # set process table
128 yield
129
130 # expecting this data to return
131 # 0x1000: 0xdeadbeef01234567,
132 # 0x1008: 0xfeedf00ff001a5a5
133
134 addr = 0x1000
135 print("pi_ld")
136
137 # TODO mmu_lookup using port interface
138 # set inputs
139 data = yield from mmu_lookup(dut, addr)
140 assert data == 0x1234567
141
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)
145
146 data = yield from mmu_lookup(dut, addr+4)
147 assert data == 0xdeadbeef
148
149 data = yield from mmu_lookup(dut, addr+8)
150 assert data == 0xf001a5a5
151
152 yield from pi_st(dut.submodules.ldst.pi, addr+4, 0x10015a5a, 4, msr_pr=1)
153
154 data = yield from mmu_lookup(dut, addr+4)
155 assert data == 0x10015a5a
156
157 yield
158 yield
159
160 stop = True
161
162 def setup_mmu():
163
164 global stop
165 stop = False
166
167 pspec = TestMemPspec(ldst_ifacetype='mmu_cache_wb',
168 imem_ifacetype='',
169 addr_wid=48,
170 #disable_cache=True, # hmmm...
171 mask_wid=8,
172 reg_wid=64)
173
174 m = Module()
175 comb = m.d.comb
176 cmpi = ConfigMemoryPortInterface(pspec)
177 m.submodules.ldst = ldst = cmpi.pi
178 m.submodules.mmu = mmu = MMU()
179 dcache = ldst.dcache
180
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
184
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
188
189 # link ldst and MMU together
190 comb += l_in.eq(ldst.m_out)
191 comb += ldst.m_in.eq(l_out)
192
193 return m, cmpi
194
195
196 def test_mmu():
197
198 m, cmpi = setup_mmu()
199
200 # virtual "memory" to use for this test
201
202 mem = {0x10000: # PARTITION_TABLE_2
203 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
204 b(0x800000000100000b),
205
206 0x30000: # RADIX_ROOT_PTE
207 # V = 1 L = 0 NLB = 0x400 NLS = 9
208 b(0x8000000000040009),
209
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),
214
215 0x1000000: # PROCESS_TABLE_3
216 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
217 b(0x40000000000300ad),
218
219 # data to return
220 0x1000: 0xdeadbeef01234567,
221 0x1008: 0xfeedf00ff001a5a5
222 }
223
224
225 # nmigen Simulation
226 sim = Simulator(m)
227 sim.add_clock(1e-6)
228
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'):
232 sim.run()
233
234
235 def ldst_sim_misalign(dut):
236 mmu = dut.submodules.mmu
237 global stop
238 stop = False
239
240 yield mmu.rin.prtbl.eq(0x1000000) # set process table
241 yield
242
243 data = yield from pi_ld(dut.submodules.ldst.pi, 0x1007, 8, msr_pr=1)
244 print ("misalign ld data", hex(data))
245
246 yield
247 stop = True
248
249
250 def test_misalign_mmu():
251
252 m, cmpi = setup_mmu()
253
254 # virtual "memory" to use for this test
255
256 mem = {0x10000: # PARTITION_TABLE_2
257 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
258 b(0x800000000100000b),
259
260 0x30000: # RADIX_ROOT_PTE
261 # V = 1 L = 0 NLB = 0x400 NLS = 9
262 b(0x8000000000040009),
263
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),
268
269 0x1000000: # PROCESS_TABLE_3
270 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
271 b(0x40000000000300ad),
272
273 # data to return
274 0x1000: 0xdeadbeef01234567,
275 0x1008: 0xfeedf00ff001a5a5
276 }
277
278
279 # nmigen Simulation
280 sim = Simulator(m)
281 sim.add_clock(1e-6)
282
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'):
286 sim.run()
287
288
289 def ldst_sim_radixmiss(dut):
290 mmu = dut.submodules.mmu
291 global stop
292 stop = False
293
294 yield mmu.rin.prtbl.eq(1<<40) # set process table
295 yield
296
297 data = yield from pi_ld(dut.submodules.ldst.pi, 0x10000000, 8, msr_pr=1)
298 print ("radixmiss ld data", hex(data))
299
300 yield
301 stop = True
302
303 def ldst_sim_dcache_regression(dut):
304 mmu = dut.submodules.mmu
305 global stop
306 stop = False
307
308 yield mmu.rin.prtbl.eq(0x1000000) # set process table
309 yield
310
311 addr = 0x10000
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)
315
316 yield
317 stop = True
318
319 def ldst_sim_dcache_random(dut):
320 mmu = dut.submodules.mmu
321 pi = dut.submodules.ldst.pi
322 global stop
323 stop = False
324
325 yield mmu.rin.prtbl.eq(0x1000000) # set process table
326 yield
327
328 memsize = 64
329
330 for i in range(16):
331 addr = randint(0, memsize-1)
332 data = randint(0, (1<<64)-1)
333 addr *= 8
334 addr += 0x10000
335
336 yield from pi_st(pi, addr, data, 8, msr_pr=1)
337 yield
338
339 ld_data = yield from pi_ld(pi, addr, 8, msr_pr=1)
340
341 eq = (data==ld_data)
342 print ("dcache_random values", hex(addr), hex(data), hex(ld_data), eq)
343 assert(data==ld_data) ## investigate why this fails -- really seldom
344
345 yield
346 stop = True
347
348 def ldst_sim_dcache_first(dut): # this test is likely to fail
349 mmu = dut.submodules.mmu
350 pi = dut.submodules.ldst.pi
351 global stop
352 stop = False
353
354 yield mmu.rin.prtbl.eq(0x1000000) # set process table
355 yield
356
357 # failed ramdom data
358 addr = 65888
359 data = 0x8c5a3e460d71f0b4
360
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)
363 yield
364
365 ld_data = yield from pi_ld(pi, addr, 8, msr_pr=1)
366
367 print ("addr",addr)
368 print ("dcache_first ld data", hex(data), hex(ld_data))
369
370 assert(data==ld_data)
371
372 yield
373 stop = True
374
375 def test_radixmiss_mmu():
376
377 m, cmpi = setup_mmu()
378
379 # virtual "memory" to use for this test
380
381 mem = {0x10000: # PARTITION_TABLE_2
382 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
383 b(0x800000000100000b),
384
385 0x30000: # RADIX_ROOT_PTE
386 # V = 1 L = 0 NLB = 0x400 NLS = 9
387 b(0x8000000000040009),
388
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),
393
394 0x1000000: # PROCESS_TABLE_3
395 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
396 b(0x40000000000300ad),
397
398 # data to return
399 0x1000: 0xdeadbeef01234567,
400 0x1008: 0xfeedf00ff001a5a5
401 }
402
403
404 # nmigen Simulation
405 sim = Simulator(m)
406 sim.add_clock(1e-6)
407
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'):
411 sim.run()
412
413 def test_dcache_regression():
414
415 m, cmpi = setup_mmu()
416
417 # dcache_load at addr 0
418 mem = {
419 0x10000: # PARTITION_TABLE_2
420 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
421 b(0x800000000100000b),
422
423 0x30000: # RADIX_ROOT_PTE
424 # V = 1 L = 0 NLB = 0x400 NLS = 9
425 b(0x8000000000040009),
426
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),
431
432 0x1000000: # PROCESS_TABLE_3
433 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
434 b(0x40000000000300ad),
435
436 # data to return
437 0x10000: 0xdeadbeef01234567,
438 0x10008: 0xfeedf00ff001a5a5
439 }
440
441 # nmigen Simulation
442 sim = Simulator(m)
443 sim.add_clock(1e-6)
444
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'):
448 sim.run()
449
450 def test_dcache_random():
451
452 m, cmpi = setup_mmu()
453
454 # dcache_load at addr 0
455 mem = {
456 0x10000: # PARTITION_TABLE_2
457 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
458 b(0x800000000100000b),
459
460 0x30000: # RADIX_ROOT_PTE
461 # V = 1 L = 0 NLB = 0x400 NLS = 9
462 b(0x8000000000040009),
463
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),
468
469 0x1000000: # PROCESS_TABLE_3
470 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
471 b(0x40000000000300ad),
472 }
473
474 # nmigen Simulation
475 sim = Simulator(m)
476 sim.add_clock(1e-6)
477
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'):
481 sim.run()
482
483 def ldst_sim_dcache_random2(dut, mem):
484 mmu = dut.submodules.mmu
485 pi = dut.submodules.ldst.pi
486 global stop
487 stop = False
488
489 yield mmu.rin.prtbl.eq(0x1000000) # set process table
490 yield
491
492 memsize = 64
493
494 refs = [
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
505
506 ]
507
508 c = 0
509 for i in refs:
510 addr = i[0]
511 data = i[1]
512 c1 = i[2]
513 c2 = i[3]
514
515 print("== write: wb_get")
516
517 for i in range(0,c1):
518 print("before_pi_st")
519 yield
520
521 yield from pi_st(pi, addr, data, 8, msr_pr=1)
522 yield
523
524 for i in range(0,c2):
525 print("before_pi_ld")
526 yield
527
528 print("== read: wb_get")
529 ld_data = yield from pi_ld(pi, addr, 8, msr_pr=1)
530
531 #dumpmem(mem,"/tmp/dumpmem"+str(c)+".txt")
532 #c += 1
533
534 eq = (data==ld_data)
535 print ("dcache_random values", hex(addr), hex(data), hex(ld_data), eq)
536 assert(data==ld_data) ## investigate why this fails -- really seldom
537
538 yield
539 stop = True
540
541 def test_dcache_random2():
542
543 m, cmpi = setup_mmu()
544
545 # dcache_load at addr 0
546 mem = {
547 0x10000: # PARTITION_TABLE_2
548 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
549 b(0x800000000100000b),
550
551 0x30000: # RADIX_ROOT_PTE
552 # V = 1 L = 0 NLB = 0x400 NLS = 9
553 b(0x8000000000040009),
554
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),
559
560 0x1000000: # PROCESS_TABLE_3
561 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
562 b(0x40000000000300ad),
563
564 ###0x101e0:0x8f15d8d05d25b152 ## flush cache -- then check again
565 }
566
567 # nmigen Simulation
568 sim = Simulator(m)
569 sim.add_clock(1e-6)
570
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'):
574 sim.run()
575
576 def test_dcache_first():
577
578 m, cmpi = setup_mmu()
579
580 # dcache_load at addr 0
581 mem = {
582 0x10000: # PARTITION_TABLE_2
583 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
584 b(0x800000000100000b),
585
586 0x30000: # RADIX_ROOT_PTE
587 # V = 1 L = 0 NLB = 0x400 NLS = 9
588 b(0x8000000000040009),
589
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),
594
595 0x1000000: # PROCESS_TABLE_3
596 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
597 b(0x40000000000300ad),
598 }
599
600 # nmigen Simulation
601 sim = Simulator(m)
602 sim.add_clock(1e-6)
603
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'):
607 sim.run()
608
609 if __name__ == '__main__':
610 test_mmu()
611 test_misalign_mmu()
612 test_radixmiss_mmu()
613 ### tests taken from src/soc/experiment/test/test_dcache.py
614 test_dcache_regression()
615 test_dcache_first()
616 test_dcache_random() #sometimes fails
617 test_dcache_random2() #reproduce error