comment out dsisr and dar in mmu FSM for now
[soc.git] / src / soc / fu / mmu / fsm.py
1 """
2 Based on microwatt mmu.vhdl
3
4 * https://bugs.libre-soc.org/show_bug.cgi?id=491
5 * https://bugs.libre-soc.org/show_bug.cgi?id=450
6 """
7
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
14
15 from soc.experiment.mmu import MMU
16
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
22
23 from soc.experiment.mem_types import LoadStore1ToMMUType
24 from soc.experiment.mem_types import MMUToLoadStore1Type
25
26 from soc.fu.ldst.loadstore import LoadStore1, TestSRAMLoadStore1
27 from nmutil.util import Display
28
29 class FSMMMUStage(ControlBase):
30 """FSM MMU
31
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
34
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
39 """
40 def __init__(self, pspec):
41 super().__init__()
42 self.pspec = pspec
43
44 # set up p/n data
45 self.p.i_data = MMUInputData(pspec)
46 self.n.o_data = MMUOutputData(pspec)
47
48 self.mmu = MMU()
49
50 # debugging output for gtkw
51 self.debug0 = Signal(4)
52 self.illegal = Signal()
53
54 # for SPR field number access
55 i = self.p.i_data
56 self.fields = DecodeFields(SignalBitRange, [i.ctx.op.insn])
57 self.fields.create_specs()
58
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.
63 """
64 # incoming PortInterface
65 self.ldst = ldst
66 self.dcache = self.ldst.dcache
67 self.pi = self.ldst.pi
68
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
73 dcache = self.dcache
74
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
80
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
84
85 # link ldst and MMU together
86 comb += l_in.eq(ldst.m_out)
87 comb += ldst.m_in.eq(l_out)
88
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
91 op = i_data.ctx.op
92 msr_i = op.msr
93 spr1_i = i_data.spr1
94
95 # these are set / got here *ON BEHALF* of LoadStore1
96 # XXX have to deal with this another way
97 # dsisr, dar = ldst.dsisr, ldst.dar
98
99 # busy/done signals
100 busy = Signal()
101 done = Signal()
102 m.d.comb += self.n.o_valid.eq(busy & done)
103 m.d.comb += self.p.o_ready.eq(~busy)
104
105 # take copy of X-Form SPR field
106 x_fields = self.fields.FormXFX
107 spr = Signal(len(x_fields.SPR))
108 comb += spr.eq(decode_spr_num(x_fields.SPR))
109
110 # based on MSR bits, set priv and virt mode. TODO: 32-bit mode
111 comb += d_in.priv_mode.eq(~msr_i[MSR.PR])
112 comb += d_in.virt_mode.eq(msr_i[MSR.DR])
113 #comb += d_in.mode_32bit.eq(msr_i[MSR.SF]) # ?? err
114
115 # ok so we have to "pulse" the MMU (or dcache) rather than
116 # hold the valid hi permanently. guess what this does...
117 valid = Signal()
118 blip = Signal()
119 m.d.comb += blip.eq(rising_edge(m, valid))
120
121 with m.If(~busy):
122 with m.If(self.p.i_valid):
123 sync += busy.eq(1)
124 with m.Else():
125
126 # based on the Micro-Op, we work out which of MMU or DCache
127 # should "action" the operation. one of MMU or DCache gets
128 # enabled ("valid") and we twiddle our thumbs until it
129 # responds ("done").
130
131 # WIP: properly implement MicrOp.OP_MTSPR and MicrOp.OP_MFSPR
132
133 with m.Switch(op.insn_type):
134 with m.Case(MicrOp.OP_MTSPR):
135 comb += Display("MMUTEST: OP_MTSPR: spr=%i", spr)
136 # despite redirection this FU **MUST** behave exactly
137 # like the SPR FU. this **INCLUDES** updating the SPR
138 # regfile because the CSV file entry for OP_MTSPR
139 # categorically defines and requires the expectation
140 # that the CompUnit **WILL** write to the regfile.
141 comb += spr1_o.data.eq(a_i)
142 comb += spr1_o.ok.eq(1)
143 # subset SPR: first check a few bits
144 # XXX NOTE this must now cover **FOUR** values: this
145 # test might not be adequate. DSISR, DAR, PGTBL and PID
146 # must ALL be covered here.
147 with m.If(~spr[9] & ~spr[5]):
148 comb += self.debug0.eq(3)
149 #if matched update local cached value
150 #commented out because there is a driver conflict
151 #with m.If(spr[0]):
152 # sync += dsisr.eq(a_i[:32])
153 #with m.Else():
154 # sync += dar.eq(a_i)
155 comb += done.eq(1)
156 # pass it over to the MMU instead
157 with m.Else():
158 # PGTBL and PID
159 comb += self.debug0.eq(4)
160 # blip the MMU and wait for it to complete
161 comb += valid.eq(1) # start "pulse"
162 comb += l_in.valid.eq(blip) # start
163 comb += l_in.mtspr.eq(1) # mtspr mode
164 comb += l_in.sprn.eq(spr) # which SPR
165 comb += l_in.rs.eq(a_i) # incoming operand (RS)
166 comb += done.eq(1) # FIXME l_out.done
167
168 with m.Case(MicrOp.OP_MFSPR):
169 comb += Display("MMUTEST: OP_MFSPR: spr=%i returns=%i",
170 spr, spr1_i)
171 comb += o.data.eq(spr1_i)
172 comb += o.ok.eq(1)
173 comb += done.eq(1)
174
175 with m.Case(MicrOp.OP_TLBIE):
176 comb += Display("MMUTEST: OP_TLBIE: insn_bits=%i", spr)
177 # pass TLBIE request to MMU (spec: v3.0B p1034)
178 # note that the spr is *not* an actual spr number, it's
179 # just that those bits happen to match with field bits
180 # RIC, PRS, R
181 comb += Display("TLBIE: %i %i", spr, l_out.done)
182 comb += valid.eq(1) # start "pulse"
183 comb += l_in.valid.eq(blip) # start
184 comb += l_in.tlbie.eq(1) # mtspr mode
185 comb += l_in.sprn.eq(spr) # use sprn to send insn bits
186 comb += l_in.addr.eq(b_i) # incoming operand (RB)
187 comb += done.eq(l_out.done) # zzzz
188 comb += self.debug0.eq(2)
189
190 with m.Case(MicrOp.OP_ILLEGAL):
191 comb += self.illegal.eq(1)
192
193 with m.If(self.n.i_ready & self.n.o_valid):
194 sync += busy.eq(0)
195
196 return m
197
198 def __iter__(self):
199 yield from self.p
200 yield from self.n
201
202 def ports(self):
203 return list(self)