-- UserTeminalHeadDLion.mesa -- Last Edited by: Taft, February 27, 1983 3:27 pm DIRECTORY BitBlt USING [BBTable], DeviceCleanup USING [Await, Item, Reason], DisplayFace, DisplayFaceExtras USING [FieldRate, MonitorType], DLionInputOutput USING [firstReservedPage, IOPage, SetReservedMemoryUse], Environment USING [bitsPerWord, PageCount, PageNumber, wordsPerPage], HeadStartChain, Inline USING [BITOR, LongCOPY, LongDiv, LowHalf], KeyboardFace, KeyStations USING [KeyBits], MouseFace, PageMap USING [Assoc, flagsClean, RealPageNumber, Value, valueVacant], Process USING [GetPriority, MsecToTicks, Pause, Priority, priorityInterrupt, SetPriority], SoundGenerator USING [], Utilities USING [LongPointerFromPage, PageFromLongPointer]; UserTerminalHeadDLion: MONITOR IMPORTS DeviceCleanup, DLionInputOutput, Inline, RemainingHeads: HeadStartChain, PageMap, Process, Utilities EXPORTS DisplayFace, DisplayFaceExtras, HeadStartChain, KeyboardFace, MouseFace, SoundGenerator SHARES PageMap = BEGIN OPEN Environment; CSB: TYPE = MACHINE DEPENDENT RECORD [ wakeups: WORD, --vertical field wake up bits-- off: BOOLEAN, unused: [0..7], invert, disconnect: BOOLEAN, line: CARDINAL [0..1024), border: RECORD [oddPairs, evenPairs: [0..400B)], cursor: DisplayFace.Point, --cursor location-- map: DisplayFace.Cursor --cursor bit map-- ]; csb: LONG POINTER TO CSB = LOOPHOLE[DLionInputOutput.IOPage + 353B]; --FFEB-- hasBuffer: PUBLIC BOOLEAN ← TRUE; width: PUBLIC CARDINAL [0..32767] ← 1024; height: PUBLIC CARDINAL [0..32767] ← 808; pagesForBitmap: PUBLIC Environment.PageCount ← (height*(width/bitsPerWord) + wordsPerPage - 1)/wordsPerPage; -- DisplayFace Implementation bitmapAddress: LONG POINTER ← NIL; -- it should it be an ERROR to this if already connected -- or to turn on/off a disconnected display Connect: PUBLIC PROC [bitMap: PageNumber] = BEGIN rp: PageMap.RealPageNumber ← DLionInputOutput.firstReservedPage; DLionInputOutput.SetReservedMemoryUse[Display]; csb.off ← TRUE; csb.disconnect ← FALSE; FOR vp: PageNumber IN [bitMap..bitMap + pagesForBitmap) DO PageMap.Assoc[vp, [FALSE, PageMap.flagsClean, rp]]; rp ← rp + 1 ENDLOOP; bitmapAddress ← Utilities.LongPointerFromPage[bitMap]; bitmapAddress↑ ← 0; Inline.LongCOPY[ from: bitmapAddress, nwords: pagesForBitmap*wordsPerPage - 1, to: bitmapAddress + 1]; END; Disconnect: PUBLIC PROC = BEGIN p: CARDINAL = Utilities.PageFromLongPointer[bitmapAddress]; csb.off ← TRUE; csb.disconnect ← TRUE; IF bitmapAddress # NIL THEN FOR vp: PageNumber IN [p..p + pagesForBitmap) DO PageMap.Assoc[vp, PageMap.valueVacant] ENDLOOP; bitmapAddress ← NIL; DLionInputOutput.SetReservedMemoryUse[notBusy]; END; TurnOn: PUBLIC PROC = {csb.off ← FALSE}; TurnOff: PUBLIC PROC = {csb.off ← TRUE}; GetBitBltTable: PUBLIC PROC RETURNS [BitBlt.BBTable] = BEGIN RETURN[ [dst: [word: bitmapAddress, bit: 0], dstBpl: width, src: [word: bitmapAddress, bit: 0], srcDesc: [srcBpl[width]], width: width, height: height, flags: []]] END; pixelsPerInch: PUBLIC CARDINAL ← 75; refreshRate: PUBLIC CARDINAL ← 39; interlaced: PUBLIC BOOLEAN ← TRUE; SetBackground: PUBLIC PROC [b: DisplayFace.Background] = {csb.invert ← (b = black)}; hasBorder: PUBLIC BOOLEAN ← TRUE; SetBorderPattern: PUBLIC PROC [oddPairs, evenPairs: [0..377B]] = {csb.border ← [oddPairs, evenPairs]}; SetCursorPattern: PUBLIC PROC [p: DisplayFace.CursorPtr] = {csb.map ← p↑}; cursorPosition: PUBLIC LONG POINTER TO DisplayFace.Point ← @csb.cursor; globalStateSize: PUBLIC CARDINAL ← 0; Initialize: PUBLIC PROC [globalState: DisplayFace.GlobalStatePtr, wakeVF: WORD] = BEGIN csb↑ ← CSB[ wakeups: Inline.BITOR[wakeVF, csb.wakeups], off: NULL, unused: 0, invert: FALSE, disconnect: TRUE, line: 0, border: [210B, 42B], cursor: [0,0], map: ALL[0]]; pSGCSB↑ ← SoundGeneratorCSB[ busy: FALSE, command: NULL, period: 0]; END; -- DisplayFaceExtras. monitorType: PUBLIC DisplayFaceExtras.MonitorType ← lf; SetFieldRate: PUBLIC PROCEDURE [rate: DisplayFaceExtras.FieldRate] RETURNS [ok: BOOLEAN] = {RETURN [rate=normalLF]}; SetVerticalWaveforms: PUBLIC PROCEDURE [sync, visible, topBorder: CARDINAL] RETURNS [ok: BOOLEAN] = {RETURN [FALSE]}; -- KeyboardFace keyboard: PUBLIC LONG POINTER TO READONLY KeyStations.KeyBits ← LOOPHOLE[DLionInputOutput.IOPage + 72B]; --FF3A -- MouseFace position: PUBLIC LONG POINTER TO READONLY MouseFace.Point ← LOOPHOLE[DLionInputOutput.IOPage + 70B]; --FF38 buttons: PUBLIC LONG POINTER TO READONLY MouseFace.Buttons ← LOOPHOLE[keyboard]; --FF3A setPosition: LONG POINTER TO MACHINE DEPENDENT RECORD [ point(0:0..31): MouseFace.Point, busy(2:0..0): BOOLEAN, fill(2:1..15): [0..32767]] = LOOPHOLE[DLionInputOutput.IOPage + 133B]; --FF5B SetPosition: PUBLIC PROC [p: MouseFace.Point] = BEGIN DO LOOPHOLE[position, LONG POINTER TO MouseFace.Point]↑ ← p; IF ~setPosition.busy THEN EXIT ENDLOOP; setPosition.point ← p; setPosition.busy ← TRUE; END; -- Sound Generator implementation SoundGeneratorCSBOffset: CARDINAL = 136B; -- = 0101 1110 = 5EX SoundGeneratorCSB: TYPE = MACHINE DEPENDENT RECORD [ busy (0:0..0): BOOLEAN, command (0:1..15): MACHINE DEPENDENT {start (0), stop (1)}, period (1:0..15): CARDINAL]; -- = 1843200/f, where f is frequency in Hz pSGCSB: LONG POINTER TO SoundGeneratorCSB = DLionInputOutput.IOPage + SoundGeneratorCSBOffset; -- Beep wants to run at interrupt priority, so it can accurately time -- the duration of the beep. Either interrupt priority should have an extra -- state vector, or Beep's code (and local and global frame) must be pinned. Beep: PUBLIC ENTRY PROC [frequency: CARDINAL, duration: CARDINAL] = BEGIN OPEN Inline; priority: Process.Priority = Process.GetPriority[]; aborted: BOOLEAN ← FALSE; WHILE pSGCSB.busy DO ENDLOOP; Process.SetPriority[MAX[Process.priorityInterrupt, priority]]; -- The MAX in the next statement prevents the LowHalf from overflowing. -- The period (in usec*1.8432) will be in the range [~29..63535]. pSGCSB.period ← LowHalf[LongDiv[1843200, MAX[frequency, 29]]]; pSGCSB.command ← start; pSGCSB.busy ← TRUE; WHILE pSGCSB.busy DO ENDLOOP; Process.Pause[Process.MsecToTicks[duration] ! ABORTED => {aborted ← TRUE; CONTINUE}]; pSGCSB.command ← stop; pSGCSB.busy ← TRUE; WHILE pSGCSB.busy DO ENDLOOP; Process.SetPriority[priority]; IF aborted THEN RETURN WITH ERROR ABORTED; END; -- Display/Raven/Sound Generator cleanup Proc InitializeCleanup: PUBLIC PROC = BEGIN OPEN DeviceCleanup; csbState: CSB; sgcsbState: SoundGeneratorCSB; item: Item; mousePos: MouseFace.Point; DO reason: Reason = Await[@item]; SELECT reason FROM turnOff, kill => BEGIN csbState ← csb↑; csb.off ← TRUE; mousePos ← position↑; THROUGH [0..8000] DO --wait for field-- ENDLOOP; THROUGH [0..30000] DO IF ~pSGCSB.busy THEN EXIT ENDLOOP; -- stop sound generator sgcsbState ← pSGCSB↑; pSGCSB.command ← stop; pSGCSB.busy ← TRUE; THROUGH [0..30000] DO IF ~pSGCSB.busy THEN EXIT ENDLOOP; END; turnOn => BEGIN setPosition.point ← mousePos; setPosition.busy ← TRUE; LOOPHOLE[position, LONG POINTER TO MouseFace.Point]↑ ← mousePos; pSGCSB↑ ← sgcsbState; csb↑ ← csbState; END; disconnect => IF bitmapAddress # NIL THEN BEGIN p: CARDINAL = Utilities.PageFromLongPointer[bitmapAddress]; FOR vp: PageNumber IN [p..p + pagesForBitmap) DO PageMap.Assoc[vp, PageMap.valueVacant] ENDLOOP; END; ENDCASE; ENDLOOP; END; -- Start Chain Start: PUBLIC PROC = {setPosition.fill ← 0; RemainingHeads.Start[]}; END.... February 27, 1983 2:12 pm Taft DisplayFaceExtras