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(1)
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(1)
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(1)
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():
393 m
, cmpi
= setup_mmu()
395 mem
= pagetables
.test1
401 icache
= m
.submodules
.ldst
.icache
402 sim
.add_sync_process(wrap(_test_loadstore1_ifetch(m
, mem
)))
403 # add two wb_get processes onto the *same* memory dictionary.
404 # this shouuuld work.... cross-fingers...
405 sim
.add_sync_process(wrap(wb_get(cmpi
.wb_bus(), mem
)))
406 sim
.add_sync_process(wrap(wb_get(icache
.bus
, mem
)))
407 with sim
.write_vcd('test_loadstore1_ifetch.vcd'):
411 def test_loadstore1():
413 m
, cmpi
= setup_mmu()
415 mem
= pagetables
.test1
421 sim
.add_sync_process(wrap(_test_loadstore1(m
, mem
)))
422 sim
.add_sync_process(wrap(wb_get(cmpi
.wb_bus(), mem
)))
423 with sim
.write_vcd('test_loadstore1.vcd'):
427 def test_loadstore1_invalid():
429 m
, cmpi
= setup_mmu()
437 sim
.add_sync_process(wrap(_test_loadstore1_invalid(m
, mem
)))
438 sim
.add_sync_process(wrap(wb_get(cmpi
.wb_bus(), mem
)))
439 with sim
.write_vcd('test_loadstore1_invalid.vcd'):
443 if __name__
== '__main__':
445 test_loadstore1_invalid()
446 test_loadstore1_ifetch()