bug #672: fix sv.minmax dd-ffirst-single unit test
[openpower-isa.git] / src / openpower / decoder / isa / caller.py
index be7850287f9f2fc7153a30276388c032b938e04a..2bb4b6086eab4ed48b70180c677cd77237065243 100644 (file)
@@ -151,6 +151,11 @@ def create_full_args(*, read_regs, special_regs, uninit_regs, write_regs,
         *read_regs, *uninit_regs, *write_regs, *special_regs], extra=extra)
 
 
+def is_ffirst_mode(dec2):
+    rm_mode = yield dec2.rm_dec.mode
+    return rm_mode == SVP64RMMode.FFIRST.value
+
+
 class GPR(dict):
     def __init__(self, decoder, isacaller, svstate, regfile):
         dict.__init__(self)
@@ -217,9 +222,13 @@ class GPR(dict):
             rnum = rnum.value
         dict.__setitem__(self, rnum, value)
 
-    def getz(self, rnum):
+    def getz(self, rnum, rvalue=None):
         # rnum = rnum.value # only SelectableInt allowed
-        log("GPR getzero?", rnum)
+        log("GPR getzero?", rnum, rvalue)
+        if rvalue is not None:
+            if rnum == 0:
+                return SelectableInt(0, rvalue.bits)
+            return rvalue
         if rnum == 0:
             return SelectableInt(0, 64)
         return self[rnum]
@@ -1757,6 +1766,7 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
         cr_field = selectconcat(negative, positive, zero, SO)
         log("handle_comparison cr_field", self.cr, cr_idx, cr_field)
         self.crl[cr_idx].eq(cr_field)
+        return cr_field
 
     def set_pc(self, pc_val):
         self.namespace['NIA'] = SelectableInt(pc_val, 64)
@@ -2088,7 +2098,7 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
                        "brh", "brw", "brd",
                        'setvl', 'svindex', 'svremap', 'svstep',
                        'svshape', 'svshape2',
-                       'ternlogi', 'bmask', 'cprop',
+                       'ternlogi', 'bmask', 'cprop', 'gbbd',
                        'absdu', 'absds', 'absdacs', 'absdacu', 'avgadd',
                        'fmvis', 'fishmv', 'pcdec', "maddedu", "divmod2du",
                        "dsld", "dsrd", "maddedus",
@@ -2105,7 +2115,7 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
             ins_name = dotstrp
 
         # match against instructions treated as nop, see nop below
-        if asmop.startswith("dc"):
+        if asmop.startswith("dcbt"):
             illegal = False
             ins_name = "nop"
 
@@ -2154,7 +2164,7 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
             ew_src = 8 << (3-int(ew_src))  # convert to bitlength
             ew_dst = 8 << (3-int(ew_dst))  # convert to bitlength
             xlen = max(ew_src, ew_dst)
-            log("elwdith", ew_src, ew_dst)
+            log("elwidth", ew_src, ew_dst)
         log("XLEN:", self.is_svp64_mode, xlen)
 
         # look up instruction in ISA.instrs, prepare namespace
@@ -2235,7 +2245,16 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
             remap_active = yield self.dec2.remap_active
         else:
             remap_active = False
-        log("remap active", bin(remap_active))
+        log("remap active", bin(remap_active), self.is_svp64_mode)
+
+        # LDST does *not* allow elwidth overrides on RA (Effective Address).
+        # this has to be detected. XXX TODO: RB for ldst-idx *may* need
+        # conversion (to 64-bit) also.
+        # see write reg this *HAS* to also override XLEN to 64 on LDST/Update
+        sv_mode = yield self.dec2.rm_dec.sv_mode
+        is_ldst = (sv_mode in [SVMode.LDST_IDX.value, SVMode.LDST_IMM.value] \
+                  and self.is_svp64_mode)
+        log("is_ldst", sv_mode, is_ldst)
 
         # main input registers (RT, RA ...)
         for name in input_names:
@@ -2249,8 +2268,12 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
                 inputs[name] = self.crl[0]
             elif name in spr_byname:
                 inputs[name] = self.spr[name]
+            elif is_ldst and name == 'RA':
+                regval = (yield from self.get_input(name, ew_src, 64))
+                log("EA (RA) regval name", name, regval)
+                inputs[name] = regval
             else:
-                regval = (yield from self.get_input(name, ew_src))
+                regval = (yield from self.get_input(name, ew_src, xlen))
                 log("regval name", name, regval)
                 inputs[name] = regval
 
@@ -2418,7 +2441,7 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
         log("        vli", vli_)
         log("     cr_bit", cr_bit)
         log("      rc_en", rc_en)
-        if not rc_en or rm_mode != SVP64RMMode.FFIRST.value:
+        if not rc_en or not is_ffirst_mode(self.dec2):
             return False, False
         # get the CR vevtor, do BO-test
         crf = "CR0"
@@ -2466,10 +2489,11 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
         elif cr0 is None:
             # if there was not an explicit CR0 in the pseudocode,
             # do implicit Rc=1
-            self.handle_comparison(result, regnum, overflow, no_so=is_setvl)
+            c = self.handle_comparison(result, regnum, overflow, no_so=is_setvl)
+            log("implicit cr0", c)
         else:
             # otherwise we just blat CR0 into the required regnum
-            log("explicit rc0", cr0)
+            log("explicit cr0", cr0)
             self.crl[regnum].eq(cr0)
 
     def do_outregs(self, info, outs, ca_en, ffirst_hit, ew_dst, outs_ok):
@@ -2550,7 +2574,7 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
             else:
                 self.namespace['D'] = imm
 
-    def get_input(self, name, ew_src):
+    def get_input(self, name, ew_src, xlen):
         # using PowerDecoder2, first, find the decoder index.
         # (mapping name RA RB RC RS to in1, in2, in3)
         regnum, is_vec = yield from get_idx_in(self.dec2, name, True)
@@ -2571,20 +2595,27 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
         regname = "_" + name
         if not self.is_svp64_mode or ew_src == 64:
             self.namespace[regname] = regnum
-        elif regname in self.namespace:
-            del self.namespace[regname]
+        else:
+            # FIXME: we're trying to access a sub-register, plain register
+            # numbers don't work for that.  for now, just pass something that
+            # can be compared to 0 and probably will cause an error if misused.
+            # see https://bugs.libre-soc.org/show_bug.cgi?id=1221
+            self.namespace[regname] = regnum * 10000
 
         if not self.is_svp64_mode or not self.pred_src_zero:
             log('reading reg %s %s' % (name, str(regnum)), is_vec)
             if name in fregs:
-                reg_val = SelectableInt(self.fpr(base, is_vec, offs, ew_src))
-                log("read reg %d/%d: 0x%x" % (base, offs, reg_val.value),
-                    kind=LogType.InstrInOuts)
+                fval = self.fpr(base, is_vec, offs, ew_src)
+                reg_val = SelectableInt(fval)
+                assert ew_src == XLEN, "TODO fix elwidth conversion"
                 self.trace("r:FPR:%d:%d:%d " % (base, offs, ew_src))
+                log("read fp reg %d/%d: 0x%x" % (base, offs, reg_val.value),
+                    kind=LogType.InstrInOuts)
             elif name is not None:
-                reg_val = SelectableInt(self.gpr(base, is_vec, offs, ew_src))
+                gval = self.gpr(base, is_vec, offs, ew_src)
+                reg_val = SelectableInt(gval.value, bits=xlen)
                 self.trace("r:GPR:%d:%d:%d " % (base, offs, ew_src))
-                log("read reg %d/%d: 0x%x" % (base, offs, reg_val.value),
+                log("read int reg %d/%d: 0x%x" % (base, offs, reg_val.value),
                     kind=LogType.InstrInOuts)
         else:
             log('zero input reg %s %s' % (name, str(regnum)), is_vec)
@@ -2713,9 +2744,24 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
         if name in fregs:
             self.fpr.write(regnum, output, is_vec, ew_dst)
             self.trace("w:FPR:%d:%d:%d " % (rnum, offset, ew_dst))
-        else:
-            self.gpr.write(regnum, output, is_vec, ew_dst)
-            self.trace("w:GPR:%d:%d:%d " % (rnum, offset, ew_dst))
+            return
+
+        # LDST/Update does *not* allow elwidths on RA (Effective Address).
+        # this has to be detected, and overridden.  see get_input (related)
+        sv_mode = yield self.dec2.rm_dec.sv_mode
+        is_ldst = (sv_mode in [SVMode.LDST_IDX.value, SVMode.LDST_IMM.value] \
+                  and self.is_svp64_mode)
+        if is_ldst and name in ['EA', 'RA']:
+            op = self.dec2.dec.op
+            if hasattr(op, "upd"):
+                # update mode LD/ST uses read-reg A also as an output
+                upd = yield op.upd
+                log("write is_ldst is_update", sv_mode, is_ldst, upd)
+                if upd == LDSTMode.update.value:
+                    ew_dst = 64 # override for RA (EA) to 64-bit
+
+        self.gpr.write(regnum, output, is_vec, ew_dst)
+        self.trace("w:GPR:%d:%d:%d " % (rnum, offset, ew_dst))
 
     def check_step_increment(self, rc_en, asmop, ins_name):
         # check if it is the SVSTATE.src/dest step that needs incrementing
@@ -2874,7 +2920,11 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
         vfirst = self.svstate.vfirst
         log("    SV Vertical First", vf, vfirst)
         if not vf and vfirst == 1:
-            if insn_name.startswith("sv.bc"):
+            # SV Branch-Conditional required to be as-if-vector
+            # because there *is* no destination register
+            # (SV normally only terminates on 1st scalar reg written
+            #  except in [slightly-misnamed] mapreduce mode)
+            if insn_name.startswith("sv.bc") or ffirst:
                 self.update_pc_next()
                 return False
             self.update_nia()
@@ -2897,6 +2947,7 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
         sv_ptype = yield self.dec2.dec.op.SV_Ptype
         out_vec = not (yield self.dec2.no_out_vec)
         in_vec = not (yield self.dec2.no_in_vec)
+        rm_mode = yield self.dec2.rm_dec.mode
         log("    svstate.vl", vl)
         log("    svstate.mvl", mvl)
         log("         rm.subvl", subvl)
@@ -2911,6 +2962,7 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
         log("    out_vec", out_vec)
         log("    in_vec", in_vec)
         log("    sv_ptype", sv_ptype, sv_ptype == SVPType.P2.value)
+        log("    rm_mode", rm_mode)
         # check if this was an sv.bc* and if so did it succeed
         if self.is_svp64_mode and insn_name.startswith("sv.bc"):
             end_loop = self.namespace['end_loop']
@@ -2926,6 +2978,13 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
             svp64_is_vector = (out_vec or in_vec)
         else:
             svp64_is_vector = out_vec
+        # also if data-dependent fail-first is used, only in_vec is tested,
+        # allowing *scalar destinations* to be used as an accumulator.
+        # effectively this implies /mr (mapreduce mode) is 100% on with ddffirst
+        # see https://bugs.libre-soc.org/show_bug.cgi?id=1183#c16
+        if is_ffirst_mode(self.dec2):
+            svp64_is_vector = in_vec
+
         # loops end at the first "hit" (source or dest)
         yield from self.advance_svstate_steps()
         loopend = self.loopend