From: Toni Wilen Date: Sun, 6 Nov 2022 16:58:25 +0000 (+0200) Subject: Accurate CPU odd cycle COPJMPx write copper/blitter bug emulation X-Git-Tag: 41000~86 X-Git-Url: https://git.unchartedbackwaters.co.uk/w/?a=commitdiff_plain;h=7f1ef95c4aad3fe52d0a1a9cd5f49c3dcd186926;p=francis%2Fwinuae.git Accurate CPU odd cycle COPJMPx write copper/blitter bug emulation --- diff --git a/blitter.cpp b/blitter.cpp index ccf01121..c1311120 100644 --- a/blitter.cpp +++ b/blitter.cpp @@ -1330,13 +1330,15 @@ static int blitter_next_cycle(void) static void blitter_doddma_new(int hpos, bool addmod) { - check_channel_mods(hpos, 4, &bltdpt); + uaecptr *hpt = NULL; - record_dma_blit(0x00, ddat1, bltdpt, hpos); - blit_chipmem_agnus_wput(bltdpt, ddat1, MW_MASK_BLITTER_D_N); - alloc_cycle_blitter(hpos, &bltdpt, 4); + check_channel_mods(hpos, 4, &bltdpt); + uaecptr orptr = alloc_cycle_blitter_conflict_or(); + record_dma_blit(0x00, ddat1, bltdpt | orptr, hpos); + blit_chipmem_agnus_wput(bltdpt | orptr, ddat1, MW_MASK_BLITTER_D_N); + bool skipadd = alloc_cycle_blitter(hpos, &bltdpt, 4, addmod ? blit_modaddd : 0); - if (!blitline) { + if (!blitline && !skipadd) { bltdpt += blit_add; } if (addmod) { @@ -1348,21 +1350,24 @@ static void blitter_dodma_new(int ch, int hpos, bool addmod) { uae_u16 dat, reg; uae_u32 *addr; + bool skipadd = false; int mod; + uaecptr orptr = alloc_cycle_blitter_conflict_or(); + switch (ch) { case 1: // A { 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(reg, 0, bltapt | orptr, hpos); + blt_info.bltadat = dat = chipmem_wget_indirect(bltapt | orptr); record_dma_blit_val(dat); regs.chipset_latch_rw = blt_info.bltadat; addr = &bltapt; mod = blit_modadda; - alloc_cycle_blitter(hpos, &bltapt, 1); + skipadd = alloc_cycle_blitter(hpos, &bltapt, 1, addmod ? mod : 0); break; } case 2: // B @@ -1370,8 +1375,8 @@ static void blitter_dodma_new(int ch, int hpos, bool addmod) int bshift = bltcon1 >> 12; 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(reg, 0, bltbpt | orptr, hpos); + blt_info.bltbdat = dat = chipmem_wget_indirect(bltbpt | orptr); record_dma_blit_val(dat); regs.chipset_latch_rw = blt_info.bltbdat; addr = &bltbpt; @@ -1382,27 +1387,27 @@ static void blitter_dodma_new(int ch, int hpos, bool addmod) blt_info.bltbhold = (((uae_u32)blt_info.bltbold << 16) | blt_info.bltbdat) >> bshift; blineb = blt_info.bltbhold; blt_info.bltbold = blt_info.bltbdat; - alloc_cycle_blitter(hpos, &bltbpt, 2); + skipadd = alloc_cycle_blitter(hpos, &bltbpt, 2, addmod ? mod : 0); break; } case 3: // C { reg = 0x70; check_channel_mods(hpos, 3, &bltcpt); - record_dma_blit(reg, 0, bltcpt, hpos); - blt_info.bltcdat = dat = chipmem_wget_indirect(bltcpt); + record_dma_blit(reg, 0, bltcpt | orptr, hpos); + blt_info.bltcdat = dat = chipmem_wget_indirect(bltcpt | orptr); record_dma_blit_val(dat); regs.chipset_latch_rw = blt_info.bltcdat; addr = &bltcpt; mod = blit_modaddc; - alloc_cycle_blitter(hpos, &bltcpt, 3); + skipadd = alloc_cycle_blitter(hpos, &bltcpt, 3, addmod ? mod : 0); break; } default: abort(); } - if (!blitline) { + if (!blitline && !skipadd) { (*addr) += blit_add; } if (addmod) { @@ -1564,13 +1569,13 @@ static bool decide_blitter_maybe_write2(int until_hpos, uaecptr addr, uae_u32 va blitter_line_proc_cpt_y(); blitlineloop = 0; } - - record_dma_blit(0x70, 0, bltcpt, hpos); + uaecptr orptr = alloc_cycle_blitter_conflict_or(); + record_dma_blit(0x70, 0, bltcpt | orptr, hpos); check_channel_mods(hpos, 3, &bltcpt); - blt_info.bltcdat = chipmem_wget_indirect(bltcpt); + 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); + alloc_cycle_blitter(hpos, &bltcpt, 3, 0); if (dat & BLITTER_PIPELINE_FIRST) { blitter_line_minterm(dat); @@ -1601,10 +1606,11 @@ static bool decide_blitter_maybe_write2(int until_hpos, uaecptr addr, uae_u32 va /* onedot mode and no pixel = bus write access is skipped */ if (blitlinepixel && c == 4) { - record_dma_blit(0x00, blt_info.bltddat, bltdpt, hpos); + uaecptr orptr = alloc_cycle_blitter_conflict_or(); + record_dma_blit(0x00, blt_info.bltddat, bltdpt | orptr, hpos); check_channel_mods(hpos, 4, &bltdpt); - blit_chipmem_agnus_wput(bltdpt, blt_info.bltddat, MW_MASK_BLITTER_D_L); - alloc_cycle_blitter(hpos, &bltdpt, 4); + blit_chipmem_agnus_wput(bltdpt | orptr, blt_info.bltddat, MW_MASK_BLITTER_D_L); + alloc_cycle_blitter(hpos, &bltdpt, 4, 0); } else { markidlecycle(hpos); } @@ -1614,7 +1620,12 @@ static bool decide_blitter_maybe_write2(int until_hpos, uaecptr addr, uae_u32 va bltdpt = bltcpt; blitter_line_minterm(dat); - +#if 0 + if (blt_info.hblitsize == 1) { + blitter_line_proc_cpt_x(); + blitter_line_proc_cpt_y(); + } +#endif } else { // normal mode channels diff --git a/custom.cpp b/custom.cpp index 2dc95fe4..6ceaa9a4 100644 --- a/custom.cpp +++ b/custom.cpp @@ -511,6 +511,10 @@ struct copper { static struct copper cop_state; static int copper_enabled_thisline; +static evt_t copper_bad_cycle; +static uaecptr copper_bad_cycle_pc_old; +static evt_t copper_bad_cycle_start; +static uaecptr copper_bad_cycle_pc_new; /* * Statistics @@ -771,18 +775,27 @@ void alloc_cycle_ext(int hpos, int type) alloc_cycle(hpos, type); } -void alloc_cycle_blitter(int hpos, uaecptr *ptr, int chnum) +uaecptr alloc_cycle_blitter_conflict_or(void) { - if (cycle_line_slot[hpos] & CYCLE_COPPER_SPECIAL) { - if ((currprefs.cs_hacks & 1) && currprefs.cpu_model == 68000) { - uaecptr srcptr = cop_state.strobe == 1 ? cop1lc : cop2lc; - //if (currprefs.cpu_model == 68000 && currprefs.cpu_cycle_exact && currprefs.blitter_cycle_exact) { - // batman group / batman vuelve triggers this incorrectly. More testing needed. - *ptr = srcptr; - //activate_debugger(); - } + uaecptr orptr = 0; + if (get_cycles() == copper_bad_cycle) { + orptr = copper_bad_cycle_pc_old; + } + return orptr; +} + +bool alloc_cycle_blitter(int hpos, uaecptr *ptr, int chnum, int add) +{ + bool skipadd = false; + if (get_cycles() == copper_bad_cycle) { + write_log("Copper PT=%08x %08x. Blitter CH=%d PT=%08x bug!\n", copper_bad_cycle_pc_old, copper_bad_cycle_pc_new, chnum, *ptr); + cop_state.ip += add; + *ptr = copper_bad_cycle_pc_new; + skipadd = true; + //activate_debugger(); } alloc_cycle(hpos, CYCLE_BLITTER); + return skipadd; } static int expand_sprres(uae_u16 con0, uae_u16 con3) @@ -7518,8 +7531,11 @@ static void COPJMP(int num, int vblank) warned--; } } - if (current_hpos() & 1) { - cop_state.state = COP_strobe_delay1x; // CPU unaligned COPJMP while waiting + int hp = current_hpos(); + if ((hp & 1) && currprefs.cpu_model == 68000 && currprefs.cpu_cycle_exact) { + // CPU unaligned COPJMP while waiting + cop_state.state = COP_strobe_delay1x; + copper_bad_cycle_start = get_cycles(); } else { cop_state.state = COP_strobe_delay1; } @@ -9600,8 +9616,8 @@ static void do_copper_fetch(int hpos, uae_u16 id) if (scandoubled_line) { return; } - if (id == COPPER_CYCLE_IDLE) { - // copper allocated cycle without DMA request + + if (id & CYCLE_PIPE_NONE) { alloc_cycle(hpos, CYCLE_COPPER); return; } @@ -9672,9 +9688,6 @@ static void do_copper_fetch(int hpos, uae_u16 id) } break; case COP_strobe_delay2x: - if (debug_dma) { - record_dma_event(DMA_EVENT_SPECIAL, hpos, vpos); - } #ifdef DEBUGGER { if (debug_dma) { @@ -9700,9 +9713,7 @@ static void do_copper_fetch(int hpos, uae_u16 id) cop_state.ip = cop2lc; } cop_state.strobe = 0; - alloc_cycle(hpos, CYCLE_COPPER); - cycle_line_slot[hpos] |= CYCLE_COPPER_SPECIAL; break; case COP_start_delay: cop_state.state = COP_read1; @@ -10023,9 +10034,31 @@ static void update_copper(int until_hpos) case COP_strobe_delay2x: // Second cycle fetches following word and tosses it away. // Cycle can be free and copper won't allocate it. - // If Blitter uses this cycle = Copper's PC gets copied to blitter DMA pointer.. - copper_cant_read(hpos, CYCLE_PIPE_COPPER | 0x09); - break; + // If Blitter uses this cycle = Copper's new PC gets copied to blitter DMA pointer.. + if (!copper_cant_read(hpos, CYCLE_PIPE_COPPER | 0x09)) { + copper_bad_cycle = get_cycles(); + // conflict also does not happen if previous cycle was used by bitplane + // (if bitplane DMA is allocated, copper internal operations are also stopped) + int bpl = 0;// get_bitplane_dma_rel(hpos, -1); + if (copper_bad_cycle - copper_bad_cycle_start != 3 * CYCLE_UNIT || bpl) { + copper_bad_cycle = 0; + } else { + if (debug_dma) { + record_dma_event(DMA_EVENT_SPECIAL, hpos, vpos); + } + // early COPJMP processing + cop_state.state = COP_read1; + copper_bad_cycle_pc_old = cop_state.ip; + if (cop_state.strobe == 1) { + cop_state.ip = cop1lc; + } else { + cop_state.ip = cop2lc; + } + copper_bad_cycle_pc_new = cop_state.ip; + cop_state.strobe = 0; + } + } + break; case COP_start_delay: // cycle after vblank strobe fetches word from old pointer first @@ -13193,6 +13226,7 @@ void custom_reset(bool hardreset, bool keyboardreset) hcenter_v2 = 0; set_hcenter(); display_reset = 1; + copper_bad_cycle = 0; if (hardreset || savestate_state) { maxhpos = ntsc ? MAXHPOS_NTSC : MAXHPOS_PAL; @@ -13331,10 +13365,9 @@ void custom_reset(bool hardreset, bool keyboardreset) toscr_delay_sh[0] = 0; toscr_delay_sh[1] = 0; + memset(&cop_state, 0, sizeof(cop_state)); cop_state.state = COP_stop; - cop_state.movedelay = 0; - cop_state.strobe = 0; - cop_state.ignore_next = 0; + vdiwstate = diw_states::DIW_waiting_start; vdiw_change(0); check_harddis(); diff --git a/include/custom.h b/include/custom.h index bbafa2a9..0302ff27 100644 --- a/include/custom.h +++ b/include/custom.h @@ -171,7 +171,6 @@ extern int display_reset; #define CYCLE_COPPER 6 #define CYCLE_BLITTER 7 #define CYCLE_CPU 8 -#define CYCLE_COPPER_SPECIAL 0x10 #define CYCLE_MASK 0x0f @@ -252,7 +251,8 @@ struct customhack { int vpos, hpos; }; extern void alloc_cycle_ext(int, int); -extern void alloc_cycle_blitter(int hpos, uaecptr *ptr, int); +extern bool alloc_cycle_blitter(int hpos, uaecptr *ptr, int, int); +extern uaecptr alloc_cycle_blitter_conflict_or(void); extern bool ispal(int *lines); extern bool isvga(void); extern int current_maxvpos(void); @@ -271,6 +271,7 @@ extern uae_u8 cycle_line_slot[MAX_CHIPSETSLOTS + RGA_PIPELINE_ADJUST]; extern uae_u16 cycle_line_pipe[MAX_CHIPSETSLOTS + RGA_PIPELINE_ADJUST]; #define CYCLE_PIPE_CPUSTEAL 0x8000 +#define CYCLE_PIPE_NONE 0x4000 #define CYCLE_PIPE_BLITTER 0x100 #define CYCLE_PIPE_COPPER 0x80 #define CYCLE_PIPE_SPRITE 0x40