{
File name CommonSubs.mc

Fiala 16-May-86 10:51:08 Changes for 4 MB storage.
Frandeen August 20, 1981  2:20 PM: Fix for new assembler. 
Johnsson, January 20, 1981  10:22 AM
Charnley, October 8, 1980  9:23 AM
Garner, April 11, 1980  4:52 PM
Description: Emulator Subroutines
Author: don charnley
Created: March 28, 1980
}

{	codes used for L0
	indicate where to return from fixing the map flags
	return is relative to RMapFixCaller
}
{	codes used for L1
	indicate how to reset state if page fault encountered
	return is relative to RFixForTrap
}
{	codes used for L1
	indicate return from CycleMask
}
{	codes used for L2
	indicate where to return from remapping a Local or Global
	return is relative to LGRemapCaller
}
{	codes used for L3
	indicate where virtual address is
}


{
	Read Map Update Subroutines
}
{Timing: 4 cycles}
{Enter at cycle 3, returns to cycle1}
{returns thru L0 if map fixed ok}
{returns thru L1 if wants to trap}
{uses L3 to distinguish where virtual address is}

RLMapFix:
	Xbus ← Rx LRot0,XwdDisp, L3 ← L3.rhTT.Q	,c3;
RLMapFixx:
	Map ← [rhTT,Q], DISP2[RFixRFlags]	,c1;

RMapFix:
	Xbus ← Rx LRot0,XwdDisp, L3 ← L3.rhMDS.Q	,c3;
	Map ← [rhMDS,Q], DISP2[RFixRFlags]	,c1;

RFixRFlags:
	MDR ← Rx or 10, L0Disp, GOTO[ReRead]	,c2, at[0,4];
	MDR ← Rx or 10, L0Disp, GOTO[ReRead]	,c2, at[1,4,RFixRFlags];
	MDR ← Rx or 10, L0Disp, GOTO[ReRead],	,c2, at[2,4,RFixRFlags];
IBEmptyTrap:
	T ← qPageFault, L1Disp, GOTO[RTrap]	,c2, at[3,4,RFixRFlags];

ReRead:	Xbus ← 1, XDisp, RET[RMapFixCaller]	,c3;

RTrap:	push, RET[RFixForTrap]	,c3;

{
	Local and Global Remap Subroutines
}
{Timing: 9 cycles (3 clicks), + 2 clicks if flags need fixing }
{Enter at cycle 1, returns to cycle1}
{returns thru L2 if all ok, thru LGRemapCaller}
{returns thru L1 {from RLMapFix} if wants to trap, thru FixForTrap}
{assumes caller executed "TT ← UvL/UvG"}

{ USES TT, Rx, rhRx, rhMDS, and Q}

LGRemap:	TT ← TT + 0FF + 1	,c1;
	Noop	,c2;
	Noop	,c3;

	Map ← [rhMDS,TT]	,c1;
	Noop	,c2;
	Rx ← rhRx ← MD, XRefBr	,c3;

LGRefetch:	MAR ← [rhRx,Q + 0], BRANCH[LGMapUD,$]	,c1;
	L2Disp	,c2;
	rhTT ← TT ← MD, RET[LGRemapCaller]	,c3;

LGMapUD:	Noop {code duplicated to protect L0}	,c2;
	Xbus ← Rx LRot0,XwdDisp, L3 ← L3.rhMDS.TT	,c3;
	Map ← [rhMDS,TT], DISP2[LGFixRFlags]	,c1;

LGFixRFlags:	MDR ← Rx or 10, GOTO[LGReRead]	,c2, at[0,4];
	MDR ← Rx or 10, GOTO[LGReRead]	,c2, at[1,4,LGFixRFlags];
	MDR ← Rx or 10, GOTO[LGReRead],	,c2, at[2,4,LGFixRFlags];
	T ← qPageFault, L1Disp, GOTO[RTrap]	,c2, at[3,4,LGFixRFlags];

LGReRead:	Xbus ← 1, XDisp, GOTO[LGRefetch]	,c3;

{
	Write Map Update Subroutines
}
{Timing: 4 cycles}
{Enter at cycle 3, returns to cycle1}
{returns thru L0 if map fixed ok}
{returns thru L1 if wants to trap}

WLMapFix:
	Xbus ← Rx LRot0, XwdDisp, L3 ← L3.rhTT.Q,	c3;
	Map ← [rhTT, Q], DISP2[FixWFlags],		c1;

WMapFix:
	Xbus ← Rx LRot0, XwdDisp, L3 ← L3.rhMDS.Q,	c3;
	Map ← [rhMDS, Q], DISP2[FixWFlags],		c1;

FixWFlags:
	MDR ← Rx or 30, L0Disp, GOTO[ReWrite],		c2, at[0,4];
	MDR ← Rx or 30, L0Disp, GOTO[ReWrite],		c2, at[1,4,FixWFlags];
	T ← qWriteProtect, L1Disp, GOTO[WTrap],		c2, at[2,4,FixWFlags];
	T ← qPageFault, L1Disp, GOTO[WTrap],		c2, at[3,4,FixWFlags];

ReWrite:
	Xbus ← 1, XDisp, RET[WMapFixCaller],		c3;

WTrap:	push, RET[WFixForTrap],				c3;


{
	Read Map Update Subroutines
}
{Timing: 4 cycles}
{Enter at cycle 3, returns to cycle1}
{returns thru L0 if map fixed ok}
{returns thru L1 if wants to trap}
{uses L3 to distinguish where virtual address is}
{LGxMapFix must be at[1,2].  See EMapUD in Refill.mc}

RLxMapFix:	Xbus ← Rx LRot0, XwdDisp, L3 ← L3.rhTT.Q	,c3;
	Map ← [rhTT, Q], DISP2[RxFixRFlags]	,c1;

RxMapFix:	Xbus ← Rx LRot0, XwdDisp, L3 ← L3.rhMDS.Q	,c3;
	Map ← [rhMDS,Q], DISP2[RxFixRFlags]	,c1;

LGxMapFix:	Xbus ← Rx LRot0, XwdDisp, L3 ← L3.rhTT.TT	,c3, at[1,2];
	Map ← [rhTT,TT], DISP2[RxFixRFlags]	,c1;

RxFixRFlags:	MDR ← Rx or 10, L0Disp, GOTO[RexRead]	,c2, at[0,4];
	MDR ← Rx or 10, L0Disp, GOTO[RexRead]	,c2, at[1,4,RxFixRFlags];
	MDR ← Rx or 10, L0Disp, GOTO[RexRead],	,c2, at[2,4,RxFixRFlags];
	T ← qPageFault, L1Disp, GOTO[RTrap]	,c2, at[3,4,RxFixRFlags];

RexRead:	Xbus ← 1, XDisp, RET[RxMapFixCaller]	,c3;

{
	Write Map Update Subroutines
}
{Timing: 4 cycles}
{Enter at cycle 3, returns to cycle1}
{returns thru L0 if map fixed ok}
{returns thru L1 if wants to trap}

WLxMapFix:
	Xbus ← Rx LRot0, XwdDisp, L3 ← L3.rhTT.Q,	c3;
	Map ← [rhTT, Q], DISP2[FixWxFlags],		c1;

WxMapFix:
	Xbus ← Rx LRot0, XwdDisp, L3 ← L3.rhMDS.Q,	c3;
	Map ← [rhMDS, Q], DISP2[FixWxFlags],		c1;

FixWxFlags:
	MDR ← Rx or 30, L0Disp, GOTO[RexWrite],		c2, at[0,4];
	MDR ← Rx or 30, L0Disp, GOTO[RexWrite],		c2, at[1,4,FixWxFlags];
	T ← qWriteProtect, L1Disp, GOTO[WTrap],		c2, at[2,4,FixWxFlags];
	T ← qPageFault, L1Disp, GOTO[WTrap],		c2, at[3,4,FixWxFlags];

RexWrite:
	Xbus ← 1, XDisp, RET[WxMapFixCaller],		c3;


{
	Read Map Update Subroutines
}
{Timing: 4 cycles}
{Enter at cycle 3, returns to cycle1}
{returns thru L0 if map fixed ok}
{returns thru L1 if wants to trap}
{uses L3 to distinguish where virtual address is}
RLyMapFix:	Xbus ← Rx LRot0, XwdDisp, L3 ← L3.rhTT.Q	,c3;
	Map ← [rhTT, Q], DISP2[RyFixRFlags]	,c1;

RyMapFix:	Xbus ← Rx LRot0, XwdDisp, L3 ← L3.rhMDS.Q	,c3;
	Map ← [rhMDS,Q], DISP2[RyFixRFlags]	,c1;

RyFixRFlags:	MDR ← Rx or 10, L0Disp, GOTO[ReyRead]	,c2, at[0,4];
	MDR ← Rx or 10, L0Disp, GOTO[ReyRead]	,c2, at[1,4,RyFixRFlags];
	MDR ← Rx or 10, L0Disp, GOTO[ReyRead],	,c2, at[2,4,RyFixRFlags];
	T ← qPageFault, L1Disp, GOTO[RTrap]	,c2, at[3,4,RyFixRFlags];

ReyRead:	Xbus ← 1, XDisp, RET[RyMap]	,c3;

{
	Write Map Update Subroutines
}
{Timing: 4 cycles}
{Enter at cycle 3, returns to cycle1}
{returns thru L0 if map fixed ok}
{returns thru L1 if wants to trap}

WyMapFix:
	Xbus ← Rx LRot0, XwdDisp, L3 ← L3.rhMDS.Q,	c3;
	Map ← [rhMDS, Q], DISP2[FixWyFlags],		c1;

FixWyFlags:
	MDR ← Rx or 30, L0Disp, GOTO[ReyWrite],		c2, at[0,4];
	MDR ← Rx or 30, L0Disp, GOTO[ReyWrite],		c2, at[1,4,FixWyFlags];
	T ← qWriteProtect, L1Disp, GOTO[WTrap],		c2, at[2,4,FixWyFlags];
	T ← qPageFault, L1Disp, GOTO[WTrap],		c2, at[3,4,FixWyFlags];

ReyWrite:
	Xbus ← 1, XDisp, RET[WyMap],			c3;


{
	RFixForTrap
}
NoFixes:	Noop, GOTO[NoMoreFix]	,c1, at[L1r.NoFixes,10,RFixForTrap];
	PC ← PC - PC16, GOTO[NoMoreFix]	,c1, at[L1r.DecOnly,10,RFixForTrap];
PopOnlyFix:	pop, GOTO[NoMoreFix]	,c1, at[L1r.PopOnly,10,RFixForTrap];
	push, GOTO[PushFix]	,c1, at[L1r.Push2Only,10,RFixForTrap];
	PC ← PC - PC16, push, GOTO[NoMoreFix]	,c1, at[L1r.PushDec,10,RFixForTrap];
	push, GOTO[NoMoreFix]	,c1, at[L1r.PushOnly,10,RFixForTrap];
	PC ← PC - 1, push, GOTO[NoMoreFix]	,c1, at[L1r.PushDecDec,10,RFixForTrap];
	PC ← PC - 1, pop, GOTO[NoMoreFix]	,c1, at[L1r.PopDecDec,10,RFixForTrap];
	PC ← PC - PC16, pop, GOTO[NoMoreFix]	,c1, at[L1r.PopDec,10,RFixForTrap];
	PC ← PC - 1, push, GOTO[PushFix]	,c1, at[L1r.Push2DecDec,10,RFixForTrap];
	PC ← PC - 1, pop, GOTO[PopFix]	,c1, at[L1r.Pop2DecDec,10,RFixForTrap];
	PC ← PC - 1, GOTO[NoMoreFix]	,c1, at[L1r.DecDec,10,RFixForTrap];


{
	WFixForTrap fixups
}
	Noop, GOTO[NoMoreFix]	,c1, at[L1w.NoFixes,10,WFixForTrap];
	PC ← PC - PC16, GOTO[NoMoreFix]	,c1, at[L1w.DecOnly,10,WFixForTrap];
	push, GOTO[PushFix]	,c1, at[L1w.Push2Only,10,WFixForTrap];
	PC ← PC - PC16, push, GOTO[PushFix]	,c1, at[L1w.Push2Dec,10,WFixForTrap];
	PC ← PC - PC16, push, GOTO[NoMoreFix]	,c1, at[L1w.PushDec,10,WFixForTrap];
	push, GOTO[NoMoreFix]	,c1, at[L1w.PushOnly,10,WFixForTrap];
	push, GOTO[Push3Fix]	,c1, at[L1w.Push3Only,10,WFixForTrap];
	PC ← PC - 1, GOTO[NoMoreFix]	,c1, at[L1w.DecDec,10,WFixForTrap];
	PC ← PC - 1, push, GOTO[NoMoreFix]	,c1, at[L1w.PushDecDec,10,WFixForTrap];
	PC ← PC - PC16, pop, GOTO[NoMoreFix]	,c1, at[L1w.PopDec,10,WFixForTrap];
	PC ← PC - 1, push, GOTO[PushFix]	,c1, at[L1w.Push2DecDec,10,WFixForTrap];
	pop, GOTO[NoMoreFix]	,c1, at[L1w.PopOnly,10,WFixForTrap];


{
	Trap Handling
}

NoMoreFix:	L3Disp, GOTO[TrapFixDone]	,c2;
PushFix:	push, L3Disp, GOTO[TrapFixDone]	,c2;
PopFix:	pop, L3Disp, GOTO[TrapFixDone]	,c2;
Push3Fix:	push, L3Disp, GOTO[TrapFixPush3]	,c2;

TrapFixDone:	DISP3[FormVA]	,c3;
TrapFixPush3:	push, DISP3[FormVA]	,c3;

FormVA:	uFaultParm0 ← Q, GOTO[VArhTT]	,c1, at[L3.rhTT.Q,8,FormVA];
	uFaultParm0 ← TT, GOTO[VArhTT]	,c1, at[L3.rhTT.TT,8,FormVA];
	uFaultParm0 ← Q, GOTO[VAMDS]	,c1, at[L3.rhMDS.Q,8,FormVA];

VAMDS:	Q ← rhMDS, GOTO[Faultc3]	,c2;
VArhTT:	Q ← rhTT, GOTO[Faultc3]	,c2;

{At Faultc3, uFaultParm0 stored, Q has uFaultPram1, T has FaultQueuePointer}
Faultc3:	uFaultParm1 ← Q	,c3;
Faultc1:	Rx ← pFault, STK ← TOS, pop, GOTO[SaveRegs]	,c1;

{At Trapc1, TT holds the trap parmater, T has the sSDIndex}
Trapc3:	GOTO[Trapc1]	,c3;
Trapc1:	UTrapParm ← TT, L2 ← L2.TRAPStashr	,c1;
Trapc2:	TT ← UvPCpage, L1←0, GOTO[StashPC0] {in Xfer.mc}	,c2;

{
	CycleMask
}
{Timing:	1 click}
{Used by: SHIFT, RF, WF, BITBLT instructions}
{Entry:	T = data to be rotated & masked,
	TT = pre-rotated version of T
	a DISP4 pending which determines rotation:
		0 => no rotation
		1 => left rotate 1
		     :
		0F => left rotate 15;
	a INIA.11 branch is pending to determine if shift should be abandoned.
	rhT = value to be dispatched on to determine mask
		0 => 1
		1 => 3
	       :
		0F => 0FFFF
Exit:	TT holds the mask,
	TOS holds the rotated data,
	T does not contain the original data,  rhT is untouched}


CycleMask:	[] ← rhT, XDisp, BRANCH[ShiftOut0, ShiftOK0],	c*, at[0,10,CycleMask];
	T ← TT, [] ← rhT, XDisp, BRANCH[ShiftOut0, ShiftOK0],	c*, at[1,10,CycleMask];
	T ← LRot1 TT, [] ← rhT, XDisp, BRANCH[ShiftOut0, ShiftOK0],	c*, at[2,10,CycleMask];
	T ← RRot1 T, [] ← rhT, XDisp, BRANCH[ShiftOut4, ShiftOK4],	c*, at[3,10,CycleMask];

	[] ← rhT, XDisp, BRANCH[ShiftOut4, ShiftOK4],	c*, at[4,10,CycleMask];
	T ← LRot1 T, [] ← rhT, XDisp, BRANCH[ShiftOut4, ShiftOK4],	c*, at[5,10,CycleMask];
	T ← LRot1 TT, [] ← rhT, XDisp, BRANCH[ShiftOut4, ShiftOK4],	c*, at[6,10,CycleMask];
	T ← RRot1 T, [] ← rhT, XDisp, BRANCH[ShiftOut8, ShiftOK8],	c*, at[7,10,CycleMask];

	[] ← rhT, XDisp, BRANCH[ShiftOut8, ShiftOK8],	c*, at[8,10,CycleMask];
	T ← LRot1 T, [] ← rhT, XDisp, BRANCH[ShiftOut8, ShiftOK8],	c*, at[9,10,CycleMask];
	T ← LRot1 TT, [] ← rhT, XDisp, BRANCH[ShiftOut8, ShiftOK8],	c*, at[0A,10,CycleMask];
	T ← RRot1 T, [] ← rhT, XDisp, BRANCH[ShiftOut12, ShiftOK12],	c*, at[0B,10,CycleMask];

	[] ← rhT, XDisp, BRANCH[ShiftOut12, ShiftOK12],	c*, at[0C,10,CycleMask];
	T ← LRot1 T, [] ← rhT, XDisp, BRANCH[ShiftOut12, ShiftOK12],	c*, at[0D,10,CycleMask];
	T ← LRot1 TT, [] ← rhT, XDisp, BRANCH[ShiftOut12, ShiftOK12],	c*, at[0E,10,CycleMask];
	T ← RRot1 T, [] ← rhT, XDisp, BRANCH[ShiftOut0, ShiftOK0],	c*, at[0F,10,CycleMask];

ShiftOK0:	TOS ← T, pRet2, DISP4[MaskTbl],	c*;
ShiftOK4:	TOS ← T LRot4, pRet2, DISP4[MaskTbl],	c*;
ShiftOK8:	TOS ← T LRot8, pRet2, DISP4[MaskTbl],	c*;
ShiftOK12:	TOS ← T LRot12, pRet2, DISP4[MaskTbl],	c*;

{Here if no pending branch on entry to CycleMask (magnitude of
shift count greater than 15).  stackP has already been
decremented--check for underflow at NegIB.}
ShiftOut0:	CANCELBR[ShiftOut, 0F],	c3;
ShiftOut4:	CANCELBR[ShiftOut, 0F],	c3;
ShiftOut8:	CANCELBR[ShiftOut, 0F],	c3;
ShiftOut12:	CANCELBR[ShiftOut, 0F],	c3;

ShiftOut:	TOS ← 0, GOTO[NegIB],	c1;

{
	MaskTbl  SUBROUTINE
	first cycle = c* , one cycle long
This subroutine generates a right justified mask. of n ones given n
(n = 1 gives 1, n = 8 gives 00FF and n = 16 gives FFFF). The subroutine
may also be used to generate a left justified mask.
	REGISTERS
Rn	number of 1 bits desired in mask (0 means 16)
mask	where the mask is generated
	CALLING SEQUENCES
For a right justified mask
	[] ← Rn - 1, YDisp	,c1;
	[] ← retnum, XDisp, DISP4[MaskTbl]	,c2;

{rtn here}	Noop	,c1, at[retnum,10,MaskRet];

For a left justified mask
	[] ← 0 - Rn, YDisp	,c2;
	[] ← retnum, XDisp, DISP4[MaskTbl]	,c3;

{rtn here}	mask ← RShift1 ~mask, SE ← 1	,c2, at[retnum,10,MaskRet];

	RETURNS THRU
MaskRet
}

MaskTbl:	TT ← 1, RET[MaskRet],	c*, at[0,10,MaskTbl];
	TT ← 3, RET[MaskRet],	c*, at[1,10,MaskTbl];
	TT ← 7, RET[MaskRet],	c*, at[2,10,MaskTbl];
	TT ← 0F, RET[MaskRet],	c*, at[3,10,MaskTbl];
	TT ← 1F, RET[MaskRet],	c*, at[4,10,MaskTbl];
	TT ← 3F, RET[MaskRet],	c*, at[5,10,MaskTbl];
	TT ← 7F, RET[MaskRet],	c*, at[6,10,MaskTbl];
	TT ← 0FF, RET[MaskRet],	c*, at[7,10,MaskTbl];
	TT ← LShift1 0FF, SE←1, RET[MaskRet] {TT ← 1FF},	c*, at[8,10,MaskTbl];
	TT ← RShift1 u7FF, RET[MaskRet] {TT ← 3FF},	c*, at[9,10,MaskTbl];
	TT ← u7FF, RET[MaskRet] {TT ← 7FF},	c*, at[0A,10,MaskTbl];
	TT ← RShift1 u1FFF, RET[MaskRet] {TT ← FFF},	c*, at[0B,10,MaskTbl];
	TT ← u1FFF, RET[MaskRet] {TT ← 1FFF},	c*, at[0C,10,MaskTbl];
	TT ← u3FFF, RET[MaskRet] {TT ← 3FFF},	c*, at[0D,10,MaskTbl];
	TT ← RShift1 (~TT xor TT), RET[MaskRet] {TT ← 7FFF},	c*, at[0E,10,MaskTbl];
	TT ← ~TT xor TT, RET[MaskRet] {TT ← FFFF},	c*, at[0F,10,MaskTbl];