{ Block.mc, HGM,  4-Nov-84  2:58:09, Patch for Dicentra Interupts

File name Block.mc
Description: Mesa Block Transfer op-codes
Author: Jim Frandeen
Created: January 30, 1981
Last edited by Daniels: 15-Jun-83 17:24:43: New instruction set
Last edited by Amy Fasnacht: 12-Jan-83 17:32:20: Move ClrIntErr away from stack instructions
Last edited by Amy Fasnacht: 22-Dec-82 10:29:02: Add BLTLR
Last edited by Jim Frandeen: January 13, 1982  3:42 PM: Fix Checksum to decrement stack when count is zero.
Sandman:  November 2, 1981  2:30 PM: Integrate into new instruction set.
Last edited by Amy Fasnacht: July 7, 1981  8:22 AM: Revision to provide for the BlockEqual parameters to be in the same order as the BlockTransfer parameters.
Last edited by Jim Frandeen: March 23, 1981  2:46 PM: Update comments and try out new coding conventions.
Last edited by Jim Frandeen: March 16, 1981  11:42 AM: Add code to handle Checksum Misc opcode.
Last edited by Jim 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.
Last edited by Jim Frandeen: February 24, 1981  10:50 PM: Fix the Zero Byte Page Carry Gotcha.
Last edited by Jim Frandeen: February 21, 1981  3:23 AM: Major rewrite. BlockEqual is a two-byte opcode.
Last edited by Jim 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
BLTCL	F	1	1	1	1
BLTL	7	0	1	1	1
BLEL	6	0	1	1	0
BLECL	E	1	1	1	0
CKSUM	4	0	1	0	0
BLTLR	5	0	1	0	1

After L2Disp:

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

Set[Transfer,0E];
Set[Block,0D];
Set[Long,0B];
Set[CodeBase,7];
Set[L1.Forward, 0];
Set[L1.Reverse, 0F];

{ 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[PopChecksum,0D];	{x10x = 0D = checksum}
	Set[PopBLEQC,9];	{x00x = 9 = BLEQC (called with no disp)}
PopCount:
	TOS ← STK, pop, DISP4[PopCountRet,9],	c*;


{******************************************************************************************
	Checksum
	   TOS = uStack5 = sourceHi
	   STK = uStack4 = = sourceLow
	   STK-1 = uStack3 = count
	   STK-2 = uStack2 = sum
We set up source and dest to be the same thing because this works out easiest when mapping.
******************************************************************************************}
@CKSUM:	
at[0A,10,ESC2n]
	L ← ~ErrnIBnStkp, ULsave ← L, L2 ← CKSUM,	c1;
	rhT {destHi} ← uStack5 {sourceHi}, CALL[SaveBlockRegs],	c2;
	{SaveBlockRegs subroutine here 	c3-c3}
at[CKSUM,10,SavebbRegsRet]
	Rx {sourceLow} ← uStack4 {sourceLow},  	c1;
	TOS ← uStack3 {count}, ZeroBr, L0 ← BLEQfini,	c2;
	TT ← rhTT {sourceHi} ← uStack5 {sourceHi}, {Next line}
	BRANCH[$, blNullChecksum],	c3;

	T ← STK{destLow}, pop{count}, GOTO[blTestCount],	c1;

blNullChecksum:
	TOS ← uStack2 {return sum in TOS}, 	c1;
	stackP ← 1 {one thing (sum) left on the stack}, CALL[RestoreBlockRegsC2],	c2;
	{RestoreBlockRegs here. Return to blChecksumDone	c3-c1};

	
{ BLOCK EQUAL INSTRUCTIONS }

{******************************************************************************************
	BLEL  Block Equal Long
	   TOS = destHi
	   STK = destLow
	   STK-1 = count
	   STK-2 = srcHi
	   STK-3 = srcLow
******************************************************************************************}
@BLEL:	
at[8,10,ESC2n]
	L ← ~ErrnIBnStkp, ULsave ← L, L2 ← BLEL,	c1;
	rhT ← TOS {destHi} LRot0, CALL[SaveBlockRegs],	c2;
	{SaveBlockRegs subroutine here 	c3-c3}
at[BLEL,10,SavebbRegsRet]
	T ← STK {destLow}, pop {count}, L2Disp, CALL[PopCount],	c1;
	{TOS ← STK, pop {srcHi}, GOTO[BLongSourceCommon],	c2;}

{******************************************************************************************
	BLECL  Block Equal Code Long 
	   TOS = destHi
	   STK = destLow
	   STK-1 = count
	   STK-2 = srcLow
******************************************************************************************}
@BLECL:
at[9,10,ESC2n]
	L ← ~ErrnIBnStkp, ULsave ← L, L2 ← BLECL,	c1;
	rhT ← TOS {destHi} LRot0, CALL[SaveBlockRegs],	c2;
	{SaveBlockRegs subroutine here 	c3-c3}
at[BLECL,10,SavebbRegsRet]
	TT ← rhTT ← UvChigh {srcHi},	c1;
blBlockEqualCodeCommon:
	T ← STK {count}, pop {count},	c2;
	TOS ← STK {count}, pop {offset}, GOTO[blPopSourceLow],	c3;


{ BLOCK TRANSFER INSTRUCTIONS }

{******************************************************************************************
	BLTLR  Block Transfer Long Reverse
	   TOS = destHi
	   STK = destLow
	   STK-1 = count
	   STK-2 = srcHi
	   STK-3 = srcLow
******************************************************************************************}

@BLTLR:	
at[7,10,ESC2n]
	L ← ~ErrnIBnStkp, ULsave ← L, L2 ← BLTLR,	c1;
	rhT ← TOS LRot0 {destHi}, CALL[SaveBlockRegs],	c2;
	{SaveBlockRegs subroutine here 	c3-c3}
at[BLTLR,10,SavebbRegsRet]
	G ← STK {destLow}, pop {count}, L2Disp, CALL[PopCount],	c1;

PopCountRet[PopChecksum]
	rhTT ← TT ← STK {srcHi}, pop {srcLow},	c3;

	Rx ← STK {srcLow}, pop {next},	c1;
	uStackPSave ← L,	c2;
	uDestLowSave ← G,	c3;

blAdjustRHRegs:
	Q ← TOS - 1, {count - 1}	c1;
	[] ← Rx + Q, CarryBr, L2 ← BLTLR,	c2;
	G ← uDestLowSave, BRANCH[blNoBankSrcCross, blBankSrcCross],	c3;

blNoBankSrcCross:
	uSourceHighSave ← TT, GOTO[blTestDestCross],	c1;
blBankSrcCross:
	uSourceHighSave ← TT, TT ← TT + 1,	c1;
blTestDestCross:
	G ← G + Q, CarryBr, L1 ← L1.Restore,	c2;
	T ← rhT, BRANCH[blNoBankDestCross, blBankDestCross],	c3;

blNoBankDestCross:
	uDestHighSave ← T, GOTO[blSetSrcHiRev],	c1;
blBankDestCross:
	uDestHighSave ← T, T ← T + 1,	c1;
blSetSrcHiRev:
	[] ← TOS, ZeroBr, L0 ← BLEQfini,	c2;
	rhT ← T LRot0, BRANCH[$, RestoreBlockRegsC1],	c3;

	T ← G,	c1;
	rhTT ← TT LRot0, GOTO[blSaveOffset],	c2;

{******************************************************************************************
	BLTL  Block Transfer Long
	   TOS = destHi
	   STK = destLow
	   STK-1 = count
	   STK-2 = srcHi
	   STK-3 = srcLow
******************************************************************************************}
@BLTL:	
opcode[364'b]
	L ← ~ErrnIBnStkp, ULsave ← L, L2 ← BLTL,	c1;
	rhT ← TOS {destHi} LRot0, push, CALL[SaveBLTRegs],	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[365'b]
	L ← ~ErrnIBnStkp, ULsave ← L, L2 ← BLTC,	c1;
	TT ← rhTT {srcHi} ← UvChigh {dstHi}, push, CALL[SaveBLTRegs],	c2;
	{SaveBlockRegs subroutine here 	c3-c3}
	rhT ← UvMDS {dstHi}, {continue next line}
at[BLTC,10,SavebbRegsRet]
	push {destLow, now in stack}, GOTO[blShortSourceCommon],	c1;

{******************************************************************************************
	BLTCL  Block Transfer Code Long
	   TOS = destHi
	   STK = destLow
	   STK-1 = count
	   STK-2 = offset of source from codebase
******************************************************************************************}
@BLTCL:	
opcode[366'b]
	L ← ~ErrnIBnStkp, ULsave ← L, L2 ← BLTCL,	c1;
	rhT ← TOS {destHi} LRot0, push, CALL[SaveBLTRegs],	c2;
	{SaveBlockRegs subroutine here 	c3-c3}
at[BLTCL,10,SavebbRegsRet]
	TT ← rhTT ← UvChigh {srcHi}, GOTO[blBlockEqualCodeCommon],	c1;

{******************************************************************************************
	BLT  Block Transfer
	   TOS = destLow
	   STK = count
	   STK-1 = srcLow
******************************************************************************************}
@BLT:
opcode[363'b]
	L ← ~ErrnIBnStkp, ULsave ← L, L2 ← BLT,	c1;
	TT ← rhTT {srcHi} ← UvMDS, push, CALL[SaveBLTRegs],	c2;
SaveBLTRegs:
	STK ← TOS, pop, CALL[SaveBlockRegsx],	c3;
	{SaveBlockRegsx subroutine here 	c1-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, 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[RestoreBlockRegsC3, RestoreBlockRegsC3Initial, 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.}
blChecksumDone: {sum is in TOS.}
blReverseTransferDone: {need to pop stack for transfer}
at[BLEQfini,10,RestoreCallers]
	{BlockCompare, BLTLR, and Checksum are two-byte instructions.}
	PC ← PC + PC16, L2Disp, 	c2;
blDone:	Xbus ← uPCCross, XRefBr, BRANCH[$, blReverseDone, Transfer],	c3;

	Noop, BRANCH[blNoInt, blSetInt],	c1;
blReverseDone:
	TOS ← STK, pop, BRANCH[blNoInt, blSetInt]	c1;
blSetInt:	PC ← PC + PC16, MesaIntRq, GOTO[NoWakeups {in Refill}],	c2;
blNoInt:	PC ← PC + PC16, 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 = L1.Restore: return address from RLMapFix or WLMapFix in case of trap.
	TT = source virtual address high
	Rx = source virtual address low
	rhT = dest virtual address high
	T = dest virtual address low (dest virt addr low + Q if BLTLR)
	Q = source offset (UvC if Code operation, TOS-1 if reverse transfer, else 0)
	TOS = count
	uDestHighSave = dest virt addr high of start of block for BLTLR only
	uDestLowSave = dest virt addr low of start of block for BLTLR only
	uSourceHighSave = source virt addr high of start of block for BLTLR only

******************************************************************************************}

blMapSource:
	{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 virtual address 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.}

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


blMapDest:
RLMFRet[L0.BLSource]
	{Map dest real address into rhRx, Rx. 
	We want to end up with the source virtual address 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.}

	Map ← [rhT, T], L2Disp, BRANCH[blSetSourceReferenced, blSourceMapOK, 0E],	c1;
blSourceMapOK:
	Q ← rhT, L0 ← L0.BLDestR, {Continue next line}
	BRANCH[blMapDestRead, blMapDestWrite, Transfer],	c2;
blMapDestWrite:
	{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.}
	rhRx ← Rx ← MD, XDirtyDisp,  	c3;

blTestDestDirty:
WLMFRet[L0.BLDest]
	{Return here from WLMapFix after we set dirty bit.}
	rhTT ← Q LRot0, BRANCH[blSetDestDirty, blDestDirty, 1],	c1;

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 = L1.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;

blDestDirty:
	{Restore while we have a spare cycle in case we get to Update.}
	TT ← uSourceHighSaveTemp, L1 ← L1.Forward, GOTO[blStart],	c2;

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:
RLMFRet[L0.BLDestR]
	{Return here from RLMapFix after we set dest referenced.}
	rhTT ← Q LRot0, {Continue next line}
	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 = L1.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 ← uSourceHighSaveTemp, L1 ← L1.Forward, GOTO[blStart],	c2;

blReadTrap:
at[L1.Restore,10,RLTrapFix]
	{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[L1.Restore,10,WTrapFix]
	{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 HiTT can save it again}
	TOS ← STK, GOTO[HiTT],	c1;


{******************************************************************************************
Block inner loop
  Entry State:
	L1 = L1.Restore: return address from RLMapFix or WLMapFix in case of trap.
	rhTT = source virtual address high 
	uSourceHighSaveTemp = 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, L0 ← BLEQfini, {this is reset later if Transfer}	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], L2Disp,  	c1;
	L2Disp, BRANCH[blFirstCksmOrRev, blFirstForward, Block],	c2;
blFirstForward:
	PC ← MD {source}, L2Disp, CANCELBR[blFirstDest, 0F],	c3;

blFirstCksmOrRev:
	PC ← MD {source}, BRANCH[blFirstChecksumWord, $, Transfer],	c3;

blFirstDestReverse:
	MAR ←  Rx ← [rhRx, T + 0], L1 ← L1.Reverse, GOTO[blWriteNextDest],	c1;

blFirstDest:
	{Set L0 to return from RestoreCallers}
	MAR ←  Rx ← [rhRx, T + 0], L0 ← BLEQfini, BRANCH[blReadNextDest, blWriteNextDest, Transfer],	c1;

	{Read next source word: high 10 bits from rhG,,G, low 8 bits from G + 1.}
blReadSourceRev:
	MAR ← G ← [rhG, G - 1], MesaIntBr, BRANCH[blCheckSource, blCountZero],  	c1;

blReadSource:
	MAR ← G ← [rhG, G + 1], MesaIntBr, BRANCH[blCheckSource, blCountZero],  	c1;
blCheckSource:
	L2Disp, DISP2[blSourceCheck],	c2;
	PC ← MD {source}, DISP4[ChksumOrRevOrOther, 0C],	c3, at[0,4,blSourceCheck];
	L1Disp, CANCELBR[blUpdate,0F], {source page cross}	c3, at[2,4,blSourceCheck];
	L1Disp, CANCELBR[blUpdate,0F], {interrupt}	c3, at[1,4,blSourceCheck];
	L1Disp, CANCELBR[blUpdate,0F], {source page cross and interrupt}	c3, at[3,4,blSourceCheck];

	{Send real address of dest: high 10 bits from rhRx,,Rx, low 8 bits from Rx + 1.}
	MAR ←  Rx ← [rhRx, Rx - 1], GOTO[blWriteNextDest], {reverse transfer}	c1, at[0D, 10, ChksumOrRevOrOther];

	MAR ←  Rx ← [rhRx, Rx + 1], GOTO[blReadNextDest],	c1, at[0E, 10, ChksumOrRevOrOther];
	MAR ←  Rx ← [rhRx, Rx + 1], GOTO[blWriteNextDest], {forward transfer}	c1, at[0F, 10, ChksumOrRevOrOther];

blWriteNextDest:
	{Come here if BlockTransfer to store the source word in the dest address.}
	MDR {dest} ← PC {source}, L2Disp, L ← L + 1, BRANCH[blNoDestWriteCross, blDestWriteCross, 1],	c2;
blNoDestWriteCross:
	TOS ← TOS - 1, ZeroBr, BRANCH[blReadSourceRev, blReadSource, Block]	c3;
blDestWriteCross:
	L ← L - 1, L1Disp, CANCELBR[blUpdate, 0F],	c3;
blReadNextDest:
	{Come here if BlockEqual to compare the source word to the dest word.}
	Noop, BRANCH[blNoDestReadPageCross, blDestReadPageCross,1],	c2;
blDestReadPageCross:
	L1Disp, GOTO[blUpdate], {Dest page cross}	c3;
blNoDestReadPageCross:
	PC ← MD {source} xor PC {dest}, 	c3;

	[] ← PC, NZeroBr,	c1;
blChecksumReturn:
	L ← L + 1, BRANCH[blDecCount, blFalse],	c2;
blFalse:
	TOS ← 0 {false}, CALL[RestoreBlockRegsC1],  	c3;
	{RestoreBlockRegs here. Return to blCompareDone.	c1-c1}

blDecCount:
	TOS ← TOS - 1, ZeroBr, GOTO[blReadSource],	c3;

blCountZero:
	TOS ← 1 {TRUE}, L2Disp, CANCELBR[$, 3],	c2;
	L2Disp, BRANCH[blChecksumCountZero, RestoreBlockRegsC1, Block],	c3;

blChecksumCountZero:
	[] ← Rx xor ~0, NZeroBr, BRANCH[$, RestoreRegs, Transfer],	c1;
	stackP ← TOS {1}, TOS ← uStack2 {sum}, BRANCH[blChecksumAllOnes, RestoreBlockRegsC2],	c2;
RestoreRegs:
	CANCELBR[RestoreBlockRegsC2, 1],	c2;

blChecksumAllOnes:
	TOS {sum} ← 0, CALL[RestoreBlockRegsC1],	c3;
	{Restore here. Return to blChecksumDone.	c1-c1}

{******************************************************************************************
ChecksumWord

The Pup checksum is a 16-bit, one's complement, add-and-cycle checksum computed over 
the 16-bit  words in the block. The checksum is initialized to zero and computed by repeated 
one's complement addition and left cycle. If the result is the ones-complement value 
"minus one" (177777B), it is converted to zero. 177777B is specifically defined to mean 
that the Pup carries no checksum.
******************************************************************************************}
blFirstChecksumWord:
	PC {next word to add to sum} ← PC LRot1, GOTO[blChecksum],	c1;
blNextChecksumWord:
	PC {next word to add to sum} ← PC LRot1, CANCELBR[blChecksum,0F],	c1, at[0C, 10, ChksumOrRevOrOther];
blChecksum:
	Rx {sum} ← uStack2 LRot1, L0 ← BLEQfini,	c2;
	Rx {sum} ← Rx + PC {next word}, CarryBr,	c3;

blTestChecksumCarry:
	uStack2 ← Rx {sum}, BRANCH[blChecksumReturn, blChecksumCarry],	c1;
blChecksumCarry:
	Rx {sum} ← Rx + 1,	c2;
	Noop, GOTO[blTestChecksumCarry],	c3;

{******************************************************************************************
blUpdate
	Come here if we got a source or dest page cross or an interrupt request.
	L1 = L1.Restore: return address from RLMapFix or WLMapFix in case of trap.
	TT = uSourceHighSaveTemp  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:	
	Rx ← uSourceLowSave, BRANCH[blUpdateForward, blUpdateReverse, 0E],	c1;
blUpdateForward:	
	T {destLow} ← T {destLow} + L {words transferred}, CarryBr,	c2;

blTestDestCarry:
	rhTT ← TT LRot0, BRANCH[blNoDestCarry, blDestCarry],	c3;
blDestCarry:
	Q ← rhT {destHi} + 1, LOOPHOLE[byteTiming],	c1;

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

blNoDestCarry:
	Rx {srcLow} ← Rx {srcLow} + L {words transferred}, CarryBr,	c1;

blTestSourceCarry:
	L ← ~ErrnIBnStkp, L2Disp, BRANCH[blUpdateStack, blSourceCarry],	c2;

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

blSetHiSource:
	rhTT ← TT LRot0, GOTO[blTestSourceCarry], {delay 1 cycle}	c1;

blUpdateReverse:
	rhTT ← TT ← uSourceHighSave,	c2;
	rhT ← uDestHighSave,	c3;

{From now on we pretend that this is BLTL.  L1 will tell us otherwise.}
	T ← uDestLowSave, L2 ← BLTL, GOTO[blTestSourceCarry],	c1;


{******************************************************************************************
If we must interrupt, we must save the state in the stack.
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:
	
BLTL and BLEL		BLTC, and BLT
TOS = destHi		TOS = destLow	
STK = destLow		STK = count	
STK-1 = count		STK-1 = srcLow	
STK-2 = srcHi		
STK-3 = srcLow

Checksum		BLECL, and BLTCL
TOS = srcHi		TOS = destHi
STK = srcLow		STK = destLow
STK-1 = count		STK-1 = count
STK-2 = sum		STK-2 = srcLow
	

******************************************************************************************}

blUpdateStack:
	Q ← rhT {destHi}, push {srcLow}, L2Disp, {Continue next line}
	DISP4[blStackFormat,9],	c3;
at[0D,10,blStackFormat]  {Checksum}
	stackP ← 3 {count}, L2Disp, CANCELBR[blStoreCountWait,0F],	c1;
at[0B,10,blStackFormat]  {Short}
	STK ← Rx {srcLow}, push {count}, L2Disp, {Continue next line}
	CANCELBR[blStoreCountWait,0F],	c1;
at[0F,10,blStackFormat]  {Long}
	STK ← Rx {srcLow}, push {srcHi/count}, {Continue next line}
	BRANCH[blStoreSourceHigh,blStoreCountWait,CodeBase],	c1;

blStoreSourceHigh:
	STK ← TT {srcHi}, push {count/next}, L2Disp,	c2;
blStoreCount:
	STK ← TOS {count}, push {destLow/srcLow}, L2Disp, {Continue}
	BRANCH[blChecksumSourceLow,blStoreDestLow,Block],	c3;
blStoreDestLow:
	STK ← T {destLow}, push{destHi/next},BRANCH[blShortDone,blStoreDestHi,Long],	c1;

blStoreCountWait:
	L2Disp,CANCELBR[blStoreCount,0F],	c2;

blStoreDestHi:
	STK ← Q {destHi}, GOTO[blCheckInterrupts],	c2;
blShortDone:
	GOTO[blCheckInterrupts],	c2;

blChecksumSourceLow:
	STK ← Rx {srcLow}, push {srcHi}, CANCELBR[$,0F],		c1;
	STK ← TT {srcHi},						c2;

blCheckInterrupts:
	[] ← uWDC, ZeroBr,						c3;
blDisableBranch:
	BRANCH[blDisabled, blNotDisabled],				c1;
	  
blDisabled:
	Q ← uSourceOffset, L1Disp,					c2;
	stackP ← L, BRANCH[blMapSource, blAdjustRHRegs, 0D],		c3;
	
blNotDisabled:  {We must wait another click until we can do ClrIntErr}
	CANCELBR[$, 0F],						c2;
	L0 ← restore.int,						c3;
	
	MesaIntBr,							c1;
	[] ← 1 {uWP}, ZeroBr, BRANCH[$, blInterrupt],			c2;
	CANCELBR[blDisableBranch, 1],					c3;
	
blInterrupt:
	ClrIntErr, BRANCH[$, blDisableBranch],				c3;
	
	stackP ← uStackPSave, CALL[RestoreBlockRegsC1],			c1;
	
	{This call to RestoreBlockRegs does not use the commented cycle numbers in BBSubs};
	{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;}