ProcessorHeadDLion.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Taft, February 27, 1983 3:40 pm
Willie-Sue, January 31, 1985 3:05:00 pm PST
Russ Atkinson (RRA) February 27, 1985 8:31:55 pm PST
Doug Wyatt, February 26, 1985 5:56:58 pm PST
DIRECTORY
Basics USING [ BITOR, HighHalf, LowHalf ],
Checksum USING [ComputeChecksumProc],
DeviceCleanup USING [Await, Item, Perform, Reason],
DLionInputOutput,
MicrocodeBooting USING [BootFileNumber, MicrocodeType, nullBootFileNumber],
MPCodes USING [powerOff],
PrincOps USING [aCHKSUM, aGETF, ControlLink, flagsVacant, InterimPageState, PageCount, PageNumber, PageState, RealPageNumber, SD, StateVector, sUnimplemented, VersionResult, zMISC],
PrincOpsUtils USING [Copy, DisableInterrupts, GetReturnFrame, GetReturnLink, LongCopy, MyLocalFrame],
ProcessorFace USING [gmtEpoch, GreenwichMeanTime, ProcessorID, SetMP],
TrapSupport USING [BumpPC, OpTrapTable, opTrapTable];
ProcessorHeadDLion: MONITOR
IMPORTS Basics, Checksum, DeviceCleanup, PrincOpsUtils, ProcessorFace, TrapSupport
EXPORTS DLionInputOutput, MicrocodeBooting, ProcessorFace
SHARES Checksum, ProcessorFace = {
DLionInputOutput
IOPage: PUBLIC LONG POINTERLOOPHOLE[LONG[177400B]];
ProcessorCSBOffset: CARDINAL = 127B; -- 57X
ProcessorCSB: TYPE = MACHINE DEPENDENT RECORD [
data2(0): WORD,
data1(1): WORD,
data0(2): WORD,
command(3): ProcessorCommand];
ProcessorCommand: TYPE = MACHINE DEPENDENT RECORD [
busy(0:0..0): BOOLTRUE,
op(0:1..15): ProcessorOperation];
ProcessorOperation: TYPE = MACHINE DEPENDENT {
setTOD(1), readTOD(2), readPID(3), boot(4), (32767)};
TimeOfDayOffset: CARDINAL = 320B; -- 0D0X
TimeOfDayClock: TYPE = MACHINE DEPENDENT RECORD [
valid(0): WORD, -- 0 => invalid, 177777B => valid
time(1): LONG CARDINAL,
lowCheck(3): CARDINAL];
Initialization
Go: PUBLIC SAFE PROC = CHECKED{
By now start trap has occurred and main-body code has run.
Scan the VM looking for the lowest real page mapped. Use this as upper bound on special real memory area (The microcode likes to use some of the bank 0 real memory for the Germ).
firstUsed: PrincOps.RealPageNumber ←
DLionInputOutput.firstReservedPage + DLionInputOutput.reservedPageCount;
FOR i: PrincOps.PageNumber IN [0..DLionInputOutput.numberVirtualPages)
DO state: PrincOps.PageState;
real: PrincOps.RealPageNumber;
TRUSTED { [state, real] ← GetPageState[i] };
IF state.flags # PrincOps.flagsVacant
AND real >= DLionInputOutput.firstReservedPage-- -- but compiler warns about "foo >= 0"
THEN firstUsed ← MIN[real, firstUsed];
ENDLOOP;
specialRealPages ← firstUsed - DLionInputOutput.firstReservedPage;
};
GetPageState: PROC [virtual: PrincOps.PageNumber] RETURNS [state: PrincOps.PageState, real: PrincOps.RealPageNumber] = INLINE {
Gets the state and real page of a virtual page.
DoGetPageState: PROC [virtual: --OldPageNumber--CARDINAL] RETURNS [state: PrincOps.InterimPageState] =
MACHINE CODE {PrincOps.zMISC, PrincOps.aGETF};
[logSingleError: , flags: state.flags, realPage: real] ← DoGetPageState[virtual].state;
};
InitializeCleanup: PUBLIC SAFE PROC = TRUSTED {
OPEN DeviceCleanup;
item: Item;
reason: Reason;
DO
reason ← Await[@item];
SELECT reason FROM
turnOff, kill => NULL -- we have a genuine clock, so don't need to invalidate it!--;
ENDCASE
ENDLOOP
};
Processor ID
processorID: PUBLIC ProcessorFace.ProcessorID ← GetProcessorID[];
GetProcessorID: PROC RETURNS [ProcessorFace.ProcessorID] = {
pCSB: LONG POINTER TO ProcessorCSB = IOPage + ProcessorCSBOffset;
WHILE pCSB.command.busy DO NULL ENDLOOP;
pCSB.command ← [op: readPID];
WHILE pCSB.command.busy DO NULL ENDLOOP;
RETURN[[pCSB.data0, pCSB.data1, pCSB.data2]];
};
Real memory configuration
firstSpecialRealPage: PUBLIC PrincOps.RealPageNumber ← DLionInputOutput.firstReservedPage;
specialRealPages: PUBLIC PrincOps.PageCount ← 0; -- set correctly in initialization code
Virtual memory layout
GetNextAvailableVM: PUBLIC SAFE PROC [page: PrincOps.PageNumber] RETURNS [firstPage: PrincOps.PageNumber, count: PrincOps.PageCount] = TRUSTED {
I believe that 376B and 377B are actually available on DLions, but at present the Germ assumes they aren't. ADB 1/23/84
IF page < 376B THEN RETURN[page, 376B - page];
page ← MAX[page, 376B + 1];
IF page < 377B THEN RETURN[page, 377B - page];
page ← MAX[page, 377B + 1];
IF page < DLionInputOutput.numberVirtualPages
THEN RETURN[page, DLionInputOutput.numberVirtualPages - page];
RETURN[LAST[PrincOps.PageNumber], 0]
};
useLongMapOps: PUBLIC BOOLFALSE;
The DLion can not use the long map ops.
GreenwichMeanTime
GreenwichMeanTime: TYPE = ProcessorFace.GreenwichMeanTime;
gmtEpoch: GreenwichMeanTime = ProcessorFace.gmtEpoch;
GetGreenwichMeanTime: PUBLIC ENTRY SAFE PROC RETURNS [gmt: GreenwichMeanTime] = TRUSTED {
tod: LONG POINTER TO TimeOfDayClock = IOPage + TimeOfDayOffset;
IF tod.valid = 0 THEN RETURN[gmtEpoch];
DO
gmt ← tod.time;
IF Basics.LowHalf[gmt] = tod.lowCheck THEN EXIT;
ENDLOOP;
RETURN
};
SetGreenwichMeanTime: PUBLIC ENTRY SAFE PROC [gmt: GreenwichMeanTime] = TRUSTED {
pCSB: LONG POINTER TO ProcessorCSB = IOPage + ProcessorCSBOffset;
tod: LONG POINTER TO TimeOfDayClock = IOPage + TimeOfDayOffset;
WHILE pCSB.command.busy DO NULL ENDLOOP;
pCSB.data2 ← Basics.LowHalf[gmt];
pCSB.data1 ← Basics.HighHalf[gmt];
pCSB.command ← [op: setTOD];
tod.valid ← 0;
WHILE pCSB.command.busy DO NULL ENDLOOP;
WHILE tod.valid = 0 DO NULL ENDLOOP;
RETURN
};
Interval time
microsecondsPerHundredPulses: PUBLIC CARDINAL ← 2878;
Naked notifies
cvTimeoutMask: WORD = 100000B; -- DLion microcode assumes level 0
reservedNakedNotifyMask: PUBLIC WORD ← cvTimeoutMask;
Condition variable time
millisecondsPerTick: PUBLIC CARDINAL ← 52;
InitializeCVTimeouts: PROC = {
DIW: LONG POINTER TO WORD = LOOPHOLE[LONG[177753B]];
DIW^ ← Basics.BITOR[DIW^, cvTimeoutMask];
};
Booting and power control
BootButton: PUBLIC SAFE PROC = TRUSTED {
pCSB: LONG POINTER TO ProcessorCSB = IOPage + ProcessorCSBOffset;
PrincOpsUtils.DisableInterrupts[];
WHILE pCSB.command.busy DO NULL ENDLOOP;
pCSB.command ← [op: boot];
DO ENDLOOP;
};
PowerOff: PUBLIC SAFE PROC [returnIfDisabled: BOOLFALSE] = TRUSTED {
NOTE: This code depends on the greenwich mean time clock running
with interrupts disabled and devices turned off.
IF powerOffCount # 0 AND returnIfDisabled THEN RETURN;
PrincOpsUtils.DisableInterrupts[];
DeviceCleanup.Perform[turnOff];
DO
ProcessorFace.SetMP[MPCodes.powerOff];
IF powerOffCount = 0 THEN EXIT;
ENDLOOP;
DO
forever
IF (GetGreenwichMeanTime[] - ProcessorFace.gmtEpoch)
>= (gmtAutomaticPowerOn - ProcessorFace.gmtEpoch)
AND (~externalEventRequired OR ExternalEvent[]) THEN BootButton[]
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;
externalEventRequired: BOOL;
ExternalEvent: PROC RETURNS [BOOL] = {RETURN[FALSE]};
SetAutomaticPowerOn: PUBLIC SAFE PROC [gmt: ProcessorFace.GreenwichMeanTime, externalEvent: BOOL] = TRUSTED {
gmtAutomaticPowerOn ← gmt; externalEventRequired ← externalEvent; };
ResetAutomaticPowerOn: PUBLIC SAFE PROC = TRUSTED {
gmtAutomaticPowerOn ← ProcessorFace.gmtEpoch - 1}; -- infinity
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]]];
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 = {
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: dandelion, majorVersion: 0, unused: 0,
floatingPoint: FALSE, cedar: FALSE, releaseDate: ProcessorFace.gmtEpoch/86400]];
};
ComputeChecksum: PRIVATE PROC [cs, nWords: CARDINAL, p: LONG POINTER] RETURNS [CARDINAL] = {
RETURN[Checksum.ComputeChecksumProc[cs, nWords, p]];
};
Main body code
InitializeCVTimeouts[];
PrincOps.SD[PrincOps.sUnimplemented] ← LOOPHOLE[UnimplementedTrap];
PrincOps.SD[137B] ← LOOPHOLE[@trapTable];
TrapSupport.opTrapTable.misc[PrincOps.aCHKSUM] ← LOOPHOLE[ComputeChecksum];
TrapSupport.opTrapTable.misc[100B] ← LOOPHOLE[LocalBlkZ];
TrapSupport.opTrapTable.misc[102B] ← LOOPHOLE[LongBlkZ];
TrapSupport.opTrapTable.misc[104B] ← LOOPHOLE[UVersion];
}.
LOG
August 5, 1980 10:28 AM Forrest Created file.
August 12, 1980 10:41 AM McJones Added dedicatedRealMemory.
September 18, 1980 1:26 PM Sandman Changed cvTimeoutMask, millisecondsPerTick for new PSB format.
October 2, 1980 2:43 PM Forrest Changed microsecondsPerHundredPulses to 2878 from 2880.
October 3, 1980 5:26 PM Forrest Moved in unimplemented trap.
November 10, 1980 4:10 PM Forrest Added memory allocation junk.
January 23, 1981 approx Gobbel ?
February 6, 1981 12:04 PM Knutsen Make compatible with new PrincOps.
August 27, 1982 9:38 am Taft Add TrapSupport, MicrocodeBooting, MicrocodeVersion, etc.
February 27, 1983 2:31 pm Taft Export HeadStartChain.Start; absorb TrapSupportImpl
January 31, 1985 1:46:15 pm; Orr Take out ProcessorFaceExtras, change in PrincOps.SD