From b134c34f1a74dabff3891e209f8daa38595bc73f Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Wed, 19 Oct 2022 15:24:01 +0300 Subject: [PATCH] 68000 accurate IPL timing emulation --- cia.cpp | 67 +++++-- custom.cpp | 122 +++++++------ debug.cpp | 75 ++++++-- gencpu.cpp | 450 +++++++++++++++++++++++++++++++++++----------- include/debug.h | 11 +- include/newcpu.h | 15 +- newcpu.cpp | 142 +++++++++------ newcpu_common.cpp | 12 +- 8 files changed, 643 insertions(+), 251 deletions(-) diff --git a/cia.cpp b/cia.cpp index 9854e6ec..33edcda1 100644 --- a/cia.cpp +++ b/cia.cpp @@ -156,6 +156,7 @@ static bool oldovl; static bool led; static int led_old_brightness; static evt_t led_cycles_on, led_cycles_off, led_cycle; +static evt_t cia_now_evt; static int kbstate, kblostsynccnt; static evt_t kbhandshakestart; @@ -721,7 +722,7 @@ void CIA_handler(void) CIA_calctimers(); } -static int get_cia_sync_cycles(void) +static int get_cia_sync_cycles(int *syncdelay) { evt_t c = get_e_cycles(); int div10 = c % DIV10; @@ -729,13 +730,13 @@ static int get_cia_sync_cycles(void) int synccycle = e_clock_sync * E_CYCLE_UNIT; if (div10 < synccycle) { add += synccycle - div10; - } - else if (div10 > synccycle) { + } else if (div10 > synccycle) { add += DIV10 - div10; add += synccycle; } - // sync + 4 first cycles of E-clock - add += e_clock_start * E_CYCLE_UNIT; + *syncdelay = add; + // 4 first cycles of E-clock + add = e_clock_start * E_CYCLE_UNIT; return add; } @@ -758,7 +759,9 @@ static void CIA_sync_interrupt(int num, uae_u8 icr) c->icr1 |= icr; return; } - int delay = get_cia_sync_cycles(); + int syncdelay = 0; + int delay = get_cia_sync_cycles(&syncdelay); + delay += syncdelay; event2_newevent_xx(-1, DIV10 + delay, num, CIA_synced_interrupt); } else { c->icr1 |= icr; @@ -2172,6 +2175,36 @@ addrbank cia_bank = { ABFLAG_IO | ABFLAG_CIA, S_READ, S_WRITE, NULL, 0x3f01, 0xbfc000 }; +static int cia_cycles(int delay, int phase, int val, int post) +{ +#ifdef DEBUGGER + if (currprefs.cpu_memory_cycle_exact && debug_dma) { + while (delay > 0) { + int hpos = current_hpos(); + record_cia_access(0xfffff, 0, 0, 0, hpos, vpos, phase + 1); + phase += 2; + if (post) { + x_do_cycles_post(CYCLE_UNIT, val); + } else { + x_do_cycles_pre(CYCLE_UNIT); + } + delay -= CYCLE_UNIT; + } + } else { +#endif + if (delay > 0) { + if (post) { + x_do_cycles_post(delay, val); + } else { + x_do_cycles_pre(delay); + } + } +#ifdef DEBUGGER + } +#endif + return phase; +} + static void cia_wait_pre(int cianummask) { if (currprefs.cachesize || currprefs.cpu_thread) @@ -2188,8 +2221,15 @@ static void cia_wait_pre(int cianummask) #endif #ifndef CUSTOM_SIMPLE - int delay = get_cia_sync_cycles(); - x_do_cycles_pre(delay); + cia_now_evt = get_cycles(); + int syncdelay = 0; + int delay = get_cia_sync_cycles(&syncdelay); + if (debug_dma) { + cia_cycles(syncdelay, 100, 0, 0); + cia_cycles(delay, 0, 0, 0); + } else { + cia_cycles(syncdelay + delay, 0, 0, 0); + } #endif } @@ -2199,7 +2239,7 @@ static void cia_wait_post(int cianummask, uaecptr addr, uae_u32 value, bool rw) if (currprefs.cpu_memory_cycle_exact && debug_dma) { int r = (addr & 0xf00) >> 8; int hpos = current_hpos(); - record_cia_access(r, cianummask, value, rw, hpos, vpos); + record_cia_access(r, cianummask, value, rw, hpos, vpos, -1); } #endif @@ -2213,7 +2253,14 @@ static void cia_wait_post(int cianummask, uaecptr addr, uae_u32 value, bool rw) do_cycles(12 * E_CYCLE_UNIT); } else { // Last 6 cycles of E-clock - x_do_cycles_post(e_clock_end * E_CYCLE_UNIT, value); + // IPL fetch that got delayed by CIA access? + if (cia_now_evt == regs.ipl_evt) { + int phase = cia_cycles((e_clock_end - 2) * E_CYCLE_UNIT, 4, value, 1); + regs.ipl[0] = regs.ipl_pin; + cia_cycles(2 * E_CYCLE_UNIT, phase, value, 1); + } else { + cia_cycles(e_clock_end * E_CYCLE_UNIT, 4, value, 1); + } #if CIA_IRQ_PROCESS_DELAY if (currprefs.cpu_memory_cycle_exact) { cia_interrupt_disabled &= ~cianummask; diff --git a/custom.cpp b/custom.cpp index 038810a4..ad844330 100644 --- a/custom.cpp +++ b/custom.cpp @@ -14887,12 +14887,13 @@ STATIC_INLINE void decide_fetch_ce(int hpos) // blitter idle cycles do count!) extern int cpu_tracer; -static int dma_cycle(uaecptr addr, uae_u32 value, int *mode) +static int dma_cycle(uaecptr addr, uae_u32 value, int *mode, int *ipl) { int hpos_next, hpos_old; blt_info.nasty_cnt = 1; blt_info.wait_nasty = 0; + *ipl = regs.ipl_pin; if (cpu_tracer < 0) { return current_hpos_safe(); } @@ -14926,6 +14927,7 @@ static int dma_cycle(uaecptr addr, uae_u32 value, int *mode) if (blt_info.nasty_cnt > 0) { blt_info.nasty_cnt++; } + *ipl = regs.ipl_pin; do_cycles(1 * CYCLE_UNIT); /* bus was allocated to dma channel, wait for next cycle.. */ } @@ -14957,13 +14959,14 @@ void do_copper(void) uae_u32 wait_cpu_cycle_read(uaecptr addr, int mode) { uae_u32 v = 0; - int hpos; + int hpos, ipl; + evt_t now = get_cycles(); sync_cycles(); x_do_cycles_pre(CYCLE_UNIT); - hpos = dma_cycle(addr, 0xffffffff, &mode); + hpos = dma_cycle(addr, 0xffffffff, &mode, &ipl); #ifdef DEBUGGER if (debug_dma) { @@ -15012,118 +15015,131 @@ uae_u32 wait_cpu_cycle_read(uaecptr addr, int mode) x_do_cycles_post(CYCLE_UNIT, v); + // if IPL fetch was pending and CPU had wait states + // Use ipl_pin value from previous cycle + if (now == regs.ipl_evt && regs.ipl_pin_change_evt > now + cpuipldelay2) { + regs.ipl[0] = ipl; + } + return v; } -uae_u32 wait_cpu_cycle_read_ce020(uaecptr addr, int mode) +void wait_cpu_cycle_write(uaecptr addr, int mode, uae_u32 v) { - uae_u32 v = 0; - int hpos; + int hpos, ipl; + evt_t now = get_cycles(); sync_cycles(); x_do_cycles_pre(CYCLE_UNIT); - hpos = dma_cycle(0xffffffff, 0xffff, NULL); + hpos = dma_cycle(addr, v, &mode, &ipl); #ifdef DEBUGGER if (debug_dma) { - int reg = 0x1000; - if (mode < 0) { + int reg = 0x1100; + if (mode == -3) { + reg |= 2; + } else if (mode < 0) { reg |= 4; } else if (mode > 0) { reg |= 2; } else { reg |= 1; } - record_dma_read(reg, addr, hpos, vpos, DMARECORD_CPU, mode == -2 || mode == 2 ? 0 : 1); + record_dma_write(reg, v, addr, hpos, vpos, DMARECORD_CPU, 1); } peekdma_data.mask = 0; #endif - switch (mode) { - case -1: - v = get_long(addr); - break; - case -2: - v = get_longi(addr); - break; - case 1: - v = get_word(addr); - break; - case 2: - v = get_wordi(addr); - break; - case 0: - v = get_byte(addr); - break; - } - -#ifdef DEBUGGER - if (debug_dma) { - record_dma_read_value(v); + if (mode > -2) { + if (mode < 0) { + put_long(addr, v); + } else if (mode > 0) { + put_word(addr, v); + } else if (mode == 0) { + put_byte(addr, v); + } } -#endif - regs.chipset_latch_rw = regs.chipset_latch_read = v; + regs.chipset_latch_rw = regs.chipset_latch_write = v; x_do_cycles_post(CYCLE_UNIT, v); - return v; + // if IPL fetch was pending and CPU had wait states: + // Use ipl_pin value from previous cycle + if (now == regs.ipl_evt && regs.ipl_pin_change_evt > now + cpuipldelay2) { + regs.ipl[0] = ipl; + } } -void wait_cpu_cycle_write(uaecptr addr, int mode, uae_u32 v) + +uae_u32 wait_cpu_cycle_read_ce020(uaecptr addr, int mode) { - int hpos; + uae_u32 v = 0; + int hpos, ipl; sync_cycles(); x_do_cycles_pre(CYCLE_UNIT); - hpos = dma_cycle(addr, v, &mode); + hpos = dma_cycle(0xffffffff, 0xffff, NULL, &ipl); #ifdef DEBUGGER if (debug_dma) { - int reg = 0x1100; - if (mode == -3) { - reg |= 2; - } else if (mode < 0) { + int reg = 0x1000; + if (mode < 0) { reg |= 4; } else if (mode > 0) { reg |= 2; } else { reg |= 1; } - record_dma_write(reg, v, addr, hpos, vpos, DMARECORD_CPU, 1); + record_dma_read(reg, addr, hpos, vpos, DMARECORD_CPU, mode == -2 || mode == 2 ? 0 : 1); } peekdma_data.mask = 0; #endif - if (mode > -2) { - if (mode < 0) { - put_long(addr, v); - } else if (mode > 0) { - put_word(addr, v); - } else if (mode == 0) { - put_byte(addr, v); - } + switch (mode) { + case -1: + v = get_long(addr); + break; + case -2: + v = get_longi(addr); + break; + case 1: + v = get_word(addr); + break; + case 2: + v = get_wordi(addr); + break; + case 0: + v = get_byte(addr); + break; } - regs.chipset_latch_rw = regs.chipset_latch_write = v; +#ifdef DEBUGGER + if (debug_dma) { + record_dma_read_value(v); + } +#endif + + regs.chipset_latch_rw = regs.chipset_latch_read = v; x_do_cycles_post(CYCLE_UNIT, v); + return v; } void wait_cpu_cycle_write_ce020(uaecptr addr, int mode, uae_u32 v) { - int hpos; + int hpos, ipl; sync_cycles(); x_do_cycles_pre(CYCLE_UNIT); - hpos = dma_cycle(0xffffffff, 0xffff, NULL); + hpos = dma_cycle(0xffffffff, 0xffff, NULL, &ipl); #ifdef DEBUGGER if (debug_dma) { diff --git a/debug.cpp b/debug.cpp index 02f087a5..b0841e48 100644 --- a/debug.cpp +++ b/debug.cpp @@ -1310,6 +1310,21 @@ static int nr_cop_records[2], curr_cop_set, selected_cop_set; static struct dma_rec *dma_record[2]; static int dma_record_toggle, dma_record_frame[2]; +static void record_dma_clear(int r) +{ + struct dma_rec *dr = dma_record[r]; + for (int v = 0; v < NR_DMA_REC_VPOS; v++) { + for (int h = 0; h < NR_DMA_REC_HPOS; h++) { + struct dma_rec *dr2 = &dr[v * NR_DMA_REC_HPOS + h]; + memset(dr2, 0, sizeof(struct dma_rec)); + dr->reg = 0xffff; + dr2->reg = 0xffff; + dr2->cf_reg = 0xffff; + dr2->addr = 0xffffffff; + } + } +} + static void dma_record_init(void) { if (!dma_record[0]) { @@ -1319,14 +1334,13 @@ static void dma_record_init(void) dma_record_toggle = 0; dma_record_frame[0] = -1; dma_record_frame[1] = -1; + record_dma_clear(0); + record_dma_clear(1); } } void record_dma_reset(int start) { - int v, h; - struct dma_rec *dr, *dr2; - if (start && !dma_record[0]) { dma_record_init(); } @@ -1334,16 +1348,7 @@ void record_dma_reset(int start) return; } dma_record_toggle ^= 1; - dr = dma_record[dma_record_toggle]; - for (v = 0; v < NR_DMA_REC_VPOS; v++) { - for (h = 0; h < NR_DMA_REC_HPOS; h++) { - dr2 = &dr[v * NR_DMA_REC_HPOS + h]; - memset (dr2, 0, sizeof (struct dma_rec)); - dr2->reg = 0xffff; - dr2->cf_reg = 0xffff; - dr2->addr = 0xffffffff; - } - } + record_dma_clear(dma_record_toggle); if (start && !debug_dma) { debug_dma = start; } @@ -1967,6 +1972,21 @@ void record_dma_ipl(int hpos, int vpos) dr = &dma_record[dma_record_toggle][vpos * NR_DMA_REC_HPOS + hpos]; dr->intlev = regs.intmask; dr->ipl = regs.ipl_pin; + dr->evt2 |= DMA_EVENT2_IPL; +} + +void record_dma_ipl_sample(int hpos, int vpos) +{ + struct dma_rec *dr; + + if (!dma_record[0]) + return; + if (hpos >= NR_DMA_REC_HPOS || vpos >= NR_DMA_REC_VPOS) + return; + dr = &dma_record[dma_record_toggle][vpos * NR_DMA_REC_HPOS + hpos]; + dr->intlev = regs.intmask; + dr->ipl2 = regs.ipl_pin; + dr->evt2 |= DMA_EVENT2_IPLSAMPLE; } void record_dma_event(uae_u32 evt, int hpos, int vpos) @@ -2100,7 +2120,7 @@ void record_dma_clear(int hpos, int vpos) dr->cf_reg = 0xffff; } -void record_cia_access(int r, int mask, uae_u16 value, bool rw, int hpos, int vpos) +void record_cia_access(int r, int mask, uae_u16 value, bool rw, int hpos, int vpos, int phase) { struct dma_rec* dr; @@ -2112,10 +2132,14 @@ void record_cia_access(int r, int mask, uae_u16 value, bool rw, int hpos, int vp dr = &dma_record[dma_record_toggle][vpos * NR_DMA_REC_HPOS + hpos]; dma_record_frame[dma_record_toggle] = timeframes; + if (dr->ciaphase < 0) { + return; + } dr->ciamask = mask; dr->ciareg = r; dr->ciavalue = value; dr->ciarw = rw; + dr->ciaphase = phase; } void record_dma_read(uae_u16 reg, uae_u32 addr, int hpos, int vpos, int type, int extra) @@ -2256,6 +2280,8 @@ static bool get_record_dma_info(struct dma_rec *dr, int hpos, int vpos, TCHAR *l ipl = 0; } *iplp = ipl; + if (dr->ipl2 > 0) { + } } if (ipl >= 0) { _stprintf(l1, _T("[%02X %d]"), hpos, ipl); @@ -2405,12 +2431,25 @@ static bool get_record_dma_info(struct dma_rec *dr, int hpos, int vpos, TCHAR *l l3[cl2++] = 'B'; } + if (dr->evt2 & DMA_EVENT2_IPLSAMPLE) { + l3[cl2++] = '^'; + } + } if (l5) { - if (dr->ciamask) { - _stprintf(l5, _T("%c%s%X %04X"), dr->ciarw ? 'W' : 'R', - dr->ciamask == 1 ? _T("A") : (dr->ciamask == 2 ? _T("B") : _T("X")), - dr->ciareg, dr->ciavalue); + if (dr->ciaphase) { + if (dr->ciamask) { + _stprintf(l5, _T("%c%s%X %04X"), dr->ciarw ? 'W' : 'R', + dr->ciamask == 1 ? _T("A") : (dr->ciamask == 2 ? _T("B") : _T("X")), + dr->ciareg, dr->ciavalue); + } else { + int ph = dr->ciaphase; + if (ph >= 100) { + _tcscpy(l5, _T(" - ")); + } else { + _stprintf(l5, _T(" %u "), ph - 1); + } + } } } if (l6) { diff --git a/gencpu.cpp b/gencpu.cpp index 7dd8dfa4..6ba883fd 100644 --- a/gencpu.cpp +++ b/gencpu.cpp @@ -100,6 +100,10 @@ static int func_noret; #define GF_PCP2 0x200000 // if set, long word fetch does it at the beginning (not second word) #define GF_NOLIPL 0x400000 +// If set, IPL sample is in mid-cycle +#define GF_IPLMID 0x800000 +// genastore + IPL +#define GF_IPL 0x1000000 typedef enum { @@ -164,6 +168,7 @@ static int last_access_offset_ipl; static int last_access_offset_ipl_prev; static int ipl_fetch_cycles; static int ipl_fetch_cycles_prev; +static int ipl_fetch_brace_level; static void out(const char *format, ...) { @@ -234,14 +239,15 @@ static void out(const char *format, ...) } } -static void insertstring(const char *s, int offset) +static int insertstring(const char *s, int offset) { int len = strlen(s); - memmove(outbuffer + offset + len + brace_level, outbuffer + offset, strlen(outbuffer + offset) + 1); - for (int i = 0; i < brace_level; i++) { + memmove(outbuffer + offset + len + ipl_fetch_brace_level, outbuffer + offset, strlen(outbuffer + offset) + 1); + for (int i = 0; i < ipl_fetch_brace_level; i++) { outbuffer[offset + i] = '\t'; } - memcpy(outbuffer + offset + brace_level, s, len); + memcpy(outbuffer + offset + ipl_fetch_brace_level, s, len); + return len + ipl_fetch_brace_level; } static int get_current_cycles(void) @@ -254,6 +260,9 @@ static void set_ipl_pre(void) if (using_ce) { pre_ipl = 1; out("ipl_fetch_pre();\n"); + } else if (using_prefetch) { + pre_ipl = 1; + //out("ipl_fetch_prefetch(%d);\n", get_current_cycles() + 2); } } @@ -261,6 +270,7 @@ static void set_ipl(void) { last_access_offset_ipl = strlen(outbuffer); ipl_fetch_cycles = get_current_cycles(); + ipl_fetch_brace_level = brace_level; ipl_fetched = 2; } @@ -276,14 +286,19 @@ static void set_last_access_ipl(void) return; last_access_offset_ipl = strlen(outbuffer); ipl_fetch_cycles = get_current_cycles(); + ipl_fetch_brace_level = brace_level; } -static void set_last_access_ipl_prev(void) +static void set_last_access_ipl_prev(uae_u32 flags) { + if (flags & GF_IPLMID) { + pre_ipl = 2; + } if (ipl_fetched < 0) return; last_access_offset_ipl_prev = strlen(outbuffer); ipl_fetch_cycles_prev = get_current_cycles(); + ipl_fetch_brace_level = brace_level; } @@ -528,7 +543,7 @@ static bool isprefetch020(void) static void check_ipl(void) { - if (ipl_fetched == 2) { + if (ipl_fetched >= 2) { return; } // So far it seems 68000 IPL fetch happens when CPU is doing @@ -663,7 +678,11 @@ static void returntail (bool iswrite) static void returncycles(int cycles) { if (using_nocycles) { - out("return 0;\n"); + if (func_noret) { + out("return;\n"); + } else { + out("return 0;\n"); + } return; } if (func_noret) { @@ -712,7 +731,7 @@ static void write_return_cycles2(int end, int no4) } if (using_ce || using_prefetch) { if (end < 0) { - if (using_ce) { + if (using_ce || func_noret) { out("return;\n"); } else { out("return 0;\n"); @@ -732,7 +751,7 @@ static void write_return_cycles2(int end, int no4) } } else { if (end < 0) { - if (using_ce020) { + if (using_ce020 || func_noret) { out("return;\n"); } else { out("return 0;\n"); @@ -832,10 +851,14 @@ static void addcycles000_2(int cycles) insn_n_cycles += cycles; } #endif -static void addcycles000_3(void) +static void addcycles000_3(bool notest) { if (using_ce) { - out("if (cycles > 0) %s(cycles);\n", do_cycles); + if (notest) { + out("%s(cycles);\n", do_cycles); + } else { + out("if (cycles > 0) %s(cycles);\n", do_cycles); + } } count_ncycles++; } @@ -1075,7 +1098,11 @@ static void gen_nextilong2(const char *type, const char *name, int flags, int mo } else if (using_ce) { /* we must do this because execution order of (something | something2) is not defined */ if (flags & GF_NOREFILL) { - set_last_access_ipl(); + if ((flags & GF_IPL) && !(flags & GF_IPLMID)) { + set_ipl(); + } else if (!(flags & GF_IPL)) { + set_last_access_ipl(); + } out("%s = %s(%d) << 16;\n", name, prefetch_word, r + 2); count_readw++; out("%s |= regs.irc;\n", name); @@ -1091,7 +1118,11 @@ static void gen_nextilong2(const char *type, const char *name, int flags, int mo do_instruction_buserror(); strcpy(bus_error_code, bus_error_code2); bus_error_code2[0] = 0; - set_last_access_ipl(); + if ((flags & GF_IPL)) { + set_ipl(); + } else if (!(flags & GF_IPL)) { + set_last_access_ipl(); + } out("%s |= %s(%d);\n", name, prefetch_word, r + 4); count_readw++; check_bus_error_ins(r + 4, -1); @@ -1228,14 +1259,15 @@ static const char *gen_nextibyte(int flags) static void makefromsr(void) { out("MakeFromSR();\n"); - if (using_ce || isce020()) + if (isce020()) { out("intlev_load(); \n"); + } } static void makefromsr_t0(void) { - out("intlev_load();\n"); - if (using_ce || isce020()) { + if (isce020()) { + out("intlev_load();\n"); out("ipl_fetch_now();\n"); } if (using_prefetch || using_ce) { @@ -1279,6 +1311,9 @@ static void fill_prefetch_bcc(void) } next_level_000(); } + if (using_ce) { + out("ipl_fetch_next();\n"); + } out("%s(%d);\n", prefetch_word, m68k_pc_offset + 2); count_readw++; check_prefetch_bus_error(m68k_pc_offset + 2, -1, 0); @@ -1474,7 +1509,9 @@ static void fill_prefetch_full_000_special(int pctype, const char *format, ...) va_end(parms); out(outbuf); } - set_ipl(); + if (using_ce) { + out("ipl_fetch_next();\n"); + } out("%s(%d);\n", prefetch_word, 2); count_readw++; if (pctype > 0) { @@ -3704,7 +3741,7 @@ static void genamode2x (amodes mode, const char *reg, wordsizes size, const char addmmufixup(reg, size, mode); } - set_last_access_ipl_prev(); + set_last_access_ipl_prev(0); if (getv == 1) { const char *srcbx = !(flags & GF_FC) ? srcb : "sfc_nommu_get_byte"; @@ -3749,6 +3786,9 @@ static void genamode2x (amodes mode, const char *reg, wordsizes size, const char switch (size) { case sz_byte: { + if (flags & GF_IPL) { + set_ipl(); + } out("uae_s8 %s = %s(%sa);\n", name, srcbx, name); count_readw++; check_bus_error(name, 0, 0, 0, NULL, 1, 0); @@ -3756,6 +3796,9 @@ static void genamode2x (amodes mode, const char *reg, wordsizes size, const char } case sz_word: { + if (flags & GF_IPL) { + set_ipl(); + } out("uae_s16 %s = %s(%sa);\n", name, srcwx, name); count_readw++; check_bus_error(name, 0, 0, 1, NULL, 1, 0); @@ -3764,21 +3807,33 @@ static void genamode2x (amodes mode, const char *reg, wordsizes size, const char case sz_long: { if ((flags & GF_REVERSE) && mode == Apdi) { + if ((flags & GF_IPL) && !(flags & GF_IPLMID)) { + set_ipl(); + } out("uae_s32 %s = %s(%sa + 2);\n", name, srcwx, name); count_readw++; check_bus_error(name, 0, 0, 1, NULL, 1, 0); - if (!(flags & GF_NOLIPL)) { - set_last_access_ipl_prev(); + if (!(flags & GF_NOLIPL) && !(flags & GF_IPL)) { + set_last_access_ipl_prev(flags); + } + if ((flags & GF_IPL) && (flags & GF_IPLMID)) { + set_ipl(); } out("%s |= %s(%sa) << 16;\n", name, srcwx, name); count_readw++; check_bus_error(name, -2, 0, 1, NULL, 1, 0); } else { + if ((flags & GF_IPL) && !(flags & GF_IPLMID)) { + set_ipl(); + } out("uae_s32 %s = %s(%sa) << 16;\n", name, srcwx, name); count_readw++; check_bus_error(name, 0, 0, 1, NULL, 1, 0); - if (!(flags & GF_NOLIPL)) { - set_last_access_ipl_prev(); + if (!(flags & GF_NOLIPL) && !(flags & GF_IPL)) { + set_last_access_ipl_prev(flags); + } + if ((flags & GF_IPL) && (flags & GF_IPLMID)) { + set_ipl(); } out("%s |= %s(%sa + 2);\n", name, srcwx, name); count_readw++; @@ -3999,7 +4054,8 @@ static void genastore_2 (const char *from, amodes mode, const char *reg, wordsiz const char *dstwx = !(flags & GF_FC) ? dstw : "dfc_nommu_put_word"; const char *dstlx = !(flags & GF_FC) ? dstl : "dfc_nommu_put_long"; - set_last_access_ipl_prev(); + set_last_access_ipl_prev(flags); + if (!(flags & GF_NOFAULTPC)) gen_set_fault_pc (false, false); if (using_mmu) { @@ -4085,8 +4141,8 @@ static void genastore_2 (const char *from, amodes mode, const char *reg, wordsiz fill_prefetch_next_after(0, NULL); insn_n_cycles += 4; } - if (!(flags & GF_NOLIPL)) { - //set_last_access_ipl_prev(); + if (flags & GF_IPL) { + set_ipl(); } out("%s(%sa, %s >> 16);\n", dstwx, to, from); sprintf(tmp, "%s >> 16", from); @@ -4100,8 +4156,8 @@ static void genastore_2 (const char *from, amodes mode, const char *reg, wordsiz if (flags & GF_SECONDWORDSETFLAGS) { genflags(flag_logical, g_instr->size, "src", "", ""); } - if (!(flags & GF_NOLIPL)) { - //set_last_access_ipl_prev(); + if (flags & GF_IPL) { + set_ipl(); } out("%s(%sa + 2, %s);\n", dstwx, to, from); count_writew++; @@ -4139,7 +4195,7 @@ static void genastore_2 (const char *from, amodes mode, const char *reg, wordsiz if (store_dir > 1) { fill_prefetch_next_after(0, NULL); } - set_last_access_ipl_prev(); + set_last_access_ipl_prev(flags); out("%s(%sa, %s >> 16); \n", dstwx, to, from); sprintf(tmp, "%s >> 16", from); count_writew++; @@ -4152,7 +4208,7 @@ static void genastore_2 (const char *from, amodes mode, const char *reg, wordsiz if (flags & GF_SECONDWORDSETFLAGS) { genflags(flag_logical, g_instr->size, "src", "", ""); } - set_last_access_ipl_prev(); + set_last_access_ipl_prev(flags); out("%s(%sa + 2, %s); \n", dstwx, to, from); count_writew++; check_bus_error(to, 2, 1, 1, from, 1, pcoffset); @@ -4211,15 +4267,15 @@ static void genastore_2 (const char *from, amodes mode, const char *reg, wordsiz static void genastore(const char *from, amodes mode, const char *reg, wordsizes size, const char *to) { - genastore_2 (from, mode, reg, size, to, 0, 0); + genastore_2(from, mode, reg, size, to, 0, 0); } static void genastore_tas (const char *from, amodes mode, const char *reg, wordsizes size, const char *to) { - genastore_2 (from, mode, reg, size, to, 0, GF_LRMW); + genastore_2(from, mode, reg, size, to, 0, GF_LRMW); } static void genastore_cas (const char *from, amodes mode, const char *reg, wordsizes size, const char *to) { - genastore_2 (from, mode, reg, size, to, 0, GF_LRMW | GF_NOFAULTPC); + genastore_2(from, mode, reg, size, to, 0, GF_LRMW | GF_NOFAULTPC); } // write to addr + 2, write to addr + 0 static void genastore_rev(const char *from, amodes mode, const char *reg, wordsizes size, const char *to) @@ -4554,7 +4610,7 @@ static void genmovemel(uae_u16 opcode) if (table68k[opcode].dmode == Aipi) { out("m68k_areg(regs, dstreg) = srca;\n"); } - set_last_access_ipl_prev(); + set_last_access_ipl_prev(0); if (cpu_level <= 1) { out("%s(srca);\n", srcw); // and final extra word fetch that goes nowhere.. count_readw++; @@ -4571,7 +4627,12 @@ static void genmovemel(uae_u16 opcode) static void genmovemel_ce(uae_u16 opcode) { int size = table68k[opcode].size == sz_long ? 4 : 2; + int ipl = 0; amodes mode = table68k[opcode].dmode; + if (mode == Aipi) { + ipl = 1; + set_ipl(); + } out("uae_u16 mask = %s;\n", gen_nextiword(mode < Ad16 ? GF_PCM2 : 0)); do_instruction_buserror(); out("uae_u32 dmask = mask & 0xff, amask = (mask >> 8) & 0xff;\n"); @@ -4579,7 +4640,6 @@ static void genmovemel_ce(uae_u16 opcode) addcycles000(2); } genamode(NULL, mode, "dstreg", table68k[opcode].size, "src", 2, -1, GF_AA | GF_MOVE | GF_PCM2); - set_ipl(); movem_ex3(0); if (table68k[opcode].size == sz_long) { out("while (dmask) {\n"); @@ -4638,6 +4698,9 @@ static void genmovemel_ce(uae_u16 opcode) out("m68k_areg(regs, dstreg) = srca;\n"); } count_ncycles++; + if (!ipl) { + set_ipl(); + } fill_prefetch_next_t(); } @@ -4738,7 +4801,7 @@ static void genmovemle(uae_u16 opcode) next_level_020_to_010(); } count_ncycles++; - set_last_access_ipl_prev(); + set_last_access_ipl_prev(0); fill_prefetch_next_t(); get_prefetch_020(); } @@ -4847,7 +4910,7 @@ static void genmovemle_ce (uae_u16 opcode) } } count_ncycles++; - set_last_access_ipl_prev(); + set_ipl(); fill_prefetch_next_t(); } @@ -4893,7 +4956,7 @@ static void shift_ce(amodes dmode, int size) out("{\n"); out("int cycles = %d;\n", c); out("cycles += 2 * ccnt;\n"); - addcycles000_3(); + addcycles000_3(false); out("}\n"); } next_level_020_to_010(); @@ -5347,9 +5410,19 @@ static void resetvars (void) } +static void illg(void) +{ + if (func_noret) { + out("op_illg_noret(opcode);\n"); + } else { + out("op_illg(opcode);\n"); + } +} + static void gen_opcode (unsigned int opcode) { struct instr *curi = table68k + opcode; + int ipl = 0; resetvars(); @@ -5377,7 +5450,7 @@ static void gen_opcode (unsigned int opcode) // do not unnecessarily create useless mmuop030 // functions when CPU is not 68030 if (curi->mnemo == i_MMUOP030 && cpu_level != 3 && !cpu_generic) { - out("op_illg(opcode);\n"); + illg(); did_prefetch = -1; goto end; } @@ -5431,6 +5504,7 @@ static void gen_opcode (unsigned int opcode) if (cpu_level == 1 && curi->smode == imm) { c += 2; } + set_ipl_pre(); if (cpu_level == 1 && (curi->smode == imm || curi->smode == Dreg)) { fill_prefetch_next_after(0, "m68k_dreg(regs, dstreg) = (src);\n"); } else { @@ -5448,8 +5522,9 @@ static void gen_opcode (unsigned int opcode) } else { fill_prefetch_next_after(0, "ccr_68000_long_move_ae_LZN(src);\n"); } - if (c > 0) + if (c > 0) { addcycles000(c); + } genastore_rev("src", curi->dmode, "dstreg", curi->size, "dst"); } else { if (curi->dmode == Dreg) { @@ -5461,8 +5536,9 @@ static void gen_opcode (unsigned int opcode) fill_prefetch_next_t(); loopmodeextra = 4; } - if (c > 0) + if (c > 0) { addcycles000(c); + } if (curi->dmode != Dreg) { genastore_rev("src", curi->dmode, "dstreg", curi->size, "dst"); } @@ -5503,8 +5579,9 @@ static void gen_opcode (unsigned int opcode) case i_SUB: { int c = 0; + int earlyipl = curi->size == sz_long && curi->dmode == Dreg && (curi->smode == imm || curi->smode == immi || curi->smode == Dreg || curi->smode == Areg); genamodedual(curi, - curi->smode, "srcreg", curi->size, "src", 1, 0, + curi->smode, "srcreg", curi->size, "src", 1, earlyipl ? GF_IPL : 0, curi->dmode, "dstreg", curi->size, "dst", 1, GF_RMW); genflags(flag_sub, curi->size, "newv", "src", "dst"); if (curi->size == sz_long) { @@ -5517,6 +5594,9 @@ static void gen_opcode (unsigned int opcode) if (cpu_level == 1 && curi->smode == immi) { c += 2; } + if (curi->smode == immi || curi->smode == Dreg || curi->smode == Areg) { // SUBQ, SUB.L reg,reg + set_ipl_pre(); + } fill_prefetch_next_after(1, "uae_s16 bnewv = (uae_s16)dst - (uae_s16)src;\n" "int bflgs = ((uae_s16)(src)) < 0;\n" @@ -5544,7 +5624,6 @@ static void gen_opcode (unsigned int opcode) "SET_VFLG((bflgs ^ bflgo) & (bflgn ^ bflgo));\n"); } if (c > 0) { - set_ipl(); addcycles000(c); } genastore_rev("newv", curi->dmode, "dstreg", curi->size, "dst"); @@ -5584,9 +5663,9 @@ static void gen_opcode (unsigned int opcode) } loopmodeextra = curi->size == sz_long ? 4 : 2; } + set_ipl_pre(); fill_prefetch_next_after(0, "areg_68000_long_replace_low(dstreg, newv);\n"); if (c > 0) { - set_ipl(); addcycles000(c); } genastore("newv", curi->dmode, "dstreg", sz_long, "dst"); @@ -5595,10 +5674,14 @@ static void gen_opcode (unsigned int opcode) case i_SUBX: exception_pc_offset_extra_000 = 2; next_level_000(); - if (!isreg(curi->smode)) + if (!isreg(curi->smode)) { addcycles000(2); + if (curi->size != sz_long) { + set_ipl(); + } + } genamode(curi, curi->smode, "srcreg", curi->size, "src", 1, 0, GF_AA | GF_REVERSE); - genamode(curi, curi->dmode, "dstreg", curi->size, "dst", 1, 0, GF_AA | GF_REVERSE | GF_RMW | GF_SECONDEA); + genamode(curi, curi->dmode, "dstreg", curi->size, "dst", 1, 0, GF_AA | GF_REVERSE | GF_RMW | GF_SECONDEA | (curi->size == sz_long && !isreg(curi->smode) ? GF_IPL | GF_IPLMID : 0)); out("uae_u32 newv = dst - src - (GET_XFLG() ? 1 : 0);\n"); if (cpu_level >= 2) { genflags(flag_subx, curi->size, "newv", "src", "dst"); @@ -5621,6 +5704,7 @@ static void gen_opcode (unsigned int opcode) } if (isreg(curi->smode)) { if (curi->size == sz_long) { + set_ipl_pre(); // set CCR using only low word if prefetch bus error fill_prefetch_next_after(1, "int bflgs = ((uae_s16)(src)) < 0;\n" @@ -5666,6 +5750,9 @@ static void gen_opcode (unsigned int opcode) if (!isreg (curi->smode)) addcycles000(2); genamode(curi, curi->smode, "srcreg", curi->size, "src", 1, 0, GF_AA); + if (!isreg(curi->smode)) { + set_ipl_pre(); + } genamode(curi, curi->dmode, "dstreg", curi->size, "dst", 1, 0, GF_AA | GF_RMW); out("uae_u16 newv_lo = (dst & 0xF) - (src & 0xF) - (GET_XFLG() ? 1 : 0);\n"); out("uae_u16 newv_hi = (dst & 0xF0) - (src & 0xF0);\n"); @@ -5707,8 +5794,9 @@ static void gen_opcode (unsigned int opcode) case i_ADD: { int c = 0; + int earlyipl = curi->size == sz_long && curi->dmode == Dreg && (curi->smode == imm || curi->smode == immi || curi->smode == Dreg || curi->smode == Areg); genamodedual(curi, - curi->smode, "srcreg", curi->size, "src", 1, 0, + curi->smode, "srcreg", curi->size, "src", 1, earlyipl ? GF_IPL : 0, curi->dmode, "dstreg", curi->size, "dst", 1, GF_RMW); genflags(flag_add, curi->size, "newv", "src", "dst"); if (curi->size == sz_long) { @@ -5722,6 +5810,9 @@ static void gen_opcode (unsigned int opcode) // 68010 Immediate long instructions 2 cycles faster, Q variants have same speed. c += 2; } + if (curi->smode == immi || curi->smode == Dreg || curi->smode == Areg) { // ADDQ, ADD.L reg,reg + set_ipl_pre(); + } fill_prefetch_next_after(1, "uae_s16 bnewv = (uae_s16)dst + (uae_s16)src;\n" "int bflgs = ((uae_s16)(src)) < 0;\n" @@ -5749,7 +5840,6 @@ static void gen_opcode (unsigned int opcode) "SET_VFLG((bflgs ^ bflgn) & (bflgo ^ bflgn));\n"); } if (c > 0) { - set_ipl(); addcycles000(c); } genastore_rev("newv", curi->dmode, "dstreg", curi->size, "dst"); @@ -5763,8 +5853,9 @@ static void gen_opcode (unsigned int opcode) fill_prefetch_next_t(); loopmodeextra = 4; } - if (c > 0) + if (c > 0) { addcycles000(c); + } if (curi->dmode != Dreg) { genastore_rev("newv", curi->dmode, "dstreg", curi->size, "dst"); } @@ -5788,9 +5879,9 @@ static void gen_opcode (unsigned int opcode) } loopmodeextra = curi->size == sz_long ? 4 : 2; } + set_ipl_pre(); fill_prefetch_next_after(1, "areg_68000_long_replace_low(dstreg, newv);\n"); if (c > 0) { - set_ipl(); addcycles000(c); } genastore("newv", curi->dmode, "dstreg", sz_long, "dst"); @@ -5801,9 +5892,12 @@ static void gen_opcode (unsigned int opcode) next_level_000(); if (!isreg(curi->smode)) { addcycles000(2); + if (curi->size != sz_long) { + set_ipl(); + } } genamode(curi, curi->smode, "srcreg", curi->size, "src", 1, 0, GF_AA | GF_REVERSE); - genamode(curi, curi->dmode, "dstreg", curi->size, "dst", 1, 0, GF_AA | GF_REVERSE | GF_RMW | GF_SECONDEA); + genamode(curi, curi->dmode, "dstreg", curi->size, "dst", 1, 0, GF_AA | GF_REVERSE | GF_RMW | GF_SECONDEA | (curi->size == sz_long && !isreg(curi->smode) ? GF_IPL | GF_IPLMID : 0)); out("uae_u32 newv = dst + src + (GET_XFLG() ? 1 : 0);\n"); if (cpu_level >= 2) { genflags(flag_addx, curi->size, "newv", "src", "dst"); @@ -5826,6 +5920,7 @@ static void gen_opcode (unsigned int opcode) } if (isreg(curi->smode)) { if (curi->size == sz_long) { + set_ipl_pre(); // set CCR using only low word if prefetch bus error fill_prefetch_next_after(1, "int bflgs = ((uae_s16)(src)) < 0;\n" @@ -5871,6 +5966,9 @@ static void gen_opcode (unsigned int opcode) if (!isreg (curi->smode)) addcycles000(2); genamode(curi, curi->smode, "srcreg", curi->size, "src", 1, 0, GF_AA); + if (!isreg(curi->smode)) { + set_ipl_pre(); + } genamode(curi, curi->dmode, "dstreg", curi->size, "dst", 1, 0, GF_AA | GF_RMW); out("uae_u16 newv_lo = (src & 0xF) + (dst & 0xF) + (GET_XFLG() ? 1 : 0);\n"); out("uae_u16 newv_hi = (src & 0xF0) + (dst & 0xF0);\n"); @@ -5904,8 +6002,6 @@ static void gen_opcode (unsigned int opcode) fill_prefetch_next_after(1, NULL); if (isreg (curi->smode)) { addcycles000(2); - } else { - set_ipl(); } exception_pc_offset_extra_000 = 0; genastore("newv", curi->dmode, "dstreg", curi->size, "dst"); @@ -5916,8 +6012,8 @@ static void gen_opcode (unsigned int opcode) if (curi->smode == Dreg) { if (curi->size == sz_long) { // prefetch bus error and long register: only low word is updated + set_ipl_pre(); fill_prefetch_next_after(1, "dreg_68000_long_replace_low(srcreg, dst);\n"); - set_ipl(); genastore_rev("dst", curi->smode, "srcreg", curi->size, "src"); } else { genastore_rev("dst", curi->smode, "srcreg", curi->size, "src"); @@ -5951,8 +6047,8 @@ static void gen_opcode (unsigned int opcode) if (curi->smode == Dreg) { if (curi->size == sz_long) { // prefetch bus error and long register: only low word is updated + set_ipl_pre(); fill_prefetch_next_after(1, "dreg_68000_long_replace_low(srcreg, newv);\n"); - set_ipl(); genastore_rev("newv", curi->smode, "srcreg", curi->size, "src"); } else { genastore_rev("newv", curi->smode, "srcreg", curi->size, "src"); @@ -5979,7 +6075,7 @@ static void gen_opcode (unsigned int opcode) } break; case i_NBCD: - genamode(curi, curi->smode, "srcreg", curi->size, "src", 1, 0, GF_RMW); + genamode(curi, curi->smode, "srcreg", curi->size, "src", 1, 0, GF_RMW | (isreg(curi->smode) ? 0 : GF_IPL)); out("uae_u16 newv_lo = - (src & 0xF) - (GET_XFLG() ? 1 : 0);\n"); out("uae_u16 newv_hi = - (src & 0xF0);\n"); out("uae_u16 newv;\n"); @@ -6012,7 +6108,6 @@ static void gen_opcode (unsigned int opcode) fill_prefetch_next_after(1, NULL); addcycles000(2); } else { - set_ipl(); fill_prefetch_next_after(1, NULL); } genastore("newv", curi->smode, "srcreg", curi->size, "src"); @@ -6025,10 +6120,10 @@ static void gen_opcode (unsigned int opcode) if (curi->size == sz_long) { // prefetch bus error and long register: only low word is updated // N flag from high word. Z both. - fill_prefetch_next_after(1, + set_ipl_pre(); + fill_prefetch_next_after(1, "m68k_dreg(regs, srcreg) = (src & 0xffff0000);\n" "SET_VFLG(0);SET_ZFLG(1);SET_NFLG(0);SET_CFLG(0);\n"); - set_ipl(); genastore_rev("0", curi->smode, "srcreg", curi->size, "src"); } else { genastore_rev("0", curi->smode, "srcreg", curi->size, "src"); @@ -6040,8 +6135,9 @@ static void gen_opcode (unsigned int opcode) } else { fill_prefetch_next_after(1, NULL); } - if (isreg(curi->smode) && curi->size == sz_long) + if (isreg(curi->smode) && curi->size == sz_long) { addcycles000(2); + } if (curi->smode != Dreg) { genastore_rev("0", curi->smode, "srcreg", curi->size, "src"); } @@ -6101,12 +6197,12 @@ static void gen_opcode (unsigned int opcode) if (curi->size == sz_long) { // prefetch bus error and long register: only low word is updated // N flag from high word. Z both. - fill_prefetch_next_after(1, + set_ipl_pre(); + fill_prefetch_next_after(1, "dreg_68000_long_replace_low(srcreg, dst);\n" "SET_VFLG(0);SET_ZFLG(!dst);\n" "SET_NFLG(dst & 0x80000000);\n" "SET_CFLG(0);\n"); - set_ipl(); genastore_rev("dst", curi->smode, "srcreg", curi->size, "src"); } else { genastore_rev("dst", curi->smode, "srcreg", curi->size, "src"); @@ -6135,20 +6231,27 @@ static void gen_opcode (unsigned int opcode) fill_prefetch_next_t(); break; case i_BTST: - genamodedual(curi, - curi->smode, "srcreg", curi->size, "src", 1, 0, - curi->dmode, "dstreg", curi->size, "dst", 1, 0); if (curi->size == sz_long) { + if (curi->smode != Dreg) { + set_ipl(); + } else { + set_ipl_pre(); + } + genamodedual(curi, + curi->smode, "srcreg", curi->size, "src", 1, 0, + curi->dmode, "dstreg", curi->size, "dst", 1, 0); fill_prefetch_next_after(1, NULL); - set_ipl(); bsetcycles(curi); out("SET_ZFLG(1 ^ ((dst >> src) & 1));\n"); } else { + genamodedual(curi, + curi->smode, "srcreg", curi->size, "src", 1, 0, + curi->dmode, "dstreg", curi->size, "dst", 1, 0); bsetcycles(curi); if (curi->dmode == imm) { // btst dn,#x + set_ipl_pre(); fill_prefetch_next_after(1, NULL); - set_ipl(); addcycles000(2); out("SET_ZFLG(1 ^ ((dst >> src) & 1));\n"); } else { @@ -6169,8 +6272,8 @@ static void gen_opcode (unsigned int opcode) curi->smode, "srcreg", curi->size, "src", 1, 0, curi->dmode, "dstreg", curi->size, "dst", 1, GF_RMW); if (curi->size == sz_long) { + set_ipl_pre(); fill_prefetch_next_after(1, NULL); - set_ipl(); } else { if (curi->smode == Dreg || curi->smode >= imm) { fill_prefetch_next_after(1, NULL); @@ -6208,11 +6311,17 @@ static void gen_opcode (unsigned int opcode) case i_CMPM: disable_noflags = 1; exception_pc_offset_extra_000 = 2; - genamodedual(curi, - curi->smode, "srcreg", curi->size, "src", 1, GF_AA, - curi->dmode, "dstreg", curi->size, "dst", 1, GF_AA | GF_NOLIPL); + if (curi->size == sz_long) { + genamodedual(curi, + curi->smode, "srcreg", curi->size, "src", 1, GF_AA | GF_IPL | GF_IPLMID, + curi->dmode, "dstreg", curi->size, "dst", 1, GF_AA | GF_NOLIPL); + } else { + set_ipl(); + genamodedual(curi, + curi->smode, "srcreg", curi->size, "src", 1, GF_AA, + curi->dmode, "dstreg", curi->size, "dst", 1, GF_AA | GF_NOLIPL); + } genflags (flag_cmp, curi->size, "newv", "src", "dst"); - set_ipl(); fill_prefetch_next_t(); break; case i_CMP: @@ -6222,8 +6331,8 @@ static void gen_opcode (unsigned int opcode) curi->dmode, "dstreg", curi->size, "dst", 1, 0); genflags(flag_cmp, curi->size, "newv", "src", "dst"); if (curi->dmode == Dreg && curi->size == sz_long) { + set_ipl_pre(); fill_prefetch_next_after(1, NULL); - set_ipl(); addcycles000(2); } else { fill_prefetch_next_t(); @@ -6235,14 +6344,12 @@ static void gen_opcode (unsigned int opcode) curi->smode, "srcreg", curi->size, "src", 1, 0, curi->dmode, "dstreg", sz_long, "dst", 1, 0); genflags(flag_cmp, sz_long, "newv", "src", "dst"); + set_ipl_pre(); if (curi->dmode == Areg) { fill_prefetch_next_after(1, NULL); } else { fill_prefetch_next_t(); } - if (curi->smode == imm || curi->smode == Dreg || curi->smode == Areg) { - set_ipl(); - } addcycles000(2); break; /* The next two are coded a little unconventional, but they are doing @@ -6278,7 +6385,7 @@ static void gen_opcode (unsigned int opcode) case i_MVPMR: // MOVEP M->R out("uaecptr mempa = m68k_areg(regs, srcreg) + (uae_s32)(uae_s16)%s;\n", gen_nextiword(0)); check_prefetch_buserror(m68k_pc_offset, -2); - ipl_fetched = 1; + set_ipl(); genamode(curi, curi->dmode, "dstreg", curi->size, "dst", 2, 0, cpu_level == 1 ? GF_NOFETCH : 0); if (curi->size == sz_word) { out("uae_u16 val = (%s(mempa) & 0xff) << 8;\n", srcb); @@ -6295,6 +6402,7 @@ static void gen_opcode (unsigned int opcode) count_readw++; check_bus_error("memp", 2, 0, 0, NULL, 1, 2); + set_ipl(); // unexpected position.. // upper word gets updated after two bytes (makes only difference if bus error is possible) if (cpu_level <= 1) { out("m68k_dreg(regs, dstreg) = (m68k_dreg(regs, dstreg) & 0x0000ffff) | val;\n"); @@ -6411,12 +6519,36 @@ static void gen_opcode (unsigned int opcode) } else { flags |= GF_PCM2 | GF_PCP2; } + + if (curi->dmode == Apdi && (curi->smode > Areg)) { + flags |= GF_IPL | GF_IPLMID; + } + if (curi->dmode == Apdi && (curi->smode <= Areg)) { + set_ipl_pre(); + } + } else { if (curi->smode >= Aind && curi->smode != absw && curi->smode != imm) { flags |= GF_PCM2; } else { flags |= GF_PCM2 | GF_PCP2; } + + if (curi->dmode == Aipi && curi->smode == imm) { + set_ipl(); + } else if (curi->dmode == Aipi && curi->smode > Areg) { + flags |= GF_IPL; + } + + if (curi->dmode == Apdi && curi->smode == imm) { + set_ipl(); + } else if (curi->dmode == Apdi && curi->smode > Areg) { + flags |= GF_IPL; + } + + if (curi->dmode == Apdi && curi->smode <= Areg) { + set_ipl_pre(); + } } genamode(curi, curi->smode, "srcreg", curi->size, "src", 1, 0, flags); @@ -6436,8 +6568,9 @@ static void gen_opcode (unsigned int opcode) flags |= GF_MOVE | GF_APDI; flags |= dualprefetch ? GF_NOREFILL : 0; - if (curi->dmode == Apdi && curi->size == sz_long) + if (curi->dmode == Apdi && curi->size == sz_long) { flags |= GF_REVERSE; + } // prefetch bus error support if (curi->mnemo == i_MOVE) { @@ -6540,12 +6673,54 @@ static void gen_opcode (unsigned int opcode) } else if (curi->dmode == Apdi) { storeflags |= GF_PCP2; } + + if (curi->size == sz_long) { + if (curi->dmode == Aind && curi->smode == imm) { + set_ipl(); + } else if (curi->dmode == Aind && curi->smode > Areg && curi->smode != absl) { + storeflags |= GF_IPL; + } + + if (curi->dmode == Aipi && curi->smode > Areg) { + set_ipl(); + } + + if ((curi->dmode == Ad16 || curi->dmode == PC16) && curi->smode > Areg && curi->smode != imm) { + storeflags |= GF_IPL; + } + if ((curi->dmode == Ad8r || curi->dmode == PC8r || curi->dmode == absl) && curi->smode > Areg && curi->smode != imm) { + storeflags |= GF_IPL; + } + if (curi->dmode == absw) { + storeflags |= GF_IPL; + } + + } else { + if (curi->dmode == Aipi && curi->smode <= Areg) { + set_ipl_pre(); + } + } + // MOVE EA,-(An) long writes are always reversed. Reads are normal. if (curi->dmode == Apdi && curi->size == sz_long) { genastore_2("src", curi->dmode, "dstreg", curi->size, "dst", 1, storeflags | GF_EXC3 | GF_MOVE); } else { genastore_2("src", curi->dmode, "dstreg", curi->size, "dst", 0, storeflags | GF_EXC3 | GF_MOVE); } + + if (curi->size == sz_long) { + if (curi->dmode == Aind && curi->smode == absl) { + set_ipl(); + } + if (curi->dmode == absl) { + set_ipl(); + } + } else { + if (curi->dmode == absl || curi->dmode == absw) { + set_ipl(); + } + } + sync_m68k_pc(); if (dualprefetch) { fill_prefetch_full_000(curi->mnemo == i_MOVE ? 2 : 1); @@ -6580,10 +6755,10 @@ static void gen_opcode (unsigned int opcode) out("MakeSR();\n"); if (isreg (curi->smode)) { if (cpu_level == 0 && curi->size == sz_word) { + set_ipl_pre(); fill_prefetch_next_after(1, "MakeSR();\n" "m68k_dreg(regs, srcreg) = (m68k_dreg(regs, srcreg) & ~0xffff) | ((regs.sr) & 0xffff);\n"); - set_ipl(); } else { fill_prefetch_next_after(1, NULL); } @@ -6622,12 +6797,14 @@ static void gen_opcode (unsigned int opcode) if (curi->size == sz_byte) { // MOVE TO CCR addcycles000(4); + set_ipl(); out("MakeSR();\nregs.sr &= 0xFF00;\nregs.sr |= src & 0xFF;\n"); makefromsr(); } else { // MOVE TO SR check_trace(); addcycles000(4); + set_ipl(); out("regs.sr = src;\n"); makefromsr_t0(); } @@ -6810,6 +6987,7 @@ static void gen_opcode (unsigned int opcode) case i_PULSE: /* 68060 debug */ break; case i_RTE: + ipl_fetched = 10; addop_ce020 (curi, 0, 0); next_level_000(); if (cpu_level <= 1 && using_exception_3) { @@ -7027,6 +7205,7 @@ static void gen_opcode (unsigned int opcode) next_cpu_level = cpu_level - 1; break; case i_RTD: + ipl_fetched = 10; out("uaecptr oldpc = %s;\n", getpc); addop_ce020 (curi, 0, 0); if (using_mmu) { @@ -7097,9 +7276,7 @@ static void gen_opcode (unsigned int opcode) write_return_cycles(0); out("}\n"); } - ipl_fetched = 1; - genastore_2("src", Apdi, "7", sz_long, "old", 0, GF_NOLIPL); - set_ipl(); + genastore_2("src", Apdi, "7", sz_long, "old", 0, GF_IPLMID); genastore("m68k_areg(regs, 7)", curi->smode, "srcreg", sz_long, "src"); out("m68k_areg(regs, 7) += offs;\n"); fill_prefetch_next_t(); @@ -7117,15 +7294,15 @@ static void gen_opcode (unsigned int opcode) } else { m68k_pc_offset = 4; genamode(curi, curi->smode, "srcreg", curi->size, "src", 1, 0, 0); - genamode(NULL, am_unknown, "src", sz_long, "old", 1, 0, 0); + genamode(NULL, am_unknown, "src", sz_long, "old", 1, 0, GF_IPLMID); out("m68k_areg(regs, 7) = src + 4;\n"); m68k_pc_offset = 2; genastore("old", curi->smode, "srcreg", curi->size, "src"); - set_ipl(); fill_prefetch_next_t(); } break; case i_RTS: + ipl_fetched = 10; addop_ce020 (curi, 0, 0); out("uaecptr oldpc = %s;\n", getpc); if (cpu_level <= 1 && using_exception_3) { @@ -7205,6 +7382,11 @@ static void gen_opcode (unsigned int opcode) if (using_prefetch) { out("uae_u16 opcode_v = opcode;\n"); } + if (using_ce) { + // IPL is not fetched if instruction traps + out("int ipl0 = regs.ipl[0];\n"); + out("int ipl1 = regs.ipl[1];\n"); + } fill_prefetch_next_after(1, "if (GET_VFLG()) {\n" "MakeSR();\n" @@ -7217,6 +7399,10 @@ static void gen_opcode (unsigned int opcode) "if(regs.t1) opcode |= 0x10000;\n" "}\n"); out("if (GET_VFLG()) {\n"); + if (using_ce) { + out("regs.ipl[0] = ipl0;\n"); + out("regs.ipl[1] = ipl1;\n"); + } if (using_prefetch) { // If exception vector is odd, // stacked opcode is TRAPV @@ -7244,6 +7430,7 @@ static void gen_opcode (unsigned int opcode) next_level_000(); break; case i_RTR: + ipl_fetched = 10; if (cpu_level <= 1 && using_exception_3) { out("if (m68k_areg(regs, 7) & 1) {\n"); incpc("2"); @@ -7570,6 +7757,7 @@ static void gen_opcode (unsigned int opcode) case i_Bcc: out("uaecptr oldpc = %s;\n", getpc); tail_ce020_done = true; + ipl_fetched = 10; if (curi->size == sz_long) { if (cpu_level < 2) { addcycles000(2); @@ -7617,7 +7805,7 @@ static void gen_opcode (unsigned int opcode) } push_ins_cnt(); if (using_prefetch) { - incpc ("(uae_s32)src + 2"); + incpc("(uae_s32)src + 2"); fill_prefetch_full_000_special(2, NULL); if (using_ce) out("return;\n"); @@ -7626,7 +7814,6 @@ static void gen_opcode (unsigned int opcode) } else { incpc ("(uae_s32)src + 2"); add_head_cycs (6); - check_ipl_always(); fill_prefetch_full_020(); returncycles (10); } @@ -7678,11 +7865,15 @@ bccl_not68020: if (curi->smode == Ad8r || curi->smode == PC8r) addcycles000(2); genastore("srca", curi->dmode, "dstreg", curi->size, "dst"); + set_ipl(); fill_prefetch_next_t(); break; case i_PEA: - if (curi->smode == Ad8r || curi->smode == PC8r) + if (curi->smode == Ad8r || curi->smode == PC8r) { addcycles000(2); + set_ipl(); + ipl = 1; + } if (cpu_level <= 1 && using_exception_3) { out("uae_u16 old_opcode = opcode;\n"); } @@ -7692,6 +7883,10 @@ bccl_not68020: addcycles000(2); } if (!(curi->smode == absw || curi->smode == absl)) { + if (!ipl) { + set_ipl_pre(); + ipl = 1; + } fill_prefetch_next_after(0, "m68k_areg(regs, 7) += 4;\n"); } if (cpu_level <= 1 && using_exception_3) { @@ -7706,9 +7901,14 @@ bccl_not68020: write_return_cycles(0); out("}\n"); } - genastore("srca", Apdi, "7", sz_long, "dst"); if ((curi->smode == absw || curi->smode == absl)) { + genastore("srca", Apdi, "7", sz_long, "dst"); + if (!ipl) { + set_ipl(); + } fill_prefetch_next_t(); + } else { + genastore_2("srca", Apdi, "7", sz_long, "dst", 0, 0); } break; case i_DBcc: @@ -7716,6 +7916,7 @@ bccl_not68020: // cc false, counter expired: idle cycle, prefetch (from branch address), 2xprefetch (from next address) // cc false, counter not expired: idle cycle, prefetch tail_ce020_done = true; + ipl_fetched = 10; if(cpu_level <= 1) { // this is quite annoying instruction.. out("int pcadjust = -2;\n"); @@ -7840,13 +8041,15 @@ bccl_not68020: } irc2ir(); add_head_cycs (6); - check_ipl_always(); if (using_prefetch || using_ce) { copy_opcode(); if (cpu_level == 0) { out("if(regs.t1) opcode |= 0x10000;\n"); } + if (using_ce) { + out("ipl_fetch_next();\n"); + } out("%s(%d);\n", prefetch_word, 2); check_prefetch_bus_error(-2, 0, -1); did_prefetch = 1; @@ -7904,7 +8107,7 @@ bccl_not68020: } fill_prefetch_next_extra("if (!val)", "if(!val && regs.t1) opcode |= 0x10000;\n"); genastore("val", curi->smode, "srcreg", curi->size, "src"); - addcycles000_3(); + addcycles000_3(false); addcycles000_nonces("(val ? 2 : 0)"); } else { fill_prefetch_next_after(1, NULL); @@ -7932,7 +8135,7 @@ bccl_not68020: out("uae_u32 rem = (uae_u32)dst %% (uae_u32)(uae_u16)src;\n"); if (using_ce) { out("int cycles = getDivu68kCycles((uae_u32)dst, (uae_u16)src);\n"); - addcycles000_3(); + addcycles000_3(true); } if (cpu_level <= 1) { addcycles000_nonces("getDivu68kCycles((uae_u32)dst, (uae_u16)src)"); @@ -7944,6 +8147,7 @@ bccl_not68020: out("newv = (newv & 0xffff) | ((uae_u32)rem << 16);\n"); genastore("newv", curi->dmode, "dstreg", sz_long, "dst"); out("}\n"); + set_ipl(); fill_prefetch_next_t(); sync_m68k_pc(); count_ncycles++; @@ -7956,6 +8160,7 @@ bccl_not68020: next_level_020_to_010(); break; case i_DIVS: + ipl_fetched = 10; exception_oldpc(); tail_ce020_done = true; genamodedual(curi, @@ -7970,12 +8175,24 @@ bccl_not68020: write_return_cycles(0); out("}\n"); pop_ins_cnt(); + if (using_ce || cpu_level <= 1) { + out("int extra = 0;\n"); + } if (using_ce) { - out("int cycles = getDivs68kCycles((uae_s32)dst, (uae_s16)src);\n"); - addcycles000_3(); + out("int cycles = getDivs68kCycles((uae_s32)dst, (uae_s16)src, &extra);\n"); + out("if (extra) {\n"); + out("cycles -= 2;\n"); + addcycles000_3(true); + out("ipl_fetch_next();\n"); + out("cycles = 2;\n"); + addcycles000_3(true); + out("} else {\n"); + addcycles000_3(true); + out("ipl_fetch_next();\n"); + out("}\n"); } if (cpu_level <= 1) { - addcycles000_nonces("getDivs68kCycles((uae_s32)dst, (uae_s16)src)"); + addcycles000_nonces("getDivs68kCycles((uae_s32)dst, (uae_s16)src, &extra)"); } out("if (dst == 0x80000000 && src == -1) {\n"); out("setdivsflags((uae_s32)dst, (uae_s16)src);\n"); @@ -8017,7 +8234,7 @@ bccl_not68020: genflags (flag_logical, sz_long, "newv", "", ""); if (using_ce) { out("int cycles = getMulu68kCycles(src);\n"); - addcycles000_3(); + addcycles000_3(true); } if (cpu_level <= 1) { addcycles000_nonces("getMulu68kCycles(src)"); @@ -8045,7 +8262,7 @@ bccl_not68020: genflags (flag_logical, sz_long, "newv", "", ""); if (using_ce) { out("int cycles = getMuls68kCycles(src);\n"); - addcycles000_3(); + addcycles000_3(true); } if (cpu_level <= 1) { addcycles000_nonces("getMuls68kCycles(src)"); @@ -8060,12 +8277,11 @@ bccl_not68020: break; case i_CHK: disable_noflags = 1; + ipl_fetched = 10; exception_oldpc(); - genamode(curi, curi->smode, "srcreg", curi->size, "src", 1, 0, 0); + genamode(curi, curi->smode, "srcreg", curi->size, "src", 1, 0, GF_IPL); genamode(curi, curi->dmode, "dstreg", curi->size, "dst", 1, 0, 0); sync_m68k_pc(); - set_last_access_ipl(); - ipl_fetched = 1; addcycles000(4); out("if (dst > src) {\n"); out("setchkundefinedflags(src, dst, %d);\n", curi->size); @@ -8079,6 +8295,7 @@ bccl_not68020: write_return_cycles(0); out("}\n"); out("setchkundefinedflags(src, dst, %d);\n", curi->size); + set_ipl(); fill_prefetch_next_t(); break; case i_CHK2: @@ -8129,6 +8346,7 @@ bccl_not68020: default: term(); } out("CLEAR_CZNV();\n"); + set_ipl_pre(); if (curi->size == sz_long) { fill_prefetch_next_noopcodecopy("SET_NFLG(val & 0x8000);\nSET_ZFLG(!(val & 0xffff));\n"); } else { @@ -8169,6 +8387,7 @@ bccl_not68020: default: term(); } out("CLEAR_CZNV();\n"); + set_ipl_pre(); if (curi->size == sz_long) { fill_prefetch_next_noopcodecopy("SET_NFLG(val & 0x8000);\nSET_ZFLG(!(val & 0xffff));\n"); } else { @@ -8213,6 +8432,7 @@ bccl_not68020: default: term(); } out("CLEAR_CZNV();\n"); + set_ipl_pre(); if (curi->size == sz_long) { fill_prefetch_next_noopcodecopy("SET_NFLG(val & 0x8000);\nSET_ZFLG(!(val & 0xffff));\n"); } else { @@ -8249,6 +8469,7 @@ bccl_not68020: default: term(); } out("CLEAR_CZNV();\n"); + set_ipl_pre(); if (curi->size == sz_long) { fill_prefetch_next_noopcodecopy("SET_NFLG(val & 0x8000);\nSET_ZFLG(!(val & 0xffff));\n"); } else { @@ -8285,6 +8506,7 @@ bccl_not68020: default: term(); } out("CLEAR_CZNV();\n"); + set_ipl_pre(); if (curi->size == sz_long) { fill_prefetch_next_noopcodecopy("SET_NFLG(val & 0x8000);\nSET_ZFLG(!(val & 0xffff));\n"); } else { @@ -8319,6 +8541,7 @@ bccl_not68020: default: term(); } out("CLEAR_CZNV();\n"); + set_ipl_pre(); if (curi->size == sz_long) { fill_prefetch_next_noopcodecopy("SET_NFLG(val & 0x8000);\nSET_ZFLG(!(val & 0xffff));\n"); } else { @@ -8353,6 +8576,7 @@ bccl_not68020: default: term(); } out("CLEAR_CZNV();\n"); + set_ipl_pre(); if (curi->size == sz_long) { fill_prefetch_next_noopcodecopy("SET_NFLG(val & 0x8000);\nSET_ZFLG(!(val & 0xffff));\nSET_CFLG(GET_XFLG());\n"); } else { @@ -8391,6 +8615,7 @@ bccl_not68020: default: term(); } out("CLEAR_CZNV();\n"); + set_ipl_pre(); if (curi->size == sz_long) { fill_prefetch_next_noopcodecopy("SET_NFLG(val & 0x8000);\nSET_ZFLG(!(val & 0xffff));\nSET_CFLG(GET_XFLG());\n"); } else { @@ -8741,18 +8966,18 @@ bccl_not68020: case i_BKPT: /* only needed for hardware emulators */ sync_m68k_pc(); addcycles000(4); - out("op_illg(opcode);\n"); + illg(); did_prefetch = -1; ipl_fetched = -1; break; case i_CALLM: /* not present in 68030 */ sync_m68k_pc(); - out("op_illg(opcode);\n"); + illg(); did_prefetch = -1; break; case i_RTM: /* not present in 68030 */ sync_m68k_pc(); - out("op_illg(opcode);\n"); + illg(); did_prefetch = -1; break; case i_TRAPcc: @@ -9217,20 +9442,28 @@ end: fill_prefetch_finish(); sync_m68k_pc(); if ((using_ce || using_prefetch) && did_prefetch >= 0) { + int ipladd = 0; if (last_access_offset_ipl > 0) { - char iplfetch[100]; + char iplfetch[100], iplfetchp[100]; int tc = get_current_cycles(); if (tc - ipl_fetch_cycles > 4 || ipl_fetched == 3) { - strcpy(iplfetch, "ipl_fetch_now();\n"); - //sprintf(iplfetch, "ipl_fetch_now(); // %d %d\n", tc, ipl_fetch_cycles); + if (pre_ipl >= 2) { + strcpy(iplfetch, "ipl_fetch_now_pre();\n"); + } else { + strcpy(iplfetch, "ipl_fetch_now();\n"); + } } else { strcpy(iplfetch, "ipl_fetch_next();\n"); - //sprintf(iplfetch, "ipl_fetch_next(); // %d %d\n", tc, ipl_fetch_cycles); } - if (!pre_ipl) { - insertstring(iplfetch, last_access_offset_ipl); + //sprintf(iplfetchp, "ipl_fetch_prefetch(%d);\n", ipl_fetch_cycles + (pre_ipl >= 2 ? 2 : 0)); + if (pre_ipl != 1) { + if (using_ce) { + ipladd = insertstring(iplfetch, last_access_offset_ipl); + } else { + //ipladd = insertstring(iplfetchp, last_access_offset_ipl); + } } - } else { + } else if (ipl_fetched < 10) { out("// MISSING\n"); } } @@ -9738,6 +9971,7 @@ static void generate_cpu_test(int mode) using_prefetch = 1; using_exception_3 = 1; using_simple_cycles = 1; + func_noret = 1; if (mode == 0) { using_simple_cycles = 0; diff --git a/include/debug.h b/include/debug.h index 61acd657..79fad4b8 100644 --- a/include/debug.h +++ b/include/debug.h @@ -223,16 +223,17 @@ struct dma_rec uae_u64 dat; uae_u16 size; uae_u32 addr; - uae_u32 evt; + uae_u32 evt, evt2; uae_u32 evtdata; bool evtdataset; uae_s16 type; uae_u16 extra; - uae_s8 intlev, ipl; + uae_s8 intlev, ipl, ipl2; uae_u16 cf_reg, cf_dat, cf_addr; int ciareg; int ciamask; bool ciarw; + int ciaphase; uae_u16 ciavalue; bool end; }; @@ -271,7 +272,8 @@ extern struct dma_rec *last_dma_rec; #define DMA_EVENT_CPUSTOP 0x20000000 #define DMA_EVENT_CPUSTOPIPL 0x40000000 #define DMA_EVENT_CPUINS 0x80000000 - +#define DMA_EVENT2_IPL 0x00000001 +#define DMA_EVENT2_IPLSAMPLE 0x00000002 #define DMARECORD_REFRESH 1 #define DMARECORD_CPU 2 @@ -296,8 +298,9 @@ extern void record_dma_clear(int hpos, int vpos); extern bool record_dma_check(int hpos, int vpos); extern void record_dma_hsync(int); extern void record_dma_vsync(int); -extern void record_cia_access(int r, int mask, uae_u16 value, bool rw, int hpos, int vpos); +extern void record_cia_access(int r, int mask, uae_u16 value, bool rw, int hpos, int vpos, int phase); extern void record_dma_ipl(int hpos, int vpos); +extern void record_dma_ipl_sample(int hpos, int vpos); extern void debug_mark_refreshed(uaecptr); extern void debug_draw(uae_u8 *buf, int bpp, int line, int width, int height, uae_u32 *xredcolors, uae_u32 *xgreencolors, uae_u32 *xbluescolors); diff --git a/include/newcpu.h b/include/newcpu.h index 0f26f467..51823a21 100644 --- a/include/newcpu.h +++ b/include/newcpu.h @@ -94,8 +94,9 @@ struct comptbl { extern cpuop_func *loop_mode_table[]; -extern uae_u32 REGPARAM3 op_illg (uae_u32) REGPARAM; -extern void REGPARAM3 op_unimpl (uae_u32) REGPARAM; +extern uae_u32 REGPARAM3 op_illg(uae_u32) REGPARAM; +extern void REGPARAM3 op_illg_noret(uae_u32) REGPARAM; +extern void REGPARAM3 op_unimpl(uae_u32) REGPARAM; typedef uae_u8 flagtype; @@ -206,7 +207,9 @@ struct regstruct int exception; int intmask; int ipl[2], ipl_pin; - evt_t ipl_evt_pre; + evt_t ipl_pin_change_evt; + evt_t ipl_evt, ipl_evt_pre; + int ipl_evt_pre_mode; uae_u32 vbr, sfc, dfc; @@ -313,7 +316,7 @@ STATIC_INLINE uae_u32 munge24 (uae_u32 x) extern int mmu_enabled, mmu_triggered; extern int cpu_cycles; -extern int cpucycleunit; +extern int cpucycleunit, cpuipldelay2, cpuipldelay4; extern int m68k_pc_indirect; extern bool m68k_interrupt_delay; @@ -698,6 +701,8 @@ extern void prepare_interrupt (uae_u32); extern void doint(void); extern void checkint(void); extern void intlev_load(void); +extern void ipl_fetch_now_pre(void); +extern void ipl_fetch_next_pre(void); extern void ipl_fetch_pre(void); extern void ipl_fetch_now(void); extern void ipl_fetch_next(void); @@ -714,7 +719,7 @@ extern bool m68k_readcache(uaecptr memaddr, bool dc, uae_u32* valp); extern int getMulu68kCycles(uae_u16 src); extern int getMuls68kCycles(uae_u16 src); extern int getDivu68kCycles (uae_u32 dividend, uae_u16 divisor); -extern int getDivs68kCycles (uae_s32 dividend, uae_s16 divisor); +extern int getDivs68kCycles (uae_s32 dividend, uae_s16 divisor, int *extra); extern void divbyzero_special(bool issigned, uae_s32 dst); extern void setdivuflags(uae_u32 dividend, uae_u16 divisor); extern void setdivsflags(uae_s32 dividend, uae_s16 divisor); diff --git a/newcpu.cpp b/newcpu.cpp index 1034d357..2e57ad78 100644 --- a/newcpu.cpp +++ b/newcpu.cpp @@ -91,6 +91,7 @@ int hardware_bus_error; static int baseclock; int m68k_pc_indirect; bool m68k_interrupt_delay; +static bool m68k_accurate_ipl; static bool m68k_reset_delay; static bool ismoves_nommu; static bool need_opcode_swap; @@ -104,7 +105,7 @@ static int cachedsets04060, cachedsets04060mask, cachedtag04060mask; static int cpu_prefs_changed_flag; -int cpuipldelay; +int cpuipldelay2, cpuipldelay4; int cpucycleunit; int cpu_tracer; @@ -2010,9 +2011,12 @@ static void build_cpufunctbl (void) currprefs.address_space_24 = false; } m68k_interrupt_delay = false; + m68k_accurate_ipl = false; if (currprefs.cpu_cycle_exact) { if (tbl == op_smalltbl_14 || tbl == op_smalltbl_13 || tbl == op_smalltbl_21 || tbl == op_smalltbl_23) m68k_interrupt_delay = true; + if (tbl == op_smalltbl_14 || tbl == op_smalltbl_13) + m68k_accurate_ipl = true; } else if (currprefs.cpu_compatible) { if (currprefs.cpu_model <= 68010 && currprefs.m68k_speed == 0) { m68k_interrupt_delay = true; @@ -2047,11 +2051,8 @@ static void build_cpufunctbl (void) } write_log(_T("\n")); - if (m68k_interrupt_delay) { - cpuipldelay = 4 * cpucycleunit; - } else { - cpuipldelay = 0; - } + cpuipldelay2 = 2 * cpucycleunit; + cpuipldelay4 = 4 * cpucycleunit; set_cpu_caches (true); target_cpu_speed(); @@ -2087,6 +2088,8 @@ static void update_68k_cycles (void) cycles_mult = (uae_u32)((cycles_mult * 1000) / (1000 + currprefs.m68k_speed_throttle)); } } + } else if (currprefs.m68k_speed < 0) { + cycles_mult = CYCLES_DIV / 20; } else { if (currprefs.m68k_speed >= 0 && !currprefs.cpu_cycle_exact && !currprefs.cpu_compatible) { if (currprefs.m68k_speed_throttle < 0) { @@ -2297,8 +2300,6 @@ STATIC_INLINE int adjust_cycles (int cycles) { int mc = regs.memory_waitstate_cycles; regs.memory_waitstate_cycles = 0; - if (currprefs.m68k_speed < 0 || cycles_mult == 0) - return cycles + mc; cycles *= cycles_mult; cycles /= CYCLES_DIV; return cycles + mc; @@ -2338,7 +2339,7 @@ static void activate_trace(void) void checkint(void) { doint(); - if (!currprefs.cachesize && !(regs.spcflags & SPCFLAG_INT) && (regs.spcflags & SPCFLAG_DOINT)) + if (!m68k_accurate_ipl && !currprefs.cachesize && !(regs.spcflags & SPCFLAG_INT) && (regs.spcflags & SPCFLAG_DOINT)) set_special(SPCFLAG_INT); } @@ -2388,14 +2389,14 @@ static void MakeFromSR_x(int t0trace) if (regs.intmask != ((regs.sr >> 8) & 7)) { int newimask = (regs.sr >> 8) & 7; - // STOP intmask change enabling already active interrupt: delay it by 1 STOP round - if (t0trace < 0 && regs.ipl[0] <= regs.intmask && regs.ipl[0] > newimask && regs.ipl[0] < 7) { - regs.ipl[0] = 0; - unset_special(SPCFLAG_INT); + if (m68k_accurate_ipl) { + // STOP intmask change enabling already active interrupt: delay it by 1 STOP round + if (t0trace < 0 && regs.ipl[0] <= regs.intmask && regs.ipl[0] > newimask && regs.ipl[0] < 7) { + regs.ipl[0] = 0; + } } regs.intmask = newimask; - - if (m68k_interrupt_delay && (regs.ipl[0] > 0 || regs.ipl[1] > 0)) { + if (regs.ipl_pin > regs.intmask) { set_special(SPCFLAG_INT); } } @@ -2682,12 +2683,11 @@ static int iack_cycle(int nr) if (1) { // non-autovectored + // this is basically normal memory access and takes 4 cycles (without wait states). vector = x_get_byte(0x00fffff1 | ((nr - 24) << 1)); - if (currprefs.cpu_compatible) - x_do_cycles(4 * cpucycleunit); } else { // autovectored - + x_do_cycles(4 * cpucycleunit); } return vector; } @@ -2793,6 +2793,7 @@ static void Exception_ce000 (int nr) x_put_word (m68k_areg (regs, 7) + 4, currpc); // write low address if (interrupt) vector_nr = iack_cycle(nr); + x_do_cycles(4 * cpucycleunit); x_put_word (m68k_areg (regs, 7) + 0, regs.sr); // write SR x_put_word (m68k_areg (regs, 7) + 2, currpc >> 16); // write high address x_put_word (m68k_areg (regs, 7) + 6, (frame_id << 12) | (vector_nr * 4)); @@ -2806,6 +2807,7 @@ static void Exception_ce000 (int nr) x_put_word (m68k_areg (regs, 7) + 4, currpc); // write low address if (interrupt) vector_nr = iack_cycle(nr); + x_do_cycles(4 * cpucycleunit); x_put_word (m68k_areg (regs, 7) + 0, regs.sr); // write SR x_put_word (m68k_areg (regs, 7) + 2, currpc >> 16); // write high address } @@ -2851,9 +2853,9 @@ kludge_me_do: } return; } - m68k_setpc (newpc); + m68k_setpc(newpc); branch_stack_push(currpc, currpc); - regs.ir = x_get_word (m68k_getpc ()); // prefetch 1 + regs.ir = x_get_word(m68k_getpc()); // prefetch 1 if (hardware_bus_error) { if (nr == 2 || nr == 3) { cpu_halt(CPU_HALT_DOUBLE_FAULT); @@ -2863,10 +2865,14 @@ kludge_me_do: return; } regs.ird = regs.ir; - x_do_cycles (2 * cpucycleunit); - regs.ipl_pin = intlev(); - ipl_fetch_now(); - regs.irc = x_get_word (m68k_getpc () + 2); // prefetch 2 + if (m68k_accurate_ipl && interrupt) { + ipl_fetch_now(); + } + x_do_cycles(2 * cpucycleunit); + if (m68k_accurate_ipl && !interrupt) { + ipl_fetch_next(); + } + regs.irc = x_get_word(m68k_getpc() + 2); // prefetch 2 if (hardware_bus_error) { if (nr == 2 || nr == 3) { cpu_halt(CPU_HALT_DOUBLE_FAULT); @@ -2878,7 +2884,7 @@ kludge_me_do: #ifdef JIT set_special (SPCFLAG_END_COMPILE); #endif - exception_check_trace (nr); + exception_check_trace(nr); } #endif @@ -3804,6 +3810,10 @@ uae_u32 REGPARAM2 op_illg (uae_u32 opcode) Exception (4); return 4; } +void REGPARAM2 op_illg_noret(uae_u32 opcode) +{ + op_illg(opcode); +} #ifdef CPUEMU_0 @@ -4405,29 +4415,53 @@ void ipl_fetch_pre(void) { ipl_fetch_next(); regs.ipl_evt_pre = get_cycles(); + regs.ipl_evt_pre_mode = 1; +} + +void ipl_fetch_now_pre(void) +{ + regs.ipl_evt_pre = get_cycles(); + regs.ipl_evt_pre_mode = 0; } // ipl check was early enough, interrupt possible after current instruction void ipl_fetch_now(void) { if (regs.ipl[0] != regs.ipl_pin) { + regs.ipl_evt = get_cycles(); regs.ipl[0] = regs.ipl_pin; regs.ipl[1] = 0; - set_special(SPCFLAG_INT); +#ifdef DEBUGGER + if (debug_dma && regs.ipl[0] > regs.intmask) { + record_dma_ipl_sample(current_hpos(), vpos); + } +#endif } } -// ipl check was too late, interrupt possible after following instruction +// ipl check max 4 cycles before end of instruction. +// interrupt starts after current instruction if IPL was changed earlier. +// if not early enough: interrupt starts after following instruction. void ipl_fetch_next(void) { if (regs.ipl[1] != regs.ipl_pin) { - regs.ipl[1] = regs.ipl_pin; - set_special(SPCFLAG_INT); + if (get_cycles() - regs.ipl_pin_change_evt >= cpuipldelay4) { + regs.ipl[0] = regs.ipl_pin; + } else { + regs.ipl[1] = regs.ipl_pin; + } +#ifdef DEBUGGER + if (debug_dma && regs.ipl[0] > regs.intmask) { + record_dma_ipl_sample(current_hpos(), vpos); + } +#endif } } void intlev_load(void) { - ipl_fetch_now(); + if (m68k_accurate_ipl) { + ipl_fetch_now(); + } doint(); } @@ -4440,19 +4474,28 @@ void doint(void) } #endif int il = intlev(); - regs.ipl_pin = il; - // check if 68000/010 interrupt was detected mid memory access, - // 2 cycles from start of memory cycle (CYCLE_UNIT == 2 CPU clocks) - if (il > 0 && get_cycles() == regs.ipl_evt_pre + CYCLE_UNIT) { - ipl_fetch_next(); - } + if (regs.ipl_pin != il) { + regs.ipl_pin = il; + regs.ipl_pin_change_evt = get_cycles(); + if (m68k_accurate_ipl) { + // check if 68000/010 interrupt was detected mid memory access, + // 2 cycles from start of memory cycle + if (il > 0 && get_cycles() == regs.ipl_evt_pre + cpuipldelay2) { + if (regs.ipl_evt_pre_mode) { + ipl_fetch_next(); + } else { + ipl_fetch_now(); + } + } + } #ifdef DEBUGGER - if (debug_dma) { - record_dma_ipl(current_hpos(), vpos); - } + if (debug_dma) { + record_dma_ipl(current_hpos(), vpos); + } #endif + } if (m68k_interrupt_delay) { - if (regs.ipl_pin > 0) { + if (!m68k_accurate_ipl && regs.ipl_pin > regs.intmask) { set_special(SPCFLAG_INT); } return; @@ -4601,12 +4644,8 @@ static int do_specialties (int cycles) unset_special(SPCFLAG_INT); do_interrupt(ipl); } else { - if (regs.ipl[0] == regs.ipl[1]) { - unset_special(SPCFLAG_INT); - } else { - regs.ipl[0] = regs.ipl[1]; - regs.ipl[1] = 0; - } + regs.ipl[0] = regs.ipl[1]; + regs.ipl[1] = 0; } } else { if (regs.spcflags & SPCFLAG_INT) { @@ -4902,11 +4941,14 @@ cont: log_dma_record (); } - if (r->spcflags) { + if (r->spcflags || regs.ipl[0]) { if (do_specialties (0)) exit = true; } + regs.ipl[0] = regs.ipl[1]; + regs.ipl[1] = 0; + if (!currprefs.cpu_cycle_exact || currprefs.cpu_model > 68010) exit = true; } @@ -5528,7 +5570,7 @@ static void m68k_run_mmu060 (void) count_instr (regs.opcode); cpu_cycles = (*cpufunctbl[regs.opcode])(regs.opcode); - cpu_cycles = adjust_cycles (cpu_cycles); + cpu_cycles = adjust_cycles(cpu_cycles); regs.instruction_cnt++; if (regs.spcflags) { @@ -5579,7 +5621,7 @@ static void m68k_run_mmu040 (void) mmu_opcode = regs.opcode = x_prefetch (0); count_instr (regs.opcode); cpu_cycles = (*cpufunctbl[regs.opcode])(regs.opcode); - cpu_cycles = adjust_cycles (cpu_cycles); + cpu_cycles = adjust_cycles(cpu_cycles); regs.instruction_cnt++; if (regs.spcflags) { @@ -5876,7 +5918,7 @@ static void m68k_run_2ce (void) memcpy(&r->prefetch020_valid, &cputrace.prefetch020_valid, CPU_PIPELINE_MAX * sizeof(uae_u8)); memcpy(&caches020, &cputrace.caches020, sizeof caches020); - m68k_setpc (cputrace.pc); + m68k_setpc(cputrace.pc); if (!r->stopped) { if (cputrace.state > 1) Exception (cputrace.state); diff --git a/newcpu_common.cpp b/newcpu_common.cpp index cf257d14..5d8a293d 100644 --- a/newcpu_common.cpp +++ b/newcpu_common.cpp @@ -817,14 +817,15 @@ int getDivu68kCycles (uae_u32 dividend, uae_u16 divisor) } } -int getDivs68kCycles (uae_s32 dividend, uae_s16 divisor) +int getDivs68kCycles (uae_s32 dividend, uae_s16 divisor, int *extra) { int mcycles; uae_u32 aquot; int i; - if (divisor == 0) + if (divisor == 0) { return 0; + } if (currprefs.cpu_model == 68010) { // Check for absolute overflow @@ -832,8 +833,10 @@ int getDivs68kCycles (uae_s32 dividend, uae_s16 divisor) return 12; mcycles = 116; // add 2 extra cycles if negative dividend - if (dividend < 0) + if (dividend < 0) { mcycles += 2; + *extra = 1; + } return mcycles; } @@ -846,6 +849,9 @@ int getDivs68kCycles (uae_s32 dividend, uae_s16 divisor) if (((uae_u32)abs (dividend) >> 16) >= (uae_u16)abs (divisor)) return (mcycles + 2) * 2 - 4; + // report special case where IPL check is 2 cycles earlier + *extra = (divisor < 0 && dividend >= 0) ? 1 : 0; + // Absolute quotient aquot = (uae_u32) abs (dividend) / (uae_u16)abs (divisor); -- 2.47.3