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:
Peter Maydell 2020-09-02 13:56:55 +01:00
commit 7068d5ef39
20 changed files with 2292 additions and 2025 deletions

View File

@ -777,11 +777,26 @@ static inline TCGv_i32 TCGV_HIGH(TCGv_i64 t)
} }
#endif #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) static inline void tcg_set_insn_param(TCGOp *op, int arg, TCGArg v)
{ {
op->args[arg] = 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) static inline void tcg_set_insn_start_param(TCGOp *op, int arg, target_ulong v)
{ {
#if TARGET_LONG_BITS <= TCG_TARGET_REG_BITS #if TARGET_LONG_BITS <= TCG_TARGET_REG_BITS

View File

@ -1038,9 +1038,12 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUMBState *env
(*regs)[pos++] = tswapreg(env->regs[i]); (*regs)[pos++] = tswapreg(env->regs[i]);
} }
for (i = 0; i < 6; i++) { (*regs)[pos++] = tswapreg(env->pc);
(*regs)[pos++] = tswapreg(env->sregs[i]); (*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 */ #endif /* TARGET_MICROBLAZE */

View File

@ -48,10 +48,10 @@ void cpu_loop(CPUMBState *env)
case EXCP_INTERRUPT: case EXCP_INTERRUPT:
/* just indicate that signals should be handled asap */ /* just indicate that signals should be handled asap */
break; break;
case EXCP_BREAK: case EXCP_SYSCALL:
/* Return address is 4 bytes after the call. */ /* Return address is 4 bytes after the call. */
env->regs[14] += 4; env->regs[14] += 4;
env->sregs[SR_PC] = env->regs[14]; env->pc = env->regs[14];
ret = do_syscall(env, ret = do_syscall(env,
env->regs[12], env->regs[12],
env->regs[5], env->regs[5],
@ -63,7 +63,7 @@ void cpu_loop(CPUMBState *env)
0, 0); 0, 0);
if (ret == -TARGET_ERESTARTSYS) { if (ret == -TARGET_ERESTARTSYS) {
/* Wind back to before the syscall. */ /* Wind back to before the syscall. */
env->sregs[SR_PC] -= 4; env->pc -= 4;
} else if (ret != -TARGET_QEMU_ESIGRETURN) { } else if (ret != -TARGET_QEMU_ESIGRETURN) {
env->regs[3] = ret; env->regs[3] = ret;
} }
@ -73,19 +73,19 @@ void cpu_loop(CPUMBState *env)
* not a userspace-usable register, as the kernel may clobber it * not a userspace-usable register, as the kernel may clobber it
* at any point.) * at any point.)
*/ */
env->regs[14] = env->sregs[SR_PC]; env->regs[14] = env->pc;
break; break;
case EXCP_HW_EXCP: case EXCP_HW_EXCP:
env->regs[17] = env->sregs[SR_PC] + 4; env->regs[17] = env->pc + 4;
if (env->iflags & D_FLAG) { if (env->iflags & D_FLAG) {
env->sregs[SR_ESR] |= 1 << 12; env->esr |= 1 << 12;
env->sregs[SR_PC] -= 4; env->pc -= 4;
/* FIXME: if branch was immed, replay the imm as well. */ /* FIXME: if branch was immed, replay the imm as well. */
} }
env->iflags &= ~(IMM_FLAG | D_FLAG); env->iflags &= ~(IMM_FLAG | D_FLAG);
switch (env->sregs[SR_ESR] & 31) { switch (env->esr & 31) {
case ESR_EC_DIVZERO: case ESR_EC_DIVZERO:
info.si_signo = TARGET_SIGFPE; info.si_signo = TARGET_SIGFPE;
info.si_errno = 0; info.si_errno = 0;
@ -96,18 +96,18 @@ void cpu_loop(CPUMBState *env)
case ESR_EC_FPU: case ESR_EC_FPU:
info.si_signo = TARGET_SIGFPE; info.si_signo = TARGET_SIGFPE;
info.si_errno = 0; info.si_errno = 0;
if (env->sregs[SR_FSR] & FSR_IO) { if (env->fsr & FSR_IO) {
info.si_code = TARGET_FPE_FLTINV; 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.si_code = TARGET_FPE_FLTDIV;
} }
info._sifields._sigfault._addr = 0; info._sifields._sigfault._addr = 0;
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break; break;
default: default:
fprintf(stderr, "Unhandled hw-exception: 0x%" PRIx64 "\n", fprintf(stderr, "Unhandled hw-exception: 0x%x\n",
env->sregs[SR_ESR] & ESR_EC_MASK); env->esr & ESR_EC_MASK);
cpu_dump_state(cs, stderr, 0); cpu_dump_state(cs, stderr, 0);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
break; break;
@ -165,5 +165,5 @@ void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
env->regs[29] = regs->r29; env->regs[29] = regs->r29;
env->regs[30] = regs->r30; env->regs[30] = regs->r30;
env->regs[31] = regs->r31; env->regs[31] = regs->r31;
env->sregs[SR_PC] = regs->pc; env->pc = regs->pc;
} }

View File

@ -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[29], &sc->regs.r29);
__put_user(env->regs[30], &sc->regs.r30); __put_user(env->regs[30], &sc->regs.r30);
__put_user(env->regs[31], &sc->regs.r31); __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) 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[29], &sc->regs.r29);
__get_user(env->regs[30], &sc->regs.r30); __get_user(env->regs[30], &sc->regs.r30);
__get_user(env->regs[31], &sc->regs.r31); __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, 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); env->regs[7] = frame_addr += offsetof(typeof(*frame), uc);
/* Offset of 4 to handle microblaze rtid r14, 0 */ /* 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); unlock_user_struct(frame, frame_addr, 1);
return; return;
@ -228,7 +228,7 @@ long do_sigreturn(CPUMBState *env)
restore_sigcontext(&frame->uc.tuc_mcontext, env); restore_sigcontext(&frame->uc.tuc_mcontext, env);
/* We got here through a sigreturn syscall, our path back is via an /* We got here through a sigreturn syscall, our path back is via an
rtb insn so setup r14 for that. */ 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); unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN; return -TARGET_QEMU_ESIGRETURN;

View File

@ -8,9 +8,24 @@
#ifndef MICROBLAZE_CPU_PARAM_H #ifndef MICROBLAZE_CPU_PARAM_H
#define MICROBLAZE_CPU_PARAM_H 1 #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_LONG_BITS 64
#define TARGET_PHYS_ADDR_SPACE_BITS 64 #define TARGET_PHYS_ADDR_SPACE_BITS 64
#define TARGET_VIRT_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. */ /* FIXME: MB uses variable pages down to 1K but linux only uses 4k. */
#define TARGET_PAGE_BITS 12 #define TARGET_PAGE_BITS 12
#define NB_MMU_MODES 3 #define NB_MMU_MODES 3

View File

@ -79,7 +79,7 @@ static void mb_cpu_set_pc(CPUState *cs, vaddr value)
{ {
MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
cpu->env.sregs[SR_PC] = value; cpu->env.pc = value;
} }
static bool mb_cpu_has_work(CPUState *cs) static bool mb_cpu_has_work(CPUState *cs)
@ -117,13 +117,13 @@ static void mb_cpu_reset(DeviceState *dev)
/* Disable stack protector. */ /* Disable stack protector. */
env->shr = ~0; env->shr = ~0;
env->sregs[SR_PC] = cpu->cfg.base_vectors; env->pc = cpu->cfg.base_vectors;
#if defined(CONFIG_USER_ONLY) #if defined(CONFIG_USER_ONLY)
/* start in user mode with interrupts enabled. */ /* 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 #else
env->sregs[SR_MSR] = 0; mb_cpu_write_msr(env, 0);
mmu_init(&env->mmu); mmu_init(&env->mmu);
env->mmu.c_mmu = 3; env->mmu.c_mmu = 3;
env->mmu.c_mmu_tlb_access = 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->class_by_name = mb_cpu_class_by_name;
cc->has_work = mb_cpu_has_work; cc->has_work = mb_cpu_has_work;
cc->do_interrupt = mb_cpu_do_interrupt; 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->cpu_exec_interrupt = mb_cpu_exec_interrupt;
cc->dump_state = mb_cpu_dump_state; cc->dump_state = mb_cpu_dump_state;
cc->set_pc = mb_cpu_set_pc; cc->set_pc = mb_cpu_set_pc;

View File

@ -31,7 +31,7 @@ typedef struct CPUMBState CPUMBState;
#define EXCP_MMU 1 #define EXCP_MMU 1
#define EXCP_IRQ 2 #define EXCP_IRQ 2
#define EXCP_BREAK 3 #define EXCP_SYSCALL 3 /* user-only */
#define EXCP_HW_BREAK 4 #define EXCP_HW_BREAK 4
#define EXCP_HW_EXCP 5 #define EXCP_HW_EXCP 5
@ -79,10 +79,13 @@ typedef struct CPUMBState CPUMBState;
/* Exception State Register (ESR) Fields */ /* Exception State Register (ESR) Fields */
#define ESR_DIZ (1<<11) /* Zone Protection */ #define ESR_DIZ (1<<11) /* Zone Protection */
#define ESR_W (1<<11) /* Unaligned word access */
#define ESR_S (1<<10) /* Store instruction */ #define ESR_S (1<<10) /* Store instruction */
#define ESR_ESS_FSL_OFFSET 5 #define ESR_ESS_FSL_OFFSET 5
#define ESR_ESS_MASK (0x7f << 5)
#define ESR_EC_FSL 0 #define ESR_EC_FSL 0
#define ESR_EC_UNALIGNED_DATA 1 #define ESR_EC_UNALIGNED_DATA 1
#define ESR_EC_ILLEGAL_OP 2 #define ESR_EC_ILLEGAL_OP 2
@ -228,15 +231,22 @@ typedef struct CPUMBState CPUMBState;
#define STREAM_CONTROL (1 << 3) #define STREAM_CONTROL (1 << 3)
#define STREAM_NONBLOCK (1 << 4) #define STREAM_NONBLOCK (1 << 4)
#define TARGET_INSN_START_EXTRA_WORDS 1
struct CPUMBState { struct CPUMBState {
uint32_t debug; uint32_t bvalue; /* TCG temporary, only valid during a TB */
uint32_t btaken; uint32_t btarget; /* Full resolved branch destination */
uint64_t btarget;
uint32_t bimm;
uint32_t imm; uint32_t imm;
uint32_t regs[32]; 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; float_status fp_status;
/* Stack protectors. Yes, it's a hw feature. */ /* Stack protectors. Yes, it's a hw feature. */
uint32_t slr, shr; uint32_t slr, shr;
@ -247,14 +257,22 @@ struct CPUMBState {
uint32_t res_val; uint32_t res_val;
/* Internal flags. */ /* Internal flags. */
#define IMM_FLAG 4 #define IMM_FLAG (1 << 0)
#define MSR_EE_FLAG (1 << 8) #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 DRTI_FLAG (1 << 16)
#define DRTE_FLAG (1 << 17) #define DRTE_FLAG (1 << 17)
#define DRTB_FLAG (1 << 18) #define DRTB_FLAG (1 << 18)
#define D_FLAG (1 << 19) /* Bit in ESR. */ #define D_FLAG (1 << 19) /* Bit in ESR. */
/* TB dependent CPUMBState. */ /* TB dependent CPUMBState. */
#define IFLAGS_TB_MASK (D_FLAG | IMM_FLAG | DRTI_FLAG | DRTE_FLAG | DRTB_FLAG) #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; uint32_t iflags;
#if !defined(CONFIG_USER_ONLY) #if !defined(CONFIG_USER_ONLY)
@ -317,11 +335,30 @@ struct MicroBlazeCPU {
void mb_cpu_do_interrupt(CPUState *cs); void mb_cpu_do_interrupt(CPUState *cs);
bool mb_cpu_exec_interrupt(CPUState *cs, int int_req); 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); void mb_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
hwaddr mb_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); 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_read_register(CPUState *cpu, GByteArray *buf, int reg);
int mb_cpu_gdb_write_register(CPUState *cpu, uint8_t *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); void mb_tcg_init(void);
/* you can call this signal handler from your SIGBUS and SIGSEGV /* you can call this signal handler from your SIGBUS and SIGSEGV
signal handlers to inform the virtual CPU of exceptions. non zero signal handlers to inform the virtual CPU of exceptions. non zero
@ -348,13 +385,15 @@ typedef MicroBlazeCPU ArchCPU;
#include "exec/cpu-all.h" #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, static inline void cpu_get_tb_cpu_state(CPUMBState *env, target_ulong *pc,
target_ulong *cs_base, uint32_t *flags) target_ulong *cs_base, uint32_t *flags)
{ {
*pc = env->sregs[SR_PC]; *pc = env->pc;
*cs_base = 0; *flags = (env->iflags & IFLAGS_TB_MASK) | (env->msr & MSR_TB_MASK);
*flags = (env->iflags & IFLAGS_TB_MASK) | *cs_base = (*flags & IMM_FLAG ? env->imm : 0);
(env->sregs[SR_MSR] & (MSR_UM | MSR_VM | MSR_EE));
} }
#if !defined(CONFIG_USER_ONLY) #if !defined(CONFIG_USER_ONLY)
@ -369,11 +408,11 @@ static inline int cpu_mmu_index(CPUMBState *env, bool ifetch)
MicroBlazeCPU *cpu = env_archcpu(env); MicroBlazeCPU *cpu = env_archcpu(env);
/* Are we in nommu mode?. */ /* 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; return MMU_NOMMU_IDX;
} }
if (env->sregs[SR_MSR] & MSR_UM) { if (env->msr & MSR_UM) {
return MMU_USER_IDX; return MMU_USER_IDX;
} }
return MMU_KERNEL_IDX; return MMU_KERNEL_IDX;

View File

@ -21,58 +21,80 @@
#include "cpu.h" #include "cpu.h"
#include "exec/gdbstub.h" #include "exec/gdbstub.h"
int mb_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) /*
{
MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
CPUMBState *env = &cpu->env;
/*
* GDB expects SREGs in the following order: * GDB expects SREGs in the following order:
* PC, MSR, EAR, ESR, FSR, BTR, EDR, PID, ZPR, TLBX, TLBSX, TLBLO, TLBHI. * 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 * 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. * 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
};
/* enum {
* GDB expects registers to be reported in this order: GDB_PC = 32 + 0,
* R0-R31 GDB_MSR = 32 + 1,
* PC-BTR GDB_EAR = 32 + 2,
* PVR0-PVR11 GDB_ESR = 32 + 3,
* EDR-TLBHI GDB_FSR = 32 + 4,
* SLR-SHR GDB_BTR = 32 + 5,
*/ GDB_PVR0 = 32 + 6,
if (n < 32) { GDB_PVR11 = 32 + 17,
return gdb_get_reg32(mem_buf, env->regs[n]); GDB_EDR = 32 + 18,
} else { GDB_SLR = 32 + 25,
n -= 32; GDB_SHR = 32 + 26,
switch (n) { };
case 0 ... 5:
return gdb_get_reg32(mem_buf, env->sregs[sreg_map[n]]); int mb_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
/* PVR12 is intentionally skipped */ {
case 6 ... 17: MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
n -= 6; CPUClass *cc = CPU_GET_CLASS(cs);
return gdb_get_reg32(mem_buf, env->pvr.regs[n]); CPUMBState *env = &cpu->env;
case 18: uint32_t val;
return gdb_get_reg32(mem_buf, env->sregs[SR_EDR]);
/* Other SRegs aren't modeled, so report a value of 0 */ if (n > cc->gdb_num_core_regs) {
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; 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) 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; CPUMBState *env = &cpu->env;
uint32_t tmp; 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) { if (n > cc->gdb_num_core_regs) {
return 0; return 0;
} }
tmp = ldl_p(mem_buf); 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) {
env->regs[n] = tmp;
} else {
n -= 32;
switch (n) { switch (n) {
case 0 ... 5: case 1 ... 31:
env->sregs[sreg_map[n]] = tmp; env->regs[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 */ /* PVR12 is intentionally skipped */
case 6 ... 17: env->pvr.regs[n - GDB_PVR0] = tmp;
n -= 6;
env->pvr.regs[n] = tmp;
break; break;
/* Only EDR is modeled in these indeces, so ignore the rest */ case GDB_EDR:
case 18: env->edr = tmp;
env->sregs[SR_EDR] = tmp;
break; break;
case 25: case GDB_SLR:
env->slr = tmp; env->slr = tmp;
break; break;
case 26: case GDB_SHR:
env->shr = tmp; env->shr = tmp;
break; break;
} }
}
return 4; return 4;
} }

View File

@ -24,8 +24,6 @@
#include "qemu/host-utils.h" #include "qemu/host-utils.h"
#include "exec/log.h" #include "exec/log.h"
#define D(x)
#if defined(CONFIG_USER_ONLY) #if defined(CONFIG_USER_ONLY)
void mb_cpu_do_interrupt(CPUState *cs) void mb_cpu_do_interrupt(CPUState *cs)
@ -35,7 +33,7 @@ void mb_cpu_do_interrupt(CPUState *cs)
cs->exception_index = -1; cs->exception_index = -1;
env->res_addr = RES_ADDR_NONE; 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, 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", qemu_log_mask(CPU_LOG_MMU, "mmu=%d miss v=%" VADDR_PRIx "\n",
mmu_idx, address); mmu_idx, address);
env->sregs[SR_EAR] = address; env->ear = address;
switch (lu.err) { switch (lu.err) {
case ERR_PROT: case ERR_PROT:
env->sregs[SR_ESR] = access_type == MMU_INST_FETCH ? 17 : 16; env->esr = access_type == MMU_INST_FETCH ? 17 : 16;
env->sregs[SR_ESR] |= (access_type == MMU_DATA_STORE) << 10; env->esr |= (access_type == MMU_DATA_STORE) << 10;
break; break;
case ERR_MISS: case ERR_MISS:
env->sregs[SR_ESR] = access_type == MMU_INST_FETCH ? 19 : 18; env->esr = access_type == MMU_INST_FETCH ? 19 : 18;
env->sregs[SR_ESR] |= (access_type == MMU_DATA_STORE) << 10; env->esr |= (access_type == MMU_DATA_STORE) << 10;
break; break;
default: default:
abort(); abort();
@ -112,12 +110,11 @@ void mb_cpu_do_interrupt(CPUState *cs)
{ {
MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
CPUMBState *env = &cpu->env; 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. */ /* IMM flag cannot propagate across a branch and into the dslot. */
assert(!((env->iflags & D_FLAG) && (env->iflags & IMM_FLAG))); assert(!((env->iflags & D_FLAG) && (env->iflags & IMM_FLAG)));
assert(!(env->iflags & (DRTI_FLAG | DRTE_FLAG | DRTB_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; env->res_addr = RES_ADDR_NONE;
switch (cs->exception_index) { switch (cs->exception_index) {
case EXCP_HW_EXCP: case EXCP_HW_EXCP:
@ -126,80 +123,79 @@ void mb_cpu_do_interrupt(CPUState *cs)
return; return;
} }
env->regs[17] = env->sregs[SR_PC] + 4; env->regs[17] = env->pc + 4;
env->sregs[SR_ESR] &= ~(1 << 12); env->esr &= ~(1 << 12);
/* Exception breaks branch + dslot sequence? */ /* Exception breaks branch + dslot sequence? */
if (env->iflags & D_FLAG) { if (env->iflags & D_FLAG) {
env->sregs[SR_ESR] |= 1 << 12 ; env->esr |= 1 << 12 ;
env->sregs[SR_BTR] = env->btarget; env->btr = env->btarget;
} }
/* Disable the MMU. */ /* Disable the MMU. */
t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1; t = (msr & (MSR_VM | MSR_UM)) << 1;
env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM); msr &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM);
env->sregs[SR_MSR] |= t; msr |= t;
/* Exception in progress. */ /* Exception in progress. */
env->sregs[SR_MSR] |= MSR_EIP; msr |= MSR_EIP;
mb_cpu_write_msr(env, msr);
qemu_log_mask(CPU_LOG_INT, qemu_log_mask(CPU_LOG_INT,
"hw exception at pc=%" PRIx64 " ear=%" PRIx64 " " "hw exception at pc=%x ear=%" PRIx64 " "
"esr=%" PRIx64 " iflags=%x\n", "esr=%x iflags=%x\n",
env->sregs[SR_PC], env->sregs[SR_EAR], env->pc, env->ear,
env->sregs[SR_ESR], env->iflags); env->esr, env->iflags);
log_cpu_state_mask(CPU_LOG_INT, cs, 0); log_cpu_state_mask(CPU_LOG_INT, cs, 0);
env->iflags &= ~(IMM_FLAG | D_FLAG); env->iflags &= ~(IMM_FLAG | D_FLAG);
env->sregs[SR_PC] = cpu->cfg.base_vectors + 0x20; env->pc = cpu->cfg.base_vectors + 0x20;
break; break;
case EXCP_MMU: 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? */ /* Exception breaks branch + dslot sequence? */
if (env->iflags & D_FLAG) { if (env->iflags & D_FLAG) {
D(qemu_log("D_FLAG set at exception bimm=%d\n", env->bimm)); env->esr |= 1 << 12 ;
env->sregs[SR_ESR] |= 1 << 12 ; env->btr = env->btarget;
env->sregs[SR_BTR] = env->btarget;
/* Reexecute the branch. */ /* Reexecute the branch. */
env->regs[17] -= 4; env->regs[17] -= 4;
/* was the branch immprefixed?. */ /* was the branch immprefixed?. */
if (env->bimm) { if (env->iflags & BIMM_FLAG) {
qemu_log_mask(CPU_LOG_INT,
"bimm exception at pc=%" PRIx64 " "
"iflags=%x\n",
env->sregs[SR_PC], env->iflags);
env->regs[17] -= 4; env->regs[17] -= 4;
log_cpu_state_mask(CPU_LOG_INT, cs, 0); log_cpu_state_mask(CPU_LOG_INT, cs, 0);
} }
} else if (env->iflags & IMM_FLAG) { } else if (env->iflags & IMM_FLAG) {
D(qemu_log("IMM_FLAG set at exception\n"));
env->regs[17] -= 4; env->regs[17] -= 4;
} }
/* Disable the MMU. */ /* Disable the MMU. */
t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1; t = (msr & (MSR_VM | MSR_UM)) << 1;
env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM); msr &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM);
env->sregs[SR_MSR] |= t; msr |= t;
/* Exception in progress. */ /* Exception in progress. */
env->sregs[SR_MSR] |= MSR_EIP; msr |= MSR_EIP;
mb_cpu_write_msr(env, msr);
qemu_log_mask(CPU_LOG_INT, qemu_log_mask(CPU_LOG_INT,
"exception at pc=%" PRIx64 " ear=%" PRIx64 " " "exception at pc=%x ear=%" PRIx64 " iflags=%x\n",
"iflags=%x\n", env->pc, env->ear, env->iflags);
env->sregs[SR_PC], env->sregs[SR_EAR], env->iflags);
log_cpu_state_mask(CPU_LOG_INT, cs, 0); log_cpu_state_mask(CPU_LOG_INT, cs, 0);
env->iflags &= ~(IMM_FLAG | D_FLAG); env->iflags &= ~(IMM_FLAG | D_FLAG);
env->sregs[SR_PC] = cpu->cfg.base_vectors + 0x20; env->pc = cpu->cfg.base_vectors + 0x20;
break; break;
case EXCP_IRQ: case EXCP_IRQ:
assert(!(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP))); assert(!(msr & (MSR_EIP | MSR_BIP)));
assert(env->sregs[SR_MSR] & MSR_IE); assert(msr & MSR_IE);
assert(!(env->iflags & D_FLAG)); assert(!(env->iflags & D_FLAG));
t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1; t = (msr & (MSR_VM | MSR_UM)) << 1;
#if 0 #if 0
#include "disas/disas.h" #include "disas/disas.h"
@ -209,53 +205,45 @@ void mb_cpu_do_interrupt(CPUState *cs)
{ {
const char *sym; const char *sym;
sym = lookup_symbol(env->sregs[SR_PC]); sym = lookup_symbol(env->pc);
if (sym if (sym
&& (!strcmp("netif_rx", sym) && (!strcmp("netif_rx", sym)
|| !strcmp("process_backlog", sym))) { || !strcmp("process_backlog", sym))) {
qemu_log( qemu_log("interrupt at pc=%x msr=%x %x iflags=%x sym=%s\n",
"interrupt at pc=%x msr=%x %x iflags=%x sym=%s\n", env->pc, msr, t, env->iflags, sym);
env->sregs[SR_PC], env->sregs[SR_MSR], t, env->iflags,
sym);
log_cpu_state(cs, 0); log_cpu_state(cs, 0);
} }
} }
#endif #endif
qemu_log_mask(CPU_LOG_INT, qemu_log_mask(CPU_LOG_INT,
"interrupt at pc=%" PRIx64 " msr=%" PRIx64 " %x " "interrupt at pc=%x msr=%x %x iflags=%x\n",
"iflags=%x\n", env->pc, msr, t, env->iflags);
env->sregs[SR_PC], env->sregs[SR_MSR], t, env->iflags);
env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM \ msr &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM | MSR_IE);
| MSR_UM | MSR_IE); msr |= t;
env->sregs[SR_MSR] |= t; mb_cpu_write_msr(env, msr);
env->regs[14] = env->sregs[SR_PC]; env->regs[14] = env->pc;
env->sregs[SR_PC] = cpu->cfg.base_vectors + 0x10; env->pc = cpu->cfg.base_vectors + 0x10;
//log_cpu_state_mask(CPU_LOG_INT, cs, 0); //log_cpu_state_mask(CPU_LOG_INT, cs, 0);
break; break;
case EXCP_BREAK:
case EXCP_HW_BREAK: case EXCP_HW_BREAK:
assert(!(env->iflags & IMM_FLAG)); assert(!(env->iflags & IMM_FLAG));
assert(!(env->iflags & D_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, qemu_log_mask(CPU_LOG_INT,
"break at pc=%" PRIx64 " msr=%" PRIx64 " %x " "break at pc=%x msr=%x %x iflags=%x\n",
"iflags=%x\n", env->pc, msr, t, env->iflags);
env->sregs[SR_PC], env->sregs[SR_MSR], t, env->iflags);
log_cpu_state_mask(CPU_LOG_INT, cs, 0); log_cpu_state_mask(CPU_LOG_INT, cs, 0);
env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM); msr &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM);
env->sregs[SR_MSR] |= t; msr |= t;
env->sregs[SR_MSR] |= MSR_BIP; msr |= MSR_BIP;
if (cs->exception_index == EXCP_HW_BREAK) { env->regs[16] = env->pc;
env->regs[16] = env->sregs[SR_PC]; env->pc = cpu->cfg.base_vectors + 0x18;
env->sregs[SR_MSR] |= MSR_BIP; mb_cpu_write_msr(env, msr);
env->sregs[SR_PC] = cpu->cfg.base_vectors + 0x18;
} else
env->sregs[SR_PC] = env->btarget;
break; break;
default: default:
cpu_abort(cs, "unhandled exception type=%d\n", 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; CPUMBState *env = &cpu->env;
if ((interrupt_request & CPU_INTERRUPT_HARD) if ((interrupt_request & CPU_INTERRUPT_HARD)
&& (env->sregs[SR_MSR] & MSR_IE) && (env->msr & MSR_IE)
&& !(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP)) && !(env->msr & (MSR_EIP | MSR_BIP))
&& !(env->iflags & (D_FLAG | IMM_FLAG))) { && !(env->iflags & (D_FLAG | IMM_FLAG))) {
cs->exception_index = EXCP_IRQ; cs->exception_index = EXCP_IRQ;
mb_cpu_do_interrupt(cs); mb_cpu_do_interrupt(cs);
@ -302,3 +290,31 @@ bool mb_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
} }
return false; 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);
}

View File

@ -1,36 +1,31 @@
DEF_HELPER_2(raise_exception, void, env, i32) DEF_HELPER_FLAGS_2(raise_exception, TCG_CALL_NO_WG, noreturn, 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_3(divs, i32, env, i32, i32) DEF_HELPER_FLAGS_3(divs, TCG_CALL_NO_WG, i32, env, i32, i32)
DEF_HELPER_3(divu, 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_FLAGS_3(fadd, TCG_CALL_NO_WG, i32, env, i32, i32)
DEF_HELPER_3(frsub, i32, env, i32, i32) DEF_HELPER_FLAGS_3(frsub, TCG_CALL_NO_WG, i32, env, i32, i32)
DEF_HELPER_3(fmul, i32, env, i32, i32) DEF_HELPER_FLAGS_3(fmul, TCG_CALL_NO_WG, i32, env, i32, i32)
DEF_HELPER_3(fdiv, i32, env, i32, i32) DEF_HELPER_FLAGS_3(fdiv, TCG_CALL_NO_WG, i32, env, i32, i32)
DEF_HELPER_2(flt, i32, env, i32) DEF_HELPER_FLAGS_2(flt, TCG_CALL_NO_WG, i32, env, i32)
DEF_HELPER_2(fint, i32, env, i32) DEF_HELPER_FLAGS_2(fint, TCG_CALL_NO_WG, i32, env, i32)
DEF_HELPER_2(fsqrt, 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_FLAGS_3(fcmp_un, TCG_CALL_NO_WG, i32, env, i32, i32)
DEF_HELPER_3(fcmp_lt, i32, env, i32, i32) DEF_HELPER_FLAGS_3(fcmp_lt, TCG_CALL_NO_WG, i32, env, i32, i32)
DEF_HELPER_3(fcmp_eq, i32, env, i32, i32) DEF_HELPER_FLAGS_3(fcmp_eq, TCG_CALL_NO_WG, i32, env, i32, i32)
DEF_HELPER_3(fcmp_le, i32, env, i32, i32) DEF_HELPER_FLAGS_3(fcmp_le, TCG_CALL_NO_WG, i32, env, i32, i32)
DEF_HELPER_3(fcmp_gt, i32, env, i32, i32) DEF_HELPER_FLAGS_3(fcmp_gt, TCG_CALL_NO_WG, i32, env, i32, i32)
DEF_HELPER_3(fcmp_ne, i32, env, i32, i32) DEF_HELPER_FLAGS_3(fcmp_ne, TCG_CALL_NO_WG, i32, env, i32, i32)
DEF_HELPER_3(fcmp_ge, 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) DEF_HELPER_FLAGS_2(pcmpbf, TCG_CALL_NO_RWG_SE, i32, i32, i32)
#if !defined(CONFIG_USER_ONLY) #if !defined(CONFIG_USER_ONLY)
DEF_HELPER_3(mmu_read, i32, env, i32, i32) DEF_HELPER_FLAGS_3(mmu_read, TCG_CALL_NO_RWG, i32, env, i32, i32)
DEF_HELPER_4(mmu_write, void, env, i32, i32, i32) DEF_HELPER_FLAGS_4(mmu_write, TCG_CALL_NO_RWG, void, env, i32, i32, i32)
#endif #endif
DEF_HELPER_5(memalign, void, env, tl, i32, i32, i32) DEF_HELPER_FLAGS_2(stackprot, TCG_CALL_NO_WG, void, env, tl)
DEF_HELPER_2(stackprot, void, env, tl)
DEF_HELPER_2(get, i32, i32, i32) DEF_HELPER_FLAGS_2(get, TCG_CALL_NO_RWG, i32, i32, i32)
DEF_HELPER_3(put, void, i32, i32, i32) DEF_HELPER_FLAGS_3(put, TCG_CALL_NO_RWG, void, i32, i32, i32)

View 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

View File

@ -1,4 +1,7 @@
gen = decodetree.process('insns.decode')
microblaze_ss = ss.source_set() microblaze_ss = ss.source_set()
microblaze_ss.add(gen)
microblaze_ss.add(files( microblaze_ss.add(files(
'cpu.c', 'cpu.c',
'gdbstub.c', 'gdbstub.c',

View File

@ -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

View File

@ -250,8 +250,8 @@ void mmu_write(CPUMBState *env, bool ext, uint32_t rn, uint32_t v)
if (rn == MMU_R_TLBHI) { if (rn == MMU_R_TLBHI) {
if (i < 3 && !(v & TLB_VALID) && qemu_loglevel_mask(~0)) if (i < 3 && !(v & TLB_VALID) && qemu_loglevel_mask(~0))
qemu_log_mask(LOG_GUEST_ERROR, qemu_log_mask(LOG_GUEST_ERROR,
"invalidating index %x at pc=%" PRIx64 "\n", "invalidating index %x at pc=%x\n",
i, env->sregs[SR_PC]); i, env->pc);
env->mmu.tids[i] = env->mmu.regs[MMU_R_PID] & 0xff; env->mmu.tids[i] = env->mmu.regs[MMU_R_PID] & 0xff;
mmu_flush_idx(env, i); mmu_flush_idx(env, i);
} }

View File

@ -26,8 +26,6 @@
#include "exec/cpu_ldst.h" #include "exec/cpu_ldst.h"
#include "fpu/softfloat.h" #include "fpu/softfloat.h"
#define D(x)
void helper_put(uint32_t id, uint32_t ctrl, uint32_t data) void helper_put(uint32_t id, uint32_t ctrl, uint32_t data)
{ {
int test = ctrl & STREAM_TEST; int test = ctrl & STREAM_TEST;
@ -71,85 +69,27 @@ void helper_raise_exception(CPUMBState *env, uint32_t index)
cpu_loop_exit(cs); 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]); if ((env->msr & MSR_EE) &&
qemu_log("rmsr=%" PRIx64 " resr=%" PRIx64 " rear=%" PRIx64 " " env_archcpu(env)->cfg.div_zero_exception) {
"debug[%x] imm=%x iflags=%x\n", CPUState *cs = env_cpu(env);
env->sregs[SR_MSR], env->sregs[SR_ESR], env->sregs[SR_EAR],
env->debug, env->imm, env->iflags); env->esr = ESR_EC_DIVZERO;
qemu_log("btaken=%d btarget=%" PRIx64 " mode=%s(saved=%s) eip=%d ie=%d\n", cs->exception_index = EXCP_HW_EXCP;
env->btaken, env->btarget, cpu_loop_exit_restore(cs, ra);
(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"); return false;
}
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);
} }
return 0; return true;
}
env->sregs[SR_MSR] &= ~MSR_DZ;
return 1;
} }
uint32_t helper_divs(CPUMBState *env, uint32_t a, uint32_t b) 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 0;
} }
return (int32_t)a / (int32_t)b; 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) 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 0;
} }
return a / b; return a / b;
} }
/* raise FPU exception. */ /* 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; CPUState *cs = env_cpu(env);
helper_raise_exception(env, EXCP_HW_EXCP);
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; int raise = 0;
if (flags & float_flag_invalid) { if (flags & float_flag_invalid) {
env->sregs[SR_FSR] |= FSR_IO; env->fsr |= FSR_IO;
raise = 1; raise = 1;
} }
if (flags & float_flag_divbyzero) { if (flags & float_flag_divbyzero) {
env->sregs[SR_FSR] |= FSR_DZ; env->fsr |= FSR_DZ;
raise = 1; raise = 1;
} }
if (flags & float_flag_overflow) { if (flags & float_flag_overflow) {
env->sregs[SR_FSR] |= FSR_OF; env->fsr |= FSR_OF;
raise = 1; raise = 1;
} }
if (flags & float_flag_underflow) { if (flags & float_flag_underflow) {
env->sregs[SR_FSR] |= FSR_UF; env->fsr |= FSR_UF;
raise = 1; raise = 1;
} }
if (raise if (raise
&& (env->pvr.regs[2] & PVR2_FPU_EXC_MASK) && (env->pvr.regs[2] & PVR2_FPU_EXC_MASK)
&& (env->sregs[SR_MSR] & MSR_EE)) { && (env->msr & MSR_EE)) {
raise_fpu_exception(env); 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); fd.f = float32_add(fa.f, fb.f, &env->fp_status);
flags = get_float_exception_flags(&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; return fd.l;
} }
@ -222,7 +165,7 @@ uint32_t helper_frsub(CPUMBState *env, uint32_t a, uint32_t b)
fb.l = b; fb.l = b;
fd.f = float32_sub(fb.f, fa.f, &env->fp_status); fd.f = float32_sub(fb.f, fa.f, &env->fp_status);
flags = get_float_exception_flags(&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; return fd.l;
} }
@ -236,7 +179,7 @@ uint32_t helper_fmul(CPUMBState *env, uint32_t a, uint32_t b)
fb.l = b; fb.l = b;
fd.f = float32_mul(fa.f, fb.f, &env->fp_status); fd.f = float32_mul(fa.f, fb.f, &env->fp_status);
flags = get_float_exception_flags(&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; return fd.l;
} }
@ -251,7 +194,7 @@ uint32_t helper_fdiv(CPUMBState *env, uint32_t a, uint32_t b)
fb.l = b; fb.l = b;
fd.f = float32_div(fb.f, fa.f, &env->fp_status); fd.f = float32_div(fb.f, fa.f, &env->fp_status);
flags = get_float_exception_flags(&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; 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) || if (float32_is_signaling_nan(fa.f, &env->fp_status) ||
float32_is_signaling_nan(fb.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; r = 1;
} }
@ -289,7 +232,7 @@ uint32_t helper_fcmp_lt(CPUMBState *env, uint32_t a, uint32_t b)
fb.l = b; fb.l = b;
r = float32_lt(fb.f, fa.f, &env->fp_status); r = float32_lt(fb.f, fa.f, &env->fp_status);
flags = get_float_exception_flags(&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; return r;
} }
@ -305,7 +248,7 @@ uint32_t helper_fcmp_eq(CPUMBState *env, uint32_t a, uint32_t b)
fb.l = b; fb.l = b;
r = float32_eq_quiet(fa.f, fb.f, &env->fp_status); r = float32_eq_quiet(fa.f, fb.f, &env->fp_status);
flags = get_float_exception_flags(&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; 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); set_float_exception_flags(0, &env->fp_status);
r = float32_le(fa.f, fb.f, &env->fp_status); r = float32_le(fa.f, fb.f, &env->fp_status);
flags = get_float_exception_flags(&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; 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); set_float_exception_flags(0, &env->fp_status);
r = float32_lt(fa.f, fb.f, &env->fp_status); r = float32_lt(fa.f, fb.f, &env->fp_status);
flags = get_float_exception_flags(&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; 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); set_float_exception_flags(0, &env->fp_status);
r = !float32_eq_quiet(fa.f, fb.f, &env->fp_status); r = !float32_eq_quiet(fa.f, fb.f, &env->fp_status);
flags = get_float_exception_flags(&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; 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); set_float_exception_flags(0, &env->fp_status);
r = !float32_lt(fa.f, fb.f, &env->fp_status); r = !float32_lt(fa.f, fb.f, &env->fp_status);
flags = get_float_exception_flags(&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; return r;
} }
@ -390,7 +333,7 @@ uint32_t helper_fint(CPUMBState *env, uint32_t a)
fa.l = a; fa.l = a;
r = float32_to_int32(fa.f, &env->fp_status); r = float32_to_int32(fa.f, &env->fp_status);
flags = get_float_exception_flags(&env->fp_status); flags = get_float_exception_flags(&env->fp_status);
update_fpu_flags(env, flags); update_fpu_flags(env, flags, GETPC());
return r; return r;
} }
@ -404,7 +347,7 @@ uint32_t helper_fsqrt(CPUMBState *env, uint32_t a)
fa.l = a; fa.l = a;
fd.l = float32_sqrt(fa.f, &env->fp_status); fd.l = float32_sqrt(fa.f, &env->fp_status);
flags = get_float_exception_flags(&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; return fd.l;
} }
@ -422,37 +365,19 @@ uint32_t helper_pcmpbf(uint32_t a, uint32_t b)
return 0; 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) void helper_stackprot(CPUMBState *env, target_ulong addr)
{ {
if (addr < env->slr || addr > env->shr) { if (addr < env->slr || addr > env->shr) {
CPUState *cs = env_cpu(env);
qemu_log_mask(CPU_LOG_INT, "Stack protector violation at " qemu_log_mask(CPU_LOG_INT, "Stack protector violation at "
TARGET_FMT_lx " %x %x\n", TARGET_FMT_lx " %x %x\n",
addr, env->slr, env->shr); addr, env->slr, env->shr);
env->sregs[SR_EAR] = addr;
env->sregs[SR_ESR] = ESR_EC_STACKPROT; env->ear = addr;
helper_raise_exception(env, EXCP_HW_EXCP); 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, int mmu_idx, MemTxAttrs attrs,
MemTxResult response, uintptr_t retaddr) MemTxResult response, uintptr_t retaddr)
{ {
MicroBlazeCPU *cpu; MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
CPUMBState *env; CPUMBState *env = &cpu->env;
qemu_log_mask(CPU_LOG_INT, "Transaction failed: vaddr 0x%" VADDR_PRIx qemu_log_mask(CPU_LOG_INT, "Transaction failed: vaddr 0x%" VADDR_PRIx
" physaddr 0x" TARGET_FMT_plx " size %d access type %s\n", " physaddr 0x" TARGET_FMT_plx " size %d access type %s\n",
addr, physaddr, size, addr, physaddr, size,
access_type == MMU_INST_FETCH ? "INST_FETCH" : access_type == MMU_INST_FETCH ? "INST_FETCH" :
(access_type == MMU_DATA_LOAD ? "DATA_LOAD" : "DATA_STORE")); (access_type == MMU_DATA_LOAD ? "DATA_LOAD" : "DATA_STORE"));
cpu = MICROBLAZE_CPU(cs);
env = &cpu->env;
cpu_restore_state(cs, retaddr, true); if (!(env->msr & MSR_EE)) {
if (!(env->sregs[SR_MSR] & MSR_EE)) {
return; return;
} }
env->sregs[SR_EAR] = addr;
if (access_type == MMU_INST_FETCH) { if (access_type == MMU_INST_FETCH) {
if ((env->pvr.regs[2] & PVR2_IOPB_BUS_EXC_MASK)) { if (!cpu->cfg.iopb_bus_exception) {
env->sregs[SR_ESR] = ESR_EC_INSN_BUS; return;
helper_raise_exception(env, EXCP_HW_EXCP);
} }
env->esr = ESR_EC_INSN_BUS;
} else { } else {
if ((env->pvr.regs[2] & PVR2_DOPB_BUS_EXC_MASK)) { if (!cpu->cfg.dopb_bus_exception) {
env->sregs[SR_ESR] = ESR_EC_DATA_BUS; return;
helper_raise_exception(env, EXCP_HW_EXCP);
} }
env->esr = ESR_EC_DATA_BUS;
} }
env->ear = addr;
cs->exception_index = EXCP_HW_EXCP;
cpu_loop_exit_restore(cs, retaddr);
} }
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -94,7 +94,7 @@ for target in $target_list; do
xtensa|xtensaeb) xtensa|xtensaeb)
arches=xtensa 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 arches=$target
;; ;;
*) *)

View File

@ -30,7 +30,9 @@ float_mapping round_flags[] = {
#ifdef FE_DOWNWARD #ifdef FE_DOWNWARD
{ FE_DOWNWARD, "downwards" }, { FE_DOWNWARD, "downwards" },
#endif #endif
#ifdef FE_TOWARDZERO
{ FE_TOWARDZERO, "to zero" } { FE_TOWARDZERO, "to zero" }
#endif
}; };
static void print_input(float input) static void print_input(float input)

View File

@ -8,6 +8,23 @@
#include <inttypes.h> #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 */ /* Number of constants in each table */
int get_num_f16(void); int get_num_f16(void);
int get_num_f32(void); int get_num_f32(void);

View File

@ -29,7 +29,9 @@ float_mapping round_flags[] = {
#ifdef FE_DOWNWARD #ifdef FE_DOWNWARD
{ FE_DOWNWARD, "downwards" }, { FE_DOWNWARD, "downwards" },
#endif #endif
#ifdef FE_TOWARDZERO
{ FE_TOWARDZERO, "to zero" } { FE_TOWARDZERO, "to zero" }
#endif
}; };