From: Toni Wilen Date: Sun, 13 Oct 2019 12:55:54 +0000 (+0300) Subject: MOVE complete bus error emulation. X-Git-Tag: 4300~84 X-Git-Url: https://git.unchartedbackwaters.co.uk/w/?a=commitdiff_plain;h=ed405c576aa70ab4b26dd8e1a5a2cea3d5906325;p=francis%2Fwinuae.git MOVE complete bus error emulation. --- diff --git a/cputest.cpp b/cputest.cpp index 3add9184..7800d42a 100644 --- a/cputest.cpp +++ b/cputest.cpp @@ -315,7 +315,7 @@ void put_byte_test(uaecptr addr, uae_u32 v) { check_bus_error(addr, 1, regs.s ? 5 : 1); uae_u8 *p = get_addr(addr, 1, 1); - if (!out_of_test_space && !noaccesshistory) { + if (!out_of_test_space && !noaccesshistory && !cpu_bus_error) { previoussame(addr, sz_byte); if (ahcnt >= MAX_ACCESSHIST) { wprintf(_T("ahist overflow!")); @@ -337,7 +337,7 @@ void put_word_test(uaecptr addr, uae_u32 v) put_byte_test(addr + 1, v >> 0); } else { uae_u8 *p = get_addr(addr, 2, 1); - if (!out_of_test_space && !noaccesshistory) { + if (!out_of_test_space && !noaccesshistory && !cpu_bus_error) { previoussame(addr, sz_word); if (ahcnt >= MAX_ACCESSHIST) { wprintf(_T("ahist overflow!")); @@ -365,7 +365,7 @@ void put_long_test(uaecptr addr, uae_u32 v) put_word_test(addr + 2, v >> 0); } else { uae_u8 *p = get_addr(addr, 4, 1); - if (!out_of_test_space && !noaccesshistory) { + if (!out_of_test_space && !noaccesshistory && !cpu_bus_error) { previoussame(addr, sz_long); if (ahcnt >= MAX_ACCESSHIST) { wprintf(_T("ahist overflow!")); @@ -2832,6 +2832,15 @@ static void test_mnemo(const TCHAR *path, const TCHAR *mnemo, const TCHAR *ovrfi abort(); } + if ((dflags & 1) && target_ea[0] == 0xffffffff && (srcaddr & addressing_mask) >= safe_memory_start - 4 && (srcaddr & addressing_mask) < safe_memory_end + 4) { + // random generated EA must never be inside safe memory + continue; + } + if ((dflags & 2) && target_ea[1] == 0xffffffff && (dstaddr & addressing_mask) >= safe_memory_start - 4 && (dstaddr & addressing_mask) < safe_memory_end + 4) { + // random generated EA must never be inside safe memory + continue; + } + #if 0 // can't test because dp may be empty if instruction is invalid if (nextpc != pc - 2) { diff --git a/cputest/asm.S b/cputest/asm.S index 9f643087..85ee63e5 100644 --- a/cputest/asm.S +++ b/cputest/asm.S @@ -16,6 +16,7 @@ .globl _msp_address2 .globl _msp_address3 .globl _msp_address4 + .globl _error_vector | must match main.c S_DREG = 0 @@ -257,6 +258,7 @@ _exceptiontable000: bsr.s exception | 47 nop exception: + move.w #0,ACTIVITYREG move.l a0,-(sp) move.l datapointer(pc),a0 movem.l d0-d7/a0-a6,(a0) @@ -283,12 +285,14 @@ exception: move.l USP,a1 move.l a1,S_AREG+7*4(a0) + move.w #0x222,ACTIVITYREG move.l superstack(pc),sp move.w (sp)+,sr movem.l (sp)+,d1-d7/a0-a6 rts _exception010: + move.w #0,ACTIVITYREG move.l a0,-(sp) move.l datapointer(pc),a0 movem.l d0-d7/a0-a6,(a0) @@ -305,12 +309,14 @@ _exception010: move.l USP,a1 move.l a1,S_AREG+7*4(a0) + move.w #0x222,ACTIVITYREG move.l superstack(pc),sp move.w (sp)+,sr movem.l (sp)+,d1-d7/a0-a6 rts _exception020: + move.w #0,ACTIVITYREG move.l a0,-(sp) move.l datapointer(pc),a0 movem.l d0-d7/a0-a6,(a0) @@ -331,6 +337,7 @@ _msp_address3: move.l USP,a1 move.l a1,S_AREG+7*4(a0) + move.w #0x222,ACTIVITYREG | restore SR first, then stack | M-bit may have been set. move.l superstack(pc),a0 @@ -340,6 +347,7 @@ _msp_address3: rts _exceptionfpu: + move.w #0,ACTIVITYREG move.l a0,-(sp) move.l datapointer(pc),a0 movem.l d0-d7/a0-a6,(a0) @@ -366,12 +374,20 @@ _msp_address4: fmove.l fpcr,(a1)+ fmove.l fpsr,(a1)+ + move.w #0x222,ACTIVITYREG move.l superstack(pc),a0 move.w (a0)+,sr move.l a0,sp movem.l (sp)+,d1-d7/a0-a6 rts +_error_vector: + or.w #0x700,sr +waiterr: + move.w #0x400,ACTIVITYREG + move.w #0x004,ACTIVITYREG + bra.s waiterr + datapointer: dc.l 0 superstack: diff --git a/cputest/main.c b/cputest/main.c index 9e394688..1f92d8a7 100644 --- a/cputest/main.c +++ b/cputest/main.c @@ -164,6 +164,7 @@ static void setcpu(uae_u32 v, uae_u32 *s, uae_u32 *d) static void flushcache(uae_u32 v) { } +static void *error_vector; #else static void xmemcpy(void *d, void *s, int size) @@ -185,6 +186,7 @@ extern uae_u32 setvbr(uae_u32); extern uae_u32 get_cpu_model(void); extern void setcpu(uae_u32, uae_u32*, uae_u32*); extern void flushcache(uae_u32); +extern void *error_vector; #endif @@ -249,6 +251,35 @@ static void safe_memcpy(uae_u8 *d, uae_u8 *s, int size) static int test_active; static uae_u32 enable_data; +static uae_u32 error_vectors[12]; + +// if exception happens outside of test code, jump to +// infinite loop and flash colors. +static void reset_error_vectors(void) +{ + uae_u32 *p; + if (cpu_lvl == 0) { + p = (uae_u32*)vbr_zero; + } else { + p = vbr; + } + for (int i = 2; i < 4; i++) { + p[i] = error_vectors[i - 2]; + } +} + +static void set_error_vectors(void) +{ + uae_u32 *p; + if (cpu_lvl == 0) { + p = (uae_u32 *)vbr_zero; + } else { + p = vbr; + } + for (int i = 2; i < 4; i++) { + p[i] = (uae_u32)&error_vector; + } +} static void start_test(void) { @@ -293,6 +324,9 @@ static void start_test(void) uae_u32 *p = (uae_u32 *)vbr_zero; for (int i = 2; i < 12; i++) { p[i] = (uae_u32)(((uae_u32)&exceptiontable000) + (i - 2) * 2); + if (i < 12 + 2) { + error_vectors[i - 2] = p[i]; + } } for (int i = 32; i < 48; i++) { p[i] = (uae_u32)(((uae_u32)&exceptiontable000) + (i - 2) * 2); @@ -301,6 +335,9 @@ static void start_test(void) oldvbr = setvbr((uae_u32)vbr); for (int i = 0; i < 256; i++) { vbr[i] = fpu_model ? (uae_u32)(&exceptionfpu) : (cpu_lvl == 1 ? (uae_u32)(&exception010) : (uae_u32)(&exception020)); + if (i >= 2 && i < 12) { + error_vectors[i - 2] = vbr[i]; + } } } setcpu(cpu_lvl, cpustatearraynew, cpustatearraystore); @@ -929,7 +966,7 @@ static void out_regs(struct registers *r, int before) strcat(outbp, " "); } outbp += strlen(outbp); - sprintf(outbp, "%c%d:%c%08lx", i < 8 ? 'D' : 'A', i & 7, test_regs.regs[i] != regs.regs[i] ? '*' : ' ', r->regs[i]); + sprintf(outbp, "%c%d:%c%08lx", i < 8 ? 'D' : 'A', i & 7, test_regs.regs[i] != last_registers.regs[i] ? '*' : ' ', r->regs[i]); outbp += strlen(outbp); } *outbp++ = '\n'; @@ -950,7 +987,7 @@ static void out_regs(struct registers *r, int before) int idx = i * 4 + j; if (j > 0) *outbp++ = ' '; - sprintf(outbp, "%c%d:%c%08lx", idx < 8 ? 'D' : 'A', idx & 7, test_regs.regs[idx] != regs.regs[idx] ? '*' : ' ', r->regs[idx]); + sprintf(outbp, "%c%d:%c%08lx", idx < 8 ? 'D' : 'A', idx & 7, test_regs.regs[idx] != last_registers.regs[idx] ? '*' : ' ', regs.regs[idx]); outbp += strlen(outbp); } } @@ -1126,7 +1163,7 @@ static uae_u8 *validate_exception(struct registers *regs, uae_u8 *p, int excnum, if (exclen == 0 || !sameexc) return p; if (memcmp(exc, sp, exclen)) { - strcpy(outbp, "Exception stack frame mismatch:\n"); + sprintf(outbp, "Exception %ld stack frame mismatch:\n", excnum); outbp += strlen(outbp); strcpy(outbp, "Expected: "); outbp += strlen(outbp); @@ -1607,6 +1644,8 @@ static void process_test(uae_u8 *p) if ((ccr_mask & ccr) || (ccr == 0)) { + reset_error_vectors(); + if (cpu_lvl == 1) { execute_test010(&test_regs); } else if (cpu_lvl >= 2) { @@ -1621,6 +1660,8 @@ static void process_test(uae_u8 *p) if (ccr_mask == 0 && ccr == 0) ignore_sr = 1; + set_error_vectors(); + } else { test_regs.sr = test_sr; @@ -1970,6 +2011,8 @@ int main(int argc, char *argv[]) ccr_mask = ~getparamval(next); i++; } + } else if (!_stricmp(s, "silent")) { + dooutput = 0; } else if (!_stricmp(s, "68000")) { cpu_lvl = 0; } else if (!_stricmp(s, "68010")) { diff --git a/debug.cpp b/debug.cpp index 373fe2a2..8a50b7da 100644 --- a/debug.cpp +++ b/debug.cpp @@ -3003,7 +3003,11 @@ static int memwatch_func (uaecptr addr, int rwi, int size, uae_u32 *valp, uae_u3 continue; if (m->bus_error) { +#if BUS_ERROR_EMULATION + cpu_bus_error = 1; +#else exception2(addr, (rwi & 2) == 0, size, ((rwi & 4) ? 2 : 1) | (regs.s ? 4 : 0)); +#endif continue; } diff --git a/disasm.cpp b/disasm.cpp index b891d97f..bd72d41c 100644 --- a/disasm.cpp +++ b/disasm.cpp @@ -176,10 +176,6 @@ uaecptr ShowEA_disp(uaecptr *pcp, uaecptr base, TCHAR *buffer, const TCHAR *name dispreg = (uae_s32)(uae_s16)(dispreg); } - if (currprefs.cpu_model >= 68020) { - dispreg <<= (dp >> 9) & 3; // SCALE - } - int m = 1 << ((dp >> 9) & 3); mult[0] = 0; if (m > 1 && buffer) { @@ -190,8 +186,11 @@ uaecptr ShowEA_disp(uaecptr *pcp, uaecptr base, TCHAR *buffer, const TCHAR *name buffer[0] = 0; if ((dp & 0x100) && currprefs.cpu_model >= 68020) { TCHAR dr[20]; - // Full format extension (68020+) uae_s32 outer = 0, disp = 0; + + // Full format extension (68020+) + + dispreg <<= (dp >> 9) & 3; // SCALE if (dp & 0x80) { // BS (base register suppress) base = 0; if (buffer) diff --git a/gencpu.cpp b/gencpu.cpp index 88054bee..975a96a4 100644 --- a/gencpu.cpp +++ b/gencpu.cpp @@ -75,6 +75,14 @@ static int optimized_flags; #define GF_OPCE020 2048 #define GF_REVERSE 4096 #define GF_REVERSE2 8192 +#define GF_SECONDWORDSETFLAGS 16384 + +typedef enum +{ + flag_logical_noclobber, flag_logical, flag_add, flag_sub, flag_cmp, flag_addx, flag_subx, flag_z, flag_zn, + flag_av, flag_sv +} +flagtypes; /* For the current opcode, the next lower level that will have different code. * Initialized to -1 for each opcode. If it remains unchanged, indicates we @@ -997,6 +1005,385 @@ static void clearmmufixup (int cnt) } } + +static void duplicate_carry(int n) +{ + int i; + for (i = 0; i <= n; i++) + printf("\t"); + printf("COPY_CARRY ();\n"); +} + +static void genflags_normal(flagtypes type, wordsizes size, const char *value, const char *src, const char *dst) +{ + char vstr[100], sstr[100], dstr[100]; + char usstr[100], udstr[100]; + char unsstr[100], undstr[100]; + + switch (size) { + case sz_byte: + strcpy(vstr, "((uae_s8)("); + strcpy(usstr, "((uae_u8)("); + break; + case sz_word: + strcpy(vstr, "((uae_s16)("); + strcpy(usstr, "((uae_u16)("); + break; + case sz_long: + strcpy(vstr, "((uae_s32)("); + strcpy(usstr, "((uae_u32)("); + break; + default: + term(); + } + strcpy(unsstr, usstr); + + strcpy(sstr, vstr); + strcpy(dstr, vstr); + strcat(vstr, value); + strcat(vstr, "))"); + strcat(dstr, dst); + strcat(dstr, "))"); + strcat(sstr, src); + strcat(sstr, "))"); + + strcpy(udstr, usstr); + strcat(udstr, dst); + strcat(udstr, "))"); + strcat(usstr, src); + strcat(usstr, "))"); + + strcpy(undstr, unsstr); + strcat(unsstr, "-"); + strcat(undstr, "~"); + strcat(undstr, dst); + strcat(undstr, "))"); + strcat(unsstr, src); + strcat(unsstr, "))"); + + switch (type) { + case flag_logical_noclobber: + case flag_logical: + case flag_z: + case flag_zn: + case flag_av: + case flag_sv: + case flag_addx: + case flag_subx: + break; + + case flag_add: + start_brace(); + printf("uae_u32 %s = %s + %s;\n", value, udstr, usstr); + break; + case flag_sub: + case flag_cmp: + start_brace(); + printf("uae_u32 %s = %s - %s;\n", value, udstr, usstr); + break; + } + + switch (type) { + case flag_logical_noclobber: + case flag_logical: + case flag_zn: + break; + + case flag_add: + case flag_sub: + case flag_addx: + case flag_subx: + case flag_cmp: + case flag_av: + case flag_sv: + start_brace(); + printf("\t" BOOL_TYPE " flgs = %s < 0;\n", sstr); + printf("\t" BOOL_TYPE " flgo = %s < 0;\n", dstr); + printf("\t" BOOL_TYPE " flgn = %s < 0;\n", vstr); + break; + } + + switch (type) { + case flag_logical: + printf("\tCLEAR_CZNV ();\n"); + printf("\tSET_ZFLG (%s == 0);\n", vstr); + printf("\tSET_NFLG (%s < 0);\n", vstr); + break; + case flag_logical_noclobber: + printf("\tSET_ZFLG (%s == 0);\n", vstr); + printf("\tSET_NFLG (%s < 0);\n", vstr); + break; + case flag_av: + printf("\tSET_VFLG ((flgs ^ flgn) & (flgo ^ flgn));\n"); + break; + case flag_sv: + printf("\tSET_VFLG ((flgs ^ flgo) & (flgn ^ flgo));\n"); + break; + case flag_z: + printf("\tSET_ZFLG (GET_ZFLG () & (%s == 0));\n", vstr); + break; + case flag_zn: + printf("\tSET_ZFLG (GET_ZFLG () & (%s == 0));\n", vstr); + printf("\tSET_NFLG (%s < 0);\n", vstr); + break; + case flag_add: + printf("\tSET_ZFLG (%s == 0);\n", vstr); + printf("\tSET_VFLG ((flgs ^ flgn) & (flgo ^ flgn));\n"); + printf("\tSET_CFLG (%s < %s);\n", undstr, usstr); + duplicate_carry(0); + printf("\tSET_NFLG (flgn != 0);\n"); + break; + case flag_sub: + printf("\tSET_ZFLG (%s == 0);\n", vstr); + printf("\tSET_VFLG ((flgs ^ flgo) & (flgn ^ flgo));\n"); + printf("\tSET_CFLG (%s > %s);\n", usstr, udstr); + duplicate_carry(0); + printf("\tSET_NFLG (flgn != 0);\n"); + break; + case flag_addx: + printf("\tSET_VFLG ((flgs ^ flgn) & (flgo ^ flgn));\n"); /* minterm SON: 0x42 */ + printf("\tSET_CFLG (flgs ^ ((flgs ^ flgo) & (flgo ^ flgn)));\n"); /* minterm SON: 0xD4 */ + duplicate_carry(0); + break; + case flag_subx: + printf("\tSET_VFLG ((flgs ^ flgo) & (flgo ^ flgn));\n"); /* minterm SON: 0x24 */ + printf("\tSET_CFLG (flgs ^ ((flgs ^ flgn) & (flgo ^ flgn)));\n"); /* minterm SON: 0xB2 */ + duplicate_carry(0); + break; + case flag_cmp: + printf("\tSET_ZFLG (%s == 0);\n", vstr); + printf("\tSET_VFLG ((flgs != flgo) && (flgn != flgo));\n"); + printf("\tSET_CFLG (%s > %s);\n", usstr, udstr); + printf("\tSET_NFLG (flgn != 0);\n"); + break; + } +} + +static void genflags(flagtypes type, wordsizes size, const char *value, const char *src, const char *dst) +{ + /* Temporarily deleted 68k/ARM flag optimizations. I'd prefer to have + them in the appropriate m68k.h files and use just one copy of this + code here. The API can be changed if necessary. */ + if (optimized_flags) { + switch (type) { + case flag_add: + case flag_sub: + start_brace(); + printf("\tuae_u32 %s;\n", value); + break; + + default: + break; + } + + /* At least some of those casts are fairly important! */ + switch (type) { + case flag_logical_noclobber: + printf("\t{uae_u32 oldcznv = GET_CZNV & ~(FLAGVAL_Z | FLAGVAL_N);\n"); + if (strcmp(value, "0") == 0) { + printf("\tSET_CZNV (olcznv | FLAGVAL_Z);\n"); + } else { + switch (size) { + case sz_byte: printf("\toptflag_testb (regs, (uae_s8)(%s));\n", value); break; + case sz_word: printf("\toptflag_testw (regs, (uae_s16)(%s));\n", value); break; + case sz_long: printf("\toptflag_testl (regs, (uae_s32)(%s));\n", value); break; + } + printf("\tIOR_CZNV (oldcznv);\n"); + } + printf("\t}\n"); + return; + case flag_logical: + if (strcmp(value, "0") == 0) { + printf("\tSET_CZNV (FLAGVAL_Z);\n"); + } else { + switch (size) { + case sz_byte: printf("\toptflag_testb (regs, (uae_s8)(%s));\n", value); break; + case sz_word: printf("\toptflag_testw (regs, (uae_s16)(%s));\n", value); break; + case sz_long: printf("\toptflag_testl (regs, (uae_s32)(%s));\n", value); break; + } + } + return; + + case flag_add: + switch (size) { + case sz_byte: printf("\toptflag_addb (regs, %s, (uae_s8)(%s), (uae_s8)(%s));\n", value, src, dst); break; + case sz_word: printf("\toptflag_addw (regs, %s, (uae_s16)(%s), (uae_s16)(%s));\n", value, src, dst); break; + case sz_long: printf("\toptflag_addl (regs, %s, (uae_s32)(%s), (uae_s32)(%s));\n", value, src, dst); break; + } + return; + + case flag_sub: + switch (size) { + case sz_byte: printf("\toptflag_subb (regs, %s, (uae_s8)(%s), (uae_s8)(%s));\n", value, src, dst); break; + case sz_word: printf("\toptflag_subw (regs, %s, (uae_s16)(%s), (uae_s16)(%s));\n", value, src, dst); break; + case sz_long: printf("\toptflag_subl (regs, %s, (uae_s32)(%s), (uae_s32)(%s));\n", value, src, dst); break; + } + return; + + case flag_cmp: + switch (size) { + case sz_byte: printf("\toptflag_cmpb (regs, (uae_s8)(%s), (uae_s8)(%s));\n", src, dst); break; + case sz_word: printf("\toptflag_cmpw (regs, (uae_s16)(%s), (uae_s16)(%s));\n", src, dst); break; + case sz_long: printf("\toptflag_cmpl (regs, (uae_s32)(%s), (uae_s32)(%s));\n", src, dst); break; + } + return; + + default: + break; + } + } + + genflags_normal(type, size, value, src, dst); +} + +// Handle special MOVE.W/.L condition codes when destination write causes bus error. +static void move_68000_bus_error(int offset, int size, int *setapdi, int *fcmodeflags) +{ + + int smode = g_instr->smode; + int dmode = g_instr->dmode; + + if (size == sz_byte) { + + if (dmode == Apdi) { + + // this is buggy, bus error stack frame opcode field contains next + // instruction opcode and Instruction/Not field is one! + printf("\t\topcode = regs.ir;\n"); + *fcmodeflags |= 0x08; // "Not instruction" = 1 + + } else if (dmode == Aipi) { + + // move.b x,(an)+: an is not increased + printf("\t\tm68k_areg(regs, dstreg) -= areg_byteinc[dstreg];\n"); + } + + } else if (size == sz_word) { + + if (dmode == Apdi) { + // this is buggy, bus error stack frame opcode field contains next + // instruction opcode and Instruction/Not field is one! + printf("\t\topcode = regs.ir;\n"); + *fcmodeflags |= 0x08; // "Not instruction" = 1 + } + + } else if (size == sz_long && ((offset == 0 && dmode != Apdi) || (offset == 2 && dmode == Apdi))) { + + // Long MOVE is more complex but not as complex as address error.. + // First word. + + int set_ccr = 0; + int set_high_word = 0; + int set_low_word = 0; + switch (smode) + { + case Dreg: + case Areg: + if (dmode == Ad16 || dmode == Ad8r) { + set_high_word = 3; + } else if (dmode == Apdi || dmode == absw || dmode == absl) { + set_ccr = 1; + } + break; + case Aind: + case Aipi: + case Apdi: + case Ad16: + case Ad8r: + case PC16: + case PC8r: + case absl: + case absw: + if (dmode == Aind || dmode == Aipi || dmode == absw || dmode == absl) { + set_low_word = 1; + } else if (dmode == Apdi || dmode == Ad16 || dmode == Ad8r) { + set_ccr = 1; + } + break; + case imm: + if (dmode == Ad16 || dmode == Ad8r) { + set_high_word = 1; + } else if (dmode == Apdi || dmode == absw || dmode == absl) { + set_ccr = 1; + } + break; + } + + if (set_low_word == 1) { + // Low word: Z and N + printf("\t\tccr_68000_long_move_ae_LZN(src);\n"); + } else if (set_high_word == 3) { + // High word: N only, clear Z if non-zero + printf("\t\tSET_NFLG(src < 0);\n"); + printf("\t\tif((src & 0xffff0000)) SET_ZFLG(0);\n"); + } else if (set_high_word) { + // High word: N set/reset and Z clear. + printf("\t\tccr_68000_long_move_ae_HNZ(src);\n"); + } else if (set_ccr) { + // Set normally. + printf("\t\tccr_68000_long_move_ae_normal(src);\n"); + } + + if (dmode == Aipi) { + printf("\t\tm68k_areg(regs, dstreg) -= 4;\n"); + } else if (dmode == Apdi) { + printf("\t\tm68k_areg(regs, dstreg) += 4;\n"); + } + + } else if (size == sz_long) { + + // Second word (much simpler) + + int set_ccr = 0; + int set_low_word = 0; + switch (smode) + { + case Dreg: + case Areg: + if (dmode == Apdi || dmode == absw || dmode == absl) { + set_ccr = 1; + } else { + set_low_word = 1; + } + break; + case Aind: + case Aipi: + case Apdi: + case Ad16: + case Ad8r: + case PC16: + case PC8r: + case absl: + case absw: + set_ccr = 1; + break; + case imm: + if (dmode == Apdi || dmode == absw || dmode == absl) { + set_ccr = 1; + } else { + set_low_word = 1; + } + break; + } + + if (set_low_word == 1) { + // Low word: Z and N + printf("\t\tccr_68000_long_move_ae_LZN(src);\n"); + } else if (set_ccr) { + // Set normally. + printf("\t\tccr_68000_long_move_ae_normal(src);\n"); + } + + if (dmode == Aipi) { + printf("\t\tm68k_areg(regs, dstreg) -= 4;\n"); + } else if (dmode == Apdi) { + printf("\t\tm68k_areg(regs, dstreg) += 4;\n"); + } + + } + +} + static char const *bus_error_reg; static int bus_error_reg_add; @@ -1009,19 +1396,30 @@ static void check_bus_error(const char *name, int offset, int write, int fc) return; printf("\tif(cpu_bus_error) {\n"); + int setapdiback = 0; + if (fc == 2) { printf("\t\texception2_read(opcode, m68k_getpci() + %d, 2);\n", offset); } else { - if (exception_pc_offset) + if (exception_pc_offset) { incpc("%d", exception_pc_offset); + } + + if (g_instr->mnemo == i_MOVE && write) { + move_68000_bus_error(offset, g_instr->size, &setapdiback, &fc); + } 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); + if (g_instr->mnemo == i_CMPM && write) { + ; + } else { + 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); @@ -1030,9 +1428,6 @@ static void check_bus_error(const char *name, int offset, int write, int fc) 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: @@ -1045,14 +1440,17 @@ static void check_bus_error(const char *name, int offset, int write, int fc) break; } + if (g_instr->mnemo == i_BTST && (g_instr->dmode == PC16 || g_instr->dmode == PC8r)) { + // BTST special case where destination is read access + fc = 2; + } + 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)); + (!write && (g_instr->smode == PC16 || g_instr->smode == PC8r)) || + (write && (g_instr->dmode == PC16 || g_instr->dmode == 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; @@ -1525,7 +1923,7 @@ static void maybeaddop_ce020 (int flags) // Handle special MOVE.W/.L condition codes when destination write causes address error. -static void move_68000_address_error(amodes mode, int size, int *setapdi, int *fcmodeflags) +static void move_68000_address_error(int size, int *setapdi, int *fcmodeflags) { int smode = g_instr->smode; int dmode = g_instr->dmode; @@ -1549,7 +1947,7 @@ static void move_68000_address_error(amodes mode, int size, int *setapdi, int *f case absw: case absl: case imm: - if (dmode == Aind || dmode == Aipi || dmode == Apdi || dmode == Ad16 || mode == Ad8r || mode == absw || mode == absl) + if (dmode == Aind || dmode == Aipi || dmode == Apdi || dmode == Ad16 || dmode == Ad8r || dmode == absw || dmode == absl) set_ccr = 1; break; } @@ -1561,9 +1959,6 @@ static void move_68000_address_error(amodes mode, int size, int *setapdi, int *f } if (set_ccr) { printf("\t\tccr_68000_word_move_ae_normal((uae_s16)(src));\n"); - //printf("\t\tCLEAR_CZNV();\n"); - //printf("\t\tSET_ZFLG(((uae_s16)(src)) == 0);\n"); - //printf("\t\tSET_NFLG(((uae_s16)(src)) < 0);\n"); } } else { // Long MOVE is much more complex.. @@ -1589,9 +1984,9 @@ static void move_68000_address_error(amodes mode, int size, int *setapdi, int *f case PC8r: case absw: case absl: - if (mode == Apdi || mode == Ad16 || mode == Ad8r || mode == absw) { + if (dmode == Apdi || dmode == Ad16 || dmode == Ad8r || dmode == absw) { set_ccr = 1; - } else if (mode == Aind || mode == Aipi || mode == absl) { + } else if (dmode == Aind || dmode == Aipi || dmode == absl) { set_low_word = 1; } else { set_low_word = 2; @@ -1615,35 +2010,15 @@ static void move_68000_address_error(amodes mode, int size, int *setapdi, int *f if (set_low_word == 1) { // Low word: Z and N printf("\t\tccr_68000_long_move_ae_LZN(src);\n"); - //printf("\t\tCLEAR_CZNV();\n"); - //printf("\t\tuae_s16 vsrc = (uae_s16)(src & 0xffff);\n"); - //printf("\t\tSET_ZFLG(vsrc == 0);\n"); - //printf("\t\tSET_NFLG(vsrc < 0);\n"); } else if (set_low_word == 2) { // Low word: N only printf("\t\tccr_68000_long_move_ae_LN(src);\n"); - //printf("\t\tCLEAR_CZNV();\n"); - //printf("\t\tuae_s16 vsrc = (uae_s16)(src & 0xffff);\n"); - //printf("\t\tSET_NFLG(vsrc < 0);\n"); } else if (set_high_word) { // High word: N and Z clear. printf("\t\tccr_68000_long_move_ae_HNZ(src);\n"); - //printf("\t\tuae_s16 vsrc = (uae_s16)(src >> 16);\n"); - //printf("\t\tif(vsrc < 0) {\n"); - //printf("\t\t\tSET_NFLG(1);\n"); - //printf("\t\t\tSET_ZFLG(0);\n"); - //printf("\t\t} else if (vsrc) {\n"); - //printf("\t\t\tSET_NFLG(0);\n"); - //printf("\t\t\tSET_ZFLG(0);\n"); - //printf("\t\t} else {\n"); - //printf("\t\t\tSET_NFLG(0);\n"); - //printf("\t\t}\n"); } else if (set_ccr) { // Set normally. printf("\t\tccr_68000_long_move_ae_normal(src);\n"); - //printf("\t\tCLEAR_CZNV();\n"); - //printf("\t\tSET_ZFLG((src) == 0);\n"); - //printf("\t\tSET_NFLG((src) < 0);\n"); } } } @@ -1994,7 +2369,7 @@ static void genamode2x (amodes mode, const char *reg, wordsizes size, const char if (g_instr->mnemo == i_MOVE) { if (getv == 2) { - move_68000_address_error(mode, size, &setapdiback, &fcmodeflags); + move_68000_address_error(size, &setapdiback, &fcmodeflags); } } else if (g_instr->mnemo == i_MVSR2) { // If MOVE from SR generates address error exception, @@ -2367,12 +2742,18 @@ static void genastore_2 (const char *from, amodes mode, const char *reg, wordsiz printf ("\t%s (%sa + 2, %s);\n", dstwx, to, from); check_bus_error(to, 2, 1, 1); check_ipl_again(); + if (flags & GF_SECONDWORDSETFLAGS) { + genflags(flag_logical, g_instr->size, "src", "", ""); + } 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(); + if (flags & GF_SECONDWORDSETFLAGS) { + genflags(flag_logical, g_instr->size, "src", "", ""); + } printf ("\t%s (%sa + 2, %s);\n", dstwx, to, from); check_bus_error(to, 2, 1, 1); } @@ -2404,11 +2785,17 @@ static void genastore_2 (const char *from, amodes mode, const char *reg, wordsiz if (store_dir) { printf("\t%s(%sa + 2, %s);\n", dstwx, to, from); check_bus_error(to, 2, 1, 1); + if (flags & GF_SECONDWORDSETFLAGS) { + genflags(flag_logical, g_instr->size, "src", "", ""); + } 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); + if (flags & GF_SECONDWORDSETFLAGS) { + genflags(flag_logical, g_instr->size, "src", "", ""); + } printf("\t%s(%sa + 2, %s); \n", dstwx, to, from); check_bus_error(to, 2, 1, 1); } @@ -2947,243 +3334,6 @@ static void genmovemle_ce (uae_u16 opcode) fill_prefetch_next (); } -static void duplicate_carry (int n) -{ - int i; - for (i = 0; i <= n; i++) - printf ("\t"); - printf ("COPY_CARRY ();\n"); -} - -typedef enum -{ - flag_logical_noclobber, flag_logical, flag_add, flag_sub, flag_cmp, flag_addx, flag_subx, flag_z, flag_zn, - flag_av, flag_sv -} -flagtypes; - -static void genflags_normal (flagtypes type, wordsizes size, const char *value, const char *src, const char *dst) -{ - char vstr[100], sstr[100], dstr[100]; - char usstr[100], udstr[100]; - char unsstr[100], undstr[100]; - - switch (size) { - case sz_byte: - strcpy (vstr, "((uae_s8)("); - strcpy (usstr, "((uae_u8)("); - break; - case sz_word: - strcpy (vstr, "((uae_s16)("); - strcpy (usstr, "((uae_u16)("); - break; - case sz_long: - strcpy (vstr, "((uae_s32)("); - strcpy (usstr, "((uae_u32)("); - break; - default: - term (); - } - strcpy (unsstr, usstr); - - strcpy (sstr, vstr); - strcpy (dstr, vstr); - strcat (vstr, value); - strcat (vstr, "))"); - strcat (dstr, dst); - strcat (dstr, "))"); - strcat (sstr, src); - strcat (sstr, "))"); - - strcpy (udstr, usstr); - strcat (udstr, dst); - strcat (udstr, "))"); - strcat (usstr, src); - strcat (usstr, "))"); - - strcpy (undstr, unsstr); - strcat (unsstr, "-"); - strcat (undstr, "~"); - strcat (undstr, dst); - strcat (undstr, "))"); - strcat (unsstr, src); - strcat (unsstr, "))"); - - switch (type) { - case flag_logical_noclobber: - case flag_logical: - case flag_z: - case flag_zn: - case flag_av: - case flag_sv: - case flag_addx: - case flag_subx: - break; - - case flag_add: - start_brace (); - printf ("uae_u32 %s = %s + %s;\n", value, udstr, usstr); - break; - case flag_sub: - case flag_cmp: - start_brace (); - printf ("uae_u32 %s = %s - %s;\n", value, udstr, usstr); - break; - } - - switch (type) { - case flag_logical_noclobber: - case flag_logical: - case flag_zn: - break; - - case flag_add: - case flag_sub: - case flag_addx: - case flag_subx: - case flag_cmp: - case flag_av: - case flag_sv: - start_brace (); - printf ("\t" BOOL_TYPE " flgs = %s < 0;\n", sstr); - printf ("\t" BOOL_TYPE " flgo = %s < 0;\n", dstr); - printf ("\t" BOOL_TYPE " flgn = %s < 0;\n", vstr); - break; - } - - switch (type) { - case flag_logical: - printf ("\tCLEAR_CZNV ();\n"); - printf ("\tSET_ZFLG (%s == 0);\n", vstr); - printf ("\tSET_NFLG (%s < 0);\n", vstr); - break; - case flag_logical_noclobber: - printf ("\tSET_ZFLG (%s == 0);\n", vstr); - printf ("\tSET_NFLG (%s < 0);\n", vstr); - break; - case flag_av: - printf ("\tSET_VFLG ((flgs ^ flgn) & (flgo ^ flgn));\n"); - break; - case flag_sv: - printf ("\tSET_VFLG ((flgs ^ flgo) & (flgn ^ flgo));\n"); - break; - case flag_z: - printf ("\tSET_ZFLG (GET_ZFLG () & (%s == 0));\n", vstr); - break; - case flag_zn: - printf ("\tSET_ZFLG (GET_ZFLG () & (%s == 0));\n", vstr); - printf ("\tSET_NFLG (%s < 0);\n", vstr); - break; - case flag_add: - printf ("\tSET_ZFLG (%s == 0);\n", vstr); - printf ("\tSET_VFLG ((flgs ^ flgn) & (flgo ^ flgn));\n"); - printf ("\tSET_CFLG (%s < %s);\n", undstr, usstr); - duplicate_carry (0); - printf ("\tSET_NFLG (flgn != 0);\n"); - break; - case flag_sub: - printf ("\tSET_ZFLG (%s == 0);\n", vstr); - printf ("\tSET_VFLG ((flgs ^ flgo) & (flgn ^ flgo));\n"); - printf ("\tSET_CFLG (%s > %s);\n", usstr, udstr); - duplicate_carry (0); - printf ("\tSET_NFLG (flgn != 0);\n"); - break; - case flag_addx: - printf ("\tSET_VFLG ((flgs ^ flgn) & (flgo ^ flgn));\n"); /* minterm SON: 0x42 */ - printf ("\tSET_CFLG (flgs ^ ((flgs ^ flgo) & (flgo ^ flgn)));\n"); /* minterm SON: 0xD4 */ - duplicate_carry (0); - break; - case flag_subx: - printf ("\tSET_VFLG ((flgs ^ flgo) & (flgo ^ flgn));\n"); /* minterm SON: 0x24 */ - printf ("\tSET_CFLG (flgs ^ ((flgs ^ flgn) & (flgo ^ flgn)));\n"); /* minterm SON: 0xB2 */ - duplicate_carry (0); - break; - case flag_cmp: - printf ("\tSET_ZFLG (%s == 0);\n", vstr); - printf ("\tSET_VFLG ((flgs != flgo) && (flgn != flgo));\n"); - printf ("\tSET_CFLG (%s > %s);\n", usstr, udstr); - printf ("\tSET_NFLG (flgn != 0);\n"); - break; - } -} - -static void genflags (flagtypes type, wordsizes size, const char *value, const char *src, const char *dst) -{ - /* Temporarily deleted 68k/ARM flag optimizations. I'd prefer to have - them in the appropriate m68k.h files and use just one copy of this - code here. The API can be changed if necessary. */ - if (optimized_flags) { - switch (type) { - case flag_add: - case flag_sub: - start_brace (); - printf ("\tuae_u32 %s;\n", value); - break; - - default: - break; - } - - /* At least some of those casts are fairly important! */ - switch (type) { - case flag_logical_noclobber: - printf ("\t{uae_u32 oldcznv = GET_CZNV & ~(FLAGVAL_Z | FLAGVAL_N);\n"); - if (strcmp (value, "0") == 0) { - printf ("\tSET_CZNV (olcznv | FLAGVAL_Z);\n"); - } else { - switch (size) { - case sz_byte: printf ("\toptflag_testb (regs, (uae_s8)(%s));\n", value); break; - case sz_word: printf ("\toptflag_testw (regs, (uae_s16)(%s));\n", value); break; - case sz_long: printf ("\toptflag_testl (regs, (uae_s32)(%s));\n", value); break; - } - printf ("\tIOR_CZNV (oldcznv);\n"); - } - printf ("\t}\n"); - return; - case flag_logical: - if (strcmp (value, "0") == 0) { - printf ("\tSET_CZNV (FLAGVAL_Z);\n"); - } else { - switch (size) { - case sz_byte: printf ("\toptflag_testb (regs, (uae_s8)(%s));\n", value); break; - case sz_word: printf ("\toptflag_testw (regs, (uae_s16)(%s));\n", value); break; - case sz_long: printf ("\toptflag_testl (regs, (uae_s32)(%s));\n", value); break; - } - } - return; - - case flag_add: - switch (size) { - case sz_byte: printf ("\toptflag_addb (regs, %s, (uae_s8)(%s), (uae_s8)(%s));\n", value, src, dst); break; - case sz_word: printf ("\toptflag_addw (regs, %s, (uae_s16)(%s), (uae_s16)(%s));\n", value, src, dst); break; - case sz_long: printf ("\toptflag_addl (regs, %s, (uae_s32)(%s), (uae_s32)(%s));\n", value, src, dst); break; - } - return; - - case flag_sub: - switch (size) { - case sz_byte: printf ("\toptflag_subb (regs, %s, (uae_s8)(%s), (uae_s8)(%s));\n", value, src, dst); break; - case sz_word: printf ("\toptflag_subw (regs, %s, (uae_s16)(%s), (uae_s16)(%s));\n", value, src, dst); break; - case sz_long: printf ("\toptflag_subl (regs, %s, (uae_s32)(%s), (uae_s32)(%s));\n", value, src, dst); break; - } - return; - - case flag_cmp: - switch (size) { - case sz_byte: printf ("\toptflag_cmpb (regs, (uae_s8)(%s), (uae_s8)(%s));\n", src, dst); break; - case sz_word: printf ("\toptflag_cmpw (regs, (uae_s16)(%s), (uae_s16)(%s));\n", src, dst); break; - case sz_long: printf ("\toptflag_cmpl (regs, (uae_s32)(%s), (uae_s32)(%s));\n", src, dst); break; - } - return; - - default: - break; - } - } - - genflags_normal (type, size, value, src, dst); -} - static void force_range_for_rox (const char *var, wordsizes size) { /* Could do a modulo operation here... which one is faster? */ @@ -4255,8 +4405,17 @@ static void gen_opcode (unsigned int opcode) prefetch_done = 1; } - if (curi->mnemo == i_MOVE) - genflags(flag_logical, curi->size, "src", "", ""); + int storeflags = 0; + + if (curi->mnemo == i_MOVE) { + if (curi->size == sz_long && cpu_level <= 1 && (using_prefetch || using_ce) && curi->dmode >= Aind) { + // to support bus error exception correct flags, flags needs to be set + // after first word has been written. + storeflags = GF_SECONDWORDSETFLAGS; + } else { + genflags(flag_logical, curi->size, "src", "", ""); + } + } if (curi->size == sz_long) { if ((curi->dmode == Ad16 || curi->dmode == PC16) && curi->smode == imm) { @@ -4268,9 +4427,9 @@ static void gen_opcode (unsigned int opcode) } // MOVE EA,-(An) long writes are always reversed. Reads are normal. if (curi->dmode == Apdi && curi->size == sz_long) { - genastore_rev("src", curi->dmode, "dstreg", curi->size, "dst"); + genastore_2("src", curi->dmode, "dstreg", curi->size, "dst", 1, storeflags); } else { - genastore("src", curi->dmode, "dstreg", curi->size, "dst"); + genastore_2("src", curi->dmode, "dstreg", curi->size, "dst", 0, storeflags); } sync_m68k_pc (); if (dualprefetch) { @@ -6995,6 +7154,8 @@ int main(int argc, char *argv[]) headerfile = fopen("cputbl.h", "wb"); + fprintf(headerfile, "#define BUS_ERROR_EMULATION %d\n", using_bus_error); + stblfile = fopen("cpustbl.cpp", "wb"); generate_includes(stblfile, 0); diff --git a/newcpu_common.cpp b/newcpu_common.cpp index 7dbb4908..ecb4f97f 100644 --- a/newcpu_common.cpp +++ b/newcpu_common.cpp @@ -1567,7 +1567,7 @@ void cpu_restore_fixup(void) } } -// Low word: Z and N +// Low word: Clear + Z and N void ccr_68000_long_move_ae_LZN(uae_s32 src) { CLEAR_CZNV(); @@ -1576,7 +1576,7 @@ void ccr_68000_long_move_ae_LZN(uae_s32 src) SET_NFLG(vsrc < 0); } -// Low word: N only +// Low word: Clear + N only void ccr_68000_long_move_ae_LN(uae_s32 src) { CLEAR_CZNV();