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 # glue logic for microwatt mmu and dcache
22 class LoadStore1(PortInterfaceBase
):
23 def __init__(self
, regwid
=64, addrwid
=4):
24 super().__init
__(regwid
, addrwid
)
25 self
.d_in
= LoadStore1ToDCacheType()
26 self
.d_out
= DCacheToLoadStore1Type()
27 self
.l_in
= LoadStore1ToMMUType()
28 self
.l_out
= MMUToLoadStore1Type()
30 def set_wr_addr(self
, m
, addr
, mask
):
31 m
.d
.comb
+= self
.d_in
.addr
.eq(addr
)
32 m
.d
.comb
+= self
.l_in
.addr
.eq(addr
)
36 def set_rd_addr(self
, m
, addr
, mask
):
37 m
.d
.comb
+= self
.d_in
.addr
.eq(addr
)
38 m
.d
.comb
+= self
.l_in
.addr
.eq(addr
)
42 def set_wr_data(self
, m
, data
, wen
):
43 m
.d
.comb
+= self
.d_in
.data
.eq(data
)
48 def get_rd_data(self
, m
):
50 data
= self
.d_out
.data
53 def elaborate(self
, platform
):
54 m
= super().elaborate(platform
)
60 yield from super().ports()
63 class FSMMMUStage(ControlBase
):
64 def __init__(self
, pspec
):
69 self
.p
.data_i
= MMUInputData(pspec
)
70 self
.n
.data_o
= MMUOutputData(pspec
)
72 # incoming PortInterface
73 self
.ldst
= LoadStore1()
74 self
.pi
= self
.ldst
.pi
76 # this Function Unit is extremely unusual in that it actually stores a
77 # "thing" rather than "processes inputs and produces outputs". hence
78 # why it has to be a FSM. linking up LD/ST however is going to have
79 # to be done back in Issuer (or Core)
82 self
.dcache
= DCache()
84 # make life a bit easier in Core
85 self
.pspec
.mmu
= self
.mmu
86 self
.pspec
.dcache
= self
.dcache
88 # debugging output for gtkw
89 self
.debug0
= Signal(4)
90 #self.debug1 = Signal(64)
91 #self.debug2 = Signal(64)
92 #self.debug3 = Signal(64)
94 # for SPR field number access
96 self
.fields
= DecodeFields(SignalBitRange
, [i
.ctx
.op
.insn
])
97 self
.fields
.create_specs()
99 def elaborate(self
, platform
):
100 m
= super().elaborate(platform
)
103 # link mmu and dcache together
104 m
.submodules
.dcache
= dcache
= self
.dcache
105 m
.submodules
.mmu
= mmu
= self
.mmu
106 m
.submodules
.ldst
= ldst
= self
.ldst
107 m
.d
.comb
+= dcache
.m_in
.eq(mmu
.d_out
)
108 m
.d
.comb
+= mmu
.d_in
.eq(dcache
.m_out
)
109 l_in
, l_out
= mmu
.l_in
, mmu
.l_out
110 d_in
, d_out
= dcache
.d_in
, dcache
.d_out
112 comb
+= l_in
.eq(self
.ldst
.l_in
)
113 comb
+= self
.ldst
.l_out
.eq(l_out
)
114 comb
+= d_in
.eq(self
.ldst
.d_in
)
115 comb
+= self
.ldst
.d_out
.eq(self
.dcache
.d_out
)
117 data_i
, data_o
= self
.p
.data_i
, self
.n
.data_o
118 a_i
, b_i
, o
= data_i
.ra
, data_i
.rb
, data_o
.o
121 # TODO: link these SPRs somewhere
128 m
.d
.comb
+= self
.n
.valid_o
.eq(busy
& done
)
129 m
.d
.comb
+= self
.p
.ready_o
.eq(~busy
)
131 # take copy of X-Form SPR field
132 x_fields
= self
.fields
.FormXFX
133 spr
= Signal(len(x_fields
.SPR
))
134 comb
+= spr
.eq(decode_spr_num(x_fields
.SPR
))
136 # ok so we have to "pulse" the MMU (or dcache) rather than
137 # hold the valid hi permanently. guess what this does...
140 m
.d
.comb
+= blip
.eq(rising_edge(m
, valid
))
143 with m
.If(self
.p
.valid_i
):
144 m
.d
.sync
+= busy
.eq(1)
147 # based on the Micro-Op, we work out which of MMU or DCache
148 # should "action" the operation. one of MMU or DCache gets
149 # enabled ("valid") and we twiddle our thumbs until it
151 with m
.Switch(op
.insn_type
):
152 with m
.Case(MicrOp
.OP_MTSPR
):
153 # subset SPR: first check a few bits
154 with m
.If(~spr
[9] & ~spr
[5]):
156 comb
+= dsisr
.eq(a_i
[:32])
160 # pass it over to the MMU instead
162 # blip the MMU and wait for it to complete
163 comb
+= valid
.eq(1) # start "pulse"
164 comb
+= l_in
.valid
.eq(blip
) # start
165 comb
+= l_in
.mtspr
.eq(1) # mtspr mode
166 comb
+= l_in
.sprn
.eq(spr
) # which SPR
167 comb
+= l_in
.rs
.eq(a_i
) # incoming operand (RS)
168 comb
+= done
.eq(l_out
.done
) # zzzz
170 with m
.Case(MicrOp
.OP_MFSPR
):
171 # subset SPR: first check a few bits
172 with m
.If(~spr
[9] & ~spr
[5]):
174 comb
+= o
.data
.eq(dsisr
)
176 comb
+= o
.data
.eq(dar
)
179 # pass it over to the MMU instead
181 # blip the MMU and wait for it to complete
182 comb
+= valid
.eq(1) # start "pulse"
183 comb
+= l_in
.valid
.eq(blip
) # start
184 comb
+= l_in
.mtspr
.eq(0) # mfspr!=mtspr
185 comb
+= l_in
.sprn
.eq(spr
) # which SPR
186 comb
+= l_in
.rs
.eq(a_i
) # incoming operand (RS)
187 comb
+= o
.data
.eq(l_out
.sprval
) # SPR from MMU
188 comb
+= o
.ok
.eq(l_out
.done
) # only when l_out valid
189 comb
+= done
.eq(l_out
.done
) # zzzz
191 with m
.Case(MicrOp
.OP_DCBZ
):
192 # activate dcbz mode (spec: v3.0B p850)
193 comb
+= valid
.eq(1) # start "pulse"
194 comb
+= d_in
.valid
.eq(blip
) # start
195 comb
+= d_in
.dcbz
.eq(1) # dcbz mode
196 comb
+= d_in
.addr
.eq(a_i
+ b_i
) # addr is (RA|0) + RB
197 comb
+= done
.eq(d_out
.store_done
) # TODO
198 comb
+= self
.debug0
.eq(1)
201 with m
.Case(MicrOp
.OP_TLBIE
):
202 # pass TLBIE request to MMU (spec: v3.0B p1034)
203 # note that the spr is *not* an actual spr number, it's
204 # just that those bits happen to match with field bits
206 comb
+= valid
.eq(1) # start "pulse"
207 comb
+= l_in
.valid
.eq(blip
) # start
208 comb
+= l_in
.tlbie
.eq(1) # mtspr mode
209 comb
+= l_in
.sprn
.eq(spr
) # use sprn to send insn bits
210 comb
+= l_in
.addr
.eq(b_i
) # incoming operand (RB)
211 comb
+= done
.eq(l_out
.done
) # zzzz
212 comb
+= self
.debug0
.eq(2)
214 with m
.If(self
.n
.ready_i
& self
.n
.valid_o
):
215 m
.d
.sync
+= busy
.eq(0)