DIRECTORY CD, CDDesignCache, CDIO, CDOps, CDSequencer, CDSequencerExtras, Core, CoreClasses, CoreCreate, CoreCDUser, CoreDirectory, CoreFlat, CoreIO, CoreOps, CoreProperties, IO, Logic, LogicUtils, Ports, PWCore, RefTab, Rope, Rosemary, Sisyph, SymTab, TerminalIO; LogicUtilsImpl: CEDAR PROGRAM IMPORTS CDDesignCache, CDIO, CDOps, CDSequencerExtras, CoreClasses, CoreCDUser, CoreDirectory, CoreFlat, CoreIO, CoreOps, CoreProperties, IO, Logic, Ports, PWCore, RefTab, Rope, Rosemary, Sisyph, SymTab, TerminalIO EXPORTS LogicUtils = BEGIN OPEN Logic, LogicUtils, CoreCreate; defaultLibName: ROPE _ "CMOSB"; -- CoreLib for the basic cells (c.f. MakeSC) schDesignName: ROPE _ "Logic"; -- ChipNDale/CoreLib file names disableSCBlock: BOOL _ TRUE; -- Say FALSE to enable atomic placement of composite cells. This is not really guaranteed to work... raiseObsoleteSignal: BOOL _ FALSE; -- Say TRUE to guarantee that obsolete macros cannot be extracted cx: Sisyph.Context _ NIL; -- the context from which Extract/GetLogicContext work logicCache: CoreDirectory.Library _ NIL; -- logicCache starts disabled CacheFetch: PUBLIC PROC [name: ROPE] RETURNS [CellType] ~ { IF logicCache=NIL THEN RETURN[NIL]; -- cache has been disabled RETURN [NARROW [SymTab.Fetch[logicCache, name].val]]; }; CacheStore: PUBLIC PROC [name: ROPE, ct: CellType] ~ { IF CoreProperties.GetCellTypeProp[ct, $LogForStats]=NIL THEN CoreProperties.PutCellTypeProp[ct, $LogForStats, name]; IF logicCache=NIL THEN RETURN; IF ~SymTab.Insert[logicCache, name, ct] THEN ERROR; -- This should never happen!!! }; Reset: PUBLIC PROC [reloadDesign: BOOL _ FALSE, cache: cacheAction _ leave] ~ { IF reloadDesign THEN { RecreateContext[]; IF logicCache#NIL THEN logicCache _ CoreDirectory.CreateLibrary[]; -- erase the cache }; SELECT cache FROM reload => { -- get from the CoreLib file if it is recent enough, else clear it logicCache _ CoreIO.RestoreLibrary[schDesignName]; IF logicCache=NIL THEN Error["Unable to read Logic core file"]; }; erase => logicCache _ CoreDirectory.CreateLibrary[]; -- erase the cache disable => logicCache _ NIL; -- disable the cache ENDCASE => NULL; -- don't touch the cache }; LibraryGet: PUBLIC PROC [lib, cell: ROPE] RETURNS [CellType _ NIL] = { library: CoreDirectory.Library _ CoreDirectory.FetchLibrary[lib]; IF library=NIL THEN { library _ CoreIO.RestoreLibrary[lib]; IF library=NIL THEN { TerminalIO.PutF["*** Error while retrieving %g in library %g: library does not exist.\n", IO.rope[cell], IO.rope[lib]]; RETURN; }; [] _ CoreDirectory.RegisterLibrary[library, lib]; }; RETURN [NARROW [SymTab.Fetch[library, cell].val]]; }; MakeSC: PUBLIC PROC [nameInLib: ROPE] RETURNS [ct: CellType] ~ { ct _ LibraryGet[defaultLibName, nameInLib]; }; RecreateContext: PROC [fileName: ROPE _ NIL] ~ { design: CD.Design; design _ CDDesignCache.Search[remoteName: schDesignName, fileName: fileName]; IF design=NIL THEN { IF fileName=NIL THEN fileName _ CDDesignCache.MakeUpFile[NIL, schDesignName]; design _ CDIO.ReadDesign[fileName, NIL, CDIO.GetWorkingDirectory[]]; CDOps.SetMutability[design, readonly]; }; cx _ Sisyph.Create[design]; }; GetLogicContext: PUBLIC PROC RETURNS [Sisyph.Context] ~ { IF cx=NIL THEN RecreateContext[]; RETURN [Sisyph.Copy[cx]]; }; Extract: PUBLIC PROC [schName: ROPE, parms: LIST OF Value _ NIL] RETURNS [ct: CellType] ~ { tmpCx: Sisyph.Context; IF cx=NIL THEN RecreateContext[]; tmpCx _ IF parms=NIL THEN cx ELSE Sisyph.Copy[cx]; WHILE parms#NIL DO Sisyph.Store[tmpCx, parms.first.name, NEW[INT _ parms.first.val]]; parms _ parms.rest; ENDLOOP; ct _ Sisyph.ES[schName, tmpCx]; }; 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] ~ { canonizedPublic: CoreFlat.FlatWire _ NARROW[RefTab.Fetch[bindings, public].val]; actual _ NARROW[RefTab.Fetch[table, canonizedPublic].val]; 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; }; [] _ RefTab.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 ~ { [] _ RefTab.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; table: RefTab.Ref _ RefTab.Create[equal: CoreFlat.FlatWireEqual, hash: CoreFlat.FlatWireHash]; IF disableSCBlock 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]; }; RoseClass: PUBLIC PROC [name: ROPE, init: Rosemary.InitProc _ NIL, evalSimple: Rosemary.EvalProc _ NIL, scheduleIfClockEval: BOOL _ FALSE, copy: Rosemary.StateCopyProc _ NIL] RETURNS [roseClassName: ROPE] ~ { roseClassName _ Rope.Cat["Logic", name]; [] _ Rosemary.Register[roseClassName, init, evalSimple, copy, scheduleIfClockEval]; }; InitPower: PROC [ct: CellType, name: ROPE] ~ { index: INT _ CoreOps.GetWireIndex[ct.public, name]; IF index>=0 THEN [] _ Ports.InitPort[wire: ct.public[index], levelType: l, initDrive: none]; }; SimulateGate: PUBLIC PROC [ct: CellType, roseClassName: ROPE] ~ { [] _ CoreFlat.CellTypeCutLabels[Rosemary.BindCellType[ct, roseClassName], logicCutSet]; InitPower[ct, "Vdd"]; InitPower[ct, "Gnd"]; }; SimulateMacro: PUBLIC PROC [ct: CellType, roseClassName: ROPE] ~ { [] _ CoreFlat.CellTypeCutLabels[Rosemary.BindCellType[ct, roseClassName], macroCutSet]; InitPower[ct, "Vdd"]; InitPower[ct, "Gnd"]; }; Error: PUBLIC PROC [msg: ROPE] ~ { TerminalIO.PutF["%l*** %g ***%l\n", IO.rope["b"], IO.rope[msg], IO.rope["B"]]; ERROR; }; ObsoleteMacro: SIGNAL [msg: ROPE] ~ CODE; Obsolete: PUBLIC PROC [msg: ROPE] ~ { TerminalIO.PutF["%l*** %g ***%l\n", IO.rope["b"], IO.rope[msg], IO.rope["B"]]; IF raiseObsoleteSignal THEN SIGNAL ObsoleteMacro[msg]; }; SizeRef: TYPE = REF SizeRec; SizeRec: TYPE = RECORD[totalArea, nb: INT _ 0]; SumThisIntProp: PROC [cell: CellType, prop: ATOM] RETURNS [sum: INT] ~ { val: REF _ CoreProperties.GetCellTypeProp[cell, prop]; sum _ IF val=NIL THEN 0 ELSE NARROW[val, REF INT]^; IF sum=0 THEN SELECT TRUE FROM cell.class=CoreClasses.recordCellClass => { rct: CoreClasses.RecordCellType _ NARROW[cell.data]; FOR i: NAT IN [0..rct.size) DO sum _ sum+SumThisIntProp[rct[i].type, prop]; ENDLOOP; }; cell.class.recast=NIL => RETURN[0]; -- all other atomic classes are ignored ENDCASE => RETURN SumThisIntProp[CoreOps.Recast[cell], prop]; -- recast! }; SortAndPrint: PROC [table: SymTab.Ref, area: INT] ~ { WHILE SymTab.GetSize[table]>0 DO -- the laziest way to sort a few entries largest: ROPE; value: REF; maxSize: INT _ 0; SelectLargestItem: SymTab.EachPairAction ~ { item: SizeRef _ NARROW[val]; name: ROPE _ NARROW[key]; IF item.totalArea > maxSize THEN {largest _ key; maxSize _ item.totalArea}; }; 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.totalArea]/area]]; }; [] _ SymTab.Pairs[table, SelectLargestItem]; value _ SymTab.Fetch[table, largest].val; PrintItem[NARROW[largest], NARROW[value]]; [] _ SymTab.Delete[table, largest]; ENDLOOP; }; GetAreaProc: TYPE ~ PROC [cell: CellType] RETURNS [area: INT, key: ROPE]; Leaf: GetAreaProc ~ { val: REF _ CoreProperties.GetCellTypeProp[cell, $CellArea]; area _ IF val=NIL THEN 0 ELSE NARROW[val, REF INT]^; key _ CoreOps.GetCellTypeName[cell]; }; Macro: GetAreaProc ~ { val: REF _ CoreProperties.GetCellTypeProp[cell, $LogForStats]; area _ IF val=NIL THEN 0 ELSE SumThisIntProp[cell, $CellArea]; key _ IF val=NIL THEN NIL ELSE NARROW[val]; }; HistogramIntProp: PROC [cell: CellType, proc: GetAreaProc, table: SymTab.Ref] RETURNS [area, nbCells: INT _ 0] ~ { key: ROPE; [area, key] _ proc[cell]; -- total area IF area#0 THEN { ref: REF; item: SizeRef; found: BOOL; [found, ref] _ SymTab.Fetch[table, key]; IF found THEN { item _ NARROW[ref]; item.totalArea _ item.totalArea+area; item.nb _ item.nb+1} ELSE item _ NEW[SizeRec _ [totalArea: area, nb: 1]]; [] _ SymTab.Store[table, key, item]; RETURN[area, 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] _ HistogramIntProp[rct[i].type, proc, table]; area _ area+subSize; nbCells _ nbCells+subNb; ENDLOOP; }; cell.class.recast=NIL => RETURN[0, 0]; -- all other atomic classes are ignored ENDCASE => RETURN HistogramIntProp[CoreOps.Recast[cell], proc, table]; -- recast }; ExtractAndMeasure: PROC [comm: CDSequencer.Command] = { DoOne: CoreCDUser.EachRootCellTypeProc ~ { leafTable: SymTab.Ref _ SymTab.Create[]; -- "xnor2" -> [totalArea, nb] macroTable: SymTab.Ref _ SymTab.Create[]; -- "MuxDN n=3 b=8" -> [totalArea, nb] area, nbCells: INT _ 0; TerminalIO.PutF["\nEstimating size of %g (excluding the routing):\n", IO.rope[CoreOps.GetCellTypeName[root]]]; [area, nbCells] _ HistogramIntProp[root, Leaf, leafTable]; TerminalIO.PutF["\nThe cell has %g placable elements\n", IO.int[nbCells]]; TerminalIO.PutF["Size is %g sq microns = %g sq mm.\n", IO.int[area/64], IO.real[REAL[area]/64000000]]; SortAndPrint[leafTable, area]; TerminalIO.PutF["\nStatistics on %g:\n", IO.rope[CoreOps.GetCellTypeName[root]]]; [area, nbCells] _ HistogramIntProp[root, Macro, macroTable]; SortAndPrint[macroTable, area]; }; [] _ CoreCDUser.EnumerateSelectedCellTypes[comm.design, DoOne]; }; Reset[reloadDesign: FALSE, cache: erase]; CDSequencerExtras.RegisterCommand[key: $LayoutMeasure, proc: ExtractAndMeasure, queue: doQueue]; END. ’LogicUtilsImpl.mesa Copyright c 1986 by Xerox Corporation. All rights reserved. Last Edited by: Louis Monier September 30, 1987 7:02:25 pm PDT Jean-Marc Frailong December 8, 1987 11:42:33 pm PST Barth, May 4, 1987 2:59:41 pm PDT Bertrand Serlet June 10, 1987 4:44:26 pm PDT Global variables Cache Fetch an entry from the Logic cache Set logging information & store into cache if enabled Initialize internal state of LogicUtils for all the cached information Should enfore dates using Loader.BCDBuildTime[proc] Accessing basic cells (with associated layout) Fetch a cell type from a library, reload the library if not present Fetch the cell from the basic cell library Extraction utilities Reload the Logic design (from cache if possible) and rebuild the context. This is a bit clumsy because CDDesignCache has strange semantics. Extracts from the Logic library with the given (INT) parameters. 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. -- if root is a leaf, bindings=NIL -- maps old CoreFlat wires to new shell internal Core wires Rosemary sugar Init power supply to (l, none) if it is present: Ports.InitPorts would scream here... Error management Print a message and raise an error Print a message and optionally raise a signal Gathering Statistics Lists the celltypes recognized as macros from Logic, with their arguments. -- Statistics on leaf cells -- The area of a standard cell is stored under the property $CellArea on the cellType; -- The area is expressed in square CD units; currently, divide by 64 to be in square microns -- Celltypes recognized as macros from Logic, with their arguments. Initialization -- Entries goes in SPACE-F Menu, Layout submenu Κ – "cedar" style˜codešœ™Kšœ Οmœ1™K™3K™!K™,K™—KšΟk œžœžœŽžœW˜ˆK˜•StartOfExpansion[]šΠblœžœž˜KšžœžœožœJ˜ΦKšžœ ˜Kšœžœžœ˜+—head™Kšœžœ Οc,˜LKšœžœ  ˜>Kšœžœžœ d˜šœžœžœ A˜dK˜—šœžœ 6˜PK˜—Kšœ$žœ ˜F—™š Οn œžœžœžœžœ˜;K™#Kš žœ žœžœžœžœ ˜>Kšžœžœ'˜5K˜K˜—š‘ œžœžœžœ˜6K™5Kšžœ2žœžœ8˜tKšžœ žœžœžœ˜Kšžœ&žœžœ ˜RKšœ˜K˜—š ‘œžœžœžœžœ!˜OK™Fšžœžœ˜Kšœ˜Kšžœ žœžœ- ˜UKšœ˜—šžœž˜šœ  B˜NKšΟb3™3Kšœ2˜2Kšžœ žœžœ)˜?K˜—Kšœ5 ˜GKšœžœ ˜1Kšžœžœ ˜)—Kšœ˜——™.š ‘ œžœžœ žœžœ žœ˜FK™CKšœA˜Ašžœ žœžœ˜Kšœ%˜%šžœ žœžœ˜KšœZžœ žœ ˜wKšžœ˜K˜—Kšœ1˜1K˜—Kšžœžœ$˜2K˜K˜—š ‘œžœžœ žœžœ˜@K™*Kšœ+˜+K˜——™š‘œžœ žœžœ˜0KšœI™IKšœA™AKšœžœ˜KšœM˜Mšžœžœžœ˜Kšžœ žœžœ%žœ˜MKšœ žœžœžœ˜DKšœ&˜&K˜—Kšœ˜K˜K˜—š‘œžœžœžœ˜9Kšžœžœžœ˜!Kšžœ˜K˜K˜—š‘œžœžœ žœ žœžœ žœžœ˜[Kšœ0žœ ™@Kšœ˜Kšžœžœžœ˜!Kš œžœžœžœžœ˜2šžœžœž˜Kšœ&žœžœ˜BK˜Kšžœ˜—Kšœ žœ˜Kšœ˜K˜—š‘œžœžœžœ˜AKšœ’™’KšœŒ™Œš‘œžœžœžœ˜0Kšžœ:žœ˜DK˜—š‘œžœ˜#Kšœ<˜Kš œžœžœžœžœ!˜>Jš œžœžœžœžœžœžœ˜+K˜K˜—š‘œžœ8žœžœ ˜rKšœžœ˜ Kšœ ˜(šžœžœ˜Kšœžœ˜ Kšœ˜Kšœžœ˜ Kšœ(˜(šžœžœ˜Kšœžœ˜Kšœ%˜%Kšœ˜—Kšžœžœ%˜4Kšœ$˜$Kšžœ ˜Kšœ˜—šžœžœž˜šœ+˜+Kšœ"žœ ˜4šžœžœžœž˜Kšœžœ˜Kšœ>˜>Kšœ˜Kšœ˜Kšžœ˜—Kšœ˜—Kšœžœžœ '˜NKšžœžœ7  ˜Q—K˜K˜—š‘œžœ ˜7KšœJ™Jš‘œ%˜*Jšœ) ˜FJšœ* %˜OJšœžœ˜Jš ™Kš X™XKš \™\JšœFžœ&˜nJšœ:˜:Jšœ9žœ˜JJšœ7žœžœžœ˜fJšœ˜Kš C™CJšœ)žœ&˜QJšœ<˜