2017-05-30 03:38:38 +02:00
|
|
|
/*
|
|
|
|
|
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
|
|
|
|
* running old operating systems and software designed for IBM
|
|
|
|
|
* PC systems and compatibles from 1981 through fairly recent
|
|
|
|
|
* system designs based on the PCI bus.
|
|
|
|
|
*
|
|
|
|
|
* This file is part of the 86Box distribution.
|
|
|
|
|
*
|
2017-10-19 21:26:02 -04:00
|
|
|
* Main emulator module where most things are controlled.
|
2017-05-30 03:38:38 +02:00
|
|
|
*
|
2018-11-08 19:21:55 +01:00
|
|
|
* Version: @(#)pc.c 1.0.89 2018/11/05
|
2017-05-30 03:38:38 +02:00
|
|
|
*
|
2017-06-04 02:11:19 -04:00
|
|
|
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
2017-05-30 03:38:38 +02:00
|
|
|
* Miran Grca, <mgrca8@gmail.com>
|
2017-10-01 16:56:15 -04:00
|
|
|
* Fred N. van Kempen, <decwiz@yahoo.com>
|
2017-10-08 19:14:46 -04:00
|
|
|
*
|
2018-01-17 18:43:36 +01:00
|
|
|
* Copyright 2008-2018 Sarah Walker.
|
|
|
|
|
* Copyright 2016-2018 Miran Grca.
|
|
|
|
|
* Copyright 2017,2018 Fred N. van Kempen.
|
2017-05-30 03:38:38 +02:00
|
|
|
*/
|
2018-01-19 15:39:13 +01:00
|
|
|
#include <inttypes.h>
|
2018-05-21 19:04:05 +02:00
|
|
|
#include <stdarg.h>
|
2016-06-26 00:34:39 +02:00
|
|
|
#include <stdio.h>
|
2017-09-25 04:31:20 -04:00
|
|
|
#include <stdint.h>
|
2016-06-26 00:34:39 +02:00
|
|
|
#include <stdlib.h>
|
2017-09-25 04:31:20 -04:00
|
|
|
#include <string.h>
|
2017-10-21 20:29:11 -04:00
|
|
|
#include <time.h>
|
2017-09-25 04:31:20 -04:00
|
|
|
#include <wchar.h>
|
2017-12-10 02:53:10 -05:00
|
|
|
#define HAVE_STDARG_H
|
2017-05-05 01:49:42 +02:00
|
|
|
#include "86box.h"
|
2017-09-04 01:52:29 -04:00
|
|
|
#include "config.h"
|
2017-10-09 03:18:50 -04:00
|
|
|
#include "cpu/cpu.h"
|
2017-10-15 02:43:13 +02:00
|
|
|
#ifdef USE_DYNAREC
|
2017-10-14 22:51:43 -04:00
|
|
|
# include "cpu/codegen.h"
|
2017-10-15 02:43:13 +02:00
|
|
|
#endif
|
2017-10-09 03:18:50 -04:00
|
|
|
#include "cpu/x86_ops.h"
|
2017-10-07 00:46:54 -04:00
|
|
|
#include "io.h"
|
2017-05-06 17:48:33 +02:00
|
|
|
#include "mem.h"
|
2017-09-25 04:31:20 -04:00
|
|
|
#include "rom.h"
|
2017-05-06 17:48:33 +02:00
|
|
|
#include "dma.h"
|
2018-04-25 23:51:13 +02:00
|
|
|
#include "pci.h"
|
2017-10-09 03:18:50 -04:00
|
|
|
#include "pic.h"
|
|
|
|
|
#include "pit.h"
|
2017-09-04 01:52:29 -04:00
|
|
|
#include "random.h"
|
2017-10-09 03:18:50 -04:00
|
|
|
#include "timer.h"
|
2017-05-05 01:49:42 +02:00
|
|
|
#include "device.h"
|
2017-10-09 03:18:50 -04:00
|
|
|
#include "nvr.h"
|
|
|
|
|
#include "machine/machine.h"
|
2017-12-04 11:59:26 -05:00
|
|
|
#include "bugger.h"
|
2018-09-03 13:55:09 +02:00
|
|
|
#include "isamem.h"
|
|
|
|
|
#include "isartc.h"
|
2017-10-09 03:18:50 -04:00
|
|
|
#include "lpt.h"
|
|
|
|
|
#include "serial.h"
|
2017-12-04 11:59:26 -05:00
|
|
|
#include "keyboard.h"
|
|
|
|
|
#include "mouse.h"
|
|
|
|
|
#include "game/gameport.h"
|
2018-01-17 18:43:36 +01:00
|
|
|
#include "floppy/fdd.h"
|
2017-12-04 11:59:26 -05:00
|
|
|
#include "floppy/fdc.h"
|
|
|
|
|
#include "disk/hdd.h"
|
|
|
|
|
#include "disk/hdc.h"
|
|
|
|
|
#include "disk/hdc_ide.h"
|
2018-04-25 23:51:13 +02:00
|
|
|
#include "scsi/scsi.h"
|
2018-10-02 22:54:28 +02:00
|
|
|
#include "scsi/scsi_device.h"
|
2017-10-02 02:15:35 -04:00
|
|
|
#include "cdrom/cdrom.h"
|
2018-07-15 01:41:53 +02:00
|
|
|
#include "disk/zip.h"
|
|
|
|
|
#include "scsi/scsi_disk.h"
|
2017-11-20 01:58:23 -05:00
|
|
|
#include "cdrom/cdrom_image.h"
|
2017-08-27 04:33:47 +01:00
|
|
|
#include "network/network.h"
|
2017-10-09 03:18:50 -04:00
|
|
|
#include "sound/sound.h"
|
|
|
|
|
#include "sound/midi.h"
|
|
|
|
|
#include "sound/snd_speaker.h"
|
|
|
|
|
#include "video/video.h"
|
2017-10-10 03:07:29 -04:00
|
|
|
#include "ui.h"
|
|
|
|
|
#include "plat.h"
|
2017-10-11 05:40:44 -04:00
|
|
|
#include "plat_midi.h"
|
2017-05-06 17:48:33 +02:00
|
|
|
|
|
|
|
|
|
2017-10-19 21:26:02 -04:00
|
|
|
/* Commandline options. */
|
|
|
|
|
int dump_on_exit = 0; /* (O) dump regs on exit */
|
2017-10-21 20:29:11 -04:00
|
|
|
int do_dump_config = 0; /* (O) dump config on load */
|
2017-10-19 21:26:02 -04:00
|
|
|
int start_in_fullscreen = 0; /* (O) start in fullscreen */
|
2017-11-23 17:42:00 -05:00
|
|
|
#ifdef _WIN32
|
|
|
|
|
int force_debug = 0; /* (O) force debug output */
|
|
|
|
|
#endif
|
2017-10-27 20:54:31 -04:00
|
|
|
#ifdef USE_WX
|
|
|
|
|
int video_fps = RENDER_FPS; /* (O) render speed in fps */
|
|
|
|
|
#endif
|
2018-01-19 15:39:13 +01:00
|
|
|
int settings_only = 0; /* (O) show only the settings dialog */
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
uint64_t unique_id = 0;
|
|
|
|
|
uint64_t source_hwnd = 0;
|
|
|
|
|
#endif
|
2017-11-23 17:42:00 -05:00
|
|
|
wchar_t log_path[1024] = { L'\0'}; /* (O) full path of logfile */
|
2017-10-19 21:26:02 -04:00
|
|
|
|
|
|
|
|
/* Configuration values. */
|
|
|
|
|
int window_w, window_h, /* (C) window size and */
|
|
|
|
|
window_x, window_y, /* position info */
|
|
|
|
|
window_remember,
|
|
|
|
|
vid_resize, /* (C) allow resizing */
|
|
|
|
|
invert_display, /* (C) invert the display */
|
|
|
|
|
suppress_overscan = 0; /* (C) suppress overscans */
|
|
|
|
|
int scale = 0; /* (C) screen scale factor */
|
|
|
|
|
int vid_api = 0; /* (C) video renderer */
|
|
|
|
|
int vid_cga_contrast = 0, /* (C) video */
|
|
|
|
|
video_fullscreen = 0, /* (C) video */
|
|
|
|
|
video_fullscreen_scale = 0, /* (C) video */
|
|
|
|
|
video_fullscreen_first = 0, /* (C) video */
|
|
|
|
|
enable_overscan = 0, /* (C) video */
|
2018-07-15 01:41:53 +02:00
|
|
|
force_43 = 0; /* (C) video */
|
2017-11-02 02:28:00 -05:00
|
|
|
int serial_enabled[SERIAL_MAX] = {0,0}, /* (C) enable serial ports */
|
|
|
|
|
lpt_enabled = 0, /* (C) enable LPT ports */
|
2018-09-03 13:55:09 +02:00
|
|
|
bugger_enabled = 0, /* (C) enable ISAbugger */
|
|
|
|
|
isamem_type[ISAMEM_MAX] = { 0,0,0,0 }, /* (C) enable ISA mem cards */
|
|
|
|
|
isartc_type = 0; /* (C) enable ISA RTC card */
|
2017-11-02 02:28:00 -05:00
|
|
|
int gfxcard = 0; /* (C) graphics/video card */
|
2017-11-05 01:57:04 -05:00
|
|
|
int sound_is_float = 1, /* (C) sound uses FP values */
|
|
|
|
|
GAMEBLASTER = 0, /* (C) sound option */
|
2017-11-02 02:28:00 -05:00
|
|
|
GUS = 0, /* (C) sound option */
|
|
|
|
|
SSI2001 = 0, /* (C) sound option */
|
|
|
|
|
voodoo_enabled = 0; /* (C) video option */
|
2018-04-25 23:51:13 +02:00
|
|
|
uint32_t mem_size = 0; /* (C) memory size */
|
2017-11-02 02:28:00 -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-08-01 18:07:52 +02:00
|
|
|
int time_sync = 0; /* (C) enable time sync */
|
2017-10-19 04:27:04 -04:00
|
|
|
|
|
|
|
|
/* Statistics. */
|
2017-10-19 21:26:02 -04:00
|
|
|
extern int
|
|
|
|
|
mmuflush,
|
|
|
|
|
readlnum,
|
|
|
|
|
writelnum;
|
|
|
|
|
|
2018-04-26 13:33:29 +02:00
|
|
|
int fps, framecount; /* emulator % */
|
2017-10-19 04:27:04 -04:00
|
|
|
|
2017-10-02 02:15:35 -04:00
|
|
|
int CPUID;
|
|
|
|
|
int output;
|
|
|
|
|
int atfullspeed;
|
2017-10-19 04:27:04 -04:00
|
|
|
int cpuspeed2;
|
2017-10-02 02:15:35 -04:00
|
|
|
int clockrate;
|
2017-10-19 04:27:04 -04:00
|
|
|
|
|
|
|
|
wchar_t exe_path[1024]; /* path (dir) of executable */
|
2017-12-04 11:59:26 -05:00
|
|
|
wchar_t usr_path[1024]; /* path (dir) of user data */
|
|
|
|
|
wchar_t cfg_path[1024]; /* full path of config file */
|
2017-11-23 17:42:00 -05:00
|
|
|
FILE *stdlog = NULL; /* file to log output to */
|
2017-10-19 04:27:04 -04:00
|
|
|
int scrnsz_x = SCREEN_RES_X, /* current screen size, X */
|
|
|
|
|
scrnsz_y = SCREEN_RES_Y; /* current screen size, Y */
|
2017-11-02 02:28:00 -05:00
|
|
|
int config_changed; /* config has changed */
|
|
|
|
|
int romset; /* current machine ID */
|
2017-10-19 04:27:04 -04:00
|
|
|
int title_update;
|
|
|
|
|
int64_t main_time;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
|
2018-02-14 12:04:54 +01:00
|
|
|
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;
|
2017-11-18 16:39:01 +01:00
|
|
|
|
|
|
|
|
|
2018-03-19 09:48:44 +01:00
|
|
|
#ifndef RELEASE_BUILD
|
2018-01-26 22:17:09 +01:00
|
|
|
static char buff[1024];
|
|
|
|
|
static int seen = 0;
|
|
|
|
|
|
2018-03-19 09:48:44 +01:00
|
|
|
static int suppr_seen = 1;
|
|
|
|
|
#endif
|
|
|
|
|
|
2017-12-04 11:59:26 -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.
|
|
|
|
|
*/
|
2017-10-02 02:15:35 -04:00
|
|
|
void
|
2017-12-10 02:53:10 -05:00
|
|
|
pclog_ex(const char *fmt, va_list ap)
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
|
|
|
|
#ifndef RELEASE_BUILD
|
2017-12-04 11:59:26 -05:00
|
|
|
char temp[1024];
|
2017-11-23 17:42:00 -05:00
|
|
|
|
|
|
|
|
if (stdlog == NULL) {
|
|
|
|
|
if (log_path[0] != L'\0') {
|
|
|
|
|
stdlog = plat_fopen(log_path, L"w");
|
|
|
|
|
if (stdlog == NULL)
|
|
|
|
|
stdlog = stdout;
|
|
|
|
|
} else {
|
|
|
|
|
stdlog = stdout;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-04 11:59:26 -05:00
|
|
|
vsprintf(temp, fmt, ap);
|
2018-03-19 09:48:44 +01:00
|
|
|
if (suppr_seen && ! strcmp(buff, temp)) {
|
2017-12-04 11:59:26 -05:00
|
|
|
seen++;
|
|
|
|
|
} else {
|
2018-03-19 09:48:44 +01:00
|
|
|
if (suppr_seen && seen) {
|
2017-12-04 11:59:26 -05:00
|
|
|
fprintf(stdlog, "*** %d repeats ***\n", seen);
|
|
|
|
|
}
|
2017-12-16 19:46:07 +01:00
|
|
|
seen = 0;
|
2017-12-04 11:59:26 -05:00
|
|
|
strcpy(buff, temp);
|
|
|
|
|
fprintf(stdlog, temp, ap);
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-23 17:42:00 -05:00
|
|
|
fflush(stdlog);
|
2016-06-26 00:34:39 +02:00
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-02 02:15:35 -04:00
|
|
|
|
2018-03-19 09:48:44 +01:00
|
|
|
void
|
|
|
|
|
pclog_toggle_suppr(void)
|
|
|
|
|
{
|
|
|
|
|
#ifndef RELEASE_BUILD
|
|
|
|
|
suppr_seen ^= 1;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2017-12-10 02:53:10 -05:00
|
|
|
/* Log something. We only do this in non-release builds. */
|
|
|
|
|
void
|
|
|
|
|
pclog(const char *fmt, ...)
|
|
|
|
|
{
|
|
|
|
|
#ifndef RELEASE_BUILD
|
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
|
|
va_start(ap, fmt);
|
|
|
|
|
pclog_ex(fmt, ap);
|
|
|
|
|
va_end(ap);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2017-10-02 02:15:35 -04:00
|
|
|
/* Log a fatal error, and display a UI message before exiting. */
|
|
|
|
|
void
|
2017-12-04 11:59:26 -05:00
|
|
|
fatal(const char *fmt, ...)
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2017-11-03 03:16:04 -05:00
|
|
|
char temp[1024];
|
|
|
|
|
va_list ap;
|
|
|
|
|
char *sp;
|
2017-10-02 02:15:35 -04:00
|
|
|
|
2017-12-04 11:59:26 -05:00
|
|
|
va_start(ap, fmt);
|
2017-11-23 17:42:00 -05:00
|
|
|
|
|
|
|
|
if (stdlog == NULL) {
|
|
|
|
|
if (log_path[0] != L'\0') {
|
|
|
|
|
stdlog = plat_fopen(log_path, L"w");
|
|
|
|
|
if (stdlog == NULL)
|
|
|
|
|
stdlog = stdout;
|
|
|
|
|
} else {
|
|
|
|
|
stdlog = stdout;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-04 11:59:26 -05:00
|
|
|
vsprintf(temp, fmt, ap);
|
2017-11-23 17:42:00 -05:00
|
|
|
fprintf(stdlog, "%s", temp);
|
|
|
|
|
fflush(stdlog);
|
2017-11-03 03:16:04 -05:00
|
|
|
va_end(ap);
|
2017-10-02 02:15:35 -04:00
|
|
|
|
2017-11-03 03:16:04 -05:00
|
|
|
nvr_save();
|
2017-10-02 02:15:35 -04:00
|
|
|
|
2017-11-03 03:16:04 -05:00
|
|
|
config_save();
|
2017-10-02 02:15:35 -04:00
|
|
|
|
2017-11-03 03:16:04 -05:00
|
|
|
dumppic();
|
|
|
|
|
dumpregs(1);
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2017-11-03 03:16:04 -05:00
|
|
|
/* Make sure the message does not have a trailing newline. */
|
|
|
|
|
if ((sp = strchr(temp, '\n')) != NULL) *sp = '\0';
|
2017-05-07 02:14:44 -04:00
|
|
|
|
2018-09-21 03:19:29 +02:00
|
|
|
/* Cleanly terminate all of the emulator's components so as
|
|
|
|
|
to avoid things like threads getting stuck. */
|
|
|
|
|
do_stop();
|
|
|
|
|
|
2017-11-03 03:16:04 -05:00
|
|
|
ui_msgbox(MBX_ERROR|MBX_FATAL|MBX_ANSI, temp);
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2017-12-04 11:59:26 -05:00
|
|
|
fflush(stdlog);
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2017-11-03 03:16:04 -05:00
|
|
|
exit(-1);
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
|
2017-10-02 02:15:35 -04:00
|
|
|
|
2018-05-21 19:04:05 +02:00
|
|
|
#ifdef ENABLE_PC_LOG
|
|
|
|
|
int pc_do_log = ENABLE_PC_LOG;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
2018-10-19 00:39:32 +02:00
|
|
|
pc_log(const char *fmt, ...)
|
2018-05-21 19:04:05 +02:00
|
|
|
{
|
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
|
|
if (pc_do_log) {
|
2018-10-19 00:39:32 +02:00
|
|
|
va_start(ap, fmt);
|
|
|
|
|
pclog_ex(fmt, ap);
|
2018-05-21 19:04:05 +02:00
|
|
|
va_end(ap);
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-10-19 00:39:32 +02:00
|
|
|
#else
|
|
|
|
|
#define pc_log(fmt, ...)
|
|
|
|
|
#endif
|
2018-05-21 19:04:05 +02:00
|
|
|
|
|
|
|
|
|
2017-10-02 02:15:35 -04:00
|
|
|
/*
|
|
|
|
|
* Perform initial startup of the PC.
|
|
|
|
|
*
|
|
|
|
|
* This is the platform-indepenent part of the startup,
|
2017-10-24 22:10:21 -04:00
|
|
|
* where we check commandline arguments and load a
|
2017-10-02 02:15:35 -04:00
|
|
|
* configuration file.
|
|
|
|
|
*/
|
2017-10-07 00:46:54 -04:00
|
|
|
int
|
2017-10-02 02:15:35 -04:00
|
|
|
pc_init(int argc, wchar_t *argv[])
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2017-12-04 11:59:26 -05:00
|
|
|
wchar_t path[2048];
|
2017-10-13 02:44:32 -04:00
|
|
|
wchar_t *cfg = NULL, *p;
|
2017-10-21 20:29:11 -04:00
|
|
|
char temp[128];
|
|
|
|
|
struct tm *info;
|
|
|
|
|
time_t now;
|
2017-10-02 02:15:35 -04:00
|
|
|
int c;
|
2018-04-25 23:51:13 +02:00
|
|
|
uint32_t *uid, *shwnd;
|
2017-10-02 02:15:35 -04:00
|
|
|
|
|
|
|
|
/* Grab the executable's full path. */
|
2017-10-17 01:59:09 -04:00
|
|
|
plat_get_exe_name(exe_path, sizeof(exe_path)-1);
|
|
|
|
|
p = plat_get_filename(exe_path);
|
2017-10-02 02:15:35 -04:00
|
|
|
*p = L'\0';
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Get the current working directory.
|
2017-12-04 11:59:26 -05:00
|
|
|
*
|
2017-10-02 02:15:35 -04:00
|
|
|
* 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.
|
|
|
|
|
*/
|
2017-12-04 11:59:26 -05:00
|
|
|
plat_getcwd(usr_path, sizeof_w(usr_path)-1);
|
|
|
|
|
memset(path, 0x00, sizeof(path));
|
2017-10-02 02:15:35 -04:00
|
|
|
|
|
|
|
|
for (c=1; c<argc; c++) {
|
2017-10-11 17:45:46 -04:00
|
|
|
if (argv[c][0] != L'-') break;
|
|
|
|
|
|
2017-10-12 14:25:17 -04:00
|
|
|
if (!wcscasecmp(argv[c], L"--help") || !wcscasecmp(argv[c], L"-?")) {
|
2017-09-23 21:12:26 -04:00
|
|
|
usage:
|
2017-10-11 17:45:46 -04:00
|
|
|
printf("\nUsage: 86box [options] [cfg-file]\n\n");
|
|
|
|
|
printf("Valid options are:\n\n");
|
2017-11-23 17:42:00 -05:00
|
|
|
printf("-? or --help - show this information\n");
|
|
|
|
|
printf("-C or --dumpcfg - dump config file after loading\n");
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
printf("-D or --debug - force debug output logging\n");
|
|
|
|
|
#endif
|
|
|
|
|
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-01-19 15:39:13 +01:00
|
|
|
printf("-S or --settings - show only the settings dialog\n");
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
printf("-H or --hwnd id,hwnd - sends back the main dialog's hwnd\n");
|
2017-10-27 20:54:31 -04:00
|
|
|
#endif
|
2017-10-14 13:38:05 -04:00
|
|
|
printf("\nA config file can be specified. If none is, the default file will be used.\n");
|
2017-10-07 00:46:54 -04:00
|
|
|
return(0);
|
2017-10-21 20:29:11 -04:00
|
|
|
} else if (!wcscasecmp(argv[c], L"--dumpcfg") ||
|
|
|
|
|
!wcscasecmp(argv[c], L"-C")) {
|
|
|
|
|
do_dump_config = 1;
|
2017-11-23 17:42:00 -05:00
|
|
|
#ifdef _WIN32
|
|
|
|
|
} else if (!wcscasecmp(argv[c], L"--debug") ||
|
2017-10-13 02:44:32 -04:00
|
|
|
!wcscasecmp(argv[c], L"-D")) {
|
2017-11-23 17:42:00 -05:00
|
|
|
force_debug = 1;
|
|
|
|
|
#endif
|
2017-10-13 02:44:32 -04:00
|
|
|
} else if (!wcscasecmp(argv[c], L"--fullscreen") ||
|
|
|
|
|
!wcscasecmp(argv[c], L"-F")) {
|
2017-10-02 02:15:35 -04:00
|
|
|
start_in_fullscreen = 1;
|
2017-11-23 17:42:00 -05:00
|
|
|
} else if (!wcscasecmp(argv[c], L"--logfile") ||
|
|
|
|
|
!wcscasecmp(argv[c], L"-L")) {
|
|
|
|
|
if ((c+1) == argc) goto usage;
|
|
|
|
|
|
|
|
|
|
wcscpy(log_path, argv[++c]);
|
2017-10-13 02:44:32 -04:00
|
|
|
} else if (!wcscasecmp(argv[c], L"--vmpath") ||
|
|
|
|
|
!wcscasecmp(argv[c], L"-P")) {
|
2017-10-27 20:54:31 -04:00
|
|
|
if ((c+1) == argc) goto usage;
|
2017-10-11 17:45:46 -04:00
|
|
|
|
2017-12-04 11:59:26 -05:00
|
|
|
wcscpy(path, argv[++c]);
|
2018-01-19 15:39:13 +01:00
|
|
|
} else if (!wcscasecmp(argv[c], L"--settings") ||
|
|
|
|
|
!wcscasecmp(argv[c], L"-S")) {
|
|
|
|
|
settings_only = 1;
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
} else if (!wcscasecmp(argv[c], L"--hwnd") ||
|
|
|
|
|
!wcscasecmp(argv[c], L"-H")) {
|
|
|
|
|
|
|
|
|
|
if ((c+1) == argc) goto usage;
|
|
|
|
|
|
|
|
|
|
wcstombs(temp, argv[++c], 128);
|
2018-04-25 23:51:13 +02:00
|
|
|
uid = (uint32_t *) &unique_id;
|
|
|
|
|
shwnd = (uint32_t *) &source_hwnd;
|
|
|
|
|
sscanf(temp, "%08X%08X,%08X%08X", uid + 1, uid, shwnd + 1, shwnd);
|
2017-10-27 20:54:31 -04:00
|
|
|
#endif
|
2017-10-13 02:44:32 -04:00
|
|
|
} else if (!wcscasecmp(argv[c], L"--test")) {
|
2017-10-02 02:15:35 -04:00
|
|
|
/* some (undocumented) test function here.. */
|
2017-05-05 01:49:42 +02:00
|
|
|
|
2017-10-02 02:15:35 -04:00
|
|
|
/* .. and then exit. */
|
2017-10-07 00:46:54 -04:00
|
|
|
return(0);
|
2016-09-27 21:38:29 +02:00
|
|
|
}
|
2017-05-05 01:49:42 +02:00
|
|
|
|
2017-10-02 02:15:35 -04:00
|
|
|
/* Uhm... out of options here.. */
|
|
|
|
|
else goto usage;
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-11 17:45:46 -04:00
|
|
|
/* One argument (config file) allowed. */
|
|
|
|
|
if (c < argc)
|
|
|
|
|
cfg = argv[c++];
|
|
|
|
|
if (c != argc) goto usage;
|
|
|
|
|
|
2017-12-04 11:59:26 -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.
|
|
|
|
|
*/
|
|
|
|
|
if (path[0] != L'\0') {
|
|
|
|
|
if (! plat_path_abs(path)) {
|
|
|
|
|
/*
|
|
|
|
|
* This looks like a relative path.
|
|
|
|
|
*
|
|
|
|
|
* Add it to the current working directory
|
|
|
|
|
* to convert it (back) to an absolute path.
|
|
|
|
|
*/
|
|
|
|
|
plat_path_slash(usr_path);
|
|
|
|
|
wcscat(usr_path, path);
|
2017-11-24 13:14:09 +01:00
|
|
|
} else {
|
2017-12-04 11:59:26 -05:00
|
|
|
/*
|
|
|
|
|
* The user-provided path seems like an
|
|
|
|
|
* absolute path, so just use that.
|
|
|
|
|
*/
|
|
|
|
|
wcscpy(usr_path, path);
|
2017-11-24 13:14:09 +01:00
|
|
|
}
|
2018-07-15 01:41:53 +02:00
|
|
|
|
|
|
|
|
/* If the specified path does not yet exist,
|
|
|
|
|
create it. */
|
2018-10-12 23:54:23 +02:00
|
|
|
if (! plat_dir_check(usr_path))
|
|
|
|
|
plat_dir_create(usr_path);
|
2017-10-02 02:15:35 -04:00
|
|
|
}
|
|
|
|
|
|
2017-12-04 11:59:26 -05:00
|
|
|
/* Make sure we have a trailing backslash. */
|
|
|
|
|
plat_path_slash(usr_path);
|
|
|
|
|
|
|
|
|
|
/* 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';
|
2017-11-24 13:14:09 +01:00
|
|
|
|
2017-10-01 16:29:15 -04:00
|
|
|
/*
|
2017-10-02 02:15:35 -04:00
|
|
|
* If this is an absolute path, keep it, as
|
2017-12-04 11:59:26 -05:00
|
|
|
* there is probably have a reason to do so.
|
2017-10-02 02:15:35 -04:00
|
|
|
* Otherwise, assume the pathname given is
|
2017-12-04 11:59:26 -05:00
|
|
|
* relative to whatever the usr_path is.
|
2017-10-01 16:29:15 -04:00
|
|
|
*/
|
2017-12-04 11:59:26 -05:00
|
|
|
if (plat_path_abs(cfg))
|
|
|
|
|
wcscpy(usr_path, cfg);
|
2017-10-02 02:15:35 -04:00
|
|
|
else
|
2017-12-04 11:59:26 -05:00
|
|
|
wcscat(usr_path, cfg);
|
|
|
|
|
|
|
|
|
|
/* Make sure we have a trailing backslash. */
|
|
|
|
|
plat_path_slash(usr_path);
|
2017-10-02 02:15:35 -04:00
|
|
|
}
|
|
|
|
|
|
2017-12-04 11:59:26 -05:00
|
|
|
/* At this point, we can safely create the full path name. */
|
|
|
|
|
plat_append_filename(cfg_path, usr_path, p);
|
|
|
|
|
|
2017-10-21 20:29:11 -04:00
|
|
|
/*
|
|
|
|
|
* This is where we start outputting to the log file,
|
|
|
|
|
* if there is one. Create a little info header first.
|
|
|
|
|
*/
|
|
|
|
|
(void)time(&now);
|
|
|
|
|
info = localtime(&now);
|
|
|
|
|
strftime(temp, sizeof(temp), "%Y/%m/%d %H:%M:%S", info);
|
|
|
|
|
pclog("#\n# %ls v%ls logfile, created %s\n#\n",
|
|
|
|
|
EMU_NAME_W, EMU_VERSION_W, temp);
|
|
|
|
|
pclog("# Emulator path: %ls\n", exe_path);
|
2017-12-04 11:59:26 -05:00
|
|
|
pclog("# Userfiles path: %ls\n", usr_path);
|
|
|
|
|
pclog("# Configuration file: %ls\n#\n\n", cfg_path);
|
2017-10-21 20:29:11 -04:00
|
|
|
|
2017-10-02 02:15:35 -04: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..
|
|
|
|
|
*/
|
|
|
|
|
hdd_init();
|
2017-10-07 00:46:54 -04:00
|
|
|
network_init();
|
2017-12-04 11:59:26 -05:00
|
|
|
mouse_init();
|
2017-10-13 02:44:32 -04:00
|
|
|
cdrom_global_init();
|
2018-01-26 22:17:09 +01:00
|
|
|
zip_global_init();
|
2017-10-02 02:15:35 -04:00
|
|
|
|
2017-10-07 00:46:54 -04:00
|
|
|
/* Load the configuration file. */
|
2017-12-04 11:59:26 -05:00
|
|
|
config_load();
|
2017-10-07 00:46:54 -04:00
|
|
|
|
|
|
|
|
/* All good! */
|
|
|
|
|
return(1);
|
2017-10-02 02:15:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
pc_full_speed(void)
|
|
|
|
|
{
|
|
|
|
|
cpuspeed2 = cpuspeed;
|
|
|
|
|
|
|
|
|
|
if (! atfullspeed) {
|
2018-05-21 19:04:05 +02:00
|
|
|
pc_log("Set fullspeed - %i %i %i\n", is386, AT, cpuspeed2);
|
2018-07-15 01:41:53 +02:00
|
|
|
if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type >= CPU_286)
|
2018-03-02 20:47:18 +01:00
|
|
|
setpitclock(machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed);
|
2018-07-15 01:41:53 +02:00
|
|
|
else
|
2017-10-02 02:15:35 -04:00
|
|
|
setpitclock(14318184.0);
|
|
|
|
|
}
|
|
|
|
|
atfullspeed = 1;
|
2018-04-25 23:51:13 +02:00
|
|
|
|
|
|
|
|
nvr_period_recalc();
|
2017-05-29 01:18:32 +02:00
|
|
|
}
|
|
|
|
|
|
2017-10-02 02:15:35 -04:00
|
|
|
|
|
|
|
|
void
|
|
|
|
|
pc_speed_changed(void)
|
2017-05-29 01:18:32 +02:00
|
|
|
{
|
2018-07-15 01:41:53 +02:00
|
|
|
if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type >= CPU_286)
|
2018-03-02 20:47:18 +01:00
|
|
|
setpitclock(machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed);
|
2018-07-15 01:41:53 +02:00
|
|
|
else
|
2017-10-02 02:15:35 -04:00
|
|
|
setpitclock(14318184.0);
|
2018-04-25 23:51:13 +02:00
|
|
|
|
|
|
|
|
nvr_period_recalc();
|
2017-10-02 02:15:35 -04:00
|
|
|
}
|
2017-05-29 01:18:32 +02:00
|
|
|
|
2017-02-18 23:45:30 +01:00
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
#if 0
|
2017-11-20 01:58:23 -05:00
|
|
|
/* Re-load system configuration and restart. */
|
2017-12-04 11:59:26 -05:00
|
|
|
/* FIXME: this has to be reviewed! */
|
2017-11-20 01:58:23 -05:00
|
|
|
void
|
|
|
|
|
pc_reload(wchar_t *fn)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
2017-12-04 11:59:26 -05:00
|
|
|
config_write(cfg_path);
|
2017-11-20 01:58:23 -05:00
|
|
|
|
|
|
|
|
for (i=0; i<FDD_NUM; i++)
|
2018-01-17 18:43:36 +01:00
|
|
|
fdd_close(i);
|
2018-04-25 23:51:13 +02:00
|
|
|
|
|
|
|
|
cdrom_close();
|
2017-11-20 01:58:23 -05:00
|
|
|
|
|
|
|
|
pc_reset_hard_close();
|
|
|
|
|
|
2017-12-04 11:59:26 -05:00
|
|
|
// FIXME: set up new config file path 'fn'... --FvK
|
|
|
|
|
|
|
|
|
|
config_load();
|
2017-11-20 01:58:23 -05:00
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
cdrom_hard_reset();
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
zip_hard_reset();
|
2018-01-26 22:17:09 +01:00
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
scsi_disk_hard_reset();
|
|
|
|
|
|
2018-01-17 18:43:36 +01:00
|
|
|
fdd_load(0, floppyfns[0]);
|
|
|
|
|
fdd_load(1, floppyfns[1]);
|
|
|
|
|
fdd_load(2, floppyfns[2]);
|
|
|
|
|
fdd_load(3, floppyfns[3]);
|
2017-11-20 01:58:23 -05:00
|
|
|
|
|
|
|
|
network_init();
|
|
|
|
|
|
|
|
|
|
pc_reset_hard_init();
|
|
|
|
|
}
|
2018-04-25 23:51:13 +02:00
|
|
|
#endif
|
2017-11-20 01:58:23 -05:00
|
|
|
|
|
|
|
|
|
2017-10-02 02:15:35 -04:00
|
|
|
/* Initialize modules, ran once, after pc_init. */
|
2017-10-07 00:46:54 -04:00
|
|
|
int
|
2017-10-02 02:15:35 -04:00
|
|
|
pc_init_modules(void)
|
|
|
|
|
{
|
2017-10-07 00:46:54 -04:00
|
|
|
int c, i;
|
|
|
|
|
|
2018-05-21 19:04:05 +02:00
|
|
|
pc_log("Scanning for ROM images:\n");
|
2017-10-19 04:27:04 -04:00
|
|
|
for (c=0,i=0; i<ROM_MAX; i++) {
|
2017-10-07 00:46:54 -04:00
|
|
|
romspresent[i] = rom_load_bios(i);
|
|
|
|
|
c += romspresent[i];
|
|
|
|
|
}
|
|
|
|
|
if (c == 0) {
|
|
|
|
|
/* No usable ROMs found, aborting. */
|
|
|
|
|
return(0);
|
|
|
|
|
}
|
2018-05-21 19:04:05 +02:00
|
|
|
pc_log("A total of %d ROM sets have been loaded.\n", c);
|
2017-10-07 00:46:54 -04:00
|
|
|
|
2017-10-19 04:27:04 -04:00
|
|
|
/* Load the ROMs for the selected machine. */
|
2017-10-07 00:46:54 -04:00
|
|
|
again:
|
|
|
|
|
if (! rom_load_bios(romset)) {
|
|
|
|
|
/* Whoops, ROMs not found. */
|
|
|
|
|
if (romset != -1)
|
2017-10-10 03:07:29 -04:00
|
|
|
ui_msgbox(MBX_INFO, (wchar_t *)IDS_2063);
|
2017-10-07 00:46:54 -04:00
|
|
|
|
2017-10-19 04:27:04 -04:00
|
|
|
/*
|
|
|
|
|
* Select another machine to use.
|
|
|
|
|
*
|
|
|
|
|
* FIXME:
|
|
|
|
|
* We should not do that here. If something turns out
|
|
|
|
|
* to be wrong with the configuration (such as missing
|
|
|
|
|
* ROM images, we should just display a fatal message
|
|
|
|
|
* in the render window's center, let them click OK,
|
|
|
|
|
* and then exit so they can remedy the situation.
|
|
|
|
|
*/
|
2017-10-07 00:46:54 -04:00
|
|
|
for (c=0; c<ROM_MAX; c++) {
|
|
|
|
|
if (romspresent[c]) {
|
|
|
|
|
romset = c;
|
|
|
|
|
machine = machine_getmachine(romset);
|
|
|
|
|
config_save();
|
|
|
|
|
|
|
|
|
|
/* This can loop if all ROMs are now bad.. */
|
|
|
|
|
goto again;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-12-04 11:59:26 -05:00
|
|
|
|
2017-10-07 00:46:54 -04:00
|
|
|
/* Make sure we have a usable video card. */
|
|
|
|
|
again2:
|
2018-09-19 20:46:42 +02:00
|
|
|
if (! video_card_available(gfxcard)) {
|
2017-10-07 00:46:54 -04:00
|
|
|
if (romset != -1) {
|
2017-10-10 03:07:29 -04:00
|
|
|
ui_msgbox(MBX_INFO, (wchar_t *)IDS_2064);
|
2017-10-07 00:46:54 -04:00
|
|
|
}
|
2018-09-19 20:46:42 +02:00
|
|
|
c = 0;
|
|
|
|
|
while (video_get_internal_name(c) != NULL) {
|
|
|
|
|
if (video_card_available(c)) {
|
2017-10-07 00:46:54 -04:00
|
|
|
gfxcard = c;
|
|
|
|
|
config_save();
|
|
|
|
|
|
|
|
|
|
/* This can loop if all cards now bad.. */
|
|
|
|
|
goto again2;
|
|
|
|
|
}
|
2018-09-19 20:46:42 +02:00
|
|
|
c++;
|
2017-10-07 00:46:54 -04:00
|
|
|
}
|
|
|
|
|
}
|
2017-10-02 02:15:35 -04:00
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
cpuspeed2 = (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type >= CPU_286) ? 2 : 1;
|
2017-10-02 02:15:35 -04:00
|
|
|
atfullspeed = 0;
|
|
|
|
|
|
|
|
|
|
random_init();
|
2017-10-01 16:29:15 -04:00
|
|
|
|
2017-10-02 02:15:35 -04:00
|
|
|
mem_init();
|
2017-10-03 05:33:31 +02:00
|
|
|
|
2017-10-15 02:43:13 +02:00
|
|
|
#ifdef USE_DYNAREC
|
2017-10-03 05:33:31 +02:00
|
|
|
codegen_init();
|
2017-10-15 02:43:13 +02:00
|
|
|
#endif
|
2017-10-03 05:33:31 +02:00
|
|
|
|
2017-12-04 11:59:26 -05:00
|
|
|
keyboard_init();
|
2017-10-02 02:15:35 -04:00
|
|
|
joystick_init();
|
2018-03-19 04:19:19 +01:00
|
|
|
|
2018-10-30 13:32:25 +01:00
|
|
|
video_init();
|
2017-01-16 01:49:19 +01:00
|
|
|
|
2018-01-17 18:43:36 +01:00
|
|
|
fdd_init();
|
2017-01-16 01:49:19 +01:00
|
|
|
|
2017-10-02 02:15:35 -04:00
|
|
|
sound_init();
|
2017-10-01 16:29:15 -04:00
|
|
|
|
2017-10-02 02:15:35 -04:00
|
|
|
hdc_init(hdc_name);
|
2017-01-16 01:49:19 +01:00
|
|
|
|
2017-10-07 00:46:54 -04:00
|
|
|
return(1);
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
|
2017-10-02 02:15:35 -04:00
|
|
|
|
2017-10-07 00:46:54 -04:00
|
|
|
/* Insert keystrokes into the machine's keyboard buffer. */
|
|
|
|
|
static void
|
2017-10-02 02:15:35 -04:00
|
|
|
pc_keyboard_send(uint8_t val)
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2017-10-02 02:15:35 -04:00
|
|
|
if (AT)
|
|
|
|
|
keyboard_at_adddata_keyboard_raw(val);
|
2018-01-04 07:44:33 +01:00
|
|
|
else
|
2017-10-02 02:15:35 -04:00
|
|
|
keyboard_send(val);
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
|
2017-10-02 02:15:35 -04:00
|
|
|
|
|
|
|
|
void
|
2018-04-25 23:51:13 +02:00
|
|
|
pc_send_ca(uint8_t sc)
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2017-10-02 02:15:35 -04:00
|
|
|
pc_keyboard_send(29); /* Ctrl key pressed */
|
|
|
|
|
pc_keyboard_send(56); /* Alt key pressed */
|
2018-04-25 23:51:13 +02:00
|
|
|
pc_keyboard_send(sc);
|
|
|
|
|
pc_keyboard_send(sc | 0x80);
|
2017-10-02 02:15:35 -04:00
|
|
|
pc_keyboard_send(184); /* Alt key released */
|
2018-04-25 23:51:13 +02:00
|
|
|
pc_keyboard_send(157); /* Ctrl key released */
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
|
2017-07-16 22:07:06 +02:00
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
/* Send the machine a Control-Alt-DEL sequence. */
|
2017-10-02 02:15:35 -04:00
|
|
|
void
|
2018-04-25 23:51:13 +02:00
|
|
|
pc_send_cad(void)
|
2017-07-16 22:07:06 +02:00
|
|
|
{
|
2018-04-25 23:51:13 +02:00
|
|
|
pc_send_ca(83);
|
2017-07-16 22:07:06 +02:00
|
|
|
}
|
|
|
|
|
|
2017-01-24 01:03:23 +01:00
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
/* Send the machine a Control-Alt-ESC sequence. */
|
2017-11-01 01:51:19 -05:00
|
|
|
void
|
2018-04-25 23:51:13 +02:00
|
|
|
pc_send_cae(void)
|
2017-11-01 01:51:19 -05:00
|
|
|
{
|
2018-04-25 23:51:13 +02:00
|
|
|
pc_send_ca(1);
|
2017-11-01 01:51:19 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2017-10-02 02:15:35 -04:00
|
|
|
void
|
2017-10-07 00:46:54 -04:00
|
|
|
pc_reset_hard_close(void)
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2018-10-21 22:09:18 +02:00
|
|
|
ui_sb_set_ready(0);
|
2018-10-19 19:10:12 +02:00
|
|
|
|
2017-10-02 02:15:35 -04:00
|
|
|
suppress_overscan = 0;
|
2017-01-24 01:03:23 +01:00
|
|
|
|
2017-10-03 16:26:55 -04:00
|
|
|
nvr_save();
|
2017-11-23 17:42:00 -05:00
|
|
|
|
2018-01-29 01:19:49 +01:00
|
|
|
mouse_close();
|
|
|
|
|
|
2018-02-06 19:53:34 +01:00
|
|
|
lpt_devices_close();
|
|
|
|
|
|
2017-10-02 02:15:35 -04:00
|
|
|
device_close_all();
|
2017-11-23 17:42:00 -05:00
|
|
|
|
2018-10-30 13:32:25 +01:00
|
|
|
scsi_device_close_all();
|
|
|
|
|
|
2017-10-14 07:03:19 +02:00
|
|
|
midi_close();
|
2017-12-04 11:59:26 -05:00
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
cdrom_close();
|
|
|
|
|
|
2018-10-10 22:33:24 +02:00
|
|
|
zip_close();
|
|
|
|
|
|
|
|
|
|
scsi_disk_close();
|
|
|
|
|
|
2017-10-02 02:15:35 -04:00
|
|
|
closeal();
|
2017-06-19 06:46:08 +02:00
|
|
|
}
|
|
|
|
|
|
2017-10-02 02:15:35 -04:00
|
|
|
|
2017-10-07 00:46:54 -04:00
|
|
|
/*
|
|
|
|
|
* 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.
|
|
|
|
|
*/
|
2017-10-02 02:15:35 -04:00
|
|
|
void
|
2017-10-07 00:46:54 -04:00
|
|
|
pc_reset_hard_init(void)
|
2017-06-19 06:46:08 +02:00
|
|
|
{
|
2017-10-29 04:20:20 -05:00
|
|
|
/*
|
|
|
|
|
* First, we reset the modules that are not part of
|
|
|
|
|
* the actual machine, but which support some of the
|
|
|
|
|
* modules that are.
|
2017-10-07 00:46:54 -04:00
|
|
|
*/
|
2017-06-22 18:32:53 +02:00
|
|
|
|
2017-10-07 00:46:54 -04:00
|
|
|
/* Reset the general machine support modules. */
|
2018-01-13 22:56:13 +01:00
|
|
|
io_init();
|
2017-10-07 00:46:54 -04:00
|
|
|
timer_reset();
|
2018-04-25 23:51:13 +02:00
|
|
|
|
2017-12-10 02:08:37 -05:00
|
|
|
device_init();
|
2017-10-07 00:46:54 -04:00
|
|
|
|
2017-10-02 02:15:35 -04:00
|
|
|
sound_reset();
|
2017-10-07 00:46:54 -04:00
|
|
|
|
|
|
|
|
/* Initialize the actual machine and its basic modules. */
|
2017-10-02 02:15:35 -04:00
|
|
|
machine_init();
|
2017-10-07 00:46:54 -04:00
|
|
|
|
2018-10-10 22:33:24 +02:00
|
|
|
/* Reset and reconfigure the Sound Card layer. */
|
|
|
|
|
sound_card_reset();
|
|
|
|
|
|
2018-09-03 13:55:09 +02:00
|
|
|
/* Reset any ISA memory cards. */
|
|
|
|
|
isamem_reset();
|
|
|
|
|
|
|
|
|
|
/* Reset any ISA RTC cards. */
|
|
|
|
|
isartc_reset();
|
|
|
|
|
|
2018-01-17 18:43:36 +01:00
|
|
|
fdd_reset();
|
|
|
|
|
|
2017-10-07 00:46:54 -04:00
|
|
|
/*
|
|
|
|
|
* Once the machine has been initialized, all that remains
|
|
|
|
|
* should be resetting all devices set up for it, to their
|
|
|
|
|
* current configurations !
|
|
|
|
|
*
|
2017-10-10 18:49:20 -04:00
|
|
|
* For now, we will call their reset functions here, but
|
|
|
|
|
* that will be a call to device_reset_all() later !
|
2017-10-07 00:46:54 -04:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* Reset some basic devices. */
|
2017-10-02 02:15:35 -04:00
|
|
|
speaker_init();
|
2018-02-06 19:53:34 +01:00
|
|
|
lpt_devices_init();
|
2017-11-19 20:33:25 +01:00
|
|
|
shadowbios = 0;
|
2017-10-25 05:30:06 -04:00
|
|
|
|
2018-01-29 01:19:49 +01:00
|
|
|
/*
|
2018-11-08 19:21:55 +01:00
|
|
|
* Reset the mouse, this will attach it to any port needed.
|
2018-01-29 01:19:49 +01:00
|
|
|
*/
|
|
|
|
|
mouse_reset();
|
|
|
|
|
|
2017-10-07 00:46:54 -04:00
|
|
|
/* Reset the Hard Disk Controller module. */
|
2017-10-02 02:15:35 -04:00
|
|
|
hdc_reset();
|
|
|
|
|
|
2017-10-07 00:46:54 -04:00
|
|
|
/* Reset and reconfigure the SCSI layer. */
|
2017-10-02 02:15:35 -04:00
|
|
|
scsi_card_init();
|
2017-10-07 00:46:54 -04:00
|
|
|
|
2018-10-10 22:33:24 +02:00
|
|
|
cdrom_hard_reset();
|
|
|
|
|
|
|
|
|
|
zip_hard_reset();
|
|
|
|
|
|
|
|
|
|
scsi_disk_hard_reset();
|
2018-04-25 23:51:13 +02:00
|
|
|
|
2017-10-07 00:46:54 -04:00
|
|
|
/* Reset and reconfigure the Network Card layer. */
|
2017-10-02 02:15:35 -04:00
|
|
|
network_reset();
|
|
|
|
|
|
2017-10-29 04:20:20 -05:00
|
|
|
if (joystick_type != 7)
|
|
|
|
|
gameport_update_joystick_type();
|
|
|
|
|
|
|
|
|
|
if (config_changed) {
|
|
|
|
|
ui_sb_update_panes();
|
|
|
|
|
|
|
|
|
|
config_save();
|
|
|
|
|
|
|
|
|
|
config_changed = 0;
|
2018-10-21 22:09:18 +02:00
|
|
|
} else
|
|
|
|
|
ui_sb_set_ready(1);
|
2017-10-29 04:20:20 -05:00
|
|
|
|
|
|
|
|
/* Needs the status bar... */
|
|
|
|
|
if (bugger_enabled)
|
|
|
|
|
device_add(&bugger_device);
|
|
|
|
|
|
2017-10-07 00:46:54 -04:00
|
|
|
/* Reset the CPU module. */
|
|
|
|
|
resetx86();
|
|
|
|
|
dma_reset();
|
|
|
|
|
pic_reset();
|
2017-11-19 20:33:25 +01:00
|
|
|
cpu_cache_int_enabled = cpu_cache_ext_enabled = 0;
|
2017-10-02 02:15:35 -04:00
|
|
|
|
2018-10-30 13:32:25 +01:00
|
|
|
pc_full_speed();
|
|
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type >= CPU_286)
|
2018-03-02 20:47:18 +01:00
|
|
|
setpitclock(machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed);
|
2017-11-19 20:33:25 +01:00
|
|
|
else
|
|
|
|
|
setpitclock(14318184.0);
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
|
2017-10-02 02:15:35 -04:00
|
|
|
|
|
|
|
|
void
|
|
|
|
|
pc_reset_hard(void)
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2017-10-07 00:46:54 -04:00
|
|
|
pc_reset_hard_close();
|
2017-10-02 02:15:35 -04:00
|
|
|
|
2017-10-07 00:46:54 -04:00
|
|
|
pc_reset_hard_init();
|
2017-06-19 06:46:08 +02:00
|
|
|
}
|
|
|
|
|
|
2017-10-02 02:15:35 -04:00
|
|
|
|
2017-10-17 01:59:09 -04:00
|
|
|
void
|
|
|
|
|
pc_reset(int hard)
|
|
|
|
|
{
|
|
|
|
|
plat_pause(1);
|
|
|
|
|
|
|
|
|
|
plat_delay_ms(100);
|
|
|
|
|
|
|
|
|
|
nvr_save();
|
|
|
|
|
|
|
|
|
|
config_save();
|
|
|
|
|
|
|
|
|
|
if (hard)
|
|
|
|
|
pc_reset_hard();
|
|
|
|
|
else
|
|
|
|
|
pc_send_cad();
|
|
|
|
|
|
|
|
|
|
plat_pause(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2017-10-02 02:15:35 -04:00
|
|
|
void
|
2017-10-19 04:27:04 -04:00
|
|
|
pc_close(thread_t *ptr)
|
2017-10-02 02:15:35 -04:00
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
2017-10-19 04:27:04 -04:00
|
|
|
/* Wait a while so things can shut down. */
|
|
|
|
|
plat_delay_ms(200);
|
|
|
|
|
|
|
|
|
|
/* Claim the video blitter. */
|
|
|
|
|
startblit();
|
|
|
|
|
|
|
|
|
|
/* Terminate the main thread. */
|
|
|
|
|
if (ptr != NULL) {
|
|
|
|
|
thread_kill(ptr);
|
|
|
|
|
|
|
|
|
|
/* Wait some more. */
|
|
|
|
|
plat_delay_ms(200);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nvr_save();
|
|
|
|
|
|
|
|
|
|
config_save();
|
|
|
|
|
|
2017-10-25 05:30:06 -04:00
|
|
|
plat_mouse_capture(0);
|
2017-10-19 04:27:04 -04:00
|
|
|
|
2018-02-06 19:53:34 +01:00
|
|
|
lpt_devices_close();
|
|
|
|
|
|
2017-10-02 02:15:35 -04:00
|
|
|
for (i=0; i<FDD_NUM; i++)
|
2018-01-17 18:43:36 +01:00
|
|
|
fdd_close(i);
|
2017-10-02 02:15:35 -04:00
|
|
|
|
2017-10-29 04:20:20 -05:00
|
|
|
if (dump_on_exit)
|
|
|
|
|
dumppic();
|
2017-10-02 02:15:35 -04:00
|
|
|
dumpregs(0);
|
|
|
|
|
|
|
|
|
|
video_close();
|
|
|
|
|
|
|
|
|
|
device_close_all();
|
2018-10-30 13:32:25 +01:00
|
|
|
|
|
|
|
|
scsi_device_close_all();
|
2017-10-02 02:15:35 -04:00
|
|
|
|
|
|
|
|
midi_close();
|
|
|
|
|
|
|
|
|
|
network_close();
|
2017-12-05 20:19:19 +01:00
|
|
|
|
|
|
|
|
sound_cd_thread_end();
|
2018-10-10 22:33:24 +02:00
|
|
|
|
2018-04-25 23:51:13 +02:00
|
|
|
cdrom_close();
|
2018-03-15 22:57:24 +01:00
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
zip_close();
|
|
|
|
|
|
|
|
|
|
scsi_disk_close();
|
2017-10-02 02:15:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2017-10-19 04:27:04 -04: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.
|
2017-10-02 02:15:35 -04:00
|
|
|
*/
|
2017-10-19 04:27:04 -04:00
|
|
|
void
|
|
|
|
|
pc_thread(void *param)
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2017-10-19 04:27:04 -04:00
|
|
|
wchar_t temp[200], wcpu[2048];
|
|
|
|
|
wchar_t wmachine[2048];
|
|
|
|
|
uint64_t start_time, end_time;
|
|
|
|
|
uint32_t old_time, new_time;
|
|
|
|
|
int done, drawits, frames;
|
|
|
|
|
int *quitp = (int *)param;
|
|
|
|
|
int framecountx;
|
|
|
|
|
|
2018-05-21 19:04:05 +02:00
|
|
|
pc_log("PC: starting main thread...\n");
|
2017-10-19 04:27:04 -04:00
|
|
|
|
|
|
|
|
main_time = 0;
|
|
|
|
|
framecountx = 0;
|
2018-04-26 13:33:29 +02:00
|
|
|
title_update = 1;
|
2017-10-19 04:27:04 -04:00
|
|
|
old_time = plat_get_ticks();
|
|
|
|
|
done = drawits = frames = 0;
|
|
|
|
|
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. */
|
|
|
|
|
startblit();
|
2018-03-02 20:47:18 +01:00
|
|
|
clockrate = machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed;
|
2017-10-19 04:27:04 -04:00
|
|
|
|
|
|
|
|
if (is386) {
|
|
|
|
|
#ifdef USE_DYNAREC
|
|
|
|
|
if (cpu_use_dynarec)
|
|
|
|
|
exec386_dynarec(clockrate/100);
|
|
|
|
|
else
|
|
|
|
|
#endif
|
|
|
|
|
exec386(clockrate/100);
|
2018-07-15 01:41:53 +02:00
|
|
|
} else if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type >= CPU_286) {
|
2017-10-19 04:27:04 -04:00
|
|
|
exec386(clockrate/100);
|
|
|
|
|
} else {
|
|
|
|
|
execx86(clockrate/100);
|
|
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2017-10-19 04:27:04 -04:00
|
|
|
mouse_process();
|
2017-10-02 02:15:35 -04:00
|
|
|
|
2017-10-19 04:27:04 -04:00
|
|
|
joystick_process();
|
2017-10-02 02:15:35 -04:00
|
|
|
|
2017-10-19 04:27:04 -04:00
|
|
|
endblit();
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2017-10-19 04:27:04 -04:00
|
|
|
/* Done with this frame, update statistics. */
|
|
|
|
|
framecount++;
|
|
|
|
|
if (++framecountx >= 100) {
|
|
|
|
|
framecountx = 0;
|
2017-10-02 02:15:35 -04:00
|
|
|
|
2017-10-19 04:27:04 -04:00
|
|
|
readlnum = writelnum = 0;
|
|
|
|
|
egareads = egawrites = 0;
|
|
|
|
|
mmuflush = 0;
|
|
|
|
|
frames = 0;
|
|
|
|
|
}
|
2017-10-02 02:15:35 -04:00
|
|
|
|
2017-10-19 04:27:04 -04:00
|
|
|
if (title_update) {
|
|
|
|
|
mbstowcs(wmachine, machine_getname(), strlen(machine_getname())+1);
|
2018-03-02 20:47:18 +01:00
|
|
|
mbstowcs(wcpu, machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].name,
|
|
|
|
|
strlen(machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].name)+1);
|
2017-10-19 04:27:04 -04:00
|
|
|
swprintf(temp, sizeof_w(temp),
|
|
|
|
|
L"%ls v%ls - %i%% - %ls - %ls - %ls",
|
|
|
|
|
EMU_NAME_W,EMU_VERSION_W,fps,wmachine,wcpu,
|
2017-10-23 05:20:18 -04:00
|
|
|
(!mouse_capture) ? plat_get_string(IDS_2077)
|
2017-12-10 02:08:37 -05:00
|
|
|
: (mouse_get_buttons() > 2) ? plat_get_string(IDS_2078) : plat_get_string(IDS_2079));
|
2017-10-02 02:15:35 -04:00
|
|
|
|
2017-10-19 04:27:04 -04:00
|
|
|
ui_window_title(temp);
|
2017-10-02 02:15:35 -04:00
|
|
|
|
2017-10-19 04:27:04 -04:00
|
|
|
title_update = 0;
|
|
|
|
|
}
|
2017-10-02 02:15:35 -04:00
|
|
|
|
2017-10-19 04:27:04 -04:00
|
|
|
/* One more frame done! */
|
|
|
|
|
done++;
|
|
|
|
|
|
|
|
|
|
/* Every 200 frames we save the machine status. */
|
|
|
|
|
if (++frames >= 200 && nvr_dosave) {
|
|
|
|
|
nvr_save();
|
|
|
|
|
nvr_dosave = 0;
|
|
|
|
|
frames = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
end_time = plat_timer_read();
|
|
|
|
|
main_time += (end_time - start_time);
|
|
|
|
|
} else {
|
|
|
|
|
/* Just so we dont overload the host OS. */
|
|
|
|
|
plat_delay_ms(1);
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-26 04:54:50 -04:00
|
|
|
/* If needed, handle a screen resize. */
|
|
|
|
|
if (doresize && !video_fullscreen) {
|
2017-10-19 04:27:04 -04:00
|
|
|
plat_resize(scrnsz_x, scrnsz_y);
|
2017-10-02 02:15:35 -04:00
|
|
|
|
2017-10-19 04:27:04 -04:00
|
|
|
doresize = 0;
|
|
|
|
|
}
|
2017-10-02 02:15:35 -04:00
|
|
|
}
|
|
|
|
|
|
2018-05-21 19:04:05 +02:00
|
|
|
pc_log("PC: main thread done.\n");
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
|
2017-10-02 02:15:35 -04:00
|
|
|
|
2017-10-19 04:27:04 -04:00
|
|
|
/* Handler for the 1-second timer to refresh the window title. */
|
2017-10-02 02:15:35 -04:00
|
|
|
void
|
2017-10-19 04:27:04 -04:00
|
|
|
pc_onesec(void)
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2017-10-02 02:15:35 -04:00
|
|
|
fps = framecount;
|
|
|
|
|
framecount = 0;
|
2017-10-19 04:27:04 -04:00
|
|
|
|
|
|
|
|
title_update = 1;
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
2017-12-04 11:59:26 -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;
|
|
|
|
|
|
|
|
|
|
/* Make sure we keep usable values. */
|
|
|
|
|
#if 0
|
2018-05-21 19:04:05 +02:00
|
|
|
pc_log("SetScreenSize(%d, %d) resize=%d\n", x, y, vid_resize);
|
2017-12-04 11:59:26 -05:00
|
|
|
#endif
|
|
|
|
|
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-02-24 17:25:50 +01:00
|
|
|
if (!(video_is_ega_vga()) && (temp_overscan_y == 16)) {
|
2017-12-04 11:59:26 -05:00
|
|
|
/* CGA */
|
|
|
|
|
dy = (((dx - dtx) / 4.0) * 3.0) + dty;
|
2018-02-24 17:25:50 +01:00
|
|
|
} else if (!(video_is_ega_vga()) && (temp_overscan_y < 16)) {
|
2017-12-04 11:59:26 -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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
get_actual_size_x(void)
|
|
|
|
|
{
|
|
|
|
|
return(unscaled_size_x);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
get_actual_size_y(void)
|
|
|
|
|
{
|
|
|
|
|
return(efscrnsz_y);
|
|
|
|
|
}
|