struct mmufixup mmufixup[2];
cpuop_func *cpufunctbl[65536];
+cpuop_func_noret *cpufunctbl_noret[65536];
struct cputbl_data
{
uae_s16 length;
struct regstruct regs;
struct flag_struct regflags;
int cpu_cycles;
+static int cycle_count_disable;
static int verbose = 1;
static int feature_exception3_data = 0;
static int feature_exception3_instruction = 0;
static int feature_sr_mask = 0;
static int feature_undefined_ccr = 0;
+static int feature_initial_interrupt = 0;
+static int feature_initial_interrupt_mask = 0;
static int feature_min_interrupt_mask = 0;
static int feature_loop_mode_cnt = 0;
static int feature_loop_mode_register = -1;
static int feature_usp = 0;
static int feature_exception_vectors = 0;
static int feature_interrupts = 0;
+static int feature_waitstates = 0;
static int feature_instruction_size = 0;
static int fpu_min_exponent, fpu_max_exponent;
static int max_file_size;
static int rnd_seed, rnd_seed_prev;
static TCHAR *feature_instruction_size_text = NULL;
static uae_u32 feature_addressing_modes[2];
+static uae_u32 feature_condition_codes;
static int feature_gzip = 0;
static int ad8r[2], pc8r[2];
static int multi_mode;
static uae_u32 opcode_memory_address;
static uaecptr branch_target;
static uaecptr branch_target_pc;
+static uae_u16 test_opcode;
+static int test_absw;
static uae_u8 imm8_cnt;
static uae_u16 imm16_cnt;
static struct regstruct cur_regs;
static uae_u16 read_buffer_prev;
static int interrupt_count;
+static uaecptr interrupt_pc;
static int interrupt_cycle_cnt, interrupt_delay_cnt;
static int interrupt_level;
+static int waitstate_cycle_cnt;
+static int waitstate_delay_cnt;
static uaecptr test_instruction_end_pc;
static uaecptr lm_safe_address1, lm_safe_address2;
static uae_u8 ccr_cnt;
if (low_memory_size != 0xffffffff && addr + size < low_memory_size) {
if (addr < test_low_memory_start || test_low_memory_start == 0xffffffff)
goto oob;
+ // only accept low memory when testing short absolute addressing
+ if (!test_absw) {
+ goto oob;
+ }
// exception vectors needed during tests
if (currprefs.cpu_model == 68000) {
if ((addr + size >= 0x08 && addr < 0x30 || (addr + size >= 0x80 && addr < 0xc0)))
goto oob;
- if (feature_interrupts && (addr + size >= 0x64 && addr < 0x7c))
+ if (feature_interrupts && (addr + size >= 0x60 && addr < 0x80))
goto oob;
}
if (addr + size >= test_low_memory_end)
goto oob;
if (addr + size >= test_high_memory_end)
goto oob;
+ // only accept high memory when testing short absolute addressing
+ if (!test_absw) {
+ goto oob;
+ }
if (w && hmem_rom)
goto oob;
if (testing_active) {
return dummy_memory;
}
-static void count_interrupt_cycles(int cycles)
+static void count_cycles(int cycles)
{
- if (!interrupt_cycle_cnt)
+ if (cycle_count_disable) {
return;
- interrupt_cycle_cnt -= cycles;
- if (interrupt_cycle_cnt <= 0) {
- regs.ipl_pin = IPL_TEST_IPL_LEVEL;
- interrupt_level = regs.ipl_pin;
- interrupt_cycle_cnt = 0;
+ }
+ while (cycles > 0) {
+ cycles--;
+ cpu_cycles++;
+ if (interrupt_cycle_cnt != 0) {
+ interrupt_cycle_cnt--;
+ if (interrupt_cycle_cnt == 0) {
+ if (regs.ipl_pin < IPL_TEST_IPL_LEVEL) {
+ regs.ipl_pin = IPL_TEST_IPL_LEVEL;
+ regs.ipl_pin_change_evt = cpu_cycles;
+ }
+ if (cpu_cycles == regs.ipl_evt_pre + cpuipldelay2) {
+ if (regs.ipl_evt_pre_mode) {
+ ipl_fetch_next();
+ } else {
+ ipl_fetch_now();
+ }
+ }
+ interrupt_pc = regs.pc;
+ interrupt_level = regs.ipl_pin;
+ interrupt_cycle_cnt = 0;
+ }
+ }
}
}
{
if (!testing_active)
return;
- cpu_cycles += cycles;
- count_interrupt_cycles(cycles);
+ count_cycles(cycles);
}
-static void add_memory_cycles(int c)
+static void add_memory_cycles(uaecptr addr, int c)
{
- if (!testing_active)
+ if (cycle_count_disable) {
return;
- if (trace_store_pc != 0xffffffff)
+ }
+ if (!testing_active) {
+ return;
+ }
+ if (trace_store_pc != 0xffffffff) {
return;
- c *= 4;
- cpu_cycles += c;
- count_interrupt_cycles(c);
+ }
+ if (waitstate_cycle_cnt && (addr & addressing_mask) < 0x200000 && c > 0) {
+ c *= 2;
+ while (c > 0) {
+ int now = cpu_cycles;
+ int ipl = regs.ipl_pin;
+ count_cycles(2);
+ c--;
+ // wait for free bus cycle
+ for (;;) {
+ int cb = (cpu_cycles - waitstate_cycle_cnt) / 2;
+ // remove init cycles
+ cb -= 3;
+ if (cb < 0) {
+ break;
+ }
+ if (feature_waitstates == 1) {
+ cb %= 3;
+ // AB-AB-AB-..
+ if (cb == 2) {
+ break;
+ }
+ } else {
+ // -BC--BCD-BCD..
+ // 012301230123
+ if (cb == 0 || cb == 3) {
+ break;
+ }
+ cb %= 4;
+ if (cb == 0) {
+ break;
+ }
+ }
+ ipl = regs.ipl_pin;
+ count_cycles(2);
+ }
+ count_cycles(2);
+ c--;
+ if (now == regs.ipl_evt) {
+ regs.ipl[0] = ipl;
+ }
+ }
+ } else {
+ c *= 4;
+ count_cycles(c);
+ }
}
static void check_bus_error(uaecptr addr, int write, int fc)
{
check_bus_error(addr, 0, regs.s ? 5 : 1);
uae_u8 *p = get_addr(addr, 1, 4);
- add_memory_cycles(1);
+ add_memory_cycles(addr, 1);
return *p;
}
return (get_ibyte_test(addr + 0) << 8) | (get_ibyte_test(addr + 1) << 0);
} else {
uae_u8 *p = get_addr(addr, 2, 4);
- add_memory_cycles(1);
+ add_memory_cycles(addr, 1);
return (p[0] << 8) | (p[1]);
}
}
} else {
uae_u8 *p = get_addr(addr, 4, 4);
v = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]);
- add_memory_cycles(2);
+ add_memory_cycles(addr, 2);
}
return v;
}
if (cpu_lvl < 2) {
o -= 2;
}
- add_memory_cycles(-1);
+ cycle_count_disable = 1;
regs.irc = get_iword_test(m68k_getpci() + o + 2);
+ cycle_count_disable = 0;
read_buffer_prev = regs.read_buffer;
regs.read_buffer = regs.irc;
- return get_iword_test(m68k_getpci() + o);
+ uae_u16 v = get_iword_test(m68k_getpci() + o);
+ return v;
}
static void previoussame(uaecptr addr, int size, uae_u32 *old)
{
if (!testing_active && is_nowrite_address(addr, 1))
return;
- if (feature_interrupts >= 2 && addr == IPL_TRIGGER_ADDR) {
- add_memory_cycles(1);
+ if (feature_interrupts >= 2) {
+ if (addr == IPL_TRIGGER_ADDR) {
+ add_memory_cycles(addr, 1);
#if IPL_TRIGGER_ADDR_SIZE == 1
- interrupt_cycle_cnt = INTERRUPT_CYCLES;
+ interrupt_cycle_cnt = INTERRUPT_CYCLES;
#endif
- return;
+ return;
+ }
}
check_bus_error(addr, 1, regs.s ? 5 : 1);
uae_u8 *p = get_addr(addr, 1, 2);
regs.write_buffer &= 0xff00;
regs.write_buffer |= v & 0xff;
*p = v;
- add_memory_cycles(1);
+ add_memory_cycles(addr, 1);
}
void put_word_test(uaecptr addr, uae_u32 v)
{
if (!testing_active && is_nowrite_address(addr, 1))
return;
- if (feature_interrupts >= 2 && addr == IPL_TRIGGER_ADDR) {
- add_memory_cycles(1);
+ if (feature_interrupts >= 2) {
+ if (addr == IPL_BLTSIZE) {
+ add_memory_cycles(addr, 1);
+ waitstate_cycle_cnt = cpu_cycles;
+ return;
+ }
+ if (addr == IPL_TRIGGER_ADDR) {
+ add_memory_cycles(addr, 1);
#if IPL_TRIGGER_ADDR_SIZE == 2
- interrupt_cycle_cnt = INTERRUPT_CYCLES;
+ interrupt_cycle_cnt = INTERRUPT_CYCLES;
#endif
- return;
+ return;
+ }
}
check_bus_error(addr, 1, regs.s ? 5 : 1);
if (addr & 1) {
p[1] = v & 0xff;
}
regs.write_buffer = v;
- add_memory_cycles(1);
+ add_memory_cycles(addr, 1);
}
void put_long_test(uaecptr addr, uae_u32 v)
{
p[1] = v >> 16;
p[2] = v >> 8;
p[3] = v >> 0;
- add_memory_cycles(2);
+ add_memory_cycles(addr, 2);
}
regs.write_buffer = v;
}
read_buffer_prev = regs.read_buffer;
regs.read_buffer &= 0xff00;
regs.read_buffer |= *p;
- add_memory_cycles(1);
+ add_memory_cycles(addr, 1);
return *p;
}
uae_u32 get_word_test(uaecptr addr)
}
read_buffer_prev = regs.read_buffer;
regs.read_buffer = v;
- add_memory_cycles(1);
+ add_memory_cycles(addr, 1);
return v;
}
uae_u32 get_long_test(uaecptr addr)
} else {
uae_u8 *p = get_addr(addr, 4, 1);
v = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]);
- add_memory_cycles(2);
+ add_memory_cycles(addr, 2);
}
read_buffer_prev = regs.read_buffer;
regs.read_buffer = v;
bool mmu_op30(uaecptr pc, uae_u32 opcode, uae_u16 extra, uaecptr extraa)
{
m68k_setpc(pc);
- op_illg(opcode);
+ op_illg_noret(opcode);
return true;
}
return 0;
}
+void ipl_fetch_next_pre(void)
+{
+ ipl_fetch_next();
+ regs.ipl_evt_pre = cpu_cycles;
+ regs.ipl_evt_pre_mode = 1;
+}
+
+void ipl_fetch_now_pre(void)
+{
+ ipl_fetch_now();
+ regs.ipl_evt_pre = cpu_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[0] = regs.ipl_pin;
- regs.ipl[1] = 0;
- }
+ int c = cpu_cycles;
+ regs.ipl_evt = c;
+ regs.ipl[0] = regs.ipl_pin;
+ regs.ipl[1] = 0;
}
// ipl check was too late, interrupt possible after following instruction
void ipl_fetch_next(void)
{
- if (regs.ipl[1] != regs.ipl_pin) {
+ int c = cpu_cycles;
+ if (c - regs.ipl_pin_change_evt >= cpuipldelay4) {
+ regs.ipl[0] = regs.ipl_pin;
+ regs.ipl[1] = 0;
+ } else {
regs.ipl[1] = regs.ipl_pin;
}
}
static void do_trace(void)
{
if (cpu_stopped) {
- m68k_incpci(4);
- cpu_stopped = 0;
+ return;
}
regs.trace_pc = regs.pc;
if (regs.t0 && !regs.t1 && currprefs.cpu_model >= 68020) {
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.m == ((regs.sr >> 12) & 1) &&
+ regs.intmask == ((regs.sr >> 8) & 7))
+ return;
+
regs.t1 = (regs.sr >> 15) & 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;
+ regs.s = (regs.sr >> 13) & 1;
+ regs.m = (regs.sr >> 12) & 1;
+
+ 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;
+ }
+ regs.intmask = newimask;
+ }
if (currprefs.cpu_model >= 68020) {
/* 68060 does not have MSP but does have M-bit.. */
}
// STOP SR-modification does not generate T0
// If this SR modification set Tx bit, no trace until next instruction.
- if ((oldt0 && t0trace && currprefs.cpu_model >= 68020) || oldt1) {
+ if (!cpu_stopped && ((oldt0 && t0trace && currprefs.cpu_model >= 68020) || oldt1)) {
// Always trace if Tx bits were already set, even if this SR modification cleared them.
activate_trace();
}
exception3_read(regs.ir | flags, test_exception_addr, 1, 2);
}
-uae_u32 REGPARAM2 op_illg_1(uae_u32 opcode)
+void REGPARAM2 op_illg_1_noret(uae_u32 opcode)
{
if ((opcode & 0xf000) == 0xf000) {
if (currprefs.cpu_model == 68030) {
// we can't test any MMU opcodes without parsing following word. TODO.
if ((opcode & 0xfe00) == 0xf000) {
test_exception = -1;
- return 0;
+ return;
}
}
test_exception = 11;
test_exception = 4;
}
doexcstack();
- return 0;
}
void REGPARAM2 op_unimpl(uae_u32 opcode)
{
test_exception = 61;
doexcstack();
}
-uae_u32 REGPARAM2 op_unimpl_1(uae_u32 opcode)
+void REGPARAM2 op_unimpl_1_noret(uae_u32 opcode)
{
if ((opcode & 0xf000) == 0xf000 || currprefs.cpu_model < 68060) {
- op_illg(opcode);
+ op_illg_noret(opcode);
} else {
op_unimpl(opcode);
}
+}
+uae_u32 REGPARAM2 op_unimpl_1(uae_u32 opcode)
+{
+ op_unimpl_1_noret(opcode);
+ return 0;
+}
+
+void REGPARAM2 op_illg_noret(uae_u32 opcode)
+{
+ op_illg_1_noret(opcode);
+}
+uae_u32 REGPARAM2 op_illg_1(uae_u32 opcode)
+{
+ op_illg_1_noret(opcode);
return 0;
}
uae_u32 REGPARAM2 op_illg(uae_u32 opcode)
{
- return op_illg_1(opcode);
+ op_illg_1_noret(opcode);
+ return 0;
}
static void exception3_pc_inc(void)
regs.irc = regs.read_buffer;
regs.read_buffer = prev;
} else {
- add_memory_cycles(1);
+ add_memory_cycles(addr, 1);
}
test_exception = 3;
test_exception_3_w = 0;
if (cpu_lvl == 1) {
get_word_test(addr & ~1);
} else {
- add_memory_cycles(1);
+ add_memory_cycles(addr, 1);
}
exception3_pc_inc();
if (cpu_lvl == 1) {
get_word_test(addr & ~1);
} else {
- add_memory_cycles(1);
+ add_memory_cycles(addr, 1);
}
exception3_pc_inc();
if (cpu_lvl == 1) {
get_word_test(addr & ~1);
} else {
- add_memory_cycles(1);
+ add_memory_cycles(addr, 1);
}
exception3_read(opcode, addr, size, fc);
}
void exception3_write_access(uae_u32 opcode, uae_u32 addr, int size, uae_u32 val, int fc)
{
- add_memory_cycles(1);
+ add_memory_cycles(addr, 1);
exception3_write(opcode, addr, size, val, fc);
}
uae_u16 exception3_word_read(uaecptr addr)
{
- add_memory_cycles(1);
+ add_memory_cycles(addr, 1);
return 0;
}
static void mergefiles(const TCHAR *dir)
{
int tsize = 0;
+ int mergecount = 0;
FILE *of = NULL;
int oi = -1;
unsigned char zero[4] = { 0, 0, 0, 0 };
- unsigned char head[4] = { 0xff, 0xff, 0xff, 0xff };
+ unsigned char head[4] = { 0xaf, 'M', 'R', 'G'};
TCHAR opath[1000];
for (int i = 0; i < filecount; i++) {
TCHAR path[1000];
wprintf(_T("Couldn't open '%s'\n"), opath);
abort();
}
+ mergecount++;
}
if (oi != i) {
_tunlink(path);
fwrite(zero, 1, 4, of);
fclose(of);
}
+ wprintf(_T("Number of files after merge: %d -> %d\n"), filecount, mergecount);
}
static void save_memory(const TCHAR *path, const TCHAR *name, uae_u8 *p, int size)
_tunlink(path2);
}
-
static uae_u8 *modify_reg(uae_u8 *dst, struct regstruct *regs, uae_u8 type, uae_u32 *valp)
{
int mode = type & CT_DATA_MASK;
return dst;
}
-static uae_u8 *store_mem_bytes(uae_u8 *dst, uaecptr start, int len, uae_u8 *old, bool header)
+static uae_u8 *store_mem_bytes(uae_u8 *dst, uaecptr start, int len, uae_u8 *old)
{
if (!len)
return dst;
}
// end
offset = start - oldstart;
- if (offset > 7) {
- start -= (offset - 7);
- old -= (offset - 7);
- offset = 7;
- }
len -= offset;
if (old) {
for (int i = len - 1; i >= 0; i--) {
}
if (!len)
return dst;
- if (header) {
- *dst++ = CT_MEMWRITES | CT_PC_BYTES;
- }
- if (len > 32) {
- *dst++ = (offset << 5) | 31;
+ *dst++ = CT_MEMWRITES | CT_PC_BYTES;
+ if ((len > 32 || offset > 7) || (len == 31 && offset == 7)) {
+ *dst++ = 0xff;
+ *dst++ = offset;
*dst++ = len;
} else {
*dst++ = (offset << 5) | (uae_u8)(len == 32 ? 0 : len);
}
for (int i = 0; i < len; i++) {
*dst++ = get_byte_test(start);
- start++;
}
return dst;
}
(feature_min_interrupt_mask << 20) | (safe_memory_mode << 23) | (feature_interrupts << 26) |
((feature_loop_mode_jit ? 1 : 0) << 28) | ((feature_loop_mode_68010 ? 1 : 0) << 29));
fwrite(data, 1, 4, f);
+ pl(data, (feature_initial_interrupt_mask & 7));
+ fwrite(data, 1, 4, f);
+ pl(data, 0);
+ fwrite(data, 1, 4, f);
+ pl(data, 0);
+ fwrite(data, 1, 4, f);
pl(data, currprefs.fpu_model);
fwrite(data, 1, 4, f);
pl(data, test_low_memory_start);
if (currprefs.cpu_model >= 68020)
v &= ~0x100;
ereg = v >> 12;
- if (loopmodelimit && (ereg == 0 || ereg == 8 + 3 || ereg == 8 + 7 || ((1 << ereg) & ignore_register_mask))) {
+ if (loopmodelimit && (ereg == 0 || ereg == 8 + 3 || ereg == 8 + 7)) {
+ continue;
+ }
+ if ((1 << ereg) & ignore_register_mask) {
continue;
}
break;
uae_u32 v;
if (!high_memory && !low_memory)
return -1;
+ test_absw = 1;
for (;;) {
v = rand16();
if (immabsw_cnt & 1)
else
*isconstant = -1;
} else {
- put_word_test(pc, imm16_cnt);
+ if (dp->mnemo == i_STOP) {
+ put_word_test(pc, imm16_cnt | 0x2000);
+ } else {
+ put_word_test(pc, imm16_cnt);
+ }
if (dp->mnemo == i_STOP && feature_interrupts > 0) {
// STOP hack to keep STOP test size smaller.
- if (feature_interrupts > 1) {
- imm16_cnt += 0x0100;
+ if (feature_interrupts > 0) {
+ imm16_cnt += 0x0080;
} else {
imm16_cnt += 0x0001;
}
}
case absw:
{
- if (target >= test_low_memory_start && target < test_low_memory_end) {
+ if ((target >= test_low_memory_start && target < test_low_memory_end) || (target >= test_high_memory_start && target < test_high_memory_end)) {
put_word_test(pc, target);
*eap = target;
+ test_absw = 1;
return 2;
}
return -2;
0, 1, 1, 1, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 6, 6
};
-static bool check_interrupts(void)
+static void check_interrupts(void)
{
if (feature_interrupts == 1) {
int ic = interrupt_count & 15;
int lvl = interrupt_levels[ic];
if (lvl > 0 && lvl > feature_min_interrupt_mask) {
- Exception(24 + lvl);
- return true;
+ regs.ipl_pin = lvl;
+ return;
}
}
- return false;
}
static int get_ipl(void)
uae_u16 opc = regs.ir;
int off = opcode_memory_address - opcode_memory_start + 2;
uae_u16 opw1 = (opcode_memory[off + 0] << 8) | (opcode_memory[off + 1] << 0);
- uae_u16 opw2 = (opcode_memory[off + 2] << 8) | (opcode_memory[off + 2] << 0);
+ uae_u16 opw2 = (opcode_memory[off + 2] << 8) | (opcode_memory[off + 3] << 0);
if (opc == 0x4e72
&& opw1 == 0xa000
//&& opw2 == 0x4afc
exception_extra_frame_type = 0;
cpu_cycles = 0;
regs.loop_mode = 0;
- regs.ipl_pin = 0;
+ regs.ipl_pin = feature_initial_interrupt;
+ interrupt_level = regs.ipl_pin;
regs.ipl[0] = regs.ipl[1] = 0;
+ regs.ipl_evt_pre = 0;
+ regs.ipl_evt = 0;
interrupt_level = 0;
interrupt_cycle_cnt = 0;
test_exception_orig = 0;
+ waitstate_cycle_cnt = 0;
+ cpuipldelay2 = 2;
+ cpuipldelay4 = 4;
int cnt = 2;
uaecptr first_pc = regs.pc;
uae_u32 loop_mode_reg = 0;
int stop_count = 0;
+ bool starts = regs.s;
+ int startimask = regs.intmask;
+ bool imaskintprevented = false;
+
+ if (regs.ipl_pin > regs.intmask) {
+ wprintf(_T("Interrupt immediately active! IPL=%d IMASK=%d\n"), regs.ipl_pin, regs.intmask);
+ abort();
+ }
+ if (feature_interrupts == 1) {
+ check_interrupts();
+ if (regs.ipl_pin > regs.intmask) {
+ Exception(24 + regs.ipl_pin);
+ goto end;
+ }
+ }
if (feature_loop_mode_68010) {
// 68010 loop mode
if (multi_mode) {
cnt = 100;
}
- if (feature_interrupts >= 2) {
- interrupt_cycle_cnt = INTERRUPT_CYCLES;
- }
for (;;) {
do_trace();
}
- if (check_interrupts()) {
- break;
- }
+ check_interrupts();
regs.instruction_pc = regs.pc;
regs.fp_ea_set = false;
}
}
- (*cpufunctbl[opc])(opc);
+ test_opcode = opc;
+ (*cpufunctbl_noret[opc])(opc);
if (fpumode) {
- // skip result has too large or small exponent
+ // skip result if it has too large or small exponent
for (int i = 0; i < 8; i++) {
if (regs.fp[i].fpx.high != cur_regs.fp[i].fpx.high || regs.fp[i].fpx.low != cur_regs.fp[i].fpx.low) {
int exp = regs.fp[i].fpx.high & 0x7fff;
break;
}
- // CPU stopped or was reset: skip
- if (cpu_stopped && feature_interrupts < 2) {
- break;
- }
-
// Supervisor mode and A7 was modified and not RTE+stack mode: skip this test round.
if (s && regs.s && regs.regs[15] != a7 && (dp->mnemo != i_RTE || feature_usp < 3)) {
// but not if RTE
break;
}
- if (get_ipl() > regs.intmask) {
- Exception(24 + get_ipl());
- break;
- }
- regs.ipl[0] = regs.ipl[1];
- regs.ipl[1] = 0;
-
- if ((regs.pc == endpc || regs.pc == targetpc) && !cpu_stopped && feature_interrupts < 2) {
+ if (((regs.pc == endpc && feature_interrupts < 2) || (regs.pc == targetpc && feature_interrupts < 2)) && !cpu_stopped) {
// Trace is only added as an exception if there was no other exceptions
// Trace stacked with other exception is handled later
if (SPCFLAG_DOTRACE && !test_exception && trace_store_pc == 0xffffffffff) {
Exception(9);
+ break;
}
+ }
- break;
+ if (feature_interrupts >= 1) {
+ if (SPCFLAG_DOTRACE) {
+ if (trace_store_pc != 0xffffffff) {
+ wprintf(_T(" Full trace in interrupt mode!?\n"));
+ abort();
+ }
+ MakeSR();
+ if (cpu_stopped) {
+ cpu_stopped = 0;
+ m68k_incpci(4);
+ regs.ir = get_iword_test(regs.pc + 0);
+ regs.irc = get_iword_test(regs.pc + 2);
+ }
+ trace_store_pc = regs.pc;
+ trace_store_sr = regs.sr;
+ SPCFLAG_DOTRACE = 0;
+ // pending interrupt always triggers during trace processing
+ regs.ipl[0] = regs.ipl_pin;
+ }
+ }
+
+ int ipl = get_ipl();
+ if (ipl > 0) {
+ if (ipl > regs.intmask) {
+ Exception(24 + ipl);
+ break;
+ }
+ if (ipl > startimask && ipl <= regs.intmask && !imaskintprevented) {
+ printf("*");
+ imaskintprevented = true;
+ }
}
+ regs.ipl[0] = regs.ipl[1];
+ regs.ipl[1] = 0;
+
if (test_exception) {
break;
}
if (!feature_loop_mode_jit && !feature_loop_mode_68010) {
// trace after NOP
if (SPCFLAG_DOTRACE) {
+ if (feature_interrupts == 3) {
+ Exception(9);
+ break;
+ }
MakeSR();
// store only first
if (trace_store_pc == 0xffffffff) {
opc = regs.ir;
}
+end:
test_exception_orig = test_exception;
// if still stopped: skip test
}
if (feature_interrupts >= 2) {
- // Skip test if end exception
- if (regs.pc == endpc || regs.pc == targetpc) {
+ // Skip test if end exception and no prevented interrupt
+ if ((regs.pc == endpc || regs.pc == targetpc) && !imaskintprevented) {
+ test_exception = -1;
+ }
+ // skip if check or privilege violation
+ if (test_exception == 6 || test_exception == 8) {
test_exception = -1;
}
// Skip test if no exception
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 - 4 &&
+ test_exception_addr != test_instruction_end_pc - 2 &&
test_exception_addr != test_instruction_end_pc &&
- test_exception_addr != branch_target) {
+ test_exception_addr != branch_target &&
+ test_exception_addr != branch_target + 2) {
test_exception = -1;
}
}
+ if (starts && (test_exception >= 24 && test_exception <= 24 + 8)) {
+ printf("");
+ }
+
}
testing_active = 0;
int quick = 0;
int rounds = feature_test_rounds;
int data_saved = 0;
- int first_cycles = 1;
+ int first_save = 1;
int count = 0;
}
ignore_register_mask = 0;
+ ignore_register_mask |= 1 << 15; // SP
if (feature_loop_mode_register >= 0) {
ignore_register_mask |= 1 << feature_loop_mode_register;
}
full_format_cnt = 0;
last_exception_len = -1;
interrupt_count = 0;
-
interrupt_delay_cnt = 0;
+ interrupt_pc = 0;
+ waitstate_delay_cnt = 0;
int sr_override = 0;
}
dst = store_reg(dst, CT_FPIAR, 0, cur_regs.fpiar, -1);
}
- cur_regs.sr = feature_min_interrupt_mask << 8;
+ cur_regs.sr = feature_initial_interrupt_mask << 8;
uae_u32 srcaddr_old = 0xffffffff;
uae_u32 dstaddr_old = 0xffffffff;
// skip all unsupported instructions if not specifically testing i_ILLG
if (dp->clev > cpu_lvl)
continue;
+ if (dp->ccuse && !(feature_condition_codes & (1 << dp->cc)))
+ continue;
}
if (feature_loop_mode_68010) {
constant_loops = 1;
}
}
+ if (feature_interrupts) {
+ constant_loops = 1;
+ }
while (constant_loops-- > 0) {
uae_u8 oldcodebytes[OPCODE_AREA];
test_exception_extra = 0;
lm_safe_address1 = 0xffffffff;
lm_safe_address2 = 0xffffffff;
+ test_absw = 0;
target_ea[0] = target_ea_bak[0];
target_ea[1] = target_ea_bak[1];
// interrupt IPL timing test mode
if (feature_interrupts >= 2) {
pc -= 2;
- // save CCR
- if (cpu_lvl == 0) {
- // move sr,d7
- put_word_test(pc + 0, 0x40c7); // 4 cycles
- } else {
- // move ccr,d7
- put_word_test(pc + 0, 0x42c7); // 4 cycles
+ if (!feature_waitstates) {
+ // save CCR
+ if (cpu_lvl == 0) {
+ // move sr,d7
+ put_word_test(pc + 0, 0x40c7); // 4 cycles
+ } else {
+ // move ccr,d7
+ put_word_test(pc + 0, 0x42c7); // 4 cycles
+ }
+ pc += 2;
}
- pc += 2;
#if IPL_TRIGGER_ADDR_SIZE == 1
// move.b #x,xxx.L (4 * 4 + 4)
put_long_test(pc, (0x13fc << 16) | IPL_TRIGGER_DATA);
// ror.l d0,d0 (4 + 4 + d0 * 2 cycles)
put_word_test(pc, 0xe0b8);
pc += 2;
- // restore CCR
- // move d7,ccr
- put_word_test(pc, 0x44c7); // 12 cycles
- pc += 2;
- put_word_test(pc, NOP_OPCODE); // 4 cycles
- pc += 2;
- put_word_test(pc, NOP_OPCODE); // 4 cycles
+ if (feature_waitstates) {
+ // move.w #x,0xdff058
+ put_long_test(pc, (0x33fc << 16) | (2 * 64 + 63));
+ pc += 4;
+ put_long_test(pc, IPL_BLTSIZE);
+ pc += 4;
+ // lsl.b #1+,d0
+ put_word_test(pc, 0xe308 + waitstate_delay_cnt * 0x200); // 4+n*2 cycles
+ pc += 2;
+ }
+ if (!feature_waitstates) {
+ // restore CCR
+ // move d7, ccr
+ put_word_test(pc, 0x44c7); // 12 cycles
+ pc += 2;
+ }
+ put_word_test(pc, REAL_NOP_OPCODE); // 4 cycles
pc += 2;
if (feature_interrupts >= 3) {
// or #$8000,sr
put_long_test(pc, 0x007c8000);
pc += 4;
} else {
- put_word_test(pc, NOP_OPCODE); // 4 cycles
+ put_word_test(pc, IPL_TEST_NOP1); // 4 cycles
pc += 2;
}
opcode_memory_address = pc;
}
+ if (feature_interrupts >= 2) {
+ put_long_test(pc, (IPL_TEST_NOP2 << 16) | REAL_NOP_OPCODE); // 8 cycles
+ pc += 4;
+ }
+
// if bus error stack checking and RTE: copy USP to ISP before RTE
if (dp->mnemo == i_RTE && feature_usp == 3) {
put_word_test(opcode_memory_address, 0x4e6f); // MOVE USP,A7
srcaddr = 0xffffffff;
dstaddr = 0xffffffff;
- if (opc == 0x4efb && get_word_debug(opcode_memory_address + 2) == 0x06d4)
- printf("");
-
uae_u32 dflags = m68k_disasm_2(out, sizeof(out) / sizeof(TCHAR), opcode_memory_address, NULL, 0, &nextpc, 1, &srcaddr, &dstaddr, 0xffffffff, 0);
if (verbose) {
my_trim(out);
}
}
-
- if (srcaddr == 0x006b022e)
- printf("");
-
// disassembler may set this
out_of_test_space = false;
}
}
- if (subtest_count == 262144)
+ if (subtest_count > 0)
printf("");
// save opcode memory
- dst = store_mem_bytes(dst, opcode_memory_start, instruction_end_pc - opcode_memory_start, oldcodebytes, true);
+ dst = store_mem_bytes(dst, opcode_memory_start, instruction_end_pc - opcode_memory_start, oldcodebytes);
// store branch target and stack modifications (these needs to be rolled back after the test)
dst = store_mem_writes(dst, 1);
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;
} else {
regs.sr = ((ccr & 1) ? 31 : 0) | sr_mask;
}
- regs.sr |= feature_min_interrupt_mask << 8;
+ if (feature_initial_interrupt_mask > ((regs.sr >> 8) & 7)) {
+ regs.sr &= ~(7 << 8);
+ regs.sr |= feature_initial_interrupt_mask << 8;
+ }
// override special register values
for (int i = 0; i < regdatacnt; i++) {
if (regs.sr & 0x2000)
prev_s_cnt++;
- if (subtest_count == 77171)
+ if (subtest_count == 9)
printf("");
// execute test instruction(s)
} else if (test_exception) {
// generated exception
exception_array[test_exception]++;
- if (test_exception == 8 && !(sr_mask & 0x2000) && !(feature_sr_mask & 0x2000)) {
- // Privilege violation exception and S mask not set? Switch to super mode in next round.
- sr_mask_request |= 0x2000;
- sr_allowed_mask |= 0x2000;
+ if (test_exception == 8) {
+ if (!(sr_mask & 0x2000) && !(feature_sr_mask & 0x2000)) {
+ // Privilege violation exception and S mask not set? Switch to super mode in next round.
+ sr_mask_request |= 0x2000;
+ sr_allowed_mask |= 0x2000;
+ }
}
// got exception 3 but didn't want them?
if (test_exception == 3) {
for (int i = 0; i < MAX_REGISTERS; i++) {
uae_u32 s = last_regs.regs[i];
uae_u32 d = regs.regs[i];
- if (s != d) {
+ if (s != d || first_save) {
if (storeregs) {
- dst = store_reg(dst, CT_DREG + i, s, d, -1);
+ dst = store_reg(dst, CT_DREG + i, s, d, first_save ? sz_long : -1);
}
last_regs.regs[i] = d;
}
}
// SR/CCR
uae_u32 ccrignoremask = get_ccr_ignore(dp, extraword, false) << 16;
- if ((regs.sr | ccrignoremask) != last_regs.sr) {
- dst = store_reg(dst, CT_SR, last_regs.sr, regs.sr | ccrignoremask, -1);
+ if ((regs.sr | ccrignoremask) != last_regs.sr || first_save) {
+ dst = store_reg(dst, CT_SR, last_regs.sr, regs.sr | ccrignoremask, first_save ? sz_word : -1);
last_regs.sr = regs.sr | ccrignoremask;
}
// PC
- if (regs.pc - extraopcodeendsize != last_regs.pc) {
+ if (regs.pc - extraopcodeendsize != last_regs.pc || first_save) {
dst = store_rel(dst, CT_PC, last_regs.pc, regs.pc - extraopcodeendsize, 0);
last_regs.pc = regs.pc - extraopcodeendsize;
}
for (int i = 0; i < 8; i++) {
floatx80 s = last_regs.fp[i].fpx;
floatx80 d = regs.fp[i].fpx;
- if (s.high != d.high || s.low != d.low) {
+ if (s.high != d.high || s.low != d.low || first_save) {
dst = store_fpureg(dst, CT_FPREG + i, &s, d, 0);
last_regs.fp[i].fpx = d;
}
}
- if (regs.fpiar != last_regs.fpiar) {
- dst = store_reg(dst, CT_FPIAR, last_regs.fpiar, regs.fpiar, -1);
+ if (regs.fpiar != last_regs.fpiar || first_save) {
+ dst = store_reg(dst, CT_FPIAR, last_regs.fpiar, regs.fpiar, first_save ? sz_long : -1);
last_regs.fpiar = regs.fpiar;
}
- if (regs.fpsr != last_regs.fpsr) {
- dst = store_reg(dst, CT_FPSR, last_regs.fpsr, regs.fpsr, -1);
+ if (regs.fpsr != last_regs.fpsr || first_save) {
+ dst = store_reg(dst, CT_FPSR, last_regs.fpsr, regs.fpsr, first_save ? sz_long : -1);
last_regs.fpsr = regs.fpsr;
}
- if (regs.fpcr != last_regs.fpcr) {
- dst = store_reg(dst, CT_FPCR, last_regs.fpcr, regs.fpcr, -1);
+ if (regs.fpcr != last_regs.fpcr || first_save) {
+ dst = store_reg(dst, CT_FPCR, last_regs.fpcr, regs.fpcr, first_save ? sz_long : -1);
last_regs.fpcr = regs.fpcr;
}
}
- if (cpu_lvl <= 1 && (last_cpu_cycles != cpu_cycles || first_cycles)) {
- dst = store_reg(dst, CT_CYCLES, last_cpu_cycles, cpu_cycles, first_cycles ? sz_word : -1);
+ if (cpu_lvl <= 1 && (last_cpu_cycles != cpu_cycles || first_save)) {
+ dst = store_reg(dst, CT_CYCLES, last_cpu_cycles, cpu_cycles, first_save ? sz_word : -1);
last_cpu_cycles = cpu_cycles;
- first_cycles = 0;
}
+
+ first_save = 0;
+
// store test instruction generated changes
dst = store_mem_writes(dst, 0);
uae_u8 bcflag = regs.pc == branch_target_pc ? CT_BRANCHED : 0;
}
}
if (verbose) {
- wprintf(_T(" OK=%d OB=%d S=%d/%d T=%d STP=%d I=%d/%d EX=%d %08x %08x"), ok, exception_array[0],
+ wprintf(_T(" OK=%d OB=%d S=%d/%d T=%d S=%d I=%d/%d EX=%d %08x %08x %08x"), ok, exception_array[0],
prev_s_cnt, s_cnt, t_cnt, cnt_stopped, interrupt_delay_cnt, interrupt_cycle_cnt,
test_exception_orig,
- test_exception_addr, regs.pc);
+ test_exception_addr, regs.pc, interrupt_pc);
if (!ccr_done)
wprintf(_T(" X"));
for (int i = 2; i < 128; i++) {
// interrupt delay test
if (feature_interrupts >= 2) {
- interrupt_delay_cnt++;
+ if (feature_waitstates) {
+ waitstate_delay_cnt++;
+ if (waitstate_delay_cnt >= 3) {
+ waitstate_delay_cnt = 0;
+ interrupt_delay_cnt++;
+ }
+ } else {
+ interrupt_delay_cnt++;
+ }
if (interrupt_delay_cnt > 2 * 63) {
break;
} else {
_T("absw"), _T("absl"), _T("PC16"), _T("PC8r"), _T("imm"), _T("Ad8rf"), _T("PC8rf"),
NULL
};
+static const TCHAR *ccnames[] =
+{
+ _T("T"), _T("F"), _T("HI"),_T("LS"),_T("CC"),_T("CS"),_T("NE"),_T("EQ"),
+ _T("VC"),_T("VS"),_T("PL"),_T("MI"),_T("GE"),_T("LT"),_T("GT"),_T("LE")
+};
+
#define INISECTION _T("cputest")
feature_addressing_modes[1] = 0xffffffff;
ad8r[0] = ad8r[1] = 1;
pc8r[0] = pc8r[1] = 1;
+ feature_condition_codes = 0xffffffff;
feature_exception3_data = 0;
ini_getvalx(ini, sections, _T("feature_exception3_data"), &feature_exception3_data);
feature_undefined_ccr = 0;
ini_getvalx(ini, sections, _T("feature_undefined_ccr"), &feature_undefined_ccr);
+ feature_initial_interrupt = 0;
+ ini_getvalx(ini, sections, _T("feature_initial_interrupt"), &feature_initial_interrupt);
+
+ feature_initial_interrupt_mask = 0;
+ ini_getvalx(ini, sections, _T("feature_initial_interrupt_mask"), &feature_initial_interrupt_mask);
+
feature_min_interrupt_mask = 0;
ini_getvalx(ini, sections, _T("feature_min_interrupt_mask"), &feature_min_interrupt_mask);
ini_getvalx(ini, sections, _T("feature_exception_vectors"), &feature_exception_vectors);
feature_interrupts = 0;
ini_getvalx(ini, sections, _T("feature_interrupts"), &feature_interrupts);
+ feature_waitstates = 0;
+ ini_getvalx(ini, sections, _T("feature_waitstates"), &feature_waitstates);
feature_full_extension_format = 0;
if (currprefs.cpu_model >= 68020) {
}
}
+ TCHAR *cc = NULL;
+ if (ini_getstringx(ini, sections, _T("feature_condition_codes"), &cc)) {
+ feature_condition_codes = 0;
+ TCHAR *p = cc;
+ while (p && *p) {
+ TCHAR *pp = _tcschr(p, ',');
+ if (pp) {
+ *pp++ = 0;
+ }
+ TCHAR cctext[256];
+ _tcscpy(cctext, p);
+ my_trim(cctext);
+ for (int i = 0; ccnames[i]; i++) {
+ if (!_tcsicmp(ccnames[i], cctext)) {
+ feature_condition_codes |= 1 << i;
+ break;
+ }
+ }
+ p = pp;
+ }
+ xfree(cc);
+ }
+
TCHAR *mode = NULL;
ini_getstringx(ini, sections, _T("mode"), &mode);
for (int opcode = 0; opcode < 65536; opcode++) {
cpufunctbl[opcode] = op_illg_1;
+ cpufunctbl_noret[opcode] = op_illg_1_noret;
}
-
- for (int i = 0; tbl[i].handler_ff != NULL; i++) {
+ for (int i = 0; tbl[i].handler_ff != NULL || tbl[i].handler_ff_noret != NULL; i++) {
int opcode = tbl[i].opcode;
cpufunctbl[opcode] = tbl[i].handler_ff;
+ cpufunctbl_noret[opcode] = tbl[i].handler_ff_noret;
cpudatatbl[opcode].length = tbl[i].length;
cpudatatbl[opcode].disp020[0] = tbl[i].disp020[0];
cpudatatbl[opcode].disp020[1] = tbl[i].disp020[1];
}
for (int opcode = 0; opcode < 65536; opcode++) {
- cpuop_func *f;
instr *table = &table68k[opcode];
if (table->mnemo == i_ILLG)
// generates unimplemented instruction exception.
if (currprefs.int_no_unimplemented && table->unimpclev == 5) {
cpufunctbl[opcode] = op_unimpl_1;
+ cpufunctbl_noret[opcode] = op_unimpl_1_noret;
continue;
}
// remove unimplemented instruction that were removed in previous models,
// clev=4: implemented in 68040 or later. unimpclev=5: not in 68060
if (table->unimpclev < 5 || (table->clev == 4 && table->unimpclev == 5)) {
cpufunctbl[opcode] = op_illg_1;
+ cpufunctbl_noret[opcode] = op_illg_1_noret;
continue;
}
} else {
- cpufunctbl[opcode] = op_illg_1;
+ cpufunctbl_noret[opcode] = op_illg_1_noret;
continue;
}
}
if (table->handler != -1) {
int idx = table->handler;
- f = cpufunctbl[idx];
- if (f == op_illg_1)
+ if (cpufunctbl[idx] == op_illg_1 || cpufunctbl_noret[idx] == op_illg_1_noret)
abort();
- cpufunctbl[opcode] = f;
+ cpufunctbl[opcode] = cpufunctbl[idx];
+ cpufunctbl_noret[opcode] = cpufunctbl_noret[idx];
memcpy(&cpudatatbl[opcode], &cpudatatbl[idx], sizeof(struct cputbl_data));
}
uae_u32 tracecnt;
uae_u16 tracedata[6];
uae_u32 cycles, cycles2, cyclest;
+ uae_u32 blttemp;
struct fpureg fpuregs[8];
uae_u32 fpiar, fpcr, fpsr;
static uae_u32 test_memory_addr, test_memory_end;
static uae_u32 test_memory_size;
static uae_u8 *test_data;
+#define BLT_TEMP_SIZE 8000
+static uae_u32 blt_data;
static uae_u8 *safe_memory_start, *safe_memory_end;
static short safe_memory_mode;
static uae_u32 user_stack_memory, super_stack_memory;
static uae_u32 fpsr_ignore_mask;
static uae_u32 addressing_mask = 0x00ffffff;
static uae_u32 interrupt_mask;
+static short initial_interrupt_mask;
+static short initial_interrupt;
static short loop_mode_jit, loop_mode_68010, loop_mode_cnt;
static short instructionsize;
static short disasm;
static int prealloc_test_data_size = 1001000;
static int prealloc_gzip_size = 500000;
static int prealloc;
+static uae_u8 *debug_item_data;
+static short debug_item_count;
#define SIZE_STORED_ADDRESS_OFFSET 6
#define SIZE_STORED_ADDRESS 20
static void free_absolute(uae_u32 addr, uae_u32 size)
{
}
+static uae_u8 *allocate_blttemp(uae_u32 size)
+{
+ return calloc(1, size);
+}
+static void free_blttemp(uae_u32 addr, uae_u32 size)
+{
+}
static void execute_test000(struct registers *regs)
{
}
extern uae_u8 *allocate_absolute(uae_u32, uae_u32);
extern void free_absolute(uae_u32, uae_u32);
+extern uae_u32 allocate_blttemp(uae_u32);
+extern void free_blttemp(uae_u32, uae_u32);
extern void execute_test000(struct registers*);
extern void execute_test010(struct registers *);
extern void execute_test020(struct registers *);
error_vectors[i - 2] = p[i];
}
}
- if (interrupttest) {
+ if (interrupttest || initial_interrupt_mask || initial_interrupt) {
for (int i = 24; i < 24 + 8; i++) {
p[i] = (uae_u32)(((uae_u32)&exceptiontable000) + (i - 2) * 2);
if (exception_vectors) {
unsigned char buf[4] = { 0 };
fseek(f, *foffsetp, SEEK_SET);
fread(buf, 1, sizeof(buf), f);
- if (buf[0] == 0xff && buf[1] == 0xff && buf[2] == 0xff && buf[3] == 0xff) {
+ if (buf[0] == 0xaf && buf[1] == 'M' && buf[2] == 'R' && buf[3] == 'G') {
fread(buf, 1, sizeof(buf), f);
size = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | (buf[3] << 0);
if (size == 0) {
}
FILE *f = fopen(fname, "rb");
if (f) {
- int gsize;
+ int gsize = 0;
if (foffsetp) {
gsize = load_file_offset(f, foffsetp);
if (gsize == 0) {
*sizep = gsize;
}
}
- if (*sizep <= 0) {
+ if (*sizep <= 0 || foffsetp == NULL) {
fseek(f, 0, SEEK_END);
gsize = ftell(f);
fseek(f, 0, SEEK_SET);
printf("Decompressing '%s' (%d -> %d)\n", fname, gsize, size);
callinflate(p, gzdata, inflatestack);
*sizep = size;
+ if (!prealloc_gzip) {
+ free(gzbuf);
+ }
return p;
} else if (candirect) {
printf("Decompressing '%s' (%d -> %d)\n", fname, gsize, size);
callinflate(p, gzdata, inflatestack);
*sizep = size;
+ if (!prealloc_gzip) {
+ free(gzbuf);
+ }
return p;
} else {
unpack = calloc(1, size);
return p;
}
+static void endinfo_debug(uae_u8 *p)
+{
+ printf("PTR %08x, %08x, count %d\n", debug_item_data, p, debug_item_count);
+}
+
static void pl(uae_u8 *p, uae_u32 v)
{
p[0] = v >> 24;
if ((v & CT_SIZE_MASK) != CT_SIZE_FPU) {
end_test();
printf("Expected CT_SIZE_FPU, got %02x\n", v);
+ endinfo_debug(p);
endinfo();
exit(0);
}
break;
case CT_SIZE_FPU:
end_test();
- printf("Unexpected CT_SIZE_FPU\n");
+ printf("Unexpected CT_SIZE_FPU (%02x)\n", v);
+ endinfo_debug(p);
endinfo();
exit(0);
break;
} else if ((val & addressing_mask) < test_memory_addr || (val & addressing_mask) >= test_memory_addr + test_memory_size) {
end_test();
printf("restore_rel CT_ABSOLUTE_LONG outside of test memory! %08x\n", v);
+ endinfo_debug(p);
endinfo();
exit(0);
}
}
-static void validate_mode(uae_u8 mode, uae_u8 v)
+static void validate_mode(uae_u8 *p, uae_u8 v)
{
+ uae_u8 mode = p[0];
if ((mode & CT_DATA_MASK) != v) {
end_test();
printf("CT_MEMWRITE expected but got %02X\n", mode);
+ endinfo_debug(p);
endinfo();
exit(0);
}
} else {
addr = low_memory + offset;
}
- validate_mode(p[0], CT_MEMWRITE);
+ validate_mode(p, CT_MEMWRITE);
*addrp = addr;
return p;
}
#else
uae_u8 *addr = (uae_u8*)val;
#endif
- validate_mode(p[0], CT_MEMWRITE);
+ validate_mode(p, CT_MEMWRITE);
*addrp = addr;
return p;
} else if (val >= test_memory_addr && val < test_memory_addr + test_memory_size) {
#else
uae_u8 *addr = (uae_u8*)val;
#endif
- validate_mode(p[0], CT_MEMWRITE);
+ validate_mode(p, CT_MEMWRITE);
*addrp = addr;
return p;
} else {
end_test();
printf("get_memory_addr CT_ABSOLUTE_LONG outside of test memory! %08x\n", val);
+ endinfo_debug(p);
endinfo();
exit(0);
}
val |= *p++;
uae_s16 offset = (uae_s16)val;
uae_u8 *addr = opcode_memory + offset;
- validate_mode(p[0], CT_MEMWRITE);
+ validate_mode(p, CT_MEMWRITE);
*addrp = addr;
return p;
}
default:
end_test();
printf("get_memory_addr unknown size %02x\n", v);
+ endinfo_debug(p);
endinfo();
exit(0);
}
static uae_u8 *restore_bytes(uae_u8 *mem, uae_u8 *p)
{
uae_u8 *addr = mem;
- uae_u16 v = *p++;
- addr += v >> 5;
- v &= 31;
- if (v == 31) {
- v = *p++;
- if (v == 0) {
- v = 256;
+ uae_u16 len, offset;
+ if (*p == 0xff) {
+ p++;
+ offset = *p++;
+ len = *p++;
+ if (len == 0) {
+ len = 256;
+ }
+ } else {
+ uae_u8 v = *p++;
+ offset = v >> 5;
+ len = v & 31;
+ if (len == 0) {
+ len = 32;
}
- } else if (v == 0) {
- v = 32;
}
+ addr += offset;
#ifndef _MSC_VER
- xmemcpy(addr, p, v);
+ xmemcpy(addr, p, len);
#endif
- p += v;
+ p += len;
return p;
}
default:
end_test();
printf("Unknown restore_memory type!?\n");
+ endinfo_debug(p);
endinfo();
exit(0);
break;
default:
end_test();
printf("Unknown restore_memory type!?\n");
+ endinfo_debug(p);
endinfo();
exit(0);
break;
default:
end_test();
printf("Unexpected CT_EDATA 0x%02x\n", *p);
+ endinfo_debug(p);
endinfo();
exit(0);
}
if (v & CT_END) {
end_test();
printf("Unexpected end bit!? 0x%02x offset %d\n", v, p - test_data);
+ endinfo_debug(p);
endinfo();
exit(0);
}
{
char *name;
int bit;
+ int size;
};
static const struct srbit srbits[] = {
- { "T1", 15 },
- { "T0", 14 },
- { "S", 13 },
- { "M", 12 },
- { "X", 4 },
- { "N", 3 },
- { "Z", 2 },
- { "V", 1 },
- { "C", 0 },
- { NULL, 0 }
+ { "T1", 15, 1 },
+ { "T0", 14, 1 },
+ { "S", 13, 1 },
+ { "M", 12, 1 },
+ { "IM", 8, 3 },
+ { "X", 4, 1 },
+ { "N", 3, 1 },
+ { "Z", 2, 1 },
+ { "V", 1, 1 },
+ { "C", 0, 1 },
+ { NULL, 0, 0 }
};
// r = registers to output
for (int i = 0; srbits[i].name; i++) {
if (i > 0)
*outbp++ = ' ';
- uae_u16 mask = 1 << srbits[i].bit;
+ uae_u16 mask = 0;
+ for (int j = 0; j < srbits[i].size; j++) {
+ mask <<= 1;
+ mask |= 1 << srbits[i].bit;
+ }
sprintf(outbp, "%s%c%d", srbits[i].name,
- (s2 & mask) != (s3 & mask) ? '!' : ((s1 & mask) != (s2 & mask) ? '*' : '='), (s & mask) != 0);
+ (s2 & mask) != (s3 & mask) ? '!' : ((s1 & mask) != (s2 & mask) ? '*' : '='), (s & mask) >> srbits[i].bit);
outbp += strlen(outbp);
}
*outbp++ = '\n';
}
sprintf(outbp, "Expected trace exception (PC=%08x) but got none.\n", pc);
outbp += strlen(outbp);
- *experr = 1;
+ *experr |= 2;
} else if (!(last_exception_extra & 0x80)) {
// Trace stacked with group 2 exception
if (!(sr & 0x2000) || (sr | 0x2000 | 0xc000) != (regs->sr | 0x2000 | 0xc000)) {
sprintf(outbp, "Trace (%d stacked) SR mismatch: %04x != %04x\n", excnum, sr, regs->sr);
outbp += strlen(outbp);
- *experr = 1;
+ *experr |= 2;
}
uae_u32 retv = exceptiontableinuse + (excnum - 2) * 2;
if (ret != retv) {
sprintf(outbp, "Trace (%d stacked) PC mismatch: %08x != %08x\n", excnum, ret, retv);
outbp += strlen(outbp);
- *experr = 1;
+ *experr |= 2;
}
*extratrace = 1;
} else {
if ((vsr & test_ccrignoremask) != (sr & test_ccrignoremask)) {
sprintf(outbp, "Trace (non-stacked) SR mismatch: %04x != %04x (PC=%08x)\n", sr, vsr, v);
outbp += strlen(outbp);
- *experr = 1;
+ *experr |= 2;
}
if (v != ret) {
sprintf(outbp, "Trace (non-stacked) PC mismatch: %08x != %08x (SR=%04x)\n", ret, v, vsr);
outbp += strlen(outbp);
- *experr = 1;
+ *experr |= 2;
}
+ *extratrace = -1;
}
} else if (!last_exception_extra && excnum != 9) {
if (regs->tracecnt > 0) {
sprintf(outbp, "Exception %d also pending.\n", excnum);
outbp += strlen(outbp);
}
- *experr = 1;
+ *experr |= 2;
}
} else if (last_exception_extra) {
end_test();
strcpy(outbp, "Got : ");
outbp += strlen(outbp);
hexdump(sp, exclen, 1);
- *experr = 1;
+ *experr |= 1;
}
exception_stored = exclen;
return p;
static uae_u16 test_intena, test_intreq;
+static const uae_u16 itable[] =
+{
+ 0,
+ 1 << 2,
+ 1 << 3,
+ 1 << 4,
+ 1 << 7,
+ 1 << 11,
+ 1 << 13,
+ 0
+};
+
static void set_interrupt(void)
{
if (interrupttest == 1) {
*intena = 0x8000 | 0x4000 | IPL_TRIGGER_INTMASK;
*intreq = IPL_TRIGGER_INTMASK;
}
+ if (initial_interrupt) {
+ uae_u16 mask = itable[initial_interrupt];
+ volatile uae_u16 *intena = (uae_u16*)0xdff09a;
+ volatile uae_u16 *intreq = (uae_u16*)0xdff09c;
+ *intena = 0x8000 | 0x4000 | mask;
+ *intreq = 0x8000 | mask;
+ }
}
static void clear_interrupt(void)
}
gotcycles += cycles_adjust;
- if (extratrace) {
+ if (extratrace > 0) {
expectedcycles += getexceptioncycles(9);
}
// address error during group 2 exception stacking (=odd exception vector)
}
if (0 || abs(gotcycles - expectedcycles) > cycles_range) {
- addinfo();
- sprintf(outbp, "Got %d cycles (%d + %d) but expected %d (%d + %d)\n",
+ sprintf(outbp, "Got %d cycles (%d + %d) but expected %d (%d + %d) %08x\n",
gotcycles, gotcycles - exceptioncycles, exceptioncycles,
- expectedcycles, expectedcycles - exceptioncycles, exceptioncycles);
+ expectedcycles, expectedcycles - exceptioncycles, exceptioncycles, test_regs.cycles);
outbp += strlen(outbp);
return 0;
}
if (cpu_lvl > 0 && exc >= 2 && cpuexc010 != cpuexc) {
if (dooutput) {
sprintf(outbp, "Exception: vector number does not match vector offset! (%d <> %d) %d\n", exc, cpuexc010, cpuexc);
- experr = 1;
+ experr |= 1;
outbp += strlen(outbp);
errflag |= 1 << 16;
}
hexdump(excp, excsize, 1);
}
}
- experr = 1;
+ if ((experr & 2) && !(experr & 1) && extratrace) {
+ sprintf(outbp, "Valid trace exception found\n");
+ outbp += strlen(outbp);
+ }
+ experr |= 2;
}
errflag |= 1 << 16;
}
}
#endif
if (exc > 1) {
- if (!experr) {
+ if (!(experr & 1)) {
sprintf(outbp, "OK: exception %d ", exc);
outbp += strlen(outbp);
if (exception_stored) {
static void out_endinfo(void)
{
- sprintf(outbp, "%u (%u/%u) ", testcnt, testcntsub, testcntsubmax);
+ sprintf(outbp, "%u (%u/%u/%u) ", testcnt, testcntsub, testcntsubmax, interrupt_delay_cnt);
outbp += strlen(outbp);
sprintf(outbp, "S=%d", supercnt);
outbp += strlen(outbp);
short doopcodeswap = 1;
- if (interrupttest >= 1) {
+ if (interrupttest >= 2) {
doopcodeswap = 0;
}
cur_regs.endpc = endpc;
cur_regs.pc = startpc;
+ debug_item_data = p;
+ debug_item_count = 0;
for (;;) {
uae_u8 v = *p;
if (v == CT_END_INIT || v == CT_END_FINISH)
break;
p = restore_data(p, &cur_regs);
+ debug_item_count++;
}
+ debug_item_count = -1;
if (*p == CT_END_FINISH)
break;
p++;
test_regs.pc = startpc;
test_regs.cyclest = 0xffffffff;
test_regs.fpeaset = 0;
+ test_regs.blttemp = blt_data;
#ifdef M68K
if (stackcopysize > 0)
} else {
test_regs.sr = (ccr & 1) ? 31 : 0;
}
- test_regs.sr |= sr_mask | (interrupt_mask << 8);
+ test_regs.sr |= sr_mask | (initial_interrupt_mask << 8);
if (fpumode) {
test_regs.fpcr = 0;
test_regs.fpsr = 0;
#ifdef AMIGA
- if (interrupttest) {
+ if (interrupttest || initial_interrupt_mask || initial_interrupt) {
set_interrupt();
}
#endif
}
#ifdef AMIGA
- if (interrupttest) {
+ if (interrupttest || initial_interrupt_mask || initial_interrupt) {
clear_interrupt();
}
#endif
static void freestuff(void)
{
- if (test_memory && test_memory_addr)
+ if (test_memory && test_memory_addr) {
free_absolute(test_memory_addr, test_memory_size);
+ }
+ if (blt_data) {
+ free_blttemp(blt_data, BLT_TEMP_SIZE);
+ }
#ifdef WAITEXIT
getchar();
#endif
test_memory_end = test_memory_addr + test_memory_size;
opcode_memory_addr = read_u32(headerfile, &headoffset);
opcode_memory = (uae_u8*)opcode_memory_addr;
- uae_u32 lvl_mask = read_u32(headerfile, &headoffset);
- lvl = (lvl_mask >> 16) & 15;
- interrupt_mask = (lvl_mask >> 20) & 7;
- addressing_mask = (lvl_mask & 0x80000000) ? 0xffffffff : 0x00ffffff;
- interrupttest = (lvl_mask >> 26) & 3;
- sr_undefined_mask = lvl_mask & 0xffff;
- safe_memory_mode = (lvl_mask >> 23) & 7;
- loop_mode_jit = (lvl_mask >> 28) & 1;
- loop_mode_68010 = (lvl_mask >> 29) & 1;
+ v = read_u32(headerfile, &headoffset);
+ lvl = (v >> 16) & 15;
+ interrupt_mask = (v >> 20) & 7;
+ addressing_mask = (v & 0x80000000) ? 0xffffffff : 0x00ffffff;
+ interrupttest = (v >> 26) & 3;
+ sr_undefined_mask = v & 0xffff;
+ safe_memory_mode = (v >> 23) & 7;
+ loop_mode_jit = (v >> 28) & 1;
+ loop_mode_68010 = (v >> 29) & 1;
+ v = read_u32(headerfile, &headoffset);
+ initial_interrupt_mask = v & 7;
+ initial_interrupt = (v >> 3) & 7;
+ v = read_u32(headerfile, &headoffset);
+ v = read_u32(headerfile, &headoffset);
fpu_model = read_u32(headerfile, &headoffset);
test_low_memory_start = read_u32(headerfile, &headoffset);
test_low_memory_end = read_u32(headerfile, &headoffset);
}
}
+ blt_data = allocate_blttemp(BLT_TEMP_SIZE);
+ if (!blt_data) {
+ printf("blt_temp failed to allocated.\n");
+ exit(0);
+ }
+
int otestcnt = -1;
for (;;) {
if (otestcnt != testcnt) {
}
}
+ if (blt_data) {
+ free_blttemp(blt_data, BLT_TEMP_SIZE);
+ blt_data = 0;
+ }
+
if (errorcnt == 0) {
outbp = outbuffer;
out_endinfo();