LogicUtilsImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Last Edited by: Louis Monier February 19, 1987 11:15:32 pm PST
Barth, February 18, 1987 8:40:34 pm PST
Bertrand Serlet January 27, 1987 2:00:15 pm PST
DIRECTORY CD, CDSequencer, Core, CoreClasses, CoreCreate, CoreDirectory, CoreFlat, CoreIO, CoreOps, CoreProperties, HashTable, IO, Logic, LogicUtils, Ports, PW, PWCore, Rosemary, SinixOps, Sisyph, TerminalIO;
Logic
UtilsImpl:
CEDAR
PROGRAM
IMPORTS CDSequencer, CoreClasses, CoreDirectory, CoreFlat, CoreIO, CoreOps, CoreProperties, HashTable, IO, Logic, PW, PWCore, Rosemary, SinixOps, Sisyph, TerminalIO
EXPORTS LogicUtils
= BEGIN OPEN Logic, LogicUtils, CoreCreate;
New Class
libCellClass:
PUBLIC Core.CellClass ← CoreIO.RegisterClass[
CoreOps.SetClassPrintProc[
NEW [Core.CellClassRec ← [
name: "LibCell",
recast: RecastLibCell,
layersProps: FALSE]], PrintLibCell], WriteLib, ReadLib];
WriteLib: CoreIO.ClassWriteProc = {
data: LibCellRef ← NARROW [cellType.data];
CoreIO.WriteRope[h, data.libName];
CoreIO.WriteRope[h, data.ctName];
};
ReadLib: CoreIO.ClassReadProc = {
data: LibCellRef ← NEW [LibCellRec];
data.libName ← CoreIO.ReadRope[h];
data.ctName ← CoreIO.ReadRope[h];
cellType.data ← data;
};
CreateLibCell:
PUBLIC
PROC [public: Wire, ctName, libName, name:
ROPE ←
NIL, props: Properties ←
NIL]
RETURNS [ct: CellType] = {
ct ← CoreOps.CreateCellType[
class: libCellClass,
public: public,
data: NEW[LibCellRec ← [libName, ctName]],
name: name,
props: props];
};
RecastLibCell: Core.RecastProc = {
-- check public!!!!
scRef: LibCellRef ← NARROW [me.data];
lib: CoreDirectory.Library ← CoreDirectory.FetchLibrary[scRef.libName];
schCell: CellType ← CoreDirectory.Fetch[library: lib, key: scRef.ctName];
IF schCell=NIL THEN Error[IO.PutFR["CellType %g not in library %g", IO.rope[scRef.ctName], IO.rope[scRef.libName]]];
new ← CoreClasses.CreatePermutedRecordCell[
iconPublic: me.public,
schCell: schCell,
table: CreateIdentityTable[me.public, schCell.public],
name: CoreOps.GetCellTypeName[me]];
PWCore.SetAbutX[new];
};
CreateIdentityTable:
PROC [iconPublic, schPublic: Wire]
RETURNS [table: HashTable.Table] ~ {
FindWire:
PROC [iconPublic: Wire, name:
ROPE]
RETURNS [iconWire: Wire ←
NIL] ~ {
n: INT ← CoreOps.GetWireIndex[iconPublic, name];
IF n>=0 THEN RETURN[iconPublic[n]];
};
AddInTable: CoreOps.EachWireProc ~ {
name: ROPE ← CoreOps.GetShortWireName[wire];
iconWire: Wire;
IF name=NIL THEN RETURN;
iconWire ← FindWire[iconPublic, name];
IF iconWire=NIL THEN RETURN;
[] ← HashTable.Store[table, wire, iconWire];
};
table ← HashTable.Create[];
[] ← CoreOps.VisitWire[schPublic, AddInTable];
};
PrintLibCell: CoreOps.PrintClassProc = {
scRef: LibCellRef ← NARROW [data];
CoreOps.PrintIndent[indent, out];
out.PutF["Cell '%g' from library '%g'\n", IO.rope[scRef.ctName], IO.rope[scRef.libName]];
};
Utilities
-- This property identify a leaf for the placer during layout
scCutSet: ATOM ← $SCPlacableElement; -- cell from the library or SCBlock[]
-- The default library name (in the sense of CoreDirectory)
defaultLibName: ROPE = "CMOSB"; -- the name of the collection of cellTypes
-- The icons resides in "Logic.dale"
schDesignName: ROPE = "Logic"; -- the name of the ChipNDale file
cx: Sisyph.Context ← NIL;
-- A table which guarantees that basic cells are created only once
scTable: HashTable.Table ← HashTable.Create[equal: HashTable.RopeEqual, hash: HashTable.HashRope];
GetLogicContext:
PUBLIC PROC
RETURNS [Sisyph.Context] ~ {
IF cx=NIL THEN cx ← Sisyph.Create[PW.OpenDesign[schDesignName]];
RETURN[cx];
};
-- The generic error
Error: PUBLIC PROC [msg: ROPE] ~ {TerminalIO.PutRopes[msg, "\n"]; ERROR};
-- Detects an X in a level sequence
HasX:
PUBLIC
PROC [ls: Ports.LevelSequence]
RETURNS [
BOOL ←
FALSE] ~ {
FOR i: NAT IN [0..ls.size) DO IF ls[i]=X THEN RETURN[TRUE] ENDLOOP};
-- Extracts by name from the Logic design
globalSwitchHackForSCBlockON: BOOL ← FALSE;
Extract:
PUBLIC
PROC [schName:
ROPE, makeBlock:
BOOL ←
FALSE]
RETURNS [ct: CellType] ~ {
IF cx=NIL THEN cx ← Sisyph.Create[PW.OpenDesign[schDesignName]];
ct ← Sisyph.ES[schName, cx];
IF makeBlock AND globalSwitchHackForSCBlockON THEN ct ← SCBlock[ct];
};
-- Creates a standard cell using the new class
MakeSC:
PUBLIC
PROC [nameInLib, name:
ROPE, public: Wire, width:
INT ← 0]
RETURNS [ct: CellType] ~ {
found: BOOL;
ref: REF;
[found, ref] ← HashTable.Fetch[scTable, nameInLib];
IF found THEN RETURN[NARROW[ref]] -- already in the table
ELSE {
ct ← CreateLibCell[name: name,
public: public,
ctName: nameInLib,
libName: defaultLibName]; -- a global
ct ← Rosemary.BindCellType[ct, name];
[] ← CoreFlat.CellTypeCutLabels[ct, logicCutSet];
CoreProperties.PutCellTypeProp[on: ct, prop: scCutSet, value: $T];
CoreProperties.PutCellTypeProp[on: ct, prop: cellWidthProp, value: NEW[INT ← width]];
[] ← HashTable.Store[scTable, nameInLib, ct];
};
};
-- Given a cellType ct, this procedure produces an equivalent cellType shell in the following way: ct is flattened until the leaves are standard cells (property $SCPlacableElement); the standard cells are then assembled in a single cellType called abut with no internal connection, with the exception of Vdd and Gnd; the abut cellType will be layed out as an abutX of standard cells and will be treated by the placer as a single element. The cellType shell has a single instance of abut and wires up all the cvonnections present in the original ct.
-- The idea is to reduce the number of placeable elements seen by the placer and thus reduce the placement time. This procedure should be used only on small-size cells (less than 10 standard cells) as the placer does not like to deal with objects of too different sizes.
scBlockHackOff: BOOL ← FALSE; -- a temporary hack
SCBlock:
PUBLIC PROC [ct: CellType]
RETURNS [shell: CellType] ~ {
IsLeaf:
PROC [cell: CellType]
RETURNS [
BOOL] ~ {
RETURN[CoreProperties.GetCellTypeProp[cell, $SCPlacableElement]#NIL]
};
MakeLeaf:
PROC [cell: CellType] ~ {
CoreProperties.PutCellTypeProp[cell, $SCPlacableElement, $T]
};
FlattenCell: CoreFlat.BoundFlatCellProc = {
IF ~IsLeaf[cell]
THEN {
-- Handle nonleaf cells here.
CoreFlat.NextBoundCellType[cell, target, flatCell, instance, index, parent, flatParent, NIL, bindings, FlattenCell]
}
ELSE {
-- Handle leaf cells here.
MakeActual:
PROC [public: Wire]
RETURNS [actual: Wire] ~ {
-- if root is a leaf, bindings=NIL
canonizedPublic: CoreFlat.FlatWire ← NARROW[HashTable.Fetch[bindings, public].value];
actual ← NARROW[HashTable.Fetch[table, canonizedPublic].value];
IF actual=
NIL
THEN {
IF public.size=0 THEN actual ← CoreOps.CreateWire[]
ELSE {
actual ← CoreOps.CreateWires[size: public.size];
FOR i:
NAT
IN [0..public.size)
DO
actual[i] ← MakeActual[public[i]];
ENDLOOP;
};
[] ← HashTable.Store[table, canonizedPublic, actual];
};
};
abutInstanceActual: Wire ← CoreOps.CopyWire[cell.public];
shellInstanceActual: Wire ← CoreOps.CreateWires[size: cell.public.size];
FOR i:
NAT
IN [0..cell.public.size)
DO
shellInstanceActual[i] ← MakeActual[cell.public[i]];
ENDLOOP;
abutInstances ← CONS[CoreClasses.CreateInstance[actual: abutInstanceActual, type: cell], abutInstances];
abutPublics ← CONS[abutInstanceActual, abutPublics];
shellInternals ← CONS[shellInstanceActual, shellInternals];
};
};
StorePublic: CoreOps.EachWirePairProc ~ {
[] ← HashTable.Store[table, NEW[CoreFlat.FlatWireRec ← [wire: publicWire]], actualWire];
};
abut: Core.CellType;
abutInstances: CoreClasses.CellInstances ← NIL;
abutPublics, shellInternals: Core.Wires ← NIL;
abutPublic, shellInternal, shellPublic: Core.Wire ← NIL;
-- maps old CoreFlat wires to new shell internal Core wires
table: HashTable.Table ← HashTable.Create[equal: CoreFlat.FlatWireEqual, hash: CoreFlat.FlatWireHash];
IF scBlockHackOff THEN RETURN[ct]; -- a temporary hack
shellPublic ← CoreOps.CopyWire[ct.public];
IF CoreOps.VisitBindingSeq[actual: shellPublic, public: ct.public, eachWirePair: StorePublic] THEN ERROR;
FlattenCell[ct];
abutPublic ← CoreOps.CreateWire[abutPublics];
shellInternal ← CoreOps.CreateWire[shellInternals];
abut ← CoreClasses.CreateRecordCell[
public: abutPublic,
internal: abutPublic,
instances: abutInstances];
shell ← CoreClasses.CreateRecordCell[
public: shellPublic,
internal: CoreOps.UnionWire[shellInternal, shellPublic],
instances: LIST[CoreClasses.CreateInstance[actual: shellInternal, type: abut]]];
PWCore.SetAbutX[abut];
MakeLeaf[abut];
};
cellWidthProp: PUBLIC ATOM ← $SCCellWidth;
standardSCHeight: INT = 104; -- hack for cmosb library only
SizeRef: TYPE = REF SizeRec;
SizeRec: TYPE = RECORD[totalWidth, nb: INT ← 0];
Size:
PROC [cell: CellType, table: HashTable.Table]
RETURNS [size, nbCells:
INT ← 0] ~ {
GetSize:
PROC [cell: CellType]
RETURNS [width:
INT ← 0] ~ {
val: REF ← CoreProperties.GetCellTypeProp[cell, cellWidthProp];
RETURN[IF val=NIL THEN 0 ELSE NARROW[val, REF INT]^];
};
width: INT ← GetSize[cell];
IF width#0
THEN {
ref: REF;
item: SizeRef;
found: BOOL;
name: ROPE ← CoreOps.GetCellTypeName[cell];
[found, ref] ← HashTable.Fetch[table, name];
IF found
THEN {
item ← NARROW[ref];
item.totalWidth ← item.totalWidth+width;
item.nb ← item.nb+1}
ELSE item ← NEW[SizeRec ← [totalWidth: width, nb: 1]];
[] ← HashTable.Store[table, name, item];
RETURN[width, 1];
};
SELECT
TRUE
FROM
cell.class=CoreClasses.recordCellClass => {
rct: CoreClasses.RecordCellType ← NARROW[cell.data];
FOR i:
NAT
IN [0..rct.size)
DO
subSize, subNb: INT ← 0;
[subSize, subNb] ← Size[rct[i].type, table];
size ← size+subSize;
nbCells ← nbCells+subNb;
ENDLOOP;
};
cell.class.recast=NIL => RETURN[0, 0]; -- all other atomic classes are ignored
ENDCASE => RETURN Size[CoreOps.Recast[cell], table]; -- if unknow and not atomic, recast!
};
ExtractAndMeasure:
PROC [comm: CDSequencer.Command] = {
width, size, nbCells: INT ← 0;
table: HashTable.Table ← HashTable.Create[equal: HashTable.RopeEqual, hash: HashTable.HashRope];
root, cellType: CellType;
[root: root, cell: cellType] ← SinixOps.SelectedCellType[comm.design, Sisyph.mode];
IF root=NIL THEN RETURN; -- Extraction ended in error, message already printed
TerminalIO.PutF["\nEstimating size of %g (excluding the routing).\n", IO.rope[CoreOps.GetCellTypeName[cellType]]];
[width, nbCells] ← Size[cellType, table];
TerminalIO.PutF["\nThe cell has %g placable elements\n", IO.int[nbCells]];
size ← width*10*standardSCHeight;
TerminalIO.PutF["Size is %g sq microns = %g sq mm.\n", IO.int[size], IO.real[REAL[size]/1000000]];
WHILE HashTable.GetSize[table]>0
DO
-- the lazziest way to sort 20 entries
SelectLargestItem: HashTable.EachPairAction ~ {
item: SizeRef ← NARROW[value];
name: ROPE ← NARROW[key];
IF item.totalWidth > maxSize THEN {largest ← key; maxSize ← item.totalWidth};
};
PrintItem:
PROC [name:
ROPE, item: SizeRef] ~ {
TerminalIO.PutF["%g %g => %5.1f%% of total area.\n", IO.int[item.nb], IO.rope[name], IO.real[100*REAL[item.totalWidth]/width]];
};
largest, value: REF;
maxSize: NAT ← 0;
[] ← HashTable.Pairs[table: table, action: SelectLargestItem];
value ← HashTable.Fetch[table, largest].value;
PrintItem[NARROW[largest], NARROW[value]];
[] ← HashTable.Delete[table: table, key: largest];
ENDLOOP;
};
-- Entry goes in Sisyph Menu
CDSequencer.ImplementCommand[key: $ExtractSelectedObjAndMeasure, proc: ExtractAndMeasure, queue: doQueue];
CDMenus.ImplementEntryCommand[menu: $OtherProgramMenu, entry: "Sisyph Extract and Rosemary", p: ExtractSelectedObjAndRunRosemary, key: $CoreRosemaryExtractSelectedObjAndRunRosemary];
CDMenus.ImplementEntryCommand[menu: $OtherProgramMenu, entry: "Sisyph Extract and Measure", p: ExtractAndMeasure, key: $ExtractSelectedObjAndMeasure];
END.