diff options
author | Edgar E. Iglesias <edgar.iglesias@gmail.com> | 2009-09-03 10:25:00 +0200 |
---|---|---|
committer | Edgar E. Iglesias <edgar.iglesias@gmail.com> | 2009-09-03 10:25:00 +0200 |
commit | cedb936bfcc9b7fe9f7df58aa24ca191cba414fe (patch) | |
tree | 6e1922f98a1a64966f2a6cf33c833b384fe1d73b /target-microblaze | |
parent | a75cf0c52d353d90594007b69f27fcba1d5f1022 (diff) |
microblaze: Add infrastructure for supporting hw exceptions.
Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
Diffstat (limited to 'target-microblaze')
-rw-r--r-- | target-microblaze/cpu.h | 21 | ||||
-rw-r--r-- | target-microblaze/helper.c | 31 |
2 files changed, 49 insertions, 3 deletions
diff --git a/target-microblaze/cpu.h b/target-microblaze/cpu.h index a1c1a99ce1..5dc2b7d5c7 100644 --- a/target-microblaze/cpu.h +++ b/target-microblaze/cpu.h @@ -38,6 +38,7 @@ struct CPUMBState; #define EXCP_IRQ 3 #define EXCP_BREAK 4 #define EXCP_HW_BREAK 5 +#define EXCP_HW_EXCP 6 /* Register aliases. R0 - R15 */ #define R_SP 1 @@ -77,7 +78,18 @@ struct CPUMBState; #define ESR_DIZ (1<<11) /* Zone Protection */ #define ESR_S (1<<10) /* Store instruction */ - +#define ESR_EC_FSL 0 +#define ESR_EC_UNALIGNED_DATA 1 +#define ESR_EC_ILLEGAL_OP 2 +#define ESR_EC_INSN_BUS 3 +#define ESR_EC_DATA_BUS 4 +#define ESR_EC_DIVZERO 5 +#define ESR_EC_FPU 6 +#define ESR_EC_PRIVINSN 7 +#define ESR_EC_DATA_STORAGE 8 +#define ESR_EC_INSN_STORAGE 9 +#define ESR_EC_DATA_TLB 10 +#define ESR_EC_INSN_TLB 11 /* Version reg. */ /* Basic PVR mask */ @@ -198,13 +210,15 @@ typedef struct CPUMBState { uint32_t sregs[24]; /* Internal flags. */ -#define IMM_FLAG 4 +#define IMM_FLAG 4 +#define MSR_EE_FLAG (1 << 8) #define DRTI_FLAG (1 << 16) #define DRTE_FLAG (1 << 17) #define DRTB_FLAG (1 << 18) #define D_FLAG (1 << 19) /* Bit in ESR. */ /* TB dependant CPUState. */ -#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 | MSR_EE_FLAG) uint32_t iflags; struct { @@ -306,6 +320,7 @@ static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc, { *pc = env->sregs[SR_PC]; *cs_base = 0; + env->iflags |= env->sregs[SR_MSR] & MSR_EE; *flags = env->iflags & IFLAGS_TB_MASK; } #endif diff --git a/target-microblaze/helper.c b/target-microblaze/helper.c index 7fbb5ddbf3..40d27b956e 100644 --- a/target-microblaze/helper.c +++ b/target-microblaze/helper.c @@ -126,6 +126,37 @@ void do_interrupt(CPUState *env) assert(!(env->iflags & (DRTI_FLAG | DRTE_FLAG | DRTB_FLAG))); /* assert(env->sregs[SR_MSR] & (MSR_EE)); Only for HW exceptions. */ switch (env->exception_index) { + case EXCP_HW_EXCP: + if (!(env->pvr.regs[0] & PVR0_USE_EXC_MASK)) { + qemu_log("Exception raised on system without exceptions!\n"); + return; + } + + env->regs[17] = env->sregs[SR_PC] + 4; + env->sregs[SR_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; + } + + /* 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; + /* Exception in progress. */ + env->sregs[SR_MSR] |= MSR_EIP; + + qemu_log_mask(CPU_LOG_INT, + "hw exception at pc=%x ear=%x esr=%x iflags=%x\n", + env->sregs[SR_PC], env->sregs[SR_EAR], + env->sregs[SR_ESR], env->iflags); + log_cpu_state_mask(CPU_LOG_INT, env, 0); + env->iflags &= ~(IMM_FLAG | D_FLAG); + env->sregs[SR_PC] = 0x20; + break; + case EXCP_MMU: env->regs[17] = env->sregs[SR_PC]; |