From: Toni Wilen Date: Sun, 31 May 2020 16:44:35 +0000 (+0300) Subject: CPU model specific edge case updates. X-Git-Tag: 4400~20 X-Git-Url: https://git.unchartedbackwaters.co.uk/w/?a=commitdiff_plain;h=9b97a6b1d92da27c80fea3b7216c0543517f4d3c;p=francis%2Fwinuae.git CPU model specific edge case updates. --- diff --git a/gencpu.cpp b/gencpu.cpp index 62befa24..1e7a0890 100644 --- a/gencpu.cpp +++ b/gencpu.cpp @@ -5360,10 +5360,18 @@ static void gen_opcode (unsigned int opcode) } addcycles000(8); out("regs.sr %c= src;\n", curi->mnemo == i_ORSR ? '|' : curi->mnemo == i_ANDSR ? '&' : '^'); - makefromsr_t0(); + if (cpu_level < 5 && curi->size == sz_word) { + makefromsr_t0(); + } else { + makefromsr(); + } sync_m68k_pc(); - fill_prefetch_full_ntx(3); - next_level_000(); + if (cpu_level < 2 || curi->size == sz_word) { + fill_prefetch_full_ntx(3); + } else { + fill_prefetch_next(); + } + next_cpu_level = cpu_level - 1; break; case i_SUB: { @@ -6445,22 +6453,28 @@ static void gen_opcode (unsigned int opcode) break; case i_MV2SR: // MOVE TO SR genamode(curi, curi->smode, "srcreg", sz_word, "src", 1, 0, 0); - if (cpu_level == 0) + if (cpu_level == 0) { out("int t1 = regs.t1;\n"); + } if (curi->size == sz_byte) { // MOVE TO CCR addcycles000(4); out("MakeSR();\nregs.sr &= 0xFF00;\nregs.sr |= src & 0xFF;\n"); + makefromsr(); } else { // MOVE TO SR check_trace(); addcycles000(4); out("regs.sr = src;\n"); + makefromsr_t0(); + } + if (cpu_level >= 2 && curi->size == sz_byte) { + fill_prefetch_next(); + } else { + // does full prefetch because S-bit change may change memory mapping under the CPU + sync_m68k_pc(); + fill_prefetch_full_ntx(3); } - makefromsr_t0(); - // does full prefetch because S-bit change may change memory mapping under the CPU - sync_m68k_pc(); - fill_prefetch_full_ntx(3); next_level_000(); break; case i_SWAP: @@ -6710,7 +6724,8 @@ static void gen_opcode (unsigned int opcode) } } else { out("uaecptr oldpc = %s;\n", getpc); - out("uae_u16 newsr; uae_u32 newpc;\n"); + out("uae_u16 oldsr = regs.sr, newsr;\n"); + out("uae_u32 newpc;\n"); out("for (;;) {\n"); out("uaecptr a = m68k_areg(regs, 7);\n"); out("uae_u16 sr = %s(a);\n", srcw); @@ -6775,28 +6790,47 @@ static void gen_opcode (unsigned int opcode) out("else if (frame == 0xb) {\nm68k_areg(regs, 7) += offset + 84; break; }\n"); } } + out("else {\n"); if (cpu_level == 1) { - out("else {\n"); out("SET_NFLG(((uae_s16)format) < 0); \n"); out("SET_ZFLG(format == 0);\n"); out("SET_VFLG(0);\n"); out("Exception_cpu(14);\n"); write_return_cycles(0); - out("}\n"); + } else if (cpu_level == 0) { + out("Exception_cpu(14);\n"); + write_return_cycles(0); + } else if (cpu_level == 3) { + // 68030: trace bits are cleared + out("regs.t1 = regs.t0 = 0;\n"); + out("Exception_cpu(14);\n"); + write_return_cycles(0); } else { - out("else {\n"); out("Exception_cpu(14);\n"); write_return_cycles(0); - out("}\n"); } - out("regs.sr = newsr;\n"); + out("}\n"); + out("regs.sr = newsr;\n"); + out("oldsr = newsr;\n"); makefromsr_t0(); out("}\n"); + out("MakeFromSR_intmask(regs.sr, newsr);\n"); out("regs.sr = newsr;\n"); addcycles_ce020 (4); makefromsr_t0(); out("if (newpc & 1) {\n"); - out("exception3_read_prefetch(opcode, newpc);\n"); + if (cpu_level == 5) { + out("regs.sr = oldsr & 0xff00;\n"); + makefromsr(); + out("SET_ZFLG(newsr == 0);\n"); + out("SET_NFLG(newsr & 0x8000);\n"); + out("exception3_read_prefetch(opcode, newpc);\n"); + } else if (cpu_level == 4) { + makefromsr(); + out("exception3_read_prefetch_68040bug(opcode, newpc, oldsr);\n"); + } else { + out("exception3_read_prefetch(opcode, newpc);\n"); + } write_return_cycles(0); out("}\n"); setpc ("newpc"); @@ -7043,7 +7077,19 @@ static void gen_opcode (unsigned int opcode) if (cpu_level >= 4) { out("if (pc & 1) {\n"); out("m68k_areg(regs, 7) -= 6;\n"); - out("exception3_read_prefetch(opcode, pc);\n"); + if (cpu_level == 5) { + out("regs.sr &= 0xFF00; sr &= 0xFF;\n"); + out("regs.sr |= sr;\n"); + makefromsr(); + out("exception3_read_prefetch(opcode, pc);\n"); + } else { + // stacked SR is original SR. Real SR has CCR part zeroed. + out("uae_u16 oldsr = regs.sr;\n"); + out("regs.sr &= 0xFF00; sr &= 0xFF;\n"); + out("regs.sr |= sr;\n"); + makefromsr(); + out("exception3_read_prefetch_68040bug(opcode, pc, oldsr);\n"); + } write_return_cycles(0); out("}\n"); } @@ -7067,7 +7113,7 @@ static void gen_opcode (unsigned int opcode) } branch_inst = 1; tail_ce020_done = true; - next_level_040_to_030(); + next_cpu_level = cpu_level - 1; break; case i_JSR: { @@ -7281,7 +7327,7 @@ static void gen_opcode (unsigned int opcode) out("if (s & 1) {\n"); if (cpu_level < 4) out("m68k_areg(regs, 7) -= 4;\n"); - out("exception3_read_prefetch(opcode, s);\n"); + out("exception3_read_prefetch(opcode, oldpc + s);\n"); write_return_cycles(0); out("}\n"); } @@ -8342,7 +8388,6 @@ bccl_not68020: write_return_cycles(0); out("}\n"); addcycles000(4); - trace_t0_68040_only(); break; case i_MOVE2C: if (cpu_level == 1) { @@ -8722,7 +8767,6 @@ bccl_not68020: next_cpu_level = 2 - 1; genastore_tas("src", curi->smode, "srcreg", curi->size, "src"); fill_prefetch_next(); - trace_t0_68040_only(); } next_level_000(); break; diff --git a/include/newcpu.h b/include/newcpu.h index ef9428bb..061fdda1 100644 --- a/include/newcpu.h +++ b/include/newcpu.h @@ -669,6 +669,7 @@ extern void flush_cpu_caches_040(uae_u16 opcode); extern void REGPARAM3 MakeSR (void) REGPARAM; extern void REGPARAM3 MakeFromSR(void) REGPARAM; extern void REGPARAM3 MakeFromSR_T0(void) REGPARAM; +extern void REGPARAM3 MakeFromSR_intmask(uae_u16 oldsr, uae_u16 newsr) REGPARAM; extern void REGPARAM3 Exception (int) REGPARAM; extern void REGPARAM3 Exception_cpu(int) REGPARAM; extern void REGPARAM3 ExceptionL (int, uaecptr) REGPARAM; @@ -737,6 +738,7 @@ extern void exception3_read_access(uae_u32 opcode, uaecptr addr, int size, int f extern void exception3_read_access2(uae_u32 opcode, uaecptr addr, int size, int fc); extern void exception3_write_access(uae_u32 opcode, uaecptr addr, int size, uae_u32 val, int fc); extern void exception3_read_prefetch(uae_u32 opcode, uaecptr addr); +extern void exception3_read_prefetch_68040bug(uae_u32 opcode, uaecptr addr, uae_u16 secondarysr); extern void exception3_read_prefetch_only(uae_u32 opcode, uaecptr addr); extern void exception3_notinstruction(uae_u32 opcode, uaecptr addr); extern void hardware_exception2(uaecptr addr, uae_u32 v, bool read, bool ins, int size); diff --git a/newcpu.cpp b/newcpu.cpp index e312b446..9214dbfd 100644 --- a/newcpu.cpp +++ b/newcpu.cpp @@ -80,6 +80,8 @@ static int last_di_for_exception_3; static bool last_notinstruction_for_exception_3; /* set when writing exception stack frame */ static int exception_in_exception; +/* secondary SR for handling 68040 bug */ +static uae_u16 last_sr_for_exception3; static void exception3_read_special(uae_u32 opcode, uaecptr addr, int size, int fc); @@ -2375,19 +2377,41 @@ void REGPARAM2 MakeFromSR(void) MakeFromSR_x(0); } +void REGPARAM2 MakeFromSR_intmask(uae_u16 oldsr, uae_u16 newsr) +{ +#if 0 + int oldlvl = (oldsr >> 8) & 7; + int newlvl = (newsr >> 8) & 7; + int ilvl = intlev(); + + // interrupt mask lowered and allows new interrupt to start? + if (newlvl < oldlvl && ilvl > 0 && ilvl > newlvl && ilvl <= oldlvl) { + if (currprefs.cpu_model >= 68020) { + unset_special(SPCFLAG_INT); + } + } +#endif +} + +static bool internalexception(int nr) +{ + return nr == 5 || nr == 6 || nr == 7 || (nr >= 32 && nr <= 47); +} + static void exception_check_trace (int nr) { unset_special (SPCFLAG_TRACE | SPCFLAG_DOTRACE); if (regs.t1) { /* trace stays pending if exception is div by zero, chk, - * trapv or trap #x + * trapv or trap #x. Except if 68040 or 68060. */ - if (nr == 5 || nr == 6 || nr == 7 || (nr >= 32 && nr <= 47)) - set_special (SPCFLAG_DOTRACE); + if (currprefs.cpu_model < 68040 && internalexception(nr)) { + set_special(SPCFLAG_DOTRACE); + } // 68010 and RTE format error: trace is not cleared - if (nr == 14 && currprefs.cpu_model == 68010) + if (nr == 14 && currprefs.cpu_model == 68010) { set_special(SPCFLAG_DOTRACE); - + } } regs.t1 = regs.t0 = 0; } @@ -2553,8 +2577,6 @@ Interrupt: */ -static void exception3f(uae_u32 opcode, uaecptr addr, bool writeaccess, bool instructionaccess, bool notinstruction, uaecptr pc, int size, int fc); - static int iack_cycle(int nr) { int vector; @@ -2725,6 +2747,7 @@ kludge_me_do: regs.irc = regs.read_buffer; exception3_read_access(regs.opcode, newpc, sz_word, 2); } else { + exception_check_trace(nr); exception3_notinstruction(regs.ir, newpc); } return; @@ -3169,6 +3192,12 @@ static void Exception_normal (int nr) if (currprefs.cpu_model == 68060 && interrupt) { regs.m = 0; } + if (currprefs.cpu_model == 68040 && nr == 3 && (last_op_for_exception_3 & 0x10000)) { + // Weird 68040 bug with RTR and RTE. New SR when exception starts. Stacked SR is different! + // Just replace it in stack, it is safe enough because we are in address error exception + // any other exception would halt the CPU. + x_put_word(m68k_areg(regs, 7), last_sr_for_exception3); + } kludge_me_do: if ((regs.vbr & 1) && currprefs.cpu_model <= 68010) { cpu_halt(CPU_HALT_DOUBLE_FAULT); @@ -3203,6 +3232,7 @@ kludge_me_do: regs.irc = regs.read_buffer; exception3_read_access(regs.ir, newpc, sz_word, 2); } else { + exception_check_trace(nr); exception3_notinstruction(regs.ir, newpc); } return; @@ -3277,6 +3307,9 @@ void REGPARAM2 Exception_cpu(int nr) // Check T0 trace // RTE format error ignores T0 trace if (nr != 14) { + if (currprefs.cpu_model >= 68040 && internalexception(nr)) { + t0 = false; + } if (t0) { activate_trace(); } @@ -4002,7 +4035,7 @@ void mmu_op (uae_u32 opcode, uae_u32 extra) static void do_trace (void) { // need to store PC because of branch instructions - regs.trace_pc = regs.pc; + regs.trace_pc = m68k_getpc(); if (regs.t0 && !regs.t1 && currprefs.cpu_model >= 68020) { // this is obsolete return; @@ -7175,7 +7208,7 @@ uae_u8 *restore_mmu (uae_u8 *src) #endif /* SAVESTATE */ -static void exception3f (uae_u32 opcode, uaecptr addr, bool writeaccess, bool instructionaccess, bool notinstruction, uaecptr pc, int size, int fc) +static void exception3f(uae_u32 opcode, uaecptr addr, bool writeaccess, bool instructionaccess, bool notinstruction, uaecptr pc, int size, int fc, uae_u16 secondarysr) { if (currprefs.cpu_model >= 68040) addr &= ~1; @@ -7185,7 +7218,7 @@ static void exception3f (uae_u32 opcode, uaecptr addr, bool writeaccess, bool in else last_addr_for_exception_3 = pc; } else if (pc == 0xffffffff) { - last_addr_for_exception_3 = m68k_getpc (); + last_addr_for_exception_3 = m68k_getpc(); } else { last_addr_for_exception_3 = pc; } @@ -7195,6 +7228,7 @@ static void exception3f (uae_u32 opcode, uaecptr addr, bool writeaccess, bool in last_fc_for_exception_3 = fc >= 0 ? fc : (instructionaccess ? 2 : 1); last_notinstruction_for_exception_3 = notinstruction; last_size_for_exception_3 = size; + last_sr_for_exception3 = secondarysr; Exception (3); #if EXCEPTION3_DEBUGGER activate_debugger(); @@ -7204,11 +7238,11 @@ static void exception3f (uae_u32 opcode, uaecptr addr, bool writeaccess, bool in void exception3_notinstruction(uae_u32 opcode, uaecptr addr) { last_di_for_exception_3 = 1; - exception3f (opcode, addr, true, false, true, 0xffffffff, 1, -1); + exception3f (opcode, addr, true, false, true, 0xffffffff, 1, -1, 0); } static void exception3_read_special(uae_u32 opcode, uaecptr addr, int size, int fc) { - exception3f(opcode, addr, false, 0, false, 0xffffffff, size, fc); + exception3f(opcode, addr, false, 0, false, 0xffffffff, size, fc, 0); } // 68010 special prefetch handling @@ -7222,7 +7256,7 @@ void exception3_read_prefetch_only(uae_u32 opcode, uae_u32 addr) x_do_cycles(4 * cpucycleunit); } last_di_for_exception_3 = 0; - exception3f(opcode, addr, false, true, false, m68k_getpc(), sz_word, -1); + exception3f(opcode, addr, false, true, false, m68k_getpc(), sz_word, -1, 0); } // Some hardware accepts address error aborted reads or writes as normal reads/writes. @@ -7233,8 +7267,15 @@ void exception3_read_prefetch(uae_u32 opcode, uaecptr addr) if (currprefs.cpu_model == 68000) { m68k_incpci(2); } - exception3f(opcode, addr, false, true, false, m68k_getpc(), sz_word, -1); + exception3f(opcode, addr, false, true, false, m68k_getpc(), sz_word, -1, 0); +} +void exception3_read_prefetch_68040bug(uae_u32 opcode, uaecptr addr, uae_u16 secondarysr) +{ + x_do_cycles(4 * cpucycleunit); + last_di_for_exception_3 = 0; + exception3f(opcode | 0x10000, addr, false, true, false, m68k_getpc(), sz_word, -1, secondarysr); } + void exception3_read_access(uae_u32 opcode, uaecptr addr, int size, int fc) { x_do_cycles(4 * cpucycleunit); @@ -7268,7 +7309,7 @@ void exception3_read(uae_u32 opcode, uaecptr addr, int size, int fc) opcode = regs.ir; } last_di_for_exception_3 = 1; - exception3f(opcode, addr, false, ia, ni, 0xffffffff, size & 15, fc); + exception3f(opcode, addr, false, ia, ni, 0xffffffff, size & 15, fc, 0); } void exception3_write(uae_u32 opcode, uaecptr addr, int size, uae_u32 val, int fc) { @@ -7287,7 +7328,7 @@ void exception3_write(uae_u32 opcode, uaecptr addr, int size, uae_u32 val, int f } last_di_for_exception_3 = 1; regs.write_buffer = val; - exception3f(opcode, addr, true, ia, ni, 0xffffffff, size & 15, fc); + exception3f(opcode, addr, true, ia, ni, 0xffffffff, size & 15, fc, 0); } void exception2_setup(uae_u32 opcode, uaecptr addr, bool read, int size, uae_u32 fc) diff --git a/newcpu_common.cpp b/newcpu_common.cpp index b0d389f4..9a791862 100644 --- a/newcpu_common.cpp +++ b/newcpu_common.cpp @@ -1726,6 +1726,7 @@ void areg_68000_long_replace_low(int reg, uae_u16 v) } // Change F-line to privilege violation if missing co-pro +// 68040 and 68060 always return F-line bool privileged_copro_instruction(uae_u16 opcode) { if (currprefs.cpu_model >= 68020 && !regs.s) { @@ -1735,14 +1736,16 @@ bool privileged_copro_instruction(uae_u16 opcode) // cpSAVE and cpRESTORE: privilege violation if user mode. if ((opcode & 0xf1c0) == 0xf100) { // cpSAVE + // check if valid EA if (mode == 2 || (mode >= 4 && mode <= 6) || (mode == 7 && (reg == 0 || reg == 1))) { - if ((currprefs.cpu_model >= 68040 && id > 0) || currprefs.cpu_model < 68040) + if (currprefs.cpu_model < 68040 || (currprefs.cpu_model >= 68040 && id == 1)) return true; } } else if ((opcode & 0xf1c0) == 0xf140) { // cpRESTORE + // check if valid EA if (mode == 2 || mode == 3 || (mode >= 5 && mode <= 6) || (mode == 7 && reg <= 3)) { - if ((currprefs.cpu_model >= 68040 && id > 0) || currprefs.cpu_model < 68040) + if (currprefs.cpu_model < 68040 || (currprefs.cpu_model >= 68040 && id == 1)) return true; } }