mirror of
https://gitlab.com/qemu-project/qemu
synced 2024-09-06 09:55:55 +00:00
![Richard Henderson](/assets/img/avatar_default.png)
The exception return address for nios2 is the instruction after the one that was executing at the time of the exception. We have so far implemented this by advancing the pc during the process of raising the exception. It is perhaps a little less confusing to do this advance in the translator (and helpers) when raising the exception in the first place, so that we may more closely match kernel sources. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Message-Id: <20220421151735.31996-58-richard.henderson@linaro.org>
318 lines
8.3 KiB
C
318 lines
8.3 KiB
C
/*
|
|
* Altera Nios II virtual CPU header
|
|
*
|
|
* Copyright (c) 2012 Chris Wulff <crwulff@gmail.com>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, see
|
|
* <http://www.gnu.org/licenses/lgpl-2.1.html>
|
|
*/
|
|
|
|
#ifndef NIOS2_CPU_H
|
|
#define NIOS2_CPU_H
|
|
|
|
#include "exec/cpu-defs.h"
|
|
#include "hw/core/cpu.h"
|
|
#include "hw/registerfields.h"
|
|
#include "qom/object.h"
|
|
|
|
typedef struct CPUArchState CPUNios2State;
|
|
#if !defined(CONFIG_USER_ONLY)
|
|
#include "mmu.h"
|
|
#endif
|
|
|
|
#define TYPE_NIOS2_CPU "nios2-cpu"
|
|
|
|
OBJECT_DECLARE_CPU_TYPE(Nios2CPU, Nios2CPUClass, NIOS2_CPU)
|
|
|
|
/**
|
|
* Nios2CPUClass:
|
|
* @parent_reset: The parent class' reset handler.
|
|
*
|
|
* A Nios2 CPU model.
|
|
*/
|
|
struct Nios2CPUClass {
|
|
/*< private >*/
|
|
CPUClass parent_class;
|
|
/*< public >*/
|
|
|
|
DeviceRealize parent_realize;
|
|
DeviceReset parent_reset;
|
|
};
|
|
|
|
#define TARGET_HAS_ICE 1
|
|
|
|
/* Configuration options for Nios II */
|
|
#define RESET_ADDRESS 0x00000000
|
|
#define EXCEPTION_ADDRESS 0x00000004
|
|
#define FAST_TLB_MISS_ADDRESS 0x00000008
|
|
|
|
#define NUM_GP_REGS 32
|
|
#define NUM_CR_REGS 32
|
|
|
|
#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 */
|
|
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 */
|
|
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
|
|
#define EXCP_TRAP 3
|
|
#define EXCP_UNIMPL 4
|
|
#define EXCP_ILLEGAL 5
|
|
#define EXCP_UNALIGN 6
|
|
#define EXCP_UNALIGND 7
|
|
#define EXCP_DIV 8
|
|
#define EXCP_SUPERA_X 9
|
|
#define EXCP_SUPERI 10
|
|
#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
|
|
|
|
struct CPUArchState {
|
|
#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;
|
|
#endif
|
|
int error_code;
|
|
};
|
|
|
|
typedef struct {
|
|
uint32_t writable;
|
|
uint32_t readonly;
|
|
} ControlRegState;
|
|
|
|
/**
|
|
* Nios2CPU:
|
|
* @env: #CPUNios2State
|
|
*
|
|
* A Nios2 CPU.
|
|
*/
|
|
struct ArchCPU {
|
|
/*< private >*/
|
|
CPUState parent_obj;
|
|
/*< public >*/
|
|
|
|
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;
|
|
|
|
/* Addresses that are hard-coded in the FPGA build settings */
|
|
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);
|
|
void nios2_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
|
|
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);
|
|
|
|
#define CPU_RESOLVING_TYPE TYPE_NIOS2_CPU
|
|
|
|
#define cpu_gen_code cpu_nios2_gen_code
|
|
|
|
#define CPU_SAVE_VERSION 1
|
|
|
|
/* MMU modes definitions */
|
|
#define MMU_SUPERVISOR_IDX 0
|
|
#define MMU_USER_IDX 1
|
|
|
|
static inline int cpu_mmu_index(CPUNios2State *env, bool ifetch)
|
|
{
|
|
return (env->ctrl[CR_STATUS] & CR_STATUS_U) ? MMU_USER_IDX :
|
|
MMU_SUPERVISOR_IDX;
|
|
}
|
|
|
|
#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
|
|
|
|
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)
|
|
{
|
|
unsigned crs = FIELD_EX32(env->ctrl[CR_STATUS], CR_STATUS, CRS);
|
|
|
|
*pc = env->pc;
|
|
*cs_base = 0;
|
|
*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 */
|