{MemTest.mc, HGM, 14-Apr-85  4:03:57

 Dicentra memory test.
 
 From Cucinitti's Syzygy of November 14, 1979  7:22 AM, 
 The random number generator was supplied by Bob Garner}

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

RegDef[bank, R, 0]; {Current bank}
RegDef[address, R, 1];  {Word within bank}
  RegDef[rhAddr, RH, 1];
RegDef[addres2, R, 2];
  RegDef[rhAdr2, RH, 2];
RegDef[expected, R, 3];
  RegDef[rhEx, RH, 3];
RegDef[found, R, 4];
RegDef[toAddr, R, 5];
RegDef[toAddrHi, RH, 5];


RegDef[highBank, U, 0]; {Highest bank to test}
RegDef[lowBank, U, 1]; {Lowest bank to test}

RegDef[errorCount, U, 10];  {Zeroed by Burdock.}
RegDef[diff, U, 11];
RegDef[picked, U, 12];
RegDef[dropped, U, 13];

RegDef[sticky, U, 20]; {Stick to this test.  Neg to ingore.}


RegDef[cc, R, 7]; {index for current constant}
RegDef[const, R, 8]; {value of current constant}
RegDef[oldConst, R, 9]; {value of constant on previous pass}

RegDef[rA, R, 0A];
RegDef[rB, R, 0B];
RegDef[rC, R, 0C];
RegDef[r3619, R, 0D];
RegDef[passCount, R, 0E]; {number of good passes}
RegDef[test, RH, 0E]; {test=passCount, current test}

RegDef[toData, U, 40];
RegDef[toCommand, U, 41];

RegDef[found2, U, 42];
RegDef[found3, U, 43];

RegDef[goodPasses, U, 44];
RegDef[reason, U, 45]; {Tell command file what's going on}

Set[Test.Write, 0];
Set[Test.Read, 1];
Set[Test.WriteC, 2];
Set[Test.ReadC, 3];
Set[Test.FlipC, 4];
Set[Test.WriteA, 5];
Set[Test.ReadA, 6];
Set[Test.WriteRot, 7];
Set[Test.ReadRot, 8];
Set[Test.WriteRead, 9];
Set[Test.Scan, 0A];
Set[Test.Flap, 0B];
Set[Test.MapWrite, 0D];
Set[Test.MapRead, 0E];
Set[Test.MapVerify, 0F];
Set[Test.WriteRef, 10]; Set[Test.WriteRefx, 00];
Set[Test.ReadRef, 11]; Set[Test.ReadRefx, 01];

Set[cc.First, 0];
Set[cc.0000, 00];  Set[cc.FFFF, 01];  Set[cc.5555, 02];  Set[cc.AAAA, 03];
Set[cc.3333, 04];  Set[cc.6666, 05];  Set[cc.CCCC, 06];  Set[cc.9999, 07];
Set[cc.000F, 08];  Set[cc.00F0, 09];  Set[cc.0F00, 0A];  Set[cc.F000, 0B];
Set[cc.00FF, 0C];  Set[cc.0FF0, 0D];  Set[cc.FF00, 0E];  Set[cc.F00F, 0F];

Set[cc.0101, 00];  Set[cc.0202, 01];  Set[cc.0404, 02];  Set[cc.0808, 03];
Set[cc.1010, 04];  Set[cc.2020, 05];  Set[cc.4040, 06];  Set[cc.8080, 07];
Set[cc.FEFE, 08];  Set[cc.FDFD, 09];  Set[cc.FBFB, 0A];  Set[cc.F7F7, 0B];
Set[cc.EFEF, 0C];  Set[cc.DFDF, 0D];  Set[cc.BFBF, 0E];  Set[cc.7F7F, 0F];

Set[cc.0303, 00];  Set[cc.0606, 01];  Set[cc.0C0C, 02];  Set[cc.1818, 03];
Set[cc.3030, 04];  Set[cc.6060, 05];  Set[cc.C0C0, 06];  Set[cc.8181, 07];
Set[cc.FCFC, 08];  Set[cc.F9F9, 09];  Set[cc.F3F3, 0A];  Set[cc.E7E7, 0B];
Set[cc.CFCF, 0C];  Set[cc.9F9F, 0D];  Set[cc.3F3F, 0E];  Set[cc.7E7E, 0F];

Set[cc.1111, 00];  Set[cc.2222, 01];  Set[cc.4444, 02];  Set[cc.8888, 03];
Set[cc.EEEE, 04];  Set[cc.DDDD, 05];  Set[cc.BBBB, 06];  Set[cc.7777, 07];
Set[cc.Last, 37];

Set[Setup0, 0];
Set[Setup1, 1];
Set[Setup2, 2];
Set[Setup3, 3];
Set[Setup4, 4];
Set[Setup5, 5];
Set[Setup6, 6];
Set[Setup7, 7];
Set[Setup8, 8];
Set[Setup9, 9];
Set[SetupA, 0A];
Set[SetupB, 0B];
Set[SetupC, 0C];
Set[SetupD, 0D];

Set[Fetch0, 0];
Set[Fetch1, 1];
Set[Fetch2, 2];
Set[Fetch3, 3];
Set[Fetch4, 4];
Set[Fetch5, 5];

Set[Info0, 0];
Set[Info1, 1];

Trap:	rA ← RRot1 ErrnIBnStkp, ClrIntErr, CANCELBR[$, 0F],	c1, at[0];
	Xbus ← rA 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;
	Noop, GOTO[Go],						c3;

Go:	r3619 ← 36,						c1;
	r3619 ← r3619 LRot8,					c2;
	r3619 ← r3619 or 19, {r3619 ← 3619}			c3;

	rhAddr ← 0,						c1;
	Noop,							c2;
	Noop,							c3;

{Setup Misc Board to Interrupt on XACK Timeout}
	rhAdr2 ← 4, {Misc CIO Chip}				c1;
	addres2 ← 090,						c2;
	addres2 ← addres2 LRot8, {9000}				c3;

	rA  ← addres2 + 0, L0 ← Setup0, {Master Control}	c1;
	Q ← 1, CALL[Setup], {Reset}				c2;
	Noop,							c3, at[Setup0, 10, SetupRet];

	rA  ← addres2 + 0, L0 ← Setup1, {Master Control}	c1;
	Q ← 00, CALL[Setup], {Clear Reset}			c2;
	Noop,							c3, at[Setup1, 10, SetupRet];

	rA  ← addres2 + 0, L0 ← Setup2, {Master Control}	c1;
	Q ← 080, CALL[Setup], {MIE}				c2;
	Noop,							c3, at[Setup2, 10, SetupRet];

	rA  ← addres2 + 20, L0 ← Setup3, {Port A Mode}		c1;
	Q ← 0, CALL[Setup], {Bit Port}				c2;
	Noop,							c3, at[Setup3, 10, SetupRet];

	rA  ← addres2 + 23, L0 ← Setup5, {Port A Direction}	c1;
	Q ← 0FF, CALL[Setup], {All Bits Input}			c2;
	Noop,							c3, at[Setup5, 10, SetupRet];

	rA  ← addres2 + 0E, L0 ← Setup6, {Port B Data}		c1;
	Q ← 0F, CALL[Setup], {Disable all outputs}		c2;
	Noop,							c3, at[Setup6, 10, SetupRet];

	rA  ← addres2 + 2B, L0 ← Setup7, {Port B Direction}	c1;
	Q ← 0F0, CALL[Setup], {Output on low 4 bits}		c2;
	Noop,							c3, at[Setup7, 10, SetupRet];

	rA  ← addres2 + 1, L0 ← Setup8, {Master Config Control}	c1;
	Q ← 084, CALL[Setup], {Enable Ports A+B}		c2;
	Noop,							c3, at[Setup8, 10, SetupRet];

	rA  ← addres2 + 2C, L0 ← Setup9, {Port B Special IO}	c1;
	Q ← 40, CALL[Setup], {ONEs Catcher for TOXack}		c2;
	Noop,							c3, at[Setup9, 10, SetupRet];

	rA  ← addres2 + 2D, L0 ← SetupA, {Port B Polarity}	c1;
	Q ← 40, CALL[Setup],					c2;
	Noop,							c3, at[SetupA, 10, SetupRet];

	rA  ← addres2 + 2F, L0 ← SetupB, {Port B Mask}		c1;
	Q ← 40, CALL[Setup],					c2;
	Noop,							c3, at[SetupB, 10, SetupRet];

	rA  ← addres2 + 09, L0 ← SetupC, {Port B Command}	c1;
	Q ← 0C0, CALL[Setup], {Set Interrupt Enable}		c2;
	Noop,							c3, at[SetupC, 10, SetupRet];

	rA  ← addres2 + 28, L0 ← Setup4, {Port B Mode}		c1;
	Q ← 4, CALL[Setup], {Bit Port, OR Matcher}		c2;
	Noop,							c3, at[Setup4, 10, SetupRet];

	ExtCtrl ← 5, {Init Incr, Zero, UnBlank}			c1;
	Noop,							c2;
	Noop,							c3;

	passCount ← 0, test ← Test.Write, ClrIntErr,		c1;
	goodPasses ← 0,						c2;
	reason ← 0, GOTO[MainLoop],				c3;

	
{------------------------------------------------------------------------------------}
MainLoop:
	Q ← sticky,						c1;
	[] ← Q, NegBr,						c2;
	BRANCH[$, MainLoopNext],				c3;

	test ← Q LRot0,						c1;
	Noop,							c2;
	Noop,							c3;

MainLoopNext:
	bank ← lowBank,						c1;
	expected ← passCount LRot8,				c2;
	expected ← expected + passCount,			c3;

NewBank:
{Put current bank number in decimal points.}
	Q ← bank,						c1;
	rA ← Q,							c2;
	rA ← rA LRot4,						c3;
	
	ExtCtrl ← rA or 7,					c1;
	Noop,							c2;
	Noop,							c3;

	rhAddr ← bank LRot0,					c1;
	address ← 0,						c2;
	expected ← (expected + bank) LRot1,			c3;

	rA ← LShift1 expected,					c1;
Random:	rB ← expected and 0FF,					c2;
	rB ← rB LRot12,						c3;

	rB ← rB RRot1,						c1;
	expected ← expected + rA, MesaIntBr,			c2;
	expected ← expected + rB, BRANCH[$, MesaInt],		c3;

	expected ← expected + r3619,				c1;
	Noop,							c2;
	Q ← test,						c3;

	Xbus ← Q LRot12, XDisp,					c1;
	Xbus ← test, XDisp, DISP4[DoWordHigh],			c2;
	
DoWordHigh:
	DISP4[DoWord0],						c3, at[0, 10, DoWordHigh];
	DISP4[DoWord1],						c3, at[1, 10, DoWordHigh];
	
NextWord:
	address ← address + 1, CarryBr,				c3;
	
	rA ← LShift1 expected, BRANCH[Random, $],		c1;
NextBank:
	MesaIntBr,						c2;
	BRANCH[$, MesaIntBank],					c3;

	Noop,							c1;
	Noop,							c2;
	bank ← bank + 1,					c3;
	
	Q ← highBank,						c1;
	Q ← Q - bank, NegBr,					c2;
	BRANCH[NewBank, NextTest],				c3;
 
NextTest:
	ExtCtrl ← 3, {Gets Bumped on rising edge} 		c1;
	ExtCtrl ← 7, 						c2;
	Noop,							c3;

	Q ← test,						c1;
	Xbus ← Q LRot12, XDisp,					c2;
	Xbus ← test, XDisp, DISP4[NewTestHigh],			c3;
	
NewTestHigh:
	DISP4[NewTest0],					c1, at[0, 10, NewTestHigh];
	DISP4[NewTest1],					c1, at[1, 10, NewTestHigh];
	
	
{------------------------------------------------------------------------------------}
WriteFinished:
	test ← Test.Read,					c2, at [Test.Write, 10, NewTest0];
	GOTO[MainLoopNext], 					c3;
	
ReadFinished:
	test ← Test.WriteC, 					c2, at [Test.Read, 10, NewTest0];
	cc ← cc.First, GOTO[MainLoop], 				c3;
	
WriteCFinished:
	test ← Test.ReadC,					c2, at [Test.WriteC, 10, NewTest0];
	oldConst ← const, GOTO[MainLoopNext], 			c3;
	
ReadCFinished:
	test ← Test.FlipC,					c2, at [Test.ReadC, 10, NewTest0];
	oldConst ← const, GOTO[MainLoopNext], 			c3;
	
FlipCFinished: {check for another constant}
	Q ← cc.Last,						c2, at [Test.FlipC, 10, NewTest0];
	[] ← cc xor Q, ZeroBr,					c3;

	cc ← cc + 1, BRANCH[NextConst, $],			c1;
	test ← Test.WriteA,					c2;
	GOTO[MainLoop], 					c3;
	
NextConst:
	test ← Test.ReadC,					c2;
	oldConst ← const, GOTO[MainLoop], 			c3;

WriteAFinished:
	test ← Test.ReadA,					c2, at [Test.WriteA, 10, NewTest0];
	GOTO[MainLoopNext], 					c3;
	
ReadAFinished:
	test ← Test.WriteRot,					c2, at [Test.ReadA, 10, NewTest0];
	const ← 1, 						c3;
	
RotThisConst:
	Noop, 							c1;
	Noop, 							c2;
	oldConst ← const, GOTO[MainLoop], 			c3;

WriteRotFinished:
	test ← Test.ReadRot,					c2, at [Test.WriteRot, 10, NewTest0];
	const ← oldConst, GOTO[MainLoopNext], 			c3;
	
ReadRotFinished:
	const ← LRot1 oldConst,					c2, at [Test.ReadRot, 10, NewTest0];
	[] ← const xor 1, ZeroBr,				c3;

	[] ← const xor ~1, NZeroBr, BRANCH[$, RotHole],		c1;
	BRANCH[$, RotNext],					c2;
	test ← Test.WriteRead, GOTO[MainLoop], 			c3;
	
RotHole:
	const ← ~1, CANCELBR[$],				c2;
RotNext:
	test ← Test.WriteRot, GOTO[RotThisConst],		c3;

WriteReadFinished:
	test ← Test.Scan,					c2, at [Test.WriteRead, 10, NewTest0];
	GOTO[MainLoop],						c3;

ScanFinished:
	test ← Test.Flap,					c2, at [Test.Scan, 10, NewTest0];
	GOTO[MainLoop],						c3;

FlapFinished:
	test ← Test.MapWrite,					c2, at [Test.Flap, 10, NewTest0];
	GOTO[MainLoop],						c3;

SkipMapWrite2:
	Noop,							c3;
SkipMapWrite1:
	GOTO[MapVerifyFinished],				c1;

MapWriteFinished:
	test ← Test.MapRead,					c2, at [Test.MapWrite, 10, NewTest0];
	GOTO[MainLoop],						c3;

MapReadFinished:
	test ← Test.MapVerify,					c2, at [Test.MapRead, 10, NewTest0];
	GOTO[MainLoop],						c3;

MapVerifyFinished:
	test ← Test.WriteRef,					c2, at [Test.MapVerify, 10, NewTest0];
	GOTO[MainLoop],						c3;

WriteRefFinished:
	test ← Test.ReadRef,					c2, at [Test.WriteRefx, 10, NewTest1];
	rB ← 200'd,						c3;

{I've got a board that only dies when running a real program. Try waiting longer.}
	rB ← LShift1 rB,					c1;
	rB ← LShift1 rB,					c2;
	rB ← LShift1 rB,					c3;
{
Don't touch memory for a while to give the bits a chance to fall
through the cracks in case refresh is broken.
With a 16MHz clock, an instruction takes 125 ns.
3*125ns*65000 => 25ms.
5sec/25ms => 200}
Dally:	Noop,							c1;
	rA ← rA - 1, ZeroBr,					c2;
Dally3:	BRANCH[Dally, $],					c3;
	
	Noop,							c1;
	rA ← rB and 0F0,					c2;
	ExtCtrl ← rA or 7,					c3;

	rB ← rB - 1, ZeroBr,					c1;
	rA ← 0, BRANCH[Dally3, $],				c2;
	GOTO[MainLoop],						c3;

ReadRefFinished:
	test ← Test.Write,					c2, at [Test.ReadRefx, 10, NewTest1];
	GOTO[PassFinished],					c3;

PassFinished:
	passCount ← passCount + 1,				c1;
	Q ← 1,							c2;
	reason ← Q,						c3;

	Q ← goodPasses,						c1;
	Q ← Q + 1,						c2;
	goodPasses ← Q,						c3;

AnotherGoodPass:
	Q ← Q - 100'd,						c1;
	[] ← Q, ZeroBr,						c2;
	reason ← 0, BRANCH[MainLoop, $],			c3;

	Noop,							c1;
	Q ← 2,							c2;
	reason ← Q,						c3;

AnotherHundredGoodPasses:
	Noop,							c1;
	goodPasses ← 0,						c2;
	reason ← 0, GOTO[MainLoop],				c3;
{------------------------------------------------------------------------------------}
{Write random data}
WriteRef:
	MAR ← [rhAddr, address + 0], RawRef, GOTO[Writex],	c1, at[Test.WriteRefx, 10, DoWord1];
Write:	MAR ← [rhAddr, address + 0], RawRef,			c1, at[Test.Write, 10, DoWord0];
Writex:
	MDR ← expected, GOTO[NextWord],				c2;

{Read and compare with random data}
ReadRef:
	MAR ← [rhAddr, address + 0], RawRef, GOTO[Readx],	c1, at[Test.ReadRefx, 10, DoWord1];
Read:	MAR ← [rhAddr, address + 0], RawRef,			c1, at[Test.Read, 10, DoWord0];
Readx:	Noop,							c2;
	found ← MD,						c3;
	
ReadCompare:
	[] ← found xor expected, ZeroBr,			c1;
	BRANCH[BugR, NextWord],					c2;

{------------------------------------------------------------------------------------}
{Write constant.}
WriteC:	CALL[GetConstant],					c1, at[Test.WriteC, 10, DoWord0];

WriteCConst:
	Noop,							c1, at[Test.WriteC, 10, ConstRet];
	Noop,							c2;
	Noop,							c3;
	
WriteCLoop:
	MAR ← [rhAddr, address + 0], RawRef,			c1;
	MDR ← const, address ← address + 1, CarryBr,		c2;
	BRANCH[WriteCLoop, $],					c3;
	
	GOTO[NextBank],						c1;
	

{Read and compare with constant}
ReadC:	expected ← oldConst,					c1, at[Test.ReadC, 10, DoWord0];
	Noop,							c2;
	Ybus ← 0, ZeroBr,					c3;
	
ReadCLoop:
	MAR ← [rhAddr, address + 0], RawRef, BRANCH[BugC, $],	c1;
	address ← address + 1, CarryBr,				c2;
	found ← expected xor MD, ZeroBr, BRANCH[ReadCLoop, $],	c3, LOOPHOLE[stw];
	
	BRANCH[BugC2, $],					c1;
	Noop,							c2;
	Noop,							c3;
	
	GOTO[NextBank],						c1;
	
	
{Compare old value and write new value: Catches addressing troubles}
FlipC:	expected ← oldConst, CALL[GetConstant],			c1, at[Test.FlipC, 10, DoWord0];

FlipCConst:
	Noop,							c1, at[Test.FlipC, 10, ConstRet];
	Noop,							c2;
	Noop,							c3;
	
FlipCLoop:
	MAR ← [rhAddr, address + 0], RawRef,			c1;
	Noop,							c2;
	found ← MD,						c3;
	
	[] ← found xor expected, ZeroBr,			c1;
	BRANCH[BugF, $],					c2;
	Noop,							c3;
	
	MAR ← [rhAddr, address + 0], RawRef,			c1;
	MDR ← const, address ← address + 1, CarryBr,		c2;
	BRANCH[FlipCLoop, $],					c3;
	
	GOTO[NextBank],						c1;

{Setup the right constant.}
GetConstant:
	Noop,							c2;
	Xbus ← cc LRot12, XDisp,				c3;
	
	Ybus ← cc, YDisp, DISP4[ConstHigh],			c1;
	
ConstHigh:
	DISP4[Const0],						c2, at[0, 10, ConstHigh];
	DISP4[Const1],						c2, at[1, 10, ConstHigh];
	DISP4[Const2],						c2, at[2, 10, ConstHigh];
	DISP4[Const3],						c2, at[3, 10, ConstHigh];
	
Const0:	const ← 0, GOTO[ConstDone],				c3, at[cc.0000, 10, Const0];
	const ← const xor ~const, GOTO[ConstDone],		c3, at[cc.FFFF, 10, Const0];
	const ← 055, GOTO[ConstBoth],				c3, at[cc.5555, 10, Const0];
	const ← 0AA, GOTO[ConstBoth],				c3, at[cc.AAAA, 10, Const0];
	const ← 033, GOTO[ConstBoth],				c3, at[cc.3333, 10, Const0];
	const ← 066, GOTO[ConstBoth],				c3, at[cc.6666, 10, Const0];
	const ← 0CC, GOTO[ConstBoth],				c3, at[cc.CCCC, 10, Const0];
	const ← 099, GOTO[ConstBoth],				c3, at[cc.9999, 10, Const0];
	const ← 014, GOTO[ConstDone],				c3, at[cc.000F, 10, Const0];
	const ← 028, GOTO[ConstDone],				c3, at[cc.00F0, 10, Const0];
	const ← 050, GOTO[ConstLeft],				c3, at[cc.0F00, 10, Const0];
	const ← 0A0, GOTO[ConstLeft],				c3, at[cc.F000, 10, Const0];
	const ← 0FF, GOTO[ConstDone],				c3, at[cc.00FF, 10, Const0];
	const ← 00F, GOTO[Const0FF0],				c3, at[cc.0FF0, 10, Const0];
	const ← 0FF, GOTO[ConstLeft],				c3, at[cc.FF00, 10, Const0];
	const ← 0F0, GOTO[ConstF00F],				c3, at[cc.F00F, 10, Const0];
	
Const1:	const ← 001, GOTO[ConstBoth],				c3, at[cc.0101, 10, Const1];
	const ← 002, GOTO[ConstBoth],				c3, at[cc.0202, 10, Const1];
	const ← 004, GOTO[ConstBoth],				c3, at[cc.0404, 10, Const1];
	const ← 008, GOTO[ConstBoth],				c3, at[cc.0808, 10, Const1];
	const ← 010, GOTO[ConstBoth],				c3, at[cc.1010, 10, Const1];
	const ← 020, GOTO[ConstBoth],				c3, at[cc.2020, 10, Const1];
	const ← 040, GOTO[ConstBoth],				c3, at[cc.4040, 10, Const1];
	const ← 080, GOTO[ConstBoth],				c3, at[cc.8080, 10, Const1];
	const ← 0FE, GOTO[ConstBoth],				c3, at[cc.FEFE, 10, Const1];
	const ← 0FD, GOTO[ConstBoth],				c3, at[cc.FDFD, 10, Const1];
	const ← 0FB, GOTO[ConstBoth],				c3, at[cc.FBFB, 10, Const1];
	const ← 0F7, GOTO[ConstBoth],				c3, at[cc.F7F7, 10, Const1];
	const ← 0EF, GOTO[ConstBoth],				c3, at[cc.EFEF, 10, Const1];
	const ← 0DF, GOTO[ConstBoth],				c3, at[cc.DFDF, 10, Const1];
	const ← 0BF, GOTO[ConstBoth],				c3, at[cc.BFBF, 10, Const1];
	const ← 07F, GOTO[ConstBoth],				c3, at[cc.7F7F, 10, Const1];

Const2:	const ← 003, GOTO[ConstBoth],				c3, at[cc.0303, 10, Const2];
	const ← 006, GOTO[ConstBoth],				c3, at[cc.0606, 10, Const2];
	const ← 00C, GOTO[ConstBoth],				c3, at[cc.0C0C, 10, Const2];
	const ← 018, GOTO[ConstBoth],				c3, at[cc.1818, 10, Const2];
	const ← 030, GOTO[ConstBoth],				c3, at[cc.3030, 10, Const2];
	const ← 060, GOTO[ConstBoth],				c3, at[cc.6060, 10, Const2];
	const ← 0C1, GOTO[ConstBoth],				c3, at[cc.C0C0, 10, Const2];
	const ← 080, GOTO[ConstBoth],				c3, at[cc.8181, 10, Const2];
	const ← 0FC, GOTO[ConstBoth],				c3, at[cc.FCFC, 10, Const2];
	const ← 0F9, GOTO[ConstBoth],				c3, at[cc.F9F9, 10, Const2];
	const ← 0F3, GOTO[ConstBoth],				c3, at[cc.F3F3, 10, Const2];
	const ← 0E7, GOTO[ConstBoth],				c3, at[cc.E7E7, 10, Const2];
	const ← 0CF, GOTO[ConstBoth],				c3, at[cc.CFCF, 10, Const2];
	const ← 099, GOTO[ConstBoth],				c3, at[cc.9F9F, 10, Const2];
	const ← 03F, GOTO[ConstBoth],				c3, at[cc.3F3F, 10, Const2];
	const ← 07E, GOTO[ConstBoth],				c3, at[cc.7E7E, 10, Const2];

Const3:	const ← 011, GOTO[ConstBoth],				c3, at[cc.1111, 10, Const3];
	const ← 022, GOTO[ConstBoth],				c3, at[cc.2222, 10, Const3];
	const ← 044, GOTO[ConstBoth],				c3, at[cc.4444, 10, Const3];
	const ← 088, GOTO[ConstBoth],				c3, at[cc.8888, 10, Const3];
	const ← 0EE, GOTO[ConstBoth],				c3, at[cc.EEEE, 10, Const3];
	const ← 0DD, GOTO[ConstBoth],				c3, at[cc.DDDD, 10, Const3];
	const ← 0BB, GOTO[ConstBoth],				c3, at[cc.BBBB, 10, Const3];
	const ← 077, GOTO[ConstBoth],				c3, at[cc.7777, 10, Const3];

Const0FF0:
	const ← const LRot8,					c1;
	const ← const or 0F0,					c2;
	GOTO[ConstDone],					c3;
	
ConstF00F:
	const ← const LRot8,					c1;
	const ← const or 00F,					c2;
	GOTO[ConstDone],					c3;
	
ConstLeft:
	const ← const LRot8, GOTO[ConstDisp],			c1;
ConstBoth:  {Copy the constant to the left half too}
	const ← const LRot8 or const, GOTO[ConstDisp],		c1;
ConstDone:
	Noop,							c1;
ConstDisp:
	Xbus ← test, XDisp,					c2;
	DISP4[ConstRet],					c3;

	
{------------------------------------------------------------------------------------}
{Write address}
WriteA:	Noop,							c1, at[Test.WriteA, 10, DoWord0];
	Noop,							c2;
	Noop,							c3;
	
WriteALoop:
	MAR ← [rhAddr, address + 0], RawRef,			c1;
	MDR ← address, address ← address + 1, CarryBr,		c2;
	BRANCH[WriteALoop, $],					c3;
	
	GOTO[NextBank],						c1;

{Read and compare with address}
ReadA:	Q ← rhAddr,						c1, at[Test.ReadA, 10, DoWord0];
	rhEx ← Q LRot0,						c2;
	Ybus ← 0, ZeroBr,					c3;

ReadALoop:
	MAR ← [rhEx, address + 0], RawRef, expected ← address + 0, BRANCH[BugA, $], c1;
	address ← address + 1, CarryBr,				c2;
	found ← expected xor MD, ZeroBr, BRANCH[ReadALoop, $],	c3, LOOPHOLE[stw];
	
	BRANCH[BugA2, $],					c1;
	Noop,							c2;
	Noop,							c3;
	
	GOTO[NextBank],						c1;

{------------------------------------------------------------------------------------}
{Floating one/zero test.  (Should also work with any other constant.)}
WriteRot:
	const ← LRot1 const,					c1, at[Test.WriteRot, 10, DoWord0];
	expected ← const,					c2;
	Noop,							c3;
	
WriteRotLoop:
	MAR ← [rhAddr, address + 0], RawRef,			c1;
	MDR ← expected, address ← address + 1, CarryBr,		c2;
	expected ← expected LRot1, BRANCH[WriteRotLoop, $],	c3;
	
	GOTO[NextBank],						c1;

ReadRot:
	const ← LRot1 const,					c1, at[Test.ReadRot, 10, DoWord0];
	expected ← const,					c2;
	Noop,							c3;

ReadRotLoop:
	MAR ← [rhAddr, address + 0], RawRef,			c1;
	address ← address + 1, CarryBr,				c2;
	found ← expected xor MD, ZeroBr, BRANCH[$, ReadRotEnd], c3, LOOPHOLE[stw];
	
	BRANCH[BugRt, $],					c1;
	Noop,							c2;
	expected ← expected LRot1, GOTO[ReadRotLoop],		c3;
	
ReadRotEnd:
	BRANCH[BugRt2, $],					c1;
	Noop,							c2;
	Noop,							c3;
	
	GOTO[NextBank],						c1;

{------------------------------------------------------------------------------------}
{Write, read, write, read, ...   all to the same word....}
WriteRead:
	MAR ← [rhAddr, address + 0], RawRef,			c1, at[Test.WriteRead, 10, DoWord0];
	MDR ← expected,						c2;
	Noop,							c3;
	
	MAR ← [rhAddr, address + 0], RawRef,			c1;
	Noop,							c2;
	found ← MD,						c3;
	
	MAR ← [rhAddr, address + 0], RawRef,			c1;
	MDR ← expected,						c2;
	[] ← found xor expected, ZeroBr,			c3;
	
	MAR ← [rhAddr, address + 0], RawRef, BRANCH[BugWR1, $],	c1;
	Noop,							c2;
	found ← MD,						c3;
	
	MAR ← [rhAddr, address + 0], RawRef,			c1;
	MDR ← expected,						c2;
	[] ← found xor expected, ZeroBr,			c3;
	
	MAR ← [rhAddr, address + 0], RawRef, BRANCH[BugWR2, $],	c1;
	Noop,							c2;
	found ← MD,						c3;
	
	MAR ← [rhAddr, address + 0], RawRef,			c1;
	MDR ← expected,						c2;
	[] ← found xor expected, ZeroBr,			c3;
	
	MAR ← [rhAddr, address + 0], RawRef, BRANCH[BugWR3, $],	c1;
	Noop,							c2;
	found ← MD,						c3;
	
	MAR ← [rhAddr, address + 0], RawRef,			c1;
	MDR ← expected,						c2;
	[] ← found xor expected, ZeroBr,			c3;
	
	MAR ← [rhAddr, address + 0], RawRef, BRANCH[BugWR4, $],	c1;
	Noop,							c2;
	found ← MD, GOTO[ReadCompare],				c3;
		
{------------------------------------------------------------------------------------}
{
Fill the whole bank with a constant.
Then scan through,
  checking each word.
  complementing each word,
  and then uncomplementing it.}
Scan:	Noop,							c1, at[Test.Scan, 10, DoWord0];
	Noop,							c2;
	Noop,							c3;
	
{Fill whole bank with a constant.}
ScanZap:
	MAR ← [rhAddr, address + 0], RawRef,			c1;
	MDR ← expected, address ← address + 1, CarryBr,		c2;
	BRANCH[ScanZap, $],					c3;
	
	Noop,							c1;
	Noop,							c2;
	Noop,							c3;

ScanLoop:
{Verify that this word hasn't changed.}
	MAR ← [rhAddr, address + 0], RawRef,			c1;
	Noop,							c2;
	found ← expected xor MD, ZeroBr,			c3, LOOPHOLE[stw];
	
{Flip this word.}
	MAR ← [rhAddr, address + 0], RawRef, BRANCH[BugS1, $],	c1;
	MDR ← ~expected,					c2;
	Noop,							c3;
	
{Verify that it flipped.}
	MAR ← [rhAddr, address + 0], RawRef,			c1;
	Noop,							c2;
	found ← ~expected xor MD, ZeroBr,			c3, LOOPHOLE[stw];
	
{Put it back the right way.}
	MAR ← [rhAddr, address + 0], RawRef, BRANCH[BugS2, $],	c1;
	MDR ← expected, address ← address + 1, CarryBr,		c2;
	BRANCH[ScanLoop, $],					c3;
	
	Noop,							c1;
	Noop,							c2;
	[] ← 0, ZeroBr,						c3;

ScanCheck:
	MAR ← [rhAddr, address + 0], RawRef, BRANCH[BugS3, $],	c1;
	address ← address + 1, CarryBr,				c2;
	found ← expected xor MD, ZeroBr, BRANCH[ScanCheck, $],	c3, LOOPHOLE[stw];
	
	BRANCH[BugS4, $],					c1;
	Noop,							c2;
	Noop,							c3;
	
	GOTO[NextBank],						c1;

{Scan a word of 0s through a bank full of 1s.}
Flap:
	Q ← rhAddr,						c1, at[Test.Flap, 10, DoWord0];
	rhAdr2 ← Q LRot0,					c2;
	addres2 ← ~address,					c3;
	
{Fill whole bank with a constant.}
FlapZap:
	MAR ← [rhAddr, address + 0], RawRef,			c1;
	MDR ← expected, address ← address + 1, CarryBr,		c2;
	BRANCH[FlapZap, $],					c3;
	
	Noop,							c1;
	Noop,							c2;
	Noop,							c3;

FlapLoop:
{Verify that this word hasn't changed.}
	MAR ← [rhAddr, address + 0], RawRef,			c1;
	Noop,							c2;
	found ← expected xor MD, ZeroBr,			c3, LOOPHOLE[stw];
	
{Check word at complement of this address.}
	MAR ← [rhAdr2, addres2 + 0], RawRef, BRANCH[BugF1, $],	c1;
	Noop,							c2;
	found ← expected xor MD, ZeroBr,			c3, LOOPHOLE[stw];
	
{Flip this word.}
	MAR ← [rhAddr, address + 0], RawRef, BRANCH[BugF2, $],	c1;
	MDR ← ~expected,					c2;
	Noop,							c3;
	
{Again, check word at complement of this address.}
	MAR ← [rhAdr2, addres2 + 0], RawRef,			c1;
	Noop,							c2;
	found ← expected xor MD, ZeroBr,			c3, LOOPHOLE[stw];
	
{Verify that it flipped.}
	MAR ← [rhAddr, address + 0], RawRef, BRANCH[BugF3, $],	c1;
	Noop,							c2;
	found ← ~expected xor MD, ZeroBr,			c3, LOOPHOLE[stw];
	
{Yet again, check word at complement of this address.}
	MAR ← [rhAdr2, addres2 + 0], RawRef, BRANCH[BugF4, $],	c1;
	Noop,							c2;
	found ← expected xor MD, ZeroBr,			c3, LOOPHOLE[stw];
	
{Put it back the right way.}
	MAR ← [rhAddr, address + 0], RawRef, BRANCH[BugF5, $],	c1;
	MDR ← expected, address ← address + 1, CarryBr,		c2;
	addres2 ← addres2 - 1, BRANCH[FlapLoop, $],		c3;
	
	Noop,							c1;
	Noop,							c2;
	[] ← 0, ZeroBr,						c3;

{Scan whole bank, just in case...}
FlapCheck:
	MAR ← [rhAddr, address + 0], RawRef, BRANCH[BugF6, $],	c1;
	address ← address + 1, CarryBr,				c2;
	found ← expected xor MD, ZeroBr, BRANCH[FlapCheck, $],	c3, LOOPHOLE[stw];
	
	BRANCH[BugF7, $],					c1;
	Noop,							c2;
	Noop,							c3;
	
	GOTO[NextBank],						c1;

{------------------------------------------------------------------------------------}
{The map tests ignore the normal loop structure.
They want to iterate through all of virtural memory.}

MapWrite:
	Q ← highBank,						c1, at[Test.MapWrite, 10, DoWord0];
	[] ← Q - 1, NegBr, {MAP is in second bank}		c2;
	Q ← lowBank - 1, BRANCH[$, SkipMapWrite1],		c3, LOOPHOLE[niblTiming];

	[] ← Q - 1, NegBr,					c1;
	expected ← 0, BRANCH[SkipMapWrite2, $],			c2;
	Q ← 0, rhAddr ← 0,					c3;

MapWriteLoop:
	Map ← [rhAddr, address + 0],				c1;
	MDR ← expected, expected ← expected + 1, PgCarryBr,	c2;
	address ← address + 0FF + 1, BRANCH[MapWriteLoop, $],	c3;
	
	Q ← Q + 1, PgCarryBr,					c1;
	BRANCH[$, DoneMapWrite],				c2;
	rhAddr ← Q LRot0, GOTO[MapWriteLoop],			c3;

DoneMapWrite:
	GOTO[NextTest],						c3;


MapRead:
	expected ← 0,						c1, at[Test.MapRead, 10, DoWord0];
	Q ← 0, rhAddr ← 0,					c2;
	Noop,							c3;

MapReadLoop:
	Map ← [rhAddr, address + 0],				c1;
	Noop,							c2;
	found ← MD,						c3;
	
	[] ← found xor expected, ZeroBr,			c1;
	expected ← expected + 1, PgCarryBr, BRANCH[BugMap, $],	c2;
	address ← address + 0FF + 1, BRANCH[MapReadLoop, $],	c3;

	Q ← Q + 1, PgCarryBr,					c1;
	BRANCH[$, DoneMapRead],					c2;
	rhAddr ← Q LRot0, GOTO[MapReadLoop],			c3;

DoneMapRead:
	GOTO[NextTest],						c3;

	
{Code copied from ReadA.  Each map word should contain it's address within the bank.}
MapVerify:
	Noop,							c1, at[Test.MapVerify, 10, DoWord0];
	rhEx ← 1,						c2;
	Ybus ← 0, ZeroBr,					c3;

MapVLoop:
	MAR ← [rhEx, address + 0], expected ← address + 0, BRANCH[BugV, $], c1;
	address ← address + 1, CarryBr,				c2;
	found ← expected xor MD, ZeroBr, BRANCH[MapVLoop, $],	c3, LOOPHOLE[stw];
	
	BRANCH[BugV2, $],					c1;
	Noop,							c2;
	GOTO[NextTest],						c3;
	
{------------------------------------------------------------------------------------}

BugR:	GOTO[Error],						c3;
BugC:	found ← found xor expected, CANCELBR[Backup],		c2;
BugC2:	found ← found xor expected, CANCELBR[Backup],		c2;
BugF:	GOTO[Error],						c3;
BugA:	found ← found xor expected, CANCELBR[Backup],		c2;
BugA2:	found ← found xor expected, CANCELBR[Backup],		c2;
BugRt:	found ← found xor expected, CANCELBR[Backup],		c2;
BugRt2:	found ← found xor expected, CANCELBR[Backup],		c2;
BugWR1:	CANCELBR[Errc3],					c2;
BugWR2:	CANCELBR[Errc3],					c2;
BugWR3:	CANCELBR[Errc3],					c2;
BugWR4:	CANCELBR[Errc3],					c2;
BugS1:	found ← found xor expected, CANCELBR[Errc3],		c2;
BugS2:	found ← found xor ~expected, CANCELBR[ErrFlip],		c2;
BugS3:	found ← found xor expected, CANCELBR[Backup],		c2;
BugS4:	found ← found xor expected, CANCELBR[Backup],		c2;
BugF1:	found ← found xor expected, CANCELBR[Errc3],		c2;
BugF2:	found ← found xor expected, CANCELBR[Swap],		c2;
BugF3:	found ← found xor expected, CANCELBR[Swap],		c2;
BugF4:	found ← found xor ~expected, CANCELBR[ErrFlip],		c2;
BugF5:	found ← found xor expected, CANCELBR[Swap],		c2;
BugF6:	found ← found xor expected, CANCELBR[Backup],		c2;
BugF7:	found ← found xor expected, CANCELBR[Backup],		c2;
BugMap:	expected ← expected - 1, CANCELBR[Error],		c3;
BugV:	found ← found xor expected, CANCELBR[Backup],		c2;
BugV2:	found ← found xor expected, CANCELBR[Backup],		c2;

Swap:	address ← ~addres2, GOTO[Error],			c3;
Backup: address ← address - 1, GOTO[Error],			c3;
	
ErrFlip:
	expected ← ~expected, GOTO[Error],			c3;
Errc3: 	Noop,							c3;

Error:	Noop,							c1;
	Noop,							c2;
	Q ← MD,							c3, LOOPHOLE[mdok];

	found2 ← Q,						c1;
	Noop,							c2;
	Noop,							c3;

	Q ← errorCount,						c1;
	Q ← Q + 1,						c2;
	errorCount ← Q,						c3;

	MAR← [rhAddr, address + 0], RawRef,			c1;
	Noop,							c2;
	Q ← MD,							c3;

	found3 ← Q,						c1;
	Noop,							c2;
	Noop,							c3;

	Q ← found xor expected,					c1;
	diff ← Q,						c2;
	Noop,							c3;

	rA ← Q and ~expected,					c1;
	picked ← rA,						c2;
	Noop,							c3;

	rA ← Q and expected,					c1;
	dropped ← rA,						c2;
	Noop,							c3;

DataMismatch:
	Noop,							c1;
	MesaIntBr,						c2;
	BRANCH[$, DataMismatchWithParityError],			c3;
	
DataMismatchButNoParityError:
	Noop,							c1;
	Noop,							c2;
	GOTO[Go],						c3;
	
DataMismatchWithParityError:
	Noop,							c1;
	L1 ← Info0,						c2;
	CALL[Info],						c3;
	
DataMismatchAndParityError:
	Noop,							c1, at[Info0, 10, InfoRet];
	Noop,							c2;
	GOTO[Go],						c3;
	
{------------------------------------------------------------------------------------}

MesaIntBank:
	Noop,							c1;
	Noop,							c2;
	Noop,							c3;
	
MesaInt:
	Noop,							c1;
	L1 ← Info1,						c2;
	CALL[Info],						c3;
	
	Q ← errorCount,						c1, at[Info1, 10, InfoRet];
	Q ← Q + 1,						c2;
	errorCount ← Q,						c3;

MesaIntIsProbablyAParityError:
	Noop,							c1;
	Noop,							c2;
	GOTO[Go],						c3;
	
{------------------------------------------------------------------------------------}

Info:
	rhAdr2 ← 4, {Misc CIO Chip}				c1;
	addres2 ← 090,						c2;
	addres2 ← addres2 LRot8, {9000}				c3;

	Q ← 05, L0 ← Fetch0, {RdTODatL}				c1;
	CALL[Fetch],						c2;
	toData ← rA,						c3, at[Fetch0, 10, FetchRet];

	Q ← 04, L0 ← Fetch1, {RdTODatH}				c1;
	CALL[Fetch],						c2;
	rA ← rA LRot8,						c3, at[Fetch1, 10, FetchRet];

	Q ← toData,						c1;
	rA ← rA or Q,						c2;
	toData ← rA,						c3;

	Q ← 03, L0 ← Fetch2, {RdTOCmd}				c1;
	CALL[Fetch],						c2;
	toCommand ← rA,						c3, at[Fetch2, 10, FetchRet];

	Q ← 00, L0 ← Fetch3, {RdTOAdrH}				c1;
	CALL[Fetch],						c2;
	toAddrHi ← rA LRot0,					c3, at[Fetch3, 10, FetchRet];

	Q ← 02, L0 ← Fetch4, {RdTOAdrL}				c1;
	CALL[Fetch],						c2;
	toAddr ← rA,						c3, at[Fetch4, 10, FetchRet];

	Q ← 01, L0 ← Fetch5, {RdTOAdrM}				c1;
	CALL[Fetch],						c2;
	rA ← rA LRot8,						c3, at[Fetch5, 10, FetchRet];

	Q ← toAddr,						c1;
	Q ← Q or rA, L1Disp,					c2;
	toAddr ← Q, DISP4[InfoRet],				c3;
	
{------------------------------------------------------------------------------------}

Setup:
	Noop,							c3;

	IO ← [rhAdr2, rA + 0], L0Disp,				c1;
	MDR ← Q, DISP4[SetupRet],				c2;

{------------------------------------------------------------------------------------}

Fetch:
	Noop,							c3;

	IO ← [rhAdr2, addres2 + 0E], {Port B Data}		c1;
	MDR ← Q + 8,						c2;
	Noop,							c3;

	IO ← [rhAdr2, addres2 + 0D], {Port A Data}		c1;
	Noop,							c2;
	rA ← MD,						c3;

	L0Disp,							c1;
	DISP4[FetchRet],					c2;

{------------------------------------------------------------------------------------}

{Scope loops: Let normal stuff run a while to initialize things..}

SpinBankLoop:
	MAR ← [rhAddr, address + 0], RawRef,		c1;
	MDR ← expected,					c2;
	rhAddr ← 1,					c3;

	MAR ← [rhAddr, address + 0], RawRef,		c1;
	MDR ← expected,					c2;
	rhAddr ← 2,					c3;

	MAR ← [rhAddr, address + 0], RawRef,		c1;
	MDR ← expected,					c2;
	rhAddr ← 3,					c3;

	MAR ← [rhAddr, address + 0], RawRef,		c1;
	MDR ← expected,					c2;
	rhAddr ← 4,					c3;

	MAR ← [rhAddr, address + 0], RawRef,		c1;
	MDR ← expected,					c2;
	rhAddr ← 5,					c3;

	MAR ← [rhAddr, address + 0], RawRef,		c1;
	MDR ← expected,					c2;
	rhAddr ← 6,					c3;

	MAR ← [rhAddr, address + 0], RawRef,		c1;
	MDR ← expected,					c2;
	rhAddr ← 7,					c3;

	MAR ← [rhAddr, address + 0], RawRef,		c1;
	MDR ← expected,					c2;
	rhAddr ← 0,					c3;

	address ← address + 1,				c1;
	expected ← expected + 1,			c2;
	Noop, GOTO[SpinBankLoop],			c3;


FlapDataAndAddress:
	Q ← rhAddr,					c1;
	Q ← Q and highBank,				c2;
	rhAdr2 ← Q LRot0,				c3;
	
	Noop,						c1;
	Noop,						c2;
	addres2 ← ~address,				c3;

FlapDataAndAddressLoop:
	MAR ← [rhAddr, address + 0], RawRef,		c1;
	MDR ← expected,					c2;
	Noop,						c3;

	MAR ← [rhAdr2, addres2 + 0], RawRef,		c1;
	MDR ← ~expected,				c2;
	Noop,						c3;

	MAR ← [rhAddr, address + 0], RawRef,		c1;
	Noop,						c2;
	found ← MD,					c3;

	MAR ← [rhAdr2, addres2 + 0], RawRef,		c1;
	Noop,						c2;
	found ← MD,					c3;

	Noop,						c1;
	Noop,						c2;
	Noop,						c3;

	Noop,						c1;
	Noop,						c2;
	Noop,						c3;

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


SpinData:
	MAR ← [rhAddr, address + 0], RawRef,		c1;
	MDR ← expected,					c2;
	Noop,						c3;

	MAR ← [rhAddr, address + 0], RawRef,		c1;
	Noop,						c2;
	found ← MD,					c3;

	expected ← expected + 1,			c1;
	Noop,						c2;
	Noop, GOTO[SpinData],				c3;


SpinAddress:
	MAR ← [rhAddr, address + 0], RawRef,		c1;
	MDR ← expected,					c2;
	Noop,						c3;

	MAR ← [rhAddr, address + 0], RawRef,		c1;
	Noop,						c2;
	found ← MD,					c3;

	address ← address + 1,				c1;
	Noop,						c2;
	Noop, GOTO[SpinAddress],			c3;

FlapMap:
	Q ← rhAddr,					c1;
	rhAdr2 ← Q LRot0,				c2;
	addres2 ← ~address,				c3;
	
FlapMapLoop:
	MAR ← [rhAddr, address + 0], RawRef,		c1;
	MDR ← expected,					c2;
	Noop,						c3;

	Map ← [rhAdr2, addres2 + 0], RawRef,		c1;
	MDR ← ~expected,				c2;
	Noop,						c3;

	MAR ← [rhAddr, address + 0], RawRef,		c1;
	Noop,						c2;
	found ← MD,					c3;

	Map ← [rhAdr2, addres2 + 0], RawRef,		c1;
	Noop,						c2;
	found ← MD,					c3;

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

ScopeWriteLoop:
	MAR ← [rhAddr, address + 0], RawRef,		c1;
	MDR ← expected,	rA ← rA + 1, CarryBr,		c2;
	BRANCH[ScopeWriteLoop, $],			c3;

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

ScopeReadLoop:
	MAR ← [rhAddr, address + 0], RawRef,		c1;
	rA ← rA + 1, CarryBr,				c2;
	found ← MD, BRANCH[ScopeReadLoop, $],		c3;
	
	Noop,						c1;
	Noop,						c2;
	GOTO[ScopeReadLoop],				c3;


WriteReadLoop:
	MAR ← [rhAddr, address + 0], RawRef,		c1;
	MDR ← expected,					c2;
	Noop,						c3;

	Noop,						c1;
	Noop,						c2;
	Noop,						c3;

	MAR ← [rhAddr, address + 0], RawRef,		c1;
	Noop,						c2;
	found ← MD,					c3;
	
	Noop, c1;  Noop, c2;  Noop, c3;
	Noop, c1;  Noop, c2;  Noop, c3;
	Noop, c1;  Noop, c2;  Noop, c3;
	
	Noop,						c1;
	expected ← expected RRot1,			c2;
	GOTO[WriteReadLoop],				c3;


{Note that bank/rhAddr doesn't really matter for IO references....}
ScopeWriteLoopIO:
	IO ← [rhAddr, address + 0],			c1;
	MDR ← expected,					c2;
	Noop,						c3;

	Noop,						c1;
	Noop,						c2;
	GOTO[ScopeWriteLoopIO],				c3;
	
ScopeReadLoopIO:
	IO ← [rhAddr, address + 0],			c1;
	Noop,						c2;
	found ← MD,					c3;

	Noop,						c1;
	Noop,						c2;
	Noop, GOTO[ScopeReadLoopIO],			c3;
	
ScopeReadLoopIOClump:
	IO ← [rhAddr, address + 0],			c1;
	Noop,						c2;
	found ← MD,					c3;

	IO ← [rhAddr, address + 0],			c1;
	Noop,						c2;
	found ← MD,					c3;

	IO ← [rhAddr, address + 0],			c1;
	Noop,						c2;
	found ← MD,					c3;

	IO ← [rhAddr, address + 0],			c1;
	Noop,						c2;
	found ← MD,					c3;

	IO ← [rhAddr, address + 0],			c1;
	Noop,						c2;
	found ← MD,					c3;

	Noop, c1;  Noop, c2;  Noop, c3;
	Noop, c1;  Noop, c2;  Noop, c3;
	Noop, c1;  Noop, c2;  Noop, c3;
	Noop, c1;  Noop, c2;  Noop, c3;
	Noop, c1;  Noop, c2;  Noop, c3;
	
	Noop, c1;  Noop, c2;  Noop, c3;
	Noop, c1;  Noop, c2;  Noop, c3;
	Noop, c1;  Noop, c2;  Noop, c3;
	Noop, c1;  Noop, c2;  Noop, c3;
	Noop, c1;  Noop, c2;  Noop, c3;
	
	Noop, c1;  Noop, c2;  Noop, c3;
	Noop, c1;  Noop, c2;  Noop, c3;
	Noop, c1;  Noop, c2;  Noop, c3;
	Noop, c1;  Noop, c2;  Noop, c3;
	Noop, c1;  Noop, c2;  Noop, c3;
	
	Noop,						c1;
	Noop,						c2;
	Noop, GOTO[ScopeReadLoopIOClump],		c3;
	
SlowScopeReadLoopIO:
	IO ← [rhAddr, address + 0],			c1;
	Noop,						c2;
	found ← MD,					c3;
	
	Noop, c1;  Noop, c2;  Noop, c3;
	Noop, c1;  Noop, c2;  Noop, c3;
	Noop, c1;  Noop, c2;  Noop, c3;
	Noop, c1;  Noop, c2;  Noop, c3;
	Noop, c1;  Noop, c2;  Noop, c3;
	
	Noop,						c1;
	Noop,						c2;
	Noop, GOTO[SlowScopeReadLoopIO],		c3;
	

SpinIOContents:
	IO ← [rhAddr, address + 0],			c1;
	MDR ← expected,					c2;
	Noop,						c3;

	IO ← [rhAddr, address + 0],			c1;
	Noop,						c2;
	found ← MD,					c3;

	expected ← expected + 1,			c1;
	Noop,						c2;
	Noop, GOTO[SpinIOContents],			c3;
	
FlapIOContents:
	IO ← [rhAddr, address + 0],			c1;
	MDR ← expected,					c2;
	Noop,						c3;

	IO ← [rhAddr, address + 0],			c1;
	MDR ← ~expected,				c2;
	Noop,						c3;

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

{------------------------------------------------------------------------------------}
KickPulseGen:
	IO ← [rhAddr, address + 0],			c1;
	MDR ← expected,					c2;
	rB ← rC,					c3;

	Noop,						c1;
	address ← address + 1, NibCarryBr,		c2;
	BRANCH[KickPulseGen, $],			c3;
	
	address ← address and ~010,			c1;
	ExtCtrl ← 3, {Gets Bumped on rising edge} 	c2;
	ExtCtrl ← 7, 					c3;

KickPulseGenA:
	Noop,						c1;
	rA ← rA - 1, ZeroBr,				c2;
KickPulseGenB:
	BRANCH[KickPulseGenA, $],			c3;
	
	rB ← rB - 1, ZeroBr,				c1;
	BRANCH[KickPulseGenB, $],			c2;
	Noop,						c3;
	
	expected ← expected + 1,			c1;
	Noop,						c2;
	Noop, GOTO[KickPulseGen],			c3;
	
{------------------------------------------------------------------------------------}
ReadHostNumber:
	rhAddr ← 0,					c1;
	address ← 32,					c2;
	address ← address LRot8,			c3;

ReadHostNumberLoop:
	IO ← [rhAddr, address + 0],			c1;
	Noop,						c2;
	rA ← MD,					c3;

	IO ← [rhAddr, address + 1],			c1;
	Noop,						c2;
	rB ← MD,					c3;

	IO ← [rhAddr, address + 2],			c1;
	Noop,						c2;
	rC ← MD,					c3;

	Noop,						c1;
	Noop,						c2;
	Noop, GOTO[ReadHostNumberLoop],			c3;
	
{------------------------------------------------------------------------------------}
CycleChecker:
	Noop,						c1;
	XC2npcDisp,					c2;
	BRANCH[WrongCycle, CycleChecker, 0D],		c3;

WrongCycle:
	Noop,						c*;
GetInSync:
	XC2npcDisp,					c*;
	BRANCH[GetInSync, CycleGlitch, 0D],		c*;

CycleGlitch:
	ExtCtrl ← 3, {Gets Bumped on rising edge} 	c1;
	ExtCtrl ← 7,					c2;
	GOTO[CycleChecker],				c3;