X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fsoc%2Fdecoder%2Fpower_decoder2.py;h=51c3511f9dc93cde787029b4903e1358f57594da;hb=65c43ae4c522d129742046eb2e1395ce27d48a09;hp=535ce65a3f8740d9fbd56181c86cd91731897597;hpb=9f39ffff358aa867e9c67fb10aed54f186c1f058;p=soc.git diff --git a/src/soc/decoder/power_decoder2.py b/src/soc/decoder/power_decoder2.py index 535ce65a..51c3511f 100644 --- a/src/soc/decoder/power_decoder2.py +++ b/src/soc/decoder/power_decoder2.py @@ -2,21 +2,68 @@ based on Anton Blanchard microwatt decode2.vhdl +Note: OP_TRAP is used for exceptions and interrupts (micro-code style) by +over-riding the internal opcode when an exception is needed. """ + from nmigen import Module, Elaboratable, Signal, Mux, Const, Cat, Repl, Record from nmigen.cli import rtlil from nmutil.iocontrol import RecordObject from nmutil.extend import exts -from soc.decoder.power_regspec_map import regspec_decode +from soc.decoder.power_regspec_map import regspec_decode_read +from soc.decoder.power_regspec_map import regspec_decode_write from soc.decoder.power_decoder import create_pdecode -from soc.decoder.power_enums import (InternalOp, CryIn, Function, +from soc.decoder.power_enums import (MicrOp, CryIn, Function, CRInSel, CROutSel, LdstLen, In1Sel, In2Sel, In3Sel, - OutSel, SPR, RC) + OutSel, SPR, RC, LDSTMode) +from soc.decoder.decode2execute1 import Decode2ToExecute1Type, Data +from soc.consts import MSR from soc.regfile.regfiles import FastRegs +from soc.consts import TT +from soc.config.state import CoreState + + +def decode_spr_num(spr): + return Cat(spr[5:10], spr[0:5]) + + +def instr_is_priv(m, op, insn): + """determines if the instruction is privileged or not + """ + comb = m.d.comb + is_priv_insn = Signal(reset_less=True) + with m.Switch(op): + with m.Case(MicrOp.OP_ATTN, MicrOp.OP_MFMSR, MicrOp.OP_MTMSRD, + MicrOp.OP_MTMSR, MicrOp.OP_RFID): + comb += is_priv_insn.eq(1) + # XXX TODO + #with m.Case(MicrOp.OP_TLBIE) : comb += is_priv_insn.eq(1) + with m.Case(MicrOp.OP_MFSPR, MicrOp.OP_MTSPR): + with m.If(insn[20]): # field XFX.spr[-1] i think + comb += is_priv_insn.eq(1) + return is_priv_insn + + +class SPRMap(Elaboratable): + """SPRMap: maps POWER9 SPR numbers to internal enum values + """ + + def __init__(self): + self.spr_i = Signal(10, reset_less=True) + self.spr_o = Signal(SPR, reset_less=True) + + 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) + return m + class DecodeA(Elaboratable): """DecodeA from instruction @@ -31,12 +78,13 @@ class DecodeA(Elaboratable): self.insn_in = Signal(32, reset_less=True) self.reg_out = Data(5, name="reg_a") self.immz_out = Signal(reset_less=True) - self.spr_out = Data(10, "spr_a") + self.spr_out = Data(SPR, "spr_a") self.fast_out = Data(3, "fast_a") def elaborate(self, platform): m = Module() comb = m.d.comb + m.submodules.sprmap = sprmap = SPRMap() # select Register A field ra = Signal(5, reset_less=True) @@ -59,42 +107,55 @@ class DecodeA(Elaboratable): # decode Fast-SPR based on instruction type op = self.dec.op - # BC or BCREG: potential implicit register (CTR) NOTE: same in DecodeOut - with m.If(op.internal_op == InternalOp.OP_BC): - with m.If(~self.dec.BO[2]): # 3.0B p38 BO2=0, use CTR reg - comb += self.fast_out.data.eq(FastRegs.CTR) # constant: CTR - comb += self.fast_out.ok.eq(1) - with m.Elif(op.internal_op == InternalOp.OP_BCREG): - xo9 = self.dec.FormXL.XO[9] # 3.0B p38 top bit of XO - xo5 = self.dec.FormXL.XO[5] # 3.0B p38 - with m.If(xo9 & ~xo5): - comb += self.fast_out.data.eq(FastRegs.CTR) # constant: CTR - comb += self.fast_out.ok.eq(1) - - # MFSPR move from SPRs - with m.If(op.internal_op == InternalOp.OP_MFSPR): - # XXX TODO: fast/slow SPR decoding and mapping - comb += self.spr_out.data.eq(self.dec.SPR) # SPR field, XFX - comb += self.spr_out.ok.eq(1) + with m.Switch(op.internal_op): + + # BC or BCREG: implicit register (CTR) NOTE: same in DecodeOut + with m.Case(MicrOp.OP_BC): + with m.If(~self.dec.BO[2]): # 3.0B p38 BO2=0, use CTR reg + # constant: CTR + comb += self.fast_out.data.eq(FastRegs.CTR) + comb += self.fast_out.ok.eq(1) + with m.Case(MicrOp.OP_BCREG): + xo9 = self.dec.FormXL.XO[9] # 3.0B p38 top bit of XO + xo5 = self.dec.FormXL.XO[5] # 3.0B p38 + with m.If(xo9 & ~xo5): + # constant: CTR + comb += self.fast_out.data.eq(FastRegs.CTR) + comb += self.fast_out.ok.eq(1) + + # MFSPR move from SPRs + 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) return m -class Data(Record): - - def __init__(self, width, name): - name_ok = "%s_ok" % name - layout = ((name, width), (name_ok, 1)) - Record.__init__(self, layout) - self.data = getattr(self, name) # convenience - self.ok = getattr(self, name_ok) # convenience - self.data.reset_less = True # grrr - self.reset_less = True # grrr - - def ports(self): - return [self.data, self.ok] - - class DecodeB(Elaboratable): """DecodeB from instruction @@ -122,39 +183,49 @@ class DecodeB(Elaboratable): comb += self.reg_out.data.eq(self.dec.RB) comb += self.reg_out.ok.eq(1) with m.Case(In2Sel.RS): - comb += self.reg_out.data.eq(self.dec.RS) # for M-Form shiftrot + # for M-Form shiftrot + comb += self.reg_out.data.eq(self.dec.RS) comb += self.reg_out.ok.eq(1) - with m.Case(In2Sel.CONST_UI): + with m.Case(In2Sel.CONST_UI): # unsigned comb += self.imm_out.data.eq(self.dec.UI) comb += self.imm_out.ok.eq(1) - with m.Case(In2Sel.CONST_SI): # TODO: sign-extend here? - comb += self.imm_out.data.eq( - exts(self.dec.SI, 16, 64)) + with m.Case(In2Sel.CONST_SI): # sign-extended 16-bit + si = Signal(16, reset_less=True) + comb += si.eq(self.dec.SI) + comb += self.imm_out.data.eq(exts(si, 16, 64)) comb += self.imm_out.ok.eq(1) - with m.Case(In2Sel.CONST_UI_HI): - comb += self.imm_out.data.eq(self.dec.UI<<16) + with m.Case(In2Sel.CONST_SI_HI): # sign-extended 16+16=32 bit + si_hi = Signal(32, reset_less=True) + comb += si_hi.eq(self.dec.SI << 16) + comb += self.imm_out.data.eq(exts(si_hi, 32, 64)) comb += self.imm_out.ok.eq(1) - with m.Case(In2Sel.CONST_SI_HI): # TODO: sign-extend here? - comb += self.imm_out.data.eq(self.dec.SI<<16) - comb += self.imm_out.data.eq( - exts(self.dec.SI << 16, 32, 64)) + with m.Case(In2Sel.CONST_UI_HI): # unsigned + ui = Signal(16, reset_less=True) + comb += ui.eq(self.dec.UI) + comb += self.imm_out.data.eq(ui << 16) comb += self.imm_out.ok.eq(1) - with m.Case(In2Sel.CONST_LI): - comb += self.imm_out.data.eq(self.dec.LI<<2) + with m.Case(In2Sel.CONST_LI): # sign-extend 24+2=26 bit + li = Signal(26, reset_less=True) + comb += li.eq(self.dec.LI << 2) + comb += self.imm_out.data.eq(exts(li, 26, 64)) comb += self.imm_out.ok.eq(1) - with m.Case(In2Sel.CONST_BD): - comb += self.imm_out.data.eq(self.dec.BD<<2) + with m.Case(In2Sel.CONST_BD): # sign-extend (14+2)=16 bit + bd = Signal(16, reset_less=True) + comb += bd.eq(self.dec.BD << 2) + comb += self.imm_out.data.eq(exts(bd, 16, 64)) comb += self.imm_out.ok.eq(1) - with m.Case(In2Sel.CONST_DS): - comb += self.imm_out.data.eq(self.dec.DS<<2) + with m.Case(In2Sel.CONST_DS): # sign-extended (14+2=16) bit + ds = Signal(16, reset_less=True) + comb += ds.eq(self.dec.DS << 2) + comb += self.imm_out.data.eq(exts(ds, 16, 64)) comb += self.imm_out.ok.eq(1) - with m.Case(In2Sel.CONST_M1): - comb += self.imm_out.data.eq(~Const(0, 64)) # all 1s + with m.Case(In2Sel.CONST_M1): # signed (-1) + comb += self.imm_out.data.eq(~Const(0, 64)) # all 1s comb += self.imm_out.ok.eq(1) - with m.Case(In2Sel.CONST_SH): + with m.Case(In2Sel.CONST_SH): # unsigned - for shift comb += self.imm_out.data.eq(self.dec.sh) comb += self.imm_out.ok.eq(1) - with m.Case(In2Sel.CONST_SH32): + with m.Case(In2Sel.CONST_SH32): # unsigned - for shift comb += self.imm_out.data.eq(self.dec.SH32) comb += self.imm_out.ok.eq(1) @@ -162,9 +233,9 @@ class DecodeB(Elaboratable): op = self.dec.op # BCREG implicitly uses LR or TAR for 2nd reg # CTR however is already in fast_spr1 *not* 2. - with m.If(op.internal_op == InternalOp.OP_BCREG): - xo9 = self.dec.FormXL.XO[9] # 3.0B p38 top bit of XO - xo5 = self.dec.FormXL.XO[5] # 3.0B p38 + with m.If(op.internal_op == MicrOp.OP_BCREG): + xo9 = self.dec.FormXL.XO[9] # 3.0B p38 top bit of XO + xo5 = self.dec.FormXL.XO[5] # 3.0B p38 with m.If(~xo9): comb += self.fast_out.data.eq(FastRegs.LR) comb += self.fast_out.ok.eq(1) @@ -194,7 +265,8 @@ class DecodeC(Elaboratable): # select Register C field with m.Switch(self.sel_in): with m.Case(In3Sel.RB): - comb += self.reg_out.data.eq(self.dec.RB) # for M-Form shiftrot + # for M-Form shiftrot + comb += self.reg_out.data.eq(self.dec.RB) comb += self.reg_out.ok.eq(1) with m.Case(In3Sel.RS): comb += self.reg_out.data.eq(self.dec.RS) @@ -214,12 +286,13 @@ class DecodeOut(Elaboratable): self.sel_in = Signal(OutSel, reset_less=True) self.insn_in = Signal(32, reset_less=True) self.reg_out = Data(5, "reg_o") - self.spr_out = Data(10, "spr_o") + self.spr_out = Data(SPR, "spr_o") self.fast_out = Data(3, "fast_o") def elaborate(self, platform): m = Module() comb = m.d.comb + m.submodules.sprmap = sprmap = SPRMap() op = self.dec.op # select Register out field @@ -231,40 +304,50 @@ class DecodeOut(Elaboratable): comb += self.reg_out.data.eq(self.dec.RA) comb += self.reg_out.ok.eq(1) with m.Case(OutSel.SPR): - comb += self.spr_out.data.eq(self.dec.SPR) # from XFX - comb += self.spr_out.ok.eq(1) + spr = Signal(10, reset_less=True) + comb += spr.eq(decode_spr_num(self.dec.SPR)) # from XFX # TODO MTSPR 1st spr (fast) - with m.If(op.internal_op == InternalOp.OP_MTSPR): - pass - """ - sprn := decode_spr_num(f_in.insn); - v.ispr1 := fast_spr_num(sprn); - -- Make slow SPRs single issue - if is_fast_spr(v.ispr1) = '0' then - v.decode.sgl_pipe := '1'; - -- send MMU-related SPRs to loadstore1 - case sprn is - when SPR_DAR | SPR_DSISR | SPR_PID | SPR_PRTBL => - v.decode.unit := LDST; - when others => - end case; - end if; - """ - - - # BC or BCREG: potential implicit register (CTR) NOTE: same in DecodeA - op = self.dec.op - with m.If((op.internal_op == InternalOp.OP_BC) | - (op.internal_op == InternalOp.OP_BCREG)): - with m.If(~self.dec.BO[2]): # 3.0B p38 BO2=0, use CTR reg - comb += self.fast_out.data.eq(FastRegs.CTR) # constant: CTR + 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) + + with m.Switch(op.internal_op): + + # BC or BCREG: implicit register (CTR) NOTE: same in DecodeA + with m.Case(MicrOp.OP_BC, MicrOp.OP_BCREG): + with m.If(~self.dec.BO[2]): # 3.0B p38 BO2=0, use CTR reg + # constant: CTR + comb += self.fast_out.data.eq(FastRegs.CTR) + comb += self.fast_out.ok.eq(1) + + # RFID 1st spr (fast) + with m.Case(MicrOp.OP_RFID): + comb += self.fast_out.data.eq(FastRegs.SRR0) # constant: SRR0 comb += self.fast_out.ok.eq(1) - # RFID 1st spr (fast) - with m.If(op.internal_op == InternalOp.OP_RFID): - comb += self.fast_out.data.eq(FastRegs.SRR0) # constant: SRR0 - comb += self.fast_out.ok.eq(1) - return m @@ -287,21 +370,24 @@ class DecodeOut2(Elaboratable): comb = m.d.comb # update mode LD/ST uses read-reg A also as an output - with m.If(self.dec.op.upd): + with m.If(self.dec.op.upd == LDSTMode.update): comb += self.reg_out.eq(self.dec.RA) comb += self.reg_out.ok.eq(1) - # BC or BCREG: potential implicit register (LR) output + # B, BC or BCREG: potential implicit register (LR) output + # these give bl, bcl, bclrl, etc. op = self.dec.op - with m.If((op.internal_op == InternalOp.OP_BC) | - (op.internal_op == InternalOp.OP_BCREG)): - with m.If(self.lk): # "link" mode - comb += self.fast_out.data.eq(FastRegs.LR) # constant: LR - comb += self.fast_out.ok.eq(1) + with m.Switch(op.internal_op): - # RFID 2nd spr (fast) - with m.If(op.internal_op == InternalOp.OP_RFID): - comb += self.fast_out.data.eq(FastRegs.SRR1) # constant: SRR1 + # BC* implicit register (LR) + with m.Case(MicrOp.OP_BC, MicrOp.OP_B, MicrOp.OP_BCREG): + with m.If(self.lk): # "link" mode + comb += self.fast_out.data.eq(FastRegs.LR) # constant: LR + comb += self.fast_out.ok.eq(1) + + # RFID 2nd spr (fast) + with m.Case(MicrOp.OP_RFID): + comb += self.fast_out.data.eq(FastRegs.SRR1) # constant: SRR1 comb += self.fast_out.ok.eq(1) return m @@ -312,6 +398,7 @@ class DecodeRC(Elaboratable): decodes Record bit Rc """ + def __init__(self, dec): self.dec = dec self.sel_in = Signal(RC, reset_less=True) @@ -348,6 +435,7 @@ class DecodeOE(Elaboratable): -- actual POWER9 does if we set it on those instructions, for now we -- test that further down when assigning to the multiplier oe input. """ + def __init__(self, dec): self.dec = dec self.sel_in = Signal(RC, reset_less=True) @@ -357,15 +445,25 @@ class DecodeOE(Elaboratable): def elaborate(self, platform): m = Module() comb = m.d.comb + op = self.dec.op - # select OE bit out field - with m.Switch(self.sel_in): - with m.Case(RC.RC): - comb += self.oe_out.data.eq(self.dec.OE) - comb += self.oe_out.ok.eq(1) + with m.Switch(op.internal_op): + + # mulhw, mulhwu, mulhd, mulhdu - these *ignore* OE + with m.Case(MicrOp.OP_MUL_H64, MicrOp.OP_MUL_H32): + pass + + # all other ops decode OE field + with m.Default(): + # select OE bit out field + with m.Switch(self.sel_in): + with m.Case(RC.RC): + comb += self.oe_out.data.eq(self.dec.OE) + comb += self.oe_out.ok.eq(1) return m + class DecodeCRIn(Elaboratable): """Decodes input CR from instruction @@ -391,7 +489,7 @@ class DecodeCRIn(Elaboratable): comb += self.whole_reg.eq(0) with m.Switch(self.sel_in): with m.Case(CRInSel.NONE): - pass # No bitfield activated + pass # No bitfield activated with m.Case(CRInSel.CR0): comb += self.cr_bitfield.data.eq(0) comb += self.cr_bitfield.ok.eq(1) @@ -440,10 +538,10 @@ class DecodeCROut(Elaboratable): comb += self.whole_reg.eq(0) with m.Switch(self.sel_in): with m.Case(CROutSel.NONE): - pass # No bitfield activated + pass # No bitfield activated with m.Case(CROutSel.CR0): comb += self.cr_bitfield.data.eq(0) - comb += self.cr_bitfield.ok.eq(self.rc_in) # only when RC=1 + 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.ok.eq(1) @@ -456,80 +554,47 @@ class DecodeCROut(Elaboratable): return m -class XerBits: - def __init__(self): - self.ca = Signal(2, reset_less=True) - self.ov = Signal(2, reset_less=True) - self.so = Signal(reset_less=True) - - def ports(self): - return [self.ca, self.ov, self.so] - - -class Decode2ToExecute1Type(RecordObject): - - def __init__(self, name=None): - - RecordObject.__init__(self, name=name) - - self.valid = Signal(reset_less=True) - self.insn_type = Signal(InternalOp, reset_less=True) - self.fn_unit = Signal(Function, reset_less=True) - self.nia = Signal(64, reset_less=True) - self.write_reg = Data(5, name="rego") - self.write_ea = Data(5, name="ea") # for LD/ST in update mode - self.read_reg1 = Data(5, name="reg1") - self.read_reg2 = Data(5, name="reg2") - self.read_reg3 = Data(5, name="reg3") - self.imm_data = Data(64, name="imm") - self.write_spr = Data(10, name="spro") - self.read_spr1 = Data(10, name="spr1") - self.read_spr2 = Data(10, name="spr2") - - self.read_fast1 = Data(3, name="fast1") - self.read_fast2 = Data(3, name="fast2") - self.write_fast1 = Data(3, name="fasto1") - self.write_fast2 = Data(3, name="fasto2") - - self.read_cr1 = Data(3, name="cr_in1") - self.read_cr2 = Data(3, name="cr_in2") - self.read_cr3 = Data(3, name="cr_in2") - self.read_cr_whole = Signal(reset_less=True) - self.write_cr = Data(3, name="cr_out") - self.write_cr_whole = Signal(reset_less=True) - self.lk = Signal(reset_less=True) - self.rc = Data(1, "rc") - self.oe = Data(1, "oe") - self.invert_a = Signal(reset_less=True) - self.zero_a = Signal(reset_less=True) - self.invert_out = Signal(reset_less=True) - self.input_carry = Signal(CryIn, reset_less=True) - self.output_carry = Signal(reset_less=True) - self.input_cr = Signal(reset_less=True) # instr. has a CR as input - self.output_cr = Signal(reset_less=True) # instr. has a CR as output - self.is_32bit = Signal(reset_less=True) - self.is_signed = Signal(reset_less=True) - self.insn = Signal(32, reset_less=True) - self.data_len = Signal(4, reset_less=True) # bytes - self.byte_reverse = Signal(reset_less=True) - self.sign_extend = Signal(reset_less=True)# do we need this? - self.update = Signal(reset_less=True) # LD/ST is "update" variant - - class PowerDecode2(Elaboratable): + """PowerDecode2: the main instruction decoder. + + whilst PowerDecode is responsible for decoding the actual opcode, this + module encapsulates further specialist, sparse information and + expansion of fields that is inconvenient to have in the CSV files. + for example: the encoding of the immediates, which are detected + and expanded out to their full value from an annotated (enum) + representation. + + implicit register usage is also set up, here. for example: OP_BC + requires implicitly reading CTR, OP_RFID requires implicitly writing + to SRR1 and so on. + + in addition, PowerDecoder2 is responsible for detecting whether + instructions are illegal (or privileged) or not, and instead of + just leaving at that, *replacing* the instruction to execute with + a suitable alternative (trap). + """ def __init__(self, dec): self.dec = dec self.e = Decode2ToExecute1Type() + # state information needed by the Decoder (TODO: this as a Record) + self.state = CoreState("dec2") + def ports(self): return self.dec.ports() + self.e.ports() def elaborate(self, platform): m = Module() comb = m.d.comb - e, op = self.e, self.dec.op + e_out, op, do_out = self.e, self.dec.op, self.e.do + msr, cia = self.state.msr, self.state.pc + + # 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 @@ -544,7 +609,7 @@ class PowerDecode2(Elaboratable): m.submodules.dec_cr_out = dec_cr_out = DecodeCROut(self.dec) # copy instruction through... - for i in [e.insn, dec_a.insn_in, dec_b.insn_in, + for i in [do.insn, dec_a.insn_in, dec_b.insn_in, dec_c.insn_in, dec_o.insn_in, dec_o2.insn_in, dec_rc.insn_in, dec_oe.insn_in, dec_cr_in.insn_in, dec_cr_out.insn_in]: comb += i.eq(self.dec.opcode_in) @@ -555,29 +620,21 @@ class PowerDecode2(Elaboratable): comb += dec_c.sel_in.eq(op.in3_sel) comb += dec_o.sel_in.eq(op.out_sel) comb += dec_o2.sel_in.eq(op.out_sel) - comb += dec_o2.lk.eq(e.lk) + comb += dec_o2.lk.eq(do.lk) comb += dec_rc.sel_in.eq(op.rc_sel) - comb += dec_oe.sel_in.eq(op.rc_sel) # XXX should be OE sel + comb += dec_oe.sel_in.eq(op.rc_sel) # XXX should be OE sel comb += dec_cr_in.sel_in.eq(op.cr_in) comb += dec_cr_out.sel_in.eq(op.cr_out) comb += dec_cr_out.rc_in.eq(dec_rc.rc_out.data) - # decode LD/ST length - with m.Switch(op.ldst_len): - with m.Case(LdstLen.is1B): - comb += e.data_len.eq(1) - with m.Case(LdstLen.is2B): - comb += e.data_len.eq(2) - with m.Case(LdstLen.is4B): - comb += e.data_len.eq(4) - with m.Case(LdstLen.is8B): - comb += e.data_len.eq(8) - - comb += e.nia.eq(0) # XXX TODO (or remove? not sure yet) - fu = op.function_unit - itype = Mux(fu == Function.NONE, InternalOp.OP_ILLEGAL, op.internal_op) - comb += e.insn_type.eq(itype) - comb += e.fn_unit.eq(fu) + # copy "state" over + comb += do.msr.eq(msr) + comb += do.cia.eq(cia) + + # set up instruction, pick fn unit + # no op: defaults to OP_ILLEGAL + comb += do.insn_type.eq(op.internal_op) + comb += do.fn_unit.eq(op.function_unit) # registers a, b, c and out and out2 (LD/ST EA) comb += e.read_reg1.eq(dec_a.reg_out) @@ -585,12 +642,12 @@ class PowerDecode2(Elaboratable): comb += e.read_reg3.eq(dec_c.reg_out) comb += e.write_reg.eq(dec_o.reg_out) comb += e.write_ea.eq(dec_o2.reg_out) - comb += e.imm_data.eq(dec_b.imm_out) # immediate in RB (usually) - comb += e.zero_a.eq(dec_a.immz_out) # RA==0 detected + comb += do.imm_data.eq(dec_b.imm_out) # immediate in RB (usually) + comb += do.zero_a.eq(dec_a.immz_out) # RA==0 detected # rc and oe out - comb += e.rc.eq(dec_rc.rc_out) - comb += e.oe.eq(dec_oe.oe_out) + comb += do.rc.eq(dec_rc.rc_out) + comb += do.oe.eq(dec_oe.oe_out) # SPRs out comb += e.read_spr1.eq(dec_a.spr_out) @@ -602,51 +659,113 @@ class PowerDecode2(Elaboratable): comb += e.write_fast1.eq(dec_o.fast_out) comb += e.write_fast2.eq(dec_o2.fast_out) + # condition registers (CR) comb += e.read_cr1.eq(dec_cr_in.cr_bitfield) comb += e.read_cr2.eq(dec_cr_in.cr_bitfield_b) comb += e.read_cr3.eq(dec_cr_in.cr_bitfield_o) - comb += e.read_cr_whole.eq(dec_cr_in.whole_reg) - comb += e.write_cr.eq(dec_cr_out.cr_bitfield) - comb += e.write_cr_whole.eq(dec_cr_out.whole_reg) + + comb += do.read_cr_whole.eq(dec_cr_in.whole_reg) + comb += do.write_cr_whole.eq(dec_cr_out.whole_reg) + comb += do.write_cr0.eq(dec_cr_out.cr_bitfield.ok) # decoded/selected instruction flags - comb += e.invert_a.eq(op.inv_a) - comb += e.invert_out.eq(op.inv_out) - comb += e.input_carry.eq(op.cry_in) # carry comes in - comb += e.output_carry.eq(op.cry_out) # carry goes out - comb += e.is_32bit.eq(op.is_32b) - comb += e.is_signed.eq(op.sgn) + comb += do.data_len.eq(op.ldst_len) + 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 + comb += do.is_32bit.eq(op.is_32b) + comb += do.is_signed.eq(op.sgn) with m.If(op.lk): - comb += e.lk.eq(self.dec.LK) # XXX TODO: accessor - - comb += e.byte_reverse.eq(op.br) - comb += e.sign_extend.eq(op.sgn_ext) - comb += e.update.eq(op.upd) # LD/ST "update" mode. + comb += do.lk.eq(self.dec.LK) # XXX TODO: accessor + comb += do.byte_reverse.eq(op.br) + comb += do.sign_extend.eq(op.sgn_ext) + comb += do.ldst_mode.eq(op.upd) # LD/ST mode (update, cache-inhibit) # These should be removed eventually - comb += e.input_cr.eq(op.cr_in) # condition reg comes in - comb += e.output_cr.eq(op.cr_out) # condition reg goes in - + comb += do.input_cr.eq(op.cr_in) # condition reg comes in + comb += do.output_cr.eq(op.cr_out) # condition reg goes in + + # sigh this is exactly the sort of thing for which the + # 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) + with m.If(op.internal_op == MicrOp.OP_MTSPR): + comb += e.xer_out.eq(1) + + # set the trapaddr to 0x700 for a td/tw/tdi/twi operation + with m.If(op.internal_op == MicrOp.OP_TRAP): + # *DO NOT* call self.trap here. that would reset absolutely + # 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 + self.trap(m, TT.PRIV, 0x700) + + # illegal instruction must redirect to trap. this is done by + # *overwriting* the decoded instruction and starting again. + # (note: the same goes for interrupts and for privileged operations, + # just with different trapaddr and traptype) + with m.Elif(op.internal_op == MicrOp.OP_ILLEGAL): + # 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_out.insn_type == MicrOp.OP_TRAP) | + (do_out.insn_type == MicrOp.OP_SC)): + # TRAP write fast1 = SRR0 + 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_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_out.insn_type == MicrOp.OP_RFID): + # TRAP read fast1 = SRR0 + 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_out.read_fast2.data.eq(FastRegs.SRR1) # constant: SRR1 + comb += e_out.read_fast2.ok.eq(1) return m - def regspecmap(self, regfile, regname): - """regspecmap: 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. + def trap(self, m, traptype, trapaddr): + """trap: this basically "rewrites" the decoded instruction as a trap """ - return regspec_decode(self.e, regfile, regname) + comb = m.d.comb + op, do, e = self.dec.op, self.e.do, self.e + comb += e.eq(0) # reset eeeeeverything - def rdflags(self, cu): - rdl = [] - for idx in range(cu.n_src): - regfile, regname, _ = cu.get_in_spec(idx) - rdflag, read, write = self.regspecmap(regfile, regname) - rdl.append(rdflag) - print ("rdflags", rdl) - return Cat(*rdl) + # start again + comb += do.insn.eq(self.dec.opcode_in) + comb += do.insn_type.eq(MicrOp.OP_TRAP) + comb += do.fn_unit.eq(Function.TRAP) + comb += do.trapaddr.eq(trapaddr >> 4) # cut bottom 4 bits + comb += do.traptype.eq(traptype) # request type + comb += do.msr.eq(self.state.msr) # copy of MSR "state" + comb += do.cia.eq(self.state.pc) # copy of PC "state" + + +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__': @@ -655,4 +774,3 @@ if __name__ == '__main__': vl = rtlil.convert(dec2, ports=dec2.ports() + pdecode.ports()) with open("dec2.il", "w") as f: f.write(vl) -