{
File name TextBlt.mc
Description: Mesa TextBlt op-code
Last edited by Jim Frandeen August 20, 1981 2:20 PM: Margin is a CARDINAL; Update MicaPos after call to BitBlt in case of page fault.
Last edited by Jim August 20, 1981 2:20 PM: Fix for new assembler.
Last edited by Jim Frandeen: July 21, 1981 10:50 AM: Test for Resolve before testing for Stop char.
Last edited by Jim Frandeen: July 7, 1981 11:06 AM: General rewrite to make it small and wonderful.
Last edited by Jim Frandeen: March 17, 1981 4:09 PM: Fix label bug: change tbFunction to tbFunction. Put one on XBus when calling CycleMask. Return with uStack6 in TOS.
Last edited by Jim Frandeen: March 16, 1981 2:14 PM: Bug fix: save MicaWidth instead of MicaPos at TestMargin. Change to call TextBltToBitBltEntry instead of LSEPNormEntry.
Last edited by Jim Frandeen: March 15, 1981 5:35 PM: Move definitions from Dandelion into TextBlt.
Last edited by Jim Frandeen: February 17, 1981 2:55 PM: Change to check for margin before function.
Last edited by Jim Frandeen: February 11, 1981 11:04 AM: use symbol to call SavebbRegs.
Author: Jim Frandeen
Created: December, 1980
}
{REGISTER USAGE:
NumberName
0VSholds the Virtual Address when calling SrcMapSpec in BitBlt.
TOSused by CycleMask to return cycled result.
1Ttemporary used by CycleMask.
VDtemporary used by DstVAMod subroutine
2TTtemporary
Used to hold Index parameter
3Ltemporary
Used to hold Last parameter.
TempBplused to hold BitPos when calling DstVAMod subroutine
4Gtemporary
SrcAUsed by SrcMapSpec to return real address
5PCUsed by ExtractByte to return value
6TempBtemporary used by DstVAMod subroutine
Rxused to hold character MicaPos
}

{SUBROUTINES }
{*****************************************************************************
Subroutine FetchVS
Fetch word pointed to by Virtual Address in VS and rhVS, offset by T.
Store UtbDstLo in UDstVALo to set up for DstVAMod subroutine.
Timing: 5 clicks
Called from cycle 3, returns to cycle 1
Returns thru L0

Input:
VS
(TOS) virtual address
rhVS
(rhMDS) virtual address (high order)
T
offset of virtual address

Output:
T
word pointed to by Virtual Address
SrcA
(G) real address page and word
rhSrcA
(rhG) real address rh
USrcValoSav
used to save VS
Q
real page and word
rhRet
tbMap (used to call SrcMapSpec)
*****************************************************************************}
MacroDef[FetchVSRet,at[#1,8,FetchVSRet]];

{Return values for FetchVS and ExtractByte Subroutines}
{0 = restore.int is reserved for use at tbFaultOrInt}
Set[FetchFlags, 1], {fetch RgFlags}
{2 = restore.pf is reserved for use at tbFaultOrInt}
Set[FetchEntry, 3], {fetch CharEntry}
Set[StoreCoord,4], {get address of Coord[Index]}
Set[FetchWidth, 5], {fetch width of character}
Set[FetchChar, 6], {fetch next character}

FetchFontData:
VS ← UtbFontBodyLo, c2;
rhVS ← UtbFontBodyHi,c3;
FetchVS:
VS ← VS + T, CarryBr,c1;
tbFetch:
T ← UtbDstLo, BRANCH[$, tbCarry],c2;
rhRet ← Fetch, CALL[SrcMapSpec],c3;

{SrcMapSpec subroutine here for 2 Clicks,c1-c3;}
{On return, SrcA and rhSrcA contain real address.}

SrcMapSpecRet[Fetch]
MAR ← [rhSrcA, SrcA + 0],c1;
UDstVALo ← T {UtbDstLo}, L0Disp,c2;
T ← MD, DISP3[FetchVSRet],c3;

tbCarry:
Q ← rhVS + 1 {Increment rh portion of VA}, LOOPHOLE[byteTiming],c3;
rhVS ← Q LRot0, GOTO[tbFetch],c1;
{*****************************************************************************
Subroutine ExtractByte
Extract byte from T depending on Index:
Index even => extract left byte
index odd => extract right byte
Timing: 2 cycles
Calling Sequence:
...L0 ← ,...
[] ← UtbIndex, XDisp, CALL[ExtractByte],c*;
Returns thru L0

Input:
T
word contains 2 bytes

Output:
PC
word contains left byte or right byte
*****************************************************************************}
MacroDef[ExtractByteRet,at[#1,8,ExtractByteRet]];
ExtractByte:
TT ← T LRot8, L0Disp, BRANCH[tbEvenChar, tbOddChar,0E],c*;

tbOddChar:
PC ← T and 0FF, DISP3[ExtractByteRet],c*;
tbEvenChar:
PC ← TT and 0FF, DISP3[ExtractByteRet],c*;



{*****************************************************************************
Subroutine TTplus256
Add 256 to TT
Timing: 1 cycle
Input:
TTword to be incremented by 256
Disp is pending for return
*****************************************************************************}
Set[OffsetPlus512,0];
Set[OffsetPlus256,1];
MacroDef[TTplus256Ret,at[#1,4,TTplus256Ret]];
TTplus256:
TT ← TT + 0FF + 1, DISP2[TTplus256Ret],c*;


{*****************************************************************************
Subroutine GgetsBitPos
Disp is pending for return
*****************************************************************************}
Set[Kern,1];
Set[Update,0];
MacroDef[GgetsBitPosRet,at[#1,4,GgetsBitPosRet]];
GgetsBitPos:
G ← UtbBitPos, DISP2[GgetsBitPosRet],c*;

{*****************************************************************************
Subroutine TTgetsSTK
Pop stack into TT and set rhType for TextBlt
Disp on Stack pointer is pending for return
*****************************************************************************}
MacroDef[TTgetsSTKRet,at[#1,10,TTgetsSTKRet]];
TTgetsSTK:
SavebbRegsRet[Savebb.TextBlt]
TT ← STK, pop, RET[TTgetsSTKRet],c*;


{*****************************************************************************
Begin TextBlt.
Come here from MISC on a Misc 15 opcode.
PC points to the byte code because BitBlt counts on this in case of a page fault.
Save R and RH registers. Move the parameters passed in the stack to other U registers.
If we need to call BitBlt, BitBlt will need to use the stack.
Input:
stackP = 5
uStack6 = ArgPtr => UtbArgPtr
uStack5 = Count => UtbCount
uStack4 = MicaPos => UtbMicaPos
uStack3 = BitPos => UtbBitPos
uStack2 = Index => UtbIndex
*****************************************************************************}
TextBlt:
at[0D,10,Misc0n]
ULsave ← L, L2 ← Savebb.TextBlt,c1;
T ← uStack6 {ArgPtr}, CALL[SavebbRegs],c2;

{SavebbRegs subroutine here for 2 2/3 Clicks,c3-c1;}
{Return to TTgetsSTK}

{TT ← STK {Count}, pop {MicaPos: stackP ← 4},c2;}
TTgetsSTKRet[0]
UtbCount ← TT {Count}, Xbus ← ErrnIBnStkp, XDisp, CALL[TTgetsSTK],c3;

{TT ← STK {MicaPos}, pop {BitPos stackP ← 3},c1;}
TTgetsSTKRet[0B] {1011 is one’s complement of stackP = 4}
UtbMicaPos ← TT {MicaPos}, {next line}
Xbus ← ErrnIBnStkp, XDisp, CALL[TTgetsSTK],c2;
{TT ← STK {BitPos}, pop {Index: stackP ← 2},c3;}
TTgetsSTKRet[0C] {1100 is one’s complement of stackP = 3}

UtbBitPos ← TT {BitPos}, {next line}
Xbus ← ErrnIBnStkp, XDisp, CALL[TTgetsSTK],c1;
{TT ← STK {Index}, pop {next: stackP ← 1},c2;}
TTgetsSTKRet[0D] {1101 is one’s complement of stackP = 2}
{Set L2 for SrcMapSpec subroutine in case of a page fault.}
UtbIndex ← TT {Index}, L2 ← sd.spec,c3;


{*****************************************************************************
Move TextBlt arguments pointed to by ArgPtr to U registers. The following loop loads U registers as follows:
60 junk
61 not touched
62 saved and restored
63 UtbFunction: arg word 0 = function
64 UtbLast: arg word 1 = Last
65 UtbTextLo: arg word 2 = TextLo
66 UtbTextHi: arg word 3 = TextHi
67 UtbFontLo: arg word 4 = FontLo
68 UtbFontHi: arg word 5 = FontHi
69 UtbDstLow: arg word 6 = DestLow
6A UtbDstHigh: arg word 7 = DestHigh
6B UtbDstBpl: arg word 8 = DestBpl
6C UtbMargin: arg word 9 = Margin
6D UtbSpace: arg word A = Space
6E UtbCoordLo: arg word B = CoordLo
6F arg word C = junk
In case of a page fault, we must be able to restore the stack and the registers.
Set rhType to return to us in case of a page fault or interrupt.
rhVS = MDS, so we don’t need to load it.
*****************************************************************************}

VS ← UtbArgPtr ← T {ArgPtr},c1;
rhType ← Type.TextBlt,c2;
rhRet ← MapArg, CALL[SrcMapSpec],c3;

{SrcMapSpec subroutine here for 2 Clicks,c1-c3;}
{On return, SrcA (G) and rhSrcA contain real address of TextBltArg.}

SrcMapSpecRet[MapArg]
L ← UtbFlags ,c1;
UFlags ← L {UtbFlags -- Set up for BitBlt},c2;
Rx ← uPMask2 {save u62, which will be wiped out},c3;

tbFetchArgLoop:
MAR ← [rhSrcA,SrcA ], SrcA ← SrcA + 1, NibCarryBr,c1;
Ybus ← SrcA+1, AltUaddr, BRANCH[$, tbFetchFontRecord, 2],c2;
tbParmBlock ← Rx, Rx ← MD, GOTO[tbFetchArgLoop],c3;



{*****************************************************************************
Fetch FontRecord data pointed to by FontLo,,FontHi into U registers.
The following loop loads U registers as follows:
50 not touched
51 not touched
52 junk
53 UtbFontBodyLo: FontRecord word 0 = FontBodyLo
54 UtbFontBodyHi: FontRecord word 1 = FontBodyHi
55 UtbFlagsLo: FontRecord word 2 = FlagsLo
56 UtbFlagsHi: FontRecord word 3 = FlagsHi
57 UtbHeight: FontRecord word 4 = Height
58 FontRecord word 5 = junk
59 FontRecord word 5 = not touched
5A FontRecord word 7 = not touched
5B FontRecord word 8 = not touched
5C FontRecord word 9 = not touched
5D FontRecord word A = not touched
5E FontRecord word B = not touched
5F FontRecord word C = not touched
*****************************************************************************}

tbFetchFontRecord:
rhRet ← MapFont {NOTE: this instruction follows AltUaddr, so beware of
any instruction with a U address here!},c3;

VS ← UtbFontLo, c1;
rhVS ← UtbFontHi,c2;
Rx ← UtbDstBpl, CALL[SrcMapSpec],c3;

{SrcMapSpec subroutine here for 2 Clicks,c1-c3;}
{On return SrcA and rhSrcA point to FontRecord.}

SrcMapSpecRet[MapFont]
tbFetchFontDataLoop:
MAR ← [rhSrcA,SrcA ], SrcA ← SrcA + 1,c1;
Ybus ← SrcA+1, YDisp, AltUaddr, CANCELBR[$,0],c2;
UtbFontData ← PC, PC ← MD, {next line}
BRANCH[tbFetchFontDataLoop,$,7],c3;

UDstBpl ← Rx {Prepare for BitBlt},c1;


{*****************************************************************************
Begin TextBlt loop.
We come through here for each character.
Subtract Index of current character from index of Last character.
If negative, then I’m done.
*****************************************************************************}
tbLoop:

L {Last} ← UtbLast,c2;
L ← L {Last} - TT {Index}, UtbIndex ← TT {Index}, NegBr,c3;

Xbus ← UtbFunction {test for resolve}, XDisp, BRANCH[$,tbFinished],c1;
Noop, BRANCH[tbFetchChar, tbResolve, 1],c2;

{*****************************************************************************
Come here if function is Resolve.
Call FetchVS to get real address of Coord[Index].
*****************************************************************************}
tbResolve:
VS ← UtbCoordLo,c3;

rhVS ← UrhMDSsave,c1;
T ← UtbIndex, L0 ← StoreCoord,c2;
{Put BitPos in L in preparation for write.}
L ← UtbBitPos, CALL[FetchVS],c3;

{FetchVS subroutine here for 5 clicks,c1-c3}
{On return, SrcA and rhSrcA contain real address of Coord[Index].}

FetchVSRet[StoreCoord]
MAR ← [rhSrcA, SrcA + 0],c1;
MDR ← L {bitPos}, c2;

tbFetchChar:
Rx ← UtbMicaPos {Prepare for tbTestMargin},c3;
{FetchText[Index]: word that contains next character.}
VS ← UtbTextLo, L0 ←FetchChar,c1;
rhVS ← UtbTextHi,c2;
T {offset} ← RShift1 TT {Index}, CALL[FetchVS],c3;

{FetchVS subroutine here for 5 clicks,c1-c3}
{On return, T contains word that contains next character.}

tbJustify:
FetchVSRet[FetchChar]
Xbus ← UtbIndex, XDisp, CALL[ExtractByte],c1;

{ExtractByte subroutine herec2-c3}
{On return, PC contains next character}

ExtractByteRet[FetchChar]
Rx ← UtbMicaPos {Prepare for tbTestMargin},c1;

tbFetchFlags: {Fetch RgFlags[char/8]. }
VS ← UtbFlagsLo, L0 ←FetchFlags,c2;
rhVS ← UtbFlagsHi,c3;

T ← LShift1 (PC {next char} and 0F8) {mask off low 3 bits},c1;
T ← T LRot12 {Char/8},c2;
{Prepare L for CycleMask below.}
L ← LShift1 (PC {next char} and 7), CALL[FetchVS],c3;

{FetchVS subroutine here for 5 clicks,c1-c3}

{*****************************************************************************
On return, T contains RgFlags[char/8]. Call CycleMask to right justify RgFlags.
We rotate RgFlags 2*(n+1), where n is the low 3 bits of Char. If n = 7, our Disp4 will cause a zero rotation.
Calling sequence to CycleMask:
T = data to be rotated (RgFlags)
TT = pre-rotated version of T
We must set INIA.11.
*****************************************************************************}

FetchVSRet[FetchFlags]
Ybus ← L {LShift1 (nextChar and 7)} + 2, YDisp, L2 ← maskRet.flags,c1;
TT ← LRot1 T {RgFlags}, Xbus ← 1, XDisp, DISP4[CycleMask],c2;

{CycleMask subroutine here for 1 click,c3-c2}
{On return, TOS contains RgFlags right justified. }

tbTestStop: {Dispatch on low order bit to test for Stop character.}
at[maskRet.flags,10,MaskRet]
UtbRgFlags ← TOS, L0 ← FetchWidth, YDisp,c3;

UDstBit ← 0 {set up for call to DstVAMod for BitBlt}, {next line}
BRANCH[tbFetchWidth,tbStopChar,0E],c1;
tbFetchWidth:
{Fetch width of character from FontBody+512[char/2]. }
TT ← LShift1 0FF, SE ← 1 {TT ← 511},c2;
T {Char/2} ← RShift1 PC {nextChar},c3;

T {offset} ← T {Char/2} + TT {511} + 1, CALL[FetchFontData],c1;

{FetchVS subroutine here for 5 2/3 clicks,c2-c3}
{On return, T contains word that contains width of character. }

FetchVSRet[FetchWidth]
Ybus ← L ← PC {nextChar}, YDisp, CALL[ExtractByte],c1;
{ExtractByte subroutine here,c2-c3}
{On return, PC contains width of Char, L contains char}

ExtractByteRet[FetchWidth]
TOS {height} ← UtbHeight,c1;
UHeight ← TOS {UtbHeight -- Prepare for BitBlt}, L0 ← FetchEntry,c2;
T ← LShift1 L {nextChar},c3;

{Fetch CharEntry[2*Char] to get offset into font table.}
L {Margin} ← UtbMargin {Prepare for TestMargin.} {next line},
CALL[FetchFontData],c1;

{FetchVS subroutine here for 5 2/3 clicks,c2-c3}

{*****************************************************************************
On return, T contains CharEntry[2*Char].
This contains the left and right kern bits and the offset of the character in the font table.
Start read of second word of CharEntry (Mica width).
Set Flags: direction: forward, disjoint: TRUE, disjointItems: TRUE, gray: FALSE, srcFunc: null, dstFunc: or
NOTE: For this to work, FontBody must be doubleword aligned;
otherwise we would have to worry about a page fault on the second word.
*****************************************************************************}
FetchVSRet[FetchEntry]
MAR ← [rhSrcA, SrcA + 1],c1;
UtbWidth ← PC, CANCELBR[$,0],c2;
TT {MicaWidth} ← MD, c3;

{TT = MicaWidth for this char.
If micaPos + MicaWidth > margin THEN GOTO tbMargin.}

tbTestMargin:
{Rx = UtbMicaPos
L = UtbMargin}
TOS {SrcHi} ← rhVS ← UtbFontBodyHi {Prepare for Display},c1;
TT {new MicaPos} ← Rx {MicaPos} + TT {MicaWidth}, L2 ← OffsetPlus256,c2;
L {we must write rB to use A bypass} ← L {Margin} - TT {MicaPos + MicaWidth}, CarryBr, c3;

{IF micaPos + MicaWidth > margin THEN GOTO tbMargin
Note that margin is a CARDINAL and can take up 16 bits,
so we must check for carry, not negative.}
Xbus ← UtbFunction, XDisp, BRANCH[tbMargin,$],c1;
UtbNewMicaPos ← TT, DISP2[tbFunction],c2;

{*****************************************************************************
Come here if function is Display.
L2 = OffsetPlus256
TOS = rhVS = UtbFontBodyHi
PC = UtbWidth = width of character
T = offset to FontTable in low 14 bits.
T = left kern in bit 0.
T = right kern in bit 1.

Set up parameters for BitBlt:
L2 = sd.spec
UDstBpl contains dstBpl
UWidth contains width of Char
UFlags contains flags
USrcBpl contains srcBpl (width of character)
UHeight contains height (from FontRecord)
UDstValo contains low order of dest BitAddress
UDstBit contains bit portion of dest BitAddress
USrcValo contains low order of source BitAddress
USrcBit contains bit portion of source BitAddress (Zero)
UrhVS and rhVS contain high order of source BitAddress
UrhVD and rhVD contain high order of dest BitAddress
*****************************************************************************}

{Calculate source address for BitBlt. Extract offset to FontTable from low 14 bits of first word of CharEntry.
Calculate address of entry for this Char in FontTable: FontBody + 640 + offset.}

tbDisplay:
at[0,4,tbFunction]
TT {offset} ← T {CharEntry} and u3FFF, {nextLine},
L2Disp, CALL[TTplus256],c3;
{TT {offset} ← TT {offset} + 0FF + 1 {256},c1;}
TTplus256Ret[OffsetPlus256]
TT {offset} ← TT {offset} + 80 {128}, {0 Disp} CALL[TTplus256],c2;

{TT {offset} ← TT {offset} + 0FF + 1 {256},c3;}

TTplus256Ret[OffsetPlus512]
L {Src} ← UtbFontBodyLo,c1;
L {Src} ← L {Src} + TT {offset}, CarryBr,c2;
tbTestFontCarry:
USrcVALo ← L {Src}, BRANCH[tbNoFontCarry, tbFontCarry],c3;
tbFontCarry:
TOS {SrcHi} ← TOS + 1,c1;
rhVS {SrcHi} ← TOS LRot0, GOTO[tbTestFontCarry],c2;

tbNoFontCarry:
UrhVS ← TOS {SrcHi}, TOS ← 0,c1;
USrcBit ← TOS {0}, TOS ← {8000} RShift1 TOS, SE ← 1,c2;

{Extract left kern and right kern bits.}
L {LKern} ← LRot1 T {Left kern in low order bit},c3;

TOS {RKern} ← (L LRot1) and TOS {8000},c1;
L {LKern} ← L {LKern} and 1 ,c2;

{Calculate Width as Width + left kern + right kern.}
PC {Width} ← PC {Width} + L {LKern},c3;

TOS {Width} ← PC {Width} + TOS {RKern}, L0 ← Kern,c1;
USrcBpl ← TOS {Width}, c2;
UWidth ← TOS {Width}, L0Disp, CALL[GgetsBitPos],c3;

{Calculate bitPos as bitPos - left kern.}
{G ← UtbBitPos,c1;}
GgetsBitPosRet[Kern]
L {BitPos} ← G {UtbBitPos} - L {LKern}, rhWho ← Dest, c2;
{*****************************************************************************
Calculate Dst address for BitBlt. Call DstVAMod to add BitPos to Dst address. Parameters must be set up as follows:
rhWhocaller
TempBplincrement for the destination address (L)
UDstValovirtual destination page and word,
set from UtbDstLo by FetchVA
UDstBitvirtual destination bit (set to 0)
UrhVDvirtual destination rh
*****************************************************************************}
T ← UtbDstHi, rhVD ← UtbDstHi,c3;

tbCalculateDst:
UrhVD ← T, CALL[DstVAMod],c1;

{DstVAMod subroutine here for 4 clicks,c2 - c1}
{On return, uDstValo has been updated by the number of words in BitPos.
TempB and UDstBit contain BitPos.
We must mask off the high order bits of BitPos from UDstBit.}

DstVAModRet[Dest]
TempB {BitPos} ← TempB and 0F, L2 ← sd.spec,c2;
UDstBit ← TempB, CALL[TextBltToBitBltEntry],c3;

{BitBlt runs here for lots of clicks.,c1 - c2}


{*****************************************************************************
Return here from BitBlt. L0 = restore.term.
Increment BitPos.
*****************************************************************************}
tbNextChar:
at[6,8,LSEPReturn]
T ← UtbWidth {width}, {0 disp}, CALL[GgetsBitPos],c3;

{G ← UtbBitPos GOTO[tbNextCharx],c1;}

{*****************************************************************************
Come here if function is Resolve.
*****************************************************************************}
at[2,4,tbFunction]
T ← UtbWidth {width}, {0 disp}, CALL[GgetsBitPos],c3;

{G ← UtbBitPos GOTO[tbNextCharx],c1;}

tbNextCharx:
GgetsBitPosRet[Update]
G {BitPos} ← G {BitPos} + T {Width}, {next line}
Xbus ← UtbRgFlags, XDisp, {Test for pad character (2 bit of RgFlags).}c2;
tbTestPad:
{Come here from tbCountPos or tbCountNotPos to delay 1 cycle.}
TT {Count} ← UtbCount, BRANCH[tbNoPad,tbPad,0D],c3;

tbPad:
T {Count} ← TT {Count} + 1,c1;
Xbus ← UtbFunction, XLDisp, {test low order bit: 1 if format}c2;

{Test for function = format. 0 => display, 1 => format, 2=> resolve.}
UtbCount ← T {Count}, TT ← TT {count-1}, NegBr, {next line}
BRANCH[$,tbNoPad],c3;

{Continue if function is not Format.
Increment BitPos by Space. If count <= 0, increment BitPos by one more.}

T ← UtbSpace, BRANCH[tbCountPos, tbCountNotPos],c1;
tbCountPos:
G {BitPos} ← G {BitPos} + T {Space}, GOTO[tbTestPad],c2;
tbCountNotPos:
G {BitPos} ← G {BitPos} + T {Space} + 1, GOTO[tbTestPad],c2;

tbNoPad:
L ← UtbNewMicaPos, CANCELBR[$,1],c1;
{Increment Index and continue loop.}
TT {Index} ← UtbIndex,c2;
UtbBitPos ← G {BitPos}, TT {Index} ← TT {Index} + 1, c3;

UtbMicaPos ← L {NewMicaPos}, GOTO[tbLoop],c1;


{*****************************************************************************
Come here if function is Format.
*****************************************************************************}
tbFormat:
at[1,4,tbFunction]
T ← UtbWidth {width}, {0 disp}, CALL[GgetsBitPos],c3;
{G ← UtbBitPos, GOTO[tbNextCharx],c1;}


tbFinished:
TOS ← 0 {normal}, CANCELBR[tbExit,3],c2;
tbMargin:
TOS ← 1 {margin}, CANCELBR[tbExit,3],c2;

tbStopChar:
TOS ← 2 {stop},c2;
{*****************************************************************************
Exit TextBlt. Add one to PC because this is a two-byte opcode.
Then exit through BBExit because we may need to fix up MesaIntRq.
*****************************************************************************}
tbExit:
PC ← UPCsave,c3;

PC ← PC + PC16, L0 ← restore.term,c1;
UPCsave ← PC, GOTO[tbRestoreStack],c2;

{*****************************************************************************
Come here from BitBlt if we get a page fault (L0 = restore.pf) or a request for an interrupt (L0 = restore.int).
Restore the Stack so that it will be set up when our opcode gets executed again.
Then go to RestoreRandRHRegs subroutine, which will return to the appropriate place in BitBlt.
*****************************************************************************}
tbFaultOrInt:
at[7,8,MoverhVToStkandRestore]
TOS ← UtbArgPtr, CALL[ExtractByte], {wait 2 cycles}c2;
{ExtractByte subroutine here.c3 - c1}

ExtractByteRet[restore.int]
{Return here from ExtractByte if L0 = interrupt}
uStack6 ← TOS, TT ← 0, GOTO[tbRestoreStackInt],c2;

{Return here from ExtractByte if L0 = page fault}
ExtractByteRet[restore.pf]
{*****************************************************************************
Subroutine RestoreStack
Timing: 3 2/3 cycles
Input:
T
value to place in Stack6
Restore the Stack with TextBlt parameters. We do this at completion, to process an interrupt, or to process a page fault.
We then exit to RestoreRandRHRegs, which will return to the appropriate place in BitBlt.
On completion, we must come here on c3.
On interrupt or page fault, we must come here on c2.
*****************************************************************************}
tbRestoreStack:
{finint}
uStack6 ← TOS, TT ← 0,c*; {c3c2}
tbRestoreStackInt:
stackP ← TT {0}, T ← UtbIndex,c*; {c1c3}
uStack2 ← T, push {stackP ← 1},c*; {c2c1}
T ←UtbBitPos, push {stackP ← 2},c*; {c3c2}

uStack3 ← T, push {stackP ← 3},c*; {c1c3}
T ← UtbMicaPos, push {stackP ← 4},c*; {c2c1}
uStack4 ← T, push {stackP ← 5},c*; {c3c2}

T ← UtbCount,c*; {c1c3}
uStack5 ← T, GOTO[RestoreRandRHRegs],c*; {c2c1}

{RestoreRandRHRegs here 2 1/3 cycles}{c3 - c3 c2 - c2}
{Continue at BBExit on c1 if finished (L0 = restore.term)}
{Continue at restore.pf on c3 if page fault (L0 = restore.pf)}
{Continue at restore.int on c3 if interrupt (L0 = restore.int)}

{END}