]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
Rewritten copper to match low level state machine
authorToni Wilen <twilen@winuae.net>
Sat, 27 Dec 2025 12:50:56 +0000 (14:50 +0200)
committerToni Wilen <twilen@winuae.net>
Sat, 27 Dec 2025 12:50:56 +0000 (14:50 +0200)
custom.cpp
include/custom.h

index 2e3ed2072c3fd3808dca6a9dc63db1872cb13e58..b4e7b32d70a5f3ab62e3f476fd5bf38711ebde4b 100644 (file)
@@ -722,51 +722,30 @@ static int copper_access;
 uae_u16 clxdat;
 static uae_u16 clxcon, clxcon2;
 
-enum copper_states {
-       COP_stop,
-       COP_waitforever,
-       COP_read1,
-       COP_read2,
-       COP_bltwait,
-       COP_bltwait2,
-       COP_wait_in2,
-       COP_skip_in2,
-       COP_wait1,
-       COP_wait,
-       COP_skip,
-       COP_skip1,
-       COP_strobe_vbl_delay,
-       COP_strobe_vbl_delay2,
-       COP_strobe_vbl_delay_nodma,
-       COP_strobe_vbl_extra_delay1,
-       COP_strobe_vbl_extra_delay2,
-       COP_strobe_vbl_extra_delay3,
-       COP_strobe_delay_start,
-       COP_strobe_delay_start_odd,
-       COP_strobe_delay1,
-       COP_strobe_delay1_odd,
-       COP_strobe_delay2,
-       COP_strobe_extra // just to skip current cycle when CPU wrote to COPJMP
-};
+#define COP_INS_MOVE 0
+#define COP_INS_WAIT 1
+#define COP_INS_SKIP 2
 
 struct copper {
        /* The current instruction words.  */
        uae_u16 ir[2];
-       enum copper_states state, state_prev;
        /* Instruction pointer.  */
        uaecptr ip;
-       uaecptr strobeip;
-       // following move does not enable COPRS
-       int ignore_next;
        int vcmp, hcmp;
-
-       int strobe; /* COPJMP1 / COPJMP2 accessed */
-       int strobetype;
-       enum copper_states strobe_next;
-       int moveaddr, movedata, movedelay;
-       uaecptr moveptr;
        uaecptr vblankip;
-       evt_t strobe_cycles;
+
+       int strobe;
+       int inst;
+       bool load1;
+       bool load2;
+       bool skiplatch;
+       int start;
+       int irload1;
+       int irload2;
+       uae_u32 startstrobe;
+       bool blitwait;
+       bool cycle_alloc;
+       bool validmove;
 };
 
 static struct copper cop_state;
@@ -2944,8 +2923,9 @@ static int test_copper_dangerous(uae_u16 reg, bool testonly)
        int addr = reg & 0x01fe;
        if (addr < ((copcon & 2) ? (ecs_agnus ? 0 : 0x40) : 0x80)) {
                if (!testonly) {
-                       cop_state.state = COP_stop;
                        copper_enabled_thisline = 0;
+                       cop_state.start = cop_state.irload1 = cop_state.irload2 = 0;
+                       cop_state.inst = COP_INS_WAIT;
                }
                return 1;
        }
@@ -2975,7 +2955,6 @@ static void immediate_copper(int num)
        int pos = 0;
        int oldpos = 0;
 
-       cop_state.state = COP_stop;
        cop_state.ip = num == 1 ? cop1lc : cop2lc;
 
        while (pos < (maxvpos << 5)) {
@@ -3016,23 +2995,25 @@ static void immediate_copper(int num)
                        }
                }
        }
-       cop_state.state = COP_stop;
 }
 
 STATIC_INLINE void COP1LCH(uae_u16 v)
 {
        cop1lc = (cop1lc & 0xffff) | ((uae_u32)v << 16);
 
+#if 0
        if (agnus_hpos == 2 && vpos == 0 && safecpu() && !copper_access && is_copper_dma(false)) {
                if (cop_state.state == COP_strobe_vbl_delay) {
                        cop_state.strobeip = cop1lc | ((regs.chipset_latch_rw & 0xffff) << 16);
                }
        }
+#endif
 }
 STATIC_INLINE void COP1LCL(uae_u16 v)
 {
        cop1lc = (cop1lc & ~0xffff) | (v & 0xfffe);
 
+#if 0
        // really strange chipset bug: if COP1LCL is written exactly at cycle 2, vpos 0,
        // vblank triggered COP1JMP loads to internal COPPTR COP1LC OR last data in chip bus!
        if (agnus_hpos == 2 && vpos == 0 && safecpu() && !copper_access && is_copper_dma(true)) {
@@ -3040,6 +3021,7 @@ STATIC_INLINE void COP1LCL(uae_u16 v)
                        cop_state.strobeip = cop1lc | (regs.chipset_latch_rw & 0xfffe);
                }
        }
+#endif
 }
 STATIC_INLINE void COP2LCH(uae_u16 v)
 {
@@ -3061,101 +3043,17 @@ static uaecptr getstrobecopip(void)
        } else {
                return cop1lc;
        }
-
-}
-static void setstrobecopip(void)
-{
-       cop_state.ip = getstrobecopip();
-       cop_state.strobe = 0;
-}
-
-static struct rgabuf *generate_copper_cycle_if_free(uae_u16 v)
-{
-       if (is_copper_dma(true) && check_rga_free_slot_in()) {
-               struct rgabuf *rga = write_rga(RGA_SLOT_IN, CYCLE_COPPER, 0x8c, &cop_state.ip);
-               rga->copdat = v;
-               return rga;
-       }
-       return NULL;
 }
 
-// normal COPJMP write: takes 2 more cycles
-static void COPJMP(int num, int vblank)
+static void COPJMP(int num, bool bsce)
 {
-       cop_state.strobe_next = COP_stop;
-
-       if (!cop_state.strobe) {
-               cop_state.state_prev = cop_state.state;
-       }
-       cop_state.strobetype = 0;
-       if ((cop_state.state == COP_wait1 || cop_state.state == COP_waitforever || cop_state.state == COP_stop ||
-               (cop_state.state == COP_read2 && ((cop_state.ir[0] & 1) || test_copper_dangerous(cop_state.ir[0], true))) ||
-               cop_state.state == COP_wait_in2 || cop_state.state == COP_skip_in2) &&
-               !vblank && is_copper_dma(false)) {
-               // no copper request for next copper cycle
-               if (blt_info.blit_main) {
-                       static int warned = 100;
-                       if (warned > 0) {
-                               write_log(_T("Potential buggy copper cycle conflict with blitter PC=%08x, COP=%08x\n"), M68K_GETPC, cop_state.ip);
-                               warned--;
-                               //activate_debugger();
-                       }
-               }
-               int hp = current_hpos();
-               if ((hp & 1) && safecpu()) {
-                       // CPU unaligned COPJMP while waiting
-                       cop_state.strobe_next = COP_strobe_delay_start_odd;
-                       cop_state.strobetype = -1;
-               } else {
-                       cop_state.state = COP_strobe_delay_start;
-               }
-               cop_state.strobeip = 0xffffffff;
+       cop_state.startstrobe = 0;
+       cop_state.startstrobe |= 8 << 0;
+       cop_state.startstrobe |= num << 4;
+       if (!bsce) {
+               cop_state.startstrobe <<= 4;
        } else {
-               // copper request done for next cycle
-               if (vblank) {
-                       if (!is_copper_dma(false)) {
-                               cop_state.state = COP_strobe_vbl_delay_nodma;
-                       } else {
-                               cop_state.state = COP_strobe_vbl_delay;
-                               cop_state.strobeip = cop1lc;
-                               cop_state.strobe = 0;
-                               struct rgabuf *r = read_rga_in();
-                               r->type |= CYCLE_COPPER;
-                               r->copdat = 0;
-                               if (!r->alloc) {
-                                       r->alloc = -1;
-                               }
-#if 1
-                               switch (cop_state.state_prev)
-                               {
-                                       case copper_states::COP_read1:
-                                               // Wake up is delayed by 1 copper cycle if copper is currently loading words
-                                               cop_state.state = COP_strobe_vbl_extra_delay1;
-                                               break;
-                                       case copper_states::COP_read2:
-                                               // Wake up is delayed by 1 copper cycle if copper is currently loading words
-                                               cop_state.state = COP_strobe_vbl_extra_delay2;
-                                               break;
-                               }
-#endif
-                       }
-               } else {
-                       if (copper_access) {
-                               cop_state.state = COP_strobe_delay1;
-                       } else {
-                               cop_state.strobe_next = COP_strobe_delay1;
-                       }
-                       cop_state.strobetype = 1;
-                       if (cop_state.state == COP_read2 && !(cop_state.ir[0] & 1)) {
-                               cop_state.strobetype = 2;
-                       }
-               }
-       }
-       cop_state.vblankip = cop1lc;
-       cop_state.strobe_cycles = get_cycles() + CYCLE_UNIT;
-
-       if (!vblank) {
-               cop_state.strobe |= num;
+               cop_state.vblankip = cop1lc;
        }
 
        if (custom_disabled) {
@@ -3165,35 +3063,18 @@ static void COPJMP(int num, int vblank)
        }
 
        compute_spcflag_copper();
-}
+}              
 
 STATIC_INLINE void COPCON(uae_u16 a)
 {
        copcon = a;
 }
 
-static void check_copper_stop(void)
-{
-       if (copper_enabled_thisline < 0 && !is_copper_dma(false)) {
-               copper_enabled_thisline = 0;
-       }
-}
-
-static void copper_stop(void)
-{
-       copper_enabled_thisline = 0;
-}
-
 static void bitplane_dma_change(uae_u32 v)
 {
        dmacon_bpl = (v & DMA_BITPLANE) && (v & DMA_MASTER);
 }
 
-static void compute_spcflag_copper_delayed(uae_u32 v)
-{
-       compute_spcflag_copper();
-}
-
 static void DMACON(int hpos, uae_u16 v)
 {
        uae_u16 changed;
@@ -4481,26 +4362,11 @@ static void bprun_start(int hpos)
        bpl_autoscale();
 }
 
-/*
-       CPU write COPJMP wakeup sequence when copper is waiting:
-       - Idle cycle (can be used by other DMA channel)
-       - Read word from current copper pointer (next word after wait instruction) to 1FE
-         This cycle can conflict with blitter DMA.
-       Normal copper cycles resume
-       - Write word from new copper pointer to 8C
-*/
-
-static int coppercomp(int hpos, bool blitwait)
+static int coppercomp(int hpos)
 {
        int hpos_cmp = hpos;
        int vpos_cmp = vpos;
 
-       // If waiting for last cycle of line and last cycle is even cycle:
-       // Horizontal counter has already wrapped around to zero.
-       if (hpos_cmp == maxhposm1 && maxhposeven == COPPER_CYCLE_POLARITY) {
-               hpos_cmp = 0;
-       }
-
        int vp = vpos_cmp & (((cop_state.ir[1] >> 8) & 0x7F) | 0x80);
        int hp = hpos_cmp & (cop_state.ir[1] & 0xFE);
 
@@ -4508,19 +4374,11 @@ static int coppercomp(int hpos, bool blitwait)
                return -1;
        }
 
-       // Cycle 0: copper can't wake up
-       if (hpos == 0) {
-               return 1;
-       }
-
        if ((cop_state.ir[1] & 0x8000) == 0) {
                if (blit_busy(false)) {
-                       if (blitwait) {
-                               /* We need to wait for the blitter.  */
-                               cop_state.state = COP_bltwait;
-                               return -2;
-                       }
-                       return 1;
+                       /* We need to wait for the blitter. */
+                       cop_state.blitwait = true;
+                       return -2;
                }
        }
 
@@ -4536,15 +4394,30 @@ static int coppercomp(int hpos, bool blitwait)
 
 static void compute_spcflag_copper(void)
 {
-       copper_enabled_thisline = 0;
-       if (cop_state.strobe_next == COP_stop) {
-               if (!is_copper_dma(true) || (cop_state.state == COP_stop || cop_state.state == COP_waitforever || cop_state.state == COP_bltwait || cop_state.state == COP_bltwait2) || custom_disabled)
+       if (cop_state.startstrobe) {
+               copper_enabled_thisline = 1;
+               return;
+       }
+       if (!is_copper_dma(true)) {
+               copper_enabled_thisline = 0;
+               return;
+       }
+       bool idle = !cop_state.start && !cop_state.irload1 && !cop_state.irload2 && !cop_state.strobe;
+       if (!idle) {
+               copper_enabled_thisline = 1;
+               return;
+       }
+       if (cop_state.inst != COP_INS_WAIT) {
+               copper_enabled_thisline = 1;
+               return;
+       }
+
+       bool waiting = cop_state.inst == COP_INS_WAIT && idle;
+       if (waiting) {
+               int vp = vpos & (((cop_state.ir[1] >> 8) & 0x7F) | 0x80);
+               if (vp < cop_state.vcmp) {
+                       copper_enabled_thisline = 0;
                        return;
-               if (cop_state.state == COP_wait1 && is_copper_dma(false)) {
-                       int vp = vpos & (((cop_state.ir[1] >> 8) & 0x7F) | 0x80);
-                       if (vp < cop_state.vcmp) {
-                               return;
-                       }
                }
        }
        copper_enabled_thisline = 1;
@@ -4552,10 +4425,10 @@ static void compute_spcflag_copper(void)
 
 void blitter_done_notify(void)
 {
-       if (cop_state.state != COP_bltwait) {
+       if (!cop_state.blitwait) {
                return;
        }
-       cop_state.state = COP_wait1;
+       cop_state.blitwait = false;
        compute_spcflag_copper();
 #ifdef DEBUGGER
        if (copper_enabled_thisline) {
@@ -5417,18 +5290,6 @@ static void vsync_handler_post(void)
        check_lineoptimizations();
 }
 
-static void copper_check(int n)
-{
-       if (cop_state.state == COP_wait) {
-               int vp = vpos & (((cop_state.ir[1] >> 8) & 0x7F) | 0x80);
-               if (vp < cop_state.vcmp) {
-                       if (copper_enabled_thisline) {
-                               write_log(_T("COPPER BUG %d: vp=%d vpos=%d vcmp=%d thisline=%d\n"), n, vp, vpos, cop_state.vcmp, copper_enabled_thisline);
-                       }
-               }
-       }
-}
-
 static void dmal_emu_disk(struct rgabuf *rga, int slot, bool w)
 {
        uae_u16 dat = 0;
@@ -6546,9 +6407,6 @@ static void hsync_handler_post(bool onvsync)
 
        rethink_uae_int();
 
-       /* See if there's a chance of a copper wait ending this line.  */
-       compute_spcflag_copper();
-
        // check reset and process it immediately, don't wait for vsync
        if (quit_program == -UAE_RESET || quit_program == -UAE_RESET_KEYBOARD || quit_program == -UAE_RESET_HARD) {
                quit_program = -quit_program;
@@ -6969,10 +6827,8 @@ void custom_reset(bool hardreset, bool keyboardreset)
        init_hz_reset();
 
        audio_reset();
-       cop_state.strobe_next = COP_stop;
        if (!isrestore()) {
                memset(&cop_state, 0, sizeof(cop_state));
-               cop_state.state = COP_stop;
                /* must be called after audio_reset */
                adkcon = 0;
 #ifdef SERIAL_PORT
@@ -7234,8 +7090,8 @@ static uae_u32 REGPARAM2 custom_wget_1(int hpos, uaecptr addr, int noput, bool i
                v = HHPOSR();
                break;
 
-       case 0x088: COPJMP(1, 0); break;
-       case 0x08a: COPJMP(2, 0); break;
+       case 0x088: COPJMP(1, false); break;
+       case 0x08a: COPJMP(2, false); break;
 
 #ifdef AGA
        case 0x180: case 0x182: case 0x184: case 0x186: case 0x188: case 0x18A:
@@ -7455,8 +7311,8 @@ static int custom_wput_agnus(int addr, uae_u32 value, int noget)
        case 0x084: COP2LCH(value); break;
        case 0x086: COP2LCL(value); break;
 
-       case 0x088: COPJMP(1, 0); break;
-       case 0x08A: COPJMP(2, 0); break;
+       case 0x088: COPJMP(1, false); break;
+       case 0x08A: COPJMP(2, false); break;
 
        case 0x08E: DIWSTRT(value); break;
        case 0x090: DIWSTOP(value); break;
@@ -7819,7 +7675,6 @@ void restore_custom_finish(void)
 void restore_custom_start(void)
 {
        memset(&cop_state, 0, sizeof(cop_state));
-       cop_state.state = COP_stop;
        denise_reset(true);
        rga_slot_first_offset = 0;
        rga_slot_in_offset = 1;
@@ -8560,11 +8415,11 @@ uae_u8 *save_custom_slots(size_t *len, uae_u8 *dstptr)
 
        uae_u32 v = 1 | 8;
        // copper final MOVE pending?
-       if (cop_state.state == COP_read1) {
-               v |= 2;
-       } else if (cop_state.state == COP_read2) {
-               v |= 4;
-       }
+//     if (cop_state.state == COP_read1) {
+//             v |= 2;
+//     } else if (cop_state.state == COP_read2) {
+//             v |= 4;
+//     }
        save_u32(v);
        save_u32(cop_state.ip);
        save_u16(cop_state.ir[0]);
@@ -8590,7 +8445,7 @@ uae_u8 *save_custom_slots(size_t *len, uae_u8 *dstptr)
                save_u32(r->auddat);
                save_u32(r->refdat);
                save_u32(r->dskdat);
-               save_u32(r->copdat);
+               save_u32(0);
                save_u16(r->bplmod);
                save_u16(r->bltmod);
                regidx = getregfrompt(r->p);
@@ -8614,12 +8469,14 @@ uae_u8 *restore_custom_slots(uae_u8 *src)
        cop_state.ip = restore_u32();
        cop_state.ir[0] = restore_u16();
        cop_state.ir[1] = restore_u16();
+#if 0
        cop_state.state = COP_stop;
        if (v & 2) {
                cop_state.state = COP_read1;
        } else if (v & 4) {
                cop_state.state = COP_read2;
        }
+#endif
 
        for (int i = 0; i < 4; i++) {
                //cycle_line_pipe[i] = restore_u16();
@@ -8644,7 +8501,7 @@ uae_u8 *restore_custom_slots(uae_u8 *src)
                        r->auddat = restore_u32();
                        r->refdat = restore_u32();
                        r->dskdat = restore_u32();
-                       r->copdat = restore_u32();
+                       restore_u32();
                        r->bplmod = restore_u16();
                        r->bltmod = restore_u16();
                        regidx = restore_u16();
@@ -9056,695 +8913,259 @@ static uae_u64 fetch64(struct rgabuf *r)
        return v;
 }
 
-
 static void process_copper(struct rgabuf *r)
 {
-       uae_u16 id = r->copdat;
-       int hpos = agnus_hpos;
-
-       if ((id & 0xf) == 0xf) {
-               // last cycle was even: cycle 1 got allocated which is unusable for copper
-               // reads from address zero!
-#ifdef DEBUGGER
-               if (debug_dma) {
-                       record_dma_read(0x1fe, 0, DMARECORD_COPPER, 7);
-               }
-#endif
-               uae_u16 tmp = chipmem_wget_indirect(0);
-#ifdef DEBUGGER
-               if (debug_dma) {
-                       record_dma_read_value(tmp);
-                       record_dma_event(DMA_EVENT_COPPERUSE);
-               }
-#endif
-               regs.chipset_latch_rw = tmp;
-               return;
-       }
-
-       switch (cop_state.state)
-       {
+       int hp = agnus_hpos;
 
-       case COP_stop:
-               break;
-       case COP_strobe_vbl_delay:
-       {
-               cop_state.state = COP_strobe_vbl_delay2;
-               cop_state.strobeip = getstrobecopip();
-               cop_state.strobe = 0;
 #ifdef DEBUGGER
-               if (debug_dma) {
-                       record_dma_event(DMA_EVENT_COPPERUSE);
+       uae_u16 reg = r->reg;
+       if (debug_dma) {
+               if (memwatch_enabled) {
+                       debug_getpeekdma_chipram(cop_state.ip, MW_MASK_COPPER, reg);
                }
-#endif
        }
-       break;
-       case COP_strobe_vbl_delay2:
-       {
-       // fake MOVE phase 2
-#ifdef DEBUGGER
-               // inhibited $8c access
-               if (debug_dma) {
-                       record_dma_read(0x1fe, cop_state.ip, DMARECORD_COPPER, 6);
-               }
 #endif
-               cop_state.ir[1] = chipmem_wget_indirect(cop_state.ip);
-#ifdef DEBUGGER
-               if (debug_dma) {
-                       record_dma_read_value(cop_state.ir[1]);
-                       record_dma_event(DMA_EVENT_COPPERUSE);
-               }
-#endif
-               cop_state.ip = cop_state.strobeip;
-               cop_state.state = COP_read1;
-               regs.chipset_latch_rw = cop_state.ir[1];
-       }
-       break;
-       case COP_strobe_vbl_delay_nodma:
-               cop_state.ip = getstrobecopip();
-               cop_state.state = COP_read1;
-               break;
 
-       case COP_strobe_vbl_extra_delay1:
-#ifdef DEBUGGER
-               if (debug_dma) {
-                       record_dma_read(0x8c, cop_state.ip, DMARECORD_COPPER, 6);
-               }
-               if (memwatch_enabled) {
-                       debug_getpeekdma_chipram(cop_state.ip, MW_MASK_COPPER, 0x8c);
-               }
-#endif
-               cop_state.ir[0] = regs.chipset_latch_rw = last_custom_value = chipmem_wget_indirect(cop_state.ip);
-               cop_state.ip = cop_state.strobeip;
-#ifdef DEBUGGER
-               if (debug_dma) {
-                       record_dma_read_value(cop_state.ir[0]);
-               }
-#endif
-               cop_state.state = COP_read1;
-       break;
-       case COP_strobe_vbl_extra_delay2:
-#ifdef DEBUGGER
-               if (debug_dma) {
-                       record_dma_read(0x8c, cop_state.ip, DMARECORD_COPPER, 6);
-               }
-               if (memwatch_enabled) {
-                       debug_getpeekdma_chipram(cop_state.ip, MW_MASK_COPPER, 0x8c);
-               }
-#endif
-               cop_state.ir[0] = regs.chipset_latch_rw = last_custom_value = chipmem_wget_indirect(cop_state.ip);
-               cop_state.ip += 2;
-#ifdef DEBUGGER
-               if (debug_dma) {
-                       record_dma_read_value(cop_state.ir[0]);
-               }
-#endif
-               cop_state.state = COP_strobe_vbl_extra_delay3;
-       break;
-       case COP_strobe_vbl_extra_delay3:
-#ifdef DEBUGGER
-               if (debug_dma) {
-                       record_dma_read(0x1fe, cop_state.ip, DMARECORD_COPPER, 6);
-               }
-#endif
-               cop_state.ir[1] = regs.chipset_latch_rw = last_custom_value = chipmem_wget_indirect(cop_state.ip);
-               cop_state.ip = cop_state.strobeip;
-#ifdef DEBUGGER
-               if (debug_dma) {
-                       record_dma_read_value(cop_state.ir[1]);
-               }
-#endif
-               cop_state.state = COP_read1;
-       break;
+       uae_u16 data = chipmem_wget_indirect(cop_state.ip);
 
-       // cycle after odd strobe write is normal IR2
-       case COP_strobe_delay_start_odd:
 #ifdef DEBUGGER
-               if (debug_dma) {
-                       record_dma_read(r->reg, cop_state.ip, DMARECORD_COPPER, 6);
+       if (debug_dma) {
+               int m = !(cop_state.ir[0] & 1) ? 1 : ((cop_state.ir[1] & 1) ? 3 : 2);
+               if (cop_state.irload2 && !(cop_state.ir[0] & 1)) {
+                       m = 1;
+                       if (!cop_state.skiplatch) {
+                               reg = cop_state.ir[0];
+                       }
                }
-#endif
-               cop_state.ir[1] = regs.chipset_latch_rw = last_custom_value = chipmem_wget_indirect(cop_state.ip);
-#ifdef DEBUGGER
-               if (debug_dma) {
-                       record_dma_read_value(cop_state.ir[1]);
+               if (cop_state.load1) {
+                       m = 5;
                }
-#endif
-               cop_state.ip += 2;
-               cop_state.strobeip = getstrobecopip();
-               cop_state.strobe = 0;
-               cop_state.state = COP_strobe_delay1_odd;
-               cop_state.ignore_next = 0;
-       break;
-
-       case COP_strobe_delay1_odd:
-       {
-               // odd cycle strobe blitter conflict possibility
-#ifdef DEBUGGER
-               if (debug_dma) {
-                       record_dma_event(DMA_EVENT_COPPERUSE);
-               }
-#endif
-               // conflict with blitter: blitter pointer becomes old copper pointer OR blitter pointer
-               // after the blit cycle, blitter pointer becomes new copper pointer. This is done in blitter emulation.
-               // copper pointer is not affected by this.
-               if (r->type & CYCLE_BLITTER) {
-                       r->conflict = r->p;
-                       r->conflictaddr = cop_state.strobeip;
-                       r->p = &dummyrgaaddr;
-                       r->pv |= cop_state.ip;
-                       cop_state.strobeip |= r->bltmod;
+               if (cop_state.strobe & 3) {
+                       m = 6;
                }
-               cop_state.ip = cop_state.strobeip;
-               cop_state.state = COP_read1;
+               record_dma_read(reg, cop_state.ip, DMARECORD_COPPER, m);
        }
-       break;
-
-       case COP_strobe_delay1:
-       {
-               if (cop_state.strobetype >= 0) {
-                       uae_u16 reg = cop_state.ir[0] & 0x1FE;
-                       // fake MOVE phase 1
-#ifdef DEBUGGER
-                       if (debug_dma) {
-                               record_dma_read(r->reg, cop_state.ip, DMARECORD_COPPER, 6);
-                       }
-                       if (memwatch_enabled) {
-                               debug_getpeekdma_chipram(cop_state.ip, MW_MASK_COPPER, r->reg);
-                       }
-#endif
-                       cop_state.ir[0] = regs.chipset_latch_rw = last_custom_value = chipmem_wget_indirect(cop_state.ip);
-                       if (cop_state.strobetype == 0) {
-                               cop_state.ip = cop_state.strobeip;
-                               cop_state.state = COP_read1;
-                       } else {
-                               cop_state.ip += 2;
-                               cop_state.strobeip = getstrobecopip();
-                               cop_state.strobe = 0;
-                               cop_state.state = COP_strobe_delay2;
-                               if (cop_state.strobetype >= 2) {
-                                       if (!test_copper_dangerous(reg, true) && !cop_state.ignore_next) {
-                                               custom_wput_copper(cop_state.ip, reg, cop_state.ir[0], 0);
-                                       }
-                               }
-                               cop_state.ignore_next = 0;
-                       }
-#ifdef DEBUGGER
-                       if (debug_dma) {
-                               record_dma_read_value(cop_state.ir[0]);
-                       }
-                       if (memwatch_enabled) {
-                               debug_getpeekdma_value(cop_state.ir[0]);
-                       }
-#endif
-               } else {
-                       // fake and hidden MOVE phase 1
-                       cop_state.ip = cop_state.strobeip;
-                       cop_state.state = COP_read1;
-               }
+       if (debug_dma) {
+               record_dma_read_value(data);
        }
-       break;
-       case COP_strobe_delay2:
-       {
-#ifdef DEBUGGER
-               if (debug_dma) {
-                       record_dma_read(r->reg, cop_state.ip, DMARECORD_COPPER, 6);
-               }
-#endif
-               cop_state.ir[1] = chipmem_wget_indirect(cop_state.ip);
-               regs.chipset_latch_rw = cop_state.ir[1];
-#ifdef DEBUGGER
-               if (debug_dma) {
-                       record_dma_read_value(cop_state.ir[1]);
-               }
-#endif
-               if (cop_state.strobetype >= 1) {
-                       cop_state.ip = cop_state.strobeip;
-               } else {
-                       cop_state.ip += 2;
-               }
-               cop_state.state = COP_read1;
+       if (memwatch_enabled) {
+               debug_getpeekdma_value(data);
        }
-       break;
+#endif
 
-       case COP_strobe_delay_start:
-       {
-               cop_state.state = COP_strobe_delay1_odd;
+       if (cop_state.load2) {
+               cop_state.ir[1] = data;
+               cop_state.load2 = false;
+               //write_log("%08x %04x %04x\n", cop_state.ip, cop_state.ir[0], cop_state.ir[1]);
+       }
+       if (cop_state.load1) {
+               cop_state.ir[0] = data;
+               cop_state.load1 = false;
        }
-       break;
 
-       case COP_read1:
-#ifdef DEBUGGER
-               if (debug_dma) {
-                       record_dma_read(0x8c, cop_state.ip, DMARECORD_COPPER, 5);
-               }
-               if (memwatch_enabled) {
-                       debug_getpeekdma_chipram(cop_state.ip, MW_MASK_COPPER, 0x8c);
-               }
-#endif
-               cop_state.ir[0] = regs.chipset_latch_rw = last_custom_value = chipmem_wget_indirect(cop_state.ip);
-#ifdef DEBUGGER
-               if (debug_dma) {
-                       record_dma_read_value(cop_state.ir[0]);
-               }
-               if (memwatch_enabled) {
-                       debug_getpeekdma_value(cop_state.ir[0]);
-               }
-#endif
-               cop_state.ip += 2;
-               cop_state.state = COP_read2;
-               break;
-       case COP_read2:
-               if (cop_state.ir[0] & 1) {
-                       // WAIT or SKIP
-#ifdef DEBUGGER
-                       if (memwatch_enabled) {
-                               debug_getpeekdma_chipram(cop_state.ip, MW_MASK_COPPER, 0x8c);
-                       }
-#endif
-                       cop_state.ir[1] = chipmem_wget_indirect(cop_state.ip);
-#ifdef DEBUGGER
-                       if (debug_dma) {
-                               record_dma_read(0x8c, cop_state.ip, DMARECORD_COPPER, (cop_state.ir[1] & 1) ? 3 : 2);
-                               record_dma_read_value(cop_state.ir[1]);
-                       }
-                       if (memwatch_enabled) {
-                               debug_getpeekdma_value(cop_state.ir[1]);
-                       }
-#endif
-                       cop_state.ip += 2;
+       cop_state.inst = !(cop_state.ir[0] & 1) ? COP_INS_MOVE : ((cop_state.ir[1] & 1) ? COP_INS_SKIP : COP_INS_WAIT);
+       cop_state.ip += 2;
 
-#ifdef DEBUGGER
-                       uaecptr debugip = cop_state.ip;
-#endif
-                       cop_state.ignore_next = 0;
-                       if (cop_state.ir[1] & 1) {
-                               cop_state.state = COP_skip_in2;
-                       } else {
-                               cop_state.state = COP_wait_in2;
-                       }
+       if (cop_state.irload2) {
 
+               if (cop_state.inst != COP_INS_MOVE) {
                        cop_state.vcmp = (cop_state.ir[0] & (cop_state.ir[1] | 0x8000)) >> 8;
                        cop_state.hcmp = (cop_state.ir[0] & cop_state.ir[1] & 0xFE);
+                       cop_state.validmove = false;
+               }
 
-#ifdef DEBUGGER
-                       if (debug_copper) {
-                               record_copper(debugip - 4, debugip, cop_state.ir[0], cop_state.ir[1], hpos, vpos);
-                       }
-#endif
-
-               } else {
-                       // MOVE
-                       uae_u16 reg = cop_state.ir[0] & 0x1FE;
+               // MOVE write
+               if (cop_state.validmove && !cop_state.skiplatch) {
+                       custom_wput_copper(cop_state.ip, cop_state.ir[0], cop_state.ir[1], 0);
+               }
+               cop_state.skiplatch = false;
 
 #ifdef DEBUGGER
-                       if (memwatch_enabled) {
-                               debug_getpeekdma_chipram(cop_state.ip, MW_MASK_COPPER, 0x8c);
-                       }
+               if (debug_copper && cop_state.irload2) {
+                       record_copper(cop_state.ip - 4, cop_state.ip, cop_state.ir[0], cop_state.ir[1], hp, vpos);
+               }
 #endif
-                       cop_state.ir[1] = chipmem_wget_indirect(cop_state.ip);
-
-                       uae_u16 data = cop_state.ir[1];
-                       cop_state.state = COP_read1;
-
-                       uae_u16 preg = reg;
-
-                       // Previous instruction was SKIP that skipped
-                       if (cop_state.ignore_next > 0) {
-                               reg = 0x08c;
-                       }
-
-                       bool dang = test_copper_dangerous(preg, false);
+       }
 
+       if (cop_state.strobe) {
+               int strobe = cop_state.strobe & 3;
+               if (strobe) {
 #ifdef DEBUGGER
-                       if (debug_dma) {
-                               record_dma_read(reg, cop_state.ip, DMARECORD_COPPER, dang ? 4 : 1);
-                               record_dma_read_value(cop_state.ir[1]);
-                       }
-                       if (memwatch_enabled) {
-                               debug_getpeekdma_value(cop_state.ir[1]);
-                       }
+                       uaecptr previp = cop_state.ip;
 #endif
-                       cop_state.ip += 2;
-
+                       cop_state.strobe = strobe;
+                       cop_state.ip = getstrobecopip();
+                       cop_state.strobe = 0;
 #ifdef DEBUGGER
-                       uaecptr debugip = cop_state.ip;
-#endif
-                       // was "dangerous" register -> copper stopped
-                       if (dang) {
-                               return;
+                       if (debug_copper) {
+                               record_copper(previp - 4, cop_state.ip, cop_state.ir[0], cop_state.ir[1], hp, vpos);
                        }
-
-                       if (reg == 0x100) {
-                               // BPLCON0 new value is needed early
-                               //bplcon0_denise_change_early(hpos, data);
-#if 0
-                               cop_state.moveaddr = reg;
-                               cop_state.movedata = data;
-                               cop_state.movedelay = 1;
-                               cop_state.moveptr = cop_state.ip;
-#else
-                               custom_wput_copper(cop_state.ip, reg, data, 0);
 #endif
-                       } else {
-                               custom_wput_copper(cop_state.ip, reg, data, 0);
-                       }
+               } else {
 #ifdef DEBUGGER
-                       if (debug_copper && cop_state.ignore_next <= 0) {
-                               uaecptr next = 0xffffffff;
-                               if (reg == 0x88) {
-                                       next = cop1lc;
-                               } else if (reg == 0x8a) {
-                                       next = cop2lc;
-                               }
-                               record_copper(debugip - 4, next, cop_state.ir[0], cop_state.ir[1], hpos, vpos);
+                       if (debug_copper && cop_state.irload2) {
+                               record_copper(cop_state.ip - 4, cop_state.ip, cop_state.ir[0], cop_state.ir[1], hp, vpos);
                        }
-#endif
-                       cop_state.ignore_next = 0;
-               }
-               regs.chipset_latch_rw = last_custom_value = cop_state.ir[1];
-               check_copper_stop();
-               break;
-
-       case COP_strobe_extra:
-               // do nothing, happens if CPU wrote to COPxJMP but copper had already requested DMA cycle
-               // Cycle will complete but nothing will happen because COPxJMP write resets copper state.
-#ifdef DEBUGGER
-               if (debug_dma) {
-                       record_dma_read(0x8c, cop_state.ip, DMARECORD_COPPER, 0);
-               }
-               if (memwatch_enabled) {
-                       debug_getpeekdma_chipram(cop_state.ip, MW_MASK_COPPER, 0x8c);
                }
 #endif
-               break;
-       default:
-               write_log(_T("copper_fetch invalid state %d! %02x\n"), cop_state.state, id);
-               break;
        }
+
 }
 
-static void generate_copper(void)
+static void alloc_copper_cycle(void)
 {
-       int hpos = agnus_hpos;
-
-       if ((hpos & 1) != COPPER_CYCLE_POLARITY) {
-               // copper does not advance if hpos bit 0 didn't toggle
-               if ((hpos & 1) == (agnus_hpos_prev & 1)) {
-                       switch (cop_state.state)
-                       {
-                               case COP_read1:
-                               case COP_read2:
-                               case COP_wait:
-                               case COP_skip:
-                               case COP_strobe_delay1:
-                               {
-                                       generate_copper_cycle_if_free(CYCLE_PIPE_COPPER | 0xf);
-                               }
-                               break;
-                       }
-               }
-               return;
-       }
-
-       if ((hpos & 1) == (agnus_hpos_prev & 1)) {
-               return;
+       struct rgabuf *rga = write_rga(RGA_SLOT_IN, CYCLE_COPPER, 0x8c, &cop_state.ip);
+       if (!cop_state.cycle_alloc) {
+               // If cycle was not marked as copper allocated 1 CCK earlier,
+               // mark copper allocated cycle as not actually allocated. Conflict possible!
+               rga->alloc = -1;
        }
+}
 
+static void generate_copper(void)
+{
+       int hp = agnus_hpos;
        bool bus_allocated = !check_rga_free_slot_in();
+       bool dma = is_copper_dma(true);
+       bool ena_odd = !bus_allocated && (hp & 1) == COPPER_CYCLE_POLARITY && dma;
+       bool act_even = (hp & 1) != COPPER_CYCLE_POLARITY && dma;
+       bool idle = !cop_state.irload1 && !cop_state.irload2 && !cop_state.start;
+       bool allocated = false;
 
-       switch (cop_state.state)
-       {
-               case COP_strobe_vbl_delay_nodma:
-               generate_copper_cycle_if_free(CYCLE_PIPE_COPPER);
-               break;
-               case COP_strobe_vbl_delay2:
-               // Second cycle after COPJMP does basically skipped MOVE (MOVE to 1FE)
-               // Cycle is used and needs to be free.
-               generate_copper_cycle_if_free(CYCLE_PIPE_COPPER);
-               break;
+       if (ena_odd) {
 
-               case COP_strobe_delay_start_odd:
-               {
-                       cop_state.strobeip = getstrobecopip();
-                       cop_state.strobe = 0;
-                       cop_state.ignore_next = 0;
-                       if (hpos == 1 && !bus_allocated) {
-                               // if COP_strobe_delay2 crossed scanlines, it will be skipped!
-                               struct rgabuf *rga = generate_copper_cycle_if_free(CYCLE_PIPE_COPPER);
-                               rga->reg = 0x1fe;
-                               cop_state.state = COP_strobe_delay1;
-                               cop_state.strobetype = 0;
-                       } else {
-                               cop_state.state = COP_strobe_delay1_odd;
-                               // not allocated
-                               struct rgabuf *rga = read_rga_in();
-                               if (rga) {
-                                       rga->type |= CYCLE_COPPER;
-                                       rga->copdat = 0;
-                                       if (!rga->alloc) {
-                                               rga->alloc = -1;
-                                       }
-                               }
-                       }
+               if (cop_state.start == 1) {
+                       cop_state.start = 2;
                }
-               break;
 
-               case COP_strobe_delay1_odd:
-               {
-                       cop_state.state = COP_strobe_delay1_odd;
-                       if (cop_state.strobe) {
-                               cop_state.strobeip = getstrobecopip();
-                               cop_state.strobe = 0;
-                               cop_state.ignore_next = 0;
-                       }
-                       // not allocated
-                       struct rgabuf *rga = read_rga_in();
-                       if (rga) {
-                               rga->type |= CYCLE_COPPER;
-                               rga->copdat = 0;
-                               if (!rga->alloc) {
-                                       rga->alloc = -1;
-                               }
-                       }
+               if (cop_state.irload1 == 1) {
+                       cop_state.irload1 = 2;
                }
-               break;
 
-               case COP_strobe_delay_start:
-               if (hpos == 1 && get_cycles() > cop_state.strobe_cycles) {
-                       cop_state.state = COP_strobe_delay1_odd;
-                       cop_state.strobeip = getstrobecopip();
-                       cop_state.strobe = 0;
-                       cop_state.ignore_next = 0;
-                       // not allocated
-                       struct rgabuf *rga = read_rga_in();
-                       if (rga) {
-                               rga->type |= CYCLE_COPPER;
-                               rga->copdat = 0;
-                               if (!rga->alloc) {
-                                       rga->alloc = -1;
-                               }
-                       }
-               } else {
-                       cop_state.state = COP_strobe_delay1;
+               if (cop_state.irload2 == 1) {
+                       cop_state.irload2 = 2;
                }
-               break;
 
-               case COP_strobe_delay1:
-               // First cycle after COPJMP. This is the strange one.
-               // This cycle does not need to be free
-               // But it still gets allocated by copper if it is free = CPU and blitter can't use it.
-               if (bus_allocated) {
-                       cop_state.state = COP_strobe_delay2;
-                       if (cop_state.strobeip == 0xffffffff) {
-                               cop_state.strobetype = 1;
-                       }
-                       cop_state.strobeip = getstrobecopip();
-                       cop_state.strobe = 0;
-                       cop_state.ignore_next = 0;
-               } else {
-                       if (hpos == 1 && get_cycles() > cop_state.strobe_cycles) {
-                               // if COP_strobe_delay2 crossed scanlines, it will be skipped!
-                               cop_state.strobetype = 0;
-                       }
-                       if (cop_state.strobetype == 0) {
-                               cop_state.strobeip = getstrobecopip();
-                               cop_state.strobe = 0;
-                               cop_state.ignore_next = 0;
-                       }
-                       cop_state.state = COP_strobe_delay1;
-                       // allocated and $1fe, not $08c
-                       struct rgabuf *rga = generate_copper_cycle_if_free(0x08);
-                       if (cop_state.strobetype == 0) {
-                               if (rga) {
-                                       rga->reg = 0x1fe;
-                               }
-                       }
+               // SKIP copper restart condition
+               if (cop_state.inst == COP_INS_SKIP && idle) {
+                       cop_state.start = 1;
                }
-               break;
-               case COP_strobe_delay2:
-               {
-                       struct rgabuf *rga = generate_copper_cycle_if_free(CYCLE_PIPE_COPPER);
-                       if (cop_state.strobe && cop_state.strobetype >= 1) {
-                               cop_state.strobe = 0;
-                               if (rga) {
-                                       rga->reg = 0x1fe;
-                               }
-                       }
-               }
-               break;
 
-               case COP_strobe_vbl_extra_delay3:
-               {
-                       struct rgabuf *rga = generate_copper_cycle_if_free(CYCLE_PIPE_COPPER);
-                       if (cop_state.strobe && cop_state.strobetype >= 1) {
-                               cop_state.strobe = 0;
-                               if (rga) {
-                                       rga->reg = 0x1fe;
+               // WAIT copper restart condition
+               if (cop_state.inst == COP_INS_WAIT && idle) {
+                       int comp = coppercomp(hp);
+                       if (comp < 0) {
+                               if (!cop_state.strobe && !cop_state.startstrobe) {
+                                       copper_enabled_thisline = 0;
                                }
-                       }
-               }
-               break;
-
-                       // Request IR1
-               case COP_read1:
-                       generate_copper_cycle_if_free(CYCLE_PIPE_COPPER | 0x02);
-                       break;
-
-                       // Request IR2
-               case COP_read2:
-                       generate_copper_cycle_if_free(CYCLE_PIPE_COPPER | 0x03);
-                       break;
-
-                       // WAIT: Got IR2, first idle cycle.
-                       // Need free cycle, cycle not allocated.
-               case COP_wait_in2:
-                       {
-                               if (bus_allocated) {
-                                       break;
-                               }
-                               cop_state.state = COP_wait1;
-                       }
-                       break;
-
-                       // WAIT: Second idle cycle. Wait until comparison matches.
-                       // Need free cycle, cycle not allocated.
-               case COP_wait1:
-                       {
-                               int comp = coppercomp(hpos, true);
-                               if (comp < 0) {
-                                       // If we need to wait for later scanline or blitter: no need to emulate copper cycle-by-cycle
-                                       if (cop_state.ir[0] == 0xFFFF && cop_state.ir[1] == 0xFFFE && maxhpos < 250) {
-                                               cop_state.state = COP_waitforever;
-                                       }
-                                       if (cop_state.strobe_next == COP_stop) {
-                                               copper_enabled_thisline = 0;
-                                       }
-#ifdef DEBUGGER
-                                       if (debug_dma && comp == -2) {
-                                               record_dma_event(DMA_EVENT_COPPERWAKE2);
-                                       }
-#endif
-                                       break;
-                               }
-
-                               if (comp) {
-                                       break;
-                               }
-
+                       } else if (!comp) {
+                               cop_state.start = 1;
 #ifdef DEBUGGER
                                if (debug_dma) {
                                        record_dma_event(DMA_EVENT_COPPERWAKE2);
                                        record_dma_event(DMA_EVENT_COPPERWAKE);
                                }
 #endif
-                               if (bus_allocated) {
-                                       break;
-                               }
-
-                               cop_state.state = COP_wait;
                        }
-                       break;
-
-                       // Wait finished, request IR1.
-               case COP_wait:
-                       {
-                               if (!generate_copper_cycle_if_free(CYCLE_PIPE_COPPER | 0x04)) {
-                                       break;
-                               }
 #ifdef DEBUGGER
-                               if (debug_dma) {
-                                       record_dma_event(DMA_EVENT_COPPERWAKE);
-                               }
-                               if (debug_copper) {
-                                       record_copper(cop_state.ip - 4, 0xffffffff, cop_state.ir[0], cop_state.ir[1], hpos, vpos);
-                               }
-#endif
-                               cop_state.state = COP_read1;
+                       if (debug_dma && comp == -2) {
+                               record_dma_event(DMA_EVENT_COPPERWAKE2);
                        }
-                       break;
-
-                       // SKIP: Got IR2. First idle cycle.
-                       // Free cycle needed, cycle not allocated.
-               case COP_skip_in2:
-
-                       if (bus_allocated) {
-                               break;
-                       }
-                       cop_state.state = COP_skip1;
-                       break;
+#endif
+               }
 
-                       // SKIP: Second idle cycle. Do nothing.
-                       // Free cycle needed, cycle not allocated.
-               case COP_skip1:
+               if (cop_state.irload2 == 2) {
+                       cop_state.irload2 = 0;
 
-                       if (bus_allocated) {
-                               break;
+                       // If MOVE: IR1 state
+                       if (cop_state.validmove && !cop_state.irload1) {
+                               alloc_copper_cycle();
+                               cop_state.load1 = true;
+                               allocated = true;
+                               cop_state.irload1 = 1;
                        }
+               }
 
-                       cop_state.state = COP_skip;
-                       break;
+               if (cop_state.irload1 == 2) {
+                       alloc_copper_cycle();
+                       cop_state.load2 = true;
+                       allocated = true;
+                       cop_state.irload1 = 0;
+                       cop_state.irload2 = 1;
+                       cop_state.validmove = cop_state.inst == COP_INS_MOVE && !test_copper_dangerous(cop_state.ir[0], true);
+               }
 
-                       // Check comparison. SKIP finished. Request IR1.
-               case COP_skip:
-                       if (!generate_copper_cycle_if_free(CYCLE_PIPE_COPPER | 0x005)) {
-                               break;
-                       }
+               if (cop_state.start == 2) {
+                       alloc_copper_cycle();
+                       cop_state.strobe = 0;
+                       cop_state.load1 = true;
+                       allocated = true;
+                       cop_state.start = 0;
+                       cop_state.irload1 = 1;
 
-                       if (!coppercomp(hpos, false)) {
-                               cop_state.ignore_next = 1;
-                       } else {
-                               cop_state.ignore_next = -1;
+                       // If SKIP: latch current comparison state
+                       if (cop_state.inst == COP_INS_SKIP) {
+                               cop_state.skiplatch = coppercomp(hp) == 0;
                        }
 
 #ifdef DEBUGGER
                        if (debug_dma) {
-                               if (cop_state.ignore_next > 0) {
+                               if (cop_state.skiplatch) {
                                        record_dma_event(DMA_EVENT_COPPERSKIP);
                                } else {
                                        record_dma_event(DMA_EVENT_COPPERWAKE2);
                                }
                        }
-                       if (debug_copper) {
-                               record_copper(cop_state.ip - 4, 0xffffffff, cop_state.ir[0], cop_state.ir[1], hpos, vpos);
-                       }
 #endif
 
-                       cop_state.state = COP_read1;
-                       break;
+               }
 
-               case COP_strobe_extra:
-                       // Wait 1 copper cycle doing nothing
-                       cop_state.state = COP_strobe_delay1;
-                       break;
+       }
 
-               default:
-                       break;
+       if (cop_state.startstrobe) {
+               // Copper state machine restart after COPxJMP strobe
+               if (cop_state.startstrobe & 8) {
+                       cop_state.irload1 = 0;
+                       cop_state.irload2 = 0;
+                       cop_state.ir[1] &= ~1;
+                       cop_state.start = 0;
+                       cop_state.skiplatch = false;
+                       cop_state.startstrobe &= ~8;
+               }
+               if (cop_state.startstrobe & 15) {
+                       cop_state.strobe = cop_state.startstrobe;
                }
+               cop_state.startstrobe >>= 4;
+       }
 
-               if (cop_state.strobe_next != COP_stop) {
-                       cop_state.state = cop_state.strobe_next;
-                       cop_state.strobe_next = COP_stop;
+       if (cop_state.strobe) {
+               // Initial DMA request after COPxJMP strobe
+               if (ena_odd) {
+                       if (!allocated) {
+                               alloc_copper_cycle();
+                       }
+                       cop_state.start = 1;
+               }
+       }
+
+       // Copper cycle allocation to CPU/Blitter priority logic is selected 1 CCK earlier
+       cop_state.cycle_alloc = false;
+       if (act_even) {
+               if (cop_state.strobe || (cop_state.startstrobe & 15)) {
+                       cop_state.cycle_alloc = true;
+               }
+               if (cop_state.start == 1) {
+                       cop_state.cycle_alloc = true;
+               }
+               if (cop_state.irload1 == 1) {
+                       cop_state.cycle_alloc = true;
                }
+               bool validmove = cop_state.inst == COP_INS_MOVE && !test_copper_dangerous(cop_state.ir[0], true);
+               if (cop_state.irload2 == 1 && validmove && !cop_state.irload1) {
+                       cop_state.cycle_alloc = true;
+               }
+       }
+
 }
 
 // Because BPL and SPR DMA is decided 1 CCK earlier than others
@@ -11391,6 +10812,9 @@ static void custom_trigger_start(void)
                }
        }
 
+       /* See if there's a chance of a copper wait ending this line.  */
+       compute_spcflag_copper();
+
        if (linear_vpos < MAX_SCANDOUBLED_LINES) {
                current_line_state = &lines[linear_vpos][lof_display];
        }
@@ -11417,7 +10841,7 @@ static void custom_trigger_start(void)
                vsync_handler_post();
 
                vsync_counter++;
-               COPJMP(1, 1);
+               COPJMP(1, true);
 
                if (bplcon0 & 4) {
                        lof_store = lof_store ? 0 : 1;
index ef7ef36b8f864facd1cff8aa1c93239d15e3efd0..a98361afa7074a099a858d25cdf7b8a6e8e07232 100644 (file)
@@ -309,7 +309,7 @@ struct rgabuf {
        bool write;
        uae_u32 *conflict;
        uaecptr conflictaddr;
-       uae_u32 bpldat, sprdat, bltdat, auddat, refdat, dskdat, copdat;
+       uae_u32 bpldat, sprdat, bltdat, auddat, refdat, dskdat;
        uae_s16 bplmod, bltmod, bltadd;
 };