minivmac4ios/Mini vMac/mnvm_core/SCCEMDEV.c
2016-05-28 14:18:59 +02:00

2793 lines
56 KiB
C
Executable File

/*
SCCEMDEV.c
Copyright (C) 2012 Philip Cummins, Weston Pawlowski,
Michael Fort, Paul C. Pratt
You can redistribute this file and/or modify it under the terms
of version 2 of the GNU General Public License as published by
the Free Software Foundation. You should have received a copy
of the license along with this file; see the file COPYING.
This file 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
license for more details.
*/
/*
Serial Communications Controller EMulated DEVice
additions for LocalTalk networking support
Copyright 2011-2012, Michael Fort
enabled with "EmLocalTalk"
-- original description: --
Emulates the Z8530 SCC found in the Mac Plus.
But only the minimum amount needed to emulate
normal operation in a Mac Plus with nothing
connected to the serial ports.
(and not even that much is complete yet)
This code adapted from "SCC.c" in vMac by Philip Cummins.
With additional code by Weston Pawlowski from the Windows
port of vMac.
Further information was found in the
"Zilog SCC/ESCC User's Manual".
*/
#ifndef AllFiles
#include "SYSDEPNS.h"
#include "MYOSGLUE.h"
#include "EMCONFIG.h"
#include "GLOBGLUE.h"
#endif
#include "SCCEMDEV.h"
#define SCC_dolog (dbglog_HAVE && 0)
#define SCC_TrackMore 0
/* Just to make things a little easier */
#define Bit0 1
#define Bit1 2
#define Bit2 4
#define Bit3 8
#define Bit4 16
#define Bit5 32
#define Bit6 64
#define Bit7 128
/* SCC Interrupts */
#define SCC_A_Rx 8 /* Rx Char Available */
#define SCC_A_Rx_Spec 7 /* Rx Special Condition */
#define SCC_A_Tx_Empty 6 /* Tx Buffer Empty */
#define SCC_A_Ext 5 /* External/Status Change */
#define SCC_B_Rx 4 /* Rx Char Available */
#define SCC_B_Rx_Spec 3 /* Rx Special Condition */
#define SCC_B_Tx_Empty 2 /* Tx Buffer Empty */
#define SCC_B_Ext 1 /* External/Status Change */
typedef struct {
blnr TxEnable;
blnr RxEnable;
blnr TxIE; /* Transmit Interrupt Enable */
blnr TxUnderrun;
blnr SyncHunt;
blnr TxIP; /* Transmit Interrupt Pending */
#if EmLocalTalk
ui3r RxBuff;
#endif
#if EmLocalTalk
/* otherwise TxBufferEmpty always true */
/*
though should behave as went false
for an instant when write to transmit buffer
*/
blnr TxBufferEmpty;
#endif
#if EmLocalTalk || SCC_TrackMore
blnr ExtIE;
#endif
#if SCC_TrackMore
blnr WaitRqstEnbl;
#endif
#if SCC_TrackMore
blnr WaitRqstSlct;
#endif
#if SCC_TrackMore
blnr WaitRqstRT;
#endif
#if SCC_TrackMore
blnr PrtySpclCond;
#endif
#if SCC_TrackMore
blnr PrtyEnable;
#endif
#if SCC_TrackMore
blnr PrtyEven;
#endif
#if SCC_TrackMore
blnr RxCRCEnbl;
#endif
#if SCC_TrackMore
blnr TxCRCEnbl;
#endif
#if SCC_TrackMore
blnr RTSctrl;
#endif
#if SCC_TrackMore
blnr SndBrkCtrl;
#endif
#if SCC_TrackMore
blnr DTRctrl;
#endif
#if EmLocalTalk || SCC_TrackMore
blnr AddrSrchMd;
#endif
#if SCC_TrackMore
blnr SyncChrLdInhb;
#endif
#if SCC_TrackMore
ui3r ClockRate;
#endif
#if SCC_TrackMore
ui3r DataEncoding;
#endif
#if SCC_TrackMore
ui3r TRxCsrc;
#endif
#if SCC_TrackMore
ui3r TClkSlct;
#endif
#if SCC_TrackMore
ui3r RClkSlct;
#endif
#if SCC_TrackMore
ui3r RBitsPerChar;
#endif
#if SCC_TrackMore
ui3r TBitsPerChar;
#endif
#if EmLocalTalk || SCC_TrackMore
ui3r RxIntMode;
#endif
#if EmLocalTalk || SCC_TrackMore
blnr FirstChar;
#endif
#if EmLocalTalk || SCC_TrackMore
ui3r SyncMode;
#endif
#if SCC_TrackMore
ui3r StopBits;
#endif
#if 0 /* AllSent always true */
blnr AllSent;
#endif
#if 0 /* CTS always false */
blnr CTS; /* input pin, unattached, so false? */
#endif
#if 0 /* DCD always false */
blnr DCD; /* Data Carrier Detect */
/*
input pin for mouse interrupts. but since
not emulating mouse this way, leave false.
*/
#endif
#if EmLocalTalk
/* otherwise RxChrAvail always false */
blnr RxChrAvail;
#endif
#if 0 /* RxOverrun always false */
blnr RxOverrun;
#endif
#if 0 /* CRCFramingErr always false */
blnr CRCFramingErr;
#endif
#if EmLocalTalk
/* otherwise EndOfFrame always false */
blnr EndOfFrame;
#endif
#if 0 /* ParityErr always false */
blnr ParityErr;
#endif
#if 0 /* ZeroCount always false */
blnr ZeroCount;
#endif
#if 0 /* BreakAbort always false */
blnr BreakAbort;
#endif
#if 0 /* SyncHuntIE usually false */
blnr SyncHuntIE;
#endif
#if SCC_TrackMore /* don't care about CTS_IE */
blnr CTS_IE;
#endif
#if SCC_TrackMore
blnr CRCPreset;
#endif
#if SCC_TrackMore
blnr BRGEnbl;
#endif
#if 0 /* don't care about DCD_IE, always true */
blnr DCD_IE;
#endif
#if SCC_TrackMore /* don't care about BreakAbortIE */
blnr BreakAbortIE;
#endif
#if SCC_TrackMore /* don't care about Baud */
ui3r BaudLo;
ui3r BaudHi;
#endif
} Channel_Ty;
typedef struct {
Channel_Ty a[2]; /* 0 = channel A, 1 = channel B */
int SCC_Interrupt_Type;
int PointerBits;
ui3b InterruptVector;
blnr MIE; /* master interrupt enable */
#if SCC_TrackMore
blnr NoVectorSlct;
#endif
#if 0 /* StatusHiLo always false */
blnr StatusHiLo;
#endif
} SCC_Ty;
LOCALVAR SCC_Ty SCC;
#if 0
LOCALVAR int ReadPrint;
LOCALVAR int ReadModem;
#endif
#if EmLocalTalk
static int rx_data_offset = 0;
/* when data pending, this is used */
#endif
EXPORTFUNC blnr SCC_InterruptsEnabled(void)
{
return SCC.MIE;
}
/* ---- */
/* Function used to update the interrupt state of the SCC */
LOCALPROC CheckSCCInterruptFlag(void)
{
#if 0 /* ReceiveAInterrupt always false */
blnr ReceiveAInterrupt = falseblnr
/*
also dependeds on WR1, bits 3 and 4, but
this doesn't change that it's all false
*/
#if EmLocalTalk
/* otherwise RxChrAvail always false */
| SCC.a[0].RxChrAvail
#endif
#if 0 /* RxOverrun always false */
| SCC.a[0].RxOverrun
#endif
#if 0 /* CRCFramingErr always false */
| SCC.a[0].CRCFramingErr
#endif
#if EmLocalTalk
/* otherwise EndOfFrame always false */
| SCC.a[0].EndOfFrame
#endif
#if 0 /* ParityErr always false */
| SCC.a[0].ParityErr
#endif
;
#endif
#if 0
blnr TransmitAInterrupt = SCC.a[0].TxBufferEmpty;
/*
but probably looking for transitions not
current value
*/
#endif
#if 0
blnr ExtStatusAInterrupt = 0
#if 0 /* ZeroCount always false */
| SCC.a[0].ZeroCount
#endif
/* probably want transition for these, not value */
#if 0 /* DCD always false */
| SCC.a[0].DCD /* DCD IE always true */
#endif
#if 0 /* CTS always false */
| SCC.a[0].CTS /* would depend on CTS_IE */
#endif
| SCC.a[0].SyncHunt /* SyncHuntIE usually false */
| SCC.a[0].TxUnderrun /* Tx underrun/EOM IE always false */
#if 0 /* BreakAbort always false */
| SCC.a[0].BreakAbort
#endif
;
#endif
ui3b NewSCCInterruptRequest;
#if EmLocalTalk
blnr ReceiveBInterrupt = falseblnr;
blnr RxSpclBInterrupt = falseblnr
/* otherwise EndOfFrame always false */
| SCC.a[1].EndOfFrame
;
#endif
#if EmLocalTalk
switch (SCC.a[1].RxIntMode) {
case 0:
/* disabled */
RxSpclBInterrupt = falseblnr;
break;
case 1:
/* Rx INT on 1st char or special condition */
if (SCC.a[1].RxChrAvail && SCC.a[1].FirstChar) {
ReceiveBInterrupt = trueblnr;
}
break;
case 2:
/* INT on all Rx char or special condition */
if (SCC.a[1].RxChrAvail) {
ReceiveBInterrupt = trueblnr;
}
break;
case 3:
/* Rx INT on special condition only */
break;
}
#endif
/* Master Interrupt Enable */
if (! SCC.MIE) {
SCC.SCC_Interrupt_Type = 0;
} else
#if 0
/* External Interrupt Enable */
if (SCC.a[1].ExtIE) {
/* DCD Interrupt Enable */
if (SCC.a[1].DCD_IE && 0) { /* dcd unchanged */
SCC.SCC_Interrupt_Type = ??;
}
}
#endif
if (SCC.a[0].TxIP && SCC.a[0].TxIE) {
SCC.SCC_Interrupt_Type = SCC_A_Tx_Empty;
} else
#if EmLocalTalk
if (ReceiveBInterrupt) {
SCC.SCC_Interrupt_Type = SCC_B_Rx;
} else
if (RxSpclBInterrupt) {
SCC.SCC_Interrupt_Type = SCC_B_Rx_Spec;
} else
#endif
if (SCC.a[1].TxIP && SCC.a[1].TxIE) {
SCC.SCC_Interrupt_Type = SCC_B_Tx_Empty;
} else
{
SCC.SCC_Interrupt_Type = 0;
}
NewSCCInterruptRequest = (SCC.SCC_Interrupt_Type != 0) ? 1 : 0;
if (NewSCCInterruptRequest != SCCInterruptRequest) {
#if SCC_dolog
dbglog_WriteSetBool("SCCInterruptRequest change",
NewSCCInterruptRequest);
dbglog_StartLine();
dbglog_writeCStr("SCC.SCC_Interrupt_Type <- ");
dbglog_writeHex(SCC.SCC_Interrupt_Type);
dbglog_writeReturn();
#endif
SCCInterruptRequest = NewSCCInterruptRequest;
#ifdef SCCinterruptChngNtfy
SCCinterruptChngNtfy();
#endif
}
}
LOCALPROC SCC_InitChannel(int chan)
{
/* anything not done by ResetChannel */
SCC.a[chan].SyncHunt = trueblnr;
#if 0 /* DCD always false */
SCC.a[chan].DCD = falseblnr; /* input pin, reset doesn't change */
#endif
#if 0 /* CTS always false */
SCC.a[chan].CTS = falseblnr; /* input pin, reset doesn't change */
#endif
#if 0 /* AllSent always true */
SCC.a[chan].AllSent = trueblnr;
#endif
#if SCC_TrackMore /* don't care about Baud */
SCC.a[chan].BaudLo = 0;
SCC.a[chan].BaudHi = 0;
#endif
#if 0 /* BreakAbort always false */
SCC.a[chan].BreakAbort = falseblnr;
#endif
#if SCC_TrackMore
SCC.a[chan].BRGEnbl = falseblnr;
#endif
#if SCC_TrackMore
SCC.a[chan].TRxCsrc = 0;
#endif
#if SCC_TrackMore
SCC.a[chan].TClkSlct = 1;
#endif
#if SCC_TrackMore
SCC.a[chan].RClkSlct = 0;
#endif
}
LOCALPROC SCC_ResetChannel(int chan)
{
/* RR 0 */
#if EmLocalTalk
SCC.a[chan].RxBuff = 0;
#endif
#if EmLocalTalk
/* otherwise RxChrAvail always false */
SCC.a[chan].RxChrAvail = falseblnr;
#endif
#if 0 /* ZeroCount always false */
SCC.a[chan].ZeroCount = falseblnr;
#endif
#if EmLocalTalk
/* otherwise TxBufferEmpty always true */
SCC.a[chan].TxBufferEmpty = trueblnr;
#endif
SCC.a[chan].TxUnderrun = trueblnr;
/* RR 1 */
#if 0 /* ParityErr always false */
SCC.a[chan].ParityErr = falseblnr;
#endif
#if 0 /* RxOverrun always false */
SCC.a[chan].RxOverrun = falseblnr;
#endif
#if 0 /* CRCFramingErr always false */
SCC.a[chan].CRCFramingErr = falseblnr;
#endif
#if EmLocalTalk
/* otherwise EndOfFrame always false */
SCC.a[chan].EndOfFrame = falseblnr;
#endif
/* RR 3 */
#if EmLocalTalk || SCC_TrackMore
SCC.a[chan].ExtIE = falseblnr;
#endif
#if SCC_TrackMore
SCC.a[chan].RxCRCEnbl = falseblnr;
#endif
#if SCC_TrackMore
SCC.a[chan].TxCRCEnbl = falseblnr;
#endif
#if SCC_TrackMore
SCC.a[chan].RTSctrl = falseblnr;
#endif
#if SCC_TrackMore
SCC.a[chan].SndBrkCtrl = falseblnr;
#endif
#if SCC_TrackMore
SCC.a[chan].DTRctrl = falseblnr;
#endif
#if EmLocalTalk || SCC_TrackMore
SCC.a[chan].AddrSrchMd = falseblnr;
#endif
#if SCC_TrackMore
SCC.a[chan].SyncChrLdInhb = falseblnr;
#endif
#if SCC_TrackMore
SCC.a[chan].WaitRqstEnbl = falseblnr;
#endif
#if SCC_TrackMore
SCC.a[chan].WaitRqstSlct = falseblnr;
#endif
#if SCC_TrackMore
SCC.a[chan].WaitRqstRT = falseblnr;
#endif
#if SCC_TrackMore
SCC.a[chan].PrtySpclCond = falseblnr;
#endif
#if SCC_TrackMore
SCC.a[chan].PrtyEnable = falseblnr;
#endif
#if SCC_TrackMore
SCC.a[chan].PrtyEven = falseblnr;
#endif
#if SCC_TrackMore
SCC.a[chan].ClockRate = 0;
#endif
#if SCC_TrackMore
SCC.a[chan].DataEncoding = 0;
#endif
#if SCC_TrackMore
SCC.a[chan].RBitsPerChar = 0;
#endif
#if SCC_TrackMore
SCC.a[chan].TBitsPerChar = 0;
#endif
#if EmLocalTalk || SCC_TrackMore
SCC.a[chan].RxIntMode = 0;
#endif
#if EmLocalTalk || SCC_TrackMore
SCC.a[chan].FirstChar = falseblnr;
#endif
#if EmLocalTalk || SCC_TrackMore
SCC.a[chan].SyncMode = 0;
#endif
#if SCC_TrackMore
SCC.a[chan].StopBits = 0;
#endif
#if SCC_TrackMore
SCC.NoVectorSlct = falseblnr;
#endif
SCC.a[chan].TxIP = falseblnr;
SCC.a[chan].TxEnable = falseblnr;
SCC.a[chan].RxEnable = falseblnr;
SCC.a[chan].TxIE = falseblnr;
#if 0 /* don't care about DCD_IE, always true */
SCC.a[chan].DCD_IE = trueblnr;
#endif
#if SCC_TrackMore /* don't care about CTS_IE */
SCC.a[chan].CTS_IE = trueblnr;
#endif
#if SCC_TrackMore
SCC.a[chan].CRCPreset = falseblnr;
#endif
#if 0 /* SyncHuntIE usually false */
SCC.a[chan].SyncHuntIE = trueblnr;
#endif
#if SCC_TrackMore /* don't care about BreakAbortIE */
SCC.a[chan].BreakAbortIE = trueblnr;
#endif
SCC.PointerBits = 0;
#if 0
if (chan != 0) {
ReadPrint = 0;
} else {
ReadModem = 0;
}
#endif
}
GLOBALPROC SCC_Reset(void)
{
SCCwaitrq = 1;
SCC.SCC_Interrupt_Type = 0;
SCCInterruptRequest = 0;
SCC.PointerBits = 0;
SCC.MIE = falseblnr;
SCC.InterruptVector = 0;
#if 0 /* StatusHiLo always false */
SCC.StatusHiLo = falseblnr;
#endif
SCC_InitChannel(1);
SCC_InitChannel(0);
SCC_ResetChannel(1);
SCC_ResetChannel(0);
}
#if EmLocalTalk
LOCALVAR blnr CTSpacketPending = falseblnr;
LOCALVAR ui3r CTSpacketRxDA;
LOCALVAR ui3r CTSpacketRxSA;
/*
Function used when all the tx data is sent to the SCC as indicated
by resetting the TX underrun/EOM latch. If the transmit packet is
a unicast RTS LAPD packet, we fake the corresponding CTS LAPD
packet. This is okay because it is only a collision avoidance
mechanism and the Ethernet device itself and BPF automatically
handle collision detection and retransmission. Besides this is
what a standard AppleTalk (LocalTalk to EtherTalk) bridge does.
*/
LOCALPROC process_transmit(void)
{
/* Check for LLAP packets, which we won't send */
if (LT_TxBuffSz == 3) {
/*
We will automatically and immediately acknowledge
any non-broadcast RTS packets
*/
if ((LT_TxBuffer[0] != 0xFF) && (LT_TxBuffer[2] == 0x84)) {
#if SCC_dolog
dbglog_WriteNote("SCC LLAP packet in process_transmit");
#endif
if (CTSpacketPending) {
ReportAbnormal(
"Already CTSpacketPending in process_transmit");
} else {
CTSpacketRxDA = LT_TxBuffer[1]; /* rx da = tx sa */
CTSpacketRxSA = LT_TxBuffer[0]; /* rx sa = tx da */
CTSpacketPending = trueblnr;
}
}
} else {
LT_TransmitPacket();
}
}
LOCALPROC SCC_TxBuffPut(ui3r Data)
{
/* Buffer the data in the transmit buffer */
if (LT_TxBuffSz < LT_TxBfMxSz) {
LT_TxBuffer[LT_TxBuffSz] = Data;
++LT_TxBuffSz;
}
}
LOCALVAR ui3b MyCTSBuffer[4];
LOCALPROC GetCTSpacket(void)
{
/* Get a single buffer worth of packets at a time */
ui3p device_buffer = MyCTSBuffer;
#if SCC_dolog
dbglog_WriteNote("SCC receiving CTS packet");
#endif
/* Create the fake response from the other node */
device_buffer[0] = CTSpacketRxDA;
device_buffer[1] = CTSpacketRxSA;
device_buffer[2] = 0x85; /* llap cts */
/* Start the receiver */
LT_RxBuffer = device_buffer;
LT_RxBuffSz = 3;
CTSpacketPending = falseblnr;
}
/*
This function is called once all the normal packet bytes have been
received.
*/
LOCALPROC rx_complete(void)
{
if (SCC.a[1].EndOfFrame) {
ReportAbnormal("EndOfFrame true in rx_complete");
}
if (! SCC.a[1].RxChrAvail) {
ReportAbnormal("RxChrAvail false in rx_complete");
}
if (SCC.a[1].SyncHunt) {
ReportAbnormal("SyncHunt true in rx_complete");
}
/*
Need to wait for rx_eof_pending (end of frame) to clear before
preparing the next packet for receive.
*/
LT_RxBuffer = nullpr;
SCC.a[1].EndOfFrame = trueblnr;
}
LOCALPROC SCC_RxBuffAdvance(void)
{
ui3r value;
/*
From the manual:
"If status is checked, it must be done before the data is read,
because the act of reading the data pops both the data and
error FIFOs."
*/
if (nullpr == LT_RxBuffer) {
value = 0x7E;
SCC.a[1].RxChrAvail = falseblnr;
} else {
if (rx_data_offset < LT_RxBuffSz) {
value = LT_RxBuffer[rx_data_offset];
} else {
ui5r i = rx_data_offset - LT_RxBuffSz;
/* if i==0 in first byte of CRC, have not got EOF yet */
if (i == 1) {
rx_complete();
}
value = 0;
}
++rx_data_offset;
}
SCC.a[1].RxBuff = value;
}
/* LLAP/SDLC address */
LOCALVAR ui3b my_node_address = 0;
LOCALPROC GetNextPacketForMe(void)
{
unsigned char dst;
unsigned char src;
label_retry:
LT_ReceivePacket();
if (nullpr != LT_RxBuffer) {
#if SCC_dolog
dbglog_WriteNote("SCC receiving packet from BPF");
#endif
/* Is this packet destined for me? */
dst = LT_RxBuffer[0];
src = LT_RxBuffer[1];
if (src == my_node_address) {
#if SCC_dolog
dbglog_WriteNote("SCC ignore packet from myself");
#endif
LT_RxBuffer = nullpr;
goto label_retry;
} else if ((dst == my_node_address)
|| (dst == 0xFF)
|| ! SCC.a[1].AddrSrchMd)
{
/* ok */
} else {
#if SCC_dolog
dbglog_WriteNote("SCC ignore packet not for me");
#endif
LT_RxBuffer = nullpr;
goto label_retry;
}
}
}
/*
External function, called periodically, to poll for any new LTOE
packets. Any new packets are queued into the packet receipt queue.
*/
GLOBALPROC LocalTalkTick(void)
{
if (SCC.a[1].RxEnable
&& (! SCC.a[1].RxChrAvail))
{
if (nullpr != LT_RxBuffer) {
#if SCC_dolog
dbglog_WriteNote("SCC recover abandoned packet");
#endif
} else {
if (CTSpacketPending) {
GetCTSpacket();
} else {
GetNextPacketForMe();
}
}
if (nullpr != LT_RxBuffer) {
rx_data_offset = 0;
SCC.a[1].EndOfFrame = falseblnr;
SCC.a[1].RxChrAvail = trueblnr;
SCC.a[1].SyncHunt = falseblnr;
SCC_RxBuffAdvance();
/* We can update the rx interrupt if enabled */
CheckSCCInterruptFlag();
}
}
}
#endif
#if 0
LOCALPROC SCC_Interrupt(int Type)
{
if (SCC.MIE) { /* Master Interrupt Enable */
if (Type > SCC.SCC_Interrupt_Type) {
SCC.SCC_Interrupt_Type = Type;
}
CheckSCCInterruptFlag();
}
}
#endif
#if 0
LOCALPROC SCC_Int(void)
{
/* This should be called at regular intervals */
/* Turn off Sync/Hunt Mode */
if (SCC.a[0].SyncHunt) {
SCC.a[0].SyncHunt = falseblnr;
#ifdef _SCC_Debug2
vMac_Message("SCC_Int: Disable Sync/Hunt on A");
#endif
#if 0 /* SyncHuntIE usually false */
if (SCC.a[0].SyncHuntIE) {
SCC_Interrupt(SCC_A_Ext);
}
#endif
}
if (SCC.a[1].SyncHunt) {
SCC.a[1].SyncHunt = falseblnr;
#ifdef _SCC_Debug2
vMac_Message("SCC_Int: Disable Sync/Hunt on B");
#endif
#if 0 /* SyncHuntIE usually false */
if (SCC.a[1].SyncHuntIE) {
SCC_Interrupt(SCC_B_Ext);
}
#endif
}
#if 0
/* Check for incoming data */
if (ModemPort)
{
if (! SCC.a[0].RxEnable) { /* Rx Disabled */
ReadModem = 0;
}
if ((ModemBytes > 0) && (ModemCount > ModemBytes - 1))
{
SCC.a[0].RxChrAvail = falseblnr;
ReadModem = ModemBytes = ModemCount = 0;
}
if (ReadModem) {
ReadModem = 2;
SCC.a[0].RxChrAvail = trueblnr;
if (SCC.a[0].WR[0] & Bit5
&& ! (SCC.a[0].WR[0] & (Bit4 | Bit3)))
{
/* Int on next Rx char */
SCC_Interrupt(SCC_A_Rx);
} else if (SCC.a[0].WR[1] & Bit3
&& ! (SCC.a[0].WR[1] & Bit4))
{
/* Int on first Rx char */
SCC_Interrupt(SCC_A_Rx);
} else if (SCC.a[0].WR[1] & Bit4
&& ! (SCC.a[0].WR[1] & Bit3))
{
/* Int on all Rx chars */
SCC_Interrupt(SCC_A_Rx);
}
}
}
if (PrintPort) {
if (! SCC.a[1].RxEnable) {
/* Rx Disabled */
ReadPrint = 0;
}
if ((PrintBytes > 0) && (PrintCount > PrintBytes - 1)) {
SCC.a[1].RxChrAvail = falseblnr;
ReadPrint = PrintBytes = PrintCount = 0;
}
if (ReadPrint) {
ReadPrint = 2;
SCC.a[1].RxChrAvail = trueblnr;
if (SCC.a[1].WR[0] & Bit5
&& ! (SCC.a[1].WR[0] & (Bit4 | Bit3)))
{
/* Int on next Rx char */
SCC_Interrupt(SCC_B_Rx);
} else if (SCC.a[1].WR[1] & Bit3
&& ! (SCC.a[1].WR[1] & Bit4))
{
/* Int on first Rx char */
SCC_Interrupt(SCC_B_Rx);
} else if (SCC.a[1].WR[1] & Bit4
&& ! (SCC.a[1].WR[1] & Bit3))
{
/* Int on all Rx chars */
SCC_Interrupt(SCC_B_Rx);
}
}
}
#endif
}
#endif
#if SCC_dolog
LOCALPROC SCC_DbgLogChanStartLine(int chan)
{
dbglog_StartLine();
dbglog_writeCStr("SCC chan(");
if (chan) {
dbglog_writeCStr("B");
} else {
dbglog_writeCStr("A");
}
/* dbglog_writeHex(chan); */
dbglog_writeCStr(")");
}
#endif
LOCALFUNC ui3r SCC_GetRR0(int chan)
{
/* happens on boot always */
return 0
#if 0 /* BreakAbort always false */
| (SCC.a[chan].BreakAbort ? (1 << 7) : 0)
#endif
| (SCC.a[chan].TxUnderrun ? (1 << 6) : 0)
#if 0 /* CTS always false */
| (SCC.a[chan].CTS ? (1 << 5) : 0)
#endif
| (SCC.a[chan].SyncHunt ? (1 << 4) : 0)
#if 0 /* DCD always false */
| (SCC.a[chan].DCD ? (1 << 3) : 0)
#endif
#if EmLocalTalk
| (SCC.a[chan].TxBufferEmpty ? (1 << 2) : 0)
#else
/* otherwise TxBufferEmpty always true */
| (1 << 2)
#endif
#if 0 /* ZeroCount always false */
| (SCC.a[chan].ZeroCount ? (1 << 1) : 0)
#endif
#if EmLocalTalk
/* otherwise RxChrAvail always false */
| (SCC.a[chan].RxChrAvail ? (1 << 0) : 0)
#endif
;
}
LOCALFUNC ui3r SCC_GetRR1(int chan)
{
/* happens in MacCheck */
ui3r value;
#if ! EmLocalTalk
UnusedParam(chan);
#endif
value = Bit2 | Bit1
#if 0 /* AllSent always true */
| (SCC.a[chan].AllSent ? (1 << 0) : 0)
#else
| Bit0
#endif
#if 0 /* ParityErr always false */
| (SCC.a[chan].ParityErr ? (1 << 4) : 0)
#endif
#if 0 /* RxOverrun always false */
| (SCC.a[chan].RxOverrun ? (1 << 5) : 0)
#endif
#if 0 /* CRCFramingErr always false */
| (SCC.a[chan].CRCFramingErr ? (1 << 6) : 0)
#endif
#if EmLocalTalk
/* otherwise EndOfFrame always false */
| (SCC.a[chan].EndOfFrame ? (1 << 7) : 0)
#endif
;
return value;
}
LOCALFUNC ui3r SCC_GetRR2(int chan)
{
/* happens in MacCheck */
/* happens in Print to ImageWriter */
ui3r value = SCC.InterruptVector;
if (chan != 0) { /* B Channel */
#if 0 /* StatusHiLo always false */
if (SCC.StatusHiLo) {
/* Status High */
value = value
& (Bit0 | Bit1 | Bit2 | Bit3 | Bit7);
ReportAbnormal("Status high/low");
switch (SCC.SCC_Interrupt_Type) {
case SCC_A_Rx:
value |= Bit4 | Bit5;
break;
case SCC_A_Rx_Spec:
value |= Bit4 | Bit5 | Bit6;
break;
case SCC_A_Tx_Empty:
value |= Bit4;
break;
case SCC_A_Ext:
value |= Bit4 | Bit6;
break;
case SCC_B_Rx:
value |= Bit5;
break;
case SCC_B_Rx_Spec:
value |= Bit5 | Bit6;
break;
case SCC_B_Tx_Empty:
value |= 0;
break;
case SCC_B_Ext:
value |= Bit6;
break;
default:
value |= Bit5 | Bit6;
break;
}
} else
#endif
{
/* Status Low */
value = value
& (Bit0 | Bit4 | Bit5 | Bit6 | Bit7);
switch (SCC.SCC_Interrupt_Type) {
case SCC_A_Rx:
value |= Bit3 | Bit2;
break;
case SCC_A_Rx_Spec:
value |= Bit3 | Bit2 | Bit1;
break;
case SCC_A_Tx_Empty:
value |= Bit3;
break;
case SCC_A_Ext:
value |= Bit3 | Bit1;
break;
case SCC_B_Rx:
value |= Bit2;
break;
case SCC_B_Rx_Spec:
value |= Bit2 | Bit1;
break;
case SCC_B_Tx_Empty:
value |= 0;
break;
case SCC_B_Ext:
value |= Bit1;
break;
default:
value |= Bit2 | Bit1;
break;
}
}
/* SCC.SCC_Interrupt_Type = 0; */
}
return value;
}
LOCALFUNC ui3r SCC_GetRR3(int chan)
{
ui3r value = 0;
UnusedParam(chan);
ReportAbnormal("RR 3");
#if 0
if (chan == 0) {
value = 0
| (SCC.a[1].TxIP ? (1 << 1) : 0)
| (SCC.a[0].TxIP ? (1 << 4) : 0)
;
} else {
value = 0;
}
#endif
return value;
}
LOCALFUNC ui3r SCC_GetRR8(int chan)
{
ui3r value = 0;
/* Receive Buffer */
/* happens on boot with appletalk on */
if (SCC.a[chan].RxEnable) {
#if EmLocalTalk
if (0 != chan) {
/*
Check the receive state, handling a complete rx
if necessary
*/
value = SCC.a[1].RxBuff;
SCC.a[1].FirstChar = falseblnr;
SCC_RxBuffAdvance();
} else {
value = 0x7E;
}
#else
/* Rx Enable */
#if (CurEmMd >= kEmMd_SE) && (CurEmMd <= kEmMd_IIx)
/* don't report */
#else
ReportAbnormal("read rr8 when RxEnable");
#endif
/* Input 1 byte from Modem Port/Printer into Data */
#endif
} else {
/* happens on boot with appletalk on */
}
return value;
}
LOCALFUNC ui3r SCC_GetRR10(int chan)
{
/* happens on boot with appletalk on */
ui3r value = 0;
UnusedParam(chan);
#if 0 && EmLocalTalk
value = 2;
#endif
return value;
}
LOCALFUNC ui3r SCC_GetRR12(int chan)
{
ui3r value = 0;
#if ! SCC_TrackMore
UnusedParam(chan);
#endif
ReportAbnormal("RR 12");
#if SCC_TrackMore /* don't care about Baud */
value = SCC.a[chan].BaudLo;
#endif
return value;
}
LOCALFUNC ui3r SCC_GetRR13(int chan)
{
ui3r value = 0;
#if ! SCC_TrackMore
UnusedParam(chan);
#endif
ReportAbnormal("RR 13");
#if SCC_TrackMore /* don't care about Baud */
value = SCC.a[chan].BaudHi;
#endif
return value;
}
LOCALFUNC ui3r SCC_GetRR15(int chan)
{
ui3r value = 0;
UnusedParam(chan);
ReportAbnormal("RR 15");
#if 0
value = 0
#if 0 /* don't care about DCD_IE, always true */
| (SCC.a[chan].DCD_IE ? Bit3 : 0)
#else
| Bit3
#endif
#if 0 /* SyncHuntIE usually false */
| (SCC.a[chan].SyncHuntIE ? Bit4 : 0)
#endif
#if SCC_TrackMore /* don't care about CTS_IE */
| (SCC.a[chan].CTS_IE ? Bit5 : 0)
#endif
#if SCC_TrackMore /* don't care about BreakAbortIE */
| (SCC.a[chan].BreakAbortIE ? Bit7 : 0)
#endif
;
#endif
return value;
}
#if SCC_dolog
LOCALPROC SCC_DbgLogChanCmnd(int chan, char *s)
{
SCC_DbgLogChanStartLine(chan);
dbglog_writeCStr(" ");
dbglog_writeCStr(s);
dbglog_writeReturn();
}
#endif
#if SCC_dolog
LOCALPROC SCC_DbgLogChanChngBit(int chan, char *s, blnr v)
{
SCC_DbgLogChanStartLine(chan);
dbglog_writeCStr(" ");
dbglog_writeCStr(s);
dbglog_writeCStr(" <- ");
if (v) {
dbglog_writeCStr("1");
} else {
dbglog_writeCStr("0");
}
dbglog_writeReturn();
}
#endif
LOCALPROC SCC_PutWR0(ui3r Data, int chan)
/*
"CRC initialize, initialization commands for the various modes,
Register Pointers"
*/
{
switch ((Data >> 6) & 3) {
case 1:
ReportAbnormal("Reset Rx CRC Checker");
break;
case 2:
#if SCC_dolog
SCC_DbgLogChanCmnd(chan, "Reset Tx CRC Generator");
#endif
/* happens on boot with appletalk on */
break;
case 3:
#if SCC_dolog
SCC_DbgLogChanCmnd(chan,
"Reset Tx Underrun/EOM Latch");
#endif
/* happens on boot with appletalk on */
#if EmLocalTalk
/*
This is the indication we are done transmitting
data for the current packet.
*/
process_transmit();
#endif
#if 0 /* It seems to work better without this */
if (SCC.a[chan].TxEnable) {
/* Tx Enabled */
SCC.a[chan].TxUnderrun = falseblnr;
if (SCC.a[chan].WR[10] & Bit2) {
/* Abort/Flag on Underrun */
/* Send Abort */
SCC.a[chan].TxUnderrun = trueblnr;
#if 0 /* TxBufferEmpty always true */
SCC.a[chan].TxBufferEmpty = trueblnr;
#endif
/* Send Flag */
}
}
#endif
break;
case 0:
default:
/* Null Code */
break;
}
SCC.PointerBits = Data & 0x07;
switch ((Data >> 3) & 7) {
case 1: /* Point High */
SCC.PointerBits |= 8;
break;
case 2:
#if SCC_dolog
SCC_DbgLogChanCmnd(chan, "Reset Ext/Status Ints");
#endif
/* happens on boot always */
SCC.a[chan].SyncHunt = falseblnr;
#if 0 /* only in sync mode */
SCC.a[chan].TxUnderrun = falseblnr;
#endif
#if 0 /* ZeroCount always false */
SCC.a[chan].ZeroCount = falseblnr;
#endif
#if 0 /* BreakAbort always false */
SCC.a[chan].BreakAbort = falseblnr;
#endif
break;
case 3:
ReportAbnormal("Send Abort (SDLC)");
#if EmLocalTalk
SCC.a[chan].TxBufferEmpty = trueblnr;
#endif
#if 0
SCC.a[chan].TxUnderrun = trueblnr;
#if 0 /* TxBufferEmpty always true */
SCC.a[chan].TxBufferEmpty = trueblnr;
#endif
#endif
break;
case 4:
#if SCC_dolog
SCC_DbgLogChanCmnd(chan,
"Enable Int on next Rx char");
#endif
#if EmLocalTalk || SCC_TrackMore
SCC.a[chan].FirstChar = trueblnr;
#endif
/* happens in MacCheck */
break;
case 5:
#if SCC_dolog
SCC_DbgLogChanCmnd(chan, "Reset Tx Int Pending");
#endif
/* happens in MacCheck */
/* happens in Print to ImageWriter */
SCC.a[chan].TxIP = falseblnr;
CheckSCCInterruptFlag();
break;
case 6:
#if SCC_dolog
SCC_DbgLogChanCmnd(chan, "Error Reset");
#endif
/* happens on boot with appletalk on */
#if EmLocalTalk
SCC.a[chan].EndOfFrame = falseblnr;
#endif
#if 0 /* ParityErr always false */
SCC.a[chan].ParityErr = falseblnr;
#endif
#if 0 /* RxOverrun always false */
SCC.a[chan].RxOverrun = falseblnr;
#endif
#if 0 /* CRCFramingErr always false */
SCC.a[chan].CRCFramingErr = falseblnr;
#endif
break;
case 7:
/* happens in "Network Watch" program (Cayman Systems) */
#if SCC_dolog
SCC_DbgLogChanCmnd(chan, "Reset Highest IUS");
#endif
break;
case 0:
default:
/* Null Code */
break;
}
}
LOCALPROC SCC_PutWR1(ui3r Data, int chan)
/*
"Transmit/Receive interrupt and data transfer mode definition"
*/
{
#if EmLocalTalk || SCC_TrackMore
{
blnr NewExtIE = (Data & Bit0) != 0;
if (SCC.a[chan].ExtIE != NewExtIE) {
SCC.a[chan].ExtIE = NewExtIE;
#if SCC_dolog
SCC_DbgLogChanChngBit(chan, "EXT INT Enable",
NewExtIE);
#endif
/*
set to 1 on start up, set to 0 in MacCheck
and in Print to ImageWriter
*/
}
}
#endif
{
blnr NewTxIE = (Data & Bit1) != 0;
if (SCC.a[chan].TxIE != NewTxIE) {
#if SCC_dolog
SCC_DbgLogChanChngBit(chan, "Tx Int Enable",
NewTxIE);
#endif
/* happens in MacCheck */
/* happens in Print to ImageWriter */
SCC.a[chan].TxIE = NewTxIE;
CheckSCCInterruptFlag();
}
}
#if SCC_TrackMore
{
blnr NewPrtySpclCond = (Data & Bit2) != 0;
if (SCC.a[chan].PrtySpclCond != NewPrtySpclCond) {
SCC.a[chan].PrtySpclCond = NewPrtySpclCond;
#if SCC_dolog
SCC_DbgLogChanChngBit(chan,
"Parity is special condition", NewPrtySpclCond);
#endif
/*
set to 1 in MacCheck
and in Print to ImageWriter
*/
}
}
#endif
#if EmLocalTalk || SCC_TrackMore
{
ui3r NewRxIntMode = (Data >> 3) & 3;
if (SCC.a[chan].RxIntMode != NewRxIntMode) {
SCC.a[chan].RxIntMode = NewRxIntMode;
switch (NewRxIntMode) {
case 0:
#if SCC_dolog
SCC_DbgLogChanCmnd(chan, "Rx INT Disable");
#endif
/* happens on boot always */
break;
case 1:
#if SCC_dolog
SCC_DbgLogChanCmnd(chan,
"Rx INT on 1st char"
" or special condition");
#endif
SCC.a[chan].FirstChar = trueblnr;
/* happens on boot with appletalk on */
break;
case 2:
#if SCC_dolog
SCC_DbgLogChanCmnd(chan,
"INT on all Rx char"
" or special condition");
#endif
/* happens in MacCheck */
/* happens in Print to ImageWriter */
break;
case 3:
ReportAbnormal(
"Rx INT on special condition only");
break;
}
}
}
#endif
#if SCC_TrackMore
{
blnr NewWaitRqstRT = (Data & Bit5) != 0;
if (SCC.a[chan].WaitRqstRT != NewWaitRqstRT) {
SCC.a[chan].WaitRqstRT = NewWaitRqstRT;
#if SCC_dolog
SCC_DbgLogChanChngBit(chan,
"Wait/DMA request on receive/transmit",
NewWaitRqstRT);
#endif
/* happens in MacCheck */
}
}
#endif
#if SCC_TrackMore
{
blnr NewWaitRqstSlct = (Data & Bit6) != 0;
if (SCC.a[chan].WaitRqstSlct != NewWaitRqstSlct) {
SCC.a[chan].WaitRqstSlct = NewWaitRqstSlct;
#if SCC_dolog
SCC_DbgLogChanChngBit(chan,
"Wait/DMA request function", NewWaitRqstSlct);
#endif
/* happens in MacCheck */
}
}
#endif
#if SCC_TrackMore
{
blnr NewWaitRqstEnbl = (Data & Bit7) != 0;
if (SCC.a[chan].WaitRqstEnbl != NewWaitRqstEnbl) {
SCC.a[chan].WaitRqstEnbl = NewWaitRqstEnbl;
#if SCC_dolog
SCC_DbgLogChanChngBit(chan,
"Wait/DMA request enable", NewWaitRqstEnbl);
#endif
/* happens in MacCheck */
}
}
#endif
}
LOCALPROC SCC_PutWR2(ui3r Data, int chan)
/* "Interrupt Vector (accessed through either channel)" */
{
/*
Only 1 interrupt vector for the SCC, which
is stored in channels A and B. B is modified
when read.
*/
/* happens on boot always */
#if ! SCC_dolog
UnusedParam(chan);
#endif
if (SCC.InterruptVector != Data) {
#if SCC_dolog
SCC_DbgLogChanStartLine(chan);
dbglog_writeCStr(" InterruptVector <- ");
dbglog_writeHex(Data);
dbglog_writeReturn();
#endif
SCC.InterruptVector = Data;
}
if ((Data & Bit0) != 0) { /* interrupt vector 0 */
ReportAbnormal("interrupt vector 0");
}
if ((Data & Bit1) != 0) { /* interrupt vector 1 */
ReportAbnormal("interrupt vector 1");
}
if ((Data & Bit2) != 0) { /* interrupt vector 2 */
ReportAbnormal("interrupt vector 2");
}
if ((Data & Bit3) != 0) { /* interrupt vector 3 */
ReportAbnormal("interrupt vector 3");
}
if ((Data & Bit4) != 0) { /* interrupt vector 4 */
/* happens on boot with appletalk on */
}
if ((Data & Bit5) != 0) { /* interrupt vector 5 */
/* happens on boot with appletalk on */
}
if ((Data & Bit6) != 0) { /* interrupt vector 6 */
ReportAbnormal("interrupt vector 6");
}
if ((Data & Bit7) != 0) { /* interrupt vector 7 */
ReportAbnormal("interrupt vector 7");
}
}
LOCALPROC SCC_PutWR3(ui3r Data, int chan)
/* "Receive parameters and control" */
{
#if SCC_TrackMore
{
ui3r NewRBitsPerChar = (Data >> 6) & 3;
if (SCC.a[chan].RBitsPerChar != NewRBitsPerChar) {
SCC.a[chan].RBitsPerChar = NewRBitsPerChar;
switch (NewRBitsPerChar) {
case 0:
#if SCC_dolog
SCC_DbgLogChanCmnd(chan,
"Rx Bits/Character <- 5");
#endif
break;
case 1:
#if SCC_dolog
SCC_DbgLogChanCmnd(chan,
"Rx Bits/Character <- 7");
#endif
break;
case 2:
#if SCC_dolog
SCC_DbgLogChanCmnd(chan,
"Rx Bits/Character <- 6");
#endif
break;
case 3:
#if SCC_dolog
SCC_DbgLogChanCmnd(chan,
"Rx Bits/Character <- 8");
#endif
break;
}
}
}
#endif
if ((Data & Bit5) != 0) { /* Auto Enables */
/*
use DCD input as receiver enable,
and set RTS output when transmit buffer empty
*/
ReportAbnormal("Auto Enables");
}
if ((Data & Bit4) != 0) { /* Enter Hunt Mode */
#if SCC_dolog
SCC_DbgLogChanCmnd(chan, "Enter Hunt Mode");
#endif
/* happens on boot with appletalk on */
if (! (SCC.a[chan].SyncHunt)) {
SCC.a[chan].SyncHunt = trueblnr;
#if 0 /* SyncHuntIE usually false */
if (SCC.a[chan].SyncHuntIE) {
SCC_Interrupt((chan == 0)
? SCC_A_Ext
: SCC_B_Ext);
}
#endif
}
}
#if SCC_TrackMore
{
blnr NewRxCRCEnbl = (Data & Bit3) != 0;
if (SCC.a[chan].RxCRCEnbl != NewRxCRCEnbl) {
SCC.a[chan].RxCRCEnbl = NewRxCRCEnbl;
#if SCC_dolog
SCC_DbgLogChanChngBit(chan,
"Rx CRC Enable", NewRxCRCEnbl);
#endif
/* happens on boot with appletalk on */
}
}
#endif
#if EmLocalTalk || SCC_TrackMore
{
blnr NewAddrSrchMd = (Data & Bit2) != 0;
if (SCC.a[chan].AddrSrchMd != NewAddrSrchMd) {
SCC.a[chan].AddrSrchMd = NewAddrSrchMd;
#if SCC_dolog
SCC_DbgLogChanChngBit(chan,
"Addr Search Mode (SDLC)", NewAddrSrchMd);
#endif
/* happens on boot with appletalk on */
}
}
#endif
#if SCC_TrackMore
{
blnr NewSyncChrLdInhb = (Data & Bit1) != 0;
if (SCC.a[chan].SyncChrLdInhb != NewSyncChrLdInhb) {
SCC.a[chan].SyncChrLdInhb = NewSyncChrLdInhb;
#if SCC_dolog
SCC_DbgLogChanChngBit(chan,
"Sync Char Load Inhibit", NewSyncChrLdInhb);
#endif
/* happens on boot with appletalk on */
}
}
#endif
{
blnr NewRxEnable = (Data & Bit0) != 0;
if (SCC.a[chan].RxEnable != NewRxEnable) {
SCC.a[chan].RxEnable = NewRxEnable;
#if SCC_dolog
SCC_DbgLogChanChngBit(chan,
"Rx Enable", NewRxEnable);
#endif
/* true on boot with appletalk on */
/* true on Print to ImageWriter */
#if EmLocalTalk
if (! NewRxEnable) {
#if SCC_dolog
if ((0 != chan) && (nullpr != LT_RxBuffer)) {
dbglog_WriteNote("SCC abandon packet");
}
#endif
/*
Go back into the idle state if we were
waiting for EOF
*/
SCC.a[chan].EndOfFrame = falseblnr;
SCC.a[chan].RxChrAvail = falseblnr;
SCC.a[chan].SyncHunt = trueblnr;
} else {
/* look for a packet */
LocalTalkTick();
}
#endif
}
}
}
LOCALPROC SCC_PutWR4(ui3r Data, int chan)
/* "Transmit/Receive miscellaneous parameters and modes" */
{
#if ! (EmLocalTalk || SCC_TrackMore)
UnusedParam(Data);
UnusedParam(chan);
#endif
#if SCC_TrackMore
{
blnr NewPrtyEnable = (Data & Bit0) != 0;
if (SCC.a[chan].PrtyEnable != NewPrtyEnable) {
SCC.a[chan].PrtyEnable = NewPrtyEnable;
#if SCC_dolog
SCC_DbgLogChanChngBit(chan,
"Parity Enable", NewPrtyEnable);
#endif
}
}
#endif
#if SCC_TrackMore
{
blnr NewPrtyEven = (Data & Bit1) != 0;
if (SCC.a[chan].PrtyEven != NewPrtyEven) {
SCC.a[chan].PrtyEven = NewPrtyEven;
#if SCC_dolog
SCC_DbgLogChanChngBit(chan,
"Parity Enable", NewPrtyEven);
#endif
}
}
#endif
#if SCC_TrackMore
{
ui3r NewStopBits = (Data >> 2) & 3;
if (SCC.a[chan].StopBits != NewStopBits) {
SCC.a[chan].StopBits = NewStopBits;
/* SCC_SetStopBits(chan, NewStopBits); */
switch (NewStopBits) {
case 0:
#if SCC_dolog
SCC_DbgLogChanCmnd(chan,
"Sync Modes Enable");
#endif
break;
case 1:
#if SCC_dolog
SCC_DbgLogChanCmnd(chan, "1 Stop Bit");
#endif
break;
case 2:
#if SCC_dolog
SCC_DbgLogChanCmnd(chan, "1 1/2 Stop Bits");
#endif
break;
case 3:
#if SCC_dolog
SCC_DbgLogChanCmnd(chan, "2 Stop Bits");
#endif
break;
}
}
}
#endif
#if EmLocalTalk || SCC_TrackMore
{
ui3r NewSyncMode = (Data >> 4) & 3;
if (SCC.a[chan].SyncMode != NewSyncMode) {
SCC.a[chan].SyncMode = NewSyncMode;
switch (NewSyncMode) {
case 0:
#if SCC_dolog
SCC_DbgLogChanCmnd(chan, "8 bit sync char");
#endif
/* happens on boot always */
break;
case 1:
ReportAbnormal("16 bit sync char");
break;
case 2:
#if SCC_dolog
SCC_DbgLogChanCmnd(chan, "SDLC MODE");
#endif
/* happens on boot with appletalk on */
#if EmLocalTalk
SCC.a[chan].TxBufferEmpty = trueblnr;
#endif
break;
case 3:
ReportAbnormal("External sync mode");
break;
}
}
}
#endif
#if SCC_TrackMore
{
ui3r NewClockRate = (Data >> 6) & 3;
if (SCC.a[chan].ClockRate != NewClockRate) {
SCC.a[chan].ClockRate = NewClockRate;
switch (NewClockRate) {
case 0:
#if SCC_dolog
SCC_DbgLogChanCmnd(chan,
"Clock Rate <- X1");
#endif
/* happens on boot with appletalk on */
break;
case 1:
#if SCC_dolog
SCC_DbgLogChanCmnd(chan,
"Clock Rate <- X16");
#endif
/* happens on boot always */
break;
case 2:
ReportAbnormal("Clock Rate <- X32");
break;
case 3:
ReportAbnormal("Clock Rate <- X64");
break;
}
}
}
#endif
}
LOCALPROC SCC_PutWR5(ui3r Data, int chan)
/* "Transmit parameters and controls" */
{
/* happens on boot with appletalk on */
/* happens in Print to ImageWriter */
#if SCC_TrackMore
{
blnr NewTxCRCEnbl = (Data & Bit0) != 0;
if (SCC.a[chan].TxCRCEnbl != NewTxCRCEnbl) {
SCC.a[chan].TxCRCEnbl = NewTxCRCEnbl;
#if SCC_dolog
SCC_DbgLogChanChngBit(chan,
"Tx CRC Enable", NewTxCRCEnbl);
#endif
/* both values on boot with appletalk on */
}
}
#endif
#if SCC_TrackMore
{
blnr NewRTSctrl = (Data & Bit1) != 0;
if (SCC.a[chan].RTSctrl != NewRTSctrl) {
SCC.a[chan].RTSctrl = NewRTSctrl;
#if SCC_dolog
SCC_DbgLogChanChngBit(chan,
"RTS Control", NewRTSctrl);
#endif
/* both values on boot with appletalk on */
/*
value of Request To Send output pin, when
Auto Enable is off
*/
}
}
#endif
if ((Data & Bit2) != 0) { /* SDLC/CRC-16 */
ReportAbnormal("SDLC/CRC-16");
}
{
blnr NewTxEnable = (Data & Bit3) != 0;
if (SCC.a[chan].TxEnable != NewTxEnable) {
SCC.a[chan].TxEnable = NewTxEnable;
#if SCC_dolog
SCC_DbgLogChanChngBit(chan,
"Tx Enable", NewTxEnable);
#endif
if (NewTxEnable) {
/* happens on boot with appletalk on */
/* happens in Print to ImageWriter */
#if EmLocalTalk
LT_TxBuffSz = 0;
#endif
} else {
#if EmLocalTalk
SCC.a[chan].TxBufferEmpty = trueblnr;
#endif
}
}
}
#if SCC_TrackMore
{
blnr NewSndBrkCtrl = (Data & Bit4) != 0;
if (SCC.a[chan].SndBrkCtrl != NewSndBrkCtrl) {
SCC.a[chan].SndBrkCtrl = NewSndBrkCtrl;
#if SCC_dolog
SCC_DbgLogChanChngBit(chan,
"Send Break Control", NewSndBrkCtrl);
#endif
/* true in Print to LaserWriter 300 */
}
}
#endif
#if SCC_TrackMore
{
ui3r NewTBitsPerChar = (Data >> 5) & 3;
if (SCC.a[chan].TBitsPerChar != NewTBitsPerChar) {
SCC.a[chan].TBitsPerChar = NewTBitsPerChar;
switch (NewTBitsPerChar) {
case 0:
ReportAbnormal("Tx Bits/Character <- 5");
break;
case 1:
ReportAbnormal("Tx Bits/Character <- 7");
break;
case 2:
ReportAbnormal("Tx Bits/Character <- 6");
break;
case 3:
#if SCC_dolog
SCC_DbgLogChanCmnd(chan,
"Tx Bits/Character <- 8");
#endif
/* happens on boot with appletalk on */
/* happens in Print to ImageWriter */
break;
}
}
}
#endif
#if SCC_TrackMore
{
blnr NewDTRctrl = (Data & Bit7) != 0;
if (SCC.a[chan].DTRctrl != NewDTRctrl) {
SCC.a[chan].DTRctrl = NewDTRctrl;
#if SCC_dolog
SCC_DbgLogChanChngBit(chan,
"Data Terminal Ready Control", NewDTRctrl);
#endif
/* zero happens in MacCheck */
/*
value of Data Terminal Ready output pin,
when WR14 D2 = 0 (DTR/request function)
*/
}
}
#endif
}
LOCALPROC SCC_PutWR6(ui3r Data, int chan)
/* "Sync characters or SDLC address field" */
{
/* happens on boot with appletalk on */
#if ! (EmLocalTalk || SCC_dolog)
UnusedParam(Data);
#endif
#if ! SCC_dolog
UnusedParam(chan);
#endif
#if SCC_dolog
SCC_DbgLogChanStartLine(chan);
dbglog_writeCStr(" Sync Char <- ");
dbglog_writeHex(Data);
dbglog_writeReturn();
#endif
#if EmLocalTalk
if (0 != Data) {
my_node_address = Data;
}
#endif
}
LOCALPROC SCC_PutWR7(ui3r Data, int chan)
/* "Sync character or SDLC flag" */
{
/* happens on boot with appletalk on */
#if ! SCC_TrackMore
UnusedParam(Data);
UnusedParam(chan);
#endif
#if SCC_TrackMore
if (2 == SCC.a[chan].SyncMode) {
if (0x7E != Data) {
ReportAbnormal(
"unexpect flag character for SDLC");
}
} else {
ReportAbnormal("WR7 and not SDLC");
}
#endif
}
LOCALPROC SCC_PutWR8(ui3r Data, int chan)
/* "Transmit Buffer" */
{
/* happens on boot with appletalk on */
/* happens in Print to ImageWriter */
#if ! (EmLocalTalk || SCC_dolog)
UnusedParam(Data);
#endif
#if SCC_dolog
SCC_DbgLogChanStartLine(chan);
dbglog_writeCStr(" Transmit Buffer");
dbglog_writeCStr(" <- ");
dbglog_writeHex(Data);
dbglog_writeCStr(" '");
dbglog_writeMacChar(Data);
dbglog_writeCStr("'");
dbglog_writeReturn();
#endif
if (SCC.a[chan].TxEnable) { /* Tx Enable */
/* Output (Data) to Modem(B) or Printer(A) Port */
/* happens on boot with appletalk on */
#if EmLocalTalk
if (chan != 0) {
SCC_TxBuffPut(Data);
}
#else
#if 0 /* TxBufferEmpty always true */
SCC.a[chan].TxBufferEmpty = trueblnr;
#endif
SCC.a[chan].TxUnderrun = trueblnr; /* underrun ? */
#endif
SCC.a[chan].TxIP = trueblnr;
CheckSCCInterruptFlag();
} else {
ReportAbnormal(
"write when Transmit Buffer not Enabled");
#if 0 /* TxBufferEmpty always true */
SCC.a[chan].TxBufferEmpty = falseblnr;
#endif
}
}
LOCALPROC SCC_PutWR9(ui3r Data, int chan)
/*
"Master interrupt control and reset
(accessed through either channel)"
*/
{
/* Only 1 WR9 in the SCC */
UnusedParam(chan);
if ((Data & Bit0) != 0) { /* VIS */
ReportAbnormal("VIS");
}
#if SCC_TrackMore
{
blnr NewNoVectorSlct = (Data & Bit1) != 0;
if (SCC.NoVectorSlct != NewNoVectorSlct) {
SCC.NoVectorSlct = NewNoVectorSlct;
#if SCC_dolog
dbglog_WriteSetBool("SCC No Vector select",
NewNoVectorSlct);
#endif
/* has both values on boot always */
}
}
#endif
if ((Data & Bit2) != 0) { /* DLC */
ReportAbnormal("DLC");
}
{
blnr NewMIE = (Data & Bit3) != 0;
/* has both values on boot always */
if (SCC.MIE != NewMIE) {
SCC.MIE = NewMIE;
#if SCC_dolog
dbglog_WriteSetBool("SCC Master Interrupt Enable",
NewMIE);
#endif
CheckSCCInterruptFlag();
}
}
#if 0 /* StatusHiLo always false */
SCC.StatusHiLo = (Data & Bit4) != 0;
#else
if ((Data & Bit4) != 0) { /* Status high/low */
ReportAbnormal("Status high/low");
}
#endif
if ((Data & Bit5) != 0) { /* WR9 b5 should be 0 */
ReportAbnormal("WR9 b5 should be 0");
}
switch ((Data >> 6) & 3) {
case 1:
#if SCC_dolog
SCC_DbgLogChanCmnd(1, "Channel Reset");
#endif
/* happens on boot always */
SCC_ResetChannel(1);
CheckSCCInterruptFlag();
break;
case 2:
#if SCC_dolog
SCC_DbgLogChanCmnd(0, "Channel Reset");
#endif
/* happens on boot always */
SCC_ResetChannel(0);
CheckSCCInterruptFlag();
break;
case 3:
#if SCC_dolog
dbglog_WriteNote("SCC Force Hardware Reset");
#endif
#if (CurEmMd >= kEmMd_SE) && (CurEmMd <= kEmMd_IIx)
/* don't report */
#else
ReportAbnormal("SCC_Reset");
#endif
SCC_Reset();
CheckSCCInterruptFlag();
break;
case 0: /* No Reset */
default:
break;
}
}
LOCALPROC SCC_PutWR10(ui3r Data, int chan)
/* "Miscellaneous transmitter/receiver control bits" */
{
/* happens on boot with appletalk on */
/* happens in Print to ImageWriter */
#if ! SCC_TrackMore
UnusedParam(chan);
#endif
if ((Data & Bit0) != 0) { /* 6 bit/8 bit sync */
ReportAbnormal("6 bit/8 bit sync");
}
if ((Data & Bit1) != 0) { /* loop mode */
ReportAbnormal("loop mode");
}
if ((Data & Bit2) != 0) { /* abort/flag on underrun */
ReportAbnormal("abort/flag on underrun");
}
if ((Data & Bit3) != 0) { /* mark/flag idle */
ReportAbnormal("mark/flag idle");
}
if ((Data & Bit4) != 0) { /* go active on poll */
ReportAbnormal("go active on poll");
}
#if SCC_TrackMore
{
ui3r NewDataEncoding = (Data >> 5) & 3;
if (SCC.a[chan].DataEncoding != NewDataEncoding) {
SCC.a[chan].DataEncoding = NewDataEncoding;
switch (NewDataEncoding) {
case 0:
#if SCC_dolog
SCC_DbgLogChanCmnd(chan,
"Data Encoding <- NRZ");
#endif
/* happens in MacCheck */
/* happens in Print to ImageWriter */
break;
case 1:
ReportAbnormal("Data Encoding <- NRZI");
break;
case 2:
ReportAbnormal("Data Encoding <- FM1");
break;
case 3:
#if SCC_dolog
SCC_DbgLogChanCmnd(chan,
"Data Encoding <- FM0");
#endif
/* happens on boot with appletalk on */
break;
}
}
}
#endif
#if SCC_TrackMore
{
blnr NewCRCPreset = (Data & Bit7) != 0;
if (SCC.a[chan].CRCPreset != NewCRCPreset) {
SCC.a[chan].CRCPreset = NewCRCPreset;
#if SCC_dolog
SCC_DbgLogChanChngBit(chan,
"CRC preset I/O", NewCRCPreset);
#endif
/* false happens in MacCheck */
/* true happens in Print to ImageWriter */
}
}
#endif
}
LOCALPROC SCC_PutWR11(ui3r Data, int chan)
/* "Clock mode control" */
{
/* happens on boot with appletalk on */
/* happens in Print to ImageWriter */
/* happens in MacCheck */
#if ! SCC_TrackMore
UnusedParam(chan);
#endif
#if SCC_TrackMore
/* Transmit External Control Selection */
{
ui3r NewTRxCsrc = Data & 3;
if (SCC.a[chan].TRxCsrc != NewTRxCsrc) {
SCC.a[chan].TRxCsrc = NewTRxCsrc;
switch (NewTRxCsrc) {
case 0:
#if SCC_dolog
SCC_DbgLogChanCmnd(chan,
"TRxC OUT = XTAL output");
#endif
/* happens on boot with appletalk on */
/* happens in Print to ImageWriter */
/* happens in MacCheck */
break;
case 1:
ReportAbnormal("TRxC OUT = transmit clock");
break;
case 2:
ReportAbnormal(
"TRxC OUT = BR generator output");
break;
case 3:
ReportAbnormal("TRxC OUT = dpll output");
break;
}
}
}
#endif
if ((Data & Bit2) != 0) {
ReportAbnormal("TRxC O/I");
}
#if SCC_TrackMore
{
ui3r NewTClkSlct = (Data >> 3) & 3;
if (SCC.a[chan].TClkSlct != NewTClkSlct) {
SCC.a[chan].TClkSlct = NewTClkSlct;
switch (NewTClkSlct) {
case 0:
ReportAbnormal("transmit clock = RTxC pin");
break;
case 1:
#if SCC_dolog
SCC_DbgLogChanCmnd(chan,
"transmit clock = TRxC pin");
#endif
/* happens in Print to LaserWriter 300 */
break;
case 2:
#if SCC_dolog
SCC_DbgLogChanCmnd(chan,
"transmit clock = BR generator output");
#endif
/* happens on boot with appletalk on */
/* happens in Print to ImageWriter */
/* happens in MacCheck */
break;
case 3:
ReportAbnormal(
"transmit clock = dpll output");
break;
}
}
}
#endif
#if SCC_TrackMore
{
ui3r NewRClkSlct = (Data >> 5) & 3;
if (SCC.a[chan].RClkSlct != NewRClkSlct) {
SCC.a[chan].RClkSlct = NewRClkSlct;
switch (NewRClkSlct) {
case 0:
ReportAbnormal("receive clock = RTxC pin");
break;
case 1:
#if SCC_dolog
SCC_DbgLogChanCmnd(chan,
"receive clock = TRxC pin");
#endif
/* happens in Print to LaserWriter 300 */
break;
case 2:
#if SCC_dolog
SCC_DbgLogChanCmnd(chan,
"receive clock = BR generator output");
#endif
/* happens in MacCheck */
/* happens in Print to ImageWriter */
break;
case 3:
#if SCC_dolog
SCC_DbgLogChanCmnd(chan,
"receive clock = dpll output");
#endif
/* happens on boot with appletalk on */
break;
}
}
}
#endif
if ((Data & Bit7) != 0) {
ReportAbnormal("RTxC XTAL/NO XTAL");
}
}
LOCALPROC SCC_PutWR12(ui3r Data, int chan)
/* "Lower byte of baud rate generator time constant" */
{
/* happens on boot with appletalk on */
/* happens in Print to ImageWriter */
#if ! SCC_TrackMore
UnusedParam(Data);
UnusedParam(chan);
#endif
#if SCC_TrackMore /* don't care about Baud */
if (SCC.a[chan].BaudLo != Data) {
SCC.a[chan].BaudLo = Data;
#if SCC_dolog
SCC_DbgLogChanStartLine(chan);
dbglog_writeCStr(" BaudLo <- ");
dbglog_writeHex(Data);
dbglog_writeReturn();
#endif
}
#endif
#if 0
SCC_SetBaud(chan,
SCC.a[chan].BaudLo + (SCC.a[chan].BaudHi << 8));
/* 380: BaudRate = 300 */
/* 94: BaudRate = 1200 */
/* 46: BaudRate = 2400 */
/* 22: BaudRate = 4800 */
/* 10: BaudRate = 9600 */
/* 4: BaudRate = 19200 */
/* 1: BaudRate = 38400 */
/* 0: BaudRate = 57600 */
#endif
}
LOCALPROC SCC_PutWR13(ui3r Data, int chan)
/* "Upper byte of baud rate generator time constant" */
{
/* happens on boot with appletalk on */
/* happens in Print to ImageWriter */
#if ! SCC_TrackMore
UnusedParam(Data);
UnusedParam(chan);
#endif
#if SCC_TrackMore /* don't care about Baud */
if (SCC.a[chan].BaudHi != Data) {
SCC.a[chan].BaudHi = Data;
#if SCC_dolog
SCC_DbgLogChanStartLine(chan);
dbglog_writeCStr(" BaudHi <- ");
dbglog_writeHex(Data);
dbglog_writeReturn();
#endif
}
#endif
#if 0
SCC_SetBaud(chan,
SCC.a[chan].BaudLo + (SCC.a[chan].BaudHi << 8));
#endif
}
LOCALPROC SCC_PutWR14(ui3r Data, int chan)
/* "Miscellaneous control bits" */
{
/* happens on boot with appletalk on */
#if ! (SCC_TrackMore || SCC_dolog)
UnusedParam(chan);
#endif
#if SCC_TrackMore
{
blnr NewBRGEnbl = (Data & Bit0) != 0;
if (SCC.a[chan].BRGEnbl != NewBRGEnbl) {
SCC.a[chan].BRGEnbl = NewBRGEnbl;
#if SCC_dolog
SCC_DbgLogChanChngBit(chan,
"BR generator enable", NewBRGEnbl);
#endif
/* both values on boot with appletalk on */
/* true happens in Print to ImageWriter */
}
}
#endif
if ((Data & Bit1) != 0) { /* BR generator source */
ReportAbnormal("BR generator source");
}
if ((Data & Bit2) != 0) { /* DTR/request function */
ReportAbnormal("DTR/request function");
}
if ((Data & Bit3) != 0) { /* auto echo */
ReportAbnormal("auto echo");
}
if ((Data & Bit4) != 0) { /* local loopback */
ReportAbnormal("local loopback");
}
switch ((Data >> 5) & 7) {
case 1:
#if SCC_dolog
SCC_DbgLogChanCmnd(chan, "enter search mode");
#endif
/* happens on boot with appletalk on */
break;
case 2:
#if SCC_dolog
SCC_DbgLogChanCmnd(chan, "reset missing clock");
#endif
/* happens on boot with appletalk on */
/*
should clear Bit 6 and Bit 7 of RR[10], but
since these are never set, don't need
to do anything
*/
break;
case 3:
ReportAbnormal("disable dpll");
/*
should clear Bit 6 and Bit 7 of RR[10], but
since these are never set, don't need
to do anything
*/
break;
case 4:
ReportAbnormal("set source = br generator");
break;
case 5:
ReportAbnormal("set source = RTxC");
break;
case 6:
#if SCC_dolog
SCC_DbgLogChanCmnd(chan, "set FM mode");
#endif
/* happens on boot with appletalk on */
break;
case 7:
ReportAbnormal("set NRZI mode");
break;
case 0: /* No Reset */
default:
break;
}
}
LOCALPROC SCC_PutWR15(ui3r Data, int chan)
/* "External/Status interrupt control" */
{
/* happens on boot always */
#if ! SCC_TrackMore
UnusedParam(chan);
#endif
if ((Data & Bit0) != 0) { /* WR15 b0 should be 0 */
ReportAbnormal("WR15 b0 should be 0");
}
if ((Data & Bit1) != 0) { /* zero count IE */
ReportAbnormal("zero count IE");
}
if ((Data & Bit2) != 0) { /* WR15 b2 should be 0 */
ReportAbnormal("WR15 b2 should be 0");
}
#if 0 /* don't care about DCD_IE, always true */
SCC.a[chan].DCD_IE = (Data & Bit3) != 0;
#else
if ((Data & Bit3) == 0) { /* DCD_IE */
#if (CurEmMd >= kEmMd_SE) && (CurEmMd <= kEmMd_IIx)
/* don't report */
#else
ReportAbnormal("not DCD IE");
#endif
}
#endif
#if 0 /* SyncHuntIE usually false */
SCC.a[chan].SyncHuntIE = (Data & Bit4) != 0;
#else
if ((Data & Bit4) != 0) {
/* SYNC/HUNT IE */
ReportAbnormal("SYNC/HUNT IE");
}
#endif
#if SCC_TrackMore /* don't care about CTS_IE */
{
blnr NewCTS_IE = (Data & Bit5) != 0;
if (SCC.a[chan].CTS_IE != NewCTS_IE) {
SCC.a[chan].CTS_IE = NewCTS_IE;
#if SCC_dolog
SCC_DbgLogChanChngBit(chan,
"CTS IE", NewCTS_IE);
#endif
/* happens in MacCheck */
/* happens in Print to ImageWriter */
}
}
#endif
if ((Data & Bit6) != 0) { /* Tx underrun/EOM IE */
ReportAbnormal("Tx underrun/EOM IE");
}
#if SCC_TrackMore
{
blnr NewBreakAbortIE = (Data & Bit7) != 0;
if (SCC.a[chan].BreakAbortIE != NewBreakAbortIE) {
SCC.a[chan].BreakAbortIE = NewBreakAbortIE;
#if SCC_dolog
SCC_DbgLogChanChngBit(chan,
"BreakAbort IE", NewBreakAbortIE);
#endif
/* happens in MacCheck */
/* happens in Print to ImageWriter */
}
}
#endif
}
LOCALFUNC ui3r SCC_GetReg(int chan, ui3r SCC_Reg)
{
ui3r value;
switch (SCC_Reg) {
case 0:
value = SCC_GetRR0(chan);
break;
case 1:
value = SCC_GetRR1(chan);
break;
case 2:
value = SCC_GetRR2(chan);
break;
case 3:
value = SCC_GetRR3(chan);
break;
case 4:
ReportAbnormal("RR 4"); /* same as RR0 */
value = SCC_GetRR0(chan);
break;
case 5:
ReportAbnormal("RR 5"); /* same as RR1 */
value = SCC_GetRR1(chan);
break;
case 6:
ReportAbnormal("RR 6"); /* same as RR2 */
value = SCC_GetRR2(chan);
break;
case 7:
ReportAbnormal("RR 7"); /* same as RR3 */
value = SCC_GetRR3(chan);
break;
case 8:
value = SCC_GetRR8(chan);
break;
case 9:
ReportAbnormal("RR 9"); /* same as RR13 */
value = SCC_GetRR13(chan);
break;
case 10:
value = SCC_GetRR10(chan);
break;
case 11:
ReportAbnormal("RR 11"); /* same as RR15 */
value = SCC_GetRR15(chan);
break;
case 12:
value = SCC_GetRR12(chan);
break;
case 13:
value = SCC_GetRR13(chan);
break;
case 14:
ReportAbnormal("RR 14");
value = 0;
break;
case 15:
value = SCC_GetRR15(chan);
break;
default:
ReportAbnormal("unexpected SCC_Reg in SCC_GetReg");
value = 0;
break;
}
#if EmLocalTalk
/*
Always check to see if interrupt state changed after
ANY register access
*/
CheckSCCInterruptFlag();
#endif
#if SCC_dolog
SCC_DbgLogChanStartLine(chan);
dbglog_writeCStr(" RR[");
dbglog_writeHex(SCC_Reg);
dbglog_writeCStr("] -> ");
dbglog_writeHex(value);
dbglog_writeReturn();
#endif
return value;
}
LOCALPROC SCC_PutReg(ui3r Data, int chan, ui3r SCC_Reg)
{
#if SCC_dolog && 0
SCC_DbgLogChanStartLine(chan);
dbglog_writeCStr(" WR[");
dbglog_writeHex(SCC_Reg);
dbglog_writeCStr("] <- ");
dbglog_writeHex(Data);
dbglog_writeReturn();
#endif
switch (SCC_Reg) {
case 0:
SCC_PutWR0(Data, chan);
break;
case 1:
SCC_PutWR1(Data, chan);
break;
case 2:
SCC_PutWR2(Data, chan);
break;
case 3:
SCC_PutWR3(Data, chan);
break;
case 4:
SCC_PutWR4(Data, chan);
break;
case 5:
SCC_PutWR5(Data, chan);
break;
case 6:
SCC_PutWR6(Data, chan);
break;
case 7:
SCC_PutWR7(Data, chan);
break;
case 8:
SCC_PutWR8(Data, chan);
break;
case 9:
SCC_PutWR9(Data, chan);
break;
case 10:
SCC_PutWR10(Data, chan);
break;
case 11:
SCC_PutWR11(Data, chan);
break;
case 12:
SCC_PutWR12(Data, chan);
break;
case 13:
SCC_PutWR13(Data, chan);
break;
case 14:
SCC_PutWR14(Data, chan);
break;
case 15:
SCC_PutWR15(Data, chan);
break;
default:
ReportAbnormal("unexpected SCC_Reg in SCC_PutReg");
break;
}
#if EmLocalTalk
/*
Always check to see if interrupt state changed after ANY
register access
*/
CheckSCCInterruptFlag();
#endif
}
GLOBALFUNC ui5b SCC_Access(ui5b Data, blnr WriteMem, CPTR addr)
{
#if EmLocalTalk
/*
Determine channel, data, and access type from address. The bus
for the 8350 is non-standard, so the Macintosh connects address
bus lines to various signals on the 8350 as shown below. The
68K will use the upper byte of the data bus for odd addresses,
and the 8350 is only wired to the upper byte, therefore use
only odd addresses or you risk resetting the 8350.
68k 8350
----- ------
a1 a/b
a2 d/c
a21 wr/rd
*/
#endif
ui3b SCC_Reg;
int chan = (~ addr) & 1; /* 0=modem, 1=printer */
if (((addr >> 1) & 1) == 0) {
/* Channel Control */
SCC_Reg = SCC.PointerBits;
SCC.PointerBits = 0;
} else {
/* Channel Data */
SCC_Reg = 8;
}
if (WriteMem) {
SCC_PutReg(Data, chan, SCC_Reg);
} else {
Data = SCC_GetReg(chan, SCC_Reg);
}
return Data;
}