mirror of
https://github.com/LIV2/WinUAE.git
synced 2025-12-06 00:12:52 +00:00
500 lines
9.5 KiB
C++
500 lines
9.5 KiB
C++
|
|
#include "config.h"
|
|
#include "sysconfig.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <signal.h>
|
|
|
|
#include <windows.h>
|
|
#include <commctrl.h>
|
|
#include <commdlg.h>
|
|
#include <shellapi.h>
|
|
#include <zmouse.h>
|
|
#include <ddraw.h>
|
|
#include <dbt.h>
|
|
#include <math.h>
|
|
#include <mmsystem.h>
|
|
|
|
#include "sysdeps.h"
|
|
#include "options.h"
|
|
#include "sound.h"
|
|
#include "uae.h"
|
|
#include "memory.h"
|
|
#include "custom.h"
|
|
#include "events.h"
|
|
#include "xwin.h"
|
|
#include "keyboard.h"
|
|
#include "inputdevice.h"
|
|
#include "keybuf.h"
|
|
#include "drawing.h"
|
|
|
|
HWND hMainWnd;
|
|
HINSTANCE hInst;
|
|
int mouseactive, focus;
|
|
int os_winnt, os_winnt_admin, useqpc, cpu_mmx, pause_emulation;
|
|
char *start_path;
|
|
|
|
static int mm_timerres;
|
|
static int timermode, timeon;
|
|
static HANDLE timehandle;
|
|
|
|
static int timeend (void)
|
|
{
|
|
if (!timeon)
|
|
return 1;
|
|
timeon = 0;
|
|
if (timeEndPeriod (mm_timerres) == TIMERR_NOERROR)
|
|
return 1;
|
|
write_log ("TimeEndPeriod() failed\n");
|
|
return 0;
|
|
}
|
|
|
|
static int timebegin (void)
|
|
{
|
|
if (timeon) {
|
|
timeend();
|
|
return timebegin();
|
|
}
|
|
timeon = 0;
|
|
if (timeBeginPeriod (mm_timerres) == TIMERR_NOERROR) {
|
|
timeon = 1;
|
|
return 1;
|
|
}
|
|
write_log ("TimeBeginPeriod() failed\n");
|
|
return 0;
|
|
}
|
|
|
|
static void init_mmtimer (void)
|
|
{
|
|
TIMECAPS tc;
|
|
mm_timerres = 0;
|
|
if (timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR)
|
|
return;
|
|
mm_timerres = min(max(tc.wPeriodMin, 1), tc.wPeriodMax);
|
|
timehandle = CreateEvent (NULL, TRUE, FALSE, NULL);
|
|
}
|
|
|
|
void sleep_millis (int ms)
|
|
{
|
|
UINT TimerEvent;
|
|
|
|
if (mm_timerres <= 0 || timermode) {
|
|
Sleep (ms);
|
|
return;
|
|
}
|
|
TimerEvent = timeSetEvent (ms, 0, timehandle, 0, TIME_ONESHOT | TIME_CALLBACK_EVENT_SET);
|
|
if (!TimerEvent) {
|
|
Sleep (ms);
|
|
} else {
|
|
WaitForSingleObject (timehandle, ms);
|
|
ResetEvent (timehandle);
|
|
timeKillEvent (TimerEvent);
|
|
}
|
|
}
|
|
|
|
void sleep_millis_busy (int ms)
|
|
{
|
|
if (timermode < 0)
|
|
return;
|
|
sleep_millis (ms);
|
|
}
|
|
|
|
#include <process.h>
|
|
static volatile int dummythread_die;
|
|
static void dummythread (void *dummy)
|
|
{
|
|
SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_LOWEST);
|
|
while (!dummythread_die);
|
|
}
|
|
|
|
static uae_u64 win32_read_processor_time (void)
|
|
{
|
|
uae_u32 foo, bar;
|
|
__asm
|
|
{
|
|
rdtsc
|
|
mov foo, eax
|
|
mov bar, edx
|
|
}
|
|
return ((uae_u64)bar << 32) | foo;
|
|
}
|
|
|
|
static int figure_processor_speed (void)
|
|
{
|
|
extern volatile frame_time_t vsynctime;
|
|
extern unsigned long syncbase;
|
|
uae_u64 clockrate, clockrateidle, qpfrate, ratea1, ratea2;
|
|
uae_u32 rate1, rate2;
|
|
double limit, clkdiv = 1, clockrate1000 = 0;
|
|
int i, ratecnt = 6;
|
|
LARGE_INTEGER freq;
|
|
int qpc_avail = 0;
|
|
int mmx = 0;
|
|
|
|
rpt_available = 1;
|
|
__try
|
|
{
|
|
__asm
|
|
{
|
|
rdtsc
|
|
}
|
|
} __except( GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION ) {
|
|
rpt_available = 0;
|
|
write_log ("CLOCKFREQ: RDTSC not supported\n");
|
|
}
|
|
__try
|
|
{
|
|
__asm
|
|
{
|
|
mov eax,1
|
|
cpuid
|
|
and edx,0x800000
|
|
mov mmx,edx
|
|
}
|
|
if (mmx)
|
|
cpu_mmx = 1;
|
|
} __except( GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION ) {
|
|
}
|
|
|
|
if (QueryPerformanceFrequency(&freq)) {
|
|
qpc_avail = 1;
|
|
write_log ("CLOCKFREQ: QPF %.2fMHz\n", freq.QuadPart / 1000000.0);
|
|
qpfrate = freq.QuadPart;
|
|
/* we don't want 32-bit overflow */
|
|
if (qpfrate > 100000000) {
|
|
qpfrate >>= 6;
|
|
qpc_avail = -1;
|
|
}
|
|
} else {
|
|
write_log ("CLOCKREQ: QPF not supported\n");
|
|
}
|
|
|
|
if (!rpt_available && !qpc_avail)
|
|
return 0;
|
|
|
|
init_mmtimer();
|
|
SetThreadPriority ( GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
|
|
sleep_millis (100);
|
|
dummythread_die = -1;
|
|
|
|
if (qpc_avail || rpt_available) {
|
|
|
|
if (rpt_available) {
|
|
clockrateidle = win32_read_processor_time();
|
|
sleep_millis (500);
|
|
clockrateidle = (win32_read_processor_time() - clockrateidle) * 2;
|
|
dummythread_die = 0;
|
|
_beginthread(&dummythread, 0, 0);
|
|
sleep_millis (100);
|
|
clockrate = win32_read_processor_time();
|
|
sleep_millis (500);
|
|
clockrate = (win32_read_processor_time() - clockrate) * 2;
|
|
write_log ("CLOCKFREQ: RDTSC %.2fMHz (busy) / %.2fMHz (idle)\n",
|
|
clockrate / 1000000.0, clockrateidle / 1000000.0);
|
|
clkdiv = (double)clockrate / (double)clockrateidle;
|
|
clockrate >>= 6;
|
|
clockrate1000 = clockrate / 1000.0;
|
|
}
|
|
if (clkdiv <= 0.95 || clkdiv >= 1.05 || !rpt_available) {
|
|
if (rpt_available)
|
|
write_log ("CLOCKFREQ: CPU throttling detected, using QPF instead of RDTSC\n");
|
|
useqpc = qpc_avail;
|
|
rpt_available = 1;
|
|
clkdiv = 1.0;
|
|
clockrate = qpfrate;
|
|
clockrate1000 = clockrate / 1000.0;
|
|
if (dummythread_die < 0) {
|
|
dummythread_die = 0;
|
|
_beginthread(&dummythread, 0, 0);
|
|
}
|
|
if (!qpc_avail)
|
|
write_log ("No working timing reference detected\n");
|
|
}
|
|
timermode = 0;
|
|
if (mm_timerres) {
|
|
sleep_millis (50);
|
|
timebegin ();
|
|
sleep_millis (50);
|
|
ratea1 = 0;
|
|
write_log ("Testing MM-timer resolution:\n");
|
|
for (i = 0; i < ratecnt; i++) {
|
|
rate1 = read_processor_time();
|
|
sleep_millis (1);
|
|
rate1 = read_processor_time() - rate1;
|
|
write_log ("%1.2fms ", rate1 / clockrate1000);
|
|
ratea1 += rate1;
|
|
}
|
|
write_log ("\n");
|
|
timeend ();
|
|
sleep_millis (50);
|
|
}
|
|
timermode = 1;
|
|
ratea2 = 0;
|
|
write_log ("Testing Sleep() resolution:\n");
|
|
for (i = 0; i < ratecnt; i++) {
|
|
rate2 = read_processor_time();
|
|
sleep_millis (1);
|
|
rate2 = read_processor_time() - rate2;
|
|
write_log ("%1.2fms ", rate2 / clockrate1000);
|
|
ratea2 += rate2;
|
|
}
|
|
write_log ("\n");
|
|
}
|
|
|
|
SetThreadPriority ( GetCurrentThread(), THREAD_PRIORITY_NORMAL);
|
|
dummythread_die = 1;
|
|
|
|
if (clkdiv >= 0.90 && clkdiv <= 1.10 && rpt_available) {
|
|
limit = 2.5;
|
|
if ((ratea2 / ratecnt) < limit * clockrate1000) { /* regular Sleep() is ok */
|
|
timermode = 1;
|
|
write_log ("Using Sleep() (resolution < %.1fms)\n", limit);
|
|
} else if (mm_timerres && (ratea1 / ratecnt) < limit * clockrate1000) { /* MM-timer is ok */
|
|
timermode = 0;
|
|
timebegin ();
|
|
write_log ("Using MultiMedia timers (resolution < %.1fms)\n", limit);
|
|
} else {
|
|
timermode = -1; /* both timers are bad, fall back to busy-wait */
|
|
write_log ("falling back to busy-loop waiting (timer resolution > %.1fms)\n", limit);
|
|
}
|
|
} else {
|
|
timermode = -1;
|
|
write_log ("forcing busy-loop wait mode\n");
|
|
}
|
|
syncbase = (unsigned long)clockrate;
|
|
return 1;
|
|
}
|
|
|
|
int needmousehack (void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void gui_message (const char *format,...)
|
|
{
|
|
}
|
|
|
|
void gui_led (int led, int on)
|
|
{
|
|
}
|
|
|
|
void gui_fps (int fps)
|
|
{
|
|
}
|
|
|
|
void gui_hd_led (int led)
|
|
{
|
|
}
|
|
|
|
void gui_cd_led (int led)
|
|
{
|
|
}
|
|
|
|
void gui_unlock (void)
|
|
{
|
|
}
|
|
|
|
void gui_lock (void)
|
|
{
|
|
}
|
|
|
|
int gui_update (void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
char *DXError (HRESULT ddrval)
|
|
{
|
|
return "";
|
|
}
|
|
|
|
void setmouseactive (int active)
|
|
{
|
|
}
|
|
|
|
void minimizewindow (void)
|
|
{
|
|
}
|
|
|
|
int isfullscreen (void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void fullscreentoggle (void)
|
|
{
|
|
}
|
|
|
|
void disablecapture (void)
|
|
{
|
|
}
|
|
|
|
void WIN32GUI_DisplayGUI (int shortcut)
|
|
{
|
|
}
|
|
|
|
void flush_block (int a, int b)
|
|
{
|
|
}
|
|
|
|
void flush_screen (int a, int b)
|
|
{
|
|
}
|
|
|
|
void flush_line (int lineno)
|
|
{
|
|
}
|
|
|
|
void flush_clear_screen (void)
|
|
{
|
|
}
|
|
|
|
int lockscr (void)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
void unlockscr (void)
|
|
{
|
|
}
|
|
|
|
void machdep_init (void)
|
|
{
|
|
}
|
|
|
|
void handle_events (void)
|
|
{
|
|
}
|
|
|
|
int debuggable (void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int graphics_init (void)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
int graphics_setup (void)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
void graphics_leave (void)
|
|
{
|
|
}
|
|
|
|
extern FILE *debugfile;
|
|
char VersionStr[256];
|
|
static OSVERSIONINFO osVersion;
|
|
void logging_init( void )
|
|
{
|
|
static int started;
|
|
static int first;
|
|
char debugfilename[MAX_DPATH];
|
|
|
|
if (first > 1) {
|
|
write_log ("** RESTART **\n");
|
|
return;
|
|
}
|
|
if (first == 1) {
|
|
if (debugfile)
|
|
fclose (debugfile);
|
|
debugfile = 0;
|
|
}
|
|
if( currprefs.win32_logfile ) {
|
|
sprintf( debugfilename, "%s\\winuaelog.txt", start_path );
|
|
if( !debugfile )
|
|
debugfile = fopen( debugfilename, "wt" );
|
|
} else if (!first) {
|
|
sprintf( debugfilename, "%s\\winuaebootlog.txt", start_path );
|
|
if( !debugfile )
|
|
debugfile = fopen( debugfilename, "wt" );
|
|
}
|
|
first++;
|
|
write_log ( "%s", VersionStr );
|
|
write_log (" (OS: %s %d.%d%s)", os_winnt ? "NT" : "W9X/ME", osVersion.dwMajorVersion, osVersion.dwMinorVersion, os_winnt_admin ? " Administrator privileges" : "");
|
|
write_log ("\n(c) 1995-2001 Bernd Schmidt - Core UAE concept and implementation."
|
|
"\n(c) 1998-2003 Toni Wilen - Win32 port, core code updates."
|
|
"\n(c) 1996-2001 Brian King - Win32 port, Picasso96 RTG, and GUI."
|
|
"\n(c) 1996-1999 Mathias Ortmann - Win32 port and bsdsocket support."
|
|
"\n(c) 2000-2001 Bernd Meyer - JIT engine."
|
|
"\n(c) 2000-2001 Bernd Roesch - MIDI input, many fixes."
|
|
"\nPress F12 to show the Settings Dialog (GUI), Alt-F4 to quit."
|
|
"\nEnd+F1 changes floppy 0, End+F2 changes floppy 1, etc."
|
|
"\n");
|
|
}
|
|
|
|
void target_save_options (FILE *f, struct uae_prefs *p)
|
|
{
|
|
}
|
|
|
|
int target_parse_option (struct uae_prefs *p, char *option, char *value)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int gui_init (void)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
void gui_exit (void)
|
|
{
|
|
}
|
|
|
|
void gui_filename (int num, const char *name)
|
|
{
|
|
}
|
|
|
|
void setup_brkhandler (void)
|
|
{
|
|
}
|
|
|
|
int check_prefs_changed_gfx (void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void screenshot (int mode)
|
|
{
|
|
}
|
|
|
|
int _stdcall WinMain (HINSTANCE hInstance, HINSTANCE prev, LPSTR cmd, int show)
|
|
{
|
|
char **argv, *posn;
|
|
int argc;
|
|
|
|
hInst = hInstance;
|
|
argc = __argc; argv = __argv;
|
|
start_path = xmalloc( MAX_DPATH );
|
|
GetModuleFileName( NULL, start_path, MAX_DPATH );
|
|
if( ( posn = strrchr( start_path, '\\' ) ) )
|
|
*posn = 0;
|
|
real_main (argc, argv);
|
|
if (mm_timerres && timermode == 0)
|
|
timeend ();
|
|
free (start_path);
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|