]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
Fix bus/address error timing. MOVE write address error fix.
authorToni Wilen <twilen@winuae.net>
Sat, 15 Feb 2020 12:28:19 +0000 (14:28 +0200)
committerToni Wilen <twilen@winuae.net>
Sat, 15 Feb 2020 12:28:19 +0000 (14:28 +0200)
cputest/main.c
gencpu.cpp
newcpu.cpp

index 9c9217f1f22d7c36f4196bd14175b06183e8684d..cbcbe236ad46aac19c6835574eddfc97c42ffa3a 100644 (file)
@@ -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) {
index c6ac67b92965e3f7c4c19f4de08b8e801c28487b..76bf9b84c42e95999a4510e5bafb09f62860e5a8 100644 (file)
@@ -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 <memory>: 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 <memory>: 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");
        }
index 3804df2e6163822de55ab1ebc75c510a818f27bd..e3e02ea2437d8005fb752eb3a69a7d5308748d9c 100644 (file)
@@ -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 */