{File name Kiku2MBlock.mc Description: Mesa Block Transfer op-codes Author: Jim Frandeen Created: January 30, 1981 Last edited by I. Yamaura: 1-Nov-84 10:33:10: Change for 2M word at {+++} Last edited by Amy Fasnacht: 11-Nov-83 14:31:58: Delete ClrIntErr at blGoDisabled 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, XwdDisp, c3; {+++ Change for 2M +++} blTestDestDirty: WLMFRet[L0.BLDest] {Return here from WLMapFix after we set dirty bit.} rhTT ← Q LRot0, DISP2[blSetDestDirty], c1; {+++ Change for 2M +++} 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,at[0,4,blSetDestDirty]; {+++ Change for 2M +++} Q ← T, CALL[WLMapFix], c2,at[2,4,blSetDestDirty]; {+++ Change for 2M +++} Q ← T, CALL[WLMapFix], c2,at[3,4,blSetDestDirty]; {+++ Change for 2M +++} blDestDirty: {Restore while we have a spare cycle in case we get to Update.} TT←uSourceHighSaveTemp,L1←L1.Forward,GOTO[blStart],c2,at[1,4,blSetDestDirty]; {+++ Change for 2M +++} 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; [] ← uWP, ZeroBr, BRANCH[$, blInterrupt], c2; blGoDisabled: 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;}