add data-dependent fail-first mode, Rc=1 variant not RC1 yet
[openpower-isa.git] / src / openpower / decoder / isa / caller.py
index a1dc8197ea291eb1809b9867f65fce2da1a4fda4..8a8a3f6ef0e3c693b68b5d9f7cbb9c22a50e9ec5 100644 (file)
@@ -95,6 +95,7 @@ REG_SORT_ORDER = {
     "CA32": 0,
 
     "overflow": 7,  # should definitely be last
+    "CR0": 8,       # likewise
 }
 
 fregs = ['FRA', 'FRB', 'FRC', 'FRS', 'FRT']
@@ -514,10 +515,14 @@ def get_pdecode_idx_out2(dec2, name):
                 out, o_isvec)
             if upd == LDSTMode.update.value:
                 return out, o_isvec
+    if name == 'RS':
+        fft_en = yield dec2.implicit_rs
+        if fft_en:
+            log("get_pdecode_idx_out2", out_sel, OutSel.RS.value,
+                out, o_isvec)
+            return out, o_isvec
     if name == 'FRS':
-        int_op = yield dec2.dec.op.internal_op
-        fft_en = yield dec2.use_svp64_fft
-        # if int_op == MicrOp.OP_FP_MADD.value and fft_en:
+        fft_en = yield dec2.implicit_rs
         if fft_en:
             log("get_pdecode_idx_out2", out_sel, OutSel.FRS.value,
                 out, o_isvec)
@@ -1518,7 +1523,10 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
             return
 
         # look up instruction in ISA.instrs, prepare namespace
-        info = self.instrs[ins_name]
+        if ins_name == 'pcdec': # grrrr yes there are others ("stbcx." etc.)
+            info = self.instrs[ins_name+"."]
+        else:
+            info = self.instrs[ins_name]
         yield from self.prep_namespace(ins_name, info.form, info.op_fields)
 
         # preserve order of register names
@@ -1655,7 +1663,7 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
                 if name == 'CA32':
                     already_done |= 2
 
-        log("carry already done?", bin(already_done))
+        log("carry already done?", bin(already_done), output_names)
         carry_en = yield self.dec2.e.do.output_carry
         if carry_en:
             yield from self.handle_carry_(inputs, results, already_done)
@@ -1667,6 +1675,13 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
                 if name == 'overflow':
                     overflow = output
 
+        # and one called CR0
+        cr0 = None
+        if info.write_regs:
+            for name, output in zip(output_names, results):
+                if name == 'CR0':
+                    cr0 = output
+
         if not self.is_svp64_mode:  # yeah just no. not in parallel processing
             # detect if overflow was in return result
             ov_en = yield self.dec2.e.do.oe.oe
@@ -1680,15 +1695,37 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
         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
+        # don't do Rc=1 for svstep it is handled explicitly.
+        # XXX TODO: now that CR0 is supported, sort out svstep's pseudocode
+        # to write directly to CR0 instead of in ISACaller. hooyahh.
         if rc_en and ins_name not in ['svstep']:
-            yield from self.do_rc_ov(ins_name, results, overflow)
+            yield from self.do_rc_ov(ins_name, results, overflow, cr0)
+
+        # check failfirst
+        rm_mode = yield self.dec2.rm_dec.mode
+        ff_inv = yield self.dec2.rm_dec.inv
+        cr_bit = yield self.dec2.rm_dec.cr_sel
+        log(" ff rm_mode", rc_en, rm_mode, SVP64RMMode.FFIRST.value)
+        log("        inv", ff_inv)
+        log("     cr_bit", cr_bit)
+        ffirst_hit = False
+        if rc_en and rm_mode == SVP64RMMode.FFIRST.value:
+            regnum, is_vec = yield from get_pdecode_cr_out(self.dec2, "CR0")
+            crtest = self.crl[regnum]
+            ffirst_hit = crtest[cr_bit] != ff_inv
+            log("cr test", regnum, int(crtest), crtest, cr_bit, ff_inv)
+            log("cr test?", ffirst_hit)
+            if ffirst_hit:
+                self.svstate.vl = srcstep
+                yield self.dec2.state.svstate.eq(self.svstate.value)
+                yield Settle()  # let decoder update
 
         # any modified return results?
         yield from self.do_outregs_nia(asmop, ins_name, info,
                                        output_names, results,
-                                       carry_en, rc_en)
+                                       carry_en, rc_en, ffirst_hit)
 
-    def do_rc_ov(self, ins_name, results, overflow):
+    def do_rc_ov(self, ins_name, results, overflow, cr0):
         if ins_name.startswith("f"):
             rc_reg = "CR1"  # not calculated correctly yet (not FP compares)
         else:
@@ -1702,17 +1739,28 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
             cmps = (SelectableInt(vl, 64), overflow,)
         else:
             overflow = None  # do not override overflow except in setvl
-        self.handle_comparison(cmps, regnum, overflow, no_so=is_setvl)
+
+        # if there was not an explicit CR0 in the pseudocode, do implicit Rc=1
+        if cr0 is None:
+            self.handle_comparison(cmps, regnum, overflow, no_so=is_setvl)
+        else:
+            # otherwise we just blat CR0 into the required regnum
+            log("explicit rc0", cr0)
+            self.crl[regnum].eq(cr0)
 
     def do_outregs_nia(self, asmop, ins_name, info, output_names, results,
-                       carry_en, rc_en):
+                       carry_en, rc_en, ffirst_hit):
         # write out any regs for this instruction
         if info.write_regs:
             for name, output in zip(output_names, results):
                 yield from self.check_write(info, name, output, carry_en)
 
-        # check advancement of src/dst/sub-steps and if PC needs updating
-        nia_update = (yield from self.check_step_increment(results, rc_en,
+        if ffirst_hit:
+            self.svp64_reset_loop()
+            nia_update = True
+        else:
+            # check advancement of src/dst/sub-steps and if PC needs updating
+            nia_update = (yield from self.check_step_increment(results, rc_en,
                                                            asmop, ins_name))
         if nia_update:
             self.update_pc_next()
@@ -1845,6 +1893,8 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
     def check_write(self, info, name, output, carry_en):
         if name == 'overflow':  # ignore, done already (above)
             return
+        if name == 'CR0':  # ignore, done already (above)
+            return
         if isinstance(output, int):
             output = SelectableInt(output, 256)
         # write carry flafs
@@ -2018,6 +2068,9 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
         unpack = self.svstate.unpack
         vl = self.svstate.vl
         subvl = yield self.dec2.rm_dec.rm_in.subvl
+        rm_mode = yield self.dec2.rm_dec.mode
+        ff_inv = yield self.dec2.rm_dec.inv
+        cr_bit = yield self.dec2.rm_dec.cr_sel
         log("    srcstep", srcstep)
         log("    dststep", dststep)
         log("        pack", pack)
@@ -2026,6 +2079,9 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
         log("    dsubstep", dsubstep)
         log("         vl", vl)
         log("      subvl", subvl)
+        log("    rm_mode", rm_mode)
+        log("        inv", ff_inv)
+        log("     cr_bit", cr_bit)
 
         # check if end reached (we let srcstep overrun, above)
         # nothing needs doing (TODO zeroing): just do next instruction