~
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: NAT ← MAX[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
];
};
vm: CountedVM.Handle ~ Allocate[nWords];
TRUSTED {
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 WORD ← LOOPHOLE[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: CARDINAL ← BITAND[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]]]}
};