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

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

/*
 * autostart.c - automatic image loading and starting
 *
 * Written by
 *  Teemu Rantanen      (tvr@cs.hut.fi)
 *  Ettore Perazzoli    (ettore@comm2000.it)
 *
 * Patches by
 *  André Fachat        (a.fachat@physik.tu-chemnitz.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.
 *
 */

#include "vice.h"

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

#include "autostart.h"

#include "attach.h"
#include "drive.h"
#include "interrupt.h"
#include "kbdbuf.h"
#include "mem.h"
#include "resources.h"
#include "serial.h"
#include "tape.h"
#include "ui.h"
#include "utils.h"
#include "vmachine.h"
#include "warn.h"


/* Kernal addresses.  Set by `autostart_init()'.  */

static int blnsw;		/* Cursor Blink enable: 0 = Flash Cursor */
static int pnt;			/* Pointer: Current Screen Line Address */
static int pntr;		/* Cursor Column on Current Line */
static int lnmx;		/* Physical Screen Line Length */

/* Current state of the autostart routine.  */
static enum {
    AUTOSTART_NONE,
    AUTOSTART_ERROR,
    AUTOSTART_HASTAPE,
    AUTOSTART_LOADINGTAPE,
    AUTOSTART_HASDISK,
    AUTOSTART_LOADINGDISK,
    AUTOSTART_DONE
} autostartmode = AUTOSTART_NONE;

/* Warnings.  */
static warn_t *pwarn = NULL;

/* Flag: was true 1541 emulation turned on when we started booting the disk
   image?  */
static int orig_true1541_state = 0;

/* Program name to load. NULL if default */
static char *autostart_program_name = NULL;

/* Minimum number of cycles before we feed BASIC with commands.  */
static CLOCK min_cycles;

/* Flag: Do we want to switch true 1541 emulation on/off during autostart?  */
static int handle_true1541;

/* Flag: autostart is initialized.  */
static int autostart_enabled = 0;

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

/* Deallocate program name if we have one */
static void deallocate_program_name(void)
{
    if (autostart_program_name) {
	free(autostart_program_name);
	autostart_program_name = NULL;
    }
}

static enum { YES, NO, NOT_YET } check(const char *s)
{
    int screen_addr = mem_read(pnt) | (mem_read(pnt + 1) << 8);
    int line_length = lnmx < 0 ? -lnmx : mem_read(lnmx) + 1;
    int cursor_column = mem_read(pntr);
    int addr, i;

    if (!kbd_buf_is_empty() || cursor_column != 0 || mem_read(blnsw) != 0)
	return NOT_YET;

    addr = screen_addr - line_length;
    for (i = 0; s[i] != '\0'; i++) {
	if (mem_read((ADDRESS) (addr + i)) != s[i] % 64) {
	    if (mem_read((ADDRESS) (addr + i)) != (BYTE) 32)
		return NO;
	    return NOT_YET;
	}
    }

    return YES;
}

static void set_true1541_mode(int on)
{
    resources_set_value("True1541", (resource_value_t) on);
    ui_update_menus();
}

static int get_true1541_state(void)
{
    int value;

    if (resources_get_value("True1541", (resource_value_t *) & value) < 0)
	return 0;

    return value;
}

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

/* Initialize autostart.  */
int autostart_init(CLOCK _min_cycles, int _handle_true1541,
		   int _blnsw, int _pnt, int _pntr, int _lnmx)
{
    blnsw = _blnsw;
    pnt = _pnt;
    pntr = _pntr;
    lnmx = _lnmx;

    if (!pwarn) {
	pwarn = warn_init("AUTOSTART", 32);
	if (!pwarn)
	    return -1;
    }
    min_cycles = _min_cycles;
    handle_true1541 = _handle_true1541;

    if (_min_cycles)
	autostart_enabled = 1;
    else
	autostart_enabled = 0;

    return 0;
}

void autostart_disable(void)
{
    if (!autostart_enabled)
	return;

    autostartmode = AUTOSTART_ERROR;
    deallocate_program_name();
    warn(pwarn, -1, "disabling autostart");
}

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

/* This function is called by the `serialreceivebyte()' trap as soon as EOF
   is reached.  */
static void disk_eof_callback(void)
{
    if (handle_true1541) {
        if (orig_true1541_state)
            warn(pwarn, -1, "switching true 1541 on");
        set_true1541_mode(orig_true1541_state);
    }

    warn(pwarn, -1, "starting program");

    autostartmode = AUTOSTART_DONE;

    serial_set_eof_callback(NULL);
}

/* This function is called by the `serialattention()' trap before
   returning.  */
static void disk_attention_callback(void)
{
    kbd_buf_feed("run\r");

    serial_set_attention_callback(NULL);

    /* Next step is waiting for end of loading, to turn true 1541 emulation
       on.  */
    serial_set_eof_callback(disk_eof_callback);
}


/* Execute the actions for the current `autostartmode', advancing to the next
   mode if necessary.  */
void autostart_advance(void)
{
    char *tmp;

    if (clk < min_cycles || !autostart_enabled)
	return;

    switch (autostartmode) {
      case AUTOSTART_HASTAPE:
        switch (check("READY.")) {
          case YES:
            warn(pwarn, -1, "loading tape");
            if (autostart_program_name) {
                tmp = concat("load\"", autostart_program_name,
                             "\"\r", NULL);
                kbd_buf_feed(tmp);
                free(tmp);
            } else
                kbd_buf_feed("load\r");
            autostartmode = AUTOSTART_LOADINGTAPE;
            deallocate_program_name();
            break;
          case NO:
            autostart_disable();
            break;
          case NOT_YET:
            break;
        }
        break;
      case AUTOSTART_LOADINGTAPE:
        switch (check("READY.")) {
          case YES:
            warn(pwarn, -1, "starting program");
            kbd_buf_feed("run\r");
            autostartmode = AUTOSTART_DONE;
            break;
          case NO:
            autostart_disable();
            break;
          case NOT_YET:
            break;
        }
        break;
      case AUTOSTART_HASDISK:
        switch (check("READY.")) {
          case YES:
            {
                int no_traps;

                warn(pwarn, -1, "loading disk");
                orig_true1541_state = get_true1541_state();
                if (handle_true1541) {
                    resources_get_value("NoTraps",
					(resource_value_t *) & no_traps);
                    if (!no_traps) {
                        if (orig_true1541_state)
                            warn(pwarn, -1,
                                 "switching true 1541 emulation off");
                        set_true1541_mode(0);
                    } else {
                        if (!orig_true1541_state)
                            warn(pwarn, -1,
                                 "switching true 1541 emulation on");
                        set_true1541_mode(1);
                    }
                } else
                    no_traps = 0;

                if (autostart_program_name) {
                    tmp = alloca(strlen(autostart_program_name) + 20);
                    sprintf(tmp, "load\"%s\",8,1\r",
                            autostart_program_name);
                    kbd_buf_feed(tmp);
                } else
                    kbd_buf_feed("load\"*\",8,1\r");

                if (no_traps) {
                    kbd_buf_feed("run\r");
                    autostartmode = AUTOSTART_DONE;
                } else {
                    autostartmode = AUTOSTART_LOADINGDISK;
                    deallocate_program_name();
                    serial_set_attention_callback(disk_attention_callback);
                }
                break;
            }
          case NO:
            autostart_disable();
            break;
          case NOT_YET:
            break;
        }
        break;
      default:
        return;
    }

    if (autostartmode == AUTOSTART_ERROR && handle_true1541) {
	warn(pwarn, -1, "now turning true 1541 emulation %s",
	     orig_true1541_state ? "on" : "off");
	set_true1541_mode(orig_true1541_state);
    }
}

static int autostart_ignore_reset = 0;

/* Clean memory and reboot for autostart.  */
static void reboot_for_autostart(const char *program_name)
{
    if (!autostart_enabled)
	return;

    warn(pwarn, -1, "rebooting...");
    mem_powerup();
    autostart_ignore_reset = 1;
    maincpu_trigger_reset();
    deallocate_program_name();
    if (program_name)
	autostart_program_name = stralloc(program_name);
}

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

/* Autostart tape image `file_name'.  */
int autostart_tape(const char *file_name, const char *program_name)
{
    if (file_name == NULL || !autostart_enabled)
	return -1;

    if (serial_select_file(DT_TAPE, 1, file_name) < 0) {
	warn(pwarn, -1, "cannot attach file '%s' (as a tape)", file_name);
	autostartmode = AUTOSTART_ERROR;
	deallocate_program_name();
	return -1;
    }
    warn(pwarn, -1, "attached file `%s' as a tape image", file_name);
    autostartmode = AUTOSTART_HASTAPE;
    reboot_for_autostart(program_name);

    return 0;
}

/* Autostart disk image `file_name'.  */
int autostart_disk(const char *file_name, const char *program_name)
{
    if (file_name == NULL || !autostart_enabled)
	return -1;

    if (file_system_attach_disk(8, file_name) < 0) {
	warn(pwarn, -1, "cannot attach file `%s' as a disk image", file_name);
	file_system_detach_disk(8);
	autostartmode = AUTOSTART_ERROR;
	deallocate_program_name();
	return -1;
    }
    warn(pwarn, -1, "attached file `%s' as a disk image to device #8",
	 file_name);
    autostartmode = AUTOSTART_HASDISK;
    reboot_for_autostart(program_name);

    return 0;
}

/* Autostart `file_name', trying to auto-detect its type.  */
int autostart_autodetect(const char *file_name, const char *program_name)
{
    if (file_name == NULL)
	return -1;

    if (!autostart_enabled) {
	fprintf(stderr, "Couldn't autostart - unknown kernal!");
	return -1;
    }
    if (autostart_disk(file_name, program_name) == 0)
	warn(pwarn, -1, "`%s' detected as a disk image", file_name);
    else if (autostart_tape(file_name, program_name) == 0)
	warn(pwarn, -1, "`%s' detected as a tape image", file_name);
    else {
	warn(pwarn, -1, "type of file `%s' unrecognized", file_name);
	return -1;
    }

    return 0;
}

/* Autostart the image attached to device `num'.  */
int autostart_device(int num)
{
    if (!autostart_enabled)
	return -1;

    switch (num) {
      case 8:
        autostartmode = AUTOSTART_HASDISK;
        break;
      case 1:
        autostartmode = AUTOSTART_HASTAPE;
        break;
      default:
        return -1;
    }

    reboot_for_autostart(NULL);
    return 0;
}

/* Disable autostart on reset.  */
void autostart_reset(void)
{
    if (!autostart_enabled)
	return;

    if (!autostart_ignore_reset
        && autostartmode != AUTOSTART_NONE
        && autostartmode != AUTOSTART_ERROR) {
	warn(pwarn, -1, "disabling autostart");
	autostartmode = AUTOSTART_NONE;
	deallocate_program_name();
    }
    autostart_ignore_reset = 0;
}

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