static int feature_exception_vectors = 0;
static int feature_interrupts = 0;
static int feature_instruction_size = 0;
+static int fpu_min_exponent, fpu_max_exponent;
+static int rnd_seed;
static TCHAR *feature_instruction_size_text = NULL;
static uae_u32 feature_addressing_modes[2];
static int feature_gzip = 0;
static int interrupt_cycle_cnt, interrupt_delay_cnt;
static int interrupt_level;
static uaecptr test_instruction_end_pc;
-static uaecptr lm_safe_address;
+static uaecptr lm_safe_address1, lm_safe_address2;
static uae_u8 ccr_cnt;
+static int condition_cnt;
+static int subtest_count;
struct uae_prefs currprefs;
static bool valid_address(uaecptr addr, int size, int rwp)
{
- int w = rwp == 2;
+ int w = (rwp & 0x7fff) == 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;
}
if (addr >= test_memory_start && addr + size < test_memory_end) {
// make sure we don't modify our test instruction
- if (testing_active && w) {
+ if ((testing_active && w) || (rwp > 0 && (rwp & 0x8000))) {
if (addr >= opcode_memory_start && addr + size < opcode_memory_start + OPCODE_AREA)
goto oob;
}
static bool check_valid_addr(uaecptr addr, int size, int rwp)
{
- if (!valid_address(addr, 1, rwp))
+ if (!valid_address(addr, 1, rwp | 0x8000))
return false;
- if (!valid_address(addr + size - 1, 1, rwp))
+ if (!valid_address(addr + size, 1, rwp | 0x8000))
return false;
return true;
}
size--;
// if loop mode: loop mode buffer can be only accessed by loop mode store instruction
- if (feature_loop_mode_jit && testing_active && addr >= test_memory_start && addr + size < test_memory_start + LM_BUFFER && lm_safe_address != regs.pc) {
+ if (feature_loop_mode_jit && testing_active && addr >= test_memory_start && addr + size < test_memory_start + LM_BUFFER && (lm_safe_address1 != regs.pc && lm_safe_address2 != regs.pc)) {
goto oob;
}
interrupt_cycle_cnt -= cycles;
if (interrupt_cycle_cnt <= 0) {
interrupt_cycle_cnt = 0;
- interrupt_level = 6;
+ Exception(24 + 6);
}
}
uae_u32(*x_next_iword)(void);
uae_u32(*x_next_ilong)(void);
-void (*x_do_cycles)(unsigned long);
+void (*x_do_cycles)(uae_u32);
uae_u32(REGPARAM3 *x_cp_get_disp_ea_020)(uae_u32 base, int idx) REGPARAM;
}
}
-void cpureset(void)
+bool cpureset(void)
{
cpu_halted = -1;
+ return false;
}
static void doexcstack2(void)
if (diff >= -128 && diff < 128) {
*dst++ = mode | CT_RELATIVE_START_BYTE;
*dst++ = diff & 0xff;
- } else if (diff >= -32768 && diff < 32767) {
+ } else if (diff >= -32768 && diff < 32768) {
*dst++ = mode | CT_RELATIVE_START_WORD;
*dst++ = (diff >> 8) & 0xff;
*dst++ = diff & 0xff;
pl(data, feature_exception_vectors);
fwrite(data, 1, 4, f);
data[0] = data[1] = data[2] = 0;
- pl(data, feature_loop_mode_cnt);
+ pl(data, feature_loop_mode_cnt | (feature_loop_mode_jit << 8));
fwrite(&data[0], 1, 4, f);
fwrite(&data[1], 1, 4, f);
fwrite(&data[2], 1, 4, f);
addr = pc + 2 - 2;
} else {
addr = cur_regs.regs[reg + 8];
- if (reg == 7) {
+ if (reg == 7 && flagsp) {
*flagsp |= EAFLAG_SP;
}
}
uaecptr pce = pc;
pc += 2;
// calculate lenght of extension
- if (mode == Ad8r && reg == 7) {
+ if (mode == Ad8r && reg == 7 && flagsp) {
*flagsp |= EAFLAG_SP;
}
*eap = ShowEA_disp(&pce, mode == Ad8r ? regs.regs[reg + 8] : pce, NULL, NULL, false);
} else if ((imm16_cnt & 15) == 0) {
v = 0;
}
+ // clear A7 from register mask
+ if (dp->mnemo == i_MVMEL) {
+ v &= ~0x8000;
+ } else if (dp->mnemo == i_MVMLE) {
+ v &= ~0x0001;
+ }
imm16_cnt++;
put_word_test(pc, v);
*isconstant = 16;
int ic = interrupt_count & 15;
int lvl = interrupt_levels[ic];
if (lvl > 0 && lvl > feature_min_interrupt_mask) {
- Exception(lvl + 24);
+ Exception(24 + lvl);
return true;
}
}
return false;
}
-static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp)
+static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp, bool fpumode)
{
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 == 0x4c58
- && opw1 == 0xf756
+ if (opc == 0xf208
+ && opw1 == 0xa000
//&& opw2 == 0x4afc
)
printf("");
cnt = 100;
}
if (feature_interrupts == 2) {
- interrupt_cycle_cnt = 10;
+ interrupt_cycle_cnt = SERPER * 10 - 20;
}
for (;;) {
(*cpufunctbl[opc])(opc);
+ if (fpumode) {
+ // skip result has too large or small exponent
+ for (int i = 0; i < 8; i++) {
+ if (regs.fp[i].fpx.high != cur_regs.fp[i].fpx.high || regs.fp[i].fpx.low != cur_regs.fp[i].fpx.low) {
+ int exp = regs.fp[i].fpx.high & 0x7fff;
+ if (exp != 0x0000) {
+ if (exp < fpu_min_exponent || exp > fpu_max_exponent) {
+ test_exception = -1;
+ break;
+ }
+ }
+ }
+ }
+ }
+
if (test_ins) {
// skip if test instruction modified loop mode register
if (feature_loop_mode_jit || feature_loop_mode_68010) {
xorshiftstate ^= ovrfilename[i];
}
}
+ xorshiftstate ^= rnd_seed;
int pathlen = _tcslen(path);
_stprintf(dir, _T("%s%s"), path, mns);
int quick = 0;
int rounds = feature_test_rounds;
- int subtest_count = 0;
int data_saved = 0;
int first_cycles = 1;
int count = 0;
+ subtest_count = 0;
+
if (feature_loop_mode_jit) {
registers[8 + 3] = test_memory_start; // A3 = start of test memory
}
for (int i = 0; i < MAX_REGISTERS; i++) {
dst = store_reg(dst, CT_DREG + i, 0, cur_regs.regs[i], -1);
}
- for (int i = 0; i < 8; i++) {
- if (fpumode) {
+ if (fpumode) {
+ for (int i = 0; i < 8; i++) {
dst = store_fpureg(dst, CT_FPREG + i, NULL, cur_regs.fp[i].fpx, 1);
}
dst = store_reg(dst, CT_FPIAR, 0, cur_regs.fpiar, -1);
uae_u32 instructionendpc_old = opcode_memory_start;
uae_u32 startpc_old = opcode_memory_start;
int branch_target_swap_mode_old = 0;
+ int doopcodeswap = 1;
+
+ if (feature_interrupts == 2) {
+ doopcodeswap = 0;
+ }
if (verbose) {
if (target_ea[0] != 0xffffffff)
fpuopsize = -1;
test_exception = 0;
test_exception_extra = 0;
- lm_safe_address = 0xffffffff;
+ lm_safe_address1 = 0xffffffff;
+ lm_safe_address2 = 0xffffffff;
target_ea[0] = target_ea_bak[0];
target_ea[1] = target_ea_bak[1];
// interrupt timing test mode
if (feature_interrupts == 2) {
pc -= 2;
- put_word_test(pc + 0, 0x7000 | interrupt_delay_cnt); // moveq #x,d0 (4 cycles)
- put_word_test(pc + 2, 0xe0b9); // ror.l d0,d1 (4 + 4 + d0 * 2 cycles)
- put_word_test(pc + 4, NOP_OPCODE);
- pc += 6;
+ // move.w #x,0xdff032 (SERDAT) (20 cycles)
+ put_long_test(pc + 0, (0x33fc << 16) | 0x100 | '!');
+ put_long_test(pc + 4, 0x00dff030);
+// // moveq #x,d0 (4 cycles)
+// put_word_test(pc + 8, 0x7000 | interrupt_delay_cnt);
+ // ror.l d0,d0 (4 + 4 + d0 * 2 cycles)
+ put_word_test(pc + 8, 0xe0b8);
+ put_word_test(pc + 10, NOP_OPCODE); // (4 cycles)
+ pc += 12;
opcode_memory_address = startpc = pc;
pc += 2;
}
put_long_test(pc, 0x4e500004 | (dp->sreg << 16));
pc += 4;
opcode_memory_address = pc;
- loopmode_jump_offset = -4;
+ loopmode_jump_offset = 4;
pc += 2;
}
if (feature_loop_mode_jit || feature_loop_mode_68010) {
int cctype = isccinst(dp);
// dbf dn, opcode_memory_start
- if (feature_loop_mode_jit) {
+ if (feature_loop_mode_jit == 1 || feature_loop_mode_jit == 2) {
// move ccr,(a3)+
- lm_safe_address = pc;
+ lm_safe_address1 = pc;
put_word(pc, LM_OPCODE);
pc += 2;
+ } else if (feature_loop_mode_jit == 3) {
+ static const int consts[] = { 5, 7, 9, 11, 0 };
+ int c = condition_cnt % 5;
+ int cond = consts[c];
+ if (cond == 0) {
+ // X
+ put_long(pc, 0x91c8c188); // SUBA.L A0,A0 ; EXG.L D0,A0
+ pc += 4;
+ put_word(pc, 0x4040); // NEGX.W D0
+ pc += 2;
+ } else {
+ // CZVN
+ put_word(pc, (cond << 8) | 0x50c0); // Scc D0
+ pc += 2;
+ }
+ put_word(pc, 0x3040); // MOVE.W D0,A0
+ pc += 2;
+ lm_safe_address1 = pc;
+ put_word(pc, 0x36c8); // MOVE.W A0,(A3)+
+ pc += 2;
+ put_long(pc, 0x307c0000 | c); // MOVEA.W #x,A0
+ pc += 4;
+ lm_safe_address2 = pc;
+ put_word(pc, 0x36c8); // MOVE.W A0,(A3)+
+ pc += 2;
+ condition_cnt++;
}
// dbf dn,label
put_long_test(pc, ((0x51c8 | feature_loop_mode_register) << 16) | ((opcode_memory_address - pc - loopmode_jump_offset - 2) & 0xffff));
// bra.s start
put_word(pc, 0x6000 + (0xfe - pc - opcode_memory_address));
pc += 2;
- } else if (feature_loop_mode_jit == 2) {
+ } else if (feature_loop_mode_jit == 2 || feature_loop_mode_jit == 4) {
// generate extra round with randomized CCR
// tst.l dx
put_word(pc, 0x4a80 | feature_loop_mode_register);
// end word, needed to detect if instruction finished normally when
// running on real hardware.
- uae_u32 originalendopcode = (ILLG_OPCODE << 16) | NOP_OPCODE;
+ uae_u32 originalendopcode = (NOP_OPCODE << 16) | ILLG_OPCODE;
uae_u32 endopcode = originalendopcode;
uae_u32 actualendpc = pc;
uae_u32 instruction_end_pc = pc;
uaecptr nextpc;
srcaddr = 0xffffffff;
dstaddr = 0xffffffff;
- uae_u32 dflags = m68k_disasm_2(out, sizeof(out) / sizeof(TCHAR), opcode_memory_address, &nextpc, 1, &srcaddr, &dstaddr, 0xffffffff, 0);
+ uae_u32 dflags = m68k_disasm_2(out, sizeof(out) / sizeof(TCHAR), opcode_memory_address, NULL, 0, &nextpc, 1, &srcaddr, &dstaddr, 0xffffffff, 0);
if (verbose) {
my_trim(out);
wprintf(_T("%08u %s"), subtest_count, out);
out_of_test_space = false;
if (get_word_test(nextpc) == ILLG_OPCODE)
break;
- m68k_disasm_2(out, sizeof(out) / sizeof(TCHAR), nextpc, &nextpc, 1, NULL, NULL, 0xffffffff, 0);
+ m68k_disasm_2(out, sizeof(out) / sizeof(TCHAR), nextpc, NULL, 0, &nextpc, 1, NULL, NULL, 0xffffffff, 0);
my_trim(out);
wprintf(_T("%08u %s\n"), subtest_count, out);
}
}
// disassembler may set this
- out_of_test_space = false;
+ out_of_test_space = false;
if ((dflags & 1) && target_ea[0] != 0xffffffff && srcaddr != 0xffffffff && srcaddr != target_ea[0]) {
if (verbose) {
if (bc) {
if (feature_loop_mode_jit) {
if (srcaddr != test_instruction_end_pc) {
- // addq.w #2,a3, jmp xxx
- put_long_test(srcaddr, 0x544b4ef9);
+ if (feature_loop_mode_jit >= 3) {
+ // addq.w #4,a3, jmp xxx
+ put_long_test(srcaddr, 0x584b4ef9);
+ } else {
+ // addq.w #2,a3, jmp xxx
+ put_long_test(srcaddr, 0x544b4ef9);
+ }
put_long_test(srcaddr + 4, test_instruction_end_pc);
}
} else {
}
}
+ if (subtest_count == 8192)
+ printf("");
+
// save opcode memory
dst = store_mem_bytes(dst, opcode_memory_start, instruction_end_pc - opcode_memory_start, oldcodebytes, true);
dst = store_reg(dst, CT_AREG + 7, 0, target_usp_address, sz_long);
}
+ if (feature_interrupts == 2) {
+ *dst++ = CT_EDATA;
+ *dst++ = CT_EDATA_IRQ_CYCLES;
+ *dst++ = interrupt_delay_cnt;
+ }
+
// pre-test data end
*dst++ = CT_END_INIT;
int t_cnt = 0;
int extraccr = 0;
+ interrupt_delay_cnt = -1;
// extra loops for supervisor and trace
uae_u16 sr_allowed_mask = feature_sr_mask & 0xf000;
uae_u16 sr_mask = 0;
int maxflag;
+ int maxflagcnt;
+ int maxflagshift;
int flagmode = 0;
if (fpumode) {
if (fpuopcode == FPUOPP_ILLEGAL || feature_flag_mode > 1) {
// Illegal FPU instruction: all on/all off only (*2)
maxflag = 2;
+ maxflagshift = 1;
} else if (dp->mnemo == i_FDBcc || dp->mnemo == i_FScc || dp->mnemo == i_FTRAPcc || dp->mnemo == i_FBcc) {
// FXXcc-instruction: FPU condition codes (*16)
maxflag = 16;
+ maxflagshift = 4;
flagmode = 1;
} else {
// Other FPU instructions: FPU rounding and precision (*16)
maxflag = 16;
+ maxflagshift = 4;
}
} else {
maxflag = 32; // all flag combinations (*32)
+ maxflagshift = 5;
if (feature_flag_mode > 1 || (feature_flag_mode == 1 && (dp->mnemo == i_ILLG || !isccinst(dp)))) {
// if not cc instruction or illegal or forced: all on/all off (*2)
maxflag = 2;
+ maxflagshift = 1;
}
}
}
*dst++ = (uae_u8)(maxflag | (fpumode ? 0x80 : 0x00) | (flagmode ? 0x40 : 0x00));
+ maxflagcnt = maxflag;
+ if (feature_interrupts == 2) {
+ maxflagcnt *= 64;
+ }
+
// Test every CPU CCR or FPU SR/rounding/precision combination
- for (int ccr = 0; ccr < maxflag; ccr++) {
+ for (int ccrcnt = 0; ccrcnt < maxflagcnt; ccrcnt++) {
bool skipped = false;
+ int ccr = ccrcnt & ((1 << maxflagshift) - 1);
out_of_test_space = 0;
test_exception = 0;
// swap end opcode illegal/nop
noaccesshistory++;
- endopcode = (endopcode >> 16) | (endopcode << 16);
+ if (doopcodeswap) {
+ endopcode = (endopcode >> 16) | (endopcode << 16);
+ }
int extraopcodeendsize = ((endopcode >> 16) == NOP_OPCODE) ? 2 : 0;
int endopcodesize = 0;
if (!is_nowrite_address(pc - 4, 4)) {
}
regs.sr |= feature_min_interrupt_mask << 8;
+ if (feature_interrupts == 2) {
+ regs.regs[0] = ccrcnt >> maxflagshift;
+ }
+
// override special register values
for (int i = 0; i < regdatacnt; i++) {
struct regdata *rd = ®datas[i];
if (regs.sr & 0x2000)
prev_s_cnt++;
- if (subtest_count == 2052)
- printf("");
+ if (subtest_count == 20609)
+ printf("");
// execute test instruction(s)
- execute_ins(pc - endopcodesize, branch_target_pc, dp);
+ execute_ins(pc - endopcodesize, branch_target_pc, dp, fpumode);
if (regs.s)
s_cnt++;
// undo any test instruction generated memory modifications
undo_memory(ahist, ahcnt_start);
}
+
nextextra:
extraccr++;
if (extraccr >= 16)
}
}
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);
+ wprintf(_T(" OK=%d OB=%d S=%d/%d T=%d STP=%d I=%d"), ok, exception_array[0], prev_s_cnt, s_cnt, t_cnt, cnt_stopped, interrupt_delay_cnt);
if (!ccr_done)
wprintf(_T(" X"));
for (int i = 2; i < 128; i++) {
nextround = true;
}
+#if 0
+ // interrupt delay test from 0 to 63
if (feature_interrupts == 2) {
interrupt_delay_cnt++;
if (interrupt_delay_cnt >= 64) {
- nextround = false;
+ break;
} else {
nextround = true;
+ rounds = 1;
}
}
+#endif
if (target_opcode_address != 0xffffffff || target_usp_address != 0xffffffff) {
nextround = false;
addressing_mask = 0xffffffff;
}
+ currprefs.int_no_unimplemented = true;
+ ini_getvalx(ini, sections, _T("cpu_unimplemented"), &v);
+ if (v) {
+ currprefs.int_no_unimplemented = false;
+ }
+
currprefs.fpu_model = 0;
currprefs.fpu_mode = 1;
ini_getvalx(ini, sections, _T("fpu"), &currprefs.fpu_model);
}
}
+ currprefs.fpu_no_unimplemented = true;
+ if (ini_getvalx(ini, sections, _T("fpu_unimplemented"), &v)) {
+ if (v) {
+ currprefs.fpu_no_unimplemented = false;
+ }
+ }
+
+ fpu_min_exponent = 0;
+ fpu_max_exponent = 32768;
+ if (ini_getvalx(ini, sections, _T("fpu_min_exponent"), &v)) {
+ if (v >= 0) {
+ fpu_min_exponent = v;
+ }
+ }
+ if (ini_getvalx(ini, sections, _T("fpu_max_exponent"), &v)) {
+ if (v >= 0) {
+ fpu_max_exponent = v;
+ }
+ }
+
+ rnd_seed = 0;
+ ini_getvalx(ini, sections, _T("seed"), &rnd_seed);
+
verbose = 1;
ini_getvalx(ini, sections, _T("verbose"), &verbose);
cpudatatbl[opcode].branch = tbl[i].branch;
}
- currprefs.int_no_unimplemented = true;
- currprefs.fpu_no_unimplemented = true;
-
for (int opcode = 0; opcode < 65536; opcode++) {
cpuop_func *f;
instr *table = &table68k[opcode];
return 0;
}
+ disasm_init();
+
TCHAR *sptr = sections;
_tcscpy(sections, INISECTION);
sptr += _tcslen(sptr) + 1;
.globl _cyclereg_address5
.globl _cyclereg_address6
.globl _berrcopy
+ .globl _fpucomp
| must match main.c
S_DREG = 0
S_FSAVE = S_FPSR+4
S_NEXT = S_FSAVE+216
+ | v1, v2, limit
+ | abs((v2 - v1) / v1) > limit
+_fpucomp:
+ move.l 4(sp),a0
+ fmovem.x (a0),fp0-fp2
+ fsub.x fp0,fp1
+ fdiv.x fp0,fp1
+ fabs.x fp1
+ moveq #1,d0
+ fcmp.x fp1,fp2
+ fbgt .larger
+ moveq #0,d0
+.larger:
+ rts
| src, dst, size, >68000
_berrcopy:
_cyclereg_address2:
move.w CYCLEREG,cycles
| pre set data output buffer.
- | we don't want random DOB contents in bus/address error frame
+ | we dont want random DOB contents in bus/address error frame
move.w #0xf00d,dummy
rte
-#define DATA_VERSION 21
+#define DATA_VERSION 22
#define CT_FPREG 0
#define CT_DREG 0
#define CT_FPIAR 20
#define CT_FPSR 21
#define CT_FPCR 22
+#define CT_EDATA 23
#define CT_CYCLES 25
#define CT_ENDPC 26
#define CT_BRANCHTARGET 27
#define CT_DATA_MASK 31
#define CT_EXCEPTION_MASK 63
+#define CT_EDATA_IRQ_CYCLES 1
+
#define CT_SIZE_BYTE (0 << 5)
#define CT_SIZE_WORD (1 << 5)
#define CT_SIZE_LONG (2 << 5)
#define NOP_OPCODE 0x2048
#define ILLG_OPCODE 0x4afc
#define LM_OPCODE 0x42db
+
+#define SERPER 8
[cputest]
; CPU model (68000, 68020, 68030, 68040 or 68060).
-cpu=68000
+cpu=68040
; CPU address space.
; If 24-bit, tester will assume upper 8-bits of addresses gets ignored.
; 24 = 24-bit address space, 32 = 32-bit address space. 680x0 = this and higher CPU models are 32-bit.
-cpu_address_space=68030
+cpu_address_space=68020
+
+; 1 = all instructions are supported (for example MOVEP if 68060 etc)
+cpu_no_unimplemented=0
; FPU model (empty string or 0, 68881, 68882, 68040, 68060)
; Enable only when testing FPU. Only FPU instruction tests are allowed if FPU is enabled.
; if CPU is 68040/060 and FPU is 68881/68882, FPU type will be automatically corrected.
fpu=
+; 1 = all instructions are supported (for example FSxxx and FDxx if 6888x, all normally
+; unimplemented (software emulated) if 68040/68060
+fpu_no_unimplemented=0
+
+; Don't generate tests that create result that has larger or smaller 16-bit extended double exponent.
+; Min exponent >0 does not prevent zero results.
+fpu_min_exponent=
+fpu_max_exponent=
+
; Write generated instructions to standard output. Always disabled in "all" mode.
verbose=1
; Low address space limits. Real hardware must have RAM in this space. Comment out to disable.
; Start should be zero if Amiga, set to 0x0800 if Atari ST.
-; Must be disabled if cycle counting, cycle count tests must only access real Fast RAM.
-test_low_memory_start=0x0000
-test_low_memory_end=0x8000
+; Must be disabled if cycle counting (instruction/interrupt), cycle count tests must only access real Fast RAM.
+;test_low_memory_start=0x0000
+;test_low_memory_end=0x8000
; High address space limits (0x00ff8000 to 0x01000000 is complete space if 24-bit). Comment out to disable.
; Automatically disabled if 32-bit CPU and end == 0x01000000
-test_high_memory_start=0x00ff8000
+;test_high_memory_start=0x00ff8000
test_high_memory_end=0x01000000
; ROM high address space. High memory is only used for read tests, uses last 32k of ROM image file.
high_rom=D:\amiga\roms\Kickstart v3.1 rev 40.63 (1993)(Commodore)(A500-A600-A2000)[!].rom
; main test memory start and size (real hardware must have RAM in this address space)
-test_memory_start=0x860000
+test_memory_start=0x00460000
;test_memory_start=0x68800000
;test_memory_start=0x43800000
;test_memory_start=0x07800000
test_memory_size=0xa0000
+;
+;test_memory_start=0x340000
+;test_memory_size=0x80000
+
; address where test instructions are located
; if not defined: mid point of test memory
feature_min_interrupt_mask=0
; Interrupt test
-; If enabled, interrupt request is set before test.
+; 1 = interrupt request is set before test.
; Tests all INTREQ bits one by one. Compatible with cycle count mode.
+; 2 = test CPU IPL sampling timing.
+; Uses serial port to generate timing interrupt. Requires serial port TX connected to RX.
+; Generates multiple extra tests.
+; Used delay instruction: ROL.L D0,D0 (D0 = number of CPU clocks * 2)
+; All test rounds that generate interrupt immediately after test instuction has been executed are stored.
; Amiga only
feature_interrupts=0
; reg=0x1234 or reg=100
;feature_forced_register=
-; generate loop test: label: <test instruction> dbf dn,label
-; value: 0 = disabled, >0 = number of loops
-; feature_loop_mode=0
-; feature_loop_mode_register=7
-; only generate 68010 loop mode compatible instructions
-: feature_loop_mode_68010=0
-; reload changed address register(s) (-(an) or (an)+) after each round
-; feature_loop_mode_reload=1
+; generate JIT loop test: label: <test instruction>, <store CCR>, dbf dn,label
+; value: 0 = disabled, 1 = enable, 2 = enable + extra rounds with random CCR, 3 = no CCR check/store
+;feature_loop_mode=0
+;feature_loop_mode_register=7 (default)
+;feature_loop_mode_cnt=8 (default)
+
+; generate 68010 loop mode tests
+;feature_loop_mode_68010=0
+;feature_loop_mode_register=7 (default)
+;feature_loop_mode_cnt=8 (default)
; 68020+ addressing modes (this makes test files much larger if other addressing modes are also enabled)
; currently does not generate any reserved mode bit combinations.
; branch = all branch instructions (branchj = non-stack only, branchs = stack using)
mode=
+; random seed (XOR'd with internally generated static seed)
+seed=
+
; test groups
; use key=* to restore default value
feature_undefined_ccr=1
mode=all
+; interrupt timing test
+[test=IPL]
+cpu=68000-68010
+enabled=0
+feature_undefined_ccr=1
+feature_interrupts=2
+mode=exg,neg,not,ror,rol,swap
+
; interrupt exception
[test=IRQ]
enabled=0
enabled=0
cpu=68010
feature_loop_mode_68010=1
-feature_loop_mode=3
-feature_loop_mode_register=7
+feature_loop_mode_cnt=3
min_opcode_test_rounds=100
feature_undefined_ccr=1
mode=all
cpu=68020-68060
feature_addressing_modes_src=Ad8rf,PC8rf
test_rounds=4
+verbose=0
min_opcode_test_rounds=5000
mode=not,move
cpu=68020-68060
feature_addressing_modes_dst=Ad8rf,PC8rf
test_rounds=4
+verbose=0
min_opcode_test_rounds=5000
mode=add,move
verbose=1
cpu=68020-68060
fpu=68882
+feature_sr_mask=0xc000
exceptions=-48,-49,-50,-51,-52,-53,-54
min_opcode_test_rounds=5000
mode=fmove,fsmove,fdmove,fint,fintrz,fneg,fsneg,fdneg,fabs,fsabs,fdabs,fdiv,fsdiv,fddiv,fadd,fsadd,fdadd,fmul,fsmul,fdmul,fsgldiv,fsglmul,fsub,fssub,fdsub,fcmp,ftst,fsqrt
; no arithmetic exceptions, unsupported instructions or datatypes, denormals or unnormals.
[test=FCPX]
enabled=0
-verbose=1
+verbose=0
cpu=68020-68030
fpu=68882
exceptions=-48,-49,-50,-51,-52,-53,-54
; non-arithmetic instructions (FMOVEM also includes FMOVE to/from control register)
[test=FINT]
enabled=0
-verbose=1
+verbose=0
cpu=68020-68060
fpu=68882
+feature_sr_mask=0xc000
mode=fmovecr,fmovem,fdbcc,fbcc,ftrapcc,fscc
; packed datatype
fpu=68882
exceptions=11,55,60,61
feature_flags_mode=2
-mode=fillegal
+mode=fall
; ******************
-; JIT loop mode test
+; JIT tests
; ******************
[test=JITLM]
enabled=0
cpu=68020-68060
cpu_address_space=68020
-feature_loop_mode=8
-feature_loop_mode_reload=1
-feature_loop_mode_register=7
+feature_loop_mode=1
opcode_memory_start=-1
+mode=mvmel,mvmle,link,unlk
+feature_flags_mode=1
+test_rounds=3
+verbose=0
+
+; basic tests
+[test=JITB]
+enabled=0
+cpu=68020-68060
+cpu_address_space=68020
+feature_flags_mode=0
+verbose=1
mode=all
+
+; 68020+ addressing mode tests
+[test=JITES]
+enabled=0
+cpu=68020-68060
+feature_addressing_modes_src=Ad8rf,PC8rf
+cpu_address_space=68020
+feature_loop_mode=1
+opcode_memory_start=-1
+test_rounds=4
+verbose=0
+min_opcode_test_rounds=5000
+mode=not,move
+
+[test=JITED]
+enabled=0
+cpu=68020-68060
+feature_addressing_modes_dst=Ad8rf,PC8rf
+cpu_address_space=68020
+feature_loop_mode=1
+opcode_memory_start=-1
+test_rounds=4
+verbose=0
+min_opcode_test_rounds=5000
+mode=add,move
+
+[test=JITX]
+enabled=0
+cpu=68020-68060
+cpu_address_space=68020
+feature_loop_mode=3
+opcode_memory_start=-1
+test_rounds=4
+feature_flags_mode=1
verbose=0
+mode=scc,dbcc,bcc
uae_u16 fpeaset;
};
+
+struct irqresult
+{
+ uae_u32 pc;
+ uae_u16 sr;
+};
+
+static struct irqresult irqresults[64 + 1], irqresults2[64 + 1];
+
static short continue_on_error;
static struct registers test_regs;
static struct registers last_regs;
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;
+static short fpu_adjust_exp;
struct fpureg fpu_adjust;
static uae_u32 cpustatearraystore[16];
static uae_u32 cpustatearraynew[] = {
static short dooutput = 1;
static short quit;
static uae_u8 ccr_mask;
+static uae_u32 fpsr_ignore_mask;
static uae_u32 addressing_mask = 0x00ffffff;
static uae_u32 interrupt_mask;
static short loop_mode_jit, loop_mode_68010, loop_mode_cnt;
static short skipccrchange;
static short askifmissing;
static short nextall;
-static int exitcnt;
+static int exitcnt, irqcnt;
static short cycles, cycles_range, cycles_adjust;
static short gotcycles;
static short interrupttest;
+static short interrupt_delay_cnt;
+static short interrupttest_diff_cnt;
static uae_u32 cyclecounter_addr;
static int errorcnt;
static short uaemode;
static void berrcopy(void *src, void *dst, uae_u32 size, uae_u32 hasvbr)
{
}
+static uae_u32 fpucomp(void *v)
+{
+ return 0;
+}
static void *error_vector;
#else
extern void flushcache(uae_u32);
extern void *error_vector;
extern void berrcopy(void*, void*, uae_u32, uae_u32);
+extern uae_u32 fpucomp(void*);
#endif
static uae_u32 exceptiontableinuse;
return (uae_s32)llu(p);
}
+static void interrupt_results(void)
+{
+ if (interrupttest == 2) {
+ short pvcnt = 0;
+ for(short i = 0; i < 64; i++) {
+ struct irqresult *irq1 = &irqresults[i];
+ struct irqresult *irq2 = &irqresults[i + 1];
+ if (irq1->pc == irq2->pc && irq1->sr == irq2->sr && i < 63) {
+ pvcnt++;
+ }
+ if (irq1->pc != irq2->pc || irq1->sr != irq2->sr || i == 63) {
+ if (irq1->sr == 0x6000) {
+ printf("S%02d-%02d: %08x ", i - pvcnt, i, irq1->pc);
+ } else {
+ printf("U%02d-%02d: %08x ", i - pvcnt, i, irq1->pc);
+ }
+ pvcnt = 0;
+ }
+ }
+ printf("\n");
+ }
+}
+
static void endinfo(void)
{
printf("Last test: %u\n", testcnt);
return p;
}
+static uae_u8 *restore_edata(uae_u8 *p)
+{
+ p++;
+ uae_u8 v = *p++;
+ switch(v)
+ {
+ case CT_EDATA_IRQ_CYCLES:
+ interrupt_delay_cnt = *p++;
+ break;
+ default:
+ end_test();
+ printf("Unexpected CT_EDATA 0x%02x\n", *p);
+ endinfo();
+ exit(0);
+ }
+ return p;
+}
+
static uae_u8 *restore_data(uae_u8 *p, struct registers *r)
{
uae_u8 v = *p;
if (v & CT_END) {
end_test();
- printf("Unexpected end bit!? offset %d\n", p - test_data);
+ printf("Unexpected end bit!? 0x%02x offset %d\n", v, p - test_data);
endinfo();
exit(0);
}
p = restore_memory(p, 1);
} else if (mode == CT_MEMWRITES) {
p = restore_memory(p, 0);
+ } else if (mode == CT_EDATA) {
+ p = restore_edata(p);
} else {
end_test();
printf("Unexpected mode %02x\n", v);
}
}
+static uae_u8 *get_exceptionframe(struct registers *regs, short excnum, int *sizep)
+{
+ uae_u8 *frame = (uae_u8 *)regs->excframe;
+ short size = 0;
+ if (cpu_lvl == 0) {
+ if (excnum == 2 || excnum == 3) {
+ size = 14;
+ } else {
+ size = 6;
+ }
+ *sizep = size;
+ return frame;
+ }
+ uae_u16 type = (frame[4] << 8) | frame[5];
+ switch (type >> 12)
+ {
+ case 0:
+ size = 8;
+ break;
+ case 2:
+ case 3:
+ size = 12;
+ break;
+ case 4:
+ size = 16;
+ break;
+ case 7:
+ size = 60;
+ break;
+ case 8:
+ size = 82;
+ break;
+ case 9:
+ size = 20;
+ break;
+ case 10:
+ size = 32;
+ break;
+ case 11:
+ size = 92;
+ break;
+ }
+ *sizep = size;
+ return frame;
+}
+
static uae_u8 *validate_exception(struct registers *regs, uae_u8 *p, short excnum, short *gotexcnum, short *experr, short *extratrace, short *group2with1)
{
int exclen = 0;
static uae_u16 test_intena, test_intreq;
+static void set_interrupt_sertest(void)
+{
+ volatile uae_u16 *intena = (uae_u16 *)0xdff09a;
+ volatile uae_u16 *serper = (uae_u16 *)0xdff032;
+ // enable serial receive interrupt
+ *intena = 0x8000 | 0x4000 | 0x0800;
+ // serial period
+ *serper = SERPER;
+}
+
static void set_interrupt(void)
{
if (interrupt_count < 15) {
return 1;
}
-static short getzobits(uae_u32 *vvp, uae_u8 b)
-{
- uae_u32 vv[2];
-
- 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)
m2[1] = f2->m[1];
uae_u16 exp1 = f1->exp & 0x7fff;
uae_u16 exp2 = f2->exp & 0x7fff;
- // NaN or Infinite: both must match but skip possible last bits
+ // NaN or Infinite
if (exp1 == 0x7fff || exp2 == 0x7fff) {
- goto lastbits;
+ if (m1[0] == 0 && m1[1] == 0) {
+ if (m2[0] != 0 || m2[1] != 0) {
+ return 0;
+ }
+ }
+ if (m2[0] == 0 && m2[1] == 0) {
+ if (m1[0] != 0 || m1[1] != 0) {
+ return 0;
+ }
+ }
+ return 1;
}
// 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 ((!exp1 && !m1[0] && !m1[1]) && (!exp2 && !m2[0] && !m2[1])) {
+ return 1;
}
- if (fpu_adjust_exp >= 0) {
- if (abs(exp1 - exp2) > fpu_adjust_exp)
- return 0;
- }
+ uae_u32 vx[9];
+ vx[0] = f1->exp << 16;
+ vx[1] = f1->m[0];
+ vx[2] = f1->m[1];
+ vx[3] = f2->exp << 16;
+ vx[4] = f2->m[0];
+ vx[5] = f2->m[1];
+ vx[6] = fpu_adjust_exp << 16;
+ vx[7] = 0x80000000;
+ vx[8] = 0x00000000;
- // 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 (fpucomp(vx)) {
+ fpu_approx++;
+ return 1;
}
- 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;
- }
-
-lastbits:
- // 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;
+ return 0;
}
static void loop_mode_error(uae_u32 ov, uae_u32 nv)
uae_u8 fpiar_changed = 0, fpsr_changed = 0, fpcr_changed = 0;
short exc = -1;
+ if (interrupttest == 2) {
+ struct irqresult *irq = &irqresults[interrupt_delay_cnt];
+ irq->pc = tregs->pc;
+ irq->sr = tregs->sr & 0xff00;
+ }
+
if (loop_mode_jit) {
memset(lmtable1, 0xff, sizeof(lmtable1));
memset(lmtable2, 0xff, sizeof(lmtable2));
if (lregs->pc + opcodeendsizeextra != tregs->pc) {
branched2 = lregs->pc < opcode_memory_addr || lregs->pc >= opcode_memory_addr + OPCODE_AREA;
if (dooutput) {
- sprintf(outbp, "PC (%c): expected %08x but got %08x\n", branched ? 'B' : '-', lregs->pc, tregs->pc);
+ int excsize;
+ uae_u8 *excp;
+ sprintf(outbp, "PC (%c): expected %08x but got %08x ", branched ? 'B' : '-', lregs->pc, tregs->pc);
outbp += strlen(outbp);
if (tregs->pc == opcode_memory_addr) {
- sprintf(outbp, "Got unexpected exception %d (unsupported instruction?)\n", cpuexc);
+ sprintf(outbp, "Got unexpected exception %d (unsupported instruction?) ", cpuexc);
} else {
- sprintf(outbp, "Got unexpected exception %d\n", cpuexc);
+ sprintf(outbp, "Got unexpected exception %d ", cpuexc);
}
outbp += strlen(outbp);
+ excp = get_exceptionframe(&test_regs, cpuexc, &excsize);
+ if (excp && excsize) {
+ hexdump(excp, excsize, 1);
+ }
}
errflag |= 1 << 16;
}
} else if (cpuexc == 4) {
sprintf(outbp, "Exception: expected %d but got %d (or no exception)\n", exc, cpuexc);
} else {
+ int excsize;
+ uae_u8 *excp;
sprintf(outbp, "Exception: expected %d but got %d\n", exc, cpuexc);
+ excp = get_exceptionframe(&test_regs, cpuexc, &excsize);
+ if (excp && excsize) {
+ hexdump(excp, excsize, 1);
+ }
}
experr = 1;
}
int size;
p = restore_value(p, &val, &size);
if (val != tregs->fpsr) {
- if (!ignore_errors) {
+ if (!ignore_errors && ((val & fpsr_ignore_mask) != (tregs->fpsr & fpsr_ignore_mask))) {
if (dooutput) {
if (sregs->fpsr == tregs->fpsr) {
sprintf(outbp, "FPSR: expected %08x but register was not modified\n", val);
}
}
if (!ignore_sr) {
- if (fpsr_changed && tregs->fpsr != lregs->fpsr) {
+ if (fpsr_changed && (tregs->fpsr & fpsr_ignore_mask) != (lregs->fpsr & fpsr_ignore_mask)) {
if (dooutput) {
uae_u32 val = lregs->fpsr;
sprintf(outbp, "FPSR: expected %08x -> %08x but got %08x\n", sregs->fpsr, val, tregs->fpsr);
}
if (loop_mode_jit) {
- short idx = 0, cnt = 0, end = loop_mode_cnt * 2;
+ short idx = 0, cnt = 0, end = loop_mode_cnt;
for (;;) {
- uae_u16 v1, v2;
- v1 = lmtable1[idx];
- v2 = lmtable2[idx];
+ uae_u16 v1a = lmtable1[idx];
+ uae_u16 v2a = lmtable2[idx];
+ uae_u16 v1b = lmtable1[idx + 1];
+ uae_u16 v2b = lmtable2[idx + 1];
idx++;
+ if (loop_mode_jit == 3 || loop_mode_jit == 4) {
+ idx++;
+ }
if (idx >= LM_BUFFER / 2) {
break;
}
- if (v1 == 0xffff && v2 == 0xffff) {
+ if (v1a == 0xffff && v2a == 0xffff) {
continue;
}
cnt++;
- if (v1 != v2) {
- sprintf(outbp, "LM %02d/%02d CCR: %02x != %02x",
- cnt, end, v1, v2);
- outbp += strlen(outbp);
- sprintf(outbp, " X%c%d N%c%d Z%c%d V%c%d C%c%d\n",
- (v1 & 0x10) != (v2 & 0x10) ? '!' : '=', (v2 & 0x10) != 0,
- (v1 & 0x08) != (v2 & 0x08) ? '!' : '=', (v2 & 0x08) != 0,
- (v1 & 0x04) != (v2 & 0x04) ? '!' : '=', (v2 & 0x04) != 0,
- (v1 & 0x02) != (v2 & 0x02) ? '!' : '=', (v2 & 0x02) != 0,
- (v1 & 0x01) != (v2 & 0x01) ? '!' : '=', (v2 & 0x01) != 0);
- outbp += strlen(outbp);
+ if (v1a != v2a) {
+ if (loop_mode_jit == 3 || loop_mode_jit == 4) {
+ static const char *constss[] = { "C", "Z", "V", "N", "X" };
+ const char *c = "?";
+ if (v1b < 5 && v1b == v2b) {
+ c = constss[v1b];
+ }
+ sprintf(outbp, "LM %02d/%02d %s: %d %c %d (%04x %04x - %04x %04x)\n",
+ cnt, end, c, (v1a & 0xff) != 0, v1a != v2a ? '!' : '=', (v2a & 0xff) != 0,
+ v1a, v1b, v2a, v2b);
+ outbp += strlen(outbp);
+ } else if (loop_mode_jit == 1 || loop_mode_jit == 2) {
+ sprintf(outbp, "LM %02d/%02d CCR: %02x != %02x",
+ cnt, end, v1a, v2a);
+ outbp += strlen(outbp);
+ sprintf(outbp, " X%c%d N%c%d Z%c%d V%c%d C%c%d\n",
+ (v1a & 0x10) != (v2a & 0x10) ? '!' : '=', (v2a & 0x10) != 0,
+ (v1a & 0x08) != (v2a & 0x08) ? '!' : '=', (v2a & 0x08) != 0,
+ (v1a & 0x04) != (v2a & 0x04) ? '!' : '=', (v2a & 0x04) != 0,
+ (v1a & 0x02) != (v2a & 0x02) ? '!' : '=', (v2a & 0x02) != 0,
+ (v1a & 0x01) != (v2a & 0x01) ? '!' : '=', (v2a & 0x01) != 0);
+ outbp += strlen(outbp);
+ }
}
if (cnt >= end) {
break;
static void copyregs(struct registers *d, struct registers *s, short fpumode)
{
if (fpumode) {
- memcpy(&d->regs[0], &s->regs[0], offsetof(struct registers, fsave));
+ memcpy(d->regs, s->regs, offsetof(struct registers, fsave));
} else {
- memcpy(&d->regs[0], &s->regs[0], offsetof(struct registers, fpuregs));
+ memcpy(d->regs, s->regs, offsetof(struct registers, fpuregs));
}
}
clear_interrupt();
#endif
ahcnt = 0;
+
+ short doopcodeswap = 1;
+
+ if (interrupttest == 2) {
+ doopcodeswap = 0;
+ }
for (;;) {
+ if (interrupttest == 2) {
+ memcpy(irqresults2, irqresults, sizeof(irqresults));
+ memset(irqresults, 0, sizeof(irqresults));
+ }
+
cur_regs.endpc = endpc;
cur_regs.pc = startpc;
copyregs(&last_regs, &cur_regs, fpumode);
- uae_u32 originalopcodeend = (ILLG_OPCODE << 16) | NOP_OPCODE;
+ uae_u32 originalopcodeend = (NOP_OPCODE << 16) | ILLG_OPCODE;
short opcodeendsizeextra = 0;
uae_u32 opcodeend = originalopcodeend;
int extraccr = 0;
sr_mask |= 0x1000; // M
uae_u8 ccrmode = *p++;
- int maxccr = ccrmode & 0x3f;
+ short maxccr = ccrmode & 0x3f;
+ short ccrshift = 0;
+ while ((maxccr - 1) & (1 << ccrshift)) {
+ ccrshift++;
+ }
+ ccrshift--;
+ if (interrupttest == 2) {
+ maxccr *= 64;
+ }
testcntsubmax = maxccr;
testcntsub = 0;
- for (short ccr = 0; ccr < maxccr; ccr++, testcntsub++) {
-
+ for (short ccrcnt = 0; ccrcnt < maxccr; ccrcnt++, testcntsub++) {
+ short ccr = ccrcnt & (maxccr - 1);
fpu_approx = 0;
- opcodeend = (opcodeend >> 16) | (opcodeend << 16);
- opcodeendsizeextra = opcodeendsizeextra ? 0 : 2;
+ if (doopcodeswap) {
+ opcodeend = (opcodeend >> 16) | (opcodeend << 16);
+ }
+ opcodeendsizeextra = (opcodeend >> 16) == NOP_OPCODE ? 2 : 0;
if (validendsize == 2) {
pl(opcode_memory_end, opcodeend);
} else if (validendsize == 1) {
pw(opcode_memory_end, opcodeend >> 16);
}
-
if (cur_regs.branchtarget != 0xffffffff && !(cur_regs.branchtarget & 1)) {
if (cur_regs.branchtarget_mode == 1) {
uae_u32 bv = gl((uae_u8*)cur_regs.branchtarget);
cur_regs.ssp = super_stack_memory - 0x80;
cur_regs.msp = super_stack_memory;
+ cur_regs.fpiar = 0xffffffff;
copyregs(&test_regs, &cur_regs, fpumode);
test_regs.pc = startpc;
- test_regs.fpiar = startpc;
test_regs.cyclest = 0xffffffff;
test_regs.fpeaset = 0;
}
#ifdef AMIGA
- if (interrupttest) {
+ if (interrupttest == 1) {
interrupt_count = *p++;
}
#endif
}
test_regs.expsr = test_regs.sr | 0x2000;
+
+ if (interrupttest == 2) {
+ interrupt_delay_cnt = ccrcnt >> ccrshift;
+ cur_regs.regs[0] = test_regs.regs[0] = interrupt_delay_cnt;
+ }
// internally modified registers become part of cur_regs
cur_regs.sr = test_regs.sr;
if (exitcnt >= 0) {
exitcnt--;
- if (exitcnt < 0) {
+ if (exitcnt == -1) {
+ volatile UWORD *cp = (volatile UWORD*)0x100;
+ *cp = 0x1234;
+#if 0
addinfo();
strcat(outbp, "Registers before:\n");
outbp += strlen(outbp);
end_test();
printf(outbuffer);
printf("\nExit count expired\n");
+ if (interrupttest == 2) {
+ interrupt_results();
+ }
exit(0);
+#endif
}
}
#ifdef AMIGA
- if (interrupttest) {
+ if (interrupttest == 1) {
set_interrupt();
+ } else if (interrupttest == 2) {
+ set_interrupt_sertest();
}
#endif
if (cpu_lvl == 1) {
fpu_approxcnt++;
}
- if (quit || errors) {
- if (!quit && errorcnt > 0 && totalerrors < errorcnt) {
- if (totalerrors > 0) {
- strcat(stored_outbuffer, "----------------------------------------\n");
- }
- if (strlen(stored_outbuffer) + strlen(outbuffer) + 40 >= outbuffer_size) {
+ if (interrupttest != 2) {
+
+ if (quit || errors) {
+ 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;
}
- 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++;
}
- totalerrors++;
}
}
}
restoreahist();
+
+ // increase count when interrupt test returns different results
+ if (interrupttest == 2) {
+ if (memcmp(irqresults, irqresults2, sizeof(irqresults))) {
+ interrupttest_diff_cnt++;
+ if (interrupttest_diff_cnt == irqcnt) {
+ end_test();
+ printf(outbuffer);
+ printf("Interrupt test count expired\n");
+ interrupt_results();
+ exit(0);
+ }
+ }
+ }
}
printf("%s", outbuffer);
}
}
+ if (interrupttest == 2) {
+ interrupt_results();
+ }
}
static void freestuff(void)
lvl = (lvl_mask >> 16) & 15;
interrupt_mask = (lvl_mask >> 20) & 7;
addressing_mask = (lvl_mask & 0x80000000) ? 0xffffffff : 0x00ffffff;
- interrupttest = (lvl_mask >> 26) & 1;
+ interrupttest = (lvl_mask >> 26) & 3;
sr_undefined_mask = lvl_mask & 0xffff;
safe_memory_mode = (lvl_mask >> 23) & 7;
loop_mode_jit = (lvl_mask >> 28) & 1;
if (loop_mode_jit || loop_mode_68010) {
loop_mode_cnt = v & 0xff;
}
+ if ((v >> 8) & 15) {
+ loop_mode_jit = (v >> 8) & 15;
+ }
read_u32(headerfile, &headoffset);
read_u32(headerfile, &headoffset);
memcpy(inst_name, headerfile + headoffset, sizeof(inst_name) - 1);
static int getparamval(const char *p)
{
+ ULONG inv = 0;
+ if (p[0] == '~') {
+ inv = 0xffffffff;
+ p++;
+ }
if (strlen(p) > 2 && p[0] == '0' && toupper(p[1]) == 'X') {
char *endptr;
- return strtol(p + 2, &endptr, 16);
+ return strtol(p + 2, &endptr, 16) ^ inv;
} else {
- return atol(p);
+ return atol(p) ^ inv;
}
}
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("-fpuadj <exp> 16-bit exponent range value. (16383 = 1.0)\n");
+ printf("-fpsrmask = ignore FPSR bits that are not set.");
printf("-cycles [range adjust] = check cycle counts.\n");
printf("-cyclecnt <address>. Use custom hardware cycle counter.\n");
#ifdef AMIGA
check_undefined_sr = 1;
ccr_mask = 0xff;
+ fpsr_ignore_mask = 0xffffffff;
disasm = 1;
exitcnt = -1;
cyclecounter_addr = 0xffffffff;
cycles_range = 2;
fpu_adjust_exp = -1;
- fpu_adjust_man = -1;
- fpu_adjust_zb = -1;
for (int i = 1; i < argc; i++) {
char *s = argv[i];
ccr_mask = ~getparamval(next);
i++;
}
+ } else if (!_stricmp(s, "-fpsrmask")) {
+ fpsr_ignore_mask = 0;
+ if (next) {
+ fpsr_ignore_mask = ~getparamval(next);
+ i++;
+ }
} else if (!_stricmp(s, "-silent")) {
dooutput = 0;
} else if (!_stricmp(s, "-68000")) {
exitcnt = atoi(next);
i++;
}
+ } else if (!_stricmp(s, "-irqcnt")) {
+ if (next) {
+ irqcnt = atoi(next);
+ i++;
+ }
} else if (!_stricmp(s, "-prealloc")) {
prealloc = 1;
} 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) {
+ if (fpu_adjust_exp >= 0) {
is_fpu_adjust = 1;
}
return 0;
}
#define MAX_FILE_LEN 128
-#define MAX_MNEMOS 256
- char *dirs = calloc(MAX_MNEMOS, MAX_FILE_LEN);
+#define MAX_FILES 500
+ char *dirs = calloc(MAX_FILES, MAX_FILE_LEN);
int diroff = 0;
+ int dircnt = 0;
if (!dirs)
return 0;
int d = isdir(path, dr->d_name);
if (d && dr->d_name[0] != '.') {
strcpy(dirs + diroff, dr->d_name);
+ dircnt++;
diroff += MAX_FILE_LEN;
- if (diroff >= MAX_FILE_LEN * MAX_MNEMOS) {
- printf("too many directories!?\n");
+ if (dircnt >= MAX_FILES) {
+ printf("too many directories!? (%d)\n", dircnt);
return 0;
}
}
- Interrupt testing (Amiga only, INTREQ bits set one by one, validate correct exception).
- Multiple test sets can be generated and tested in single step.
- Stack usage reduced, gzip decompression works with default 4096 byte stack.
+
+06.12.2021
+
+- FPU testing improvements
void m68k_setstopped(void);
void check_t0_trace(void);
-void cpureset(void);
+bool cpureset(void);