mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-03 07:43:54 -06:00
-----BEGIN PGP SIGNATURE-----
iQIcBAABAgAGBQJaTlhMAAoJEPMMOL0/L748xsMQAIcRxsab41rsDuTVE3LU9OlW DKVO8O8gqG/l2QlFVAHphg5/w1d1CqTVQE5pFu6qf+/O1V2mcO95g9ZaIRQ2Rt/C blstw+D6xxxqaBe3EFnbuWUGrfdp6Mc8rfR/HtG8J5quNucMX/IpnKVSYxDqql6m gCDwT/N9hGMfEIW+QdcTh3tSpT4D1fWyJSbWWpM02necmAvg+mSvcJ8qQ8uYVyA5 Yc0OjSMZix9SFTn/QSKeh2+ofv+0HpauOLIGBcZ44xw0N40NiRhMFDITwyuv/rY6 tA8cQFw2OhwX7J9tbW4h4Jq8zyFjlarZfHFAij+X0mC2Id58KZaCcsCLlOhbR3x9 EA6Rtd9UKLHlrQfSLuB/bcJ3LgjxkiEjoooBHeFYofqhcW5A3Uk5FxxnMO5kYodZ yWOLZ3r7i9mzDHPECfNvKRIyC0IWp+hsZqC9UQt51/vupwAMq1EGYOJ2HBBpa0PS QSIAQX2XhKj/0yCAXM4nTKqAE9h6UKHNNmYoxJvPUsF7/Bobahr3sDZAepuuGADP b4l95pZ/Gjqm5d8S9I/A6zIm5vV8Fp0BMozhigNQ4e9yGpKapyOYZPiIgNb8wj0L /6Pqq9zoD8jbszg2H9/0kPTt57NjSMgqgHNRWfvvY8zL2LkvGxzpLmOe80BQcjYe CxWyb6Y53IWR6F3CXpnj =42iq -----END PGP SIGNATURE----- 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: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
232e5537e4
10 changed files with 937 additions and 129 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue