This is c64mem.c in view mode; [Download] [Up]
/*
* c64mem.c -- C64 memory handling.
*
* Written by
* Ettore Perazzoli (ettore@comm2000.it)
* Andreas Boose (boose@unixserv.rz.fh-hannover.de)
*
* This file is part of VICE, the Versatile Commodore Emulator.
* See README for copyright notice.
*
* 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.
*
*/
#ifndef CBM64
#define CBM64 /* for mkdep */
#endif
#include "vice.h"
#include <stdio.h>
#include "c64cia.h"
#include "c64mem.h"
#include "c64tpi.h"
#include "cartridge.h"
#include "cmdline.h"
#include "emuid.h"
#include "interrupt.h"
#include "maincpu.h"
#include "memutils.h"
#include "mon.h"
#include "parallel.h"
#include "patchrom.h"
#include "resources.h"
#include "reu.h"
#include "sid.h"
#include "tapeunit.h"
#include "true1541.h"
#include "utils.h"
#include "vicii.h"
#include "vmachine.h"
#ifdef HAVE_RS232
#include "c64acia.h"
#endif
/* ------------------------------------------------------------------------- */
/* C64 memory-related resources. */
/* Name of the character ROM. */
static char *chargen_rom_name;
/* Name of the BASIC ROM. */
static char *basic_rom_name;
/* Name of the Kernal ROM. */
static char *kernal_rom_name;
/* Kernal revision for ROM patcher. */
static char *kernal_revision;
/* Flag: Do we enable the Emulator ID? */
static int emu_id_enabled;
/* Flag: Do we enable the IEEE488 interface emulation? */
static int ieee488_enabled;
/* Flag: Do we enable the external REU? */
static int reu_enabled;
/* Type of the cartridge attached. */
static int mem_cartridge_type = CARTRIDGE_NONE;
#ifdef HAVE_RS232
/* Flag: Do we enable the $DE** ACIA RS232 interface emulation? */
static int acia_de_enabled;
/* Flag: Do we enable the $D6** ACIA RS232 interface emulation? */
static int acia_d6_enabled;
#endif
static void cartridge_config_changed(BYTE mode);
/* FIXME: Should load the new character ROM. */
static int set_chargen_rom_name(resource_value_t v)
{
const char *name = (const char *) v;
if (chargen_rom_name != NULL && name != NULL
&& strcmp(name, chargen_rom_name) == 0)
return 0;
string_set(&chargen_rom_name, name);
return 0;
}
/* FIXME: Should load the new Kernal ROM. */
static int set_kernal_rom_name(resource_value_t v)
{
const char *name = (const char *) v;
if (kernal_rom_name != NULL && name != NULL
&& strcmp(name, kernal_rom_name) == 0)
return 0;
string_set(&kernal_rom_name, name);
return 0;
}
/* FIXME: Should load the new BASIC ROM. */
static int set_basic_rom_name(resource_value_t v)
{
const char *name = (const char *) v;
if (basic_rom_name != NULL
&& name != NULL
&& strcmp(name, basic_rom_name) == 0)
return 0;
string_set(&basic_rom_name, name);
return 0;
}
static int set_emu_id_enabled(resource_value_t v)
{
if (!(int) v) {
emu_id_enabled = 0;
return 0;
} else if (mem_cartridge_type == CARTRIDGE_NONE) {
emu_id_enabled = 1;
return 0;
} else {
/* Other extensions share the same address space, so they cannot be
enabled at the same time. */
return -1;
}
}
static int set_ieee488_enabled(resource_value_t v)
{
if (!(int) v) {
ieee488_enabled = 0;
return 0;
} else if (!reu_enabled && (mem_cartridge_type == CARTRIDGE_NONE)) {
ieee488_enabled = 1;
return 0;
} else {
/* The REU and the IEEE488 interface share the same address space, so
they cannot be enabled at the same time. */
return -1;
}
}
/* FIXME: Should initialize the REU when turned on. */
static int set_reu_enabled(resource_value_t v)
{
if (!(int) v) {
reu_enabled = 0;
return 0;
} else if (!ieee488_enabled && (mem_cartridge_type == CARTRIDGE_NONE)) {
reu_enabled = 1;
return 0;
} else {
/* The REU and the IEEE488 interface share the same address space, so
they cannot be enabled at the same time. */
return -1;
}
}
/* FIXME: Should patch the ROM on-the-fly. */
static int set_kernal_revision(resource_value_t v)
{
const char *rev = (const char *) v;
string_set(&kernal_revision, rev);
return 0;
}
#ifdef HAVE_RS232
static int set_acia_d6_enabled(resource_value_t v)
{
acia_d6_enabled = (int) v;
return 0;
}
static int set_acia_de_enabled(resource_value_t v)
{
acia_de_enabled = (int) v;
return 0;
}
#endif
static resource_t resources[] = {
{ "ChargenName", RES_STRING, (resource_value_t) "chargen",
(resource_value_t *) &chargen_rom_name, set_chargen_rom_name },
{ "KernalName", RES_STRING, (resource_value_t) "kernal",
(resource_value_t *) &kernal_rom_name, set_kernal_rom_name },
{ "BasicName", RES_STRING, (resource_value_t) "basic",
(resource_value_t *) &basic_rom_name, set_basic_rom_name },
{ "REU", RES_INTEGER, (resource_value_t) 0,
(resource_value_t *) &reu_enabled, set_reu_enabled },
{ "IEEE488", RES_INTEGER, (resource_value_t) 0,
(resource_value_t *) &ieee488_enabled, set_ieee488_enabled },
{ "EmuID", RES_INTEGER, (resource_value_t) 0,
(resource_value_t *) &emu_id_enabled, set_emu_id_enabled },
{ "KernalRev", RES_STRING, (resource_value_t) NULL,
(resource_value_t *) &kernal_revision, set_kernal_revision },
#ifdef HAVE_RS232
{ "AciaDE", RES_INTEGER, (resource_value_t) 0,
(resource_value_t *) &acia_de_enabled, set_acia_de_enabled },
{ "AciaD6", RES_INTEGER, (resource_value_t) 0,
(resource_value_t *) &acia_d6_enabled, set_acia_d6_enabled },
#endif
{ NULL }
};
int c64_mem_init_resources(void)
{
return resources_register(resources);
}
/* ------------------------------------------------------------------------- */
/* C64 memory-related command-line options. */
/* FIXME: Maybe the `-kernal', `-basic' and `-chargen' options should not
really affect resources. */
static cmdline_option_t cmdline_options[] =
{
{ "-kernal", SET_RESOURCE, 1, NULL, NULL, "KernalName", NULL,
"<name>", "Specify name of Kernal ROM image" },
{ "-basic", SET_RESOURCE, 1, NULL, NULL, "BasicName", NULL,
"<name>", "Specify name of BASIC ROM image" },
{ "-chargen", SET_RESOURCE, 1, NULL, NULL, "ChargenName", NULL,
"<name>", "Specify name of character generator ROM image" },
{ "-reu", SET_RESOURCE, 0, NULL, NULL, "REU", (resource_value_t) 1,
NULL, "Enable the 512K RAM expansion unit" },
{ "+reu", SET_RESOURCE, 0, NULL, NULL, "REU", (resource_value_t) 0,
NULL, "Disable the 512K RAM expansion unit" },
{ "-emuid", SET_RESOURCE, 0, NULL, NULL, "EmuID", (resource_value_t) 1,
NULL, "Enable emulator identification" },
{ "+emuid", SET_RESOURCE, 0, NULL, NULL, "EmuID", (resource_value_t) 0,
NULL, "Disable emulator identification" },
{ "-ieee488", SET_RESOURCE, 0, NULL, NULL, "IEEE488", (resource_value_t) 1,
NULL, "Enable the IEEE488 interface emulation" },
{ "+ieee488", SET_RESOURCE, 0, NULL, NULL, "IEEE488", (resource_value_t) 0,
NULL, "Disable the IEEE488 interface emulation" },
{ "-kernalrev", SET_RESOURCE, 1, NULL, NULL, "KernalRev", NULL,
"<revision>", "Patch the Kernal ROM to the specified <revision>" },
#ifdef HAVE_RS232
{ "-acia1", SET_RESOURCE, 0, NULL, NULL, "AciaDE", (resource_value_t) 1,
NULL, "Enable the $DE** ACIA RS232 interface emulation" },
{ "+acia1", SET_RESOURCE, 0, NULL, NULL, "AciaDE", (resource_value_t) 0,
NULL, "Disable the $DE** ACIA RS232 interface emulation" },
#if 0
{ "-acia2", SET_RESOURCE, 0, NULL, NULL, "AciaD6", (resource_value_t) 1,
NULL, "Enable the $D6** ACIA RS232 interface emulation" },
{ "+acia2", SET_RESOURCE, 0, NULL, NULL, "AciaD6", (resource_value_t) 0,
NULL, "Disable the $D6** ACIA RS232 interface emulation" },
#endif
#endif
{ NULL }
};
int c64_mem_init_cmdline_options(void)
{
return cmdline_register_options(cmdline_options);
}
/* ------------------------------------------------------------------------- */
/* Number of possible memory configurations. */
#define NUM_CONFIGS 32
/* Number of possible video banks (16K each). */
#define NUM_VBANKS 4
/* The C64 memory. */
BYTE ram[C64_RAM_SIZE];
BYTE basic_rom[C64_BASIC_ROM_SIZE];
BYTE kernal_rom[C64_KERNAL_ROM_SIZE];
BYTE chargen_rom[C64_CHARGEN_ROM_SIZE];
/* Size of RAM... */
int ram_size = C64_RAM_SIZE;
/* Flag: nonzero if the Kernal and BASIC ROMs have been loaded. */
int rom_loaded = 0;
/* Pointers to the currently used memory read and write tables. */
read_func_ptr_t *_mem_read_tab_ptr;
store_func_ptr_t *_mem_write_tab_ptr;
BYTE **_mem_read_base_tab_ptr;
/* Memory read and write tables. */
static store_func_ptr_t mem_write_tab[NUM_VBANKS][NUM_CONFIGS][0x101];
static read_func_ptr_t mem_read_tab[NUM_CONFIGS][0x101];
static BYTE *mem_read_base_tab[NUM_CONFIGS][0x101];
static store_func_ptr_t mem_write_tab_watch[0x101];
static read_func_ptr_t mem_read_tab_watch[0x101];
/* Processor port. */
static struct {
BYTE dir, data;
} pport;
/* Expansion port signals. */
static struct {
int exrom;
int game;
} export;
/* Current video bank (0, 1, 2 or 3). */
static int vbank;
/* Current memory configuration. */
static int mem_config;
/* Tape sense status: 1 = some button pressed, 0 = no buttons pressed. */
static int tape_sense = 0;
/* Exansion port ROML/ROMH images. */
BYTE roml_banks[0x8000], romh_banks[0x8000];
/* Exansion port RAM images. */
BYTE export_ram0[0x2000];
/* Expansion port ROML/ROMH/RAM banking. */
static int roml_bank, romh_bank, export_ram;
/* ------------------------------------------------------------------------- */
BYTE REGPARM1 read_watch(ADDRESS addr)
{
mon_watch_push_load_addr(addr, e_comp_space);
return mem_read_tab[mem_config][addr >> 8](addr);
}
void REGPARM2 store_watch(ADDRESS addr, BYTE value)
{
mon_watch_push_store_addr(addr, e_comp_space);
mem_write_tab[vbank][mem_config][addr >> 8](addr, value);
}
/* ------------------------------------------------------------------------- */
static inline void pla_config_changed(void)
{
mem_config = (((~pport.dir | pport.data) & 0x7) | (export.exrom << 3)
| (export.game << 4));
/* Bit 4: tape sense. 0 = some button pressed, 1 = no buttons pressed. */
if (tape_sense)
ram[1] = (pport.data | ~pport.dir) & 0x2f;
else
ram[1] = (pport.data | ~pport.dir) & 0x3f;
ram[0] = pport.dir;
if (any_watchpoints(e_comp_space)) {
_mem_read_tab_ptr = mem_read_tab_watch;
_mem_write_tab_ptr = mem_write_tab_watch;
} else {
_mem_read_tab_ptr = mem_read_tab[mem_config];
_mem_write_tab_ptr = mem_write_tab[vbank][mem_config];
}
_mem_read_base_tab_ptr = mem_read_base_tab[mem_config];
}
void mem_toggle_watchpoints(int flag)
{
if (flag) {
_mem_read_tab_ptr = mem_read_tab_watch;
_mem_write_tab_ptr = mem_write_tab_watch;
} else {
_mem_read_tab_ptr = mem_read_tab[mem_config];
_mem_write_tab_ptr = mem_write_tab[vbank][mem_config];
}
}
BYTE REGPARM1 read_zero(ADDRESS addr)
{
return ram[addr & 0xff];
}
void REGPARM2 store_zero(ADDRESS addr, BYTE value)
{
addr &= 0xff;
switch ((BYTE) addr) {
case 0:
if (pport.dir != value) {
pport.dir = value;
pla_config_changed();
}
break;
case 1:
if (pport.data != value) {
pport.data = value;
pla_config_changed();
}
break;
default:
ram[addr] = value;
}
}
BYTE REGPARM1 read_basic(ADDRESS addr)
{
return basic_rom[addr & 0x1fff];
}
BYTE REGPARM1 read_kernal(ADDRESS addr)
{
return kernal_rom[addr & 0x1fff];
}
BYTE REGPARM1 read_chargen(ADDRESS addr)
{
return chargen_rom[addr & 0xfff];
}
BYTE REGPARM1 read_ram(ADDRESS addr)
{
return ram[addr];
}
void REGPARM2 store_ram(ADDRESS addr, BYTE value)
{
ram[addr] = value;
}
void REGPARM2 store_ram_hi(ADDRESS addr, BYTE value)
{
ram[addr] = value;
if (reu_enabled && addr == 0xff00)
reu_dma(-1);
}
void REGPARM2 store_io2(ADDRESS addr, BYTE value)
{
if ((addr & 0xff00) == 0xdf00) {
if (reu_enabled)
store_reu(addr & 0x0f, value);
if (ieee488_enabled)
store_tpi(addr & 0x07, value);
}
if ((mem_cartridge_type == CARTRIDGE_ACTION_REPLAY) && export_ram)
export_ram0[0x1f00 + (addr & 0xff)] = value;
if (mem_cartridge_type == CARTRIDGE_KCS_POWER)
export_ram0[0x1f00 + (addr & 0xff)] = value;
return;
}
BYTE REGPARM1 read_io2(ADDRESS addr)
{
if (emu_id_enabled && addr >= 0xdfa0) {
addr &= 0xff;
if (addr == 0xff)
emulator_id[addr - 0xa0] ^= 0xff;
return emulator_id[addr - 0xa0];
}
if ((addr & 0xff00) == 0xdf00) {
if (reu_enabled)
return read_reu(addr & 0x0f);
if (ieee488_enabled)
return read_tpi(addr & 0x07);
if (mem_cartridge_type == CARTRIDGE_ACTION_REPLAY) {
if (export_ram)
return export_ram0[0x1f00 + (addr & 0xff)];
switch (roml_bank) {
case 0:
return roml_banks[addr & 0x1fff];
case 1:
return roml_banks[(addr & 0x1fff) + 0x2000];
case 2:
return roml_banks[(addr & 0x1fff) + 0x4000];
case 3:
return roml_banks[(addr & 0x1fff) + 0x6000];
}
}
if (mem_cartridge_type == CARTRIDGE_KCS_POWER)
return export_ram0[0x1f00 + (addr & 0xff)];
}
return rand();
}
void REGPARM2 store_io1(ADDRESS addr, BYTE value)
{
if ((addr & 0xff00) == 0xde00) {
if (mem_cartridge_type == CARTRIDGE_ACTION_REPLAY)
cartridge_config_changed(value);
if (mem_cartridge_type == CARTRIDGE_KCS_POWER)
cartridge_config_changed(1);
if (mem_cartridge_type == CARTRIDGE_SIMONS_BASIC)
cartridge_config_changed(1);
}
#ifdef HAVE_RS232
if (acia_de_enabled)
store_acia1(addr & 0x03, value);
#endif
return;
}
BYTE REGPARM1 read_io1(ADDRESS addr)
{
if ((addr & 0xff00) == 0xde00) {
if (mem_cartridge_type == CARTRIDGE_ACTION_REPLAY)
return rand();
if (mem_cartridge_type == CARTRIDGE_KCS_POWER) {
cartridge_config_changed(0);
return roml_banks[0x1e00 + (addr & 0xff)];
}
if (mem_cartridge_type == CARTRIDGE_SIMONS_BASIC)
cartridge_config_changed(0);
}
#ifdef HAVE_RS232
if (acia_de_enabled)
return read_acia1(addr & 0x03);
#endif
return rand();
}
void REGPARM2 store_d6(ADDRESS addr, BYTE value)
{
#if 0 /*def HAVE_RS232 */
if (acia_d6_enabled)
store_acia2(addr, value);
else
#endif
store_sid(addr, value);
return;
}
BYTE REGPARM1 read_d6(ADDRESS addr)
{
#if 0 /*def HAVE_RS232 */
if (acia_d6_enabled)
return read_acia2(addr);
#endif
return read_sid(addr);
}
BYTE REGPARM1 read_rom(ADDRESS addr)
{
switch (addr & 0xf000) {
case 0xa000:
case 0xb000:
return read_basic(addr);
case 0xd000:
return read_chargen(addr);
case 0xe000:
case 0xf000:
return read_kernal(addr);
}
return 0;
}
void REGPARM2 store_rom(ADDRESS addr, BYTE value)
{
switch (addr & 0xf000) {
case 0xa000:
case 0xb000:
basic_rom[addr & 0x1fff] = value;
break;
case 0xd000:
chargen_rom[addr & 0x0fff] = value;
break;
case 0xe000:
case 0xf000:
kernal_rom[addr & 0x1fff] = value;
break;
}
}
BYTE REGPARM1 read_roml(ADDRESS addr)
{
if (export_ram)
return export_ram0[addr & 0x1fff];
switch (roml_bank) {
case 0:
return roml_banks[addr & 0x1fff];
case 1:
return roml_banks[(addr & 0x1fff) + 0x2000];
case 2:
return roml_banks[(addr & 0x1fff) + 0x4000];
case 3:
return roml_banks[(addr & 0x1fff) + 0x6000];
}
return 0;
}
BYTE REGPARM1 read_romh(ADDRESS addr)
{
switch (romh_bank) {
case 0:
return romh_banks[addr & 0x1fff];
case 1:
return romh_banks[(addr & 0x1fff) + 0x2000];
case 2:
return romh_banks[(addr & 0x1fff) + 0x4000];
case 3:
return romh_banks[(addr & 0x1fff) + 0x6000];
}
return 0;
}
void REGPARM2 store_roml(ADDRESS addr, BYTE value)
{
if (export_ram)
export_ram0[addr & 0x1fff] = value;
return;
}
/* ------------------------------------------------------------------------- */
/* Generic memory access. */
void REGPARM2 mem_store(ADDRESS addr, BYTE value)
{
_mem_write_tab_ptr[addr >> 8](addr, value);
}
BYTE REGPARM1 mem_read(ADDRESS addr)
{
return _mem_read_tab_ptr[addr >> 8](addr);
}
/* ------------------------------------------------------------------------- */
static void set_write_hook(int config, int page, store_func_t * f)
{
int i;
for (i = 0; i < NUM_VBANKS; i++) {
mem_write_tab[i][config][page] = f;
}
}
void initialize_memory(void)
{
int i, j, k;
/* IO is enabled at memory configs 5, 6, 7 and Ultimax. */
int io_config[32] = { 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1 };
/* ROML is enabled at memory configs 11, 15, 27, 31 and Ultimax. */
int roml_config[32] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1,
1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1 };
/* ROMH is enabled at memory configs 10, 11, 14, 15, 26, 27, 30, 31
and Ultimax. */
int romh_config[32] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1 };
/* ROMH is mapped to $A000-$BFFF at memory configs 10, 11, 14, 15, 26,
27, 30, 31. If Ultimax is enabled it is mapped to $E000-$FFFF. */
int romh_mapping[32] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0,
0x00, 0x00, 0xa0, 0xa0, 0x00, 0x00, 0xa0, 0xa0 };
/* Default is RAM. */
for (i = 0; i <= 0xff; i++) {
mem_read_tab_watch[i] = read_watch;
mem_write_tab_watch[i] = store_watch;
}
for (i = 0; i < NUM_CONFIGS; i++) {
set_write_hook(i, 0, store_zero);
mem_read_tab[i][0] = read_zero;
mem_read_base_tab[i][0] = ram;
for (j = 1; j <= 0xfe; j++) {
mem_read_tab[i][j] = read_ram;
mem_read_base_tab[i][j] = ram + (j << 8);
for (k = 0; k < NUM_VBANKS; k++) {
if ((j & 0xc0) == (k << 6)) {
switch (j & 0x3fff) {
case 0x39:
mem_write_tab[k][i][j] = store_vbank_39xx;
break;
case 0x3f:
mem_write_tab[k][i][j] = store_vbank_3fxx;
break;
default:
mem_write_tab[k][i][j] = store_vbank;
}
} else {
mem_write_tab[k][i][j] = store_ram;
}
}
}
mem_read_tab[i][0xff] = read_ram;
mem_read_base_tab[i][0xff] = ram + 0xff00;
/* FIXME: we do not care about vbank writes here, but we probably
should. Anyway, the $FFxx addresses are not so likely to contain
sprites or other stuff that really needs the special handling, and
it's much easier this way. */
set_write_hook(i, 0xff, store_ram_hi);
}
/* Setup BASIC ROM at $A000-$BFFF (memory configs 3, 7, 11, 15). */
for (i = 0xa0; i <= 0xbf; i++) {
mem_read_tab[3][i] = read_basic;
mem_read_tab[7][i] = read_basic;
mem_read_tab[11][i] = read_basic;
mem_read_tab[15][i] = read_basic;
mem_read_base_tab[3][i] = basic_rom + ((i & 0x1f) << 8);
mem_read_base_tab[7][i] = basic_rom + ((i & 0x1f) << 8);
mem_read_base_tab[11][i] = basic_rom + ((i & 0x1f) << 8);
mem_read_base_tab[15][i] = basic_rom + ((i & 0x1f) << 8);
}
/* Setup character generator ROM at $D000-$DFFF (memory configs 1, 2,
3, 9, 10, 11, 25, 26, 27). */
for (i = 0xd0; i <= 0xdf; i++) {
mem_read_tab[1][i] = read_chargen;
mem_read_tab[2][i] = read_chargen;
mem_read_tab[3][i] = read_chargen;
mem_read_tab[9][i] = read_chargen;
mem_read_tab[10][i] = read_chargen;
mem_read_tab[11][i] = read_chargen;
mem_read_tab[25][i] = read_chargen;
mem_read_tab[26][i] = read_chargen;
mem_read_tab[27][i] = read_chargen;
mem_read_base_tab[1][i] = chargen_rom + ((i & 0x0f) << 8);
mem_read_base_tab[2][i] = chargen_rom + ((i & 0x0f) << 8);
mem_read_base_tab[3][i] = chargen_rom + ((i & 0x0f) << 8);
mem_read_base_tab[9][i] = chargen_rom + ((i & 0x0f) << 8);
mem_read_base_tab[10][i] = chargen_rom + ((i & 0x0f) << 8);
mem_read_base_tab[11][i] = chargen_rom + ((i & 0x0f) << 8);
mem_read_base_tab[25][i] = chargen_rom + ((i & 0x0f) << 8);
mem_read_base_tab[26][i] = chargen_rom + ((i & 0x0f) << 8);
mem_read_base_tab[27][i] = chargen_rom + ((i & 0x0f) << 8);
}
/* Setup I/O at $D000-$DFFF (memory configs 5, 6, 7). */
for (j = 0; j < NUM_CONFIGS; j++) {
if (io_config[j]) {
for (i = 0xd0; i <= 0xd3; i++) {
mem_read_tab[j][i] = read_vic;
set_write_hook(j, i, store_vic);
}
for (i = 0xd4; i <= 0xd5; i++) {
mem_read_tab[j][i] = read_sid;
set_write_hook(j, i, store_sid);
}
for (i = 0xd6; i <= 0xd7; i++) {
mem_read_tab[j][i] = read_d6;
set_write_hook(j, i, store_d6);
}
for (i = 0xd8; i <= 0xdb; i++) {
mem_read_tab[j][i] = read_colorram;
set_write_hook(j, i, store_colorram);
}
mem_read_tab[j][0xdc] = read_cia1;
set_write_hook(j, 0xdc, store_cia1);
mem_read_tab[j][0xdd] = read_cia2;
set_write_hook(j, 0xdd, store_cia2);
mem_read_tab[j][0xde] = read_io1;
set_write_hook(j, 0xde, store_io1);
mem_read_tab[j][0xdf] = read_io2;
set_write_hook(j, 0xdf, store_io2);
for (i = 0xd0; i <= 0xdf; i++)
mem_read_base_tab[j][i] = NULL;
}
}
/* Setup Kernal ROM at $E000-$FFFF (memory configs 2, 3, 6, 7, 10,
11, 14, 15, 26, 27, 30, 31). */
for (i = 0xe0; i <= 0xff; i++) {
mem_read_tab[2][i] = read_kernal;
mem_read_tab[3][i] = read_kernal;
mem_read_tab[6][i] = read_kernal;
mem_read_tab[7][i] = read_kernal;
mem_read_tab[10][i] = read_kernal;
mem_read_tab[11][i] = read_kernal;
mem_read_tab[14][i] = read_kernal;
mem_read_tab[15][i] = read_kernal;
mem_read_tab[26][i] = read_kernal;
mem_read_tab[27][i] = read_kernal;
mem_read_tab[30][i] = read_kernal;
mem_read_tab[31][i] = read_kernal;
mem_read_base_tab[2][i] = kernal_rom + ((i & 0x1f) << 8);
mem_read_base_tab[3][i] = kernal_rom + ((i & 0x1f) << 8);
mem_read_base_tab[6][i] = kernal_rom + ((i & 0x1f) << 8);
mem_read_base_tab[7][i] = kernal_rom + ((i & 0x1f) << 8);
mem_read_base_tab[10][i] = kernal_rom + ((i & 0x1f) << 8);
mem_read_base_tab[11][i] = kernal_rom + ((i & 0x1f) << 8);
mem_read_base_tab[14][i] = kernal_rom + ((i & 0x1f) << 8);
mem_read_base_tab[15][i] = kernal_rom + ((i & 0x1f) << 8);
mem_read_base_tab[26][i] = kernal_rom + ((i & 0x1f) << 8);
mem_read_base_tab[27][i] = kernal_rom + ((i & 0x1f) << 8);
mem_read_base_tab[30][i] = kernal_rom + ((i & 0x1f) << 8);
mem_read_base_tab[31][i] = kernal_rom + ((i & 0x1f) << 8);
}
/* Setup ROML at $8000-$9FFF. */
for (j = 0; j < NUM_CONFIGS; j++) {
if (roml_config[j]) {
for (i = 0x80; i <= 0x9f; i++) {
mem_read_tab[j][i] = read_roml;
mem_read_base_tab[j][i] = NULL;
}
}
}
for (j = 16; j < 24; j++)
for (i = 0x80; i <= 0x9f; i++)
set_write_hook(j, i, store_roml);
/* Setup ROMH at $A000-$BFFF and $E000-$FFFF. */
for (j = 0; j < NUM_CONFIGS; j++) {
if (romh_config[j]) {
for (i = romh_mapping[j]; i <= (romh_mapping[j] + 0x1f); i++) {
mem_read_tab[j][i] = read_romh;
mem_read_base_tab[j][i] = NULL;
}
}
}
for (i = 0; i < NUM_CONFIGS; i++) {
mem_read_tab[i][0x100] = mem_read_tab[i][0];
for (j = 0; j < NUM_VBANKS; j++) {
mem_write_tab[j][i][0x100] = mem_write_tab[j][i][0];
}
mem_read_base_tab[i][0x100] = mem_read_base_tab[i][0];
}
_mem_read_tab_ptr = mem_read_tab[7];
_mem_write_tab_ptr = mem_write_tab[vbank][7];
_mem_read_base_tab_ptr = mem_read_base_tab[7];
pport.data = 0xff;
pport.dir = 0x0;
export.exrom = 0;
export.game = 0;
/* Setup initial memory configuration. */
pla_config_changed();
switch (mem_cartridge_type) {
case CARTRIDGE_ACTION_REPLAY:
case CARTRIDGE_KCS_POWER:
case CARTRIDGE_GENERIC_8KB:
cartridge_config_changed(0);
break;
case CARTRIDGE_SIMONS_BASIC:
case CARTRIDGE_GENERIC_16KB:
cartridge_config_changed(1);
break;
}
}
/* ------------------------------------------------------------------------- */
/* Initialize RAM for power-up. */
void mem_powerup(void)
{
int i;
#ifndef __MSDOS__
printf("Initializing RAM for power-up...\n");
#endif
for (i = 0; i < 0x10000; i += 0x80) {
memset(ram + i, 0, 0x40);
memset(ram + i + 0x40, 0xff, 0x40);
}
}
/* Load ROMs at startup. This is half-stolen from the old `load_mem()' in
`memory.c'. */
int mem_load(void)
{
WORD sum; /* ROM checksum */
int id; /* ROM identification number */
int i;
mem_powerup();
/* Load Kernal ROM. */
if (mem_load_sys_file(kernal_rom_name,
kernal_rom, C64_KERNAL_ROM_SIZE,
C64_KERNAL_ROM_SIZE) < 0) {
fprintf(stderr, "Couldn't load kernal ROM `%s'.\n",
kernal_rom_name);
return -1;
}
/* Check Kernal ROM. */
for (i = 0, sum = 0; i < C64_KERNAL_ROM_SIZE; i++)
sum += kernal_rom[i];
id = read_rom(0xff80);
printf("Kernal rev #%d.\n", id);
if ((id == 0
&& sum != C64_KERNAL_CHECKSUM_R00)
|| (id == 3
&& sum != C64_KERNAL_CHECKSUM_R03
&& sum != C64_KERNAL_CHECKSUM_R03swe)
|| (id == 0x43
&& sum != C64_KERNAL_CHECKSUM_R43)
|| (id == 0x64
&& sum != C64_KERNAL_CHECKSUM_R64)) {
fprintf(stderr,
"Warning: Unknown Kernal image `%s'. Sum: %d ($%04X)\n",
kernal_rom_name, sum, sum);
} else if (kernal_revision != NULL) {
if (patch_rom(kernal_revision) < 0)
return -1;
}
/* Load Basic ROM. */
if (mem_load_sys_file(basic_rom_name,
basic_rom, C64_BASIC_ROM_SIZE,
C64_BASIC_ROM_SIZE) < 0) {
fprintf(stderr, "Couldn't load basic ROM `%s'.\n",
basic_rom_name);
return -1;
}
/* Check Basic ROM. */
for (i = 0, sum = 0; i < C64_BASIC_ROM_SIZE; i++)
sum += basic_rom[i];
if (sum != C64_BASIC_CHECKSUM)
fprintf(stderr,
"Warning: Unknown Basic image `%s'. Sum: %d ($%04X)\n",
basic_rom_name, sum, sum);
/* Load chargen ROM. */
if (mem_load_sys_file(chargen_rom_name,
chargen_rom, C64_CHARGEN_ROM_SIZE,
C64_CHARGEN_ROM_SIZE) < 0) {
fprintf(stderr, "Couldn't load character ROM `%s'.\n",
chargen_rom_name);
return -1;
}
rom_loaded = 1;
return 0;
}
void mem_attach_cartridge(int type, BYTE * rawcart)
{
mem_cartridge_type = type;
switch (type) {
case CARTRIDGE_GENERIC_8KB:
memcpy(roml_banks, rawcart, 0x2000);
cartridge_config_changed(0);
break;
case CARTRIDGE_SIMONS_BASIC:
case CARTRIDGE_GENERIC_16KB:
memcpy(roml_banks, rawcart, 0x2000);
memcpy(romh_banks, &rawcart[0x2000], 0x2000);
cartridge_config_changed(1);
break;
case CARTRIDGE_ACTION_REPLAY:
memcpy(roml_banks, rawcart, 0x8000);
memcpy(romh_banks, rawcart, 0x8000);
cartridge_config_changed(0);
break;
case CARTRIDGE_KCS_POWER:
memcpy(roml_banks, rawcart, 0x2000);
memcpy(romh_banks, &rawcart[0x2000], 0x2000);
cartridge_config_changed(0);
break;
default:
mem_cartridge_type = CARTRIDGE_NONE;
}
return;
}
void mem_detach_cartridge(int type)
{
cartridge_config_changed(6);
mem_cartridge_type = CARTRIDGE_NONE;
return;
}
void mem_freeze_cartridge(int type)
{
if (type == CARTRIDGE_ACTION_REPLAY)
cartridge_config_changed(35);
if (type == CARTRIDGE_KCS_POWER)
cartridge_config_changed(3);
}
/* ------------------------------------------------------------------------- */
/* Change the current video bank. */
void mem_set_vbank(int new_vbank)
{
if (new_vbank != vbank) {
vbank = new_vbank;
_mem_write_tab_ptr = mem_write_tab[new_vbank][mem_config];
vic_ii_set_vbank(new_vbank);
}
}
/* Set the tape sense status. */
void mem_set_tape_sense(int sense)
{
tape_sense = sense;
pla_config_changed();
}
/* Enable/disable the REU. FIXME: should initialize the REU if necessary? */
void mem_toggle_reu(int flag)
{
reu_enabled = flag;
}
/* Enable/disable the IEEE488 interface. */
void mem_toggle_ieee488(int flag)
{
ieee488_enabled = flag;
}
/* Enable/disable the Emulator ID. */
void mem_toggle_emu_id(int flag)
{
emu_id_enabled = flag;
}
static void cartridge_config_changed(BYTE mode)
{
export.game = mode & 1;
export.exrom = ((mode >> 1) & 1) ^ 1;
roml_bank = (mode >> 3) & 3;
export_ram = (mode >> 5) & 1;
pla_config_changed();
if (mode & 0x40)
cartridge_release_freeze();
}
/* ------------------------------------------------------------------------- */
/* FIXME: this part needs to be checked. */
void mem_get_basic_text(ADDRESS * start, ADDRESS * end)
{
if (start != NULL)
*start = ram[0x2b] | (ram[0x2c] << 8);
if (end != NULL)
*end = ram[0x2d] | (ram[0x2e] << 8);
}
void mem_set_basic_text(ADDRESS start, ADDRESS end)
{
ram[0x2b] = ram[0xac] = start & 0xff;
ram[0x2c] = ram[0xad] = start >> 8;
ram[0x2d] = ram[0x2f] = ram[0x31] = ram[0xae] = end & 0xff;
ram[0x2e] = ram[0x30] = ram[0x32] = ram[0xaf] = end >> 8;
}
/* ------------------------------------------------------------------------- */
int mem_rom_trap_allowed(ADDRESS addr)
{
return addr >= 0xe000 && (mem_config & 0x2);
}
/* ------------------------------------------------------------------------- */
/* Banked memory access functions for the monitor. */
/* FIXME: peek, cartridge support */
static void store_bank_io(ADDRESS addr, BYTE byte)
{
switch (addr &= 0xff00) {
case 0xd000:
case 0xd100:
case 0xd200:
case 0xd300:
store_vic(addr, byte);
break;
case 0xd400:
case 0xd500:
store_sid(addr, byte);
break;
case 0xd600:
case 0xd700:
store_d6(addr, byte);
break;
case 0xd800:
case 0xd900:
case 0xda00:
case 0xdb00:
store_colorram(addr, byte);
break;
case 0xdc00:
store_cia1(addr, byte);
break;
case 0xdd00:
store_cia2(addr, byte);
break;
case 0xde00:
store_io1(addr, byte);
break;
case 0xdf00:
store_io2(addr, byte);
break;
}
return;
}
static BYTE read_bank_io(ADDRESS addr)
{
switch (addr &= 0xff00) {
case 0xd000:
case 0xd100:
case 0xd200:
case 0xd300:
return read_vic(addr);
case 0xd400:
case 0xd500:
return read_sid(addr);
case 0xd600:
case 0xd700:
return read_d6(addr);
case 0xd800:
case 0xd900:
case 0xda00:
case 0xdb00:
return read_colorram(addr);
case 0xdc00:
return read_cia1(addr);
case 0xdd00:
return read_cia2(addr);
case 0xde00:
return read_io1(addr);
case 0xdf00:
return read_io2(addr);
}
return 0xff;
}
static BYTE peek_bank_io(ADDRESS addr)
{
switch (addr &= 0xff00) {
case 0xd000:
case 0xd100:
case 0xd200:
case 0xd300:
return read_vic(addr); /* FIXME */
case 0xd400:
case 0xd500:
return read_sid(addr);
case 0xd600:
case 0xd700:
return read_d6(addr); /* FIXME */
case 0xd800:
case 0xd900:
case 0xda00:
case 0xdb00:
return read_colorram(addr);
case 0xdc00:
return peek_cia1(addr);
case 0xdd00:
return peek_cia2(addr);
case 0xde00:
return read_io1(addr); /* FIXME */
case 0xdf00:
return read_io2(addr); /* FIXME */
}
return 0xff;
}
/* ------------------------------------------------------------------------- */
/* Exported banked memory access functions for the monitor. */
static const char *banknames[] =
{
"default", "cpu", "ram", "rom", "io", "cart", NULL
};
static int banknums[] =
{
1, 0, 1, 2, 3, 4
};
const char **mem_bank_list(void)
{
return banknames;
}
int mem_bank_from_name(const char *name)
{
int i = 0;
while (banknames[i]) {
if (!strcmp(name, banknames[i])) {
return banknums[i];
}
i++;
}
return -1;
}
BYTE mem_bank_read(int bank, ADDRESS addr)
{
switch (bank) {
case 0: /* current */
return mem_read(addr);
break;
case 3: /* io */
if (addr >= 0xd000 && addr < 0xe000) {
return read_bank_io(addr);
}
case 4: /* cart */
if (addr >= 0x8000 && addr <= 0x9FFF) {
return roml_banks[addr & 0x1fff];
}
if (addr >= 0xA000 && addr <= 0xBFFF) {
return romh_banks[addr & 0x1fff];
}
case 2: /* rom */
if (addr >= 0xA000 && addr <= 0xBFFF) {
return basic_rom[addr & 0x1fff];
}
if (addr >= 0xD000 && addr <= 0xDfff) {
return chargen_rom[addr & 0x1fff];
}
if (addr >= 0xE000 && addr <= 0xffff) {
return kernal_rom[addr & 0x1fff];
}
case 1: /* ram */
}
return ram[addr];
}
BYTE mem_bank_peek(int bank, ADDRESS addr)
{
switch (bank) {
case 0: /* current */
return mem_read(addr); /* FIXME */
break;
case 3: /* io */
if (addr >= 0xd000 && addr < 0xe000) {
return peek_bank_io(addr);
}
}
return mem_bank_read(bank, addr);
}
void mem_bank_write(int bank, ADDRESS addr, BYTE byte)
{
switch (bank) {
case 0: /* current */
mem_store(addr, byte);
return;
case 3: /* io */
if (addr >= 0xd000 && addr < 0xe000) {
store_bank_io(addr, byte);
return;
}
case 2: /* rom */
if (addr >= 0xA000 && addr <= 0xBFFF) {
return;
}
if (addr >= 0xD000 && addr <= 0xDfff) {
return;
}
if (addr >= 0xE000 && addr <= 0xffff) {
return;
}
case 1: /* ram */
}
ram[addr] = byte;
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.