return;
}
blt_info.blit_interrupt = 1;
- send_interrupt(6, 3 * CYCLE_UNIT);
+ INTREQ_INT(6, 3);
if (debug_dma) {
record_dma_event(DMA_EVENT_BLITIRQ, current_hpos(), vpos);
}
blt_delayed_irq--;
if (blt_delayed_irq <= 0) {
blt_delayed_irq = 0;
- send_interrupt(6, 2 * CYCLE_UNIT);
+ INTREQ_INT(6, 3);
}
}
devices_rethink();
}
-static void send_interrupt_do(uae_u32 v)
+static void intreq_checks(uae_u16 old)
{
- INTREQ_0(0x8000 | (1 << v));
+ if ((old & 0x0800) && !(intreq & 0x0800)) {
+ serial_rbf_clear();
+ }
+}
+
+static void doint_delay_do_ext(uae_u32 v)
+{
+ uae_u16 old = intreq;
+ setclr(&intreq, (1 << v) | 0x8000);
+ intreq_checks(old);
+
+ doint();
}
-// external delayed interrupt (4 CCKs minimum)
-void send_interrupt(int num, int delay)
+static void send_interrupt_do_ext(uae_u32 v)
{
- if (delay > 0 && m68k_interrupt_delay) {
- event2_newevent_xx(-1, delay, num, send_interrupt_do);
+ //uae_u16 old = intreq;
+ //setclr(&intreq, (1 << v) | 0x8000);
+ //intreq_checks(old);
+
+ event2_newevent_xx(-1, 1 * CYCLE_UNIT, v, doint_delay_do_ext);
+}
+
+// external delayed interrupt
+void INTREQ_INT(int num, int delay)
+{
+ if (m68k_interrupt_delay) {
+ if (delay < CYCLE_UNIT) {
+ delay *= CYCLE_UNIT;
+ }
+ event2_newevent_xx(-1, delay + CYCLE_UNIT, num, doint_delay_do_ext);
} else {
- send_interrupt_do(num);
+ doint_delay_do_ext(num);
}
}
-static void doint_delay_do(uae_u32 v)
+static void doint_delay_do_intreq(uae_u32 v)
{
+ uae_u16 old = intreq;
+ setclr(&intreq, v);
+ intreq_checks(old);
+
doint();
}
-static void doint_delay(void)
+static void doint_delay_intreq(uae_u16 v)
{
if (m68k_interrupt_delay) {
// INTREQ or INTENA write: IPL line changes 0.5 CCKs later.
// 68000 needs one more CPU clock (0.5 CCK) before it detects it.
- event2_newevent_xx(-1, 1 * CYCLE_UNIT, 0, doint_delay_do);
+ event2_newevent_xx(-1, 1 * CYCLE_UNIT, v, doint_delay_do_intreq);
} else {
- doint_delay_do(0);
+ doint_delay_do_intreq(v);
+ }
+}
+
+static void doint_delay_do_intena(uae_u32 v)
+{
+ doint();
+}
+
+static void doint_delay_intena(uae_u16 v)
+{
+ if (m68k_interrupt_delay) {
+ // INTREQ or INTENA write: IPL line changes 0.5 CCKs later.
+ // 68000 needs one more CPU clock (0.5 CCK) before it detects it.
+ event2_newevent_xx(-1, 1 * CYCLE_UNIT, v, doint_delay_do_intena);
+ }
+ else {
+ doint_delay_do_intena(v);
}
}
setclr(&intena, v);
if (old != intena) {
- doint_delay();
+ doint_delay_intena(v);
}
}
static void INTREQ_nodelay(uae_u16 v)
{
+ uae_u16 old = intreq;
setclr(&intreq, v);
+ intreq_checks(old);
doint();
}
{
uae_u16 old = intreq;
setclr(&intreq, v);
- if ((old & 0x0800) && !(intreq & 0x0800)) {
- serial_rbf_clear();
- }
+ intreq_checks(old);
}
bool INTREQ_0(uae_u16 v)
//write_log("%04x %04x -> %04x %08x\n", v, old, intreq, M68K_GETPC);
- if ((old & 0x0800) && !(intreq & 0x0800)) {
- serial_rbf_clear();
- }
+ intreq_checks(old);
if (old != intreq) {
- doint_delay();
+ doint_delay_intreq(v);
}
return true;
}
static void delayed_framestart(uae_u32 v)
{
check_vblank_copjmp(0);
- send_interrupt(5, 2 * CYCLE_UNIT); // total REFRESH_FIRST_HPOS + 1
+ INTREQ_INT(5, 2); // total REFRESH_FIRST_HPOS + 1
}
// this prepares for new line
// copper and vblank trigger in same line
event2_newevent_xx(-1, 2 * CYCLE_UNIT, 0, delayed_framestart);
} else if (vb_start_line == 1) {
- send_interrupt(5, (REFRESH_FIRST_HPOS + 1) * CYCLE_UNIT);
+ INTREQ_INT(5, REFRESH_FIRST_HPOS + 1);
} else if (vpos == 0) {
event2_newevent_xx(-1, 2 * CYCLE_UNIT, 0, check_vblank_copjmp);
}
evt_t e = restore_u64();
uae_u32 data = restore_u32();
if (type == 1)
- event2_newevent_xx(-1, e, data, send_interrupt_do);
+ event2_newevent_xx(-1, e, data, send_interrupt_do_ext);
}
return src;
}
for (int i = ev2_misc; i < ev2_max; i++) {
struct ev2 *e = &eventtab2[i];
- if (e->active && e->handler == send_interrupt_do) {
+ if (e->active && e->handler == send_interrupt_do_ext) {
cnt++;
}
}
save_u8(cnt);
for (int i = ev2_misc; i < ev2_max; i++) {
struct ev2 *e = &eventtab2[i];
- if (e->active && e->handler == send_interrupt_do) {
+ if (e->active && e->handler == send_interrupt_do_ext) {
save_u8(1);
save_u64(e->evtime - get_cycles());
save_u32(e->data);
static char outbuffer[30000];
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 void out(const char *format, ...)
{
memcpy(outbuffer + offset + brace_level, s, len);
}
+static int get_current_cycles(void)
+{
+ return (count_readw + count_writew) * 4 + (count_readl + count_writel) * 8 + count_cycles;
+}
+
static void set_last_access_ipl(void)
{
if (ipl_fetched)
return;
last_access_offset_ipl = strlen(outbuffer);
+ ipl_fetch_cycles = get_current_cycles();
}
static void set_last_access_ipl_prev(void)
if (ipl_fetched < 0)
return;
last_access_offset_ipl_prev = strlen(outbuffer);
+ ipl_fetch_cycles_prev = get_current_cycles();
}
// if memory cycle happened previously: use it.
last_access_offset_ipl = last_access_offset_ipl_prev;
ipl_fetched = 1;
+ ipl_fetch_cycles = ipl_fetch_cycles_prev;
+ }
+}
+
+static void check_ipl_next(void)
+{
+ if (using_ce) {
+ out("ipl_fetch_next();\n");
+ }
+ if (isce020()) {
+ out("ipl_fetch_next();\n");
}
}
static void check_ipl_always(void)
{
if (using_ce) {
- out("ipl_fetch();\n");
+ out("ipl_fetch_now();\n");
}
if (isce020()) {
- out("ipl_fetch();\n");
+ out("ipl_fetch_now();\n");
}
}
static void makefromsr_t0(void)
{
+ out("intlev_load();\n");
+ if (using_ce || isce020()) {
+ out("ipl_fetch_now();\n");
+ }
if (using_prefetch || using_ce) {
out("MakeFromSR();\n");
} else {
out("MakeFromSR_T0();\n");
}
- if (using_ce || isce020())
- out("intlev_load();\n");
}
static void irc2ir (bool dozero)
if (!(flags & GF_NOLIPL)) {
set_last_access_ipl_prev();
}
- out("%s |= %s(%sa) << 16; \n", name, srcwx, name);
+ 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_NOLIPL)) {
set_last_access_ipl_prev();
}
- out("%s |= %s(%sa + 2); \n", name, srcwx, name);
+ out("%s |= %s(%sa + 2);\n", name, srcwx, name);
count_readw++;
check_bus_error(name, 2, 0, 1, NULL, 1, 0);
}
insn_n_cycles += 4;
}
if (!(flags & GF_NOLIPL)) {
- set_last_access_ipl_prev();
+ //set_last_access_ipl_prev();
}
out("%s(%sa, %s >> 16);\n", dstwx, to, from);
sprintf(tmp, "%s >> 16", from);
genflags(flag_logical, g_instr->size, "src", "", "");
}
if (!(flags & GF_NOLIPL)) {
- set_last_access_ipl_prev();
+ //set_last_access_ipl_prev();
}
out("%s(%sa + 2, %s);\n", dstwx, to, from);
count_writew++;
opcode_nextcopy = 0;
last_access_offset_ipl = -1;
last_access_offset_ipl_prev = -1;
+ ipl_fetch_cycles = -1;
+ ipl_fetch_cycles_prev = -1;
loopmode = 0;
// 68010 loop mode available if
write_return_cycles(0);
out("}\n");
}
- check_ipl_always();
+ check_ipl_next();
if (cpu_level <= 1) {
out("checkint();\n");
out("regs.sr = sr;\n");
sync_m68k_pc();
if ((using_ce || using_prefetch) && did_prefetch >= 0) {
if (last_access_offset_ipl > 0) {
- insertstring("ipl_fetch();\n", last_access_offset_ipl);
+ char iplfetch[100];
+ int tc = get_current_cycles();
+ if (tc - ipl_fetch_cycles > 4) {
+ strcpy(iplfetch, "ipl_fetch_now();\n");
+ //sprintf(iplfetch, "ipl_fetch_now(); // %d %d\n", tc, ipl_fetch_cycles);
+ } else {
+ strcpy(iplfetch, "ipl_fetch_next();\n");
+ //sprintf(iplfetch, "ipl_fetch_next(); // %d %d\n", tc, ipl_fetch_cycles);
+ }
+ insertstring(iplfetch, last_access_offset_ipl);
} else {
out("// MISSING\n");
}
x_do_cycles (clocks * cpucycleunit);
}
-STATIC_INLINE void ipl_fetch (void)
-{
- regs.ipl[1] = regs.ipl[0];
- regs.ipl[0] = regs.ipl_pin;
- regs.ipl_time = get_cycles();
-}
-
uae_u32 mem_access_delay_word_read (uaecptr addr);
uae_u32 mem_access_delay_wordi_read (uaecptr addr);
uae_u32 mem_access_delay_byte_read (uaecptr addr);
extern void INTREQ(uae_u16);
extern bool INTREQ_0(uae_u16);
extern void INTREQ_f(uae_u16);
-extern void send_interrupt(int num, int delay);
+extern void INTREQ_INT(int num, int delay);
extern void rethink_uae_int(void);
extern uae_u16 INTREQR(void);
int exception;
int intmask;
int ipl[2], ipl_pin;
- evt_t ipl_time;
uae_u32 vbr, sfc, dfc;
extern void doint(void);
extern void checkint(void);
extern void intlev_load(void);
+extern void ipl_fetch_now(void);
+extern void ipl_fetch_next(void);
extern void dump_counts (void);
extern int m68k_move2c (int, uae_u32 *);
extern int m68k_movec2 (int, uae_u32 *);
set_special(SPCFLAG_INT);
}
-void REGPARAM2 MakeSR (void)
+void REGPARAM2 MakeSR(void)
{
regs.sr = ((regs.t1 << 15) | (regs.t0 << 14)
| (regs.s << 13) | (regs.m << 12) | (regs.intmask << 8)
- | (GET_XFLG () << 4) | (GET_NFLG () << 3)
- | (GET_ZFLG () << 2) | (GET_VFLG () << 1)
- | GET_CFLG ());
-
+ | (GET_XFLG() << 4) | (GET_NFLG() << 3)
+ | (GET_ZFLG() << 2) | (GET_VFLG() << 1)
+ | GET_CFLG());
}
-static void SetSR (uae_u16 sr)
+static void SetSR(uae_u16 sr)
{
regs.sr &= 0xff00;
regs.sr |= sr;
- SET_XFLG ((regs.sr >> 4) & 1);
- SET_NFLG ((regs.sr >> 3) & 1);
- SET_ZFLG ((regs.sr >> 2) & 1);
- SET_VFLG ((regs.sr >> 1) & 1);
- SET_CFLG (regs.sr & 1);
+ SET_XFLG((regs.sr >> 4) & 1);
+ SET_NFLG((regs.sr >> 3) & 1);
+ SET_ZFLG((regs.sr >> 2) & 1);
+ SET_VFLG((regs.sr >> 1) & 1);
+ SET_CFLG(regs.sr & 1);
}
static void MakeFromSR_x(int t0trace)
int oldt0 = regs.t0;
int oldt1 = regs.t1;
- SET_XFLG ((regs.sr >> 4) & 1);
- SET_NFLG ((regs.sr >> 3) & 1);
- SET_ZFLG ((regs.sr >> 2) & 1);
- SET_VFLG ((regs.sr >> 1) & 1);
- SET_CFLG (regs.sr & 1);
+ SET_XFLG((regs.sr >> 4) & 1);
+ SET_NFLG((regs.sr >> 3) & 1);
+ SET_ZFLG((regs.sr >> 2) & 1);
+ SET_VFLG((regs.sr >> 1) & 1);
+ SET_CFLG(regs.sr & 1);
if (regs.t1 == ((regs.sr >> 15) & 1) &&
regs.t0 == ((regs.sr >> 14) & 1) &&
regs.s == ((regs.sr >> 13) & 1) &&
regs.t0 = (regs.sr >> 14) & 1;
regs.s = (regs.sr >> 13) & 1;
regs.m = (regs.sr >> 12) & 1;
- regs.intmask = (regs.sr >> 8) & 7;
+
+ if (regs.intmask != ((regs.sr >> 8) & 7)) {
+ regs.intmask = (regs.sr >> 8) & 7;
+ if (m68k_interrupt_delay && (regs.ipl[0] > 0 || regs.ipl[1] > 0)) {
+ set_special(SPCFLAG_INT);
+ }
+ }
if (currprefs.cpu_model >= 68020) {
/* 68060 does not have MSP but does have M-bit.. */
}
#endif
- if (t0trace >= 0) {
- checkint();
- }
-
if (regs.t1 || regs.t0) {
set_special (SPCFLAG_TRACE);
} else {
regs.ird = regs.ir;
x_do_cycles (2 * cpucycleunit);
regs.ipl_pin = intlev();
- ipl_fetch();
+ ipl_fetch_now();
regs.irc = x_get_word (m68k_getpc () + 2); // prefetch 2
if (hardware_bus_error) {
if (nr == 2 || nr == 3) {
#endif
branch_stack_push(currpc, nextpc);
regs.ipl_pin = intlev();
- ipl_fetch();
+ ipl_fetch_now();
fill_prefetch ();
exception_check_trace (nr);
}
static int get_ipl(void)
{
- if (get_cycles() - cpuipldelay > regs.ipl_time) {
- return regs.ipl[0];
- }
- return regs.ipl[1];
+ return regs.ipl[0];
}
static void do_interrupt (int nr)
atomic_or(p, 1 << id);
atomic_or(&uae_interrupt, 1);
} else {
- uae_u16 v = i6 ? 0x2000 : 0x0008;
- if (currprefs.cpu_cycle_exact || (!(intreq & v) && !currprefs.cpu_cycle_exact)) {
+ int inum = i6 ? 13 : 3;
+ uae_u16 v = 1 << inum;
+ if (currprefs.cpu_cycle_exact || currprefs.cpu_compatible) {
+ INTREQ_INT(inum, 0);
+ } else if (!(intreq & v)) {
INTREQ_0(0x8000 | v);
}
}
#endif
-// handle interrupt delay (few cycles)
+// check if interrupt active
static bool time_for_interrupt(void)
{
int ipl = get_ipl();
return ipl > regs.intmask || ipl == 7;
}
+// ipl check was early enough, interrupt possible after current instruction
+void ipl_fetch_now(void)
+{
+ if (regs.ipl[0] != regs.ipl_pin) {
+ regs.ipl[0] = regs.ipl_pin;
+ regs.ipl[1] = 0;
+ set_special(SPCFLAG_INT);
+ }
+}
+// ipl check was too late, interrupt possible 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);
+ }
+}
+
void intlev_load(void)
{
doint();
if (m68k_interrupt_delay) {
int il = intlev();
regs.ipl_pin = il;
- if (regs.ipl_pin > regs.intmask || regs.ipl_pin == 7) {
+ if (regs.ipl_pin > 0) {
set_special(SPCFLAG_INT);
}
return;
if (time_for_interrupt()) {
unset_special(SPCFLAG_INT);
do_interrupt(get_ipl());
+ } else {
+ if (regs.ipl[0] == regs.ipl[1]) {
+ unset_special(SPCFLAG_INT);
+ } else {
+ regs.ipl[0] = regs.ipl[1];
+ regs.ipl[1] = 0;
+ }
}
} else {
if (regs.spcflags & SPCFLAG_INT) {
if (do_specialties (cpu_cycles))
exit = true;
}
- ipl_fetch ();
+ ipl_fetch_now();
}
} CATCH(prb) {
bus_error();
if (do_specialties(cpu_cycles))
exit = true;
}
- ipl_fetch();
+ ipl_fetch_now();
} ENDTRY
}
}
void do_cycles_stop(int c)
{
+ c *= cpucycleunit;
if (!currprefs.cpu_compatible) {
do_cycles(c);
} else {
if (debug_dma) {
- while (c >= 2) {
+ while (c > 0) {
debug_cpu_stop();
- do_cycles_ce000_internal(2);
- c -= 2;
+ x_do_cycles(c > CYCLE_UNIT ? CYCLE_UNIT : c);
+ c -= CYCLE_UNIT;
}
} else {
- do_cycles_ce000_internal(c);
+ x_do_cycles(c);
}
}
}
idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc2);
}
- ipl_fetch();
+ ipl_fetch_now();
if (currprefs.cpu_cycle_exact)
regs.irc = get_word_ce030_prefetch_opcode (0);
else
}
}
- ipl_fetch();
+ ipl_fetch_now();
if (currprefs.cpu_cycle_exact)
regs.irc = get_word_ce030_prefetch_opcode(0);
else
idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc);
}
- ipl_fetch();
+ ipl_fetch_now();
if (currprefs.cpu_cycle_exact)
regs.irc = get_word_ce020_prefetch_opcode (0);
else