add misalign flag to PortInterfaceBase
[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 class TestMicrowattMemoryPortInterface(PortInterfaceBase):
47 """TestMicrowattMemoryPortInterface
48
49 This is a Test Class for MMU and DCache conforming to PortInterface
50 """
51
52 def __init__(self, mmu, dcache, regwid=64, addrwid=4,):
53 super().__init__(regwid, addrwid)
54 self.mmu = mmu
55 self.dcache = dcache
56
57 def set_wr_addr(self, m, addr, mask, misalign):
58 m.d.comb += self.dcache.d_in.addr.eq(addr)
59 m.d.comb += self.mmu.l_in.addr.eq(addr)
60 m.d.comb += self.mmu.l_in.load.eq(0)
61 m.d.comb += self.mmu.l_in.priv.eq(1)
62 m.d.comb += self.mmu.l_in.valid.eq(1)
63
64 def set_rd_addr(self, m, addr, mask, misalign):
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(1)
68 m.d.comb += self.mmu.l_in.priv.eq(1)
69 m.d.comb += self.mmu.l_in.valid.eq(1)
70
71 def set_wr_data(self, m, data, wen):
72 m.d.comb += self.dcache.d_in.data.eq(data) # write st to mem
73 m.d.comb += self.dcache.d_in.load.eq(~wen) # enable writes
74 st_ok = Const(1, 1)
75 return st_ok
76
77 # LoadStore1ToDCacheType
78 # valid
79 # dcbz
80 # nc
81 # reserve
82 # virt_mode
83 # addr # TODO
84 # byte_sel(8)
85
86 def get_rd_data(self, m):
87 # get data from dcache
88 ld_ok = self.mmu.l_out.done
89 data = self.dcache.d_out.data
90 return data, ld_ok
91
92 # DCacheToLoadStore1Type NC
93 # store_done
94 # error
95 # cache_paradox
96
97 return None
98
99 def elaborate(self, platform):
100 m = super().elaborate(platform)
101
102 m.submodules.mmu = self.mmu
103 m.submodules.dcache = self.dcache
104
105 # link mmu and dcache together
106 m.d.comb += self.dcache.m_in.eq(self.mmu.d_out)
107 m.d.comb += self.mmu.d_in.eq(self.dcache.m_out)
108
109 return m
110
111 def ports(self):
112 yield from super().ports()
113 # TODO: memory ports
114
115 stop = False
116
117
118 def wb_get(dc):
119 """simulator process for getting memory load requests
120 """
121
122 global stop
123
124 def b(x):
125 return int.from_bytes(x.to_bytes(8, byteorder='little'),
126 byteorder='big', signed=False)
127
128 mem = {0x10000: # PARTITION_TABLE_2
129 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
130 b(0x800000000100000b),
131
132 0x30000: # RADIX_ROOT_PTE
133 # V = 1 L = 0 NLB = 0x400 NLS = 9
134 b(0x8000000000040009),
135
136 0x40000: # RADIX_SECOND_LEVEL
137 # V = 1 L = 1 SW = 0 RPN = 0
138 # R = 1 C = 1 ATT = 0 EAA 0x7
139 b(0xc000000000000187),
140
141 0x1000000: # PROCESS_TABLE_3
142 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
143 b(0x40000000000300ad),
144 }
145
146 while not stop:
147 while True: # wait for dc_valid
148 if stop:
149 return
150 cyc = yield (dc.wb_out.cyc)
151 stb = yield (dc.wb_out.stb)
152 if cyc and stb:
153 break
154 yield
155 addr = (yield dc.wb_out.adr) << 3
156 if addr not in mem:
157 print (" DCACHE LOOKUP FAIL %x" % (addr))
158 stop = True
159 return
160
161 yield
162 data = mem[addr]
163 yield dc.wb_in.dat.eq(data)
164 print (" DCACHE get %x data %x" % (addr, data))
165 yield dc.wb_in.ack.eq(1)
166 yield
167 yield dc.wb_in.ack.eq(0)
168
169
170 def mmu_lookup(dut, addr):
171 mmu = dut.mmu
172 global stop
173
174 print("pi_st")
175 yield from pi_ld(dut.pi, addr, 1)
176 print("pi_st_done")
177 """
178 # original test code kept for reference
179 while not stop: # wait for dc_valid / err
180 print("waiting for mmu")
181 l_done = yield (mmu.l_out.done)
182 l_err = yield (mmu.l_out.err)
183 l_badtree = yield (mmu.l_out.badtree)
184 l_permerr = yield (mmu.l_out.perm_error)
185 l_rc_err = yield (mmu.l_out.rc_error)
186 l_segerr = yield (mmu.l_out.segerr)
187 l_invalid = yield (mmu.l_out.invalid)
188 if (l_done or l_err or l_badtree or
189 l_permerr or l_rc_err or l_segerr or l_invalid):
190 break
191 yield
192 """
193 phys_addr = yield mmu.d_out.addr
194 pte = yield mmu.d_out.pte
195 l_done = yield (mmu.l_out.done)
196 l_err = yield (mmu.l_out.err)
197 l_badtree = yield (mmu.l_out.badtree)
198 print ("translated done %d err %d badtree %d addr %x pte %x" % \
199 (l_done, l_err, l_badtree, phys_addr, pte))
200 yield
201 yield mmu.l_in.valid.eq(0)
202
203 return phys_addr
204
205 def mmu_sim(dut):
206 mmu = dut.mmu
207 global stop
208 yield mmu.rin.prtbl.eq(0x1000000) # set process table
209 yield
210
211 addr = 0x10000
212 data = 0
213 print("pi_st")
214
215 # TODO mmu_lookup using port interface
216 # set inputs
217 phys_addr = yield from mmu_lookup(dut, 0x10000)
218 assert phys_addr == 0x40000
219
220 phys_addr = yield from mmu_lookup(dut, 0x10000)
221 assert phys_addr == 0x40000
222
223 stop = True
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 if __name__ == '__main__':
243 test_mmu()