reorganise twin-predication
[riscv-isa-sim.git] / riscv / sv.cc
index 824541c7a37953901f3998eba166e1c63113b727..9cc46507e524b5dfafd3d917762841426bd8dd0e 100644 (file)
@@ -1,8 +1,169 @@
 #include "sv.h"
+#include "sv_decode.h"
+
+sv_pred_entry* sv_insn_t::get_predentry(uint64_t reg, bool intreg)
+{
+  // okaay so first determine which map to use.  intreg is passed
+  // in (ultimately) from id_regs.py's examination of the use of
+  // FRS1/RS1, WRITE_FRD/WRITE_RD, which in turn gets passed
+  // in from sv_insn_t::fimap...
+  sv_pred_entry *r;
+  if (intreg)
+  {
+    return &p->get_state()->sv_pred_int_tb[reg];
+  }
+  else
+  {
+    return &p->get_state()->sv_pred_fp_tb[reg];
+  }
+}
+
+sv_reg_entry* sv_insn_t::get_regentry(uint64_t reg, bool intreg)
+{
+  // okaay so first determine which map to use.  intreg is passed
+  // in (ultimately) from id_regs.py's examination of the use of
+  // FRS1/RS1, WRITE_FRD/WRITE_RD, which in turn gets passed
+  // in from sv_insn_t::fimap...
+  sv_reg_entry *r;
+  if (intreg)
+  {
+    return &p->get_state()->sv_int_tb[reg];
+  }
+  else
+  {
+    return &p->get_state()->sv_fp_tb[reg];
+  }
+}
+
+bool sv_insn_t::sv_check_reg(bool intreg, uint64_t reg)
+{
+  sv_reg_entry *r = get_regentry(reg, intreg);
+  if (r->elwidth != 0)
+  {
+    // XXX raise exception
+  }
+  if (r->active && r->isvec)
+  {
+    fprintf(stderr, "checkreg: %ld active\n", reg);
+    return true;
+  }
+  return false;
+}
+
+/* this is the "remap" function.  note that registers can STILL BE REDIRECTED
+ * yet NOT BE MARKED AS A VECTOR.
+ *
+ * reg 5 -> active=false, regidx=XX, isvec=XX     -> returns 5
+ * reg 5 -> active=true , regidx=35, isvec=false  -> returns 35
+ * reg 5 -> active=true , regidx=35, isvec=true   -> returns 35 *PLUS LOOP*
+ *
+ * so it is possible for example to use the remap system for C  instructions
+ * to get access to the *full* range of registers x0..x63 (yes 63 because
+ * SV doubles both the int and fp regfile sizes), by setting
+ * "active=true, isvec=false" for any of x8..x15
+ *
+ * where "active=true, isvec=true" this is the "expected" behaviour
+ * of SV.  it's "supposed" to "just" be a vectorisation API. it isn't:
+ * it's quite a bit more.
+ */
+uint64_t sv_insn_t::remap(uint64_t reg, bool intreg, int &voffs)
+{
+  // okaay so first determine which map to use.  intreg is passed
+  // in (ultimately) from id_regs.py's examination of the use of
+  // FRS1/RS1, WRITE_FRD/WRITE_RD, which in turn gets passed
+  // in from sv_insn_t::fimap...
+  sv_reg_entry *r = get_regentry(reg, intreg);
+
+  // next we check if this entry is active.  if not, the register
+  // is not being "redirected", so just return the actual reg.
+  if (!r->active)
+  {
+    return reg; // not active: return as-is
+  }
+  vloop_continue = true;
+
+  // next we go through the lookup table.  *THIS* is why the
+  // sv_reg_entry table is 32 entries (5-bit) *NOT* 6 bits
+  // the *KEY* (reg) is 5-bit, the *VALUE* (actual target reg) is 6-bit
+  // XXX TODO: must actually double NXPR and NXFR in processor.h to cope!!
+  reg = r->regidx;
+
+  // now we determine if this is a scalar/vector: if it's scalar
+  // we return the re-mapped register...
+  if (!r->isvec) // scalar
+  {
+    return reg; 
+  }
+  vloop_continue = true;
+
+  // aaand now, as it's a "vector", FINALLY we can add on the loop-offset
+  // which was passed in to the sv_insn_t constructor (by reference)
+  // and, at last, we have "parallelism" a la contiguous registers.
+  reg += voffs; // wheww :)
+
+  return reg;
+}
+
+/* gets the predication value (if active).  returns all-1s if not active
+ * also returns whether zeroing is enabled/disabled for this register.
+ *
+ * uses the same sort of lookup logic as remap:
+ *
+ * - first thing to note is, there is one CSR table for FP and one for INT
+ *   (so, FP regs can be predicated separately from INT ones)
+ * - redirection occurs if the CSR entry for the register is "active".
+ * - inversion of the predication can be set (so it's possible to have
+ *   the same actual register value be unchanged yet be referred to by
+ *   *TWO* redirections, one with inversion, one with not).
+ *
+ * note that this function *actually* returns the value of the (integer)
+ * register file, hence why processor_t has to be passed in
+ *
+ * note also that *even scalar* ops will be predicated (i.e. if a register
+ * has been set active=true and isvec=false in sv_int_tb or sv_fp_tb).
+ * the way to ensure that scalar ops are not predicated is: set VLEN=0,
+ * set active=false in sv_int_tb/sv_fp_tb for that register, or switch off
+ * the predication for that register (sv_pred_int_tb/sv_pred_fb_tb).
+ *
+ * note also that the hard limit on SV maximum vector length is actually
+ * down to the number of bits in the predication i.e. the bitwidth of integer
+ * registers (i.e. XLEN bits).
+ */
+reg_t sv_insn_t::predicate(uint64_t reg, bool intreg, bool &zeroing)
+{
+  sv_reg_entry *pr = get_regentry(reg, intreg);
+  if (!pr->active)
+  {
+    return ~0x0; // *REGISTER* not active: return all-1s (unconditional "on")
+  }
+  sv_pred_entry *r = get_predentry(reg, intreg);
+  if (!r->active)
+  {
+    return ~0x0; // *PREDICATION* not active: return all-1s (unconditional "on")
+  }
+  zeroing = r->zero;
+  reg = r->regidx;
+  reg_t predicate = READ_REG(reg); // macros go through processor_t state
+  if (r->inv)
+  {
+    return ~predicate;
+  }
+  return predicate;
+}
+
+uint64_t sv_insn_t::predicated(uint64_t reg, int offs, uint64_t pred)
+{
+    if (pred & (1<<offs))
+    {
+        return reg;
+    }
+    fprintf(stderr, "predication %ld %d %lx\n", reg, offs, pred);
+    return 0;
+}
+
+bool sv_insn_t::stop_vloop(void)
+{
+    return (p->get_state()->vl == 0) || !vloop_continue;
+}
 
-sv_reg_csr_entry sv_csrs[SV_CSR_SZ];
-sv_reg_entry sv_int_tb[NXPR];
-sv_reg_entry sv_fp_tb[NFPR];
-sv_pred_csr_entry sv_pred_csrs[SV_CSR_SZ];
-sv_pred_entry sv_pred_tb[NXPR];