]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
Custom chipset WIP updates.
authorToni Wilen <twilen@winuae.net>
Sun, 25 Jul 2021 19:37:10 +0000 (22:37 +0300)
committerToni Wilen <twilen@winuae.net>
Sun, 25 Jul 2021 19:37:10 +0000 (22:37 +0300)
custom.cpp
drawing.cpp
events.cpp
genlinetoscr.cpp
include/drawing.h

index ebe99aa7df1838acf49fd95197a6463d7349a1f6..20ef6b3f5984ebe08bdcba4fb19d80b300b3572f 100644 (file)
@@ -70,7 +70,8 @@
 #define SPRBORDER 0
 
 #define EXTRAWIDTH_BROADCAST 14
-#define EXTRAHEIGHT_BROADCAST 2
+#define EXTRAHEIGHT_BROADCAST_TOP 0
+#define EXTRAHEIGHT_BROADCAST_BOTTOM 0
 #define EXTRAWIDTH_EXTREME 32
 #define EXTRAHEIGHT_EXTREME 24
 
@@ -299,7 +300,7 @@ static int maxhposm1;
 static bool maxhposeven;
 int hsyncendpos, hsyncstartpos;
 int hsync_end_left_border;
-static int hsyncstartpos_start;
+static int hsyncstartpos_start, hsyncstartpos_start_cycles;
 
 static int hsyncstartpos_start_hw;
 int hsyncstartpos_hw;
@@ -428,7 +429,8 @@ static int first_bpl_vpos;
 static int last_decide_line_hpos;
 static int last_fetch_hpos, last_decide_sprite_hpos;
 static int diwfirstword, diwlastword;
-static int last_diwlastword, last_diwlastword_cc;
+static int last_diwlastword;
+static int hb_last_diwlastword;
 static int last_hdiw;
 static enum diw_states diwstate, hdiwstate;
 static int diwstate_vpos;
@@ -505,9 +507,9 @@ static int current_change_set;
 static struct sprite_entry sprite_entries[2][MAX_SPR_PIXELS / 16];
 static struct color_change color_changes[2][MAX_REG_CHANGE];
 
-struct decision line_decisions[2 * (MAXVPOS + 2) + 1];
-static struct draw_info line_drawinfo[2][2 * (MAXVPOS + 2) + 1];
-#define COLOR_TABLE_SIZE (MAXVPOS + 2) * 2
+struct decision line_decisions[2 * (MAXVPOS + MAXVPOS_WRAPLINES) + 1];
+static struct draw_info line_drawinfo[2][2 * (MAXVPOS + MAXVPOS_WRAPLINES) + 1];
+#define COLOR_TABLE_SIZE (MAXVPOS + MAXVPOS_WRAPLINES) * 2
 static struct color_entry color_tables[2][COLOR_TABLE_SIZE];
 
 static int next_sprite_entry = 0;
@@ -539,7 +541,7 @@ static int ddf_stopping, ddf_enable_on;
 static int bprun;
 static int bprun_cycle;
 static int bprun_pipeline_flush_delay;
-static bool plane0;
+static bool plane0, plane0p, plane0p_enabled, plane0_prehsync;
 static bool harddis_v, harddis_h;
 static uae_u16 dmal_alloc_mask;
 
@@ -583,7 +585,7 @@ static bool bplcon0_planes_changed;
 static bool sprites_enabled_this_line;
 static int shifter_mask, shifter_size, toscr_delay_shifter[2];
 static int out_subpix[2];
-
+static bool speedup_first;
 
 /* The number of bits left from the last fetched words.
 This is an optimization - conceptually, we have to make sure the result is
@@ -647,6 +649,17 @@ static void setclr(uae_u16 *p, uae_u16 val)
        }
 }
 
+static void adjust_hr(uae_u16 *vp)
+{
+       uae_u16 v = *vp;
+       if (currprefs.chipset_hr) {
+               v &= ~(3 >> currprefs.gfx_resolution);
+       } else {
+               v &= ~3;
+       }
+       *vp = v;
+}
+
 static void alloc_cycle(int hpos, int type)
 {
 #ifdef CPUEMU_13
@@ -821,10 +834,20 @@ static void reset_bpl_vars()
        thisline_decision.bplres = output_res(bplcon0_res);
 }
 
+// hblank start = enable border (bitplane not visible until next BPL1DAT)..
+static void hblank_reset(int hblankpos)
+{
+       if (thisline_decision.plfleft < 0) {
+               return;
+       }
+       hb_last_diwlastword = coord_diw_shres_to_window_x(hblankpos);
+       SET_LINE_CYCLEBASED;
+}
+
 static void record_color_change2(int hpos, int regno, uae_u32 value)
 {
        color_change *cc;
-       int pos = ((hpos + hpos_hsync_extra) * 2 - DDF_OFFSET) * 4;
+       int pos = hpos < 0 ? -hpos : ((hpos + hpos_hsync_extra) * 2 - DDF_OFFSET) * 4;
 
        // AGA has extra hires pixel delay in color changes
        if ((regno < RECORDED_REGISTER_CHANGE_OFFSET || regno == RECORDED_REGISTER_CHANGE_OFFSET + 0x10c) && aga_mode) {
@@ -858,9 +881,6 @@ static void record_color_change2(int hpos, int regno, uae_u32 value)
                cc = &curr_color_changes[next_color_change];
                int prevpos = last_color_change == next_color_change ? 0 : cc[-1].linepos;
                int chpos = pos;
-               if (regno == 0xffff) {
-                       chpos = 0x7fff;
-               }
                // inject programmed hblank start and end in color changes
                if (hbstrt_v2 <= hbstop_v2) {
                        if (chpos >= hbstrt_v2 && prevpos < hbstrt_v2) {
@@ -870,6 +890,7 @@ static void record_color_change2(int hpos, int regno, uae_u32 value)
                                cc->value = 1;
                                next_color_change++;
                                cc[1].regno = -1;
+                               hblank_reset(hbstrt_v2);
                        }
                        if (chpos >= hbstop_v2 && prevpos < hbstop_v2) {
                                cc = &curr_color_changes[next_color_change];
@@ -895,41 +916,49 @@ static void record_color_change2(int hpos, int regno, uae_u32 value)
                                cc->value = 1;
                                next_color_change++;
                                cc[1].regno = -1;
+                               hblank_reset(hbstrt_v2);
                        }
                }
        }
 
-       if (regno == 0xffff) {
-               return;
+       if (regno != 0xffff) {
+               cc = &curr_color_changes[next_color_change];
+               cc->linepos = pos;
+               cc->regno = regno;
+               cc->value = value;
+               next_color_change++;
+               cc[1].regno = -1;
        }
-
-       cc = &curr_color_changes[next_color_change];
-       cc->linepos = pos;
-       cc->regno = regno;
-       cc->value = value;
-       next_color_change++;
-       cc[1].regno = -1;
 }
 
 // hdiw opened again in same scanline
 // erase (color0 or bblank) area between previous end and new start
-static void hdiw_restart(int ccnum, int diw_last, int diw_current)
+static void hdiw_restart(int diw_last, int diw_current)
 {
-       for (int i = next_color_change; i > ccnum; i--) {
-               memcpy(&curr_color_changes[i], &curr_color_changes[i - 1], sizeof(struct color_change));
+       // update state
+       record_color_change2(-(diw_current - 1), 0xffff, 0);
+
+       // 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_last) {
+                       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[ccnum];
+
+       struct color_change *cc = &curr_color_changes[ii];
        cc->linepos = diw_last;
        cc->regno = 0;
        cc->value = COLOR_CHANGE_ACTBORDER | 1;
        next_color_change++;
-       cc = &curr_color_changes[next_color_change];
-       cc->linepos = diw_current;
-       cc->regno = 0;
-       cc->value = COLOR_CHANGE_ACTBORDER | 0;
-       cc[1].regno = -1;
-       next_color_change++;
-       //write_log("%d %d\n", diw_last, diw_current);
+
+       record_color_change2(-diw_current, 0, COLOR_CHANGE_ACTBORDER | 0);
 }
 
 /* Called to determine the state of the horizontal display window state
@@ -955,24 +984,34 @@ static void decide_diw(int hpos)
                        lhdiw = 512;
                }
 
-               if (lhdiw >= diw_hstrt && last_hdiw < diw_hstrt && hdiwstate == DIW_waiting_start) {
-                       if (thisline_decision.diwfirstword < 0) {
-                               thisline_decision.diwfirstword = diwfirstword < 0 ? min_diwlastword : diwfirstword;
-                       } else if (thisline_decision.diwlastword >= 0 && diwfirstword > thisline_decision.diwfirstword && last_diwlastword_cc < 0) {
-                               last_diwlastword = thisline_decision.diwlastword;
-                               last_diwlastword_cc = next_color_change;
+               if (hdiwstate == DIW_waiting_start) {
+                       if (lhdiw >= diw_hstrt && last_hdiw < diw_hstrt) {
+                               if (last_diwlastword >= 0) {
+                                       uae_u16 pos = (((hpos_hsync_extra) * 2 - DDF_OFFSET) * 4);
+                                       hdiw_restart(last_diwlastword * 2, diwfirstword * 2 + coord_diw_shres_to_window_x(pos * 2));
+                                       last_diwlastword = -1;
+                               }
+                               if (thisline_decision.diwfirstword < 0) {
+                                       thisline_decision.diwfirstword = diwfirstword < 0 ? min_diwlastword : diwfirstword;
+                               } else if (thisline_decision.diwlastword >= 0 && diwfirstword > thisline_decision.diwfirstword) {
+                                       last_diwlastword = thisline_decision.diwlastword;
+                               }
+                               hdiwstate = DIW_waiting_stop;
                        }
-                       hdiwstate = DIW_waiting_stop;
                }
-               if ((lhdiw >= diw_hstop && last_hdiw < diw_hstop) && hdiwstate == DIW_waiting_stop) {
-                       int last = diwlastword < 0 ? 0 : diwlastword;
-                       if (last > thisline_decision.diwlastword) {
-                               thisline_decision.diwlastword = last;
-                               if (last_diwlastword_cc >= 0) {
-                                       hdiw_restart(last_diwlastword_cc, last_diwlastword * 2, diwfirstword * 2);
+               if (hdiwstate == DIW_waiting_stop) {
+                       if (lhdiw >= diw_hstop && last_hdiw < diw_hstop) {
+                               int last = diwlastword < 0 ? 0 : diwlastword;
+                               if (last > thisline_decision.diwlastword) {
+                                       thisline_decision.diwlastword = last;
+                                       if (last_diwlastword >= 0) {
+                                               hdiw_restart(last_diwlastword * 2, diwfirstword * 2);
+                                       } else {
+                                               last_diwlastword = thisline_decision.diwlastword;
+                                       }
                                }
+                               hdiwstate = DIW_waiting_start;
                        }
-                       hdiwstate = DIW_waiting_start;
                }
                if (lhdiw != 512) {
                        break;
@@ -1170,7 +1209,7 @@ static void create_cycle_diagram_table(void)
 static void clear_bitplane_pipeline(int type)
 {
        // clear bitplane allocations
-       int safepos = (hsyncstartpos_start >> CCK_SHRES_SHIFT) - 1;
+       int safepos = hsyncstartpos_start_cycles - 1;
        int count = RGA_PIPELINE_ADJUST + 1;
        if (type) {
                for (int i = 0; i < maxhpos + RGA_PIPELINE_ADJUST; i++) {
@@ -1477,6 +1516,12 @@ static int islinetoggle(void)
        return linetoggle;
 }
 
+static void compute_shifter_mask(void)
+{
+       shifter_size = 16 << (fetchmode + LORES_TO_SHRES_SHIFT - toscr_res);
+       shifter_mask = shifter_size - 1;
+}
+
 /* Expand bplcon0/bplcon1 into the toscr_xxx variables.  */
 static void compute_toscr_delay(int bplcon1)
 {
@@ -1486,8 +1531,7 @@ static void compute_toscr_delay(int bplcon1)
        int shdelay2 = (bplcon1 >> 12) & 3;
        int delaymask = fetchmode_mask >> toscr_res;
 
-       shifter_size = 16 << (fetchmode + LORES_TO_SHRES_SHIFT - toscr_res);
-       shifter_mask = shifter_size - 1;
+       compute_shifter_mask();
 
        toscr_delay_shifter[0] = (delay1 & delaymask) << LORES_TO_SHRES_SHIFT;
        toscr_delay_shifter[1] = (delay2 & delaymask) << LORES_TO_SHRES_SHIFT;
@@ -1526,7 +1570,7 @@ static void set_delay_lastcycle(void)
        if (islinetoggle()) {
                delay_lastcycle[1] += 1 << LORES_TO_SHRES_SHIFT;
        }
-       delay_hsynccycle = (((maxhpos + (hsyncstartpos_start >> CCK_SHRES_SHIFT)) * 2) - DDF_OFFSET) << LORES_TO_SHRES_SHIFT;
+       delay_hsynccycle = (((maxhpos + hsyncstartpos_start_cycles) * 2) - DDF_OFFSET) << LORES_TO_SHRES_SHIFT;
 }
 
 static void setup_fmodes_hr(void)
@@ -1853,20 +1897,20 @@ STATIC_INLINE void toscr_3_aga_hr(int oddeven, int step, int nbits, int fm_size_
 
 #endif
 
-static void NOINLINE toscr_2_0(int nbits) { toscr_3_ecs(0, 1, nbits); }
-static void NOINLINE toscr_2_0_oe(int oddeven, int step, int nbits) { toscr_3_ecs(oddeven, step, nbits); }
+static void toscr_2_0(int nbits) { toscr_3_ecs(0, 1, nbits); }
+static void toscr_2_0_oe(int oddeven, int step, int nbits) { toscr_3_ecs(oddeven, step, nbits); }
 #ifdef AGA
-static void NOINLINE toscr_2_1(int nbits) { toscr_3_aga(0, 1, nbits, 32); }
-static void NOINLINE toscr_2_1_oe(int oddeven, int step, int nbits) { toscr_3_aga(oddeven, step, nbits, 32); }
-static void NOINLINE toscr_2_2(int nbits) { toscr_3_aga(0, 1, nbits, 64); }
-static void NOINLINE toscr_2_2_oe(int oddeven, int step, int nbits) { toscr_3_aga(oddeven, step, nbits, 64); }
+static void toscr_2_1(int nbits) { toscr_3_aga(0, 1, nbits, 32); }
+static void toscr_2_1_oe(int oddeven, int step, int nbits) { toscr_3_aga(oddeven, step, nbits, 32); }
+static void toscr_2_2(int nbits) { toscr_3_aga(0, 1, nbits, 64); }
+static void toscr_2_2_oe(int oddeven, int step, int nbits) { toscr_3_aga(oddeven, step, nbits, 64); }
 
-static void NOINLINE toscr_2_0_hr(int nbits) { toscr_3_aga_hr(0, 1, nbits, 16 - 1); }
-static void NOINLINE toscr_2_0_hr_oe(int oddeven, int step, int nbits) { toscr_3_aga_hr(oddeven, step, nbits, 16 - 1); }
-static void NOINLINE toscr_2_1_hr(int nbits) { toscr_3_aga_hr(0, 1, nbits, 32 - 1); }
-static void NOINLINE toscr_2_1_hr_oe(int oddeven, int step, int nbits) { toscr_3_aga_hr(oddeven, step, nbits, 32 - 1); }
-static void NOINLINE toscr_2_2_hr(int nbits) { toscr_3_aga_hr(0, 1, nbits, 64 - 1); }
-static void NOINLINE toscr_2_2_hr_oe(int oddeven, int step, int nbits) { toscr_3_aga_hr(oddeven, step, nbits, 64 - 1); }
+static void toscr_2_0_hr(int nbits) { toscr_3_aga_hr(0, 1, nbits, 16 - 1); }
+static void toscr_2_0_hr_oe(int oddeven, int step, int nbits) { toscr_3_aga_hr(oddeven, step, nbits, 16 - 1); }
+static void toscr_2_1_hr(int nbits) { toscr_3_aga_hr(0, 1, nbits, 32 - 1); }
+static void toscr_2_1_hr_oe(int oddeven, int step, int nbits) { toscr_3_aga_hr(oddeven, step, nbits, 32 - 1); }
+static void toscr_2_2_hr(int nbits) { toscr_3_aga_hr(0, 1, nbits, 64 - 1); }
+static void toscr_2_2_hr_oe(int oddeven, int step, int nbits) { toscr_3_aga_hr(oddeven, step, nbits, 64 - 1); }
 #endif
 
 static void do_tosrc(int oddeven, int step, int nbits, int fm)
@@ -2151,23 +2195,23 @@ STATIC_INLINE void do_delays_fast_3_aga_hr(int nbits, int fm)
 
 #endif
 
-static void NOINLINE do_delays_2_0(int nbits) { do_delays_3_ecs(nbits); }
+static void do_delays_2_0(int nbits) { do_delays_3_ecs(nbits); }
 #ifdef AGA
-static void NOINLINE do_delays_2_1(int nbits) { do_delays_3_aga(nbits, 1); }
-static void NOINLINE do_delays_2_2(int nbits) { do_delays_3_aga(nbits, 2); }
+static void do_delays_2_1(int nbits) { do_delays_3_aga(nbits, 1); }
+static void do_delays_2_2(int nbits) { do_delays_3_aga(nbits, 2); }
 
-static void NOINLINE do_delays_2_0_hr(int nbits) { do_delays_3_aga_hr(nbits, 0); }
-static void NOINLINE do_delays_2_1_hr(int nbits) { do_delays_3_aga_hr(nbits, 1); }
-static void NOINLINE do_delays_2_2_hr(int nbits) { do_delays_3_aga_hr(nbits, 2); }
-static void NOINLINE do_delays_fast_2_0_hr(int nbits) { do_delays_fast_3_aga_hr(nbits, 0); }
-static void NOINLINE do_delays_fast_2_1_hr(int nbits) { do_delays_fast_3_aga_hr(nbits, 1); }
-static void NOINLINE do_delays_fast_2_2_hr(int nbits) { do_delays_fast_3_aga_hr(nbits, 2); }
+static void do_delays_2_0_hr(int nbits) { do_delays_3_aga_hr(nbits, 0); }
+static void do_delays_2_1_hr(int nbits) { do_delays_3_aga_hr(nbits, 1); }
+static void do_delays_2_2_hr(int nbits) { do_delays_3_aga_hr(nbits, 2); }
+static void do_delays_fast_2_0_hr(int nbits) { do_delays_fast_3_aga_hr(nbits, 0); }
+static void do_delays_fast_2_1_hr(int nbits) { do_delays_fast_3_aga_hr(nbits, 1); }
+static void do_delays_fast_2_2_hr(int nbits) { do_delays_fast_3_aga_hr(nbits, 2); }
 #endif
 
-static void NOINLINE do_delays_fast_2_0(int nbits) { do_delays_fast_3_ecs(nbits); }
+static void do_delays_fast_2_0(int nbits) { do_delays_fast_3_ecs(nbits); }
 #ifdef AGA
-static void NOINLINE do_delays_fast_2_1(int nbits) { do_delays_fast_3_aga(nbits, 1); }
-static void NOINLINE do_delays_fast_2_2(int nbits) { do_delays_fast_3_aga(nbits, 2); }
+static void do_delays_fast_2_1(int nbits) { do_delays_fast_3_aga(nbits, 1); }
+static void do_delays_fast_2_2(int nbits) { do_delays_fast_3_aga(nbits, 2); }
 #endif
 
 
@@ -2360,6 +2404,7 @@ static void toscr_special_hr(int nbits, int fm)
        }
 }
 
+
 static void toscr_1(int nbits, int fm)
 {
        int total = nbits << toscr_res_pixels_shift;
@@ -2520,6 +2565,30 @@ static void flush_plane_data_hr(int fm, int hpos)
        }
 }
 
+static void quick_add_delay_cycles(int total)
+{
+       while (total > 0) {
+               int total2 = total;
+               if (delay_cycles2 <= delay_lastcycle[lol] && delay_cycles2 + total2 > delay_lastcycle[lol]) {
+                       total2 = delay_lastcycle[lol] - delay_cycles2;
+               }
+               if (delay_cycles2 <= delay_hsynccycle && delay_cycles2 + total2 > delay_hsynccycle) {
+                       total2 = delay_hsynccycle - delay_cycles2;
+               }
+               delay_cycles += total2;
+               delay_cycles2 += total2;
+               total -= total2;
+               if (total <= 0) {
+                       break;
+               }
+               if (currprefs.chipset_hr) {
+                       toscr_special_hr(1, fetchmode);
+               } else {
+                       toscr_special(1, fetchmode);
+               }
+       }
+}
+
 // flush remaining data but leave data after hsync
 static void flush_plane_data(int fm, int hpos)
 {
@@ -2539,15 +2608,13 @@ static void flush_display(int fm)
                        toscr(toscr_nbits, fm);
                }
        } else if (toscr_nbits) {
+               int total;
                if (currprefs.chipset_hr) {
-                       int total = toscr_nbits << (toscr_res_mult + toscr_res_pixels_shift_hr);
-                       delay_cycles += total;
-                       delay_cycles2 += total;
+                       total = toscr_nbits << (toscr_res_mult + toscr_res_pixels_shift_hr);
                } else {
-                       int total = toscr_nbits << toscr_res_pixels_shift;
-                       delay_cycles += total;
-                       delay_cycles2 += total;
+                       total = toscr_nbits << toscr_res_pixels_shift;
                }
+               quick_add_delay_cycles(total);
        }
        toscr_nbits = 0;
 }
@@ -2609,6 +2676,19 @@ static void update_denise_vars(void)
        }
        toscr_res_pixels = 1 << toscr_res_pixels_shift;
        toscr_res2p = 2 << toscr_res;
+       compute_shifter_mask();
+}
+
+static void update_planecount(void)
+{
+       toscr_nr_planes = GET_PLANES(bplcon0d);
+       if (isocs7planes()) {
+               if (toscr_nr_planes2 < 6) {
+                       toscr_nr_planes2 = 6;
+               }
+       } else {
+               toscr_nr_planes2 = toscr_nr_planes;
+       }
 }
 
 static void update_denise(int hpos)
@@ -2617,14 +2697,7 @@ static void update_denise(int hpos)
        if (bplcon0d_old != bplcon0d) {
                bplcon0d_old = bplcon0d;
                record_color_change2(hpos, 0x100 + RECORDED_REGISTER_CHANGE_OFFSET, bplcon0d);
-               toscr_nr_planes = GET_PLANES(bplcon0d);
-               if (isocs7planes()) {
-                       if (toscr_nr_planes2 < 6) {
-                               toscr_nr_planes2 = 6;
-                       }
-               } else {
-                       toscr_nr_planes2 = toscr_nr_planes;
-               }
+               update_planecount();
                hack_shres_delay(hpos);
        }
 }
@@ -2650,14 +2723,49 @@ static void update_toscr_planes(int fm)
        thisline_decision.nr_planes = toscr_nr_planes_agnus;
 }
 
+static void hbstrt_bordercheck(int hpos)
+{
+       if (hb_last_diwlastword < 0) {
+               return;
+       }
+       // if HBSTRT re-enabled border (and HDIW was already open), BPL1DAT access will disable border again.
+       record_color_change2(hpos - 1, 0xffff, 0);
+       uae_u16 pos = (((hpos + hpos_hsync_extra) * 2 - DDF_OFFSET) * 4);
+       pos -= 2; // 1 hires pixel early
+       adjust_hr(&pos);
+       hdiw_restart(hb_last_diwlastword * 2, coord_diw_shres_to_window_x(pos * 2));
+       hb_last_diwlastword = -1;
+}
+
+static void beginning_of_plane_block_early(int hpos)
+{
+       plane0p = false;
+       if (thisline_decision.plfleft >= 0 || plane0_prehsync) {
+               return;
+       }
+       plane0_prehsync = true;
+       bprun_pipeline_flush_delay = maxhpos;
+       flush_display(fetchmode);
+       reset_bpl_vars();
+       bpl_shifter = true;
+       int left = hpos + hpos_hsync_extra;
+       thisline_decision.plfleft = left * 2;
+       if (hdiwstate == DIW_waiting_stop && thisline_decision.diwfirstword < 0) {
+               // 1.5 lores pixels
+               thisline_decision.diwfirstword = coord_diw_shres_to_window_x(((left - DDF_OFFSET / 2) << CCK_SHRES_SHIFT) + 6);
+       }
+
+       hbstrt_bordercheck(hpos);
+}
+
 /* Called when all planes have been fetched, i.e. when a new block
 of data is available to be displayed.  The data in fetched[] is
 moved into todisplay[].  */
-static void beginning_of_plane_block(int hpos, int fm)
+static void beginning_of_plane_block(int hpos)
 {
-       flush_display(fm);
+       flush_display(fetchmode);
 
-       if (fm == 0 && (!currprefs.chipset_hr || !ALL_SUBPIXEL))
+       if (fetchmode == 0 && (!currprefs.chipset_hr || !ALL_SUBPIXEL))
                for (int i = 0; i < MAX_PLANES; i++) {
                        todisplay[i] = fetched[i];
                }
@@ -2677,12 +2785,17 @@ static void beginning_of_plane_block(int hpos, int fm)
                        thisline_decision.plfleft = left * 2;
                        bpl_shifter = true;
                        reset_bpl_vars();
+                       if (hdiwstate == DIW_waiting_stop && thisline_decision.diwfirstword < 0) {
+                               thisline_decision.diwfirstword = min_diwlastword;
+                       }
                }
        }
 
+       hbstrt_bordercheck(hpos);
+
        update_denise(hpos);
        if (toscr_nr_planes_agnus > thisline_decision.nr_planes) {
-               update_toscr_planes(fm);
+               update_toscr_planes(fetchmode);
        }
 }
 
@@ -3015,7 +3128,7 @@ static void long_fetch_64_1 (int hpos, int nwords) { long_fetch_64 (hpos, nwords
 
 static void do_long_fetch(int hpos, int nwords, int fm)
 {
-       beginning_of_plane_block(hpos, fm);
+       beginning_of_plane_block(hpos);
 
        // adjust to current resolution
        nwords >>= 3 - toscr_res;
@@ -3061,8 +3174,7 @@ static void do_long_fetch(int hpos, int nwords, int fm)
        out_nbits += nwords * 16;
        out_offs += out_nbits >> 5;
        out_nbits &= 31;
-       delay_cycles += (nwords * 16) << toscr_res_pixels_shift;
-       delay_cycles2 += (nwords * 16) << toscr_res_pixels_shift;
+       quick_add_delay_cycles((nwords * 16) << toscr_res_pixels_shift);
 
        plane0 = toscr_nr_planes > 0;
 }
@@ -3196,6 +3308,14 @@ STATIC_INLINE void one_fetch_cycle_0(int hpos, int fm)
                cycle_line_pipe[hpos] = 0;
        }
 
+       if (plane0p_enabled) {
+               int offset = get_rga_pipeline(hpos, 1);
+               uae_u16 d = cycle_line_pipe[offset];
+               if ((d & CYCLE_PIPE_BITPLANE) && (d & 7) == 1) {
+                       plane0p = true;
+               }
+       }
+
        fetch_cycle++;
        toscr_nbits += toscr_res2p;
 
@@ -3264,6 +3384,9 @@ static void update_fetch(int until, int fm)
                        last_fetch_hpos = until;
                        return;
                }
+               if (plane0p) {
+                       beginning_of_plane_block_early(hpos);
+               }
                if (plane0) {
                        break;
                }
@@ -3300,8 +3423,9 @@ static void update_fetch(int until, int fm)
 
                        int stoppos = hpos + count;
 
-                       if (thisline_decision.plfleft < 0) {
+                       if (speedup_first) {
                                compute_toscr_delay(bplcon1);
+                               speedup_first = false;
                        }
 
                        do_long_fetch(hpos, count, fm);
@@ -3347,8 +3471,11 @@ static void update_fetch(int until, int fm)
        }
 #endif
        while (hpos < until) {
+               if (plane0p) {
+                       beginning_of_plane_block_early(hpos);
+               }
                if (plane0) {
-                       beginning_of_plane_block(hpos, fm);
+                       beginning_of_plane_block(hpos);
                }
                one_fetch_cycle(hpos, fm);
                hpos++;
@@ -3380,22 +3507,7 @@ static void decide_bpl_fetch(int endhpos)
                        } else {
                                int diff = endhpos - hpos;
                                int total = diff << (1 + LORES_TO_SHRES_SHIFT);
-                               while (total > 0) {
-                                       int total2 = total;
-                                       if (delay_cycles2 <= delay_lastcycle[lol] && delay_cycles2 + total2 > delay_lastcycle[lol]) {
-                                               total2 = delay_lastcycle[lol] - delay_cycles2;
-                                       }
-                                       if (delay_cycles2 <= delay_hsynccycle && delay_cycles2 + total2 > delay_hsynccycle) {
-                                               total2 = delay_hsynccycle - delay_cycles2;
-                                       }
-                                       delay_cycles += total2;
-                                       delay_cycles2 += total2;
-                                       total -= total2;
-                                       if (total <= 0) {
-                                               break;
-                                       }
-                                       toscr_special(1, fetchmode);
-                               }
+                               quick_add_delay_cycles(total);
                        }
                        last_fetch_hpos = endhpos;
                }
@@ -3462,7 +3574,7 @@ static void record_color_change(int hpos, int regno, uae_u32 value)
        if (regno < RECORDED_REGISTER_CHANGE_OFFSET && nodraw())
                return;
        /* vsync period don't appear on-screen. */
-       if (vpos >= maxvpos_display_vsync && vpos < minfirstline)
+       if (vpos >= maxvpos_display_vsync && vpos < minfirstline - 1)
                return;
 
        decide_diw(hpos);
@@ -3508,9 +3620,9 @@ static bool isbrdblank(int hpos, uae_u16 bplcon0, uae_u16 bplcon3)
        // extblankmode = use hardwired or programmed blanking
        if (aga_mode) {
                extblank = true;
-               extblankmode = (bplcon0 & 1) && (bplcon3 & 0x01);
+               extblankmode = (bplcon0 & 1) && (bplcon3 & 1);
        } else {
-               extblank = !ecs_denise || !(bplcon0 & 1) || ((bplcon0 & 1) && (bplcon3 & 0x01));
+               extblank = !ecs_denise || !(bplcon0 & 1) || ((bplcon0 & 1) && (bplcon3 & 1));
                extblankmode = false;
        }
 #else
@@ -3521,7 +3633,7 @@ static bool isbrdblank(int hpos, uae_u16 bplcon0, uae_u16 bplcon3)
 #endif
        if (hpos >= 0 && (ce_is_borderblank(current_colors.extra) != brdblank || ce_is_borderntrans(current_colors.extra) != brdntrans
                || ce_is_extblankset(current_colors.extra) != extblank || ce_is_extblankmode(current_colors.extra) != extblankmode)) {
-               record_color_change(hpos, 0, COLOR_CHANGE_BRDBLANK | (brdblank ? 1 : 0) | (ce_is_bordersprite(current_colors.extra) ? 2 : 0) | (brdntrans ? 4 : 0) | (extblank ? 8 : 0));
+               record_color_change(hpos, 0, COLOR_CHANGE_BRDBLANK | (brdblank ? 1 : 0) | (ce_is_bordersprite(current_colors.extra) ? 2 : 0) | (brdntrans ? 4 : 0) | (extblank ? 8 : 0) | (extblankmode ? 16 : 0));
                current_colors.extra &= ~(1 << CE_BORDERBLANK);
                current_colors.extra &= ~(1 << CE_BORDERNTRANS);
                current_colors.extra &= ~(1 << CE_EXTBLANKSET);
@@ -3550,12 +3662,14 @@ static bool issprbrd(int hpos, uae_u16 bplcon0, uae_u16 bplcon3)
        brdsprt = false;
 #endif
        if (hpos >= 0 && ce_is_bordersprite(current_colors.extra) != brdsprt) {
-               record_color_change(hpos, 0, COLOR_CHANGE_BRDBLANK | (ce_is_borderblank(current_colors.extra) ? 1 : 0) | (ce_is_borderntrans(current_colors.extra) ? 4 : 0) | (brdsprt ? 2 : 0));
+               record_color_change(hpos, 0, COLOR_CHANGE_BRDBLANK | (ce_is_borderblank(current_colors.extra) ? 1 : 0) | (brdsprt ? 2 : 0) |
+                       (ce_is_borderntrans(current_colors.extra) ? 4 : 0) | (ce_is_extblankset(current_colors.extra) ? 8 : 0) | (ce_is_extblankmode(current_colors.extra) ? 16 : 0));
                current_colors.extra &= ~(1 << CE_BORDERSPRITE);
                current_colors.extra |= brdsprt ? (1 << CE_BORDERSPRITE) : 0;
                remembered_color_entry = -1;
-               if (brdsprt && !ce_is_borderblank(current_colors.extra))
+               if (brdsprt && !ce_is_borderblank(current_colors.extra)) {
                        thisline_decision.bordersprite_seen = true;
+               }
        }
        return brdsprt && !ce_is_borderblank(current_colors.extra);
 }
@@ -4219,13 +4333,10 @@ static void finish_decisions(int hpos)
        /* Large DIWSTOP values can cause the stop position never to be
        * reached, so the state machine always stays in the same state and
        * there's a more-or-less full-screen DIW. */
-       if (hdiwstate == DIW_waiting_stop) {
+       if (hdiwstate == DIW_waiting_stop && thisline_decision.diwfirstword >= 0) {
                thisline_decision.diwlastword = max_diwlastword;
-               if (thisline_decision.diwfirstword <= 0) {
-                       thisline_decision.diwfirstword = -1;
-               }
-               last_diwlastword_cc = -1;
        }
+       last_diwlastword = -1;
 
        if (thisline_decision.diwfirstword != line_decisions[next_lineno].diwfirstword) {
                MARK_LINE_CHANGED;
@@ -4333,7 +4444,7 @@ static void reset_decisions_hsync_start(void)
                return;
        }
 
-       toscr_nr_planes = toscr_nr_planes2 = 0;
+       //toscr_nr_planes = toscr_nr_planes2 = 0;
 
        /* decided_res shouldn't be touched before it's initialized by decide_line(). */
        thisline_decision.diwfirstword = -2;
@@ -4363,7 +4474,8 @@ static void reset_decisions_hsync_start(void)
 
        hack_delay_shift = 0;
 
-       last_diwlastword_cc = -1;
+       last_diwlastword = -1;
+       hb_last_diwlastword = -1;
 
        if (line_cyclebased > 0) {
                line_cyclebased--;
@@ -4393,8 +4505,8 @@ static void reset_decisions_hsync_start(void)
                thisline_decision.vb = 1;
        }
 #endif
-       bplcon0d_old = -1;
-       toscr_res_old = -1;
+       //bplcon0d_old = -1;
+       //toscr_res_old = -1;
 
        int left = thisline_decision.plfleft;
 
@@ -4411,25 +4523,20 @@ static void reset_decisions_hsync_start(void)
        hpos_hsync_extra = 0;
        int hpos = current_hpos();
        bool normalstart = true;
+       plane0p_enabled = false;
+       speedup_first = true;
        delay_cycles = ((hpos) * 2 - DDF_OFFSET + 0) << LORES_TO_SHRES_SHIFT;
        delay_cycles2 = delay_cycles;
        set_delay_lastcycle();
-       if (1 && fetchmode > 0) {
+
+       //bpl_shifter = true;
+       if (1 && fetchmode >= 2) {
                // handle bitplane data wrap around
-               bool toshift = false;
-#if 0
-               for (int i = 0; i < thisline_decision.nr_planes; i++) {
-                       if (todisplay2_aga[i] && fetchmode > 1) {
-                               toshift = true;
-                       }
-               }
-#endif
-               if (bprun != 0 || todisplay_fetched[0] || toshift || plane0) {
+               if (bprun != 0 || todisplay_fetched[0] || plane0 || plane0p || plane0_prehsync) {
                        normalstart = false;
                        SET_LINE_CYCLEBASED;
                        //thisline_decision.plfleft = hpos;
                        bpl_shifter = true;
-                       toscr_nr_planes2 = toscr_nr_planes = thisline_decision.nr_planes;
                        if (toscr_hend == 2) {
                                for (int i = 0; i < MAX_PLANES; i++) {
                                        todisplay[i] = todisplay_saved[i];
@@ -4439,19 +4546,26 @@ static void reset_decisions_hsync_start(void)
                                }
                                todisplay_fetched[0] = todisplay_fetched_saved[0];
                                todisplay_fetched[1] = todisplay_fetched_saved[1];
-                               memset(outword, 0, sizeof outword);
-                               memset(outword64, 0, sizeof outword64);
+                       }
+                       if (plane0p) {
+                               beginning_of_plane_block_early(hpos);
+                               plane0p = false;
                        }
                        if (plane0) {
-                               beginning_of_plane_block(hpos, fetchmode);
+                               beginning_of_plane_block(hpos);
                                plane0 = false;
                        }
                }
+               // make sure bprun stays enabled until next line
+               bprun_pipeline_flush_delay = maxhpos;
+               plane0p_enabled = true;
        }
+
        if (normalstart) {
                plane0 = false;
-               thisline_decision.bplres = output_res(bplcon0_res);
-               thisline_decision.nr_planes = 0;
+               plane0p = false;
+               //thisline_decision.bplres = output_res(bplcon0_res);
+               //thisline_decision.nr_planes = 0;
                memset(outword, 0, sizeof outword);
                // fetched[] must not be cleared (Sony VX-90 / Royal Amiga Force)
                todisplay_fetched[0] = todisplay_fetched[1] = false;
@@ -4466,9 +4580,7 @@ static void reset_decisions_hsync_start(void)
 #endif
        }
 
-       if (bprun_pipeline_flush_delay < 0 && !bprun) {
-               bprun_pipeline_flush_delay = 0;
-       }
+       plane0_prehsync = false;
        toscr_hend = 0;
 }
 
@@ -4607,18 +4719,28 @@ static void updateextblk(void)
        if (aga_mode) {
                hbstop_v |= (hbstop >> 8) & 7;
        }
-       // 1.5 hires pixel offset
-       hbstrt_v2 = hbstrt_v - 3;
-       if (hbstrt_v >= (1 << CCK_SHRES_SHIFT) && hbstrt_v2 < (1 << CCK_SHRES_SHIFT)) {
-               hbstrt_v2 += maxhpos << CCK_SHRES_SHIFT;
-       }
-       hbstop_v2 = hbstop_v - 3;
-       if (hbstop_v >= (1 << CCK_SHRES_SHIFT) && hbstop_v2 < (1 << CCK_SHRES_SHIFT)) {
-               hbstop_v2 += maxhpos << CCK_SHRES_SHIFT;
+       if (aga_mode) {
+               // 1.5 hires pixel offset
+               hbstrt_v2 = hbstrt_v - 3;
+               if (hbstrt_v >= (1 << CCK_SHRES_SHIFT) && hbstrt_v2 < (1 << CCK_SHRES_SHIFT)) {
+                       hbstrt_v2 += maxhpos << CCK_SHRES_SHIFT;
+               }
+               hbstop_v2 = hbstop_v - 3;
+               if (hbstop_v >= (1 << CCK_SHRES_SHIFT) && hbstop_v2 < (1 << CCK_SHRES_SHIFT)) {
+                       hbstop_v2 += maxhpos << CCK_SHRES_SHIFT;
+               }
+               exthblank = (bplcon0 & 1) && (bplcon3 & 1);
+       } else {
+               if (new_beamcon0 & new_beamcon0 & 0x0010) { // VARCSYEN
+                       // ECS HBLANK uses CSYNC input and matches HSSYNC period.
+                       hbstrt_v2 = (hsstrt & 0xff) << CCK_SHRES_SHIFT;
+                       hbstop_v2 = (hsstop & 0xff) << CCK_SHRES_SHIFT;
+                       exthblank = (bplcon0 & 1) && !(bplcon3 & 1);
+               } else {
+                       exthblank = false;
+               }
        }
 
-       exthblank = (bplcon0 & 1) && (bplcon3 & 1);
-
        if (new_beamcon0 & 0x0110) { // VARHSYEN | VARCSYEN
 
                hsyncstartpos = hsstrt;
@@ -4683,18 +4805,15 @@ static void updateextblk(void)
                hbstop_v2 += maxhpos << CCK_SHRES_SHIFT;
        }
 
-       if (currprefs.chipset_hr) {
-               hbstrt_v2 &= ~(3 >> currprefs.gfx_resolution);
-               hbstop_v2 &= ~(3 >> currprefs.gfx_resolution);
-       } else {
-               hbstrt_v2 &= ~3;
-               hbstop_v2 &= ~3;
-       }
+       adjust_hr(&hbstrt_v2);
+       adjust_hr(&hbstop_v2);
 
        hsyncstartpos_start_hw <<= CCK_SHRES_SHIFT;
        hsyncstartpos_hw <<= CCK_SHRES_SHIFT;
        hsyncendpos_hw <<= CCK_SHRES_SHIFT;
 
+       hsyncstartpos_start_cycles = hsyncstartpos_start;
+
        hsyncstartpos_start <<= CCK_SHRES_SHIFT;
        hsyncstartpos <<= CCK_SHRES_SHIFT;
        hsyncendpos <<= CCK_SHRES_SHIFT;
@@ -4713,7 +4832,7 @@ struct chipset_refresh *get_chipset_refresh(struct uae_prefs *p)
        struct amigadisplay *ad = &adisplays[0];
        int islace = interlace_seen ? 1 : 0;
        int isntsc = (beamcon0 & 0x20) ? 0 : 1;
-       int custom = (beamcon0 & 0x80) ? 1 : 0;
+       int custom = programmedmode == 1 ? 1 : 0;
 
        if (!ecs_agnus) {
                isntsc = currprefs.ntscmode ? 1 : 0;
@@ -4832,7 +4951,7 @@ void compute_framesync(void)
        vidinfo->drawbuffer.inyoffset = -1;
        updateextblk();
 
-       if (new_beamcon0 & 0x80) {
+       if (programmedmode == 1) {
                int res = GET_RES_AGNUS (bplcon0);
                int vres = islace ? 1 : 0;
                int res2, vres2;
@@ -4879,7 +4998,7 @@ void compute_framesync(void)
                        vidinfo->drawbuffer.extrawidth = -1;
                }
                vidinfo->drawbuffer.inwidth2 = vidinfo->drawbuffer.inwidth;
-               vidinfo->drawbuffer.inheight = (maxvpos_display - minfirstline + maxvpos_display_vsync) << currprefs.gfx_vresolution;
+               vidinfo->drawbuffer.inheight = (maxvpos_display + maxvpos_display_vsync - minfirstline) << currprefs.gfx_vresolution;
                vidinfo->drawbuffer.inheight2 = vidinfo->drawbuffer.inheight;
                vidinfo->drawbuffer.inxoffset = 0;
        }
@@ -5030,14 +5149,11 @@ static void init_hz(bool checkvposw)
        vblank_lastline_hw = maxvpos + maxvpos_display_vsync + vblank_extraline;
        vblank_firstline_hw = minfirstline;
 
-       int maxvpos_display_vsync_hw = maxvpos_display_vsync;
        int minfirstline_hw = minfirstline;
        if (currprefs.gfx_overscanmode == OVERSCANMODE_EXTREME) {
                minfirstline_hw -= EXTRAHEIGHT_EXTREME / 2;
-               maxvpos_display_vsync_hw += EXTRAHEIGHT_EXTREME / 2;
        } else if (currprefs.gfx_overscanmode == OVERSCANMODE_BROADCAST) {
-               minfirstline_hw -= EXTRAHEIGHT_BROADCAST / 2;
-               maxvpos_display_vsync_hw += EXTRAHEIGHT_BROADCAST / 2;
+               minfirstline_hw -= EXTRAHEIGHT_BROADCAST_TOP;
        }
        if (beamcon0 & 0x0080) {
                minfirstline_hw = 0;
@@ -5073,27 +5189,25 @@ static void init_hz(bool checkvposw)
                }
                minfirstline++;
                firstblankedline = vbstrt;
+               if (vsstrt > 0 && vsstrt < maxvpos / 2) {
+                       maxvpos_display_vsync += vsstrt;
+               }
        } else if (beamcon0 & (0x0200 | 0x0010)) { // VARVSYEN | VARCSYEN
                firstblankedline = maxvpos + 1;
        } else if (beamcon0 & 0x1000) { // VARVBEN
                firstblankedline = vbstrt;
+               if (vsstrt > 0 && vsstrt < maxvpos / 2) {
+                       maxvpos_display_vsync += vsstrt;
+               }
        } else {
                firstblankedline = maxvpos + 1;
        }
 
        if (beamcon0 & (0x1000 | 0x0200 | 0x0010)) {
-               maxvpos_display_vsync = 4;
                programmedmode = 2;
        }
 
        int eh = currprefs.gfx_extraheight;
-       if (eh <= 0) {
-               if (currprefs.gfx_overscanmode == OVERSCANMODE_EXTREME) {
-                       eh = EXTRAHEIGHT_EXTREME;
-               } else if (currprefs.gfx_overscanmode == OVERSCANMODE_BROADCAST) {
-                       eh = EXTRAHEIGHT_BROADCAST;
-               }
-       }
        if (eh > 0) {
                if (beamcon0 & (0x0200 | 0x0010)) {
                        maxvpos_display_vsync += eh / 2;
@@ -5123,15 +5237,12 @@ static void init_hz(bool checkvposw)
        }
 
        if (firstblankedline < minfirstline) {
-               firstblankedline = maxvpos + 1;
+               firstblankedline = maxvpos + maxvpos_display_vsync + 1;
        }
 
        if (minfirstline < minfirstline_hw) {
                minfirstline = minfirstline_hw;
        }
-       if (maxvpos_display_vsync > maxvpos_display_vsync_hw) {
-               maxvpos_display_vsync = maxvpos_display_vsync_hw;
-       }
 
        if (beamcon0 & (0x0200 | 0x0010)) {
                if (maxvpos_display_vsync >= vsstop - 3) {
@@ -5174,11 +5285,16 @@ static void init_hz(bool checkvposw)
                maxvpos_nom = maxvpos;
                maxvpos_display = maxvpos;
                equ_vblank_endline = -1;
-               doublescan = htotal <= 164 && vtotal >= 350 ? 1 : 0;
-               // if superhires and wide enough: not doublescan
-               if (doublescan && htotal >= 140 && (bplcon0 & 0x0040))
-                       doublescan = 0;
-               programmedmode = 1;
+
+               programmedmode = 2;
+               if ((htotal < 226 || htotal > 229) || (vtotal < 256 || vtotal > 320)) {
+                       doublescan = htotal <= 164 && vtotal >= 350 ? 1 : 0;
+                       // if superhires and wide enough: not doublescan
+                       if (doublescan && htotal >= 140 && (bplcon0 & 0x0040))
+                               doublescan = 0;
+                       programmedmode = 1;
+               }
+
                varsync_changed = 1;
                vpos_count = maxvpos_nom;
                vpos_count_diff = maxvpos_nom;
@@ -6111,7 +6227,7 @@ static void BEAMCON0(int hpos, uae_u16 v)
        }
 }
 
-static void varsync(void)
+static void varsync(bool resync)
 {
        struct amigadisplay *ad = &adisplays[0];
        if (!ecs_agnus) {
@@ -6124,6 +6240,9 @@ static void varsync(void)
        }
 #endif
        updateextblk();
+       if (resync) {
+               varsync_changed = 1;
+       }
 }
 
 #ifdef PICASSO96
@@ -6424,7 +6543,7 @@ static void BPLxDAT_next(uae_u32 v)
        int hpos = current_hpos();
 
        // only BPL1DAT access can do anything visible
-       if (num == 0 && hpos >= (hsyncstartpos_start >> CCK_SHRES_SHIFT)) {
+       if (num == 0 && hpos >= hsyncstartpos_start_cycles) {
                decide_line(hpos);
                decide_fetch_safe(hpos);
        }
@@ -6446,12 +6565,12 @@ static void BPLxDAT(int hpos, int num, uae_u16 v)
        uae_u32 vv = (num << 16) | v;
        BPLxDAT_next(vv);
 
-       if (num == 0 && hpos >= (hsyncstartpos_start >> CCK_SHRES_SHIFT)) {
+       if (num == 0 && hpos >= hsyncstartpos_start_cycles) {
                if (thisline_decision.plfleft < 0) {
                        reset_bpl_vars();
                }
-               beginning_of_plane_block(hpos, fetchmode);
-               bprun_pipeline_flush_delay = -1;
+               beginning_of_plane_block(hpos);
+               bprun_pipeline_flush_delay = maxhpos;
                SET_LINE_CYCLEBASED;
        }
 }
@@ -7336,7 +7455,7 @@ static void decide_line(int endhpos)
                        if (bprun < 0) {
                                decide_line_decision_fetches(hpos);
                                bprun = 1;
-                               bprun_pipeline_flush_delay = -2;
+                               bprun_pipeline_flush_delay = maxhpos;
                                bprun_cycle = 0;
                        }
 
@@ -7357,7 +7476,7 @@ static void decide_line(int endhpos)
                                        }
                                }
                                bprun = 0;
-                               bprun_pipeline_flush_delay = -2;
+                               bprun_pipeline_flush_delay = maxhpos;
                                SET_LINE_CYCLEBASED;
                                end_estimate_last_fetch_cycle(hpos);
                        }
@@ -7422,7 +7541,7 @@ static void decide_line(int endhpos)
                                }
                                bprun_start(hpos);
                                if (ddf_stopping) {
-                                       bprun_pipeline_flush_delay = -2;
+                                       bprun_pipeline_flush_delay = maxhpos;
                                }
                        }
 
@@ -7442,14 +7561,14 @@ static void decide_line(int endhpos)
                        if (bprun < 0) {
                                decide_line_decision_fetches(hpos);
                                bprun = 1;
-                               bprun_pipeline_flush_delay = -2;
+                               bprun_pipeline_flush_delay = maxhpos;
                                bprun_cycle = 0;
                        }
                        // BPRUN latched: off
                        if (bprun == 2) {
                                decide_line_decision_fetches(hpos);
                                bprun = 0;
-                               bprun_pipeline_flush_delay = -2;
+                               bprun_pipeline_flush_delay = maxhpos;
                                // If DDF has passed, jumps to last step.
                                // (For example Scoopex Crash landing crack intro)
                                if (ddf_stopping == 1) {
@@ -7499,7 +7618,7 @@ static void decide_line(int endhpos)
                                }
                                bprun_start(hpos);
                                if (ddf_stopping) {
-                                       bprun_pipeline_flush_delay = -2;
+                                       bprun_pipeline_flush_delay = maxhpos;
                                }
                        }
 
@@ -8149,12 +8268,6 @@ void blitter_done_notify(int blitline)
        event2_newevent_xx(-1, 1 * CYCLE_UNIT, 0, blitter_done_notify_wakeup);
 }
 
-void do_copper(void)
-{
-       int hpos = current_hpos();
-       update_copper(hpos);
-}
-
 static void sync_copper(int hpos)
 {
        if (copper_enabled_thisline) {
@@ -8403,10 +8516,6 @@ static void decide_sprite_fetch(int endhpos)
                                if (slot == 0 || slot == 2) {
                                        struct sprite *s = &spr[num];
                                        if (slot == 0) {
-                                               if (vb_end_line) {
-                                                       s->dmastate = 0;
-                                                       s->dmacycle = 0;
-                                               }
                                                if (!s->dmacycle && s->dmastate) {
                                                        s->dmacycle = 1;
                                                }
@@ -8422,7 +8531,7 @@ static void decide_sprite_fetch(int endhpos)
                                                        s->dmacycle = 1;
                                                }
                                        }
-                                       if (dmaen(DMA_SPRITE) && hpos <= plfstrt_sprite && s->dmacycle) {
+                                       if (dmaen(DMA_SPRITE) && hpos <= plfstrt_sprite && s->dmacycle && !vb_end_line) {
                                                bool dodma = true;
 #ifdef AGA
                                                if (s->dblscan && (fmode & 0x8000) && (vpos & 1) != (s->vstart & 1) && s->dmastate) {
@@ -8441,7 +8550,7 @@ static void decide_sprite_fetch(int endhpos)
                                                        cycle_line_pipe[offset] = dat;
                                                }
                                        }
-                                       if (s->dmacycle) {
+                                       if (!vb_end_line && s->dmacycle) {
                                                s->dmacycle++;
                                                if (s->dmacycle > 2) {
                                                        s->dmacycle = 0;
@@ -9437,7 +9546,7 @@ static void reset_autoscale(void)
 static void hautoscale_check(void)
 {
        // border detection/autoscale
-       if (GET_PLANES(bplcon0) > 0 && dmaen(DMA_BITPLANE)) {
+       if (GET_PLANES(bplcon0) > 0 && dmaen(DMA_BITPLANE) && !vb_state && !vb_end_line && !vb_start_line) {
                if (first_bplcon0 == 0) {
                        first_bplcon0 = bplcon0;
                }
@@ -9594,17 +9703,18 @@ static void hsync_handler_pre(bool onvsync)
                        sprite_0 = 0;
                }
 
-               if (!lightpen_triggered && !vb_state && (bplcon0 & 8)) {
+               if (!lightpen_triggered && (bplcon0 & 8)) {
                        // lightpen always triggers at the beginning of the last line
-                       if (vpos + 1 == maxvpos + lof_store) {
+                       if (vb_start_line == 1) {
                                vpos_lpen = vpos;
                                hpos_lpen = 1;
                                hhpos_lpen = HHPOSR();
                                lightpen_triggered = 1;
-                       } else if (lightpen_enabled) {
+                       } else if (lightpen_enabled && !vb_state) {
                                int lpnum = inputdevice_get_lightpen_id();
-                               if (lpnum < 0)
+                               if (lpnum < 0) {
                                        lpnum = 0;
+                               }
                                if (lightpen_cx[lpnum] > 0 && lightpen_cy[lpnum] == vpos) {
                                        event2_newevent_xx(-1, lightpen_cx[lpnum] * CYCLE_UNIT, lightpen_cx[lpnum], lightpen_trigger_func);
                                }
@@ -9648,7 +9758,7 @@ static void hsync_handler_pre(bool onvsync)
        // to record decisions correctly between end of scanline and start of hsync
        hpos_hsync_extra = maxhpos;
        if (!eventtab[ev_hsynch].active) {
-               eventtab[ev_hsynch].evtime = get_cycles() + (hsyncstartpos_start >> CCK_SHRES_SHIFT) * CYCLE_UNIT;
+               eventtab[ev_hsynch].evtime = get_cycles() + hsyncstartpos_start_cycles * CYCLE_UNIT;
                eventtab[ev_hsynch].active = 1;
                events_schedule();
        }
@@ -10529,7 +10639,7 @@ static void hsync_handler_post (bool onvsync)
                                vb_state = true;
                        }
                }
-               if (vpos == hardwired_vbstop) {
+               if (vpos == hardwired_vbstop - 1) {
                        vb_end_line = true;
                        vb_state = false;
                }
@@ -10543,12 +10653,10 @@ static void hsync_handler_post (bool onvsync)
 #ifdef DEBUGGER
                if (debug_dma) {
                        uae_u16 strobe = 0x3c;
-                       if (vpos < equ_vblank_endline) {
+                       if (vb_state && vpos < equ_vblank_endline) {
                                strobe = 0x38;
-                       } else if (vpos < minfirstline) {
+                       } else if (vb_state) {
                                strobe = 0x3a;
-                       } else if (vpos + 1 == maxvpos + lof_store) {
-                               strobe = 0x38;
                        } else if (ecs_agnus && lol) {
                                strobe = 0x3e;
                        }
@@ -10757,7 +10865,7 @@ static void hsync_handler(void)
                        uae_reset(0, 0);
                        return;
                }
-               eventtab[ev_hsynch].evtime = get_cycles() + (hsyncstartpos_start >> CCK_SHRES_SHIFT) * CYCLE_UNIT;
+               eventtab[ev_hsynch].evtime = get_cycles() + hsyncstartpos_start_cycles * CYCLE_UNIT;
                eventtab[ev_hsynch].active = 1;
                events_schedule();
 
@@ -11572,74 +11680,73 @@ static int REGPARAM2 custom_wput_1 (int hpos, uaecptr addr, uae_u32 value, int n
        case 0x1C0:
                if (htotal != value) {
                        htotal = value & (MAXHPOS_ROWS - 1);
-                       varsync();
+                       varsync(1);
                }
                break;
        case 0x1C2:
                if (hsstop != value) {
                        hsstop = value & (MAXHPOS_ROWS - 1);
-                       varsync();
+                       varsync(1);
                }
                break;
        case 0x1C4:
                if (hbstrt != value) {
-                       hbstrt = value & 0x7ff;
-                       varsync();
-                       updateextblk();
                        if (exthblank) {
                                record_color_change2(hpos, 0xffff, 0);
                        }
+                       hbstrt = value & 0x7ff;
+                       varsync(0);
                }
                break;
        case 0x1C6:
                if (hbstop != value) {
-                       hbstop = value & 0x7ff;
-                       varsync();
-                       updateextblk();
                        if (exthblank) {
                                record_color_change2(hpos, 0xffff, 0);
                        }
+                       hbstop = value & 0x7ff;
+                       varsync(0);
                }
                break;
        case 0x1C8:
                if (vtotal != value) {
                        vtotal = value & (MAXVPOS_LINES_ECS - 1);
-                       varsync();
+                       varsync(1);
                }
                break;
        case 0x1CA:
                if (vsstop != value) {
                        vsstop = value & (MAXVPOS_LINES_ECS - 1);
-                       varsync();
+                       varsync(1);
                }
                break;
        case 0x1CC:
                if (vbstrt != value) {
                        vbstrt = value & (MAXVPOS_LINES_ECS - 1);
-                       varsync();
+                       varsync(0);
                }
                break;
        case 0x1CE:
                if (vbstop != value) {
                        vbstop = value & (MAXVPOS_LINES_ECS - 1);
-                       varsync();
+                       varsync(0);
                }
                break;
        case 0x1DE:
                if (hsstrt != value) {
                        hsstrt = value & (MAXHPOS_ROWS - 1);
-                       varsync();
+                       varsync(1);
                }
                break;
        case 0x1E0:
                if (vsstrt != value) {
                        vsstrt = value & (MAXVPOS_LINES_ECS - 1);
-                       varsync();
+                       varsync(1);
                }
                break;
        case 0x1E2:
                if (hcenter != value) {
-                       hcenter = value & (MAXHPOS_ROWS - 1); varsync();
+                       hcenter = value & (MAXHPOS_ROWS - 1);
+                       varsync(0);
                }
                break;
 
@@ -12555,7 +12662,7 @@ static int dma_cycle(uaecptr addr, uae_u32 value, int *mode)
        return hpos_old;
 }
 
-static void sync_ce020(void)
+static void sync_cycles(void)
 {
        unsigned long c;
        int extra;
@@ -12568,6 +12675,13 @@ static void sync_ce020(void)
        }
 }
 
+void do_copper(void)
+{
+       sync_cycles();
+       int hpos = current_hpos();
+       update_copper(hpos);
+}
+
 #define SETIFCHIP \
        if (addr < 0xd80000) \
                last_custom_value1 = v;
@@ -12577,6 +12691,7 @@ uae_u32 wait_cpu_cycle_read(uaecptr addr, int mode)
        uae_u32 v = 0;
        int hpos;
 
+       sync_cycles();
        hpos = dma_cycle(addr, 0xffffffff, &mode);
 
 #ifdef DEBUGGER
@@ -12637,7 +12752,7 @@ uae_u32 wait_cpu_cycle_read_ce020(uaecptr addr, int mode)
        uae_u32 v = 0;
        int hpos;
 
-       sync_ce020();
+       sync_cycles();
        hpos = dma_cycle(0xffffffff, 0xffff, NULL);
 
 #ifdef DEBUGGER
@@ -12693,6 +12808,7 @@ void wait_cpu_cycle_write(uaecptr addr, int mode, uae_u32 v)
 {
        int hpos;
 
+       sync_cycles();
        hpos = dma_cycle(addr, v, &mode);
 
 #ifdef DEBUGGER
@@ -12735,7 +12851,7 @@ void wait_cpu_cycle_write_ce020(uaecptr addr, int mode, uae_u32 v)
 {
        int hpos;
 
-       sync_ce020();
+       sync_cycles();
        hpos = dma_cycle(0xffffffff, 0xffff, NULL);
 
 #ifdef DEBUGGER
@@ -12842,7 +12958,7 @@ bool is_cycle_ce(uaecptr addr)
 
 bool isvga(void)
 {
-       if (!(beamcon0 & 0x80)) {
+       if (programmedmode != 1) {
                return false;
        }
        if (hblank_hz >= 20000) {
@@ -12851,9 +12967,12 @@ bool isvga(void)
        return false;
 }
 
-bool ispal(void)
+bool ispal(int *lines)
 {
-       if (beamcon0 & 0x80) {
+       if (lines) {
+               *lines = maxvpos_display;
+       }
+       if (programmedmode == 1) {
                return currprefs.ntscmode == 0;
        }
        return maxvpos_display >= MAXVPOS_NTSC + (MAXVPOS_PAL - MAXVPOS_NTSC) / 2;
index 4fca20f0564b3731a70ceb75deab7b5a333c527a..db8856699caeed40914f574526261a711598cd21 100644 (file)
@@ -236,11 +236,11 @@ typedef void (*line_draw_func)(int, int, int);
 #define LINE_DONE_AS_PREVIOUS 8
 #define LINE_REMEMBERED_AS_PREVIOUS 9
 
-#define LINESTATE_SIZE ((MAXVPOS + 2) * 2 + 1)
+#define LINESTATE_SIZE ((MAXVPOS + MAXVPOS_WRAPLINES) * 2 + 1)
 
 static uae_u8 linestate[LINESTATE_SIZE];
 
-uae_u8 line_data[(MAXVPOS + 2) * 2][MAX_PLANES * MAX_WORDS_PER_LINE * 2];
+uae_u8 line_data[(MAXVPOS + MAXVPOS_WRAPLINES) * 2][MAX_PLANES * MAX_WORDS_PER_LINE * 2];
 
 /* Centering variables.  */
 static int min_diwstart, max_diwstop;
@@ -497,7 +497,7 @@ static void set_blanking_limits(void)
        bool hardwired = !dp_for_drawing || !ce_is_extblankset(colors_for_drawing.extra) || !ce_is_extblankmode(colors_for_drawing.extra);
        bool doblank = false;
        int hbstrt = (235 << CCK_SHRES_SHIFT) - 3;
-       int hbstop = (47 << CCK_SHRES_SHIFT) - 7;
+       int hbstop = (46 << CCK_SHRES_SHIFT) - 7;
 
        if (currprefs.gfx_overscanmode < OVERSCANMODE_OVERSCAN) {
                int mult = (OVERSCANMODE_OVERSCAN - currprefs.gfx_overscanmode) * 4;
@@ -515,10 +515,10 @@ static void set_blanking_limits(void)
                doblank = true;
        } else if (currprefs.gfx_overscanmode == OVERSCANMODE_BROADCAST) {
                hbstrt = (239 << CCK_SHRES_SHIFT) - 3;
-               hbstop = (47 << CCK_SHRES_SHIFT) - 3;
+               hbstop = (46 << CCK_SHRES_SHIFT) - 7;
                doblank = true;
        }
-       if (doblank && !(new_beamcon0 & 0x80)) {
+       if (doblank && programmedmode != 1) {
                if (new_beamcon0 & 0x0110) {
                        extern uae_u16 hsstrt;
                        hbstrt += (hsstrt - 17) << CCK_SHRES_SHIFT;
@@ -781,7 +781,7 @@ int get_custom_limits (int *pw, int *ph, int *pdx, int *pdy, int *prealh)
                dx = 0;
 
        *prealh = -1;
-       if (programmedmode <= 1 && first_planes_vpos) {
+       if (programmedmode != 1 && first_planes_vpos) {
                int th = (maxvpos - minfirstline) * 95 / 100;
                if (th > h) {
                        th = xshift (th, dbl1);
@@ -795,7 +795,7 @@ int get_custom_limits (int *pw, int *ph, int *pdx, int *pdy, int *prealh)
        if (w == 0 || h == 0)
                return 0;
 
-       if (doublescan <= 0 && programmedmode <= 1) {
+       if (doublescan <= 0 && programmedmode != 1) {
                if ((w >> currprefs.gfx_resolution) < MIN_DISPLAY_W) {
                        dx += (w - (MIN_DISPLAY_W << currprefs.gfx_resolution)) / 2;
                        w = MIN_DISPLAY_W << currprefs.gfx_resolution;
@@ -819,7 +819,7 @@ int get_custom_limits (int *pw, int *ph, int *pdx, int *pdy, int *prealh)
 
        if (w <= 0 || h <= 0 || dx < 0 || dy < 0)
                return ret;
-       if (doublescan <= 0 && programmedmode <= 1) {
+       if (doublescan <= 0 && programmedmode != 1) {
                if (dx > vidinfo->outbuffer->inwidth / 3)
                        return ret;
                if (dy > vidinfo->outbuffer->inheight / 3)
@@ -1882,10 +1882,11 @@ static int linetoscr_16_shrink2f_sh(int spix, int dpix, int stoppos)
 #endif
 
 typedef int(*call_linetoscr)(int spix, int dpix, int dpix_end);
+typedef int(*call_linetoscrb)(int spix, int dpix, int dpix_end, int blank);
 
 static call_linetoscr pfield_do_linetoscr_normal, pfield_do_linetoscr_normal2;
 static call_linetoscr pfield_do_linetoscr_sprite, pfield_do_linetoscr_sprite2;
-static call_linetoscr pfield_do_linetoscr_spriteonly;
+static call_linetoscrb pfield_do_linetoscr_spriteonly;
 
 static void pfield_do_linetoscr(int start, int stop, int blank)
 {
@@ -1901,8 +1902,8 @@ static void pfield_do_linetoscr_spr(int start, int stop, int blank)
 {
        int pixel;
        if (extborder) {
-               pfield_do_fill_line(start, stop, ce_is_borderblank(colors_for_drawing.extra) ? 1 : 0);
-               pixel = pfield_do_linetoscr_spriteonly(src_pixel, start, stop);
+               pfield_do_fill_line(start, stop, ce_is_borderblank(colors_for_drawing.extra) || exthblank ? 1 : 0);
+               pixel = pfield_do_linetoscr_spriteonly(src_pixel, start, stop, ce_is_borderblank(colors_for_drawing.extra) || exthblank);
        } else {
                pixel = pfield_do_linetoscr_sprite(src_pixel, start, stop);
                if (exthblank) {
@@ -1915,6 +1916,10 @@ static int pfield_do_nothing(int a, int b, int c)
 {
        return a;
 }
+static int pfield_do_nothingb(int a, int b, int c, int d)
+{
+       return a;
+}
 
 /* AGA subpixel delay hack */
 static call_linetoscr pfield_do_linetoscr_shdelay_normal;
@@ -1942,11 +1947,11 @@ static int pfield_do_linetoscr_sprite_shdelay(int spix, int dpix, int dpix_end)
                // Crosses real_playfield_start.
                // Render only from dpix to real_playfield_start.
                int len = real_playfield_start - dpix;
-               out = pfield_do_linetoscr_spriteonly(out, dpix, dpix + len);
+               out = pfield_do_linetoscr_spriteonly(out, dpix, dpix + len, false);
                dpix = real_playfield_start;
        } else if (dpix_end <= real_playfield_start) {
                // Does not cross real_playfield_start, nothing special needed.
-               out = pfield_do_linetoscr_spriteonly(out, dpix, dpix_end);
+               out = pfield_do_linetoscr_spriteonly(out, dpix, dpix_end, false);
                return out;
        }
        // Render bitplane with subpixel scroll, from real_playfield_start to end.
@@ -1976,7 +1981,7 @@ static void pfield_set_linetoscr (void)
                p_acolors = direct_colors_for_drawing.acolors;
        }
        spritepixels = spritepixels_buffer;
-       pfield_do_linetoscr_spriteonly = pfield_do_nothing;
+       pfield_do_linetoscr_spriteonly = pfield_do_nothingb;
 #ifdef AGA
        if (aga_mode) {
                if (res_shift == 0) {
@@ -2215,11 +2220,11 @@ static void pfield_set_linetoscr (void)
 // left or right AGA border sprite
 static void pfield_do_linetoscr_bordersprite_aga(int start, int stop, int blank)
 {
-       if (blank) {
+       if (blank || exthblank || extborder) {
                pfield_do_fill_line(start, stop, blank);
                return;
        }
-       pfield_do_linetoscr_spriteonly(src_pixel, start, stop);
+       pfield_do_linetoscr_spriteonly(src_pixel, start, stop, false);
 }
 
 static void dummy_worker (int start, int stop, int blank)
@@ -3052,7 +3057,7 @@ static bool isham(uae_u16 bplcon0)
        return 0;
 }
 
-static void pfield_expand_dp_bplconx (int regno, int v, int vp, int hp)
+static void pfield_expand_dp_bplconx (int regno, int v, int hp, int vp)
 {
        regno -= RECORDED_REGISTER_CHANGE_OFFSET;
        switch (regno)
@@ -3178,93 +3183,95 @@ static void do_color_changes(line_draw_func worker_border, line_draw_func worker
                        nextpos_in_range = endpos;
                }
 
-               // left hblank (left edge to hblank end)
-               if (nextpos_in_range > lastpos && lastpos < hblank_left_start) {
-                       int t = nextpos_in_range <= hblank_left_start ? nextpos_in_range : hblank_left_start;
-                       (*worker_border)(lastpos, t, 1);
-                       lastpos = t;
-               }
-
-               // vblank + extblanken: blanked
-               if (!(vb_state & 1) && ce_is_extblankset(colors_for_drawing.extra) || vp < vblank_top_start || vp >= vblank_bottom_stop) {
-
-                       if (nextpos_in_range > lastpos && lastpos < playfield_end) {
-                               int t = nextpos_in_range <= playfield_end ? nextpos_in_range : playfield_end;
+               if (vp >= 0) {
+                       // left hblank (left edge to hblank end)
+                       if (nextpos_in_range > lastpos && lastpos < hblank_left_start) {
+                               int t = nextpos_in_range <= hblank_left_start ? nextpos_in_range : hblank_left_start;
                                (*worker_border)(lastpos, t, 1);
                                lastpos = t;
                        }
 
-               // normal
-               } else if (playfield_start_pre >= playfield_start || !ce_is_borderblank(colors_for_drawing.extra)) {
+                       // vblank + extblanken: blanked
+                       if (!(vb_state & 1) && ce_is_extblankset(colors_for_drawing.extra) || vp < vblank_top_start || vp >= vblank_bottom_stop) {
 
-                       // normal left border (hblank end to playfield start)
-                       if (nextpos_in_range > lastpos && lastpos < playfield_start) {
-                               int t = nextpos_in_range <= playfield_start ? nextpos_in_range : playfield_start;
-                               (*worker_border)(lastpos, t, 0);
-                               lastpos = t;
-                       }
+                               if (nextpos_in_range > lastpos && lastpos < playfield_end) {
+                                       int t = nextpos_in_range <= playfield_end ? nextpos_in_range : playfield_end;
+                                       (*worker_border)(lastpos, t, 1);
+                                       lastpos = t;
+                               }
+
+                               // normal
+                       } else if (playfield_start_pre >= playfield_start || !ce_is_borderblank(colors_for_drawing.extra)) {
 
-                       // playfield
-                       if (nextpos_in_range > lastpos && lastpos >= playfield_start && lastpos < playfield_end) {
-                               int t = nextpos_in_range <= playfield_end ? nextpos_in_range : playfield_end;
-                               if ((plf2pri >= 5 || plf1pri >= 5) && !aga_mode) {
-                                       weird_bitplane_fix(lastpos, t);
+                               // normal left border (hblank end to playfield start)
+                               if (nextpos_in_range > lastpos && lastpos < playfield_start) {
+                                       int t = nextpos_in_range <= playfield_start ? nextpos_in_range : playfield_start;
+                                       (*worker_border)(lastpos, t, 0);
+                                       lastpos = t;
                                }
-                               if (may_require_hard_way && (may_require_hard_way < 0 || (bplxor && may_require_hard_way && worker_pfield != pfield_do_linetoscr_bordersprite_aga))) {
-                                       playfield_hard_way(worker_pfield, lastpos, t);
-                               } else {
-                                       (*worker_pfield)(lastpos, t, 0);
+
+                               // playfield
+                               if (nextpos_in_range > lastpos && lastpos >= playfield_start && lastpos < playfield_end) {
+                                       int t = nextpos_in_range <= playfield_end ? nextpos_in_range : playfield_end;
+                                       if ((plf2pri >= 5 || plf1pri >= 5) && !aga_mode) {
+                                               weird_bitplane_fix(lastpos, t);
+                                       }
+                                       if (may_require_hard_way && (may_require_hard_way < 0 || (bplxor && may_require_hard_way && worker_pfield != pfield_do_linetoscr_bordersprite_aga))) {
+                                               playfield_hard_way(worker_pfield, lastpos, t);
+                                       } else {
+                                               (*worker_pfield)(lastpos, t, 0);
+                                       }
+                                       lastpos = t;
                                }
-                               lastpos = t;
-                       }
 
-               } else {
-                       // special AGA borderblank 1 hires pixel delay
+                       } else {
+                               // special AGA borderblank 1 hires pixel delay
 
-                       // borderblank left border (hblank end to playfield_start_pre)
-                       if (nextpos_in_range > lastpos && lastpos < playfield_start_pre) {
-                               int t = nextpos_in_range <= playfield_start_pre ? nextpos_in_range : playfield_start_pre;
-                               (*worker_border)(lastpos, t, 0);
-                               lastpos = t;
-                       }
-                       // AGA "buggy" borderblank, real background color visible, single hires pixel wide.
-                       if (nextpos_in_range > lastpos && lastpos < playfield_start) {
-                               int t = nextpos_in_range <= playfield_start ? nextpos_in_range : playfield_start;
-                               (*worker_border)(lastpos, t, -1);
-                               lastpos = t;
-                       }
+                               // borderblank left border (hblank end to playfield_start_pre)
+                               if (nextpos_in_range > lastpos && lastpos < playfield_start_pre) {
+                                       int t = nextpos_in_range <= playfield_start_pre ? nextpos_in_range : playfield_start_pre;
+                                       (*worker_border)(lastpos, t, 0);
+                                       lastpos = t;
+                               }
+                               // AGA "buggy" borderblank, real background color visible, single hires pixel wide.
+                               if (nextpos_in_range > lastpos && lastpos < playfield_start) {
+                                       int t = nextpos_in_range <= playfield_start ? nextpos_in_range : playfield_start;
+                                       (*worker_border)(lastpos, t, -1);
+                                       lastpos = t;
+                               }
 
-                       // playfield with last hires pixel not drawn.
-                       if (nextpos_in_range > lastpos && lastpos >= playfield_start && lastpos < playfield_end_pre) {
-                               int t = nextpos_in_range <= playfield_end_pre ? nextpos_in_range : playfield_end_pre;
-                               if (may_require_hard_way && (may_require_hard_way < 0 || (bplxor && may_require_hard_way && worker_pfield != pfield_do_linetoscr_bordersprite_aga))) {
-                                       playfield_hard_way(worker_pfield, lastpos, t);
-                               } else {
-                                       (*worker_pfield)(lastpos, t, 0);
+                               // playfield with last hires pixel not drawn.
+                               if (nextpos_in_range > lastpos && lastpos >= playfield_start && lastpos < playfield_end_pre) {
+                                       int t = nextpos_in_range <= playfield_end_pre ? nextpos_in_range : playfield_end_pre;
+                                       if (may_require_hard_way && (may_require_hard_way < 0 || (bplxor && may_require_hard_way && worker_pfield != pfield_do_linetoscr_bordersprite_aga))) {
+                                               playfield_hard_way(worker_pfield, lastpos, t);
+                                       } else {
+                                               (*worker_pfield)(lastpos, t, 0);
+                                       }
+                                       lastpos = t;
                                }
-                               lastpos = t;
+
+                               // last 1 hires pixel of playfield blanked
+                               if (nextpos_in_range > lastpos && lastpos >= playfield_end_pre && lastpos < playfield_end) {
+                                       int t = nextpos_in_range <= playfield_end ? nextpos_in_range : playfield_end;
+                                       (*worker_border)(lastpos, t, 0);
+                                       lastpos = t;
+                               }
+
                        }
 
-                       // last 1 hires pixel of playfield blanked
-                       if (nextpos_in_range > lastpos && lastpos >= playfield_end_pre && lastpos < playfield_end) {
-                               int t = nextpos_in_range <= playfield_end ? nextpos_in_range : playfield_end;
+                       // right border (playfield end to hblank start)
+                       if (nextpos_in_range > lastpos && lastpos >= playfield_end_pre) {
+                               int t = nextpos_in_range <= hblank_right_stop ? nextpos_in_range : hblank_right_stop;
                                (*worker_border)(lastpos, t, 0);
                                lastpos = t;
                        }
 
-               }
-
-               // right border (playfield end to hblank start)
-               if (nextpos_in_range > lastpos && lastpos >= playfield_end_pre) {
-                       int t = nextpos_in_range <= hblank_right_stop ? nextpos_in_range : hblank_right_stop;
-                       (*worker_border)(lastpos, t, 0);
-                       lastpos = t;
-               }
-
-               // right hblank (hblank start to right edge, hblank start may be earlier than playfield end)
-               if (nextpos_in_range > hblank_right_stop) {
-                       (*worker_border) (hblank_right_stop, nextpos_in_range, 1);
-                       lastpos = nextpos_in_range;
+                       // right hblank (hblank start to right edge, hblank start may be earlier than playfield end)
+                       if (nextpos_in_range > hblank_right_stop) {
+                               (*worker_border) (hblank_right_stop, nextpos_in_range, 1);
+                               lastpos = nextpos_in_range;
+                       }
                }
 
                if (i < dip_for_drawing->last_color_change) {
@@ -3309,14 +3316,14 @@ static void do_color_changes(line_draw_func worker_border, line_draw_func worker
                }
        }
 #if 1
-       if (vp < visible_top_start || vp >= visible_bottom_stop || vp < vblank_top_start || vp >= vblank_bottom_stop) {
+       if (vp >= 0 && (vp < visible_top_start || vp >= visible_bottom_stop || vp < vblank_top_start || vp >= vblank_bottom_stop)) {
                // outside of visible area
                // Just overwrite with black. Above code needs to run because of custom registers,
                // not worth the trouble for separate code path just for max 10 lines or so
-               (*worker_border)(visible_left_border, visible_right_border - visible_left_border, 1);
+               (*worker_border)(visible_left_border, visible_right_border, 1);
        }
 #endif
-       if (hsync_shift_hack > 0) {
+       if (vp >= 0 && hsync_shift_hack > 0) {
                // hpos shift hack
                int shift = (hsync_shift_hack << lores_shift) * vidinfo->drawbuffer.pixbytes;
                if (shift) {
@@ -3603,7 +3610,7 @@ static void center_image (void)
                        }
                }
 #endif
-       } else if (vidinfo->drawbuffer.extrawidth > 0 || ew == -1 || currprefs.gfx_overscanmode == OVERSCANMODE_EXTREME) {
+       } else if (vidinfo->drawbuffer.extrawidth > 0 || currprefs.gfx_overscanmode == OVERSCANMODE_EXTREME) {
                // wide mode
                visible_left_border = (hsync_end_left_border * 2) << currprefs.gfx_resolution;
        } else if (vidinfo->drawbuffer.extrawidth > 0 || ew == -1) {
@@ -3699,7 +3706,6 @@ static void init_drawing_frame (void)
 {
        struct amigadisplay *ad = &adisplays[0];
        struct vidbuf_description *vidinfo = &ad->gfxvidinfo;
-       int i, maxline;
        static int frame_res_old;
 
        int largest_res = 0;
@@ -3719,7 +3725,7 @@ static void init_drawing_frame (void)
 
        if (currprefs.gfx_resolution == changed_prefs.gfx_resolution && lines_count > 0) {
 
-               if (currprefs.gfx_autoresolution_vga && programmedmode > 1 && vidinfo->gfx_resolution_reserved >= RES_HIRES && vidinfo->gfx_vresolution_reserved >= VRES_DOUBLE) {
+               if (currprefs.gfx_autoresolution_vga && programmedmode == 1 && vidinfo->gfx_resolution_reserved >= RES_HIRES && vidinfo->gfx_vresolution_reserved >= VRES_DOUBLE) {
                        if (largest_res == RES_SUPERHIRES && (vidinfo->gfx_resolution_reserved < RES_SUPERHIRES || vidinfo->gfx_vresolution_reserved < 1)) {
                                // enable full doubling/superhires support if programmed mode. It may be "half-width" only and may fit in normal display window.
                                vidinfo->gfx_resolution_reserved = RES_SUPERHIRES;
@@ -3857,8 +3863,8 @@ static void init_drawing_frame (void)
        if (thisframe_first_drawn_line > thisframe_last_drawn_line)
                thisframe_last_drawn_line = thisframe_first_drawn_line;
 
-       maxline = ((maxvpos_display + 1) << linedbl) + 2;
-       for (i = 0; i < maxline; i++) {
+       int maxline = ((maxvpos_display + maxvpos_display_vsync + 1) << linedbl) + 2;
+       for (int i = 0; i < maxline; i++) {
                int ls = linestate[i];
                switch (ls) {
                case LINE_DONE_AS_PREVIOUS:
@@ -4027,7 +4033,7 @@ static void lightpen_update(struct vidbuffer *vb, int lpnum)
        if (lightpen_y[lpnum] >= max_ypos_thisframe1 - LIGHTPEN_HEIGHT - 1)
                lightpen_y[lpnum] = max_ypos_thisframe1 - LIGHTPEN_HEIGHT - 2;
 
-       int cx = (((lightpen_x[lpnum] + visible_left_border) >> lores_shift) >> 1) + DISPLAY_LEFT_SHIFT - DIW_DDF_OFFSET - 2;
+       int cx = (((lightpen_x[lpnum] + visible_left_border) >> lores_shift) >> 1) + 29;
 
        int cy = lightpen_y[lpnum];
        cy >>= linedbl;
@@ -4036,14 +4042,15 @@ static void lightpen_update(struct vidbuffer *vb, int lpnum)
        cx += currprefs.lightpen_offset[0];
        cy += currprefs.lightpen_offset[1];
 
-       if (cx < 0x18)
+       if (cx < 0x18) {
                cx = 0x18;
-       if (cx >= maxhpos)
-               cx -= maxhpos;
-       if (cy < minfirstline)
+       }
+       if (cy < minfirstline) {
                cy = minfirstline;
-       if (cy >= maxvpos)
+       }
+       if (cy >= maxvpos) {
                cy = maxvpos - 1;
+       }
 
        if (currprefs.lightpen_crosshair && lightpen_active) {
                for (int i = 0; i < LIGHTPEN_HEIGHT; i++) {
@@ -4130,6 +4137,9 @@ static void draw_frame2(struct vidbuffer *vbin, struct vidbuffer *vbout)
 #endif
 
        set_blanking_limits();
+
+       bool firstline = true;
+       int lastline = thisframe_y_adjust_real - (1 << linedbl);
        for (int i = 0; i < max_ypos_thisframe1; i++) {
                int i1 = i + min_ypos_for_screen;
                int line = i + thisframe_y_adjust_real;
@@ -4138,10 +4148,22 @@ static void draw_frame2(struct vidbuffer *vbin, struct vidbuffer *vbout)
 
                if (whereline >= vbin->inheight)
                        break;
-               if (whereline < 0)
+               if (whereline < 0) {
+                       lastline = line;
                        continue;
+               }
 
-
+               if (firstline) {
+                       if (lastline >= 0) {
+                               // scan line - 1 events, it might have hblank enable for next line.
+                               for (int j = 0; j < 2; j++) {
+                                       dip_for_drawing = curr_drawinfo + lastline;
+                                       do_color_changes(NULL, NULL, -1);
+                                       lastline++;
+                               }
+                       }
+                       firstline = false;
+               }
 
 #if LARGEST_LINE_DEBUG
                if (largest < whereline)
index c98a933928a4ff1b67d1eabf7cf1d28696e2bf3e..e8cd45d4d5d3ff65f2e9f97f3ed6159a9e8aa260 100644 (file)
@@ -394,7 +394,7 @@ void event2_newevent_x_replace(evt t, uae_u32 data, evfunc2 func)
 
 int current_hpos (void)
 {
-       int hp = current_hpos_safe ();
+       int hp = current_hpos_safe();
        if (hp < 0 || hp > 256) {
                gui_message(_T("hpos = %d!?\n"), hp);
                hp = 0;
index 8dca327e96b7bd4c4183bc4accb4b6e89a9ea24a..28923be589436ed8ef520806b97d07051a6c9121 100644 (file)
@@ -130,9 +130,15 @@ static void outlnf (const char *s, ...)
 
 static void out_linetoscr_decl (DEPTH_T bpp, HMODE_T hmode, int aga, int spr, int genlock)
 {
-       outlnf ("static int NOINLINE linetoscr_%s%s%s%s%s(int spix, int dpix, int dpix_end)",
-               get_depth_str (bpp),
-               get_hmode_str (hmode), aga ? "_aga" : "", spr > 0 ? "_spr" : (spr < 0 ? "_spronly" : ""), genlock ? "_genlock" : "");
+       if (spr < 0) {
+               outlnf("static int NOINLINE linetoscr_%s%s%s%s%s(int spix, int dpix, int dpix_end, int blank)",
+                       get_depth_str(bpp),
+                       get_hmode_str(hmode), aga ? "_aga" : "", "_spronly", genlock ? "_genlock" : "");
+       } else {
+               outlnf("static int NOINLINE linetoscr_%s%s%s%s%s(int spix, int dpix, int dpix_end)",
+                       get_depth_str(bpp),
+                       get_hmode_str(hmode), aga ? "_aga" : "", spr > 0 ? "_spr" : "", genlock ? "_genlock" : "");
+       }
 }
 
 static void out_linetoscr_do_srcpix (DEPTH_T bpp, HMODE_T hmode, int aga, CMODE_T cmode, int spr)
@@ -418,7 +424,7 @@ static void out_linetoscr_mode (DEPTH_T bpp, HMODE_T hmode, int aga, int spr, CM
        if (spr >= 0)
                outln (         "    out_val = dpix_val;");
        else
-               outln (         "    out_val = p_acolors[0];");
+               outln (         "    out_val = blank ? 0 : p_acolors[0];");
 
        if (hmode == HMODE_DOUBLE) {
                put_dpixgenlock(0, cmode, aga, genlock, NULL);
index 53d92fe40fd808b2ca4ced7c92562326d126077d..48ce1b055bff201deeaa8cf50467c5aae3572214 100644 (file)
@@ -256,8 +256,10 @@ struct color_change {
 #define MAX_PIXELS_PER_LINE 2048
 #endif
 
+#define MAXVPOS_WRAPLINES 10
+
 /* No divisors for MAX_PIXELS_PER_LINE; we support AGA and SHRES sprites */
-#define MAX_SPR_PIXELS (((MAXVPOS + 1) * 2 + 1) * MAX_PIXELS_PER_LINE)
+#define MAX_SPR_PIXELS (((MAXVPOS + MAXVPOS_WRAPLINES) * 2 + 1) * MAX_PIXELS_PER_LINE)
 
 struct sprite_entry
 {
@@ -284,7 +286,7 @@ extern uae_u16 spixels[MAX_SPR_PIXELS * 2];
 #endif
 
 /* Way too much... */
-#define MAX_REG_CHANGE ((MAXVPOS + 1) * 2 * MAXHPOS)
+#define MAX_REG_CHANGE ((MAXVPOS + MAXVPOS_WRAPLINES) * 2 * MAXHPOS)
 
 extern struct color_entry *curr_color_tables, *prev_color_tables;
 
@@ -326,9 +328,9 @@ struct draw_info {
        int nr_color_changes, nr_sprites;
 };
 
-extern struct decision line_decisions[2 * (MAXVPOS + 2) + 1];
+extern struct decision line_decisions[2 * (MAXVPOS + MAXVPOS_WRAPLINES) + 1];
 
-extern uae_u8 line_data[(MAXVPOS + 2) * 2][MAX_PLANES * MAX_WORDS_PER_LINE * 2];
+extern uae_u8 line_data[(MAXVPOS + MAXVPOS_WRAPLINES) * 2][MAX_PLANES * MAX_WORDS_PER_LINE * 2];
 
 /* Functions in drawing.c.  */
 extern int coord_native_to_amiga_y (int);