-- 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....