Sorry, everyone.
}
#define require_supervisor_hwacha \
- if (unlikely(!(p->get_state()->sr & SR_S))) \
+ if (get_field(p->get_state()->mstatus, MSTATUS_PRV) < PRV_S) \
h->take_exception(HWACHA_CAUSE_PRIVILEGED_INSTRUCTION, uint32_t(insn.bits()));
#endif
void ut_state_t::reset()
{
- run = false;
- XPR.reset();
- FPR.reset();
+ memset(this, 0, sizeof(*this));
}
void hwacha_t::reset()
cause = c;
aux = a;
raise_interrupt();
- if (!(p->get_state()->sr & SR_EI))
- throw std::logic_error("hwacha exception posted, but SR_EI bit not set!");
- throw std::logic_error("hwacha exception posted, but IM[COP] bit not set!");
+ throw std::logic_error("a hwacha exception was posted, but interrupts are disabled!");
}
-require_xpr64;
+require_rv64;
require_fp;
softfloat_roundingMode = RM;
WRITE_HFRD(i64_to_f32(RS1));
-require_xpr64;
+require_rv64;
require_fp;
softfloat_roundingMode = RM;
WRITE_HFRD(ui64_to_f32(RS1));
-require_xpr64;
+require_rv64;
require_fp;
softfloat_roundingMode = RM;
WRITE_RD(f32_to_i64(HFRS1, RM, true));
-require_xpr64;
+require_rv64;
require_fp;
softfloat_roundingMode = RM;
WRITE_RD(f32_to_ui64(HFRS1, RM, true));
#include <cstdint>
#include <string.h>
+#include <strings.h>
#include "encoding.h"
#include "config.h"
#include "common.h"
class regfile_t
{
public:
- void reset()
- {
- memset(data, 0, sizeof(data));
- }
void write(size_t i, T value)
{
if (!zero_reg || i != 0)
#define FRS1 STATE.FPR[insn.rs1()]
#define FRS2 STATE.FPR[insn.rs2()]
#define FRS3 STATE.FPR[insn.rs3()]
-#define WRITE_FRD(value) STATE.FPR.write(insn.rd(), value)
+#define dirty_fp_state (STATE.mstatus |= MSTATUS_FS | (xlen == 64 ? MSTATUS64_SD : MSTATUS32_SD))
+#define dirty_ext_state (STATE.mstatus |= MSTATUS_XS | (xlen == 64 ? MSTATUS64_SD : MSTATUS32_SD))
+#define do_write_frd(value) (STATE.FPR.write(insn.rd(), value), dirty_fp_state)
-#ifdef RISCV_ENABLE_COMMITLOG
- #undef WRITE_FRD
- #define WRITE_FRD(value) ({ \
- freg_t wdata = value; /* value is a func with side-effects */ \
+#ifndef RISCV_ENABLE_COMMITLOG
+# define WRITE_FRD(value) do_write_frd(value)
+#else
+# define WRITE_FRD(value) ({ \
+ freg_t wdata = (value); /* value may have side effects */ \
STATE.log_reg_write = (commit_log_reg_t){(insn.rd() << 1) | 1, wdata}; \
- STATE.FPR.write(insn.rd(), wdata); \
+ do_write_frd(wdata); \
})
#endif
if(rm > 4) throw trap_illegal_instruction(); \
rm; })
-#define xpr64 (xlen == 64)
+#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_supervisor if(unlikely(!(STATE.sr & SR_S))) throw trap_privileged_instruction()
-#define require_xpr64 if(unlikely(!xpr64)) throw trap_illegal_instruction()
-#define require_xpr32 if(unlikely(xpr64)) throw trap_illegal_instruction()
-#ifndef RISCV_ENABLE_FPU
-# define require_fp throw trap_illegal_instruction()
-#else
-# define require_fp if(unlikely(!(STATE.sr & SR_EF))) throw trap_fp_disabled()
-#endif
-#define require_accelerator if(unlikely(!(STATE.sr & SR_EA))) throw trap_accelerator_disabled()
+#define require_privilege(p) if (get_field(STATE.mstatus, MSTATUS_PRV) < (p)) throw trap_illegal_instruction()
+#define require_rv64 if(unlikely(xlen != 64)) throw trap_illegal_instruction()
+#define require_rv32 if(unlikely(xlen != 32)) throw trap_illegal_instruction()
+#define require_fp if (unlikely((STATE.mstatus & MSTATUS_FS) == 0)) throw trap_illegal_instruction()
+#define require_accelerator if (unlikely((STATE.mstatus & MSTATUS_XS) == 0)) throw trap_illegal_instruction()
#define cmp_trunc(reg) (reg_t(reg) << (64-xlen))
#define set_fp_exceptions ({ STATE.fflags |= softfloat_exceptionFlags; \
#define set_pc(x) (npc = sext_xlen(x))
#define validate_csr(which, write) ({ \
- unsigned my_priv = (STATE.sr & SR_S) ? 1 : 0; \
- unsigned read_priv = ((which) >> 10) & 3; \
- unsigned write_priv = (((which) >> 8) & 3); \
- if (read_priv == 3) read_priv = write_priv, write_priv = -1; \
- if (my_priv < ((write) ? write_priv : read_priv)) \
- throw trap_privileged_instruction(); \
+ 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(); \
(which); })
#endif
#ifndef RISCV_CSR_ENCODING_H
#define RISCV_CSR_ENCODING_H
-#define SR_S 0x00000001
-#define SR_PS 0x00000002
-#define SR_EI 0x00000004
-#define SR_PEI 0x00000008
-#define SR_EF 0x00000010
-#define SR_U64 0x00000020
-#define SR_S64 0x00000040
-#define SR_VM 0x00000080
-#define SR_EA 0x00000100
-#define SR_IM 0x00FF0000
-#define SR_IP 0xFF000000
-#define SR_ZERO ~(SR_S|SR_PS|SR_EI|SR_PEI|SR_EF|SR_U64|SR_S64|SR_VM|SR_EA|SR_IM|SR_IP)
-#define SR_IM_SHIFT 16
-#define SR_IP_SHIFT 24
+#define MSTATUS_SSIP 0x00000002
+#define MSTATUS_HSIP 0x00000004
+#define MSTATUS_MSIP 0x00000008
+#define MSTATUS_IE 0x00000010
+#define MSTATUS_PRV 0x00000060
+#define MSTATUS_IE1 0x00000080
+#define MSTATUS_PRV1 0x00000300
+#define MSTATUS_IE2 0x00000400
+#define MSTATUS_PRV2 0x00001800
+#define MSTATUS_IE3 0x00002000
+#define MSTATUS_PRV3 0x0000C000
+#define MSTATUS_MPRV 0x00030000
+#define MSTATUS_VM 0x00780000
+#define MSTATUS_STIE 0x01000000
+#define MSTATUS_HTIE 0x02000000
+#define MSTATUS_MTIE 0x04000000
+#define MSTATUS_FS 0x18000000
+#define MSTATUS_XS 0x60000000
+#define MSTATUS32_SD 0x80000000
+#define MSTATUS64_UA 0x0000000F00000000
+#define MSTATUS64_SA 0x000000F000000000
+#define MSTATUS64_HA 0x00000F0000000000
+#define MSTATUS64_SD 0x8000000000000000
-#define IRQ_COP 2
-#define IRQ_IPI 5
-#define IRQ_HOST 6
-#define IRQ_TIMER 7
+#define SSTATUS_SIP 0x00000002
+#define SSTATUS_IE 0x00000010
+#define SSTATUS_PIE 0x00000080
+#define SSTATUS_PS 0x00000100
+#define SSTATUS_UA 0x000F0000
+#define SSTATUS_TIE 0x01000000
+#define SSTATUS_TIP 0x04000000
+#define SSTATUS_FS 0x18000000
+#define SSTATUS_XS 0x60000000
+#define SSTATUS32_SD 0x80000000
+#define SSTATUS64_SD 0x8000000000000000
+
+#define PRV_U 0
+#define PRV_S 1
+#define PRV_H 2
+#define PRV_M 3
+
+#define VM_MBARE 0
+#define VM_MBB 1
+#define VM_MBBID 2
+#define VM_SV32 4
+#define VM_SV43 5
+
+#define UA_RV32 0
+#define UA_RV64 4
+#define UA_RV128 8
+
+#define IRQ_TIMER 0
+#define IRQ_IPI 1
+#define IRQ_HOST 2
+#define IRQ_COP 3
#define IMPL_SPIKE 1
#define IMPL_ROCKET 2
#ifdef __riscv
#ifdef __riscv64
+# define MSTATUS_UA MSTATUS64_UA
+# define MSTATUS_SA MSTATUS64_SA
+# define MSTATUS_HA MSTATUS64_HA
+# define MSTATUS_SD MSTATUS64_SD
+# define SSTATUS_SD SSTATUS64_SD
# define RISCV_PGLEVELS 3
# define RISCV_PGSHIFT 13
#else
+# define MSTATUS_SD MSTATUS32_SD
+# define SSTATUS_SD SSTATUS32_SD
# define RISCV_PGLEVELS 2
# define RISCV_PGSHIFT 12
#endif
#ifndef __ASSEMBLER__
-#define read_csr(reg) ({ long __tmp; \
+#ifdef __GNUC__
+
+#define read_csr(reg) ({ unsigned long __tmp; \
asm volatile ("csrr %0, " #reg : "=r"(__tmp)); \
__tmp; })
asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "r"(val)); \
__tmp; })
-#define set_csr(reg, bit) ({ long __tmp; \
+#define set_csr(reg, bit) ({ unsigned long __tmp; \
if (__builtin_constant_p(bit) && (bit) < 32) \
asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "i"(bit)); \
else \
asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "r"(bit)); \
__tmp; })
-#define clear_csr(reg, bit) ({ long __tmp; \
+#define clear_csr(reg, bit) ({ unsigned long __tmp; \
if (__builtin_constant_p(bit) && (bit) < 32) \
asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "i"(bit)); \
else \
asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "r"(bit)); \
__tmp; })
-#define rdtime() ({ unsigned long __tmp; \
- asm volatile ("rdtime %0" : "=r"(__tmp)); \
- __tmp; })
-
-#define rdcycle() ({ unsigned long __tmp; \
- asm volatile ("rdcycle %0" : "=r"(__tmp)); \
- __tmp; })
+#define rdtime() read_csr(time)
+#define rdcycle() read_csr(cycle)
+#define rdinstret() read_csr(instret)
-#define rdinstret() ({ unsigned long __tmp; \
- asm volatile ("rdinstret %0" : "=r"(__tmp)); \
- __tmp; })
+#endif
#endif
#define MASK_FSGNJN_D 0xfe00707f
#define MATCH_FMIN_S 0x28000053
#define MASK_FMIN_S 0xfe00707f
+#define MATCH_MRET 0x30200073
+#define MASK_MRET 0xffffffff
#define MATCH_CSRRW 0x1073
#define MASK_CSRRW 0x707f
#define MATCH_SLLIW 0x101b
#define MASK_SCALL 0xffffffff
#define MATCH_FCLASS_S 0xe0001053
#define MASK_FCLASS_S 0xfff0707f
+#define MATCH_SFENCE_VM 0x10400073
+#define MASK_SFENCE_VM 0xfff07fff
#define MATCH_SC_W 0x1800202f
#define MASK_SC_W 0xf800707f
#define MATCH_REM 0x2006033
#define MASK_MULH 0xfe00707f
#define MATCH_FMUL_S 0x10000053
#define MASK_FMUL_S 0xfe00007f
+#define MATCH_MCALL 0x20000073
+#define MASK_MCALL 0xffffffff
#define MATCH_CSRRSI 0x6073
#define MASK_CSRRSI 0x707f
#define MATCH_SRAI 0x40005013
#define MASK_FSUB_D 0xfe00007f
#define MATCH_FSGNJX_S 0x20002053
#define MASK_FSGNJX_S 0xfe00707f
+#define MATCH_MRTS 0x30900073
+#define MASK_MRTS 0xffffffff
#define MATCH_FEQ_D 0xa2002053
#define MASK_FEQ_D 0xfe00707f
#define MATCH_FCVT_D_WU 0xd2100053
#define MASK_ANDI 0x707f
#define MATCH_FMV_X_S 0xe0000053
#define MASK_FMV_X_S 0xfff0707f
-#define MATCH_SRET 0x80000073
+#define MATCH_SRET 0x10200073
#define MASK_SRET 0xffffffff
#define MATCH_FNMADD_S 0x4f
#define MASK_FNMADD_S 0x600007f
#define CSR_FFLAGS 0x1
#define CSR_FRM 0x2
#define CSR_FCSR 0x3
-#define CSR_STATS 0xc0
-#define CSR_SUP0 0x500
-#define CSR_SUP1 0x501
-#define CSR_EPC 0x502
-#define CSR_BADVADDR 0x503
-#define CSR_PTBR 0x504
-#define CSR_ASID 0x505
-#define CSR_COUNT 0x506
-#define CSR_COMPARE 0x507
-#define CSR_EVEC 0x508
-#define CSR_CAUSE 0x509
-#define CSR_STATUS 0x50a
-#define CSR_HARTID 0x50b
-#define CSR_IMPL 0x50c
-#define CSR_FATC 0x50d
-#define CSR_SEND_IPI 0x50e
-#define CSR_CLEAR_IPI 0x50f
-#define CSR_RESET 0x51d
-#define CSR_TOHOST 0x51e
-#define CSR_FROMHOST 0x51f
#define CSR_CYCLE 0xc00
#define CSR_TIME 0xc01
#define CSR_INSTRET 0xc02
+#define CSR_STATS 0xc0
#define CSR_UARCH0 0xcc0
#define CSR_UARCH1 0xcc1
#define CSR_UARCH2 0xcc2
#define CSR_UARCH13 0xccd
#define CSR_UARCH14 0xcce
#define CSR_UARCH15 0xccf
-#define CSR_COUNTH 0x586
+#define CSR_SSTATUS 0x100
+#define CSR_STVEC 0x101
+#define CSR_STIMECMP 0x121
+#define CSR_SSCRATCH 0x140
+#define CSR_SEPC 0x141
+#define CSR_SPTBR 0x188
+#define CSR_SASID 0x189
+#define CSR_SCYCLE 0x900
+#define CSR_STIME 0x901
+#define CSR_SINSTRET 0x902
+#define CSR_SCAUSE 0xd40
+#define CSR_SBADADDR 0xd41
+#define CSR_MSTATUS 0x300
+#define CSR_MSCRATCH 0x340
+#define CSR_MEPC 0x341
+#define CSR_MCAUSE 0x342
+#define CSR_MBADADDR 0x343
+#define CSR_RESET 0x780
+#define CSR_TOHOST 0x781
+#define CSR_FROMHOST 0x782
+#define CSR_SEND_IPI 0x783
+#define CSR_HARTID 0xfc0
#define CSR_CYCLEH 0xc80
#define CSR_TIMEH 0xc81
#define CSR_INSTRETH 0xc82
+#define CSR_SCYCLEH 0x980
+#define CSR_STIMEH 0x981
+#define CSR_SINSTRETH 0x982
#define CAUSE_MISALIGNED_FETCH 0x0
#define CAUSE_FAULT_FETCH 0x1
#define CAUSE_ILLEGAL_INSTRUCTION 0x2
-#define CAUSE_PRIVILEGED_INSTRUCTION 0x3
-#define CAUSE_FP_DISABLED 0x4
-#define CAUSE_SYSCALL 0x6
+#define CAUSE_SCALL 0x4
+#define CAUSE_HCALL 0x5
+#define CAUSE_MCALL 0x6
#define CAUSE_BREAKPOINT 0x7
#define CAUSE_MISALIGNED_LOAD 0x8
-#define CAUSE_MISALIGNED_STORE 0x9
-#define CAUSE_FAULT_LOAD 0xa
+#define CAUSE_FAULT_LOAD 0x9
+#define CAUSE_MISALIGNED_STORE 0xa
#define CAUSE_FAULT_STORE 0xb
-#define CAUSE_ACCELERATOR_DISABLED 0xc
#endif
#ifdef DECLARE_INSN
DECLARE_INSN(fmv_s_x, MATCH_FMV_S_X, MASK_FMV_S_X)
DECLARE_INSN(bltu, MATCH_BLTU, MASK_BLTU)
DECLARE_INSN(fsgnjn_d, MATCH_FSGNJN_D, MASK_FSGNJN_D)
DECLARE_INSN(fmin_s, MATCH_FMIN_S, MASK_FMIN_S)
+DECLARE_INSN(mret, MATCH_MRET, MASK_MRET)
DECLARE_INSN(csrrw, MATCH_CSRRW, MASK_CSRRW)
DECLARE_INSN(slliw, MATCH_SLLIW, MASK_SLLIW)
DECLARE_INSN(lb, MATCH_LB, MASK_LB)
DECLARE_INSN(blt, MATCH_BLT, MASK_BLT)
DECLARE_INSN(scall, MATCH_SCALL, MASK_SCALL)
DECLARE_INSN(fclass_s, MATCH_FCLASS_S, MASK_FCLASS_S)
+DECLARE_INSN(sfence_vm, MATCH_SFENCE_VM, MASK_SFENCE_VM)
DECLARE_INSN(sc_w, MATCH_SC_W, MASK_SC_W)
DECLARE_INSN(rem, MATCH_REM, MASK_REM)
DECLARE_INSN(srliw, MATCH_SRLIW, MASK_SRLIW)
DECLARE_INSN(addi, MATCH_ADDI, MASK_ADDI)
DECLARE_INSN(mulh, MATCH_MULH, MASK_MULH)
DECLARE_INSN(fmul_s, MATCH_FMUL_S, MASK_FMUL_S)
+DECLARE_INSN(mcall, MATCH_MCALL, MASK_MCALL)
DECLARE_INSN(csrrsi, MATCH_CSRRSI, MASK_CSRRSI)
DECLARE_INSN(srai, MATCH_SRAI, MASK_SRAI)
DECLARE_INSN(amoand_d, MATCH_AMOAND_D, MASK_AMOAND_D)
DECLARE_INSN(srl, MATCH_SRL, MASK_SRL)
DECLARE_INSN(fsub_d, MATCH_FSUB_D, MASK_FSUB_D)
DECLARE_INSN(fsgnjx_s, MATCH_FSGNJX_S, MASK_FSGNJX_S)
+DECLARE_INSN(mrts, MATCH_MRTS, MASK_MRTS)
DECLARE_INSN(feq_d, MATCH_FEQ_D, MASK_FEQ_D)
DECLARE_INSN(fcvt_d_wu, MATCH_FCVT_D_WU, MASK_FCVT_D_WU)
DECLARE_INSN(or, MATCH_OR, MASK_OR)
DECLARE_CSR(fflags, CSR_FFLAGS)
DECLARE_CSR(frm, CSR_FRM)
DECLARE_CSR(fcsr, CSR_FCSR)
-DECLARE_CSR(stats, CSR_STATS)
-DECLARE_CSR(sup0, CSR_SUP0)
-DECLARE_CSR(sup1, CSR_SUP1)
-DECLARE_CSR(epc, CSR_EPC)
-DECLARE_CSR(badvaddr, CSR_BADVADDR)
-DECLARE_CSR(ptbr, CSR_PTBR)
-DECLARE_CSR(asid, CSR_ASID)
-DECLARE_CSR(count, CSR_COUNT)
-DECLARE_CSR(compare, CSR_COMPARE)
-DECLARE_CSR(evec, CSR_EVEC)
-DECLARE_CSR(cause, CSR_CAUSE)
-DECLARE_CSR(status, CSR_STATUS)
-DECLARE_CSR(hartid, CSR_HARTID)
-DECLARE_CSR(impl, CSR_IMPL)
-DECLARE_CSR(fatc, CSR_FATC)
-DECLARE_CSR(send_ipi, CSR_SEND_IPI)
-DECLARE_CSR(clear_ipi, CSR_CLEAR_IPI)
-DECLARE_CSR(reset, CSR_RESET)
-DECLARE_CSR(tohost, CSR_TOHOST)
-DECLARE_CSR(fromhost, CSR_FROMHOST)
DECLARE_CSR(cycle, CSR_CYCLE)
DECLARE_CSR(time, CSR_TIME)
DECLARE_CSR(instret, CSR_INSTRET)
+DECLARE_CSR(stats, CSR_STATS)
DECLARE_CSR(uarch0, CSR_UARCH0)
DECLARE_CSR(uarch1, CSR_UARCH1)
DECLARE_CSR(uarch2, CSR_UARCH2)
DECLARE_CSR(uarch13, CSR_UARCH13)
DECLARE_CSR(uarch14, CSR_UARCH14)
DECLARE_CSR(uarch15, CSR_UARCH15)
-DECLARE_CSR(counth, CSR_COUNTH)
+DECLARE_CSR(sstatus, CSR_SSTATUS)
+DECLARE_CSR(stvec, CSR_STVEC)
+DECLARE_CSR(stimecmp, CSR_STIMECMP)
+DECLARE_CSR(sscratch, CSR_SSCRATCH)
+DECLARE_CSR(sepc, CSR_SEPC)
+DECLARE_CSR(sptbr, CSR_SPTBR)
+DECLARE_CSR(sasid, CSR_SASID)
+DECLARE_CSR(scycle, CSR_SCYCLE)
+DECLARE_CSR(stime, CSR_STIME)
+DECLARE_CSR(sinstret, CSR_SINSTRET)
+DECLARE_CSR(scause, CSR_SCAUSE)
+DECLARE_CSR(sbadaddr, CSR_SBADADDR)
+DECLARE_CSR(mstatus, CSR_MSTATUS)
+DECLARE_CSR(mscratch, CSR_MSCRATCH)
+DECLARE_CSR(mepc, CSR_MEPC)
+DECLARE_CSR(mcause, CSR_MCAUSE)
+DECLARE_CSR(mbadaddr, CSR_MBADADDR)
+DECLARE_CSR(reset, CSR_RESET)
+DECLARE_CSR(tohost, CSR_TOHOST)
+DECLARE_CSR(fromhost, CSR_FROMHOST)
+DECLARE_CSR(send_ipi, CSR_SEND_IPI)
+DECLARE_CSR(hartid, CSR_HARTID)
DECLARE_CSR(cycleh, CSR_CYCLEH)
DECLARE_CSR(timeh, CSR_TIMEH)
DECLARE_CSR(instreth, CSR_INSTRETH)
+DECLARE_CSR(scycleh, CSR_SCYCLEH)
+DECLARE_CSR(stimeh, CSR_STIMEH)
+DECLARE_CSR(sinstreth, CSR_SINSTRETH)
#endif
#ifdef DECLARE_CAUSE
DECLARE_CAUSE("fflags", CAUSE_FFLAGS)
DECLARE_CAUSE("frm", CAUSE_FRM)
DECLARE_CAUSE("fcsr", CAUSE_FCSR)
-DECLARE_CAUSE("stats", CAUSE_STATS)
-DECLARE_CAUSE("sup0", CAUSE_SUP0)
-DECLARE_CAUSE("sup1", CAUSE_SUP1)
-DECLARE_CAUSE("epc", CAUSE_EPC)
-DECLARE_CAUSE("badvaddr", CAUSE_BADVADDR)
-DECLARE_CAUSE("ptbr", CAUSE_PTBR)
-DECLARE_CAUSE("asid", CAUSE_ASID)
-DECLARE_CAUSE("count", CAUSE_COUNT)
-DECLARE_CAUSE("compare", CAUSE_COMPARE)
-DECLARE_CAUSE("evec", CAUSE_EVEC)
-DECLARE_CAUSE("cause", CAUSE_CAUSE)
-DECLARE_CAUSE("status", CAUSE_STATUS)
-DECLARE_CAUSE("hartid", CAUSE_HARTID)
-DECLARE_CAUSE("impl", CAUSE_IMPL)
-DECLARE_CAUSE("fatc", CAUSE_FATC)
-DECLARE_CAUSE("send_ipi", CAUSE_SEND_IPI)
-DECLARE_CAUSE("clear_ipi", CAUSE_CLEAR_IPI)
-DECLARE_CAUSE("reset", CAUSE_RESET)
-DECLARE_CAUSE("tohost", CAUSE_TOHOST)
-DECLARE_CAUSE("fromhost", CAUSE_FROMHOST)
DECLARE_CAUSE("cycle", CAUSE_CYCLE)
DECLARE_CAUSE("time", CAUSE_TIME)
DECLARE_CAUSE("instret", CAUSE_INSTRET)
+DECLARE_CAUSE("stats", CAUSE_STATS)
DECLARE_CAUSE("uarch0", CAUSE_UARCH0)
DECLARE_CAUSE("uarch1", CAUSE_UARCH1)
DECLARE_CAUSE("uarch2", CAUSE_UARCH2)
DECLARE_CAUSE("uarch13", CAUSE_UARCH13)
DECLARE_CAUSE("uarch14", CAUSE_UARCH14)
DECLARE_CAUSE("uarch15", CAUSE_UARCH15)
-DECLARE_CAUSE("counth", CAUSE_COUNTH)
+DECLARE_CAUSE("sstatus", CAUSE_SSTATUS)
+DECLARE_CAUSE("stvec", CAUSE_STVEC)
+DECLARE_CAUSE("stimecmp", CAUSE_STIMECMP)
+DECLARE_CAUSE("sscratch", CAUSE_SSCRATCH)
+DECLARE_CAUSE("sepc", CAUSE_SEPC)
+DECLARE_CAUSE("sptbr", CAUSE_SPTBR)
+DECLARE_CAUSE("sasid", CAUSE_SASID)
+DECLARE_CAUSE("scycle", CAUSE_SCYCLE)
+DECLARE_CAUSE("stime", CAUSE_STIME)
+DECLARE_CAUSE("sinstret", CAUSE_SINSTRET)
+DECLARE_CAUSE("scause", CAUSE_SCAUSE)
+DECLARE_CAUSE("sbadaddr", CAUSE_SBADADDR)
+DECLARE_CAUSE("mstatus", CAUSE_MSTATUS)
+DECLARE_CAUSE("mscratch", CAUSE_MSCRATCH)
+DECLARE_CAUSE("mepc", CAUSE_MEPC)
+DECLARE_CAUSE("mcause", CAUSE_MCAUSE)
+DECLARE_CAUSE("mbadaddr", CAUSE_MBADADDR)
+DECLARE_CAUSE("reset", CAUSE_RESET)
+DECLARE_CAUSE("tohost", CAUSE_TOHOST)
+DECLARE_CAUSE("fromhost", CAUSE_FROMHOST)
+DECLARE_CAUSE("send_ipi", CAUSE_SEND_IPI)
+DECLARE_CAUSE("hartid", CAUSE_HARTID)
DECLARE_CAUSE("cycleh", CAUSE_CYCLEH)
DECLARE_CAUSE("timeh", CAUSE_TIMEH)
DECLARE_CAUSE("instreth", CAUSE_INSTRETH)
+DECLARE_CAUSE("scycleh", CAUSE_SCYCLEH)
+DECLARE_CAUSE("stimeh", CAUSE_STIMEH)
+DECLARE_CAUSE("sinstreth", CAUSE_SINSTRETH)
#endif
void extension_t::raise_interrupt()
{
- p->set_interrupt(IRQ_COP, true);
- p->take_interrupt();
+ p->raise_interrupt(IRQ_COP);
}
void extension_t::clear_interrupt()
{
- p->set_interrupt(IRQ_COP, false);
}
if (write)
memcpy(&new_val, p.get_payload(), sizeof(new_val));
- // TODO mapping HTIF regno to CSR[4:0] is arbitrary; consider alternative
switch (regno)
{
- case CSR_HARTID & 0x1f:
- old_val = coreid;
- break;
- case CSR_TOHOST & 0x1f:
+ case CSR_TOHOST:
old_val = proc->get_state()->tohost;
if (write)
proc->get_state()->tohost = new_val;
break;
- case CSR_FROMHOST & 0x1f:
+ case CSR_FROMHOST:
old_val = proc->get_state()->fromhost;
if (write && old_val == 0)
- proc->set_fromhost(new_val);
+ proc->get_state()->fromhost = new_val;
break;
- case CSR_RESET & 0x1f:
+ case CSR_RESET:
old_val = !proc->running();
if (write)
{
-require_xpr64;
+require_rv64;
WRITE_RD(sext32(insn.i_imm() + RS1));
-require_xpr64;
+require_rv64;
WRITE_RD(sext32(RS1 + RS2));
-require_xpr64;
+require_rv64;
reg_t v = MMU.load_uint64(RS1);
MMU.store_uint64(RS1, RS2 + v);
WRITE_RD(v);
-require_xpr64;
+require_rv64;
reg_t v = MMU.load_uint64(RS1);
MMU.store_uint64(RS1, RS2 & v);
WRITE_RD(v);
-require_xpr64;
+require_rv64;
sreg_t v = MMU.load_int64(RS1);
MMU.store_uint64(RS1, std::max(sreg_t(RS2),v));
WRITE_RD(v);
-require_xpr64;
+require_rv64;
reg_t v = MMU.load_uint64(RS1);
MMU.store_uint64(RS1, std::max(RS2,v));
WRITE_RD(v);
-require_xpr64;
+require_rv64;
sreg_t v = MMU.load_int64(RS1);
MMU.store_uint64(RS1, std::min(sreg_t(RS2),v));
WRITE_RD(v);
-require_xpr64;
+require_rv64;
reg_t v = MMU.load_uint64(RS1);
MMU.store_uint64(RS1, std::min(RS2,v));
WRITE_RD(v);
-require_xpr64;
+require_rv64;
reg_t v = MMU.load_uint64(RS1);
MMU.store_uint64(RS1, RS2 | v);
WRITE_RD(v);
-require_xpr64;
+require_rv64;
reg_t v = MMU.load_uint64(RS1);
MMU.store_uint64(RS1, RS2);
WRITE_RD(v);
-require_xpr64;
+require_rv64;
reg_t v = MMU.load_uint64(RS1);
MMU.store_uint64(RS1, RS2 ^ v);
WRITE_RD(v);
int csr = validate_csr(insn.csr(), true);
-reg_t old = p->get_pcr(csr);
-p->set_pcr(csr, old & ~RS1);
+reg_t old = p->get_csr(csr);
+p->set_csr(csr, old & ~RS1);
WRITE_RD(sext_xlen(old));
int csr = validate_csr(insn.csr(), true);
-reg_t old = p->get_pcr(csr);
-p->set_pcr(csr, old & ~(reg_t)insn.rs1());
+reg_t old = p->get_csr(csr);
+p->set_csr(csr, old & ~(reg_t)insn.rs1());
WRITE_RD(sext_xlen(old));
int csr = validate_csr(insn.csr(), insn.rs1() != 0);
-reg_t old = p->get_pcr(csr);
-p->set_pcr(csr, old | RS1);
+reg_t old = p->get_csr(csr);
+p->set_csr(csr, old | RS1);
WRITE_RD(sext_xlen(old));
int csr = validate_csr(insn.csr(), true);
-reg_t old = p->get_pcr(csr);
-p->set_pcr(csr, old | insn.rs1());
+reg_t old = p->get_csr(csr);
+p->set_csr(csr, old | insn.rs1());
WRITE_RD(sext_xlen(old));
int csr = validate_csr(insn.csr(), true);
-reg_t old = p->get_pcr(csr);
-p->set_pcr(csr, RS1);
+reg_t old = p->get_csr(csr);
+p->set_csr(csr, RS1);
WRITE_RD(sext_xlen(old));
int csr = validate_csr(insn.csr(), true);
-reg_t old = p->get_pcr(csr);
-p->set_pcr(csr, insn.rs1());
+reg_t old = p->get_csr(csr);
+p->set_csr(csr, insn.rs1());
WRITE_RD(sext_xlen(old));
-require_xpr64;
+require_rv64;
reg_t lhs = zext32(RS1);
reg_t rhs = zext32(RS2);
if(rhs == 0)
-require_xpr64;
+require_rv64;
sreg_t lhs = sext32(RS1);
sreg_t rhs = sext32(RS2);
if(rhs == 0)
-require_xpr64;
+require_rv64;
require_fp;
softfloat_roundingMode = RM;
WRITE_FRD(i64_to_f64(RS1));
-require_xpr64;
+require_rv64;
require_fp;
softfloat_roundingMode = RM;
WRITE_FRD(ui64_to_f64(RS1));
-require_xpr64;
+require_rv64;
require_fp;
softfloat_roundingMode = RM;
WRITE_RD(f64_to_i64(FRS1, RM, true));
-require_xpr64;
+require_rv64;
require_fp;
softfloat_roundingMode = RM;
WRITE_RD(f32_to_i64(FRS1, RM, true));
-require_xpr64;
+require_rv64;
require_fp;
softfloat_roundingMode = RM;
WRITE_RD(f64_to_ui64(FRS1, RM, true));
-require_xpr64;
+require_rv64;
require_fp;
softfloat_roundingMode = RM;
WRITE_RD(f32_to_ui64(FRS1, RM, true));
-require_xpr64;
+require_rv64;
require_fp;
softfloat_roundingMode = RM;
WRITE_FRD(i64_to_f32(RS1));
-require_xpr64;
+require_rv64;
require_fp;
softfloat_roundingMode = RM;
WRITE_FRD(ui64_to_f32(RS1));
-require_xpr64;
+require_rv64;
require_fp;
WRITE_FRD(RS1);
-require_xpr64;
+require_rv64;
require_fp;
WRITE_RD(FRS1);
-require_xpr64;
+require_rv64;
WRITE_RD(MMU.load_int64(RS1 + insn.i_imm()));
-require_xpr64;
+require_rv64;
p->get_state()->load_reservation = RS1;
WRITE_RD(MMU.load_int64(RS1));
-require_xpr64;
+require_rv64;
WRITE_RD(MMU.load_uint32(RS1 + insn.i_imm()));
--- /dev/null
+require_privilege(PRV_S); // or PRV_H if implemented
+throw trap_mcall();
--- /dev/null
+require_privilege(PRV_M);
+p->pop_privilege_stack();
+set_pc(p->get_state()->mepc);
--- /dev/null
+require_privilege(PRV_M);
+p->set_csr(CSR_MSTATUS, set_field(STATE.mstatus, MSTATUS_PRV, PRV_S));
+STATE.sbadaddr = STATE.mbadaddr;
+STATE.scause = STATE.mcause;
+STATE.sepc = STATE.mepc;
+set_pc(STATE.stvec);
-if (xpr64)
+if (xlen == 64)
WRITE_RD(mulh(RS1, RS2));
else
WRITE_RD(sext32((sext32(RS1) * sext32(RS2)) >> 32));
-if (xpr64)
+if (xlen == 64)
WRITE_RD(mulhsu(RS1, RS2));
else
WRITE_RD(sext32((sext32(RS1) * reg_t((uint32_t)RS2)) >> 32));
-if (xpr64)
+if (xlen == 64)
WRITE_RD(mulhu(RS1, RS2));
else
WRITE_RD(sext32(((uint64_t)(uint32_t)RS1 * (uint64_t)(uint32_t)RS2) >> 32));
-require_xpr64;
+require_rv64;
WRITE_RD(sext32(RS1 * RS2));
-require_xpr64;
+require_rv64;
reg_t lhs = zext32(RS1);
reg_t rhs = zext32(RS2);
if(rhs == 0)
-require_xpr64;
+require_rv64;
sreg_t lhs = sext32(RS1);
sreg_t rhs = sext32(RS2);
if(rhs == 0)
-require_xpr64;
+require_rv64;
if (RS1 == p->get_state()->load_reservation)
{
MMU.store_uint64(RS1, RS2);
-throw trap_syscall();
+throw trap_scall();
-require_xpr64;
+require_rv64;
MMU.store_uint64(RS1 + insn.s_imm(), RS2);
--- /dev/null
+require_privilege(PRV_S);
+MMU.flush_tlb();
-if(xpr64)
+if (xlen == 64)
WRITE_RD(RS1 << SHAMT);
else
{
-require_xpr64;
+require_rv64;
WRITE_RD(sext32(RS1 << SHAMT));
-require_xpr64;
+require_rv64;
WRITE_RD(sext32(RS1 << (RS2 & 0x1F)));
-if(xpr64)
+if (xlen == 64)
WRITE_RD(sreg_t(RS1) >> SHAMT);
else
{
-require_xpr64;
+require_rv64;
WRITE_RD(sext32(int32_t(RS1) >> SHAMT));
-require_xpr64;
+require_rv64;
WRITE_RD(sext32(int32_t(RS1) >> (RS2 & 0x1F)));
-require_supervisor;
-p->set_pcr(CSR_STATUS, ((p->get_state()->sr & ~(SR_S | SR_EI)) |
- ((p->get_state()->sr & SR_PS) ? SR_S : 0)) |
- ((p->get_state()->sr & SR_PEI) ? SR_EI : 0));
-set_pc(p->get_state()->epc);
+require_privilege(PRV_S);
+p->pop_privilege_stack();
+set_pc(p->get_state()->sepc);
-if(xpr64)
+if (xlen == 64)
WRITE_RD(RS1 >> (RS2 & 0x3F));
else
WRITE_RD(sext32((uint32_t)RS1 >> (RS2 & 0x1F)));
-if(xpr64)
+if (xlen == 64)
WRITE_RD(RS1 >> SHAMT);
else
{
-require_xpr64;
+require_rv64;
WRITE_RD(sext32((uint32_t)RS1 >> SHAMT));
-require_xpr64;
+require_rv64;
WRITE_RD(sext32((uint32_t)RS1 >> (RS2 & 0x1F)));
-require_xpr64;
+require_rv64;
WRITE_RD(sext32(RS1 - RS2));
if(args.size() != 2)
throw trap_illegal_instruction();
- int p = atoi(args[0].c_str());
- int r = std::find(xpr_name, xpr_name + NXPR, args[1]) - xpr_name;
- if (r == NXPR)
- r = atoi(args[1].c_str());
- if(p >= (int)num_cores() || r >= NXPR)
+ char* ptr;
+ unsigned long p = strtoul(args[0].c_str(), &ptr, 10);
+ if (*ptr || p >= num_cores())
+ throw trap_illegal_instruction();
+
+ unsigned long r = std::find(xpr_name, xpr_name + NXPR, args[1]) - xpr_name;
+ if (r == NXPR) {
+ r = strtoul(args[1].c_str(), &ptr, 10);
+ if (*ptr) {
+ #define DECLARE_CSR(name, number) if (args[1] == #name) return procs[p]->get_csr(number);
+ if (0) ;
+ #include "encoding.h"
+ else r = NXPR;
+ #undef DECLARE_CSR
+ }
+ }
+
+ if (r >= NXPR)
throw trap_illegal_instruction();
return procs[p]->state.XPR[r];
reg_t idx = (addr >> PGSHIFT) % TLB_ENTRIES;
reg_t expected_tag = addr >> PGSHIFT;
- reg_t pte = walk(addr);
+ reg_t pte = 0;
+ reg_t mstatus = proc ? proc->state.mstatus : 0;
+
+ bool vm_disabled = get_field(mstatus, MSTATUS_VM) == VM_MBARE;
+ bool mode_m = get_field(mstatus, MSTATUS_PRV) == PRV_M;
+ bool mode_s = get_field(mstatus, MSTATUS_PRV) == PRV_S;
+ bool mprv_m = get_field(mstatus, MSTATUS_MPRV) == PRV_M;
+ bool mprv_s = get_field(mstatus, MSTATUS_MPRV) == PRV_S;
+
+ if (vm_disabled || (mode_m && (mprv_m || fetch))) {
+ // virtual memory is disabled. merely check legality of physical address.
+ if (addr < memsz) {
+ // produce a fake PTE for the TLB's benefit.
+ pte = PTE_V | PTE_UX | PTE_SX | ((addr >> PGSHIFT) << PGSHIFT);
+ if (vm_disabled || !(mode_m && !mprv_m))
+ pte |= PTE_UR | PTE_SR | PTE_UW | PTE_SW;
+ }
+ } else {
+ pte = walk(addr);
+ }
reg_t pte_perm = pte & PTE_PERM;
- if (proc == NULL || (proc->state.sr & SR_S))
+ if (mode_s || (mode_m && mprv_s && !fetch))
pte_perm = (pte_perm/(PTE_SX/PTE_UX)) & PTE_PERM;
pte_perm |= pte & PTE_V;
pte_t mmu_t::walk(reg_t addr)
{
- pte_t pte = 0;
-
- // the address must be a canonical sign-extended VA_BITS-bit number
- int shift = 8*sizeof(reg_t) - VA_BITS;
- if (((sreg_t)addr << shift >> shift) != (sreg_t)addr)
- ;
- else if (proc == NULL || !(proc->state.sr & SR_VM))
- {
- if(addr < memsz)
- pte = PTE_V | PTE_PERM | ((addr >> PGSHIFT) << PGSHIFT);
- }
- else
- {
- reg_t base = proc->get_state()->ptbr;
- reg_t ptd;
-
- int ptshift = (LEVELS-1)*PTIDXBITS;
- for(reg_t i = 0; i < LEVELS; i++, ptshift -= PTIDXBITS)
- {
- reg_t idx = (addr >> (PGSHIFT+ptshift)) & ((1<<PTIDXBITS)-1);
-
- reg_t pte_addr = base + idx*sizeof(pte_t);
- if(pte_addr >= memsz)
- break;
-
- ptd = *(pte_t*)(mem+pte_addr);
-
- if (!(ptd & PTE_V)) // invalid mapping
- break;
- else if (ptd & PTE_T) // next level of page table
- base = (ptd >> PGSHIFT) << PGSHIFT;
- else // the actual PTE
- {
- // if this PTE is from a larger PT, fake a leaf
- // PTE so the TLB will work right
- reg_t vpn = addr >> PGSHIFT;
- ptd |= (vpn & ((1<<(ptshift))-1)) << PGSHIFT;
-
- // fault if physical addr is out of range
- if (((ptd >> PGSHIFT) << PGSHIFT) < memsz)
- pte = ptd;
- break;
- }
+ reg_t msb_mask = -(reg_t(1) << (VA_BITS-1));
+ if ((addr & msb_mask) != 0 && (addr & msb_mask) != msb_mask)
+ return 0; // address isn't properly sign-extended
+
+ reg_t base = proc->get_state()->sptbr;
+ reg_t ptd;
+
+ int ptshift = (LEVELS-1)*PTIDXBITS;
+ for (reg_t i = 0; i < LEVELS; i++, ptshift -= PTIDXBITS) {
+ reg_t idx = (addr >> (PGSHIFT+ptshift)) & ((1<<PTIDXBITS)-1);
+
+ // check that physical address of PTE is legal
+ reg_t pte_addr = base + idx*sizeof(pte_t);
+ if (pte_addr >= memsz)
+ return 0;
+
+ ptd = *(pte_t*)(mem+pte_addr);
+
+ if (!(ptd & PTE_V)) { // invalid mapping
+ return 0;
+ } else if (ptd & PTE_T) { // next level of page table
+ base = (ptd >> PGSHIFT) << PGSHIFT;
+ } else {
+ // we've found the PTE.
+ // for superpage mappings, make a fake leaf PTE for the TLB's benefit.
+ reg_t vpn = addr >> PGSHIFT;
+ ptd |= (vpn & ((1<<(ptshift))-1)) << PGSHIFT;
+
+ // check that physical address is legal
+ if (((ptd >> PGSHIFT) << PGSHIFT) >= memsz)
+ return 0;
+
+ return ptd;
}
}
-
- return pte;
+ return 0;
}
void mmu_t::register_memtracer(memtracer_t* t)
void state_t::reset()
{
- // the ISA guarantees on boot that the PC is 0x2000 and the the processor
- // is in supervisor mode, and in 64-bit mode, if supported, with traps
- // and virtual memory disabled.
- sr = SR_S | SR_S64 | SR_U64;
- pc = 0x2000;
-
- // the following state is undefined upon boot-up,
- // but we zero it for determinism
- XPR.reset();
- FPR.reset();
-
- epc = 0;
- badvaddr = 0;
- evec = 0;
- ptbr = 0;
- pcr_k0 = 0;
- pcr_k1 = 0;
- cause = 0;
- tohost = 0;
- fromhost = 0;
- count = 0;
- compare = 0;
- fflags = 0;
- frm = 0;
-
+ memset(this, 0, sizeof(*this));
+ mstatus = set_field(mstatus, MSTATUS_PRV, PRV_M);
+ mstatus = set_field(mstatus, MSTATUS_PRV1, PRV_S);
+ mstatus = set_field(mstatus, MSTATUS_PRV2, PRV_S);
+#ifdef RISCV_ENABLE_64BIT
+ mstatus = set_field(mstatus, MSTATUS64_UA, UA_RV64);
+ mstatus = set_field(mstatus, MSTATUS64_SA, UA_RV64);
+#endif
+ pc = 0x100;
load_reservation = -1;
}
run = !value;
state.reset(); // reset the core
- set_pcr(CSR_STATUS, state.sr);
+ set_csr(CSR_MSTATUS, state.mstatus);
if (ext)
ext->reset(); // reset the extension
serialized = true, throw serialize_t();
}
+void processor_t::raise_interrupt(reg_t which)
+{
+ throw trap_t(((reg_t)1 << 63) | which);
+}
+
void processor_t::take_interrupt()
{
- int irqs = ((state.sr & SR_IP) >> SR_IP_SHIFT) & (state.sr >> SR_IM_SHIFT);
- if (likely(!irqs) || likely(!(state.sr & SR_EI)))
- return;
+ int priv = get_field(state.mstatus, MSTATUS_PRV);
+ int ie = get_field(state.mstatus, MSTATUS_IE);
+
+ if (priv < PRV_M || (priv == PRV_M && ie)) {
+ if (get_field(state.mstatus, MSTATUS_MSIP))
+ raise_interrupt(IRQ_IPI);
+
+ if (state.fromhost != 0)
+ raise_interrupt(IRQ_HOST);
+ }
+
+ if (priv < PRV_S || (priv == PRV_S && ie)) {
+ if (get_field(state.mstatus, MSTATUS_SSIP))
+ raise_interrupt(IRQ_IPI);
- for (int i = 0; ; i++)
- if ((irqs >> i) & 1)
- throw trap_t((1ULL << ((state.sr & SR_S64) ? 63 : 31)) + i);
+ if (state.stip && get_field(state.mstatus, MSTATUS_STIE))
+ raise_interrupt(IRQ_TIMER);
+ }
}
static void commit_log(state_t* state, reg_t pc, insn_t insn)
{
#ifdef RISCV_ENABLE_COMMITLOG
- if (state->sr & SR_EI) {
+ if (get_field(state->mstatus, MSTATUS_IE)) {
uint64_t mask = (insn.length() == 8 ? uint64_t(0) : (uint64_t(1) << (insn.length() * 8))) - 1;
if (state->log_reg_write.addr) {
fprintf(stderr, "0x%016" PRIx64 " (0x%08" PRIx64 ") %c%2" PRIu64 " 0x%016" PRIx64 "\n",
static void update_timer(state_t* state, size_t instret)
{
- uint64_t count0 = (uint64_t)(uint32_t)state->count;
- state->count += instret;
- uint64_t before = count0 - state->compare;
+ uint64_t count0 = (uint64_t)(uint32_t)state->scount;
+ state->scount += instret;
+ uint64_t before = count0 - state->stimecmp;
if (int64_t(before ^ (before + instret)) < 0)
- state->sr |= (1 << (IRQ_TIMER + SR_IP_SHIFT));
+ state->stip = true;
}
static size_t next_timer(state_t* state)
{
- return state->compare - (uint32_t)state->count;
+ return state->stimecmp - (uint32_t)state->scount;
}
void processor_t::step(size_t n)
update_timer(&state, instret);
}
+void processor_t::push_privilege_stack()
+{
+ reg_t s = state.mstatus;
+ s = set_field(s, MSTATUS_PRV2, get_field(state.mstatus, MSTATUS_PRV1));
+ s = set_field(s, MSTATUS_IE2, get_field(state.mstatus, MSTATUS_IE1));
+ s = set_field(s, MSTATUS_PRV1, get_field(state.mstatus, MSTATUS_PRV));
+ s = set_field(s, MSTATUS_IE1, get_field(state.mstatus, MSTATUS_IE));
+ s = set_field(s, MSTATUS_PRV, PRV_M);
+ s = set_field(s, MSTATUS_MPRV, PRV_M);
+ s = set_field(s, MSTATUS_IE, 0);
+ set_csr(CSR_MSTATUS, s);
+}
+
+void processor_t::pop_privilege_stack()
+{
+ reg_t s = state.mstatus;
+ s = set_field(s, MSTATUS_PRV, get_field(state.mstatus, MSTATUS_PRV1));
+ s = set_field(s, MSTATUS_IE, get_field(state.mstatus, MSTATUS_IE1));
+ s = set_field(s, MSTATUS_PRV1, get_field(state.mstatus, MSTATUS_PRV2));
+ s = set_field(s, MSTATUS_IE1, get_field(state.mstatus, MSTATUS_IE2));
+ s = set_field(s, MSTATUS_PRV2, PRV_U);
+ s = set_field(s, MSTATUS_IE2, 1);
+ set_csr(CSR_MSTATUS, s);
+}
+
reg_t processor_t::take_trap(trap_t& t, reg_t epc)
{
if (debug)
fprintf(stderr, "core %3d: exception %s, epc 0x%016" PRIx64 "\n",
id, t.name(), epc);
- // switch to supervisor, set previous supervisor bit, disable interrupts
- set_pcr(CSR_STATUS, (((state.sr & ~SR_EI) | SR_S) & ~SR_PS & ~SR_PEI) |
- ((state.sr & SR_S) ? SR_PS : 0) |
- ((state.sr & SR_EI) ? SR_PEI : 0));
-
+ reg_t tvec = 0x40 * get_field(state.mstatus, MSTATUS_PRV);
+ push_privilege_stack();
yield_load_reservation();
- state.cause = t.cause();
- state.epc = epc;
+ state.mcause = t.cause();
+ state.mepc = epc;
t.side_effects(&state); // might set badvaddr etc.
- return state.evec;
+ return tvec;
}
void processor_t::deliver_ipi()
{
- if (run)
- set_pcr(CSR_CLEAR_IPI, 1);
+ state.mstatus |= MSTATUS_MSIP;
}
void processor_t::disasm(insn_t insn)
id, state.pc, bits, disassembler->disassemble(insn).c_str());
}
-void processor_t::set_pcr(int which, reg_t val)
+static bool validate_priv(reg_t priv)
+{
+ return priv == PRV_U || priv == PRV_S || priv == PRV_M;
+}
+
+static bool validate_arch(reg_t arch)
+{
+#ifdef RISCV_ENABLE_64BIT
+ if (arch == UA_RV64) return true;
+#endif
+ return arch == UA_RV32;
+}
+
+static bool validate_vm(reg_t vm)
+{
+ // TODO: VM_SV32 support
+#ifdef RISCV_ENABLE_64BIT
+ if (vm == VM_SV43) return true;
+#endif
+ return vm == VM_MBARE;
+}
+
+void processor_t::set_csr(int which, reg_t val)
{
switch (which)
{
case CSR_FFLAGS:
+ dirty_fp_state;
state.fflags = val & (FSR_AEXC >> FSR_AEXC_SHIFT);
break;
case CSR_FRM:
+ dirty_fp_state;
state.frm = val & (FSR_RD >> FSR_RD_SHIFT);
break;
case CSR_FCSR:
+ dirty_fp_state;
state.fflags = (val & FSR_AEXC) >> FSR_AEXC_SHIFT;
state.frm = (val & FSR_RD) >> FSR_RD_SHIFT;
break;
- case CSR_STATUS:
- state.sr = (val & ~SR_IP) | (state.sr & SR_IP);
-#ifndef RISCV_ENABLE_64BIT
- state.sr &= ~(SR_S64 | SR_U64);
+ case CSR_SCYCLE:
+ case CSR_STIME:
+ case CSR_SINSTRET:
+ state.scount = val; break;
+ case CSR_SCYCLEH:
+ case CSR_STIMEH:
+ case CSR_SINSTRETH:
+ state.scount = (val << 32) | (uint32_t)state.scount;
+ break;
+ case CSR_MSTATUS:
+ {
+ if ((val ^ state.mstatus) & (MSTATUS_VM | MSTATUS_PRV | MSTATUS_MPRV))
+ mmu->flush_tlb();
+
+ reg_t mask = MSTATUS_SSIP | MSTATUS_MSIP | MSTATUS_IE | MSTATUS_IE1
+ | MSTATUS_IE2 | MSTATUS_IE3 | MSTATUS_STIE;
+#ifdef RISCV_ENABLE_FPU
+ mask |= MSTATUS_FS;
#endif
-#ifndef RISCV_ENABLE_FPU
- state.sr &= ~SR_EF;
+ if (ext)
+ mask |= MSTATUS_XS;
+ state.mstatus = (state.mstatus & ~mask) | (val & mask);
+
+ if (validate_vm(get_field(val, MSTATUS_VM)))
+ state.mstatus = (state.mstatus & ~MSTATUS_VM) | (val & MSTATUS_VM);
+ if (validate_priv(get_field(val, MSTATUS_MPRV)))
+ state.mstatus = (state.mstatus & ~MSTATUS_MPRV) | (val & MSTATUS_MPRV);
+ if (validate_priv(get_field(val, MSTATUS_PRV)))
+ state.mstatus = (state.mstatus & ~MSTATUS_PRV) | (val & MSTATUS_PRV);
+ if (validate_priv(get_field(val, MSTATUS_PRV1)))
+ state.mstatus = (state.mstatus & ~MSTATUS_PRV1) | (val & MSTATUS_PRV1);
+ if (validate_priv(get_field(val, MSTATUS_PRV2)))
+ state.mstatus = (state.mstatus & ~MSTATUS_PRV2) | (val & MSTATUS_PRV2);
+ if (validate_priv(get_field(val, MSTATUS_PRV3)))
+ state.mstatus = (state.mstatus & ~MSTATUS_PRV3) | (val & MSTATUS_PRV3);
+ xlen = 32;
+
+ bool dirty = (state.mstatus & MSTATUS_FS) == MSTATUS_FS;
+ dirty |= (state.mstatus & MSTATUS_XS) == MSTATUS_XS;
+#ifndef RISCV_ENABLE_64BIT
+ state.mstatus = set_field(state.mstatus, MSTATUS32_SD, dirty);
+#else
+ state.mstatus = set_field(state.mstatus, MSTATUS64_SD, dirty);
+
+ if (validate_arch(get_field(val, MSTATUS64_UA)))
+ state.mstatus = (state.mstatus & ~MSTATUS64_UA) | (val & MSTATUS64_UA);
+ if (validate_arch(get_field(val, MSTATUS64_SA)))
+ state.mstatus = (state.mstatus & ~MSTATUS64_SA) | (val & MSTATUS64_SA);
+ switch (get_field(state.mstatus, MSTATUS_PRV)) {
+ case PRV_U: if (get_field(state.mstatus, MSTATUS64_UA)) xlen = 64; break;
+ case PRV_S: if (get_field(state.mstatus, MSTATUS64_SA)) xlen = 64; break;
+ case PRV_M: xlen = 64; break;
+ default: abort();
+ }
#endif
- if (!ext)
- state.sr &= ~SR_EA;
- state.sr &= ~SR_ZERO;
- rv64 = (state.sr & SR_S) ? (state.sr & SR_S64) : (state.sr & SR_U64);
- mmu->flush_tlb();
- break;
- case CSR_EPC:
- state.epc = val;
- break;
- case CSR_EVEC:
- state.evec = val & ~3;
- break;
- case CSR_COUNT:
- state.count = val;
- break;
- case CSR_COUNTH:
- state.count = (val << 32) | (uint32_t)state.count;
break;
- case CSR_COMPARE:
+ }
+ case CSR_SSTATUS:
+ {
+ reg_t ms = state.mstatus;
+ ms = set_field(ms, MSTATUS_SSIP, get_field(val, SSTATUS_SIP));
+ ms = set_field(ms, MSTATUS_IE, get_field(val, SSTATUS_IE));
+ ms = set_field(ms, MSTATUS_IE1, get_field(val, SSTATUS_PIE));
+ ms = set_field(ms, MSTATUS_PRV1, get_field(val, SSTATUS_PS));
+ ms = set_field(ms, MSTATUS64_UA, get_field(val, SSTATUS_UA));
+ ms = set_field(ms, MSTATUS_STIE, get_field(val, SSTATUS_TIE));
+ ms = set_field(ms, MSTATUS_FS, get_field(val, SSTATUS_FS));
+ ms = set_field(ms, MSTATUS_XS, get_field(val, SSTATUS_XS));
+ return set_csr(CSR_MSTATUS, ms);
+ }
+ case CSR_SEPC: state.sepc = val; break;
+ case CSR_STVEC: state.stvec = val & ~3; break;
+ case CSR_STIMECMP:
serialize();
- set_interrupt(IRQ_TIMER, false);
- state.compare = val;
- break;
- case CSR_PTBR:
- state.ptbr = val & ~(PGSIZE-1);
- break;
- case CSR_SEND_IPI:
- sim->send_ipi(val);
- break;
- case CSR_CLEAR_IPI:
- set_interrupt(IRQ_IPI, val & 1);
- break;
- case CSR_SUP0:
- state.pcr_k0 = val;
- break;
- case CSR_SUP1:
- state.pcr_k1 = val;
+ state.stip = false;
+ state.stimecmp = val;
break;
+ case CSR_SPTBR: state.sptbr = val & ~(PGSIZE-1); break;
+ case CSR_SSCRATCH: state.sscratch = val; break;
+ case CSR_MEPC: state.mepc = val; break;
+ case CSR_MSCRATCH: state.mscratch = val; break;
+ case CSR_MCAUSE: state.mcause = val; break;
+ case CSR_SEND_IPI: sim->send_ipi(val); break;
case CSR_TOHOST:
if (state.tohost == 0)
state.tohost = val;
break;
- case CSR_FROMHOST:
- set_fromhost(val);
- break;
+ case CSR_FROMHOST: state.fromhost = val; break;
}
}
-void processor_t::set_fromhost(reg_t val)
-{
- set_interrupt(IRQ_HOST, val != 0);
- state.fromhost = val;
-}
-
-reg_t processor_t::get_pcr(int which)
+reg_t processor_t::get_csr(int which)
{
switch (which)
{
case CSR_FCSR:
require_fp;
return (state.fflags << FSR_AEXC_SHIFT) | (state.frm << FSR_RD_SHIFT);
- case CSR_STATUS:
- return state.sr;
- case CSR_EPC:
- return state.epc;
- case CSR_BADVADDR:
- return state.badvaddr;
- case CSR_EVEC:
- return state.evec;
case CSR_CYCLE:
case CSR_TIME:
case CSR_INSTRET:
- case CSR_COUNT:
+ case CSR_SCYCLE:
+ case CSR_STIME:
+ case CSR_SINSTRET:
serialize();
- return state.count;
+ return state.scount;
case CSR_CYCLEH:
case CSR_TIMEH:
case CSR_INSTRETH:
- case CSR_COUNTH:
- if (rv64)
+ case CSR_SCYCLEH:
+ case CSR_STIMEH:
+ case CSR_SINSTRETH:
+ if (xlen == 64)
break;
serialize();
- return state.count >> 32;
- case CSR_COMPARE:
- return state.compare;
- case CSR_CAUSE:
- return state.cause;
- case CSR_PTBR:
- return state.ptbr;
- case CSR_SEND_IPI:
- case CSR_CLEAR_IPI:
- return 0;
- case CSR_ASID:
- return 0;
- case CSR_FATC:
- mmu->flush_tlb();
- return 0;
- case CSR_HARTID:
- return id;
- case CSR_IMPL:
- return 1;
- case CSR_SUP0:
- return state.pcr_k0;
- case CSR_SUP1:
- return state.pcr_k1;
+ return state.scount >> 32;
+ case CSR_SSTATUS:
+ {
+ reg_t ss = 0;
+ ss = set_field(ss, SSTATUS_SIP, get_field(state.mstatus, MSTATUS_SSIP));
+ ss = set_field(ss, SSTATUS_IE, get_field(state.mstatus, MSTATUS_IE));
+ ss = set_field(ss, SSTATUS_PIE, get_field(state.mstatus, MSTATUS_IE1));
+ ss = set_field(ss, SSTATUS_PS, get_field(state.mstatus, MSTATUS_PRV1));
+ ss = set_field(ss, SSTATUS_UA, get_field(state.mstatus, MSTATUS64_UA));
+ ss = set_field(ss, SSTATUS_TIE, get_field(state.mstatus, MSTATUS_STIE));
+ ss = set_field(ss, SSTATUS_TIP, state.stip);
+ ss = set_field(ss, SSTATUS_FS, get_field(state.mstatus, MSTATUS_FS));
+ ss = set_field(ss, SSTATUS_XS, get_field(state.mstatus, MSTATUS_XS));
+ if (get_field(state.mstatus, MSTATUS64_SD))
+ ss = set_field(ss, (xlen == 32 ? SSTATUS32_SD : SSTATUS64_SD), 1);
+ return ss;
+ }
+ case CSR_SEPC: return state.sepc;
+ case CSR_SBADADDR: return state.sbadaddr;
+ case CSR_STVEC: return state.stvec;
+ case CSR_STIMECMP: return state.stimecmp;
+ case CSR_SCAUSE:
+ if (xlen == 32 && (state.scause >> 63) != 0)
+ return state.scause | ((reg_t)1 << 31);
+ return state.scause;
+ case CSR_SPTBR: return state.sptbr;
+ case CSR_SASID: return 0;
+ case CSR_SSCRATCH: return state.sscratch;
+ case CSR_MSTATUS: return state.mstatus;
+ case CSR_MEPC: return state.mepc;
+ case CSR_MSCRATCH: return state.mscratch;
+ case CSR_MCAUSE: return state.mcause;
+ case CSR_MBADADDR: return state.mbadaddr;
case CSR_TOHOST:
sim->get_htif()->tick(); // not necessary, but faster
return state.tohost;
case CSR_FROMHOST:
sim->get_htif()->tick(); // not necessary, but faster
return state.fromhost;
+ case CSR_SEND_IPI: return 0;
+ case CSR_HARTID: return id;
case CSR_UARCH0:
case CSR_UARCH1:
case CSR_UARCH2:
throw trap_illegal_instruction();
}
-void processor_t::set_interrupt(int which, bool on)
-{
- uint32_t mask = (1 << (which + SR_IP_SHIFT)) & SR_IP;
- if (on)
- state.sr |= mask;
- else
- state.sr &= ~mask;
-}
-
reg_t illegal_instruction(processor_t* p, insn_t insn, reg_t pc)
{
throw trap_illegal_instruction();
while ((insn.bits() & desc->mask) != desc->match)
desc++;
- return rv64 ? desc->rv64 : desc->rv32;
+ return xlen == 64 ? desc->rv64 : desc->rv32;
}
void processor_t::register_insn(insn_desc_t desc)
regfile_t<freg_t, NFPR, false> FPR;
// control and status registers
- reg_t epc;
- reg_t badvaddr;
- reg_t evec;
- reg_t ptbr;
- reg_t pcr_k0;
- reg_t pcr_k1;
- reg_t cause;
+ reg_t mstatus;
+ reg_t mepc;
+ reg_t mbadaddr;
+ reg_t mscratch;
+ reg_t mcause;
+ reg_t sepc;
+ reg_t sbadaddr;
+ reg_t sscratch;
+ reg_t stvec;
+ reg_t sptbr;
+ reg_t scause;
reg_t tohost;
reg_t fromhost;
- reg_t count;
- uint32_t compare;
- uint32_t sr; // only modify the status register using set_pcr()
+ reg_t scount;
+ bool stip;
+ uint32_t stimecmp;
uint32_t fflags;
uint32_t frm;
void step(size_t n); // run for n cycles
void deliver_ipi(); // register an interprocessor interrupt
bool running() { return run; }
- void set_pcr(int which, reg_t val);
- void set_fromhost(reg_t val);
- void set_interrupt(int which, bool on);
- reg_t get_pcr(int which);
+ void set_csr(int which, reg_t val);
+ void raise_interrupt(reg_t which);
+ reg_t get_csr(int which);
mmu_t* get_mmu() { return mmu; }
state_t* get_state() { return &state; }
extension_t* get_extension() { return ext; }
+ void push_privilege_stack();
+ void pop_privilege_stack();
void yield_load_reservation() { state.load_reservation = (reg_t)-1; }
void update_histogram(size_t pc);
disassembler_t* disassembler;
state_t state;
uint32_t id;
+ int xlen;
bool run; // !reset
bool debug;
bool histogram_enabled;
- bool rv64;
bool serialized;
std::vector<insn_desc_t> instructions;
#define customX(n) \
static reg_t c##n(processor_t* p, insn_t insn, reg_t pc) \
{ \
- require_accelerator; \
rocc_t* rocc = static_cast<rocc_t*>(p->get_extension()); \
rocc_insn_union_t u; \
u.i = insn; \
void mem_trap_t::side_effects(state_t* state)
{
- state->badvaddr = badvaddr;
+ state->mbadaddr = badvaddr;
}
DECLARE_MEM_TRAP(CAUSE_MISALIGNED_FETCH, instruction_address_misaligned)
DECLARE_MEM_TRAP(CAUSE_FAULT_FETCH, instruction_access_fault)
DECLARE_TRAP(CAUSE_ILLEGAL_INSTRUCTION, illegal_instruction)
-DECLARE_TRAP(CAUSE_PRIVILEGED_INSTRUCTION, privileged_instruction)
-DECLARE_TRAP(CAUSE_FP_DISABLED, fp_disabled)
-DECLARE_TRAP(CAUSE_SYSCALL, syscall)
+DECLARE_TRAP(CAUSE_SCALL, scall)
+DECLARE_TRAP(CAUSE_MCALL, mcall)
DECLARE_TRAP(CAUSE_BREAKPOINT, breakpoint)
DECLARE_MEM_TRAP(CAUSE_MISALIGNED_LOAD, load_address_misaligned)
DECLARE_MEM_TRAP(CAUSE_MISALIGNED_STORE, store_address_misaligned)
DECLARE_MEM_TRAP(CAUSE_FAULT_LOAD, load_access_fault)
DECLARE_MEM_TRAP(CAUSE_FAULT_STORE, store_access_fault)
-DECLARE_TRAP(CAUSE_ACCELERATOR_DISABLED, accelerator_disabled)
#endif