// See LICENSE for license details.
+#define xstr(s) str(s)
+#define str(s) #s
+
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_RD
- insn.check_reg(true, s_insn.rd()) |
-#endif
-#ifdef USING_RS1
- insn.check_reg(true, s_insn.rs1()) |
-#endif
-#ifdef USING_RS2
- insn.check_reg(true, s_insn.rs2()) |
+ 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
-#ifdef USING_RS2
- insn.check_reg(true, s_insn.rs3()) |
-#endif
- // fp ops, RD, RS1, RS2, RS3 (use sv_fp_tb)
-#ifdef USING_FRD
- insn.check_reg(false, s_insn.frd()) |
-#endif
-#ifdef USING_FRS1
- insn.check_reg(false, s_insn.frs1()) |
-#endif
-#ifdef USING_FRS2
- insn.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_FRS2
- insn.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 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)
{
- // TODO: vlen = p->CSR(SIMPLEV_VL); // something like that...
+ 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);