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