{
File name CommonSubs.mc
Description: Emulator Subroutines
Author: DXC     
Created: March 28, 1980
Last edited: 
AHL/JPM	 5-Jan-87  9:01:08  Change LGMap for MDS relief
KXI	14-Jan-86 18:07:08  add coments.
KXI	20-Dec-85 14:13:50  add L1.Push2Dec2 into WTrapFix fixups routine for @PushByte and @PushByteToWordBoundary.
JPM	11-Sep-84 14:02:12  Altered to reflect new value of L1.Pop
DEG	 1-Sep-84 19:27:14  Add copyright notice
AEF	18-Jul-83 15:42:32  Change WLMapFix for double byte codes
JGS, September 23, 1981  4:41 PM New Instruction Set
RXG, April 11, 1980  4:52 PM
RXJ, January 20, 1981  10:22 AM
DXC, October 8, 1980  9:23 AM
}


{ 	Copyright (C) 1980, 1981, 1983, 1984, 1985, 1986 by Xerox Corporation.  All rights reserved.}
{*****************************************************************************
	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}

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

RCMapFix:
	Xbus ← Rx LRot0, XwdDisp, L3 ← L3.rhTT.TT,		c3;
	Map ← [rhTT, TT], Xbus ← 0, XDisp, DISP2[RMapa],	c1;

RMapa:	MDR ← Rx or map.referenced, L0Disp, DISP4[RMapb],	c2, at[0,10];
	MDR ← Rx or map.referenced, L0Disp, DISP4[RMapb],	c2, at[1,10,RMapa];
	MDR ← Rx or map.referenced, L0Disp, DISP4[RMapb],	c2, at[2,10,RMapa];
IBEmptyTrap:
	T ← qPageFault, L1Disp, DISP4[RTrap],			c2, at[3,10,RMapa];


RMapb:	Xbus ← 1{save step in caller}, XDisp, RET[RMFRtn],	c3, at[0,10,RMapb];
RTrap:	push, RET[RTrapFix],					c3, at[0,10,RTrap];


{*****************************************************************************
	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}

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

WMapa:	MDR ← Rx or map.rd, L0Disp, GOTO[WMapb],		c2, at[0,4];
	T ← qWriteProtect, L1Disp, GOTO[WTrap],			c2, at[1,4,WMapa];
	MDR ← Rx or map.rd, L0Disp, GOTO[WMapb],		c2, at[2,4,WMapa];
	T ← qPageFault, L1Disp, GOTO[WTrap],			c2, at[3,4,WMapa];

WMapb:	Xbus ← 2, XDisp, RET[WMFRtn],				c3;

WTrap:	push, RET[WTrapFix],					c3;


{*****************************************************************************
	Read Long 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;
RLMapx:	Map ← [rhTT,Q], Xbus ← 1, XDisp, DISP2[RMapa],		c1;

RLMapb:	Xbus ← 1, XDisp, RET[RLMFRtn],				c3, at[1,10,RMapb];

RLTrap:	push, RET[RLTrapFix],					c3, at[1,10,RTrap];


{*****************************************************************************
	Write Long 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], L0Disp, DISP2[WLMapa],				c1;

WLMapa:	MDR ← Rx or map.rd, L0Disp, CANCELBR[WLMapb,0F], LOOPHOLE[wok],	c2, at[0,4];
	T ← qWriteProtect, L1Disp, BRANCH[WLTrapD,WLTrap,0E],		c2, at[1,4,WLMapa];
	MDR ← Rx or map.rd, L0Disp, CANCELBR[WLMapb,0F], LOOPHOLE[wok],	c2, at[2,4,WLMapa];
	T ← qPageFault, L1Disp, BRANCH[WLTrapD,WLTrap,0E],		c2, at[3,4,WLMapa];

WLMapb:	Xbus ← 2, XDisp, RET[WLMFRtn],					c3;

WLTrapD:Noop, RET[WTrapFix],						c3;
WLTrap:	push, RET[WTrapFix],						c3;


{*****************************************************************************
	Local and Global Remap Subroutines
*****************************************************************************}
{Timing: 8 cycles (2 2/3 clicks), + 2 clicks if flags need fixing }
{Enter at cycle 2, returns to cycle 1}
{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, rhTT ← UvMDS/UvGhigh"}


LGMap:	Q ← Q - TT,						c2;
	Q ← Q and 0FF,						c3;

	Map ← Q ← [rhTT, TT + Q],				c1;
	Noop,							c2;
	Rx ← rhRx ← MD, XRefBr,					c3;

LGMa:	MAR ← [rhRx, Q + 0], BRANCH[LGMUD,$],			c1;
	L2Disp,							c2;
	rhTT ← TT ← MD, RET[LGMRtn],				c3;

LGMUD:	L1←L1.PopDec2,						c2;
	Xbus ← Rx LRot0, XwdDisp, L3 ← L3.rhTT.Q,		c3;
	Map ← [rhTT, Q], Xbus ← 2, XDisp, DISP2[RMapa],	c1;

	Xbus ← 1, XDisp, CANCELBR[LGMa,0F],			c3, at[2,10,RMapb];

	push, RET[RTrapFix],					c3, at[2,10,RTrap];


{*****************************************************************************
	RTrapFix
*****************************************************************************}

MacroDef[RTF, at[#1,10,RTrapFix]];

NoFixes:
	Noop, GOTO[NoMoreFix],				c1, RTF[L1.None];
	PC ← PC - PC16, GOTO[NoMoreFix],		c1, RTF[L1.Dec];
	PC ← PC - 1, GOTO[NoMoreFix],			c1, RTF[L1.Dec2];
	PC ← PC - 1, pop, GOTO[NoMoreFix],		c1, RTF[L1.PopDec2];
	PC ← PC - PC16, pop, GOTO[NoMoreFix],		c1, RTF[L1.PopDec];
	PC ← PC - PC16, pop, GOTO[PopFix],		c1, RTF[L1.Pop2Dec];
	PC ← PC - 1, pop, GOTO[PopFix],			c1, RTF[L1.Pop2Dec2];


{*****************************************************************************
	RLTrapFix
*****************************************************************************}

MacroDef[RLTF, at[#1,10,RLTrapFix]];

	Noop, GOTO[NoMoreFix],				c1, RLTF[L1.None];
	PC ← PC - PC16, GOTO[NoMoreFix],		c1, RLTF[L1.Dec];
	PC ← PC - 1, GOTO[NoMoreFix],			c1, RLTF[L1.Dec2];
	PC ← PC - 1, pop, GOTO[NoMoreFix],		c1, RLTF[L1.PopDec2];
	PC ← PC - PC16, pop, GOTO[NoMoreFix],		c1, RLTF[L1.PopDec];
	PC ← PC - PC16, pop, GOTO[PopFix],		c1, RLTF[L1.Pop2Dec];
	PC ← PC - 1, pop, GOTO[PopFix],			c1, RLTF[L1.Pop2Dec2];
	push, GOTO[PushFix],				c1, RLTF[L1.Push2];
	PC ← PC - PC16, push, GOTO[NoMoreFix],		c1, RLTF[L1.PushDec];
	PC ← PC - 1, push, GOTO[NoMoreFix],		c1, RLTF[L1.PushDec2];
	push, GOTO[NoMoreFix],				c1, RLTF[L1.Push];
	PC ← PC - 1 - PC16, GOTO[NoMoreFix],		c1, RLTF[L1.Dec3];


{*****************************************************************************
	WTrapFix fixups
*****************************************************************************}

MacroDef[WTF, at[#1,10,WTrapFix]];

	Noop, GOTO[NoMoreFix],				c1, WTF[L1.None];
	PC ← PC - PC16, GOTO[NoMoreFix],		c1, WTF[L1.Dec];
	PC ← PC - 1, GOTO[NoMoreFix],			c1, WTF[L1.Dec2];
	PC ← PC - 1, pop, GOTO[NoMoreFix],		c1, WTF[L1.PopDec2];
	PC ← PC - PC16, pop, GOTO[NoMoreFix],		c1, WTF[L1.PopDec];
	PC ← PC - PC16, pop, GOTO[PopFix],		c1, WTF[L1.Pop2Dec];
	PC ← PC + PC16, push, GOTO[NoMoreFix],		c1, WTF[L1.PushInc];
	push, GOTO[PushFix],				c1, WTF[L1.Push2];
	PC ← PC - PC16, push, GOTO[NoMoreFix],		c1, WTF[L1.PushDec];
	PC ← PC - 1, push, GOTO[NoMoreFix],		c1, WTF[L1.PushDec2];
	push, GOTO[NoMoreFix],				c1, WTF[L1.Push];
	PC ← PC - 1 - PC16, push, GOTO[NoMoreFix],	c1, WTF[L1.PushDec3];
PopOnlyFix:
	pop, GOTO[NoMoreFix],				c1, WTF[L1.Pop];
	PC ← PC - 1, push, GOTO[PushFix],		c1, WTF[L1.Push2Dec2];


{*****************************************************************************
	Trap Handling
*****************************************************************************}

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

TrapFixDone:	L3Disp, BRANCH[LowQ, LowTT, 2],				c3;

LowQ:	uFaultParm0 ← Q, BRANCH[HiMDS, HiTT, 1],			c1;
LowTT:	uFaultParm0 ← TT, BRANCH[HiMDS, HiTT, 1],			c1;

HiMDS:	Q ← rhMDS, GOTO[Faultc3],					c2;
HiTT:	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}
Trapc2:	GOTO[Trapc3],							c2;
Trapc3:	G ← 0, GOTO[Trapc1],						c3;
Trapc1:	uTrapParm0 ← TT, L2 ← L2.TRAPSpc,				c1;
	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;
	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, GOTO[ShiftOK0],			c*, at[0,10,CycleMask];
	T ← TT, [] ← rhT, XDisp, GOTO[ShiftOK0],		c*, at[1,10,CycleMask];
	T ← LRot1 TT, [] ← rhT, XDisp, GOTO[ShiftOK0],		c*, at[2,10,CycleMask];
	T ← RRot1 T, [] ← rhT, XDisp, GOTO[ShiftOK4],		c*, at[3,10,CycleMask];

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

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

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

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


{*****************************************************************************
	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];