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

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]);
}
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 */

View File

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

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[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;

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
}

View File

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

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.add(gen)
microblaze_ss.add(files(
'cpu.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 (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);
}

View File

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

View File

@ -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
;;
*)

View File

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

View File

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

View File

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