-- Copyright (C) 1984 by Xerox Corporation. All rights reserved. -- ProcessorHeadDicentra.mesa, HGM, 16-Nov-84 0:34:46 DIRECTORY BitBlt USING [AlignedBBTable, BITBLT, BBptr, BBTableSpace], DicentraInputOutput USING [Input, IOAddress, Output, numberVirtualPages], ESCAlpha USING [aBYTBLTR, aBYTBLT, aDMUL, aSDIV, aSDDIV, aUDDIV], Environment USING [bitsPerByte, bytesPerWord, Byte, PageCount, PageNumber], Frame USING [GetReturnFrame, ReadPC, WritePC], Inline USING [ BITAND, BITSHIFT, BITXOR, DBITSHIFT, DIVMOD, HighHalf, LongCOPY, LongCOPYReverse, LongNumber, LongDiv, LongDivMod, LongMult], Mopcodes USING [zDIS, zDIS2], PrincOps USING [ControlLink, ESCTrapTable, LocalFrameHandle, StateVector], ProcessOperations USING [DisableInterrupts], ProcessorFace USING [GetClockPulses, ProcessorID, SpecialSetMP], SDDefs USING [SD, sOpcodeTrap], MultibusAddresses USING [eprom, first3ComBoard, processorIdLocation, timeout]; ProcessorHeadDicentra: PROGRAM IMPORTS BitBlt, DicentraInputOutput, Frame, Inline, ProcessOperations, ProcessorFace EXPORTS ProcessorFace SHARES ProcessorFace = BEGIN -- ProcessorFace Implementation Start: PUBLIC PROCEDURE = BEGIN temp: ARRAY [0..3) OF WORD; PrincOps.ESCTrapTable­ ¬ ALL[LOOPHOLE[UnimplementedTrapHandler, PrincOps.ControlLink]]; PrincOps.ESCTrapTable[ESCAlpha.aSDIV] ¬ LOOPHOLE[SDIV]; PrincOps.ESCTrapTable[ESCAlpha.aSDDIV] ¬ LOOPHOLE[SDDIV]; PrincOps.ESCTrapTable[ESCAlpha.aUDDIV] ¬ LOOPHOLE[UDDIV]; PrincOps.ESCTrapTable[ESCAlpha.aDMUL] ¬ LOOPHOLE[DMUL]; -- Note: BITBLT is not simulated. PrincOps.ESCTrapTable[ESCAlpha.aBYTBLT] ¬ LOOPHOLE[BYTBLT]; PrincOps.ESCTrapTable[ESCAlpha.aBYTBLTR] ¬ LOOPHOLE[BYTBLTR]; DicentraInputOutput.Output[400B, first3ComBoard]; -- Reset temp ¬ [ DicentraInputOutput.Input[ethernetHostNumber+0], DicentraInputOutput.Input[ethernetHostNumber+1], DicentraInputOutput.Input[ethernetHostNumber+2]]; processorID ¬ LOOPHOLE[temp]; temp[1] ¬ Inline.BITAND[temp[1], 0FF00H]; IF temp[0] # 0260H OR temp[1] # 8C00H THEN BEGIN ProcessOperations.DisableInterrupts[]; ProcessorFace.SpecialSetMP[898]; DO ENDLOOP; END; END; -- KROCK *********** first3ComBoard: DicentraInputOutput.IOAddress = MultibusAddresses.first3ComBoard; ethernetHostNumber: DicentraInputOutput.IOAddress = MultibusAddresses.processorIdLocation; processorID: PUBLIC ProcessorFace.ProcessorID; mp: PUBLIC CARDINAL; SetMP: PUBLIC PROCEDURE [mpnew: CARDINAL] = BEGIN ProcessorFace.SpecialSetMP[mp ¬ mpnew]; END; -- Virtual memory layout GetNextAvailableVM: PUBLIC PROCEDURE [page: Environment.PageNumber] RETURNS [firstPage: Environment.PageNumber, count: Environment.PageCount] = BEGIN SELECT page FROM 0 => RETURN[0, DicentraInputOutput.numberVirtualPages]; ENDCASE => RETURN[0, 0]; END; -- Interval time microsecondsPerHundredPulses: PUBLIC CARDINAL ¬ 1280; -- Naked notifies cvTimeoutMask: WORD = 100000B; -- Microcode uses bit 0 reservedNakedNotifyMask: PUBLIC WORD ¬ cvTimeoutMask; -- Condition variable time millisecondsPerTick: PUBLIC CARDINAL ¬ 50; -- A lot of this has already been done by the initialization microcode InitializeClocks: PROCEDURE = BEGIN timeout: DicentraInputOutput.IOAddress = MultibusAddresses.timeout; eprom: DicentraInputOutput.IOAddress = MultibusAddresses.eprom; -- Now the Process ticker -- PClk = 400ns. Counter runs off PClk/2. 50ms => count should be 62500 = F424. WriteMisc[0F4H, eprom + 01AH]; -- Cnt3 MSB WriteMisc[024H, eprom + 01BH]; -- Cnt3 LSB WriteMisc[080H, eprom + 01EH]; -- Cnt 3 Mode ¬ Cont, Pulse WriteMisc[000H, eprom + 004H]; -- Int Vect for Timers -- 0 => Tick, 6 => 2+ Ticks (Error), 0FF => No interrupt pending WriteMisc[097H, eprom + 001H]; -- Master Config Control ¬ Enables, Link Timers WriteMisc[080H, eprom + 000H]; -- Master Interrupt Control ¬ MIE WriteMisc[0C6H, eprom + 00CH]; -- Counter 3 Cntrl ¬ Set IE, GCB, Trgr BEGIN -- Yetch. The trigger doesn't really happen until the first clock pulse. start: LONG CARDINAL ¬ ProcessorFace.GetClockPulses[]; DO now: LONG CARDINAL ¬ ProcessorFace.GetClockPulses[]; IF Inline.HighHalf[now] # Inline.HighHalf[start] THEN EXIT; ENDLOOP; END; END; WriteMisc: PROCEDURE [data: UNSPECIFIED, address: DicentraInputOutput.IOAddress] = BEGIN DicentraInputOutput.Output[data, address]; END; -- Booting and power control BootButton: PUBLIC PROCEDURE = BEGIN timeout: DicentraInputOutput.IOAddress = MultibusAddresses.timeout; ProcessOperations.DisableInterrupts[]; DO WriteMisc[001H, timeout + 000H]; -- Master Interrupt Control ¬ Reset WriteMisc[000H, timeout + 000H]; -- Master Interrupt Control ¬ No Reset WriteMisc[00EH, timeout + 006H]; -- Port C Direction ¬ Bit 0 ¬ output WriteMisc[000H, timeout + 00FH]; -- Port C Data ¬ 0 WriteMisc[010H, timeout + 001H]; -- Master Config Control ¬ Enable Port C ENDLOOP; END; -- Software assist for microcode -- assumes return link is a frame, and has been started InstructionNotImplemented: ERROR = CODE; -- This should actually be in traps UnimplementedTrapHandler: PRIVATE PROCEDURE = { v: RECORD [a: ARRAY [0..3) OF WORD, state: PrincOps.StateVector]; v.state ¬ STATE; ERROR InstructionNotImplemented}; -- Implemention of instructions not implemented in microcode Number: TYPE = Inline.LongNumber; SDIV: PROC [q, r: INTEGER] RETURNS [INTEGER <<, INTEGER>>] = BEGIN -- remainder returned above the stack. Pop: PROC [INTEGER, INTEGER] RETURNS [INTEGER] = MACHINE CODE {Mopcodes.zDIS}; lf: PrincOps.LocalFrameHandle; state: PrincOps.StateVector; negnum, negden: BOOLEAN; state ¬ STATE; IF negden ¬ (r < 0) THEN r ¬ -r; IF negnum ¬ (q < 0) THEN q ¬ -q; [quotient: q, remainder: r] ¬ Inline.DIVMOD[num: q, den: r]; IF Inline.BITXOR[negnum, negden] # 0 THEN q ¬ -q; IF negnum THEN r ¬ -r; lf ¬ Frame.GetReturnFrame[]; Frame.WritePC[pc: [Frame.ReadPC[lf] + 2], lf: lf]; STATE ¬ state; RETURN Pop[q, r]; END; -- SDIV-- DMUL:PROC [a, b: Number] RETURNS [product: Number] = BEGIN lf: PrincOps.LocalFrameHandle; state: PrincOps.StateVector; state ¬ STATE; product.lc ¬ Inline.LongMult[a.lowbits, b.lowbits]; product.highbits ¬ product.highbits + a.lowbits*b.highbits + a.highbits*b.lowbits; lf ¬ Frame.GetReturnFrame[]; Frame.WritePC[pc: [Frame.ReadPC[lf] + 2], lf: lf]; STATE ¬ state; END; --DMUL-- SDDIV: PROC [num, den: Number] RETURNS [quotient <<, remainder>>: Number] = BEGIN -- remainder returned above the stack Pop2: PROC [Number, Number] RETURNS [Number] = MACHINE CODE {Mopcodes.zDIS2}; remainder: Number; lf: PrincOps.LocalFrameHandle; negNum, negDen: BOOLEAN ¬ FALSE; state: PrincOps.StateVector; state ¬ STATE; IF INTEGER[num.highbits] < 0 THEN {negNum ¬ TRUE; num.li ¬ -num.li}; IF INTEGER[den.highbits] < 0 THEN {negDen ¬ TRUE; den.li ¬ -den.li}; [quotient: quotient, remainder: remainder] ¬ DUDivMod[num, den]; IF Inline.BITXOR[negNum, negDen] # 0 THEN quotient.li ¬ -quotient.li; IF negNum THEN remainder.li ¬ -remainder.li; lf ¬ Frame.GetReturnFrame[]; Frame.WritePC[pc: [Frame.ReadPC[lf] + 2], lf: lf]; STATE ¬ state; RETURN Pop2[quotient, remainder]; END; --SDDIV-- UDDIV: PROC [num, den: Number] RETURNS [quotient <<, remainder>>: Number] = BEGIN Pop2: PROC [Number, Number] RETURNS [Number] = MACHINE CODE {Mopcodes.zDIS2}; remainder: Number; lf: PrincOps.LocalFrameHandle; state: PrincOps.StateVector; state ¬ STATE; [quotient: quotient, remainder: remainder] ¬ DUDivMod[num, den]; lf ¬ Frame.GetReturnFrame[]; Frame.WritePC[pc: [Frame.ReadPC[lf] + 2], lf: lf]; STATE ¬ state; RETURN Pop2[quotient, remainder]; END; --UDDIV-- DUDivMod: PROC [num, den: Number] RETURNS [quotient, remainder: Number] = BEGIN OPEN Inline; qq: CARDINAL; count: [0..31); lTemp: Number; IF den.highbits = 0 THEN BEGIN [quotient.highbits, qq] ¬ LongDivMod[ num: LOOPHOLE[Number[num[lowbits: num.highbits, highbits: 0]]], den: den.lowbits]; [quotient.lowbits, remainder.lowbits] ¬ LongDivMod[ num: LOOPHOLE[Number[num[lowbits: num.lowbits, highbits: qq]]], den: den.lowbits]; remainder.highbits ¬ 0; END ELSE BEGIN count ¬ 0; quotient.highbits ¬ 0; lTemp ¬ den; WHILE lTemp.highbits # 0 DO -- normalize lTemp.lc ¬ DBITSHIFT[lTemp.lc, -1]; count ¬ count + 1; ENDLOOP; IF num.highbits >= lTemp.lowbits THEN { -- subtract off 2­16*divisor and fix up count div: Number ¬ Number[num[lowbits: 0, highbits: lTemp.lowbits]]; qq ¬ LongDiv[num.lc - div.lc, lTemp.lowbits]/2 + 100000B; count ¬ count - 1} ELSE qq ¬ LongDiv[num.lc, lTemp.lowbits]; -- trial quotient qq ¬ BITSHIFT[qq, -count]; lTemp.lc ¬ LongMult[den.lowbits, qq]; -- multiply by trial quotient lTemp.highbits ¬ lTemp.highbits + den.highbits*qq; UNTIL lTemp.lc <= num.lc DO -- decrease quotient until product is small enough lTemp.lc ¬ lTemp.lc - den.lc; qq ¬ qq - 1; ENDLOOP; quotient.lowbits ¬ qq; remainder.lc ¬ num.lc - lTemp.lc; END; END; --DUDivMod-- BYTBLT: PROC [ destBase: LONG ORDERED POINTER, destIndex, count: CARDINAL, sourceBase: LONG ORDERED POINTER, sourceIndex: CARDINAL] = BEGIN OPEN Environment; lf: PrincOps.LocalFrameHandle = Frame.GetReturnFrame[]; bba: BitBlt.BBTableSpace; bbt: BitBlt.BBptr = BitBlt.AlignedBBTable[@bba]; MaxBytesPerScanLine: CARDINAL = 40B; bytesPerScanLine: CARDINAL ¬ MaxBytesPerScanLine; bitsPerScanLine: CARDINAL; lines, tail: CARDINAL; destBase ¬ destBase + destIndex/2; destIndex ¬ destIndex MOD 2; sourceBase ¬ sourceBase + sourceIndex/2; sourceIndex ¬ sourceIndex MOD 2; IF destIndex = sourceIndex THEN BEGIN -- Can use Inline.LongCOPY s: LONG POINTER TO PACKED ARRAY [0..0) OF Environment.Byte ¬ LOOPHOLE[sourceBase]; d: LONG POINTER TO PACKED ARRAY [0..0) OF Environment.Byte ¬ LOOPHOLE[destBase]; words: CARDINAL; moved: CARDINAL ¬ 0; IF destIndex # 0 THEN BEGIN -- Thus destIndex = sourceIndex = 1 d[1] ¬ s[1]; d ¬ d+1; s ¬ s+1; moved ¬ 1; END; words ¬ (count-moved)/2; Inline.LongCOPY[to: d, from: s, nwords: words]; IF (moved + 2*words) # count THEN -- d[2*words] ¬ s[2*words]; -- Move the one remaining byte Frame.WritePC[pc: [Frame.ReadPC[lf] + 2], lf: lf]; RETURN; END; << Can't use Inline.LongCOPY, because source and destination are "not aligned", i.e., one starts at a word boundary, the other in the middle of a word. >> SELECT destBase FROM > sourceBase => BEGIN wDiff: LONG CARDINAL = destBase - sourceBase; IF wDiff <= LAST[CARDINAL]/2 THEN bytesPerScanLine ¬ CARDINAL[wDiff]* bytesPerWord + destIndex - sourceIndex; END; < sourceBase => NULL; ENDCASE => IF sourceIndex < destIndex THEN bytesPerScanLine ¬ 1; bytesPerScanLine ¬ MIN[bytesPerScanLine, MaxBytesPerScanLine]; bitsPerScanLine ¬ bytesPerScanLine*bitsPerByte; [quotient: lines, remainder: tail] ¬ Inline.DIVMOD[num: count, den: bytesPerScanLine]; bbt­ ¬ [ dst: [word: destBase, bit: destIndex*bitsPerByte], dstBpl: bitsPerScanLine, src: [word: sourceBase, bit: sourceIndex*bitsPerByte], srcDesc: [srcBpl[bitsPerScanLine]], width: bitsPerScanLine, height: lines, flags: [ direction: forward, disjoint: FALSE, disjointItems: FALSE, gray: FALSE, srcFunc: null, dstFunc: null]]; IF lines # 0 THEN BitBlt.BITBLT[bbt]; IF tail # 0 THEN BEGIN count ¬ lines*bytesPerScanLine; bbt.dst.word ¬ bbt.dst.word + count/2; bbt.src.word ¬ bbt.src.word + count/2; IF count MOD 2 = 1 THEN BEGIN IF destIndex = 0 THEN bbt.dst.bit ¬ bitsPerByte ELSE bbt.dst ¬ [word: bbt.dst.word + 1, bit: 0]; IF sourceIndex = 0 THEN bbt.src.bit ¬ bitsPerByte ELSE bbt.src ¬ [word: bbt.src.word + 1, bit: 0]; END; bbt.width ¬ bitsPerByte*tail; bbt.height ¬ 1; BitBlt.BITBLT[bbt]; END; Frame.WritePC[pc: [Frame.ReadPC[lf] + 2], lf: lf]; END; --BYTBLT-- BYTBLTR: PROC [ destBase: LONG ORDERED POINTER, destIndex, count: CARDINAL, sourceBase: LONG ORDERED POINTER, sourceIndex: CARDINAL] = BEGIN OPEN Environment; lf: PrincOps.LocalFrameHandle ¬ Frame.GetReturnFrame[]; bba: BitBlt.BBTableSpace; bbt: BitBlt.BBptr = BitBlt.AlignedBBTable[@bba]; MaxBytesPerScanLine: CARDINAL = 40B; bytesPerScanLine: CARDINAL ¬ MaxBytesPerScanLine; bitsPerScanLine: CARDINAL; lines, tail: CARDINAL; destBase ¬ destBase + destIndex/2; destIndex ¬ destIndex MOD 2; sourceBase ¬ sourceBase + sourceIndex/2; sourceIndex ¬ sourceIndex MOD 2; IF destIndex = sourceIndex THEN BEGIN -- Can use Inline.LongCOPYReverse s: LONG POINTER TO PACKED ARRAY [0..0) OF Environment.Byte ¬ LOOPHOLE[sourceBase]; d: LONG POINTER TO PACKED ARRAY [0..0) OF Environment.Byte ¬ LOOPHOLE[destBase]; words: CARDINAL; odd: CARDINAL ¬ count MOD 2; IF sourceIndex # odd THEN BEGIN d[count-odd] ¬ s[count-odd]; count ¬ count - 1; END; words ¬ count/2; IF sourceIndex # 0 THEN BEGIN Inline.LongCOPYReverse[to: d+1, from: s+1, nwords: words]; d[1] ¬ s[1]; -- Move the one remaining byte END ELSE Inline.LongCOPYReverse[to: d, from: s, nwords: words]; Frame.WritePC[pc: [Frame.ReadPC[lf] + 2], lf: lf]; RETURN; END; SELECT sourceBase FROM > destBase => BEGIN wDiff: LONG CARDINAL = sourceBase - destBase; IF wDiff <= LAST[CARDINAL]/2 THEN bytesPerScanLine ¬ CARDINAL[wDiff]*bytesPerWord + sourceIndex - destIndex; END; < destBase => NULL; ENDCASE => IF destIndex < sourceIndex THEN bytesPerScanLine ¬ 1; bytesPerScanLine ¬ MIN[bytesPerScanLine, MaxBytesPerScanLine]; bitsPerScanLine ¬ bytesPerScanLine*bitsPerByte; [quotient: lines, remainder: tail] ¬ Inline.DIVMOD[num: count, den: bytesPerScanLine]; bbt­ ¬ [ dst: [ word: destBase + (count + destIndex - bytesPerScanLine)/2, bit: ((count + destIndex - bytesPerScanLine) MOD 2)*bitsPerByte], dstBpl: -INTEGER[bitsPerScanLine], src: [ word: sourceBase + (count + sourceIndex - bytesPerScanLine)/2, bit: ((count + sourceIndex - bytesPerScanLine) MOD 2)*bitsPerByte], srcDesc: [srcBpl[-INTEGER[bitsPerScanLine]]], width: bitsPerScanLine, height: lines, flags: [ direction: backward, disjoint: FALSE, disjointItems: FALSE, gray: FALSE, srcFunc: null, dstFunc: null]]; IF lines # 0 THEN BitBlt.BITBLT[bbt]; IF tail # 0 THEN BEGIN bbt.dst ¬ [word: destBase, bit: destIndex*bitsPerByte]; bbt.src ¬ [word: sourceBase, bit: sourceIndex*bitsPerByte]; bbt.width ¬ bitsPerByte*tail; bbt.height ¬ 1; BitBlt.BITBLT[bbt]; END; Frame.WritePC[pc: [Frame.ReadPC[lf] + 2], lf: lf]; END; --BYTBLTR-- -- Main body code InitializeClocks[]; SDDefs.SD[SDDefs.sOpcodeTrap] ¬ LOOPHOLE[UnimplementedTrapHandler]; END....