mirror of
https://github.com/qemu/qemu.git
synced 2024-11-26 04:13:39 +08:00
Convert microblaze to generic translator loop
Convert microblaze to decodetree Fix mb_cpu_transaction_failed Other misc cleanups -----BEGIN PGP SIGNATURE----- iQFRBAABCgA7FiEEekgeeIaLTbaoWgXAZN846K9+IV8FAl9OZf8dHHJpY2hhcmQu aGVuZGVyc29uQGxpbmFyby5vcmcACgkQZN846K9+IV99nwgAoBfPM7ClfItMAAo5 7EnSDooia07pGrUFb1M3j5jd3et3yCqFGwKqngHlD7gbp4pxlgQuBMr6dVf2Ie9R aVErzqKCWSXyESlWULdIIddSzYbAVAJn1aRYG9iw0zBTJ/JUKuqOyxbmsZ5f/xK3 SXwO5zGqwMGKgbviNA428kzuOPB/i6mhWou4bIyzfAh8rJW8Wu0iJ0K2FoUeB5+r 0XLm3C5WFiF8ujCw4MXALo3PQMOsJKTiurfi4KqubMHus3BHawKz3YH+okmBibQ8 PQxkabCwoes6VrAp6ZtCr5IdYQW24q0sExeQEhREKNV7pwePnjCXbno+LJBqCKR9 9e9+7g== =T+SS -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/rth/tags/pull-mb-20200901' into staging Convert microblaze to generic translator loop Convert microblaze to decodetree Fix mb_cpu_transaction_failed Other misc cleanups # gpg: Signature made Tue 01 Sep 2020 16:17:19 BST # gpg: using RSA key 7A481E78868B4DB6A85A05C064DF38E8AF7E215F # gpg: issuer "richard.henderson@linaro.org" # gpg: Good signature from "Richard Henderson <richard.henderson@linaro.org>" [full] # Primary key fingerprint: 7A48 1E78 868B 4DB6 A85A 05C0 64DF 38E8 AF7E 215F * remotes/rth/tags/pull-mb-20200901: (76 commits) target/microblaze: Reduce linux-user address space to 32-bit target/microblaze: Add flags markup to some helpers target/microblaze: Remove cpu_R[0] target/microblaze: Remove last of old decoder target/microblaze: Convert dec_stream to decodetree target/microblaze: Convert dec_msr to decodetree target/microblaze: Convert msrclr, msrset to decodetree target/microblaze: Tidy do_rti, do_rtb, do_rte target/microblaze: Convert dec_rts to decodetree target/microblaze: Convert dec_bcc to decodetree target/microblaze: Convert dec_br to decodetree target/microblaze: Reorganize branching target/microblaze: Convert mbar to decodetree target/microblaze: Convert brk and brki to decodetree target/microblaze: Tidy mb_cpu_dump_state target/microblaze: Replace delayed_branch with tb_flags_to_set target/microblaze: Replace clear_imm with tb_flags_to_set target/microblaze: Use cc->do_unaligned_access tcg: Add tcg_get_insn_start_param target/microblaze: Store "current" iflags in insn_start ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
7068d5ef39
@ -777,11 +777,26 @@ static inline TCGv_i32 TCGV_HIGH(TCGv_i64 t)
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline TCGArg tcg_get_insn_param(TCGOp *op, int arg)
|
||||
{
|
||||
return op->args[arg];
|
||||
}
|
||||
|
||||
static inline void tcg_set_insn_param(TCGOp *op, int arg, TCGArg v)
|
||||
{
|
||||
op->args[arg] = v;
|
||||
}
|
||||
|
||||
static inline target_ulong tcg_get_insn_start_param(TCGOp *op, int arg)
|
||||
{
|
||||
#if TARGET_LONG_BITS <= TCG_TARGET_REG_BITS
|
||||
return tcg_get_insn_param(op, arg);
|
||||
#else
|
||||
return tcg_get_insn_param(op, arg * 2) |
|
||||
((uint64_t)tcg_get_insn_param(op, arg * 2 + 1) << 32);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void tcg_set_insn_start_param(TCGOp *op, int arg, target_ulong v)
|
||||
{
|
||||
#if TARGET_LONG_BITS <= TCG_TARGET_REG_BITS
|
||||
|
@ -1038,9 +1038,12 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUMBState *env
|
||||
(*regs)[pos++] = tswapreg(env->regs[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
(*regs)[pos++] = tswapreg(env->sregs[i]);
|
||||
}
|
||||
(*regs)[pos++] = tswapreg(env->pc);
|
||||
(*regs)[pos++] = tswapreg(mb_cpu_read_msr(env));
|
||||
(*regs)[pos++] = 0;
|
||||
(*regs)[pos++] = tswapreg(env->ear);
|
||||
(*regs)[pos++] = 0;
|
||||
(*regs)[pos++] = tswapreg(env->esr);
|
||||
}
|
||||
|
||||
#endif /* TARGET_MICROBLAZE */
|
||||
|
@ -48,10 +48,10 @@ void cpu_loop(CPUMBState *env)
|
||||
case EXCP_INTERRUPT:
|
||||
/* just indicate that signals should be handled asap */
|
||||
break;
|
||||
case EXCP_BREAK:
|
||||
case EXCP_SYSCALL:
|
||||
/* Return address is 4 bytes after the call. */
|
||||
env->regs[14] += 4;
|
||||
env->sregs[SR_PC] = env->regs[14];
|
||||
env->pc = env->regs[14];
|
||||
ret = do_syscall(env,
|
||||
env->regs[12],
|
||||
env->regs[5],
|
||||
@ -63,7 +63,7 @@ void cpu_loop(CPUMBState *env)
|
||||
0, 0);
|
||||
if (ret == -TARGET_ERESTARTSYS) {
|
||||
/* Wind back to before the syscall. */
|
||||
env->sregs[SR_PC] -= 4;
|
||||
env->pc -= 4;
|
||||
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
|
||||
env->regs[3] = ret;
|
||||
}
|
||||
@ -73,19 +73,19 @@ void cpu_loop(CPUMBState *env)
|
||||
* not a userspace-usable register, as the kernel may clobber it
|
||||
* at any point.)
|
||||
*/
|
||||
env->regs[14] = env->sregs[SR_PC];
|
||||
env->regs[14] = env->pc;
|
||||
break;
|
||||
case EXCP_HW_EXCP:
|
||||
env->regs[17] = env->sregs[SR_PC] + 4;
|
||||
env->regs[17] = env->pc + 4;
|
||||
if (env->iflags & D_FLAG) {
|
||||
env->sregs[SR_ESR] |= 1 << 12;
|
||||
env->sregs[SR_PC] -= 4;
|
||||
env->esr |= 1 << 12;
|
||||
env->pc -= 4;
|
||||
/* FIXME: if branch was immed, replay the imm as well. */
|
||||
}
|
||||
|
||||
env->iflags &= ~(IMM_FLAG | D_FLAG);
|
||||
|
||||
switch (env->sregs[SR_ESR] & 31) {
|
||||
switch (env->esr & 31) {
|
||||
case ESR_EC_DIVZERO:
|
||||
info.si_signo = TARGET_SIGFPE;
|
||||
info.si_errno = 0;
|
||||
@ -96,18 +96,18 @@ void cpu_loop(CPUMBState *env)
|
||||
case ESR_EC_FPU:
|
||||
info.si_signo = TARGET_SIGFPE;
|
||||
info.si_errno = 0;
|
||||
if (env->sregs[SR_FSR] & FSR_IO) {
|
||||
if (env->fsr & FSR_IO) {
|
||||
info.si_code = TARGET_FPE_FLTINV;
|
||||
}
|
||||
if (env->sregs[SR_FSR] & FSR_DZ) {
|
||||
if (env->fsr & FSR_DZ) {
|
||||
info.si_code = TARGET_FPE_FLTDIV;
|
||||
}
|
||||
info._sifields._sigfault._addr = 0;
|
||||
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unhandled hw-exception: 0x%" PRIx64 "\n",
|
||||
env->sregs[SR_ESR] & ESR_EC_MASK);
|
||||
fprintf(stderr, "Unhandled hw-exception: 0x%x\n",
|
||||
env->esr & ESR_EC_MASK);
|
||||
cpu_dump_state(cs, stderr, 0);
|
||||
exit(EXIT_FAILURE);
|
||||
break;
|
||||
@ -165,5 +165,5 @@ void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
|
||||
env->regs[29] = regs->r29;
|
||||
env->regs[30] = regs->r30;
|
||||
env->regs[31] = regs->r31;
|
||||
env->sregs[SR_PC] = regs->pc;
|
||||
env->pc = regs->pc;
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ static void setup_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
|
||||
__put_user(env->regs[29], &sc->regs.r29);
|
||||
__put_user(env->regs[30], &sc->regs.r30);
|
||||
__put_user(env->regs[31], &sc->regs.r31);
|
||||
__put_user(env->sregs[SR_PC], &sc->regs.pc);
|
||||
__put_user(env->pc, &sc->regs.pc);
|
||||
}
|
||||
|
||||
static void restore_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
|
||||
@ -124,7 +124,7 @@ static void restore_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
|
||||
__get_user(env->regs[29], &sc->regs.r29);
|
||||
__get_user(env->regs[30], &sc->regs.r30);
|
||||
__get_user(env->regs[31], &sc->regs.r31);
|
||||
__get_user(env->sregs[SR_PC], &sc->regs.pc);
|
||||
__get_user(env->pc, &sc->regs.pc);
|
||||
}
|
||||
|
||||
static abi_ulong get_sigframe(struct target_sigaction *ka,
|
||||
@ -188,7 +188,7 @@ void setup_frame(int sig, struct target_sigaction *ka,
|
||||
env->regs[7] = frame_addr += offsetof(typeof(*frame), uc);
|
||||
|
||||
/* Offset of 4 to handle microblaze rtid r14, 0 */
|
||||
env->sregs[SR_PC] = (unsigned long)ka->_sa_handler;
|
||||
env->pc = (unsigned long)ka->_sa_handler;
|
||||
|
||||
unlock_user_struct(frame, frame_addr, 1);
|
||||
return;
|
||||
@ -228,7 +228,7 @@ long do_sigreturn(CPUMBState *env)
|
||||
restore_sigcontext(&frame->uc.tuc_mcontext, env);
|
||||
/* We got here through a sigreturn syscall, our path back is via an
|
||||
rtb insn so setup r14 for that. */
|
||||
env->regs[14] = env->sregs[SR_PC];
|
||||
env->regs[14] = env->pc;
|
||||
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
|
@ -8,9 +8,24 @@
|
||||
#ifndef MICROBLAZE_CPU_PARAM_H
|
||||
#define MICROBLAZE_CPU_PARAM_H 1
|
||||
|
||||
/*
|
||||
* While system mode can address up to 64 bits of address space,
|
||||
* this is done via the lea/sea instructions, which are system-only
|
||||
* (as they also bypass the mmu).
|
||||
*
|
||||
* We can improve the user-only experience by only exposing 32 bits
|
||||
* of address space.
|
||||
*/
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
#define TARGET_LONG_BITS 32
|
||||
#define TARGET_PHYS_ADDR_SPACE_BITS 32
|
||||
#define TARGET_VIRT_ADDR_SPACE_BITS 32
|
||||
#else
|
||||
#define TARGET_LONG_BITS 64
|
||||
#define TARGET_PHYS_ADDR_SPACE_BITS 64
|
||||
#define TARGET_VIRT_ADDR_SPACE_BITS 64
|
||||
#endif
|
||||
|
||||
/* FIXME: MB uses variable pages down to 1K but linux only uses 4k. */
|
||||
#define TARGET_PAGE_BITS 12
|
||||
#define NB_MMU_MODES 3
|
||||
|
@ -79,7 +79,7 @@ static void mb_cpu_set_pc(CPUState *cs, vaddr value)
|
||||
{
|
||||
MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
|
||||
|
||||
cpu->env.sregs[SR_PC] = value;
|
||||
cpu->env.pc = value;
|
||||
}
|
||||
|
||||
static bool mb_cpu_has_work(CPUState *cs)
|
||||
@ -117,13 +117,13 @@ static void mb_cpu_reset(DeviceState *dev)
|
||||
/* Disable stack protector. */
|
||||
env->shr = ~0;
|
||||
|
||||
env->sregs[SR_PC] = cpu->cfg.base_vectors;
|
||||
env->pc = cpu->cfg.base_vectors;
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
/* start in user mode with interrupts enabled. */
|
||||
env->sregs[SR_MSR] = MSR_EE | MSR_IE | MSR_VM | MSR_UM;
|
||||
mb_cpu_write_msr(env, MSR_EE | MSR_IE | MSR_VM | MSR_UM);
|
||||
#else
|
||||
env->sregs[SR_MSR] = 0;
|
||||
mb_cpu_write_msr(env, 0);
|
||||
mmu_init(&env->mmu);
|
||||
env->mmu.c_mmu = 3;
|
||||
env->mmu.c_mmu_tlb_access = 3;
|
||||
@ -317,6 +317,7 @@ static void mb_cpu_class_init(ObjectClass *oc, void *data)
|
||||
cc->class_by_name = mb_cpu_class_by_name;
|
||||
cc->has_work = mb_cpu_has_work;
|
||||
cc->do_interrupt = mb_cpu_do_interrupt;
|
||||
cc->do_unaligned_access = mb_cpu_do_unaligned_access;
|
||||
cc->cpu_exec_interrupt = mb_cpu_exec_interrupt;
|
||||
cc->dump_state = mb_cpu_dump_state;
|
||||
cc->set_pc = mb_cpu_set_pc;
|
||||
|
@ -31,7 +31,7 @@ typedef struct CPUMBState CPUMBState;
|
||||
|
||||
#define EXCP_MMU 1
|
||||
#define EXCP_IRQ 2
|
||||
#define EXCP_BREAK 3
|
||||
#define EXCP_SYSCALL 3 /* user-only */
|
||||
#define EXCP_HW_BREAK 4
|
||||
#define EXCP_HW_EXCP 5
|
||||
|
||||
@ -79,10 +79,13 @@ typedef struct CPUMBState CPUMBState;
|
||||
|
||||
/* Exception State Register (ESR) Fields */
|
||||
#define ESR_DIZ (1<<11) /* Zone Protection */
|
||||
#define ESR_W (1<<11) /* Unaligned word access */
|
||||
#define ESR_S (1<<10) /* Store instruction */
|
||||
|
||||
#define ESR_ESS_FSL_OFFSET 5
|
||||
|
||||
#define ESR_ESS_MASK (0x7f << 5)
|
||||
|
||||
#define ESR_EC_FSL 0
|
||||
#define ESR_EC_UNALIGNED_DATA 1
|
||||
#define ESR_EC_ILLEGAL_OP 2
|
||||
@ -228,15 +231,22 @@ typedef struct CPUMBState CPUMBState;
|
||||
#define STREAM_CONTROL (1 << 3)
|
||||
#define STREAM_NONBLOCK (1 << 4)
|
||||
|
||||
#define TARGET_INSN_START_EXTRA_WORDS 1
|
||||
|
||||
struct CPUMBState {
|
||||
uint32_t debug;
|
||||
uint32_t btaken;
|
||||
uint64_t btarget;
|
||||
uint32_t bimm;
|
||||
uint32_t bvalue; /* TCG temporary, only valid during a TB */
|
||||
uint32_t btarget; /* Full resolved branch destination */
|
||||
|
||||
uint32_t imm;
|
||||
uint32_t regs[32];
|
||||
uint64_t sregs[14];
|
||||
uint32_t pc;
|
||||
uint32_t msr; /* All bits of MSR except MSR[C] and MSR[CC] */
|
||||
uint32_t msr_c; /* MSR[C], in low bit; other bits must be 0 */
|
||||
target_ulong ear;
|
||||
uint32_t esr;
|
||||
uint32_t fsr;
|
||||
uint32_t btr;
|
||||
uint32_t edr;
|
||||
float_status fp_status;
|
||||
/* Stack protectors. Yes, it's a hw feature. */
|
||||
uint32_t slr, shr;
|
||||
@ -247,14 +257,22 @@ struct CPUMBState {
|
||||
uint32_t res_val;
|
||||
|
||||
/* Internal flags. */
|
||||
#define IMM_FLAG 4
|
||||
#define MSR_EE_FLAG (1 << 8)
|
||||
#define IMM_FLAG (1 << 0)
|
||||
#define BIMM_FLAG (1 << 1)
|
||||
#define ESR_ESS_FLAG (1 << 2) /* indicates ESR_ESS_MASK is present */
|
||||
/* MSR_EE (1 << 8) -- these 3 are not in iflags but tb_flags */
|
||||
/* MSR_UM (1 << 11) */
|
||||
/* MSR_VM (1 << 13) */
|
||||
/* ESR_ESS_MASK [11:5] -- unwind into iflags for unaligned excp */
|
||||
#define DRTI_FLAG (1 << 16)
|
||||
#define DRTE_FLAG (1 << 17)
|
||||
#define DRTB_FLAG (1 << 18)
|
||||
#define D_FLAG (1 << 19) /* Bit in ESR. */
|
||||
|
||||
/* TB dependent CPUMBState. */
|
||||
#define IFLAGS_TB_MASK (D_FLAG | IMM_FLAG | DRTI_FLAG | DRTE_FLAG | DRTB_FLAG)
|
||||
#define MSR_TB_MASK (MSR_UM | MSR_VM | MSR_EE)
|
||||
|
||||
uint32_t iflags;
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
@ -317,11 +335,30 @@ struct MicroBlazeCPU {
|
||||
|
||||
void mb_cpu_do_interrupt(CPUState *cs);
|
||||
bool mb_cpu_exec_interrupt(CPUState *cs, int int_req);
|
||||
void mb_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,
|
||||
MMUAccessType access_type,
|
||||
int mmu_idx, uintptr_t retaddr);
|
||||
void mb_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
|
||||
hwaddr mb_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
||||
int mb_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
|
||||
int mb_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||
|
||||
static inline uint32_t mb_cpu_read_msr(const CPUMBState *env)
|
||||
{
|
||||
/* Replicate MSR[C] to MSR[CC]. */
|
||||
return env->msr | (env->msr_c * (MSR_C | MSR_CC));
|
||||
}
|
||||
|
||||
static inline void mb_cpu_write_msr(CPUMBState *env, uint32_t val)
|
||||
{
|
||||
env->msr_c = (val >> 2) & 1;
|
||||
/*
|
||||
* Clear both MSR[C] and MSR[CC] from the saved copy.
|
||||
* MSR_PVR is not writable and is always clear.
|
||||
*/
|
||||
env->msr = val & ~(MSR_C | MSR_CC | MSR_PVR);
|
||||
}
|
||||
|
||||
void mb_tcg_init(void);
|
||||
/* you can call this signal handler from your SIGBUS and SIGSEGV
|
||||
signal handlers to inform the virtual CPU of exceptions. non zero
|
||||
@ -348,13 +385,15 @@ typedef MicroBlazeCPU ArchCPU;
|
||||
|
||||
#include "exec/cpu-all.h"
|
||||
|
||||
/* Ensure there is no overlap between the two masks. */
|
||||
QEMU_BUILD_BUG_ON(MSR_TB_MASK & IFLAGS_TB_MASK);
|
||||
|
||||
static inline void cpu_get_tb_cpu_state(CPUMBState *env, target_ulong *pc,
|
||||
target_ulong *cs_base, uint32_t *flags)
|
||||
{
|
||||
*pc = env->sregs[SR_PC];
|
||||
*cs_base = 0;
|
||||
*flags = (env->iflags & IFLAGS_TB_MASK) |
|
||||
(env->sregs[SR_MSR] & (MSR_UM | MSR_VM | MSR_EE));
|
||||
*pc = env->pc;
|
||||
*flags = (env->iflags & IFLAGS_TB_MASK) | (env->msr & MSR_TB_MASK);
|
||||
*cs_base = (*flags & IMM_FLAG ? env->imm : 0);
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
@ -369,11 +408,11 @@ static inline int cpu_mmu_index(CPUMBState *env, bool ifetch)
|
||||
MicroBlazeCPU *cpu = env_archcpu(env);
|
||||
|
||||
/* Are we in nommu mode?. */
|
||||
if (!(env->sregs[SR_MSR] & MSR_VM) || !cpu->cfg.use_mmu) {
|
||||
if (!(env->msr & MSR_VM) || !cpu->cfg.use_mmu) {
|
||||
return MMU_NOMMU_IDX;
|
||||
}
|
||||
|
||||
if (env->sregs[SR_MSR] & MSR_UM) {
|
||||
if (env->msr & MSR_UM) {
|
||||
return MMU_USER_IDX;
|
||||
}
|
||||
return MMU_KERNEL_IDX;
|
||||
|
@ -21,58 +21,80 @@
|
||||
#include "cpu.h"
|
||||
#include "exec/gdbstub.h"
|
||||
|
||||
/*
|
||||
* GDB expects SREGs in the following order:
|
||||
* PC, MSR, EAR, ESR, FSR, BTR, EDR, PID, ZPR, TLBX, TLBSX, TLBLO, TLBHI.
|
||||
*
|
||||
* PID, ZPR, TLBx, TLBsx, TLBLO, and TLBHI aren't modeled, so we don't
|
||||
* map them to anything and return a value of 0 instead.
|
||||
*/
|
||||
|
||||
enum {
|
||||
GDB_PC = 32 + 0,
|
||||
GDB_MSR = 32 + 1,
|
||||
GDB_EAR = 32 + 2,
|
||||
GDB_ESR = 32 + 3,
|
||||
GDB_FSR = 32 + 4,
|
||||
GDB_BTR = 32 + 5,
|
||||
GDB_PVR0 = 32 + 6,
|
||||
GDB_PVR11 = 32 + 17,
|
||||
GDB_EDR = 32 + 18,
|
||||
GDB_SLR = 32 + 25,
|
||||
GDB_SHR = 32 + 26,
|
||||
};
|
||||
|
||||
int mb_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
|
||||
{
|
||||
MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
|
||||
CPUClass *cc = CPU_GET_CLASS(cs);
|
||||
CPUMBState *env = &cpu->env;
|
||||
/*
|
||||
* GDB expects SREGs in the following order:
|
||||
* PC, MSR, EAR, ESR, FSR, BTR, EDR, PID, ZPR, TLBX, TLBSX, TLBLO, TLBHI.
|
||||
* They aren't stored in this order, so make a map.
|
||||
* PID, ZPR, TLBx, TLBsx, TLBLO, and TLBHI aren't modeled, so we don't
|
||||
* map them to anything and return a value of 0 instead.
|
||||
*/
|
||||
static const uint8_t sreg_map[6] = {
|
||||
SR_PC,
|
||||
SR_MSR,
|
||||
SR_EAR,
|
||||
SR_ESR,
|
||||
SR_FSR,
|
||||
SR_BTR
|
||||
};
|
||||
uint32_t val;
|
||||
|
||||
/*
|
||||
* GDB expects registers to be reported in this order:
|
||||
* R0-R31
|
||||
* PC-BTR
|
||||
* PVR0-PVR11
|
||||
* EDR-TLBHI
|
||||
* SLR-SHR
|
||||
*/
|
||||
if (n < 32) {
|
||||
return gdb_get_reg32(mem_buf, env->regs[n]);
|
||||
} else {
|
||||
n -= 32;
|
||||
switch (n) {
|
||||
case 0 ... 5:
|
||||
return gdb_get_reg32(mem_buf, env->sregs[sreg_map[n]]);
|
||||
/* PVR12 is intentionally skipped */
|
||||
case 6 ... 17:
|
||||
n -= 6;
|
||||
return gdb_get_reg32(mem_buf, env->pvr.regs[n]);
|
||||
case 18:
|
||||
return gdb_get_reg32(mem_buf, env->sregs[SR_EDR]);
|
||||
/* Other SRegs aren't modeled, so report a value of 0 */
|
||||
case 19 ... 24:
|
||||
return gdb_get_reg32(mem_buf, 0);
|
||||
case 25:
|
||||
return gdb_get_reg32(mem_buf, env->slr);
|
||||
case 26:
|
||||
return gdb_get_reg32(mem_buf, env->shr);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
if (n > cc->gdb_num_core_regs) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (n) {
|
||||
case 1 ... 31:
|
||||
val = env->regs[n];
|
||||
break;
|
||||
case GDB_PC:
|
||||
val = env->pc;
|
||||
break;
|
||||
case GDB_MSR:
|
||||
val = mb_cpu_read_msr(env);
|
||||
break;
|
||||
case GDB_EAR:
|
||||
val = env->ear;
|
||||
break;
|
||||
case GDB_ESR:
|
||||
val = env->esr;
|
||||
break;
|
||||
case GDB_FSR:
|
||||
val = env->fsr;
|
||||
break;
|
||||
case GDB_BTR:
|
||||
val = env->btr;
|
||||
break;
|
||||
case GDB_PVR0 ... GDB_PVR11:
|
||||
/* PVR12 is intentionally skipped */
|
||||
val = env->pvr.regs[n - GDB_PVR0];
|
||||
break;
|
||||
case GDB_EDR:
|
||||
val = env->edr;
|
||||
break;
|
||||
case GDB_SLR:
|
||||
val = env->slr;
|
||||
break;
|
||||
case GDB_SHR:
|
||||
val = env->shr;
|
||||
break;
|
||||
default:
|
||||
/* Other SRegs aren't modeled, so report a value of 0 */
|
||||
val = 0;
|
||||
break;
|
||||
}
|
||||
return gdb_get_reg32(mem_buf, val);
|
||||
}
|
||||
|
||||
int mb_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||
@ -82,60 +104,47 @@ int mb_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||
CPUMBState *env = &cpu->env;
|
||||
uint32_t tmp;
|
||||
|
||||
/*
|
||||
* GDB expects SREGs in the following order:
|
||||
* PC, MSR, EAR, ESR, FSR, BTR, EDR, PID, ZPR, TLBX, TLBSX, TLBLO, TLBHI.
|
||||
* They aren't stored in this order, so make a map.
|
||||
* PID, ZPR, TLBx, TLBsx, TLBLO, and TLBHI aren't modeled, so we don't
|
||||
* map them to anything.
|
||||
*/
|
||||
static const uint8_t sreg_map[6] = {
|
||||
SR_PC,
|
||||
SR_MSR,
|
||||
SR_EAR,
|
||||
SR_ESR,
|
||||
SR_FSR,
|
||||
SR_BTR
|
||||
};
|
||||
|
||||
if (n > cc->gdb_num_core_regs) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
tmp = ldl_p(mem_buf);
|
||||
|
||||
/*
|
||||
* GDB expects registers to be reported in this order:
|
||||
* R0-R31
|
||||
* PC-BTR
|
||||
* PVR0-PVR11
|
||||
* EDR-TLBHI
|
||||
* SLR-SHR
|
||||
*/
|
||||
if (n < 32) {
|
||||
switch (n) {
|
||||
case 1 ... 31:
|
||||
env->regs[n] = tmp;
|
||||
} else {
|
||||
n -= 32;
|
||||
switch (n) {
|
||||
case 0 ... 5:
|
||||
env->sregs[sreg_map[n]] = tmp;
|
||||
break;
|
||||
break;
|
||||
case GDB_PC:
|
||||
env->pc = tmp;
|
||||
break;
|
||||
case GDB_MSR:
|
||||
mb_cpu_write_msr(env, tmp);
|
||||
break;
|
||||
case GDB_EAR:
|
||||
env->ear = tmp;
|
||||
break;
|
||||
case GDB_ESR:
|
||||
env->esr = tmp;
|
||||
break;
|
||||
case GDB_FSR:
|
||||
env->fsr = tmp;
|
||||
break;
|
||||
case GDB_BTR:
|
||||
env->btr = tmp;
|
||||
break;
|
||||
case GDB_PVR0 ... GDB_PVR11:
|
||||
/* PVR12 is intentionally skipped */
|
||||
case 6 ... 17:
|
||||
n -= 6;
|
||||
env->pvr.regs[n] = tmp;
|
||||
break;
|
||||
/* Only EDR is modeled in these indeces, so ignore the rest */
|
||||
case 18:
|
||||
env->sregs[SR_EDR] = tmp;
|
||||
break;
|
||||
case 25:
|
||||
env->slr = tmp;
|
||||
break;
|
||||
case 26:
|
||||
env->shr = tmp;
|
||||
break;
|
||||
}
|
||||
env->pvr.regs[n - GDB_PVR0] = tmp;
|
||||
break;
|
||||
case GDB_EDR:
|
||||
env->edr = tmp;
|
||||
break;
|
||||
case GDB_SLR:
|
||||
env->slr = tmp;
|
||||
break;
|
||||
case GDB_SHR:
|
||||
env->shr = tmp;
|
||||
break;
|
||||
}
|
||||
return 4;
|
||||
}
|
||||
|
@ -24,8 +24,6 @@
|
||||
#include "qemu/host-utils.h"
|
||||
#include "exec/log.h"
|
||||
|
||||
#define D(x)
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
|
||||
void mb_cpu_do_interrupt(CPUState *cs)
|
||||
@ -35,7 +33,7 @@ void mb_cpu_do_interrupt(CPUState *cs)
|
||||
|
||||
cs->exception_index = -1;
|
||||
env->res_addr = RES_ADDR_NONE;
|
||||
env->regs[14] = env->sregs[SR_PC];
|
||||
env->regs[14] = env->pc;
|
||||
}
|
||||
|
||||
bool mb_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
@ -85,15 +83,15 @@ bool mb_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
qemu_log_mask(CPU_LOG_MMU, "mmu=%d miss v=%" VADDR_PRIx "\n",
|
||||
mmu_idx, address);
|
||||
|
||||
env->sregs[SR_EAR] = address;
|
||||
env->ear = address;
|
||||
switch (lu.err) {
|
||||
case ERR_PROT:
|
||||
env->sregs[SR_ESR] = access_type == MMU_INST_FETCH ? 17 : 16;
|
||||
env->sregs[SR_ESR] |= (access_type == MMU_DATA_STORE) << 10;
|
||||
env->esr = access_type == MMU_INST_FETCH ? 17 : 16;
|
||||
env->esr |= (access_type == MMU_DATA_STORE) << 10;
|
||||
break;
|
||||
case ERR_MISS:
|
||||
env->sregs[SR_ESR] = access_type == MMU_INST_FETCH ? 19 : 18;
|
||||
env->sregs[SR_ESR] |= (access_type == MMU_DATA_STORE) << 10;
|
||||
env->esr = access_type == MMU_INST_FETCH ? 19 : 18;
|
||||
env->esr |= (access_type == MMU_DATA_STORE) << 10;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
@ -112,12 +110,11 @@ void mb_cpu_do_interrupt(CPUState *cs)
|
||||
{
|
||||
MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
|
||||
CPUMBState *env = &cpu->env;
|
||||
uint32_t t;
|
||||
uint32_t t, msr = mb_cpu_read_msr(env);
|
||||
|
||||
/* IMM flag cannot propagate across a branch and into the dslot. */
|
||||
assert(!((env->iflags & D_FLAG) && (env->iflags & IMM_FLAG)));
|
||||
assert(!(env->iflags & (DRTI_FLAG | DRTE_FLAG | DRTB_FLAG)));
|
||||
/* assert(env->sregs[SR_MSR] & (MSR_EE)); Only for HW exceptions. */
|
||||
env->res_addr = RES_ADDR_NONE;
|
||||
switch (cs->exception_index) {
|
||||
case EXCP_HW_EXCP:
|
||||
@ -126,80 +123,79 @@ void mb_cpu_do_interrupt(CPUState *cs)
|
||||
return;
|
||||
}
|
||||
|
||||
env->regs[17] = env->sregs[SR_PC] + 4;
|
||||
env->sregs[SR_ESR] &= ~(1 << 12);
|
||||
env->regs[17] = env->pc + 4;
|
||||
env->esr &= ~(1 << 12);
|
||||
|
||||
/* Exception breaks branch + dslot sequence? */
|
||||
if (env->iflags & D_FLAG) {
|
||||
env->sregs[SR_ESR] |= 1 << 12 ;
|
||||
env->sregs[SR_BTR] = env->btarget;
|
||||
env->esr |= 1 << 12 ;
|
||||
env->btr = env->btarget;
|
||||
}
|
||||
|
||||
/* Disable the MMU. */
|
||||
t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1;
|
||||
env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM);
|
||||
env->sregs[SR_MSR] |= t;
|
||||
t = (msr & (MSR_VM | MSR_UM)) << 1;
|
||||
msr &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM);
|
||||
msr |= t;
|
||||
/* Exception in progress. */
|
||||
env->sregs[SR_MSR] |= MSR_EIP;
|
||||
msr |= MSR_EIP;
|
||||
mb_cpu_write_msr(env, msr);
|
||||
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"hw exception at pc=%" PRIx64 " ear=%" PRIx64 " "
|
||||
"esr=%" PRIx64 " iflags=%x\n",
|
||||
env->sregs[SR_PC], env->sregs[SR_EAR],
|
||||
env->sregs[SR_ESR], env->iflags);
|
||||
"hw exception at pc=%x ear=%" PRIx64 " "
|
||||
"esr=%x iflags=%x\n",
|
||||
env->pc, env->ear,
|
||||
env->esr, env->iflags);
|
||||
log_cpu_state_mask(CPU_LOG_INT, cs, 0);
|
||||
env->iflags &= ~(IMM_FLAG | D_FLAG);
|
||||
env->sregs[SR_PC] = cpu->cfg.base_vectors + 0x20;
|
||||
env->pc = cpu->cfg.base_vectors + 0x20;
|
||||
break;
|
||||
|
||||
case EXCP_MMU:
|
||||
env->regs[17] = env->sregs[SR_PC];
|
||||
env->regs[17] = env->pc;
|
||||
|
||||
env->sregs[SR_ESR] &= ~(1 << 12);
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"MMU exception at pc=%x iflags=%x ear=%" PRIx64 "\n",
|
||||
env->pc, env->iflags, env->ear);
|
||||
|
||||
env->esr &= ~(1 << 12);
|
||||
/* Exception breaks branch + dslot sequence? */
|
||||
if (env->iflags & D_FLAG) {
|
||||
D(qemu_log("D_FLAG set at exception bimm=%d\n", env->bimm));
|
||||
env->sregs[SR_ESR] |= 1 << 12 ;
|
||||
env->sregs[SR_BTR] = env->btarget;
|
||||
env->esr |= 1 << 12 ;
|
||||
env->btr = env->btarget;
|
||||
|
||||
/* Reexecute the branch. */
|
||||
env->regs[17] -= 4;
|
||||
/* was the branch immprefixed?. */
|
||||
if (env->bimm) {
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"bimm exception at pc=%" PRIx64 " "
|
||||
"iflags=%x\n",
|
||||
env->sregs[SR_PC], env->iflags);
|
||||
if (env->iflags & BIMM_FLAG) {
|
||||
env->regs[17] -= 4;
|
||||
log_cpu_state_mask(CPU_LOG_INT, cs, 0);
|
||||
}
|
||||
} else if (env->iflags & IMM_FLAG) {
|
||||
D(qemu_log("IMM_FLAG set at exception\n"));
|
||||
env->regs[17] -= 4;
|
||||
}
|
||||
|
||||
/* Disable the MMU. */
|
||||
t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1;
|
||||
env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM);
|
||||
env->sregs[SR_MSR] |= t;
|
||||
t = (msr & (MSR_VM | MSR_UM)) << 1;
|
||||
msr &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM);
|
||||
msr |= t;
|
||||
/* Exception in progress. */
|
||||
env->sregs[SR_MSR] |= MSR_EIP;
|
||||
msr |= MSR_EIP;
|
||||
mb_cpu_write_msr(env, msr);
|
||||
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"exception at pc=%" PRIx64 " ear=%" PRIx64 " "
|
||||
"iflags=%x\n",
|
||||
env->sregs[SR_PC], env->sregs[SR_EAR], env->iflags);
|
||||
"exception at pc=%x ear=%" PRIx64 " iflags=%x\n",
|
||||
env->pc, env->ear, env->iflags);
|
||||
log_cpu_state_mask(CPU_LOG_INT, cs, 0);
|
||||
env->iflags &= ~(IMM_FLAG | D_FLAG);
|
||||
env->sregs[SR_PC] = cpu->cfg.base_vectors + 0x20;
|
||||
env->pc = cpu->cfg.base_vectors + 0x20;
|
||||
break;
|
||||
|
||||
case EXCP_IRQ:
|
||||
assert(!(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP)));
|
||||
assert(env->sregs[SR_MSR] & MSR_IE);
|
||||
assert(!(msr & (MSR_EIP | MSR_BIP)));
|
||||
assert(msr & MSR_IE);
|
||||
assert(!(env->iflags & D_FLAG));
|
||||
|
||||
t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1;
|
||||
t = (msr & (MSR_VM | MSR_UM)) << 1;
|
||||
|
||||
#if 0
|
||||
#include "disas/disas.h"
|
||||
@ -209,53 +205,45 @@ void mb_cpu_do_interrupt(CPUState *cs)
|
||||
{
|
||||
const char *sym;
|
||||
|
||||
sym = lookup_symbol(env->sregs[SR_PC]);
|
||||
sym = lookup_symbol(env->pc);
|
||||
if (sym
|
||||
&& (!strcmp("netif_rx", sym)
|
||||
|| !strcmp("process_backlog", sym))) {
|
||||
|
||||
qemu_log(
|
||||
"interrupt at pc=%x msr=%x %x iflags=%x sym=%s\n",
|
||||
env->sregs[SR_PC], env->sregs[SR_MSR], t, env->iflags,
|
||||
sym);
|
||||
qemu_log("interrupt at pc=%x msr=%x %x iflags=%x sym=%s\n",
|
||||
env->pc, msr, t, env->iflags, sym);
|
||||
|
||||
log_cpu_state(cs, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"interrupt at pc=%" PRIx64 " msr=%" PRIx64 " %x "
|
||||
"iflags=%x\n",
|
||||
env->sregs[SR_PC], env->sregs[SR_MSR], t, env->iflags);
|
||||
"interrupt at pc=%x msr=%x %x iflags=%x\n",
|
||||
env->pc, msr, t, env->iflags);
|
||||
|
||||
env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM \
|
||||
| MSR_UM | MSR_IE);
|
||||
env->sregs[SR_MSR] |= t;
|
||||
msr &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM | MSR_IE);
|
||||
msr |= t;
|
||||
mb_cpu_write_msr(env, msr);
|
||||
|
||||
env->regs[14] = env->sregs[SR_PC];
|
||||
env->sregs[SR_PC] = cpu->cfg.base_vectors + 0x10;
|
||||
env->regs[14] = env->pc;
|
||||
env->pc = cpu->cfg.base_vectors + 0x10;
|
||||
//log_cpu_state_mask(CPU_LOG_INT, cs, 0);
|
||||
break;
|
||||
|
||||
case EXCP_BREAK:
|
||||
case EXCP_HW_BREAK:
|
||||
assert(!(env->iflags & IMM_FLAG));
|
||||
assert(!(env->iflags & D_FLAG));
|
||||
t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1;
|
||||
t = (msr & (MSR_VM | MSR_UM)) << 1;
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"break at pc=%" PRIx64 " msr=%" PRIx64 " %x "
|
||||
"iflags=%x\n",
|
||||
env->sregs[SR_PC], env->sregs[SR_MSR], t, env->iflags);
|
||||
"break at pc=%x msr=%x %x iflags=%x\n",
|
||||
env->pc, msr, t, env->iflags);
|
||||
log_cpu_state_mask(CPU_LOG_INT, cs, 0);
|
||||
env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM);
|
||||
env->sregs[SR_MSR] |= t;
|
||||
env->sregs[SR_MSR] |= MSR_BIP;
|
||||
if (cs->exception_index == EXCP_HW_BREAK) {
|
||||
env->regs[16] = env->sregs[SR_PC];
|
||||
env->sregs[SR_MSR] |= MSR_BIP;
|
||||
env->sregs[SR_PC] = cpu->cfg.base_vectors + 0x18;
|
||||
} else
|
||||
env->sregs[SR_PC] = env->btarget;
|
||||
msr &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM);
|
||||
msr |= t;
|
||||
msr |= MSR_BIP;
|
||||
env->regs[16] = env->pc;
|
||||
env->pc = cpu->cfg.base_vectors + 0x18;
|
||||
mb_cpu_write_msr(env, msr);
|
||||
break;
|
||||
default:
|
||||
cpu_abort(cs, "unhandled exception type=%d\n",
|
||||
@ -293,8 +281,8 @@ bool mb_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
|
||||
CPUMBState *env = &cpu->env;
|
||||
|
||||
if ((interrupt_request & CPU_INTERRUPT_HARD)
|
||||
&& (env->sregs[SR_MSR] & MSR_IE)
|
||||
&& !(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP))
|
||||
&& (env->msr & MSR_IE)
|
||||
&& !(env->msr & (MSR_EIP | MSR_BIP))
|
||||
&& !(env->iflags & (D_FLAG | IMM_FLAG))) {
|
||||
cs->exception_index = EXCP_IRQ;
|
||||
mb_cpu_do_interrupt(cs);
|
||||
@ -302,3 +290,31 @@ bool mb_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void mb_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
|
||||
MMUAccessType access_type,
|
||||
int mmu_idx, uintptr_t retaddr)
|
||||
{
|
||||
MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
|
||||
uint32_t esr, iflags;
|
||||
|
||||
/* Recover the pc and iflags from the corresponding insn_start. */
|
||||
cpu_restore_state(cs, retaddr, true);
|
||||
iflags = cpu->env.iflags;
|
||||
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"Unaligned access addr=" TARGET_FMT_lx " pc=%x iflags=%x\n",
|
||||
(target_ulong)addr, cpu->env.pc, iflags);
|
||||
|
||||
esr = ESR_EC_UNALIGNED_DATA;
|
||||
if (likely(iflags & ESR_ESS_FLAG)) {
|
||||
esr |= iflags & ESR_ESS_MASK;
|
||||
} else {
|
||||
qemu_log_mask(LOG_UNIMP, "Unaligned access without ESR_ESS_FLAG\n");
|
||||
}
|
||||
|
||||
cpu->env.ear = addr;
|
||||
cpu->env.esr = esr;
|
||||
cs->exception_index = EXCP_HW_EXCP;
|
||||
cpu_loop_exit(cs);
|
||||
}
|
||||
|
@ -1,36 +1,31 @@
|
||||
DEF_HELPER_2(raise_exception, void, env, i32)
|
||||
DEF_HELPER_1(debug, void, env)
|
||||
DEF_HELPER_FLAGS_3(carry, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32)
|
||||
DEF_HELPER_2(cmp, i32, i32, i32)
|
||||
DEF_HELPER_2(cmpu, i32, i32, i32)
|
||||
DEF_HELPER_FLAGS_2(raise_exception, TCG_CALL_NO_WG, noreturn, env, i32)
|
||||
|
||||
DEF_HELPER_3(divs, i32, env, i32, i32)
|
||||
DEF_HELPER_3(divu, i32, env, i32, i32)
|
||||
DEF_HELPER_FLAGS_3(divs, TCG_CALL_NO_WG, i32, env, i32, i32)
|
||||
DEF_HELPER_FLAGS_3(divu, TCG_CALL_NO_WG, i32, env, i32, i32)
|
||||
|
||||
DEF_HELPER_3(fadd, i32, env, i32, i32)
|
||||
DEF_HELPER_3(frsub, i32, env, i32, i32)
|
||||
DEF_HELPER_3(fmul, i32, env, i32, i32)
|
||||
DEF_HELPER_3(fdiv, i32, env, i32, i32)
|
||||
DEF_HELPER_2(flt, i32, env, i32)
|
||||
DEF_HELPER_2(fint, i32, env, i32)
|
||||
DEF_HELPER_2(fsqrt, i32, env, i32)
|
||||
DEF_HELPER_FLAGS_3(fadd, TCG_CALL_NO_WG, i32, env, i32, i32)
|
||||
DEF_HELPER_FLAGS_3(frsub, TCG_CALL_NO_WG, i32, env, i32, i32)
|
||||
DEF_HELPER_FLAGS_3(fmul, TCG_CALL_NO_WG, i32, env, i32, i32)
|
||||
DEF_HELPER_FLAGS_3(fdiv, TCG_CALL_NO_WG, i32, env, i32, i32)
|
||||
DEF_HELPER_FLAGS_2(flt, TCG_CALL_NO_WG, i32, env, i32)
|
||||
DEF_HELPER_FLAGS_2(fint, TCG_CALL_NO_WG, i32, env, i32)
|
||||
DEF_HELPER_FLAGS_2(fsqrt, TCG_CALL_NO_WG, i32, env, i32)
|
||||
|
||||
DEF_HELPER_3(fcmp_un, i32, env, i32, i32)
|
||||
DEF_HELPER_3(fcmp_lt, i32, env, i32, i32)
|
||||
DEF_HELPER_3(fcmp_eq, i32, env, i32, i32)
|
||||
DEF_HELPER_3(fcmp_le, i32, env, i32, i32)
|
||||
DEF_HELPER_3(fcmp_gt, i32, env, i32, i32)
|
||||
DEF_HELPER_3(fcmp_ne, i32, env, i32, i32)
|
||||
DEF_HELPER_3(fcmp_ge, i32, env, i32, i32)
|
||||
DEF_HELPER_FLAGS_3(fcmp_un, TCG_CALL_NO_WG, i32, env, i32, i32)
|
||||
DEF_HELPER_FLAGS_3(fcmp_lt, TCG_CALL_NO_WG, i32, env, i32, i32)
|
||||
DEF_HELPER_FLAGS_3(fcmp_eq, TCG_CALL_NO_WG, i32, env, i32, i32)
|
||||
DEF_HELPER_FLAGS_3(fcmp_le, TCG_CALL_NO_WG, i32, env, i32, i32)
|
||||
DEF_HELPER_FLAGS_3(fcmp_gt, TCG_CALL_NO_WG, i32, env, i32, i32)
|
||||
DEF_HELPER_FLAGS_3(fcmp_ne, TCG_CALL_NO_WG, i32, env, i32, i32)
|
||||
DEF_HELPER_FLAGS_3(fcmp_ge, TCG_CALL_NO_WG, i32, env, i32, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_2(pcmpbf, TCG_CALL_NO_RWG_SE, i32, i32, i32)
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
DEF_HELPER_3(mmu_read, i32, env, i32, i32)
|
||||
DEF_HELPER_4(mmu_write, void, env, i32, i32, i32)
|
||||
DEF_HELPER_FLAGS_3(mmu_read, TCG_CALL_NO_RWG, i32, env, i32, i32)
|
||||
DEF_HELPER_FLAGS_4(mmu_write, TCG_CALL_NO_RWG, void, env, i32, i32, i32)
|
||||
#endif
|
||||
|
||||
DEF_HELPER_5(memalign, void, env, tl, i32, i32, i32)
|
||||
DEF_HELPER_2(stackprot, void, env, tl)
|
||||
DEF_HELPER_FLAGS_2(stackprot, TCG_CALL_NO_WG, void, env, tl)
|
||||
|
||||
DEF_HELPER_2(get, i32, i32, i32)
|
||||
DEF_HELPER_3(put, void, i32, i32, i32)
|
||||
DEF_HELPER_FLAGS_2(get, TCG_CALL_NO_RWG, i32, i32, i32)
|
||||
DEF_HELPER_FLAGS_3(put, TCG_CALL_NO_RWG, void, i32, i32, i32)
|
||||
|
256
target/microblaze/insns.decode
Normal file
256
target/microblaze/insns.decode
Normal file
@ -0,0 +1,256 @@
|
||||
#
|
||||
# MicroBlaze instruction decode definitions.
|
||||
#
|
||||
# Copyright (c) 2020 Richard Henderson <rth@twiddle.net>
|
||||
#
|
||||
# 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/>.
|
||||
#
|
||||
|
||||
&typea0 rd ra
|
||||
&typea rd ra rb
|
||||
&typea_br rd rb
|
||||
&typea_bc ra rb
|
||||
&typeb rd ra imm
|
||||
&typeb_br rd imm
|
||||
&typeb_bc ra imm
|
||||
&type_msr rd imm
|
||||
|
||||
# Include any IMM prefix in the value reported.
|
||||
%extimm 0:s16 !function=typeb_imm
|
||||
|
||||
@typea ...... rd:5 ra:5 rb:5 ... .... .... &typea
|
||||
@typeb ...... rd:5 ra:5 ................ &typeb imm=%extimm
|
||||
|
||||
# Officially typea, but with rb==0, which is not used.
|
||||
@typea0 ...... rd:5 ra:5 ................ &typea0
|
||||
|
||||
# Officially typea, but with ra as opcode.
|
||||
@typea_br ...... rd:5 ..... rb:5 ........... &typea_br
|
||||
|
||||
# Officially typea, but with rd as opcode.
|
||||
@typea_bc ...... ..... ra:5 rb:5 ........... &typea_bc
|
||||
|
||||
# Officially typeb, but any immediate extension is unused.
|
||||
@typeb_bs ...... rd:5 ra:5 ..... ...... imm:5 &typeb
|
||||
|
||||
# Officially typeb, but with ra as opcode.
|
||||
@typeb_br ...... rd:5 ..... ................ &typeb_br imm=%extimm
|
||||
|
||||
# Officially typeb, but with rd as opcode.
|
||||
@typeb_bc ...... ..... ra:5 ................ &typeb_bc imm=%extimm
|
||||
|
||||
# For convenience, extract the two imm_w/imm_s fields, then pack
|
||||
# them back together as "imm". Doing this makes it easiest to
|
||||
# match the required zero at bit 5.
|
||||
%ieimm 6:5 0:5
|
||||
@typeb_ie ...... rd:5 ra:5 ..... ..... . ..... &typeb imm=%ieimm
|
||||
|
||||
@type_msr ...... rd:5 ...... imm:15 &type_msr
|
||||
|
||||
###
|
||||
|
||||
{
|
||||
zero 000000 00000 00000 00000 000 0000 0000
|
||||
add 000000 ..... ..... ..... 000 0000 0000 @typea
|
||||
}
|
||||
addc 000010 ..... ..... ..... 000 0000 0000 @typea
|
||||
addk 000100 ..... ..... ..... 000 0000 0000 @typea
|
||||
addkc 000110 ..... ..... ..... 000 0000 0000 @typea
|
||||
|
||||
addi 001000 ..... ..... ................ @typeb
|
||||
addic 001010 ..... ..... ................ @typeb
|
||||
addik 001100 ..... ..... ................ @typeb
|
||||
addikc 001110 ..... ..... ................ @typeb
|
||||
|
||||
and 100001 ..... ..... ..... 000 0000 0000 @typea
|
||||
andi 101001 ..... ..... ................ @typeb
|
||||
|
||||
andn 100011 ..... ..... ..... 000 0000 0000 @typea
|
||||
andni 101011 ..... ..... ................ @typeb
|
||||
|
||||
beq 100111 00000 ..... ..... 000 0000 0000 @typea_bc
|
||||
bge 100111 00101 ..... ..... 000 0000 0000 @typea_bc
|
||||
bgt 100111 00100 ..... ..... 000 0000 0000 @typea_bc
|
||||
ble 100111 00011 ..... ..... 000 0000 0000 @typea_bc
|
||||
blt 100111 00010 ..... ..... 000 0000 0000 @typea_bc
|
||||
bne 100111 00001 ..... ..... 000 0000 0000 @typea_bc
|
||||
|
||||
beqd 100111 10000 ..... ..... 000 0000 0000 @typea_bc
|
||||
bged 100111 10101 ..... ..... 000 0000 0000 @typea_bc
|
||||
bgtd 100111 10100 ..... ..... 000 0000 0000 @typea_bc
|
||||
bled 100111 10011 ..... ..... 000 0000 0000 @typea_bc
|
||||
bltd 100111 10010 ..... ..... 000 0000 0000 @typea_bc
|
||||
bned 100111 10001 ..... ..... 000 0000 0000 @typea_bc
|
||||
|
||||
beqi 101111 00000 ..... ................ @typeb_bc
|
||||
bgei 101111 00101 ..... ................ @typeb_bc
|
||||
bgti 101111 00100 ..... ................ @typeb_bc
|
||||
blei 101111 00011 ..... ................ @typeb_bc
|
||||
blti 101111 00010 ..... ................ @typeb_bc
|
||||
bnei 101111 00001 ..... ................ @typeb_bc
|
||||
|
||||
beqid 101111 10000 ..... ................ @typeb_bc
|
||||
bgeid 101111 10101 ..... ................ @typeb_bc
|
||||
bgtid 101111 10100 ..... ................ @typeb_bc
|
||||
bleid 101111 10011 ..... ................ @typeb_bc
|
||||
bltid 101111 10010 ..... ................ @typeb_bc
|
||||
bneid 101111 10001 ..... ................ @typeb_bc
|
||||
|
||||
br 100110 ..... 00000 ..... 000 0000 0000 @typea_br
|
||||
bra 100110 ..... 01000 ..... 000 0000 0000 @typea_br
|
||||
brd 100110 ..... 10000 ..... 000 0000 0000 @typea_br
|
||||
brad 100110 ..... 11000 ..... 000 0000 0000 @typea_br
|
||||
brld 100110 ..... 10100 ..... 000 0000 0000 @typea_br
|
||||
brald 100110 ..... 11100 ..... 000 0000 0000 @typea_br
|
||||
|
||||
bri 101110 ..... 00000 ................ @typeb_br
|
||||
brai 101110 ..... 01000 ................ @typeb_br
|
||||
brid 101110 ..... 10000 ................ @typeb_br
|
||||
braid 101110 ..... 11000 ................ @typeb_br
|
||||
brlid 101110 ..... 10100 ................ @typeb_br
|
||||
bralid 101110 ..... 11100 ................ @typeb_br
|
||||
|
||||
brk 100110 ..... 01100 ..... 000 0000 0000 @typea_br
|
||||
brki 101110 ..... 01100 ................ @typeb_br
|
||||
|
||||
bsrl 010001 ..... ..... ..... 000 0000 0000 @typea
|
||||
bsra 010001 ..... ..... ..... 010 0000 0000 @typea
|
||||
bsll 010001 ..... ..... ..... 100 0000 0000 @typea
|
||||
|
||||
bsrli 011001 ..... ..... 00000 000000 ..... @typeb_bs
|
||||
bsrai 011001 ..... ..... 00000 010000 ..... @typeb_bs
|
||||
bslli 011001 ..... ..... 00000 100000 ..... @typeb_bs
|
||||
|
||||
bsefi 011001 ..... ..... 01000 .....0 ..... @typeb_ie
|
||||
bsifi 011001 ..... ..... 10000 .....0 ..... @typeb_ie
|
||||
|
||||
clz 100100 ..... ..... 00000 000 1110 0000 @typea0
|
||||
|
||||
cmp 000101 ..... ..... ..... 000 0000 0001 @typea
|
||||
cmpu 000101 ..... ..... ..... 000 0000 0011 @typea
|
||||
|
||||
fadd 010110 ..... ..... ..... 0000 000 0000 @typea
|
||||
frsub 010110 ..... ..... ..... 0001 000 0000 @typea
|
||||
fmul 010110 ..... ..... ..... 0010 000 0000 @typea
|
||||
fdiv 010110 ..... ..... ..... 0011 000 0000 @typea
|
||||
fcmp_un 010110 ..... ..... ..... 0100 000 0000 @typea
|
||||
fcmp_lt 010110 ..... ..... ..... 0100 001 0000 @typea
|
||||
fcmp_eq 010110 ..... ..... ..... 0100 010 0000 @typea
|
||||
fcmp_le 010110 ..... ..... ..... 0100 011 0000 @typea
|
||||
fcmp_gt 010110 ..... ..... ..... 0100 100 0000 @typea
|
||||
fcmp_ne 010110 ..... ..... ..... 0100 101 0000 @typea
|
||||
fcmp_ge 010110 ..... ..... ..... 0100 110 0000 @typea
|
||||
|
||||
# Note that flt and fint, unlike fsqrt, are documented as having the RB
|
||||
# operand which is unused. So allow the field to be non-zero but discard
|
||||
# the value and treat as 2-operand insns.
|
||||
flt 010110 ..... ..... ----- 0101 000 0000 @typea0
|
||||
fint 010110 ..... ..... ----- 0110 000 0000 @typea0
|
||||
fsqrt 010110 ..... ..... 00000 0111 000 0000 @typea0
|
||||
|
||||
get 011011 rd:5 00000 0 ctrl:5 000000 imm:4
|
||||
getd 010011 rd:5 00000 rb:5 0 ctrl:5 00000
|
||||
|
||||
idiv 010010 ..... ..... ..... 000 0000 0000 @typea
|
||||
idivu 010010 ..... ..... ..... 000 0000 0010 @typea
|
||||
|
||||
imm 101100 00000 00000 imm:16
|
||||
|
||||
lbu 110000 ..... ..... ..... 0000 000 0000 @typea
|
||||
lbur 110000 ..... ..... ..... 0100 000 0000 @typea
|
||||
lbuea 110000 ..... ..... ..... 0001 000 0000 @typea
|
||||
lbui 111000 ..... ..... ................ @typeb
|
||||
|
||||
lhu 110001 ..... ..... ..... 0000 000 0000 @typea
|
||||
lhur 110001 ..... ..... ..... 0100 000 0000 @typea
|
||||
lhuea 110001 ..... ..... ..... 0001 000 0000 @typea
|
||||
lhui 111001 ..... ..... ................ @typeb
|
||||
|
||||
lw 110010 ..... ..... ..... 0000 000 0000 @typea
|
||||
lwr 110010 ..... ..... ..... 0100 000 0000 @typea
|
||||
lwea 110010 ..... ..... ..... 0001 000 0000 @typea
|
||||
lwx 110010 ..... ..... ..... 1000 000 0000 @typea
|
||||
lwi 111010 ..... ..... ................ @typeb
|
||||
|
||||
mbar 101110 imm:5 00010 0000 0000 0000 0100
|
||||
|
||||
mfs 100101 rd:5 0 e:1 000 10 rs:14
|
||||
mts 100101 0 e:1 000 ra:5 11 rs:14
|
||||
|
||||
msrclr 100101 ..... 100010 ............... @type_msr
|
||||
msrset 100101 ..... 100000 ............... @type_msr
|
||||
|
||||
mul 010000 ..... ..... ..... 000 0000 0000 @typea
|
||||
mulh 010000 ..... ..... ..... 000 0000 0001 @typea
|
||||
mulhu 010000 ..... ..... ..... 000 0000 0011 @typea
|
||||
mulhsu 010000 ..... ..... ..... 000 0000 0010 @typea
|
||||
muli 011000 ..... ..... ................ @typeb
|
||||
|
||||
or 100000 ..... ..... ..... 000 0000 0000 @typea
|
||||
ori 101000 ..... ..... ................ @typeb
|
||||
|
||||
pcmpbf 100000 ..... ..... ..... 100 0000 0000 @typea
|
||||
pcmpeq 100010 ..... ..... ..... 100 0000 0000 @typea
|
||||
pcmpne 100011 ..... ..... ..... 100 0000 0000 @typea
|
||||
|
||||
put 011011 00000 ra:5 1 ctrl:5 000000 imm:4
|
||||
putd 010011 00000 ra:5 rb:5 1 ctrl:5 00000
|
||||
|
||||
rsub 000001 ..... ..... ..... 000 0000 0000 @typea
|
||||
rsubc 000011 ..... ..... ..... 000 0000 0000 @typea
|
||||
rsubk 000101 ..... ..... ..... 000 0000 0000 @typea
|
||||
rsubkc 000111 ..... ..... ..... 000 0000 0000 @typea
|
||||
|
||||
rsubi 001001 ..... ..... ................ @typeb
|
||||
rsubic 001011 ..... ..... ................ @typeb
|
||||
rsubik 001101 ..... ..... ................ @typeb
|
||||
rsubikc 001111 ..... ..... ................ @typeb
|
||||
|
||||
rtbd 101101 10010 ..... ................ @typeb_bc
|
||||
rtid 101101 10001 ..... ................ @typeb_bc
|
||||
rted 101101 10100 ..... ................ @typeb_bc
|
||||
rtsd 101101 10000 ..... ................ @typeb_bc
|
||||
|
||||
sb 110100 ..... ..... ..... 0000 000 0000 @typea
|
||||
sbr 110100 ..... ..... ..... 0100 000 0000 @typea
|
||||
sbea 110100 ..... ..... ..... 0001 000 0000 @typea
|
||||
sbi 111100 ..... ..... ................ @typeb
|
||||
|
||||
sh 110101 ..... ..... ..... 0000 000 0000 @typea
|
||||
shr 110101 ..... ..... ..... 0100 000 0000 @typea
|
||||
shea 110101 ..... ..... ..... 0001 000 0000 @typea
|
||||
shi 111101 ..... ..... ................ @typeb
|
||||
|
||||
sw 110110 ..... ..... ..... 0000 000 0000 @typea
|
||||
swr 110110 ..... ..... ..... 0100 000 0000 @typea
|
||||
swea 110110 ..... ..... ..... 0001 000 0000 @typea
|
||||
swx 110110 ..... ..... ..... 1000 000 0000 @typea
|
||||
swi 111110 ..... ..... ................ @typeb
|
||||
|
||||
sext8 100100 ..... ..... 00000 000 0110 0000 @typea0
|
||||
sext16 100100 ..... ..... 00000 000 0110 0001 @typea0
|
||||
|
||||
sra 100100 ..... ..... 00000 000 0000 0001 @typea0
|
||||
src 100100 ..... ..... 00000 000 0010 0001 @typea0
|
||||
srl 100100 ..... ..... 00000 000 0100 0001 @typea0
|
||||
|
||||
swapb 100100 ..... ..... 00000 001 1110 0000 @typea0
|
||||
swaph 100100 ..... ..... 00000 001 1110 0010 @typea0
|
||||
|
||||
# Cache operations have no effect in qemu: discard the arguments.
|
||||
wdic 100100 00000 ----- ----- -00 -11- 01-0 # wdc
|
||||
wdic 100100 00000 ----- ----- 000 0110 1000 # wic
|
||||
|
||||
xor 100010 ..... ..... ..... 000 0000 0000 @typea
|
||||
xori 101010 ..... ..... ................ @typeb
|
@ -1,4 +1,7 @@
|
||||
gen = decodetree.process('insns.decode')
|
||||
|
||||
microblaze_ss = ss.source_set()
|
||||
microblaze_ss.add(gen)
|
||||
microblaze_ss.add(files(
|
||||
'cpu.c',
|
||||
'gdbstub.c',
|
||||
|
@ -1,59 +0,0 @@
|
||||
/*
|
||||
* MicroBlaze insn decoding macros.
|
||||
*
|
||||
* Copyright (c) 2009 Edgar E. Iglesias <edgar.iglesias@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 TARGET_MICROBLAZE_MICROBLAZE_DECODE_H
|
||||
#define TARGET_MICROBLAZE_MICROBLAZE_DECODE_H
|
||||
|
||||
/* Convenient binary macros. */
|
||||
#define HEX__(n) 0x##n##LU
|
||||
#define B8__(x) ((x&0x0000000FLU)?1:0) \
|
||||
+ ((x&0x000000F0LU)?2:0) \
|
||||
+ ((x&0x00000F00LU)?4:0) \
|
||||
+ ((x&0x0000F000LU)?8:0) \
|
||||
+ ((x&0x000F0000LU)?16:0) \
|
||||
+ ((x&0x00F00000LU)?32:0) \
|
||||
+ ((x&0x0F000000LU)?64:0) \
|
||||
+ ((x&0xF0000000LU)?128:0)
|
||||
#define B8(d) ((unsigned char)B8__(HEX__(d)))
|
||||
|
||||
/* Decode logic, value and mask. */
|
||||
#define DEC_ADD {B8(00000000), B8(00110001)}
|
||||
#define DEC_SUB {B8(00000001), B8(00110001)}
|
||||
#define DEC_AND {B8(00100001), B8(00110101)}
|
||||
#define DEC_XOR {B8(00100010), B8(00110111)}
|
||||
#define DEC_OR {B8(00100000), B8(00110111)}
|
||||
#define DEC_BIT {B8(00100100), B8(00111111)}
|
||||
#define DEC_MSR {B8(00100101), B8(00111111)}
|
||||
|
||||
#define DEC_BARREL {B8(00010001), B8(00110111)}
|
||||
#define DEC_MUL {B8(00010000), B8(00110111)}
|
||||
#define DEC_DIV {B8(00010010), B8(00110111)}
|
||||
#define DEC_FPU {B8(00010110), B8(00111111)}
|
||||
|
||||
#define DEC_LD {B8(00110000), B8(00110100)}
|
||||
#define DEC_ST {B8(00110100), B8(00110100)}
|
||||
#define DEC_IMM {B8(00101100), B8(00111111)}
|
||||
|
||||
#define DEC_BR {B8(00100110), B8(00110111)}
|
||||
#define DEC_BCC {B8(00100111), B8(00110111)}
|
||||
#define DEC_RTS {B8(00101101), B8(00111111)}
|
||||
|
||||
#define DEC_STREAM {B8(00010011), B8(00110111)}
|
||||
|
||||
#endif
|
@ -250,8 +250,8 @@ void mmu_write(CPUMBState *env, bool ext, uint32_t rn, uint32_t v)
|
||||
if (rn == MMU_R_TLBHI) {
|
||||
if (i < 3 && !(v & TLB_VALID) && qemu_loglevel_mask(~0))
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"invalidating index %x at pc=%" PRIx64 "\n",
|
||||
i, env->sregs[SR_PC]);
|
||||
"invalidating index %x at pc=%x\n",
|
||||
i, env->pc);
|
||||
env->mmu.tids[i] = env->mmu.regs[MMU_R_PID] & 0xff;
|
||||
mmu_flush_idx(env, i);
|
||||
}
|
||||
|
@ -26,8 +26,6 @@
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "fpu/softfloat.h"
|
||||
|
||||
#define D(x)
|
||||
|
||||
void helper_put(uint32_t id, uint32_t ctrl, uint32_t data)
|
||||
{
|
||||
int test = ctrl & STREAM_TEST;
|
||||
@ -71,85 +69,27 @@ void helper_raise_exception(CPUMBState *env, uint32_t index)
|
||||
cpu_loop_exit(cs);
|
||||
}
|
||||
|
||||
void helper_debug(CPUMBState *env)
|
||||
static bool check_divz(CPUMBState *env, uint32_t a, uint32_t b, uintptr_t ra)
|
||||
{
|
||||
int i;
|
||||
if (unlikely(b == 0)) {
|
||||
env->msr |= MSR_DZ;
|
||||
|
||||
qemu_log("PC=%" PRIx64 "\n", env->sregs[SR_PC]);
|
||||
qemu_log("rmsr=%" PRIx64 " resr=%" PRIx64 " rear=%" PRIx64 " "
|
||||
"debug[%x] imm=%x iflags=%x\n",
|
||||
env->sregs[SR_MSR], env->sregs[SR_ESR], env->sregs[SR_EAR],
|
||||
env->debug, env->imm, env->iflags);
|
||||
qemu_log("btaken=%d btarget=%" PRIx64 " mode=%s(saved=%s) eip=%d ie=%d\n",
|
||||
env->btaken, env->btarget,
|
||||
(env->sregs[SR_MSR] & MSR_UM) ? "user" : "kernel",
|
||||
(env->sregs[SR_MSR] & MSR_UMS) ? "user" : "kernel",
|
||||
(bool)(env->sregs[SR_MSR] & MSR_EIP),
|
||||
(bool)(env->sregs[SR_MSR] & MSR_IE));
|
||||
for (i = 0; i < 32; i++) {
|
||||
qemu_log("r%2.2d=%8.8x ", i, env->regs[i]);
|
||||
if ((i + 1) % 4 == 0)
|
||||
qemu_log("\n");
|
||||
}
|
||||
qemu_log("\n\n");
|
||||
}
|
||||
if ((env->msr & MSR_EE) &&
|
||||
env_archcpu(env)->cfg.div_zero_exception) {
|
||||
CPUState *cs = env_cpu(env);
|
||||
|
||||
static inline uint32_t compute_carry(uint32_t a, uint32_t b, uint32_t cin)
|
||||
{
|
||||
uint32_t cout = 0;
|
||||
|
||||
if ((b == ~0) && cin)
|
||||
cout = 1;
|
||||
else if ((~0 - a) < (b + cin))
|
||||
cout = 1;
|
||||
return cout;
|
||||
}
|
||||
|
||||
uint32_t helper_cmp(uint32_t a, uint32_t b)
|
||||
{
|
||||
uint32_t t;
|
||||
|
||||
t = b + ~a + 1;
|
||||
if ((b & 0x80000000) ^ (a & 0x80000000))
|
||||
t = (t & 0x7fffffff) | (b & 0x80000000);
|
||||
return t;
|
||||
}
|
||||
|
||||
uint32_t helper_cmpu(uint32_t a, uint32_t b)
|
||||
{
|
||||
uint32_t t;
|
||||
|
||||
t = b + ~a + 1;
|
||||
if ((b & 0x80000000) ^ (a & 0x80000000))
|
||||
t = (t & 0x7fffffff) | (a & 0x80000000);
|
||||
return t;
|
||||
}
|
||||
|
||||
uint32_t helper_carry(uint32_t a, uint32_t b, uint32_t cf)
|
||||
{
|
||||
return compute_carry(a, b, cf);
|
||||
}
|
||||
|
||||
static inline int div_prepare(CPUMBState *env, uint32_t a, uint32_t b)
|
||||
{
|
||||
MicroBlazeCPU *cpu = env_archcpu(env);
|
||||
|
||||
if (b == 0) {
|
||||
env->sregs[SR_MSR] |= MSR_DZ;
|
||||
|
||||
if ((env->sregs[SR_MSR] & MSR_EE) && cpu->cfg.div_zero_exception) {
|
||||
env->sregs[SR_ESR] = ESR_EC_DIVZERO;
|
||||
helper_raise_exception(env, EXCP_HW_EXCP);
|
||||
env->esr = ESR_EC_DIVZERO;
|
||||
cs->exception_index = EXCP_HW_EXCP;
|
||||
cpu_loop_exit_restore(cs, ra);
|
||||
}
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
env->sregs[SR_MSR] &= ~MSR_DZ;
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t helper_divs(CPUMBState *env, uint32_t a, uint32_t b)
|
||||
{
|
||||
if (!div_prepare(env, a, b)) {
|
||||
if (!check_divz(env, a, b, GETPC())) {
|
||||
return 0;
|
||||
}
|
||||
return (int32_t)a / (int32_t)b;
|
||||
@ -157,43 +97,46 @@ uint32_t helper_divs(CPUMBState *env, uint32_t a, uint32_t b)
|
||||
|
||||
uint32_t helper_divu(CPUMBState *env, uint32_t a, uint32_t b)
|
||||
{
|
||||
if (!div_prepare(env, a, b)) {
|
||||
if (!check_divz(env, a, b, GETPC())) {
|
||||
return 0;
|
||||
}
|
||||
return a / b;
|
||||
}
|
||||
|
||||
/* raise FPU exception. */
|
||||
static void raise_fpu_exception(CPUMBState *env)
|
||||
static void raise_fpu_exception(CPUMBState *env, uintptr_t ra)
|
||||
{
|
||||
env->sregs[SR_ESR] = ESR_EC_FPU;
|
||||
helper_raise_exception(env, EXCP_HW_EXCP);
|
||||
CPUState *cs = env_cpu(env);
|
||||
|
||||
env->esr = ESR_EC_FPU;
|
||||
cs->exception_index = EXCP_HW_EXCP;
|
||||
cpu_loop_exit_restore(cs, ra);
|
||||
}
|
||||
|
||||
static void update_fpu_flags(CPUMBState *env, int flags)
|
||||
static void update_fpu_flags(CPUMBState *env, int flags, uintptr_t ra)
|
||||
{
|
||||
int raise = 0;
|
||||
|
||||
if (flags & float_flag_invalid) {
|
||||
env->sregs[SR_FSR] |= FSR_IO;
|
||||
env->fsr |= FSR_IO;
|
||||
raise = 1;
|
||||
}
|
||||
if (flags & float_flag_divbyzero) {
|
||||
env->sregs[SR_FSR] |= FSR_DZ;
|
||||
env->fsr |= FSR_DZ;
|
||||
raise = 1;
|
||||
}
|
||||
if (flags & float_flag_overflow) {
|
||||
env->sregs[SR_FSR] |= FSR_OF;
|
||||
env->fsr |= FSR_OF;
|
||||
raise = 1;
|
||||
}
|
||||
if (flags & float_flag_underflow) {
|
||||
env->sregs[SR_FSR] |= FSR_UF;
|
||||
env->fsr |= FSR_UF;
|
||||
raise = 1;
|
||||
}
|
||||
if (raise
|
||||
&& (env->pvr.regs[2] & PVR2_FPU_EXC_MASK)
|
||||
&& (env->sregs[SR_MSR] & MSR_EE)) {
|
||||
raise_fpu_exception(env);
|
||||
&& (env->msr & MSR_EE)) {
|
||||
raise_fpu_exception(env, ra);
|
||||
}
|
||||
}
|
||||
|
||||
@ -208,7 +151,7 @@ uint32_t helper_fadd(CPUMBState *env, uint32_t a, uint32_t b)
|
||||
fd.f = float32_add(fa.f, fb.f, &env->fp_status);
|
||||
|
||||
flags = get_float_exception_flags(&env->fp_status);
|
||||
update_fpu_flags(env, flags);
|
||||
update_fpu_flags(env, flags, GETPC());
|
||||
return fd.l;
|
||||
}
|
||||
|
||||
@ -222,7 +165,7 @@ uint32_t helper_frsub(CPUMBState *env, uint32_t a, uint32_t b)
|
||||
fb.l = b;
|
||||
fd.f = float32_sub(fb.f, fa.f, &env->fp_status);
|
||||
flags = get_float_exception_flags(&env->fp_status);
|
||||
update_fpu_flags(env, flags);
|
||||
update_fpu_flags(env, flags, GETPC());
|
||||
return fd.l;
|
||||
}
|
||||
|
||||
@ -236,7 +179,7 @@ uint32_t helper_fmul(CPUMBState *env, uint32_t a, uint32_t b)
|
||||
fb.l = b;
|
||||
fd.f = float32_mul(fa.f, fb.f, &env->fp_status);
|
||||
flags = get_float_exception_flags(&env->fp_status);
|
||||
update_fpu_flags(env, flags);
|
||||
update_fpu_flags(env, flags, GETPC());
|
||||
|
||||
return fd.l;
|
||||
}
|
||||
@ -251,7 +194,7 @@ uint32_t helper_fdiv(CPUMBState *env, uint32_t a, uint32_t b)
|
||||
fb.l = b;
|
||||
fd.f = float32_div(fb.f, fa.f, &env->fp_status);
|
||||
flags = get_float_exception_flags(&env->fp_status);
|
||||
update_fpu_flags(env, flags);
|
||||
update_fpu_flags(env, flags, GETPC());
|
||||
|
||||
return fd.l;
|
||||
}
|
||||
@ -266,7 +209,7 @@ uint32_t helper_fcmp_un(CPUMBState *env, uint32_t a, uint32_t b)
|
||||
|
||||
if (float32_is_signaling_nan(fa.f, &env->fp_status) ||
|
||||
float32_is_signaling_nan(fb.f, &env->fp_status)) {
|
||||
update_fpu_flags(env, float_flag_invalid);
|
||||
update_fpu_flags(env, float_flag_invalid, GETPC());
|
||||
r = 1;
|
||||
}
|
||||
|
||||
@ -289,7 +232,7 @@ uint32_t helper_fcmp_lt(CPUMBState *env, uint32_t a, uint32_t b)
|
||||
fb.l = b;
|
||||
r = float32_lt(fb.f, fa.f, &env->fp_status);
|
||||
flags = get_float_exception_flags(&env->fp_status);
|
||||
update_fpu_flags(env, flags & float_flag_invalid);
|
||||
update_fpu_flags(env, flags & float_flag_invalid, GETPC());
|
||||
|
||||
return r;
|
||||
}
|
||||
@ -305,7 +248,7 @@ uint32_t helper_fcmp_eq(CPUMBState *env, uint32_t a, uint32_t b)
|
||||
fb.l = b;
|
||||
r = float32_eq_quiet(fa.f, fb.f, &env->fp_status);
|
||||
flags = get_float_exception_flags(&env->fp_status);
|
||||
update_fpu_flags(env, flags & float_flag_invalid);
|
||||
update_fpu_flags(env, flags & float_flag_invalid, GETPC());
|
||||
|
||||
return r;
|
||||
}
|
||||
@ -321,7 +264,7 @@ uint32_t helper_fcmp_le(CPUMBState *env, uint32_t a, uint32_t b)
|
||||
set_float_exception_flags(0, &env->fp_status);
|
||||
r = float32_le(fa.f, fb.f, &env->fp_status);
|
||||
flags = get_float_exception_flags(&env->fp_status);
|
||||
update_fpu_flags(env, flags & float_flag_invalid);
|
||||
update_fpu_flags(env, flags & float_flag_invalid, GETPC());
|
||||
|
||||
|
||||
return r;
|
||||
@ -337,7 +280,7 @@ uint32_t helper_fcmp_gt(CPUMBState *env, uint32_t a, uint32_t b)
|
||||
set_float_exception_flags(0, &env->fp_status);
|
||||
r = float32_lt(fa.f, fb.f, &env->fp_status);
|
||||
flags = get_float_exception_flags(&env->fp_status);
|
||||
update_fpu_flags(env, flags & float_flag_invalid);
|
||||
update_fpu_flags(env, flags & float_flag_invalid, GETPC());
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -351,7 +294,7 @@ uint32_t helper_fcmp_ne(CPUMBState *env, uint32_t a, uint32_t b)
|
||||
set_float_exception_flags(0, &env->fp_status);
|
||||
r = !float32_eq_quiet(fa.f, fb.f, &env->fp_status);
|
||||
flags = get_float_exception_flags(&env->fp_status);
|
||||
update_fpu_flags(env, flags & float_flag_invalid);
|
||||
update_fpu_flags(env, flags & float_flag_invalid, GETPC());
|
||||
|
||||
return r;
|
||||
}
|
||||
@ -366,7 +309,7 @@ uint32_t helper_fcmp_ge(CPUMBState *env, uint32_t a, uint32_t b)
|
||||
set_float_exception_flags(0, &env->fp_status);
|
||||
r = !float32_lt(fa.f, fb.f, &env->fp_status);
|
||||
flags = get_float_exception_flags(&env->fp_status);
|
||||
update_fpu_flags(env, flags & float_flag_invalid);
|
||||
update_fpu_flags(env, flags & float_flag_invalid, GETPC());
|
||||
|
||||
return r;
|
||||
}
|
||||
@ -390,7 +333,7 @@ uint32_t helper_fint(CPUMBState *env, uint32_t a)
|
||||
fa.l = a;
|
||||
r = float32_to_int32(fa.f, &env->fp_status);
|
||||
flags = get_float_exception_flags(&env->fp_status);
|
||||
update_fpu_flags(env, flags);
|
||||
update_fpu_flags(env, flags, GETPC());
|
||||
|
||||
return r;
|
||||
}
|
||||
@ -404,7 +347,7 @@ uint32_t helper_fsqrt(CPUMBState *env, uint32_t a)
|
||||
fa.l = a;
|
||||
fd.l = float32_sqrt(fa.f, &env->fp_status);
|
||||
flags = get_float_exception_flags(&env->fp_status);
|
||||
update_fpu_flags(env, flags);
|
||||
update_fpu_flags(env, flags, GETPC());
|
||||
|
||||
return fd.l;
|
||||
}
|
||||
@ -422,37 +365,19 @@ uint32_t helper_pcmpbf(uint32_t a, uint32_t b)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void helper_memalign(CPUMBState *env, target_ulong addr,
|
||||
uint32_t dr, uint32_t wr,
|
||||
uint32_t mask)
|
||||
{
|
||||
if (addr & mask) {
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"unaligned access addr=" TARGET_FMT_lx
|
||||
" mask=%x, wr=%d dr=r%d\n",
|
||||
addr, mask, wr, dr);
|
||||
env->sregs[SR_EAR] = addr;
|
||||
env->sregs[SR_ESR] = ESR_EC_UNALIGNED_DATA | (wr << 10) \
|
||||
| (dr & 31) << 5;
|
||||
if (mask == 3) {
|
||||
env->sregs[SR_ESR] |= 1 << 11;
|
||||
}
|
||||
if (!(env->sregs[SR_MSR] & MSR_EE)) {
|
||||
return;
|
||||
}
|
||||
helper_raise_exception(env, EXCP_HW_EXCP);
|
||||
}
|
||||
}
|
||||
|
||||
void helper_stackprot(CPUMBState *env, target_ulong addr)
|
||||
{
|
||||
if (addr < env->slr || addr > env->shr) {
|
||||
CPUState *cs = env_cpu(env);
|
||||
|
||||
qemu_log_mask(CPU_LOG_INT, "Stack protector violation at "
|
||||
TARGET_FMT_lx " %x %x\n",
|
||||
addr, env->slr, env->shr);
|
||||
env->sregs[SR_EAR] = addr;
|
||||
env->sregs[SR_ESR] = ESR_EC_STACKPROT;
|
||||
helper_raise_exception(env, EXCP_HW_EXCP);
|
||||
|
||||
env->ear = addr;
|
||||
env->esr = ESR_EC_STACKPROT;
|
||||
cs->exception_index = EXCP_HW_EXCP;
|
||||
cpu_loop_exit_restore(cs, GETPC());
|
||||
}
|
||||
}
|
||||
|
||||
@ -473,32 +398,33 @@ void mb_cpu_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr,
|
||||
int mmu_idx, MemTxAttrs attrs,
|
||||
MemTxResult response, uintptr_t retaddr)
|
||||
{
|
||||
MicroBlazeCPU *cpu;
|
||||
CPUMBState *env;
|
||||
MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
|
||||
CPUMBState *env = &cpu->env;
|
||||
|
||||
qemu_log_mask(CPU_LOG_INT, "Transaction failed: vaddr 0x%" VADDR_PRIx
|
||||
" physaddr 0x" TARGET_FMT_plx " size %d access type %s\n",
|
||||
addr, physaddr, size,
|
||||
access_type == MMU_INST_FETCH ? "INST_FETCH" :
|
||||
(access_type == MMU_DATA_LOAD ? "DATA_LOAD" : "DATA_STORE"));
|
||||
cpu = MICROBLAZE_CPU(cs);
|
||||
env = &cpu->env;
|
||||
|
||||
cpu_restore_state(cs, retaddr, true);
|
||||
if (!(env->sregs[SR_MSR] & MSR_EE)) {
|
||||
if (!(env->msr & MSR_EE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
env->sregs[SR_EAR] = addr;
|
||||
if (access_type == MMU_INST_FETCH) {
|
||||
if ((env->pvr.regs[2] & PVR2_IOPB_BUS_EXC_MASK)) {
|
||||
env->sregs[SR_ESR] = ESR_EC_INSN_BUS;
|
||||
helper_raise_exception(env, EXCP_HW_EXCP);
|
||||
if (!cpu->cfg.iopb_bus_exception) {
|
||||
return;
|
||||
}
|
||||
env->esr = ESR_EC_INSN_BUS;
|
||||
} else {
|
||||
if ((env->pvr.regs[2] & PVR2_DOPB_BUS_EXC_MASK)) {
|
||||
env->sregs[SR_ESR] = ESR_EC_DATA_BUS;
|
||||
helper_raise_exception(env, EXCP_HW_EXCP);
|
||||
if (!cpu->cfg.dopb_bus_exception) {
|
||||
return;
|
||||
}
|
||||
env->esr = ESR_EC_DATA_BUS;
|
||||
}
|
||||
|
||||
env->ear = addr;
|
||||
cs->exception_index = EXCP_HW_EXCP;
|
||||
cpu_loop_exit_restore(cs, retaddr);
|
||||
}
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -94,7 +94,7 @@ for target in $target_list; do
|
||||
xtensa|xtensaeb)
|
||||
arches=xtensa
|
||||
;;
|
||||
alpha|cris|hppa|i386|lm32|m68k|openrisc|riscv64|s390x|sh4|sparc64)
|
||||
alpha|cris|hppa|i386|lm32|microblaze|microblazeel|m68k|openrisc|riscv64|s390x|sh4|sparc64)
|
||||
arches=$target
|
||||
;;
|
||||
*)
|
||||
|
@ -30,7 +30,9 @@ float_mapping round_flags[] = {
|
||||
#ifdef FE_DOWNWARD
|
||||
{ FE_DOWNWARD, "downwards" },
|
||||
#endif
|
||||
#ifdef FE_TOWARDZERO
|
||||
{ FE_TOWARDZERO, "to zero" }
|
||||
#endif
|
||||
};
|
||||
|
||||
static void print_input(float input)
|
||||
|
@ -8,6 +8,23 @@
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
/* Some hosts do not have support for all of these; not required by ISO C. */
|
||||
#ifndef FE_OVERFLOW
|
||||
#define FE_OVERFLOW 0
|
||||
#endif
|
||||
#ifndef FE_UNDERFLOW
|
||||
#define FE_UNDERFLOW 0
|
||||
#endif
|
||||
#ifndef FE_DIVBYZERO
|
||||
#define FE_DIVBYZERO 0
|
||||
#endif
|
||||
#ifndef FE_INEXACT
|
||||
#define FE_INEXACT 0
|
||||
#endif
|
||||
#ifndef FE_INVALID
|
||||
#define FE_INVALID 0
|
||||
#endif
|
||||
|
||||
/* Number of constants in each table */
|
||||
int get_num_f16(void);
|
||||
int get_num_f32(void);
|
||||
|
@ -29,7 +29,9 @@ float_mapping round_flags[] = {
|
||||
#ifdef FE_DOWNWARD
|
||||
{ FE_DOWNWARD, "downwards" },
|
||||
#endif
|
||||
#ifdef FE_TOWARDZERO
|
||||
{ FE_TOWARDZERO, "to zero" }
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user