From: Toni Wilen Date: Sun, 8 Sep 2019 15:09:18 +0000 (+0300) Subject: CPU tester updates. 68060 special cases: MOVEC, HALT, PULSE, LPSTOP fix. RTE 68010... X-Git-Tag: 4300~124 X-Git-Url: https://git.unchartedbackwaters.co.uk/w/?a=commitdiff_plain;h=da0eadd8abef2c6dd380103b620e50845c29be9d;p=francis%2Fwinuae.git CPU tester updates. 68060 special cases: MOVEC, HALT, PULSE, LPSTOP fix. RTE 68010+ support. MOVEC register check added. 68040 undefined flags tested. --- diff --git a/cputest.cpp b/cputest.cpp index acfbdf84..712be3ca 100644 --- a/cputest.cpp +++ b/cputest.cpp @@ -107,9 +107,11 @@ static uae_u32 immabsl_cnt; static uae_u32 addressing_mask; static int opcodecnt; static int cpu_stopped; +static int cpu_halted; static int cpu_lvl = 0; static int test_count; static int testing_active; +static uae_u16 testing_active_opcode; static time_t starttime; static int filecount; static uae_u16 sr_undefined_mask; @@ -134,6 +136,16 @@ static int noaccesshistory = 0; static struct accesshistory ahist[MAX_ACCESSHIST]; static struct accesshistory ahist2[MAX_ACCESSHIST]; +static int is_superstack_use_required(void) +{ + switch (testing_active_opcode) + { + case 0x4e73: // RTE + return 1; + } + return 0; +} + #define OPCODE_AREA 32 static bool valid_address(uaecptr addr, int size, int w) @@ -176,6 +188,18 @@ static bool valid_address(uaecptr addr, int size, int w) test_memory_accessed = w ? -1 : 1; return 1; } + if (addr >= test_memory_end - RESERVED_SUPERSTACK && addr + size < test_memory_end) { + // allow only instructions that have to access super stack, for example RTE + // read-only + if (w) + goto oob; + if (testing_active) { + if (is_superstack_use_required()) { + test_memory_accessed = 1; + return 1; + } + } + } oob: return 0; } @@ -440,9 +464,11 @@ void dfc_nommu_put_long(uaecptr addr, uae_u32 v) put_long_test(addr, v); } -uae_u16 get_wordi_test(uaecptr addr) +uae_u16 get_wordi_test(int o) { - return get_word_test(addr); + uae_u32 v = get_word_test_prefetch(o); + regs.pc += 2; + return v; } uae_u32 memory_get_byte(uaecptr addr) @@ -653,6 +679,11 @@ void REGPARAM2 MakeFromSR(void) MakeFromSR_x(0); } +void cpu_halt(int halt) +{ + cpu_halted = halt; +} + static void exception_check_trace(int nr) { SPCFLAG_TRACE = 0; @@ -688,7 +719,7 @@ void check_t0_trace(void) void cpureset(void) { - test_exception = 1; + cpu_halted = -1; } static void doexcstack(void) @@ -1461,7 +1492,21 @@ static int create_ea(uae_u16 *opcodep, uaecptr pc, int mode, int reg, struct ins if (opcodecnt == 1) { // STOP #xxxx: test all combinations // (also includes RTD) - put_word_test(pc, imm16_cnt++); + if (dp->mnemo == i_LPSTOP) { + uae_u16 lp = 0x01c0; + if (imm16_cnt & (0x40 | 0x80)) { + for (;;) { + lp = rand16(); + if (lp != 0x01c0) + break; + } + } + put_word_test(pc, lp); + put_word_test(pc + 2, imm16_cnt++); + pc += 2; + } else { + put_word_test(pc, imm16_cnt++); + } if (imm16_cnt == 0) *isconstant = 0; else @@ -1632,17 +1677,102 @@ static void handle_specials_extra(uae_u16 opcode, uaecptr pc, struct instr *dp) } } +static uae_u32 generate_stack_return(int cnt) +{ + uae_u32 v = rand32(); + switch (cnt & 3) + { + case 0: + case 3: + v = opcode_memory_start + 128; + break; + case 1: + v &= 0xffff; + if (test_low_memory_start == 0xffffffff) + v |= 0x8000; + if (test_high_memory_start == 0xffffffff) + v &= 0x7fff; + break; + case 2: + v = opcode_memory_start + (uae_s16)v; + break; + } + if (!feature_exception3_instruction) + v &= ~1; + return v; +} + +static int handle_rte(uae_u16 opcode, uaecptr pc, struct instr *dp, int *isconstant, uaecptr addr) +{ + // skip bus error/address error frames because internal fields can't be simply randomized + int offset = 2; + int frame, v; + + imm_special++; + for (;;) { + frame = (imm_special >> 2) & 15; + // 68010 bus/address error + if (cpu_lvl == 1 && (frame == 8)) { + imm_special += 4; + continue; + } + if ((cpu_lvl == 2 || cpu_lvl == 3) && (frame == 9 || frame == 10 || frame == 11)) { + imm_special += 4; + continue; + } + // 68040 FP post-instruction, FP unimplemented, Address error + if (cpu_lvl == 4 && (frame == 3 || frame == 4 || frame == 7)) { + imm_special += 4; + continue; + } + // 68060 access fault/FP disabled, FP post-instruction + if (cpu_lvl == 5 && (frame == 3 || frame == 4)) { + imm_special += 4; + continue; + } + // throwaway frame + if (frame == 1) { + imm_special += 4; + continue; + } + break; + } + v = imm_special >> 6; + uae_u16 sr = v & 31; + sr |= (v >> 5) << 12; + put_word_test(addr, sr); + addr += 2 + 4; + // frame + vector offset + put_word_test(addr, (frame << 12) | (rand16() & 0x0fff)); + addr += 2; +#if 0 + if (frame == 1) { + int imm_special_tmp = imm_special; + imm_special &= ~(15 << 2); + if (rand8() & 1) + imm_special |= 2 << 2; + handle_rte(opcode, addr, dp, isconstant, addr); + imm_special = imm_special_tmp; + v = generate_stack_return(imm_special); + put_long_test(addr + 2, v); + offset += 8 + 2; +#endif + if (frame == 2) { + put_long_test(addr, rand32()); + } + return offset; +} + static int handle_specials_stack(uae_u16 opcode, uaecptr pc, struct instr *dp, int *isconstant) { int offset = 0; if (dp->mnemo == i_RTE || dp->mnemo == i_RTD || dp->mnemo == i_RTS || dp->mnemo == i_RTR || dp->mnemo == i_UNLK) { uae_u32 v; uaecptr addr = regs.regs[8 + 7]; - imm_special++; // RTE, RTD, RTS and RTR if (dp->mnemo == i_RTR) { // RTR - v = imm_special; + v = imm_special++; uae_u16 ccr = v & 31; ccr |= rand16() & ~31; put_word_test(addr, ccr); @@ -1652,6 +1782,7 @@ static int handle_specials_stack(uae_u16 opcode, uaecptr pc, struct instr *dp, i } else if (dp->mnemo == i_RTE) { // RTE if (currprefs.cpu_model == 68000) { + imm_special++; v = imm_special >> 2; uae_u16 sr = v & 31; sr |= (v >> 5) << 12; @@ -1659,27 +1790,15 @@ static int handle_specials_stack(uae_u16 opcode, uaecptr pc, struct instr *dp, i addr += 2; offset += 2; } else { - // TODO 68010+ RTE + offset += handle_rte(opcode, pc, dp, isconstant, addr); + addr += 2; } *isconstant = imm_special >= (1 << (4 + 5)) * 4 ? 0 : -1; } else if (dp->mnemo == i_RTS) { // RTS *isconstant = imm_special >= 256 ? 0 : -1; } - v = rand32(); - switch (imm_special & 3) - { - case 0: - case 3: - v = opcode_memory_start + 128; - break; - case 1: - v &= 0xffff; - break; - case 2: - v = opcode_memory_start + (uae_s16)v; - break; - } + v = generate_stack_return(imm_special); put_long_test(addr, v); if (out_of_test_space) { wprintf(_T("handle_specials out of bounds access!?")); @@ -1693,8 +1812,8 @@ static void execute_ins(uae_u16 opc, uaecptr endpc, uaecptr targetpc, struct ins { uae_u16 opw1 = (opcode_memory[2] << 8) | (opcode_memory[3] << 0); uae_u16 opw2 = (opcode_memory[4] << 8) | (opcode_memory[5] << 0); - if (opc == 0x4c42 - && opw1 == 0xcf19 + if (opc == 0x89c2 + //&& opw1 == 0xcf19 //&& opw2 == 0x504e ) printf(""); @@ -1713,6 +1832,7 @@ static void execute_ins(uae_u16 opc, uaecptr endpc, uaecptr targetpc, struct ins high_memory_accessed = 0; test_memory_accessed = 0; testing_active = 1; + testing_active_opcode = opc; int cnt = feature_loop_mode * 2; @@ -1727,9 +1847,11 @@ static void execute_ins(uae_u16 opc, uaecptr endpc, uaecptr targetpc, struct ins (*cpufunctbl[opc])(opc); - // supervisor mode and A7 was modified: skip this test round. + // Supervisor mode and A7 was modified: skip this test round. if (s && regs.regs[15] != a7) { - test_exception = -1; + // but not if RTE + if (!is_superstack_use_required()) + test_exception = -1; } if (!test_exception) { @@ -1831,7 +1953,6 @@ static int isunsupported(struct instr *dp) switch (dp->mnemo) { case i_MOVE2C: - case i_MOVEC2: case i_FSAVE: case i_FRESTORE: case i_PFLUSH: @@ -1846,14 +1967,21 @@ static int isunsupported(struct instr *dp) case i_CINVA: case i_CINVL: case i_CINVP: + case i_PLPAR: + case i_PLPAW: return 1; - case i_RTE: - if (cpu_lvl > 0) - return 1; - break; } return 0; +} +static int noregistercheck(struct instr *dp) +{ + switch (dp->mnemo) + { + case i_MOVEC2: + return 1; + } + return 0; } static uae_u8 last_exception[256]; @@ -1922,12 +2050,14 @@ static uae_u8 *save_exception(uae_u8 *p, struct instr *dp) return p; } -static uae_u16 get_ccr_ignore(struct instr *dp) +static uae_u16 get_ccr_ignore(struct instr *dp, uae_u16 extra) { uae_u16 ccrignoremask = 0; - if ((cpu_lvl == 2 || cpu_lvl == 3) && test_exception == 5 && (dp->mnemo == i_DIVS || dp->mnemo == i_DIVL)) { - // 68020/030 DIVS.W/.L + Divide by Zero: V state is not stable. - ccrignoremask |= 2; // mask CCR=V + if ((cpu_lvl == 2 || cpu_lvl == 3) && test_exception == 5) { + if ((dp->mnemo == i_DIVS) || (dp->mnemo == i_DIVL && (extra & 0x0800) && !(extra & 0x0400))) { + // 68020/030 DIVS.W/.L + Divide by Zero: V state is not stable. + ccrignoremask |= 2; // mask CCR=V + } } return ccrignoremask; } @@ -2010,6 +2140,8 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi } } + xorshiftstate ^= 0x12; + int pathlen = _tcslen(path); _stprintf(dir, _T("%s%s"), path, mns); if (fpuopcode < 0) { @@ -2187,7 +2319,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi if (opc == 0x0156) printf(""); - if (subtest_count == 1537) + if (subtest_count == 416) printf(""); @@ -2416,6 +2548,7 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi out_of_test_space = 0; test_exception = 0; cpu_stopped = 0; + cpu_halted = 0; ahcnt = 0; memset(®s, 0, sizeof(regs)); @@ -2440,6 +2573,8 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi regs.sr = ccr | sr_mask; regs.usp = regs.regs[8 + 7]; regs.isp = test_memory_end - 0x80; + // copy user stack to super stack, for RTE etc support + memcpy(regs.isp - test_memory_start + test_memory, regs.usp - test_memory_start + test_memory, 0x20); regs.msp = test_memory_end; // data size optimization, only store data @@ -2477,6 +2612,9 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi cnt_stopped++; // CPU stopped, skip test skipped = 1; + } else if (cpu_halted) { + // CPU halted or reset, skip test + skipped = 1; } else if (out_of_test_space) { exception_array[0]++; // instruction accessed memory out of test address space bounds @@ -2490,11 +2628,8 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi exception_array[test_exception]++; if (test_exception == 8 && !(sr_mask & 0x2000)) { // Privilege violation exception? Switch to super mode in next round. - // Except if reset.. - if (lookup->mnemo != i_RESET) { - sr_mask_request |= 0x2000; - sr_allowed_mask |= 0x2000; - } + sr_mask_request |= 0x2000; + sr_allowed_mask |= 0x2000; } if (test_exception == 3) { if (!feature_exception3_data && !(test_exception_3_fc & 2)) { @@ -2520,23 +2655,30 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi // validate branch instructions if (isbranchinst(dp)) { if ((regs.pc != srcaddr && regs.pc != pc - 2) || pcaddr[0] != 0x4a && pcaddr[1] != 0xfc) { - printf("Branch instruction target fault\n"); - exit(0); + wprintf(_T("Branch instruction target fault\n")); + abort(); } } } MakeSR(); if (!skipped) { + bool storeregs = true; + if (noregistercheck(dp)) { + *dst++ = CT_SKIP_REGS; + storeregs = false; + } // save modified registers for (int i = 0; i < MAX_REGISTERS; i++) { uae_u32 s = last_registers[i]; uae_u32 d = regs.regs[i]; if (s != d) { - dst = store_reg(dst, CT_DREG + i, s, d, -1); + if (storeregs) { + dst = store_reg(dst, CT_DREG + i, s, d, -1); + } last_registers[i] = d; } } - uae_u32 ccrignoremask = get_ccr_ignore(dp) << 16; + uae_u32 ccrignoremask = get_ccr_ignore(dp, ((pcaddr[2] << 8) | pcaddr[3])) << 16; if ((regs.sr | ccrignoremask) != last_sr) { dst = store_reg(dst, CT_SR, last_sr, regs.sr | ccrignoremask, -1); last_sr = regs.sr | ccrignoremask; @@ -2740,6 +2882,9 @@ static void test_mnemo_text(const TCHAR *path, const TCHAR *mode) _tcscpy(modetxt, _T("MULL")); extra_and = 0x0800; ovrname = _T("MULU"); + } else if (!_tcsicmp(modetxt, _T("MOVEC"))) { + _tcscpy(modetxt, _T("MOVEC2")); + ovrname = _T("MOVEC"); } for (int j = 0; lookuptab[j].name; j++) { diff --git a/cputest/amiga.S b/cputest/amiga.S index dcd6a41b..c7b4dd94 100644 --- a/cputest/amiga.S +++ b/cputest/amiga.S @@ -68,7 +68,7 @@ _get_cpu_model: movem.l a5/a6,-(sp) move.l a0,a6 lea scpucheck(pc),a5 - jsr -0x1e(a6) + jsr -0x1e(a6) | Supervisor movem.l (sp)+,a5/a6 bra.s .cpudone2 .cpucheck2: @@ -81,7 +81,7 @@ _get_cpu_model: bne.s .cpudone dbf d0,.cpucheck .cpudone: - addq.l #1,d0 + addq.w #1,d0 .cpudone2: rts diff --git a/cputest/cputest_defines.h b/cputest/cputest_defines.h index 169a496d..9f332d90 100644 --- a/cputest/cputest_defines.h +++ b/cputest/cputest_defines.h @@ -33,4 +33,5 @@ #define CT_END_FINISH 0xff #define CT_END_INIT (0x80 | 0x40) #define CT_END_SKIP (0x80 | 0x40 | 0x01) +#define CT_SKIP_REGS (0x80 | 0x40 | 0x02) #define CT_EMPTY CT_END_INIT diff --git a/cputest/cputestgen.ini b/cputest/cputestgen.ini index 21be525a..36cdbaa5 100644 --- a/cputest/cputestgen.ini +++ b/cputest/cputestgen.ini @@ -1,12 +1,12 @@ [cputest] -; CPU model (68000, 68020, 68040 or 68060). +; CPU model (68000, 68020, 68030, 68040 or 68060). ; Always select 68020 when testing FPU instructions, even if test hardware CPU is 68040 or 68060. -cpu=68020 +cpu=68000 ; CPU address space. 24-bit or 32-bit. If 24-bit, tester will assume upper 8-bits of addresses gets ignored. -cpu_address_space=32 +cpu_address_space=24 ; FPU model (empty string or 0, 68881, 68882, 68040, 68060) ; Enable only when testing FPU. Enabled FPU mode will slow down native test execution even when not testing FPU instructions. @@ -23,15 +23,17 @@ 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. -;test_high_memory_start=0x00ff8000 -;test_high_memory_end=0x01000000 +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=0x780000 -test_memory_start=0x68800000 +test_memory_start=0x780000 +;test_memory_start=0x68800000 +;test_memory_start=0x07800000 +;test_memory_start=0x08800000 test_memory_size=0x080000 ; number of test rounds (registers are re-randomized after each round) @@ -45,13 +47,13 @@ feature_exception3_data=0 ; test branches to odd addresses ; same options as above -feature_exception3_instruction=1 +feature_exception3_instruction=0 ; SR extra mask. ; 0x8000 = T1 -; 0x4000 = T0 (68020) +; 0x4000 = T0 (68020-68040) ; 0x2000 = S -; 0x1000 = M (68020) +; 0x1000 = M (68020-68060) ; Other bits are ignored. ; For example 0xa000 adds 3 extra test rounds: S=1/T1=0, S=0/T1=1 and S=1/T1=1 ; Note: instructions that generate privilege violation exception will automatically add extra S=1 round. diff --git a/cputest/main.c b/cputest/main.c index 16c3688d..05e039ff 100644 --- a/cputest/main.c +++ b/cputest/main.c @@ -684,7 +684,7 @@ static uae_u8 *restore_data(uae_u8 *p) return p; } -static uae_u16 test_sr, test_ccrignoremask; +static uae_u16 test_ccrignoremask; static uae_u32 test_fpsr, test_fpcr; static void addinfo(void) @@ -764,18 +764,21 @@ static void out_regs(struct registers *r, int before) } strcat(outbp, "\n"); outbp += strlen(outbp); - sprintf(outbp, "SR:%c%04x PC: %08lx ISP: %08lx MSP: %08lx\n", test_regs.sr != test_sr ? '*' : ' ', before ? test_sr : r->sr, r->pc, r->ssp, r->msp); + sprintf(outbp, "SR:%c%04x PC: %08lx ISP: %08lx MSP: %08lx\n", + test_regs.sr != last_registers.sr ? '*' : ' ', before ? regs.sr : test_regs.sr, + r->pc, r->ssp, r->msp); outbp += strlen(outbp); if (before >= 0) { - uae_u16 s = before ? test_sr : r->sr; - uae_u16 s1 = test_regs.sr; - uae_u16 s2 = test_sr; - uae_u16 s3 = before ? s1 : last_registers.sr; + uae_u16 s = before ? regs.sr : test_regs.sr; // current value + uae_u16 s1 = regs.sr; // original value + uae_u16 s2 = test_regs.sr; // test result value + uae_u16 s3 = last_registers.sr; // expected result value for (int i = 0; srbits[i].name; i++) { if (i > 0) *outbp++ = ' '; uae_u16 mask = 1 << srbits[i].bit; - sprintf(outbp, "%s%c%d", srbits[i].name, (s3 & mask) != (s1 & mask) ? '!' : ((s1 & mask) != (s2 & mask) ? '*' : '='), (s & mask) != 0); + sprintf(outbp, "%s%c%d", srbits[i].name, + (s2 & mask) != (s3 & mask) ? '!' : ((s1 & mask) != (s2 & mask) ? '*' : '='), (s & mask) != 0); outbp += strlen(outbp); } } @@ -827,7 +830,7 @@ static void hexdump(uae_u8 *p, int len) static uae_u8 last_exception[256]; static int last_exception_len; -static uae_u8 *validate_exception(struct registers *regs, uae_u8 *p, int excnum, int sameexc) +static uae_u8 *validate_exception(struct registers *regs, uae_u8 *p, int excnum, int sameexc, int *experr) { int exclen = 0; uae_u8 *exc; @@ -931,10 +934,15 @@ static uae_u8 *validate_exception(struct registers *regs, uae_u8 *p, int excnum, outbp += strlen(outbp); hexdump(sp, exclen); errors = 1; + *experr = 1; } return p; } +// regs: registers before execution of test code +// test_reg: registers used during execution of test code, also modified by test code. +// last_registers: registers after modifications from data files. Test ok if test_reg == last_registers. + static uae_u8 *validate_test(uae_u8 *p, int ignore_errors, int ignore_sr) { uae_u8 regs_changed[16] = { 0 }; @@ -974,6 +982,7 @@ static uae_u8 *validate_test(uae_u8 *p, int ignore_errors, int ignore_sr) if (*p == CT_END_SKIP) return p + 1; + int experr = 0; for (;;) { uae_u8 v = *p; if (v & CT_END) { @@ -994,7 +1003,7 @@ static uae_u8 *validate_test(uae_u8 *p, int ignore_errors, int ignore_sr) } if (ignore_errors) { if (exc) { - p = validate_exception(&test_regs, p, exc, exc == cpuexc); + p = validate_exception(&test_regs, p, exc, exc == cpuexc, &experr); } break; } @@ -1008,7 +1017,7 @@ static uae_u8 *validate_test(uae_u8 *p, int ignore_errors, int ignore_sr) break; } if (exc) { - p = validate_exception(&test_regs, p, exc, exc == cpuexc); + p = validate_exception(&test_regs, p, exc, exc == cpuexc, &experr); } if (exc != cpuexc) { addinfo(); @@ -1018,6 +1027,7 @@ static uae_u8 *validate_test(uae_u8 *p, int ignore_errors, int ignore_sr) } else { sprintf(outbp, "Exception ID: expected %d but got %d\n", exc, cpuexc); } + experr = 1; } outbp += strlen(outbp); errors++; @@ -1065,7 +1075,7 @@ static uae_u8 *validate_test(uae_u8 *p, int ignore_errors, int ignore_sr) if ((val & (sr_undefined_mask & test_ccrignoremask)) != (test_regs.sr & (sr_undefined_mask & test_ccrignoremask)) && !ignore_errors && !ignore_sr) { addinfo(); if (dooutput) { - sprintf(outbp, "SR: expected %04x -> %04x but got %04x (%04x)\n", test_sr, val & 0xffff, test_regs.sr & 0xffff, test_ccrignoremask); + sprintf(outbp, "SR: expected %04x -> %04x but got %04x (%04x)\n", regs.sr & 0xffff, val & 0xffff, test_regs.sr & 0xffff, test_ccrignoremask); outbp += strlen(outbp); } errors++; @@ -1245,8 +1255,10 @@ static uae_u8 *validate_test(uae_u8 *p, int ignore_errors, int ignore_sr) } out_regs(&test_regs, 0); if (exc > 1) { - sprintf(outbp, "OK: Generated exception %d\n", exc); - outbp += strlen(outbp); + if (!experr) { + sprintf(outbp, "OK: Generated exception %d\n", exc); + outbp += strlen(outbp); + } if (exc == 3 && cpu_lvl == 0) { sprintf(outbp, "RW=%d IN=%d FC=%d\n", ((test_regs.exc >> (16 + 4)) & 1), @@ -1326,10 +1338,11 @@ static void process_test(uae_u8 *p) regs.pc = opcode_memory_addr; regs.fpiar = opcode_memory_addr; + memcpy((void*)regs.ssp, (void*)regs.regs[15], 0x20); xmemcpy(&test_regs, ®s, sizeof(struct registers)); test_regs.sr = ccr | sr_mask; - test_sr = test_regs.sr; + uae_u32 test_sr = test_regs.sr; if (fpumode) { test_regs.fpsr = (ccr & 15) << 24; test_regs.fpcr = (ccr >> 4) << 4; @@ -1374,6 +1387,13 @@ static void process_test(uae_u8 *p) last_registers.pc = last_pc; last_registers.fpiar = last_fpiar; + if ((*p) == CT_SKIP_REGS) { + p++; + for (int i = 0; i < 16; i++) { + test_regs.regs[i] = regs.regs[i]; + } + } + p = validate_test(p, ignore_errors, ignore_sr); last_pc = last_registers.pc; @@ -1517,7 +1537,7 @@ static int test_mnemo(const char *path, const char *opcode) exit(0); } - printf("CPUlvl=%d, Mask=%08lx\n", cpu_lvl, addressing_mask); + printf("CPUlvl=%d, Mask=%08lx Code=%08lx\n", cpu_lvl, addressing_mask, opcode_memory); printf("%s:\n", inst_name); testcnt = 0; diff --git a/cputest/readme.txt b/cputest/readme.txt new file mode 100644 index 00000000..778f0047 --- /dev/null +++ b/cputest/readme.txt @@ -0,0 +1,100 @@ + +UAE CPU Tester + +I finally wrote utility (this was my "Summer 2019" project) that can be used to verify operation of for example software emulated or FPGA 680x0 CPUs. +It is based on UAE CPU core (gencpu generated special test core). All the CPU logic comes from UAE CPU core. + +Verifies: + +- All CPU registers (D0-D7/A0-A7, PC and SR/CCR) +- All FPU registers (FP0-FP7, FPIAR, FPCR, FPSR) +- Generated exception and stack frame contents (if any) +- Memory writes, including stack modifications (if any) +- Loop mode for JIT testing. (generates , dbf dn,loop) +- Supports 68000, 68020, 68030 (only difference between 020 and 030 seems to be data cache and MMU), 68040 and 68060. (I don't currently have real 68010) + +Tests executed for each tested instruction: + +- Every CCR combination (32 tests) +- Every FPU condition combination (4 bits) + 2 precision bits + 2 rounding bits (256 tests) +- Every addressing mode, including optionally 68020+ addressing modes. +- If instruction generated privilege violation exception, extra test round is run in supervisor mode (Total 64 tests). +- Optionally can do any combination of T0, T1, S and M -bit SR register extra test rounds. +- Every opcode value is tested. Total number of tests per opcode depends on available addressing modes etc. It can be hundreds of thousands or even millions.. + +Test generation details: + +Instruction's effective address is randomized. It is accepted if it points to any of 3 test memory regions. If it points outside of test memory, it will be re-randomized few times. Test will be skipped if current EA makes it impossible to point to any of 3 test regions. +If 68000/68010 and address error testing is enabled: 2 extra test rounds are generated, one with even and another with odd EAs to test and verify address errors. + +Notes and limitations: + +- Test generator is very brute force based, it should be more intelligent.. +- Address error testing is optional, if disabled, generated tests never cause address errors. +- RTE test only tests stack frame types 0 and 2 (if 68020+) +- All tests that would halt or reset the CPU are skipped (RESET in supervisor mode, STOP parameter that would stop the CPU etc) +- Single instruction test set will take long time to run on real 68000. Few minutes to much longer... +- Undefined flags (for example DIV and CHK) are also verified. It probably would be good idea to optionally filter them out. +- Instruction cycle order or timing is ignored. It is not possible without extra hardware. +- 68000 bus errors are not tested but there are some plans for future version with custom hardware. (Hatari also uses UAE CPU core) +- FPU testing is not yet fully implemented. +- Sometimes reported old and new condition code state does not match error report.. + +Tester compatibility (integer instructions only): + +68000: Complete. +68010: Not supported yet (Don't have real 68010, at least not yet). +68020: Almost complete (DIVS.W/DIVS.L V-flag weirdness). +68030: Same as 68020. +68040: Almost complete (Weird unaligned MOVE16 behavior which may be board specific). +68060: Same as 68040. + +More CPU details in WinUAE changelog. + +Not implemented or only partially implemented: + +68010+: + +- MOVEC: Only MOVEC to An/Dn is tested and read value is ignored. Basically only verifies if correct and only correct CPU model specific control registers exist. +- RTE: long frames with undefined fields are skipped. Basic frame types 0 and 2 are verified, also unsupported frame types are tested, error is reported if CPU does not generate frame exception. +- 68020+ undefined addressing mode bit combinations are not tested. + +All models: + +- Interrupts (stack frames and STOP) +- MMU instructions (Not going to happen) +- 68020+ cache related instructions. +- FPU FSAVE/FRESTORE, FPU support also isn't fully implemented yet. + +Build instructions: + +- buildm68k first (already built if UAE core was previously compiled) +- gencpu with CPU_TEST=1 define. This creates cpuemu_x_test.cpp files (x=90-94), cpustbl_test.cpp and cputbl_test.h +- build cputestgen project. +- build native Amiga project (cputest directory). Assembly files probably only compiles with Bebbo's GCC. + + +Test generator quick instructions: + +Update cputestgen.ini to match your CPU model, memory settings etc... + +"Low memory" = memory accessible using absolute word addressing mode, positive value (0x0000 to 0x7fff). Can be larger. +"High memory" = memory accessible using absolute word addressing mode, negative value (0xFFF8000 to 0xFFFFFFFF) + +If high memory is ROM space (like on 24-bit address space Amigas), memory region is used for read only tests, use "high_rom=" to select ROM image. Last 32k of image is loaded. + +Use "test_low_memory_start"/"test_high_memory_start" and "test_low_memory_end"/"test_high_memory_end" to restrict range of memory region used for tests, for example if part of region is normally inaccessible. + +"test_memory_start"/"test_memory_size" is the main test memory, tested instruction and stack is located here. Must be at least 128k but larger the size, the easier it is for the generator to find effective addresses that hit test memory. This memory space must be free on target m68k hardware. + +All 3 memory regions (if RAM) are filled with pseudo-random pattern and saved as "lmem.dat", "hmem.dat" and "tmem.dat" + +Usage of Amiga m68k native test program: + +Copy all three dat files, test executable compiled for target platform (currently only Amiga is supported) and data file directories to target system. + +cputest all = run all tests, in alphabetical order. Stops when mismatch is detected. +cputest tst.b = run tst.b tests only +cputest all tst.b = run tst.b, then tst.w and so on in alphabetical order until end or mismatch is detected. + +If mismatch is detected, opcode word(s), instruction disassembly, registers before and after and reason message is shown on screen. If difference is in exception stack frame, both expected and returned stack frame is shown in hexadecimal. diff --git a/disasm.cpp b/disasm.cpp index 318ca197..ecf6810c 100644 --- a/disasm.cpp +++ b/disasm.cpp @@ -1824,6 +1824,15 @@ void m68k_disasm_2 (TCHAR *buf, int bufsize, uaecptr pc, uaecptr *nextpc, int cn extra = get_word_debug(pc); _stprintf(instrname + _tcslen(instrname), _T(",#$%04x"), extra); pc += 2; + } else if (lookup->mnemo == i_LPSTOP) { + if (extra == 0x01c0) { + uae_u16 extra2 = get_word_debug(pc + 2); + _stprintf(instrname, _T("LPSTOP #$%04x"), extra2); + pc += 4; + } else { + _stprintf(instrname, _T("ILLG #$%04x"), extra); + pc += 2; + } } else if (lookup->mnemo == i_FDBcc) { pc = ShowEA(NULL, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &seaddr2, safemode); pc += 2; diff --git a/gencpu.cpp b/gencpu.cpp index d1770636..74576d68 100644 --- a/gencpu.cpp +++ b/gencpu.cpp @@ -4201,12 +4201,12 @@ static void gen_opcode (unsigned int opcode) // if new SR S-bit is not set: // 68000 (68010?): Update SR, increase PC and then cause privilege violation exception (handled in newcpu) // 68000 (68010?): Traced STOP runs 4 cycles faster. - // 68020 68030: STOP works normally - // 68040 68060: Immediate privilege violation exception + // 68020 68030 68040: STOP works normally + // 68060: Immediate privilege violation exception if ((cpu_level == 0 || cpu_level == 1) && using_ce) { printf("\t%s(regs.t1 ? 4 : 8);\n", do_cycles); } - if (cpu_level >= 4) { + if (cpu_level >= 5) { printf("\tif (!(sr & 0x2000)) {\n"); incpc("%d", m68k_pc_offset); printf("\t\tException(8); goto %s;\n", endlabelstr); @@ -4221,17 +4221,27 @@ static void gen_opcode (unsigned int opcode) next_cpu_level = cpu_level - 1; break; case i_LPSTOP: /* 68060 */ - printf ("\tuae_u16 sw = %s (2);\n", srcwi); - printf ("\tif (sw != (0x100|0x80|0x40)) { Exception (4); goto %s; }\n", endlabelstr); + printf ("\tuae_u16 sw = %s(2);\n", srcwi); + printf ("\tif (sw != 0x01c0) { Exception (11); goto %s; }\n", endlabelstr); printf("\tif (!(regs.sr & 0x2000)) {\n"); printf("\t\tException(8); goto %s;\n", endlabelstr); printf("\t}\n"); - printf("\tregs.sr = %s (4);\n", srcwi); + printf("\tuae_u16 newsr = %s(4);\n", srcwi); + printf("\tif (!(newsr & 0x2000)) {\n"); + printf("\t\tException(8); goto %s;\n", endlabelstr); + printf("\t}\n"); + printf("\tregs.sr = newsr;\n"); makefromsr(); printf ("\tm68k_setstopped();\n"); m68k_pc_offset += 4; sync_m68k_pc (); fill_prefetch_full_ntx(); + need_endlabel = 1; + break; + case i_HALT: /* 68060 debug */ + printf("\tcpu_halt(CPU_HALT_68060_HALT);\n"); + break; + case i_PULSE: /* 68060 debug */ break; case i_RTE: addop_ce020 (curi, 0); @@ -4267,9 +4277,9 @@ static void gen_opcode (unsigned int opcode) printf ("\t\tint frame = format >> 12;\n"); printf ("\t\tint offset = 8;\n"); printf ("\t\tnewsr = sr; newpc = pc;\n"); - printf ("\t\tif (frame == 0x0) { m68k_areg (regs, 7) += offset; break; }\n"); - printf ("\t\telse if (frame == 0x8) { m68k_areg (regs, 7) += offset + 50; break; }\n"); - printf ("\t\telse { Exception_cpu(14); goto %s; }\n", endlabelstr); + printf ("\t\tif (frame == 0x0) {\n\t\t\tm68k_areg (regs, 7) += offset; break; }\n"); + printf ("\t\telse if (frame == 0x8) {\n\t\t\tm68k_areg (regs, 7) += offset + 50; break; }\n"); + printf ("\t\telse {\n\t\t\tException_cpu(14); goto %s; }\n", endlabelstr); printf ("\t\tregs.sr = newsr; MakeFromSR ();\n}\n"); pop_braces (old_brace_level); printf ("\tregs.sr = newsr;\n"); @@ -4300,49 +4310,49 @@ static void gen_opcode (unsigned int opcode) printf ("\t\tint offset = 8;\n"); printf ("\t\tnewsr = sr; newpc = pc;\n"); addcycles_ce020 (6); - printf ("\t\tif (frame == 0x0) { m68k_areg (regs, 7) += offset; break; }\n"); + printf ("\t\tif (frame == 0x0) {\n\t\t\tm68k_areg (regs, 7) += offset; break; }\n"); if (cpu_level >= 2) { // 68020+ - printf ("\t\telse if (frame == 0x1) { m68k_areg (regs, 7) += offset; }\n"); - printf ("\t\telse if (frame == 0x2) { m68k_areg (regs, 7) += offset + 4; break; }\n"); + printf ("\t\telse if (frame == 0x1) {\n\t\t\tm68k_areg (regs, 7) += offset; }\n"); + printf ("\t\telse if (frame == 0x2) {\n\t\t\tm68k_areg (regs, 7) += offset + 4; break; }\n"); } if (cpu_level >= 4) { // 68040+ - printf ("\t\telse if (frame == 0x3) { m68k_areg (regs, 7) += offset + 4; break; }\n"); + printf ("\t\telse if (frame == 0x3) {\n\t\t\tm68k_areg (regs, 7) += offset + 4; break; }\n"); } if (using_mmu == 68060) { - printf ("\t\telse if (frame == 0x4) { m68k_do_rte_mmu060 (a); m68k_areg (regs, 7) += offset + 8; break; }\n"); + printf ("\t\telse if (frame == 0x4) {\n\t\t\tm68k_do_rte_mmu060 (a); m68k_areg (regs, 7) += offset + 8; break; }\n"); } else if (cpu_level >= 4) { // 68040+ - printf ("\t\telse if (frame == 0x4) { m68k_areg (regs, 7) += offset + 8; break; }\n"); + printf ("\t\telse if (frame == 0x4) {\n\t\t\tm68k_areg (regs, 7) += offset + 8; break; }\n"); } if (cpu_level == 1) { // 68010 only - printf("\t\telse if (frame == 0x8) { m68k_areg (regs, 7) += offset + 50; break; }\n"); + printf("\t\telse if (frame == 0x8) {\n\t\t\tm68k_areg (regs, 7) += offset + 50; break; }\n"); } if (using_mmu == 68040) { - printf ("\t\telse if (frame == 0x7) { m68k_do_rte_mmu040 (a); m68k_areg (regs, 7) += offset + 52; break; }\n"); - } else if (cpu_level >= 4) { - // 68040+ - printf ("\t\telse if (frame == 0x7) { m68k_areg (regs, 7) += offset + 52; break; }\n"); + printf ("\t\telse if (frame == 0x7) {\n\t\t\tm68k_do_rte_mmu040 (a); m68k_areg (regs, 7) += offset + 52; break; }\n"); + } else if (cpu_level == 4) { + // 68040 only + printf ("\t\telse if (frame == 0x7) {\n\t\t\tm68k_areg (regs, 7) += offset + 52; break; }\n"); } if (cpu_level == 2 || cpu_level == 3) { // 68020/68030 only - printf ("\t\telse if (frame == 0x9) { m68k_areg (regs, 7) += offset + 12; break; }\n"); + printf ("\t\telse if (frame == 0x9) {\n\t\t\tm68k_areg (regs, 7) += offset + 12; break; }\n"); if (using_mmu == 68030) { if (using_prefetch_020) { - printf ("\t\telse if (frame == 0xa) { m68k_do_rte_mmu030c (a); goto %s; }\n", endlabelstr); - printf ("\t\telse if (frame == 0xb) { m68k_do_rte_mmu030c (a); goto %s; }\n", endlabelstr); + printf ("\t\telse if (frame == 0xa) {\n\t\t\tm68k_do_rte_mmu030c (a); goto %s; }\n", endlabelstr); + printf ("\t\telse if (frame == 0xb) {\n\t\t\tm68k_do_rte_mmu030c (a); goto %s; }\n", endlabelstr); } else { - printf ("\t\telse if (frame == 0xa) { m68k_do_rte_mmu030 (a); goto %s; }\n", endlabelstr); - printf ("\t\telse if (frame == 0xb) { m68k_do_rte_mmu030 (a); goto %s; }\n", endlabelstr); + printf ("\t\telse if (frame == 0xa) {\n\t\t\tm68k_do_rte_mmu030 (a); goto %s; }\n", endlabelstr); + printf ("\t\telse if (frame == 0xb) {\n\t\t\tm68k_do_rte_mmu030 (a); goto %s; }\n", endlabelstr); } } else { - printf ("\t\telse if (frame == 0xa) { m68k_areg (regs, 7) += offset + 24; break; }\n"); - printf ("\t\telse if (frame == 0xb) { m68k_areg (regs, 7) += offset + 84; break; }\n"); + printf ("\t\telse if (frame == 0xa) {\n\t\t\tm68k_areg (regs, 7) += offset + 24; break; }\n"); + printf ("\t\telse if (frame == 0xb) {\n\t\t\tm68k_areg (regs, 7) += offset + 84; break; }\n"); } } - printf ("\t\telse { Exception_cpu(14); goto %s; }\n", endlabelstr); + printf ("\t\telse {\n\t\t\tException_cpu(14); goto %s; }\n", endlabelstr); printf ("\t\tregs.sr = newsr;\n"); makefromsr_t0(); printf ("}\n"); @@ -4875,7 +4885,6 @@ bccl_not68020: printf("\t\tException_cpu(5);\n"); printf("\t\tgoto %s;\n", endlabelstr); printf("\t}\n"); - printf("\tsetdivuflags(false, (uae_u32)dst, (uae_u16)src);\n"); printf("\tuae_u32 newv = (uae_u32)dst / (uae_u32)(uae_u16)src;\n"); printf("\tuae_u32 rem = (uae_u32)dst %% (uae_u32)(uae_u16)src;\n"); if (using_ce) { @@ -4886,7 +4895,7 @@ bccl_not68020: addcycles000_nonces("\t\t", "(getDivu68kCycles((uae_u32)dst, (uae_u16)src)) - 4"); fill_prefetch_next(); printf("\t\tif (newv > 0xffff) {\n"); - printf("\t\t\tsetdivuflags(true, (uae_u32)dst, (uae_u16)src);\n"); + printf("\t\t\tsetdivuflags((uae_u32)dst, (uae_u16)src);\n"); printf("\t\t} else {\n"); printf("\t\t"); genflags (flag_logical, sz_word, "newv", "", ""); @@ -4912,7 +4921,6 @@ bccl_not68020: printf("\t\tException_cpu(5);\n"); printf("\t\tgoto %s;\n", endlabelstr); printf("\t}\n"); - printf("\tsetdivsflags(false, (uae_s32)dst, (uae_s16)src);\n"); if (using_ce) { start_brace(); printf("\t\tint cycles = (getDivs68kCycles((uae_s32)dst, (uae_s16)src)) - 4;\n"); @@ -4921,12 +4929,12 @@ bccl_not68020: addcycles000_nonces("\t\t", "(getDivs68kCycles((uae_s32)dst, (uae_s16)src)) - 4"); fill_prefetch_next (); printf("\tif (dst == 0x80000000 && src == -1) {\n"); - printf("\t\tsetdivsflags(true, (uae_s32)dst, (uae_s16)src);\n"); + printf("\t\tsetdivsflags((uae_s32)dst, (uae_s16)src);\n"); printf("\t} else {\n"); printf("\t\tuae_s32 newv = (uae_s32)dst / (uae_s32)(uae_s16)src;\n"); printf("\t\tuae_u16 rem = (uae_s32)dst %% (uae_s32)(uae_s16)src;\n"); printf("\t\tif ((newv & 0xffff8000) != 0 && (newv & 0xffff8000) != 0xffff8000) {\n"); - printf("\t\t\tsetdivsflags(true, (uae_s32)dst, (uae_s16)src);\n"); + printf("\t\t\tsetdivsflags((uae_s32)dst, (uae_s16)src);\n"); printf("\t\t} else {\n"); printf("\t\t\tif (((uae_s16)rem < 0) != ((uae_s32)dst < 0)) rem = -rem;\n"); genflags(flag_logical, sz_word, "newv", "", ""); @@ -5488,6 +5496,7 @@ bccl_not68020: printf ("\tuae_u32 *regp = regs.regs + regno;\n"); printf ("\tif (! m68k_movec2(src & 0xFFF, regp)) goto %s;\n", endlabelstr); trace_t0_68040_only(); + need_endlabel = 1; break; case i_MOVE2C: genamode (curi, curi->smode, "srcreg", curi->size, "src", 1, 0, 0); @@ -5497,6 +5506,7 @@ bccl_not68020: printf ("\tuae_u32 *regp = regs.regs + regno;\n"); printf ("\tif (! m68k_move2c(src & 0xFFF, regp)) goto %s;\n", endlabelstr); trace_t0_68040_only(); + need_endlabel = 1; break; case i_CAS: { diff --git a/include/cputest.h b/include/cputest.h index 954586a3..550065f0 100644 --- a/include/cputest.h +++ b/include/cputest.h @@ -39,7 +39,7 @@ extern int movem_index2[256]; extern int movem_next[256]; uae_u16 get_word_test_prefetch(int); -uae_u16 get_wordi_test(uaecptr); +uae_u16 get_wordi_test(int); void put_byte_test(uaecptr, uae_u32); void put_word_test(uaecptr, uae_u32); diff --git a/include/newcpu.h b/include/newcpu.h index b672e3c1..5ff7f505 100644 --- a/include/newcpu.h +++ b/include/newcpu.h @@ -679,8 +679,8 @@ extern void m68k_dumpcache (bool); extern int getDivu68kCycles (uae_u32 dividend, uae_u16 divisor); extern int getDivs68kCycles (uae_s32 dividend, uae_s16 divisor); extern void divbyzero_special(bool issigned, uae_s32 dst); -extern void setdivuflags(bool overflow, uae_u32 dividend, uae_u16 divisor); -extern void setdivsflags(bool overflow, uae_s32 dividend, uae_s16 divisor); +extern void setdivuflags(uae_u32 dividend, uae_u16 divisor); +extern void setdivsflags(uae_s32 dividend, uae_s16 divisor); extern void setchkundefinedflags(uae_s32 src, uae_s32 dst, int size); extern void setchk2undefinedflags(uae_s32 lower, uae_s32 upper, uae_s32 val, int size); extern void protect_roms (bool); @@ -816,6 +816,7 @@ extern bool can_cpu_tracer (void); #define CPU_HALT_CPU_STUCK 9 #define CPU_HALT_SSP_IN_NON_EXISTING_ADDRESS 10 #define CPU_HALT_INVALID_START_ADDRESS 11 +#define CPU_HALT_68060_HALT 12 uae_u32 process_cpu_indirect_memory_read(uae_u32 addr, int size); void process_cpu_indirect_memory_write(uae_u32 addr, uae_u32 data, int size); diff --git a/include/readcpu.h b/include/readcpu.h index 86639dee..cec52381 100644 --- a/include/readcpu.h +++ b/include/readcpu.h @@ -35,7 +35,7 @@ ENUMDECL { i_CINVL, i_CINVP, i_CINVA, i_CPUSHL, i_CPUSHP, i_CPUSHA, i_MOVE16, i_MMUOP030, i_PFLUSHN, i_PFLUSH, i_PFLUSHAN, i_PFLUSHA, i_PLPAR, i_PLPAW, i_PTESTR, i_PTESTW, - i_LPSTOP, + i_LPSTOP, i_HALT, i_PULSE, MAX_OPCODE_FAMILY } ENUMNAME (instrmnem); diff --git a/newcpu_common.cpp b/newcpu_common.cpp index 01fa5462..aad3f7d8 100644 --- a/newcpu_common.cpp +++ b/newcpu_common.cpp @@ -110,10 +110,18 @@ int m68k_move2c (int regno, uae_u32 *regp) #if MOVEC_DEBUG > 0 write_log (_T("move2c %04X <- %08X PC=%x\n"), regno, *regp, M68K_GETPC); #endif - if (movec_illg (regno)) { - op_illg (0x4E7B); + if (movec_illg(regno)) { + if (currprefs.cpu_model < 68060 && !regs.s) { + Exception(8); + return 0; + } + op_illg(0x4E7B); return 0; } else { + if (!regs.s) { + Exception(8); + return 0; + } switch (regno) { case 0: regs.sfc = *regp & 7; break; case 1: regs.dfc = *regp & 7; break; @@ -185,10 +193,18 @@ int m68k_movec2 (int regno, uae_u32 *regp) #if MOVEC_DEBUG > 0 write_log (_T("movec2 %04X PC=%x\n"), regno, M68K_GETPC); #endif - if (movec_illg (regno)) { - op_illg (0x4E7A); + if (movec_illg(regno)) { + if (currprefs.cpu_model < 68060 && !regs.s) { + Exception(8); + return 0; + } + op_illg(0x4E7A); return 0; } else { + if (!regs.s) { + Exception(8); + return 0; + } switch (regno) { case 0: *regp = regs.sfc; break; case 1: *regp = regs.dfc; break; @@ -804,31 +820,27 @@ void divbyzero_special (bool issigned, uae_s32 dst) * 68000: V=1, C=0, Z=0, N=1 * 68020: V=1, C=0, Z=0, N=X * 68040: V=1, C=0, NZ not modified. - * 68060: V=1, C=0, N=0, Z=0 + * 68060: V=1, C=0, NZ not modified. * * X) N is set if original 32-bit destination value is negative. * */ -void setdivuflags(bool overflow, uae_u32 dividend, uae_u16 divisor) +void setdivuflags(uae_u32 dividend, uae_u16 divisor) { - if (!overflow) { - if (currprefs.cpu_model != 68040) - CLEAR_CZNV(); - } else { - if (currprefs.cpu_model == 68060) { - SET_VFLG(1); - } else if (currprefs.cpu_model == 68040) { - SET_VFLG(1); - SET_CFLG(0); - } else if (currprefs.cpu_model >= 68020) { - SET_VFLG(1); - if ((uae_s32)dividend < 0) - SET_NFLG(1); - } else { - SET_VFLG(1); + if (currprefs.cpu_model == 68060) { + SET_VFLG(1); + SET_CFLG(0); + } else if (currprefs.cpu_model == 68040) { + SET_VFLG(1); + SET_CFLG(0); + } else if (currprefs.cpu_model >= 68020) { + SET_VFLG(1); + if ((uae_s32)dividend < 0) SET_NFLG(1); - } + } else { + SET_VFLG(1); + SET_NFLG(1); } } @@ -838,47 +850,46 @@ void setdivuflags(bool overflow, uae_u32 dividend, uae_u16 divisor) * 68000: V=1, C=0, N=1, Z=0 * 68020: V=1, C=0, ZN = X * 68040: V=1, C=0. NZ not modified. - * 68060: V=1, C=0, N=0, Z=0 + * 68060: V=1, C=0, NZ not modified. * * X) if absolute overflow(Check getDivs68kCycles for details) : Z = 0, N = 0 * if not absolute overflow : N is set if internal result BYTE is negative, Z is set if it is zero! * */ -void setdivsflags(bool overflow, uae_s32 dividend, uae_s16 divisor) +void setdivsflags(uae_s32 dividend, uae_s16 divisor) { - if (!overflow) { - if (currprefs.cpu_model != 68040) - CLEAR_CZNV(); - } else { - if (currprefs.cpu_model == 68060) { - SET_VFLG(1); - } else if (currprefs.cpu_model == 68040) { - SET_VFLG(1); - SET_CFLG(0); - } else if (currprefs.cpu_model >= 68020) { - SET_VFLG(1); - // absolute overflow? - if (((uae_u32)abs(dividend) >> 16) >= (uae_u16)abs(divisor)) - return; - uae_u32 aquot = (uae_u32)abs(dividend) / (uae_u16)abs(divisor); - if ((uae_s8)aquot == 0) - SET_ZFLG(1); - if ((uae_s8)aquot < 0) - SET_NFLG(1); - } else { - SET_VFLG(1); + if (currprefs.cpu_model == 68060) { + SET_VFLG(1); + SET_CFLG(0); + } else if (currprefs.cpu_model == 68040) { + SET_VFLG(1); + SET_CFLG(0); + } else if (currprefs.cpu_model >= 68020) { + CLEAR_CZNV(); + SET_VFLG(1); + // absolute overflow? + if (((uae_u32)abs(dividend) >> 16) >= (uae_u16)abs(divisor)) + return; + uae_u32 aquot = (uae_u32)abs(dividend) / (uae_u16)abs(divisor); + if ((uae_s8)aquot == 0) + SET_ZFLG(1); + if ((uae_s8)aquot < 0) SET_NFLG(1); - } + } else { + CLEAR_CZNV(); + SET_VFLG(1); + SET_NFLG(1); } } /* - * CHK.W undefined flags + * CHK undefined flags * * 68000: CV=0. Z: dst==0. N: dst < 0. !N: dst > src. * 68020: Z: dst==0. N: dst < 0. V: src-dst overflow. C: if dst < 0: (dst > src || src >= 0), if dst > src: (src >= 0). - * 68040: N=0. If exception: N=dst < 0 + * 68040: C=0. C=1 if exception and (dst < 0 && src >= 0) || (src >= 0 && dst >= src) || (dst < 0 && src < dst) + * 68060: N=0. If exception: N=dst < 0 * */ void setchkundefinedflags(uae_s32 src, uae_s32 dst, int size) @@ -899,14 +910,14 @@ void setchkundefinedflags(uae_s32 src, uae_s32 dst, int size) if (dst < 0 || dst > src) { if (size == sz_word) { int flgs = ((uae_s16)(dst)) < 0; - int flgo = ((uae_s16)(src)) < 0; - uae_s16 val = (uae_s16)src - (uae_s16)dst; - int flgn = val < 0; - SET_VFLG((flgs ^ flgo) & (flgn ^ flgo)); + int flgo = ((uae_s16)(src)) < 0; + uae_s16 val = (uae_s16)src - (uae_s16)dst; + int flgn = val < 0; + SET_VFLG((flgs ^ flgo) & (flgn ^ flgo)); } else { int flgs = dst < 0; - int flgo = src < 0; - uae_s32 val = src - dst; + int flgo = src < 0; + uae_s32 val = src - dst; int flgn = val < 0; SET_VFLG((flgs ^ flgo) & (flgn ^ flgo)); } @@ -916,7 +927,19 @@ void setchkundefinedflags(uae_s32 src, uae_s32 dst, int size) SET_CFLG(src >= 0); } } - } else { + } else if (currprefs.cpu_model == 68040) { + SET_CFLG(0); + if (dst < 0 || dst > src) { + if (dst < 0 && src >= 0) { + SET_CFLG(1); + } else if (src >= 0 && dst >= src) { + SET_CFLG(1); + } else if (dst < 0 && src < dst) { + SET_CFLG(1); + } + } + SET_NFLG(dst < 0); + } else if (currprefs.cpu_model == 68060) { SET_NFLG(0); if (dst < 0 || dst > src) { SET_NFLG(dst < 0); @@ -928,7 +951,8 @@ void setchkundefinedflags(uae_s32 src, uae_s32 dst, int size) * CHK2/CMP2 undefined flags * * 68020-68030: See below.. - * 68040: N: val<0 V=0 + * 68040: NV not modified. + * 68060: N: val<0 V=0 * */ @@ -936,14 +960,17 @@ void setchkundefinedflags(uae_s32 src, uae_s32 dst, int size) // Someone else can attempt to simplify this.. void setchk2undefinedflags(uae_s32 lower, uae_s32 upper, uae_s32 val, int size) { - SET_NFLG(0); - SET_VFLG(0); - - if (currprefs.cpu_model >= 68040) { + if (currprefs.cpu_model == 68060) { + SET_VFLG(0); SET_NFLG(val < 0); return; + } else if (currprefs.cpu_model == 68040) { + return; } + SET_NFLG(0); + SET_VFLG(0); + if (val == lower || val == upper) return; @@ -1079,7 +1106,7 @@ static void divul_overflow(uae_u16 extra, uae_s64 a) static void divsl_divbyzero(uae_u16 extra, uae_s64 a) { - if (currprefs.cpu_model == 68060) { + if (currprefs.cpu_model >= 68040) { SET_CFLG(0); } else { SET_NFLG(0); @@ -1091,7 +1118,7 @@ static void divsl_divbyzero(uae_u16 extra, uae_s64 a) static void divul_divbyzero(uae_u16 extra, uae_s64 a) { - if (currprefs.cpu_model == 68060) { + if (currprefs.cpu_model >= 68040) { SET_CFLG(0); } else { uae_s32 a32 = (uae_s32)a; diff --git a/readcpu.cpp b/readcpu.cpp index eb9f1856..c7896a0c 100644 --- a/readcpu.cpp +++ b/readcpu.cpp @@ -151,6 +151,8 @@ struct mnemolookup lookuptab[] = { { i_PTESTW, _T("PTESTW"), NULL, 0 }, { i_LPSTOP, _T("LPSTOP"), NULL, 0 }, + { i_HALT, _T("HALT"), NULL, 0 }, + { i_PULSE, _T("PULSE"), NULL, 0 }, { i_ILLG, _T(""), NULL, 0 }, }; diff --git a/table68k b/table68k index 24405726..57632d70 100644 --- a/table68k +++ b/table68k @@ -263,9 +263,9 @@ 0100 1110 0111 0111:000:XNZVC:-----:00: RTR - 1 0 12 -0100 1110 0111 1010:102:?????:?????:10: MOVEC2 #1 +0100 1110 0111 1010:100:?????:?????:10: MOVEC2 #1 - 6 0 6 -0100 1110 0111 1011:102:?????:?????:10: MOVE2C #1 +0100 1110 0111 1011:100:?????:?????:10: MOVE2C #1 - 6 0 6 0100 1110 10ss sSSS:000://///://///:80: JSR.L s[!Dreg,Areg,Aipi,Apdi,Immd] - 0 0 4 jea @@ -511,7 +511,9 @@ 1111 0110 00dd dDDD:400:-----:-----:12: MOVE16 L,d[Aipi-Aind] % 68060 -1111 1000 0000 0000:502:?????:?????:10: LPSTOP #1 +1111 1000 0000 0000:500:?????:?????:10: LPSTOP #1 1111 0101 1000 1rrr:502:-----:-----:00: PLPAW Ara 1111 0101 1100 1rrr:502:-----:-----:00: PLPAR Ara - +% "Debug Pipe Control Mode Commands" +0100 1010 1100 1000:502:?????:?????:00: HALT +0100 1010 1100 1100:500:?????:?????:00: PULSE