reorganise twin-predication
[riscv-isa-sim.git] / riscv / insn_template_sv.cc
index 3ff09e8061842ca190d7af2aa6f3034db3fb1d53..cab74d7c8f9ea254589f58183eec7050bb6b45e1 100644 (file)
@@ -8,65 +8,133 @@ reg_t FN(processor_t* p, insn_t s_insn, reg_t pc)
   int xlen = ISASZ;
   reg_t npc = sext_xlen(pc + insn_length(INSNCODE));
   // messy way to do it: insn_t is used elsewhere in a union,
-  // so a workaround is to grab the bits from the insn_t
+  // so cannot create virtual functions.
+  // a workaround is to grab the bits from the insn_t
   // and create an sv-variant.  also an opportunity to pass
-  // in the loop index (voffs) which will be added on to
-  // any registers that are marked as "vectorised"
+  // in a stack of other things that are needed.
   insn_bits_t bits = s_insn.bits();
 #ifndef USING_NOREGS
-  int vlen = 1;
+  int vlen = p->get_state()->vl;
   // need to know if register is used as float or int.
   // REGS_PATTERN is generated by id_regs.py (per opcode)
   unsigned int floatintmap = REGS_PATTERN;
-  sv_insn_t insn(p, bits, floatintmap);
-  reg_t predicate = 0;
-  // identify which regs have had their CSR entries set as vectorised.
-  // really could do with a macro for-loop here... oh well...
-  // integer ops, RD, RS1, RS2, RS3 (use sv_int_tb)
-  bool vectorop =
-#ifdef USING_REG_RD
-  insn.sv_check_reg(true, s_insn.rd()) |
-#endif
-#ifdef USING_REG_RS1
-  insn.sv_check_reg(true, s_insn.rs1()) |
-#endif
-#ifdef USING_REG_RS2
-  insn.sv_check_reg(true, s_insn.rs2()) |
-#endif
-#ifdef USING_REG_RS2
- insn.sv_check_reg(true, s_insn.rs3()) |
+  reg_t dest_pred = ~0x0;
+  int dest_offs = 0;
+  bool zeroing = false;
+#ifdef INSN_CATEGORY_TWINPREDICATION
+  reg_t src_pred = ~0x0;
+  int src_offs = 0;
+  bool zeroingsrc = false;
 #endif
-  // fp ops, RD, RS1, RS2, RS3 (use sv_fp_tb)
-#ifdef USING_REG_FRD
-  insn.sv_check_reg(false, s_insn.rd()) |
-#endif
-#ifdef USING_REG_FRS1
-  insn.sv_check_reg(false, s_insn.rs1()) |
-#endif
-#ifdef USING_REG_FRS2
-  insn.sv_check_reg(false, s_insn.rs2()) |
+  sv_insn_t insn(p, bits, floatintmap, PRED_ARGS, OFFS_ARGS);
+  if (vlen > 0)
+  {
+    fprintf(stderr, "pre-ex reg %s %x rd %ld rs1 %ld rs2 %ld vlen %d\n",
+            xstr(INSN), INSNCODE, s_insn.rd(), s_insn.rs1(), s_insn.rs2(),
+            vlen);
+#ifdef INSN_CATEGORY_TWINPREDICATION
+    src_pred = insn.predicate(s_insn.SRC_REG(), SRC_PREDINT, zeroingsrc);
 #endif
-#ifdef USING_REG_FRS2
-  insn.sv_check_reg(false, s_insn.rs3()) |
+#ifdef DEST_PREDINT
+  // use the ORIGINAL, i.e. NON-REDIRECTED, register here
+    dest_pred = insn.predicate(s_insn.DEST_REG(), DEST_PREDINT, zeroing);
 #endif
-  false; // save a few cycles by |ing the checks together.
-
+  }
+  // identify which regs have had their CSR entries set as vectorised.
+  // really could do with a macro for-loop here... oh well...
+  // integer ops, RD, RS1, RS2, RS3 (use sv_int_tb)
   if (insn.sv_check_reg(true, 16))
   {
-    fprintf(stderr, "reg %s %x rd %ld rs1 %ld rs2 %ld\n",
-            xstr(INSN), INSNCODE, s_insn.rd(), s_insn.rs1(), s_insn.rs2());
+    fprintf(stderr, "reg %s %x rd %ld rs1 %ld rs2 %ld vlen %d\n",
+            xstr(INSN), INSNCODE, s_insn.rd(), s_insn.rs1(), s_insn.rs2(),
+            vlen);
   }
   // if vectorop is set, one of the regs is not a scalar,
   // so we must read the VL CSR and do a loop
-  if (vectorop)
+  if (vlen == 0)
   {
-    vlen = p->get_state()->vl;
-    fprintf(stderr, "vectorop %x vlen %d\n", INSNCODE, vlen);
+    vlen = 1; // minimum of one loop
   }
   for (int voffs=0; voffs < vlen; voffs++)
   {
+    insn.reset_vloop_check();
+#ifdef INSN_CATEGORY_TWINPREDICATION
+    if (src_offs >= vlen) {
+        break;
+    }
+    if (dest_offs >= vlen) {
+        break;
+    }
+#ifdef INSN_C_MV
+        fprintf(stderr, "pre twin reg %s src %d dest %d pred %lx %lx\n",
+            xstr(INSN), src_offs, dest_offs, src_pred, dest_pred);
+#endif
+    if (!zeroingsrc)
+    {
+      while ((src_pred & (1<<src_offs)) == 0) {
+          src_offs += 1;
+          if (src_offs >= vlen) {
+              break;
+          }
+      }
+    }
+    if (!zeroing)
+    {
+      while ((dest_pred & (1<<dest_offs)) == 0) {
+          dest_offs += 1;
+          if (dest_offs >= vlen) {
+              break;
+          }
+      }
+    }
+    if (src_offs >= vlen || dest_offs >= vlen) {
+        break; // end vector loop if either src or dest pred reaches end
+    }
+    if (vlen > 1)
+    {
+        fprintf(stderr, "twin reg %s src %d dest %d pred %lx %lx\n",
+            xstr(INSN), src_offs, dest_offs, src_pred, dest_pred);
+    }
+#endif
+#ifdef INSN_C_MV
+    fprintf(stderr, "pre loop reg %s %x vloop %d %d %d" \
+                      "vlen %d stop %d pred %lx rdv %lx rd %d rvc2 %d\n",
+                xstr(INSN), INSNCODE, voffs, src_offs, dest_offs,
+                vlen, insn.stop_vloop(),
+                dest_pred & (1<<voffs), READ_REG(insn._rd()),
+                insn._rd(), insn._rvc_rs2());
+#endif
       #include INCLUDEFILE
-      insn.reset_caches(); // ready to increment offsets in next iteration
+#ifdef DEST_PREDINT
+      // don't check inversion here as dest_pred has already been inverted
+      if (zeroing && ((dest_pred & (1<<dest_offs)) == 0))
+      {
+          // insn._rd() would be predicated: have to use insn._rd() here
+          WRITE_REG(insn._DEST_REG(), 0);
+      }
+#endif
+      if (vlen > 1)
+      {
+#if defined(USING_REG_RD)
+        fprintf(stderr, "reg %s %x vloop %d vlen %d stop %d pred %lx rd%lx\n",
+                xstr(INSN), INSNCODE, voffs, vlen, insn.stop_vloop(),
+                dest_pred & (1<<voffs), READ_REG(insn._rd()));
+#endif
+#if defined(USING_REG_FRD)
+        fprintf(stderr, "reg %s %x vloop %d vlen %d stop %d pred %lx rd%lx\n",
+                xstr(INSN), INSNCODE, voffs, vlen, insn.stop_vloop(),
+                dest_pred & (1<<voffs),
+                (READ_FREG(insn._rd())));
+#endif
+      }
+      if (insn.stop_vloop())
+      {
+        break;
+      }
+#ifdef INSN_CATEGORY_TWINPREDICATION
+      src_offs += 1;
+#endif
+      dest_offs += 1;
   }
 #else
   insn_t insn(bits);