From: Toni Wilen Date: Sun, 26 Jan 2020 14:24:56 +0000 (+0200) Subject: 68010 full support and bug fixes. X-Git-Tag: 4400~165 X-Git-Url: https://git.unchartedbackwaters.co.uk/w/?a=commitdiff_plain;h=497cb179f9c59138a5d75add718574fc8bc53da1;p=francis%2Fwinuae.git 68010 full support and bug fixes. --- diff --git a/cputest.cpp b/cputest.cpp index 7286362c..8f0fcb4e 100644 --- a/cputest.cpp +++ b/cputest.cpp @@ -167,6 +167,7 @@ struct accesshistory uae_u32 val; uae_u32 oldval; int size; + bool donotsave; }; static int ahcnt_current, ahcnt_written; static int noaccesshistory = 0; @@ -359,15 +360,26 @@ uae_u16 get_word_test_prefetch(int o) return get_iword_test(m68k_getpci() + o); } -// Move from SR does two writes to same address: -// ignore the first one static void previoussame(uaecptr addr, int size) { if (!ahcnt_current || ahcnt_current == ahcnt_written) return; - struct accesshistory *ah = &ahist[ahcnt_current - 1]; - if (ah->addr == addr && ah->size == size) { - ahcnt_current--; + // Move from SR does two writes to same address. + // Loop mode can write different values to same address. + // Mark old values as do not save. + for (int i = ahcnt_written; i < ahcnt_current; i++) { + struct accesshistory *ah = &ahist[i]; + if (ah->size == size && ah->addr == addr) { + ah->donotsave = true; + } + if (size == sz_long) { + if (ah->size == sz_word && ah->addr == addr) { + ah->donotsave = true; + } + if (ah->size == sz_word && ah->addr == addr + 2) { + ah->donotsave = true; + } + } } } @@ -388,6 +400,7 @@ void put_byte_test(uaecptr addr, uae_u32 v) ah->val = v & 0xff; ah->oldval = *p; ah->size = sz_byte; + ah->donotsave = false; } regs.write_buffer = v; *p = v; @@ -414,6 +427,7 @@ void put_word_test(uaecptr addr, uae_u32 v) ah->val = v & 0xffff; ah->oldval = (p[0] << 8) | p[1]; ah->size = sz_word; + ah->donotsave = false; } p[0] = v >> 8; p[1] = v & 0xff; @@ -446,6 +460,7 @@ void put_long_test(uaecptr addr, uae_u32 v) ah->val = v; ah->oldval = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; ah->size = sz_long; + ah->donotsave = false; } p[0] = v >> 24; p[1] = v >> 16; @@ -1512,6 +1527,8 @@ static uae_u8 *store_mem_writes(uae_u8 *dst, int storealways) struct accesshistory *ah = &ahist[i]; if (ah->oldval == ah->val && !storealways) continue; + if (ah->donotsave) + continue; validate_addr(ah->addr, 1 << ah->size); uaecptr addr = ah->addr; addr &= addressing_mask; @@ -2713,8 +2730,8 @@ static void execute_ins(uaecptr endpc, uaecptr targetpc, struct instr *dp) 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 == 0x40ef - && opw1 == 0x64fc + if (opc == 0xd196 + //&& opw1 == 0x64fc //&& opw2 == 0x4afc ) printf(""); @@ -3388,6 +3405,8 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi if (feature_loop_mode_68010) { if (!opcode_loop_mode(opcode)) continue; + if (dp->mnemo == i_DBcc) + continue; } target_ea[0] = target_ea_bak[0]; diff --git a/cputest/adis/defs.h b/cputest/adis/defs.h index 1a1c53d0..9c1e2a38 100644 --- a/cputest/adis/defs.h +++ b/cputest/adis/defs.h @@ -157,7 +157,8 @@ struct opcode_sub_entry enum { SR, CCR, USP, SFC, DFC, CACR, VBR, CAAR, MSP, ISP, TC, - ITT0, ITT1, DTT0, DTT1, MMUSR, URP, SRP, TT0, TT1, CRP + ITT0, ITT1, DTT0, DTT1, MMUSR, URP, SRP, TT0, TT1, CRP, + BUSCR, PCR }; #define PC (ushort)16 /* index into reg_names array */ @@ -283,7 +284,8 @@ extern BOOL single_file; extern BOOL ascending_label_numbers; extern BOOL disasm_as_lib; extern BOOL old_style; -extern BOOL cpu68020, +extern BOOL cpu68010, + cpu68020, cpu68030, cpu68040, cpu68060, @@ -301,7 +303,6 @@ extern short cpu68020_disabled []; extern short cpu68030_disabled []; extern short cpu68040_disabled []; extern short cpu68060_disabled []; -extern short cpuCF_disabled []; extern short fpu68881_disabled []; extern int OPCODE_COL; diff --git a/cputest/adis/globals.c b/cputest/adis/globals.c index e8d53ca9..5500aa01 100644 --- a/cputest/adis/globals.c +++ b/cputest/adis/globals.c @@ -87,11 +87,11 @@ BOOL try_small = FALSE; /* -b */ BOOL single_file = TRUE; BOOL print_illegal_instr_offset = FALSE; /* -i */ BOOL old_style = FALSE; -BOOL cpu68020 = TRUE, /* -m2 */ +BOOL cpu68010 = TRUE, + cpu68020 = TRUE, /* -m2 */ cpu68030 = TRUE, /* -m3 */ cpu68040 = TRUE, /* -m4 */ cpu68060 = TRUE, /* -m6 */ - cpuCF = FALSE, fpu68881 = TRUE; /* -m8 */ BOOL disasm_as_lib = FALSE; /* -l */ BOOL ascending_label_numbers = FALSE; /* -dn */ @@ -188,6 +188,8 @@ char *special_regs [] = "tt0", /* 18 */ "tt1", /* 19 */ "crp" /* 20 */ + "buscr" /* 21 */ + "pcr" /* 22 */ }; /**********************************************************************/ @@ -276,52 +278,3 @@ short cpu68060_disabled [] = 983, /* PLPAR */ 0 }; - -short cpuCF_disabled [] = - { - 452, /* MVS.B */ - 453, /* MVS.W */ - 454, /* MVZ.B */ - 455, /* MVZ.W */ - 460, /* MVS.B */ - 461, /* MVS.W */ - 462, /* MVZ.B */ - 463, /* MVZ.W */ - 468, /* MVS.B */ - 469, /* MVS.W */ - 470, /* MVZ.B */ - 471, /* MVZ.W */ - 476, /* MVS.B */ - 477, /* MVS.W */ - 478, /* MVZ.B */ - 479, /* MVZ.W */ - 484, /* MVS.B */ - 485, /* MVS.W */ - 486, /* MVZ.B */ - 487, /* MVZ.W */ - 492, /* MVS.B */ - 493, /* MVS.W */ - 494, /* MVZ.B */ - 495, /* MVZ.W */ - 500, /* MVS.B */ - 501, /* MVS.W */ - 502, /* MVZ.B */ - 503, /* MVZ.W */ - 508, /* MVS.B */ - 509, /* MVS.W */ - 510, /* MVZ.B */ - 511, /* MVZ.W */ - 645, /* MOV3Q */ - 653, /* MOV3Q */ - 661, /* MOV3Q */ - 669, /* MOV3Q */ - 677, /* MOV3Q */ - 685, /* MOV3Q */ - 693, /* MOV3Q */ - 701, /* MOV3Q */ - 1056, /* BITREV */ - 1057, /* BYTEREV */ - 1058, /* FF1 */ - 1059, /* SATS */ - 0 - }; diff --git a/cputest/adis/opcode_handler_cpu.c b/cputest/adis/opcode_handler_cpu.c index 0700fd24..e5f82f20 100644 --- a/cputest/adis/opcode_handler_cpu.c +++ b/cputest/adis/opcode_handler_cpu.c @@ -380,7 +380,7 @@ if ((*code & 0x38) == 0x30) case 3: ptr = "rte"; instr_end = TRUE; break; - case 4: if (!cpu68020) + case 4: if (!cpu68010) return (TRANSFER); ptr = "rtd"; instr_end = TRUE; @@ -408,7 +408,7 @@ else if ((*code & 0x3e) == 0x3a) /* MOVEC */ { short reg_offset; - if (!cpu68020) + if (!cpu68010) return (TRANSFER); switch (*(code + 1) & 0xfff) { @@ -418,30 +418,17 @@ else if ((*code & 0x3e) == 0x3a) /* MOVEC */ break; case 0x002: ptr = special_regs [CACR]; break; - case 0x003: if (cpu68040) - ptr = special_regs [TC]; - else - return (TRANSFER); + case 0x003: ptr = special_regs [TC]; + break; + case 0x004: ptr = special_regs [ITT0]; break; - case 0x004: if (cpu68040) - ptr = special_regs [ITT0]; - else - return (TRANSFER); + case 0x005: ptr = special_regs [ITT1]; break; - case 0x005: if (cpu68040) - ptr = special_regs [ITT1]; - else - return (TRANSFER); + case 0x006: ptr = special_regs [DTT0]; break; - case 0x006: if (cpu68040) - ptr = special_regs [DTT0]; - else - return (TRANSFER); + case 0x007: ptr = special_regs [DTT1]; break; - case 0x007: if (cpu68040) - ptr = special_regs [DTT1]; - else - return (TRANSFER); + case 0x008: ptr = special_regs [BUSCR]; break; case 0x800: ptr = special_regs [USP]; break; @@ -453,20 +440,13 @@ else if ((*code & 0x3e) == 0x3a) /* MOVEC */ break; case 0x804: ptr = special_regs [ISP]; break; - case 0x805: if (cpu68040) - ptr = special_regs [MMUSR]; - else - return (TRANSFER); + case 0x805: ptr = special_regs [MMUSR]; + break; + case 0x806: ptr = special_regs [URP]; break; - case 0x806: if (cpu68040) - ptr = special_regs [URP]; - else - return (TRANSFER); + case 0x807: ptr = special_regs [SRP]; break; - case 0x807: if (cpu68040) - ptr = special_regs [SRP]; - else - return (TRANSFER); + case 0x808: ptr = special_regs [PCR]; break; default : return (TRANSFER); } @@ -474,7 +454,7 @@ else if ((*code & 0x3e) == 0x3a) /* MOVEC */ reg_offset = (*(code + 1) & 0x8000) ? 8 : 0; if (pass3) { - str_cpy (opcode, "movec.l"); + str_cpy (opcode, "movec"); if (*code & 0x1) { /* from general register to control register */ @@ -1196,29 +1176,3 @@ if (pass3) } return (1); } - -/********************************************************************** - ColdFire handlers -**********************************************************************/ - -uint mov3q (struct opcode_entry *op) - -/* handler for ColdFire mov3q */ -{ -if (pass3) - { - char *to; - to = src; - *to++ = '#'; - UBYTE data = (UBYTE)op->param; - if (data) - *to++ = data + '0'; - else - { - *to++ = '-'; - *to++ = '1'; - } - *to = 0; - } -return (decode_ea (dest, MODE_NUM(*code), REG_NUM(*code), ACC_LONG, 1) + 1); -} diff --git a/cputest/adis/opcodes_cpu.c b/cputest/adis/opcodes_cpu.c index 12a6cbb4..320f8d34 100644 --- a/cputest/adis/opcodes_cpu.c +++ b/cputest/adis/opcodes_cpu.c @@ -697,7 +697,7 @@ struct opcode_entry opcode_table [] = { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 000 010 */ { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 000 011 */ { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 000 100 */ -{ mov3q , 0xff, 0x0f, 1024, "mov3q" , 0, ACC_LONG }, /* 1010 000 101 */ +{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 000 101 */ { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 000 110 */ { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 000 111 */ { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 001 000 */ @@ -705,7 +705,7 @@ struct opcode_entry opcode_table [] = { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 001 010 */ { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 001 011 */ { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 001 100 */ -{ mov3q , 0xff, 0x0f, 1024, "mov3q" , 1, ACC_LONG }, /* 1010 001 101 */ +{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 001 101 */ { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 001 110 */ { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 001 111 */ { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 010 000 */ @@ -713,7 +713,7 @@ struct opcode_entry opcode_table [] = { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 010 010 */ { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 010 011 */ { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 010 100 */ -{ mov3q , 0xff, 0x0f, 1024, "mov3q" , 2, ACC_LONG }, /* 1010 010 101 */ +{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 010 101 */ { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 010 110 */ { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 010 111 */ { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 011 000 */ @@ -721,7 +721,7 @@ struct opcode_entry opcode_table [] = { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 011 010 */ { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 011 011 */ { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 011 100 */ -{ mov3q , 0xff, 0x0f, 1024, "mov3q" , 3, ACC_LONG }, /* 1010 011 101 */ +{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 011 101 */ { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 011 110 */ { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 011 111 */ { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 100 000 */ @@ -729,7 +729,7 @@ struct opcode_entry opcode_table [] = { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 100 010 */ { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 100 011 */ { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 100 100 */ -{ mov3q , 0xff, 0x0f, 1024, "mov3q" , 4, ACC_LONG }, /* 1010 100 101 */ +{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 100 101 */ { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 100 110 */ { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 100 111 */ { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 101 000 */ @@ -737,7 +737,7 @@ struct opcode_entry opcode_table [] = { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 101 010 */ { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 101 011 */ { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 101 100 */ -{ mov3q , 0xff, 0x0f, 1024, "mov3q" , 5, ACC_LONG }, /* 1010 101 101 */ +{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 101 101 */ { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 101 110 */ { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 101 111 */ { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 110 000 */ @@ -745,7 +745,7 @@ struct opcode_entry opcode_table [] = { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 110 010 */ { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 110 011 */ { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 110 100 */ -{ mov3q , 0xff, 0x0f, 1024, "mov3q" , 6, ACC_LONG }, /* 1010 110 101 */ +{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 110 101 */ { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 110 110 */ { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 110 111 */ { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 111 000 */ @@ -753,7 +753,7 @@ struct opcode_entry opcode_table [] = { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 111 010 */ { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 111 011 */ { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 111 100 */ -{ mov3q , 0xff, 0x0f, 1024, "mov3q" , 7, ACC_LONG }, /* 1010 111 101 */ +{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 111 101 */ { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 111 110 */ { invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 111 111 */ { EA_to_Rn , 0xff, 0x1f, 1024, "cmp.b" , 0, ACC_BYTE }, /* 1011 000 000 */ @@ -1114,10 +1114,5 @@ struct opcode_entry opcode_table [] = { op2_bcdx , 0x03, 0x00, 1024, "subx.b" , NO_ADJ, 0 }, /* 1052 */ { op2_bcdx , 0x03, 0x00, 1024, "subx.w" , NO_ADJ, 0 }, /* 1053 */ { op2_bcdx , 0x03, 0x00, 1024, "subx.l" , NO_ADJ, 0 }, /* 1054 */ -{ link_l , 0x02, 0x00, 1024, "link.l" , 0, 0 }, /* 1055 */ -/* ColdFire chains */ -{ op1 , 0x03, 0x00, 1024, "bitrev" , 0, ACC_LONG }, /* 1056 */ -{ op1 , 0x03, 0x00, 1024, "byterev" , 0, ACC_LONG }, /* 1057 */ -{ op1 , 0x03, 0x00, 1024, "ff1" , 0, ACC_LONG }, /* 1058 */ -{ op1 , 0x03, 0x00, 1024, "sats" , 0, ACC_SLONG } /* 1059 */ +{ link_l , 0x02, 0x00, 1024, "link.l" , 0, 0 } /* 1055 */ }; diff --git a/cputest/adis/util.c b/cputest/adis/util.c index 8df07bde..2288acac 100644 --- a/cputest/adis/util.c +++ b/cputest/adis/util.c @@ -986,6 +986,9 @@ uint disasm_instr(UWORD *instr, char *out, int cpu_lvl) cpu68020 = 0; fpu68881 = 0; } + if (cpu_lvl < 1) { + cpu68010 = 0; + } set_pass3; diff --git a/cputest/cputestgen.ini b/cputest/cputestgen.ini index 24007c9b..f00fa188 100644 --- a/cputest/cputestgen.ini +++ b/cputest/cputestgen.ini @@ -134,6 +134,8 @@ feature_sr_mask=0x0000 ; 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 ; 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. diff --git a/cputest/main.c b/cputest/main.c index fd66d0ae..3dba92a7 100644 --- a/cputest/main.c +++ b/cputest/main.c @@ -128,6 +128,9 @@ static uae_u32 interrupt_mask; static short disasm; static short basicexcept; static short excskipccr; +static short skipmemwrite; +static short skipregchange; +static short skipccrchange; static short askifmissing; static short nextall; static int exitcnt; @@ -1158,7 +1161,7 @@ static void out_disasm(uae_u8 *mem) uae_u8 *p = mem; int offset = 0; int lines = 0; - while (lines++ < 5) { + while (lines++ < 7) { int v = 0; if (!is_valid_test_addr_read((uae_u32)p) || !is_valid_test_addr_read((uae_u32)p + 1)) { sprintf(outbp, "%08x -- INACCESSIBLE --\n", (uae_u32)p); @@ -1708,18 +1711,15 @@ static int getexceptioncycles(int exc) case 3: return 126; case 4: - case 10: - case 11: - return 38; case 5: - return 38; case 6: - return 44; - case 7: - return 40; case 8: - return 38; case 9: + case 10: + case 11: + case 14: + return 38; + case 7: return 38; case 24: case 25: @@ -1863,7 +1863,7 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr) { uae_u8 regs_changed[16] = { 0 }; uae_u8 regs_fpuchanged[8] = { 0 }; - uae_u8 sr_changed = 0, pc_changed = 0; + uae_u8 sr_changed = 0, ccr_changed = 0, pc_changed = 0; uae_u8 fpiar_changed = 0, fpsr_changed = 0, fpcr_changed = 0; short exc = -1; @@ -1872,9 +1872,12 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr) regs_changed[i] = 1; } } - if ((last_registers.sr & test_ccrignoremask) != (test_regs.sr & test_ccrignoremask)) { + if ((last_registers.sr & test_ccrignoremask & 0xff00) != (test_regs.sr & test_ccrignoremask & 0xff00)) { sr_changed = 1; } + if ((last_registers.sr & test_ccrignoremask & 0x00ff) != (test_regs.sr & test_ccrignoremask & 0x00ff)) { + ccr_changed = 1; + } if (last_registers.pc != test_regs.pc) { pc_changed = 1; } @@ -1979,7 +1982,7 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr) uae_u32 val = last_registers.regs[mode]; int size; p = restore_value(p, &val, &size); - if (val != test_regs.regs[mode] && !ignore_errors) { + if (val != test_regs.regs[mode] && !ignore_errors && !skipregchange) { if (dooutput) { sprintf(outbp, "%c%d: expected %08x but got %08x\n", mode < CT_AREG ? 'D' : 'A', mode & 7, val, test_regs.regs[mode]); outbp += strlen(outbp); @@ -1988,7 +1991,7 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr) } regs_changed[mode] = 0; last_registers.regs[mode] = val; - } else if (mode < CT_AREG && (v & CT_SIZE_MASK) == CT_SIZE_FPU) { + } else if (mode < CT_AREG && (v & CT_SIZE_MASK) == CT_SIZE_FPU && !skipregchange) { struct fpureg val; p = restore_fpvalue(p, &val); if (memcmp(&val, &test_regs.fpuregs[mode], sizeof(struct fpureg)) && !ignore_errors) { @@ -2027,11 +2030,12 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr) } // CCR check mask = test_ccrignoremask & 0x00ff; - if ((val & (sr_undefined_mask & mask)) == (test_regs.sr & (sr_undefined_mask & mask))) { + if (skipccrchange || ((val & (sr_undefined_mask & mask)) == (test_regs.sr & (sr_undefined_mask & mask)))) { errflag &= ~(1 << 7); } } sr_changed = 0; + ccr_changed = 0; last_registers.sr = val; if (!(test_regs.expsr & 0x2000)) { sprintf(outbp, "SR S-bit is not set at start of exception handler!\n"); @@ -2107,7 +2111,7 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr) { case 0: mval = addr[0]; - if (mval != val && !ignore_errors) { + if (mval != val && !ignore_errors && !skipmemwrite) { if (dooutput) { sprintf(outbp, "Memory byte write: address %08x, expected %02x but got %02x\n", (uae_u32)addr, val, mval); outbp += strlen(outbp); @@ -2118,7 +2122,7 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr) break; case 1: mval = (addr[0] << 8) | (addr[1]); - if (mval != val && !ignore_errors) { + 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); outbp += strlen(outbp); @@ -2130,7 +2134,7 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr) break; case 2: mval = gl(addr); - if (mval != val && !ignore_errors) { + if (mval != val && !ignore_errors && !skipmemwrite) { if (dooutput) { sprintf(outbp, "Memory long write: address %08x, expected %08x but got %08x\n", (uae_u32)addr, val, mval); outbp += strlen(outbp); @@ -2147,7 +2151,7 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr) } } if (!ignore_errors) { - if (!ignore_sr) { + if (!skipregchange) { for (int i = 0; i < 16; i++) { if (regs_changed[i]) { if (dooutput) { @@ -2157,12 +2161,20 @@ static uae_u8 *validate_test(uae_u8 *p, short ignore_errors, short ignore_sr) errflag |= 1 << 0; } } + } + if (!ignore_sr) { if (sr_changed) { if (dooutput) { sprintf(outbp, "SR: modified %04x -> %04x but expected no modifications\n", last_registers.sr & 0xffff, test_regs.sr & 0xffff); outbp += strlen(outbp); } errflag |= 1 << 2; + } else if (ccr_changed && !skipccrchange) { + if (dooutput) { + sprintf(outbp, "SR: modified %04x -> %04x but expected no modifications\n", last_registers.sr & 0xffff, test_regs.sr & 0xffff); + outbp += strlen(outbp); + } + errflag |= 1 << 2; } } for (int i = 0; i < 8; i++) { @@ -2886,7 +2898,9 @@ int main(int argc, char *argv[]) printf("-ccrmask = ignore CCR bits that are not set.\n"); printf("-nodisasm = do not disassemble failed test.\n"); printf("-basicexc = do only basic checks when exception is 2 or 3.\n"); - printf("-excskipccr = ignore CCR if DivByZero, CHK, Address/Bus error exception.\n"); + printf("-skipexcccr = ignore CCR if DivByZero, CHK, Address/Bus error exception.\n"); + printf("-skipmem = do not validate memory writes.\n"); + printf("-skipreg = do not validate registers.\n"); printf("-askifmissing = ask for new path if dat file is missing.\n"); printf("-exit n = exit after n tests.\n"); printf("-cycles [range adjust] = check cycle counts.\n"); @@ -2939,8 +2953,14 @@ int main(int argc, char *argv[]) disasm = 0; } else if (!_stricmp(s, "-basicexc")) { basicexcept = 1; - } else if (!_stricmp(s, "-excskipccr")) { + } else if (!_stricmp(s, "-skipexcccr")) { excskipccr = 1; + } else if (!_stricmp(s, "-skipmem")) { + skipmemwrite = 1; + } else if (!_stricmp(s, "-skipreg")) { + skipregchange = 1; + } else if (!_stricmp(s, "-skipccr")) { + skipccrchange = 1; } else if (!_stricmp(s, "-askifmissing")) { askifmissing = 1; } else if (!_stricmp(s, "-next")) { diff --git a/cputest/readme.txt b/cputest/readme.txt index 1c553904..fdd58ff3 100644 --- a/cputest/readme.txt +++ b/cputest/readme.txt @@ -12,7 +12,7 @@ Verifies: - Memory writes, including stack modifications (if any) - Loop mode for JIT testing. (generates , dbf dn,loop) - Supports 68000, 68010, 68020, 68030 (only difference between 020 and 030 seems to be data cache and MMU), 68040 and 68060. -- Cycle counts (68000 Amiga only) +- Cycle counts (68000/68010, Amiga only) Tests executed for each tested instruction: @@ -43,25 +43,26 @@ Notes and limitations: Tester compatibility (integer instructions only): 68000: Complete. Including bus and address error stack frame/register/CCR modification undocumented behavior. Cycle count support. -68010: Almost complete. Bus errors are only partially supported. DIVS undefined condition codes are not yet supported. +68010: Almost complete (same as 68000). Loop mode is also fully supported. NOTE: DIVS overflow undocumented N-flag is not fully correct. 68020: Almost complete (DIV undocumented behavior is not yet known) 68030: Same as 68020. 68040: Almost complete (Weird unaligned MOVE16 behavior which may be board specific). 68060: Same as 68040. -68000 cycle count testing: +68000/68010 cycle count testing: Cycle counting requires 100% accurate timing also for following instructions: - BSR.B - NOP - MOVE.W ABS.L,ABS.L - MOVE SR,-(SP) +- MOVE.W #x,ABS.L (68010 only) - RTE - Illegal instruction exception - If instruction internally generates exception, internal exception also needs to be cycle-accurate. 0xDFF006 is used for cycle counting = accuracy will be +-2 CPU cycles. 0xDFF006 behavior must be accurate. -Currently only supported hardware for cycle counting is 7MHz 68000 PAL Amiga with real Fast RAM. +Currently only supported hardware for cycle counting is 7MHz 68000/68010 PAL Amiga with real Fast RAM. Bus error cycle counting is not yet supported. @@ -124,7 +125,18 @@ If mismatch is detected, opcode word(s), instruction disassembly, registers befo Change log: +18.01.2020 + - Cycle count validation (Amiga, 68000 only), including exceptions (except bus errors). - 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. + +26.01.2020 + +- 68010 is now almost fully supported, including loop mode and cycle count verification. +- Removed most ColdFire instructions from disassembler. RTD was not disassembled if 68010. Added missing 68060 PCR and BUSCR control registers. +- Fixed ahist overflow when generating MOVEM with more than 1 SR flag combination. +- Some instructions (for example TRAP) had wrong expected cycle count if instruction generated any non-trace exception and also trace exception. +- added -skipexcccr parameter. Skip CCR check if instruction generates bus, address, divide by zero or CHK exception. +- added -skipmem (ignore memory write mismatches) -skipreg (ignore register mismatched) -skipccr (ignored CCR mismatch) parameters. diff --git a/gencpu.cpp b/gencpu.cpp index dd84ab42..877c8fa9 100644 --- a/gencpu.cpp +++ b/gencpu.cpp @@ -59,23 +59,25 @@ static int opcode_nextcopy; static int optimized_flags; -#define GF_APDI 1 -#define GF_AD8R 2 -#define GF_PC8R 4 -#define GF_AA 7 -#define GF_NOREFILL 8 -#define GF_PREFETCH 16 -#define GF_FC 32 -#define GF_MOVE 64 -#define GF_IR2IRC 128 -#define GF_LRMW 256 -#define GF_NOFAULTPC 512 -#define GF_RMW 1024 -#define GF_OPCE020 2048 -#define GF_REVERSE 4096 -#define GF_REVERSE2 8192 -#define GF_SECONDWORDSETFLAGS 16384 -#define GF_SECONDEA 32768 +#define GF_APDI 0x00001 +#define GF_AD8R 0x00002 +#define GF_PC8R 0x00004 +#define GF_AA 0x00007 +#define GF_NOREFILL 0x00008 +#define GF_PREFETCH 0x00010 +#define GF_FC 0x00020 +#define GF_MOVE 0x00040 +#define GF_IR2IRC 0x00080 +#define GF_LRMW 0x00100 +#define GF_NOFAULTPC 0x00200 +#define GF_RMW 0x00400 +#define GF_OPCE020 0x00800 +#define GF_REVERSE 0x01000 +#define GF_REVERSE2 0x02000 +#define GF_SECONDWORDSETFLAGS 0x04000 +#define GF_SECONDEA 0x08000 +#define GF_NOFETCH 0x10000 // 68010 +#define GF_CLR68010 0x20000 // 68010 typedef enum { @@ -103,6 +105,8 @@ static char rmw_varname[100]; static struct instr *g_instr; static char g_srcname[100]; static int loopmode; +static int loopmodeextra; +static int loopmode_set; #define GENA_GETV_NO_FETCH 0 #define GENA_GETV_FETCH 1 @@ -197,7 +201,15 @@ static instr *curi_ce020; static bool no_prefetch_ce020; static bool got_ea_ce020; -// 68020-30 needs different implementation than 68040/060 +// 68010-40 needs different implementation than 68060 +static void next_level_060_to_040(void) +{ + if (cpu_level >= 5) { + if (next_cpu_level < 5) + next_cpu_level = 5 - 1; + } +} +// 68010-30 needs different implementation than 68040/060 static void next_level_040_to_030(void) { if (cpu_level >= 4) { @@ -205,7 +217,6 @@ static void next_level_040_to_030(void) next_cpu_level = 4 - 1; } } - // 68000 <> 68010 static void next_level_000(void) { @@ -420,6 +431,15 @@ static void returncycles(const char *s, int cycles) printf("%sreturn %d * CYCLE_UNIT / 2;\n", s, cycles); } +static void write_return_cycles_none(const char *s) +{ + if (using_ce || using_ce020) { + printf("%sreturn;\n", s); + } else { + printf("%sreturn 0;\n", s); + } +} + static void write_return_cycles(const char *s, int end) { if (end <= 0) { @@ -909,8 +929,12 @@ static void fill_prefetch_1 (int o) { if (using_prefetch) { printf("\t%s(%d);\n", prefetch_word, o); - count_read++; - insn_n_cycles += 4; + if (!loopmode || using_ce) { + count_read++; + insn_n_cycles += 4; + } else { + addcycles000_nonce("\t", 4); + } check_prefetch_bus_error(o, 0); did_prefetch = 1; ir2irc = 0; @@ -1081,25 +1105,113 @@ static void fill_prefetch_0 (void) ir2irc = 0; } +static void loopmode_start(void) +{ + loopmode_set = 0; + loopmodeextra = 0; + if (loopmode) { + printf("\tint loop_mode = regs.loop_mode;\n"); + } +} +static void loopmode_stop(void) +{ + if (loopmode) { + printf("\tregs.loop_mode = loop_mode;\n"); + } +} static void loopmode_begin(void) { if (loopmode) { - printf("\tif(!regs.loop_mode) {\n"); + printf("\tif(!loop_mode) {\n"); + } +} +static void loopmode_access(void) +{ + if (loopmode && loopmode_set) { + loopmode_set = 0; + printf("\tif(loop_mode & 0xfffe) {\n"); + if (using_ce) { + printf("\t\t%s(loop_mode & 0xfffe);\n", do_cycles); + } else { + addcycles000_nonces("\t\t", "loop_mode & 0xfffe"); + } + // CLR.L adds 2 extra cycles when loop exits + if (g_instr->mnemo == i_CLR && g_instr->size == sz_long) { + printf("\t\tloop_mode &= 0xffff0000;\n"); + printf("\t\tloop_mode |= 1;\n"); + } else { + printf("\t\tloop_mode = 1;\n"); + } + printf("\t}\n"); } } + static void loopmode_end(void) { if (loopmode) { + int s = g_instr->size; int m = g_instr->mnemo; - if (using_ce && (g_instr->dmode == Apdi || (m != i_MOVE && m != i_CLR))) { - printf("\t} else {\n"); - if (m == i_ASLW || m == i_ASRW || m == i_LSLW || m == i_LSRW || m == i_ROLW || m == i_RORW || m == i_ROXLW || m == i_ROXRW) { - addcycles000(4); + int cycs = 0; + int ecycs = 0; + if (using_prefetch) { + if (m == i_CLR) { + cycs += 2; + ecycs += 4; + } else if (m == i_MOVE) { + cycs += 2; + if (isreg(g_instr->smode)) { + ecycs = 2; + } + } else if (m == i_ADDX || m == i_SUBX) { + if (s == sz_long) { + cycs += 2; + } else { + cycs += 4; + } + } else if (m == i_CMPM) { + if (s == sz_long) { + cycs += 4; + } else { + cycs += 2; + } + } else if (m == i_NBCD) { + cycs += 6; } else { - addcycles000(2); + cycs += 4; + } + // destination -(an)? + if ((m == i_MOVE || m == i_ABCD || m == i_SBCD) && g_instr->dmode == Apdi) { + cycs += 2; + } + + if (ecycs == 0) { + ecycs = cycs; } + + if (m == i_TST && s == sz_long) { + ecycs = 4; + cycs = 6; + } else if (m == i_MOVE) { + if (isreg(g_instr->smode)) { + ecycs += 2; + } + } else if (m == i_CMP && s == sz_long) { + ecycs -= 2; + } + + if (cycs > 0 || ecycs > 0) { + printf("\t} else {\n"); + printf("\t\tloop_mode = 0;\n"); + if (cycs > 0) { + printf("\t\tloop_mode |= %d;\n", cycs); + } + if (ecycs > 0) { + printf("\t\tloop_mode |= %d << 16;\n", ecycs); + } + } + printf("\t}\n"); + loopmode_set = 1; } - printf("\t}\n"); } } @@ -2617,6 +2729,8 @@ static void genamode2x (amodes mode, const char *reg, wordsizes size, const char genamode_cnt++; } + loopmode_access(); + start_brace (); switch (mode) { @@ -2684,6 +2798,9 @@ static void genamode2x (amodes mode, const char *reg, wordsizes size, const char printf("\tuaecptr %sa;\n", name); add_mmu040_movem (movem); printf("\t%sa = m68k_areg(regs, %s);\n", name, reg); + if ((flags & GF_NOFETCH) && using_prefetch) { + addcycles000(2); + } break; case Aipi: // (An)+ switch (fetchmode) @@ -2697,6 +2814,9 @@ static void genamode2x (amodes mode, const char *reg, wordsizes size, const char printf("\tuaecptr %sa;\n", name); add_mmu040_movem (movem); printf("\t%sa = m68k_areg(regs, %s);\n", name, reg); + if ((flags & GF_NOFETCH) && using_prefetch) { + addcycles000(4); + } break; case Apdi: // -(An) switch (fetchmode) @@ -2724,7 +2844,13 @@ static void genamode2x (amodes mode, const char *reg, wordsizes size, const char default: term (); } - if (!(flags & GF_APDI)) { + if (flags & GF_NOFETCH) { + if (using_prefetch) { + addcycles000(4); + } + insn_n_cycles += 2; + count_cycles_ea += 2; + } else if (!(flags & GF_APDI)) { addcycles000 (2); insn_n_cycles += 2; count_cycles_ea += 2; @@ -2768,7 +2894,7 @@ static void genamode2x (amodes mode, const char *reg, wordsizes size, const char insn_n_cycles += 4; printf("\t%sa = %s(m68k_areg(regs, %s), %d);\n", name, disp020, reg, disp020cnt++); } else { - if (!(flags & GF_AD8R)) { + if (!(flags & GF_AD8R) && !(flags & GF_NOFETCH) && !(flags & GF_CLR68010)) { addcycles000 (2); insn_n_cycles += 2; count_cycles_ea += 2; @@ -2780,6 +2906,16 @@ static void genamode2x (amodes mode, const char *reg, wordsizes size, const char } count_read_ea++; } + if ((flags & GF_NOFETCH) && using_prefetch) { + addcycles000(4); + insn_n_cycles += 4; + count_cycles_ea += 4; + } + if ((flags & GF_CLR68010) && using_prefetch) { + addcycles000(4); + insn_n_cycles += 4; + count_cycles_ea += 4; + } addr = true; break; case PC8r: // (d8,PC,Xn) @@ -2817,6 +2953,9 @@ static void genamode2x (amodes mode, const char *reg, wordsizes size, const char printf("\t%sa = %s(tmppc, %s);\n", name, disp000, gen_nextiword (flags)); } } + if ((flags & GF_NOFETCH) && using_prefetch) { + addcycles000(4); + } addr = true; break; case absw: @@ -3123,14 +3262,16 @@ static void genamode2x (amodes mode, const char *reg, wordsizes size, const char switch (size) { case sz_byte: { - insn_n_cycles += 4; printf("\tuae_s8 %s = %s(%sa);\n", name, srcbx, name); + insn_n_cycles += 4; + printf("\tuae_s8 %s = %s(%sa);\n", name, srcbx, name); count_read++; check_bus_error(name, 0, 0, 0, NULL, 1); break; } case sz_word: { - insn_n_cycles += 4; printf("\tuae_s16 %s = %s(%sa);\n", name, srcwx, name); + insn_n_cycles += 4; + printf("\tuae_s16 %s = %s(%sa);\n", name, srcwx, name); count_read++; check_bus_error(name, 0, 0, 1, NULL, 1); break; @@ -3142,14 +3283,14 @@ static void genamode2x (amodes mode, const char *reg, wordsizes size, const char printf("\tuae_s32 %s = %s(%sa + 2);\n", name, srcwx, name); count_read++; check_bus_error(name, 0, 0, 1, NULL, 1); - printf("\t%s |= %s(%sa) << 16; \n", name, srcw, name); + printf("\t%s |= %s(%sa) << 16; \n", name, srcwx, name); count_read++; check_bus_error(name, -2, 0, 1, NULL, 1); } else { printf("\tuae_s32 %s = %s(%sa) << 16;\n", name, srcwx, name); count_read++; check_bus_error(name, 0, 0, 1, NULL, 1); - printf("\t%s |= %s(%sa + 2); \n", name, srcw, name); + printf("\t%s |= %s(%sa + 2); \n", name, srcwx, name); count_read++; check_bus_error(name, 2, 0, 1, NULL, 1); } @@ -3310,6 +3451,9 @@ static void genastore_2 (const char *from, amodes mode, const char *reg, wordsiz if (strcmp (rmw_varname, to) != 0) candormw = false; } + + loopmode_access(); + genastore_done = true; if (!(flags & GF_LRMW)) { returntail(mode != Dreg && mode != Areg); @@ -3439,7 +3583,7 @@ static void genastore_2 (const char *from, amodes mode, const char *reg, wordsiz if (flags & GF_SECONDWORDSETFLAGS) { genflags(flag_logical, g_instr->size, "src", "", ""); } - printf("%s(%sa, %s >> 16);\n", dstwx, to, from); + printf("\t%s(%sa, %s >> 16);\n", dstwx, to, from); sprintf(tmp, "%s >> 16", from); count_write++; check_bus_error(to, 0, 1, 1, tmp, 1); @@ -4621,6 +4765,7 @@ static void gen_opcode (unsigned int opcode) if (curi->mnemo == i_DBcc || loopmode) { next_level_000(); } + loopmode_start(); } // do not unnecessarily create useless mmuop030 @@ -4677,10 +4822,14 @@ static void gen_opcode (unsigned int opcode) if (cpu_level == 0) { c += 2; } + if (cpu_level == 1 && curi->smode == immi) { + c += 2; + } fill_prefetch_next_after(1, "\t\tccr_68000_long_move_ae_LZN(src);\n\t\tdreg_68000_long_replace_low(dstreg, src);\n"); } else { fill_prefetch_next_after(1, "\t\tdreg_68000_long_replace_low(dstreg, src);\n"); } + loopmodeextra = 4; } else { fill_prefetch_next_after(0, "\t\tccr_68000_long_move_ae_LZN(src);\n"); } @@ -4695,6 +4844,7 @@ static void gen_opcode (unsigned int opcode) fill_prefetch_next_after(1, NULL); } else { fill_prefetch_next_t(); + loopmodeextra = 4; } if (c > 0) addcycles000(c); @@ -4741,6 +4891,9 @@ static void gen_opcode (unsigned int opcode) if (cpu_level == 0) { c += 2; } + if (cpu_level == 1 && curi->smode == immi) { + c += 2; + } fill_prefetch_next_after(1, "\t\tuae_s16 bnewv = (uae_s16)dst - (uae_s16)src;\n" "\t\tint bflgs = ((uae_s16)(src)) < 0;\n" @@ -4754,6 +4907,7 @@ static void gen_opcode (unsigned int opcode) } else { fill_prefetch_next_after(1, "\t\tdreg_68000_long_replace_low(dstreg, newv);\n"); } + loopmodeextra = 4; } else { fill_prefetch_next_after(0, "\t\tuae_s16 bnewv = (uae_s16)dst - (uae_s16)src;\n" @@ -4776,6 +4930,7 @@ static void gen_opcode (unsigned int opcode) fill_prefetch_next_after(1, NULL); } else { fill_prefetch_next_t(); + loopmodeextra = 4; } if (c > 0) addcycles000(c); @@ -4797,12 +4952,15 @@ static void gen_opcode (unsigned int opcode) c += 4; } else { c = curi->size == sz_long ? 2 : 4; - if (islongimm (curi)) + if (islongimm(curi)) { c += 2; + } + loopmodeextra = curi->size == sz_long ? 4 : 2; } fill_prefetch_next_after(0, "\t\tareg_68000_long_replace_low(dstreg, newv);\n"); - if (c > 0) - addcycles000 (c); + if (c > 0) { + addcycles000(c); + } genastore ("newv", curi->dmode, "dstreg", sz_long, "dst"); break; } @@ -4912,6 +5070,10 @@ static void gen_opcode (unsigned int opcode) if (cpu_level == 0) { c += 2; } + if (cpu_level == 1 && curi->smode == immi) { + // 68010 Immediate long instructions 2 cycles faster, Q variants have same speed. + c += 2; + } fill_prefetch_next_after(1, "\t\tuae_s16 bnewv = (uae_s16)dst + (uae_s16)src;\n" "\t\tint bflgs = ((uae_s16)(src)) < 0;\n" @@ -4925,6 +5087,7 @@ static void gen_opcode (unsigned int opcode) } else { fill_prefetch_next_after(1, "\t\tdreg_68000_long_replace_low(dstreg, newv);\n"); } + loopmodeextra = 4; } else { fill_prefetch_next_after(0, "\t\tuae_s16 bnewv = (uae_s16)dst + (uae_s16)src;\n" @@ -4947,6 +5110,7 @@ static void gen_opcode (unsigned int opcode) fill_prefetch_next_after(1, NULL); } else { fill_prefetch_next_t(); + loopmodeextra = 4; } if (c > 0) addcycles000(c); @@ -4968,12 +5132,15 @@ static void gen_opcode (unsigned int opcode) c += 4; } else { c = curi->size == sz_long ? 2 : 4; - if (islongimm (curi)) + if (islongimm(curi)) { c += 2; + } + loopmodeextra = curi->size == sz_long ? 4 : 2; } fill_prefetch_next_after(1, "\t\tareg_68000_long_replace_low(dstreg, newv);\n"); - if (c > 0) - addcycles000 (c); + if (c > 0) { + addcycles000(c); + } genastore("newv", curi->dmode, "dstreg", sz_long, "dst"); break; } @@ -5221,9 +5388,10 @@ static void gen_opcode (unsigned int opcode) genastore_rev("0", curi->smode, "srcreg", curi->size, "src"); } } else if (cpu_level == 1) { - genamode(curi, curi->smode, "srcreg", curi->size, "src", 3, 0, 0); - if (isreg(curi->smode) && curi->size == sz_long) + genamode(curi, curi->smode, "srcreg", curi->size, "src", 3, 0, GF_CLR68010); + if (isreg(curi->smode) && curi->size == sz_long) { addcycles000(2); + } if (!isreg(curi->smode) && using_exception_3 && curi->size != sz_byte && (using_prefetch || using_ce)) { printf("\tif(srca & 1) {\n"); if (curi->size == sz_word) { @@ -5344,8 +5512,16 @@ static void gen_opcode (unsigned int opcode) } bsetcycles(curi); // bclr needs 1 extra cycle - if (curi->mnemo == i_BCLR && curi->dmode == Dreg) - addcycles000 (2); + if (curi->mnemo == i_BCLR && curi->dmode == Dreg) { + addcycles000(2); + } + if (curi->mnemo == i_BCLR && curi->size == sz_byte) { + if (cpu_level == 1) { + // 68010 BCLR.B is 2 cycles slower + addcycles000(2); + } + next_level_000(); + } if (curi->mnemo == i_BCHG) { printf("\tdst ^= (1 << src);\n"); printf("\tSET_ZFLG(((uae_u32)dst & (1 << src)) >> src);\n"); @@ -5397,7 +5573,7 @@ static void gen_opcode (unsigned int opcode) /* The next two are coded a little unconventional, but they are doing * weird things... */ case i_MVPRM: // MOVEP R->M - genamode (curi, curi->smode, "srcreg", curi->size, "src", 1, 0, 0); + genamode (curi, curi->smode, "srcreg", curi->size, "src", 1, 0, cpu_level == 1 ? GF_NOFETCH : 0); printf("\tuaecptr mempa = m68k_areg(regs, dstreg) + (uae_s32)(uae_s16)%s;\n", gen_nextiword (0)); check_prefetch_buserror(m68k_pc_offset); if (curi->size == sz_word) { @@ -5426,7 +5602,7 @@ static void gen_opcode (unsigned int opcode) case i_MVPMR: // MOVEP M->R printf("\tuaecptr mempa = m68k_areg(regs, srcreg) + (uae_s32)(uae_s16)%s;\n", gen_nextiword (0)); check_prefetch_buserror(m68k_pc_offset); - genamode (curi, curi->dmode, "dstreg", curi->size, "dst", 2, 0, 0); + genamode (curi, curi->dmode, "dstreg", curi->size, "dst", 2, 0, cpu_level == 1 ? GF_NOFETCH : 0); if (curi->size == sz_word) { printf("\tuae_u16 val = (%s(mempa) & 0xff) << 8;\n", srcb); count_read++; @@ -5683,7 +5859,8 @@ static void gen_opcode (unsigned int opcode) } break; case i_MVSR2: // MOVE FROM SR - genamode (curi, curi->smode, "srcreg", sz_word, "src", cpu_level == 0 ? 2 : 3, 0, 0); + next_level_000(); + genamode (curi, curi->smode, "srcreg", sz_word, "src", cpu_level == 0 ? 2 : 3, 0, cpu_level == 1 ? GF_NOFETCH : 0); printf("\tMakeSR();\n"); if (isreg (curi->smode)) { if (cpu_level == 0 && curi->size == sz_word) { @@ -5693,7 +5870,9 @@ static void gen_opcode (unsigned int opcode) } else { fill_prefetch_next_after(1, NULL); } - addcycles000 (2); + if (cpu_level == 0) { + addcycles000(2); + } } else { // 68000: read first and ignore result if (cpu_level == 0 && curi->size == sz_word) { @@ -5798,14 +5977,22 @@ static void gen_opcode (unsigned int opcode) clear_m68k_offset(); break; case i_MVR2USP: + next_level_000(); genamode(curi, curi->smode, "srcreg", curi->size, "src", 1, 0, 0); printf("\tregs.usp = src;\n"); + if (cpu_level == 1) { + addcycles000(2); + } fill_prefetch_next_t(); trace_t0_68040_only(); break; case i_MVUSP2R: + next_level_000(); genamode(curi, curi->smode, "srcreg", curi->size, "src", 2, 0, 0); genastore("regs.usp", curi->smode, "srcreg", curi->size, "src"); + if (cpu_level == 1) { + addcycles000(2); + } fill_prefetch_next_t(); break; case i_RESET: @@ -5907,8 +6094,16 @@ static void gen_opcode (unsigned int opcode) // 68010 int old_brace_level = n_braces; printf("\tuaecptr oldpc = %s;\n", getpc); - printf("\tuae_u16 newsr; uae_u32 newpc;\n"); + printf("\tuae_u16 newsr;\n"); + printf("\tuae_u32 newpc;\n"); printf("\tuaecptr a = m68k_areg(regs, 7);\n"); + printf("\tuae_u16 sr = %s(a);\n", srcw); + count_read++; + check_bus_error("", 0, 0, 1, NULL, 1); + printf("\tuae_u32 pc = %s(a + 2) << 16;\n", srcw); + count_read++; + check_bus_error("", 2, 0, 1, NULL, 1); + printf("\tuae_u16 format = %s(a + 2 + 4);\n", srcw); count_read++; check_bus_error("", 6, 0, 1, NULL, 1); @@ -5925,12 +6120,7 @@ static void gen_opcode (unsigned int opcode) printf("\t\tException_cpu(14);\n"); write_return_cycles("\t\t", 0); printf("\t}\n"); - printf("\tuae_u16 sr = %s(a);\n", srcw); - count_read++; - check_bus_error("", 0, 0, 1, NULL, 1); - printf("\tuae_u32 pc = %s(a + 2) << 16;\n", srcw); - count_read++; - check_bus_error("", 2, 0, 1, NULL, 1); + printf("\tpc |= %s(a + 4); \n", srcw); count_read++; check_bus_error("", 4, 0, 1, NULL, 1); @@ -6066,7 +6256,7 @@ static void gen_opcode (unsigned int opcode) printf("\tm68k_areg(regs, 7) += offs;\n"); } else { genamode (NULL, Aipi, "7", sz_long, "pc", 1, 0, 0); - genamode (curi, curi->smode, "srcreg", curi->size, "offs", 1, 0, 0); + genamode (curi, curi->smode, "srcreg", curi->size, "offs", 1, 0, GF_NOREFILL); printf("\tm68k_areg(regs, 7) += offs;\n"); } printf("\tif (pc & 1) {\n"); @@ -6209,31 +6399,49 @@ static void gen_opcode (unsigned int opcode) break; case i_TRAPV: sync_m68k_pc(); - // TRAPV is really weird - // If V is set but prefetch causes bus error: S is set. - // for some reason T is also cleared! - if (using_prefetch) { - printf("\tuae_u16 opcode_v = opcode;\n"); - } - fill_prefetch_next_after(1, - "\t\tif (GET_VFLG()) {\n" - "\t\t\tMakeSR();\n" - "\t\t\tregs.sr |= 0x2000;\n" - "\t\t\tregs.sr &= ~0x8000;\n" - "\t\t\tMakeFromSR();\n" - "\t\t} else {\n" - "\t\t\topcode = regs.ir | 0x20000;\n" - "\t\t\tif(regs.t1) opcode |= 0x10000;\n" - "\t\t}\n"); - printf("\tif (GET_VFLG()) {\n"); - if (using_prefetch) { - // If exception vector is odd, - // stacked opcode is TRAPV - printf("\t\tregs.ir = opcode_v;\n"); + next_level_000(); + if (cpu_level == 0) { + // 68000 TRAPV is really weird + // If V is set but prefetch causes bus error: S is set. + // for some reason T is also cleared! + if (using_prefetch) { + printf("\tuae_u16 opcode_v = opcode;\n"); + } + fill_prefetch_next_after(1, + "\t\tif (GET_VFLG()) {\n" + "\t\t\tMakeSR();\n" + "\t\t\tregs.sr |= 0x2000;\n" + "\t\t\tregs.sr &= ~0x8000;\n" + "\t\t\tMakeFromSR();\n" + "\t\t} else {\n" + "\t\t\topcode = regs.ir | 0x20000;\n" + "\t\t\tif(regs.t1) opcode |= 0x10000;\n" + "\t\t}\n"); + printf("\tif (GET_VFLG()) {\n"); + if (using_prefetch) { + // If exception vector is odd, + // stacked opcode is TRAPV + printf("\t\tregs.ir = opcode_v;\n"); + } + printf("\t\tException_cpu(7);\n"); + write_return_cycles("\t\t", 0); + printf("\t}\n"); + } else if (cpu_level == 1) { + push_ins_cnt(); + printf("\tif (GET_VFLG()) {\n"); + addcycles000(2); + printf("\t\tException_cpu(7);\n"); + write_return_cycles("\t\t", 0); + printf("\t}\n"); + pop_ins_cnt(); + fill_prefetch_next(); + } else { + fill_prefetch_next(); + printf("\tif (GET_VFLG()) {\n"); + printf("\t\tException_cpu(7);\n"); + write_return_cycles("\t\t", 0); + printf("\t}\n"); } - printf("\t\tException_cpu(7);\n"); - write_return_cycles("\t\t", 0); - printf("\t}\n"); break; case i_RTR: printf("\tuaecptr oldpc = %s;\n", getpc); @@ -6619,10 +6827,12 @@ bccl_not68020: curi->smode, "srcreg", curi->size, "src", 1, GF_AA | (cpu_level < 2 ? GF_NOREFILL : 0), curi->dmode, "dstreg", curi->size, "offs", 1, GF_AA | (cpu_level < 2 ? GF_NOREFILL : 0)); if (cpu_level == 1) { - printf("\tregs.loop_mode = false;\n"); + printf("\tint was_loop_mode = regs.loop_mode;\n"); + printf("\tregs.loop_mode = 0;\n"); } printf("\tuaecptr oldpc = %s;\n", getpc); - addcycles000 (2); + addcycles000(2); + addcycles000_nonce("\t", 2); if (using_exception_3 && cpu_level >= 4) { printf("\tif (offs & 1) {\n"); printf("\t\t\texception3i(opcode, oldpc + (uae_s32)offs + 2);\n"); @@ -6650,35 +6860,73 @@ bccl_not68020: // 68010 loop mode handling if (cpu_level == 1) { printf("\t\tif(offs == -4 && !regs.t1 && loop_mode_table[regs.ird]) {\n"); - printf("\t\t\tregs.loop_mode = true;\n"); + // first loop takes as many cycles as normal DBcc branch + // perhaps it also does actual prefetches?? + printf("\t\t\tif(!was_loop_mode) {\n"); + addcycles000(6); + addcycles000_nonce("\t\t", 6); + printf("\t\t\t}\n"); + printf("\t\t\tregs.loop_mode = 1;\n"); printf("\t\t\tsrc = m68k_dreg(regs, srcreg);\n"); genastore("(src - 1)", curi->smode, "srcreg", curi->size, "src"); addcycles000(2); + addcycles000_nonce("\t\t", 2); printf("\t\t\tif (src) {\n"); if (using_ce) { printf("\t\t\t\tloop_mode_table[regs.ird](regs.ird);\n"); } else { printf("\t\t\t\tcount_cycles += loop_mode_table[regs.ird](regs.ird);\n"); } + + printf("\t // quick exit if condition false and count expired\n"); + printf("\t\t\t\tif (!cctrue(%d) && (m68k_dreg(regs, srcreg) & 0xffff) == 0) {\n", curi->cc); + printf("\t\t\t\t\tm68k_dreg(regs, srcreg) |= 0xffff;\n"); + + printf("\t // loop exit: add possible extra cycle(s)\n"); + printf("\t\t\t\t\tif(regs.loop_mode >> 16) {\n"); + if (using_ce) { + printf("\t\t\t\t\t\t%s(regs.loop_mode >> 16);\n", do_cycles); + } + addcycles000_nonces("\t\t\t\t\t\t", "regs.loop_mode >> 16"); + printf("\t\t\t\t\t}\n"); + + printf("\t\t\t\t\tregs.loop_mode = 0;\n"); + setpc("oldpc + %d", m68k_pc_offset); + int old_m68k_pc_offset = m68k_pc_offset; + int old_m68k_pc_total = m68k_pc_total; + clear_m68k_offset(); + get_prefetch_020_continue(); + fill_prefetch_full_000_special(); + returncycles("\t\t\t", 8); + m68k_pc_offset = old_m68k_pc_offset; + m68k_pc_total = old_m68k_pc_total; + printf("\t\t\t\t}\n"); + + printf("\t // loop continue: add possible extra cycle(s)\n"); + printf("\t\t\t\tif(regs.loop_mode & 0xfffe) {\n"); + addcycles000_nonces("\t\t\t\t\t", "regs.loop_mode & 0xfffe"); + if (using_ce) { + printf("\t\t\t\t\t%s(regs.loop_mode & 0xfffe);\n", do_cycles); + } + printf("\t\t\t\t}\n"); + setpc("oldpc"); check_ipl(); - addcycles000(2); - returncycles("\t\t\t\t", 4); - printf("\t\t\t} else {\n"); - addcycles000(2); + returncycles("\t\t\t\t", 0); printf("\t\t\t}\n"); - printf("\t\t\tregs.loop_mode = false;\n"); + printf("\t\t\tregs.loop_mode = 0;\n"); setpc("oldpc + %d", m68k_pc_offset); fill_prefetch_full_000_special(); - returncycles("\t\t\t", 6); + returncycles("\t\t\t", 8); printf("\t\t}\n"); } printf("\t"); fill_prefetch_1(0); printf("\t"); - if (cpu_level < 2 || cpu_level >= 4) - genastore ("(src - 1)", curi->smode, "srcreg", curi->size, "src"); + if (cpu_level < 2 || cpu_level >= 4) { + genastore("(src - 1)", curi->smode, "srcreg", curi->size, "src"); + } printf("\t\tif (src) {\n"); irc2ir (); add_head_cycs (6); @@ -6723,9 +6971,8 @@ bccl_not68020: next_level_040_to_030(); break; case i_Scc: - // confirmed next_level_000(); - genamode(curi, curi->smode, "srcreg", curi->size, "src", cpu_level == 0 ? 1 : 2, 0, 0); + genamode(curi, curi->smode, "srcreg", curi->size, "src", cpu_level == 0 ? 1 : 2, 0, cpu_level == 1 ? GF_NOFETCH : 0); if (isreg(curi->smode)) { // If mode is Dn and condition true = 2 extra cycles needed. printf("\tint val = cctrue(%d) ? 0xff : 0x00;\n", curi->cc); @@ -7235,6 +7482,7 @@ bccl_not68020: printf("\tSET_CFLG (cflg);\n"); duplicate_carry (0); genastore ("val", curi->smode, "srcreg", curi->size, "data"); + loopmodeextra = 2; break; case i_ASLW: genamode (curi, curi->smode, "srcreg", curi->size, "data", 1, 0, GF_RMW); @@ -7254,6 +7502,7 @@ bccl_not68020: duplicate_carry (0); printf("\tSET_VFLG (GET_VFLG () | (sign2 != sign));\n"); genastore ("val", curi->smode, "srcreg", curi->size, "data"); + loopmodeextra = 2; break; case i_LSRW: genamode (curi, curi->smode, "srcreg", curi->size, "data", 1, 0, GF_RMW); @@ -7270,6 +7519,7 @@ bccl_not68020: printf("\tSET_CFLG (carry);\n"); duplicate_carry (0); genastore ("val", curi->smode, "srcreg", curi->size, "data"); + loopmodeextra = 2; break; case i_LSLW: genamode (curi, curi->smode, "srcreg", curi->size, "data", 1, 0, GF_RMW); @@ -7286,6 +7536,7 @@ bccl_not68020: printf("\tSET_CFLG (carry >> %d);\n", bit_size (curi->size) - 1); duplicate_carry (0); genastore ("val", curi->smode, "srcreg", curi->size, "data"); + loopmodeextra = 2; break; case i_ROLW: genamode (curi, curi->smode, "srcreg", curi->size, "data", 1, 0, GF_RMW); @@ -7302,6 +7553,7 @@ bccl_not68020: genflags (flag_logical, curi->size, "val", "", ""); printf("\tSET_CFLG (carry >> %d);\n", bit_size (curi->size) - 1); genastore ("val", curi->smode, "srcreg", curi->size, "data"); + loopmodeextra = 2; break; case i_RORW: genamode (curi, curi->smode, "srcreg", curi->size, "data", 1, 0, GF_RMW); @@ -7318,6 +7570,7 @@ bccl_not68020: genflags (flag_logical, curi->size, "val", "", ""); printf("\tSET_CFLG (carry);\n"); genastore ("val", curi->smode, "srcreg", curi->size, "data"); + loopmodeextra = 2; break; case i_ROXLW: genamode (curi, curi->smode, "srcreg", curi->size, "data", 1, 0, GF_RMW); @@ -7335,6 +7588,7 @@ bccl_not68020: printf("\tSET_CFLG (carry >> %d);\n", bit_size (curi->size) - 1); duplicate_carry (0); genastore ("val", curi->smode, "srcreg", curi->size, "data"); + loopmodeextra = 2; break; case i_ROXRW: genamode (curi, curi->smode, "srcreg", curi->size, "data", 1, 0, GF_RMW); @@ -7352,29 +7606,40 @@ bccl_not68020: printf("\tSET_CFLG (carry);\n"); duplicate_carry (0); genastore ("val", curi->smode, "srcreg", curi->size, "data"); + loopmodeextra = 2; break; case i_MOVEC2: - genamode (curi, curi->smode, "srcreg", curi->size, "src", 1, 0, 0); - fill_prefetch_next (); - start_brace (); + if (cpu_level == 1) { + printf("\tif(!regs.s) {\n"); + printf("\t\tException(8);\n"); + write_return_cycles_none("\t\t"); + printf("\t}\n"); + } + genamode(curi, curi->smode, "srcreg", curi->size, "src", 1, 0, 0); + fill_prefetch_next(); printf("\tint regno = (src >> 12) & 15;\n"); printf("\tuae_u32 *regp = regs.regs + regno;\n"); printf("\tif (!m68k_movec2(src & 0xFFF, regp)) {\n"); write_return_cycles("\t\t", 0); printf("\t}\n"); - addcycles000(2); + addcycles000(4); trace_t0_68040_only(); break; case i_MOVE2C: + if (cpu_level == 1) { + printf("\tif(!regs.s) {\n"); + printf("\t\tException(8);\n"); + write_return_cycles_none("\t\t"); + printf("\t}\n"); + } genamode (curi, curi->smode, "srcreg", curi->size, "src", 1, 0, 0); fill_prefetch_next (); - start_brace (); printf("\tint regno = (src >> 12) & 15;\n"); printf("\tuae_u32 *regp = regs.regs + regno;\n"); printf("\tif (!m68k_move2c(src & 0xFFF, regp)) {\n"); write_return_cycles("\t\t", 0); printf("\t}\n"); - addcycles000(4); + addcycles000(2); trace_t0_68040_only(); break; case i_CAS: @@ -7477,37 +7742,35 @@ bccl_not68020: break; case i_MOVES: /* ignore DFC and SFC when using_mmu == false */ { - int old_brace_level; tail_ce020_done = true; genamode (curi, curi->smode, "srcreg", curi->size, "extra", 1, 0, 0); + strcpy(g_srcname, "src"); + addcycles000(4); printf("if (extra & 0x800) {\n"); { + int srcdone = 0; int old_m68k_pc_offset = m68k_pc_offset; int old_m68k_pc_total = m68k_pc_total; - old_brace_level = n_braces; - start_brace (); - // 68060 stores original value - if (cpu_level == 5) { - printf("\tuae_u32 src = regs.regs[(extra >> 12) & 15];\n"); - } - genamode (curi, curi->dmode, "dstreg", curi->size, "dst", 2, 0, 0); + push_ins_cnt(); + // 68060 stores original value, 68010 MOVES.L also stores original value. + printf("\tuae_u32 src = regs.regs[(extra >> 12) & 15];\n"); + genamode (curi, curi->dmode, "dstreg", curi->size, "dst", 2, 0, cpu_level == 1 ? GF_NOFETCH : 0); tail_ce020_done = false; returntail(false); did_prefetch = 0; // Earlier models do -(an)/(an)+ EA calculation first - if (cpu_level <= 4) { - printf("\tuae_u32 src = regs.regs[(extra >> 12) & 15];\n"); + if (!(cpu_level == 5 || (curi->dmode != Aipi && curi->dmode != Apdi) || (cpu_level == 1 && curi->size == sz_long))) { + printf("\tsrc = regs.regs[(extra >> 12) & 15];\n"); } genastore_fc ("src", curi->dmode, "dstreg", curi->size, "dst"); sync_m68k_pc(); - pop_braces(old_brace_level); + pop_ins_cnt(); m68k_pc_offset = old_m68k_pc_offset; m68k_pc_total = old_m68k_pc_total; } printf("} else {\n"); { - start_brace(); - genamode(curi, curi->dmode, "dstreg", curi->size, "src", 1, 0, GF_FC); + genamode(curi, curi->dmode, "dstreg", curi->size, "src", 1, 0, GF_FC | (cpu_level == 1 ? GF_NOFETCH : 0)); printf("\tif (extra & 0x8000) {\n"); switch (curi->size) { case sz_byte: printf("\tm68k_areg(regs, (extra >> 12) & 7) = (uae_s32)(uae_s8)src;\n"); break; @@ -7521,14 +7784,16 @@ bccl_not68020: sync_m68k_pc(); tail_ce020_done = false; returntail(false); - pop_braces(old_brace_level); } printf("}\n"); trace_t0_68040_only(); + fill_prefetch_next(); + next_level_060_to_040(); } break; case i_BKPT: /* only needed for hardware emulators */ sync_m68k_pc (); + addcycles000(4); printf("\top_illg (opcode);\n"); did_prefetch = -1; break; @@ -7930,6 +8195,13 @@ bccl_not68020: break; } end: + if (loopmode && loopmodeextra) { + printf("\tif (loop_mode) {\n"); + addcycles000_onlyce(loopmodeextra); + addcycles000_nonce("\t\t", loopmodeextra); + printf("\t}\n"); + } + loopmode_stop(); if (!genastore_done) returntail (0); finish_braces (); diff --git a/include/newcpu.h b/include/newcpu.h index abbb0877..216b346c 100644 --- a/include/newcpu.h +++ b/include/newcpu.h @@ -185,7 +185,7 @@ struct regstruct uae_u32 chipset_latch_read; uae_u32 chipset_latch_write; uae_u16 db, write_buffer, read_buffer; - bool loop_mode; + int loop_mode; uaecptr usp, isp, msp; uae_u16 sr; diff --git a/newcpu.cpp b/newcpu.cpp index 90417152..e8f0dbb1 100644 --- a/newcpu.cpp +++ b/newcpu.cpp @@ -2487,7 +2487,7 @@ static void Exception_ce000 (int nr) start = 0; else if (nr >= 32 && nr < 32 + 16) // TRAP #x start = 4; - else if (nr == 4 || nr == 5 || nr == 6 || nr == 8 || nr == 9 || nr == 10 || nr == 11) // ILLG, DIVBYZERO, PRIV, TRACE, LINEA, LINEF + else if (nr == 4 || nr == 5 || nr == 6 || nr == 8 || nr == 9 || nr == 10 || nr == 11 || nr == 14) // ILLG, DIVBYZERO, PRIV, TRACE, LINEA, LINEF, RTE start = 4; } @@ -2794,17 +2794,16 @@ static void add_approximate_exception_cycles(int nr) { int cycles; - if (currprefs.cpu_model > 68000) - return; - if (nr >= 24 && nr <= 31) { - /* Interrupts */ - cycles = 44 + 4; - } else if (nr >= 32 && nr <= 47) { - /* Trap (total is 34, but cpuemux.c already adds 4) */ - cycles = 34 - 4; - } else { - switch (nr) - { + if (currprefs.cpu_model == 68000) { + if (nr >= 24 && nr <= 31) { + /* Interrupts */ + cycles = 44 + 4; + } else if (nr >= 32 && nr <= 47) { + /* Trap (total is 34, but cpuemux.c already adds 4) */ + cycles = 34 - 4; + } else { + switch (nr) + { case 2: cycles = 50; break; /* Bus error */ case 3: cycles = 50; break; /* Address error */ case 4: cycles = 34; break; /* Illegal instruction */ @@ -2816,9 +2815,38 @@ static void add_approximate_exception_cycles(int nr) case 10: cycles = 34; break; /* Line-A */ case 11: cycles = 34; break; /* Line-F */ default: - cycles = 4; - break; + cycles = 4; + break; + } } + } else if (currprefs.cpu_model == 68010) { + if (nr >= 24 && nr <= 31) { + /* Interrupts */ + cycles = 48 + 4; + } else if (nr >= 32 && nr <= 47) { + /* Trap */ + cycles = 38 - 4; + } else { + switch (nr) + { + case 2: cycles = 126; break; /* Bus error */ + case 3: cycles = 126; break; /* Address error */ + case 4: cycles = 38; break; /* Illegal instruction */ + case 5: cycles = 38; break; /* Division by zero */ + case 6: cycles = 38; break; /* CHK */ + case 7: cycles = 40; break; /* TRAPV */ + case 8: cycles = 38; break; /* Privilege violation */ + case 9: cycles = 38; break; /* Trace */ + case 10: cycles = 38; break; /* Line-A */ + case 11: cycles = 38; break; /* Line-F */ + case 14: cycles = 38; break; /* RTE frame error */ + default: + cycles = 4; + break; + } + } + } else { + return; } cycles = adjust_cycles(cycles * CYCLE_UNIT / 2); x_do_cycles(cycles); @@ -3006,6 +3034,7 @@ static void Exception_normal (int nr) x_put_word (m68k_areg (regs, 7), 0x1000 + vector_nr * 4); } } else { + add_approximate_exception_cycles(nr); Exception_build_stack_frame_common(oldpc, currpc, regs.mmu_ssw, nr); used_exception_build_stack_frame = true; } diff --git a/newcpu_common.cpp b/newcpu_common.cpp index d0b35e5b..42e7da93 100644 --- a/newcpu_common.cpp +++ b/newcpu_common.cpp @@ -646,12 +646,12 @@ int getMulu68kCycles(uae_u16 src) int cycles = 0; if (currprefs.cpu_model == 68000) { cycles = 38 - 4; + for (int bits = 0; bits < 16 && src; bits++, src >>= 1) { + if (src & 1) + cycles += 2; + } } else { - cycles = 8 - 4; - } - for (int bits = 0; bits < 16 && src; bits++, src >>= 1) { - if (src & 1) - cycles += 2; + cycles = 40 - 4; } return cycles; } @@ -661,14 +661,17 @@ int getMuls68kCycles(uae_u16 src) int cycles; if (currprefs.cpu_model == 68000) { cycles = 38 - 4; + uae_u32 usrc = ((uae_u32)src) << 1; + for (int bits = 0; bits < 16 && usrc; bits++, usrc >>= 1) { + if ((usrc & 3) == 1 || (usrc & 3) == 2) { + cycles += 2; + } + } } else { - cycles = 10 - 4; - } - uae_u32 usrc = ((uae_u32)src) << 1; - for (int bits = 0; bits < 16 && usrc; bits++, usrc >>= 1) { - if ((usrc & 3) == 1 || (usrc & 3) == 2) { + cycles = 40 - 4; + // 2 extra cycles added if source is negative + if (src & 0x8000) cycles += 2; - } } return cycles; } @@ -741,15 +744,18 @@ int getDivu68kCycles (uae_u32 dividend, uae_u16 divisor) if (divisor == 0) return 0; + if (currprefs.cpu_model == 68010) { + // Overflow + if ((dividend >> 16) >= divisor) + return 4; + return 104; + } + // Overflow if ((dividend >> 16) >= divisor) return (mcycles = 5) * 2 - 4; - if (currprefs.cpu_model == 68000) { - mcycles = 38; - } else { - mcycles = 22; - } + mcycles = 38; hdivisor = divisor << 16; @@ -783,6 +789,17 @@ int getDivs68kCycles (uae_s32 dividend, uae_s16 divisor) if (divisor == 0) return 0; + if (currprefs.cpu_model == 68010) { + // Check for absolute overflow + if (((uae_u32)abs(dividend) >> 16) >= (uae_u16)abs(divisor)) + return 12; + mcycles = 116; + // add 2 extra cycles if negative dividend + if (dividend < 0) + mcycles += 2; + return mcycles; + } + mcycles = 6; if (dividend < 0) @@ -795,11 +812,7 @@ int getDivs68kCycles (uae_s32 dividend, uae_s16 divisor) // Absolute quotient aquot = (uae_u32) abs (dividend) / (uae_u16)abs (divisor); - if (currprefs.cpu_model == 68000) { - mcycles += 55; - } else { - mcycles += 37; - } + mcycles += 55; if (divisor >= 0) { if (dividend >= 0) diff --git a/readcpu.cpp b/readcpu.cpp index 0498c34e..9891f5c2 100644 --- a/readcpu.cpp +++ b/readcpu.cpp @@ -909,8 +909,8 @@ bool opcode_loop_mode(uae_u16 opcode) (!c->duse || (isreg(c->smode) && !isreg(c->dmode)) || (!isreg(c->smode) && isreg(c->dmode)) || (!isreg(c->smode) && !isreg(c->dmode)))) { loopmode = true; } - if (c->mnemo == i_MOVE) { - // move x,dn: not supported + if (c->mnemo == i_MOVE || c->mnemo == i_MOVEA) { + // move x,reg: not supported if (isreg(c->dmode)) loopmode = false; // move reg,-(an): not supported diff --git a/table68k b/table68k index 57632d70..0ec4ffb6 100644 --- a/table68k +++ b/table68k @@ -129,7 +129,7 @@ 0000 1010 11ss sSSS:200:?????:?????:13: CAS.B #1,s[!Dreg,Areg,Immd,PC8r,PC16] 0000 1100 11ss sSSS:200:?????:?????:13: CAS.W #1,s[!Dreg,Areg,Immd,PC8r,PC16] 0000 1100 1111 1100:250:?????:?????:10: CAS2.W #2 -0000 1110 zzss sSSS:202:?????:?????:13: MOVES.z #1,s[!Dreg,Areg,Immd,PC8r,PC16] +0000 1110 zzss sSSS:102:?????:?????:13: MOVES.z #1,s[!Dreg,Areg,Immd,PC8r,PC16] 0000 1110 11ss sSSS:200:?????:?????:13: CAS.L #1,s[!Dreg,Areg,Immd,PC8r,PC16] 0000 1110 1111 1100:250:?????:?????:10: CAS2.L #2 @@ -197,7 +197,7 @@ 0100 1000 00dd dDDD:000:X?Z?C:X-Z--:30: NBCD.B d[!Areg] - 0 0 6 -0100 1000 0100 1kkk:200:?????:?????:10: BKPT #k +0100 1000 0100 1kkk:100:?????:?????:10: BKPT #k 0100 1000 01ss sSSS:000:-NZ00:-----:30: SWAP.W s[Dreg] - 4 0 4