From f31dc40cd6c4907be76c033e206110b73d91c58b Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Mon, 7 Feb 2022 18:00:40 +0200 Subject: [PATCH] Cputester beta updates --- cputest.cpp | 225 +++++++++++++---- cputest/asm.S | 17 +- cputest/cputest_defines.h | 7 +- cputest/cputestgen.ini | 132 ++++++++-- cputest/main.c | 495 ++++++++++++++++++++++++-------------- cputest/readme.txt | 4 + include/cputest.h | 2 +- 7 files changed, 631 insertions(+), 251 deletions(-) diff --git a/cputest.cpp b/cputest.cpp index ed869efc..04f7b9cd 100644 --- a/cputest.cpp +++ b/cputest.cpp @@ -70,6 +70,8 @@ static int feature_usp = 0; 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; @@ -169,8 +171,10 @@ static int interrupt_count; 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; @@ -226,9 +230,10 @@ static int is_superstack_use_required(void) 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; @@ -280,7 +285,7 @@ static bool valid_address(uaecptr addr, int size, int rwp) } 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; } @@ -300,9 +305,9 @@ 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; } @@ -336,7 +341,7 @@ static uae_u8 *get_addr(uaecptr addr, int size, int rwp) 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; } @@ -368,7 +373,7 @@ static void count_interrupt_cycles(int cycles) interrupt_cycle_cnt -= cycles; if (interrupt_cycle_cnt <= 0) { interrupt_cycle_cnt = 0; - interrupt_level = 6; + Exception(24 + 6); } } @@ -841,7 +846,7 @@ uae_u32(*x_cp_next_ilong)(void); 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; @@ -1017,9 +1022,10 @@ void check_t0_trace(void) } } -void cpureset(void) +bool cpureset(void) { cpu_halted = -1; + return false; } static void doexcstack2(void) @@ -2017,7 +2023,7 @@ static uae_u8 *store_rel(uae_u8 *dst, uae_u8 mode, uae_u32 s, uae_u32 d, int ord 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; @@ -2358,7 +2364,7 @@ static void save_data(uae_u8 *dst, const TCHAR *dir, int size) 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); @@ -2688,7 +2694,7 @@ static int create_ea_random(uae_u16 *opcodep, uaecptr pc, int mode, int reg, str addr = pc + 2 - 2; } else { addr = cur_regs.regs[reg + 8]; - if (reg == 7) { + if (reg == 7 && flagsp) { *flagsp |= EAFLAG_SP; } } @@ -2760,7 +2766,7 @@ static int create_ea_random(uae_u16 *opcodep, uaecptr pc, int mode, int reg, str 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); @@ -3037,6 +3043,12 @@ static int create_ea_random(uae_u16 *opcodep, uaecptr pc, int mode, int reg, str } 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; @@ -3864,20 +3876,20 @@ static bool check_interrupts(void) 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(""); @@ -3930,7 +3942,7 @@ static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp) cnt = 100; } if (feature_interrupts == 2) { - interrupt_cycle_cnt = 10; + interrupt_cycle_cnt = SERPER * 10 - 20; } for (;;) { @@ -3974,6 +3986,21 @@ static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp) (*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) { @@ -4367,6 +4394,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi xorshiftstate ^= ovrfilename[i]; } } + xorshiftstate ^= rnd_seed; int pathlen = _tcslen(path); _stprintf(dir, _T("%s%s"), path, mns); @@ -4416,12 +4444,13 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi 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 } @@ -4545,8 +4574,8 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi 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); @@ -4561,6 +4590,11 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi 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) @@ -4691,7 +4725,8 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi 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]; @@ -4736,10 +4771,15 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi // 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; } @@ -4751,7 +4791,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi put_long_test(pc, 0x4e500004 | (dp->sreg << 16)); pc += 4; opcode_memory_address = pc; - loopmode_jump_offset = -4; + loopmode_jump_offset = 4; pc += 2; } @@ -4908,11 +4948,37 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi 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)); @@ -4937,7 +5003,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi // 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); @@ -4970,7 +5036,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi // 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; @@ -5019,7 +5085,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi 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); @@ -5035,7 +5101,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi 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); } @@ -5043,7 +5109,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi } // 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) { @@ -5152,8 +5218,13 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi 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 { @@ -5181,6 +5252,9 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi } } + if (subtest_count == 8192) + printf(""); + // save opcode memory dst = store_mem_bytes(dst, opcode_memory_start, instruction_end_pc - opcode_memory_start, oldcodebytes, true); @@ -5220,6 +5294,12 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi 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; @@ -5236,6 +5316,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi 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; @@ -5245,24 +5326,31 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi 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; } } @@ -5283,10 +5371,16 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi } *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; @@ -5306,7 +5400,9 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi // 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)) { @@ -5406,6 +5502,10 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi } 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]; @@ -5430,11 +5530,11 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi 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++; @@ -5704,6 +5804,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi // undo any test instruction generated memory modifications undo_memory(ahist, ahcnt_start); } + nextextra: extraccr++; if (extraccr >= 16) @@ -5757,7 +5858,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi } } 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++) { @@ -5847,14 +5948,18 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi 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; @@ -6279,6 +6384,12 @@ static int test(struct ini_data *ini, const TCHAR *sections, const TCHAR *testna 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); @@ -6303,6 +6414,29 @@ static int test(struct ini_data *ini, const TCHAR *sections, const TCHAR *testna } } + 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); @@ -6802,9 +6936,6 @@ static int test(struct ini_data *ini, const TCHAR *sections, const TCHAR *testna 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]; @@ -6994,6 +7125,8 @@ int __cdecl main(int argc, char *argv[]) return 0; } + disasm_init(); + TCHAR *sptr = sections; _tcscpy(sections, INISECTION); sptr += _tcslen(sptr) + 1; diff --git a/cputest/asm.S b/cputest/asm.S index b1e22947..5ff07086 100644 --- a/cputest/asm.S +++ b/cputest/asm.S @@ -25,6 +25,7 @@ .globl _cyclereg_address5 .globl _cyclereg_address6 .globl _berrcopy + .globl _fpucomp | must match main.c S_DREG = 0 @@ -49,6 +50,20 @@ S_FPSR = S_FPCR+4 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: @@ -214,7 +229,7 @@ _execute_test010: _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 diff --git a/cputest/cputest_defines.h b/cputest/cputest_defines.h index cc3a4458..4bca3244 100644 --- a/cputest/cputest_defines.h +++ b/cputest/cputest_defines.h @@ -1,5 +1,5 @@ -#define DATA_VERSION 21 +#define DATA_VERSION 22 #define CT_FPREG 0 #define CT_DREG 0 @@ -11,6 +11,7 @@ #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 @@ -21,6 +22,8 @@ #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) @@ -54,3 +57,5 @@ #define NOP_OPCODE 0x2048 #define ILLG_OPCODE 0x4afc #define LM_OPCODE 0x42db + +#define SERPER 8 diff --git a/cputest/cputestgen.ini b/cputest/cputestgen.ini index d26f6e96..a5d97cbf 100644 --- a/cputest/cputestgen.ini +++ b/cputest/cputestgen.ini @@ -1,18 +1,30 @@ [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 @@ -28,24 +40,28 @@ feature_gzip=0 ; 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 @@ -126,8 +142,13 @@ feature_flags_mode=1 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 @@ -151,14 +172,16 @@ feature_undefined_ccr=0 ; reg=0x1234 or reg=100 ;feature_forced_register= -; generate loop test: label: 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: , , 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. @@ -185,6 +208,9 @@ feature_instruction_size= ; 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 @@ -207,6 +233,14 @@ feature_sr_mask=0x8000 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 @@ -345,8 +379,7 @@ mode=all 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 @@ -377,6 +410,7 @@ enabled=0 cpu=68020-68060 feature_addressing_modes_src=Ad8rf,PC8rf test_rounds=4 +verbose=0 min_opcode_test_rounds=5000 mode=not,move @@ -385,6 +419,7 @@ enabled=0 cpu=68020-68060 feature_addressing_modes_dst=Ad8rf,PC8rf test_rounds=4 +verbose=0 min_opcode_test_rounds=5000 mode=add,move @@ -432,6 +467,7 @@ enabled=0 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 @@ -440,7 +476,7 @@ mode=fmove,fsmove,fdmove,fint,fintrz,fneg,fsneg,fdneg,fabs,fsabs,fdabs,fdiv,fsdi ; 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 @@ -451,9 +487,10 @@ mode=flog10,flogn,flognp1,fsin,fsincos,fsinh,ftan,ftanh,ftentox ; 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 @@ -477,19 +514,64 @@ cpu=68020-68060 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 diff --git a/cputest/main.c b/cputest/main.c index f3b1d5b7..5a1c9060 100644 --- a/cputest/main.c +++ b/cputest/main.c @@ -61,6 +61,15 @@ struct registers 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; @@ -90,7 +99,7 @@ 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; +static short fpu_adjust_exp; struct fpureg fpu_adjust; static uae_u32 cpustatearraystore[16]; static uae_u32 cpustatearraynew[] = { @@ -132,6 +141,7 @@ static int fpu_approx, fpu_approxcnt; 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; @@ -144,10 +154,12 @@ static short skipregchange; 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; @@ -222,6 +234,10 @@ static void flushcache(uae_u32 v) 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 @@ -246,6 +262,7 @@ extern void setcpu(uae_u32, uae_u32*, uae_u32*); 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; @@ -301,6 +318,29 @@ uae_s32 lls(uae_u16 *p) 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); @@ -1194,12 +1234,30 @@ static uae_u8 *restore_memory(uae_u8 *p, int storedata) 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); } @@ -1248,6 +1306,8 @@ static uae_u8 *restore_data(uae_u8 *p, struct registers *r) 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); @@ -1613,6 +1673,52 @@ static int compare_exception(uae_u8 *s1, uae_u8 *s2, int len, int domask, uae_u8 } } +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; @@ -2070,6 +2176,16 @@ static int get_cycles_amiga(void) 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) { @@ -2191,29 +2307,6 @@ static int check_cycles(int exc, short extratrace, short extrag2w1, struct regis 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) @@ -2229,97 +2322,44 @@ 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) @@ -2386,6 +2426,12 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr, st 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)); @@ -2469,14 +2515,20 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr, st 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; } @@ -2501,7 +2553,13 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr, st } 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; } @@ -2630,7 +2688,7 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr, st 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); @@ -2768,7 +2826,7 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr, st } } 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); @@ -2809,30 +2867,46 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr, st } 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; @@ -2948,9 +3022,9 @@ static uae_u32 xorshift32(void) 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)); } } @@ -2982,9 +3056,20 @@ static void process_test(uae_u8 *p) 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; @@ -3016,7 +3101,7 @@ static void process_test(uae_u8 *p) 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; @@ -3042,22 +3127,31 @@ static void process_test(uae_u8 *p) 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); @@ -3075,11 +3169,11 @@ static void process_test(uae_u8 *p) 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; @@ -3112,7 +3206,7 @@ static void process_test(uae_u8 *p) } #ifdef AMIGA - if (interrupttest) { + if (interrupttest == 1) { interrupt_count = *p++; } #endif @@ -3161,6 +3255,11 @@ static void process_test(uae_u8 *p) } 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; @@ -3184,7 +3283,10 @@ static void process_test(uae_u8 *p) 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); @@ -3192,7 +3294,11 @@ static void process_test(uae_u8 *p) end_test(); printf(outbuffer); printf("\nExit count expired\n"); + if (interrupttest == 2) { + interrupt_results(); + } exit(0); +#endif } } @@ -3223,8 +3329,10 @@ static void process_test(uae_u8 *p) #ifdef AMIGA - if (interrupttest) { + if (interrupttest == 1) { set_interrupt(); + } else if (interrupttest == 2) { + set_interrupt_sertest(); } #endif if (cpu_lvl == 1) { @@ -3289,26 +3397,29 @@ static void process_test(uae_u8 *p) 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++; } } @@ -3328,6 +3439,20 @@ static void process_test(uae_u8 *p) } 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); + } + } + } } @@ -3343,6 +3468,9 @@ end: printf("%s", outbuffer); } } + if (interrupttest == 2) { + interrupt_results(); + } } static void freestuff(void) @@ -3402,7 +3530,7 @@ static int test_mnemo(const char *opcode) 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; @@ -3421,6 +3549,9 @@ static int test_mnemo(const char *opcode) 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); @@ -3590,11 +3721,16 @@ static int test_mnemo(const char *opcode) 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; } } @@ -3670,7 +3806,8 @@ int main(int argc, char *argv[]) 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 .\n"); + printf("-fpuadj 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
. Use custom hardware cycle counter.\n"); #ifdef AMIGA @@ -3684,13 +3821,12 @@ int main(int argc, char *argv[]) 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]; @@ -3711,6 +3847,12 @@ int main(int argc, char *argv[]) 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")) { @@ -3746,20 +3888,17 @@ int main(int argc, char *argv[]) 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; } @@ -3893,9 +4032,10 @@ int main(int argc, char *argv[]) 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; @@ -3906,9 +4046,10 @@ int main(int argc, char *argv[]) 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; } } diff --git a/cputest/readme.txt b/cputest/readme.txt index f3c81d28..b9a5e49f 100644 --- a/cputest/readme.txt +++ b/cputest/readme.txt @@ -218,3 +218,7 @@ Only test generator was updated. Data structures or m68k tester has not been cha - 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 diff --git a/include/cputest.h b/include/cputest.h index bbfd0e31..a640d236 100644 --- a/include/cputest.h +++ b/include/cputest.h @@ -66,4 +66,4 @@ void m68k_do_jsr_ce(uaecptr oldpc, uaecptr dest); void m68k_setstopped(void); void check_t0_trace(void); -void cpureset(void); +bool cpureset(void); -- 2.47.3