<> <> <> <> <> <> <> <> <<>> <> 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]; <> <<>> <> <<>> <> <> 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; <> 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]; <> bandRecordLimit: Index = firstBandRecord + MaxBands*SIZE[BandRecord]; <> 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]. <> 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]; <> 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; <> 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: 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...