static floatx80 fpuregisters[8];
static uae_u32 fpu_fpiar, fpu_fpcr, fpu_fpsr;
+struct regtype
+{
+ const TCHAR *name;
+ uae_u8 type;
+};
+struct regdata
+{
+ uae_u32 data[3];
+ uae_u8 type;
+};
+
const int areg_byteinc[] = { 1, 1, 1, 1, 1, 1, 1, 2 };
const int imm8_table[] = { 8, 1, 2, 3, 4, 5, 6, 7 };
static uae_u32 target_ea[3];
static int maincpu[6];
static uae_u8 exceptionenabletable[256];
+#define MAX_REGDATAS 32
+static int regdatacnt;
+static struct regdata regdatas[MAX_REGDATAS];
#define HIGH_MEMORY_START (addressing_mask == 0xffffffff ? 0xffff8000 : 0x00ff8000)
static int high_memory_accessed;
static int test_memory_accessed;
static uae_u16 extra_or, extra_and;
-static uae_u32 cur_registers[MAX_REGISTERS];
+static struct regstruct cur_regs;
static uae_u16 read_buffer_prev;
static int interrupt_count;
#define MAX_ACCESSHIST 16000
static struct accesshistory ahist[MAX_ACCESSHIST];
+static void pw(uae_u8 *p, uae_u16 v)
+{
+ p[0] = v >> 8;
+ p[1] = v >> 0;
+}
+static void pl(uae_u8 *p, uae_u32 v)
+{
+ p[0] = v >> 24;
+ p[1] = v >> 16;
+ p[2] = v >> 8;
+ p[3] = v >> 0;
+}
+static uae_u32 gl(uae_u8 *p)
+{
+ return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3] << 0);
+}
+static uae_u32 gw(uae_u8 *p)
+{
+ return (p[0] << 8) | (p[1] << 0);
+}
+
void cputester_fault(void)
{
test_exception = -1;
regs.sr &= ~0x8000;
MakeFromSR();
+ regs.pc = original_exception * 4;
+
int flags = 0;
if (cpu_lvl == 1) {
// IF = 1
return op_illg_1(opcode);
}
+static void exception3_pc_inc(void)
+{
+ if (currprefs.cpu_model == 68000) {
+ m68k_incpci(2);
+ }
+}
+
+
static void exception2_fetch_common(uae_u32 opcode, int offset)
{
test_exception = 2;
} else {
add_memory_cycles(1);
}
-
test_exception = 3;
test_exception_3_w = 0;
test_exception_addr = addr;
} else {
add_memory_cycles(1);
}
+ exception3_pc_inc();
test_exception = 3;
test_exception_3_w = 0;
{
add_memory_cycles(1);
exception3_write(opcode, addr, size, val, fc);
-
}
uae_u16 exception3_word_read(uaecptr addr)
static int fpuregcnts[8];
static float_status fpustatus;
-static bool fpuregchange(int reg, floatx80 *regs)
+static bool fpuregchange(int reg, fpdata *regs)
{
int regcnt = fpuregcnts[reg];
- floatx80 v = regs[reg];
+ floatx80 v = regs[reg].fpx;
floatx80 add;
+ // don't unnecessarily modify static forced register
+ for (int i = 0; i < regdatacnt; i++) {
+ struct regdata *rd = ®datas[i];
+ int mode = rd->type & CT_DATA_MASK;
+ int size = rd->type & CT_SIZE_MASK;
+ if (size == CT_SIZE_FPU && mode == CT_DREG + reg) {
+ return false;
+ }
+ }
+
switch(reg)
{
case 0: // positive
break;
}
fpuregcnts[reg]++;
- regs[reg] = v;
+ regs[reg].fpx = v;
return true;
}
if (generate_address_mode && reg >= 8)
return false;
+ // don't unnecessarily modify static forced register
+ for (int i = 0; i < regdatacnt; i++) {
+ struct regdata *rd = ®datas[i];
+ int mode = rd->type & CT_DATA_MASK;
+ int size = rd->type & CT_SIZE_MASK;
+ if (size != CT_SIZE_FPU && mode == CT_DREG + reg) {
+ return false;
+ }
+ }
+
switch (reg)
{
case 0:
compressfile(fname, 2);
}
+static uae_u8 *modify_reg(uae_u8 *dst, struct regstruct *regs, uae_u8 type, uae_u32 *valp)
+{
+ int mode = type & CT_DATA_MASK;
+ int size = type & CT_SIZE_MASK;
+ uae_u32 val = valp[0];
+ if (size != CT_SIZE_FPU && mode >= CT_DREG && mode < CT_DREG + 8) {
+ if (regs->regs[mode - CT_DREG] == val)
+ return dst;
+ regs->regs[mode - CT_DREG] = val;
+ } else if (size != CT_SIZE_FPU && mode >= CT_AREG && mode < CT_AREG + 8) {
+ if (regs->regs[mode - CT_AREG + 8] == val)
+ return dst;
+ regs->regs[mode - CT_AREG + 8] = val;
+ } else if (size == CT_SIZE_FPU && mode >= CT_DREG && mode < CT_DREG + 7) {
+ fpdata *fpd = ®s->fp[mode - CT_DREG];
+ uae_u64 v = ((uae_u64)valp[1] << 32) | valp[2];
+ if (fpd->fpx.high == val && fpd->fpx.low == v)
+ return dst;
+ fpd->fpx.high = val;
+ fpd->fpx.low = v;
+ } else if (mode == CT_SR) {
+ if (size == CT_SIZE_BYTE) {
+ if ((regs->sr & 0xff) == (val & 0xff))
+ return dst;
+ regs->sr &= 0xff00;
+ regs->sr |= val & 0xff;
+ } else {
+ if (regs->sr == val)
+ return dst;
+ regs->sr = val;
+ }
+ } else if (mode == CT_FPSR) {
+ if (regs->fpsr == val)
+ return dst;
+ regs->fpsr = val;
+ } else if (mode == CT_FPCR) {
+ if (regs->fpcr == val)
+ return dst;
+ regs->fpcr = val;
+ } else if (mode == CT_FPIAR) {
+ if (regs->fpiar == val)
+ return dst;
+ regs->fpiar = val;
+ }
+ if (dst) {
+ *dst++ = CT_OVERRIDE_REG;
+ *dst++ = type;
+ if (size == CT_SIZE_BYTE) {
+ *dst = (uae_u8)val;
+ dst += 1;
+ } else if (size == CT_SIZE_WORD) {
+ pw(dst, (uae_u16)val);
+ dst += 2;
+ } else if (size == CT_SIZE_LONG) {
+ pl(dst, val);
+ dst += 4;
+ } else if (size == CT_SIZE_FPU) {
+ pl(dst, val);
+ dst += 4;
+ pl(dst, valp[1]);
+ dst += 4;
+ pl(dst, valp[2]);
+ dst += 4;
+ }
+ }
+ return dst;
+}
+
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;
return dst;
}
-static uae_u8 *store_fpureg(uae_u8 *dst, uae_u8 mode, floatx80 d)
-{
+static uae_u8 *store_fpureg(uae_u8 *dst, uae_u8 mode, floatx80 *s, floatx80 d, int forced)
+{
+ if (forced || s == NULL) {
+ *dst++ = mode | CT_SIZE_FPU;
+ *dst++ = 0xff;
+ *dst++ = (d.high >> 8) & 0xff;
+ *dst++ = (d.high >> 0) & 0xff;
+ *dst++ = (d.low >> 56) & 0xff;
+ *dst++ = (d.low >> 48) & 0xff;
+ *dst++ = (d.low >> 40) & 0xff;
+ *dst++ = (d.low >> 32) & 0xff;
+ *dst++ = (d.low >> 24) & 0xff;
+ *dst++ = (d.low >> 16) & 0xff;
+ *dst++ = (d.low >> 8) & 0xff;
+ *dst++ = (d.low >> 0) & 0xff;
+ return dst;
+ }
+ if (s->high == d.high && s->low == d.low) {
+ return dst;
+ }
+ uae_u8 fs[10], fd[10];
+ fs[0] = s->high >> 8;
+ fs[1] = s->high;
+ fs[2] = s->low >> 56;
+ fs[3] = s->low >> 48;
+ fs[4] = s->low >> 40;
+ fs[5] = s->low >> 32;
+ fs[6] = s->low >> 24;
+ fs[7] = s->low >> 16;
+ fs[8] = s->low >> 8;
+ fs[9] = s->low >> 0;
+ fd[0] = d.high >> 8;
+ fd[1] = d.high;
+ fd[2] = d.low >> 56;
+ fd[3] = d.low >> 48;
+ fd[4] = d.low >> 40;
+ fd[5] = d.low >> 32;
+ fd[6] = d.low >> 24;
+ fd[7] = d.low >> 16;
+ fd[8] = d.low >> 8;
+ fd[9] = d.low >> 0;
*dst++ = mode | CT_SIZE_FPU;
- *dst++ = (d.high >> 8) & 0xff;
- *dst++ = (d.high >> 0) & 0xff;
- *dst++ = (d.low >> 56) & 0xff;
- *dst++ = (d.low >> 48) & 0xff;
- *dst++ = (d.low >> 40) & 0xff;
- *dst++ = (d.low >> 32) & 0xff;
- *dst++ = (d.low >> 24) & 0xff;
- *dst++ = (d.low >> 16) & 0xff;
- *dst++ = (d.low >> 8) & 0xff;
- *dst++ = (d.low >> 0) & 0xff;
+ if (fs[4] != fd[4] || fs[5] != fd[5]) {
+ *dst++ = 0xff;
+ *dst++ = (d.high >> 8) & 0xff;
+ *dst++ = (d.high >> 0) & 0xff;
+ *dst++ = (d.low >> 56) & 0xff;
+ *dst++ = (d.low >> 48) & 0xff;
+ *dst++ = (d.low >> 40) & 0xff;
+ *dst++ = (d.low >> 32) & 0xff;
+ *dst++ = (d.low >> 24) & 0xff;
+ *dst++ = (d.low >> 16) & 0xff;
+ *dst++ = (d.low >> 8) & 0xff;
+ *dst++ = (d.low >> 0) & 0xff;
+ return dst;
+ }
+ uae_u8 *flagp = dst;
+ *flagp = 0;
+ dst++;
+ if ((fs[0] != fd[0] || fs[1] != fd[1] || fs[2] != fd[2] || fs[3] != fd[3]) && fs[4] == fd[4]) {
+ uae_u8 cnt = 4;
+ for (int i = 3; i >= 0; i--) {
+ if (fs[i] != fd[i])
+ break;
+ cnt--;
+ }
+ if (cnt > 0) {
+ *flagp |= cnt << 4;
+ for (int i = 0; i < cnt; i++) {
+ *dst++ = fd[i];
+ }
+ }
+ }
+ if ((fs[9] != fd[9] || fs[8] != fd[8] || fs[7] != fd[7] || fs[6] != fd[6]) && fs[5] == fd[5]) {
+ uae_u8 cnt = 4;
+ for (int i = 6; i <= 9; i++) {
+ if (fs[i] != fd[i])
+ break;
+ cnt--;
+ }
+ if (cnt > 0) {
+ *flagp |= cnt;
+ for (int i = 0; i < cnt; i++) {
+ *dst++ = fd[9 - i];
+ }
+ }
+ }
return dst;
}
return dst;
}
-static void pl(uae_u8 *p, uae_u32 v)
-{
- p[0] = v >> 24;
- p[1] = v >> 16;
- p[2] = v >> 8;
- p[3] = v >> 0;
-}
-static uae_u32 gl(uae_u8 *p)
-{
- return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3] << 0);
-}
-static uae_u32 gw(uae_u8 *p)
-{
- return (p[0] << 8) | (p[1] << 0);
-}
-
static bool load_file(const TCHAR *path, const TCHAR *file, uae_u8 *p, int size, int offset)
{
TCHAR fname[1000];
case Aind:
case Aipi:
*regused = reg + 8;
- *eap = cur_registers[reg + 8];
+ *eap = cur_regs.regs[reg + 8];
break;
case Apdi:
*regused = reg + 8;
if (fpuopsize < 0) {
- *eap = cur_registers[reg + 8] - (1 << dp->size);
+ *eap = cur_regs.regs[reg + 8] - (1 << dp->size);
} else {
- *eap = cur_registers[reg + 8] - bytesizes[fpuopsize];
+ *eap = cur_regs.regs[reg + 8] - bytesizes[fpuopsize];
}
break;
case Ad16:
int maxcnt = 1000;
for (;;) {
v = rand16();
- addr = cur_registers[reg + 8] + (uae_s16)v;
+ addr = cur_regs.regs[reg + 8] + (uae_s16)v;
*regused = reg + 8;
if (fpuopsize >= 0) {
if (check_valid_addr(addr, bytesizes[fpuopsize], 2))
v = rand16();
if (currprefs.cpu_model >= 68020)
v &= ~0x100;
- addr = mode == PC8r ? pc + 2 - 2 : cur_registers[reg + 8];
+ addr = mode == PC8r ? pc + 2 - 2 : cur_regs.regs[reg + 8];
*regused = v >> 12;
- add = cur_registers[v >> 12];
+ add = cur_regs.regs[v >> 12];
if (currprefs.cpu_model >= 68020) {
add <<= (v >> 9) & 3; // SCALE
}
case Aind:
case Aipi:
{
- if (cur_registers[reg + 8] == target) {
+ if (cur_regs.regs[reg + 8] == target) {
*eap = target;
*regused = reg + 8;
return 0;
}
case Apdi:
{
- if (cur_registers[reg + 8] == target + (1 << dp->size)) {
+ if (cur_regs.regs[reg + 8] == target + (1 << dp->size)) {
*eap = target;
*regused = reg + 8;
return 0;
}
case Ad16:
{
- uae_u32 v = cur_registers[reg + 8];
+ uae_u32 v = cur_regs.regs[reg + 8];
if (target <= v + 0x7ffe && (target >= v - 0x8000 || v < 0x8000)) {
put_word_test(pc, target - v);
*eap = target;
case Ad8r:
{
for (int r = 0; r < 16; r++) {
- uae_u32 aval = cur_registers[reg + 8];
+ uae_u32 aval = cur_regs.regs[reg + 8];
int rn = ((ea_exact_cnt >> 1) + r) & 15;
for (int i = 0; i < 2; i++) {
if ((ea_exact_cnt & 1) == 0 || i == 1) {
- uae_s32 val32 = cur_registers[rn];
+ uae_s32 val32 = cur_regs.regs[rn];
uae_u32 addr = aval + val32;
if (target <= addr + 0x7f && target >= addr - 0x80) {
put_word_test(pc, (rn << 12) | 0x0800 | ((target - addr) & 0xff));
return 2;
}
} else {
- uae_s16 val16 = (uae_s16)cur_registers[rn];
+ uae_s16 val16 = (uae_s16)cur_regs.regs[rn];
uae_u32 addr = aval + val16;
if (target <= addr + 0x7f && target >= addr - 0x80) {
put_word_test(pc, (rn << 12) | 0x0000 | ((target - addr) & 0xff));
int rn = ((ea_exact_cnt >> 1) + r) & 15;
for (int i = 0; i < 2; i++) {
if ((ea_exact_cnt & 1) == 0 || i == 1) {
- uae_s32 val32 = cur_registers[rn];
+ uae_s32 val32 = cur_regs.regs[rn];
uae_u32 addr = aval + val32;
if (target <= addr + 0x7f && target >= addr - 0x80) {
put_word_test(pc, (rn << 12) | 0x0800 | ((target - addr) & 0xff));
return 2;
}
} else {
- uae_s16 val16 = (uae_s16)cur_registers[rn];
+ uae_s16 val16 = (uae_s16)cur_regs.regs[rn];
uae_u32 addr = aval + val16;
if (target <= addr + 0x7f && target >= addr - 0x80) {
put_word_test(pc, (rn << 12) | 0x0000 | ((target - addr) & 0xff));
uae_u16 opc = regs.ir;
uae_u16 opw1 = (opcode_memory[2] << 8) | (opcode_memory[3] << 0);
uae_u16 opw2 = (opcode_memory[4] << 8) | (opcode_memory[5] << 0);
- if (opc == 0xf200
- && opw1 == 0x6c12
+ if (opc == 0xf202
+ && opw1 == 0x5225
//&& opw2 == 0x4afc
)
printf("");
}
// access address
p = store_rel(p, 0, opcode_memory_start, gl(sf + 2), 1);
+ // program counter
+ p = store_rel(p, 0, opcode_memory_start, gl(sf + 10), 1);
}
} else if (cpu_lvl > 0) {
uae_u8 ccrmask = 0;
}
for (int i = 0; i < MAX_REGISTERS; i++) {
- cur_registers[i] = registers[i];
+ cur_regs.regs[i] = registers[i];
}
- floatx80 cur_fpuregisters[8];
for (int i = 0; i < 8; i++) {
- cur_fpuregisters[i] = fpuregisters[i];
+ cur_regs.fp[i].fpx = fpuregisters[i];
}
+ cur_regs.fpiar = 0xffffffff;
if (target_address != 0xffffffff) {
- generate_target_registers(target_address, cur_registers);
+ generate_target_registers(target_address, cur_regs.regs);
}
dst = storage_buffer;
if (quick)
break;
+ // overrides
+ for (int i = 0; i < regdatacnt; i++) {
+ struct regdata *rd = ®datas[i];
+ uae_u8 v = rd->type & CT_DATA_MASK;
+ modify_reg(NULL, &cur_regs, rd->type, rd->data);
+ }
+
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];
+ cur_regs.regs[feature_loop_mode_register] &= 0xffff0000;
+ cur_regs.regs[feature_loop_mode_register] |= feature_loop_mode - 1;
}
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];
+ dst = store_reg(dst, CT_DREG + i, 0, cur_regs.regs[i], -1);
}
for (int i = 0; i < 8; i++) {
if (fpumode) {
- dst = store_fpureg(dst, CT_FPREG + i, cur_fpuregisters[i]);
+ dst = store_fpureg(dst, CT_FPREG + i, NULL, cur_regs.fp[i].fpx, 1);
}
- regs.fp[i].fpx = cur_fpuregisters[i];
+ dst = store_reg(dst, CT_FPIAR, 0, cur_regs.fpiar, -1);
}
- regs.sr = feature_min_interrupt_mask << 8;
+ cur_regs.sr = feature_min_interrupt_mask << 8;
uae_u32 srcaddr_old = 0xffffffff;
uae_u32 dstaddr_old = 0xffffffff;
target_opcode_address = target_opcode_address_bak;
if (target_usp_address != 0xffffffff) {
- cur_registers[15] = target_usp_address;
- regs.regs[15] = target_usp_address;
+ cur_regs.regs[15] = target_usp_address;
}
+ memcpy(®s, &cur_regs, sizeof(cur_regs));
+
regs.usp = regs.regs[15];
regs.isp = super_stack_memory - 0x80;
TCHAR out[256];
memset(out, 0, sizeof(out));
// disassemble and output generated instruction
- for (int i = 0; i < MAX_REGISTERS; i++) {
- regs.regs[i] = cur_registers[i];
- }
- for (int i = 0; i < 8; i++) {
- regs.fp[i].fpx = cur_fpuregisters[i];
- }
+ memcpy(®s, &cur_regs, sizeof(cur_regs));
uaecptr nextpc;
srcaddr = 0xffffffff;
srcaddr = get_long_test(regs.regs[15] + stackoffset);
}
// branch target is not accessible? skip.
- 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)) {
+ if ((((srcaddr & addressing_mask) >= cur_regs.regs[15] - 16 && (srcaddr & addressing_mask) <= cur_regs.regs[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)
int ok = 0;
int cnt_stopped = 0;
- uae_u32 last_sr = 0;
- uae_u32 last_pc = 0;
uae_u32 last_cpu_cycles = 0;
- uae_u32 last_registers[MAX_REGISTERS];
- floatx80 last_fpuregisters[8];
- uae_u32 last_fpiar = 0;
- uae_u32 last_fpsr = 0;
- uae_u32 last_fpcr = 0;
+ regstruct last_regs;
int ccr_done = 0;
int prev_s_cnt = 0;
int maxflag;
int flagmode = 0;
if (fpumode) {
- if (fpuopcode == FPUOPP_ILLEGAL) {
+ if (fpuopcode == FPUOPP_ILLEGAL || feature_flag_mode > 1) {
// Illegal FPU instruction: all on/all off only (*2)
maxflag = 2;
} else if (dp->mnemo == i_FDBcc || dp->mnemo == i_FScc || dp->mnemo == i_FTRAPcc || dp->mnemo == i_FBcc) {
// swap end opcode illegal/nop
noaccesshistory++;
endopcode = (endopcode >> 16) | (endopcode << 16);
+ int extraopcodeendsize = ((endopcode >> 16) == 0x4e71) ? 2 : 0;
int endopcodesize = 0;
if (!is_nowrite_address(pc - 4, 4)) {
put_long_test(pc - 4, endopcode);
// set up registers
for (int i = 0; i < MAX_REGISTERS; i++) {
- regs.regs[i] = cur_registers[i];
+ regs.regs[i] = cur_regs.regs[i];
}
if (fpumode) {
for (int i = 0; i < 8; i++) {
- regs.fp[i].fpx = cur_fpuregisters[i];
+ regs.fp[i].fpx = cur_regs.fp[i].fpx;
}
- regs.fpiar = regs.pc;
+ regs.fpiar = cur_regs.fpiar;
uae_u32 fpsr = 0, fpcr = 0;
if (maxflag == 16) {
if (flagmode) {
fpsr = ((ccr & 1) ? 15 : 0) << 24;
fpcr = ((ccr & 1) ? 15 : 0) << 4;
}
+ // override special register values
+ for (int i = 0; i < regdatacnt; i++) {
+ struct regdata *rd = ®datas[i];
+ uae_u8 v = rd->type & CT_DATA_MASK;
+ if (v == CT_FPSR || v == CT_FPCR || v == CT_FPIAR) {
+ if (v == CT_FPSR) {
+ regs.fpsr = fpsr;
+ } else if (v == CT_FPCR) {
+ regs.fpcr = fpcr;
+ }
+ dst = modify_reg(dst, ®s, rd->type, rd->data);
+ if (v == CT_FPSR) {
+ fpsr = regs.fpsr;
+ } else if (v == CT_FPCR) {
+ fpcr = regs.fpcr;
+ }
+ }
+ }
// condition codes
fpp_set_fpsr(fpsr);
// precision and rounding
fpp_set_fpcr(fpcr);
-
}
+
// all CCR combinations or only all ones/all zeros?
if (maxflag >= 32) {
regs.sr = (ccr & 0xff) | sr_mask;
regs.sr = ((ccr & 1) ? 31 : 0) | sr_mask;
}
regs.sr |= feature_min_interrupt_mask << 8;
+
+ // override special register values
+ for (int i = 0; i < regdatacnt; i++) {
+ struct regdata *rd = ®datas[i];
+ uae_u8 v = rd->type & CT_DATA_MASK;
+ if (v == CT_SR) {
+ dst = modify_reg(dst, ®s, rd->type, rd->data);
+ }
+ }
+
regs.usp = regs.regs[15];
regs.isp = super_stack_memory - 0x80;
// copy user stack to super stack, for RTE etc support
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
if (!ccr && !extraccr) {
- last_sr = regs.sr;
- last_pc = regs.pc;
- for (int i = 0; i < 16; i++) {
- last_registers[i] = regs.regs[i];
- }
- for (int i = 0; i < 8; i++) {
- last_fpuregisters[i] = regs.fp[i].fpx;
- }
- last_fpiar = regs.fpiar;
- last_fpcr = regs.fpcr;
- last_fpsr = regs.fpsr;
+ memcpy(&last_regs, ®s, sizeof(regstruct));
}
if (regs.sr & 0x2000)
if (regs.s)
s_cnt++;
- // validate PC
- uae_u8 *pcaddr = get_addr(regs.pc, 2, 0);
+ uae_u8 *pcaddr;
+ // validate PC (PC in exception space if exception is fine, don't set out of space)
+ if (test_exception && regs.pc < 0x100 && low_memory) {
+ pcaddr = low_memory + regs.pc;
+ } else {
+ pcaddr = get_addr(regs.pc, 2, 0);
+ }
// examine results
}
// save modified registers
for (int i = 0; i < MAX_REGISTERS; i++) {
- uae_u32 s = last_registers[i];
+ uae_u32 s = last_regs.regs[i];
uae_u32 d = regs.regs[i];
if (s != d) {
if (storeregs) {
dst = store_reg(dst, CT_DREG + i, s, d, -1);
}
- last_registers[i] = d;
+ last_regs.regs[i] = d;
}
}
// SR/CCR
uae_u32 ccrignoremask = get_ccr_ignore(dp, extraword) << 16;
- if ((regs.sr | ccrignoremask) != last_sr) {
- dst = store_reg(dst, CT_SR, last_sr, regs.sr | ccrignoremask, -1);
- last_sr = regs.sr | ccrignoremask;
+ if ((regs.sr | ccrignoremask) != last_regs.sr) {
+ dst = store_reg(dst, CT_SR, last_regs.sr, regs.sr | ccrignoremask, -1);
+ last_regs.sr = regs.sr | ccrignoremask;
}
// PC
- if (regs.pc != last_pc) {
- dst = store_rel(dst, CT_PC, last_pc, regs.pc, 0);
- last_pc = regs.pc;
+ if (regs.pc - extraopcodeendsize != last_regs.pc) {
+ dst = store_rel(dst, CT_PC, last_regs.pc, regs.pc - extraopcodeendsize, 0);
+ last_regs.pc = regs.pc - extraopcodeendsize;
}
// FPU stuff
if (currprefs.fpu_model) {
for (int i = 0; i < 8; i++) {
- floatx80 s = last_fpuregisters[i];
+ floatx80 s = last_regs.fp[i].fpx;
floatx80 d = regs.fp[i].fpx;
if (s.high != d.high || s.low != d.low) {
- dst = store_fpureg(dst, CT_FPREG + i, d);
- last_fpuregisters[i] = d;
+ dst = store_fpureg(dst, CT_FPREG + i, &s, d, 0);
+ last_regs.fp[i].fpx = d;
}
}
- if (regs.fpiar != last_fpiar) {
- dst = store_reg(dst, CT_FPIAR, last_fpiar, regs.fpiar, -1);
- last_fpiar = regs.fpiar;
+ if (regs.fpiar != last_regs.fpiar) {
+ dst = store_reg(dst, CT_FPIAR, last_regs.fpiar, regs.fpiar, -1);
+ last_regs.fpiar = regs.fpiar;
}
- if (regs.fpsr != last_fpsr) {
- dst = store_reg(dst, CT_FPSR, last_fpsr, regs.fpsr, -1);
- last_fpsr = regs.fpsr;
+ if (regs.fpsr != last_regs.fpsr) {
+ dst = store_reg(dst, CT_FPSR, last_regs.fpsr, regs.fpsr, -1);
+ last_regs.fpsr = regs.fpsr;
}
- if (regs.fpcr != last_fpcr) {
- dst = store_reg(dst, CT_FPCR, last_fpcr, regs.fpcr, -1);
- last_fpcr = regs.fpcr;
+ if (regs.fpcr != last_regs.fpcr) {
+ dst = store_reg(dst, CT_FPCR, last_regs.fpcr, regs.fpcr, -1);
+ last_regs.fpcr = regs.fpcr;
}
}
if (cpu_lvl <= 1 && (last_cpu_cycles != cpu_cycles || first_cycles)) {
data_saved = 1;
// if test used data or fpu register as a source or destination: 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);
+ uae_u32 prev = cur_regs.regs[srcregused];
+ if (regchange(srcregused, cur_regs.regs)) {
+ dst = store_reg(dst, CT_DREG + srcregused, prev, cur_regs.regs[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);
+ uae_u32 prev = cur_regs.regs[dstregused];
+ if (regchange(dstregused, cur_regs.regs)) {
+ dst = store_reg(dst, CT_DREG + dstregused, prev, cur_regs.regs[dstregused], -1);
}
}
if (srcfpuregused >= 0) {
- if (fpuregchange(srcfpuregused, cur_fpuregisters)) {
- dst = store_fpureg(dst, CT_FPREG + srcfpuregused, cur_fpuregisters[srcfpuregused]);
+ floatx80 prev = cur_regs.fp[srcfpuregused].fpx;
+ if (fpuregchange(srcfpuregused, cur_regs.fp)) {
+ dst = store_fpureg(dst, CT_FPREG + srcfpuregused, &prev, cur_regs.fp[srcfpuregused].fpx, 0);
}
}
if (dstfpuregused >= 0 && srcfpuregused != dstfpuregused) {
- if (fpuregchange(dstfpuregused, cur_fpuregisters)) {
- dst = store_fpureg(dst, CT_FPREG + dstfpuregused, cur_fpuregisters[dstfpuregused]);
+ floatx80 prev = cur_regs.fp[dstfpuregused].fpx;
+ if (fpuregchange(dstfpuregused, cur_regs.fp)) {
+ dst = store_fpureg(dst, CT_FPREG + dstfpuregused, &prev, cur_regs.fp[dstfpuregused].fpx, 0);
}
}
}
}
dst = storage_buffer;
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];
+ dst = store_reg(dst, CT_DREG + i, 0, cur_regs.regs[i], -1);
+ regs.regs[i] = cur_regs.regs[i];
}
if (currprefs.fpu_model) {
for (int i = 0; i < 8; i++) {
- dst = store_fpureg(dst, CT_FPREG + i, cur_fpuregisters[i]);
- regs.fp[i].fpx = cur_fpuregisters[i];
+ dst = store_fpureg(dst, CT_FPREG + i, NULL, cur_regs.fp[i].fpx, 0);
+ regs.fp[i].fpx = cur_regs.fp[i].fpx;
}
}
}
target_address = feature_target_ea[target_ea_dst_cnt][1];
target_ea[1] = target_address;
}
- generate_target_registers(target_address, cur_registers);
+ generate_target_registers(target_address, cur_regs.regs);
} else {
nextround = true;
}
}
}
- cur_registers[0] &= 0xffff;
- cur_registers[8] &= 0xffff;
- cur_registers[8 + 6]--;
- cur_registers[15] -= 2;
-
- if (fpumode) {
- for (int i = 0; i < 8; i++) {
- uae_u32 v = rand32();
- cur_fpuregisters[i] = int32_to_floatx80(v);
- }
- }
+ cur_regs.regs[0] &= 0xffff;
+ cur_regs.regs[8] &= 0xffff;
+ cur_regs.regs[8 + 6]--;
+ cur_regs.regs[15] -= 2;
}
markfile(dir);
return ret;
}
+static const struct regtype regtypes[] =
+{
+ { _T("D0"), CT_SIZE_LONG | (CT_DREG + 0) },
+ { _T("D1"), CT_SIZE_LONG | (CT_DREG + 1) },
+ { _T("D2"), CT_SIZE_LONG | (CT_DREG + 2) },
+ { _T("D3"), CT_SIZE_LONG | (CT_DREG + 3) },
+ { _T("D4"), CT_SIZE_LONG | (CT_DREG + 4) },
+ { _T("D5"), CT_SIZE_LONG | (CT_DREG + 5) },
+ { _T("D6"), CT_SIZE_LONG | (CT_DREG + 6) },
+ { _T("D7"), CT_SIZE_LONG | (CT_DREG + 7) },
+
+ { _T("A0"), CT_SIZE_LONG | (CT_AREG + 0) },
+ { _T("A1"), CT_SIZE_LONG | (CT_AREG + 1) },
+ { _T("A2"), CT_SIZE_LONG | (CT_AREG + 2) },
+ { _T("A3"), CT_SIZE_LONG | (CT_AREG + 3) },
+ { _T("A4"), CT_SIZE_LONG | (CT_AREG + 4) },
+ { _T("A5"), CT_SIZE_LONG | (CT_AREG + 5) },
+ { _T("A6"), CT_SIZE_LONG | (CT_AREG + 6) },
+ { _T("A7"), CT_SIZE_LONG | (CT_AREG + 7) },
+
+ { _T("FP0"), CT_SIZE_FPU | (CT_FPREG + 0) },
+ { _T("FP1"), CT_SIZE_FPU | (CT_FPREG + 1) },
+ { _T("FP2"), CT_SIZE_FPU | (CT_FPREG + 2) },
+ { _T("FP3"), CT_SIZE_FPU | (CT_FPREG + 3) },
+ { _T("FP4"), CT_SIZE_FPU | (CT_FPREG + 4) },
+ { _T("FP5"), CT_SIZE_FPU | (CT_FPREG + 5) },
+ { _T("FP6"), CT_SIZE_FPU | (CT_FPREG + 6) },
+ { _T("FP7"), CT_SIZE_FPU | (CT_FPREG + 7) },
+
+ { _T("CCR"), CT_SR | CT_SIZE_BYTE, },
+ { _T("SR"), CT_SR | CT_SIZE_WORD, },
+ { _T("FPCR"), CT_FPCR | CT_SIZE_LONG, },
+ { _T("FPSR"), CT_FPSR | CT_SIZE_LONG, },
+ { _T("FPIAR"), CT_FPIAR | CT_SIZE_LONG, },
+
+ { NULL }
+};
+
static int cputoindex(int cpu)
{
if (cpu == 68000) {
safe_memory_mode = 0;
}
+ if (ini_getstringx(ini, sections, _T("feature_forced_register"), &vs)) {
+ bool first = true;
+ TCHAR *p = vs;
+ while (p && *p) {
+ TCHAR *pp = _tcschr(p, ',');
+ if (pp) {
+ *pp++ = 0;
+ }
+ TCHAR *pp2 = _tcschr(p, ':');
+ if (pp2) {
+ *pp2++ = 0;
+ for (int i = 0; regtypes[i].name; i++) {
+ if (!_tcsicmp(regtypes[i].name, p)) {
+ if (regdatacnt >= MAX_REGDATAS) {
+ wprintf(_T("Out of regdata!\n"));
+ abort();
+ }
+ struct regdata *rd = ®datas[regdatacnt];
+ rd->type = regtypes[i].type;
+ if (pp2[0] == '0' && (pp2[1] == 'x' || pp2[1] == 'X')) {
+ TCHAR *endptr;
+ rd->data[0] = _tcstol(pp2, &endptr, 16);
+ } else {
+ rd->data[0] = _tstol(pp2);
+ }
+ regdatacnt++;
+ break;
+ }
+ }
+ }
+ p = pp;
+ }
+ xfree(vs);
+ }
+
+
if (ini_getstringx(ini, sections, _T("exceptions"), &vs)) {
bool first = true;
uae_u32 expsr;
uae_u32 exc, exc010;
uae_u32 excframe;
- struct fpureg fpuregs[8];
- uae_u32 fpiar, fpcr, fpsr;
- uae_u32 fsave[216/4];
uae_u32 tracecnt;
uae_u16 tracedata[6];
uae_u32 cycles, cycles2, cyclest;
+ struct fpureg fpuregs[8];
+ uae_u32 fpiar, fpcr, fpsr;
+ uae_u32 fsave[216 / 4];
+
uae_u32 srcaddr, dstaddr, branchtarget;
uae_u8 branchtarget_mode;
uae_u32 endpc;
+
uae_u16 fpeaset;
};
static short continue_on_error;
static struct registers test_regs;
-static struct registers last_registers;
-static struct registers regs;
+static struct registers last_regs;
+static struct registers cur_regs;
static uae_u8 *opcode_memory;
static uae_u32 opcode_memory_addr;
static uae_u8 *low_memory;
static int cpu_lvl, fpu_model;
static uae_u16 sr_undefined_mask;
static int check_undefined_sr;
+static short is_fpu_adjust;
+static short fpu_adjust_man, fpu_adjust_exp, fpu_adjust_zb;
+struct fpureg fpu_adjust;
static uae_u32 cpustatearraystore[16];
static uae_u32 cpustatearraynew[] = {
0x00000005, // SFC
static uae_u32 startpc, endpc;
static char inst_name[16+1];
-#define DEFAULT_OUTBUFFER_SIZE 20000
+#define PAGE_OUTBUFFER_SIZE 3000
static int outbuffer_size;
-static char *outbuffer;
-static char *outbuffer2;
+static char *stored_outbuffer;
+static char outbuffer[6000];
+static char outbuffer2[6000];
static char tmpbuffer[1024];
static char path[256];
static char *outbp;
static short infoadded;
static int errors;
+static int totalerrors;
static int testcnt;
+static short testcntsub, testcntsubmax;
+static int fpu_approx, fpu_approxcnt;
static short dooutput = 1;
static short quit;
static uae_u8 ccr_mask;
static short interrupttest;
static short randomizetest;
static uae_u32 cyclecounter_addr;
+static int errorcnt;
static short uaemode;
#ifdef AMIGA
static short interrupt_count;
endinfo();
exit(0);
}
- fp->exp = gw(p);
- p += 2;
- fp->m[0] = gl(p);
- p += 4;
- fp->m[1] = gl(p);
- p += 4;
fp->dummy = 0;
+ uae_u8 size = *p++;
+ if (size == 0x00) {
+ fp->exp = 0;
+ fp->m[0] = fp->m[1] = 0;
+ } else if (size == 0xff) {
+ fp->exp = gw(p);
+ p += 2;
+ fp->m[0] = gl(p);
+ p += 4;
+ fp->m[1] = gl(p);
+ p += 4;
+ } else {
+ uae_u8 f[10];
+ f[0] = fp->exp >> 8;
+ f[1] = fp->exp;
+ f[2] = fp->m[0] >> 24;
+ f[3] = fp->m[0] >> 16;
+ f[4] = fp->m[0] >> 8;
+ f[5] = fp->m[0] >> 0;
+ f[6] = fp->m[1] >> 24;
+ f[7] = fp->m[1] >> 16;
+ f[8] = fp->m[1] >> 8;
+ f[9] = fp->m[1] >> 0;
+ uae_u8 size1 = (size >> 4) & 15;
+ for (uae_u8 i = 0; i < size1; i++) {
+ f[i] = *p++;
+ }
+ uae_u8 size2 = (size >> 0) & 15;
+ for (uae_u8 i = 0; i < size2; i++) {
+ f[9 - i] = *p++;
+ }
+ fp->exp = (f[0] << 8) | (f[1] << 0);
+ fp->m[0] = (f[2] << 24) | (f[3] << 16) | (f[4] << 8) | (f[5] << 0);
+ fp->m[1] = (f[6] << 24) | (f[7] << 16) | (f[8] << 8) | (f[9] << 0);
+ }
return p;
}
return p;
}
-static uae_u8 *restore_data(uae_u8 *p)
+static uae_u8 *restore_data(uae_u8 *p, struct registers *r)
{
uae_u8 v = *p;
if (v & CT_END) {
int mode = v & CT_DATA_MASK;
if (mode == CT_SRCADDR) {
int size;
- p = restore_value(p, ®s.srcaddr, &size);
+ p = restore_value(p, &r->srcaddr, &size);
} else if (mode == CT_DSTADDR) {
int size;
- p = restore_value(p, ®s.dstaddr, &size);
+ p = restore_value(p, &r->dstaddr, &size);
} else if (mode == CT_ENDPC) {
int size;
- p = restore_value(p, ®s.endpc, &size);
+ p = restore_value(p, &r->endpc, &size);
} else if (mode == CT_PC) {
int size;
- p = restore_value(p, ®s.pc, &size);
+ p = restore_value(p, &r->pc, &size);
} else if (mode == CT_BRANCHTARGET) {
int size;
- p = restore_value(p, ®s.branchtarget, &size);
- regs.branchtarget_mode = *p++;
+ p = restore_value(p, &r->branchtarget, &size);
+ r->branchtarget_mode = *p++;
} else if (mode < CT_AREG + 8) {
int size;
if ((v & CT_SIZE_MASK) == CT_SIZE_FPU) {
- p = restore_fpvalue(p, ®s.fpuregs[mode]);
+ p = restore_fpvalue(p, &r->fpuregs[mode]);
} else {
- p = restore_value(p, ®s.regs[mode], &size);
+ p = restore_value(p, &r->regs[mode], &size);
}
} else if (mode == CT_SR) {
int size;
- p = restore_value(p, ®s.sr, &size);
+ p = restore_value(p, &r->sr, &size);
} else if (mode == CT_CYCLES) {
int size;
- p = restore_value(p, ®s.cycles, &size);
+ p = restore_value(p, &r->cycles, &size);
gotcycles = 1;
} else if (mode == CT_FPIAR) {
int size;
- p = restore_value(p, ®s.fpiar, &size);
+ p = restore_value(p, &r->fpiar, &size);
} else if (mode == CT_FPCR) {
int size;
- p = restore_value(p, ®s.fpcr, &size);
+ p = restore_value(p, &r->fpcr, &size);
} else if (mode == CT_FPSR) {
int size;
- p = restore_value(p, ®s.fpsr, &size);
+ p = restore_value(p, &r->fpsr, &size);
} else if (mode == CT_MEMWRITE) {
// if memwrite, store old data
p = restore_memory(p, 1);
return p;
}
-static uae_u16 test_sr, test_ccrignoremask;
-static uae_u32 test_fpsr, test_fpcr;
+static uae_u16 test_ccrignoremask;
static int addr_diff(uae_u8 *ap, uae_u8 *bp, int size)
{
static void addinfo(void)
{
+ struct registers *r = &cur_regs;
if (infoadded)
return;
infoadded = 1;
if (disasm) {
out_disasm(opcode_memory);
- }
-
- if (regs.branchtarget != 0xffffffff) {
- out_disasm((uae_u8*)regs.branchtarget);
+ if (r->branchtarget != 0xffffffff && !(r->branchtarget & 1)) {
+ out_disasm((uae_u8 *)r->branchtarget);
+ }
}
uae_u16 *code = (uae_u16*)opcode_memory;
addinfo_bytes("P", stackaddr, stackaddr_ptr, -SIZE_STORED_ADDRESS_OFFSET, SIZE_STORED_ADDRESS);
addinfo_bytes(" ", (uae_u8 *)stackaddr_ptr - SIZE_STORED_ADDRESS_OFFSET, stackaddr_ptr, -SIZE_STORED_ADDRESS_OFFSET, SIZE_STORED_ADDRESS);
}
- if (regs.srcaddr != 0xffffffff) {
+ if (r->srcaddr != 0xffffffff) {
uae_u8 *a = srcaddr;
- uae_u8 *b = (uae_u8 *)regs.srcaddr - SIZE_STORED_ADDRESS_OFFSET;
- addinfo_bytes("S", a, regs.srcaddr, -SIZE_STORED_ADDRESS_OFFSET, SIZE_STORED_ADDRESS);
+ uae_u8 *b = (uae_u8 *)r->srcaddr - SIZE_STORED_ADDRESS_OFFSET;
+ addinfo_bytes("S", a, r->srcaddr, -SIZE_STORED_ADDRESS_OFFSET, SIZE_STORED_ADDRESS);
if (addr_diff(a, b, SIZE_STORED_ADDRESS)) {
- addinfo_bytes(" ", b, regs.srcaddr, -SIZE_STORED_ADDRESS_OFFSET, SIZE_STORED_ADDRESS);
+ addinfo_bytes(" ", b, r->srcaddr, -SIZE_STORED_ADDRESS_OFFSET, SIZE_STORED_ADDRESS);
}
}
- if (regs.dstaddr != 0xffffffff) {
+ if (r->dstaddr != 0xffffffff) {
uae_u8 *a = dstaddr;
- uae_u8 *b = (uae_u8*)regs.dstaddr - SIZE_STORED_ADDRESS_OFFSET;
- addinfo_bytes("D", a, regs.dstaddr, -SIZE_STORED_ADDRESS_OFFSET, SIZE_STORED_ADDRESS);
+ uae_u8 *b = (uae_u8*)r->dstaddr - SIZE_STORED_ADDRESS_OFFSET;
+ addinfo_bytes("D", a, r->dstaddr, -SIZE_STORED_ADDRESS_OFFSET, SIZE_STORED_ADDRESS);
if (addr_diff(a, b, SIZE_STORED_ADDRESS)) {
- addinfo_bytes(" ", b, regs.dstaddr, -SIZE_STORED_ADDRESS_OFFSET, SIZE_STORED_ADDRESS);
+ addinfo_bytes(" ", b, r->dstaddr, -SIZE_STORED_ADDRESS_OFFSET, SIZE_STORED_ADDRESS);
}
}
- if (regs.branchtarget != 0xffffffff && regs.srcaddr != regs.branchtarget && regs.dstaddr != regs.branchtarget) {
- uae_u8 *b = (uae_u8 *)regs.branchtarget - SIZE_STORED_ADDRESS_OFFSET;
- addinfo_bytes("B", b, regs.branchtarget, -SIZE_STORED_ADDRESS_OFFSET, SIZE_STORED_ADDRESS);
+ if (r->branchtarget != 0xffffffff && r->srcaddr != r->branchtarget && r->dstaddr != r->branchtarget) {
+ uae_u8 *b = (uae_u8 *)r->branchtarget - SIZE_STORED_ADDRESS_OFFSET;
+ addinfo_bytes("B", b, r->branchtarget, -SIZE_STORED_ADDRESS_OFFSET, SIZE_STORED_ADDRESS);
}
// sprintf(outbp, "STARTPC=%08x ENDPC=%08x\n", startpc, endpc);
// outbp += strlen(outbp);
{ NULL, 0 }
};
-static void out_regs(struct registers *r, int before)
+// r = registers to output
+// r1 = test results
+// r2 = expected results
+// sreg = original registers
+
+static void out_regs(struct registers *r, struct registers *r1, struct registers *r2, struct registers *sreg, int before)
{
if (before) {
for (int i = 0; i < 16; i++) {
strcat(outbp, " ");
}
outbp += strlen(outbp);
- sprintf(outbp, "%c%d:%c%08x", i < 8 ? 'D' : 'A', i & 7, test_regs.regs[i] != last_registers.regs[i] ? '*' : ' ', r->regs[i]);
+ sprintf(outbp, "%c%d:%c%08x", i < 8 ? 'D' : 'A', i & 7, r1->regs[i] != r2->regs[i] ? '*' : ' ', r->regs[i]);
outbp += strlen(outbp);
}
*outbp++ = '\n';
- sprintf(outbp, "SR:%c%04x PC: %08x ISP: %08x", test_sr != last_registers.sr ? '*' : ' ', test_sr, r->pc, r->ssp);
+ sprintf(outbp, "SR:%c%04x PC: %08x ISP: %08x", r1->sr != r2->sr ? '*' : ' ', r->sr, r->pc, r->ssp);
} else {
// output only lines that have at least one modified register to save screen space
for (int i = 0; i < 4; i++) {
int diff = 0;
for (int j = 0; j < 4; j++) {
int idx = i * 4 + j;
- if (test_regs.regs[idx] != regs.regs[idx]) {
+ if (r1->regs[idx] != r2->regs[idx]) {
diff = 1;
}
}
int idx = i * 4 + j;
if (j > 0)
*outbp++ = ' ';
- sprintf(outbp, "%c%d:%c%08x", idx < 8 ? 'D' : 'A', idx & 7, test_regs.regs[idx] != last_registers.regs[idx] ? '*' : ' ', test_regs.regs[idx]);
+ sprintf(outbp, "%c%d:%c%08x", idx < 8 ? 'D' : 'A', idx & 7, r->regs[idx] != r2->regs[idx] ? '*' : ' ', r->regs[idx]);
outbp += strlen(outbp);
}
*outbp++ = '\n';
}
}
- sprintf(outbp, "SR:%c%04x/%04x PC: %08x ISP: %08x", test_sr != last_registers.sr ? '*' : ' ', test_regs.sr, test_regs.expsr, r->pc, r->ssp);
+ sprintf(outbp, "SR:%c%04x/%04x PC: %08x ISP: %08x", r->sr != r2->sr ? '*' : ' ', r->sr, r->expsr, r->pc, r->ssp);
}
outbp += strlen(outbp);
if (cpu_lvl >= 2 && cpu_lvl <= 4) {
outbp += strlen(outbp);
}
*outbp++ = '\n';
+ *outbp = 0;
if (before >= 0) {
- uae_u16 s = before ? test_sr : test_regs.sr; // current value
- uae_u16 s1 = regs.sr; // original value
- uae_u16 s2 = test_regs.sr; // test result value
- uae_u16 s3 = last_registers.sr; // expected result value
+ uae_u16 s = r->sr; // current value
+ uae_u16 s1 = sreg->sr; // original value
+ uae_u16 s2 = r1->sr; // test result value
+ uae_u16 s3 = r2->sr; // expected result value
for (int i = 0; srbits[i].name; i++) {
if (i > 0)
*outbp++ = ' ';
outbp += strlen(outbp);
}
*outbp++ = '\n';
+ *outbp = 0;
}
if (!fpu_model)
return;
- for (int i = 0; i < 8; i++) {
- if (i > 0 && (i % 2) == 0) {
- strcat(outbp, "\n");
+ if (before) {
+ for (int i = 0; i < 8; i++) {
+ if (i > 0 && (i % 2) == 0) {
+ strcat(outbp, "\n");
+ } else if ((i % 4) != 0) {
+ strcat(outbp, " ");
+ }
+ outbp += strlen(outbp);
+ struct fpureg *f = &r->fpuregs[i];
+ void *f1 = &r->fpuregs[i];
+ void *f2 = &r1->fpuregs[i];
+ sprintf(outbp, "FP%d:%c%04x-%08x%08x %f",
+ i,
+ memcmp(f1, f2, sizeof(struct fpureg)) ? '*' : ' ',
+ f->exp, f->m[0], f->m[1],
+ *((long double *)f));
+ outbp += strlen(outbp);
}
- else if ((i % 4) != 0) {
- strcat(outbp, " ");
+ *outbp++ = '\n';
+ *outbp = 0;
+ } else {
+ for (int i = 0; i < 8; i += 2) {
+ struct fpureg *f = &r->fpuregs[i];
+ void *f1 = &r1->fpuregs[i];
+ void *f2 = &r2->fpuregs[i];
+ void *f1b = &r1->fpuregs[i + 1];
+ void *f2b = &r2->fpuregs[i + 1];
+
+ if (memcmp(f1, f2, sizeof(struct fpureg)) || memcmp(f1b, f2b, sizeof(struct fpureg))) {
+ for (int j = 0; j < 2; j++) {
+ f1 = &r->fpuregs[i + j];
+ f2 = &test_regs.fpuregs[i + j];
+ f = &test_regs.fpuregs[i + j];
+ if (j > 0)
+ *outbp++ = ' ';
+ sprintf(outbp, "FP%d:%c%04x-%08x%08x %f",
+ i + j,
+ memcmp(f1, f2, sizeof(struct fpureg)) ? '*' : ' ',
+ f->exp, f->m[0], f->m[1],
+ *((long double *)f));
+ outbp += strlen(outbp);
+ }
+ *outbp++ = '\n';
+ *outbp = 0;
+ }
}
- outbp += strlen(outbp);
- struct fpureg *f = &r->fpuregs[i];
- void *f1 = ®s.fpuregs[i];
- void *f2 = &test_regs.fpuregs[i];
- sprintf(outbp, "FP%d:%c%04x-%08x%08x %f",
- i,
- memcmp(f1, f2, sizeof(struct fpureg)) ? '*' : ' ',
- f->exp, f->m[0], f->m[1],
- *((long double*)f));
- outbp += strlen(outbp);
}
- sprintf(outbp, "\nFPSR:%c%08x FPCR:%c%08x FPIAR:%c%08x\n",
- test_fpsr != last_registers.fpsr ? '*' : ' ', before ? test_fpsr : test_regs.fpsr,
- test_fpcr != last_registers.fpcr ? '*' : ' ', before ? test_fpcr : test_regs.fpcr,
- regs.fpiar != last_registers.fpiar ? '*' : ' ', r->fpiar);
+ sprintf(outbp, "FPSR:%c%08x FPCR:%c%08x FPIAR:%c%08x\n",
+ r->fpsr != r2->fpsr ? '*' : ' ', r->fpsr,
+ r->fpcr != r2->fpcr ? '*' : ' ', r->fpcr,
+ r->fpiar != r2->fpiar ? '*' : ' ', r->fpiar);
outbp += strlen(outbp);
// sr
exc[8] = regs->sr >> 8;
exc[9] = regs->sr;
- // pc
- pl(exc + 10, regs->pc);
+ // program counter
+ v = opcode_memory_addr;
+ p = restore_rel_ordered(p, &v);
+ pl(exc + 10, v);
exclen = 14;
if (basicexcept) {
// I/N field is not always as documented
}
#endif
-static int check_cycles(int exc, short extratrace, short extrag2w1)
+static int check_cycles(int exc, short extratrace, short extrag2w1, struct registers *lregs)
{
int gotcycles = 0;
#endif
}
- int expectedcycles = last_registers.cycles;
+ int expectedcycles = lregs->cycles;
int exceptioncycles = getexceptioncycles(exc);
if (cpu_lvl == 0) {
// move.w CYCLEREG,cycles
return 1;
}
-// regs: registers before execution of test code
-// test_reg: registers used during execution of test code, also modified by test code.
-// last_registers: registers after modifications from data files. Test ok if test_reg == last_registers.
+static short getzobits(uae_u32 *vvp, uae_u8 b)
+{
+ uae_u32 vv[2];
-static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr)
+ vv[0] = vvp[0];
+ vv[1] = vvp[1];
+ // xxxx-yyyyyyy-00000001 <> xxxx-yyyyyyyy-00000000
+ if ((vv[1] & 0x1f) == 0x01) {
+ vv[1] &= ~1;
+ }
+ int bc = 0;
+ for (short i = 1; i >= 0; i--) {
+ uae_u32 v = vv[i];
+ for (short j = 0; j < 32; j++) {
+ if ((v & 1) != b)
+ return bc;
+ v >>= 1;
+ bc++;
+ }
+ }
+ return bc;
+}
+
+// mostly ugly workarounds for logarithmic/trigonometric functions
+// not returning identical values (6888x algorithms are unknown)
+static short fpucheckextra(struct fpureg *f1, struct fpureg *f2)
{
- uae_u8 regs_changed[16] = { 0 };
- uae_u8 regs_fpuchanged[8] = { 0 };
+ if (!is_fpu_adjust)
+ return 0;
+
+ uae_u32 m1[2];
+ uae_u32 m2[2];
+ m1[0] = f1->m[0];
+ m1[1] = f1->m[1];
+ m2[0] = f2->m[0];
+ m2[1] = f2->m[1];
+ uae_u16 exp1 = f1->exp & 0x7fff;
+ uae_u16 exp2 = f2->exp & 0x7fff;
+ // NaN or Infinite: both must match
+ if (exp1 == 0x7fff || exp2 == 0x7fff) {
+ return 0;
+ }
+ // Zero: both must match
+ if ((!exp1 && !m1[0] && !m1[1]) || (!exp2 && !m2[0] && !m2[1])) {
+ return 0;
+ }
+
+ // rounding difference
+ // yyyy-ffffffff-ffffffff <> xxxx+1-80000000-00000000
+ if (exp1 == exp2 + 1 && m1[0] == 0x80000000 && m1[1] == 0x00000000 && (m2[0] & 0xffff0000) == 0xffff0000) {
+ exp1--;
+ m1[0] = m2[0];
+ m1[1] = m2[1];
+ } else if (exp2 == exp1 + 1 && m2[0] == 0x80000000 && m2[1] == 0x00000000 && (m1[0] & 0xffff0000) == 0xffff0000) {
+ exp2--;
+ m2[0] = m1[0];
+ m2[1] = m1[1];
+ }
+
+ if (fpu_adjust_exp >= 0) {
+ if (abs(exp1 - exp2) > fpu_adjust_exp)
+ return 0;
+ }
+
+ // Some functions return xxxxxxxx-xxxxx800
+ // ...f800 -> ...ffff
+ // ...0800 -> ...0000
+ if ((m1[1] & 0xffff) == 0x0800) {
+ m1[1] &= ~0xffff;
+ }
+ if ((m1[1] & 0xffff) == 0xf800) {
+ m1[1] |= 0xffff;
+ }
+ if ((m2[1] & 0xffff) == 0x0800) {
+ m2[1] &= ~0xffff;
+ }
+ if ((m2[1] & 0xffff) == 0xf800) {
+ m2[1] |= 0xffff;
+ }
+
+ short zb1 = getzobits(m1, 0);
+ short zb2 = getzobits(m2, 0);
+ short ob1 = getzobits(m1, 1);
+ short ob2 = getzobits(m2, 1);
+
+ // if another value ends to multiple zero bits
+ // and another to multiple one bits:
+ // skip it.
+ if (zb1 >= 4 && ob2 >= 4 && !zb2) {
+ zb2 = zb1;
+ } else if (zb2 >= 4 && ob1 >= 4 && !zb1) {
+ zb1 = zb2;
+ }
+
+ if (fpu_adjust_zb >= 0) {
+
+ if (abs(zb1 - zb2) > fpu_adjust_zb)
+ return 0;
+ }
+
+ // skip n bits from the end
+ if (fpu_adjust_man >= 0) {
+ short shift = zb1 < zb2 ? zb1 : zb2;
+ short startm = 1;
+ if (shift >= 32) {
+ startm = 0;
+ shift -= 32;
+ }
+
+ short diff = 0;
+ for (short i = startm; i >= 0; i--) {
+ while (shift < 32) {
+ short v1 = (m1[i] >> shift) & 1;
+ short v2 = (m2[i] >> shift) & 1;
+ if (v1 != v2) {
+ diff++;
+ if (diff > fpu_adjust_man) {
+ return 0;
+ }
+ }
+ shift++;
+ }
+ shift = 0;
+ }
+ }
+
+ fpu_approx++;
+ return 1;
+}
+
+// sregs: registers before execution of test code
+// tregs: registers used during execution of test code, also modified by test code.
+// lregs: registers after modifications from data files. Test ok if tregs == lregs.
+
+static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr, struct registers *sregs, struct registers *tregs, struct registers *lregs, int opcodeendsizeextra)
+{
+ uae_u8 regs_changed[16] = { 0 }, regs_changed_any = 0;
+ uae_u8 regs_fpuchanged[8] = { 0 }, regs_fpuchanged_any = 0;
uae_u8 sr_changed = 0, ccr_changed = 0, pc_changed = 0;
uae_u8 fpiar_changed = 0, fpsr_changed = 0, fpcr_changed = 0;
short exc = -1;
- for (int i = 0; i < 16; i++) {
- if (last_registers.regs[i] != test_regs.regs[i]) {
+ // Register modified in test? (start register != test register)
+ for (short i = 0; i < 16; i++) {
+ if (sregs->regs[i] != tregs->regs[i]) {
regs_changed[i] = 1;
+ regs_changed_any = 1;
}
}
- if ((last_registers.sr & test_ccrignoremask & 0xff00) != (test_regs.sr & test_ccrignoremask & 0xff00)) {
+ if ((sregs->sr & test_ccrignoremask & 0xff00) != (tregs->sr & test_ccrignoremask & 0xff00)) {
sr_changed = 1;
}
- if ((last_registers.sr & test_ccrignoremask & 0x00ff) != (test_regs.sr & test_ccrignoremask & 0x00ff)) {
+ if ((sregs->sr & test_ccrignoremask & 0x00ff) != (tregs->sr & test_ccrignoremask & 0x00ff)) {
ccr_changed = 1;
}
- if (last_registers.pc != test_regs.pc) {
+ if (sregs->pc + opcodeendsizeextra != tregs->pc) {
pc_changed = 1;
}
if (fpu_model) {
- for (int i = 0; i < 8; i++) {
- if (memcmp(&last_registers.fpuregs[i], &test_regs.fpuregs[i], sizeof(struct fpureg))) {
+ for (short i = 0; i < 8; i++) {
+ if (memcmp(&sregs->fpuregs[i], &tregs->fpuregs[i], sizeof(struct fpureg))) {
regs_fpuchanged[i] = 1;
+ regs_fpuchanged_any = 1;
}
}
- if (last_registers.fpsr != test_regs.fpsr) {
+ if (sregs->fpsr != tregs->fpsr) {
fpsr_changed = 1;
}
- if (last_registers.fpcr != test_regs.fpcr) {
+ if (sregs->fpcr != tregs->fpcr) {
fpcr_changed = 1;
}
- if (last_registers.fpiar != test_regs.fpiar) {
+ if (sregs->fpiar != tregs->fpiar) {
fpiar_changed = 1;
}
}
uae_u8 v = *p;
if (v & CT_END) {
exc = v & CT_EXCEPTION_MASK;
- short cpuexc = test_regs.exc & 65535;
- short cpuexc010 = test_regs.exc010 & 65535;
+ short cpuexc = tregs->exc & 65535;
+ short cpuexc010 = tregs->exc010 & 65535;
p++;
if ((v & CT_END_INIT) == CT_END_INIT) {
end_test();
}
if (exc == 0 && cpuexc == 4) {
// successful complete generates exception 4 with matching PC
- if (last_registers.pc != test_regs.pc && dooutput) {
- sprintf(outbp, "PC: expected %08x but got %08x\n", last_registers.pc, test_regs.pc);
+ if (lregs->pc + opcodeendsizeextra != tregs->pc && dooutput) {
+ sprintf(outbp, "PC: expected %08x but got %08x\n", lregs->pc, tregs->pc);
outbp += strlen(outbp);
- if (test_regs.pc == opcode_memory_addr) {
+ if (tregs->pc == opcode_memory_addr) {
sprintf(outbp, "Got unexpected exception %d (unsupported instruction?)\n", cpuexc);
} else {
sprintf(outbp, "Got unexpected exception %d\n", cpuexc);
}
if (exc != cpuexc && exc >= 2) {
if (dooutput) {
- if (cpuexc == 4 && last_registers.pc == test_regs.pc) {
+ if (cpuexc == 4 && lregs->pc + opcodeendsizeextra == tregs->pc) {
sprintf(outbp, "Exception: expected %d but got no exception.\n", exc);
} else if (cpuexc == 4) {
sprintf(outbp, "Exception: expected %d but got %d (or no exception)\n", exc, cpuexc);
short mode = v & CT_DATA_MASK;
if (mode < CT_AREG + 8 && (v & CT_SIZE_MASK) != CT_SIZE_FPU) {
- uae_u32 val = last_registers.regs[mode];
+ uae_u32 val = lregs->regs[mode];
int size;
p = restore_value(p, &val, &size);
- if (val != test_regs.regs[mode] && !ignore_errors && !skipregchange) {
- if (dooutput) {
- if (regs.regs[mode] == test_regs.regs[mode]) {
- sprintf(outbp, "%c%d: expected %08x but register was not modified\n", mode < CT_AREG ? 'D' : 'A', mode & 7, val);
- } else {
- sprintf(outbp, "%c%d: expected %08x but got %08x\n", mode < CT_AREG ? 'D' : 'A', mode & 7, val, test_regs.regs[mode]);
+ if (val != tregs->regs[mode]) {
+ if (!ignore_errors && !skipregchange) {
+ if (dooutput) {
+ if (sregs->regs[mode] == tregs->regs[mode]) {
+ sprintf(outbp, "%c%d: expected %08x but register was not modified\n", mode < CT_AREG ? 'D' : 'A', mode & 7, val);
+ } else {
+ sprintf(outbp, "%c%d: expected %08x but got %08x\n", mode < CT_AREG ? 'D' : 'A', mode & 7, val, tregs->regs[mode]);
+ }
+ outbp += strlen(outbp);
}
- outbp += strlen(outbp);
+ errflag |= 1 << 0;
}
- errflag |= 1 << 0;
}
+ lregs->regs[mode] = val;
regs_changed[mode] = 0;
- last_registers.regs[mode] = val;
- } else if (mode < CT_AREG && (v & CT_SIZE_MASK) == CT_SIZE_FPU && !skipregchange) {
+ } else if (mode < CT_AREG && (v & CT_SIZE_MASK) == CT_SIZE_FPU) {
struct fpureg val;
+ memcpy(&val, &lregs->fpuregs[mode], sizeof(struct fpureg));
p = restore_fpvalue(p, &val);
- if (memcmp(&val, &test_regs.fpuregs[mode], sizeof(struct fpureg)) && !ignore_errors) {
- if (dooutput) {
- if (regs.fpuregs[mode].m[0] == test_regs.fpuregs[mode].m[0] &&
- regs.fpuregs[mode].m[1] == test_regs.fpuregs[mode].m[1] &&
- regs.fpuregs[mode].exp == test_regs.fpuregs[mode].exp) {
- sprintf(outbp, "FP%d: expected %04x-%08x%08x but register was not modified\n", mode,
- val.exp, val.m[0], val.m[1]);
- } else {
- sprintf(outbp, "FP%d: expected %04x-%08x%08x but got %04x-%08x%08x\n", mode,
- val.exp, val.m[0], val.m[1],
- test_regs.fpuregs[mode].exp, test_regs.fpuregs[mode].m[0], test_regs.fpuregs[mode].m[1]);
+ if (memcmp(&val, &tregs->fpuregs[mode], sizeof(struct fpureg))) {
+ if (!ignore_errors && !skipregchange && !fpucheckextra(&val, &tregs->fpuregs[mode])) {
+ if (dooutput) {
+ if (!memcmp(&sregs->fpuregs, &tregs->fpuregs[mode], sizeof(struct fpureg))) {
+ sprintf(outbp, "FP%d: expected %04x-%08x%08x but register was not modified\n", mode,
+ val.exp, val.m[0], val.m[1]);
+ } else {
+ sprintf(outbp, "FP%d: expected %04x-%08x%08x but got %04x-%08x%08x\n", mode,
+ val.exp, val.m[0], val.m[1],
+ tregs->fpuregs[mode].exp, tregs->fpuregs[mode].m[0], tregs->fpuregs[mode].m[1]);
+ }
+ outbp += strlen(outbp);
}
- outbp += strlen(outbp);
+ errflag |= 1 << 1;
}
- errflag |= 1 << 1;
}
+ memcpy(&lregs->fpuregs[mode], &val, sizeof(struct fpureg));
regs_fpuchanged[mode] = 0;
- xmemcpy(&last_registers.fpuregs[mode], &val, sizeof(struct fpureg));
} else if (mode == CT_SR) {
- uae_u32 val = last_registers.sr;
+ uae_u32 val = lregs->sr;
int size;
// High 16 bit: ignore mask, low 16 bit: SR/CCR
p = restore_value(p, &val, &size);
test_ccrignoremask = ~(val >> 16);
- if ((val & (sr_undefined_mask & test_ccrignoremask)) != (test_regs.sr & (sr_undefined_mask & test_ccrignoremask)) && !ignore_errors && !ignore_sr) {
+ if ((val & (sr_undefined_mask & test_ccrignoremask)) != (tregs->sr & (sr_undefined_mask & test_ccrignoremask)) && !ignore_errors && !ignore_sr) {
if (dooutput) {
- sprintf(outbp, "SR: expected %04x -> %04x but got %04x", test_sr & 0xffff, val & 0xffff, test_regs.sr & 0xffff);
+ sprintf(outbp, "SR: expected %04x -> %04x but got %04x", sregs->sr & 0xffff, val & 0xffff, tregs->sr & 0xffff);
outbp += strlen(outbp);
if (test_ccrignoremask != 0xffff) {
sprintf(outbp, " (%04x)", test_ccrignoremask);
}
// SR check
uae_u16 mask = test_ccrignoremask & 0xff00;
- if ((val & (sr_undefined_mask & mask)) == (test_regs.sr & (sr_undefined_mask & mask))) {
+ if ((val & (sr_undefined_mask & mask)) == (tregs->sr & (sr_undefined_mask & mask))) {
errflag &= ~(1 << 2);
}
// CCR check
mask = test_ccrignoremask & 0x00ff;
- if (skipccrchange || ((val & (sr_undefined_mask & mask)) == (test_regs.sr & (sr_undefined_mask & mask)))) {
+ if (skipccrchange || ((val & (sr_undefined_mask & mask)) == (tregs->sr & (sr_undefined_mask & mask)))) {
errflag &= ~(1 << 7);
}
}
sr_changed = 0;
ccr_changed = 0;
- last_registers.sr = val;
- if (!(test_regs.expsr & 0x2000)) {
+ if (!(tregs->expsr & 0x2000)) {
sprintf(outbp, "SR S-bit is not set at start of exception handler!\n");
outbp += strlen(outbp);
errflag |= 1 << 16;
}
- if ((test_regs.expsr & 0xff) != (test_regs.sr & 0xff)) {
+ if ((tregs->expsr & 0xff) != (tregs->sr & 0xff)) {
sprintf(outbp, "Exception stacked CCR != CCR at start of exception handler!\n");
outbp += strlen(outbp);
errflag |= 1 << 16;
}
-
+ lregs->sr = val;
} else if (mode == CT_PC) {
- uae_u32 val = last_registers.pc;
+ uae_u32 val = lregs->pc;
p = restore_rel(p, &val, 0);
pc_changed = 0;
- last_registers.pc = val;
+ lregs->pc = val;
} else if (mode == CT_CYCLES) {
- uae_u32 val = last_registers.cycles;
+ uae_u32 val = lregs->cycles;
int size;
p = restore_value(p, &val, &size);
- last_registers.cycles = val;
+ lregs->cycles = val;
gotcycles = 1;
} else if (mode == CT_FPCR) {
- uae_u32 val = last_registers.fpcr;
+ uae_u32 val = lregs->fpcr;
int size;
p = restore_value(p, &val, &size);
- if (val != test_regs.fpcr && !ignore_errors) {
- if (dooutput) {
- if (regs.fpcr == test_regs.fpcr) {
- sprintf(outbp, "FPCR: expected %08x but register was not modified\n", val);
- } else {
- sprintf(outbp, "FPCR: expected %08x -> %08x but got %08x\n", test_fpcr, val, test_regs.fpcr);
+ if (val != tregs->fpcr) {
+ if (!ignore_errors) {
+ if (dooutput) {
+ if (sregs->fpcr == tregs->fpcr) {
+ sprintf(outbp, "FPCR: expected %08x but register was not modified\n", val);
+ } else {
+ sprintf(outbp, "FPCR: expected %08x -> %08x but got %08x\n", sregs->fpcr, val, tregs->fpcr);
+ }
+ outbp += strlen(outbp);
}
- outbp += strlen(outbp);
+ errflag |= 1 << 3;
}
- errflag |= 1 << 3;
}
+ lregs->fpcr = val;
fpcr_changed = 0;
- last_registers.fpcr = val;
} else if (mode == CT_FPSR) {
- uae_u32 val = last_registers.fpsr;
+ uae_u32 val = lregs->fpsr;
int size;
p = restore_value(p, &val, &size);
- if (val != test_regs.fpsr && !ignore_errors) {
- if (dooutput) {
- if (regs.fpsr == test_regs.fpsr) {
- sprintf(outbp, "FPSR: expected %08x but register was not modified\n", val);
- } else {
- sprintf(outbp, "FPSR: expected %08x -> %08x but got %08x\n", test_fpsr, val, test_regs.fpsr);
+ if (val != tregs->fpsr) {
+ if (!ignore_errors) {
+ if (dooutput) {
+ if (sregs->fpsr == tregs->fpsr) {
+ sprintf(outbp, "FPSR: expected %08x but register was not modified\n", val);
+ } else {
+ sprintf(outbp, "FPSR: expected %08x -> %08x but got %08x\n", sregs->fpsr, val, tregs->fpsr);
+ }
+ outbp += strlen(outbp);
}
- outbp += strlen(outbp);
+ errflag |= 1 << 4;
}
- errflag |= 1 << 4;
}
+ lregs->fpsr = val;
fpsr_changed = 0;
- last_registers.fpsr = val;
} else if (mode == CT_FPIAR) {
- uae_u32 val = last_registers.fpiar;
+ uae_u32 val = lregs->fpiar;
int size;
p = restore_value(p, &val, &size);
- if (val != test_regs.fpiar && !ignore_errors) {
- if (dooutput) {
- if (regs.fpiar == test_regs.fpiar) {
- sprintf(outbp, "FPIAR: expected %08x but register was not modified\n", val);
- } else {
- sprintf(outbp, "FPIAR: expected %08x but got %08x\n", val, test_regs.fpiar);
+ if (val != tregs->fpiar) {
+ if (!ignore_errors) {
+ if (dooutput) {
+ if (sregs->fpiar == tregs->fpiar) {
+ sprintf(outbp, "FPIAR: expected %08x but register was not modified\n", val);
+ } else {
+ sprintf(outbp, "FPIAR: expected %08x but got %08x\n", val, tregs->fpiar);
+ }
+ outbp += strlen(outbp);
}
- outbp += strlen(outbp);
+ errflag |= 1 << 5;
}
- errflag |= 1 << 5;
}
+ lregs->fpiar = val;
fpiar_changed = 0;
- last_registers.fpiar = val;
-
} else if (mode == CT_MEMWRITES) {
p = restore_memory(p, 0);
} else if (mode == CT_MEMWRITE) {
}
}
if (!ignore_errors) {
- if (!skipregchange) {
- for (int i = 0; i < 16; i++) {
- if (regs_changed[i]) {
+ if (!skipregchange && regs_changed_any) {
+ for (short mode = 0; mode < 16; mode++) {
+ if (regs_changed[mode] && tregs->regs[mode] != lregs->regs[mode]) {
if (dooutput) {
- sprintf(outbp, "%c%d: modified %08x -> %08x but expected no modifications\n", i < 8 ? 'D' : 'A', i & 7, last_registers.regs[i], test_regs.regs[i]);
- outbp += strlen(outbp);
+ uae_u32 val = lregs->regs[mode];
+ sprintf(outbp, "%c%d: expected %08x but got %08x\n", mode < CT_AREG ? 'D' : 'A', mode & 7, val, tregs->regs[mode]);
}
errflag |= 1 << 0;
}
}
}
if (!ignore_sr) {
- if (sr_changed) {
+ if (sr_changed && tregs->sr != lregs->sr) {
if (dooutput) {
- sprintf(outbp, "SR: modified %04x -> %04x but expected no modifications\n", last_registers.sr & 0xffff, test_regs.sr & 0xffff);
+ sprintf(outbp, "SR: modified %04x -> %04x but expected %04x\n", sregs->sr & 0xffff, tregs->sr & 0xffff, lregs->sr & 0xffff);
outbp += strlen(outbp);
}
errflag |= 1 << 2;
- } else if (ccr_changed && !skipccrchange) {
+ } else if (ccr_changed && !skipccrchange && (tregs->sr & 0xff) != (lregs->sr & 0xff)) {
if (dooutput) {
- sprintf(outbp, "SR: modified %04x -> %04x but expected no modifications\n", last_registers.sr & 0xffff, test_regs.sr & 0xffff);
+ sprintf(outbp, "SR: modified %04x -> %04x but expected %04x\n", sregs->sr & 0xffff, tregs->sr & 0xffff, lregs->sr & 0xffff);
outbp += strlen(outbp);
}
errflag |= 1 << 2;
}
}
- if (!skipregchange) {
- for (int i = 0; i < 8; i++) {
- if (regs_fpuchanged[i]) {
- if (dooutput) {
- sprintf(outbp, "FP%d: modified %04x-%08x%08x -> %04x-%08x%08x but expected no modifications\n", i,
- last_registers.fpuregs[i].exp, last_registers.fpuregs[i].m[0], last_registers.fpuregs[i].m[1],
- test_regs.fpuregs[i].exp, test_regs.fpuregs[i].m[0], test_regs.fpuregs[i].m[1]);
- outbp += strlen(outbp);
+ if (!skipregchange && regs_fpuchanged_any) {
+ for (short mode = 0; mode < 8; mode++) {
+ if (regs_fpuchanged[mode] && memcmp(&tregs->fpuregs[mode], &lregs->fpuregs[mode], sizeof(struct fpureg))) {
+ if (!fpucheckextra(&tregs->fpuregs[mode], &lregs->fpuregs[mode])) {
+ if (dooutput) {
+ struct fpureg *val = &lregs->fpuregs[mode];
+ sprintf(outbp, "FP%d: expected %04x-%08x%08x but got %04x-%08x%08x\n", mode,
+ val->exp, val->m[0], val->m[1],
+ tregs->fpuregs[mode].exp, tregs->fpuregs[mode].m[0], tregs->fpuregs[mode].m[1]);
+ outbp += strlen(outbp);
+ }
+ errflag |= 1 << 1;
}
- errflag |= 1 << 1;
}
}
}
if (!ignore_sr) {
- if (fpsr_changed) {
+ if (fpsr_changed && tregs->fpsr != lregs->fpsr) {
if (dooutput) {
- sprintf(outbp, "FPSR: modified %08x -> %08x but expected no modifications\n", last_registers.fpsr, test_regs.fpsr);
+ uae_u32 val = lregs->fpsr;
+ sprintf(outbp, "FPSR: expected %08x -> %08x but got %08x\n", sregs->fpsr, val, tregs->fpsr);
outbp += strlen(outbp);
}
errflag |= 1 << 3;
}
}
- if (fpcr_changed) {
+ if (fpcr_changed && tregs->fpcr != lregs->fpcr) {
if (dooutput) {
- sprintf(outbp, "FPCR: modified %08x -> %08x but expected no modifications\n", last_registers.fpcr, test_regs.fpcr);
+ uae_u32 val = lregs->fpcr;
+ sprintf(outbp, "FPCR: expected %08x -> %08x but got %08x\n", sregs->fpcr, val, tregs->fpcr);
outbp += strlen(outbp);
}
errflag |= 1 << 4;
}
- if (fpiar_changed) {
+ if (fpiar_changed && tregs->fpiar != lregs->fpiar) {
if (dooutput) {
- sprintf(outbp, "FPIAR: modified %08x -> %08x but expected no modifications\n", last_registers.fpiar, test_regs.fpiar);
+ uae_u32 val = lregs->fpiar;
+ sprintf(outbp, "FPIAR: expected %08x but got %08x\n", val, tregs->fpiar);
outbp += strlen(outbp);
}
errflag |= 1 << 5;
outbp += strlen(outbp);
}
} else {
- if (!check_cycles(exc, extratrace, extrag2w1)) {
+ if (!check_cycles(exc, extratrace, extrag2w1, lregs)) {
errflag |= 1 << 8;
}
}
strcpy(outbp, outbuffer2);
strcat(outbp, "Registers before:\n");
outbp += strlen(outbp);
- out_regs(®s, 1);
+ out_regs(sregs, tregs, lregs, sregs, 1);
strcat(outbp, "Registers after:\n");
outbp += strlen(outbp);
- out_regs(&test_regs, 0);
+ out_regs(tregs, tregs, lregs, sregs, 0);
if (exc > 1) {
if (!experr) {
sprintf(outbp, "OK: exception %d ", exc);
((test_regs.exc >> (16 + 0)) & 7));
outbp += strlen(outbp);
}
- } else if (exc == 0 && (test_regs.exc & 65535) == 4 && last_registers.pc == test_regs.pc) {
+ } else if (exc == 0 && (test_regs.exc & 65535) == 4 && lregs->pc == test_regs.pc) {
sprintf(outbp, "OK: No exception generated\n");
outbp += strlen(outbp);
}
return p;
}
+static void out_endinfo(void)
+{
+ sprintf(outbp, "%u (%u/%u) ", testcnt, testcntsub, testcntsubmax);
+ outbp += strlen(outbp);
+ sprintf(outbp, "S=%d", supercnt);
+ outbp += strlen(outbp);
+ for (int i = 0; i < 128; i++) {
+ if (exceptioncount[0][i] || exceptioncount[1][i] || exceptioncount[2][i]) {
+ if (i == 2 || i == 3) {
+ sprintf(outbp, " E%02d=%d/%d/%d", i, exceptioncount[0][i], exceptioncount[1][i], exceptioncount[2][i]);
+ } else {
+ sprintf(outbp, " E%02d=%d", i, exceptioncount[0][i]);
+ }
+ outbp += strlen(outbp);
+ }
+ }
+ strcat(outbp, "\n");
+ outbp += strlen(outbp);
+ if (fpu_approxcnt) {
+ sprintf(outbp, "FPU approximate matches: %d\n", fpu_approxcnt);
+ }
+ supercnt = 0;
+ memset(exceptioncount, 0, sizeof(exceptioncount));
+}
+
static void store_addr(uae_u32 s, uae_u8 *d)
{
if (s == 0xffffffff)
return xorshiftstate;
}
+static void copyregs(struct registers *d, struct registers *s, short fpumode)
+{
+ memcpy(&d->regs[0], &s->regs[0], offsetof(struct registers, cycles));
+ if (fpumode) {
+ memcpy(&d->fpuregs[0], &s->fpuregs[0], offsetof(struct registers, fsave) - offsetof(struct registers, fpuregs));
+ }
+}
+
static void process_test(uae_u8 *p)
{
outbp = outbuffer2;
infoadded = 0;
errors = 0;
- memset(®s, 0, sizeof(struct registers));
- regs.sr = interrupt_mask << 8;
- regs.srcaddr = 0xffffffff;
- regs.dstaddr = 0xffffffff;
- regs.branchtarget = 0xffffffff;
+ memset(&cur_regs, 0, sizeof(struct registers));
+ cur_regs.sr = interrupt_mask << 8;
+ cur_regs.srcaddr = 0xffffffff;
+ cur_regs.dstaddr = 0xffffffff;
+ cur_regs.branchtarget = 0xffffffff;
if (safe_memory_mode) {
set_berr(safe_memory_mode, 0);
for (;;) {
- regs.endpc = endpc;
- regs.pc = startpc;
+ cur_regs.endpc = endpc;
+ cur_regs.pc = startpc;
for (;;) {
uae_u8 v = *p;
if (v == CT_END_INIT || v == CT_END_FINISH)
break;
- p = restore_data(p);
+ p = restore_data(p, &cur_regs);
}
if (*p == CT_END_FINISH)
break;
p++;
int stackcopysize = 0;
- for (int i = 0; i < 32; i += 2) {
- if (!is_valid_test_addr_readwrite(regs.regs[15] + i))
+ for (short i = 0; i < 32; i += 2) {
+ if (!is_valid_test_addr_readwrite(cur_regs.regs[15] + i))
break;
stackcopysize += 2;
}
- store_addr(regs.srcaddr, srcaddr);
- store_addr(regs.dstaddr, dstaddr);
- store_addr(regs.branchtarget, branchtarget);
- startpc = regs.pc;
- endpc = regs.endpc;
+ store_addr(cur_regs.srcaddr, srcaddr);
+ store_addr(cur_regs.dstaddr, dstaddr);
+ store_addr(cur_regs.branchtarget, branchtarget);
+ startpc = cur_regs.pc;
+ endpc = cur_regs.endpc;
uae_u8 *opcode_memory_end = (uae_u8*)endpc;
- xmemcpy(&last_registers, ®s, sizeof(struct registers));
-
int fpumode = fpu_model && (opcode_memory[0] & 0xf0) == 0xf0;
+ copyregs(&last_regs, &cur_regs, fpumode);
+
uae_u32 originalopcodeend = 0x4afc4e71;
+ short opcodeendsizeextra = 0;
uae_u32 opcodeend = originalopcodeend;
int extraccr = 0;
int validendsize = 0;
validendsize = 1;
}
- uae_u32 last_pc = startpc;
- uae_u32 last_fpiar = startpc;
int old_super = -1;
for (;;) {
uae_u8 ccrmode = *p++;
int maxccr = ccrmode & 0x3f;
- for (int ccr = 0; ccr < maxccr; ccr++) {
+ testcntsubmax = maxccr;
+ testcntsub = 0;
+ for (short ccr = 0; ccr < maxccr; ccr++, testcntsub++) {
+
+ copyregs(&test_regs, &cur_regs, fpumode);
+ fpu_approx = 0;
opcodeend = (opcodeend >> 16) | (opcodeend << 16);
+ opcodeendsizeextra = opcodeendsizeextra ? 0 : 2;
if (validendsize == 2) {
pl(opcode_memory_end, opcodeend);
} else if (validendsize == 1) {
pw(opcode_memory_end, opcodeend >> 16);
}
- if (regs.branchtarget != 0xffffffff && !(regs.branchtarget & 1)) {
- if (regs.branchtarget_mode == 1) {
- uae_u32 bv = gl((uae_u8*)regs.branchtarget);
+ if (test_regs.branchtarget != 0xffffffff && !(test_regs.branchtarget & 1)) {
+ if (test_regs.branchtarget_mode == 1) {
+ uae_u32 bv = gl((uae_u8*)test_regs.branchtarget);
bv = (bv >> 16) | (bv << 16);
- pl((uae_u8*)regs.branchtarget, bv);
- } else if (regs.branchtarget_mode == 2) {
- uae_u16 bv = gw((uae_u8 *)regs.branchtarget);
+ pl((uae_u8*)test_regs.branchtarget, bv);
+ } else if (test_regs.branchtarget_mode == 2) {
+ uae_u16 bv = gw((uae_u8 *)test_regs.branchtarget);
if (bv == 0x4e71)
bv = 0x4afc;
else
bv = 0x4e71;
- pw((uae_u8 *)regs.branchtarget, bv);
+ pw((uae_u8 *)test_regs.branchtarget, bv);
}
}
- regs.ssp = super_stack_memory - 0x80;
- regs.msp = super_stack_memory;
- regs.pc = startpc;
- regs.fpiar = startpc;
- regs.cyclest = 0xffffffff;
- regs.fpeaset = 0;
+ test_regs.ssp = super_stack_memory - 0x80;
+ test_regs.msp = super_stack_memory;
+ test_regs.pc = startpc;
+ test_regs.fpiar = startpc;
+ test_regs.cyclest = 0xffffffff;
+ test_regs.fpeaset = 0;
#ifdef M68K
if (stackcopysize > 0)
- xmemcpy((void*)regs.ssp, (void*)regs.regs[15], stackcopysize);
+ xmemcpy((void*)test_regs.ssp, (void*)test_regs.regs[15], stackcopysize);
#endif
- xmemcpy(&test_regs, ®s, sizeof(struct registers));
-
if (maxccr >= 32) {
test_regs.sr = ccr & 0xff;
} else {
test_regs.sr = (ccr & 1) ? 31 : 0;
}
test_regs.sr |= sr_mask | (interrupt_mask << 8);
- test_regs.expsr = test_regs.sr | 0x2000;
- test_sr = test_regs.sr;
if (fpumode) {
test_regs.fpcr = 0;
test_regs.fpsr = 0;
test_regs.fpcr = (ccr & 15) << 4;
}
}
- test_fpsr = test_regs.fpsr;
- test_fpcr = test_regs.fpcr;
}
+
+ while ((*p) == CT_OVERRIDE_REG) {
+ p++;
+ uae_u8 v = *p++;
+ uae_u8 r = v & CT_DATA_MASK;
+ uae_u8 size = v & CT_SIZE_MASK;
+ if (r == CT_SR) {
+ if (size == CT_SIZE_BYTE) {
+ test_regs.sr &= 0xff00;
+ test_regs.sr |= *p++;
+ } else {
+ test_regs.sr = (*p++) << 8;
+ test_regs.sr |= *p++;
+ }
+ cur_regs.sr = test_regs.sr;
+ } else if (r == CT_FPSR) {
+ cur_regs.fpsr = test_regs.fpsr = gl(p);
+ p += 4;
+ } else if (r == CT_FPCR) {
+ cur_regs.fpcr = test_regs.fpcr = gl(p);
+ p += 4;
+ } else if (r == CT_FPIAR) {
+ cur_regs.fpiar = test_regs.fpiar = gl(p);
+ p += 4;
+ } else if (r >= CT_DREG && r < CT_DREG + 16) {
+ if (size == CT_SIZE_FPU) {
+ struct fpureg *f = &test_regs.fpuregs[r - CT_DREG];
+ uae_u32 val = gl(p);
+ f->exp = val >> 16;
+ f->dummy = val;
+ f->m[0] = gl(p + 4);
+ f->m[1] = gl(p + 8);
+ p += 12;
+ } else {
+ cur_regs.regs[r - CT_DREG] = gl(p);
+ p += 4;
+ }
+ } else {
+ end_test();
+ printf("Unknown override register %02x!\n", v);
+ exit(0);
+ }
+ }
+
+ test_regs.expsr = test_regs.sr | 0x2000;
+
+ // internally modified registers become part of cur_regs
+ cur_regs.sr = test_regs.sr;
+ cur_regs.expsr = test_regs.expsr;
+ cur_regs.fpsr = test_regs.fpsr;
+ cur_regs.fpcr = test_regs.fpcr;
+ if (!sr_mask && !ccr) {
+ last_regs.sr = test_regs.sr;
+ last_regs.expsr = test_regs.expsr;
+ last_regs.fpsr = test_regs.fpsr;
+ last_regs.fpcr = test_regs.fpcr;
+ }
+
int super = (test_regs.sr & 0x2000) != 0;
if (super != old_super) {
- stackaddr_ptr = super ? regs.ssp : regs.regs[15];
+ stackaddr_ptr = super ? test_regs.ssp : test_regs.regs[15];
store_addr(stackaddr_ptr, stackaddr);
old_super = super;
}
addinfo();
strcat(outbp, "Registers before:\n");
outbp += strlen(outbp);
- out_regs(®s, 1);
+ out_regs(&cur_regs, &test_regs, &last_regs, &cur_regs, 1);
end_test();
printf(outbuffer);
printf("\nExit count expired\n");
volatile int *tn = (volatile int*)0x100;
*tn = testcnt;
#endif
+#if 0
+ uae_u32 *sx = (uae_u32 *)startpc;
+ if (*sx == 0xf2364c98) {
+ volatile uae_u16 *tn = (volatile uae_u16*)0x70000;
+ *tn = 0x1234;
+ }
+#endif
+
#ifdef AMIGA
if (interrupttest) {
set_interrupt();
}
#endif
-
if (cpu_lvl == 1) {
execute_test010(&test_regs);
} else if (cpu_lvl >= 2) {
} else {
- test_regs.sr = test_sr;
- test_regs.fpsr = test_fpsr;
ignore_errors = 1;
ignore_sr = 1;
}
- last_registers.pc = last_pc;
- last_registers.fpiar = last_fpiar;
-
+#if 0
if ((*p) == CT_SKIP_REGS) {
p++;
for (int i = 0; i < 16; i++) {
}
}
}
+#endif
- p = validate_test(p, ignore_errors, ignore_sr);
+ p = validate_test(p, ignore_errors, ignore_sr, &cur_regs, &test_regs, &last_regs, opcodeendsizeextra);
testcnt++;
if (super)
supercnt++;
- last_pc = last_registers.pc;
- last_fpiar = last_registers.fpiar;
}
if (testexit()) {
exit(0);
}
+ if (fpu_approx) {
+ fpu_approxcnt++;
+ }
+
if (quit || errors) {
- if (continue_on_error) {
- // always abort if buffer is getting too small
- if (outbp - outbuffer >= outbuffer_size - 3000)
+ if (!quit && errorcnt > 0 && totalerrors < errorcnt) {
+ if (totalerrors > 0) {
+ strcat(stored_outbuffer, "----------------------------------------\n");
+ }
+ if (strlen(stored_outbuffer) + strlen(outbuffer) + 40 >= outbuffer_size) {
goto end;
+ }
+ strcat(stored_outbuffer, outbuffer);
+ outbp = stored_outbuffer + strlen(stored_outbuffer);
+ out_endinfo();
+ infoadded = 0;
+ errors = 0;
+ outbuffer[0] = 0;
+ outbuffer2[0] = 0;
+ outbp = outbuffer2;
} else {
goto end;
}
+ totalerrors++;
}
}
end_test();
set_berr(0, 0);
- if (infoadded) {
- printf("\n");
- printf(outbuffer);
+ if (errorcnt > 0) {
+ printf("%s", stored_outbuffer);
+ } else {
+ if (infoadded) {
+ printf("\n");
+ printf("%s", outbuffer);
+ }
}
}
printf("%s (%s):\n", inst_name, group);
testcnt = 0;
+ fpu_approxcnt = 0;
memset(exceptioncount, 0, sizeof(exceptioncount));
supercnt = 0;
filecnt++;
}
- printf("%u ", testcnt);
- printf("S=%d", supercnt);
- for (int i = 0; i < 128; i++) {
- if (exceptioncount[0][i] || exceptioncount[1][i] || exceptioncount[2][i]) {
- if (i == 2 || i == 3) {
- printf(" E%02d=%d/%d/%d", i, exceptioncount[0][i], exceptioncount[1][i], exceptioncount[2][i]);
- } else {
- printf(" E%02d=%d", i, exceptioncount[0][i]);
- }
- }
+ if (errorcnt == 0) {
+ outbp = outbuffer;
+ out_endinfo();
+ printf("%s", outbuffer);
}
- printf("\n");
if (!errors && !quit) {
printf("All tests complete (total %u).\n", testcnt);
printf("all <mnemonic> = test all, starting from <mnemonic>\n");
printf("all <mnemonic> -next = test all, starting after <mnemonic>\n");
printf("-continue = don't stop on error (continue to next test, all mode only)\n");
- printf("-nostop = don't stop on error (continue current instruction)\n");
+ printf("-errors n = store up to n errors before aborting test.\n");
printf("-ccrmask = ignore CCR bits that are not set.\n");
printf("-nodisasm = do not disassemble failed test.\n");
printf("-basicexc = do only basic checks when exception is 2 or 3.\n");
printf("-skipreg = do not validate registers.\n");
printf("-askifmissing = ask for new path if dat file is missing.\n");
printf("-exit n = exit after n tests.\n");
+ printf("-fpuadj <exp diff> <man bit count diff> <man zero bit count diff>.\n");
printf("-cycles [range adjust] = check cycle counts.\n");
printf("-cyclecnt <address>. Use custom hardware cycle counter.\n");
#ifdef AMIGA
exitcnt = -1;
cyclecounter_addr = 0xffffffff;
cycles_range = 2;
- outbuffer_size = DEFAULT_OUTBUFFER_SIZE;
+ fpu_adjust_exp = -1;
+ fpu_adjust_man = -1;
+ fpu_adjust_zb = -1;
for (int i = 1; i < argc; i++) {
char *s = argv[i];
exitcnt = atoi(next);
i++;
}
+ } else if (!_stricmp(s, "-fpuadj")) {
+ if (next) {
+ fpu_adjust_exp = atol(next);
+ char *p = strchr(next, ',');
+ if (p) {
+ fpu_adjust_man = atol(p + 1);
+ char *p = strchr(next, ',');
+ if (p) {
+ fpu_adjust_zb = atol(p + 1);
+ }
+ }
+ if (fpu_adjust_exp >= 0 || fpu_adjust_man >= 0 || fpu_adjust_zb >= 0) {
+ is_fpu_adjust = 1;
+ }
+
+ }
} else if (!_stricmp(s, "-cycles")) {
cycles = 1;
if (i + 1 < argc && argv[i][0] != '-') {
}
} else if (!_stricmp(s, "-uae")) {
uaemode = 1;
- } else if (!_stricmp(s, "-outbuffer")) {
+ } else if (!_stricmp(s, "-errors")) {
if (i + 1 < argc) {
i++;
- outbuffer_size = atoi(argv[i]);
+ errorcnt = atoi(argv[i]);
}
}
}
#endif
- if (outbuffer_size < 4000) {
- outbuffer_size = 4000;
- }
- outbuffer = (char*)calloc(outbuffer_size, 1);
- outbuffer2 = (char*)calloc(outbuffer_size, 1);
- if (!outbuffer || !outbuffer2) {
- printf("Out of memory when allocating output buffer.\n");
- return 0;
+ if (errorcnt > 0) {
+ outbuffer_size = errorcnt * PAGE_OUTBUFFER_SIZE;
+ stored_outbuffer = calloc(outbuffer_size, 1);
+ if (!stored_outbuffer) {
+ printf("Out of memory when allocating temporary output buffer.\n");
+ return 0;
+ }
}
DIR *groupd = NULL;