ProcessorHeadD0.mesa
Last Edited by: Taft, February 27, 1983 3:26 pm
Last Edited by: Birrell, November 3, 1983 1:19 pm
DIRECTORY
Basics USING [BITOR, LongDiv],
D0InputOutput USING [ControllerNumber, ControllerType, CSBArray, Input, null,
nullControllerNumber, rdc, rdcWithServiceLate],
DeviceCleanup USING [Await, Item, Reason],
MicrocodeBooting USING [BootFileNumber, MicrocodeType, nullBootFileNumber],
MicrocodeVersion USING [VersionResult],
PrincOps USING [aLOADRAMJ, aREADRAM, ControlLink, FrameHandle, PageCount, SD, StateVector, sUnimplemented, PageNumber, wordsPerPage, zMISC],
PrincOpsUtils USING [COPY, 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 BEGIN 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] =
BEGIN
i: ControllerIndex;
FOR i DECREASING IN ControllerIndex DO
IF type = controllerRoster[i]
AND (prev = nullControllerNumber OR prev > i) THEN RETURN[i];
ENDLOOP;
RETURN[nullControllerNumber]
END;
InitializeD0InputOutput: PRIVATE PROC =
BEGIN
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;
END;
ProcessorFace
Processor id
processorID: ProcessorFace.ProcessorID ← GetProcessorID[];
GetProcessorID: PRIVATE PROC RETURNS [ProcessorFace.ProcessorID] =
BEGIN
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 BEGIN PrincOps.zMISC, PrincOps.aREADRAM END;
RETURN[[0, csw.bits0To15, csw.bits16To31]] -- note most significant first
END;
Real memory configuration
dedicatedRealMemory: PrincOps.PageCount ← 0;
Virtual memory layout
GetNextAvailableVM: SAFE PROC [page: PrincOps.PageNumber]
RETURNS [firstPage: PrincOps.PageNumber, count: PrincOps.PageCount] = CHECKED
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[PrincOps.PageNumber], 0];
END;
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 =
BEGIN
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];
END;
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 =
BEGIN
DIW: LONG POINTER TO WORD = LOOPHOLE[LONG[421B]];
DIW^ ← Basics.BITOR[DIW^, cvTimeoutMask];
END;
Booting and power control
BootButton: SAFE PROC = TRUSTED
BEGIN
LoadRam: PROC [pMicrocode: LONG POINTER, andJump: BOOLEAN] =
MACHINE CODE BEGIN PrincOps.zMISC, PrincOps.aLOADRAMJ END;
bootMe: ARRAY [0..7) OF WORD
[000000B, 170000B, 000047B, 015000B, 177760B, 163351B, 007400B];
LoadRam[@bootMe, TRUE] -- never returns
END;
MicrocodeBooting; degenerate implementation for now
BootSpecificMicrocode: PUBLIC PROCEDURE [bfn: MicrocodeBooting.BootFileNumber] =
BEGIN
BootButton[];
END;
GetBootFileNumber: PUBLIC PROCEDURE [type: MicrocodeBooting.MicrocodeType]
RETURNS [bfn: MicrocodeBooting.BootFileNumber] =
BEGIN
RETURN[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 [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
END;
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 ← @(PrincOpsUtils.GetReturnFrame[].local[0]);
p^ ← 0;
IF count#1 THEN PrincOpsUtils.COPY[from: p, to: p+1, nwords: count-1];
END;
state.dest.frame ← PrincOpsUtils.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 PrincOpsUtils.LongCOPY[from: p, to: p+1, nwords: count-1];
END;
resultP ← p;
state.dest.frame ← PrincOpsUtils.MyLocalFrame[];
TRANSFER WITH state;
END;
UVersion: PROC RETURNS [MicrocodeVersion.VersionResult] =
BEGIN
TrapSupport.BumpPC[2];
RETURN [[
machineType: dolphin, majorVersion: 0, unused: 0,
floatingPoint: FALSE, cedar: FALSE, releaseDate: ProcessorFace.gmtEpoch/86400]];
END;
READRTrap: PROC [reg: [0..377]] RETURNS [UNSPECIFIED] =
BEGIN
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];
END;
Initialization
Go: PUBLIC SAFE PROC = CHECKED{-- By now start trap has occurred and main-body code has run--};
InitializeCleanup: PUBLIC SAFE PROCEDURE = TRUSTED
BEGIN OPEN DeviceCleanup;
item: Item;
reason: Reason;
DO
reason ← Await[@item];
SELECT reason FROM
turnOff, kill => gmtSimulated ← ProcessorFace.gmtEpoch;
ENDCASE
ENDLOOP
END;
InitializeCVTimeouts[];
InitializeD0InputOutput[];
PrincOps.SD[PrincOps.sUnimplemented] ← UnimplementedTrap;
PrincOps.SD[137B] ← @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];
END.
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