target-xtensa: implement exceptions

- mark privileged opcodes with ring check;
- make debug exception on exception handler entry.

Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
This commit is contained in:
Max Filippov 2011-09-06 03:55:41 +04:00 committed by Blue Swirl
parent f0a548b93d
commit 40643d7c0f
6 changed files with 242 additions and 6 deletions

View file

@ -108,7 +108,12 @@ enum {
enum {
SAR = 3,
SCOMPARE1 = 12,
EPC1 = 177,
DEPC = 192,
EXCSAVE1 = 209,
PS = 230,
EXCCAUSE = 232,
EXCVADDR = 238,
};
#define PS_INTLEVEL 0xf
@ -129,9 +134,60 @@ enum {
#define PS_WOE 0x40000
enum {
/* Static vectors */
EXC_RESET,
EXC_MEMORY_ERROR,
/* Dynamic vectors */
EXC_WINDOW_OVERFLOW4,
EXC_WINDOW_UNDERFLOW4,
EXC_WINDOW_OVERFLOW8,
EXC_WINDOW_UNDERFLOW8,
EXC_WINDOW_OVERFLOW12,
EXC_WINDOW_UNDERFLOW12,
EXC_IRQ,
EXC_KERNEL,
EXC_USER,
EXC_DOUBLE,
EXC_MAX
};
enum {
ILLEGAL_INSTRUCTION_CAUSE = 0,
SYSCALL_CAUSE,
INSTRUCTION_FETCH_ERROR_CAUSE,
LOAD_STORE_ERROR_CAUSE,
LEVEL1_INTERRUPT_CAUSE,
ALLOCA_CAUSE,
INTEGER_DIVIDE_BY_ZERO_CAUSE,
PRIVILEGED_CAUSE = 8,
LOAD_STORE_ALIGNMENT_CAUSE,
INSTR_PIF_DATA_ERROR_CAUSE = 12,
LOAD_STORE_PIF_DATA_ERROR_CAUSE,
INSTR_PIF_ADDR_ERROR_CAUSE,
LOAD_STORE_PIF_ADDR_ERROR_CAUSE,
INST_TLB_MISS_CAUSE,
INST_TLB_MULTI_HIT_CAUSE,
INST_FETCH_PRIVILEGE_CAUSE,
INST_FETCH_PROHIBITED_CAUSE = 20,
LOAD_STORE_TLB_MISS_CAUSE = 24,
LOAD_STORE_TLB_MULTI_HIT_CAUSE,
LOAD_STORE_PRIVILEGE_CAUSE,
LOAD_PROHIBITED_CAUSE = 28,
STORE_PROHIBITED_CAUSE,
COPROCESSOR0_DISABLED = 32,
};
typedef struct XtensaConfig {
const char *name;
uint64_t options;
int excm_level;
int ndepc;
uint32_t exception_vector[EXC_MAX];
} XtensaConfig;
typedef struct CPUXtensaState {
@ -141,6 +197,8 @@ typedef struct CPUXtensaState {
uint32_t sregs[256];
uint32_t uregs[256];
int exception_taken;
CPU_COMMON
} CPUXtensaState;
@ -164,6 +222,15 @@ static inline bool xtensa_option_enabled(const XtensaConfig *config, int opt)
return (config->options & XTENSA_OPTION_BIT(opt)) != 0;
}
static inline int xtensa_get_cintlevel(const CPUState *env)
{
int level = (env->sregs[PS] & PS_INTLEVEL) >> PS_INTLEVEL_SHIFT;
if ((env->sregs[PS] & PS_EXCM) && env->config->excm_level > level) {
level = env->config->excm_level;
}
return level;
}
static inline int xtensa_get_ring(const CPUState *env)
{
if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {