/* 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; }