6e42be7cd1
A transition from CPUFooState to FooCPU can be considered safe,
just like FooCPU::env access in the opposite direction.
The only benefit of the FOO_CPU() casts would be protection against
bogus CPUFooState pointers, but then surrounding code would likely
break, too.
This should slightly improve interrupt etc. performance when going from
CPUFooState to FooCPU.
For any additional CPU() casts see 3556c233d9
(qom: allow turning cast debugging off).
Reported-by: Anthony Liguori <aliguori@us.ibm.com>
Acked-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Andreas Färber <afaerber@suse.de>
437 lines
12 KiB
C
437 lines
12 KiB
C
/*
|
|
* OpenRISC virtual CPU header.
|
|
*
|
|
* Copyright (c) 2011-2012 Jia Liu <proljc@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 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/>.
|
|
*/
|
|
|
|
#ifndef CPU_OPENRISC_H
|
|
#define CPU_OPENRISC_H
|
|
|
|
#define TARGET_LONG_BITS 32
|
|
#define ELF_MACHINE EM_OPENRISC
|
|
|
|
#define CPUArchState struct CPUOpenRISCState
|
|
|
|
/* cpu_openrisc_map_address_* in CPUOpenRISCTLBContext need this decl. */
|
|
struct OpenRISCCPU;
|
|
|
|
#include "config.h"
|
|
#include "qemu-common.h"
|
|
#include "exec/cpu-defs.h"
|
|
#include "fpu/softfloat.h"
|
|
#include "qom/cpu.h"
|
|
|
|
#define TYPE_OPENRISC_CPU "or32-cpu"
|
|
|
|
#define OPENRISC_CPU_CLASS(klass) \
|
|
OBJECT_CLASS_CHECK(OpenRISCCPUClass, (klass), TYPE_OPENRISC_CPU)
|
|
#define OPENRISC_CPU(obj) \
|
|
OBJECT_CHECK(OpenRISCCPU, (obj), TYPE_OPENRISC_CPU)
|
|
#define OPENRISC_CPU_GET_CLASS(obj) \
|
|
OBJECT_GET_CLASS(OpenRISCCPUClass, (obj), TYPE_OPENRISC_CPU)
|
|
|
|
/**
|
|
* OpenRISCCPUClass:
|
|
* @parent_realize: The parent class' realize handler.
|
|
* @parent_reset: The parent class' reset handler.
|
|
*
|
|
* A OpenRISC CPU model.
|
|
*/
|
|
typedef struct OpenRISCCPUClass {
|
|
/*< private >*/
|
|
CPUClass parent_class;
|
|
/*< public >*/
|
|
|
|
DeviceRealize parent_realize;
|
|
void (*parent_reset)(CPUState *cpu);
|
|
} OpenRISCCPUClass;
|
|
|
|
#define NB_MMU_MODES 3
|
|
|
|
enum {
|
|
MMU_NOMMU_IDX = 0,
|
|
MMU_SUPERVISOR_IDX = 1,
|
|
MMU_USER_IDX = 2,
|
|
};
|
|
|
|
#define TARGET_PAGE_BITS 13
|
|
|
|
#define TARGET_PHYS_ADDR_SPACE_BITS 32
|
|
#define TARGET_VIRT_ADDR_SPACE_BITS 32
|
|
|
|
#define SET_FP_CAUSE(reg, v) do {\
|
|
(reg) = ((reg) & ~(0x3f << 12)) | \
|
|
((v & 0x3f) << 12);\
|
|
} while (0)
|
|
#define GET_FP_ENABLE(reg) (((reg) >> 7) & 0x1f)
|
|
#define UPDATE_FP_FLAGS(reg, v) do {\
|
|
(reg) |= ((v & 0x1f) << 2);\
|
|
} while (0)
|
|
|
|
/* Version Register */
|
|
#define SPR_VR 0xFFFF003F
|
|
|
|
/* Internal flags, delay slot flag */
|
|
#define D_FLAG 1
|
|
|
|
/* Interrupt */
|
|
#define NR_IRQS 32
|
|
|
|
/* Unit presece register */
|
|
enum {
|
|
UPR_UP = (1 << 0),
|
|
UPR_DCP = (1 << 1),
|
|
UPR_ICP = (1 << 2),
|
|
UPR_DMP = (1 << 3),
|
|
UPR_IMP = (1 << 4),
|
|
UPR_MP = (1 << 5),
|
|
UPR_DUP = (1 << 6),
|
|
UPR_PCUR = (1 << 7),
|
|
UPR_PMP = (1 << 8),
|
|
UPR_PICP = (1 << 9),
|
|
UPR_TTP = (1 << 10),
|
|
UPR_CUP = (255 << 24),
|
|
};
|
|
|
|
/* CPU configure register */
|
|
enum {
|
|
CPUCFGR_NSGF = (15 << 0),
|
|
CPUCFGR_CGF = (1 << 4),
|
|
CPUCFGR_OB32S = (1 << 5),
|
|
CPUCFGR_OB64S = (1 << 6),
|
|
CPUCFGR_OF32S = (1 << 7),
|
|
CPUCFGR_OF64S = (1 << 8),
|
|
CPUCFGR_OV64S = (1 << 9),
|
|
};
|
|
|
|
/* DMMU configure register */
|
|
enum {
|
|
DMMUCFGR_NTW = (3 << 0),
|
|
DMMUCFGR_NTS = (7 << 2),
|
|
DMMUCFGR_NAE = (7 << 5),
|
|
DMMUCFGR_CRI = (1 << 8),
|
|
DMMUCFGR_PRI = (1 << 9),
|
|
DMMUCFGR_TEIRI = (1 << 10),
|
|
DMMUCFGR_HTR = (1 << 11),
|
|
};
|
|
|
|
/* IMMU configure register */
|
|
enum {
|
|
IMMUCFGR_NTW = (3 << 0),
|
|
IMMUCFGR_NTS = (7 << 2),
|
|
IMMUCFGR_NAE = (7 << 5),
|
|
IMMUCFGR_CRI = (1 << 8),
|
|
IMMUCFGR_PRI = (1 << 9),
|
|
IMMUCFGR_TEIRI = (1 << 10),
|
|
IMMUCFGR_HTR = (1 << 11),
|
|
};
|
|
|
|
/* Float point control status register */
|
|
enum {
|
|
FPCSR_FPEE = 1,
|
|
FPCSR_RM = (3 << 1),
|
|
FPCSR_OVF = (1 << 3),
|
|
FPCSR_UNF = (1 << 4),
|
|
FPCSR_SNF = (1 << 5),
|
|
FPCSR_QNF = (1 << 6),
|
|
FPCSR_ZF = (1 << 7),
|
|
FPCSR_IXF = (1 << 8),
|
|
FPCSR_IVF = (1 << 9),
|
|
FPCSR_INF = (1 << 10),
|
|
FPCSR_DZF = (1 << 11),
|
|
};
|
|
|
|
/* Exceptions indices */
|
|
enum {
|
|
EXCP_RESET = 0x1,
|
|
EXCP_BUSERR = 0x2,
|
|
EXCP_DPF = 0x3,
|
|
EXCP_IPF = 0x4,
|
|
EXCP_TICK = 0x5,
|
|
EXCP_ALIGN = 0x6,
|
|
EXCP_ILLEGAL = 0x7,
|
|
EXCP_INT = 0x8,
|
|
EXCP_DTLBMISS = 0x9,
|
|
EXCP_ITLBMISS = 0xa,
|
|
EXCP_RANGE = 0xb,
|
|
EXCP_SYSCALL = 0xc,
|
|
EXCP_FPE = 0xd,
|
|
EXCP_TRAP = 0xe,
|
|
EXCP_NR,
|
|
};
|
|
|
|
/* Supervisor register */
|
|
enum {
|
|
SR_SM = (1 << 0),
|
|
SR_TEE = (1 << 1),
|
|
SR_IEE = (1 << 2),
|
|
SR_DCE = (1 << 3),
|
|
SR_ICE = (1 << 4),
|
|
SR_DME = (1 << 5),
|
|
SR_IME = (1 << 6),
|
|
SR_LEE = (1 << 7),
|
|
SR_CE = (1 << 8),
|
|
SR_F = (1 << 9),
|
|
SR_CY = (1 << 10),
|
|
SR_OV = (1 << 11),
|
|
SR_OVE = (1 << 12),
|
|
SR_DSX = (1 << 13),
|
|
SR_EPH = (1 << 14),
|
|
SR_FO = (1 << 15),
|
|
SR_SUMRA = (1 << 16),
|
|
SR_SCE = (1 << 17),
|
|
};
|
|
|
|
/* OpenRISC Hardware Capabilities */
|
|
enum {
|
|
OPENRISC_FEATURE_NSGF = (15 << 0),
|
|
OPENRISC_FEATURE_CGF = (1 << 4),
|
|
OPENRISC_FEATURE_OB32S = (1 << 5),
|
|
OPENRISC_FEATURE_OB64S = (1 << 6),
|
|
OPENRISC_FEATURE_OF32S = (1 << 7),
|
|
OPENRISC_FEATURE_OF64S = (1 << 8),
|
|
OPENRISC_FEATURE_OV64S = (1 << 9),
|
|
};
|
|
|
|
/* Tick Timer Mode Register */
|
|
enum {
|
|
TTMR_TP = (0xfffffff),
|
|
TTMR_IP = (1 << 28),
|
|
TTMR_IE = (1 << 29),
|
|
TTMR_M = (3 << 30),
|
|
};
|
|
|
|
/* Timer Mode */
|
|
enum {
|
|
TIMER_NONE = (0 << 30),
|
|
TIMER_INTR = (1 << 30),
|
|
TIMER_SHOT = (2 << 30),
|
|
TIMER_CONT = (3 << 30),
|
|
};
|
|
|
|
/* TLB size */
|
|
enum {
|
|
DTLB_WAYS = 1,
|
|
DTLB_SIZE = 64,
|
|
DTLB_MASK = (DTLB_SIZE-1),
|
|
ITLB_WAYS = 1,
|
|
ITLB_SIZE = 64,
|
|
ITLB_MASK = (ITLB_SIZE-1),
|
|
};
|
|
|
|
/* TLB prot */
|
|
enum {
|
|
URE = (1 << 6),
|
|
UWE = (1 << 7),
|
|
SRE = (1 << 8),
|
|
SWE = (1 << 9),
|
|
|
|
SXE = (1 << 6),
|
|
UXE = (1 << 7),
|
|
};
|
|
|
|
/* check if tlb available */
|
|
enum {
|
|
TLBRET_INVALID = -3,
|
|
TLBRET_NOMATCH = -2,
|
|
TLBRET_BADADDR = -1,
|
|
TLBRET_MATCH = 0
|
|
};
|
|
|
|
typedef struct OpenRISCTLBEntry {
|
|
uint32_t mr;
|
|
uint32_t tr;
|
|
} OpenRISCTLBEntry;
|
|
|
|
#ifndef CONFIG_USER_ONLY
|
|
typedef struct CPUOpenRISCTLBContext {
|
|
OpenRISCTLBEntry itlb[ITLB_WAYS][ITLB_SIZE];
|
|
OpenRISCTLBEntry dtlb[DTLB_WAYS][DTLB_SIZE];
|
|
|
|
int (*cpu_openrisc_map_address_code)(struct OpenRISCCPU *cpu,
|
|
hwaddr *physical,
|
|
int *prot,
|
|
target_ulong address, int rw);
|
|
int (*cpu_openrisc_map_address_data)(struct OpenRISCCPU *cpu,
|
|
hwaddr *physical,
|
|
int *prot,
|
|
target_ulong address, int rw);
|
|
} CPUOpenRISCTLBContext;
|
|
#endif
|
|
|
|
typedef struct CPUOpenRISCState {
|
|
target_ulong gpr[32]; /* General registers */
|
|
target_ulong pc; /* Program counter */
|
|
target_ulong npc; /* Next PC */
|
|
target_ulong ppc; /* Prev PC */
|
|
target_ulong jmp_pc; /* Jump PC */
|
|
|
|
target_ulong machi; /* Multiply register MACHI */
|
|
target_ulong maclo; /* Multiply register MACLO */
|
|
|
|
target_ulong fpmaddhi; /* Multiply and add float register FPMADDHI */
|
|
target_ulong fpmaddlo; /* Multiply and add float register FPMADDLO */
|
|
|
|
target_ulong epcr; /* Exception PC register */
|
|
target_ulong eear; /* Exception EA register */
|
|
|
|
uint32_t sr; /* Supervisor register */
|
|
uint32_t vr; /* Version register */
|
|
uint32_t upr; /* Unit presence register */
|
|
uint32_t cpucfgr; /* CPU configure register */
|
|
uint32_t dmmucfgr; /* DMMU configure register */
|
|
uint32_t immucfgr; /* IMMU configure register */
|
|
uint32_t esr; /* Exception supervisor register */
|
|
uint32_t fpcsr; /* Float register */
|
|
float_status fp_status;
|
|
|
|
uint32_t flags; /* cpu_flags, we only use it for exception
|
|
in solt so far. */
|
|
uint32_t btaken; /* the SR_F bit */
|
|
|
|
CPU_COMMON
|
|
|
|
#ifndef CONFIG_USER_ONLY
|
|
CPUOpenRISCTLBContext * tlb;
|
|
|
|
struct QEMUTimer *timer;
|
|
uint32_t ttmr; /* Timer tick mode register */
|
|
uint32_t ttcr; /* Timer tick count register */
|
|
|
|
uint32_t picmr; /* Interrupt mask register */
|
|
uint32_t picsr; /* Interrupt contrl register*/
|
|
#endif
|
|
void *irq[32]; /* Interrupt irq input */
|
|
} CPUOpenRISCState;
|
|
|
|
/**
|
|
* OpenRISCCPU:
|
|
* @env: #CPUOpenRISCState
|
|
*
|
|
* A OpenRISC CPU.
|
|
*/
|
|
typedef struct OpenRISCCPU {
|
|
/*< private >*/
|
|
CPUState parent_obj;
|
|
/*< public >*/
|
|
|
|
CPUOpenRISCState env;
|
|
|
|
uint32_t feature; /* CPU Capabilities */
|
|
} OpenRISCCPU;
|
|
|
|
static inline OpenRISCCPU *openrisc_env_get_cpu(CPUOpenRISCState *env)
|
|
{
|
|
return container_of(env, OpenRISCCPU, env);
|
|
}
|
|
|
|
#define ENV_GET_CPU(e) CPU(openrisc_env_get_cpu(e))
|
|
|
|
#define ENV_OFFSET offsetof(OpenRISCCPU, env)
|
|
|
|
OpenRISCCPU *cpu_openrisc_init(const char *cpu_model);
|
|
|
|
void cpu_openrisc_list(FILE *f, fprintf_function cpu_fprintf);
|
|
int cpu_openrisc_exec(CPUOpenRISCState *s);
|
|
void openrisc_cpu_do_interrupt(CPUState *cpu);
|
|
void openrisc_cpu_dump_state(CPUState *cpu, FILE *f,
|
|
fprintf_function cpu_fprintf, int flags);
|
|
void openrisc_translate_init(void);
|
|
int cpu_openrisc_handle_mmu_fault(CPUOpenRISCState *env,
|
|
target_ulong address,
|
|
int rw, int mmu_idx);
|
|
int cpu_openrisc_signal_handler(int host_signum, void *pinfo, void *puc);
|
|
|
|
#define cpu_list cpu_openrisc_list
|
|
#define cpu_exec cpu_openrisc_exec
|
|
#define cpu_gen_code cpu_openrisc_gen_code
|
|
#define cpu_handle_mmu_fault cpu_openrisc_handle_mmu_fault
|
|
#define cpu_signal_handler cpu_openrisc_signal_handler
|
|
|
|
#ifndef CONFIG_USER_ONLY
|
|
extern const struct VMStateDescription vmstate_openrisc_cpu;
|
|
|
|
/* hw/openrisc_pic.c */
|
|
void cpu_openrisc_pic_init(OpenRISCCPU *cpu);
|
|
|
|
/* hw/openrisc_timer.c */
|
|
void cpu_openrisc_clock_init(OpenRISCCPU *cpu);
|
|
void cpu_openrisc_count_update(OpenRISCCPU *cpu);
|
|
void cpu_openrisc_count_start(OpenRISCCPU *cpu);
|
|
void cpu_openrisc_count_stop(OpenRISCCPU *cpu);
|
|
|
|
void cpu_openrisc_mmu_init(OpenRISCCPU *cpu);
|
|
int cpu_openrisc_get_phys_nommu(OpenRISCCPU *cpu,
|
|
hwaddr *physical,
|
|
int *prot, target_ulong address, int rw);
|
|
int cpu_openrisc_get_phys_code(OpenRISCCPU *cpu,
|
|
hwaddr *physical,
|
|
int *prot, target_ulong address, int rw);
|
|
int cpu_openrisc_get_phys_data(OpenRISCCPU *cpu,
|
|
hwaddr *physical,
|
|
int *prot, target_ulong address, int rw);
|
|
#endif
|
|
|
|
static inline CPUOpenRISCState *cpu_init(const char *cpu_model)
|
|
{
|
|
OpenRISCCPU *cpu = cpu_openrisc_init(cpu_model);
|
|
if (cpu) {
|
|
return &cpu->env;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
#include "exec/cpu-all.h"
|
|
|
|
static inline void cpu_get_tb_cpu_state(CPUOpenRISCState *env,
|
|
target_ulong *pc,
|
|
target_ulong *cs_base, int *flags)
|
|
{
|
|
*pc = env->pc;
|
|
*cs_base = 0;
|
|
/* D_FLAG -- branch instruction exception */
|
|
*flags = (env->flags & D_FLAG);
|
|
}
|
|
|
|
static inline int cpu_mmu_index(CPUOpenRISCState *env)
|
|
{
|
|
if (!(env->sr & SR_IME)) {
|
|
return MMU_NOMMU_IDX;
|
|
}
|
|
return (env->sr & SR_SM) == 0 ? MMU_USER_IDX : MMU_SUPERVISOR_IDX;
|
|
}
|
|
|
|
#define CPU_INTERRUPT_TIMER CPU_INTERRUPT_TGT_INT_0
|
|
static inline bool cpu_has_work(CPUState *cpu)
|
|
{
|
|
return cpu->interrupt_request & (CPU_INTERRUPT_HARD |
|
|
CPU_INTERRUPT_TIMER);
|
|
}
|
|
|
|
#include "exec/exec-all.h"
|
|
|
|
static inline target_ulong cpu_get_pc(CPUOpenRISCState *env)
|
|
{
|
|
return env->pc;
|
|
}
|
|
|
|
static inline void cpu_pc_from_tb(CPUOpenRISCState *env, TranslationBlock *tb)
|
|
{
|
|
env->pc = tb->pc;
|
|
}
|
|
|
|
#endif /* CPU_OPENRISC_H */
|