From a908d1510946b1c832859881a5a855f0eb566b30 Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Sat, 16 Sep 2023 19:33:54 +0300 Subject: [PATCH] chipset updates, part 1 --- custom.cpp | 880 +++++++++++++++++++++++++++------------------- debug.cpp | 48 ++- drawing.cpp | 86 +++-- events.cpp | 11 +- include/custom.h | 7 +- include/debug.h | 2 + include/drawing.h | 2 +- include/events.h | 1 + 8 files changed, 636 insertions(+), 401 deletions(-) diff --git a/custom.cpp b/custom.cpp index bdeb807f..787c04e5 100644 --- a/custom.cpp +++ b/custom.cpp @@ -73,6 +73,7 @@ #define DMAL_FIRST_HPOS 11 #define SPR_FIRST_HPOS 25 #define COPPER_CYCLE_POLARITY 0 +#define HARDWIRED_DMA_TRIGGER_HPOS 1 #define REF_RAS_ADD_AGA 0x000 #define REF_RAS_ADD_ECS 0x200 @@ -136,6 +137,7 @@ int scandoubled_line; static bool lof_lastline, lof_prev_lastline; static int lol, lol_prev; static int next_lineno; +static int linear_vpos; static enum nln_how nextline_how; static int lof_changed = 0, lof_changing = 0, interlace_changed = 0; static int lof_changed_previous_field; @@ -159,6 +161,7 @@ static evt_t line_start_cycles; static bool initial_frame; static evt_t custom_color_write_cycle; static int color_writes_num; +static bool line_equ_freerun; #define LOF_TOGGLES_NEEDED 3 //#define NLACE_CNT_NEEDED 50 @@ -309,6 +312,7 @@ int maxvpos = MAXVPOS_PAL; int maxvpos_nom = MAXVPOS_PAL; // nominal value (same as maxvpos but "faked" maxvpos in fake 60hz modes) int maxvpos_display = MAXVPOS_PAL; // value used for display size int maxhpos_display = AMIGA_WIDTH_MAX; +int maxvsize_display = AMIGA_HEIGHT_MAX; int maxvpos_display_vsync; // extra lines from top visible in bottom static int vblank_extraline; static int maxhposm1; @@ -325,6 +329,7 @@ int hsyncendpos_hw; int denisehtotal; static int maxvpos_total = 511; int minfirstline = VBLANK_ENDLINE_PAL; +int minfirstline_linear = VBLANK_ENDLINE_PAL; static int firstblankedline; static int equ_vblank_endline = EQU_ENDLINE_PAL; static bool equ_vblank_toggle = true; @@ -337,12 +342,13 @@ int doublescan; int programmedmode; frame_time_t syncbase; static int fmode_saved, fmode; -uae_u16 beamcon0, new_beamcon0, beamcon0_previous; +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; static int varsync_changed; +static uae_u16 vt_old, ht_old, hs_old, vs_old; uae_u16 vtotal, htotal; static int maxvpos_stored, maxhpos_stored; uae_u16 hsstop, hsstrt; @@ -352,7 +358,7 @@ static uae_u16 vsstop, vsstrt; static uae_u16 vbstop, vbstrt; static uae_u16 hcenter, hcenter_v2, hcenter_v2_end, hcenter_sync_v2; static bool hcenter_active; -static uae_u16 hbstop_v, hbstrt_v, hbstop_v2, hbstrt_v2, hbstop_sync_v2, hbstrt_sync_v2; +static uae_u16 hbstop_v, hbstrt_v, hbstop_v2, hbstrt_v2, hbstop_sync_v2, hbstrt_sync_v2, hbstop_reg, hbstrt_reg; static uae_u16 hsstrt_v2, hsstop_v2; static int vsstrt_m, vsstop_m, vbstrt_m, vbstop_m; static bool vb_state, vb_end_line; @@ -366,15 +372,14 @@ static int hhbpl, hhspr; static int ciavsyncmode; static int diw_hstrt, diw_hstop; static int hdiw_counter; -static uae_u16 hdiw_counter_sconflict, hdiw_counter_sconflict_mask; -static uae_u16 hdiw_counter_conflict; static int hstrobe_hdiw_min; 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_conflict2; +static bool hstrobe_conflict; +static bool vhposw_modified; static int line_disabled; static bool custom_disabled; @@ -413,7 +418,8 @@ static uae_u8 magic_sprite_mask = 0xff; static int hardwired_vbstop; -static int last_sprite_point, nr_armed; +static int last_sprite_point, last_sprite_point_abs; +static int nr_armed; static int sprite_width, sprres; static int sprite_sprctlmask; int sprite_buffer_res; @@ -454,7 +460,7 @@ int plffirstline_total, plflastline_total; int vblank_firstline_hw; static int autoscale_bordercolors; static int plfstrt, plfstop; -static int sprite_minx, sprite_maxx; +static int sprite_minx; static int first_bpl_vpos; static int last_decide_line_hpos; static int last_fetch_hpos, last_decide_sprite_hpos; @@ -462,11 +468,11 @@ static int diwfirstword, diwlastword; static int last_diwlastword; static int hb_last_diwlastword; static int last_hdiw; -static diw_states vdiwstate, hdiwstate, hdiwstate_conflict; +static diw_states vdiwstate, hdiwstate, hdiwstate_blank; static int bpl_hstart; static bool exthblank, exthblank_state, hcenterblank_state; static int hsyncdebug; -static int last_diw_hpos, last_diw_hpos2; +static int last_diw_hpos; static int last_recorded_diw_hpos; static int last_hblank_start; static int collision_hpos; @@ -613,7 +619,7 @@ struct custom_store custom_storage[256]; static int out_nbits, out_offs; static uae_u32 todisplay[MAX_PLANES], todisplay2[MAX_PLANES]; static uae_u32 outword[MAX_PLANES]; -static uae_u64 outword64[MAX_PLANES]; +static uae_u64 outword64[MAX_PLANES], outword64_extra[MAX_PLANES]; static uae_u16 fetched[MAX_PLANES]; static uae_u16 todisplay_fetched; #ifdef AGA @@ -636,7 +642,7 @@ static int toscr_delay_adjusted[2], toscr_delay_sh[2]; static bool shdelay_disabled; static int delay_cycles, delay_cycles2; static int delay_lastcycle[2], delay_hsynccycle; -static int vhposr_delay_offset, vhposr_sprite_offset; +static int vhposr_delay_offset; static bool bplcon1_written; static bool bplcon0_planes_changed; static bool sprites_enabled_this_line; @@ -652,7 +658,7 @@ static bool dmal_ce; static void update_copper(int until_hpos); static void decide_sprites_fetch(int endhpos); static void decide_line(int endhpos); -static void decide_sprites(int hpos, bool usepointx, bool quick); +static void decide_sprites(int hpos, bool quick, bool halfcycle); static void decide_sprites(int hpos); /* The number of bits left from the last fetched words. @@ -969,10 +975,23 @@ static void remember_ctable_for_border(void) remember_ctable(); } -// This does not need start line check because only OCS Denise modes use this. static int get_equ_vblank_endline(void) { - return equ_vblank_endline + (equ_vblank_toggle ? (lof_store ? 1 : 0) : 0); + if (new_beamcon0 & (BEAMCON0_BLANKEN | BEAMCON0_VARCSYEN)) { + return -1; + } + return equ_vblank_endline + (equ_vblank_toggle ? (lof_store ? 1 : 0) : 0) + (agnusa1000 ? 1 : 0); +} +static int get_equ_vblank_startline(void) +{ + if (new_beamcon0 & (BEAMCON0_BLANKEN | BEAMCON0_VARCSYEN)) { + return 30000; + } + if (agnusa1000) { + return 1; + } else { + return 0; + } } static int output_res(int res) @@ -995,7 +1014,7 @@ static void reset_bpl_vars() STATIC_INLINE bool line_hidden(void) { - return vpos >= maxvpos_display_vsync && vpos < minfirstline - 1 && currprefs.gfx_overscanmode < OVERSCANMODE_ULTRA; + return linear_vpos >= maxvpos_display_vsync && linear_vpos < minfirstline - 1 && currprefs.gfx_overscanmode < OVERSCANMODE_ULTRA; } // hblank start = enable border (bitplane not visible until next BPL1DAT).. @@ -1419,9 +1438,9 @@ static void sync_color_changes(int hpos) record_color_change2(hpos, 0xffff, 0); } -static void insert_actborder(int diw, bool onoff) +static void insert_actborder(int diw, bool onoff, bool blank) { - if (line_hidden() || custom_disabled) { + if (custom_disabled) { return; } @@ -1430,7 +1449,7 @@ static void insert_actborder(int diw, bool onoff) for (i = last_color_change; i < next_color_change; i++) { struct color_change *cc = &curr_color_changes[i]; if (cc->linepos == diw && cc->regno == 0 && (cc->value & COLOR_CHANGE_MASK) == COLOR_CHANGE_ACTBORDER) { - cc->value = COLOR_CHANGE_ACTBORDER | (onoff ? 1 : 0); + cc->value = COLOR_CHANGE_ACTBORDER | (onoff ? 1 : 0) | (blank ? 2 : 0); return; } } @@ -1449,19 +1468,20 @@ static void insert_actborder(int diw, bool onoff) struct color_change *cc = &curr_color_changes[i]; cc->linepos = diw; cc->regno = 0; - cc->value = COLOR_CHANGE_ACTBORDER | (onoff ? 1 : 0); + cc->value = COLOR_CHANGE_ACTBORDER | (onoff ? 1 : 0) | (blank ? 2 : 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) +static void hdiw_restart(int diw_last, int diw_current, bool blank) { if (diw_last >= diw_current || line_hidden() || custom_disabled) { return; } // update state diw_current = adjust_hr(diw_current); + diw_last = adjust_hr(diw_last); record_color_change2(-diw_current, 0xffff, 0); // find slot to insert into @@ -1480,90 +1500,63 @@ static void hdiw_restart(int diw_last, int diw_current) struct color_change *cc = &curr_color_changes[i]; cc->linepos = diw_last; cc->regno = 0; - cc->value = COLOR_CHANGE_ACTBORDER | 1; + cc->value = COLOR_CHANGE_ACTBORDER | 1 | (blank ? 2 : 0); next_color_change++; record_color_change2(-diw_current, 0, COLOR_CHANGE_ACTBORDER | 0); } -static void decide_hstrobe_hdiw(int hpos) -{ - int off = hdiw_counter_conflict; - - hpos += hpos_hsync_extra; - if (hpos <= hstrobe_hdiw_min) { - return; - } - - int max = (hpos * 2 + 1) << 2; - int min = (hstrobe_hdiw_min * 2 + 1) << 2; - - int hdiw1 = (diw_hstrt - off) & ((512 << 2) - 1); - int hdiw2 = (diw_hstop - off) & ((512 << 2) - 1); - - hdiw1 = adjust_hr(hdiw1); - hdiw2 = adjust_hr(hdiw2); - - max = adjust_hr(max); - min = adjust_hr(min); +/* Called to determine the state of the horizontal display window state +* machine at the current position. It might have changed since we last +* checked. */ - if (hdiw1 < min) { - hdiw1 = min; - } - if (hdiw2 < min) { - hdiw2 = min; - } - if (hdiw1 > max) { - hdiw1 = max; - } - if (hdiw2 > max) { - hdiw2 = max; - } +static int hdiw_denisecounter, hdiw_denisecounter_abs, hdiw_denisecounter_reset; - if (hdiw1 < hdiw2) { - if (hdiw1 > min && hdiwstate_conflict == diw_states::DIW_waiting_start) { - insert_actborder(min, true); - insert_actborder(hdiw1, false); - hdiwstate_conflict = diw_states::DIW_waiting_stop; - } - if (hdiw2 < max && hdiwstate_conflict == diw_states::DIW_waiting_stop) { - insert_actborder(hdiw2, true); - insert_actborder(max, false); +// hblank start +static void decide_hdiw_blank_check_start(int hpos, int start_diw_hpos, int end_diw_hpos) +{ + if (hdiwstate_blank == diw_states::DIW_waiting_start) { + if (hbstrt_reg >= start_diw_hpos && hbstrt_reg < end_diw_hpos) { + int val = hdiw_denisecounter_abs + (hbstrt_reg - start_diw_hpos); + insert_actborder(val, true, true); + MARK_LINE_CHANGED; + hdiwstate_blank = diw_states::DIW_waiting_stop; } - } else if (hdiw1 > hdiw2) { - insert_actborder(hdiw2, true); - insert_actborder(hdiw1, false); - hdiwstate_conflict = diw_states::DIW_waiting_stop; } - - hstrobe_hdiw_min = hpos; } - -static void decide_conflict_hdiw(int hpos) +// hblank end +static void decide_hdiw_blank_check_stop(int hpos, int start_diw_hpos, int end_diw_hpos) { - if (hstrobe_conflict) { - decide_hstrobe_hdiw(hpos); + if (hdiwstate_blank == diw_states::DIW_waiting_stop) { + if (hbstop_reg >= start_diw_hpos && hbstop_reg < end_diw_hpos) { + int val = hdiw_denisecounter_abs + (hbstop_reg - start_diw_hpos); + insert_actborder(val, false, true); + MARK_LINE_CHANGED; + hdiwstate_blank = diw_states::DIW_waiting_start; + } } } - -/* Called to determine the state of the horizontal display window state -* machine at the current position. It might have changed since we last -* checked. */ - -static void decide_hdiw_check_start(int start_diw_hpos, int end_diw_hpos, int extrahpos) +// hdiw open +static void decide_hdiw_check_start(int start_diw_hpos, int end_diw_hpos) { if (hdiwstate == diw_states::DIW_waiting_start) { - if (diw_hstrt > start_diw_hpos && diw_hstrt < end_diw_hpos && !hstrobe_conflict) { - int first = diwfirstword + extrahpos; + if (diw_hstrt >= start_diw_hpos && diw_hstrt < end_diw_hpos) { + int val = hdiw_denisecounter_abs + (diw_hstrt - start_diw_hpos); + int first = coord_diw_shres_to_window_x(val); if (last_diwlastword >= 0) { - int first2 = first * 2; - first2 = adjust_hr(first2); - // was closed previously in same line: blank closed part. - hdiw_restart(last_diwlastword, first2); + // was closed previously in same line: fill closed part using color0. + if (denisea1000) { + last_diwlastword += 4 << shres_shift; + if (last_diwlastword < val) { + hdiw_restart(last_diwlastword, val, false); + } + } else { + hdiw_restart(last_diwlastword, val, false); + } last_diwlastword = -1; #ifdef DEBUGGER if (debug_dma) { - record_dma_event(DMA_EVENT_HDIWS, diw_to_hpos(first2), vpos); + record_dma_event(DMA_EVENT_HDIWS, diw_to_hpos(val), vpos); } #endif } @@ -1583,16 +1576,17 @@ static void decide_hdiw_check_start(int start_diw_hpos, int end_diw_hpos, int ex } } } -static void decide_hdiw_check_stop(int start_diw_hpos, int end_diw_hpos, int extrahpos) +// hdiw close +static void decide_hdiw_check_stop(int start_diw_hpos, int end_diw_hpos) { if (hdiwstate == diw_states::DIW_waiting_stop) { - if (diw_hstop > start_diw_hpos && diw_hstop <= end_diw_hpos && !hstrobe_conflict) { - int last = diwlastword + extrahpos; + if (diw_hstop >= start_diw_hpos && diw_hstop < end_diw_hpos) { + int val = hdiw_denisecounter_abs + (diw_hstop - start_diw_hpos); + int last = coord_diw_shres_to_window_x(val); if (last > thisline_decision.diwlastword) { thisline_decision.diwlastword = adjust_hr2(last); // if HDIW opens again in same line - int v = thisline_decision.diwlastword * 2; - last_diwlastword = adjust_hr(v); + last_diwlastword = val; #ifdef DEBUGGER if (debug_dma) { record_dma_event(DMA_EVENT_HDIWE, diw_to_hpos(last), vpos); @@ -1604,52 +1598,101 @@ static void decide_hdiw_check_stop(int start_diw_hpos, int end_diw_hpos, int ext } } -static void decide_hdiw_check(int start_diw_hpos, int end_diw_hpos, int extrahpos) +static void decide_hdiw_check(int hpos, int start_diw_hpos, int end_diw_hpos) { - if (diw_hstrt < diw_hstop) { - decide_hdiw_check_start(start_diw_hpos, end_diw_hpos, extrahpos); - decide_hdiw_check_stop(start_diw_hpos, end_diw_hpos, extrahpos); + if ((diw_hstrt >= start_diw_hpos && diw_hstrt < end_diw_hpos) && + (diw_hstop >= start_diw_hpos && diw_hstop < end_diw_hpos)) { + if (diw_hstrt > diw_hstop) { + decide_hdiw_check_stop(start_diw_hpos, end_diw_hpos); + decide_hdiw_check_start(start_diw_hpos, end_diw_hpos); + } else { + decide_hdiw_check_start(start_diw_hpos, end_diw_hpos); + decide_hdiw_check_stop(start_diw_hpos, end_diw_hpos); + } } else { - decide_hdiw_check_stop(start_diw_hpos, end_diw_hpos, extrahpos); - decide_hdiw_check_start(start_diw_hpos, end_diw_hpos, extrahpos); + decide_hdiw_check_start(start_diw_hpos, end_diw_hpos); + decide_hdiw_check_stop(start_diw_hpos, end_diw_hpos); } + // check also hblank if there is chance it has been moved to visible area + static bool xcv = true; + if (xcv && 1) { + if (hstrobe_conflict || vhposw_modified) { + decide_hdiw_blank_check_start(hpos, start_diw_hpos, end_diw_hpos); + } + if (hdiwstate_blank == diw_states::DIW_waiting_stop) { + decide_hdiw_blank_check_stop(hpos, start_diw_hpos, end_diw_hpos); + } + } + hdiw_denisecounter_abs += end_diw_hpos - start_diw_hpos; } -static void decide_hdiw(int hpos) +static void decide_hdiw2(int hpos, bool halfcycle) { - /* 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 - (PAL) or lines 0 to 10 (NTSC). A1000 PAL: 1 to 9, NTSC: 1 to 10. - ECS Denise and AGA: no above "features" - */ - - int hpos2 = hpos + (hpos_hsync_extra ? 0 : hsyncstartpos_start_cycles); - if (hpos2 <= last_diw_hpos2) { + int hp = (hpos << 1) + halfcycle; // cck->lores + int c = (hp - last_diw_hpos) << (CCK_SHRES_SHIFT - 1); // ->shres + if (c <= 0) { return; } - int start_diw_hpos = ((last_diw_hpos * 2 - DDF_OFFSET + 1) << 2) + 3; - int end_diw_hpos = ((hpos * 2 + 1) << 2) + 3; - // should handle wrap around.. - if (start_diw_hpos < ((1 << 2) + 3)) { - start_diw_hpos = (1 << 2) + 3; + if (last_diw_hpos < (HARDWIRED_DMA_TRIGGER_HPOS << 1) && hp >= (HARDWIRED_DMA_TRIGGER_HPOS << 1)) { + hdiw_denisecounter_reset = (REFRESH_FIRST_HPOS - HARDWIRED_DMA_TRIGGER_HPOS + 3) << CCK_SHRES_SHIFT; + //hdiw_denisecounter_reset += 1 << (CCK_SHRES_SHIFT - 1); } - int extrahpos = coord_diw_shres_to_window_x(hpos_hsync_extra << CCK_SHRES_SHIFT); - if (!ecs_denise && vpos <= get_equ_vblank_endline()) { - // free running horizontal counter - start_diw_hpos = (hdiw_counter & 511) << 2; - end_diw_hpos = start_diw_hpos + end_diw_hpos; - 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_hdiw_check(start_diw_hpos, end_diw_hpos, extrahpos); + int start = hdiw_denisecounter; + int max = 512 << (CCK_SHRES_SHIFT - 1); + + if (hdiw_denisecounter_reset > 0 && c >= hdiw_denisecounter_reset && !line_equ_freerun && !hstrobe_conflict) { + // strobe crossed? + hdiw_denisecounter += hdiw_denisecounter_reset; + decide_hdiw_check(hpos, start, hdiw_denisecounter); + hdiw_denisecounter = 2 << LORES_TO_SHRES_SHIFT; + start = hdiw_denisecounter; + hdiw_denisecounter += c - hdiw_denisecounter_reset; + decide_hdiw_check(hpos, start, hdiw_denisecounter); + hdiw_denisecounter_reset = -1; + } else { + hdiw_denisecounter += c; + // wrap around? + if (hdiw_denisecounter >= max) { + decide_hdiw_check(hpos, start, max); + hdiw_denisecounter &= max - 1; + if (hdiw_denisecounter > 0) { + decide_hdiw_check(hpos, 0, hdiw_denisecounter); + } + } else { + decide_hdiw_check(hpos, start, hdiw_denisecounter); } + if (hdiw_denisecounter_reset >= 0) { + hdiw_denisecounter_reset -= c; + } + } + + last_diw_hpos = hp; +} + +static void decide_hdiw(int hpos, bool halfcycle = false) +{ +#ifdef DEBUGGER + if (!debug_dma) { + decide_hdiw2(hpos, halfcycle); } else { - decide_hdiw_check(start_diw_hpos, end_diw_hpos, extrahpos); + for (int i = (last_diw_hpos >> 1); i <= hpos; i++) { + decide_hdiw2(i, halfcycle); + halfcycle = false; + record_dma_denise(i, hdiw_denisecounter >> 2); + } } - last_diw_hpos = hpos; - last_diw_hpos2 = hpos2; +#else + decide_hdiw2(hpos); +#endif +} + +static void sync_changes(int hpos) +{ + decide_hdiw(hpos); + decide_sprites(hpos); + record_color_change2(hpos, 0xffff, 0); + } static int fetchmode, fetchmode_size, fetchmode_mask, fetchmode_bytes; @@ -1925,7 +1968,7 @@ static void estimate_last_fetch_cycle(int hpos) } else { #if OPTIMIZED_ESTIMATE - if (estimated_bplcon0 == bplcon0 && plfstrt == hpos && estimated_plfstrt == plfstrt && estimated_plfstop == plfstop && estimated_fm == fetchmode) { + if (estimated_bplcon0 == bplcon0 && bpl_hstart == hpos && estimated_plfstrt == bpl_hstart && estimated_plfstop == plfstop && estimated_fm == fetchmode) { if (maxhpos == estimated_maxhpos[0]) { estimated_cycles = estimated_cycles_buf0; return; @@ -2035,7 +2078,7 @@ static void estimate_last_fetch_cycle(int hpos) } } #if OPTIMIZED_ESTIMATE - if (estimated_empty && plfstrt == hpos && !ddf_stopping) { + if (estimated_empty && bpl_hstart == hpos && !ddf_stopping) { estimated_empty = false; // zero rest of buffer if (end_pos != start_pos2) { @@ -2047,7 +2090,7 @@ static void estimate_last_fetch_cycle(int hpos) } } estimated_bplcon0 = bplcon0; - estimated_plfstrt = plfstrt; + estimated_plfstrt = bpl_hstart; estimated_plfstop = plfstop; estimated_fm = fetchmode; estimated_maxhpos[maxhposeven] = maxhpos; @@ -2190,7 +2233,6 @@ static void set_chipset_mode(void) refmask >>= 1; } } - hdiw_counter_sconflict_mask = (512 << sprite_buffer_res) - 1; calcdiw(); } @@ -2200,6 +2242,10 @@ static void update_mirrors(void) ecs_agnus = (currprefs.chipset_mask & CSMASK_ECS_AGNUS) != 0; ecs_denise = (currprefs.chipset_mask & CSMASK_ECS_DENISE) != 0; agnusa1000 = currprefs.cs_agnusmodel == AGNUSMODEL_A1000 || currprefs.cs_agnusmodel == AGNUSMODEL_VELVET; + if (agnusa1000) { + ecs_agnus = false; + aga_mode = false; + } denisea1000_noehb = currprefs.cs_denisemodel == DENISEMODEL_VELVET || currprefs.cs_denisemodel == DENISEMODEL_A1000NOEHB; denisea1000 = currprefs.cs_denisemodel == DENISEMODEL_VELVET || currprefs.cs_denisemodel == DENISEMODEL_A1000NOEHB || currprefs.cs_denisemodel == DENISEMODEL_A1000; direct_rgb = aga_mode; @@ -2458,9 +2504,9 @@ static uae_u16 get_strobe_reg(int slot) uae_u16 strobe = 0x1fe; if (slot == 0) { strobe = 0x3c; - if (vb_state && vpos < equ_vblank_endline) { + if (vb_start_line > 1 && vpos < get_equ_vblank_endline() && vpos >= get_equ_vblank_startline()) { strobe = 0x38; - } else if (vb_state) { + } else if (vb_start_line > 1 || vb_end_line || vb_end_next_line) { strobe = 0x3a; } } else if (slot == 1 && ecs_agnus && lol) { @@ -2767,22 +2813,8 @@ static void fetch_strobe_conflict(int nr, int fm, int hpos, bool addmodulo) // decide sprites before sprite offset change decide_sprites(hpos + 1); - if (!hstrobe_conflict) { - hdiwstate_conflict = hdiwstate; - } - - hdiw_counter_sconflict += (512 - ((maxhpos * 2 + 1) - 1)) << sprite_buffer_res; - hdiw_counter_sconflict &= hdiw_counter_sconflict_mask; - - if (hstrobe_conflict) { - hdiw_counter_conflict += ((maxhpos * 2 + 1) - 1) << 2; - } - hdiw_counter_conflict &= (512 << 2) - 1; - - hstrobe_conflict2 = true; hstrobe_conflict = true; - SET_LINE_CYCLEBASED(hpos); } @@ -3238,18 +3270,11 @@ static void pull_toscr_output_bits(int nbits, int planes, uae_u32 *ptrs) return; } int tbits = nbits - out_nbits; - uae_u64 tmask = (1 << tbits) - 1; uae_u64 nmask = (1 << out_nbits) - 1; - uae_u8 *dataptr = line_data[next_lineno] + (out_offs - 2) * 4; for (int i = 0; i < planes; i++) { ptrs[i] = 0; - if (out_offs >= 2) { - uae_u64 *dataptr64 = (uae_u64*)dataptr; - uae_u64 vv = *dataptr64; - uae_u64 v = (vv >> 32) | (vv << 32); - ptrs[i] = (uae_u32)((v << out_nbits) & mask); - dataptr += MAX_WORDS_PER_LINE * 2; - } + uae_u64 v = outword64_extra[i]; + ptrs[i] = (uae_u32)((v << out_nbits) & mask); ptrs[i] |= outword64[i] & nmask; } } @@ -3267,21 +3292,13 @@ static void push_toscr_output_bits(int nbits, int planes, uae_u32 *ptrs) int tbits = nbits - out_nbits; uae_u64 tmask = (1 << tbits) - 1; uae_u64 nmask = (1 << out_nbits) - 1; - uae_u8 *dataptr = line_data[next_lineno] + (out_offs - 2) * 4; for (int i = 0; i < planes; i++) { - if (out_offs >= 2) { - uae_u64 *dataptr64 = (uae_u64*)dataptr; - uae_u64 vv = *dataptr64; - uae_u64 v = (vv >> 32) | (vv << 32); - v &= ~tmask; - v |= (ptrs[i] >> out_nbits) & tmask; - vv = (v >> 32) | (v << 32); - *dataptr64 = vv; - dataptr += MAX_WORDS_PER_LINE * 2; - } + uae_u64 v = outword64_extra[i]; + v &= ~tmask; + v |= (ptrs[i] >> out_nbits) & tmask; + outword64_extra[i] = v; outword64[i] &= ~nmask; outword64[i] |= ptrs[i] & nmask; - thisline_changed = 1; } } @@ -3291,7 +3308,10 @@ STATIC_INLINE void toscr_1_hr_nbits(void) uae_u8 *dataptr = line_data[next_lineno] + out_offs * 4; for (int i = 0; i < toscr_nr_planes2; i++) { uae_u64 *dataptr64 = (uae_u64 *)dataptr; - uae_u64 v = (outword64[i] >> 32) | (outword64[i] << 32); + uae_u64 v = outword64[i]; +// uae_u64 v = outword64_extra[i]; +// outword64_extra[i] = outword64[i]; + v = (v >> 32) | (v << 32); if (thisline_changed || *dataptr64 != v) { thisline_changed = 1; *dataptr64 = v; @@ -4209,7 +4229,7 @@ static void hbstrt_bordercheck(int hpos, bool early) } pos -= 2; // 1 hires pixel early pos = adjust_hr(pos); - hdiw_restart(hb_last_diwlastword, pos); + hdiw_restart(hb_last_diwlastword, pos, false); hb_last_diwlastword = -1; } @@ -4278,7 +4298,7 @@ static void beginning_of_plane_block(int hpos) // do not mistake end of bitplane as start of low value hblank programmed mode if (bpl_shifter <= 0 && hpos > REFRESH_FIRST_HPOS) { - if (ecs_denise || hpos >= OCS_DENISE_HBLANK_DISABLE_HPOS + 1 || hdiwstate == diw_states::DIW_waiting_stop) { + if (ecs_denise || hpos >= OCS_DENISE_HBLANK_DISABLE_HPOS || hdiwstate == diw_states::DIW_waiting_stop) { start_noborder(hpos + hpos_hsync_extra); } } @@ -5137,11 +5157,13 @@ static void record_color_change(int hpos, int regno, uae_u32 value) { if (regno < RECORDED_REGISTER_CHANGE_OFFSET && nodraw()) return; + + decide_hdiw(hpos); + /* vsync period don't appear on-screen. */ if (line_hidden()) return; - decide_hdiw(hpos); decide_line(hpos); if (thisline_decision.ctable < 0) { @@ -5690,13 +5712,9 @@ static void add_sprite(int *countp, int num, int sprxp, int posns[], int nrs[]) static void calcsprite(void) { sprite_minx = 0; - sprite_maxx = -1; if (thisline_decision.diwfirstword >= 0) { sprite_minx = tospritexdiw(thisline_decision.diwfirstword); } - if (thisline_decision.diwlastword >= 0) { - sprite_maxx = tospritexdiw(thisline_decision.diwlastword); - } if (thisline_decision.plfleft >= 0) { int min = tospritexddf(thisline_decision.plfleft); int max = tospritexddf(thisline_decision.plfright); @@ -5711,42 +5729,25 @@ static void calcsprite(void) } } -static void decide_sprites(int hpos, bool usepointx, bool quick) +static int last_sprite_hpos, last_sprite_hpos_reset; + +static void decide_sprites2(int start, int end, int *countp, int *nrs, int *posns) { - int nrs[MAX_SPRITES * 2], posns[MAX_SPRITES * 2]; - int count; - int point; + int count = *countp; 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 - - point = (hpos + hpos_hsync_extra) * 2 - DDF_OFFSET; - - if (point <= last_sprite_point) { - return; - } if (nodraw() || nr_armed == 0) { - last_sprite_point = point; return; } - if (!quick) { - decide_hdiw(hpos); - decide_line(hpos); - calcsprite(); - } - - count = 0; for (int i = 0; i < MAX_SPRITES; i++) { struct sprite *s = &spr[i]; - int xpos = (spr[i].xpos + hdiw_counter_sconflict + vhposr_sprite_offset) & hdiw_counter_sconflict_mask; + int xpos = spr[i].xpos; 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) { continue; } @@ -5769,42 +5770,113 @@ static void decide_sprites(int hpos, bool usepointx, bool quick) hw_xp = sprxp >> sprite_buffer_res; } - if ((hw_xp > 0 || hdiw_counter_sconflict) && hw_xp > last_sprite_point && hw_xp <= point + pointx) { - add_sprite(&count, i, sprxp, posns, nrs); + if (hw_xp >= start && hw_xp < end) { + int xdiff = hw_xp - start; + int sprxp_abs = (last_sprite_point_abs + xdiff) << sprite_buffer_res; + // add hires/shres back + sprxp_abs |= xpos & (3 >> (RES_MAX - sprite_buffer_res)); + add_sprite(&count, i, sprxp_abs, posns, nrs); } /* SSCAN2-bit is fun.. */ - if ((fmode & 0x8000) && !(sprxp & sscanmask)) { + if (1 && (fmode & 0x8000) && !(sprxp & sscanmask)) { sprxp |= sscanmask; hw_xp = sprxp >> sprite_buffer_res; - if (hw_xp > last_sprite_point && hw_xp <= point + pointx) { - add_sprite(&count, MAX_SPRITES + i, sprxp, posns, nrs); + if (hw_xp >= start && hw_xp < end) { + int xdiff = hw_xp - start; + int sprxp_abs = (last_sprite_point_abs + xdiff) << sprite_buffer_res; + sprxp_abs |= xpos & (3 >> (RES_MAX - sprite_buffer_res)); + add_sprite(&count, MAX_SPRITES + i, sprxp_abs, posns, nrs); } - } else if (xpos >= (2 << sprite_buffer_res) && xpos <= (extrahpos << sprite_buffer_res)) { - // right border wrap around. SPRxCTL horizontal bits do not matter. - sprxp += (maxhpos * 2) << sprite_buffer_res; - hw_xp = sprxp >> sprite_buffer_res; - if (hw_xp > last_sprite_point && hw_xp <= point + pointx) { - add_sprite(&count, MAX_SPRITES + i, sprxp, posns, nrs); + } + } + *countp = count; + + +} + +static void decide_sprites(int hpos, bool quick, bool halfcycle = false) +{ + int count = 0; + int gotdata = 0; + int nrs[MAX_SPRITES * 2], posns[MAX_SPRITES * 2]; + int hp = (hpos << 1) + halfcycle; + + // don't bother with sprites during vblank lines + if (vb_start_line > 1) { + last_sprite_hpos = hp; + return; + } + + int c = hp - last_sprite_hpos; + if (c <= 0) { + return; + } + + if (!quick) { + decide_hdiw(hpos); + decide_line(hpos); + calcsprite(); + } + + if (last_sprite_hpos < (HARDWIRED_DMA_TRIGGER_HPOS << 1) && hp >= (HARDWIRED_DMA_TRIGGER_HPOS << 1)) { + last_sprite_hpos_reset = (REFRESH_FIRST_HPOS - HARDWIRED_DMA_TRIGGER_HPOS + 2) << 1; + last_sprite_hpos_reset += 1; + } + + int start = last_sprite_point; + int max = 512; + + if (last_sprite_hpos_reset > 0 && c >= last_sprite_hpos_reset && !line_equ_freerun && !hstrobe_conflict) { + // strobe crossed? + last_sprite_point += last_sprite_hpos_reset + 0; + decide_sprites2(start, last_sprite_point, &count, nrs, posns); + last_sprite_point_abs += last_sprite_point - start; + last_sprite_point = 2; + start = last_sprite_point; + last_sprite_point += c - last_sprite_hpos_reset; + decide_sprites2(start, last_sprite_point, &count, nrs, posns); + last_sprite_point_abs += last_sprite_point - start; + last_sprite_hpos_reset = -1; + } else { + last_sprite_point += c; + // wrap around? + if (last_sprite_point >= max) { + decide_sprites2(start, max, &count, nrs, posns); + last_sprite_point_abs += max - start; + last_sprite_point &= max - 1; + if (last_sprite_point > 0) { + decide_sprites2(0, last_sprite_point, &count, nrs, posns); + last_sprite_point_abs += last_sprite_point - 0; } - // (not really mutually exclusive of SSCAN2-bit but not worth the trouble) + } else { + decide_sprites2(start, last_sprite_point, &count, nrs, posns); + last_sprite_point_abs += last_sprite_point - start; + } + if (last_sprite_hpos_reset >= 0) { + last_sprite_hpos_reset -= c; } } + last_sprite_hpos = hp; + for (int i = 0; i < count; i++) { int nr = nrs[i] & (MAX_SPRITES - 1); struct sprite *s = &spr[nr]; + + // ECS Denise weird behavior in shres if (s->ecs_denise_hires && !(bplcon0d & 0x40)) { s->data[0] &= 0x7fff; s->datb[0] &= 0x7fff; } + record_sprite(nr, posns[i], s->data, s->datb, s->ctl); /* get left and right sprite edge if brdsprt enabled */ #if AUTOSCALE_SPRITES - if (dmaen (DMA_SPRITE) && brdspractive() && !(bplcon3 & 0x20) && nr > 0) { + if (dmaen(DMA_SPRITE) && brdspractive() && !(bplcon3 & 0x20) && nr > 0) { int j, jj; - for (j = 0, jj = 0; j < sprite_width; j+= 16, jj++) { + for (j = 0, jj = 0; j < sprite_width; j += 16, jj++) { int nx = fromspritexdiw(posns[i] + j); if (s->data[jj] || s->datb[jj]) { if (diwfirstword_total > nx && nx >= (48 << currprefs.gfx_resolution)) { @@ -5818,11 +5890,8 @@ static void decide_sprites(int hpos, bool usepointx, bool quick) gotdata = 1; } #endif - } - last_sprite_point = point; - #if AUTOSCALE_SPRITES /* get upper and lower sprite position if brdsprt enabled */ if (gotdata) { @@ -5841,6 +5910,7 @@ static void decide_sprites(int hpos, bool usepointx, bool quick) } #endif } + static void decide_sprites(int hpos) { decide_sprites(hpos, false, false); @@ -5926,19 +5996,12 @@ static void hstrobe_conflict_check(uae_u32 v) // not conflict? if (!(datreg & CYCLE_PIPE_BITPLANE)) { hstrobe_conflict = false; - hdiw_counter_conflict += ((maxhpos * 2 + 1) - 1) << 2; - hdiw_counter_conflict &= (512 << 2) - 1; - decide_hstrobe_hdiw(hpos); - hdiwstate = hdiwstate_conflict; - decide_hdiw(hpos); - hdiw_counter_sconflict = 0; - hdiw_counter_conflict = 0; - flush_display(fetchmode); - delay_cycles = (2 + 2) << LORES_TO_SHRES_SHIFT; + int pos = hpos_to_diwx(hpos); + addcc(pos, 0, COLOR_CHANGE_ACTBORDER | 2); + MARK_LINE_CHANGED; } } - static void finish_decisions(int hpos) { struct amigadisplay *ad = &adisplays[0]; @@ -5958,10 +6021,12 @@ static void finish_decisions(int hpos) thisline_decision.bplres = output_res(RES_LORES); } +#if 0 if (hstrobe_conflict) { sync_color_changes(hpos + DDF_OFFSET / 2 + 1); decide_hstrobe_hdiw(hpos); } +#endif // Add DDF_OFFSET to detect blanking changes past hpos max sync_color_changes(hpos + DDF_OFFSET / 2 + 1); @@ -5973,8 +6038,6 @@ static void finish_decisions(int hpos) thisline_decision.diwlastword = max_diwlastword; } - last_diwlastword = -1; - if (thisline_decision.diwfirstword != line_decisions[next_lineno].diwfirstword) { MARK_LINE_CHANGED; } @@ -6048,7 +6111,6 @@ static void reset_decisions_scanline_start(void) return; if (hstrobe_conflict) { - hstrobe_conflict2 = false; event2_newevent_xx(-1, REFRESH_FIRST_HPOS * CYCLE_UNIT, 0, hstrobe_conflict_check); } @@ -6059,7 +6121,8 @@ static void reset_decisions_scanline_start(void) ddfstrt_hpos = -1; ddfstop_hpos = -1; last_diw_hpos = 0; - last_diw_hpos2 = 0; + last_sprite_hpos = 0; + last_sprite_hpos_reset = 0; blt_info.finishhpos = -1; /* Default to no bitplane DMA overriding sprite DMA */ @@ -6136,6 +6199,8 @@ static void reset_decisions_hsync_start(void) return; } + int hpos = current_hpos(); + thisline_decision.diwfirstword = -1; thisline_decision.diwlastword = -1; // hdiw already open? @@ -6153,8 +6218,9 @@ static void reset_decisions_hsync_start(void) last_color_change = next_color_change; curr_drawinfo[next_lineno].first_sprite_entry = next_sprite_entry; next_sprite_forced = 1; + last_sprite_point_abs = ((1 + (hpos - REFRESH_FIRST_HPOS - 2)) << 1) + 1; + hdiw_denisecounter_abs = ((1 + (hpos - REFRESH_FIRST_HPOS - 2)) << CCK_SHRES_SHIFT) + 0; - last_sprite_point = 0; sprites_enabled_this_line = false; bpl1mod_hpos = -1; bpl2mod_hpos = -1; @@ -6162,7 +6228,7 @@ static void reset_decisions_hsync_start(void) collision_hpos = 0; vhposr_delay_offset = 0; - vhposr_sprite_offset = 0; + vhposw_modified = false; compute_toscr_delay(bplcon1); @@ -6220,6 +6286,7 @@ static void reset_decisions_hsync_start(void) } else { thisline_decision.vb = vb_start_line >= 2 + vblank_extraline || vb_end_next_line ? 0 : VB_NOVB; } + // if programmed vblank if ((new_beamcon0 & BEAMCON0_VARVBEN) && ecs_agnus) { if (!thisline_decision.vb) { @@ -6284,7 +6351,6 @@ static void reset_decisions_hsync_start(void) thisline_decision.max_planes = toscr_nr_planes2 > toscr_nr_planes_agnus ? toscr_nr_planes2 : toscr_nr_planes_agnus; hpos_hsync_extra = 0; - int hpos = current_hpos(); bool normalstart = true; plane0p_enabled = ecs_denise && (bplcon0 & 1) && (bplcon3 & 0x20); plane0p_forced = false; @@ -6389,6 +6455,7 @@ static void reset_decisions_hsync_start(void) //memset(todisplay_aga, 0, sizeof todisplay_aga); memset(todisplay2_aga, 0, sizeof todisplay2_aga); memset(outword64, 0, sizeof outword64); + memset(outword64_extra, 0, sizeof outword64_extra); } #endif } @@ -6468,7 +6535,7 @@ void compute_vsynctime(void) void getsyncregisters(uae_u16 *phsstrt, uae_u16 *phsstop, uae_u16 *pvsstrt, uae_u16 *pvsstop) { *phsstrt = hsstrt; - *phsstop = hsstop_detect * 2; + *phsstop = hsstop_detect2 / 2; *pvsstrt = vsstrt; *pvsstop = vsstop; } @@ -6581,11 +6648,11 @@ static void updateextblk(void) // hblank has 1 lores pixel offset hbstrt_v2 = hbstrt_v - 4; if (hbstrt_v >= (1 << CCK_SHRES_SHIFT) && hbstrt_v2 < (1 << CCK_SHRES_SHIFT)) { - hbstrt_v2 += maxhpos << CCK_SHRES_SHIFT; + hbstrt_v2 += maxhpos_short << CCK_SHRES_SHIFT; } hbstop_v2 = hbstop_v - 4; if (hbstop_v >= (1 << CCK_SHRES_SHIFT) && hbstop_v2 < (1 << CCK_SHRES_SHIFT)) { - hbstop_v2 += maxhpos << CCK_SHRES_SHIFT; + hbstop_v2 += maxhpos_short << CCK_SHRES_SHIFT; } exthblank = (bplcon0 & 1) && (bplcon3 & 1); } else { @@ -6614,10 +6681,10 @@ static void updateextblk(void) hbstrt_v2 -= 4; hbstop_v2 -= 4; if (hbstrt_v >= (1 << CCK_SHRES_SHIFT) && hbstrt_v2 < (1 << CCK_SHRES_SHIFT)) { - hbstrt_v2 += maxhpos << CCK_SHRES_SHIFT; + hbstrt_v2 += maxhpos_short << CCK_SHRES_SHIFT; } if (hbstop_v >= (1 << CCK_SHRES_SHIFT) && hbstop_v2 < (1 << CCK_SHRES_SHIFT)) { - hbstop_v2 += maxhpos << CCK_SHRES_SHIFT; + hbstop_v2 += maxhpos_short << CCK_SHRES_SHIFT; } exthblank = (bplcon0 & 1) && (bplcon3 & 1); } @@ -6629,25 +6696,29 @@ static void updateextblk(void) hbstop_v2 = adjust_hr(hbstop_v2); } - if (new_beamcon0 & bemcon0_hsync_mask) { + hbstrt_reg = hbstrt_v2; + hbstop_reg = hbstop_v2; + + if ((new_beamcon0 & bemcon0_hsync_mask) && (!currprefs.monitoremu || currprefs.cs_hvcsync > 0)) { hsyncstartpos = hsstrt + 2; - if (hsyncstartpos >= maxhpos) { - hsyncstartpos -= maxhpos; + + if (hsyncstartpos >= maxhpos_short) { + hsyncstartpos -= maxhpos_short; } hsyncendpos = hsstop; hsstop_detect2 = (hsstrt + 21) * 2; - if (hsstop_detect2 >= maxhpos * 2) { - hsstop_detect2 -= maxhpos * 2; + if (hsstop_detect2 >= maxhpos_short * 2) { + hsstop_detect2 -= maxhpos_short * 2; } hsyncstartpos_start = hsyncstartpos; - if (hsyncstartpos < maxhpos / 2) { + if (hsyncstartpos < maxhpos_short / 2) { hsyncstartpos = maxhpos_short + hsyncstartpos_start; denisehtotal = hsyncstartpos; } else { - denisehtotal = maxhpos + hsyncstartpos; + denisehtotal = maxhpos_short + hsyncstartpos; } // make sure possible BPL DMA cycles before first refresh slot are processed before hsync if (hsyncstartpos_start < REFRESH_FIRST_HPOS + 1) { @@ -6661,17 +6732,19 @@ static void updateextblk(void) hsyncstartpos_start = hsyncstartpos_start_hw; hsyncstartpos = hsyncstartpos_hw; - denisehtotal = maxhpos + 7; + denisehtotal = maxhpos_short + 7; hsstop_detect2 = (35 + 9) * 2; hsstrt_v2 = 18 << CCK_SHRES_SHIFT; hsstop_v2 = 35 << CCK_SHRES_SHIFT; hsyncendpos = hsyncendpos_hw; + } hsstrt_v2 = adjust_hr(hsstrt_v2); hsstop_v2 = adjust_hr(hsstop_v2); + // Out of range left. Denise/Lisa hcounter starts from 2 (skips first 2 lores pixels) if (hbstrt_v2 < (1 << CCK_SHRES_SHIFT)) { hbstrt_v2 = 0xffff; @@ -6680,22 +6753,22 @@ static void updateextblk(void) hbstop_v2 = 0xffff; } // Out of range right - if (hbstrt_v2 >= (maxhpos << CCK_SHRES_SHIFT) + (1 << CCK_SHRES_SHIFT)) { + if (hbstrt_v2 >= (maxhpos_short << CCK_SHRES_SHIFT) + (1 << CCK_SHRES_SHIFT)) { hbstrt_v2 = 0xffff; } - if (hbstop_v2 >= (maxhpos << CCK_SHRES_SHIFT) + (1 << CCK_SHRES_SHIFT)) { + if (hbstop_v2 >= (maxhpos_short << CCK_SHRES_SHIFT) + (1 << CCK_SHRES_SHIFT)) { hbstop_v2 = 0xffff; } // hsync start offset adjustment if (hbstrt_v2 <= (hsyncstartpos_start << CCK_SHRES_SHIFT)) { - hbstrt_v2 += maxhpos << CCK_SHRES_SHIFT; - if (hbstrt_v2 > (maxhpos + hsyncstartpos_start_cycles) << CCK_SHRES_SHIFT) { + hbstrt_v2 += maxhpos_short << CCK_SHRES_SHIFT; + if (hbstrt_v2 > (maxhpos_short + hsyncstartpos_start_cycles) << CCK_SHRES_SHIFT) { hbstrt_v2 = 1 << CCK_SHRES_SHIFT; } } if (hbstop_v2 <= (hsyncstartpos_start << CCK_SHRES_SHIFT)) { - hbstop_v2 += maxhpos << CCK_SHRES_SHIFT; - if (hbstop_v2 > (maxhpos + hsyncstartpos_start_cycles) << CCK_SHRES_SHIFT) { + hbstop_v2 += maxhpos_short << CCK_SHRES_SHIFT; + if (hbstop_v2 > (maxhpos_short + hsyncstartpos_start_cycles) << CCK_SHRES_SHIFT) { hbstop_v2 = 1 << CCK_SHRES_SHIFT; } } @@ -6709,12 +6782,12 @@ static void updateextblk(void) int add = currprefs.chipset_hr ? (1 << currprefs.gfx_resolution) : 4; if (strt < stop) { hbstop_v2 += add; - if (hbstop_v2 >= (maxhpos << CCK_SHRES_SHIFT) + (1 << CCK_SHRES_SHIFT)) { + if (hbstop_v2 >= (maxhpos_short << CCK_SHRES_SHIFT) + (1 << CCK_SHRES_SHIFT)) { hbstop_v2 = 0; } } else if (strt > stop) { hbstrt_v2 += add; - if (hbstrt_v2 >= (maxhpos << CCK_SHRES_SHIFT) + (1 << CCK_SHRES_SHIFT)) { + if (hbstrt_v2 >= (maxhpos_short << CCK_SHRES_SHIFT) + (1 << CCK_SHRES_SHIFT)) { hbstrt_v2 = 0; } } @@ -6915,7 +6988,7 @@ void compute_framesync(void) 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; + vidinfo->drawbuffer.inheight = maxvsize_display << vres2; vidinfo->drawbuffer.inheight2 = vidinfo->drawbuffer.inheight; vidinfo->drawbuffer.inxoffset = 0; @@ -6984,7 +7057,7 @@ void compute_framesync(void) } /* set PAL/NTSC or custom timing variables */ -static void init_beamcon0(void) +static void init_beamcon0(bool fakehz) { int isntsc, islace; int hpos = current_hpos(); @@ -7223,7 +7296,7 @@ static void init_beamcon0(void) minfirstline_hw = 0; } - if (vpos_count > 0) { + if (fakehz && vpos_count > maxvpos_display_vsync) { // we come here if vpos_count != maxvpos and beamcon0 didn't change // (someone poked VPOSW) if (vpos_count < 10) { @@ -7365,6 +7438,7 @@ static void init_beamcon0(void) vblank_hz = 300; } maxhpos_short = maxhpos; + minfirstline_linear = minfirstline; set_delay_lastcycle(); updateextblk(); maxvpos_total = ecs_agnus ? (MAXVPOS_LINES_ECS - 1) : (MAXVPOS_LINES_OCS - 1); @@ -7372,8 +7446,8 @@ static void init_beamcon0(void) maxvpos_total = MAXVPOS; } set_maxhpos(maxhpos); - display_reset = 2; estimated_fm = 0xffff; + maxvsize_display = maxvpos_display + maxvpos_display_vsync - minfirstline; if ((currprefs.m68k_speed == 0 || copper_access) && maxhpos != oldmaxhpos) { if (hpos >= maxhpos) { @@ -7423,7 +7497,7 @@ static void init_hz(bool checkvposw) hzc = 1; } - init_beamcon0(); + init_beamcon0(checkvposw); if (doublescan != odbl || maxvpos != omaxvpos) { hzc = 1; @@ -7515,11 +7589,9 @@ static void calcdiw(void) diwfirstword = coord_diw_shres_to_window_x(hstrt); diwlastword = coord_diw_shres_to_window_x(hstop); - if (diwfirstword < min_diwlastword) { - diwfirstword = min_diwlastword; - } - if (diwlastword < min_diwlastword) { - diwlastword = min_diwlastword; + int mindiw = min_diwlastword; + if (diwfirstword < mindiw) { + diwfirstword = mindiw; } int hpos = current_hpos(); @@ -7650,15 +7722,15 @@ STATIC_INLINE uae_u16 DMACONR(int hpos) } STATIC_INLINE uae_u16 INTENAR(void) { - return intena; + return intena & 0x7fff; } uae_u16 INTREQR(void) { - return intreq; + return intreq & 0x7fff; } STATIC_INLINE uae_u16 ADKCONR(void) { - return adkcon; + return adkcon & 0x7fff; } STATIC_INLINE int islightpentriggered(void) @@ -7725,6 +7797,12 @@ static void vb_check(void) vb_end_line = true; vb_state = false; } + if (vpos == hardwired_vbstop) { + vb_end_line = false; + vb_state = false; + vb_start_line = 0; + vb_end_next_line = true; + } } static void vhpos_adj(uae_u16 *hpp, uae_u16 *vpp) @@ -7842,10 +7920,15 @@ static void VHPOSW_delayed(uae_u32 v) int oldvpos = vpos; int newvpos = vpos; int hpos_org = current_hpos(); + int hnew = hpos_org; bool enabled = false; + decide_vline(hpos_org); + decide_hdiw(hpos_org); decide_line(hpos_org); decide_fetch_safe(hpos_org); + decide_sprites(hpos_org); + flush_display(fetchmode); #if 0 if (M68K_GETPC < 0xf00000 || 1) @@ -7855,7 +7938,7 @@ static void VHPOSW_delayed(uae_u32 v) if ((currprefs.m68k_speed >= 0 && !currprefs.cachesize) || copper_access) { enabled = true; int hpos = hpos_org; - int hnew = (v & 0xff); + hnew = (v & 0xff); int hnew_org = hnew; bool newinc = false; if (hpos == 0 || hpos == 1) { @@ -7877,11 +7960,9 @@ static void VHPOSW_delayed(uae_u32 v) } if (hdiff) { - delay_cycles += ((-hdiff * 8 - 2) & 7) << LORES_TO_SHRES_SHIFT; if (hdiff & 1) { vhposr_delay_offset = 1; } - vhposr_sprite_offset += (hdiff * 4 - 2) << sprite_buffer_res; evt_t hsync_evtime = eventtab[ev_hsync].evtime; evt_t hsync_oldcycles = eventtab[ev_hsync].oldcycles; @@ -7946,10 +8027,19 @@ static void VHPOSW_delayed(uae_u32 v) memset(blitter_pipe, 0, t * sizeof(uae_u16)); } } - set_blitter_last(hnew + 1); - last_copper_hpos = hnew + 1; + int nhp = hnew + 1; + set_blitter_last(nhp); + last_copper_hpos = nhp; + last_fetch_hpos = nhp; + last_decide_line_hpos = nhp; + last_decide_sprite_hpos = nhp; } } + + delay_cycles = ((hnew + 0) & 0xff) << CCK_SHRES_SHIFT; + + last_diw_hpos = hnew << 1; + hdiw_denisecounter = ((hnew + 0) & 0xff) << CCK_SHRES_SHIFT; } newvpos &= 0xff00; @@ -7970,16 +8060,32 @@ static void VHPOSW_delayed(uae_u32 v) } } #endif - SET_LINE_CYCLEBASED(hpos_org); } vpos = newvpos; + record_dma_denise(hnew, hdiw_denisecounter >> 2); vb_check(); - decide_vline(hpos_org); + decide_vline(hnew); + vhposw_modified = true; +} + +static void VHPOSW_delayed1(uae_u32 v) +{ + int hpos = current_hpos(); + decide_hdiw(hpos); + decide_line(hpos); + decide_fetch_safe(hpos); + decide_sprites(hpos, false, true); + + int hnew = v & 0xff; + last_sprite_hpos = (hnew << 1) - 1; + last_sprite_point = (((hnew + 0) & 0xff) << 1) + 0; + + event2_newevent_xx(-1, 1 * CYCLE_UNIT, v, VHPOSW_delayed); } static void VHPOSW(uae_u16 v) { - event2_newevent_xx(-1, 2 * CYCLE_UNIT, v, VHPOSW_delayed); + event2_newevent_xx(-1, 1 * CYCLE_UNIT, v, VHPOSW_delayed1); } static uae_u16 VHPOSR(void) @@ -8456,16 +8562,17 @@ static void DMACON(int hpos, uae_u16 v) if (!oldcop && newcop) { bootwarpmode(); } - if (oldcop != newcop && (copper_access || safecpu())) { - copper_dma_change_cycle = get_cycles(); - } if (newcop && !oldcop) { - if (copper_dma_change_cycle == get_cycles()) { + if (copper_access || safecpu()) { + copper_dma_change_cycle = get_cycles(); event2_newevent_xx(-1, CYCLE_UNIT, 0, compute_spcflag_copper_delayed); } else { compute_spcflag_copper(); } } else if (!newcop && oldcop) { + if (copper_access || safecpu()) { + copper_dma_change_cycle = get_cycles(); + } compute_spcflag_copper(); } @@ -8773,18 +8880,12 @@ static void check_harddis(void) harddis_v = ecs_agnus && ((new_beamcon0 & BEAMCON0_VARBEAMEN) || (new_beamcon0 & BEAMCON0_VARVBEN) || (new_beamcon0 & BEAMCON0_HARDDIS)); } -static bool beamcon0_changed_critical(uae_u16 beamcon0a, uae_u16 beamcon0b) -{ - return (beamcon0a & (BEAMCON0_VARCSYEN | BEAMCON0_PAL | BEAMCON0_VARBEAMEN | BEAMCON0_VARHSYEN | BEAMCON0_VARVSYEN | BEAMCON0_VARVBEN | BEAMCON0_HARDDIS)) != - (beamcon0b & (BEAMCON0_VARCSYEN | BEAMCON0_PAL | BEAMCON0_VARBEAMEN | BEAMCON0_VARHSYEN | BEAMCON0_VARVSYEN | BEAMCON0_VARVBEN | BEAMCON0_HARDDIS)); -} - static void BEAMCON0(int hpos, uae_u16 v) { if (ecs_agnus) { bool beamcon0_changed = false; if (v != new_beamcon0) { - sync_color_changes(hpos); + sync_changes(hpos); new_beamcon0 = v; write_log(_T("BEAMCON0 = %04X, PC=%08X\n"), v, M68K_GETPC); // not LPENDIS, LOLDIS, PAL, BLANKEN, SYNC INVERT @@ -8798,7 +8899,7 @@ static void BEAMCON0(int hpos, uae_u16 v) check_harddis(); calcdiw(); if (beamcon0_changed) { - init_beamcon0(); + init_beamcon0(false); } } } @@ -8839,7 +8940,7 @@ static void varsync(int reg, bool resync) varsync_changed = 1; } if (varsync_changed) { - init_beamcon0(); + init_beamcon0(false); } } @@ -9232,42 +9333,53 @@ static void BPLxDAT(int hpos, int num, uae_u16 data) if (!num) { SET_LINE_CYCLEBASED(hpos); } - event2_newevent_xx(-1, 1 * CYCLE_UNIT, vv, BPLxDAT_next); + event2_newevent_xx_ce(1 * CYCLE_UNIT, vv, BPLxDAT_next); } +static void DIWSTRT_next(uae_u32 v) +{ + int hpos = current_hpos(); + decide_hdiw(hpos); + decide_line(hpos); + diwhigh_written = 0; + diwstrt = v; + calcdiw(); +} static void DIWSTRT(int hpos, uae_u16 v) { if (diwstrt == v && !diwhigh_written) { return; } - // if hpos matches previous hstart: it gets ignored. - if ((diw_hstrt >> 2) + DDF_OFFSET >= hpos * 2 - 2 && (diw_hstrt >> 2) + DDF_OFFSET <= hpos * 2 + 2) { - diw_hstrt = max_diwlastword << 2; - } + event2_newevent_xx_ce(1 * CYCLE_UNIT, v, DIWSTRT_next); +} + +static void DIWSTOP_next(uae_u32 v) +{ + int hpos = current_hpos(); decide_hdiw(hpos); - decide_conflict_hdiw(hpos); decide_line(hpos); diwhigh_written = 0; - diwstrt = v; + diwstop = v; calcdiw(); } - static void DIWSTOP(int hpos, uae_u16 v) { if (diwstop == v && !diwhigh_written) { return; } - if ((diw_hstop >> 2) + DDF_OFFSET >= hpos * 2 - 2 && (diw_hstop >> 2) + DDF_OFFSET <= hpos * 2 + 2) { - diw_hstop = min_diwlastword << 2; - } - decide_hdiw(hpos); - decide_conflict_hdiw(hpos); + event2_newevent_xx_ce(1 * CYCLE_UNIT, v, DIWSTOP_next); +} + +static void DIWHIGH_next(uae_u32 v) +{ + int hpos = current_hpos(); + // DIWHIGH has 1.5CCK delay + decide_hdiw(hpos, true); decide_line(hpos); - diwhigh_written = 0; - diwstop = v; + diwhigh_written = 1; + diwhigh = v; calcdiw(); } - static void DIWHIGH(int hpos, uae_u16 v) { if (!ecs_agnus && !ecs_denise) { @@ -9280,12 +9392,7 @@ static void DIWHIGH(int hpos, uae_u16 v) if (diwhigh_written && diwhigh == v) { return; } - decide_hdiw(hpos); - decide_conflict_hdiw(hpos); - decide_line(hpos); - diwhigh_written = 1; - diwhigh = v; - calcdiw(); + event2_newevent_xx_ce(1 * CYCLE_UNIT, v, DIWHIGH_next); } static void DDFSTRT(int hpos, uae_u16 v) @@ -9723,7 +9830,7 @@ static void sprite_get_bpl_data(int hpos, struct sprite *s, uae_u16 *dat) static void SPRxDATA(int hpos, uae_u16 v, int num) { struct sprite *s = &spr[num]; - decide_sprites(hpos, true, false); + decide_sprites(hpos, false); SPRxDATA_1(v, num, hpos); // if 32 (16-bit double CAS only) or 64 pixel wide sprite and SPRxDATx write: // - first 16 pixel part: previous chipset bus data @@ -9736,10 +9843,11 @@ static void SPRxDATA(int hpos, uae_u16 v, int num) } } } + static void SPRxDATB(int hpos, uae_u16 v, int num) { struct sprite *s = &spr[num]; - decide_sprites(hpos, true, false); + decide_sprites(hpos, false); SPRxDATB_1(v, num, hpos); // See above if (fmode & 8) { @@ -9751,8 +9859,11 @@ static void SPRxDATB(int hpos, uae_u16 v, int num) } } -static void SPRxCTL(int hpos, uae_u16 v, int num) +static void SPRxCTL_2(uae_u32 vv) { + int hpos = current_hpos(); + uae_u16 v = vv >> 16; + int num = vv & 7; #if SPRITE_DEBUG > 0 if (vpos >= SPRITE_DEBUG_MINY && vpos <= SPRITE_DEBUG_MAXY && (SPRITE_DEBUG & (1 << num))) { write_log(_T("%d:%d:SPR%dCTLC %06X\n"), vpos, hpos, num, spr[num].pt); @@ -9762,8 +9873,17 @@ static void SPRxCTL(int hpos, uae_u16 v, int num) decide_sprites(hpos); SPRxCTL_1(v, num, hpos); } -static void SPRxPOS(int hpos, uae_u16 v, int num) +static void SPRxCTL(int hpos, uae_u16 v, int num) { + uae_u32 vv = (v << 16) | num; + event2_newevent_xx_ce(1 * CYCLE_UNIT, vv, SPRxCTL_2); +} + +static void SPRxPOS_2(uae_u32 vv) +{ + int hpos = current_hpos(); + uae_u16 v = vv >> 16; + int num = vv & 7; struct sprite *s = &spr[num]; #if SPRITE_DEBUG > 0 if (vpos >= SPRITE_DEBUG_MINY && vpos <= SPRITE_DEBUG_MAXY && (SPRITE_DEBUG & (1 << num))) { @@ -9773,6 +9893,11 @@ static void SPRxPOS(int hpos, uae_u16 v, int num) decide_sprites(hpos); SPRxPOS_1(v, num, hpos); } +static void SPRxPOS(int hpos, uae_u16 v, int num) +{ + uae_u32 vv = (v << 16) | num; + event2_newevent_xx_ce(1 * CYCLE_UNIT, vv, SPRxPOS_2); +} static void SPRxPTH(int hpos, uae_u16 v, int num) { @@ -11098,9 +11223,9 @@ static void compute_spcflag_copper(void) { copper_enabled_thisline = 0; unset_special(SPCFLAG_COPPER); - if (!is_copper_dma(false) || cop_state.state == COP_stop || cop_state.state == COP_waitforever || cop_state.state == COP_bltwait || cop_state.state == COP_bltwait2 || custom_disabled) + if (!is_copper_dma(true) || cop_state.state == COP_stop || cop_state.state == COP_waitforever || cop_state.state == COP_bltwait || cop_state.state == COP_bltwait2 || custom_disabled) return; - if (cop_state.state == COP_wait1) { + if (cop_state.state == COP_wait1 && is_copper_dma(false)) { int vp = vpos & (((cop_state.ir[1] >> 8) & 0x7F) | 0x80); if (vp < cop_state.vcmp) { return; @@ -11305,7 +11430,7 @@ static void do_sprite_fetch(int hpos, uae_u16 dat) bool dmastate = (dat & 0x10) != 0; // render sprites first - decide_sprites(hpos, false, true); + decide_sprites(hpos, true); sprite_fetch_full(s, hpos, slot, dmastate, &data, &data321, &data322); @@ -11580,7 +11705,8 @@ void init_hardware_for_drawing_frame(void) end_sprite_entry = MAX_SPRITE_ENTRIES - 2; spixels_max = sizeof(spixels) / sizeof(*spixels) - MAX_PIXELS_PER_LINE; - next_lineno = calculate_lineno(vpos); + linear_vpos = vpos; + next_lineno = calculate_lineno(linear_vpos); last_color_change = 0; next_color_change = 0; next_color_entry = 0; @@ -12070,7 +12196,7 @@ static void vsync_check_vsyncmode(void) { if (varsync_changed == 1) { init_hz_normal(); - } else if (vpos_count > 0 && abs(vpos_count - vpos_count_diff) > 1 && vposw_change < 4) { + } else if (vpos_count > 0 && abs(vpos_count - vpos_count_diff) > 1 && vposw_change && vposw_change < 4) { init_hz_vposw(); } else if (interlace_changed || changed_chipset_refresh() || lof_changed) { compute_framesync(); @@ -12081,6 +12207,40 @@ static void vsync_check_vsyncmode(void) } } +static void check_display_mode_change(void) +{ + int vt, ht, hs, vs; + if (new_beamcon0 & BEAMCON0_VARBEAMEN) { + vt = vtotal; + ht = htotal; + } else { + vt = maxvpos; + ht = maxhpos; + } + if (new_beamcon0 & (BEAMCON0_VARHSYEN | BEAMCON0_VARCSYEN)) { + hs = hsstrt; + } else { + hs = 18; + } + if (new_beamcon0 & (BEAMCON0_VARVSYEN | BEAMCON0_VARCSYEN)) { + vs = vsstrt; + } else { + vs = (new_beamcon0 & BEAMCON0_PAL) ? 2 : 3; + } + + // recalculate display if vtotal, htotal, hsync start or vsync start changed > 1 + if ((abs(vt - vt_old) > 1 || abs(ht - ht_old) > 1 || abs(hs - hs_old) > 1 || abs(vs - vs_old) > 1) && vt_old && ht_old) { + varsync_changed = 1; + nosignal_trigger = true; + display_reset = 2; + } + + vt_old = vt; + ht_old = ht; + vs_old = vs; + hs_old = hs; +} + // emulated hardware vsync static void vsync_handler_post(void) { @@ -12247,18 +12407,7 @@ static void vsync_handler_post(void) devices_vsync_post(); - if (beamcon0_changed_critical(new_beamcon0, beamcon0_previous)) { - varsync_changed = 1; - if ((beamcon0_previous ^ new_beamcon0) & BEAMCON0_PAL) { - nosignal_trigger = true; - } - if ((beamcon0_previous ^ new_beamcon0) & BEAMCON0_VARBEAMEN) { - if (vtotal != maxvpos || htotal != maxhpos) { - nosignal_trigger = true; - } - } - } - beamcon0_previous = new_beamcon0; + check_display_mode_change(); vsync_check_vsyncmode(); @@ -12276,16 +12425,19 @@ static void vsync_handler_post(void) } } if (nosignal_trigger) { + struct amigadisplay *ad = &adisplays[0]; nosignal_trigger = false; - if (currprefs.gfx_monitorblankdelay > 0) { - nosignal_status = 1; - nosignal_cnt = (int)(currprefs.gfx_monitorblankdelay / (1000.0f / vblank_hz)); - if (nosignal_cnt <= 0) { - nosignal_cnt = 1; + if (!ad->specialmonitoron) { + if (currprefs.gfx_monitorblankdelay > 0) { + nosignal_status = 1; + nosignal_cnt = (int)(currprefs.gfx_monitorblankdelay / (1000.0f / vblank_hz)); + if (nosignal_cnt <= 0) { + nosignal_cnt = 1; + } + } else { + nosignal_status = 2; + nosignal_cnt = (int)(vblank_hz / 2); } - } else { - nosignal_status = 2; - nosignal_cnt = (int)(vblank_hz / 2); } } @@ -12324,7 +12476,7 @@ static void reset_scandoubler_sync(int hpos) last_fetch_hpos = hpos; last_copper_hpos = hpos; last_diw_hpos = hpos; - last_diw_hpos2 = hpos; + last_sprite_hpos = hpos; sprites_enabled_this_line = false; plfstrt_sprite = 0x100; bprun = 0; @@ -12703,8 +12855,16 @@ static void hautoscale_check(int vp) } if (diw_change == 0) { if (vp_start >= first_planes_vpos && vp_end <= last_planes_vpos) { - int diwlastword_lores = diwlastword; int diwfirstword_lores = diwfirstword; + int diwlastword_lores = diwlastword; + // >0x1c7? Calculate "real" right edge for scaling modes + if (diwlastword_lores < min_diwlastword && diwfirstword_lores >= 2) { + if (diwlastword_lores < diwfirstword_lores) { + diwlastword_lores = max_diwlastword + (diwlastword_lores - 2); + } else { + diwlastword_lores = min_diwlastword; + } + } if (diwlastword_lores > diwlastword_total) { diwlastword_total = diwlastword_lores; if (diwlastword_total > coord_diw_shres_to_window_x(hsyncstartpos)) { @@ -12765,11 +12925,14 @@ static void hsync_handlerh(bool onvsync) hautoscale_check(vposh); - int lineno = calculate_lineno(vposh); - next_lineno = lineno; + next_lineno = calculate_lineno(linear_vpos); reset_decisions_hsync_start(); } + linear_vpos++; + if (vpos >= minfirstline && minfirstline_linear == minfirstline) { + minfirstline_linear = linear_vpos; + } vposh++; hpos_hsync_extra = 0; @@ -12868,6 +13031,9 @@ static void hsync_handler_pre(bool onvsync) if (vpos >= maxvpos_total) { vpos = 0; } + + line_equ_freerun = !ecs_denise && vpos >= get_equ_vblank_startline() && vpos <= get_equ_vblank_endline(); + if (onvsync) { #ifdef DEBUGGER if (debug_dma) { @@ -14083,9 +14249,7 @@ static void hsync_handler(void) vsync_display_rendered = false; lof_display = lof_store; hstrobe_conflict = false; - hstrobe_conflict2 = false; - hdiw_counter_conflict = 0; - hdiw_counter_sconflict = 0; + minfirstline_linear = minfirstline; reset_autoscale(); } vsync_line = vs; @@ -14206,6 +14370,9 @@ void custom_reset(bool hardreset, bool keyboardreset) blitter_dma_change_cycle = -1; sprite_dma_change_cycle_on = -1; custom_color_write_cycle = -1; + vt_old = 0; + ht_old = 0; + hdiwstate_blank = diw_states::DIW_waiting_start; irq_forced_delay = 0; irq_forced = 0; @@ -14312,7 +14479,7 @@ void custom_reset(bool hardreset, bool keyboardreset) CLXCON(-1, 0); CLXCON2(-1, 0); setup_fmodes(0, bplcon0); - beamcon0 = new_beamcon0 = beamcon0_previous = beamcon0_saved = currprefs.ntscmode ? 0x00 : BEAMCON0_PAL; + beamcon0 = new_beamcon0 = beamcon0_saved = currprefs.ntscmode ? 0x00 : BEAMCON0_PAL; blt_info.blit_main = 0; blt_info.blit_finald = 0; blt_info.blit_pending = 0; @@ -14995,28 +15162,28 @@ static int REGPARAM2 custom_wput_1 (int hpos, uaecptr addr, uae_u32 value, int n case 0x1DC: BEAMCON0(hpos, value); break; case 0x1C0: if (htotal != value) { - sync_color_changes(hpos); + sync_changes(hpos); htotal = value & (MAXHPOS_ROWS - 1); varsync(addr, 1); } break; case 0x1C2: if (hsstop != value) { - sync_color_changes(hpos); + sync_changes(hpos); hsstop = value & (MAXHPOS_ROWS - 1); varsync(addr, 1); } break; case 0x1C4: if (hbstrt != value) { - sync_color_changes(hpos); + sync_changes(hpos); hbstrt = value & 0x7ff; varsync(addr, 0); } break; case 0x1C6: if (hbstop != value) { - sync_color_changes(hpos); + sync_changes(hpos); hbstop = value & 0x7ff; varsync(addr, 0); } @@ -15029,42 +15196,42 @@ static int REGPARAM2 custom_wput_1 (int hpos, uaecptr addr, uae_u32 value, int n break; case 0x1CA: if (vsstop != value) { - sync_color_changes(hpos); + sync_changes(hpos); vsstop = value & (MAXVPOS_LINES_ECS - 1); varsync(addr, 1); } break; case 0x1CC: if (vbstrt != value) { - sync_color_changes(hpos); + sync_changes(hpos); vbstrt = value & (MAXVPOS_LINES_ECS - 1); varsync(addr, 0); } break; case 0x1CE: if (vbstop != value) { - sync_color_changes(hpos); + sync_changes(hpos); vbstop = value & (MAXVPOS_LINES_ECS - 1); varsync(addr, 0); } break; case 0x1DE: if (hsstrt != value) { - sync_color_changes(hpos); + sync_changes(hpos); hsstrt = value & (MAXHPOS_ROWS - 1); varsync(addr, 1); } break; case 0x1E0: if (vsstrt != value) { - sync_color_changes(hpos); + sync_changes(hpos); vsstrt = value & (MAXVPOS_LINES_ECS - 1); varsync(addr, 1); } break; case 0x1E2: if (hcenter != value) { - sync_color_changes(hpos); + sync_changes(hpos); hcenter = value & (MAXHPOS_ROWS - 1); varsync(addr, 0); } @@ -16040,8 +16207,6 @@ void check_prefs_changed_custom(void) currprefs.cs_deniserev = changed_prefs.cs_deniserev; currprefs.cs_mbdmac = changed_prefs.cs_mbdmac; currprefs.cs_df0idhw = changed_prefs.cs_df0idhw; - currprefs.cs_denisemodel = changed_prefs.cs_denisemodel; - currprefs.cs_agnusmodel = changed_prefs.cs_agnusmodel; currprefs.cs_agnussize = changed_prefs.cs_agnussize; currprefs.cs_z3autoconfig = changed_prefs.cs_z3autoconfig; currprefs.cs_bytecustomwritebug = changed_prefs.cs_bytecustomwritebug; @@ -16058,6 +16223,8 @@ void check_prefs_changed_custom(void) if (currprefs.chipset_mask != changed_prefs.chipset_mask || currprefs.picasso96_nocustom != changed_prefs.picasso96_nocustom || currprefs.ntscmode != changed_prefs.ntscmode || + currprefs.cs_agnusmodel != changed_prefs.cs_agnusmodel || + currprefs.cs_denisemodel != changed_prefs.cs_denisemodel || currprefs.cs_hvcsync != changed_prefs.cs_hvcsync ) { currprefs.picasso96_nocustom = changed_prefs.picasso96_nocustom; @@ -16069,7 +16236,7 @@ void check_prefs_changed_custom(void) new_beamcon0 = beamcon0_saved; } else if (!(changed_prefs.chipset_mask & CSMASK_ECS_AGNUS) && (currprefs.chipset_mask & CSMASK_ECS_AGNUS)) { beamcon0_saved = beamcon0; - beamcon0 = new_beamcon0 = beamcon0_previous = currprefs.ntscmode ? 0x00 : BEAMCON0_PAL; + beamcon0 = new_beamcon0 = currprefs.ntscmode ? 0x00 : BEAMCON0_PAL; diwhigh = 0; diwhigh_written = 0; bplcon0 &= ~(0x10 | 0x01); @@ -16081,7 +16248,6 @@ void check_prefs_changed_custom(void) } currprefs.chipset_mask = changed_prefs.chipset_mask; currprefs.cs_agnusmodel = changed_prefs.cs_agnusmodel; - currprefs.cs_agnussize = changed_prefs.cs_agnussize; currprefs.cs_denisemodel = changed_prefs.cs_denisemodel; currprefs.cs_hvcsync = changed_prefs.cs_hvcsync; init_custom(); diff --git a/debug.cpp b/debug.cpp index ce5c3219..8681f7f4 100644 --- a/debug.cpp +++ b/debug.cpp @@ -235,7 +235,8 @@ static const TCHAR help[] = { _T(" dj [] Enable joystick/mouse input debugging.\n") _T(" smc [<0-1>] Enable self-modifying code detector. 1 = enable break.\n") _T(" dm Dump current address space map.\n") - _T(" v [] Show DMA data (accurate only in cycle-exact mode).\n") + _T(" v [] []\n") + _T(" Show DMA data (accurate only in cycle-exact mode).\n") _T(" v [-1 to -4] = enable visual DMA debugger.\n") _T(" vh [ ] \"Heat map\"\n") _T(" I Send custom event string\n") @@ -2234,6 +2235,7 @@ void record_dma_read_value(uae_u32 v) last_dma_rec->size = 2; } } + void record_dma_read_value_wide(uae_u64 v, bool quad) { if (last_dma_rec) { @@ -2245,6 +2247,7 @@ 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]) { @@ -2257,6 +2260,20 @@ bool record_dma_check(int hpos, int vpos) struct dma_rec *dr = &dma_record[dma_record_toggle][vpos * NR_DMA_REC_HPOS + hpos]; return dr->reg != 0xffff; } + +void record_dma_denise(int hpos, int dhpos) +{ + if (!dma_record[0]) { + return; + } + hpos += dma_record_hoffset; + 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->dhpos = dhpos; +} + void record_dma_clear(int hpos, int vpos) { if (!dma_record[0]) { @@ -2362,6 +2379,7 @@ static bool get_record_dma_info(struct dma_rec *drs, struct dma_rec *dr, TCHAR * l6[0] = 0; int hpos = dr->hpos; + int dhpos = dr->dhpos; if (hpos < 0) { struct dma_rec *dr2 = dr; int cnt = 0; @@ -2466,7 +2484,7 @@ static bool get_record_dma_info(struct dma_rec *drs, struct dma_rec *dr, TCHAR * } } if (ipl >= 0) { - _stprintf(l1, _T("[%02X %d]"), hpos, ipl); + _stprintf(l1, _T("[%02X %03X %d]"), hpos, dhpos, ipl); } else if (ipl == -2) { _stprintf(l1, _T("[%02X -]"), hpos); } else { @@ -2670,7 +2688,7 @@ static bool get_record_dma_info(struct dma_rec *drs, struct dma_rec *dr, TCHAR * -static void decode_dma_record(int hpos, int vpos, int toggle, bool logfile) +static void decode_dma_record(int hpos, int vpos, int count, int toggle, bool logfile) { struct dma_rec *dr, *dr_start; int h, i, maxh = 0; @@ -2783,6 +2801,12 @@ static void decode_dma_record(int hpos, int vpos, int toggle, bool logfile) console_out_f(_T("%s\n"), l6); console_out_f(_T("\n")); } + if (count > 0) { + count--; + if (!count) { + break; + } + } } if (logfile) flush_log(); @@ -2794,7 +2818,7 @@ void log_dma_record (void) return; if (!debug_dma) return; - decode_dma_record (0, 0, 0, true); + decode_dma_record (0, 0, 0, 0, true); } static void init_record_copper(void) @@ -6950,7 +6974,7 @@ static bool debug_line (TCHAR *input) case 'v': case 'V': { - int v1 = vpos, v2 = 0; + int v1 = vpos, v2 = 0, v3 = 0; if (*inptr == 'h') { inptr++; if (more_params(&inptr) && *inptr == '?') { @@ -7036,19 +7060,21 @@ static bool debug_line (TCHAR *input) if (nextcmd == 'l') { next_char(&inptr); } - if (more_params (&inptr)) - v1 = readint (&inptr, NULL); - if (more_params (&inptr)) - v2 = readint (&inptr, NULL); + if (more_params(&inptr)) + v1 = readint(&inptr, NULL); + if (more_params(&inptr)) + v2 = readint(&inptr, NULL); + if (more_params(&inptr)) + v3 = readint(&inptr, NULL); if (debug_dma && v1 >= 0 && v2 >= 0) { - decode_dma_record (v2, v1, cmd == 'v', nextcmd == 'l'); + decode_dma_record(v2, v1, v3, cmd == 'v', nextcmd == 'l'); } else { if (debug_dma) { record_dma_reset(0); reset_drawing(); } debug_dma = v1 < 0 ? -v1 : 1; - console_out_f (_T("DMA debugger enabled, mode=%d.\n"), debug_dma); + console_out_f(_T("DMA debugger enabled, mode=%d.\n"), debug_dma); } } } diff --git a/drawing.cpp b/drawing.cpp index 59cda0ee..128a6371 100644 --- a/drawing.cpp +++ b/drawing.cpp @@ -262,6 +262,7 @@ static int hblank_left_start, hblank_right_stop; static int hblank_left_start_hard, hblank_right_stop_hard; static bool extborder, exthblanken, exthblankon; static int exthblank; +static bool exthblank_force; static int exthblank_set; static bool ehb_enable; static bool syncdebug; @@ -595,7 +596,7 @@ int get_vertical_visible_height(bool useoldsize) int vbstrt, vbstop; if (programmedmode <= 1) { - h = maxvpos_display + maxvpos_display_vsync - minfirstline; + h = maxvsize_display; if (useoldsize) { // 288/576 or 243/486 if (h == 288 || h == 243) { @@ -1082,7 +1083,9 @@ static int sprite_playfield_start, sprite_end; static int may_require_hard_way; static int linetoscr_diw_start, linetoscr_diw_end; static int native_ddf_left, native_ddf_right; +#if 0 static int hamleftborderhidden; +#endif static int pixels_offset; static int src_pixel; @@ -1110,7 +1113,7 @@ static xcolnr getbgc(int blank) //return colors_for_drawing.acolors[0]; return xcolors[0xf0f]; #endif - if (exthblank > 0) { + if (exthblank > 0 || exthblank_force) { return fullblack; } bool extblken = ce_is_extblankset(colors_for_drawing.extra); @@ -1160,7 +1163,6 @@ static void pfield_init_linetoscr (bool border) /* First, get data fetch start/stop in DIW coordinates. */ int ddf_left = dp_for_drawing->plfleft + DIW_DDF_OFFSET - DDF_OFFSET; int ddf_right = dp_for_drawing->plfright + DIW_DDF_OFFSET - DDF_OFFSET; - int leftborderhidden; int native_ddf_left2; bool expanded = false; @@ -1188,10 +1190,6 @@ static void pfield_init_linetoscr (bool border) if (linetoscr_diw_start < 0) { linetoscr_diw_start = 0; } - // OCS Denise shows only background until hpos 95. - if (!ecs_denise && linetoscr_diw_start < shres_coord_hw_to_window_x(95 << 2)) { - linetoscr_diw_start = shres_coord_hw_to_window_x(95 << 2); - } /* Perverse cases happen. */ if (linetoscr_diw_end < linetoscr_diw_start) linetoscr_diw_end = linetoscr_diw_start; @@ -1364,13 +1362,15 @@ static void pfield_init_linetoscr (bool border) ddf_left <<= bplres; pixels_offset = MAX_PIXELS_PER_LINE - ddf_left; - leftborderhidden = playfield_start - native_ddf_left2; - hamleftborderhidden = 0; + int leftborderhidden = playfield_start - native_ddf_left2; +#if 0 + hamleftborderhidden = 0; if (hblank_left_start > playfield_start) { leftborderhidden += hblank_left_start - playfield_start; hamleftborderhidden = hblank_left_start - playfield_start; } +#endif src_pixel = MAX_PIXELS_PER_LINE + res_shift_from_window(leftborderhidden); @@ -1698,7 +1698,7 @@ static void fill_line2(int startpos, int len) } } -static void fill_line_border(int lineno) +static void fill_line_border(int lineno, int bordertype) { struct vidbuf_description *vidinfo = &adisplays[0].gfxvidinfo; int lastpos = visible_left_border; @@ -1712,7 +1712,7 @@ static void fill_line_border(int lineno) int b = hposblank; hposblank = 3; fill_line2(lastpos, w); - if (syncdebug) { + if (syncdebug && bordertype >= 0) { pfield_do_darken_line(lastpos, endpos, lineno); } if (need_genlock_data) { @@ -1726,7 +1726,7 @@ static void fill_line_border(int lineno) if (hposblank) { hposblank = 3; fill_line2(lastpos, w); - if (syncdebug) { + if (syncdebug && bordertype >= 0) { pfield_do_darken_line(lastpos, endpos, lineno); } if (need_genlock_data) { @@ -1769,7 +1769,7 @@ static uae_u8 render_sprites(int pos, int dualpf, uae_u8 apixel, int aga) int *shift_lookup = dualpf ? (bpldualpfpri ? dblpf_ms2 : dblpf_ms1) : dblpf_ms; int maskshift, plfmask; - if (exthblank) { + if (exthblank || exthblank_force) { return 0; } if (extborder && (ce_is_borderblank(colors_for_drawing.extra) || !ce_is_bordersprite(colors_for_drawing.extra))) { @@ -1869,7 +1869,7 @@ static uae_u8 sh_render_sprites(int pos, int dualpf, uae_u8 apixel, int aga) int *shift_lookup = dualpf ? (bpldualpfpri ? dblpf_ms2 : dblpf_ms1) : dblpf_ms; int maskshift, plfmask; - if (exthblank) { + if (exthblank || exthblank_force) { return 0; } if (extborder && ce_is_borderblank(colors_for_drawing.extra)) { @@ -2257,7 +2257,7 @@ static call_linetoscrb pfield_do_linetoscr_spriteonly; static void pfield_do_linetoscr(int start, int stop, int blank) { int pixel = pfield_do_linetoscr_normal(src_pixel, start, stop); - if (exthblank) { + if (exthblank || exthblank_force) { pfield_do_fill_line(start, stop, 1); } else if (extborder) { #if EXTBORDER_BLANK @@ -2279,10 +2279,10 @@ static void pfield_do_linetoscr_spr(int start, int stop, int blank) bool bb = ce_is_borderblank(colors_for_drawing.extra); #endif pixel = pfield_do_linetoscr_sprite(src_pixel, start, stop); - pfield_do_fill_line(start, stop, bb || exthblank > 0); + pfield_do_fill_line(start, stop, bb || exthblank > 0 || exthblank_force); } else { pixel = pfield_do_linetoscr_sprite(src_pixel, start, stop); - if (exthblank) { + if (exthblank || exthblank_force) { pfield_do_fill_line(start, stop, 1); } } @@ -2667,7 +2667,7 @@ static void pfield_set_linetoscr (void) // A1000 Denise right border bug: sprites have 1 extra lores pixel visible static void pfield_do_linetoscr_bordersprite_a1000(int start, int stop, int blank) { - if (blank || exthblank > 0 || extborder) { + if (blank || exthblank > 0 || exthblank_force || extborder) { pfield_do_fill_line(start, stop, blank); return; } @@ -2687,7 +2687,7 @@ static void pfield_do_linetoscr_bordersprite_a1000(int start, int stop, int blan // left or right AGA border sprite static void pfield_do_linetoscr_bordersprite_aga(int start, int stop, int blank) { - if (blank || exthblank > 0 || extborder) { + if (blank || exthblank > 0 || exthblank_force || extborder) { pfield_do_fill_line(start, stop, blank); return; } @@ -2772,7 +2772,10 @@ static void init_ham_decoding(void) { int unpainted_amiga = unpainted; - ham_decode_pixel = src_pixel - hamleftborderhidden; + ham_decode_pixel = src_pixel; +#if 0 + ham_decode_pixel = -hamleftborderhidden; +#endif ham_lastcolor = color_reg_get(&colors_for_drawing, 0); while (unpainted_amiga-- > 0) { decode_ham_pixel(ham_decode_pixel++); @@ -3146,6 +3149,7 @@ static void NOINLINE pfield_doline64_n8(uae_u64 *data, int count, uae_u8* real_b static void pfield_doline(int lineno) { uae_u8 *real_bplpt[8]; + int offset = 0; // currprefs.chipset_hr ? 8 : 0; #if 0 int wordcount = (dp_for_drawing->plflinelen + 1) / 2; @@ -3181,7 +3185,7 @@ static void pfield_doline(int lineno) int wordcount = dp_for_drawing->plflinelen; uae_u32 *data = pixdata.apixels_l + MAX_PIXELS_PER_LINE / sizeof(uae_u32); -#define DATA_POINTER(n) ((debug_bpl_mask & (1 << n)) ? (line_data[lineno] + (n) * MAX_WORDS_PER_LINE * 2) : (debug_bpl_mask_one ? all_ones : all_zeros)) +#define DATA_POINTER(n) ((debug_bpl_mask & (1 << n)) ? (line_data[lineno] + (n) * MAX_WORDS_PER_LINE * 2 + offset) : (debug_bpl_mask_one ? all_ones : all_zeros)) real_bplpt[0] = DATA_POINTER(0); real_bplpt[1] = DATA_POINTER(1); real_bplpt[2] = DATA_POINTER(2); @@ -3525,6 +3529,15 @@ static void pfield_expand_dp_bplconx (int regno, int v, int hp, int vp) exthblank = 0; } return; + case 0x208: // forced hblank + if (v) { + exthblanken = true; + exthblankon = true; + } else { + exthblanken = false; + exthblank = 0; + } + return; case 0x202: // hsync (debug) hsync_debug = v; return; @@ -3657,6 +3670,10 @@ static void do_color_changes(line_draw_func worker_border, line_draw_func worker if (nextpos_in_range > lastpos && lastpos < hblank_left) { int t = nextpos_in_range <= hblank_left ? nextpos_in_range : hblank_left; (*worker_border)(lastpos, t, 1); + // if playfield starts before hblank end: adjust back to playfield start + if (t > playfield_start) { + t = playfield_start; + } lastpos = t; } @@ -3684,6 +3701,10 @@ static void do_color_changes(line_draw_func worker_border, line_draw_func worker } else { (*worker_pfield)(lastpos, t, 0); } + // playfield started inside hblank? Overwrite it with blank. + if (playfield_start < hblank_left) { + (*worker_border)(playfield_start, hblank_left, 1); + } lastpos = t; } @@ -3756,10 +3777,18 @@ static void do_color_changes(line_draw_func worker_border, line_draw_func worker colors_for_drawing.acolors[regno] = getxcolor(value); } else if (regno == 0 && (value & COLOR_CHANGE_MASK)) { if ((value & COLOR_CHANGE_MASK) == COLOR_CHANGE_ACTBORDER) { - if (value & 1) { - extborder = true; + if (value & 2) { + if (value & 1) { + exthblank_force = true; + } else { + exthblank_force = false; + } } else { - extborder = false; + if (value & 1) { + extborder = true; + } else { + extborder = false; + } } } else if (value & COLOR_CHANGE_BLANK) { if (value & 1) { @@ -3992,18 +4021,18 @@ static void pfield_draw_line(struct vidbuffer *vb, int lineno, int gfx_ypos, int // blanked border line int tmp = hposblank; hposblank = 1; - fill_line_border(lineno); + fill_line_border(lineno, border); hposblank = tmp; } else { // normal border line - fill_line_border(lineno); + fill_line_border(lineno, border); } if (do_double) { if (dh == dh_buf) { xlinebuffer = row_map[follow_ypos] - linetoscr_x_adjust_pixbytes; xlinebuffer_genlock = row_map_genlock[follow_ypos] - linetoscr_x_adjust_pixels; - fill_line_border(lineno); + fill_line_border(lineno, border); } /* If dh == dh_line, do_flush_line will re-use the rendered line * from linemem. */ @@ -4047,7 +4076,7 @@ static void pfield_draw_line(struct vidbuffer *vb, int lineno, int gfx_ypos, int // top or bottom blanking region int tmp = hposblank; hposblank = 1; - fill_line_border(lineno); + fill_line_border(lineno, border); hposblank = tmp; } @@ -5316,6 +5345,7 @@ void reset_drawing(void) max_diwstop = 0; vb_state = 0; exthblank = 0; + exthblank_force = false; exthblank_set = syncdebug ? -1 : 1; exthblanken = false; exthblankon = false; diff --git a/events.cpp b/events.cpp index 6503c55c..92bbc8f8 100644 --- a/events.cpp +++ b/events.cpp @@ -360,7 +360,16 @@ void MISC_handler(void) recursive--; } -void event2_newevent_xx (int no, evt_t t, uae_u32 data, evfunc2 func) +void event2_newevent_xx_ce(evt_t t, uae_u32 data, evfunc2 func) +{ + if (!currprefs.cpu_memory_cycle_exact) { + func(data); + return; + } + event2_newevent_xx(-1, t, data, func); +} + +void event2_newevent_xx(int no, evt_t t, uae_u32 data, evfunc2 func) { evt_t et; static int next = ev2_misc; diff --git a/include/custom.h b/include/custom.h index f6a7f558..16dca1b0 100644 --- a/include/custom.h +++ b/include/custom.h @@ -143,14 +143,15 @@ extern uae_u16 INTREQR(void); #define VSYNC_ENDLINE_PAL 5 #define VSYNC_ENDLINE_NTSC 6 #define EQU_ENDLINE_PAL 8 -#define EQU_ENDLINE_NTSC 10 +#define EQU_ENDLINE_NTSC 9 -#define OCS_DENISE_HBLANK_DISABLE_HPOS 0x2d +#define OCS_DENISE_HBLANK_DISABLE_HPOS 0x2e extern int maxhpos, maxhposm0, maxhpos_short; extern int maxvpos, maxvpos_nom, maxvpos_display, maxvpos_display_vsync, maxhpos_display; +extern int maxvsize_display; extern int hsyncstartpos_hw, hsyncendpos_hw; -extern int minfirstline, vblank_endline, numscrlines; +extern int minfirstline, minfirstline_linear, vblank_endline, numscrlines; extern float vblank_hz, fake_vblank_hz; extern float hblank_hz; extern int vblank_skip, doublescan; diff --git a/include/debug.h b/include/debug.h index 9121e99f..ccf35574 100644 --- a/include/debug.h +++ b/include/debug.h @@ -226,6 +226,7 @@ extern struct peekdma peekdma_data; struct dma_rec { int hpos, vpos; + int dhpos; uae_u16 reg; uae_u64 dat; uae_u16 size; @@ -312,6 +313,7 @@ extern void record_dma_reoffset(int, int, int); extern void record_cia_access(int r, int mask, uae_u16 value, bool rw, int hpos, int vpos, int phase); extern void record_dma_ipl(int hpos, int vpos); extern void record_dma_ipl_sample(int hpos, int vpos); +extern void record_dma_denise(int pos, int dhpos); 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); diff --git a/include/drawing.h b/include/drawing.h index dbdd1fcc..1b0db893 100644 --- a/include/drawing.h +++ b/include/drawing.h @@ -89,7 +89,7 @@ STATIC_INLINE int PIXEL_XPOS(int xx) return x; } -#define min_diwlastword (0) +#define min_diwlastword (PIXEL_XPOS(hsyncstartpos_start_cycles << CCK_SHRES_SHIFT)) #define max_diwlastword (PIXEL_XPOS(denisehtotal)) STATIC_INLINE int coord_window_to_hw_x(int x) diff --git a/include/events.h b/include/events.h index de3c8a81..cc04dfb6 100644 --- a/include/events.h +++ b/include/events.h @@ -137,6 +137,7 @@ extern void event2_newevent_xx(int no, evt_t t, uae_u32 data, evfunc2 func); extern void event2_newevent_x_replace(evt_t t, uae_u32 data, evfunc2 func); extern void event2_newevent_x_replace_exists(evt_t t, uae_u32 data, evfunc2 func); extern void event2_newevent_x_remove(evfunc2 func); +extern void event2_newevent_xx_ce(evt_t t, uae_u32 data, evfunc2 func); STATIC_INLINE void event2_newevent_x(int no, evt_t t, uae_u32 data, evfunc2 func) { -- 2.47.3