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