DragonSampleMapOpsImpl.mesa
Copyright © 1985, 1986 by Xerox Corporation. All rights reserved.
Michael Plass, December 13, 1985 1:30:00 pm PST
Willie-Sue, September 15, 1986 11:12:07 am PDT
DIRECTORY
DragonBitBlt,
DragOpsCross,
DragOpsCrossUtils,
Basics, CountedVM, FunctionCache, PrincOps, PrincOpsUtils, VM,
SampleMapOps,
SlowSampleMapOps;
DragonSampleMapOpsImpl: CEDAR MONITOR
IMPORTS
DragonBitBlt, DragOpsCrossUtils,
Basics, CountedVM, FunctionCache, PrincOpsUtils, VM,
SampleMapOps
EXPORTS SlowSampleMapOps
~ BEGIN
bitsPerWord: NAT ~ Basics.bitsPerWord;
Buffer: TYPE ~ SampleMapOps.Buffer;
BufferRep: TYPE ~ SampleMapOps.BufferRep;
maxCount: NAT ~ SampleMapOps.maxCount;
CVEC: TYPE ~ SampleMapOps.CVEC;
Function: TYPE ~ SampleMapOps.Function;
nullFunction: Function ~ SampleMapOps.nullFunction;
lastCVEC: CVEC ~ SampleMapOps.lastCVEC;
logBitsPerWord: NAT ~ Basics.logBitsPerWord;
SampleMap: TYPE ~ SampleMapOps.SampleMap;
SampleMapRep: TYPE ~ SampleMapOps.SampleMapRep;
SubMap: TYPE ~ SampleMapOps.SubMap;
seedWord: WORD ← 123456B;
BITAND: PROC [a, b: CARDINAL] RETURNS [CARDINAL]
~ INLINE {RETURN[Basics.BITAND[a, b]]};
Shift: PROC [a: CARDINAL, b: INTEGER] RETURNS [CARDINAL]
~ INLINE {RETURN[Basics.BITSHIFT[a, b]]};
Check: PROC[x: CARDINAL, max: NAT] RETURNS [NAT] ~
TRUSTED MACHINE CODE { PrincOps.zINC; PrincOps.zBNDCK };
IF x IN[0..max] THEN RETURN[x] ELSE ERROR RuntimeError.BoundsFault
IsPowerOfTwo: PROC [c: CARDINAL] RETURNS [BOOLEAN] ~ INLINE {
RETURN [BITAND[c, c-1] = 0]
};
WordCountFromBit: PROC [bitCount: LONG CARDINAL] RETURNS [LONG CARDINAL] ~ {
RETURN [Basics.DoubleShiftRight[[lc[bitCount+(bitsPerWord-1)]], logBitsPerWord].lc]
};
Lg: PROC [a: NAT] RETURNS [lg: NAT ← 0] ~ {
b: CARDINAL ← 1;
UNTIL b >= a DO
lg ← lg + 1;
b ← b*2;
ENDLOOP;
};
RoundUp: PROC [a: NAT] RETURNS [x: NAT] ~ INLINE {
Round a bit size up to a whole number of (dragon) words.
x ← BITAND[a+(DragOpsCross.bitsPerWord-1), CARDINAL.LAST-(DragOpsCross.bitsPerWord-1)];
};
ConvertToDragonBitAddress: PROC[ba: PrincOps.BitAddress]
 RETURNS[da: DragonBitBlt.DragonBitAddress] = TRUSTED {
da.word ← LOOPHOLE[LOOPHOLE[ba.word, INT]/2, DragonBitBlt.DragonPointer];
da.bit ← ba.bit;
IF Basics.BITAND[LOOPHOLE[ba.word, Basics.LongNumber].lo, 1B] = 0 THEN RETURN;
da.bit ← da.bit + bitsPerWord;
};
SpecialConvertToDragonBitAddress: PROC[ba: PrincOps.BitAddress]
 RETURNS[da: DragonBitBlt.DragonBitAddress] = TRUSTED {
round up to the next 32-bit address
da.word ← LOOPHOLE[LOOPHOLE[ba.word, INT]/2, DragonBitBlt.DragonPointer];
da.bit ← ba.bit;
IF Basics.BITAND[LOOPHOLE[ba.word, Basics.LongNumber].lo, 1B] = 0 THEN RETURN;
da.word ← LOOPHOLE[da.word+1];
};
DstFunc: PROC[function: Function] RETURNS[dstFunc: DragonBitBlt.DstFunc] = {
SELECT function.dstFunc FROM
null => dstFunc ← null;
and => dstFunc ← and;
or => dstFunc ← or;
xor => dstFunc ← xor;
ENDCASE => NULL;
};
SrcFunc: PROC[function: Function] RETURNS[srcFunc: DragonBitBlt.SrcFunc] = {
srcFunc ← IF function.srcFunc = null THEN null ELSE complement;
};
smallSize: NAT ← 511;
WordSeqRep: TYPE ~ RECORD [SEQUENCE length: NAT OF WORD];
Create: PUBLIC PROC [sSize: CARDINAL, fSize: CARDINAL, bitsPerSample: [0..Basics.bitsPerWord]] RETURNS [s: SampleMap] ~
{ RETURN[CreateSampleMap[sSize, fSize, bitsPerSample, none]] };
CreateZ: PUBLIC PROC [sSize: CARDINAL, fSize: CARDINAL, bitsPerSample: [0..Basics.bitsPerWord]] RETURNS [s: SampleMap] ~
{ RETURN[CreateSampleMap[sSize, fSize, bitsPerSample, zeros]] };
CreateO: PUBLIC PROC [sSize: CARDINAL, fSize: CARDINAL, bitsPerSample: [0..Basics.bitsPerWord]] RETURNS [s: SampleMap] ~
{ RETURN[CreateSampleMap[sSize, fSize, bitsPerSample, ones]] };
HowToInit: TYPE = {none, zeros, ones};
CreateSampleMap: PROC [
sSize: CARDINAL, fSize: CARDINAL,
bitsPerSample: [0..Basics.bitsPerWord], how: HowToInit] RETURNS [s: SampleMap] ~ {
bitsPerLine: NAT ~ RoundUp[Basics.LongMult[fSize, bitsPerSample]];
nWords: LONG CARDINAL ~ Basics.LongMult[sSize, bitsPerLine/bitsPerWord];
IF nWords <= smallSize THEN TRUSTED {
words: NATMAX[NAT[nWords], 1];
wordSeq: REF WordSeqRep ← NEW[WordSeqRep[words]];
s ← UnsafeCreate[
sSize: sSize,
fSize: fSize,
bitsPerSample: bitsPerSample,
bitsPerLine: bitsPerLine,
base: [word: @wordSeq[0], bit: 0],
nWords: words,
ref: wordSeq
];
}
ELSE TRUSTED {
vm: CountedVM.Handle ~ Allocate[nWords];
s ← UnsafeCreate[
sSize: sSize, fSize: fSize,
bitsPerSample: bitsPerSample, bitsPerLine: bitsPerLine,
base: [word: vm.pointer, bit: 0], nWords: vm.words,
ref: vm
];
};
make sure the words are not simply zeroes
TRUSTED {
lp: LONG POINTER TO WORDLOOPHOLE[s.base.word];
initVal: WORD;
SELECT how FROM
none => initVal ← seedWord;
zeros => initVal ← 0;
ones => initVal ← 177777B;
ENDCASE => initVal ← seedWord;
FOR i: LONG CARDINAL IN [0..nWords) DO
IF how # none THEN lp^ ← initVal
ELSE IF lp^ = 0 THEN lp^ ← initVal ← Basics.BITNOT[initVal];
lp ← LOOPHOLE[lp + 1];
ENDLOOP;
};
};
Allocate: PROC [nWords: LONG CARDINAL] RETURNS [vm: CountedVM.Handle ← NIL] ~ {
nWords ← MAX[nWords, 256];
vm ← CountedVM.SimpleAllocate[nWords ! VM.CantAllocate => CONTINUE];
IF vm = NIL THEN {
Try flushing the global function cache to get some space back.
cache: FunctionCache.Cache ~ FunctionCache.GlobalCache[];
info: FunctionCache.CacheInfo ~ FunctionCache.GetInfo[cache];
FunctionCache.SetLimits[cache, 0, 0];
FunctionCache.SetLimits[x: cache, maxEntries: info.maxEntries, maxTotalSize: info.maxTotalSize];
vm ← CountedVM.SimpleAllocate[nWords];
};
};
Copy: PUBLIC PROC [subMap: SubMap] RETURNS [SampleMap] ~ {
s: SampleMap ~ subMap.sampleMap;
sMin: NAT ~ Check[subMap.start.s, s.sSize];
fMin: NAT ~ Check[subMap.start.f, s.fSize];
sSize: NAT ~ MIN[subMap.size.s, LOOPHOLE[s.sSize-sMin, NAT]];
fSize: NAT ~ MIN[subMap.size.f, LOOPHOLE[s.fSize-fMin, NAT]];
new: SampleMap ~ CreateO[sSize: sSize, fSize: fSize, bitsPerSample: s.bitsPerSample];
Transfer[dest: new, destStart: [0, 0], source: subMap, function: [null, null], goodDest: NIL];
RETURN [new];
};
DoubleCopy: PUBLIC PROC [to, slowTo, from: SampleMap, destStart: CVEC] = {
SampleMapOps.Transfer[dest: to, destStart: destStart, source: [from], function: [null, null]];
Transfer[dest: slowTo, destStart: destStart, source: [from], function: [null, null], goodDest: to];
};
ComputeWords: PROC [sSize: CARDINAL, fSize: CARDINAL, bitsPerSample: [0..bitsPerWord]] RETURNS [LONG CARDINAL] ~ {
bitsPerLine: NAT ~ RoundUp[Basics.LongMult[fSize, bitsPerSample]];
RETURN [Basics.LongMult[sSize, bitsPerLine/bitsPerWord]]
};
nullBitBltTable: DragonBitBlt.BitBltTable ~ [
dst: [word: NIL, bit: 0], dstBpl: 0,
src: [word: NIL, bit: 0], srcDesc: [srcBpl[0]],
width: 0, height: 0, flags: []
];
disjointBitBltTable: DragonBitBlt.BitBltTable ~ [
dst: [word: NIL, bit: 0], dstBpl: 0,
src: [word: NIL, bit: 0], srcDesc: [srcBpl[0]],
width: 0, height: 0, flags: [disjoint: TRUE, disjointItems: TRUE]
];
grayBitBltTable: DragonBitBlt.BitBltTable ~ [
dst: [word: NIL, bit: 0], dstBpl: 0,
src: [word: NIL, bit: 0], srcDesc: [srcBpl[0]],
width: 0, height: 0, flags: [disjoint: TRUE, disjointItems: TRUE, gray: TRUE]
];
UnsafeCreate: PUBLIC UNSAFE PROC [sSize: CARDINAL, fSize: CARDINAL, bitsPerSample: [0..Basics.bitsPerWord], bitsPerLine: NAT, base: PrincOps.BitAddress, nWords: LONG CARDINAL, ref: REF, scratchDescriptor: SampleMap ← NIL] RETURNS [SampleMap] ~ {
dataBitsPerLine: LONG CARDINAL ~ Basics.LongMult[fSize, bitsPerSample];
fillBits: NAT ~ bitsPerLine-dataBitsPerLine;
totalBits: LONG CARDINAL ~ Basics.LongMult[sSize, bitsPerLine]-fillBits+base.bit;
wrds: LONG CARDINAL ~ WordCountFromBit[totalBits];
check: BOOL[FALSE..FALSE] ~ (nWords < wrds);
s: SampleMap ~ IF scratchDescriptor#NIL THEN scratchDescriptor ELSE NEW[SampleMapRep];
s^ ← [
sSize: sSize,
fSize: fSize,
bitsPerSample: bitsPerSample,
base: base,
bitsPerLine: bitsPerLine,
ref: ref
];
RETURN [s];
};
GetSample: PUBLIC PROC [sampleMap: SampleMap, index: CVEC] RETURNS [CARDINAL] ~ TRUSTED {
s: CARDINAL ~ Basics.BoundsCheck[index.s, sampleMap.sSize];
f: CARDINAL ~ Basics.BoundsCheck[index.f, sampleMap.fSize];
bitsPerSample: NAT ~ sampleMap.bitsPerSample;
bitIndex: LONG CARDINAL ~ sampleMap.base.bit + Basics.LongMult[s, sampleMap.bitsPerLine] + Basics.LongMult[f, bitsPerSample];
bitAddress: PrincOps.BitAddress ~ IndexBit[sampleMap.base.word, [lc[bitIndex]]];
pointer: LONG POINTER TO ARRAY [0..1] OF WORD ~ bitAddress.word;
shiftAmt: INTEGER ~ bitAddress.bit + bitsPerSample - bitsPerWord;
mask: CARDINAL ~ Shift[1, bitsPerSample]-1;
shiftedBits: CARDINAL ~ IF shiftAmt <= 0
THEN Shift[pointer^[0], shiftAmt]
ELSE Shift[pointer^[0], shiftAmt] + Shift[pointer^[1], shiftAmt-16];
RETURN [BITAND[shiftedBits, mask]]
};
PutSample: PUBLIC PROC [sampleMap: SampleMap, index: CVEC, value: CARDINAL,
 function: Function, goodDest: SampleMap] ~ TRUSTED {
s: CARDINAL ~ Basics.BoundsCheck[index.s, sampleMap.sSize];
f: CARDINAL ~ Basics.BoundsCheck[index.f, sampleMap.fSize];
bitsPerSample: NAT ~ sampleMap.bitsPerSample;
bitIndex: LONG CARDINAL ~ sampleMap.base.bit + Basics.LongMult[s, sampleMap.bitsPerLine] + Basics.LongMult[f, bitsPerSample];
bbPtr: DragonBitBlt.BitBltTable;
bb: DragonBitBlt.BitBltTablePtr ← @bbPtr;
bb^ ← [
dst: ConvertToDragonBitAddress[IndexBit[sampleMap.base.word, [lc[bitIndex]]]],
dstBpl: 0,
src: ConvertToDragonBitAddress[[word: @value, bit: bitsPerWord-bitsPerSample]],
srcDesc: [srcBpl[0]],
height: 1,
width: bitsPerSample,
flags: [direction: forward, disjoint: TRUE, disjointItems: TRUE, gray: FALSE, srcFunc: SrcFunc[function], dstFunc: DstFunc[function]]
];
DragonBitBlt.BITBLT[bb];
};
DumbTransfer: PROC [dest: SampleMap, destStart: CVEC, source: SubMap, function: Function,
 goodDest: SampleMap] ~ {
sSize: NAT ~ MIN[source.size.s, dest.sSize-destStart.s, source.sampleMap.sSize-source.start.s];
fSize: NAT ~ MIN[source.size.f, dest.fSize-destStart.f, source.sampleMap.fSize-source.start.f];
FOR s: NAT IN [0..sSize) DO
FOR f: NAT IN [0..fSize) DO
sample: CARDINAL ~ GetSample[source.sampleMap, [source.start.s+s, source.start.f+f]];
PutSample[dest, [destStart.s+s, destStart.f+f], sample, function, goodDest];
ENDLOOP;
ENDLOOP;
};
BitAddressOverlay: TYPE ~ MACHINE DEPENDENT RECORD [
This record is to designed to avoid the need for partial-word access to the bit offset field, since the BITBLT format has carefully made this field word-aligned, and PrincOps.BitAddress has just as carefully made it hard to take advantage of this fact.
SELECT OVERLAID * FROM
ba => [bitAddress: PrincOps.BitAddress],
ov => [pointer: LONG POINTER, offset: CARDINAL],
ENDCASE
];
IndexBit: UNSAFE PROC [pointer: LONG POINTER, bitOffset: Basics.LongNumber] RETURNS [PrincOps.BitAddress] ~ UNCHECKED INLINE {
addr: BitAddressOverlay ~ [ov[
pointer: pointer + Basics.DoubleShiftRight[bitOffset, logBitsPerWord].lc,
offset: bitOffset.lo MOD bitsPerWord
]];
RETURN [addr.bitAddress]
};
Transfer: PUBLIC PROC [dest: SampleMap, destStart: CVEC, source: SubMap, function: Function,
 goodDest: SampleMap] ~ TRUSTED {
bps: NAT ~ dest.bitsPerSample;
src: SampleMap ~ source.sampleMap;
sSize: NAT ~ MIN[source.size.s, dest.sSize-destStart.s, source.sampleMap.sSize-source.start.s];
fSize: NAT ~ MIN[source.size.f, src.fSize-source.start.f, dest.fSize-destStart.f];
SELECT TRUE FROM
source.sampleMap.bitsPerSample = bps => {
bbPtr: DragonBitBlt.BitBltTable;
bb: DragonBitBlt.BitBltTablePtr ← @bbPtr;
dstBitIndex: LONG CARDINAL ~ dest.base.bit +
Basics.LongMult[Check[destStart.s, dest.sSize], dest.bitsPerLine] +
Basics.LongMult[Check[destStart.f, dest.fSize], bps];
srcBitIndex: LONG CARDINAL ~ src.base.bit +
Basics.LongMult[Check[source.start.s, src.sSize], src.bitsPerLine] +
Basics.LongMult[Check[source.start.f, src.fSize], bps];
bb^ ← disjointBitBltTable;
bb.dst ← ConvertToDragonBitAddress[ IndexBit[dest.base.word, [lc[dstBitIndex]]] ];
bb.dstBpl ← dest.bitsPerLine;
bb.src ← ConvertToDragonBitAddress[ IndexBit[src.base.word, [lc[srcBitIndex]]] ];
bb.srcDesc ← [srcBpl[src.bitsPerLine]];
bb.height ← sSize;
bb.width ← fSize * bps;
bb.flags.srcFunc ← SrcFunc[function];
bb.flags.dstFunc ← DstFunc[function];
DragonBitBlt.BITBLT[bb];
};
ENDCASE => DumbTransfer[dest, destStart, source, function, goodDest];
};
Move: PUBLIC PROC [sampleMap: SampleMap, destStart: CVEC, sourceStart: CVEC, size: CVEC, function: Function, goodDest: SampleMap] ~ TRUSTED {
bps: NAT ~ sampleMap.bitsPerSample;
bpl: NAT ~ sampleMap.bitsPerLine;
sSize: NAT ~ sampleMap.sSize;
fSize: NAT ~ sampleMap.fSize;
bbPtr: DragonBitBlt.BitBltTable;
bb: DragonBitBlt.BitBltTablePtr ← @bbPtr;
dstBitIndex: LONG CARDINAL ← sampleMap.base.bit +
Basics.LongMult[Check[destStart.s, sSize], bpl] +
Basics.LongMult[Check[destStart.f, fSize], bps];
srcBitIndex: LONG CARDINAL ← sampleMap.base.bit +
Basics.LongMult[Check[sourceStart.s, sSize], bpl] +
Basics.LongMult[Check[sourceStart.f, fSize], bps];
sSamples: NAT ~ MIN[size.s, sSize-sourceStart.s, sSize-destStart.s];
fSamples: NAT ~ MIN[size.f, fSize-sourceStart.f, fSize-destStart.f];
bb^ ← disjointBitBltTable;
bb.dstBpl ← bpl;
bb.srcDesc ← [srcBpl[bpl]];
bb.height ← sSamples;
bb.width ← bps * fSamples;
bb.flags.srcFunc ← SrcFunc[function];
bb.flags.dstFunc ← DstFunc[function];
IF sSamples > 0 AND (sourceStart.f+fSamples) > destStart.f AND
(destStart.f+fSamples) > sourceStart.f AND
(sourceStart.s+sSamples) > destStart.s AND
(destStart.s+sSamples) > sourceStart.s THEN {
bb.flags.disjoint ← FALSE; -- the rectangles overlap
IF sourceStart.s=destStart.s THEN bb.flags.disjointItems ← FALSE; -- so do the items
IF destStart.s>sourceStart.s OR (destStart.s=sourceStart.s AND destStart.f>sourceStart.f) THEN { -- reverse direction
delta: LONG CARDINAL ← Basics.LongMult[sSamples-1, bpl];
bb.flags.direction ← backward; bb.srcDesc.srcBpl ← bb.dstBpl ← -bb.dstBpl;
dstBitIndex ← dstBitIndex + delta;
srcBitIndex ← srcBitIndex + delta;
};
};
bb.dst ← ConvertToDragonBitAddress[ IndexBit[sampleMap.base.word, [lc[dstBitIndex]]] ];
bb.src ← ConvertToDragonBitAddress[ IndexBit[sampleMap.base.word, [lc[srcBitIndex]]] ];
DragonBitBlt.BITBLT[bb];
};
DumbFill: PROC [dest: SubMap, value: CARDINAL, function: Function, goodDest: SubMap] ~ {
sSize: NAT ~ MIN[dest.size.s, dest.sampleMap.sSize-dest.start.s];
fSize: NAT ~ MIN[dest.size.f, dest.sampleMap.fSize-dest.start.f];
FOR s: NAT IN [0..sSize) DO
FOR f: NAT IN [0..fSize) DO
PutSample[dest.sampleMap, [dest.start.s+s, dest.start.f+f], value, function, goodDest.sampleMap];
ENDLOOP;
ENDLOOP;
};
replicator: ARRAY [0..4] OF CARDINAL ~ [0FFFFH, 05555H, 01111H, 00101H, 00001H];
Fill: PUBLIC PROC [dest: SubMap, value: CARDINAL, function: Function, goodDest: SubMap] ~ {
bps: NAT ~ dest.sampleMap.bitsPerSample;
IF bitsPerWord MOD bps = 0 THEN TRUSTED {
dstBitIndex: LONG CARDINAL ~ dest.sampleMap.base.bit +
Basics.LongMult[Check[dest.start.s, dest.sampleMap.sSize], dest.sampleMap.bitsPerLine] +
Basics.LongMult[Check[dest.start.f, dest.sampleMap.fSize], bps];
sSize: NAT ~ MIN[dest.size.s, dest.sampleMap.sSize-dest.start.s];
fSize: NAT ~ MIN[dest.size.f, dest.sampleMap.fSize-dest.start.f];
bbPtr: DragonBitBlt.BitBltTable;
bb: DragonBitBlt.BitBltTablePtr ← @bbPtr;
replicatedPixel: CARDINALBITAND[value, Shift[1, bps]-1] * replicator[Lg[bps]];
must make sure than pixelToUse is on a 32-bit boundary
pixelToUse: ARRAY [0..2] OF DragOpsCross.Half ←
ALL[DragOpsCrossUtils.CardToHalf[replicatedPixel]];
IF function = [null, complement] THEN {
Bug in Dorado BITBLT microcode (as of December 4, 1985)
replicatedPixel ← CARDINAL.LAST-replicatedPixel;
function ← [null, null];
};
bb^ ← grayBitBltTable;
bb.dst ←
ConvertToDragonBitAddress[ IndexBit[dest.sampleMap.base.word, [lc[dstBitIndex]]] ];
bb.dstBpl ← dest.sampleMap.bitsPerLine;
bb.src ← SpecialConvertToDragonBitAddress[ [word: @pixelToUse, bit: 0] ];
bb.height ← MIN[dest.size.s, dest.sampleMap.sSize-dest.start.s];
bb.width ← bps*MIN[dest.size.f, dest.sampleMap.fSize-dest.start.f];
bb.flags.srcFunc ← SrcFunc[function];
bb.flags.dstFunc ← DstFunc[function];
DragonBitBlt.BITBLT[bb];
}
ELSE DumbFill[dest, value, function, goodDest];
};
TileBox: PUBLIC PROC [dest: SampleMap, start: CVEC, size: CVEC, source: SampleMap, s0, f0: INTEGER, phase: NAT, function: Function, goodDest: SampleMap] ~ {
boxes: PROC[box: BoxProc] ~ {box[start.s, start.f, start.s+size.s, start.f+size.f]};
TileBoxes[dest, boxes, source, s0, f0, phase, function, goodDest];
};
QR: TYPE ~ RECORD [quotient: INTEGER, remainder: NAT];
DivMod: PROC [n: INTEGER, d: NAT] RETURNS [qr: QR] ~ {
Number-theoretic: 0 <= remainder < d, n = quotient*d + remainder
IF d#1 THEN {
nn: Basics.LongNumber ← [li[n]];
qq: Basics.LongNumber ← [lc[0]];
IF nn.li < 0 THEN {nn.highbits ← nn.highbits + d; -- qq.highbits ← CARDINAL.LAST --};
[quotient: qq.lowbits, remainder: qr.remainder] ← Basics.LongDivMod[nn.lc, d];
quotient ← qq.li;
qr.quotient ← LOOPHOLE[qq.lowbits];
}
ELSE RETURN [[quotient: n, remainder: 0]];
};
Mod: PROC [n: INT, d: NAT] RETURNS [remainder: NAT] ~ {
Number-theoretic: 0 <= remainder < d
IF d#1 THEN {
nn: Basics.LongNumber ← [li[n]];
WHILE nn.li < 0 DO nn.highbits ← nn.highbits + d ENDLOOP;
WHILE nn.highbits >= d DO nn.highbits ← nn.highbits - d ENDLOOP;
RETURN [Basics.LongDivMod[nn.lc, d].remainder];
}
ELSE RETURN [remainder: 0];
};
EnlargedSize: PROC [fSize: NAT, bps: NAT] RETURNS [NAT] ~ {
n: CARDINAL ~ ((smallWidth+fSize-1)/fSize+bps-1)/bps;
RETURN [Basics.LongMult[n, fSize]]
};
smallWidth: NAT ← 128;
BoxProc: TYPE ~ SampleMapOps.BoxProc;
TileBoxes: PUBLIC PROC [dest: SampleMap, boxes: PROC[BoxProc], source: SampleMap, s0, f0: INTEGER, phase: NAT, function: Function, goodDest: SampleMap] ~ {
sSize: NAT ~ dest.sSize;
fSize: NAT ~ dest.fSize;
bps: NAT ~ dest.bitsPerSample;
MacroBrickAction: PROC [scratch: SampleMap] ~ {
scratchBoxes: PROC[box: BoxProc] ~ {box[0, 0, scratch.sSize, scratch.fSize]};
GeneralTileBoxes[scratch, scratchBoxes, source, 0, 0, phase, [null, null], NIL];
GeneralTileBoxes[dest, boxes, scratch, s0, f0, phase, function, goodDest];
};
IF bps=source.bitsPerSample AND source.fSize*bps = bitsPerWord AND source.bitsPerLine = bitsPerWord AND source.sSize IN (0..16] AND phase = 0 AND source.base.bit = 0 AND function # [null, complement] THEN TRUSTED {
bbPtr: DragonBitBlt.BitBltTable;
bb: DragonBitBlt.BitBltTablePtr ← @bbPtr;
destBPL: CARDINAL ~ dest.bitsPerLine;
easyBox: SAFE PROC [smin, fmin, smax, fmax: CARDINAL] ~ TRUSTED {
dstBitIndex: LONG CARDINAL ~ dest.base.bit +
Basics.LongMult[Check[smin, smax], destBPL] +
Basics.LongMult[Check[fmin, fmax], bps];
yOffset: CARDINAL ~ LOOPHOLE[smin-s0, CARDINAL] MOD source.sSize;
bb.dst ← ConvertToDragonBitAddress[ IndexBit[dest.base.word, [lc[dstBitIndex]]] ];
bb.src ← ConvertToDragonBitAddress[
[word: source.base.word+yOffset, bit: LOOPHOLE[fmin-f0, CARDINAL] MOD 16] ];
bb.srcDesc.gray.yOffset ← yOffset;
bb.height ← Check[smax, sSize]-smin;
bb.width ← Basics.LongMult[Check[fmax, fSize]-fmin, bps];
DragonBitBlt.BITBLT[bb];
};
bb^ ← grayBitBltTable;
bb.dstBpl ← dest.bitsPerLine;
bb.srcDesc.gray.heightMinusOne ← source.sSize-1;
bb.flags.srcFunc ← SrcFunc[function];
bb.flags.dstFunc ← DstFunc[function];
boxes[easyBox];
RETURN
};
IF bps#source.bitsPerSample OR source.fSize*bps < MIN[smallWidth, dest.fSize]
THEN SampleMapOps.DoWithScratch[sSize: source.sSize, fSize: EnlargedSize[source.fSize, bps], bitsPerSample: bps, action: MacroBrickAction]
ELSE GeneralTileBoxes[dest, boxes, source, s0, f0, phase, function, goodDest];
};
QMul: PROC [a: INTEGER, b: CARDINAL] RETURNS [INT] ~ INLINE {
IF a >= 0 THEN RETURN [LOOPHOLE[Basics.LongMult[a, b]]]
ELSE RETURN [-LOOPHOLE[Basics.LongMult[-a, b], INT]]
};
GeneralTileBoxes: PROC [dest: SampleMap, boxes: PROC[BoxProc], source: SampleMap, s0, f0: INTEGER, phase: NAT, function: Function, goodDest: SampleMap] ~ {
bps: NAT ~ dest.bitsPerSample;
sSize: NAT ~ dest.sSize;
fSize: NAT ~ dest.fSize;
box: SAFE PROC [smin, fmin, smax, fmax: CARDINAL] ~ TRUSTED {
sBrickSize: NAT ~ source.sSize;
fBrickSize: NAT ~ source.fSize;
qr: QR ~ DivMod[(INTEGER[smin]-s0), sBrickSize];
s: CARDINAL ← smin;
sDelta: CARDINAL ← sBrickSize - qr.remainder;
fSource: CARDINAL ← Mod[fmin-f0 - QMul[qr.quotient, phase], fBrickSize];
WHILE s < smax DO
sBrick: NAT ~ sBrickSize-sDelta;
sClipSize: NAT ~ MIN[sBrickSize+s, smax]-s;
f: NAT ← fmin;
fDelta: NAT ← fBrickSize-fSource;
WHILE f < fmax DO
IF goodDest = NIL THEN
SampleMapOps.Transfer[dest: dest, destStart: [s, f], source: [source, [sBrick, fBrickSize-fDelta], [sClipSize, MIN[fBrickSize+f, fmax]-f]], function: function]
ELSE Transfer[dest: dest, destStart: [s, f], source: [source, [sBrick, fBrickSize-fDelta], [sClipSize, MIN[fBrickSize+f, fmax]-f]], function: function, goodDest: goodDest];
f ← f + fDelta;
fDelta ← fBrickSize;
ENDLOOP;
s ← s + sDelta;
sDelta ← sBrickSize;
WHILE fSource < phase DO fSource ← fSource + fBrickSize ENDLOOP;
fSource ← fSource - phase;
ENDLOOP;
};
boxes[box];
};
Get: PUBLIC PROC [buffer: Buffer, start: NAT ← 0, count: NAT ← maxCount,
sampleMap: SampleMap, s, f: NAT ← 0, ds: NAT ← 0, df: NAT ← 1] ~ TRUSTED {
size: NAT ~ MIN[count, buffer.length-start];
IF size # 0 THEN {
sSize: NAT ~ sampleMap.sSize;
fSize: NAT ~ sampleMap.fSize;
bpl: NAT ~ sampleMap.bitsPerLine;
bps: NAT ~ sampleMap.bitsPerSample;
bbPtr: DragonBitBlt.BitBltTable;
bb: DragonBitBlt.BitBltTablePtr ← @bbPtr;
bufferPointer: LONG POINTER ~ InlineGetPointer[buffer, start, size];
srcBitIndex: LONG CARDINAL ← sampleMap.base.bit +
Basics.LongMult[Basics.BoundsCheck[s, sSize], bpl] +
Basics.LongMult[Basics.BoundsCheck[f, fSize], bps];
srcBitDelta: NAT ~ Basics.LongMult[ds, bpl] + Basics.LongMult[df, bps];
srcBitSkipDelta: NAT ← srcBitDelta;
lgSkip: NAT ← 0;
skipMinusOne: NAT ← 0;
IF ds > 0 THEN [] ← Basics.BoundsCheck[s+Basics.LongMult[size-1, ds], sSize];
IF df > 0 THEN [] ← Basics.BoundsCheck[f+Basics.LongMult[size-1, df], fSize];
WHILE srcBitSkipDelta <= NAT.LAST/2 AND LOOPHOLE[srcBitSkipDelta, CARDINAL] MOD bitsPerWord # 0 DO
srcBitSkipDelta ← srcBitSkipDelta * 2;
lgSkip ← lgSkip + 1;
ENDLOOP;
skipMinusOne ← Shift[1, lgSkip]-1;
PrincOpsUtils.LongZero[where: bufferPointer, nwords: size];
bb^ ← disjointBitBltTable;
bb.dstBpl ← Shift[bitsPerWord, lgSkip];
bb.srcDesc ← [srcBpl[srcBitSkipDelta]];
bb.width ← bps;
FOR i: NAT IN [0..Shift[1, lgSkip]) DO
bb.src ←
ConvertToDragonBitAddress[ IndexBit[sampleMap.base.word, [lc[srcBitIndex]]] ];
bb.height ← Shift[size-i+skipMinusOne, -lgSkip];
bb.dst ← ConvertToDragonBitAddress[ [word: bufferPointer+i, bit: bitsPerWord-bps] ];
DragonBitBlt.BITBLT[bb];
srcBitIndex ← srcBitIndex + srcBitDelta;
ENDLOOP;
DragonBitBlt.BITBLT[bb];
};
};
Put: PUBLIC PROC [buffer: Buffer, start: NAT ← 0, count: NAT ← maxCount,
sampleMap: SampleMap, s, f: NAT ← 0, ds: NAT ← 0, df: NAT ← 1,
function: Function ← nullFunction, goodDest: SampleMap] ~ TRUSTED {
size: NAT ~ MIN[count, buffer.length-start];
IF size # 0 THEN {
sSize: NAT ~ sampleMap.sSize;
fSize: NAT ~ sampleMap.fSize;
bpl: NAT ~ sampleMap.bitsPerLine;
bps: NAT ~ sampleMap.bitsPerSample;
bbPtr: DragonBitBlt.BitBltTable;
bb: DragonBitBlt.BitBltTablePtr ← @bbPtr;
bufferPointer: LONG POINTER ~ InlineGetPointer[buffer, start, size];
dstBitIndex: LONG CARDINAL ← sampleMap.base.bit +
Basics.LongMult[Basics.BoundsCheck[s, sSize], bpl] +
Basics.LongMult[Basics.BoundsCheck[f, fSize], bps];
dstBitDelta: NAT ← Basics.LongMult[ds, bpl] + Basics.LongMult[df, bps];
dstBitSkipDelta: NAT ← dstBitDelta;
lgSkip: NAT ← 0;
skipMinusOne: NAT ← 0;
bufferFirst: LONG POINTER ← bufferPointer;
IF ds > 0 THEN [] ← Basics.BoundsCheck[s+Basics.LongMult[size-1, ds], sSize];
IF df > 0 THEN [] ← Basics.BoundsCheck[f+Basics.LongMult[size-1, df], fSize];
WHILE dstBitSkipDelta <= NAT.LAST/2 AND LOOPHOLE[dstBitSkipDelta, CARDINAL] MOD bitsPerWord # 0 DO
dstBitSkipDelta ← dstBitSkipDelta * 2;
lgSkip ← lgSkip + 1;
ENDLOOP;
skipMinusOne ← Shift[1, lgSkip]-1;
bb^ ← disjointBitBltTable;
bb.flags.srcFunc ← SrcFunc[function];
bb.flags.dstFunc ← DstFunc[function];
bb.dstBpl ← dstBitSkipDelta;
bb.srcDesc ← [srcBpl[Shift[bitsPerWord, lgSkip]]];
bb.width ← bps;
FOR i: NAT IN [0..Shift[1, lgSkip]) DO
bb.dst ←
ConvertToDragonBitAddress[ IndexBit[sampleMap.base.word, [lc[dstBitIndex]]] ];
bb.height ← Shift[size-i+skipMinusOne, -lgSkip];
bb.src ← ConvertToDragonBitAddress[ [word: bufferPointer+i, bit: bitsPerWord-bps] ];
DragonBitBlt.BITBLT[bb];
dstBitIndex ← dstBitIndex + dstBitDelta;
ENDLOOP;
};
};
Flip: PUBLIC PROC [buffer: Buffer] ~ TRUSTED {
size: NAT ~ buffer.length;
last: INTEGER ~ size-1;
s: LONG POINTER TO Basics.RawWords ~ InlineGetPointer[buffer, 0, size];
k: NAT ← size;
FOR j: NAT IN [0..size/2) DO
t: CARDINAL ← s[j];
s[j] ← s[k ← k-1];
s[k] ← t;
ENDLOOP;
};
InlineGetPointer: PROC [buffer: Buffer, start: NAT, count: NAT] RETURNS [LONG POINTER TO Basics.RawWords] ~ TRUSTED INLINE {
[] ← Check[start+count, buffer.maxLength];
TRUSTED {RETURN [LOOPHOLE[buffer, LONG POINTER TO Basics.RawWords]+SIZE[BufferRep[start]]]}
};
END.