EU2Impl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Louis Monier June 17, 1986 8:06:14 pm PDT
McCreight, May 12, 1986 12:23:08 pm PDT
Bertrand Serlet August 11, 1986 11:58:20 pm PDT
Barth, April 19, 1986 5:25:00 pm PST
Last Edited by: Louis Monier September 12, 1986 1:52:15 pm PDT
Don Curry November 2, 1986 11:58:10 am PST
DIRECTORY CMosB, Core, CoreClasses, CoreFlat, CoreIO, CoreProperties, Dragon, DragonRosemary, EU2, EU2Arith, EU2Utils, Ports, Rosemary;
EU2Impl:
CEDAR
PROGRAM
IMPORTS CoreClasses, CoreFlat, CoreIO, CoreProperties, DragonRosemary, EU2Arith, EU2Utils, Ports, Rosemary
EXPORTS EU2 =
BEGIN OPEN EU2;
Wire: TYPE = Core.Wire;
CellType: TYPE = Core.CellType;
ROPE: TYPE = Core.ROPE;
Properties: TYPE = Core.Properties;
useCachedEU2: BOOL ← FALSE;
public: Wire ← EU2Utils.GenWiresForBonnie[];
Vdd, Gnd, PadVdd, PadGnd, PhA, PhB, VRef, DPRejectB, DPData: PUBLIC NAT;
KBus, EURdFromPBus3AB, EUWriteToPBus3AB, EUAluOp2AB, EUCondSel2AB, EUCondition2B : PUBLIC NAT;
DShA, DShB, DShRd, DShWt, DShIn, DShOut, DHold, DStAd: PUBLIC NAT;
CreateEU2:
PUBLIC
PROC [ typeData:
REF EUTypeData ←
NIL, fullEU:
BOOL ←
FALSE]
RETURNS [ cellType: CellType ] = {
name: ROPE ← "EU2";
props: Properties ← CoreProperties.Props[[$ClusterInfo, typeData]];
[Vdd, Gnd, PadVdd, PadGnd, PhA, PhB, VRef, DPRejectB, DPData] ← Ports.PortIndexes[public, "Vdd", "Gnd", "PadVdd", "PadGnd", "PhA", "PhB", "VRef", "DPRejectB", "DPData"];
[KBus, EURdFromPBus3AB, EUWriteToPBus3AB, EUAluOp2AB, EUCondSel2AB, EUCondition2B] ← Ports.PortIndexes[public, "KBus", "EURdFromPBus3AB", "EUWriteToPBus3AB", "EUAluOp2AB", "EUCondSel2AB", "EUCondition2B"];
[DShA, DShB, DShRd, DShWt, DShIn, DShOut, DHold, DStAd] ← Ports.PortIndexes[public, "DShA", "DShB", "DShRd", "DShWt", "DShIn", "DShOut", "DHold", "DStAd"];
cellType ←
SELECT
TRUE
FROM
~fullEU => CoreClasses.CreateUnspecified[public, name, props],
fullEU AND ~useCachedEU2 => ERROR,
ENDCASE => CoreIO.RestoreCellType["EU2"];
[] ← Rosemary.SetFixedWire[cellType.public[Vdd], H];
[] ← Rosemary.SetFixedWire[cellType.public[Gnd], L];
[] ← Rosemary.SetFixedWire[cellType.public[PadVdd], H];
[] ← Rosemary.SetFixedWire[cellType.public[PadGnd], L];
Ports.InitPorts[cellType, lc, none, "DPData", "KBus"];
Ports.InitPorts[cellType, c, none, "EUAluOp2AB", "EUCondSel2AB", "DStAd"];
Ports.InitPorts[cellType, b, drive, "EUCondition2B", "DShOut"];
[] ← Rosemary.BindCellType[cellType: cellType, roseClassName: EU2RoseClass];
[] ← CoreFlat.CellTypeCutLabels[on: cellType, l1: EU2RoseClass];
};
EU2RoseClass: ROPE = Rosemary.Register[roseClassName: "EU2", init: EU2Init, evalSimple: EU2Simple];
EU2Init: Rosemary.InitProc = {
state: EU2State ← NEW[EU2StateRec -- [ nRegs ] -- ];
state.data ← NARROW[CoreProperties.GetCellTypeProp[cellType, $ClusterInfo]];
FOR i:
NAT
IN [0..nRegs)
DO
state.ram[i] ← 0;
ENDLOOP;
state.ram[EU2Utils.constAdr+1] ← 1;
state.ram[EU2Utils.constAdr+2] ← 2;
state.ram[EU2Utils.constAdr+3] ← 3;
stateAny ← state;
};
EU2Simple: Rosemary.EvalProc = {
state: EU2State ← NARROW[stateAny];
{OPEN state, EU2Utils; -- only for concision!
aAdr, bAdr, cAdr: CARD; -- actually, only bytes
lSrc, rSrc, stSrc: NAT;
st3IsC: BOOL;
EUAluLeftSrc1BA: Dragon.ALULeftSources;
2 bits {aBus(0), rBus(1), cBus(2), reserve3(3)}
EUAluRightSrc1BA: Dragon.ALURightSources;
3 bits {bBus(0), rBus(1), cBus(2), kBus(3), fCtlReg(4)}
EUStore2ASrc1BA: Dragon.Store2ASources;
2 bits {bBus(0), rBus(1), cBus(2), reserve3(3)}
p[KBus].d ← p[DPData].d ← none;
-- PhA phase. Note that rejectBA alone inhibits almost any state change during PhA
IF p[PhA].b
THEN {
-- Updating the RAM addresses and various control bits; notice the role of reject
[aAdr, bAdr, cAdr, st3IsC, lSrc, rSrc, stSrc] ← EU2Arith.ExplodeKReg[simRegs[kReg]];
EUStore2ASrc1BA ← VAL[stSrc];
EUAluRightSrc1BA ← VAL[rSrc];
EUAluLeftSrc1BA ← VAL[lSrc];
IF rejectBA THEN cAdr ← marAdr; -- force address
-- On every PhA with RejectBA the faulty address is saved in ram[euMAR]; the EU generates the appropriate cAdr when RejectBA is sensed, so the rule is: we always write into the register file!
IF cAdr # junkAdr
THEN {
IF data #
NIL
AND data.noteStore #
NIL
AND
NOT data.storeNoted
THEN {
data.noteStore[data: data.data, reg: cAdr, value: simRegs[cBus]];
data.storeNoted ← TRUE;
};
SELECT cAdr
FROM
IFUAdr => {p[KBus].d ← drive; p[KBus].lc ← simRegs[cBus]};
IN [stackAdr .. bogusAdr) => ram[cAdr] ← simRegs[cBus];
ENDCASE => DragonRosemary.Assert[FALSE, "EU cAdr out of range"];
IF cAdr=fieldAdr THEN simRegs[field] ← simRegs[cBus];
};
IF ~rejectBA AND ~conditionBA THEN carryAB ← carryBA;
IF ~rejectBA
THEN {
simRegs[left] ←
SELECT EUAluLeftSrc1BA
FROM
aBus => ram[aAdr],
rBus => simRegs[r2B],
cBus => simRegs[cBus],
ENDCASE => ERROR;
simRegs[right] ←
SELECT EUAluRightSrc1BA
FROM
bBus => ram[bAdr],
rBus => simRegs[r2B],
cBus => simRegs[cBus],
kBus => p[KBus].lc,
fCtlReg => simRegs[field],
ENDCASE => ERROR;
simRegs[st2A] ←
SELECT EUStore2ASrc1BA
FROM
bBus => ram[bAdr],
cBus => simRegs[cBus],
rBus => simRegs[r2B],
ENDCASE => ERROR;
simRegs[r3A] ← simRegs[r2B];
simRegs[st3A] ← IF st3IsC THEN simRegs[cBus] ELSE simRegs[st2B];
p[DPData].d ← drive; -- Send address to Cache only once: the cache latches it.
p[DPData].lc ← simRegs[r2B];
};
}
ELSE IF data # NIL THEN data.storeNoted ← FALSE;
-- PhiB phase. Most of the computations take place during PhB
IF p[PhB].b
THEN {
aluOut, fuOut: CARD; -- temporary
overflow, c32, lz, ez, il: BOOL;
aluOps: Dragon.ALUOps ← VAL[p[EUAluOp2AB].c];
DPRejectB is valid at the end of PhiB but bogus on PhiA, so it must be latched on PhiB.
rejectBA ← p[DPRejectB].b;
-- Receive RAM addresses and control bits on KBus from IFU
simRegs[kReg] ← p[KBus].lc;
-- PBus: notice that in case of reject during a store, we keep sending the data even though it is useless; this could be changed if needed.
DragonRosemary.Assert[NOT (p[EUWriteToPBus3AB].b AND p[EURdFromPBus3AB].b)];
IF (p[EUWriteToPBus3AB].b AND p[EURdFromPBus3AB].b) THEN ERROR;
simRegs[r3B] ← simRegs[r3A]; -- copy address
simRegs[dataIn] ← p[DPData].lc; -- latch whatever comes from the pads
-- Driving the PBus in case of a store
IF p[EUWriteToPBus3AB].b
THEN {
p[DPData].d ← drive;
p[DPData].lc ← simRegs[st3A]
};
-- This instruction must be the last one of the PBus stuff: don't touch r3B or dataIn after!
-- We select dataIn only in the case of a fetch without reject
simRegs[cBus] ←
IF
NOT p[DPRejectB].b
AND p[EURdFromPBus3AB].b
THEN simRegs[dataIn]
ELSE simRegs[r3B];
-- Data pipe
simRegs[st2B] ← simRegs[st2A];
-- ALU computation
[aluOut, c32, carryBA] ← EU2Arith.ALUOperation[aluOps, simRegs[left], simRegs[right], carryAB];
-- FU computation
fuOut ← IF aluOps=FOP THEN EU2Arith.FieldOp[simRegs[left], simRegs[st2A], simRegs[right]] ELSE 0;
-- Now pick up the result
simRegs[r2B] ←
SELECT aluOps
FROM
BndChk => simRegs[left],
FOP => fuOut,
ENDCASE => aluOut;
-- Condition and trap generation
overflow ← ((c32 # EU2Arith.EBFLC[aluOut, 0]) # (EU2Arith.EBFLC[simRegs[left], 0] # EU2Arith.EBFLC[simRegs[right], 0]));
lz ← (c32#(EU2Arith.EBFLC[simRegs[left], 0]#EU2Arith.EBFLC[simRegs[right], 0]));
ez ← aluOut=0;
il ← EU2Arith.LispTest[simRegs[left]] OR EU2Arith.LispTest[simRegs[right]] OR EU2Arith.LispTest[aluOut];
conditionBA ←
SELECT Dragon.CondSelects[
VAL[p[EUCondSel2AB].c]]
FROM
False => FALSE,
EZ => ez,
LZ => lz, -- VSub<0
LE => ez OR lz, -- VSub<=0,
NE => ~ez,
GE => ~lz, -- VSub>=0
GZ => ~(ez OR lz), -- VSub>0,
OvFl => overflow,
BC => ~c32,
IL => il, -- the 3 high-order bits must be the same for both operands and result
NotBC => c32,
NotIL => ~il,
ModeFault => TRUE,
ENDCASE => ERROR Rosemary.Stop["Invalid EUCondition2B Code"];
p[EUCondition2B].b ← conditionBA;
};
}};
globalPos: NAT ← 0; -- add the increment, then put the pad
SetFirst: PROC [pos: NAT] = {globalPos ← pos};
Next: PROC [] RETURNS [NAT] = {RETURN[Move[1]]};
Move:
PROC [delta:
NAT]
RETURNS [
NAT] = {
globalPos ← globalPos+delta;
RETURN[globalPos]};
END.