diff options
Diffstat (limited to 'target/nios2/cpu.h')
| -rw-r--r-- | target/nios2/cpu.h | 252 |
1 files changed, 161 insertions, 91 deletions
diff --git a/target/nios2/cpu.h b/target/nios2/cpu.h index 1bab805bb0..f85581ee56 100644 --- a/target/nios2/cpu.h +++ b/target/nios2/cpu.h @@ -23,6 +23,7 @@ #include "exec/cpu-defs.h" #include "hw/core/cpu.h" +#include "hw/registerfields.h" #include "qom/object.h" typedef struct CPUArchState CPUNios2State; @@ -56,83 +57,114 @@ struct Nios2CPUClass { #define EXCEPTION_ADDRESS 0x00000004 #define FAST_TLB_MISS_ADDRESS 0x00000008 +#define NUM_GP_REGS 32 +#define NUM_CR_REGS 32 -/* GP regs + CR regs + PC */ -#define NUM_CORE_REGS (32 + 32 + 1) +#ifndef CONFIG_USER_ONLY +/* 63 shadow register sets; index 0 is the primary register set. */ +#define NUM_REG_SETS 64 +#endif /* General purpose register aliases */ -#define R_ZERO 0 -#define R_AT 1 -#define R_RET0 2 -#define R_RET1 3 -#define R_ARG0 4 -#define R_ARG1 5 -#define R_ARG2 6 -#define R_ARG3 7 -#define R_ET 24 -#define R_BT 25 -#define R_GP 26 -#define R_SP 27 -#define R_FP 28 -#define R_EA 29 -#define R_BA 30 -#define R_RA 31 +enum { + R_ZERO = 0, + R_AT = 1, + R_RET0 = 2, + R_RET1 = 3, + R_ARG0 = 4, + R_ARG1 = 5, + R_ARG2 = 6, + R_ARG3 = 7, + R_ET = 24, + R_BT = 25, + R_GP = 26, + R_SP = 27, + R_FP = 28, + R_EA = 29, + R_BA = 30, + R_SSTATUS = 30, + R_RA = 31, +}; /* Control register aliases */ -#define CR_BASE 32 -#define CR_STATUS (CR_BASE + 0) -#define CR_STATUS_PIE (1 << 0) -#define CR_STATUS_U (1 << 1) -#define CR_STATUS_EH (1 << 2) -#define CR_STATUS_IH (1 << 3) -#define CR_STATUS_IL (63 << 4) -#define CR_STATUS_CRS (63 << 10) -#define CR_STATUS_PRS (63 << 16) -#define CR_STATUS_NMI (1 << 22) -#define CR_STATUS_RSIE (1 << 23) -#define CR_ESTATUS (CR_BASE + 1) -#define CR_BSTATUS (CR_BASE + 2) -#define CR_IENABLE (CR_BASE + 3) -#define CR_IPENDING (CR_BASE + 4) -#define CR_CPUID (CR_BASE + 5) -#define CR_CTL6 (CR_BASE + 6) -#define CR_EXCEPTION (CR_BASE + 7) -#define CR_PTEADDR (CR_BASE + 8) -#define CR_PTEADDR_PTBASE_SHIFT 22 -#define CR_PTEADDR_PTBASE_MASK (0x3FF << CR_PTEADDR_PTBASE_SHIFT) -#define CR_PTEADDR_VPN_SHIFT 2 -#define CR_PTEADDR_VPN_MASK (0xFFFFF << CR_PTEADDR_VPN_SHIFT) -#define CR_TLBACC (CR_BASE + 9) -#define CR_TLBACC_IGN_SHIFT 25 -#define CR_TLBACC_IGN_MASK (0x7F << CR_TLBACC_IGN_SHIFT) -#define CR_TLBACC_C (1 << 24) -#define CR_TLBACC_R (1 << 23) -#define CR_TLBACC_W (1 << 22) -#define CR_TLBACC_X (1 << 21) -#define CR_TLBACC_G (1 << 20) -#define CR_TLBACC_PFN_MASK 0x000FFFFF -#define CR_TLBMISC (CR_BASE + 10) -#define CR_TLBMISC_WAY_SHIFT 20 -#define CR_TLBMISC_WAY_MASK (0xF << CR_TLBMISC_WAY_SHIFT) -#define CR_TLBMISC_RD (1 << 19) -#define CR_TLBMISC_WR (1 << 18) -#define CR_TLBMISC_PID_SHIFT 4 -#define CR_TLBMISC_PID_MASK (0x3FFF << CR_TLBMISC_PID_SHIFT) -#define CR_TLBMISC_DBL (1 << 3) -#define CR_TLBMISC_BAD (1 << 2) -#define CR_TLBMISC_PERM (1 << 1) -#define CR_TLBMISC_D (1 << 0) -#define CR_ENCINJ (CR_BASE + 11) -#define CR_BADADDR (CR_BASE + 12) -#define CR_CONFIG (CR_BASE + 13) -#define CR_MPUBASE (CR_BASE + 14) -#define CR_MPUACC (CR_BASE + 15) - -/* Other registers */ -#define R_PC 64 +enum { + CR_STATUS = 0, + CR_ESTATUS = 1, + CR_BSTATUS = 2, + CR_IENABLE = 3, + CR_IPENDING = 4, + CR_CPUID = 5, + CR_EXCEPTION = 7, + CR_PTEADDR = 8, + CR_TLBACC = 9, + CR_TLBMISC = 10, + CR_ENCINJ = 11, + CR_BADADDR = 12, + CR_CONFIG = 13, + CR_MPUBASE = 14, + CR_MPUACC = 15, +}; + +FIELD(CR_STATUS, PIE, 0, 1) +FIELD(CR_STATUS, U, 1, 1) +FIELD(CR_STATUS, EH, 2, 1) +FIELD(CR_STATUS, IH, 3, 1) +FIELD(CR_STATUS, IL, 4, 6) +FIELD(CR_STATUS, CRS, 10, 6) +FIELD(CR_STATUS, PRS, 16, 6) +FIELD(CR_STATUS, NMI, 22, 1) +FIELD(CR_STATUS, RSIE, 23, 1) +FIELD(CR_STATUS, SRS, 31, 1) /* only in sstatus */ + +#define CR_STATUS_PIE R_CR_STATUS_PIE_MASK +#define CR_STATUS_U R_CR_STATUS_U_MASK +#define CR_STATUS_EH R_CR_STATUS_EH_MASK +#define CR_STATUS_IH R_CR_STATUS_IH_MASK +#define CR_STATUS_NMI R_CR_STATUS_NMI_MASK +#define CR_STATUS_RSIE R_CR_STATUS_RSIE_MASK +#define CR_STATUS_SRS R_CR_STATUS_SRS_MASK + +FIELD(CR_EXCEPTION, CAUSE, 2, 5) +FIELD(CR_EXCEPTION, ECCFTL, 31, 1) + +FIELD(CR_PTEADDR, VPN, 2, 20) +FIELD(CR_PTEADDR, PTBASE, 22, 10) + +FIELD(CR_TLBACC, PFN, 0, 20) +FIELD(CR_TLBACC, G, 20, 1) +FIELD(CR_TLBACC, X, 21, 1) +FIELD(CR_TLBACC, W, 22, 1) +FIELD(CR_TLBACC, R, 23, 1) +FIELD(CR_TLBACC, C, 24, 1) +FIELD(CR_TLBACC, IG, 25, 7) + +#define CR_TLBACC_C R_CR_TLBACC_C_MASK +#define CR_TLBACC_R R_CR_TLBACC_R_MASK +#define CR_TLBACC_W R_CR_TLBACC_W_MASK +#define CR_TLBACC_X R_CR_TLBACC_X_MASK +#define CR_TLBACC_G R_CR_TLBACC_G_MASK + +FIELD(CR_TLBMISC, D, 0, 1) +FIELD(CR_TLBMISC, PERM, 1, 1) +FIELD(CR_TLBMISC, BAD, 2, 1) +FIELD(CR_TLBMISC, DBL, 3, 1) +FIELD(CR_TLBMISC, PID, 4, 14) +FIELD(CR_TLBMISC, WE, 18, 1) +FIELD(CR_TLBMISC, RD, 19, 1) +FIELD(CR_TLBMISC, WAY, 20, 4) +FIELD(CR_TLBMISC, EE, 24, 1) + +#define CR_TLBMISC_EE R_CR_TLBMISC_EE_MASK +#define CR_TLBMISC_RD R_CR_TLBMISC_RD_MASK +#define CR_TLBMISC_WE R_CR_TLBMISC_WE_MASK +#define CR_TLBMISC_DBL R_CR_TLBMISC_DBL_MASK +#define CR_TLBMISC_BAD R_CR_TLBMISC_BAD_MASK +#define CR_TLBMISC_PERM R_CR_TLBMISC_PERM_MASK +#define CR_TLBMISC_D R_CR_TLBMISC_D_MASK /* Exceptions */ #define EXCP_BREAK 0x1000 +#define EXCP_SEMIHOST 0x1001 #define EXCP_RESET 0 #define EXCP_PRESET 1 #define EXCP_IRQ 2 @@ -142,20 +174,27 @@ struct Nios2CPUClass { #define EXCP_UNALIGN 6 #define EXCP_UNALIGND 7 #define EXCP_DIV 8 -#define EXCP_SUPERA 9 +#define EXCP_SUPERA_X 9 #define EXCP_SUPERI 10 -#define EXCP_SUPERD 11 -#define EXCP_TLBD 12 -#define EXCP_TLBX 13 -#define EXCP_TLBR 14 -#define EXCP_TLBW 15 +#define EXCP_SUPERA_D 11 +#define EXCP_TLB_X 12 +#define EXCP_TLB_D (0x1000 | EXCP_TLB_X) +#define EXCP_PERM_X 13 +#define EXCP_PERM_R 14 +#define EXCP_PERM_W 15 #define EXCP_MPUI 16 #define EXCP_MPUD 17 -#define CPU_INTERRUPT_NMI CPU_INTERRUPT_TGT_EXT_3 - struct CPUArchState { - uint32_t regs[NUM_CORE_REGS]; +#ifdef CONFIG_USER_ONLY + uint32_t regs[NUM_GP_REGS]; +#else + uint32_t shadow_regs[NUM_REG_SETS][NUM_GP_REGS]; + /* Pointer into shadow_regs for the current register set. */ + uint32_t *regs; +#endif + uint32_t ctrl[NUM_CR_REGS]; + uint32_t pc; #if !defined(CONFIG_USER_ONLY) Nios2MMU mmu; @@ -163,6 +202,11 @@ struct CPUArchState { int error_code; }; +typedef struct { + uint32_t writable; + uint32_t readonly; +} ControlRegState; + /** * Nios2CPU: * @env: #CPUNios2State @@ -177,7 +221,10 @@ struct ArchCPU { CPUNegativeOffsetState neg; CPUNios2State env; + bool diverr_present; bool mmu_present; + bool eic_present; + uint32_t pid_num_bits; uint32_t tlb_num_ways; uint32_t tlb_num_entries; @@ -186,9 +233,31 @@ struct ArchCPU { uint32_t reset_addr; uint32_t exception_addr; uint32_t fast_tlb_miss_addr; + + /* Bits within each control register which are reserved or readonly. */ + ControlRegState cr_state[NUM_CR_REGS]; + + /* External Interrupt Controller Interface */ + uint32_t rha; /* Requested handler address */ + uint32_t ril; /* Requested interrupt level */ + uint32_t rrs; /* Requested register set */ + bool rnmi; /* Requested nonmaskable interrupt */ }; +static inline bool nios2_cr_reserved(const ControlRegState *s) +{ + return (s->writable | s->readonly) == 0; +} + +static inline void nios2_update_crs(CPUNios2State *env) +{ +#ifndef CONFIG_USER_ONLY + unsigned crs = FIELD_EX32(env->ctrl[CR_STATUS], CR_STATUS, CRS); + env->regs = env->shadow_regs[crs]; +#endif +} + void nios2_tcg_init(void); void nios2_cpu_do_interrupt(CPUState *cs); void dump_mmu(CPUNios2State *env); @@ -197,6 +266,8 @@ hwaddr nios2_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); G_NORETURN void nios2_cpu_do_unaligned_access(CPUState *cpu, vaddr addr, MMUAccessType access_type, int mmu_idx, uintptr_t retaddr); +G_NORETURN void nios2_cpu_loop_exit_advance(CPUNios2State *env, + uintptr_t retaddr); void do_nios2_semihosting(CPUNios2State *env); @@ -212,36 +283,35 @@ void do_nios2_semihosting(CPUNios2State *env); static inline int cpu_mmu_index(CPUNios2State *env, bool ifetch) { - return (env->regs[CR_STATUS] & CR_STATUS_U) ? MMU_USER_IDX : + return (env->ctrl[CR_STATUS] & CR_STATUS_U) ? MMU_USER_IDX : MMU_SUPERVISOR_IDX; } -#ifdef CONFIG_USER_ONLY -void nios2_cpu_record_sigsegv(CPUState *cpu, vaddr addr, - MMUAccessType access_type, - bool maperr, uintptr_t ra); -#else +#ifndef CONFIG_USER_ONLY bool nios2_cpu_tlb_fill(CPUState *cs, vaddr address, int size, MMUAccessType access_type, int mmu_idx, bool probe, uintptr_t retaddr); #endif -static inline int cpu_interrupts_enabled(CPUNios2State *env) -{ - return env->regs[CR_STATUS] & CR_STATUS_PIE; -} - typedef CPUNios2State CPUArchState; typedef Nios2CPU ArchCPU; #include "exec/cpu-all.h" +FIELD(TBFLAGS, CRS0, 0, 1) /* Set if CRS == 0. */ +FIELD(TBFLAGS, U, 1, 1) /* Overlaps CR_STATUS_U */ +FIELD(TBFLAGS, R0_0, 2, 1) /* Set if R0 == 0. */ + static inline void cpu_get_tb_cpu_state(CPUNios2State *env, target_ulong *pc, target_ulong *cs_base, uint32_t *flags) { - *pc = env->regs[R_PC]; + unsigned crs = FIELD_EX32(env->ctrl[CR_STATUS], CR_STATUS, CRS); + + *pc = env->pc; *cs_base = 0; - *flags = (env->regs[CR_STATUS] & (CR_STATUS_EH | CR_STATUS_U)); + *flags = (env->ctrl[CR_STATUS] & CR_STATUS_U) + | (crs ? 0 : R_TBFLAGS_CRS0_MASK) + | (env->regs[0] ? 0 : R_TBFLAGS_R0_0_MASK); } #endif /* NIOS2_CPU_H */ |