set separate "iside" signal in LoadStore1 to not confuse it
[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 #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
15
16 from soc.fu.ldst.loadstore import LoadStore1
17 from soc.experiment.mmu import MMU
18 from soc.experiment.test import pagetables
19
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
24
25
26 def setup_mmu():
27
28 wbget.stop = False
29
30 pspec = TestMemPspec(ldst_ifacetype='mmu_cache_wb',
31 imem_ifacetype='',
32 addr_wid=48,
33 #disable_cache=True, # hmmm...
34 mask_wid=8,
35 reg_wid=64)
36
37 m = Module()
38 comb = m.d.comb
39 cmpi = ConfigMemoryPortInterface(pspec)
40 m.submodules.ldst = ldst = cmpi.pi
41 m.submodules.mmu = mmu = MMU()
42 dcache = ldst.dcache
43 icache = ldst.icache
44
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
48
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
53
54 # link ldst and MMU together
55 comb += l_in.eq(ldst.m_out)
56 comb += ldst.m_in.eq(l_out)
57
58 return m, cmpi
59
60
61 test_exceptions = True
62 test_dcbz = True
63 test_random = True
64
65
66 def _test_loadstore1_ifetch(dut, mem):
67 mmu = dut.submodules.mmu
68 ldst = dut.submodules.ldst
69 pi = ldst.pi
70 icache = dut.submodules.ldst.icache
71 wbget.stop = False
72
73 print("=== test loadstore instruction (real) ===")
74
75 i_in = icache.i_in
76 i_out = icache.i_out
77 i_m_in = icache.m_in
78
79 # first virtual memory test
80
81 print ("set process table")
82 yield mmu.rin.prtbl.eq(0x1000000) # set process table
83 yield
84
85 # set address to zero, update mem[0] to 01234
86 addr = 8
87 expected_insn = 0x1234
88 mem[addr] = expected_insn
89
90 yield i_in.priv_mode.eq(1)
91 yield i_in.req.eq(0)
92 yield i_in.nia.eq(addr)
93 yield i_in.stop_mark.eq(0)
94 yield i_m_in.tlbld.eq(0)
95 yield i_m_in.tlbie.eq(0)
96 yield i_m_in.addr.eq(0)
97 yield i_m_in.pte.eq(0)
98 yield
99 yield
100 yield
101
102 # miss, stalls for a bit
103 yield i_in.req.eq(1)
104 yield i_in.nia.eq(addr)
105 yield
106 valid = yield i_out.valid
107 while not valid:
108 yield
109 valid = yield i_out.valid
110 yield i_in.req.eq(0)
111
112 nia = yield i_out.nia
113 insn = yield i_out.insn
114 yield
115 yield
116
117 print ("fetched %x from addr %x" % (insn, nia))
118 assert insn == expected_insn
119
120 print("=== test loadstore instruction (virtual) ===")
121
122 # look up i-cache expecting it to fail
123
124 # set address to zero, update mem[0] to 01234
125 virt_addr = 0x10200
126 real_addr = virt_addr
127 expected_insn = 0x5678
128 mem[real_addr] = expected_insn
129
130 yield i_in.priv_mode.eq(1)
131 yield i_in.virt_mode.eq(1)
132 yield i_in.req.eq(0)
133 yield i_in.nia.eq(virt_addr)
134 yield i_in.stop_mark.eq(0)
135 yield i_m_in.tlbld.eq(0)
136 yield i_m_in.tlbie.eq(0)
137 yield i_m_in.addr.eq(0)
138 yield i_m_in.pte.eq(0)
139 yield
140 yield
141 yield
142
143 # miss, stalls for a bit
144 yield i_in.req.eq(1)
145 yield i_in.nia.eq(virt_addr)
146 yield
147 valid = yield i_out.valid
148 failed = yield i_out.fetch_failed
149 while not valid and not failed:
150 yield
151 valid = yield i_out.valid
152 failed = yield i_out.fetch_failed
153 yield i_in.req.eq(0)
154
155 print ("failed?", "yes" if failed else "no")
156 assert failed == 1
157 yield
158 yield
159
160 print("=== test loadstore instruction (instruction fault) ===")
161
162 virt_addr = 0x10200
163
164 yield mmu.l_in.iside.eq(1)
165 yield mmu.l_in.load.eq(1)
166 yield mmu.l_in.valid.eq(1)
167 yield mmu.l_in.priv.eq(1)
168 yield mmu.l_in.addr.eq(virt_addr)
169 #ld_data, exctype, exc = yield from pi_ld(pi, virt_addr, 8, msr_pr=1)
170 #yield ldst.iside.eq(0)
171 yield
172 l_done = yield (mmu.l_out.done)
173 l_err = yield (mmu.l_out.err)
174 while not l_done and not l_err:
175 yield
176 l_done = yield (mmu.l_out.done)
177 l_err = yield (mmu.l_out.err)
178 yield mmu.l_in.valid.eq(0)
179 yield
180 yield
181 yield
182
183 wbget.stop = True
184
185
186 def _test_loadstore1_invalid(dut, mem):
187 mmu = dut.submodules.mmu
188 pi = dut.submodules.ldst.pi
189 wbget.stop = False
190
191 print("=== test invalid ===")
192
193 addr = 0
194 ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr_pr=1)
195 print("ld_data", ld_data, exctype, exc)
196 assert (exctype == "slow")
197 invalid = exc.invalid
198 assert (invalid == 1)
199
200 print("=== test invalid done ===")
201
202 wbget.stop = True
203
204
205 def _test_loadstore1(dut, mem):
206 mmu = dut.submodules.mmu
207 pi = dut.submodules.ldst.pi
208 ldst = dut.submodules.ldst # to get at DAR (NOT part of PortInterface)
209 wbget.stop = False
210
211 yield mmu.rin.prtbl.eq(0x1000000) # set process table
212 yield
213
214 addr = 0x100e0
215 data = 0xf553b658ba7e1f51
216
217 if test_dcbz:
218 yield from pi_st(pi, addr, data, 8, msr_pr=1)
219 yield
220
221 ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr_pr=1)
222 assert ld_data == 0xf553b658ba7e1f51
223 assert exctype is None
224
225 ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr_pr=1)
226 assert ld_data == 0xf553b658ba7e1f51
227 assert exctype is None
228
229 print("do_dcbz ===============")
230 yield from pi_st(pi, addr, data, 8, msr_pr=1, is_dcbz=1)
231 print("done_dcbz ===============")
232 yield
233
234 ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr_pr=1)
235 print("ld_data after dcbz")
236 print(ld_data)
237 assert ld_data == 0
238 assert exctype is None
239
240 if test_exceptions:
241 print("=== alignment error (ld) ===")
242 addr = 0xFF100e0FF
243 ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr_pr=1)
244 if exc:
245 alignment = exc.alignment
246 happened = exc.happened
247 yield # wait for dsr to update
248 dar = yield ldst.dar
249 else:
250 alignment = 0
251 happened = 0
252 dar = 0
253 assert (happened == 1)
254 assert (alignment == 1)
255 assert (dar == addr)
256 assert (exctype == "fast")
257 yield from wait_busy(pi, debug="pi_ld_E_alignment_error")
258 # wait is only needed in case of in exception here
259 print("=== alignment error test passed (ld) ===")
260
261 # take some cycles in between so that gtkwave separates out
262 # signals
263 yield
264 yield
265 yield
266 yield
267
268 print("=== alignment error (st) ===")
269 addr = 0xFF100e0FF
270 exctype, exc = yield from pi_st(pi, addr,0, 8, msr_pr=1)
271 if exc:
272 alignment = exc.alignment
273 happened = exc.happened
274 else:
275 alignment = 0
276 happened = 0
277 assert (happened == 1)
278 assert (alignment==1)
279 assert (dar==addr)
280 assert (exctype == "fast")
281 #???? yield from wait_busy(pi, debug="pi_st_E_alignment_error")
282 # wait is only needed in case of in exception here
283 print("=== alignment error test passed (st) ===")
284 yield #FIXME hangs
285
286 if True:
287 print("=== no alignment error (ld) ===")
288 addr = 0x100e0
289 ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr_pr=1)
290 print("ld_data", ld_data, exctype, exc)
291 if exc:
292 alignment = exc.alignment
293 happened = exc.happened
294 else:
295 alignment = 0
296 happened = 0
297 assert (happened == 0)
298 assert (alignment == 0)
299 print("=== no alignment error done (ld) ===")
300
301 if test_random:
302 addrs = [0x456920,0xa7a180,0x299420,0x1d9d60]
303
304 for addr in addrs:
305 print("== RANDOM addr ==",hex(addr))
306 ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr_pr=1)
307 print("ld_data[RANDOM]",ld_data,exc,addr)
308 assert (exctype == None)
309
310 for addr in addrs:
311 print("== RANDOM addr ==",hex(addr))
312 exc = yield from pi_st(pi, addr,0xFF*addr, 8, msr_pr=1)
313 assert (exctype == None)
314
315 # readback written data and compare
316 for addr in addrs:
317 print("== RANDOM addr ==",hex(addr))
318 ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr_pr=1)
319 print("ld_data[RANDOM_READBACK]",ld_data,exc,addr)
320 assert (exctype == None)
321 assert (ld_data == 0xFF*addr)
322
323 print("== RANDOM addr done ==")
324
325 wbget.stop = True
326
327
328 def test_loadstore1_ifetch():
329
330 m, cmpi = setup_mmu()
331
332 mem = pagetables.test1
333
334 # nmigen Simulation
335 sim = Simulator(m)
336 sim.add_clock(1e-6)
337
338 icache = m.submodules.ldst.icache
339 sim.add_sync_process(wrap(_test_loadstore1_ifetch(m, mem)))
340 # add two wb_get processes onto the *same* memory dictionary.
341 # this shouuuld work.... cross-fingers...
342 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
343 sim.add_sync_process(wrap(wb_get(icache.bus, mem)))
344 with sim.write_vcd('test_loadstore1_ifetch.vcd'):
345 sim.run()
346
347
348 def test_loadstore1():
349
350 m, cmpi = setup_mmu()
351
352 mem = pagetables.test1
353
354 # nmigen Simulation
355 sim = Simulator(m)
356 sim.add_clock(1e-6)
357
358 sim.add_sync_process(wrap(_test_loadstore1(m, mem)))
359 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
360 with sim.write_vcd('test_loadstore1.vcd'):
361 sim.run()
362
363
364 def test_loadstore1_invalid():
365
366 m, cmpi = setup_mmu()
367
368 mem = {}
369
370 # nmigen Simulation
371 sim = Simulator(m)
372 sim.add_clock(1e-6)
373
374 sim.add_sync_process(wrap(_test_loadstore1_invalid(m, mem)))
375 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
376 with sim.write_vcd('test_loadstore1_invalid.vcd'):
377 sim.run()
378
379
380 if __name__ == '__main__':
381 #test_loadstore1()
382 #test_loadstore1_invalid()
383 test_loadstore1_ifetch()