cleanup 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 from openpower.test.wb_get import wb_get
14 from openpower.test import wb_get as wbget
15
16 if True:
17 from nmigen.back.pysim import Simulator, Delay, Settle
18 else:
19 from nmigen.sim.cxxsim import Simulator, Delay, Settle
20 from nmutil.util import wrap
21
22 from soc.config.test.test_pi2ls import pi_ld, pi_st, pi_ldst
23 from soc.config.test.test_loadstore import TestMemPspec
24 from soc.config.loadstore import ConfigMemoryPortInterface
25
26 from soc.fu.ldst.loadstore import LoadStore1
27 from soc.experiment.mmu import MMU
28
29 from nmigen.compat.sim import run_simulation
30
31 msr_default = MSRSpec(pr=1, dr=0, sf=1) # 64 bit by default
32
33
34 wbget.stop = False
35
36 def b(x): # byte-reverse function
37 return int.from_bytes(x.to_bytes(8, byteorder='little'),
38 byteorder='big', signed=False)
39
40 #def dumpmem(mem,fn):
41 # f = open(fn,"w")
42 # for cell in mem:
43 # f.write(str(hex(cell))+"="+str(hex(mem[cell]))+"\n")
44
45
46 def mmu_lookup(dut, addr):
47 mmu = dut.submodules.mmu
48
49 print("pi_ld", hex(addr))
50 data, _, _ = yield from pi_ld(dut.submodules.ldst.pi, addr, 4, msr=msr_default)
51 print("pi_ld done, data", hex(data))
52 """
53 # original test code kept for reference
54 while not wbget.stop: # wait for dc_valid / err
55 print("waiting for mmu")
56 l_done = yield (mmu.l_out.done)
57 l_err = yield (mmu.l_out.err)
58 l_badtree = yield (mmu.l_out.badtree)
59 l_permerr = yield (mmu.l_out.perm_error)
60 l_rc_err = yield (mmu.l_out.rc_error)
61 l_segerr = yield (mmu.l_out.segerr)
62 l_invalid = yield (mmu.l_out.invalid)
63 if (l_done or l_err or l_badtree or
64 l_permerr or l_rc_err or l_segerr or l_invalid):
65 break
66 yield
67 """
68 phys_addr = yield mmu.d_out.addr
69 pte = yield mmu.d_out.pte
70 l_done = yield (mmu.l_out.done)
71 l_err = yield (mmu.l_out.err)
72 l_badtree = yield (mmu.l_out.badtree)
73 print ("translated done %d err %d badtree %d addr %x pte %x" % \
74 (l_done, l_err, l_badtree, phys_addr, pte))
75 yield
76 yield mmu.l_in.valid.eq(0)
77
78 return data
79
80
81 def ldst_sim(dut):
82 mmu = dut.submodules.mmu
83 yield mmu.rin.prtbl.eq(0x1000000) # set process table
84 yield
85
86 # expecting this data to return
87 # 0x1000: 0xdeadbeef01234567,
88 # 0x1008: 0xfeedf00ff001a5a5
89
90 addr = 0x1000
91 print("pi_ld")
92
93 # TODO mmu_lookup using port interface
94 # set inputs
95 data = yield from mmu_lookup(dut, addr)
96 assert data == 0x1234567
97
98 data = yield from mmu_lookup(dut, addr+8)
99 assert data == 0xf001a5a5
100 #assert phys_addr == addr # happens to be the same (for this example)
101
102 data = yield from mmu_lookup(dut, addr+4)
103 assert data == 0xdeadbeef
104
105 data = yield from mmu_lookup(dut, addr+8)
106 assert data == 0xf001a5a5
107
108 yield from pi_st(dut.submodules.ldst.pi, addr+4, 0x10015a5a, 4, msr=msr_default)
109
110 data = yield from mmu_lookup(dut, addr+4)
111 assert data == 0x10015a5a
112
113 yield
114 yield
115
116 wbget.stop = True
117
118 def setup_mmu():
119
120 wbget.stop = False
121
122 pspec = TestMemPspec(ldst_ifacetype='mmu_cache_wb',
123 imem_ifacetype='',
124 addr_wid=48,
125 #disable_cache=True, # hmmm...
126 mask_wid=8,
127 reg_wid=64)
128
129 m = Module()
130 comb = m.d.comb
131 cmpi = ConfigMemoryPortInterface(pspec)
132 m.submodules.ldst = ldst = cmpi.pi
133 m.submodules.mmu = mmu = MMU()
134 dcache = ldst.dcache
135
136 l_in, l_out = mmu.l_in, mmu.l_out
137 d_in, d_out = dcache.d_in, dcache.d_out
138
139 # link mmu and dcache together
140 m.d.comb += dcache.m_in.eq(mmu.d_out) # MMUToDCacheType
141 m.d.comb += mmu.d_in.eq(dcache.m_out) # DCacheToMMUType
142
143 # link ldst and MMU together
144 comb += l_in.eq(ldst.m_out)
145 comb += ldst.m_in.eq(l_out)
146
147 return m, cmpi
148
149
150 def test_mmu():
151
152 m, cmpi = setup_mmu()
153
154 # virtual "memory" to use for this test
155
156 mem = {0x10000: # PARTITION_TABLE_2
157 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
158 b(0x800000000100000b),
159
160 0x30000: # RADIX_ROOT_PTE
161 # V = 1 L = 0 NLB = 0x400 NLS = 9
162 b(0x8000000000040009),
163
164 0x40000: # RADIX_SECOND_LEVEL
165 # V = 1 L = 1 SW = 0 RPN = 0
166 # R = 1 C = 1 ATT = 0 EAA 0x7
167 b(0xc000000000000183),
168
169 0x1000000: # PROCESS_TABLE_3
170 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
171 b(0x40000000000300ad),
172
173 # data to return
174 0x1000: 0xdeadbeef01234567,
175 0x1008: 0xfeedf00ff001a5a5
176 }
177
178
179 # nmigen Simulation
180 sim = Simulator(m)
181 sim.add_clock(1e-6)
182
183 sim.add_sync_process(wrap(ldst_sim(m)))
184 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
185 with sim.write_vcd('test_ldst_pi.vcd'):
186 sim.run()
187
188
189 def ldst_sim_misalign(dut):
190 mmu = dut.submodules.mmu
191 wbget.stop = False
192
193 yield mmu.rin.prtbl.eq(0x1000000) # set process table
194 yield
195
196 data, _, _ = yield from pi_ld(dut.submodules.ldst.pi, 0x1007, 8, msr_default)
197 print ("misalign ld data", data)
198
199 yield
200 wbget.stop = True
201
202
203 def test_misalign_mmu():
204
205 m, cmpi = setup_mmu()
206
207 # virtual "memory" to use for this test
208
209 mem = {0x10000: # PARTITION_TABLE_2
210 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
211 b(0x800000000100000b),
212
213 0x30000: # RADIX_ROOT_PTE
214 # V = 1 L = 0 NLB = 0x400 NLS = 9
215 b(0x8000000000040009),
216
217 0x40000: # RADIX_SECOND_LEVEL
218 # V = 1 L = 1 SW = 0 RPN = 0
219 # R = 1 C = 1 ATT = 0 EAA 0x7
220 b(0xc000000000000183),
221
222 0x1000000: # PROCESS_TABLE_3
223 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
224 b(0x40000000000300ad),
225
226 # data to return
227 0x1000: 0xdeadbeef01234567,
228 0x1008: 0xfeedf00ff001a5a5
229 }
230
231
232 # nmigen Simulation
233 sim = Simulator(m)
234 sim.add_clock(1e-6)
235
236 sim.add_sync_process(wrap(ldst_sim_misalign(m)))
237 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
238 with sim.write_vcd('test_ldst_pi_misalign.vcd'):
239 sim.run()
240
241
242 def ldst_sim_radixmiss(dut):
243 mmu = dut.submodules.mmu
244 wbget.stop = False
245
246 yield mmu.rin.prtbl.eq(1<<40) # set process table
247 yield
248
249 data, _, _ = yield from pi_ld(dut.submodules.ldst.pi,
250 0x10000000, 8, msr=msr_default)
251 print ("radixmiss ld data", data)
252
253 yield
254 wbget.stop = True
255
256 def ldst_sim_dcache_regression(dut):
257 mmu = dut.submodules.mmu
258 wbget.stop = False
259
260 yield mmu.rin.prtbl.eq(0x1000000) # set process table
261 yield
262
263 addr = 0x10000
264 data, _, _ = yield from pi_ld(dut.submodules.ldst.pi, addr, 8, msr=msr_default)
265 print ("=== dcache_regression ld data", data)
266 assert(data == 0xdeadbeef01234567)
267
268 yield
269 wbget.stop = True
270
271 def ldst_sim_dcache_random(dut):
272 mmu = dut.submodules.mmu
273 pi = dut.submodules.ldst.pi
274 wbget.stop = False
275
276 yield mmu.rin.prtbl.eq(0x1000000) # set process table
277 yield
278
279 memsize = 64
280
281 for i in range(16):
282 addr = randint(0, memsize-1)
283 data = randint(0, (1<<64)-1)
284 addr *= 8
285 addr += 0x10000
286
287 yield from pi_st(pi, addr, data, 8, msr=msr_default)
288 yield
289
290 ld_data, _, _ = yield from pi_ld(pi, addr, 8, msr=msr_default)
291
292 eq = (data==ld_data)
293 print ("dcache_random values", hex(addr), hex(data), hex(ld_data), eq)
294 assert(data==ld_data) ## investigate why this fails -- really seldom
295
296 yield
297 wbget.stop = True
298
299 def ldst_sim_dcache_first(dut): # this test is likely to fail
300 mmu = dut.submodules.mmu
301 pi = dut.submodules.ldst.pi
302 wbget.stop = False
303
304 yield mmu.rin.prtbl.eq(0x1000000) # set process table
305 yield
306
307 # failed ramdom data
308 addr = 65888
309 data = 0x8c5a3e460d71f0b4
310
311 # known to fail without bugfix in src/soc/fu/ldst/loadstore.py
312 yield from pi_st(pi, addr, data, 8, msr=msr_default)
313 yield
314
315 ld_data, _, _ = yield from pi_ld(pi, addr, 8, msr=msr_default)
316
317 print ("addr",addr)
318 print ("dcache_first ld data", hex(data), hex(ld_data))
319
320 assert(data==ld_data)
321
322 yield
323 wbget.stop = True
324
325 def test_radixmiss_mmu():
326
327 m, cmpi = setup_mmu()
328
329 # virtual "memory" to use for this test
330
331 mem = {0x10000: # PARTITION_TABLE_2
332 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
333 b(0x800000000100000b),
334
335 0x30000: # RADIX_ROOT_PTE
336 # V = 1 L = 0 NLB = 0x400 NLS = 9
337 b(0x8000000000040009),
338
339 0x40000: # RADIX_SECOND_LEVEL
340 # V = 1 L = 1 SW = 0 RPN = 0
341 # R = 1 C = 1 ATT = 0 EAA 0x7
342 b(0xc000000000000183),
343
344 0x1000000: # PROCESS_TABLE_3
345 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
346 b(0x40000000000300ad),
347
348 # data to return
349 0x1000: 0xdeadbeef01234567,
350 0x1008: 0xfeedf00ff001a5a5
351 }
352
353
354 # nmigen Simulation
355 sim = Simulator(m)
356 sim.add_clock(1e-6)
357
358 sim.add_sync_process(wrap(ldst_sim_radixmiss(m)))
359 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
360 with sim.write_vcd('test_ldst_pi_radix_miss.vcd'):
361 sim.run()
362
363 def test_dcache_regression():
364
365 m, cmpi = setup_mmu()
366
367 # dcache_load at addr 0
368 mem = {
369 0x10000: # PARTITION_TABLE_2
370 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
371 b(0x800000000100000b),
372
373 0x30000: # RADIX_ROOT_PTE
374 # V = 1 L = 0 NLB = 0x400 NLS = 9
375 b(0x8000000000040009),
376
377 0x40000: # RADIX_SECOND_LEVEL
378 # V = 1 L = 1 SW = 0 RPN = 0
379 # R = 1 C = 1 ATT = 0 EAA 0x7
380 b(0xc000000000000183),
381
382 0x1000000: # PROCESS_TABLE_3
383 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
384 b(0x40000000000300ad),
385
386 # data to return
387 0x10000: 0xdeadbeef01234567,
388 0x10008: 0xfeedf00ff001a5a5
389 }
390
391 # nmigen Simulation
392 sim = Simulator(m)
393 sim.add_clock(1e-6)
394
395 sim.add_sync_process(wrap(ldst_sim_dcache_regression(m)))
396 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
397 with sim.write_vcd('test_ldst_pi_radix_miss.vcd'):
398 sim.run()
399
400 def test_dcache_random():
401
402 m, cmpi = setup_mmu()
403
404 # dcache_load at addr 0
405 mem = {
406 0x10000: # PARTITION_TABLE_2
407 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
408 b(0x800000000100000b),
409
410 0x30000: # RADIX_ROOT_PTE
411 # V = 1 L = 0 NLB = 0x400 NLS = 9
412 b(0x8000000000040009),
413
414 0x40000: # RADIX_SECOND_LEVEL
415 # V = 1 L = 1 SW = 0 RPN = 0
416 # R = 1 C = 1 ATT = 0 EAA 0x7
417 b(0xc000000000000183),
418
419 0x1000000: # PROCESS_TABLE_3
420 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
421 b(0x40000000000300ad),
422 }
423
424 # nmigen Simulation
425 sim = Simulator(m)
426 sim.add_clock(1e-6)
427
428 sim.add_sync_process(wrap(ldst_sim_dcache_random(m)))
429 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
430 with sim.write_vcd('test_ldst_pi_random.vcd'):
431 sim.run()
432
433 def ldst_sim_dcache_random2(dut, mem):
434 mmu = dut.submodules.mmu
435 pi = dut.submodules.ldst.pi
436 wbget.stop = False
437
438 yield mmu.rin.prtbl.eq(0x1000000) # set process table
439 yield
440
441 memsize = 64
442
443 refs = [
444 ## random values from a failed test
445 #[0x100e0,0xf553b658ba7e1f51,0,0], ## 1
446 #[0x10150,0x12c95a730df1cee7,0,0], ## 2
447 #[0x10080,0x5a921ae06674cd81,0,0], ## 3
448 #[0x100f8,0x4fea5eab80090fa5,0,0], ## 4
449 #[0x10080,0xd481432d17a340be,0,0], ## 5
450 #[0x10060,0x8553fcf29526fb32,0,0], ## 6
451 [0x101d0,0x327c967c8be30ded,0,0], ## 7
452 [0x101e0,0x8f15d8d05d25b151,1,0] ## 8
453 #uncommenting line 7 will cause the original test not to fail
454
455 ]
456
457 c = 0
458 for i in refs:
459 addr = i[0]
460 data = i[1]
461 c1 = i[2]
462 c2 = i[3]
463
464 print("== write: wb_get")
465
466 for i in range(0,c1):
467 print("before_pi_st")
468 yield
469
470 yield from pi_st(pi, addr, data, 8, msr=msr_default)
471 yield
472
473 for i in range(0,c2):
474 print("before_pi_ld")
475 yield
476
477 print("== read: wb_get")
478 ld_data, _, _ = yield from pi_ld(pi, addr, 8, msr=msr_default)
479
480 #dumpmem(mem,"/tmp/dumpmem"+str(c)+".txt")
481 #c += 1
482
483 eq = (data==ld_data)
484 print ("dcache_random values", hex(addr), hex(data), hex(ld_data), eq)
485 assert(data==ld_data) ## investigate why this fails -- really seldom
486
487 yield
488 wbget.stop = True
489
490 def test_dcache_random2():
491
492 m, cmpi = setup_mmu()
493
494 # dcache_load at addr 0
495 mem = {
496 0x10000: # PARTITION_TABLE_2
497 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
498 b(0x800000000100000b),
499
500 0x30000: # RADIX_ROOT_PTE
501 # V = 1 L = 0 NLB = 0x400 NLS = 9
502 b(0x8000000000040009),
503
504 0x40000: # RADIX_SECOND_LEVEL
505 # V = 1 L = 1 SW = 0 RPN = 0
506 # R = 1 C = 1 ATT = 0 EAA 0x7
507 b(0xc000000000000183),
508
509 0x1000000: # PROCESS_TABLE_3
510 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
511 b(0x40000000000300ad),
512
513 ###0x101e0:0x8f15d8d05d25b152 ## flush cache -- then check again
514 }
515
516 # nmigen Simulation
517 sim = Simulator(m)
518 sim.add_clock(1e-6)
519
520 sim.add_sync_process(wrap(ldst_sim_dcache_random2(m, mem)))
521 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
522 with sim.write_vcd('test_ldst_pi_random2.vcd'):
523 sim.run()
524
525 def test_dcache_first():
526
527 m, cmpi = setup_mmu()
528
529 # dcache_load at addr 0
530 mem = {
531 0x10000: # PARTITION_TABLE_2
532 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
533 b(0x800000000100000b),
534
535 0x30000: # RADIX_ROOT_PTE
536 # V = 1 L = 0 NLB = 0x400 NLS = 9
537 b(0x8000000000040009),
538
539 0x40000: # RADIX_SECOND_LEVEL
540 # V = 1 L = 1 SW = 0 RPN = 0
541 # R = 1 C = 1 ATT = 0 EAA 0x7
542 b(0xc000000000000183),
543
544 0x1000000: # PROCESS_TABLE_3
545 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
546 b(0x40000000000300ad),
547 }
548
549 # nmigen Simulation
550 sim = Simulator(m)
551 sim.add_clock(1e-6)
552
553 sim.add_sync_process(wrap(ldst_sim_dcache_first(m)))
554 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
555 with sim.write_vcd('test_ldst_pi_first.vcd'):
556 sim.run()
557
558 if __name__ == '__main__':
559 test_mmu()
560 test_misalign_mmu()
561 test_radixmiss_mmu()
562 ### tests taken from src/soc/experiment/test/test_dcache.py
563 test_dcache_regression()
564 test_dcache_first()
565 test_dcache_random() #sometimes fails
566 test_dcache_random2() #reproduce error