{File name <tajo>TMyBusExt.mc
Description: DandeLion Interlisp Emulator Bus Extension
Author: Purcell
Created: 31-May-84 16:45:34
}

{	purcell  3-Jun-85 23:03:10 add long delays in bus}


{	by don 24-Mar-85 11:40:24
	deleted spurious output at tail of input/writes
	added extra arg for BusCtl command
	added u for mBusAddrM {fZ = 3}
	added u for orig alpha
	changed stack reads to STK
	saved L {instead of PV}
	fixed page fault exits
	fixed normal exits
	reallocated u regs
	changed loading of rhTT from uVirtH
}
{INPUT:	TOSH ← smallpl, DISP4[MiscIn],	c1, at[0D,10, MiscDisp];}

{
(\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
}

{L}		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[uPPsave, U, 0CE];{unused u reg}
RegDef[uxx3, U, 43];{fZ=3}
RegDef[uAlpha, U, 4B];{any temp}
RegDef[uVirtL, U, 27];{TT}
RegDef[uVirtH, U, 4A];{any temp}
RegDef[uBusCtl, U, 52];{fZ=2}
RegDef[uAddr, U, 33];{rAddr}{fZ=3}
RegDef[uDataOut, U, 42];{fZ=2}
{RegDef[UrL,	U,	3B];	{rA = L, fZ = ←RH}}


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

{
	orig alpha: == operation
	0	read/output word
	1	read/output bytes
	2	read/output bytes reversed
	3	read/output nibbles
	4	input/write word
	5	input/write bytes
	6	input/write bytes reversed

	TOS		count{16 bits}
	STK-0	bus control word
	STK-1	low base address out{16 bits}
	STK-2	mBusAddrM{16 bits}
	STK-3	virt addr of buffer{24 bits}
	STK-5	operation{3 bits}

	Regs:
	L	saved into UrL
	TOS	remaining count
	T	temp
	Rx	temp
	TT	temp
	UrL ← L
	uPPsave	last write to PP
	uVirtL	buffer addr lo
	uAddr	Bus addr
	uBusCtl	Control to Bus
	uDataOut	data out
}

{	in new version of Misc.mc
@ESC:	Xbus ← ibHigh, XDisp,				c1, opcode[370'b];
ESCx:	TT ← ib, XDisp, push, DISP4[ESCHi],			c2;
	PC ← PC + 1, STK ← TOS, pop, DISP4[ESC8n],	c3, at[8,10,ESCHi];
}

{	this replaces  @BANDBLT }
PCBKW:	at[3,10,ESC8n],

	FloatNop,	L1 ← L1.None,		c1;
	UrL ← L, L2 ← 0,		c2;
	Rx ← 0FF + 1,	c3;

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

	{seventh arg in TOS}
	Rx ← STK, pop,	c1;{sixth arg}
	uBusCtl ← Rx,	c2;
	,	c3;

	rAddr ← STK, pop,	c1;{fifth arg}
	Rx ← STK, pop,	c2;{fourth arg}
	uxx3 ← Rx,	c3;

	Rx ← STK, pop,	c1;{third arg}
	uVirtH ← Rx,	c2;
	Rx ← STK, pop,	c3;{second arg}

	uVirtL ← Rx,	c1;
	Rx ← STK, pop,	c2;{first arg}
	uAlpha ← Rx,	c3;

	Rx{2*TOS} ← TOS LShift1,	c1;
	FLTimes.WA.WB{% fZ=3}, Float.M, Xbus{mBusAddrM} ← uxx3,	c2;
	,	c3;

{TT=rDataOut=virtL}	
pcA4:
	Xbus ← uAlpha, 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:
	rAddr ← rAddr -1,	c1;
	uAddr ← rAddr, Rx ← 0{force remap}, 		c2;
	Xbus ← uAlpha, XDisp,	c3;
	
pcBCtl:	Float.L, Xbus{mBusAddrL} ← uAddr, BRANCH[pcBOut, pcBIn, 0B],	c1;
pcBIn:	{T{TOSH} ← T{TOSH} or 1, }GOTO[pcCtlj],	c2; {set mBusCtl for reads}
pcBOut:	{T{TOSH} ← T{TOSH} or 2, }GOTO[pcCtlj],	c2; {set mBusCtl for writes}
pcCtlj: {uBusCtl ← T{TOSH}},		c3;

	Xbus ← uAlpha, XDisp,	c1;
	Float.M, Xbus{mBusCtl} ← uBusCtl, L3 ← 0, {L3 ← alpha} 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;
{%P  3-Jun-85 23:02:25}
	
{	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;}

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

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

pcBus3CH:	uAddr ← rAddr,	c3;
	uDataOut ← rDataOut,	c1;{% good for 5; ok others ?}
	Xbus ← FloatResult{mBusIData}, FLFloatA{fZ=2}, Float.L,	c2;
{%P  3-Jun-85 23:02:25}
pcBusCH:	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;}

pcBus1CH:	Ybus ← TOS - 1, ZeroBr, CANCELBR[$, 3],	c1;
	BRANCH[$, pcskipit],	c2;
	Ybus ← rDataIn, Xbus ← PPort, XwdDisp{9(,10)},	c3;

	Q ← rDataIn or FloatResult, L3Disp, BRANCH[$, pcWaitCH, 1],	c1;
	rDataIn ← Q, Float.L, Xbus{mBusOData} ← uDataOut, {RET[pcBusRet{%T}],} BRANCH[pcBRo, pcBRi, 0B],	c2;
	
pcBRo:	Ybus ← 2, YDisp, L3Disp, GOTO[pcBR]	c3;
pcBRi:	Ybus ← rDataIn and 2, YDisp, L3Disp, GOTO[pcBR]	c3;
pcBR:	L3Disp, BRANCH[zBit1, $, 0D],	c1;
	Noop, RET[pcBusRet],	c2;
zBit1:	Xbus ← TIData,{%T} RET[pcBusRet],	c2;

pcWaitCH: Xbus ← FloatResult{mBusIData}, FLFloatA{fZ=2}, Float.L, CANCELBR[pcBusCH, 0F],	c2;

pcskipit:
	Ybus ← rDataIn, Xbus ← PPort, XwdDisp{9(,10)},	c3;

	Q ← rDataIn or FloatResult, L3Disp, BRANCH[$, pcWaitCHs, 1],	c1;
	rDataIn ← Q, FloatNop{turn off mBusIData}, {RET[pcBusRet{%T}],} BRANCH[pcBRo, pcBRi, 0B],	c2;
pcWaitCHs: Xbus ← FloatResult{mBusIData}, FLFloatA{fZ=2}, Float.L, CANCELBR[pcBusCH, 0F],	c2;



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

pcOW:	TOS ← TOS -1, CarryBr, c1, at[0, 10, pcReadRet];
	uDataOut ← rDataOut, BRANCH[pcDn, pcBus, 0E], c2;

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



{1: Block Read/Output Bytes}
	CALL[pcRead],	c3, at[1, 10, pcBlk];
	
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];
	
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];
	
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;
	
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;
 

	
{4: Block Input/Write Words}
	rAddr ← rAddr -1,	c3, at[4, 10, pcBlk];
pcInPipeStartCH:	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[pcBusCH], c2;
 
pcIW:	TOS ← TOS -1, NZeroBr, c1, at[4, 10, pcWriteRet];
	uAddr ← rAddr, rDataIn ← 0, BRANCH[pcDnCH, pcBusCH, 0E], c2;
	
	rDataIn ← rDataIn, CALL[pcWrite], c3, at[4, 10, pcBusRet];
	
pcWrite:
{% T test bit 1}
	Ybus ← rDataIn, YDisp, c1;
	BRANCH[zeroBit1, $, 0D], c2;
	Noop, GOTO[pcWrite1],	c3;
zeroBit1:	Xbus ← TStatus, GOTO[pcWrite1],	c3;

pcWrite1: 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];

	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[pcBus3CH], c2;

	rDataIn ← rDataIn LRot8, CALL[pcWrite], c3, at[0D, 10, pcBusRet];


pcIB:	TOS ← TOS -1, NZeroBr, L3 ← 5, c1, at[0D, 10, pcWriteRet];
	uAddr ← rAddr, rDataIn ← 0, BRANCH[pcDn, pcBus, 0E], c2;
	
	

{6: Block Input/Write Bytes Reversed}
	
	rAddr ← rAddr -1, GOTO[pcInPipeStart],	c3, at[6, 10, pcBlk];

	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[pcBus3CH], c2;
	
	rDataIn ← rDataIn LRot0, CALL[pcWrite], c3, at[0E, 10, pcBusRet];

pcIBr:	TOS ← TOS -1, NZeroBr, L3 ← 6, c1, at[0E, 10, pcWriteRet];
	uAddr ← rAddr, rDataIn ← 0, BRANCH[pcDn, pcBus, 0E], c2;
	
	{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,	c3;
	
	rhTT ← uVirtH, BRANCH[pcnoInc, pcInc],	c1;

pcnoInc:
	,	c2;
	GOTO[pcMp],	c3;

pcInc:
	Q ← rhTT+1, 	LOOPHOLE[byteTiming], c2;
	rhTT ← Q LRot0, GOTO[pcMp],	c3;

pcMp:
	Map ← Q ← [rhTT, TT],	c1;
	TOS ← TOS + 1,	c2;
	Rx ← rhRx ← MD, XwdDisp,	c3;
	
	Map ← Q ← [rhTT, TT], DISP2[pcFault],	c1;
	MDR ← Rx or 0B0, GOTO[beWMapb],	c2, at[0,4,pcFault];
	MDR ← Rx or 0B0, GOTO[beWMapb],	c2, at[1,4,pcFault];
beWMapb:
	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:
	T ← qWriteProtect, GOTO[beWMapX],	c2, at[2,4,pcFault];
	T ← qPageFault, GOTO[beWMapX],	c2, at[3,4,pcFault];
beWMapX:
	{push stack back = 6 push's}
	Q ← uPPsave, push,	c3;
	PPort ← Q, push,	c1;
	L ← UrL, push, c2;
	PC ← PC - 1, push,	c3;
	push,	c1;
	L1Disp, push, GOTO[WTrap],	c2;

	{exits}
pcDnCH:	GOTO[pcDn1],	c3;

pcDn2:	, CANCELBR[$, 2],	c2;

pcDn:	,	c3;

pcDn1:	
	L ← UrL, CANCELBR[$, 3],	c1;
	Rx ← uPPsave, IBDisp, c2;
	PPort ← Rx, DISPNI[OpTable],	c3;


	{ E N D }