-- ProcessorHeadDorado.mesa
-- Last Edited by: Taft, February 27, 1983 3:29 pm
DIRECTORY
BitBlt USING [BitBltTable, BitBltTablePtr, BITBLT],
DeviceCleanup USING [Perform],
DisplayFace USING [Cursor, CursorPtr, Point],
DoradoInputOutput USING [GetMemConfig, Halt, pagesPerBank, RWMufMan],
Environment USING [Byte, PageCount, maxPagesInVM, PageNumber],
Frame USING [GetReturnFrame, GetReturnLink, MyLocalFrame],
HeadStartChain USING [],
Inline USING [BITAND, BITOR, COPY, DIVMOD, LongCOPY, LongDiv, LongMult, LongNumber,
LowHalf, HighHalf],
MicrocodeBooting USING [BootFileNumber, MicrocodeType, nullBootFileNumber],
MicrocodeVersion USING [VersionResult],
MiscAlpha USING [aSETMP, aTEXTBLT],
Mopcodes USING [zMISC],
PilotMP USING [cClient, Code, cPowerOff],
PrincOps USING [ControlLink, FrameHandle, StateVector],
ProcessInternal USING [DisableInterrupts, EnableInterrupts],
ProcessorFace USING [GetClockPulses, gmtEpoch, GreenwichMeanTime, ProcessorID, SetMP],
SDDefs USING [SD, sUnimplemented],
SoftwareTextBlt USING [TextBlt],
System USING [gmtEpoch],
TrapSupport USING [BumpPC, OpTrapTable, opTrapTable];
ProcessorHeadDorado: PROGRAM
IMPORTS BitBlt, DeviceCleanup, DoradoInputOutput, Frame, Inline, ProcessInternal,
ProcessorFace, SoftwareTextBlt, TrapSupport
EXPORTS DoradoInputOutput, HeadStartChain, MicrocodeBooting, ProcessorFace
SHARES ProcessorFace =
BEGIN OPEN DoradoInputOutput;
-- ProcessorFace
-- Initialization
-- This is exported BOTH to ProcessorFace and to HeadStartChain.
-- Consequently it must not do anything besides cause a start trap on the first call.
Start: PUBLIC PROC = { -- By now start trap has occurred and main-body code has run--};
-- Processor id
processorID: PUBLIC ProcessorFace.ProcessorID ← GetProcessorID[];
baseProcessorIDDorado: ProcessorFace.ProcessorID = [a: 0, b: 52612B, c: 100000B];
GetProcessorID: PRIVATE PROC RETURNS [ProcessorFace.ProcessorID] =
BEGIN
doradoSN: [0..377B] ← 0;
FOR i: CARDINAL IN [0..7] DO
doradoSN ← 2*doradoSN + RWMufMan[[useDMD: FALSE, dMuxAddr: 2220B+i]].dMuxData;
ENDLOOP;
RETURN[[a: baseProcessorIDDorado.a,
b: baseProcessorIDDorado.b,
c: baseProcessorIDDorado.c + doradoSN]] -- note most significant first
END;
-- Real memory configuration
dedicatedRealMemory: PUBLIC Environment.PageCount ← 0;
-- Virtual memory layout
GetNextAvailableVM: PUBLIC PROC [page: Environment.PageNumber]
RETURNS [firstPage: Environment.PageNumber, count: Environment.PageCount] =
BEGIN
IF page < page1 THEN RETURN[page, page1 - page];
page ← MAX[page, page1 + 1];
IF page < page376B THEN RETURN[page, page376B - page];
page ← MAX[page, page376B + 1];
IF page < pageIO THEN RETURN[page, pageIO - page];
page ← MAX[page, pageIO + 1];
IF page < pageFirstUnimplemented THEN
RETURN[page, pageFirstUnimplemented - page];
RETURN[LAST[Environment.PageNumber], 0];
END;
-- I/O page for Alto-compatible display, cursor, mouse coords.
-- NOTE: even though we declare this page off-limits, Pilot boot files may
-- contain data for it. Therefore, Pilot boot devices (disk and Ethernet)
-- CANNOT use page1 for their CSBs.
page1: Environment.PageNumber = 1B;
-- I/O page for Alto-compatible keyboard/mouse bitmap
page376B: Environment.PageNumber = 376B;
-- I/O page for newly-written Pilot device microcode
pageIO: Environment.PageNumber = 377B;
-- First nonexistent VM page.
-- Note that Environment.PageNumber is presently a CARDINAL rather than a LONG CARDINAL.
pageFirstUnimplemented: Environment.PageNumber =
IF GetMemConfig[].virtualBanks > Environment.maxPagesInVM/pagesPerBank
THEN Environment.maxPagesInVM ELSE GetMemConfig[].virtualBanks * pagesPerBank;
-- Interval time
microsecondsPerHundredPulses: PUBLIC CARDINAL ← 32*100;
-- Naked notifies
cvTimeoutMask: WORD = 100000B; -- Dorado microcode assumes level 0
reservedNakedNotifyMask: PUBLIC WORD ← cvTimeoutMask;
-- Condition variable time
-- millisecondsPerTick is exported by UserTerminalHeadDorado,
-- since its value depends on the display refresh rate.
InitializeCVTimeouts: PROC =
BEGIN
DIW: LONG POINTER TO WORD = LOOPHOLE[LONG[421B]];
DIW↑ ← Inline.BITOR[DIW↑, cvTimeoutMask];
END;
-- Greenwich mean time
GetGreenwichMeanTime: PUBLIC PROC RETURNS [ProcessorFace.GreenwichMeanTime] =
BEGIN OPEN ProcessorFace;
IF gmtSimulated ~= gmtEpoch THEN -- don't update clock unless it has been set
BEGIN
seconds: GreenwichMeanTime =
(GetClockPulses[] - pulsesGmtSimulated)/pulsesPerSecond;
pulsesGmtSimulated ← pulsesGmtSimulated + seconds*pulsesPerSecond; -- long multiply!
gmtSimulated ← gmtSimulated + seconds;
END;
RETURN[gmtSimulated]
END;
SetGreenwichMeanTime: PUBLIC PROCEDURE [gmt: ProcessorFace.GreenwichMeanTime] =
BEGIN pulsesGmtSimulated ← ProcessorFace.GetClockPulses[]; gmtSimulated ← gmt; END;
gmtSimulated: ProcessorFace.GreenwichMeanTime ← ProcessorFace.gmtEpoch; -- => not set
pulsesGmtSimulated: LONG CARDINAL; -- interval timer value corresponding to gmtSimulated
pulsesPerSecond: LONG CARDINAL = Inline.LongDiv[1D6*100, microsecondsPerHundredPulses];
-- Booting and power control
BootButton: PUBLIC PROC =
BEGIN
ProcessInternal.DisableInterrupts[];
[] ← RWMufMan[[useDMD: TRUE, dMuxAddr: 2264B]]; -- Request BaseBoard boot
DO ENDLOOP;
END;
PowerOff: PUBLIC PROC =
BEGIN OPEN ProcessorFace;
-- Double-by-single multiply procedure, specially defined because the compiler would
-- otherwise generate calls to nonresident software routines in Instructions.mesa.
MultLCxC: PROC [lc: LONG CARDINAL, c: CARDINAL] RETURNS [LONG CARDINAL] = INLINE {
result: Inline.LongNumber ← [lc[Inline.LongMult[Inline.LowHalf[lc], c]]];
result.highbits ← result.highbits + Inline.HighHalf[lc]*c;
RETURN [result.lc]};
timeToGo: LONG INTEGER;
ProcessInternal.DisableInterrupts[];
DeviceCleanup.Perform[turnOff];
SetMP[PilotMP.cPowerOff];
timeToGo ← gmtAutomaticPowerOn - GetGreenwichMeanTime[];
-- Manifold 2262 turns the machine off indefinitely.
-- Manifold 2263 turns the machine off for a specified interval in units of 25.6 sec.
-- The interval must be left on the BMux when the machine halts.
IF gmtAutomaticPowerOn = gmtEpoch-1 THEN [] ← RWMufMan[[useDMD: TRUE, dMuxAddr: 2262B]]
ELSE IF timeToGo<26 THEN BootButton[]
ELSE [] ← RWMufMan[[useDMD: TRUE,
dMuxAddr: IF timeToGo >= (200000B*256)/10 THEN 2262B ELSE 2263B]];
Halt[Inline.LongDiv[MultLCxC[timeToGo, 10], 256]];
END;
gmtAutomaticPowerOn: ProcessorFace.GreenwichMeanTime;
SetAutomaticPowerOn: PUBLIC PROCEDURE [
gmt: ProcessorFace.GreenwichMeanTime, externalEvent: BOOLEAN] =
BEGIN gmtAutomaticPowerOn ← gmt; END;
ResetAutomaticPowerOn: PUBLIC PROCEDURE =
BEGIN
gmtAutomaticPowerOn ← ProcessorFace.gmtEpoch - 1; -- infinity
END;
-- MicrocodeBooting
BootSpecificMicrocode: PUBLIC PROCEDURE [bfn: MicrocodeBooting.BootFileNumber] =
BEGIN
microcodeBFNOffset: CARDINAL = 3000B; -- microcode boot server uses offset BFNs
ubfn: CARDINAL ← bfn-microcodeBFNOffset;
bootParameterSeal: CARDINAL = 56623B;
PushBootParams: PROCEDURE [ubfn, seal, checksum: CARDINAL] = MACHINE CODE {};
-- Push sealed and checksum boot file parameters on the stack for Initial to look at.
-- Note: in general calling BootButton with a non-empty stack would be illegal,
-- but is OK here because BootButton calls only machine code procedures.
IF bfn#MicrocodeBooting.nullBootFileNumber THEN
PushBootParams[ubfn, bootParameterSeal, 0-(ubfn+bootParameterSeal)];
BootButton[];
END;
GetBootFileNumber: PUBLIC PROCEDURE [type: MicrocodeBooting.MicrocodeType]
RETURNS [bfn: MicrocodeBooting.BootFileNumber] =
BEGIN
RETURN[[
SELECT type FROM
altoMesa => 3110B,
lisp => 3112B,
smalltalk76 => 3111B,
smalltalk80 => MicrocodeBooting.nullBootFileNumber,
pilotMesa, cedarMesa => 3113B,
ENDCASE => MicrocodeBooting.nullBootFileNumber]];
END;
-- TrapSupport.
UnimplementedInstruction: ERROR = CODE;
Unimplemented: PROCEDURE =
BEGIN
v: MACHINE DEPENDENT RECORD [a, b: UNSPECIFIED, state: PrincOps.StateVector];
v.state ← STATE;
ERROR UnimplementedInstruction;
END;
trapTable: TrapSupport.OpTrapTable ←
[ALL[LOOPHOLE[Unimplemented]], ALL[LOOPHOLE[Unimplemented]]];
-- Software assist for microcode
-- assumes return link is a frame, and has been started.
-- This trap procedure is called only if the Cedar TrapSupport microcode is NOT present.
-- If the microcode IS present, it calls the appropriate trap routine directly.
UnimplementedTrap: PROC =
BEGIN
l: PrincOps.ControlLink;
code: LONG POINTER TO PACKED ARRAY [0..0) OF Environment.Byte;
opcode: [0..400B);
state: PrincOps.StateVector;
state ← STATE;
state.source ← l ← Frame.GetReturnLink[];
code ← LOOPHOLE[l.frame.accesslink.code.longbase];
opcode ← code[l.frame.pc];
state.dest ← IF opcode # Mopcodes.zMISC THEN TrapSupport.opTrapTable.main[opcode]
ELSE TrapSupport.opTrapTable.misc[code[l.frame.pc+1]];
-- If handler is fixed-frame, manually plant the return link.
-- (Microcode does that for traps, but not for ordinary XFERs to frames.)
IF ~state.dest.proc THEN state.dest.frame.returnlink ← l;
RETURN WITH state; -- Flush my frame and transfer to real trap handler
END;
-- Handler for TEXTBLT trap.
-- The opcode actually takes a pile of arguments and returns a pile of results.
-- The trap handler is defined strangely in order to avoid needless pushing and popping.
TEXTBLTTrap: PROC =
BEGIN
-- TEXTBLT is a minimal-stack instruction, so no need to save state vector.
TextBlt: PROC = LOOPHOLE[SoftwareTextBlt.TextBlt];
TrapSupport.BumpPC[2];
TextBlt[];
END;
-- Fixed-frame handler for SetMP trap.
-- (Needs to be fixed-frame because SetMP may occur in contexts where
-- frame allocation is impossible.)
InitSetMPTrap: PROC =
BEGIN
GetCode: PROC RETURNS [code: PilotMP.Code] = MACHINE CODE BEGIN END;
code: PilotMP.Code;
cursorPtr: DisplayFace.CursorPtr = LOOPHOLE[LONG[431B]];
state: MACHINE DEPENDENT RECORD [a, b: UNSPECIFIED, v: PrincOps.StateVector];
TrapSupport.opTrapTable.misc[MiscAlpha.aSETMP].frame ← Frame.MyLocalFrame[];
state.v ← STATE;
ProcessInternal.DisableInterrupts[];
DO
state.v.dest ← Frame.GetReturnLink[];
ProcessInternal.EnableInterrupts[];
TRANSFER WITH state.v;
-- SetMP trap enters here with code on top of stack.
ProcessInternal.DisableInterrupts[];
code ← GetCode[];
state.v ← STATE;
TrapSupport.BumpPC[2];
IF code=PilotMP.cClient THEN cursorPtr↑ ← savedCursor
ELSE BEGIN
-- I should use the procedures exported through DisplayFace to do this,
-- but DisplayHeadDorado may not have been STARTed yet (or may not exist).
cursorPosition: LONG POINTER TO DisplayFace.Point = LOOPHOLE[LONG[426B]];
digit, digitOffset: CARDINAL;
cursorPosition↑ ← [x: 304, y: 404];
FOR i: CARDINAL IN [0..15] DO cursorPtr[i] ← 0; ENDLOOP;
FOR i: CARDINAL DECREASING IN [0..2] DO
[code, digit] ← Inline.DIVMOD[code, 10];
digitOffset ← digit*5;
bbPtr↑ ← [
dst: [word: cursorPtr, bit: 5*i],
dstBpl: 16,
src: [word: @digitFont + digitOffset/16, bit: digitOffset MOD 16],
srcDesc: [srcBpl[64]],
width: 5, height: 6, flags: [disjoint: TRUE, dstFunc: or]];
BitBlt.BITBLT[bbPtr];
ENDLOOP;
END;
ENDLOOP;
END;
-- These belong in SETMPTrap's local frame, but are here in the global frame
-- because if SETMPTrap's local frame is too large it causes frame allocation traps
-- during early initialization when they can't be handled.
-- Note: PrincOps BBTable must be 16-word aligned, but Dorado requires only 2-word.
bbTable: ARRAY[0..SIZE[BitBlt.BitBltTable]+1) OF UNSPECIFIED;
bbPtr: BitBlt.BitBltTablePtr = Inline.BITAND[@bbTable+1, 177776B];
digitFont: ARRAY [0..24) OF CARDINAL ← [
-- Strike-format font, densely packed, characters 6 high, 5 wide
30614B, 61474B, 167461B, 117000B,
45222B, 112441B, 512B, 57000B,
54202B, 22471B, 141062B, 57000B,
64214B, 14405B, 21111B, 157000B,
44220B, 117645B, 22110B, 57000B,
31736B, 60430B, 142063B, 117000B];
-- SetCursorPattern stores a copy of the real cursor here, and the SetMP trap handler
-- copies this into the real cursor whenever a code of cClient is posted, thereby
-- restoring the client's cursor across world-swaps. This can't be done by
-- UserTerminalHeadDorado's cleanup procedure, because calls to cleanup procedures
-- are surrounded by SetMPs, thereby clobbering the cursor.
savedCursor: PUBLIC DisplayFace.Cursor ← ALL[0];
-- Trap support for Cedar-related opcodes
LocalBlkZ: PROC [count: CARDINAL] =
BEGIN
state: PrincOps.StateVector;
p: POINTER;
state ← STATE;
TrapSupport.BumpPC[2];
IF count#0 THEN
BEGIN
p ← @(Frame.GetReturnFrame[].local[0]);
p↑ ← 0;
IF count#1 THEN Inline.COPY[from: p, to: p+1, nwords: count-1];
END;
state.dest.frame ← Frame.GetReturnFrame[];
RETURN WITH state;
END;
LongBlkZ: PROC [p: LONG POINTER, count: CARDINAL] RETURNS [resultP: LONG POINTER] =
BEGIN
state: PrincOps.StateVector;
state ← STATE;
TrapSupport.BumpPC[2];
IF count#0 THEN
BEGIN
p↑ ← 0;
IF count#1 THEN Inline.LongCOPY[from: p, to: p+1, nwords: count-1];
END;
resultP ← p;
state.dest.frame ← Frame.MyLocalFrame[];
TRANSFER WITH state;
END;
UVersion: PROC RETURNS [MicrocodeVersion.VersionResult] =
BEGIN
TrapSupport.BumpPC[2];
RETURN [[
machineType: dorado, majorVersion: 0, unused: 0,
floatingPoint: FALSE, cedar: FALSE, releaseDate: System.gmtEpoch/86400]];
END;
--
-- Initialization
InitializeCVTimeouts[];
SDDefs.SD[SDDefs.sUnimplemented] ← UnimplementedTrap;
SDDefs.SD[137B] ← @trapTable;
InitSetMPTrap[];
TrapSupport.opTrapTable.misc[MiscAlpha.aTEXTBLT] ← LOOPHOLE[TEXTBLTTrap];
TrapSupport.opTrapTable.misc[100B] ← LOOPHOLE[LocalBlkZ];
TrapSupport.opTrapTable.misc[102B] ← LOOPHOLE[LongBlkZ];
TrapSupport.opTrapTable.misc[104B] ← LOOPHOLE[UVersion];
ResetAutomaticPowerOn[];
END.
December 5, 1980 5:39 PM Taft Convert for Dorado; mostly remove D0 I/O junk
December 11, 1980 12:55 PM Taft Maint panel in cursor
9-Jun-81 18:59:01 Taft Export savedCursor; use it when SetMP code = cClient
7-Jul-81 19:50:43 Taft Use TrapSupport; pass TextBlt trap off to SoftwareTextBlt; fully implement GetNextAvailableVM; add PowerOff and residual stuff from GMTUsingIntervalTimer.
17-Aug-81 13:55:50 Taft Fixed frame handler for SetMP trap.
21-Aug-81 9:54:25 Taft BootButton now requests BaseBoard boot.
26-Sep-81 13:22:52 Taft Fix bug in PowerOff; fully implement SetAutomaticPowerOn.
22-Jun-82 14:59:02 Taft Implement and export MicrocodeBooting.
14-Jul-82 12:36:50 Taft Add trap support for LocalBlkZ, LongBlkZ, and UVersion opcodes.
September 28, 1982 3:55 pm Taft Do arithmetic right in PowerOff
February 13, 1983 1:21 pm Taft Remove machine code procs to DoradoInputOutput
February 27, 1983 2:31 pm Taft Export HeadStartChain.Start; absorb TrapSupportImpl