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;
};
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];
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 */
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;
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)
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();
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];
#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;
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) {
}
}
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.
}
#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) {
}
}
- // 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
}
// 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
}
ddf_stopping = 2;
}
bprun = 0;
- plfstrt_sprite = 0x100;
#ifdef DEBUGGER
if (debug_dma) {
record_dma_event_agnus(AGNUS_EVENT_BPRUN, false);
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);
}
}
- 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) {
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;
}
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);