From ec702151403226a05aa1c0d9c96ea4c937e01c6a Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Sat, 5 Oct 2019 14:32:59 +0300 Subject: [PATCH] CPU tester WIP 68000 bus error support. Misc updates and fixes. --- cputest.cpp | 101 ++++++++---- cputest/adis/decode_ea.c | 16 +- cputest/adis/globals.c | 10 +- cputest/adis/opcode_handler_cpu.c | 12 +- cputest/cputestgen.ini | 4 + cputest/main.c | 91 +++++------ gencpu.cpp | 262 ++++++++++++++++++++++++++---- include/newcpu.h | 5 +- ini.cpp | 2 + jit/exception_handler.cpp | 2 +- newcpu.cpp | 21 ++- newcpu_common.cpp | 16 +- 12 files changed, 397 insertions(+), 145 deletions(-) diff --git a/cputest.cpp b/cputest.cpp index 21cfeefb..34bbecd2 100644 --- a/cputest.cpp +++ b/cputest.cpp @@ -5,7 +5,6 @@ #include "disasm.h" #include "ini.h" #include "fpp.h" -#include "mmu_common.h" #include "options.h" @@ -42,6 +41,7 @@ int movem_index1[256]; int movem_index2[256]; int movem_next[256]; int bus_error_offset; +int cpu_bus_error; struct mmufixup mmufixup[2]; cpuop_func *cpufunctbl[65536]; @@ -66,6 +66,7 @@ static int feature_loop_mode_register = -1; static int feature_full_extension_format = 0; static int feature_test_rounds = 2; static int feature_flag_mode = 0; +static TCHAR *feature_instruction_size = NULL; static uae_u32 feature_addressing_modes[2]; static int ad8r[2], pc8r[2]; static int multi_mode; @@ -215,6 +216,11 @@ oob: return 0; } +static bool is_nowrite_address(uaecptr addr, int size) +{ + return addr + size >= safe_memory_start && addr < safe_memory_end; +} + static void validate_addr(uaecptr addr, int size) { if (valid_address(addr, size, 0)) @@ -265,11 +271,7 @@ static void check_bus_error(uaecptr addr, int write, int fc) if (safe_memory_start == 0xffffffff && safe_memory_end == 0xffffffff) return; if (addr >= safe_memory_start && addr < safe_memory_end) { - test_exception = 2; - test_exception_3_w = write; - test_exception_addr = addr; - test_exception_3_fc = fc; - THROW(2); + cpu_bus_error = 1; } } @@ -851,6 +853,27 @@ uae_u32 REGPARAM2 op_illg(uae_u32 opcode) return op_illg_1(opcode); } +void exception2_read(uae_u32 opcode, uaecptr addr, int fc) +{ + test_exception = 2; + test_exception_3_w = 0; + test_exception_addr = addr; + test_exception_opcode = opcode; + test_exception_3_fc = fc; + doexcstack(); +} + +void exception2_write(uae_u32 opcode, uaecptr addr, int fc) +{ + test_exception = 2; + test_exception_3_w = 1; + test_exception_addr = addr; + test_exception_opcode = opcode; + test_exception_3_fc = fc; + doexcstack(); +} + + void exception3_read(uae_u32 opcode, uae_u32 addr, int fc) { test_exception = 3; @@ -1691,7 +1714,7 @@ static int create_ea_exact(uae_u16 *opcodep, uaecptr pc, int mode, int reg, stru } case PC16: { - uae_u32 pct = opcode_memory_start + 2; + uae_u32 pct = pc + 2 - 2; if (target <= pct + 0x7ffe && target >= pct - 0x8000) { put_word_test(pc, target - pct); *eap = target; @@ -1729,7 +1752,7 @@ static int create_ea_exact(uae_u16 *opcodep, uaecptr pc, int mode, int reg, stru case PC8r: { for (int r = 0; r < 16; r++) { - uae_u32 aval = opcode_memory_start + 2; + uae_u32 aval = pc + 2 - 2; int rn = ((ea_exact_cnt >> 1) + r) & 15; for (int i = 0; i < 2; i++) { if ((ea_exact_cnt & 1) == 0 || i == 1) { @@ -2126,6 +2149,7 @@ static void execute_ins(uae_u16 opc, uaecptr endpc, uaecptr targetpc, struct ins test_memory_accessed = 0; testing_active = 1; testing_active_opcode = opc; + cpu_bus_error = 0; int cnt = feature_loop_mode * 2; if (multi_mode) @@ -2140,12 +2164,7 @@ static void execute_ins(uae_u16 opc, uaecptr endpc, uaecptr targetpc, struct ins uaecptr a7 = regs.regs[15]; int s = regs.s; - TRY (ex) { - (*cpufunctbl[opc])(opc); - } CATCH(ex) { - // got bus error - Exception(2); - } ENDTRY + (*cpufunctbl[opc])(opc); // Supervisor mode and A7 was modified: skip this test round. if (s && regs.regs[15] != a7) { @@ -2296,7 +2315,7 @@ static uae_u8 *save_exception(uae_u8 *p, struct instr *dp) // parse exception and store fields that are unique // SR and PC was already saved with non-exception data if (cpu_lvl == 0) { - if (test_exception == 3) { + if (test_exception == 2 || test_exception == 3) { // status *p++ = sf[1]; // opcode (which is not necessarily current opcode!) @@ -2844,7 +2863,9 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi continue; } else { // branch target = generate exception - put_word_test(srcaddr, 0x4afc); + if (!is_nowrite_address(srcaddr, 2)) { + put_word_test(srcaddr, 0x4afc); + } branch_target = srcaddr; dst = store_mem(dst, 1); memcpy(&ahist2, &ahist, sizeof(struct accesshistory) *MAX_ACCESSHIST); @@ -3215,24 +3236,30 @@ static void test_mnemo_text(const TCHAR *path, const TCHAR *mode) _tcscpy(modetxt, mode); my_trim(modetxt); TCHAR *s = _tcschr(modetxt, '.'); - if (s) { - *s = 0; - TCHAR c = _totlower(s[1]); - if (c == 'b') + if (s || feature_instruction_size != NULL) { + TCHAR c = 0; + if (s) { + *s = 0; + TCHAR c = _totlower(s[1]); + } + if (!c && feature_instruction_size) { + c = feature_instruction_size[0]; + } + if (c == 'b' || c == 'B') sizes = 6; - if (c == 'w') + if (c == 'w' || c == 'W') sizes = 4; - if (c == 'l') + if (c == 'l' || c == 'L') sizes = 0; - if (c == 'u') + if (c == 'u' || c == 'U') sizes = 8; - if (c == 's') + if (c == 's' || c == 'S') sizes = 1; - if (c == 'x') + if (c == 'x' || c == 'X') sizes = 2; - if (c == 'p') + if (c == 'p' || c == 'P') sizes = 3; - if (c == 'd') + if (c == 'd' || c == 'D') sizes = 5; } @@ -3349,7 +3376,7 @@ static const TCHAR *addrmodes[] = int __cdecl main(int argc, char *argv[]) { const struct cputbl *tbl = NULL; - TCHAR path[1000]; + TCHAR path[1000], *vs; int v; struct ini_data *ini = ini_load(_T("cputestgen.ini"), false); @@ -3400,12 +3427,13 @@ int __cdecl main(int argc, char *argv[]) feature_exception3_instruction = 0; ini_getval(ini, INISECTION, _T("feature_exception3_instruction"), &feature_exception3_instruction); - v = -1; - ini_getval(ini, INISECTION, _T("feature_target_src_ea"), &v); - feature_target_ea[0] = v; - v = -1; - ini_getval(ini, INISECTION, _T("feature_target_dst_ea"), &v); - feature_target_ea[1] = v; + feature_target_ea[0] = 0xffffffff; + if (ini_getval(ini, INISECTION, _T("feature_target_src_ea"), &v)) + feature_target_ea[0] = v; + feature_target_ea[1] = 0xffffffff; + if (ini_getval(ini, INISECTION, _T("feature_target_dst_ea"), &v)) + feature_target_ea[1] = v; + if (feature_target_ea[0] != 0xffffffff || feature_target_ea[1] != 0xffffffff) { if (feature_target_ea[0] & 1) { feature_exception3_data = 3; @@ -3510,6 +3538,11 @@ int __cdecl main(int argc, char *argv[]) feature_test_rounds = 2; ini_getval(ini, INISECTION, _T("test_rounds"), &feature_test_rounds); + feature_instruction_size = NULL; + ini_getstring(ini, INISECTION, _T("feature_instruction_size"), &feature_instruction_size); + + ini_getval(ini, INISECTION, _T("feature_instruction_size"), &feature_test_rounds); + v = 0; ini_getval(ini, INISECTION, _T("test_memory_start"), &v); if (!v) { diff --git a/cputest/adis/decode_ea.c b/cputest/adis/decode_ea.c index b44eb731..24874dda 100644 --- a/cputest/adis/decode_ea.c +++ b/cputest/adis/decode_ea.c @@ -152,13 +152,14 @@ switch (mode) else { UWORD size = (first_ext_w >> 9) & 0x3; - +#if 0 if (!cpu68020 && size != 0) /* Only size of 1 allowed for 68000 */ { instr_bad = TRUE; return (0); } - if (pass3) +#endif + if (pass3) { /* To get the sign right */ disp_an_indexed (to, (ushort)(reg + 8), @@ -267,22 +268,25 @@ switch (mode) /* long extension word */ if (cpu68020) return (full_extension (to, code + first_ext, mode, reg)); - else +#if 0 + else { instr_bad = TRUE; return (0); } - } +#endif + } else { UWORD size = (first_ext_w >> 9) & 0x3; - +#if 0 if (!cpu68020 && size != 0) /* Only size of 1 allowed for 68000 */ { instr_bad = TRUE; return (0); } - /* A neg displacement can make ref neg if out of bounds. */ +#endif + /* A neg displacement can make ref neg if out of bounds. */ ref = current_ref + ((ULONG)first_ext << 1) + (BYTE)first_ext_w; if (pass3) disp_pc_indexed (to, ref, (BYTE)first_ext_w, diff --git a/cputest/adis/globals.c b/cputest/adis/globals.c index 79d472f9..e8d53ca9 100644 --- a/cputest/adis/globals.c +++ b/cputest/adis/globals.c @@ -87,12 +87,12 @@ BOOL try_small = FALSE; /* -b */ BOOL single_file = TRUE; BOOL print_illegal_instr_offset = FALSE; /* -i */ BOOL old_style = FALSE; -BOOL cpu68020 = FALSE, /* -m2 */ - cpu68030 = FALSE, /* -m3 */ - cpu68040 = FALSE, /* -m4 */ - cpu68060 = FALSE, /* -m6 */ +BOOL cpu68020 = TRUE, /* -m2 */ + cpu68030 = TRUE, /* -m3 */ + cpu68040 = TRUE, /* -m4 */ + cpu68060 = TRUE, /* -m6 */ cpuCF = FALSE, - fpu68881 = FALSE; /* -m8 */ + fpu68881 = TRUE; /* -m8 */ BOOL disasm_as_lib = FALSE; /* -l */ BOOL ascending_label_numbers = FALSE; /* -dn */ BOOL verbose = FALSE; diff --git a/cputest/adis/opcode_handler_cpu.c b/cputest/adis/opcode_handler_cpu.c index 4afbc9f2..700b467b 100644 --- a/cputest/adis/opcode_handler_cpu.c +++ b/cputest/adis/opcode_handler_cpu.c @@ -172,6 +172,7 @@ uint imm_b (struct opcode_entry *op) { ULONG instr = *(ULONG*)code; +#if 0 if ((instr & 0xfc0000ff) == 0) /* if ori.b #0,ea or andi.b #0,ea */ { /* ori.b #0,ea and andi.b #0,ea are probably not code */ @@ -185,7 +186,7 @@ if (!((instr == 0) || (instr == 0x0000ff00))) /* GCC immediate may be $ffxx */ instr_bad = TRUE; return (1); } - +#endif if (pass3) { char *to; @@ -202,13 +203,14 @@ uint imm_w (struct opcode_entry *op) /* handler for ori.w andi.w eori.w subi.w addi.w cmpi.w */ { +#if 0 if ((*((ULONG*)code) & 0xfc00ffff) == 0) { /* ori.w #0,ea and andi.w #0,ea are probably not code */ instr_bad = TRUE; return (1); } - +#endif if (pass3) { char *to; @@ -227,13 +229,14 @@ uint imm_l (struct opcode_entry *op) { register ULONG instr_ext = *(ULONG*)(code + 1); +#if 0 if ((instr_ext == 0) && (*(code) & 0xfc00) == 0) { /* ori.l #0,ea and andi.l #0,ea are probably not code */ instr_bad = TRUE; return (1); } - +#endif if (pass2 && FLAGS_RELOC (current_ref + 2)) { enter_ref (instr_ext, NULL, ACC_UNKNOWN); @@ -291,13 +294,14 @@ uint bit_imm (struct opcode_entry *op) UWORD code_w = *code; UWORD data_w = *(code + 1); +#if 0 if ((data_w & 0xff00) != 0) { /* only bit #0-255 are valid */ instr_bad = TRUE; return (1); } - +#endif if (pass3) { char *to; diff --git a/cputest/cputestgen.ini b/cputest/cputestgen.ini index d048564d..903d48cc 100644 --- a/cputest/cputestgen.ini +++ b/cputest/cputestgen.ini @@ -104,6 +104,10 @@ feature_full_extension_format=0 feature_addressing_modes_src= feature_addressing_modes_dst= +; Limit test instruction size +; B = byte, W = word, L = long, empty = no size limit +feature_instruction_size= + ; mnemonics separated by comma or all/fall. ; all = generate all CPU tests. tst = generate tst.b, tst.w and tst.l. tst.l = generate only tst.l ; fall = generate all FPU tests. diff --git a/cputest/main.c b/cputest/main.c index 8a4e5443..0ba549e8 100644 --- a/cputest/main.c +++ b/cputest/main.c @@ -108,7 +108,8 @@ static uae_u8 ccr_mask; static uae_u32 addressing_mask = 0x00ffffff; static uae_u32 interrupt_mask; -#define SIZE_STORED_ADDRESS 20 +#define SIZE_STORED_ADDRESS_OFFSET 8 +#define SIZE_STORED_ADDRESS 16 static uae_u8 srcaddr[SIZE_STORED_ADDRESS]; static uae_u8 dstaddr[SIZE_STORED_ADDRESS]; static uae_u8 stackaddr[SIZE_STORED_ADDRESS]; @@ -351,40 +352,34 @@ static uae_u8 *load_file(const char *path, const char *file, uae_u8 *p, int *siz exit(0); } } - if (safe_memory_start == (uae_u8*)0xffffffff && safe_memory_end == (uae_u8*)0xffffffff) { - *sizep = fread(p, 1, size, f); - } else if (safe_memory_end < p || safe_memory_start >= p + size) { + if (safe_memory_end < p || safe_memory_start >= p + size) { *sizep = fread(p, 1, size, f); } else { - *sizep = size; - uae_u8 *pp = p; - while (size > 0) { - int size2 = size > sizeof(tmpbuffer) ? sizeof(tmpbuffer) : size; - if (p + size2 > safe_memory_start && p < safe_memory_end) { - if (fread(tmpbuffer, 1, size2, f) != size2) { - printf("Couldn't read file '%s' %ld\n", fname, size2); - exit(0); - } - uae_u8 *sp = tmpbuffer; - for (int i = 0; i < size2; i++) { - if (pp < safe_memory_start || pp >= safe_memory_end) { - *pp = *sp; - } - pp++; - sp++; - } - } else { - if (fread(p, 1, size2, f) != size2) { - printf("Couldn't read file '%s'\n", fname); - exit(0); - } - p += size2; - } + if (size > 0 && p < safe_memory_start) { + int size2 = safe_memory_start - p; + if (size2 > size) + size2 = size; + if (fread(p, 1, size2, f) != size2) + goto end; + p += size2; + size -= size2; + } + if (size > 0 && p >= safe_memory_start && p < safe_memory_end) { + int size2 = safe_memory_end - p; + if (size2 > size) + size2 = size; + fseek(f, size2, SEEK_CUR); + p += size2; size -= size2; } + if (size > 0) { + if (fread(p, 1, size, f) != size) + goto end; + } size = *sizep; } if (*sizep != size) { +end: printf("Couldn't read file '%s'\n", fname); exit(0); } @@ -811,7 +806,7 @@ static int addr_diff(uae_u8 *ap, uae_u8 *bp, int size) static void addinfo_bytes(char *name, uae_u8 *src, uae_u32 address, int offset, int len) { - sprintf(outbp, "%s: %08lx ", name, address); + sprintf(outbp, "%s %08lx ", name, address); address += offset; outbp += strlen(outbp); int cnt = 0; @@ -885,35 +880,25 @@ static void addinfo(void) } *outbp = 0; if (code[0] == 0x4e73 || code[0] == 0x4e74 || code[0] == 0x4e75) { - addinfo_bytes("SA", stackaddr, stackaddr_ptr, -SIZE_STORED_ADDRESS / 2, SIZE_STORED_ADDRESS); - addinfo_bytes(" ", (uae_u8 *)stackaddr_ptr - SIZE_STORED_ADDRESS / 2, stackaddr_ptr, -SIZE_STORED_ADDRESS / 2, SIZE_STORED_ADDRESS); + addinfo_bytes("P", stackaddr, stackaddr_ptr, -SIZE_STORED_ADDRESS_OFFSET, SIZE_STORED_ADDRESS); + addinfo_bytes(" ", (uae_u8 *)stackaddr_ptr - SIZE_STORED_ADDRESS_OFFSET, stackaddr_ptr, -SIZE_STORED_ADDRESS_OFFSET, SIZE_STORED_ADDRESS); } if (regs.srcaddr != 0xffffffff) { uae_u8 *a = srcaddr; - uae_u8 *b = (uae_u8 *)regs.srcaddr - SIZE_STORED_ADDRESS / 2; - addinfo_bytes("SA", a, regs.srcaddr, -SIZE_STORED_ADDRESS / 2, SIZE_STORED_ADDRESS); + uae_u8 *b = (uae_u8 *)regs.srcaddr - SIZE_STORED_ADDRESS_OFFSET; + addinfo_bytes("S", a, regs.srcaddr, -SIZE_STORED_ADDRESS_OFFSET, SIZE_STORED_ADDRESS); if (addr_diff(a, b, SIZE_STORED_ADDRESS)) { - addinfo_bytes(" ", b, regs.srcaddr, -SIZE_STORED_ADDRESS / 2, SIZE_STORED_ADDRESS); + addinfo_bytes(" ", b, regs.srcaddr, -SIZE_STORED_ADDRESS_OFFSET, SIZE_STORED_ADDRESS); } } if (regs.dstaddr != 0xffffffff) { uae_u8 *a = dstaddr; - uae_u8 *b = (uae_u8*)regs.dstaddr - SIZE_STORED_ADDRESS / 2; - addinfo_bytes("DA", a, regs.dstaddr, -SIZE_STORED_ADDRESS / 2, SIZE_STORED_ADDRESS); + uae_u8 *b = (uae_u8*)regs.dstaddr - SIZE_STORED_ADDRESS_OFFSET; + addinfo_bytes("D", a, regs.dstaddr, -SIZE_STORED_ADDRESS_OFFSET, SIZE_STORED_ADDRESS); if (addr_diff(a, b, SIZE_STORED_ADDRESS)) { - addinfo_bytes(" ", b, regs.dstaddr, -SIZE_STORED_ADDRESS / 2, SIZE_STORED_ADDRESS); + addinfo_bytes(" ", b, regs.dstaddr, -SIZE_STORED_ADDRESS_OFFSET, SIZE_STORED_ADDRESS); } } - -#if 0 -int Disass68k(long addr, char *labelBuffer, char *opcodeBuffer, char *operandBuffer, char *commentBuffer); -void Disasm_SetCPUType(int CPU, int FPU); - Disasm_SetCPUType(0, 0); - char buf1[80], buf2[80], buf3[80], buf4[80]; - Disass68k((long)opcode_memory, buf1, buf2, buf3, buf4); - sprintf(outbp, "%s %s\n", buf2, buf3); - outbp += strlen(outbp); -#endif } struct srbit @@ -1061,7 +1046,7 @@ static uae_u8 *validate_exception(struct registers *regs, uae_u8 *p, int excnum, exc = last_exception; if (excdatalen != 0xff) { if (cpu_lvl == 0) { - if (excnum == 3) { + if (excnum == 2 || excnum == 3) { // status (with undocumented opcode part) uae_u8 opcode0 = p[1]; uae_u8 opcode1 = p[2]; @@ -1496,8 +1481,8 @@ static void store_addr(uae_u32 s, uae_u8 *d) { if (s == 0xffffffff) return; - for (int i = -SIZE_STORED_ADDRESS / 2; i < SIZE_STORED_ADDRESS / 2; i++) { - uae_u32 ss = s + i; + for (int i = 0; i < SIZE_STORED_ADDRESS; i++) { + uae_u32 ss = s + (i - SIZE_STORED_ADDRESS_OFFSET); if (is_valid_test_addr(ss)) { *d++ = *((uae_u8 *)ss); } else { @@ -1940,10 +1925,7 @@ int main(int argc, char *argv[]) cpu_lvl = get_cpu_model(); -#endif - if (cpu_lvl == 5) { -#ifdef M68K // Overwrite MOVEC to/from MSP // with NOPs if 68060 extern void *msp_address1; @@ -1954,9 +1936,10 @@ int main(int argc, char *argv[]) *((uae_u32*)&msp_address2) = 0x4e714e71; *((uae_u32*)&msp_address3) = 0x4e714e71; *((uae_u32*)&msp_address4) = 0x4e714e71; -#endif } +#endif + if (argc < 2) { printf("cputest () (continue)\n"); printf("mnemonic = test single mnemonic\n"); diff --git a/gencpu.cpp b/gencpu.cpp index ddeb28a3..4ae77af4 100644 --- a/gencpu.cpp +++ b/gencpu.cpp @@ -177,6 +177,7 @@ static int genamode_cnt, genamode8r_offset[2]; static int n_braces, limit_braces; static int m68k_pc_offset, m68k_pc_offset_old; static int m68k_pc_total; +static int exception_pc_offset; static int branch_inst; static int insn_n_cycles, insn_n_cycles020; static int ir2irc; @@ -480,6 +481,31 @@ static void add_mmu040_movem (int movem) start_brace (); } +static char bus_error_text[200]; + +static void do_instruction_buserror(void) +{ + if (bus_error_text[0]) { + printf("\tif(cpu_bus_error) {\n"); + printf("%s", bus_error_text); + printf("\t\tgoto %s;\n", endlabelstr); + need_endlabel = 1; + printf("\t}\n"); + bus_error_text[0] = 0; + } +} + +static void check_bus_error_ins(int offset) +{ + sprintf(bus_error_text, "\t\texception2_read(opcode, m68k_getpci() + %d, 2);\n", offset); +} + +static void check_prefetch_bus_error(int offset) +{ + check_bus_error_ins(offset); + do_instruction_buserror(); +} + static void gen_nextilong2 (const char *type, const char *name, int flags, int movem) { int r = m68k_pc_offset; @@ -526,6 +552,7 @@ static void gen_nextilong2 (const char *type, const char *name, int flags, int m } static void gen_nextilong (const char *type, const char *name, int flags) { + bus_error_text[0] = 0; gen_nextilong2 (type, name, flags, 0); } @@ -535,6 +562,7 @@ static const char *gen_nextiword (int flags) int r = m68k_pc_offset; m68k_pc_offset += 2; + bus_error_text[0] = 0; if (using_ce020) { if (flags & GF_NOREFILL) sprintf(buffer, "%s (%d)", prefetch_word, r); @@ -547,6 +575,7 @@ static const char *gen_nextiword (int flags) } else { sprintf (buffer, "%s (%d)", prefetch_word, r + 2); count_read++; + check_bus_error_ins(r + 2); } } else { if (using_prefetch) { @@ -555,10 +584,12 @@ static const char *gen_nextiword (int flags) } else { sprintf (buffer, "%s (%d)", prefetch_word, r + 2); count_read++; + check_bus_error_ins(r + 2); insn_n_cycles += 4; } } else { sprintf (buffer, "%s (%d)", prefetch_word, r); + check_bus_error_ins(r); insn_n_cycles += 4; } } @@ -571,6 +602,7 @@ static const char *gen_nextibyte (int flags) int r = m68k_pc_offset; m68k_pc_offset += 2; + bus_error_text[0] = 0; if (using_ce020 || using_prefetch_020) { if (flags & GF_NOREFILL) sprintf(buffer, "(uae_u8)%s (%d)", prefetch_word, r); @@ -583,6 +615,7 @@ static const char *gen_nextibyte (int flags) } else { sprintf (buffer, "(uae_u8)%s (%d)", prefetch_word, r + 2); count_read++; + check_bus_error_ins(r + 2); } } else { insn_n_cycles += 4; @@ -591,11 +624,13 @@ static const char *gen_nextibyte (int flags) strcpy (buffer, "(uae_u8)regs.irc"); } else { sprintf (buffer, "(uae_u8)%s (%d)", prefetch_word, r + 2); - insn_n_cycles += 4; count_read++; + check_bus_error_ins(r + 2); + insn_n_cycles += 4; } } else { sprintf (buffer, "%s (%d)", srcbi, r); + check_bus_error_ins(r); insn_n_cycles += 4; } } @@ -669,6 +704,7 @@ static void fill_prefetch_2 (void) if (!using_prefetch) return; printf ("\t%s (%d);\n", prefetch_word, m68k_pc_offset + 2); + check_prefetch_bus_error(m68k_pc_offset + 2); did_prefetch = 1; ir2irc = 0; count_read++; @@ -679,6 +715,7 @@ static void fill_prefetch_1 (int o) { if (using_prefetch) { printf ("\t%s (%d);\n", prefetch_word, o); + check_prefetch_bus_error(o); did_prefetch = 1; ir2irc = 0; count_read++; @@ -781,6 +818,7 @@ static void fill_prefetch_0 (void) if (!using_prefetch) return; printf ("\t%s (0);\n", prefetch_word); + check_prefetch_bus_error(0); did_prefetch = 1; ir2irc = 0; count_read++; @@ -793,6 +831,7 @@ static void dummy_prefetch (void) if (!using_prefetch) return; printf ("\t%s (%d);\n", srcwi, o); + check_prefetch_bus_error(o); count_read++; insn_n_cycles += 4; } @@ -917,6 +956,67 @@ static void clearmmufixup (int cnt) } } +static char const *bus_error_reg; +static int bus_error_reg_add; + +static void check_bus_error(const char *name, int offset, int write, int fc) +{ + // check possible bus error (if 68000/010 and enabled) + if (!using_bus_error) + return; + if (!using_prefetch && !using_ce) + return; + printf("\tif(cpu_bus_error) {\n"); + + if (fc == 2) { + + printf("\t\texception2_read(opcode, m68k_getpci() + %d, 2);\n", offset); + + } else { + + if (exception_pc_offset) + incpc("%d", exception_pc_offset); + + switch (bus_error_reg_add) + { + case 1: + printf("\t\tm68k_areg(regs, %s) += areg_byteinc[%s] + %d;\n", bus_error_reg, bus_error_reg, offset); + break; + case 2: + printf("\t\tm68k_areg(regs, %s) += 2 + %d;\n", bus_error_reg, offset); + break; + case 3: + if (g_instr->mnemo == i_CMPM) { + // CMPM.L (an)+,(an)+: increased by 2 + printf("\t\tm68k_areg(regs, %s) += 2 + %d;\n", bus_error_reg, offset); + } else { + // not increased if long first word causes bus error + ; + } + break; + case 4: + if ((g_instr->mnemo == i_ADDX || g_instr->mnemo == i_SUBX) && g_instr->size == sz_long) { + // ADDX.L/SUBX.L -(an),-(an): not decreased + ; + } else { + printf("\t\tm68k_areg (regs, %s) = %sa;\n", bus_error_reg, name); + } + break; + } + + printf("\t\texception2_%s(opcode, %sa + %d, %d);\n", + write ? "write" : "read", name, offset, + (!write && (g_instr->smode == PC16 || g_instr->smode == PC8r) ? 2 : fc)); + } + + // if (exception_pc_offset) + // printf("\tbus_error_offset = %d;\n", exception_pc_offset); + + printf("\t\tgoto %s;\n", endlabelstr); + printf("\t}\n"); + need_endlabel = 1; +} + static void gen_set_fault_pc (bool multi, bool not68030) { int m68k_pc_total_old = m68k_pc_total; @@ -1768,6 +1868,7 @@ static void genamode2x (amodes mode, const char *reg, wordsizes size, const char default: term (); } + do_instruction_buserror(); maybeaddop_ce020 (flags); syncmovepc (getv, flags); return; @@ -1810,13 +1911,15 @@ static void genamode2x (amodes mode, const char *reg, wordsizes size, const char term (); } + do_instruction_buserror(); + syncmovepc (getv, flags); maybeaddop_ce020 (flags); /* We get here for all non-reg non-immediate addressing modes to * actually fetch the value. */ - int exception_pc_offset = 0; + exception_pc_offset = 0; if (getv == 2) { // store if (pc_68000_offset) { @@ -1877,16 +1980,32 @@ static void genamode2x (amodes mode, const char *reg, wordsizes size, const char start_brace (); } - if ((using_prefetch || using_ce) && using_bus_error && getv != 0) { - if (exception_pc_offset) - printf("\tbus_error_offset = %d;\n", exception_pc_offset); - } - if (flags & GF_PREFETCH) fill_prefetch_next (); else if (flags & GF_IR2IRC) irc2ir (true); + bus_error_reg_add = 0; + bus_error_reg = reg; + if (!movem) { + if (mode == Aipi) { + switch (size) + { + case sz_byte: + bus_error_reg_add = 1; + break; + case sz_word: + bus_error_reg_add = 2; + break; + case sz_long: + bus_error_reg_add = 3; + break; + } + } else if (mode == Apdi) { + bus_error_reg_add = 4; + } + } + if (getv == 1) { const char *srcbx = !(flags & GF_FC) ? srcb : "sfc_nommu_get_byte"; const char *srcwx = !(flags & GF_FC) ? srcw : "sfc_nommu_get_word"; @@ -1917,14 +2036,34 @@ static void genamode2x (amodes mode, const char *reg, wordsizes size, const char } } else if (using_ce || using_prefetch) { switch (size) { - case sz_byte: insn_n_cycles += 4; printf ("\tuae_s8 %s = %s (%sa);\n", name, srcbx, name); count_read++; break; - case sz_word: insn_n_cycles += 4; printf ("\tuae_s16 %s = %s (%sa);\n", name, srcwx, name); count_read++; break; - case sz_long: { + case sz_byte: + { + insn_n_cycles += 4; printf("\tuae_s8 %s = %s (%sa);\n", name, srcbx, name); + count_read++; + check_bus_error(name, 0, 0, 1); + break; + } + case sz_word: + { + insn_n_cycles += 4; printf("\tuae_s16 %s = %s (%sa);\n", name, srcwx, name); + count_read++; + check_bus_error(name, 0, 0, 1); + break; + } + case sz_long: + { insn_n_cycles += 8; - if ((flags & GF_REVERSE) && mode == Apdi) - printf("\tuae_s32 %s = %s (%sa + 2); %s |= %s (%sa) << 16;\n", name, srcwx, name, name, srcw, name); - else - printf("\tuae_s32 %s = %s (%sa) << 16; %s |= %s (%sa + 2);\n", name, srcwx, name, name, srcw, name); + if ((flags & GF_REVERSE) && mode == Apdi) { + printf("\tuae_s32 %s = %s (%sa + 2);\n", name, srcwx, name); + check_bus_error(name, 0, 0, 1); + printf("\t%s |= % s(% sa) << 16; \n", name, srcw, name); + check_bus_error(name, 0, 0, 1); + } else { + printf("\tuae_s32 %s = %s (%sa) << 16;\n", name, srcwx, name); + check_bus_error(name, 0, 0, 1); + printf("\t%s |= % s(% sa + 2); \n", name, srcw, name); + check_bus_error(name, 2, 0, 1); + } count_read += 2; break; } @@ -1940,6 +2079,8 @@ static void genamode2x (amodes mode, const char *reg, wordsizes size, const char } } + bus_error_reg_add = 0; + /* We now might have to fix up the register for pre-dec or post-inc * addressing modes. */ if (!movem) @@ -2168,6 +2309,7 @@ static void genastore_2 (const char *from, amodes mode, const char *reg, wordsiz check_ipl_again(); printf ("\tx_put_byte (%sa, %s);\n", to, from); count_write++; + check_bus_error(to, 0, 1, 1); break; case sz_word: if (cpu_level < 2 && (mode == PC16 || mode == PC8r)) @@ -2175,18 +2317,23 @@ static void genastore_2 (const char *from, amodes mode, const char *reg, wordsiz check_ipl_again(); printf ("\tx_put_word (%sa, %s);\n", to, from); count_write++; + check_bus_error(to, 0, 1, 1); break; case sz_long: if (cpu_level < 2 && (mode == PC16 || mode == PC8r)) term (); if (store_dir) { printf ("\t%s (%sa + 2, %s);\n", dstwx, to, from); + check_bus_error(to, 2, 1, 1); check_ipl_again(); printf ("%s (%sa, %s >> 16);\n", dstwx, to, from); + check_bus_error(to, 0, 1, 1); } else { printf ("\t%s (%sa, %s >> 16);\n", dstwx, to, from); + check_bus_error(to, 0, 1, 1); check_ipl_again(); printf ("\t%s (%sa + 2, %s);\n", dstwx, to, from); + check_bus_error(to, 2, 1, 1); } count_write += 2; break; @@ -2199,22 +2346,31 @@ static void genastore_2 (const char *from, amodes mode, const char *reg, wordsiz insn_n_cycles += 4; printf ("\t%s (%sa, %s);\n", dstbx, to, from); count_write++; + check_bus_error(to, 0, 1, 1); break; case sz_word: insn_n_cycles += 4; if (cpu_level < 2 && (mode == PC16 || mode == PC8r)) term (); printf ("\t%s (%sa, %s);\n", dstwx, to, from); + check_bus_error(to, 0, 1, 1); count_write++; break; case sz_long: insn_n_cycles += 8; if (cpu_level < 2 && (mode == PC16 || mode == PC8r)) term (); - if (store_dir) - printf ("\t%s (%sa + 2, %s); %s (%sa, %s >> 16);\n", dstwx, to, from, dstwx, to, from); - else - printf ("\t%s (%sa, %s >> 16); %s (%sa + 2, %s);\n", dstwx, to, from, dstwx, to, from); + if (store_dir) { + printf("\t%s(%sa + 2, %s);\n", dstwx, to, from); + check_bus_error(to, 2, 1, 1); + printf("\t%s(%sa, %s >> 16); \n", dstwx, to, from); + check_bus_error(to, 0, 1, 1); + } else { + printf("\t%s (%sa, %s >> 16);\n", dstwx, to, from); + check_bus_error(to, 0, 1, 1); + printf("\t%s(%sa + 2, %s); \n", dstwx, to, from); + check_bus_error(to, 2, 1, 1); + } count_write += 2; break; default: @@ -3902,29 +4058,45 @@ static void gen_opcode (unsigned int opcode) * weird things... */ case i_MVPRM: // MOVEP R->M genamode (curi, curi->smode, "srcreg", curi->size, "src", 1, 0, 0); - printf ("\tuaecptr memp = m68k_areg (regs, dstreg) + (uae_s32)(uae_s16)%s;\n", gen_nextiword (0)); + printf ("\tuaecptr mempa = m68k_areg (regs, dstreg) + (uae_s32)(uae_s16)%s;\n", gen_nextiword (0)); if (curi->size == sz_word) { - printf ("\t%s (memp, src >> 8);\n\t%s (memp + 2, src);\n", dstb, dstb); + printf("\t%s(mempa, src >> 8);\n", dstb); + check_bus_error("memp", 0, 1, 1); + printf("\t%s(mempa + 2, src); \n", dstb); + check_bus_error("memp", 2, 1, 1); count_write += 2; } else { - printf ("\t%s (memp, src >> 24);\n\t%s (memp + 2, src >> 16);\n", dstb, dstb); - printf ("\t%s (memp + 4, src >> 8);\n\t%s (memp + 6, src);\n", dstb, dstb); + printf("\t%s(mempa, src >> 24);\n", dstb); + check_bus_error("memp", 0, 1, 1); + printf("\t%s(mempa + 2, src >> 16);\n", dstb); + check_bus_error("memp", 2, 1, 1); + printf("\t%s(mempa + 4, src >> 8);\n", dstb); + check_bus_error("memp", 4, 1, 1); + printf("\t%s(mempa + 6, src); \n", dstb); + check_bus_error("memp", 6, 1, 1); count_write += 4; } fill_prefetch_next (); break; case i_MVPMR: // MOVEP M->R - printf ("\tuaecptr memp = m68k_areg (regs, srcreg) + (uae_s32)(uae_s16)%s;\n", gen_nextiword (0)); + printf ("\tuaecptr mempa = m68k_areg (regs, srcreg) + (uae_s32)(uae_s16)%s;\n", gen_nextiword (0)); genamode (curi, curi->dmode, "dstreg", curi->size, "dst", 2, 0, 0); if (curi->size == sz_word) { - printf ("\tuae_u16 val = (%s (memp) & 0xff) << 8;\n", srcb); - printf ("\t val |= (%s (memp + 2) & 0xff);\n", srcb); + printf ("\tuae_u16 val = (%s (mempa) & 0xff) << 8;\n", srcb); + check_bus_error("memp", 0, 0, 1); + printf ("\t val |= (%s (mempa + 2) & 0xff);\n", srcb); + check_bus_error("memp", 2, 0, 1); count_read += 2; } else { - printf ("\tuae_u32 val = (%s (memp) & 0xff) << 24;\n", srcb); - printf ("\t val |= (%s (memp + 2) & 0xff) << 16;\n", srcb); - printf ("\t val |= (%s (memp + 4) & 0xff) << 8;\n", srcb); - printf ("\t val |= (%s (memp + 6) & 0xff);\n", srcb); + printf ("\tuae_u32 val = (%s (mempa) & 0xff) << 24;\n", srcb); + check_bus_error("memp", 0, 0, 1); + printf ("\t val |= (%s (mempa + 2) & 0xff) << 16;\n", srcb); + check_bus_error("memp", 2, 0, 1); + printf ("\t val |= (%s (mempa + 4) & 0xff) << 8;\n", srcb); + check_bus_error("memp", 4, 0, 1); + printf ("\t val |= (%s (mempa + 6) & 0xff);\n", srcb); + printf ("\t val |= (%s (mempa + 6) & 0xff);\n", srcb); + check_bus_error("memp", 6, 0, 1); count_read += 4; } fill_prefetch_next (); @@ -4493,9 +4665,15 @@ static void gen_opcode (unsigned int opcode) } else if (using_ce020 == 2) { add_head_cycs (1); printf ("\tm68k_do_rts_ce030 ();\n"); - } else if (using_ce) { - printf ("\tm68k_do_rts_ce ();\n"); - } else if (using_prefetch || using_prefetch_020) { + } else if (using_ce || using_prefetch || (using_test && cpu_level <= 1)) { + printf("\tuaecptr newpc, dsta = m68k_areg(regs, 7);\n"); + printf("\tnewpc = %s(dsta) << 16;\n", srcw); + check_bus_error("dst", 0, 0, 1); + printf("\tnewpc |= %s(dsta + 2);\n", srcw); + check_bus_error("dst", 2, 0, 1); + printf("\tm68k_areg(regs, 7) += 4;\n"); + setpc("newpc"); + } else if (using_prefetch_020 || (using_test && cpu_level >= 2)) { printf ("\tm68k_do_rtsi ();\n"); } else { printf ("\tm68k_do_rts ();\n"); @@ -4609,10 +4787,13 @@ static void gen_opcode (unsigned int opcode) clear_m68k_offset(); fill_prefetch_1 (0); if (using_ce || using_prefetch) { - printf ("\t%s (m68k_areg (regs, 7), nextpc >> 16);\n", dstw); - printf ("\t%s (m68k_areg (regs, 7) + 2, nextpc);\n", dstw); + printf("\tuaecptr dsta = m68k_areg(regs, 7);\n"); + printf("\t%s(dsta, nextpc >> 16);\n", dstw); + check_bus_error("dst", 0, 1, 1); + printf("\t%s(dsta + 2, nextpc);\n", dstw); + check_bus_error("dst", 2, 1, 1); } else { - printf ("\t%s (m68k_areg (regs, 7), nextpc);\n", dstl); + printf ("\t%s(m68k_areg(regs, 7), nextpc);\n", dstl); } if (using_debugmem) { printf("\tif (debugmem_trace)\n"); @@ -4696,7 +4877,15 @@ static void gen_opcode (unsigned int opcode) printf ("\tm68k_do_bsr_ce030 (nextpc, s);\n"); } else if (using_ce) { printf ("\tm68k_do_bsr_ce (nextpc, s);\n"); - } else if (using_prefetch || using_prefetch_020 || using_test) { + } else if (using_prefetch || (using_test && cpu_level <= 1)) { + printf("\tm68k_areg(regs, 7) -= 4;\n"); + printf("\tuaecptr dsta = m68k_areg(regs, 7);\n"); + printf("\t%s(dsta, nextpc >> 16);\n", dstw); + check_bus_error("dst", 0, 1, 1); + printf("\t%s(dsta + 2, nextpc);\n", dstw); + check_bus_error("dst", 2, 1, 1); + incpc("s"); + } else if (using_prefetch_020 || (using_test && cpu_level >= 2)) { printf ("\tm68k_do_bsri (nextpc, s);\n"); } else { printf ("\tm68k_do_bsr (nextpc, s);\n"); @@ -6480,6 +6669,7 @@ static void generate_cpu_test(int mode) } using_exception_3 = 1; + using_bus_error = 1; using_prefetch = 0; using_prefetch_020 = 0; using_ce = 0; diff --git a/include/newcpu.h b/include/newcpu.h index 5c5a6b1d..1f69cf54 100644 --- a/include/newcpu.h +++ b/include/newcpu.h @@ -53,6 +53,7 @@ extern int fpp_movem_next[256]; #endif extern int bus_error_offset; +extern int cpu_bus_error; typedef uae_u32 REGPARAM3 cpuop_func (uae_u32) REGPARAM; typedef void REGPARAM3 cpuop_func_ce (uae_u32) REGPARAM; @@ -722,7 +723,9 @@ extern void exception3_notinstruction(uae_u32 opcode, uaecptr addr); extern void exception3i (uae_u32 opcode, uaecptr addr); extern void exception3b (uae_u32 opcode, uaecptr addr, bool w, bool i, uaecptr pc); extern void exception2 (uaecptr addr, bool read, int size, uae_u32 fc); -extern void exception2_setup(uaecptr addr, bool read, int size, uae_u32 fc); +extern void exception2_setup(uaecptr addr, bool read, uae_u32 fc); +extern void exception2_read(uae_u32 opcode, uaecptr addr, int fc); +extern void exception2_write(uae_u32 opcode, uaecptr addr, int fc); extern void m68k_reset (void); extern void cpureset (void); extern void cpu_halt (int id); diff --git a/ini.cpp b/ini.cpp index bd68b8fd..4e555ff0 100644 --- a/ini.cpp +++ b/ini.cpp @@ -347,6 +347,8 @@ bool ini_getval_multi(struct ini_data *ini, const TCHAR *section, const TCHAR *k TCHAR *out2 = NULL; if (!ini_getstring_multi(ini, section, key, &out2, ctx)) return false; + if (out2[0] == 0) + return false; if (_tcslen(out2) > 2 && out2[0] == '0' && _totupper(out2[1]) == 'X') { TCHAR *endptr; *v = _tcstol(out2 + 2, &endptr, 16); diff --git a/jit/exception_handler.cpp b/jit/exception_handler.cpp index 9f4698b0..efc4e04a 100644 --- a/jit/exception_handler.cpp +++ b/jit/exception_handler.cpp @@ -507,7 +507,7 @@ LONG WINAPI EvalException(LPEXCEPTION_POINTERS info) } if (currprefs.comp_catchfault) { // setup fake exception - exception2_setup(uae_p32(address) - uae_p32(NATMEM_OFFSET), info->ExceptionRecord->ExceptionInformation[0] == 0, 1, regs.s ? 4 : 0); + exception2_setup(uae_p32(address) - uae_p32(NATMEM_OFFSET), info->ExceptionRecord->ExceptionInformation[0] == 0, regs.s ? 4 : 0); return EXCEPTION_EXECUTE_HANDLER; } return EXCEPTION_CONTINUE_SEARCH; diff --git a/newcpu.cpp b/newcpu.cpp index 81b0350a..e89fe279 100644 --- a/newcpu.cpp +++ b/newcpu.cpp @@ -79,6 +79,7 @@ static int exception_in_exception; int mmu_enabled, mmu_triggered; int cpu_cycles; int bus_error_offset; +int cpu_bus_error; static int baseclock; int m68k_pc_indirect; bool m68k_interrupt_delay; @@ -6852,7 +6853,7 @@ void exception3b (uae_u32 opcode, uaecptr addr, bool w, bool i, uaecptr pc) exception3f (opcode, addr, w, i, false, pc, true, -1); } -void exception2_setup(uaecptr addr, bool read, int size, uae_u32 fc) +void exception2_setup(uaecptr addr, bool read, uae_u32 fc) { last_addr_for_exception_3 = m68k_getpc() + bus_error_offset; last_fault_for_exception_3 = addr; @@ -6860,9 +6861,10 @@ void exception2_setup(uaecptr addr, bool read, int size, uae_u32 fc) last_fc_for_exception_3 = fc; last_op_for_exception_3 = regs.opcode; last_notinstruction_for_exception_3 = exception_in_exception != 0; + cpu_bus_error = 0; } -void exception2 (uaecptr addr, bool read, int size, uae_u32 fc) +void exception2(uaecptr addr, bool read, int size, uae_u32 fc) { if (currprefs.mmu_model) { if (currprefs.mmu_model == 68030) { @@ -6872,11 +6874,24 @@ void exception2 (uaecptr addr, bool read, int size, uae_u32 fc) mmu_bus_error (addr, 0, fc, read == false, size, 0, true); } } else { - exception2_setup(addr, read, size, fc); + exception2_setup(addr, read, fc); THROW(2); + activate_debugger(); } } +void exception2_read(uae_u32 opcode, uaecptr addr, int fc) +{ + exception2_setup(addr, true, fc); + Exception(2); +} + +void exception2_write(uae_u32 opcode, uaecptr addr, int fc) +{ + exception2_setup(addr, false, fc); + Exception(2); +} + void cpureset (void) { /* RESET hasn't increased PC yet, 1 word offset */ diff --git a/newcpu_common.cpp b/newcpu_common.cpp index 7314172b..7dbb4908 100644 --- a/newcpu_common.cpp +++ b/newcpu_common.cpp @@ -817,7 +817,8 @@ void divbyzero_special (bool issigned, uae_s32 dst) /* DIVU overflow * - * 68000: V=1, C=0, Z=0, N=1 + * 68000: V=1, N=1, C=0, Z=0 + * 68010: V=1, N=1, C=0, Z=0 * 68020: V=1, C=0, Z=0, N=X * 68040: V=1, C=0, NZ not modified. * 68060: V=1, C=0, NZ not modified. @@ -838,9 +839,17 @@ void setdivuflags(uae_u32 dividend, uae_u16 divisor) SET_VFLG(1); if ((uae_s32)dividend < 0) SET_NFLG(1); + } else if (currprefs.cpu_model == 68010) { + SET_VFLG(1); + SET_NFLG(1); + SET_ZFLG(0); + SET_CFLG(0); } else { + // 68000 SET_VFLG(1); SET_NFLG(1); + SET_ZFLG(0); + SET_CFLG(0); } } @@ -876,7 +885,12 @@ void setdivsflags(uae_s32 dividend, uae_s16 divisor) SET_ZFLG(1); if ((uae_s8)aquot < 0) SET_NFLG(1); + } else if (currprefs.cpu_model == 68010) { + CLEAR_CZNV(); + SET_VFLG(1); + SET_NFLG(1); } else { + // 68000 CLEAR_CZNV(); SET_VFLG(1); SET_NFLG(1); -- 2.47.3