1 from nmigen
import Elaboratable
, Module
, Signal
, Shape
, unsigned
, Cat
, Mux
2 from nmigen
import Const
3 from soc
.fu
.mmu
.pipe_data
import MMUInputData
, MMUOutputData
, MMUPipeSpec
4 from nmutil
.singlepipe
import ControlBase
5 from nmutil
.util
import rising_edge
7 from soc
.experiment
.mmu
import MMU
8 from soc
.experiment
.dcache
import DCache
10 from soc
.decoder
.power_fields
import DecodeFields
11 from soc
.decoder
.power_fieldsn
import SignalBitRange
12 from soc
.decoder
.power_decoder2
import decode_spr_num
13 from soc
.decoder
.power_enums
import MicrOp
, SPR
, XER_bits
15 from soc
.experiment
.pimem
import PortInterface
16 from soc
.experiment
.pimem
import PortInterfaceBase
18 from soc
.experiment
.mem_types
import LoadStore1ToDCacheType
, LoadStore1ToMMUType
19 from soc
.experiment
.mem_types
import DCacheToLoadStore1Type
, MMUToLoadStore1Type
21 # for testing purposes
22 from soc
.experiment
.testmem
import TestMemory
24 # glue logic for microwatt mmu and dcache
25 class LoadStore1(PortInterfaceBase
):
26 def __init__(self
, regwid
=64, addrwid
=4):
27 super().__init
__(regwid
, addrwid
)
28 self
.d_in
= LoadStore1ToDCacheType()
29 self
.d_out
= DCacheToLoadStore1Type()
30 self
.l_in
= LoadStore1ToMMUType()
31 self
.l_out
= MMUToLoadStore1Type()
32 # for debugging with gtkwave only
33 self
.debug1
= Signal()
34 self
.debug2
= Signal()
36 def set_wr_addr(self
, m
, addr
, mask
):
37 #m.d.comb += self.d_in.valid.eq(1)
38 #m.d.comb += self.l_in.valid.eq(1)
39 #m.d.comb += self.d_in.load.eq(0)
40 #m.d.comb += self.l_in.load.eq(0)
41 m
.d
.comb
+= self
.d_in
.addr
.eq(addr
)
42 m
.d
.comb
+= self
.l_in
.addr
.eq(addr
)
46 def set_rd_addr(self
, m
, addr
, mask
):
47 m
.d
.comb
+= self
.d_in
.valid
.eq(1)
48 m
.d
.comb
+= self
.l_in
.valid
.eq(1)
49 m
.d
.comb
+= self
.d_in
.load
.eq(1)
50 m
.d
.comb
+= self
.l_in
.load
.eq(1)
51 m
.d
.comb
+= self
.d_in
.addr
.eq(addr
)
52 m
.d
.comb
+= self
.l_in
.addr
.eq(addr
)
53 m
.d
.comb
+= self
.debug1
.eq(1)
54 # m.d.comb += self.debug2.eq(1)
55 # connect testmem first
56 return None #FIXME return value
58 def set_wr_data(self
, m
, data
, wen
):
59 m
.d
.comb
+= self
.d_in
.data
.eq(data
)
64 def get_rd_data(self
, m
):
66 data
= self
.d_out
.data
69 def elaborate(self
, platform
):
70 m
= super().elaborate(platform
)
75 exc
= self
.pi
.exception_o
77 #happened, alignment, instr_fault, invalid,
78 m
.d
.comb
+= exc
.happened
.eq(d_out
.error | l_out
.err
)
79 m
.d
.comb
+= exc
.invalid
.eq(l_out
.invalid
)
81 #badtree, perm_error, rc_error, segment_fault
82 m
.d
.comb
+= exc
.badtree
.eq(l_out
.badtree
)
83 m
.d
.comb
+= exc
.perm_error
.eq(l_out
.perm_error
)
84 m
.d
.comb
+= exc
.rc_error
.eq(l_out
.rc_error
)
85 m
.d
.comb
+= exc
.segment_fault
.eq(l_out
.segerr
)
87 # TODO connect those signals somewhere
88 #print(d_out.valid) -> no error
89 #print(d_out.store_done) -> no error
90 #print(d_out.cache_paradox) -> ?
91 #print(l_out.done) -> no error
93 # TODO some exceptions set SPRs
98 yield from super().ports()
101 class FSMMMUStage(ControlBase
):
102 def __init__(self
, pspec
):
107 self
.p
.data_i
= MMUInputData(pspec
)
108 self
.n
.data_o
= MMUOutputData(pspec
)
110 # incoming PortInterface
111 self
.ldst
= LoadStore1() # TODO make this depend on pspec
112 self
.pi
= self
.ldst
.pi
114 # this Function Unit is extremely unusual in that it actually stores a
115 # "thing" rather than "processes inputs and produces outputs". hence
116 # why it has to be a FSM. linking up LD/ST however is going to have
117 # to be done back in Issuer (or Core)
120 self
.dcache
= DCache()
123 # for verification of DCache
124 # TODO: create connection to real memory, backend memory interface
125 self
.testmem
= TestMemory(regwid
, aw
, granularity
=regwid
//8, init
=False)
127 # make life a bit easier in Core
128 self
.pspec
.mmu
= self
.mmu
129 self
.pspec
.dcache
= self
.dcache
131 # debugging output for gtkw
132 self
.debug0
= Signal(4)
133 self
.debug_wb_cyc
= Signal()
134 self
.debug_wb_stb
= Signal()
135 self
.debug_wb_we
= Signal()
136 #self.debug1 = Signal(64)
137 #self.debug2 = Signal(64)
138 #self.debug3 = Signal(64)
139 self
.illegal
= Signal()
141 # for SPR field number access
143 self
.fields
= DecodeFields(SignalBitRange
, [i
.ctx
.op
.insn
])
144 self
.fields
.create_specs()
146 def elaborate(self
, platform
):
147 m
= super().elaborate(platform
)
150 # link mmu and dcache together
151 m
.submodules
.dcache
= dcache
= self
.dcache
152 m
.submodules
.mmu
= mmu
= self
.mmu
153 m
.submodules
.ldst
= ldst
= self
.ldst
154 m
.submodules
.testmem
= testmem
= self
.testmem
155 m
.d
.comb
+= dcache
.m_in
.eq(mmu
.d_out
)
156 m
.d
.comb
+= mmu
.d_in
.eq(dcache
.m_out
)
157 l_in
, l_out
= mmu
.l_in
, mmu
.l_out
158 d_in
, d_out
= dcache
.d_in
, dcache
.d_out
159 wb_out
, wb_in
= dcache
.wb_out
, dcache
.wb_in
161 # link ldst and dcache together
162 comb
+= l_in
.eq(self
.ldst
.l_in
)
163 comb
+= self
.ldst
.l_out
.eq(l_out
)
164 comb
+= d_in
.eq(self
.ldst
.d_in
)
165 comb
+= self
.ldst
.d_out
.eq(self
.dcache
.d_out
)
168 rdport
= self
.testmem
.rdport
169 comb
+= rdport
.addr
.eq(wb_out
.adr
)
170 comb
+= wb_in
.dat
.eq(rdport
.data
)
173 wrport
= self
.testmem
.wrport
174 comb
+= wrport
.addr
.eq(wb_out
.adr
)
175 comb
+= wrport
.data
.eq(wb_out
.dat
) # write st to mem
176 comb
+= wrport
.en
.eq(wb_out
.cyc
& wb_out
.we
) # enable writes
178 # connect DCache wishbone master to debugger
179 comb
+= self
.debug_wb_cyc
.eq(wb_out
.cyc
)
180 comb
+= self
.debug_wb_stb
.eq(wb_out
.stb
)
181 comb
+= self
.debug_wb_we
.eq(wb_out
.we
)
183 comb
+= wb_in
.stall
.eq(0)
184 # testmem only takes on cycle
185 with m
.If( wb_out
.cyc
):
186 m
.d
.sync
+= wb_in
.ack
.eq( wb_out
.stb
)
188 data_i
, data_o
= self
.p
.data_i
, self
.n
.data_o
189 a_i
, b_i
, o
= data_i
.ra
, data_i
.rb
, data_o
.o
192 # TODO: link these SPRs somewhere
199 m
.d
.comb
+= self
.n
.valid_o
.eq(busy
& done
)
200 m
.d
.comb
+= self
.p
.ready_o
.eq(~busy
)
202 # take copy of X-Form SPR field
203 x_fields
= self
.fields
.FormXFX
204 spr
= Signal(len(x_fields
.SPR
))
205 comb
+= spr
.eq(decode_spr_num(x_fields
.SPR
))
207 # ok so we have to "pulse" the MMU (or dcache) rather than
208 # hold the valid hi permanently. guess what this does...
211 m
.d
.comb
+= blip
.eq(rising_edge(m
, valid
))
214 with m
.If(self
.p
.valid_i
):
215 m
.d
.sync
+= busy
.eq(1)
218 # based on the Micro-Op, we work out which of MMU or DCache
219 # should "action" the operation. one of MMU or DCache gets
220 # enabled ("valid") and we twiddle our thumbs until it
223 # FIXME: properly implement MicrOp.OP_MTSPR and MicrOp.OP_MFSPR
225 with m
.Switch(op
.insn_type
):
226 with m
.Case(MicrOp
.OP_MTSPR
):
228 comb
+= self
.debug0
.eq(3)
230 # subset SPR: first check a few bits
231 with m.If(~spr[9] & ~spr[5]):
232 comb += self.debug0.eq(3)
234 comb += dsisr.eq(a_i[:32])
238 # pass it over to the MMU instead
240 comb += self.debug0.eq(4)
241 # blip the MMU and wait for it to complete
242 comb += valid.eq(1) # start "pulse"
243 comb += l_in.valid.eq(blip) # start
244 comb += l_in.mtspr.eq(1) # mtspr mode
245 comb += l_in.sprn.eq(spr) # which SPR
246 comb += l_in.rs.eq(a_i) # incoming operand (RS)
247 comb += done.eq(1) # FIXME l_out.done
250 with m
.Case(MicrOp
.OP_MFSPR
):
252 comb
+= self
.debug0
.eq(4)
254 # subset SPR: first check a few bits
255 with m.If(~spr[9] & ~spr[5]):
256 comb += self.debug0.eq(5)
258 comb += o.data.eq(dsisr)
260 comb += o.data.eq(dar)
263 # pass it over to the MMU instead
265 comb += self.debug0.eq(6)
266 # blip the MMU and wait for it to complete
267 comb += valid.eq(1) # start "pulse"
268 comb += l_in.valid.eq(blip) # start
269 comb += l_in.mtspr.eq(0) # mfspr!=mtspr
270 comb += l_in.sprn.eq(spr) # which SPR
271 comb += l_in.rs.eq(a_i) # incoming operand (RS)
272 comb += o.data.eq(l_out.sprval) # SPR from MMU
273 comb += o.ok.eq(l_out.done) # only when l_out valid
274 comb += done.eq(1) # FIXME l_out.done
277 with m
.Case(MicrOp
.OP_DCBZ
):
278 # activate dcbz mode (spec: v3.0B p850)
279 comb
+= valid
.eq(1) # start "pulse"
280 comb
+= d_in
.valid
.eq(blip
) # start
281 comb
+= d_in
.dcbz
.eq(1) # dcbz mode
282 comb
+= d_in
.addr
.eq(a_i
+ b_i
) # addr is (RA|0) + RB
283 comb
+= done
.eq(d_out
.store_done
) # TODO
284 comb
+= self
.debug0
.eq(1)
286 with m
.Case(MicrOp
.OP_TLBIE
):
287 # pass TLBIE request to MMU (spec: v3.0B p1034)
288 # note that the spr is *not* an actual spr number, it's
289 # just that those bits happen to match with field bits
291 comb
+= valid
.eq(1) # start "pulse"
292 comb
+= l_in
.valid
.eq(blip
) # start
293 comb
+= l_in
.tlbie
.eq(1) # mtspr mode
294 comb
+= l_in
.sprn
.eq(spr
) # use sprn to send insn bits
295 comb
+= l_in
.addr
.eq(b_i
) # incoming operand (RB)
296 comb
+= done
.eq(l_out
.done
) # zzzz
297 comb
+= self
.debug0
.eq(2)
298 with m
.Case(MicrOp
.OP_ILLEGAL
):
299 comb
+= self
.illegal
.eq(1)
301 with m
.If(self
.n
.ready_i
& self
.n
.valid_o
):
302 m
.d
.sync
+= busy
.eq(0)