rename substep to ssubstep, add dsubstep to SVP64State
[openpower-isa.git] / src / openpower / decoder / power_decoder2.py
index 2fa6feac74a14f9ccf2bc573395a90eb3240a7e7..52ae69cecfc41cfe5ce739ccd53c6ebeec0c9a2d 100644 (file)
@@ -41,7 +41,7 @@ from openpower.consts import (MSR, SPEC, EXTRA2, EXTRA3, SVP64P, field,
                               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):
@@ -78,7 +78,8 @@ class SPRMap(Elaboratable):
 
         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()
@@ -95,6 +96,10 @@ class SPRMap(Elaboratable):
                 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
 
 
@@ -116,7 +121,8 @@ class DecodeA(Elaboratable):
         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):
@@ -181,6 +187,7 @@ class DecodeA(Elaboratable):
                 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
 
@@ -229,7 +236,7 @@ class DecodeB(Elaboratable):
         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()
@@ -323,6 +330,9 @@ class DecodeBImm(Elaboratable):
             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
 
@@ -365,7 +375,7 @@ class DecodeC(Elaboratable):
                 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)
 
@@ -375,7 +385,7 @@ class DecodeC(Elaboratable):
 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):
@@ -390,7 +400,8 @@ class DecodeOut(Elaboratable):
         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()
@@ -401,6 +412,9 @@ class DecodeOut(Elaboratable):
 
         # 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)
@@ -418,6 +432,7 @@ class DecodeOut(Elaboratable):
                     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):
@@ -460,8 +475,8 @@ class DecodeOut2(Elaboratable):
         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()
@@ -572,7 +587,7 @@ class DecodeOE(Elaboratable):
                         MicrOp.OP_SHL, MicrOp.OP_SHR, MicrOp.OP_RLC,
                         MicrOp.OP_LOAD, MicrOp.OP_STORE,
                         MicrOp.OP_RLCL, MicrOp.OP_RLCR,
-                        MicrOp.OP_EXTSWSLI):
+                        MicrOp.OP_EXTSWSLI, MicrOp.OP_GREV, MicrOp.OP_TERNLOG):
                 pass
 
             # all other ops decode OE field
@@ -753,6 +768,7 @@ record_names = {'insn_type': 'internal_op',
                 'is_signed': 'sgn',
                 'lk': 'lk',
                 'data_len': 'ldst_len',
+                'reserve': 'rsrv',
                 'byte_reverse': 'br',
                 'sign_extend': 'sgn_ext',
                 'ldst_mode': 'upd',
@@ -847,6 +863,11 @@ class PowerDecodeSubset(Elaboratable):
                 # 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'])
                 )
 
@@ -940,20 +961,30 @@ class PowerDecodeSubset(Elaboratable):
 
         # 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
@@ -1060,6 +1091,7 @@ class PowerDecodeSubset(Elaboratable):
         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:
@@ -1108,13 +1140,17 @@ class PowerDecode2(PowerDecodeSubset):
     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")
@@ -1270,16 +1306,25 @@ class PowerDecode2(PowerDecodeSubset):
 
             # 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)
             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)
 
             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((
@@ -1287,7 +1332,7 @@ class PowerDecode2(PowerDecodeSubset):
                 ("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
@@ -1312,12 +1357,12 @@ class PowerDecode2(PowerDecodeSubset):
                     selectstep = dststep if out else srcstep
                     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))+ssubstep)
                     with m.Else():
-                        comb += step.eq(selectstep)
+                        comb += step.eq((selectstep*(subvl+1))+ssubstep)
                     # 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():
@@ -1373,7 +1418,8 @@ class PowerDecode2(PowerDecodeSubset):
 
             # 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])
@@ -1460,6 +1506,9 @@ class PowerDecode2(PowerDecodeSubset):
         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
@@ -1501,22 +1550,33 @@ class PowerDecode2(PowerDecodeSubset):
         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):
@@ -1599,12 +1659,15 @@ class PowerDecode2(PowerDecodeSubset):
         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)