-- ProcessorHeadD0.mesa
-- Last Edited by: Taft, February 27, 1983 3:26 pm
DIRECTORY
D0InputOutput USING [ControllerNumber, ControllerType, CSBArray, Input, null,
nullControllerNumber, rdc, rdcWithServiceLate],
Environment USING [Byte, PageCount, PageNumber, wordsPerPage],
Frame USING [GetReturnFrame, GetReturnLink, MyLocalFrame],
HeadStartChain USING [],
Inline USING [BITOR, COPY, LongCOPY, LongDiv],
MicrocodeBooting USING [BootFileNumber, MicrocodeType, nullBootFileNumber],
MicrocodeVersion USING [VersionResult],
MiscAlpha USING [aLOADRAMJ, aREADRAM],
Mopcodes USING [zMISC],
PrincOps USING [ControlLink, FrameHandle, StateVector],
ProcessorFace USING [ProcessorID],
SDDefs USING [SD, sUnimplemented],
System USING [gmtEpoch],
TrapSupport USING [BumpPC, OpTrapTable, opTrapTable];
ProcessorHeadD0: PROGRAM
IMPORTS Frame, D0InputOutput, Inline, TrapSupport
EXPORTS D0InputOutput, HeadStartChain, MicrocodeBooting, ProcessorFace
SHARES ProcessorFace =
PUBLIC BEGIN OPEN D0InputOutput;
--
-- D0InputOutput
IOPage: LONG POINTER TO CSBArray ← LOOPHOLE[LONG[pageIO*Environment.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
-- 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: PROC = {-- By now start trap has occurred and main-body code has run--};
-- 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 Mopcodes.zMISC, MiscAlpha.aREADRAM END;
RETURN[[0, csw.bits0To15, csw.bits16To31]] -- note most significant first
END;
-- Real memory configuration
dedicatedRealMemory: Environment.PageCount ← 0;
-- Virtual memory layout
GetNextAvailableVM: 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;
page1: PRIVATE Environment.PageNumber = 1B;
-- I/O page for Alto-compatible Diablo31, display, cursor, mouse coords
page376B: PRIVATE Environment.PageNumber = 376B;
-- I/O page for Alto-compatible keyboard/mouse bitmap
pageIO: PRIVATE Environment.PageNumber = 377B; -- "official" D0 I/O page
pageFirstUnimplemented: PRIVATE Environment.PageNumber = 40000B;
-- [pageFirstUnimplemented..LAST[PageNumber]] not implemented
-- Interval time
microsecondsPerHundredPulses: CARDINAL;
InitializeClockRate: PRIVATE PROC =
BEGIN
ReadRegister: PROC [address: [0..377B]] RETURNS [UNSPECIFIED] = MACHINE CODE {
Mopcodes.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 ← Inline.LongDiv[LONG[100]*64*320, clockRate];
END;
-- Naked notifies
cvTimeoutMask: PRIVATE WORD = 100000B; -- D0 microcode assumes level 0
reservedNakedNotifyMask: WORD ← cvTimeoutMask;
-- Condition variable time
-- millisecondsPerTick is exported by UserTerminalHeadD0,
-- since its value depends on the display refresh rate.
InitializeCVTimeouts: PRIVATE PROC =
BEGIN
DIW: LONG POINTER TO WORD = LOOPHOLE[LONG[421B]];
DIW↑ ← Inline.BITOR[DIW↑, cvTimeoutMask];
END;
-- Booting and power control
BootButton: PROC =
BEGIN
LoadRam: PROC [pMicrocode: LONG POINTER, andJump: BOOLEAN] =
MACHINE CODE BEGIN Mopcodes.zMISC, MiscAlpha.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 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;
-- 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: dolphin, majorVersion: 0, unused: 0,
floatingPoint: FALSE, cedar: FALSE, releaseDate: System.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
InitializeCVTimeouts[];
InitializeD0InputOutput[];
SDDefs.SD[SDDefs.sUnimplemented] ← UnimplementedTrap;
SDDefs.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[];
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