2018-02-20 21:44:51 -05:00
|
|
|
/*
|
2018-03-08 15:58:46 -05:00
|
|
|
* VARCem Virtual ARchaeological Computer EMulator.
|
2018-02-20 21:44:51 -05:00
|
|
|
* An emulator of (mostly) x86-based PC systems and devices,
|
|
|
|
|
* using the ISA,EISA,VLB,MCA and PCI system buses, roughly
|
|
|
|
|
* spanning the era between 1981 and 1995.
|
|
|
|
|
*
|
|
|
|
|
* This file is part of the VARCem Project.
|
|
|
|
|
*
|
|
|
|
|
* Main emulator module where most things are controlled.
|
|
|
|
|
*
|
2018-10-08 02:27:07 -04:00
|
|
|
* Version: @(#)pc.c 1.0.55 2018/10/07
|
2018-02-20 21:44:51 -05:00
|
|
|
*
|
|
|
|
|
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
|
|
|
|
|
* Miran Grca, <mgrca8@gmail.com>
|
|
|
|
|
* Sarah Walker, <tommowalker@tommowalker.co.uk>
|
|
|
|
|
*
|
|
|
|
|
* Copyright 2017,2018 Fred N. van Kempen.
|
|
|
|
|
* Copyright 2016-2018 Miran Grca.
|
|
|
|
|
* Copyright 2008-2018 Sarah Walker.
|
|
|
|
|
*
|
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful, but
|
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
* General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, write to the:
|
|
|
|
|
*
|
|
|
|
|
* Free Software Foundation, Inc.
|
|
|
|
|
* 59 Temple Place - Suite 330
|
|
|
|
|
* Boston, MA 02111-1307
|
|
|
|
|
* USA.
|
|
|
|
|
*/
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdint.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
#include <time.h>
|
|
|
|
|
#include <wchar.h>
|
|
|
|
|
#define HAVE_STDARG_H
|
|
|
|
|
#include "emu.h"
|
2018-03-08 01:21:26 -05:00
|
|
|
#include "version.h"
|
2018-02-20 21:44:51 -05:00
|
|
|
#include "config.h"
|
|
|
|
|
#include "cpu/cpu.h"
|
|
|
|
|
#ifdef USE_DYNAREC
|
2018-10-06 18:20:09 -04:00
|
|
|
# include "cpu/x86.h"
|
2018-02-20 21:44:51 -05:00
|
|
|
# include "cpu/codegen.h"
|
|
|
|
|
#endif
|
2018-05-06 22:47:14 -04:00
|
|
|
#include "machines/machine.h"
|
2018-02-20 21:44:51 -05:00
|
|
|
#include "io.h"
|
2018-05-06 22:47:14 -04:00
|
|
|
#include "devices/system/dma.h"
|
|
|
|
|
#include "devices/system/pic.h"
|
|
|
|
|
#include "devices/system/pit.h"
|
2018-02-20 21:44:51 -05:00
|
|
|
#include "random.h"
|
|
|
|
|
#include "timer.h"
|
|
|
|
|
#include "device.h"
|
|
|
|
|
#include "nvr.h"
|
2018-05-06 22:47:14 -04:00
|
|
|
#include "devices/ports/game.h"
|
|
|
|
|
#include "devices/ports/serial.h"
|
|
|
|
|
#include "devices/ports/parallel.h"
|
|
|
|
|
#include "devices/input/keyboard.h"
|
|
|
|
|
#include "devices/input/mouse.h"
|
|
|
|
|
#include "devices/input/game/joystick.h"
|
|
|
|
|
#include "devices/floppy/fdd.h"
|
|
|
|
|
#include "devices/floppy/fdd_common.h"
|
|
|
|
|
#include "devices/disk/hdd.h"
|
|
|
|
|
#include "devices/disk/hdc.h"
|
2018-10-06 18:20:09 -04:00
|
|
|
#include "devices/scsi/scsi.h"
|
|
|
|
|
#include "devices/scsi/scsi_device.h"
|
|
|
|
|
#include "devices/scsi/scsi_disk.h"
|
2018-05-06 22:47:14 -04:00
|
|
|
#include "devices/disk/zip.h"
|
|
|
|
|
#include "devices/cdrom/cdrom.h"
|
|
|
|
|
#include "devices/network/network.h"
|
|
|
|
|
#include "devices/sound/sound.h"
|
|
|
|
|
#include "devices/video/video.h"
|
2018-05-08 03:09:43 -04:00
|
|
|
#include "devices/misc/bugger.h"
|
2018-08-25 14:52:23 -04:00
|
|
|
#include "devices/misc/isamem.h"
|
2018-08-29 03:58:50 -04:00
|
|
|
#include "devices/misc/isartc.h"
|
2018-04-29 19:36:54 -04:00
|
|
|
#include "ui/ui.h"
|
2018-02-20 21:44:51 -05:00
|
|
|
#include "plat.h"
|
|
|
|
|
|
|
|
|
|
|
2018-06-16 18:38:02 -04:00
|
|
|
#define PCLOG_BUFF_SIZE 8192 /* has to be big enough!! */
|
|
|
|
|
|
|
|
|
|
|
2018-02-20 21:44:51 -05:00
|
|
|
/* Commandline options. */
|
|
|
|
|
int dump_on_exit = 0; /* (O) dump regs on exit */
|
|
|
|
|
int do_dump_config = 0; /* (O) dump config on load */
|
|
|
|
|
int start_in_fullscreen = 0; /* (O) start in fullscreen */
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
int force_debug = 0; /* (O) force debug output */
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef USE_WX
|
|
|
|
|
int video_fps = RENDER_FPS; /* (O) render speed in fps */
|
|
|
|
|
#endif
|
|
|
|
|
int settings_only = 0; /* (O) only the settings dlg */
|
2018-03-22 00:01:41 -05:00
|
|
|
int config_ro = 0; /* (O) dont modify cfg file */
|
2018-10-06 18:20:09 -04:00
|
|
|
int log_level = LOG_INFO; /* (O) global logging level */
|
2018-02-20 21:44:51 -05:00
|
|
|
wchar_t log_path[1024] = { L'\0'}; /* (O) full path of logfile */
|
|
|
|
|
|
|
|
|
|
/* Configuration values. */
|
2018-10-06 18:20:09 -04:00
|
|
|
int language = 0x0000; /* (C) language ID */
|
2018-02-20 21:44:51 -05:00
|
|
|
int window_w, window_h, /* (C) window size and */
|
|
|
|
|
window_x, window_y, /* position info */
|
2018-04-20 04:16:43 -04:00
|
|
|
window_remember;
|
|
|
|
|
int vid_api = 0, /* (C) video renderer */
|
2018-02-20 21:44:51 -05:00
|
|
|
vid_resize, /* (C) allow resizing */
|
2018-04-20 04:16:43 -04:00
|
|
|
vid_cga_contrast = 0, /* (C) video */
|
|
|
|
|
vid_fullscreen = 0, /* (C) video */
|
|
|
|
|
vid_fullscreen_scale = 0, /* (C) video */
|
|
|
|
|
vid_fullscreen_first = 0, /* (C) video */
|
|
|
|
|
vid_grayscale = 0, /* (C) video */
|
|
|
|
|
vid_graytype = 0, /* (C) video */
|
|
|
|
|
invert_display = 0, /* (C) invert the display */
|
|
|
|
|
suppress_overscan = 0, /* (C) suppress overscans */
|
|
|
|
|
scale = 0, /* (C) screen scale factor */
|
2018-02-20 21:44:51 -05:00
|
|
|
enable_overscan = 0, /* (C) video */
|
|
|
|
|
force_43 = 0, /* (C) video */
|
2018-10-06 18:20:09 -04:00
|
|
|
rctrl_is_lalt; /* (C) set R-CTRL as L-ALT */
|
2018-04-29 19:36:54 -04:00
|
|
|
int video_card = 0, /* (C) graphics/video card */
|
2018-04-20 04:16:43 -04:00
|
|
|
voodoo_enabled = 0; /* (C) video option */
|
|
|
|
|
int mouse_type = 0; /* (C) selected mouse type */
|
2018-10-06 18:20:09 -04:00
|
|
|
int time_sync = 0; /* (C) enable time sync */
|
2018-04-26 16:46:42 -04:00
|
|
|
int game_enabled = 0, /* (C) enable game port */
|
|
|
|
|
serial_enabled[] = {0,0}, /* (C) enable serial ports */
|
2018-04-08 17:25:35 -04:00
|
|
|
parallel_enabled[] = {0,0,0}, /* (C) enable LPT ports */
|
|
|
|
|
parallel_device[] = {0,0,0}, /* (C) set up LPT devices */
|
2018-08-25 14:52:23 -04:00
|
|
|
bugger_enabled = 0, /* (C) enable ISAbugger */
|
2018-08-29 03:58:50 -04:00
|
|
|
isamem_type[ISAMEM_MAX] = { 0,0,0,0 }, /* (C) enable ISA mem cards */
|
|
|
|
|
isartc_type = 0; /* (C) enable ISA RTC card */
|
2018-02-20 21:44:51 -05:00
|
|
|
#ifdef WALTJE
|
|
|
|
|
int romdos_enabled = 0; /* (C) enable ROM DOS */
|
|
|
|
|
#endif
|
2018-04-07 00:23:55 -04:00
|
|
|
int hdc_type = 0; /* (C) HDC type */
|
2018-04-20 04:16:43 -04:00
|
|
|
int scsi_card = 0; /* (C) selected SCSI card */
|
|
|
|
|
int sound_card = 0, /* (C) selected sound card */
|
|
|
|
|
sound_is_float = 1, /* (C) sound uses FP values */
|
|
|
|
|
sound_gain = 0, /* (C) sound volume gain */
|
2018-04-08 21:19:10 -04:00
|
|
|
mpu401_standalone_enable = 0, /* (C) sound option */
|
2018-10-06 18:20:09 -04:00
|
|
|
opl_type = 0, /* (C) sound option */
|
2018-04-20 04:16:43 -04:00
|
|
|
midi_device; /* (C) selected midi device */
|
2018-03-20 17:13:12 -05:00
|
|
|
int joystick_type = 0; /* (C) joystick type */
|
2018-02-20 21:44:51 -05:00
|
|
|
int mem_size = 0; /* (C) memory size */
|
2018-10-06 18:20:09 -04:00
|
|
|
int machine = -1; /* (C) current machine ID */
|
2018-02-20 21:44:51 -05:00
|
|
|
int cpu_manufacturer = 0, /* (C) cpu manufacturer */
|
|
|
|
|
cpu_use_dynarec = 0, /* (C) cpu uses/needs Dyna */
|
|
|
|
|
cpu = 3, /* (C) cpu type */
|
|
|
|
|
enable_external_fpu = 0; /* (C) enable external FPU */
|
2018-03-17 23:13:46 -05:00
|
|
|
int network_type; /* (C) net provider type */
|
|
|
|
|
int network_card; /* (C) net interface num */
|
|
|
|
|
char network_host[512]; /* (C) host network intf */
|
|
|
|
|
|
2018-10-06 18:20:09 -04:00
|
|
|
/* Global variables. */
|
2018-03-22 00:01:41 -05:00
|
|
|
char emu_title[64]; /* full name of application */
|
|
|
|
|
char emu_version[32]; /* short version ID string */
|
|
|
|
|
char emu_fullversion[128]; /* full version ID string */
|
2018-08-26 23:54:14 -04:00
|
|
|
wchar_t exe_path[1024]; /* emu executable path */
|
2018-03-03 00:47:51 -05:00
|
|
|
wchar_t emu_path[1024]; /* emu installation path */
|
2018-02-20 21:44:51 -05:00
|
|
|
wchar_t usr_path[1024]; /* path (dir) of user data */
|
|
|
|
|
wchar_t cfg_path[1024]; /* full path of config file */
|
2018-10-06 18:20:09 -04:00
|
|
|
int emu_lang_id; /* current language ID */
|
2018-02-20 21:44:51 -05:00
|
|
|
int scrnsz_x = SCREEN_RES_X, /* current screen size, X */
|
|
|
|
|
scrnsz_y = SCREEN_RES_Y; /* current screen size, Y */
|
2018-10-06 18:20:09 -04:00
|
|
|
int config_changed, /* config has changed */
|
|
|
|
|
dopause = 0, /* system is paused */
|
|
|
|
|
doresize = 0, /* screen resize requested */
|
|
|
|
|
mouse_capture = 0; /* mouse is captured in app */
|
|
|
|
|
|
|
|
|
|
/* Local variables. */
|
|
|
|
|
static int fps, /* statistics */
|
|
|
|
|
framecount,
|
|
|
|
|
title_update, /* we want title updated */
|
|
|
|
|
atfullspeed,
|
|
|
|
|
cpuspeed2;
|
|
|
|
|
static int unscaled_size_x = SCREEN_RES_X, /* current unscaled size X */
|
|
|
|
|
unscaled_size_y = SCREEN_RES_Y, /* current unscaled size Y */
|
|
|
|
|
efscrnsz_y = SCREEN_RES_Y;
|
|
|
|
|
static FILE *stdlog = NULL; /* file to log output to */
|
2018-02-20 21:44:51 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Log something to the logfile or stdout.
|
|
|
|
|
*
|
|
|
|
|
* To avoid excessively-large logfiles because some
|
|
|
|
|
* module repeatedly logs, we keep track of what is
|
|
|
|
|
* being logged, and catch repeating entries.
|
2018-06-16 18:38:02 -04:00
|
|
|
*
|
|
|
|
|
* Note: we need fairly large buffers here, to allow
|
|
|
|
|
* for the network code dumping packet content
|
|
|
|
|
* with this.
|
2018-02-20 21:44:51 -05:00
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
pclog_ex(const char *fmt, va_list ap)
|
|
|
|
|
{
|
2018-06-16 18:38:02 -04:00
|
|
|
static char buff[PCLOG_BUFF_SIZE];
|
2018-02-20 21:44:51 -05:00
|
|
|
static int seen = 0;
|
2018-06-27 15:03:58 -04:00
|
|
|
static int detect = 1;
|
2018-06-16 18:38:02 -04:00
|
|
|
char temp[PCLOG_BUFF_SIZE];
|
2018-10-08 02:27:07 -04:00
|
|
|
FILE *fp;
|
2018-02-20 21:44:51 -05:00
|
|
|
|
2018-06-27 15:03:58 -04:00
|
|
|
if (fmt == NULL) {
|
|
|
|
|
/* Initialize. */
|
|
|
|
|
detect = (ap != NULL) ? 1 : 0;
|
|
|
|
|
seen = 0;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-08 02:27:07 -04:00
|
|
|
/* If a logpath was set, override the default. */
|
|
|
|
|
if (log_path[0] != L'\0') {
|
|
|
|
|
fp = plat_fopen(log_path, L"w");
|
|
|
|
|
if (fp != NULL)
|
|
|
|
|
stdlog = fp;
|
2018-02-20 21:44:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vsprintf(temp, fmt, ap);
|
2018-06-27 15:03:58 -04:00
|
|
|
if (detect && !strcmp(buff, temp)) {
|
2018-02-20 21:44:51 -05:00
|
|
|
seen++;
|
|
|
|
|
} else {
|
|
|
|
|
if (seen) {
|
2018-10-08 02:27:07 -04:00
|
|
|
fprintf(stdlog, "*** %i repeats ***\n", seen);
|
2018-02-20 21:44:51 -05:00
|
|
|
}
|
|
|
|
|
seen = 0;
|
|
|
|
|
strcpy(buff, temp);
|
|
|
|
|
fprintf(stdlog, temp, ap);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fflush(stdlog);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Log something. We only do this in non-release builds. */
|
|
|
|
|
void
|
2018-10-06 18:20:09 -04:00
|
|
|
pclog(int level, const char *fmt, ...)
|
2018-02-20 21:44:51 -05:00
|
|
|
{
|
|
|
|
|
va_list ap;
|
|
|
|
|
|
2018-10-06 18:20:09 -04:00
|
|
|
if (fmt == NULL) {
|
|
|
|
|
fflush(stdlog);
|
|
|
|
|
fclose(stdlog);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (log_level >= level) {
|
|
|
|
|
va_start(ap, fmt);
|
|
|
|
|
pclog_ex(fmt, ap);
|
|
|
|
|
va_end(ap);
|
|
|
|
|
}
|
2018-02-20 21:44:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-06-27 15:03:58 -04:00
|
|
|
/* Enable or disable detection of repeated info being logged. */
|
|
|
|
|
void
|
|
|
|
|
pclog_repeat(int enabled)
|
|
|
|
|
{
|
|
|
|
|
pclog_ex(NULL, (va_list)enabled);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
|
/* Log a block of code around the current CS:IP. */
|
|
|
|
|
void
|
|
|
|
|
pclog_dump(int num)
|
|
|
|
|
{
|
|
|
|
|
char buff[128];
|
|
|
|
|
char *sp = NULL;
|
|
|
|
|
int i, k;
|
|
|
|
|
|
|
|
|
|
/* We make the current PC be in the middle of the block. */
|
|
|
|
|
num >>= 1;
|
|
|
|
|
i = -num;
|
|
|
|
|
|
|
|
|
|
/* Disable the repeat-detection. */
|
|
|
|
|
pclog_repeat(0);
|
|
|
|
|
|
|
|
|
|
while (i < num) {
|
|
|
|
|
if (sp == NULL) {
|
|
|
|
|
sp = buff;
|
2018-07-28 20:52:51 -04:00
|
|
|
sprintf(sp, "%08lx:", (unsigned long)cpu_state.pc + i);
|
2018-06-27 15:03:58 -04:00
|
|
|
sp += strlen(sp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Get byte from memory. */
|
|
|
|
|
k = readmembl(cpu_state.pc + i);
|
|
|
|
|
i++;
|
|
|
|
|
|
|
|
|
|
sprintf(sp, " %02x", k & 0xff);
|
|
|
|
|
sp += strlen(sp);
|
|
|
|
|
|
|
|
|
|
if ((i % 16) == 0) {
|
2018-10-06 18:20:09 -04:00
|
|
|
DBGLOG(2, "%s\n", buff);
|
2018-06-27 15:03:58 -04:00
|
|
|
sp = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (sp != NULL) {
|
2018-10-06 18:20:09 -04:00
|
|
|
DBGLOG(2, "%s\n", buff);
|
2018-06-27 15:03:58 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Re-enable the repeat-detection. */
|
|
|
|
|
pclog_repeat(1);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
2018-02-20 21:44:51 -05:00
|
|
|
/* Log a fatal error, and display a UI message before exiting. */
|
|
|
|
|
void
|
|
|
|
|
fatal(const char *fmt, ...)
|
|
|
|
|
{
|
|
|
|
|
char temp[1024];
|
|
|
|
|
va_list ap;
|
|
|
|
|
char *sp;
|
|
|
|
|
|
|
|
|
|
va_start(ap, fmt);
|
|
|
|
|
|
|
|
|
|
if (stdlog == NULL) {
|
|
|
|
|
if (log_path[0] != L'\0') {
|
|
|
|
|
stdlog = plat_fopen(log_path, L"w");
|
|
|
|
|
if (stdlog == NULL)
|
|
|
|
|
stdlog = stdout;
|
|
|
|
|
} else {
|
|
|
|
|
stdlog = stdout;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vsprintf(temp, fmt, ap);
|
|
|
|
|
fprintf(stdlog, "%s", temp);
|
|
|
|
|
fflush(stdlog);
|
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
|
|
nvr_save();
|
|
|
|
|
|
|
|
|
|
config_save();
|
|
|
|
|
|
|
|
|
|
dumppic();
|
|
|
|
|
dumpregs(1);
|
|
|
|
|
|
2018-09-22 19:14:45 -04:00
|
|
|
/*
|
|
|
|
|
* Attempt to perform a clean exit by terminating the
|
|
|
|
|
* main loop of the emulator, which hopefully also do
|
|
|
|
|
* a shutdown of all running threads.
|
|
|
|
|
*/
|
|
|
|
|
plat_stop();
|
|
|
|
|
|
2018-02-20 21:44:51 -05:00
|
|
|
/* Make sure the message does not have a trailing newline. */
|
|
|
|
|
if ((sp = strchr(temp, '\n')) != NULL) *sp = '\0';
|
|
|
|
|
|
|
|
|
|
ui_msgbox(MBX_ERROR|MBX_FATAL|MBX_ANSI, temp);
|
|
|
|
|
|
|
|
|
|
fflush(stdlog);
|
|
|
|
|
|
|
|
|
|
exit(-1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-03-08 01:21:26 -05:00
|
|
|
/* Set the application version ID string. */
|
|
|
|
|
void
|
|
|
|
|
pc_version(const char *platform)
|
|
|
|
|
{
|
|
|
|
|
char temp[128];
|
|
|
|
|
|
|
|
|
|
sprintf(emu_title, "%s for %s", EMU_NAME, platform);
|
|
|
|
|
|
2018-04-09 23:09:44 -04:00
|
|
|
#ifdef EMU_VER_PATCH
|
2018-04-09 23:12:23 -04:00
|
|
|
sprintf(emu_version, "v%s", EMU_VERSION_4);
|
2018-04-09 23:09:44 -04:00
|
|
|
#else
|
2018-03-22 00:01:41 -05:00
|
|
|
sprintf(emu_version, "v%s", EMU_VERSION);
|
2018-04-09 23:09:44 -04:00
|
|
|
#endif
|
2018-03-22 00:01:41 -05:00
|
|
|
strcpy(emu_fullversion, emu_version);
|
2018-03-08 01:21:26 -05:00
|
|
|
|
2018-06-16 18:38:02 -04:00
|
|
|
#if defined(_MSC_VER)
|
2018-10-08 02:27:07 -04:00
|
|
|
sprintf(temp, " [VC %i]", _MSC_VER);
|
2018-06-16 18:38:02 -04:00
|
|
|
#elif defined(__clang_major__)
|
2018-10-08 02:27:07 -04:00
|
|
|
sprintf(temp, " [Clang %i.%i.%i]",
|
2018-06-16 18:38:02 -04:00
|
|
|
__clang_major__, __clang_minor__, __clang_patchlevel__);
|
|
|
|
|
#elif defined(__GNUC__)
|
2018-10-08 02:27:07 -04:00
|
|
|
sprintf(temp, " [GCC %i.%i.%i]",
|
2018-06-16 18:38:02 -04:00
|
|
|
__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__);
|
2018-05-03 17:25:04 -04:00
|
|
|
#endif
|
2018-06-16 18:38:02 -04:00
|
|
|
strcat(emu_fullversion, temp);
|
2018-05-03 17:25:04 -04:00
|
|
|
|
2018-03-08 01:21:26 -05:00
|
|
|
#ifdef BUILD
|
2018-10-08 02:27:07 -04:00
|
|
|
sprintf(temp, " (Build %i", BUILD);
|
2018-03-22 00:01:41 -05:00
|
|
|
strcat(emu_fullversion, temp);
|
2018-03-14 14:07:34 -05:00
|
|
|
#endif
|
2018-03-08 01:21:26 -05:00
|
|
|
#ifdef COMMIT
|
2018-03-18 18:39:02 -05:00
|
|
|
sprintf(temp, " [Commit #%x]", COMMIT);
|
2018-03-22 00:01:41 -05:00
|
|
|
strcat(emu_fullversion, temp);
|
2018-03-08 01:21:26 -05:00
|
|
|
#endif
|
2018-03-14 14:07:34 -05:00
|
|
|
#ifdef BUILD
|
2018-03-22 00:01:41 -05:00
|
|
|
strcat(emu_fullversion, ")");
|
2018-03-08 01:21:26 -05:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef UPSTREAM
|
|
|
|
|
sprintf(temp, " [Upstream #%x]", UPSTREAM);
|
2018-03-22 00:01:41 -05:00
|
|
|
strcat(emu_fullversion, temp);
|
2018-03-08 01:21:26 -05:00
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-04-01 22:00:58 -04:00
|
|
|
/*
|
|
|
|
|
* NOTE:
|
|
|
|
|
*
|
|
|
|
|
* Although we now use relative pathnames in the code,
|
|
|
|
|
* we may still bump into old configuration files that
|
|
|
|
|
* still have old, absolute pathnames.
|
|
|
|
|
*
|
|
|
|
|
* We try to "fix" those by stripping the "usr_path"
|
|
|
|
|
* component from them, if they have that. If another
|
|
|
|
|
* path, well, nothing we can do here.
|
|
|
|
|
*/
|
|
|
|
|
void
|
2018-04-11 17:40:51 -04:00
|
|
|
pc_path(wchar_t *dst, int sz, const wchar_t *src)
|
2018-04-01 22:00:58 -04:00
|
|
|
{
|
2018-05-11 21:31:30 -04:00
|
|
|
const wchar_t *str = src;
|
|
|
|
|
wchar_t *ptr = dst;
|
2018-04-03 03:34:42 -04:00
|
|
|
int i = wcslen(usr_path);
|
|
|
|
|
|
2018-04-01 22:00:58 -04:00
|
|
|
/*
|
|
|
|
|
* Fix all the slashes.
|
|
|
|
|
*
|
|
|
|
|
* Since Windows will handle both \ and / paths, we
|
|
|
|
|
* now convert ALL paths to the latter format, so it
|
|
|
|
|
* is always the same.
|
|
|
|
|
*/
|
2018-05-11 21:31:30 -04:00
|
|
|
if (str == NULL)
|
|
|
|
|
str = ptr;
|
|
|
|
|
while ((sz > 0) && (*str != L'\0')) {
|
|
|
|
|
if (*str == L'\\')
|
|
|
|
|
*ptr = L'/';
|
2018-04-01 22:00:58 -04:00
|
|
|
else
|
2018-05-11 21:31:30 -04:00
|
|
|
*ptr = *str;
|
|
|
|
|
str++;
|
|
|
|
|
ptr++;
|
2018-04-01 22:00:58 -04:00
|
|
|
sz--;
|
|
|
|
|
}
|
2018-05-11 21:31:30 -04:00
|
|
|
*ptr = L'\0';
|
|
|
|
|
|
|
|
|
|
if ((src != NULL) && !wcsncasecmp(dst, usr_path, i))
|
|
|
|
|
wcscpy(dst, &dst[i]);
|
2018-04-01 22:00:58 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-02-20 21:44:51 -05:00
|
|
|
/*
|
2018-05-06 16:18:38 -04:00
|
|
|
* Perform initial setup of the PC.
|
2018-02-20 21:44:51 -05:00
|
|
|
*
|
2018-10-06 18:20:09 -04:00
|
|
|
* This is the platform-indepenent part of the startup, where we
|
|
|
|
|
* check commandline arguments and load a configuration file.
|
2018-02-20 21:44:51 -05:00
|
|
|
*/
|
|
|
|
|
int
|
2018-05-06 16:18:38 -04:00
|
|
|
pc_setup(int argc, wchar_t *argv[])
|
2018-02-20 21:44:51 -05:00
|
|
|
{
|
2018-10-06 18:20:09 -04:00
|
|
|
wchar_t temp[1024];
|
|
|
|
|
char tempA[128];
|
2018-02-20 21:44:51 -05:00
|
|
|
wchar_t *cfg = NULL, *p;
|
|
|
|
|
struct tm *info;
|
|
|
|
|
time_t now;
|
2018-06-04 16:45:39 -04:00
|
|
|
int c, ret = 0;
|
2018-02-20 21:44:51 -05:00
|
|
|
|
2018-10-06 18:20:09 -04:00
|
|
|
/* Are we doing first initialization? */
|
|
|
|
|
if (argc == 0) {
|
|
|
|
|
/* Grab the executable's full path. */
|
|
|
|
|
plat_get_exe_name(emu_path, sizeof_w(emu_path));
|
|
|
|
|
if ((p = plat_get_basename(emu_path)) != NULL)
|
2018-03-03 00:47:51 -05:00
|
|
|
*p = L'\0';
|
2018-10-06 18:20:09 -04:00
|
|
|
wcscpy(exe_path, emu_path);
|
|
|
|
|
plat_append_slash(exe_path);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* See if we are perhaps in a "bin/" subfolder of the
|
|
|
|
|
* installation path, in which case the real root of
|
|
|
|
|
* the installation is one level up. We can test this
|
|
|
|
|
* by looking for the 'roms' folder.
|
|
|
|
|
*/
|
|
|
|
|
wcscpy(temp, emu_path);
|
|
|
|
|
plat_append_slash(temp);
|
|
|
|
|
wcscat(temp, ROMS_PATH);
|
|
|
|
|
if (! plat_dir_check(temp)) {
|
|
|
|
|
/* No 'roms' folder found, so go up one level. */
|
|
|
|
|
wcscpy(temp, emu_path);
|
|
|
|
|
if ((p = plat_get_basename(temp)) != NULL)
|
2018-03-03 00:47:51 -05:00
|
|
|
*p = L'\0';
|
2018-10-06 18:20:09 -04:00
|
|
|
plat_append_slash(temp);
|
|
|
|
|
wcscat(temp, ROMS_PATH);
|
|
|
|
|
if (plat_dir_check(temp)) {
|
|
|
|
|
if (p != NULL)
|
|
|
|
|
*p = L'\0';
|
|
|
|
|
wcscpy(emu_path, temp);
|
|
|
|
|
}
|
2018-03-03 00:47:51 -05:00
|
|
|
}
|
2018-10-06 18:20:09 -04:00
|
|
|
plat_append_slash(emu_path);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Get the current working directory.
|
|
|
|
|
*
|
|
|
|
|
* This is normally the directory from where the
|
|
|
|
|
* program was run. If we have been started via
|
|
|
|
|
* a shortcut (desktop icon), however, the CWD
|
|
|
|
|
* could have been set to something else.
|
|
|
|
|
*/
|
|
|
|
|
plat_getcwd(usr_path, sizeof_w(usr_path));
|
|
|
|
|
|
2018-10-08 02:27:07 -04:00
|
|
|
/*
|
|
|
|
|
* Initialize the 'stdlog' variable, this is
|
|
|
|
|
* somewhat platform-specific. On Windows, it
|
|
|
|
|
* will always be 'stdout', but on UNIX-based
|
|
|
|
|
* systems, it can be 'stderr' for the console
|
|
|
|
|
* mode (since 'stdout' is used by the UI),
|
|
|
|
|
* and 'stdout' for the GUI versins, etc...
|
|
|
|
|
*/
|
|
|
|
|
stdlog = (FILE *)argv;
|
|
|
|
|
|
2018-10-06 18:20:09 -04:00
|
|
|
return(0);
|
2018-03-03 00:47:51 -05:00
|
|
|
}
|
2018-02-20 21:44:51 -05:00
|
|
|
|
2018-10-06 18:20:09 -04:00
|
|
|
memset(temp, 0x00, sizeof(temp));
|
2018-02-20 21:44:51 -05:00
|
|
|
|
2018-06-04 16:45:39 -04:00
|
|
|
for (c = 1; c < argc; c++) {
|
2018-02-20 21:44:51 -05:00
|
|
|
if (argv[c][0] != L'-') break;
|
|
|
|
|
|
|
|
|
|
if (!wcscasecmp(argv[c], L"--help") || !wcscasecmp(argv[c], L"-?")) {
|
|
|
|
|
usage:
|
2018-04-01 22:00:58 -04:00
|
|
|
#ifdef _WIN32
|
|
|
|
|
plat_console(1);
|
|
|
|
|
#endif
|
2018-03-22 00:01:41 -05:00
|
|
|
printf("\n%s %s\n", emu_title, emu_fullversion);
|
2018-10-08 02:27:07 -04:00
|
|
|
p = plat_get_basename(argv[0]);
|
|
|
|
|
if (*p == L'/' || *p == L'\\') p++;
|
|
|
|
|
printf("\nUsage: %ls [options] [cfg-file]\n\n", p);
|
2018-02-20 21:44:51 -05:00
|
|
|
printf("Valid options are:\n\n");
|
2018-03-08 01:21:26 -05:00
|
|
|
printf(" -? or --help - show this information\n");
|
|
|
|
|
printf(" -C or --dumpcfg - dump config file after loading\n");
|
2018-10-06 18:20:09 -04:00
|
|
|
printf(" -D or --debug - force debug logging\n");
|
2018-03-08 01:21:26 -05:00
|
|
|
printf(" -F or --fullscreen - start in fullscreen mode\n");
|
|
|
|
|
printf(" -L or --logfile path - set 'path' to be the logfile\n");
|
|
|
|
|
printf(" -P or --vmpath path - set 'path' to be root for vm\n");
|
2018-10-06 18:20:09 -04:00
|
|
|
printf(" -q or --quiet - set logging level to QUIET\n");
|
2018-02-20 21:44:51 -05:00
|
|
|
#ifdef USE_WX
|
2018-03-08 01:21:26 -05:00
|
|
|
printf(" -R or --fps num - set render speed to 'num' fps\n");
|
2018-02-20 21:44:51 -05:00
|
|
|
#endif
|
2018-03-08 01:21:26 -05:00
|
|
|
printf(" -S or --settings - show only the settings dialog\n");
|
2018-03-22 00:01:41 -05:00
|
|
|
printf(" -W or --readonly - do not modify the config file\n");
|
2018-02-20 21:44:51 -05:00
|
|
|
printf("\nA config file can be specified. If none is, the default file will be used.\n");
|
2018-06-04 16:45:39 -04:00
|
|
|
return(ret);
|
2018-02-20 21:44:51 -05:00
|
|
|
} else if (!wcscasecmp(argv[c], L"--dumpcfg") ||
|
|
|
|
|
!wcscasecmp(argv[c], L"-C")) {
|
|
|
|
|
do_dump_config = 1;
|
|
|
|
|
} else if (!wcscasecmp(argv[c], L"--debug") ||
|
|
|
|
|
!wcscasecmp(argv[c], L"-D")) {
|
2018-10-06 18:20:09 -04:00
|
|
|
#ifdef _WIN32
|
2018-02-20 21:44:51 -05:00
|
|
|
force_debug = 1;
|
|
|
|
|
#endif
|
2018-10-06 18:20:09 -04:00
|
|
|
log_level++;
|
2018-02-20 21:44:51 -05:00
|
|
|
} else if (!wcscasecmp(argv[c], L"--fullscreen") ||
|
|
|
|
|
!wcscasecmp(argv[c], L"-F")) {
|
|
|
|
|
start_in_fullscreen = 1;
|
|
|
|
|
} else if (!wcscasecmp(argv[c], L"--logfile") ||
|
|
|
|
|
!wcscasecmp(argv[c], L"-L")) {
|
2018-06-04 16:45:39 -04:00
|
|
|
if ((c+1) == argc) {
|
|
|
|
|
ret = -1;
|
|
|
|
|
goto usage;
|
|
|
|
|
}
|
2018-02-20 21:44:51 -05:00
|
|
|
wcscpy(log_path, argv[++c]);
|
|
|
|
|
} else if (!wcscasecmp(argv[c], L"--vmpath") ||
|
|
|
|
|
!wcscasecmp(argv[c], L"-P")) {
|
2018-06-04 16:45:39 -04:00
|
|
|
if ((c+1) == argc) {
|
|
|
|
|
ret = -1;
|
|
|
|
|
goto usage;
|
|
|
|
|
}
|
2018-10-06 18:20:09 -04:00
|
|
|
wcsncpy(temp, argv[++c], sizeof_w(temp));
|
|
|
|
|
} else if (!wcscasecmp(argv[c], L"--quiet") ||
|
|
|
|
|
!wcscasecmp(argv[c], L"-q")) {
|
|
|
|
|
log_level = LOG_DEBUG;
|
2018-02-20 21:44:51 -05:00
|
|
|
#ifdef USE_WX
|
|
|
|
|
} else if (!wcscasecmp(argv[c], L"--fps") ||
|
|
|
|
|
!wcscasecmp(argv[c], L"-R")) {
|
2018-06-04 16:45:39 -04:00
|
|
|
if ((c+1) == argc) {
|
|
|
|
|
ret = -1;
|
|
|
|
|
goto usage;
|
|
|
|
|
}
|
2018-02-20 21:44:51 -05:00
|
|
|
video_fps = wcstol(argv[++c], NULL, 10);
|
|
|
|
|
#endif
|
|
|
|
|
} else if (!wcscasecmp(argv[c], L"--settings") ||
|
|
|
|
|
!wcscasecmp(argv[c], L"-S")) {
|
|
|
|
|
settings_only = 1;
|
2018-03-22 00:01:41 -05:00
|
|
|
} else if (!wcscasecmp(argv[c], L"--readonly") ||
|
|
|
|
|
!wcscasecmp(argv[c], L"-W")) {
|
|
|
|
|
config_ro = 1;
|
2018-02-20 21:44:51 -05:00
|
|
|
} else if (!wcscasecmp(argv[c], L"--test")) {
|
|
|
|
|
/* some (undocumented) test function here.. */
|
|
|
|
|
|
|
|
|
|
/* .. and then exit. */
|
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Uhm... out of options here.. */
|
|
|
|
|
else goto usage;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* One argument (config file) allowed. */
|
|
|
|
|
if (c < argc)
|
|
|
|
|
cfg = argv[c++];
|
2018-06-04 16:45:39 -04:00
|
|
|
if (c != argc) {
|
|
|
|
|
ret = -2;
|
|
|
|
|
goto usage;
|
|
|
|
|
}
|
2018-02-20 21:44:51 -05:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If the user provided a path for files, use that
|
|
|
|
|
* instead of the current working directory. We do
|
|
|
|
|
* make sure that if that was a relative path, we
|
|
|
|
|
* make it absolute.
|
|
|
|
|
*/
|
2018-10-06 18:20:09 -04:00
|
|
|
if (temp[0] != L'\0') {
|
|
|
|
|
if (! plat_path_abs(temp)) {
|
2018-02-20 21:44:51 -05:00
|
|
|
/*
|
|
|
|
|
* This looks like a relative path.
|
|
|
|
|
*
|
|
|
|
|
* Add it to the current working directory
|
|
|
|
|
* to convert it (back) to an absolute path.
|
|
|
|
|
*/
|
2018-03-08 01:21:26 -05:00
|
|
|
plat_append_slash(usr_path);
|
2018-10-06 18:20:09 -04:00
|
|
|
wcscat(usr_path, temp);
|
2018-02-20 21:44:51 -05:00
|
|
|
} else {
|
|
|
|
|
/*
|
|
|
|
|
* The user-provided path seems like an
|
|
|
|
|
* absolute path, so just use that.
|
|
|
|
|
*/
|
2018-10-06 18:20:09 -04:00
|
|
|
wcscpy(usr_path, temp);
|
2018-02-20 21:44:51 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Make sure we have a trailing backslash. */
|
2018-03-08 01:21:26 -05:00
|
|
|
plat_append_slash(usr_path);
|
2018-02-20 21:44:51 -05:00
|
|
|
|
|
|
|
|
/* Grab the name of the configuration file. */
|
|
|
|
|
if (cfg == NULL)
|
|
|
|
|
cfg = CONFIG_FILE;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If the configuration file name has (part of)
|
|
|
|
|
* a pathname, consider that to be part of the
|
|
|
|
|
* actual working directory.
|
|
|
|
|
*
|
|
|
|
|
* This can happen when people load a config
|
|
|
|
|
* file using the UI, for example.
|
|
|
|
|
*/
|
|
|
|
|
p = plat_get_filename(cfg);
|
|
|
|
|
if (cfg != p) {
|
|
|
|
|
/*
|
|
|
|
|
* OK, the configuration file name has a
|
|
|
|
|
* path component. Separate the two, and
|
|
|
|
|
* add the path component to the cfg path.
|
|
|
|
|
*/
|
|
|
|
|
*(p-1) = L'\0';
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If this is an absolute path, keep it, as
|
|
|
|
|
* there is probably have a reason to do so.
|
|
|
|
|
* Otherwise, assume the pathname given is
|
|
|
|
|
* relative to whatever the usr_path is.
|
|
|
|
|
*/
|
|
|
|
|
if (plat_path_abs(cfg))
|
|
|
|
|
wcscpy(usr_path, cfg);
|
|
|
|
|
else
|
|
|
|
|
wcscat(usr_path, cfg);
|
|
|
|
|
|
|
|
|
|
/* Make sure we have a trailing backslash. */
|
2018-03-08 01:21:26 -05:00
|
|
|
plat_append_slash(usr_path);
|
2018-02-20 21:44:51 -05:00
|
|
|
}
|
|
|
|
|
|
2018-04-03 03:34:42 -04:00
|
|
|
/* Don't forget to clean up the user path. */
|
|
|
|
|
pc_path(usr_path, sizeof_w(usr_path), NULL);
|
|
|
|
|
|
2018-02-20 21:44:51 -05:00
|
|
|
/* At this point, we can safely create the full path name. */
|
|
|
|
|
plat_append_filename(cfg_path, usr_path, p);
|
|
|
|
|
|
2018-04-01 22:00:58 -04:00
|
|
|
/* If no extension was given, tack on the default one. */
|
|
|
|
|
if ((cfg = wcschr(p, L'.')) == NULL)
|
|
|
|
|
wcscat(cfg_path, CONFIG_FILE_EXT);
|
|
|
|
|
|
2018-02-20 21:44:51 -05:00
|
|
|
/*
|
|
|
|
|
* This is where we start outputting to the log file,
|
|
|
|
|
* if there is one. Create a little info header first.
|
2018-04-01 22:00:58 -04:00
|
|
|
*
|
|
|
|
|
* For the Windows version, if we do not have a console
|
|
|
|
|
* meaning, not logging to file..), request one if we
|
|
|
|
|
* have force_debug set.
|
2018-02-20 21:44:51 -05:00
|
|
|
*/
|
2018-04-01 22:00:58 -04:00
|
|
|
#ifdef _WIN32
|
|
|
|
|
if (force_debug)
|
|
|
|
|
plat_console(1);
|
|
|
|
|
#endif
|
2018-02-20 21:44:51 -05:00
|
|
|
(void)time(&now);
|
|
|
|
|
info = localtime(&now);
|
2018-10-06 18:20:09 -04:00
|
|
|
strftime(tempA, sizeof(temp), "%Y/%m/%d %H:%M:%S", info);
|
|
|
|
|
INFO("#\n# %s %s\n#\n# Logfile created %s\n#\n",
|
|
|
|
|
emu_title, emu_fullversion, tempA);
|
|
|
|
|
INFO("# Emulator path: %ls\n", emu_path);
|
|
|
|
|
INFO("# Userfiles path: %ls\n", usr_path);
|
|
|
|
|
INFO("# Configuration file: %ls\n#\n\n", cfg_path);
|
2018-02-20 21:44:51 -05:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* We are about to read the configuration file, which MAY
|
|
|
|
|
* put data into global variables (the hard- and floppy
|
|
|
|
|
* disks are an example) so we have to initialize those
|
|
|
|
|
* modules before we load the config..
|
|
|
|
|
*/
|
|
|
|
|
mouse_init();
|
2018-04-01 22:00:58 -04:00
|
|
|
hdd_init();
|
2018-02-20 21:44:51 -05:00
|
|
|
cdrom_global_init();
|
|
|
|
|
zip_global_init();
|
2018-10-06 18:20:09 -04:00
|
|
|
scsi_disk_global_init();
|
|
|
|
|
|
2018-04-01 22:00:58 -04:00
|
|
|
network_init();
|
2018-02-20 21:44:51 -05:00
|
|
|
|
|
|
|
|
/* Load the configuration file. */
|
2018-06-04 16:45:39 -04:00
|
|
|
if (! config_load()) return(2);
|
2018-02-20 21:44:51 -05:00
|
|
|
|
2018-06-04 16:45:39 -04:00
|
|
|
/* All good. */
|
2018-02-20 21:44:51 -05:00
|
|
|
return(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-10-06 18:20:09 -04:00
|
|
|
void
|
|
|
|
|
pc_set_speed(void)
|
|
|
|
|
{
|
|
|
|
|
if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type >= CPU_286)
|
|
|
|
|
setpitclock((float)machine_speed());
|
|
|
|
|
else
|
|
|
|
|
setpitclock(14318184.0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-02-20 21:44:51 -05:00
|
|
|
void
|
|
|
|
|
pc_full_speed(void)
|
|
|
|
|
{
|
|
|
|
|
cpuspeed2 = cpuspeed;
|
|
|
|
|
|
|
|
|
|
if (! atfullspeed) {
|
2018-10-06 18:20:09 -04:00
|
|
|
DEBUG("Set fullspeed - %i\n", cpuspeed2);
|
|
|
|
|
pc_set_speed();
|
|
|
|
|
atfullspeed = 1;
|
2018-02-20 21:44:51 -05:00
|
|
|
}
|
2018-10-06 18:20:09 -04:00
|
|
|
|
|
|
|
|
nvr_period_recalc();
|
2018-02-20 21:44:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
pc_speed_changed(void)
|
|
|
|
|
{
|
2018-10-06 18:20:09 -04:00
|
|
|
pc_set_speed();
|
|
|
|
|
|
|
|
|
|
nvr_period_recalc();
|
2018-02-20 21:44:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Re-load system configuration and restart. */
|
|
|
|
|
/* FIXME: this has to be reviewed! */
|
|
|
|
|
void
|
2018-04-11 17:40:51 -04:00
|
|
|
pc_reload(const wchar_t *fn)
|
2018-02-20 21:44:51 -05:00
|
|
|
{
|
|
|
|
|
config_write(cfg_path);
|
|
|
|
|
|
2018-03-20 17:13:12 -05:00
|
|
|
floppy_close();
|
|
|
|
|
|
2018-10-06 18:20:09 -04:00
|
|
|
cdrom_close();
|
2018-02-20 21:44:51 -05:00
|
|
|
|
|
|
|
|
pc_reset_hard_close();
|
|
|
|
|
|
|
|
|
|
// FIXME: set up new config file path 'fn'... --FvK
|
|
|
|
|
|
|
|
|
|
config_load();
|
|
|
|
|
|
2018-10-06 18:20:09 -04:00
|
|
|
cdrom_hard_reset();
|
2018-02-20 21:44:51 -05:00
|
|
|
|
2018-10-06 18:20:09 -04:00
|
|
|
zip_hard_reset();
|
2018-02-20 21:44:51 -05:00
|
|
|
|
2018-10-06 18:20:09 -04:00
|
|
|
scsi_disk_hard_reset();
|
2018-02-20 21:44:51 -05:00
|
|
|
|
|
|
|
|
fdd_load(0, floppyfns[0]);
|
|
|
|
|
fdd_load(1, floppyfns[1]);
|
|
|
|
|
fdd_load(2, floppyfns[2]);
|
|
|
|
|
fdd_load(3, floppyfns[3]);
|
|
|
|
|
|
|
|
|
|
network_init();
|
|
|
|
|
|
|
|
|
|
pc_reset_hard_init();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-05-06 16:18:38 -04:00
|
|
|
/* Initialize the configured PC. Run once, after pc_setup() is done. */
|
2018-02-20 21:44:51 -05:00
|
|
|
int
|
2018-05-06 16:18:38 -04:00
|
|
|
pc_init(void)
|
2018-02-20 21:44:51 -05:00
|
|
|
{
|
2018-10-06 18:20:09 -04:00
|
|
|
wchar_t temp[128];
|
|
|
|
|
char tempA[128];
|
2018-05-10 03:58:47 -04:00
|
|
|
const wchar_t *str;
|
2018-09-23 16:35:28 -04:00
|
|
|
const char *stransi;
|
2018-02-20 21:44:51 -05:00
|
|
|
|
2018-06-04 16:45:39 -04:00
|
|
|
/* If no machine selected, force user into Setup Wizard. */
|
|
|
|
|
if (machine < 0) {
|
|
|
|
|
str = get_string(IDS_ERR_NOCONF);
|
|
|
|
|
|
|
|
|
|
/* Show the messagebox, and abort if 'No' was selected. */
|
|
|
|
|
if (ui_msgbox(MBX_QUESTION, str) != 0) return(0);
|
|
|
|
|
|
|
|
|
|
/* OK, user wants to set up a machine. */
|
|
|
|
|
machine = 0;
|
|
|
|
|
|
|
|
|
|
return(2);
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-20 21:44:51 -05:00
|
|
|
/* Load the ROMs for the selected machine. */
|
2018-06-04 16:45:39 -04:00
|
|
|
if (! machine_available(machine)) {
|
2018-03-02 18:58:18 -05:00
|
|
|
/* Whoops, selected machine not available. */
|
2018-10-06 18:20:09 -04:00
|
|
|
stransi = machine_getname();
|
|
|
|
|
if (stransi == NULL) {
|
|
|
|
|
/* This happens if configured machine is not even in table.. */
|
|
|
|
|
sprintf(tempA, "machine_%i", machine);
|
|
|
|
|
stransi = (const char *)tempA;
|
|
|
|
|
}
|
2018-02-20 21:44:51 -05:00
|
|
|
|
2018-03-02 18:58:18 -05:00
|
|
|
/* Show the messagebox, and abort if 'No' was selected. */
|
2018-10-06 18:20:09 -04:00
|
|
|
swprintf(temp, sizeof_w(temp),
|
|
|
|
|
get_string(IDS_ERR_NOAVAIL), get_string(IDS_3310), stransi);
|
2018-03-02 18:58:18 -05:00
|
|
|
if (ui_msgbox(MBX_CONFIG, temp) == 1) return(0);
|
|
|
|
|
|
|
|
|
|
/* OK, user wants to (re-)configure.. */
|
|
|
|
|
return(2);
|
2018-02-20 21:44:51 -05:00
|
|
|
}
|
|
|
|
|
|
2018-10-06 18:20:09 -04:00
|
|
|
if ((video_card < 0) || !video_card_available(video_card)) {
|
2018-03-02 18:58:18 -05:00
|
|
|
/* Whoops, selected video not available. */
|
2018-09-23 16:35:28 -04:00
|
|
|
stransi = video_card_getname(video_card);
|
|
|
|
|
if (stransi == NULL) {
|
|
|
|
|
/* This happens if configured card is not even in table.. */
|
2018-10-06 18:20:09 -04:00
|
|
|
sprintf(tempA, "vid_%i", video_card);
|
|
|
|
|
stransi = (const char *)tempA;
|
|
|
|
|
}
|
2018-03-02 18:58:18 -05:00
|
|
|
|
|
|
|
|
/* Show the messagebox, and abort if 'No' was selected. */
|
2018-10-06 18:20:09 -04:00
|
|
|
swprintf(temp, sizeof_w(temp),
|
|
|
|
|
get_string(IDS_ERR_NOAVAIL), get_string(IDS_3311), stransi);
|
2018-03-02 18:58:18 -05:00
|
|
|
if (ui_msgbox(MBX_CONFIG, temp) == 1) return(0);
|
|
|
|
|
|
|
|
|
|
/* OK, user wants to (re-)configure.. */
|
|
|
|
|
return(2);
|
2018-02-20 21:44:51 -05:00
|
|
|
}
|
|
|
|
|
|
2018-03-02 18:58:18 -05:00
|
|
|
/*
|
|
|
|
|
* At this point, we know that the selected machine and
|
|
|
|
|
* video card are available, so we can proceed with the
|
|
|
|
|
* initialization of things.
|
|
|
|
|
*/
|
2018-10-06 18:20:09 -04:00
|
|
|
cpuspeed2 = (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type >= CPU_286) ? 2 : 1;
|
2018-02-20 21:44:51 -05:00
|
|
|
atfullspeed = 0;
|
|
|
|
|
|
|
|
|
|
random_init();
|
|
|
|
|
|
|
|
|
|
mem_init();
|
|
|
|
|
|
|
|
|
|
#ifdef USE_DYNAREC
|
|
|
|
|
codegen_init();
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef WALTJE_SERIAL
|
|
|
|
|
serial_init();
|
|
|
|
|
#endif
|
|
|
|
|
keyboard_init();
|
|
|
|
|
joystick_init();
|
|
|
|
|
video_init();
|
|
|
|
|
|
2018-03-18 21:09:07 -05:00
|
|
|
device_init();
|
|
|
|
|
|
2018-02-20 21:44:51 -05:00
|
|
|
timer_reset();
|
|
|
|
|
|
2018-04-08 17:25:35 -04:00
|
|
|
sound_init();
|
2018-02-20 21:44:51 -05:00
|
|
|
|
2018-10-06 18:20:09 -04:00
|
|
|
#if 0
|
|
|
|
|
fdd_init();
|
|
|
|
|
#else
|
|
|
|
|
floppy_init(); //FIXME: fdd_init() now?
|
|
|
|
|
#endif
|
2018-02-20 21:44:51 -05:00
|
|
|
|
2018-04-07 00:23:55 -04:00
|
|
|
/* FIXME: should be disk_init() */
|
2018-02-20 21:44:51 -05:00
|
|
|
cdrom_hard_reset();
|
|
|
|
|
zip_hard_reset();
|
|
|
|
|
|
2018-04-07 00:23:55 -04:00
|
|
|
/* FIXME: should be scsi_init() */
|
2018-10-06 18:20:09 -04:00
|
|
|
scsi_disk_hard_reset();
|
2018-02-20 21:44:51 -05:00
|
|
|
scsi_card_init();
|
|
|
|
|
|
|
|
|
|
pc_full_speed();
|
|
|
|
|
shadowbios = 0;
|
|
|
|
|
|
|
|
|
|
return(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-05-06 16:18:38 -04:00
|
|
|
/* Close down a running machine. */
|
|
|
|
|
void
|
|
|
|
|
pc_close(thread_t *ptr)
|
|
|
|
|
{
|
|
|
|
|
/* Wait a while so things can shut down. */
|
|
|
|
|
plat_delay_ms(200);
|
|
|
|
|
|
|
|
|
|
/* Claim the video blitter. */
|
2018-05-09 18:06:59 -04:00
|
|
|
plat_startblit();
|
2018-05-06 16:18:38 -04:00
|
|
|
|
|
|
|
|
/* Terminate the main thread. */
|
|
|
|
|
if (ptr != NULL) {
|
|
|
|
|
thread_kill(ptr);
|
|
|
|
|
|
|
|
|
|
/* Wait some more. */
|
|
|
|
|
plat_delay_ms(200);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nvr_save();
|
|
|
|
|
|
|
|
|
|
machine_close();
|
|
|
|
|
|
|
|
|
|
config_save();
|
|
|
|
|
|
2018-10-06 18:20:09 -04:00
|
|
|
ui_mouse_capture(0);
|
2018-05-06 16:18:38 -04:00
|
|
|
|
2018-10-06 18:20:09 -04:00
|
|
|
zip_close();
|
2018-05-06 16:18:38 -04:00
|
|
|
|
2018-10-06 18:20:09 -04:00
|
|
|
scsi_disk_close();
|
2018-05-06 16:18:38 -04:00
|
|
|
|
2018-10-06 18:20:09 -04:00
|
|
|
// floppy_close();
|
2018-05-06 16:18:38 -04:00
|
|
|
|
|
|
|
|
if (dump_on_exit)
|
|
|
|
|
dumppic();
|
|
|
|
|
dumpregs(0);
|
|
|
|
|
|
|
|
|
|
video_close();
|
|
|
|
|
|
|
|
|
|
device_close_all();
|
|
|
|
|
|
|
|
|
|
network_close();
|
|
|
|
|
|
|
|
|
|
sound_close();
|
|
|
|
|
|
2018-10-06 18:20:09 -04:00
|
|
|
cdrom_close();
|
2018-05-06 16:18:38 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-02-20 21:44:51 -05:00
|
|
|
void
|
|
|
|
|
pc_reset_hard_close(void)
|
|
|
|
|
{
|
|
|
|
|
suppress_overscan = 0;
|
|
|
|
|
|
|
|
|
|
nvr_save();
|
|
|
|
|
|
|
|
|
|
machine_close();
|
|
|
|
|
|
|
|
|
|
mouse_close();
|
|
|
|
|
|
2018-10-06 18:20:09 -04:00
|
|
|
cdrom_close();
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
sound_close();
|
|
|
|
|
#endif
|
|
|
|
|
|
2018-02-20 21:44:51 -05:00
|
|
|
device_close_all();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This is basically the spot where we start up the actual machine,
|
|
|
|
|
* by issuing a 'hard reset' to the entire configuration. Order is
|
|
|
|
|
* somewhat important here. Functions here should be named _reset
|
|
|
|
|
* really, as that is what they do.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
pc_reset_hard_init(void)
|
|
|
|
|
{
|
|
|
|
|
/* Reset the general machine support modules. */
|
|
|
|
|
io_init();
|
|
|
|
|
timer_reset();
|
|
|
|
|
device_init();
|
|
|
|
|
|
2018-04-20 04:16:43 -04:00
|
|
|
/* Reset the ports [before machine!] so they can be configured. */
|
2018-04-08 17:25:35 -04:00
|
|
|
parallel_reset();
|
2018-04-20 04:16:43 -04:00
|
|
|
serial_reset();
|
2018-04-08 17:25:35 -04:00
|
|
|
|
2018-10-06 18:20:09 -04:00
|
|
|
/* FIXME: these, should be in disk_reset(). */
|
|
|
|
|
cdrom_hard_reset();
|
|
|
|
|
zip_hard_reset();
|
2018-08-29 03:58:50 -04:00
|
|
|
|
2018-10-06 18:20:09 -04:00
|
|
|
/*
|
|
|
|
|
* Reset the actual machine and its basic modules.
|
|
|
|
|
*
|
|
|
|
|
* Note that on PCI-based machines, this will also reset
|
|
|
|
|
* the PCI bus state, so, we MUST reset PCI devices after
|
|
|
|
|
* the machine!
|
|
|
|
|
*/
|
|
|
|
|
machine_reset();
|
2018-02-20 21:44:51 -05:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Once the machine has been initialized, all that remains
|
|
|
|
|
* should be resetting all devices set up for it, to their
|
|
|
|
|
* current configurations !
|
|
|
|
|
*
|
|
|
|
|
* For now, we will call their reset functions here, but
|
|
|
|
|
* that will be a call to device_reset_all() later !
|
|
|
|
|
*/
|
2018-10-06 18:20:09 -04:00
|
|
|
#if 0
|
|
|
|
|
/* FIXME: move elsewhere? */
|
|
|
|
|
shadowbios = 0;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* Reset any ISA memory cards. */
|
|
|
|
|
isamem_reset();
|
|
|
|
|
|
|
|
|
|
/* Reset any ISA RTC cards. */
|
|
|
|
|
isartc_reset();
|
2018-02-20 21:44:51 -05:00
|
|
|
|
|
|
|
|
/* Reset some basic devices. */
|
|
|
|
|
mouse_reset();
|
2018-10-06 18:20:09 -04:00
|
|
|
keyboard_reset();
|
2018-02-20 21:44:51 -05:00
|
|
|
|
2018-10-06 18:20:09 -04:00
|
|
|
/* Reset sound system. This MAY add a game port, so before joystick! */
|
|
|
|
|
sound_reset();
|
2018-03-20 17:13:12 -05:00
|
|
|
|
2018-10-06 18:20:09 -04:00
|
|
|
/* Reset the Floppy and Hard Disk modules. */
|
|
|
|
|
fdd_reset();
|
2018-02-20 21:44:51 -05:00
|
|
|
hdc_reset();
|
|
|
|
|
|
|
|
|
|
/* Reset and reconfigure the SCSI layer. */
|
|
|
|
|
scsi_card_init();
|
|
|
|
|
|
|
|
|
|
/* Reset and reconfigure the Network Card layer. */
|
|
|
|
|
network_reset();
|
|
|
|
|
|
2018-04-26 16:46:42 -04:00
|
|
|
//FIXME: this needs to be re-done. */
|
|
|
|
|
if (joystick_type != JOYSTICK_NONE)
|
|
|
|
|
game_update_joystick_type();
|
2018-02-20 21:44:51 -05:00
|
|
|
|
|
|
|
|
if (config_changed) {
|
2018-10-06 18:20:09 -04:00
|
|
|
ui_sb_reset();
|
2018-02-20 21:44:51 -05:00
|
|
|
|
|
|
|
|
config_save();
|
|
|
|
|
|
|
|
|
|
config_changed = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Needs the status bar... */
|
|
|
|
|
if (bugger_enabled)
|
|
|
|
|
device_add(&bugger_device);
|
|
|
|
|
|
2018-06-04 16:45:39 -04:00
|
|
|
/* Needs the status bar initialized. */
|
2018-10-06 18:20:09 -04:00
|
|
|
ui_mouse_capture(-1);
|
2018-06-04 16:45:39 -04:00
|
|
|
|
2018-02-20 21:44:51 -05:00
|
|
|
/* Reset the CPU module. */
|
|
|
|
|
resetx86();
|
|
|
|
|
dma_reset();
|
|
|
|
|
pic_reset();
|
2018-10-06 18:20:09 -04:00
|
|
|
pc_set_speed();
|
2018-02-20 21:44:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
pc_reset_hard(void)
|
|
|
|
|
{
|
|
|
|
|
pc_reset_hard_close();
|
|
|
|
|
|
|
|
|
|
pc_reset_hard_init();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
pc_reset(int hard)
|
|
|
|
|
{
|
2018-10-06 18:20:09 -04:00
|
|
|
pc_pause(1);
|
2018-02-20 21:44:51 -05:00
|
|
|
|
|
|
|
|
plat_delay_ms(100);
|
|
|
|
|
|
|
|
|
|
nvr_save();
|
|
|
|
|
|
2018-03-20 17:13:12 -05:00
|
|
|
machine_close();
|
|
|
|
|
|
2018-02-20 21:44:51 -05:00
|
|
|
config_save();
|
|
|
|
|
|
|
|
|
|
if (hard)
|
|
|
|
|
pc_reset_hard();
|
|
|
|
|
else
|
2018-10-06 18:20:09 -04:00
|
|
|
keyboard_cad();
|
2018-02-20 21:44:51 -05:00
|
|
|
|
2018-10-06 18:20:09 -04:00
|
|
|
pc_pause(0);
|
2018-02-20 21:44:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The main thread runs the actual emulator code.
|
|
|
|
|
*
|
|
|
|
|
* We basically run until the upper layers terminate us, by
|
|
|
|
|
* setting the variable 'quited' there to 1. We get a pointer
|
|
|
|
|
* to that variable as our function argument.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
pc_thread(void *param)
|
|
|
|
|
{
|
2018-03-08 01:21:26 -05:00
|
|
|
wchar_t temp[200];
|
2018-02-20 21:44:51 -05:00
|
|
|
uint64_t start_time, end_time;
|
2018-10-06 18:20:09 -04:00
|
|
|
int64_t main_time;
|
2018-02-20 21:44:51 -05:00
|
|
|
uint32_t old_time, new_time;
|
2018-10-06 18:20:09 -04:00
|
|
|
uint32_t clockrate;
|
2018-05-05 15:46:31 -04:00
|
|
|
int done, drawits, frm;
|
2018-02-20 21:44:51 -05:00
|
|
|
int *quitp = (int *)param;
|
|
|
|
|
|
2018-10-06 18:20:09 -04:00
|
|
|
INFO("PC: starting main thread...\n");
|
2018-02-20 21:44:51 -05:00
|
|
|
|
|
|
|
|
main_time = 0;
|
2018-10-06 18:20:09 -04:00
|
|
|
title_update = 1;
|
2018-02-20 21:44:51 -05:00
|
|
|
old_time = plat_get_ticks();
|
2018-05-05 15:46:31 -04:00
|
|
|
done = drawits = frm = 0;
|
2018-02-20 21:44:51 -05:00
|
|
|
while (! *quitp) {
|
|
|
|
|
/* See if it is time to run a frame of code. */
|
|
|
|
|
new_time = plat_get_ticks();
|
|
|
|
|
drawits += (new_time - old_time);
|
|
|
|
|
old_time = new_time;
|
|
|
|
|
if (drawits > 0 && !dopause) {
|
|
|
|
|
/* Yes, so do one frame now. */
|
|
|
|
|
start_time = plat_timer_read();
|
|
|
|
|
drawits -= 10;
|
|
|
|
|
if (drawits > 50)
|
|
|
|
|
drawits = 0;
|
|
|
|
|
|
|
|
|
|
/* Run a block of code. */
|
2018-05-09 18:06:59 -04:00
|
|
|
plat_startblit();
|
2018-10-06 18:20:09 -04:00
|
|
|
clockrate = machine_speed();
|
2018-02-20 21:44:51 -05:00
|
|
|
|
|
|
|
|
if (is386) {
|
|
|
|
|
#ifdef USE_DYNAREC
|
|
|
|
|
if (cpu_use_dynarec)
|
|
|
|
|
exec386_dynarec(clockrate/100);
|
|
|
|
|
else
|
|
|
|
|
#endif
|
|
|
|
|
exec386(clockrate/100);
|
2018-10-06 18:20:09 -04:00
|
|
|
} else if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type >= CPU_286) {
|
2018-02-20 21:44:51 -05:00
|
|
|
exec386(clockrate/100);
|
|
|
|
|
} else {
|
|
|
|
|
execx86(clockrate/100);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mouse_process();
|
|
|
|
|
|
|
|
|
|
joystick_process();
|
|
|
|
|
|
2018-05-09 18:06:59 -04:00
|
|
|
plat_endblit();
|
2018-02-20 21:44:51 -05:00
|
|
|
|
|
|
|
|
if (title_update) {
|
|
|
|
|
swprintf(temp, sizeof_w(temp),
|
2018-03-22 00:01:41 -05:00
|
|
|
L"%s %s - %i%% - %s - %s",
|
2018-03-08 01:21:26 -05:00
|
|
|
EMU_NAME,emu_version,fps,machine_getname(),
|
2018-03-22 00:01:41 -05:00
|
|
|
machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].name);
|
2018-02-20 21:44:51 -05:00
|
|
|
ui_window_title(temp);
|
|
|
|
|
|
|
|
|
|
title_update = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* One more frame done! */
|
2018-10-06 18:20:09 -04:00
|
|
|
framecount++;
|
2018-02-20 21:44:51 -05:00
|
|
|
done++;
|
|
|
|
|
|
|
|
|
|
/* Every 200 frames we save the machine status. */
|
2018-05-05 15:46:31 -04:00
|
|
|
if (++frm >= 200 && nvr_dosave) {
|
2018-02-20 21:44:51 -05:00
|
|
|
nvr_save();
|
|
|
|
|
nvr_dosave = 0;
|
2018-05-05 15:46:31 -04:00
|
|
|
frm = 0;
|
2018-02-20 21:44:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
end_time = plat_timer_read();
|
|
|
|
|
main_time += (end_time - start_time);
|
|
|
|
|
} else {
|
|
|
|
|
/* Just so we dont overload the host OS. */
|
|
|
|
|
plat_delay_ms(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If needed, handle a screen resize. */
|
2018-04-20 04:16:43 -04:00
|
|
|
if (doresize && !vid_fullscreen) {
|
2018-05-08 03:09:43 -04:00
|
|
|
ui_resize(scrnsz_x, scrnsz_y);
|
2018-02-20 21:44:51 -05:00
|
|
|
|
|
|
|
|
doresize = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-06 18:20:09 -04:00
|
|
|
INFO("PC: main thread done.\n");
|
2018-02-20 21:44:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Handler for the 1-second timer to refresh the window title. */
|
|
|
|
|
void
|
|
|
|
|
pc_onesec(void)
|
|
|
|
|
{
|
|
|
|
|
fps = framecount;
|
|
|
|
|
framecount = 0;
|
|
|
|
|
|
|
|
|
|
title_update = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-10-06 18:20:09 -04:00
|
|
|
/* Pause or unpause the emulator. */
|
|
|
|
|
void
|
|
|
|
|
pc_pause(int p)
|
|
|
|
|
{
|
|
|
|
|
static wchar_t oldtitle[512];
|
|
|
|
|
wchar_t title[512];
|
|
|
|
|
|
|
|
|
|
/* If un-pausing, ask the renderer if that's OK. */
|
|
|
|
|
if (p == 0)
|
|
|
|
|
p = vidapi_pause();
|
|
|
|
|
|
|
|
|
|
/* If already so, done. */
|
|
|
|
|
if (dopause == p) return;
|
|
|
|
|
|
|
|
|
|
if (p) {
|
|
|
|
|
wcscpy(oldtitle, ui_window_title(NULL));
|
|
|
|
|
wcscpy(title, oldtitle);
|
|
|
|
|
wcscat(title, L" - PAUSED -");
|
|
|
|
|
ui_window_title(title);
|
|
|
|
|
} else {
|
|
|
|
|
ui_window_title(oldtitle);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dopause = p;
|
|
|
|
|
|
|
|
|
|
/* Update the actual menu item. */
|
|
|
|
|
menu_set_item(IDM_PAUSE, dopause);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-02-20 21:44:51 -05:00
|
|
|
void
|
|
|
|
|
set_screen_size(int x, int y)
|
|
|
|
|
{
|
|
|
|
|
int owsx = scrnsz_x;
|
|
|
|
|
int owsy = scrnsz_y;
|
|
|
|
|
int temp_overscan_x = overscan_x;
|
|
|
|
|
int temp_overscan_y = overscan_y;
|
|
|
|
|
double dx, dy, dtx, dty;
|
2018-10-06 18:20:09 -04:00
|
|
|
int vid;
|
|
|
|
|
|
2018-10-08 02:27:07 -04:00
|
|
|
DEBUG("SetScreenSize(%i, %i) resize=%i\n", x, y, vid_resize);
|
2018-02-20 21:44:51 -05:00
|
|
|
|
|
|
|
|
/* Make sure we keep usable values. */
|
|
|
|
|
if (x < 320) x = 320;
|
|
|
|
|
if (y < 200) y = 200;
|
|
|
|
|
if (x > 2048) x = 2048;
|
|
|
|
|
if (y > 2048) y = 2048;
|
|
|
|
|
|
|
|
|
|
/* Save the new values as "real" (unscaled) resolution. */
|
|
|
|
|
unscaled_size_x = x;
|
|
|
|
|
efscrnsz_y = y;
|
|
|
|
|
|
|
|
|
|
if (suppress_overscan)
|
|
|
|
|
temp_overscan_x = temp_overscan_y = 0;
|
|
|
|
|
|
|
|
|
|
if (force_43) {
|
|
|
|
|
dx = (double)x;
|
|
|
|
|
dtx = (double)temp_overscan_x;
|
|
|
|
|
|
|
|
|
|
dy = (double)y;
|
|
|
|
|
dty = (double)temp_overscan_y;
|
|
|
|
|
|
|
|
|
|
/* Account for possible overscan. */
|
2018-10-06 18:20:09 -04:00
|
|
|
vid = video_type();
|
|
|
|
|
if ((vid == VID_TYPE_CGA) && (temp_overscan_y == 16)) {
|
2018-02-20 21:44:51 -05:00
|
|
|
/* CGA */
|
|
|
|
|
dy = (((dx - dtx) / 4.0) * 3.0) + dty;
|
2018-10-06 18:20:09 -04:00
|
|
|
} else if ((vid == VID_MDA) && (temp_overscan_y < 16)) {
|
2018-02-20 21:44:51 -05:00
|
|
|
/* MDA/Hercules */
|
|
|
|
|
dy = (x / 4.0) * 3.0;
|
|
|
|
|
} else {
|
|
|
|
|
if (enable_overscan) {
|
|
|
|
|
/* EGA/(S)VGA with overscan */
|
|
|
|
|
dy = (((dx - dtx) / 4.0) * 3.0) + dty;
|
|
|
|
|
} else {
|
|
|
|
|
/* EGA/(S)VGA without overscan */
|
|
|
|
|
dy = (x / 4.0) * 3.0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
unscaled_size_y = (int)dy;
|
|
|
|
|
} else {
|
|
|
|
|
unscaled_size_y = efscrnsz_y;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch(scale) {
|
|
|
|
|
case 0: /* 50% */
|
|
|
|
|
scrnsz_x = (unscaled_size_x>>1);
|
|
|
|
|
scrnsz_y = (unscaled_size_y>>1);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 1: /* 100% */
|
|
|
|
|
scrnsz_x = unscaled_size_x;
|
|
|
|
|
scrnsz_y = unscaled_size_y;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 2: /* 150% */
|
|
|
|
|
scrnsz_x = ((unscaled_size_x*3)>>1);
|
|
|
|
|
scrnsz_y = ((unscaled_size_y*3)>>1);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 3: /* 200% */
|
|
|
|
|
scrnsz_x = (unscaled_size_x<<1);
|
|
|
|
|
scrnsz_y = (unscaled_size_y<<1);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If the resolution has changed, let the main thread handle it. */
|
|
|
|
|
if ((owsx != scrnsz_x) || (owsy != scrnsz_y))
|
|
|
|
|
doresize = 1;
|
|
|
|
|
else
|
|
|
|
|
doresize = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
set_screen_size_natural(void)
|
|
|
|
|
{
|
|
|
|
|
set_screen_size(unscaled_size_x, unscaled_size_y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-10-06 18:20:09 -04:00
|
|
|
void
|
|
|
|
|
get_screen_size_natural(int *x, int *y)
|
2018-02-20 21:44:51 -05:00
|
|
|
{
|
2018-10-06 18:20:09 -04:00
|
|
|
if (x != NULL)
|
|
|
|
|
*x = unscaled_size_x;
|
|
|
|
|
if (y != NULL)
|
|
|
|
|
*y = efscrnsz_y;
|
2018-02-20 21:44:51 -05:00
|
|
|
}
|