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; 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; 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; 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; dedicatedRealMemory: PrincOps.PageCount _ 0; 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; page376B: PRIVATE PrincOps.PageNumber = 376B; pageIO: PRIVATE PrincOps.PageNumber = 377B; -- "official" D0 I/O page pageFirstUnimplemented: PRIVATE PrincOps.PageNumber = 40000B; microsecondsPerHundredPulses: CARDINAL; InitializeClockRate: PRIVATE PROC = BEGIN ReadRegister: PROC [address: [0..377B]] RETURNS [UNSPECIFIED] = MACHINE CODE { PrincOps.zMISC, 106B}; clockRate: CARDINAL = ReadRegister[323B]; microsecondsPerHundredPulses _ Basics.LongDiv[LONG[100]*64*320, clockRate]; END; 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; cvTimeoutMask: PRIVATE WORD = 100000B; -- D0 microcode assumes level 0 reservedNakedNotifyMask: WORD _ cvTimeoutMask; 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; 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; BootSpecificMicrocode: PUBLIC PROCEDURE [bfn: MicrocodeBooting.BootFileNumber] = BEGIN BootButton[]; END; GetBootFileNumber: PUBLIC PROCEDURE [type: MicrocodeBooting.MicrocodeType] RETURNS [bfn: MicrocodeBooting.BootFileNumber] = BEGIN RETURN[MicrocodeBooting.nullBootFileNumber]; END; 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]]]; 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 ~state.dest.proc THEN state.dest.frame.returnlink _ l; RETURN WITH state; -- Flush my frame and transfer to real trap handler END; 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 TrapSupport.BumpPC[2]; RETURN [320]; END; 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 PProcessorHeadD0.mesa Last Edited by: Taft, February 27, 1983 3:26 pm Last Edited by: Birrell, November 3, 1983 1:19 pm D0InputOutput Initialization microcode really should have put roster into memory somewhere. ProcessorFace Processor id Real memory configuration Virtual memory layout I/O page for Alto-compatible Diablo31, display, cursor, mouse coords I/O page for Alto-compatible keyboard/mouse bitmap [pageFirstUnimplemented..LAST[PageNumber]] not implemented Interval time The number read here is proportional to clock ticks per unit of time, where the value 320 denotes 1 tick every 64 microseconds. Greenwich mean time Naked notifies Condition variable time Booting and power control MicrocodeBooting; degenerate implementation for now TrapSupport. 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. If handler is fixed-frame, manually plant the return link. (Microcode does that for traps, but not for ordinary XFERs to frames.) Trap support for Cedar-related opcodes 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. Initialization Ê À˜Jšœ™Jšœ/™/J™1šÏk ˜ Jšœœœ ˜šœœ:˜MJ˜/—Jšœœ˜*Jšœœ5˜KJšœœ˜'Jšœ œ<œ@˜ŒJšœœœ9˜RJšœœ<˜OJšœ œ$˜5J˜—šœœÏc)˜BJšœP˜WJšœ/˜6Jšœ˜—J˜Jšœœœ˜ J˜J™Jšœ ™ J˜Jš œœœœ œ˜JJšœ(ž(˜PJšœ(ž/˜WJšœœ6˜KJšœœœœ˜FJ˜šÏnœœ˜Jšœ.œ˜JJš˜J˜šœ œœ˜&šœ˜Jšœœ œœ˜=—Jšœ˜—Jšœ˜Jšœ˜J˜—šŸœœœ˜'Jš˜š œ œœ œœ˜-J˜)—Jšœž+˜:J˜J˜J˜JšœM™Mšœœ˜Jšœœ8˜DJ˜ Jšœœ ž˜6J˜Jšœ˜—Jšœ˜J˜—J™Jšœ ™ J˜Jšœ ™ J˜J˜:J˜šŸœœœœ˜BJš˜J˜š œœœ œœ˜)Jšœ œ˜Jšœ œ˜J˜J˜—šŸœœœ ˜6Jšœœœ#œ˜9—Jšœ%ž˜IJšœ˜J˜—Jšœ™J˜Jšœ,˜,J˜Jšœ™J˜šŸœœœ˜9Jšœ?˜MJš˜Jšœœœ˜0Jšœœ˜Jšœœœ˜6Jšœœ˜Jšœœœ˜2Jšœœ˜šœ˜%Jšœ&˜,—Jšœœ˜%Jšœ˜J˜—šœœ˜(JšœD™D—šœ œ˜-Jšœ2™2—Jšœœž˜Ešœœ˜=Jšœ:™:J˜—Jšœ ™ J˜Jšœœ˜'J˜šŸœœœ˜#Jš˜š Ÿ œœœ œœœ˜NJšœ˜—JšœE™EJšœ9™9Jšœ œ˜)Jšœ.œ˜KJšœ˜J˜—Jšœ™J˜šŸœœœœœœ%œ˜aJšœ˜Jšœœœ˜šœœž,˜O˜J˜8—JšœDž˜UJ˜&Jšœ˜—Jšœ˜Jšœ˜J˜—š Ÿœœœœœ)˜UJšœ˜Jšœœœ˜Jšœ4˜4Jšœ˜Jšœ˜J˜—JšœIž ˜VJšœœœž5˜YJšœœœ˜J˜Jšœ™J˜Jšœœœ ž˜FJšœœ˜.J˜Jšœ™J™Jšœœœž/˜ZJ˜šŸœœœ˜$Jš˜Jšœœœœœœœ˜1Jšœ œœ˜)Jšœ˜J˜—Jšœ™J˜šŸ œœœ˜Jš˜š Ÿœœœœ œ˜œ˜_J˜š Ÿœœœ œ˜2Jšœœ˜J˜ J˜š˜J˜šœ˜Jšœ7˜7Jš˜—Jš˜—Jšœ˜—J˜J˜J˜Jšœ œ.˜9Jšœ œ˜Jšœ%œ ˜9Jšœ%œ ˜8Jšœ%œ ˜8Jšœ%œ ˜9J˜JšœH˜HJ˜Jšœ˜J˜Jšœœ˜.J˜Jšœœ œ˜ZJ˜Jšœœ‚˜œJ˜JšœœE˜_J˜Jšœœ$˜