add packed (non-default) elwidth support in DO_WRITE_FREG
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Wed, 31 Oct 2018 11:37:15 +0000 (11:37 +0000)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Wed, 31 Oct 2018 11:37:15 +0000 (11:37 +0000)
riscv/sv_insn_redirect.cc

index a11ec6aa2bcc13ab6d52c6fc53ae1fd1eea19c99..b995c788bf571fa051cb89d13fd5b49e3269d92a 100644 (file)
@@ -86,16 +86,60 @@ void (sv_proc_t::WRITE_RD)(sv_reg_t const& value)
     WRITE_REG( _insn->rd(), value ); // XXX TODO: replace properly
 }
 
+union freg_shift {
+    freg_t f;
+    uint8_t b[sizeof(freg_t)*8];
+};
+
 void (sv_proc_t::DO_WRITE_FREG)(reg_spec_t const& spec, sv_freg_t const& value)
 {
+    int flen = sizeof(freg_t) * 8; // FLEN (not specified in spike)
     reg_t reg = spec.reg;
     uint8_t dest_elwidth = _insn->reg_elwidth(reg, false);
-    if (spec.offset) {
-        reg += *spec.offset;
-    }
+    int bitwidth = get_bitwidth(dest_elwidth, flen);
     fprintf(stderr, "DO_WRITE_FRD rd %ld ew %d data %lx %lx\n",
             reg, dest_elwidth, ((freg_t)value).v[0], ((freg_t)value).v[1]);
-    STATE.FPR.write(reg, value);
+    unsigned int shift = 0;
+    unsigned int offs = 0;
+    if (spec.offset != NULL) {
+        unsigned int nbytes = xlen / bitwidth;
+        offs = *spec.offset;
+        shift = offs % nbytes;
+        offs /= nbytes;
+        reg += offs;
+        fprintf(stderr, "writefreg spec %ld bitwidth %d offs %d shift %d\n",
+                        reg, bitwidth, offs, shift);
+    }
+    freg_shift fd;
+    if (xlen != bitwidth)
+    {
+        char report[2] = {};
+        freg_shift fs;
+        fs.f = value;
+        fd.f = _insn->p->get_state()->FPR[reg];
+        int sblen = shift*bitwidth/8;
+        for (int i = 0; i < ((int)bitwidth/8); i++) {
+            if (i < (bitwidth/8)) {
+               fd.b[i+sblen] = fs.b[i];
+            }
+        }
+        if (!spec.isvec) {
+            for (int i = (bitwidth/8); i < ((int)flen/8); i++) {
+                    fd.b[i] = 0xff;
+            }
+            report[0] = 's';
+        }
+        fprintf(stderr, "writefreg %s %ld bitwidth %d offs %d shift %d " \
+                        " %lx:%lx %lx:%lx\n",
+                        report, spec.reg, bitwidth, offs, shift,
+                        fs.f.v[0], fs.f.v[1],
+                        fd.f.v[0], fd.f.v[1]);
+    }
+    else
+    {
+        fd.f = value;
+    }
+    STATE.FPR.write(reg, fd.f);
     dirty_fp_state;
 }
 
@@ -143,11 +187,6 @@ void (sv_proc_t::WRITE_REG)(reg_spec_t const& spec, sv_reg_t const& value)
     STATE.XPR.write(reg, wval);
 }
 
-union freg_shift {
-    freg_t f;
-    uint8_t b[sizeof(freg_t)*8];
-};
-
 freg_t (sv_proc_t::READ_FREG)(reg_spec_t const& spec)
 {
     int flen = sizeof(freg_t) * 8; // FLEN (not specified in spike)