-- File: AltoMesaByteBlt.mesa, Last Edit: HGM November 12, 1979 5:47 PM -- Copyright Xerox Corporation 1979, 1980 DIRECTORY Stream: FROM "Stream" USING [Block], BitBltDefs: FROM "BitBltDefs" USING [BBptr, BBTable, BITBLT], InlineDefs: FROM "InlineDefs" USING [COPY], ByteBltDefs: FROM "ByteBltDefs"; -- EXPORTS AltoMesaByteBlt: PROGRAM IMPORTS BitBltDefs, InlineDefs EXPORTS ByteBltDefs = BEGIN StartIndexGreaterThanStopIndexPlusOne: PUBLIC ERROR = CODE; ByteBlt: PUBLIC PROCEDURE [to, from: Stream.Block] RETURNS [nBytes: CARDINAL] = BEGIN -- NB: to+from are RECORDs, not POINTERs to RECORDs, so we can update them toBytes, fromBytes: POINTER TO PACKED ARRAY [0..0) OF [0..377B); moved: CARDINAL _ 0; -- This check is necessary since subtracting CARDINALs gives big numbers IF to.startIndex>to.stopIndexPlusOne OR from.startIndex>from.stopIndexPlusOne THEN ERROR StartIndexGreaterThanStopIndexPlusOne; nBytes _ MIN[to.stopIndexPlusOne-to.startIndex,from.stopIndexPlusOne-from.startIndex]; IF nBytes=0 THEN RETURN; toBytes _ ShortenPointer[to.blockPointer]; fromBytes _ ShortenPointer[from.blockPointer]; -- move the first odd byte (if any) to be sure that to is word aligned IF (to.startIndex MOD 2)#0 THEN BEGIN toBytes[to.startIndex] _ fromBytes[from.startIndex]; moved _ 1; to.startIndex _ to.startIndex+1; from.startIndex _ from.startIndex+1; END; IF (from.startIndex MOD 2)=0 THEN -- fast case: both are word aligned BEGIN words: CARDINAL = (nBytes-moved)/2; InlineDefs.COPY[ to: toBytes+to.startIndex/2, from: fromBytes+from.startIndex/2, nwords: words ]; IF (moved+2*words)#nBytes THEN -- move the one and only remaining byte BEGIN toBytes[to.startIndex+2*words] _ fromBytes[from.startIndex+2*words]; END; END ELSE -- slow case: have to ripple things BEGIN lineWidth: CARDINAL = 16; -- words per scan line: controls interrupt latency bba: ARRAY [0..SIZE[BitBltDefs.BBTable]] OF WORD; -- NB: [...] gets us one extra bbt: BitBltDefs.BBptr _ LOOPHOLE[BASE[bba]]; lines, bytes, tail: CARDINAL; IF (LOOPHOLE[bbt,CARDINAL] MOD 2)#0 THEN bbt_bbt+1; -- EVEN word alignment bbt^ _ [ pad: 0, sourcealt: FALSE, destalt: FALSE, sourcetype: block, function: replace, unused: , dbca: toBytes+to.startIndex/2, dbmr: lineWidth, dlx: 0, dty: , dw: 16*lineWidth, dh: , sbca: fromBytes+from.startIndex/2, sbmr: lineWidth, slx: 8, sty: , gray0: , gray1: , gray2: , gray3: ]; -- BITBLT is not interruptable except at the end of each scan line, so we break things up into chunks in order to maintain reasonable interrupt latency for the IO devices. It takes about 200microsec to move 50 bytes with the display off. bytes _ nBytes-moved; tail _ bytes MOD (2*lineWidth); -- bytes left to move with second BitBlt lines _ bytes/(2*lineWidth); bytes _ lines*(2*lineWidth); -- bytes we move with main BitBlt -- This "moves" a rectangle that is lineWidth words wide by as many lines high as will fit. NB: It cheats and actually reads a byte from beyond the edge of the rectangle. This is not really legal, but works out OK for any reasonable inplementation of BitBlt. bbt.dty _ bbt.sty _ 0; bbt.dw _ 16*lineWidth; bbt.dh _ lines; BitBltDefs.BITBLT[bbt]; -- This BitBlt will move one line that is less than lineWidth words wide. bbt.dty _ bbt.sty _ lines; bbt.dw _ 8*tail; bbt.dh _ 1; BitBltDefs.BITBLT[bbt]; END; END; HyperSpaceNotSupported: PUBLIC ERROR = CODE; NilRejected: PUBLIC ERROR = CODE; ShortenPointer: PUBLIC PROCEDURE [lp: LONG POINTER] RETURNS [sp: POINTER] = BEGIN LongPointer: TYPE = RECORD [p: POINTER, other: WORD]; myCopy: LongPointer _ LOOPHOLE[lp]; IF myCopy.other#0 THEN ERROR HyperSpaceNotSupported; IF lp=NIL THEN ERROR NilRejected; sp _ myCopy.p; END; -- initialization END. -- AltoMesaByteBlt(2048)\372b37B24b7B81i77I90bi75BI346i53I4i16I1354i239I205bi261BI102i52I9i13I113b22B23b11B24b14B