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