DIRECTORY
BasicTime USING [Pulses, MicrosecondsToPulses],
DeviceCleanup USING [Item, Reason, Await],
DLionInputOutput USING [GetRealPage, IOPage, ioPageRealAddrLow],
Loader USING [MakeProcedureResident, MakeGlobalFrameResident],
PrincOps USING [PageCount, PageNumber, wordsPerPage],
PrincOpsUtils USING [BITAND, GetClockPulses, LongZero],
RavenFace,
VM USING [AddressForPageNumber, Interval, nullInterval, Pin],
VMSideDoor USING [AssignSpecialRealMemory, ReleaseSpecialRealMemory];
RavenStuff
There is a game going on that the relative pointers "work" in relation BOTH to Physical 10000x and some virtual Base addresses.
Raven occupies from 10x through 38x on the IOPage
This stuff is hear for the sake of the compiler.
IOPage: LONG POINTER = DLionInputOutput.IOPage;
imageLoc: LONG POINTER TO ImageCSB = LOOPHOLE[IOPage + 20B];
firstBandRecord: Index = LOOPHOLE [DLionInputOutput.ioPageRealAddrLow + 20B + SIZE[ImageCSB]];
BandRecordBase: TYPE = LONG BASE POINTER TO RECORD [UNSPECIFIED]; -- base to BandRecord
bandRecordBase: BandRecordBase = LOOPHOLE[imageLoc + SIZE[ImageCSB] - LOOPHOLE[firstBandRecord, CARDINAL]]; -- The IO page address
Index:
PUBLIC
TYPE = BandRecordBase
RELATIVE
ORDERED
POINTER
TO BandRecord;
This is an offset into the table of BandRecords loacated in the IOPage.
BandRecord:
TYPE =
MACHINE
DEPENDENT
RECORD [
band(0): Band, -- Relative to Real page 0
next(1): Index, -- This is relative to the start of the IOPage!!!
status(2): INTEGER];
firstBandRecord: Index = LOOPHOLE [20B + SIZE[ImageCSB]];
bandRecordLimit: Index = firstBandRecord + MaxBands*
SIZE[BandRecord];
This is a real mess. I think that the effective address of bandRecordBase[firstBandRecord] = IOPage + 20B + SIZE[ImageCSB] and bandRecordBase[firstBandRecord.NEXT] = IOPage + 20B + SIZE[ImageCSB] + SIZE[BandRecord] and so on.
BandBufferBase: TYPE = LONG BASE POINTER TO RECORD [UNSPECIFIED]; -- Band memory as defined by the band records.
bandBufferBase: BandBufferBase; -- Set by AllocateBands as a real address for the uCode.
Band: TYPE = BandBufferBase RELATIVE POINTER; -- real relative pointer
VBandBufferBase: TYPE = LONG BASE POINTER TO RECORD [UNSPECIFIED]; -- Virtual band memory as defined by the band records. This is so we keep track of the mapping between the real address of the bands and the virtual addresses.
vBandBufferBase: VBandBufferBase; -- Set by AllocateBands as the original virtual address of the band.
VBand: TYPE = VBandBufferBase RELATIVE POINTER; -- Virtual relative pointer. Band[bandBufferBase] should be the real address = Band[vBandBufferBase].
imageLoc: LONG POINTER TO ImageCSB = LOOPHOLE[IOPage + 20B];
ImageCSB:
TYPE =
MACHINE
DEPENDENT
RECORD [
run(0): Index,
overrun(1): WORD, -- zero => ok, nonzero => overrun
mask(2): CARDINAL, -- band empty wakeup mask
bandSize(3): CARDINAL, -- number of lines (pages) in band
lastStartedBand(4): Index, -- used by device cleanup to wait for printer to stop
lineSize(5): CARDINAL, -- constant = 256
tab(6): CARDINAL, -- words of pixels to skip before starting scan
scans(7): CARDINAL]; -- number of blank lines after page sync
controlLoc: LONG POINTER TO CCSB = LOOPHOLE[IOPage + 60B]; -- FF30'x
CCSB: TYPE = MACHINE DEPENDENT RECORD [unused(0): WORD, mask(1): WORD, data(2): WORD, status(3): WORD];
statusLoc: LONG POINTER TO SCSB = LOOPHOLE[IOPage + 64B]; -- FF34'x
SCSB: TYPE = MACHINE DEPENDENT RECORD [overrun(0): WORD, mask(1): WORD, data(2): WORD, status(3): CARDINAL]; -- actually PrinterStatus
pagesCurrentlyInBands: PrincOps.PageCount ← 0; -- How many are used.
nullIndex: Index = LOOPHOLE[0];
heldBandVM: VM.Interval ← VM.nullInterval;
IthIndex:
PROC [i:
CARDINAL [0..MaxBands)]
RETURNS [Index] = {
RETURN[firstBandRecord + (i*SIZE[BandRecord])]};
AllocateBands:
PUBLIC
PROC [bandVM:
VM.Interval, nBands: (0..MaxBands], sizeEachBand:
CARDINAL] =
BEGIN
realPage: CARDINAL;
words: INT;
IF heldBandVM # VM.nullInterval THEN ERROR; -- Storage already allocated.
IF bandVM.count < (nBands*sizeEachBand) THEN ERROR;
VMSideDoor.AssignSpecialRealMemory[bandVM]; -- Move to low core and Pin
bandBufferBase ← VM.AddressForPageNumber[DLionInputOutput.GetRealPage[bandVM.page]];
vBandBufferBase ← VM.AddressForPageNumber[bandVM.page]; -- Make the virtual LP
pagesCurrentlyInBands ← sizeEachBand*nBands;
words ← LONG[nBands] * LONG[sizeEachBand] * LONG[PrincOps.wordsPerPage];
DLionInputOutput.SetReservedMemoryUse[Raven, pagesCurrentlyInBands];
realPage ← LOOPHOLE[DLionInputOutput.GetRealPage[bandVM.page]];
ClearCore[VM.AddressForPageNumber[bandVM.page], words];
FOR i:
CARDINAL
IN [0..nBands)
DO
bandRecordBase[IthIndex[i]] ← [band: LOOPHOLE[(realPage + i * sizeEachBand) * PrincOps.wordsPerPage], next: IthIndex[(i+1) MOD nBands], status: 0];
ENDLOOP;
imageLoc.bandSize ← sizeEachBand;
imageLoc.lastStartedBand ← nullIndex;
imageLoc.lineSize ← PrincOps.wordsPerPage;
heldBandVM ← bandVM;
END;
ClearCore:
PROC [pointer:
LONG
POINTER, words:
INT] =
BEGIN
WHILE words > 32768
DO
PrincOpsUtils.LongZero[pointer, 32768];
pointer ← pointer + 32768;
words ← words - 32768;
ENDLOOP;
PrincOpsUtils.LongZero[pointer, words];
END;
SetInterruptMasks:
PUBLIC
PROC [control, status, data:
WORD] = {
controlLoc.mask ← control; statusLoc.mask ← status; imageLoc.mask ← data};
DeallocateBands:
PUBLIC
PROC =
BEGIN
imageLoc.lastStartedBand ← nullIndex;
IF heldBandVM = VM.nullInterval THEN ERROR; -- Storage not allocated.
VMSideDoor.ReleaseSpecialRealMemory[heldBandVM];
pagesCurrentlyInBands ← 0;
heldBandVM ← VM.nullInterval;
DLionInputOutput.SetReservedMemoryUse[notBusy];
END;
Display:
PUBLIC
PROC [char: ConsoleCharacter] = {
Send[LOOPHOLE[char, WORD]]};
Feed:
PUBLIC
PROC [paperSource: PaperSource, paperStacking: PaperStacking] =
BEGIN
Send[100B + (IF paperSource = bottom THEN 0 ELSE 20B) + (IF paperStacking = aligned THEN 0 ELSE 1)]
END;
WakeUp: PUBLIC PROC = {Send[40B]};
DozeOff: PUBLIC PROC = {Send[132B]};
ReadStatus:
PUBLIC
PROC
RETURNS [status: PrinterStatus] = {
Send[40B]; RETURN [SolicitStatus[]]};
SolicitStatus:
PUBLIC
PROC
RETURNS [s: PrinterStatus] =
BEGIN
IF statusLoc.overrun # 0
THEN {statusLoc.status ← 0; statusLoc.overrun ← 0; s ← statusOverRun}
ELSE
IF statusLoc.status # 0
THEN {s ← LOOPHOLE[PrincOpsUtils.BITAND[statusLoc.data, 177B]]; statusLoc.status ← 0}
ELSE s ← noStatus;
END;
SetScanLineLength:
PUBLIC
PROC [activeWordsEachScanLine: (0..PrincOps.wordsPerPage]] =
BEGIN
offset: [0..PrincOps.wordsPerPage) = PrincOps.wordsPerPage - activeWordsEachScanLine;
FOR i: Index ← firstBandRecord, i +
SIZE[BandRecord]
WHILE i < bandRecordLimit
DO
pageOffset: TYPE = MACHINE DEPENDENT RECORD [page(0:0..7): [0..377B), offset(0:8..15): [0..377B)];
LOOPHOLE[bandRecordBase[i].band, pageOffset].offset ← offset;
ENDLOOP;
END;
SetPageOffsets:
PUBLIC
PROC [linesFromLeft, wordTabFromBottom:
CARDINAL] = {
imageLoc.tab ← wordTabFromBottom; imageLoc.scans ← linesFromLeft};
ResetBands:
PUBLIC
PROC
RETURNS [Index,
LONG
POINTER] =
BEGIN
imageLoc.lastStartedBand ← nullIndex;
FOR i: Index ← firstBandRecord, i +
SIZE[BandRecord]
WHILE i < bandRecordLimit
DO bandRecordBase[i].status ← 0 ENDLOOP;
RETURN[firstBandRecord, @vBandBufferBase[bandRecordBase[firstBandRecord].band]]
END;
StartImage: PUBLIC PROC [band: Index] = {imageLoc.overrun ← 0; imageLoc.run ← band};
BandOverrun: PUBLIC PROC RETURNS [BOOLEAN] = {RETURN[imageLoc.overrun # 0]};
AdvanceBand:
PUBLIC
PROC [currentBand: Index]
RETURNS [Index,
LONG
POINTER] =
BEGIN
b: LONG POINTER TO BandRecord = @bandRecordBase[currentBand];
b.status ← LAST[INTEGER];
imageLoc.lastStartedBand ← currentBand;
RETURN[b.next, @vBandBufferBase[bandRecordBase[b.next].band]]
END;
BandFull:
PUBLIC
PROC [band: Index]
RETURNS [
BOOLEAN] = {
RETURN[bandRecordBase[band].status # 0]};
LastBand:
PUBLIC
PROC [band: Index] = {
bandRecordBase[band].status ← -1; imageLoc.lastStartedBand ← band};
send off a control word
Send:
PROC [w:
WORD] =
BEGIN
UNTIL controlLoc.status = 0 DO --GORP??-- ENDLOOP;
controlLoc.data ← w;
controlLoc.status ← LAST[WORD]
END;
InitializeCleanUp:
PUBLIC
PROC =
BEGIN
item: DeviceCleanup.Item;
saveCSB: ImageCSB;
maxWaitTime: LONG CARDINAL = LONG[27500]*(2*MaxBands);
waitTime: BasicTime.Pulses = BasicTime.MicrosecondsToPulses[maxWaitTime];
DO
reason: DeviceCleanup.Reason = DeviceCleanup.Await[@item];
SELECT reason
FROM
turnOff =>
BEGIN
then: BasicTime.Pulses = PrincOpsUtils.GetClockPulses[];
IF imageLoc.lastStartedBand # nullIndex THEN
WHILE (PrincOpsUtils.GetClockPulses[] - then) < waitTime AND bandRecordBase[imageLoc.lastStartedBand].status # 0 DO ENDLOOP;
saveCSB ← imageLoc^;
END;
turnOn =>
--restore csb; client will have to redo page.
{saveCSB.lastStartedBand ← nullIndex; imageLoc ^ ← saveCSB};
disconnect =>
{IF heldBandVM = VM.nullInterval THEN ERROR; -- Storage not allocated.
VMSideDoor.ReleaseSpecialRealMemory[heldBandVM];
heldBandVM ← VM.nullInterval};
ENDCASE;
ENDLOOP;
END;
Loader.MakeProcedureResident[AllocateBands];
Loader.MakeGlobalFrameResident[AllocateBands];
END...