unsigned int evtime;
bool dmaenstore;
bool intreq2;
+ bool irqcheck;
bool dr;
bool dsr;
bool pbufldl;
write_log (_T("%d: ZEROSTATE\n"), nr);
#endif
cdp->state = 0;
+ cdp->irqcheck = false;
cdp->evtime = MAX_EV;
cdp->intreq2 = 0;
cdp->dmaenstore = false;
if (v > 64)
v = 64;
cdp->data.audvol = v;
- if (!currprefs.sound_volcnt)
- cdp->data.mixvol = v;
}
uae_u16 audio_dmal (void)
loaddat (nr, false);
}
+static void loadper1(int nr)
+{
+ struct audio_channel_data *cdp = audio_channel + nr;
+ cdp->evtime = 1 * CYCLE_UNIT;
+}
+
+static void loadperm1(int nr)
+{
+ struct audio_channel_data *cdp = audio_channel + nr;
+
+ if (cdp->per > CYCLE_UNIT) {
+ cdp->evtime = cdp->per - 1 * CYCLE_UNIT;
+ } else {
+ cdp->evtime = 65536 * CYCLE_UNIT + cdp->per;
+ }
+}
+
static void loadper (int nr)
{
struct audio_channel_data *cdp = audio_channel + nr;
cdp->evtime = cdp->per;
+ cdp->data.mixvol = cdp->data.audvol;
if (cdp->evtime < CYCLE_UNIT)
write_log (_T("LOADPER%d bug %d\n"), nr, cdp->evtime);
}
-static void audio_state_channel2 (int nr, bool perfin)
+static bool audio_state_channel2 (int nr, bool perfin)
{
struct audio_channel_data *cdp = audio_channel + nr;
bool chan_ena = (dmacon & DMA_MASTER) && (dmacon & (1 << nr));
if (currprefs.produce_sound == 0) {
zerostate (nr);
- return;
+ return true;
}
audio_activate ();
- if (cdp->state == 2 || cdp->state == 3) {
+ if ((cdp->state & 15) == 2 || (cdp->state & 15) == 3) {
if (!chan_ena && old_dma) {
// DMA switched off, state=2/3 and "too fast CPU": set flag
cdp->dmaofftime_active = true;
cdp->evtime = MAX_EV;
if (!chan_ena) {
zerostate (nr);
- return;
+ return true;
}
if (!cdp->dat_written)
- return;
+ return true;
#if TEST_AUDIO > 0
if (debugchannel (nr) && !cdp->have_dat)
write_log (_T("%d: state 1 but no have_dat\n"), nr);
cdp->evtime = MAX_EV;
if (!chan_ena) {
zerostate (nr);
- return;
+ return true;
}
if (!cdp->dat_written)
- return;
+ return true;
#if DEBUG_AUDIO > 0
if (debugchannel (nr))
write_log (_T("%d:>5: LEN=%d PT=%08X PC=%08X\n"), nr, cdp->wlen, cdp->pt, M68K_GETPC);
cdp->pbufldl = false;
}
if (!perfin)
- return;
+ return true;
#if DEBUG_AUDIO2 > 0
setirq (nr, 22);
}
cdp->pbufldl = true;
+ cdp->irqcheck = false;
cdp->state = 3;
audio_state_channel2 (nr, false);
break;
+
+ case 3 + 0x10: // manual audio period==1 cycle
+ if (!perfin) {
+ return true;
+ }
+ cdp->state = 3;
+ loadper1(nr);
+ if (!chan_ena && isirq(nr)) {
+ cdp->irqcheck = true;
+ }
+ return false;
+
case 3:
if (cdp->pbufldl) {
#if TEST_AUDIO > 0
cdp->losample = false;
#endif
newsample (nr, (cdp->dat2 >> 0) & 0xff);
- loadper (nr);
+ if (chan_ena) {
+ loadper(nr);
+ } else {
+ cdp->state |= 0x10;
+ loadperm1(nr);
+ }
cdp->pbufldl = false;
}
if (!perfin)
- return;
+ return true;
#if DEBUG_AUDIO2 > 0
if (debugchannel(nr)) {
if (napnav)
setdr(nr, false);
} else {
- if (isirq (nr)) {
+ if (cdp->irqcheck) {
#if DEBUG_AUDIO > 0
if (debugchannel (nr))
write_log (_T("%d: IDLE\n"), nr);
#endif
zerostate (nr);
- return;
+ return true;
}
loaddat (nr);
if (napnav)
audio_state_channel2 (nr, false);
break;
}
+ return true;
}
static void audio_state_channel (int nr, bool perfin)
{
struct audio_channel_data *cdp = audio_channel + nr;
if (nr < AUDIO_CHANNELS_PAULA) {
- audio_state_channel2 (nr, perfin);
- cdp->dat_written = false;
+ if (audio_state_channel2(nr, perfin)) {
+ cdp->dat_written = false;
+ }
} else {
bool ok = false;
int streamid = nr - AUDIO_CHANNELS_PAULA + 1;
update_audio ();
for (int nr = 0; nr < AUDIO_CHANNELS_PAULA; nr++) {
struct audio_channel_data *cdp = audio_channel + nr;
- audio_state_channel2 (nr, false);
- cdp->dat_written = false;
+ if (audio_state_channel2(nr, false)) {
+ cdp->dat_written = false;
+ }
}
schedule_audio ();
events_schedule ();
if (currprefs.sound_volcnt) {
cdp->data.mixvol = 1;
} else {
- cdp->data.mixvol = cdp->data.audvol;
+ cdp->data.mixvol = 0;
}
}
audio_total_extra_streams = 0;
static void audxdat_func(uae_u32 v)
{
int nr = v & 3;
- int chan_ena = (v & 0x100) != 0;
+ int chan_ena = (v & 0x80) != 0;
struct audio_channel_data *cdp = audio_channel + nr;
- if (cdp->state == 2 || cdp->state == 3) {
+ if ((cdp->state & 15) == 2 || (cdp->state & 15) == 3) {
if (chan_ena) {
#if DEBUG_AUDIO > 0
if (debugchannel(nr) && (cdp->wlen >= cdp->len - 1 || cdp->wlen <= 2))
} else {
cdp->wlen = (cdp->wlen - 1) & 0xffff;
}
+ } else {
+ cdp->dat = v >> 8;
+ cdp->dat_written = true;
}
} else {
+ cdp->dat = v >> 8;
+ cdp->dat_written = true;
audio_activate();
update_audio();
audio_state_channel(nr, false);
#endif
#if DEBUG_AUDIO > 0
- if (debugchannel (nr) && (DEBUG_AUDIO > 1 || (!chan_ena || addr == 0xffffffff || (cdp->state != 2 && cdp->state != 3)))) {
+ if (debugchannel (nr) && (DEBUG_AUDIO > 1 || (!chan_ena || addr == 0xffffffff || ((cdp->state & 15) != 2 && (cdp->state & 15) != 3))))) {
write_log (_T("AUD%dDAT: %04X ADDR=%08X LEN=%d/%d %d,%d,%d %06X\n"), nr,
v, addr, cdp->wlen, cdp->len, cdp->state, chan_ena, isirq (nr) ? 1 : 0, M68K_GETPC);
}
#endif
- cdp->dat = v;
- cdp->dat_written = true;
#if TEST_MISSED_DMA
cdp->dat_loaded = true;
#endif
write_log (_T("%d: audxdat 1=%04x 2=%04x but old dat not yet used\n"), nr, cdp->dat, cdp->dat2);
cdp->have_dat = true;
#endif
- // AUDxLEN is processed after 2 cycle delay
+ if (chan_ena) {
+ cdp->dat = v;
+ cdp->dat_written = true;
+ }
+ uae_u32 vv = nr | (chan_ena ? 0x80 : 0) | (v << 8);
if (!currprefs.cachesize && (cdp->per < PERIOD_LOW * CYCLE_UNIT || currprefs.cpu_compatible)) {
- event2_newevent_xx(-1, 2 * CYCLE_UNIT, nr | (chan_ena ? 0x100 : 0), audxdat_func);
+ int cyc;
+ if (chan_ena) {
+ // AUDxLEN is processed after 2 cycle delay
+ cyc = 2 * CYCLE_UNIT;
+ } else if (cdp->state == 0) {
+ cyc = 1 * CYCLE_UNIT;
+ } else {
+ cyc = 1 * CYCLE_UNIT;
+ }
+ if (cyc > 0) {
+ event2_newevent_xx(-1, cyc, vv, audxdat_func);
+ } else {
+ audxdat_func(vv);
+ }
} else {
- audxdat_func(nr | (chan_ena ? 0x100 : 0));
+ audxdat_func(vv);
}
}
void AUDxDAT (int nr, uae_u16 v)
#include "rommgr.h"
#include "specialmonitors.h"
+
+#define FRAMEWAIT_MIN_MS 2
+#define FRAMEWAIT_SPLIT 4
+
#define CYCLE_CONFLICT_LOGGING 0
#define SPEEDUP 1
thisline_decision.bplres = output_res(bplcon0_res);
}
+STATIC_INLINE bool line_hidden(void)
+{
+ return vpos >= maxvpos_display_vsync && vpos < minfirstline - 1;
+}
+
// hblank start = enable border (bitplane not visible until next BPL1DAT)..
static void hblank_reset(int hblankpos)
{
color_change *cc;
int pos = hpos < 0 ? -hpos : hpos_to_diw(hpos);
- if (scandoubled_line) {
+ if (scandoubled_line || line_hidden()) {
return;
}
// erase (color0 or bblank) area between previous end and new start
static void hdiw_restart(int diw_last, int diw_current)
{
- if (diw_last >= diw_current) {
+ if (diw_last >= diw_current || line_hidden()) {
return;
}
// update state
if (regno < RECORDED_REGISTER_CHANGE_OFFSET && nodraw())
return;
/* vsync period don't appear on-screen. */
- if (vpos >= maxvpos_display_vsync && vpos < minfirstline - 1)
+ if (line_hidden())
return;
decide_diw(hpos);
remember_ctable();
}
+ hpos += hack_delay_shift;
+
record_color_change2(hpos, regno, value);
}
last_diw_hpos = 0;
last_diw_hpos2 = 0;
blt_info.finishhpos = -1;
+ hack_delay_shift = 0;
/* Default to no bitplane DMA overriding sprite DMA */
plfstrt_sprite = 0x100;
compute_toscr_delay(bplcon1);
- hack_delay_shift = 0;
-
last_diwlastword = -1;
hb_last_diwlastword = -1;
int chp = current_hpos_safe() - 4;
int hp = v & 0xff;
if (chp >= 0x21 && chp <= 0x29 && hp == 0x2d) {
- hack_delay_shift = 0;
+ hack_delay_shift = 4;
record_color_change(chp, 0, COLOR_CHANGE_HSYNC_HACK | 6);
thisline_changed = 1;
}
static void compute_spcflag_copper(void);
-// vblank = copper starts at hpos=2
// normal COPJMP write: takes 2 more cycles
static void COPJMP(int num, int vblank)
{
cop_state.state = COP_strobe_delay1;
}
} else {
- cop_state.state = vblank ? COP_start_delay : (copper_access ? COP_strobe_delay1 : COP_strobe_extra);
+ cop_state.state = vblank ? COP_strobe_delay2 : (copper_access ? COP_strobe_delay1 : COP_strobe_extra);
}
cop_state.vblankip = cop1lc;
copper_enabled_thisline = 0;
// external delayed interrupt (4 CCKs minimum)
void send_interrupt(int num, int delay)
{
- if (delay > 0 && (currprefs.cpu_cycle_exact || currprefs.cpu_compatible)) {
+ if (delay > 0 && currprefs.cpu_compatible) {
event2_newevent_xx(-1, delay, num, send_interrupt_do);
} else {
send_interrupt_do(num);
{
int v;
- hpos += hack_delay_shift;
value = debug_putpeekdma_chipset(0xdff000 + addr, value, MW_MASK_COPPER, 0x08c);
copper_access = 1;
v = custom_wput_1(hpos, addr, value, noget);
// "emulate" chip internal delays, not the right place but fast and 99.9% programs
// use only copper to write BPLCON1 etc.. (exception is HulkaMania/TSP..)
// this table should be filled with zeros and done somewhere else..
-static int customdelay[]= {
+static const int customdelay[]= {
1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0, /* 32 0x00 - 0x3e */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x40 - 0x5e */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x60 - 0x7e */
0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0, /* 0x80 - 0x9e */
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 32 0xa0 - 0xde */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 32 0xa0 - 0xde */
/* BPLxPTH/BPLxPTL */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 16 */
/* BPLCON0-3,BPLMOD1-2 */
goto next;
}
- // 226 -> 0 (even to even cycle transition) skip.
- // Copper clock signal is low bit of hpos counter.
- if (hpos == 0 && maxhposeven == COPPER_CYCLE_POLARITY && cop_state.state != COP_start_delay) {
+ // cycle 0 is not available
+ if (hpos == 0 && cop_state.state != COP_start_delay) {
goto next;
}
}
}
+static int calculate_lineno(int vp)
+{
+ int lineno = vp;
+ if (lineno >= MAXVPOS) {
+ lineno %= MAXVPOS;
+ }
+ nextline_how = nln_normal;
+ if (doflickerfix() && interlace_seen > 0) {
+ lineno *= 2;
+ }
+ else if (!interlace_seen && doublescan <= 0 && currprefs.gfx_vresolution && currprefs.gfx_pscanlines > 1) {
+ lineno *= 2;
+ if (timeframes & 1) {
+ lineno++;
+ nextline_how = currprefs.gfx_pscanlines == 3 ? nln_lower_black_always : nln_lower_black;
+ } else {
+ nextline_how = currprefs.gfx_pscanlines == 3 ? nln_upper_black_always : nln_upper_black;
+ }
+ } else if ((doublescan <= 0 || interlace_seen > 0) && currprefs.gfx_vresolution && currprefs.gfx_iscanlines) {
+ lineno *= 2;
+ if (interlace_seen) {
+ if (!lof_current) {
+ lineno++;
+ nextline_how = currprefs.gfx_iscanlines == 2 ? nln_lower_black_always : nln_lower_black;
+ } else {
+ nextline_how = currprefs.gfx_iscanlines == 2 ? nln_upper_black_always : nln_upper_black;
+ }
+ } else {
+ nextline_how = currprefs.gfx_vresolution > VRES_NONDOUBLE && currprefs.gfx_pscanlines == 1 ? nln_nblack : nln_doubled;
+ }
+ } else if (currprefs.gfx_vresolution && (doublescan <= 0 || interlace_seen > 0)) {
+ lineno *= 2;
+ if (interlace_seen) {
+ if (!lof_current) {
+ lineno++;
+ nextline_how = nln_lower;
+ } else {
+ nextline_how = nln_upper;
+ }
+ } else {
+ nextline_how = currprefs.gfx_vresolution > VRES_NONDOUBLE && currprefs.gfx_pscanlines == 1 ? nln_nblack : nln_doubled;
+ }
+ }
+ return lineno;
+}
+
// vsync start
void init_hardware_for_drawing_frame(void)
{
}
prev_next_sprite_entry = next_sprite_entry;
- next_lineno = 0;
+ next_lineno = calculate_lineno(vpos);
last_color_change = 0;
next_color_change = 0;
next_sprite_entry = 0;
if (!currprefs.cpu_thread) {
while (!currprefs.turbo_emulation) {
float v = rpt_vsync(clockadjust) / (syncbase / 1000.0);
- if (v >= -3)
+ if (v >= -FRAMEWAIT_MIN_MS)
break;
rtg_vsynccheck();
maybe_process_pull_audio();
}
while (rpt_vsync(clockadjust) < 0) {
rtg_vsynccheck();
- maybe_process_pull_audio();
+ if (audio_is_pull_event()) {
+ maybe_process_pull_audio();
+ break;
+ }
}
}
idletime += read_processor_time() - start;
}
t += frameskipt_avg;
- vsynctimeperline = (vstb - t) / 4;
+ vsynctimeperline = (vstb - t) / FRAMEWAIT_SPLIT;
if (vsynctimeperline < 1) {
vsynctimeperline = 1;
- } else if (vsynctimeperline > vstb / 4) {
- vsynctimeperline = vstb / 4;
+ } else if (vsynctimeperline > vstb / FRAMEWAIT_SPLIT) {
+ vsynctimeperline = vstb / FRAMEWAIT_SPLIT;
}
frame_shown = true;
hautoscale_check();
- int lineno = vposh;
- if (lineno >= MAXVPOS) {
- lineno %= MAXVPOS;
- }
- nextline_how = nln_normal;
- if (doflickerfix() && interlace_seen > 0) {
- lineno *= 2;
- } else if (!interlace_seen && doublescan <= 0 && currprefs.gfx_vresolution && currprefs.gfx_pscanlines > 1) {
- lineno *= 2;
- if (timeframes & 1) {
- lineno++;
- nextline_how = currprefs.gfx_pscanlines == 3 ? nln_lower_black_always : nln_lower_black;
- } else {
- nextline_how = currprefs.gfx_pscanlines == 3 ? nln_upper_black_always : nln_upper_black;
- }
- } else if ((doublescan <= 0 || interlace_seen > 0) && currprefs.gfx_vresolution && currprefs.gfx_iscanlines) {
- lineno *= 2;
- if (interlace_seen) {
- if (!lof_current) {
- lineno++;
- nextline_how = currprefs.gfx_iscanlines == 2 ? nln_lower_black_always : nln_lower_black;
- } else {
- nextline_how = currprefs.gfx_iscanlines == 2 ? nln_upper_black_always : nln_upper_black;
- }
- } else {
- nextline_how = currprefs.gfx_vresolution > VRES_NONDOUBLE && currprefs.gfx_pscanlines == 1 ? nln_nblack : nln_doubled;
- }
- } else if (currprefs.gfx_vresolution && (doublescan <= 0 || interlace_seen > 0)) {
- lineno *= 2;
- if (interlace_seen) {
- if (!lof_current) {
- lineno++;
- nextline_how = nln_lower;
- } else {
- nextline_how = nln_upper;
- }
- } else {
- nextline_how = currprefs.gfx_vresolution > VRES_NONDOUBLE && currprefs.gfx_pscanlines == 1 ? nln_nblack : nln_doubled;
- }
- }
+ int lineno = calculate_lineno(vposh);
next_lineno = lineno;
reset_decisions_hsync_start();
}
// vblank interrupt = next line after VBSTRT
if (vb_start_line == 1) {
// first refresh (strobe) slot triggers vblank interrupt
- send_interrupt(5, REFRESH_FIRST_HPOS * CYCLE_UNIT);
+ send_interrupt(5, (REFRESH_FIRST_HPOS - 1) * CYCLE_UNIT);
}
// lastline - 1?
if (vpos + 1 == maxvpos + lof_store || vpos + 1 == maxvpos + lof_store + 1) {
hsync_handlerh(vsync_line);
}
+static void audio_evhandler2(void)
+{
+ // update copper first
+ // if copper had written to audio registers
+ int hpos = current_hpos();
+ sync_copper(hpos);
+ audio_evhandler();
+}
+
void init_eventtab (void)
{
int i;
eventtab[ev_hsynch].evtime = get_cycles() + HSYNCTIME;
eventtab[ev_hsynch].active = 0;
eventtab[ev_misc].handler = MISC_handler;
- eventtab[ev_audio].handler = audio_evhandler;
+ eventtab[ev_audio].handler = audio_evhandler2;
eventtab2[ev2_blitter].handler = blitter_handler;
eventtab2[ev2_disk].handler = DISK_handler;