1361 lines
35 KiB
C
1361 lines
35 KiB
C
/*
|
|
* atari.c - main high-level routines
|
|
*
|
|
* Copyright (c) 1995-1998 David Firth
|
|
* Copyright (c) 1998-2008 Atari800 development team (see DOC/CREDITS)
|
|
*
|
|
* This file is part of the Atari800 emulator project which emulates
|
|
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
|
|
*
|
|
* Atari800 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.
|
|
*
|
|
* Atari800 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 Atari800; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include "afile.h"
|
|
#include "config.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#ifdef HAVE_SIGNAL_H
|
|
#include <signal.h>
|
|
#endif
|
|
#ifdef TIME_WITH_SYS_TIME
|
|
# include <sys/time.h>
|
|
# include <time.h>
|
|
#else
|
|
# ifdef HAVE_SYS_TIME_H
|
|
# include <sys/time.h>
|
|
# elif defined(HAVE_TIME_H)
|
|
# include <time.h>
|
|
# endif
|
|
#endif
|
|
#ifdef HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
#ifdef WIN32
|
|
#include <windows.h>
|
|
#endif
|
|
#ifdef __EMX__
|
|
#define INCL_DOS
|
|
#include <os2.h>
|
|
#endif
|
|
#ifdef __BEOS__
|
|
#include <OS.h>
|
|
#endif
|
|
#ifdef HAVE_LIBZ
|
|
#include <zlib.h>
|
|
#endif
|
|
#ifdef R_SERIAL
|
|
#include <sys/stat.h>
|
|
#endif
|
|
|
|
#include "akey.h"
|
|
#include "antic.h"
|
|
#include "atari.h"
|
|
#include "binload.h"
|
|
#include "cartridge.h"
|
|
#include "cassette.h"
|
|
#include "cfg.h"
|
|
#include "cpu.h"
|
|
#include "devices.h"
|
|
#include "esc.h"
|
|
#include "gtia.h"
|
|
#include "input.h"
|
|
#include "log.h"
|
|
#include "memory.h"
|
|
#include "monitor.h"
|
|
#include "pia.h"
|
|
#include "platform.h"
|
|
#include "pokey.h"
|
|
#include "rtime.h"
|
|
#include "pbi.h"
|
|
#include "sio.h"
|
|
#include "util.h"
|
|
#if !defined(BASIC) && !defined(CURSES_BASIC)
|
|
#include "colours.h"
|
|
#include "screen.h"
|
|
#endif
|
|
#ifndef BASIC
|
|
#include "statesav.h"
|
|
#ifndef __PLUS
|
|
#include "ui.h"
|
|
#endif
|
|
#endif /* BASIC */
|
|
#if defined(SOUND) && !defined(__PLUS)
|
|
#include "pokeysnd.h"
|
|
#include "sndsave.h"
|
|
#include "sound.h"
|
|
#endif
|
|
#ifdef R_IO_DEVICE
|
|
#include "rdevice.h"
|
|
#endif
|
|
#ifdef __PLUS
|
|
#ifdef _WX_
|
|
#include "export.h"
|
|
#else /* _WX_ */
|
|
#include "globals.h"
|
|
#include "macros.h"
|
|
#include "display_win.h"
|
|
#include "misc_win.h"
|
|
#include "registry.h"
|
|
#include "timing.h"
|
|
#include "FileService.h"
|
|
#include "Helpers.h"
|
|
#endif /* _WX_ */
|
|
#endif /* __PLUS */
|
|
#ifdef PBI_BB
|
|
#include "pbi_bb.h"
|
|
#endif
|
|
#ifdef PBI_XLD
|
|
#include "pbi_xld.h"
|
|
#endif
|
|
#ifdef XEP80_EMULATION
|
|
#include "xep80.h"
|
|
#endif
|
|
#ifdef NTSC_FILTER
|
|
#include "atari_ntsc.h"
|
|
#endif
|
|
|
|
int Atari800_machine_type = Atari800_MACHINE_XLXE;
|
|
int Atari800_tv_mode = Atari800_TV_PAL;
|
|
int Atari800_disable_basic = TRUE;
|
|
|
|
int verbose = FALSE;
|
|
|
|
int Atari800_display_screen = FALSE;
|
|
int Atari800_nframes = 0;
|
|
int Atari800_refresh_rate = 1;
|
|
int Atari800_collisions_in_skipped_frames = FALSE;
|
|
|
|
#ifdef BENCHMARK
|
|
static double benchmark_start_time;
|
|
static double Atari_time(void);
|
|
#endif
|
|
|
|
int emuos_mode = 1; /* 0 = never use EmuOS, 1 = use EmuOS if real OS not available, 2 = always use EmuOS */
|
|
|
|
#ifdef HAVE_SIGNAL
|
|
static RETSIGTYPE sigint_handler(int num)
|
|
{
|
|
int restart;
|
|
|
|
restart = Atari800_Exit(TRUE);
|
|
if (restart) {
|
|
signal(SIGINT, sigint_handler);
|
|
return;
|
|
}
|
|
|
|
exit(0);
|
|
}
|
|
#endif
|
|
|
|
void Atari800_Warmstart(void)
|
|
{
|
|
if (Atari800_machine_type == Atari800_MACHINE_OSA || Atari800_machine_type == Atari800_MACHINE_OSB) {
|
|
/* A real Axlon homebanks on reset */
|
|
/* XXX: what does Mosaic do? */
|
|
if (MEMORY_axlon_enabled) MEMORY_PutByte(0xcfff, 0);
|
|
/* RESET key in 400/800 does not reset chips,
|
|
but only generates RNMI interrupt */
|
|
ANTIC_NMIST = 0x3f;
|
|
CPU_NMI();
|
|
}
|
|
else {
|
|
PBI_Reset();
|
|
PIA_Reset();
|
|
ANTIC_Reset();
|
|
/* CPU_Reset() must be after PIA_Reset(),
|
|
because Reset routine vector must be read from OS ROM */
|
|
CPU_Reset();
|
|
/* note: POKEY and GTIA have no Reset pin */
|
|
}
|
|
#ifdef __PLUS
|
|
HandleResetEvent();
|
|
#endif
|
|
}
|
|
|
|
void Atari800_Coldstart(void)
|
|
{
|
|
PBI_Reset();
|
|
PIA_Reset();
|
|
ANTIC_Reset();
|
|
/* CPU_Reset() must be after PIA_Reset(),
|
|
because Reset routine vector must be read from OS ROM */
|
|
CPU_Reset();
|
|
/* note: POKEY and GTIA have no Reset pin */
|
|
#ifdef __PLUS
|
|
HandleResetEvent();
|
|
#endif
|
|
/* reset cartridge to power-up state */
|
|
CARTRIDGE_Start();
|
|
/* set Atari OS Coldstart flag */
|
|
MEMORY_dPutByte(0x244, 1);
|
|
/* handle Option key (disable BASIC in XL/XE)
|
|
and Start key (boot from cassette) */
|
|
GTIA_consol_index = 2;
|
|
GTIA_consol_table[2] = 0x0f;
|
|
if (Atari800_disable_basic && !BINLOAD_loading_basic) {
|
|
/* hold Option during reboot */
|
|
GTIA_consol_table[2] &= ~INPUT_CONSOL_OPTION;
|
|
}
|
|
if (CASSETTE_hold_start) {
|
|
/* hold Start during reboot */
|
|
GTIA_consol_table[2] &= ~INPUT_CONSOL_START;
|
|
}
|
|
GTIA_consol_table[1] = GTIA_consol_table[2];
|
|
}
|
|
|
|
int Atari800_LoadImage(const char *filename, UBYTE *buffer, int nbytes)
|
|
{
|
|
FILE *f;
|
|
int len;
|
|
|
|
f = fopen(filename, "rb");
|
|
if (f == NULL) {
|
|
Log_print("Error loading ROM image: %s", filename);
|
|
return FALSE;
|
|
}
|
|
len = fread(buffer, 1, nbytes, f);
|
|
fclose(f);
|
|
if (len != nbytes) {
|
|
Log_print("Error reading %s", filename);
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
#include "emuos.h"
|
|
|
|
#define COPY_EMUOS(padding) do { \
|
|
memset(MEMORY_os, 0, padding); \
|
|
memcpy(MEMORY_os + (padding), emuos_h, 0x2000); \
|
|
} while (0)
|
|
|
|
static int load_roms(void)
|
|
{
|
|
switch (Atari800_machine_type) {
|
|
case Atari800_MACHINE_OSA:
|
|
if (emuos_mode == 2)
|
|
COPY_EMUOS(0x0800);
|
|
else if (!Atari800_LoadImage(CFG_osa_filename, MEMORY_os, 0x2800)) {
|
|
if (emuos_mode == 1)
|
|
COPY_EMUOS(0x0800);
|
|
else
|
|
return FALSE;
|
|
}
|
|
else
|
|
MEMORY_have_basic = Atari800_LoadImage(CFG_basic_filename, MEMORY_basic, 0x2000);
|
|
break;
|
|
case Atari800_MACHINE_OSB:
|
|
if (emuos_mode == 2)
|
|
COPY_EMUOS(0x0800);
|
|
else if (!Atari800_LoadImage(CFG_osb_filename, MEMORY_os, 0x2800)) {
|
|
if (emuos_mode == 1)
|
|
COPY_EMUOS(0x0800);
|
|
else
|
|
return FALSE;
|
|
}
|
|
else
|
|
MEMORY_have_basic = Atari800_LoadImage(CFG_basic_filename, MEMORY_basic, 0x2000);
|
|
break;
|
|
case Atari800_MACHINE_XLXE:
|
|
if (emuos_mode == 2)
|
|
COPY_EMUOS(0x2000);
|
|
else if (!Atari800_LoadImage(CFG_xlxe_filename, MEMORY_os, 0x4000)) {
|
|
if (emuos_mode == 1)
|
|
COPY_EMUOS(0x2000);
|
|
else
|
|
return FALSE;
|
|
}
|
|
else {
|
|
/* if you really don't want built-in BASIC */
|
|
if (!strcmp(CFG_basic_filename,"none"))
|
|
memset(MEMORY_basic, 0, 0x2000);
|
|
else if (!Atari800_LoadImage(CFG_basic_filename, MEMORY_basic, 0x2000))
|
|
return FALSE;
|
|
}
|
|
MEMORY_xe_bank = 0;
|
|
break;
|
|
case Atari800_MACHINE_5200:
|
|
if (!Atari800_LoadImage(CFG_5200_filename, MEMORY_os, 0x800))
|
|
return FALSE;
|
|
break;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
int Atari800_InitialiseMachine(void)
|
|
{
|
|
#if !defined(BASIC) && !defined(CURSES_BASIC)
|
|
Colours_InitialiseMachine();
|
|
#endif
|
|
ESC_ClearAll();
|
|
if (!load_roms())
|
|
return FALSE;
|
|
MEMORY_InitialiseMachine();
|
|
Devices_UpdatePatches();
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
int Atari800_Initialise(int *argc, char *argv[])
|
|
{
|
|
int i, j;
|
|
const char *rom_filename = NULL;
|
|
const char *run_direct = NULL;
|
|
#ifndef BASIC
|
|
const char *state_file = NULL;
|
|
#endif
|
|
#ifdef __PLUS
|
|
/* Atari800Win PLus doesn't use configuration files,
|
|
it reads configuration from the Registry */
|
|
#ifndef _WX_
|
|
int bUpdateRegistry = (*argc > 1);
|
|
#endif
|
|
int bTapeFile = FALSE;
|
|
int nCartType = CARTRIDGE_type;
|
|
|
|
/* It is necessary because of the CARTRIDGE_Start (there must not be the
|
|
registry-read value available at startup) */
|
|
CARTRIDGE_type = CARTRIDGE_NONE;
|
|
|
|
#ifndef _WX_
|
|
/* Print the time info in the "Log file" window */
|
|
Misc_PrintTime();
|
|
|
|
/* Force screen refreshing */
|
|
g_nTestVal = _GetRefreshRate() - 1;
|
|
|
|
g_ulAtariState = ATARI_UNINITIALIZED;
|
|
#endif /* _WX_ */
|
|
|
|
#else /* __PLUS */
|
|
const char *rtconfig_filename = NULL;
|
|
int got_config;
|
|
int help_only = FALSE;
|
|
|
|
if (*argc > 1) {
|
|
for (i = j = 1; i < *argc; i++) {
|
|
if (strcmp(argv[i], "-config") == 0) {
|
|
if (i + 1 < *argc)
|
|
rtconfig_filename = argv[++i];
|
|
else {
|
|
Log_print("Missing argument for '%s'", argv[i]);
|
|
return FALSE;
|
|
}
|
|
}
|
|
else if (strcmp(argv[i], "-v") == 0 ||
|
|
strcmp(argv[i], "-version") == 0 ||
|
|
strcmp(argv[i], "--version") == 0) {
|
|
printf("%s\n", Atari800_TITLE);
|
|
return FALSE;
|
|
}
|
|
else if (strcmp(argv[i], "--usage") == 0 ||
|
|
strcmp(argv[i], "--help") == 0) {
|
|
argv[j++] = "-help";
|
|
}
|
|
else if (strcmp(argv[i], "-verbose") == 0) {
|
|
verbose = TRUE;
|
|
}
|
|
else {
|
|
argv[j++] = argv[i];
|
|
}
|
|
}
|
|
*argc = j;
|
|
}
|
|
got_config = CFG_LoadConfig(rtconfig_filename);
|
|
|
|
/* try to find ROM images if the configuration file is not found
|
|
or it does not specify some ROM paths (blank paths count as specified) */
|
|
CFG_FindROMImages("", TRUE); /* current directory */
|
|
#if defined(unix) || defined(__unix__) || defined(__linux__)
|
|
CFG_FindROMImages("/usr/share/atari800", TRUE);
|
|
#endif
|
|
if (*argc > 0 && argv[0] != NULL) {
|
|
char atari800_exe_dir[FILENAME_MAX];
|
|
char atari800_exe_rom_dir[FILENAME_MAX];
|
|
/* the directory of the Atari800 program */
|
|
Util_splitpath(argv[0], atari800_exe_dir, NULL);
|
|
CFG_FindROMImages(atari800_exe_dir, TRUE);
|
|
/* "rom" and "ROM" subdirectories of this directory */
|
|
Util_catpath(atari800_exe_rom_dir, atari800_exe_dir, "rom");
|
|
CFG_FindROMImages(atari800_exe_rom_dir, TRUE);
|
|
/* skip "ROM" on systems that are known to be case-insensitive */
|
|
#if !defined(DJGPP) && !defined(WIN32)
|
|
Util_catpath(atari800_exe_rom_dir, atari800_exe_dir, "ROM");
|
|
CFG_FindROMImages(atari800_exe_rom_dir, TRUE);
|
|
#endif
|
|
}
|
|
/* finally if nothing is found, set some defaults to make
|
|
the configuration file easier to edit */
|
|
if (Util_filenamenotset(CFG_osa_filename))
|
|
strcpy(CFG_osa_filename, "atariosa.rom");
|
|
if (Util_filenamenotset(CFG_osb_filename))
|
|
strcpy(CFG_osb_filename, "atariosb.rom");
|
|
if (Util_filenamenotset(CFG_xlxe_filename))
|
|
strcpy(CFG_xlxe_filename, "atarixl.rom");
|
|
if (Util_filenamenotset(CFG_5200_filename))
|
|
strcpy(CFG_5200_filename, "5200.rom");
|
|
if (Util_filenamenotset(CFG_basic_filename))
|
|
strcpy(CFG_basic_filename, "ataribas.rom");
|
|
|
|
/* if no configuration file read, try to save one with the defaults */
|
|
if (!got_config)
|
|
CFG_WriteConfig();
|
|
|
|
#endif /* __PLUS */
|
|
|
|
for (i = j = 1; i < *argc; i++) {
|
|
if (strcmp(argv[i], "-atari") == 0) {
|
|
if (Atari800_machine_type != Atari800_MACHINE_OSA) {
|
|
Atari800_machine_type = Atari800_MACHINE_OSB;
|
|
MEMORY_ram_size = 48;
|
|
}
|
|
}
|
|
else if (strcmp(argv[i], "-xl") == 0) {
|
|
Atari800_machine_type = Atari800_MACHINE_XLXE;
|
|
MEMORY_ram_size = 64;
|
|
}
|
|
else if (strcmp(argv[i], "-xe") == 0) {
|
|
Atari800_machine_type = Atari800_MACHINE_XLXE;
|
|
MEMORY_ram_size = 128;
|
|
}
|
|
else if (strcmp(argv[i], "-320xe") == 0) {
|
|
Atari800_machine_type = Atari800_MACHINE_XLXE;
|
|
MEMORY_ram_size = MEMORY_RAM_320_COMPY_SHOP;
|
|
}
|
|
else if (strcmp(argv[i], "-rambo") == 0) {
|
|
Atari800_machine_type = Atari800_MACHINE_XLXE;
|
|
MEMORY_ram_size = MEMORY_RAM_320_RAMBO;
|
|
}
|
|
else if (strcmp(argv[i], "-5200") == 0) {
|
|
Atari800_machine_type = Atari800_MACHINE_5200;
|
|
MEMORY_ram_size = 16;
|
|
}
|
|
else if (strcmp(argv[i], "-nobasic") == 0)
|
|
Atari800_disable_basic = TRUE;
|
|
else if (strcmp(argv[i], "-basic") == 0)
|
|
Atari800_disable_basic = FALSE;
|
|
else if (strcmp(argv[i], "-nopatch") == 0)
|
|
ESC_enable_sio_patch = FALSE;
|
|
else if (strcmp(argv[i], "-nopatchall") == 0)
|
|
ESC_enable_sio_patch = Devices_enable_h_patch = Devices_enable_p_patch = Devices_enable_r_patch = FALSE;
|
|
else if (strcmp(argv[i], "-pal") == 0)
|
|
Atari800_tv_mode = Atari800_TV_PAL;
|
|
else if (strcmp(argv[i], "-ntsc") == 0)
|
|
Atari800_tv_mode = Atari800_TV_NTSC;
|
|
else if (strcmp(argv[i], "-a") == 0) {
|
|
Atari800_machine_type = Atari800_MACHINE_OSA;
|
|
MEMORY_ram_size = 48;
|
|
}
|
|
else if (strcmp(argv[i], "-b") == 0) {
|
|
Atari800_machine_type = Atari800_MACHINE_OSB;
|
|
MEMORY_ram_size = 48;
|
|
}
|
|
else if (strcmp(argv[i], "-emuos") == 0)
|
|
emuos_mode = 2;
|
|
else if (strcmp(argv[i], "-c") == 0) {
|
|
if (MEMORY_ram_size == 48)
|
|
MEMORY_ram_size = 52;
|
|
}
|
|
else if (strcmp(argv[i], "-axlon0f") == 0) {
|
|
MEMORY_axlon_0f_mirror = TRUE;
|
|
}
|
|
#ifdef STEREO_SOUND
|
|
else if (strcmp(argv[i], "-stereo") == 0) {
|
|
POKEYSND_stereo_enabled = TRUE;
|
|
}
|
|
else if (strcmp(argv[i], "-nostereo") == 0) {
|
|
POKEYSND_stereo_enabled = FALSE;
|
|
}
|
|
#endif /* STEREO_SOUND */
|
|
else {
|
|
/* parameters that take additional argument follow here */
|
|
int i_a = (i + 1 < *argc); /* is argument available? */
|
|
int a_m = FALSE; /* error, argument missing! */
|
|
|
|
if (strcmp(argv[i], "-osa_rom") == 0) {
|
|
if (i_a) Util_strlcpy(CFG_osa_filename, argv[++i], sizeof(CFG_osa_filename)); else a_m = TRUE;
|
|
}
|
|
#ifdef R_IO_DEVICE
|
|
else if (strcmp(argv[i], "-rdevice") == 0) {
|
|
Devices_enable_r_patch = TRUE;
|
|
#ifdef R_SERIAL
|
|
if (i_a && i + 2 < *argc && *argv[i + 1] != '-') { /* optional serial device name */
|
|
struct stat statbuf;
|
|
if (! stat(argv[i + 1], &statbuf)) {
|
|
if (S_ISCHR(statbuf.st_mode)) { /* only accept devices as serial device */
|
|
Util_strlcpy(RDevice_serial_device, argv[++i], FILENAME_MAX);
|
|
RDevice_serial_enabled = TRUE;
|
|
}
|
|
}
|
|
}
|
|
#endif /* R_SERIAL */
|
|
}
|
|
#endif
|
|
else if (strcmp(argv[i], "-osb_rom") == 0) {
|
|
if (i_a) Util_strlcpy(CFG_osb_filename, argv[++i], sizeof(CFG_osb_filename)); else a_m = TRUE;
|
|
}
|
|
else if (strcmp(argv[i], "-xlxe_rom") == 0) {
|
|
if (i_a) Util_strlcpy(CFG_xlxe_filename, argv[++i], sizeof(CFG_xlxe_filename)); else a_m = TRUE;
|
|
}
|
|
else if (strcmp(argv[i], "-5200_rom") == 0) {
|
|
if (i_a) Util_strlcpy(CFG_5200_filename, argv[++i], sizeof(CFG_5200_filename)); else a_m = TRUE;
|
|
}
|
|
else if (strcmp(argv[i], "-basic_rom") == 0) {
|
|
if (i_a) Util_strlcpy(CFG_basic_filename, argv[++i], sizeof(CFG_basic_filename)); else a_m = TRUE;
|
|
}
|
|
else if (strcmp(argv[i], "-cart") == 0) {
|
|
if (i_a) rom_filename = argv[++i]; else a_m = TRUE;
|
|
}
|
|
else if (strcmp(argv[i], "-run") == 0) {
|
|
if (i_a) run_direct = argv[++i]; else a_m = TRUE;
|
|
}
|
|
else if (strcmp(argv[i], "-mosaic") == 0) {
|
|
if (i_a) {
|
|
int total_ram = Util_sscandec(argv[++i]);
|
|
MEMORY_mosaic_enabled = TRUE;
|
|
MEMORY_mosaic_maxbank = (total_ram - 48)/4 - 1;
|
|
if (((total_ram - 48) % 4 != 0) || (MEMORY_mosaic_maxbank > 0x3e) || (MEMORY_mosaic_maxbank < 0)) {
|
|
Log_print("Invalid Mosaic total RAM size");
|
|
return FALSE;
|
|
}
|
|
if (MEMORY_axlon_enabled) {
|
|
Log_print("Axlon and Mosaic can not both be enabled, because they are incompatible");
|
|
return FALSE;
|
|
}
|
|
}
|
|
else a_m = TRUE;
|
|
}
|
|
else if (strcmp(argv[i], "-axlon") == 0) {
|
|
if (i_a) {
|
|
int total_ram = Util_sscandec(argv[++i]);
|
|
int banks = ((total_ram) - 32) / 16;
|
|
MEMORY_axlon_enabled = TRUE;
|
|
if (((total_ram - 32) % 16 != 0) || ((banks != 8) && (banks != 16) && (banks != 32) && (banks != 64) && (banks != 128) && (banks != 256))) {
|
|
Log_print("Invalid Axlon total RAM size");
|
|
return FALSE;
|
|
}
|
|
if (MEMORY_mosaic_enabled) {
|
|
Log_print("Axlon and Mosaic can not both be enabled, because they are incompatible");
|
|
return FALSE;
|
|
}
|
|
MEMORY_axlon_bankmask = banks - 1;
|
|
}
|
|
else a_m = TRUE;
|
|
}
|
|
#ifndef BASIC
|
|
/* The BASIC version does not support state files, because:
|
|
1. It has no ability to save state files, because of lack of UI.
|
|
2. It uses a simplified emulation, so the state files would be
|
|
incompatible with other versions.
|
|
3. statesav is not compiled in to make the executable smaller. */
|
|
else if (strcmp(argv[i], "-state") == 0) {
|
|
if (i_a) state_file = argv[++i]; else a_m = TRUE;
|
|
}
|
|
else if (strcmp(argv[i], "-refresh") == 0) {
|
|
if (i_a) {
|
|
Atari800_refresh_rate = Util_sscandec(argv[++i]);
|
|
if (Atari800_refresh_rate < 1) {
|
|
Log_print("Invalid refresh rate, using 1");
|
|
Atari800_refresh_rate = 1;
|
|
}
|
|
}
|
|
else
|
|
a_m = TRUE;
|
|
}
|
|
#endif /* BASIC */
|
|
else {
|
|
/* all options known to main module tried but none matched */
|
|
|
|
if (strcmp(argv[i], "-help") == 0) {
|
|
#ifndef __PLUS
|
|
help_only = TRUE;
|
|
Log_print("\t-config <file> Specify Alternate Configuration File");
|
|
#endif
|
|
Log_print("\t-atari Emulate Atari 800");
|
|
Log_print("\t-xl Emulate Atari 800XL");
|
|
Log_print("\t-xe Emulate Atari 130XE");
|
|
Log_print("\t-320xe Emulate Atari 320XE (COMPY SHOP)");
|
|
Log_print("\t-rambo Emulate Atari 320XE (RAMBO)");
|
|
Log_print("\t-5200 Emulate Atari 5200 Games System");
|
|
Log_print("\t-nobasic Turn off Atari BASIC ROM");
|
|
Log_print("\t-basic Turn on Atari BASIC ROM");
|
|
Log_print("\t-pal Enable PAL TV mode");
|
|
Log_print("\t-ntsc Enable NTSC TV mode");
|
|
Log_print("\t-osa_rom <file> Load OS A ROM from file");
|
|
Log_print("\t-osb_rom <file> Load OS B ROM from file");
|
|
Log_print("\t-xlxe_rom <file> Load XL/XE ROM from file");
|
|
Log_print("\t-5200_rom <file> Load 5200 ROM from file");
|
|
Log_print("\t-basic_rom <fil> Load BASIC ROM from file");
|
|
Log_print("\t-cart <file> Install cartridge (raw or CART format)");
|
|
Log_print("\t-run <file> Run Atari program (COM, EXE, XEX, BAS, LST)");
|
|
#ifndef BASIC
|
|
Log_print("\t-state <file> Load saved-state file");
|
|
Log_print("\t-refresh <rate> Specify screen refresh rate");
|
|
#endif
|
|
Log_print("\t-nopatch Don't patch SIO routine in OS");
|
|
Log_print("\t-nopatchall Don't patch OS at all, H: device won't work");
|
|
Log_print("\t-a Use OS A");
|
|
Log_print("\t-b Use OS B");
|
|
Log_print("\t-c Enable RAM between 0xc000 and 0xcfff in Atari 800");
|
|
Log_print("\t-axlon <n> Use Atari 800 Axlon memory expansion: <n> k total RAM");
|
|
Log_print("\t-axlon0f Use Axlon shadow at 0x0fc0-0x0fff");
|
|
Log_print("\t-mosaic <n> Use 400/800 Mosaic memory expansion: <n> k total RAM");
|
|
#ifdef R_IO_DEVICE
|
|
Log_print("\t-rdevice [<dev>] Enable R: emulation (using serial device <dev>)");
|
|
#endif
|
|
Log_print("\t-v Show version/release number");
|
|
}
|
|
|
|
/* copy this option for platform/module specific evaluation */
|
|
argv[j++] = argv[i];
|
|
}
|
|
|
|
/* this is the end of the additional argument check */
|
|
if (a_m) {
|
|
printf("Missing argument for '%s'\n", argv[i]);
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
*argc = j;
|
|
if (
|
|
#if !defined(BASIC) && !defined(CURSES_BASIC)
|
|
!Colours_Initialise(argc, argv) ||
|
|
#endif
|
|
!Devices_Initialise(argc, argv)
|
|
|| !RTIME_Initialise(argc, argv)
|
|
|| !SIO_Initialise (argc, argv)
|
|
|| !CASSETTE_Initialise(argc, argv)
|
|
|| !PBI_Initialise(argc,argv)
|
|
#ifndef BASIC
|
|
|| !INPUT_Initialise(argc, argv)
|
|
#endif
|
|
#ifdef XEP80_EMULATION
|
|
|| !XEP80_Initialise(argc, argv)
|
|
#endif
|
|
#ifdef NTSC_FILTER
|
|
|| !atari_ntsc_Initialise(argc, argv)
|
|
#endif
|
|
#ifndef DONT_DISPLAY
|
|
/* Platform Specific Initialisation */
|
|
|| !PLATFORM_Initialise(argc, argv)
|
|
#endif
|
|
#if !defined(BASIC) && !defined(CURSES_BASIC)
|
|
|| !Screen_Initialise(argc, argv)
|
|
#endif
|
|
/* Initialise Custom Chips */
|
|
|| !ANTIC_Initialise(argc, argv)
|
|
|| !GTIA_Initialise(argc, argv)
|
|
|| !PIA_Initialise(argc, argv)
|
|
|| !POKEY_Initialise(argc, argv)
|
|
)
|
|
return FALSE;
|
|
|
|
#ifndef __PLUS
|
|
|
|
if (help_only) {
|
|
Atari800_Exit(FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Configure Atari System */
|
|
Atari800_InitialiseMachine();
|
|
#else /* __PLUS */
|
|
|
|
if (!InitialiseMachine()) {
|
|
#ifndef _WX_
|
|
if (bUpdateRegistry)
|
|
WriteAtari800Registry();
|
|
#endif
|
|
return FALSE;
|
|
}
|
|
|
|
#endif /* __PLUS */
|
|
|
|
/* Auto-start files left on the command line */
|
|
j = 1; /* diskno */
|
|
for (i = 1; i < *argc; i++) {
|
|
if (j > 8) {
|
|
/* The remaining arguments are not necessary disk images, but ignore them... */
|
|
Log_print("Too many disk image filenames on the command line (max. 8).");
|
|
break;
|
|
}
|
|
switch (AFILE_OpenFile(argv[i], i == 1, j, FALSE)) {
|
|
case AFILE_ERROR:
|
|
Log_print("Error opening \"%s\"", argv[i]);
|
|
break;
|
|
case AFILE_ATR:
|
|
case AFILE_XFD:
|
|
case AFILE_ATR_GZ:
|
|
case AFILE_XFD_GZ:
|
|
case AFILE_DCM:
|
|
case AFILE_PRO:
|
|
j++;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Install requested ROM cartridge */
|
|
if (rom_filename) {
|
|
int r = CARTRIDGE_Insert(rom_filename);
|
|
if (r < 0) {
|
|
Log_print("Error inserting cartridge \"%s\": %s", rom_filename,
|
|
r == CARTRIDGE_CANT_OPEN ? "Can't open file" :
|
|
r == CARTRIDGE_BAD_FORMAT ? "Bad format" :
|
|
r == CARTRIDGE_BAD_CHECKSUM ? "Bad checksum" :
|
|
"Unknown error");
|
|
}
|
|
if (r > 0) {
|
|
#ifdef BASIC
|
|
Log_print("Raw cartridge images not supported in BASIC version!");
|
|
#else /* BASIC */
|
|
|
|
#ifndef __PLUS
|
|
UI_is_active = TRUE;
|
|
CARTRIDGE_type = UI_SelectCartType(r);
|
|
UI_is_active = FALSE;
|
|
#else /* __PLUS */
|
|
CARTRIDGE_type = (CARTRIDGE_NONE == nCartType ? UI_SelectCartType(r) : nCartType);
|
|
#endif /* __PLUS */
|
|
CARTRIDGE_Start();
|
|
|
|
#endif /* BASIC */
|
|
}
|
|
#ifndef __PLUS
|
|
if (CARTRIDGE_type != CARTRIDGE_NONE) {
|
|
int for5200 = CARTRIDGE_IsFor5200(CARTRIDGE_type);
|
|
if (for5200 && Atari800_machine_type != Atari800_MACHINE_5200) {
|
|
Atari800_machine_type = Atari800_MACHINE_5200;
|
|
MEMORY_ram_size = 16;
|
|
Atari800_InitialiseMachine();
|
|
}
|
|
else if (!for5200 && Atari800_machine_type == Atari800_MACHINE_5200) {
|
|
Atari800_machine_type = Atari800_MACHINE_XLXE;
|
|
MEMORY_ram_size = 64;
|
|
Atari800_InitialiseMachine();
|
|
}
|
|
}
|
|
#endif /* __PLUS */
|
|
}
|
|
|
|
/* Load Atari executable, if any */
|
|
if (run_direct != NULL)
|
|
BINLOAD_Loader(run_direct);
|
|
|
|
#ifndef BASIC
|
|
/* Load state file */
|
|
if (state_file != NULL) {
|
|
if (StateSav_ReadAtariState(state_file, "rb"))
|
|
/* Don't press Option */
|
|
GTIA_consol_table[1] = GTIA_consol_table[2] = 0x0f;
|
|
}
|
|
#endif
|
|
|
|
#ifdef HAVE_SIGNAL
|
|
/* Install CTRL-C Handler */
|
|
signal(SIGINT, sigint_handler);
|
|
#endif
|
|
|
|
#ifdef __PLUS
|
|
#ifndef _WX_
|
|
/* Update the Registry if any parameters were specified */
|
|
if (bUpdateRegistry)
|
|
WriteAtari800Registry();
|
|
Timer_Start(FALSE);
|
|
#endif /* _WX_ */
|
|
g_ulAtariState &= ~ATARI_UNINITIALIZED;
|
|
#endif /* __PLUS */
|
|
|
|
#ifdef BENCHMARK
|
|
benchmark_start_time = Atari_time();
|
|
#endif
|
|
return TRUE;
|
|
}
|
|
|
|
UNALIGNED_STAT_DEF(Screen_atari_write_long_stat)
|
|
UNALIGNED_STAT_DEF(pm_scanline_read_long_stat)
|
|
UNALIGNED_STAT_DEF(memory_read_word_stat)
|
|
UNALIGNED_STAT_DEF(memory_write_word_stat)
|
|
UNALIGNED_STAT_DEF(memory_read_aligned_word_stat)
|
|
UNALIGNED_STAT_DEF(memory_write_aligned_word_stat)
|
|
|
|
int Atari800_Exit(int run_monitor)
|
|
{
|
|
int restart;
|
|
|
|
#ifdef __PLUS
|
|
if (CPU_cim_encountered)
|
|
g_ulAtariState |= ATARI_CRASHED;
|
|
#endif
|
|
|
|
#ifdef STAT_UNALIGNED_WORDS
|
|
printf("(ptr&7) Screen_atari pm_scanline _____ memory ______ memory (aligned addr)\n");
|
|
printf(" 32-bit W 32-bit R 16-bit R 16-bit W 16-bit R 16-bit W\n");
|
|
{
|
|
unsigned int sums[6] = {0, 0, 0, 0, 0, 0};
|
|
int i;
|
|
for (i = 0; i < 8; i++) {
|
|
printf("%6d%12u%14u%11u%11u%11u%11u\n", i,
|
|
Screen_atari_write_long_stat[i], pm_scanline_read_long_stat[i],
|
|
memory_read_word_stat[i], memory_write_word_stat[i],
|
|
memory_read_aligned_word_stat[i], memory_write_aligned_word_stat[i]);
|
|
sums[0] += Screen_atari_write_long_stat[i];
|
|
sums[1] += pm_scanline_read_long_stat[i];
|
|
sums[2] += memory_read_word_stat[i];
|
|
sums[3] += memory_write_word_stat[i];
|
|
sums[4] += memory_read_aligned_word_stat[i];
|
|
sums[5] += memory_write_aligned_word_stat[i];
|
|
}
|
|
printf("total:%12u%14u%11u%11u%11u%11u\n",
|
|
sums[0], sums[1], sums[2], sums[3], sums[4], sums[5]);
|
|
}
|
|
#endif /* STAT_UNALIGNED_WORDS */
|
|
restart = PLATFORM_Exit(run_monitor);
|
|
#ifndef __PLUS
|
|
if (!restart) {
|
|
SIO_Exit(); /* umount disks, so temporary files are deleted */
|
|
#ifndef BASIC
|
|
INPUT_Exit(); /* finish event recording */
|
|
#endif
|
|
#ifdef R_IO_DEVICE
|
|
RDevice_Exit(); /* R: Device cleanup */
|
|
#endif
|
|
#ifdef SOUND
|
|
SndSave_CloseSoundFile();
|
|
#endif
|
|
}
|
|
#endif /* __PLUS */
|
|
return restart;
|
|
}
|
|
|
|
#ifndef __PLUS
|
|
|
|
#ifdef PS2
|
|
|
|
double Atari_time(void);
|
|
void Atari_sleep(double s);
|
|
|
|
#else /* PS2 */
|
|
|
|
static double Atari_time(void)
|
|
{
|
|
#ifdef WIN32
|
|
return GetTickCount() * 1e-3;
|
|
#elif defined(DJGPP)
|
|
/* DJGPP has gettimeofday, but it's not more accurate than uclock */
|
|
return uclock() * (1.0 / UCLOCKS_PER_SEC);
|
|
#elif defined(HAVE_GETTIMEOFDAY)
|
|
struct timeval tp;
|
|
gettimeofday(&tp, NULL);
|
|
return tp.tv_sec + 1e-6 * tp.tv_usec;
|
|
#elif defined(HAVE_UCLOCK)
|
|
return uclock() * (1.0 / UCLOCKS_PER_SEC);
|
|
#elif defined(HAVE_CLOCK)
|
|
return clock() * (1.0 / CLK_TCK);
|
|
#else
|
|
#error No function found for Atari_time()
|
|
#endif
|
|
}
|
|
|
|
/* FIXME: Ports should use SUPPORTS_PLATFORM_SLEEP and SUPPORTS_PLATFORM_TIME */
|
|
/* and not this mess */
|
|
#ifndef SUPPORTS_PLATFORM_SLEEP
|
|
|
|
static void Atari_sleep(double s)
|
|
{
|
|
if (s > 0) {
|
|
#ifdef WIN32
|
|
Sleep((DWORD) (s * 1e3));
|
|
#elif defined(DJGPP)
|
|
/* DJGPP has usleep and select, but they don't work that good */
|
|
/* XXX: find out why */
|
|
double curtime = Atari_time();
|
|
while ((curtime + s) > Atari_time());
|
|
#elif defined(HAVE_NANOSLEEP)
|
|
struct timespec ts;
|
|
ts.tv_sec = 0;
|
|
ts.tv_nsec = s * 1e9;
|
|
nanosleep(&ts, NULL);
|
|
#elif defined(HAVE_USLEEP)
|
|
usleep(s * 1e6);
|
|
#elif defined(__BEOS__)
|
|
/* added by Walter Las for BeOS */
|
|
snooze(s * 1e6);
|
|
#elif defined(__EMX__)
|
|
/* added by Brian Smith for os/2 */
|
|
DosSleep(s);
|
|
#elif defined(HAVE_SELECT)
|
|
/* linux */
|
|
struct timeval tp;
|
|
tp.tv_sec = 0;
|
|
tp.tv_usec = s * 1e6;
|
|
select(1, NULL, NULL, NULL, &tp);
|
|
#else
|
|
double curtime = Atari_time();
|
|
while ((curtime + s) > Atari_time());
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#endif /* SUPPORTS_PLATFORM_SLEEP */
|
|
|
|
#endif /* PS2 */
|
|
|
|
void Atari800_Sync(void)
|
|
{
|
|
static double lasttime = 0;
|
|
double deltatime = 1.0 / ((Atari800_tv_mode == Atari800_TV_PAL) ? 50 : 60);
|
|
double curtime;
|
|
#ifdef ALTERNATE_SYNC_WITH_HOST
|
|
if (! UI_is_active)
|
|
deltatime *= Atari800_refresh_rate;
|
|
#endif
|
|
lasttime += deltatime;
|
|
#ifdef SUPPORTS_PLATFORM_SLEEP
|
|
PLATFORM_Sleep(lasttime - Atari_time());
|
|
#else
|
|
Atari_sleep(lasttime - Atari_time());
|
|
#endif
|
|
curtime = Atari_time();
|
|
|
|
if ((lasttime + deltatime) < curtime)
|
|
lasttime = curtime;
|
|
}
|
|
|
|
#ifdef USE_CURSES
|
|
void curses_clear_screen(void);
|
|
#endif
|
|
|
|
#if defined(BASIC) || defined(VERY_SLOW) || defined(CURSES_BASIC)
|
|
|
|
#ifdef CURSES_BASIC
|
|
void curses_display_line(int anticmode, const UBYTE *screendata);
|
|
#endif
|
|
|
|
static int scanlines_to_dl;
|
|
|
|
/* steal cycles and generate DLI */
|
|
static void basic_antic_scanline(void)
|
|
{
|
|
static UBYTE IR = 0;
|
|
static const UBYTE mode_scanlines[16] =
|
|
{ 0, 0, 8, 10, 8, 16, 8, 16, 8, 4, 4, 2, 1, 2, 1, 1 };
|
|
static const UBYTE mode_bytes[16] =
|
|
{ 0, 0, 40, 40, 40, 40, 20, 20, 10, 10, 20, 20, 20, 40, 40, 40 };
|
|
static const UBYTE font40_cycles[4] = { 0, 32, 40, 47 };
|
|
static const UBYTE font20_cycles[4] = { 0, 16, 20, 24 };
|
|
#ifdef CURSES_BASIC
|
|
static int scanlines_to_curses_display = 0;
|
|
static UWORD screenaddr = 0;
|
|
static UWORD newscreenaddr = 0;
|
|
#endif
|
|
|
|
int bytes = 0;
|
|
if (--scanlines_to_dl <= 0) {
|
|
if (ANTIC_DMACTL & 0x20) {
|
|
IR = ANTIC_GetDLByte(&ANTIC_dlist);
|
|
ANTIC_xpos++;
|
|
}
|
|
else
|
|
IR &= 0x7f; /* repeat last instruction, but don't generate DLI */
|
|
switch (IR & 0xf) {
|
|
case 0:
|
|
scanlines_to_dl = ((IR >> 4) & 7) + 1;
|
|
break;
|
|
case 1:
|
|
if (ANTIC_DMACTL & 0x20) {
|
|
ANTIC_dlist = ANTIC_GetDLWord(&ANTIC_dlist);
|
|
ANTIC_xpos += 2;
|
|
}
|
|
scanlines_to_dl = (IR & 0x40) ? 1024 /* no more DL in this frame */ : 1;
|
|
break;
|
|
default:
|
|
if (IR & 0x40 && ANTIC_DMACTL & 0x20) {
|
|
#ifdef CURSES_BASIC
|
|
screenaddr =
|
|
#endif
|
|
ANTIC_GetDLWord(&ANTIC_dlist);
|
|
ANTIC_xpos += 2;
|
|
}
|
|
/* can't steal cycles now, because DLI must come first */
|
|
/* just an approximation: doesn't check HSCROL */
|
|
switch (ANTIC_DMACTL & 3) {
|
|
case 1:
|
|
bytes = mode_bytes[IR & 0xf] * 8 / 10;
|
|
break;
|
|
case 2:
|
|
bytes = mode_bytes[IR & 0xf];
|
|
break;
|
|
case 3:
|
|
bytes = mode_bytes[IR & 0xf] * 12 / 10;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
#ifdef CURSES_BASIC
|
|
/* Normally, we would call curses_display_line here,
|
|
and not use scanlines_to_curses_display at all.
|
|
That would however cause incorrect color of the "MEMORY"
|
|
menu item in Self Test - it isn't set properly
|
|
in the first scanline. We therefore postpone
|
|
curses_display_line call to the next scanline. */
|
|
scanlines_to_curses_display = 2;
|
|
newscreenaddr = screenaddr + bytes;
|
|
#endif
|
|
/* just an approximation: doesn't check VSCROL */
|
|
scanlines_to_dl = mode_scanlines[IR & 0xf];
|
|
break;
|
|
}
|
|
}
|
|
if (scanlines_to_dl == 1 && (IR & 0x80)) {
|
|
CPU_GO(ANTIC_NMIST_C);
|
|
ANTIC_NMIST = 0x9f;
|
|
if (ANTIC_NMIEN & 0x80) {
|
|
CPU_GO(ANTIC_NMI_C);
|
|
CPU_NMI();
|
|
}
|
|
}
|
|
#ifdef CURSES_BASIC
|
|
if (--scanlines_to_curses_display == 0) {
|
|
curses_display_line(IR & 0xf, MEMORY_mem + screenaddr);
|
|
/* 4k wrap */
|
|
if (((screenaddr ^ newscreenaddr) & 0x1000) != 0)
|
|
screenaddr = newscreenaddr - 0x1000;
|
|
else
|
|
screenaddr = newscreenaddr;
|
|
}
|
|
#endif
|
|
ANTIC_xpos += bytes;
|
|
/* steal cycles in font modes */
|
|
switch (IR & 0xf) {
|
|
case 2:
|
|
case 3:
|
|
case 4:
|
|
case 5:
|
|
ANTIC_xpos += font40_cycles[ANTIC_DMACTL & 3];
|
|
break;
|
|
case 6:
|
|
case 7:
|
|
ANTIC_xpos += font20_cycles[ANTIC_DMACTL & 3];
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
#define BASIC_LINE CPU_GO(ANTIC_LINE_C); ANTIC_xpos -= ANTIC_LINE_C - ANTIC_DMAR; ANTIC_screenline_cpu_clock += ANTIC_LINE_C; ANTIC_ypos++
|
|
|
|
static void basic_frame(void)
|
|
{
|
|
/* scanlines 0 - 7 */
|
|
ANTIC_ypos = 0;
|
|
do {
|
|
POKEY_Scanline(); /* check and generate IRQ */
|
|
BASIC_LINE;
|
|
} while (ANTIC_ypos < 8);
|
|
|
|
scanlines_to_dl = 1;
|
|
/* scanlines 8 - 247 */
|
|
do {
|
|
POKEY_Scanline(); /* check and generate IRQ */
|
|
basic_antic_scanline();
|
|
BASIC_LINE;
|
|
} while (ANTIC_ypos < 248);
|
|
|
|
/* scanline 248 */
|
|
POKEY_Scanline(); /* check and generate IRQ */
|
|
CPU_GO(ANTIC_NMIST_C);
|
|
ANTIC_NMIST = 0x5f; /* Set VBLANK */
|
|
if (ANTIC_NMIEN & 0x40) {
|
|
CPU_GO(ANTIC_NMI_C);
|
|
CPU_NMI();
|
|
}
|
|
BASIC_LINE;
|
|
|
|
/* scanlines 249 - 261(311) */
|
|
do {
|
|
POKEY_Scanline(); /* check and generate IRQ */
|
|
BASIC_LINE;
|
|
} while (ANTIC_ypos < Atari800_tv_mode);
|
|
}
|
|
|
|
#endif /* defined(BASIC) || defined(VERY_SLOW) || defined(CURSES_BASIC) */
|
|
|
|
void Atari800_Frame(void)
|
|
{
|
|
#ifndef BASIC
|
|
static int refresh_counter = 0;
|
|
switch (INPUT_key_code) {
|
|
case AKEY_COLDSTART:
|
|
Atari800_Coldstart();
|
|
break;
|
|
case AKEY_WARMSTART:
|
|
Atari800_Warmstart();
|
|
break;
|
|
case AKEY_EXIT:
|
|
Atari800_Exit(FALSE);
|
|
exit(0);
|
|
case AKEY_UI:
|
|
#ifdef SOUND
|
|
Sound_Pause();
|
|
#endif
|
|
UI_Run();
|
|
#ifdef SOUND
|
|
Sound_Continue();
|
|
#endif
|
|
break;
|
|
#ifndef CURSES_BASIC
|
|
case AKEY_SCREENSHOT:
|
|
Screen_SaveNextScreenshot(FALSE);
|
|
break;
|
|
case AKEY_SCREENSHOT_INTERLACE:
|
|
Screen_SaveNextScreenshot(TRUE);
|
|
break;
|
|
#endif /* CURSES_BASIC */
|
|
case AKEY_PBI_BB_MENU:
|
|
#ifdef PBI_BB
|
|
PBI_BB_Menu();
|
|
#endif
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
#endif /* BASIC */
|
|
|
|
#ifdef PBI_BB
|
|
PBI_BB_Frame(); /* just to make the menu key go up automatically */
|
|
#endif
|
|
#ifdef PBI_XLD
|
|
PBI_XLD_VFrame(); /* for the Votrax */
|
|
#endif
|
|
Devices_Frame();
|
|
#ifndef BASIC
|
|
INPUT_Frame();
|
|
#endif
|
|
GTIA_Frame();
|
|
#ifdef SOUND
|
|
Sound_Update();
|
|
#endif
|
|
|
|
#ifdef BASIC
|
|
basic_frame();
|
|
#else /* BASIC */
|
|
if (++refresh_counter >= Atari800_refresh_rate) {
|
|
refresh_counter = 0;
|
|
#ifdef USE_CURSES
|
|
curses_clear_screen();
|
|
#endif
|
|
#ifdef CURSES_BASIC
|
|
basic_frame();
|
|
#else
|
|
ANTIC_Frame(TRUE);
|
|
INPUT_DrawMousePointer();
|
|
Screen_DrawAtariSpeed(Atari_time());
|
|
Screen_DrawDiskLED();
|
|
#endif /* CURSES_BASIC */
|
|
#ifdef DONT_DISPLAY
|
|
Atari800_display_screen = FALSE;
|
|
#else
|
|
Atari800_display_screen = TRUE;
|
|
#endif /* DONT_DISPLAY */
|
|
}
|
|
else {
|
|
#if defined(VERY_SLOW) || defined(CURSES_BASIC)
|
|
basic_frame();
|
|
#else
|
|
ANTIC_Frame(Atari800_collisions_in_skipped_frames);
|
|
#endif
|
|
Atari800_display_screen = FALSE;
|
|
}
|
|
#endif /* BASIC */
|
|
POKEY_Frame();
|
|
Atari800_nframes++;
|
|
#ifdef BENCHMARK
|
|
if (Atari800_nframes >= BENCHMARK) {
|
|
double benchmark_time = Atari_time() - benchmark_start_time;
|
|
Atari800_Exit(FALSE);
|
|
printf("%d frames emulated in %.2f seconds\n", BENCHMARK, benchmark_time);
|
|
exit(0);
|
|
}
|
|
#else
|
|
|
|
#ifdef ALTERNATE_SYNC_WITH_HOST
|
|
if (refresh_counter == 0)
|
|
#endif
|
|
Atari800_Sync();
|
|
#endif /* BENCHMARK */
|
|
}
|
|
|
|
#endif /* __PLUS */
|
|
|
|
#ifndef BASIC
|
|
|
|
void Atari800_StateSave(void)
|
|
{
|
|
UBYTE temp;
|
|
int default_tv_mode;
|
|
int os = 0;
|
|
int default_system = 3;
|
|
int pil_on = FALSE;
|
|
|
|
if (Atari800_tv_mode == Atari800_TV_PAL) {
|
|
temp = 0;
|
|
default_tv_mode = 1;
|
|
}
|
|
else {
|
|
temp = 1;
|
|
default_tv_mode = 2;
|
|
}
|
|
StateSav_SaveUBYTE(&temp, 1);
|
|
|
|
switch (Atari800_machine_type) {
|
|
case Atari800_MACHINE_OSA:
|
|
temp = MEMORY_ram_size == 16 ? 5 : 0;
|
|
os = 1;
|
|
default_system = 1;
|
|
break;
|
|
case Atari800_MACHINE_OSB:
|
|
temp = MEMORY_ram_size == 16 ? 5 : 0;
|
|
os = 2;
|
|
default_system = 2;
|
|
break;
|
|
case Atari800_MACHINE_XLXE:
|
|
switch (MEMORY_ram_size) {
|
|
case 16:
|
|
temp = 6;
|
|
default_system = 3;
|
|
break;
|
|
case 64:
|
|
temp = 1;
|
|
default_system = 3;
|
|
break;
|
|
case 128:
|
|
temp = 2;
|
|
default_system = 4;
|
|
break;
|
|
case 192:
|
|
temp = 9;
|
|
default_system = 8;
|
|
break;
|
|
case MEMORY_RAM_320_RAMBO:
|
|
case MEMORY_RAM_320_COMPY_SHOP:
|
|
temp = 3;
|
|
default_system = 5;
|
|
break;
|
|
case 576:
|
|
temp = 7;
|
|
default_system = 6;
|
|
break;
|
|
case 1088:
|
|
temp = 8;
|
|
default_system = 7;
|
|
break;
|
|
}
|
|
break;
|
|
case Atari800_MACHINE_5200:
|
|
temp = 4;
|
|
default_system = 6;
|
|
break;
|
|
}
|
|
StateSav_SaveUBYTE(&temp, 1);
|
|
|
|
StateSav_SaveINT(&os, 1);
|
|
StateSav_SaveINT(&pil_on, 1);
|
|
StateSav_SaveINT(&default_tv_mode, 1);
|
|
StateSav_SaveINT(&default_system, 1);
|
|
}
|
|
|
|
void Atari800_StateRead(void)
|
|
{
|
|
int new_tv_mode;
|
|
/* these are all for compatibility with previous versions */
|
|
UBYTE temp;
|
|
int default_tv_mode;
|
|
int os;
|
|
int default_system;
|
|
int pil_on;
|
|
|
|
StateSav_ReadUBYTE(&temp, 1);
|
|
new_tv_mode = (temp == 0) ? Atari800_TV_PAL : Atari800_TV_NTSC;
|
|
if (new_tv_mode != Atari800_tv_mode) {
|
|
Atari800_tv_mode = new_tv_mode;
|
|
#if !defined(BASIC) && !defined(CURSES_BASIC)
|
|
Colours_InitialiseMachine();
|
|
#endif
|
|
}
|
|
|
|
StateSav_ReadUBYTE(&temp, 1);
|
|
StateSav_ReadINT(&os, 1);
|
|
switch (temp) {
|
|
case 0:
|
|
Atari800_machine_type = os == 1 ? Atari800_MACHINE_OSA : Atari800_MACHINE_OSB;
|
|
MEMORY_ram_size = 48;
|
|
break;
|
|
case 1:
|
|
Atari800_machine_type = Atari800_MACHINE_XLXE;
|
|
MEMORY_ram_size = 64;
|
|
break;
|
|
case 2:
|
|
Atari800_machine_type = Atari800_MACHINE_XLXE;
|
|
MEMORY_ram_size = 128;
|
|
break;
|
|
case 3:
|
|
Atari800_machine_type = Atari800_MACHINE_XLXE;
|
|
MEMORY_ram_size = MEMORY_RAM_320_COMPY_SHOP;
|
|
break;
|
|
case 4:
|
|
Atari800_machine_type = Atari800_MACHINE_5200;
|
|
MEMORY_ram_size = 16;
|
|
break;
|
|
case 5:
|
|
Atari800_machine_type = os == 1 ? Atari800_MACHINE_OSA : Atari800_MACHINE_OSB;
|
|
MEMORY_ram_size = 16;
|
|
break;
|
|
case 6:
|
|
Atari800_machine_type = Atari800_MACHINE_XLXE;
|
|
MEMORY_ram_size = 16;
|
|
break;
|
|
case 7:
|
|
Atari800_machine_type = Atari800_MACHINE_XLXE;
|
|
MEMORY_ram_size = 576;
|
|
break;
|
|
case 8:
|
|
Atari800_machine_type = Atari800_MACHINE_XLXE;
|
|
MEMORY_ram_size = 1088;
|
|
break;
|
|
case 9:
|
|
Atari800_machine_type = Atari800_MACHINE_XLXE;
|
|
MEMORY_ram_size = 192;
|
|
break;
|
|
default:
|
|
Atari800_machine_type = Atari800_MACHINE_XLXE;
|
|
MEMORY_ram_size = 64;
|
|
Log_print("Warning: Bad machine type read in from state save, defaulting to 800 XL");
|
|
break;
|
|
}
|
|
|
|
StateSav_ReadINT(&pil_on, 1);
|
|
StateSav_ReadINT(&default_tv_mode, 1);
|
|
StateSav_ReadINT(&default_system, 1);
|
|
load_roms();
|
|
/* XXX: what about patches? */
|
|
}
|
|
|
|
#endif
|