ProcessorHeadDLion.mesa
Copyright © 1985, 1986 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) June 13, 1986 5:46:56 pm PDT
Doug Wyatt, February 26, 1985 5:56:58 pm PST
Hal Murray, May 24, 1986 10:16:49 pm PDT
DIRECTORY
Basics USING [ BITOR, HighHalf, LowHalf ],
Checksum USING [ComputeChecksumProc],
DeviceCleanup USING [Await, Item, Perform, Reason],
DLionInputOutput,
MicrocodeBooting USING [BootFileNumber, MicrocodeType, nullBootFileNumber],
MPCodes USING [processorIDChanged, powerOff],
PrincOps USING [aCHKSUM, aGETF, alpha, ControlLink, flagsVacant, InterimPageState, PageCount, PageNumber, PageState, PageValue, 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 = TRUSTED {
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
pv: PrincOps.PageValue ← GetPageValue[i];
IF pv.state.flags # PrincOps.flagsVacant THEN firstUsed ← MIN[pv.real, firstUsed];
ENDLOOP;
specialRealPages ← firstUsed - DLionInputOutput.firstReservedPage;
};
NOTE: Ideally GetPageValue should be from a common definitions file. We share this definition with BootFile and VMInternal.
aSETMAP: PrincOps.alpha = 150B;
aGETMAPFLAGS: PrincOps.alpha = 151B;
aSETMAPFLAGS: PrincOps.alpha = 152B;
GetPageValue: PROC [virtual: PrincOps.PageNumber] RETURNS [pv: PrincOps.PageValue] = {
Gets the state and real page of a virtual page.
OldGetPageValue: PROC [virtual: CARDINAL] RETURNS [state: PrincOps.InterimPageState] = MACHINE CODE {PrincOps.zMISC, PrincOps.aGETF};
NewGetPageValue: PROC [vp: LONG CARDINAL] RETURNS [PrincOps.PageState, LONG CARDINAL] = MACHINE CODE {PrincOps.zMISC, aGETMAPFLAGS};
IF --ProcessorFace.--useLongMapOps
THEN [pv.state, pv.real] ← NewGetPageValue[virtual]
ELSE [flags: pv.state.flags, realPage: pv.real] ← OldGetPageValue[virtual].state;
};
InitializeCleanup: PUBLIC SAFE PROC = TRUSTED {
initial: ProcessorFace.ProcessorID ← processorID;
item: DeviceCleanup.Item;
DO
reason: DeviceCleanup.Reason ← DeviceCleanup.Await[@item];
SELECT reason FROM
turnOff, kill => NULL -- we have a genuine clock, so don't need to invalidate it!--;
turnOn => { -- Can't call procs (maybe no frames) so copy code
pCSB: LONG POINTER TO ProcessorCSB = IOPage + ProcessorCSBOffset;
current: ProcessorFace.ProcessorID;
WHILE pCSB.command.busy DO NULL ENDLOOP;
pCSB.command ← [op: readPID];
WHILE pCSB.command.busy DO NULL ENDLOOP;
current ← [pCSB.data0, pCSB.data1, pCSB.data2];
IF initial # current THEN {
Rollback on a different machine?
ProcessorFace.SetMP[MPCodes.processorIDChanged];
DO ENDLOOP; }; };
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 BOOLTRUE;
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 Code;
Code: TYPE = RECORD [SEQUENCE COMPUTED CARDINAL OF CodeByte];
CodeByte: TYPE = [0..255];
opcode: CodeByte;
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.misc[code[l.frame.pc+1]]
ELSE TrapSupport.opTrapTable.main[opcode];
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
LocalGetPageValue: PROC [virtual: PrincOps.PageNumber] RETURNS [ps: PrincOps.PageState, pn: LONG CARDINAL] = {
pv: PrincOps.PageValue;
IF useLongMapOps THEN useLongMapOps ← FALSE ELSE ERROR;
TrapSupport.BumpPC[2];
pv ← GetPageValue[virtual];
ps ← pv.state;
pn ← pv.real;
};
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];
TrapSupport.opTrapTable.misc[aGETMAPFLAGS] ← LOOPHOLE[LocalGetPageValue];
}.
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
June 4, 1986 6:48:39 pm PDT; Orr Take out ProcessorFaceExtras, change in PrincOps.SD, GetPageValue, OldGetPageValue (local of GetPageValue), NewGetPageValue (local of GetPageValue), InitializeCleanup, useLongMapOps, ResetAutomaticPowerOn, TrapSupport, January
Russ Atkinson (RRA) June 4, 1986 6:24:56 pm PDT
Added support for long map opcodes.