ftp.nice.ch/pub/next/tools/emulators/vice.0.15.0.NeXT.sd.tgz#/vice-0.15.0/src/c128/c128mem.c

This is c128mem.c in view mode; [Download] [Up]

/*
 * c128mem.c -- Memory handling for the C128 emulator.
 *
 * Written by
 *  Ettore Perazzoli (ettore@comm2000.it)
 *
 * Based on the original work in VICE 0.11.0 by
 *  Jouko Valta (jopi@stekt.oulu.fi)
 *
 * 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.
 *
 */

/* This is just a quick hack!  */

/* TODO:
   - cartridge support;
   - maybe C64 mode?  */

#include "vice.h"

#include <stdio.h>

#include "vmachine.h"
#include "true1541.h"
#include "c128mem.h"
#include "resources.h"
#include "cmdline.h"
#include "c64cia.h"
#include "sid.h"
#include "memutils.h"
#include "maincpu.h"
#include "parallel.h"
#include "c64tpi.h"
#include "tapeunit.h"
#include "mon.h"
#include "utils.h"
#include "vdc.h"
#include "emuid.h"
#include "rs232.h"
#include "../c64/vicii.h"

#ifdef HAVE_RS232
#include "c64acia.h"
#endif

/* #define DEBUG_MMU */

#ifdef DEBUG_MMU
#define DEBUG(x) printf x
#else
#define DEBUG(x)
#endif

/* ------------------------------------------------------------------------- */

/* C128 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;

/* 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;

#ifdef HAVE_RS232
/* Flag: Do we enable the $DE** ACIA RS232 interface emulation?  */
static int acia_de_enabled;

/* Flag: Do we enable the $D7** ACIA RS232 interface emulation?  */
static int acia_d7_enabled;
#endif

/* 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 {
        emu_id_enabled = 1;
        return 0;
    }
}

static int set_ieee488_enabled(resource_value_t v)
{
    if (!(int) v) {
        ieee488_enabled = 0;
        return 0;
    } else if (!reu_enabled) {
        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) {
        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;
    }
}

#ifdef HAVE_RS232
static int set_acia_d7_enabled(resource_value_t v)
{
    acia_d7_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 },
#ifdef HAVE_RS232
    { "AciaDE", RES_INTEGER, (resource_value_t) 0,
     (resource_value_t *) & acia_de_enabled, set_acia_de_enabled },
    { "AciaD7", RES_INTEGER, (resource_value_t) 0,
     (resource_value_t *) & acia_d7_enabled, set_acia_d7_enabled },
#endif
    { NULL }
};

int c128_mem_init_resources(void)
{
    return resources_register(resources);
}

/* ------------------------------------------------------------------------- */

/* C128 memory-related command-line options.  */

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, "AciaD7", (resource_value_t) 1,
      NULL, "Enable the $D7** ACIA RS232 interface emulation" },
    { "+acia2", SET_RESOURCE, 0, NULL, NULL, "AciaD7", (resource_value_t) 0,
      NULL, "Disable the $D7** ACIA RS232 interface emulation" },
#endif
#endif
    { NULL }
};

int c128_mem_init_cmdline_options(void)
{
    return cmdline_register_options(cmdline_options);
}

/* ------------------------------------------------------------------------- */

/* Number of possible video banks (16K each).  */
#define NUM_VBANKS      4

/* The C128 memory.  */
BYTE ram[C128_RAM_SIZE];
BYTE basic_rom[C128_BASIC_ROM_SIZE + C128_EDITOR_ROM_SIZE];
BYTE kernal_rom[C128_KERNAL_ROM_SIZE];
BYTE chargen_rom[C128_CHARGEN_ROM_SIZE];

/* Size of RAM...  */
int ram_size = C128_RAM_SIZE;

/* Currently selected RAM bank.  */
static BYTE *ram_bank;

/* Memory configuration.  */
static int chargen_in;
static int basic_lo_in;
static int basic_hi_in;
static int kernal_in;
static int editor_in;
static int io_in;

/* Shared memory.  */
static ADDRESS top_shared_limit, bottom_shared_limit;

/* Tape sense status: 1 = some button pressed, 0 = no buttons pressed.  */
static int tape_sense = 0;

/* Pointers to pages 0 and 1 (which can be physically placed anywhere).  */
BYTE *page_zero, *page_one;

static BYTE mmu[11];

/* Flag: nonzero if the Kernal and BASIC ROMs have been loaded.  */
int rom_loaded = 0;

/* Memory read and write tables.  These are non-static to allow the CPU code
   to access them.  */
store_func_ptr_t _mem_write_tab[0x101];
read_func_ptr_t _mem_read_tab[0x101];
store_func_ptr_t *_mem_write_tab_ptr = _mem_write_tab;
read_func_ptr_t *_mem_read_tab_ptr = _mem_read_tab;

/* Fake BIOS initialization.  This is required because the real C128 is
   normally booted by the Z80, which we currently don't emulate at all.  */
static BYTE biostab[] = {
    0x78, 0xa9, 0x3e, 0x8d, 0x00, 0xff, 0xa9, 0xb0, 0x8d, 0x05,
    0xd5, 0xea, 0x58, 0x60, 0x00, 0x00, 0xf3, 0x3e, 0x3e, 0x32,
    0x00, 0xff, 0x01, 0x05, 0xd5, 0x3e, 0xb1, 0xed, 0x79, 0x00,
    0xcf
};

/* Current video bank (0, 1, 2 or 3).  */
static int vbank;

/* ------------------------------------------------------------------------- */

/* MMU Implementation.  */

inline BYTE REGPARM1 read_mmu(ADDRESS addr)
{
    addr &= 0xff;

    if (addr < 0xb) {
        if (addr == 5) {
            /* 0x80 = 40/80 key released.  */
            return mmu[5] | 0x80;
        } else {
            return mmu[addr];
        }
    } else {
        return 0xf;
    }
}

inline void REGPARM2 store_mmu(ADDRESS address, BYTE value)
{
    address &= 0xff;

    if (address < 0xb) {
        mmu[address] = value;

        switch (address) {
          case 0:
            /* Configuration register (CR).  */
            {
                io_in = !(value & 0x1);
                basic_lo_in = !(value & 0x2);
                basic_hi_in = !(value & 0xc);
                kernal_in = chargen_in = editor_in = !(value & 0x30);
                /* (We handle only 128K here.)  */
                ram_bank = ram + (((long) value & 0x40) << 10);
                DEBUG(("MMU: Store CR = $%02x\n", value));
                DEBUG(("MMU: RAM bank at $%05X\n", ram_bank - ram));
            }
            break;

          case 6:
            /* RAM configuration register (RCR).  */
            {
                int shared_size;

                vic_ii_set_ram_base(ram + ((value & 0xc0) << 2));

                DEBUG(("MMU: Store RCR = $%02x\n", value));
                DEBUG(("MMU: VIC-II base at $%05X\n", ((value & 0xc0) << 2)));

                if (value & 0x3)
                    shared_size = 0x1000 << (value & 0x3);
                else
                    shared_size = 0x400;

                /* Share high memory?  */
                if (value & 0x8) {
                    top_shared_limit = 0xffff - shared_size;
                    DEBUG(("MMU: Sharing high RAM from $%04X\n",
                           top_shared_limit + 1));
                } else {
                    top_shared_limit = 0xffff;
                    DEBUG(("MMU: No high shared RAM\n"));
                }

                /* Share low memory?  */
                if (value & 0x4) {
                    bottom_shared_limit = shared_size;
                    DEBUG(("MMU: Sharing low RAM up to $%04X\n",
                           bottom_shared_limit - 1));
                } else {
                    bottom_shared_limit = 0;
                    DEBUG(("MMU: No low shared RAM\n"));
                }
            }
            break;

          case 5:
            value = (value & 0x7f) | 0x30;
            if ((value & 0x41) != 0x01)
                fprintf(stderr,
                        "MMU: Attempted accessing unimplemented mode: $D505 <- $%02X.\n",
                        value);
            break;

          case 7:
          case 8:
          case 9:
          case 10:
            page_zero = (ram + (mmu[0x8] & 0x1 ? 0x10000 : 0x00000)
                         + (mmu[0x7] << 8));
            page_one = (ram + (mmu[0xa] & 0x1 ? 0x10000 : 0x00000)
                        + (mmu[0x9] << 8));
            DEBUG(("MMU: Page Zero at $%05X, Page One at $%05X\n",
                   page_zero - ram, page_one - ram));
            break;
        }
    }
}

/* ------------------------------------------------------------------------- */

/* External memory access functions.  */

BYTE REGPARM1 read_basic(ADDRESS addr)
{
    return basic_rom[addr - 0x4000];
}

void REGPARM2 store_basic(ADDRESS addr, BYTE value)
{
    basic_rom[addr - 0x4000] = value;
}

BYTE REGPARM1 read_kernal(ADDRESS addr)
{
    return kernal_rom[addr & 0x1fff];
}

void REGPARM2 store_kernal(ADDRESS addr, BYTE value)
{
    kernal_rom[addr & 0x1fff] = value;
}

BYTE REGPARM1 read_chargen(ADDRESS addr)
{
    return chargen_rom[addr & 0xffff];
}

BYTE REGPARM1 read_rom(ADDRESS addr)
{
    switch (addr & 0xf000) {
      case 0xe000:
      case 0xf000:
        return read_kernal(addr);
      case 0x4000:
      case 0x5000:
      case 0x6000:
      case 0x7000:
      case 0x8000:
      case 0x9000:
      case 0xa000:
      case 0xb000:
        return read_basic(addr);
    }

    return 0;
}

void REGPARM2 store_rom(ADDRESS addr, BYTE value)
{
    switch (addr & 0xf000) {
      case 0xe000:
      case 0xf000:
        store_kernal(addr, value);
        break;
      case 0x4000:
      case 0x5000:
      case 0x6000:
      case 0x7000:
      case 0x8000:
      case 0x9000:
      case 0xa000:
      case 0xb000:
        store_basic(addr, value);
        break;
    }
}

/* 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[addr >> 8](addr);
}

/* ------------------------------------------------------------------------- */

/* CPU Memory interface.  */

/* The MMU can basically do the following:

   - select one of the two (four) memory banks as the standard
   (non-shared) memory;

   - turn ROM and I/O on and off;

   - enable/disable top/bottom shared RAM (from 1K to 16K, so bottom
   shared RAM cannot go beyond $3FFF and top shared RAM cannot go
   under $C000);

   - move pages 0 and 1 to any physical address.  */

#define READ_TOP_SHARED(addr)                           \
    ((addr) > top_shared_limit ? ram[(addr)]            \
                                : ram_bank[(addr)])

#define STORE_TOP_SHARED(addr, value)                           \
    ((addr) > top_shared_limit ? (ram[(addr)] = (value))        \
                               : (ram_bank[(addr)] = (value)))

#define READ_BOTTOM_SHARED(addr)                        \
    ((addr) < bottom_shared_limit ? ram[(addr)]         \
                                  : ram_bank[(addr)])

#define STORE_BOTTOM_SHARED(addr, value)                                \
    ((addr) < bottom_shared_limit ? (ram[(addr)] = (value))             \
                                  : (ram_bank[(addr)] = (value)))

BYTE REGPARM1 read_zero(ADDRESS addr)
{
    return page_zero[addr];
}

void REGPARM2 store_zero(ADDRESS addr, BYTE value)
{
    page_zero[addr] = value;
}

static BYTE REGPARM1 read_one(ADDRESS addr)
{
    return page_one[addr - 0x100];
}

static void REGPARM2 store_one(ADDRESS addr, BYTE value)
{
    page_one[addr - 0x100] = value;
}


/* $0200 - $3FFF: RAM (normal or shared).  */

static BYTE REGPARM1 read_lo(ADDRESS addr)
{
    return READ_BOTTOM_SHARED(addr);
}

static void REGPARM2 store_lo(ADDRESS addr, BYTE value)
{
    STORE_BOTTOM_SHARED(addr, value);
}


/* $4000 - $7FFF: RAM or low BASIC ROM.  */

static BYTE REGPARM1 read_basic_lo(ADDRESS addr)
{
    if (basic_lo_in)
        return basic_rom[addr - 0x4000];
    else
        return ram_bank[addr];
}

static void REGPARM2 store_basic_lo(ADDRESS addr, BYTE value)
{
    ram_bank[addr] = value;
}


/* $8000 - $BFFF: RAM or high BASIC ROM.  */

static BYTE REGPARM1 read_basic_hi(ADDRESS addr)
{
    if (basic_hi_in) {
        return basic_rom[addr - 0x4000];
    } else
        return ram_bank[addr];
}

static void REGPARM2 store_basic_hi(ADDRESS addr, BYTE value)
{
    ram_bank[addr] = value;
}


/* $C000 - $CFFF: RAM (normal or shared) or Editor ROM.  */

static BYTE REGPARM1 read_editor(ADDRESS addr)
{
    if (editor_in)
        return basic_rom[addr - 0x4000];
    else
        return READ_TOP_SHARED(addr);
}

static void REGPARM2 store_editor(ADDRESS addr, BYTE value)
{
    STORE_TOP_SHARED(addr, value);
}

static BYTE REGPARM1 read_d0xx(ADDRESS addr)
{
    if (io_in)
        return read_vic(addr);
    else if (chargen_in)
        return chargen_rom[addr];
    else
        return READ_TOP_SHARED(addr);
}

static void REGPARM2 store_d0xx(ADDRESS addr, BYTE value)
{
    if (io_in)
        store_vic(addr, value);
    else
        STORE_TOP_SHARED(addr, value);
}

static BYTE REGPARM1 read_d4xx(ADDRESS addr)
{
    if (io_in)
        return read_sid(addr);
    else if (chargen_in)
        return chargen_rom[addr];
    else
        return READ_TOP_SHARED(addr);
}

static void REGPARM2 store_d4xx(ADDRESS addr, BYTE value)
{
    if (io_in)
        store_sid(addr, value);
    else
        STORE_TOP_SHARED(addr, value);
}

static BYTE REGPARM1 read_d5xx(ADDRESS addr)
{
    if (io_in)
        return read_mmu(addr);
    else if (chargen_in)
        return chargen_rom[addr];
    else
        return READ_TOP_SHARED(addr);
}

static void REGPARM2 store_d5xx(ADDRESS addr, BYTE value)
{
    if (io_in)
        store_mmu(addr, value);
    else
        STORE_TOP_SHARED(addr, value);
}

static BYTE REGPARM1 read_d6xx(ADDRESS addr)
{
    if (io_in)
        return read_vdc(addr);
    else if (chargen_in)
        return chargen_rom[addr];
    else
        return READ_TOP_SHARED(addr);
}

static void REGPARM2 store_d6xx(ADDRESS addr, BYTE value)
{
    if (io_in)
        store_vdc(addr, value);
    else
        STORE_TOP_SHARED(addr, value);
}

static BYTE REGPARM1 read_d7xx(ADDRESS addr)
{
    if (io_in) {
#if 0                           /*def HAVE_RS232 */
        if (acia_d7_enabled)
            return read_acia2(addr);
        else
#endif
            return 0xff;
    } else if (chargen_in)
        return chargen_rom[addr];
    else
        return READ_TOP_SHARED(addr);
}

static void REGPARM2 store_d7xx(ADDRESS addr, BYTE value)
{
    if (io_in) {
#if 0                           /*def HAVE_RS232 */
        if (acia_d7_enabled) {
            store_acia2(addr, value);
        }
#endif
    } else
        STORE_TOP_SHARED(addr, value);
}

static BYTE REGPARM1 read_d8xx(ADDRESS addr)
{
    if (io_in)
        return read_colorram(addr);
    else if (chargen_in)
        return chargen_rom[addr];
    else
        return READ_TOP_SHARED(addr);
}

static void REGPARM2 store_d8xx(ADDRESS addr, BYTE value)
{
    if (io_in)
        store_colorram(addr, value);
    else
        STORE_TOP_SHARED(addr, value);
}

static BYTE REGPARM1 read_dcxx(ADDRESS addr)
{
    if (io_in)
        return read_cia1(addr);
    else if (chargen_in)
        return chargen_rom[addr];
    else
        return READ_TOP_SHARED(addr);
}

static void REGPARM2 store_dcxx(ADDRESS addr, BYTE value)
{
    if (io_in)
        store_cia1(addr, value);
    else
        STORE_TOP_SHARED(addr, value);
}

static BYTE REGPARM1 read_ddxx(ADDRESS addr)
{
    if (io_in)
        return read_cia2(addr);
    else if (chargen_in)
        return chargen_rom[addr];
    else
        return READ_TOP_SHARED(addr);
}

static void REGPARM2 store_ddxx(ADDRESS addr, BYTE value)
{
    if (io_in)
        store_cia2(addr, value);
    else
        STORE_TOP_SHARED(addr, value);
}

/* $E000 - $FFFF: RAM or Kernal.  */
static BYTE REGPARM1 read_hi(ADDRESS addr)
{
    if (kernal_in)
        return kernal_rom[addr & 0x1fff];
    else
        return READ_TOP_SHARED(addr);
}

/* $E000 - $FEFF: RAM or Kernal.  */
static void REGPARM2 store_hi(ADDRESS addr, BYTE value)
{
    STORE_TOP_SHARED(addr, value);
}


/* $FF00 - $FFFF: RAM or Kernal, with MMU at $FF00 - $FF04.  */

static BYTE REGPARM1 read_ffxx(ADDRESS addr)
{
    if (addr == 0xff00)
        return mmu[0];
    else if (kernal_in)
        return kernal_rom[addr & 0x1fff];
    else
        return READ_TOP_SHARED(addr);
}

static void REGPARM2 store_ffxx(ADDRESS addr, BYTE value)
{
    if (addr == 0xff00)
        store_mmu(0, value);
    else if (addr <= 0xff04)
        store_mmu(0, mmu[addr & 0xf]);
    else
        STORE_TOP_SHARED(addr, value);
}

static BYTE REGPARM1 read_empty_io(ADDRESS addr)
{
    if (io_in)
        return 0xff;
    else if (chargen_in)
        return chargen_rom[addr - 0xd000];
    else
        return READ_TOP_SHARED(addr);
}

static void REGPARM2 store_empty_io(ADDRESS addr, BYTE value)
{
    if (!io_in)
        STORE_TOP_SHARED(addr, value);
}

/* ------------------------------------------------------------------------- */
/* those are approximate copies from the c64 versions....
 * they leave out the cartridge support
 */

void REGPARM2 store_io1(ADDRESS addr, BYTE value)
{
    if (!io_in) {
        STORE_TOP_SHARED(addr, value);
    } else {
#ifdef HAVE_RS232
        if (acia_de_enabled)
            store_acia1(addr & 0x03, value);
#endif
    }
    return;
}

BYTE REGPARM1 read_io1(ADDRESS addr)
{
    if (io_in) {
#ifdef HAVE_RS232
        if (acia_de_enabled)
            return read_acia1(addr & 0x03);
#endif
        return 0xff;            /* rand(); - C64 has rand(), which is correct? */
    } else if (chargen_in)
        return chargen_rom[addr - 0xd000];
    else
        return READ_TOP_SHARED(addr);
}

void REGPARM2 store_io2(ADDRESS addr, BYTE value)
{
    if (!io_in) {
        STORE_TOP_SHARED(addr, value);
    } else {
        if (ieee488_enabled) {
            store_tpi(addr & 0x07, value);
        }
    }
    return;
}

BYTE REGPARM1 read_io2(ADDRESS addr)
{
    if (io_in) {
        if (emu_id_enabled && addr >= 0xdfa0) {
            addr &= 0xff;
            if (addr == 0xff)
                emulator_id[addr - 0xa0] ^= 0xff;
            return emulator_id[addr - 0xa0];
        }
        if (ieee488_enabled) {
            return read_tpi(addr & 0x07);
        }
        return 0xff;  /* rand(); - C64 has rand(), which is correct? */
    } else if (chargen_in)
        return chargen_rom[addr - 0xd000];
    else
        return READ_TOP_SHARED(addr);
}

/* ------------------------------------------------------------------------- */

void initialize_memory(void)
{
    int i;

    _mem_read_tab[0] = read_zero;
    _mem_write_tab[0] = store_zero;
    _mem_read_tab[1] = read_one;
    _mem_write_tab[1] = store_one;

    for (i = 0x02; i <= 0x3f; i++) {
        _mem_read_tab[i] = read_lo;
        _mem_write_tab[i] = store_lo;
    }

    for (i = 0x40; i <= 0x7f; i++) {
        _mem_read_tab[i] = read_basic_lo;
        _mem_write_tab[i] = store_basic_lo;
    }

    for (i = 0x80; i <= 0xbf; i++) {
        _mem_read_tab[i] = read_basic_hi;
        _mem_write_tab[i] = store_basic_hi;
    }

    for (i = 0xc0; i <= 0xcf; i++) {
        _mem_read_tab[i] = read_editor;
        _mem_write_tab[i] = store_editor;
    }

    for (i = 0xd0; i <= 0xd3; i++) {
        _mem_read_tab[i] = read_d0xx;
        _mem_write_tab[i] = store_d0xx;
    }

    _mem_read_tab[0xd4] = read_d4xx;
    _mem_write_tab[0xd4] = store_d4xx;
    _mem_read_tab[0xd5] = read_d5xx;
    _mem_write_tab[0xd5] = store_d5xx;
    _mem_read_tab[0xd6] = read_d6xx;
    _mem_write_tab[0xd6] = store_d6xx;

    _mem_read_tab[0xd7] = read_d7xx;    /* read_empty_io; */
    _mem_write_tab[0xd7] = store_d7xx;  /* store_empty_io; */

    _mem_read_tab[0xd8] = _mem_read_tab[0xd9] = read_d8xx;
    _mem_read_tab[0xda] = _mem_read_tab[0xdb] = read_d8xx;
    _mem_write_tab[0xd8] = _mem_write_tab[0xd9] = store_d8xx;
    _mem_write_tab[0xda] = _mem_write_tab[0xdb] = store_d8xx;

    _mem_read_tab[0xdc] = read_dcxx;
    _mem_write_tab[0xdc] = store_dcxx;
    _mem_read_tab[0xdd] = read_ddxx;
    _mem_write_tab[0xdd] = store_ddxx;

    _mem_read_tab[0xde] = read_io1;
    _mem_write_tab[0xde] = store_io1;

    _mem_read_tab[0xdf] = read_io2;
    _mem_write_tab[0xdf] = store_io2;

    for (i = 0xe0; i <= 0xfe; i++) {
        _mem_read_tab[i] = read_hi;
        _mem_write_tab[i] = store_hi;
    }

    _mem_read_tab[0xff] = read_ffxx;
    _mem_write_tab[0xff] = store_ffxx;

    _mem_read_tab[0x100] = _mem_read_tab[0x0];
    _mem_write_tab[0x100] = _mem_write_tab[0x0];

    /* FIXME?  Is this the real configuration?  */
    basic_lo_in = basic_hi_in = kernal_in = editor_in = 1;
    io_in = 1;
    chargen_in = 0;
    top_shared_limit = 0xffff;
    bottom_shared_limit = 0x0000;
    ram_bank = ram;
    page_zero = ram;
    page_one = ram + 0x100;
}

/* ------------------------------------------------------------------------- */

/* 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 < 0x20000; 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();

    page_zero = ram;
    page_one = ram + 0x100;

    initialize_memory();

    /* Load Kernal ROM.  */
    if (mem_load_sys_file(kernal_rom_name,
                          kernal_rom, C128_KERNAL_ROM_SIZE,
                          C128_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 < C128_KERNAL_ROM_SIZE; i++)
        sum += kernal_rom[i];

    id = read_rom(0xff80);

    printf("Kernal rev #%d.\n", id);
    if (id == 1
        && sum != C128_KERNAL_CHECKSUM_R01
        && sum != C128_KERNAL_CHECKSUM_R01SWE
        && sum != C128_KERNAL_CHECKSUM_R01GER)
        fprintf(stderr, "Warning: Kernal image may be corrupted. Sum: %d\n",
                sum);

    /* Load Basic ROM.  */
    if (mem_load_sys_file(basic_rom_name,
                   basic_rom, C128_BASIC_ROM_SIZE + C128_EDITOR_ROM_SIZE,
                       C128_BASIC_ROM_SIZE + C128_EDITOR_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 < C128_BASIC_ROM_SIZE; i++)
        sum += basic_rom[i];

    if (sum != C128_BASIC_CHECKSUM_85 && sum != C128_BASIC_CHECKSUM_86)
        fprintf(stderr,
                "Warning: Unknown Basic image `%s'.  Sum: %d ($%04X)\n",
                basic_rom_name, sum, sum);

    /* Check Editor ROM.  */
    for (i = C128_BASIC_ROM_SIZE, sum = 0;
         i < C128_BASIC_ROM_SIZE + C128_EDITOR_ROM_SIZE;
         i++)
        sum += basic_rom[i];

    if (id == 01
        && sum != C128_EDITOR_CHECKSUM_R01
        && sum != C128_EDITOR_CHECKSUM_R01SWE
        && sum != C128_EDITOR_CHECKSUM_R01GER) {
        fprintf(stderr, "Warning: EDITOR image may be corrupted. Sum: %d\n",
                sum);
        fprintf(stderr, "Check your Basic ROM\n");
    }
    /* Load chargen ROM.  */
    if (mem_load_sys_file(chargen_rom_name,
                          chargen_rom, C128_CHARGEN_ROM_SIZE,
                          C128_CHARGEN_ROM_SIZE) < 0) {
        fprintf(stderr, "Couldn't load character ROM `%s'.\n",
                chargen_rom_name);
        return -1;
    }
    /* Fake BIOS initialization.  This is needed because the real C128 is
       initialized by the Z80, which we currently do not implement.  */
    memcpy(ram + 0xffd0, biostab, sizeof(biostab));

    rom_loaded = 1;
    return 0;
}

/* ------------------------------------------------------------------------- */

/* Change the current video bank.  */
void mem_set_vbank(int new_vbank)
{
    /* FIXME: Still to do.  */
}

void mem_toggle_watchpoints(int flag)
{
    /* FIXME: Still to do.  */
}

/* Set the tape sense status.  */
void mem_set_tape_sense(int sense)
{
    tape_sense = sense;
}

/* 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;
}

/* ------------------------------------------------------------------------- */

void mem_get_basic_text(ADDRESS * start, ADDRESS * end)
{
    if (start != NULL)
        *start = ram[0x2b] | (ram[0x2c] << 8);
    if (end != NULL)
        *end = ram[0x1210] | (ram[0x1211] << 8);
}

void mem_set_basic_text(ADDRESS start, ADDRESS end)
{
    ram[0x2b] = ram[0xac] = start & 0xff;
    ram[0x2c] = ram[0xad] = start >> 8;
    ram[0x1210] = end & 0xff;
    ram[0x1211] = end >> 8;
}

/* ------------------------------------------------------------------------- */

int mem_rom_trap_allowed(ADDRESS addr)
{
    return 1;
}

/* ------------------------------------------------------------------------- */

/* 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_d0xx(addr, byte);
        break;
      case 0xd400:
        store_d4xx(addr, byte);
        break;
      case 0xd500:
        store_d5xx(addr, byte);
        break;
      case 0xd600:
        store_d6xx(addr, byte);
        break;
      case 0xd700:
        store_d7xx(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_d0xx(addr);
      case 0xd400:
        return read_d4xx(addr);
      case 0xd500:
        return read_d5xx(addr);
      case 0xd600:
        return read_d6xx(addr);
      case 0xd700:
        return read_d7xx(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_d0xx(addr); /* FIXME */
      case 0xd400:
        return read_d4xx(addr); /* FIXME */
      case 0xd500:
        return read_d5xx(addr); /* FIXME */
      case 0xd600:
        return read_d6xx(addr); /* FIXME */
      case 0xd700:
        return read_d7xx(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", "ram1", 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 4:                   /* ram1 */
        return ram[addr + 0x10000];
      case 3:                   /* io */
        if (addr >= 0xd000 && addr < 0xe000) {
            return read_bank_io(addr);
        }
      case 2:                   /* rom */
        if (addr >= 0x4000 && addr <= 0xCFFF) {
            return basic_rom[addr - 0x4000];
        }
        if (addr >= 0xD000 && addr <= 0xDFFF) {
            return chargen_rom[addr & 0x0fff];
        }
        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 4:                   /* ram1 */
        ram[addr + 0x10000] = byte;
        return;
      case 3:                   /* io */
        if (addr >= 0xd000 && addr < 0xe000) {
            store_bank_io(addr, byte);
            return;
        }
      case 2:                   /* rom */
        if (addr >= 0x4000 && addr <= 0xCFFF) {
            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.