and now for something completely different...
[soc.git] / src / soc / sv / trans / svp64.py
index b1b59f18a1b7682e1fa98e77d8b4e760d57553b4..7fe923170e0a25e73b5f6d2b348675068c665560 100644 (file)
@@ -39,6 +39,72 @@ def get_regtype(regname):
     if is_GPR(regname):
         return "GPR"
 
+# decode GPR into sv extra
+def  get_extra_gpr(etype, regmode, field):
+    if regmode == 'scalar':
+        # cut into 2-bits 5-bits SS FFFFF
+        sv_extra = field >> 5
+        field = field & 0b11111
+    else:
+        # cut into 5-bits 2-bits FFFFF SS
+        sv_extra = field & 0b11
+        field = field >> 2
+    return sv_extra, field
+
+
+# decode 3-bit CR into sv extra
+def  get_extra_cr_3bit(etype, regmode, field):
+    if regmode == 'scalar':
+        # cut into 2-bits 3-bits SS FFF
+        sv_extra = field >> 3
+        field = field & 0b111
+    else:
+        # cut into 3-bits 4-bits FFF SSSS but will cut 2 zeros off later
+        sv_extra = field & 0b1111
+        field = field >> 4
+    return sv_extra, field
+
+
+# decodes SUBVL
+def decode_subvl(encoding):
+    pmap = {'2': 0b01, '3': 0b10, '4': 0b11}
+    assert encoding in pmap, \
+        "encoding %s for SUBVL not recognised" % encoding
+    return pmap[encoding]
+
+
+# decodes elwidth
+def decode_elwidth(encoding):
+    pmap = {'8': 0b11, '16': 0b10, '32': 0b01}
+    assert encoding in pmap, \
+        "encoding %s for elwidth not recognised" % encoding
+    return pmap[encoding]
+
+
+# decodes predicate register encoding
+def decode_predicate(encoding):
+    pmap = { # integer
+            '1<<r3': (0, 0b001),
+            'r3'   : (0, 0b010),
+            '~r3'   : (0, 0b011),
+            'r10'   : (0, 0b100),
+            '~r10'  : (0, 0b101),
+            'r30'   : (0, 0b110),
+            '~r30'  : (0, 0b111),
+            # CR
+            'lt'    : (1, 0b000),
+            'nl'    : (1, 0b001), 'ge'    : (1, 0b001), # same value
+            'gt'    : (1, 0b010),
+            'ng'    : (1, 0b011), 'le'    : (1, 0b011), # same value
+            'eq'    : (1, 0b100),
+            'ne'    : (1, 0b101),
+            'so'    : (1, 0b110), 'un'    : (1, 0b110), # same value
+            'ns'    : (1, 0b111), 'nu'    : (1, 0b111), # same value
+           }
+    assert encoding in pmap, \
+        "encoding %s for predicate not recognised" % encoding
+    return pmap[encoding]
+
 
 # gets SVP64 ReMap information
 class SVP64RM:
@@ -72,7 +138,7 @@ class SVP64:
             # now find opcode fields
             fields = ''.join(ls[1:]).split(',')
             fields = list(map(str.strip, fields))
-            print (opcode, fields)
+            print ("opcode, fields", ls, opcode, fields)
 
             # identify if is a svp64 mnemonic
             if not opcode.startswith('sv.'):
@@ -102,6 +168,9 @@ class SVP64:
 
             # first turn the svp64 rm into a "by name" dict, recording
             # which position in the RM EXTRA it goes into
+            # also: record if the src or dest was a CR, for sanity-checking
+            # (elwidth overrides on CRs are banned)
+            dest_reg_cr, src_reg_cr = False, False
             svp64_reg_byname = {}
             for i in range(4):
                 rfield = rm[str(i)]
@@ -110,8 +179,17 @@ class SVP64:
                 print ("EXTRA field", i, rfield)
                 rfield = rfield.split(";") # s:RA;d:CR1 etc.
                 for r in rfield:
+                    rtype = r[0]
                     r = r[2:] # ignore s: and d:
                     svp64_reg_byname[r] = i # this reg in EXTRA position 0-3
+                    # check the regtype (if CR, record that)
+                    regtype = get_regtype(r)
+                    if regtype in ['CR_3bit', 'CR_5bit']:
+                        if rtype == 'd':
+                            dest_reg_cr = True
+                        if rtype == 'd':
+                            src_reg_cr = True
+
             print ("EXTRA field index, by regname", svp64_reg_byname)
 
             # okaaay now we identify the field value (opcode N,N,N) with
@@ -129,6 +207,7 @@ class SVP64:
             # great! got the extra fields in their associated positions:
             # also we know the register type. now to create the EXTRA encodings
             etype = rm['Etype'] # Extra type: EXTRA3/EXTRA2
+            ptype = rm['Ptype'] # Predication type: Twin / Single
             extra_bits = 0
             v30b_newfields = []
             for extra_idx, (idx, field, regname, regtype) in extras.items():
@@ -146,31 +225,208 @@ class SVP64:
                     elif field[1] == 'v':
                         regmode = 'vector'
                 field = int(field[0]) # actual register number
-                print ("    ", regmode, field)
+                print ("    ", regmode, field, end=" ")
+
+                # XXX TODO: the following is a bit of a laborious repeated
+                # mess, which could (and should) easily be parameterised.
+
+                # encode SV-GPR field into extra, v3.0field
                 if regtype == 'GPR':
-                    if regmode == 'scalar':
-                        # cut into 2-bits 5-bits SS FFFFF
-                        sv_extra = field >> 5
-                        field = field & 0b11111
-                    else:
-                        # cut into 5-bits 2-bits FFFFF SS
-                        sv_extra = field & 0b11
-                        field = field >> 2
+                    sv_extra, field = get_extra_gpr(etype, regmode, field)
                     # now sanity-check. EXTRA3 is ok, EXTRA2 has limits
+                    # (and shrink to a single bit if ok)
                     if etype == 'EXTRA2':
                         if regmode == 'scalar':
-                            assert sv_extra & 0b10 == 0, \
-                                "scalar field %s cannot fit into EXTRA2 %s" % \
+                            # range is r0-r63 in increments of 1
+                            assert (sv_extra >> 1) == 0, \
+                                "scalar GPR %s cannot fit into EXTRA2 %s" % \
                                     (regname, str(extras[extra_idx]))
+                            # all good: encode as scalar
+                            sv_extra = sv_extra & 0b01
                         else:
+                            # range is r0-r127 in increments of 4
                             assert sv_extra & 0b01 == 0, \
                                 "vector field %s cannot fit into EXTRA2 %s" % \
                                     (regname, str(extras[extra_idx]))
+                            # all good: encode as vector (bit 2 set)
+                            sv_extra = 0b10 | (sv_extra >> 1)
+                    elif regmode == 'vector':
+                        # EXTRA3 vector bit needs marking
+                        sv_extra |= 0b100
+
+                # encode SV-CR 3-bit field into extra, v3.0field
+                elif regtype == 'CR_3bit':
+                    sv_extra, field = get_extra_cr_3bit(etype, regmode, field)
+                    # now sanity-check (and shrink afterwards)
+                    if etype == 'EXTRA2':
+                        if regmode == 'scalar':
+                            # range is CR0-CR15 in increments of 1
+                            assert (sv_extra >> 1) == 0, \
+                                "scalar CR %s cannot fit into EXTRA2 %s" % \
+                                    (regname, str(extras[extra_idx]))
+                            # all good: encode as scalar
+                            sv_extra = sv_extra & 0b01
+                        else:
+                            # range is CR0-CR127 in increments of 16
+                            assert sv_extra & 0b111 == 0, \
+                                "vector CR %s cannot fit into EXTRA2 %s" % \
+                                    (regname, str(extras[extra_idx]))
+                            # all good: encode as vector (bit 2 set)
+                            sv_extra = 0b10 | (sv_extra >> 3)
+                    else:
+                        if regmode == 'scalar':
+                            # range is CR0-CR31 in increments of 1
+                            assert (sv_extra >> 2) == 0, \
+                                "scalar CR %s cannot fit into EXTRA2 %s" % \
+                                    (regname, str(extras[extra_idx]))
+                            # all good: encode as scalar
+                            sv_extra = sv_extra & 0b11
+                        else:
+                            # range is CR0-CR127 in increments of 8
+                            assert sv_extra & 0b11 == 0, \
+                                "vector CR %s cannot fit into EXTRA2 %s" % \
+                                    (regname, str(extras[extra_idx]))
+                            # all good: encode as vector (bit 3 set)
+                            sv_extra = 0b100 | (sv_extra >> 2)
+
+                # encode SV-CR 5-bit field into extra, v3.0field
+                # *sigh* this is the same as 3-bit except the 2 LSBs are
+                # passed through
+                elif regtype == 'CR_5bit':
+                    cr_subfield = field & 0b11
+                    field = field >> 2 # strip bottom 2 bits
+                    sv_extra, field = get_extra_cr_3bit(etype, regmode, field)
+                    # now sanity-check (and shrink afterwards)
+                    if etype == 'EXTRA2':
+                        if regmode == 'scalar':
+                            # range is CR0-CR15 in increments of 1
+                            assert (sv_extra >> 1) == 0, \
+                                "scalar CR %s cannot fit into EXTRA2 %s" % \
+                                    (regname, str(extras[extra_idx]))
+                            # all good: encode as scalar
+                            sv_extra = sv_extra & 0b01
+                        else:
+                            # range is CR0-CR127 in increments of 16
+                            assert sv_extra & 0b111 == 0, \
+                                "vector CR %s cannot fit into EXTRA2 %s" % \
+                                    (regname, str(extras[extra_idx]))
+                            # all good: encode as vector (bit 2 set)
+                            sv_extra = 0b10 | (sv_extra >> 3)
+                    else:
+                        if regmode == 'scalar':
+                            # range is CR0-CR31 in increments of 1
+                            assert (sv_extra >> 2) == 0, \
+                                "scalar CR %s cannot fit into EXTRA2 %s" % \
+                                    (regname, str(extras[extra_idx]))
+                            # all good: encode as scalar
+                            sv_extra = sv_extra & 0b11
+                        else:
+                            # range is CR0-CR127 in increments of 8
+                            assert sv_extra & 0b11 == 0, \
+                                "vector CR %s cannot fit into EXTRA2 %s" % \
+                                    (regname, str(extras[extra_idx]))
+                            # all good: encode as vector (bit 3 set)
+                            sv_extra = 0b100 | (sv_extra >> 2)
+
+                    # reconstruct the actual 5-bit CR field
+                    field = (field << 2) | cr_subfield
+
+                # capture the extra field info
+                print ("=>", "%5s" % bin(sv_extra), field)
+                extras[extra_idx] = sv_extra
 
                 # append altered field value to v3.0b
                 v30b_newfields.append(str(field))
 
             print ("new v3.0B fields", v30b_op, v30b_newfields)
+            print ("extras", extras)
+
+            # rright.  now we have all the info. start creating SVP64 RM
+            svp64_rm = 0b0
+
+            # begin with EXTRA fields
+            for idx, sv_extra in extras.items():
+                if idx is None: continue
+                # start at bit 10, work up 2/3 times EXTRA idx
+                offs = 2 if etype == 'EXTRA2' else 3 # 2 or 3 bits
+                svp64_rm |= sv_extra << (10+idx*offs)
+
+            # parts of svp64_rm
+            mmode = 0  # bit 0
+            pmask = 0  # bits 1-3
+            destwid = 0 # bits 4-5
+            srcwid = 0 # bits 6-7
+            subvl = 0   # bits 8-9
+            smask = 0 # bits 16-18 but only for twin-predication
+            mode = 0 # bits 19-23
+
+            has_pmask = False
+            has_smask = False
+
+            # ok let's start identifying opcode augmentation fields
+            for encmode in opmodes:
+                # predicate mask (dest)
+                if encmode.startswith("m="):
+                    pme = encmode
+                    pmmode, pmask = decode_predicate(encmode[2:])
+                    mmode = pmmode
+                    has_pmask = True
+                # predicate mask (src, twin-pred)
+                elif encmode.startswith("sm="):
+                    sme = encmode
+                    smmode, smask = decode_predicate(encmode[3:])
+                    mmode = smmode
+                    has_smask = True
+                # vec2/3/4
+                elif encmode.startswith("vec"):
+                    subvl = decode_subvl(encmode[3:])
+                # elwidth
+                elif encmode.startswith("ew="):
+                    destwid = decode_elwidth(encmode[3:])
+                elif encmode.startswith("sw="):
+                    srcwid = decode_elwidth(encmode[3:])
+
+            # sanity-check that 2Pred mask is same mode
+            if has_pmask and has_smask:
+                assert smmode == pmmode, \
+                    "predicate masks %s and %s must be same reg type" % \
+                        (pme, sme)
+
+            # sanity-check that twin-predication mask only specified in 2P mode
+            if ptype == '1P':
+                assert has_smask == False, \
+                    "source-mask can only be specified on Twin-predicate ops"
+
+            # put in predicate masks into svp64_rm
+            if ptype == '2P':
+                svp64_rm |= (smask << 16) # source pred: bits 16-18
+            svp64_rm |= (mmode)           # mask mode: bit 0
+            svp64_rm |= (pmask << 1)      # 1-pred: bits 1-3
+
+            # and subvl
+            svp64_rm += (subvl << 8)      # subvl: bits 8-9
+
+            # put in elwidths
+            svp64_rm += (srcwid << 6)      # srcwid: bits 6-7
+            svp64_rm += (destwid << 4)     # destwid: bits 4-5
+
+            # nice debug printout. (and now for something completely different)
+            # https://youtu.be/u0WOIwlXE9g?t=146
+            print ("svp64_rm", hex(svp64_rm), bin(svp64_rm))
+            print ("    mmode  0    :", bin(mmode))
+            print ("    pmask  1-3  :", bin(pmask))
+            print ("    dstwid 4-5  :", bin(destwid))
+            print ("    srcwid 6-7  :", bin(srcwid))
+            print ("    subvl  8-9  :", bin(subvl))
+            offs = 2 if etype == 'EXTRA2' else 3 # 2 or 3 bits
+            for idx, sv_extra in extras.items():
+                if idx is None: continue
+                start = (10+idx*offs)
+                end = start + offs-1
+                print ("    extra%d %2d-%2d:" % (idx, start, end),
+                        bin(sv_extra))
+            if ptype == '2P':
+                print ("    smask  16-17:", bin(smask))
             print ()
 
         return res
@@ -180,7 +436,10 @@ if __name__ == '__main__':
                  'extsw 5, 3',
                  'sv.extsw 5, 3',
                  'sv.cmpi 5, 1, 3, 2',
-                 'sv.setb 5, 3',
-                 'sv.isel 64.v, 3, 2, 0'
+                 'sv.setb 5, 31',
+                 'sv.isel 64.v, 3, 2, 65.v',
+                 'sv.setb.m=r3.sm=1<<r3 5, 31',
+                 'sv.setb.vec2 5, 31',
+                 'sv.setb.sw=8.ew=16 5, 31',
                 ])
     csvs = SVP64RM()