ProcessorHeadD0.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Taft, February 27, 1983 3:26 pm
Birrell, November 3, 1983 1:19 pm
Willie-Sue, January 31, 1985 1:47:52 pm PST
Russ Atkinson (RRA) February 27, 1985 8:31:58 pm PST
Doug Wyatt, February 26, 1985 5:55:44 pm PST
DIRECTORY
Basics USING [BITOR, LongDiv],
D0InputOutput USING [ControllerNumber, ControllerType, CSBArray, Input, null, nullControllerNumber, rdc, rdcWithServiceLate],
DeviceCleanup USING [Await, Item, Perform, Reason],
MicrocodeBooting USING [BootFileNumber, MicrocodeType, nullBootFileNumber],
PrincOps USING [aLOADRAMJ, aREADRAM, ControlLink, FrameHandle, PageCount, RealPageNumber, SD, StateVector, sUnimplemented, PageNumber, VersionResult, wordsPerPage, zMISC],
PrincOpsUtils USING [Copy, DisableInterrupts, LongCopy, GetReturnFrame, GetReturnLink, MyLocalFrame],
ProcessorFace USING [GetClockPulses, gmtEpoch, GreenwichMeanTime, ProcessorID],
TrapSupport USING [BumpPC, OpTrapTable, opTrapTable];
ProcessorHeadD0: MONITOR -- Protects GreenwichMeanTime calculation
IMPORTS Basics, D0InputOutput, DeviceCleanup, PrincOpsUtils, ProcessorFace, TrapSupport
EXPORTS D0InputOutput, MicrocodeBooting, ProcessorFace
SHARES ProcessorFace = PUBLIC { OPEN D0InputOutput;
D0InputOutput
IOPage: LONG POINTER TO CSBArray ← LOOPHOLE[pageIO*PrincOps.wordsPerPage];
firstController: ControllerNumber = 4B; -- tasks 0B thru 3B taken up by emulator
lastController: ControllerNumber = 15B; -- tasks 16B and 17B taken by timers and faults
ControllerIndex: TYPE = ControllerNumber [firstController..lastController];
controllerRoster: ARRAY ControllerIndex OF ControllerType ← ALL[null];
GetNextController: PROC [type: ControllerType, prev: ControllerNumber] RETURNS [ControllerNumber] = {
i: ControllerIndex;
FOR i DECREASING IN ControllerIndex DO
IF type = controllerRoster[i] AND (prev = nullControllerNumber OR prev > i) THEN RETURN[i];
ENDLOOP;
RETURN[nullControllerNumber]
};
InitializeD0InputOutput: PRIVATE PROC = {
IDRegister: TYPE = MACHINE DEPENDENT RECORD [
type: ControllerType, lowByte: [0..256)];
r: IDRegister; -- code generator bug in 6.0n requires this
idRegNo: [0..17B] = 0;
i: ControllerIndex;
t: ControllerType;
Initialization microcode really should have put roster into memory somewhere.
FOR i IN ControllerIndex DO
r ← LOOPHOLE[Input[[controller: i, register: idRegNo]], IDRegister];
t ← r.type;
IF t = rdcWithServiceLate THEN t ← rdc; -- #*%$@!! RDC
controllerRoster[i] ← t;
ENDLOOP;
};
ProcessorFace
Processor id
processorID: ProcessorFace.ProcessorID ← GetProcessorID[];
GetProcessorID: PRIVATE PROC RETURNS [ProcessorFace.ProcessorID] = {
csw: CSWord = ReadRam[7777B];
CSWord: TYPE = MACHINE DEPENDENT RECORD [
bits16To31: CARDINAL,
bits0To15: CARDINAL,
bits32To35: [0..17B],
address: [0..7777B]];
ReadRam: PROC [address: [0..7777B]] RETURNS [CSWord] =
MACHINE CODE { PrincOps.zMISC, PrincOps.aREADRAM };
RETURN[[0, csw.bits0To15, csw.bits16To31]] -- note most significant first
};
Real memory configuration
dedicatedRealMemory: PrincOps.PageCount ← 0;
firstSpecialRealPage: PUBLIC PrincOps.RealPageNumber ← 0;
specialRealPages: PUBLIC PrincOps.PageCount ← 0;
Virtual memory layout
GetNextAvailableVM: SAFE PROC [page: PrincOps.PageNumber] RETURNS [firstPage: PrincOps.PageNumber, count: PrincOps.PageCount] = CHECKED {
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[PrincOps.PageNumber], 0];
};
useLongMapOps: PUBLIC BOOLFALSE;
The Dolphin can not use the long map ops.
page1: PRIVATE PrincOps.PageNumber = 1B;
I/O page for Alto-compatible Diablo31, display, cursor, mouse coords
page376B: PRIVATE PrincOps.PageNumber = 376B;
I/O page for Alto-compatible keyboard/mouse bitmap
pageIO: PRIVATE PrincOps.PageNumber = 377B; -- "official" D0 I/O page
pageFirstUnimplemented: PRIVATE PrincOps.PageNumber = 40000B;
[pageFirstUnimplemented..LAST[PageNumber]] not implemented
Interval time
microsecondsPerHundredPulses: CARDINAL;
InitializeClockRate: PRIVATE PROC = {
ReadRegister: PROC [address: [0..377B]] RETURNS [UNSPECIFIED] = MACHINE CODE {
PrincOps.zMISC, 106B};
The number read here is proportional to clock ticks per unit of time,
where the value 320 denotes 1 tick every 64 microseconds.
clockRate: CARDINAL = ReadRegister[323B];
microsecondsPerHundredPulses ← Basics.LongDiv[LONG[100]*64*320, clockRate];
};
Greenwich mean time
GetGreenwichMeanTime: PUBLIC ENTRY SAFE PROC RETURNS [ProcessorFace.GreenwichMeanTime] = CHECKED{
OPEN ProcessorFace;
ENABLE UNWIND => NULL;
IF gmtSimulated ~= gmtEpoch THEN {-- don't update clock unless it has been set
seconds: GreenwichMeanTime =
(GetClockPulses[] - pulsesGmtSimulated)/pulsesPerSecond;
pulsesGmtSimulated ← pulsesGmtSimulated + seconds*pulsesPerSecond; -- long multiply!
gmtSimulated ← gmtSimulated + seconds;
};
RETURN[gmtSimulated]
};
SetGreenwichMeanTime: PUBLIC ENTRY SAFE PROC [gmt: ProcessorFace.GreenwichMeanTime] = CHECKED {
ENABLE UNWIND => NULL;
pulsesGmtSimulated ← ProcessorFace.GetClockPulses[];
gmtSimulated ← gmt
};
gmtSimulated: ProcessorFace.GreenwichMeanTime ← ProcessorFace.gmtEpoch; -- => not set
pulsesGmtSimulated: LONG CARDINAL; -- interval timer value corresponding to gmtSimulated
pulsesPerSecond: LONG CARDINAL;
Naked notifies
cvTimeoutMask: PRIVATE WORD = 100000B; -- D0 microcode assumes level 0
reservedNakedNotifyMask: WORD ← cvTimeoutMask;
Condition variable time
millisecondsPerTick: PUBLIC CARDINAL ← 40; -- the correct value is set by UserTerminalHead
InitializeCVTimeouts: PRIVATE PROC = {
DIW: LONG POINTER TO WORD = LOOPHOLE[LONG[421B]];
DIW^ ← Basics.BITOR[DIW^, cvTimeoutMask];
};
Booting and power control
BootButton: SAFE PROC = TRUSTED {
LoadRam: PROC [pMicrocode: LONG POINTER, andJump: BOOL] =
MACHINE CODE { PrincOps.zMISC, PrincOps.aLOADRAMJ };
bootMe: ARRAY [0..7) OF WORD
[000000B, 170000B, 000047B, 015000B, 177760B, 163351B, 007400B];
LoadRam[@bootMe, TRUE] -- never returns
};
PowerOff: PUBLIC SAFE PROC [returnIfDisabled: BOOLFALSE] = TRUSTED {
OPEN ProcessorFace;
IF powerOffCount # 0 AND returnIfDisabled THEN RETURN;
PrincOpsUtils.DisableInterrupts[];
DeviceCleanup.Perform[turnOff];
DO
ENDLOOP;
};
powerOffCount: INT ← 0;
DisablePowerOff: PUBLIC ENTRY SAFE PROC = TRUSTED {
Bumps the power off disable count. This is useful during a critical operation to avoid power off operations.
powerOffCount ← powerOffCount + 1;
};
EnablePowerOff: PUBLIC ENTRY SAFE PROC = TRUSTED {
Decrements the power off disable count (pins at 0).
IF powerOffCount > 0 THEN powerOffCount ← powerOffCount - 1;
};
gmtAutomaticPowerOn: ProcessorFace.GreenwichMeanTime;
SetAutomaticPowerOn: PUBLIC SAFE PROC [gmt: ProcessorFace.GreenwichMeanTime, externalEvent: BOOL] = TRUSTED {
};
ResetAutomaticPowerOn: PUBLIC SAFE PROC = TRUSTED {
};
MicrocodeBooting; degenerate implementation for now
BootSpecificMicrocode: PUBLIC PROC [bfn: MicrocodeBooting.BootFileNumber] = {
BootButton[];
};
GetBootFileNumber: PUBLIC PROC [type: MicrocodeBooting.MicrocodeType] RETURNS [bfn: MicrocodeBooting.BootFileNumber] = {
RETURN[MicrocodeBooting.nullBootFileNumber];
};
TrapSupport.
UnimplementedInstruction: ERROR = CODE;
Unimplemented: PROC = {
v: MACHINE DEPENDENT RECORD [a, b: UNSPECIFIED, state: PrincOps.StateVector];
v.state ← STATE;
ERROR UnimplementedInstruction;
};
trapTable: TrapSupport.OpTrapTable ←
[ALL[LOOPHOLE[Unimplemented]], ALL[LOOPHOLE[Unimplemented]]];
UnimplementedTrap: PROC = {
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.
l: PrincOps.ControlLink;
code: LONG POINTER TO PACKED ARRAY [0..0) OF [0..377B];
opcode: [0..400B);
state: PrincOps.StateVector;
state ← STATE;
state.source ← l ← PrincOpsUtils.GetReturnLink[];
code ← LOOPHOLE[l.frame.accesslink.code.longbase];
opcode ← code[l.frame.pc];
state.dest ← IF opcode # PrincOps.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
};
Trap support for Cedar-related opcodes
LocalBlkZ: PROC [count: CARDINAL] = {
state: PrincOps.StateVector;
p: POINTER;
state ← STATE;
TrapSupport.BumpPC[2];
IF count#0 THEN {
p ← @(PrincOpsUtils.GetReturnFrame[].local[0]);
p^ ← 0;
IF count#1 THEN PrincOpsUtils.Copy[from: p, to: p+1, nwords: count-1];
};
state.dest.frame ← PrincOpsUtils.GetReturnFrame[];
RETURN WITH state;
};
LongBlkZ: PROC [p: LONG POINTER, count: CARDINAL] RETURNS [resultP: LONG POINTER] = {
state: PrincOps.StateVector;
state ← STATE;
TrapSupport.BumpPC[2];
IF count#0 THEN {
p^ ← 0;
IF count#1 THEN PrincOpsUtils.LongCopy[from: p, to: p+1, nwords: count-1];
};
resultP ← p;
state.dest.frame ← PrincOpsUtils.MyLocalFrame[];
TRANSFER WITH state;
};
UVersion: PROC RETURNS [PrincOps.VersionResult] = {
TrapSupport.BumpPC[2];
RETURN [[
machineType: dolphin, majorVersion: 0, unused: 0,
floatingPoint: FALSE, cedar: FALSE, releaseDate: ProcessorFace.gmtEpoch/86400]];
};
READRTrap: PROC [reg: [0..377]] RETURNS [UNSPECIFIED] = {
If READR traps, assume we are reading the clock rate (see InitializeClockRate above)
and return a value denoting a 40 MHz crystal and 2560 cycles per clock tick.
TrapSupport.BumpPC[2];
RETURN [320];
};
Initialization
Go: PUBLIC SAFE PROC = CHECKED{-- By now start trap has occurred and main-body code has run--};
InitializeCleanup: PUBLIC SAFE PROC = TRUSTED {
OPEN DeviceCleanup;
item: Item;
reason: Reason;
DO
reason ← Await[@item];
SELECT reason FROM
turnOff, kill => gmtSimulated ← ProcessorFace.gmtEpoch;
ENDCASE
ENDLOOP
};
InitializeCVTimeouts[];
InitializeD0InputOutput[];
PrincOps.SD[PrincOps.sUnimplemented] ← LOOPHOLE[UnimplementedTrap];
PrincOps.SD[137B] ← LOOPHOLE[@trapTable];
TrapSupport.opTrapTable.misc[100B] ← LOOPHOLE[LocalBlkZ];
TrapSupport.opTrapTable.misc[102B] ← LOOPHOLE[LongBlkZ];
TrapSupport.opTrapTable.misc[104B] ← LOOPHOLE[UVersion];
TrapSupport.opTrapTable.misc[106B] ← LOOPHOLE[READRTrap];
InitializeClockRate[];
pulsesPerSecond ← Basics.LongDiv[1D6*100, microsecondsPerHundredPulses];
}.
August 8, 1979 1:47 AM Redell Create file
October 17, 1979 6:54 PM Redell Add patch to detect RDC thinking it's an old ethernet
February 4, 1980 10:36 AM McJones Rename OISProcessorFaceD0Impl=>OISProcessorHeadD0; delete device registry/enumeration; add new OISProcessorFace items
February 25, 1980 3:06 PM McJones Move export of millisecondsPerTick to UserTerminalHeadD0
April 30, 1980 10:17 AM Forrest Add InitializeCVTimeout
May 14, 1980 4:27 PM McJones Add reservedNakedNotifyMask; remove Start from HeadStartChain (export to OISProcessorFace now); change GetNextController to deliver highest controller number first
June 25, 1980 4:23 PM McJones Drop "OIS" from name; expand processor id to 48 bits.
August 12, 1980 10:26 AM McJones Add dedicatedRealMemory; use MiscAlpha.
August 26, 1980 11:17 AM McJones Change cvTimeoutMask for new process microcode.
October 3, 1980 5:17 PM Forrest Move in unimplemented trap.
February 4, 1981 1:08 PM Knutsen PrincOps fields changed names.
19-Jul-81 14:43:33 Taft Use TrapSupport to handle unimplemented opcode traps.
22-Jun-82 16:53:22 Taft Implement and export MicrocodeBooting; degenerate implementation for now.
14-Jul-82 15:56:50 Taft Add trap support for LocalBlkZ, LongBlkZ, and UVersion opcodes.
October 4, 1982 12:50 pm Taft Init microsecondsPerHundredPulses according to system clock rate.
October 8, 1982 3:07 pm Taft Don't InitializeClockRate until after trap support set up.
February 27, 1983 2:31 pm Taft Export HeadStartChain.Start; absorb TrapSupportImpl
November 3, 1983 10:51 am Birrell 5.0 conversion
January 31, 1985 1:46:15 pm; Orr Take out ProcessorFaceExtras, change in PrincOps.SD