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
ELSE THROUGH [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: BOOL ← FALSE;
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: BOOL ← TRUE] = {
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:
ROPE ←
NARROW
[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: ROPE ← NARROW
[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.