Implement clearing-misa.C-while-PC-is-misaligned proposal
[riscv-isa-sim.git] / riscv / decode.h
index f525ff16f1a0670caaffe676a7bcab86a35ec22e..596a2ad9bfea1bfe24b38ed1b733e5a8c91bb688 100644 (file)
@@ -7,17 +7,22 @@
 # error spike requires a two''s-complement c++ implementation
 #endif
 
+#ifdef WORDS_BIGENDIAN
+# error spike requires a little-endian host
+#endif
+
 #include <cstdint>
 #include <string.h>
 #include <strings.h>
 #include "encoding.h"
 #include "config.h"
 #include "common.h"
+#include "softfloat_types.h"
+#include "specialize.h"
 #include <cinttypes>
 
 typedef int64_t sreg_t;
 typedef uint64_t reg_t;
-typedef uint64_t freg_t;
 
 const int NXPR = 32;
 const int NFPR = 32;
@@ -130,15 +135,15 @@ private:
 
 #ifndef RISCV_ENABLE_COMMITLOG
 # define WRITE_REG(reg, value) STATE.XPR.write(reg, value)
-# define WRITE_FREG(reg, value) DO_WRITE_FREG(reg, value)
+# define WRITE_FREG(reg, value) DO_WRITE_FREG(reg, freg(value))
 #else
 # define WRITE_REG(reg, value) ({ \
     reg_t wdata = (value); /* value may have side effects */ \
-    STATE.log_reg_write = (commit_log_reg_t){(reg) << 1, wdata}; \
+    STATE.log_reg_write = (commit_log_reg_t){(reg) << 1, {wdata, 0}}; \
     STATE.XPR.write(reg, wdata); \
   })
 # define WRITE_FREG(reg, value) ({ \
-    freg_t wdata = (value); /* value may have side effects */ \
+    freg_t wdata = freg(value); /* value may have side effects */ \
     STATE.log_reg_write = (commit_log_reg_t){((reg) << 1) | 1, wdata}; \
     DO_WRITE_FREG(reg, wdata); \
   })
@@ -170,21 +175,24 @@ private:
 #define JUMP_TARGET (pc + insn.uj_imm())
 #define RM ({ int rm = insn.rm(); \
               if(rm == 7) rm = STATE.frm; \
-              if(rm > 4) throw trap_illegal_instruction(); \
+              if(rm > 4) throw trap_illegal_instruction(0); \
               rm; })
 
 #define get_field(reg, mask) (((reg) & (decltype(reg))(mask)) / ((mask) & ~((mask) << 1)))
 #define set_field(reg, mask, val) (((reg) & ~(decltype(reg))(mask)) | (((decltype(reg))(val) * ((mask) & ~((mask) << 1))) & (decltype(reg))(mask)))
 
-#define require(x) if (unlikely(!(x))) throw trap_illegal_instruction()
-#define require_privilege(p) require(get_field(STATE.mstatus, MSTATUS_PRV) >= (p))
+#define require(x) if (unlikely(!(x))) throw trap_illegal_instruction(0)
+#define require_privilege(p) require(STATE.prv >= (p))
 #define require_rv64 require(xlen == 64)
 #define require_rv32 require(xlen == 32)
 #define require_extension(s) require(p->supports_extension(s))
 #define require_fp require((STATE.mstatus & MSTATUS_FS) != 0)
 #define require_accelerator require((STATE.mstatus & MSTATUS_XS) != 0)
 
-#define set_fp_exceptions ({ STATE.fflags |= softfloat_exceptionFlags; \
+#define set_fp_exceptions ({ if (softfloat_exceptionFlags) { \
+                               dirty_fp_state; \
+                               STATE.fflags |= softfloat_exceptionFlags; \
+                             } \
                              softfloat_exceptionFlags = 0; })
 
 #define sext32(x) ((sreg_t)(int32_t)(x))
@@ -193,25 +201,74 @@ private:
 #define zext_xlen(x) (((reg_t)(x) << (64-xlen)) >> (64-xlen))
 
 #define set_pc(x) \
-  do { if (unlikely(((x) & 2)) && !p->supports_extension('C')) \
-         throw trap_instruction_address_misaligned(x); \
+  do { p->check_pc_alignment(x); \
        npc = sext_xlen(x); \
      } while(0)
 
-#define PC_SERIALIZE 3 /* sentinel value indicating simulator pipeline flush */
+#define set_pc_and_serialize(x) \
+  do { reg_t __npc = (x); \
+       npc = PC_SERIALIZE_AFTER; \
+       STATE.pc = __npc; \
+     } while(0)
+
+#define serialize() set_pc_and_serialize(npc)
+
+/* Sentinel PC values to serialize simulator pipeline */
+#define PC_SERIALIZE_BEFORE 3
+#define PC_SERIALIZE_AFTER 5
+#define invalid_pc(pc) ((pc) & 1)
 
 /* Convenience wrappers to simplify softfloat code sequences */
-#define f32(x) ((float32_t){(uint32_t)x})
-#define f64(x) ((float64_t){(uint64_t)x})
+#define isBoxedF32(r) (isBoxedF64(r) && ((uint32_t)((r.v[0] >> 32) + 1) == 0))
+#define unboxF32(r) (isBoxedF32(r) ? (uint32_t)r.v[0] : defaultNaNF32UI)
+#define isBoxedF64(r) ((r.v[1] + 1) == 0)
+#define unboxF64(r) (isBoxedF64(r) ? r.v[0] : defaultNaNF64UI)
+typedef float128_t freg_t;
+inline float32_t f32(uint32_t v) { return { v }; }
+inline float64_t f64(uint64_t v) { return { v }; }
+inline float32_t f32(freg_t r) { return f32(unboxF32(r)); }
+inline float64_t f64(freg_t r) { return f64(unboxF64(r)); }
+inline float128_t f128(freg_t r) { return r; }
+inline freg_t freg(float32_t f) { return { ((uint64_t)-1 << 32) | f.v, (uint64_t)-1 }; }
+inline freg_t freg(float64_t f) { return { f.v, (uint64_t)-1 }; }
+inline freg_t freg(float128_t f) { return f; }
+#define F32_SIGN ((uint32_t)1 << 31)
+#define F64_SIGN ((uint64_t)1 << 63)
+#define fsgnj32(a, b, n, x) \
+  f32((f32(a).v & ~F32_SIGN) | ((((x) ? f32(a).v : (n) ? F32_SIGN : 0) ^ f32(b).v) & F32_SIGN))
+#define fsgnj64(a, b, n, x) \
+  f64((f64(a).v & ~F64_SIGN) | ((((x) ? f64(a).v : (n) ? F64_SIGN : 0) ^ f64(b).v) & F64_SIGN))
+
+#define isNaNF128(x) isNaNF128UI(x.v[1], x.v[0])
+inline float128_t defaultNaNF128()
+{
+  float128_t nan;
+  nan.v[1] = defaultNaNF128UI64;
+  nan.v[0] = defaultNaNF128UI0;
+  return nan;
+}
+inline freg_t fsgnj128(freg_t a, freg_t b, bool n, bool x)
+{
+  a.v[1] = (a.v[1] & ~F64_SIGN) | (((x ? a.v[1] : n ? F64_SIGN : 0) ^ b.v[1]) & F64_SIGN);
+  return a;
+}
+inline freg_t f128_negate(freg_t a)
+{
+  a.v[1] ^= F64_SIGN;
+  return a;
+}
 
 #define validate_csr(which, write) ({ \
-  if (!STATE.serialized) return PC_SERIALIZE; \
+  if (!STATE.serialized) return PC_SERIALIZE_BEFORE; \
   STATE.serialized = false; \
-  unsigned my_priv = get_field(STATE.mstatus, MSTATUS_PRV); \
   unsigned csr_priv = get_field((which), 0x300); \
   unsigned csr_read_only = get_field((which), 0xC00) == 3; \
-  if (((write) && csr_read_only) || my_priv < csr_priv) \
-    throw trap_illegal_instruction(); \
+  if (((write) && csr_read_only) || STATE.prv < csr_priv) \
+    throw trap_illegal_instruction(0); \
   (which); })
 
+// Seems that 0x0 doesn't work.
+#define DEBUG_START             0x100
+#define DEBUG_END                 (0x1000 - 1)
+
 #endif