{File name <tajo>BusExt.mc
Description: DandeLion Interlisp Emulator Bus Extension
Author: Purcell
Created: 31-May-84 16:45:34
Purcell  8-Mar-85 18:32:51  add bytes reversed code 
Purcell 6-Mar-85 14:57:37  fix bug in pcbus 
charnley   early feb   {%L} change for intermezzo 
Purcell 4-Aug-84  3:07:29  remove delay; mask adc to 12 bits 
Purcell 4-Aug-84  1:02:24  add delay to pcblt 
Purcell 1-Aug-84 20:48:27  forgot to "←ib" after "←ibNA"; 5 needed in pipe primed
Purcell 30-Jul-84 20:59:53  start more pipe on inputs (4) (5 needs work]
Purcell 28-Jul-84 15:56:16 check out
Purcell 28-Jul-84 11:53:43 more desk checking of block, test bit 9
Purcell 27-Jul-84  0:42:14 restart pc bus block opcode
Purcell 11-Jul-84 22:39:45 pc bus block write
Purcell 11-Jul-84 16:41:15 add pipe delay in input and move TOSH← earlier
Purcell 10-Jul-84  9:29:57 fix Y0 bug in output
Purcell 26-Jun-84 14:19:53
}
{INPUT:	TOSH ← smallpl, DISP4[MiscIn],	c1, at[0D,10, MiscDisp];}

{
(SETQ MBUS.OUTL (PLUS 0 (LLSH REG 4)))
(SETQ MBUS.OUTM (PLUS 11 (LLSH REG 4)))
(SETQ MBUS.INL (PLUS 9 (LLSH REG 4)))
(SETQ MBUS.INM (PLUS 10 (LLSH REG 4)))

(\DEVICE.OUTPUT DATA MBUS.OUTL)
(\DEVICE.OUTPUT DATA MBUS.OUTM)
(SETQ DATA (\DEVICE.INPUT MBUS.INL))
(SETQ DATA (\DEVICE.INPUT MBUS.INM))

(\PCBLT (alpha op) VIRTUALADDR PCADDRH PCADDRL COUNT)
L3Disp values initialized to alpha byte
1,2 bit data size: 0=word, 1=byte, 2=reversed bytes, 3=nibble
4 bit	0=output, 1=input
8 bit	extra states

0	read/output word
1,9	read/output bytes
2,A	read/output bytes reversed
3,7,B,F read/output nibbles
4	input/write word
5,D	input/write bytes
6,E	input/write bytes reversed
}

{PV}	RegDef[rAddr, R, 3]; {pc bus address low 16 bits}
{TOSH}	RegDef[rDataIn, R, 1]; 
{TT}	RegDef[rDataOut, R, 2]; {rDataOut not needed during cross so alias with and use TT}

{Rx	real
TOS	word count remaining (end input/write at 0; end read/output at -1)(fetch from virt+TOS-1)
Q	used by mapping routine
}
{
RegDef[uVirtL, U, 27];{TT}{uTT}		{ok}
RegDef[uVirtH, U, 0C];{TOS}{ibNA}	{BitBlt}{OK}
RegDef[uBusCtl, U, 2];{fZ=2}		{BitBlt}{OK}
RegDef[uAddr, U, 33];{rAddr}{fZ=3}	{OK} - moved to 43
RegDef[uDataOut, U, 12];{fZ=2}	{OK} - moved to 42
}

{L0	unused
L1	Fix {L1.NoFixes}
L2	0=normal, 1=test loop
L3	phase and op}

PCBKW:	FloatNop,	L1 ← L1.NoFixes,		c1, opcode[60'b];
	uPV ← PV, L2 ← 0,		c2;
	Rx ← 0FF + 1,	c3;

	Q ← uPPsave,	c1;
	PPort ← Q and ~Rx,	c2;
	,	c3;

	
pcA1:	MAR ← [rhS, S+0],	c1;
	S ← S - 2, 	c2;
	rAddr{L} ← MD, FloatNop,	c3;
	
pcA2:	MAR ← [rhS, S+0],	c1;
	S ← S - 2, 		c2;
	FLTimes.WA.WB{% fZ=3}, Float.M, Xbus{mBusAddrM} ← MD,	c3;
	
pcA3:	MAR ← [rhS, S+0],	c1;
	S ← S - 1,		c2;
	uTOS ← TOS, TT ← MD{virtL},	c3;
	
{TT=rDataOut=virtL}	
pcA4:	Rx{2*TOS} ← TOS LShift1, Xbus ← ibNA, XDisp,	c1;
	rDataIn{4*TOS} ← Rx LShift1, DISP4[pcAdd, 0C],	c2;

	rAddr ← rAddr + TOS, GOTO[pcArg],	c3, at[0C, 10, pcAdd];{word addressing}
	rAddr ← rAddr + Rx{2*TOS}, GOTO[pcArg],	c3, at[0D, 10, pcAdd];{byte addressing}
	rAddr ← rAddr + Rx{2*TOS}, GOTO[pcArg],	c3, at[0E, 10, pcAdd];{byte reversed}
	rAddr ← rAddr + rDataIn{4*TOS}, GOTO[pcArg],	c3, at[0F, 10, pcAdd];{nibble addressing}

pcArg:	MAR ← [rhS, S+0],	c1;
	S ← S + 5,		c2;
	uVirtL ← TT, TT ← MD{virtH}, 	c3;
	
	rAddr ← rAddr -1,	c1;
	uAddr ← rAddr, Rx ← 0{force remap}, 		c2;
	uVirtH ← TT, Xbus ← ibNA, XDisp,	c3;
	
pcBCtl:	TOSH ← 0{uBusCtl}, Float.L, Xbus{mBusAddrL} ← uAddr, BRANCH[pcBOut, pcBIn, 0B],	c1;
pcBIn:	TOSH ← TOSH or 1, GOTO[pcCtlj],	c2; {set mBusCtl for reads}
pcBOut:	TOSH ← TOSH or 2, GOTO[pcCtlj],	c2; {set mBusCtl for writes}
pcCtlj: uBusCtl ← TOSH,		c3;

	Xbus ← ib, XDisp,	c1;
	Float.M, Xbus{mBusCtl} ← uBusCtl, L3 ← 0, DISP4[pcBlk],	c2;

{pcRead subroutine; return to pcReadRet+L3, use uAddr, update uAddr, read virt+TOS-1}	
pcRead:	MAR ← Rx ← [rhRx, Rx-1], BRANCH[$, pcDn2],	c1;
	rAddr ← rAddr -1, Float.L, Xbus{mBusAddrL} ← uAddr, L3Disp, BRANCH[$, pcRcr, 1],	c2;
pcRead3:	uAddr ← rAddr, rDataOut ← MD, RET[pcReadRet],		c3;
	
{pcBus subroutine: return to pcBusRet+L3, used both for input and output; rDataIn ignored on output}
pcBus2:	Noop, c2;
pcBus3:	uAddr ← rAddr,	c3;
	uDataOut ← rDataOut,	c1;{% good for 5; ok others ?}
	Xbus ← FloatResult{mBusIData}, FLFloatA{fZ=2}, Float.L,	c2;

pcBus:	Noop,	c3;
pcBus1:	Noop, CANCELBR[$, 3],	c1;
	Noop,	c2;
	Ybus ← rDataIn, Xbus ← PPort, XwdDisp{9(,10)},	c3;

{pcBus1:}	Q ← rDataIn or FloatResult, L3Disp, BRANCH[$, pcWait, 1],	c1;
	rDataIn ← Q, Float.L, Xbus{mBusOData} ← uDataOut, RET[pcBusRet],	c2;
pcWait: Xbus ← FloatResult{mBusIData}, FLFloatA{fZ=2}, Float.L, CANCELBR[pcBus, 0F],	c2;

		
{0: Block Read/Output Words}{uAddr=rAddr=last, TOS=cnt}
	CALL[pcRead],	c3, at[0, 10, pcBlk];

{pcRead:	MAR ← Rx ← [rhRx, Rx-1],	c1;
pcRead2: rAddr ← rAddr -1, Float.L, Xbus{mBusAddrL} ← uAddr, L3Disp, BRANCH[$, pcRcr, 1],	c2;
	uAddr ← rAddr, rDataOut ← MD, RET[pcReadRet],		c3;
}	
pcOW:	TOS ← TOS -1, CarryBr, c1, at[0, 10, pcReadRet];
	uDataOut ← rDataOut, BRANCH[pcDn, pcBus, 0E], c2;

{pcBus:	Xbus ← PPort, XwdDisp{9,10},	c3;
pcBus1:	Q ← rDataIn or FloatResult, L3Disp, BRANCH[$, pcWait, 1],	c1;
	rDataIn ← Q, Float.L, Xbus{mBusOData} ← uDataOut, RET[pcBusRet],	c2;
}
	Noop, CALL[pcRead], c3, at[0, 10, pcBusRet], c3;



{1: Block Read/Output Bytes}
	CALL[pcRead],	c3, at[1, 10, pcBlk];
	
{pcRead:	MAR ← Rx ← [rhRx, Rx-1],	c1;
pcRead2: rAddr ← rAddr -1, Float.L, Xbus{mBusAddrL} ← uAddr, L3Disp, BRANCH[$, pcRcr, 1],	c2;
	uAddr ← rAddr, rDataOut ← MD, RET[pcReadRet],		c3;
}
pcOB:	TOS ← TOS -1, CarryBr, L3 ← 9, c1, at[1, 10, pcReadRet];
	uDataOut ← rDataOut, BRANCH[pcDn, pcBus, 0E], c2;
	
	rDataOut ← rDataOut LRot8, L3 ← 1, c3, at[9, 10, pcBusRet];
pcOBB:	rAddr ← rAddr -1, Float.L, Xbus{mBusAddrL} ← uAddr, GOTO[pcBus2], c1;

	CALL[pcRead], c3, at[1, 10, pcBusRet], c3;


{2: Block Read/Output Bytes Reversed}
	Ybus ← TOS, ZeroBr, CALL[pcRead],	c3, at[2, 10, pcBlk];
	
{pcRead:	MAR ← Rx ← [rhRx, Rx-1],	c1;
pcRead2: rAddr ← rAddr -1, Float.L, Xbus{mBusAddrL} ← uAddr, L3Disp, BRANCH[$, pcRcr, 1],	c2;
	uAddr ← rAddr, rDataOut ← MD, RET[pcReadRet],		c3;
}
{pcOBr:	TOS ← TOS -1, CarryBr, L3 ← 0A, c1, at[2, 10, pcReadRet];
	rDataOut ← rDataOut LRot8, BRANCH[pcDnR, pcBusR, 0E], c2;
	
pcBusR:	uDataOut ← rDataOut, Xbus ← PPort, XwdDisp{9(,10)}, GOTO[pcBus1],	c3;
pcDnR:	S ← S - 6, L2Disp, GOTO[pcDn1],	c3;
}
pcOBr:	rDataOut ← rDataOut LRot8,	c1, at[2, 10, pcReadRet];
	uDataOut ← rDataOut, L3 ← 0A, c2;
	TOS ← TOS-1, Xbus ← PPort, XwdDisp{9(,10)}, GOTO[pcBus1], c3;
{TOS was tested for zero at Read}	
	

	rDataOut ← rDataOut LRot8, L3 ← 2, c3, at[0A, 10, pcBusRet];
pcOBBr:	rAddr ← rAddr -1, Float.L, Xbus{mBusAddrL} ← uAddr, GOTO[pcBus2], c1;

	Ybus ← TOS, ZeroBr, , CALL[pcRead], c3, at[2, 10, pcBusRet], c3;


{3: Block Read/Output Nibbles}
	CALL[pcRead],	c3, at[3, 10, pcBlk];
	
{pcRead:	MAR ← Rx ← [rhRx, Rx-1],	c1;
pcRead2: rAddr ← rAddr -1, Float.L, Xbus{mBusAddrL} ← uAddr, L3Disp, BRANCH[$, pcRcr, 1],	c2;
	uAddr ← rAddr, rDataOut ← MD, RET[pcReadRet],		c3;}

pcON:	TOS ← TOS -1, CarryBr, L3 ← 7, c1, at[3, 10, pcReadRet];
	uDataOut ← rDataOut, BRANCH[pcDn, pcBus, 0E], c2;
	
	rDataOut ← rDataOut LRot12, L3 ← 0B, c3, at[7, 10, pcBusRet];
pcONN:	rAddr ← rAddr -1, Float.L, Xbus{mBusAddrL} ← uAddr, GOTO[pcBus2], c1;

	rDataOut ← rDataOut LRot12, L3 ← 0F, c3, at[0B, 10, pcBusRet];
pcONNN:	rAddr ← rAddr -1, Float.L, Xbus{mBusAddrL} ← uAddr, GOTO[pcBus2], c1;

	rDataOut ← rDataOut LRot12, L3 ← 3, c3, at[0F, 10, pcBusRet];
pcONNNN: rAddr ← rAddr -1, Float.L, Xbus{mBusAddrL} ← uAddr, GOTO[pcBus2], c1;

	Noop, CALL[pcRead], c3, at[3, 10, pcBusRet], c3;
	

	
{4: Block Input/Write Words}
	rAddr ← rAddr -1,	c3, at[4, 10, pcBlk];
pcInPipeStart:	uAddr ← rAddr, c1;
	Float.L, Xbus{mBusOData} ← uDataOut,	c2;
	Float.L, Xbus{mBusAddrL} ← uAddr, 	c3;
	rAddr ← rAddr -1, Xbus ← FloatResult{mBusIData}, FLFloatA{fZ=2}, Float.L,	c1;
	uAddr ← rAddr, rDataIn ← 0, GOTO[pcBus], c2;
 
pcIW:	TOS ← TOS -1, NZeroBr, c1, at[4, 10, pcWriteRet];
	uAddr ← rAddr, rDataIn ← 0, BRANCH[pcDn, pcBus, 0E], c2;
	
{pcBus:	Xbus ← PPort, XwdDisp{9,10},	c*;
	Q ← rDataIn or FloatResult, L3Disp, BRANCH[$, pcWait, 1],	c*;
	rDataIn ← Q, Float.L, Xbus{mBusOData} ← uDataOut, RET[pcBusRet],	c*;
}
	rDataIn ← rDataIn, CALL[pcWrite], c3, at[4, 10, pcBusRet];
	
pcWrite: MAR ← Rx ← [rhRx, Rx-1],	c1;
pcWrite2: MDR ← rDataIn, Float.L, Xbus{mBusAddrL} ← uAddr, L3Disp, BRANCH[$, pcWcr, 1],	c2;
	rAddr ← rAddr -1, Xbus ← FloatResult{mBusIData}, FLFloatA{fZ=2}, Float.L, RET[pcWriteRet],	c3;
	
	
{5: Block Input/Write Bytes}
	
	rAddr ← rAddr -1, GOTO[pcInPipeStart],	c3, at[5, 10, pcBlk];
{	uAddr ← rAddr, c1;
	Float.L, Xbus{mBusOData} ← uDataOut,	c2;
	Float.L, Xbus{mBusAddrL} ← uAddr, 	c3;
	rAddr ← rAddr -1, Xbus ← FloatResult{mBusIData}, FLFloatA{fZ=2}, Float.L,	c1;
	uAddr ← rAddr, rDataIn ← 0, GOTO[pcBus], c2;}

 {{	Float.L, Xbus{mBusOData} ← uDataOut,	c3, at[5, 10, pcBlk];
	rAddr ← rAddr -1, Xbus ← FloatResult{mBusIData}, FLFloatA{fZ=2}, Float.L,	c1;
	uAddr ← rAddr, rDataIn ← 0, GOTO[pcBus], c2;}}



pcIB:	TOS ← TOS -1, NZeroBr, L3 ← 5, c1, at[0D, 10, pcWriteRet];
	uAddr ← rAddr, rDataIn ← 0, BRANCH[pcDn, pcBus, 0E], c2;
	
	rDataIn ← rDataIn {and 0F}, L3 ← 0D, c3, at[5, 10, pcBusRet];
pcIBB:	rAddr ← rAddr -1, Float.L, Xbus{mBusAddrL} ← uAddr,  c1;
	rDataIn ← rDataIn LRot8,  GOTO[pcBus3], c2;
	
{pcBus3:	uAddr ← rAddr, c3;
	uDataOut ← rDataOut,	c1;
	Xbus ← FloatResult{mBusIData}, FLFloatA{fZ=2}, Float.L,	c2;

	Xbus ← PPort, XwdDisp{9(,10)},	c3;

pcBus1:	Q ← rDataIn or FloatResult, L3Disp, BRANCH[$, pcWait, 1],	c1;
	rDataIn ← Q, Float.L, Xbus{mBusOData} ← uDataOut, RET[pcBusRet],	c2;
}
{no BX debug}	
	rDataIn ← rDataIn LRot8, CALL[pcWrite], c3, at[0D, 10, pcBusRet];

{BX debug  3-Mar-85 16:56:43}
{       Xbus ← rDataIn LRot8, XLDisp, c3, at[0D, 10, pcBusRet];
	Ybus ← rDataIn, NZeroBr, BRANCH[bxE, bxO, 2], c1;
bxE:	Noop, BRANCH[bxZ, bxNZ], c2;
bxO:	Noop, BRANCH[bxZ, bxNZ], c2;
bxZ:	CALL[pcWrite], c3;
bxNZ:	CALL[pcWrite], c3;
}

{6: Block Input/Write Bytes Reversed}
	
	rAddr ← rAddr -1, GOTO[pcInPipeStart],	c3, at[6, 10, pcBlk];
{	uAddr ← rAddr, c1;
	Float.L, Xbus{mBusOData} ← uDataOut,	c2;
	Float.L, Xbus{mBusAddrL} ← uAddr, 	c3;
	rAddr ← rAddr -1, Xbus ← FloatResult{mBusIData}, FLFloatA{fZ=2}, Float.L,	c1;
	uAddr ← rAddr, rDataIn ← 0, GOTO[pcBus], c2;

	Float.L, Xbus{mBusOData} ← uDataOut,	c3, at[6, 10, pcBlk];
	rAddr ← rAddr -1, Xbus ← FloatResult{mBusIData}, FLFloatA{fZ=2}, Float.L,	c1;
	uAddr ← rAddr, rDataIn ← 0, GOTO[pcBus], c2;
}


pcIBr:	TOS ← TOS -1, NZeroBr, L3 ← 6, c1, at[0E, 10, pcWriteRet];
	uAddr ← rAddr, rDataIn ← 0, BRANCH[pcDn, pcBus, 0E], c2;
	
	rDataIn ← rDataIn {and 0F}, L3 ← 0E, c3, at[6, 10, pcBusRet];
pcIBBr:	rAddr ← rAddr -1, Float.L, Xbus{mBusAddrL} ← uAddr,  c1;
	rDataIn ← rDataIn LRot8,  GOTO[pcBus3], c2;
	
{pcBus3:	uAddr ← rAddr, c3;
	uDataOut ← rDataOut,	c1;
	Xbus ← FloatResult{mBusIData}, FLFloatA{fZ=2}, Float.L,	c2;

	Xbus ← PPort, XwdDisp{9(,10)},	c3;

pcBus1:	Q ← rDataIn or FloatResult, L3Disp, BRANCH[$, pcWait, 1],	c1;
	rDataIn ← Q, Float.L, Xbus{mBusOData} ← uDataOut, RET[pcBusRet],	c2;
}	
	rDataIn ← rDataIn LRot0, CALL[pcWrite], c3, at[0E, 10, pcBusRet];

{Exceptions}

{Remap to Virt+TOS-1}{don't fault if TOS=0}	
pcWcr:	Noop, CANCELBR[pcCr, 0F],	c3;
pcRcr:	rAddr ← rAddr +1, CANCELBR[pcCr, 0F],	c3;
pcCr:	TOS ← TOS -1, CarryBr,	c1;
	TT ← uVirtL, BRANCH[pcCz, pcCnz],	c2;
pcCz:	rhTT ← uVirtH, GOTO[pcMp],	c3;
pcCnz:	TT ← TT + TOS, CarryBr,	rhTT ← uVirtH, GOTO[pcMp],	c3;
	
pcInc:	Q ← rhTT+1, 	LOOPHOLE[byteTiming], c2;
	rhTT ← Q LRot0,	c3;

pcMp:	Map ← Q ← [rhTT, TT], BRANCH[pcMp2, pcInc],	c1;
pcMp2:	TOS ← TOS + 1,	c2;
	Rx ← rhRx ← MD, XwdDisp,	c3;
	
	Map ← Q ← [rhTT, TT], BRANCH[$, pcFault, 1],	c1;
	MDR ← Rx or 30,	c2;
	L3Disp,		c3;

pcMpD:	MAR ← Rx ← [rhRx, TT+0], BRANCH[pcRead2, pcWrite2, 0B],	c1;
pcRead2: rAddr ← rAddr -1, Float.L, Xbus{mBusAddrL} ← uAddr, L3Disp, GOTO[pcRead3],	c2;
	
{% fix ups}
pcFault: TOSH ← smallpl,	c2;
	Q ← uPPsave,	c3;
	PPort ← Q,	c1;
	PV ← uPV, GOTO[RWTrap], c2;

pcDn2:	, CANCELBR[$, 2],	c2;
pcDn:	, {L2Disp,}	c3;

pcDn1:	TOSH ← smallpl, L2Disp, CANCELBR[$, 3], {BRANCH[$, pcRep],}	c1;
	PV ← uPV, BRANCH[$, pcRep],	c2;
pcAlmost:
	Rx ← uPPsave,	c3;
	
pcEnd:
	PPort ← Rx, L2 ← L2.0,	c1;
	S ← S - 6, IBDisp, c2;
	PC ← PC + 1,  L2 ← L2.0, DISPNI[OpTable],	c3;


{pcRep:	, c2;}
pcRep:	TOS ← uTOS, GOTO[pcA1],	c3;
	


	
		
BusX:	FloatNop{free BX in 2 BX cycles},	c2, at[09,10,MiscIn];{read L}
	TOS ← TOS LRot12, {FloatUMS,}		c3;
	Ybus ← TOS, AltUaddr,			c1;
	FloatULP, TOS ← FloatResult,	c2;
pcInDn:	TOS ← FloatResult, 	c3;

	GOTO[IB.nop],	c1;

	FloatNop{free BX in 2 BX cycles},	c2, at[0A,10,MiscIn];{read M}
	TOS ← TOS LRot12, {FloatUMS,}	c3;
	Ybus ← TOS, AltUaddr,			c1;
	FloatUMP, TOS ← FloatResult, GOTO[pcInDn],	c2;


	{TT ← MD,}				c3, at[0,10,MiscOut];{Write L}	
{%L	FloatNop{free BX in 2 BX cycles},	c1;
	TOS ← TOS LRot12, FloatUMS,		c2;
	rhRx ← nRhS, Rx ← S + 2,						c3;
%L}
	FloatNop{free BX in 2 BX cycles}, Rx ← S - 0 - 1,	c1;
	TOS ← TOS LRot12, FloatUMS,		c2;
	rhRx ← nRhS, Rx ← Rx + 3,						c3;
	
	
	MAR ← Rx ← [rhRx, Rx + 0],						c1;
	Ybus ← TOS, AltUaddr, L2 ← L2.0, IBDisp,			c2;
	FloatULP, Xbus ← MD { ← FloatResult}, L2 ← L2.0, DISPNI[OpTable],	c3;

	{TT ← MD,}				c3, at[0B,10,MiscOut];{Write M}	
{%L	FloatNop{free BX in 2 BX cycles},	c1;
	TOS ← TOS LRot12, FloatUMS,		c2;
	rhRx ← nRhS, Rx ← S + 2,						c3;
%L}
	FloatNop{free BX in 2 BX cycles}, Rx ← S - 0 - 1,	c1;
	TOS ← TOS LRot12, FloatUMS,		c2;
	rhRx ← nRhS, Rx ← Rx + 3,						c3;
	
	MAR ← Rx ← [rhRx, Rx + 0],						c1;
	Ybus ← TOS, AltUaddr, L2 ← L2.0, IBDisp,			c2;
	FloatUMP, Xbus ← MD, L2 ← L2.0, DISPNI[OpTable],	c3;

	{ E N D }