From 33b11270f8d5a340ea1fdd85e7263852e9aa8b06 Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Wed, 19 Nov 2025 19:27:17 +0200 Subject: [PATCH] DDFSTRT/STOP/etc handling rewrite --- custom.cpp | 240 +++++++++++++++++++++++++---------------------------- 1 file changed, 115 insertions(+), 125 deletions(-) diff --git a/custom.cpp b/custom.cpp index 58de9be8..de0889d9 100644 --- a/custom.cpp +++ b/custom.cpp @@ -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); -- 2.47.3