fix wb_get error where data was being corrupted
[soc.git] / src / soc / experiment / test / test_mmu_dcache_pi.py
1 """MMU PortInterface Test
2
3 quite basic, calls pi_ld to get data via PortInterface. this test
4 shouldn't really exist, it's superceded by test_ldst_pi.py
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.iocontrol import RecordObject
11 from nmutil.byterev import byte_reverse
12 from nmutil.mask import Mask, masked
13 from nmutil.util import Display
14
15 if True:
16 from nmigen.back.pysim import Simulator, Delay, Settle
17 else:
18 from nmigen.sim.cxxsim import Simulator, Delay, Settle
19 from nmutil.util import wrap
20
21 from soc.config.test.test_pi2ls import pi_ld, pi_st, pi_ldst
22
23 from soc.experiment.mem_types import (LoadStore1ToMMUType,
24 MMUToLoadStore1Type,
25 MMUToDCacheType,
26 DCacheToMMUType,
27 MMUToICacheType)
28
29 from soc.experiment.mmu import MMU
30 from soc.experiment.dcache import DCache
31
32 #more imports
33
34 from soc.experiment.l0_cache import L0CacheBuffer2
35 from nmigen import Module, Signal, Mux, Elaboratable, Cat, Const
36 from nmigen.cli import rtlil
37
38 from soc.config.test.test_pi2ls import pi_ld, pi_st, pi_ldst
39
40 from soc.experiment.pimem import PortInterfaceBase
41
42 from nmigen.compat.sim import run_simulation, Settle
43
44 # guess: those four need to be connected
45 #class DCacheToLoadStore1Type(RecordObject): dcache.d_out
46 #class LoadStore1ToDCacheType(RecordObject): dcache.d_in
47 #class LoadStore1ToMMUType(RecordObject): mmu.l_in
48 #class MMUToLoadStore1Type(RecordObject): mmu.l_out
49 # will take at least one week (10.10.2020)
50 # many unconnected signals
51
52
53 class TestMicrowattMemoryPortInterface(PortInterfaceBase):
54 """TestMicrowattMemoryPortInterface
55
56 This is a Test Class for MMU and DCache conforming to PortInterface
57 """
58
59 def __init__(self, mmu, dcache, regwid=64, addrwid=4):
60 super().__init__(regwid, addrwid)
61 self.mmu = mmu
62 self.dcache = dcache
63
64 def set_wr_addr(self, m, addr, mask, misalign, msr_pr):
65 m.d.comb += self.dcache.d_in.addr.eq(addr)
66 m.d.comb += self.mmu.l_in.addr.eq(addr)
67 m.d.comb += self.mmu.l_in.load.eq(0)
68 m.d.comb += self.mmu.l_in.priv.eq(1) # TODO put msr_pr here
69 m.d.comb += self.mmu.l_in.valid.eq(1)
70
71 def set_rd_addr(self, m, addr, mask, misalign, msr_pr):
72 m.d.comb += self.dcache.d_in.addr.eq(addr)
73 m.d.comb += self.mmu.l_in.addr.eq(addr)
74 m.d.comb += self.mmu.l_in.load.eq(1)
75 m.d.comb += self.mmu.l_in.priv.eq(1) # TODO put msr_pr here
76 m.d.comb += self.mmu.l_in.valid.eq(1)
77
78 def set_wr_data(self, m, data, wen):
79 m.d.comb += self.dcache.d_in.data.eq(data) # write st to mem
80 m.d.comb += self.dcache.d_in.load.eq(~wen) # enable writes
81 st_ok = Const(1, 1)
82 return st_ok
83
84 # LoadStore1ToDCacheType
85 # valid
86 # dcbz
87 # nc
88 # reserve
89 # virt_mode
90 # addr # TODO
91 # byte_sel(8)
92
93 def get_rd_data(self, m):
94 # get data from dcache
95 ld_ok = self.mmu.l_out.done
96 data = self.dcache.d_out.data
97 return data, ld_ok
98
99
100 # DCacheToLoadStore1Type NC
101 # store_done
102 # error
103 # cache_paradox
104
105 return None
106
107 def elaborate(self, platform):
108 m = super().elaborate(platform)
109
110 m.submodules.mmu = self.mmu
111 m.submodules.dcache = self.dcache
112
113 # link mmu and dcache together
114 m.d.comb += self.dcache.m_in.eq(self.mmu.d_out)
115 m.d.comb += self.mmu.d_in.eq(self.dcache.m_out)
116
117 return m
118
119 def ports(self):
120 yield from super().ports()
121 # TODO: memory ports
122
123 stop = False
124
125
126 def wb_get(dc):
127 """simulator process for getting memory load requests
128 """
129
130 global stop
131
132 def b(x):
133 return int.from_bytes(x.to_bytes(8, byteorder='little'),
134 byteorder='big', signed=False)
135
136 mem = {0x10000: # PARTITION_TABLE_2
137 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
138 b(0x800000000100000b),
139
140 0x30000: # RADIX_ROOT_PTE
141 # V = 1 L = 0 NLB = 0x400 NLS = 9
142 b(0x8000000000040009),
143
144 0x40000: # RADIX_SECOND_LEVEL
145 # V = 1 L = 1 SW = 0 RPN = 0
146 # R = 1 C = 1 ATT = 0 EAA 0x7
147 b(0xc000000000000187),
148
149 0x1000000: # PROCESS_TABLE_3
150 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
151 b(0x40000000000300ad),
152 }
153
154 while not stop:
155 while True: # wait for dc_valid
156 if stop:
157 return
158 cyc = yield (dc.wb_out.cyc)
159 stb = yield (dc.wb_out.stb)
160 if cyc and stb:
161 break
162 yield
163 addr = (yield dc.wb_out.adr) << 3
164 if addr not in mem:
165 print (" WB LOOKUP NO entry @ %x, returning zero" % (addr))
166
167 data = mem.get(addr, 0)
168 yield dc.wb_in.dat.eq(data)
169 print (" DCACHE get %x data %x" % (addr, data))
170 yield dc.wb_in.ack.eq(1)
171 yield
172 yield dc.wb_in.ack.eq(0)
173 yield
174
175
176 def mmu_lookup(dut, addr):
177 mmu = dut.mmu
178 global stop
179
180 print("pi_ld")
181 yield from pi_ld(dut.pi, addr, 1)
182 print("pi_ld done")
183 """
184 # original test code kept for reference
185 while not stop: # wait for dc_valid / err
186 print("waiting for mmu")
187 l_done = yield (mmu.l_out.done)
188 l_err = yield (mmu.l_out.err)
189 l_badtree = yield (mmu.l_out.badtree)
190 l_permerr = yield (mmu.l_out.perm_error)
191 l_rc_err = yield (mmu.l_out.rc_error)
192 l_segerr = yield (mmu.l_out.segerr)
193 l_invalid = yield (mmu.l_out.invalid)
194 if (l_done or l_err or l_badtree or
195 l_permerr or l_rc_err or l_segerr or l_invalid):
196 break
197 yield
198 """
199 phys_addr = yield mmu.d_out.addr
200 pte = yield mmu.d_out.pte
201 l_done = yield (mmu.l_out.done)
202 l_err = yield (mmu.l_out.err)
203 l_badtree = yield (mmu.l_out.badtree)
204 print ("translated done %d err %d badtree %d addr %x pte %x" % \
205 (l_done, l_err, l_badtree, phys_addr, pte))
206 yield
207 yield mmu.l_in.valid.eq(0)
208
209 return phys_addr
210
211 def mmu_sim(dut):
212 mmu = dut.mmu
213 global stop
214 yield mmu.rin.prtbl.eq(0x1000000) # set process table
215 yield
216
217 addr = 0x10000
218 data = 0
219 print("pi_st")
220
221 # TODO mmu_lookup using port interface
222 # set inputs
223 phys_addr = yield from mmu_lookup(dut, 0x10000)
224 assert phys_addr == 0x40000
225
226 phys_addr = yield from mmu_lookup(dut, 0x10000)
227 assert phys_addr == 0x40000
228
229 stop = True
230
231
232 def test_mmu():
233 mmu = MMU()
234 dcache = DCache()
235 dut = TestMicrowattMemoryPortInterface(mmu, dcache)
236
237 m = Module()
238 m.submodules.dut = dut
239
240 # nmigen Simulation
241 sim = Simulator(m)
242 sim.add_clock(1e-6)
243
244 sim.add_sync_process(wrap(mmu_sim(dut)))
245 sim.add_sync_process(wrap(wb_get(dcache)))
246 with sim.write_vcd('test_mmu_pi.vcd'):
247 sim.run()
248
249
250 if __name__ == '__main__':
251 test_mmu()