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