/*    Commodore 64 Emulator v0.4      Earle F. Philhower III     Copyright (C) 1993-4            (st916w9r@dunx1.ocs.drexel.edu)    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., 675 Mass Ave, Cambridge, MA 02139, USA.*/#include "Processor.h"#include "Traps.h"#include "Serial.h"#include "Error.h"typedef struct{    byte inuse  : 1;    byte isopen : 1;    byte (*getf)(byte *, int);    byte (*putf)(byte, int);    byte (*openf)(char *, int, int);    byte (*closef)(int);    void (*flushf)(int);} SerialType;static SerialType device[16];#define BUFFERLEN 127static byte serialBuffer[BUFFERLEN];static byte serialPtr, latestListen, trapListen, latestSaListen;static void SerialSendByte(void), SerialRecieveByte(void), SerialListen(void),			SerialSaListen(void), FloppyReadyTrap(void);static byte SerialDummy(void);static trap serialTrap[] ={	{ 0xed40, {0x78, 0x20, 0x97}, SerialSendByte },	{ 0xee13, {0x78, 0xa9, 0x00}, SerialRecieveByte },	{ 0xed0e, {0x20, 0xa4, 0xf0}, SerialListen },	{ 0xed36, {0x78, 0x20, 0x8e}, SerialSaListen },	{ 0xeea9, {0xad, 0x00, 0xdd}, FloppyReadyTrap }};int SerialInitialize(void){    byte i;	SerialType *p;		AddTrap(serialTrap[0]);	AddTrap(serialTrap[1]);	AddTrap(serialTrap[2]);	AddTrap(serialTrap[3]);	AddTrap(serialTrap[4]);    for (i = 0; i < 16; i++) {		p=&device[i];		p->getf=(byte (*)(byte *, int ))SerialDummy;		p->putf=(byte (*)(byte, int ))SerialDummy;		p->openf=(byte (*)(char *, int , int ))SerialDummy;		p->closef=(byte (*)(int ))SerialDummy;		p->flushf=(void (*)(int ))NULL; }		return kNoError;}void AddSerialDevice(int devnum, byte (*getf)(byte *, int),	byte (*putf)(byte, int), byte (*openf)(char *, int, int),	byte (*closef)(int), void (*flushf)(int)){    SerialType *p;    if ((devnum<0)||(devnum>15)) InternalError(kInvalidDeviceNumber);    p=&device[devnum];	if (p->inuse!=0) InternalError(kDeviceNumberInUse);    p->getf = getf;    p->putf = putf;    p->openf = openf;    p->closef = closef;    p->flushf = flushf;    p->inuse = 1;}static void SerialSendByte(void){    byte data;    SerialType *p;	extern void i60(void);    data=RAM[0x95];    p=&device[latestListen&0x0f];    if (p->isopen==0) {		if (serialPtr<BUFFERLEN) serialBuffer[serialPtr++] = data; }    else (*p->putf)(data, latestSaListen & 0x0f);	i60();	/* RTS */}static void SerialRecieveByte(void){    byte pp;    SerialType *p;	extern void i60(void);    p=&device[latestListen&0x0f];    RAM[0x90]=(*p->getf)(&pp, latestSaListen&0x0f);	RAM[0xa4]=a=pp;	flags &= ~CAR;	i60();	/* RTS */}static void SerialListen(void){	extern void i60(void);		trapListen=a;	i60();	/* RTS */}static void SerialSaListen(void){	SerialType *p;	byte b, i;	extern void i60(void);    b=RAM[0x95];    p=&device[latestListen&0x0f];	if (b==0x3f)		switch (latestSaListen&0xf0) {			case 0xf0:	 			if (p->isopen==0) {					p->isopen=1;					i=(*p->openf)((char *)serialBuffer, serialPtr, latestSaListen&0x0f);					serialPtr=0;					RAM[0x90]=i;					if (i) {						p->isopen=0;						(*p->closef)(latestSaListen&0x0f); } }	    		if (p->flushf) (*p->flushf)(latestSaListen&0x0f);				break;			case 0x60:				if (p->isopen==0) {					p->isopen=1;					(*p->openf)(NULL, 0, latestSaListen&0x0f);					for (i=0; i<serialPtr; i++)						(*p->putf)(serialBuffer[i], latestSaListen&0x0f);					serialPtr=0; }				if (p->flushf) (*p->flushf)(latestSaListen&0x0f);				break;			case 0xe0:				p->isopen=0;				(*p->closef)(latestSaListen&0x0f);				break;			default:				DebugStr("\pUnimplemented Serial Command"); break;			}	latestListen=trapListen;	latestSaListen=b;	i60();	/* RTS */}static void FloppyReadyTrap(void){    extern void i60(void);		a = 0x01;	flags &=(~NEG+ZER);	i60();	/* RTS */}static byte SerialDummy(void) { return 2; }