]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
Accurate CPU odd cycle COPJMPx write copper/blitter bug emulation
authorToni Wilen <twilen@winuae.net>
Sun, 6 Nov 2022 16:58:25 +0000 (18:58 +0200)
committerToni Wilen <twilen@winuae.net>
Sun, 6 Nov 2022 16:58:25 +0000 (18:58 +0200)
blitter.cpp
custom.cpp
include/custom.h

index ccf011213eaab85e612cbf6b9762d5d5e34facc6..c1311120b7a4ba9911df84fb410674d80a833c4e 100644 (file)
@@ -1330,13 +1330,15 @@ static int blitter_next_cycle(void)
 
 static void blitter_doddma_new(int hpos, bool addmod)
 {
-       check_channel_mods(hpos, 4, &bltdpt);
+       uaecptr *hpt = NULL;
 
-       record_dma_blit(0x00, ddat1, bltdpt, hpos);
-       blit_chipmem_agnus_wput(bltdpt, ddat1, MW_MASK_BLITTER_D_N);
-       alloc_cycle_blitter(hpos, &bltdpt, 4);
+       check_channel_mods(hpos, 4, &bltdpt);
+       uaecptr orptr = alloc_cycle_blitter_conflict_or();
+       record_dma_blit(0x00, ddat1, bltdpt | orptr, hpos);
+       blit_chipmem_agnus_wput(bltdpt | orptr, ddat1, MW_MASK_BLITTER_D_N);
+       bool skipadd = alloc_cycle_blitter(hpos, &bltdpt, 4, addmod ? blit_modaddd : 0);
 
-       if (!blitline) {
+       if (!blitline && !skipadd) {
                bltdpt += blit_add;
        }
        if (addmod) {
@@ -1348,21 +1350,24 @@ static void blitter_dodma_new(int ch, int hpos, bool addmod)
 {
        uae_u16 dat, reg;
        uae_u32 *addr;
+       bool skipadd = false;
        int mod;
 
+       uaecptr orptr = alloc_cycle_blitter_conflict_or();
+
        switch (ch)
        {
        case 1: // A
        {
                check_channel_mods(hpos, 1, &bltapt);
                reg = 0x74;
-               record_dma_blit(reg, 0, bltapt, hpos);
-               blt_info.bltadat = dat = chipmem_wget_indirect(bltapt);
+               record_dma_blit(reg, 0, bltapt | orptr, hpos);
+               blt_info.bltadat = dat = chipmem_wget_indirect(bltapt | orptr);
                record_dma_blit_val(dat);
                regs.chipset_latch_rw = blt_info.bltadat;
                addr = &bltapt;
                mod = blit_modadda;
-               alloc_cycle_blitter(hpos, &bltapt, 1);
+               skipadd = alloc_cycle_blitter(hpos, &bltapt, 1, addmod ? mod : 0);
                break;
        }
        case 2: // B
@@ -1370,8 +1375,8 @@ static void blitter_dodma_new(int ch, int hpos, bool addmod)
                int bshift = bltcon1 >> 12;
                check_channel_mods(hpos, 2, &bltbpt);
                reg = 0x72;
-               record_dma_blit(reg, 0, bltbpt, hpos);
-               blt_info.bltbdat = dat = chipmem_wget_indirect(bltbpt);
+               record_dma_blit(reg, 0, bltbpt | orptr, hpos);
+               blt_info.bltbdat = dat = chipmem_wget_indirect(bltbpt | orptr);
                record_dma_blit_val(dat);
                regs.chipset_latch_rw = blt_info.bltbdat;
                addr = &bltbpt;
@@ -1382,27 +1387,27 @@ static void blitter_dodma_new(int ch, int hpos, bool addmod)
                        blt_info.bltbhold = (((uae_u32)blt_info.bltbold << 16) | blt_info.bltbdat) >> bshift;
                blineb = blt_info.bltbhold;
                blt_info.bltbold = blt_info.bltbdat;
-               alloc_cycle_blitter(hpos, &bltbpt, 2);
+               skipadd = alloc_cycle_blitter(hpos, &bltbpt, 2, addmod ? mod : 0);
                break;
        }
        case 3: // C
        {
                reg = 0x70;
                check_channel_mods(hpos, 3, &bltcpt);
-               record_dma_blit(reg, 0, bltcpt, hpos);
-               blt_info.bltcdat = dat = chipmem_wget_indirect(bltcpt);
+               record_dma_blit(reg, 0, bltcpt | orptr, hpos);
+               blt_info.bltcdat = dat = chipmem_wget_indirect(bltcpt | orptr);
                record_dma_blit_val(dat);
                regs.chipset_latch_rw = blt_info.bltcdat;
                addr = &bltcpt;
                mod = blit_modaddc;
-               alloc_cycle_blitter(hpos, &bltcpt, 3);
+               skipadd = alloc_cycle_blitter(hpos, &bltcpt, 3, addmod ? mod : 0);
                break;
        }
        default:
                abort();
        }
 
-       if (!blitline) {
+       if (!blitline && !skipadd) {
                (*addr) += blit_add;
        }
        if (addmod) {
@@ -1564,13 +1569,13 @@ static bool decide_blitter_maybe_write2(int until_hpos, uaecptr addr, uae_u32 va
                                        blitter_line_proc_cpt_y();
                                        blitlineloop = 0;
                                }
-
-                               record_dma_blit(0x70, 0, bltcpt, hpos);
+                               uaecptr orptr = alloc_cycle_blitter_conflict_or();
+                               record_dma_blit(0x70, 0, bltcpt | orptr, hpos);
                                check_channel_mods(hpos, 3, &bltcpt);
-                               blt_info.bltcdat = chipmem_wget_indirect(bltcpt);
+                               blt_info.bltcdat = chipmem_wget_indirect(bltcpt | orptr);
                                regs.chipset_latch_rw = blt_info.bltcdat;
                                record_dma_blit_val(blt_info.bltcdat);
-                               alloc_cycle_blitter(hpos, &bltcpt, 3);
+                               alloc_cycle_blitter(hpos, &bltcpt, 3, 0);
 
                                if (dat & BLITTER_PIPELINE_FIRST) {
                                        blitter_line_minterm(dat);
@@ -1601,10 +1606,11 @@ static bool decide_blitter_maybe_write2(int until_hpos, uaecptr addr, uae_u32 va
 
                                /* onedot mode and no pixel = bus write access is skipped */
                                if (blitlinepixel && c == 4) {
-                                       record_dma_blit(0x00, blt_info.bltddat, bltdpt, hpos);
+                                       uaecptr orptr = alloc_cycle_blitter_conflict_or();
+                                       record_dma_blit(0x00, blt_info.bltddat, bltdpt | orptr, hpos);
                                        check_channel_mods(hpos, 4, &bltdpt);
-                                       blit_chipmem_agnus_wput(bltdpt, blt_info.bltddat, MW_MASK_BLITTER_D_L);
-                                       alloc_cycle_blitter(hpos, &bltdpt, 4);
+                                       blit_chipmem_agnus_wput(bltdpt | orptr, blt_info.bltddat, MW_MASK_BLITTER_D_L);
+                                       alloc_cycle_blitter(hpos, &bltdpt, 4, 0);
                                } else {
                                        markidlecycle(hpos);
                                }
@@ -1614,7 +1620,12 @@ static bool decide_blitter_maybe_write2(int until_hpos, uaecptr addr, uae_u32 va
                                bltdpt = bltcpt;
 
                                blitter_line_minterm(dat);
-
+#if 0
+                               if (blt_info.hblitsize == 1) {
+                                       blitter_line_proc_cpt_x();
+                                       blitter_line_proc_cpt_y();
+                               }
+#endif
                        } else {
 
                                // normal mode channels
index 2dc95fe46558c572f8de59198a904b8610f5b63d..6ceaa9a464fe899cdb68c19e34a989dffd3b2aaa 100644 (file)
@@ -511,6 +511,10 @@ struct copper {
 
 static struct copper cop_state;
 static int copper_enabled_thisline;
+static evt_t copper_bad_cycle;
+static uaecptr copper_bad_cycle_pc_old;
+static evt_t copper_bad_cycle_start;
+static uaecptr copper_bad_cycle_pc_new;
 
 /*
 * Statistics
@@ -771,18 +775,27 @@ void alloc_cycle_ext(int hpos, int type)
        alloc_cycle(hpos, type);
 }
 
-void alloc_cycle_blitter(int hpos, uaecptr *ptr, int chnum)
+uaecptr alloc_cycle_blitter_conflict_or(void)
 {
-       if (cycle_line_slot[hpos] & CYCLE_COPPER_SPECIAL) {
-               if ((currprefs.cs_hacks & 1) && currprefs.cpu_model == 68000) {
-                       uaecptr srcptr = cop_state.strobe == 1 ? cop1lc : cop2lc;
-                       //if (currprefs.cpu_model == 68000 && currprefs.cpu_cycle_exact && currprefs.blitter_cycle_exact) {
-                       // batman group / batman vuelve triggers this incorrectly. More testing needed.
-                       *ptr = srcptr;
-                       //activate_debugger();
-               }
+       uaecptr orptr = 0;
+       if (get_cycles() == copper_bad_cycle) {
+               orptr = copper_bad_cycle_pc_old;
+       }
+       return orptr;
+}
+
+bool alloc_cycle_blitter(int hpos, uaecptr *ptr, int chnum, int add)
+{
+       bool skipadd = false;
+       if (get_cycles() == copper_bad_cycle) {
+               write_log("Copper PT=%08x %08x. Blitter CH=%d PT=%08x bug!\n", copper_bad_cycle_pc_old, copper_bad_cycle_pc_new, chnum, *ptr);
+               cop_state.ip += add;
+               *ptr = copper_bad_cycle_pc_new;
+               skipadd = true;
+               //activate_debugger();
        }
        alloc_cycle(hpos, CYCLE_BLITTER);
+       return skipadd;
 }
 
 static int expand_sprres(uae_u16 con0, uae_u16 con3)
@@ -7518,8 +7531,11 @@ static void COPJMP(int num, int vblank)
                                warned--;
                        }
                }
-               if (current_hpos() & 1) {
-                       cop_state.state = COP_strobe_delay1x; // CPU unaligned COPJMP while waiting
+               int hp = current_hpos();
+               if ((hp & 1) && currprefs.cpu_model == 68000 && currprefs.cpu_cycle_exact) {
+                       // CPU unaligned COPJMP while waiting
+                       cop_state.state = COP_strobe_delay1x;
+                       copper_bad_cycle_start = get_cycles();
                } else {
                        cop_state.state = COP_strobe_delay1;
                }
@@ -9600,8 +9616,8 @@ static void do_copper_fetch(int hpos, uae_u16 id)
        if (scandoubled_line) {
                return;
        }
-       if (id == COPPER_CYCLE_IDLE) {
-               // copper allocated cycle without DMA request
+
+       if (id & CYCLE_PIPE_NONE) {
                alloc_cycle(hpos, CYCLE_COPPER);
                return;
        }
@@ -9672,9 +9688,6 @@ static void do_copper_fetch(int hpos, uae_u16 id)
        }
        break;
        case COP_strobe_delay2x:
-               if (debug_dma) {
-                       record_dma_event(DMA_EVENT_SPECIAL, hpos, vpos);
-               }
 #ifdef DEBUGGER
                {
                        if (debug_dma) {
@@ -9700,9 +9713,7 @@ static void do_copper_fetch(int hpos, uae_u16 id)
                        cop_state.ip = cop2lc;
                }
                cop_state.strobe = 0;
-
                alloc_cycle(hpos, CYCLE_COPPER);
-               cycle_line_slot[hpos] |= CYCLE_COPPER_SPECIAL;
                break;
        case COP_start_delay:
                cop_state.state = COP_read1;
@@ -10023,9 +10034,31 @@ static void update_copper(int until_hpos)
                case COP_strobe_delay2x:
                        // Second cycle fetches following word and tosses it away.
                        // Cycle can be free and copper won't allocate it.
-                       // If Blitter uses this cycle = Copper's PC gets copied to blitter DMA pointer..
-                       copper_cant_read(hpos, CYCLE_PIPE_COPPER | 0x09);
-               break;
+                       // If Blitter uses this cycle = Copper's new PC gets copied to blitter DMA pointer..
+                       if (!copper_cant_read(hpos, CYCLE_PIPE_COPPER | 0x09)) {
+                               copper_bad_cycle = get_cycles();
+                               // conflict also does not happen if previous cycle was used by bitplane
+                               // (if bitplane DMA is allocated, copper internal operations are also stopped)
+                               int bpl = 0;// get_bitplane_dma_rel(hpos, -1);
+                               if (copper_bad_cycle - copper_bad_cycle_start != 3 * CYCLE_UNIT || bpl) {
+                                       copper_bad_cycle = 0;
+                               } else {
+                                       if (debug_dma) {
+                                               record_dma_event(DMA_EVENT_SPECIAL, hpos, vpos);
+                                       }
+                                       // early COPJMP processing
+                                       cop_state.state = COP_read1;
+                                       copper_bad_cycle_pc_old = cop_state.ip;
+                                       if (cop_state.strobe == 1) {
+                                               cop_state.ip = cop1lc;
+                                       } else {
+                                               cop_state.ip = cop2lc;
+                                       }
+                                       copper_bad_cycle_pc_new = cop_state.ip;
+                                       cop_state.strobe = 0;
+                               }
+                       }
+                       break;
 
                case COP_start_delay:
                        // cycle after vblank strobe fetches word from old pointer first
@@ -13193,6 +13226,7 @@ void custom_reset(bool hardreset, bool keyboardreset)
        hcenter_v2 = 0;
        set_hcenter();
        display_reset = 1;
+       copper_bad_cycle = 0;
 
        if (hardreset || savestate_state) {
                maxhpos = ntsc ? MAXHPOS_NTSC : MAXHPOS_PAL;
@@ -13331,10 +13365,9 @@ void custom_reset(bool hardreset, bool keyboardreset)
        toscr_delay_sh[0] = 0;
        toscr_delay_sh[1] = 0;
 
+       memset(&cop_state, 0, sizeof(cop_state));
        cop_state.state = COP_stop;
-       cop_state.movedelay = 0;
-       cop_state.strobe = 0;
-       cop_state.ignore_next = 0;
+
        vdiwstate = diw_states::DIW_waiting_start;
        vdiw_change(0);
        check_harddis();
index bbafa2a93803a067d9b7deeadd4686ff535714e8..0302ff27fc35cdd6c38213f3ca73789dfd29b0f3 100644 (file)
@@ -171,7 +171,6 @@ extern int display_reset;
 #define CYCLE_COPPER   6
 #define CYCLE_BLITTER  7
 #define CYCLE_CPU              8
-#define CYCLE_COPPER_SPECIAL 0x10
 
 #define CYCLE_MASK 0x0f
 
@@ -252,7 +251,8 @@ struct customhack {
        int vpos, hpos;
 };
 extern void alloc_cycle_ext(int, int);
-extern void alloc_cycle_blitter(int hpos, uaecptr *ptr, int);
+extern bool alloc_cycle_blitter(int hpos, uaecptr *ptr, int, int);
+extern uaecptr alloc_cycle_blitter_conflict_or(void);
 extern bool ispal(int *lines);
 extern bool isvga(void);
 extern int current_maxvpos(void);
@@ -271,6 +271,7 @@ extern uae_u8 cycle_line_slot[MAX_CHIPSETSLOTS + RGA_PIPELINE_ADJUST];
 extern uae_u16 cycle_line_pipe[MAX_CHIPSETSLOTS + RGA_PIPELINE_ADJUST];
 
 #define CYCLE_PIPE_CPUSTEAL 0x8000
+#define CYCLE_PIPE_NONE 0x4000
 #define CYCLE_PIPE_BLITTER 0x100
 #define CYCLE_PIPE_COPPER 0x80
 #define CYCLE_PIPE_SPRITE 0x40