EURegsImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Louis Monier June 19, 1986 4:43:22 pm PDT
Barth, April 22, 1986 12:27:26 pm PST
Bertrand Serlet August 26, 1986 1:37:24 am PDT
Last Edited by: Louis Monier March 16, 1987 11:43:39 am PST
DIRECTORY CD, CDSimpleRules, CMosB, CoreCreate, CoreOps, CoreProperties, CoreGeometry, EUInner, EUUtils, PWCore, PWObjects, Rope, Sisyph;
EURegsImpl: CEDAR PROGRAM
IMPORTS CD, CDSimpleRules, CMosB, CoreCreate, CoreOps, CoreProperties, CoreGeometry, EUUtils, PWCore, PWObjects, Rope, Sisyph
EXPORTS EUInner =
BEGIN OPEN CoreCreate, EUInner;
l: INT = CMosB.cmosB.lambda;
dpPitch: INT = 140*l;  -- Should be changed whenever the pitch of the DataPath changes!
dReadBus: ROPE ← "cBus"; -- the bus used for debugging
Bus: TYPE = EUUtils.Bus;
Source: TYPE = EUUtils.Source;
DPBus: PROC [index: EUUtils.BusRange] RETURNS [EUUtils.Bus]~{
RETURN[EUUtils.buses[index]]};
DPSource: PROC [index: EUUtils.SourceRange] RETURNS [EUUtils.Source]~{
RETURN[EUUtils.sources[index]]};
-- All the buses at the level of this source
AllBuses: PROC [reg: Source] RETURNS [Wire] ~ {
names: LIST OF WRNIL;
FOR busIndex: EUUtils.BusRange IN EUUtils.BusRange DO
bus: Bus ← DPBus[busIndex];
IF IsBusInReg[bus, reg] THEN names ← CONS[bus.name, names];
ENDLOOP;
RETURN [IF names=NIL THEN NIL ELSE WireList[names]];
};
-- All the buses used as input or output, including the bus for debugging (dReadBus)
ConnectedBuses: PROC [reg: Source] RETURNS [buses: Wire] ~ {
dReadBusPresent: BOOLFALSE;
names: LIST OF WRNIL;
name: ROPE;
FOR i: NAT IN [0..reg.sizeSel) DO
name ← DPBus[reg.inputs[i]].name;  -- name of one input bus
IF Rope.Equal[name, dReadBus] THEN dReadBusPresent ← TRUE;
names ← CONS[name, names];
ENDLOOP;
-- no bus is both an input and an output
name ← DPBus[reg.output].name; -- name of the output of the source
names ← CONS[name, names];
IF Rope.Equal[name, dReadBus] THEN dReadBusPresent ← TRUE;
-- add the dReadBus if not yet present
IF ~dReadBusPresent THEN names ← CONS[dReadBus, names];
buses ← WireList[names];
};
-- Creates the buses on the right side of the cell;
CreateBuses: PROC [reg: Source, leftCT: CellType, horizontalWire: Wire] RETURNS [cellType: CellType] ~ {
public: Wire ← CoreOps.CopyWire[Union[AllBuses[reg], horizontalWire]]; -- do not forget the copy wire! (otherwise, wires are shared and that might result in 815!!!)
cellType ← Cell[name: "CreateBuses", public: public, instances: NIL];
PWCore.SetLayout[cellType, $CreateBusesLayout, $LeftCellType, leftCT];
CoreProperties.PutCellTypeProp[cellType, $Reg, reg];
};
-- Returns NIL if not a datapath bus
IsBus: PROC [name: ROPE] RETURNS [Bus] ~ {
FOR bus: EUUtils.BusRange IN EUUtils.BusRange DO
IF Rope.Equal[EUUtils.buses[bus].name, name] THEN RETURN [EUUtils.buses[bus]];
ENDLOOP;
RETURN[NIL]
};
NameToBus: PROC [name: ROPE] RETURNS [bus: Bus] ~ {
bus ← IsBus[name];
IF bus=NIL THEN ERROR-- unknown bus
};
FindBusPosX: PROC [name: ROPE] RETURNS [INT] ~ {
RETURN[(NameToBus[name].trackPosX*8+2)*CMosB.lambda];
};
IsTopBus: PROC [name: ROPE, reg: Source] RETURNS [BOOLFALSE] ~ {
RETURN [DPSource[NameToBus[name].bottom] = reg];
};
IsBotBus: PROC [name: ROPE, reg: Source] RETURNS [BOOLFALSE] ~ {
RETURN [DPSource[NameToBus[name].top] = reg];
};
IsBusInReg: PROC [bus: Bus, reg: Source] RETURNS [BOOL] ~ {
RETURN[DPSource[bus.top].position<= reg.position
AND reg.position<=DPSource[bus.bottom].position];
};
IsVBus: PROC [name: ROPE, reg: Source] RETURNS [BOOLFALSE] ~ {
bus: Bus ← IsBus[name];
RETURN[IF bus=NIL THEN FALSE ELSE IsBusInReg[bus, reg]];
};
CreateBusesLayout: PWCore.LayoutProc = {
DrawNet: PROC [wire: Wire] ~ {
geometry: LIST OF PWObjects.PlacedObject ← NIL;
name: ROPE ← CoreOps.GetFullWireName[cellType.public, wire];
leftWire: Wire ← CoreCreate.FindWire[leftCT.public, name];
SELECT TRUE FROM
leftWire=NIL => geometry ← LIST [
[CDSimpleRules.Rect[[4*l, sizeY], CMosB.met2], [FindBusPosX[name], 0]]];
NOT IsVBus[name, reg] => {
-- control line or contact on this bus, i.e. pins found on the right side of leftCT
DrawHoriz: CoreGeometry.EachPinProc = {
IF side=right AND layer=CMosB.met THEN geometry ← CONS [
[CDSimpleRules.Rect[[sizeX, max-min], CMosB.met], [0, min]], geometry];
};
[] ← CoreGeometry.EnumerateSides[PWCore.extractMode.decoration, leftCT, leftWire, DrawHoriz];
};
ENDCASE => {
-- contact on this bus
DrawContact: CoreGeometry.EachPinProc = {
IF side#right THEN RETURN;
IF layer#CMosB.met THEN RETURN;
geometry ← CONS [
[CDSimpleRules.Rect[[posX, max-min], CMosB.met], [0, min]],
geometry];
geometry ← CONS [
[CDSimpleRules.Contact[CMosB.met, CMosB.met2], [posX, min]],
geometry];
y1 ← MIN [y1, min]; y2 ← MAX [y2, max];
};
posX: INT ← FindBusPosX[name];
y1: INTIF IsTopBus[name, reg] THEN LAST[INT] ELSE 0;
y2: INTIF IsBotBus[name, reg] THEN FIRST[INT] ELSE sizeY;
[] ← CoreGeometry.EnumerateSides[PWCore.extractMode.decoration, leftCT, leftWire, DrawContact];
geometry ← CONS [
[CDSimpleRules.Rect[[4*l, y2-y1], CMosB.met2], [posX, y1]], geometry];
};
nodes ← CONS [PWObjects.CreateNode[geometry, LIST [[key: $SignalName, val: name], [key: $SignalName, val: name]]], nodes];
};
leftCT: CellType ← NARROW [CoreProperties.GetCellTypeProp[cellType, $LeftCellType]];
leftSize: CD.Position ← CD.InterestSize[PWCore.Layout[leftCT]];
sizeX: INT ← dpPitch-leftSize.x;
sizeY: INT ← leftSize.y;
reg: SourceNARROW [CoreProperties.GetCellTypeProp[cellType, $Reg], Source];
nodes: LIST OF PWObjects.Node ← NIL;
CoreOps.VisitRootAtomics[cellType.public, DrawNet];
obj ← PWObjects.CreateRouting[[0, 0, sizeX, sizeY], nodes];
};
-- Assemble the register (ev. with a tristate driver) with the muxes
-- The inputs in EUUtils.sources[reg].inputs must be in order, i.e. for left: sel[0]->ramA
-- write from cBus (for debugging only) is mapped onto sel[max+1]
-- dRead is mapped onto sel[max+2], unless tristate; then enWrite is mapped onto sel[max+2]
CreateRegAndMuxOnly: PROC [reg: Source, cx: Sisyph.Context] RETURNS [cellType: CellType] ~ {
-- The select lines, i.e. selLeftSrc[0..3), and all public of reg, except "in"
sel: Wire ← Seq["sel", reg.sizeSel+2];
-- Instances: the register and all mux transistors
muxTop: CellType ← Sisyph.ES["RegMuxTop.sch", cx]; -- Vdd, Gnd, sel, muxIn, muxOut
mux: CellType ← Sisyph.ES["RegMux.sch", cx]; -- Vdd, Gnd, sel, muxIn, muxOut
muxOut: Wire ← CoreOps.CreateWire[name: "muxOut"];
tristate: BOOL ← reg.tristate;
ct: CellType ← Sisyph.ES[IF tristate THEN "Tristate.sch" ELSE "Register.sch", cx];
-- the top mux has a slightly different layout
instances: LIST OF CellInstance ← LIST[
Instance[muxTop,
["sel", Index[sel, 0]],
["muxIn", DPBus[reg.inputs[0]].name],
["muxOut", muxOut]]];
FOR i: NAT IN [1..reg.sizeSel) DO
instances ← CONS[
Instance[mux,
["sel", Index[sel, i]],
["muxIn", DPBus[reg.inputs[i]].name],
["muxOut", muxOut]],
instances];
ENDLOOP;
instances ← CONS[ -- sel[max] = write cBus
Instance[mux,
["sel", sel[reg.sizeSel]],
["muxIn", dReadBus],
["muxOut", muxOut]],
instances];
instances ← CONS[
Instance[ct,  -- Vdd, Gnd, in, out, dRead or sel[max+1], dOut
["in", muxOut],
["out", DPBus[reg.output].name],
["enW", Index[sel, reg.sizeSel+1]],
IF tristate THEN [] ELSE ["dOut", dReadBus] ],
instances];
cellType ← Cell[
name: "RegAndMuxOnly",
public: Union[ConnectedBuses[reg], Wires[sel, "Vdd", "Gnd"]],
onlyInternal: Wires[muxOut],
instances: instances
];
PWCore.SetAbutY[cellType];
};
-- Assemble a register with its mux and adds the routing on the right using a table in EUUtils
CreateRegCell: PROC [reg: Source, cx: Sisyph.Context] RETURNS [cellType: CellType] ~ {
sel: Wire ← Seq["sel", reg.sizeSel+2]; -- including enW
leftCt: CellType ← CreateRegAndMuxOnly[reg, cx];
cellType ← Cell[
name: "Reg",
public: Union[AllBuses[reg], Wires[sel, "Vdd", "Gnd"]],
instances: LIST[
Instance[leftCt],
Instance[CreateBuses[reg, leftCt, Wires[sel]]]]
];
PWCore.SetAbutX[cellType];
};
-- Just a replication of 32 register+mux
CreateReg: PUBLIC PROC [regIndex: EUUtils.PipeRange, cx: Sisyph.Context] RETURNS [cellType: CellType] = {
reg: Source ← DPSource[regIndex];
cellType ← SequenceCell[
name: "RegWithMux",
baseCell: CreateRegCell[reg: reg, cx: cx],
count: 32,
sequencePorts: AllBuses[reg]]; -- the only "vertical" wires
PWCore.SetArrayX[cellType];
};
-- Special guys
CreatePDriver: PUBLIC PROC [cx: Sisyph.Context] RETURNS [cellType: CellType] = {
leftCt, thisPDriver, onePDriver: CellType;
reg: Source ← DPSource[EUUtils.pDriverRow];
leftCt ← Sisyph.ES["PDriver.sch", cx];
-- binding to the real buses
thisPDriver ← Cell[
name: "thisPDriver",
public: Wires["r2B", "st3A", "pDriver", "phA", "phB", "nPhA", "nPhB", "Vdd", "Gnd"],
instances: LIST[Instance[leftCt, ["inA", "r2B"], ["inB", "st3A"], ["out", "pDriver"]]]
];
PWCore.SetAbutX[thisPDriver];
-- adding the buses
onePDriver ← Cell[
name: "PDriverWithBuses",
public: Union[AllBuses[reg], Wires["phA", "phB", "nPhA", "nPhB", "Vdd", "Gnd"]],
instances: LIST[
Instance[thisPDriver],
Instance[CreateBuses[reg, thisPDriver, Wires["phA", "phB", "nPhA", "nPhB", "Vdd", "Gnd"]]]]
];
PWCore.SetAbutX[onePDriver];
-- a sequence of 32
cellType ← SequenceCell[
name: "PDriver",
baseCell: onePDriver,
count: 32,
sequencePorts: AllBuses[reg]]; -- the only "vertical" wires
PWCore.SetArrayX[cellType];
};
CreatekRegAndShift: PUBLIC PROC [cx: Sisyph.Context] RETURNS [ct: CellType] = {
ct ← EUUtils.Fetch["kRegAndShift"];
IF ct=NIL THEN {
ct ← Sisyph.ES["kRegAndShift.sch", cx];
EUUtils.Store["kRegAndShift", ct];
};
};
[] ← PWCore.RegisterLayoutAtom[$CreateBusesLayout, CreateBusesLayout, PWCore.DecorateValue];
END.