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

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

/*
 * parallel.c - IEEE488 emulation.
 *
 * Written 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.
 *
 */

/* This file contains the ieee488 emulator.
 * The ieee488 emulator calls (modifed) routines from serial.c
 * to use the standard floppy interface.
 * The current state of the bus and methods to set output lines
 * are exported.
 * This hardware emulation is necessary, as different PET kernels would
 * need different traps. But it's also much faster than the (hardware
 * simulated) serial bus, as it's parallel. So we don't need traps.
 */

#include "vice.h"

#include <stdio.h>

#include "types.h"
#include "parallel.h"
#include "serial.h"

/* globals */

int pardebug = 0;

/* state of the bus lines - if(par_eoi) { eoi is detected } */
char par_eoi = 0;
char par_ndac = 0;
char par_nrfd = 0;
char par_dav = 0;
char par_atn = 0;

BYTE par_bus = 0;	/* data lines */

int par_status = 0;		/* lower 8 bits = PET par_status, upper bits own */

/* local values */
/* what has been put on the bus from the CPU - to detect changes */
static char par_eoi_out = 0;
static char par_ndac_out = 0;
static char par_nrfd_out = 0;
static char par_dav_out = 0;
static char par_atn_out = 0;
static BYTE par_bus_out = 0;	/* data lines */

/* what has been put on the bus from the device */
static char par_eoi_dev = 0;
static char par_ndac_dev = 0;
static char par_nrfd_dev = 0;
static char par_dav_dev = 0;
static char par_atn_dev = 0;
static BYTE par_bus_dev = 0;	/* data lines */

/* set the real bus line values by 'wire-oring' the signals */
#define	set_atn_out(a)	par_atn_out=(a);par_atn=par_atn_dev|par_atn_out
#define	set_ndac_out(a)	par_ndac_out=(a);par_ndac=par_ndac_dev|par_ndac_out
#define	set_nrfd_out(a)	par_nrfd_out=(a);par_nrfd=par_nrfd_dev|par_nrfd_out
#define	set_dav_out(a)	par_dav_out=(a);par_dav=par_dav_dev|par_dav_out
#define	set_eoi_out(a)	par_eoi_out=(a);par_eoi=par_eoi_dev|par_eoi_out
#define	set_bus_out(a)	par_bus_out=(a);par_bus=par_bus_dev|par_bus_out

/* set the real bus line values by 'wire-oring' the signals */
#define	set_atn_dev(a)	par_atn_dev=(a);par_atn=par_atn_dev|par_atn_out
#define	set_ndac_dev(a)	par_ndac_dev=(a);par_ndac=par_ndac_dev|par_ndac_out
#define	set_nrfd_dev(a)	par_nrfd_dev=(a);par_nrfd=par_nrfd_dev|par_nrfd_out
#define	set_dav_dev(a)	par_dav_dev=(a);par_dav=par_dav_dev|par_dav_out
#define	set_eoi_dev(a)	par_eoi_dev=(a);par_eoi=par_eoi_dev|par_eoi_out
#define	set_bus_dev(a)	par_bus_dev=(a);par_bus=par_bus_dev|par_bus_out


/***************************************************************************
 * State engine for the parallel bus
 *
 * Names here are as seen from a device, not from the PET
 *
 * Possible States
 *	WaitATN		Wait for ATN, ignore everything else
 *
 *	In1		Wait for DAV low when reading a byte
 *	In2		Wait for DAV high when reading a byte
 *
 * 	OldPet		The PET 3032 doesn't set NRFD and NDAC low
 *			before releasing ATN after a TALK command,
 *			wait for a NDAC low first!
 *
 *	Out1		Wait for NRFD high when sending a byte
 *	Out1a		Wait for NRFD low when sending a byte
 *			Trying to save this didn't work
 *	Out2		Wait for NDAC high when sending a byte
 *
 *
 * Each state reacts on the different line transitions.
 *
 * 	atnlo, atnhi, ndaclo, ndachi, nrfdlo, nrfdhi, davlo, davhi
 *
 *
 * Some common functions are:
 *
 *	ResetBus	Set all lines high
 *	ignore		ignore any transition
 *	unexpected	this transition is unexpected
 *
 *	Go		change the state
 *
 * Globals:
 *
 *	Trans[]		name of the transitions
 *	State[]		jump table
 *	state		actual state
 */

#define	NTRANS		8	/* number of possible transitions */
#define	NSTATE		7

/* States */

#define	WaitATN		0
#define	In1		1
#define	In2		2
#define	OldPet		3
#define	Out1		4
#define	Out1a		5
#define	Out2		6


/* Transitions */

#define	ATNlo		0
#define	ATNhi		1
#define	DAVlo		2
#define	DAVhi		3
#define	NDAClo		4
#define	NDAChi		5
#define	NRFDlo		6
#define	NRFDhi		7

typedef struct State_t {
	char	*name;
	void	(*m[NTRANS])(int);
} State_t;

static char *Trans[NTRANS] = {
	"ATN low", "ATN high", "DAV low", "DAV high",
	"NDAC low", "NDAC high", "NRFD low", "NRFD high"
};

static State_t State[NSTATE];
static int state = WaitATN;

#define	Go(a)		state=(a);return
#define	isListening()	((par_status&0xf000)==0x2000)
#define	isTalking()	((par_status&0xf000)==0x4000)

/*#define	DoTrans(a)	State[state].m[(a)](a)}*/
static void DoTrans(int tr) {
	State[state].m[tr](tr);
	fflush(stdout);
}

static void ResetBus(void) {
	set_atn_dev(0);
	set_dav_dev(0);
	set_eoi_dev(0);
	set_nrfd_dev(0);
	set_ndac_dev(0);
	set_bus_dev(0);
	par_status = 0;
}

static void ignore(int i) {}

static void unexpected(int trans) {
	if(pardebug)
	printf("IEEE488: unexpected line transition in state %s: %s\n",
		State[state].name, Trans[trans]);
}

static void WATN_atnlo(int tr) {
	set_ndac_dev(1);
	set_dav_dev(0);
	set_eoi_dev(0);
	set_bus_dev(0);
	set_nrfd_dev(0);
	Go(In1);
}

#define	In1_atnlo	WATN_atnlo

static void In1_atnhi(int tr) {
	if(par_status & 0xff) {
	  ResetBus();
	  Go(WaitATN);
	} else
	if(isListening()) {
	  Go(In1);
	} else
	if(isTalking()) {
	  ResetBus();
	  if(!par_ndac) {	/* old pet... */
	    Go(OldPet);
	  } else {
	    State[OldPet].m[NDAClo](tr);
	    return;
	  }
	} else {
	  if(pardebug)
	  printf("IEEE488: Ouch, something weird happened: %s got %s\n",
		State[In1].name, Trans[tr]);
	  ResetBus();
	  Go(WaitATN);
	}
}

static void In1_davlo(int tr) {
	static BYTE b;

	set_nrfd_dev(1);
	b = par_bus;
	set_ndac_dev(0);

	if(par_atn) {
	  par_status = parallelattention(b);
	} else {
	  par_status = parallelsendbyte(b);
	}
	if(pardebug) printf("IEEE488: sendbyte returns %04x\n",par_status);

	Go(In2);
}

static void In1_ndaclo(int tr) {
	if(!par_atn) unexpected(tr);
}

static void In1_nrfdlo(int tr) {
	if(!par_atn) unexpected(tr);
}


static void In1_nrfdhi(int tr) {
	unexpected(tr);
}

#define	In2_atnlo	WATN_atnlo

static void In2_atnhi(a) {	/* atn data transfer interrupted */
	ResetBus();
	Go(WaitATN);		/* ??? */
}

static void In2_davhi(int tr) {
	set_ndac_dev(1);
	set_nrfd_dev(0);

 	Go(In1);
}

#define	OPet_atnlo	WATN_atnlo

static void OPet_ndaclo(int tr) {
	if(!par_nrfd) {
	  State[Out1].m[NRFDhi](tr);
	  return;
	} else {
	  Go(Out1);
	}
}

#define	Out1_atnlo	WATN_atnlo

static void Out1_nrfdhi(int tr) {
	static BYTE b;

	par_status = parallelreceivebyte(&b, 1);
/*if(par_status & 0xff)
	  printf("IEEE488: Out1_nrfdhi: par_status=%x\n",par_status);*/

	if(par_status & 0x40) {
	  set_eoi_dev(1);
	} else {
	  set_eoi_dev(0);
	}

	set_bus_dev(b^255);

	set_dav_dev(1);

	Go(Out1a);
}

#define	Out1a_atnlo	WATN_atnlo

static void Out1a_nrfdlo(int tr) {
	Go(Out2);
}

static void Out1a_ndachi(int tr) {
	ResetBus();
	Go(WaitATN);
}

#define	Out2_atnlo	WATN_atnlo

static void Out2_ndachi(int tr) {
	static BYTE b;

	set_dav_dev(0);
	set_eoi_dev(0);
	set_bus_dev(0);

	par_status = parallelreceivebyte(&b, 0);
/*if(par_status & 0xff)
	  printf("IEEE488: Out2_ndachi: par_status=%x\n",par_status);*/
	if(par_status & 0xff) {
	  ResetBus();
	  Go(WaitATN);
	} else {
	  Go(Out1);
	}
}

/**************************************************************************
 * State table
 *
 */

static State_t State[NSTATE] = {
	{ "WaitATN", 	{ WATN_atnlo,  ignore, 	   ignore,     ignore,     ignore,      ignore,       ignore,       ignore } },
	{ "In1", 	{ In1_atnlo,   In1_atnhi,  In1_davlo,  unexpected, In1_ndaclo,  unexpected,   In1_nrfdlo,   In1_nrfdhi } },
	{ "In2", 	{ In2_atnlo,   In2_atnhi,  unexpected, In2_davhi,  unexpected,  unexpected,   unexpected,   unexpected } },
	{ "OldPet", 	{ OPet_atnlo,  unexpected, unexpected, unexpected, OPet_ndaclo, unexpected,   unexpected,   unexpected } },
	{ "Out1", 	{ Out1_atnlo,  unexpected, unexpected, unexpected, ignore,      unexpected,   unexpected,   Out1_nrfdhi } },
	{ "Out1a", 	{ Out1a_atnlo, unexpected, unexpected, unexpected, unexpected,  Out1a_ndachi, Out1a_nrfdlo, unexpected } },
	{ "Out2", 	{ Out2_atnlo,  unexpected, unexpected, unexpected, unexpected,  Out2_ndachi,  unexpected,   unexpected } }
};

/**************************************************************************
 * methods to set output lines for the CPU
 *
 */

void par_set_atn( char b ) {
	if(b==par_atn_out) return; set_atn_out(b);
	if(pardebug) printf("par_set_atn(%d)\n",b);
	if(b) DoTrans(ATNlo); else DoTrans(ATNhi); return;
}

void par_set_ndac( char b ) {
	if(b==par_ndac_out) return; set_ndac_out(b);
	if(b) DoTrans(NDAClo); else DoTrans(NDAChi); return;
}

void par_set_nrfd( char b ) {
	if(b==par_nrfd_out) return; set_nrfd_out(b);
	if(b) DoTrans(NRFDlo); else DoTrans(NRFDhi); return;
}

void par_set_dav( char b ) {
	if(b==par_dav_out) return; set_dav_out(b);
	if(b) DoTrans(DAVlo); else DoTrans(DAVhi); return;
}

void par_set_bus( BYTE b ) {
	if(b==par_bus_out) return; set_bus_out(b);
	if(pardebug) printf("par_set_bus(%d)\n",b);
}

void par_set_eoi( char b ) {
	if(b==par_eoi_out) return; set_eoi_out(b);
	if(pardebug) printf("par_set_eoi(%d)\n",b);
}


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