From: Toni Wilen Date: Mon, 14 Mar 2022 16:00:53 +0000 (+0200) Subject: Refresh cycle conflict emulation, bitplane/sprite conflict special case, C/HV sync... X-Git-Tag: 41000~266 X-Git-Url: https://git.unchartedbackwaters.co.uk/w/?a=commitdiff_plain;h=c0298eea64713337f0cff7e4c2ea3ced7dd7276b;p=francis%2Fwinuae.git Refresh cycle conflict emulation, bitplane/sprite conflict special case, C/HV sync updates, extreme ultra overscan mode, CPU/chipset cycle access timing fix --- diff --git a/cfgfile.cpp b/cfgfile.cpp index 92e1c2fd..64648c2d 100644 --- a/cfgfile.cpp +++ b/cfgfile.cpp @@ -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; diff --git a/custom.cpp b/custom.cpp index 9a776a60..cec44bba 100644 --- a/custom.cpp +++ b/custom.cpp @@ -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" @@ -72,6 +73,10 @@ #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) { diff --git a/debug.cpp b/debug.cpp index d86ac6e6..21334629 100644 --- 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, diff --git a/disasm.cpp b/disasm.cpp index f29de32b..76acbe51 100644 --- a/disasm.cpp +++ b/disasm.cpp @@ -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 } diff --git a/drawing.cpp b/drawing.cpp index 5f0bf745..8e2c0861 100644 --- a/drawing.cpp +++ b/drawing.cpp @@ -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) diff --git a/include/custom.h b/include/custom.h index 166c5885..fa356ef8 100644 --- a/include/custom.h +++ b/include/custom.h @@ -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 diff --git a/include/debug.h b/include/debug.h index 4fb3c932..5c3e208c 100644 --- a/include/debug.h +++ b/include/debug.h @@ -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 diff --git a/include/options.h b/include/options.h index cd93adec..76d9cf4c 100644 --- a/include/options.h +++ b/include/options.h @@ -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]; diff --git a/include/savestate.h b/include/savestate.h index 8a43bd48..66d989d9 100644 --- a/include/savestate.h +++ b/include/savestate.h @@ -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 *); diff --git a/od-win32/win32gui.cpp b/od-win32/win32gui.cpp index 507a48a0..09cec340 100644 --- a/od-win32/win32gui.cpp +++ b/od-win32/win32gui.cpp @@ -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 diff --git a/savestate.cpp b/savestate.cpp index 5d7ad11d..0c46b2cb 100644 --- a/savestate.cpp +++ b/savestate.cpp @@ -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(); diff --git a/statusline.cpp b/statusline.cpp index bc010d5b..caca9fa8 100644 --- a/statusline.cpp +++ b/statusline.cpp @@ -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;