static int feature_exception3_data = 0;
static int feature_exception3_instruction = 0;
static int feature_sr_mask = 0;
+static int feature_loop_mode = 0;
+static int feature_loop_mode_register = -1;
static int feature_full_extension_format = 0;
static uae_u32 feature_addressing_modes[2];
static int ad8r[2], pc8r[2];
addr &= addressing_mask;
size--;
if (addr + size < LOW_MEMORY_END) {
- if (addr < test_low_memory_start)
+ if (addr < test_low_memory_start || test_low_memory_start == 0xffffffff)
goto oob;
// exception vectors needed during tests
if ((addr + size >= 0x0c && addr < 0x30 || (addr + size >= 0x80 && addr < 0xc0)) && regs.vbr == 0)
return 1;
}
if (addr >= HIGH_MEMORY_START && addr < HIGH_MEMORY_START + 0x8000) {
- if (addr < test_high_memory_start)
+ if (addr < test_high_memory_start || test_high_memory_start == 0xffffffff)
goto oob;
if (addr + size >= test_high_memory_end)
goto oob;
-static uae_u8 *store_rel(uae_u8 *dst, uae_u8 mode, uae_u32 s, uae_u32 d)
+static uae_u8 *store_rel(uae_u8 *dst, uae_u8 mode, uae_u32 s, uae_u32 d, int ordered)
{
int diff = (uae_s32)d - (uae_s32)s;
- if (diff == 0)
+ if (diff == 0) {
+ if (!ordered)
+ return dst;
+ *dst++ = CT_EMPTY;
return dst;
+ }
if (diff >= -128 && diff < 128) {
*dst++ = mode | CT_RELATIVE_START_BYTE;
*dst++ = diff & 0xff;
fwrite(data, 1, 4, f);
pl(data, (uae_u32)starttime);
fwrite(data, 1, 4, f);
- pl(data, (hmem_rom << 16) | lmem_rom);
+ pl(data, ((hmem_rom | (test_high_memory_start == 0xffffffff ? 0x8000 : 0x0000)) << 16) | (lmem_rom | (test_low_memory_start == 0xffffffff ? 0x8000 : 0x0000)));
fwrite(data, 1, 4, f);
pl(data, test_memory_start);
fwrite(data, 1, 4, f);
switch (mode)
{
case Dreg:
+ if (reg == feature_loop_mode_register) {
+ if (((dp->sduse & 0x20) && !srcdst) || ((dp->sduse & 0x02) && srcdst)) {
+ int pos = srcdst ? dp->dpos : dp->spos;
+ opcode &= ~(7 << pos);
+ opcode |= ((reg + 1) & 7) << pos;
+ }
+ }
+ break;
case Areg:
case Aind:
case Aipi:
addr += 2;
offset += 2;
*isconstant = imm_special >= (1 << (0 + 5)) * 4 ? 0 : -1;
- } else if (opcode == 0x4e77) {
+ } else if (opcode == 0x4e74) {
// RTD
v = imm_special >> 2;
uae_u16 sr = v & 31;
return offset;
}
-static void execute_ins(uae_u16 opc)
+static void execute_ins(uae_u16 opc, uaecptr endpc, uaecptr targetpc)
{
uae_u16 opw1 = (opcode_memory[2] << 8) | (opcode_memory[3] << 0);
uae_u16 opw2 = (opcode_memory[4] << 8) | (opcode_memory[5] << 0);
testing_active = 1;
- if (SPCFLAG_TRACE)
- do_trace();
+ int cnt = feature_loop_mode * 2;
+
+ for (;;) {
+
+ if (SPCFLAG_TRACE)
+ do_trace();
+
+ (*cpufunctbl[opc])(opc);
+
+ if (!test_exception) {
+ if (SPCFLAG_DOTRACE)
+ Exception(9);
+
+ if (cpu_stopped && regs.s == 0 && currprefs.cpu_model <= 68010) {
+ // 68000/68010 undocumented special case:
+ // if STOP clears S-bit and T was not set:
+ // cause privilege violation exception, PC pointing to following instruction.
+ // If T was set before STOP: STOP works as documented.
+ cpu_stopped = 0;
+ Exception(8);
+ }
+ }
+
+ if (regs.pc == endpc || regs.pc == targetpc)
+ break;
+
+ if (test_exception)
+ break;
+
+ if (!valid_address(regs.pc, 2, 0))
+ break;
- (*cpufunctbl[opc])(opc);
+ if (!feature_loop_mode) {
+ wprintf(_T("Test instruction didn't finish in single step in non-loop mode!?\n"));
+ abort();
+ }
- if (!test_exception) {
- if (SPCFLAG_DOTRACE)
- Exception(9);
+ if (cpu_lvl < 2) {
+ opc = get_word_test_prefetch(2);
+ m68k_incpc(2);
+ } else {
+ opc = get_word_test_prefetch(0);
+ m68k_incpc(2);
+ }
- if (cpu_stopped && regs.s == 0 && currprefs.cpu_model <= 68010) {
- // 68000/68010 undocumented special case:
- // if STOP clears S-bit and T was not set:
- // cause privilege violation exception, PC pointing to following instruction.
- // If T was set before STOP: STOP works as documented.
- cpu_stopped = 0;
- Exception(8);
+ cnt--;
+ if (cnt <= 0) {
+ wprintf(_T("Loop mode didn't end!?\n"));
+ abort();
}
}
}
+static uae_u8 *save_exception(uae_u8 *p)
+{
+ uae_u8 size = 0;
+ *p++ = size;
+ return p;
+}
+
static const TCHAR *sizes[] = { _T("B"), _T("W"), _T("L") };
static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, int opcodesize, int fpuopcode)
if (quick)
break;
+ if (feature_loop_mode) {
+ regs.regs[feature_loop_mode_register] &= 0xffff0000;
+ regs.regs[feature_loop_mode_register] |= feature_loop_mode - 1;
+ cur_registers[feature_loop_mode_register] = regs.regs[feature_loop_mode_register];
+ }
+
for (int i = 0; i < MAX_REGISTERS; i++) {
dst = store_reg(dst, CT_DREG + i, 0, cur_registers[i], -1);
regs.regs[i] = cur_registers[i];
)
printf("");
- if (opc != opcode) {
- // source EA modified opcode
- dp = table68k + opc;
- }
+ // if source EA modified opcode
+ dp = table68k + opc;
// create destination addressing mode
if (dp->duse) {
pc += o;
}
+ // if destination EA modified opcode
+ dp = table68k + opc;
+
uae_u8 *bo = opcode_memory + 2;
uae_u16 bopw1 = (bo[0] << 8) | (bo[1] << 0);
uae_u16 bopw2 = (bo[2] << 8) | (bo[3] << 0);
pc += handle_specials_branch(opc, pc, dp, &isconstant_src);
put_word_test(opcode_memory_start, opc);
+
+ // loop mode
+ if (feature_loop_mode) {
+ // dbf dn, opcode_memory_start
+ put_long_test(pc, ((0x51c8 | feature_loop_mode_register) << 16) | ((opcode_memory_start - pc - 2) & 0xffff));
+ pc += 4;
+ }
+
// end word, needed to detect if instruction finished normally when
// running on real hardware.
put_word_test(pc, 0x4afc); // illegal instruction
abort();
}
#endif
+ uaecptr branch_target = 0xffffffff;
int bc = isbranchinst(dp);
if (bc) {
if (bc < 0) {
} else {
// branch target = generate exception
put_word_test(srcaddr, 0x4afc);
+ branch_target = srcaddr;
dst = store_mem(dst, 1);
memcpy(&ahist2, &ahist, sizeof(struct accesshistory) *MAX_ACCESSHIST);
ahcnt2 = ahcnt;
if (regs.sr & 0x2000)
prev_s_cnt++;
- execute_ins(opc);
+ execute_ins(opc, pc - 2, branch_target);
if (regs.s)
s_cnt++;
last_sr = regs.sr;
}
if (regs.pc != last_pc) {
- dst = store_rel(dst, CT_PC, last_pc, regs.pc);
+ dst = store_rel(dst, CT_PC, last_pc, regs.pc, 0);
last_pc = regs.pc;
}
if (currprefs.fpu_model) {
}
}
if (regs.fpiar != last_fpiar) {
- dst = store_rel(dst, CT_FPIAR, last_fpiar, regs.fpiar);
+ dst = store_rel(dst, CT_FPIAR, last_fpiar, regs.fpiar, 0);
last_fpiar = regs.fpiar;
}
if (regs.fpsr != last_fpsr) {
dst = store_mem(dst, 0);
if (test_exception) {
*dst++ = CT_END | test_exception;
+ dst = save_exception(dst);
} else {
*dst++ = CT_END;
}
{
const struct cputbl *tbl = NULL;
TCHAR path[1000];
+ int v;
struct ini_data *ini = ini_load(_T("cputestgen.ini"), false);
if (!ini) {
wprintf(_T("Unsupported CPU model.\n"));
return 0;
}
+
+ currprefs.address_space_24 = 1;
+ addressing_mask = 0x00ffffff;
+ v = 24;
+ ini_getval(ini, INISECTION, _T("cpu_address_space"), &v);
+ if (v == 32) {
+ currprefs.address_space_24 = 0;
+ addressing_mask = 0xffffffff;
+ }
+
currprefs.fpu_model = 0;
currprefs.fpu_mode = 1;
ini_getval(ini, INISECTION, _T("fpu"), &currprefs.fpu_model);
ini_getval(ini, INISECTION, _T("feature_exception3_instruction"), &feature_exception3_instruction);
feature_sr_mask = 0;
ini_getval(ini, INISECTION, _T("feature_sr_mask"), &feature_sr_mask);
+ feature_loop_mode = 0;
+ ini_getval(ini, INISECTION, _T("feature_loop_mode"), &feature_loop_mode);
+ if (feature_loop_mode) {
+ feature_loop_mode_register = 7;
+ }
+
feature_full_extension_format = 0;
if (currprefs.cpu_model > 68000) {
ini_getval(ini, INISECTION, _T("feature_full_extension_format"), &feature_full_extension_format);
pc8r[1] |= 2;
}
}
+
for (int j = 0; j < 2; j++) {
TCHAR *am = NULL;
if (ini_getstring(ini, INISECTION, j ? _T("feature_addressing_modes_dst") : _T("feature_addressing_modes_src"), &am)) {
xorshiftstate = 1;
- int v = 0;
+ v = 0;
ini_getval(ini, INISECTION, _T("test_memory_start"), &v);
if (!v) {
wprintf(_T("test_memory_start is required\n"));
test_memory_size = v;
test_memory_end = test_memory_start + test_memory_size;
- test_low_memory_start = 0x0000;
- test_low_memory_end = 0x8000;
+ test_low_memory_start = 0xffffffff;
+ test_low_memory_end = 0xffffffff;
v = 0;
if (ini_getval(ini, INISECTION, _T("test_low_memory_start"), &v))
test_low_memory_start = v;
if (ini_getval(ini, INISECTION, _T("test_low_memory_end"), &v))
test_low_memory_end = v;
- test_high_memory_start = 0x00ff8000;
- test_high_memory_end = 0x01000000;
+ test_high_memory_start = 0xffffffff;
+ test_high_memory_end = 0xffffffff;
v = 0;
if (ini_getval(ini, INISECTION, _T("test_high_memory_start"), &v))
test_high_memory_start = v;
TCHAR *lmem_rom_name = NULL;
ini_getstring(ini, INISECTION, _T("low_rom"), &lmem_rom_name);
- if (lmem_rom_name) {
+ if (lmem_rom_name && test_low_memory_start != 0xffffffff) {
if (load_file(NULL, lmem_rom_name, low_memory_temp, 32768, 0)) {
wprintf(_T("Low test memory ROM loaded\n"));
lmem_rom = 1;
TCHAR *hmem_rom_name = NULL;
ini_getstring(ini, INISECTION, _T("high_rom"), &hmem_rom_name);
- if (hmem_rom_name) {
+ if (hmem_rom_name && test_high_memory_start != 0xffffffff) {
if (load_file(NULL, hmem_rom_name, high_memory_temp, 32768, -1)) {
wprintf(_T("High test memory ROM loaded\n"));
hmem_rom = 1;
if (currprefs.cpu_model == 68000) {
tbl = op_smalltbl_90_test_ff;
cpu_lvl = 0;
- addressing_mask = 0x00ffffff;
} else if (currprefs.cpu_model == 68010) {
tbl = op_smalltbl_91_test_ff;
cpu_lvl = 1;
- addressing_mask = 0x00ffffff;
} else if (currprefs.cpu_model == 68020) {
tbl = op_smalltbl_92_test_ff;
cpu_lvl = 2;
- addressing_mask = 0x00ffffff;
} else {
wprintf(_T("Unsupported CPU model.\n"));
abort();
uae_u32 m[2];
};
+// must match asm.S
struct registers
{
uae_u32 regs[16];
uae_u32 pc;
uae_u32 sr;
uae_u32 exc;
+ uae_u32 excframe;
struct fpureg fpuregs[8];
uae_u32 fpiar, fpcr, fpsr;
};
return;
#ifndef _MSC_VER
- if (lmem_rom) {
+ if (lmem_rom > 0) {
if (memcmp(low_memory, low_memory_temp, 32768)) {
printf("Low memory ROM mismatch!\n");
exit(0);
}
}
- if (hmem_rom) {
+ if (hmem_rom > 0) {
if (memcmp(high_memory, high_memory_temp, 32768)) {
printf("High memory ROM mismatch!\n");
exit(0);
}
+static void hexdump(uae_u8 *p, int len)
+{
+ for (int i = 0; i < len; i++) {
+ if (i > 0)
+ *outbp++ = '.';
+ sprintf(outbp, "%02x", p[i]);
+ outbp += strlen(outbp);
+ }
+ *outbp++ = '\n';
+}
+
+static void validate_exception(struct registers *regs, uae_u8 *p)
+{
+ int exclen = 0;
+ uae_u8 excmatch[32];
+ uae_u8 *sp = (uae_u8*)regs->excframe;
+ uae_u32 v;
+ uae_u8 excdatalen = *p++;
+
+ if (!excdatalen)
+ return;
+
+ if (cpu_lvl == 0) {
+ if (regs->exc == 3) {
+ // status (with undocumented opcode part)
+ excmatch[0] = opcode_memory[0];
+ excmatch[1] = (opcode_memory[1] & 0xf0) | (*p++);
+ // access address
+ v = opcode_memory_addr;
+ p = restore_rel(p, &v);
+ pl(excmatch + 2, v);
+ p += 4;
+ // opcode
+ excmatch[6] = opcode_memory[0];
+ excmatch[7] = opcode_memory[1];
+ // sr
+ excmatch[8] = regs->sr >> 8;
+ excmatch[9] = regs->sr;
+ // pc
+ pl(excmatch + 10, regs->pc);
+ exclen = 14;
+ }
+ } else {
+ // sr
+ excmatch[0] = regs->sr >> 8;
+ excmatch[1] = regs->sr;
+ pl(excmatch + 2, regs->pc);
+ }
+ if (exclen == 0)
+ return;
+ if (memcmp(excmatch, sp, exclen)) {
+ strcpy(outbp, "Exception stack frame mismatch");
+ outbp += strlen(outbp);
+ hexdump(sp, exclen);
+ hexdump(excmatch, exclen);
+ }
+}
+
static uae_u8 *validate_test(uae_u8 *p, int ignore_errors, int ignore_sr)
{
uae_u8 regs_changed[16] = { 0 };
}
break;
}
+ if (exc) {
+ uae_u8 excdatalen = *p++;
+ if (exc == cpuexc && excdatalen) {
+ validate_exception(&test_regs, p);
+ }
+ p += excdatalen;
+ }
if (exc != cpuexc) {
addinfo();
if (dooutput) {
}
}
if (!ignore_errors) {
- for (int i = 0; i < 16; i++) {
- if (regs_changed[i]) {
+ if (!ignore_sr) {
+ for (int i = 0; i < 16; i++) {
+ if (regs_changed[i]) {
+ addinfo();
+ if (dooutput) {
+ sprintf(outbp, "%c%d: modified %08lx -> %08lx but expected no modifications\n", i < 8 ? 'D' : 'A', i & 7, last_registers.regs[i], test_regs.regs[i]);
+ outbp += strlen(outbp);
+ }
+ errors++;
+ }
+ }
+ if (sr_changed) {
addinfo();
if (dooutput) {
- sprintf(outbp, "%c%d: modified %08lx -> %08lx but expected no modifications\n", i < 8 ? 'D' : 'A', i & 7, last_registers.regs[i], test_regs.regs[i]);
+ sprintf(outbp, "SR: modified %04x -> %04x but expected no modifications\n", last_registers.sr, test_regs.sr);
outbp += strlen(outbp);
}
errors++;
}
}
- if (sr_changed) {
- addinfo();
- if (dooutput) {
- sprintf(outbp, "SR: modified %04x -> %04x but expected no modifications\n", last_registers.sr, test_regs.sr);
- outbp += strlen(outbp);
- }
- errors++;
- }
for (int i = 0; i < 8; i++) {
if (regs_fpuchanged[i]) {
addinfo();
fread(data, 1, 4, f);
starttimeid = gl(data);
fread(data, 1, 4, f);
- hmem_rom = gl(data) >> 16;
- lmem_rom = gl(data) & 65535;
+ hmem_rom = (uae_s16)(gl(data) >> 16);
+ lmem_rom = (uae_s16)(gl(data) & 65535);
fread(data, 1, 4, f);
test_memory_addr = gl(data);
fread(data, 1, 4, f);