From: Toni Wilen Date: Wed, 21 Jan 2015 17:46:45 +0000 (+0200) Subject: 3100b5 X-Git-Tag: 3100~112 X-Git-Url: https://git.unchartedbackwaters.co.uk/w/?a=commitdiff_plain;h=8cd9555e292b4cd61b719e77de2b1efb3e980f72;p=francis%2Fwinuae.git 3100b5 --- diff --git a/custom.cpp b/custom.cpp index a6de4710..d8398f32 100644 --- a/custom.cpp +++ b/custom.cpp @@ -253,8 +253,6 @@ static uaecptr bplpt[8], bplptx[8]; static uaecptr dbplptl[8], dbplpth[8]; static int dbplptl_on[8], dbplpth_on[8], dbplptl_on2, dbplpth_on2; static int bitplane_line_crossing; -static int bitplane_dma_changed_hpos; -static bool ddfstop_matched; static struct color_entry current_colors; unsigned int bplcon0; @@ -389,6 +387,9 @@ static int plf_start_hpos, plf_end_hpos; static int ddfstop_written_hpos; static int bitplane_off_delay; static bool ocs_agnus_ddf_enable_toggle; +static int bpl_dma_off_when_active; +static int bitplane_maybe_start_hpos; +static bool ddfstop_matched; enum plfstate { @@ -695,21 +696,27 @@ static void reset_dbplh (int hpos, int num) static void reset_dbplh_all (int hpos) { if (dbplpth_on2) { - for (int i = 0; i < MAX_PLANES; i++) { - reset_dbplh (hpos, i); + for (int num = 0; num < MAX_PLANES; num++) { + reset_dbplh(hpos, num); } dbplpth_on2 = 0; } } -static void reset_bplldelays (void) +static void reset_dbpll (int hpos, int num) +{ + if (dbplptl_on[num] && hpos >= dbplptl_on[num]) { + bplpt[num] = (bplpt[num] & 0xffff0000) | dbplptl[num]; + dbplptl_on[num] = 0; + dbplptl_on2--; + } +} + +static void reset_dbpll_all (int hpos) { if (dbplptl_on2) { - for (int i = 0; i < MAX_PLANES; i++) { - if (dbplptl_on[i]) { - bplpt[i] = (bplpt[i] & 0xffff0000) | dbplptl[i]; - dbplptl_on[i] = 0; - } + for (int num = 0; num < MAX_PLANES; num++) { + reset_dbpll(hpos, num); } dbplptl_on2 = 0; } @@ -751,7 +758,7 @@ static void add_modulo (int hpos, int nr) bplpt[nr] += mod; bplptx[nr] += mod; reset_moddelays (); - reset_bplldelays (); + reset_dbpll_all (-1); } static void add_modulos (void) @@ -759,7 +766,7 @@ static void add_modulos (void) int m1, m2; reset_moddelays (); - reset_bplldelays (); + reset_dbpll_all (-1); if (fmode & 0x4000) { if (((diwstrt >> 8) ^ vpos) & 1) m1 = m2 = bpl2mod; @@ -914,9 +921,17 @@ static void estimate_last_fetch_cycle (int hpos) int lastfetchunit = fetchunit >= 8 ? 8 : fetchunit; if (plf_state < plf_passed_stop) { - int stop = plfstop + DDF_OFFSET < hpos || plfstop > HARD_DDF_STOP ? HARD_DDF_STOP : plfstop; + int stop; + + if (currprefs.chipset_mask & CSMASK_ECS_AGNUS) { + // ECS: stop wins if start == stop + stop = plfstop + DDF_OFFSET < hpos || plfstop > HARD_DDF_STOP ? HARD_DDF_STOP : plfstop; + } else { + // OCS: start wins if start == stop + stop = plfstop + DDF_OFFSET <= hpos || plfstop > HARD_DDF_STOP ? HARD_DDF_STOP : plfstop; + } /* We know that fetching is up-to-date up until hpos, so we can use fetch_cycle. */ - int fetch_cycle_at_stop = fetch_cycle + (stop - hpos + DDF_OFFSET); + int fetch_cycle_at_stop = fetch_cycle + (stop - hpos); int starting_last_block_at = (fetch_cycle_at_stop + fetchunit - 1) & ~(fetchunit - 1); estimated_last_fetch_cycle = hpos + (starting_last_block_at - fetch_cycle) + lastfetchunit; @@ -1280,7 +1295,9 @@ static void fetch (int nr, int fm, int hpos) bplptx[nr] += add; if (dbplpth_on2) - reset_dbplh (nr, hpos); + reset_dbplh (hpos, nr); + if (dbplptl_on2) + reset_dbpll (hpos, nr); if (nr == 0) bpl1dat_written = true; @@ -2162,6 +2179,40 @@ static void finish_final_fetch (void) STATIC_INLINE int one_fetch_cycle_0 (int pos, int dma, int fm) { + bool bplactive = true; + if (plf_state == plf_wait && dma && diwstate == DIW_waiting_stop) { + bpl_dma_off_when_active = 0; + if (currprefs.chipset_mask & CSMASK_ECS_AGNUS) { + plf_state = plf_passed_stop; + } else { + plf_state = plf_active; + } + } else if (!dma || diwstate != DIW_waiting_stop) { + bplactive = false; + // ecs and dma/diw off: turn off bitplane output after 4 cycles + // ddf is not closed at the end of line + // (Starflight / Phenomena jumping scroller in ECS) + if (currprefs.chipset_mask & CSMASK_ECS_AGNUS) { + if (plf_state == plf_active || plf_state == plf_passed_stop || plf_state == plf_passed_stop_act) { + bpl_dma_off_when_active = 1; + if (bitplane_off_delay < 0) { + bitplane_off_delay = 4; + } + } + if (bitplane_off_delay >= 0) { + bplactive = true; + if (bitplane_off_delay > 0) + bitplane_off_delay--; + if (bitplane_off_delay == 0) { + bplactive = false; + plf_state = plf_wait; + } + } + } else { + plf_state = plf_wait; + } + } + if ((dma && diwstate == DIW_waiting_stop) || (currprefs.chipset_mask & CSMASK_ECS_AGNUS)) { if (plf_state != plf_wait) { if (pos == plfstop && ddfstop_written_hpos != pos) { @@ -2198,32 +2249,6 @@ STATIC_INLINE int one_fetch_cycle_0 (int pos, int dma, int fm) maybe_check (pos); - bool bplactive = true; - if (plf_state == plf_wait && dma && diwstate == DIW_waiting_stop) { - plf_state = plf_active; - } else if (!dma || diwstate != DIW_waiting_stop) { - bplactive = false; - // ecs and dma/diw off: turn off bitplane output after 4 cycles - // ddf is not closed at the end of line - // (Starflight / Phenomena jumping scroller in ECS) - if (dma && (currprefs.chipset_mask & CSMASK_ECS_AGNUS)) { - if (plf_state == plf_active) { - if (bitplane_off_delay < 0) { - bitplane_off_delay = 4; - } - } - if (bitplane_off_delay >= 0) { - bplactive = true; - if (bitplane_off_delay > 0) - bitplane_off_delay--; - if (bitplane_off_delay == 0) { - bplactive = false; - plf_state = plf_wait; - } - } - } - } - if (bplactive) { /* fetchstart_mask can be larger than fm_maxplane if FMODE > 0. This means that the remaining cycles are idle; we'll fall through the whole switch @@ -2437,14 +2462,16 @@ static void update_fetch (int until, int fm) the screen. But the calculation of delay_offset must happen _before_. */ maybe_first_bpl1dat (pos); - if (pos <= ddfstop_to_test_ddf && stoppos > ddfstop_to_test_ddf) { + if (pos <= plfstop && stoppos > plfstop) { plf_state = plf_passed_stop; - plf_end_hpos = ddfstop_to_test; + plf_end_hpos = plfstop + DDF_OFFSET; } if (pos <= plfstop + DDF_OFFSET && stoppos > plfstop + DDF_OFFSET) { + plf_state = plf_passed_stop_act; + plf_end_hpos = 256 + DDF_OFFSET; ddfstop_matched = true; } - if (pos <= ddfstop_to_test && stoppos > ddfstop_to_test) { + if (pos <= HARD_DDF_STOP && stoppos > HARD_DDF_STOP) { plf_state = plf_passed_stop_act; } if (pos <= ddfstop_to_test && stoppos > ddf2) { @@ -2606,6 +2633,8 @@ STATIC_INLINE bool cant_this_last_line (void) /* This function is responsible for turning on datafetch if necessary. */ static void decide_line (int hpos) { + bool ecs = (currprefs.chipset_mask & CSMASK_ECS_AGNUS) != 0; + /* Take care of the vertical DIW. */ if (vpos == plffirstline) { // A1000 Agnus won't start bitplane DMA if vertical diw is zero. @@ -2615,7 +2644,7 @@ static void decide_line (int hpos) } } // last line of field can never have bitplane dma active if not A1000 Agnus. - if (vpos == plflastline || cant_this_last_line ()) { + if (vpos == plflastline || cant_this_last_line () || (vpos == 0 && currprefs.cs_dipagnus)) { diwstate = DIW_waiting_start; SET_LINE_CYCLEBASED; } @@ -2623,8 +2652,7 @@ static void decide_line (int hpos) if (hpos <= last_decide_line_hpos) return; - bool dma = dmaen (DMA_BITPLANE) != 0 && hpos >= bitplane_dma_changed_hpos; - bool ecs = (currprefs.chipset_mask & CSMASK_ECS_AGNUS) != 0; + bool dma = dmaen (DMA_BITPLANE) != 0; bool diw = diwstate == DIW_waiting_stop; if (ecs) { @@ -2634,25 +2662,29 @@ static void decide_line (int hpos) } } } else { - if (dma && diw) { + if (1) { if (last_decide_line_hpos < plfstrt && hpos >= plfstrt) { ddfstop_matched = false; + // plfstrt==0 works strangely (Nakudemo / Vision-X) + if (plfstrt > -DDF_OFFSET) + ocs_agnus_ddf_enable_toggle = false; } } } if (fetch_state == fetch_not_started) { bool strtpassed = false; + plfstate nextstate = plf_end; int hstart; hstart = last_decide_line_hpos; - if (hstart < bitplane_dma_changed_hpos) - hstart = bitplane_dma_changed_hpos; + if (hstart < bitplane_maybe_start_hpos) + hstart = bitplane_maybe_start_hpos; if (hstart < HARD_DDF_START_REAL + DDF_OFFSET) hstart = HARD_DDF_START_REAL + DDF_OFFSET; // DMA enabled mid-line: DDF_OFFSET delay first - if (bitplane_dma_changed_hpos + DDF_OFFSET > hstart) - hstart = bitplane_dma_changed_hpos + DDF_OFFSET; + if (bitplane_maybe_start_hpos + DDF_OFFSET > hstart) + hstart = bitplane_maybe_start_hpos + DDF_OFFSET; if (hstart & 1) hstart++; @@ -2660,7 +2692,8 @@ static void decide_line (int hpos) // ECS DDFSTRT/STOP matching does not require DMA or DIW. if (1) { if (last_decide_line_hpos < plfstrt && hpos >= plfstrt) { - if (plf_state < plf_passed_start) { + // active == already started because ddfstop was not detected in last line + if (plf_state != plf_active) { plf_state = plf_passed_start; strtpassed = true; plf_start_hpos = plfstrt + DDF_OFFSET; @@ -2684,11 +2717,6 @@ static void decide_line (int hpos) ocs_agnus_ddf_enable_toggle = true; } } - if (1) { - if (last_decide_line_hpos < plfstrt && hpos >= plfstrt) { - ocs_agnus_ddf_enable_toggle = false; - } - } // OCS DDFSTRT/STOP matching requires DMA and DIW enabled. if (dma && diw) { if (last_decide_line_hpos < plfstrt && hpos >= plfstrt) { @@ -2714,14 +2742,20 @@ static void decide_line (int hpos) bool test = false; if (ecs) { test = (plf_state == plf_active && (hpos >= HARD_DDF_START_REAL + DDF_OFFSET || HARD_DDF_LIMITS_DISABLED)); + if (bpl_dma_off_when_active) { + if (plfstop < hstart) { + test = false; + } + } } else { test = (plf_state == plf_active); // if DMA enabled mid-scanline but ddfstrt not matched (dma was off): start when ddfstop is matched // (Crash Landing crack intro / Scoopex) if (!test && last_decide_line_hpos < plfstop && hstart > plfstop) { - if (hstart == ((bitplane_dma_changed_hpos + DDF_OFFSET + 1) & ~1)) { + if (hstart == ((bitplane_maybe_start_hpos + DDF_OFFSET + 1) & ~1)) { hstart = plfstop + DDF_OFFSET; test = true; + nextstate = plf_passed_stop; } } } @@ -2729,19 +2763,28 @@ static void decide_line (int hpos) start_bpl_dma (hstart); // if ECS: pre-set plf_end_hpos if we have already passed virtual ddfstop if (ecs) { - if (last_decide_line_hpos < plfstop && hstart > plfstop) { + if (last_decide_line_hpos < hstart && hstart >= plfstop && hstart - plfstop <= DDF_OFFSET) { plf_end_hpos = plfstop + DDF_OFFSET; - plf_state = plf_passed_stop; + nextstate = plf_passed_stop; } if (last_decide_line_hpos < HARD_DDF_STOP && hstart > HARD_DDF_STOP) { plf_end_hpos = HARD_DDF_STOP + DDF_OFFSET; - plf_state = plf_passed_stop; + nextstate = plf_passed_stop; } + if (bpl_dma_off_when_active) { + nextstate = plf_passed_stop_act; + bpl_dma_off_when_active = 0; + } + } + if (nextstate != plf_end) { + plf_state = nextstate; + estimate_last_fetch_cycle(hstart); } last_decide_line_hpos = hpos; do_sprites (hpos); return; } + } if (ecs) { @@ -2749,11 +2792,13 @@ static void decide_line (int hpos) // ddfstrt == ddfstop: ddfstrt wins. if (plfstrt != plfstop && last_decide_line_hpos < plfstop && hpos >= plfstop && plfstop <= maxhpos - DDF_OFFSET) { ddfstop_matched = true; - if (plf_state != plf_wait && plf_state < plf_passed_stop) + if (plf_state != plf_wait && plf_state < plf_passed_stop) { plf_state = plf_passed_stop; + plf_end_hpos = plfstop + DDF_OFFSET; + } } if (last_decide_line_hpos < HARD_DDF_STOP && hpos >= HARD_DDF_STOP) { - plf_state = plf_passed_stop2; + plf_state = plf_passed_stop_act; } } } else { @@ -3551,7 +3596,7 @@ static void reset_decisions (void) bpldmasetupphase = 0; bpldmawasactive = false; reset_moddelays (); - reset_bplldelays (); + reset_dbpll_all (256); reset_dbplh_all (256); delay_cycles = 0; compute_toscr_delay (bplcon1); @@ -3570,7 +3615,7 @@ static void reset_decisions (void) plf_start_hpos = 256 + DDF_OFFSET; plf_end_hpos = 256 + DDF_OFFSET; ddfstop_written_hpos = -1; - bitplane_dma_changed_hpos = -1; + bitplane_maybe_start_hpos = -1; bitplane_off_delay = -1; if (line_cyclebased) @@ -4177,6 +4222,12 @@ static void calcdiw (void) if (diwfirstword < min_diwlastword) diwfirstword = min_diwlastword; + if (vstrt == vpos && vstop != vpos && diwstate == DIW_waiting_start) { + // This may start BPL DMA immediately. + SET_LINE_CYCLEBASED; + bitplane_maybe_start_hpos = current_hpos(); + } + plffirstline = vstrt; plflastline = vstop; @@ -4665,7 +4716,7 @@ static void DMACON (int hpos, uae_u16 v) if (changed & (DMA_MASTER | DMA_BITPLANE)) { SET_LINE_CYCLEBASED; - bitplane_dma_changed_hpos = hpos + 1; + bitplane_maybe_start_hpos = hpos; #if 0 if (dmaen (DMA_BITPLANE)) { if (vpos == 0xba) @@ -4913,9 +4964,11 @@ static void BPLxPTH (int hpos, uae_u16 v, int num) decide_line (hpos); decide_fetch_safe (hpos); if (copper_access && is_bitplane_dma (hpos + 1) == num + 1) { - dbplpth[num] = (v << 16) & 0xffff0000; - dbplpth_on[num] = hpos; - dbplpth_on2++; + if (is_bitplane_dma(hpos + 2)) { + dbplpth[num] = (v << 16) & 0xffff0000; + dbplpth_on[num] = hpos; + dbplpth_on2++; + } SET_LINE_CYCLEBASED; return; } @@ -4930,21 +4983,29 @@ static void BPLxPTL (int hpos, uae_u16 v, int num) decide_line (hpos); decide_fetch_safe (hpos); reset_dbplh (hpos, num); - /* chipset feature: BPLxPTL write and next cycle doing DMA fetch using same pointer register -> - * this write goes nowhere (same happens with all DMA channels, not just BPL) - * (intro MoreNewStuffy by PlasmaForce) + /* chipset feature: + * BPLxPTL write and next cycle doing DMA fetch using same pointer register -> + * next DMA cycle uses old value. + * (Multiscroll / Cult) + * + * If following cycle is not BPL DMA: written value is lost * - * NEW: last fetch block does not have this side-effect, probably due to modulo adds. + * last fetch block does not have this side-effect, probably due to modulo adds. * Also it seems only plane 0 fetches have this feature + * (MoreNewStuffy / PlasmaForce) */ /* only detect copper accesses to prevent too fast CPU mode glitches */ - if (copper_access && num == 0 && is_bitplane_dma (hpos + 1) == num + 1) { - if (plf_state < plf_passed_stop) - return; - /* modulo adds use old value! Argh! */ - dbplptl[num] = v & 0x0000fffe; - dbplptl_on[num] = 255; - dbplptl_on2 = 1; + if (copper_access && is_bitplane_dma (hpos + 1) == num + 1) { + if (num == 0 && plf_state >= plf_passed_stop) { + /* modulo adds use old value! Argh! */ + dbplptl[num] = v & 0x0000fffe; + dbplptl_on[num] = -1; + dbplptl_on2++; + } else if (is_bitplane_dma(hpos + 2)) { + dbplptl[num] = v & 0x0000fffe; + dbplptl_on[num] = hpos; + dbplptl_on2++; + } SET_LINE_CYCLEBASED; return; } diff --git a/debug.cpp b/debug.cpp index c6755b2d..28fe422d 100644 --- a/debug.cpp +++ b/debug.cpp @@ -3540,6 +3540,7 @@ static int cycle_breakpoint(TCHAR **c) } else { count += maxvpos - vpos; } + count *= maxhpos; if (hp >= current_hpos()) { count += hp - current_hpos(); } else { diff --git a/inputdevice.cpp b/inputdevice.cpp index 6b8ffd59..0836cf16 100644 --- a/inputdevice.cpp +++ b/inputdevice.cpp @@ -5658,27 +5658,36 @@ void inputdevice_devicechange (struct uae_prefs *prefs) { int acc = input_acquired; int i, idx; - TCHAR *jports[MAX_JPORTS]; + TCHAR *jports_name[MAX_JPORTS]; + TCHAR *jports_configname[MAX_JPORTS]; int jportskb[MAX_JPORTS], jportsmode[MAX_JPORTS]; int jportid[MAX_JPORTS], jportaf[MAX_JPORTS]; for (i = 0; i < MAX_JPORTS; i++) { - jports[i] = NULL; jportskb[i] = -1; jportid[i] = prefs->jports[i].id; jportaf[i] = prefs->jports[i].autofire; + jports_name[i] = NULL; + jports_configname[i] = NULL; idx = inputdevice_getjoyportdevice (i, prefs->jports[i].id); if (idx >= JSEM_LASTKBD) { - struct inputdevice_functions *idf; - int devidx; - idx -= JSEM_LASTKBD; - idf = getidf (idx); - devidx = inputdevice_get_device_index (idx); - jports[i] = my_strdup (idf->get_uniquename (devidx)); + if (prefs->jports[i].name[0] == 0 && prefs->jports[i].configname[0] == 0) { + struct inputdevice_functions *idf; + int devidx; + idx -= JSEM_LASTKBD; + idf = getidf (idx); + devidx = inputdevice_get_device_index (idx); + jports_name[i] = my_strdup (idf->get_friendlyname (devidx)); + jports_configname[i] = my_strdup (idf->get_uniquename (devidx)); + } } else { jportskb[i] = idx; } jportsmode[i] = prefs->jports[i].mode; + if (jports_name[i] == NULL) + jports_name[i] = my_strdup(prefs->jports[i].name); + if (jports_configname[i] == NULL) + jports_configname[i] = my_strdup(prefs->jports[i].configname); } inputdevice_unacquire (); @@ -5696,15 +5705,18 @@ void inputdevice_devicechange (struct uae_prefs *prefs) freejport (prefs, i); if (jportid[i] == JPORT_CUSTOM) { inputdevice_joyport_config (prefs, _T("custom"), i, jportsmode[i], 0, true); - } else if (jports[i]) { - inputdevice_joyport_config (prefs, jports[i], i, jportsmode[i], 2, true); + } else if (jports_name[i][0] || jports_configname[i][0]) { + if (!inputdevice_joyport_config (prefs, jports_configname[i], i, jportsmode[i], 1, true)) { + inputdevice_joyport_config (prefs, jports_name[i], i, jportsmode[i], 2, true); + } } else if (jportskb[i] >= 0) { TCHAR tmp[10]; _stprintf (tmp, _T("kbd%d"), jportskb[i]); inputdevice_joyport_config (prefs, tmp, i, jportsmode[i], 0, true); } prefs->jports[i].autofire = jportaf[i]; - xfree (jports[i]); + xfree (jports_name[i]); + xfree (jports_configname[i]); } if (prefs == &changed_prefs) @@ -7329,6 +7341,10 @@ int inputdevice_joyport_config (struct uae_prefs *p, const TCHAR *value, int por case 2: { int i, j; + if (type == 2) + _tcscpy(p->jports[portnum].name, value); + else if (type == 1) + _tcscpy(p->jports[portnum].configname, value); for (j = 0; j < MAX_JPORTS; j++) { struct inputdevice_functions *idf; int type = IDTYPE_MOUSE; diff --git a/od-win32/win32.h b/od-win32/win32.h index 4dcad6ad..52f07959 100644 --- a/od-win32/win32.h +++ b/od-win32/win32.h @@ -20,12 +20,12 @@ #define LANG_DLL_FULL_VERSION_MATCH 1 #if WINUAEPUBLICBETA -#define WINUAEBETA _T("4") +#define WINUAEBETA _T("5") #else #define WINUAEBETA _T("") #endif -#define WINUAEDATE MAKEBD(2015, 1, 18) +#define WINUAEDATE MAKEBD(2015, 1, 21) //#define WINUAEEXTRA _T("AmiKit Preview") //#define WINUAEEXTRA _T("Amiga Forever Edition") diff --git a/od-win32/win32gui.cpp b/od-win32/win32gui.cpp index dd6f068c..9fefb145 100644 --- a/od-win32/win32gui.cpp +++ b/od-win32/win32gui.cpp @@ -1686,6 +1686,7 @@ static void show_rom_list (void) 69, 67, 70, -1, -1, // nordic power 65, 68, -1, -1, // x-power 62, 60, -1, -1, // action cartridge + 116, -1, -1, // pro access 52, 25, -1, -1, // ar 1 26, 27, 28, -1, -1, // ar 2 29, 30, -1, -1, // ar 3 @@ -1711,6 +1712,7 @@ static void show_rom_list (void) _T("Blizzard PPC\0CyberStorm PPC\0") _T("Nordic Power\0X-Power Professional 500\0Action Cartridge Super IV Professional\0") + _T("Pro Access\0") _T("Action Replay MK I\0Action Replay MK II\0Action Replay MK III\0") _T("Action Replay 1200\0") @@ -16708,7 +16710,7 @@ int dragdrop (HWND hDlg, HDROP hd, struct uae_prefs *prefs, int currentpage) _tcscpy (prefs->romfile, file); if (rd->type == ROMTYPE_EXTCD32 || rd->type == ROMTYPE_EXTCDTV) _tcscpy (prefs->romextfile, file); - if (rd->type == ROMTYPE_AR) + if (rd->type & ROMTYPE_FREEZER) _tcscpy (prefs->cartfile, file); } else { _tcscpy (prefs->romfile, file); diff --git a/od-win32/winuaechangelog.txt b/od-win32/winuaechangelog.txt index 5cd865dd..41f36d07 100644 --- a/od-win32/winuaechangelog.txt +++ b/od-win32/winuaechangelog.txt @@ -1,4 +1,18 @@ +Beta 5: + +- Fixed ESP SCSI DMA emulation bug I introduced when non-DMA mode support was added (Original code from QEMU was DMA-only) +- Nordic Power v3.2 and Pro Access v2.17 (early version of cartridge that become Action Replay 1) support added. +- Some chipset emulation tweaks. Strange bitplane DMA on/off mid scanline behavior now emulated, not sure if exactly + right yet. Also some strange OCS/ECS differences tweaked. Should be mostly finished now. + I'll post more details later. +- Some tweaks to writing to BPLxPT 1 cycle before BPL DMA fetches same bitplane. Nakudemo / Vision-X ECS only corruption + is now correct (and also looks much worse than previously). +- GVP SCSI WD33C93 transfer info command with DMA enabled was not working. +- Compressed flashable rom images didn't unpack automatically. Flash modifications are not saved if using compressed image. +- Remember original input device name when loading config and input device is not currently available. If/when input + device gets connected, device is automatically inserted in to originally configured port. Remembered name is "forgotten" + when input device is manually changed in GUI or if autoswitching is used. Beta 4: