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
12 #from soc.config.test.test_pi2ls import pi_st_debug
13 from soc
.config
.test
.test_loadstore
import TestMemPspec
14 from soc
.config
.loadstore
import ConfigMemoryPortInterface
16 from soc
.fu
.ldst
.loadstore
import LoadStore1
17 from soc
.experiment
.mmu
import MMU
18 from soc
.experiment
.test
import pagetables
20 from nmigen
.compat
.sim
import run_simulation
21 from random
import random
22 from openpower
.test
.wb_get
import wb_get
23 from openpower
.test
import wb_get
as wbget
30 pspec
= TestMemPspec(ldst_ifacetype
='mmu_cache_wb',
33 #disable_cache=True, # hmmm...
39 cmpi
= ConfigMemoryPortInterface(pspec
)
40 m
.submodules
.ldst
= ldst
= cmpi
.pi
41 m
.submodules
.mmu
= mmu
= MMU()
45 l_in
, l_out
= mmu
.l_in
, mmu
.l_out
46 d_in
, d_out
= dcache
.d_in
, dcache
.d_out
47 i_in
, i_out
= icache
.i_in
, icache
.i_out
# FetchToICache, ICacheToDecode
49 # link mmu, dcache and icache together
50 m
.d
.comb
+= dcache
.m_in
.eq(mmu
.d_out
) # MMUToDCacheType
51 m
.d
.comb
+= icache
.m_in
.eq(mmu
.i_out
) # MMUToICacheType
52 m
.d
.comb
+= mmu
.d_in
.eq(dcache
.m_out
) # DCacheToMMUType
54 # link ldst and MMU together
55 comb
+= l_in
.eq(ldst
.m_out
)
56 comb
+= ldst
.m_in
.eq(l_out
)
61 test_exceptions
= True
66 def _test_loadstore1_ifetch(dut
, mem
):
67 """test_loadstore1_ifetch
69 this is quite a complex multi-step test.
71 * first (just because, as a demo) read in priv mode, non-virtual.
72 just like in experiment/icache.py itself.
74 * second, using the (usual) PTE for these things (which came originally
75 from gem5-experimental experiment/radix_walk_example.txt) do a
76 virtual-memory read through the *instruction* cache.
77 this is expected to FAIL
79 * third: mess about with the MMU, setting "iside" (instruction-side),
80 requesting an MMU RADIX LOOKUP. this triggers an itlb_load
81 (instruction-cache TLB entry-insertion)
83 * fourth and finally: retry the read of the instruction through i-cache.
84 this is now expected to SUCCEED
89 mmu
= dut
.submodules
.mmu
90 ldst
= dut
.submodules
.ldst
92 icache
= dut
.submodules
.ldst
.icache
95 print("=== test loadstore instruction (real) ===")
101 # first virtual memory test
103 print ("set process table")
104 yield mmu
.rin
.prtbl
.eq(0x1000000) # set process table
107 # set address to zero, update mem[0] to 01234
109 expected_insn
= 0x1234
110 mem
[addr
] = expected_insn
112 yield i_in
.priv_mode
.eq(1)
114 yield i_in
.nia
.eq(addr
)
115 yield i_in
.stop_mark
.eq(0)
116 yield i_m_in
.tlbld
.eq(0)
117 yield i_m_in
.tlbie
.eq(0)
118 yield i_m_in
.addr
.eq(0)
119 yield i_m_in
.pte
.eq(0)
124 # miss, stalls for a bit
126 yield i_in
.nia
.eq(addr
)
128 valid
= yield i_out
.valid
131 valid
= yield i_out
.valid
134 nia
= yield i_out
.nia
135 insn
= yield i_out
.insn
139 print ("fetched %x from addr %x" % (insn
, nia
))
140 assert insn
== expected_insn
142 print("=== test loadstore instruction (virtual) ===")
144 # look up i-cache expecting it to fail
146 # set address to 0x10200, update mem[] to 5678
148 real_addr
= virt_addr
149 expected_insn
= 0x5678
150 mem
[real_addr
] = expected_insn
152 yield i_in
.priv_mode
.eq(1)
153 yield i_in
.virt_mode
.eq(1)
155 yield i_in
.nia
.eq(virt_addr
)
156 yield i_in
.stop_mark
.eq(0)
157 yield i_m_in
.tlbld
.eq(0)
158 yield i_m_in
.tlbie
.eq(0)
159 yield i_m_in
.addr
.eq(0)
160 yield i_m_in
.pte
.eq(0)
165 # miss, stalls for a bit
167 yield i_in
.nia
.eq(virt_addr
)
169 valid
= yield i_out
.valid
170 failed
= yield i_out
.fetch_failed
171 while not valid
and not failed
:
173 valid
= yield i_out
.valid
174 failed
= yield i_out
.fetch_failed
177 print ("failed?", "yes" if failed
else "no")
182 print("=== test loadstore instruction (instruction fault) ===")
186 yield ldst
.priv_mode
.eq(1)
187 yield ldst
.instr_fault
.eq(1)
188 yield ldst
.maddr
.eq(virt_addr
)
189 #ld_data, exctype, exc = yield from pi_ld(pi, virt_addr, 8, msr_pr=1)
191 yield ldst
.instr_fault
.eq(0)
193 done
= yield (ldst
.done
)
197 yield ldst
.instr_fault
.eq(0)
202 print("=== test loadstore instruction (try instruction again) ===")
203 # set address to 0x10200, update mem[] to 5678
205 real_addr
= virt_addr
206 expected_insn
= 0x5678
208 yield i_in
.priv_mode
.eq(1)
209 yield i_in
.virt_mode
.eq(1)
211 yield i_in
.nia
.eq(virt_addr
)
212 yield i_in
.stop_mark
.eq(0)
213 yield i_m_in
.tlbld
.eq(0)
214 yield i_m_in
.tlbie
.eq(0)
215 yield i_m_in
.addr
.eq(0)
216 yield i_m_in
.pte
.eq(0)
221 # miss, stalls for a bit
223 yield i_in
.nia
.eq(virt_addr
)
225 valid
= yield i_out
.valid
226 failed
= yield i_out
.fetch_failed
227 while not valid
and not failed
:
229 valid
= yield i_out
.valid
230 failed
= yield i_out
.fetch_failed
232 nia
= yield i_out
.nia
233 insn
= yield i_out
.insn
237 print ("failed?", "yes" if failed
else "no")
240 print ("fetched %x from addr %x" % (insn
, nia
))
241 assert insn
== expected_insn
246 def _test_loadstore1_invalid(dut
, mem
):
247 mmu
= dut
.submodules
.mmu
248 pi
= dut
.submodules
.ldst
.pi
251 print("=== test invalid ===")
254 ld_data
, exctype
, exc
= yield from pi_ld(pi
, addr
, 8, msr_pr
=1)
255 print("ld_data", ld_data
, exctype
, exc
)
256 assert (exctype
== "slow")
257 invalid
= exc
.invalid
258 assert (invalid
== 1)
260 print("=== test invalid done ===")
265 def _test_loadstore1(dut
, mem
):
266 mmu
= dut
.submodules
.mmu
267 pi
= dut
.submodules
.ldst
.pi
268 ldst
= dut
.submodules
.ldst
# to get at DAR (NOT part of PortInterface)
271 yield mmu
.rin
.prtbl
.eq(0x1000000) # set process table
275 data
= 0xf553b658ba7e1f51
278 yield from pi_st(pi
, addr
, data
, 8, msr_pr
=1)
281 ld_data
, exctype
, exc
= yield from pi_ld(pi
, addr
, 8, msr_pr
=1)
282 assert ld_data
== 0xf553b658ba7e1f51
283 assert exctype
is None
285 ld_data
, exctype
, exc
= yield from pi_ld(pi
, addr
, 8, msr_pr
=1)
286 assert ld_data
== 0xf553b658ba7e1f51
287 assert exctype
is None
289 print("do_dcbz ===============")
290 yield from pi_st(pi
, addr
, data
, 8, msr_pr
=1, is_dcbz
=1)
291 print("done_dcbz ===============")
294 ld_data
, exctype
, exc
= yield from pi_ld(pi
, addr
, 8, msr_pr
=1)
295 print("ld_data after dcbz")
298 assert exctype
is None
301 print("=== alignment error (ld) ===")
303 ld_data
, exctype
, exc
= yield from pi_ld(pi
, addr
, 8, msr_pr
=1)
305 alignment
= exc
.alignment
306 happened
= exc
.happened
307 yield # wait for dsr to update
313 assert (happened
== 1)
314 assert (alignment
== 1)
316 assert (exctype
== "fast")
317 yield from wait_busy(pi
, debug
="pi_ld_E_alignment_error")
318 # wait is only needed in case of in exception here
319 print("=== alignment error test passed (ld) ===")
321 # take some cycles in between so that gtkwave separates out
328 print("=== alignment error (st) ===")
330 exctype
, exc
= yield from pi_st(pi
, addr
,0, 8, msr_pr
=1)
332 alignment
= exc
.alignment
333 happened
= exc
.happened
337 assert (happened
== 1)
338 assert (alignment
==1)
340 assert (exctype
== "fast")
341 #???? yield from wait_busy(pi, debug="pi_st_E_alignment_error")
342 # wait is only needed in case of in exception here
343 print("=== alignment error test passed (st) ===")
347 print("=== no alignment error (ld) ===")
349 ld_data
, exctype
, exc
= yield from pi_ld(pi
, addr
, 8, msr_pr
=1)
350 print("ld_data", ld_data
, exctype
, exc
)
352 alignment
= exc
.alignment
353 happened
= exc
.happened
357 assert (happened
== 0)
358 assert (alignment
== 0)
359 print("=== no alignment error done (ld) ===")
362 addrs
= [0x456920,0xa7a180,0x299420,0x1d9d60]
365 print("== RANDOM addr ==",hex(addr
))
366 ld_data
, exctype
, exc
= yield from pi_ld(pi
, addr
, 8, msr_pr
=1)
367 print("ld_data[RANDOM]",ld_data
,exc
,addr
)
368 assert (exctype
== None)
371 print("== RANDOM addr ==",hex(addr
))
372 exc
= yield from pi_st(pi
, addr
,0xFF*addr
, 8, msr_pr
=1)
373 assert (exctype
== None)
375 # readback written data and compare
377 print("== RANDOM addr ==",hex(addr
))
378 ld_data
, exctype
, exc
= yield from pi_ld(pi
, addr
, 8, msr_pr
=1)
379 print("ld_data[RANDOM_READBACK]",ld_data
,exc
,addr
)
380 assert (exctype
== None)
381 assert (ld_data
== 0xFF*addr
)
383 print("== RANDOM addr done ==")
388 def test_loadstore1_ifetch():
390 m
, cmpi
= setup_mmu()
392 mem
= pagetables
.test1
398 icache
= m
.submodules
.ldst
.icache
399 sim
.add_sync_process(wrap(_test_loadstore1_ifetch(m
, mem
)))
400 # add two wb_get processes onto the *same* memory dictionary.
401 # this shouuuld work.... cross-fingers...
402 sim
.add_sync_process(wrap(wb_get(cmpi
.wb_bus(), mem
)))
403 sim
.add_sync_process(wrap(wb_get(icache
.bus
, mem
)))
404 with sim
.write_vcd('test_loadstore1_ifetch.vcd'):
408 def test_loadstore1():
410 m
, cmpi
= setup_mmu()
412 mem
= pagetables
.test1
418 sim
.add_sync_process(wrap(_test_loadstore1(m
, mem
)))
419 sim
.add_sync_process(wrap(wb_get(cmpi
.wb_bus(), mem
)))
420 with sim
.write_vcd('test_loadstore1.vcd'):
424 def test_loadstore1_invalid():
426 m
, cmpi
= setup_mmu()
434 sim
.add_sync_process(wrap(_test_loadstore1_invalid(m
, mem
)))
435 sim
.add_sync_process(wrap(wb_get(cmpi
.wb_bus(), mem
)))
436 with sim
.write_vcd('test_loadstore1_invalid.vcd'):
440 if __name__
== '__main__':
442 test_loadstore1_invalid()
443 test_loadstore1_ifetch()