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

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

/*
 * traps.c - Allow VICE to replace ROM code with C function calls.
 *
 * Written by
 *   Teemu Rantanen (tvr@cs.hut.fi)
 *   Jarkko Sonninen (sonninen@lut.fi)
 *   Ettore Perazzoli (ettore@comm2000.it)
 *
 * 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.
 *
 */

#include "vice.h"

#include <stdio.h>
#include <stdlib.h>
#include <memory.h>

#include "traps.h"
#include "maincpu.h"
#include "mem.h"
#include "interrupt.h"
#include "resources.h"
#include "cmdline.h"
#include "utils.h"

/* #define DEBUG_TRAPS */

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

typedef struct _traplist_t {
    struct _traplist_t *next;
    const trap_t *trap;
} traplist_t;

static traplist_t *traplist;

static int install_trap(const trap_t *t);
static int remove_trap(const trap_t *t);

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

/* Trap-related resources.  */

/* Flag: Should we avoid installing traps at all?  */
static int no_traps_enabled;

static int set_no_traps_enabled(resource_value_t v)
{
    int new_value = (int) v;

    if ((!no_traps_enabled && new_value) || (no_traps_enabled && !new_value)) {
        if (new_value) {
            /* Traps have been disabled.  */
            traplist_t *p;

            for (p = traplist; p != NULL; p = p->next)
                remove_trap(p->trap);
        } else {
            /* Traps have been enabled.  */
            traplist_t *p;

            for (p = traplist; p != NULL; p = p->next)
                install_trap(p->trap);
        }
    }

    no_traps_enabled = new_value;
    return 0;
}

static resource_t resources[] = {
    { "NoTraps", RES_INTEGER, (resource_value_t) 0,
      (resource_value_t) &no_traps_enabled, set_no_traps_enabled },
    { NULL }
};

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

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

/* Trap-related command-line options.  */

static cmdline_option_t cmdline_options[] = {
    { "-traps", SET_RESOURCE, 0, NULL, NULL, "NoTraps", (resource_value_t) 0,
      NULL, "Enable Kernal serial traps for fast serial/tape emulation" },
    { "+traps", SET_RESOURCE, 0, NULL, NULL, "NoTraps", (resource_value_t) 1,
      NULL, "Do not install any Kernal traps" },
    { NULL }
};

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

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

void traps_init(void)
{
    traplist = NULL;
}

static int install_trap(const trap_t *t)
{
    int i;

    DEBUG(("TRAPS: Patching ROM for trap `%s' at $%04X\n",
           t->name, t->address));

    for (i = 0; i < 3; i++) {
	if (read_rom(t->address + i) != t->check[i]) {
	    printf("TRAPS: Incorrect checkbyte for trap `%s'.  Not installed.\n",
                   t->name);
	    return -1;
	}
    }

    /* BRK (0x00) is trap-opcode.  */
    store_rom(t->address, 0x00);

    return 0;
}

int traps_add(const trap_t *t)
{
    traplist_t *p;

    DEBUG(("TRAPS: Adding trap `%s' at $%04X (enabled=%d).\n", t->name, t->address, !no_traps_enabled));

    p = (traplist_t *) xmalloc (sizeof (traplist_t));
    p->next = traplist;
    p->trap = t;
    traplist = p;

    if (!no_traps_enabled)
        install_trap(t);

    return 0;
}

static int remove_trap(const trap_t *t)
{
    DEBUG(("TRAPS: Removing trap `%s' at $%04X.\n", t->name, t->address));

    if (read_rom(t->address) != 0x00) {
	printf("TRAPS: No trap `%s' installed?\n", t->name);
        return -1;
    }

    store_rom(t->address, t->check[0]);
    return 0;
}

int traps_remove(const trap_t *t)
{
    traplist_t *p = traplist, *prev = NULL;

    while (p) {
	if (p->trap->address == t->address)
	    break;
	prev = p;
	p = p->next;
    }

    if (!p) {
	printf("TRAPS: Trap `%s' not found.\n", t->name);
	return -1;
    }

    if (prev)
	prev->next = p->next;
    else
	traplist = p ->next;

    free(p);

    if (!no_traps_enabled)
        remove_trap(t);

    return 0;
}

int traps_handler(void)
{
    traplist_t *p = traplist;
    unsigned int pc = MOS6510_REGS_GET_PC(&maincpu_regs);

    DEBUG(("TRAPS: Checking for trap at PC=$%04X, p=%p.\n", maincpu_regs.pc,p));

    while (p) {
        DEBUG(("TRAPS: check Address %04X\n", p->trap->address));
	if (p->trap->address == pc) {
            /* This allows the trap function to remove traps.  */
            ADDRESS resume_address = p->trap->resume_address;

            DEBUG(("TRAPS: Found %s\n", p->trap->name));
	    (*p->trap->func)();
            /* XXX ALERT!  `p' might not be valid anymore here, because
               `p->trap->func()' might have removed all the traps.  */
            MOS6510_REGS_SET_PC(&maincpu_regs, resume_address);
            return 0;
	}
	p = p->next;
    }

    return -1;
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.