dfbc49fc0231391f6ec38a79480aee5637c3bbb4
2 Based on microwatt mmu.vhdl
4 * https://bugs.libre-soc.org/show_bug.cgi?id=491
5 * https://bugs.libre-soc.org/show_bug.cgi?id=450
8 from nmigen
import Elaboratable
, Module
, Signal
, Shape
, unsigned
, Cat
, Mux
9 from nmigen
import Record
, Memory
10 from nmigen
import Const
11 from soc
.fu
.mmu
.pipe_data
import MMUInputData
, MMUOutputData
, MMUPipeSpec
12 from nmutil
.singlepipe
import ControlBase
13 from nmutil
.util
import rising_edge
15 from soc
.experiment
.mmu
import MMU
17 from openpower
.consts
import MSR
18 from openpower
.decoder
.power_fields
import DecodeFields
19 from openpower
.decoder
.power_fieldsn
import SignalBitRange
20 from openpower
.decoder
.power_decoder2
import decode_spr_num
21 from openpower
.decoder
.power_enums
import MicrOp
23 from soc
.experiment
.mem_types
import LoadStore1ToMMUType
24 from soc
.experiment
.mem_types
import MMUToLoadStore1Type
26 from soc
.fu
.ldst
.loadstore
import LoadStore1
, TestSRAMLoadStore1
27 from nmutil
.util
import Display
29 class FSMMMUStage(ControlBase
):
32 FSM-based MMU: must call set_ldst_interface and pass in an instance
33 of a LoadStore1. this to comply with the ConfigMemoryPortInterface API
35 this Function Unit is extremely unusual in that it actually stores a
36 "thing" rather than "processes inputs and produces outputs". hence
37 why it has to be a FSM. linking up LD/ST however is going to have
38 to be done back in Issuer (or Core). sorted: call set_ldst_interface
40 def __init__(self
, pspec
):
45 self
.p
.i_data
= MMUInputData(pspec
)
46 self
.n
.o_data
= MMUOutputData(pspec
)
50 # debugging output for gtkw
51 self
.debug0
= Signal(4)
52 self
.illegal
= Signal()
54 # for SPR field number access
56 self
.fields
= DecodeFields(SignalBitRange
, [i
.ctx
.op
.insn
])
57 self
.fields
.create_specs()
59 def set_ldst_interface(self
, ldst
):
60 """must be called back in Core, after FUs have been set up.
61 one of those will be the MMU (us!) but the LoadStore1 instance
62 must be set up in ConfigMemoryPortInterface. sigh.
64 # incoming PortInterface
66 self
.dcache
= self
.ldst
.dcache
67 self
.pi
= self
.ldst
.pi
69 def elaborate(self
, platform
):
70 assert hasattr(self
, "dcache"), "remember to call set_ldst_interface"
71 m
= super().elaborate(platform
)
72 comb
, sync
= m
.d
.comb
, m
.d
.sync
75 # link mmu and dcache together
76 m
.submodules
.mmu
= mmu
= self
.mmu
77 ldst
= self
.ldst
# managed externally: do not add here
78 m
.d
.comb
+= dcache
.m_in
.eq(mmu
.d_out
) # MMUToDCacheType
79 m
.d
.comb
+= mmu
.d_in
.eq(dcache
.m_out
) # DCacheToMMUType
81 l_in
, l_out
= mmu
.l_in
, mmu
.l_out
82 d_in
, d_out
= dcache
.d_in
, dcache
.d_out
83 wb_out
, wb_in
= dcache
.wb_out
, dcache
.wb_in
85 # link ldst and MMU together
86 comb
+= l_in
.eq(ldst
.m_out
)
87 comb
+= ldst
.m_in
.eq(l_out
)
89 i_data
, o_data
= self
.p
.i_data
, self
.n
.o_data
90 a_i
, b_i
, o
, spr1_o
= i_data
.ra
, i_data
.rb
, o_data
.o
, o_data
.spr1
97 m
.d
.comb
+= self
.n
.o_valid
.eq(busy
& done
)
98 m
.d
.comb
+= self
.p
.o_ready
.eq(~busy
)
100 # take copy of X-Form SPR field
101 x_fields
= self
.fields
.FormXFX
102 spr
= Signal(len(x_fields
.SPR
))
103 comb
+= spr
.eq(decode_spr_num(x_fields
.SPR
))
105 # ok so we have to "pulse" the MMU (or dcache) rather than
106 # hold the valid hi permanently. guess what this does...
109 m
.d
.comb
+= blip
.eq(rising_edge(m
, valid
))
112 with m
.If(self
.p
.i_valid
):
116 # based on the Micro-Op, we work out which of MMU or DCache
117 # should "action" the operation. one of MMU or DCache gets
118 # enabled ("valid") and we twiddle our thumbs until it
121 # WIP: properly implement MicrOp.OP_MTSPR and MicrOp.OP_MFSPR
123 with m
.Switch(op
.insn_type
):
124 with m
.Case(MicrOp
.OP_MTSPR
):
125 comb
+= Display("MMUTEST: OP_MTSPR: spr=%i", spr
)
126 # despite redirection this FU **MUST** behave exactly
127 # like the SPR FU. this **INCLUDES** updating the SPR
128 # regfile because the CSV file entry for OP_MTSPR
129 # categorically defines and requires the expectation
130 # that the CompUnit **WILL** write to the regfile.
131 comb
+= spr1_o
.data
.eq(a_i
)
132 comb
+= spr1_o
.ok
.eq(1)
133 # subset SPR: first check a few bits
134 # XXX NOTE this must now cover **FOUR** values: this
135 # test might not be adequate. DSISR, DAR, PGTBL and PID
136 # must ALL be covered here.
137 with m
.If(~spr
[9] & ~spr
[5]):
138 comb
+= self
.debug0
.eq(3)
139 #if matched update local cached value
140 #commented out because there is a driver conflict
141 comb
+= ldst
.sprval_in
.eq(a_i
)
142 comb
+= ldst
.mmu_set_spr
.eq(1)
144 comb
+= ldst
.mmu_set_dar
.eq(1)
146 comb
+= ldst
.mmu_set_dsisr
.eq(1)
148 # pass it over to the MMU instead
151 comb
+= self
.debug0
.eq(4)
152 # blip the MMU and wait for it to complete
153 comb
+= valid
.eq(1) # start "pulse"
154 comb
+= l_in
.valid
.eq(blip
) # start
155 comb
+= l_in
.mtspr
.eq(1) # mtspr mode
156 comb
+= l_in
.sprn
.eq(spr
) # which SPR
157 comb
+= l_in
.rs
.eq(a_i
) # incoming operand (RS)
158 comb
+= done
.eq(1) # FIXME l_out.done
160 with m
.Case(MicrOp
.OP_MFSPR
):
161 comb
+= Display("MMUTEST: OP_MFSPR: spr=%i returns=%i",
163 # partial SPR number decoding perfectly fine
164 with m
.If(spr
[9] | spr
[5]):
165 # identified as an MMU OP_MFSPR, contact the MMU.
166 # interestingly, the read is combinatorial: no need
167 # to set "valid", just set the SPR number
168 comb
+= l_in
.sprn
.eq(spr
) # which SPR
169 comb
+= o
.data
.eq(l_out
.sprval
)
171 # identified as DSISR or DAR. again: read the SPR
172 # directly, combinatorial access
174 comb
+= o
.data
.eq(ldst
.dar
)
176 comb
+= o
.data
.eq(ldst
.dsisr
)
181 with m
.Case(MicrOp
.OP_TLBIE
):
182 comb
+= Display("MMUTEST: OP_TLBIE: insn_bits=%i", spr
)
183 # pass TLBIE request to MMU (spec: v3.0B p1034)
184 # note that the spr is *not* an actual spr number, it's
185 # just that those bits happen to match with field bits
187 comb
+= Display("TLBIE: %i %i", spr
, l_out
.done
)
188 comb
+= valid
.eq(1) # start "pulse"
189 comb
+= l_in
.valid
.eq(blip
) # start
190 comb
+= l_in
.tlbie
.eq(1) # mtspr mode
191 comb
+= l_in
.sprn
.eq(spr
) # use sprn to send insn bits
192 comb
+= l_in
.addr
.eq(b_i
) # incoming operand (RB)
193 comb
+= done
.eq(l_out
.done
) # zzzz
194 comb
+= self
.debug0
.eq(2)
196 with m
.Case(MicrOp
.OP_ILLEGAL
):
197 comb
+= self
.illegal
.eq(1)
199 with m
.If(self
.n
.i_ready
& self
.n
.o_valid
):