Files
libretro-atari800/atari800/src/esc.c
T
2015-12-14 14:00:35 +01:00

244 lines
6.7 KiB
C

/*
* esc.c - Patch the OS with escape sequences
*
* 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 "config.h"
#include "atari.h"
#include "cassette.h"
#include "cpu.h"
#include "devices.h"
#include "esc.h"
#include "log.h"
#include "memory.h"
#include "pia.h"
#include "sio.h"
#include "sysrom.h"
#include "ui.h"
#include <stdlib.h>
int ESC_enable_sio_patch = TRUE;
/* Now we check address of every escape code, to make sure that the patch
has been set by the emulator and is not a CIM in Atari program.
Also switch() for escape codes has been changed to array of pointers
to functions. This allows adding port-specific patches (e.g. modem device)
using ESC_Add, Devices_UpdateHATABSEntry etc. without modifying
atari.c/devices.c. Unfortunately it can't be done for patches in Atari OS,
because the OS in XL/XE can be disabled.
*/
static UWORD esc_address[256];
static ESC_FunctionType esc_function[256];
void ESC_ClearAll(void)
{
int i;
for (i = 0; i < 256; i++)
esc_function[i] = NULL;
}
void ESC_Add(UWORD address, UBYTE esc_code, ESC_FunctionType function)
{
esc_address[esc_code] = address;
esc_function[esc_code] = function;
MEMORY_dPutByte(address, 0xf2); /* ESC */
MEMORY_dPutByte(address + 1, esc_code); /* ESC CODE */
}
void ESC_AddEscRts(UWORD address, UBYTE esc_code, ESC_FunctionType function)
{
esc_address[esc_code] = address;
esc_function[esc_code] = function;
MEMORY_dPutByte(address, 0xf2); /* ESC */
MEMORY_dPutByte(address + 1, esc_code); /* ESC CODE */
MEMORY_dPutByte(address + 2, 0x60); /* RTS */
}
/* 0xd2 is ESCRTS, which works same as pair of ESC and RTS (I think so...).
So this function does effectively the same as ESC_AddEscRts,
except that it modifies 2, not 3 bytes in Atari memory.
I don't know why it is done that way, so I simply leave it
unchanged (0xf2/0xd2 are used as in previous versions).
*/
void ESC_AddEscRts2(UWORD address, UBYTE esc_code, ESC_FunctionType function)
{
esc_address[esc_code] = address;
esc_function[esc_code] = function;
MEMORY_dPutByte(address, 0xd2); /* ESCRTS */
MEMORY_dPutByte(address + 1, esc_code); /* ESC CODE */
}
void ESC_Remove(UBYTE esc_code)
{
esc_function[esc_code] = NULL;
}
void ESC_Run(UBYTE esc_code)
{
if (esc_address[esc_code] == CPU_regPC - 2 && esc_function[esc_code] != NULL) {
esc_function[esc_code]();
return;
}
#ifdef CRASH_MENU
CPU_regPC -= 2;
UI_crash_address = CPU_regPC;
UI_crash_afterCIM = CPU_regPC + 2;
UI_crash_code = MEMORY_dGetByte(UI_crash_address);
UI_Run();
#else /* CRASH_MENU */
CPU_cim_encountered = 1;
Log_print("Invalid ESC code %02x at address %04x", esc_code, CPU_regPC - 2);
#ifndef __PLUS
if (!Atari800_Exit(TRUE))
exit(0);
#else /* __PLUS */
Atari800_Exit(TRUE);
#endif /* __PLUS */
#endif /* CRASH_MENU */
}
void ESC_PatchOS(void)
{
int patched = Devices_PatchOS();
if (ESC_enable_sio_patch) {
UWORD addr_l;
UWORD addr_s;
UBYTE check_s_0;
UBYTE check_s_1;
/* patch Open() of C: so we know when a leader is processed */
switch (Atari800_os_version) {
case SYSROM_A_NTSC:
case SYSROM_B_NTSC:
case SYSROM_800_CUSTOM:
addr_l = 0xef74;
addr_s = 0xefbc;
check_s_0 = 0xa0;
check_s_1 = 0x80;
break;
case SYSROM_A_PAL:
addr_l = 0xef74;
addr_s = 0xefbc;
check_s_0 = 0xa0;
check_s_1 = 0xc0;
break;
case SYSROM_AA00R10:
addr_l = 0xed47;
addr_s = 0xed94;
check_s_0 = 0xa9;
check_s_1 = 0x03;
break;
case SYSROM_AA01R11:
case SYSROM_BB00R1:
case SYSROM_BB01R2:
case SYSROM_BB02R3:
case SYSROM_BB02R3V4:
case SYSROM_BB01R3:
case SYSROM_BB01R4_OS:
case SYSROM_BB01R59:
case SYSROM_BB01R59A:
case SYSROM_XL_CUSTOM:
addr_l = 0xfd13;
addr_s = 0xfd60;
check_s_0 = 0xa9;
check_s_1 = 0x03;
break;
case SYSROM_CC01R4:
addr_l = 0xef74;
addr_s = 0xefbc;
check_s_0 = 0xa9;
check_s_1 = 0x03;
break;
default:
return;
}
/* don't hurt non-standard OSes that may not support cassette at all */
if (MEMORY_dGetByte(addr_l) == 0xa9 && MEMORY_dGetByte(addr_l + 1) == 0x03
&& MEMORY_dGetByte(addr_l + 2) == 0x8d && MEMORY_dGetByte(addr_l + 3) == 0x2a
&& MEMORY_dGetByte(addr_l + 4) == 0x02
&& MEMORY_dGetByte(addr_s) == check_s_0
&& MEMORY_dGetByte(addr_s + 1) == check_s_1
&& MEMORY_dGetByte(addr_s + 2) == 0x20 && MEMORY_dGetByte(addr_s + 3) == 0x5c
&& MEMORY_dGetByte(addr_s + 4) == 0xe4) {
ESC_Add(addr_l, ESC_COPENLOAD, CASSETTE_LeaderLoad);
ESC_Add(addr_s, ESC_COPENSAVE, CASSETTE_LeaderSave);
}
ESC_AddEscRts(0xe459, ESC_SIOV, SIO_Handler);
patched = TRUE;
}
else {
ESC_Remove(ESC_COPENLOAD);
ESC_Remove(ESC_COPENSAVE);
ESC_Remove(ESC_SIOV);
};
if (patched){
UWORD addr;
switch (Atari800_os_version) {
case SYSROM_AA00R10:
addr = 0xc3d2;
break;
case SYSROM_AA01R11:
addr = 0xc346;
break;
case SYSROM_BB00R1:
addr = 0xc32b;
break;
case SYSROM_BB01R2:
case SYSROM_BB02R3:
case SYSROM_BB01R3:
case SYSROM_BB01R4_OS:
case SYSROM_BB01R59:
case SYSROM_BB01R59A:
case SYSROM_XL_CUSTOM:
addr = 0xc31d;
break;
case SYSROM_BB02R3V4:
addr = 0xc32c;
break;
case SYSROM_CC01R4:
addr = 0xc2e0;
break;
default:
/* Don't disable checksum test. */
return;
}
/* Disable setting NGFLAG on wrong OS checksum. */
MEMORY_dPutByte(addr, 0xea);
MEMORY_dPutByte(addr+1, 0xea);
}
}
void ESC_UpdatePatches(void)
{
/* Patch only if OS enabled. */
if (Atari800_machine_type != Atari800_MACHINE_5200 &&
(Atari800_machine_type != Atari800_MACHINE_XLXE || (PIA_PORTB & 1) != 0)) {
int const os_rom_start = Atari800_machine_type == Atari800_MACHINE_800 ? 0xd800 : 0xc000;
/* Restore unpatched OS */
if (os_rom_start < 0xd000)
MEMORY_dCopyToMem(MEMORY_os, os_rom_start, 0xd000 - os_rom_start);
MEMORY_dCopyToMem(MEMORY_os + 0xd800 - os_rom_start, 0xd800, 0x2800);
/* Set patches */
ESC_PatchOS();
Devices_UpdatePatches();
}
}