fix AttributeError in radixmmu testcase
[soc.git] / src / soc / decoder / isa / caller.py
index 2bc5b640d1b512025e59cb576ab01395f49ee6e1..ba24f48fa54d0a9130ab30b6ce68594fc9469a8d 100644 (file)
@@ -21,12 +21,15 @@ from soc.decoder.selectable_int import (FieldSelectableInt, SelectableInt,
                                         selectconcat)
 from soc.decoder.power_enums import (spr_dict, spr_byname, XER_bits,
                                      insns, MicrOp, In1Sel, In2Sel, In3Sel,
-                                     OutSel, CROutSel)
+                                     OutSel, CROutSel,
+                                     SVP64RMMode, SVP64PredMode,
+                                     SVP64PredInt, SVP64PredCR)
 
 from soc.decoder.power_enums import SVPtype
 
 from soc.decoder.helpers import exts, gtu, ltu, undefined
 from soc.consts import PIb, MSRb  # big-endian (PowerISA versions)
+from soc.consts import SVP64CROffs
 from soc.decoder.power_svp64 import SVP64RM, decode_extra
 
 from soc.decoder.isa.radixmmu import RADIX
@@ -121,6 +124,65 @@ class GPR(dict):
             print("reg", "%2d" % i, s)
 
 
+class SPR(dict):
+    def __init__(self, dec2, initial_sprs={}):
+        self.sd = dec2
+        dict.__init__(self)
+        for key, v in initial_sprs.items():
+            if isinstance(key, SelectableInt):
+                key = key.value
+            key = special_sprs.get(key, key)
+            if isinstance(key, int):
+                info = spr_dict[key]
+            else:
+                info = spr_byname[key]
+            if not isinstance(v, SelectableInt):
+                v = SelectableInt(v, info.length)
+            self[key] = v
+
+    def __getitem__(self, key):
+        print("get spr", key)
+        print("dict", self.items())
+        # if key in special_sprs get the special spr, otherwise return key
+        if isinstance(key, SelectableInt):
+            key = key.value
+        if isinstance(key, int):
+            key = spr_dict[key].SPR
+        key = special_sprs.get(key, key)
+        if key == 'HSRR0':  # HACK!
+            key = 'SRR0'
+        if key == 'HSRR1':  # HACK!
+            key = 'SRR1'
+        if key in self:
+            res = dict.__getitem__(self, key)
+        else:
+            if isinstance(key, int):
+                info = spr_dict[key]
+            else:
+                info = spr_byname[key]
+            dict.__setitem__(self, key, SelectableInt(0, info.length))
+            res = dict.__getitem__(self, key)
+        print("spr returning", key, res)
+        return res
+
+    def __setitem__(self, key, value):
+        if isinstance(key, SelectableInt):
+            key = key.value
+        if isinstance(key, int):
+            key = spr_dict[key].SPR
+            print("spr key", key)
+        key = special_sprs.get(key, key)
+        if key == 'HSRR0':  # HACK!
+            self.__setitem__('SRR0', value)
+        if key == 'HSRR1':  # HACK!
+            self.__setitem__('SRR1', value)
+        print("setting spr", key, value)
+        dict.__setitem__(self, key, value)
+
+    def __call__(self, ridx):
+        return self[ridx]
+
+
 class PC:
     def __init__(self, pc_init=0):
         self.CIA = SelectableInt(pc_init, 64)
@@ -204,64 +266,58 @@ SV64P_MAJOR_SIZE = len(SVP64PrefixFields().major.br)
 SV64P_PID_SIZE = len(SVP64PrefixFields().pid.br)
 SV64P_RM_SIZE = len(SVP64PrefixFields().rm.br)
 
+# decode SVP64 predicate integer to reg number and invert
+def get_predint(gpr, mask):
+    r10 = gpr(10)
+    r30 = gpr(30)
+    print ("get_predint", mask, SVP64PredInt.ALWAYS.value)
+    if mask == SVP64PredInt.ALWAYS.value:
+        return 0xffff_ffff_ffff_ffff
+    if mask == SVP64PredInt.R3_UNARY.value:
+        return 1 << (gpr(3).value & 0b111111)
+    if mask == SVP64PredInt.R3.value:
+        return gpr(3).value
+    if mask == SVP64PredInt.R3_N.value:
+        return ~gpr(3).value
+    if mask == SVP64PredInt.R10.value:
+        return gpr(10).value
+    if mask == SVP64PredInt.R10_N.value:
+        return ~gpr(10).value
+    if mask == SVP64PredInt.R30.value:
+        return gpr(30).value
+    if mask == SVP64PredInt.R30_N.value:
+        return ~gpr(30).value
+
+# decode SVP64 predicate CR to reg number and invert status
+def _get_predcr(mask):
+    if mask == SVP64PredCR.LT.value:
+        return 0, 1
+    if mask == SVP64PredCR.GE.value:
+        return 0, 0
+    if mask == SVP64PredCR.GT.value:
+        return 1, 1
+    if mask == SVP64PredCR.LE.value:
+        return 1, 0
+    if mask == SVP64PredCR.EQ.value:
+        return 2, 1
+    if mask == SVP64PredCR.NE.value:
+        return 2, 0
+    if mask == SVP64PredCR.SO.value:
+        return 3, 1
+    if mask == SVP64PredCR.NS.value:
+        return 3, 0
+
+# read individual CR fields (0..VL-1), extract the required bit
+# and construct the mask
+def get_predcr(crl, mask, vl):
+    idx, noninv = _get_predcr(mask)
+    mask = 0
+    for i in range(vl):
+        cr = crl[i+SVP64CROffs.CRPred]
+        if cr[idx].value == noninv:
+            mask |= (1<<i)
+    return mask
 
-class SPR(dict):
-    def __init__(self, dec2, initial_sprs={}):
-        self.sd = dec2
-        dict.__init__(self)
-        for key, v in initial_sprs.items():
-            if isinstance(key, SelectableInt):
-                key = key.value
-            key = special_sprs.get(key, key)
-            if isinstance(key, int):
-                info = spr_dict[key]
-            else:
-                info = spr_byname[key]
-            if not isinstance(v, SelectableInt):
-                v = SelectableInt(v, info.length)
-            self[key] = v
-
-    def __getitem__(self, key):
-        print("get spr", key)
-        print("dict", self.items())
-        # if key in special_sprs get the special spr, otherwise return key
-        if isinstance(key, SelectableInt):
-            key = key.value
-        if isinstance(key, int):
-            key = spr_dict[key].SPR
-        key = special_sprs.get(key, key)
-        if key == 'HSRR0':  # HACK!
-            key = 'SRR0'
-        if key == 'HSRR1':  # HACK!
-            key = 'SRR1'
-        if key in self:
-            res = dict.__getitem__(self, key)
-        else:
-            if isinstance(key, int):
-                info = spr_dict[key]
-            else:
-                info = spr_byname[key]
-            dict.__setitem__(self, key, SelectableInt(0, info.length))
-            res = dict.__getitem__(self, key)
-        print("spr returning", key, res)
-        return res
-
-    def __setitem__(self, key, value):
-        if isinstance(key, SelectableInt):
-            key = key.value
-        if isinstance(key, int):
-            key = spr_dict[key].SPR
-            print("spr key", key)
-        key = special_sprs.get(key, key)
-        if key == 'HSRR0':  # HACK!
-            self.__setitem__('SRR0', value)
-        if key == 'HSRR1':  # HACK!
-            self.__setitem__('SRR1', value)
-        print("setting spr", key, value)
-        dict.__setitem__(self, key, value)
-
-    def __call__(self, ridx):
-        return self[ridx]
 
 def get_pdecode_idx_in(dec2, name):
     op = dec2.dec.op
@@ -341,7 +397,7 @@ def get_pdecode_idx_out(dec2, name):
         if out_sel == OutSel.RA.value:
             return out, o_isvec
     elif name == 'RT':
-        print ("get_pdecode_idx_out", out_sel, OutSel.RT.value, 
+        print ("get_pdecode_idx_out", out_sel, OutSel.RT.value,
                                       OutSel.RT_OR_ZERO.value, out, o_isvec)
         if out_sel == OutSel.RT.value:
             return out, o_isvec
@@ -413,11 +469,11 @@ class ISACaller:
         self.mem = Mem(row_bytes=8, initial_mem=initial_mem)
         self.imem = Mem(row_bytes=4, initial_mem=initial_insns)
         # MMU mode, redirect underlying Mem through RADIX
+        self.msr = SelectableInt(initial_msr, 64)  # underlying reg
         if mmu:
             self.mem = RADIX(self.mem, self)
             self.imem = RADIX(self.imem, self)
         self.pc = PC()
-        self.msr = SelectableInt(initial_msr, 64)  # underlying reg
 
         # TODO, needed here:
         # FPR (same as GPR except for FP nums)
@@ -859,10 +915,74 @@ class ISACaller:
         if self.is_svp64_mode:
             vl = self.svstate.vl.asint(msb0=True)
             srcstep = self.svstate.srcstep.asint(msb0=True)
+            dststep = self.svstate.dststep.asint(msb0=True)
             sv_a_nz = yield self.dec2.sv_a_nz
             in1 = yield self.dec2.e.read_reg1.data
-            print ("SVP64: VL, srcstep, sv_a_nz, in1",
-                    vl, srcstep, sv_a_nz, in1)
+            print ("SVP64: VL, srcstep, dststep, sv_a_nz, in1",
+                    vl, srcstep, dststep, sv_a_nz, in1)
+
+        # get predicate mask
+        srcmask = dstmask = 0xffff_ffff_ffff_ffff
+        if self.is_svp64_mode:
+            pmode = yield self.dec2.rm_dec.predmode
+            sv_ptype = yield self.dec2.dec.op.SV_Ptype
+            srcpred = yield self.dec2.rm_dec.srcpred
+            dstpred = yield self.dec2.rm_dec.dstpred
+            pred_src_zero = yield self.dec2.rm_dec.pred_sz
+            pred_dst_zero = yield self.dec2.rm_dec.pred_dz
+            if pmode == SVP64PredMode.INT.value:
+                srcmask = dstmask = get_predint(self.gpr, dstpred)
+                if sv_ptype == SVPtype.P2.value:
+                    srcmask = get_predint(self.gpr, srcpred)
+            elif pmode == SVP64PredMode.CR.value:
+                srcmask = dstmask = get_predcr(self.crl, dstpred, vl)
+                if sv_ptype == SVPtype.P2.value:
+                    srcmask = get_predcr(self.crl, srcpred, vl)
+            print ("    pmode", pmode)
+            print ("    ptype", sv_ptype)
+            print ("    srcpred", bin(srcpred))
+            print ("    dstpred", bin(dstpred))
+            print ("    srcmask", bin(srcmask))
+            print ("    dstmask", bin(dstmask))
+            print ("    pred_sz", bin(pred_src_zero))
+            print ("    pred_dz", bin(pred_dst_zero))
+
+            # okaaay, so here we simply advance srcstep (TODO dststep)
+            # until the predicate mask has a "1" bit... or we run out of VL
+            # let srcstep==VL be the indicator to move to next instruction
+            if not pred_src_zero:
+                while (((1<<srcstep) & srcmask) == 0) and (srcstep != vl):
+                    print ("      skip", bin(1<<srcstep))
+                    srcstep += 1
+            # same for dststep
+            if not pred_dst_zero:
+                while (((1<<dststep) & dstmask) == 0) and (dststep != vl):
+                    print ("      skip", bin(1<<dststep))
+                    dststep += 1
+
+            # now work out if the relevant mask bits require zeroing
+            if pred_dst_zero:
+                pred_dst_zero = ((1<<dststep) & dstmask) == 0
+            if pred_src_zero:
+                pred_src_zero = ((1<<srcstep) & srcmask) == 0
+
+            # update SVSTATE with new srcstep
+            self.svstate.srcstep[0:7] = srcstep
+            self.svstate.dststep[0:7] = dststep
+            self.namespace['SVSTATE'] = self.svstate.spr
+            yield self.dec2.state.svstate.eq(self.svstate.spr.value)
+            yield Settle() # let decoder update
+            srcstep = self.svstate.srcstep.asint(msb0=True)
+            dststep = self.svstate.dststep.asint(msb0=True)
+            print ("    srcstep", srcstep)
+            print ("    dststep", dststep)
+
+            # check if end reached (we let srcstep overrun, above)
+            # nothing needs doing (TODO zeroing): just do next instruction
+            if srcstep == vl or dststep == vl:
+                self.svp64_reset_loop()
+                self.update_pc_next()
+                return
 
         # VL=0 in SVP64 mode means "do nothing: skip instruction"
         if self.is_svp64_mode and vl == 0:
@@ -885,8 +1005,12 @@ class ISACaller:
             # in case getting the register number is needed, _RA, _RB
             regname = "_" + name
             self.namespace[regname] = regnum
-            print('reading reg %s %s' % (name, str(regnum)), is_vec)
-            reg_val = self.gpr(regnum)
+            if not self.is_svp64_mode or not pred_src_zero:
+                print('reading reg %s %s' % (name, str(regnum)), is_vec)
+                reg_val = self.gpr(regnum)
+            else:
+                print('zero input reg %s %s' % (name, str(regnum)), is_vec)
+                reg_val = 0
             inputs.append(reg_val)
 
         # "special" registers
@@ -899,6 +1023,7 @@ class ISACaller:
         # clear trap (trap) NIA
         self.trap_nia = None
 
+        # execute actual instruction here
         print("inputs", inputs)
         results = info.func(self, *inputs)
         print("results", results)
@@ -928,27 +1053,29 @@ class ISACaller:
         if carry_en:
             yield from self.handle_carry_(inputs, results, already_done)
 
-        # detect if overflow was in return result
-        overflow = None
-        if info.write_regs:
-            for name, output in zip(output_names, results):
-                if name == 'overflow':
-                    overflow = output
-
-        if hasattr(self.dec2.e.do, "oe"):
-            ov_en = yield self.dec2.e.do.oe.oe
-            ov_ok = yield self.dec2.e.do.oe.ok
-        else:
-            ov_en = False
-            ov_ok = False
-        print("internal overflow", overflow, ov_en, ov_ok)
-        if ov_en & ov_ok:
-            yield from self.handle_overflow(inputs, results, overflow)
-
-        if hasattr(self.dec2.e.do, "rc"):
-            rc_en = yield self.dec2.e.do.rc.rc
-        else:
-            rc_en = False
+        if not self.is_svp64_mode: # yeah just no. not in parallel processing
+            # detect if overflow was in return result
+            overflow = None
+            if info.write_regs:
+                for name, output in zip(output_names, results):
+                    if name == 'overflow':
+                        overflow = output
+
+            if hasattr(self.dec2.e.do, "oe"):
+                ov_en = yield self.dec2.e.do.oe.oe
+                ov_ok = yield self.dec2.e.do.oe.ok
+            else:
+                ov_en = False
+                ov_ok = False
+            print("internal overflow", overflow, ov_en, ov_ok)
+            if ov_en & ov_ok:
+                yield from self.handle_overflow(inputs, results, overflow)
+
+        # only do SVP64 dest predicated Rc=1 if dest-pred is not enabled
+        rc_en = False
+        if not self.is_svp64_mode or not pred_dst_zero:
+            if hasattr(self.dec2.e.do, "rc"):
+                rc_en = yield self.dec2.e.do.rc.rc
         if rc_en:
             regnum, is_vec = yield from get_pdecode_cr_out(self.dec2, "CR0")
             self.handle_comparison(results, regnum)
@@ -981,7 +1108,13 @@ class ISACaller:
                         # temporary hack for not having 2nd output
                         regnum = yield getattr(self.decoder, name)
                         is_vec = False
-                    print('writing reg %d %s' % (regnum, str(output)), is_vec)
+                    if self.is_svp64_mode and pred_dst_zero:
+                        print('zeroing reg %d %s' % (regnum, str(output)),
+                                                     is_vec)
+                        output = SelectableInt(0, 256)
+                    else:
+                        print('writing reg %d %s' % (regnum, str(output)),
+                                                     is_vec)
                     if output.bits > 64:
                         output = SelectableInt(output.value, 64)
                     self.gpr[regnum] = output
@@ -993,12 +1126,14 @@ class ISACaller:
             vl = self.svstate.vl.asint(msb0=True)
             mvl = self.svstate.maxvl.asint(msb0=True)
             srcstep = self.svstate.srcstep.asint(msb0=True)
+            dststep = self.svstate.dststep.asint(msb0=True)
             sv_ptype = yield self.dec2.dec.op.SV_Ptype
             no_out_vec = not (yield self.dec2.no_out_vec)
             no_in_vec = not (yield self.dec2.no_in_vec)
             print ("    svstate.vl", vl)
             print ("    svstate.mvl", mvl)
             print ("    svstate.srcstep", srcstep)
+            print ("    svstate.dststep", dststep)
             print ("    no_out_vec", no_out_vec)
             print ("    no_in_vec", no_in_vec)
             print ("    sv_ptype", sv_ptype, sv_ptype == SVPtype.P2.value)
@@ -1010,21 +1145,21 @@ class ISACaller:
                 svp64_is_vector = (no_out_vec or no_in_vec)
             else:
                 svp64_is_vector = no_out_vec
-            if svp64_is_vector and srcstep != vl-1:
+            if svp64_is_vector and srcstep != vl-1 and dststep != vl-1:
                 self.svstate.srcstep += SelectableInt(1, 7)
+                self.svstate.dststep += SelectableInt(1, 7)
                 self.pc.NIA.value = self.pc.CIA.value
                 self.namespace['NIA'] = self.pc.NIA
                 self.namespace['SVSTATE'] = self.svstate.spr
                 print("end of sub-pc call", self.namespace['CIA'],
                                      self.namespace['NIA'])
                 return # DO NOT allow PC to update whilst Sub-PC loop running
-            # reset to zero
-            self.svstate.srcstep[0:7] = 0
-            print ("    svstate.srcstep loop end (PC to update)")
-            self.pc.update_nia(self.is_svp64_mode)
-            self.namespace['NIA'] = self.pc.NIA
-            self.namespace['SVSTATE'] = self.svstate.spr
+            # reset loop to zero
+            self.svp64_reset_loop()
 
+        self.update_pc_next()
+
+    def update_pc_next(self):
         # UPDATE program counter
         self.pc.update(self.namespace, self.is_svp64_mode)
         self.svstate.spr = self.namespace['SVSTATE']
@@ -1032,6 +1167,13 @@ class ISACaller:
                              self.namespace['NIA'],
                              self.namespace['SVSTATE'])
 
+    def svp64_reset_loop(self):
+        self.svstate.srcstep[0:7] = 0
+        self.svstate.dststep[0:7] = 0
+        print ("    svstate.srcstep loop end (PC to update)")
+        self.pc.update_nia(self.is_svp64_mode)
+        self.namespace['NIA'] = self.pc.NIA
+        self.namespace['SVSTATE'] = self.svstate.spr
 
 def inject():
     """Decorator factory.