<> <> <> <<>> <> DIRECTORY Basics, BitBltOps, PrincOps; BitBltOpsImpl: PROGRAM IMPORTS Basics EXPORTS BitBltOps = BEGIN OPEN Basics; BitAddress: TYPE = PrincOps.BitAddress; BitBltInc: TYPE = RECORD[wVal, bitVal: INT, easy: BOOL]; -- easy if value MOD bitsPerWord = 0 nulBitAddress: BitAddress = [NIL, 0, 0]; srcAddr: BitAddress; -- address of source word at beginning of line dstAddr: BitAddress; -- address of destination word at beginning of line goodDstAddr: BitAddress; -- address of good destination word at beginning of line srcFunc: PrincOps.SrcFunc _ null; dstFunc: PrincOps.DstFunc _ null; srcInc, dstInc: BitBltInc; goingForward: BOOL _ TRUE; isThin: BOOL _ FALSE; -- true if dest is all within one word lMask: WORD; rMask: WORD; skew: NAT; dWidth, sWidth: INTEGER; -- width in words, including left & right partial words <> < 2 => left partial, dWidth-2 full words, and right partial>> < left partial, right partial only>> < entire destination within one word - special case as both masks need to be applied at the same time>> extraWordAtLeft, extraWordAtRight: BOOL; <> <> <> < dst.bit mod 20 then left else right>> isGray: BOOL _ FALSE; grayParam: PrincOps.GrayParm; grayWidth: BitBltInc; grayBump: BitBltInc; lastGray: [0..15); lastBBT: PrincOps.BitBltTable; InvalidBitBltCall: ERROR = CODE; HardCase: SIGNAL = CODE; BadValueForward: SIGNAL[ATOM] = CODE; BadValueBackward: SIGNAL[ATOM] = CODE; BadValueThin: SIGNAL = CODE; debugging: BOOL _ FALSE; BitBltOpCheck: PUBLIC PROC[bbt: PrincOps.BitBltTablePtr, goodDest: BitAddress] = { < NULL;>> grayHeightMod: CARDINAL; lineNum: CARDINAL _ DoSetup[bbt, goodDest]; -- which line do we start with IF isGray THEN grayHeightMod _ grayParam.heightMinusOne+1; WHILE lineNum IN [0..bbt.height) DO sInc: BitBltInc; IF goingForward THEN { IF isGray THEN BltOneLineForwardGrayCheck[] ELSE BltOneLineForwardCheck[] } ELSE BltOneLineBackward[]; lineNum _ lineNum + (IF goingForward THEN 1 ELSE -1); sInc _ IF bbt.flags.gray THEN IF (lineNum MOD grayHeightMod) = lastGray THEN grayBump ELSE grayWidth ELSE srcInc; IF sInc.easy AND dstInc.easy THEN { srcAddr _ BitBltAddrInc[srcAddr, sInc]; dstAddr _ BitBltAddrInc[dstAddr, dstInc]; goodDstAddr _ BitBltAddrInc[goodDstAddr, dstInc]; } ELSE RecomputeCheck[bbt, goodDest, sInc]; ENDLOOP; }; BitBltOp: PUBLIC PROC[bbt: PrincOps.BitBltTablePtr] = { < NULL;>> grayHeightMod: CARDINAL; lineNum: CARDINAL _ DoSetup[bbt, nulBitAddress]; -- which line do we start with IF isGray THEN grayHeightMod _ grayParam.heightMinusOne+1; WHILE lineNum IN [0..bbt.height) DO sInc: BitBltInc; IF goingForward THEN { IF isGray THEN BltOneLineForwardGray[] ELSE BltOneLineForward[] } ELSE BltOneLineBackwardCheck[]; lineNum _ lineNum + (IF goingForward THEN 1 ELSE -1); sInc _ IF bbt.flags.gray THEN IF (lineNum MOD grayHeightMod) = lastGray THEN grayBump ELSE grayWidth ELSE srcInc; IF sInc.easy AND dstInc.easy THEN { srcAddr _ BitBltAddrInc[srcAddr, sInc]; dstAddr _ BitBltAddrInc[dstAddr, dstInc]; } ELSE Recompute[bbt, sInc]; ENDLOOP; }; DoSetup: PROC[bbt: PrincOps.BitBltTablePtr, goodDest: BitAddress] RETURNS[lineNum: CARDINAL] = { <> IF bbt.flags.reserved # 0 OR bbt.reserved # 0 OR bbt.src.reserved # 0 OR bbt.dst.reserved # 0 OR <<(~bbt.flags.gray AND LOOPHOLE[bbt.srcDesc, INTEGER] = 0) OR -- bbt.dstBpl = 0 OR>> bbt.width > LAST[NAT] OR bbt.height > LAST[NAT] THEN ERROR InvalidBitBltCall; lastBBT _ bbt^; goingForward _ bbt.flags.direction = forward; srcFunc _ bbt.flags.srcFunc; dstFunc _ bbt.flags.dstFunc; srcAddr _ bbt.src; -- true for either real source or gray IF (isGray _ bbt.flags.gray) THEN { grayParam _ LOOPHOLE[bbt.srcDesc]; <> IF grayParam.widthMinusOne # 0 OR grayParam.reserved # 0 OR ~goingForward OR ~bbt.flags.disjoint OR bbt.dstBpl < 0 THEN ERROR InvalidBitBltCall; grayWidth.easy _ TRUE; grayWidth.wVal _ grayParam.widthMinusOne+1; grayWidth.bitVal _ grayWidth.wVal * bitsPerWord; grayBump.easy _ TRUE; grayBump.wVal _ -grayWidth.wVal*grayParam.heightMinusOne; grayBump.bitVal _ grayBump.wVal * bitsPerWord; } ELSE { srcI: INTEGER = LOOPHOLE[bbt.srcDesc]; IF srcI < 0 THEN srcInc.easy _ (-srcI MOD bitsPerWord) = 0 ELSE srcInc.easy _ (srcI MOD bitsPerWord) = 0; srcInc.wVal _ IF srcInc.easy THEN srcI/bitsPerWord ELSE -1; srcInc.bitVal _ srcI; IF (goingForward AND (srcInc.bitVal < 0 OR bbt.dstBpl < 0)) OR (~goingForward AND (srcInc.bitVal > 0 OR bbt.dstBpl > 0)) THEN ERROR InvalidBitBltCall; }; IF bbt.dstBpl < 0 THEN dstInc.easy _ (-bbt.dstBpl MOD bitsPerWord) = 0 ELSE dstInc.easy _ (bbt.dstBpl MOD bitsPerWord) = 0; dstInc.bitVal _ bbt.dstBpl; dstInc.wVal _ IF dstInc.easy THEN bbt.dstBpl/bitsPerWord ELSE -1; dstAddr _ bbt.dst; IF goodDest.word # NIL THEN goodDstAddr _ goodDest; IF isGray THEN lastGray _ IF goingForward THEN grayParam.heightMinusOne - grayParam.yOffset ELSE grayParam.yOffset; lineNum _ IF goingForward THEN 0 ELSE bbt.height-1; <<>> <> BEGIN bitSkew: INTEGER = srcAddr.bit - dstAddr.bit; finalDstInFirstLine: BitAddress _ BitBltAddrInc[bbt.dst, [wVal: -1, bitVal: bbt.width, easy: FALSE] ]; lMask _ LMask[dstAddr.bit]; rMask _ RMask[finalDstInFirstLine.bit]; skew _ IF bitSkew < 0 THEN bitsPerWord + bitSkew ELSE bitSkew; dWidth _ (dstAddr.bit + bbt.width + bitsPerWord - 1)/bitsPerWord; sWidth _ (srcAddr.bit + bbt.width + bitsPerWord - 1)/bitsPerWord; isThin _ (dWidth = 1); extraWordAtLeft _ extraWordAtRight _ FALSE; SELECT TRUE FROM sWidth > dWidth => extraWordAtLeft _ extraWordAtRight _ TRUE; sWidth < dWidth, sWidth = 1 => NULL; ENDCASE => IF bitSkew >= 0 THEN extraWordAtLeft _ TRUE ELSE extraWordAtRight _ TRUE; IF ~dstInc.easy AND dstInc.bitVal < 0 AND debugging THEN SIGNAL HardCase; END; }; BitBltAddrInc: PROC[base: BitAddress, offset: BitBltInc] RETURNS[ba: BitAddress] = { IF offset.easy THEN { ba.word _ LOOPHOLE[base.word + offset.wVal]; ba.bit _ base.bit; } ELSE { add: LongNumber = LOOPHOLE[base.bit + offset.bitVal]; wordPart: LongNumber _ LOOPHOLE[DoubleShift[add, -logBitsPerWord]]; <> <> <> wordPart.hi _ add.hi; -- makes negative if add was negative ba.word _ LOOPHOLE[base.word + LOOPHOLE[wordPart, INT]]; ba.bit _ BITAND[add.lo, bitsPerWord-1]; }; }; Recompute: PROC[bbt: PrincOps.BitBltTablePtr, sInc: BitBltInc] = { <> <<>> bitSkew: INTEGER; finalDstAddrInLine: BitAddress; srcAddr _ BitBltAddrInc[srcAddr, [wVal: sInc.wVal, bitVal: sInc.bitVal, easy: sInc.easy] ]; dstAddr _ BitBltAddrInc[dstAddr, [wVal: dstInc.wVal, bitVal: dstInc.bitVal, easy: dstInc.easy] ]; bitSkew _ srcAddr.bit - dstAddr.bit; skew _ IF bitSkew < 0 THEN bitsPerWord + bitSkew ELSE bitSkew; finalDstAddrInLine _ BitBltAddrInc[dstAddr, [wVal: -1, bitVal: bbt.width, easy: FALSE] ]; lMask _ LMask[dstAddr.bit]; rMask _ RMask[finalDstAddrInLine.bit]; dWidth _ (dstAddr.bit + bbt.width + bitsPerWord - 1)/bitsPerWord; sWidth _ (srcAddr.bit + bbt.width + bitsPerWord - 1)/bitsPerWord; isThin _ dWidth = 1; extraWordAtLeft _ extraWordAtRight _ FALSE; SELECT TRUE FROM sWidth > dWidth => extraWordAtLeft _ extraWordAtRight _ TRUE; sWidth < dWidth, sWidth = 1 => NULL; ENDCASE => IF bitSkew >= 0 THEN extraWordAtLeft _ TRUE ELSE extraWordAtRight _ TRUE; }; RecomputeCheck: PROC[ bbt: PrincOps.BitBltTablePtr, goodDestBase: BitAddress, sInc: BitBltInc] = { <> <<>> bitSkew: INTEGER; finalDstAddrInLine: BitAddress; srcAddr _ BitBltAddrInc[srcAddr, [wVal: sInc.wVal, bitVal: sInc.bitVal, easy: sInc.easy] ]; dstAddr _ BitBltAddrInc[dstAddr, [wVal: dstInc.wVal, bitVal: dstInc.bitVal, easy: dstInc.easy] ]; IF goodDestBase.word # NIL THEN goodDstAddr _ BitBltAddrInc[goodDstAddr, [wVal: dstInc.wVal, bitVal: dstInc.bitVal, easy: dstInc.easy] ]; bitSkew _ srcAddr.bit - dstAddr.bit; skew _ IF bitSkew < 0 THEN bitsPerWord - bitSkew ELSE bitSkew; finalDstAddrInLine _ BitBltAddrInc[dstAddr, [wVal: -1, bitVal: bbt.width, easy: FALSE] ]; lMask _ LMask[dstAddr.bit]; rMask _ RMask[finalDstAddrInLine.bit]; dWidth _ (dstAddr.bit + bbt.width + bitsPerWord - 1)/bitsPerWord; sWidth _ (srcAddr.bit + bbt.width + bitsPerWord - 1)/bitsPerWord; isThin _ dWidth = 1; extraWordAtLeft _ extraWordAtRight _ FALSE; SELECT TRUE FROM sWidth > dWidth => extraWordAtLeft _ extraWordAtRight _ TRUE; sWidth < dWidth, sWidth = 1 => NULL; ENDCASE => IF bitSkew >= 0 THEN extraWordAtLeft _ TRUE ELSE extraWordAtRight _ TRUE; }; BltOneLineForward: PROC = TRUSTED { src: LONG POINTER TO WORD _ LOOPHOLE[srcAddr.word]; dst: LONG POINTER TO WORD _ LOOPHOLE[dstAddr.word]; longSrc, shiftedSrc: Basics.LongNumber; dstValue, srcWord, curVal: WORD; width: INTEGER _ dWidth; longSrc.hi _ longSrc.lo _ src^; src _ LOOPHOLE[src+1]; IF extraWordAtLeft THEN { longSrc.lo _ src^; src _ LOOPHOLE[src+1]; }; [shiftedSrc, srcWord, dstValue] _ ComputeDstValue[longSrc, dst]; IF isThin THEN { doubleMask: WORD = Basics.BITAND[lMask, rMask]; curVal _ Basics.BITAND[dst^, Basics.BITNOT[doubleMask]]; dstValue _ Basics.BITAND[dstValue, doubleMask]; dst^ _ Basics.BITOR[curVal, dstValue]; RETURN; }; dstValue _ Basics.BITAND[dstValue, lMask]; -- at left side, so do left mask curVal _ Basics.BITAND[dst^, BITNOT[lMask]]; dstValue _ Basics.BITOR[curVal, dstValue]; DO -- store full words in this loop dst^ _ dstValue; dst _ LOOPHOLE[dst + 1]; longSrc _ Basics.SwapHalves[longSrc]; -- cheaper than shifting IF width <=2 THEN EXIT; longSrc.lo _ src^; [shiftedSrc, srcWord, dstValue] _ ComputeDstValue[longSrc, dst]; src _ LOOPHOLE[src+1]; width _ width - 1; ENDLOOP; IF extraWordAtRight THEN longSrc.lo _ src^; [shiftedSrc, srcWord, dstValue] _ ComputeDstValue[longSrc, dst]; curVal _ Basics.BITAND[dst^, Basics.BITNOT[rMask] ]; dstValue _ Basics.BITAND[dstValue, rMask]; -- at right side, so do right mask dst^ _ Basics.BITOR[curVal, dstValue]; }; BltOneLineForwardCheck: PROC = TRUSTED { src: LONG POINTER TO WORD _ LOOPHOLE[srcAddr.word]; dst: LONG POINTER TO WORD _ LOOPHOLE[dstAddr.word]; goodDst: LONG POINTER TO WORD _ LOOPHOLE[goodDstAddr.word]; longSrc, shiftedSrc: Basics.LongNumber; dstValue, srcWord, curVal: WORD; width: INTEGER _ dWidth; first: BOOL _ TRUE; longSrc.hi _ longSrc.lo _ src^; src _ LOOPHOLE[src+1]; IF extraWordAtLeft THEN { longSrc.lo _ src^; src _ LOOPHOLE[src+1]; }; [shiftedSrc, srcWord, dstValue] _ ComputeDstValue[longSrc, dst]; IF isThin THEN { doubleMask: WORD = Basics.BITAND[lMask, rMask]; goodMaskedVal: WORD = Basics.BITAND[goodDst^, doubleMask]; dstValue _ Basics.BITAND[dstValue, doubleMask]; IF dstValue # goodMaskedVal THEN SIGNAL BadValueThin; curVal _ Basics.BITAND[dst^, Basics.BITNOT[doubleMask]]; dst^ _ Basics.BITOR[curVal, dstValue]; RETURN; }; DO -- store full words in this loop IF first THEN { goodMaskedVal: WORD = Basics.BITAND[goodDst^, lMask]; dstValue _ Basics.BITAND[dstValue, lMask]; -- at left side, so do left mask curVal _ Basics.BITAND[dst^, BITNOT[lMask]]; IF dstValue # goodMaskedVal THEN SIGNAL BadValueForward[$left]; dstValue _ Basics.BITOR[curVal, dstValue]; first _ FALSE; } ELSE IF dstValue # goodDst^ THEN SIGNAL BadValueForward[$middle]; dst^ _ dstValue; dst _ LOOPHOLE[dst + 1]; goodDst _ LOOPHOLE[goodDst + 1]; longSrc _ Basics.SwapHalves[longSrc]; -- cheaper than shifting IF width <=2 THEN EXIT; longSrc.lo _ src^; src _ LOOPHOLE[src+1]; [shiftedSrc, srcWord, dstValue] _ ComputeDstValue[longSrc, dst]; width _ width - 1; ENDLOOP; IF extraWordAtRight THEN longSrc.lo _ src^; [shiftedSrc, srcWord, dstValue] _ ComputeDstValue[longSrc, dst]; <<>> BEGIN goodMaskedVal: WORD = Basics.BITAND[goodDst^, rMask]; curVal _ Basics.BITAND[dst^, Basics.BITNOT[rMask] ]; dstValue _ Basics.BITAND[dstValue, rMask]; -- at right side, so do right mask IF dstValue # goodMaskedVal THEN SIGNAL BadValueForward[$right]; dstValue _ Basics.BITOR[curVal, dstValue]; END; dst^ _ dstValue; }; BltOneLineForwardGray: PROC = TRUSTED { src: LONG POINTER TO WORD _ LOOPHOLE[srcAddr.word]; dst: LONG POINTER TO WORD _ LOOPHOLE[dstAddr.word]; longSrc, shiftedSrc: Basics.LongNumber; dstValue, srcWord, curVal: WORD; width: INTEGER _ dWidth; count: CARDINAL _ 0; longSrc.hi _ longSrc.lo _ src^; src _ GrayInc[src, count _ count + 1]; IF extraWordAtLeft THEN { longSrc.lo _ src^; src _ GrayInc[src, count _ count + 1]; }; [shiftedSrc, srcWord, dstValue] _ ComputeDstValue[longSrc, dst]; IF isThin THEN { doubleMask: WORD = Basics.BITAND[lMask, rMask]; curVal _ Basics.BITAND[dst^, Basics.BITNOT[doubleMask]]; dstValue _ Basics.BITAND[dstValue, doubleMask]; dst^ _ Basics.BITOR[curVal, dstValue]; RETURN; }; dstValue _ Basics.BITAND[dstValue, lMask]; -- at left side, so do left mask curVal _ Basics.BITAND[dst^, BITNOT[lMask]]; dstValue _ Basics.BITOR[curVal, dstValue]; DO -- store full words in this loop dst^ _ dstValue; dst _ LOOPHOLE[dst + 1]; longSrc _ Basics.SwapHalves[longSrc]; -- cheaper than shifting IF width <=2 THEN EXIT; longSrc.lo _ src^; [shiftedSrc, srcWord, dstValue] _ ComputeDstValue[longSrc, dst]; src _ GrayInc[src, count _ count + 1]; width _ width - 1; ENDLOOP; IF extraWordAtRight THEN longSrc.lo _ src^; [shiftedSrc, srcWord, dstValue] _ ComputeDstValue[longSrc, dst]; curVal _ Basics.BITAND[dst^, Basics.BITNOT[rMask] ]; dstValue _ Basics.BITAND[dstValue, rMask]; -- at right side, so do right mask dst^ _ Basics.BITOR[curVal, dstValue]; }; BltOneLineForwardGrayCheck: PROC = TRUSTED { src: LONG POINTER TO WORD _ LOOPHOLE[srcAddr.word]; dst: LONG POINTER TO WORD _ LOOPHOLE[dstAddr.word]; goodDst: LONG POINTER TO WORD _ LOOPHOLE[goodDstAddr.word]; longSrc, shiftedSrc: Basics.LongNumber; dstValue, srcWord, curVal: WORD; width: INTEGER _ dWidth; first: BOOL _ TRUE; count: CARDINAL _ 0; longSrc.hi _ longSrc.lo _ src^; src _ GrayInc[src, count _ count + 1]; IF extraWordAtLeft THEN { longSrc.lo _ src^; src _ GrayInc[src, count _ count + 1]; }; [shiftedSrc, srcWord, dstValue] _ ComputeDstValue[longSrc, dst]; IF isThin THEN { doubleMask: WORD = Basics.BITAND[lMask, rMask]; goodMaskedVal: WORD = Basics.BITAND[goodDst^, doubleMask]; dstValue _ Basics.BITAND[dstValue, doubleMask]; IF dstValue # goodMaskedVal THEN SIGNAL BadValueThin; curVal _ Basics.BITAND[dst^, Basics.BITNOT[doubleMask]]; dst^ _ Basics.BITOR[curVal, dstValue]; RETURN; }; DO -- store full words in this loop IF first THEN { goodMaskedVal: WORD = Basics.BITAND[goodDst^, lMask]; dstValue _ Basics.BITAND[dstValue, lMask]; -- at left side, so do left mask curVal _ Basics.BITAND[dst^, BITNOT[lMask]]; IF dstValue # goodMaskedVal THEN SIGNAL BadValueForward[$left]; dstValue _ Basics.BITOR[curVal, dstValue]; first _ FALSE; } ELSE IF dstValue # goodDst^ THEN SIGNAL BadValueForward[$middle]; dst^ _ dstValue; dst _ LOOPHOLE[dst + 1]; goodDst _ LOOPHOLE[goodDst + 1]; longSrc _ Basics.SwapHalves[longSrc]; -- cheaper than shifting IF width <=2 THEN EXIT; longSrc.lo _ src^; src _ GrayInc[src, count _ count + 1]; [shiftedSrc, srcWord, dstValue] _ ComputeDstValue[longSrc, dst]; width _ width - 1; ENDLOOP; <<>> IF extraWordAtRight THEN longSrc.lo _ src^; [shiftedSrc, srcWord, dstValue] _ ComputeDstValue[longSrc, dst]; <<>> BEGIN goodMaskedVal: WORD = Basics.BITAND[goodDst^, rMask]; curVal _ Basics.BITAND[dst^, Basics.BITNOT[rMask] ]; dstValue _ Basics.BITAND[dstValue, rMask]; -- at right side, so do right mask IF dstValue # goodMaskedVal THEN SIGNAL BadValueForward[$right]; dstValue _ Basics.BITOR[curVal, dstValue]; END; dst^ _ dstValue; }; BltOneLineBackward: PROC = TRUSTED { src: LONG POINTER TO WORD _ LOOPHOLE[srcAddr.word + sWidth - 1]; dst: LONG POINTER TO WORD _ LOOPHOLE[dstAddr.word + dWidth - 1]; longSrc, shiftedSrc: Basics.LongNumber; dstValue, srcWord, curVal: WORD; width: INTEGER _ dWidth; longSrc.hi _ longSrc.lo _ src^; src _ LOOPHOLE[src-1]; IF extraWordAtRight THEN { longSrc.hi _ src^; src _ LOOPHOLE[src-1]; }; [shiftedSrc, srcWord, dstValue] _ ComputeDstValue[longSrc, dst]; IF isThin THEN { doubleMask: WORD = Basics.BITAND[lMask, rMask]; curVal _ Basics.BITAND[dst^, Basics.BITNOT[doubleMask]]; dstValue _ Basics.BITAND[dstValue, doubleMask]; dst^ _ Basics.BITOR[curVal, dstValue]; RETURN; }; dstValue _ Basics.BITAND[dstValue, rMask]; -- at right side, so do right mask curVal _ Basics.BITAND[dst^, Basics.BITNOT[rMask] ]; dstValue _ Basics.BITOR[curVal, dstValue]; DO -- store full words in this loop dst^ _ dstValue; dst _ LOOPHOLE[dst-1]; longSrc _ Basics.SwapHalves[longSrc]; -- cheaper than shifting IF width <=2 THEN EXIT; longSrc.hi _ src^; src _ LOOPHOLE[src-1]; [shiftedSrc, srcWord, dstValue] _ ComputeDstValue[longSrc, dst]; width _ width - 1; ENDLOOP; <<>> IF extraWordAtLeft THEN longSrc.lo _ src^; [shiftedSrc, srcWord, dstValue] _ ComputeDstValue[longSrc, dst]; <<>> dstValue _ Basics.BITAND[dstValue, lMask]; -- at left side, so do left mask curVal _ Basics.BITAND[dst^, BITNOT[lMask]]; dst^ _ Basics.BITOR[curVal, dstValue]; }; BltOneLineBackwardCheck: PROC = TRUSTED { src: LONG POINTER TO WORD _ LOOPHOLE[srcAddr.word + sWidth - 1]; dst: LONG POINTER TO WORD _ LOOPHOLE[dstAddr.word + dWidth - 1]; goodDst: LONG POINTER TO WORD _ LOOPHOLE[goodDstAddr.word + dWidth - 1]; longSrc, shiftedSrc: Basics.LongNumber; dstValue, srcWord, curVal: WORD; width: INTEGER _ dWidth; first: BOOL _ TRUE; longSrc.hi _ longSrc.lo _ src^; src _ LOOPHOLE[src-1]; IF extraWordAtRight THEN { longSrc.hi _ src^; src _ LOOPHOLE[src-1]; }; [shiftedSrc, srcWord, dstValue] _ ComputeDstValue[longSrc, dst]; IF isThin THEN { doubleMask: WORD = Basics.BITAND[lMask, rMask]; goodMaskedVal: WORD = Basics.BITAND[goodDst^, doubleMask]; dstValue _ Basics.BITAND[dstValue, doubleMask]; IF dstValue # goodMaskedVal THEN SIGNAL BadValueThin; curVal _ Basics.BITAND[dst^, Basics.BITNOT[doubleMask]]; dst^ _ Basics.BITOR[curVal, dstValue]; RETURN; }; dstValue _ Basics.BITAND[dstValue, rMask]; -- at right side, so do right mask curVal _ Basics.BITAND[dst^, Basics.BITNOT[rMask] ]; DO -- store full words in this loop IF first THEN { goodMaskedVal: WORD = Basics.BITAND[goodDst^, rMask]; IF dstValue # goodMaskedVal THEN SIGNAL BadValueBackward[$right]; dstValue _ Basics.BITOR[curVal, dstValue]; first _ FALSE; } ELSE IF dstValue # goodDst^ THEN SIGNAL BadValueBackward[$middle]; dst^ _ dstValue; dst _ LOOPHOLE[dst-1]; goodDst _ LOOPHOLE[goodDst-1]; longSrc _ Basics.SwapHalves[longSrc]; -- cheaper than shifting IF width <=2 THEN EXIT; longSrc.hi _ src^; src _ LOOPHOLE[src-1]; [shiftedSrc, srcWord, dstValue] _ ComputeDstValue[longSrc, dst]; width _ width - 1; ENDLOOP; IF extraWordAtLeft THEN longSrc.lo _ src^; [shiftedSrc, srcWord, dstValue] _ ComputeDstValue[longSrc, dst]; BEGIN goodMaskedVal: WORD = Basics.BITAND[goodDst^, lMask]; curVal _ Basics.BITAND[dst^, BITNOT[lMask]]; dstValue _ Basics.BITAND[dstValue, lMask]; -- at left side, so do left mask IF dstValue # goodMaskedVal THEN SIGNAL BadValueBackward[$left]; dstValue _ Basics.BITOR[curVal, dstValue]; END; dst^ _ dstValue; }; ComputeDstValue: PROC[longSrc: Basics.LongNumber, dst: LONG POINTER TO WORD] RETURNS[shiftedSrc: Basics.LongNumber, srcWord, dstValue: WORD] = { shiftedSrc _ Basics.DoubleShiftLeft[longSrc, skew]; srcWord _ shiftedSrc.hi; IF srcFunc = complement THEN srcWord _ Basics.BITNOT[srcWord]; dstValue _ SELECT dstFunc FROM null => srcWord, and => Basics.BITAND[srcWord, dst^], or => Basics.BITOR[srcWord, dst^], xor =>Basics.BITXOR[srcWord, dst^], ENDCASE => ERROR InvalidBitBltCall; }; GrayInc: PROC[src: LONG POINTER TO WORD, count: INT] RETURNS[LONG POINTER TO WORD] = { inc: INT; IF grayWidth.wVal = 1 THEN RETURN[src] -- special case ELSE inc _ count MOD grayWidth.wVal; RETURN[LOOPHOLE[src+inc]]; }; LMask: PROC[bitNum: [0..bitsPerWord)] RETURNS[WORD] = { SELECT bitNum FROM 0 => RETURN[177777B]; 1 => RETURN[ 77777B]; 2 => RETURN[ 37777B]; 3 => RETURN[ 17777B]; 4 => RETURN[ 7777B]; 5 => RETURN[ 3777B]; 6 => RETURN[ 1777B]; 7 => RETURN[ 777B]; 8 => RETURN[ 377B]; 9 => RETURN[ 177B]; 10 => RETURN[ 77B]; 11 => RETURN[ 37B]; 12 => RETURN[ 17B]; 13 => RETURN[ 7B]; 14 => RETURN[ 3B]; 15 => RETURN[ 1B]; ENDCASE => ERROR InvalidBitBltCall; }; RMask: PROC[bitNum: [0..bitsPerWord)] RETURNS[WORD] = { SELECT bitNum FROM 0 => RETURN[177777B]; -- really bit 16 ENDCASE => RETURN[BITNOT[LMask[bitNum]] ]; }; END.