from nmigen import Module, Elaboratable, Signal, Mux, Const, Cat, Repl, Record
from nmigen.cli import rtlil
+from soc.regfile.regfiles import XERRegs
+from nmutil.picker import PriorityPicker
from nmutil.iocontrol import RecordObject
from nmutil.extend import exts
from soc.regfile.regfiles import FastRegs
from soc.consts import TT
from soc.config.state import CoreState
+from soc.regfile.util import spr_to_fast
def decode_spr_num(spr):
class SPRMap(Elaboratable):
- """SPRMap: maps POWER9 SPR numbers to internal enum values
+ """SPRMap: maps POWER9 SPR numbers to internal enum values, fast and slow
"""
def __init__(self):
self.spr_i = Signal(10, reset_less=True)
- self.spr_o = Signal(SPR, reset_less=True)
+ self.spr_o = Data(SPR, name="spr_o")
+ self.fast_o = Data(3, name="fast_o")
def elaborate(self, platform):
m = Module()
with m.Switch(self.spr_i):
for i, x in enumerate(SPR):
with m.Case(x.value):
- m.d.comb += self.spr_o.eq(i)
+ m.d.comb += self.spr_o.data.eq(i)
+ m.d.comb += self.spr_o.ok.eq(1)
+ for x, v in spr_to_fast.items():
+ with m.Case(x.value):
+ m.d.comb += self.fast_o.data.eq(v)
+ m.d.comb += self.fast_o.ok.eq(1)
return m
with m.Case(MicrOp.OP_MFSPR):
spr = Signal(10, reset_less=True)
comb += spr.eq(decode_spr_num(self.dec.SPR)) # from XFX
- with m.Switch(spr):
- # fast SPRs
- with m.Case(SPR.CTR.value):
- comb += self.fast_out.data.eq(FastRegs.CTR)
- comb += self.fast_out.ok.eq(1)
- with m.Case(SPR.LR.value):
- comb += self.fast_out.data.eq(FastRegs.LR)
- comb += self.fast_out.ok.eq(1)
- with m.Case(SPR.TAR.value):
- comb += self.fast_out.data.eq(FastRegs.TAR)
- comb += self.fast_out.ok.eq(1)
- with m.Case(SPR.SRR0.value):
- comb += self.fast_out.data.eq(FastRegs.SRR0)
- comb += self.fast_out.ok.eq(1)
- with m.Case(SPR.SRR1.value):
- comb += self.fast_out.data.eq(FastRegs.SRR1)
- comb += self.fast_out.ok.eq(1)
- with m.Case(SPR.XER.value):
- pass # do nothing
- # : map to internal SPR numbers
- # XXX TODO: dec and tb not to go through mapping.
- with m.Default():
- comb += sprmap.spr_i.eq(spr)
- comb += self.spr_out.data.eq(sprmap.spr_o)
- comb += self.spr_out.ok.eq(1)
+ comb += sprmap.spr_i.eq(spr)
+ comb += self.spr_out.eq(sprmap.spr_o)
+ comb += self.fast_out.eq(sprmap.fast_o)
return m
with m.Case(OutSel.SPR):
spr = Signal(10, reset_less=True)
comb += spr.eq(decode_spr_num(self.dec.SPR)) # from XFX
- # TODO MTSPR 1st spr (fast)
+ # MFSPR move to SPRs - needs mapping
with m.If(op.internal_op == MicrOp.OP_MTSPR):
- with m.Switch(spr):
- # fast SPRs
- with m.Case(SPR.CTR.value):
- comb += self.fast_out.data.eq(FastRegs.CTR)
- comb += self.fast_out.ok.eq(1)
- with m.Case(SPR.LR.value):
- comb += self.fast_out.data.eq(FastRegs.LR)
- comb += self.fast_out.ok.eq(1)
- with m.Case(SPR.TAR.value):
- comb += self.fast_out.data.eq(FastRegs.TAR)
- comb += self.fast_out.ok.eq(1)
- with m.Case(SPR.SRR0.value):
- comb += self.fast_out.data.eq(FastRegs.SRR0)
- comb += self.fast_out.ok.eq(1)
- with m.Case(SPR.SRR1.value):
- comb += self.fast_out.data.eq(FastRegs.SRR1)
- comb += self.fast_out.ok.eq(1)
- with m.Case(SPR.XER.value):
- pass # do nothing
- # : map to internal SPR numbers
- # XXX TODO: dec and tb not to go through mapping.
- with m.Default():
- comb += sprmap.spr_i.eq(spr)
- comb += self.spr_out.data.eq(sprmap.spr_o)
- comb += self.spr_out.ok.eq(1)
+ comb += sprmap.spr_i.eq(spr)
+ comb += self.spr_out.eq(sprmap.spr_o)
+ comb += self.fast_out.eq(sprmap.fast_o)
with m.Switch(op.internal_op):
with m.Switch(op.internal_op):
# mulhw, mulhwu, mulhd, mulhdu - these *ignore* OE
- with m.Case(MicrOp.OP_MUL_H64, MicrOp.OP_MUL_H32):
+ # also rotate
+ # XXX ARGH! ignoring OE causes incompatibility with microwatt
+ # http://lists.libre-soc.org/pipermail/libre-soc-dev/2020-August/000302.html
+ with m.Case(MicrOp.OP_MUL_H64, MicrOp.OP_MUL_H32,
+ MicrOp.OP_EXTS, MicrOp.OP_CNTZ,
+ MicrOp.OP_SHL, MicrOp.OP_SHR, MicrOp.OP_RLC,
+ MicrOp.OP_LOAD, MicrOp.OP_STORE,
+ MicrOp.OP_RLCL, MicrOp.OP_RLCR,
+ MicrOp.OP_EXTSWSLI):
pass
# all other ops decode OE field
self.cr_bitfield = Data(3, "cr_bitfield")
self.cr_bitfield_b = Data(3, "cr_bitfield_b")
self.cr_bitfield_o = Data(3, "cr_bitfield_o")
- self.whole_reg = Signal(reset_less=True)
+ self.whole_reg = Data(8, "cr_fxm")
def elaborate(self, platform):
m = Module()
+ m.submodules.ppick = ppick = PriorityPicker(8, reverse_i=True,
+ reverse_o=True)
+
comb = m.d.comb
+ op = self.dec.op
comb += self.cr_bitfield.ok.eq(0)
comb += self.cr_bitfield_b.ok.eq(0)
- comb += self.whole_reg.eq(0)
+ comb += self.whole_reg.ok.eq(0)
with m.Switch(self.sel_in):
with m.Case(CRInSel.NONE):
pass # No bitfield activated
with m.Case(CRInSel.CR0):
- comb += self.cr_bitfield.data.eq(0)
+ comb += self.cr_bitfield.data.eq(0) # CR0 (MSB0 numbering)
comb += self.cr_bitfield.ok.eq(1)
with m.Case(CRInSel.BI):
comb += self.cr_bitfield.data.eq(self.dec.BI[2:5])
comb += self.cr_bitfield.data.eq(self.dec.BC[2:5])
comb += self.cr_bitfield.ok.eq(1)
with m.Case(CRInSel.WHOLE_REG):
- comb += self.whole_reg.eq(1)
+ comb += self.whole_reg.ok.eq(1)
+ move_one = Signal(reset_less=True)
+ comb += move_one.eq(self.insn_in[20]) # MSB0 bit 11
+ with m.If((op.internal_op == MicrOp.OP_MFCR) & move_one):
+ # must one-hot the FXM field
+ comb += ppick.i.eq(self.dec.FXM)
+ comb += self.whole_reg.data.eq(ppick.o)
+ with m.Else():
+ # otherwise use all of it
+ comb += self.whole_reg.data.eq(0xff)
return m
self.sel_in = Signal(CROutSel, reset_less=True)
self.insn_in = Signal(32, reset_less=True)
self.cr_bitfield = Data(3, "cr_bitfield")
- self.whole_reg = Signal(reset_less=True)
+ self.whole_reg = Data(8, "cr_fxm")
def elaborate(self, platform):
m = Module()
comb = m.d.comb
+ op = self.dec.op
+ m.submodules.ppick = ppick = PriorityPicker(8, reverse_i=True,
+ reverse_o=True)
comb += self.cr_bitfield.ok.eq(0)
- comb += self.whole_reg.eq(0)
+ comb += self.whole_reg.ok.eq(0)
with m.Switch(self.sel_in):
with m.Case(CROutSel.NONE):
pass # No bitfield activated
with m.Case(CROutSel.CR0):
- comb += self.cr_bitfield.data.eq(0)
+ comb += self.cr_bitfield.data.eq(0) # CR0 (MSB0 numbering)
comb += self.cr_bitfield.ok.eq(self.rc_in) # only when RC=1
with m.Case(CROutSel.BF):
comb += self.cr_bitfield.data.eq(self.dec.FormX.BF)
comb += self.cr_bitfield.data.eq(self.dec.FormXL.BT[2:5])
comb += self.cr_bitfield.ok.eq(1)
with m.Case(CROutSel.WHOLE_REG):
- comb += self.whole_reg.eq(1)
+ comb += self.whole_reg.ok.eq(1)
+ move_one = Signal(reset_less=True)
+ comb += move_one.eq(self.insn_in[20])
+ with m.If((op.internal_op == MicrOp.OP_MTCRF)):
+ with m.If(move_one):
+ # must one-hot the FXM field
+ comb += ppick.i.eq(self.dec.FXM)
+ with m.If(ppick.en_o):
+ comb += self.whole_reg.data.eq(ppick.o)
+ with m.Else():
+ comb += self.whole_reg.data.eq(0b00000001) # CR7
+ with m.Else():
+ comb += self.whole_reg.data.eq(self.dec.FXM)
+ with m.Else():
+ # otherwise use all of it
+ comb += self.whole_reg.data.eq(0xff)
return m
self.dec = dec
self.e = Decode2ToExecute1Type()
- self.valid = Signal() # sync signal
# state information needed by the Decoder (TODO: this as a Record)
self.state = CoreState("dec2")
def elaborate(self, platform):
m = Module()
comb = m.d.comb
- e, op, do = self.e, self.dec.op, self.e.do
- msr, cia = self.state.msr, self.state.pc
+ state = self.state
+ e_out, op, do_out = self.e, self.dec.op, self.e.do
+ dec_spr, msr, cia, ext_irq = state.dec, state.msr, state.pc, state.eint
+
+ # fill in for a normal instruction (not an exception)
+ # copy over if non-exception, non-privileged etc. is detected
+ e = Decode2ToExecute1Type()
+ do = e.do
# set up submodule decoders
m.submodules.dec = self.dec
# decoded/selected instruction flags
comb += do.data_len.eq(op.ldst_len)
- comb += do.invert_a.eq(op.inv_a)
+ comb += do.invert_in.eq(op.inv_a)
comb += do.invert_out.eq(op.inv_out)
comb += do.input_carry.eq(op.cry_in) # carry comes in
comb += do.output_carry.eq(op.cry_out) # carry goes out
# decoder is designed to not need. MTSPR, MFSPR and others need
# access to the XER bits. however setting e.oe is not appropriate
with m.If(op.internal_op == MicrOp.OP_MFSPR):
- comb += e.xer_in.eq(1)
+ comb += e.xer_in.eq(0b111) # SO, CA, OV
+ with m.If(op.internal_op == MicrOp.OP_CMP):
+ comb += e.xer_in.eq(1<<XERRegs.SO) # SO
with m.If(op.internal_op == MicrOp.OP_MTSPR):
comb += e.xer_out.eq(1)
# rverything including destroying read of RA and RB.
comb += do.trapaddr.eq(0x70) # addr=0x700 (strip first nibble)
- # TODO: get msr, then can do privileged instruction
- with m.If(instr_is_priv(m, op.internal_op, e.do.insn) & msr[MSR.PR]):
- # privileged instruction trap
+ # check if instruction is privileged
+ is_priv_insn = instr_is_priv(m, op.internal_op, e.do.insn)
+
+ # external interrupt? only if MSR.EE set
+ with m.If(ext_irq & msr[MSR.EE]): # v3.0B p944 (MSR.EE)
+ self.trap(m, TT.EINT, 0x500)
+
+ # decrement counter (v3.0B p1099): TODO 32-bit version (MSR.LPCR)
+ with m.If(dec_spr[63] & msr[MSR.EE]): # v3.0B 6.5.11 p1076
+ self.trap(m, TT.DEC, 0x900) # v3.0B 6.5 p1065
+
+ # privileged instruction trap
+ with m.Elif(is_priv_insn & msr[MSR.PR]):
self.trap(m, TT.PRIV, 0x700)
# illegal instruction must redirect to trap. this is done by
# illegal instruction trap
self.trap(m, TT.ILLEG, 0x700)
+ # no exception, just copy things to the output
+ with m.Else():
+ comb += e_out.eq(e)
+
# trap: (note e.insn_type so this includes OP_ILLEGAL) set up fast regs
# Note: OP_SC could actually be modified to just be a trap
- with m.If((do.insn_type == MicrOp.OP_TRAP) |
- (do.insn_type == MicrOp.OP_SC)):
+ with m.If((do_out.insn_type == MicrOp.OP_TRAP) |
+ (do_out.insn_type == MicrOp.OP_SC)):
# TRAP write fast1 = SRR0
- comb += e.write_fast1.data.eq(FastRegs.SRR0) # constant: SRR0
- comb += e.write_fast1.ok.eq(1)
+ comb += e_out.write_fast1.data.eq(FastRegs.SRR0) # constant: SRR0
+ comb += e_out.write_fast1.ok.eq(1)
# TRAP write fast2 = SRR1
- comb += e.write_fast2.data.eq(FastRegs.SRR1) # constant: SRR1
- comb += e.write_fast2.ok.eq(1)
+ comb += e_out.write_fast2.data.eq(FastRegs.SRR1) # constant: SRR1
+ comb += e_out.write_fast2.ok.eq(1)
# RFID: needs to read SRR0/1
- with m.If(do.insn_type == MicrOp.OP_RFID):
+ with m.If(do_out.insn_type == MicrOp.OP_RFID):
# TRAP read fast1 = SRR0
- comb += e.read_fast1.data.eq(FastRegs.SRR0) # constant: SRR0
- comb += e.read_fast1.ok.eq(1)
+ comb += e_out.read_fast1.data.eq(FastRegs.SRR0) # constant: SRR0
+ comb += e_out.read_fast1.ok.eq(1)
# TRAP read fast2 = SRR1
- comb += e.read_fast2.data.eq(FastRegs.SRR1) # constant: SRR1
- comb += e.read_fast2.ok.eq(1)
+ comb += e_out.read_fast2.data.eq(FastRegs.SRR1) # constant: SRR1
+ comb += e_out.read_fast2.ok.eq(1)
return m
"""trap: this basically "rewrites" the decoded instruction as a trap
"""
comb = m.d.comb
- e, op, do = self.e, self.dec.op, self.e.do
+ op, do, e = self.dec.op, self.e.do, self.e
comb += e.eq(0) # reset eeeeeverything
+
# start again
comb += do.insn.eq(self.dec.opcode_in)
comb += do.insn_type.eq(MicrOp.OP_TRAP)
comb += do.msr.eq(self.state.msr) # copy of MSR "state"
comb += do.cia.eq(self.state.pc) # copy of PC "state"
- def regspecmap_read(self, regfile, regname):
- """regspecmap_read: provides PowerDecode2 with an encoding relationship
- to Function Unit port regfiles (read-enable, read regnum, write regnum)
- regfile and regname arguments are fields 1 and 2 from a given regspec.
- """
- return regspec_decode_read(self.e, regfile, regname)
- def regspecmap_write(self, regfile, regname):
- """regspecmap_write: provides PowerDecode2 with an encoding relationship
- to Function Unit port regfiles (write port, write regnum)
- regfile and regname arguments are fields 1 and 2 from a given regspec.
- """
- return regspec_decode_write(self.e, regfile, regname)
-
- def rdflags(self, cu):
- rdl = []
- for idx in range(cu.n_src):
- regfile, regname, _ = cu.get_in_spec(idx)
- rdflag, read = self.regspecmap_read(regfile, regname)
- rdl.append(rdflag)
- print("rdflags", rdl)
- return Cat(*rdl)
+def get_rdflags(e, cu):
+ rdl = []
+ for idx in range(cu.n_src):
+ regfile, regname, _ = cu.get_in_spec(idx)
+ rdflag, read = regspec_decode_read(e, regfile, regname)
+ rdl.append(rdflag)
+ print("rdflags", rdl)
+ return Cat(*rdl)
if __name__ == '__main__':