static int qcode_valid;
static int cdrom_disk, cdrom_paused, cdrom_playing, cdrom_audiostatus;
-static int cdrom_command_active;
+static int cdrom_command_active, cdrom_command_startdelay, cdrom_command_idle;
static int cdrom_command_length;
static int cdrom_checksum_error, cdrom_unknown_command;
static int cdrom_data_offset, cdrom_speed, cdrom_sector_counter;
static void set_status (uae_u32 status)
{
+#if AKIKO_DEBUG_IO
+ if (!(cdrom_intreq & status))
+ write_log (L"Akiko INTREQ %08x (%08x)\n", status, cdrom_intreq | status);
+#endif
cdrom_intreq |= status;
checkint ();
cdrom_led ^= LED_CD_ACTIVE2;
return 0;
}
+static int cdrom_command_idle_status (void)
+{
+ cdrom_result_buffer[0] = 0x0a;
+ cdrom_result_buffer[1] = 0x70;
+ write_log (L"X");
+ return 2;
+}
+
static int cdrom_command_media_status (void)
{
cdrom_result_buffer[0] = 0x0a;
if (!(cdrom_flags & CDFLAG_TXD))
return;
+ if (cdrom_command_startdelay)
+ return;
for (;;) {
if (cdrom_command_active)
return;
if (cdcomtxinx == cdcomtxcmp)
return;
cdrom_command = get_byte (cdtx_address + cdcomtxinx);
+#if 1
if ((cdrom_command & 0xf0) == 0) {
cdcomtxinx = (cdcomtxinx + 1) & 0xff;
return;
}
+#endif
cdrom_checksum_error = 0;
cdrom_unknown_command = 0;
int i, sector, inc;
int read = 0;
int sec;
- static int seccnt;
+ int seccnt;
if (!(cdrom_flags & CDFLAG_ENABLE))
return;
if (sector_buffer_info_1[sec] != 0xff)
sector_buffer_info_1[sec]--;
#if AKIKO_DEBUG_IO_CMD
- write_log (L"read sector=%d, scnt=%d -> %d. %08X\n",
- cdrom_data_offset, cdrom_sector_counter, sector, cdrom_addressdata + seccnt * 4096);
+ write_log (L"read sector=%d, scnt=%d -> %d. %d %08X\n",
+ cdrom_data_offset, cdrom_sector_counter, sector, seccnt, cdrom_addressdata + seccnt * 4096);
#endif
} else {
inc = 0;
if (!cdrom_command_active)
cdrom_run_command_run ();
}
+#if 0
+ if (!cdrom_playing && !cdrom_command_active) {
+ cdrom_command_idle++;
+ if (cdrom_command_idle > 1000) {
+ cdrom_command_idle = 0;
+ cdrom_start_return_data (cdrom_command_idle_status ());
+ }
+ }
+#endif
}
void AKIKO_hsync_handler (void)
if (!currprefs.cs_cd32cd || !akiko_inited)
return;
+ if (cdrom_command_startdelay > 0) {
+ cdrom_command_startdelay--;
+ }
+
static float framecounter;
framecounter--;
if (framecounter <= 0) {
case 0x12:
case 0x13:
akiko_put_long (&cdrom_addressdata, addr - 0x10, v);
- cdrom_addressdata &= 0x00ff0000;
+ cdrom_addressdata &= 0x00fff000;
break;
case 0x14:
case 0x15:
case 0x1d:
cdrom_intreq &= ~CDINTERRUPT_TXDMADONE;
cdcomtxcmp = v;
+ if (cdrom_command_active == 0)
+ cdrom_command_startdelay = 2;
break;
case 0x1f:
cdrom_intreq &= ~CDINTERRUPT_RXDMADONE;
return ((1 << ch) & DEBUG_CHANNEL_MASK) != 0;
}
-STATIC_INLINE bool usehacks (void)
+STATIC_INLINE bool usehacks1 (void)
+{
+ return currprefs.cpu_model >= 68020 || currprefs.m68k_speed != 0;
+}
+
+#if 0
+STATIC_INLINE bool usehacks2 (void)
{
if (currprefs.cpu_cycle_exact && currprefs.cpu_model <= 68020)
return false;
return currprefs.cpu_model >= 68020 || currprefs.m68k_speed != 0;
}
+#endif
#define SINC_QUEUE_MAX_AGE 2048
/* Queue length 128 implies minimum emulated period of 16. I add a few extra
bool have_dat;
int per_original;
#endif
+ /* too fast cpu fixes */
+ uaecptr ptx;
+ bool ptx_written;
};
static int samplecnt;
#if DEBUG_AUDIO > 0
if (!debugchannel (nr))
sample = 0;
+#endif
+#if DEBUG_AUDIO > 1
+ if (debugchannel (nr))
+ write_log (L"SAMPLE%d: %02x\n", nr, sample & 0xff);
#endif
if (!(audio_channel_mask & (1 << nr)))
sample = 0;
cdp->evtime = cdp->per;
if (cdp->evtime < CYCLE_UNIT)
- write_log (L"loadper%d bug %d\n", nr, cdp->evtime);
+ write_log (L"LOADPER%d bug %d\n", nr, cdp->evtime);
}
}
audio_activate ();
- if ((cdp->state == 2 || cdp->state == 3) && usehacks () && !chan_ena && old_dma) {
+ if ((cdp->state == 2 || cdp->state == 3) && usehacks1 () && !chan_ena && old_dma) {
// DMA switched off, state=2/3 and "too fast CPU": kill DMA instantly
// or CPU timed DMA wait routines in common tracker players will lose notes
#if DEBUG_AUDIO > 0
cdp->dr = true;
cdp->drhpos = hpos;
cdp->wlen = cdp->len;
- // too fast CPU and some tracker players: enable DMA, CPU delay, update AUDxPT with loop position
- if (usehacks ()) {
- // copy AUDxPT - 2 to internal latch instantly
- cdp->pt = cdp->lc - 2;
- cdp->dsr = false;
- } else {
- // normal hardware behavior: latch it after first DMA fetch comes
- cdp->dsr = true;
- }
+ cdp->ptx_written = false;
+ cdp->dsr = true;
#if TEST_AUDIO > 0
cdp->have_dat = false;
#endif
#if DEBUG_AUDIO > 0
- if (debugchannel (nr))
+ if (debugchannel (nr)) {
write_log (L"%d:0>1: LEN=%d PC=%08x\n", nr, cdp->wlen, M68K_GETPC);
+ if (cdp->wlen == 1)
+ write_log (L"*");
+ }
#endif
} else if (cdp->dat_written && !isirq (nr)) {
cdp->state = 2;
setirq (nr, 0);
loaddat (nr);
- if (usehacks () && cdp->per < 10 * CYCLE_UNIT) {
+ if (usehacks1 () && cdp->per < 10 * CYCLE_UNIT) {
// make sure audio.device AUDxDAT startup returns to idle state before DMA is enabled
newsample (nr, (cdp->dat2 >> 0) & 0xff);
zerostate (nr);
if (debugchannel (nr))
write_log (L"%d:>5: LEN=%d PT=%08X PC=%08X\n", nr, cdp->wlen, cdp->pt, M68K_GETPC);
#endif
+ if (cdp->ptx_written) {
+ cdp->ptx_written = 0;
+ cdp->lc = cdp->ptx;
+ }
loaddat (nr);
if (napnav)
setdr (nr);
int chan_ena = (dmacon & DMA_MASTER) && (dmacon & (1 << nr));
#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 != 2 && cdp->state != 3)))) {
write_log (L"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;
struct audio_channel_data *cdp = audio_channel + nr;
audio_activate ();
update_audio ();
- cdp->lc = (cdp->lc & 0xffff) | ((uae_u32)v << 16);
+
+ // someone wants to update PT but DSR has not yet been processed.
+ // too fast CPU and some tracker players: enable DMA, CPU delay, update AUDxPT with loop position
+ if (usehacks1 () && ((cdp->dsr && cdp->state == 1) || cdp->ptx_written)) {
+ cdp->ptx = cdp->lc;
+ cdp->ptx_written = true;
+ } else {
+ cdp->lc = (cdp->lc & 0xffff) | ((uae_u32)v << 16);
+ }
#if DEBUG_AUDIO > 0
if (debugchannel (nr))
write_log (L"AUD%dLCH: %04X %08X\n", nr, v, M68K_GETPC);
struct audio_channel_data *cdp = audio_channel + nr;
audio_activate ();
update_audio ();
- cdp->lc = (cdp->lc & ~0xffff) | (v & 0xFFFE);
+ if (usehacks1 () && ((cdp->dsr && cdp->state == 1) || cdp->ptx_written)) {
+ cdp->ptx = cdp->lc;
+ cdp->ptx_written = true;
+ } else {
+ cdp->lc = (cdp->lc & ~0xffff) | (v & 0xFFFE);
+ }
#if DEBUG_AUDIO > 0
if (debugchannel (nr))
write_log (L"AUD%dLCL: %04X %08X\n", nr, v, M68K_GETPC);
{
#if SOUNDSTUFF > 0
int max, min;
- int vsync = isfullscreen () > 0 && currprefs.gfx_avsync;
+ int vsync = isvsync ();
static int lastdir;
if (!vsync) {
init_comm_pipe (&requests, 100, 1);
uae_start_thread (L"cdtv", dev_thread, NULL, NULL);
while (!thread_alive)
- sleep_millis(10);
+ sleep_millis (10);
uae_sem_init (&sub_sem, 0, 1);
}
write_comm_pipe_u32 (&requests, 0x0104, 1);
if (p->m68k_speed > 0)
cfgfile_write (f, L"finegrain_cpu_speed", L"%d", p->m68k_speed);
else
- cfgfile_write_str (f, L"cpu_speed", p->m68k_speed == -1 ? L"max" : L"real");
+ cfgfile_write_str (f, L"cpu_speed", p->m68k_speed < 0 ? L"max" : L"real");
/* do not reorder start */
write_compatibility_cpu(f, p);
if (dstptr)
dstbak = dst = dstptr;
else
- dstbak = dst = xmalloc (uae_u8, 4 + 4 + 1 + 1 + 1);
+ dstbak = dst = xmalloc (uae_u8, 4 + 4 + 1 + 1 + 1 + 1);
save_u32 (getcapslockstate () ? 1 : 0);
save_u32 (1);
save_u8 (kbstate);
void reset_frame_rate_hack (void)
{
- if (currprefs.m68k_speed != -1)
+ if (currprefs.m68k_speed >= 0)
return;
if (! rpt_available) {
return linetoggle;
}
-static int isvsync (void)
-{
- if (picasso_on || !currprefs.gfx_avsync || (currprefs.gfx_avsync == 0 && !currprefs.gfx_afullscreen))
- return 0;
- return currprefs.gfx_avsyncmode == 0 ? 1 : -1;
-}
-
int vsynctime_orig;
void compute_vsynctime (void)
int freetime;
extern int extraframewait;
vsyncmintime = vsynctime;
- render_screen ();
- vsync_busywait (&freetime);
+
+ if (vs == -2) {
- curr_time = read_processor_time ();
- vsyncmintime = curr_time + vsynctime * 8 / 10;
+ show_screen ();
+ vsync_busywait_end ();
+ vsync_busywait_do (&freetime);
+ curr_time = read_processor_time ();
+ vsyncmintime = curr_time + vsynctime;
+ render_screen ();
+ vsync_busywait_start ();
+
+ } else {
+
+ render_screen ();
+ vsync_busywait_do (&freetime);
+ curr_time = read_processor_time ();
+ vsyncmintime = curr_time + vsynctime;
+ show_screen ();
+ if (extraframewait)
+ sleep_millis (extraframewait);
- show_screen ();
- if (extraframewait) {
- sleep_millis (extraframewait);
}
return;
}
- render_screen ();
+ bool didrender = false;
+ if (!picasso_on)
+ didrender = render_screen ();
for (;;) {
double v = rpt_vsync () / (syncbase / 1000.0);
if (v >= -4)
break;
- sleep_millis (2);
+ sleep_millis_main (2);
}
curr_time = start = read_processor_time ();
while (rpt_vsync () < 0);
curr_time = read_processor_time ();
vsyncmintime = curr_time + vsynctime;
idletime += read_processor_time() - start;
- show_screen ();
+ if (didrender)
+ show_screen ();
}
static frame_time_t frametime2;
// emulated hardware vsync
static void vsync_handler_post (void)
{
+ static frame_time_t prevtime;
+
+ //write_log (L"%d %d %d\n", vsynctime, read_processor_time () - vsyncmintime, read_processor_time () - prevtime);
+ prevtime = read_processor_time ();
+
fpscounter ();
if (!isvsync ()
#ifdef JIT
if (!currprefs.cachesize) {
#endif
- if (currprefs.m68k_speed == -1) {
+ if (currprefs.m68k_speed < 0) {
frame_time_t curr_time = read_processor_time ();
vsyncmintime += vsynctime;
/* @@@ Mathias? How do you think we should do this? */
if ((long int)(curr_time - vsyncmintime) > 0 || rpt_did_reset)
vsyncmintime = curr_time + vsynctime;
rpt_did_reset = 0;
- render_screen ();
- show_screen ();
+ if (render_screen ())
+ show_screen ();
} else if (rpt_available) {
framewait ();
}
}
static void frh_handler (void)
{
- if (currprefs.m68k_speed == -1) {
+ if (currprefs.m68k_speed < 0) {
frame_time_t curr_time = read_processor_time ();
vsyncmintime += vsynctime * N_LINES / maxvpos_nom;
/* @@@ Mathias? How do you think we should do this? */
/* Allow this to be one frame's worth of cycles out */
while (diff32 (curr_time, vsyncmintime + vsynctime) > 0) {
vsyncmintime += vsynctime * N_LINES / maxvpos_nom;
- if (currprefs.turbo_emulation)
+ if (currprefs.turbo_emulation || thread_vblank_found)
break;
}
}
}
// this finishes current line
-static void hsync_handler_pre (bool isvsync)
+static void hsync_handler_pre (bool onvsync)
{
int hpos = current_hpos ();
vpos_count++;
if (vpos >= maxvpos_total)
vpos = 0;
- if (isvsync) {
+ if (onvsync) {
vpos = 0;
vsync_counter++;
}
}
// this prepares for new line
-static void hsync_handler_post (bool isvsync)
+static void hsync_handler_post (bool onvsync)
{
last_copper_hpos = 0;
#ifdef CPUEMU_12
CIA_vsync_posthandler (1);
cia_hsync += ((MAXVPOS_PAL * MAXHPOS_PAL * 50 * 256) / (maxhpos * (currprefs.cs_ciaatod == 2 ? 60 : 50)));
}
- } else if (currprefs.cs_ciaatod == 0 && isvsync) {
+ } else if (currprefs.cs_ciaatod == 0 && onvsync) {
CIA_vsync_posthandler (ciasyncs);
}
}
}
- if (isvsync) {
+ if (onvsync) {
// vpos_count >= MAXVPOS just to not crash if VPOSW writes prevent vsync completely
if ((bplcon0 & 8) && !lightpen_triggered) {
vpos_lpen = vpos - 1;
#ifdef JIT
if (currprefs.cachesize) {
- if (currprefs.m68k_speed == -1) {
+ if (currprefs.m68k_speed < 0) {
static int count = 0;
count++;
if (trigger_frh (count)) {
}
} else {
#endif
- is_lastline = vpos + 1 == maxvpos + lof_store && currprefs.m68k_speed == -1;
+ is_lastline = vpos + 1 == maxvpos + lof_store && currprefs.m68k_speed < 0;
#ifdef JIT
}
#endif
unlockscr (vb);
if (start <= stop)
flush_screen (vb, start, stop);
- else if (currprefs.gfx_afullscreen == GFX_FULLSCREEN && currprefs.gfx_avsync)
+ else if (isvsync ())
flush_screen (vb, 0, 0); /* vsync mode */
}
else if (currprefs.cpu_cycle_exact)
init_hardware_for_drawing_frame ();
} else {
- if (currprefs.gfx_afullscreen == GFX_FULLSCREEN && currprefs.gfx_avsync)
+ if (isvsync ())
flush_screen (gfxvidinfo.inbuffer, 0, 0); /* vsync mode */
}
gui_flicker_led (-1, 0, 0);
reset_drawing ();
}
+int isvsync (void)
+{
+ if (picasso_on || !currprefs.gfx_avsync || (currprefs.gfx_avsync == 0 && !currprefs.gfx_afullscreen))
+ return 0;
+ if (currprefs.gfx_avsyncmode == 0)
+ return 1;
+ return currprefs.m68k_speed < 0 ? -2 : -1;
+}
#endif
}
+extern volatile bool thread_vblank_found;
+
STATIC_INLINE void do_cycles_slow (unsigned long cycles_to_add)
{
+ if (thread_vblank_found && pissoff > 0)
+ cycles_do_special ();
+
if ((pissoff -= cycles_to_add) >= 0)
return;
int v = rpt - vsyncmintime;
if (v > (int)syncbase || v < -((int)syncbase))
vsyncmintime = rpt;
- if (v < 0) {
+ if (v < 0 && !thread_vblank_found && !currprefs.turbo_emulation) {
pissoff = pissoff_value * CYCLE_UNIT;
return;
}
nextevent = currcycle + mintime;
}
+extern volatile bool thread_vblank_found;
+
STATIC_INLINE void do_cycles_slow (unsigned long cycles_to_add)
{
if (is_lastline && eventtab[ev_hsync].evtime - currcycle <= cycles_to_add
- && (long int)(read_processor_time () - vsyncmintime) < 0)
+ && (long int)(read_processor_time () - vsyncmintime) < 0 && !thread_vblank_found)
return;
while ((nextevent - currcycle) <= cycles_to_add) {
extern void usage (void);
extern void parse_cmdline (int argc, TCHAR **argv);
extern void sleep_millis (int ms);
+extern void sleep_millis_main (int ms);
extern void sleep_millis_busy (int ms);
extern int sleep_resolution;
extern void toggle_mousegrab (void);
extern void desktop_coords (int *dw, int *dh, int *x, int *y, int *w, int *h);
extern bool vsync_switchmode (int);
-extern bool vsync_busywait (int*);
+extern void vsync_busywait_end (void);
+extern bool vsync_busywait_do (int*);
+extern void vsync_busywait_start (void);
extern double vblank_calibrate (double, bool);
extern void doflashscreen (void);
extern int flashscreen;
extern void updatedisplayarea (void);
+extern int isvsync (void);
extern void flush_line (struct vidbuffer*, int);
extern void flush_block (struct vidbuffer*, int, int);
uae_u8 *bufmem, *bufmemend;
uae_u8 *realbufmem;
bool bufmem_allocated;
+ bool bufmem_lockable;
int rowbytes; /* Bytes per row in the memory pointed at by bufmem. */
int pixbytes; /* Bytes per pixel. */
/* size of this buffer */
extern int check_for_cache_miss(void);
-#define scaled_cycles(x) (currprefs.m68k_speed==-1?(((x)/SCALE)?(((x)/SCALE<MAXCYCLES?((x)/SCALE):MAXCYCLES)):1):(x))
+#define scaled_cycles(x) (currprefs.m68k_speed<0?(((x)/SCALE)?(((x)/SCALE<MAXCYCLES?((x)/SCALE):MAXCYCLES)):1):(x))
extern uae_u32 needed_flags;
lvpos = vpos;
if (sleepcnt < 0) {
sleepcnt = IDLETIME / 2;
- sleep_millis (1);
+ sleep_millis_main (1);
}
}
}
return di;
}
-void win32_aspi_media_change (TCHAR driveletter, int insert)
+bool win32_aspi_media_change (TCHAR driveletter, int insert)
{
int i, now;
write_log (L"ASPI: media change %c %d\n", driveletter, insert);
si[i].mediainserted = now;
scsi_do_disk_change (i + 1, insert, NULL);
+ return true;
}
}
}
+ return false;
}
static int check_isatapi (int unitnum)
return di;
}
-void win32_ioctl_media_change (TCHAR driveletter, int insert)
+bool win32_ioctl_media_change (TCHAR driveletter, int insert)
{
for (int i = 0; i < total_devices; i++) {
struct dev_info_ioctl *ciw = &ciw32[i];
update_device_info (unitnum);
scsi_do_disk_change (unitnum, insert, NULL);
blkdev_cd_change (unitnum, ciw->drvlettername);
+ return true;
}
}
}
+ return false;
}
static int ioctl_scsiemu (int unitnum, uae_u8 *cmd)
return di;
}
-void win32_spti_media_change (TCHAR driveletter, int insert)
+bool win32_spti_media_change (TCHAR driveletter, int insert)
{
for (int i = 0; i < total_devices; i++) {
struct dev_info_spti *di = &dev_info[i];
update_device_info (unitnum);
scsi_do_disk_change (unitnum, insert, NULL);
blkdev_cd_change (unitnum, di->drvletter ? di->drvlettername : di->name);
+ return true;
}
}
}
+ return false;
}
static int check_isatapi (int unitnum)
return false;
}
*vpos = rt.ScanLine;
- if (rt.ScanLine > maxscanline)
- maxscanline = rt.ScanLine;
if (rt.InVBlank != 0)
*vpos = -1;
return true;
}
}
+bool D3D_vblank_getstate (bool *state)
+{
+ int vpos;
+ if (!getvblankstate (&vpos))
+ return false;
+ if (vpos <= 0 || vpos >= maxscanline - 5) {
+ *state = true;
+ return true;
+ }
+ *state = false;
+ return true;
+}
+
+
const TCHAR *D3D_init (HWND ahwnd, int w_w, int w_h, int t_w, int t_h, int depth, int mmult)
{
HRESULT ret, hr;
HINSTANCE d3dDLL, d3dx;
typedef HRESULT (WINAPI *LPDIRECT3DCREATE9EX)(UINT, IDirect3D9Ex**);
LPDIRECT3DCREATE9EX d3dexp = NULL;
- bool newvsync = currprefs.gfx_avsync && currprefs.gfx_avsyncmode && !picasso_on;
+ int vsync = isvsync ();
D3D_free2 ();
memset (&dpp, 0, sizeof (dpp));
dpp.Windowed = isfullscreen () <= 0;
dpp.BackBufferFormat = mode.Format;
- dpp.BackBufferCount = newvsync ? 0 : currprefs.gfx_backbuffers;
+ dpp.BackBufferCount = vsync == -1 ? 0 : (vsync == -2 ? 2 : currprefs.gfx_backbuffers);
dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
dpp.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
dpp.BackBufferWidth = w_w;
dpp.BackBufferHeight = w_h;
- dpp.PresentationInterval = (dpp.Windowed || currprefs.gfx_backbuffers == 0 || newvsync) ? D3DPRESENT_INTERVAL_IMMEDIATE : D3DPRESENT_INTERVAL_ONE;
+ dpp.PresentationInterval = (dpp.Windowed || dpp.BackBufferCount == 0 || vsync == -1) ? D3DPRESENT_INTERVAL_IMMEDIATE : D3DPRESENT_INTERVAL_ONE;
modeex.Width = w_w;
modeex.Height = w_h;
maxscanline = 0;
d3d_enabled = 1;
- if (newvsync) {
+ if (vsync == -1) {
hr = d3ddev->CreateQuery(D3DQUERYTYPE_EVENT, &query);
if (FAILED (hr))
write_log (L"%s: CreateQuery(D3DQUERYTYPE_EVENT) failed: %s\n", D3DHEAD, D3D_ErrorString (hr));
extern void D3D_setcursor (int x, int y, int visible);
extern bool D3D_vblank_busywait (void);
extern bool D3D_waitvblankstate (bool);
+extern bool D3D_vblank_getstate (bool *state);
extern double D3D_getrefreshrate (void);
extern LPDIRECT3DTEXTURE9 cursorsurfaced3d;
BOOL vb;
HRESULT hr;
- dx_check ();
- if (dxdata.islost)
+ if ((dxdata.primary == NULL && dxdata.fsmodeset > 0) || dxdata.islost || !dxdata.maindd)
return false;
for (;;) {
hr = IDirectDraw7_GetVerticalBlankStatus (dxdata.maindd, &vb);
return false;
return true;
}
+
+bool DirectDraw_getvblankstate (bool *state)
+{
+ BOOL vb;
+ HRESULT hr;
+
+ if ((dxdata.primary == NULL && dxdata.fsmodeset > 0) || dxdata.islost || !dxdata.maindd)
+ return false;
+ hr = IDirectDraw7_GetVerticalBlankStatus (dxdata.maindd, &vb);
+ if (FAILED (hr)) {
+ write_log (L"IDirectDraw7_GetVerticalBlankStatus %s\n", DXError (hr));
+ return false;
+ }
+ *state = vb != 0;
+ return true;
+}
void DirectDraw_FillPrimary (void);
bool DirectDraw_vblank_busywait (void);
bool DirectDraw_waitvblankstate (bool);
+bool DirectDraw_getvblankstate (bool*);
void dx_check (void);
int dx_islost (void);
#include "savestate.h"
#include "driveclick.h"
#include "gensound.h"
+#include "xwin.h"
#include <windows.h>
#include <mmsystem.h>
return 1;
}
-static int isvsync (void)
-{
- return currprefs.gfx_avsync && currprefs.gfx_afullscreen == GFX_FULLSCREEN;
-}
-
float scaled_sample_evtime_orig;
extern float sampler_evtime;
void update_sound (double freq, int longframe, int linetoggle)
return 1;
}
-void sleep_millis (int ms)
+static void sleep_millis2 (int ms, bool main)
{
UINT TimerEvent;
- int start;
+ int start = 0;
int cnt;
- start = read_processor_time ();
+ if (main)
+ start = read_processor_time ();
EnterCriticalSection (&cs_time);
cnt = timehandlecounter++;
if (timehandlecounter >= MAX_TIMEHANDLES)
WaitForSingleObject (timehandle[cnt], ms);
ResetEvent (timehandle[cnt]);
timeKillEvent (TimerEvent);
- idletime += read_processor_time () - start;
+ if (main)
+ idletime += read_processor_time () - start;
+}
+
+void sleep_millis_main (int ms)
+{
+ sleep_millis2 (ms, true);
}
+void sleep_millis (int ms)
+{
+ sleep_millis2 (ms, false);
+}
+
frame_time_t read_processor_time_qpf (void)
{
return TRUE;
case WM_DEVICECHANGE:
{
- extern void win32_spti_media_change (TCHAR driveletter, int insert);
- extern void win32_ioctl_media_change (TCHAR driveletter, int insert);
- extern void win32_aspi_media_change (TCHAR driveletter, int insert);
+ extern bool win32_spti_media_change (TCHAR driveletter, int insert);
+ extern bool win32_ioctl_media_change (TCHAR driveletter, int insert);
+ extern bool win32_aspi_media_change (TCHAR driveletter, int insert);
DEV_BROADCAST_HDR *pBHdr = (DEV_BROADCAST_HDR *)lParam;
static int waitfornext;
else
inserted = 0;
if (pBVol->dbcv_flags & DBTF_MEDIA) {
+ bool matched = false;
#ifdef WINDDK
- win32_spti_media_change (drive, inserted);
- win32_ioctl_media_change (drive, inserted);
+ matched |= win32_spti_media_change (drive, inserted);
+ matched |= win32_ioctl_media_change (drive, inserted);
#endif
- win32_aspi_media_change (drive, inserted);
+ matched |= win32_aspi_media_change (drive, inserted);
}
if (type == DRIVE_REMOVABLE || type == DRIVE_CDROM || !inserted) {
write_log (L"WM_DEVICECHANGE '%s' type=%d inserted=%d\n", drvname, type, inserted);
#endif
}
-int os_winnt, os_winnt_admin, os_64bit, os_win7, os_vista, os_winxp;
+int os_winnt, os_winnt_admin, os_64bit, os_win7, os_vista, os_winxp, cpu_number;
static int isadminpriv (void)
{
if (SystemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
os_64bit = 1;
}
+ cpu_number = SystemInfo.dwNumberOfProcessors;
if (!os_winnt)
return 0;
os_winnt_admin = isadminpriv ();
//#define WINUAEBETA L""
#define WINUAEBETA L"Beta 2"
-#define WINUAEDATE MAKEBD(2011, 12, 4)
+#define WINUAEDATE MAKEBD(2011, 12, 11)
#define WINUAEEXTRA L""
#define WINUAEREV L""
extern TCHAR prtname[];
extern TCHAR VersionStr[256];
extern TCHAR BetaStr[64];
-extern int os_winnt_admin, os_64bit, os_vista, os_winxp, os_win7;
+extern int os_winnt_admin, os_64bit, os_vista, os_winxp, os_win7, cpu_number;
extern OSVERSIONINFO osVersion;
extern int paraport_mask;
extern int gui_active;
void setpathmode (pathtype pt);
extern void sleep_millis (int ms);
+extern void sleep_millis_main (int ms);
extern void sleep_millis_busy (int ms);
extern void wait_keyrelease (void);
extern void keyboard_settrans (void);
getfilterrect2 (&dr, &sr, &zr, dst_width, dst_height, aw, ah, scale, temp_width, temp_height);
//write_log (L"(%d %d %d %d) - (%d %d %d %d) (%d %d)\n", dr.left, dr.top, dr.right, dr.bottom, sr.left, sr.top, sr.right, sr.bottom, zr.left, zr.top);
OffsetRect (&sr, zr.left, zr.top);
- if (sr.left >= 0 && sr.top >= 0 && sr.right < temp_width && sr.bottom < temp_height) {
+ if (sr.left < 0)
+ sr.left = 0;
+ if (sr.top < 0)
+ sr.top = 0;
+ if (sr.right < temp_width && sr.bottom < temp_height) {
if (sr.left < sr.right && sr.top < sr.bottom)
DirectDraw_BlitRect (NULL, &dr, tempsurf, &sr);
}
struct uae_filter *usedfilter;
static int scalepicasso;
static double remembered_vblank;
+static volatile int vblankthread_mode, vblankthread_counter;
struct winuae_currentmode {
unsigned int flags;
static struct winuae_currentmode *currentmode = ¤tmodestruct;
static int wasfullwindow_a, wasfullwindow_p;
-static int vblankbasewait, vblankbasefull;
+static int vblankbasewait, vblankbasewait2, vblankbasefull;
int screen_is_picasso = 0;
extern int reopen (int);
+#define VBLANKTH_KILL 0
+#define VBLANKTH_CALIBRATE 1
+#define VBLANKTH_IDLE 2
+#define VBLANKTH_ACTIVE_WAIT 3
+#define VBLANKTH_ACTIVE 4
+#define VBLANKTH_ACTIVE_START 5
+
+static void changevblankthreadmode (int newmode)
+{
+ int t = vblankthread_counter;
+ thread_vblank_found = false;
+ if (vblankthread_mode <= 0 || vblankthread_mode == newmode)
+ return;
+ vblankthread_mode = newmode;
+ while (t == vblankthread_counter && vblankthread_mode > 0)
+ sleep_millis (1);
+ thread_vblank_found = false;
+}
+
int WIN32GFX_IsPicassoScreen (void)
{
return screen_is_picasso;
return;
} else if (currentmode->flags & DM_DDRAW) {
DirectDraw_SurfaceUnlock ();
+ gfxvidinfo.outbuffer->bufmem = NULL;
}
}
{
int ret, i;
+ changevblankthreadmode (VBLANKTH_IDLE);
+
inputdevice_unacquire ();
wait_keyrelease ();
reset_sound ();
currentmode->current_height != wc->current_height ||
currentmode->current_depth != wc->current_depth)
return -1;
- if (!gfxvidinfo.outbuffer->bufmem_allocated)
+ if (!gfxvidinfo.outbuffer->bufmem_lockable)
return -1;
}
} else if (isfullscreen () == 0) {
void graphics_leave (void)
{
+ changevblankthreadmode (VBLANKTH_KILL);
close_windows ();
}
void close_windows (void)
{
+ changevblankthreadmode (VBLANKTH_IDLE);
reset_sound();
#if defined (GFXFILTER)
S2X_free ();
xfree (gfxvidinfo.drawbuffer.realbufmem);
xfree (gfxvidinfo.tempbuffer.realbufmem);
gfxvidinfo.drawbuffer.bufmem_allocated = false;
+ gfxvidinfo.drawbuffer.bufmem_lockable = false;
gfxvidinfo.drawbuffer.realbufmem = NULL;
gfxvidinfo.tempbuffer.bufmem_allocated = false;
+ gfxvidinfo.tempbuffer.bufmem_lockable = false;
gfxvidinfo.tempbuffer.realbufmem = NULL;
DirectDraw_Release ();
close_hwnds ();
}
-bool waitvblankstate (bool state)
+static bool waitvblankstate (bool state)
{
if (currprefs.gfx_api) {
return D3D_waitvblankstate (state);
}
}
+static bool getvblankstate (bool *state)
+{
+ if (currprefs.gfx_api) {
+ if (!D3D_vblank_getstate (state))
+ return false;
+ return true;
+ } else {
+ if (!DirectDraw_getvblankstate (state))
+ return false;
+ return true;
+ }
+}
+
double getcurrentvblankrate (void)
{
if (remembered_vblank)
return DirectDraw_CurrentRefreshRate ();
}
+static bool threaded_vsync = false;
+volatile bool thread_vblank_found;
+static volatile frame_time_t vblank_prev_time, thread_vblank_time;
+
#include <process.h>
-static volatile int dummythread_die;
-int dummy_counter;
-static void _cdecl dummythread (void *dummy)
-{
- SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_LOWEST);
- while (!dummythread_die)
- dummy_counter++;
+
+static void _cdecl vblankthread (void *dummy)
+{
+ while (vblankthread_mode > VBLANKTH_KILL) {
+ vblankthread_counter++;
+ if (vblankthread_mode == VBLANKTH_CALIBRATE) {
+ // calibrate mode, try to keep CPU power saving inactive
+ SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_LOWEST);
+ while (vblankthread_mode == 0)
+ vblankthread_counter++;
+ SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_ABOVE_NORMAL);
+ } else if (vblankthread_mode == VBLANKTH_IDLE) {
+ // idle mode
+ Sleep(20);
+ } else if (vblankthread_mode == VBLANKTH_ACTIVE_WAIT) {
+ sleep_millis (1);
+ } else if (vblankthread_mode == VBLANKTH_ACTIVE_START) {
+ // do not start until vblank has been passed
+ bool vb = false;
+ bool ok = getvblankstate (&vb);
+ if (vb == false)
+ vblankthread_mode = VBLANKTH_ACTIVE;
+ else
+ sleep_millis (1);
+ } else if (vblankthread_mode == VBLANKTH_ACTIVE) {
+ // busy wait mode
+ frame_time_t t = read_processor_time ();
+ bool donotwait = false;
+ if (!thread_vblank_found) {
+ if (t - thread_vblank_time > vblankbasewait2) {
+ bool vb = false;
+ bool ok = getvblankstate (&vb);
+ if (!ok || vb) {
+ thread_vblank_found = true;
+ //write_log (L"%d\n", t - thread_vblank_time);
+ thread_vblank_time = t;
+ }
+ donotwait = true;
+ }
+ }
+ if (t - vblank_prev_time > vblankbasefull * 3)
+ vblankthread_mode = VBLANKTH_IDLE;
+ if (!donotwait)
+ sleep_millis (1);
+ } else {
+ break;
+ }
+ }
+ vblankthread_mode = -1;
}
+
double vblank_calibrate (double approx_vblank, bool waitonly)
{
frame_time_t t1, t2;
int maxcnt, maxtotal, total, cnt, tcnt2;
HANDLE th;
- if (remembered_vblank > 0)
+ threaded_vsync = (cpu_number > 1 && currprefs.m68k_speed < 0);
+
+ if (remembered_vblank > 0 && (!threaded_vsync || (threaded_vsync && vblankthread_mode > 0)))
return remembered_vblank;
if (waitonly) {
vblankbasefull = syncbase / approx_vblank;
vblankbasewait = (syncbase / approx_vblank) * 3 / 4;
+ vblankbasewait2 = (syncbase / approx_vblank) * 5 / 10;
remembered_vblank = -1;
return -1;
}
+
th = GetCurrentThread ();
int oldpri = GetThreadPriority (th);
SetThreadPriority (th, THREAD_PRIORITY_HIGHEST);
- dummythread_die = -1;
- dummy_counter = 0;
- _beginthread (&dummythread, 0, 0);
+ if (vblankthread_mode <= VBLANKTH_KILL) {
+ vblankthread_mode = VBLANKTH_CALIBRATE;
+ _beginthread (&vblankthread, 0, 0);
+ } else {
+ changevblankthreadmode (VBLANKTH_CALIBRATE);
+ }
sleep_millis (100);
maxtotal = 10;
maxcnt = maxtotal;
cnt = total;
for (cnt = 0; cnt < total; cnt++) {
if (!waitvblankstate (true))
- return -1;
+ goto fail;
if (!waitvblankstate (false))
- return -1;
+ goto fail;
if (!waitvblankstate (true))
- return -1;
+ goto fail;
t1 = read_processor_time ();
if (!waitvblankstate (false))
- return -1;
+ goto fail;
if (!waitvblankstate (true))
- return -1;
+ goto fail;
t2 = read_processor_time ();
tval = (double)syncbase / (t2 - t1);
if (cnt == 0)
tfirst = tval;
if (abs (tval - tfirst) > 1) {
- write_log (L"very unstable vsync! %.6f vs %.6f, retrying..\n", tval, tfirst);
+ write_log (L"Very unstable vsync! %.6f vs %.6f, retrying..\n", tval, tfirst);
break;
}
tsum2 += tval;
tcnt2++;
if (abs (tval - tfirst) > 0.1) {
- write_log (L"unstable vsync! %.6f vs %.6f\n", tval, tfirst);
+ write_log (L"Unstable vsync! %.6f vs %.6f\n", tval, tfirst);
break;
}
tsum += tval;
if (cnt >= total)
break;
}
- dummythread_die = 0;
+ changevblankthreadmode (VBLANKTH_IDLE);
SetThreadPriority (th, oldpri);
if (maxcnt >= maxtotal) {
tsum = tsum2 / tcnt2;
- write_log (L"unstable vsync reporting, using average value\n");
+ write_log (L"Unstable vsync reporting, using average value\n");
} else {
tsum /= total;
}
tsum /= 2;
vblankbasefull = (syncbase / tsum);
vblankbasewait = (syncbase / tsum) * 3 / 4;
- write_log (L"VSync calibration: %.6fHz\n", tsum);
+ vblankbasewait2 = (syncbase / tsum) * 5 / 10;
+ write_log (L"VSync calibration: %.6fHz. Units = %d Mode = %s\n", tsum, vblankbasefull, threaded_vsync ? L"threaded" : L"normal");
remembered_vblank = tsum;
+ vblank_prev_time = read_processor_time ();
return tsum;
+fail:
+ write_log (L"VSync calibration failed\n");
+ changed_prefs.gfx_avsync = 0;
+ return -1;
}
static int frame_missed, frame_counted, frame_errors;
static int frame_usage, frame_usage_avg, frame_usage_total;
extern int log_vsync;
-bool vsync_busywait (int *freetime)
+void vsync_busywait_end (void)
+{
+// frame_time_t t = read_processor_time ();
+
+ changevblankthreadmode (VBLANKTH_ACTIVE_WAIT);
+
+// write_log (L"%d\n", t - thread_vblank_time);
+
+// if (t - vblank_prev_time > vblankbasefull + vblankbasefull * 1 / 3) {
+// frame_missed++;
+// waitvblankstate (true);
+// }
+}
+
+void vsync_busywait_start (void)
+{
+ changevblankthreadmode (VBLANKTH_ACTIVE_START);
+ vblank_prev_time = thread_vblank_time;
+}
+
+bool vsync_busywait_do (int *freetime)
{
bool v;
- static frame_time_t prevtime;
static bool framelost;
+ int ti;
frame_time_t t;
+ frame_time_t prevtime = vblank_prev_time;
- if (log_vsync) {
- console_out_f(L"%8d %8d %3d%% (%3d%%)\r", frame_counted, frame_missed, frame_usage, frame_usage_avg);
- }
-
- *freetime = 0;
- if (currprefs.turbo_emulation) {
+ t = read_processor_time ();
+ ti = t - prevtime;
+ if (ti > 2 * vblankbasefull || ti < -2 * vblankbasefull) {
+ waitvblankstate (false);
+ t = read_processor_time ();
+ vblank_prev_time = t;
+ thread_vblank_time = t;
frame_missed++;
return true;
}
- t = read_processor_time ();
+ if (log_vsync) {
+ console_out_f(L"F:%8d M:%8d E:%8d %3d%% (%3d%%) %10d\r", frame_counted, frame_missed, frame_errors, frame_usage, frame_usage_avg, (t - vblank_prev_time) - vblankbasefull);
+ }
- if (!framelost && t - prevtime > vblankbasefull) {
- framelost = true;
+ *freetime = 0;
+ if (currprefs.turbo_emulation) {
frame_missed++;
return true;
}
frame_usage_avg = frame_usage_total / frame_counted;
v = false;
- while (!framelost && read_processor_time () - prevtime < vblankbasewait)
- sleep_millis (1);
- framelost = false;
- if (currprefs.gfx_api) {
- v = D3D_vblank_busywait ();
+
+ if (threaded_vsync) {
+
+ framelost = false;
+ v = true;
+
} else {
- v = DirectDraw_vblank_busywait ();
+
+ if (!framelost && t - prevtime > vblankbasefull) {
+ framelost = true;
+ frame_missed++;
+ return true;
+ }
+
+ while (!framelost && read_processor_time () - prevtime < vblankbasewait)
+ sleep_millis_main (1);
+
+ framelost = false;
+ if (currprefs.gfx_api) {
+ v = D3D_vblank_busywait ();
+ } else {
+ v = DirectDraw_vblank_busywait ();
+ }
}
+
if (v) {
- prevtime = read_processor_time ();
+ vblank_prev_time = read_processor_time ();
frame_counted++;
return true;
}
static void allocsoftbuffer(struct vidbuffer *buf, int flags, int width, int height, int depth)
{
- if (!(flags & (DM_SWSCALE | DM_D3D)))
- return;
buf->pixbytes = (depth + 7) / 8;
buf->width = (width + 7) & ~7;
buf->height = height;
- if (flags & DM_SWSCALE) {
+ if ((flags & DM_DDRAW) && !(flags & (DM_D3D | DM_SWSCALE))) {
+
+ if (buf != &gfxvidinfo.drawbuffer)
+ return;
+
+ buf->bufmem = NULL;
+ buf->bufmemend = NULL;
+ buf->realbufmem = NULL;
+ buf->bufmem_allocated = false;
+ buf->bufmem_lockable = true;
+
+ } else if (flags & DM_SWSCALE) {
int w = width * 2;
int h = height * 2;
buf->rowbytes = w * 2 * buf->pixbytes;
buf->bufmemend = buf->realbufmem + size - buf->rowbytes;
buf->bufmem_allocated = true;
+ buf->bufmem_lockable = true;
} else if (flags & DM_D3D) {
buf->rowbytes = currentmode->amiga_width * buf->pixbytes;
buf->bufmemend = buf->bufmem + size;
buf->bufmem_allocated = true;
+ buf->bufmem_lockable = true;
+
}
}
gfxvidinfo.drawbuffer.realbufmem = NULL;
gfxvidinfo.drawbuffer.bufmem = NULL;
gfxvidinfo.drawbuffer.bufmem_allocated = false;
+ gfxvidinfo.drawbuffer.bufmem_lockable = false;
gfxvidinfo.outbuffer = &gfxvidinfo.drawbuffer;
gfxvidinfo.inbuffer = &gfxvidinfo.drawbuffer;
if (!screen_is_picasso) {
- if ((currentmode->flags & DM_DDRAW) && !(currentmode->flags & (DM_D3D | DM_SWSCALE))) {
-
- gfxvidinfo.drawbuffer.bufmem_allocated = true;
-
- } else {
-
- allocsoftbuffer(&gfxvidinfo.drawbuffer, currentmode->flags,
- currentmode->current_width > currentmode->amiga_width ? currentmode->current_width : currentmode->amiga_width,
- currentmode->current_height > currentmode->amiga_height ? currentmode->current_height : currentmode->amiga_height,
+ allocsoftbuffer(&gfxvidinfo.drawbuffer, currentmode->flags,
+ currentmode->current_width > currentmode->amiga_width ? currentmode->current_width : currentmode->amiga_width,
+ currentmode->current_height > currentmode->amiga_height ? currentmode->current_height : currentmode->amiga_height,
+ currentmode->current_depth);
+ if (currprefs.monitoremu)
+ allocsoftbuffer(&gfxvidinfo.tempbuffer, currentmode->flags,
+ currentmode->amiga_width > 1024 ? currentmode->amiga_width : 1024,
+ currentmode->amiga_height > 1024 ? currentmode->amiga_height : 1024,
currentmode->current_depth);
- if (currprefs.monitoremu)
- allocsoftbuffer(&gfxvidinfo.tempbuffer, currentmode->flags,
- currentmode->amiga_width > 1024 ? currentmode->amiga_width : 1024,
- currentmode->amiga_height > 1024 ? currentmode->amiga_height : 1024,
- currentmode->current_depth);
- if (currentmode->current_width > gfxvidinfo.drawbuffer.outwidth)
- gfxvidinfo.drawbuffer.outwidth = currentmode->current_width;
- if (gfxvidinfo.drawbuffer.outwidth > gfxvidinfo.drawbuffer.width)
- gfxvidinfo.drawbuffer.outwidth = gfxvidinfo.drawbuffer.width;
+ if (currentmode->current_width > gfxvidinfo.drawbuffer.outwidth)
+ gfxvidinfo.drawbuffer.outwidth = currentmode->current_width;
+ if (gfxvidinfo.drawbuffer.outwidth > gfxvidinfo.drawbuffer.width)
+ gfxvidinfo.drawbuffer.outwidth = gfxvidinfo.drawbuffer.width;
- if (currentmode->current_height > gfxvidinfo.drawbuffer.outheight)
- gfxvidinfo.drawbuffer.outheight = currentmode->current_height;
- if (gfxvidinfo.drawbuffer.outheight > gfxvidinfo.drawbuffer.height)
- gfxvidinfo.drawbuffer.outheight = gfxvidinfo.drawbuffer.height;
+ if (currentmode->current_height > gfxvidinfo.drawbuffer.outheight)
+ gfxvidinfo.drawbuffer.outheight = currentmode->current_height;
+ if (gfxvidinfo.drawbuffer.outheight > gfxvidinfo.drawbuffer.height)
+ gfxvidinfo.drawbuffer.outheight = gfxvidinfo.drawbuffer.height;
- }
init_row_map ();
}
init_colors ();
CheckRadioButton (hDlg, IDC_CPU0, IDC_CPU5, cpu_ids[cpu]);
CheckRadioButton (hDlg, IDC_FPU0, IDC_FPU3, fpu_ids[workprefs.fpu_model == 0 ? 0 : (workprefs.fpu_model == 68881 ? 1 : (workprefs.fpu_model == 68882 ? 2 : 3))]);
- if (workprefs.m68k_speed == -1)
+ if (workprefs.m68k_speed < 0)
CheckRadioButton(hDlg, IDC_CS_HOST, IDC_CS_ADJUSTABLE, IDC_CS_HOST);
else if (workprefs.m68k_speed == 0)
CheckRadioButton(hDlg, IDC_CS_HOST, IDC_CS_ADJUSTABLE, IDC_CS_68000);
+Beta 3:
+
+- Fixed DirectDraw mode crash (b1)
+- Fixed uaenet.device crash if program attempted to open it but winpcap was not installed. (old)
+- Added CD32 drive emulation hack, CD32 Mutation Gold Compilation games now load (but they didn't work on my real CD32 either so technically
+ not working is correct behavior. This hack is removed if it breaks other programs)
+- Too fast CPU audio hack update, one of the hacks actually caused sound glitches with some strange sound routines.
+- Do not blank screen if display can't be shown (DirectDraw display position negative upper left coordinates), now sets coordinates to zero.
+- Keyboard statesave buffer overflow (b1)
+
+- Experimental new vsync mode for fastest possible/JIT CPU modes. Tested using WHDLoad demos and games.
+ - Uses secondary thread which polls vblank state continuously. There is no way to get signal/message/whatever during vblank. Stupid Windows.
+ - Activates automatically if 2 or more CPUs/cores detected and fastest possible/JIT and low latency mode selected.
+ - JIT is also supported.
+ - Works in windowed and fullscreen modes (just like normal low latency vsync).
+ - This mode is currently buffered, used to hide horrible tearing (flip timing is much more complex if fastest possible CPU), will be hopefully improved later.
+ - Sound pitch changes possible, this also needs some improving later.
+
Beta 2:
- Adjusted horizontal positioning, full overscan was not visible.
pdev->unit = unit;
pdev->flags = flags;
pdev->inuse = 1;
- pdev->td = &td[unit];
+ pdev->td = td ? &td[unit] : NULL;
pdev->promiscuous = (flags & SANA2OPF_PROM) ? 1 : 0;
- if (pdev->td->active == 0)
+ if (pdev->td == NULL || pdev->td->active == 0)
return openfail (ioreq, IOERR_OPENFAIL);
if (dev->opencnt == 0) {
}
write_log (L"%s: initializing unit %d\n", getdevname (), unit);
dev->td = pdev->td;
- dev->adapter = pdev->td->active;
+ dev->adapter = pdev->td ? pdev->td->active : 0;
if (dev->adapter) {
dev->online = 1;
dev->configured = 1;