DIRECTORY CD, CDMenus, CDSequencer, Core, CoreClasses, CoreCreate, CoreDirectory, CoreFlat, CoreIO, CoreOps, CoreProperties, HashTable, IO, Logic, LogicUtils, Ports, PW, PWCore, RopeList, Rosemary, RosemaryUser, SinixOps, Sisyph, TerminalIO; LogicUtilsImpl: CEDAR PROGRAM IMPORTS CDMenus, CoreClasses, CoreDirectory, CoreFlat, CoreIO, CoreOps, CoreProperties, HashTable, IO, Logic, Ports, PW, PWCore, RopeList, Rosemary, RosemaryUser, SinixOps, Sisyph, TerminalIO EXPORTS LogicUtils = BEGIN OPEN Logic, LogicUtils, CoreCreate; 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]]; }; scCutSet: ATOM _ $SCPlacableElement; -- cell from the library or SCBlock[] defaultLibName: ROPE = "CMOSB"; -- the name of the collection of cellTypes schDesignName: ROPE = "Logic"; -- the name of the ChipNDale file schDesign: CD.Design _ PW.OpenDesign[schDesignName]; cx: PUBLIC Sisyph.Context _ Sisyph.Create[schDesign]; scTable: HashTable.Table _ HashTable.Create[equal: HashTable.RopeEqual, hash: HashTable.HashRope]; Error: PUBLIC PROC [msg: ROPE] ~ {TerminalIO.WriteRopes[msg, "\n"]; ERROR}; 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}; globalSwitchHackForSCBlockON: BOOL _ FALSE; Extract: PUBLIC PROC [schName: ROPE, makeBlock: BOOL _ FALSE] RETURNS [ct: CellType] ~ { ct _ Sisyph.ES[schName, cx]; IF makeBlock AND globalSwitchHackForSCBlockON THEN ct _ SCBlock[ct]; }; 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]; }; }; 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, parent, flatParent, NIL, bindings, FlattenCell] } ELSE { -- Handle leaf cells here. MakeActual: PROC [public: Wire] RETURNS [actual: Wire] ~ { 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; 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]; }; LogicTest: RosemaryUser.TestProc ~ { logicTime: NAT _ Ports.PortIndex[cellType.public, "RosemaryLogicTime"]; p[logicTime].b _ TRUE; p[logicTime].d _ drive; DO p[logicTime].b _ NOT p[logicTime].b; Eval[]; ENDLOOP; }; ExtractSelectedObjAndRunRosemary: PROC [comm: CDSequencer.Command] = { globalNames: Sisyph.ROPES _ Sisyph.GetGlobalNames[Sisyph.Create[comm.design]]; UnnamedOrGlobal: PROC [wire: Wire] RETURNS [BOOL] ~ { name: ROPE = CoreOps.GetShortWireName[wire]; RETURN [name=NIL OR RopeList.Memb[globalNames, name]]; }; NotBus: PROC [wire: Wire] RETURNS [BOOL] ~ { FOR i: NAT IN [0..wire.size) DO -- Skipped if wire is atomic IF wire.elements[i].size#0 THEN RETURN[TRUE]; ENDLOOP; RETURN [FALSE]; }; WorthGraphing: CoreOps.EachWireProc ~ { SELECT TRUE FROM UnnamedOrGlobal[wire] => RETURN [subWires: FALSE]; -- don't even consider sons NotBus[wire] => RETURN [subWires: TRUE]; -- will have interesting sons ENDCASE => graphWires _ CONS[NEW [CoreFlat.FlatWireRec _ [wire: wire]], graphWires]; }; AtomicsInGraph: PROC [wire: Wire] ~ { graphWires _ CONS[NEW[CoreFlat.FlatWireRec _ [flatCell: CoreFlat.rootCellType, wire: wire]], graphWires]; }; logicVdd, logicGnd: NAT; graphWires: CoreFlat.FlatWires _ NIL; root, cellType: CellType; internal: Core.WireSeq; [root: root, cell: cellType] _ SinixOps.SelectedCellType[comm.design, Sisyph.mode]; IF root=NIL THEN RETURN; -- Extraction ended in error, message already printed IF cellType.class#CoreClasses.recordCellClass THEN Error["I can't simulate this thing"]; internal _ NARROW[cellType.data, CoreClasses.RecordCellType].internal; [] _ CoreOps.VisitWireSeq[internal, WorthGraphing]; logicVdd _ Ports.PortIndex[cellType.public, "Vdd"]; logicGnd _ Ports.PortIndex[cellType.public, "Gnd"]; [] _ Rosemary.SetFixedWire[cellType.public[logicVdd], H]; [] _ Rosemary.SetFixedWire[cellType.public[logicGnd], L]; [] _ RosemaryUser.TestProcedureViewer[ cellType: cellType, testButtons: LIST["Logic Test"], name: CoreOps.GetCellTypeName[cellType], displayWires: graphWires, graphWires: graphWires, cutSet: CoreFlat.CreateCutSet[labels: IF CoreProperties.GetCellTypeProp[from: cellType, prop: $Simulation]=$Fast THEN LIST[macroCutSet, logicCutSet] ELSE LIST[logicCutSet]]]; }; 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 PW.WriteF["\nEstimating size of %g (excluding the routing).\n", IO.rope[CoreOps.GetCellTypeName[cellType]]]; [width, nbCells] _ Size[cellType, table]; PW.WriteF["\nThe cell has %g placable elements\n", IO.int[nbCells]]; size _ width*10*standardSCHeight; PW.WriteF["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] ~ { PW.WriteF["%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; }; 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]; RosemaryUser.RegisterTestProc["Logic Test", LogicTest]; END. ฺLogicUtilsImpl.mesa Copyright c 1986 by Xerox Corporation. All rights reserved. Last Edited by: Louis Monier January 12, 1987 2:25:41 pm PST Barth, October 22, 1986 11:53:33 am PDT Bertrand Serlet October 18, 1986 0:01:28 am PDT New Class Utilities -- This property identify a leaf for the placer during layout -- The default library name (in the sense of CoreDirectory) -- The icons resides in "Logic.dale" -- A table which guarantees that basic cells are created only once -- The generic error -- Detects an X in a level sequence -- Extracts by name from the Logic design -- Creates a standard cell using the new class -- 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 -- a wire is innocent until proven guilty -- Let's make sure we have something to simulate -- Find out which wires to display: top-level only -- Prepare the cell for simulation -- Entry goes in Sisyph Menu ส ฺ– "cedar" style˜codešœ™Kšœ ฯmœ1™žœ*˜lJšœ)˜)Jšžœ1žœ˜DJšœ!˜!Jšžœ/žœ žœžœ˜\šžœžœก&˜JšŸœ˜/Jšœžœ˜Jšœžœžœ˜Kšžœžœ,˜MK˜—šŸ œžœžœ˜/Jš žœ-žœžœ žœ žœ˜yK˜—Jšœžœ˜Jšœ žœ˜Jšœ>˜>Jšœ.˜.Jšœ žœ žœ ˜*Jšœ2˜2Kšžœ˜—J˜J˜—K™Kšœถ˜ถKšœ–˜–K˜Kšœ7˜7K˜K˜Kšžœ˜K˜—…—/TC