]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
68000 prefetch bus error stacked PC fix.
authorToni Wilen <twilen@winuae.net>
Sat, 16 May 2020 15:39:27 +0000 (18:39 +0300)
committerToni Wilen <twilen@winuae.net>
Sat, 16 May 2020 15:39:27 +0000 (18:39 +0300)
gencpu.cpp
include/newcpu.h
newcpu.cpp

index 4a4f95dc2e333946060c3e7c5e662efe75645162..67a6f8c835d7030abf1128ad07d1b3828ac6f332 100644 (file)
@@ -88,6 +88,10 @@ static int optimized_flags;
 #define GF_CLR68010    0x20000 // 68010
 #define GF_NOEXC3      0x40000
 #define GF_EXC3                0x80000
+// internal PC is 2 less than address being prefetched.
+#define GF_PCM2                0x100000
+// internal PC is 2 more than address being prefetched.
+#define GF_PCP2                0x200000
 
 typedef enum
 {
@@ -800,6 +804,77 @@ static void end_mmu040_movem(void)
        mmu040_movem = 0;
 }
 
+static void setpcstring(char *dst, const char *format, ...)
+{
+       va_list parms;
+       char buffer[1000];
+
+       va_start(parms, format);
+       _vsnprintf(buffer, 1000 - 1, format, parms);
+       va_end(parms);
+
+       if (using_mmu)
+               sprintf(dst, "m68k_setpci(%s);\n", buffer);
+       else if (using_prefetch || using_prefetch_020 || using_test)
+               sprintf(dst, "m68k_setpci_j(%s);\n", buffer);
+       else
+               sprintf(dst, "m68k_setpc_j(%s);\n", buffer);
+}
+
+static void setpc(const char *format, ...)
+{
+       va_list parms;
+       char buffer[1000];
+
+       va_start(parms, format);
+       _vsnprintf(buffer, 1000 - 1, format, parms);
+       va_end(parms);
+
+       if (using_mmu)
+               out("m68k_setpci(%s);\n", buffer);
+       else if (using_prefetch || using_prefetch_020 || using_test)
+               out("m68k_setpci_j(%s);\n", buffer);
+       else
+               out("m68k_setpc_j(%s);\n", buffer);
+}
+
+static void incpc(const char *format, ...)
+{
+       va_list parms;
+       char buffer[1000];
+
+       va_start(parms, format);
+       _vsnprintf(buffer, 1000 - 1, format, parms);
+       va_end(parms);
+
+       if (using_mmu || using_prefetch || using_prefetch_020 || using_test)
+               out("m68k_incpci(%s);\n", buffer);
+       else
+               out("m68k_incpc(%s);\n", buffer);
+}
+
+static void sync_m68k_pc(void)
+{
+       m68k_pc_offset_old = m68k_pc_offset;
+       if (m68k_pc_offset == 0)
+               return;
+       incpc("%d", m68k_pc_offset);
+       m68k_pc_total += m68k_pc_offset;
+       m68k_pc_offset = 0;
+}
+
+static void clear_m68k_offset(void)
+{
+       m68k_pc_total += m68k_pc_offset;
+       m68k_pc_offset = 0;
+}
+
+static void sync_m68k_pc_noreset(void)
+{
+       sync_m68k_pc();
+       m68k_pc_offset = m68k_pc_offset_old;
+}
+
 static char bus_error_text[200];
 static int bus_error_specials;
 static int bus_error_cycles;
@@ -813,6 +888,7 @@ static void do_instruction_buserror(void)
 
        if (bus_error_text[0]) {
                out("if(hardware_bus_error) {\n");
+               out("int pcoffset = 0;\n");
                if (bus_error_code[0])
                        out("%s", bus_error_code);
                out("%s", bus_error_text);
@@ -823,7 +899,7 @@ static void do_instruction_buserror(void)
        bus_error_specials = 0;
 }
 
-static void check_bus_error_ins(int offset)
+static void check_bus_error_ins(int offset, int pcoffset)
 {
        const char *opcode;
        if (bus_error_specials) {
@@ -831,10 +907,14 @@ static void check_bus_error_ins(int offset)
        } else {
                opcode = "opcode";
        }
-       sprintf(bus_error_text, "exception2_fetch(%s, %d);\n", opcode, offset);
+       if (pcoffset == -1) {
+               sprintf(bus_error_text, "exception2_fetch(%s, %d, pcoffset);\n", opcode, offset);
+       } else {
+               sprintf(bus_error_text, "exception2_fetch(%s, %d, %d);\n", opcode, offset, pcoffset);
+       }
 }
 
-static void check_bus_error_ins_opcode(int offset)
+static void check_bus_error_ins_opcode(int offset, int pcoffset)
 {
        const char *opcode;
        if (bus_error_specials) {
@@ -842,10 +922,14 @@ static void check_bus_error_ins_opcode(int offset)
        } else {
                opcode = "opcode";
        }
-       sprintf(bus_error_text, "exception2_fetch_opcode(%s, %d);\n", opcode, offset);
+       if (pcoffset == -1) {
+               sprintf(bus_error_text, "exception2_fetch_opcode(%s, %d, pcoffset);\n", opcode, offset);
+       } else {
+               sprintf(bus_error_text, "exception2_fetch_opcode(%s, %d, %d);\n", opcode, offset, pcoffset);
+       }
 }
 
-static void check_prefetch_bus_error(int offset, int secondprefetchmode)
+static void check_prefetch_bus_error(int offset, int pcoffset, int secondprefetchmode)
 {
        if (!needbuserror())
                return;
@@ -860,20 +944,21 @@ static void check_prefetch_bus_error(int offset, int secondprefetchmode)
                        bus_error_specials = 1;
                }
        }
-       check_bus_error_ins_opcode(offset);
+       check_bus_error_ins_opcode(offset, pcoffset);
        do_instruction_buserror();
 }
 
-static void check_prefetch_buserror(int offset)
+static void check_prefetch_buserror(int offset, int pcoffset)
 {
-       check_bus_error_ins(offset);
+       check_bus_error_ins(offset, pcoffset);
        do_instruction_buserror();
 }
 
 
-static void gen_nextilong2 (const char *type, const char *name, int flags, int movem)
+static void gen_nextilong2(const char *type, const char *name, int flags, int movem)
 {
        int r = m68k_pc_offset;
+       int pcoffset = ((flags & (GF_PCM2 | GF_PCP2)) == (GF_PCM2 | GF_PCP2) ? 0 : (((flags & GF_PCM2) ? -2 : (flags & GF_PCP2) ? 2 : 0)));
        m68k_pc_offset += 4;
 
        out("%s %s;\n", type, name);
@@ -891,7 +976,7 @@ static void gen_nextilong2 (const char *type, const char *name, int flags, int m
                        out("%s = %s(%d) << 16;\n", name, prefetch_word, r + 2);
                        count_readw++;
                        out("%s |= regs.irc;\n", name);
-                       check_bus_error_ins(r + 2);
+                       check_bus_error_ins(r + 2, pcoffset);
                        do_instruction_buserror();
                        strcpy(bus_error_code, bus_error_code2);
                        bus_error_code2[0] = 0;
@@ -899,14 +984,14 @@ static void gen_nextilong2 (const char *type, const char *name, int flags, int m
                } else {
                        out("%s = %s(%d) << 16;\n", name, prefetch_word, r + 2);
                        count_readw++;
-                       check_bus_error_ins(r + 2);
+                       check_bus_error_ins(r + 2, pcoffset);
                        do_instruction_buserror();
                        strcpy(bus_error_code, bus_error_code2);
                        bus_error_code2[0] = 0;
                        set_last_access();
                        out("%s |= %s(%d);\n", name, prefetch_word, r + 4);
                        count_readw++;
-                       check_bus_error_ins(r + 4);
+                       check_bus_error_ins(r + 4, -1);
                }
        } else if (using_prefetch) {
                if (flags & GF_NOREFILL) {
@@ -914,7 +999,7 @@ static void gen_nextilong2 (const char *type, const char *name, int flags, int m
                        out("%s = %s(%d) << 16;\n", name, prefetch_word, r + 2);
                        count_readw++;
                        out("%s |= regs.irc;\n", name);
-                       check_bus_error_ins(r + 2);
+                       check_bus_error_ins(r + 2, pcoffset);
                        do_instruction_buserror();
                        strcpy(bus_error_code, bus_error_code2);
                        bus_error_code2[0] = 0;
@@ -922,14 +1007,14 @@ static void gen_nextilong2 (const char *type, const char *name, int flags, int m
                } else {
                        out("%s = %s(%d) << 16;\n", name, prefetch_word, r + 2);
                        count_readw++;
-                       check_bus_error_ins(r + 2);
+                       check_bus_error_ins(r + 2, pcoffset);
                        do_instruction_buserror();
                        strcpy(bus_error_code, bus_error_code2);
                        bus_error_code2[0] = 0;
                        set_last_access();
                        out("%s |= %s(%d);\n", name, prefetch_word, r + 4);
                        count_readw++;
-                       check_bus_error_ins(r + 4);
+                       check_bus_error_ins(r + 4, -1);
                }
        } else {
                if (flags & GF_NOREFILL) {
@@ -949,10 +1034,11 @@ static void gen_nextilong (const char *type, const char *name, int flags)
        gen_nextilong2 (type, name, flags, 0);
 }
 
-static const char *gen_nextiword (int flags)
+static const char *gen_nextiword(int flags)
 {
        static char buffer[80];
        int r = m68k_pc_offset;
+       int pcoffset = ((flags & (GF_PCM2 | GF_PCP2)) == (GF_PCM2 | GF_PCP2) ? 0 : (((flags & GF_PCM2) ? -2 : (flags & GF_PCP2) ? 2 : 0)));
        m68k_pc_offset += 2;
 
        bus_error_text[0] = 0;
@@ -970,7 +1056,7 @@ static const char *gen_nextiword (int flags)
                        set_last_access();
                        sprintf(buffer, "%s(%d)", prefetch_word, r + 2);
                        count_readw++;
-                       check_bus_error_ins(r + 2);
+                       check_bus_error_ins(r + 2, pcoffset);
                }
        } else if (using_prefetch) {
                if (flags & GF_NOREFILL) {
@@ -979,23 +1065,24 @@ static const char *gen_nextiword (int flags)
                        set_last_access();
                        sprintf(buffer, "%s(%d)", prefetch_word, r + 2);
                        count_readw++;
-                       check_bus_error_ins(r + 2);
+                       check_bus_error_ins(r + 2, pcoffset);
                }
        } else {
                sprintf(buffer, "%s(%d)", prefetch_word, r);
                if (!(flags & GF_NOREFILL)) {
                        count_readw++;
                        count_readp++;
-                       check_bus_error_ins(r);
+                       check_bus_error_ins(r, pcoffset);
                }
        }
        return buffer;
 }
 
-static const char *gen_nextibyte (int flags)
+static const char *gen_nextibyte(int flags)
 {
        static char buffer[80];
        int r = m68k_pc_offset;
+       int pcoffset = ((flags & (GF_PCM2 | GF_PCP2)) == (GF_PCM2 | GF_PCP2) ? 0 : (((flags & GF_PCM2) ? -2 : (flags & GF_PCP2) ? 2 : 0)));
        m68k_pc_offset += 2;
 
        bus_error_text[0] = 0;
@@ -1013,7 +1100,7 @@ static const char *gen_nextibyte (int flags)
                        set_last_access();
                        sprintf(buffer, "(uae_u8)%s(%d)", prefetch_word, r + 2);
                        count_readw++;
-                       check_bus_error_ins(r + 2);
+                       check_bus_error_ins(r + 2, pcoffset);
                }
        } else if (using_prefetch) {
                if (flags & GF_NOREFILL) {
@@ -1022,14 +1109,14 @@ static const char *gen_nextibyte (int flags)
                        set_last_access();
                        sprintf(buffer, "(uae_u8)%s(%d)", prefetch_word, r + 2);
                        count_readw++;
-                       check_bus_error_ins(r + 2);
+                       check_bus_error_ins(r + 2, pcoffset);
                }
        } else {
                sprintf(buffer, "%s(%d)", srcbi, r);
                if (!(flags & GF_NOREFILL)) {
                        count_readw++;
                        count_readp++;
-                       check_bus_error_ins(r);
+                       check_bus_error_ins(r, pcoffset);
                }
        }
        return buffer;
@@ -1089,7 +1176,7 @@ static void fill_prefetch_bcc(void)
        set_last_access();
        out("%s(%d);\n", prefetch_word, m68k_pc_offset + 2);
        count_readw++;
-       check_prefetch_bus_error(m68k_pc_offset + 2, 0);
+       check_prefetch_bus_error(m68k_pc_offset + 2, -1, 0);
        did_prefetch = 1;
        ir2irc = 0;
 }
@@ -1104,7 +1191,7 @@ static void fill_prefetch_1(int o)
                } else {
                        addcycles000_nonce(4);
                }
-               check_prefetch_bus_error(o, 0);
+               check_prefetch_bus_error(o, -1, 0);
                did_prefetch = 1;
                ir2irc = 0;
        } else {
@@ -1119,7 +1206,7 @@ static void fill_prefetch_1_empty(int o)
                set_last_access();
                out("%s(%d);\n", prefetch_word, o);
                count_readw++;
-               check_prefetch_bus_error(o ? -2 : -1, 0);
+               check_prefetch_bus_error(o ? -2 : -1, 0, 0);
                did_prefetch = 1;
                ir2irc = 0;
        } else {
@@ -1230,8 +1317,13 @@ static void fill_prefetch_full(int beopcode)
        }
 }
 
-static void fill_prefetch_full_000_special(const char *format, ...)
+// 0 = pc not changed
+// 1 = pc == oldpc + 2, both address and PC
+// 2 = pc not changed, stacked PC is oldpc + 2
+// -1 = first fetch: pcoffset - adjustment second: pcoffset = 0 (dbcc)
+static void fill_prefetch_full_000_special(int pctype, const char *format, ...)
 {
+       char tmp[100];
        if (!using_prefetch) {
                if (format && cpu_level <= 1) {
                        char outbuf[256];
@@ -1247,7 +1339,16 @@ static void fill_prefetch_full_000_special(const char *format, ...)
 
        out("%s(%d);\n", prefetch_word, 0);
        count_readw++;
-       check_prefetch_bus_error(-1, -1);
+       if (pctype == 1) {
+               setpcstring(tmp, "oldpc + 2");
+               strcpy(bus_error_code, tmp);
+       } else if (pctype == 2) {
+               sprintf(tmp, "pcoffset = oldpc - %s + 2;\n", getpc);
+               strcpy(bus_error_code, tmp);
+       } else if (pctype == -1) {
+               strcpy(bus_error_code, "pcoffset += pcadjust;\n");
+       }
+       check_prefetch_bus_error(-1, -1, -1);
        irc2ir();
        if (using_bus_error) {
                copy_opcode();
@@ -1271,7 +1372,10 @@ static void fill_prefetch_full_000_special(const char *format, ...)
        set_last_access();
        out("%s(%d);\n", prefetch_word, 2);
        count_readw++;
-       check_prefetch_bus_error(-2, -1);
+       if (pctype > 0) {
+               strcpy(bus_error_code, tmp);
+       }
+       check_prefetch_bus_error(-2, -1, -1);
        did_prefetch = 1;
        ir2irc = 0;
 }
@@ -1302,7 +1406,7 @@ static void fill_prefetch_0 (void)
        if (using_prefetch) {
                out("%s(0);\n", prefetch_word);
                count_readw++;
-               check_prefetch_bus_error(0, 0);
+               check_prefetch_bus_error(0, 0, 0);
                did_prefetch = 1;
                ir2irc = 0;
        } else {
@@ -1577,38 +1681,6 @@ static void fill_prefetch_finish (void)
        }
 }
 
-static void setpc (const char *format, ...)
-{
-       va_list parms;
-       char buffer[1000];
-
-       va_start (parms, format);
-       _vsnprintf(buffer, 1000 - 1, format, parms);
-       va_end (parms);
-
-       if (using_mmu)
-               out("m68k_setpci(%s);\n", buffer);
-       else if (using_prefetch || using_prefetch_020 || using_test)
-               out("m68k_setpci_j(%s);\n", buffer);
-       else
-               out("m68k_setpc_j(%s);\n", buffer);
-}
-
-static void incpc (const char *format, ...)
-{
-       va_list parms;
-       char buffer[1000];
-
-       va_start (parms, format);
-       _vsnprintf(buffer, 1000 - 1, format, parms);
-       va_end (parms);
-
-       if (using_mmu || using_prefetch || using_prefetch_020 || using_test)
-               out("m68k_incpci(%s);\n", buffer);
-       else
-               out("m68k_incpc(%s);\n", buffer);
-}
-
 static void dummy_prefetch(const char *newpc, const char *oldpc)
 {
        if (using_prefetch && cpu_level == 1) {
@@ -1630,28 +1702,6 @@ static void dummy_prefetch(const char *newpc, const char *oldpc)
        }
 }
 
-static void sync_m68k_pc (void)
-{
-       m68k_pc_offset_old = m68k_pc_offset;
-       if (m68k_pc_offset == 0)
-               return;
-       incpc ("%d", m68k_pc_offset);
-       m68k_pc_total += m68k_pc_offset;
-       m68k_pc_offset = 0;
-}
-
-static void clear_m68k_offset(void)
-{
-       m68k_pc_total += m68k_pc_offset;
-       m68k_pc_offset = 0;
-}
-
-static void sync_m68k_pc_noreset (void)
-{
-       sync_m68k_pc();
-       m68k_pc_offset = m68k_pc_offset_old;
-}
-
 static void duplicate_carry(void)
 {
        out("COPY_CARRY();\n");
@@ -2160,7 +2210,7 @@ static void check_bus_error(const char *name, int offset, int write, int size, c
 
                if (pcoffset < 0) {
                        incpc("%d", m68k_pc_offset + 2);
-               } else if (exception_pc_offset || exception_pc_offset_extra || pcoffset) {
+               } else if (exception_pc_offset + exception_pc_offset_extra + pcoffset) {
                        incpc("%d", exception_pc_offset + exception_pc_offset_extra + pcoffset);
                }
 
@@ -3123,6 +3173,8 @@ static void genamode2x (amodes mode, const char *reg, wordsizes size, const char
        int pc_68000_offset_fetch = 0;
        int pc_68000_offset_store = 0;
        bool addr = false;
+       // common EA prefetch bus error PC behavior
+       int pcflag = !(flags & (GF_PCM2 | GF_PCP2)) ? GF_PCM2 : 0;
 
        sprintf(namea, "%sa", name);
        if ((flags & GF_RMW) && using_mmu == 68060) {
@@ -3263,7 +3315,7 @@ static void genamode2x (amodes mode, const char *reg, wordsizes size, const char
        case Ad16: // (d16,An)
                out("uaecptr %sa;\n", name);
                start_mmu040_movem(movem);
-               out("%sa = m68k_areg(regs, %s) + (uae_s32)(uae_s16)%s;\n", name, reg, gen_nextiword (flags));
+               out("%sa = m68k_areg(regs, %s) + (uae_s32)(uae_s16)%s;\n", name, reg, gen_nextiword(flags | pcflag));
                count_read_ea++; 
                addr = true;
                break;
@@ -3271,7 +3323,7 @@ static void genamode2x (amodes mode, const char *reg, wordsizes size, const char
                out("uaecptr %sa;\n", name);
                start_mmu040_movem(movem);
                out("%sa = %s + %d;\n", name, getpc, m68k_pc_offset);
-               out("%sa += (uae_s32)(uae_s16)%s;\n", name, gen_nextiword (flags));
+               out("%sa += (uae_s32)(uae_s16)%s;\n", name, gen_nextiword(flags | pcflag));
                addr = true;
                break;
        case Ad8r: // (d8,An,Xn)
@@ -3301,7 +3353,7 @@ static void genamode2x (amodes mode, const char *reg, wordsizes size, const char
                        if ((flags & GF_NOREFILL) && using_prefetch) {
                                out("%sa = %s(m68k_areg(regs, %s), regs.irc);\n", name, disp000, reg);
                        } else {
-                               out("%sa = %s(m68k_areg(regs, %s), %s);\n", name, disp000, reg, gen_nextiword (flags));
+                               out("%sa = %s(m68k_areg(regs, %s), %s);\n", name, disp000, reg, gen_nextiword(flags | pcflag));
                        }
                        count_read_ea++; 
                }
@@ -3344,7 +3396,7 @@ static void genamode2x (amodes mode, const char *reg, wordsizes size, const char
                        if ((flags & GF_NOREFILL) && using_prefetch) {
                                out("%sa = %s(tmppc, regs.irc);\n", name, disp000);
                        } else {
-                               out("%sa = %s(tmppc, %s);\n", name, disp000, gen_nextiword (flags));
+                               out("%sa = %s(tmppc, %s);\n", name, disp000, gen_nextiword(flags | pcflag));
                        }
                }
                if ((flags & GF_NOFETCH) && using_prefetch) {
@@ -3355,12 +3407,12 @@ static void genamode2x (amodes mode, const char *reg, wordsizes size, const char
        case absw:
                out("uaecptr %sa;\n", name);
                start_mmu040_movem(movem);
-               out("%sa = (uae_s32)(uae_s16)%s;\n", name, gen_nextiword (flags));
+               out("%sa = (uae_s32)(uae_s16)%s;\n", name, gen_nextiword(flags));
                pc_68000_offset_fetch += 2;
                addr = true;
                break;
        case absl:
-               gen_nextilong2 ("uaecptr", namea, flags, movem);
+               gen_nextilong2("uaecptr", namea, flags | pcflag, movem);
                count_read_ea += 2;
                pc_68000_offset_fetch += 4;
                pc_68000_offset_store += 2;
@@ -3372,15 +3424,15 @@ static void genamode2x (amodes mode, const char *reg, wordsizes size, const char
                        term();
                switch (size) {
                case sz_byte:
-                       out("uae_s8 %s = %s;\n", name, gen_nextibyte (flags));
+                       out("uae_s8 %s = %s;\n", name, gen_nextibyte(flags));
                        count_read_ea++;
                        break;
                case sz_word:
-                       out("uae_s16 %s = %s;\n", name, gen_nextiword (flags));
+                       out("uae_s16 %s = %s;\n", name, gen_nextiword(flags));
                        count_read_ea++;
                        break;
                case sz_long:
-                       gen_nextilong ("uae_s32", name, flags);
+                       gen_nextilong("uae_s32", name, flags | pcflag);
                        count_read_ea += 2;
                        break;
                default:
@@ -3394,7 +3446,7 @@ static void genamode2x (amodes mode, const char *reg, wordsizes size, const char
        case imm0:
                if (getv != 1)
                        term();
-               out("uae_s8 %s = %s;\n", name, gen_nextibyte (flags));
+               out("uae_s8 %s = %s;\n", name, gen_nextibyte(flags));
                count_read_ea++;
                do_instruction_buserror();
                maybeaddop_ce020 (flags);
@@ -3404,7 +3456,7 @@ static void genamode2x (amodes mode, const char *reg, wordsizes size, const char
        case imm1:
                if (getv != 1)
                        term();
-               out("uae_s16 %s = %s;\n", name, gen_nextiword (flags));
+               out("uae_s16 %s = %s;\n", name, gen_nextiword(flags));
                count_read_ea++;
                do_instruction_buserror();
                maybeaddop_ce020 (flags);
@@ -3414,10 +3466,10 @@ static void genamode2x (amodes mode, const char *reg, wordsizes size, const char
        case imm2:
                if (getv != 1)
                        term();
-               gen_nextilong ("uae_s32", name, flags);
+               gen_nextilong("uae_s32", name, flags);
                count_read_ea += 2;
-               maybeaddop_ce020 (flags);
-               syncmovepc (getv, flags);
+               maybeaddop_ce020(flags);
+               syncmovepc(getv, flags);
                strcpy(g_srcname, name);
                return;
        case immi:
@@ -3482,15 +3534,15 @@ static void genamode2x (amodes mode, const char *reg, wordsizes size, const char
                }
        }
 
-       exception_pc_offset = 0;
+       exception_pc_offset = pc_68000_offset;
        if (getv == 2) {
                // store
                if (pc_68000_offset) {
-                       exception_pc_offset = pc_68000_offset + pc_68000_offset_store + 2;
+                       exception_pc_offset += pc_68000_offset_store + 2;
                }
        } else {
                // fetch
-               exception_pc_offset = pc_68000_offset + pc_68000_offset_fetch;
+               exception_pc_offset += pc_68000_offset_fetch;
        }
 
        if (!(flags & GF_NOEXC3)) {
@@ -3726,6 +3778,8 @@ static void genastore_2 (const char *from, amodes mode, const char *reg, wordsiz
 {
        char tmp[100];
 
+       exception_pc_offset = m68k_pc_offset;
+
        if (candormw) {
                if (strcmp (rmw_varname, to) != 0)
                        candormw = false;
@@ -4353,13 +4407,14 @@ static void genmovemel(uae_u16 opcode)
 static void genmovemel_ce(uae_u16 opcode)
 {
        int size = table68k[opcode].size == sz_long ? 4 : 2;
-       out("uae_u16 mask = %s;\n", gen_nextiword (0));
-       check_prefetch_buserror(m68k_pc_offset);
+       amodes mode = table68k[opcode].dmode;
+       out("uae_u16 mask = %s;\n", gen_nextiword(mode < Ad16 ? GF_PCM2 : 0));
+       do_instruction_buserror();
        out("uae_u32 dmask = mask & 0xff, amask = (mask >> 8) & 0xff;\n");
-       if (table68k[opcode].dmode == Ad8r || table68k[opcode].dmode == PC8r) {
+       if (mode == Ad8r || mode == PC8r) {
                addcycles000(2);
        }
-       genamode(NULL, table68k[opcode].dmode, "dstreg", table68k[opcode].size, "src", 2, -1, GF_AA | GF_MOVE);
+       genamode(NULL, mode, "dstreg", table68k[opcode].size, "src", 2, -1, GF_AA | GF_MOVE | GF_PCM2);
        movem_ex3(0);
        if (table68k[opcode].size == sz_long) {
                out("while (dmask) {\n");
@@ -4414,8 +4469,9 @@ static void genmovemel_ce(uae_u16 opcode)
        out("%s(srca);\n", srcw); // and final extra word fetch that goes nowhere..
        count_readw++;
        check_bus_error("src", 0, 0, 1, NULL, 1, -1);
-       if (table68k[opcode].dmode == Aipi)
+       if (mode == Aipi) {
                out("m68k_areg(regs, dstreg) = srca;\n");
+       }
        count_ncycles++;
        fill_prefetch_next_t();
 }
@@ -4524,15 +4580,17 @@ static void genmovemle(uae_u16 opcode)
 static void genmovemle_ce (uae_u16 opcode)
 {
        int size = table68k[opcode].size == sz_long ? 4 : 2;
+       amodes mode = table68k[opcode].dmode;
 
-       out("uae_u16 mask = %s;\n", gen_nextiword (0));
-       check_prefetch_buserror(m68k_pc_offset);
-       if (table68k[opcode].dmode == Ad8r || table68k[opcode].dmode == PC8r) {
+       out("uae_u16 mask = %s;\n", gen_nextiword(mode >= Ad8r && mode != absw && mode != absl ? GF_PCM2 : ((mode == Ad16 || mode == PC16 || mode == absw || mode == absl) ? 0 : GF_PCP2)));
+       do_instruction_buserror();
+       if (mode == Ad8r || mode == PC8r) {
                addcycles000(2);
        }
-       genamode(NULL, table68k[opcode].dmode, "dstreg", table68k[opcode].size, "src", 2, 1, GF_AA | GF_MOVE | GF_REVERSE | GF_REVERSE2);
+       strcpy(bus_error_code2, "pcoffset += 2;\n");
+       genamode(NULL, mode, "dstreg", table68k[opcode].size, "src", 2, 1, GF_AA | GF_MOVE | GF_REVERSE | GF_REVERSE2 | (mode == absl ? GF_PCM2 : GF_PCP2));
        if (table68k[opcode].size == sz_long) {
-               if (table68k[opcode].dmode == Apdi) {
+               if (mode == Apdi) {
                        out("uae_u16 amask = mask & 0xff, dmask = (mask >> 8) & 0xff;\n");
                        movem_ex3(1);
                        out("while (amask) {\n");
@@ -4581,7 +4639,7 @@ static void genmovemle_ce (uae_u16 opcode)
                        out("}\n");
                }
        } else {
-               if (table68k[opcode].dmode == Apdi) {
+               if (mode == Apdi) {
                        out("uae_u16 amask = mask & 0xff, dmask = (mask >> 8) & 0xff;\n");
                        movem_ex3(1);
                        out("while (amask) {\n");
@@ -5286,8 +5344,9 @@ static void gen_opcode (unsigned int opcode)
                                        "SET_XFLG(GET_CFLG());\n"
                                        "SET_VFLG((bflgs ^ bflgo) & (bflgn ^ bflgo));\n");
                        }
-                       if (c > 0)
+                       if (c > 0) {
                                addcycles000(c);
+                       }
                        genastore_rev("newv", curi->dmode, "dstreg", curi->size, "dst");
                } else {
                        if (curi->dmode == Dreg) {
@@ -5299,8 +5358,9 @@ static void gen_opcode (unsigned int opcode)
                                fill_prefetch_next_t();
                                loopmodeextra = 4;
                        }
-                       if (c > 0)
+                       if (c > 0) {
                                addcycles000(c);
+                       }
                        if (curi->dmode != Dreg) {
                                genastore_rev("newv", curi->dmode, "dstreg", curi->size, "dst");
                        }
@@ -5836,8 +5896,9 @@ static void gen_opcode (unsigned int opcode)
                } else {
                        fill_prefetch_next_after(1, NULL);
                }
-               if (isreg (curi->smode) && curi->size == sz_long)
+               if (isreg(curi->smode) && curi->size == sz_long) {
                        addcycles000(2);
+               }
                if (curi->smode != Dreg) {
                        genastore_rev("dst", curi->smode, "srcreg", curi->size, "src");
                }
@@ -5951,8 +6012,8 @@ 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, cpu_level == 1 ? GF_NOFETCH : 0);
-               out("uaecptr mempa = m68k_areg(regs, dstreg) + (uae_s32)(uae_s16)%s;\n", gen_nextiword (0));
-               check_prefetch_buserror(m68k_pc_offset);
+               out("uaecptr mempa = m68k_areg(regs, dstreg) + (uae_s32)(uae_s16)%s;\n", gen_nextiword(0));
+               check_prefetch_buserror(m68k_pc_offset, -2);
                if (curi->size == sz_word) {
                        out("%s(mempa, src >> 8);\n", dstb);
                        count_writew++;
@@ -5978,8 +6039,8 @@ static void gen_opcode (unsigned int opcode)
                next_level_000();
                break;
        case i_MVPMR: // MOVEP M->R
-               out("uaecptr mempa = m68k_areg(regs, srcreg) + (uae_s32)(uae_s16)%s;\n", gen_nextiword (0));
-               check_prefetch_buserror(m68k_pc_offset);
+               out("uaecptr mempa = m68k_areg(regs, srcreg) + (uae_s32)(uae_s16)%s;\n", gen_nextiword(0));
+               check_prefetch_buserror(m68k_pc_offset, -2);
                genamode(curi, curi->dmode, "dstreg", curi->size, "dst", 2, 0, cpu_level == 1 ? GF_NOFETCH : 0);
                if (curi->size == sz_word) {
                        out("uae_u16 val  = (%s(mempa) & 0xff) << 8;\n", srcb);
@@ -6102,12 +6163,40 @@ static void gen_opcode (unsigned int opcode)
 
                        } else if (cpu_level < 2) {
 
-                               int prefetch_done = 0, flags;
+                               int prefetch_done = 0;
+                               int flags = 0;
                                int dualprefetch = curi->dmode == absl && (curi->smode != Dreg && curi->smode != Areg && curi->smode != imm);
 
-                               genamode(curi, curi->smode, "srcreg", curi->size, "src", 1, 0, 0);
+                               if (curi->size == sz_long) {
+                                       if (curi->smode >= Aind && curi->smode != absw) {
+                                               flags |= GF_PCM2;
+                                       } else {
+                                               flags |= GF_PCM2 | GF_PCP2;
+                                       }
+                               } else {
+                                       if (curi->smode >= Aind && curi->smode != absw && curi->smode != imm) {
+                                               flags |= GF_PCM2;
+                                       } else {
+                                               flags |= GF_PCM2 | GF_PCP2;
+                                       }
+                               }
+
+                               genamode(curi, curi->smode, "srcreg", curi->size, "src", 1, 0, flags);
+
+                               flags = 0;
+                               // unexpectedly MOVEA vs MOVE have different prefetch bus error stack frame PC field behavior.
+                               if (curi->mnemo == i_MOVE) {
+                                       if ((curi->smode == imm && curi->dmode == absl)
+                                               || (curi->smode >= Ad16 && curi->smode != imm && curi->smode != absw && curi->smode != absl && curi->dmode < Ad16)
+                                               || (curi->smode == absl && curi->dmode < Ad16)
+                                               || ((curi->smode == Areg || curi->smode == Dreg) && curi->dmode == absl)) {
+                                               flags |= GF_PCM2;
+                                       } else {
+                                               flags |= GF_PCM2 | GF_PCP2;
+                                       }
+                               }
 
-                               flags = GF_MOVE | GF_APDI;
+                               flags |= GF_MOVE | GF_APDI;
                                flags |= dualprefetch ? GF_NOREFILL : 0;
                                if (curi->dmode == Apdi && curi->size == sz_long)
                                        flags |= GF_REVERSE;
@@ -6647,7 +6736,7 @@ static void gen_opcode (unsigned int opcode)
                clear_m68k_offset();
                tail_ce020_done = true;
                if (using_ce || using_prefetch) {
-                       fill_prefetch_full_000_special(NULL);
+                       fill_prefetch_full_000_special(2, NULL);
                } else {
                        fill_prefetch_full_ntx(0);
                }
@@ -6655,6 +6744,7 @@ static void gen_opcode (unsigned int opcode)
                next_cpu_level = cpu_level - 1;
                break;
        case i_RTD:
+               out("uaecptr oldpc = %s;\n", getpc);
                addop_ce020 (curi, 0, 0);
                if (using_mmu) {
                        genamode(curi, curi->smode, "srcreg", curi->size, "offs", GENA_GETV_FETCH, GENA_MOVEM_DO_INC, 0);
@@ -6677,7 +6767,7 @@ static void gen_opcode (unsigned int opcode)
                clear_m68k_offset();
                tail_ce020_done = true;
                if (using_prefetch || using_ce) {
-                       fill_prefetch_full_000_special(NULL);
+                       fill_prefetch_full_000_special(1, NULL);
                } else {
                        fill_prefetch_full(0);
                }
@@ -6712,7 +6802,7 @@ static void gen_opcode (unsigned int opcode)
                                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);
+                       genamode(NULL, curi->dmode, "dstreg", curi->size, "offs", 1, 0, GF_PCP2);
                        if (cpu_level <= 1 && using_exception_3) {
                                out("if (olda & 1) {\n");
                                out("m68k_areg(regs, 7) += 4;\n");
@@ -6749,7 +6839,7 @@ static void gen_opcode (unsigned int opcode)
                break;
        case i_RTS:
                addop_ce020 (curi, 0, 0);
-               out("uaecptr pc = %s;\n", getpc);
+               out("uaecptr oldpc = %s;\n", getpc);
                if (cpu_level <= 1 && using_exception_3) {
                        out("if (m68k_areg(regs, 7) & 1) {\n");
                        incpc("2");
@@ -6790,12 +6880,12 @@ static void gen_opcode (unsigned int opcode)
                }
                if (using_debugmem) {
                        out("if (debugmem_trace) {\n");
-                       out("branch_stack_pop_rts(pc);\n");
+                       out("branch_stack_pop_rts(oldpc);\n");
                        out("}\n");
                }
            out("if (%s & 1) {\n", getpc);
                out("uaecptr faultpc = %s;\n", getpc);
-               setpc("pc");
+               setpc("oldpc");
                if (cpu_level >= 4) {
                        out("m68k_areg(regs, 7) -= 4;\n");
                }
@@ -6807,7 +6897,7 @@ static void gen_opcode (unsigned int opcode)
                out("}\n");
                clear_m68k_offset();
                if (using_prefetch || using_ce) {
-                       fill_prefetch_full_000_special(NULL);
+                       fill_prefetch_full_000_special(2, NULL);
                } else {
                        fill_prefetch_full(0);
                }
@@ -6832,6 +6922,7 @@ static void gen_opcode (unsigned int opcode)
                                "regs.sr |= 0x2000;\n"
                                "regs.sr &= ~0x8000;\n"
                                "MakeFromSR();\n"
+                               "pcoffset -= 2;\n"
                                "} else {\n"
                                "opcode = regs.ir | 0x20000;\n"
                                "if(regs.t1) opcode |= 0x10000;\n"
@@ -6896,7 +6987,7 @@ static void gen_opcode (unsigned int opcode)
                }
                clear_m68k_offset();
                if (using_prefetch || using_ce) {
-                       fill_prefetch_full_000_special(NULL);
+                       fill_prefetch_full_000_special(2, NULL);
                } else {
                        fill_prefetch_full(0);
                }
@@ -7008,7 +7099,7 @@ static void gen_opcode (unsigned int opcode)
                                        out("if(regs.t1) opcode |= 0x10000;\n");
                                out("%s(%d);\n", prefetch_word, 2);
                                count_readw++;
-                               check_prefetch_bus_error(-2, sp);
+                               check_prefetch_bus_error(-2, 0, sp);
                                did_prefetch = 1;
                                ir2irc = 0;
                        } else {
@@ -7048,7 +7139,7 @@ static void gen_opcode (unsigned int opcode)
                if (using_prefetch || using_ce) {
                        out("%s(%d);\n", prefetch_word, 0);
                        count_readw++;
-                       check_prefetch_bus_error(-1, 0);
+                       check_prefetch_bus_error(-1, 0, 0);
                        irc2ir();
                        set_last_access();
                        out("%s(%d);\n", prefetch_word, 2);
@@ -7057,7 +7148,7 @@ static void gen_opcode (unsigned int opcode)
                        if (sp < 0 && cpu_level == 0)
                                out("if(regs.t1) opcode |= 0x10000;\n");
                        count_readw++;
-                       check_prefetch_bus_error(-2, sp);
+                       check_prefetch_bus_error(-2, 0, sp);
                        did_prefetch = 1;
                        ir2irc = 0;
                } else {
@@ -7155,7 +7246,7 @@ static void gen_opcode (unsigned int opcode)
                }
                clear_m68k_offset();
                if (using_prefetch || using_ce) {
-                       fill_prefetch_full_000_special(NULL);
+                       fill_prefetch_full_000_special(0, NULL);
                } else {
                        fill_prefetch_full(0);
                }
@@ -7166,6 +7257,7 @@ static void gen_opcode (unsigned int opcode)
                }
                break;
        case i_Bcc:
+               out("uaecptr oldpc = %s;\n", getpc);
                tail_ce020_done = true;
                if (curi->size == sz_long) {
                        if (cpu_level < 2) {
@@ -7213,7 +7305,7 @@ static void gen_opcode (unsigned int opcode)
                push_ins_cnt();
                if (using_prefetch) {
                        incpc ("(uae_s32)src + 2");
-                       fill_prefetch_full_000_special(NULL);
+                       fill_prefetch_full_000_special(2, NULL);
                        check_ipl_always();
                        if (using_ce)
                                out("return;\n");
@@ -7242,10 +7334,10 @@ static void gen_opcode (unsigned int opcode)
                        fill_prefetch_bcc();
                } else if (curi->size == sz_word) {
                        add_head_cycs (6);
-                       fill_prefetch_full_000_special(NULL);
+                       fill_prefetch_full_000_special(0, NULL);
                } else {
                        add_head_cycs (6);
-                       fill_prefetch_full_000_special(NULL);
+                       fill_prefetch_full_000_special(0, NULL);
                }
                insn_n_cycles = curi->size == sz_byte ? 8 : 12;
                branch_inst = 1;
@@ -7254,8 +7346,9 @@ bccl_not68020:
                        next_level_020_to_010();
                break;
        case i_LEA:
-               if (curi->smode == Ad8r || curi->smode == PC8r)
+               if (curi->smode == Ad8r || curi->smode == PC8r) {
                        addcycles000(2);
+               }
                if (curi->smode == absl) {
                        if (cpu_level == 0) {
                                strcpy(bus_error_code, "m68k_areg(regs, dstreg) = (m68k_areg(regs, dstreg) & 0x0000ffff) | (srca & 0xffff0000);\n");
@@ -7268,7 +7361,7 @@ bccl_not68020:
                        }
                }
                genamodedual(curi,
-                       curi->smode, "srcreg", curi->size, "src", 0, GF_AA,
+                       curi->smode, "srcreg", curi->size, "src", 0, GF_AA | ((curi->smode == absw) ? GF_PCM2 : 0),
                        curi->dmode, "dstreg", curi->size, "dst", 2, GF_AA);
                if (curi->smode == Ad8r || curi->smode == PC8r)
                        addcycles000(2);
@@ -7307,6 +7400,10 @@ bccl_not68020:
                // cc false, counter expired: idle cycle, prefetch (from branch address), 2xprefetch (from next address)
                // cc false, counter not expired: idle cycle, prefetch
                tail_ce020_done = true;
+               if(cpu_level <= 1) {
+                       // this is quite annoying instruction..
+                       out("int pcadjust = -2;\n");
+               }
                genamodedual(curi,
                        curi->smode, "srcreg", curi->size, "src", 1, GF_AA | (cpu_level < 2 ? GF_NOREFILL : 0),
                        curi->dmode, "dstreg", curi->size, "offs", 1, GF_AA | (cpu_level < 2 ? GF_NOREFILL : 0));
@@ -7349,11 +7446,11 @@ bccl_not68020:
                        // read looping instruction opcode
                        addcycles000_nonce(4);
                        out("%s(%d);\n", prefetch_word, 0);
-                       check_prefetch_bus_error(-1, -1);
+                       check_prefetch_bus_error(-1, 0, -1);
                        // read dbcc opcode
                        addcycles000_nonce(4);
                        out("%s(%d);\n", prefetch_word, 2);
-                       check_prefetch_bus_error(-2, -1);
+                       check_prefetch_bus_error(-2, 0, -1);
                        out("regs.irc = irc;\n");
                        out("} else {\n");
                        addcycles000(2);
@@ -7387,7 +7484,7 @@ bccl_not68020:
                        int old_m68k_pc_total = m68k_pc_total;
                        clear_m68k_offset();
                        get_prefetch_020_continue();
-                       fill_prefetch_full_000_special(NULL);
+                       fill_prefetch_full_000_special(1, NULL);
                        returncycles(8);
                        m68k_pc_offset = old_m68k_pc_offset;
                        m68k_pc_total = old_m68k_pc_total;
@@ -7407,13 +7504,15 @@ bccl_not68020:
                        out("}\n");
                        out("regs.loop_mode = 0;\n");
                        setpc("oldpc + %d", m68k_pc_offset);
-                       fill_prefetch_full_000_special(NULL);
+                       fill_prefetch_full_000_special(1, NULL);
                        returncycles(8);
                        out("}\n");
                        pop_ins_cnt();
                }
 
+               sprintf(bus_error_code, "pcoffset = oldpc - %s + 4;\n", getpc);
                fill_prefetch_1(0);
+               bus_error_code[0] = 0;
                if (cpu_level >= 4) {
                        genastore("(src - 1)", curi->smode, "srcreg", curi->size, "src");
                }
@@ -7431,7 +7530,7 @@ bccl_not68020:
                                out("if(regs.t1) opcode |= 0x10000;\n");
                        }
                        out("%s(%d);\n", prefetch_word, 2);
-                       check_prefetch_bus_error(-2, -1);
+                       check_prefetch_bus_error(-2, 0, -1);
                        did_prefetch = 1;
                        ir2irc = 0;
                        count_readw++;
@@ -7447,6 +7546,9 @@ bccl_not68020:
                        addcycles000_nonce(6);
                }
                add_head_cycs (10);
+               if (cpu_level <= 1) {
+                       out("pcadjust = 0;\n");
+               }
                if (cpu_level == 0 && using_ce) {
                        out("} else {\n");
                        addcycles000_onlyce(2);
@@ -7460,7 +7562,7 @@ bccl_not68020:
                setpc ("oldpc + %d", m68k_pc_offset);
                clear_m68k_offset();
                get_prefetch_020_continue();
-               fill_prefetch_full_000_special("if (!cctrue(%d)) {\nm68k_dreg(regs, srcreg) = (m68k_dreg(regs, srcreg) & ~0xffff) | (((src - 1)) & 0xffff);\n}\n", curi->cc);
+               fill_prefetch_full_000_special(-1, "if (!cctrue(%d)) {\nm68k_dreg(regs, srcreg) = (m68k_dreg(regs, srcreg) & ~0xffff) | (((src - 1)) & 0xffff);\n}\n", curi->cc);
                branch_inst = 1;
                if (!next_level_040_to_030()) {
                        if (!next_level_020_to_010())
@@ -7587,7 +7689,10 @@ bccl_not68020:
                fill_prefetch_next_after(1,
                        "CLEAR_CZNV();\n"
                        "SET_ZFLG(1);\n"
-                       "m68k_dreg(regs, dstreg) &= 0xffff0000;\n");
+                       "pcoffset -= %d;\n"
+                       "m68k_dreg(regs, dstreg) &= 0xffff0000;\n",
+                       // strange EA behavior, no other instruction work like this
+                       curi->smode == Apdi ? 0 : (curi->smode == absl || curi->smode == absw || curi->smode == imm ? 2 : m68k_pc_offset));
                out("uae_u32 newv = (uae_u32)(uae_u16)dst * (uae_u32)(uae_u16)src;\n");
                genflags (flag_logical, sz_long, "newv", "", "");
                if (using_ce) {
@@ -7613,7 +7718,9 @@ bccl_not68020:
                fill_prefetch_next_after(1, 
                        "CLEAR_CZNV();\n"
                        "SET_ZFLG(1);\n"
-                       "m68k_dreg(regs, dstreg) &= 0xffff0000;\n");
+                       "pcoffset -= %d;\n"
+                       "m68k_dreg(regs, dstreg) &= 0xffff0000;\n",
+                       curi->smode == Apdi ? 0 : (curi->smode == absl || curi->smode == absw || curi->smode == imm ? 2 : m68k_pc_offset));
                out("uae_u32 newv = (uae_s32)(uae_s16)dst * (uae_s32)(uae_s16)src;\n");
                genflags (flag_logical, sz_long, "newv", "", "");
                if (using_ce) {
index f4a186e71414d101200e7f0e8557d88ded826f7c..668a9d02e35d16372b7056269bda137aeacfb126 100644 (file)
@@ -743,8 +743,8 @@ extern void hardware_exception2(uaecptr addr, uae_u32 v, bool read, bool ins, in
 extern void exception2_setup(uae_u32 opcode, uaecptr addr, bool read, int size, uae_u32 fc);
 extern void exception2_read(uae_u32 opcode, uaecptr addr, int size, int fc);
 extern void exception2_write(uae_u32 opcode, uaecptr addr, int size, uae_u32 val, int fc);
-extern void exception2_fetch_opcode(uae_u32 opcode, int offset);
-extern void exception2_fetch(uae_u32 opcode, int offset);
+extern void exception2_fetch_opcode(uae_u32 opcode, int offset, int pcoffset);
+extern void exception2_fetch(uae_u32 opcode, int offset, int pcoffset);
 extern void m68k_reset (void);
 extern void cpureset (void);
 extern void cpu_halt (int id);
index a1e677674b47d4b285e912afbdf1de6551d958b2..759edc5cb85e9f67809b70fc3852af864590280a 100644 (file)
@@ -2733,7 +2733,7 @@ kludge_me_do:
                        cpu_halt(CPU_HALT_DOUBLE_FAULT);
                        return;
                }
-               exception2_fetch(regs.irc, 0);
+               exception2_fetch(regs.irc, 0, 0);
                return;
        }
        regs.ird = regs.ir;
@@ -2746,7 +2746,7 @@ kludge_me_do:
                        cpu_halt(CPU_HALT_DOUBLE_FAULT);
                        return;
                }
-               exception2_fetch(regs.ir, 2);
+               exception2_fetch(regs.ir, 0, 2);
                return;
        }
 #ifdef JIT
@@ -7360,18 +7360,20 @@ static void exception2_fetch_common(uae_u32 opcode, int offset)
        }
 }
 
-void exception2_fetch_opcode(uae_u32 opcode, int offset)
+void exception2_fetch_opcode(uae_u32 opcode, int offset, int pcoffset)
 {
        exception2_fetch_common(opcode, offset);
+       last_addr_for_exception_3 += pcoffset;
        if (currprefs.cpu_model == 68010) {
                last_di_for_exception_3 = -1;
        }
        Exception(2);
 }
 
-void exception2_fetch(uae_u32 opcode, int offset)
+void exception2_fetch(uae_u32 opcode, int offset, int pcoffset)
 {
        exception2_fetch_common(opcode, offset);
+       last_addr_for_exception_3 += pcoffset;
        Exception(2);
 }