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 September 1, 1987 11:40:30 pm 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, CoreCreate, CoreOps, CoreProperties,
RefTab, IO,
PW, PWCore,
Rope,
Sinix, Sisyph,
TilingClass,
TerminalIO;
BooleCoreImpl: CEDAR PROGRAM
IMPORTS Boole, CD, CDBasics, CDDirectory, CDInstances, CDProperties, CDRects, CMosB, CoreCreate, CoreOps, CoreProperties, RefTab, 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]]];
};
InputLength: PROC [inputs: Inputs] RETURNS [length: NAT ← 0] = {
WHILE inputs#NIL DO length ← length + 1; inputs ← inputs.rest ENDLOOP;
};
OutputLength: PROC [outputs: Outputs] RETURNS [length: NAT ← 0] = {
WHILE outputs#NIL DO length ← length + 1; outputs ← outputs.rest ENDLOOP;
};
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[];
};
};
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];
};
TILE: PROC [cell: ATOM] RETURNS [TilingClass.Tile] = {
RETURN [NEW [TilingClass.TileRec ← [CoreCell[cell]]]];
};
This function is not a very efficient primitive, but who cares??
AppendOneRow: PROC [old: TilingClass.TileArray, row: TilingClass.TileRow] RETURNS [new: TilingClass.TileArray] = {
new ← NEW [TilingClass.TileArrayRec[old.size+1]];
FOR i: NAT IN [0 .. old.size) DO new[i] ← old[i] ENDLOOP;
new[old.size] ← row;
};
AddCaseCellsInLibrary: PW.GeneratorProc = {
l: INT = design.technology.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 [alps: CellType] = {
nbIn: NAT = InputLength[inputs];
nbOut: NAT = OutputLength[outputs];
array: TilingClass.TileArray ← NEW [TilingClass.TileArrayRec[0]];
wireToRefInt: RefTab.Ref ← RefTab.Create[];
CheckAtomic[public, "Gnd"]; CheckAtomic[public, "Vdd"];
BEGIN
inputDrivers: TilingClass.TileRow ← NEW [TilingClass.TileRowRec[nbIn+2]];
subIndex: NAT ← 0;
WHILE inputs#NIL DO
driver: CellType ← inputs.first.driver;
input: Wire ← CoreCreate.FindWire[public, inputs.first.input];
IF input=NIL THEN ERROR;
[] ← RefTab.Store[wireToRefInt, input, NEW [INT ← subIndex]];
CheckAtomic[driver.public, "Input"]; CheckPlusMinus[driver.public, "Output"];
inputDrivers[subIndex] ← NEW [TilingClass.TileRec ← [driver, CONS [["Input", input], inputs.first.pas]]];
subIndex ← subIndex + 1;
inputs ← inputs.rest;
ENDLOOP;
inputDrivers[nbIn] ← TILE[$FillerInputRoute];
inputDrivers[nbIn+1] ← TILE[$FillerDriverCorner];
array ← AppendOneRow[array, inputDrivers];
END;
BEGIN
refContactPolyMetal2: REF INTNARROW [CoreProperties.GetProp[props, $ContactPolyMetal2]];
contactPolyMetal2: INTIF refContactPolyMetal2=NIL THEN LAST [INT] ELSE refContactPolyMetal2^;
distSinceLastContact: INT ← 0;
WHILE outputs#NIL DO
arr: TilingClass.TileArray;
driver: CellType = outputs.first.driver;
output: Wire ← CoreCreate.FindWire[public, outputs.first.output];
rowPas: LIST OF PA ← outputs.first.pas;
IF output=NIL THEN ERROR;
rowPas ← CONS [["Output", output], rowPas];
FOR i: NAT IN [0 .. driver.public.size) DO
name: ROPE ← CoreOps.GetShortWireName[driver.public[i]];
IF name=NIL THEN ERROR;
IF Rope.Equal[name, "Output"] OR Rope.Equal[name, "Input"] OR Rope.Equal[name, "Plus"] OR Rope.Equal[name, "Minus"] THEN LOOP;
FOR pas: LIST OF PA ← rowPas, 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 EXIT;
REPEAT FINISHED => rowPas ← CONS [[name, name], rowPas];
ENDLOOP;
ENDLOOP;
arr ← CreateOneOuputArray[nbIn, TranslateVar[wireToRefInt, Boole.Not[outputs.first.expr]], driver, rowPas];
FOR i: NAT IN [0 .. arr.size) DO array ← AppendOneRow[array, arr[i]] ENDLOOP;
distSinceLastContact ← distSinceLastContact + arr.size;
outputs ← outputs.rest;
IF distSinceLastContact>=contactPolyMetal2 THEN {
row: TilingClass.TileRow ← NEW [TilingClass.TileRowRec[nbIn+2]];
FOR j: NAT IN [0 .. nbIn) DO row[j] ← TILE[$ContactPolyMetal2] ENDLOOP;
row[nbIn] ← TILE[$ContactPolyMetal2Route];
row[nbIn+1] ← TILE[$ContactPolyMetal2OutputFiller];
array ← AppendOneRow[array, row];
distSinceLastContact ← 0;
};
ENDLOOP;
END;
TerminalIO.PutF["Tiling for AlpsCell: %g inputs and %g outputs\n", IO.int[nbIn], IO.int[nbOut]];
alps ← TilingClass.CreateTiling[public: public, tileArray: array, neighborX: TilingClass.LayoutNeighborX, neighborY: TilingClass.LayoutNeighborY, name: name, props: props];
};
Generating a single ouput
Assumed are "Output", "Gnd", "Vdd".
expr contains variables which are REF INT, public[INT] being the variable
CreateOneOuputArray: PROC [nbInput: NAT, expr: Expression, driver: CellType, pas: LIST OF PA] RETURNS [alpsArray: TilingClass.TileArray] = {
Tile: PROC [i, j: NAT, case: ATOM] = {alpsArray[i][j] ← TILE[case]};
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] 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] 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;
};
size: NAT = Size[nbInput, expr];
alpsArray ← NEW [TilingClass.TileArrayRec[size]];
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
];
alpsArray[i][nbInput+1] ← IF i=0
THEN NEW [TilingClass.TileRec ← [type: driver, renaming: pas]]
ELSE TILE[$FillerOutputDriver];
ENDLOOP;
FillArray[expr, nbInput, 0, size];
};
Initialization
IF debug THEN PW.RegisterGenerator[AddCaseCellsInLibrary, "AddCaseCellsInLibrary"];
END.