b418b8841feef5978821a24136f8ad3def8e5bb6
[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(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(0x1000000) # set process table
527 yield
528
529 addr = 0x100e0
530 data = 0xf553b658ba7e1f51
531 msr = MSRSpec(pr=0, dr=0, sf=0)
532
533 if test_dcbz:
534 yield from pi_st(pi, addr, data, 8, msr=msr)
535 yield
536
537 ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr=msr)
538 assert ld_data == 0xf553b658ba7e1f51
539 assert exctype is None
540
541 ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr=msr)
542 assert ld_data == 0xf553b658ba7e1f51
543 assert exctype is None
544
545 print("do_dcbz ===============")
546 yield from pi_st(pi, addr, data, 8, msr=msr, is_dcbz=1)
547 print("done_dcbz ===============")
548 yield
549
550 ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr=msr)
551 print("ld_data after dcbz")
552 print(ld_data)
553 assert ld_data == 0
554 assert exctype is None
555
556 if test_exceptions:
557 print("=== alignment error (ld) ===")
558 addr = 0xFF100e0FF
559 ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr=msr)
560 if exc:
561 alignment = exc.alignment
562 happened = exc.happened
563 yield # wait for dsr to update
564 dar = yield ldst.dar
565 else:
566 alignment = 0
567 happened = 0
568 dar = 0
569 assert (happened == 1)
570 assert (alignment == 1)
571 assert (dar == addr)
572 assert (exctype == "fast")
573 yield from wait_busy(pi, debug="pi_ld_E_alignment_error")
574 # wait is only needed in case of in exception here
575 print("=== alignment error test passed (ld) ===")
576
577 # take some cycles in between so that gtkwave separates out
578 # signals
579 yield
580 yield
581 yield
582 yield
583
584 print("=== alignment error (st) ===")
585 addr = 0xFF100e0FF
586 exctype, exc = yield from pi_st(pi, addr,0, 8, msr=msr)
587 if exc:
588 alignment = exc.alignment
589 happened = exc.happened
590 else:
591 alignment = 0
592 happened = 0
593 assert (happened == 1)
594 assert (alignment==1)
595 assert (dar==addr)
596 assert (exctype == "fast")
597 #???? yield from wait_busy(pi, debug="pi_st_E_alignment_error")
598 # wait is only needed in case of in exception here
599 print("=== alignment error test passed (st) ===")
600 yield #FIXME hangs
601
602 if True:
603 print("=== no alignment error (ld) ===")
604 addr = 0x100e0
605 ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr=msr)
606 print("ld_data", ld_data, exctype, exc)
607 if exc:
608 alignment = exc.alignment
609 happened = exc.happened
610 else:
611 alignment = 0
612 happened = 0
613 assert (happened == 0)
614 assert (alignment == 0)
615 print("=== no alignment error done (ld) ===")
616
617 if test_random:
618 addrs = [0x456920,0xa7a180,0x299420,0x1d9d60]
619
620 for addr in addrs:
621 print("== RANDOM addr ==",hex(addr))
622 ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr=msr)
623 print("ld_data[RANDOM]",ld_data,exc,addr)
624 assert (exctype == None)
625
626 for addr in addrs:
627 print("== RANDOM addr ==",hex(addr))
628 exc = yield from pi_st(pi, addr,0xFF*addr, 8, msr=msr)
629 assert (exctype == None)
630
631 # readback written data and compare
632 for addr in addrs:
633 print("== RANDOM addr ==",hex(addr))
634 ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr=msr)
635 print("ld_data[RANDOM_READBACK]",ld_data,exc,addr)
636 assert (exctype == None)
637 assert (ld_data == 0xFF*addr)
638
639 print("== RANDOM addr done ==")
640
641 wbget.stop = True
642
643
644 def _test_loadstore1_ifetch_invalid(dut, mem):
645 mmu = dut.submodules.mmu
646 ldst = dut.submodules.ldst
647 pi = ldst.pi
648 icache = dut.submodules.ldst.icache
649 wbget.stop = False
650
651 print("=== test loadstore instruction (invalid) ===")
652
653 i_in = icache.i_in
654 i_out = icache.i_out
655 i_m_in = icache.m_in
656
657 # first virtual memory test
658
659 print ("set process table")
660 yield from debug(dut, "set prtbl")
661 yield mmu.rin.prtbl.eq(0x1000000) # set process table
662 yield
663
664 yield from debug(dut, "real mem instruction")
665 # set address to zero, update mem[0] to 01234
666 addr = 8
667 expected_insn = 0x1234
668 mem[addr] = expected_insn
669
670 yield i_in.priv_mode.eq(1)
671 yield i_in.req.eq(0)
672 yield i_in.nia.eq(addr)
673 yield i_in.stop_mark.eq(0)
674 yield i_m_in.tlbld.eq(0)
675 yield i_m_in.tlbie.eq(0)
676 yield i_m_in.addr.eq(0)
677 yield i_m_in.pte.eq(0)
678 yield
679 yield
680 yield
681
682 # miss, stalls for a bit
683 yield i_in.req.eq(1)
684 yield i_in.nia.eq(addr)
685 yield
686 valid = yield i_out.valid
687 nia = yield i_out.nia
688 while not valid:
689 yield
690 valid = yield i_out.valid
691 yield i_in.req.eq(0)
692
693 nia = yield i_out.nia
694 insn = yield i_out.insn
695
696 yield
697 yield
698
699 print ("fetched %x from addr %x" % (insn, nia))
700 assert insn == expected_insn
701
702 print("=== test loadstore instruction (virtual) ===")
703 yield from debug(dut, "virtual instr req")
704
705 # look up i-cache expecting it to fail
706
707 # set address to 0x10200, update mem[] to 5678
708 virt_addr = 0x10200
709 real_addr = virt_addr
710 expected_insn = 0x5678
711 mem[real_addr] = expected_insn
712
713 yield i_in.priv_mode.eq(1)
714 yield i_in.virt_mode.eq(1)
715 yield i_in.req.eq(0)
716 yield i_in.nia.eq(virt_addr)
717 yield i_in.stop_mark.eq(0)
718 yield i_m_in.tlbld.eq(0)
719 yield i_m_in.tlbie.eq(0)
720 yield i_m_in.addr.eq(0)
721 yield i_m_in.pte.eq(0)
722 yield
723 yield
724 yield
725
726 # miss, stalls for a bit
727 yield i_in.req.eq(1)
728 yield i_in.nia.eq(virt_addr)
729 yield
730 valid = yield i_out.valid
731 failed = yield i_out.fetch_failed
732 while not valid and not failed:
733 yield
734 valid = yield i_out.valid
735 failed = yield i_out.fetch_failed
736 yield i_in.req.eq(0)
737
738 print ("failed?", "yes" if failed else "no")
739 assert failed == 1
740 yield
741 yield
742
743 print("=== test invalid loadstore instruction (instruction fault) ===")
744
745 yield from debug(dut, "instr fault (perm err expected)")
746 virt_addr = 0x10200
747
748 yield ldst.priv_mode.eq(0)
749 yield ldst.instr_fault.eq(1)
750 yield ldst.maddr.eq(virt_addr)
751 #ld_data, exctype, exc = yield from pi_ld(pi, virt_addr, 8, msr=msr)
752 yield
753 yield ldst.instr_fault.eq(0)
754 while True:
755 done = yield (ldst.done)
756 exc_info = yield from get_exception_info(pi.exc_o)
757 if done or exc_info.happened:
758 break
759 yield
760 assert exc_info.happened == 1 # different here as expected
761
762 # TODO: work out what kind of exception occurred and check it's
763 # the right one. we *expect* it to be a permissions error because
764 # the RPTE leaf node in pagetables.test2 is marked as "non-executable"
765 # but we also expect instr_fault to be set because it is an instruction
766 # (iside) lookup
767 print (" MMU lookup exception type?")
768 for fname in LDSTExceptionTuple._fields:
769 print (" fname %20s %d" % (fname, getattr(exc_info, fname)))
770
771 # ok now printed them out and visually inspected: check them with asserts
772 assert exc_info.instr_fault == 1 # instruction fault (yes!)
773 assert exc_info.perm_error == 1 # permissions (yes!)
774 assert exc_info.rc_error == 0
775 assert exc_info.alignment == 0
776 assert exc_info.invalid == 0
777 assert exc_info.segment_fault == 0
778 assert exc_info.rc_error == 0
779
780 yield from debug(dut, "test done")
781 yield ldst.instr_fault.eq(0)
782 yield
783 yield
784 yield
785
786 wbget.stop = True
787
788
789 def test_loadstore1_ifetch_unit_iface():
790
791 m, cmpi = setup_mmu()
792
793 mem = pagetables.test1
794
795 # set this up before passing to Simulator (which calls elaborate)
796 icache = m.submodules.ldst.icache
797 icache.use_fetch_interface() # this is the function which converts
798 # to FetchUnitInterface. *including*
799 # rewiring the Wishbone Bus to ibus
800
801 # nmigen Simulation
802 sim = Simulator(m)
803 sim.add_clock(1e-6)
804
805 sim.add_sync_process(wrap(_test_loadstore1_ifetch_iface(m, mem)))
806 # add two wb_get processes onto the *same* memory dictionary.
807 # this shouuuld work.... cross-fingers...
808 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
809 sim.add_sync_process(wrap(wb_get(icache.ibus, mem))) # ibus not bus
810 with sim.write_vcd('test_loadstore1_ifetch_iface.vcd',
811 traces=[m.debug_status]): # include extra debug
812 sim.run()
813
814
815 def test_loadstore1_ifetch():
816
817 m, cmpi = setup_mmu()
818
819 mem = pagetables.test1
820
821 # nmigen Simulation
822 sim = Simulator(m)
823 sim.add_clock(1e-6)
824
825 icache = m.submodules.ldst.icache
826 sim.add_sync_process(wrap(_test_loadstore1_ifetch(m, mem)))
827 # add two wb_get processes onto the *same* memory dictionary.
828 # this shouuuld work.... cross-fingers...
829 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
830 sim.add_sync_process(wrap(wb_get(icache.bus, mem)))
831 with sim.write_vcd('test_loadstore1_ifetch.vcd',
832 traces=[m.debug_status]): # include extra debug
833 sim.run()
834
835
836 def test_loadstore1():
837
838 m, cmpi = setup_mmu()
839
840 mem = pagetables.test1
841
842 # nmigen Simulation
843 sim = Simulator(m)
844 sim.add_clock(1e-6)
845
846 sim.add_sync_process(wrap(_test_loadstore1(m, mem)))
847 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
848 with sim.write_vcd('test_loadstore1.vcd'):
849 sim.run()
850
851
852 def test_loadstore1_microwatt_mmu_bin_test2():
853
854 m, cmpi = setup_mmu()
855
856 mem = pagetables.microwatt_test2
857
858 # nmigen Simulation
859 sim = Simulator(m)
860 sim.add_clock(1e-6)
861
862 sim.add_sync_process(wrap(_test_loadstore1_microwatt_mmu_bin_test2(m, mem)))
863 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
864 with sim.write_vcd('test_loadstore1.vcd'):
865 sim.run()
866
867
868 def test_loadstore1_invalid():
869
870 m, cmpi = setup_mmu()
871
872 mem = {}
873
874 # nmigen Simulation
875 sim = Simulator(m)
876 sim.add_clock(1e-6)
877
878 sim.add_sync_process(wrap(_test_loadstore1_invalid(m, mem)))
879 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
880 with sim.write_vcd('test_loadstore1_invalid.vcd'):
881 sim.run()
882
883
884 def test_loadstore1_ifetch_invalid():
885 m, cmpi = setup_mmu()
886
887 # this is a specially-arranged page table which has the permissions
888 # barred for execute on the leaf node (EAA=0x2 instead of EAA=0x3)
889 mem = pagetables.test2
890
891 # nmigen Simulation
892 sim = Simulator(m)
893 sim.add_clock(1e-6)
894
895 icache = m.submodules.ldst.icache
896 sim.add_sync_process(wrap(_test_loadstore1_ifetch_invalid(m, mem)))
897 # add two wb_get processes onto the *same* memory dictionary.
898 # this shouuuld work.... cross-fingers...
899 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
900 sim.add_sync_process(wrap(wb_get(icache.bus, mem)))
901 with sim.write_vcd('test_loadstore1_ifetch_invalid.vcd',
902 traces=[m.debug_status]): # include extra debug
903 sim.run()
904
905
906 def test_loadstore1_ifetch_multi():
907 m, cmpi = setup_mmu()
908 wbget.stop = False
909
910 # this is a specially-arranged page table which has the permissions
911 # barred for execute on the leaf node (EAA=0x2 instead of EAA=0x3)
912 mem = pagetables.test1
913
914 # set this up before passing to Simulator (which calls elaborate)
915 icache = m.submodules.ldst.icache
916 icache.use_fetch_interface() # this is the function which converts
917 # to FetchUnitInterface. *including*
918 # rewiring the Wishbone Bus to ibus
919
920 # nmigen Simulation
921 sim = Simulator(m)
922 sim.add_clock(1e-6)
923
924 sim.add_sync_process(wrap(_test_loadstore1_ifetch_multi(m, mem)))
925 # add two wb_get processes onto the *same* memory dictionary.
926 # this shouuuld work.... cross-fingers...
927 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
928 sim.add_sync_process(wrap(wb_get(icache.ibus, mem))) # ibus not bus
929 with sim.write_vcd('test_loadstore1_ifetch_multi.vcd',
930 traces=[m.debug_status]): # include extra debug
931 sim.run()
932
933 if __name__ == '__main__':
934 #test_loadstore1()
935 test_loadstore1_microwatt_mmu_bin_test2()
936 #test_loadstore1_invalid()
937 #test_loadstore1_ifetch() #FIXME
938 #test_loadstore1_ifetch_invalid()
939 #test_loadstore1_ifetch_unit_iface() # guess: should be working
940 #test_loadstore1_ifetch_multi()