]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
Refresh cycle conflict emulation, bitplane/sprite conflict special case, C/HV sync...
authorToni Wilen <twilen@winuae.net>
Mon, 14 Mar 2022 16:00:53 +0000 (18:00 +0200)
committerToni Wilen <twilen@winuae.net>
Mon, 14 Mar 2022 16:00:53 +0000 (18:00 +0200)
12 files changed:
cfgfile.cpp
custom.cpp
debug.cpp
disasm.cpp
drawing.cpp
include/custom.h
include/debug.h
include/options.h
include/savestate.h
od-win32/win32gui.cpp
savestate.cpp
statusline.cpp

index 92e1c2fd739a69d7df0e76ef2ef148fb0c6cf066..64648c2d75754029c29076c25ea14cfa79f5a4a4 100644 (file)
@@ -205,7 +205,7 @@ static const TCHAR *vsyncmodes[] = { _T("false"), _T("true"), _T("autoswitch"),
 static const TCHAR *vsyncmodes2[] = { _T("normal"), _T("busywait"), 0 };
 static const TCHAR *filterapi[] = { _T("directdraw"), _T("direct3d"), _T("direct3d11"), _T("direct3d11"), 0};
 static const TCHAR *filterapiopts[] = { _T("hardware"), _T("software"), 0 };
-static const TCHAR *overscanmodes[] = { _T("tv_narrow"), _T("tv_standard"), _T("tv_wide"), _T("overscan"), _T("broadcast"), _T("extreme"), NULL };
+static const TCHAR *overscanmodes[] = { _T("tv_narrow"), _T("tv_standard"), _T("tv_wide"), _T("overscan"), _T("broadcast"), _T("extreme"), _T("ultra"), NULL};
 static const TCHAR *dongles[] =
 {
        _T("none"),
@@ -248,6 +248,7 @@ static const TCHAR *cycleexact[] = { _T("false"), _T("memory"), _T("true"), 0  }
 static const TCHAR *unmapped[] = { _T("floating"), _T("zero"), _T("one"), 0 };
 static const TCHAR *ciatype[] = { _T("default"), _T("391078-01"), 0 };
 static const TCHAR *debugfeatures[] = { _T("segtracker"), _T("fsdebug"), 0 };
+static const TCHAR *hvcsync[] = { _T("hvcsync"), _T("csync"), _T("hvsync"), 0 };
 
 struct hdcontrollerconfig
 {
@@ -2289,7 +2290,7 @@ void cfgfile_save_options (struct zfile *f, struct uae_prefs *p, int type)
        cfgfile_dwrite(f, _T("gfx_frame_slices"), _T("%d"), p->gfx_display_sections);
        cfgfile_dwrite_bool(f, _T("gfx_vrr_monitor"), p->gfx_variable_sync != 0);
        cfgfile_dwrite_str(f, _T("gfx_overscanmode"), overscanmodes[p->gfx_overscanmode]);
-       
+       cfgfile_dwrite(f, _T("gfx_monitorblankdelay"), _T("%d"), p->monitorblankdelay);
 
 #ifdef GFXFILTER
        for (int j = 0; j < 2; j++) {
@@ -2546,6 +2547,7 @@ void cfgfile_save_options (struct zfile *f, struct uae_prefs *p, int type)
        cfgfile_dwrite_bool(f, _T("z3_autoconfig"), p->cs_z3autoconfig);
        cfgfile_dwrite_bool(f, _T("1mchipjumper"), p->cs_1mchipjumper);
        cfgfile_dwrite_bool(f, _T("color_burst"), p->cs_color_burst);
+       cfgfile_dwrite_str(f, _T("hvcsync"), hvcsync[p->cs_hvcsync]);
        cfgfile_dwrite_bool(f, _T("toshiba_gary"), p->cs_toshibagary);
        cfgfile_dwrite_bool(f, _T("rom_is_slow"), p->cs_romisslow);
        cfgfile_dwrite_str(f, _T("ciaa_type"), ciatype[p->cs_ciatype[0]]);
@@ -3440,6 +3442,7 @@ static int cfgfile_parse_host (struct uae_prefs *p, TCHAR *option, TCHAR *value)
                || cfgfile_floatval(option, value, _T("rtg_horiz_zoom_multf"), &p->rtg_horiz_zoom_mult)
                || cfgfile_intval(option, value, _T("gfx_horizontal_extra"), &p->gfx_extrawidth, 1)
                || cfgfile_intval(option, value, _T("gfx_vertical_extra"), &p->gfx_extraheight, 1)
+               || cfgfile_intval(option, value, _T("gfx_monitorblankdelay"), &p->monitorblankdelay, 1)
 
                || cfgfile_intval (option, value, _T("floppy0sound"), &p->floppyslots[0].dfxclick, 1)
                || cfgfile_intval (option, value, _T("floppy1sound"), &p->floppyslots[1].dfxclick, 1)
@@ -5678,6 +5681,7 @@ static int cfgfile_parse_hardware (struct uae_prefs *p, const TCHAR *option, TCH
                || cfgfile_strval (option, value,  _T("scsidev_mode"), &p->uaescsidevmode, uaescsidevmodes, 0)
                || cfgfile_strval(option, value, _T("boot_rom_uae"), &p->boot_rom, uaebootrom, 0)
                || cfgfile_strval (option, value,  _T("serial_translate"), &p->serial_crlf, serialcrlf, 0)
+               || cfgfile_strval(option, value, _T("hvcsync"), &p->cs_hvcsync, hvcsync, 0)
                || cfgfile_strval(option, value, _T("unmapped_address_space"), &p->cs_unmapped_space, unmapped, 0)
                || cfgfile_strval(option, value, _T("ciaa_type"), &p->cs_ciatype[0], ciatype, 0)
                || cfgfile_strval(option, value, _T("ciab_type"), &p->cs_ciatype[1], ciatype, 0)
@@ -8043,6 +8047,7 @@ void default_prefs (struct uae_prefs *p, bool reset, int type)
        p->clipboard_sharing = false;
        p->native_code = false;
        p->lightpen_crosshair = true;
+       p->monitorblankdelay = 1000;
 
        p->cs_compatible = CP_GENERIC;
        p->cs_rtc = 2;
@@ -8067,6 +8072,7 @@ void default_prefs (struct uae_prefs *p, bool reset, int type)
        p->cs_ciatodbug = false;
        p->cs_unmapped_space = 0;
        p->cs_color_burst = false;
+       p->cs_hvcsync = false;
        p->cs_ciatype[0] = 0;
        p->cs_ciatype[1] = 0;
 
index 9a776a6075144cc90c988f37f8cab882f85fd912..cec44bba056a36beafa297d701c4104e8c8565da 100644 (file)
@@ -31,6 +31,7 @@
 #include "inputdevice.h"
 #include "serial.h"
 #include "autoconf.h"
+#include "autoconf.h"
 #include "traps.h"
 #include "gui.h"
 #include "picasso96.h"
 #define SPR_FIRST_HPOS 25
 #define COPPER_CYCLE_POLARITY 0
 
+#define REF_RAS_ADD_AGA 0x000
+#define REF_RAS_ADD_ECS 0x200
+#define REF_RAS_ADD_OCS 0x002
+
 #define SPRBORDER 0
 
 #define EXTRAWIDTH_BROADCAST 15
@@ -79,6 +84,7 @@
 #define EXTRAHEIGHT_BROADCAST_BOTTOM 0
 #define EXTRAWIDTH_EXTREME 33
 #define EXTRAHEIGHT_EXTREME 24
+#define EXTRAWIDTH_ULTRA 77
 
 #define LORES_TO_SHRES_SHIFT 2
 
@@ -142,6 +148,8 @@ static bool graphicsbuffer_retry;
 static int cia_hsync;
 static bool toscr_scanline_complex_bplcon1, toscr_scanline_complex_bplcon1_off;
 static int toscr_hend;
+static int nosignal_cnt, nosignal_status;
+static bool nosignal_trigger;
 int display_reset;
 
 #define LOF_TOGGLES_NEEDED 3
@@ -176,7 +184,7 @@ uae_u16 intena, intreq;
 uae_u16 dmacon;
 uae_u16 adkcon; /* used by audio code */
 uae_u16 last_custom_value;
-static bool dmacon_bpl;
+static bool dmacon_bpl, vdiwstate_bpl;
 
 static uae_u32 cop1lc, cop2lc, copcon;
 
@@ -317,6 +325,7 @@ int programmedmode;
 int syncbase;
 static int fmode_saved, fmode;
 uae_u16 beamcon0, new_beamcon0;
+uae_u16 bemcon0_hsync_mask, bemcon0_vsync_mask;
 static uae_u16 beamcon0_saved;
 static uae_u16 bplcon0_saved, bplcon1_saved, bplcon2_saved;
 static uae_u16 bplcon3_saved, bplcon4_saved;
@@ -341,9 +350,15 @@ static uae_u16 sprhstrt_v, sprhstop_v, bplhstrt_v, bplhstop_v;
 static int hhbpl, hhspr;
 static int ciavsyncmode;
 static int diw_hstrt, diw_hstop;
-static int diw_hcounter;
-static uae_u16 refptr;
-static uae_u32 refptr_val;
+static int hdiw_counter;
+static int hdiw_counter_sconflict, hdiw_counter_sconflict_mask;
+static int hdiw_counter_conflict;
+static uae_u32 ref_ras_add;
+static uaecptr refptr, refptr_p;
+static uae_u32 refmask;
+static int refresh_handled_slot;
+static bool refptr_preupdated;
+static bool hstrobe_conflict, hstrobe_conflict_frame;
 static int line_disabled;
 static bool custom_disabled;
 
@@ -360,6 +375,7 @@ struct sprite {
        int dmacycle;
        int width;
        bool ecs_denise_hires;
+       bool firstslotdone;
 
        uae_u16 ctl, pos;
 #ifdef AGA
@@ -371,6 +387,7 @@ struct sprite {
 
 static struct sprite spr[MAX_SPRITES];
 static int plfstrt_sprite;
+static int sprbplconflict, sprbplconflict_hpos;
 uaecptr sprite_0;
 int sprite_0_width, sprite_0_height, sprite_0_doubled;
 uae_u32 sprite_0_colors[4];
@@ -426,8 +443,7 @@ static int diwfirstword, diwlastword;
 static int last_diwlastword;
 static int hb_last_diwlastword;
 static int last_hdiw;
-static diw_states diwstate, hdiwstate;
-static int diwstate_vpos;
+static diw_states vdiwstate, hdiwstate;
 static int bpl_hstart;
 static bool exthblank, exthblank_state, hcenterblank_state;
 static int last_diw_hpos, last_diw_hpos2;
@@ -535,7 +551,7 @@ static int fetch_cycle, fetch_modulo_cycle;
 
 static bool ddf_limit, ddf_limit_latch, ddfstrt_match, hwi_old;
 static int ddf_stopping, ddf_enable_on;
-static int bprun;
+static int bprun, bprun_end;
 static int bprun_cycle;
 static int bprun_pipeline_flush_delay;
 static bool plane0, plane0p, plane0p_enabled, plane0p_forced, plane0_first_done;
@@ -884,6 +900,18 @@ static void reset_bpl_vars()
        thisline_decision.bplres = output_res(bplcon0_res);
 }
 
+static int get_strobe_conflict_shift(int hpos)
+{
+       // Because Denise hcounter is not synced to Agnus hcounter, BPL1DAT DMA
+       // has now offset causing jagged display. Emulate it here.
+       int unalign = hpos * 2 + hdiw_counter;
+       unalign >>= 1;
+       unalign -= 5;
+       unalign &= 7;
+       unalign *= 2;
+       return unalign - 2;
+}
+
 STATIC_INLINE bool line_hidden(void)
 {
        return vpos >= maxvpos_display_vsync && vpos < minfirstline - 1;
@@ -1073,6 +1101,33 @@ static void sync_color_changes(int hpos)
        record_color_change2(hpos, 0xffff, 0);
 }
 
+static void insert_actborder(int diw, bool onoff)
+{
+       if (line_hidden() || custom_disabled) {
+               return;
+       }
+       diw = adjust_hr(diw);
+       // find slot to insert into
+       int i;
+       for (i = last_color_change; i < next_color_change; i++) {
+               struct color_change *cc = &curr_color_changes[i];
+               if (cc->linepos > diw) {
+                       break;
+               }
+       }
+       int ii = i;
+       while (i < next_color_change) {
+               memcpy(&curr_color_changes[i + 1], &curr_color_changes[i], sizeof(struct color_change));
+               i++;
+       }
+
+       struct color_change *cc = &curr_color_changes[ii];
+       cc->linepos = diw;
+       cc->regno = 0;
+       cc->value = COLOR_CHANGE_ACTBORDER | (onoff ? 1 : 0);
+       next_color_change++;
+}
+
 // hdiw opened again in same scanline
 // erase (color0 or bblank) area between previous end and new start
 static void hdiw_restart(int diw_last, int diw_current)
@@ -1111,7 +1166,7 @@ static void hdiw_restart(int diw_last, int diw_current)
 * machine at the current position. It might have changed since we last
 * checked.  */
 
-static void decide_diw_check_start(int start_diw_hpos, int end_diw_hpos, int extrahpos)
+static void decide_hdiw_check_start(int start_diw_hpos, int end_diw_hpos, int extrahpos)
 {
        if (hdiwstate == diw_states::DIW_waiting_start) {
                if (diw_hstrt > start_diw_hpos && diw_hstrt < end_diw_hpos) {
@@ -1140,9 +1195,9 @@ static void decide_diw_check_start(int start_diw_hpos, int end_diw_hpos, int ext
                }
        }
 }
-static void decide_diw_check_stop(int start_diw_hpos, int end_diw_hpos, int extrahpos)
+static void decide_hdiw_check_stop(int start_diw_hpos, int end_diw_hpos, int extrahpos)
 {
-       if (hdiwstate == diw_states::DIW_waiting_stop) {
+       if (hdiwstate == diw_states::DIW_waiting_stop && !hstrobe_conflict) {
                if (diw_hstop > start_diw_hpos && diw_hstop <= end_diw_hpos) {
                        int last = diwlastword + extrahpos;
                        if (last > thisline_decision.diwlastword) {
@@ -1159,18 +1214,18 @@ static void decide_diw_check_stop(int start_diw_hpos, int end_diw_hpos, int extr
        }
 }
 
-static void decide_diw_check(int start_diw_hpos, int end_diw_hpos, int extrahpos)
+static void decide_hdiw_check(int start_diw_hpos, int end_diw_hpos, int extrahpos)
 {
        if (diw_hstrt < diw_hstop) {
-               decide_diw_check_start(start_diw_hpos, end_diw_hpos, extrahpos);
-               decide_diw_check_stop(start_diw_hpos, end_diw_hpos, extrahpos);
+               decide_hdiw_check_start(start_diw_hpos, end_diw_hpos, extrahpos);
+               decide_hdiw_check_stop(start_diw_hpos, end_diw_hpos, extrahpos);
        } else {
-               decide_diw_check_stop(start_diw_hpos, end_diw_hpos, extrahpos);
-               decide_diw_check_start(start_diw_hpos, end_diw_hpos, extrahpos);
+               decide_hdiw_check_stop(start_diw_hpos, end_diw_hpos, extrahpos);
+               decide_hdiw_check_start(start_diw_hpos, end_diw_hpos, extrahpos);
        }
 }
 
-static void decide_diw(int hpos)
+static void decide_hdiw(int hpos)
 {
        /* Last hpos = hpos + 0.5, eg. normal PAL end hpos is 227.5 * 2 = 455
           OCS Denise: 9 bit hdiw counter does not reset during lines 0 to 9
@@ -1192,16 +1247,16 @@ static void decide_diw(int hpos)
 
        if (!ecs_denise && vpos <= get_equ_vblank_endline()) {
                // free running horizontal counter
-               start_diw_hpos = (diw_hcounter & 511) << 2;
+               start_diw_hpos = (hdiw_counter & 511) << 2;
                end_diw_hpos = start_diw_hpos + end_diw_hpos;
-               decide_diw_check(start_diw_hpos, end_diw_hpos, extrahpos);
+               decide_hdiw_check(start_diw_hpos, end_diw_hpos, extrahpos);
                if (end_diw_hpos >= (512 << 2)) {
                        start_diw_hpos = -1;
                        end_diw_hpos -= (512 << 2);
-                       decide_diw_check(start_diw_hpos, end_diw_hpos, extrahpos);
+                       decide_hdiw_check(start_diw_hpos, end_diw_hpos, extrahpos);
                }
        } else {
-               decide_diw_check(start_diw_hpos, end_diw_hpos, extrahpos);
+               decide_hdiw_check(start_diw_hpos, end_diw_hpos, extrahpos);
        }
        last_diw_hpos = hpos;
        last_diw_hpos2 = hpos2;
@@ -1317,11 +1372,11 @@ static const uae_u8 fetchunits[] = { 8,8,8,0, 16,8,8,0, 32,16,8,0 };
 static const uae_u8 fetchstarts[] = { 3,2,1,0, 4,3,2,0, 5,4,3,0 };
 static const uae_u8 fm_maxplanes[] = { 3,2,1,0, 3,3,2,0, 3,3,3,0 };
 
-static uae_u8 cycle_diagram_table[3][3][9][32];
-static uae_u8 cycle_diagram_free_cycles[3][3][9];
-static uae_u8 cycle_diagram_total_cycles[3][3][9];
-static uae_u8 *curr_diagram;
-static const uae_u8 cycle_sequences[3 * 8] = { 2,1,2,1,2,1,2,1, 4,2,3,1,4,2,3,1, 8,4,6,2,7,3,5,1 };
+static uae_s8 cycle_diagram_table[3][3][9][32];
+static uae_s8 cycle_diagram_free_cycles[3][3][9];
+static uae_s8 cycle_diagram_total_cycles[3][3][9];
+static uae_s8 *curr_diagram;
+static const uae_s8 cycle_sequences[3 * 8] = { 2,1,2,1,2,1,2,1, 4,2,3,1,4,2,3,1, 8,4,6,2,7,3,5,1 };
 
 static void debug_cycle_diagram(void)
 {
@@ -1350,7 +1405,7 @@ static void create_cycle_diagram_table(void)
 {
        int fm, res, cycle, planes, rplanes, v;
        int fetch_start, max_planes, freecycles;
-       const uae_u8 *cycle_sequence;
+       const uae_s8 *cycle_sequence;
 
        for (fm = 0; fm <= 2; fm++) {
                for (res = 0; res <= 2; res++) {
@@ -1368,7 +1423,7 @@ static void create_cycle_diagram_table(void)
                                                if (cycle < max_planes && planes >= cycle_sequence[cycle & 7]) {
                                                        v = cycle_sequence[cycle & 7];
                                                } else {
-                                                       v = 0;
+                                                       v = -1;
                                                        freecycles++;
                                                }
                                                cycle_diagram_table[fm][res][planes][cycle] = v;
@@ -1421,12 +1476,12 @@ static void clear_bitplane_pipeline(int type)
 #define ESTIMATED_FETCH_MODE 1
 #define OPTIMIZED_ESTIMATE 1
 
-static uae_u8 estimated_cycles_buf0[256];
-static uae_u8 estimated_cycles_buf1[256];
-static uae_u8 estimated_cycles_empty[256];
+static uae_s8 estimated_cycles_buf0[256];
+static uae_s8 estimated_cycles_buf1[256];
+static uae_s8 estimated_cycles_empty[256];
 static int estimate_cycles_empty_index = -1;
 static uae_u16 estimated_bplcon0, estimated_fm, estimated_plfstrt, estimated_plfstop;
-static uae_u8* estimated_cycles = estimated_cycles_empty;
+static uae_s8 *estimated_cycles = estimated_cycles_empty;
 static bool estimated_empty;
 static int estimated_maxhpos[2];
 
@@ -1534,9 +1589,10 @@ static void estimate_last_fetch_cycle(int hpos)
                        int fc = fetch_cycle;
                        int starting_last_block_at = (fc + fetchunit - 1) & ~(fetchunit - 1);
                        if (ddf_stopping == 2) {
-                               starting_last_block_at -= fetchunit;
-                               if (starting_last_block_at < 0) {
-                                       starting_last_block_at += maxhpos;
+                               if (starting_last_block_at <= fetchunit) {
+                                       starting_last_block_at = 0;
+                               } else {
+                                       starting_last_block_at -= fetchunit;
                                }
                        }
                        estimated_cycle_count = (starting_last_block_at - fc) + lastfetchunit;
@@ -1613,7 +1669,7 @@ struct bpl_estimate {
        uae_u16 start_pos;
        uae_u16 end_pos;
        uae_u16 vpos;
-       uae_u8 *cycle_diagram;
+       uae_s8 *cycle_diagram;
        uae_u16 ce_offset;
 };
 
@@ -1726,6 +1782,17 @@ static void set_chipset_mode(void)
        }
        shdelay_disabled = false;
        exthblank_state = false;
+       refmask = 0x1fffff;
+       ref_ras_add = REF_RAS_ADD_AGA;
+       if (!aga_mode) {
+               ref_ras_add = REF_RAS_ADD_ECS;
+               refmask >>= 1;
+               if (!ecs_agnus) {
+                       ref_ras_add = REF_RAS_ADD_OCS;
+                       refmask >>= 1;
+               }
+       }
+       hdiw_counter_sconflict_mask = (512 << sprite_buffer_res) - 1;
        calcdiw();
 }
 
@@ -1966,77 +2033,424 @@ static void setup_fmodes(int hpos)
        SET_LINE_CYCLEBASED;
 }
 
-static int fetch_warn(int nr, int hpos, bool *addmodulop)
+static int REGPARAM2 custom_wput_1(int hpos, uaecptr addr, uae_u32 value, int noget);
+
+static uae_u16 get_strobe_reg(int slot)
 {
-       static int warned1 = 30, warned2 = 30;
-       int add = fetchmode_bytes;
-       // fake add value must not be large enough for high word to change
-       if (cycle_line_slot[hpos] == CYCLE_STROBE) {
-               if (warned1 >= 0) {
-                       write_log(_T("WARNING: BPL strobe refresh conflict, hpos %02X!\n"), hpos);
-                       warned1--;
+       uae_u16 strobe = 0x1fe;
+       if (slot == 0) {
+               strobe = 0x3c;
+               if (vb_state && vpos < equ_vblank_endline) {
+                       strobe = 0x38;
+               } else if (vb_state) {
+                       strobe = 0x3a;
                }
-               *addmodulop = false;
-               add = refptr_val & 0x0ffe;
+       } else if (slot == 1 && ecs_agnus && lol) {
+               strobe = 0x3e;
+       }
+       return strobe;
+}
+
+static uae_u16 fetch16(uaecptr p, int nr)
+{
+       uae_u16 v;
+       if (aga_mode) {
+               // AGA always does 32-bit fetches, this is needed
+               // to emulate 64 pixel wide sprite side-effects.
+               uae_u32 vv = chipmem_lget_indirect(p & ~3);
+               if (p & 2) {
+                       v = (uae_u16)vv;
+                       if (nr >= 0) {
+                               fetched_aga_spr[nr] = (v << 16) | v;
+                       }
+               } else {
+                       v = vv >> 16;
+                       if (nr >= 0) {
+                               fetched_aga_spr[nr] = vv;
+                       }
+               }
+       } else {
+               v = chipmem_wget_indirect(p);
+       }
+#ifdef DEBUGGER
+       if (memwatch_enabled) {
+               debug_getpeekdma_value(v);
+       }
+       if (debug_dma) {
+               record_dma_read_value(v);
+       }
+#endif
+       return v;
+}
+
+static uae_u32 fetch32(uaecptr p)
+{
+       uae_u32 v;
+       uaecptr pm = p & ~3;
+       if (p & 2) {
+               v = chipmem_lget_indirect(pm) & 0x0000ffff;
+               v |= v << 16;
+       } else if (fetchmode_fmode_bpl & 2) { // optimized (fetchmode_fmode & 3) == 2
+               v = chipmem_lget_indirect(pm) & 0xffff0000;
+               v |= v >> 16;
+       } else {
+               v = chipmem_lget_indirect(pm);
+       }
+#ifdef DEBUGGER
+       if (memwatch_enabled) {
+               debug_getpeekdma_value_long(v, p - pm);
+       }
+       if (debug_dma) {
+               record_dma_read_value_wide(v, false);
+       }
+#endif
+       return v;
+}
+
+static uae_u64 fetch64(uaecptr p)
+{
+       uae_u64 v;
+       uaecptr pm = p & ~7;
+       uaecptr pm1, pm2;
+       if (p & 4) {
+               pm1 = pm + 4;
+               pm2 = pm + 4;
+       } else {
+               pm1 = pm;
+               pm2 = pm + 4;
+       }
+       if (p & 2) {
+               uae_u32 v1 = chipmem_lget_indirect(pm1) & 0x0000ffff;
+               uae_u32 v2 = chipmem_lget_indirect(pm2) & 0x0000ffff;
+               v1 |= v1 << 16;
+               v2 |= v2 << 16;
+               v = (((uae_u64)v1) << 32) | v2;
        } else {
-               if (warned2 >= 0) {
-                       warned2--;
-                       write_log(_T("WARNING: BPL refresh conflict, hpos %02X!\n"), hpos);
+               v = ((uae_u64)chipmem_lget_indirect(pm1)) << 32;
+               v |= chipmem_lget_indirect(pm2);
+       }
+#ifdef DEBUGGER
+       if (memwatch_enabled) {
+               debug_getpeekdma_value_long((uae_u32)(v >> 32), p - pm1);
+               debug_getpeekdma_value_long((uae_u32)(v >> 0), p - pm2);
+       }
+       if (debug_dma) {
+               record_dma_read_value_wide(v, true);
+       }
+#endif
+       return v;
+}
+
+// Nasty chipset bitplane/sprite DMA conflict bug
+//
+// If bitplane DMA ends before sprite slots and last bitplane slot also has active sprite slot, sprite DMA is not stolen by bitplane DMA but sprite DMA conflicts with bitplane DMA:
+// Target DMA custom register becomes AND of last bitplane BPLxDAT register and conflicting sprite register, for example 0x110 (BPL1DAT) & 0x168 (SPR5POS) = 0x100 (BPLCON0).
+// Source DMA address becomes OR of bitplane and sprite pointer addresses.
+// DMA reads word (or larger if FMODE>0) from OR'd DMA address and writes it to new target custom register.
+// Bitplane +2/+4/+8 and possible modulo is added to OR'd DMA address.
+// DMA address gets written back to both bitplane and sprite pointers.
+// This is fully repeatable, no random side-effects noticed.
+
+static int bplsprchipsetbug(int nr, int fm, int hpos)
+{
+       uae_u16 breg = 0x110 + nr * 2;
+       uae_u16 sreg = sprbplconflict;
+       uae_u16 creg = breg & sreg;
+       int snum = (sreg - 0x140) / 8;
+       uaecptr px = bplpt[nr] | spr[snum].pt;
+
+       if (creg < 0x110 || creg >= 0x120) {
+#ifdef DEBUGGER
+               if (debug_dma) {
+                       record_dma_read(creg, px, hpos, vpos, DMARECORD_BITPLANE, nr);
+               }
+#endif
+       }
+
+       uae_u64 v;
+       uae_u16 v2;
+       if (fm == 0) {
+               v = fetch16(px, -1);
+               v2 = v;
+       } else if (fm == 1) {
+               v = fetch32(px);
+               v2 = v >> 16;
+       } else {
+               v = fetch64(px);
+               v2 = v >> 48;
+       }
+       bplpt[nr] = px;
+
+       if (creg < 0x110 || creg >= 0x120) {
+               custom_wput_1(hpos, creg, v2, 1);
+#ifdef DEBUGGER
+               if (debug_dma) {
+                       record_dma_read_value_wide(v, false);
+                       record_dma_read(breg, px, hpos, vpos, DMARECORD_BITPLANE, nr);
                }
-               add = refptr_val & 0x0ffe;
-               *addmodulop = false;
+#endif
+               nr = -1;
+
+       } else {
+
+               uaecptr px = bplpt[nr] | spr[snum].pt;
+               spr[snum].pt = px;
+               bplpt[nr] = px;
+
+               nr = (creg - 0x110) / 2;
        }
-       return add;
+
+       return nr;
 }
 
-static bool fetch(int nr, int fm, int hpos, bool addmodulo)
+bool get_ras_cas(uaecptr addr, int *rasp, int *casp)
 {
-       int add = fetchmode_bytes;
-
-       if (cycle_line_slot[hpos] == CYCLE_STROBE) {
-               // strobe refresh conflict
-               add = fetch_warn(nr, hpos, &addmodulo);
-       } else if (cycle_line_slot[hpos] == CYCLE_REFRESH) {
-               // refresh conflict
-               add = fetch_warn(nr, hpos, &addmodulo);
-       } else if (cycle_line_slot[hpos] == CYCLE_MISC) {
-               // DMAL conflict
-               // AUDxDAT AND BPLxDAT = read-only register
-               // DSKDATR AND BLPxDAT = read-only register
-               // DSKDAT AND BPLxDAT = read-only register
-               return false;
+       int ras, cas;
+       bool ret = false;
+       if (aga_mode) {
+               ras = (((addr >> 12) & 127) << 1) | ((addr >> 9) & 1);
+               cas = (addr >> 0) & 0xff;
+               if ((addr >> 8) & 1) {
+                       ras |= 0x100;
+               }
+               if ((addr >> 19) & 1) {
+                       ras |= 0x200;
+               }
+               if ((addr >> 10) & 1) {
+                       cas |= 0x100;
+               }
+               if ((addr >> 11) & 1) {
+                       cas |= 0x200;
+               }
+       } else if (ecs_agnus && currprefs.chipmem.size > 0x100000) {
+               ras = (addr >> 9) & 0x1ff;
+               cas = (addr >> 1) & 0xff;
+               if ((addr >> 19) & 1) {
+                       ras |= 0x200;
+               }
+               if ((addr >> 18) & 1) {
+                       cas |= 0x100;
+               }
+       } else if (ecs_agnus) {
+               ras = (addr >> 9) & 0x1ff;
+               cas = (addr >> 1) & 0xff;
+               if ((addr >> 19) & 1) {
+                       ret = true;
+               }
+               if ((addr >> 18) & 1) {
+                       cas |= 0x100;
+               }
        } else {
-               cycle_line_slot[hpos] = CYCLE_BITPLANE;
-#if 0
-               // audio/disk conflict? Both channel DMA transfers are skipped.
-               if (dmal_alloc_mask && hpos >= DMAL_FIRST_HPOS && hpos < DMAL_FIRST_HPOS + 8 * 2) {
-                       for (int i = 0; i < 3 * 2 + 4 * 2; i += 2) {
-                               if ((dmal_alloc_mask & (3 << i)) && hpos == DMAL_FIRST_HPOS + i) {
-                                       uae_u16 bpladdr = 0x110 + nr * 2;
-                                       uae_u16 dmaladdr;
-                                       if (i < 3 * 2) {
-                                               dmaladdr = (i & (1 << i)) ? 0x026 : 0x008;
-                                       } else {
-                                               dmaladdr = 0xaa + (i - 3 * 2) * 16 / 2;
-                                       }
-                                       uae_u16 newaddr = bpladdr & dmaladdr;
-                                       write_log("%04x-%04x=%04x ", dmaladdr, bpladdr,newaddr);
-                                       // clear DMAL request bits
-                                       dmal &= ~(3 << i);
-                                       // skip BPL DMA
-                                       return false;
+               ras = (addr >> 1) & 0xff;
+               cas = (addr >> 9) & 0xff;
+               if ((addr >> 17) & 1) {
+                       ras |= 0x100;
+               }
+               if ((addr >> 18) & 1) {
+                       cas |= 0x100;
+               }
+       }
+       *rasp = ras;
+       *casp = cas;
+       return ret;
+}
+
+
+static uaecptr update_refptr(int slot, int end, bool process, bool overwrite)
+{
+       if (refptr_preupdated) {
+               refptr_preupdated = false;
+               refptr = refptr_p;
+       }
+
+       uaecptr rp = refptr;
+       for (int i = slot + 1; i < end; i++) {
+               if (!(refresh_handled_slot & (1 << i))) {
+#ifdef DEBUGGER
+                       if (debug_dma) {
+                               int hp = REFRESH_FIRST_HPOS + i * 2;
+                               if (overwrite || (!overwrite && !record_dma_check(hp, vpos))) {
+                                       uae_u16 strobe = get_strobe_reg(i);
+                                       record_dma_clear(hp, vpos);
+                                       record_dma_read(strobe, rp & refmask, hp, vpos, DMARECORD_REFRESH, i);
+                                       record_dma_read_value(0xffff);
                                }
                        }
+#endif
+                       rp += ref_ras_add;
+               }
+               if (process) {
+                       refresh_handled_slot |= 1 << i;
+               }
+       }
+       return rp;
+}
+
+// Strobe+refresh (always first, second possible if ECS and NTSC) slot conflict
+static void fetch_strobe_conflict(int nr, int fm, int hpos, bool addmodulo)
+{
+       int slot = (hpos - REFRESH_FIRST_HPOS) / 2;
+       static int warned1 = 30;
+
+       refptr = update_refptr(-1, slot, true, true);
+       refresh_handled_slot |= 1 << slot;
+
+       uae_u16 rreg = get_strobe_reg(slot);
+       uae_u16 breg = 0x110 + nr * 2;
+       uae_u16 creg = rreg & breg;
+
+       uaecptr bplptx = bplpt[nr];
+       uaecptr refptx = refptr;
+       uaecptr px = bplptx | refptx;
+
+       if (creg != rreg) {
+#ifdef DEBUGGER
+               if (debug_dma) {
+                       record_dma_clear(hpos, vpos);
+                       record_dma_read(creg, px, hpos, vpos, DMARECORD_REFRESH, nr);
                }
 #endif
        }
 
-       uaecptr p = bplpt[nr];
+#ifdef DEBUGGER
+       if (debug_dma) {
+               record_dma_read_value_wide(0xffff, false);
+               record_dma_read(breg, px, hpos, vpos, DMARECORD_BITPLANE, nr);
+       }
+#endif
+
+       if (addmodulo) {
+               // modulo is OR'd with REF_RAS_ADD
+               bplpt[nr] = px;
+               uae_s16 m1 = bpl1mod, m2 = bpl2mod;
+               uae_s16 m3 = bpl1mod_prev, m4 = bpl2mod_prev;
+               bpl1mod |= ref_ras_add;
+               bpl2mod |= ref_ras_add;
+               bpl1mod_prev |= ref_ras_add;
+               bpl2mod_prev |= ref_ras_add;
+               add_modulo(hpos, nr);
+               bpl1mod = m1; bpl2mod = m2;
+               bpl1mod_prev = m3; bpl2mod_prev = m4;
+               px = bplpt[nr];
+       } else {
+               px += ref_ras_add;
+       }
+
+       px &= refmask;
+       bplpt[nr] = px;
+       refptr = px;
+       update_refptr(slot, 4, false, true);
+
+       if (warned1 >= 0) {
+               write_log(_T("WARNING: BPL strobe refresh conflict, slot %d!\n"), slot);
+               warned1--;
+       }
+
+       if (!hstrobe_conflict_frame) {
+               int d = 512 - (maxhpos * 2 + 1) + 1;
+               hdiw_counter_sconflict = d << sprite_buffer_res;
+               hdiw_counter_conflict = 0;
+               hstrobe_conflict_frame = true;
+       }
+       hstrobe_conflict = true;
+
+       SET_LINE_CYCLEBASED;
+}
+
+// refresh only slot conflict
+static void fetch_refresh_conflict(int nr, int fm, int hpos, bool addmodulo)
+{
+       int slot = (hpos - REFRESH_FIRST_HPOS) / 2;
+       static int warned1 = 30;
+
+       refptr = update_refptr(-1, slot, true, true);
+       refresh_handled_slot |= 1 << slot;
+
+       uaecptr bplptx = bplpt[nr];
+       uaecptr refptx = refptr;
+       uaecptr px = bplptx | refptx;
+
+#ifdef DEBUGGER
+       if (debug_dma) {
+               record_dma_clear(hpos, vpos);
+               record_dma_read(0x1fe, px, hpos, vpos, DMARECORD_REFRESH, slot);
+       }
+#endif
 
-       bplpt[nr] += add;
-       bplptx[nr] += add;
        if (addmodulo) {
+               // modulo is OR'd with REF_RAS_ADD
+               bplpt[nr] = px;
+               uae_s16 m1 = bpl1mod, m2 = bpl2mod;
+               uae_s16 m3 = bpl1mod_prev, m4 = bpl2mod_prev;
+               bpl1mod |= ref_ras_add;
+               bpl2mod |= ref_ras_add;
+               bpl1mod_prev |= ref_ras_add;
+               bpl2mod_prev |= ref_ras_add;
                add_modulo(hpos, nr);
+               bpl1mod = m1; bpl2mod = m2;
+               bpl1mod_prev = m3; bpl2mod_prev = m4;
+               px = bplpt[nr];
+       } else {
+               px += ref_ras_add;
+       }
+
+       px &= refmask;
+       bplpt[nr] = px;
+       refptr = px;
+       update_refptr(slot, 4, false, true);
+
+       if (warned1 >= 0) {
+               write_log(_T("WARNING: BPL refresh conflict, slot %d!\n"), slot);
+               warned1--;
+       }
+
+       SET_LINE_CYCLEBASED;
+}
+
+static bool fetch(int nr, int fm, int hpos, bool addmodulo)
+{
+       bool sprbplconflict = false;
+       bool stroberefbplconflict = false;
+       bool refbplconflict = false;
+       int snum = 0;
+
+       uae_u8 dmaslot = cycle_line_slot[hpos];
+       uaecptr p = bplpt[nr];
+
+       if (dmaslot) {
+               if (dmaslot == CYCLE_STROBE) {
+                       // strobe refresh conflict
+                       fetch_strobe_conflict(nr, fm, hpos, addmodulo);
+                       return false;
+               } else if (dmaslot == CYCLE_REFRESH) {
+                       // refresh conflict
+                       fetch_refresh_conflict(nr, fm, hpos, addmodulo);
+                       p = bplpt[nr];
+               } else if (dmaslot == CYCLE_MISC) {
+                       // DMAL conflict
+                       // AUDxDAT AND BPLxDAT = read-only register
+                       // DSKDATR AND BLPxDAT = read-only register
+                       // DSKDAT AND BPLxDAT = read-only register
+                       return false;
+               }
+       } else {
+               if (hpos == sprbplconflict_hpos) {
+                       nr = bplsprchipsetbug(nr, fm, hpos);
+                       if (nr < 0) {
+                               return false;
+                       }
+                       p = bplpt[nr];
+               }
+
+               // normal BPL cycle
+               cycle_line_slot[hpos] = CYCLE_BITPLANE;
+
+               bplpt[nr] += fetchmode_bytes;
+               bplptx[nr] += fetchmode_bytes;
+               if (addmodulo) {
+                       add_modulo(hpos, nr);
+               }
+
        }
 
 #ifdef DEBUGGER
@@ -2046,35 +2460,13 @@ static bool fetch(int nr, int fm, int hpos, bool addmodulo)
        if (memwatch_enabled) {
                debug_getpeekdma_chipram(p, MW_MASK_BPL_0 << nr, 0x110 + nr * 2, 0xe0 + nr * 4);
        }
-       uae_u32 v = aga_mode ? chipmem_lget_indirect(p & ~3) : chipmem_wget_indirect(p);
 #endif
+
        switch (fm)
        {
        case 0:
        {
-               uae_u16 v;
-               if (aga_mode) {
-                       // AGA always does 32-bit fetches, this is needed
-                       // to emulate 64 pixel wide sprite side-effects.
-                       uae_u32 vv = chipmem_lget_indirect(p & ~3);
-                       if (p & 2) {
-                               v = (uae_u16)vv;
-                               fetched_aga_spr[nr] = (v << 16) | v;
-                       } else {
-                               v = vv >> 16;
-                               fetched_aga_spr[nr] = vv;
-                       }
-               } else {
-                       v = chipmem_wget_indirect(p);
-               }
-#ifdef DEBUGGER
-               if (memwatch_enabled) {
-                       debug_getpeekdma_value(v);
-               }
-               if (debug_dma) {
-                       record_dma_read_value(v);
-               }
-#endif
+               uae_u16 v = fetch16(p, nr);
                fetched_aga[nr] = fetched[nr] = v;
                regs.chipset_latch_rw = v;
                last_custom_value = (uae_u16)regs.chipset_latch_rw;
@@ -2083,24 +2475,7 @@ static bool fetch(int nr, int fm, int hpos, bool addmodulo)
 #ifdef AGA
        case 1:
        {
-               uaecptr pm = p & ~3;
-               if (p & 2) {
-                       fetched_aga[nr] = chipmem_lget_indirect(pm) & 0x0000ffff;
-                       fetched_aga[nr] |= fetched_aga[nr] << 16;
-               } else if (fetchmode_fmode_bpl & 2) { // optimized (fetchmode_fmode & 3) == 2
-                       fetched_aga[nr] = chipmem_lget_indirect(pm) & 0xffff0000;
-                       fetched_aga[nr] |= fetched_aga[nr] >> 16;
-               } else {
-                       fetched_aga[nr] = chipmem_lget_indirect(pm);
-               }
-#ifdef DEBUGGER
-               if (memwatch_enabled) {
-                       debug_getpeekdma_value_long(fetched_aga[nr], p - pm);
-               }
-               if (debug_dma) {
-                       record_dma_read_value_wide(fetched_aga[nr], false);
-               }
-#endif
+               fetched_aga[nr] = fetch32(p);
                regs.chipset_latch_rw = (uae_u32)fetched_aga[nr];
                last_custom_value = (uae_u16)regs.chipset_latch_rw;
                fetched[nr] = (uae_u16)fetched_aga[nr];
@@ -2108,34 +2483,7 @@ static bool fetch(int nr, int fm, int hpos, bool addmodulo)
        }
        case 2:
        {
-               uaecptr pm = p & ~7;
-               uaecptr pm1, pm2;
-               if (p & 4) {
-                       pm1 = pm + 4;
-                       pm2 = pm + 4;
-               } else {
-                       pm1 = pm;
-                       pm2 = pm + 4;
-               }
-               if (p & 2) {
-                       uae_u32 v1 = chipmem_lget_indirect(pm1) & 0x0000ffff;
-                       uae_u32 v2 = chipmem_lget_indirect(pm2) & 0x0000ffff;
-                       v1 |= v1 << 16;
-                       v2 |= v2 << 16;
-                       fetched_aga[nr] = (((uae_u64)v1) << 32) | v2;
-               } else {
-                       fetched_aga[nr] = ((uae_u64)chipmem_lget_indirect(pm1)) << 32;
-                       fetched_aga[nr] |= chipmem_lget_indirect(pm2);
-               }
-#ifdef DEBUGGER
-               if (memwatch_enabled) {
-                       debug_getpeekdma_value_long((uae_u32)(fetched_aga[nr] >> 32), p - pm1);
-                       debug_getpeekdma_value_long((uae_u32)(fetched_aga[nr] >> 0), p - pm2);
-               }
-               if (debug_dma) {
-                       record_dma_read_value_wide(fetched_aga[nr], true);
-               }
-#endif
+               fetched_aga[nr] = fetch64(p);
                regs.chipset_latch_rw = (uae_u32)fetched_aga[nr];
                last_custom_value = (uae_u16)regs.chipset_latch_rw;
                fetched[nr] = (uae_u16)fetched_aga[nr];
@@ -2959,6 +3307,9 @@ static void beginning_of_plane_block_early(int hpos)
        bpl_shifter = 1;
        int left = hpos + hpos_hsync_extra;
        thisline_decision.plfleft = left * 2;
+       if (hstrobe_conflict) {
+               thisline_decision.plfleft -= get_strobe_conflict_shift(hpos);
+       }
        if (hdiwstate == diw_states::DIW_waiting_stop && thisline_decision.diwfirstword < 0) {
                // 1.5 lores pixels
                int v = hpos_to_diw(hpos);
@@ -2976,6 +3327,9 @@ static void start_noborder(int hpos)
        reset_bpl_vars();
        if (thisline_decision.plfleft < 0) {
                thisline_decision.plfleft = hpos * 2;
+               if (hstrobe_conflict) {
+                       thisline_decision.plfleft -= get_strobe_conflict_shift(hpos);
+               }
                if (hdiwstate == diw_states::DIW_waiting_stop && thisline_decision.diwfirstword < 0) {
                        thisline_decision.diwfirstword = min_diwlastword;
                }
@@ -3507,6 +3861,8 @@ static void bpl_dma_normal_stop(int hpos)
 {
        ddf_stopping = 0;
        bprun = 0;
+       bprun_end = hpos;
+       plfstrt_sprite = 0x100;
        bprun_pipeline_flush_delay = 8;
        if (!ecs_agnus) {
                ddf_limit = true;
@@ -3572,7 +3928,7 @@ STATIC_INLINE void one_fetch_cycle_0(int hpos, int fm)
                int offset = get_rga_pipeline(hpos, 1);
                uae_u16 d = cycle_line_pipe[offset];
                if ((d & CYCLE_PIPE_BITPLANE) && (d & 7) == 1) {
-                       decide_diw(hpos);
+                       decide_hdiw(hpos);
                        if (hdiwstate == diw_states::DIW_waiting_stop || plane0p_forced) {
                                plane0p = true;
                        }
@@ -3796,20 +4152,29 @@ static void decide_bpl_fetch(int endhpos)
        }
 }
 
+static void vdiw_change(uae_u32 v)
+{
+       vdiwstate_bpl = v != 0;
+}
+
 static void decide_vline(void)
 {
        bool forceoff = (vb_start_line == 1 && !harddis_v);
 
        /* Take care of the vertical DIW.  */
        if (vpos == plffirstline && !forceoff) {
-               diwstate = diw_states::DIW_waiting_stop;
-               diwstate_vpos = vpos;
+               if (vdiwstate != diw_states::DIW_waiting_stop) {
+                       event2_newevent_xx(-1, CYCLE_UNIT, 1, vdiw_change);
+               }
+               vdiwstate = diw_states::DIW_waiting_stop;
                SET_LINE_CYCLEBASED;
        }
        // VB start line forces vertical display window off (if HARDDIS=0)
        if (vpos == plflastline || forceoff) {
-               diwstate = diw_states::DIW_waiting_start;
-               diwstate_vpos = vpos;
+               if (vdiwstate != diw_states::DIW_waiting_start) {
+                       event2_newevent_xx(-1, CYCLE_UNIT, 0, vdiw_change);
+               }
+               vdiwstate = diw_states::DIW_waiting_start;
                SET_LINE_CYCLEBASED;
        }
 }
@@ -3856,7 +4221,7 @@ static void record_color_change(int hpos, int regno, uae_u32 value)
        if (line_hidden())
                return;
 
-       decide_diw(hpos);
+       decide_hdiw(hpos);
        decide_line(hpos);
 
        if (thisline_decision.ctable < 0) {
@@ -4129,24 +4494,105 @@ static void do_sprite_collisions(void)
                        }
                }
        }
-#if 0
-       {
-               static int olx;
-               if (clxdat != olx)
-                       write_log(_T("%d: %04X\n"), vpos, clxdat);
-               olx = clxdat;
-       }
-#endif
-}
-
-static void check_sprite_collisions(void)
-{
-       if (sprites_enabled_this_line || brdspractive()) {
-               if (currprefs.collision_level > 1)
-                       do_sprite_collisions();
-               if (currprefs.collision_level > 2)
-                       do_playfield_collisions();
-       }
+#if 0
+       {
+               static int olx;
+               if (clxdat != olx)
+                       write_log(_T("%d: %04X\n"), vpos, clxdat);
+               olx = clxdat;
+       }
+#endif
+}
+
+static void check_sprite_collisions(void)
+{
+       if (sprites_enabled_this_line || brdspractive()) {
+               if (currprefs.collision_level > 1)
+                       do_sprite_collisions();
+               if (currprefs.collision_level > 2)
+                       do_playfield_collisions();
+       }
+}
+
+static int tospritexdiw(int diw)
+{
+       int v = (coord_window_to_hw_x(diw) - DIW_DDF_OFFSET) << sprite_buffer_res;
+       v -= (1 << sprite_buffer_res) - 1;
+       return v;
+}
+static int tospritexddf(int ddf)
+{
+       return (ddf - DIW_DDF_OFFSET - DDF_OFFSET) << sprite_buffer_res;
+}
+static int fromspritexdiw(int ddf)
+{
+       return coord_hw_to_window_x_lores(ddf >> sprite_buffer_res) + (DIW_DDF_OFFSET << lores_shift);
+}
+
+static void record_sprite_2(int sprxp, uae_u16 *buf, uae_u32 datab, int num, int dbl,
+       unsigned int mask, int do_collisions, uae_u32 collision_mask)
+{
+       uae_u16 erasemask = ~(3 << (2 * num));
+
+       // handle free running hdiw hiding sprites in different horizontal positions in different lines
+       int hdiwx1 = (diw_hstrt + (hdiw_counter_conflict << 2) + 3) & ((512 << 2) - 1);
+       int hdiwx2 = (diw_hstop + (hdiw_counter_conflict << 2) + 3) & ((512 << 2) - 1);
+       int hdiw1 = tospritexdiw(hdiwx1);
+       int hdiw2 = tospritexdiw(hdiwx2);
+
+       int j = 0;
+       while (datab) {
+               unsigned int col = 0;
+               unsigned coltmp = 0;
+
+               col = (datab & 3) << (2 * num);
+               if (hdiw2 > hdiw1) {
+                       if (sprxp < hdiw1 || sprxp >= hdiw2) {
+                               col = 0;
+                       }
+               } else {
+                       if (sprxp >= hdiw2 && sprxp < hdiw1) {
+                               col = 0;
+                       }
+               }
+
+               if ((j & mask) == 0) {
+                       unsigned int tmp = ((*buf) & erasemask) | col;
+                       *buf++ = tmp;
+                       if (do_collisions)
+                               coltmp |= tmp;
+                       sprxp++;
+               }
+               if (dbl > 0) {
+                       unsigned int tmp = ((*buf) & erasemask) | col;
+                       *buf++ = tmp;
+                       if (do_collisions)
+                               coltmp |= tmp;
+                       sprxp++;
+               }
+               if (dbl > 1) {
+                       unsigned int tmp;
+                       tmp = ((*buf) & erasemask) | col;
+                       *buf++ = tmp;
+                       if (do_collisions)
+                               coltmp |= tmp;
+                       tmp = ((*buf) & erasemask) | col;
+                       *buf++ = tmp;
+                       if (do_collisions)
+                               coltmp |= tmp;
+                       sprxp++;
+                       sprxp++;
+               }
+               j++;
+               datab >>= 2;
+               if (do_collisions) {
+                       coltmp &= collision_mask;
+                       if (coltmp) {
+                               unsigned int shrunk_tmp = sprite_ab_merge[coltmp & 255] | (sprite_ab_merge[coltmp >> 8] << 2);
+                               clxdat |= sprclx[shrunk_tmp];
+                       }
+               }
+       }
 }
 
 static void record_sprite_1(int sprxp, uae_u16 *buf, uae_u32 datab, int num, int dbl,
@@ -4262,10 +4708,13 @@ static void record_sprite(int num, int sprxp, uae_u16 *data, uae_u16 *datb, unsi
                        | (sprtabb[db & 0xFF] << 16) | sprtabb[db >> 8]);
                int off = (i << dbl) >> half;
                uae_u16 *buf = spixels + word_offs + off;
-               if (currprefs.collision_level > 0 && collision_mask)
+               if (hstrobe_conflict) {
+                       record_sprite_2(sprxp + off, buf, datab, num, dbl, mask, 1, collision_mask);
+               } else if (currprefs.collision_level > 0 && collision_mask) {
                        record_sprite_1(sprxp + off, buf, datab, num, dbl, mask, 1, collision_mask);
-               else
+               } else {
                        record_sprite_1(sprxp + off, buf, datab, num, dbl, mask, 0, collision_mask);
+               }
                data++;
                datb++;
        }
@@ -4330,21 +4779,6 @@ static void add_sprite(int *countp, int num, int sprxp, int posns[], int nrs[])
        *countp = count;
 }
 
-static int tospritexdiw(int diw)
-{
-       int v = (coord_window_to_hw_x (diw) - DIW_DDF_OFFSET) << sprite_buffer_res;
-       v -= (1 << sprite_buffer_res) - 1;
-       return v;
-}
-static int tospritexddf(int ddf)
-{
-       return (ddf - DIW_DDF_OFFSET - DDF_OFFSET) << sprite_buffer_res;
-}
-static int fromspritexdiw(int ddf)
-{
-       return coord_hw_to_window_x_lores(ddf >> sprite_buffer_res) + (DIW_DDF_OFFSET << lores_shift);
-}
-
 static void calcsprite(void)
 {
        sprite_minx = 0;
@@ -4381,8 +4815,10 @@ static void decide_sprites(int hpos, bool usepointx, bool quick)
        int sscanmask = 0x100 << sprite_buffer_res;
        int gotdata = 0;
        int extrahpos = hsyncstartpos_start_cycles * 2; // hpos 0 to this value is visible in right border
+       int conflict_diff = 0;
 
        point = (hpos + hpos_hsync_extra) * 2 - DDF_OFFSET;
+
        if (point <= last_sprite_point) {
                return;
        }
@@ -4393,7 +4829,7 @@ static void decide_sprites(int hpos, bool usepointx, bool quick)
        }
 
        if (!quick) {
-               decide_diw(hpos);
+               decide_hdiw(hpos);
                decide_line(hpos);
                calcsprite();
        }
@@ -4401,13 +4837,13 @@ static void decide_sprites(int hpos, bool usepointx, bool quick)
        count = 0;
        for (int i = 0; i < MAX_SPRITES; i++) {
                struct sprite *s = &spr[i];
-               int xpos = spr[i].xpos;
+               int xpos = (spr[i].xpos + hdiw_counter_sconflict) & hdiw_counter_sconflict_mask;
                int sprxp = (fmode & 0x8000) ? (xpos & ~sscanmask) : xpos;
                int hw_xp = sprxp >> sprite_buffer_res;
                int pointx = usepointx && (s->ctl & sprite_sprctlmask) ? 0 : 1;
 
                // Sprite does not start if X=0 but SSCAN2 sprite does. Don't do X == 0 check here.
-               if (sprxp < 0 || hw_xp > maxhpos * 2 + 1) {
+               if (sprxp < 0 || (!hdiw_counter_sconflict && hw_xp > maxhpos * 2 + 1)) {
                        continue;
                }
 
@@ -4425,7 +4861,7 @@ static void decide_sprites(int hpos, bool usepointx, bool quick)
                        hw_xp = sprxp >> sprite_buffer_res;
                }
 
-               if (hw_xp > 0 && hw_xp > last_sprite_point && hw_xp <= point + pointx) {
+               if ((hw_xp > 0 || hdiw_counter_sconflict) && hw_xp > last_sprite_point && hw_xp <= point + pointx) {
                        add_sprite(&count, i, sprxp, posns, nrs);
                }
 
@@ -4564,7 +5000,7 @@ static void sync_copper(int hpos);
 static void finish_partial_decision(int hpos)
 {
        sync_copper(hpos);
-       decide_diw(hpos);
+       decide_hdiw(hpos);
        decide_line(hpos);
        decide_fetch_safe(hpos);
        decide_sprites(hpos);
@@ -4592,6 +5028,22 @@ static void finish_decisions(int hpos)
                thisline_decision.bplres = output_res(RES_LORES);
        }
 
+       if (hstrobe_conflict) {
+               sync_color_changes(hpos + DDF_OFFSET / 2 + 1);
+               int hdiw1 = (diw_hstrt + (hdiw_counter_conflict << 2) + 3) & ((512 << 2) - 1);
+               int hdiw2 = (diw_hstop + (hdiw_counter_conflict << 2) + 3) & ((512 << 2) - 1);
+               if (hdiw1 < hdiw2) {
+                       if (hdiw1 > 0) {
+                               insert_actborder(0, true);
+                               insert_actborder(hdiw1, false);
+                       }
+                       insert_actborder(hdiw2, true);
+               } else {
+                       insert_actborder(hdiw2, true);
+                       insert_actborder(hdiw1, false);
+               }
+       }
+
        // Add DDF_OFFSET to detect blanking changes past hpos max
        sync_color_changes(hpos + DDF_OFFSET / 2 + 1);
 
@@ -4687,6 +5139,8 @@ static void reset_decisions_scanline_start(void)
 
        /* Default to no bitplane DMA overriding sprite DMA */
        plfstrt_sprite = 0x100;
+       sprbplconflict_hpos = -1;
+       bprun_end = 0;
 
        // clear sprite allocations
        for (int i = 0; i < maxhpos; i++) {
@@ -4696,7 +5150,7 @@ static void reset_decisions_scanline_start(void)
                }
        }
 
-       if (!ecs_denise) {
+       if (!ecs_denise && currprefs.gfx_overscanmode < OVERSCANMODE_ULTRA) {
                if (currprefs.cs_dipagnus || !ecs_agnus) {
                        if (vb_start_line == 2 + vblank_extraline) {
                                record_color_change2(0, 0, COLOR_CHANGE_BLANK | 1);
@@ -4817,6 +5271,15 @@ static void reset_decisions_hsync_start(void)
                thisline_decision.vb = VB_NOVB;
        }
 #endif
+       if (currprefs.gfx_overscanmode == OVERSCANMODE_ULTRA) {
+               thisline_decision.vb = VB_NOVB;
+       }
+       if (nosignal_status > 0 || nosignal_status) {
+               thisline_decision.vb = VB_XBLANK;
+               MARK_LINE_CHANGED;
+       } else if (nosignal_status < 0) {
+               MARK_LINE_CHANGED;
+       }
 
        int left = thisline_decision.plfleft;
 
@@ -4856,7 +5319,7 @@ static void reset_decisions_hsync_start(void)
        if (1 && fetchmode >= 2 && !doflickerfix_active()) {
                // handle bitplane data wrap around
                bool toshift = false;
-               if ((exthblank || (beamcon0 & (BEAMCON0_VARHSYEN | BEAMCON0_VARCSYEN))) && (thisline_decision.bplres == 0 || currprefs.chipset_hr)) {
+               if ((exthblank || (beamcon0 & bemcon0_hsync_mask)) && (thisline_decision.bplres == 0 || currprefs.chipset_hr)) {
                        for (int i = 0; i < thisline_decision.nr_planes; i++) {
                                if (todisplay2_aga_saved[i]) {
                                        toshift = true;
@@ -4949,7 +5412,7 @@ static void reset_decisions_hsync_start(void)
 #endif
        }
 
-       if (debug_dma && (new_beamcon0 & (BEAMCON0_VARHSYEN | BEAMCON0_VARCSYEN))) {
+       if (debug_dma && (new_beamcon0 & bemcon0_hsync_mask)) {
                record_dma_event(DMA_EVENT_HSS, hpos, vpos);
                record_dma_event(DMA_EVENT_HSE, hsstop, vpos);
        }
@@ -5081,7 +5544,7 @@ static void checklacecount(bool lace)
 static void set_hcenter(void)
 {
        if (!aga_mode && ecs_denise) {
-               if (beamcon0 & (BEAMCON0_VARVSYEN | BEAMCON0_VARCSYEN)) {
+               if (beamcon0 & bemcon0_vsync_mask) {
                        hcenter_v2 = (hcenter & 0xff) << CCK_SHRES_SHIFT;
                } else {
                        hcenter_v2 = 132 << CCK_SHRES_SHIFT;
@@ -5161,7 +5624,7 @@ static void updateextblk(void)
                exthblank = (bplcon0 & 1) && (bplcon3 & 1);
        }
 
-       if (new_beamcon0 & (BEAMCON0_VARHSYEN | BEAMCON0_VARCSYEN)) {
+       if (new_beamcon0 & bemcon0_hsync_mask) {
 
                hsyncstartpos = hsstrt + 2;
                if (hsyncstartpos >= maxhpos) {
@@ -5265,7 +5728,9 @@ static void updateextblk(void)
        denisehtotal <<= CCK_SHRES_SHIFT;
 
        // ECS Denise has 1 extra lores pixel in right border
-       if (ecs_denise) {
+       if (currprefs.gfx_overscanmode == OVERSCANMODE_ULTRA) {
+               denisehtotal += 2 << (CCK_SHRES_SHIFT - 1);
+       } else if (ecs_denise) {
                denisehtotal += 1 << (CCK_SHRES_SHIFT - 1);
        }
 
@@ -5438,7 +5903,7 @@ void compute_framesync(void)
        if (currprefs.gfx_extraheight > 0) {
                vidinfo->drawbuffer.extraheight = currprefs.gfx_extraheight << vres2;
        }
-       if (vidinfo->drawbuffer.extrawidth == -2 && ((new_beamcon0 & (BEAMCON0_VARVBEN | BEAMCON0_VARVSYEN | BEAMCON0_VARCSYEN)) || currprefs.gfx_overscanmode == OVERSCANMODE_EXTREME)) {
+       if (vidinfo->drawbuffer.extrawidth == -2 && ((new_beamcon0 & (BEAMCON0_VARVBEN | bemcon0_vsync_mask)) || currprefs.gfx_overscanmode >= OVERSCANMODE_EXTREME)) {
                vidinfo->drawbuffer.extrawidth = -1;
        }
        vidinfo->drawbuffer.inheight = (maxvpos_display + maxvpos_display_vsync - minfirstline) << vres2;
@@ -5513,9 +5978,11 @@ void compute_framesync(void)
 static void init_hz(bool checkvposw)
 {
        int isntsc, islace;
-       int odbl = doublescan, omaxvpos = maxvpos;
+       int odbl = doublescan;
        double ovblank = vblank_hz;
        int hzc = 0;
+       int omaxhpos = maxhpos;
+       int omaxvpos = maxvpos;
 
        if (!checkvposw) {
                vpos_count = 0;
@@ -5536,6 +6003,17 @@ static void init_hz(bool checkvposw)
        }
 
        beamcon0 = new_beamcon0;
+       if (currprefs.cs_hvcsync == 0) {
+               bemcon0_hsync_mask = BEAMCON0_VARHSYEN | BEAMCON0_VARCSYEN;
+               bemcon0_vsync_mask = BEAMCON0_VARVSYEN | BEAMCON0_VARCSYEN;
+       } else if (currprefs.cs_hvcsync == 1) {
+               bemcon0_hsync_mask = BEAMCON0_VARCSYEN;
+               bemcon0_vsync_mask = BEAMCON0_VARCSYEN;
+       } else {
+               bemcon0_hsync_mask = BEAMCON0_VARHSYEN;
+               bemcon0_vsync_mask = BEAMCON0_VARVSYEN;
+       }
+
        isntsc = (beamcon0 & BEAMCON0_PAL) ? 0 : 1;
        islace = (interlace_seen) ? 1 : 0;
        if (!ecs_agnus) {
@@ -5588,7 +6066,7 @@ static void init_hz(bool checkvposw)
 
        // after vsync, it seems earlier possible visible line is vsync+3.
        int vsync_startline = 3;
-       if ((beamcon0 & BEAMCON0_VARVBEN) && (beamcon0 & (BEAMCON0_VARVSYEN | BEAMCON0_VARCSYEN))) {
+       if ((beamcon0 & BEAMCON0_VARVBEN) && (beamcon0 & bemcon0_vsync_mask)) {
                vsync_startline += vsstrt;
                if (vsync_startline >= maxvpos / 2) {
                        vsync_startline = 3;
@@ -5608,7 +6086,11 @@ static void init_hz(bool checkvposw)
        // calculate max possible display width in lores pixels
        if (beamcon0 & BEAMCON0_VARBEAMEN) {
                // assume VGA-like monitor if VARBEAMEN
-               if (currprefs.gfx_overscanmode == OVERSCANMODE_EXTREME) {
+               if (currprefs.gfx_overscanmode >= OVERSCANMODE_ULTRA) {
+                       maxhpos_display = maxhpos - 2;
+                       hsstop_detect = 0;
+                       maxvpos_display_vsync += 2;
+               } else if (currprefs.gfx_overscanmode >= OVERSCANMODE_EXTREME) {
                        maxhpos_display = maxhpos - 2;
                        hsstop_detect = 18;
                        maxvpos_display_vsync += 2;
@@ -5658,11 +6140,23 @@ static void init_hz(bool checkvposw)
                maxhpos_display = AMIGA_WIDTH_MAX;
                hsstop_detect = hsstop_detect2;
 
-               if (beamcon0 & (BEAMCON0_VARHSYEN | BEAMCON0_VARCSYEN)) {
+               if (beamcon0 & bemcon0_hsync_mask) {
                        if (currprefs.gfx_overscanmode < OVERSCANMODE_BROADCAST) {
                                hsstop_detect += 7;
                        } else if (currprefs.gfx_overscanmode == OVERSCANMODE_BROADCAST) {
                                hsstop_detect += 5;
+                       } else if (currprefs.gfx_overscanmode == OVERSCANMODE_ULTRA) {
+                               maxhpos_display += EXTRAWIDTH_ULTRA;
+                               maxvpos_display_vsync += 2;
+                               minfirstline = 0;
+                       }
+               } else {
+
+                       if (currprefs.gfx_overscanmode == OVERSCANMODE_ULTRA) {
+                               maxhpos_display += EXTRAWIDTH_ULTRA;
+                               maxvpos_display_vsync += 2;
+                               hsstop_detect = 8;
+                               minfirstline = 0;
                        }
                }
 
@@ -5696,7 +6190,9 @@ static void init_hz(bool checkvposw)
        vblank_extraline = !currprefs.cs_dipagnus && !ecs_denise ? 1 : 0;
 
        int minfirstline_hw = minfirstline;
-       if (currprefs.gfx_overscanmode == OVERSCANMODE_EXTREME) {
+       if (currprefs.gfx_overscanmode == OVERSCANMODE_ULTRA) {
+               minfirstline_hw = 0;
+       } else if (currprefs.gfx_overscanmode == OVERSCANMODE_EXTREME) {
                minfirstline_hw -= EXTRAHEIGHT_EXTREME / 2;
        } else if (currprefs.gfx_overscanmode == OVERSCANMODE_BROADCAST) {
                minfirstline_hw -= EXTRAHEIGHT_BROADCAST_TOP;
@@ -5728,7 +6224,7 @@ static void init_hz(bool checkvposw)
                vpos_count_diff = maxvpos;
        }
 
-       if ((beamcon0 & BEAMCON0_VARVBEN) && (beamcon0 & (BEAMCON0_VARVSYEN | BEAMCON0_VARCSYEN))) {
+       if ((beamcon0 & BEAMCON0_VARVBEN) && (beamcon0 & bemcon0_vsync_mask)) {
                minfirstline = vsync_startline;
                if (minfirstline > maxvpos / 2) {
                        minfirstline = vsync_startline;
@@ -5738,7 +6234,7 @@ static void init_hz(bool checkvposw)
                if (vsstrt > 0 && vsstrt < maxvpos / 2) {
                        maxvpos_display_vsync += vsstrt;
                }
-       } else if (beamcon0 & (BEAMCON0_VARVSYEN | BEAMCON0_VARCSYEN)) {
+       } else if (beamcon0 & bemcon0_vsync_mask) {
                firstblankedline = maxvpos + 1;
        } else if (beamcon0 & BEAMCON0_VARVBEN) {
                firstblankedline = vbstrt;
@@ -5748,13 +6244,13 @@ static void init_hz(bool checkvposw)
        } else {
                firstblankedline = maxvpos + 1;
        }
-       if (beamcon0 & (BEAMCON0_VARVBEN | BEAMCON0_VARVSYEN | BEAMCON0_VARCSYEN)) {
+       if (beamcon0 & (BEAMCON0_VARVBEN | bemcon0_vsync_mask)) {
                programmedmode = 2;
        }
 
        int eh = currprefs.gfx_extraheight;
        if (eh > 0) {
-               if (beamcon0 & (BEAMCON0_VARVSYEN | BEAMCON0_VARCSYEN)) {
+               if (beamcon0 & bemcon0_vsync_mask) {
                        maxvpos_display_vsync += eh / 2;
                        minfirstline -= eh / 2;
                } else {
@@ -5783,7 +6279,7 @@ static void init_hz(bool checkvposw)
                minfirstline = minfirstline_hw;
        }
 
-       if (beamcon0 & (BEAMCON0_VARVSYEN | BEAMCON0_VARCSYEN)) {
+       if (beamcon0 & bemcon0_vsync_mask) {
                if (maxvpos_display_vsync >= vsstrt + 3) {
                        maxvpos_display_vsync = vsstrt + 3;
                }
@@ -5854,6 +6350,11 @@ static void init_hz(bool checkvposw)
        if (maxvpos_total > MAXVPOS) {
                maxvpos_total = MAXVPOS;
        }
+
+       if (maxvpos != omaxvpos || maxhpos != omaxhpos) {
+               nosignal_trigger = true;
+       }
+
 #ifdef PICASSO96
        if (!p96refresh_active) {
                maxvpos_stored = maxvpos;
@@ -5936,7 +6437,7 @@ static void calcdiw(void)
                diwlastword = min_diwlastword;
        }
 
-       if (vstrt == vpos && vstop != vpos && diwstate == diw_states::DIW_waiting_start) {
+       if (vstrt == vpos && vstop != vpos && vdiwstate == diw_states::DIW_waiting_start) {
                // This may start BPL DMA immediately.
                SET_LINE_CYCLEBASED;
        }
@@ -6341,44 +6842,193 @@ static void BPLHSTOP(int hpos, uae_u16 v)
        bplhstop_v = v & (MAXVPOS_LINES_ECS - 1);
 }
 
+/*
 
-static void REFPTR(uae_u16 v)
-{
-       /*
-        ECS Agnus:
-
-        b15 8000: R 040
-        b14 4000: R 020
-        b13 2000: R 010
-        b12 1000: R 008
-        b11 0800: R 004 
-        b10 0400: R 002
-        b09 0200: R 001
-        b08 0100: C 080
-        b07 0080: C 040
-        b06 0040: C 020
-        b05 0020: C 010
-        b04 0010: C 008
-        b03 0008: C 004
-        b02 0004: C 002 C 100
-        b01 0002: C 001 R 100
-        b00 0001: R 080
+       REFPTR bit mapping to hidden refresh DMA pointer register.
+
+       OCS Agnus (RAS/CAS 9/9, 8-bit ROR refresh):
+
+       B  RAS CAS
+       0: 000 080
+       1: 101 000
+       2: 002 100
+       3: 004 000
+       4: 008 000
+       5: 010 000
+       6: 020 000
+       7: 040 000
+       8: 080 000
+       9: 000 001
+       A: 000 002
+       B: 000 004
+       C: 000 008
+       D: 000 010
+       E: 000 020
+       F: 000 040
+
+       ECS Agnus 1M (RAS/CAS 9/9, 9-bit ROR refresh):
+
+       B  RAS CAS
+       0: 080 000
+       1: 100 001
+       2: 000 102
+       3: 000 004
+       4: 000 008
+       5: 000 010
+       6: 000 020
+       7: 000 040
+       8: 000 080
+       9: 001 000
+       A: 002 000
+       B: 004 000
+       C: 008 000
+       D: 010 000
+       E: 020 000
+       F: 040 000
+
+       ECS Agnus 2M (RAS/CAS 10/10, 9-bit ROR refresh):
+
+       B  RAS CAS
+       0: 080 000
+       1: 100 001
+       2: 000 102
+       3: 200 004
+       4: 000 208
+       5: 000 010
+       6: 000 020
+       7: 000 040
+       8: 000 080
+       9: 001 000
+       A: 002 000
+       B: 004 000
+       C: 008 000
+       D: 010 000
+       E: 020 000
+       F: 040 000
+
+       AGA (RAS/CAS 10/10, CBR refresh)
+
+       0: 040/000
+       1: 080/001
+       2: 100/002
+       3: 200/004
+       4: 001/008
+       5: 000/010
+       6: 000/020
+       7: 000/040
+       8: 000/080
+       9: 000/100
+       A: 000/200
+       B: 002/000
+       C: 004/000
+       D: 008/000
+       E: 010/000
+       F: 020/000
 
-       */
+*/
 
-       refptr = v;
-       refptr_val = (v & 0xfe00) | ((v & 0x01fe) >> 1);
-       if (v & 1) {
-               refptr_val |= 0x80 << 9;
+static void REFPTR(int hpos, uae_u16 v)
+{
+       int diff = hpos - REFRESH_FIRST_HPOS;
+       // write exactly 1 cycle before refresh slot: write ignored.
+       if (diff == -1 || diff == 1 || diff == 3 || diff == 5) {
+               return;
        }
-       if (v & 2) {
-               refptr_val |= 1;
-               refptr_val |= 0x100 << 9;
+       int slot = diff / 2;
+       if (slot >= 0) {
+               if (slot > 4) {
+                       slot = 4;
+               }
+               update_refptr(-1, slot, true, true);
        }
-       if (v & 4) {
-               refptr_val |= 2;
-               refptr_val |= 0x100;
+
+       if (aga_mode) {
+               refptr = 0;
+               if (v & (1 << 0)) {
+                       refptr |= 0x020000;
+               }
+               if (v & (1 << 1)) {
+                       refptr |= 0x040000 | 0x000001;
+               }
+               if (v & (1 << 2)) {
+                       refptr |= 0x000100 | 0x000002;
+               }
+               if (v & (1 << 3)) {
+                       refptr |= 0x080000 | 0x000004;
+               }
+               if (v & (1 << 4)) {
+                       refptr |= 0x000200 | 0x000008;
+               }
+               if (v & (1 << 5)) {
+                       refptr |= 0x000010;
+               }
+               if (v & (1 << 6)) {
+                       refptr |= 0x000020;
+               }
+               if (v & (1 << 7)) {
+                       refptr |= 0x000040;
+               }
+               if (v & (1 << 8)) {
+                       refptr |= 0x000080;
+               }
+               if (v & (1 << 9)) {
+                       refptr |= 0x000400;
+               }
+               if (v & (1 << 10)) {
+                       refptr |= 0x000800;
+               }
+               if (v & (1 << 11)) {
+                       refptr |= 0x001000;
+               }
+               if (v & (1 << 12)) {
+                       refptr |= 0x002000;
+               }
+               if (v & (1 << 13)) {
+                       refptr |= 0x004000;
+               }
+               if (v & (1 << 14)) {
+                       refptr |= 0x008000;
+               }
+               if (v & (1 << 15)) {
+                       refptr |= 0x010000;
+               }
+               refptr <<= 1;
+       } else if (ecs_agnus) {
+               refptr = v & 0xfffe;
+               if (v & 1) {
+                       refptr |= 0x10000;
+               }
+               if (v & 2) {
+                       refptr |= 0x20000;
+               }
+               if (v & 4) {
+                       refptr |= 0x40000;
+               }
+               if (v & 8) {
+                       refptr |= 0x80000;
+               }
+               if (currprefs.chipmem.size > 0x100000) {
+                       if (v & 16) {
+                               refptr |= 0x100000;
+                       }
+               }
+       } else {
+               refptr = v & 0xfffe;
+               if (v & 1) {
+                       refptr |= 0x10000;
+               }
+               if (v & 2) {
+                       refptr |= 0x20000;
+               }
+               if (v & 4) {
+                       refptr |= 0x40000;
+               }
        }
+#if 0
+       int ras, cas;
+       bool x = get_ras_cas(refptr, &ras, &cas);
+       write_log("%04x %08x %c %03x %03X\n", v, refptr, x ? '+' : ' ', ras, cas);
+#endif
 }
 
 static int test_copper_dangerous(uaecptr address)
@@ -6527,9 +7177,9 @@ static void copper_stop(void)
        unset_special(SPCFLAG_COPPER);
 }
 
-static void DMACON_vars(void)
+static void bitplane_dma_change(uae_u32 v)
 {
-       dmacon_bpl = dmaen(DMA_BITPLANE);
+       dmacon_bpl = (v & DMA_BITPLANE) && (v & 0x200);
 }
 
 static void DMACON(int hpos, uae_u16 v)
@@ -6544,7 +7194,6 @@ static void DMACON(int hpos, uae_u16 v)
 
        setclr(&dmacon, v);
        dmacon &= 0x07FF;
-       DMACON_vars();
 
        changed = dmacon ^ oldcon;
 #if 0
@@ -6594,6 +7243,12 @@ static void DMACON(int hpos, uae_u16 v)
                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);
+               }
                SET_LINE_CYCLEBASED;
        }
 }
@@ -6687,7 +7342,9 @@ static void doint_delay_do(uae_u32 v)
 static void doint_delay(void)
 {
        if (m68k_interrupt_delay) {
-               event2_newevent_xx(-1, 3 * CYCLE_UNIT + CYCLE_UNIT / 2, 0, doint_delay_do);
+               // INTREQ or INTENA write: IPL line changes 0.5 CCKs later.
+               // 68000 needs one more CPU clock (0.5 CCK) before it detects it.
+               event2_newevent_xx(-1, 1 * CYCLE_UNIT, 0, doint_delay_do);
        } else {
                doint_delay_do(0);
        }
@@ -6800,17 +7457,19 @@ static void varsync(int reg, bool resync)
        // TOTAL
        if ((reg == 0x1c0 || reg == 0x1c8) && (beamcon0 & BEAMCON0_VARBEAMEN)) {
                varsync_changed = 1;
+               nosignal_trigger = true;
        }
        // VB
        if ((reg == 0x1cc || reg == 0x1ce) && (beamcon0 & BEAMCON0_VARVBEN)) {
                varsync_changed = 1;
        }
        // VS
-       if ((reg == 0x1e0 || reg == 0x1ca) && (beamcon0 & (BEAMCON0_VARVSYEN | BEAMCON0_VARCSYEN))) {
+       if ((reg == 0x1e0 || reg == 0x1ca) && (beamcon0 & bemcon0_vsync_mask)) {
                varsync_changed = 1;
+               nosignal_trigger = true;
        }
        // HS
-       if ((reg == 0x1de || reg == 0x1c2) && (beamcon0 & (BEAMCON0_VARHSYEN | BEAMCON0_VARCSYEN))) {
+       if ((reg == 0x1de || reg == 0x1c2) && (beamcon0 & bemcon0_hsync_mask)) {
                varsync_changed = 1;
        }
 }
@@ -6942,7 +7601,7 @@ static void bplcon0_denise_change(int hpos, uae_u16 con0)
        }
        
        SET_LINE_CYCLEBASED;
-       decide_diw(hpos);
+       decide_hdiw(hpos);
        decide_line(hpos);
        decide_fetch_safe(hpos);
 
@@ -7019,7 +7678,7 @@ static void BPLCON0(int hpos, uae_u16 v)
        }
 
        SET_LINE_CYCLEBASED;
-       decide_diw(hpos);
+       decide_hdiw(hpos);
        decide_line(hpos);
        decide_fetch_safe(hpos);
 
@@ -7047,7 +7706,7 @@ static void BPLCON0(int hpos, uae_u16 v)
                // clearing lightpen bit immediately returns VPOSR back to normal
                lightpen_triggered = 0;
        }
-       
+
        bplcon0 = v;
 
        check_harddis();
@@ -7227,7 +7886,7 @@ static void DIWSTRT(int hpos, uae_u16 v)
        if ((diw_hstrt >> 2) + DDF_OFFSET >= hpos * 2 - 2 && (diw_hstrt >> 2) + DDF_OFFSET <= hpos * 2 + 2) {
                diw_hstrt = max_diwlastword << 2;
        }
-       decide_diw(hpos);
+       decide_hdiw(hpos);
        decide_line(hpos);
        diwhigh_written = 0;
        diwstrt = v;
@@ -7242,7 +7901,7 @@ static void DIWSTOP(int hpos, uae_u16 v)
        if ((diw_hstop >> 2) + DDF_OFFSET >= hpos * 2 - 2 && (diw_hstop >> 2) + DDF_OFFSET <= hpos * 2 + 2) {
                diw_hstop = min_diwlastword << 2;
        }
-       decide_diw(hpos);
+       decide_hdiw(hpos);
        decide_line(hpos);
        diwhigh_written = 0;
        diwstop = v;
@@ -7261,7 +7920,7 @@ static void DIWHIGH(int hpos, uae_u16 v)
        if (diwhigh_written && diwhigh == v) {
                return;
        }
-       decide_diw(hpos);
+       decide_hdiw(hpos);
        decide_line(hpos);
        diwhigh_written = 1;
        diwhigh = v;
@@ -7972,7 +8631,7 @@ bool bitplane_dma_access(int hpos, int offset)
        if (hpos >= maxhpos) {
                hpos -= maxhpos;
        }
-       if (estimated_cycles[hpos]) {
+       if (estimated_cycles[hpos] > 0) {
                return true;
        }
        return false;
@@ -8003,9 +8662,9 @@ bool bitplane_dma_access(int hpos, int offset)
                        }
                        if (bploffset < 0xffff) {
                                uae_u16 idx = (bploffset - be->ce_offset) & fetchstart_mask;
-                               uae_u8 *cd = be->cycle_diagram;
+                               uae_s8 *cd = be->cycle_diagram;
                                int v = cd[idx];
-                               if (v) {
+                               if (v > 0) {
                                        return true;
                                }
                                return false;
@@ -8147,12 +8806,8 @@ static void decide_line(int endhpos)
                        cycle_line_pipe[hpos] = 0;
                }
 
-               bool dma = dmaen(DMA_BITPLANE) != 0;
-               bool diw = diwstate == diw_states::DIW_waiting_stop;
-               // DIW latching takes one cycle
-               if (hpos == 0 && vpos == diwstate_vpos) {
-                       diw = !diw;
-               }
+               bool dma = dmacon_bpl;
+               bool diw = vdiwstate_bpl;
 
                if (ecs) {
                        // ECS/AGA
@@ -8167,24 +8822,18 @@ static void decide_line(int endhpos)
                        }
 
                        // BPRUN latched: off
-                       if (bprun == 2) {
+                       if (bprun == 3) {
                                decide_line_decision_fetches(hpos);
-                               // If DDF has passed, jumps to last step.
-                               // (For example Scoopex Crash landing crack intro)
                                if (ddf_stopping == 1) {
-                                       ddf_stopping = 2;
-                               }
-                               // If DDF has not passed, set it as passed.
-                               if (ddf_stopping == 0) {
-                                       ddf_stopping = 1;
                                        // If bpl sequencer counter was all ones (last cycle of block): ddf passed jumps to last step.
                                        if (islastbplseq()) {
                                                ddf_stopping = 2;
                                        }
                                }
                                bprun = 0;
+                               bprun_end = hpos;
+                               plfstrt_sprite = 0x100;
                                bprun_pipeline_flush_delay = maxhpos;
-                               SET_LINE_CYCLEBASED;
                                end_estimate_last_fetch_cycle(hpos);
                        }
 
@@ -8252,27 +8901,40 @@ static void decide_line(int endhpos)
                        }
 
                        // BPRUN can only start if DMA, DIW or DDF state has changed since last time
-                       bool hwi = dma && diw && ddf_enable_on && (!ddf_limit || harddis_h);
-
-                       if (!bprun && dma && diw && hwi && !hwi_old) {
-                               decide_line_decision_fetches(hpos);
-                               // Bitplane sequencer activated
-                               bprun = -1;
-                               if (plfstrt_sprite > hpos) {
-                                       plfstrt_sprite = hpos;
-                               }
-                               bprun_start(hpos);
-                               if (ddf_stopping) {
-                                       bprun_pipeline_flush_delay = maxhpos;
-                               }
+                       if (!(hpos & 1)) {
+                               bool hwi = dma && diw && ddf_enable_on > 0 && (!ddf_limit || harddis_h);
+                               if (!bprun && dma && diw && hwi && !hwi_old) {
+                                       decide_line_decision_fetches(hpos);
+                                       // Bitplane sequencer activated
+                                       bprun = -1;
+                                       if (plfstrt_sprite > hpos) {
+                                               plfstrt_sprite = hpos;
+                                       }
+                                       bprun_start(hpos);
+                                       if (ddf_stopping) {
+                                               bprun_pipeline_flush_delay = maxhpos;
+                                       }
 #ifdef DEBUGGER
-                               if (debug_dma) {
-                                       record_dma_event(DMA_EVENT_DDFSTRT, hpos, vpos);
-                               }
+                                       if (debug_dma) {
+                                               record_dma_event(DMA_EVENT_DDFSTRT, hpos, vpos);
+                                       }
 #endif
+                               }
+
+                               hwi_old = hwi;
                        }
 
-                       hwi_old = hwi;
+                       if (bprun == 2) {
+                               bprun = 3;
+                               // If DDF has passed, jumps to last step.
+                               // (For example Scoopex Crash landing crack intro)
+                               if (ddf_stopping == 1) {
+                                       ddf_stopping = 2;
+                               } else if (ddf_stopping == 0) {
+                                       // If DDF has not passed, set it as passed.
+                                       ddf_stopping = 1;
+                               }
+                       }
 
                        // DIW or DMA switched off: clear BPRUN
                        if ((!dma || !diw) && bprun == 1) {
@@ -8293,16 +8955,12 @@ static void decide_line(int endhpos)
                                scandoubler_bpl_dma_start();
                        }
                        // BPRUN latched: off
-                       if (bprun == 2) {
+                       if (bprun == 3) {
                                decide_line_decision_fetches(hpos);
                                bprun = 0;
+                               bprun_end = hpos;
+                               plfstrt_sprite = 0x100;
                                bprun_pipeline_flush_delay = maxhpos;
-                               // If DDF has passed, jumps to last step.
-                               // (For example Scoopex Crash landing crack intro)
-                               if (ddf_stopping == 1) {
-                                       ddf_stopping = 2;
-                               }
-                               SET_LINE_CYCLEBASED;
                                end_estimate_last_fetch_cycle(hpos);
                        }
 
@@ -8365,6 +9023,15 @@ static void decide_line(int endhpos)
 #endif
                        }
 
+                       if (bprun == 2) {
+                               // If DDF has passed, jumps to last step.
+                               // (For example Scoopex Crash landing crack intro)
+                               if (ddf_stopping == 1) {
+                                       ddf_stopping = 2;
+                               }
+                               bprun = 3;
+                       }
+
                        // DMA or DIW off: clear BPRUN
                        if ((!dma || !diw) && bprun == 1) {
                                decide_line_decision_fetches(hpos);
@@ -8399,10 +9066,10 @@ static void decide_line(int endhpos)
 // use only copper to write BPLCON1 etc.. (exception is HulkaMania/TSP..)
 // this table should be filled with zeros and done somewhere else..
 static const int customdelay[]= {
-       1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0, /* 32 0x00 - 0x3e */
+       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 32 0x00 - 0x3e */
        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x40 - 0x5e */
        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x60 - 0x7e */
-       0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0, /* 0x80 - 0x9e */
+       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x80 - 0x9e */
        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 32 0xa0 - 0xde */
        /* BPLxPTH/BPLxPTL */
        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 16 */
@@ -8566,10 +9233,10 @@ static void do_copper_fetch(int hpos, uae_u8 id)
                        // WAIT or SKIP
 #ifdef DEBUGGER
                        if (debug_dma) {
-                               record_dma_read(0x8c, cop_state.ip - 2, hpos, vpos, DMARECORD_COPPER, (cop_state.ir[0] & 1) ? 1 : 0);
+                               record_dma_read(0x8c, cop_state.ip, hpos, vpos, DMARECORD_COPPER, (cop_state.ir[0] & 1) ? 1 : 0);
                        }
                        if (memwatch_enabled) {
-                               debug_getpeekdma_chipram(cop_state.ip - 2, MW_MASK_COPPER, 0x8c, cop_state.last_strobe == 2 ? 0x84 : 0x80);
+                               debug_getpeekdma_chipram(cop_state.ip, MW_MASK_COPPER, 0x8c, cop_state.last_strobe == 2 ? 0x84 : 0x80);
                        }
 #endif
                        cop_state.ir[1] = chipmem_wget_indirect(cop_state.ip);
@@ -9173,7 +9840,7 @@ static void do_sprite_fetch(int hpos, uae_u8 dat)
        // render sprites first
        decide_sprites(hpos, false, true);
 
-       sprite_fetch_full(s, hpos, slot, false, &data, &data321, &data322);
+       sprite_fetch_full(s, hpos, slot, dmastate, &data, &data321, &data322);
        int sprxp = s->xpos >> (sprite_buffer_res + 1);
        if (dmastate) {
                if (!slot) {
@@ -9184,7 +9851,7 @@ static void do_sprite_fetch(int hpos, uae_u8 dat)
 #ifdef AGA
                switch (sprite_width)
                {
-               case 64:
+                       case 64:
                        if (!slot) {
                                s->data[1] = data321;
                                s->data[2] = data322 >> 16;
@@ -9195,7 +9862,7 @@ static void do_sprite_fetch(int hpos, uae_u8 dat)
                                s->datb[3] = data322;
                        }
                        break;
-               case 32:
+                       case 32:
                        if (!slot) {
                                s->data[1] = data321;
                                s->data[2] = data;
@@ -9229,6 +9896,16 @@ static void do_sprite_fetch(int hpos, uae_u8 dat)
 
 }
 
+static void sprite_stolen_cycle(uae_u32 num)
+{
+       uae_u32 v = regs.chipset_latch_rw;
+       struct sprite *s = &spr[num & 7];
+       if (num & 0x100) {
+               s->datb[0] = v;
+               s->datb[1] = v >> 16;
+       }
+}
+
 static void decide_sprites_fetch(int endhpos)
 {
        int hpos = last_decide_sprite_hpos;
@@ -9255,6 +9932,7 @@ static void decide_sprites_fetch(int endhpos)
                                if (slot == 0 || slot == 2) {
                                        struct sprite *s = &spr[num];
                                        if (slot == 0) {
+                                               s->firstslotdone = false;
                                                if (!s->dmacycle && s->dmastate) {
                                                        s->dmacycle = 1;
                                                }
@@ -9270,10 +9948,20 @@ static void decide_sprites_fetch(int endhpos)
                                                        s->dmacycle = 1;
                                                }
                                        }
-                                       if (dmaen(DMA_SPRITE) && hpos <= plfstrt_sprite && s->dmacycle && !vb_end_line) {
-                                               bool dodma = true;
+                                       if (dmaen(DMA_SPRITE) && s->dmacycle && !vb_end_line) {
+                                               bool dodma = false;
+
+                                               decide_bpl_fetch(hpos + 1);
+
+                                               if (hpos <= plfstrt_sprite) {
+                                                       dodma = true;
+                                               } else {
+                                                       if (slot == 2 && sprite_width > 16 && s->firstslotdone) {
+                                                               event2_newevent_xx(-1, RGA_PIPELINE_OFFSET_SPRITE * CYCLE_UNIT, num | (s->dmastate ? 0x100 : 0), sprite_stolen_cycle);
+                                                       }
+                                               }
 #ifdef AGA
-                                               if (s->dblscan && (fmode & 0x8000) && (vpos & 1) != (s->vstart & 1) && s->dmastate) {
+                                               if (dodma && s->dblscan && (fmode & 0x8000) && (vpos & 1) != (s->vstart & 1) && s->dmastate) {
                                                        spr_arm(num, 1);
                                                        dodma = false;
                                                }
@@ -9286,7 +9974,13 @@ static void decide_sprites_fetch(int endhpos)
                                                                write_log(_T("sprite cycle already allocated! %02x\n"), cycle_line_pipe[offset]);
                                                        }
 #endif
-                                                       cycle_line_pipe[offset] = dat;
+                                                       if (bprun_end == hpos) {
+                                                               sprbplconflict = 0x140 + num * 8 + slot + (s->dmacycle ? 4 : 0);
+                                                               sprbplconflict_hpos = hpos + RGA_PIPELINE_OFFSET_SPRITE;
+                                                       } else {
+                                                               cycle_line_pipe[offset] = dat;
+                                                       }
+                                                       s->firstslotdone = true;
                                                }
                                        }
                                        if (!vb_end_line && s->dmacycle) {
@@ -9318,7 +10012,8 @@ static void init_sprites(void)
 static void init_hardware_frame(void)
 {
        if (!harddis_v) {
-               diwstate = diw_states::DIW_waiting_start;
+               vdiwstate = diw_states::DIW_waiting_start;
+               vdiw_change(0);
        }
 }
 
@@ -9737,9 +10432,9 @@ static void fpscounter(bool frameok)
                        idle = 100 * 10;
                gui_data.fps = fps;
                gui_data.idle = (int)idle;
-               gui_data.fps_color = frameok ? 0 : 1;
+               gui_data.fps_color = nosignal_status ? 2 : (frameok ? 0 : 1);
                if ((timeframes & 15) == 0) {
-                       gui_fps (fps, (int)idle, frameok ? 0 : 1);
+                       gui_fps (fps, (int)idle, gui_data.fps_color);
                }
        }
 }
@@ -9909,6 +10604,43 @@ static void vsync_handler_post(void)
                genlockvtoggle = lof_store ? 1 : 0;
        }
 
+       if ((bplcon0 & 2) && !currprefs.genlock) {
+               nosignal_trigger = true;
+       }
+       if ((beamcon0 & BEAMCON0_CSYTRUE) && currprefs.cs_hvcsync == 1) {
+               nosignal_trigger = true;
+       }
+       if ((beamcon0 & BEAMCON0_BLANKEN) && currprefs.cs_hvcsync == 1) {
+               nosignal_trigger = true;
+       }
+       if ((beamcon0 & BEAMCON0_CSCBEN) && currprefs.cs_hvcsync == 2) {
+               nosignal_trigger = true;
+       }
+       if (beamcon0 & BEAMCON0_VARBEAMEN) {
+               if (htotal < 100 || htotal > 250) {
+                       nosignal_trigger = true;
+               }
+               if (vtotal < 100 || vtotal > 1000) {
+                       nosignal_trigger = true;
+               }
+       }
+       if (beamcon0 & (BEAMCON0_VARHSYEN | BEAMCON0_VARCSYEN)) {
+               if (hsstop < hsstrt) {
+                       hsstop += maxhpos;
+               }
+               if (hsstop - hsstrt <= 2 || hsstop - hsstrt > 80) {
+                       nosignal_trigger = true;
+               }
+       }
+       if (beamcon0 & (BEAMCON0_VARVSYEN | BEAMCON0_VARCSYEN)) {
+               if (vsstop < vsstrt) {
+                       vsstop += maxvpos;
+               }
+               if (vsstop - vsstrt <= 1 || vsstop - vsstrt > 80) {
+                       nosignal_trigger = true;
+               }
+       }
+
        if (lof_prev_lastline != lof_lastline) {
                if (lof_togglecnt_lace < LOF_TOGGLES_NEEDED) {
                        lof_togglecnt_lace++;
@@ -9968,10 +10700,12 @@ static void vsync_handler_post(void)
        }
 
 #ifdef DEBUGGER
-       if (debug_copper)
+       if (debug_copper) {
                record_copper_reset();
-       if (debug_dma)
+       }
+       if (debug_dma) {
                record_dma_reset();
+       }
 #endif
 
 #ifdef PICASSO96
@@ -9989,6 +10723,14 @@ static void vsync_handler_post(void)
                if (!varsync_changed) {
                        varsync_changed = 2;
                }
+               if ((beamcon0 ^ new_beamcon0) & BEAMCON0_PAL) {
+                       nosignal_trigger = true;
+               }
+               if ((beamcon0 ^ new_beamcon0) & BEAMCON0_VARBEAMEN) {
+                       if (vtotal != maxvpos || htotal != maxhpos) {
+                               nosignal_trigger = true;
+                       }
+               }
        }
 
        vsync_check_vsyncmode();
@@ -9997,6 +10739,26 @@ static void vsync_handler_post(void)
                bogusframe--;
        }
 
+       if (nosignal_status < 0) {
+               nosignal_status = 0;
+       }
+       if (nosignal_cnt) {
+               nosignal_cnt--;
+               if (nosignal_cnt == 0) {
+                       nosignal_status = -1;
+               }
+       }
+       if (nosignal_trigger) {
+               nosignal_trigger = false;
+               if (currprefs.monitorblankdelay > 0) {
+                       nosignal_status = 1;
+                       nosignal_cnt = currprefs.monitorblankdelay / (1000 / vblank_hz);
+                       if (nosignal_cnt <= 0) {
+                               nosignal_cnt = 1;
+                       }
+               }
+       }
+
        config_check_vsync();
        if (timehack_alive > 0) {
                timehack_alive--;
@@ -10271,17 +11033,21 @@ static void events_dmal_hsync2(uae_u32 v)
 {
        int dmal_first = DMAL_FIRST_HPOS - v;
        // 3 disk + 4 audio
-       if (dmal) {
+       if (dmal && !hstrobe_conflict_frame) {
                write_log(_T("DMAL error!? %04x\n"), dmal);
        }
-       dmal = audio_dmal();
-       dmal <<= (3 * 2);
-       dmal |= disk_dmal();
-       dmal &= dmal_htotal_mask;
+       uae_u16 dmalt = audio_dmal();
+       dmalt <<= (3 * 2);
+       dmalt |= disk_dmal();
+       dmalt &= dmal_htotal_mask;
+       dmal |= dmalt;
        dmal_alloc_mask = dmal;
        if (!dmal) {
                return;
        }
+       if (hstrobe_conflict) {
+               return;
+       }
        dmal_hpos = 0;
        if (currprefs.cpu_memory_cycle_exact) {
                for (int i = 0; i < 3 * 2 + 4 * 2; i += 2) {
@@ -10411,7 +11177,7 @@ static void hautoscale_check(void)
                                firstword_bplcon1 = bplcon1;
                        }
                }
-               if (diwstate == diw_states::DIW_waiting_stop) {
+               if (vdiwstate == diw_states::DIW_waiting_stop) {
                        int f = 8 << fetchmode;
                        if (plfstrt + f < ddffirstword_total + f) {
                                ddffirstword_total = plfstrt + f;
@@ -10466,7 +11232,7 @@ static void hsync_handlerh(bool onvsync)
        hpos_hsync_extra = 0;
        estimate_last_fetch_cycle(hpos);
 
-       if (vb_end_next_line && !ecs_denise) {
+       if (vb_end_next_line && !ecs_denise && currprefs.gfx_overscanmode < OVERSCANMODE_ULTRA) {
                record_color_change2(hpos, 0, COLOR_CHANGE_BLANK | 1);
        }
 
@@ -10520,22 +11286,30 @@ static void hsync_handler_pre(bool onvsync)
                        }
                }
 
-               diw_hcounter += maxhpos * 2;
-               if (!ecs_denise && vpos == get_equ_vblank_endline() - 1) {
-                       diw_hcounter++;
-               }
-               if (ecs_denise || vpos > get_equ_vblank_endline() || (currprefs.cs_dipagnus && vpos == 0)) {
-                       diw_hcounter = maxhpos * 2;
+               hdiw_counter += maxhpos * 2;
+               if (!hstrobe_conflict) {
+                       hdiw_counter_sconflict = 0;
+                       hdiw_counter_conflict = 0;
+                       if (!ecs_denise && vpos == get_equ_vblank_endline() - 1) {
+                               hdiw_counter++;
+                       }
+                       if (ecs_denise || vpos > get_equ_vblank_endline() || (currprefs.cs_dipagnus && vpos == 0)) {
+                               hdiw_counter = maxhpos * 2;
+                       }
+               } else {
+                       hdiwstate = diw_states::DIW_waiting_stop;
+                       hdiw_counter_sconflict += ((512 - maxhpos * 2 + 1) + 1) << sprite_buffer_res;
+                       hdiw_counter_sconflict &= hdiw_counter_sconflict_mask;
+                       hdiw_counter_conflict += 512 - (maxhpos * 2 + 1) + 1;
+                       hdiw_counter_conflict &= 511;
                }
+               hdiw_counter &= 511;
        }
 
        devices_hsync();
 
        hsync_counter++;
 
-       refptr += 0x0200 * 4;
-       refptr_val += 0x0200 * 4;
-
        vpos_prev = vpos;
        vpos++;
        vpos_count++;
@@ -10565,6 +11339,23 @@ static void hsync_handler_pre(bool onvsync)
                events_schedule();
        }
 
+       for (int i = 0; i < 4; i++) {
+               if (!(refresh_handled_slot & (1 << i))) {
+#ifdef DEBUGGER
+                       if (debug_dma) {
+                               debug_mark_refreshed(refptr_p + i * ref_ras_add);
+                       }
+#endif
+                       if (!refptr_preupdated) {
+                               refptr += ref_ras_add;
+                       }
+               }
+       }
+       if (!hstrobe_conflict) {
+               dmal = 0;
+       }
+       hstrobe_conflict = false;
+
        debug_hsync();
 }
 
@@ -11330,7 +12121,7 @@ static void hsync_handler_post(bool onvsync)
        }
 
        if (!custom_disabled) {
-               if (!currprefs.blitter_cycle_exact && blt_info.blit_main && dmaen (DMA_BITPLANE) && diwstate == diw_states::DIW_waiting_stop) {
+               if (!currprefs.blitter_cycle_exact && blt_info.blit_main && dmaen (DMA_BITPLANE) && vdiwstate == diw_states::DIW_waiting_stop) {
                        blitter_slowdown(thisline_decision.plfleft, thisline_decision.plfright - (16 << fetchmode),
                                cycle_diagram_total_cycles[fetchmode][GET_RES_AGNUS (bplcon0)][GET_PLANES_LIMIT (bplcon0)],
                                cycle_diagram_free_cycles[fetchmode][GET_RES_AGNUS (bplcon0)][GET_PLANES_LIMIT (bplcon0)]);
@@ -11458,7 +12249,7 @@ static void hsync_handler_post(bool onvsync)
                }
        }
 
-       if (new_beamcon0 & (BEAMCON0_VARVSYEN | BEAMCON0_VARCSYEN)) {
+       if (new_beamcon0 & bemcon0_vsync_mask) {
                vs_state_on = vs_state;
        } else {
                vs_state_on = vs_state_hw;
@@ -11471,31 +12262,22 @@ static void hsync_handler_post(bool onvsync)
        decide_vline();
 
        int hp = REFRESH_FIRST_HPOS;
+       refptr_p = refptr;
        for (int i = 0; i < 4; i++) {
-               bool type = i == 0 || (i == 1 && ecs_agnus && lol);
-               alloc_cycle(hp, type ? CYCLE_STROBE : CYCLE_REFRESH);
+               uae_u16 strobe = get_strobe_reg(i);
+               alloc_cycle(hp, strobe != 0x1fe ? CYCLE_STROBE : CYCLE_REFRESH);
+               // assume refresh pointer not changed or conflicted
 #ifdef DEBUGGER
                if (debug_dma) {
-                       uae_u16 strobe = 0x1fe;
-                       if (i == 0) {
-                               strobe = 0x3c;
-                               if (vb_state && vpos < equ_vblank_endline) {
-                                       strobe = 0x38;
-                               } else if (vb_state) {
-                                       strobe = 0x3a;
-                               }
-                       } else if (i == 1 && ecs_agnus && lol) {
-                               strobe = 0x3e;
-                       }
-                       record_dma_read(strobe, 0xffffffff, hp, vpos, DMARECORD_REFRESH, i);
+                       record_dma_read(strobe, refptr & refmask, hp, vpos, DMARECORD_REFRESH, i);
                        record_dma_read_value(0xffff);
                }
 #endif
+               refptr += ref_ras_add;
                hp += 2;
-               if (hp >= maxhpos) {
-                       hp -= maxhpos;
-               }
        }
+       refresh_handled_slot = 0;
+       refptr_preupdated = true;
 
        if (debug_dma) {
                if (vs_state_on) {
@@ -11504,7 +12286,7 @@ static void hsync_handler_post(bool onvsync)
                if (vb_start_line) {
                        record_dma_event(DMA_EVENT_VB, REFRESH_FIRST_HPOS, vpos);
                }
-               if (diwstate == diw_states::DIW_waiting_stop) {
+               if (vdiwstate == diw_states::DIW_waiting_stop) {
                        record_dma_event(DMA_EVENT_VDIW, REFRESH_FIRST_HPOS, vpos);
                }
                if (lof_store) {
@@ -11513,6 +12295,7 @@ static void hsync_handler_post(bool onvsync)
                if (lol) {
                        record_dma_event(DMA_EVENT_LOL, REFRESH_FIRST_HPOS + 2, vpos);
                }
+               record_dma_hsync();
        }
 
 
@@ -11721,6 +12504,8 @@ static void hsync_handler(void)
                vsync_display_render();
                vsync_display_rendered = false;
                lof_display = lof_store;
+               hstrobe_conflict = false;
+               hstrobe_conflict_frame = false;
                reset_autoscale();
        }
        vsync_line = vs;
@@ -11839,7 +12624,6 @@ void custom_reset(bool hardreset, bool keyboardreset)
        display_reset = 1;
 
        if (!savestate_state) {
-               refptr_val = 0;
                cia_hsync = 0;
                extra_cycle = 0;
                hsync_counter = 0;
@@ -11906,7 +12690,11 @@ void custom_reset(bool hardreset, bool keyboardreset)
                diwhigh_written = 0;
                hdiwstate = diw_states::DIW_waiting_start; // this does not reset at vblank
 
-               refptr = 0xffff;
+               refptr = 0;
+               if (aga_mode) {
+                       refptr = 0x1ffffe;
+               }
+               refptr_p = refptr;
                FMODE(0, 0);
                CLXCON(0);
                CLXCON2(0);
@@ -11950,7 +12738,8 @@ void custom_reset(bool hardreset, bool keyboardreset)
        cop_state.movedelay = 0;
        cop_state.strobe = 0;
        cop_state.ignore_next = 0;
-       diwstate = diw_states::DIW_waiting_start;
+       vdiwstate = diw_states::DIW_waiting_start;
+       vdiw_change(0);
        check_harddis();
 
        dmal = 0;
@@ -12066,18 +12855,28 @@ void custom_reset(bool hardreset, bool keyboardreset)
 
 }
 
+void custom_dumpstate(int mode)
+{
+       if (!mode) {
+               console_out_f(_T("VPOS: %03d ($%03x) HPOS: %03d ($%03x) COP: $%08x\n"),
+                       vpos, vpos, current_hpos(), current_hpos(),
+                       cop_state.ip);
+       }
+}
+
 void dumpcustom(void)
 {
-       console_out_f(_T("DMACON: %04x INTENA: %04x (%04x) INTREQ: %04x (%04x) VPOS: %x HPOS: %x\n"), DMACONR (current_hpos ()),
-               intena, intena, intreq, intreq, vpos, current_hpos ());
-       console_out_f(_T("INT: %04x IPL: %d\n"), intena & intreq, intlev());
-       console_out_f(_T("COP1LC: %08lx, COP2LC: %08lx COPPTR: %08lx\n"), (unsigned long)cop1lc, (unsigned long)cop2lc, cop_state.ip);
-       console_out_f(_T("DIWSTRT: %04x DIWSTOP: %04x DDFSTRT: %04x DDFSTOP: %04x\n"),
-               (unsigned int)diwstrt, (unsigned int)diwstop, (unsigned int)ddfstrt, (unsigned int)ddfstop);
-       console_out_f(_T("BPLCON 0: %04x 1: %04x 2: %04x 3: %04x 4: %04x LOF=%d/%d HDIW=%d VDIW=%d\n"),
+       console_out_f(_T("DMACON: $%04x INTENA: $%04x ($%04x) INTREQ: $%04x ($%04x) VPOS: %03d ($%03x) HPOS: %03d ($%03x)\n"),
+               DMACONR(current_hpos()),
+               intena, intena, intreq, intreq, vpos, vpos, current_hpos(), current_hpos());
+       console_out_f(_T("INT: $%04x IPL: %d\n"), intena & intreq, intlev());
+       console_out_f(_T("COP1LC: $%08x, COP2LC: $%08x COPPTR: $%08x\n"), cop1lc, cop2lc, cop_state.ip);
+       console_out_f(_T("DIWSTRT: $%04x DIWSTOP: $%04x DDFSTRT: $%04x DDFSTOP: $%04x\n"),
+               diwstrt, diwstop, ddfstrt, ddfstop);
+       console_out_f(_T("BPLCON 0: $%04x 1: $%04x 2: $%04x 3: $%04x 4: $%04x LOF=%d/%d HDIW=%d VDIW=%d\n"),
                bplcon0, bplcon1, bplcon2, bplcon3, bplcon4,
                lof_display, lof_store,
-               hdiwstate == diw_states::DIW_waiting_start ? 0 : 1, diwstate == diw_states::DIW_waiting_start ? 0 : 1);
+               hdiwstate == diw_states::DIW_waiting_start ? 0 : 1, vdiwstate == diw_states::DIW_waiting_start ? 0 : 1);
        if (timeframes) {
                console_out_f(_T("Average frame time: %.2f ms [frames: %d time: %d]\n"),
                        (double)frametime / timeframes, timeframes, frametime);
@@ -12384,7 +13183,7 @@ static int REGPARAM2 custom_wput_1 (int hpos, uaecptr addr, uae_u32 value, int n
        case 0x022: DSKPTL(value); break;
        case 0x024: DSKLEN(value, hpos); break;
        case 0x026: /* DSKDAT(value). Writing to DMA write registers won't do anything */; break;
-       case 0x028: REFPTR(value); break;
+       case 0x028: REFPTR(hpos, value); break;
        case 0x02A: VPOSW(value); break;
        case 0x02C: VHPOSW(value); break;
        case 0x02E: COPCON(value); break;
@@ -12717,6 +13516,14 @@ void custom_prepare_savestate(void)
        }
 }
 
+void restore_custom_finish(void)
+{
+       if ((bplcon0 & 2) && !currprefs.genlock) {
+               changed_prefs.genlock = currprefs.genlock = 1;
+               write_log(_T("statefile with BPLCON0 ERSY set without Genlock. Enabling Genlock.\n"));
+       }
+}
+
 #define RB restore_u8()
 #define SRB (uae_s8)restore_u8()
 #define RBB restore_u8() != 0
@@ -12845,7 +13652,7 @@ uae_u8 *restore_custom(uae_u8 *src)
        diwhigh = RW;                   /* 1E4 DIWHIGH */
        diwhigh_written = (diwhigh & 0x8000) ? 1 : 0;
        hdiwstate = (diwhigh & 0x4000) ? diw_states::DIW_waiting_stop : diw_states::DIW_waiting_start;
-       diwstate = (diwhigh & 0x0080) ? diw_states::DIW_waiting_start : diw_states::DIW_waiting_stop;
+       vdiwstate = (diwhigh & 0x0080) ? diw_states::DIW_waiting_start : diw_states::DIW_waiting_stop;
        diwhigh &= 0x3f3f;
        RW;                                             /* 1E6 ? */
        RW;                                             /* 1E8 ? */
@@ -12863,6 +13670,7 @@ uae_u8 *restore_custom(uae_u8 *src)
        }
        fmode = RW;                             /* 1FC FMODE */
        last_custom_value = RW; /* 1FE ? */
+       refptr = RL;                    /* full refresh pointer */
 
        bplcon0_saved = bplcon0;
        bplcon1_saved = bplcon1;
@@ -12873,7 +13681,8 @@ uae_u8 *restore_custom(uae_u8 *src)
        beamcon0_saved = new_beamcon0;
        bplcon0d = bplcon0;
        bplcon0d_old = 0;
-       DMACON_vars();
+       bitplane_dma_change(dmacon);
+       vdiw_change(vdiwstate == diw_states::DIW_waiting_stop);
 
        current_colors.extra = 0;
        if (isbrdblank(-1, bplcon0, bplcon3)) {
@@ -13055,7 +13864,7 @@ uae_u8 *save_custom(int *len, uae_u8 *dstptr, int full)
        SW(hsstrt);                     /* 1DE HSSTRT */
        SW(vsstrt);                     /* 1E0 VSSTRT */
        SW(hcenter);            /* 1E2 HCENTER */
-       SW(diwhigh | (diwhigh_written ? 0x8000 : 0) | (hdiwstate == diw_states::DIW_waiting_stop ? 0x4000 : 0) | (diwstate == diw_states::DIW_waiting_start ? 0x0080 : 0)); /* 1E4 DIWHIGH */
+       SW(diwhigh | (diwhigh_written ? 0x8000 : 0) | (hdiwstate == diw_states::DIW_waiting_stop ? 0x4000 : 0) | (vdiwstate == diw_states::DIW_waiting_start ? 0x0080 : 0)); /* 1E4 DIWHIGH */
        SW(0);                          /* 1E6 */
        SW(0);                          /* 1E8 */
        SW(0);                          /* 1EA */
@@ -13069,6 +13878,7 @@ uae_u8 *save_custom(int *len, uae_u8 *dstptr, int full)
        SW(0x8000 | (currprefs.ntscmode ? 1 : 0));                      /* 1FA (re-used for NTSC) */
        SW(fmode);                      /* 1FC FMODE */
        SW(last_custom_value);  /* 1FE */
+       SL(refptr);
 
        *len = dst - dstbak;
        return dstbak;
@@ -13427,7 +14237,9 @@ void check_prefs_changed_custom(void)
        if (currprefs.chipset_mask != changed_prefs.chipset_mask ||
                currprefs.cs_dipagnus != changed_prefs.cs_dipagnus ||
                currprefs.picasso96_nocustom != changed_prefs.picasso96_nocustom ||
-               currprefs.ntscmode != changed_prefs.ntscmode) {
+               currprefs.ntscmode != changed_prefs.ntscmode ||
+               currprefs.cs_hvcsync != changed_prefs.cs_hvcsync
+               ) {
                        currprefs.picasso96_nocustom = changed_prefs.picasso96_nocustom;
                        if (currprefs.ntscmode != changed_prefs.ntscmode) {
                                currprefs.ntscmode = changed_prefs.ntscmode;
@@ -13444,6 +14256,7 @@ void check_prefs_changed_custom(void)
                        }
                        currprefs.chipset_mask = changed_prefs.chipset_mask;
                        currprefs.cs_dipagnus = changed_prefs.cs_dipagnus;
+                       currprefs.cs_hvcsync = changed_prefs.cs_hvcsync;
                        init_custom();
        }
 
@@ -13555,6 +14368,9 @@ uae_u32 wait_cpu_cycle_read(uaecptr addr, int mode)
        int hpos;
 
        sync_cycles();
+
+       x_do_cycles_pre(CYCLE_UNIT);
+
        hpos = dma_cycle(addr, 0xffffffff, &mode);
 
 #ifdef DEBUGGER
@@ -13575,8 +14391,6 @@ uae_u32 wait_cpu_cycle_read(uaecptr addr, int mode)
        peekdma_data.mask = 0;
 #endif
 
-       x_do_cycles_pre(CYCLE_UNIT);
-
        switch(mode)
        {
                case -1:
@@ -13615,6 +14429,9 @@ uae_u32 wait_cpu_cycle_read_ce020(uaecptr addr, int mode)
        int hpos;
 
        sync_cycles();
+
+       x_do_cycles_pre(CYCLE_UNIT);
+
        hpos = dma_cycle(0xffffffff, 0xffff, NULL);
 
 #ifdef DEBUGGER
@@ -13632,8 +14449,6 @@ uae_u32 wait_cpu_cycle_read_ce020(uaecptr addr, int mode)
        peekdma_data.mask = 0;
 #endif
 
-       x_do_cycles_pre(CYCLE_UNIT);
-
        switch (mode) {
                case -1:
                v = get_long(addr);
@@ -13670,6 +14485,9 @@ void wait_cpu_cycle_write(uaecptr addr, int mode, uae_u32 v)
        int hpos;
 
        sync_cycles();
+
+       x_do_cycles_pre(CYCLE_UNIT);
+
        hpos = dma_cycle(addr, v, &mode);
 
 #ifdef DEBUGGER
@@ -13689,8 +14507,6 @@ void wait_cpu_cycle_write(uaecptr addr, int mode, uae_u32 v)
        peekdma_data.mask = 0;
 #endif
 
-       x_do_cycles_pre(CYCLE_UNIT);
-
        if (mode > -2) {
                if (mode < 0) {
                        put_long(addr, v);
@@ -13712,6 +14528,9 @@ void wait_cpu_cycle_write_ce020(uaecptr addr, int mode, uae_u32 v)
        int hpos;
 
        sync_cycles();
+
+       x_do_cycles_pre(CYCLE_UNIT);
+
        hpos = dma_cycle(0xffffffff, 0xffff, NULL);
 
 #ifdef DEBUGGER
@@ -13728,8 +14547,6 @@ void wait_cpu_cycle_write_ce020(uaecptr addr, int mode, uae_u32 v)
        peekdma_data.mask = 0;
 #endif
 
-       x_do_cycles_pre(CYCLE_UNIT);
-
        if (mode < 0) {
                put_long(addr, v);
        } else if (mode > 0) {
index d86ac6e69fb2782a173e99ee1f35d9e308781002..21334629b0cdb3311f72473d54b4cc5a8c3a8dc0 100644 (file)
--- a/debug.cpp
+++ b/debug.cpp
@@ -89,9 +89,9 @@ static uaecptr debug_copper_pc;
 extern int audio_channel_mask;
 extern int inputdevice_logging;
 
-static void debug_cycles(void)
+static void debug_cycles(int mode)
 {
-       trace_cycles = 1;
+       trace_cycles = mode;
        last_cycles2 = get_cycles();
        last_vpos2 = vpos;
        last_hpos2 = current_hpos();
@@ -128,7 +128,7 @@ void activate_debugger (void)
                // during disassembly etc..
                return;
        }
-       debug_cycles();
+       debug_cycles(1);
        debugger_active = 1;
        set_special (SPCFLAG_BRK);
        debugging = 1;
@@ -1388,7 +1388,7 @@ static bool debug_colors_set;
 
 static void set_dbg_color(int index, int extra, uae_u8 r, uae_u8 g, uae_u8 b, int max, const TCHAR *name)
 {
-       if (extra == 0) {
+       if (extra <= 0) {
                debug_colors[index].r = r;
                debug_colors[index].g = g;
                debug_colors[index].b = b;
@@ -1398,7 +1398,13 @@ static void set_dbg_color(int index, int extra, uae_u8 r, uae_u8 g, uae_u8 b, in
                debug_colors[index].name = name;
        if (max > 0)
                debug_colors[index].max = max;
-       debug_colors[index].l[extra] = lc((r << 16) | (g << 8) | (b << 0));
+       if (extra >= 0) {
+               debug_colors[index].l[extra] = lc((r << 16) | (g << 8) | (b << 0));
+       } else {
+               for (int i = 0; i < DMARECORD_MAX; i++) {
+                       debug_colors[index].l[i] = lc((r << 16) | (g << 8) | (b << 0));
+               }
+       }
 }
 
 static void set_debug_colors(void)
@@ -1415,6 +1421,7 @@ static void set_debug_colors(void)
        set_dbg_color(DMARECORD_BITPLANE,               0, 0x00, 0x00, 0xff, 8, _T("Bitplane"));
        set_dbg_color(DMARECORD_SPRITE,                 0, 0xff, 0x00, 0xff, 8, _T("Sprite"));
        set_dbg_color(DMARECORD_DISK,                   0, 0xff, 0xff, 0xff, 3, _T("Disk"));
+       set_dbg_color(DMARECORD_CONFLICT,               0, 0xff, 0xb8, 0x40, 0, _T("Conflict"));
 
        for (int i = 0; i < DMARECORD_MAX; i++) {
                for (int j = 1; j < DMARECORD_SUBITEMS; j++) {
@@ -1429,6 +1436,8 @@ static void set_debug_colors(void)
        set_dbg_color(DMARECORD_BLITTER,                2, 0x00, 0xff, 0x00, 0, NULL); // line
 }
 
+static int cycles_toggle;
+
 static void debug_draw_cycles (uae_u8 *buf, int bpp, int line, int width, int height, uae_u32 *xredcolors, uae_u32 *xgreencolors, uae_u32 *xbluescolors)
 {
        int y, x, xx, dx, xplus, yplus;
@@ -1467,6 +1476,9 @@ static void debug_draw_cycles (uae_u8 *buf, int bpp, int line, int width, int he
                dr = &dma_record[t][y * NR_DMA_REC_HPOS + x];
                if (dr->reg != 0xffff && debug_colors[dr->type].enabled) {
                        c = debug_colors[dr->type].l[dr->extra];
+                       if (dr->cf_reg != 0xffff && ((cycles_toggle ^ line) & 1)) {
+                               c = debug_colors[DMARECORD_CONFLICT].l[0];
+                       }
                }
                if (dr->intlev > intlev)
                        intlev = dr->intlev;
@@ -1739,7 +1751,7 @@ static void init_heatmap(void)
                heatmap = xcalloc(struct memory_heatmap, max_heatmap / HEATMAP_DIV);
 }
 
-static void memwatch_heatmap (uaecptr addr, int rwi, int size, uae_u32 accessmask)
+static void memwatch_heatmap(uaecptr addr, int rwi, int size, uae_u32 accessmask)
 {
        if (addr >= max_heatmap || !heatmap)
                return;
@@ -1800,6 +1812,73 @@ static void memwatch_heatmap (uaecptr addr, int rwi, int size, uae_u32 accessmas
        hm->mask |= accessmask;
 }
 
+struct refdata
+{
+       uae_u32 c;
+       uae_u32 cnt;
+};
+static struct refdata refreshtable[1024];
+static int refcheck_count;
+#define REFRESH_LINES 64
+
+static void check_refreshed(void)
+{
+       int max = ecs_agnus ? 512 : 256;
+       int reffail = 0;
+       uae_u32 c = get_cycles();
+       for (int i = 0; i < max; i++) {
+               struct refdata *rd = &refreshtable[i];
+               if (rd->cnt < 10) {
+                       rd->cnt++;
+               }
+               if (rd->cnt == 10) {
+                       reffail++;
+                       rd->cnt = 0;
+               }
+               if (rd->c && (int)c - (int)rd->c >= CYCLE_UNIT * maxhpos * REFRESH_LINES) {
+                       reffail++;
+                       rd->c = 0;
+                       rd->cnt = 0;
+               }
+               if (reffail) {
+                       write_log("%03u ", i);
+               }
+       }
+       if (reffail) {
+               write_log("%d memory rows not refreshed fast enough!\n", reffail);
+       }
+}
+
+void debug_mark_refreshed(uaecptr rp)
+{
+       int ras;
+       if (ecs_agnus && currprefs.chipmem.size > 0x100000) {
+               ras = (rp >> 9) & 0x3ff;
+       } else if (ecs_agnus) {
+               ras = (rp >> 9) & 0x1ff;
+       } else {
+               ras = (rp >> 1) & 0xff;
+       }
+       struct refdata *rd = &refreshtable[ras];
+       uae_u32 c = get_cycles();
+       rd->c = c;
+       rd->cnt = 0;
+}
+
+void record_dma_hsync(void)
+{
+       if (vpos == 0) {
+               cycles_toggle = cycles_toggle ? 0 : 1;
+       }
+#if 0
+       refcheck_count++;
+       if (refcheck_count >= REFRESH_LINES / 8) {
+               refcheck_count = 0;
+               check_refreshed();
+       }
+#endif
+}
+
 void record_dma_event (uae_u32 evt, int hpos, int vpos)
 {
        struct dma_rec *dr;
@@ -1869,6 +1948,7 @@ void record_dma_write(uae_u16 reg, uae_u32 dat, uae_u32 addr, int hpos, int vpos
        dr->intlev = regs.intmask;
        dr->size = 2;
        last_dma_rec = dr;
+       debug_mark_refreshed(dr->addr);
 }
 struct dma_rec *last_dma_rec;
 void record_dma_read_value(uae_u32 v)
@@ -1893,15 +1973,39 @@ void record_dma_read_value_wide(uae_u64 v, bool quad)
                last_dma_rec->size = quad ? 8 : 4;
        }
 }
+bool record_dma_check(int hpos, int vpos)
+{
+       if (!dma_record[0]) {
+               return false;
+       }
+       if (hpos >= NR_DMA_REC_HPOS || vpos >= NR_DMA_REC_VPOS) {
+               return false;
+       }
+       struct dma_rec *dr = &dma_record[dma_record_toggle][vpos * NR_DMA_REC_HPOS + hpos];
+       return dr->reg != 0xffff;
+}
+void record_dma_clear(int hpos, int vpos)
+{
+       if (!dma_record[0]) {
+               return;
+       }
+       if (hpos >= NR_DMA_REC_HPOS || vpos >= NR_DMA_REC_VPOS) {
+               return;
+       }
+       struct dma_rec *dr = &dma_record[dma_record_toggle][vpos * NR_DMA_REC_HPOS + hpos];
+       dr->reg = 0xffff;
+       dr->cf_reg = 0xffff;
+}
+
 void record_dma_read(uae_u16 reg, uae_u32 addr, int hpos, int vpos, int type, int extra)
 {
        struct dma_rec *dr;
 
        if (!dma_record[0]) {
-               dma_record[0] = xmalloc (struct dma_rec, NR_DMA_REC_HPOS * NR_DMA_REC_VPOS);
-               dma_record[1] = xmalloc (struct dma_rec, NR_DMA_REC_HPOS * NR_DMA_REC_VPOS);
+               dma_record[0] = xmalloc(struct dma_rec, NR_DMA_REC_HPOS * NR_DMA_REC_VPOS);
+               dma_record[1] = xmalloc(struct dma_rec, NR_DMA_REC_HPOS * NR_DMA_REC_VPOS);
                dma_record_toggle = 0;
-               record_dma_reset ();
+               record_dma_reset();
                dma_record_frame[0] = -1;
                dma_record_frame[1] = -1;
        }
@@ -1926,9 +2030,9 @@ void record_dma_read(uae_u16 reg, uae_u32 addr, int hpos, int vpos, int type, in
        dr->extra = extra;
        dr->intlev = regs.intmask;
        last_dma_rec = dr;
+       debug_mark_refreshed(dr->addr);
 }
 
-
 static bool get_record_dma_info(struct dma_rec *dr, int hpos, int vpos, uae_u32 cycles, TCHAR *l1, TCHAR *l2, TCHAR *l3, TCHAR *l4, TCHAR *l5)
 {
        int longsize = dr->size;
@@ -2144,7 +2248,18 @@ static bool get_record_dma_info(struct dma_rec *dr, int hpos, int vpos, uae_u32
                }
        }
        if (l5) {
-               _stprintf (l5, _T("%08X"), cycles + (vpos * maxhpos + hpos) * CYCLE_UNIT);
+               if (dr->addr != 0xffffffff) {
+                       int ras, cas;
+                       TCHAR xtra = ' ';
+                       bool ret = get_ras_cas(dr->addr, &ras, &cas);
+                       if (ret) {
+                               xtra = '+';
+                       }
+                       _stprintf(l5, _T("%c%03X %03X"), xtra, ras, cas);
+               } else {
+                       l5[0] = 0;
+               }
+               //_stprintf (l5, _T("%08X"), cycles + (vpos * maxhpos + hpos) * CYCLE_UNIT);
        }
        if (extra64) {
                _tcscpy(l5, l4);
@@ -2163,6 +2278,8 @@ static void decode_dma_record (int hpos, int vpos, int toggle, bool logfile)
 
        if (!dma_record[0] || hpos < 0 || vpos < 0)
                return;
+       if (hpos >= NR_DMA_REC_HPOS || vpos >= NR_DMA_REC_VPOS)
+               return;
        dr_start = dr = &dma_record[dma_record_toggle ^ toggle][vpos * NR_DMA_REC_HPOS];
        if (logfile)
                write_dlog (_T("Line: %02X %3d HPOS %02X %3d:\n"), vpos, vpos, hpos, hpos);
@@ -2453,7 +2570,7 @@ static void listcheater(int mode, int size)
        if (!trainerdata)
                return;
        if (mode)
-               skip = 6;
+               skip = 4;
        else
                skip = 8;
        for(i = 0; i < totaltrainers; i++) {
@@ -3336,7 +3453,7 @@ static int memwatch_func (uaecptr addr, int rwi, int size, uae_u32 *valp, uae_u3
                if (!m->nobreak && !m->reportonly) {
                        debugging = 1;
                        debug_pc = M68K_GETPC;
-                       debug_cycles();
+                       debug_cycles(1);
                        set_special(SPCFLAG_BRK);
                }
                return 1;
@@ -4869,6 +4986,7 @@ static void breakfunc(uae_u32 v)
        debugging = 1;
        debug_vpos = -1;
        debug_hpos = -1;
+       debug_cycles(2);
        set_special(SPCFLAG_BRK);
 }
 
@@ -5431,8 +5549,8 @@ static void debug_sprite (TCHAR **inptr)
                                        int vv1 = ww1 & 1;
                                        int vv2 = ww2 & 1;
                                        int vv = vv1 * 2 + vv2;
-                                       vv1 >>= 1;
-                                       vv2 >>= 1;
+                                       ww1 >>= 1;
+                                       ww2 >>= 1;
                                        v *= 4;
                                        v += vv;
                                        tmp[width - (x + 1)] = v >= 10 ? 'A' + v - 10 : v + '0';
@@ -5785,6 +5903,7 @@ static bool debug_line (TCHAR *input)
                        } else if (more_params(&inptr)) {
                                m68k_modify(&inptr);
                        } else {
+                               custom_dumpstate(0);
                                m68k_dumpstate(&nextpc, 0xffffffff);
                        }
                }
@@ -5905,7 +6024,7 @@ static bool debug_line (TCHAR *input)
                        break;
                case 't':
                        no_trace_exceptions = 0;
-                       debug_cycles();
+                       debug_cycles(2);
                        trace_param[0] = trace_param[1] = 0;
                        if (*inptr == 't') {
                                no_trace_exceptions = 1;
@@ -5955,7 +6074,7 @@ static bool debug_line (TCHAR *input)
                        trace_mode = TRACE_MATCH_PC;
                        trace_param[0] = nextpc;
                        exception_debugging = 1;
-                       debug_cycles();
+                       debug_cycles(2);
                        return true;
 
                case 'f':
@@ -5967,14 +6086,15 @@ static bool debug_line (TCHAR *input)
                                if (process_breakpoint (&inptr))
                                        return true;
                        } else if (inptr[0] == 'c' || inptr[0] == 's') {
-                               if (cycle_breakpoint(&inptr))
+                               if (cycle_breakpoint(&inptr)) {
                                        return true;
+                               }
                        } else if (inptr[0] == 'e' && inptr[1] == 'n') {
                                break_if_enforcer = break_if_enforcer ? false : true;
                                console_out_f(_T("Break when enforcer hit: %s\n"), break_if_enforcer ? _T("enabled") : _T("disabled"));
                        } else {
                                if (instruction_breakpoint(&inptr)) {
-                                       debug_cycles();
+                                       debug_cycles(1);
                                        return true;
                                }
                        }
@@ -6323,6 +6443,7 @@ static void debug_1 (void)
 {
        TCHAR input[MAX_LINEWIDTH];
 
+       custom_dumpstate(0);
        m68k_dumpstate(&nextpc, debug_pc);
        debug_pc = 0xffffffff;
        nxdis = nextpc; nxmem = 0;
@@ -6537,7 +6658,7 @@ void debug (void)
                        }
                        if (bp > 0)
                                console_out_f(_T("Breakpoint %d triggered.\n"), bp - 1);
-                       debug_cycles();
+                       debug_cycles(1);
                }
        } else {
                memwatch_hit_msg(memwatch_triggered - 1);
@@ -6565,7 +6686,7 @@ void debug (void)
        debugmem_disable();
 
        if (trace_cycles && last_frame >= 0) {
-               if (last_frame + 2 >= timeframes) {
+               if (last_frame + 2 >= timeframes || trace_cycles > 1) {
                        console_out_f(_T("Cycles: %d Chip, %d CPU. (V=%d H=%d -> V=%d H=%d)\n"),
                                (last_cycles2 - last_cycles1) / CYCLE_UNIT,
                                (last_cycles2 - last_cycles1) / cpucycleunit,
index f29de32b6b7e79d38638a508eec2f8fb630e1d9c..76acbe5126ff781a82a19ac6651d94645eb39529 100644 (file)
@@ -674,7 +674,7 @@ uaecptr ShowEA(void *f, uaecptr pc, uae_u16 opcode, int reg, amodes mode, wordsi
 
 static const TCHAR *ccnames[] =
 {
-       _T("T "),_T("F "),_T("HI"),_T("LS"),_T("CC"),_T("CS"),_T("NE"),_T("EQ"),
+       _T("T"), _T("F"), _T("HI"),_T("LS"),_T("CC"),_T("CS"),_T("NE"),_T("EQ"),
        _T("VC"),_T("VS"),_T("PL"),_T("MI"),_T("GE"),_T("LT"),_T("GT"),_T("LE")
 };
 static const TCHAR *fpccnames[] =
@@ -1959,7 +1959,7 @@ uae_u32 m68k_disasm_2(TCHAR *buf, int bufsize, uaecptr pc, uae_u16 *bufpc, int b
                                        _tcscpy(ccpt, fpccnames[extra & 0x1f]);
                                }
                        } else {
-                               _tcsncpy(ccpt, ccnames[dp->cc], 2);
+                               _tcsncpy(ccpt, ccnames[dp->cc], _tcslen(ccnames[dp->cc]));
                                if (dp->mnemo == i_Bcc && dp->cc == 0) {
                                        _tcscpy(ccpt, _T("RA")); // BT -> BRA
                                }
index 5f0bf74506dda4828e213ede5ab05b972dece442..8e2c08613f21832856b5483b600591aa8e516fb7 100644 (file)
@@ -548,6 +548,10 @@ static void set_vblanking_limits(void)
                vblank_bottom_stop = visible_bottom_stop;
        }
 
+       if (currprefs.gfx_overscanmode == OVERSCANMODE_ULTRA) {
+               return;
+       }
+
        bool hardwired = true;
        if (ecs_agnus) {
                hardwired = (new_beamcon0 & BEAMCON0_VARVBEN) == 0;
@@ -603,6 +607,10 @@ int get_vertical_visible_height(bool useoldsize)
 
 static void set_hblanking_limits(void)
 {
+       if (currprefs.gfx_overscanmode == OVERSCANMODE_ULTRA) {
+               return;
+       }
+
        // horizontal blanking
        bool hardwired = !dp_for_drawing || !ce_is_extblankset(colors_for_drawing.extra);
        bool doblank = false;
@@ -631,7 +639,7 @@ static void set_hblanking_limits(void)
        if (doblank && programmedmode != 1) {
                // reposition to sync
                // use hardwired hblank emulation as overscan blanking.
-               if ((new_beamcon0 & (BEAMCON0_VARHSYEN | BEAMCON0_VARCSYEN)) && !hardwired) {
+               if ((new_beamcon0 & bemcon0_hsync_mask) && !hardwired) {
                        extern uae_u16 hsstrt;
                        hbstrt += (hsstrt - 18) << CCK_SHRES_SHIFT;
                        hbstop += (hsstrt - 18) << CCK_SHRES_SHIFT;
@@ -2027,8 +2035,8 @@ static void pfield_do_linetoscr_spr(int start, int stop, int blank)
        int pixel;
        if (extborder) {
                bool bb = ce_is_borderblank(colors_for_drawing.extra);
-               pfield_do_fill_line(start, stop, bb || exthblank ? 1 : 0);
-               pixel = pfield_do_linetoscr_spriteonly(src_pixel, start, stop, bb || exthblank);
+               pixel = pfield_do_linetoscr_sprite(src_pixel, start, stop);
+               pfield_do_fill_line(start, stop, bb || exthblank);
        } else {
                pixel = pfield_do_linetoscr_sprite(src_pixel, start, stop);
                if (exthblank) {
@@ -3227,7 +3235,9 @@ static void pfield_expand_dp_bplconx (int regno, int v, int hp, int vp)
                break;
        case 0x200: // hblank
                if (v) {
-                       exthblanken = true;
+                       if (currprefs.gfx_overscanmode < OVERSCANMODE_ULTRA) {
+                               exthblanken = true;
+                       }
                        if (vp >= 0) {
                                extblankcheck();
                        } else {
@@ -3751,6 +3761,7 @@ static void center_image (void)
        int w = vidinfo->drawbuffer.inwidth;
        int ew = vidinfo->drawbuffer.extrawidth;
        int maxdiw = max_diwlastword;
+
        if (currprefs.gfx_overscanmode <= OVERSCANMODE_OVERSCAN && currprefs.gfx_xcenter && !currprefs.gf[0].gfx_filter_autoscale && max_diwstop > 0) {
 
                if (max_diwstop - min_diwstart < w && currprefs.gfx_xcenter == 2)
index 166c5885f97c4c65a00e05232a26d4def5b8bb9d..fa356ef8eac65266aa43840cea1d0c2bdda04136 100644 (file)
@@ -178,6 +178,7 @@ extern int display_reset;
 
 extern unsigned long frametime, timeframes;
 extern uae_u16 htotal, vtotal, beamcon0, new_beamcon0;
+extern uae_u16 bemcon0_hsync_mask, bemcon0_vsync_mask;
 
 // 100 words give you 1600 horizontal pixels. Should be more than enough for superhires. 
 // Extreme overscan superhires needs more.
@@ -261,6 +262,8 @@ extern void getsyncregisters(uae_u16 *phsstrt, uae_u16 *phsstop, uae_u16 *pvsstr
 bool blitter_cant_access(int hpos);
 void custom_cpuchange(void);
 bool bitplane_dma_access(int hpos, int offset);
+void custom_dumpstate(int);
+bool get_ras_cas(uaecptr, int*, int*);
 
 #define RGA_PIPELINE_ADJUST 4
 #define MAX_CHIPSETSLOTS 256
index 4fb3c932758880817299125d5dfb9a9225eddedf..5c3e208ca17fdd9a2c57f3745a420627358ccc6b 100644 (file)
@@ -266,7 +266,8 @@ extern struct dma_rec *last_dma_rec;
 #define DMARECORD_BITPLANE 6
 #define DMARECORD_SPRITE 7
 #define DMARECORD_DISK 8
-#define DMARECORD_MAX 9
+#define DMARECORD_CONFLICT 9
+#define DMARECORD_MAX 10
 
 extern void record_dma_read(uae_u16 reg, uae_u32 addr, int hpos, int vpos, int type, int extra);
 extern void record_dma_write(uae_u16 reg, uae_u32 v, uae_u32 addr, int hpos, int vpos, int type, int extra);
@@ -275,6 +276,10 @@ extern void record_dma_read_value_wide(uae_u64 v, bool quad);
 extern void record_dma_replace(int hpos, int vpos, int type, int extra);
 extern void record_dma_reset(void);
 extern void record_dma_event(uae_u32 evt, int hpos, int vpos);
+extern void record_dma_clear(int hpos, int vpos);
+extern bool record_dma_check(int hpos, int vpos);
+extern void record_dma_hsync(void);
+extern void debug_mark_refreshed(uaecptr);
 extern void debug_draw(uae_u8 *buf, int bpp, int line, int width, int height, uae_u32 *xredcolors, uae_u32 *xgreencolors, uae_u32 *xbluescolors);
 
 #define TRACE_SKIP_INS 1
index cd93adecc6a441a8c080990f9994ea10342f86b8..76d9cf4c59abf0ce63cf3b971fdbc9ec7e77d4ae 100644 (file)
@@ -297,6 +297,7 @@ enum { CP_GENERIC = 1, CP_CDTV, CP_CDTVCR, CP_CD32, CP_A500, CP_A500P, CP_A600,
 #define OVERSCANMODE_OVERSCAN 3
 #define OVERSCANMODE_BROADCAST 4
 #define OVERSCANMODE_EXTREME 5
+#define OVERSCANMODE_ULTRA 6
 
 #define MAX_FILTERSHADERS 4
 
@@ -648,6 +649,7 @@ struct uae_prefs {
        int uaescsidevmode;
        bool reset_delay;
        bool crash_auto_reset;
+       int monitorblankdelay;
 
        int cs_compatible;
        int cs_ciaatod;
@@ -692,6 +694,7 @@ struct uae_prefs {
        int cs_hacks;
        int cs_ciatype[2];
        int cs_kbhandshake;
+       int cs_hvcsync;
 
        struct boardromconfig expansionboard[MAX_EXPANSION_BOARDS];
 
index 8a43bd483e40a12608ef2b2d7857b1139a1f0565..66d989d9368de2b0f76ecf8adf30a816a4a79bde 100644 (file)
@@ -98,6 +98,7 @@ extern uae_u8 *restore_custom (uae_u8 *);
 extern uae_u8 *save_custom (int *, uae_u8 *, int);
 extern uae_u8 *restore_custom_extra (uae_u8 *);
 extern uae_u8 *save_custom_extra (int *, uae_u8 *);
+extern void restore_custom_finish(void);
 
 extern uae_u8 *restore_custom_sprite (int num, uae_u8 *src);
 extern uae_u8 *save_custom_sprite (int num, int *len, uae_u8 *);
index 507a48a095264b451fe1a34183c6b642ed5d3f64..09cec340f95bb33615cf32a61d6cce50784ba9e9 100644 (file)
@@ -8397,6 +8397,7 @@ static void values_to_displaydlg (HWND hDlg)
        SendDlgItemMessage(hDlg, IDC_OVERSCANMODE, CB_ADDSTRING, 0, (LPARAM)_T("Overscan"));
        SendDlgItemMessage(hDlg, IDC_OVERSCANMODE, CB_ADDSTRING, 0, (LPARAM)_T("Overscan+"));
        SendDlgItemMessage(hDlg, IDC_OVERSCANMODE, CB_ADDSTRING, 0, (LPARAM)_T("Extreme"));
+       SendDlgItemMessage(hDlg, IDC_OVERSCANMODE, CB_ADDSTRING, 0, (LPARAM)_T("Ultra extreme debug"));
        SendDlgItemMessage(hDlg, IDC_OVERSCANMODE, CB_SETCURSEL, workprefs.gfx_overscanmode, 0);
 
        SendDlgItemMessage(hDlg, IDC_AUTORESOLUTIONSELECT, CB_RESETCONTENT, 0, 0);
@@ -8926,6 +8927,8 @@ static void values_to_chipsetdlg (HWND hDlg)
        CheckDlgButton(hDlg, IDC_BLITWAIT, workprefs.waiting_blits);
        CheckDlgButton(hDlg, IDC_KEYBOARD_CONNECTED, workprefs.keyboard_connected);
        CheckDlgButton(hDlg, IDC_SUBPIXEL, workprefs.chipset_hr);
+       SendDlgItemMessage(hDlg, IDC_CS_HVCSYNC, CB_SETCURSEL, workprefs.cs_hvcsync, 0);
+
        CheckRadioButton(hDlg, IDC_COLLISION0, IDC_COLLISION3, IDC_COLLISION0 + workprefs.collision_level);
        CheckDlgButton(hDlg, IDC_CYCLEEXACT, workprefs.cpu_cycle_exact);
        CheckDlgButton(hDlg, IDC_CYCLEEXACTMEMORY, workprefs.cpu_memory_cycle_exact);
@@ -8955,6 +8958,9 @@ static void values_from_chipsetdlg (HWND hDlg, UINT msg, WPARAM wParam, LPARAM l
        workprefs.waiting_blits = ischecked (hDlg, IDC_BLITWAIT) ? 1 : 0;
        workprefs.chipset_hr = ischecked(hDlg, IDC_SUBPIXEL);
        workprefs.keyboard_connected = ischecked(hDlg, IDC_KEYBOARD_CONNECTED) ? 1 : 0;
+       LRESULT val = SendDlgItemMessage(hDlg, IDC_CS_HVCSYNC, CB_GETCURSEL, 0, 0L);
+       if (val != CB_ERR)
+               workprefs.cs_hvcsync = val;
 
        n2 = ischecked (hDlg, IDC_CYCLEEXACTMEMORY);
        n1 = ischecked (hDlg, IDC_CYCLEEXACT);
@@ -9121,6 +9127,11 @@ static INT_PTR CALLBACK ChipsetDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPAR
                        SendDlgItemMessage(hDlg, IDC_MONITOREMU_MON, CB_ADDSTRING, 0, (LPARAM)buffer);
                }
 
+               SendDlgItemMessage(hDlg, IDC_CS_HVCSYNC, CB_RESETCONTENT, 0, 0);
+               SendDlgItemMessage(hDlg, IDC_CS_HVCSYNC, CB_ADDSTRING, 0, (LPARAM)_T("Combined"));
+               SendDlgItemMessage(hDlg, IDC_CS_HVCSYNC, CB_ADDSTRING, 0, (LPARAM)_T("Composite Sync"));
+               SendDlgItemMessage(hDlg, IDC_CS_HVCSYNC, CB_ADDSTRING, 0, (LPARAM)_T("H/V Sync"));
+
 #ifndef        AGA
                ew(hDlg, IDC_AGA, FALSE);
 #endif
index 5d7ad11dd68a7a7c4055b18efce2c4c91083b833..0c46b2cb7c0c7b859bfba31ef59cf9098281d104 100644 (file)
@@ -832,30 +832,31 @@ void savestate_restore_final(void)
 
 bool savestate_restore_finish(void)
 {
-       if (!isrestore ())
+       if (!isrestore())
                return false;
-       zfile_fclose (savestate_file);
+       zfile_fclose(savestate_file);
        savestate_file = 0;
-       restore_cpu_finish ();
-       restore_audio_finish ();
-       restore_disk_finish ();
-       restore_blitter_finish ();
+       restore_cpu_finish();
+       restore_audio_finish();
+       restore_disk_finish();
+       restore_blitter_finish();
        restore_expansion_finish();
-       restore_akiko_finish ();
+       restore_akiko_finish();
+       restore_custom_finish();
 #ifdef CDTV
-       restore_cdtv_finish ();
+       restore_cdtv_finish();
 #endif
 #ifdef PICASSO96
-       restore_p96_finish ();
+       restore_p96_finish();
 #endif
 #ifdef A2065
-       restore_a2065_finish ();
+       restore_a2065_finish();
 #endif
-       restore_cia_finish ();
+       restore_cia_finish();
 #ifdef ACTION_REPLAY
        restore_ar_finish();
 #endif
-       restore_debug_memwatch_finish ();
+       restore_debug_memwatch_finish();
        savestate_state = 0;
        init_hz_normal();
        audio_activate();
index bc010d5b256e1ede7307a280b9b8f3cac5b96c79..caca9fa8966c5342144e76fb06632416cac919b2 100644 (file)
@@ -257,7 +257,7 @@ void draw_status_line_single(int monid, uae_u8 *buf, int bpp, int y, int totalwi
                        } else {
                                int fps = (gui_data.fps + 5) / 10;
                                on_rgb = 0x000000;
-                               off_rgb = gui_data.fps_color ? 0xcccc00 : 0x000000;
+                               off_rgb = gui_data.fps_color == 1 ? 0xcccc00 : (gui_data.fps_color == 2 ? 0x0000cc : 0x000000);
                                am = 3;
                                if (fps > 999) {
                                        fps += 50;