DIRECTORY CD, CDBasics, CDBasicsInline, CDCells, CDCommandOps, CDDirectory, CDImports, CDInstances, CDOps, CDProperties, CDSatellites, CDSequencer, CDViewer, Core, CoreCDUser, CoreClasses, CoreFlat, CoreGeometry, CoreOps, ExtractOps, InstanceTable, IO, PW, PWCore, RefTab, Rope, Sinix, Sisyph, TerminalIO, ViewerClasses, ViewerOps; DAUserHacks: CEDAR PROGRAM IMPORTS CD, CDBasics, CDCells, CDCommandOps, CDDirectory, CDImports, CDInstances, CDOps, CDProperties, CDSatellites, CDSequencer, CDViewer, CoreCDUser, CoreClasses, CoreFlat, CoreGeometry, CoreOps, ExtractOps, InstanceTable, IO, PW, PWCore, RefTab, Rope, Sinix, Sisyph, TerminalIO, ViewerOps ~ BEGIN hackMenu: ATOM _ $SpecialMenu; -- where DAUserHacks commands are forcefully registered CoreCDItem: TYPE ~ RECORD [core: REF ANY, inst: CD.Instance]; Context: TYPE ~ REF ContextRep; ContextRep: TYPE ~ RECORD [ design: CD.Design _ NIL, mode: Sinix.Mode _ NIL, ob: CD.Object, -- the top-level pushed-in object name: Rope.ROPE _ NIL, -- of current wire, there may be only one highlight: CD.InstanceList _ NIL, userData: REF ANY _ NIL, rects: SEQUENCE nbOfLayers: NAT OF InstanceTable.Table ]; NewContext: PROC [design: CD.Design] RETURNS [cx: Context] ~ { CheckInstance: CDCells.InstEnumerator ~ { subResult: REF; subProps: Core.Properties; badInst: BOOL _ FALSE; CDProperties.PutInstanceProp[inst, Sinix.satellitesProp, CDSatellites.GetSatelliteRopes[inst]]; [subResult, subProps] _ Sinix.Extract[inst.ob, cx.mode, inst.properties, cx.userData]; IF subResult#NIL THEN WITH subResult SELECT FROM subWire: Core.Wire => badInst _ badInst OR subWire.size#0; subWires: Core.Wires => UNTIL subWires=NIL DO badInst _ badInst OR subWires.first.size#0; subWires _ subWires.rest; ENDLOOP; subCellType: Core.CellType => FOR i: NAT IN [0..subCellType.public.size) DO badInst _ badInst OR subCellType.public[i].size#0; ENDLOOP; ENDCASE => ERROR; -- Extract returned incorrect value... IF badInst THEN cx.highlight _ CONS [ExtractOps.HighlightInstance[[inst.ob, inst.trans]], cx.highlight]; }; ob: CD.Object = CDOps.PushedTopCell[design]; mode: Sinix.Mode = ExtractOps.GetExtractMode[design, ob]; cx _ NEW [ContextRep[mode.nbOfLayers]]; cx.design _ design; cx.ob _ ob; IF CDOps.RealTopCell[design]=ob THEN ERROR; -- not pushed into a cell [] _ CDSatellites.GetSatellites[ob]; -- enforce satellites links !!! cx.mode _ mode; cx.userData _ IF mode.userData#NIL THEN mode.userData[design] ELSE NIL; [] _ CDCells.EnumerateInstances[ob, CheckInstance]; ExtractOps.HighlightDesignList[cx.design, cx.highlight]; -- in any case IF cx.highlight#NIL THEN { -- something went wrong TerminalIO.PutF["Highlighted instances have structured wires, not supported...\n"]; cx _ NIL; -- notifies of error return }; }; DestroyContext: PROC [cx: Context] ~ { FOR i: NAT IN [0..cx.mode.nbOfLayers) DO InstanceTable.DeleteOutside[cx.rects[i]]; ENDLOOP; }; Select: PROC [inst: CD.Instance, cx: Context] RETURNS [new: BOOL] ~ { IF inst.selected THEN RETURN [new: FALSE]; inst.selected _ TRUE; CDOps.RedrawInstance[cx.design, inst]; RETURN [new: TRUE]; }; CheckName: PROC [wire: Core.Wire, trans: CoreGeometry.Transformation, cx: Context] RETURNS [ok: BOOL] ~ { wireName: Rope.ROPE = CoreOps.GetShortWireName[wire]; IF cx.name=NIL THEN cx.name _ wireName; ok _ wireName=NIL OR Rope.Equal[cx.name, wireName]; IF NOT ok THEN { TerminalIO.PutF["Wire named %g connected to %g\n", IO.rope[CoreOps.GetShortWireName[wire]], IO.rope[cx.name]]; FOR pins: CoreGeometry.Instances _ CoreGeometry.GetPins[cx.mode.decoration, wire], pins.rest UNTIL pins=NIL DO pin: CoreGeometry.Instance = CoreGeometry.Transform[trans, pins.first]; cx.highlight _ CONS [ExtractOps.HighlightInstance[pin], cx.highlight]; ENDLOOP; }; }; AddGeometry: PROC [wire: Core.Wire, trans: CoreGeometry.Transformation, cx: Context] ~ { FOR pins: CoreGeometry.Instances _ CoreGeometry.GetPins[cx.mode.decoration, wire], pins.rest UNTIL pins=NIL DO pin: CoreGeometry.Instance = CoreGeometry.Transform[trans, pins.first]; layers: Sinix.LayerRange = cx.mode.instanceLayer[pin]; FOR i: NAT IN [layers.min .. layers.max] DO InstanceTable.Insert[cx.rects[i], pin, NIL]; ENDLOOP; ENDLOOP; }; Connects: PROC [wire: Core.Wire, trans: CoreGeometry.Transformation, cx: Context] RETURNS [connected: BOOL _ FALSE] ~ { FOR pins: CoreGeometry.Instances _ CoreGeometry.GetPins[cx.mode.decoration, wire], pins.rest UNTIL pins=NIL DO CheckOne: PROC [instance: CoreGeometry.Instance, value: InstanceTable.Value] ~ { IF cx.mode.touchProc[cx.mode.touchProc, instance, pin] THEN connected _ TRUE; }; pin: CoreGeometry.Instance = CoreGeometry.Transform[trans, pins.first]; layers: Sinix.LayerRange = cx.mode.instanceLayer[pin]; rect: CD.Rect = CoreGeometry.InlineBBox[pin]; FOR i: NAT IN [layers.min .. layers.max] DO InstanceTable.Enumerate[cx.rects[i], CheckOne, rect]; ENDLOOP; ENDLOOP; }; SelectionFromName: PROC [cx: Context] ~ { SelectIfNamed: CDCells.InstEnumerator ~ { newSel: BOOL _ FALSE; subResult: REF; subProps: Core.Properties; [subResult, subProps] _ Sinix.Extract[inst.ob, cx.mode, inst.properties, cx.userData]; IF subResult#NIL THEN WITH subResult SELECT FROM subWire: Core.Wire => IF Rope.Equal[CoreOps.GetShortWireName[subWire], cx.name] THEN newSel _ TRUE; subWires: Core.Wires => UNTIL subWires=NIL DO IF Rope.Equal[CoreOps.GetShortWireName[subWires.first], cx.name] THEN newSel _ TRUE; subWires _ subWires.rest; ENDLOOP; subCellType: Core.CellType => NULL; -- never forces a wire name ENDCASE => ERROR; -- Extract returned incorrect value... IF inst.selected#newSel THEN { inst.selected _ newSel; CDOps.RedrawInstance[cx.design, inst]; }; IF inst.selected THEN newSels _ newSels+1; }; newSels: INT _ 0; cx.name _ NIL; WHILE Rope.IsEmpty[cx.name] DO cx.name _ TerminalIO.RequestRope["Wire name:"]; ENDLOOP; [] _ CDCells.EnumerateInstances[cx.ob, SelectIfNamed]; CDOps.DoTheDelayedRedraws[cx.design]; -- to show progressive selection TerminalIO.PutF["Selected %g instance(s) specifying wire name '%g'\n", IO.int[newSels], IO.rope[cx.name]]; }; InitializeContext: PROC [cx: Context] RETURNS [failed: BOOL] ~ { EachInstance: CDCells.InstEnumerator ~ { subResult: REF; subProps: Core.Properties; IF NOT inst.selected THEN RETURN; -- not interesting [subResult, subProps] _ Sinix.Extract[inst.ob, cx.mode, inst.properties, cx.userData]; IF subResult#NIL THEN WITH subResult SELECT FROM subWire: Core.Wire => IF CheckName[subWire, inst.trans, cx] THEN AddGeometry[subWire, inst.trans, cx]; subWires: Core.Wires => UNTIL subWires=NIL DO IF CheckName[subWires.first, inst.trans, cx] THEN AddGeometry[subWires.first, inst.trans, cx]; subWires _ subWires.rest; ENDLOOP; subCellType: Core.CellType => pending _ CONS [[subCellType, inst], pending]; ENDCASE => ERROR; -- Extract returned incorrect value... }; pending: LIST OF CoreCDItem _ NIL; FOR i: NAT IN [0..cx.mode.nbOfLayers) DO cx.rects[i] _ InstanceTable.Create[range: cx.ob.bbox, logSize: 8]; ENDLOOP; [] _ CDCells.EnumerateInstances[cx.ob, EachInstance]; UNTIL pending=NIL DO -- cells are handled in a delayed fashion... cell: Core.CellType = NARROW [pending.first.core]; inst: CD.Instance = pending.first.inst; pending _ pending.rest; FOR i: NAT IN [0..cell.public.size) DO IF Connects[cell.public[i], inst.trans, cx] THEN AddGeometry[cell.public[i], inst.trans, cx]; ENDLOOP; ENDLOOP; ExtractOps.HighlightDesignList[cx.design, cx.highlight]; -- in any case failed _ cx.highlight#NIL; IF failed THEN TerminalIO.PutF["Wire specification has conflicting names\n"]; }; GrowContext: PROC [cx: Context] RETURNS [finished: BOOL] ~ { EachInstance: CDCells.InstEnumerator ~ { AddIfOK: PROC [wire: Core.Wire, named: BOOL] ~ { IF wire.size#0 THEN ERROR; -- should have been checked earlier ... IF inst.selected OR NOT Connects[wire, inst.trans, cx] THEN RETURN; IF named AND NOT CheckName[wire, inst.trans, cx] THEN RETURN; addToSet _ CONS [[wire, inst], addToSet]; }; subResult: REF; subProps: Core.Properties; IF inst.selected THEN RETURN; [subResult, subProps] _ Sinix.Extract[inst.ob, cx.mode, inst.properties, cx.userData]; IF subResult#NIL THEN WITH subResult SELECT FROM subWire: Core.Wire => AddIfOK[subWire, TRUE]; subWires: Core.Wires => UNTIL subWires=NIL DO AddIfOK[subWires.first, TRUE]; subWires _ subWires.rest; ENDLOOP; subCellType: Core.CellType => FOR i: NAT IN [0..subCellType.public.size) DO AddIfOK[subCellType.public[i], FALSE]; ENDLOOP; ENDCASE => ERROR; -- Extract returned incorrect value... }; addToSet: LIST OF CoreCDItem _ NIL; newSels: INT _ 0; [] _ CDCells.EnumerateInstances[cx.ob, EachInstance]; UNTIL addToSet=NIL DO wire: Core.Wire = NARROW [addToSet.first.core]; inst: CD.Instance = addToSet.first.inst; addToSet _ addToSet.rest; IF Select[inst, cx] THEN newSels _ newSels+1; AddGeometry[wire, inst.trans, cx]; ENDLOOP; ExtractOps.HighlightDesignList[cx.design, cx.highlight]; -- in any case CDOps.DoTheDelayedRedraws[cx.design]; -- to show progressive selection SELECT TRUE FROM newSels#0 => TerminalIO.PutF["Added %g instance(s) to wire '%g'\n", IO.int[newSels], IO.rope[IF Rope.IsEmpty[cx.name] THEN "" ELSE cx.name]]; cx.highlight=NIL => TerminalIO.PutF["No more instances to add to wire '%g'\n", IO.rope[IF Rope.IsEmpty[cx.name] THEN "" ELSE cx.name]]; ENDCASE => NULL; IF cx.highlight#NIL THEN TerminalIO.PutF["Incorrect connections highlighted\n"]; finished _ cx.highlight#NIL OR newSels=0; }; DoSelectWireRoots: PROC [comm: CDSequencer.Command] ~ { cx: Context; newSels: INT _ 0; cx _ NewContext[comm.design]; IF cx=NIL THEN RETURN; SelectionFromName[cx]; }; DoGrowWireOneStep: PROC [comm: CDSequencer.Command] ~ { cx: Context; cx _ NewContext[comm.design]; IF cx=NIL OR InitializeContext[cx] THEN RETURN; [] _ GrowContext[cx]; }; DoGrowWireToMax: PROC [comm: CDSequencer.Command] ~ { cx: Context; cx _ NewContext[comm.design]; IF cx=NIL THEN RETURN; IF CDInstances.OnlySelected[CDOps.InstList[cx.design]]=NIL THEN SelectionFromName[cx]; IF InitializeContext[cx] THEN RETURN; UNTIL GrowContext[cx] DO NULL ENDLOOP; }; SanityCheck: PROC [ct: Core.CellType] ~ { Explore: CoreFlat.BoundFlatCellProc ~ { IF cell.class=CoreClasses.transistorCellClass THEN { -- note transistor and its connections Check: PROC [p1, p2: CoreClasses.TransistorPort] ~ { fw1: CoreFlat.FlatWire = NARROW [RefTab.Fetch[bindings, public[p1.ORD]].val]; fw2: CoreFlat.FlatWire = NARROW [RefTab.Fetch[bindings, public[p2.ORD]].val]; IF fw1.wire=fw2.wire THEN TerminalIO.PutF["Transistor %g: %g and %g connected together\n", IO.rope[CoreFlat.CellTypePathRope[ct, flatCell]], IO.rope[transistorNames[p1]], IO.rope[transistorNames[p2]]]; }; CheckPower: PROC [p: CoreClasses.TransistorPort, to: Core.Wire, msg: Rope.ROPE] ~ { fw: CoreFlat.FlatWire = NARROW [RefTab.Fetch[bindings, public[p.ORD]].val]; IF fw#NIL AND fw.wire=to THEN TerminalIO.PutF["Transistor %g: %g connected to %g\n", IO.rope[CoreFlat.CellTypePathRope[ct, flatCell]], IO.rope[transistorNames[p]], IO.rope[msg]]; }; transistor: CoreClasses.Transistor = NARROW [cell.data]; public: Core.Wire = cell.public; Check[gate, ch1]; -- check source, drain & gate all different Check[gate, ch2]; Check[ch1, ch2]; IF vdd#NIL THEN CheckPower[gate, vdd, "Vdd"]; IF gnd#NIL THEN CheckPower[gate, gnd, "Gnd"]; IF vdd#NIL AND transistor.type=pE THEN { well: CoreFlat.FlatWire = NARROW [RefTab.Fetch[bindings, public[vddPos]].val]; IF well.wire#vdd THEN TerminalIO.PutF["Transistor %g: Well is not connected to Vdd\n", IO.rope[CoreFlat.CellTypePathRope[ct, flatCell]]]; }; } ELSE CoreFlat.NextBoundCellType[cell, target, flatCell, instance, index, parent, flatParent, data, bindings, Explore]; }; transistorNames: ARRAY CoreClasses.TransistorPort OF Rope.ROPE _ [ch1: "ch1", ch2: "ch2", gate: "gate", Vdd: "Vdd"]; -- for printing vdd: Core.Wire = CoreOps.FindWire[ct.public, "Vdd"]; gnd: Core.Wire = CoreOps.FindWire[ct.public, "Gnd"]; vddPos: NAT = CoreClasses.TransistorPort.Vdd.ORD; IF vdd=NIL THEN TerminalIO.PutF["Vdd is not a public of the cell...\n"]; IF gnd=NIL THEN TerminalIO.PutF["Gnd is not a public of the cell...\n"]; Explore[cell: ct]; }; DoSanityCheck: PROC [comm: CDSequencer.Command] ~ { EachCell: CoreCDUser.EachRootCellTypeProc ~ { TerminalIO.PutF["DAUserHacks: Sanity check on %g\n", IO.rope[CoreOps.GetCellTypeName[root]]]; SanityCheck[root]; TerminalIO.PutF["DAUserHacks: Done\n"]; }; [] _ CoreCDUser.EnumerateSelectedCellTypes[comm.design, EachCell]; }; WhoUses: PROC [obj: CD.Object, design: CD.Design] ~ { Describe: PROC [me: CD.Object] RETURNS [id: Rope.ROPE] ~ { id _ CDDirectory.Name[me, design]; IF Rope.Length[id]=0 THEN id _ CD.Describe[ob: me, design: design]; }; EachObject: CDDirectory.EachObjectProc ~ { EachInstance: CDCells.InstEnumerator ~ { IF inst.ob=obj THEN { TerminalIO.PutF[" %g", IO.rope[Describe[me]]]; nOccurrences _ nOccurrences+1; quit _ TRUE; -- stop enumerating children of me }; }; IF CDCells.IsCell[me] THEN { -- only interesting case... [] _ CDCells.EnumerateInstances[me, EachInstance]; }; }; nOccurrences: NAT _ 0; TerminalIO.PutF["%g is used in cells", IO.rope[Describe[obj]]]; [] _ CDDirectory.EnumerateDesign[design: design, proc: EachObject]; TerminalIO.PutF[" (%g occurences)\n", IO.int[nOccurrences]]; }; DoWhoUses: PROC [comm: CDSequencer.Command] ~ { selected: CD.InstanceList _ CDInstances.OnlySelected[CDOps.InstList[comm. design]]; IF selected#NIL THEN { FOR il: CD.InstanceList _ selected, il.rest UNTIL il=NIL DO WhoUses[il.first.ob, comm.design]; ENDLOOP; } ELSE { name: Rope.ROPE _ NIL; obj: CD.Object _ NIL; name _ TerminalIO.RequestRope[prompt: "Search who uses cell "]; obj _ CDDirectory.Fetch[comm.design, name]; IF obj=NIL THEN TerminalIO.PutF["Not found\n"] ELSE WhoUses[obj, comm.design]; }; }; cellVisibility: REAL _ 100.0; FlatObject: TYPE ~ REF FlatObjectRep; FlatObjectRep: TYPE ~ RECORD [obj: CD.Object, orientation: CD.Orientation]; FlattenLayout: PROC [initial: CD.Object, cache: RefTab.Ref, into: CD.Design] RETURNS [newObj: CD.Object, newOrient: CD.Orientation] ~ { newObj _ initial; newOrient _ original; IF newObj.class.composed THEN { EachInstance: CDCells.InstEnumerator ~ { subOrient: CD.Orientation; [inst.ob, subOrient] _ FlattenLayout[inst.ob, cache, into]; inst.trans.orient _ CDBasics.ComposeOrient[subOrient, inst.trans.orient]; }; entry: FlatObject _ NARROW [RefTab.Fetch[cache, newObj].val]; SELECT TRUE FROM entry#NIL => RETURN [newObj: entry.obj, newOrient: entry.orientation]; newObj.class=PW.rotationClass => { -- name inherited from underlying rotSpec: PW.RotationSpecific _ NARROW [newObj.specific]; subOrient: CD.Orientation; [newObj, subOrient] _ FlattenLayout[rotSpec.obj, cache, into]; newOrient _ CDBasics.ComposeOrient[CDBasics.ComposeOrient[subOrient, rotSpec.orientation], newOrient]; }; newObj.class=PW.indirectClass => { -- name inherited from underlying indSpec: CD.Object _ NARROW [newObj.specific]; subOrient: CD.Orientation; [newObj, subOrient] _ FlattenLayout[indSpec, cache, into]; newOrient _ CDBasics.ComposeOrient[subOrient, newOrient]; }; CDImports.IsImport[newObj] => { -- no need for naming import: CDImports.ImportSpecific _ NARROW [newObj.specific]; newObj _ CDImports.CreateImportFromCache[into: into, objectName: import.objectName, importeeName: import.designName]; }; CDCells.IsCell[newObj] => { -- enforce parent name newObj _ CDDirectory.Another1[newObj, NIL, NIL, FALSE].new; newObj.immutable _ FALSE; -- Horrible hack, but CDCells.Another does not do it... PW.SetName[newObj, PW.Name[initial]]; }; ENDCASE => { -- enforce parent name newObj _ CDDirectory.Expand1[newObj, NIL, NIL, FALSE].new; PW.SetName[newObj, PW.Name[initial]]; }; IF CDCells.IsCell[newObj] THEN { [] _ CDCells.EnumerateInstances[newObj, EachInstance]; CDCells.SetBorderMode[newObj, TRUE]; CDCells.SetSimplificationTreshhold[newObj, cellVisibility, TRUE]; }; [] _ RefTab.Store[cache, initial, NEW [FlatObjectRep _ [newObj, newOrient]]]; }; }; GetWorkingDesign: PROC [] RETURNS [work: CD.Design, viewer: ViewerClasses.Viewer] ~ { vl: CDViewer.ViewerList; work _ CDViewer.FindDesign["LayoutWorkArea"]; viewer _ NIL; IF work=NIL THEN { -- create it if not found work _ CDOps.CreateDesign[CD.FetchTechnology[$cmosB]]; CDOps.SetMutability[work, editable]; CDProperties.PutDesignProp[work, $CDxDontBackgroundSave, $TRUE]; -- prevent background saving [] _ CDOps.RenameDesign[work, "LayoutWorkArea"]; }; vl _ CDViewer.ViewersOf[work]; IF vl=NIL THEN { viewer _ CDViewer.CreateViewer[work, FALSE]; CDSequencer.ExecuteCommand[queue: doQueue, comm: NEW [CDSequencer.CommandRec _ [key: $ViewBord, design: work, ref: viewer]]]; ViewerOps.SetViewer[viewer: viewer, data: NEW [INT_work.technology.lambda/2], op: $Grid]; -- force grid to l/2; works because previous resyncs design... } ELSE viewer _ vl.first; }; DoFlattenLayout: PROC [comm: CDSequencer.Command] ~ { EachRoot: CoreCDUser.EachRootCellTypeProc ~ { layout: CD.Object; orient: CD.Orientation; inst: CD.Instance; name: Rope.ROPE = CoreOps.GetCellTypeName[root]; into: CD.Design; viewer: ViewerClasses.Viewer; TerminalIO.PutF["Generating layout for %g.\n", IO.rope[name]]; layout _ PWCore.Layout[root]; TerminalIO.PutF["Flattening layout for %g.\n", IO.rope[name]]; [into, viewer] _ GetWorkingDesign[]; [layout, orient] _ FlattenLayout[layout, RefTab.Create[], into]; inst _ CDOps.PlaceInst[into, layout, NIL]; inst.trans.orient _ orient; inst.selected _ TRUE; CDViewer.ShowAndScale[viewer, CDInstances.InstRectO[inst]]; }; [] _ CoreCDUser.EnumerateSelectedCellTypes[comm.design, EachRoot]; }; DoShellIntoWork: PROC [comm: CDSequencer.Command] ~ { EachRoot: CoreCDUser.EachRootCellTypeProc ~ { shell: CD.Object; mode: Rope.ROPE _ "Layout"; inst: CD.Instance; name: Rope.ROPE = CoreOps.GetCellTypeName[root]; into: CD.Design; viewer: ViewerClasses.Viewer; TerminalIO.PutF["Generating shell for %g.\n", IO.rope[name]]; IF CoreCDUser.GetRootCellTypeDecoration[root]=Sisyph.mode.decoration THEN { [] _ PWCore.Layout[root]; mode _ "Schematic"; }; [into, viewer] _ GetWorkingDesign[]; shell _ CoreGeometry.CreateShell[PWCore.extractMode.decoration, root, FALSE]; PW.SetName[shell, IO.PutFR["%g-Shell-%g", IO.rope[mode], IO.rope[name]]]; inst _ CDOps.PlaceInst[into, shell, NIL]; inst.selected _ TRUE; CDViewer.ShowAndScale[viewer, CDInstances.InstRectO[inst]]; }; [] _ CoreCDUser.EnumerateSelectedCellTypes[comm.design, EachRoot]; }; DoRemoveDescribe: PROC [comm: CDSequencer.Command] ~ { RemoveDescribe: CDDirectory.EachEntryAction ~ { IF CDProperties.GetObjectProp[ob, $Describe]#NIL THEN CDProperties.PutObjectProp[ob, $Describe, NIL]; }; iList: CD.InstanceList _ CDInstances.OnlySelected[CDOps.InstList[comm.design]]; IF iList#NIL THEN { UNTIL iList=NIL DO [] _ RemoveDescribe[NIL, iList.first.ob]; iList _ iList.rest; ENDLOOP; TerminalIO.PutF["Removed $Describe from selected object(s)\n"]; } ELSE { [] _ CDDirectory.Enumerate[comm.design, RemoveDescribe]; TerminalIO.PutF["Removed $Describe from all object(s) in directory\n"]; }; }; CDCommandOps.RegisterWithMenu[hackMenu, "Select wire roots", "Select all instances that extract as a wire with a given name", $DAUserHacksSelectWireRoots, DoSelectWireRoots]; CDCommandOps.RegisterWithMenu[hackMenu, "Grow wire one step", "Extend the currently selected piece of wire by one connection step", $DAUserHacksGrowWireOneStep, DoGrowWireOneStep]; CDCommandOps.RegisterWithMenu[hackMenu, "Grow wire to max", "Select all geometry for the wire until done or error", $DAUserHacksGrowWireToMax, DoGrowWireToMax]; CDCommandOps.RegisterWithMenu[hackMenu, "Layout sanity check", "Make some simple consistency checks for handcrafted layout", $DAUserHackSanityCheck, DoSanityCheck]; CDCommandOps.RegisterWithMenu[hackMenu, "Who uses", "Locate all cells using selected/named object", $DAUserHackWhoUses, DoWhoUses]; CDCommandOps.RegisterWithMenu[hackMenu, "Flattened Layout", "Generate flattened layout for selected CTs", $DAUserHackFlattenLayout, DoFlattenLayout]; CDCommandOps.RegisterWithMenu[hackMenu, "Usable shell", "Generate shell into work area", $DAUserHacksShell, DoShellIntoWork]; CDCommandOps.RegisterWithMenu[hackMenu, "Remove $Describe", "Remove name hint property from selected objects or directory", $DAUserHackRemoveDescribe, DoRemoveDescribe]; END. ๖DAUserHacks.mesa Copyright ำ 1987 by Xerox Corporation. All rights reserved. Jean-Marc Frailong December 30, 1987 8:46:27 pm PST Various hacks that are useful debuging tools in some painful cases Wire name mismatch helper This section helps understanding why two wires with different names are fused. It works exclusively if no structured wires are present (i.e. most probably on layout...) It implements 3 commands, all of which should be called when pushed in the faulty cell: Select wire roots ==> select all instances that would enfore a given wire name (through CD satellites, instance properties or otherwise). Grow wire one step ==> assuming that all selected instances are part of a single wire, add to the selection all instances that connect directly to one of the initially selected instances (i.e. a 1-step neighbour operation). Complain loudly if a name inconsistency crops up. Select wire ==> if nothing is selected, do first a 'Select wire roots' operations. Then repeat a 'Grow wire one step' operation until either nothing more gets connected, or an error occurs. All the commands assume that instances within the pushed-in cell are themselves extractible correctly. Instances that extract as wires are treated directly. Instances that extract as celltypes are added only insofar as one of their public wires connects to an already selected wire (independently of names), and only the geometry for such wires is recorded for future conections. Beware, this is not fast... but it's still much faster than doing it by hand. Types Context management Create a new context object, initialize all fields, enfore all invariants and check that all sub-objects extracts with atomic wires. Returns NIL if something went wrong. Cleanup context data structure Select instance and add it to context if not already selected Initialize the context from all instances that carry a wire with the specified cx.name Initialize the context with the set of currently selected instances Takes current information from context & extend object by a single connection step InstanceTables are assumed to contain all the geometry for selected instances. Upon return, new instances may have ben selected, the InstanceTables will contain all the geometry for selected instances, cx.highlight will be non-NIL if something went wrong (but the highlight has not been done yet). May raise the signal Bug if an instance does something wrong (e.g. having non-atomic wires). Returns TRUE iff no need to call again (error or nothing added). Commands Layout sanity checker This section may be used as a preliminary pass to Lichen for large cells, in order to discover trivial errors that would make Lichen more confused. The following tests are performed: - Transistors in which connections are not all different - Transistor gates connected to Gnd/Vdd - p-transistor well must be connected to Vdd None of these tests is really an error, they just seem to be strange... Effective code The technique consists in doing a CoreFlat enumeration of the connectivity and building a connection table transistor -> canonical flat wires. Check that the two specified terminals are not connected together Check that the specified terminal is not connected to power Command Who uses an object Return the list of 1st-order ancestors of a given object. Useful to know who will be disturbed if an object is modified... Effective code Print the list of objects that include this guy at 1st level PROC [me: CD.Object, data: REF_NIL] RETURNS [quit: BOOL_FALSE] PROC [inst: CD.Instance] RETURNS [quit: BOOL_FALSE] Command Usable layout Generate the layout for an object, recast all non-cells to cells and include the result into the well-know design "LayoutWorkArea". Same function provided for layout shells. Effective code Command Generate layout object for root, flatten it & include it Generate layout object for root, flatten it & include it Remove name hints Remove the $Describe CD property either from the whole design if nothing is selected, otherwise from whoever is selected. Command Initializations สษ˜codešœ™Kšœ<™K™ฉšก œ˜)Kšœ œ˜*Kšœ œœ˜Kšœ_˜_K˜Vš œ œœœ œ˜0Kšœ(œ˜:šœœ œ˜-Kšœœ˜+Kšœ˜Kšœ˜—šœœœœ˜KKšœœ˜2Kšœ˜—KšœœŸ&˜8—Kšœ œœE˜hK˜—Kšœ,˜,Kšœ9˜9Kšœœ˜'Kšœ˜Kšœ ˜ KšœœœŸ˜EKšœ%Ÿ˜DKšœ˜Kš œœœœœœ˜GKšœ3˜3Kšœ9Ÿ˜GšœœœŸ˜2KšœS˜SKšœœŸ˜%K˜—K˜K˜—šกœœ˜&K™šœœœ˜(Jšœ)˜)Kšœ˜—K˜K˜—š กœœœœœ˜EK™=Kšœœœœ˜*Kšœœ˜Kšœ&˜&Kšœœ˜K˜K˜—šก œœDœœ˜iKšœœ"˜5Kšœ œœ˜'Kšœœœ˜3šœœœ˜Kšœ3œ'œ˜nšœZœœ˜nKšœG˜GKšœœ3˜FKšœ˜—Kšœ˜—K˜K˜—šก œœG˜XšœZœœ˜nKšœG˜GKšœ6˜6šœœœ˜+Jšœ'œ˜,Jšœ˜—Kšœ˜—K˜K˜—š กœœDœ œœ˜wšœZœœ˜nšกœœB˜PKšœ5œ œ˜MK˜—KšœG˜GKšœ6˜6J•StartOfExpansion> -- [key: RefTab.Key, val: RefTab.Val] RETURNS [quit: BOOLEAN]šœœ%˜-šœœœ˜+Jšœ5˜5Jšœ˜—Kšœ˜—K˜K˜—šกœœ˜)K™Všก œ˜)Kšœœœ˜Jšœ œ˜*K˜Vš œ œœœ œ˜0Kšœœ8œ œ˜cšœœ œ˜-Kšœ?œ œ˜TKšœ˜Kšœ˜—KšœœŸ˜?KšœœŸ&˜8—šœœ˜Kšœ˜Kšœ&˜&Kšœ˜—Kšœœ˜*K˜—Kšœ œ˜Kšœ œ˜šœ˜Kšœ/˜/Kšœ˜—Kšœ6˜6Kšœ&Ÿ ˜FKšœGœœ˜jK˜K˜—šกœœœ œ˜@K™Cšก œ˜(Kšœ œ˜*Kš œœœœŸ˜4K˜Vš œ œœœ œ˜0Kšœœ#œ&˜fšœœ œ˜-Kšœ*œ-˜^Kšœ˜Kšœ˜—Kšœ(œ ˜LKšœœŸ&˜8—K˜—Kšœ œœœ˜"šœœœ˜(KšœB˜BKšœ˜—Kšœ5˜5šœ œœŸ,˜AKšœœ˜2Kšœœ˜'K˜šœœœ˜&Kšœ*œ-˜]Kšœ˜—Kšœ˜—Kšœ9Ÿ˜GKšœœ˜Kšœœ?˜MK˜K˜—šก œœœ œ˜šก œ˜(Kš œœ œœœ™3šœ œ˜Kšœœ˜.Kšœ˜KšœœŸ"˜/K˜—K˜—šœœŸ˜8Kšœ2˜2Kšœ˜—K˜—Kšœœ˜Kšœ'œ˜?KšœC˜CKšœ&œ˜˜>Kšœf˜fKšœ˜—šœ œŸ!˜DKšœœ˜.Kšœ œ ˜Kšœ:˜:Kšœ9˜9Kšœ˜—šœ Ÿ˜5Kšœ#œ˜Kšœ˜Jšœ/œ ˜>Jšœ$˜$Kšœ@˜@Kšœ%œ˜*Kšœ,œ˜1Kšœ;˜;K˜—KšœB˜BK˜K˜—šกœœ ˜5šกœ%˜-K™8Kšœœœœ ˜@Kšœ œ!˜0Kšœœ&˜.Jšœ.œ ˜=šœCœ˜KKšœ˜K˜K˜—Jšœ$˜$KšœFœ˜MKšœœœ œ˜IKšœ$œ˜)Kšœœ˜Kšœ;˜;K˜—KšœB˜BK˜———™K™y™šกœœ ˜6šกœ!˜/Kšœ+œœ+œ˜eK˜—JšœœF˜Ošœœœ˜šœœ˜Kšœœ˜)Kšœ˜Kšœ˜—K˜?K˜—šœ˜Kšœ8˜8K˜GK˜—K˜K˜———™Kšœฎ˜ฎKšœด˜ดšœ ˜ K™—šœค˜คK™—šœƒ˜ƒK™—Kšœ•˜•šœ}˜}K™—šœฉ˜ฉK™——K˜Kšœ˜—…—Nยs