update test_ldst_pi.py
[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 wb_get(wb, mem):
37 """simulator process for getting memory load requests
38 """
39
40 global stop
41 assert(stop==False)
42
43 while not stop:
44 while True: # wait for dc_valid
45 if stop:
46 return
47 cyc = yield (wb.cyc)
48 stb = yield (wb.stb)
49 if cyc and stb:
50 break
51 yield
52 addr = (yield wb.adr) << 3
53 if addr not in mem:
54 print (" WB LOOKUP NO entry @ %x, returning zero" % (addr))
55
56 # read or write?
57 we = (yield wb.we)
58 if we:
59 store = (yield wb.dat_w)
60 sel = (yield wb.sel)
61 data = mem.get(addr, 0)
62 # note we assume 8-bit sel, here
63 res = 0
64 for i in range(8):
65 mask = 0xff << (i*8)
66 if sel & (1<<i):
67 res |= store & mask
68 else:
69 res |= data & mask
70 mem[addr] = res
71 print (" DCACHE set %x mask %x data %x" % (addr, sel, res))
72 else:
73 data = mem.get(addr, 0)
74 yield wb.dat_r.eq(data)
75 print (" DCACHE get %x data %x" % (addr, data))
76
77 yield wb.ack.eq(1)
78 yield
79 yield wb.ack.eq(0)
80 yield
81
82
83 def mmu_lookup(dut, addr):
84 mmu = dut.submodules.mmu
85 global stop
86
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))
90 """
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):
103 break
104 yield
105 """
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))
113 yield
114 yield mmu.l_in.valid.eq(0)
115
116 return data
117
118
119 def ldst_sim(dut):
120 mmu = dut.submodules.mmu
121 global stop
122 yield mmu.rin.prtbl.eq(0x1000000) # set process table
123 yield
124
125 # expecting this data to return
126 # 0x1000: 0xdeadbeef01234567,
127 # 0x1008: 0xfeedf00ff001a5a5
128
129 addr = 0x1000
130 print("pi_ld")
131
132 # TODO mmu_lookup using port interface
133 # set inputs
134 data = yield from mmu_lookup(dut, addr)
135 assert data == 0x1234567
136
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)
140
141 data = yield from mmu_lookup(dut, addr+4)
142 assert data == 0xdeadbeef
143
144 data = yield from mmu_lookup(dut, addr+8)
145 assert data == 0xf001a5a5
146
147 yield from pi_st(dut.submodules.ldst.pi, addr+4, 0x10015a5a, 4, msr_pr=1)
148
149 data = yield from mmu_lookup(dut, addr+4)
150 assert data == 0x10015a5a
151
152 yield
153 yield
154
155 stop = True
156
157 def setup_mmu():
158
159 global stop
160 stop = False
161
162 pspec = TestMemPspec(ldst_ifacetype='mmu_cache_wb',
163 imem_ifacetype='',
164 addr_wid=48,
165 #disable_cache=True, # hmmm...
166 mask_wid=8,
167 reg_wid=64)
168
169 m = Module()
170 comb = m.d.comb
171 cmpi = ConfigMemoryPortInterface(pspec)
172 m.submodules.ldst = ldst = cmpi.pi
173 m.submodules.mmu = mmu = MMU()
174 dcache = ldst.dcache
175
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
179
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
183
184 # link ldst and MMU together
185 comb += l_in.eq(ldst.m_out)
186 comb += ldst.m_in.eq(l_out)
187
188 return m, cmpi
189
190
191 def test_mmu():
192
193 m, cmpi = setup_mmu()
194
195 # virtual "memory" to use for this test
196
197 mem = {0x10000: # PARTITION_TABLE_2
198 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
199 b(0x800000000100000b),
200
201 0x30000: # RADIX_ROOT_PTE
202 # V = 1 L = 0 NLB = 0x400 NLS = 9
203 b(0x8000000000040009),
204
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),
209
210 0x1000000: # PROCESS_TABLE_3
211 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
212 b(0x40000000000300ad),
213
214 # data to return
215 0x1000: 0xdeadbeef01234567,
216 0x1008: 0xfeedf00ff001a5a5
217 }
218
219
220 # nmigen Simulation
221 sim = Simulator(m)
222 sim.add_clock(1e-6)
223
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'):
227 sim.run()
228
229
230 def ldst_sim_misalign(dut):
231 mmu = dut.submodules.mmu
232 global stop
233 stop = False
234
235 yield mmu.rin.prtbl.eq(0x1000000) # set process table
236 yield
237
238 data = yield from pi_ld(dut.submodules.ldst.pi, 0x1007, 8, msr_pr=1)
239 print ("misalign ld data", hex(data))
240
241 yield
242 stop = True
243
244
245 def test_misalign_mmu():
246
247 m, cmpi = setup_mmu()
248
249 # virtual "memory" to use for this test
250
251 mem = {0x10000: # PARTITION_TABLE_2
252 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
253 b(0x800000000100000b),
254
255 0x30000: # RADIX_ROOT_PTE
256 # V = 1 L = 0 NLB = 0x400 NLS = 9
257 b(0x8000000000040009),
258
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),
263
264 0x1000000: # PROCESS_TABLE_3
265 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
266 b(0x40000000000300ad),
267
268 # data to return
269 0x1000: 0xdeadbeef01234567,
270 0x1008: 0xfeedf00ff001a5a5
271 }
272
273
274 # nmigen Simulation
275 sim = Simulator(m)
276 sim.add_clock(1e-6)
277
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'):
281 sim.run()
282
283
284 def ldst_sim_radixmiss(dut):
285 mmu = dut.submodules.mmu
286 global stop
287 stop = False
288
289 yield mmu.rin.prtbl.eq(1<<40) # set process table
290 yield
291
292 data = yield from pi_ld(dut.submodules.ldst.pi, 0x10000000, 8, msr_pr=1)
293 print ("radixmiss ld data", hex(data))
294
295 yield
296 stop = True
297
298 def ldst_sim_dcache_regression(dut):
299 mmu = dut.submodules.mmu
300 global stop
301 stop = False
302
303 yield mmu.rin.prtbl.eq(0x1000000) # set process table
304 yield
305
306 addr = 0x10000
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)
310
311 yield
312 stop = True
313
314 def ldst_sim_dcache_random2(dut):
315 mmu = dut.submodules.mmu
316 pi = dut.submodules.ldst.pi
317 global stop
318 stop = False
319
320 yield mmu.rin.prtbl.eq(0x1000000) # set process table
321 yield
322
323 memsize = 64
324
325 refs = [
326 ## random values from a failed test
327 [0x100e0,0xf553b658ba7e1f51],
328 [0x10150,0x12c95a730df1cee7],
329 [0x10080,0x5a921ae06674cd81],
330 [0x100f8,0x4fea5eab80090fa5],
331 [0x10080,0xd481432d17a340be],
332 [0x10060,0x8553fcf29526fb32],
333 # [0x101d0,0x327c967c8be30ded],
334 [0x101e0,0x8f15d8d05d25b151]
335 ]
336
337 for i in refs:
338 addr = i[0]
339 data = i[1]
340
341 yield from pi_st(pi, addr, data, 8, msr_pr=1)
342 yield
343
344 ld_data = yield from pi_ld(pi, addr, 8, msr_pr=1)
345
346 print ("dcache_random values", hex(addr), hex(data), hex(ld_data), data==ld_data)
347 assert(data==ld_data) ## investigate why this fails -- really seldom
348
349 yield
350 stop = True
351
352 def ldst_sim_dcache_random(dut):
353 mmu = dut.submodules.mmu
354 pi = dut.submodules.ldst.pi
355 global stop
356 stop = False
357
358 yield mmu.rin.prtbl.eq(0x1000000) # set process table
359 yield
360
361 memsize = 64
362
363 for i in range(16):
364 addr = randint(0, memsize-1)
365 data = randint(0, (1<<64)-1)
366 addr *= 8
367 addr += 0x10000
368
369 yield from pi_st(pi, addr, data, 8, msr_pr=1)
370 yield
371
372 ld_data = yield from pi_ld(pi, addr, 8, msr_pr=1)
373
374 print ("dcache_random values", hex(addr), hex(data), hex(ld_data), data==ld_data)
375 assert(data==ld_data) ## investigate why this fails -- really seldom
376
377 yield
378 stop = True
379
380 def ldst_sim_dcache_first(dut): # this test is likely to fail
381 mmu = dut.submodules.mmu
382 pi = dut.submodules.ldst.pi
383 global stop
384 stop = False
385
386 yield mmu.rin.prtbl.eq(0x1000000) # set process table
387 yield
388
389 # failed ramdom data
390 addr = 65888
391 data = 0x8c5a3e460d71f0b4
392
393 # known to fail without bugfix in src/soc/fu/ldst/loadstore.py
394 yield from pi_st(pi, addr, data, 8, msr_pr=1)
395 yield
396
397 ld_data = yield from pi_ld(pi, addr, 8, msr_pr=1)
398
399 print ("addr",addr)
400 print ("dcache_first ld data", hex(data), hex(ld_data))
401
402 assert(data==ld_data)
403
404 yield
405 stop = True
406
407 def test_radixmiss_mmu():
408
409 m, cmpi = setup_mmu()
410
411 # virtual "memory" to use for this test
412
413 mem = {0x10000: # PARTITION_TABLE_2
414 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
415 b(0x800000000100000b),
416
417 0x30000: # RADIX_ROOT_PTE
418 # V = 1 L = 0 NLB = 0x400 NLS = 9
419 b(0x8000000000040009),
420
421 0x40000: # RADIX_SECOND_LEVEL
422 # V = 1 L = 1 SW = 0 RPN = 0
423 # R = 1 C = 1 ATT = 0 EAA 0x7
424 b(0xc000000000000183),
425
426 0x1000000: # PROCESS_TABLE_3
427 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
428 b(0x40000000000300ad),
429
430 # data to return
431 0x1000: 0xdeadbeef01234567,
432 0x1008: 0xfeedf00ff001a5a5
433 }
434
435
436 # nmigen Simulation
437 sim = Simulator(m)
438 sim.add_clock(1e-6)
439
440 sim.add_sync_process(wrap(ldst_sim_radixmiss(m)))
441 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
442 with sim.write_vcd('test_ldst_pi_radix_miss.vcd'):
443 sim.run()
444
445 def test_dcache_regression():
446
447 m, cmpi = setup_mmu()
448
449 # dcache_load at addr 0
450 mem = {
451 0x10000: # PARTITION_TABLE_2
452 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
453 b(0x800000000100000b),
454
455 0x30000: # RADIX_ROOT_PTE
456 # V = 1 L = 0 NLB = 0x400 NLS = 9
457 b(0x8000000000040009),
458
459 0x40000: # RADIX_SECOND_LEVEL
460 # V = 1 L = 1 SW = 0 RPN = 0
461 # R = 1 C = 1 ATT = 0 EAA 0x7
462 b(0xc000000000000183),
463
464 0x1000000: # PROCESS_TABLE_3
465 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
466 b(0x40000000000300ad),
467
468 # data to return
469 0x10000: 0xdeadbeef01234567,
470 0x10008: 0xfeedf00ff001a5a5
471 }
472
473 # nmigen Simulation
474 sim = Simulator(m)
475 sim.add_clock(1e-6)
476
477 sim.add_sync_process(wrap(ldst_sim_dcache_regression(m)))
478 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
479 with sim.write_vcd('test_ldst_pi_radix_miss.vcd'):
480 sim.run()
481
482 def test_dcache_random():
483
484 m, cmpi = setup_mmu()
485
486 # dcache_load at addr 0
487 mem = {
488 0x10000: # PARTITION_TABLE_2
489 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
490 b(0x800000000100000b),
491
492 0x30000: # RADIX_ROOT_PTE
493 # V = 1 L = 0 NLB = 0x400 NLS = 9
494 b(0x8000000000040009),
495
496 0x40000: # RADIX_SECOND_LEVEL
497 # V = 1 L = 1 SW = 0 RPN = 0
498 # R = 1 C = 1 ATT = 0 EAA 0x7
499 b(0xc000000000000183),
500
501 0x1000000: # PROCESS_TABLE_3
502 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
503 b(0x40000000000300ad),
504 }
505
506 # nmigen Simulation
507 sim = Simulator(m)
508 sim.add_clock(1e-6)
509
510 sim.add_sync_process(wrap(ldst_sim_dcache_random(m)))
511 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
512 with sim.write_vcd('test_ldst_pi_random.vcd'):
513 sim.run()
514
515 def test_dcache_random2():
516
517 m, cmpi = setup_mmu()
518
519 # dcache_load at addr 0
520 mem = {
521 0x10000: # PARTITION_TABLE_2
522 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
523 b(0x800000000100000b),
524
525 0x30000: # RADIX_ROOT_PTE
526 # V = 1 L = 0 NLB = 0x400 NLS = 9
527 b(0x8000000000040009),
528
529 0x40000: # RADIX_SECOND_LEVEL
530 # V = 1 L = 1 SW = 0 RPN = 0
531 # R = 1 C = 1 ATT = 0 EAA 0x7
532 b(0xc000000000000183),
533
534 0x1000000: # PROCESS_TABLE_3
535 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
536 b(0x40000000000300ad),
537 }
538
539 # nmigen Simulation
540 sim = Simulator(m)
541 sim.add_clock(1e-6)
542
543 sim.add_sync_process(wrap(ldst_sim_dcache_random2(m)))
544 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
545 with sim.write_vcd('test_ldst_pi_random2.vcd'):
546 sim.run()
547
548 def test_dcache_first():
549
550 m, cmpi = setup_mmu()
551
552 # dcache_load at addr 0
553 mem = {
554 0x10000: # PARTITION_TABLE_2
555 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
556 b(0x800000000100000b),
557
558 0x30000: # RADIX_ROOT_PTE
559 # V = 1 L = 0 NLB = 0x400 NLS = 9
560 b(0x8000000000040009),
561
562 0x40000: # RADIX_SECOND_LEVEL
563 # V = 1 L = 1 SW = 0 RPN = 0
564 # R = 1 C = 1 ATT = 0 EAA 0x7
565 b(0xc000000000000183),
566
567 0x1000000: # PROCESS_TABLE_3
568 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
569 b(0x40000000000300ad),
570 }
571
572 # nmigen Simulation
573 sim = Simulator(m)
574 sim.add_clock(1e-6)
575
576 sim.add_sync_process(wrap(ldst_sim_dcache_first(m)))
577 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
578 with sim.write_vcd('test_ldst_pi_first.vcd'):
579 sim.run()
580
581 if __name__ == '__main__':
582 test_mmu()
583 test_misalign_mmu()
584 test_radixmiss_mmu()
585 ### tests taken from src/soc/experiment/test/test_dcache.py
586 test_dcache_regression()
587 test_dcache_first()
588 test_dcache_random() #sometimes fails
589 test_dcache_random2() #reproduce error