Allow the formal engine to perform a same-cycle result in the ALU
[soc.git] / src / soc / experiment / test / test_ldst_pi.py
1 """MMU PortInterface Test
2
3 quite basic, goes directly to the MMU to assert signals (does not
4 yet use PortInterface)
5 """
6
7 from nmigen import (C, Module, Signal, Elaboratable, Mux, Cat, Repl, Signal)
8 from nmigen.cli import main
9 from nmigen.cli import rtlil
10 from nmutil.mask import Mask, masked
11 from nmutil.util import Display
12
13 if True:
14 from nmigen.back.pysim import Simulator, Delay, Settle
15 else:
16 from nmigen.sim.cxxsim import Simulator, Delay, Settle
17 from nmutil.util import wrap
18
19 from soc.config.test.test_pi2ls import pi_ld, pi_st, pi_ldst
20 from soc.config.test.test_loadstore import TestMemPspec
21 from soc.config.loadstore import ConfigMemoryPortInterface
22
23 from soc.fu.ldst.loadstore import LoadStore1
24 from soc.experiment.mmu import MMU
25
26 from nmigen.compat.sim import run_simulation
27
28
29 stop = False
30
31 def b(x): # byte-reverse function
32 return int.from_bytes(x.to_bytes(8, byteorder='little'),
33 byteorder='big', signed=False)
34
35 def wb_get(wb, mem):
36 """simulator process for getting memory load requests
37 """
38
39 global stop
40
41 while not stop:
42 while True: # wait for dc_valid
43 if stop:
44 return
45 cyc = yield (wb.cyc)
46 stb = yield (wb.stb)
47 if cyc and stb:
48 break
49 yield
50 addr = (yield wb.adr) << 3
51 if addr not in mem:
52 print (" WB LOOKUP NO entry @ %x, returning zero" % (addr))
53
54 # read or write?
55 we = (yield wb.we)
56 if we:
57 store = (yield wb.dat_w)
58 sel = (yield wb.sel)
59 data = mem.get(addr, 0)
60 # note we assume 8-bit sel, here
61 res = 0
62 for i in range(8):
63 mask = 0xff << (i*8)
64 if sel & (1<<i):
65 res |= store & mask
66 else:
67 res |= data & mask
68 mem[addr] = res
69 print (" DCACHE set %x mask %x data %x" % (addr, sel, res))
70 else:
71 data = mem.get(addr, 0)
72 yield wb.dat_r.eq(data)
73 print (" DCACHE get %x data %x" % (addr, data))
74
75 yield wb.ack.eq(1)
76 yield
77 yield wb.ack.eq(0)
78 yield
79
80
81 def mmu_lookup(dut, addr):
82 mmu = dut.submodules.mmu
83 global stop
84
85 print("pi_ld", hex(addr))
86 data = yield from pi_ld(dut.submodules.ldst.pi, addr, 4, msr_pr=1)
87 print("pi_ld done, data", hex(data))
88 """
89 # original test code kept for reference
90 while not stop: # wait for dc_valid / err
91 print("waiting for mmu")
92 l_done = yield (mmu.l_out.done)
93 l_err = yield (mmu.l_out.err)
94 l_badtree = yield (mmu.l_out.badtree)
95 l_permerr = yield (mmu.l_out.perm_error)
96 l_rc_err = yield (mmu.l_out.rc_error)
97 l_segerr = yield (mmu.l_out.segerr)
98 l_invalid = yield (mmu.l_out.invalid)
99 if (l_done or l_err or l_badtree or
100 l_permerr or l_rc_err or l_segerr or l_invalid):
101 break
102 yield
103 """
104 phys_addr = yield mmu.d_out.addr
105 pte = yield mmu.d_out.pte
106 l_done = yield (mmu.l_out.done)
107 l_err = yield (mmu.l_out.err)
108 l_badtree = yield (mmu.l_out.badtree)
109 print ("translated done %d err %d badtree %d addr %x pte %x" % \
110 (l_done, l_err, l_badtree, phys_addr, pte))
111 yield
112 yield mmu.l_in.valid.eq(0)
113
114 return data
115
116
117 def ldst_sim(dut):
118 mmu = dut.submodules.mmu
119 global stop
120 yield mmu.rin.prtbl.eq(0x1000000) # set process table
121 yield
122
123 # expecting this data to return
124 # 0x1000: 0xdeadbeef01234567,
125 # 0x1008: 0xfeedf00ff001a5a5
126
127 addr = 0x1000
128 print("pi_ld")
129
130 # TODO mmu_lookup using port interface
131 # set inputs
132 data = yield from mmu_lookup(dut, addr)
133 assert data == 0x1234567
134
135 data = yield from mmu_lookup(dut, addr+8)
136 assert data == 0xf001a5a5
137 #assert phys_addr == addr # happens to be the same (for this example)
138
139 data = yield from mmu_lookup(dut, addr+4)
140 assert data == 0xdeadbeef
141
142 data = yield from mmu_lookup(dut, addr+8)
143 assert data == 0xf001a5a5
144
145 yield from pi_st(dut.submodules.ldst.pi, addr+4, 0x10015a5a, 4, msr_pr=1)
146
147 data = yield from mmu_lookup(dut, addr+4)
148 assert data == 0x10015a5a
149
150 yield
151 yield
152
153 stop = True
154
155 def setup_mmu():
156
157 pspec = TestMemPspec(ldst_ifacetype='mmu_cache_wb',
158 imem_ifacetype='',
159 addr_wid=48,
160 #disable_cache=True, # hmmm...
161 mask_wid=8,
162 reg_wid=64)
163
164 m = Module()
165 comb = m.d.comb
166 cmpi = ConfigMemoryPortInterface(pspec)
167 m.submodules.ldst = ldst = cmpi.pi
168 m.submodules.mmu = mmu = MMU()
169 dcache = ldst.dcache
170
171 l_in, l_out = mmu.l_in, mmu.l_out
172 d_in, d_out = dcache.d_in, dcache.d_out
173 wb_out, wb_in = dcache.wb_out, dcache.wb_in
174
175 # link mmu and dcache together
176 m.d.comb += dcache.m_in.eq(mmu.d_out) # MMUToDCacheType
177 m.d.comb += mmu.d_in.eq(dcache.m_out) # DCacheToMMUType
178
179 # link ldst and MMU together
180 comb += l_in.eq(ldst.m_out)
181 comb += ldst.m_in.eq(l_out)
182
183 return m, cmpi
184
185
186 def test_mmu():
187
188 m, cmpi = setup_mmu()
189
190 # virtual "memory" to use for this test
191
192 mem = {0x10000: # PARTITION_TABLE_2
193 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
194 b(0x800000000100000b),
195
196 0x30000: # RADIX_ROOT_PTE
197 # V = 1 L = 0 NLB = 0x400 NLS = 9
198 b(0x8000000000040009),
199
200 0x40000: # RADIX_SECOND_LEVEL
201 # V = 1 L = 1 SW = 0 RPN = 0
202 # R = 1 C = 1 ATT = 0 EAA 0x7
203 b(0xc000000000000183),
204
205 0x1000000: # PROCESS_TABLE_3
206 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
207 b(0x40000000000300ad),
208
209 # data to return
210 0x1000: 0xdeadbeef01234567,
211 0x1008: 0xfeedf00ff001a5a5
212 }
213
214
215 # nmigen Simulation
216 sim = Simulator(m)
217 sim.add_clock(1e-6)
218
219 sim.add_sync_process(wrap(ldst_sim(m)))
220 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
221 with sim.write_vcd('test_ldst_pi.vcd'):
222 sim.run()
223
224 def ldst_sim_misalign(dut):
225 mmu = dut.submodules.mmu
226 global stop
227 stop = False
228
229 yield mmu.rin.prtbl.eq(0x1000000) # set process table
230 yield
231
232 data = yield from pi_ld(dut.submodules.ldst.pi, 0x1007, 8, msr_pr=1)
233 print ("misalign ld data", hex(data))
234
235 yield
236 stop = True
237
238
239 def test_misalign_mmu():
240
241 m, cmpi = setup_mmu()
242
243 # virtual "memory" to use for this test
244
245 mem = {0x10000: # PARTITION_TABLE_2
246 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
247 b(0x800000000100000b),
248
249 0x30000: # RADIX_ROOT_PTE
250 # V = 1 L = 0 NLB = 0x400 NLS = 9
251 b(0x8000000000040009),
252
253 0x40000: # RADIX_SECOND_LEVEL
254 # V = 1 L = 1 SW = 0 RPN = 0
255 # R = 1 C = 1 ATT = 0 EAA 0x7
256 b(0xc000000000000183),
257
258 0x1000000: # PROCESS_TABLE_3
259 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
260 b(0x40000000000300ad),
261
262 # data to return
263 0x1000: 0xdeadbeef01234567,
264 0x1008: 0xfeedf00ff001a5a5
265 }
266
267
268 # nmigen Simulation
269 sim = Simulator(m)
270 sim.add_clock(1e-6)
271
272 sim.add_sync_process(wrap(ldst_sim_misalign(m)))
273 sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
274 with sim.write_vcd('test_ldst_pi_misalign.vcd'):
275 sim.run()
276
277
278 if __name__ == '__main__':
279 test_mmu()
280 test_misalign_mmu()