{File name MdbNewLisp.mc; DandeLion Interlisp Emulator - slow returns
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 0F, YDisp, c2;
DISP4[CvtFlags,1], c3;
TOS ← 00, GOTO[RFExit], c1, at[01,10,CvtFlags]; {00} {clean}
TOS ← 01, GOTO[RFExit], c1, at[03,10,CvtFlags]; {20} {dirty}
TOS ← 03, GOTO[RFExit], c1, at[05,10,CvtFlags]; {40} {vacant}
TOS ← 03, GOTO[RFExit], c1, at[07,10,CvtFlags]; {60} {vacant, dirty}
TOS ← 08, GOTO[RFExit], c1, at[09,10,CvtFlags]; {80} {ref}
TOS ← 0A, GOTO[RFExit], c1, at[0B,10,CvtFlags]; {A0} {vacant, ref}
TOS ← 09, GOTO[RFExit], c1, at[0D,10,CvtFlags]; {C0} {dirty, ref}
TOS ← 0F, GOTO[RFExit], c1, at[0F,10,CvtFlags]; {F0} {???}
RFExit: TOS ← TOS LRot12, IBDisp, L2 ← L2.0, GOTO[DNI.pc1], c2;
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 ~0E0, DISP4[wmf, 4], c2;
Rx ← Rx or 0, GOTO[wMap], c3, at[4, 10, wmf]; {clean}
Rx ← Rx or 80, GOTO[wMap], c3, at[0C,10,wmf]; {ref, clean}
Rx ← Rx or 0C0, GOTO[wMap], c3, at[5, 10, wmf]; {dirty --> dirty, ref}
Rx ← Rx or 0C0, GOTO[wMap], c3, at[0D,10,wmf]; {dirty, ref --> dirty, ref}
Rx ← Rx or 60, GOTO[wMap], c3, at[6, 10, wmf]; {vacant --> vacant, dirty}
Rx ← Rx or 0A0, GOTO[wMap], c3, at[0E,10,wmf]; {vacant, ref --> vacant, ref}
Rx ← Rx or 060, GOTO[wMap], c3, at[7, 10, wmf]; {vacant, dirty --> vacant, dirty}
Rx ← Rx or 0E0, GOTO[wMap], {reserved} c3, at[0F,10,wmf]; {?? - everything}
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 PCCrossL←true}
{ PCCrossL and PC#FF then updatepc}
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;
Noop, GOTO[PUNT], c3;
setCross: uPCCrossL ← TT xor ~TT, GOTO[PUNT], c3;
{**************************************************}
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;
pntPC:{Store relative byte PC = 2*[UvPCpageL-UvCL+(PC and 0FF)]+PC16}
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 }