RavenHeadDLion.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
last edit by Govvel on February 4, 1981 2:50 PM
last edit by Jarvis on July 30, 1980 1:47 PM
ast edit by Olmstead on October 31, 1980 9:07 AM
last edit by Forrect on December 1, 1980 1:52 PM
Tim Diebert: January 22, 1987 12:26:09 pm PST
To do: bury ImageCSB.lineSize into the microcode. Re-arrange ImageCSB to make fields the microcode cares about contiguous.
Reconstructed from the Pilot 6 listing.
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];
RavenHeadDLion: PROGRAM
IMPORTS BasicTime, DeviceCleanup, DLionInputOutput, Loader, PrincOpsUtils, VM, VMSideDoor
EXPORTS RavenFace =
BEGIN OPEN RavenFace;
resolution: PUBLIC ResolutionPair ← [300, 300];
size: PUBLIC SizePair ← [300*11, 8*300+300/2];
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...