now generic variants behave differently in RV32 and RV64.
#include "config.h"
-#ifdef RISCV_ENABLE_64BIT
-# define support_64bit 1
-#else
-# define support_64bit 0
-#endif
-
-#ifdef RISCV_ENABLE_FPU
-# define support_fp 1
-#else
-# define support_fp 0
-#endif
-
-
typedef int int128_t __attribute__((mode(TI)));
typedef unsigned int uint128_t __attribute__((mode(TI)));
const int OPCODE_BITS = 7;
-const int GPR_BITS = 8*sizeof(reg_t);
-const int GPRID_BITS = 5;
-const int NGPR = 1 << GPRID_BITS;
+const int XPRID_BITS = 5;
+const int NXPR = 1 << XPRID_BITS;
const int FPR_BITS = 64;
const int FPRID_BITS = 5;
unsigned opcode : OPCODE_BITS;
unsigned funct : FUNCT_BITS;
signed imm12 : IMM_BITS;
- unsigned rs1 : GPRID_BITS;
- unsigned rd : GPRID_BITS;
+ unsigned rs1 : XPRID_BITS;
+ unsigned rd : XPRID_BITS;
};
struct btype_t
unsigned opcode : OPCODE_BITS;
unsigned funct : FUNCT_BITS;
unsigned immlo : IMMLO_BITS;
- unsigned rs2 : GPRID_BITS;
- unsigned rs1 : GPRID_BITS;
+ unsigned rs2 : XPRID_BITS;
+ unsigned rs1 : XPRID_BITS;
signed immhi : IMM_BITS-IMMLO_BITS;
};
unsigned opcode : OPCODE_BITS;
unsigned funct : FUNCT_BITS;
unsigned functr : FUNCTR_BITS;
- unsigned rs2 : GPRID_BITS;
- unsigned rs1 : GPRID_BITS;
- unsigned rd : GPRID_BITS;
+ unsigned rs2 : XPRID_BITS;
+ unsigned rs1 : XPRID_BITS;
+ unsigned rd : XPRID_BITS;
};
struct ltype_t
{
unsigned opcode : OPCODE_BITS;
unsigned bigimm : BIGIMM_BITS;
- unsigned rd : GPRID_BITS;
+ unsigned rd : XPRID_BITS;
};
struct ftype_t
#endif
// helpful macros, etc
-#define RS1 R[insn.rtype.rs1]
-#define RS2 R[insn.rtype.rs2]
-#define RD do_writeback(R,insn.rtype.rd)
-#define RA do_writeback(R,1)
-#define FRS1 FR[insn.ftype.rs1]
-#define FRS2 FR[insn.ftype.rs2]
-#define FRS3 FR[insn.ftype.rs3]
-#define FRD FR[insn.ftype.rd]
+#define RS1 XPR[insn.rtype.rs1]
+#define RS2 XPR[insn.rtype.rs2]
+#define RD do_writeback(XPR,insn.rtype.rd)
+#define RA do_writeback(XPR,1)
+#define FRS1 FPR[insn.ftype.rs1]
+#define FRS2 FPR[insn.ftype.rs2]
+#define FRS3 FPR[insn.ftype.rs3]
+#define FRD FPR[insn.ftype.rd]
#define BIGIMM insn.ltype.bigimm
#define SIMM insn.itype.imm12
#define BIMM ((signed)insn.btype.immlo | (insn.btype.immhi << IMMLO_BITS))
((fsr & FSR_RD) >> FSR_RD_SHIFT))
#define require_supervisor if(!(sr & SR_S)) throw trap_privileged_instruction
-#define require64 if(gprlen != 64) throw trap_illegal_instruction
+#define xpr64 (xprlen == 64)
+#define require_xpr64 if(!xpr64) throw trap_illegal_instruction
#define require_fp if(!(sr & SR_EF)) throw trap_fp_disabled
-#define cmp_trunc(reg) (reg_t(reg) << (64-gprlen))
+#define cmp_trunc(reg) (reg_t(reg) << (64-xprlen))
#define set_fp_exceptions ({ set_fsr(fsr | \
(softfloat_exceptionFlags << FSR_AEXC_SHIFT)); \
softfloat_exceptionFlags = 0; })
return arg;
}
+#define sext_xprlen(x) ((sreg_t(x) << (64-xprlen)) >> (64-xprlen))
+
#endif
#include "insns/divuw.h"
break;
}
- if((insn.bits & 0x1ffff) == 0xcf7)
- {
- #include "insns/mulhuw.h"
- break;
- }
if((insn.bits & 0x1ffff) == 0xf7)
{
#include "insns/mulw.h"
#include "insns/remw.h"
break;
}
- if((insn.bits & 0x1ffff) == 0x8f7)
- {
- #include "insns/mulhw.h"
- break;
- }
if((insn.bits & 0x1ffff) == 0x10f7)
{
#include "insns/divw.h"
-require64;
-RD = RS1 + RS2;
+RD = sext_xprlen(RS1 + RS2);
-require64;
-RD = SIMM + RS1;
+RD = sext_xprlen(RS1 + SIMM);
+require_xpr64;
RD = sext32(SIMM + RS1);
+require_xpr64;
RD = sext32(RS1 + RS2);
-
-require64;
+require_xpr64;
reg_t v = mmu.load_uint64(RS1);
mmu.store_uint64(RS1, RS2 + v);
RD = v;
-require64;
+require_xpr64;
reg_t v = mmu.load_uint64(RS1);
mmu.store_uint64(RS1, RS2 & v);
RD = v;
-require64;
+require_xpr64;
sreg_t v = mmu.load_int64(RS1);
mmu.store_uint64(RS1, std::max(sreg_t(RS2),v));
RD = v;
-require64;
+require_xpr64;
reg_t v = mmu.load_uint64(RS1);
mmu.store_uint64(RS1, std::max(RS2,v));
RD = v;
-require64;
+require_xpr64;
sreg_t v = mmu.load_int64(RS1);
mmu.store_uint64(RS1, std::min(sreg_t(RS2),v));
RD = v;
-require64;
+require_xpr64;
reg_t v = mmu.load_uint64(RS1);
mmu.store_uint64(RS1, std::min(RS2,v));
RD = v;
-require64;
+require_xpr64;
reg_t v = mmu.load_uint64(RS1);
mmu.store_uint64(RS1, RS2 | v);
RD = v;
-require64;
+require_xpr64;
reg_t v = mmu.load_uint64(RS1);
mmu.store_uint64(RS1, RS2);
RD = v;
-require64;
+require_xpr64;
require_fp;
softfloat_roundingMode = RM;
FRD = i64_to_f64(RS1);
-require64;
+require_xpr64;
require_fp;
softfloat_roundingMode = RM;
RD = f64_to_i64_r_minMag(FRS1,true);
-require64;
+require_xpr64;
require_fp;
softfloat_roundingMode = RM;
RD = f32_to_i64_r_minMag(FRS1,true);
-require64;
+require_xpr64;
require_fp;
softfloat_roundingMode = RM;
FRD = i64_to_f32(RS1);
-require64;
+require_xpr64;
require_fp;
softfloat_roundingMode = RM;
FRD = i64_to_f64(RS1);
-require64;
+require_xpr64;
require_fp;
softfloat_roundingMode = RM;
RD = f64_to_i64_r_minMag(FRS1,true);
-require64;
+require_xpr64;
require_fp;
softfloat_roundingMode = RM;
RD = f32_to_i64_r_minMag(FRS1,true);
-require64;
+require_xpr64;
require_fp;
softfloat_roundingMode = RM;
FRD = i64_to_f32(RS1);
-require64;
if(RS2 == 0 || (sreg_t(RS1) == INT64_MIN && sreg_t(RS2) == -1))
- RD = sreg_t(RS1) < 0 ? INT64_MIN : INT64_MAX;
+{
+ if(xpr64)
+ RD = sreg_t(RS1) < 0 ? INT64_MIN : INT64_MAX;
+ else
+ RD = sreg_t(RS1) < 0 ? sext32(INT32_MIN) : INT32_MAX;
+}
else
- RD = sreg_t(RS1) / sreg_t(RS2);
+ RD = sext_xprlen(sreg_t(RS1) / sreg_t(RS2));
-require64;
if(RS2 == 0)
RD = UINT64_MAX;
else
- RD = RS1 / RS2;
+ RD = sext_xprlen(RS1 / RS2);
-if(uint32_t(RS2) == 0)
- RD = sext32(UINT32_MAX);
+require_xpr64;
+if(RS2 == 0)
+ RD = UINT64_MAX;
else
- RD = sext32(uint32_t(RS1)/uint32_t(RS2));
+ RD = sext32(RS1 / RS2);
-if(int32_t(RS2) == 0 || (int32_t(RS1) == INT32_MIN && int32_t(RS2) == -1))
- RD = sext32(int32_t(RS1) < 0 ? INT32_MIN : INT32_MAX);
+require_xpr64;
+// INT64_MIN/-1 corner case shouldn't occur in correct code, since
+// INT64_MIN is not a proper 32-bit signed value
+if(RS2 == 0 || (sreg_t(RS1) == INT64_MIN && sreg_t(RS2) == -1))
+ RD = sext32(sreg_t(RS1) < 0 ? INT32_MIN : INT32_MAX);
else
- RD = sext32(int32_t(RS1)/int32_t(RS2));
+ RD = sext32(sreg_t(RS1) / sreg_t(RS2));
-require64;
+require_xpr64;
RD = mmu.load_int64(RS1+SIMM);
val = -1;
}
-RD = gprlen == 64 ? val : sext32(val);
+RD = sext_xprlen(val);
-require64;
+require_xpr64;
require_fp;
RD = FRS2;
val = -1;
}
-RD = gprlen == 64 ? val : sext32(val);
+RD = sext_xprlen(val);
-require64;
+require_xpr64;
require_fp;
FRD = RS1;
-require64;
-RD = RS1 * RS2;
+RD = sext_xprlen(RS1 * RS2);
-require64;
-int64_t rb = RS1;
-int64_t ra = RS2;
-RD = (int128_t(rb) * int128_t(ra)) >> 64;
+if(xpr64)
+{
+ int64_t a = RS1;
+ int64_t b = RS2;
+ RD = (int128_t(a) * int128_t(b)) >> 64;
+}
+else
+ RD = sext32((sreg_t(RS1) * sreg_t(RS2)) >> 32);
-require64;
-RD = (uint128_t(RS1) * uint128_t(RS2)) >> 64;
+if(xpr64)
+ RD = (uint128_t(RS1) * uint128_t(RS2)) >> 64;
+else
+ RD = sext32((RS1 * RS2) >> 32);
+++ /dev/null
-RD = sext32((RS1 * RS2) >> 32);
-
+++ /dev/null
-RD = sext32((sreg_t(RS1) * sreg_t(RS2)) >> 32);
-
+require_xpr64;
RD = sext32(RS1 * RS2);
-
-require64;
-if(RS2 == 0 || (sreg_t(RS1) == INT64_MIN && sreg_t(RS2) == -1))
+if(RS2 == 0)
+ RD = RS1;
+else if(sreg_t(RS1) == INT64_MIN && sreg_t(RS2) == -1)
RD = 0;
else
- RD = sreg_t(RS1) % sreg_t(RS2);
+ RD = sext_xprlen(sreg_t(RS1) % sreg_t(RS2));
-require64;
if(RS2 == 0)
- RD = 0;
+ RD = RS1;
else
- RD = RS1 % RS2;
+ RD = sext_xprlen(RS1 % RS2);
-if(uint32_t(RS2) == 0)
- RD = 0;
+require_xpr64;
+if(RS2 == 0)
+ RD = RS1;
else
- RD = sext32(uint32_t(RS1) % uint32_t(RS2));
+ RD = sext32(RS1 % RS2);
-if(int32_t(RS2) == 0 || (int32_t(RS1) == INT32_MIN && int32_t(RS2) == -1))
+require_xpr64;
+// INT64_MIN/-1 corner case shouldn't occur in correct code, since
+// INT64_MIN is not a proper 32-bit signed value
+if(RS2 == 0)
+ RD = RS1;
+else if(sreg_t(RS1) == INT64_MIN && sreg_t(RS2) == -1)
RD = 0;
else
- RD = sext32(int32_t(RS1) % int32_t(RS2));
+ RD = sext32(sreg_t(RS1) % sreg_t(RS2));
-require64;
+require_xpr64;
mmu.store_uint64(RS1+BIMM, RS2);
-require64;
-RD = RS1 << (RS2 & 0x3F);
+RD = sext_xprlen(RS1 << (RS2 & (xprlen-1)));
-require64;
-RD = RS1 << SHAMT;
+if(xpr64)
+ RD = RS1 << SHAMT;
+else
+{
+ if(SHAMT & 0x20)
+ throw trap_illegal_instruction;
+ RD = sext32(RS1 << SHAMT);
+}
+require_xpr64;
RD = sext32(RS1 << SHAMTW);
+require_xpr64;
RD = sext32(RS1 << (RS2 & 0x1F));
-require64;
-RD = sreg_t(RS1) >> (RS2 & 0x3F);
+RD = sext_xprlen(sreg_t(RS1) >> (RS2 & (xprlen-1)));
-require64;
-RD = sreg_t(RS1) >> SHAMT;
+if(xpr64)
+ RD = sreg_t(RS1) >> SHAMT;
+else
+{
+ if(SHAMT & 0x20)
+ throw trap_illegal_instruction;
+ RD = sext32(sreg_t(RS1) >> SHAMT);
+}
+require_xpr64;
RD = sext32(sreg_t(RS1) >> SHAMTW);
+require_xpr64;
RD = sext32(sreg_t(RS1) >> (RS2 & 0x1F));
-require64;
-RD = RS1 >> (RS2 & 0x3F);
+if(xpr64)
+ RD = RS1 >> (RS2 & 0x3F);
+else
+ RD = sext32((uint32_t)RS1 >> (RS2 & 0x1F));
-require64;
-RD = RS1 >> SHAMT;
+if(xpr64)
+ RD = RS1 >> SHAMT;
+else
+{
+ if(SHAMT & 0x20)
+ throw trap_illegal_instruction;
+ RD = sext32((uint32_t)RS1 >> SHAMT);
+}
+require_xpr64;
RD = sext32((uint32_t)RS1 >> SHAMTW);
+require_xpr64;
RD = sext32((uint32_t)RS1 >> (RS2 & 0x1F));
-require64;
-RD = RS1 - RS2;
+RD = sext_xprlen(RS1 - RS2);
+require_xpr64;
RD = sext32(RS1 - RS2);
processor_t::processor_t(sim_t* _sim, char* _mem, size_t _memsz)
: sim(_sim), mmu(_mem,_memsz)
{
- memset(R,0,sizeof(R));
- memset(FR,0,sizeof(FR));
+ memset(XPR,0,sizeof(XPR));
+ memset(FPR,0,sizeof(FPR));
pc = 0;
evec = 0;
epc = 0;
count = 0;
compare = 0;
interrupts_pending = 0;
- set_sr(SR_S | (support_64bit ? SR_SX : 0));
+ set_sr(SR_S | SR_SX); // SX ignored if 64b mode not supported
set_fsr(0);
memset(counters,0,sizeof(counters));
void processor_t::set_sr(uint32_t val)
{
sr = val & ~SR_ZERO;
- if(!support_64bit)
- sr &= ~(SR_SX | SR_UX);
- if(!support_fp)
- sr &= ~SR_EF;
-
- gprlen = ((sr & SR_S) ? (sr & SR_SX) : (sr & SR_UX)) ? 64 : 32;
+#ifndef RISCV_ENABLE_64BIT
+ sr &= ~(SR_SX | SR_UX);
+#endif
+#ifndef RISCV_ENABLE_64BIT
+ sr &= ~SR_EF;
+#endif
+
+ xprlen = ((sr & SR_S) ? (sr & SR_SX) : (sr & SR_UX)) ? 64 : 32;
}
void processor_t::set_fsr(uint32_t val)
#include "execute.h"
pc = npc;
- R[0] = 0;
+ XPR[0] = 0;
if(count++ == compare)
interrupts_pending |= 1 << TIMER_IRQ;
sim_t* sim;
// architected state
- reg_t R[NGPR];
- freg_t FR[NFPR];
+ reg_t XPR[NXPR];
+ freg_t FPR[NFPR];
// privileged control registers
reg_t pc;
// unprivileged control registers
uint32_t fsr;
- // 32-bit or 64-bit mode (redundant with sr)
- int gprlen;
+ // # of bits in an XPR (32 or 64). (redundant with sr)
+ int xprlen;
// shared memory
mmu_t mmu;
int p = atoi(args[0].c_str());
int r = atoi(args[1].c_str());
- if(p >= (int)procs.size() || r >= NGPR)
+ if(p >= (int)procs.size() || r >= NXPR)
throw trap_illegal_instruction;
- return procs[p].R[r];
+ return procs[p].XPR[r];
}
reg_t sim_t::get_freg(const std::vector<std::string>& args)
if(p >= (int)procs.size() || r >= NFPR)
throw trap_illegal_instruction;
- return procs[p].FR[r];
+ return procs[p].FPR[r];
}
reg_t sim_t::get_tohost(const std::vector<std::string>& args)