From: Toni Wilen Date: Wed, 29 Jul 2020 13:12:02 +0000 (+0300) Subject: CPU tester JIT loop mode updates. X-Git-Tag: 4900~332 X-Git-Url: https://git.unchartedbackwaters.co.uk/w/?a=commitdiff_plain;h=e3ecae76062d5900e7963e8c0477cb104df152f0;p=francis%2Fwinuae.git CPU tester JIT loop mode updates. --- diff --git a/cputest.cpp b/cputest.cpp index 30db6f02..ed869efc 100644 --- a/cputest.cpp +++ b/cputest.cpp @@ -58,9 +58,10 @@ static int feature_exception3_instruction = 0; static int feature_sr_mask = 0; static int feature_undefined_ccr = 0; static int feature_min_interrupt_mask = 0; -static int feature_loop_mode = 0; +static int feature_loop_mode_cnt = 0; static int feature_loop_mode_register = -1; static int feature_loop_mode_68010 = 0; +static int feature_loop_mode_jit = 0; static int feature_full_extension_format = 0; static int feature_test_rounds = 2; static int feature_test_rounds_opcode = 0; @@ -168,6 +169,8 @@ 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 uae_u8 ccr_cnt; struct uae_prefs currprefs; @@ -182,7 +185,7 @@ struct accesshistory static int ahcnt_current, ahcnt_written; static int noaccesshistory = 0; -#define MAX_ACCESSHIST 16000 +#define MAX_ACCESSHIST 32000 static struct accesshistory ahist[MAX_ACCESSHIST]; static void pw(uae_u8 *p, uae_u16 v) @@ -331,6 +334,12 @@ static uae_u8 *get_addr(uaecptr addr, int size, int rwp) } addr &= addressing_mask; 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) { + goto oob; + } + if (low_memory_size != 0xffffffff && addr + size < low_memory_size) { return low_memory + addr; } else if (high_memory_size != 0xffffffff && addr >= HIGH_MEMORY_START && addr <= HIGH_MEMORY_START + 0x7fff) { @@ -479,7 +488,7 @@ static void previoussame(uaecptr addr, int size, uae_u32 *old) bool gotold = false; for (int i = ahcnt_written; i < ahcnt_current; i++) { struct accesshistory *ah = &ahist[i]; - if ((!feature_loop_mode || !testing_active) && ah->size == size && ah->addr == addr) { + if (((!feature_loop_mode_jit && !feature_loop_mode_68010) || !testing_active) && ah->size == size && ah->addr == addr) { ah->donotsave = true; if (!gotold) { *old = ah->oldval; @@ -1450,7 +1459,7 @@ void REGPARAM2 Exception(int n) test_exception_opcode = -1; doexcstack(); } -void REGPARAM2 Exception_cpu(int n) +void REGPARAM2 Exception_cpu_oldpc(int n, uaecptr oldpc) { test_exception = n; test_exception_addr = m68k_getpci(); @@ -1465,6 +1474,10 @@ void REGPARAM2 Exception_cpu(int n) } doexcstack(); } +void REGPARAM2 Exception_cpu(int n) +{ + Exception_cpu_oldpc(n, 0xffffffff); +} void exception3i(uae_u32 opcode, uaecptr addr) { test_exception = 3; @@ -1488,6 +1501,36 @@ void exception3b(uae_u32 opcode, uaecptr addr, bool w, bool i, uaecptr pc) doexcstack(); } +#define CCR_C 1 +#define CCR_V 2 +#define CCR_Z 4 +#define CCR_N 8 + +void getcc(int cc, uae_u8 *ccrorp, uae_u8 *ccrandp) +{ + uae_u8 cor = 0, cand = 0; + switch (cc) + { + case 2: cand |= CCR_C | CCR_Z; break; + case 3: cor |= CCR_C | CCR_Z; break; + case 4: cand |= CCR_C; break; + case 5: cor |= CCR_C; break; + case 6: cand |= CCR_Z; break; + case 7: cor |= CCR_Z; break; + case 8: cand |= CCR_V; break; + case 9: cor |= CCR_V; break; + case 10: cand |= CCR_N; break; + case 11: cor |= CCR_N; break; + case 12: cor |= CCR_N | CCR_V; break; + case 13: cor |= CCR_N; cand |= CCR_V; break; + case 14: cor |= CCR_N | CCR_V; cand |= CCR_Z; break; + case 15: cor |= CCR_N | CCR_Z; cand |= CCR_V; break; + } + cand ^= 0xff; + *ccrorp = cor; + *ccrandp = cand; +} + int cctrue(int cc) { uae_u32 cznv = regflags.cznv; @@ -1779,15 +1822,12 @@ static bool regchange(int reg, uae_u32 *regs) } break; case 11: - if (feature_loop_mode && !feature_loop_mode_68010) { + if (feature_loop_mode_jit) { return false; } v ^= 0x8000; break; case 12: - if (feature_loop_mode && !feature_loop_mode_68010) { - return false; - } v ^= 0x80000000; v = (v & 0xffffff00) | ((v + 0x14) & 0xff); break; @@ -1821,6 +1861,9 @@ static void fill_memory(void) if (high_memory_temp) fill_memory_buffer(high_memory_temp, high_memory_size); fill_memory_buffer(test_memory_temp, test_memory_size); + if (feature_loop_mode_jit) { + memset(test_memory_temp, 0xff, LM_BUFFER); + } } static void compressfile(TCHAR *path, int flags) @@ -2292,7 +2335,7 @@ static void save_data(uae_u8 *dst, const TCHAR *dir, int size) fwrite(data, 1, 4, f); pl(data, (cpu_lvl << 16) | sr_undefined_mask | (addressing_mask == 0xffffffff ? 0x80000000 : 0) | (feature_min_interrupt_mask << 20) | (safe_memory_mode << 23) | (feature_interrupts << 26) | - ((feature_loop_mode ? 1 : 0) << 28) | ((feature_loop_mode_68010 ? 1 : 0) << 29)); + ((feature_loop_mode_jit ? 1 : 0) << 28) | ((feature_loop_mode_68010 ? 1 : 0) << 29)); fwrite(data, 1, 4, f); pl(data, currprefs.fpu_model); fwrite(data, 1, 4, f); @@ -2315,7 +2358,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); + pl(data, feature_loop_mode_cnt); fwrite(&data[0], 1, 4, f); fwrite(&data[1], 1, 4, f); fwrite(&data[2], 1, 4, f); @@ -2518,8 +2561,8 @@ static int create_ea_random(uae_u16 *opcodep, uaecptr pc, int mode, int reg, str if (feature_full_extension_format == 2 && (ad8r[srcdst] || pc8r[srcdst]) && (mode != Ad8r && mode != PC8r)) return -1; - if (feature_loop_mode) { - // loop mode JMP or JSR: skip if A3, A4 or A7 is used in EA calculation + if (feature_loop_mode_jit) { + // loop mode JMP or JSR: skip if A3 or A7 is used in EA calculation if (dp->mnemo == i_JMP || dp->mnemo == i_JSR) { if (mode == Areg || mode == Aind || mode == Aipi || mode == Apdi || mode == Ad16 || mode == Ad8r) { if (reg == 3 || reg == 7) { @@ -2533,16 +2576,21 @@ static int create_ea_random(uae_u16 *opcodep, uaecptr pc, int mode, int reg, str switch (mode) { case Dreg: - *regused = reg; - if (reg == feature_loop_mode_register) { - if (((dp->sduse & 0x20) && !srcdst) || ((dp->sduse & 0x02) && srcdst)) { - int newreg = (reg + 1) & 7; - int pos = srcdst ? dp->dpos : dp->spos; - opcode &= ~(7 << pos); - opcode |= newreg << pos; - *regused = newreg; + for (;;) { + if (reg == feature_loop_mode_register) { + if (((dp->sduse & 0x20) && !srcdst) || ((dp->sduse & 0x02) && srcdst)) { + reg = (reg + 1) & 7; + int pos = srcdst ? dp->dpos : dp->spos; + opcode &= ~(7 << pos); + opcode |= reg << pos; + } else { + break; + } + } else { + break; } } + *regused = reg; break; case Areg: *regused = reg + 8; @@ -2649,7 +2697,7 @@ static int create_ea_random(uae_u16 *opcodep, uaecptr pc, int mode, int reg, str if (currprefs.cpu_model >= 68020) v &= ~0x100; ereg = v >> 12; - if (loopmodelimit && (ereg == 0 || ereg == 8 + 3 || ereg == 8 + 4 || ereg == 8 + 7 || ereg == feature_loop_mode_register)) { + if (loopmodelimit && (ereg == 0 || ereg == 8 + 3 || ereg == 8 + 7 || ereg == feature_loop_mode_register)) { continue; } break; @@ -2704,7 +2752,7 @@ static int create_ea_random(uae_u16 *opcodep, uaecptr pc, int mode, int reg, str break; } int ereg = v >> 12; - if (loopmodelimit && (ereg == 0 || ereg == 8 + 3 || ereg == 8 + 4 || ereg == 8 + 7 || ereg == feature_loop_mode_register)) { + if (loopmodelimit && (ereg == 0 || ereg == 8 + 3 || ereg == 8 + 7 || ereg == feature_loop_mode_register)) { return -1; } *regused = ereg; @@ -3019,7 +3067,6 @@ static int create_ea_random(uae_u16 *opcodep, uaecptr pc, int mode, int reg, str break; } } -end: *opcodep = opcode; return pc - old_pc; } @@ -3546,7 +3593,7 @@ static uaecptr handle_specials_extra(uae_u16 opcode, uaecptr pc, struct instr *d static uae_u32 generate_stack_return(int cnt) { uae_u32 v; - if (feature_loop_mode) { + if (feature_loop_mode_jit) { // if loop mode: return after test instruction v = test_instruction_end_pc; } else if (target_ea[0] != 0xffffffff && feature_usp < 3) { @@ -3610,7 +3657,7 @@ static int handle_rte(uae_u16 opcode, uaecptr pc, struct instr *dp, int *isconst imm_special += 4; continue; } - if (feature_loop_mode && frame != 0 && frame != 2) { + if (feature_loop_mode_jit && frame != 0 && frame != 2) { imm_special += 4; continue; } @@ -3619,7 +3666,7 @@ static int handle_rte(uae_u16 opcode, uaecptr pc, struct instr *dp, int *isconst v = imm_special >> 6; uae_u16 sr = v & 31; sr |= (v >> 5) << 12; - if (feature_loop_mode) { + if (feature_loop_mode_jit) { sr &= ~(0x8000 | 0x4000 | 0x1000); sr |= 0x2000; } @@ -3704,6 +3751,108 @@ static int handle_specials_stack(uae_u16 opcode, uaecptr pc, struct instr *dp, i return offset; } +// instruction that reads or writes stack +static int stackinst(struct instr *dp) +{ + switch (dp->mnemo) + { + case i_RTS: + case i_RTR: + case i_RTD: + case i_RTE: + case i_UNLK: + return 1; + case i_BSR: + case i_JSR: + case i_LINK: + case i_PEA: + return 2; + } + return 0; +} + +// instructions that check CCs +// does not use dp->ccuse because TrapV isn't actual CC instruction +static int isccinst(struct instr *dp) +{ + switch (dp->mnemo) + { + case i_Bcc: + case i_DBcc: + case i_Scc: + case i_FBcc: + case i_FDBcc: + case i_FScc: + return 1; + case i_TRAPcc: + case i_TRAPV: + case i_FTRAPcc: + return 2; + + } + return 0; +} + +// any instruction that can branch execution +static int isbranchinst(struct instr *dp) +{ + switch (dp->mnemo) + { + case i_Bcc: + case i_BSR: + case i_JMP: + case i_JSR: + return 1; + case i_RTS: + case i_RTR: + case i_RTD: + case i_RTE: + return 2; + case i_DBcc: + case i_FBcc: + case i_FDBcc: + return -1; + } + return 0; +} + +static int isunsupported(struct instr *dp) +{ + switch (dp->mnemo) + { + case i_MOVE2C: + case i_FSAVE: + case i_FRESTORE: + case i_PFLUSH: + case i_PFLUSHA: + case i_PFLUSHAN: + case i_PFLUSHN: + case i_PTESTR: + case i_PTESTW: + case i_CPUSHA: + case i_CPUSHL: + case i_CPUSHP: + case i_CINVA: + case i_CINVL: + case i_CINVP: + case i_PLPAR: + case i_PLPAW: + case i_CALLM: + case i_RTM: + return 1; + } + if (feature_loop_mode_jit) { + switch (dp->mnemo) + { + case i_MOVEC2: + case i_RTE: + case i_ILLG: + return 1; + } + } + return 0; +} + static const int interrupt_levels[] = { 0, 1, 1, 1, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 6, 6 @@ -3772,10 +3921,10 @@ static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp) uae_u32 loop_mode_reg = 0; if (feature_loop_mode_68010) { // 68010 loop mode - cnt = (feature_loop_mode + 1) * 2; - } else if (feature_loop_mode) { + cnt = (feature_loop_mode_cnt + 1) * 2; + } else if (feature_loop_mode_jit) { // JIT loop mode - cnt = (feature_loop_mode + 1) * 20; + cnt = (feature_loop_mode_cnt + 1) * 20 * 2; } if (multi_mode) { cnt = 100; @@ -3793,6 +3942,11 @@ static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp) } if (cnt <= 0) { + if (feature_loop_mode_jit && isccinst(dp) == 2) { + // if instruction was always false + test_exception = -1; + break; + } wprintf(_T(" Loop mode didn't end!?\n")); abort(); } @@ -3813,7 +3967,7 @@ static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp) bool test_ins = false; if (regs.pc == first_pc) { test_ins = true; - if (feature_loop_mode) { + if (feature_loop_mode_jit || feature_loop_mode_68010) { loop_mode_reg = regs.regs[feature_loop_mode_register]; } } @@ -3822,7 +3976,7 @@ static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp) if (test_ins) { // skip if test instruction modified loop mode register - if (feature_loop_mode) { + if (feature_loop_mode_jit || feature_loop_mode_68010) { if ((regs.regs[feature_loop_mode_register] & 0xffff) != (loop_mode_reg & 0xffff)) { test_exception = -1; break; @@ -3888,7 +4042,7 @@ static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp) break; } - if (!feature_loop_mode) { + if (!feature_loop_mode_jit && !feature_loop_mode_68010) { // trace after NOP if (SPCFLAG_DOTRACE) { MakeSR(); @@ -3914,7 +4068,7 @@ static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp) cnt--; - if (!feature_loop_mode && !multi_mode && opc != NOP_OPCODE) { + if (!feature_loop_mode_jit && !feature_loop_mode_68010 && !multi_mode && opc != NOP_OPCODE) { wprintf(_T(" Test instruction didn't finish in single step in non-loop mode!?\n")); abort(); } @@ -3936,87 +4090,6 @@ static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp) } } -// instruction that reads or writes stack -static int stackinst(struct instr *dp) -{ - switch (dp->mnemo) - { - case i_RTS: - case i_RTR: - case i_RTD: - case i_RTE: - case i_UNLK: - return 1; - case i_BSR: - case i_JSR: - case i_LINK: - case i_PEA: - return 2; - } - return 0; -} - -// any instruction that can branch execution -static int isbranchinst(struct instr *dp) -{ - switch (dp->mnemo) - { - case i_Bcc: - case i_BSR: - case i_JMP: - case i_JSR: - return 1; - case i_RTS: - case i_RTR: - case i_RTD: - case i_RTE: - return 2; - case i_DBcc: - case i_FBcc: - case i_FDBcc: - return -1; - } - return 0; -} - -static int isunsupported(struct instr *dp) -{ - switch (dp->mnemo) - { - case i_MOVE2C: - case i_FSAVE: - case i_FRESTORE: - case i_PFLUSH: - case i_PFLUSHA: - case i_PFLUSHAN: - case i_PFLUSHN: - case i_PTESTR: - case i_PTESTW: - case i_CPUSHA: - case i_CPUSHL: - case i_CPUSHP: - case i_CINVA: - case i_CINVL: - case i_CINVP: - case i_PLPAR: - case i_PLPAW: - case i_CALLM: - case i_RTM: - return 1; - } - if (feature_loop_mode) { - switch (dp->mnemo) - { - case i_MOVEC2: - case i_UNLK: - case i_RTE: - case i_ILLG: - return 1; - } - } - return 0; -} - static int noregistercheck(struct instr *dp) { return 0; @@ -4349,9 +4422,8 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi int count = 0; - if (feature_loop_mode && !feature_loop_mode_68010) { - registers[8 + 3] = 0; // A3 = 0 - registers[8 + 4] = 0; // A4 = 0 + if (feature_loop_mode_jit) { + registers[8 + 3] = test_memory_start; // A3 = start of test memory } registers[8 + 6] = opcode_memory_start - 0x100; @@ -4464,9 +4536,10 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi modify_reg(NULL, &cur_regs, rd->type, rd->data); } - if (feature_loop_mode) { + if (feature_loop_mode_jit || feature_loop_mode_68010) { cur_regs.regs[feature_loop_mode_register] &= 0xffff0000; - cur_regs.regs[feature_loop_mode_register] |= feature_loop_mode - 1; + cur_regs.regs[feature_loop_mode_register] |= feature_loop_mode_cnt - 1; + cur_regs.regs[feature_loop_mode_register] |= 0x80000000; } for (int i = 0; i < MAX_REGISTERS; i++) { @@ -4606,6 +4679,8 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi int srceaflags = 0; int dsteaflags = 0; + int loopmode_jump_offset = 0; + out_of_test_space = 0; noaccesshistory = 0; hardware_bus_error_fake = 0; @@ -4616,6 +4691,7 @@ 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; target_ea[0] = target_ea_bak[0]; target_ea[1] = target_ea_bak[1]; @@ -4668,6 +4744,17 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi pc += 2; } + // UNLK loop mode special case + if (dp->mnemo == i_UNLK && feature_loop_mode_jit) { + pc -= 2; + // link an,#x + put_long_test(pc, 0x4e500004 | (dp->sreg << 16)); + pc += 4; + opcode_memory_address = pc; + loopmode_jump_offset = -4; + pc += 2; + } + // Start address to start address + 3 must be accessible or // jump prefetch would cause early bus error which we don't want if (is_nowrite_address(startpc, 4)) { @@ -4818,65 +4905,62 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi test_instruction_end_pc = pc; // loop mode - if (feature_loop_mode) { + if (feature_loop_mode_jit || feature_loop_mode_68010) { + int cctype = isccinst(dp); // dbf dn, opcode_memory_start - if (!feature_loop_mode_68010) { - uae_u16 ccrmaskt = get_ccr_ignore(dp, extraword, true); - uae_u16 ccrmask = ccrmaskt & (0x08 | 0x01); - if (ccrmaskt & 0x04) - ccrmask |= 0x02; - if (ccrmaskt & 0x02) - ccrmask |= 0x04; - // add.l a3,a3 - put_word(pc, 0xd7cb); - pc += 2; - // add.l a4,a4 - put_word(pc, 0xd9cc); - pc += 2; - for (int i = 0; i < 4; i++) { - // bcc, bne, bvc, bpl - uaecptr bcc = pc; - pc += 2; - uae_u32 add = 0; - if (!(ccrmask & (1 << i))) { - add = 1 << (i * 8); - } - if (add >= 1 && add <= 8) { - if (add == 8) { - add = 0; - } - // addq.w #x,a3 - put_word(pc, 0x5048 | 3 | (add << 9)); - pc += 2; - } else if (add < 65536) { - // add.w #x,a3 - put_long(pc, (0xd6fc << 16) | add); - pc += 4; - } else { - // add.l #x,a3 - put_word(pc, 0xd7fc); - pc += 2; - put_long(pc, add); - pc += 4; - } - put_word(bcc, 0x6400 + (i * 0x0200) + (pc - bcc) - 2); - } - // sub.l d0,a4 - put_word(pc, 0x99c0); - pc += 2; - // negx.w d0 - put_word(pc, 0x4080); - pc += 2; - // neg.w d0 - put_word(pc, 0x4480); - pc += 2; - // add.l d0,a4 - put_word(pc, 0xd9c0); + if (feature_loop_mode_jit) { + // move ccr,(a3)+ + lm_safe_address = pc; + put_word(pc, LM_OPCODE); pc += 2; } // dbf dn,label - put_long_test(pc, ((0x51c8 | feature_loop_mode_register) << 16) | ((opcode_memory_address - pc - 2) & 0xffff)); + put_long_test(pc, ((0x51c8 | feature_loop_mode_register) << 16) | ((opcode_memory_address - pc - loopmode_jump_offset - 2) & 0xffff)); pc += 4; + if (feature_loop_mode_jit) { + if (cctype == 2) { + // generate matching CCR, for TRAPcc, TRAPv, FTRAPcc + uae_u8 ccor, ccand; + getcc(dp->cc, &ccor, &ccand); + // move ccr,d0 + put_word(pc, 0x42c1); + pc += 2; + // or.w #x,d0 + put_long(pc, 0x00410000 | ccor); + pc += 4; + // and.w #x,d0 + put_long(pc, 0x02410000 | ccand); + pc += 4; + // move d0,ccr + put_word(pc, 0x44c1); + pc += 2; + // bra.s start + put_word(pc, 0x6000 + (0xfe - pc - opcode_memory_address)); + pc += 2; + } else if (feature_loop_mode_jit == 2) { + // generate extra round with randomized CCR + // tst.l dx + put_word(pc, 0x4a80 | feature_loop_mode_register); + pc += 2; + // bpl.s end + put_word(pc, 0x6a08); + pc += 2; + // moveq #x,dx + put_word(pc, 0x7000 | (feature_loop_mode_register << 9) | (feature_loop_mode_cnt - 1)); + pc += 2; + // move #x,ccr + put_long(pc, 0x44fc0000 | ((ccr_cnt++) & 0x1f)); + pc += 4; + // bra.s start + put_word_test(pc, 0x6000 | ((opcode_memory_address - pc - loopmode_jump_offset - 2) & 0xff)); + pc += 2; + } + } + } + + if (pc - opcode_memory_address > OPCODE_AREA) { + wprintf(_T("Test code too large!\n")); + abort(); } // if instruction was long enough to hit safe area, decrease pc until we are back to normal area @@ -4945,7 +5029,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi if (dstaddr != 0xffffffff && srcaddr != dstaddr) { outbytes(_T("D"), dstaddr); } - if (feature_loop_mode) { + if (feature_loop_mode_jit || feature_loop_mode_68010) { wprintf(_T("\n")); for (int i = 0; i < 20; i++) { out_of_test_space = false; @@ -5013,7 +5097,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi int stackpcoffset = 0; int stackoffset = 0; // if loop mode: all loop mode rounds need stacked data - for (int i = 0; i < (feature_loop_mode ? feature_loop_mode : 1); i++) { + for (int i = 0; i < (feature_loop_mode_cnt ? feature_loop_mode_cnt : 1); i++) { stackpcoffset = handle_specials_stack(opc, pc, dp, &isconstant_src, &stackoffset); } if (isconstant_src < 0 || isconstant_dst < 0) { @@ -5035,8 +5119,10 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi continue; } testing_active = 1; - if (feature_loop_mode) { - if ((srcaddr & addressing_mask) != test_instruction_end_pc && !valid_address(srcaddr, 8, 1)) { + if (feature_loop_mode_jit) { + if ((srcaddr & addressing_mask) != test_instruction_end_pc && (!valid_address(srcaddr, 8, 1) || + ((srcaddr + 2) & addressing_mask) == opcode_memory_start || ((srcaddr + 4) & addressing_mask) == opcode_memory_start || + ((srcaddr + 6) & addressing_mask) == opcode_memory_start || ((srcaddr + 8) & addressing_mask) == opcode_memory_start)) { if (verbose) { wprintf(_T(" Branch target inaccessible (%08x)\n"), srcaddr); } @@ -5045,7 +5131,8 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi continue; } } else { - if (!valid_address(srcaddr, 2, 1) || ((srcaddr + 2) & addressing_mask) == opcode_memory_start) { + if (!valid_address(srcaddr, 2, 1) || ((srcaddr + 2) & addressing_mask) == opcode_memory_start || + ((srcaddr + 4) & addressing_mask) == opcode_memory_start || ((srcaddr + 6) & addressing_mask) == opcode_memory_start) { if (verbose) { wprintf(_T(" Branch target inaccessible (%08x)\n"), srcaddr); } @@ -5063,7 +5150,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi oldbcbytes_inuse = 0; if (bc) { - if (feature_loop_mode) { + if (feature_loop_mode_jit) { if (srcaddr != test_instruction_end_pc) { // addq.w #2,a3, jmp xxx put_long_test(srcaddr, 0x544b4ef9); @@ -5173,7 +5260,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi } } else { maxflag = 32; // all flag combinations (*32) - if (feature_flag_mode > 1 || (feature_flag_mode == 1 && (dp->mnemo == i_ILLG || !dp->ccuse))) { + 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; } @@ -5427,7 +5514,8 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi } } - if (test_exception >= 2 && feature_loop_mode) { + // skip exceptions if loop mode and not CC instruction + if (test_exception >= 2 && feature_loop_mode_jit && !isccinst(dp)) { skipped = 1; } @@ -5488,7 +5576,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi abort(); } } - if (!feature_loop_mode) { + if (!feature_loop_mode_jit) { uae_u32 t1 = gl(pcaddr - 2); uae_u32 t2 = gl(pcaddr); if (t1 != ((NOP_OPCODE << 16) | ILLG_OPCODE) && t2 != ((ILLG_OPCODE << 16) | NOP_OPCODE)) { @@ -6380,13 +6468,25 @@ static int test(struct ini_data *ini, const TCHAR *sections, const TCHAR *testna feature_min_interrupt_mask = 0; ini_getvalx(ini, sections, _T("feature_min_interrupt_mask"), &feature_min_interrupt_mask); - feature_loop_mode = 0; - ini_getvalx(ini, sections, _T("feature_loop_mode"), &feature_loop_mode); - if (feature_loop_mode) { + feature_loop_mode_jit = 0; + feature_loop_mode_68010 = 0; + ini_getvalx(ini, sections, _T("feature_loop_mode"), &feature_loop_mode_jit); + if (feature_loop_mode_jit) { + feature_loop_mode_cnt = 8; + feature_loop_mode_68010 = 0; feature_loop_mode_register = 7; } feature_loop_mode_68010 = 0; ini_getvalx(ini, sections, _T("feature_loop_mode_68010"), &feature_loop_mode_68010); + if (feature_loop_mode_68010) { + feature_loop_mode_cnt = 8; + feature_loop_mode_jit = 0; + feature_loop_mode_register = 7; + } + if (feature_loop_mode_jit || feature_loop_mode_68010) { + ini_getvalx(ini, sections, _T("feature_loop_mode_register"), &feature_loop_mode_register); + ini_getvalx(ini, sections, _T("feature_loop_mode_cnt"), &feature_loop_mode_cnt); + } feature_flag_mode = 0; ini_getvalx(ini, sections, _T("feature_flags_mode"), &feature_flag_mode); @@ -6664,8 +6764,7 @@ static int test(struct ini_data *ini, const TCHAR *sections, const TCHAR *testna movem_next[i] = i & (~(1 << j)); } - read_table68k(); - do_merges(); + init_table68k(); if (currprefs.cpu_model == 68000) { tbl = op_smalltbl_90_test_ff; @@ -6694,9 +6793,9 @@ static int test(struct ini_data *ini, const TCHAR *sections, const TCHAR *testna cpufunctbl[opcode] = op_illg_1; } - for (int i = 0; tbl[i].handler != NULL; i++) { + for (int i = 0; tbl[i].handler_ff != NULL; i++) { int opcode = tbl[i].opcode; - cpufunctbl[opcode] = tbl[i].handler; + cpufunctbl[opcode] = tbl[i].handler_ff; cpudatatbl[opcode].length = tbl[i].length; cpudatatbl[opcode].disp020[0] = tbl[i].disp020[0]; cpudatatbl[opcode].disp020[1] = tbl[i].disp020[1]; diff --git a/cputest/cputest_defines.h b/cputest/cputest_defines.h index 9be180a2..cc3a4458 100644 --- a/cputest/cputest_defines.h +++ b/cputest/cputest_defines.h @@ -47,8 +47,10 @@ #define OPCODE_AREA 48 #define BRANCHTARGET_AREA 4 +#define LM_BUFFER 128 // MOVEA.L A0,A0 // not NOP because on 68040 NOP generates T0 trace. #define NOP_OPCODE 0x2048 #define ILLG_OPCODE 0x4afc +#define LM_OPCODE 0x42db diff --git a/cputest/main.c b/cputest/main.c index cfb795aa..56cfe4af 100644 --- a/cputest/main.c +++ b/cputest/main.c @@ -134,7 +134,7 @@ static short quit; static uae_u8 ccr_mask; static uae_u32 addressing_mask = 0x00ffffff; static uae_u32 interrupt_mask; -static short loop_mode, loop_mode_68010, loop_mode_cnt; +static short loop_mode_jit, loop_mode_68010, loop_mode_cnt; static short instructionsize; static short disasm; static short basicexcept; @@ -1306,6 +1306,8 @@ static short is_valid_word(uae_u8 *p) return 1; } +#define MAX_DISM_LINES 15 + static void out_disasm(uae_u8 *mem) { uae_u16 *code; @@ -1321,7 +1323,8 @@ static void out_disasm(uae_u8 *mem) uae_u8 *p = mem; int offset = 0; int lines = 0; - while (lines++ < 15) { + short last = 0; + while (lines++ < MAX_DISM_LINES) { int v = 0; if (!is_valid_word(p)) { sprintf(outbp, "%08x -- INACCESSIBLE --\n", (uae_u32)p); @@ -1348,8 +1351,12 @@ static void out_disasm(uae_u8 *mem) outbp += strlen(outbp); if (!is_valid_word((uae_u8*)(code + offset))) break; - if (v <= 0 || code[offset] == ILLG_OPCODE) + if (v <= 0) + break; + if (last) break; + if (code[offset] == ILLG_OPCODE) + last = 1; while (v > 0) { offset++; p += 2; @@ -2222,9 +2229,9 @@ 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 + // NaN or Infinite: both must match but skip possible last bits if (exp1 == 0x7fff || exp2 == 0x7fff) { - return 0; + goto lastbits; } // Zero: both must match if ((!exp1 && !m1[0] && !m1[1]) || (!exp2 && !m2[0] && !m2[1])) { @@ -2284,6 +2291,7 @@ static short fpucheckextra(struct fpureg *f1, struct fpureg *f2) return 0; } +lastbits: // skip n bits from the end if (fpu_adjust_man >= 0) { short shift = zb1 < zb2 ? zb1 : zb2; @@ -2340,6 +2348,10 @@ static void loop_mode_error(uae_u32 ov, uae_u32 nv) static const char cvzn[] = { "CVZN" }; static void loop_mode_error_CVZN(uae_u32 ov, uae_u32 nv) { + // Swap V<>Z + ov = (ov & 0xff0000ff) | ((ov >> 8) & 0x0000ff00) | ((ov << 8) & 0x00ff0000); + nv = (nv & 0xff0000ff) | ((nv >> 8) & 0x0000ff00) | ((nv << 8) & 0x00ff0000); + for (short i = 0; i < 4; i++) { if ((ov & 0xff) != (nv & 0xff)) { sprintf(outbp, "Loop mode %c:", cvzn[i]); @@ -2354,9 +2366,14 @@ static void loop_mode_error_X(uae_u32 ov, uae_u32 nv) { sprintf(outbp, "Loop mode X:"); outbp += strlen(outbp); + ov >>= 4; + nv >>= 4; loop_mode_error(ov, nv); } +static uae_u16 lmtable1[LM_BUFFER / 2]; +static uae_u16 lmtable2[LM_BUFFER / 2]; + // sregs: registers before execution of test code // tregs: registers used during execution of test code, also modified by test code. // lregs: registers after modifications from data files. Test ok if tregs == lregs. @@ -2369,6 +2386,11 @@ 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 (loop_mode_jit) { + memset(lmtable1, 0xff, sizeof(lmtable1)); + memset(lmtable2, 0xff, sizeof(lmtable2)); + } + // Register modified in test? (start register != test register) for (short i = 0; i < 16; i++) { if (sregs->regs[i] != tregs->regs[i]) { @@ -2503,13 +2525,6 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr, st sprintf(outbp, "%c%d: expected %08x but got %08x\n", mode < CT_AREG ? 'D' : 'A', mode & 7, val, tregs->regs[mode]); } outbp += strlen(outbp); - if (loop_mode && !loop_mode_68010) { - if (mode == CT_AREG + 3) { - loop_mode_error_CVZN(val, tregs->regs[mode]); - } else if (mode == CT_AREG + 4) { - loop_mode_error_X(val, tregs->regs[mode]); - } - } } errflag |= 1 << 0; } @@ -2654,6 +2669,7 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr, st uae_u8 *addr; uae_u32 val = 0, mval = 0, oldval = 0; int size; + short lm = 0; p = get_memory_addr(p, &addr); p = restore_value(p, &oldval, &size); p = restore_value(p, &val, &size); @@ -2672,9 +2688,16 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr, st break; case 1: mval = (addr[0] << 8) | (addr[1]); + if (loop_mode_jit && addr >= test_memory && addr < test_memory + LM_BUFFER) { + lmtable1[(addr - test_memory) / 2] = val; + lmtable2[(addr - test_memory) / 2] = mval; + lm = 1; + } if (mval != val && !ignore_errors && !skipmemwrite) { if (dooutput) { - sprintf(outbp, "Memory word write: address %08x, expected %04x but got %04x\n", (uae_u32)addr, val, mval); + if (!lm || (lm && (val == 0xffff || mval == 0xffff))) { + sprintf(outbp, "Memory word write: address %08x, expected %04x but got %04x\n", (uae_u32)addr, val, mval); + } outbp += strlen(outbp); } errflag |= 1 << 6; @@ -2708,13 +2731,6 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr, st uae_u32 val = lregs->regs[mode]; sprintf(outbp, "%c%d: expected %08x but got %08x\n", mode < CT_AREG ? 'D' : 'A', mode & 7, val, tregs->regs[mode]); outbp += strlen(outbp); - if (loop_mode && !loop_mode_68010) { - if (mode == CT_AREG + 3) { - loop_mode_error_CVZN(val, tregs->regs[mode]); - } else if (mode == CT_AREG + 4) { - loop_mode_error_X(val, tregs->regs[mode]); - } - } } errflag |= 1 << 0; } @@ -2792,6 +2808,38 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr, st errflag_orig |= errflag; } + if (loop_mode_jit) { + short idx = 0, cnt = 0, end = loop_mode_cnt * 2; + for (;;) { + uae_u16 v1, v2; + v1 = lmtable1[idx]; + v2 = lmtable2[idx]; + idx++; + if (idx >= LM_BUFFER / 2) { + break; + } + if (v1 == 0xffff && v2 == 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 (cnt >= end) { + break; + } + } + } + // if excskipccr + bus, address, divide by zero or chk + only CCR mismatch detected: clear error if (excskipccr && errflag == (1 << 7) && (exceptionnum == 2 || exceptionnum == 3 || exceptionnum == 5 || exceptionnum == 6)) { errflag = 0; @@ -3357,7 +3405,7 @@ static int test_mnemo(const char *opcode) interrupttest = (lvl_mask >> 26) & 1; sr_undefined_mask = lvl_mask & 0xffff; safe_memory_mode = (lvl_mask >> 23) & 7; - loop_mode = (lvl_mask >> 28) & 1; + loop_mode_jit = (lvl_mask >> 28) & 1; loop_mode_68010 = (lvl_mask >> 29) & 1; fpu_model = read_u32(headerfile, &headoffset); test_low_memory_start = read_u32(headerfile, &headoffset); @@ -3370,7 +3418,7 @@ static int test_mnemo(const char *opcode) super_stack_memory = read_u32(headerfile, &headoffset); exception_vectors = read_u32(headerfile, &headoffset); v = read_u32(headerfile, &headoffset); - if (loop_mode) { + if (loop_mode_jit || loop_mode_68010) { loop_mode_cnt = v & 0xff; } read_u32(headerfile, &headoffset); diff --git a/cputest/readme.txt b/cputest/readme.txt index 87094a69..f3c81d28 100644 --- a/cputest/readme.txt +++ b/cputest/readme.txt @@ -130,6 +130,10 @@ If mismatch is detected, opcode word(s), instruction disassembly, registers befo Change log: +25.07.2020 + +- JIT loop mode test improved. + 13.07.2020 - Added undefined_ccr option. Ignores undefined flags, currently supports DIVx, CHK and CHK2 (Instructions that don't have simple undefined behavior) diff --git a/cputest_support.cpp b/cputest_support.cpp index 50ebdbe5..714c619d 100644 --- a/cputest_support.cpp +++ b/cputest_support.cpp @@ -90,9 +90,7 @@ void set_cpu_caches(bool flush) { } -void flush_icache(int v) -{ -} +void (*flush_icache)(int); void flush_cpu_caches_040(uae_u16 opcode) {