1 from nmigen
import (C
, Module
, Signal
, Elaboratable
, Mux
, Cat
, Repl
, Signal
,
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
11 from soc
.config
.test
.test_pi2ls
import (pi_ld
, pi_st
, pi_ldst
, wait_busy
,
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
17 from soc
.fu
.ldst
.loadstore
import LoadStore1
18 from soc
.experiment
.mmu
import MMU
19 from soc
.experiment
.test
import pagetables
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
31 pspec
= TestMemPspec(ldst_ifacetype
='mmu_cache_wb',
34 #disable_cache=True, # hmmm...
40 cmpi
= ConfigMemoryPortInterface(pspec
)
41 m
.submodules
.ldst
= ldst
= cmpi
.pi
42 m
.submodules
.mmu
= mmu
= MMU()
46 l_in
, l_out
= mmu
.l_in
, mmu
.l_out
47 d_in
, d_out
= dcache
.d_in
, dcache
.d_out
48 i_in
, i_out
= icache
.i_in
, icache
.i_out
# FetchToICache, ICacheToDecode
50 # link mmu, dcache and icache together
51 m
.d
.comb
+= dcache
.m_in
.eq(mmu
.d_out
) # MMUToDCacheType
52 m
.d
.comb
+= icache
.m_in
.eq(mmu
.i_out
) # MMUToICacheType
53 m
.d
.comb
+= mmu
.d_in
.eq(dcache
.m_out
) # DCacheToMMUType
55 # link ldst and MMU together
56 comb
+= l_in
.eq(ldst
.m_out
)
57 comb
+= ldst
.m_in
.eq(l_out
)
62 test_exceptions
= True
67 def _test_loadstore1_ifetch(dut
, mem
):
68 """test_loadstore1_ifetch
70 this is quite a complex multi-step test.
72 * first (just because, as a demo) read in priv mode, non-virtual.
73 just like in experiment/icache.py itself.
75 * second, using the (usual) PTE for these things (which came originally
76 from gem5-experimental experiment/radix_walk_example.txt) do a
77 virtual-memory read through the *instruction* cache.
78 this is expected to FAIL
80 * third: mess about with the MMU, setting "iside" (instruction-side),
81 requesting an MMU RADIX LOOKUP. this triggers an itlb_load
82 (instruction-cache TLB entry-insertion)
84 * fourth and finally: retry the read of the instruction through i-cache.
85 this is now expected to SUCCEED
90 mmu
= dut
.submodules
.mmu
91 ldst
= dut
.submodules
.ldst
93 icache
= dut
.submodules
.ldst
.icache
96 print("=== test loadstore instruction (real) ===")
102 # first virtual memory test
104 print ("set process table")
105 yield mmu
.rin
.prtbl
.eq(0x1000000) # set process table
108 # set address to zero, update mem[0] to 01234
110 expected_insn
= 0x1234
111 mem
[addr
] = expected_insn
113 yield i_in
.priv_mode
.eq(1)
115 yield i_in
.nia
.eq(addr
)
116 yield i_in
.stop_mark
.eq(0)
117 yield i_m_in
.tlbld
.eq(0)
118 yield i_m_in
.tlbie
.eq(0)
119 yield i_m_in
.addr
.eq(0)
120 yield i_m_in
.pte
.eq(0)
125 # miss, stalls for a bit
127 yield i_in
.nia
.eq(addr
)
129 valid
= yield i_out
.valid
132 valid
= yield i_out
.valid
135 nia
= yield i_out
.nia
136 insn
= yield i_out
.insn
140 print ("fetched %x from addr %x" % (insn
, nia
))
141 assert insn
== expected_insn
143 print("=== test loadstore instruction (virtual) ===")
145 # look up i-cache expecting it to fail
147 # set address to 0x10200, update mem[] to 5678
149 real_addr
= virt_addr
150 expected_insn
= 0x5678
151 mem
[real_addr
] = expected_insn
153 yield i_in
.priv_mode
.eq(0)
154 yield i_in
.virt_mode
.eq(1)
156 yield i_in
.nia
.eq(virt_addr
)
157 yield i_in
.stop_mark
.eq(0)
158 yield i_m_in
.tlbld
.eq(0)
159 yield i_m_in
.tlbie
.eq(0)
160 yield i_m_in
.addr
.eq(0)
161 yield i_m_in
.pte
.eq(0)
166 # miss, stalls for a bit
168 yield i_in
.nia
.eq(virt_addr
)
170 valid
= yield i_out
.valid
171 failed
= yield i_out
.fetch_failed
172 while not valid
and not failed
:
174 valid
= yield i_out
.valid
175 failed
= yield i_out
.fetch_failed
178 print ("failed?", "yes" if failed
else "no")
183 print("=== test loadstore instruction (instruction fault) ===")
187 yield ldst
.priv_mode
.eq(0)
188 yield ldst
.instr_fault
.eq(1)
189 yield ldst
.maddr
.eq(virt_addr
)
190 #ld_data, exctype, exc = yield from pi_ld(pi, virt_addr, 8, msr_pr=1)
192 yield ldst
.instr_fault
.eq(0)
194 done
= yield (ldst
.done
)
195 exc_info
= yield from get_exception_info(pi
.exc_o
)
196 if done
or exc_info
.happened
:
199 assert exc_info
.happened
== 0 # assert just before doing the fault set zero
200 yield ldst
.instr_fault
.eq(0)
205 print("=== test loadstore instruction (try instruction again) ===")
206 # set address to 0x10200, update mem[] to 5678
208 real_addr
= virt_addr
209 expected_insn
= 0x5678
211 yield i_in
.priv_mode
.eq(0)
212 yield i_in
.virt_mode
.eq(1)
214 yield i_in
.nia
.eq(virt_addr
)
215 yield i_in
.stop_mark
.eq(0)
216 yield i_m_in
.tlbld
.eq(0)
217 yield i_m_in
.tlbie
.eq(0)
218 yield i_m_in
.addr
.eq(0)
219 yield i_m_in
.pte
.eq(0)
224 # miss, stalls for a bit
226 yield i_in
.nia
.eq(virt_addr
)
228 valid
= yield i_out
.valid
229 failed
= yield i_out
.fetch_failed
230 while not valid
and not failed
:
232 valid
= yield i_out
.valid
233 failed
= yield i_out
.fetch_failed
235 nia
= yield i_out
.nia
236 insn
= yield i_out
.insn
240 print ("failed?", "yes" if failed
else "no")
243 print ("fetched %x from addr %x" % (insn
, nia
))
244 assert insn
== expected_insn
249 def _test_loadstore1_invalid(dut
, mem
):
250 mmu
= dut
.submodules
.mmu
251 pi
= dut
.submodules
.ldst
.pi
254 print("=== test invalid ===")
257 ld_data
, exctype
, exc
= yield from pi_ld(pi
, addr
, 8, msr_pr
=1)
258 print("ld_data", ld_data
, exctype
, exc
)
259 assert (exctype
== "slow")
260 invalid
= exc
.invalid
261 assert (invalid
== 1)
263 print("=== test invalid done ===")
268 def _test_loadstore1(dut
, mem
):
269 mmu
= dut
.submodules
.mmu
270 pi
= dut
.submodules
.ldst
.pi
271 ldst
= dut
.submodules
.ldst
# to get at DAR (NOT part of PortInterface)
274 yield mmu
.rin
.prtbl
.eq(0x1000000) # set process table
278 data
= 0xf553b658ba7e1f51
281 yield from pi_st(pi
, addr
, data
, 8, msr_pr
=1)
284 ld_data
, exctype
, exc
= yield from pi_ld(pi
, addr
, 8, msr_pr
=1)
285 assert ld_data
== 0xf553b658ba7e1f51
286 assert exctype
is None
288 ld_data
, exctype
, exc
= yield from pi_ld(pi
, addr
, 8, msr_pr
=1)
289 assert ld_data
== 0xf553b658ba7e1f51
290 assert exctype
is None
292 print("do_dcbz ===============")
293 yield from pi_st(pi
, addr
, data
, 8, msr_pr
=1, is_dcbz
=1)
294 print("done_dcbz ===============")
297 ld_data
, exctype
, exc
= yield from pi_ld(pi
, addr
, 8, msr_pr
=1)
298 print("ld_data after dcbz")
301 assert exctype
is None
304 print("=== alignment error (ld) ===")
306 ld_data
, exctype
, exc
= yield from pi_ld(pi
, addr
, 8, msr_pr
=1)
308 alignment
= exc
.alignment
309 happened
= exc
.happened
310 yield # wait for dsr to update
316 assert (happened
== 1)
317 assert (alignment
== 1)
319 assert (exctype
== "fast")
320 yield from wait_busy(pi
, debug
="pi_ld_E_alignment_error")
321 # wait is only needed in case of in exception here
322 print("=== alignment error test passed (ld) ===")
324 # take some cycles in between so that gtkwave separates out
331 print("=== alignment error (st) ===")
333 exctype
, exc
= yield from pi_st(pi
, addr
,0, 8, msr_pr
=1)
335 alignment
= exc
.alignment
336 happened
= exc
.happened
340 assert (happened
== 1)
341 assert (alignment
==1)
343 assert (exctype
== "fast")
344 #???? yield from wait_busy(pi, debug="pi_st_E_alignment_error")
345 # wait is only needed in case of in exception here
346 print("=== alignment error test passed (st) ===")
350 print("=== no alignment error (ld) ===")
352 ld_data
, exctype
, exc
= yield from pi_ld(pi
, addr
, 8, msr_pr
=1)
353 print("ld_data", ld_data
, exctype
, exc
)
355 alignment
= exc
.alignment
356 happened
= exc
.happened
360 assert (happened
== 0)
361 assert (alignment
== 0)
362 print("=== no alignment error done (ld) ===")
365 addrs
= [0x456920,0xa7a180,0x299420,0x1d9d60]
368 print("== RANDOM addr ==",hex(addr
))
369 ld_data
, exctype
, exc
= yield from pi_ld(pi
, addr
, 8, msr_pr
=1)
370 print("ld_data[RANDOM]",ld_data
,exc
,addr
)
371 assert (exctype
== None)
374 print("== RANDOM addr ==",hex(addr
))
375 exc
= yield from pi_st(pi
, addr
,0xFF*addr
, 8, msr_pr
=1)
376 assert (exctype
== None)
378 # readback written data and compare
380 print("== RANDOM addr ==",hex(addr
))
381 ld_data
, exctype
, exc
= yield from pi_ld(pi
, addr
, 8, msr_pr
=1)
382 print("ld_data[RANDOM_READBACK]",ld_data
,exc
,addr
)
383 assert (exctype
== None)
384 assert (ld_data
== 0xFF*addr
)
386 print("== RANDOM addr done ==")
391 def _test_loadstore1_ifetch_invalid(dut
, mem
):
392 mmu
= dut
.submodules
.mmu
393 ldst
= dut
.submodules
.ldst
395 icache
= dut
.submodules
.ldst
.icache
398 print("=== test loadstore instruction (invalid) ===")
404 # first virtual memory test
406 print ("set process table")
407 yield mmu
.rin
.prtbl
.eq(0x1000000) # set process table
410 # set address to zero, update mem[0] to 01234
412 expected_insn
= 0x1234
413 mem
[addr
] = expected_insn
415 yield i_in
.priv_mode
.eq(1)
417 yield i_in
.nia
.eq(addr
)
418 yield i_in
.stop_mark
.eq(0)
419 yield i_m_in
.tlbld
.eq(0)
420 yield i_m_in
.tlbie
.eq(0)
421 yield i_m_in
.addr
.eq(0)
422 yield i_m_in
.pte
.eq(0)
427 # miss, stalls for a bit
429 yield i_in
.nia
.eq(addr
)
431 valid
= yield i_out
.valid
432 nia
= yield i_out
.nia
435 valid
= yield i_out
.valid
438 nia
= yield i_out
.nia
439 insn
= yield i_out
.insn
444 print ("fetched %x from addr %x" % (insn
, nia
))
445 assert insn
== expected_insn
447 print("=== test loadstore instruction (virtual) ===")
449 # look up i-cache expecting it to fail
451 # set address to 0x10200, update mem[] to 5678
453 real_addr
= virt_addr
454 expected_insn
= 0x5678
455 mem
[real_addr
] = expected_insn
457 yield i_in
.priv_mode
.eq(1)
458 yield i_in
.virt_mode
.eq(1)
460 yield i_in
.nia
.eq(virt_addr
)
461 yield i_in
.stop_mark
.eq(0)
462 yield i_m_in
.tlbld
.eq(0)
463 yield i_m_in
.tlbie
.eq(0)
464 yield i_m_in
.addr
.eq(0)
465 yield i_m_in
.pte
.eq(0)
470 # miss, stalls for a bit
472 yield i_in
.nia
.eq(virt_addr
)
474 valid
= yield i_out
.valid
475 failed
= yield i_out
.fetch_failed
476 while not valid
and not failed
:
478 valid
= yield i_out
.valid
479 failed
= yield i_out
.fetch_failed
482 print ("failed?", "yes" if failed
else "no")
490 def test_loadstore1_ifetch():
492 m
, cmpi
= setup_mmu()
494 mem
= pagetables
.test1
500 icache
= m
.submodules
.ldst
.icache
501 sim
.add_sync_process(wrap(_test_loadstore1_ifetch(m
, mem
)))
502 # add two wb_get processes onto the *same* memory dictionary.
503 # this shouuuld work.... cross-fingers...
504 sim
.add_sync_process(wrap(wb_get(cmpi
.wb_bus(), mem
)))
505 sim
.add_sync_process(wrap(wb_get(icache
.bus
, mem
)))
506 with sim
.write_vcd('test_loadstore1_ifetch.vcd'):
510 def test_loadstore1():
512 m
, cmpi
= setup_mmu()
514 mem
= pagetables
.test1
520 sim
.add_sync_process(wrap(_test_loadstore1(m
, mem
)))
521 sim
.add_sync_process(wrap(wb_get(cmpi
.wb_bus(), mem
)))
522 with sim
.write_vcd('test_loadstore1.vcd'):
526 def test_loadstore1_invalid():
528 m
, cmpi
= setup_mmu()
536 sim
.add_sync_process(wrap(_test_loadstore1_invalid(m
, mem
)))
537 sim
.add_sync_process(wrap(wb_get(cmpi
.wb_bus(), mem
)))
538 with sim
.write_vcd('test_loadstore1_invalid.vcd'):
541 def test_loadstore1_ifetch_invalid():
542 m
, cmpi
= setup_mmu()
544 # this is a specially-arranged page table which has the permissions
545 # barred for execute on the leaf node (EAA=0x2 instead of EAA=0x3)
546 mem
= pagetables
.test2
552 icache
= m
.submodules
.ldst
.icache
553 sim
.add_sync_process(wrap(_test_loadstore1_ifetch_invalid(m
, mem
)))
554 # add two wb_get processes onto the *same* memory dictionary.
555 # this shouuuld work.... cross-fingers...
556 sim
.add_sync_process(wrap(wb_get(cmpi
.wb_bus(), mem
)))
557 sim
.add_sync_process(wrap(wb_get(icache
.bus
, mem
)))
558 with sim
.write_vcd('test_loadstore1_ifetch_invalid.vcd'):
563 if __name__
== '__main__':
565 test_loadstore1_invalid()
566 test_loadstore1_ifetch()
567 test_loadstore1_ifetch_invalid()