DIRECTORY
Basics USING [BITOR, bitsPerWord],
D0InputOutput
USING [
ControllerNumber, ControllerType, GetNextController, Input, millisecondsPerTick, null,
nullControllerNumber, uibScb, utvfc],
DeviceCleanup USING [Await, Item, Reason],
DisplayFace USING [Background, Cursor, CursorPtr, FieldRate, GlobalStatePtr, MonitorType, Point],
PrincOps USING [BBTable, PageCount, PageNumber, wordsPerPage],
PrincOpsUtils USING [AddressForPageNumber, LowHalf, PagesForWords],
KeyboardFace USING [KeyBits],
MouseFace USING [Buttons, Point],
ProcessorFace USING [GetClockPulses, microsecondsPerHundredPulses];
UserTerminalHeadD0:
PROGRAM
IMPORTS
Basics, D0InputOutput, DeviceCleanup, PrincOpsUtils, ProcessorFace
EXPORTS
DisplayFace, KeyboardFace, MouseFace =
BEGIN
DisplayFace
CSBPtr: TYPE = LONG POINTER TO CSBState;
CSBState:
TYPE =
MACHINE
DEPENDENT
RECORD [
dcbChainHead: PDCB, wakeupMask: WORD];
csbPtr: CSBPtr = LOOPHOLE[LONG[420B]]; -- SHOULD MOVE TO IO PAGE
PDCB: TYPE = POINTER TO DCB;
DCB:
TYPE =
MACHINE
DEPENDENT
RECORD [
-- address must be even
next: PDCB,
resolution: {high, low},
background: DisplayFace.Background,
indenting: [0..77B], -- in units of 16 bits
width: [0..377B], -- in units of 16 bits; must be even
shortBitmap: POINTER, -- must be even
tag: {short, long},
height: [0..77777B], -- in double scan lines
longBitmap: LONG POINTER]; -- must be even
UTVFCControlRegister:
TYPE =
MACHINE
DEPENDENT
RECORD [
not currently used
controlNibbles: [0..377B] ← 0,
IncNC: [0..1] ← 0,
PPBckGnd: [0..3] ← 0,
PPBlank, PPVS, PreOField, AllowWU, ClrNC: [0..1] ← 0];
UTVFCInputRegister:
TYPE =
MACHINE
DEPENDENT
RECORD [
controllerIDa: [0..377B] ← 2,
bitClockRate: [0..37B],
controllerIDb: [0..3] ← 2,
test: [0..1]];
cslBitClockRate: [0..37B] = 5B;
lfBitClockRate: [0..37B] = 3B;
displayState: {disconnected, off, on} ← disconnected;
bitmapBase: LONG POINTER; -- undefined if displayState=disconnected
controllerType: D0InputOutput.ControllerType;
controller: D0InputOutput.ControllerNumber;
pDCBReal: LONG POINTER TO DCB;
pDCBBlank: LONG POINTER TO DCB;
pDCBNull: PDCB = LOOPHOLE[0];
hasBuffer: PUBLIC BOOLEAN ← FALSE;
pagesForBitmap: PUBLIC PrincOps.PageCount; -- see initialization below
Connect:
PUBLIC
SAFE
PROCEDURE [bitmap: PrincOps.PageNumber] =
TRUSTED
BEGIN
displayState ← off;
bitmapBase ← PrincOpsUtils.AddressForPageNumber[bitmap];
LongPointerFromPage
csbPtr.dcbChainHead ← PrincOpsUtils.LowHalf[pDCBBlank]; -- DCB's are in first64K
END;
Disconnect:
PUBLIC
SAFE
PROCEDURE =
TRUSTED
{displayState ← disconnected; csbPtr.dcbChainHead ← pDCBNull};
TurnOn:
PUBLIC
SAFE
PROCEDURE =
TRUSTED
BEGIN
IF displayState = disconnected THEN ERROR;
displayState ← on;
pDCBReal.longBitmap ← bitmapBase;
csbPtr.dcbChainHead ← PrincOpsUtils.LowHalf[pDCBReal] -- DCB's are in first64K
END;
TurnOff:
PUBLIC
SAFE
PROCEDURE =
TRUSTED
BEGIN
IF displayState = disconnected THEN ERROR;
displayState ← off;
csbPtr.dcbChainHead ← PrincOpsUtils.LowHalf[pDCBBlank]; -- DCB's are in first64K
END;
GetBitBltTable:
PUBLIC
SAFE
PROCEDURE
RETURNS [PrincOps.BBTable] =
TRUSTED
BEGIN
IF displayState = disconnected THEN ERROR;
RETURN[[
dst: [word: bitmapBase, bit: 0], dstBpl: bitmapWidth,
src: [word: bitmapBase, bit: 0], srcDesc: [srcBpl[bitmapWidth]],
width: width, height: height, flags: []]];
END;
SetBackground:
PUBLIC
SAFE
PROCEDURE [background: DisplayFace.Background] =
TRUSTED
{pDCBReal.background ← pDCBBlank.background ← background};
See Start for initialization:
width:
PUBLIC
NAT ← lfWordsPerLine*Basics.bitsPerWord;
cslWordsPerLine: CARDINAL = 38;
lfWordsPerLine: CARDINAL = 64;
torWordsPerLine: CARDINAL = 40;
Size of bitmap, possibly large than screen image (initialized in Start):
bitmapWidth: CARDINAL ← lfWordsPerLine*Basics.bitsPerWord;
See Start for initialization:
height:
PUBLIC
NAT ← 808;
-- LF and CSL
torHeight: CARDINAL = 800;
pixelsPerInch: PUBLIC CARDINAL ← 72;
See Start for initialization:
refreshRate:
PUBLIC
CARDINAL ← lfRefreshRate;
-- frames (two fields) per second
cslRefreshRate: CARDINAL = 30;
lfRefreshRate: CARDINAL = 38; -- actually ??
interlaced: PUBLIC BOOLEAN ← TRUE;
SetScanLineWakeup not implemented.
GetScanLine not implemented.
hasBorder: PUBLIC BOOLEAN ← FALSE;
SetBorderPattern: PUBLIC SAFE PROCEDURE [oddPairs, evenPairs: [0..377B]] = CHECKED{};
pHardwareCursor: DisplayFace.CursorPtr =
LOOPHOLE[
LONG[431B]];
SHOULD BE IN IO PAGE
SetCursorPattern:
PUBLIC
SAFE
PROCEDURE [cursorPtr: DisplayFace.CursorPtr] =
TRUSTED
BEGIN pHardwareCursor^ ← cursorPtr^ END;
cursorPosition:
PUBLIC
LONG
POINTER
TO DisplayFace.Point ←
LOOPHOLE[LONG[426B]];
globalStateSize: PUBLIC CARDINAL ← SIZE[DCB]*2;
InitializeCleanup:
PUBLIC
SAFE
PROCEDURE =
TRUSTED
BEGIN OPEN DeviceCleanup;
item: Item;
reason: Reason;
state: CSBState;
mouseCoord: MouseFace.Point;
cursorCoord: DisplayFace.Point;
cursor: DisplayFace.Cursor;
timeDone: LONG CARDINAL;
maxPulsesPerRefresh:
LONG
CARDINAL =
2*
--for safety--
(
LONG[100]*
--pulsesPerHundredPulses--1000000
--microsecondsPerSecond--
)/(
LONG[refreshRate]
--framesPerSecond--
*ProcessorFace.microsecondsPerHundredPulses);
DO
reason ← Await[@item];
SELECT reason
FROM
turnOff =>
BEGIN
state ← csbPtr^;
mouseCoord ← mouse^;
cursorCoord ← cursorPosition^;
cursor ← pHardwareCursor^;
csbPtr.dcbChainHead ← pDCBNull;
timeDone ← ProcessorFace.GetClockPulses[];
WHILE ProcessorFace.GetClockPulses[] - timeDone < maxPulsesPerRefresh
DO
ENDLOOP;
END;
turnOn =>
BEGIN
mouse^ ← mouseCoord;
cursorPosition^ ← cursorCoord;
pHardwareCursor^ ← cursor;
csbPtr^ ← state;
END;
ENDCASE;
ENDLOOP;
END;
Initialize:
PUBLIC
PROCEDURE [
globalState: DisplayFace.GlobalStatePtr, wakeVF: WORD] =
BEGIN
dcb:
DCB =
[next: pDCBNull, resolution: high, background: white, indenting: 0,
width: 0, shortBitmap: NIL, tag: long, height: 0, longBitmap: NIL];
csbPtr.wakeupMask ← Basics.BITOR[wakeVF, csbPtr.wakeupMask];
pDCBBlank ← globalState;
pDCBReal ← globalState + SIZE[DCB];
pDCBBlank^ ← pDCBReal^ ← dcb;
pDCBReal.width ← width/Basics.bitsPerWord;
pDCBReal.height ← height/2;
END;
monitorType: PUBLIC DisplayFace.MonitorType ← lf; -- changed in Init
SetFieldRate:
PUBLIC
SAFE
PROCEDURE [rate: DisplayFace.FieldRate]
RETURNS [ok: BOOLEAN] = CHECKED
BEGIN
RETURN [
SELECT monitorType
FROM
alto => rate=normalAlto,
lf => rate=normalLF,
ENDCASE => FALSE];
END;
SetVerticalWaveforms:
PUBLIC
SAFE
PROCEDURE [sync, visible, topBorder:
CARDINAL]
RETURNS [ok: BOOLEAN] = CHECKED
{RETURN [FALSE]};
KeyboardFace
keyboard:
PUBLIC
LONG
POINTER
TO
READONLY KeyboardFace.KeyBits ←
LOOPHOLE[LONG[177033B]];
MouseFace
position: PUBLIC LONG POINTER TO READONLY MouseFace.Point ← mouse;
SetPosition:
PUBLIC
SAFE
PROCEDURE [newMousePosition: MouseFace.Point] =
TRUSTED
BEGIN mouse^ ← newMousePosition END;
buttons:
PUBLIC
LONG
POINTER
TO
READONLY MouseFace.Buttons ←
LOOPHOLE[keyboard];
mouse: LONG POINTER TO MouseFace.Point = LOOPHOLE[LONG[424B]];
Initialization
Init:
PROCEDURE =
BEGIN OPEN D0InputOutput;
cslMillisecondsPerTick: CARDINAL = 50;
lfMillisecondsPerTick: CARDINAL = 40; -- actually 39.7
torMillisecondsPerTick: CARDINAL = 40; -- what should this be?
D0InputOutput.millisecondsPerTick ← lfMillisecondsPerTick;
IF (controller ← GetNextController[utvfc, nullControllerNumber]) ~=
nullControllerNumber THEN
BEGIN
inputReg: UTVFCInputRegister = Input[[controller: controller, register: 0]];
controllerType ← utvfc;
IF inputReg.bitClockRate = cslBitClockRate
THEN
BEGIN
monitorType ← alto;
bitmapWidth ← width ← cslWordsPerLine*Basics.bitsPerWord;
refreshRate ← cslRefreshRate;
D0InputOutput.millisecondsPerTick ← cslMillisecondsPerTick;
END;
END
ELSE
IF (controller ← GetNextController[uibScb, nullControllerNumber]) ~=
nullControllerNumber THEN
BEGIN
monitorType ← lf;
controllerType ← uibScb;
width ← torWordsPerLine*Basics.bitsPerWord;
bitmapWidth ← torWordsPerLine*Basics.bitsPerWord;
height ← torHeight;
D0InputOutput.millisecondsPerTick ← torMillisecondsPerTick;
END
ELSE controllerType ← null;
pagesForBitmap ←
PrincOpsUtils.PagesForWords[(bitmapWidth.LONG/Basics.bitsPerWord)*height];
csbPtr.dcbChainHead ← pDCBNull; -- DCB's are in first64K
END;
Init[];
END.