{File name FixedBlock.mc
Description: Mesa Block Transfer opcodes
Author: Jim Frandeen
Created: January 30, 1981
Last edited Trow 17-Nov-87 20:15:35

Copyright (C) 1981, 1982, 1983, 1984, 1985, 1986, 1987 by Xerox Corporation.  All rights reserved.

Trow	17-Nov-87 20:15:00 Start to modify interrupt code.
Trow	22-Oct-87 17:32:29 Change XwdDisp to XdwDisp.
Trow	13-Oct-87 14:37:43 Reverse targets 1 and 2 of XwdDisp.
Fiala 15-May-86  9:58:36 Change for 4MB storage at blSetDestDirty.
Fiala 18-Apr-86  9:48:08 Deleted Checksum opcode (moved to CedarB0.mc and CedarMisc.mc
	with performance improvements); renamed file to "FixedBlock.mc".
Fiala, BJackson  4-Jun-85 18:30:57: Fix Checksum for count=0
Frandeen March 23, 1981  2:46 PM: Update comments and try out new coding conventions.
Frandeen March 16, 1981  11:42 AM: Add code to handle Checksum Misc opcode.
Frandeen February 25, 1981  3:02 PM: Major rewrite. The goddamn BlockEqual instructions
	are not at all like the BlockTransfer instructions. The code offset is on the top of the stack.
Frandeen February 24, 1981  10:50 PM: Fix the Zero Byte Page Carry Gotcha.
Frandeen February 21, 1981  3:23 AM: Major rewrite. BlockEqual is a two-byte opcode.
Frandeen February 17, 1981  11:10 PM: Change to check for zero count BEFORE we do any maps.
	Unfortunately, we get address fault otherwise.
}

{This module handles BlockTransfer and BlockEqual instructions.
For the Block instructions, L2 is used to call SaveBlockRegs. It is also used
to distinguish the opcodes as follows:

Inst.	L2	code	long	Block	Transfer
					
BLT	3	0	0	1	1
BLTC	B	1	0	1	1
BLEQ	2	0	0	1	0
BLEQC	A	1	0	1	0
BLTL	7	0	1	1	1
BLEQL	6	0	1	1	0
BLEQCL	E	1	1	1	0

After L2Disp:

	BRANCH[NotBlockTransferInstruction, BlockTransferInstruction, 0E],
	BRANCH[ShortInstruction, LongInstruction, 0B],	
	BRANCH[ZeroBase, CodeBase, 7],	}

Set[Transfer,0E];
Set[Block,0D];
Set[Long,0B];
Set[CodeBase,7];


{ SUBROUTINES }

{******************************************************************************************
	PopCount subroutine
	   L2Disp is pending on call.
******************************************************************************************}
	MacroDef[PopCountRet,at[#1,10,PopCountRet]];
	{Return depending on the two middle bits of L2:}
	Set[PopShortBlock,0B];	{x01x = 0B = short Block}
	Set[PopLongBlock,0F];	{x11x = 0F = long Block}
	Set[PopBLEQC,9];	{x00x = 9 = BLEQC (called with no disp)}
PopCount:
	TOS ← STK, pop, DISP4[PopCountRet,9],	c*;

{ BLOCK EQUAL INSTRUCTIONS }

{******************************************************************************************
	BLEQL  Block Equal Long  (sBLTE = KFCB 56B)
	   TOS = srcHi
	   STK = srcLow
	   STK-1 = count
	   STK-2 = destHi
	   STK-3 = destLow
We will treat this just like BlockTransferLong. This means that if we update the stack because we are interrupted, we will come back in with the operands reversed in the stack.
******************************************************************************************}
@BLEQL:	
at[6,8,BlockEqual]
	L ← ~ErrnIBnStkp, ULsave ← L, L2 ← BLEQL,	c1;
	rhT ← TOS {destHi} LRot0, CALL[SaveBlockRegs],	c2;
	{SaveBlockRegs subroutine here 	c3-c3}
at[BLEQL,10,SavebbRegsRet]
	T ← STK {destLow}, pop {count}, L2Disp, CALL[PopCount],	c1;
	{TOS ← STK, pop {srcHi}, GOTO[BLongSourceCommon],	c2;}

{******************************************************************************************
	BLEQCL  Block Equal Code Long 
	   TOS = offset of source from code
	   STK = count
	   STK-1 = destHi
	   STK-2 = destLow
******************************************************************************************}
@BLEQCL:
at[0,8,BlockEqual]
	L ← ~ErrnIBnStkp, ULsave ← L, L2 ← BLEQCL,	c1;
	Rx ← TOS {code offset}, CALL[SaveBlockRegs],	c2;
	{SaveBlockRegs subroutine here 	c3-c3}
at[BLEQCL,10,SavebbRegsRet]
	TOS ← STK {count}, pop {destHigh},	c1;
	rhT ← STK {destHigh}, pop{destLow}, {Continue next line}
	GOTO[BlockEqualCodeCommon],	c2;

{******************************************************************************************
	BLEQ  Block Equal  (sBLTE = KFCB 52B)
	   TOS = srcLow
	   STK = count
	   STK-1 = destLow
We will treat this just like BlockTransfer. This means that if we update the stack because we are interrupted, we will come back in with the operands reversed in the stack.
******************************************************************************************}
@BLEQ:	
at[2,8,BlockEqual],
	L ← ~ErrnIBnStkp, ULsave ← L, L2 ← BLEQ,	c1;
	TT ← rhTT {srcHi} ← UvMDS,CALL[SaveBlockRegs],	c2;
	{SaveBlockRegs subroutine here 	c3-c3}
	rhT ← UvMDS {dstHi}, {Continue next line}
at[BLEQ,10,SavebbRegsRet]
	push {destLow, now in stack}, GOTO[blShortSourceCommon],  	c1;


{******************************************************************************************
	BLEQC  Block Equal Code  (sBLTE = KFCB 54B)
	   TOS = offset of source from codebase
	   STK = count
	   STK-1 = destLow
******************************************************************************************}
@BLEQC:	
at[4,8,BlockEqual]
	L ← ~ErrnIBnStkp, ULsave ← L, L2 ← BLEQC,	c1;
	Rx ← TOS {code offset}, CALL[SaveBlockRegs],	c2;
	{SaveBlockRegs subroutine here 	c3-c3}
at[BLEQC,10,SavebbRegsRet]
	rhT ← UvMDS {dstHi}, {0 disp} CALL[PopCount], 	c1;
	{TOS ← STK {count}, pop {destLow},	c2;}
BlockEqualCodeCommon:
PopCountRet[PopBLEQC]
	TT ← rhTT ← UvChigh {srcHi},	c3;

	T ← STK {destLow}, pop, GOTO[blTestCount],	c1;

{ BLOCK TRANSFER INSTRUCTIONS }

{******************************************************************************************
	BLTL  Block Transfer Long
	   TOS = destHi
	   STK = destLow
	   STK-1 = count
	   STK-2 = srcHi
	   STK-3 = srcLow
******************************************************************************************}
@BLTL:	
opcode[353'b]
	L ← ~ErrnIBnStkp, ULsave ← L, L2 ← BLTL,	c1;
	rhT ← TOS {destHi} LRot0, CALL[SaveBlockRegs],	c2;
	{SaveBlockRegs subroutine here 	c3-c3}
at[BLTL,10,SavebbRegsRet]
	T ← STK {destLow}, pop {count}, L2Disp, CALL[PopCount],    	c1;
	{TOS ← STK {count}, pop{srcHi},	c2;}

blLongSourceCommon:
PopCountRet[PopLongBlock]
	TT ← rhTT ← STK {srcHi}, pop {srcLow}, GOTO[blPopSourceLow]	c3;

{******************************************************************************************
	BLTC  Block Transfer Code
	   TOS = destLow
	   STK = count
	   STK-1 = offset of source from codebase
******************************************************************************************}
@BLTC:	
opcode[354'b]
	L ← ~ErrnIBnStkp, ULsave ← L, L2 ← BLTC,	c1;
	TT ← rhTT {srcHi} ← UvChigh {dstHi}, CALL[SaveBlockRegs],	c2;
	{SaveBlockRegs subroutine here 	c3-c3}
	rhT ← UvMDS {dstHi}, {continue next line}
at[BLTC,10,SavebbRegsRet]
	push {destLow, now in stack}, GOTO[blShortSourceCommon],	c1;

{******************************************************************************************
	BLT  Block Transfer
	   TOS = destLow
	   STK = count
	   STK-1 = srcLow
******************************************************************************************}
@BLT:
opcode[352'b]
	L ← ~ErrnIBnStkp, ULsave ← L, L2 ← BLT,	c1;
	TT ← rhTT {srcHi} ← UvMDS, CALL[SaveBlockRegs],	c2;
	{SaveBlockRegs subroutine here 	c3-c3}
at[BLT,10,SavebbRegsRet]
	rhT ← UvMDS {dstHi}, push {destLow, now in stack},  	c1;
blShortSourceCommon:
	T ← STK {destLow}, pop {count}, L2Disp, CALL[PopCount],  	c2;

	{TOS ← STK {count}, pop {srcLow},	c3;}
blPopSourceLow:
PopCountRet[PopShortBlock]
	Rx ← STK {srcLow}, pop {next},  	c1;
blTestCount:
	[] ← TOS {count}, ZeroBr, CANCELBR[$,1],  	c2;
blTestOffset:
	L2Disp, BRANCH[$,blNullCount],  	c3;

blSaveStackP:
	uStackPSave ← L, BRANCH[blZeroOffset,blCodeOffset, CodeBase], 	c1;
blZeroOffset:
	Q ← 0, GOTO[blSaveOffset], 	c2;
blCodeOffset:
	Q ← UvC,	c2;
blSaveOffset:
	uSourceOffset ← Q, L1 ← L1w.Restore, GOTO[blMapSource],	c3;

blNullCount:
	{L2Disp is pending. Load L0 to return to BLTransferDone or BLCompareDone.
	Put one in TOS for TRUE in case this is BlockEqual. It doesn't matter which Restore
	entry we use so long as it is 3 cycles and we don't try to restore rhL. }
	TOS ← 1 {TRUE}, L0 ← BLEQfini, {continue next line}
	BRANCH[RestoreBlockRegsC3Initial, RestoreBlockRegsC3, Transfer],	c1;
	{Restore here	c2-c1};
blTransferDone:
at[BLTfini,10,RestoreCallers]
	TOS ← STK, pop, GOTO[blDone],	c2;
blCompareDone: {1 (TRUE) or 0 (FALSE) is in TOS.}
at[BLEQfini,10,RestoreCallers]
	{BlockCompare is a two-byte instruction.}
	PC ← PC + PC16, 	c2;
blDone:	Xbus ← uPCCross, XRefBr,	c3;

	PC ← PC + PC16, BRANCH[IBDispOnly,blSetInt],	c1;
blSetInt:	MesaIntRq, GOTO[NoWakeups {in Refill}],	c2;	
{NoWakeups:	
	GOTO[IgnoreInt]	,c3;}
{IgnoreInt:
	Noop	,c1;}
{IBDispOnly:
	IBDisp, GOTO[DISPNIonly]	,c2;}

{******************************************************************************************
Map source and dest virtual addresses
  Entry State:
	Registers have been saved by SaveBlockRegs and must be restored.
	All arguments have been removed from the stack except for the case of Checksum.
	In the case of Checksum, we must set Stack pointer to 1 before we exit.
	L1 = L1w.Restore: return address from RLMapFix or WLMapFix in case of trap.
	rhTT = TT = source virtual address high
	Rx = source virtual address low
	rhT = dest virtual address high
	T = dest virtual address low
	Q = source offset (0 if not Code operation, else UvC)
	TOS = count
******************************************************************************************}

{Map source real address into rhG, G. Test map for referenced. If not referenced,
update the map since we are about to read it.  We want to end up with the source VA
in rhTT,,Q in case of a trap on source.  Save rhTT (source high) and Rx (source low)
so that we can restore it later.  Set up L0 to return to BLMapDest if we call RLMapFix.}

blMapSource:
	Map ← Q ← [rhTT, Rx + Q], 	c1;
blMapSourcex:
	uSourceHighSave ← TT, PC ← Q, L0 ← L0.BLSource,	c2;
	G ← rhG ← MD, XRefBr, uSourceLowSave ← Rx, 	c3;


{Map dest real address into rhRx, Rx. We want to end up with the source VA
in rhTT,,Q in case of a trap on dest.  Return here from RLMapFix if we needed
to set the referenced bit.  Set up L0 to return to BLTestDestDirty if
BlockTransfer or BLTestDestReferenced if BlockEqual.}

blMapDest:
	Map ← [rhT, T], L2Disp, BRANCH[blSetSourceReferenced, blSourceMapOK],	c1, at[L0.BLSource, 10, RMapFixCaller];
blSourceMapOK:
	Q ← rhT, L0 ← L0.BLDestR, BRANCH[blMapDestRead, blMapDestWrite, Transfer],	c2;

{Come here for BlockTransfer to map the dest address for write.
If not dirty, we will have to fix the map since we are about to write it.}

blMapDestWrite:
	rhRx ← Rx ← MD, XdwDisp,			c3;

blTestDestDirty:
	{Return here from WLMapFix after we set dirty bit.}
	rhTT ← Q LRot0, DISP2[blSetDestDirty],	c1, at[L0.BLDest,10,WMapFixCaller];

blSetSourceReferenced:
	{Come here if source map must be fixed for referenced. 
	Q = virtual sourceLow. rhTT = virtual sourceHi. Set Rx to map data.
	L0 = L0.BLSource to return to BLMapDest above after we set referenced bit.
	L1 = L1w.restore = L1r.Restore to return to BLReadTrap in case of trap.}
	Rx ← G, CANCELBR[RLMapFix,0F],	c2;

blSetDestDirty:
	{Come here if dest map must be fixed for dirty. 
	Rx = map data. rhTT = virtual destHi. Set Q to virtual destLow.
	L0 = L0.BLDest for return to BLTestDestDirty after we set dirty bit.
	L1 = L1w.restore = L1r.restore to return to BLWriteTrap in case of trap.}
	Q ← T, CALL[WLMapFix],				c2, at[0, 4, blSetDestDirty];
{db}	Q ← T, CALL[WLMapFix],				c2, at[1, 4, blSetDestDirty];
	Q ← T, CALL[WLMapFix],				c2, at[3, 4, blSetDestDirty];
blDestDirty:
	{Restore while we have a spare cycle in case we get to Update.}
{db}	TT ← rhTT ← uSourceHighSave, GOTO[blStart],	c2, at[2, 4, blSetDestDirty];

blMapDestRead:	
	{Come here if Block Equal. Test dest for referenced. 
	If not referenced, we will have to fix the map since we are about to read it. }
	rhRx ← Rx ← MD, XRefBr, 	c3;
blTestDestReferenced:
at[L0.BLDestR,10,RMapFixCaller]
	{Return here from RLMapFix after we set dest referenced.}
	rhTT ← Q LRot0, BRANCH[blSetDestReferenced, blDestReferenced],	c1;
blSetDestReferenced:
	{Come here if dest map must be fixed for referenced. 
	Rx = map data. rhTT = virtual destHi. Set Q to virtual destLow.
	L0 = L0.BLDest for return to blTestDestReferenced after we set dirty bit.
	L1 = L1w.restore = L1r.Restore to return to blWriteTrap in case of trap.}
	Q ← T, CALL[RLMapFix],	c2;
blDestReferenced:
	{Restore while we have a spare cycle in case we get to Update.}
	TT ← rhTT ← uSourceHighSave, GOTO[blStart],	c2;

blReadTrap:
at[L1r.Restore,10,RFixForTrap]
	{Return here from RLMapFix in case of trap on either source or dest (if Block Equal).}
	stackP ← uStackPSave, {Continue next line}
	L0 ← restore.trap, GOTO[blRestoreBlockRegs],	c1;

blWriteTrap:
at[L1w.Restore,10,WFixForTrap]
	{Return here from WLMapFix in case of trap on dest.}
	stackP ← uStackPSave, L0 ← restore.trap,	c1;
blRestoreBlockRegs:
	{StackP has been restored from uStackPSave. Restore all other registers.
	Q = virtual address low. TT = virtual address high.}
	uFaultParm0 ← Q, push, CALL[RestoreBlockRegsC1],	c2;
	{Restore here. 	c3-c3}
at[restore.trap,10,RestoreCallers]
	{Restore TOS so VArhTT can save it again}
	TOS ← STK, GOTO[VArhTT],	c1;


{******************************************************************************************
Block inner loop
  Entry State:
	L1 = L1w.Restore: return address from RLMapFix or WLMapFix in case of trap.
	rhTT = source virtual address high 
	uSourceHighSave = source virtual address High
	PC = source virtual address low
	uSourceLowSave = source virtual address low
	rhG,,G = source real address high
	rhT = dest virtual address high
	T = dest virtual address low
	rhRx,,Rx = dest real address high
	TOS = count
Registers used:
	Q = words transferred
	L = source word read
******************************************************************************************}
blStart:
	L {words transferred} ← 0,  	c3;

	{Note that it is necessary to do the first memory reference separately.
	Unfortunately, we cannot use Q to add to the virtual address each time through the loop.
	When the low byte of the virtual address is zero, we will never get a page cross branch.
	This is the Zero Byte Page Cross Gotcha. }

	MAR ← G ← [rhG, PC+0],  	c1;
	Noop,				c2;
	PC ← MD {source}, L2Disp,	c3;

blFirstDest:
	MAR ←  Rx ← [rhRx, T + 0], {Continue next line}
	{Set L0 to return to BLTransferDone or BLCompareDone.}
	L0 ← BLEQfini, BRANCH[blReadNextDest, blWriteNextDest, Transfer],	c1;

	{Read next source word: high 10 bits from rhG,,G, low 8 bits from G + 1.}
blReadSource:
	MAR ← G ← [rhG, G + 1], MesaIntBr,  	c1;
	DISP2[blSourceCheck],	c2;
	PC ← MD {source}, L2Disp, GOTO[blNextDest],	c3, at[0,4,blSourceCheck];
	GOTO[blUpdate], {source page cross}		c3, at[2,4,blSourceCheck];
	GOTO[blUpdate], {interrupt}			c3, at[1,4,blSourceCheck];
	GOTO[blUpdate], {source page cross and interrupt}	c3, at[3,4,blSourceCheck];

blNextDest:
	{Send real address of dest: high 10 bits from rhRx,,Rx, low 8 bits from Rx + 1.}
	MAR ←  Rx ← [rhRx, Rx + 1], BRANCH[blReadNextDest, blWriteNextDest, Transfer],	c1;
blWriteNextDest:
	{Come here if BlockTransfer to store the source word in the dest address.}
	MDR {dest} ← PC {source}, TOS {count} ← TOS - 1, ZeroBr, DISP2[blDestWriteCheck],	c2;
blIncrementWordsTransferred:
	L {words transferred} ← L + 1, BRANCH[blReadSource, blCountZero],	c3, at[0,4,blDestWriteCheck];
	TOS {count} ← TOS + 1, CANCELBR[blUpdate,1],	c3, at[2,4,blDestWriteCheck];
blReadNextDest:
	{Come here if BlockEqual to compare the source word to the dest word.}
	Noop, BRANCH[blNoDestReadPageCross, blDestReadPageCross,1],	c2;
blDestReadPageCross:
	Noop, GOTO[blUpdate], {Dest page cross}	c3;
blNoDestReadPageCross:
	PC ← MD {source} xor PC {dest}, 	c3;

	[] ← PC, NZeroBr,	c1;
blDecrementCount:
	TOS {count} ← TOS - 1, ZeroBr, BRANCH[blIncrementWordsTransferred, blFalse],	c2;
blFalse:
	TOS ← 0 {false}, CANCELBR[RestoreBlockRegsC1,1],  	c3;
	{RestoreBlockRegs here. Return to blCompareDone.	c1-c1}

blCountZero:
	TOS ← 1 {TRUE}, {next line}
	GOTO[RestoreBlockRegsC3],	c1;
	{Return to blTransferDone or blCompareDone.	c2-c1}

{******************************************************************************************
blUpdate
	Come here if we got a source or dest page cross or an interrupt request.
	L1 = L1w.Restore: return address from RLMapFix or WLMapFix in case of trap.
	TT = rhTT =uSourceHighSave  source virtual address high
	uSourceLowSave = source virtual address low
	uSourceOffset =  0 if not code, UvC if code operation
	rhT = dest virtual address high
	T = dest virtual address low
	TOS = count
	L = number of words transferred
	uStackPSave = stack pointer at beginning of operation.
******************************************************************************************}
blUpdate:	
	T {new destLow} ← T {destLow} + L {words transferred}, {Continue next line}
	CarryBr, CANCELBR[$,0F],	c1;
blTestDestCarry:	
	Rx ← uSourceLowSave {srcLow}, {Continue next line}
	BRANCH[blNoDestCarry, blDestCarry],	c2;
blDestCarry:	
	Q ← rhT {destHi} + 1, LOOPHOLE[byteTiming],	c3;

	rhT ← Q LRot0, GOTO[blTestDestCarry], {delay 1 cycle}	c1;

blNoDestCarry:	
	Rx {sourceLow} ← Rx {sourceLow} + L {words transferred}, CarryBr,	c3;

blTestSourceCarry:
	L ← ~ErrnIBnStkp, {Continue next line}
	L2Disp, BRANCH[blUpdateStack, blSourceCarry], 	c1;

blSourceCarry:	
	TT ← TT {sourceHigh} + 1, CANCELBR[$,0F], 	c2;

	rhTT ← TT LRot0, GOTO[blTestSourceCarry], {delay 1 cycle}	c3;



{******************************************************************************************
If we must interrupt, we must save the state in the stack. This is messy
because BlockEqual and BlockTransfer are currently different. Current State:
	TT = rhTT = source virtual address high
	Rx = source virtual address low
	rhT = dest virtual address high
	T =  dest virtual address low
	TOS = count
	stack pointer points to next.
	This is the way the stack should look when we are done:

BLEQL	BLEQCL	BLEQ and BLEQC   
TOS = srcHi	TOS = srcLow	TOS = srcLow
STK = srcLow	STK = count	STK = count
STK-1 = count	STK-1 = destHi	STK-1 = destLow
STK-2 = destHi	STK-2 = destLow	
STK-3 = destLow	

BLTL	BLTC and BLT	   
TOS = destHi	TOS = destLow	
STK = destLow	STK = count	
STK-1 = count	STK-1 = srcLow	
STK-2 = srcHi		
STK-3 = srcLow	

We treat BLEQ just like BLT, and we treat BLEQL just like BLTL. This means that the operands will be reversed in the stack.
******************************************************************************************}

blUpdateStack:
	L2Disp, Q ← rhT {destHigh}, push {destLow/sourceLow}, DISP4[blStackFormat,0C], 	c2;
blSourceFirst:     {BlockTransfer}	
	STK ← Rx {sourceLow}, push {srcHi/count}, BRANCH[blShortSourceFirst,blLongSourceFirst, Long],  	c3, at[0F,10,blStackFormat];
blShortSourceFirst:
	L2Disp, GOTO[blStoreCount],	c1;
blLongSourceFirst:
	STK ← TT {sourceHi}, push {count}, L2Disp, GOTO[blStoreCount],	c1;
blDestFirst:     {BlockEqual}	
	STK ← T {destLow}, push {destHi/count}, at[0E,10,blStackFormat], BRANCH[blShortDestFirst,blLongDestFirst, Long],  	c3;
blShortDestFirst:
	L2Disp, GOTO[blStoreCount],	c1;
blLongDestFirst:
	STK ← Q {destHi}, push {count}, L2Disp, GOTO[blStoreCount],	c1;
blStoreCount:	
	STK ← TOS {count}, push {sourceLow/destLow}, L2Disp, BRANCH[blSourceLast, blDestLast, Transfer],	c2;
blSourceLast:     {BlockEqual}	
	STK ← Rx {sourceLow}, push {srcHi/next}, L2Disp, BRANCH[blShortSourceLast,blLongSourceLast, Long],  	c3;
blLongSourceLast:
	MesaIntBr, BRANCH[blStoreLongSourceHiLast, blTestInterrupt, CodeBase],	c1;
blStoreLongSourceHiLast:
	{Two extra words here to handle Block Equal Code Long. Not too bad.}
	STK ← TT {sourceHi}, CANCELBR[$,1], 	c2;
	Noop, 	c3;

blShortSourceLast:
	MesaIntBr , CANCELBR[blTestInterrupt,0F],	c1;
blDestLast:     {BlockTransfer}	
	STK ← T {destLow}, push {destHi/next}, BRANCH[blShortDestLast,blLongDestLast, Long],  	c3;
blShortDestLast:
	MesaIntBr, GOTO[blTestInterrupt],	c1;
blLongDestLast:
	STK ← Q {destHi}, MesaIntBr, 	c1;

{db ***** original code}
blTestInterrupt:
	{We came through here because the interrupt request was set or
	because we crossed a page boundary. If the interrupt request is
	not on, go back to start on the next page.}
	Q {sourceOffset} ← uSourceOffset, ClrIntErr, BRANCH[blNoInterrupt, blInterrupt], 	c2;
blNoInterrupt:
	{Restore the stack pointer the way it was when all arguments were removed.}
	stackP ← L, GOTO[blMapSource],	c3;
blInterrupt:
	[] ← uWP {wakeups pending}, ZeroBr,	c3;

	{Restore the stack pointer the way it was when all arguments were removed.
	We must have the original stack pointer in L when we get to TestCount.}
	stackP ← L, L ← uStackPSave, BRANCH[blTestWakeupsDisabled, blTestCount {none pending}],	c1;

blTestWakeupsDisabled:
	[] ← uWDC {wakeup disable count}, L0 ← restore.int, NZeroBr, 	c2;
	Noop, BRANCH[blDoInt {not disabled}, blMapSource {disabled}],	c3;

blDoInt:
	stackP ← uStackPSave, CALL[RestoreBlockRegsC1],	c1;
	{RestoreBlockRegs here. Return to bbInit:	c2-c2};
	{RestoreRRegsAndRhG here. Return to bbInit:	c1-c2};

	{Rx ← pInt, push,	c3, at[restore.int,10,RestoreCallers]};

	{TOS ← STK, pop, GOTO[SaveRegs],	c1;}
{db *****}





{db ***** new code
blTestInterrupt:
	{We came through here because the interrupt request was set or because we crossed a page boundary. If the interrupt request is not on, go back to start on the next page.}

	Q {sourceOffset} ← uSourceOffset, {ClrIntErr}, BRANCH[blNoInterrupt, blInterrupt], 	c2;

blNoInterrupt:
	{Restore the stack pointer the way it was when all arguments were removed.}

	stackP ← L, GOTO[blMapSource],								c3;

blInterrupt:
	[] ← uWP {wakeups pending}, ZeroBr,							c3;

	{Restore the stack pointer the way it was when all arguments were removed.  We must have the original stack pointer in L when we get to TestCount.}

	stackP ← L, L ← uStackPSave, BRANCH[blTestWakeupsDisabled, blTestCount {none pending}],	c1;

blTestWakeupsDisabled:
	[] ← uWDC {wakeup disable count}, L0 ← restore.int, NZeroBr, 				c2;
	Noop, BRANCH[blDoInt {not disabled}, blMapSource {disabled}],				c3;

blDoInt:
	stackP ← uStackPSave, CALL[RestoreBlockRegsC1],						c1;

	{RestoreBlockRegs here. Return to bbInit:	c2-c2};
	{RestoreRRegsAndRhG here. Return to bbInit:	c1-c2};

	{Rx ← pInt, push,									c3, at[restore.int,10,RestoreCallers]};

	{TOS ← STK, pop, GOTO[SaveRegs],							c1;}
db *****}