BooleCoreImpl.mesa
Copyright Ó 1985, 1986, 1987 by Xerox Corporation. All rights reversed.
Created by Bertrand Serlet August 13, 1985 5:47:24 pm PDT
Bertrand Serlet May 19, 1987 0:16:27 am PDT
Louis Monier June 3, 1986 7:12:53 pm PDT
Barth, April 2, 1987 11:37:41 am PST
DIRECTORY
Boole, BooleCore,
CD, CDBasics, CDDirectory, CDInstances, CDProperties, CDRects, CMosB,
Core, CoreClasses, CoreCreate, CoreOps, CoreProperties,
RefTab, GList, IO,
PW, PWCore,
Rope,
Sinix, Sisyph,
TilingClass,
TerminalIO;
BooleCoreImpl: CEDAR PROGRAM
IMPORTS Boole, CD, CDBasics, CDDirectory, CDInstances, CDProperties, CDRects, CMosB, CoreClasses, CoreCreate, CoreOps, CoreProperties, RefTab, GList, IO, PW, PWCore, Rope, Sinix, Sisyph, TilingClass, TerminalIO
EXPORTS BooleCore
SHARES Boole =
BEGIN OPEN BooleCore;
Basics
false: Expression = Boole.false;
true: Expression = Boole.true;
Signal: SIGNAL = CODE;
debug: BOOLTRUE;
cellLibrary: PRIVATE CD.Design ← NIL;
GetCellLibrary: PUBLIC PROC RETURNS [CD.Design] = {
IF cellLibrary#NIL THEN RETURN [cellLibrary];
cellLibrary ← PW.OpenDesign["BooleLibrary"];
RETURN [cellLibrary];
};
GetCellLibraryCell: PUBLIC PROC [name: ROPE] RETURNS [CellType ← NIL] = {
name ← Rope.Cat[name, ".sch"];
IF CDDirectory.Fetch[GetCellLibrary[], name].object=NIL THEN RETURN [NIL];
RETURN [Sisyph.ES[name, Sisyph.Create[GetCellLibrary[]]]];
};
Connection with Core
EqualInt: PUBLIC PROC [wire: Wire, int: INT] RETURNS [expr: Expression] = {
Andify: PROC [wire: Wire] = {
var: Variable ← wire;
max ← max / 2;
IF int>=max THEN int ← int - max ELSE var ← Boole.Not[var];
expr ← Boole.And[var, expr];
};
count: NAT ← CoreOps.WireBits[wire];
max: INT ← 1;
WHILE count>0 DO max ← max * 2; count ← count -1 ENDLOOP;
IF int>=max THEN Signal[];
expr ← true;
CoreOps.VisitRootAtomics[wire, Andify];
IF int#0 THEN Signal[];
};
Utilities
TranslateVar: PROC [wireToRefInt: RefTab.Ref, source: Expression] RETURNS [Expression] = {
whenTrue, whenFalse: Expression;
var: Variable = Boole.FindVar[source];
newVar: Variable ← NARROW [RefTab.Fetch[wireToRefInt, var].val];
IF source=true OR source=false THEN RETURN [source];
[whenTrue, whenFalse] ← Boole.Eval[var, source];
IF newVar=NIL THEN ERROR; -- variable is not an input wire!
RETURN [Boole.If[newVar, TranslateVar[wireToRefInt, whenTrue], TranslateVar[wireToRefInt, whenFalse]]];
};
CheckAtomic: PROC [public: Wire, name: ROPE] = {
wire: Wire ← CoreCreate.FindWire[public, name];
IF wire=NIL OR wire.size#0 THEN {
TerminalIO.PutF["*** Atomic wire %g does not appear correctly in public\n", IO.rope[name]];
Signal[];
};
};
CheckPlusMinus: PROC [public: Wire, name: ROPE] = {
wire: Wire ← CoreCreate.FindWire[public, name];
IF wire=NIL OR wire.size#2 OR ~Rope.Equal[CoreOps.GetShortWireName[wire[0]], "Plus"] OR wire[0].size#0 OR ~Rope.Equal[CoreOps.GetShortWireName[wire[1]], "Minus"] OR wire[1].size#0 THEN {
TerminalIO.PutF["*** Structured (Plus, Minus) wire %g does not appear correctly in public\n", IO.rope[name]];
Signal[];
};
};
CreatePlusMinus: PUBLIC PROC [name: ROPE] RETURNS [wire: Wire] = {
wire ← CoreOps.CreateWire[
elements: LIST [CoreOps.CreateWire[name: "Plus"], CoreOps.CreateWire[name: "Minus"]],
name: name];
};
CDCell: PROC [case: ATOM] RETURNS [obj: CD.Object] = {
obj ← CDDirectory.Fetch[GetCellLibrary[], IO.PutR[IO.atom[case], IO.rope[".mask"]]].object;
};
CoreCell: PROC [case: ATOM] RETURNS [cellType: CellType] = {
schCell: CD.Object ← CDDirectory.Fetch[GetCellLibrary[], IO.PutR[IO.atom[case], IO.rope[".sch"]]].object;
IF schCell=NIL THEN {
obj: CD.Object ← CDDirectory.Fetch[GetCellLibrary[], IO.PutR[IO.atom[case], IO.rope[".mask"]]].object;
cellType ← PWCore.FromLayoutWithoutPublic[obj];
RETURN;
};
cellType ← NARROW [Sinix.Extract[schCell, Sisyph.mode, NIL, Sisyph.Create[GetCellLibrary[]]].result];
};
AddCaseCellsInLibrary: PW.GeneratorProc = {
l: INT = CMosB.lambda;
size: CD.Position = [8*l, 12*l];
AtomicTile: TYPE = {nope, gnd, trans};
masks: ARRAY AtomicTile OF CD.Object ← [PW.Get[GetCellLibrary[], "AtomicNope.mask"], PW.Get[GetCellLibrary[], "AtomicGnd.mask"], PW.Get[GetCellLibrary[], "AtomicTrans.mask"]];
Square: PROC [name: ATOM, upLeft, upRight, lowLeft, lowRight: AtomicTile] RETURNS [cell: CD.Object] = {
IncludeMask: PROC [mask: CD.Object, pos: CD.Position, orient: CD.Orientation] = {
instances ← CONS [CDInstances.NewInst[mask, [CDBasics.SubPoints[pos, CDBasics.BaseOfRect[CDBasics.MapRect[CD.InterestRect[mask], [[0, 0], orient]]]], orient]], instances];
};
IncludePin: PROC [name: ROPE, layer: CD.Layer, pos: CD.Position, size: CD.Position] = {
inst: CD.Instance = CDInstances.NewInst[CDRects.CreateRect[size, layer], [pos]];
instances ← CONS [inst, instances];
CDProperties.PutInstanceProp[inst, $SignalName, name];
};
instances: CD.InstanceList ← NIL;
IncludeMask[masks[upLeft], [0, size.y], original];
IncludeMask[masks[upRight], size, mirrorX];
IncludeMask[masks[lowLeft], [0, 0], rotate180X];
IncludeMask[masks[lowRight], [size.x, 0], rotate180];
IncludePin["Input", CMosB.pol, [3*l, 0], [2*l, 2*size.y]];
IncludePin["Input", CMosB.met2, [2*l, 0], [4*l, 2*size.y]];
IncludePin["NotInput", CMosB.pol, [11*l, 0], [2*l, 2*size.y]];
IncludePin["NotInput", CMosB.met2, [10*l, 0], [4*l, 2*size.y]];
IncludePin["Gnd", CMosB.met, [0, 10*l], [2*size.x, 4*l]];
IncludePin["Plus", CMosB.met, [14*l, 19*l], [2*l, 3*l]];
IncludePin["Minus", CMosB.met, [14*l, 2*l], [2*l, 3*l]];
IF upLeft=trans OR upRight=trans
THEN IncludePin["PlusLeft", CMosB.met, [0, 19*l], [2*l, 3*l]];
IF lowLeft=trans OR lowRight=trans
THEN IncludePin["MinusLeft", CMosB.met, [0, 2*l], [2*l, 3*l]];
cell ← PW.CreateCell[instances, [0, 0, 2*size.x, 2*size.y]];
cell ← PW.Flatten[cell];
[] ← CDDirectory.Include[design, cell, IO.PutFR["%g.mask", IO.atom[name]]];
CoreOps.Print[Sinix.Extract[cell, PWCore.extractMode].result, TerminalIO.TOS[]];
};
RETURN [PW.AbutListX[LIST [
Square[$Case11, gnd, gnd, nope, nope],
Square[$Case00, nope, nope, gnd, gnd],
Square[$Case10, gnd, nope, nope, gnd],
Square[$Case01, nope, gnd, gnd, nope],
Square[$Case1X, gnd, nope, nope, trans],
Square[$Case0X, nope, trans, gnd, nope],
Square[$CaseX1, nope, gnd, trans, nope],
Square[$CaseX0, trans, nope, nope, gnd],
Square[$CaseXX, nope, nope, nope, nope],
Square[$CaseTX, trans, nope, trans, nope],
Square[$CaseXT, nope, trans, nope, trans]
]]];
};
Connection with CoreCreate: making the array
The order of instances of the returned recordCell is the following:
each input driver (left to right) (in the given order)
each alps row (bottom to top) (in the given order)
AlpsCell: PUBLIC PROC [public: Wire, inputs: Inputs, outputs: Outputs, name: ROPENIL, props: Properties ← NIL] RETURNS [recordCell: CellType] = {
wireToRefInt: RefTab.Ref ← RefTab.Create[];
nbIn, nbOut: NAT ← 0;
instances: LIST OF CoreClasses.CellInstance ← NIL;
structuredInputs: Wire; -- each of the nbIn wires is a Plus-Minus
inputWires: Wires ← NIL; -- aux. var.
CheckAtomic[public, "Gnd"]; CheckAtomic[public, "Vdd"];
WHILE inputs#NIL DO
driver: CellType ← inputs.first.driver;
pas: LIST OF PA ← inputs.first.pas;
input: Wire ← CoreCreate.FindWire[public, inputs.first.input];
drivedInput: Wire ← CreatePlusMinus[CoreOps.GetFullWireName[public, input]];
IF input=NIL THEN ERROR;
[] ← RefTab.Store[wireToRefInt, input, NEW [INT ← nbIn]];
CheckAtomic[driver.public, "Input"]; CheckPlusMinus[driver.public, "Output"];
inputWires ← CONS [drivedInput, inputWires];
pas ← CONS [["Output", drivedInput], pas];
pas ← CONS [["Input", input], pas];
instances ← CONS [CoreCreate.InstanceList[driver, pas], instances];
inputs ← inputs.rest;
nbIn ← nbIn + 1;
ENDLOOP;
structuredInputs ← CoreOps.CreateWire[elements: CoreOps.Reverse[inputWires], name: "PlusMinusInputs"];
WHILE outputs#NIL DO
driver: CellType = outputs.first.driver;
row: CellType;
subPas: LIST OF PANIL;
rowPas: LIST OF PANIL;
output: Wire ← CoreCreate.FindWire[public, outputs.first.output];
outputName: ROPE ← CoreOps.GetFullWireName[public, output];
subInput: Wire = CoreOps.SetShortWireName[CoreOps.CopyWire[structuredInputs], "Input"];
subPublic: Wire ← CoreOps.CreateWire[LIST [
subInput,
CoreOps.CreateWire[name: "Output"],
CoreOps.CreateWire[name: "Gnd"], CoreOps.CreateWire[name: "Vdd"]
]];
IF output=NIL THEN ERROR;
-- let us add the top level wires of output.driver.public
FOR i: NAT IN [0 .. driver.public.size) DO
name: ROPE ← CoreOps.GetShortWireName[driver.public[i]];
new: Wire ← CoreOps.CopyWire[driver.public[i]];
IF CoreOps.GetWireIndex[subPublic, name]#-1 THEN LOOP; -- easy one!
subPublic ← CoreOps.UnionWire[subPublic, CoreOps.CreateWire[LIST [new]]];
FOR pas: LIST OF PA ← outputs.first.pas, pas.rest WHILE pas#NIL DO
pub: Wire ← CoreCreate.FindWire[driver.public, pas.first.public];
IF pub=NIL THEN ERROR;
IF pub=driver.public[i] THEN {
subPas ← CONS [[new, pas.first.actual], subPas];
rowPas ← CONS [[pub, new], rowPas];
EXIT;
};
REPEAT FINISHED => ERROR;
ENDLOOP;
ENDLOOP;
row ← CreateAlps[subPublic, TranslateVar[wireToRefInt, Boole.Not[outputs.first.expr]], driver, rowPas, outputName]; -- Not because of current output drivers
subPas ← CONS [["Input", structuredInputs], subPas];
subPas ← CONS [["Output", output], subPas];
instances ← CONS [CoreCreate.InstanceList[row, subPas], instances];
outputs ← outputs.rest;
nbOut ← nbOut + 1;
ENDLOOP;
TerminalIO.PutF["Core for AlpsCell done: %g inputs and %g outputs\n", IO.int[nbIn], IO.int[nbOut]];
recordCell ← CoreCreate.Cell[
public: public,
onlyInternal: CoreOps.CreateWire[LIST [structuredInputs]],
instances: CoreClasses.ReverseCellInstances[instances],
name: name, props: props
];
CoreProperties.PutCellTypeProp[recordCell, $NbIn, NEW [INT ← nbIn]];
PWCore.SetLayout[recordCell, $FullAlpsCell];
};
FullAlpsCellLayout: PWCore.LayoutProc = {
refNbIn: REF INTNARROW [CoreProperties.GetCellTypeProp[cellType, $NbIn]];
nbIn: INT ← refNbIn^;
l: INT = CMosB.lambda;
data: CoreClasses.RecordCellType ← NARROW [cellType.data];
refContactPolyMetal2: REF INTNARROW [CoreProperties.GetCellTypeProp[cellType, $ContactPolyMetal2]];
contactPolyMetal2: INTIF refContactPolyMetal2=NIL THEN LAST [INT] ELSE refContactPolyMetal2^;
distanceSinceLastContact: INT ← 0;
i: NAT ← 0;
lineObjects: LIST OF CD.Object; -- lines from top to bottom (during construction)
contactLine: CD.Object;
Make the contact line
contacts: LIST OF CD.Object ← LIST [CDCell[$ContactPolyMetal2Route], CDCell[$ContactPolyMetal2OutputFiller]];
THROUGH [0 .. nbIn) DO contacts ← CONS [CDCell[$ContactPolyMetal2], contacts] ENDLOOP;
contactLine ← PW.AbutListX[contacts];
Input Drivers
BEGIN
inputDriversObjects: LIST OF CD.Object ← NIL;
WHILE i<nbIn DO
inputDriversObjects ← CONS [PWCore.Layout[data[i].type], inputDriversObjects];
i ← i + 1;
ENDLOOP;
inputDriversObjects ← CONS [CDCell[$FillerCornerDriver], inputDriversObjects];
lineObjects ← LIST [PW.AbutListX[NARROW[GList.Reverse[inputDriversObjects]]]];
END;
Alps lines
WHILE i<data.size DO
row: CD.Object ← PWCore.Layout[data[i].type];
rowSize: CD.Position ← CD.InterestSize[row];
nbSubRows: INT ← rowSize.y / (24*l);
distanceSinceLastContact ← distanceSinceLastContact + nbSubRows;
lineObjects ← CONS [row, lineObjects];
IF distanceSinceLastContact>=contactPolyMetal2 THEN {
lineObjects ← CONS [contactLine, lineObjects];
distanceSinceLastContact ← 0;
};
i ← i + 1;
ENDLOOP;
obj ← PW.AbutListY[NARROW[GList.Reverse[lineObjects]]];
};
DecorateFullAlpsCell: PWCore.DecorateProc = {
Sort: PROC [pos1, pos2: CD.Position] RETURNS [BOOL] = {
RETURN [pos1.y<pos2.y OR (pos1.y=pos2.y AND pos1.x<pos2.x)];
};
PWCore.DecorateFlatten[cellType, obj, Sort];
};
Alps Class and related utilities
Plus: NAT = 0;
Minus: NAT = 1;
public is the public of the Alps Cell. The resulting public is Input (2 levels of structure), Output (1 level of structure), Gnd, Vdd, and all the others found in the output driver that are not "Gnd", "Vdd", "Input", "Output" or the ones found in the pas of the driver.
expr contains variables which are REF INT, public[INT] being the variable
CreateAlps: PROC [public: Wire, expr: Expression, driver: CellType, pas: LIST OF PA, name: ROPENIL, props: Properties ← NIL] RETURNS [alps: CellType] = {
Tile: PROC [i, j: NAT, case: ATOM, renaming: LIST OF TilingClass.PA] = {
alpsArray[i][j] ← NEW [TilingClass.TileRec ← [
type: CoreCell[case], flatten: case=$CaseXX OR case=$CaseNull, renaming: renaming
]];
};
Size: PROC [input: NAT, expr: Expression] RETURNS [size: INT ← 1] = {
whenTrue, whenFalse: Expression;
IF input=0 THEN {IF expr#true AND expr#false THEN ERROR; RETURN};
[whenTrue, whenFalse] ← Boole.Eval[NEW [INT ← input-1], expr];
SELECT Boole.Case[whenTrue, whenFalse] FROM
$Case11, $Case00, $Case10, $Case01 => RETURN;
$Case1X, $Case0X, $CaseXX   => RETURN [Size[input-1, whenFalse]]; 
$CaseX1, $CaseX0      => RETURN [Size[input-1, whenTrue]]; 
$CaseXY         => RETURN [Size[input-1, whenTrue] + Size[input-1, whenFalse]];
ENDCASE         => ERROR;
};
FillArray: PROC [expr: Expression, input: NAT, minLine, nbLines: NAT] = {
FillSubColumn: PROC [case: ATOM, min: NAT, nb: NAT] = {
FOR i: NAT IN [min .. min+nb) DO
Tile [i, input-1, case, LIST [
["Input", Input[input-1][Plus]],
["NotInput", Input[input-1][Minus]],
["Gnd", "Gnd"]
]];
ENDLOOP;
};
FillColumn: PROC [case: ATOM] = {FillSubColumn[case, minLine, nbLines]};
Empty: PROC = {
FOR i: NAT IN [minLine .. minLine+nbLines) DO
FOR j: NAT IN [0 .. input-1) DO
Tile[i, j, $CaseNull, LIST [
["Input", Input[j][Plus]],
["NotInput", Input[j][Minus]],
["Gnd", "Gnd"]
]];
ENDLOOP;
ENDLOOP;
};
var: Variable ← NEW [INT ← input-1];
whenTrue, whenFalse: Expression;
case: ATOM;
[whenTrue, whenFalse] ← Boole.Eval[var, expr];
case ← Boole.Case[whenTrue, whenFalse];
SELECT case FROM
$Case11, $Case00, $Case10, $Case01  => {FillColumn[case]; Empty[]};
$Case1X, $Case0X, $CaseXX    => {
FillColumn[case]; FillArray[whenFalse, input-1, minLine, nbLines];
};
$CaseX1, $CaseX0       => {
FillColumn[case]; FillArray[whenTrue, input-1, minLine, nbLines];
};
$CaseXY          => {
sizeTrue: NAT ← Size[input-1, whenTrue];
sizeFalse: NAT ← Size[input-1, whenFalse];
IF sizeTrue+sizeFalse#nbLines THEN Signal[];
FillSubColumn[$CaseTX, minLine, sizeTrue]; FillArray[whenTrue, input-1, minLine, sizeTrue];
FillSubColumn[$CaseXT, minLine+sizeTrue, sizeFalse]; FillArray[whenFalse, input-1, minLine+sizeTrue, sizeFalse];
};
ENDCASE          => ERROR;
};
inputIndex: INT ← CoreOps.GetWireIndex[public, "Input"];
Input: Wire = public[NAT[inputIndex]]; -- this avoid CoreOps.FindWire[public, "Input"] which cost much, much more (creates a name cache)
nbInput: NAT = Input.size;
size: NAT = Size[nbInput, expr];
alpsArray: TilingClass.TileArray = NEW [TilingClass.TileArrayRec[size]];
CheckPlusMinus[driver.public, "Input"]; CheckAtomic[driver.public, "Output"];
pas ← CONS [["Gnd", "Gnd"], pas];
pas ← CONS [["Vdd", "Vdd"], pas];
pas ← CONS [["Output", "Output"], pas];
FOR i: NAT IN [0 .. size) DO
alpsArray[i] ← NEW [TilingClass.TileRowRec[nbInput+2]]; -- last Tiles is for pseudo-routing and driver
Tile[
i, nbInput,
SELECT TRUE FROM
size=1  => $AlpsRouteNone,
i=size-1 => $AlpsRouteTop,
i=0 => $AlpsRouteBottom,
ENDCASE => $AlpsRoute,
LIST [["Gnd", "Gnd"], ["Vdd", "Vdd"]]
];
alpsArray[i][nbInput+1] ← IF i=0
THEN NEW [TilingClass.TileRec ← [type: driver, renaming: pas]]
ELSE NEW [TilingClass.TileRec ← [type: CoreCell[$FillerOutputDriver]]];
ENDLOOP;
FillArray[expr, nbInput, 0, size];
TerminalIO.PutF["%gTiling done for Expression '%g' : %g lines.\n", IO.rope[IF size=1 THEN NIL ELSE "*** "], IO.rope[Boole.ToRope[expr]], IO.int[size]];
alps ← TilingClass.CreateTiling[public: public, tileArray: alpsArray, neighborX: TilingClass.LayoutNeighborX, neighborY: TilingClass.LayoutNeighborY, name: name, props: props];
};
Initialization
[] ← PWCore.RegisterLayoutAtom[$FullAlpsCell, FullAlpsCellLayout, DecorateFullAlpsCell];
IF debug THEN PW.RegisterGenerator[AddCaseCellsInLibrary, "AddCaseCellsInLibrary"];
END.