return subset
def rowsubsetfn(self, opcode, row):
- return row['unit'] == self.fn_name
+ """select per-Function-Unit subset of opcodes to be processed
+
+ normally this just looks at the "unit" column. MMU is different
+ in that it processes specific SPR set/get operations that the SPR
+ pipeline should not.
+ """
+ return (row['unit'] == self.fn_name or
+ # sigh a dreadful hack: MTSPR and MFSPR need to be processed
+ # by the MMU pipeline so we direct those opcodes to MMU **AND**
+ # SPR pipelines, then selectively weed out the SPRs that should
+ # or should not not go to each pipeline, further down.
+ # really this should be done by modifying the CSV syntax
+ # to support multiple tasks (unit column multiple entries)
+ # see https://bugs.libre-soc.org/show_bug.cgi?id=310
+ (self.fn_name == 'MMU' and row['unit'] == 'SPR' and
+ row['internal op'] in ['OP_MTSPR', 'OP_MFSPR'])
+ )
def ports(self):
return self.dec.ports() + self.e.ports() + self.sv_rm.ports()
# set up instruction type
# no op: defaults to OP_ILLEGAL
- if self.fn_name=="MMU":
- # mmu is special case: needs SPR opcode as well
- mmu0 = self.mmu0_spr_dec
- with m.If(((mmu0.dec.op.internal_op == MicrOp.OP_MTSPR) |
- (mmu0.dec.op.internal_op == MicrOp.OP_MFSPR))):
- comb += self.do_copy("insn_type", mmu0.op_get("internal_op"))
- with m.Else():
- comb += self.do_copy("insn_type", self.op_get("internal_op"))
- else:
- comb += self.do_copy("insn_type", self.op_get("internal_op"))
+ internal_op = self.op_get("internal_op")
+ comb += self.do_copy("insn_type", internal_op)
# function unit for decoded instruction: requires minor redirect
# for SPR set/get
# Microwatt doesn't implement the partition table
# instead has PRTBL(SVSRR0) register (SPR) to point to process table
- with m.If(((self.dec.op.internal_op == MicrOp.OP_MTSPR) |
- (self.dec.op.internal_op == MicrOp.OP_MFSPR)) &
- ((spr == SPR.DSISR.value) | (spr == SPR.DAR.value) |
- (spr==SPR.SVSRR0.value) | (spr==SPR.PIDR.value))):
- comb += self.do_copy("fn_unit", Function.MMU)
+ is_spr_mv = Signal()
+ is_mmu_spr = Signal()
+ comb += is_spr_mv.eq((internal_op == MicrOp.OP_MTSPR) |
+ (internal_op == MicrOp.OP_MFSPR))
+ comb += is_mmu_spr.eq((spr == SPR.DSISR.value) |
+ (spr == SPR.DAR.value) |
+ (spr == SPR.SVSRR0.value) |
+ (spr == SPR.PIDR.value))
+ # MMU must receive MMU SPRs
+ with m.If(is_spr_mv & (fn == Function.SPR) & is_mmu_spr):
+ comb += self.do_copy("fn_unit", Function.NONE)
+ comb += self.do_copy("insn_type", MicrOp.OP_ILLEGAL)
+ # SPR pipe must *not* receive MMU SPRs
+ with m.Elif(is_spr_mv & (fn == Function.MMU) & ~is_mmu_spr):
+ comb += self.do_copy("fn_unit", Function.NONE)
+ comb += self.do_copy("insn_type", MicrOp.OP_ILLEGAL)
+ # all others ok
with m.Else():
- comb += self.do_copy("fn_unit",fn)
+ comb += self.do_copy("fn_unit", fn)
# immediates
if self.needs_field("zero_a", "in1_sel"):
comb += self.ldst.d_out.eq(self.dcache.d_out)
data_i, data_o = self.p.data_i, self.n.data_o
- a_i, b_i, o = data_i.ra, data_i.rb, data_o.o
+ a_i, b_i, o, spr1_o = data_i.ra, data_i.rb, data_o.o, data_o.spr1
op = data_i.ctx.op
# TODO: link these SPRs somewhere
with m.Switch(op.insn_type):
with m.Case(MicrOp.OP_MTSPR):
+ # 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
+ # categorically defines and requires the expectation
+ # that the CompUnit **WILL** write to the regfile.
+ comb += spr1_o.data.eq(spr)
+ comb += spr1_o.ok.eq(1)
# subset SPR: first check a few bits
with m.If(~spr[9] & ~spr[5]):
comb += self.debug0.eq(3)