add mmu.bin test2 to much simpler test_loadstore1.py
[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 def _test_loadstore1_ifetch_multi(dut, mem):
223 mmu = dut.submodules.mmu
224 ldst = dut.submodules.ldst
225 pi = ldst.pi
226 icache = dut.submodules.ldst.icache
227 assert wbget.stop == False
228
229 print ("set process table")
230 yield from debug(dut, "set prtble")
231 yield mmu.rin.prtbl.eq(0x1000000) # set process table
232 yield
233
234 i_in = icache.i_in
235 i_out = icache.i_out
236 i_m_in = icache.m_in
237
238 # fetch instructions from multiple addresses
239 # should cope with some addresses being invalid
240 real_addrs = [0,4,8,0,8,4,0,0,12]
241 write_mem2(mem,0,0xF0,0xF4)
242 write_mem2(mem,8,0xF8,0xFC)
243
244 yield i_in.priv_mode.eq(1)
245 for addr in real_addrs:
246 yield from debug(dut, "real_addr "+hex(addr))
247 insn = yield from read_from_addr(icache, addr, stall=False)
248 nia = yield i_out.nia # NO, must use FetchUnitInterface
249 print ("TEST_MULTI: fetched %x from addr %x == %x" % (insn, nia,addr))
250 assert insn==0xF0+addr
251
252 # now with virtual memory enabled
253 yield i_in.virt_mode.eq(1)
254
255 virt_addrs = [0x10200,0x10204,0x10208,0x10200,
256 0x102008,0x10204,0x10200,0x10200,0x10200C]
257
258 write_mem2(mem,0x10200,0xF8,0xFC)
259
260 for addr in virt_addrs:
261 yield from debug(dut, "virt_addr "+hex(addr))
262
263 valid, failed = yield from lookup_virt(dut,addr)
264 yield
265 print("TEST_MULTI: failed=",failed) # this is reported wrong
266 if failed==1: # test one first
267 yield from mmu_lookup(dut,addr)
268 valid, failed = yield from lookup_virt(dut,addr)
269 assert(valid==1)
270
271 wbget.stop = True
272
273
274 def _test_loadstore1_ifetch(dut, mem):
275 """test_loadstore1_ifetch
276
277 this is quite a complex multi-step test.
278
279 * first (just because, as a demo) read in priv mode, non-virtual.
280 just like in experiment/icache.py itself.
281
282 * second, using the (usual) PTE for these things (which came originally
283 from gem5-experimental experiment/radix_walk_example.txt) do a
284 virtual-memory read through the *instruction* cache.
285 this is expected to FAIL
286
287 * third: mess about with the MMU, setting "iside" (instruction-side),
288 requesting an MMU RADIX LOOKUP. this triggers an itlb_load
289 (instruction-cache TLB entry-insertion)
290
291 * fourth and finally: retry the read of the instruction through i-cache.
292 this is now expected to SUCCEED
293
294 a lot going on.
295 """
296
297 mmu = dut.submodules.mmu
298 ldst = dut.submodules.ldst
299 pi = ldst.pi
300 icache = dut.submodules.ldst.icache
301 wbget.stop = False
302
303 print("=== test loadstore instruction (real) ===")
304
305 i_in = icache.i_in
306 i_out = icache.i_out
307 i_m_in = icache.m_in
308
309 # first virtual memory test
310
311 print ("set process table")
312 yield from debug(dut, "set prtble")
313 yield mmu.rin.prtbl.eq(0x1000000) # set process table
314 yield
315
316 yield from debug(dut, "real mem instruction")
317 # set address to zero, update mem[0] to 01234
318 addr = 8
319 expected_insn = 0x1234
320 mem[addr] = expected_insn
321
322 yield i_in.priv_mode.eq(1)
323 yield i_in.req.eq(0)
324 yield i_in.nia.eq(addr)
325 yield i_in.stop_mark.eq(0)
326 yield i_m_in.tlbld.eq(0)
327 yield i_m_in.tlbie.eq(0)
328 yield i_m_in.addr.eq(0)
329 yield i_m_in.pte.eq(0)
330 yield
331 yield
332 yield
333
334 # miss, stalls for a bit -- this one is different here
335 ##nia, insn, valid, failed = yield from icache_read(dut,addr,0,0)
336 ##assert(valid==0)
337 ##assert(failed==1)
338
339 yield i_in.req.eq(1)
340 yield i_in.nia.eq(addr)
341 yield
342 valid = yield i_out.valid
343 while not valid:
344 yield
345 valid = yield i_out.valid
346 yield i_in.req.eq(0)
347
348 nia = yield i_out.nia
349 insn = yield i_out.insn
350 yield
351 yield
352
353 print ("fetched %x from addr %x" % (insn, nia))
354 assert insn == expected_insn
355
356 print("=== test loadstore instruction (virtual) ===")
357
358 # look up i-cache expecting it to fail
359
360 yield from debug(dut, "virtual instr req")
361 # set address to 0x10200, update mem[] to 5678
362 virt_addr = 0x10200
363 real_addr = virt_addr
364 expected_insn = 0x5678
365 mem[real_addr] = expected_insn
366
367 yield i_in.priv_mode.eq(0)
368 yield i_in.virt_mode.eq(1)
369 yield i_in.req.eq(0)
370 yield i_in.nia.eq(virt_addr)
371 yield i_in.stop_mark.eq(0)
372 yield i_m_in.tlbld.eq(0)
373 yield i_m_in.tlbie.eq(0)
374 yield i_m_in.addr.eq(0)
375 yield i_m_in.pte.eq(0)
376 yield
377 yield
378 yield
379
380 # miss, stalls for a bit
381 yield i_in.req.eq(1)
382 yield i_in.nia.eq(virt_addr)
383 yield
384 valid = yield i_out.valid
385 failed = yield i_out.fetch_failed
386 while not valid and not failed:
387 yield
388 valid = yield i_out.valid
389 failed = yield i_out.fetch_failed
390 yield i_in.req.eq(0)
391
392 print ("failed?", "yes" if failed else "no")
393 assert failed == 1
394 yield
395 yield
396
397 print("=== test loadstore instruction (instruction fault) ===")
398
399 yield from debug(dut, "instr fault")
400
401 virt_addr = 0x10200
402
403 yield ldst.priv_mode.eq(0)
404 yield ldst.instr_fault.eq(1)
405 yield ldst.maddr.eq(virt_addr)
406 # still broken -- investigate
407 # msr = MSRSpec(pr=?, dr=?, sf=0)
408 # ld_data, exctype, exc = yield from pi_ld(pi, virt_addr, 8, msr=msr)
409 yield
410 yield ldst.instr_fault.eq(0)
411 while True:
412 done = yield (ldst.done)
413 exc_info = yield from get_exception_info(pi.exc_o)
414 if done or exc_info.happened:
415 break
416 yield
417 assert exc_info.happened == 0 # assert just before doing the fault set zero
418 yield ldst.instr_fault.eq(0)
419 yield
420 yield
421 yield
422
423 print("=== test loadstore instruction (try instruction again) ===")
424 yield from debug(dut, "instr virt retry")
425 # set address to 0x10200, update mem[] to 5678
426 virt_addr = 0x10200
427 real_addr = virt_addr
428 expected_insn = 0x5678
429
430 yield i_in.priv_mode.eq(0)
431 yield i_in.virt_mode.eq(1)
432 yield i_in.req.eq(0)
433 yield i_in.nia.eq(virt_addr)
434 yield i_in.stop_mark.eq(0)
435 yield i_m_in.tlbld.eq(0)
436 yield i_m_in.tlbie.eq(0)
437 yield i_m_in.addr.eq(0)
438 yield i_m_in.pte.eq(0)
439 yield
440 yield
441 yield
442
443 # miss, stalls for a bit
444 """
445 yield i_in.req.eq(1)
446 yield i_in.nia.eq(virt_addr)
447 yield
448 valid = yield i_out.valid
449 failed = yield i_out.fetch_failed
450 while not valid and not failed:
451 yield
452 valid = yield i_out.valid
453 failed = yield i_out.fetch_failed
454 yield i_in.req.eq(0)
455 nia = yield i_out.nia
456 insn = yield i_out.insn
457 """
458
459 ## part 4
460 nia, insn, valid, failed = yield from icache_read(dut,virt_addr,0,1)
461
462 yield from debug(dut, "test done")
463 yield
464 yield
465
466 print ("failed?", "yes" if failed else "no")
467 assert failed == 0
468
469 print ("fetched %x from addr %x" % (insn, nia))
470 assert insn == expected_insn
471
472 wbget.stop = True
473
474
475 def _test_loadstore1_invalid(dut, mem):
476 mmu = dut.submodules.mmu
477 pi = dut.submodules.ldst.pi
478 wbget.stop = False
479
480 print("=== test invalid ===")
481
482 addr = 0
483 msr = MSRSpec(pr=1, dr=0, sf=0) # set problem-state
484 ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr=msr)
485 print("ld_data", ld_data, exctype, exc)
486 assert (exctype == "slow")
487 invalid = exc.invalid
488 assert (invalid == 1)
489
490 print("=== test invalid done ===")
491
492 wbget.stop = True
493
494
495 def _test_loadstore1_microwatt_mmu_bin_test2(dut, mem):
496 mmu = dut.submodules.mmu
497 pi = dut.submodules.ldst.pi
498 ldst = dut.submodules.ldst # to get at DAR (NOT part of PortInterface)
499 wbget.stop = False
500
501 yield mmu.rin.prtbl.eq(0x12000) # set process table
502 yield mmu.rin.pid.eq(0x1) # set PID=1
503 yield
504
505 addr = 0x124108
506 msr = MSRSpec(pr=1, dr=1, sf=1)
507
508 print("=== alignment error (ld) ===")
509
510 ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr=msr)
511 print("ld_data after mmu.bin test2")
512 print(ld_data)
513 assert ld_data == 0x0000000badc0ffee
514 assert exctype is None
515
516 wbget.stop = True
517
518
519 def _test_loadstore1(dut, mem):
520 mmu = dut.submodules.mmu
521 pi = dut.submodules.ldst.pi
522 ldst = dut.submodules.ldst # to get at DAR (NOT part of PortInterface)
523 wbget.stop = False
524
525 yield mmu.rin.prtbl.eq(0x1000000) # set process table
526 yield
527
528 addr = 0x100e0
529 data = 0xf553b658ba7e1f51
530 msr = MSRSpec(pr=0, dr=0, sf=0)
531
532 if test_dcbz:
533 yield from pi_st(pi, addr, data, 8, msr=msr)
534 yield
535
536 ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr=msr)
537 assert ld_data == 0xf553b658ba7e1f51
538 assert exctype is None
539
540 ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr=msr)
541 assert ld_data == 0xf553b658ba7e1f51
542 assert exctype is None
543
544 print("do_dcbz ===============")
545 yield from pi_st(pi, addr, data, 8, msr=msr, is_dcbz=1)
546 print("done_dcbz ===============")
547 yield
548
549 ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr=msr)
550 print("ld_data after dcbz")
551 print(ld_data)
552 assert ld_data == 0
553 assert exctype is None
554
555 if test_exceptions:
556 print("=== alignment error (ld) ===")
557 addr = 0xFF100e0FF
558 ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr=msr)
559 if exc:
560 alignment = exc.alignment
561 happened = exc.happened
562 yield # wait for dsr to update
563 dar = yield ldst.dar
564 else:
565 alignment = 0
566 happened = 0
567 dar = 0
568 assert (happened == 1)
569 assert (alignment == 1)
570 assert (dar == addr)
571 assert (exctype == "fast")
572 yield from wait_busy(pi, debug="pi_ld_E_alignment_error")
573 # wait is only needed in case of in exception here
574 print("=== alignment error test passed (ld) ===")
575
576 # take some cycles in between so that gtkwave separates out
577 # signals
578 yield
579 yield
580 yield
581 yield
582
583 print("=== alignment error (st) ===")
584 addr = 0xFF100e0FF
585 exctype, exc = yield from pi_st(pi, addr,0, 8, msr=msr)
586 if exc:
587 alignment = exc.alignment
588 happened = exc.happened
589 else:
590 alignment = 0
591 happened = 0
592 assert (happened == 1)
593 assert (alignment==1)
594 assert (dar==addr)
595 assert (exctype == "fast")
596 #???? yield from wait_busy(pi, debug="pi_st_E_alignment_error")
597 # wait is only needed in case of in exception here
598 print("=== alignment error test passed (st) ===")
599 yield #FIXME hangs
600
601 if True:
602 print("=== no alignment error (ld) ===")
603 addr = 0x100e0
604 ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr=msr)
605 print("ld_data", ld_data, exctype, exc)
606 if exc:
607 alignment = exc.alignment
608 happened = exc.happened
609 else:
610 alignment = 0
611 happened = 0
612 assert (happened == 0)
613 assert (alignment == 0)
614 print("=== no alignment error done (ld) ===")
615
616 if test_random:
617 addrs = [0x456920,0xa7a180,0x299420,0x1d9d60]
618
619 for addr in addrs:
620 print("== RANDOM addr ==",hex(addr))
621 ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr=msr)
622 print("ld_data[RANDOM]",ld_data,exc,addr)
623 assert (exctype == None)
624
625 for addr in addrs:
626 print("== RANDOM addr ==",hex(addr))
627 exc = yield from pi_st(pi, addr,0xFF*addr, 8, msr=msr)
628 assert (exctype == None)
629
630 # readback written data and compare
631 for addr in addrs:
632 print("== RANDOM addr ==",hex(addr))
633 ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr=msr)
634 print("ld_data[RANDOM_READBACK]",ld_data,exc,addr)
635 assert (exctype == None)
636 assert (ld_data == 0xFF*addr)
637
638 print("== RANDOM addr done ==")
639
640 wbget.stop = True
641
642
643 def _test_loadstore1_ifetch_invalid(dut, mem):
644 mmu = dut.submodules.mmu
645 ldst = dut.submodules.ldst
646 pi = ldst.pi
647 icache = dut.submodules.ldst.icache
648 wbget.stop = False
649
650 print("=== test loadstore instruction (invalid) ===")
651
652 i_in = icache.i_in
653 i_out = icache.i_out
654 i_m_in = icache.m_in
655
656 # first virtual memory test
657
658 print ("set process table")
659 yield from debug(dut, "set prtbl")
660 yield mmu.rin.prtbl.eq(0x1000000) # set process table
661 yield
662
663 yield from debug(dut, "real mem instruction")
664 # set address to zero, update mem[0] to 01234
665 addr = 8
666 expected_insn = 0x1234
667 mem[addr] = expected_insn
668
669 yield i_in.priv_mode.eq(1)
670 yield i_in.req.eq(0)
671 yield i_in.nia.eq(addr)
672 yield i_in.stop_mark.eq(0)
673 yield i_m_in.tlbld.eq(0)
674 yield i_m_in.tlbie.eq(0)
675 yield i_m_in.addr.eq(0)
676 yield i_m_in.pte.eq(0)
677 yield
678 yield
679 yield
680
681 # miss, stalls for a bit
682 yield i_in.req.eq(1)
683 yield i_in.nia.eq(addr)
684 yield
685 valid = yield i_out.valid
686 nia = yield i_out.nia
687 while not valid:
688 yield
689 valid = yield i_out.valid
690 yield i_in.req.eq(0)
691
692 nia = yield i_out.nia
693 insn = yield i_out.insn
694
695 yield
696 yield
697
698 print ("fetched %x from addr %x" % (insn, nia))
699 assert insn == expected_insn
700
701 print("=== test loadstore instruction (virtual) ===")
702 yield from debug(dut, "virtual instr req")
703
704 # look up i-cache expecting it to fail
705
706 # set address to 0x10200, update mem[] to 5678
707 virt_addr = 0x10200
708 real_addr = virt_addr
709 expected_insn = 0x5678
710 mem[real_addr] = expected_insn
711
712 yield i_in.priv_mode.eq(1)
713 yield i_in.virt_mode.eq(1)
714 yield i_in.req.eq(0)
715 yield i_in.nia.eq(virt_addr)
716 yield i_in.stop_mark.eq(0)
717 yield i_m_in.tlbld.eq(0)
718 yield i_m_in.tlbie.eq(0)
719 yield i_m_in.addr.eq(0)
720 yield i_m_in.pte.eq(0)
721 yield
722 yield
723 yield
724
725 # miss, stalls for a bit
726 yield i_in.req.eq(1)
727 yield i_in.nia.eq(virt_addr)
728 yield
729 valid = yield i_out.valid
730 failed = yield i_out.fetch_failed
731 while not valid and not failed:
732 yield
733 valid = yield i_out.valid
734 failed = yield i_out.fetch_failed
735 yield i_in.req.eq(0)
736
737 print ("failed?", "yes" if failed else "no")
738 assert failed == 1
739 yield
740 yield
741
742 print("=== test invalid loadstore instruction (instruction fault) ===")
743
744 yield from debug(dut, "instr fault (perm err expected)")
745 virt_addr = 0x10200
746
747 yield ldst.priv_mode.eq(0)
748 yield ldst.instr_fault.eq(1)
749 yield ldst.maddr.eq(virt_addr)
750 #ld_data, exctype, exc = yield from pi_ld(pi, virt_addr, 8, msr=msr)
751 yield
752 yield ldst.instr_fault.eq(0)
753 while True:
754 done = yield (ldst.done)
755 exc_info = yield from get_exception_info(pi.exc_o)
756 if done or exc_info.happened:
757 break
758 yield
759 assert exc_info.happened == 1 # different here as expected
760
761 # TODO: work out what kind of exception occurred and check it's
762 # the right one. we *expect* it to be a permissions error because
763 # the RPTE leaf node in pagetables.test2 is marked as "non-executable"
764 # but we also expect instr_fault to be set because it is an instruction
765 # (iside) lookup
766 print (" MMU lookup exception type?")
767 for fname in LDSTExceptionTuple._fields:
768 print (" fname %20s %d" % (fname, getattr(exc_info, fname)))
769
770 # ok now printed them out and visually inspected: check them with asserts
771 assert exc_info.instr_fault == 1 # instruction fault (yes!)
772 assert exc_info.perm_error == 1 # permissions (yes!)
773 assert exc_info.rc_error == 0
774 assert exc_info.alignment == 0
775 assert exc_info.invalid == 0
776 assert exc_info.segment_fault == 0
777 assert exc_info.rc_error == 0
778
779 yield from debug(dut, "test done")
780 yield ldst.instr_fault.eq(0)
781 yield
782 yield
783 yield
784
785 wbget.stop = True
786
787
788 def test_loadstore1_ifetch_unit_iface():
789
790 m, cmpi = setup_mmu()
791
792 mem = pagetables.test1
793
794 # set this up before passing to Simulator (which calls elaborate)
795 icache = m.submodules.ldst.icache
796 icache.use_fetch_interface() # this is the function which converts
797 # to FetchUnitInterface. *including*
798 # rewiring the Wishbone Bus to ibus
799
800 # nmigen Simulation
801 sim = Simulator(m)
802 sim.add_clock(1e-6)
803
804 sim.add_sync_process(wrap(_test_loadstore1_ifetch_iface(m, mem)))
805 # add two wb_get processes onto the *same* memory dictionary.
806 # this shouuuld work.... cross-fingers...
807 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
808 sim.add_sync_process(wrap(wb_get(icache.ibus, mem))) # ibus not bus
809 with sim.write_vcd('test_loadstore1_ifetch_iface.vcd',
810 traces=[m.debug_status]): # include extra debug
811 sim.run()
812
813
814 def test_loadstore1_ifetch():
815
816 m, cmpi = setup_mmu()
817
818 mem = pagetables.test1
819
820 # nmigen Simulation
821 sim = Simulator(m)
822 sim.add_clock(1e-6)
823
824 icache = m.submodules.ldst.icache
825 sim.add_sync_process(wrap(_test_loadstore1_ifetch(m, mem)))
826 # add two wb_get processes onto the *same* memory dictionary.
827 # this shouuuld work.... cross-fingers...
828 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
829 sim.add_sync_process(wrap(wb_get(icache.bus, mem)))
830 with sim.write_vcd('test_loadstore1_ifetch.vcd',
831 traces=[m.debug_status]): # include extra debug
832 sim.run()
833
834
835 def test_loadstore1():
836
837 m, cmpi = setup_mmu()
838
839 mem = pagetables.test1
840
841 # nmigen Simulation
842 sim = Simulator(m)
843 sim.add_clock(1e-6)
844
845 sim.add_sync_process(wrap(_test_loadstore1(m, mem)))
846 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
847 with sim.write_vcd('test_loadstore1.vcd'):
848 sim.run()
849
850
851 def test_loadstore1_microwatt_mmu_bin_test2():
852
853 m, cmpi = setup_mmu()
854
855 mem = pagetables.microwatt_test2
856
857 # nmigen Simulation
858 sim = Simulator(m)
859 sim.add_clock(1e-6)
860
861 sim.add_sync_process(wrap(_test_loadstore1_microwatt_mmu_bin_test2(m, mem)))
862 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
863 with sim.write_vcd('test_loadstore1.vcd'):
864 sim.run()
865
866
867 def test_loadstore1_invalid():
868
869 m, cmpi = setup_mmu()
870
871 mem = {}
872
873 # nmigen Simulation
874 sim = Simulator(m)
875 sim.add_clock(1e-6)
876
877 sim.add_sync_process(wrap(_test_loadstore1_invalid(m, mem)))
878 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
879 with sim.write_vcd('test_loadstore1_invalid.vcd'):
880 sim.run()
881
882 def test_loadstore1_ifetch_invalid():
883 m, cmpi = setup_mmu()
884
885 # this is a specially-arranged page table which has the permissions
886 # barred for execute on the leaf node (EAA=0x2 instead of EAA=0x3)
887 mem = pagetables.test2
888
889 # nmigen Simulation
890 sim = Simulator(m)
891 sim.add_clock(1e-6)
892
893 icache = m.submodules.ldst.icache
894 sim.add_sync_process(wrap(_test_loadstore1_ifetch_invalid(m, mem)))
895 # add two wb_get processes onto the *same* memory dictionary.
896 # this shouuuld work.... cross-fingers...
897 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
898 sim.add_sync_process(wrap(wb_get(icache.bus, mem)))
899 with sim.write_vcd('test_loadstore1_ifetch_invalid.vcd',
900 traces=[m.debug_status]): # include extra debug
901 sim.run()
902
903 def test_loadstore1_ifetch_multi():
904 m, cmpi = setup_mmu()
905 wbget.stop = False
906
907 # this is a specially-arranged page table which has the permissions
908 # barred for execute on the leaf node (EAA=0x2 instead of EAA=0x3)
909 mem = pagetables.test1
910
911 # set this up before passing to Simulator (which calls elaborate)
912 icache = m.submodules.ldst.icache
913 icache.use_fetch_interface() # this is the function which converts
914 # to FetchUnitInterface. *including*
915 # rewiring the Wishbone Bus to ibus
916
917 # nmigen Simulation
918 sim = Simulator(m)
919 sim.add_clock(1e-6)
920
921 sim.add_sync_process(wrap(_test_loadstore1_ifetch_multi(m, mem)))
922 # add two wb_get processes onto the *same* memory dictionary.
923 # this shouuuld work.... cross-fingers...
924 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
925 sim.add_sync_process(wrap(wb_get(icache.ibus, mem))) # ibus not bus
926 with sim.write_vcd('test_loadstore1_ifetch_multi.vcd',
927 traces=[m.debug_status]): # include extra debug
928 sim.run()
929
930 if __name__ == '__main__':
931 #test_loadstore1()
932 test_loadstore1_microwatt_mmu_bin_test2()
933 #test_loadstore1_invalid()
934 #test_loadstore1_ifetch() #FIXME
935 #test_loadstore1_ifetch_invalid()
936 #test_loadstore1_ifetch_unit_iface() # guess: should be working
937 #test_loadstore1_ifetch_multi()