add OP_MFSPR to mmu
[soc.git] / src / soc / fu / mmu / fsm.py
1 from nmigen import Elaboratable, Module, Signal, Shape, unsigned, Cat, Mux
2 from soc.fu.mmu.pipe_data import MMUInputData, MMUOutputData, MMUPipeSpec
3 from nmutil.singlepipe import ControlBase
4
5 from soc.experiment.mmu import MMU
6 from soc.experiment.dcache import DCache
7
8 from soc.decoder.power_fields import DecodeFields
9 from soc.decoder.power_fieldsn import SignalBitRange
10 from soc.decoder.power_decoder2 import decode_spr_num
11 from soc.decoder.power_enums import MicrOp, SPR, XER_bits
12
13
14 class FSMMMUStage(ControlBase):
15 def __init__(self, pspec):
16 super().__init__()
17 self.pspec = pspec
18
19 # set up p/n data
20 self.p.data_i = MMUInputData(pspec)
21 self.n.data_o = MMUOutputData(pspec)
22
23 # this Function Unit is extremely unusual in that it actually stores a
24 # "thing" rather than "processes inputs and produces outputs". hence
25 # why it has to be a FSM. linking up LD/ST however is going to have
26 # to be done back in Issuer (or Core)
27
28 self.mmu = MMU()
29 self.dcache = DCache()
30
31 # make life a bit easier in Core
32 self.pspec.mmu = self.mmu
33 self.pspec.dcache = self.dcache
34
35 # for SPR field number access
36 i = self.p.data_i
37 self.fields = DecodeFields(SignalBitRange, [i.ctx.op.insn])
38 self.fields.create_specs()
39
40 def elaborate(self, platform):
41 m = super().elaborate(platform)
42
43 # link mmu and dcache together
44 m.submodules.dcache = dcache = self.dcache
45 m.submodules.mmu = mmu = self.mmu
46 m.d.comb += dcache.m_in.eq(mmu.d_out)
47 m.d.comb += mmu.d_in.eq(dcache.m_out)
48 m_in, m_out = mmu.m_in, mmu.m_out
49 d_in, d_out = dcache.d_in, dcache.d_out
50
51 data_i, data_o = self.p.data_i, self.n.data_o
52 a_i, b_i, o = data_i.ra, data_i.rb, data_o.o
53 op = data_i.ctx.op
54
55 # busy/done signals
56 busy = Signal()
57 done = Signal()
58 m.d.comb += self.n.valid_o.eq(busy & done)
59 m.d.comb += self.p.ready_o.eq(~busy)
60
61 # take copy of X-Form SPR field
62 x_fields = self.fields.FormXFX
63 spr = Signal(len(x_fields.SPR))
64 comb += spr.eq(decode_spr_num(x_fields.SPR))
65
66 with m.If(~busy):
67 with m.If(self.p.valid_i):
68 m.d.sync += busy.eq(1)
69 with m.Else():
70
71 # based on the Micro-Op, we work out which of MMU or DCache
72 # should "action" the operation. one of MMU or DCache gets
73 # enabled ("valid") and we twiddle our thumbs until it
74 # responds ("done").
75 with m.Switch(op):
76
77 with m.Case(MicrOp.OP_MTSPR):
78 # subset SPR: first check a few bits
79 with m.If(~spr[9] & ~spr[5]):
80 with m.If(spr[0]):
81 comb += dsisr.eq(a_i[:32])
82 with m.Else():
83 comb += dar.eq(a_i)
84 comb += done.eq(1)
85 # pass it over to the MMU instead
86 with m.Else():
87 # kick the MMU and wait for it to complete
88 comb += m_in.valid.eq(1) # start
89 comb += m_in.mtspr.eq(1) # mtspr mode
90 comb += m_in.sprn.eq(spr) # which SPR
91 comb += m_in.rs.eq(a_i) # incoming operand (RS)
92 comb += done.eq(m_out.done) # zzzz
93
94 with m.Case(MicrOp.OP_MFSPR):
95 # subset SPR: first check a few bits
96 with m.If(~spr[9] & ~spr[5]):
97 with m.If(spr[0]):
98 comb += o.data.eq(dsisr)
99 with m.Else():
100 comb += o.data.eq(dar)
101 comb += o.ok.eq(1)
102 comb += done.eq(1)
103 # pass it over to the MMU instead
104 with m.Else():
105 # kick the MMU and wait for it to complete
106 comb += m_in.valid.eq(1) # start
107 comb += m_in.mtspr.eq(1) # mtspr mode
108 comb += m_in.sprn.eq(spr) # which SPR
109 comb += m_in.rs.eq(a_i) # incoming operand (RS)
110 comb += o.data.eq(m_out.sprval) # SPR from MMU
111 comb += o.ok.eq(m_out.done) # only when m_out valid
112 comb += done.eq(m_out.done) # zzzz
113
114 with m.Case(MicrOp.OP_DCBZ):
115 # activate dcbz mode (spec: v3.0B p850)
116 comb += d_in.valid.eq(1) # start
117 comb += d_in.dcbz.eq(1) # dcbz mode
118 comb += d_in.addr.eq(a_i + b_i) # addr is (RA|0) + RB
119 comb += done.eq(d_out.done) # zzzz
120
121 with m.Case(MicrOp.OP_TLBIE):
122 # pass TLBIE request to MMU (spec: v3.0B p1034)
123 # note that the spr is *not* an actual spr number, it's
124 # just that those bits happen to match with field bits
125 # RIC, PRS, R
126 comb += m_in.valid.eq(1) # start
127 comb += m_in.tlbie.eq(1) # mtspr mode
128 comb += m_in.sprn.eq(spr) # use sprn to send insn bits
129 comb += m_in.addr.eq(b_i) # incoming operand (RB)
130 comb += done.eq(m_out.done) # zzzz
131
132 with m.If(self.n.ready_i & self.n.valid_o):
133 m.d.sync += busy.eq(0)
134
135 return m
136
137 def __iter__(self):
138 yield from self.p
139 yield from self.n
140
141 def ports(self):
142 return list(self)