-- ProcessorHeadDorado.mesa -- Last Edited by: Taft, February 27, 1983 3:29 pm DIRECTORY BitBlt USING [BitBltTable, BitBltTablePtr, BITBLT], DeviceCleanup USING [Perform], DisplayFace USING [Cursor, CursorPtr, Point], DoradoInputOutput USING [GetMemConfig, Halt, pagesPerBank, RWMufMan], Environment USING [Byte, PageCount, maxPagesInVM, PageNumber], Frame USING [GetReturnFrame, GetReturnLink, MyLocalFrame], HeadStartChain USING [], Inline USING [BITAND, BITOR, COPY, DIVMOD, LongCOPY, LongDiv, LongMult, LongNumber, LowHalf, HighHalf], MicrocodeBooting USING [BootFileNumber, MicrocodeType, nullBootFileNumber], MicrocodeVersion USING [VersionResult], MiscAlpha USING [aSETMP, aTEXTBLT], Mopcodes USING [zMISC], PilotMP USING [cClient, Code, cPowerOff], PrincOps USING [ControlLink, FrameHandle, StateVector], ProcessInternal USING [DisableInterrupts, EnableInterrupts], ProcessorFace USING [GetClockPulses, gmtEpoch, GreenwichMeanTime, ProcessorID, SetMP], SDDefs USING [SD, sUnimplemented], SoftwareTextBlt USING [TextBlt], System USING [gmtEpoch], TrapSupport USING [BumpPC, OpTrapTable, opTrapTable]; ProcessorHeadDorado: PROGRAM IMPORTS BitBlt, DeviceCleanup, DoradoInputOutput, Frame, Inline, ProcessInternal, ProcessorFace, SoftwareTextBlt, TrapSupport EXPORTS DoradoInputOutput, HeadStartChain, MicrocodeBooting, ProcessorFace SHARES ProcessorFace = BEGIN OPEN DoradoInputOutput; -- 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: PUBLIC PROC = { -- By now start trap has occurred and main-body code has run--}; -- Processor id processorID: PUBLIC ProcessorFace.ProcessorID ← GetProcessorID[]; baseProcessorIDDorado: ProcessorFace.ProcessorID = [a: 0, b: 52612B, c: 100000B]; GetProcessorID: PRIVATE PROC RETURNS [ProcessorFace.ProcessorID] = BEGIN doradoSN: [0..377B] ← 0; FOR i: CARDINAL IN [0..7] DO doradoSN ← 2*doradoSN + RWMufMan[[useDMD: FALSE, dMuxAddr: 2220B+i]].dMuxData; ENDLOOP; RETURN[[a: baseProcessorIDDorado.a, b: baseProcessorIDDorado.b, c: baseProcessorIDDorado.c + doradoSN]] -- note most significant first END; -- Real memory configuration dedicatedRealMemory: PUBLIC Environment.PageCount ← 0; -- Virtual memory layout GetNextAvailableVM: PUBLIC 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; -- I/O page for Alto-compatible display, cursor, mouse coords. -- NOTE: even though we declare this page off-limits, Pilot boot files may -- contain data for it. Therefore, Pilot boot devices (disk and Ethernet) -- CANNOT use page1 for their CSBs. page1: Environment.PageNumber = 1B; -- I/O page for Alto-compatible keyboard/mouse bitmap page376B: Environment.PageNumber = 376B; -- I/O page for newly-written Pilot device microcode pageIO: Environment.PageNumber = 377B; -- First nonexistent VM page. -- Note that Environment.PageNumber is presently a CARDINAL rather than a LONG CARDINAL. pageFirstUnimplemented: Environment.PageNumber = IF GetMemConfig[].virtualBanks > Environment.maxPagesInVM/pagesPerBank THEN Environment.maxPagesInVM ELSE GetMemConfig[].virtualBanks * pagesPerBank; -- Interval time microsecondsPerHundredPulses: PUBLIC CARDINAL ← 32*100; -- Naked notifies cvTimeoutMask: WORD = 100000B; -- Dorado microcode assumes level 0 reservedNakedNotifyMask: PUBLIC WORD ← cvTimeoutMask; -- Condition variable time -- millisecondsPerTick is exported by UserTerminalHeadDorado, -- since its value depends on the display refresh rate. InitializeCVTimeouts: PROC = BEGIN DIW: LONG POINTER TO WORD = LOOPHOLE[LONG[421B]]; DIW↑ ← Inline.BITOR[DIW↑, cvTimeoutMask]; END; -- Greenwich mean time GetGreenwichMeanTime: PUBLIC PROC RETURNS [ProcessorFace.GreenwichMeanTime] = BEGIN OPEN ProcessorFace; IF gmtSimulated ~= gmtEpoch THEN -- don't update clock unless it has been set BEGIN seconds: GreenwichMeanTime = (GetClockPulses[] - pulsesGmtSimulated)/pulsesPerSecond; pulsesGmtSimulated ← pulsesGmtSimulated + seconds*pulsesPerSecond; -- long multiply! gmtSimulated ← gmtSimulated + seconds; END; RETURN[gmtSimulated] END; SetGreenwichMeanTime: PUBLIC PROCEDURE [gmt: ProcessorFace.GreenwichMeanTime] = BEGIN pulsesGmtSimulated ← ProcessorFace.GetClockPulses[]; gmtSimulated ← gmt; END; gmtSimulated: ProcessorFace.GreenwichMeanTime ← ProcessorFace.gmtEpoch; -- => not set pulsesGmtSimulated: LONG CARDINAL; -- interval timer value corresponding to gmtSimulated pulsesPerSecond: LONG CARDINAL = Inline.LongDiv[1D6*100, microsecondsPerHundredPulses]; -- Booting and power control BootButton: PUBLIC PROC = BEGIN ProcessInternal.DisableInterrupts[]; [] ← RWMufMan[[useDMD: TRUE, dMuxAddr: 2264B]]; -- Request BaseBoard boot DO ENDLOOP; END; PowerOff: PUBLIC PROC = BEGIN OPEN ProcessorFace; -- Double-by-single multiply procedure, specially defined because the compiler would -- otherwise generate calls to nonresident software routines in Instructions.mesa. MultLCxC: PROC [lc: LONG CARDINAL, c: CARDINAL] RETURNS [LONG CARDINAL] = INLINE { result: Inline.LongNumber ← [lc[Inline.LongMult[Inline.LowHalf[lc], c]]]; result.highbits ← result.highbits + Inline.HighHalf[lc]*c; RETURN [result.lc]}; timeToGo: LONG INTEGER; ProcessInternal.DisableInterrupts[]; DeviceCleanup.Perform[turnOff]; SetMP[PilotMP.cPowerOff]; timeToGo ← gmtAutomaticPowerOn - GetGreenwichMeanTime[]; -- Manifold 2262 turns the machine off indefinitely. -- Manifold 2263 turns the machine off for a specified interval in units of 25.6 sec. -- The interval must be left on the BMux when the machine halts. IF gmtAutomaticPowerOn = gmtEpoch-1 THEN [] ← RWMufMan[[useDMD: TRUE, dMuxAddr: 2262B]] ELSE IF timeToGo<26 THEN BootButton[] ELSE [] ← RWMufMan[[useDMD: TRUE, dMuxAddr: IF timeToGo >= (200000B*256)/10 THEN 2262B ELSE 2263B]]; Halt[Inline.LongDiv[MultLCxC[timeToGo, 10], 256]]; END; gmtAutomaticPowerOn: ProcessorFace.GreenwichMeanTime; SetAutomaticPowerOn: PUBLIC PROCEDURE [ gmt: ProcessorFace.GreenwichMeanTime, externalEvent: BOOLEAN] = BEGIN gmtAutomaticPowerOn ← gmt; END; ResetAutomaticPowerOn: PUBLIC PROCEDURE = BEGIN gmtAutomaticPowerOn ← ProcessorFace.gmtEpoch - 1; -- infinity END; -- MicrocodeBooting BootSpecificMicrocode: PUBLIC PROCEDURE [bfn: MicrocodeBooting.BootFileNumber] = BEGIN microcodeBFNOffset: CARDINAL = 3000B; -- microcode boot server uses offset BFNs ubfn: CARDINAL ← bfn-microcodeBFNOffset; bootParameterSeal: CARDINAL = 56623B; PushBootParams: PROCEDURE [ubfn, seal, checksum: CARDINAL] = MACHINE CODE {}; -- Push sealed and checksum boot file parameters on the stack for Initial to look at. -- Note: in general calling BootButton with a non-empty stack would be illegal, -- but is OK here because BootButton calls only machine code procedures. IF bfn#MicrocodeBooting.nullBootFileNumber THEN PushBootParams[ubfn, bootParameterSeal, 0-(ubfn+bootParameterSeal)]; BootButton[]; END; GetBootFileNumber: PUBLIC PROCEDURE [type: MicrocodeBooting.MicrocodeType] RETURNS [bfn: MicrocodeBooting.BootFileNumber] = BEGIN RETURN[[ SELECT type FROM altoMesa => 3110B, lisp => 3112B, smalltalk76 => 3111B, smalltalk80 => MicrocodeBooting.nullBootFileNumber, pilotMesa, cedarMesa => 3113B, ENDCASE => 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; -- Handler for TEXTBLT trap. -- The opcode actually takes a pile of arguments and returns a pile of results. -- The trap handler is defined strangely in order to avoid needless pushing and popping. TEXTBLTTrap: PROC = BEGIN -- TEXTBLT is a minimal-stack instruction, so no need to save state vector. TextBlt: PROC = LOOPHOLE[SoftwareTextBlt.TextBlt]; TrapSupport.BumpPC[2]; TextBlt[]; END; -- Fixed-frame handler for SetMP trap. -- (Needs to be fixed-frame because SetMP may occur in contexts where -- frame allocation is impossible.) InitSetMPTrap: PROC = BEGIN GetCode: PROC RETURNS [code: PilotMP.Code] = MACHINE CODE BEGIN END; code: PilotMP.Code; cursorPtr: DisplayFace.CursorPtr = LOOPHOLE[LONG[431B]]; state: MACHINE DEPENDENT RECORD [a, b: UNSPECIFIED, v: PrincOps.StateVector]; TrapSupport.opTrapTable.misc[MiscAlpha.aSETMP].frame ← Frame.MyLocalFrame[]; state.v ← STATE; ProcessInternal.DisableInterrupts[]; DO state.v.dest ← Frame.GetReturnLink[]; ProcessInternal.EnableInterrupts[]; TRANSFER WITH state.v; -- SetMP trap enters here with code on top of stack. ProcessInternal.DisableInterrupts[]; code ← GetCode[]; state.v ← STATE; TrapSupport.BumpPC[2]; IF code=PilotMP.cClient THEN cursorPtr↑ ← savedCursor ELSE BEGIN -- I should use the procedures exported through DisplayFace to do this, -- but DisplayHeadDorado may not have been STARTed yet (or may not exist). cursorPosition: LONG POINTER TO DisplayFace.Point = LOOPHOLE[LONG[426B]]; digit, digitOffset: CARDINAL; cursorPosition↑ ← [x: 304, y: 404]; FOR i: CARDINAL IN [0..15] DO cursorPtr[i] ← 0; ENDLOOP; FOR i: CARDINAL DECREASING IN [0..2] DO [code, digit] ← Inline.DIVMOD[code, 10]; digitOffset ← digit*5; bbPtr↑ ← [ dst: [word: cursorPtr, bit: 5*i], dstBpl: 16, src: [word: @digitFont + digitOffset/16, bit: digitOffset MOD 16], srcDesc: [srcBpl[64]], width: 5, height: 6, flags: [disjoint: TRUE, dstFunc: or]]; BitBlt.BITBLT[bbPtr]; ENDLOOP; END; ENDLOOP; END; -- These belong in SETMPTrap's local frame, but are here in the global frame -- because if SETMPTrap's local frame is too large it causes frame allocation traps -- during early initialization when they can't be handled. -- Note: PrincOps BBTable must be 16-word aligned, but Dorado requires only 2-word. bbTable: ARRAY[0..SIZE[BitBlt.BitBltTable]+1) OF UNSPECIFIED; bbPtr: BitBlt.BitBltTablePtr = Inline.BITAND[@bbTable+1, 177776B]; digitFont: ARRAY [0..24) OF CARDINAL ← [ -- Strike-format font, densely packed, characters 6 high, 5 wide 30614B, 61474B, 167461B, 117000B, 45222B, 112441B, 512B, 57000B, 54202B, 22471B, 141062B, 57000B, 64214B, 14405B, 21111B, 157000B, 44220B, 117645B, 22110B, 57000B, 31736B, 60430B, 142063B, 117000B]; -- SetCursorPattern stores a copy of the real cursor here, and the SetMP trap handler -- copies this into the real cursor whenever a code of cClient is posted, thereby -- restoring the client's cursor across world-swaps. This can't be done by -- UserTerminalHeadDorado's cleanup procedure, because calls to cleanup procedures -- are surrounded by SetMPs, thereby clobbering the cursor. savedCursor: PUBLIC DisplayFace.Cursor ← ALL[0]; -- 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: dorado, majorVersion: 0, unused: 0, floatingPoint: FALSE, cedar: FALSE, releaseDate: System.gmtEpoch/86400]]; END; -- -- Initialization InitializeCVTimeouts[]; SDDefs.SD[SDDefs.sUnimplemented] ← UnimplementedTrap; SDDefs.SD[137B] ← @trapTable; InitSetMPTrap[]; TrapSupport.opTrapTable.misc[MiscAlpha.aTEXTBLT] ← LOOPHOLE[TEXTBLTTrap]; TrapSupport.opTrapTable.misc[100B] ← LOOPHOLE[LocalBlkZ]; TrapSupport.opTrapTable.misc[102B] ← LOOPHOLE[LongBlkZ]; TrapSupport.opTrapTable.misc[104B] ← LOOPHOLE[UVersion]; ResetAutomaticPowerOn[]; END. December 5, 1980 5:39 PM Taft Convert for Dorado; mostly remove D0 I/O junk December 11, 1980 12:55 PM Taft Maint panel in cursor 9-Jun-81 18:59:01 Taft Export savedCursor; use it when SetMP code = cClient 7-Jul-81 19:50:43 Taft Use TrapSupport; pass TextBlt trap off to SoftwareTextBlt; fully implement GetNextAvailableVM; add PowerOff and residual stuff from GMTUsingIntervalTimer. 17-Aug-81 13:55:50 Taft Fixed frame handler for SetMP trap. 21-Aug-81 9:54:25 Taft BootButton now requests BaseBoard boot. 26-Sep-81 13:22:52 Taft Fix bug in PowerOff; fully implement SetAutomaticPowerOn. 22-Jun-82 14:59:02 Taft Implement and export MicrocodeBooting. 14-Jul-82 12:36:50 Taft Add trap support for LocalBlkZ, LongBlkZ, and UVersion opcodes. September 28, 1982 3:55 pm Taft Do arithmetic right in PowerOff February 13, 1983 1:21 pm Taft Remove machine code procs to DoradoInputOutput February 27, 1983 2:31 pm Taft Export HeadStartChain.Start; absorb TrapSupportImpl