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