add skeleton for test_loadstore1_ifetch_invalid()
[soc.git] / src / soc / experiment / test / test_loadstore1.py
1 from nmigen import (C, Module, Signal, Elaboratable, Mux, Cat, Repl, Signal,
2 Const)
3 from nmigen.cli import main
4 from nmigen.cli import rtlil
5 from nmutil.mask import Mask, masked
6 from nmutil.util import Display
7 from random import randint, seed
8 from nmigen.sim import Simulator, Delay, Settle
9 from nmutil.util import wrap
10
11 from soc.config.test.test_pi2ls import pi_ld, pi_st, pi_ldst, wait_busy
12 #from soc.config.test.test_pi2ls import pi_st_debug
13 from soc.config.test.test_loadstore import TestMemPspec
14 from soc.config.loadstore import ConfigMemoryPortInterface
15
16 from soc.fu.ldst.loadstore import LoadStore1
17 from soc.experiment.mmu import MMU
18 from soc.experiment.test import pagetables
19
20 from nmigen.compat.sim import run_simulation
21 from random import random
22 from openpower.test.wb_get import wb_get
23 from openpower.test import wb_get as wbget
24
25
26 def setup_mmu():
27
28 wbget.stop = False
29
30 pspec = TestMemPspec(ldst_ifacetype='mmu_cache_wb',
31 imem_ifacetype='',
32 addr_wid=48,
33 #disable_cache=True, # hmmm...
34 mask_wid=8,
35 reg_wid=64)
36
37 m = Module()
38 comb = m.d.comb
39 cmpi = ConfigMemoryPortInterface(pspec)
40 m.submodules.ldst = ldst = cmpi.pi
41 m.submodules.mmu = mmu = MMU()
42 dcache = ldst.dcache
43 icache = ldst.icache
44
45 l_in, l_out = mmu.l_in, mmu.l_out
46 d_in, d_out = dcache.d_in, dcache.d_out
47 i_in, i_out = icache.i_in, icache.i_out # FetchToICache, ICacheToDecode
48
49 # link mmu, dcache and icache together
50 m.d.comb += dcache.m_in.eq(mmu.d_out) # MMUToDCacheType
51 m.d.comb += icache.m_in.eq(mmu.i_out) # MMUToICacheType
52 m.d.comb += mmu.d_in.eq(dcache.m_out) # DCacheToMMUType
53
54 # link ldst and MMU together
55 comb += l_in.eq(ldst.m_out)
56 comb += ldst.m_in.eq(l_out)
57
58 return m, cmpi
59
60
61 test_exceptions = True
62 test_dcbz = True
63 test_random = True
64
65
66 def _test_loadstore1_ifetch(dut, mem):
67 """test_loadstore1_ifetch
68
69 this is quite a complex multi-step test.
70
71 * first (just because, as a demo) read in priv mode, non-virtual.
72 just like in experiment/icache.py itself.
73
74 * second, using the (usual) PTE for these things (which came originally
75 from gem5-experimental experiment/radix_walk_example.txt) do a
76 virtual-memory read through the *instruction* cache.
77 this is expected to FAIL
78
79 * third: mess about with the MMU, setting "iside" (instruction-side),
80 requesting an MMU RADIX LOOKUP. this triggers an itlb_load
81 (instruction-cache TLB entry-insertion)
82
83 * fourth and finally: retry the read of the instruction through i-cache.
84 this is now expected to SUCCEED
85
86 a lot going on.
87 """
88
89 mmu = dut.submodules.mmu
90 ldst = dut.submodules.ldst
91 pi = ldst.pi
92 icache = dut.submodules.ldst.icache
93 wbget.stop = False
94
95 print("=== test loadstore instruction (real) ===")
96
97 i_in = icache.i_in
98 i_out = icache.i_out
99 i_m_in = icache.m_in
100
101 # first virtual memory test
102
103 print ("set process table")
104 yield mmu.rin.prtbl.eq(0x1000000) # set process table
105 yield
106
107 # set address to zero, update mem[0] to 01234
108 addr = 8
109 expected_insn = 0x1234
110 mem[addr] = expected_insn
111
112 yield i_in.priv_mode.eq(1)
113 yield i_in.req.eq(0)
114 yield i_in.nia.eq(addr)
115 yield i_in.stop_mark.eq(0)
116 yield i_m_in.tlbld.eq(0)
117 yield i_m_in.tlbie.eq(0)
118 yield i_m_in.addr.eq(0)
119 yield i_m_in.pte.eq(0)
120 yield
121 yield
122 yield
123
124 # miss, stalls for a bit
125 yield i_in.req.eq(1)
126 yield i_in.nia.eq(addr)
127 yield
128 valid = yield i_out.valid
129 while not valid:
130 yield
131 valid = yield i_out.valid
132 yield i_in.req.eq(0)
133
134 nia = yield i_out.nia
135 insn = yield i_out.insn
136 yield
137 yield
138
139 print ("fetched %x from addr %x" % (insn, nia))
140 assert insn == expected_insn
141
142 print("=== test loadstore instruction (virtual) ===")
143
144 # look up i-cache expecting it to fail
145
146 # set address to 0x10200, update mem[] to 5678
147 virt_addr = 0x10200
148 real_addr = virt_addr
149 expected_insn = 0x5678
150 mem[real_addr] = expected_insn
151
152 yield i_in.priv_mode.eq(1)
153 yield i_in.virt_mode.eq(1)
154 yield i_in.req.eq(0)
155 yield i_in.nia.eq(virt_addr)
156 yield i_in.stop_mark.eq(0)
157 yield i_m_in.tlbld.eq(0)
158 yield i_m_in.tlbie.eq(0)
159 yield i_m_in.addr.eq(0)
160 yield i_m_in.pte.eq(0)
161 yield
162 yield
163 yield
164
165 # miss, stalls for a bit
166 yield i_in.req.eq(1)
167 yield i_in.nia.eq(virt_addr)
168 yield
169 valid = yield i_out.valid
170 failed = yield i_out.fetch_failed
171 while not valid and not failed:
172 yield
173 valid = yield i_out.valid
174 failed = yield i_out.fetch_failed
175 yield i_in.req.eq(0)
176
177 print ("failed?", "yes" if failed else "no")
178 assert failed == 1
179 yield
180 yield
181
182 print("=== test loadstore instruction (instruction fault) ===")
183
184 virt_addr = 0x10200
185
186 yield ldst.priv_mode.eq(1)
187 yield ldst.instr_fault.eq(1)
188 yield ldst.maddr.eq(virt_addr)
189 #ld_data, exctype, exc = yield from pi_ld(pi, virt_addr, 8, msr_pr=1)
190 yield
191 yield ldst.instr_fault.eq(0)
192 while True:
193 done = yield (ldst.done)
194 if done:
195 break
196 yield
197 yield ldst.instr_fault.eq(0)
198 yield
199 yield
200 yield
201
202 print("=== test loadstore instruction (try instruction again) ===")
203 # set address to 0x10200, update mem[] to 5678
204 virt_addr = 0x10200
205 real_addr = virt_addr
206 expected_insn = 0x5678
207
208 yield i_in.priv_mode.eq(1)
209 yield i_in.virt_mode.eq(1)
210 yield i_in.req.eq(0)
211 yield i_in.nia.eq(virt_addr)
212 yield i_in.stop_mark.eq(0)
213 yield i_m_in.tlbld.eq(0)
214 yield i_m_in.tlbie.eq(0)
215 yield i_m_in.addr.eq(0)
216 yield i_m_in.pte.eq(0)
217 yield
218 yield
219 yield
220
221 # miss, stalls for a bit
222 yield i_in.req.eq(1)
223 yield i_in.nia.eq(virt_addr)
224 yield
225 valid = yield i_out.valid
226 failed = yield i_out.fetch_failed
227 while not valid and not failed:
228 yield
229 valid = yield i_out.valid
230 failed = yield i_out.fetch_failed
231 yield i_in.req.eq(0)
232 nia = yield i_out.nia
233 insn = yield i_out.insn
234 yield
235 yield
236
237 print ("failed?", "yes" if failed else "no")
238 assert failed == 0
239
240 print ("fetched %x from addr %x" % (insn, nia))
241 assert insn == expected_insn
242
243 wbget.stop = True
244
245
246 def _test_loadstore1_invalid(dut, mem):
247 mmu = dut.submodules.mmu
248 pi = dut.submodules.ldst.pi
249 wbget.stop = False
250
251 print("=== test invalid ===")
252
253 addr = 0
254 ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr_pr=1)
255 print("ld_data", ld_data, exctype, exc)
256 assert (exctype == "slow")
257 invalid = exc.invalid
258 assert (invalid == 1)
259
260 print("=== test invalid done ===")
261
262 wbget.stop = True
263
264
265 def _test_loadstore1(dut, mem):
266 mmu = dut.submodules.mmu
267 pi = dut.submodules.ldst.pi
268 ldst = dut.submodules.ldst # to get at DAR (NOT part of PortInterface)
269 wbget.stop = False
270
271 yield mmu.rin.prtbl.eq(0x1000000) # set process table
272 yield
273
274 addr = 0x100e0
275 data = 0xf553b658ba7e1f51
276
277 if test_dcbz:
278 yield from pi_st(pi, addr, data, 8, msr_pr=1)
279 yield
280
281 ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr_pr=1)
282 assert ld_data == 0xf553b658ba7e1f51
283 assert exctype is None
284
285 ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr_pr=1)
286 assert ld_data == 0xf553b658ba7e1f51
287 assert exctype is None
288
289 print("do_dcbz ===============")
290 yield from pi_st(pi, addr, data, 8, msr_pr=1, is_dcbz=1)
291 print("done_dcbz ===============")
292 yield
293
294 ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr_pr=1)
295 print("ld_data after dcbz")
296 print(ld_data)
297 assert ld_data == 0
298 assert exctype is None
299
300 if test_exceptions:
301 print("=== alignment error (ld) ===")
302 addr = 0xFF100e0FF
303 ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr_pr=1)
304 if exc:
305 alignment = exc.alignment
306 happened = exc.happened
307 yield # wait for dsr to update
308 dar = yield ldst.dar
309 else:
310 alignment = 0
311 happened = 0
312 dar = 0
313 assert (happened == 1)
314 assert (alignment == 1)
315 assert (dar == addr)
316 assert (exctype == "fast")
317 yield from wait_busy(pi, debug="pi_ld_E_alignment_error")
318 # wait is only needed in case of in exception here
319 print("=== alignment error test passed (ld) ===")
320
321 # take some cycles in between so that gtkwave separates out
322 # signals
323 yield
324 yield
325 yield
326 yield
327
328 print("=== alignment error (st) ===")
329 addr = 0xFF100e0FF
330 exctype, exc = yield from pi_st(pi, addr,0, 8, msr_pr=1)
331 if exc:
332 alignment = exc.alignment
333 happened = exc.happened
334 else:
335 alignment = 0
336 happened = 0
337 assert (happened == 1)
338 assert (alignment==1)
339 assert (dar==addr)
340 assert (exctype == "fast")
341 #???? yield from wait_busy(pi, debug="pi_st_E_alignment_error")
342 # wait is only needed in case of in exception here
343 print("=== alignment error test passed (st) ===")
344 yield #FIXME hangs
345
346 if True:
347 print("=== no alignment error (ld) ===")
348 addr = 0x100e0
349 ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr_pr=1)
350 print("ld_data", ld_data, exctype, exc)
351 if exc:
352 alignment = exc.alignment
353 happened = exc.happened
354 else:
355 alignment = 0
356 happened = 0
357 assert (happened == 0)
358 assert (alignment == 0)
359 print("=== no alignment error done (ld) ===")
360
361 if test_random:
362 addrs = [0x456920,0xa7a180,0x299420,0x1d9d60]
363
364 for addr in addrs:
365 print("== RANDOM addr ==",hex(addr))
366 ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr_pr=1)
367 print("ld_data[RANDOM]",ld_data,exc,addr)
368 assert (exctype == None)
369
370 for addr in addrs:
371 print("== RANDOM addr ==",hex(addr))
372 exc = yield from pi_st(pi, addr,0xFF*addr, 8, msr_pr=1)
373 assert (exctype == None)
374
375 # readback written data and compare
376 for addr in addrs:
377 print("== RANDOM addr ==",hex(addr))
378 ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr_pr=1)
379 print("ld_data[RANDOM_READBACK]",ld_data,exc,addr)
380 assert (exctype == None)
381 assert (ld_data == 0xFF*addr)
382
383 print("== RANDOM addr done ==")
384
385 wbget.stop = True
386
387 def _test_loadstore1_ifetch_invalid(dut, mem):
388 mmu = dut.submodules.mmu
389 pi = dut.submodules.ldst.pi
390 ldst = dut.submodules.ldst # to get at DAR (NOT part of PortInterface)
391 wbget.stop = False
392
393 yield mmu.rin.prtbl.eq(0x1000000) # set process table
394 yield
395
396 # TODO
397
398 wbget.stop = True
399
400
401 def test_loadstore1_ifetch():
402
403 m, cmpi = setup_mmu()
404
405 mem = pagetables.test1
406
407 # nmigen Simulation
408 sim = Simulator(m)
409 sim.add_clock(1e-6)
410
411 icache = m.submodules.ldst.icache
412 sim.add_sync_process(wrap(_test_loadstore1_ifetch(m, mem)))
413 # add two wb_get processes onto the *same* memory dictionary.
414 # this shouuuld work.... cross-fingers...
415 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
416 sim.add_sync_process(wrap(wb_get(icache.bus, mem)))
417 with sim.write_vcd('test_loadstore1_ifetch.vcd'):
418 sim.run()
419
420
421 def test_loadstore1():
422
423 m, cmpi = setup_mmu()
424
425 mem = pagetables.test1
426
427 # nmigen Simulation
428 sim = Simulator(m)
429 sim.add_clock(1e-6)
430
431 sim.add_sync_process(wrap(_test_loadstore1(m, mem)))
432 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
433 with sim.write_vcd('test_loadstore1.vcd'):
434 sim.run()
435
436
437 def test_loadstore1_invalid():
438
439 m, cmpi = setup_mmu()
440
441 mem = {}
442
443 # nmigen Simulation
444 sim = Simulator(m)
445 sim.add_clock(1e-6)
446
447 sim.add_sync_process(wrap(_test_loadstore1_invalid(m, mem)))
448 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
449 with sim.write_vcd('test_loadstore1_invalid.vcd'):
450 sim.run()
451
452 def test_loadstore1_ifetch_invalid():
453
454 m, cmpi = setup_mmu()
455
456 mem = {}
457
458 # nmigen Simulation
459 sim = Simulator(m)
460 sim.add_clock(1e-6)
461
462 sim.add_sync_process(wrap(_test_loadstore1_ifetch_invalid(m, mem)))
463 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
464 with sim.write_vcd('test_loadstore1_invalid.vcd'):
465 sim.run()
466
467
468 if __name__ == '__main__':
469 test_loadstore1()
470 test_loadstore1_invalid()
471 test_loadstore1_ifetch()
472 test_loadstore1_ifetch_invalid()