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