-- 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