cfgfile_dwrite_bool (f, _T("tablet_library"), p->tablet_library);
cfgfile_dwrite_bool (f, _T("clipboard_sharing"), p->clipboard_sharing);
cfgfile_dwrite_bool(f, _T("native_code"), p->native_code);
+ cfgfile_dwrite_bool(f, _T("cputester"), p->cputester);
cfgfile_write (f, _T("gfx_display"), _T("%d"), p->gfx_apmode[APMODE_NATIVE].gfx_display);
cfgfile_write_str (f, _T("gfx_display_friendlyname"), target_get_display_name (p->gfx_apmode[APMODE_NATIVE].gfx_display, true));
|| cfgfile_yesno(option, value, _T("clipboard_sharing"), &p->clipboard_sharing)
|| cfgfile_yesno(option, value, _T("native_code"), &p->native_code)
|| cfgfile_yesno(option, value, _T("tablet_library"), &p->tablet_library)
+ || cfgfile_yesno(option, value, _T("cputester"), &p->cputester)
|| cfgfile_yesno(option, value, _T("bsdsocket_emu"), &p->socket_emu))
return 1;
return getclockreg (addr, ct);
}
+static void cputester_event(uae_u32 v)
+{
+ IRQ_forced(1, 64 / 2);
+}
+
static void REGPARAM2 clock_lput (uaecptr addr, uae_u32 value)
{
if ((addr & 0xffff) >= 0x8000 && currprefs.cs_fatgaryrev >= 0) {
{
// write_log(_T("W: %x (%x): %x, PC=%08x\n"), addr, (addr & 0xff) >> 2, value & 0xff, M68K_GETPC);
+ if (currprefs.cputester && (addr & 65535) == 0) {
+ event2_newevent_xx(-1, CYCLE_UNIT * (64 / 2), 0, cputester_event);
+ }
+
if ((addr & 0xffff) >= 0x8000 && currprefs.cs_fatgaryrev >= 0) {
dummy_put(addr, 1, value);
return;
static uae_u16 trace_store_sr;
static int generate_address_mode;
static int test_memory_access_mask;
+static uae_u32 opcode_memory_address;
static uae_u8 imm8_cnt;
static uae_u16 imm16_cnt;
return;
interrupt_cycle_cnt -= cycles;
if (interrupt_cycle_cnt <= 0) {
+ regs.ipl_pin = 1;
interrupt_cycle_cnt = 0;
- Exception(24 + 6);
}
}
uae_u16 get_word_test_prefetch(int o)
{
// no real prefetch
- if (cpu_lvl < 2)
+ if (cpu_lvl < 2) {
o -= 2;
+ }
add_memory_cycles(-1);
regs.irc = get_iword_test(m68k_getpci() + o + 2);
read_buffer_prev = regs.read_buffer;
{
if (!testing_active && is_nowrite_address(addr, 1))
return;
+ if (feature_interrupts == 2 && addr == IPL_TRIGGER_ADDR) {
+ add_memory_cycles(1);
+ interrupt_cycle_cnt = INTERRUPT_CYCLES - 2;
+ return;
+ }
check_bus_error(addr, 1, regs.s ? 5 : 1);
uae_u8 *p = get_addr(addr, 1, 2);
if (!out_of_test_space && !noaccesshistory && !hardware_bus_error_fake) {
void ipl_fetch(void)
{
+ if (regs.ipl_pin) {
+ regs.ipl = regs.ipl_pin;
+ }
}
int intlev(void)
cpu_cycles = 0;
regs.loop_mode = 0;
regs.ipl_pin = 0;
+ regs.ipl = 0;
interrupt_level = 0;
interrupt_cycle_cnt = 0;
cnt = 100;
}
if (feature_interrupts == 2) {
- interrupt_cycle_cnt = SERPER * 10 - 20;
+ interrupt_cycle_cnt = INTERRUPT_CYCLES;
}
for (;;) {
break;
}
+ if (feature_interrupts == 2) {
+ if (regs.ipl > regs.intmask) {
+ Exception(24 + regs.ipl);
+ break;
+ }
+ } else {
+ if (regs.ipl_pin > regs.intmask) {
+ Exception(24 + regs.ipl_pin);
+ break;
+ }
+ }
+
if (regs.pc == endpc || regs.pc == targetpc) {
// Trace is only added as an exception if there was no other exceptions
// Trace stacked with other exception is handled later
if (!valid_address(regs.pc, 2, 0))
break;
- if (regs.ipl_pin > regs.intmask) {
- Exception(24 + regs.ipl_pin);
- break;
- }
-
if (!feature_loop_mode_jit && !feature_loop_mode_68010) {
// trace after NOP
if (SPCFLAG_DOTRACE) {
opc = regs.ir;
}
+ if (feature_interrupts == 2) {
+ // IPL test must cause some exception
+ if (!test_exception) {
+ test_exception = -1;
+ }
+ // Interrupt start must be before test instruction,
+ // after test instruction
+ // or after end NOP instruction
+ if (test_exception >= 24 && test_exception <= 24 + 8) {
+ if (test_exception_addr != opcode_memory_address &&
+ test_exception_addr != opcode_memory_address - 2 &&
+ test_exception_addr != test_instruction_end_pc)
+ {
+ test_exception = -1;
+ }
+ }
+ }
+
testing_active = 0;
if (regs.s) {
full_format_cnt = 0;
last_exception_len = -1;
interrupt_count = 0;
+ interrupt_delay_cnt = 0;
int sr_override = 0;
target_address_bak = target_address;
target_opcode_address_bak = target_opcode_address;
- uae_u32 opcode_memory_address = opcode_memory_start;
+ opcode_memory_address = opcode_memory_start;
uae_u8 *opcode_memory_ptr = opcode_memory;
if (target_opcode_address != 0xffffffff) {
opcode_memory_address += target_opcode_address;
int branch_target_swap_mode_old = 0;
int doopcodeswap = 1;
- if (feature_interrupts == 2) {
- doopcodeswap = 0;
- }
-
if (verbose) {
if (target_ea[0] != 0xffffffff)
wprintf(_T(" Target EA SRC=%08x\n"), target_ea[0]);
// interrupt timing test mode
if (feature_interrupts == 2) {
pc -= 2;
- // move.w #x,0xdff032 (SERDAT) (20 cycles)
- put_long_test(pc + 0, (0x33fc << 16) | 0x100 | '!');
- put_long_test(pc + 4, 0x00dff030);
-// // moveq #x,d0 (4 cycles)
-// put_word_test(pc + 8, 0x7000 | interrupt_delay_cnt);
+ // moveq #x,d0 (4)
+ put_word_test(pc + 0, 0x7000 | interrupt_delay_cnt);
+ // move.b d0,0xdcfffc (RTCW) (8 + 4 + 4)
+ put_word_test(pc + 2, 0x13c0);
+ put_long_test(pc + 4, IPL_TRIGGER_ADDR);
// ror.l d0,d0 (4 + 4 + d0 * 2 cycles)
put_word_test(pc + 8, 0xe0b8);
put_word_test(pc + 10, NOP_OPCODE); // (4 cycles)
pc += 12;
- opcode_memory_address = startpc = pc;
+ opcode_memory_address = pc;
pc += 2;
}
if (dstaddr != 0xffffffff && srcaddr != dstaddr) {
outbytes(_T("D"), dstaddr);
}
- if (feature_loop_mode_jit || feature_loop_mode_68010) {
+ if (feature_loop_mode_jit || feature_loop_mode_68010) { // || feature_interrupts == 2) {
wprintf(_T("\n"));
+ nextpc = opcode_memory_start;
for (int i = 0; i < 20; i++) {
out_of_test_space = false;
if (get_word_test(nextpc) == ILLG_OPCODE)
dst = store_reg(dst, CT_AREG + 7, 0, target_usp_address, sz_long);
}
- if (feature_interrupts == 2) {
- *dst++ = CT_EDATA;
- *dst++ = CT_EDATA_IRQ_CYCLES;
- *dst++ = interrupt_delay_cnt;
- }
-
// pre-test data end
*dst++ = CT_END_INIT;
int t_cnt = 0;
int extraccr = 0;
- interrupt_delay_cnt = -1;
// extra loops for supervisor and trace
uae_u16 sr_allowed_mask = feature_sr_mask & 0xf000;
*dst++ = (uae_u8)(maxflag | (fpumode ? 0x80 : 0x00) | (flagmode ? 0x40 : 0x00));
maxflagcnt = maxflag;
- if (feature_interrupts == 2) {
- maxflagcnt *= 64;
- }
// Test every CPU CCR or FPU SR/rounding/precision combination
for (int ccrcnt = 0; ccrcnt < maxflagcnt; ccrcnt++) {
}
regs.sr |= feature_min_interrupt_mask << 8;
- if (feature_interrupts == 2) {
- regs.regs[0] = ccrcnt >> maxflagshift;
- }
-
// override special register values
for (int i = 0; i < regdatacnt; i++) {
struct regdata *rd = ®datas[i];
}
}
if (verbose) {
- wprintf(_T(" OK=%d OB=%d S=%d/%d T=%d STP=%d I=%d"), ok, exception_array[0], prev_s_cnt, s_cnt, t_cnt, cnt_stopped, interrupt_delay_cnt);
+ wprintf(_T(" OK=%d OB=%d S=%d/%d T=%d STP=%d I=%d/%d %08x"), ok, exception_array[0],
+ prev_s_cnt, s_cnt, t_cnt, cnt_stopped, interrupt_delay_cnt, interrupt_cycle_cnt, test_exception_addr);
if (!ccr_done)
wprintf(_T(" X"));
for (int i = 2; i < 128; i++) {
nextround = true;
}
-#if 0
- // interrupt delay test from 0 to 63
+ // interrupt delay test
if (feature_interrupts == 2) {
interrupt_delay_cnt++;
- if (interrupt_delay_cnt >= 64) {
+ if (interrupt_delay_cnt >= MAX_INTERRUPT_DELAY) {
break;
} else {
nextround = true;
rounds = 1;
}
}
-#endif
if (target_opcode_address != 0xffffffff || target_usp_address != 0xffffffff) {
nextround = false;
S_FSAVE = S_FPSR+4
S_NEXT = S_FSAVE+216
+asm_start:
+
| v1, v2, limit
| abs((v2 - v1) / v1) > limit
_fpucomp:
_cyclereg_address4:
move.w CYCLEREG,cycles+2
move.w #0,ACTIVITYREG
+ | exception start inside this assembly code?
+ cmp.l #asm_start,2+4+2(sp)
+ bcs.s .okpc
+ cmp.l #asm_end,2+4+2(sp)
+ bhi.s .okpc
+ | interrupt?
+ cmp.l #_exceptiontable000+24*2,2(sp)
+ bcs.s .okpc
+ cmp.l #_exceptiontable000+(24+8)*2,2(sp)
+ bcc.s .okpc
+ | possibly IPL tester spurious interrupt
+ | ignore it
+ addq.l #2+4,sp
+ rte
+.okpc:
move.l a0,-(sp)
move.l datapointer(pc),a0
movem.l d0-d7/a0-a6,(a0)
move.w (sp),S_EXC+0(a0)
addq.w #8,sp
.noaddresserror:
+ cmp.w #24,d0
+ bcs.s .nointerrupt
+ cmp.w #24+8,d0
+ bcc.s .nointerrupt
+ | possible IPL test run, delay a bit
+ | to make sure tester hardware is not pulling
+ | IPL line down anymore
+ moveq #16-1,d1
+.delay1:
+ dbf d1,.delay1
+.nointerrupt:
+
move.w (sp)+,S_SR+2(a0)
move.l (sp)+,S_PC(a0)
dc.l 0
nullframe:
dc.l 0,0,0
+asm_end:
#define ILLG_OPCODE 0x4afc
#define LM_OPCODE 0x42db
-#define SERPER 8
+#define INTERRUPT_CYCLES 64
+#define MAX_INTERRUPT_DELAY 64
+#define IPL_TRIGGER_ADDR 0xdc0000
feature_exception_vectors=
; global exception disable/enable
-; -<exception number> = disable all except listed. <exception number> = enable only listed
+; -<exception number> = disable listed, enable all others. <exception number> = enable only listed
; default: all enabled
exceptions=
; interrupt timing test
[test=IPL]
cpu=68000-68010
-enabled=0
+enabled=1
+verbose=0
feature_undefined_ccr=1
feature_interrupts=2
-mode=exg,neg,not,ror,rol,swap
+mode=all
; interrupt exception
[test=IRQ]
uae_u16 fpeaset;
};
-
-struct irqresult
-{
- uae_u32 pc;
- uae_u16 sr;
-};
-
-static struct irqresult irqresults[64 + 1], irqresults2[64 + 1];
-
static short continue_on_error;
static struct registers test_regs;
static struct registers last_regs;
return (uae_s32)llu(p);
}
-static void interrupt_results(void)
-{
- if (interrupttest == 2) {
- short pvcnt = 0;
- for(short i = 0; i < 64; i++) {
- struct irqresult *irq1 = &irqresults[i];
- struct irqresult *irq2 = &irqresults[i + 1];
- if (irq1->pc == irq2->pc && irq1->sr == irq2->sr && i < 63) {
- pvcnt++;
- }
- if (irq1->pc != irq2->pc || irq1->sr != irq2->sr || i == 63) {
- if (irq1->sr == 0x6000) {
- printf("S%02d-%02d: %08x ", i - pvcnt, i, irq1->pc);
- } else {
- printf("U%02d-%02d: %08x ", i - pvcnt, i, irq1->pc);
- }
- pvcnt = 0;
- }
- }
- printf("\n");
- }
-}
-
static void endinfo(void)
{
printf("Last test: %u\n", testcnt);
static uae_u16 test_intena, test_intreq;
-static void set_interrupt_sertest(void)
-{
- volatile uae_u16 *intena = (uae_u16 *)0xdff09a;
- volatile uae_u16 *serper = (uae_u16 *)0xdff032;
- // enable serial receive interrupt
- *intena = 0x8000 | 0x4000 | 0x0800;
- // serial period
- *serper = SERPER;
-}
-
static void set_interrupt(void)
{
if (interrupt_count < 15) {
uae_u8 fpiar_changed = 0, fpsr_changed = 0, fpcr_changed = 0;
short exc = -1;
- if (interrupttest == 2) {
- struct irqresult *irq = &irqresults[interrupt_delay_cnt];
- irq->pc = tregs->pc;
- irq->sr = tregs->sr & 0xff00;
- }
-
if (loop_mode_jit) {
memset(lmtable1, 0xff, sizeof(lmtable1));
memset(lmtable2, 0xff, sizeof(lmtable2));
outbp += strlen(outbp);
out_regs(tregs, tregs, lregs, sregs, 0, branched2);
#ifdef AMIGA
- if (interrupttest) {
+ if (interrupttest == 1) {
sprintf(outbp, "INTREQ: %04x INTENA: %04x\n", test_intreq, test_intena);
outbp += strlen(outbp);
}
short doopcodeswap = 1;
- if (interrupttest == 2) {
- doopcodeswap = 0;
- }
-
for (;;) {
- if (interrupttest == 2) {
- memcpy(irqresults2, irqresults, sizeof(irqresults));
- memset(irqresults, 0, sizeof(irqresults));
- }
-
cur_regs.endpc = endpc;
cur_regs.pc = startpc;
ccrshift++;
}
ccrshift--;
- if (interrupttest == 2) {
- maxccr *= 64;
- }
testcntsubmax = maxccr;
testcntsub = 0;
for (short ccrcnt = 0; ccrcnt < maxccr; ccrcnt++, testcntsub++) {
test_regs.expsr = test_regs.sr | 0x2000;
- if (interrupttest == 2) {
- interrupt_delay_cnt = ccrcnt >> ccrshift;
- cur_regs.regs[0] = test_regs.regs[0] = interrupt_delay_cnt;
- }
-
// internally modified registers become part of cur_regs
cur_regs.sr = test_regs.sr;
cur_regs.expsr = test_regs.expsr;
#ifdef AMIGA
if (interrupttest == 1) {
set_interrupt();
- } else if (interrupttest == 2) {
- set_interrupt_sertest();
}
#endif
if (cpu_lvl == 1) {
fpu_approxcnt++;
}
- if (interrupttest != 2) {
-
- if (quit || errors) {
- if (!quit && errorcnt > 0 && totalerrors < errorcnt) {
- if (totalerrors > 0) {
- strcat(stored_outbuffer, "----------------------------------------\n");
- }
- if (strlen(stored_outbuffer) + strlen(outbuffer) + 40 >= outbuffer_size) {
- goto end;
- }
- strcat(stored_outbuffer, outbuffer);
- outbp = stored_outbuffer + strlen(stored_outbuffer);
- out_endinfo();
- infoadded = 0;
- errors = 0;
- outbuffer[0] = 0;
- outbuffer2[0] = 0;
- outbp = outbuffer2;
- } else {
+ if (quit || errors) {
+ if (!quit && errorcnt > 0 && totalerrors < errorcnt) {
+ if (totalerrors > 0) {
+ strcat(stored_outbuffer, "----------------------------------------\n");
+ }
+ if (strlen(stored_outbuffer) + strlen(outbuffer) + 40 >= outbuffer_size) {
goto end;
}
- totalerrors++;
+ strcat(stored_outbuffer, outbuffer);
+ outbp = stored_outbuffer + strlen(stored_outbuffer);
+ out_endinfo();
+ infoadded = 0;
+ errors = 0;
+ outbuffer[0] = 0;
+ outbuffer2[0] = 0;
+ outbp = outbuffer2;
+ } else {
+ goto end;
}
+ totalerrors++;
}
}
}
restoreahist();
-
- // increase count when interrupt test returns different results
- if (interrupttest == 2) {
- if (memcmp(irqresults, irqresults2, sizeof(irqresults))) {
- interrupttest_diff_cnt++;
- if (interrupttest_diff_cnt == irqcnt) {
- end_test();
- printf(outbuffer);
- printf("Interrupt test count expired\n");
- interrupt_results();
- exit(0);
- }
- }
- }
-
}
end:
printf("%s", outbuffer);
}
}
- if (interrupttest == 2) {
- interrupt_results();
- }
}
static void freestuff(void)
static int getparamval(const char *p)
{
- ULONG inv = 0;
+ uae_u32 inv = 0;
if (p[0] == '~') {
inv = 0xffffffff;
p++;
}
}
-static int irq_nmi;
+static int irq_forced, irq_delay;
-void NMI_delayed(void)
+void IRQ_forced(int lvl, int delay)
{
- irq_nmi = 1;
+ irq_forced = lvl;
+ irq_delay = -1;
+ if (delay > 0 && currprefs.cpu_compatible) {
+ irq_delay = get_cycles() + irq_delay * CYCLE_UNIT;
+ }
+ doint();
}
int intlev(void)
{
- uae_u16 imask = intreq & intena;
- if (irq_nmi) {
- irq_nmi = 0;
- return 7;
+ if (irq_forced) {
+ int lvl = irq_forced;
+ if (irq_delay == -1 || ((int)get_cycles()) - irq_delay > 0) {
+ irq_forced = 0;
+ irq_delay = -1;
+ }
+ return lvl;
}
+ uae_u16 imask = intreq & intena;
if (!(imask && (intena & 0x4000)))
return -1;
if (imask & (0x4000 | 0x2000)) // 13 14
extern void REGPARAM3 Exception_cpu_oldpc(int, uaecptr) REGPARAM;
extern void REGPARAM3 ExceptionL (int, uaecptr) REGPARAM;
extern void NMI (void);
-extern void NMI_delayed (void);
+extern void IRQ_forced(int, int);
extern void prepare_interrupt (uae_u32);
extern void doint (void);
extern void dump_counts (void);
bool obs_sound_toccata_mixer;
bool obs_sound_es1370;
bool obs_sound_fm801;
+ bool cputester;
int mountitems;
struct uaedev_config_data mountconfig[MOUNT_CONFIG_SIZE];
changed_prefs.cdslots[0].inuse = false;
break;
case AKS_IRQ7:
- NMI_delayed ();
+ IRQ_forced(7, 0);
break;
case AKS_PAUSE:
pausemode(newstate > 0 ? 1 : newstate);