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;
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
{
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;
}
bplpt[nr] += mod;
bplptx[nr] += mod;
reset_moddelays ();
- reset_bplldelays ();
+ reset_dbpll_all (-1);
}
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;
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;
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;
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) {
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
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) {
/* 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.
}
}
// 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;
}
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) {
}
}
} 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++;
// 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;
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) {
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;
}
}
}
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) {
// 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 {
bpldmasetupphase = 0;
bpldmawasactive = false;
reset_moddelays ();
- reset_bplldelays ();
+ reset_dbpll_all (256);
reset_dbplh_all (256);
delay_cycles = 0;
compute_toscr_delay (bplcon1);
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)
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;
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)
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;
}
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;
}
{
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 ();
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)
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;