uae_u32 bltapt, bltbpt, bltcpt, bltdpt;
uae_u32 bltptx;
int bltptxpos, bltptxc;
-int blitter_nasty;
-// blitter is active and D may write to visible bitplane addresses
-int blitter_dangerous_bpl;
static int original_ch, original_fill, original_line;
static uae_u16 ddat1, ddat2;
static int ddat1use, ddat2use;
-int blit_interrupt;
-
static int last_blitter_hpos;
static uae_u16 debug_bltcon0, debug_bltcon1;
static void blitter_interrupt (int hpos, int done)
{
- if (blit_interrupt)
+ if (blt_info.blit_interrupt)
return;
if (!done && (!blitter_cycle_exact || immediate_blits || currprefs.cpu_model >= 68030 || currprefs.cachesize || currprefs.m68k_speed < 0))
return;
- blit_interrupt = 1;
+ blt_info.blit_interrupt = 1;
send_interrupt (6, 4 * CYCLE_UNIT);
if (debug_dma)
record_dma_event (DMA_EVENT_BLITIRQ, hpos, vpos);
if (log_blitter & 1)
write_log (_T("cycles %d, missed %d, total %d\n"),
blit_totalcyclecounter, blit_misscyclecounter, blit_totalcyclecounter + blit_misscyclecounter);
- blitter_dangerous_bpl = 0;
+ blt_info.blitter_dangerous_bpl = 0;
}
STATIC_INLINE void chipmem_agnus_wput2 (uaecptr addr, uae_u32 w)
if (v <= 0) {
blit_misscyclecounter++;
- blitter_nasty++;
break;
}
blitter_read ();
alloc_cycle_blitter (last_blitter_hpos, &bltcpt, 3);
record_dma_blit (0x70, blt_info.bltcdat, bltcpt, last_blitter_hpos);
- blitter_nasty++;
} else if (c == 5) {
alloc_cycle_blitter (last_blitter_hpos, &bltdpt, 4);
record_dma_blit (0x00, blt_info.bltddat, bltdpt, last_blitter_hpos);
blitlinepixel = 0;
- blitter_nasty++;
}
if (blt_info.vblitsize == 0) {
bltdpt = bltcpt;
#if 1
if ((blit_cyclecounter < 0 || !blit_final || (blitfill && blit_cycle_diagram_fill[blit_ch][0])) && ((c == 0 && v == 0) || v < 0)) {
blit_misscyclecounter++;
- blitter_nasty++;
break;
}
#else
}
if (blitfill && blit_cycle_diagram_fill[blit_ch][0]) {
blit_misscyclecounter++;
- blitter_nasty++;
break;
}
}
break;
}
- blitter_nasty++;
-
if (v <= 0) {
blit_misscyclecounter++;
break;
if (!savestate_state && bltstate != BLT_done && bltstate != BLT_init && blitline && blitline_started) {
blitline = 0;
bltstate = BLT_done;
- blit_interrupt = 1;
+ blt_info.blit_interrupt = 1;
write_log (_T("BLITTER: register modification during linedraw! %08x\n"), M68K_GETPC);
if (log_blitter & 16)
activate_debugger ();
blit_bltset (1 | 2);
blit_modset ();
ddat1use = ddat2use = 0;
- blit_interrupt = 0;
+ blt_info.blit_interrupt = 0;
blt_info.bltaold = 0;
blt_info.bltbold = 0;
blitlinepixel = 0;
blitsing = bltcon1 & 0x2;
}
+
+ if (!(dmacon & DMA_BLITPRI) && blt_info.nasty_cnt >= BLIT_NASTY_CPU_STEAL_CYCLE_COUNT) {
+ blt_info.wait_nasty = 1;
+ } else {
+ blt_info.wait_nasty = 0;
+ }
}
static void do_blitter2(int hpos, int copper, uaecptr pc)
do_blitter2(hpos, copper, pc);
return;
}
+
+ if (dmaen(DMA_BLITTER) && (log_blitter & 16)) {
+ activate_debugger();
+ }
+
if (!dmaen (DMA_BLITTER) || !blt_info.got_cycle)
return;
// previous blit may have last write cycle left
void check_is_blit_dangerous (uaecptr *bplpt, int planes, int words)
{
- blitter_dangerous_bpl = 0;
+ blt_info.blitter_dangerous_bpl = 0;
if (bltstate == BLT_done || !blitter_cycle_exact)
return;
// too simple but better than nothing
uaecptr bpl = bplpt[i];
uaecptr dpt = bltdpt & chipmem_bank.mask;
if (dpt >= bpl - 2 * words && dpt < bpl + 2 * words) {
- blitter_dangerous_bpl = 1;
+ blt_info.blitter_dangerous_bpl = 1;
return;
}
}
record_dma_reset ();
record_dma_reset ();
if (blt_statefile_type == 0) {
- blit_interrupt = 1;
+ blt_info.blit_interrupt = 1;
if (bltstate == BLT_init) {
write_log (_T("blitter was started but DMA was inactive during save\n"));
//do_blitter (0);
blitlinepixel = restore_u8 ();
blitsing = restore_u8 ();
blitlinepixel = restore_u8 ();
- blit_interrupt = restore_u8 ();
+ blt_info.blit_interrupt = restore_u8 ();
blt_delayed_irq = restore_u8 ();
blt_info.blitzero = restore_u8 ();
blt_info.got_cycle = restore_u8 ();
if (restore_u16 () != 0x1234)
write_log (_T("error\n"));
- blitter_nasty = restore_u8 ();
+ blt_info.blitter_nasty = restore_u8 ();
bltstate = BLT_done;
if (!blitter_cycle_exact) {
save_u8 (blitlinepixel);
save_u8 (blitsing);
save_u8 (blitlinepixel);
- save_u8 (blit_interrupt);
+ save_u8 (blt_info.blit_interrupt);
save_u8 (blt_delayed_irq);
save_u8 (blt_info.blitzero);
save_u8 (blt_info.got_cycle);
save_u16 (0x1234);
- save_u8 (blitter_nasty);
+ save_u8 (blt_info.blitter_nasty);
*len = dst - dstbak;
return dstbak;
int strobe; /* COPJMP1 / COPJMP2 accessed */
int last_strobe;
int moveaddr, movedata, movedelay;
+ int blitbusy;
};
static struct copper cop_state;
plf_wait,
// ddfstop passed
plf_passed_stop,
+ // before ddfstop+4 passed
+ plf_passed_stop_pre_act,
// ddfstop+4 passed
plf_passed_stop_act,
// last block finished
// 4+ stage shift register that causes these delays.
if (plf_state == plf_active || plf_state == plf_passed_stop || plf_state == plf_passed_stop_act) {
bpl_dma_off_when_active = 1;
+ if (!dma) {
+ // if DMA ends just before next BPL1DAT fetch: do one block only.
+ // otherwise: do two blocks.
+ if (is_bitplane_dma(pos + 2) != 1) {
+ bpl_dma_off_when_active = 2;
+ }
+ bpl_dma_off_when_active |= 4;
+ }
if (bitplane_off_delay <= 0)
bitplane_off_delay = !dma ? 4 : 5;
}
plf_state = plf_wait;
}
}
+ if (bpl_dma_off_when_active) {
+ // check if passed DDFSTOP
+ if (pos == plfstop && ddfstop_written_hpos != pos) {
+ bpl_dma_off_when_active |= 8;
+ }
+ }
}
if ((dma && diw) || (currprefs.chipset_mask & CSMASK_ECS_AGNUS)) {
finish_last_fetch(pos, fm, false);
return 1;
}
- if (plf_state == plf_passed_stop_act) {
+ if (plf_state == plf_passed_stop_pre_act) {
+ plf_state = plf_passed_stop_act;
+ } else if (plf_state == plf_passed_stop_act) {
plf_state = plf_passed_stop2;
}
}
STATIC_INLINE void decide_fetch_safe (int hpos)
{
- if (!blitter_dangerous_bpl && !bitplane_overrun) {
+ if (!blt_info.blitter_dangerous_bpl && !bitplane_overrun) {
decide_fetch (hpos);
decide_blitter (hpos);
} else {
plf_end_hpos = HARD_DDF_STOP + DDF_OFFSET;
nextstate = plf_passed_stop;
}
- if (bpl_dma_off_when_active) {
-#if 0
- if ((bitplane_maybe_start_hpos < hstart && bitplane_maybe_start_hpos >= 0) && (currprefs.chipset_mask & CSMASK_AGA)) {
- nextstate = plf_passed_stop2;
- } else {
-#endif
- nextstate = plf_passed_stop_act;
-#if 0
- }
-#endif
- bpl_dma_off_when_active = 0;
+ // if DMA was switched off, DDFSTOP was passed during off period and DMA got re-enabled: state machine continues from DDFSTOP passed state.
+ if (bpl_dma_off_when_active & 8) {
+ nextstate = (bpl_dma_off_when_active & 1) ? plf_passed_stop_act : plf_passed_stop_pre_act;
+ ddfstop_matched = true;
+ }
+ } else {
+ if ((bpl_dma_off_when_active & 8) && (bpl_dma_off_when_active & 4)) {
+ nextstate = (bpl_dma_off_when_active & 1) ? plf_passed_stop_act : plf_passed_stop_pre_act;
+ ddfstop_matched = true;
}
}
+ bpl_dma_off_when_active = 0;
if (nextstate != plf_end) {
plf_state = nextstate;
estimate_last_fetch_cycle(hstart);
hack_delay_shift = 0;
toscr_scanline_complex_bplcon1 = false;
- if (line_cyclebased) {
- line_cyclebased--;
- if (!line_cyclebased) {
- bpl_dma_off_when_active = 0;
- }
- }
-
memset(outword, 0, sizeof outword);
// fetched[] must not be cleared (Sony VX-90 / Royal Amiga Force)
todisplay_fetched[0] = todisplay_fetched[1] = false;
*missing = 1;
return 0xFFFF;
}
+
+static bool blit_busy(void)
+{
+ if (blt_info.blit_interrupt)
+ return false;
+ if (currprefs.cs_agnusbltbusybug) {
+ // Blitter busy bug: A1000 Agnus only sets busy-bit when blitter gets first DMA slot.
+ if (!blt_info.blit_interrupt && !blt_info.got_cycle)
+ return false;
+ // A1000 Agnus also has below bug but it does not need separate check because of above bug.
+ } else if (!(currprefs.chipset_mask & CSMASK_AGA)) {
+#if 0
+ // AGA apparently does not have this bug.
+ // Blitter busy bug: Blitter nasty off, CPU attempting to steal cycle, Copper started blitter,
+ // Copper WAITing for blitter finished: busy is not set until CPU gets the cycle.
+ // NOT CORRECT YET
+ if (!(dmacon & DMA_BLITPRI) && blt_info.wait_nasty && blt_info.nasty_cnt >= BLIT_NASTY_CPU_STEAL_CYCLE_COUNT)
+ return false;
+#endif
+ }
+ return true;
+}
+
STATIC_INLINE uae_u16 DMACONR (int hpos)
{
decide_line (hpos);
decide_fetch_safe (hpos);
dmacon &= ~(0x4000 | 0x2000);
- dmacon |= ((blit_interrupt || (!blit_interrupt && currprefs.cs_agnusbltbusybug && !blt_info.got_cycle)) ? 0 : 0x4000)
- | (blt_info.blitzero ? 0x2000 : 0);
+ dmacon |= (blit_busy() ? 0x4000 : 0x0000) | (blt_info.blitzero ? 0x2000 : 0);
return dmacon;
}
STATIC_INLINE uae_u16 INTENAR (void)
vpos = oldvpos;
}
-
static void VHPOSW (uae_u16 v)
{
int oldvpos = vpos;
if (currprefs.cpu_compatible) {
event2_newevent_xx(-1, CYCLE_UNIT + CYCLE_UNIT / 2, 0, doint_delay_do);
} else {
- doint();
+ doint_delay_do(0);
}
}
/* Needed in special OCS/ECS "7-plane" mode,
* also handles CPU generated bitplane data
*/
-static void BPLxDAT (int hpos, int num, uae_u16 v)
+static void BPLxDAT_next(uae_u32 v)
{
+ int num = v >> 16;
+ uae_u16 data = (uae_u16)v;
+ int hpos = current_hpos();
+
// only BPL1DAT access can do anything visible
if (num == 0 && hpos >= 8) {
- decide_line (hpos);
- decide_fetch_safe (hpos);
+ decide_line(hpos);
+ decide_fetch_safe(hpos);
}
- flush_display (fetchmode);
+ flush_display(fetchmode);
fetched[num] = v;
if ((fmode & 3) == 3) {
fetched_aga[num] = ((uae_u64)last_custom_value2 << 48) | ((uae_u64)v << 32) | (v << 16) | v;
} else {
fetched_aga[num] = v;
}
+}
+
+
+static void BPLxDAT (int hpos, int num, uae_u16 v)
+{
+ event2_newevent2(1, (num << 16) | v, BPLxDAT_next);
+
if (num == 0 && hpos >= 8) {
bpl1dat_written = true;
bpl1dat_written_at_least_once = true;
if (thisline_decision.plfleft < 0)
- reset_bpl_vars ();
- beginning_of_plane_block (hpos, fetchmode);
+ reset_bpl_vars();
+ beginning_of_plane_block(hpos, fetchmode);
}
}
if (copper_cant_read (old_hpos, 0))
continue;
cop_state.state = COP_wait1;
+ // check blitter status early
+ cop_state.blitbusy = 0;
+ if ((cop_state.saved_i2 & 0x8000) == 0) {
+ decide_blitter(old_hpos);
+ cop_state.blitbusy = blit_busy();
+ }
break;
case COP_skip_in2:
if (copper_cant_read (old_hpos, 0))
continue;
cop_state.state = COP_skip1;
+ // check blitter status early
+ cop_state.blitbusy = 0;
+ if ((cop_state.saved_i2 & 0x8000) == 0) {
+ decide_blitter(old_hpos);
+ cop_state.blitbusy = blit_busy();
+ }
break;
case COP_strobe_extra:
*/
if ((cop_state.saved_i2 & 0x8000) == 0) {
decide_blitter(old_hpos);
- if (bltstate != BLT_done) {
+ if (cop_state.blitbusy) {
+ if (!blit_busy()) {
+ // if blitter was actually finished
+ // check again next copper cycle.
+ cop_state.state = COP_wait_in2;
+ continue;
+ }
/* We need to wait for the blitter. */
cop_state.state = COP_bltwait;
copper_enabled_thisline = 0;
{
unsigned int vcmp, hcmp, vp1, hp1;
- if (c_hpos >= (maxhpos & ~1) || (c_hpos & 1))
- break;
-
if (copper_cant_read (old_hpos, 0))
continue;
+ int ch_comp = c_hpos;
+ if (ch_comp & 1)
+ ch_comp = 0;
+
vcmp = (cop_state.saved_i1 & (cop_state.saved_i2 | 0x8000)) >> 8;
hcmp = (cop_state.saved_i1 & cop_state.saved_i2 & 0xFE);
vp1 = vpos & (((cop_state.saved_i2 >> 8) & 0x7F) | 0x80);
- hp1 = c_hpos & (cop_state.saved_i2 & 0xFE);
+ hp1 = ch_comp & (cop_state.saved_i2 & 0xFE);
- if ((vp1 > vcmp || (vp1 == vcmp && hp1 >= hcmp)) && ((cop_state.saved_i2 & 0x8000) != 0 || bltstate == BLT_done))
+ if ((vp1 > vcmp || (vp1 == vcmp && hp1 >= hcmp)) && ((cop_state.saved_i2 & 0x8000) != 0 || !cop_state.blitbusy))
cop_state.ignore_next = 1;
cop_state.state = COP_read1;
setup_fmodes (0);
beamcon0 = new_beamcon0 = beamcon0_saved = currprefs.ntscmode ? 0x00 : 0x20;
bltstate = BLT_done;
- blit_interrupt = 1;
+ blt_info.blit_interrupt = 1;
init_sprites ();
}
bplcon3_saved = bplcon3;
bplcon4_saved = bplcon4;
fmode_saved = fmode;
+ beamcon0_saved = new_beamcon0;
current_colors.extra = 0;
if (isbrdblank (-1, bplcon0, bplcon3))
STATIC_INLINE void decide_fetch_ce (int hpos)
{
- if ((line_cyclebased || blitter_dangerous_bpl) && vpos < current_maxvpos ())
+ if ((line_cyclebased || blt_info.blitter_dangerous_bpl) && vpos < current_maxvpos ())
decide_fetch (hpos);
}
-#define BLIT_NASTY 4
-
// blitter not in nasty mode = CPU gets one cycle if it has been waiting
// at least 4 cycles (all DMA cycles count, not just blitter cycles, even
// blitter idle cycles do count!)
{
int hpos, hpos_old;
- blitter_nasty = 1;
- if (cpu_tracer < 0)
+ blt_info.nasty_cnt = 1;
+ blt_info.wait_nasty = 0;
+ if (cpu_tracer < 0)
return current_hpos_safe();
if (!currprefs.cpu_memory_cycle_exact)
return current_hpos_safe();
decide_fetch_ce (hpos);
bpldma = is_bitplane_dma (hpos_old);
if (bltstate != BLT_done) {
- if (!blitpri && blitter_nasty >= BLIT_NASTY && (cycle_line[hpos_old] & CYCLE_MASK) == 0 && !bpldma) {
+ if (!blitpri && blt_info.nasty_cnt >= BLIT_NASTY_CPU_STEAL_CYCLE_COUNT && (cycle_line[hpos_old] & CYCLE_MASK) == 0 && !bpldma) {
alloc_cycle (hpos_old, CYCLE_CPUNASTY);
+ if (debug_dma && blt_info.nasty_cnt >= BLIT_NASTY_CPU_STEAL_CYCLE_COUNT) {
+ record_dma_event(DMA_EVENT_CPUBLITTERSTOLEN, hpos_old, vpos);
+ }
break;
}
decide_blitter (hpos);
alloc_cycle (hpos_old, CYCLE_CPU);
break;
}
+ if (debug_dma && blt_info.nasty_cnt >= BLIT_NASTY_CPU_STEAL_CYCLE_COUNT) {
+ record_dma_event(DMA_EVENT_CPUBLITTERSTEAL, hpos_old, vpos);
+ }
+
+ blt_info.nasty_cnt++;
do_cycles (1 * CYCLE_UNIT);
/* bus was allocated to dma channel, wait for next cycle.. */
}
+ blt_info.nasty_cnt = 0;
return hpos_old;
}
STATIC_INLINE void checknasty (int hpos, int vpos)
{
- if (blitter_nasty >= BLIT_NASTY && !(dmacon & DMA_BLITPRI))
+ if (blt_info.blitter_nasty >= BLIT_NASTY_CPU_STEAL_CYCLE_COUNT && !(dmacon & DMA_BLITPRI))
record_dma_event (DMA_EVENT_BLITNASTY, hpos, vpos);
}
decide_line (hpos);
sync_copper (hpos);
decide_fetch_ce (hpos);
- if (bltstate != BLT_done)
- decide_blitter (hpos);
+ if (bltstate != BLT_done) {
+ decide_blitter(hpos);
+ }
do_cycles (1 * CYCLE_UNIT);
cycles -= CYCLE_UNIT;
}