CoreLibraryImpl.mesa
Copyright c 1985 by Xerox Corporation. All rights reserved.
Curry October 18, 1986 5:36:16 pm PDT
Don Curry October 27, 1986 12:46:49 pm PST
DIRECTORY CD, CDBasics, CDCells, CDDirectory, CDInstances, CDOps, CDProperties, CDSymbolicObjects, CDViewer, Core, CoreBlock, CoreClasses, CoreGeometry, CoreLibrary, CoreName, CoreProperties, HashTable, IO, PW, PWC, Rope, RopeList, Rosemary, ViewerClasses, WriteCapa;
CoreLibraryImpl: CEDAR PROGRAM
IMPORTS CD, CDBasics, CDCells, CDDirectory, CDInstances, CDProperties, CDSymbolicObjects, CoreBlock, CoreClasses, CoreGeometry, CoreName, CoreProperties, HashTable, IO, PW, PWC, Rope, RopeList, Rosemary, WriteCapa
EXPORTS CoreLibrary =
BEGIN
Signal:   SIGNAL = CODE;
ROPE:    TYPE = Core.ROPE;
CellType:   TYPE = Core.CellType;
Library:   TYPE = CoreLibrary.Library;
LibraryRec:  TYPE = CoreLibrary.LibraryRec;
RenamePinsProc: TYPE = CoreLibrary.RenamePinsProc;
designArchive: LIST OF CD.Design ← NIL; -- prevent garbage collection
OpenLibrary: PUBLIC PROC[name: ROPE] RETURNS[lib: Library] = {
lib ← NEW[LibraryRec ← [
design: PW.OpenDesign[name],
table:  HashTable.Create[equal: HashTable.RopeEqual, hash: HashTable.HashRope] ] ];
IF lib.design=NIL THEN Signal[];
designArchive ← CONS[lib.design, designArchive]};
Get: PUBLIC PROC[
lib:    Library,
name:    ROPE,
removeNamed: BOOL    ← TRUE,
conds:    LIST OF ROPE ← NIL,
flatten:   INT    ← -1,
merge:   BOOL    ← FALSE]
RETURNS[cell: Core.CellType] = {
obj:   CD.Object;
refName:  ROPE ← name;
IF name.Length[]=0 THEN Signal[];
IF conds#NIL THEN {
conds ← RopeList.Sort[conds, RopeList.Compare];
refName ← refName.Cat[IF removeNamed THEN "-Remove" ELSE "-Keep"];
FOR list: LIST OF ROPE ← conds, list.rest WHILE list#NIL DO
refName ← refName.Cat["-", (IF list.first=NIL THEN "NONE" ELSE list.first)] ENDLOOP };
name  ← CoreName.RopeNm[name];
refName ← CoreName.RopeNm[refName];
cell ← NARROW[HashTable.Fetch[lib.table, refName].value];
IF cell#NIL THEN RETURN[cell];
obj ← CDDirectory.Fetch[lib.design, name].object;
IF obj=NIL THEN RETURN[NIL];
IF conds#NIL THEN obj ←PW.Inst[obj, conds, removeNamed];
cell ← ObjCell[obj, refName, NIL, flatten];
IF merge THEN CoreBlock.MergeCell[cell];
Set[lib, refName, cell]};
Set: PUBLIC PROC[
lib: Library,
name: ROPE,
cell: Core.CellType ] = {
old: Core.CellType;
name ← CoreName.CellNm[cell, name].n;
IF name.Length[]=0 THEN Signal[];
old ← NARROW[HashTable.Fetch[lib.table, name].value];
IF old#NIL AND old#cell THEN Signal[];
[ ] ← HashTable.Store[lib.table, name, cell]};
ObjCell: PUBLIC PROC[
obj:    CD.Object,
name:    ROPE,
rename:   RenamePinsProc ← NIL,
flatten:   INT    ← -1]
RETURNS[cell: Core.CellType] = {
PW.WriteF["Define Core Cell: %g\n", IO.rope[name]];
IF flatten=-1
THEN obj ← Flatten[obj, rename] -- New independent object
ELSETHROUGH [0..flatten) DO obj ← FlattenOneLevel[obj, rename].new ENDLOOP;
IF name.Length[]=0 THEN Signal[];
IF CDDirectory.Name[obj]=NIL THEN PWC.SetObjName[obj, name];
cell ← PWC.Extract[obj];
cell ← PWC.Extract[obj ! Sinix.FusionPropMismatch =>
{IF CheckMismatch[name, prop, value1, value2].ok THEN RESUME}];
IF CoreProperties.GetCellTypeProp[cell, $CoreIOGlobal]#NIL THEN RETURN[cell];
[] ← CoreProperties.PutCellTypeProp[cell, $CoreIOGlobal, $CoreIOGlobal];
[] ← CoreName.CellNm[cell, name];
CoreBlock.MarkSides[cell];
CoreBlock.DeletePseudoPublics[cell];
WriteCapa.WriteWireCapa[cell]; -- put capacitance on all leaf cells
MarkWeakTransistors[cell];
Sos.CheckDesignRules
[cell, NIL, NIL, TRUE, $PWCLayout, $SinixCMosBInstance, $SinixCMosBWireGeometry];
};
CheckMismatch: PROC[name: ROPE, prop: ATOM, value1, value2: REF]
RETURNS[ok: BOOL] = {
log: IO.STREAM ← CoreFrame.GetLog[];
nv, ng, rv, rg: BOOLFALSE;
r1, r2: ROPE;
cnt: INT ← 0;
IF prop#$CoreName THEN RETURN[FALSE];
r1 ← NARROW[value1];
r2 ← NARROW[value2];
IF Rope.Find[name, "VDD", 0, FALSE]>0 THEN nv ← TRUE;
IF Rope.Find[name, "GND", 0, FALSE]>0 THEN ng ← TRUE;
IF Rope.Equal[r1, "VDD",  FALSE] THEN {rv ← TRUE; cnt ← cnt+1};
IF Rope.Equal[r1, "GND",  FALSE] THEN {rg ← TRUE; cnt ← cnt+1};
IF Rope.Equal[r2, "VDD",  FALSE] THEN {rv ← TRUE; cnt ← cnt+1};
IF Rope.Equal[r2, "GND",  FALSE] THEN {rg ← TRUE; cnt ← cnt+1};
ok ← cnt=1 AND ((rv AND nv) OR (rg AND ng));
IF ok THEN log.PutF["%g and %g fused in %g\n", IO.rope[r1], IO.rope[r2], IO.rope[name] ]};
MergeUnnamedWellPublic: PROC [cell: Core.CellType] = {
publics: Core.Wires ← NIL;
vddPins: LIST OF CD.Instance ← NIL;
vdd:  Core.Wire ← CoreOps.FindWire[cell.public, "VDD"];
IF vdd=NIL THEN vdd ← CoreOps.FindWire[cell.public, "+"];
IF vdd#NIL THEN vddPins ← CoreGeometry.GetPins[PWC.extractMode.decoration, vdd];
FOR i: INT DECREASING IN [0..cell.public.size) DO
list: LIST OF CD.Instance;
IF CoreName.WireNm[cell.public[i]].n.Length[]#0
THEN {publics ← CONS[cell.public[i], publics]; LOOP};
list ← CoreGeometry.GetPins[PWC.extractMode.decoration, cell.public[i]];
FOR list ← list, list.rest WHILE list#NIL DO
IF list.first.ob.layer#CMosB.nwell THEN Signal[] ELSE vddPins←CONS[list.first, vddPins];
ENDLOOP;
IF vdd=NIL
THEN {
[] ← CoreName.WireNm[cell.public[i], "VDD"];
PW.WriteF["Unnamed NWell public renamed to VDD\n"];
vdd ← cell.public[i];
publics ← CONS[cell.public[i], publics]}
ELSE PW.WriteF["Removing Unnamed NWell public\n"];
ENDLOOP;
cell.public ← CoreOps.CreateWire[publics];
CoreGeometry.PutPins[PWC.extractMode.decoration, vdd, vddPins]};
Flatten: PUBLIC PROC [cell: CD.Object, rename: RenamePinsProc←NIL]
RETURNS [new: CD.Object] = {
flat:  BOOL   ← FALSE;
new  ← Crystallize[cell];
PW.WriteF["Flatten cell: %g ", IO.rope[NARROW[new.specificRef, CD.CellPtr].name]];
FOR pass: INT IN [0..10) WHILE NOT flat DO
PW.WriteF["."];
[new, flat] ← FlattenOneLevel[new, rename] ENDLOOP;
PW.WriteF[" done\n"]};
FlattenOneLevel: PUBLIC PROC [cell: CD.Object, rename: RenamePinsProc←NIL]
RETURNS [new: CD.Object, flat: BOOLTRUE] = {
IncludeInNew: PROC[child: CD.Instance] = {
baby: CD.Instance;
IF CDSymbolicObjects.IsPin[child.ob] AND rename#NIL THEN {
name: ROPE     ← CDSymbolicObjects.GetName[child];
sides: CoreGeometry.Sides ← CoreGeometry.GetSides[iRect, child];
SELECT TRUE FROM
sides[left] => name ← rename[name, left,  child.location.y-iBase.y];
sides[right] => name ← rename[name, right, child.location.y-iBase.y];
sides[top]  => name ← rename[name, top,  child.location.x-iBase.x];
sides[bottom] => name ← rename[name, bottom, child.location.x-iBase.x];
ENDCASE  => RETURN;
IF name=NIL THEN RETURN;
CDSymbolicObjects.SetName[child, name]};
baby ← CDCells.IncludeOb[
design:  NIL,
cell:   new,
ob:   child.ob,
position:  child.location, -- iBase,
orientation: child.orientation,
cellCSystem: cdCoords, -- interrestCoords,
obCSystem: cdCoords, -- interrestCoords,
mode:   dontPropagate ].newInst;
CDProperties.CopyProps[child.properties, baby] };
list0, list1: CD.InstanceList;
iRect: CD.Rect  ← CD.InterestRect[cell];
iBase: CD.Position ← CDBasics.BaseOfRect[iRect];
IF NOT CDCells.IsCell[cell] THEN ERROR;
new ← CDCells.CreateEmptyCell[];
CDCells.SetInterestRect[new, CD.InterestRect[cell]];
list0 ← NARROW [cell.specificRef, CD.CellPtr].contents;
FOR list0 ← list0, list0.rest WHILE list0 # NIL DO
inst: CD.Instance ← NEW[CD.InstanceRep ← list0.first^];
inst.ob ← Crystallize[inst.ob];
IF CDCells.IsCell[inst.ob]
THEN {
list1 ← NARROW [inst.ob.specificRef, CD.CellPtr].contents;
list1 ← CDInstances.ComposedList[list1, inst.location, inst.ob.size, inst.orientation];
FOR list1 ← list1, list1.rest WHILE list1 # NIL DO
flat ← flat AND NOT inst.ob.class.inDirectory;
IncludeInNew[list1.first]
ENDLOOP }
ELSE IncludeInNew[inst];
ENDLOOP;
[ ] ← CDCells.RepositionCell[new, NIL] };
Crystallize: PUBLIC PROC [cell: CD.Object] RETURNS [new: CD.Object] = {
new ← cell;
WHILE cell.class.inDirectory AND NOT CDCells.IsCell[new] DO
new ← CDDirectory.Expand[new, NIL, NIL].new;
IF new=NIL THEN Signal[]; ENDLOOP};
FlattenAll: PROC [cell: CD.Object] RETURNS [new: CD.Object] = {
cell ← Crystallize[cell];
PW.WriteF["Flatten cell: %g \n", IO.rope[NARROW[cell.specificRef, CD.CellPtr].name]];
new ← FlattenAllLevels[cell]};
FlattenAllLevels: PROC [cell: CD.Object]
RETURNS [new: CD.Object] = {
IncludeInNew: PROC[child: CD.Instance] = {
baby: CD.Instance;
baby ← CDCells.IncludeOb[
design:  NIL,
cell:   new,
ob:   child.ob,
position:  child.location, -- iBase,
orientation: child.orientation,
cellCSystem: cdCoords, -- interrestCoords,
obCSystem: cdCoords, -- interrestCoords,
mode:   dontPropagate ].newInst;
CDProperties.CopyProps[child.properties, baby] };
list0, list1: CD.InstanceList;
iBase: CD.Position ← CDBasics.BaseOfRect[CD.InterestRect[cell]];
IF NOT cell.class.inDirectory THEN RETURN[cell];
cell ← Crystallize[cell];
new ← CDCells.CreateEmptyCell[];
CDCells.SetInterestRect[new, CD.InterestRect[cell]];
list0 ← NARROW [cell.specificRef, CD.CellPtr].contents;
FOR list0 ← list0, list0.rest WHILE list0 # NIL DO
inst: CD.Instance ← NEW[CD.InstanceRep ← list0.first^];
inst.ob ← FlattenAllLevels[inst.ob];
IF NOT CDCells.IsCell[inst.ob]
THEN IncludeInNew[inst]
ELSE {
list1 ← NARROW [inst.ob.specificRef, CD.CellPtr].contents;
list1 ← CDInstances.ComposedList[list1, inst.location, inst.ob.size, inst.orientation];
FOR list1 ← list1, list1.rest WHILE list1 # NIL
DO IncludeInNew[list1.first] ENDLOOP };
ENDLOOP;
[ ] ← CDCells.RepositionCell[new, NIL] };
MarkWeakTransistors: PROC [cell: CellType] = {
SELECT cell.class FROM
CoreClasses.transistorCellClass => ERROR;
CoreClasses.recordCellClass  => {
data: CoreClasses.RecordCellType ← NARROW[cell.data];
FOR child: NAT IN [0..data.size) DO
IF data.instances[child].type.class # CoreClasses.transistorCellClass
THEN MarkWeakTransistors[ data.instances[child].type]
ELSE {
name: ROPENARROW
[CoreProperties.GetCellInstanceProp[data.instances[child], $CoreName]];
IF Rope.Equal[name, "driveWeak"] THEN
[] ← Rosemary.SetTransistorInstanceSize[data.instances[child], driveWeak]};
ENDLOOP };
ENDCASE => ERROR};
MarkWeakTransistors: PROC [cell: CellType, lengthToWidthMin: REAL ← .5] = {
SELECT cell.class FROM
CoreClasses.transistorCellClass => ERROR;
CoreClasses.recordCellClass  => {
data: CoreClasses.RecordCellType ← NARROW[cell.data];
FOR child: NAT IN [0..data.size) DO
IF data.instances[child].type.class # CoreClasses.transistorCellClass
THEN MarkWeakTransistors[ data.instances[child].type, lengthToWidthMin ]
ELSE {
trans: CoreClasses.Transistor ← NARROW[data.instances[child].type.data];
name: ROPENARROW
[CoreProperties.GetCellInstanceProp[data.instances[child], $CoreName]];
length: REAL ← trans.length;
width: REAL ← trans.width;
IF length/width > lengthToWidthMin OR Rope.Equal[name, "driveWeak"] THEN
[] ← Rosemary.SetTransistorInstanceSize[data.instances[child], driveWeak];
ENDLOOP };
ENDCASE => MarkWeakTransistors[ CoreOps.Recast[cell], lengthToWidthMin ]};
ENDCASE => ERROR};
Test: PROC[design, name: ROPE] = {
lib:  Library   ← OpenLibrary[design];
cell:  Core.CellType ← Get[lib, name];
ref:  CD.Object   ← PW.Get[lib.design, name];
obj:  CD.Object   ← PWC.Layout[cell];
iRect:  CD.Rect   ← CD.InterestRect[obj];
viewer: ViewerClasses.Viewer;
CoreOps.PrintCellType[cell];
IF ref=NIL OR obj=NIL THEN Signal[];
CDOps.IncludeObjectI[lib.design, obj, [0, 0]];
CDCleanUp.CleanUp[lib.design];
viewer ← CDViewer.CreateViewer[lib.design];
CDViewer.ShowAndScale[viewer, iRect];
Signal[]};
Test["IFUCore", "Junk"];
END.