{file:  QJump.mc
last edit   29-Aug-85 10:16:22
}
	SetTask[0];

{*************************
	JUMP	1%  2 clicks
**************************}
@JUMP:	opcode[200'b],
	MAR ← PC ← [rhPC, PC+1], GOTO[JnPos],	c1;
	MAR ← PC ← [rhPC, PC+1+PC16], GOTO[JnPos],	c1,opcode[201'b];
	MAR ← PC ← [rhPC, PC+2], GOTO[JnPos],	c1,opcode[202'b];
	MAR ← PC ← [rhPC, PC+2+PC16], GOTO[JnPos],	c1,opcode[203'b];
	MAR ← PC ← [rhPC, PC+3], GOTO[JnPos],	c1,opcode[204'b];
	MAR ← PC ← [rhPC, PC+3+PC16], GOTO[JnPos],	c1,opcode[205'b];
	MAR ← PC ← [rhPC, PC+4], GOTO[JnPos],	c1,opcode[206'b];
	MAR ← PC ← [rhPC, PC+4+PC16], GOTO[JnPos],	c1,opcode[207'b];

	MAR ← PC ← [rhPC, PC+5], GOTO[JnPos],	c1,opcode[210'b];{88}
	MAR ← PC ← [rhPC, PC+5+PC16], GOTO[JnPos],	c1,opcode[211'b];
	MAR ← PC ← [rhPC, PC+6], GOTO[JnPos],	c1,opcode[212'b];
	MAR ← PC ← [rhPC, PC+6+PC16], GOTO[JnPos],	c1,opcode[213'b];
	MAR ← PC ← [rhPC, PC+7], GOTO[JnPos],	c1,opcode[214'b];
	MAR ← PC ← [rhPC, PC+7+PC16], GOTO[JnPos],	c1,opcode[215'b];
	MAR ← PC ← [rhPC, PC+8], GOTO[JnPos],	c1,opcode[216'b];
	MAR ← PC ← [rhPC, PC+8+PC16], GOTO[JnPos],	c1,opcode[217'b];

JnPos:	Xbus ← 0, XC2npcDisp, BRANCH[$, JnCross, 1],	c2;
	IB ← MD, BRANCH[ptr1, ptr0, 0E],	c3;

JnCross:	Q ← 0FF + 1, L0 ← L0.JRemap, CANCELBR[UpdatePC, 0F],	c3;

@JUMPX:	opcode[260'b],
	S ← S + 1, Xbus ← ibNA, XLDisp, L2 ← L2.ok,	c1;
	Rx ← ib RShift1, XLDisp, SE ← 0, BRANCH[jxp, jxn, 1],	c2;
jxp:	BRANCH[jpe, jpo, 2],	c3;
jxn:	Rx ← 7F - Rx, BRANCH[jne, jno, 2],	c3;


{*************************
	FJUMP, TJUMP	4%  4 clicks
**************************}

@FJUMP:	opcode[220'b],
	MAR ← [rhS, S], S ← S -1, L2 ← 0,	c1;
	 Ybus ← TOSH or TOS, NZeroBr, CANCELBR[jmp, 2],	c2;
	MAR ← [rhS, S], S ← S -1, L2 ← 1,	c1, opcode[221'b];
	 Ybus ← TOSH or TOS, NZeroBr, CANCELBR[jmp, 2],	c2;
	MAR ← [rhS, S], S ← S -1, L2 ← 2,	c1, opcode[222'b];
	 Ybus ← TOSH or TOS, NZeroBr, CANCELBR[jmp, 2],	c2;
	MAR ← [rhS, S], S ← S -1, L2 ← 3,	c1, opcode[223'b];
	 Ybus ← TOSH or TOS, NZeroBr, CANCELBR[jmp, 2],	c2;
	MAR ← [rhS, S], S ← S -1, L2 ← 4,	c1, opcode[224'b];
	 Ybus ← TOSH or TOS, NZeroBr, CANCELBR[jmp, 2],	c2;
	MAR ← [rhS, S], S ← S -1, L2 ← 5,	c1, opcode[225'b];
	 Ybus ← TOSH or TOS, NZeroBr, CANCELBR[jmp, 2],	c2;
	MAR ← [rhS, S], S ← S -1, L2 ← 6,	c1, opcode[226'b];
	 Ybus ← TOSH or TOS, NZeroBr, CANCELBR[jmp, 2],	c2;
	MAR ← [rhS, S], S ← S -1, L2 ← 7,	c1, opcode[227'b];
	 Ybus ← TOSH or TOS, NZeroBr, CANCELBR[jmp, 2],	c2;
	MAR ← [rhS, S], S ← S -1, L2 ← 8,	c1, opcode[230'b];{98}
	 Ybus ← TOSH or TOS, NZeroBr, CANCELBR[jmp, 2],	c2;
	MAR ← [rhS, S], S ← S -1, L2 ← 9,	c1, opcode[231'b];
	 Ybus ← TOSH or TOS, NZeroBr, CANCELBR[jmp, 2],	c2;
	MAR ← [rhS, S], S ← S -1, L2 ← 0A,	c1, opcode[232'b];
	 Ybus ← TOSH or TOS, NZeroBr, CANCELBR[jmp, 2],	c2;
	MAR ← [rhS, S], S ← S -1, L2 ← 0B,	c1, opcode[233'b];
	 Ybus ← TOSH or TOS, NZeroBr, CANCELBR[jmp, 2],	c2;
	MAR ← [rhS, S], S ← S -1, L2 ← 0C,	c1, opcode[234'b];
	 Ybus ← TOSH or TOS, NZeroBr, CANCELBR[jmp, 2],	c2;
	MAR ← [rhS, S], S ← S -1, L2 ← 0D,	c1, opcode[235'b];
	 Ybus ← TOSH or TOS, NZeroBr, CANCELBR[jmp, 2],	c2;
	MAR ← [rhS, S], S ← S -1, L2 ← 0E,	c1, opcode[236'b];
	 Ybus ← TOSH or TOS, NZeroBr, CANCELBR[jmp, 2],	c2;
	MAR ← [rhS, S], S ← S -1, L2 ← 0F,	c1, opcode[237'b];
fj:	 Ybus ← TOSH or TOS, NZeroBr, CANCELBR[jmp, 2],	c2;

@TJUMP:	opcode[240'b],
	MAR ← [rhS, S], S ← S -1, GOTO[tj],	c1;
	MAR ← [rhS, S], S ← S -1, GOTO[tj],	c1, opcode[241'b];
	MAR ← [rhS, S], S ← S -1, GOTO[tj],	c1, opcode[242'b];
	MAR ← [rhS, S], S ← S -1, GOTO[tj],	c1, opcode[243'b];
	MAR ← [rhS, S], S ← S -1, GOTO[tj],	c1, opcode[244'b];
	MAR ← [rhS, S], S ← S -1, GOTO[tj],	c1, opcode[245'b];
	MAR ← [rhS, S], S ← S -1, GOTO[tj],	c1, opcode[246'b];
	MAR ← [rhS, S], S ← S -1, GOTO[tj],	c1, opcode[247'b];
	MAR ← [rhS, S], S ← S -1, GOTO[tj],	c1, opcode[250'b];{A8}
	MAR ← [rhS, S], S ← S -1, GOTO[tj],	c1, opcode[251'b];
	MAR ← [rhS, S], S ← S -1, GOTO[tj],	c1, opcode[252'b];
	MAR ← [rhS, S], S ← S -1, GOTO[tj],	c1, opcode[253'b];
	MAR ← [rhS, S], S ← S -1, GOTO[tj],	c1, opcode[254'b];
	MAR ← [rhS, S], S ← S -1, GOTO[tj],	c1, opcode[255'b];
	MAR ← [rhS, S], S ← S -1, GOTO[tj],	c1, opcode[256'b];
	MAR ← [rhS, S], S ← S -1, GOTO[tj],	c1, opcode[257'b];
tj:	Ybus ← TOSH or TOS, ZeroBr, CANCELBR[jmp, 2],	c2;

jmp:	TOS ← MD, BRANCH[$, NoJump], L2Disp,	c3;

	MAR ← [rhS, S + 0], DISP4[TgetsL,1],	c1;
TgetsL:	Rx ← 1, L2Disp, GOTO[jjoin],	c2, at[1, 10, TgetsL];
	Rx ← 2, L2Disp, GOTO[jjoin],	c2, at[3, 10, TgetsL];
	Rx ← 3, L2Disp, GOTO[jjoin],	c2, at[5, 10, TgetsL];
	Rx ← 4, L2Disp, GOTO[jjoin],	c2, at[7, 10, TgetsL];
	Rx ← 5, L2Disp, GOTO[jjoin],	c2, at[9, 10, TgetsL];
	Rx ← 6, L2Disp, GOTO[jjoin],	c2, at[0B, 10, TgetsL];
	Rx ← 7, L2Disp, GOTO[jjoin],	c2, at[0D, 10, TgetsL];
	Rx ← 8, L2Disp, GOTO[jjoin],	c2, at[0F, 10, TgetsL];

NoJump:	MAR ← [rhS, S], S ← S -1, CANCELBR[$, 0F],	c1;
	PC ← PC+PC16, L2 ← L2.0, IBDisp, DISP2[njNoCar],	c2;
	S ← S - 0FF,	c3, at[2, 10, njNoCar];

	MAR ← [rhS, S+0],	c1;
	S ← S -1, L2 ← L2.0, IBDisp,	c2;
njNoCar:	TOSH ← MD, L2 ← L2.0, DISPNI[OpTable],	c3, at[0, 10, njNoCar];


{*************************
	FJUMPX, TJUMPX
**************************}
{based on the stack pointer conventions:}
{Q: does MAR← interfere with XLDisp when no pagecarry?}

@FJUMPX:	opcode[262'b],
	MAR ← [rhS, S], S ← S - 1, Xbus ← ibNA, XLDisp,	c1;
	Ybus ← TOSH or TOS, NZeroBr, BRANCH[pos, neg, 1],	c2;

@TJUMPX:	opcode[263'b],
	MAR ← [rhS, S], S ← S -1, Xbus← ibNA, XLDisp,	c1;
	Ybus ← TOSH or TOS, ZeroBr, BRANCH[pos, neg, 1],	c2;


{*************************
	NFJUMPX, NTJUMPX	2%  4 clicks
**************************}

@NFJUMPX:	opcode[264'b],
	{different on jump: don't pop}
	MAR ← [rhS, S], S ← S - 1, Xbus ← ibNA, XLDisp,	c1;
	Ybus ← TOSH or TOS, NZeroBr, BRANCH[Npos, Nneg, 1],	c2;

@NTJUMPX:	opcode[265'b],
MAR ← [rhS, S], S ← S - 1, Xbus ← ibNA, XLDisp,	c1;
	Ybus ← TOSH or TOS, ZeroBr, BRANCH[Npos, Nneg, 1],	c2;

Npos:	uTOS ← TOS, TOS ← MD, BRANCH[$, NoJumpP],	c3;
	TOS ← uTOS,	c1;
	Rx ← ib RShift1, XLDisp, SE ← 0,	c2;
	S ← S + 2, BRANCH[jpe, jpo, 2],	c3;

Nneg:	uTOS ← TOS, TOS ← MD, BRANCH[$, NoJumpF],	c3;
	Rx ← 0FF,	c1;
	,	c2;
	,	c3;
	TOS ← uTOS,	c1;
	Rx ← (ib xor Rx) RShift1, XLDisp, SE ← 0,	c2;
	S ← S + 2, BRANCH[jne, jno, 2],	c3;

{*************************
	JUMPXX
**************************}

@JUMPXX:	opcode[261'b],
	Rx ← ib, XLDisp,	c1;
jw:	Rx ← Rx LRot8, BRANCH[jwPos, jwNeg, 1],	c2;

jwPos:	Rx ← RShift1 (Rx or ib), SE←0, XLDisp, GOTO[jwtos],	c3;
jwNeg:	Rx ← RShift1 (Rx or ib), SE←1, XLDisp, GOTO[jwtos],	c3;

jwtos:	PC ← PC and 0FF, BRANCH[jwEven, jwOdd, 2],	c1;

{PC,,pc16←location in page}
jwEven:	PC ← PC + Rx, GOTO[jwCross],	c2;
jwOdd:	PC ← PC + Rx + PC16, GOTO[jwCross],	c2;

jwCross:	
	uPCCrossL ← 0,	c3;

	,	c1;
	,	c2;
	Q ← PC and ~0FF, L0 ← L0.JRemap, GOTO[UpdatePC],	c3;

{*************************
	Common Jump Code
**************************}
pos:	TOS ← MD, BRANCH[$, NoJumpX],	c3;

	MAR ← [rhS, S+0],	c1;
	Rx ← ib RShift1, XLDisp, SE ← 0,	c2;
jjoin:	TOSH ← MD, BRANCH[jpe, jpo, 0E],	c3; 

jpe:	MAR ← PC ← [rhPC, PC + Rx], GOTO[jp], MesaIntBr,	c1;
jpo:	MAR ← PC ← [rhPC, PC + Rx + PC16], MesaIntBr,	c1;
jp:	S ← S - 1, Xbus ← 0, XC2npcDisp, DISP2[JumpPX],	c2;
jp3:	IB ← MD, BRANCH[ptr1, ptr0, 0E],	c3, at[0, 4, JumpPX];

ptr0:	MAR ← [rhPC, PC + 1], IBPtr ← 0, L2 ← L2.0, GOTO[RefillNE2],	c1; 
ptr1:	MAR ← [rhPC, PC + 1], IBPtr ← 1, L2 ← L2.0, GOTO[RefillNE2],	c1;

NoJumpP:	MAR ← [rhS, S], S ← S - 1, Xbus ← ib, GOTO[nj],	c1;
NoJumpF:	MAR ← [rhS, S], S ← S - 1, Xbus ← ib, GOTO[nj],	c1;
NoJumpN:	MAR ← [rhS, S], S ← S - 1, Xbus ← ib, GOTO[nj],	c1;
NoJumpX:	MAR ← [rhS, S], S ← S - 1, Xbus ← ib, GOTO[nj],	c1;
nj:	PC ← PC+1, IBDisp, L2 ← L2.0, DISP4[njxNoCar],	c2;
	S ← S - 0FF,	c3, at[2, 10, njxNoCar];

	MAR ← [rhS, S+0],	c1;
	S ← S - 1, IBDisp, L2 ← L2.0,	c2;
njxNoCar:	TOSH ← MD, L2 ← L2.0, DISPNI[OpTable],	c3, at[0, 10, njxNoCar];

	Q ← 0FF + 1, L0 ← L0.JRemap, CANCELBR[UpdatePC, 0F],	c3, at[2, 4, JumpPX];
	Q ← ~0FF, L0 ← L0.JRemap, CANCELBR[UpdatePC, 0F],	c3, at[2, 4, JumpNX];
	Q ← 0FF + 1, L0 ← L0.JRemap, CANCELBR[UpdatePC, 0F],	c3, at[3, 4, JumpPX];
	Q ← ~0FF, L0 ← L0.JRemap, CANCELBR[UpdatePC, 0F],	c3, at[3, 4, JumpNX];

	IB ← MD, uPCCrossL ← 0, BRANCH[ptrJ1, ptrJ0, 0E],	c3, at[1, 4, JumpPX];
	IB ← MD, uPCCrossL ← 0, BRANCH[ptrJ1, ptrJ0, 0E],	c3, at[1, 4, JumpNX];

ptrJ0:	IBPtr←0, GOTO[MInt],	c1; 
ptrJ1:	IBPtr←1, GOTO[MInt],	c1;

neg:	TOS ← MD, BRANCH[$, NoJumpN],	c3;

	TT ← 0FF,	c1;
	,	c2;
	,	c3;

	STK ← MAR ← [rhS, S],	c1;
	Rx ← (ib xor TT) RShift1, SE ← 0, XLDisp, CANCELBR[$, 2],	c2;
	TOSH ← MD, BRANCH[jne, jno, 2],	c3;

jne:	MAR ← PC ← [rhPC, PC - Rx -1], GOTO[jn], MesaIntBr,	c1;
jno:	MAR ← PC ← [rhPC, PC - Rx - PC16], GOTO[jn], MesaIntBr,	c1;
jn:	S ← S - 1, Xbus ← 0, XC2npcDisp, DISP2[JumpNX],	c2;
jn3:	IB ← MD, BRANCH[ptr1, ptr0, 0E],	c3, at[0, 4, JumpNX];

{*************************}
{
Jump.dfn	comments on PC, IFU, page crossing and control transfer

The DLion Interlisp-D Instruction Fetch Unit (IFU) is implemented in hardware and microcode.
Code arrays cannot cross segments.  Name tables cannot cross pages.
The IFU state variables and their values AT OPCODE ENTRY are:	

STATE CONCEPTUALLY STORED IN THE LOCAL FRAME
codeB		UvCL + UvChighL*2↑16			fn header		
tPC		2*[UvPCpageL-UvCL+(PC and 0FF)]+PC16	true byte PC	

ADDITIONAL IFU STATE
IBCnt=IBPtr	number of valid bytes in IFU  (must correlate even/odd with pc16 in puntFor? elsewhere ErrnIBnStkp?)

CACHED IFU STATE :
UvChighL	(codeB)/(2↑16)				code base high
UvCL		(0FFFF and codeB)

UvPCpageL	(0FF00 and (codeB + tPC/2)
rhPC		upper Map(codeB + tPC/2))			PC real segment and flags
PC		(0FF and tPC/2)+(0FF00 and Map(codeB + tPC/2))	PC real word address
pc16		(tPC and 1)					PC byte flip flop

uPCCrossL	((tPC and 1FE)=1FE) = (PC = (FF mod 100)) 	
MInt		interrupt or uPCCrossL


IFU STATE AT OPCODE ENTRY
A1) OPCODE ENTRY				STANDARD
A2) OPCODE ENTRY abort to Pfault PUNT		uPCCrossL and (PC and FE)#FE has special meaning (for puntFor? for 4 byte ops?) => tPC ← tPC + 200
						L2 has special meaning

B1) OPCODE EXIT to refill		(1b)	(Mint)    if (uPCCrossL and (PC and FF)#FF)		then UpdatePC + 100; {uPCCrossL ← 0}
					(2)	(RefillE) if ~uPCCrossL and IBCnt=0 and (tPC and 1FF)=0 then UpdatePC + 100
					(1a)	(RefilNE) uPCCrossL ← (PC and FF)=FF
						
B2) OPCODE EXIT to "punt forward"	(1b)	if uPCCrossL and (PC and FE)#FE 			then UpdatePC + 100
					(2)	if {~uPCCrossL and} IBCnt=0 and (tPC and 1FF)=0 	then UpdatePC + 100


PAGE CROSS PRINCIPLE: Notice page cross by (1a+1b)IFU containing bytes from 2 pages or (2) by IFU exhausted at exactly page boundry.
PAGE CROSS PRINCIPLE for 4 bytes (i) still valid (ii):


{c) going to PCUpdate				tPC ← tPC + 2*Q}

f) at fmMD of function call			L3



}


{Buffer Empty Refill.  Control goes from NoRCross to RefillNE since RefillE+1 does not contain an IBDisp.}
RefillE:
	MAR ← [rhPC, PC], PC ← PC - PC16, L0 ← L0.ERefill,	c1, at[400];
	PC ← PC+PC16 {restore}, DISP2[NoRCross],	c2;


{Buffer Not Empty Refill.}
	{"Noop" location of Instruction Dispatch table}
OpTable:
RefillNE:		at[OpTable],
Refil:
	MAR ← [rhPC, PC + 1], L2 ← L2.0,	c1;
RefillNE2:	AlwaysIBDisp, L0 ← L0.NERefill.Set, DISP2[NoRCross],	c2;

NoRCross:	IB ← MD, uPCCrossL ← 0, L2 ← L2.0, DISPNI[OpTable],	c3, at[0,4,NoRCross];
RCross:	Q ← 0FF + 1, GOTO[UpdatePC],	c3, at[2,4,NoRCross];

{************************
	Refill Remap Routines
*******************************}

{
Entry:
T	old real PC
Q[0-7]	page displacement to be added to virtual PC
Q[8-15]	ignored
PC[0-7]	ignored
PC[8-15]	valid location within new page
pc16	must be valid

Exit:
UvPCpageL	new virtual PC page
TT	new virtual PC page
rhTT	UvChighL
PC	new real PC value
Q	new real PC value
}
{L0.ERefill & uPCCrossL indicate remap and fetch (NE) PC+1}

UpdatePC:	TT ← UvPCpageL, L1 ← L1.Refill{for fault trap},	c1, at[0F,10];
UpdatePC2:	TT ← TT + Q, rhTT ← UvChighL,	c2;
UpdatePC3:	Q{lowPC} ← PC,	c3;

	Map ← TT ← [rhTT, TT], L0Disp,	c1;
	TT ← TT and ~0FF , DISP4[ECross],	c2;

	PC ← Q{lowPC}, GOTO[NoMoreFix],	c1, at[L1.Refill, 10, Fix];

{Buffer Empty Refill page cross OR PCCross flag true.  Remap the PC (which points to 1st or 2nd word of page).  If we are doing an empty refill, return to the Empty Refill code at NoRCross.  If we are updating the PC because PCCross is true, return to Refill-interrupt code.}
{Even if we fault, have UvPCpageL updated.}

ECross:	UvPCpageL ← TT, PC ← MD, rhPC ← MD, ReadXRefBr,	c3, at[L0.ERefill, 10, ECross];

ERedo:	MAR ← Q ← [rhPC, Q+0], Xbus ← uPCCrossL, XRefBr, ReadBRANCH[EMapUD, $],	c1, at[L0.ERefill, 10, RMapFixCaller];
EMapOK:
	PC ← Q, BRANCH[NoRCross, PageCrossed],	c2;

EMapUD:	Rx ← PC, CANCELBR[RLMapFix]  {returns at ERedo},	c2;


{Buffer Not Empty Refill page cross.  Fetch the first word of the next page and do NOT Remap PC.  Set PCCross true and the Refill-Interrupt hardware bit.  Dispatch on the IB (as in the RefillNE code).}

NECross:	Rx ← MD, rhRx ← MD, ReadXRefBr,	c3, at[L0.NERefill,10,ECross];

NERedo:	MAR ← [rhRx, 0+0], MesaIntRq, ReadBRANCH[NEMapUD, $],	c1, at[L0.NERefill,10,RMapFixCaller];
	AlwaysIBDisp, L2 ← L2.0,	c2;
	IB ← MD, uPCCrossL ← (~TT xor TT), L2 ← L2.0, DISPNI[OpTable],	c3;

NEMapUD:	uPCCrossL ← (~TT xor TT), CALL[RLMapFix]  {returns at NERedo},	c2;

{Jump Cross Remap.  Remap the PC (which can point to any word of a page).  uPCCrossL should remain unaltered in case the page cross test at Jgo is true.}
{Even if we fault, have UvPCpageL updated.}

JCross:	UvPCpageL ← TT, PC ← MD, rhPC ← MD, ReadXRefBr,	c3, at[L0.JRemap, 10, ECross];

JRedo:	MAR ← Q ← [rhPC, Q+0], ReadBRANCH[JMapUD, $],	c1, at[L0.JRemap, 10, RMapFixCaller];
	PC ← Q, Xbus ← 0, XC2npcDisp,	c2;
	IB ← MD, BRANCH[ptr1, ptr0, 0E],	c3;

JMapUD:	Rx ← PC, CALL[RLMapFix]  {returns at JRedo},	c2;

{uPCCrossL is true.  Check if we are still on last word of page.  If not, go update the PC to point to the next page.  T contains 0 if buffer is empty, -1 otherwise.  This is put back into uPCCrossL.  If buffer is not empty control goes from ECross to PageCross which ignores the first word fetched.}

Crossing:
	Ybus ← PC + 1, PgCarryBr, CANCELBR[$],	c3;

	L0 ← L0.ERefill, BRANCH[$, NotAcross],	c1;
	uPCCrossL ← TT, GOTO[RCross],	c2;

{We haven't crossed the boundary yet.  Save state again, keep uPCCrossL true.}

NotAcross:
	AlwaysIBDisp, L2 ← L2.0, GOTO[DNI.nop],	c2;

{We've crossed the page boundary & updated the PC to point to the next page.  Zero uPCCrossL. We know the buffer is not empty, but we also know it is not full so we exit through RefillNE.}

PageCrossed:
	uPCCrossL ← 0, GOTO[RefillNE],	c3, at[1,4,NoRCross];

	{ E N D }