#define MAX_REGISTERS 16
-static uae_u32 registers[] =
-{
- 0x00000010,
- 0x00000000,
- 0xffffffff,
- 0xffffff00,
- 0xffff0000,
- 0x80008080,
- 0x7fff7fff,
- 0xaaaaaaaa,
-
- 0x00000000,
- 0x00000080,
- 0x00008000,
- 0x00007fff,
- 0xfffffffe,
- 0xffffff00,
- 0x00000000, // replaced with opcode memory
- 0x00000000 // replaced with stack
-};
static floatx80 fpuregisters[8];
static uae_u32 fpu_fpiar, fpu_fpcr, fpu_fpsr;
static int feature_loop_mode_68010 = 0;
static int feature_full_extension_format = 0;
static int feature_test_rounds = 2;
+static int feature_test_rounds_opcode = 0;
static int feature_flag_mode = 0;
static int feature_usp = 0;
static int feature_exception_vectors = 0;
static int test_exception_opcode;
static uae_u32 trace_store_pc;
static uae_u16 trace_store_sr;
+static int generate_address_mode;
static uae_u8 imm8_cnt;
static uae_u16 imm16_cnt;
static uae_u32 imm32_cnt;
static uae_u32 immabsl_cnt;
+static uae_u32 specials_cnt;
static uae_u32 addressing_mask;
static int opcodecnt;
static int cpu_stopped;
#define OPCODE_AREA 32
#define BRANCHTARGET_AREA 4
-static bool valid_address(uaecptr addr, int size, int w)
+static bool valid_address(uaecptr addr, int size, int rwp)
{
+ int w = rwp == 2;
addr &= addressing_mask;
size--;
if (low_memory_size != 0xffffffff && addr + size < low_memory_size) {
if (addr < test_low_memory_start || test_low_memory_start == 0xffffffff)
goto oob;
// exception vectors needed during tests
- if ((addr + size >= 0x08 && addr < 0x30 || (addr + size >= 0x80 && addr < 0xc0)) && regs.vbr == 0)
+ if ((addr + size >= 0x08 && addr < 0x30 || (addr + size >= 0x80 && addr < 0xc0)) && currprefs.cpu_model == 68000)
goto oob;
if (addr + size >= test_low_memory_end)
goto oob;
if (addr >= opcode_memory_start && addr + size < opcode_memory_start + OPCODE_AREA)
goto oob;
}
+ // don't read data from our test instruction or nop/illegal words. Prefetches allowed.
+ if (testing_active && (rwp & 1)) {
+ if (addr >= opcode_memory_start && addr + size < opcode_memory_start + OPCODE_AREA)
+ goto oob;
+ }
test_memory_accessed = w ? -1 : 1;
return 1;
}
}
-static uae_u8 *get_addr(uaecptr addr, int size, int w)
+static uae_u8 *get_addr(uaecptr addr, int size, int rwp)
{
// allow debug output to read memory even if oob condition
- if (w >= 0 && out_of_test_space)
+ if (rwp >= 0 && out_of_test_space)
goto oob;
- if (!valid_address(addr, 1, w))
+ if (!valid_address(addr, 1, rwp))
goto oob;
if (size > 1) {
- if (!valid_address(addr + size - 1, 1, w))
+ if (!valid_address(addr + size - 1, 1, rwp))
goto oob;
}
addr &= addressing_mask;
return test_memory + (addr - test_memory_start);
}
oob:
- if (w >= 0) {
+ if (rwp >= 0) {
if (!out_of_test_space) {
out_of_test_space = true;
out_of_test_space_addr = addr;
static uae_u8 get_ibyte_test(uaecptr addr)
{
check_bus_error(addr, 0, regs.s ? 5 : 1);
- uae_u8 *p = get_addr(addr, 1, 0);
+ uae_u8 *p = get_addr(addr, 1, 4);
add_memory_cycles(1);
return *p;
}
if (addr & 1) {
return (get_ibyte_test(addr + 0) << 8) | (get_ibyte_test(addr + 1) << 0);
} else {
- uae_u8 *p = get_addr(addr, 2, 0);
+ uae_u8 *p = get_addr(addr, 2, 4);
add_memory_cycles(1);
return (p[0] << 8) | (p[1]);
}
if (!testing_active && is_nowrite_address(addr, 1))
return;
check_bus_error(addr, 1, regs.s ? 5 : 1);
- uae_u8 *p = get_addr(addr, 1, 1);
+ uae_u8 *p = get_addr(addr, 1, 2);
if (!out_of_test_space && !noaccesshistory && !hardware_bus_error_fake) {
previoussame(addr, sz_byte);
if (ahcnt_current >= MAX_ACCESSHIST) {
put_byte_test(addr + 0, v >> 8);
put_byte_test(addr + 1, v >> 0);
} else {
- uae_u8 *p = get_addr(addr, 2, 1);
+ uae_u8 *p = get_addr(addr, 2, 2);
if (!out_of_test_space && !noaccesshistory && !hardware_bus_error_fake) {
previoussame(addr, sz_word);
if (ahcnt_current >= MAX_ACCESSHIST) {
put_word_test(addr + 0, v >> 16);
put_word_test(addr + 2, v >> 0);
} else {
- uae_u8 *p = get_addr(addr, 4, 1);
+ uae_u8 *p = get_addr(addr, 4, 2);
if (!out_of_test_space && !noaccesshistory && !hardware_bus_error_fake) {
previoussame(addr, sz_long);
if (ahcnt_current >= MAX_ACCESSHIST) {
uae_u32 get_byte_test(uaecptr addr)
{
check_bus_error(addr, 0, regs.s ? 5 : 1);
- uae_u8 *p = get_addr(addr, 1, 0);
+ uae_u8 *p = get_addr(addr, 1, 1);
read_buffer_prev = regs.read_buffer;
regs.read_buffer &= 0xff00;
regs.read_buffer |= *p;
if (addr & 1) {
v = (get_byte_test(addr + 0) << 8) | (get_byte_test(addr + 1) << 0);
} else {
- uae_u8 *p = get_addr(addr, 2, 0);
+ uae_u8 *p = get_addr(addr, 2, 1);
v = (p[0] << 8) | (p[1]);
}
read_buffer_prev = regs.read_buffer;
uae_u16 v1 = get_word_test(addr + 2);
v = (v0 << 16) | (v1 << 0);
} else {
- uae_u8 *p = get_addr(addr, 4, 0);
+ uae_u8 *p = get_addr(addr, 4, 1);
v = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]);
add_memory_cycles(2);
}
return (uae_u8)xorshift32();
}
+static uae_u32 registers[] =
+{
+ 0x00000010, // 0
+ 0x00000000, // 1
+ 0xffffffff, // 2
+ 0xffffff00, // 3
+ 0xffff0000, // 4
+ 0x80008080, // 5
+ 0x00010101, // 6
+ 0xaaaaaaaa, // 7
+
+ 0x00000000, // 8
+ 0x00000078, // 9
+ 0x00007ff0, // 10
+ 0x00007fff, // 11
+ 0xfffffffe, // 12
+ 0xffffff00, // 13
+ 0x00000000, // 14 replaced with opcode memory
+ 0x00000000 // 15 replaced with stack
+};
+static int regcnts[16];
+
+static bool regchange(int reg, uae_u32 *regs)
+{
+ int regcnt = regcnts[reg];
+ uae_u32 v = regs[reg];
+
+ if (generate_address_mode && reg >= 8)
+ return false;
+
+ switch (reg)
+ {
+ case 0:
+ v += 0x12;
+ break;
+ case 1:
+ return false;
+ case 2:
+ if (regcnt) {
+ v ^= 1 << ((regcnt - 1) & 31);
+ }
+ v ^= 0x80008080;
+ v ^= 1 << (regcnt & 31);
+ break;
+ case 3:
+ if (regcnt) {
+ v ^= 1 << ((regcnt - 1) & 31);
+ }
+ v = (v >> 2) | (v << 30);
+ v ^= 1 << (regcnt & 31);
+ break;
+ case 4:
+ if (regcnt) {
+ v ^= 1 << ((regcnt - 1) & 31);
+ }
+ v &= 0x7fffff7f;
+ v = (v >> 2) | (v << 30);
+ v |= 0x80000080;
+ v ^= 1 << (regcnt & 31);
+ break;
+ case 5:
+ v ^= 0x80008080;
+ v += 0x00010101;
+ break;
+ case 6:
+ v = ((((v & 0xff) << 1) | ((v & 0xff) >> 7)) & 0xff) |
+ ((((v & 0xff00) << 1) | ((v & 0xff00) >> 7)) & 0xff00) |
+ ((((v & 0xffff0000) << 1) | ((v & 0xffff0000) >> 15)) & 0xffff0000);
+ break;
+ case 7:
+ v = rand32();
+ break;
+ case 8:
+ return false;
+ case 9:
+ v += 1;
+ v &= 0xff;
+ if (v < 0x70)
+ v = 0x90;
+ if (v >= 0x90) {
+ v -= 0x90 - 0x70;
+ }
+ break;
+ case 10:
+ v += 0x13;
+ v &= 0xffff;
+ if (v < 0x7fe0)
+ v = 0x8020;
+ if (v >= 0x8020) {
+ v -= 0x8020 - 0x7fe0;
+ }
+ break;
+ case 11:
+ v ^= 0x8000;
+ break;
+ case 12:
+ v ^= 0x80000000;
+ v = (v & 0xffffff00) | ((v + 0x14) & 0xff);
+ break;
+ case 13:
+ v = (v >> 2) | (v << 30);
+ break;
+ default:
+ return false;
+ }
+ regcnts[reg]++;
+ regs[reg] = v;
+ return true;
+}
+
static void fill_memory_buffer(uae_u8 *p, int size)
{
for (int i = 0; i < size; i++) {
}
// generate mostly random EA.
-static int create_ea_random(uae_u16 *opcodep, uaecptr pc, int mode, int reg, struct instr *dp, int *isconstant, int srcdst, int fpuopcode, int opcodesize, uae_u32 *eap)
+static int create_ea_random(uae_u16 *opcodep, uaecptr pc, int mode, int reg, struct instr *dp, int *isconstant, int srcdst, int fpuopcode, int opcodesize, uae_u32 *eap, int *regused)
{
uaecptr old_pc = pc;
uae_u16 opcode = *opcodep;
switch (mode)
{
case Dreg:
+ *regused = reg;
if (reg == feature_loop_mode_register) {
if (((dp->sduse & 0x20) && !srcdst) || ((dp->sduse & 0x02) && srcdst)) {
+ int newreg = (reg + 1) & 7;
int pos = srcdst ? dp->dpos : dp->spos;
opcode &= ~(7 << pos);
- opcode |= ((reg + 1) & 7) << pos;
+ opcode |= newreg << pos;
+ *regused = newreg;
}
}
break;
case Areg:
case Aind:
case Aipi:
+ *regused = reg + 8;
*eap = cur_registers[reg + 8];
break;
case Apdi:
+ *regused = reg + 8;
*eap = cur_registers[reg + 8] - (1 << dp->size);
break;
case Ad16:
for (;;) {
v = rand16();
addr = cur_registers[reg + 8] + (uae_s16)v;
+ *regused = reg + 8;
if (analyze_address(dp, srcdst, addr))
break;
maxcnt--;
if (currprefs.cpu_model >= 68020)
v &= ~0x100;
addr = mode == PC8r ? pc + 2 - 2 : cur_registers[reg + 8];
+ *regused = v >> 12;
add = cur_registers[v >> 12];
if (v & 0x0800) {
// L
}
break;
}
+ *regused = v >> 12;
put_word_test(pc, v);
uaecptr pce = pc;
pc += 2;
static int ea_exact_cnt;
// generate exact EA (for bus error test)
-static int create_ea_exact(uae_u16 *opcodep, uaecptr pc, int mode, int reg, struct instr *dp, int *isconstant, int srcdst, int fpuopcode, int opcodesize, uae_u32 *eap)
+static int create_ea_exact(uae_u16 *opcodep, uaecptr pc, int mode, int reg, struct instr *dp, int *isconstant, int srcdst, int fpuopcode, int opcodesize, uae_u32 *eap, int *regused)
{
uae_u32 target = target_ea[srcdst];
ea_exact_cnt++;
switch (mode)
{
- // always allow modes that don't have EA
- case Areg:
+ // always allow modes that don't have EA
case Dreg:
+ *regused = reg;
+ return 0;
+ case Areg:
+ *regused = reg + 8;
return 0;
case Aind:
case Aipi:
{
if (cur_registers[reg + 8] == target) {
*eap = target;
+ *regused = reg + 8;
return 0;
}
return -2;
{
if (cur_registers[reg + 8] == target + (1 << dp->size)) {
*eap = target;
+ *regused = reg + 8;
return 0;
}
return -2;
if (target <= v + 0x7ffe && (target >= v - 0x8000 || v < 0x8000)) {
put_word_test(pc, target - v);
*eap = target;
+ *regused = reg + 8;
return 2;
}
return -2;
if (target <= addr + 0x7f && target >= addr - 0x80) {
put_word_test(pc, (rn << 12) | 0x0800 | ((target - addr) & 0xff));
*eap = target;
+ *regused = rn;
return 2;
}
} else {
if (target <= addr + 0x7f && target >= addr - 0x80) {
put_word_test(pc, (rn << 12) | 0x0000 | ((target - addr) & 0xff));
*eap = target;
+ *regused = rn;
return 2;
}
}
if (target <= addr + 0x7f && target >= addr - 0x80) {
put_word_test(pc, (rn << 12) | 0x0800 | ((target - addr) & 0xff));
*eap = target;
+ *regused = rn;
return 2;
}
} else {
if (target <= addr + 0x7f && target >= addr - 0x80) {
put_word_test(pc, (rn << 12) | 0x0000 | ((target - addr) & 0xff));
*eap = target;
+ *regused = rn;
return 2;
}
}
return -2;
}
-static int create_ea(uae_u16 *opcodep, uaecptr pc, int mode, int reg, struct instr *dp, int *isconstant, int srcdst, int fpuopcode, int opcodesize, uae_u32 *ea)
+static int create_ea(uae_u16 *opcodep, uaecptr pc, int mode, int reg, struct instr *dp, int *isconstant, int srcdst, int fpuopcode, int opcodesize, uae_u32 *ea, int *regused)
{
int am = mode >= imm ? imm : mode;
return -1;
if (target_ea[srcdst] == 0xffffffff) {
- return create_ea_random(opcodep, pc, mode, reg, dp, isconstant, srcdst, fpuopcode, opcodesize, ea);
+ return create_ea_random(opcodep, pc, mode, reg, dp, isconstant, srcdst, fpuopcode, opcodesize, ea, regused);
} else {
- return create_ea_exact(opcodep, pc, mode, reg, dp, isconstant, srcdst, fpuopcode, opcodesize, ea);
+ return create_ea_exact(opcodep, pc, mode, reg, dp, isconstant, srcdst, fpuopcode, opcodesize, ea, regused);
}
}
return 0;
}
-static uaecptr handle_specials_extra(uae_u16 opcode, uaecptr pc, struct instr *dp)
+static uaecptr handle_specials_extra(uae_u16 opcode, uaecptr pc, struct instr *dp, int *regused)
{
// CAS undocumented (marked as zero in document) fields do something weird, for example
// setting bit 9 will make "Du" address register but results are not correct.
// so lets make sure unused zero bits are zeroed.
+ specials_cnt++;
switch (dp->mnemo)
{
case i_CAS:
if (extra != extra2) {
put_word_test(opcode_memory_start + 2, extra);
}
+ if (specials_cnt & 1) {
+ *regused = extra & 7;
+ } else {
+ *regused = (extra >> 6) & 7;
+ }
break;
}
case i_CAS2:
if (extra != extra2) {
put_word_test(opcode_memory_start + 4, extra);
}
+ switch (specials_cnt & 7)
+ {
+ case 0:
+ case 6:
+ *regused = extra >> 12;
+ break;
+ case 1:
+ *regused = (extra >> 6) & 7;
+ break;
+ case 2:
+ *regused = (extra >> 0) & 7;
+ break;
+ case 7:
+ case 3:
+ *regused = extra2 >> 12;
+ break;
+ case 4:
+ *regused = (extra2 >> 6) & 7;
+ break;
+ case 5:
+ *regused = (extra2 >> 0) & 7;
+ break;
+ }
break;
}
case i_CHK2: // also CMP2
if (extra != extra2) {
put_word_test(opcode_memory_start + 2, extra);
}
+ *regused = extra >> 12;
+ break;
+ }
+ case i_BFSET:
+ case i_BFTST:
+ case i_BFCLR:
+ case i_BFCHG:
+ {
+ uae_u16 extra = get_word_test(opcode_memory_start + 2);
+ if ((extra & 0x0800) && (extra & 0x0020)) {
+ if (specials_cnt & 1) {
+ *regused = (extra >> 6) & 7;
+ } else {
+ *regused = (extra >> 0) & 7;
+ }
+ } else if (extra & 0x0800) {
+ *regused = (extra >> 6) & 7;
+ } else if (extra & 0x0020) {
+ *regused = (extra >> 0) & 7;
+ }
break;
}
case i_BFINS:
case i_BFEXTS:
case i_BFEXTU:
{
+ uae_u16 extra = get_word_test(opcode_memory_start + 2);
if (cpu_lvl >= 4) {
// 68040+ and extra word bit 15 not zero (hidden A/D field):
// REGISTER field becomes address register in some internal
// operations, results are also wrong. So clear it here..
- uae_u16 extra = get_word_test(opcode_memory_start + 2);
if (extra & 0x8000) {
extra &= ~0x8000;
put_word_test(opcode_memory_start + 2, extra);
}
}
+ if((extra & 0x0800) || (extra & 0x0020)) {
+ if ((extra & 0x0800) && (specials_cnt & 3) == 0) {
+ *regused = (extra >> 6) & 7;
+ } else if ((extra & 0x0020) && (specials_cnt & 3) == 1) {
+ *regused = (extra >> 0) & 7;
+ } else {
+ *regused = (extra >> 12) & 7;
+ }
+ } else {
+ *regused = (extra >> 12) & 7;
+ }
break;
}
case i_DIVL:
case i_MULL:
{
+ uae_u16 extra = get_word_test(opcode_memory_start + 2);
if (cpu_lvl >= 4) {
// same as BF instructions but also other bits need clearing
// or results are unexplained..
- uae_u16 extra = get_word_test(opcode_memory_start + 2);
if (extra & 0x83f8) {
extra &= ~0x83f8;
put_word_test(opcode_memory_start + 2, extra);
}
}
+ if (specials_cnt & 1) {
+ *regused = (extra >> 12) & 7;
+ } else {
+ *regused = extra & 7;
+ }
break;
}
}
out[i] = i - 4;
}
out[7] = target_address - opcode_memory_start;
+ generate_address_mode = 1;
}
static const TCHAR *sizes[] = { _T("B"), _T("W"), _T("L") };
target_ea_src_cnt = 0;
target_ea_dst_cnt = 0;
target_ea_opcode_cnt = 0;
+ generate_address_mode = 0;
// 1.0
fpuregisters[0].high = 0x3fff;
uae_u32 branch_target_data_original = 0x4afc4e71;
uae_u32 branch_target_data = branch_target_data_original;
- out_of_test_space = 0;
+ int srcregused = -1;
+ int dstregused = -1;
+
+ out_of_test_space = 0;
noaccesshistory = 0;
hardware_bus_error_fake = 0;
hardware_bus_error = 0;
// create source addressing mode
if (dp->suse) {
- int o = create_ea(&opc, pc, dp->smode, dp->sreg, dp, &isconstant_src, 0, fpuopcode, opcodesize, &srcea);
+ int o = create_ea(&opc, pc, dp->smode, dp->sreg, dp, &isconstant_src, 0, fpuopcode, opcodesize, &srcea, &srcregused);
if (o < 0) {
memcpy(opcode_memory, oldcodebytes, sizeof(oldcodebytes));
if (o == -1)
// create destination addressing mode
if (dp->duse) {
- int o = create_ea(&opc, pc, dp->dmode, dp->dreg, dp, &isconstant_dst, 1, fpuopcode, opcodesize, &dstea);
+ int o = create_ea(&opc, pc, dp->dmode, dp->dreg, dp, &isconstant_dst, 1, fpuopcode, opcodesize, &dstea, &dstregused);
if (o < 0) {
memcpy(opcode_memory, oldcodebytes, sizeof(oldcodebytes));
if (o == -1)
}
- pc = handle_specials_extra(opc, pc, dp);
+ pc = handle_specials_extra(opc, pc, dp, &srcregused);
// if destination EA modified opcode
dp = table68k + opc;
uae_u32 originalendopcode = 0x4afc4e71;
uae_u32 endopcode = originalendopcode;
uae_u32 actualendpc = pc;
+
uae_u32 instructionendpc = pc;
if (isconstant_src < 0 || isconstant_dst < 0) {
srcaddr = get_long_test(regs.regs[15] + stackoffset);
}
// branch target is not accessible? skip.
- if (((srcaddr >= cur_registers[15] - 16 && srcaddr <= cur_registers[15] + 16) && dp->mnemo != i_RTE) || ((srcaddr & 1) && !feature_exception3_instruction && feature_usp < 2)) {
+ if ((((srcaddr & addressing_mask) >= cur_registers[15] - 16 && (srcaddr & addressing_mask) <= cur_registers[15] + 16) && dp->mnemo != i_RTE) || ((srcaddr & 1) && !feature_exception3_instruction && feature_usp < 2)) {
// lets not jump directly to stack..
if (verbose) {
if (srcaddr & 1)
continue;
}
testing_active = 1;
- if (!valid_address(srcaddr, 2, 1) || srcaddr + 2 == opcode_memory_start) {
+ if (!valid_address(srcaddr, 2, 1) || ((srcaddr + 2) & addressing_mask) == opcode_memory_start) {
if (verbose) {
wprintf(_T(" Branch target inaccessible (%08x)\n"), srcaddr);
}
wprintf(_T(" Branch instruction target fault\n"));
abort();
}
- if (branch_target_pc < safe_memory_start || branch_target_pc >= safe_memory_end) {
+ if (safe_memory_start != 0xffffffff && (branch_target_pc & addressing_mask) < safe_memory_start || (branch_target_pc & addressing_mask) >= safe_memory_end) {
if ((pcaddr[0] != 0x4a && pcaddr[1] != 0xfc) && (pcaddr[0] != 0x4e && pcaddr[1] != 0x71)) {
wprintf(_T(" Branch instruction target fault\n"));
abort();
} else {
full_format_cnt++;
data_saved = 1;
+ // if test used data register as a source: modify it
+ if (srcregused >= 0) {
+ uae_u32 prev = cur_registers[srcregused];
+ if (regchange(srcregused, cur_registers)) {
+ dst = store_reg(dst, CT_DREG + srcregused, prev, cur_registers[srcregused], -1);
+ }
+ }
+ if (dstregused >= 0 && srcregused != dstregused) {
+ uae_u32 prev = cur_registers[dstregused];
+ if (regchange(dstregused, cur_registers)) {
+ dst = store_reg(dst, CT_DREG + dstregused, prev, cur_registers[dstregused], -1);
+ }
+ }
}
if (verbose) {
wprintf(_T(" OK=%d OB=%d S=%d/%d T=%d STP=%d"), ok, exception_array[0], prev_s_cnt, s_cnt, t_cnt, cnt_stopped);
}
dst = storage_buffer;
- if (opcodecnt == 1 && target_address == 0xffffffff && target_opcode_address == 0xffffffff && target_usp_address == 0xffffffff)
+ if (opcodecnt == 1 && target_address == 0xffffffff && target_opcode_address == 0xffffffff && target_usp_address == 0xffffffff && subtest_count >= feature_test_rounds_opcode)
break;
if (lookup->mnemo == i_ILLG)
break;
}
generate_target_registers(target_address, cur_registers);
} else {
- // randomize registers
- for (int i = 0; i < 16 - 2; i++) {
- cur_registers[i] = rand32();
- }
nextround = true;
}
if (nextround) {
rounds--;
- if (rounds < 0)
- break;
+ if (rounds < 0) {
+ if (subtest_count >= feature_test_rounds_opcode)
+ break;
+ rounds = 1;
+ }
}
cur_registers[0] &= 0xffff;
feature_test_rounds = 2;
ini_getvalx(ini, sections, _T("test_rounds"), &feature_test_rounds);
+ feature_test_rounds_opcode = 0;
+ ini_getvalx(ini, sections, _T("min_opcode_test_rounds"), &feature_test_rounds_opcode);
+
feature_instruction_size = NULL;
ini_getstringx(ini, sections, _T("feature_instruction_size"), &feature_instruction_size);
}
}
-
UAE 680x0 CPU Tester
I finally wrote utility (This was my "Summer 2019" project) that can be used to verify operation of for example software emulated or FPGA 680x0 CPUs.
-It is based on UAE CPU core (gencpu generated special test core). All the CPU logic comes from UAE CPU core.
+Tester is based on UAE CPU core (gencpu generated special test core). All the CPU logic comes from UAE CPU core.
Verifies:
- If instruction generated privilege violation exception, extra test round is run in supervisor mode.
- Optionally can do any combination of T0, T1, S and M -bit SR register extra test rounds.
- Every opcode value is tested. Total number of tests per opcode depends on available addressing modes etc. It can be hundreds of thousands or even millions..
-- Optinnally can be used to fully validate address and bus errors. Bus error testing requires extra hardware/logic.
+- Optionally can be used to fully validate address and bus errors. Bus error testing requires extra hardware/logic.
Test generation details:
-If normal mode: Instruction's effective address is randomized. It is accepted if it points to any of 3 test memory regions. If it points outside of test memory, it will be re-randomized few times. Test will be skipped if current EA makes it impossible to point to any of 3 test regions.
+If normal mode: instruction's effective address is randomized. It is accepted if it points to any of 3 test memory regions. If it points outside of test memory, it will be re-randomized few times. Test will be skipped if current EA makes it impossible to point to any of 3 test regions.
If 68000/68010 and address error testing is enabled: 2 extra test rounds are generated, one with even and another with odd EAs to test and verify address errors.
If target EA mode: instruction's effective address always points to configured target address(es). Very useful when testing address or bus errors.
Notes and limitations:
-- Test generator is very brute force based, it should be more intelligent.. Now has optional target src/dst/opcode modes for better bus/address error testing.
+- Test generator was originally very brute force based, it should be more intelligent.. Now has optional target src/dst/opcode modes for better bus/address error testing.
- Bus and address error testing is optional, if disabled, generated tests never cause bus/address errors.
- RTE test only tests stack frame types 0 and 2 (if 68020+)
- All tests that would halt or reset the CPU are skipped (RESET in supervisor mode, STOP parameter that would stop the CPU etc)
- Undefined flags (for example DIV and CHK or 68000/010 bus address error) are also verified. It probably would be good idea to optionally filter them out.
- FPU testing is not yet fully implemented.
- TAS test will return wrong results if test RAM region is not fully TAS read-modify-write special memory access compatible.
+- if 24-bit address space and high ram is enabled, tester can generate word or long accesses that wrap around. (For example: move.l $fffffe,d0)
Tester compatibility (integer instructions only):
68010+:
- MOVEC: Most control registers tested: Write all ones, write all zeros, read it back, restore original value. 68040+ TC/TT registers enable bit is always zero.
-- RTE: long frames with undefined fields are skipped. Basic frame types 0 and 2 are verified, also unsupported frame types are tested, error is reported if CPU does not generate frame exception.
+- RTE: address/bus error undefined fields are skipped. Basic frame types 0, 2 and 8 are verified, also unsupported frame types are tested, error is reported if CPU does not generate frame exception.
- 68020+ undefined addressing mode bit combinations are not tested.
All models:
- buildm68k first (already built if UAE core was previously compiled)
- gencpu with CPU_TEST=1 define. This creates cpuemu_x_test.cpp files (x=90-94), cpustbl_test.cpp and cputbl_test.h
- build cputestgen project.
-- build native Amiga project (cputest directory). Assembly files probably only compiles with Bebbo's GCC.
+- build native Amiga project (cputest directory). Assembly files probably only compile with Bebbo's GCC.
More CPU details in WinUAE changelog.
Test generator quick instructions:
-Update cputestgen.ini to match your CPU model, memory settings etc.
+Update cputestgen.ini to match your CPU model, memory settings etc. Enable (enabled=1) preset test set, for example 68000 Basic test is good starting point.
"Low memory" = memory accessible using absolute word addressing mode, positive value (0x0000 to 0x7fff). Can be larger.
"High memory" = memory accessible using absolute word addressing mode, negative value (0xFFF8000 to 0xFFFFFFFF)
Copy all memory dat files, test executable compiled for target platform (currently only Amiga is supported) and data/<cpu model> contents to target system, keeping original directory structure.
-cputest all = run all tests, in alphabetical order. Stops when mismatch is detected.
-cputest tst.b = run tst.b tests only
-cputest all tst.b = run tst.b, then tst.w and so on in alphabetical order until end or mismatch is detected.
+cputest basic/all = run all tests, in alphabetical order. Stops when mismatch is detected. (Assuming 68000 Basic test set)
+cputest basic/tst.b = run tst.b tests only
+cputest basic/all tst.b = run tst.b, then tst.w and so on in alphabetical order until end or mismatch is detected.
If mismatch is detected, opcode word(s), instruction disassembly, registers before and after and reason message is shown on screen. If difference is in exception stack frame, both expected and returned stack frame is shown in hexadecimal.
Change log:
+15.03.2020
+
+- Test coverage improved: If test uses data or address register as a source or destination, register gets modified after each test. Each register has different modification logic. (Some simply toggle few bits, some shift data etc..). Previously registers were static during single test round and start of each new round randomized register contents.
+- 68020+ addressing mode test sets improved.
+
+Only test generator was updated. Data structures or m68k tester has not been changed.
+
16.02.2020
- 68000 prefetch bus error BTST Dn,#x, NBCD.B and LSLW fix. All prefetch bus error tests verified.