-- 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

StartIndexGreater
ThanStopIndexPlusOne: 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 si
nce 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];
fro
mBytes ← 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 200micr
osec 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*lin
eWidth); -- 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 f
or 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;

H
yperSpaceNotSupported: PUBLIC ERROR = CODE;
NilRe
jected: 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