<> <> <> <> <> DIRECTORY BitOps, CD, CDBasics, CDCells, CDCommandOps, CDEvents, CDImports, CDOps, CDProperties, CDSequencer, CDViewer, Core, CoreClasses, CoreFlat, CoreGeometry, CoreOps, CoreProperties, IntHashTable, IO, Ports, PW, RefTab, Rope, Rosemary, RosemaryUser, Sisyph, TerminalIO, TiogaButtons, ViewerClasses, ViewerOps; SchematicSimulation: CEDAR PROGRAM IMPORTS BitOps, CDBasics, CDCells, CDCommandOps, CDEvents, CDImports, CDOps, CDProperties, CDViewer, CoreClasses, CoreFlat, CoreGeometry, CoreOps, CoreProperties, IntHashTable, IO, Ports, PW, RefTab, Rope, Rosemary, RosemaryUser, Sisyph, TerminalIO, TiogaButtons, ViewerOps = BEGIN SchSimError: ERROR [msg: Rope.ROPE] = CODE; SchSimDebug: BOOL _ FALSE; <> SchematicSimulationValue: PROC [command: CDSequencer.Command] = { PrintAValue: SelectedFlatWireActionProc = { TerminalIO.PutF[ "Value[%g] = %g\n", IO.rope[CoreFlat.WirePathRope[display.cellType, flatWire^]], IO.rope[Ports.LSToRope[ Rosemary.WireValue[display.simulation, flatWire]]]]; }; DoForSelectedFlatWire[command, PrintAValue]; }; SchematicSimulationAddToPlot: PROC [command: CDSequencer.Command] = { AddAWire: SelectedFlatWireActionProc = { errorMsg _ RosemaryUser.AddWireToPlot[display, flatWire]; }; DoForSelectedFlatWire[command, AddAWire]; }; SelectedFlatWireActionProc: TYPE = PROC [display: RosemaryUser.RoseDisplay, flatWire: CoreFlat.FlatWire] RETURNS [errorMsg: Rope.ROPE _ NIL]; DoForSelectedFlatWire: PROC [command: CDSequencer.Command, action: SelectedFlatWireActionProc] = { errorMsg: Rope.ROPE; { ENABLE SchSimError, CoreFlat.PathError => {errorMsg _ msg; GOTO Done}; DoAValue: EachSelectedFlatWireProc = { flatWireRef: CoreFlat.FlatWire _ NEW[CoreFlat.FlatWireRec]; flatWireRef^ _ selectedFlatWire; IF RefTab.Insert[x: enumeratedWires, key: flatWireRef, val: $Enumerated] THEN { errorMsg _ action[display, flatWireRef]; someValueFound _ TRUE; quit _ errorMsg#NIL; }; }; display: RosemaryUser.RoseDisplay _ NARROW [CDProperties.GetDesignProp[command.design, $DAUserRoseDisplay]]; someValueFound: BOOL _ FALSE; enumeratedWires: RefTab.Ref _ RefTab.Create[equal: CoreFlat.FlatWireEqual, hash: CoreFlat.FlatWireHash]; [] _ EnumerateSelectedFlatWires[command.design, Sisyph.mode.decoration, display.cellType, display.cutSet, DoAValue]; IF NOT someValueFound THEN errorMsg _ "*** No such wire(s) found."; EXITS Done => NULL; }; IF errorMsg#NIL THEN TerminalIO.PutRopes[errorMsg, "\n"]; }; PopViewerForImport: PROC [command: CDSequencer.Command] ~ { multiple: BOOL; instance: CD.Instance; importedDesign: CD.Design; specific: CDImports.ImportSpecific; display: RosemaryUser.RoseDisplay; [instance, multiple] _ CDOps.SelectedInstance[command.design]; SELECT TRUE FROM multiple => { TerminalIO.PutF["\n** Multiple selections. No action.\n"]; RETURN}; instance=NIL => { TerminalIO.PutF["\n** No selection. No action.\n"]; RETURN}; NOT CDImports.IsImport[instance.ob] => { TerminalIO.PutF["\n** Not an import. No action.\n"]; RETURN}; ENDCASE => NULL; specific _ NARROW[instance.ob.specific]; importedDesign _ specific.boundDesign; IF importedDesign=NIL THEN { TerminalIO.PutF["\n** Import not bound yet. No action.\n"]; RETURN}; [] _ CDViewer.CreateViewer[importedDesign, FALSE]; display _ NARROW [CDProperties.GetDesignProp[command.design, $DAUserRoseDisplay]]; CDProperties.PutDesignProp[importedDesign, $DAUserRoseDisplay, display]; }; <> ResolveData: TYPE = REF ResolveDataRec; ResolveDataRec: TYPE = RECORD [ cell: Core.CellType _ NIL, instanceData: IntHashTable.Table _ NIL, feedBackButton: TiogaButtons.TiogaButton _ NIL, selectedInstance: NAT _ 0, doesNotMatter: BOOL _ TRUE, struckOut: BOOL _ FALSE]; InstanceData: TYPE = REF InstanceDataRec; InstanceDataRec: TYPE = RECORD [ design: CD.Design _ NIL, pushedData: PushedData _ NIL, resolve: ResolveData _ NIL, instance: NAT _ 0, objects: LIST OF CoreGeometry.Object _ NIL, -- only needed for debug if ChoiceRequired changed to use transitiveClosure cells: LIST OF Core.CellType _ NIL, -- only needed for debug button: TiogaButtons.TiogaButton _ NIL]; pushedDataAtom: ATOM = $DAUserPushedData; PushedData: TYPE = REF PushedDataRec; PushedDataRec: TYPE = RECORD [ topViewer: ViewerClasses.Viewer _ NIL, decoration: CoreGeometry.Decoration _ NIL, root: Core.CellType _ NIL, cutSet: CoreFlat.CutSet _ NIL, selectionData: RefTab.Ref _ NIL, transitiveClosure: RefTab.Ref _ NIL, cellType: Core.CellType _ NIL, flatCellType: CoreFlat.FlatCellTypeRec _ [], errorMessage: Rope.ROPE _ NIL]; CreateSelectionViewer: PROC [design: CD.Design, pushedData: PushedData, root: Core.CellType, decoration: CoreGeometry.Decoration, cutSet: CoreFlat.CutSet _ NIL] RETURNS [selectionData: RefTab.Ref _ NIL, transitiveClosure: RefTab.Ref _ NIL] = { RecordEachAncestor: EachLeastCommonObjectAncestorProc = { resolveData: ResolveData _ NARROW[RefTab.Fetch[selectionData, ancestor].val]; instanceData: InstanceData _ NIL; IF resolveData=NIL THEN { resolveData _ NEW[ResolveDataRec]; IF NOT RefTab.Insert[selectionData, ancestor, resolveData] THEN ERROR; resolveData.cell _ ancestor; resolvers _ CONS[resolveData, resolvers]; resolveData.instanceData _ IntHashTable.Create[]; }; instanceData _ NARROW[IntHashTable.Fetch[resolveData.instanceData, instance].value]; IF instanceData=NIL THEN { instanceData _ NEW[InstanceDataRec]; instanceData.design _ design; instanceData.pushedData _ pushedData; instanceData.resolve _ resolveData; instanceData.instance _ instance; IF NOT IntHashTable.Insert[resolveData.instanceData, instance, instanceData] THEN ERROR; }; IF object#NIL THEN FOR objects: LIST OF CoreGeometry.Object _ instanceData.objects, objects.rest UNTIL objects=NIL DO IF objects.first=object THEN EXIT; REPEAT FINISHED => instanceData.objects _ CONS[object, instanceData.objects]; ENDLOOP; IF cell#NIL THEN FOR cells: LIST OF Core.CellType _ instanceData.cells, cells.rest UNTIL cells=NIL DO IF cells.first=cell THEN EXIT; REPEAT FINISHED => instanceData.cells _ CONS[cell, instanceData.cells]; ENDLOOP; }; viewer: ViewerClasses.Viewer _ TiogaButtons.CreateViewer[[ name: Rope.Cat[CoreOps.GetCellTypeName[root], " Selection"], iconic: FALSE, column: left]]; resolvers: LIST OF ResolveData _ NIL; pushedData.topViewer _ viewer; selectionData _ RefTab.Create[]; transitiveClosure _ EnumerateLeastCommonObjectAncestors[root, decoration, RecordEachAncestor, cutSet]; FOR resolveList: LIST OF ResolveData _ resolvers, resolveList.rest UNTIL resolveList=NIL DO FindType: IntHashTable.EachPairAction = { IF RefTab.Insert[x: finishedSubCells, key: data[key].type, val: $Finished] THEN { subCellType _ data[key].type; quit _ TRUE; }; }; data: CoreClasses.RecordCellType _ NARROW[resolveList.first.cell.data]; subCellType: Core.CellType _ NIL; resolveName: Rope.ROPE _ CoreOps.GetCellTypeName[resolveList.first.cell]; button: TiogaButtons.TiogaButton _ TiogaButtons.CreateButton[viewer: viewer, rope: Rope.Cat[resolveName, ": "], looks: "f"]; finishedSubCells: RefTab.Ref _ RefTab.Create[]; firstChoice: BOOL _ TRUE; IF SchSimDebug THEN TerminalIO.PutRopes[resolveName, "\n"]; resolveList.first.feedBackButton _ button; WHILE IntHashTable.Pairs[resolveList.first.instanceData, FindType] DO AddInstanceChoice: IntHashTable.EachPairAction = { IF data[key].type=subCellType THEN { instanceData: InstanceData _ NARROW[value]; instanceName: Rope.ROPE _ CoreClasses.GetCellInstanceName[data[key]]; instanceData.button _ TiogaButtons.AppendToButton[button: button, rope: IF instanceName=NIL THEN IO.PutFR["%g", IO.int[key]] ELSE instanceName, looks: "f", proc: RecordInstanceNumber, clientData: instanceData, fork: FALSE]; [] _ TiogaButtons.AppendToButton[button: button, rope: " "]; IF firstChoice THEN { SetInstanceNumber[instanceData]; firstChoice _ FALSE; }; IF SchSimDebug THEN { TerminalIO.PutRopes[" ", IO.PutFR["%g(%g)", IO.int[key], IO.rope[CoreOps.GetCellTypeName[data[key].type]]], "\n"]; TerminalIO.PutRope[" Cells:\n"]; FOR cells: LIST OF Core.CellType _ instanceData.cells, cells.rest UNTIL cells=NIL DO TerminalIO.PutRopes[" ", CoreOps.GetCellTypeName[cells.first], "\n"]; ENDLOOP; TerminalIO.PutRope[" Objects:\n"]; FOR objects: LIST OF CoreGeometry.Object _ instanceData.objects, objects.rest UNTIL objects=NIL DO TerminalIO.PutRopes[" ", PW.Name[objects.first], "\n"]; ENDLOOP; }; }; }; [] _ IntHashTable.Pairs[resolveList.first.instanceData, AddInstanceChoice]; [] _ TiogaButtons.AppendToButton[button: button, rope: Rope.Cat["(", CoreOps.GetCellTypeName[subCellType], ") "], looks: "f"]; ENDLOOP; ENDLOOP; }; <<>> RecordInstanceNumber: TiogaButtons.TiogaButtonProc = { instanceData: InstanceData _ NARROW[clientData]; oldInstanceData: InstanceData _ NARROW[IntHashTable.Fetch[table: instanceData.resolve.instanceData, key: instanceData.resolve.selectedInstance].value]; TiogaButtons.ChangeButtonLooks[oldInstanceData.button, NIL, "i"]; SetInstanceNumber[instanceData]; RecomputePushedCellType[instanceData.design, instanceData.pushedData]; }; <<>> SetInstanceNumber: PROC [instanceData: InstanceData] = { instanceData.resolve.selectedInstance _ instanceData.instance; TiogaButtons.ChangeButtonLooks[instanceData.button, "i"]; instanceData _ instanceData; }; <<>> PushPop: CDEvents.EventProc = { pushedData: PushedData _ NARROW[CDProperties.GetDesignProp[design, pushedDataAtom]]; IF pushedData#NIL THEN RecomputePushedCellType[design, pushedData]; }; <<>> RecomputePushedCellType: PROC [design: CD.Design, pushedData: PushedData] = { BuildFlatCell: PROC [cell: Core.CellType, flatCell: CoreFlat.FlatCellTypeRec _ CoreFlat.rootCellType, instance: CoreClasses.CellInstance _ NIL, instances: LIST OF CD.Instance] = { matchingObject: BOOL _ CoreGeometry.GetObject[pushedData.decoration, cell]=instances.first.ob; SELECT TRUE FROM matchingObject AND instances.rest=NIL => { pushedData.errorMessage _ NIL; pushedData.cellType _ cell; pushedData.flatCellType _ flatCell; }; FixedCutSetMemberResolved[flatCell, instance, cell, pushedData.cutSet] => pushedData.errorMessage _ "*** No such cell"; cell.class=CoreClasses.recordCellClass => { rct: CoreClasses.RecordCellType _ NARROW[cell.data]; IF matchingObject THEN FOR inst: NAT IN [0..rct.size) DO thisInstance: CoreClasses.CellInstance _ rct[inst]; possibleInst: CoreGeometry.Instance _ [CoreGeometry.GetObject[pushedData.decoration, thisInstance.type], CoreGeometry.GetTrans[pushedData.decoration, thisInstance]]; IF SameCDInstance[instances.rest.first, instances.first.trans, possibleInst] THEN { BuildFlatCell[thisInstance.type, [CoreFlat.ExtendPath[flatCell.path, inst, rct], 0], thisInstance, instances.rest]; EXIT; }; REPEAT FINISHED => ERROR; -- record cell with CD object and next instance does not match? ENDLOOP ELSE { found: BOOL _ FALSE; multiple: BOOL _ FALSE; inst: NAT _ LAST[NAT]; FOR i: NAT IN [0..rct.size) DO subCellTable: RefTab.Ref _ NARROW[RefTab.Fetch[ pushedData.transitiveClosure, rct[i].type].val]; IF RefTab.Fetch[subCellTable, instances.first.ob].found THEN { multiple _ found; found _ TRUE; inst _ i; IF multiple THEN EXIT; }; ENDLOOP; SELECT TRUE FROM NOT found => pushedData.errorMessage _ "*** Cell cannot be reached with current selection viewer settings or selection viewer cannot disambiguate this object"; NOT multiple => { thisInstance: CoreClasses.CellInstance _ rct[inst]; BuildFlatCell[thisInstance.type, [CoreFlat.ExtendPath[flatCell.path, inst, rct], 0], thisInstance, instances]; }; ENDCASE => { resolveData: ResolveData _ NARROW[RefTab.Fetch[pushedData.selectionData, cell].val]; IF resolveData=NIL THEN pushedData.errorMessage _ "*** Selection viewer cannot disambiguate the push stack" ELSE { thisInstance: CoreClasses.CellInstance _ rct[resolveData.selectedInstance]; resolveData.doesNotMatter _ FALSE; BuildFlatCell[thisInstance.type, [CoreFlat.ExtendPath[flatCell.path, resolveData.selectedInstance, rct], 0], thisInstance, instances]; }; }; }; }; ENDCASE => { thisCell: Core.CellType _ CoreOps.Recast[cell]; BuildFlatCell[thisCell, IF thisCell=cell THEN flatCell ELSE [flatCell.path, flatCell.recastCount+1], instance, IF matchingObject THEN instances.rest ELSE instances]; }; }; instanceStack: LIST OF CD.Instance _ UnwindCDStack[design ! SchSimError => {pushedData.errorMessage _ msg; GOTO Quit}]; IF RefTab.Pairs[pushedData.selectionData, SetDoesNotMatter] THEN ERROR; BuildFlatCell[cell: pushedData.root, instances: instanceStack]; IF pushedData.errorMessage=NIL THEN IF RefTab.Pairs[pushedData.selectionData, DisplayDoesNotMatter] THEN ERROR; EXITS Quit => NULL; }; <<>> <> <<>> <> <> <> <> <> <<}>> <> <> <> <> <> <<};>> <<};>> <<};>> <<>> <> < {pushedData.errorMessage _ msg; GOTO Quit}] THEN IF NOT alreadyCalled THEN pushedData.errorMessage _ "*** Selection data picks no cell.";>> < NULL;>> <<};>> <<>> FilterUsingSelectionData: PROC [root: Core.CellType, flatCell: CoreFlat.FlatCellTypeRec, selectionData: RefTab.Ref, instanceSelections: RefTab.Ref] RETURNS [pass: BOOL _ FALSE] = { CheckSelection: CoreFlat.UnboundFlatCellProc = { SELECT TRUE FROM CoreFlat.FlatCellTypeEqualRec[flatCell, target] => pass _ TRUE; cell.class=CoreClasses.recordCellClass => { resolveData: ResolveData _ NARROW[RefTab.Fetch[selectionData, cell].val]; IF resolveData=NIL THEN CoreFlat.NextUnboundCellType[cell, target, flatCell, instance, index, parent, flatParent, NIL, CheckSelection] ELSE { ChoiceRequired: IntHashTable.EachPairAction = { instanceData: InstanceData _ NARROW[value]; FOR objects: LIST OF CoreGeometry.Object _ instanceData.objects, objects.rest UNTIL objects=NIL DO IF objects.first=instanceSelect.subObject THEN { quit _ found; found _ TRUE; EXIT; }; ENDLOOP; }; rct: CoreClasses.RecordCellType _ NARROW[cell.data]; pathBits: NAT _ BitOps.NBits[rct.size]; instanceBits: PACKED ARRAY [0..16) OF BOOL _ ALL [FALSE]; thisIndex: NAT _ 0; found: BOOL _ FALSE; instanceSelect: InstanceSelectionData _ NARROW[RefTab.Fetch[instanceSelections, cell].val]; FOR bit: NAT IN [0..pathBits) DO instanceBits[16-pathBits+bit] _ target.path.bits[flatCell.path.length+bit]; ENDLOOP; thisIndex _ LOOPHOLE[instanceBits]; resolveData.doesNotMatter _ (instanceSelect#NIL AND (thisIndex=instanceSelect.instance OR (instanceSelect.subObject#NIL AND NOT IntHashTable.Pairs[resolveData.instanceData, ChoiceRequired]))); IF thisIndex=resolveData.selectedInstance OR resolveData.doesNotMatter THEN CoreFlat.NextUnboundCellType[cell, target, flatCell, instance, index, parent, flatParent, NIL, CheckSelection] }; }; ENDCASE => CoreFlat.NextUnboundCellType[cell, target, flatCell, instance, index, parent, flatParent, NIL, CheckSelection]; }; IF RefTab.Pairs[selectionData, SetDoesNotMatter] THEN ERROR; CheckSelection[cell: root, target: flatCell]; IF pass THEN IF RefTab.Pairs[selectionData, DisplayDoesNotMatter] THEN ERROR; }; <<>> SetDoesNotMatter: RefTab.EachPairAction = { resolveData: ResolveData _ NARROW[val]; resolveData.doesNotMatter _ TRUE; }; DisplayDoesNotMatter: RefTab.EachPairAction = { resolveData: ResolveData _ NARROW[val]; IF resolveData.doesNotMatter#resolveData.struckOut THEN { IF resolveData.doesNotMatter THEN TiogaButtons.ChangeButtonLooks[resolveData.feedBackButton, "y"] ELSE TiogaButtons.ChangeButtonLooks[resolveData.feedBackButton, NIL, "y"]; resolveData.struckOut _ resolveData.doesNotMatter; }; }; EachLeastCommonObjectAncestorProc: TYPE = PROC [ancestor: Core.CellType, instance: NAT, cell: Core.CellType _ NIL, object: CoreGeometry.Object _ NIL]; FixedCutSetMemberResolved: PROC [flatCell: CoreFlat.FlatCellTypeRec, instance: CoreClasses.CellInstance, cellType: Core.CellType, cutSet: CoreFlat.CutSet] RETURNS [member: BOOL] = { member _ cellType.class=CoreClasses.transistorCellClass OR cellType.class=CoreClasses.unspecifiedCellClass OR CoreFlat.CutSetMemberResolved[flatCell, instance, cellType, cutSet]; }; EnumerateLeastCommonObjectAncestors: PROC [root: Core.CellType, decoration: CoreGeometry.Decoration, eachLeastCommonAncestor: EachLeastCommonObjectAncestorProc, cutSet: CoreFlat.CutSet _ NIL] RETURNS [transitiveClosure: RefTab.Ref _ NIL] = { <> ComputeCellObjectDependence: PROC [cell: Core.CellType, flatCell: CoreFlat.FlatCellTypeRec _ CoreFlat.rootCellType, instance: CoreClasses.CellInstance _ NIL] RETURNS [cellObjects: RefTab.Ref] = { cellObjects _ NARROW[RefTab.Fetch[transitiveClosure, cell].val]; IF cellObjects=NIL THEN { cellObjects _ RefTab.Create[]; IF CoreProperties.GetCellTypeProp[cell, $DAUserIgnoreForSelection]=NIL THEN { IF NOT RefTab.Insert[cellObjects, cell, $DependsOn] THEN ERROR; IF cell.class#CoreClasses.transistorCellClass AND CoreGeometry.HasObject[decoration, cell] THEN IF NOT RefTab.Insert[cellObjects, CoreGeometry.GetObject[ decoration, cell], $DependsOn] THEN ERROR; SELECT TRUE FROM FixedCutSetMemberResolved[flatCell, instance, cell, cutSet] => NULL; cell.class=CoreClasses.recordCellClass => { rct: CoreClasses.RecordCellType _ NARROW[cell.data]; FOR i: NAT IN [0..rct.size) DO InsertRecordSubObject: RefTab.EachPairAction = { subCell: Core.CellType _ NIL; object: CoreGeometry.Object _ NIL; IF NOT RefTab.Insert[cellObjects, key, NEW[NAT _ i]] THEN { firstInstance: REF ANY _ RefTab.Fetch[cellObjects, key].val; WITH key SELECT FROM o: CoreGeometry.Object => object _ o; s: Core.CellType => subCell _ s; ENDCASE => ERROR; IF ISTYPE[firstInstance, REF NAT] THEN { eachLeastCommonAncestor[cell, NARROW[firstInstance, REF NAT]^, subCell, object]; [] _ RefTab.Store[cellObjects, key, $DependsOn]; }; eachLeastCommonAncestor[cell, i, subCell, object]; }; }; subCellObjects: RefTab.Ref _ ComputeCellObjectDependence[rct[i].type, [CoreFlat.ExtendPath[flatCell.path, i, rct], 0], rct[i]]; IF RefTab.Pairs[subCellObjects, InsertRecordSubObject] THEN ERROR; ENDLOOP; }; ENDCASE => { InsertOtherSubObject: RefTab.EachPairAction = { [] _ RefTab.Store[cellObjects, key, $DependsOn]; }; new: Core.CellType _ CoreOps.Recast[cell]; recastCellObjects: RefTab.Ref _ IF cell=new THEN ComputeCellObjectDependence[cell, flatCell, instance] ELSE ComputeCellObjectDependence[new, [flatCell.path, flatCell.recastCount+1], instance]; IF RefTab.Pairs[recastCellObjects, InsertOtherSubObject] THEN ERROR; }; }; IF NOT RefTab.Insert[transitiveClosure, cell, cellObjects] THEN ERROR; }; }; transitiveClosure _ RefTab.Create[]; [] _ ComputeCellObjectDependence[root]; }; <<>> EachSelectedFlatWireProc: TYPE = PROC [selectedFlatWire: CoreFlat.FlatWireRec] RETURNS [quit: BOOL _ FALSE]; EnumerateSelectedFlatWires: PROC [design: CD.Design, decoration: CoreGeometry.Decoration, root: Core.CellType, cutSet: CoreFlat.CutSet _ NIL, eachSelectedFlatWire: EachSelectedFlatWireProc] RETURNS [quit: BOOL _ FALSE] = { ThisSelectedWire: EachSelectedWireProc = { quit _ eachSelectedFlatWire[[ flatCell: flatCell, wireRoot: IF publicWire THEN public ELSE internal, wire: selectedWire]]; }; publicWire: BOOL _ FALSE; flatCell: CoreFlat.FlatCellTypeRec _ []; cellType: Core.CellType _ NIL; [cellType, flatCell] _ FlatCellTypeFromPushed[design, decoration, root, cutSet]; IF cellType=NIL THEN ERROR SchSimError["The object of the instance at the top of the push stack does not appear in the simulation"]; publicWire _ cellType.class#CoreClasses.recordCellClass; quit _ EnumerateSelectedWires[design, decoration, IF publicWire THEN cellType.public ELSE NARROW[cellType.data, CoreClasses.RecordCellType].internal, publicWire, ThisSelectedWire]; }; <<>> FlatCellTypeFromPushed: PROC [design: CD.Design, decoration: CoreGeometry.Decoration, root: Core.CellType, cutSet: CoreFlat.CutSet _ NIL] RETURNS [pushedCellType: Core.CellType _ NIL, pushedFlatCellType: CoreFlat.FlatCellTypeRec _ CoreFlat.rootCellType] = { GetPushData: PROC = { IF pushedData.errorMessage#NIL THEN ERROR SchSimError[pushedData.errorMessage]; pushedCellType _ pushedData.cellType; pushedFlatCellType _ pushedData.flatCellType; }; pushedData: PushedData _ NARROW[CDProperties.GetDesignProp[design, pushedDataAtom]]; IF pushedData#NIL AND pushedData.root#root THEN { ViewerOps.DestroyViewer[pushedData.topViewer]; TerminalIO.PutRope["*** Only single selection viewer allowed per ChipNDale design\n"]; pushedData _ NIL; }; IF pushedData=NIL THEN { <<>> CheckForMultiple: EachSelectedFlatCellTypeProc = { pushedCellType _ cellType; pushedFlatCellType _ flatCellType; quit _ alreadyCalled; alreadyCalled _ TRUE; }; alreadyCalled: BOOL _ FALSE; IF EnumerateCellTypesForPushed[design, decoration, root, cutSet, CheckForMultiple] THEN { pushedData _ NEW[PushedDataRec]; pushedData.decoration _ decoration; pushedData.root _ root; pushedData.cutSet _ cutSet; [pushedData.selectionData, pushedData.transitiveClosure] _ CreateSelectionViewer[design, pushedData, root, decoration, cutSet]; CDProperties.PutDesignProp[design, pushedDataAtom, pushedData]; RecomputePushedCellType[design, pushedData]; GetPushData[]; }; } ELSE GetPushData[]; }; EachSelectedFlatCellTypeProc: TYPE = PROC [cellType: Core.CellType, flatCellType: CoreFlat.FlatCellTypeRec, instanceSelections: RefTab.Ref] RETURNS [quit: BOOL _ FALSE]; instanceSelectionNoInstance: NAT = LAST[NAT]; InstanceSelectionData: TYPE = REF InstanceSelectionDataRec; InstanceSelectionDataRec: TYPE = RECORD [ subObject: CoreGeometry.Object _ NIL, instance: NAT _ instanceSelectionNoInstance]; UnwindEnumeration: ERROR = CODE; EnumerateCellTypesForPushed: PROC [design: CD.Design, decoration: CoreGeometry.Decoration, root: Core.CellType, cutSet: CoreFlat.CutSet _ NIL, eachFlatCellType: EachSelectedFlatCellTypeProc] RETURNS [quit: BOOL _ FALSE] = { EnumerateCellTypes: CoreFlat.UnboundFlatCellProc = { instances: LIST OF CD.Instance _ NARROW[data]; matchingObject: BOOL _ CoreGeometry.HasObject[decoration, cell] AND CoreGeometry.GetObject[decoration, cell]=instances.first.ob; IF parent#NIL THEN { selectionData: InstanceSelectionData _ GetSelectionData[parent]; selectionData.subObject _ instances.first.ob; }; IF matchingObject AND instances.rest=NIL THEN {IF eachFlatCellType[cell, flatCell, instanceSelections] THEN ERROR UnwindEnumeration[]} ELSE IF NOT FixedCutSetMemberResolved[flatCell, instance, cell, cutSet] THEN IF cell.class=CoreClasses.recordCellClass AND matchingObject THEN CoreFlat.NextUnboundCellType[cell, target, flatCell, instance, index, parent, flatParent, instances, TransformInstance] ELSE CoreFlat.NextUnboundCellType[cell, target, flatCell, instance, index, parent, flatParent, IF matchingObject THEN instances.rest ELSE instances, EnumerateCellTypes]; }; TransformInstance: CoreFlat.UnboundFlatCellProc = { instances: LIST OF CD.Instance = NARROW [data]; possibleInst: CoreGeometry.Instance = [CoreGeometry.GetObject[decoration, instance.type], CoreGeometry.GetTrans[decoration, instance]]; IF SameCDInstance[instances.rest.first, instances.first.trans, possibleInst] THEN { selectionData: InstanceSelectionData _ GetSelectionData[parent]; selectionData.instance _ index; EnumerateCellTypes[cell, target, flatCell, instance, index, parent, flatParent, instances.rest]; selectionData.instance _ instanceSelectionNoInstance; }; }; GetSelectionData: PROC [parent: Core.CellType] RETURNS [selectionData: InstanceSelectionData] = { selectionData _ NARROW[RefTab.Fetch[instanceSelections, parent].val]; IF selectionData=NIL THEN { selectionData _ NEW[InstanceSelectionDataRec]; IF NOT RefTab.Insert[instanceSelections, parent, selectionData] THEN ERROR; }; }; instanceStack: LIST OF CD.Instance _ UnwindCDStack[design]; instanceSelections: RefTab.Ref _ RefTab.Create[]; EnumerateCellTypes[cell: root, data: instanceStack ! UnwindEnumeration => GOTO Quit]; EXITS Quit => quit _ TRUE; }; <<>> EachSelectedWireProc: TYPE = PROC [selectedWire: Core.Wire] RETURNS [quit: BOOL _ FALSE]; EnumerateSelectedWires: PROC [design: CD.Design, decoration: CoreGeometry.Decoration, root: Core.Wire, public: BOOL _ FALSE, eachSelectedWire: EachSelectedWireProc] RETURNS [quit: BOOL _ FALSE] = { ThisSelectedInstance: EachSelectedInstanceProc = { ThisWire: CoreOps.EachWireProc = { ThisWireInstance: CoreGeometry.EachInstanceProc = { quit _ instance=selectedInstance; }; match: BOOL _ IF public THEN CoreGeometry.EnumeratePins[decoration, wire, ThisWireInstance] ELSE CoreGeometry.EnumerateGeometry[decoration, wire, ThisWireInstance]; IF match THEN quit _ eachSelectedWire[wire]; }; quit _ CoreOps.VisitWire[root, ThisWire] }; quit _ EnumerateSelectedInstances[design, ThisSelectedInstance]; }; <<>> EachSelectedInstanceProc: TYPE = PROC [selectedInstance: CoreGeometry.Instance] RETURNS [quit: BOOL _ FALSE]; EnumerateSelectedInstances: PROC [design: CD.Design, eachInstance: EachSelectedInstanceProc] RETURNS [quit: BOOL _ FALSE] = { ThisInstance: CDCells.InstEnumerator = { IF inst.selected THEN { trans: CD.Transformation _ design.actual.first.mightReplace.trans; quit _ eachInstance[[inst.ob, [CDBasics.DeMapPoint[inst.trans.off, trans], CDBasics.DecomposeOrient[itemInWorld: inst.trans.orient, cellInWorld: trans.orient]]]]; }; }; quit _ CDCells.EnumerateInstances[design.actual.first.dummyCell.ob, ThisInstance]; }; <<>> SameCDInstance: PROC [cdinst: CD.Instance, trans: CD.Transformation, instance: CoreGeometry.Instance] RETURNS [BOOL] = { RETURN [ cdinst.ob=instance.obj AND CDBasics.DeMapPoint[cdinst.trans.off, trans]=instance.trans.off AND CDBasics.DecomposeOrient[itemInWorld: cdinst.trans.orient, cellInWorld: trans.orient]=instance.trans.orient ]; }; UnwindCDStack: PROC [design: CD.Design] RETURNS [instanceStack: LIST OF CD.Instance] = { IF design.actual.rest=NIL THEN ERROR SchSimError["*** No currently pushed-in cell."]; FOR stack: LIST OF CD.PushRec _ design.actual, stack.rest WHILE stack.rest#NIL DO IF stack.first.specific.changed THEN ERROR SchSimError[IO.PutFR["*** Impossible to extract stack, cell %g has been changed and not saved.", IO.rope[PW.Name[stack.first.mightReplace.ob]]]]; instanceStack _ CONS[stack.first.mightReplace, instanceStack]; ENDLOOP; }; <<>> CDCommandOps.RegisterWithMenu[menu: $OtherProgramMenu, entry: "Schematic Simulation Value", key: $DAUserSchematicSimulationValue, proc: SchematicSimulationValue, queue: doQueue]; CDCommandOps.RegisterWithMenu[menu: $OtherProgramMenu, entry: "Schematic Simulation Add To Plot", key: $DAUserSchematicSimulationAddToPlot, proc: SchematicSimulationAddToPlot, queue: doQueue]; CDCommandOps.RegisterWithMenu[menu: $OtherProgramMenu, entry: "Pop viewer for import", key: $DAUserSchematicSimulationPopViewer, proc: PopViewerForImport, queue: doQueue]; CDEvents.RegisterEventProc[event: $AfterPush, proc: PushPop]; CDEvents.RegisterEventProc[event: $AfterPop, proc: PushPop]; END. <<>>