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