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 WR ← NIL;
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: BOOL ← FALSE;
names: LIST OF WR ← NIL;
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 [
BOOL ←
FALSE] ~ {
RETURN [DPSource[NameToBus[name].bottom] = reg];
};
IsBotBus:
PROC [name:
ROPE, reg: Source]
RETURNS [
BOOL ←
FALSE] ~ {
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 [
BOOL ←
FALSE] ~ {
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: INT ← IF IsTopBus[name, reg] THEN LAST[INT] ELSE 0;
y2: INT ← IF 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: Source ← NARROW [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];