{File name MdbNewLisp.mc;    DandeLion Interlisp Emulator - slow returns
Last edited: Purcell, 16-Jun-85 21:23:14 new IFU {Pc} marks changes
Last edited: Purcell, 28-Dec-83 12:35:27 use 3 mapflags only
 Last edited: Charnley,  29-Dec-83 14:32:39
Last edited: Purcell, 28-Dec-83 12:35:27 use 3 mapflags for 4MB real mem but keep dp stored for iop
Last edited: Charnley, 15-Jul-83 10:37:34
Last edited: April 7, 1983  12:34 AM; sink if fault and PV<3000'b
Last edited: April 5, 1983  11:31 AM disable fault context double exit trap
Last edited: February 5, 1983  11:42 AM
Last edited: January 17, 1983  12:54 PM moved initialization to InitLisp.mc
 Last edited: November 20, 1982  4:33 PM % debugging hack: draw screen and pause
Last edited: November 20, 1982  1:00 PM debugging IOP starting handshake
Last edited: August 11, 1982  1:45 AM Try keeping display off during disk boot
}

SetTask[0];  {StartAddress[Start];}

{M1Loc:	Q ← 129'd, GOTO[sink2],	c1, at[Maintenance1Loc];{MP9129}
	Q ← 130'd, GOTO[sink3],	c2, at[Maintenance2Loc];{MP9130}
	Q ← 131'd, GOTO[sink1],	c3, at[Maintenance3Loc];{MP9131}}

{******************************************************************
	READFLAGS
*******************************************************************}
READFLAGS:
	Xbus ← TOSH xor smallpl, NZeroBr,	c1, opcode[161'b]; {71}
	rhTT ← TT ← TOS LRot8, BRANCH[$, rdfUfn],	c2;
	TOSH ← smallpl,	c3;

	Map ← [rhTT, TT],	c1;
	TOS ← 0E0,	c2;
	TOS ← MD and TOS,	c3;

	TOS ← TOS LRot12,	c1;
	Ybus ← TOS and 4, ZeroBr,	c2;
	BRANCH[rfsetD, $],	c3;

	,	c1;
rfafterD:
	TOS ← TOS LRot12, IBDisp, L2 ← L2.0, GOTO[DNI.pc1],	c2;
rfsetD:
	TOS ← TOS - 3, GOTO[rfafterD],	c1;

rdfUfn:	Rx ← 161'b, GOTO[ufn1],	c3;
{******************************************************************
	READRP
*******************************************************************}
READRP:
	Xbus ← TOSH xor smallpl, NZeroBr,	c1, opcode[162'b]; 
	rhTT ← TT ← TOS LRot8, BRANCH[$, rdrpUfn],	c2;
	TOSH ← smallpl,	c3;

	Map ← [rhTT, TT],	c1;
	TOS ← ~0E0, L2 ← L2.0,	c2;
	TOS ← MD and TOS, c3;

{%M}
	Ybus ← TOS - 1, PgCarryBr,	c1;
	BRANCH[rsect0, rsectN0],	c2;
rsect0:
	GOTO[readrpend],	c3;
rsectN0:
	TOS ← TOS - 3, GOTO[readrpend],	c3;
{%M}
readrpend:
	PC ← PC + PC16,	c1;
	IBDisp,	c2;
	TOS ← TOS LRot8, L2 ← L2.0, DISPNI[OpTable],	c3;

rdrpUfn:	Rx ← 162'b, GOTO[ufn1],	c3; {******************************************************************
	WRITEMAP
*******************************************************************}

WRITEMAP:   {vp, rp, flag => vp}

	MAR ← [rhS, S], S ← S -1,	c1, opcode[163'b];{73}
	Ybus ← TOSH xor smallpl, NZeroBr, CANCELBR[$, 2],	c2;
	Rx ← MD{rp}, BRANCH[$, ufnWM0],	c3;
	
{ Test to see if the rp is in the display bank. If so, leave it alone else bump pg# by 300}
	TT ← Rx and ~0FF, c1;
	Ybus ← TT + 0, ZeroBr, c2;
	TT ← 3, BRANCH[notDB, isDB], c3;
	
notDB:	TT ← TT LRot8, c1;
	Rx ← Rx + TT, c2;  {add 3 segs}
	, c3;

isDB:	MAR ← [rhS, S + 0],	c1;
	S ← S -1, 	c2;
	Q ← MD{rpH},	c3;

	MAR ← [rhS, S], S ← S -1,	c1;
	Ybus ← Q xor smallpl, NZeroBr, CANCELBR[$,2],	c2;
	TT ← MD{vp}, BRANCH[$, ufnWM1],	c3;

	MAR ← [rhS, S+0], L2 ← L2.0,	c1;
	Rx ← Rx LRot8,			c2;
	Q ← MD{vpH},			c3;
	
	Noop, 				c1;
	Ybus ← Q xor smallpl, NZeroBr,	c2;
	rhTT ← TT ← TT LRot8, BRANCH[$, ufnWM2],	c3;

	S ← S -1, Xbus ← TOS LRot4, XDisp,	c1;
	Rx ← Rx and ~070, DISP4[wmf, 4],	c2;

	Rx ← Rx or 0, GOTO[wMap],	c3, at[4, 10, wmf];
	Rx ← Rx or 10, GOTO[wMap],	c3, at[0C,10,wmf];
	Rx ← Rx or 0{A}20, GOTO[wMap], 	c3, at[5, 10, wmf];
	Rx ← Rx or 0{B}30, GOTO[wMap],	c3, at[0D,10,wmf];
	Rx ← Rx or 40, GOTO[wMap],	c3, at[6, 10, wmf];
	Rx ← Rx or 50, GOTO[wMap],	c3, at[0E,10,wmf];
	Rx ← Rx or 60, GOTO[wMap],	c3, at[7, 10, wmf];
	Rx ← Rx or 70, GOTO[wMap], {reserved}	c3, at[0F,10,wmf];

wMap:	Map ← [rhTT, TT],	c1;
	MDR ← Rx, PC ← PC + PC16, IBDisp,	c2;
	TOS ← TT LRot8, L2 ← L2.0, DISPNI[OpTable],	c3;

ufnWM0:	S ← S+1, GOTO[ufnX2],	c1; 
ufnWM1:	S ← S+3, GOTO[ufnX2],	c1; 
ufnWM2:	S ← S+3, GOTO[ufnX2],	c1; 


{*************************
	Read Map Update Subroutine 
**************************}
{Timing: 4 cycles}
{Enter at cycle 3, returns to cycle1}
{returns thru L0 if map fixed ok, relative to RMapFixCaller}
{returns thru L1 if wants to trap, relative to RFixForTrap}


RLMapFix:	Xbus ← Rx LRot0,XwdDisp, GOTO[RLMapFix1],	c3;

{RLMapFixPC:
	Rx ← PC, Xbus ← PC LRot0,XwdDisp, GOTO[RLMapFix1],	c3;}

RLMapFix1:
	Map ← [rhTT,TT], DISP2[RFixRFlags],	c1;

RFixRFlags:
	MDR ← Rx or 80, L0Disp, GOTO[ReRead],	c2, at[PgClean,4];
	MDR ← Rx or 80, L0Disp, GOTO[ReRead],	c2, at[PgDirty,4,RFixRFlags];
	MDR ← Rx or 80, L0Disp, GOTO[ReRead],	c2, at[PgProt,4,RFixRFlags];
	GOTO[RWTrap],	c2, at[PgVacant,4,RFixRFlags];

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

RWTrap:	Noop, GOTO[PFault],	c3;

{copy of MapFix for more than 16 returns}

RLxMapFix:	Xbus ← Rx LRot0, XwdDisp,	c3;

RLxMapFix1:		
	Map ← [rhTT,TT], DISP2[RxFixRFlags],	c1;

RxFixRFlags:
	MDR ← Rx or 80, L0Disp, GOTO[RexRead],	c2, at[PgClean,4];
	MDR ← Rx or 80, L0Disp, GOTO[RexRead],	c2, at[PgDirty,4,RxFixRFlags];
	MDR ← Rx or 80, L0Disp, GOTO[RexRead],	c2, at[PgProt,4,RxFixRFlags];

	GOTO[RWTrap],	c2, at[PgVacant,4,RxFixRFlags];

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


{*************************
	Write Map Update Subroutine 
**************************}
{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,	c3;
	Map ← [rhTT, TT], WriteDISP2[FixWFlags],	c1;

FixWFlags:
	MDR ← Rx or 0C0, L0Disp, GOTO[ReWrite],	c2, at[PgWrtOK,4,FixWFlags];
	GOTO[RWTrap],	c2, at[PgNoWrt,4,FixWFlags];

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


{*************************
	FixForTrap (merge RFixForTrap and WFixForTrap)
**************************}
	PC ← PC - 1, GOTO[NoMoreFix],	c1, at[L1.DecDec,10,Fix];
	PC ← PC - 1, GOTO[PushFix],	c1, at[L1.PushDec2,10,Fix];
PushFix:	S ← S + 2, GOTO[TrapFixDone],	c2;
	PC ← PC - PC16, GOTO[NoMoreFix],	c1, at[L1.DecOnly,10,Fix];
	PC ← PC - 1 - PC16, GOTO[NoMoreFix],	c1, at[L1.Dec3,10,Fix];
	S ← S + 2, GOTO[NoMoreFix],	c1, at[L1.PushOnly,10,Fix];
	S ← S - 2, GOTO[NoMoreFix],	c1, at[L1.PopOnly,10,Fix];
	S ← S + 4, GOTO[NoMoreFix],	c1, 
at[L1.Push2OK,10,Fix];
NoMoreFix:	Noop, GOTO[TrapFixDone],	c2;


TrapFixDone: Noop, {GOTO[PUNT]}	c3;

NoFixes:	Rx ← PV LRot8,	c1, at[L1.NoFixes,10,Fix];
	Ybus ← 5 - Rx {- 6}{+FFFA}, PgCarryBr{small PV},	c2;
	Rx ← FAULTFXP, BRANCH[PUNT, ReFault],	c3;

{store fault address in interface page}

PFault:	, at[BBFault],
	rhRx ←  INTERFACEspace, 	c1;
	Rx ← INTERFACEbasePage{20'b}{INTERFACEbase=10000'b},	c2;
	Rx ← Rx LRot8,	c3;

{for debugging set uPageFault  to all ones while in fault}
	Map ←  [rhRx,Rx],	c1;
	,	c2;
	Rx ← rhRx ← MD,	c3;

	MAR ← [rhRx, 0 + IFPFAULTHI],	c1;
	MDR ← rhTT, CANCELBR[$, 2], WriteOK,	c2;
	uPageFault ← S xor ~ S,	c3;

	MAR ← [rhRx, 0 + IFPFAULTHI + 1], L2 ← 0{NotInCall},	c1;
	MDR ← TT, L1Disp, CANCELBR[$, 2], WriteOK,	c2;
	Rx ← {0 -} FAULTFXP, RET[Fix],	c3;

ReFault:	Q ← 24'd, GOTO[sink2],	c1;{MP9024}

{**************************************************}
CONTEXTSWITCH: 			
{**************************************************}

{Takes context number in TOS: switch to that context, return value ignored}

{% SHOULD CHECK IF ANY PENDING INTERRUPTS - CURRENTLY
 MAY MISS KEYSTROKES }

opcode[176'b],{7E}
	Ybus ← TOS xor FAULTFXP, ZeroBr{faultExit}, L2← 0{NotInCall},	c1;
	Rx← TOS, BRANCH[$,  SwFault],	c2;
	TOSH ← 0, CANCELBR[ConJn],	c3;

SwFault:	uPageFault ← TOSH ← 0{notFaulting},	c3;
ConJn:	uWDC ← TOSH, PC← PC + PC16 {advance PC}, GOTO[PuntFor2],	c1;


{note that this code winds up storing the context number on the stack and then
setting the no-push bit in the frame. This is not exactly the same as the Dorado, but no code relies on the value returned "to" a context}



{**************************************************}
{UvPCpageL is up to date as each opcode starts executing.  If the instruction buffer holds bytes from two pages then mint is set and uPCCrossL ← -1.  At end of instruction if (uPCCrossL and PC#0FF) then PC has crossed page as it was advanced in the instruction.  In such a case the buffer will need refill and the situation will be caught at the next IBDisp by means of mint.  If a trap such as stack overflow should happen after PC is advanced but before IBDisp then this case must be explicitly checked for}



StackOverflow:   {testing}
	Rx ← {0 -} SubovFXP, L2 ← 0{NotInCall}, GOTO[PuntFor2],	c1;

{**************************************************
PuntFor: 	{Punt without Back up}  {Rx=FXP#}{L2 odd  => set InCall bit}		
**************************************************}
{to finish an opcode simulate the fetch for the next one}

{i.e.  ibEmpty and PC=0 then 'UpdatePC' by (optionally: PCCrossL←true) and definitely: UvPCpageL ← UvPCpageL + 100h}

{     old punt would do : if (PCCrossL and PC#FF/FE) then inc UvPCpageL}
{     new punt will do : if (PCCrossL and PC=FF/FE) then dec UvPCpageL}

PuntFor:   Noop,	c1;
PuntFor2:	Ybus ← PC - PC16, PgCarryBr,	c2;
	TT ← 30{ibPtrMask}, Cin ← pc16, BRANCH[pcZero, pcNZero],	c3;

pcNZero:	Noop, GOTO[pntC2],	c1;

pcZero:	Ybus ← TT and ~ ErrnIBnStkp, ZeroBr{empty},	c1;
pntC2:	Noop, BRANCH[$, setCross],	c2;

{Pc}
{	GOTO[PUNT],	c3;
setCross:	uPCCrossL ← TT xor ~TT, GOTO[PUNT],	c3;
}

	{uPCCrossL ← 0,} GOTO[{newPc}PUNT],	c3;{not (ibEmpty and PC=0)}

setCross:
	TT ← TT + 0FF + 1,	c3;{ibEmpty and PC=0}
	UvPCpageL ← TT,	c1;
	uPCCrossL ← 0,	c2;{just in case -- old code always set it, wiping out the old value}
	GOTO[PUNT],	c3;
{Pc}

{**************************************************}
PUNT: 	{L2 odd  => set InCall bit  ELSE  set NoPush bit}		
{**************************************************}

	MAR ← S ← [rhS, S + 1], GOTO[RetCont9],	c1;
RetCont9:	MDR ← TOSH, BRANCH[$, RetCar9, 1],	c2;
	Noop,	c3;

	MAR ← S ← [rhS, S + 1],	c1;
	MDR ← TOS,  CANCELBR[$, 2], WriteOK,	c2;
	PV ← PV - 0A{flags-pvar},	c3;

pntNP:{Set NoPushReturn bit}

	MAR ← PV ← [rhPV, PV + 0], 	c1;
	Noop,	c2;
	Q{flags} ← MD{flags}, L2Disp,	c3;

pntNP1:	MAR ← PV ← [rhPV, PV + 0], BRANCH[$, pntInC, 0E],	c1;
	MDR ← Q{flags} or uFxNoPushReturn, GOTO[pntJ],	c2;
pntInC:	MDR ← Q{flags} or uFxInCall, GOTO[pntJ],	c2;
pntJ:	TT ← PC and 0FF,	c3;

{Store relative byte PC  = 2*[UvPCpageL-UvCL+(PC and 0FF)]+PC16}
{Pc}{UvPCpageL may be too advanced if uPCCrossL and (PC mod 256)=FF or FE}
{Pc}{if it IS too advanced then it gets decremented by 100h at {UnCross:} }

pntPC:
	Q ← UvCL,	c1;
	TT{PC-UvCL-1} ← TT - Q - 1, Xbus ← uPCCrossL, XRefBr,	c2;
Crossed:	Q ← UvPCpageL, BRANCH[pntNC, $],	c3;

{Pc}
pntC:{Optional click: uPCCross is true, so check for PC#00}

{option}	Ybus ← PC - 2{PC+2 just as good}, PgCarryBr{FirstWord?},	c1;
{option}	Q{bytePC} ← Q - 0FF - 1, BRANCH[Crossed{00}, ${FF}],	c2;
{option}{UnCross:}	uPCCrossL ← 0, {UvPCpageL corrected}	c3;
{Pc}

{	Q ← UvCL,	c1;
	TT{PC-UvCL-1} ← TT - Q - 1, Xbus ← uPCCrossL, XRefBr,	c2;
UnCross:	Q ← UvPCpageL, BRANCH[pntNC, $],	c3;

pntC:{Optional click: uPCCross is true, so check for PC#FF}

{option}	Ybus ← PC + 2, PgCarryBr{LastWord?},	c1;
{option}	Q{bytePC} ← Q + 0FF + 1, BRANCH[$, UnCross],	c2;
{option}	uPCCrossL ← 0, {UvPCpageL corrected}	c3;
}
pntNC:	TT{PC-UvCL+UvPCpageL} ← TT + Q + 1,	c1;
	TT{bytePC} ← TT + TT + PC16, CarryBr,	c2;
	PV ← PV + 5{FxPc - FxFlags}, BRANCH[$, PcNegError],	c3;

	MAR ← PV ← [rhPV, PV + 0],	c1;
	MDR{bytePC} ← TT{bytePC},	c2;
	TT{ESP} ← uStkLimO,	c3;

pntN:{store Next}

	MAR ← PV ← [rhPV, PV - 1], {pc = next or 1}	c1;
	MDR{next} ← S ← S + 1, CANCELBR[$, 2], WriteOK,	c2;
	PV ← PV - 04{0 - next}, {restore PV}	c3;

pntF:{make remaining stack Free}

	MAR ← S ← [rhS, S + 0], 	c1;
	MDR{next} ← uFreeStackBlock,	c2;
	TT{size} ← TT - S,	c3;

	MAR ← S ← [rhS, S + 1], 	c1;
	MDR{next} ← TT + nStkLimOffset, CANCELBR[$, 2], WriteOK,	c2;
	Noop{@@} {rhTT ←  INTERFACEspace},	c3;

{pntP:}{swap PV with memory in interface page}

{make subroutine %%%}{MidPunt called by RTN2 when  stack overflow}
pntP:	TT ← INTERFACEbasePage, GOTO[MidPunt2],	c1;
MidPunt:	TT ← INTERFACEbasePage, GOTO[MidPunt2],	c1;
MidPunt2:	TT ← TT LRot8,	c2;
	TT ← TT  + Rx{punt}, rhTT ←  INTERFACEspace,	c3;

	Map ← Q ← [rhTT,TT],	c1;
	Rx ← Rx -1,	c2;
	uuPV ← PV, TT ← rhTT ← MD,{ XRefBr,}	c3;

{%M	MAR ← [rhTT, Q + 0],	c1;
	MDR{next} ← PV, Rx ← Rx{punt}-1, ZeroBr{KeyFXP},	c2;
	PV ← MD, BRANCH[RTN2, RTN2K],	c3;
%M}

	MAR ← [rhTT, Q + 0],	c1;
	,	c2;
	Rx ← MD,	c3;

	MAR ← [rhTT, Q + 0],	c1;
	MDR{next} ← PV,	c2;
	PV ← Rx, GOTO[RTN2],	c3;

{exceptions:}

RetCar9:	S ← S +0FF + 1, CANCELBR[$, 1],	c3;
	MAR ← [rhS, S + 0], GOTO[RetCont9],	c1;

PcNegError:
	Q ← 126'd, GOTO[sink2],	c1;{MP9126}

{**************************************************}
RETURN: 		{3%  8 clicks}
{**************************************************}

	MAR ← Q{pAlink} ← [rhPV, PV - 9{alink-pvar}], CANCELBR[$, 0F],	c1, opcode[20'b];{10}
RetCont0:	TT{ivar} ← uIVar, BRANCH[$, RetCar0{smash PV}, 1],	c2;
	PV ← MD{aLink}, XLDisp, L1 ← 1{TT{S}},	c3;

rtI:{IVar}{if aLink is odd then the next fetch hits Flags instead of ivar}

	MAR ←  [rhPV, PV - 0B{IVar}], BRANCH[FastRet2, SlowRet, 2],	c1;
SlowRet:	Rx{alinkFlags} ← PV - 0B{flags-(pvar+1)},  CANCELBR[$, 2],	c2;
	STK{alinkFlags} ← Rx, PV{pClink} ← Q{pAlink} + 7+1{clink-alink},	c3;


{************ HARD RETURN is necessary? **************}
{	hardRet1 if self.alink#self.clink	}
{	hardRet2 if caller.usecnt>0	}
{	hardRet3 if caller.next is busy	}
{	   unless caller.next=ivar & self.blink.cnt=0	}
{*****************************************************}
{	hardRet3a if caller.next#ivar  &  caller.next#free	}
{	hardRet3b if self.blink.cnt>0  &  caller.next#free	}
{*****************************************************}

rthC:{clink - 1}

	{uuPV{pClink} ←} MAR ← PV ← [rhPV, PV + 0],	c1;
	Q{alink} ← Rx{alinkFlags} + 0A{pvar-flags},	c2;
	TT{clink} ← MD{clink},	c3;

rthF:{flags.usecnt - 2}

	rhRx ← nRhS,	c1;
	,	c2;
	,	c3;

	MAR ← [rhRx, Rx{alinkFlags}+0],	c1;
{RetCont4:}	Ybus ← Q{alink} xor TT{clink}, NZeroBr, rhTT ← nRhS,	c2;
	TT{flags} ← MD{flags}, BRANCH[$, hardRet1],	c3;

rthN:{next - 3}

	MAR ← Rx ← [rhRx, Rx + 4{next-flags}],	c1;
RetCont5:	Ybus← TT{flags} - 1, PgCarryBr{cnt>0?}, rhRx ← nRhS, BRANCH[$, RetCar5, 1],	c2;
	Rx{next} ← MD{next}, BRANCH[$, hardRet2],	c3;

rthT:{next stack block type free?}

	MAR ← Q{next} ← [rhRx, Rx{next} + 0],	c1;
	Noop, 	c2;
	Rx{block} ← MD{block},	c3;

rthBL:{blink}

sav0:	MAR ← PV{pBlink} ← [rhPV, PV - 1],	c1;
	Ybus ← Rx{block} xor uFreeStackBlock, ZeroBr{free}, CANCELBR[$, 2],	c2;
	TT{t3:blink} ← MD{blink}, L1{free}←0, BRANCH[free0, free1],	c3;

rthBLF:{blinkFlags}

free0:	MAR ← [rhTT, TT{t3:blink} + 0], GOTO[free2],	c1;
free1:	MAR ← [rhTT, TT{t3:blink} + 0], GOTO[free2],	c1;
free2:	Ybus ← uIVar xor Q{next}, ZeroBr, L1Disp{free},	c2;
	Q{t4:blinkFlags} ← MD{blinkFlags}, BRANCH[hardRet3a,$],	c3;

rthBF:{get bflags}

	MAR ← PV ← [rhPV, PV - 0A{bflags - blink}],	c1;
RetCont6:	Ybus ← 0 - Q{t4:blinkFlags}, PgCarryBr{cnt=0?}, L1Disp{free}, BRANCH[$, RetCar6, 1],	c2;
	Rx{bflags} ← MD{bflags}, BRANCH[hardRet3b, $],	c3;


{************ FREE FRAMES (basic and extension) ************}
rtfM:{misc}

	Ybus ← Rx{bflags} and uBfResidualRhmask, ZeroBr,	c1;
	Ybus ← 0 - Q{t4:blinkFlags}, PgCarryBr{cnt=0?}, BRANCH[rtSkip, $],	c2;
	PV ← uIVar,{treat BF as part of FX} CANCELBR[freeFx, 1],		c3;
rtSkip:		Rx{ivar} ← uIVar, BRANCH[$, freeBf],	c3;

nqnz:	MAR ← [rhTT, TT{t3:blink} + 0],	c1;
	MDR ← Q{blinkFlags} - 1,	c2;
	Noop, GOTO[freeFx],	c3;

{rtfBF: free basic frame}

freeBf:	MAR ← [rhRx, Rx{ivar} + 0],	c1;
	MDR ← uFreeStackBlock,	c2;
	TT{t3:blink} ← TT + 2,	c3;

	MAR ← [rhRx, Rx{ivar}+1],	c1;
	MDR ← TT{t3:blink} - Rx{uIVar}, CANCELBR[$, 2],WriteOK,	c2;
	Noop,	c3;

{rtfFX: free frame extension}{free from PV to ESP, then return to uuPV{alink}}

freeFx:	MAR ← PV ← [rhPV, PV + 0{bflags - bflags}],	c1;
	MDR ← uFreeStackBlock,	c2;
	TT{ESP} ← uESP,	c3;

	MAR ←  [rhPV, PV + 1],	c1;
	MDR ← TT{ESP} - PV, CANCELBR[$, 2],WriteOK,	c2;
	PV{destFX} ← STK{alinkFlags}{uRx{alinkFlags}}, GOTO[RTN2],	c3;


{************ Keyboard context switch ************}
RTN2K:	MAR ← [rhPV, PV + 4{FxNext}], L1 ← 1, GOTO[rtn22],	c1;

{************ RESTORE STATE of frame ************}
RTN2:	{return to frame pointed to by PV{points to flags}}{context switch here}
{************ ***********************************}

	MAR ← [rhPV, PV + 4{FxNext}], L1 ← 1,	c1;
rtn22:	rhTT ← nRhS, BRANCH[$, RetCar8, 1],	c2;
RetCont8:	TT{ESP} ← MD{next}, L1Disp{1},	c3;

{rtrS: check free stack block}

extend:	MAR ← [rhTT, TT{ESP} + 0], BRANCH[$, rtrFirst],	c1;
	uStkLimO ← Q{uStkLimO}, {skip on first iteration}	c2;
extend3:	Rx{block} ← MD{block},	c3;

	MAR ← [rhTT, TT{ESP} + 1],	c1;
	Ybus ← Rx{block} xor uFreeStackBlock, NZeroBr, CANCELBR[$, 2],	c2;
	Rx{size} ← MD{size}, BRANCH[$, notFree],	c3;

	{uESP ←} TT{ESP} ← TT{ESP} + Rx{size}, L1 ← 0,	c1;
	uESP ← TT,	c2;
	Q{uStkLimO} ← TT{ESP} - nStkLimOffset, GOTO[extend]	c3;

rtrFirst:	S ← TT{ESP}, GOTO[extend3],	c2;

{{rtrF: flags}}

{sufficient stack?}

notFree:	Noop, {PV unchanged, ready to overflow punt}	c1;
	Ybus ← S - Q{uStkLimO}, CarryBr{S >= limit},	c2;
	Rx ← SubovFXP, BRANCH[$, MidPunt],	c3;

	MAR ← PV ← [rhPV, PV + 0], L1Disp,	c1;
	Rx{pFlags} ← PV, rhRx ← nRhS, BRANCH[$, notFreeTrap],	c2;
	TT{flags} ← MD{flags},	c3;

	Xbus ← TT{flags} LRot8, XDisp,	c1;
	UvCL ← 0, L1 ← 0, DISP4[rtf, 0A],	c2;
	PV ← PV + 0A{pvar - flags}, GOTO[FastRet],	c3, at[0A, 10, rtf];

rtrNoP: {Other cases: turn off special bit, discard TOS, TOSH}

	Q{flagMask} ← ~ uFxNoPushReturn, GOTO[rtrFix],	c3, at[0B, 10, rtf];
	Q{flagMask} ← ~ uFxInCall, GOTO[rtrFix],	c3, at[0E, 10, rtf];
	Q{flagMask} ← ~ uFxInCall, GOTO[rtrFix],	c3, at[0F, 10, rtf];

rtrFix:	MAR ← [rhRx, Rx{pFlags} + 0],	c1;
	MDR ← TT{flags} and Q{flagMask},	c2;
	S ← S - 1,	c3;

	MAR ← [rhS, S], S ← S - 1,	c1;
	PV ← PV + 5{pc-flags}, CANCELBR[$, 2],	c2;
	TOS ← MD, L1Disp,	c3;

	MAR ← [rhS, S + 0], BRANCH[$, InCall, 0B],	c1;
	PV ← PV + 5{pvar-pc},  	c2;
	TOSH ← MD, GOTO[FastRet],	c3;

InCall:	S ← S -1,	c2;
	TOSH ← MD,	c3;

{(PC) get byte PC into PC and UvPCpageL for immediate storing}{UvCL = 0}

	MAR ← [rhPV, PV+0], Xbus ← 0, XC2npcDisp,	c1;
	PV ← PV + 5{pvar-pc}, BRANCH[ICwasO, ICwasE, 2],	c2;
ICwasE:	PC{pc} ← MD{pc}, GOTO[ICnowO], Cin ← pc16,	c3;
ICwasO:	PC{pc} ← MD{pc}, GOTO[ICnowO],	c3;

ICnowO:	PC ← (PC{bytePC} - 1{apply incs}) RShift1, SE ← 0, YDisp,	c1;
	Q ← PC{pc} and ~0FF, BRANCH[pcEv, pcOdd, 0E],	c2;
pcEv:	UvPCpageL ← Q, Cin←pc16, GOTO[preAPPLY],	c3;
pcOdd:	UvPCpageL ← Q, GOTO[preAPPLY],	c3;

preAPPLY:
	IBPtr ← 1,	c1;
	uPCCrossL ← 0,	c2;
	Xbus ← ib, GOTO[APPLY],	c3;

{************ Slow Exceptions ************}
hardRet1:	PV{pPvar} ← PV{pClink} +1, GOTO[hdRet],	c1;
hardRet2:	PV{pPvar} ← PV{pClink} +1, GOTO[hdRet],	c1;
hardRet3a:	PV{pPvar} ← PV{pBlink} +2, GOTO[hdRet],	c1;
hardRet3b:	PV{pPvar} ← PV{pBflags} +0C, GOTO[hdRet],	c1;

hdRet:	Rx ← 20'b, GOTO[ufn3],	c2;
{	Noop,	c3;
hardRet:	Noop, GOTO[ufn2], {cycle one break point}	c1;}


notFreeTrap:	Q ← 16'd, GOTO[sink1],	c3;{MP9016}

RetCar5:	Rx ← Rx +0FF + 1, CANCELBR[$, 1],	c3;
	MAR ← [rhRx, Rx + 0], GOTO[RetCont5],	c1;

RetCar6:	PV ← PV - 0FF -  1, CANCELBR[$, 1],	c3;
	MAR ← [rhPV, PV + 0], GOTO[RetCont6],	c1;

RetCar8:	PV ← PV +4{FxNext},	c3;
	MAR ← [rhPV, PV + 0],	c1;
	PV ← PV - 4, GOTO[RetCont8],	c2;


{************************************
	FAST RETURN:   PV{PVars},  S{next} if L1:2   TT{next} if L1:1	
*************************************}

{(A) get IVar}

FastRet:	MAR ← [rhPV, PV - 0B{pvar-IVar}], L1 ← 2{S:next},	c1;
FastRet2:	PV ← PV - 5{pvar-pc}, BRANCH[$, RetCar2, 1],	c2;
RetCont2:	STK ← TOSH, TOSH ← MD{ivar}, L1Disp,	c3;

{(PC) get byte PC (relative to code base)}

rtPC:	MAR ← [rhPV, PV+0], Xbus ← 0, XC2npcDisp, BRANCH[rtS, rtTT, 2],	c1;
rtS:	S ← S -1, BRANCH[wasO, wasE, 2], IB ← 6{constant used later},	c2;
rtTT:	S ← TT -1, BRANCH[wasO, wasE, 2], IB ← 6{constant used later},	c2;
wasE:	PC{PC} ← MD{PC}, GOTO[nowO], Cin ← pc16,	c3;
wasO:	PC{PC} ← MD{PC}, GOTO[nowO],	c3;

{(C) get UvCL, code base}

nowO:	MAR ← PV ← [rhPV, PV- 3{fn lo}], L0 ← L0.RetRedo,	c1;
	Ybus ← PC, PC ← PC RShift1, SE ← 0, YDisp, IBPtr ← 1, BRANCH[$, RetCar7, 1],	c2;
RetCont7:	TT{UvCL} ← MD{UvCL}, L3 ← 0E, BRANCH[beEven, beOdd, 0E],	c3;

{(C) get UvChighL, calulate virtual PC in TT}

beEven:	MAR ← Q ← [rhPV, PV + PC16{=1}], L1 ← L1.Ret, GOTO[jnRet],	c1;
beOdd:	MAR ← Q ← [rhPV, PV + 1], L1 ← L1.Ret, GOTO[jnRet],	c1;
jnRet:	UvCL ← TT, PV ← Q + ibNA{6} + 1{fn hi}, CANCELBR[$, 2],	c2;
	rhTT ← MD{UvChighL}, TT ← TT + PC,	c3;

{(MF) map and fetch with restored PC}

rtMF:	Map ← Q ← [rhTT, TT], L0 ← L0.RetRedo,	c1;
	TT ← TT and ~0FF, L2 ← L2.0,	c2;
	UvPCpageL ← TT, rhPC ← PC ← MD, ReadXRefBr,	c3;

{(F) fetch instructions with restored PC}

	MAR ← Q ← [rhPC, Q + 0], ReadBRANCH[RetMapX,$],	c1, at[L0.RetRedo,10,RMapFixCaller];
	uIVar ← TOSH, TT ← rhTT, L3Disp,	c2;
	IB ← MD, PC ← Q, UvChighL ← TT, BRANCH[rptr0, rptr1, 0E],	c3;

rptr0:	MAR ← [rhPC, PC + 1], IBPtr←0, L0←L0.NERefill, GOTO[retjoin],	c1; 
rptr1:	MAR ← [rhPC, PC + 1], IBPtr←1, L0←L0.NERefill, GOTO[retjoin],	c1;
retjoin:	TOSH ← STK, AlwaysIBDisp, DISP2[NoRCross],	c2;

{exceptions:}

RetMapX:	Rx ← PC, GOTO[RLMapFix],	c2;

RetFix:	uIVar ← TOSH, TT ← rhTT,	c1, at[L1.Ret,10,Fix];
	UvChighL ← TT, PC ← Q,	c2;
	TOSH ← STK,	c3;

	uPCCrossL ← 0, GOTO[NoMoreFix],	c1;

RetCar0:	PV ← PV - 9{alink-pvar},	c3;
	MAR ← Q ← [rhPV, PV + 0], GOTO[RetCont0],	c1;

RetCar2:	PV ← PV -6,	c3;
	MAR ← [rhPV, PV + 0],	c1;
	PV ← PV +6, GOTO[RetCont2],	c2;

RetCar7:	PV ← PV -0FF - 1, L3 ← 0E, BRANCH[rc7e, rc7o, 0E],	c3;
rc7e:	MAR ← [rhPV, PV + 0], GOTO[rc7],	c1;
rc7o:	MAR ← [rhPV, PV + 0], GOTO[rc7],	c1;
rc7:	L3Disp, GOTO[RetCont7],	c2;

	{ E N D }