test_ldst_pi.py: first version of test_dcache_random()
[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(1024):
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 test_radixmiss_mmu():
346
347 m, cmpi = setup_mmu()
348
349 # virtual "memory" to use for this test
350
351 mem = {0x10000: # PARTITION_TABLE_2
352 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
353 b(0x800000000100000b),
354
355 0x30000: # RADIX_ROOT_PTE
356 # V = 1 L = 0 NLB = 0x400 NLS = 9
357 b(0x8000000000040009),
358
359 0x40000: # RADIX_SECOND_LEVEL
360 # V = 1 L = 1 SW = 0 RPN = 0
361 # R = 1 C = 1 ATT = 0 EAA 0x7
362 b(0xc000000000000183),
363
364 0x1000000: # PROCESS_TABLE_3
365 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
366 b(0x40000000000300ad),
367
368 # data to return
369 0x1000: 0xdeadbeef01234567,
370 0x1008: 0xfeedf00ff001a5a5
371 }
372
373
374 # nmigen Simulation
375 sim = Simulator(m)
376 sim.add_clock(1e-6)
377
378 sim.add_sync_process(wrap(ldst_sim_radixmiss(m)))
379 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
380 with sim.write_vcd('test_ldst_pi_radix_miss.vcd'):
381 sim.run()
382
383 def test_dcache_regression():
384
385 m, cmpi = setup_mmu()
386
387 # dcache_load at addr 0
388 mem = {
389 0x10000: # PARTITION_TABLE_2
390 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
391 b(0x800000000100000b),
392
393 0x30000: # RADIX_ROOT_PTE
394 # V = 1 L = 0 NLB = 0x400 NLS = 9
395 b(0x8000000000040009),
396
397 0x40000: # RADIX_SECOND_LEVEL
398 # V = 1 L = 1 SW = 0 RPN = 0
399 # R = 1 C = 1 ATT = 0 EAA 0x7
400 b(0xc000000000000183),
401
402 0x1000000: # PROCESS_TABLE_3
403 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
404 b(0x40000000000300ad),
405
406 # data to return
407 0x10000: 0xdeadbeef01234567,
408 0x10008: 0xfeedf00ff001a5a5
409 }
410
411 # nmigen Simulation
412 sim = Simulator(m)
413 sim.add_clock(1e-6)
414
415 sim.add_sync_process(wrap(ldst_sim_dcache_regression(m)))
416 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
417 with sim.write_vcd('test_ldst_pi_radix_miss.vcd'):
418 sim.run()
419
420 def test_dcache_random():
421
422 m, cmpi = setup_mmu()
423
424 # dcache_load at addr 0
425 mem = {
426 0x10000: # PARTITION_TABLE_2
427 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
428 b(0x800000000100000b),
429
430 0x30000: # RADIX_ROOT_PTE
431 # V = 1 L = 0 NLB = 0x400 NLS = 9
432 b(0x8000000000040009),
433
434 0x40000: # RADIX_SECOND_LEVEL
435 # V = 1 L = 1 SW = 0 RPN = 0
436 # R = 1 C = 1 ATT = 0 EAA 0x7
437 b(0xc000000000000183),
438
439 0x1000000: # PROCESS_TABLE_3
440 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
441 b(0x40000000000300ad),
442 }
443
444 # nmigen Simulation
445 sim = Simulator(m)
446 sim.add_clock(1e-6)
447
448 sim.add_sync_process(wrap(ldst_sim_dcache_random(m)))
449 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
450 with sim.write_vcd('test_ldst_pi_radix_miss.vcd'):
451 sim.run()
452
453 if __name__ == '__main__':
454 test_mmu()
455 test_misalign_mmu()
456 test_radixmiss_mmu()
457 ### tests taken from src/soc/experiment/test/test_dcache.py
458 test_dcache_regression()
459 test_dcache_random() #first access to memory fails - investigate
460 #TODO test_dcache()