mirror of
https://github.com/zydeco/minivmac4ios.git
synced 2024-11-01 06:05:26 +00:00
2793 lines
56 KiB
C
Executable File
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;
|
|
}
|