]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
DDFSTRT/STOP/etc handling rewrite
authorToni Wilen <twilen@winuae.net>
Wed, 19 Nov 2025 17:27:17 +0000 (19:27 +0200)
committerToni Wilen <twilen@winuae.net>
Wed, 19 Nov 2025 17:27:17 +0000 (19:27 +0200)
custom.cpp

index 58de9be88bf529e867b205a6aa15d4c4d8cd2f26..de0889d94df331e2cb00f7aabaf03579b2f1c1f3 100644 (file)
@@ -447,10 +447,9 @@ static uae_u16 cregs[256];
 uae_u16 intena, intreq;
 static uae_u16 intena2, intreq2;
 uae_u16 dmacon;
-static uae_u16 dmacon_next;
 uae_u16 adkcon; /* used by audio code */
 uae_u16 last_custom_value;
-static bool dmacon_bpl;
+static bool dmacon_bpl, dmacon_bpl2;
 
 static uae_u32 cop1lc, cop2lc, copcon;
 
@@ -664,7 +663,6 @@ struct sprite {
 };
 
 static struct sprite spr[MAX_SPRITES];
-static int plfstrt_sprite;
 uaecptr sprite_0;
 int sprite_0_width, sprite_0_height, sprite_0_doubled;
 uae_u32 sprite_0_colors[4];
@@ -683,7 +681,9 @@ static uae_u16 bplcon1, bplcon2, bplcon3, bplcon4;
 static uae_u32 bplcon0_res, bplcon0_planes, bplcon0_planes_limit;
 static int diwstrt, diwstop, diwhigh;
 static int diwhigh_written;
-static uae_u16 ddfstrt, ddfstop, ddf_mask;
+static uae_u16 ddfstrt, ddfstrt_val, ddfstop, ddf_mask;
+static uae_u16 ddfstrt_val_old, ddfstop_old;
+static evt_t ddfstrt_cycle, ddfstop_cycle;
 static int diw_change;
 
 /* The display and data fetch windows */
@@ -783,7 +783,7 @@ int bogusframe;
 static int display_vsync_counter, display_hsync_counter;
 static evt_t display_last_hsync, display_last_vsync;
 
-static bool ddf_limit, ddfstrt_match, hwi_old;
+static bool ddf_limit_in, ddf_limit_out, ddf_limit, ddfstrt_match, hwi_old;
 static int ddf_stopping, ddf_enable_on;
 static int bprun;
 static int bprun_cycle;
@@ -3806,19 +3806,23 @@ static void DIWHIGH(uae_u16 v)
 
 static void DDFSTRT(uae_u16 v)
 {
-       // DDFSTRT modified when DDFSTRT==hpos: neither value matches
+       // DDFSTRT modification: new value is available after 2 CCKs
        ddfstrt_saved = v;
+       ddfstrt_val_old = ddfstrt_val;
+       ddfstrt_cycle = get_cycles() + CYCLE_UNIT;
        v &= ddf_mask;
-       ddfstrt = 0xffff;
-       push_pipeline(&ddfstrt, v);
+       ddfstrt = v;
+       ddfstrt_val = v | 1;
 }
 
 static void DDFSTOP(uae_u16 v)
 {
-       // DDFSTOP modified when DDFSTOP==hpos: old value matches
+       // DDFSTOP modification: new value is available after 2 CCKs
        ddfstop_saved = v;
+       ddfstop_old = ddfstop;
+       ddfstop_cycle = get_cycles() + CYCLE_UNIT;
        v &= ddf_mask;
-       push_pipeline(&ddfstop, v);
+       ddfstop = v;
 }
 
 static void FMODE(uae_u16 v)
@@ -7949,6 +7953,11 @@ uae_u8 *restore_custom(uae_u8 *src)
        ddfstrt_saved = ddfstrt;
        ddfstop_saved = ddfstop;
        diwhigh_saved = diwhigh;
+       ddfstrt_val = ddfstrt | 1;
+       ddfstrt_val_old = ddfstrt_val;
+       ddfstrt_cycle = 0;
+       ddfstop_old = ddfstop;
+       ddfstop_cycle = 0;
 
        bitplane_dma_change(dmacon);
        calcvdiw();
@@ -9721,9 +9730,14 @@ static void bitplane_rga_ptmod(void)
                        write_rga_update(r, &bplpt[bpl]);
                        r->bplmod = mod;
                } else if (r->type == CYCLE_SPRITE) {
-                       int num = r->sprdat & 7;
-                       struct sprite *s = &spr[num];
-                       write_rga_update(r, &s->pt);
+                       // OCS off by one bitplane sprite cycle stealing bug
+                       if (bprun && !ecs_agnus) {
+                               clear_rga(r);
+                       } else {
+                               int num = r->sprdat & 7;
+                               struct sprite *s = &spr[num];
+                               write_rga_update(r, &s->pt);
+                       }
                } else if (r->type == (CYCLE_BITPLANE | CYCLE_SPRITE)) {
                        int num = r->sprdat & 7;
                        struct sprite *s = &spr[num];
@@ -9772,9 +9786,8 @@ static void bpl_dma_normal_stop(int hpos)
 #endif
        ddf_stopping = 0;
        bprun = 0;
-       plfstrt_sprite = 0x100;
        if (!ecs_agnus) {
-               ddf_limit = true;
+               ddf_limit_in = true;
        }
        if (bplcon0_planes > 0 && hpos > ddflastword_total) {
                ddflastword_total = hpos;
@@ -9836,23 +9849,16 @@ static void update_bpl_scandoubler(void)
 
 static void decide_bpl(int hpos)
 {
-       bool dma = dmacon_bpl;
        bool diw = vdiwstate == diw_states::DIW_waiting_stop;
+       evt_t cyc = get_cycles();
+
+       ddf_limit_out = ddf_limit_in;
 
        if (ecs_agnus) {
                // ECS/AGA
+               bool dma = dmacon_bpl;
 
-               // BPRUN latched: on
-               if (bprun < 0 && (hpos & 1)) {
-                       bprun = 1;
-                       bprun_cycle = 0;
-#ifdef DEBUGGER
-                       if (debug_dma) {
-                               record_dma_event_agnus(AGNUS_EVENT_BPRUN, true);
-                       }
-#endif
-               }
-
+#if 0
                // BPRUN latched: off
                if (bprun == 3) {
                        if (ddf_stopping == 1) {
@@ -9862,94 +9868,86 @@ static void decide_bpl(int hpos)
                                }
                        }
                        bprun = 0;
-                       plfstrt_sprite = 0x100;
                }
-
+#endif
                // Hard start limit
-               if (hpos == (0x18 | 0)) {
-                       ddf_limit = false;
+               if (hpos == 0x18) {
+                       ddf_limit_in = false;
                }
 
                // Hard stop limit
-               if (hpos == (0xd7 + 0)) {
+               if (hpos == 0xd7) {
                        // Triggers DDFSTOP condition if hard limits are not disabled.
                        if (!harddis_h) {
-                               ddf_limit = true;
-                               if (bprun && !ddf_stopping) {
-                                       ddf_stopping = 1;
+                               ddf_limit_in = true;
+                       }
+               }
+
+               // DDFSTRT (odd cycle)
+               if ((hpos == ddfstrt_val && cyc > ddfstrt_cycle) || (hpos == ddfstrt_val_old && cyc <= ddfstrt_cycle)) {
+                       ddf_enable_on = 1;
+                       if (currprefs.gfx_scandoubler && linear_vpos < MAX_SCANDOUBLED_LINES) {
+                               update_bpl_scandoubler();
+                       }
+                       if (ddf_stopping < 0) {
+                               ddf_stopping = 0;
+                       }
 #ifdef DEBUGGER
-                                       if (debug_dma) {
-                                               record_dma_event_agnus(AGNUS_EVENT_BPRUN2, true);
-                                       }
+                       if (debug_dma) {
+                               record_dma_event(DMA_EVENT_DDFSTRT);
+                       }
 #endif
-                               }
+               } else {
+                       if (ddf_stopping < 0) {
+                               ddf_stopping = 1;
+                       }
+               }
+
+               // DDFSTOP (even cycle)
+               // Triggers DDFSTOP condition.
+               // Clears DDF allowed flag.
+               if ((hpos == ddfstop && cyc > ddfstop_cycle) || (hpos == ddfstop_old && cyc <= ddfstop_cycle)) {
+                       ddf_enable_on = 0;
+#ifdef DEBUGGER
+                       if (debug_dma) {
+                               record_dma_event(DMA_EVENT_DDFSTOP);
                        }
+#endif
                }
 
-               if (hpos == ddfstrt && hpos == ddfstop) {
+               // BPRUN can only start if DMA, DIW or DDF state has changed since last time
+               if (1) {
+                       bool hwi = dma && diw && ddf_enable_on && (!ddf_limit_out || harddis_h);
 
-                       // DDFSTRT == DDFSTOP
-                       if (bprun && ddf_enable_on) {
-                               ddf_stopping = 1;
-                               if (currprefs.gfx_scandoubler && linear_vpos < MAX_SCANDOUBLED_LINES) {
-                                       update_bpl_scandoubler();
-                               }
+                       if (!bprun && hwi && !hwi_old) {
+
+                               // Bitplane sequencer activated
+                               bprun = 1;
+                               bprun_cycle = 0;
 #ifdef DEBUGGER
                                if (debug_dma) {
-                                       record_dma_event_agnus(AGNUS_EVENT_BPRUN2, true);
+                                       record_dma_event_agnus(AGNUS_EVENT_BPRUN, true);
                                }
 #endif
-                       }
-                       ddf_enable_on = 1;
-                       if (!bprun) {
-                               hwi_old = 0;
-                       }
+                               bprun_start(hpos + 1);
 
-               } else {
+                       } else if (bprun && !hwi && hwi_old) {
 
-                       // DDFSTRT
-                       if (hpos == ddfstrt) {
-                               ddf_enable_on = 1;
-                               if (currprefs.gfx_scandoubler && linear_vpos < MAX_SCANDOUBLED_LINES) {
-                                       update_bpl_scandoubler();
-                               }
-                       }
-
-                       // DDFSTOP
-                       // Triggers DDFSTOP condition.
-                       // Clears DDF allowed flag.
-                       if (hpos == ddfstop) {
-                               ddf_enable_on = 0;
-                               if (bprun && !ddf_stopping) {
+                               // Activate ddfstop passed condition
+                               if (!ddf_stopping) {
                                        ddf_stopping = 1;
 #ifdef DEBUGGER
                                        if (debug_dma) {
-                                               record_dma_event_agnus(AGNUS_EVENT_BPRUN2, true);
+                                               record_dma_event(DMA_EVENT_DDFSTOP2);
                                        }
 #endif
                                }
                        }
-               }
 
-               // BPRUN can only start if DMA, DIW or DDF state has changed since last time
-               if (!(hpos & 1)) {
-                       bool hwi = dma && diw && ddf_enable_on && (!ddf_limit || harddis_h);
-                       if (!bprun && dma && diw && hwi && !hwi_old) {
-                               // Bitplane sequencer activated
-                               bprun = -1;
-                               if (plfstrt_sprite > hpos + 1) {
-                                       plfstrt_sprite = hpos + 1;
-                               }
-                               bprun_start(hpos);
-#ifdef DEBUGGER
-                               if (debug_dma) {
-                                       record_dma_event(DMA_EVENT_DDFSTRT);
-                               }
-#endif
-                       }
                        hwi_old = hwi;
                }
 
+#if 0
                if (bprun == 2) {
                        bprun = 3;
                        // If DDF has passed, jumps to last step.
@@ -9965,37 +9963,44 @@ static void decide_bpl(int hpos)
                                }
 #endif
                        }
-                       plfstrt_sprite = 0x100;
 #ifdef DEBUGGER
                        if (debug_dma) {
                                record_dma_event_agnus(AGNUS_EVENT_BPRUN, false);
                        }
 #endif
                }
+#endif
+#if 1
+               if (bprun == 3) {
+                       bprun = 0;
+               }
+               if (bprun > 1) {
+                       bprun++;
+               }
 
                // DIW or DMA switched off: clear BPRUN
                if ((!dma || !diw) && bprun == 1) {
                        bprun = 2;
-                       if (ddf_stopping == 1) {
-                               ddf_stopping = 2;
-                               bprun = 0;
-                               plfstrt_sprite = 0x100;
 #ifdef DEBUGGER
-                               if (debug_dma) {
-                                       record_dma_event_agnus(AGNUS_EVENT_BPRUN, false);
-                               }
-#endif
+                       if (debug_dma) {
+                               record_dma_event_agnus(AGNUS_EVENT_BPRUN2, true);
                        }
+#endif
                }
+#endif
 
        } else {
 
                // OCS
 
+               bool dma = dmacon_bpl2;
+               // OCS BPLENA is delayed by extra 1 CCK compared to ECS/AGA
+               dmacon_bpl2 = dmacon_bpl;
+
                // DDFSTOP
                // Triggers DDFSTOP condition.
-               if (hpos == (ddfstop | 0)) {
-                       if (bprun > 0 && !ddf_stopping) {
+               if ((hpos == ddfstop && cyc > ddfstop_cycle) || (hpos == ddfstop_old && cyc <= ddfstop_cycle)) {
+                       if (bprun && !ddf_stopping) {
                                ddf_stopping = 1;
 #ifdef DEBUGGER
                                if (debug_dma) {
@@ -10005,25 +10010,14 @@ static void decide_bpl(int hpos)
                        }
                }
 
-               // BPRUN latched: On
-               if (bprun < 0 && (hpos & 1)) {
-                       bprun = 1;
-                       bprun_cycle = 0;
-#ifdef DEBUGGER
-                       if (debug_dma) {
-                               record_dma_event_agnus(AGNUS_EVENT_BPRUN, true);
-                       }
-#endif
-               }
-
                // Hard start limit
                if (hpos == 0x18) {
-                       ddf_limit = false;
+                       ddf_limit_in = false;
                }
 
                // Hard stop limit
                // Triggers DDFSTOP condition. Last cycle of bitplane DMA resets DDFSTRT limit.
-               if (hpos == (0xd7 + 0)) {
+               if (hpos == 0xd7) {
                        if (bprun && !ddf_stopping) {
                                ddf_stopping = 1;
 #ifdef DEBUGGER
@@ -10035,25 +10029,28 @@ static void decide_bpl(int hpos)
                }
 
                // DDFSTRT
-               if (hpos == ddfstrt) {
+               if ((hpos == ddfstrt_val && cyc > ddfstrt_cycle) || (hpos == ddfstrt_val_old && cyc <= ddfstrt_cycle)) {
                        ddfstrt_match = true;
                        if (currprefs.gfx_scandoubler && linear_vpos < MAX_SCANDOUBLED_LINES) {
                                update_bpl_scandoubler();
                        }
+#ifdef DEBUGGER
+                       if (debug_dma) {
+                               record_dma_event(DMA_EVENT_DDFSTRT);
+                       }
+#endif
                } else {
                        ddfstrt_match = false;
                }
 
-               if (!ddf_limit && ddfstrt_match && !bprun && dma && diw) {
+               if (!ddf_limit_out && ddfstrt_match && !bprun && dma && diw) {
                        // Bitplane sequencer activated
-                       bprun = -1;
-                       if (plfstrt_sprite > hpos) {
-                               plfstrt_sprite = hpos;
-                       }
                        bprun_start(hpos);
+                       bprun = 1;
+                       bprun_cycle = 0;
 #ifdef DEBUGGER
                        if (debug_dma) {
-                               record_dma_event(DMA_EVENT_DDFSTRT);
+                               record_dma_event_agnus(AGNUS_EVENT_BPRUN, true);
                        }
 #endif
                }
@@ -10065,7 +10062,6 @@ static void decide_bpl(int hpos)
                                ddf_stopping = 2;
                        }
                        bprun = 0;
-                       plfstrt_sprite = 0x100;
 #ifdef DEBUGGER
                        if (debug_dma) {
                                record_dma_event_agnus(AGNUS_EVENT_BPRUN, false);
@@ -10079,7 +10075,6 @@ static void decide_bpl(int hpos)
                        if (ddf_stopping == 1) {
                                ddf_stopping = 2;
                                bprun = 0;
-                               plfstrt_sprite = 0x100;
 #ifdef DEBUGGER
                                if (debug_dma) {
                                        record_dma_event_agnus(AGNUS_EVENT_BPRUN, false);
@@ -10159,7 +10154,7 @@ static void generate_sprites(int num, int slot)
                                }
                        }
 
-                       if (hp <= plfstrt_sprite || bplconflict) {
+                       if (bprun != 1 || bplconflict) {
                                dodma = true;
 #ifdef AGA
                                if (dodma && s->dblscan && (fmode & 0x8000) && (vpos & 1) != (s->vstart & 1) && s->dmastate) {
@@ -11579,10 +11574,6 @@ static void inc_cck(void)
                agnus_pos_change--;
                if (agnus_pos_change == 0) {
                        if (agnus_hpos_next >= 0) {
-                               if (agnus_hpos_next) {
-                                       int hnewglitch = agnus_hpos_next & ~1;
-                                       decide_bpl(hnewglitch);
-                               }
                                agnus_hpos = agnus_hpos_next;
                                agnus_hpos_next = -1;
                        }
@@ -12308,8 +12299,7 @@ static void do_cck(bool docycles)
                do_cycles_normal(1 * CYCLE_UNIT);
        }
 
-       dmacon_bpl = dmaen(DMA_BITPLANE);
-       dmacon_next = dmacon;
+       dmacon_bpl = (dmacon & DMA_BITPLANE) && (dmacon & 0x200);
 
        handle_pipelined_write();
        handle_pipelined_custom_write(false);