whoops update PowerDecoder2 svp64 comments, reg sizes (7 bit)
[soc.git] / src / soc / decoder / power_decoder2.py
index 5e89916a28d5f9d3d6a5ed7588f7a53cfb0df4c3..71b2b0788d952484d85a4beb180b238533914f41 100644 (file)
@@ -22,9 +22,11 @@ from soc.decoder.power_decoder import create_pdecode
 from soc.decoder.power_enums import (MicrOp, CryIn, Function,
                                      CRInSel, CROutSel,
                                      LdstLen, In1Sel, In2Sel, In3Sel,
-                                     OutSel, SPR, RC, LDSTMode)
+                                     OutSel, SPR, RC, LDSTMode,
+                                     SVEXTRA, SVEtype)
 from soc.decoder.decode2execute1 import (Decode2ToExecute1Type, Data,
                                          Decode2ToOperand)
+from soc.sv.svp64 import SVP64Rec
 from soc.consts import MSR
 
 from soc.regfile.regfiles import FastRegs
@@ -77,6 +79,77 @@ class SPRMap(Elaboratable):
         return m
 
 
+class SVP64RegExtra(Elaboratable):
+    """SVP64RegExtra - decodes SVP64 Extra fields to determine reg extension
+
+    incoming 5-bit GPR/FP is turned into a 7-bit and marked as scalar/vector
+    depending on info in one of the positions in the EXTRA field.
+
+    designed so that "no change" to the 5-bit register number occurs if
+    SV either does not apply or the relevant EXTRA2/3 field bits are zero.
+
+    see https://libre-soc.org/openpower/sv/svp64/
+    """
+    def __init__(self):
+        self.extra   = Signal(10, reset_less=True)
+        self.etype   = Signal(SVEtype, reset_less=True) # 2 or 3 bits
+        self.idx     = Signal(SVEXTRA, reset_less=True) # which part of extra
+        self.reg_in  = Signal(5) # incoming reg number (5 bits, RA, RB)
+        self.reg_out = Signal(7) # extra-augmented output (7 bits)
+        self.isvec   = Signal(1) # reg is marked as vector if true
+
+    def elaborate(self, platform):
+        m = Module()
+        comb = m.d.comb
+
+        # first get the spec.  if not changed it's "scalar identity behaviour"
+        # which is zero which is ok.
+        spec = Signal(3)
+
+        # back in the LDSTRM-* and RM-* files generated by sv_analysis.py
+        # we marked every op with an Etype: EXTRA2 or EXTRA3, and also said
+        # which of the 4 (or 3 for EXTRA3) sub-fields of bits 10:18 contain
+        # the register-extension information.  extract those how
+        with m.Switch(self.etype):
+            # 2-bit index selection mode
+            with m.Case(SVEtype.EXTRA2):
+                with m.Switch(self.idx):
+                    with m.Case(SVEXTRA.Idx0): # 1st 2 bits
+                        comb += spec[1:3].eq(self.extra[0:2])
+                    with m.Case(SVEXTRA.Idx1): # 2nd 2 bits
+                        comb += spec[1:3].eq(self.extra[2:4])
+                    with m.Case(SVEXTRA.Idx2): # 3rd 2 bits
+                        comb += spec[1:3].eq(self.extra[4:6])
+                    with m.Case(SVEXTRA.Idx3): # 4th 2 bits
+                        comb += spec[1:3].eq(self.extra[6:8])
+            # 3-bit index selection mode
+            with m.Case(SVEtype.EXTRA3):
+                with m.Switch(self.idx):
+                    with m.Case(SVEXTRA.Idx0): # 1st 3 bits
+                        comb += spec.eq(self.extra[0:3])
+                    with m.Case(SVEXTRA.Idx1): # 2nd 3 bits
+                        comb += spec.eq(self.extra[3:6])
+                    with m.Case(SVEXTRA.Idx2): # 3rd 3 bits
+                        comb += spec.eq(self.extra[6:9])
+                    # cannot fit more than 9 bits so there is no 4th thing
+
+        # now decode it. bit 2 is "scalar/vector".  note that spec could be zero
+        #  from above, which (by design) has the effect of "no change", below.
+
+        # simple: isvec is top bit of spec
+        comb += self.isvec.eq(spec[2])
+
+        # decode vector differently from scalar
+        with m.If(self.isvec):
+            # Vector: shifted up, extra in LSBs (RA << 2) | spec[0:1]
+            comb += self.reg_out.eq(Cat(spec[:2], self.reg_in))
+        with m.Else():
+            # Scalar: not shifted up, extra in MSBs RA | (spec[0:1] << 5)
+            comb += self.reg_out.eq(Cat(self.reg_in, spec[:2]))
+
+        return m
+
+
 class DecodeA(Elaboratable):
     """DecodeA from instruction
 
@@ -85,16 +158,23 @@ class DecodeA(Elaboratable):
 
     def __init__(self, dec):
         self.dec = dec
+        self.sv_rm = SVP64Rec() # SVP64 RM field
         self.sel_in = Signal(In1Sel, reset_less=True)
         self.insn_in = Signal(32, reset_less=True)
-        self.reg_out = Data(5, name="reg_a")
+        self.reg_out = Data(7, name="reg_a")
+        self.reg_isvec = Signal(1, name="reg_a_isvec") # TODO: in reg_out
         self.spr_out = Data(SPR, "spr_a")
         self.fast_out = Data(3, "fast_a")
 
     def elaborate(self, platform):
         m = Module()
         comb = m.d.comb
+        op = self.dec.op
         m.submodules.sprmap = sprmap = SPRMap()
+        m.submodules.svdec = svdec = SVP64RegExtra()
+
+        # get the 5-bit reg data before svp64-munging it into 7-bit plus isvec
+        reg = Signal(5, reset_less=True)
 
         # select Register A field
         ra = Signal(5, reset_less=True)
@@ -102,16 +182,32 @@ class DecodeA(Elaboratable):
         with m.If((self.sel_in == In1Sel.RA) |
                   ((self.sel_in == In1Sel.RA_OR_ZERO) &
                    (ra != Const(0, 5)))):
-            comb += self.reg_out.data.eq(ra)
+            comb += reg.eq(ra)
             comb += self.reg_out.ok.eq(1)
 
         # some Logic/ALU ops have RS as the 3rd arg, but no "RA".
+        # moved it to 1st position (in1_sel)... because
+        rs = Signal(5, reset_less=True)
+        comb += rs.eq(self.dec.RS)
         with m.If(self.sel_in == In1Sel.RS):
-            comb += self.reg_out.data.eq(self.dec.RS)
+            comb += reg.eq(rs)
             comb += self.reg_out.ok.eq(1)
 
+        # now do the SVP64 munging.  op.SV_Etype and op.sv_in1 comes from
+        # PowerDecoder which in turn comes from LDST-RM*.csv and RM-*.csv
+        # which in turn were auto-generated by sv_analysis.py
+
+        extra = self.sv_rm.extra            # SVP64 extra bits 10:18
+        comb += svdec.extra.eq(extra)       # EXTRA field of SVP64 RM
+        comb += svdec.etype.eq(op.SV_Etype) # EXTRA2/3 for this insn
+        comb += svdec.idx.eq(op.sv_in1)     # SVP64 reg #1 (matches in1_sel)
+        comb += svdec.reg_in.eq(reg)        # 5-bit (RA, RS)
+
+        # outputs: 7-bit reg number and whether it's vectorised
+        comb += self.reg_out.data.eq(svdec.reg_out)
+        comb += self.reg_isvec.eq(svdec.isvec)
+
         # decode Fast-SPR based on instruction type
-        op = self.dec.op
         with m.Switch(op.internal_op):
 
             # BC or BCREG: implicit register (CTR) NOTE: same in DecodeOut
@@ -175,27 +271,45 @@ class DecodeB(Elaboratable):
 
     def __init__(self, dec):
         self.dec = dec
+        self.sv_rm = SVP64Rec() # SVP64 RM field
         self.sel_in = Signal(In2Sel, reset_less=True)
         self.insn_in = Signal(32, reset_less=True)
-        self.reg_out = Data(5, "reg_b")
+        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")
 
     def elaborate(self, platform):
         m = Module()
         comb = m.d.comb
+        op = self.dec.op
+        m.submodules.svdec = svdec = SVP64RegExtra()
+
+        # get the 5-bit reg data before svp64-munging it into 7-bit plus isvec
+        reg = Signal(5, reset_less=True)
 
         # select Register B field
         with m.Switch(self.sel_in):
             with m.Case(In2Sel.RB):
-                comb += self.reg_out.data.eq(self.dec.RB)
+                comb += reg.eq(self.dec.RB)
                 comb += self.reg_out.ok.eq(1)
             with m.Case(In2Sel.RS):
                 # for M-Form shiftrot
-                comb += self.reg_out.data.eq(self.dec.RS)
+                comb += reg.eq(self.dec.RS)
                 comb += self.reg_out.ok.eq(1)
 
+        # now do the SVP64 munging.  different from DecodeA only by sv_in2
+
+        extra = self.sv_rm.extra            # SVP64 extra bits 10:18
+        comb += svdec.extra.eq(extra)       # EXTRA field of SVP64 RM
+        comb += svdec.etype.eq(op.SV_Etype) # EXTRA2/3 for this insn
+        comb += svdec.idx.eq(op.sv_in2)     # SVP64 reg #2 (matches in2_sel)
+        comb += svdec.reg_in.eq(reg)        # 5-bit (RA, RS)
+
+        # outputs: 7-bit reg number and whether it's vectorised
+        comb += self.reg_out.data.eq(svdec.reg_out)
+        comb += self.reg_isvec.eq(svdec.isvec)
+
         # decode SPR2 based on instruction type
-        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 == MicrOp.OP_BCREG):
@@ -279,24 +393,43 @@ class DecodeC(Elaboratable):
 
     def __init__(self, dec):
         self.dec = dec
+        self.sv_rm = SVP64Rec() # SVP64 RM field
         self.sel_in = Signal(In3Sel, reset_less=True)
         self.insn_in = Signal(32, reset_less=True)
-        self.reg_out = Data(5, "reg_c")
+        self.reg_out = Data(7, "reg_c")
+        self.reg_isvec = Signal(1, name="reg_c_isvec") # TODO: in reg_out
 
     def elaborate(self, platform):
         m = Module()
         comb = m.d.comb
+        op = self.dec.op
+        m.submodules.svdec = svdec = SVP64RegExtra()
+
+        # get the 5-bit reg data before svp64-munging it into 7-bit plus isvec
+        reg = Signal(5, reset_less=True)
 
         # select Register C field
         with m.Switch(self.sel_in):
             with m.Case(In3Sel.RB):
                 # for M-Form shiftrot
-                comb += self.reg_out.data.eq(self.dec.RB)
+                comb += reg.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)
+                comb += reg.eq(self.dec.RS)
                 comb += self.reg_out.ok.eq(1)
 
+        # now do the SVP64 munging.  different from DecodeA only by sv_in3
+
+        extra = self.sv_rm.extra            # SVP64 extra bits 10:18
+        comb += svdec.extra.eq(extra)       # EXTRA field of SVP64 RM
+        comb += svdec.etype.eq(op.SV_Etype) # EXTRA2/3 for this insn
+        comb += svdec.idx.eq(op.sv_in3)     # SVP64 reg #3 (matches in3_sel)
+        comb += svdec.reg_in.eq(reg)        # 5-bit (RA, RS)
+
+        # outputs: 7-bit reg number and whether it's vectorised
+        comb += self.reg_out.data.eq(svdec.reg_out)
+        comb += self.reg_isvec.eq(svdec.isvec)
+
         return m
 
 
@@ -308,9 +441,11 @@ class DecodeOut(Elaboratable):
 
     def __init__(self, dec):
         self.dec = dec
+        self.sv_rm = SVP64Rec() # SVP64 RM field
         self.sel_in = Signal(OutSel, reset_less=True)
         self.insn_in = Signal(32, reset_less=True)
-        self.reg_out = Data(5, "reg_o")
+        self.reg_out = Data(7, "reg_o")
+        self.reg_isvec = Signal(1, name="reg_o_isvec") # TODO: in reg_out
         self.spr_out = Data(SPR, "spr_o")
         self.fast_out = Data(3, "fast_o")
 
@@ -319,14 +454,18 @@ class DecodeOut(Elaboratable):
         comb = m.d.comb
         m.submodules.sprmap = sprmap = SPRMap()
         op = self.dec.op
+        m.submodules.svdec = svdec = SVP64RegExtra()
+
+        # get the 5-bit reg data before svp64-munging it into 7-bit plus isvec
+        reg = Signal(5, reset_less=True)
 
         # select Register out field
         with m.Switch(self.sel_in):
             with m.Case(OutSel.RT):
-                comb += self.reg_out.data.eq(self.dec.RT)
+                comb += reg.eq(self.dec.RT)
                 comb += self.reg_out.ok.eq(1)
             with m.Case(OutSel.RA):
-                comb += self.reg_out.data.eq(self.dec.RA)
+                comb += reg.eq(self.dec.RA)
                 comb += self.reg_out.ok.eq(1)
             with m.Case(OutSel.SPR):
                 spr = Signal(10, reset_less=True)
@@ -337,6 +476,19 @@ class DecodeOut(Elaboratable):
                     comb += self.spr_out.eq(sprmap.spr_o)
                     comb += self.fast_out.eq(sprmap.fast_o)
 
+        # now do the SVP64 munging.  different from DecodeA only by sv_out
+
+        extra = self.sv_rm.extra            # SVP64 extra bits 10:18
+        comb += svdec.extra.eq(extra)       # EXTRA field of SVP64 RM
+        comb += svdec.etype.eq(op.SV_Etype) # EXTRA2/3 for this insn
+        comb += svdec.idx.eq(op.sv_out)     # SVP64 reg out1 (matches out_sel)
+        comb += svdec.reg_in.eq(reg)        # 5-bit (RA, RS)
+
+        # outputs: 7-bit reg number and whether it's vectorised
+        comb += self.reg_out.data.eq(svdec.reg_out)
+        comb += self.reg_isvec.eq(svdec.isvec)
+
+        # determine Fast Reg
         with m.Switch(op.internal_op):
 
             # BC or BCREG: implicit register (CTR) NOTE: same in DecodeA
@@ -357,30 +509,44 @@ class DecodeOut(Elaboratable):
 class DecodeOut2(Elaboratable):
     """DecodeOut2 from instruction
 
-    decodes output registers
+    decodes output registers (2nd one).  note that RA is *implicit* below,
+    which now causes problems with SVP64
+
+    TODO: SVP64 is a little more complex, here.  svp64 allows extending
+    by one more destination by having one more EXTRA field.  RA-as-src
+    is not the same as RA-as-dest.  limited in that it's the same first
+    5 bits (from the v3.0B opcode), but still kinda cool.  mostly used
+    for operations that have src-as-dest: mostly this is LD/ST-with-update
+    but there are others.
     """
 
     def __init__(self, dec):
         self.dec = dec
+        self.sv_rm = SVP64Rec() # SVP64 RM field
         self.sel_in = Signal(OutSel, reset_less=True)
         self.lk = Signal(reset_less=True)
         self.insn_in = Signal(32, reset_less=True)
-        self.reg_out = Data(5, "reg_o")
-        self.fast_out = Data(3, "fast_o")
+        self.reg_out = Data(7, "reg_o2")
+        #self.reg_isvec = Signal(1, name="reg_o2_isvec") # TODO: in reg_out
+        self.fast_out = Data(3, "fast_o2")
 
     def elaborate(self, platform):
         m = Module()
         comb = m.d.comb
+        op = self.dec.op
+        #m.submodules.svdec = svdec = SVP64RegExtra()
+
+        # get the 5-bit reg data before svp64-munging it into 7-bit plus isvec
+        #reg = Signal(5, reset_less=True)
 
         if hasattr(self.dec.op, "upd"):
             # update mode LD/ST uses read-reg A also as an output
             with m.If(self.dec.op.upd == LDSTMode.update):
-                comb += self.reg_out.eq(self.dec.RA)
+                comb += self.reg_out.data.eq(self.dec.RA)
                 comb += self.reg_out.ok.eq(1)
 
         # B, BC or BCREG: potential implicit register (LR) output
         # these give bl, bcl, bclrl, etc.
-        op = self.dec.op
         with m.Switch(op.internal_op):
 
             # BC* implicit register (LR)
@@ -485,6 +651,7 @@ class DecodeCRIn(Elaboratable):
 
     def __init__(self, dec):
         self.dec = dec
+        self.sv_rm = SVP64Rec() # SVP64 RM field
         self.sel_in = Signal(CRInSel, reset_less=True)
         self.insn_in = Signal(32, reset_less=True)
         self.cr_bitfield = Data(3, "cr_bitfield")
@@ -549,6 +716,7 @@ class DecodeCROut(Elaboratable):
 
     def __init__(self, dec):
         self.dec = dec
+        self.sv_rm = SVP64Rec() # SVP64 RM field
         self.rc_in = Signal(reset_less=True)
         self.sel_in = Signal(CROutSel, reset_less=True)
         self.insn_in = Signal(32, reset_less=True)
@@ -623,18 +791,23 @@ record_names = {'insn_type': 'internal_op',
 
 class PowerDecodeSubset(Elaboratable):
     """PowerDecodeSubset: dynamic subset decoder
+
+    only fields actually requested are copied over. hence, "subset" (duh).
     """
     def __init__(self, dec, opkls=None, fn_name=None, final=False, state=None):
 
+        self.sv_rm = SVP64Rec(name="dec_svp64") # SVP64 RM field
         self.final = final
         self.opkls = opkls
         self.fn_name = fn_name
         if opkls is None:
             opkls = Decode2ToOperand
         self.do = opkls(fn_name)
+        col_subset = self.get_col_subset(self.do)
+
+        # only needed for "main" PowerDecode2
         if not self.final:
             self.e = Decode2ToExecute1Type(name=self.fn_name, do=self.do)
-        col_subset = self.get_col_subset(self.do)
 
         # create decoder if one not already given
         if dec is None:
@@ -659,7 +832,7 @@ class PowerDecodeSubset(Elaboratable):
         return row['unit'] == self.fn_name
 
     def ports(self):
-        return self.dec.ports() + self.e.ports()
+        return self.dec.ports() + self.e.ports() + self.sv_rm.ports()
 
     def needs_field(self, field, op_field):
         if self.final:
@@ -713,6 +886,8 @@ class PowerDecodeSubset(Elaboratable):
         comb += dec_rc.sel_in.eq(op.rc_sel)
         comb += dec_oe.sel_in.eq(op.rc_sel)  # XXX should be OE sel
         comb += self.dec_cr_in.sel_in.eq(op.cr_in)
+        comb += self.dec_cr_in.sv_rm.eq(self.sv_rm)
+        comb += self.dec_cr_out.sv_rm.eq(self.sv_rm)
         comb += self.dec_cr_out.sel_in.eq(op.cr_out)
         comb += self.dec_cr_out.rc_in.eq(dec_rc.rc_out.data)
 
@@ -720,10 +895,24 @@ class PowerDecodeSubset(Elaboratable):
         comb += self.do_copy("msr", msr)
         comb += self.do_copy("cia", cia)
 
-        # set up instruction, pick fn unit
+        # set up instruction type
         # no op: defaults to OP_ILLEGAL
         comb += self.do_copy("insn_type", self.op_get("internal_op"))
-        comb += self.do_copy("fn_unit", self.op_get("function_unit"))
+
+        # function unit for decoded instruction: requires minor redirect
+        # for SPR set/get
+        fn = self.op_get("function_unit")
+        spr = Signal(10, reset_less=True)
+        comb += spr.eq(decode_spr_num(self.dec.SPR)) # from XFX
+
+        # for first test only forward SPRs 18 and 19 to MMU, when
+        # operation is MTSPR or MFSPR.  TODO: add other MMU SPRs
+        with m.If(((self.dec.op.internal_op == MicrOp.OP_MTSPR) |
+                   (self.dec.op.internal_op == MicrOp.OP_MFSPR)) &
+                  ((spr == SPR.DSISR) | (spr == SPR.DAR))):
+            comb += self.do_copy("fn_unit", Function.MMU)
+        with m.Else():
+            comb += self.do_copy("fn_unit",fn)
 
         # immediates
         if self.needs_field("zero_a", "in1_sel"):
@@ -804,11 +993,17 @@ class PowerDecode2(PowerDecodeSubset):
 
     def get_col_subset(self, opkls):
         subset = super().get_col_subset(opkls)
-        subset.add("in1_sel")
         subset.add("asmcode")
+        subset.add("in1_sel")
         subset.add("in2_sel")
         subset.add("in3_sel")
         subset.add("out_sel")
+        subset.add("sv_in1")
+        subset.add("sv_in2")
+        subset.add("sv_in3")
+        subset.add("sv_out")
+        subset.add("SV_Etype")
+        subset.add("SV_Ptype")
         subset.add("lk")
         subset.add("internal_op")
         subset.add("form")
@@ -838,6 +1033,11 @@ class PowerDecode2(PowerDecodeSubset):
                   dec_c.insn_in, dec_o.insn_in, dec_o2.insn_in]:
             comb += i.eq(self.dec.opcode_in)
 
+        # ... and svp64 rm
+        for i in [dec_a.insn_in, dec_b.insn_in,
+                  dec_c.insn_in, dec_o.insn_in, dec_o2.insn_in]:
+            comb += i.eq(self.sv_rm)
+
         # ...and subdecoders' input fields
         comb += dec_a.sel_in.eq(op.in1_sel)
         comb += dec_b.sel_in.eq(op.in2_sel)
@@ -848,11 +1048,14 @@ class PowerDecode2(PowerDecodeSubset):
             comb += dec_o2.lk.eq(do.lk)
 
         # registers a, b, c and out and out2 (LD/ST EA)
-        comb += e.read_reg1.eq(dec_a.reg_out)
-        comb += e.read_reg2.eq(dec_b.reg_out)
-        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)
+        for to_reg, fromreg in (
+            (e.read_reg1, dec_a.reg_out),
+            (e.read_reg2, dec_b.reg_out),
+            (e.read_reg3, dec_c.reg_out),
+            (e.write_reg, dec_o.reg_out),
+            (e.write_ea, dec_o2.reg_out)):
+            comb += to_reg.data.eq(fromreg.data)
+            comb += to_reg.ok.eq(fromreg.ok)
 
         # SPRs out
         comb += e.read_spr1.eq(dec_a.spr_out)