static void blitter_doddma_new(int hpos, bool addmod)
{
uaecptr *hpt = NULL;
+ bool skip = false;
check_channel_mods(hpos, 4, &bltdpt);
- bltdpt |= alloc_cycle_blitter_conflict_or(hpos);
- record_dma_blit(0x00, ddat1, bltdpt, hpos);
- blit_chipmem_agnus_wput(bltdpt, ddat1, MW_MASK_BLITTER_D_N);
- bool skipadd = alloc_cycle_blitter(hpos, &bltdpt, 4, addmod ? blit_modaddd : 0);
+ bltdpt |= alloc_cycle_blitter_conflict_or(hpos, 4, &skip);
+ // alloc_cycle_blitter() can change modulo, old modulo is used during this cycle.
+ int mod = blit_modaddd;
+ if (!skip) {
+ record_dma_blit(0x00, ddat1, bltdpt, hpos);
+ blit_chipmem_agnus_wput(bltdpt, ddat1, MW_MASK_BLITTER_D_N);
+ }
+ bool skipadd = alloc_cycle_blitter(hpos, &bltdpt, 4, addmod ? mod : 0);
if (!blitline && !skipadd) {
bltdpt += blit_add;
}
if (addmod) {
- bltdpt += blit_modaddd;
+ bltdpt += mod;
}
}
static void blitter_dodma_new(int ch, int hpos, bool addmod)
{
- uae_u16 dat, reg;
+ uae_u16 dat;
uae_u32 *addr;
bool skipadd = false;
int mod;
+ bool skip = false;
- uaecptr orptr = alloc_cycle_blitter_conflict_or(hpos);
+ uaecptr orptr = alloc_cycle_blitter_conflict_or(hpos, ch, &skip);
switch (ch)
{
{
bltapt |= orptr;
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_val(dat);
- regs.chipset_latch_rw = blt_info.bltadat;
+ if (!skip) {
+ uae_u16 reg = 0x74;
+ record_dma_blit(reg, 0, bltapt, hpos);
+ blt_info.bltadat = dat = chipmem_wget_indirect(bltapt);
+ record_dma_blit_val(dat);
+ regs.chipset_latch_rw = blt_info.bltadat;
+ }
addr = &bltapt;
mod = blit_modadda;
skipadd = alloc_cycle_blitter(hpos, &bltapt, 1, addmod ? mod : 0);
int bshift = bltcon1 >> 12;
bltbpt |= orptr;
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_val(dat);
- regs.chipset_latch_rw = blt_info.bltbdat;
+ if (!skip) {
+ uae_u16 reg = 0x72;
+ record_dma_blit(reg, 0, bltbpt, hpos);
+ blt_info.bltbdat = dat = chipmem_wget_indirect(bltbpt);
+ record_dma_blit_val(dat);
+ regs.chipset_latch_rw = blt_info.bltbdat;
+ }
addr = &bltbpt;
mod = blit_modaddb;
if (blitdesc)
}
case 3: // C
{
- reg = 0x70;
bltcpt |= orptr;
check_channel_mods(hpos, 3, &bltcpt);
- record_dma_blit(reg, 0, bltcpt, hpos);
- blt_info.bltcdat = dat = chipmem_wget_indirect(bltcpt);
- record_dma_blit_val(dat);
- regs.chipset_latch_rw = blt_info.bltcdat;
+ if (!skip) {
+ uae_u16 reg = 0x70;
+ record_dma_blit(reg, 0, bltcpt, hpos);
+ blt_info.bltcdat = dat = chipmem_wget_indirect(bltcpt);
+ record_dma_blit_val(dat);
+ regs.chipset_latch_rw = blt_info.bltcdat;
+ }
addr = &bltcpt;
mod = blit_modaddc;
skipadd = alloc_cycle_blitter(hpos, &bltcpt, 3, addmod ? mod : 0);
blitter_line_proc_cpt_y();
blitlineloop = 0;
}
- uaecptr orptr = alloc_cycle_blitter_conflict_or(hpos);
+ bool skip = false;
+ uaecptr orptr = alloc_cycle_blitter_conflict_or(hpos, 3, &skip);
record_dma_blit(0x70, 0, bltcpt | orptr, hpos);
check_channel_mods(hpos, 3, &bltcpt);
- blt_info.bltcdat = chipmem_wget_indirect(bltcpt | orptr);
- regs.chipset_latch_rw = blt_info.bltcdat;
- record_dma_blit_val(blt_info.bltcdat);
+ if (!skip) {
+ 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, 0);
if (dat & BLITTER_PIPELINE_FIRST) {
/* onedot mode and no pixel = bus write access is skipped */
if (blitlinepixel && c == 4) {
- uaecptr orptr = alloc_cycle_blitter_conflict_or(hpos);
+ bool skip = false;
+ uaecptr orptr = alloc_cycle_blitter_conflict_or(hpos, 4, &skip);
record_dma_blit(0x00, blt_info.bltddat, bltdpt | orptr, hpos);
check_channel_mods(hpos, 4, &bltdpt);
- blit_chipmem_agnus_wput(bltdpt | orptr, blt_info.bltddat, MW_MASK_BLITTER_D_L);
+ if (!skip) {
+ blit_chipmem_agnus_wput(bltdpt | orptr, blt_info.bltddat, MW_MASK_BLITTER_D_L);
+ }
alloc_cycle_blitter(hpos, &bltdpt, 4, 0);
} else {
markidlecycle(hpos);
#define ALL_SUBPIXEL 1
#define RGA_COPPER_PIPELINE_DEPTH 2
-#define RGA_SPRITE_PIPELINE_DEPTH 3
+#define RGA_SPRITE_PIPELINE_DEPTH 2
#define REFRESH_FIRST_HPOS 3
#define DMAL_FIRST_HPOS 11
#define SPR_FIRST_HPOS 25
static struct sprite spr[MAX_SPRITES];
static int plfstrt_sprite;
static int sprbplconflict, sprbplconflict_hpos;
+static int sprbplconflict2, sprbplconflict_hpos2;
+static uae_u16 sprbplconflict_dat;
uaecptr sprite_0;
int sprite_0_width, sprite_0_height, sprite_0_doubled;
uae_u32 sprite_0_colors[4];
static evt_t copper_bad_cycle_start;
static uaecptr copper_bad_cycle_pc_new;
+static evt_t copper_dma_change_cycle;
+static evt_t blitter_dma_change_cycle;
+static evt_t sprite_dma_change_cycle_on, sprite_dma_change_cycle_off;
+
/*
* Statistics
*/
#define RGA_PIPELINE_OFFSET_BPL_WRITE 3
#define RGA_PIPELINE_OFFSET_COPPER 2
-#define RGA_PIPELINE_OFFSET_SPRITE 3
+#define RGA_PIPELINE_OFFSET_SPRITE 2
#define RGA_PIPELINE_OFFSET_DMAL 2
struct custom_store custom_storage[256];
* helper functions
*/
+static bool safecpu(void)
+{
+ return currprefs.cpu_model == 68000 && currprefs.cpu_cycle_exact && currprefs.blitter_cycle_exact && currprefs.m68k_speed == 0 && !(currprefs.cs_hacks & 16);
+}
+
static void check_nocustom(void)
{
struct amigadisplay* ad = &adisplays[0];
alloc_cycle(hpos, type);
}
-uaecptr alloc_cycle_blitter_conflict_or(int hpos)
+uaecptr alloc_cycle_blitter_conflict_or(int hpos, int chnum, bool *skip)
{
uaecptr orptr = 0;
if (copper_bad_cycle && line_start_cycles + hpos * CYCLE_UNIT == copper_bad_cycle) {
orptr = copper_bad_cycle_pc_old;
+ } else if (hpos == sprbplconflict_hpos2) {
+ uae_u16 bltdat = chnum == 4 ? 0x000 : (3 - chnum) * 2 + 0x70;
+ uae_u16 rga = bltdat & sprbplconflict2;
+ int spnum = (sprbplconflict2 - 0x140) / 8;
+ orptr = spr[spnum].pt;
+ if (rga != bltdat) {
+ *skip = true;
+ }
}
return orptr;
}
{
bool skipadd = false;
if (copper_bad_cycle && line_start_cycles + hpos * CYCLE_UNIT == copper_bad_cycle) {
- write_log("Copper PT=%08x/%08x. Blitter CH=%d PT=%08x. Conflict bug!\n", copper_bad_cycle_pc_old, copper_bad_cycle_pc_new, chnum, *ptr);
+ write_log("Copper PT=%08x/%08x. Blitter CH=%d MOD=%d PT=%08x. Conflict bug!\n", copper_bad_cycle_pc_old, copper_bad_cycle_pc_new, chnum, add, *ptr);
cop_state.ip += add;
*ptr = copper_bad_cycle_pc_old;
skipadd = true;
copper_bad_cycle = 0;
- //activate_debugger();
+ } else if (hpos == sprbplconflict_hpos2) {
+ uae_u16 v = chipmem_wget_indirect(*ptr);
+ uae_u16 bltdat = chnum == 4 ? 0x000 : (3 - chnum) * 2 + 0x70;
+ uae_u16 rga = bltdat & sprbplconflict2;
+ int spnum = (sprbplconflict2 - 0x140) / 8;
+ uaecptr pt = spr[spnum].pt;
+ spr[spnum].pt = *ptr + 2 + add;
+ custom_wput_1(hpos, rga, v, 1);
+#ifdef DEBUGGER
+ if (debug_dma) {
+ record_dma_read_value(v);
+ record_dma_read(rga, *ptr, hpos, vpos, DMARECORD_SPRITE, spnum);
+ }
+#endif
+ write_log("Sprite %d. Blitter CH=%d MOD=%d PT=%08x. Conflict bug!\n", spnum, chnum, add, *ptr);
}
alloc_cycle(hpos, CYCLE_BLITTER);
return skipadd;
/* Default to no bitplane DMA overriding sprite DMA */
plfstrt_sprite = 0x100;
sprbplconflict_hpos = -1;
+ sprbplconflict_hpos2 = -1;
bprun_end = 0;
// clear sprite allocations
return 0;
}
+// if DMA was changed during same cycle: previous value is used
+static bool is_blitter_dma(void)
+{
+ bool dma = dmaen(DMA_BLITTER);
+ if (get_cycles() == blitter_dma_change_cycle) {
+ return dma == false;
+ }
+ return dma;
+}
+static bool is_copper_dma(void)
+{
+ bool dma = dmaen(DMA_COPPER);
+ if (get_cycles() == copper_dma_change_cycle) {
+ return dma == false;
+ }
+ return dma;
+}
+
static void immediate_copper(int num)
{
int pos = 0;
if (oldpos > pos) {
pos = oldpos;
}
- if (!dmaen(DMA_COPPER)) {
+ if (!is_copper_dma()) {
break;
}
if (cop_state.ip >= currprefs.chipmem.size &&
if (!oldstrobe) {
cop_state.state_prev = cop_state.state;
}
- if ((cop_state.state == COP_wait1 || cop_state.state == COP_waitforever) && !vblank && dmaen(DMA_COPPER)) {
+ if ((cop_state.state == COP_wait1 || cop_state.state == COP_waitforever) && !vblank && is_copper_dma()) {
if (blt_info.blit_main) {
static int warned = 100;
if (warned > 0) {
}
}
int hp = current_hpos();
- if ((hp & 1) && currprefs.cpu_model == 68000 && currprefs.cpu_cycle_exact && currprefs.blitter_cycle_exact && currprefs.m68k_speed == 0 && !(currprefs.cs_hacks & 16)) {
+ if ((hp & 1) && safecpu()) {
// CPU unaligned COPJMP while waiting
cop_state.state = COP_strobe_delay1x;
copper_bad_cycle_start = get_cycles();
return;
}
- if (dmaen(DMA_COPPER)) {
+ if (is_copper_dma()) {
compute_spcflag_copper();
} else if (wasstopped || (oldstrobe > 0 && oldstrobe != num && cop_state.state_prev == COP_wait1)) {
/* dma disabled, copper idle and accessed both COPxJMPs -> copper stops! */
static void check_copper_stop(void)
{
- if (copper_enabled_thisline < 0 && !((dmacon & DMA_COPPER) && (dmacon & DMA_MASTER))) {
+ if (copper_enabled_thisline < 0 && !(is_copper_dma() && (dmacon & DMA_MASTER))) {
copper_enabled_thisline = 0;
unset_special(SPCFLAG_COPPER);
}
static void DMACON(int hpos, uae_u16 v)
{
- int oldcop, newcop;
uae_u16 changed;
-
uae_u16 oldcon = dmacon;
decide_line(hpos);
if (changed)
write_log(_T("%04x -> %04x %08x\n"), oldcon, dmacon, m68k_getpc ());
#endif
- oldcop = (oldcon & DMA_COPPER) && (oldcon & DMA_MASTER);
- newcop = (dmacon & DMA_COPPER) && (dmacon & DMA_MASTER);
- if (oldcop != newcop) {
- if (newcop && !oldcop) {
- compute_spcflag_copper();
- } else if (!newcop) {
- copper_stop();
+ int oldcop = (oldcon & DMA_COPPER) && (oldcon & DMA_MASTER);
+ int newcop = (dmacon & DMA_COPPER) && (dmacon & DMA_MASTER);
+ if (oldcop != newcop && (copper_access || safecpu())) {
+ copper_dma_change_cycle = get_cycles();
+ }
+ if (newcop && !oldcop) {
+ compute_spcflag_copper();
+ }
+
+ int oldblt = (oldcon & DMA_BLITTER) && (oldcon & DMA_MASTER);
+ int newblt = (dmacon & DMA_BLITTER) && (dmacon & DMA_MASTER);
+ if (oldblt != newblt && (copper_access || safecpu())) {
+ if (copper_access) {
+ blitter_dma_change_cycle = get_cycles();
+ } else {
+ // because of CPU vs blitter emulation side-effect
+ blitter_dma_change_cycle = get_cycles() + CYCLE_UNIT;
+ }
+ }
+
+ int oldspr = (oldcon & DMA_SPRITE) && (oldcon & DMA_MASTER);
+ int newspr = (dmacon & DMA_SPRITE) && (dmacon & DMA_MASTER);
+ if (!oldspr && newspr) {
+ if (copper_access || safecpu()) {
+ sprite_dma_change_cycle_on = get_cycles() + CYCLE_UNIT;
}
}
}
#endif
- if ((dmacon & DMA_BLITPRI) > (oldcon & DMA_BLITPRI) && (blt_info.blit_main || blt_info.blit_finald || blt_info.blit_queued))
+ if ((dmacon & DMA_BLITPRI) > (oldcon & DMA_BLITPRI) && (blt_info.blit_main || blt_info.blit_finald || blt_info.blit_queued)) {
set_special(SPCFLAG_BLTNASTY);
+ }
- if (dmaen (DMA_BLITTER) && blt_info.blit_pending) {
+ if (dmaen(DMA_BLITTER) && blt_info.blit_pending) {
blitter_check_start();
}
if ((dmacon & (DMA_BLITPRI | DMA_BLITTER | DMA_MASTER)) != (DMA_BLITPRI | DMA_BLITTER | DMA_MASTER))
unset_special(SPCFLAG_BLTNASTY);
- if (changed & (DMA_MASTER | 0x0f))
+ if (changed & (DMA_MASTER | DMA_AUD3 | DMA_AUD2 | DMA_AUD1 | DMA_AUD0)) {
audio_state_machine();
+ }
if (changed & (DMA_MASTER | DMA_BITPLANE)) {
- if (dmaen(DMA_BITPLANE)) {
- bitplane_dma_change(dmacon);
- } else {
- bitplane_dma_change(dmacon);
- //event2_newevent_xx(-1, CYCLE_UNIT, dmacon, bitplane_dma_change);
- }
+ bitplane_dma_change(dmacon);
SET_LINE_CYCLEBASED;
}
}
bool blitter_cant_access(int hpos)
{
- if (!dmaen(DMA_BLITTER)) {
+ if (!is_blitter_dma()) {
return true;
}
// bitplane dma check
static bool copper_cant_read(int hpos, uae_u16 alloc)
{
- if (!dmaen(DMA_COPPER)) {
+ if (!is_copper_dma()) {
return true;
}
static void compute_spcflag_copper(void)
{
- if (!dmaen(DMA_COPPER) || cop_state.state == COP_stop || cop_state.state == COP_waitforever || cop_state.state == COP_bltwait || cop_state.state == COP_bltwait2 || custom_disabled)
+ if (!is_copper_dma() || cop_state.state == COP_stop || cop_state.state == COP_waitforever || cop_state.state == COP_bltwait || cop_state.state == COP_bltwait2 || custom_disabled)
return;
if (cop_state.state == COP_wait1) {
int vp = vpos & (((cop_state.ir[1] >> 8) & 0x7F) | 0x80);
decide_sprites(hpos, false, true);
sprite_fetch_full(s, hpos, slot, dmastate, &data, &data321, &data322);
+
+ // do pointer increase only
+ if (!(dat & CYCLE_PIPE_SPRITE)) {
+ if (debug_dma) {
+ record_dma_event(DMA_EVENT_SPECIAL, hpos, vpos);
+ }
+ return;
+ }
+
int sprxp = s->xpos >> (sprite_buffer_res + 1);
if (dmastate) {
if (!slot) {
while (hpos < endhpos) {
if (hpos >= SPR_FIRST_HPOS - RGA_SPRITE_PIPELINE_DEPTH && hpos < SPR_FIRST_HPOS + MAX_SPRITES * 4) {
- bool sprite_dma = (cycle_line_pipe[hpos] & CYCLE_PIPE_SPRITE) != 0;
- if (sprite_dma) {
- uae_u16 dat = cycle_line_pipe[hpos];
- do_sprite_fetch(hpos, dat);
- }
-
if (hpos < SPR_FIRST_HPOS + MAX_SPRITES * 4 - RGA_SPRITE_PIPELINE_DEPTH) {
int num = (hpos - (SPR_FIRST_HPOS - RGA_SPRITE_PIPELINE_DEPTH)) / 4;
int slot = (hpos - (SPR_FIRST_HPOS - RGA_SPRITE_PIPELINE_DEPTH)) & 3;
write_log(_T("sprite cycle already allocated! %02x\n"), cycle_line_pipe[offset]);
}
#endif
- if (bprun_end == hpos) {
+ evt_t t = line_start_cycles + hpos * CYCLE_UNIT;
+ if (t == sprite_dma_change_cycle_on) {
+ // if sprite DMA is switched on just when sprite DMA is decided, channel is still decided to it is not allocated!
+ sprbplconflict2 = 0x140 + num * 8 + slot + (s->dmacycle ? 4 : 0);
+ sprbplconflict_hpos = sprbplconflict_hpos2 = hpos + RGA_PIPELINE_OFFSET_SPRITE;
+ sprbplconflict_dat = dat & ~CYCLE_PIPE_SPRITE;
+ } else if (bprun_end == hpos) {
+ // last bitplane cycle is available for sprites (if bitplane ends before all sprites)
sprbplconflict = 0x140 + num * 8 + slot + (s->dmacycle ? 4 : 0);
sprbplconflict_hpos = hpos + RGA_PIPELINE_OFFSET_SPRITE;
+ sprbplconflict_dat = dat & ~CYCLE_PIPE_SPRITE;
} else {
cycle_line_pipe[offset] = dat;
}
}
}
}
+
+ bool sprite_dma = (cycle_line_pipe[hpos] & CYCLE_PIPE_SPRITE) != 0;
+ if (sprite_dma) {
+ uae_u16 dat = cycle_line_pipe[hpos];
+ do_sprite_fetch(hpos, dat);
+ }
+ if (hpos == sprbplconflict_hpos2) {
+ do_sprite_fetch(hpos, sprbplconflict_dat);
+ }
}
hpos++;
}
set_hcenter();
display_reset = 1;
copper_bad_cycle = 0;
+ copper_dma_change_cycle = -1;
+ blitter_dma_change_cycle = -1;
+ sprite_dma_change_cycle_on = -1;
if (hardreset || savestate_state) {
maxhpos = ntsc ? MAXHPOS_NTSC : MAXHPOS_PAL;