big reorganisation to support twin-predication
[riscv-isa-sim.git] / riscv / insn_template_sv.cc
index 7804625808b48e8620c1b76e4267c1b966f27a75..40d2a9b398a992e3c61c0a4c139ecec557c60a82 100644 (file)
@@ -19,44 +19,25 @@ reg_t FN(processor_t* p, insn_t s_insn, reg_t pc)
   // REGS_PATTERN is generated by id_regs.py (per opcode)
   unsigned int floatintmap = REGS_PATTERN;
   reg_t dest_pred = ~0x0;
+  bool zeroing = false;
 #ifdef INSN_CATEGORY_TWINPREDICATION
   reg_t src_pred = ~0x0;
+  bool zeroingsrc = false;
 #endif
-  sv_insn_t insn(p, bits, floatintmap,
-                 dest_pred,
-#ifdef INSN_CATEGORY_TWINPREDICATION
-// twin-predication ONLY applies to dual-op operands: MV, FCVT, LD/ST.
-// however we don't know which register any of those will use, so
-// pass src_pred to each of rs1-3 and let the instruction sort it out.
-src_pred, src_pred, src_pred
-#else
-dest_pred, dest_pred, dest_pred
-#endif
-                );
-  bool zeroing;
+  sv_insn_t insn(p, bits, floatintmap, PRED_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
-#ifdef USING_REG_RS1
-  #define SRCREG s_insn.rs1()
-#endif
-#ifdef USING_REG_RS2
-  #define SRCREG s_insn.rs2()
-#endif
-#ifdef USING_REG_RS3
-  #define SRCREG s_insn.rs3()
-#endif
-#if (defined(USING_REG_RVC_RS1) || defined(USING_REG_RVC_RS1S))
-  #define SRCREG s_insn.rvc_rs1()
+    src_pred = insn.predicate(s_insn.SRC_REG(), SRC_PREDINT, zeroingsrc);
 #endif
-#if (defined(USING_REG_RVC_RS2) || defined(USING_REG_RVC_RS2S))
-  #define SRCREG s_insn.rvc_rs2()
-#endif
-  src_pred = insn.predicate(SRCREG, floatintmap & (REG_RS1|REG_RS2|REG_RS3),
-                            zeroing);
-#endif
-#if defined(USING_REG_RD) || defined(USING_REG_FRD)
+#ifdef DEST_PREDINT
   // use the ORIGINAL, i.e. NON-REDIRECTED, register here
-  dest_pred = insn.predicate(s_insn.rd(), floatintmap & REG_RD, zeroing);
+    dest_pred = insn.predicate(s_insn.DEST_REG(), DEST_PREDINT, zeroing);
 #endif
+  }
   // 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)
@@ -74,18 +55,55 @@ dest_pred, dest_pred, dest_pred
   }
   for (int voffs=0; voffs < vlen; voffs++)
   {
-      insn.reset_vloop_check();
+    insn.reset_vloop_check();
+#ifdef INSN_CATEGORY_TWINPREDICATION
+    int srcoffs = insn.rs_offs();
+    if (!zeroingsrc)
+    {
+      while ((src_pred & (1<<srcoffs)) == 0) {
+          srcoffs = insn.rs_offs_inc();
+          if (srcoffs == vlen) {
+              break;
+          }
+      }
+    }
+    int destoffs = insn.rd_offs();
+    if (!zeroing)
+    {
+      while ((dest_pred & (1<<destoffs)) == 0) {
+          destoffs = insn.rd_offs_inc();
+          if (destoffs == vlen) {
+              break;
+          }
+      }
+    }
+    if (srcoffs == vlen || destoffs == 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), srcoffs, destoffs, src_pred, dest_pred);
+    }
+#endif
+#ifdef INSN_C_MV
+    fprintf(stderr, "pre loop reg %s %x vloop %d " \
+                      "vlen %d stop %d pred %lx rd%lx rvc2%d\n",
+                xstr(INSN), INSNCODE, voffs, vlen, insn.stop_vloop(),
+                dest_pred & (1<<voffs), READ_REG(insn._rd()), insn.rvc_rs2());
+#endif
       #include INCLUDEFILE
-#if defined(USING_REG_RD) || defined(USING_REG_FRD)
+#ifdef DEST_PREDINT
       // don't check inversion here as dest_pred has already been inverted
-      if (zeroing && ((dest_pred & (1<<voffs)) == 0))
+      if (zeroing && ((dest_pred & (1<<insn.rd_offs())) == 0))
       {
           // insn._rd() would be predicated: have to use insn._rd() here
-          WRITE_REG(insn._rd(), 0);
+          WRITE_REG(insn._DEST_REG(), 0);
       }
 #endif
       if (vlen > 1)
       {
+        insn.reset_caches(); // ready to increment offsets
 #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(),
@@ -98,7 +116,6 @@ dest_pred, dest_pred, dest_pred
                 (READ_FREG(insn._rd())));
 #endif
       }
-      insn.reset_caches(); // ready to increment offsets in next iteration
       if (insn.stop_vloop())
       {
         break;