提交 232e5537 编写于 作者: P Peter Maydell

Merge remote-tracking branch 'remotes/vivier/tags/m68k-for-2.12-pull-request' into staging

# gpg: Signature made Thu 04 Jan 2018 16:37:32 GMT
# gpg:                using RSA key 0xF30C38BD3F2FBE3C
# gpg: Good signature from "Laurent Vivier <lvivier@redhat.com>"
# gpg:                 aka "Laurent Vivier <laurent@vivier.eu>"
# gpg:                 aka "Laurent Vivier (Red Hat) <lvivier@redhat.com>"
# Primary key fingerprint: CD2F 75DD C8E3 A4DC 2E4F  5173 F30C 38BD 3F2F BE3C

* remotes/vivier/tags/m68k-for-2.12-pull-request:
  target/m68k: fix m68k_cpu_dump_state()
  target/m68k: add the Interrupt Stack Pointer
  target/m68k: add andi/ori/eori to SR/CCR
  target/m68k: add 680x0 "move to SR" instruction
  target/m68k: move CCR/SR functions
  target/m68k: implement fsave/frestore
  target/m68k: add reset
  target/m68k: add cpush/cinv
  target/m68k: softmmu cleanup
  target/m68k: add move16
  target/m68k: add chk and chk2
  target/m68k: manage 680x0 stack frames
  target/m68k: add CPU_LOG_INT trace
  target/m68k: use insn_pc to generate instruction fault address
  linux-user, m68k: correctly manage SR in context
  target/m68k: fix gen_get_ccr()
  target-m68k: sync CC_OP before gen_jmp_tb()
Signed-off-by: NPeter Maydell <peter.maydell@linaro.org>
......@@ -2985,6 +2985,13 @@ void cpu_loop(CPUM68KState *env)
info._sifields._sigfault._addr = env->pc;
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
case EXCP_CHK:
info.si_signo = TARGET_SIGFPE;
info.si_errno = 0;
info.si_code = TARGET_FPE_INTOVF;
info._sifields._sigfault._addr = env->pc;
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
case EXCP_DIV0:
info.si_signo = TARGET_SIGFPE;
info.si_errno = 0;
......
......@@ -5612,13 +5612,14 @@ struct target_rt_sigframe
static void setup_sigcontext(struct target_sigcontext *sc, CPUM68KState *env,
abi_ulong mask)
{
uint32_t sr = (env->sr & 0xff00) | cpu_m68k_get_ccr(env);
__put_user(mask, &sc->sc_mask);
__put_user(env->aregs[7], &sc->sc_usp);
__put_user(env->dregs[0], &sc->sc_d0);
__put_user(env->dregs[1], &sc->sc_d1);
__put_user(env->aregs[0], &sc->sc_a0);
__put_user(env->aregs[1], &sc->sc_a1);
__put_user(env->sr, &sc->sc_sr);
__put_user(sr, &sc->sc_sr);
__put_user(env->pc, &sc->sc_pc);
}
......@@ -5634,7 +5635,7 @@ restore_sigcontext(CPUM68KState *env, struct target_sigcontext *sc)
__get_user(env->aregs[1], &sc->sc_a1);
__get_user(env->pc, &sc->sc_pc);
__get_user(temp, &sc->sc_sr);
env->sr = (env->sr & 0xff00) | (temp & 0xff);
cpu_m68k_set_ccr(env, temp);
}
/*
......@@ -5726,7 +5727,7 @@ static inline int target_rt_setup_ucontext(struct target_ucontext *uc,
CPUM68KState *env)
{
target_greg_t *gregs = uc->tuc_mcontext.gregs;
uint32_t sr = cpu_m68k_get_ccr(env);
uint32_t sr = (env->sr & 0xff00) | cpu_m68k_get_ccr(env);
__put_user(TARGET_MCONTEXT_VERSION, &uc->tuc_mcontext.version);
__put_user(env->dregs[0], &gregs[0]);
......
......@@ -55,17 +55,17 @@ static void m68k_cpu_reset(CPUState *s)
mcc->parent_reset(s);
memset(env, 0, offsetof(CPUM68KState, end_reset_fields));
#if !defined(CONFIG_USER_ONLY)
env->sr = 0x2700;
#ifdef CONFIG_SOFTMMU
cpu_m68k_set_sr(env, SR_S | SR_I);
#else
cpu_m68k_set_sr(env, 0);
#endif
m68k_switch_sp(env);
for (i = 0; i < 8; i++) {
env->fregs[i].d = nan;
}
cpu_m68k_set_fpcr(env, 0);
env->fpsr = 0;
cpu_m68k_set_ccr(env, 0);
/* TODO: We should set PC from the interrupt vector. */
env->pc = 0;
}
......@@ -134,9 +134,18 @@ static void m68020_cpu_initfn(Object *obj)
m68k_set_feature(env, M68K_FEATURE_CAS);
m68k_set_feature(env, M68K_FEATURE_BKPT);
m68k_set_feature(env, M68K_FEATURE_RTD);
m68k_set_feature(env, M68K_FEATURE_CHK2);
}
#define m68030_cpu_initfn m68020_cpu_initfn
#define m68040_cpu_initfn m68020_cpu_initfn
static void m68040_cpu_initfn(Object *obj)
{
M68kCPU *cpu = M68K_CPU(obj);
CPUM68KState *env = &cpu->env;
m68020_cpu_initfn(obj);
m68k_set_feature(env, M68K_FEATURE_M68040);
}
static void m68060_cpu_initfn(Object *obj)
{
......@@ -156,6 +165,7 @@ static void m68060_cpu_initfn(Object *obj)
m68k_set_feature(env, M68K_FEATURE_CAS);
m68k_set_feature(env, M68K_FEATURE_BKPT);
m68k_set_feature(env, M68K_FEATURE_RTD);
m68k_set_feature(env, M68K_FEATURE_CHK2);
}
static void m5208_cpu_initfn(Object *obj)
......
......@@ -45,6 +45,8 @@
#define EXCP_ADDRESS 3 /* Address error. */
#define EXCP_ILLEGAL 4 /* Illegal instruction. */
#define EXCP_DIV0 5 /* Divide by zero */
#define EXCP_CHK 6 /* CHK, CHK2 Instructions */
#define EXCP_TRAPCC 7 /* FTRAPcc, TRAPcc, TRAPV Instructions */
#define EXCP_PRIVILEGE 8 /* Privilege violation. */
#define EXCP_TRACE 9
#define EXCP_LINEA 10 /* Unimplemented line-A (MAC) opcode. */
......@@ -53,6 +55,9 @@
#define EXCP_DEBEGBP 13 /* Breakpoint debug interrupt. */
#define EXCP_FORMAT 14 /* RTE format error. */
#define EXCP_UNINITIALIZED 15
#define EXCP_SPURIOUS 24 /* Spurious interrupt */
#define EXCP_INT_LEVEL_1 25 /* Level 1 Interrupt autovector */
#define EXCP_INT_LEVEL_7 31 /* Level 7 Interrupt autovector */
#define EXCP_TRAP0 32 /* User trap #0. */
#define EXCP_TRAP15 47 /* User trap #15. */
#define EXCP_FP_BSUN 48 /* Branch Set on Unordered */
......@@ -63,6 +68,9 @@
#define EXCP_FP_OVFL 53 /* Overflow */
#define EXCP_FP_SNAN 54 /* Signaling Not-A-Number */
#define EXCP_FP_UNIMP 55 /* Unimplemented Data type */
#define EXCP_MMU_CONF 56 /* MMU Configuration Error */
#define EXCP_MMU_ILLEGAL 57 /* MMU Illegal Operation Error */
#define EXCP_MMU_ACCESS 58 /* MMU Access Level Violation Error */
#define EXCP_UNSUPPORTED 61
#define EXCP_RTE 0x100
......@@ -81,7 +89,7 @@ typedef struct CPUM68KState {
/* SSP and USP. The current_sp is stored in aregs[7], the other here. */
int current_sp;
uint32_t sp[2];
uint32_t sp[3];
/* Condition flags. */
uint32_t cc_op;
......@@ -170,6 +178,7 @@ int cpu_m68k_signal_handler(int host_signum, void *pinfo,
void *puc);
uint32_t cpu_m68k_get_ccr(CPUM68KState *env);
void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t);
void cpu_m68k_set_sr(CPUM68KState *env, uint32_t);
void cpu_m68k_set_fpcr(CPUM68KState *env, uint32_t val);
......@@ -210,10 +219,79 @@ typedef enum {
#define SR_I 0x0700
#define SR_M 0x1000
#define SR_S 0x2000
#define SR_T 0x8000
#define SR_T_SHIFT 14
#define SR_T 0xc000
#define M68K_SSP 0
#define M68K_USP 1
#define M68K_ISP 2
/* m68k Control Registers */
/* ColdFire */
/* Memory Management Control Registers */
#define M68K_CR_ASID 0x003
#define M68K_CR_ACR0 0x004
#define M68K_CR_ACR1 0x005
#define M68K_CR_ACR2 0x006
#define M68K_CR_ACR3 0x007
#define M68K_CR_MMUBAR 0x008
/* Processor Miscellaneous Registers */
#define M68K_CR_PC 0x80F
/* Local Memory and Module Control Registers */
#define M68K_CR_ROMBAR0 0xC00
#define M68K_CR_ROMBAR1 0xC01
#define M68K_CR_RAMBAR0 0xC04
#define M68K_CR_RAMBAR1 0xC05
#define M68K_CR_MPCR 0xC0C
#define M68K_CR_EDRAMBAR 0xC0D
#define M68K_CR_SECMBAR 0xC0E
#define M68K_CR_MBAR 0xC0F
/* Local Memory Address Permutation Control Registers */
#define M68K_CR_PCR1U0 0xD02
#define M68K_CR_PCR1L0 0xD03
#define M68K_CR_PCR2U0 0xD04
#define M68K_CR_PCR2L0 0xD05
#define M68K_CR_PCR3U0 0xD06
#define M68K_CR_PCR3L0 0xD07
#define M68K_CR_PCR1U1 0xD0A
#define M68K_CR_PCR1L1 0xD0B
#define M68K_CR_PCR2U1 0xD0C
#define M68K_CR_PCR2L1 0xD0D
#define M68K_CR_PCR3U1 0xD0E
#define M68K_CR_PCR3L1 0xD0F
/* MC680x0 */
/* MC680[1234]0/CPU32 */
#define M68K_CR_SFC 0x000
#define M68K_CR_DFC 0x001
#define M68K_CR_USP 0x800
#define M68K_CR_VBR 0x801 /* + Coldfire */
/* MC680[234]0 */
#define M68K_CR_CACR 0x002 /* + Coldfire */
#define M68K_CR_CAAR 0x802 /* MC68020 and MC68030 only */
#define M68K_CR_MSP 0x803
#define M68K_CR_ISP 0x804
/* MC68040/MC68LC040 */
#define M68K_CR_TC 0x003
#define M68K_CR_ITT0 0x004
#define M68K_CR_ITT1 0x005
#define M68K_CR_DTT0 0x006
#define M68K_CR_DTT1 0x007
#define M68K_CR_MMUSR 0x805
#define M68K_CR_URP 0x806
#define M68K_CR_SRP 0x807
/* MC68EC040 */
#define M68K_CR_IACR0 0x004
#define M68K_CR_IACR1 0x005
#define M68K_CR_DACR0 0x006
#define M68K_CR_DACR1 0x007
#define M68K_FPIAR_SHIFT 0
#define M68K_FPIAR (1 << M68K_FPIAR_SHIFT)
......@@ -296,6 +374,8 @@ enum m68k_features {
M68K_FEATURE_CAS,
M68K_FEATURE_BKPT,
M68K_FEATURE_RTD,
M68K_FEATURE_CHK2,
M68K_FEATURE_M68040, /* instructions specific to MC68040 */
};
static inline int m68k_feature(CPUM68KState *env, int feature)
......
......@@ -63,7 +63,7 @@ int m68k_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
} else {
switch (n) {
case 16:
env->sr = tmp;
cpu_m68k_set_sr(env, tmp);
break;
case 17:
env->pc = tmp;
......
......@@ -171,28 +171,84 @@ void m68k_cpu_init_gdb(M68kCPU *cpu)
/* TODO: Add [E]MAC registers. */
}
void HELPER(movec)(CPUM68KState *env, uint32_t reg, uint32_t val)
void HELPER(cf_movec_to)(CPUM68KState *env, uint32_t reg, uint32_t val)
{
M68kCPU *cpu = m68k_env_get_cpu(env);
switch (reg) {
case 0x02: /* CACR */
case M68K_CR_CACR:
env->cacr = val;
m68k_switch_sp(env);
break;
case 0x04: case 0x05: case 0x06: case 0x07: /* ACR[0-3] */
case M68K_CR_ACR0:
case M68K_CR_ACR1:
case M68K_CR_ACR2:
case M68K_CR_ACR3:
/* TODO: Implement Access Control Registers. */
break;
case 0x801: /* VBR */
case M68K_CR_VBR:
env->vbr = val;
break;
/* TODO: Implement control registers. */
default:
cpu_abort(CPU(cpu), "Unimplemented control register write 0x%x = 0x%x\n",
cpu_abort(CPU(cpu),
"Unimplemented control register write 0x%x = 0x%x\n",
reg, val);
}
}
void HELPER(m68k_movec_to)(CPUM68KState *env, uint32_t reg, uint32_t val)
{
M68kCPU *cpu = m68k_env_get_cpu(env);
switch (reg) {
/* MC680[1234]0 */
case M68K_CR_VBR:
env->vbr = val;
return;
/* MC680[234]0 */
case M68K_CR_CACR:
env->cacr = val;
m68k_switch_sp(env);
return;
/* MC680[34]0 */
case M68K_CR_USP:
env->sp[M68K_USP] = val;
return;
case M68K_CR_MSP:
env->sp[M68K_SSP] = val;
return;
case M68K_CR_ISP:
env->sp[M68K_ISP] = val;
return;
}
cpu_abort(CPU(cpu), "Unimplemented control register write 0x%x = 0x%x\n",
reg, val);
}
uint32_t HELPER(m68k_movec_from)(CPUM68KState *env, uint32_t reg)
{
M68kCPU *cpu = m68k_env_get_cpu(env);
switch (reg) {
/* MC680[1234]0 */
case M68K_CR_VBR:
return env->vbr;
/* MC680[234]0 */
case M68K_CR_CACR:
return env->cacr;
/* MC680[34]0 */
case M68K_CR_USP:
return env->sp[M68K_USP];
case M68K_CR_MSP:
return env->sp[M68K_SSP];
case M68K_CR_ISP:
return env->sp[M68K_ISP];
}
cpu_abort(CPU(cpu), "Unimplemented control register read 0x%x\n",
reg);
}
void HELPER(set_macsr)(CPUM68KState *env, uint32_t val)
{
uint32_t acc;
......@@ -232,8 +288,20 @@ void m68k_switch_sp(CPUM68KState *env)
int new_sp;
env->sp[env->current_sp] = env->aregs[7];
if (m68k_feature(env, M68K_FEATURE_M68000)) {
if (env->sr & SR_S) {
if (env->sr & SR_M) {
new_sp = M68K_SSP;
} else {
new_sp = M68K_ISP;
}
} else {
new_sp = M68K_USP;
}
} else {
new_sp = (env->sr & SR_S && env->cacr & M68K_CACR_EUSP)
? M68K_SSP : M68K_USP;
}
env->aregs[7] = env->sp[new_sp];
env->current_sp = new_sp;
}
......@@ -316,13 +384,17 @@ uint32_t HELPER(sats)(uint32_t val, uint32_t v)
return val;
}
void HELPER(set_sr)(CPUM68KState *env, uint32_t val)
void cpu_m68k_set_sr(CPUM68KState *env, uint32_t sr)
{
env->sr = val & 0xffe0;
cpu_m68k_set_ccr(env, val);
env->sr = sr & 0xffe0;
cpu_m68k_set_ccr(env, sr);
m68k_switch_sp(env);
}
void HELPER(set_sr)(CPUM68KState *env, uint32_t val)
{
cpu_m68k_set_sr(env, val);
}
/* MAC unit. */
/* FIXME: The MAC unit implementation is a bit of a mess. Some helpers
......@@ -707,3 +779,10 @@ void HELPER(set_mac_extu)(CPUM68KState *env, uint32_t val, uint32_t acc)
res |= (uint64_t)(val & 0xffff0000) << 16;
env->macc[acc + 1] = res;
}
#if defined(CONFIG_SOFTMMU)
void HELPER(reset)(CPUM68KState *env)
{
/* FIXME: reset all except CPU */
}
#endif
......@@ -8,7 +8,9 @@ DEF_HELPER_4(divsl, void, env, int, int, s32)
DEF_HELPER_4(divull, void, env, int, int, i32)
DEF_HELPER_4(divsll, void, env, int, int, s32)
DEF_HELPER_2(set_sr, void, env, i32)
DEF_HELPER_3(movec, void, env, i32, i32)
DEF_HELPER_3(cf_movec_to, void, env, i32, i32)
DEF_HELPER_3(m68k_movec_to, void, env, i32, i32)
DEF_HELPER_2(m68k_movec_from, i32, env, i32)
DEF_HELPER_4(cas2w, void, env, i32, i32, i32)
DEF_HELPER_4(cas2l, void, env, i32, i32, i32)
DEF_HELPER_4(cas2l_parallel, void, env, i32, i32, i32)
......@@ -94,3 +96,10 @@ DEF_HELPER_FLAGS_4(bfchg_mem, TCG_CALL_NO_WG, i32, env, i32, s32, i32)
DEF_HELPER_FLAGS_4(bfclr_mem, TCG_CALL_NO_WG, i32, env, i32, s32, i32)
DEF_HELPER_FLAGS_4(bfset_mem, TCG_CALL_NO_WG, i32, env, i32, s32, i32)
DEF_HELPER_FLAGS_4(bfffo_mem, TCG_CALL_NO_WG, i64, env, i32, s32, i32)
DEF_HELPER_3(chk, void, env, s32, s32)
DEF_HELPER_4(chk2, void, env, s32, s32, s32)
#if defined(CONFIG_SOFTMMU)
DEF_HELPER_FLAGS_1(reset, TCG_CALL_NO_RWG, void, env)
#endif
......@@ -30,6 +30,7 @@ static const MonitorDef monitor_defs[] = {
{ "sr", offsetof(CPUM68KState, sr) },
{ "ssp", offsetof(CPUM68KState, sp[0]) },
{ "usp", offsetof(CPUM68KState, sp[1]) },
{ "isp", offsetof(CPUM68KState, sp[2]) },
{ NULL },
};
......
......@@ -51,7 +51,7 @@ void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type,
}
}
static void do_rte(CPUM68KState *env)
static void cf_rte(CPUM68KState *env)
{
uint32_t sp;
uint32_t fmt;
......@@ -62,13 +62,158 @@ static void do_rte(CPUM68KState *env)
sp |= (fmt >> 28) & 3;
env->aregs[7] = sp + 8;
helper_set_sr(env, fmt);
cpu_m68k_set_sr(env, fmt);
}
static void do_interrupt_all(CPUM68KState *env, int is_hw)
static void m68k_rte(CPUM68KState *env)
{
uint32_t sp;
uint16_t fmt;
uint16_t sr;
sp = env->aregs[7];
throwaway:
sr = cpu_lduw_kernel(env, sp);
sp += 2;
env->pc = cpu_ldl_kernel(env, sp);
sp += 4;
if (m68k_feature(env, M68K_FEATURE_QUAD_MULDIV)) {
/* all except 68000 */
fmt = cpu_lduw_kernel(env, sp);
sp += 2;
switch (fmt >> 12) {
case 0:
break;
case 1:
env->aregs[7] = sp;
cpu_m68k_set_sr(env, sr);
goto throwaway;
case 2:
case 3:
sp += 4;
break;
case 4:
sp += 8;
break;
case 7:
sp += 52;
break;
}
}
env->aregs[7] = sp;
cpu_m68k_set_sr(env, sr);
}
static const char *m68k_exception_name(int index)
{
switch (index) {
case EXCP_ACCESS:
return "Access Fault";
case EXCP_ADDRESS:
return "Address Error";
case EXCP_ILLEGAL:
return "Illegal Instruction";
case EXCP_DIV0:
return "Divide by Zero";
case EXCP_CHK:
return "CHK/CHK2";
case EXCP_TRAPCC:
return "FTRAPcc, TRAPcc, TRAPV";
case EXCP_PRIVILEGE:
return "Privilege Violation";
case EXCP_TRACE:
return "Trace";
case EXCP_LINEA:
return "A-Line";
case EXCP_LINEF:
return "F-Line";
case EXCP_DEBEGBP: /* 68020/030 only */
return "Copro Protocol Violation";
case EXCP_FORMAT:
return "Format Error";
case EXCP_UNINITIALIZED:
return "Unitialized Interruot";
case EXCP_SPURIOUS:
return "Spurious Interrupt";
case EXCP_INT_LEVEL_1:
return "Level 1 Interrupt";
case EXCP_INT_LEVEL_1 + 1:
return "Level 2 Interrupt";
case EXCP_INT_LEVEL_1 + 2:
return "Level 3 Interrupt";
case EXCP_INT_LEVEL_1 + 3:
return "Level 4 Interrupt";
case EXCP_INT_LEVEL_1 + 4:
return "Level 5 Interrupt";
case EXCP_INT_LEVEL_1 + 5:
return "Level 6 Interrupt";
case EXCP_INT_LEVEL_1 + 6:
return "Level 7 Interrupt";
case EXCP_TRAP0:
return "TRAP #0";
case EXCP_TRAP0 + 1:
return "TRAP #1";
case EXCP_TRAP0 + 2:
return "TRAP #2";
case EXCP_TRAP0 + 3:
return "TRAP #3";
case EXCP_TRAP0 + 4:
return "TRAP #4";
case EXCP_TRAP0 + 5:
return "TRAP #5";
case EXCP_TRAP0 + 6:
return "TRAP #6";
case EXCP_TRAP0 + 7:
return "TRAP #7";
case EXCP_TRAP0 + 8:
return "TRAP #8";
case EXCP_TRAP0 + 9:
return "TRAP #9";
case EXCP_TRAP0 + 10:
return "TRAP #10";
case EXCP_TRAP0 + 11:
return "TRAP #11";
case EXCP_TRAP0 + 12:
return "TRAP #12";
case EXCP_TRAP0 + 13:
return "TRAP #13";
case EXCP_TRAP0 + 14:
return "TRAP #14";
case EXCP_TRAP0 + 15:
return "TRAP #15";
case EXCP_FP_BSUN:
return "FP Branch/Set on unordered condition";
case EXCP_FP_INEX:
return "FP Inexact Result";
case EXCP_FP_DZ:
return "FP Divide by Zero";
case EXCP_FP_UNFL:
return "FP Underflow";
case EXCP_FP_OPERR:
return "FP Operand Error";
case EXCP_FP_OVFL:
return "FP Overflow";
case EXCP_FP_SNAN:
return "FP Signaling NAN";
case EXCP_FP_UNIMP:
return "FP Unimplemented Data Type";
case EXCP_MMU_CONF: /* 68030/68851 only */
return "MMU Configuration Error";
case EXCP_MMU_ILLEGAL: /* 68851 only */
return "MMU Illegal Operation";
case EXCP_MMU_ACCESS: /* 68851 only */
return "MMU Access Level Violation";
case 64 ... 255:
return "User Defined Vector";
}
return "Unassigned";
}
static void cf_interrupt_all(CPUM68KState *env, int is_hw)
{
CPUState *cs = CPU(m68k_env_get_cpu(env));
uint32_t sp;
uint32_t sr;
uint32_t fmt;
uint32_t retaddr;
uint32_t vector;
......@@ -80,7 +225,7 @@ static void do_interrupt_all(CPUM68KState *env, int is_hw)
switch (cs->exception_index) {
case EXCP_RTE:
/* Return from an exception. */
do_rte(env);
cf_rte(env);
return;
case EXCP_HALT_INSN:
if (semihosting_enabled()
......@@ -106,10 +251,17 @@ static void do_interrupt_all(CPUM68KState *env, int is_hw)
vector = cs->exception_index << 2;
sr = env->sr | cpu_m68k_get_ccr(env);
if (qemu_loglevel_mask(CPU_LOG_INT)) {
static int count;
qemu_log("INT %6d: %s(%#x) pc=%08x sp=%08x sr=%04x\n",
++count, m68k_exception_name(cs->exception_index),
vector, env->pc, env->aregs[7], sr);
}
fmt |= 0x40000000;
fmt |= vector << 16;
fmt |= env->sr;
fmt |= cpu_m68k_get_ccr(env);
fmt |= sr;
env->sr |= SR_S;
if (is_hw) {
......@@ -131,6 +283,119 @@ static void do_interrupt_all(CPUM68KState *env, int is_hw)
env->pc = cpu_ldl_kernel(env, env->vbr + vector);
}
static inline void do_stack_frame(CPUM68KState *env, uint32_t *sp,
uint16_t format, uint16_t sr,
uint32_t addr, uint32_t retaddr)
{
CPUState *cs = CPU(m68k_env_get_cpu(env));
switch (format) {
case 4:
*sp -= 4;
cpu_stl_kernel(env, *sp, env->pc);
*sp -= 4;
cpu_stl_kernel(env, *sp, addr);
break;
case 3:
case 2:
*sp -= 4;
cpu_stl_kernel(env, *sp, addr);
break;
}
*sp -= 2;
cpu_stw_kernel(env, *sp, (format << 12) + (cs->exception_index << 2));
*sp -= 4;
cpu_stl_kernel(env, *sp, retaddr);
*sp -= 2;
cpu_stw_kernel(env, *sp, sr);
}
static void m68k_interrupt_all(CPUM68KState *env, int is_hw)
{
CPUState *cs = CPU(m68k_env_get_cpu(env));
uint32_t sp;
uint32_t retaddr;
uint32_t vector;
uint16_t sr, oldsr;
retaddr = env->pc;
if (!is_hw) {
switch (cs->exception_index) {
case EXCP_RTE:
/* Return from an exception. */
m68k_rte(env);
return;
case EXCP_TRAP0 ... EXCP_TRAP15:
/* Move the PC after the trap instruction. */
retaddr += 2;
break;
}
}
vector = cs->exception_index << 2;
sr = env->sr | cpu_m68k_get_ccr(env);
if (qemu_loglevel_mask(CPU_LOG_INT)) {
static int count;
qemu_log("INT %6d: %s(%#x) pc=%08x sp=%08x sr=%04x\n",
++count, m68k_exception_name(cs->exception_index),
vector, env->pc, env->aregs[7], sr);
}
/*
* MC68040UM/AD, chapter 9.3.10
*/
/* "the processor first make an internal copy" */
oldsr = sr;
/* "set the mode to supervisor" */
sr |= SR_S;
/* "suppress tracing" */
sr &= ~SR_T;
/* "sets the processor interrupt mask" */
if (is_hw) {
sr |= (env->sr & ~SR_I) | (env->pending_level << SR_I_SHIFT);
}
cpu_m68k_set_sr(env, sr);
sp = env->aregs[7];
sp &= ~1;
if (cs->exception_index == EXCP_ADDRESS) {
do_stack_frame(env, &sp, 2, oldsr, 0, retaddr);
} else if (cs->exception_index == EXCP_ILLEGAL ||
cs->exception_index == EXCP_DIV0 ||
cs->exception_index == EXCP_CHK ||
cs->exception_index == EXCP_TRAPCC ||
cs->exception_index == EXCP_TRACE) {
/* FIXME: addr is not only env->pc */
do_stack_frame(env, &sp, 2, oldsr, env->pc, retaddr);
} else if (is_hw && oldsr & SR_M &&
cs->exception_index >= EXCP_SPURIOUS &&
cs->exception_index <= EXCP_INT_LEVEL_7) {
do_stack_frame(env, &sp, 0, oldsr, 0, retaddr);
oldsr = sr;
env->aregs[7] = sp;
cpu_m68k_set_sr(env, sr &= ~SR_M);
sp = env->aregs[7] & ~1;
do_stack_frame(env, &sp, 1, oldsr, 0, retaddr);
} else {
do_stack_frame(env, &sp, 0, oldsr, 0, retaddr);
}
env->aregs[7] = sp;
/* Jump to vector. */
env->pc = cpu_ldl_kernel(env, env->vbr + vector);
}
static void do_interrupt_all(CPUM68KState *env, int is_hw)
{
if (m68k_feature(env, M68K_FEATURE_M68000)) {
m68k_interrupt_all(env, is_hw);
return;
}
cf_interrupt_all(env, is_hw);
}
void m68k_cpu_do_interrupt(CPUState *cs)
{
M68kCPU *cpu = M68K_CPU(cs);
......@@ -679,3 +944,64 @@ uint64_t HELPER(bfffo_mem)(CPUM68KState *env, uint32_t addr,
is already zero. */
return n | ffo;
}
void HELPER(chk)(CPUM68KState *env, int32_t val, int32_t ub)
{
/* From the specs:
* X: Not affected, C,V,Z: Undefined,
* N: Set if val < 0; cleared if val > ub, undefined otherwise
* We implement here values found from a real MC68040:
* X,V,Z: Not affected
* N: Set if val < 0; cleared if val >= 0
* C: if 0 <= ub: set if val < 0 or val > ub, cleared otherwise
* if 0 > ub: set if val > ub and val < 0, cleared otherwise
*/
env->cc_n = val;
env->cc_c = 0 <= ub ? val < 0 || val > ub : val > ub && val < 0;
if (val < 0 || val > ub) {
CPUState *cs = CPU(m68k_env_get_cpu(env));
/* Recover PC and CC_OP for the beginning of the insn. */
cpu_restore_state(cs, GETPC());
/* flags have been modified by gen_flush_flags() */
env->cc_op = CC_OP_FLAGS;
/* Adjust PC to end of the insn. */
env->pc += 2;
cs->exception_index = EXCP_CHK;
cpu_loop_exit(cs);
}
}
void HELPER(chk2)(CPUM68KState *env, int32_t val, int32_t lb, int32_t ub)
{
/* From the specs:
* X: Not affected, N,V: Undefined,
* Z: Set if val is equal to lb or ub
* C: Set if val < lb or val > ub, cleared otherwise
* We implement here values found from a real MC68040:
* X,N,V: Not affected
* Z: Set if val is equal to lb or ub
* C: if lb <= ub: set if val < lb or val > ub, cleared otherwise
* if lb > ub: set if val > ub and val < lb, cleared otherwise
*/
env->cc_z = val != lb && val != ub;
env->cc_c = lb <= ub ? val < lb || val > ub : val > ub && val < lb;
if (env->cc_c) {
CPUState *cs = CPU(m68k_env_get_cpu(env));
/* Recover PC and CC_OP for the beginning of the insn. */
cpu_restore_state(cs, GETPC());
/* flags have been modified by gen_flush_flags() */
env->cc_op = CC_OP_FLAGS;
/* Adjust PC to end of the insn. */
env->pc += 4;
cs->exception_index = EXCP_CHK;
cpu_loop_exit(cs);
}
}
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册