5f6b19f23a01286b04396e370ec91a51438a677b
[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_random(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 for i in range(4):
326 addr = randint(0, memsize-1)
327 data = randint(0, (1<<64)-1)
328 addr *= 8
329 addr += 0x10000
330
331 yield from pi_st(pi, addr, data, 8, msr_pr=1)
332 yield
333
334 ld_data = yield from pi_ld(pi, addr, 8, msr_pr=1)
335
336 print ("addr",addr)
337 print ("dcache_random random ld data", hex(data), hex(ld_data))
338 if data!=ld_data:
339 print("==== data read at random test differs")
340 assert(data==ld_data)
341
342 yield
343 stop = True
344
345 def ldst_sim_dcache_first(dut): # this test is likely to fail
346 mmu = dut.submodules.mmu
347 pi = dut.submodules.ldst.pi
348 global stop
349 stop = False
350
351 yield mmu.rin.prtbl.eq(0x1000000) # set process table
352 yield
353
354 # failed ramdom data
355 addr = 65888
356 data = 0x8c5a3e460d71f0b4
357
358 # known to fail without bugfix in src/soc/fu/ldst/loadstore.py
359 yield from pi_st(pi, addr, data, 8, msr_pr=1)
360 yield
361
362 ld_data = yield from pi_ld(pi, addr, 8, msr_pr=1)
363
364 print ("addr",addr)
365 print ("dcache_first ld data", hex(data), hex(ld_data))
366
367 assert(data==ld_data)
368
369 yield
370 stop = True
371
372 def test_radixmiss_mmu():
373
374 m, cmpi = setup_mmu()
375
376 # virtual "memory" to use for this test
377
378 mem = {0x10000: # PARTITION_TABLE_2
379 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
380 b(0x800000000100000b),
381
382 0x30000: # RADIX_ROOT_PTE
383 # V = 1 L = 0 NLB = 0x400 NLS = 9
384 b(0x8000000000040009),
385
386 0x40000: # RADIX_SECOND_LEVEL
387 # V = 1 L = 1 SW = 0 RPN = 0
388 # R = 1 C = 1 ATT = 0 EAA 0x7
389 b(0xc000000000000183),
390
391 0x1000000: # PROCESS_TABLE_3
392 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
393 b(0x40000000000300ad),
394
395 # data to return
396 0x1000: 0xdeadbeef01234567,
397 0x1008: 0xfeedf00ff001a5a5
398 }
399
400
401 # nmigen Simulation
402 sim = Simulator(m)
403 sim.add_clock(1e-6)
404
405 sim.add_sync_process(wrap(ldst_sim_radixmiss(m)))
406 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
407 with sim.write_vcd('test_ldst_pi_radix_miss.vcd'):
408 sim.run()
409
410 def test_dcache_regression():
411
412 m, cmpi = setup_mmu()
413
414 # dcache_load at addr 0
415 mem = {
416 0x10000: # PARTITION_TABLE_2
417 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
418 b(0x800000000100000b),
419
420 0x30000: # RADIX_ROOT_PTE
421 # V = 1 L = 0 NLB = 0x400 NLS = 9
422 b(0x8000000000040009),
423
424 0x40000: # RADIX_SECOND_LEVEL
425 # V = 1 L = 1 SW = 0 RPN = 0
426 # R = 1 C = 1 ATT = 0 EAA 0x7
427 b(0xc000000000000183),
428
429 0x1000000: # PROCESS_TABLE_3
430 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
431 b(0x40000000000300ad),
432
433 # data to return
434 0x10000: 0xdeadbeef01234567,
435 0x10008: 0xfeedf00ff001a5a5
436 }
437
438 # nmigen Simulation
439 sim = Simulator(m)
440 sim.add_clock(1e-6)
441
442 sim.add_sync_process(wrap(ldst_sim_dcache_regression(m)))
443 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
444 with sim.write_vcd('test_ldst_pi_radix_miss.vcd'):
445 sim.run()
446
447 def test_dcache_random():
448
449 m, cmpi = setup_mmu()
450
451 # dcache_load at addr 0
452 mem = {
453 0x10000: # PARTITION_TABLE_2
454 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
455 b(0x800000000100000b),
456
457 0x30000: # RADIX_ROOT_PTE
458 # V = 1 L = 0 NLB = 0x400 NLS = 9
459 b(0x8000000000040009),
460
461 0x40000: # RADIX_SECOND_LEVEL
462 # V = 1 L = 1 SW = 0 RPN = 0
463 # R = 1 C = 1 ATT = 0 EAA 0x7
464 b(0xc000000000000183),
465
466 0x1000000: # PROCESS_TABLE_3
467 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
468 b(0x40000000000300ad),
469 }
470
471 # nmigen Simulation
472 sim = Simulator(m)
473 sim.add_clock(1e-6)
474
475 sim.add_sync_process(wrap(ldst_sim_dcache_random(m)))
476 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
477 with sim.write_vcd('test_ldst_pi_random.vcd'):
478 sim.run()
479
480 def test_dcache_first():
481
482 m, cmpi = setup_mmu()
483
484 # dcache_load at addr 0
485 mem = {
486 0x10000: # PARTITION_TABLE_2
487 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
488 b(0x800000000100000b),
489
490 0x30000: # RADIX_ROOT_PTE
491 # V = 1 L = 0 NLB = 0x400 NLS = 9
492 b(0x8000000000040009),
493
494 0x40000: # RADIX_SECOND_LEVEL
495 # V = 1 L = 1 SW = 0 RPN = 0
496 # R = 1 C = 1 ATT = 0 EAA 0x7
497 b(0xc000000000000183),
498
499 0x1000000: # PROCESS_TABLE_3
500 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
501 b(0x40000000000300ad),
502 }
503
504 # nmigen Simulation
505 sim = Simulator(m)
506 sim.add_clock(1e-6)
507
508 sim.add_sync_process(wrap(ldst_sim_dcache_first(m)))
509 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
510 with sim.write_vcd('test_ldst_pi_first.vcd'):
511 sim.run()
512
513 if __name__ == '__main__':
514 test_mmu()
515 test_misalign_mmu()
516 test_radixmiss_mmu()
517 ### tests taken from src/soc/experiment/test/test_dcache.py
518 test_dcache_regression()
519 test_dcache_first()
520 test_dcache_random() #first access to memory still fails after recent change