fix MMU lookup after 2nd request (misaligned) by also updating the
[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 get_exception_info)
13 #from soc.config.test.test_pi2ls import pi_st_debug
14 from soc.config.test.test_loadstore import TestMemPspec
15 from soc.config.loadstore import ConfigMemoryPortInterface
16
17 from soc.fu.ldst.loadstore import LoadStore1
18 from soc.experiment.mmu import MMU
19 from soc.experiment.test import pagetables
20
21 from nmigen.compat.sim import run_simulation
22 from random import random
23 from openpower.test.wb_get import wb_get
24 from openpower.test import wb_get as wbget
25 from openpower.exceptions import LDSTExceptionTuple
26
27 from soc.config.test.test_fetch import read_from_addr
28 from openpower.decoder.power_enums import MSRSpec
29
30
31 def setup_mmu():
32
33 wbget.stop = False
34
35 pspec = TestMemPspec(ldst_ifacetype='mmu_cache_wb',
36 imem_ifacetype='',
37 addr_wid=48,
38 #disable_cache=True, # hmmm...
39 mask_wid=8,
40 reg_wid=64)
41
42 m = Module()
43 comb = m.d.comb
44 cmpi = ConfigMemoryPortInterface(pspec)
45 m.submodules.ldst = ldst = cmpi.pi
46 m.submodules.mmu = mmu = MMU()
47 dcache = ldst.dcache
48 icache = ldst.icache
49
50 l_in, l_out = mmu.l_in, mmu.l_out
51 d_in, d_out = dcache.d_in, dcache.d_out
52 i_in, i_out = icache.i_in, icache.i_out # FetchToICache, ICacheToDecode
53
54 # link mmu, dcache and icache together
55 m.d.comb += dcache.m_in.eq(mmu.d_out) # MMUToDCacheType
56 m.d.comb += icache.m_in.eq(mmu.i_out) # MMUToICacheType
57 m.d.comb += mmu.d_in.eq(dcache.m_out) # DCacheToMMUType
58
59 # link ldst and MMU together
60 comb += l_in.eq(ldst.m_out)
61 comb += ldst.m_in.eq(l_out)
62
63 # add a debug status Signal: use "msg.str = "blah"
64 # then toggle with yield msg.eq(0); yield msg.eq(1)
65 debug_status = Signal(8, decoder=lambda _ : debug_status.str)
66 m.debug_status = debug_status
67 debug_status.str = ''
68
69 return m, cmpi
70
71
72 def icache_read(dut,addr,priv,virt):
73
74 icache = dut.submodules.ldst.icache
75 i_in = icache.i_in
76 i_out = icache.i_out
77
78 yield i_in.priv_mode.eq(priv)
79 yield i_in.virt_mode.eq(virt)
80 yield i_in.req.eq(1)
81 yield i_in.nia.eq(addr)
82 yield i_in.stop_mark.eq(0)
83
84 yield i_in.req.eq(1)
85 yield i_in.nia.eq(addr)
86 yield
87 valid = yield i_out.valid
88 failed = yield i_out.fetch_failed
89 while not valid and not failed:
90 yield
91 valid = yield i_out.valid
92 failed = yield i_out.fetch_failed
93 yield i_in.req.eq(0)
94
95 nia = yield i_out.nia
96 insn = yield i_out.insn
97 yield
98 yield
99
100 return nia, insn, valid, failed
101
102
103 test_exceptions = True
104 test_dcbz = True
105 test_random = True
106
107
108 def debug(dut, msg):
109 print ("set debug message", msg)
110 dut.debug_status.str = msg # set the message
111 yield dut.debug_status.eq(0) # trigger an update
112 yield dut.debug_status.eq(1)
113
114
115 def _test_loadstore1_ifetch_iface(dut, mem):
116 """test_loadstore1_ifetch_iface
117
118 read in priv mode, non-virtual. tests the FetchUnitInterface
119
120 """
121
122 mmu = dut.submodules.mmu
123 ldst = dut.submodules.ldst
124 pi = ldst.pi
125 icache = dut.submodules.ldst.icache
126 wbget.stop = False
127
128 print("=== test loadstore instruction (real) ===")
129
130 i_in = icache.i_in
131 i_out = icache.i_out
132 i_m_in = icache.m_in
133
134 yield from debug(dut, "real mem instruction")
135 # set address to 0x8, update mem[0x8] to 01234 | 0x5678<<32
136 # (have to do 64-bit writes into the dictionary-memory-emulated-thing)
137 addr = 8
138 addr2 = 12
139 expected_insn2 = 0x5678
140 expected_insn = 0x1234
141 mem[addr] = expected_insn | expected_insn2<<32
142
143 yield i_in.priv_mode.eq(1)
144 insn = yield from read_from_addr(icache, addr, stall=False)
145
146 nia = yield i_out.nia # NO, must use FetchUnitInterface
147 print ("fetched %x from addr %x" % (insn, nia))
148 assert insn == expected_insn
149
150 print("=== test loadstore instruction (2nd, real) ===")
151 yield from debug(dut, "real mem 2nd (addr 0xc)")
152
153 insn2 = yield from read_from_addr(icache, addr2, stall=False)
154
155 nia = yield i_out.nia # NO, must use FetchUnitInterface
156 print ("fetched %x from addr2 %x" % (insn2, nia))
157 assert insn2 == expected_insn2
158
159 print("=== test loadstore instruction (done) ===")
160
161 yield from debug(dut, "test done")
162 yield
163 yield
164
165 print ("fetched %x from addr %x" % (insn, nia))
166 assert insn == expected_insn
167
168 wbget.stop = True
169
170
171 def write_mem2(mem, addr, i1, i2):
172 mem[addr] = i1 | i2<<32
173
174
175 #TODO: use fetch interface here
176 def lookup_virt(dut,addr):
177 icache = dut.submodules.ldst.icache
178 i_in = icache.i_in
179 i_out = icache.i_out
180 yield i_in.priv_mode.eq(0)
181 yield i_in.virt_mode.eq(1)
182 yield i_in.req.eq(0)
183 yield i_in.stop_mark.eq(0)
184
185 yield icache.a_i_valid.eq(1)
186 yield icache.a_pc_i.eq(addr)
187 yield
188 valid = yield i_out.valid
189 failed = yield i_out.fetch_failed
190 while not valid and not failed:
191 yield
192 valid = yield i_out.valid
193 failed = yield i_out.fetch_failed
194 yield icache.a_i_valid.eq(0)
195
196 return valid,failed
197
198
199 def mmu_lookup(dut,addr):
200 ldst = dut.submodules.ldst
201 pi = ldst.pi
202 yield from debug(dut, "instr fault "+hex(addr))
203 yield ldst.priv_mode.eq(0)
204 yield ldst.instr_fault.eq(1)
205 yield ldst.maddr.eq(addr)
206 yield
207 yield ldst.instr_fault.eq(0)
208 while True:
209 done = yield (ldst.done)
210 exc_info = yield from get_exception_info(pi.exc_o)
211 if done or exc_info.happened:
212 break
213 yield
214 yield
215 assert exc_info.happened == 0 # assert just before doing the fault set zero
216 yield ldst.instr_fault.eq(0)
217 yield from debug(dut, "instr fault done "+hex(addr))
218 yield
219 yield
220 yield
221
222
223 def _test_loadstore1_ifetch_multi(dut, mem):
224 mmu = dut.submodules.mmu
225 ldst = dut.submodules.ldst
226 pi = ldst.pi
227 icache = dut.submodules.ldst.icache
228 assert wbget.stop == False
229
230 print ("set process table")
231 yield from debug(dut, "set prtble")
232 yield mmu.rin.prtbl.eq(0x1000000) # set process table
233 yield
234
235 i_in = icache.i_in
236 i_out = icache.i_out
237 i_m_in = icache.m_in
238
239 # fetch instructions from multiple addresses
240 # should cope with some addresses being invalid
241 real_addrs = [0,4,8,0,8,4,0,0,12]
242 write_mem2(mem,0,0xF0,0xF4)
243 write_mem2(mem,8,0xF8,0xFC)
244
245 yield i_in.priv_mode.eq(1)
246 for addr in real_addrs:
247 yield from debug(dut, "real_addr "+hex(addr))
248 insn = yield from read_from_addr(icache, addr, stall=False)
249 nia = yield i_out.nia # NO, must use FetchUnitInterface
250 print ("TEST_MULTI: fetched %x from addr %x == %x" % (insn, nia,addr))
251 assert insn==0xF0+addr
252
253 # now with virtual memory enabled
254 yield i_in.virt_mode.eq(1)
255
256 virt_addrs = [0x10200,0x10204,0x10208,0x10200,
257 0x102008,0x10204,0x10200,0x10200,0x10200C]
258
259 write_mem2(mem,0x10200,0xF8,0xFC)
260
261 for addr in virt_addrs:
262 yield from debug(dut, "virt_addr "+hex(addr))
263
264 valid, failed = yield from lookup_virt(dut,addr)
265 yield
266 print("TEST_MULTI: failed=",failed) # this is reported wrong
267 if failed==1: # test one first
268 yield from mmu_lookup(dut,addr)
269 valid, failed = yield from lookup_virt(dut,addr)
270 assert(valid==1)
271
272 wbget.stop = True
273
274
275 def _test_loadstore1_ifetch(dut, mem):
276 """test_loadstore1_ifetch
277
278 this is quite a complex multi-step test.
279
280 * first (just because, as a demo) read in priv mode, non-virtual.
281 just like in experiment/icache.py itself.
282
283 * second, using the (usual) PTE for these things (which came originally
284 from gem5-experimental experiment/radix_walk_example.txt) do a
285 virtual-memory read through the *instruction* cache.
286 this is expected to FAIL
287
288 * third: mess about with the MMU, setting "iside" (instruction-side),
289 requesting an MMU RADIX LOOKUP. this triggers an itlb_load
290 (instruction-cache TLB entry-insertion)
291
292 * fourth and finally: retry the read of the instruction through i-cache.
293 this is now expected to SUCCEED
294
295 a lot going on.
296 """
297
298 mmu = dut.submodules.mmu
299 ldst = dut.submodules.ldst
300 pi = ldst.pi
301 icache = dut.submodules.ldst.icache
302 wbget.stop = False
303
304 print("=== test loadstore instruction (real) ===")
305
306 i_in = icache.i_in
307 i_out = icache.i_out
308 i_m_in = icache.m_in
309
310 # first virtual memory test
311
312 print ("set process table")
313 yield from debug(dut, "set prtble")
314 yield mmu.rin.prtbl.eq(0x1000000) # set process table
315 yield
316
317 yield from debug(dut, "real mem instruction")
318 # set address to zero, update mem[0] to 01234
319 addr = 8
320 expected_insn = 0x1234
321 mem[addr] = expected_insn
322
323 yield i_in.priv_mode.eq(1)
324 yield i_in.req.eq(0)
325 yield i_in.nia.eq(addr)
326 yield i_in.stop_mark.eq(0)
327 yield i_m_in.tlbld.eq(0)
328 yield i_m_in.tlbie.eq(0)
329 yield i_m_in.addr.eq(0)
330 yield i_m_in.pte.eq(0)
331 yield
332 yield
333 yield
334
335 # miss, stalls for a bit -- this one is different here
336 ##nia, insn, valid, failed = yield from icache_read(dut,addr,0,0)
337 ##assert(valid==0)
338 ##assert(failed==1)
339
340 yield i_in.req.eq(1)
341 yield i_in.nia.eq(addr)
342 yield
343 valid = yield i_out.valid
344 while not valid:
345 yield
346 valid = yield i_out.valid
347 yield i_in.req.eq(0)
348
349 nia = yield i_out.nia
350 insn = yield i_out.insn
351 yield
352 yield
353
354 print ("fetched %x from addr %x" % (insn, nia))
355 assert insn == expected_insn
356
357 print("=== test loadstore instruction (virtual) ===")
358
359 # look up i-cache expecting it to fail
360
361 yield from debug(dut, "virtual instr req")
362 # set address to 0x10200, update mem[] to 5678
363 virt_addr = 0x10200
364 real_addr = virt_addr
365 expected_insn = 0x5678
366 mem[real_addr] = expected_insn
367
368 yield i_in.priv_mode.eq(0)
369 yield i_in.virt_mode.eq(1)
370 yield i_in.req.eq(0)
371 yield i_in.nia.eq(virt_addr)
372 yield i_in.stop_mark.eq(0)
373 yield i_m_in.tlbld.eq(0)
374 yield i_m_in.tlbie.eq(0)
375 yield i_m_in.addr.eq(0)
376 yield i_m_in.pte.eq(0)
377 yield
378 yield
379 yield
380
381 # miss, stalls for a bit
382 yield i_in.req.eq(1)
383 yield i_in.nia.eq(virt_addr)
384 yield
385 valid = yield i_out.valid
386 failed = yield i_out.fetch_failed
387 while not valid and not failed:
388 yield
389 valid = yield i_out.valid
390 failed = yield i_out.fetch_failed
391 yield i_in.req.eq(0)
392
393 print ("failed?", "yes" if failed else "no")
394 assert failed == 1
395 yield
396 yield
397
398 print("=== test loadstore instruction (instruction fault) ===")
399
400 yield from debug(dut, "instr fault")
401
402 virt_addr = 0x10200
403
404 yield ldst.priv_mode.eq(0)
405 yield ldst.instr_fault.eq(1)
406 yield ldst.maddr.eq(virt_addr)
407 # still broken -- investigate
408 # msr = MSRSpec(pr=?, dr=?, sf=0)
409 # ld_data, exctype, exc = yield from pi_ld(pi, virt_addr, 8, msr=msr)
410 yield
411 yield ldst.instr_fault.eq(0)
412 while True:
413 done = yield (ldst.done)
414 exc_info = yield from get_exception_info(pi.exc_o)
415 if done or exc_info.happened:
416 break
417 yield
418 assert exc_info.happened == 0 # assert just before doing the fault set zero
419 yield ldst.instr_fault.eq(0)
420 yield
421 yield
422 yield
423
424 print("=== test loadstore instruction (try instruction again) ===")
425 yield from debug(dut, "instr virt retry")
426 # set address to 0x10200, update mem[] to 5678
427 virt_addr = 0x10200
428 real_addr = virt_addr
429 expected_insn = 0x5678
430
431 yield i_in.priv_mode.eq(0)
432 yield i_in.virt_mode.eq(1)
433 yield i_in.req.eq(0)
434 yield i_in.nia.eq(virt_addr)
435 yield i_in.stop_mark.eq(0)
436 yield i_m_in.tlbld.eq(0)
437 yield i_m_in.tlbie.eq(0)
438 yield i_m_in.addr.eq(0)
439 yield i_m_in.pte.eq(0)
440 yield
441 yield
442 yield
443
444 # miss, stalls for a bit
445 """
446 yield i_in.req.eq(1)
447 yield i_in.nia.eq(virt_addr)
448 yield
449 valid = yield i_out.valid
450 failed = yield i_out.fetch_failed
451 while not valid and not failed:
452 yield
453 valid = yield i_out.valid
454 failed = yield i_out.fetch_failed
455 yield i_in.req.eq(0)
456 nia = yield i_out.nia
457 insn = yield i_out.insn
458 """
459
460 ## part 4
461 nia, insn, valid, failed = yield from icache_read(dut,virt_addr,0,1)
462
463 yield from debug(dut, "test done")
464 yield
465 yield
466
467 print ("failed?", "yes" if failed else "no")
468 assert failed == 0
469
470 print ("fetched %x from addr %x" % (insn, nia))
471 assert insn == expected_insn
472
473 wbget.stop = True
474
475
476 def _test_loadstore1_invalid(dut, mem):
477 mmu = dut.submodules.mmu
478 pi = dut.submodules.ldst.pi
479 wbget.stop = False
480
481 print("=== test invalid ===")
482
483 addr = 0
484 msr = MSRSpec(pr=1, dr=0, sf=0) # set problem-state
485 ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr=msr)
486 print("ld_data", ld_data, exctype, exc)
487 assert (exctype == "slow")
488 invalid = exc.invalid
489 assert (invalid == 1)
490
491 print("=== test invalid done ===")
492
493 wbget.stop = True
494
495
496 def _test_loadstore1_microwatt_mmu_bin_test2(dut, mem):
497 mmu = dut.submodules.mmu
498 pi = dut.submodules.ldst.pi
499 ldst = dut.submodules.ldst # to get at DAR (NOT part of PortInterface)
500 wbget.stop = False
501
502 yield mmu.rin.prtbl.eq(0x12000) # set process table
503 yield mmu.rin.pid.eq(0x1) # set PID=1
504 yield
505
506 addr = 0x124108
507 msr = MSRSpec(pr=1, dr=1, sf=1)
508
509 print("=== alignment error (ld) ===")
510
511 ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr=msr)
512 print("ld_data after mmu.bin test2")
513 print(ld_data)
514 assert ld_data == 0x0000000badc0ffee
515 assert exctype is None
516
517 wbget.stop = True
518
519
520 def _test_loadstore1_microwatt_mmu_bin_test5(dut, mem):
521 mmu = dut.submodules.mmu
522 pi = dut.submodules.ldst.pi
523 ldst = dut.submodules.ldst # to get at DAR (NOT part of PortInterface)
524 wbget.stop = False
525
526 yield mmu.rin.prtbl.eq(0x12000) # set process table
527 yield mmu.rin.pid.eq(0x1) # set PID=1
528 yield
529
530 addr = 0x39fffd
531 msr = MSRSpec(pr=1, dr=1, sf=1)
532
533 print("=== page-fault alignment error (ld) ===")
534
535 ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr=msr)
536 print("ld_data after mmu.bin test5")
537 print(ld_data)
538 print (exctype, exc)
539
540 wbget.stop = True
541
542
543 def test_pi_ld_misalign(pi,addr,data_len,msr):
544 for i in range(0,data_len):
545 ld_data, exctype, exc = yield from pi_ld(pi, addr+i, data_len, msr=msr)
546 yield
547 if i == 0:
548 assert exc is None # use "is None" not "== None"
549 print("MISALIGN: test_pi_ld_misalign returned",hex(ld_data))
550 else:
551 assert exc.alignment == 1
552
553
554 def _test_loadstore1_misalign(dut, mem):
555 mmu = dut.submodules.mmu
556 pi = dut.submodules.ldst.pi
557 ldst = dut.submodules.ldst # to get at DAR (NOT part of PortInterface)
558 wbget.stop = False
559
560 yield mmu.rin.prtbl.eq(0x12000) # set process table
561 yield mmu.rin.pid.eq(0x1) # set PID=1
562 #yield
563
564 addr = 1
565 msr = MSRSpec(pr=0, dr=0, sf=1)
566
567 yield from test_pi_ld_misalign(pi,0,8,msr)
568
569 wbget.stop = True
570
571
572 def _test_loadstore1(dut, mem):
573 mmu = dut.submodules.mmu
574 pi = dut.submodules.ldst.pi
575 ldst = dut.submodules.ldst # to get at DAR (NOT part of PortInterface)
576 wbget.stop = False
577
578 yield mmu.rin.prtbl.eq(0x1000000) # set process table
579 yield
580
581 addr = 0x100e0
582 data = 0xf553b658ba7e1f51
583 msr = MSRSpec(pr=0, dr=0, sf=0)
584
585 if test_dcbz:
586 yield from pi_st(pi, addr, data, 8, msr=msr)
587 yield
588
589 ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr=msr)
590 assert ld_data == 0xf553b658ba7e1f51
591 assert exctype is None
592
593 ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr=msr)
594 assert ld_data == 0xf553b658ba7e1f51
595 assert exctype is None
596
597 print("do_dcbz ===============")
598 yield from pi_st(pi, addr, data, 8, msr=msr, is_dcbz=1)
599 print("done_dcbz ===============")
600 yield
601
602 ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr=msr)
603 print("ld_data after dcbz")
604 print(ld_data)
605 assert ld_data == 0
606 assert exctype is None
607
608 if test_exceptions:
609 print("=== alignment error (ld) ===")
610 addr = 0xFF100e0FF
611 ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr=msr)
612 if exc:
613 alignment = exc.alignment
614 happened = exc.happened
615 yield # wait for dsr to update
616 dar = yield ldst.dar
617 else:
618 alignment = 0
619 happened = 0
620 dar = 0
621 assert (happened == 1)
622 assert (alignment == 1)
623 assert (dar == addr)
624 assert (exctype == "fast")
625 yield from wait_busy(pi, debug="pi_ld_E_alignment_error")
626 # wait is only needed in case of in exception here
627 print("=== alignment error test passed (ld) ===")
628
629 # take some cycles in between so that gtkwave separates out
630 # signals
631 yield
632 yield
633 yield
634 yield
635
636 print("=== alignment error (st) ===")
637 addr = 0xFF100e0FF
638 exctype, exc = yield from pi_st(pi, addr,0, 8, msr=msr)
639 if exc:
640 alignment = exc.alignment
641 happened = exc.happened
642 else:
643 alignment = 0
644 happened = 0
645 assert (happened == 1)
646 assert (alignment==1)
647 assert (dar==addr)
648 assert (exctype == "fast")
649 #???? yield from wait_busy(pi, debug="pi_st_E_alignment_error")
650 # wait is only needed in case of in exception here
651 print("=== alignment error test passed (st) ===")
652 yield #FIXME hangs
653
654 if True:
655 print("=== no alignment error (ld) ===")
656 addr = 0x100e0
657 ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr=msr)
658 print("ld_data", ld_data, exctype, exc)
659 if exc:
660 alignment = exc.alignment
661 happened = exc.happened
662 else:
663 alignment = 0
664 happened = 0
665 assert (happened == 0)
666 assert (alignment == 0)
667 print("=== no alignment error done (ld) ===")
668
669 if test_random:
670 addrs = [0x456920,0xa7a180,0x299420,0x1d9d60]
671
672 for addr in addrs:
673 print("== RANDOM addr ==",hex(addr))
674 ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr=msr)
675 print("ld_data[RANDOM]",ld_data,exc,addr)
676 assert (exctype == None)
677
678 for addr in addrs:
679 print("== RANDOM addr ==",hex(addr))
680 exc = yield from pi_st(pi, addr,0xFF*addr, 8, msr=msr)
681 assert (exctype == None)
682
683 # readback written data and compare
684 for addr in addrs:
685 print("== RANDOM addr ==",hex(addr))
686 ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr=msr)
687 print("ld_data[RANDOM_READBACK]",ld_data,exc,addr)
688 assert (exctype == None)
689 assert (ld_data == 0xFF*addr)
690
691 print("== RANDOM addr done ==")
692
693 wbget.stop = True
694
695
696 def _test_loadstore1_ifetch_invalid(dut, mem):
697 mmu = dut.submodules.mmu
698 ldst = dut.submodules.ldst
699 pi = ldst.pi
700 icache = dut.submodules.ldst.icache
701 wbget.stop = False
702
703 print("=== test loadstore instruction (invalid) ===")
704
705 i_in = icache.i_in
706 i_out = icache.i_out
707 i_m_in = icache.m_in
708
709 # first virtual memory test
710
711 print ("set process table")
712 yield from debug(dut, "set prtbl")
713 yield mmu.rin.prtbl.eq(0x1000000) # set process table
714 yield
715
716 yield from debug(dut, "real mem instruction")
717 # set address to zero, update mem[0] to 01234
718 addr = 8
719 expected_insn = 0x1234
720 mem[addr] = expected_insn
721
722 yield i_in.priv_mode.eq(1)
723 yield i_in.req.eq(0)
724 yield i_in.nia.eq(addr)
725 yield i_in.stop_mark.eq(0)
726 yield i_m_in.tlbld.eq(0)
727 yield i_m_in.tlbie.eq(0)
728 yield i_m_in.addr.eq(0)
729 yield i_m_in.pte.eq(0)
730 yield
731 yield
732 yield
733
734 # miss, stalls for a bit
735 yield i_in.req.eq(1)
736 yield i_in.nia.eq(addr)
737 yield
738 valid = yield i_out.valid
739 nia = yield i_out.nia
740 while not valid:
741 yield
742 valid = yield i_out.valid
743 yield i_in.req.eq(0)
744
745 nia = yield i_out.nia
746 insn = yield i_out.insn
747
748 yield
749 yield
750
751 print ("fetched %x from addr %x" % (insn, nia))
752 assert insn == expected_insn
753
754 print("=== test loadstore instruction (virtual) ===")
755 yield from debug(dut, "virtual instr req")
756
757 # look up i-cache expecting it to fail
758
759 # set address to 0x10200, update mem[] to 5678
760 virt_addr = 0x10200
761 real_addr = virt_addr
762 expected_insn = 0x5678
763 mem[real_addr] = expected_insn
764
765 yield i_in.priv_mode.eq(1)
766 yield i_in.virt_mode.eq(1)
767 yield i_in.req.eq(0)
768 yield i_in.nia.eq(virt_addr)
769 yield i_in.stop_mark.eq(0)
770 yield i_m_in.tlbld.eq(0)
771 yield i_m_in.tlbie.eq(0)
772 yield i_m_in.addr.eq(0)
773 yield i_m_in.pte.eq(0)
774 yield
775 yield
776 yield
777
778 # miss, stalls for a bit
779 yield i_in.req.eq(1)
780 yield i_in.nia.eq(virt_addr)
781 yield
782 valid = yield i_out.valid
783 failed = yield i_out.fetch_failed
784 while not valid and not failed:
785 yield
786 valid = yield i_out.valid
787 failed = yield i_out.fetch_failed
788 yield i_in.req.eq(0)
789
790 print ("failed?", "yes" if failed else "no")
791 assert failed == 1
792 yield
793 yield
794
795 print("=== test invalid loadstore instruction (instruction fault) ===")
796
797 yield from debug(dut, "instr fault (perm err expected)")
798 virt_addr = 0x10200
799
800 yield ldst.priv_mode.eq(0)
801 yield ldst.instr_fault.eq(1)
802 yield ldst.maddr.eq(virt_addr)
803 #ld_data, exctype, exc = yield from pi_ld(pi, virt_addr, 8, msr=msr)
804 yield
805 yield ldst.instr_fault.eq(0)
806 while True:
807 done = yield (ldst.done)
808 exc_info = yield from get_exception_info(pi.exc_o)
809 if done or exc_info.happened:
810 break
811 yield
812 assert exc_info.happened == 1 # different here as expected
813
814 # TODO: work out what kind of exception occurred and check it's
815 # the right one. we *expect* it to be a permissions error because
816 # the RPTE leaf node in pagetables.test2 is marked as "non-executable"
817 # but we also expect instr_fault to be set because it is an instruction
818 # (iside) lookup
819 print (" MMU lookup exception type?")
820 for fname in LDSTExceptionTuple._fields:
821 print (" fname %20s %d" % (fname, getattr(exc_info, fname)))
822
823 # ok now printed them out and visually inspected: check them with asserts
824 assert exc_info.instr_fault == 1 # instruction fault (yes!)
825 assert exc_info.perm_error == 1 # permissions (yes!)
826 assert exc_info.rc_error == 0
827 assert exc_info.alignment == 0
828 assert exc_info.invalid == 0
829 assert exc_info.segment_fault == 0
830 assert exc_info.rc_error == 0
831
832 yield from debug(dut, "test done")
833 yield ldst.instr_fault.eq(0)
834 yield
835 yield
836 yield
837
838 wbget.stop = True
839
840
841 def test_loadstore1_ifetch_unit_iface():
842
843 m, cmpi = setup_mmu()
844
845 mem = pagetables.test1
846
847 # set this up before passing to Simulator (which calls elaborate)
848 icache = m.submodules.ldst.icache
849 icache.use_fetch_interface() # this is the function which converts
850 # to FetchUnitInterface. *including*
851 # rewiring the Wishbone Bus to ibus
852
853 # nmigen Simulation
854 sim = Simulator(m)
855 sim.add_clock(1e-6)
856
857 sim.add_sync_process(wrap(_test_loadstore1_ifetch_iface(m, mem)))
858 # add two wb_get processes onto the *same* memory dictionary.
859 # this shouuuld work.... cross-fingers...
860 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
861 sim.add_sync_process(wrap(wb_get(icache.ibus, mem))) # ibus not bus
862 with sim.write_vcd('test_loadstore1_ifetch_iface.vcd',
863 traces=[m.debug_status]): # include extra debug
864 sim.run()
865
866
867 def test_loadstore1_ifetch():
868
869 m, cmpi = setup_mmu()
870
871 mem = pagetables.test1
872
873 # nmigen Simulation
874 sim = Simulator(m)
875 sim.add_clock(1e-6)
876
877 icache = m.submodules.ldst.icache
878 sim.add_sync_process(wrap(_test_loadstore1_ifetch(m, mem)))
879 # add two wb_get processes onto the *same* memory dictionary.
880 # this shouuuld work.... cross-fingers...
881 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
882 sim.add_sync_process(wrap(wb_get(icache.bus, mem)))
883 with sim.write_vcd('test_loadstore1_ifetch.vcd',
884 traces=[m.debug_status]): # include extra debug
885 sim.run()
886
887
888 def test_loadstore1():
889
890 m, cmpi = setup_mmu()
891
892 mem = pagetables.test1
893
894 # nmigen Simulation
895 sim = Simulator(m)
896 sim.add_clock(1e-6)
897
898 sim.add_sync_process(wrap(_test_loadstore1(m, mem)))
899 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
900 with sim.write_vcd('test_loadstore1.vcd'):
901 sim.run()
902
903
904 def test_loadstore1_microwatt_mmu_bin_test2():
905
906 m, cmpi = setup_mmu()
907
908 mem = pagetables.microwatt_test2
909
910 # nmigen Simulation
911 sim = Simulator(m)
912 sim.add_clock(1e-6)
913
914 sim.add_sync_process(wrap(_test_loadstore1_microwatt_mmu_bin_test2(m, mem)))
915 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
916 with sim.write_vcd('test_microwatt_mmu_test2.vcd'):
917 sim.run()
918
919
920 def test_loadstore1_microwatt_mmu_bin_test5():
921
922 m, cmpi = setup_mmu()
923
924 mem = pagetables.microwatt_test5
925
926 # nmigen Simulation
927 sim = Simulator(m)
928 sim.add_clock(1e-6)
929
930 sim.add_sync_process(wrap(_test_loadstore1_microwatt_mmu_bin_test5(m, mem)))
931 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
932 with sim.write_vcd('test_microwatt_mmu_test5.vcd'):
933 sim.run()
934
935
936 def test_loadstore1_misalign():
937
938 m, cmpi = setup_mmu()
939
940 mem = pagetables.microwatt_test2
941
942 # nmigen Simulation
943 sim = Simulator(m)
944 sim.add_clock(1e-6)
945
946 ###########1122334455667788
947 mem[0] = 0x0102030405060708
948
949 sim.add_sync_process(wrap(_test_loadstore1_misalign(m, mem)))
950 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
951 with sim.write_vcd('test_loadstore1_misalign.vcd'):
952 sim.run()
953
954
955 def test_loadstore1_invalid():
956
957 m, cmpi = setup_mmu()
958
959 mem = {}
960
961 # nmigen Simulation
962 sim = Simulator(m)
963 sim.add_clock(1e-6)
964
965 sim.add_sync_process(wrap(_test_loadstore1_invalid(m, mem)))
966 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
967 with sim.write_vcd('test_loadstore1_invalid.vcd'):
968 sim.run()
969
970
971 def test_loadstore1_ifetch_invalid():
972 m, cmpi = setup_mmu()
973
974 # this is a specially-arranged page table which has the permissions
975 # barred for execute on the leaf node (EAA=0x2 instead of EAA=0x3)
976 mem = pagetables.test2
977
978 # nmigen Simulation
979 sim = Simulator(m)
980 sim.add_clock(1e-6)
981
982 icache = m.submodules.ldst.icache
983 sim.add_sync_process(wrap(_test_loadstore1_ifetch_invalid(m, mem)))
984 # add two wb_get processes onto the *same* memory dictionary.
985 # this shouuuld work.... cross-fingers...
986 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
987 sim.add_sync_process(wrap(wb_get(icache.bus, mem)))
988 with sim.write_vcd('test_loadstore1_ifetch_invalid.vcd',
989 traces=[m.debug_status]): # include extra debug
990 sim.run()
991
992
993 def test_loadstore1_ifetch_multi():
994 m, cmpi = setup_mmu()
995 wbget.stop = False
996
997 # this is a specially-arranged page table which has the permissions
998 # barred for execute on the leaf node (EAA=0x2 instead of EAA=0x3)
999 mem = pagetables.test1
1000
1001 # set this up before passing to Simulator (which calls elaborate)
1002 icache = m.submodules.ldst.icache
1003 icache.use_fetch_interface() # this is the function which converts
1004 # to FetchUnitInterface. *including*
1005 # rewiring the Wishbone Bus to ibus
1006
1007 # nmigen Simulation
1008 sim = Simulator(m)
1009 sim.add_clock(1e-6)
1010
1011 sim.add_sync_process(wrap(_test_loadstore1_ifetch_multi(m, mem)))
1012 # add two wb_get processes onto the *same* memory dictionary.
1013 # this shouuuld work.... cross-fingers...
1014 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
1015 sim.add_sync_process(wrap(wb_get(icache.ibus, mem))) # ibus not bus
1016 with sim.write_vcd('test_loadstore1_ifetch_multi.vcd',
1017 traces=[m.debug_status]): # include extra debug
1018 sim.run()
1019
1020 if __name__ == '__main__':
1021 #test_loadstore1()
1022 #test_loadstore1_microwatt_mmu_bin_test2()
1023 test_loadstore1_microwatt_mmu_bin_test5()
1024 #test_loadstore1_invalid()
1025 #test_loadstore1_ifetch() #FIXME
1026 #test_loadstore1_ifetch_invalid()
1027 #test_loadstore1_ifetch_unit_iface() # guess: should be working
1028 #test_loadstore1_ifetch_multi()
1029 #test_loadstore1_misalign()