// large enough for RTD
#define STACK_SIZE (0x8000 + 8)
#define RESERVED_SUPERSTACK 1024
+// space between superstack and USP
+#define RESERVED_USERSTACK_EXTRA 64
// space for extra exception, not part of test region
#define EXTRA_RESERVED_SPACE 1024
static uae_u32 high_memory_size = 32768;
static uae_u32 safe_memory_start;
static uae_u32 safe_memory_end;
+static int safe_memory_mode;
+static uae_u32 user_stack_memory, super_stack_memory;
static uae_u8 *low_memory, *high_memory, *test_memory;
static uae_u8 *low_memory_temp, *high_memory_temp, *test_memory_temp;
high_memory_accessed = w ? -1 : 1;
return 1;
}
+ if (addr >= super_stack_memory - RESERVED_SUPERSTACK && addr + size < super_stack_memory) {
+ // allow only instructions that have to access super stack, for example RTE
+ // read-only
+ if (w) {
+ goto oob;
+ }
+ if (testing_active) {
+ if (is_superstack_use_required()) {
+ test_memory_accessed = 1;
+ return 1;
+ }
+ }
+ goto oob;
+ }
if (addr >= test_memory_end && addr + size < test_memory_end + EXTRA_RESERVED_SPACE) {
if (testing_active < 0)
return 1;
}
- if (addr >= test_memory_start && addr + size < test_memory_end - RESERVED_SUPERSTACK) {
+ if (addr >= test_memory_start && addr + size < test_memory_end) {
// make sure we don't modify our test instruction
if (testing_active && w) {
if (addr >= opcode_memory_start && addr + size < opcode_memory_start + OPCODE_AREA)
test_memory_accessed = w ? -1 : 1;
return 1;
}
- if (addr >= test_memory_end - RESERVED_SUPERSTACK && addr + size < test_memory_end) {
- // allow only instructions that have to access super stack, for example RTE
- // read-only
- if (w)
- goto oob;
- if (testing_active) {
- if (is_superstack_use_required()) {
- test_memory_accessed = 1;
- return 1;
- }
- }
- }
oob:
return 0;
}
if (safe_memory_start == 0xffffffff && safe_memory_end == 0xffffffff)
return;
if (addr >= safe_memory_start && addr < safe_memory_end) {
- cpu_bus_error = 1;
+ if ((safe_memory_mode & 1) && !write)
+ cpu_bus_error = 1;
+ if ((safe_memory_mode & 2) && write)
+ cpu_bus_error = 1;
}
}
uae_u32 REGPARAM2 op_illg_1(uae_u32 opcode)
{
- if ((opcode & 0xf000) == 0xf000)
+ if ((opcode & 0xf000) == 0xf000) {
+ if (currprefs.cpu_model == 68030) {
+ // mmu instruction extra check
+ // because mmu checks following word to detect if addressing mode is supported,
+ // we can't test any MMU opcodes without parsing following word. TODO.
+ if ((opcode & 0xfe00) == 0xf000) {
+ test_exception = -1;
+ return 0;
+ }
+ }
test_exception = 11;
- else if ((opcode & 0xf000) == 0xa000)
+ if (privileged_copro_instruction(opcode)) {
+ test_exception = 8;
+ }
+ } else if ((opcode & 0xf000) == 0xa000) {
test_exception = 10;
- else
+ } else {
test_exception = 4;
+ }
doexcstack();
return 0;
}
fwrite(data, 1, 4, f);
pl(data, test_memory_size);
fwrite(data, 1, 4, f);
- pl(data, opcode_memory_start - test_memory_start);
+ pl(data, opcode_memory_start);
fwrite(data, 1, 4, f);
pl(data, (cpu_lvl << 16) | sr_undefined_mask | (addressing_mask == 0xffffffff ? 0x80000000 : 0) | ((feature_flag_mode & 1) << 30) | (feature_min_interrupt_mask << 20));
fwrite(data, 1, 4, f);
fwrite(data, 1, 4, f);
pl(data, safe_memory_end);
fwrite(data, 1, 4, f);
- pl(data, 0);
+ pl(data, user_stack_memory);
fwrite(data, 1, 4, f);
- pl(data, 0);
+ pl(data, super_stack_memory);
fwrite(data, 1, 4, f);
fwrite(inst_name, 1, sizeof(inst_name) - 1, f);
fclose(f);
return pc;
}
+static int ea_state_found[3];
+
+static void reset_ea_state(void)
+{
+ ea_state_found[0] = 0;
+ ea_state_found[1] = 0;
+ ea_state_found[2] = 0;
+}
+
+// attempt to find at least one zero, positive and negative source value
+static int analyze_address(struct instr *dp, int srcdst, uae_u32 addr)
+{
+ uae_u32 v;
+ uae_u32 mask;
+
+ if (srcdst)
+ return 1;
+ if (dp->size == sz_byte) {
+ v = get_byte_test(addr);
+ mask = 0x80;
+ } else if (dp->size == sz_word) {
+ v = get_word_test(addr);
+ mask = 0x8000;
+ } else {
+ v = get_long_test(addr);
+ mask = 0x80000000;
+ }
+ if (out_of_test_space) {
+ out_of_test_space = false;
+ return 0;
+ }
+ if (ea_state_found[0] >= 2 && ea_state_found[1] >= 2 && ea_state_found[2] >= 2)
+ return 1;
+ // zero
+ if (v == 0) {
+ if (ea_state_found[0] >= 2 && (ea_state_found[1] < 2 || ea_state_found[2] < 2))
+ return 0;
+ ea_state_found[0]++;
+ }
+ // negative value
+ if (v & mask) {
+ if (ea_state_found[1] >= 2 && (ea_state_found[0] < 2 || ea_state_found[2] < 2))
+ return 0;
+ ea_state_found[1]++;
+ }
+ // positive value
+ if (v < mask && v > 0) {
+ if (ea_state_found[2] >= 2 && (ea_state_found[0] < 2 || ea_state_found[1] < 2))
+ return 0;
+ ea_state_found[2]++;
+ }
+ return 1;
+}
+
// 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)
{
case Areg:
case Aind:
case Aipi:
+ *eap = cur_registers[reg + 8];
+ break;
case Apdi:
- *eap = 1;
+ *eap = cur_registers[reg + 8] - (1 << dp->size);
break;
case Ad16:
+ {
+ uae_u16 v;
+ uae_u32 addr;
+ int maxcnt = 1000;
+ for (;;) {
+ v = rand16();
+ addr = cur_registers[reg + 8] + (uae_s16)v;
+ if (analyze_address(dp, srcdst, addr))
+ break;
+ maxcnt--;
+ if (maxcnt < 0)
+ break;
+ }
+ put_word_test(pc, v);
+ *isconstant = 16;
+ pc += 2;
+ *eap = addr;
+ break;
+ }
case PC16:
- put_word_test(pc, rand16());
+ {
+ uae_u32 pct = pc + 2 - 2;
+ uae_u16 v;
+ uae_u32 addr;
+ int maxcnt = 1000;
+ for (;;) {
+ v = rand16();
+ addr = pct + (uae_s16)v;
+ if (analyze_address(dp, srcdst, addr))
+ break;
+ maxcnt--;
+ if (maxcnt < 0)
+ break;
+ }
*isconstant = 16;
pc += 2;
*eap = 1;
break;
+ }
case Ad8r:
case PC8r:
{
- uae_u16 v = rand16();
+ uae_u32 addr;
+ uae_u16 v = rand16() & 0x0100;
if (!feature_full_extension_format)
v &= ~0x100;
if (mode == Ad8r) {
v |= 0x100;
}
if (currprefs.cpu_model < 68020 || (v & 0x100) == 0) {
+ // brief format extension
+ uae_u32 add = 0;
+ int maxcnt = 1000;
+ for (;;) {
+ v = rand16();
+ if (currprefs.cpu_model >= 68020)
+ v &= ~0x100;
+ addr = mode == PC8r ? pc + 2 - 2 : cur_registers[reg + 8];
+ add = cur_registers[v >> 12];
+ if (v & 0x0800) {
+ // L
+ addr += add;
+ } else {
+ // W
+ addr += (uae_s16)add;
+ }
+ if (currprefs.cpu_model >= 68020) {
+ add <<= (v >> 9) & 3; // SCALE
+ }
+ addr += (uae_s8)(v & 0xff); // DISPLACEMENT
+ if (analyze_address(dp, srcdst, addr))
+ break;
+ maxcnt--;
+ if (maxcnt < 0)
+ break;
+ }
*isconstant = 16;
put_word_test(pc, v);
pc += 2;
+ *eap = addr;
} else {
// full format extension
// attempt to generate every possible combination,
// one by one.
+ v |= rand16() & ~0x100;
for (;;) {
v &= 0xff00;
v |= full_format_cnt & 0xff;
pc += 2;
}
*isconstant = 32;
+ *eap = 1;
}
- *eap = 1;
break;
}
case absw:
- put_word_test(pc, rand16());
+ {
+ uae_u16 v;
+ for (;;) {
+ v = rand16();
+ if (analyze_address(dp, srcdst, v))
+ break;
+ }
+ put_word_test(pc, v);
*isconstant = 16;
pc += 2;
- *eap = 1;
+ *eap = v >= 0x8000 ? (0xffff0000 | v) : v;
break;
+ }
case absl:
- {
- uae_u32 v = rand32();
+ {
+ uae_u32 v;
+ for (;;) {
+ v = rand32();
if ((immabsl_cnt & 7) == 0) {
- v &= 0x0000ffff;
- } else if ((immabsl_cnt & 7) >= 4) {
+ v &= 0x00007fff;
+ } else if ((immabsl_cnt & 7) == 1) {
+ v &= 0x00007fff;
+ v = 0xffff8000 | v;
+ } else if ((immabsl_cnt & 7) >= 5) {
int offset = 0;
for (;;) {
offset = (uae_s16)rand16();
v = opcode_memory_start + offset;
}
immabsl_cnt++;
- put_long_test(pc, v);
- *isconstant = 32;
- pc += 4;
+ if (analyze_address(dp, srcdst, v))
+ break;
}
- *eap = 1;
+ put_long_test(pc, v);
+ *isconstant = 32;
+ pc += 4;
+ *eap = v;
break;
+ }
case imm:
if (fpuopcode >= 0 && opcodesize < 8) {
pc = putfpuimm(pc, opcodesize, isconstant);
{
// byte immediate but randomly fill also upper byte
uae_u16 v = rand16();
- if ((imm8_cnt & 3) == 0)
+ if ((imm8_cnt & 15) == 0) {
+ v = 0;
+ } else if ((imm8_cnt & 3) == 0) {
v &= 0xff;
+ }
imm8_cnt++;
put_word_test(pc, v);
*isconstant = 16;
}
} else {
uae_u16 v = rand16();
- if ((imm16_cnt & 7) == 0)
+ if ((imm16_cnt & 7) == 0) {
v &= 0x00ff;
- if ((imm16_cnt & 15) == 0)
- v &= 0x000f;
+ } else if ((imm16_cnt & 15) == 0) {
+ v = 0;
+ }
imm16_cnt++;
put_word_test(pc, v);
*isconstant = 16;
{
// long immediate
uae_u32 v = rand32();
- if ((imm32_cnt & 7) == 0) {
+ if ((imm32_cnt & 63) == 0) {
+ v = 0;
+ } else if ((imm32_cnt & 7) == 0) {
v &= 0x0000ffff;
}
imm32_cnt++;
return 0;
}
-static int handle_specials_pack(uae_u16 opcode, uaecptr pc, struct instr *dp, int *isconstant)
+static int handle_specials_misc(uae_u16 opcode, uaecptr pc, struct instr *dp, int *isconstant)
{
// PACK and UNPK has third parameter
if (dp->mnemo == i_PACK || dp->mnemo == i_UNPK) {
put_word_test(pc, v);
*isconstant = 16;
return 2;
+ } else if (dp->mnemo == i_CALLM) {
+ // CALLM has extra parameter
+ uae_u16 v = rand16();
+ put_word_test(pc, v);
+ *isconstant = 16;
+ return 2;
}
return 0;
}
{
uae_u16 opw1 = (opcode_memory[2] << 8) | (opcode_memory[3] << 0);
uae_u16 opw2 = (opcode_memory[4] << 8) | (opcode_memory[5] << 0);
- if (opc == 0x89c2
- //&& opw1 == 0xcf19
+ if (opc == 0xf23d
+ //&& opw1 == 0xee38
//&& opw2 == 0x504e
)
printf("");
break;
if (!feature_loop_mode && !multi_mode) {
- wprintf(_T("Test instruction didn't finish in single step in non-loop mode!?\n"));
+ wprintf(_T(" Test instruction didn't finish in single step in non-loop mode!?\n"));
abort();
}
cnt--;
if (cnt <= 0) {
- wprintf(_T("Loop mode didn't end!?\n"));
+ wprintf(_T(" Loop mode didn't end!?\n"));
abort();
}
}
case i_CINVP:
case i_PLPAR:
case i_PLPAW:
+ case i_CALLM:
+ case i_RTM:
return 1;
}
return 0;
if (size == 3 && !dp->unsized)
continue;
// skip all unsupported instructions if not specifically testing i_ILLG
- if (dp->clev > cpu_lvl && lookup->mnemo != i_ILLG)
- continue;
+ if (lookup->mnemo != i_ILLG) {
+ if (dp->clev > cpu_lvl)
+ continue;
+ if (isunsupported(dp))
+ return;
+ if (isfpp(lookup->mnemo) && !currprefs.fpu_model)
+ return;
+ }
opcodecnt++;
- if (isunsupported(dp))
- return;
- if (isfpp(lookup->mnemo) && !currprefs.fpu_model)
- return;
fpumode = currprefs.fpu_model && isfpp(lookup->mnemo);
}
int count = 0;
registers[8 + 6] = opcode_memory_start - 0x100;
- registers[8 + 7] = test_memory_end - STACK_SIZE;
+ registers[8 + 7] = user_stack_memory;
uae_u32 target_address = 0xffffffff;
target_ea[0] = 0xffffffff;
target_ea[1] = target_ea_bak[1];
target_address = target_address_bak;
+ reset_ea_state();
// retry few times if out of bounds access
int oob_retries = 10;
// if instruction has immediate(s), repeat instruction test multiple times
uae_u8 *ao = opcode_memory + 2;
uae_u16 apw1 = (ao[0] << 8) | (ao[1] << 0);
uae_u16 apw2 = (ao[2] << 8) | (ao[3] << 0);
- if (opc == 0x48a8
- && apw1 == 0x0000
- //&& apw2 == 0xfff0
+ if (opc == 0x4eb1
+ && apw1 == 0xee38
+ //&& apw2 == 0x7479
)
printf("");
// bcc.x
pc += handle_specials_branch(opc, pc, dp, &isconstant_src);
- // pack
- pc += handle_specials_pack(opc, pc, dp, &isconstant_src);
+ // misc
+ pc += handle_specials_misc(opc, pc, dp, &isconstant_src);
put_word_test(opcode_memory_start, opc);
}
regs.sr |= feature_min_interrupt_mask << 8;
regs.usp = regs.regs[8 + 7];
- regs.isp = test_memory_end - 0x80;
+ regs.isp = super_stack_memory - 0x80;
// copy user stack to super stack, for RTE etc support
- memcpy(regs.isp - test_memory_start + test_memory, regs.usp - test_memory_start + test_memory, 0x20);
- regs.msp = test_memory_end;
+ memcpy(test_memory + (regs.isp - test_memory_start), test_memory + (regs.usp - test_memory_start), 0x20);
+ regs.msp = super_stack_memory;
// data size optimization, only store data
// if it is different than in previous round
safe_memory_end = 0xffffffff;
if (ini_getval(ini, INISECTION, _T("feature_safe_memory_size"), &v))
safe_memory_end = safe_memory_start + v;
+ safe_memory_mode = 3;
+ if (ini_getstring(ini, INISECTION, _T("feature_safe_memory_mode"), &vs)) {
+ safe_memory_mode = 0;
+ if (_totupper(vs[0]) == 'R')
+ safe_memory_mode |= 1;
+ if (_totupper(vs[0]) == 'W')
+ safe_memory_mode |= 2;
+ xfree(vs);
+ }
feature_sr_mask = 0;
ini_getval(ini, INISECTION, _T("feature_sr_mask"), &feature_sr_mask);
return 0;
}
- opcode_memory = test_memory + test_memory_size / 2;
- opcode_memory_start = test_memory_start + test_memory_size / 2;
+ v = 0;
+ if (ini_getval(ini, INISECTION, _T("feature_opcode_memory"), &v)) {
+ opcode_memory_start = v;
+ opcode_memory = test_memory + (opcode_memory_start - test_memory_start);
+ } else {
+ opcode_memory = test_memory + test_memory_size / 2;
+ opcode_memory_start = test_memory_start + test_memory_size / 2;
+ }
+ if (opcode_memory_start < opcode_memory_start || opcode_memory_start > test_memory_start + test_memory_size - 256) {
+ wprintf(_T("Opcode memory out of bounds\n"));
+ return 0;
+ }
+ if (ini_getval(ini, INISECTION, _T("feature_stack_memory"), &v)) {
+ super_stack_memory = v;
+ user_stack_memory = super_stack_memory - (RESERVED_SUPERSTACK + RESERVED_USERSTACK_EXTRA);
+ } else {
+ super_stack_memory = test_memory_end;
+ user_stack_memory = test_memory_end - (RESERVED_SUPERSTACK + RESERVED_USERSTACK_EXTRA);
+ }
low_memory_size = test_low_memory_end;
if (low_memory_size < 0x8000)
static uae_u32 test_memory_size;
static uae_u8 *test_data;
static uae_u8 *safe_memory_start, *safe_memory_end;
+static uae_u32 user_stack_memory, super_stack_memory;
static int test_data_size;
static uae_u32 oldvbr;
static uae_u8 *vbr_zero = 0;
static void safe_memcpy(uae_u8 *d, uae_u8 *s, int size)
{
if (safe_memory_start == (uae_u8*)0xffffffff && safe_memory_end == (uae_u8*)0xffffffff) {
- memcpy(d, s, size);
+ xmemcpy(d, s, size);
return;
}
if (safe_memory_end <= d || safe_memory_start >= d + size) {
if (safe_memory_end <= s || safe_memory_start >= s + size) {
- memcpy(d, s, size);
+ xmemcpy(d, s, size);
return;
}
}
while (size > 0) {
int size2 = size > sizeof(tmpbuffer) ? sizeof(tmpbuffer) : size;
if ((d + size2 > safe_memory_start && d < safe_memory_end) ||
- (s + size2 > safe_memory_start && d < safe_memory_end)) {
+ (s + size2 > safe_memory_start && s < safe_memory_end)) {
for (int i = 0; i < size2; i++) {
if ((d >= safe_memory_start && d < safe_memory_end) ||
- (s >= safe_memory_start && d < safe_memory_end)) {
+ (s >= safe_memory_start && s < safe_memory_end)) {
s++;
d++;
continue;
*d++ = *s++;
}
} else {
- memcpy(d, s, size2);
+ xmemcpy(d, s, size2);
d += size2;
s += size2;
}
v &= 31;
if (v == 0)
v = 32;
- memcpy(addr, p, v);
+ xmemcpy(addr, p, v);
p += v;
break;
}
sprintf(outbp, "SR:%c%04x PC: %08lx ISP: %08lx", test_sr != last_registers.sr ? '*' : ' ', before ? test_sr : test_regs.sr, r->pc, r->ssp);
outbp += strlen(outbp);
if (cpu_lvl >= 2 && cpu_lvl <= 4) {
- sprintf(outbp, " MSP: %08lx\n", r->msp);
+ sprintf(outbp, " MSP: %08lx", r->msp);
outbp += strlen(outbp);
}
*outbp++ = '\n';
(s2 & mask) != (s3 & mask) ? '!' : ((s1 & mask) != (s2 & mask) ? '*' : '='), (s & mask) != 0);
outbp += strlen(outbp);
}
+ *outbp++ = '\n';
}
- if (!fpu_model) {
- strcat(outbp, "\n");
- outbp += strlen(outbp);
+ if (!fpu_model)
return;
- }
for (int i = 0; i < 8; i++) {
if ((i % 2) == 0) {
errors++;
}
regs_fpuchanged[mode] = 0;
- memcpy(&last_registers.fpuregs[mode], &val, sizeof(struct fpureg));
+ xmemcpy(&last_registers.fpuregs[mode], &val, sizeof(struct fpureg));
} else if (mode == CT_SR) {
uae_u32 val = last_registers.sr;
int size;
}
for (int ccr = 0; ccr < maxccr; ccr++) {
- regs.ssp = test_memory_addr + test_memory_size - 0x80;
- regs.msp = test_memory_addr + test_memory_size;
+ regs.ssp = super_stack_memory - 0x80;
+ regs.msp = super_stack_memory;
regs.pc = opcode_memory_addr;
regs.fpiar = opcode_memory_addr;
#ifdef M68K
- memcpy((void*)regs.ssp, (void*)regs.regs[15], 0x20);
+ xmemcpy((void*)regs.ssp, (void*)regs.regs[15], 0x20);
#endif
xmemcpy(&test_regs, ®s, sizeof(struct registers));
test_memory_size = gl(data);
test_memory_end = test_memory_addr + test_memory_size;
fread(data, 1, 4, f);
- opcode_memory_addr = gl(data) + test_memory_addr;
+ opcode_memory_addr = gl(data);
+ opcode_memory = (uae_u8*)opcode_memory_addr;
fread(data, 1, 4, f);
lvl = (gl(data) >> 16) & 15;
interrupt_mask = (gl(data) >> 20) & 7;
fread(data, 1, 4, f);
safe_memory_end = (uae_u8*)gl(data);
fread(data, 1, 4, f);
+ user_stack_memory = gl(data);
fread(data, 1, 4, f);
+ super_stack_memory = gl(data);
fread(inst_name, 1, sizeof(inst_name) - 1, f);
inst_name[sizeof(inst_name) - 1] = 0;
exit(0);
}
- opcode_memory = test_memory + (opcode_memory_addr - test_memory_addr);
-
size = test_memory_size;
load_file(path, "tmem.dat", test_memory, &size, 1);
if (size != test_memory_size) {
exit(0);
}
- printf("CPUlvl=%d, Mask=%08lx Code=%08lx\n", cpu_lvl, addressing_mask, opcode_memory);
+ printf("CPUlvl=%d, Mask=%08lx Code=%08lx SP=%08lx ISP=%08lx\n",
+ cpu_lvl, addressing_mask, opcode_memory,
+ user_stack_memory, super_stack_memory);
printf(" Low: %08lx-%08lx High: %08lx-%08lx\n",
test_low_memory_start, test_low_memory_end,
test_high_memory_start, test_high_memory_end);