from soc.fu.ldst.loadstore import LoadStore1, TestSRAMLoadStore1
from nmutil.util import Display
+
class FSMMMUStage(ControlBase):
"""FSM MMU
# set up p/n data
self.p.i_data = MMUInputData(pspec)
self.n.o_data = MMUOutputData(pspec)
+ self.exc_o = self.n.o_data.exception # AllFunctionUnits needs this
self.mmu = MMU()
# incoming PortInterface
self.ldst = ldst
self.dcache = self.ldst.dcache
+ self.icache = self.ldst.icache
self.pi = self.ldst.pi
def elaborate(self, platform):
assert hasattr(self, "dcache"), "remember to call set_ldst_interface"
m = super().elaborate(platform)
comb, sync = m.d.comb, m.d.sync
- dcache = self.dcache
+ dcache, icache = self.dcache, self.icache
+ ldst = self.ldst # managed externally: do not add here
- # link mmu and dcache together
+ # link mmu, dcache and icache together
m.submodules.mmu = mmu = self.mmu
- ldst = self.ldst # managed externally: do not add here
m.d.comb += dcache.m_in.eq(mmu.d_out) # MMUToDCacheType
m.d.comb += mmu.d_in.eq(dcache.m_out) # DCacheToMMUType
+ m.d.comb += icache.m_in.eq(mmu.i_out) # MMUToICacheType
l_in, l_out = mmu.l_in, mmu.l_out
d_in, d_out = dcache.d_in, dcache.d_out
- wb_out, wb_in = dcache.wb_out, dcache.wb_in
# link ldst and MMU together
comb += l_in.eq(ldst.m_out)
comb += ldst.m_in.eq(l_out)
i_data, o_data = self.p.i_data, self.n.o_data
- a_i, b_i, o, spr1_o = i_data.ra, i_data.rb, o_data.o, o_data.spr1
op = i_data.ctx.op
+ cia_i = op.cia
msr_i = op.msr
- spr1_i = i_data.spr1
-
- # these are set / got here *ON BEHALF* of LoadStore1
- dsisr, dar = ldst.dsisr, ldst.dar
+ a_i, b_i, spr1_i = i_data.ra, i_data.rb, i_data.spr1
+ o, exc_o, spr1_o = o_data.o, o_data.exception, o_data.spr1
# busy/done signals
- busy = Signal()
- done = Signal()
- m.d.comb += self.n.valid_o.eq(busy & done)
- m.d.comb += self.p.ready_o.eq(~busy)
+ busy = Signal(name="mmu_fsm_busy")
+ done = Signal(name="mmu_fsm_done")
+ m.d.comb += self.n.o_valid.eq(busy & done)
+ m.d.comb += self.p.o_ready.eq(~busy)
# take copy of X-Form SPR field
x_fields = self.fields.FormXFX
spr = Signal(len(x_fields.SPR))
comb += spr.eq(decode_spr_num(x_fields.SPR))
- # based on MSR bits, set priv and virt mode. TODO: 32-bit mode
- comb += d_in.priv_mode.eq(~msr_i[MSR.PR])
- comb += d_in.virt_mode.eq(msr_i[MSR.DR])
- #comb += d_in.mode_32bit.eq(msr_i[MSR.SF]) # ?? err
-
# ok so we have to "pulse" the MMU (or dcache) rather than
# hold the valid hi permanently. guess what this does...
valid = Signal()
m.d.comb += blip.eq(rising_edge(m, valid))
with m.If(~busy):
- with m.If(self.p.valid_i):
+ with m.If(self.p.i_valid):
sync += busy.eq(1)
with m.Else():
# enabled ("valid") and we twiddle our thumbs until it
# responds ("done").
- # FIXME: properly implement MicrOp.OP_MTSPR and MicrOp.OP_MFSPR
+ # WIP: properly implement MicrOp.OP_MTSPR and MicrOp.OP_MFSPR
with m.Switch(op.insn_type):
+
+ ##########
+ # OP_MTSPR
+ ##########
+
with m.Case(MicrOp.OP_MTSPR):
+ comb += Display("MMUTEST: OP_MTSPR: spr=%i", spr)
# despite redirection this FU **MUST** behave exactly
# like the SPR FU. this **INCLUDES** updating the SPR
# regfile because the CSV file entry for OP_MTSPR
comb += self.debug0.eq(3)
#if matched update local cached value
#commented out because there is a driver conflict
- #with m.If(spr[0]):
- # sync += dsisr.eq(a_i[:32])
- #with m.Else():
- # sync += dar.eq(a_i)
+ comb += ldst.sprval_in.eq(a_i)
+ comb += ldst.mmu_set_spr.eq(1)
+ with m.If(spr[0]):
+ comb += ldst.mmu_set_dar.eq(1)
+ with m.Else():
+ comb += ldst.mmu_set_dsisr.eq(1)
comb += done.eq(1)
# pass it over to the MMU instead
with m.Else():
+ # PGTBL and PID
comb += self.debug0.eq(4)
# blip the MMU and wait for it to complete
comb += valid.eq(1) # start "pulse"
comb += l_in.rs.eq(a_i) # incoming operand (RS)
comb += done.eq(1) # FIXME l_out.done
+ ##########
+ # OP_MFSPR
+ ##########
+
with m.Case(MicrOp.OP_MFSPR):
- # subset SPR: first check a few bits
- #with m.If(~spr[9] & ~spr[5]):
- # comb += self.debug0.eq(5)
- #with m.If(spr[0]):
- # comb += o.data.eq(dsisr)
- #with m.Else():
- # comb += o.data.eq(dar)
- #do NOT return cached values
- comb += o.data.eq(spr1_i)
+ comb += Display("MMUTEST: OP_MFSPR: spr=%i returns=%i",
+ spr, spr1_i)
+ # partial SPR number decoding perfectly fine
+ with m.If(spr[9] | spr[5]):
+ # identified as an MMU OP_MFSPR, contact the MMU.
+ # interestingly, the read is combinatorial: no need
+ # to set "valid", just set the SPR number
+ comb += l_in.sprn.eq(spr) # which SPR
+ comb += o.data.eq(l_out.sprval)
+ with m.Else():
+ # identified as DSISR or DAR. again: read the SPR
+ # directly, combinatorial access
+ with m.If(spr[0]):
+ comb += o.data.eq(ldst.dar)
+ with m.Else():
+ comb += o.data.eq(ldst.dsisr)
+
comb += o.ok.eq(1)
comb += done.eq(1)
- # pass it over to the MMU instead
- #with m.Else():
- # comb += self.debug0.eq(6)
- # # blip the MMU and wait for it to complete
- # comb += valid.eq(1) # start "pulse"
- # comb += l_in.valid.eq(blip) # start
- # comb += l_in.mtspr.eq(0) # mfspr!=mtspr
- # comb += l_in.sprn.eq(spr) # which SPR
- # comb += l_in.rs.eq(a_i) # incoming operand (RS)
- # comb += o.data.eq(l_out.sprval) # SPR from MMU
- # comb += o.ok.eq(l_out.done) # only when l_out valid
- # comb += done.eq(1) # FIXME l_out.done
-
- # XXX this one is going to have to go through LDSTCompUnit
- # because it's LDST that has control over dcache
- # (through PortInterface). or, another means is devised
- # so as not to have double-drivers of d_in.valid and addr
- #
- #with m.Case(MicrOp.OP_DCBZ):
- # # activate dcbz mode (spec: v3.0B p850)
- # comb += valid.eq(1) # start "pulse"
- # comb += d_in.valid.eq(blip) # start
- # comb += d_in.dcbz.eq(1) # dcbz mode
- # comb += d_in.addr.eq(a_i + b_i) # addr is (RA|0) + RB
- # comb += done.eq(d_out.store_done) # TODO
- # comb += self.debug0.eq(1)
+
+ ##########
+ # OP_TLBIE
+ ##########
with m.Case(MicrOp.OP_TLBIE):
+ comb += Display("MMUTEST: OP_TLBIE: insn_bits=%i", spr)
# pass TLBIE request to MMU (spec: v3.0B p1034)
# note that the spr is *not* an actual spr number, it's
# just that those bits happen to match with field bits
# RIC, PRS, R
- comb += Display("TLBIE: %i %i",spr,l_out.done)
+ comb += Display("TLBIE: %i %i", spr, l_out.done)
comb += valid.eq(1) # start "pulse"
comb += l_in.valid.eq(blip) # start
comb += l_in.tlbie.eq(1) # mtspr mode
comb += done.eq(l_out.done) # zzzz
comb += self.debug0.eq(2)
+ ##########
+ # OP_FETCH_FAILED
+ ##########
+
+ with m.Case(MicrOp.OP_FETCH_FAILED):
+ comb += Display("MMUTEST: OP_FETCH_FAILED: @%x", cia_i)
+ # trigger an instruction fetch failed MMU event.
+ # PowerDecoder2 drops svstate.pc into NIA for us
+ # really, this should be direct communication with the
+ # MMU, rather than going through LoadStore1. but, doing
+ # so allows for the opportunity to prevent LoadStore1
+ # from accepting any other LD/ST requests.
+ comb += valid.eq(1) # start "pulse"
+ comb += ldst.instr_fault.eq(blip)
+ comb += ldst.priv_mode.eq(~msr_i[MSR.PR])
+ comb += ldst.maddr.eq(cia_i)
+ # XXX should not access this!
+ comb += done.eq(ldst.done)
+ comb += self.debug0.eq(3)
+ # LDST unit contains exception data, which (messily)
+ # is copied over, here. not ideal but it will do for now
+ comb += exc_o.eq(ldst.pi.exc_o)
+
+ ############
+ # OP_ILLEGAL
+ ############
+
with m.Case(MicrOp.OP_ILLEGAL):
comb += self.illegal.eq(1)
- with m.If(self.n.ready_i & self.n.valid_o):
+ with m.If(self.n.i_ready & self.n.o_valid):
sync += busy.eq(0)
return m