CRInSel, CROutSel,
LdstLen, In1Sel, In2Sel, In3Sel,
OutSel, SPRfull, SPRreduced,
- RC, SVP64LDSTmode, LDSTMode,
+ RCOE, SVP64LDSTmode, LDSTMode,
SVEXTRA, SVEtype, SVPtype)
from openpower.decoder.decode2execute1 import (Decode2ToExecute1Type, Data,
Decode2ToOperand)
FastRegsEnum, XERRegsEnum, TT)
from openpower.state import CoreState
-from openpower.util import (spr_to_fast, log)
+from openpower.util import (spr_to_fast, spr_to_state, log)
def decode_spr_num(spr):
self.spr_i = Signal(10, reset_less=True)
self.spr_o = Data(SPR, name="spr_o")
- self.fast_o = Data(3, name="fast_o")
+ self.fast_o = Data(4, name="fast_o")
+ self.state_o = Data(3, name="state_o")
def elaborate(self, platform):
m = Module()
with m.Case(x.value):
m.d.comb += self.fast_o.data.eq(v)
m.d.comb += self.fast_o.ok.eq(1)
+ for x, v in spr_to_state.items():
+ with m.Case(x.value):
+ m.d.comb += self.state_o.data.eq(v)
+ m.d.comb += self.state_o.ok.eq(1)
return m
self.insn_in = Signal(32, reset_less=True)
self.reg_out = Data(5, name="reg_a")
self.spr_out = Data(SPR, "spr_a")
- self.fast_out = Data(3, "fast_a")
+ self.fast_out = Data(4, "fast_a")
+ self.state_out = Data(3, "state_a")
self.sv_nz = Signal(1)
def elaborate(self, platform):
comb += sprmap.spr_i.eq(spr)
comb += self.spr_out.eq(sprmap.spr_o)
comb += self.fast_out.eq(sprmap.fast_o)
+ comb += self.state_out.eq(sprmap.state_o)
return m
self.insn_in = Signal(32, reset_less=True)
self.reg_out = Data(7, "reg_b")
self.reg_isvec = Signal(1, name="reg_b_isvec") # TODO: in reg_out
- self.fast_out = Data(3, "fast_b")
+ self.fast_out = Data(4, "fast_b")
def elaborate(self, platform):
m = Module()
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)
+ with m.Case(In2Sel.CONST_XBI): # unsigned - for grevi
+ comb += self.imm_out.data.eq(self.dec.FormXB.XBI)
+ comb += self.imm_out.ok.eq(1)
return m
comb += reg.data.eq(self.dec.RC)
comb += reg.ok.eq(1)
with m.Case(In3Sel.RT):
- # for TI-form ternary
+ # for TLI-form ternlogi
comb += reg.data.eq(self.dec.RT)
comb += reg.ok.eq(1)
class DecodeOut(Elaboratable):
"""DecodeOut from instruction
- decodes output register RA, RT or SPR
+ decodes output register RA, RT, FRS, FRT, or SPR
"""
def __init__(self, dec, op, regreduce_en):
self.insn_in = Signal(32, reset_less=True)
self.reg_out = Data(5, "reg_o")
self.spr_out = Data(SPR, "spr_o")
- self.fast_out = Data(3, "fast_o")
+ self.fast_out = Data(4, "fast_o")
+ self.state_out = Data(3, "state_o")
def elaborate(self, platform):
m = Module()
# select Register out field
with m.Switch(self.sel_in):
+ with m.Case(OutSel.FRS):
+ comb += reg.data.eq(self.dec.FRS)
+ comb += reg.ok.eq(1)
with m.Case(OutSel.FRT):
comb += reg.data.eq(self.dec.FRT)
comb += reg.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)
+ comb += self.state_out.eq(sprmap.state_o)
# determine Fast Reg
with m.Switch(op.internal_op):
self.insn_in = Signal(32, reset_less=True)
self.reg_out = Data(5, "reg_o2")
self.fp_madd_en = Signal(reset_less=True) # FFT instruction detected
- self.fast_out = Data(3, "fast_o2")
- self.fast_out3 = Data(3, "fast_o3")
+ self.fast_out = Data(4, "fast_o2")
+ self.fast_out3 = Data(4, "fast_o3")
def elaborate(self, platform):
m = Module()
def __init__(self, dec):
self.dec = dec
- self.sel_in = Signal(RC, reset_less=True)
+ self.sel_in = Signal(RCOE, reset_less=True)
self.insn_in = Signal(32, reset_less=True)
self.rc_out = Data(1, "rc")
# select Record bit out field
with m.Switch(self.sel_in):
- with m.Case(RC.RC):
+ with m.Case(RCOE.RC, RCOE.RC_ONLY):
comb += self.rc_out.data.eq(self.dec.Rc)
comb += self.rc_out.ok.eq(1)
- with m.Case(RC.ONE):
+ with m.Case(RCOE.ONE):
comb += self.rc_out.data.eq(1)
comb += self.rc_out.ok.eq(1)
- with m.Case(RC.NONE):
+ with m.Case(RCOE.NONE):
comb += self.rc_out.data.eq(0)
comb += self.rc_out.ok.eq(1)
class DecodeOE(Elaboratable):
"""DecodeOE from instruction
- decodes OE field: uses RC decode detection which might not be good
-
- -- For now, use "rc" in the decode table to decide whether oe exists.
- -- This is not entirely correct architecturally: For mulhd and
- -- mulhdu, the OE field is reserved. It remains to be seen what an
- -- actual POWER9 does if we set it on those instructions, for now we
- -- test that further down when assigning to the multiplier oe input.
+ decodes OE field: uses RC decode detection which has now been
+ updated to separate out RC_ONLY. all cases RC_ONLY are *NOT*
+ listening to the OE field, here.
"""
def __init__(self, dec, op):
self.dec = dec
self.op = op
- self.sel_in = Signal(RC, reset_less=True)
+ self.sel_in = Signal(RCOE, reset_less=True)
self.insn_in = Signal(32, reset_less=True)
self.oe_out = Data(1, "oe")
def elaborate(self, platform):
m = Module()
comb = m.d.comb
- op = self.op
-
- with m.Switch(op.internal_op):
- # mulhw, mulhwu, mulhd, mulhdu - these *ignore* OE
- # 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
+ with m.Switch(self.sel_in):
+ with m.Case(RCOE.RC):
+ comb += self.oe_out.data.eq(self.dec.OE)
+ comb += self.oe_out.ok.eq(1)
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)
+ # default: clear OE.
+ comb += self.oe_out.data.eq(0)
+ comb += self.oe_out.ok.eq(0)
return m
'is_signed': 'sgn',
'lk': 'lk',
'data_len': 'ldst_len',
+ 'reserve': 'rsrv',
'byte_reverse': 'br',
'sign_extend': 'sgn_ext',
'ldst_mode': 'upd',
self.regreduce_en = regreduce_en
if svp64_en:
self.is_svp64_mode = Signal() # mark decoding as SVP64 Mode
- self.use_svp64_ldst_dec = Signal() # must use LDST decoder
self.use_svp64_fft = Signal() # FFT Mode
self.sv_rm = SVP64Rec(name="dec_svp64") # SVP64 RM field
self.rm_dec = SVP64RMModeDecode("svp64_rm_dec")
# alternatives. useful for PCR (Program Compatibility Register)
# amongst other things
if svp64_en:
- conditions = {'SVP64BREV': self.use_svp64_ldst_dec,
+ conditions = {
'SVP64FFT': self.use_svp64_fft,
}
else:
# 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']) or
+ # urrr... and the KAIVB SPR, which must also be redirected
+ # (to the TRAP pipeline)
+ # see https://bugs.libre-soc.org/show_bug.cgi?id=859
+ (self.fn_name == 'TRAP' and row['unit'] == 'SPR' and
row['internal op'] in ['OP_MTSPR', 'OP_MFSPR'])
)
if self.svp64_en:
ports += self.sv_rm.ports()
ports.append(self.is_svp64_mode)
- ports.append(self.use_svp64_ldst_dec)
ports.append(self.use_svp64_fft)
return ports
# Microwatt doesn't implement the partition table
# instead has PRTBL register (SPR) to point to process table
+ # Kestrel has a KAIVB SPR to "rebase" exceptions. rebasing is normally
+ # done with Hypervisor Mode which is not implemented (yet)
is_spr_mv = Signal()
is_mmu_spr = Signal()
+ is_trap_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.PRTBL.value) |
(spr == SPR.PIDR.value))
+ comb += is_trap_spr.eq((spr == SPR.KAIVB.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.MMU)
comb += self.do_copy("insn_type", internal_op)
- # SPR pipe must *not* receive MMU SPRs
- with m.Elif(is_spr_mv & (fn == Function.MMU) & ~is_mmu_spr):
+ # TRAP must receive TRAP SPR KAIVB
+ with m.If(is_spr_mv & (fn == Function.SPR) & is_trap_spr):
+ comb += self.do_copy("fn_unit", Function.TRAP)
+ comb += self.do_copy("insn_type", internal_op)
+ # SPR pipe must *not* receive MMU or TRAP SPRs
+ with m.Elif(is_spr_mv & ((fn == Function.MMU) & ~is_mmu_spr) &
+ ((fn == Function.TRAP) & ~is_trap_spr)):
comb += self.do_copy("fn_unit", Function.NONE)
comb += self.do_copy("insn_type", MicrOp.OP_ILLEGAL)
# all others ok
# the alternative decoder, svdecldst. what a mess... *sigh*
sv_ptype = self.op_get("SV_Ptype")
fn = self.op_get("function_unit")
- # detect major opcode for LDs: include 58 here. from CSV files.
- # BLECH! TODO: these should be done using "mini decoders",
- # using row and column subsets
- is_major_ld = Signal()
- # bits... errr... MSB0 0..5 which is 26:32 python
- major = Signal(6)
- comb += major.eq(self.dec.opcode_in[26:32])
- comb += is_major_ld.eq((major == 34) | (major == 35) |
- (major == 50) | (major == 51) |
- (major == 48) | (major == 49) |
- (major == 42) | (major == 43) |
- (major == 40) | (major == 41) |
- (major == 32) | (major == 33) |
- (major == 58))
- with m.If(self.is_svp64_mode & is_major_ld):
- # straight-up: "it's a LD". this gives enough info
- # for SVP64 RM Mode decoding to detect LD/ST, and
- # consequently detect the SHIFT mode. sigh
- comb += rm_dec.fn_in.eq(Function.LDST)
- with m.Else():
- comb += rm_dec.fn_in.eq(fn) # decode needs to know Fn type
+ comb += rm_dec.fn_in.eq(fn) # decode needs to know Fn type
comb += rm_dec.ptype_in.eq(sv_ptype) # Single/Twin predicated
comb += rm_dec.rc_in.eq(rc_out) # Rc=1
comb += rm_dec.rm_in.eq(self.sv_rm) # SVP64 RM mode
comb += rm_dec.ldst_imz_in.eq(bzero) # B immediate is zero
# main PowerDecoder2 determines if different SVP64 modes enabled
- if not self.final:
- # if shift mode requested
- shiftmode = rm_dec.ldstmode == SVP64LDSTmode.SHIFT
- comb += self.use_svp64_ldst_dec.eq(shiftmode)
# detect if SVP64 FFT mode enabled (really bad hack),
# exclude fcfids and others
# XXX this is a REALLY bad hack, REALLY has to be done better.
# likely with a sub-decoder.
+ major = Signal(6)
+ comb += major.eq(self.dec.opcode_in[26:32])
xo5 = Signal(1) # 1 bit from Minor 59 XO field == 0b0XXXX
comb += xo5.eq(self.dec.opcode_in[5])
xo = Signal(5) # 5 bits from Minor 59 fcfids == 0b01110
comb += self.do_copy("byte_reverse", self.op_get("br"))
comb += self.do_copy("sign_extend", self.op_get("sgn_ext"))
comb += self.do_copy("ldst_mode", self.op_get("upd")) # LD/ST mode
+ comb += self.do_copy("reserve", self.op_get("rsrv")) # atomic
# copy over SVP64 input record fields (if they exist)
if self.svp64_en:
to make this work, TestIssuer must notice "exception.happened"
after the (failed) LD/ST and copies the LDSTException info from
the output, into here (PowerDecoder2). without incrementing PC.
+
+ also instr_fault works the same way: the instruction is "rewritten"
+ so that the "fake" op that gets created is OP_FETCH_FAILED
"""
def __init__(self, dec, opkls=None, fn_name=None, final=False,
state=None, svp64_en=True, regreduce_en=False):
super().__init__(dec, opkls, fn_name, final, state, svp64_en,
regreduce_en=False)
- self.ldst_exc = LDSTException("dec2_exc")
+ self.ldst_exc = LDSTException("dec2_exc") # rewrites as OP_TRAP
+ self.instr_fault = Signal() # rewrites instruction as OP_FETCH_FAILED
if self.svp64_en:
self.cr_out_isvec = Signal(1, name="cr_out_isvec")
# get SVSTATE srcstep (TODO: elwidth etc.) needed below
vl = Signal.like(self.state.svstate.vl)
+ subvl = Signal.like(self.rm_dec.rm_in.subvl)
srcstep = Signal.like(self.state.svstate.srcstep)
dststep = Signal.like(self.state.svstate.dststep)
+ ssubstep = Signal.like(self.state.svstate.ssubstep)
+ dsubstep = Signal.like(self.state.svstate.ssubstep)
comb += vl.eq(self.state.svstate.vl)
+ comb += subvl.eq(self.rm_dec.rm_in.subvl)
comb += srcstep.eq(self.state.svstate.srcstep)
comb += dststep.eq(self.state.svstate.dststep)
+ comb += ssubstep.eq(self.state.svstate.ssubstep)
+ comb += dsubstep.eq(self.state.svstate.dsubstep)
in1_step, in2_step = self.in1_step, self.in2_step
in3_step = self.in3_step
o_step, o2_step = self.o_step, self.o2_step
+ # multiply vl by subvl - note that this is only 7 bit!
+ # when elwidth overrides get involved this will have to go up
+ vmax = Signal(7)
+ comb += vmax.eq(vl*(subvl+1))
+
# registers a, b, c and out and out2 (LD/ST EA)
sv_etype = self.op_get("SV_Etype")
for i, stuff in enumerate((
("RB", e.read_reg2, dec_b.reg_out, in2_svdec, in2_step, False),
("RC", e.read_reg3, dec_c.reg_out, in3_svdec, in3_step, False),
("RT", e.write_reg, dec_o.reg_out, o_svdec, o_step, True),
- ("EA", e.write_ea, dec_o2.reg_out, o2_svdec, o2_step, True))):
+ ("EA", e.write_ea, dec_o2.reg_out, o2_svdec, o2_step, True))):
rname, to_reg, fromreg, svdec, remapstep, out = stuff
comb += svdec.extra.eq(extra) # EXTRA field of SVP64 RM
comb += svdec.etype.eq(sv_etype) # EXTRA2/3 for this insn
# to_reg is 7-bits, outs get dststep added, ins get srcstep
with m.If(svdec.isvec):
selectstep = dststep if out else srcstep
+ subselect = dsubstep if out else ssubstep
step = Signal(7, name="step_%s" % rname.lower())
with m.If(self.remap_active[i]):
- comb += step.eq(remapstep)
+ comb += step.eq((remapstep*(subvl+1))+subselect)
with m.Else():
- comb += step.eq(selectstep)
+ comb += step.eq((selectstep*(subvl+1))+subselect)
# reverse gear goes the opposite way
with m.If(self.rm_dec.reverse_gear):
- comb += to_reg.data.eq(offs+svdec.reg_out+(vl-1-step))
+ comb += to_reg.data.eq(offs+svdec.reg_out+(vmax-1-step))
with m.Else():
comb += to_reg.data.eq(offs+step+svdec.reg_out)
with m.Else():
# TODO add SPRs here. must be True when *all* are scalar
l = map(lambda svdec: svdec.isvec, [in1_svdec, in2_svdec, in3_svdec,
- crin_svdec, crin_svdec_b, crin_svdec_o])
+ crin_svdec, crin_svdec_b,
+ crin_svdec_o])
comb += self.no_in_vec.eq(~Cat(*l).bool()) # all input scalar
l = map(lambda svdec: svdec.isvec, [
o2_svdec, o_svdec, crout_svdec])
comb += e.write_fast1.eq(dec_o.fast_out) # SRR0 (OP_RFID)
comb += e.write_fast2.eq(dec_o2.fast_out) # SRR1 (ditto)
comb += e.write_fast3.eq(dec_o2.fast_out3) # SVSRR0 (ditto)
+ # and State regs (DEC, TB)
+ comb += e.read_state1.eq(dec_a.state_out) # DEC/TB
+ comb += e.write_state1.eq(dec_o.state_out) # DEC/TB
# sigh this is exactly the sort of thing for which the
# decoder is designed to not need. MTSPR, MFSPR and others need
comb += priv_ok.eq(is_priv_insn & msr[MSR.PR])
comb += illeg_ok.eq(op.internal_op == MicrOp.OP_ILLEGAL)
+ # absolute top priority: check for an instruction failed
+ with m.If(self.instr_fault):
+ comb += self.e.eq(0) # reset eeeeeverything
+ comb += self.do_copy("insn", self.dec.opcode_in, True)
+ comb += self.do_copy("insn_type", MicrOp.OP_FETCH_FAILED, True)
+ comb += self.do_copy("fn_unit", Function.MMU, True)
+ comb += self.do_copy("cia", self.state.pc, True) # PC
+ comb += self.do_copy("msr", self.state.msr, True) # MSR
+ # special override on internal_op, due to being a "fake" op
+ comb += self.dec.op.internal_op.eq(MicrOp.OP_FETCH_FAILED)
+
# LD/ST exceptions. TestIssuer copies the exception info at us
# after a failed LD/ST.
- with m.If(ldst_exc.happened):
+ with m.Elif(ldst_exc.happened):
with m.If(ldst_exc.alignment):
- self.trap(m, TT.PRIV, 0x600)
+ self.trap(m, TT.MEMEXC, 0x600)
with m.Elif(ldst_exc.instr_fault):
with m.If(ldst_exc.segment_fault):
- self.trap(m, TT.PRIV, 0x480)
+ self.trap(m, TT.MEMEXC, 0x480)
with m.Else():
# pass exception info to trap to create SRR1
self.trap(m, TT.MEMEXC, 0x400, ldst_exc)
with m.Else():
with m.If(ldst_exc.segment_fault):
- self.trap(m, TT.PRIV, 0x380)
+ self.trap(m, TT.MEMEXC, 0x380)
with m.Else():
- self.trap(m, TT.PRIV, 0x300)
+ self.trap(m, TT.MEMEXC, 0x300)
# decrement counter (v3.0B p1099): TODO 32-bit version (MSR.LPCR)
with m.Elif(dec_irq_ok):
comb += self.do_copy("svstate", self.state.svstate, True) # SVSTATE
-def get_rdflags(e, cu):
+def get_rdflags(m, e, cu):
+ """returns a sequential list of the read "ok" flags for a given FU.
+ this list is in order of the CompUnit input specs
+ """
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)
+ decinfo = regspec_decode_read(m, e, regfile, regname)
+ rdl.append(decinfo.okflag)
log("rdflags", rdl)
return Cat(*rdl)