From: Toni Wilen Date: Sat, 15 Feb 2020 12:28:19 +0000 (+0200) Subject: Fix bus/address error timing. MOVE write address error fix. X-Git-Tag: 4400~126 X-Git-Url: https://git.unchartedbackwaters.co.uk/w/?a=commitdiff_plain;h=44b186a46a25781ee43cd6966d6a1e95c772423b;p=francis%2Fwinuae.git Fix bus/address error timing. MOVE write address error fix. --- diff --git a/cputest/main.c b/cputest/main.c index 9c9217f1..cbcbe236 100644 --- a/cputest/main.c +++ b/cputest/main.c @@ -1715,7 +1715,7 @@ static int getexceptioncycles(int exc) { case 2: case 3: - return 56; + return 54; case 4: case 5: case 6: @@ -1743,7 +1743,7 @@ static int getexceptioncycles(int exc) { case 2: case 3: - return 132; + return 130; case 4: case 5: case 6: @@ -1888,8 +1888,13 @@ static int check_cycles(int exc, short extratrace, short extrag2w1) } // address error during group 2 exception stacking (=odd exception vector) if (extrag2w1) { - // 4 idle, write pc low, write sr, write pc high, read vector high, read vector low - expectedcycles += 6 * 4; + // 4 idle, write pc low, write sr, write pc high, read vector high, read vector low, + // exception vector fetch that generates address error + expectedcycles += 7 * 4; + if (extrag2w1 == 7) { + // TRAPV has no startup idle cycles + expectedcycles -= 4; + } if (cpu_lvl == 1) { // 68010: frame type expectedcycles += 4; @@ -1898,6 +1903,7 @@ static int check_cycles(int exc, short extratrace, short extrag2w1) // interrupt expectedcycles += 2 + 4 + 4; } + exceptioncount[0][extrag2w1]++; } if (0 || abs(gotcycles - expectedcycles) > cycles_range) { diff --git a/gencpu.cpp b/gencpu.cpp index c6ac67b9..76bf9b84 100644 --- a/gencpu.cpp +++ b/gencpu.cpp @@ -86,7 +86,8 @@ static int optimized_flags; #define GF_SECONDEA 0x08000 #define GF_NOFETCH 0x10000 // 68010 #define GF_CLR68010 0x20000 // 68010 -#define GF_NOEXC 0x40000 +#define GF_NOEXC3 0x40000 +#define GF_EXC3 0x80000 typedef enum { @@ -2654,10 +2655,13 @@ static void move_68000_address_error(int size, int *setapdi, int *fcmodeflags) if (dmode == Apdi) { addcycles000_onlyce(2); addcycles000_nonce(2); + } else if (dmode == Aipi) { + // move.x x,(an)+: an is not increased + out("m68k_areg(regs, dstreg) -= %d;\n", 1 << size); } if (size == sz_word) { - // Word MOVE is relatively simply + // Word MOVE is relatively simple int set_ccr = 0; switch(smode) { @@ -2679,13 +2683,6 @@ static void move_68000_address_error(int size, int *setapdi, int *fcmodeflags) set_ccr = 1; break; } - if (dmode == Apdi) { - // partial prefetch already done - out("regs.ir = regs.irc;\n"); - // if trace, I/N is also set - out("if(regs.t1) opcode |= 0x10000;\n"); - - } if (set_ccr) { out("ccr_68000_word_move_ae_normal((uae_s16)(src));\n"); } @@ -2734,6 +2731,8 @@ static void move_68000_address_error(int size, int *setapdi, int *fcmodeflags) if (dmode == Apdi) { *setapdi = 0; + out("m68k_areg(regs, dstreg) += 4;\n"); + out("regs.ir = opcode;\n"); } if (set_low_word == 1) { @@ -2759,7 +2758,7 @@ static void move_68010_address_error(int size, int *setapdi, int *fcmodeflags) int dmode = g_instr->dmode; if (size == sz_word) { - // Word MOVE is relatively simply + // Word MOVE is relatively simple int set_ccr = 0; switch (smode) { @@ -2856,6 +2855,108 @@ static void move_68010_address_error(int size, int *setapdi, int *fcmodeflags) } } +static void check_address_error(const char *name, int mode, const char *reg, int size, int getv, int movem, int flags) +{ + // check possible address error (if 68000/010 and enabled) + if ((using_prefetch || using_ce) && using_exception_3 && getv != 0 && getv != 3 && size != sz_byte && !movem && !(flags & GF_NOEXC3)) { + int setapdiback = 0; + int fcmodeflags = 0; + int exp3rw = getv == 2; + + next_level_000(); + + out("if (%sa & 1) {\n", name); + + if (cpu_level == 1) { + int bus_error_reg_add_old = bus_error_reg_add; + if (abs(bus_error_reg_add) == 4) + bus_error_reg_add = 0; + // 68010 CLR : pre and post are not added yet + if (g_instr->mnemo == i_CLR) { + if (mode == Aipi) + bus_error_reg_add = 0; + if (mode == Apdi) + bus_error_reg_add = 0; + } + if (g_instr->mnemo == i_MOVE || g_instr->mnemo == i_MOVEA) { + if (getv != 2) { + do_bus_error_fixes(name, 0, getv == 2); + } + } else { + do_bus_error_fixes(name, 0, getv == 2); + } + // x,-(an): an is modified (MOVE to CCR counts as word sized) + if (mode == Apdi && (g_instr->size == sz_word || g_instr->size == i_MV2SR) && g_instr->mnemo != i_CLR) { + out("m68k_areg(regs, %s) = %sa;\n", reg, name); + } + bus_error_reg_add = bus_error_reg_add_old; + } + + if (g_instr->mnemo == i_ADDX || g_instr->mnemo == i_SUBX) { + // ADDX/SUBX special case + if (g_instr->size == sz_word) { + out("m68k_areg(regs, %s) = %sa;\n", reg, name); + } + } else if (mode == Apdi && g_instr->mnemo != i_LINK) { + // 68000 decrements register first, then checks for address error + // 68010 does not + if (cpu_level == 0) + setapdiback = 1; + } + + + if (exception_pc_offset) { + incpc("%d", exception_pc_offset); + } + + if (g_instr->mnemo == i_MOVE) { + if (getv == 2) { + if (cpu_level == 0) { + move_68000_address_error(size, &setapdiback, &fcmodeflags); + } else { + move_68010_address_error(size, &setapdiback, &fcmodeflags); + } + } + } else if (g_instr->mnemo == i_MVSR2) { + // If MOVE from SR generates address error exception, + // Change it to read because it does dummy read first. + exp3rw = 0; + if (cpu_level == 1) { + out("opcode |= 0x20000;\n"); // upper byte of SSW is zero -flag. + } + } else if (g_instr->mnemo == i_LINK) { + // a7 -> a0 copy done before A7 address error check + out("m68k_areg(regs, srcreg) = olda;\n"); + setapdiback = 0; + } + + if (setapdiback) { + out("m68k_areg(regs, %s) = %sa;\n", reg, name); + } + + // MOVE.L EA,-(An) causing address error: stacked value is original An - 2, not An - 4. + if ((flags & (GF_REVERSE | GF_REVERSE2)) && size == sz_long && mode == Apdi) + out("%sa += %d;\n", name, flags & GF_REVERSE2 ? -2 : 2); + + if (exp3rw) { + const char *shift = (size == sz_long && !(flags & GF_REVERSE)) ? " >> 16" : ""; + out("exception3_write_opcode(opcode, %sa, %d, %s%s, %d);\n", + name, size, g_srcname, shift, + // PC-relative: FC=2 + (getv == 1 && (g_instr->smode == PC16 || g_instr->smode == PC8r) ? 2 : 1) | fcmodeflags); + + } else { + out("exception3_read_opcode(opcode, %sa, %d, %d);\n", + name, size, + // PC-relative: FC=2 + (getv == 1 && (g_instr->smode == PC16 || g_instr->smode == PC8r) ? 2 : 1) | fcmodeflags); + } + + write_return_cycles_noadd(0); + out("}\n"); + } +} + /* getv == 1: fetch data; getv != 0: check for odd address. If movem != 0, * the calling routine handles Apdi and Aipi modes. * gb-- movem == 2 means the same thing but for a MOVE16 instruction */ @@ -3246,102 +3347,8 @@ static void genamode2x (amodes mode, const char *reg, wordsizes size, const char exception_pc_offset = pc_68000_offset + pc_68000_offset_fetch; } - // check possible address error (if 68000/010 and enabled) - if ((using_prefetch || using_ce) && using_exception_3 && getv != 0 && getv != 3 && size != sz_byte && !movem && !(flags & GF_NOEXC)) { - int setapdiback = 0; - int fcmodeflags = 0; - int exp3rw = getv == 2; - - next_level_000(); - - out("if (%sa & 1) {\n", name); - - if (cpu_level == 1) { - int bus_error_reg_add_old = bus_error_reg_add; - if (abs(bus_error_reg_add) == 4) - bus_error_reg_add = 0; - // 68010 CLR : pre and post are not added yet - if (g_instr->mnemo == i_CLR) { - if (mode == Aipi) - bus_error_reg_add = 0; - if (mode == Apdi) - bus_error_reg_add = 0; - } - if (g_instr->mnemo == i_MOVE || g_instr->mnemo == i_MOVEA) { - if (getv != 2) { - do_bus_error_fixes(name, 0, getv == 2); - } - } else { - do_bus_error_fixes(name, 0, getv == 2); - } - // x,-(an): an is modified (MOVE to CCR counts as word sized) - if (mode == Apdi && (g_instr->size == sz_word || g_instr->size == i_MV2SR) && g_instr->mnemo != i_CLR) { - out("m68k_areg(regs, %s) = %sa;\n", reg, name); - } - bus_error_reg_add = bus_error_reg_add_old; - } - - if (g_instr->mnemo == i_ADDX || g_instr->mnemo == i_SUBX) { - // ADDX/SUBX special case - if (g_instr->size == sz_word) { - out("m68k_areg(regs, %s) = %sa;\n", reg, name); - } - } else if (mode == Apdi && g_instr->mnemo != i_LINK) { - // 68000 decrements register first, then checks for address error - // 68010 does not - if (cpu_level == 0) - setapdiback = 1; - } - - - if (exception_pc_offset) - incpc("%d", exception_pc_offset); - - if (g_instr->mnemo == i_MOVE) { - if (getv == 2) { - if (cpu_level == 0) { - move_68000_address_error(size, &setapdiback, &fcmodeflags); - } else { - move_68010_address_error(size, &setapdiback, &fcmodeflags); - } - } - } else if (g_instr->mnemo == i_MVSR2) { - // If MOVE from SR generates address error exception, - // Change it to read because it does dummy read first. - exp3rw = 0; - if (cpu_level == 1) { - out("opcode |= 0x20000;\n"); // upper byte of SSW is zero -flag. - } - } else if (g_instr->mnemo == i_LINK) { - // a7 -> a0 copy done before A7 address error check - out("m68k_areg(regs, srcreg) = olda;\n"); - setapdiback = 0; - } - - if (setapdiback) { - out("m68k_areg(regs, %s) = %sa;\n", reg, name); - } - - // MOVE.L EA,-(An) causing address error: stacked value is original An - 2, not An - 4. - if ((flags & (GF_REVERSE | GF_REVERSE2)) && size == sz_long && mode == Apdi) - out("%sa += %d;\n", name, flags & GF_REVERSE2 ? -2 : 2); - - if (exp3rw) { - const char *shift = (size == sz_long && !(flags & GF_REVERSE)) ? " >> 16" : ""; - out("exception3_write_opcode(opcode, %sa, %d, %s%s, %d);\n", - name, size, g_srcname, shift, - // PC-relative: FC=2 - (getv == 1 && (g_instr->smode == PC16 || g_instr->smode == PC8r) ? 2 : 1) | fcmodeflags); - - } else { - out("exception3_read_opcode(opcode, %sa, %d, %d);\n", - name, size, - // PC-relative: FC=2 - (getv == 1 && (g_instr->smode == PC16 || g_instr->smode == PC8r) ? 2 : 1) | fcmodeflags); - } - - write_return_cycles_noadd(0); - out("}\n"); + if (!(flags & GF_NOEXC3)) { + check_address_error(name, mode, reg, size, getv, movem, flags); } if (flags & GF_PREFETCH) @@ -3583,6 +3590,10 @@ static void genastore_2 (const char *from, amodes mode, const char *reg, wordsiz returntail(mode != Dreg && mode != Areg); } + if ((flags & GF_EXC3) && !isreg(mode)) { + check_address_error(to, mode, reg, size, 2, 0, flags); + } + switch (mode) { case Dreg: switch (size) { @@ -5959,7 +5970,7 @@ static void gen_opcode (unsigned int opcode) } } - genamode(curi, curi->dmode, "dstreg", curi->size, "dst", 2, 0, flags); + genamode(curi, curi->dmode, "dstreg", curi->size, "dst", 2, 0, flags | GF_NOEXC3); if (curi->mnemo == i_MOVEA && curi->size == sz_word) out("src = (uae_s32)(uae_s16)src;\n"); @@ -5994,13 +6005,13 @@ static void gen_opcode (unsigned int opcode) } } - int storeflags = 0; + int storeflags = flags & (GF_REVERSE | GF_APDI); 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; + storeflags |= GF_SECONDWORDSETFLAGS; } else { genflags(flag_logical, curi->size, "src", "", ""); } @@ -6011,9 +6022,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_2("src", curi->dmode, "dstreg", curi->size, "dst", 1, storeflags); + genastore_2("src", curi->dmode, "dstreg", curi->size, "dst", 1, storeflags | GF_EXC3); } else { - genastore_2("src", curi->dmode, "dstreg", curi->size, "dst", 0, storeflags); + genastore_2("src", curi->dmode, "dstreg", curi->size, "dst", 0, storeflags | GF_EXC3); } sync_m68k_pc(); if (dualprefetch) { @@ -6497,11 +6508,11 @@ static void gen_opcode (unsigned int opcode) addop_ce020(curi, 0, 0); // smode must be first in case it is A7. Except if 68040! if (cpu_level == 4) { - genamode(NULL, Apdi, "7", sz_long, "old", 2, 0, GF_AA | GF_NOEXC); + genamode(NULL, Apdi, "7", sz_long, "old", 2, 0, GF_AA | GF_NOEXC3); genamode(NULL, curi->smode, "srcreg", sz_long, "src", 1, 0, GF_AA); } else { genamode(NULL, curi->smode, "srcreg", sz_long, "src", 1, 0, GF_AA); - genamode(NULL, Apdi, "7", sz_long, "old", 2, 0, GF_AA | GF_NOEXC); + genamode(NULL, Apdi, "7", sz_long, "old", 2, 0, GF_AA | GF_NOEXC3); } strcpy(bus_error_code, "m68k_areg(regs, 7) += 4;\n"); genamode(NULL, curi->dmode, "dstreg", curi->size, "offs", 1, 0, 0); @@ -7039,7 +7050,7 @@ bccl_not68020: out("uae_u16 old_opcode = opcode;\n"); } genamode(curi, curi->smode, "srcreg", curi->size, "src", 0, 0, GF_AA); - genamode(NULL, Apdi, "7", sz_long, "dst", 2, 0, GF_AA | GF_NOEXC); + genamode(NULL, Apdi, "7", sz_long, "dst", 2, 0, GF_AA | GF_NOEXC3); if (curi->smode == Ad8r || curi->smode == PC8r) addcycles000(2); if (!(curi->smode == absw || curi->smode == absl)) @@ -8928,7 +8939,7 @@ static void generate_cpu_test(int mode) for (rp = 0; rp < nr_cpuop_funcs; rp++) opcode_next_clev[rp] = cpu_level; - out("#include \"cputest.h\"\n"); + printf("#include \"cputest.h\"\n"); if (!mode) { fprintf(stblfile, "#include \"cputest.h\"\n"); } diff --git a/newcpu.cpp b/newcpu.cpp index 3804df2e..e3e02ea2 100644 --- a/newcpu.cpp +++ b/newcpu.cpp @@ -2370,7 +2370,6 @@ Address/Bus Error: - write fault address low word - write status code - write fault address high word -- 2 idle cycles - read exception address high word - read exception address low word - prefetch @@ -2415,7 +2414,7 @@ TrapV: CHK: -- 4 idle cycles (EA + 4 cycles in cpuemu) +- 4 idle cycles (EA + 4/6 cycles in cpuemu) - write PC low word - write SR - write PC high word @@ -2537,7 +2536,6 @@ static void Exception_ce000 (int nr) x_put_word(m68k_areg(regs, 7) + 4, last_fault_for_exception_3); x_put_word(m68k_areg(regs, 7) + 0, mode); x_put_word(m68k_areg(regs, 7) + 2, last_fault_for_exception_3 >> 16); - x_do_cycles(2 * cpucycleunit); goto kludge_me_do; } else { // 68010 bus/address error (partially implemented only) @@ -2821,8 +2819,8 @@ static void add_approximate_exception_cycles(int nr) } else { switch (nr) { - case 2: cycles = 56; break; /* Bus error */ - case 3: cycles = 56; break; /* Address error */ + case 2: cycles = 54; break; /* Bus error */ + case 3: cycles = 54; break; /* Address error */ case 4: cycles = 34; break; /* Illegal instruction */ case 5: cycles = 34; break; /* Division by zero */ case 6: cycles = 34; break; /* CHK */ @@ -2846,8 +2844,8 @@ static void add_approximate_exception_cycles(int nr) } else { switch (nr) { - case 2: cycles = 132; break; /* Bus error */ - case 3: cycles = 132; break; /* Address error */ + case 2: cycles = 130; break; /* Bus error */ + case 3: cycles = 130; break; /* Address error */ case 4: cycles = 38; break; /* Illegal instruction */ case 5: cycles = 38; break; /* Division by zero */ case 6: cycles = 38; break; /* CHK */