{SDLCTest.mc, HGM,   4-Nov-84  2:32:27

 Simple SDLC Test for First SCC chip on Dicentra Misc board.
 Run MemTest after cycling power or you will get confused by memory parity errors.}


	Reserve[0F5F, 0FFF]; {section used by the CP Kernel }
	SetTask[0]; StartAddress[SetupMap];

{Emulator gets [0..7].  Kernel gets 0F.  That leaves us with [8..E].}

RegDef[SCC,		R, 08];
RegDef[SCCh,		RH, 08];
RegDef[IOCB,		R, 09];
RegDef[IOCBh,		RH, 09];
RegDef[CSB,		R, 0A];
RegDef[CSBh,		RH, 0A];
RegDef[Buffer,		R, 0B];
RegDef[BufferH,		RH, 0B];

RegDef[state,		R, 0C];
RegDef[count,		R, 0D];
RegDef[temp,		R, 0E];
RegDef[tempH,		RH, 0E]; {For mapping things}

{These can get overlapped with something else.}
RegDef[extStat,		R, 02];
RegDef[intAck,		R, 03];

{Parms}
RegDef[clock,		U, 00];
RegDef[dally,		U, 01];

{Counters}
RegDef[u0Timeout,	U, 10];
RegDef[u1Timeout,	U, 11];
RegDef[uPhoneyInt,	U, 1F];

{Things we expect in the emulator}
RegDef[uPhones,		U, 20];
RegDef[u1000,		U, 21];
RegDef[u9000,		U, 22];



{ L0 used for various return points.}

{Transmitter states.}
Set[TS.readyToSend, 0];
Set[TS.sendLeft, 1];
Set[TS.sendRight, 2];
Set[TS.waitingForEOP, 3];

{Receiver states.}
Set[RS.readyToRecv, 0];
Set[RS.skipping, 1];
Set[RS.recvLeft, 2]; {2 bit on => IOCB valid}
Set[RS.recvRight, 3];

Set[IOCB.next, 0];
Set[IOCB.status, 1];
Set[IOCB.bufferLo, 2];
Set[IOCB.bufferHi, 3];
Set[IOCB.bytes, 4];
Set[IOCB.bytesLeft, 05];

{Scratch area for microcode}
Set[IOCB.fingerLo, 8];
Set[IOCB.fingerHi, 9];
Set[IOCB.mappedLo, 0A];
Set[IOCB.mappedHi, 0B];

Set[CSB.tState, 00];
Set[CSB.tIOCB, 01];
Set[CSB.tIOCBm, 02];
Set[CSB.tIOCBmh, 03];

Set[CSB.rState, 04];
Set[CSB.rIOCB, 05];
Set[CSB.rIOCBm, 06];
Set[CSB.rIOCBmh, 07];

Set[CSB.tMsg, 08];
Set[CSB.tUnder, 09];
Set[CSB.rMsg, 0A];
Set[CSB.rBad, 0B];
Set[CSB.rAborted, 0C];

Set[CSB.timer, 0F];



Trap:	temp ← RRot1 ErrnIBnStkp, ClrIntErr,			c1, at[0];
	Xbus ← temp LRot0, XwdDisp,				c2;
	DISP2[TrapType],					c3;
	
Parity:	GOTO[GoToGo],						c1, at[0,4,TrapType];
Init:	GOTO[GoToGo],						c1, at[1,4,TrapType];
Stack:	GOTO[GoToGo],						c1, at[2,4,TrapType];
IB:	GOTO[GoToGo],						c1, at[3,4,TrapType];

GoToGo:	Noop,							c2;
	GOTO[Go],						c3;




Go:	Noop,							c1;
	Noop,							c2;
	ExtCtrl ← 5, {Init Incr, Zero, UnBlank}			c3;
	
{Initialize LoopBack Clock for first 2 lines}
	SCCh ← 2, {Modem0 drives LC0'}				c1;
	SCC ← 10,						c2;
	SCC ← SCC LRot8 {1000},					c3;

	IO ← [SCCh, SCC + 0], {Master Interrupt Control}	c1;
	MDR ← 0,						c2;
	Noop,							c3;

	IO ← [SCCh, SCC + 1], {Master Config Control}		c1;
	MDR ← 010, {Enable PortC and Cnt3}			c2;
	temp ← SCC + 10,					c3;

	IO ← [SCCh, temp + 0A], {Cnt3 MSB}			c1;
	MDR ← 0,						c2;
	Noop,							c3;

	IO ← [SCCh, temp + 0B], {Cnt3 LSB}			c1;
	MDR ← 00B, {56KB, actually 56.846}			c2;
	Noop,							c3;

	IO ← [SCCh, temp + 0E], {Cnt3 Mode}			c1;
	MDR ← 0C2, {Sq out}					c2;
	Noop,							c3;

	IO ← [SCCh, SCC + 0C], {Cnt3 Cmd}			c1;
	MDR ← 06, {Go}						c2;
	Noop,							c3;

	IO ← [SCCh, SCC + 06], {Port C Direction}		c1;
	MDR ← 0FE, {Bit 0 ← output}				c2;
	Noop,							c3;

{Initialize all those registers}
	IOCBh ← 0,						c1;
	CSBh ← 0,						c2;
	CSB ← uPhones,						c3;

{Reset state and idle counter: Line 0}
	MAR ← [CSBh, CSB + CSB.timer],				c1;
	MDR ← 0, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	Noop,							c3;

	MAR ← [CSBh, CSB + CSB.tMsg],				c1;
	MDR ← 0, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	Noop,							c3;

	MAR ← [CSBh, CSB + CSB.tUnder],				c1;
	MDR ← 0, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	Noop,							c3;

	MAR ← [CSBh, CSB + CSB.rMsg],				c1;
	MDR ← 0, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	Noop,							c3;

	MAR ← [CSBh, CSB + CSB.rBad],				c1;
	MDR ← 0, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	Noop,							c3;

	MAR ← [CSBh, CSB + CSB.rAborted],			c1;
	MDR ← 0, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	Noop,							c3;

	MAR ← [CSBh, CSB + CSB.tState],				c1;
	MDR ← state ← TS.readyToSend, CANCELBR[$, 0],		c2, LOOPHOLE[wok];
	Noop,							c3;

	MAR ← [CSBh, CSB + CSB.rState],				c1;
	MDR ← state ← RS.readyToRecv, CANCELBR[$, 0],		c2, LOOPHOLE[wok];
	CSB ← CSB + 10,						c3;

{Reset state and idle counter: Line 1}
	MAR ← [CSBh, CSB + CSB.timer],				c1;
	MDR ← 0, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	Noop,							c3;

	MAR ← [CSBh, CSB + CSB.tMsg],				c1;
	MDR ← 0, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	Noop,							c3;

	MAR ← [CSBh, CSB + CSB.tUnder],				c1;
	MDR ← 0, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	Noop,							c3;

	MAR ← [CSBh, CSB + CSB.rMsg],				c1;
	MDR ← 0, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	Noop,							c3;

	MAR ← [CSBh, CSB + CSB.rBad],				c1;
	MDR ← 0, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	Noop,							c3;

	MAR ← [CSBh, CSB + CSB.rAborted],			c1;
	MDR ← 0, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	Noop,							c3;

	MAR ← [CSBh, CSB + CSB.tState],				c1;
	MDR ← state ← TS.readyToSend, CANCELBR[$, 0],		c2, LOOPHOLE[wok];
	Noop,							c3;

	MAR ← [CSBh, CSB + CSB.rState],				c1;
	MDR ← state ← RS.readyToRecv, CANCELBR[$, 0],		c2, LOOPHOLE[wok];
	CSB ← CSB + 10,						c3;

{Beware:  Chan A has a higher address than chan B.  Chan B has lower priority.}
	SCC ← 10,						c1;
	SCC ← SCC LRot8,					c2;
	u1000 ← SCC, {1000}					c3;
	
	SCC ← 90, {First SCC is 9000H}				c1;
	SCC ← SCC LRot8,					c2;
	u9000 ← SCC,						c3;
	
	SCC ← SCC + 00, {Chan B}				c1;
	SCCh ← 0,						c2;
	Noop,							c3;
	
	IO ← [SCCh, SCC+00], {WR0B/A}				c1;
	MDR ← 2, {Shift Left (ADR0 is ignored)}			c2;
	Noop,							c3;
	
{Hardware Reset}
Reset:	IO ← [SCCh, SCC+09], {WR9x}				c1;
	MDR ← 0C9, {Reset, MIE, V, VIS}				c2;
	Noop,							c3;
	
	temp ← 02, L0 ← 02, {WR2x}				c1;
	Q ← 000, {Int Vector}					c2;
	CALL[SendToBoth],					c3;
	
	temp ← 04, L0 ← 03, {WR4x}				c1, at[02,10,SendToBothRet];
	Q ← 020, {SDLC}						c2;
	CALL[SendToBoth],					c3;
	
	temp ← 01, L0 ← 04, {WR1x}				c1, at[03,10,SendToBothRet];
	Q ← 13, {Rx All Int, Tx Int En, Ext Int En}		c2;
	CALL[SendToBoth],					c3;
	
	temp ← 03, L0 ← 05, {WR3x}				c1, at[04,10,SendToBothRet];
	Q ← 0D9, {8bits/char, Hunt, CRC, RxE}			c2;
	CALL[SendToBoth],					c3;
	
	temp ← 05, L0 ← 06, {WR5x}				c1, at[05,10,SendToBothRet];
	Q ← 0EB, {DTR, 8bits/char, TxE, RTS, CRC}		c2;
	CALL[SendToBoth],					c3;
	
	temp ← 07, L0 ← 07, {WR7x}				c1, at[06,10,SendToBothRet];
	Q ← 07E, {Flag Char !!!}				c2;
	CALL[SendToBoth],					c3;
	
	temp ← 0A, L0 ← 08, {WR10x}				c1, at[07,10,SendToBothRet];
	Q ← 084, {CRC←1, Abort on Underrun}			c2;
	CALL[SendToBoth],					c3;
	
Go15:	temp ← 0F, L0 ← 09, {WR15x}				c1, at[08,10,SendToBothRet];
	Q ← 080, {Enable Abort}					c2;
	CALL[SendToBoth],					c3;

	temp ← 00, L0 ← 0A, {WR0x}				c1, at[09,10,SendToBothRet];
	Q ← 090, {Reset Ext/Sts Int, Reset Tx CRC}		c2;
	CALL[SendToBoth],					c3;

{TC ← (PClk/(2*F))-2
Actualy, Trial and error is simpler if you have a scope handy.
10kb is handy for scoping.  That's 077.
100kb doesn't work out cleanly.  Try 00B.
9600 baud is 104 microseconds per bit. 07E works out about right.
56kb is 17.86 microseconds per bit.  014 is a hair fast, but 15 is too slow.}
Go12:	temp ← 0C, L0 ← 0B, {WR12x}				c1, at[0A,10,SendToBothRet];
	Q ← clock, {Low byte of time constant}			c2;
	CALL[SendToBoth],					c3;

Go13:	temp ← 0D, L0 ← 0C, {WR13x}				c1, at[0B,10,SendToBothRet];
	Q ← 0, {High byte of time constant ← 0}			c2;
	CALL[SendToBoth],					c3;

Go14:	temp ← 0E, L0 ← 0D, {WR14x}				c1, at[0C,10,SendToBothRet];
	Q ← 3, {Enable Baud Rate Gen from PClk}			c2;
	CALL[SendToBoth],					c3;

Go11:	temp ← 0B, L0 ← 0E, {WR11x}				c1, at[0D,10,SendToBothRet];
	Q ← 050, {Clocks from BR Gen}				c2;
{	Q ← 008, {External clocks}				c2;}
	CALL[SendToBoth],					c3;

{Bypass test first time to Prime pump}
Prime:	temp ← 08, L0 ← 0F, {WR8x}				c1, at[0E,10,SendToBothRet];
	Q ← 0FF,						c2;
	CALL[SendToBoth],					c3;
	

MainLoop:
	extStat ← ExtStat,					c1, at[0F,10,SendToBothRet];
{6}	Xbus ← extStat LRot8, XDisp, {08 = Int4}		c2;
	CSB ← uPhones, BRANCH[$, DoSCC, 07],			c3;

Check0:	MAR ← [CSBh, CSB + CSB.timer],				c1;
	Noop, CANCELBR[$, 0],					c2;
	Q ← MD,							c3;

	Noop,							c1;
	Q ← Q  + 1, PgCarryBr,					c2;
	BRANCH[$, Timeout0],					c3;
	
	MAR ← [CSBh, CSB + CSB.timer],				c1;
	MDR ← Q, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	CSB ← CSB + 10,						c3;

Check1:	MAR ← [CSBh, CSB + CSB.timer],				c1;
	Noop, CANCELBR[$, 0],					c2;
	Q ← MD,							c3;

	Noop,							c1;
	Q ← Q  + 1, PgCarryBr,					c2;
	BRANCH[$, Timeout1],					c3;
	
	MAR ← [CSBh, CSB + CSB.timer],				c1;
	MDR ← Q, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	Q ← dally,						c3;

{Pause a while to simulate an Emulator that doesn't check MesaInt often enough.}
DallyLoop:
	[] ← Q, ZeroBr,						c1;
	BRANCH[$, Dallyed],					c2;
	Q ← Q - 1, GOTO[DallyLoop],				c3;
	
Dallyed:
	GOTO[MainLoop],						c3;
	

Timeout0:
	ExtCtrl ← 5, {Clear MP}					c1;
	ExtCtrl ← 7,						c2;
	Noop,							c3;

	Q ← u0Timeout,						c1;
	Q ← Q + 1,						c2;
	u0Timeout ← Q, GOTO[Go],				c3;
	
Timeout1:
	ExtCtrl ← 5, {Clear MP}					c1;
	ExtCtrl ← 7,						c2;
	Noop,							c3;

	Q ← u1Timeout,						c1;
	Q ← Q + 1,						c2;
	u1Timeout ← Q, GOTO[Go],				c3;
	

{
We need to leave 6*400+200 ns (2.6 microseconds) between references to the SCC chip.
With a 16mhz Xtal, 6 clicks takes 2.25 microseconds and 7 clicks takes 2.6 microseconds.
Memory reads will take a bit longer.}

DoSCC:	
	Noop,							c1;
	SCCh ← 0,						c2;
	SCC ← u1000, {IntAck address}				c3;
	
	IO ← [SCCh, SCC+00], {Int Ack}				c1;
{0}	Q ← uPhones, ClrIntErr, L0 ← 0A,			c2;
	intAck ← MD,						c3;
	
	SCC ← LShift1 intAck and ~07,				c1;
{1}	CSB ← SCC + Q,						c2;
	CSB ← CSB xor 10,					c3;

	Q ← SCC,						c1;
{2}	SCCh ← intAck LRot12, Ybus ← intAck, YDisp,		c2;
	SCC ← Q or u9000, DISP4[SCCDisp, 09],			c3;
	

{Request to send next data byte}
TxTranByte:
	MAR ← [CSBh, CSB + CSB.tIOCBm],				c1, at[09, 10, SCCDisp];
{3}	Noop, CANCELBR[$, 0],					c2;
	IOCB ← MD,						c3;

	MAR ← [CSBh, CSB + CSB.tIOCBmh],			c1;
{4}	Noop, CANCELBR[$, 0],					c2;
	IOCBh ← MD,						c3;

	MAR ← [CSBh, CSB + CSB.tState],				c1;
{5}	Noop, CANCELBR[$, 0],					c2;
	state ← MD,						c3;

	Noop,							c1;
{6}	Ybus ← state, YDisp,					c2;
	DISP3[TranData],					c3;

{Start sending new frame}
TxStart:
	IO ← [SCCh, SCC+0A], {WR10}				c1, at[TS.readyToSend, 8, TranData];
{0}	MDR ← 084, {CRC←1, Abort on Underrun} 			c2;
	Noop,							c3;
	
	MAR ← [CSBh, CSB + CSB.tIOCB],				c1;
{1}	tempH ← 0, CANCELBR[$, 0],				c2;
	temp ← MD,						c3;

	Map ← [tempH, temp],					c1;
{2}	Q ← temp, ZeroBr,					c2;
	IOCBh ← IOCB ← MD, BRANCH[$, TxNothingToSend],		c3;

{cycle memory for the side effects of MAR ←}
	MAR ← IOCB ← [IOCBh, temp + 0],				c1;
{3}	Noop,							c2;
	Noop,							c3;

	MAR ← [CSBh, CSB + CSB.tIOCBm],				c1;
{4}	MDR ← IOCB, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	Noop,							c3;

	MAR ← [CSBh, CSB + CSB.tIOCBmh],			c1;
{5}	MDR ← IOCBh, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	Noop,							c3;

	IO ← [SCCh, SCC+00], {WR0}				c1;
{0}	MDR ← 080, {Reset Tx CRC}				c2;
	Noop,							c3;

	MAR ← [IOCBh, IOCB + IOCB.bufferHi],			c1;
{1}	Noop, CANCELBR[$, 0],					c2;
	tempH ← temp ← MD,					c3;

	MAR ← [IOCBh, IOCB + IOCB.fingerHi],			c1;
{2}	MDR ← temp, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	Noop,							c3;

	MAR ← [IOCBh, IOCB + IOCB.bufferLo],			c1;
{3}	Noop, CANCELBR[$, 0],					c2;
	temp ← MD,						c3;

	MAR ← [IOCBh, IOCB + IOCB.fingerLo],			c1;
{4}	MDR ← temp, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	Noop,							c3;

	Map ← [tempH, temp],					c1;
{5}	Q ← temp, CANCELBR[$, 0],				c2;
	BufferH ← Buffer ← MD,					c3;

{cycle memory for the side effects of MAR ←}
	MAR ← Buffer ← [BufferH, temp + 0],			c1;
{6}	Noop,							c2;
	Noop,							c3;

TxStarting:
	IO ← [SCCh, SCC+00], {WR0}				c1;
{0}	MDR ← 0C0, {Reset EOM}					c2;
	Noop,							c3;
	
	MAR ← [IOCBh, IOCB + IOCB.mappedHi],			c1;
{1}	MDR ← BufferH, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	Noop,							c3;

	MAR ← [IOCBh, IOCB + IOCB.mappedLo],			c1;
{2}	MDR ← Buffer, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	Noop,							c3;

	MAR ← [IOCBh, IOCB + IOCB.bytes],			c1;
{3}	Noop, CANCELBR[$, 0],					c2;
	count ← MD, GOTO[TxSendLeftByte],			c3;

TxLeftByte:
	IO ← [SCCh, SCC+00], {RR0} L0 ← 00,			c1, at[TS.sendLeft, 8, TranData];
{0-4}	CALL[TxBufferSetup],					c2;

TxSendLeftByte:
	MAR ← [BufferH, Buffer + 0],				c1, at[00, 04, TxBufferRet];
{5}	state ← TS.sendRight,					c2;
	temp ← MD,						c3;
	
	temp ← temp LRot8,					c1;
{6}	count ← count - 1, NegBr,				c2;
	BRANCH[TxSendByte, TxEnd],				c3;


TxRightByte:
	IO ← [SCCh, SCC+00], {RR0} L0 ← 01,			c1, at[TS.sendRight, 8, TranData];
{0-4}	CALL[TxBufferSetup],					c2;
	
TxSendRightByte:
	MAR ← [BufferH, Buffer], Buffer ← Buffer + 1,		c1, at[01, 04, TxBufferRet];
{5}	state ← TS.sendLeft, BRANCH[$, TxNewPage, 1],		c2;
	temp ← MD, GOTO[TxSaveBuffer],				c3;
	
TxNewPage:
	temp ← MD,						c3;
	
	MAR ← [IOCBh, IOCB + IOCB.fingerLo],			c1;
	Q ← 0FF + 1, CANCELBR[$, 0],				c2;
	Buffer ← MD,						c3;

	MAR ← [IOCBh, IOCB + IOCB.fingerHi],			c1;
	Buffer ← Buffer + Q, CarryBr, CANCELBR[$, 0],		c2;
	BufferH ← MD, BRANCH[TxNoBankCross, $],		c3;

TxNewBank:
	Q ← BufferH,						c1;
	Q ← Q + 1,						c2;
	BufferH ← Q LRot0,					c3;

	MAR ← [IOCBh, IOCB + IOCB.fingerHi],			c1;
	MDR ← BufferH, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	Noop,							c3;

TxNoBankCross:
	MAR ← [IOCBh, IOCB + IOCB.fingerLo],			c1;
	MDR ← Buffer, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	Noop,							c3;

	Map ← [BufferH, Buffer],				c1;
	Noop,							c2;
	BufferH ← Buffer ← MD,					c3;

	MAR ← [IOCBh, IOCB + IOCB.mappedHi],			c1;
	MDR ← BufferH, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	Buffer ← Buffer and ~0FF,				c3;

TxSaveBuffer:
	MAR ← [IOCBh, IOCB + IOCB.mappedLo],			c1;
{6}	MDR ← Buffer, count ← count - 1, NegBr, CANCELBR[$, 0],		c2, LOOPHOLE[wok];
	BRANCH[TxSendByte, TxEnd],				c3;

TxSendByte:
	IO ← [SCCh, SCC+08], {WR8}				c1;
{0}	MDR ← temp, {Transmit Data}				c2;
	Noop,							c3;
	
TxSaveCountAndState:
	MAR ← [IOCBh, IOCB + IOCB.bytesLeft],			c1;
{1}	MDR ← count, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	Noop,							c3;

TxSaveState:
	MAR ← [CSBh, CSB + CSB.timer],				c1;
{x}	MDR ← 0, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	Noop,							c3;

	MAR ← [CSBh, CSB + CSB.tState],				c1;
{2}	MDR ← state, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	GOTO[AckInt],						c3;



{Finish sending frame}
{It could underrun right now.  ????}
TxEnd:	IO ← [SCCh, SCC+0A], {WR10}				c1;
{0}	MDR ← 080, {Send CRC}					c2;
	Noop,							c3;
	
	MAR ← [IOCBh, IOCB + IOCB.next],			c1;
{1}	CANCELBR[$, 0],						c2;
	Q ← MD,							c3;

	IO ← [SCCh, SCC+00], {WR0}				c1;
{0}	MDR ← 028, {Reset Tx Int}				c2;
	Noop,							c3;

	MAR ← [CSBh, CSB + CSB.tIOCB],				c1;
{1}	MDR ← Q, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	state ← TS.waitingForEOP, GOTO[TxSaveState],		c3;


{Extra interrupt after packet has been sent.}
TxSent:	MAR ← [IOCBh, IOCB + IOCB.status],			c1, at[TS.waitingForEOP, 8, TranData];
{7}	MDR ← ~0, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	Noop,							c3;

	MAR ← [IOCBh, IOCB + IOCB.next],			c1;
{8}	CANCELBR[$, 0],						c2;
	Q ← MD,							c3;

	MAR ← [CSBh, CSB + CSB.tIOCB],				c1;
{9}	MDR ← Q, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	Noop,							c3;

	MAR ← [CSBh, CSB + CSB.tMsg],				c1;
{x}	CANCELBR[$, 0],						c2;
	Q ← MD,							c3;
	
	MAR ← [CSBh, CSB + CSB.tMsg],				c1;
{x}	MDR ← Q + 1, CANCELBR[$, 0]				c2, LOOPHOLE[wok];
	state ← TS.readyToSend, GOTO[TxStart],			c3;



TxBufferSetup:
	temp ← MD,						c3;
	
	Q ← temp and 040, {TxUnderrun}				c1;
{1}	[] ← Q, NZeroBr,					c2;
	BRANCH[$, TxUnderrun],					c3;
	
	MAR ← [IOCBh, IOCB + IOCB.mappedHi],			c1;
{2}	Noop, CANCELBR[$, 0],					c2;
	BufferH ← MD,						c3;

	MAR ← [IOCBh, IOCB + IOCB.mappedLo],			c1;
{3}	Noop, CANCELBR[$, 0],					c2;
	Buffer ← MD,						c3;

	MAR ← [IOCBh, IOCB + IOCB.bytesLeft],			c1;
{4}	L0Disp, CANCELBR[$, 0],					c2;
	count ← MD, DISP2[TxBufferRet],				c3;

TxUnderrun:
	IO ← [SCCh, SCC+00], {WR0}				c1;
{0}	MDR ← 018, {Send Abort}					c2;
	state ← TS.readyToSend,					c3;

	MAR ← [CSBh, CSB + CSB.tUnder],				c1;
{1}	Noop, CANCELBR[$, 0],					c2;
	Q ← MD,							c3;
	
	MAR ← [CSBh, CSB + CSB.tUnder],				c1;
{2}	MDR ← Q + 1, CANCELBR[$, 0]				c2, LOOPHOLE[wok];
	GOTO[TxSaveState],					c3;


TxNothingToSend:
	IO ← [SCCh, SCC+00], {WR0}				c1;
	MDR ← 028, {Reset Tx Int}				c2;
	GOTO[TxSaveState],					c3;



ExternalStatusChange:
	MAR ← [CSBh, CSB + CSB.rIOCBm],				c1, at[0B, 10, SCCDisp];
{3}	Noop, CANCELBR[$, 0],					c2;
	IOCB ← MD,						c3;

	MAR ← [CSBh, CSB + CSB.rIOCBmh],			c1;
{4}	Noop, CANCELBR[$, 0],					c2;
	IOCBh ← MD,						c3;

	MAR ← [CSBh, CSB + CSB.rState],				c1;
{5}	Noop, CANCELBR[$, 0],					c2;
	state ← MD,						c3;

	IO ← [SCCh, SCC+00], {RR0}				c1;
{0}	Noop,							c2;
	temp ← MD,						c3;
	
	IO ← [SCCh, SCC+00], {WR0}				c1;
{0}	MDR ← 010, {Reset Ext/Sts Int}				c2;
	Noop,							c3;
	
	Q ← temp and 080, {Abort}				c1;
{1}	[] ← Q, NZeroBr,					c2;
	BRANCH[$, RxAbortedExt],				c3;
	
	Noop,							c1;
{2}	Noop,							c2;
	GOTO[AckInt],						c3;
	

	
{Grab next character of frame}
DoRx:	MAR ← [CSBh, CSB + CSB.rIOCBm],				c1, at[0D, 10, SCCDisp];
{3}	Noop, CANCELBR[$, 0],					c2;
	IOCB ← MD,						c3;

	MAR ← [CSBh, CSB + CSB.rIOCBmh],			c1;
{4}	Noop, CANCELBR[$, 0],					c2;
	IOCBh ← MD,						c3;

	MAR ← [CSBh, CSB + CSB.rState],				c1;
{5}	Noop, CANCELBR[$, 0],					c2;
	state ← MD,						c3;
	
	Noop,							c1;
{6}	Ybus ← state, YDisp,					c2;
	DISP3[RecvData],					c3;

{Here comes a new frame}
RxStart:
	IO ← [SCCh, SCC+00], {RR0}				c1, at[RS.readyToRecv, 8, RecvData];
{0}	Noop,							c2;
	temp ← MD,						c3;

	Q ← temp and 80,					c1;
{1}	[] ← Q, NZeroBr,					c2;
	BRANCH[$, RxAbortStray],				c3;

	MAR ← [CSBh, CSB + CSB.rIOCB],				c1;
{2}	tempH ← 0, CANCELBR[$, 0],				c2;
	temp ← MD,						c3;

	Map ← [tempH, temp],					c1;
{3}	Q ← temp, ZeroBr,					c2;
	IOCBh ← IOCB ← MD, BRANCH[$, RxNoBuffer],		c3;

{cycle memory for the side effects of MAR ←}
	MAR ← IOCB ← [IOCBh, temp + 0],				c1;
{4}	Noop,							c2;
	Noop,							c3;

	MAR ← [CSBh, CSB + CSB.rIOCBm],				c1;
{5}	MDR ← IOCB, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	Noop,							c3;

	MAR ← [CSBh, CSB + CSB.rIOCBmh],			c1;
{6}	MDR ← IOCBh, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	Noop,							c3;

	MAR ← [IOCBh, IOCB + IOCB.bufferHi],			c1;
{7}	Noop, CANCELBR[$, 0],					c2;
	tempH ← temp ← MD,					c3;

	MAR ← [IOCBh, IOCB + IOCB.fingerHi],			c1;
{8}	MDR ← temp, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	Noop,							c3;

	MAR ← [IOCBh, IOCB + IOCB.bufferLo],			c1;
{9}	Noop, CANCELBR[$, 0],					c2;
	temp ← MD,						c3;

	MAR ← [IOCBh, IOCB + IOCB.fingerLo],			c1;
{10}	MDR ← temp, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	Noop,							c3;

	Map ← [tempH, temp],					c1;
{11}	Q ← temp, CANCELBR[$, 0],				c2;
	BufferH ← Buffer ← MD,					c3;

{cycle memory for the side effects of MAR ←}
	MAR ← Buffer ← [BufferH, temp + 0],			c1;
{12}	Noop,							c2;
	Noop,							c3;

	MAR ← [IOCBh, IOCB + IOCB.mappedHi],			c1;
{13}	MDR ← BufferH, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	Noop,							c3;

	MAR ← [IOCBh, IOCB + IOCB.mappedLo],			c1;
{14}	MDR ← Buffer, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	Noop,							c3;

	MAR ← [IOCBh, IOCB + IOCB.bytes],			c1;
{15}	Noop, CANCELBR[$, 0],					c2;
	count ← MD, GOTO[RxGrabLeftByte],			c3;

	
	
RxLeftByte:
	IO ← [SCCh, SCC+00], {RR0} L0 ← 00,			c1, at[RS.recvLeft, 8, RecvData];
{0-4}	CALL[RxBufferSetup],					c2;

RxGrabLeftByte:
	IO ← [SCCh, SCC+08], {RR8}				c1, at[00, 04, RxBufferRet];
{0}	Noop,							c2;
	temp ← MD,						c3;

	temp ← temp LRot8,					c1;
{1}	count ← count - 1, NegBr,				c2;
	BRANCH[$, RxOverflowLeft],				c3;

	MAR ← [BufferH, Buffer + 0],				c1;
{2}	MDR ← temp,						c2;
	state ← RS.recvRight,					c3;

RxSaveCountAndState:
	MAR ← [IOCBh, IOCB + IOCB.bytesLeft],			c1;
{3}	MDR ← count, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	Noop,							c3;

RxSaveState:
	MAR ← [CSBh, CSB + CSB.timer],				c1;
{x}	MDR ← 0, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	Noop,							c3;

	MAR ← [CSBh, CSB + CSB.rState],				c1;
{4}	MDR ← state, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	GOTO[AckInt],						c3;


RxRightByte:
	IO ← [SCCh, SCC+00], {RR0} L0 ← 01,			c1, at[RS.recvRight, 8, RecvData];
{0-4}	CALL[RxBufferSetup],					c2;

RxRecvRightByte:
	MAR ← [BufferH, Buffer + 0],				c1, at[01, 04, RxBufferRet];
{5}	count ← count - 1, NegBr,				c2;
	temp ← MD, BRANCH[$, RxOverflowRight],			c3;

	IO ← [SCCh, SCC+08], {RR8}				c1;
{0}	state ← RS.recvLeft,					c2;
	temp ← temp or MD,					c3;

	MAR ← [BufferH, Buffer], Buffer ← Buffer + 1,		c1;
{2}	MDR ← temp, BRANCH[$, RxNewPage, 1],			c2;
	GOTO[RxSaveBuffer],					c3;


RxNewPage: {Rats, write canceled}
	Noop,							c3;
	
	MAR ← [BufferH, Buffer + 0FF],				c1;
	MDR ← temp, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	Noop,							c3;

	MAR ← [IOCBh, IOCB + IOCB.fingerLo],			c1;
	Q ← 0FF + 1, CANCELBR[$, 0],				c2;
	Buffer ← MD,						c3;

	MAR ← [IOCBh, IOCB + IOCB.fingerHi],			c1;
	Buffer ← Buffer + Q, CarryBr, CANCELBR[$, 0],		c2;
	BufferH ← MD, BRANCH[RxNoBankCross, $],		c3;

RxNewBank:
	Q ← BufferH,						c1;
	Q ← Q + 1,						c2;
	BufferH ← Q LRot0,					c3;

	MAR ← [IOCBh, IOCB + IOCB.fingerHi],			c1;
	MDR ← BufferH, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	Noop,							c3;

RxNoBankCross:
	MAR ← [IOCBh, IOCB + IOCB.fingerLo],			c1;
	MDR ← Buffer, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	Noop,							c3;

	Map ← [BufferH, Buffer],				c1;
	Noop,							c2;
	BufferH ← Buffer ← MD,					c3;

	MAR ← [IOCBh, IOCB + IOCB.mappedHi],			c1;
	MDR ← BufferH, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	Buffer ← Buffer and ~0FF,				c3;

RxSaveBuffer:
	MAR ← [IOCBh, IOCB + IOCB.mappedLo],			c1;
{6}	MDR ← Buffer, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	GOTO[RxSaveCountAndState],				c3;



RxOverflowLeft: {Buffer ended before packet}
{-}	Noop, c1;  Noop, c2;  Noop, c3;
RxOverflowRight: {Buffer ended before packet}
	Noop,							c1;
{-}	state ← RS.skipping,					c2;
	temp ← 1, GOTO[RxNextBuffer],				c3;


{This needs a counter in the CSB?}
RxNoBuffer:
	MAR ← [CSBh, CSB + CSB.rState],				c1;
{4}	MDR ← state ← RS.skipping, CANCELBR[$, 0],		c2, LOOPHOLE[wok];
	GOTO[RxDiscardDataByte],				c3;




RxSkipByte:
	IO ← [SCCh, SCC+00], {RR0}				c1, at[RS.skipping, 8, RecvData];
{0}	Noop,							c2;
	temp ← MD,						c3;
	
	Q ← temp and 80,					c1;
{1}	[] ← Q, NZeroBr,					c2;
	BRANCH[$, RxAbortedSkip],				c3;
	
RxDiscardDataByte:
	IO ← [SCCh, SCC+08], {RR8},				c1;
{0}	Noop,							c2;
	temp ← MD, GOTO[AckInt],				c3;
	


RxBufferSetup:
	temp ← MD,						c3;
	
	Q ← temp and 80,					c1;
{1}	[] ← Q, NZeroBr,					c2;
	BRANCH[$, RxAborted],					c3;
	
	MAR ← [IOCBh, IOCB + IOCB.mappedHi],			c1;
{2}	Noop, CANCELBR[$, 0],					c2;
	BufferH ← MD,						c3;

	MAR ← [IOCBh, IOCB + IOCB.mappedLo],			c1;
{3}	Noop, CANCELBR[$, 0],					c2;
	Buffer ← MD,						c3;

	MAR ← [IOCBh, IOCB + IOCB.bytesLeft],			c1;
{4}	L0Disp, CANCELBR[$, 0],					c2;
	count ← MD, DISP2[RxBufferRet],				c3;


RxAbortedExt:
	[] ← state and 2, ZeroBr,				c1;
{2}	BRANCH[$, RxAbortedExtSkip],				c2;
	Noop,							c3;

RxAborted:
	IO ← [SCCh, SCC+00], {WR0}				c1;
{0}	MDR ← 010, {Reset Ext/Sts Int}				c2;
	state ← RS.readyToRecv, GOTO[RxNextBuffer],		c3;


RxAbortedExtSkip:
	Noop,							c3;

RxAbortedSkip:
	MAR ← [CSBh, CSB + CSB.rState],				c1;
{4}	MDR ← state ← RS.readyToRecv, CANCELBR[$, 0],		c2, LOOPHOLE[wok];
	Noop,							c3;

RxAbortStray:
	MAR ← [CSBh, CSB + CSB.rAborted],			c1;
{2}	ExtCtrl ← 5, CANCELBR[$, 0],				c2;
	Q ← MD,							c3;
	
	MAR ← [CSBh, CSB + CSB.rAborted],			c1;
{3}	MDR ← Q + 1, CANCELBR[$, 0]				c2, LOOPHOLE[wok];
	Noop,							c3;
	
	IO ← [SCCh, SCC+00], L0 ← 09, {WR0}			c1;
{0}	MDR ← 010, {Reset Ext/Sts Int}				c2;
	GOTO[AckInt],						c3;
	
		

{RecvChar is "special", hopefully it's the End of a frame}
DoRxSpecial:
	MAR ← [CSBh, CSB + CSB.rIOCBm],				c1, at[0F, 10, SCCDisp];
{3}	Noop, CANCELBR[$, 0],					c2;
	IOCB ← MD,						c3;

	MAR ← [CSBh, CSB + CSB.rIOCBmh],			c1;
{4}	Noop, CANCELBR[$, 0],					c2;
	IOCBh ← MD,						c3;

	MAR ← [CSBh, CSB + CSB.rState],				c1;
{5}	Noop, CANCELBR[$, 0],					c2;
	state ← MD,						c3;
	
	IO ← [SCCh, SCC+00], {RR0}				c1;
{0}	Noop,							c2;
	temp ← MD,						c3;
	
	IO ← [SCCh, SCC+01], {RR1}				c1;
{0}	temp ← temp LRot8,					c2;
	temp ← temp or MD,					c3;
	
	IO ← [SCCh, SCC+08], {RR8}				c1;
{0}	Noop,							c2;
	Xbus ← MD,						c3;
{Discard shifted last byte of the CRC.}

	IO ← [SCCh, SCC+00], {WR0}				c1;
{0}	MDR ← 030, {Reset Errs}					c2;
	Q ← temp and 0FF,					c3;
	
	Q ← Q xor 87,						c1;
{x}	[] ← Q, ZeroBr,						c2;
	BRANCH[RxBad, RxGood],					c3;

	
RxBad:	MAR ← [CSBh, CSB + CSB.rBad],				c1;
{x}	ExtCtrl ← 5, CANCELBR[$, 0],				c2;
	Q ← MD,							c3;
	
	MAR ← [CSBh, CSB + CSB.rBad],				c1;
{x}	MDR ← Q + 1, CANCELBR[$, 0]				c2, LOOPHOLE[wok];
	GOTO[RxMP],						c3;
	
	
RxGood:	MAR ← [CSBh, CSB + CSB.rMsg],				c1;
{x}	ExtCtrl ← 3, CANCELBR[$, 0],				c2;
	Q ← MD,							c3;
	
	MAR ← [CSBh, CSB + CSB.rMsg],				c1;
{x}	MDR ← Q + 1, CANCELBR[$, 0]				c2, LOOPHOLE[wok];
	GOTO[RxMP],						c3;
	
RxMP:	ExtCtrl ← 7,						c1;
{x}	state ← RS.readyToRecv,					c2;
	GOTO[RxNextBuffer],					c3;
	

{Store final status and chain to next recv buffer.
  state has new state (RS.skipping or RS.readyToRecv)
  temp has status}
RxNextBuffer:
	MAR ← [IOCBh, IOCB + IOCB.status],			c1;
{1}	MDR ← temp, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	Noop,							c3;

	MAR ← [IOCBh, IOCB + IOCB.next],			c1;
{2}	CANCELBR[$, 0],						c2;
	Q ← MD,							c3;

	MAR ← [CSBh, CSB + CSB.rIOCB],				c1;
{3}	MDR ← Q, CANCELBR[$, 0],				c2, LOOPHOLE[wok];
	GOTO[RxSaveState],					c3;


AckInt:
	IO ← [SCCh, SCC+00], {WR0x}				c1;
{0}	MDR ← 38, {Reset Highest IUS}				c2;
	Noop,							c3;

{Pause a while to let interrupt come on again in time.}
	Noop,							c1;
	Noop,							c2;
	Noop,							c3;

	Noop,							c1;
	Noop,							c2;
	GOTO[MainLoop],						c3;
	

SendToBoth:
	SCC ← u9000,						c1;
	SCC ← SCC or 00, {Chan B}				c2;
	Noop,							c3;
	
	IO ← [SCCh, SCC+temp],					c1;
	MDR ← Q,						c2;
	SCC ← SCC or 10, {Chan A}				c3;
	
	IO ← [SCCh, SCC+temp],					c1;
	MDR ← Q, L0Disp,					c2;
	DISP4[SendToBothRet],					c3;
	


{Assume 4 banks.  Map things 1 to 1, skiping over bank 1 which has the map.}

SetupMap:
	temp ← 60,						c1;
	IOCBh ← 1, IOCB ← 0,					c2;
	count ← 0,						c3;

ClearMapLoop:
	MAR ← [IOCBh, IOCB+0],					c1;
	MDR ← temp, count ← count + 1, CarryBr,			c2;
	IOCB ← IOCB + 1, BRANCH[ClearMapLoop, $],		c3;
	
SetupBank0:
	temp ← 0,						c1;
	Noop,							c2;
	Noop,							c3;

FillBank0:
	MAR ← [IOCBh, IOCB+0],					c1;
	MDR ← temp,						c2;
	temp ← temp + 0FF + 1,					c3;

	Noop,							c1;
	count ← count + 1, PgCarryBr,				c2;
	IOCB ← IOCB + 1, BRANCH[FillBank0, $],			c3;


SetupBank2:
	temp ← temp + 2,					c1;
	IOCB ← IOCB + 0FF + 1, {skip bank1}			c2;
	Noop,							c3;

FillBank2:
	MAR ← [IOCBh, IOCB+0],					c1;
	MDR ← temp,						c2;
	temp ← temp + 0FF + 1,					c3;

	Noop,							c1;
	count ← count + 1, PgCarryBr,				c2;
	IOCB ← IOCB + 1, BRANCH[FillBank2, $],			c3;

SetupBank3:
	temp ← temp + 1,					c1;
	Noop,							c2;
	Noop,							c3;

FillBank3:
	MAR ← [IOCBh, IOCB+0],					c1;
	MDR ← temp,						c2;
	temp ← temp + 0FF + 1,					c3;

	Noop,							c1;
	count ← count + 1, PgCarryBr,				c2;
	IOCB ← IOCB + 1, BRANCH[FillBank3, $],			c3;

SetupMapFinished:
	Noop,							c1;
	Noop,							c2;
	GOTO[Go],						c3;