PipalCoreCDUserImpl.mesa
Copyright Ó 1987, 1988 by Xerox Corporation. All rights reserved.
Barth, February 16, 1988 4:33:50 pm PST
Jean-Marc Frailong December 14, 1987 4:30:14 pm PST
Last tweaked by Mike Spreitzer on February 17, 1988 9:01:31 am PST
Bertrand Serlet May 12, 1988 0:06:44 am PDT
DIRECTORY
CD, CDBasics, CDBasicsInline, CDCells, CDCellsInteractions, CDDirectory, CDEvents, CDImports, CDInstances, CDOps, CDProperties, CDRects, CDViewer, Containers, Core, CoreClasses, CoreFlat, CoreOps, CoreProperties, IntHashTable, IO,
PipalCore, PipalCoreCDUser, PipalExtractOps, PipalSinix,
PW, RefTab, Rope, TerminalIO, TiogaButtons, ViewerClasses, ViewerOps;
PipalCoreCDUserImpl: CEDAR PROGRAM
IMPORTS CD, CDBasics, CDBasicsInline, CDCells, CDCellsInteractions, CDDirectory, CDEvents, CDImports, CDInstances, CDOps, CDProperties, CDRects, CDViewer, Containers, CoreClasses, CoreFlat, CoreOps, CoreProperties, IntHashTable, IO, PipalCore, PipalExtractOps, PW, RefTab, Rope, TerminalIO, TiogaButtons, ViewerOps
EXPORTS PipalCoreCDUser
SHARES CDImports
= BEGIN OPEN PipalCoreCDUser;
CoreCDUserError: PUBLIC SIGNAL [msg: Rope.ROPE] = CODE;
Context
EnumerateSelectedCellTypes: PUBLIC PROC [design: PipalUI.Design, eachRootCellType: EachRootCellTypeProc, mode: PipalSinix.Mode ← NIL] RETURNS [quit: BOOLFALSE] = {
originalSelectedInstances: CD.InstanceList ← CDInstances.OnlySelected[CDOps.InstList[design]];
IF originalSelectedInstances=NIL THEN TerminalIO.PutRope["PipalCoreCDUser: Nothing selected\n"]
ELSE FOR instances: CD.InstanceList ← originalSelectedInstances, instances.rest WHILE instances#NIL DO
thisMode: PipalSinix.Mode ← IF mode=NIL THEN PipalExtractOps.GetExtractMode[instances.first.ob] ELSE mode; -- JMF: added parameter to GetExtractMode
root: Core.CellType ← PipalExtractOps.ExtractCDInstanceCellTypeAndReport[instances.first, design, thisMode];
IF root#NIL THEN {
SetDesignRootCellType[design, root];
SetRootCellTypeDecoration[root, thisMode.decoration];
IF (quit ← eachRootCellType[root]) THEN EXIT;
};
ENDLOOP;
};
designRootCellTypeProp: ATOM = $CoreCDUserDesignRootCellType;
designImporterDesignProp: ATOM = $CoreCDUserDesignImporterDesign;
rootCellTypeDecorationProp: ATOM = $CoreCDUserRootCellTypeDecoration;
SetDesignRootCellType: PUBLIC PROC [design: PipalUI.Design, root: Core.CellType] = {
CDProperties.PutDesignProp[design, designRootCellTypeProp, root];
CDProperties.PutDesignProp[design, designImporterDesignProp, NIL];
FOR cl: LIST OF CDImports.Cache ← CDImports.GetCacheList[design].list, cl.rest UNTIL cl=NIL DO
IF cl.first.importee#NIL THEN SetImporterDesign[cl.first.importee, design]; -- JMF: Beware
ENDLOOP;
CoreProperties.PutCellTypeProp[root, designRootCellTypeProp, design];
CDProperties.PutDesignProp[design, transitiveClosureCache, NIL]; -- this should be done on pop which selects replace or new or during edit at top level but I don't know of any CD facilities to do so
SetImporterLabels[design];
};
GetDesignRootCellType: PUBLIC PROC [design: PipalUI.Design] RETURNS [root: Core.CellType] = {
IF GetImporterDesign[design]#NIL THEN design ← GetImporterDesign[design];
root ← NARROW[CDProperties.GetDesignProp[design, designRootCellTypeProp]];
};
GetRootCellTypeDesign: PUBLIC PROC [root: Core.CellType] RETURNS [design: PipalUI.Design] = {
design ← NARROW[CoreProperties.GetCellTypeProp[root, designRootCellTypeProp]];
};
SetImporterDesign: PUBLIC PROC [importee: PipalUI.Design, importer: PipalUI.Design] = {
CDProperties.PutDesignProp[importee, designRootCellTypeProp, NIL];
CDProperties.PutDesignProp[importee, designImporterDesignProp, importer];
SetImporteeLabels[importee];
FOR cl: LIST OF CDImports.Cache ← CDImports.GetCacheList[importee].list, cl.rest UNTIL cl=NIL DO
SetImporterDesign[cl.first.importee, importer];
ENDLOOP;
};
GetImporterDesign: PUBLIC PROC [importee: PipalUI.Design] RETURNS [importer: PipalUI.Design] = {
importer ← NARROW[CDProperties.GetDesignProp[importee, designImporterDesignProp]];
};
SetRootCellTypeDecoration: PUBLIC PROC [root: Core.CellType, decoration: PipalCore.Decoration] = {
CoreProperties.PutCellTypeProp[root, rootCellTypeDecorationProp, decoration];
};
GetRootCellTypeDecoration: PUBLIC PROC [root: Core.CellType] RETURNS [decoration: PipalCore.Decoration] = {
decoration ← NARROW[CoreProperties.GetCellTypeProp[root, rootCellTypeDecorationProp]];
};
FindDesignAndDecoration: PROC [root: Core.CellType, design: PipalUI.Design, decoration: PipalCore.Decoration] RETURNS [outDesign: PipalUI.Design, outDecoration: PipalCore.Decoration] = {
outDesign ← IF design=NIL THEN GetRootCellTypeDesign[root] ELSE design;
IF outDesign=NIL THEN ERROR CoreCDUserError["No design associated with root cell type"];
outDecoration ← IF decoration=NIL THEN GetRootCellTypeDecoration[root] ELSE decoration;
IF outDecoration=NIL THEN ERROR CoreCDUserError["No decoration associated with root cell type"];
};
SetImporterLabels: PROC [importer: PipalUI.Design] = {
label: Rope.ROPE ← GetImporterLabel[importer];
FOR viewers: CDViewer.ViewerList ← CDViewer.ViewersOf[importer], viewers.rest UNTIL viewers=NIL DO
ViewerOps.SetViewer[viewer: viewers.first, data: label, op: $Label];
ENDLOOP;
};
GetImporterLabel: PROC [importer: PipalUI.Design] RETURNS [label: Rope.ROPENIL] = {
root: Core.CellType ← GetDesignRootCellType[importer];
IF root#NIL THEN {
rootName: Rope.ROPE ← CoreOps.GetCellTypeName[root];
IF rootName=NIL THEN rootName ← "<no name>";
label ← Rope.Cat[importer.name, ": ", rootName];
};
};
SetImporteeLabels: PROC [importee: PipalUI.Design] = {
label: Rope.ROPE ← GetImporteeLabel[importee];
FOR viewers: CDViewer.ViewerList ← CDViewer.ViewersOf[importee], viewers.rest UNTIL viewers=NIL DO
ViewerOps.SetViewer[viewer: viewers.first, data: label, op: $Label];
ENDLOOP;
};
GetImporteeLabel: PROC [importee: PipalUI.Design] RETURNS [label: Rope.ROPENIL] = {
importer: PipalUI.Design ← GetImporterDesign[importee];
IF importer#NIL THEN {
importerLabel: Rope.ROPE ← GetImporterLabel[importer];
IF importerLabel#NIL THEN label ← Rope.Cat[importee.name, " -> ", importerLabel];
};
};
GetDesignLabel: PUBLIC PROC [design: PipalUI.Design] RETURNS [label: Rope.ROPENIL] = {
label ← IF GetImporterDesign[design]=NIL THEN GetImporterLabel[design] ELSE GetImporteeLabel[design];
};
Core To CD
HighlightFlatCellType: PUBLIC PROC [root: Core.CellType, flatCell: CoreFlat.FlatCellTypeRec, design: PipalUI.DesignNIL, decoration: PipalCore.Decoration ← NIL, viewer: ViewerClasses.Viewer ← NIL, clearFirst: BOOLTRUE] = {
cell: Core.CellType ← CoreFlat.ResolveFlatCellType[root, flatCell].cellType;
transform: CD.Transformation ← [];
[design, decoration] ← FindDesignAndDecoration[root, design, decoration];
[design, transform] ← FindFlatCellTransform[design, decoration, root, flatCell, cell];
IF clearFirst THEN PipalUI.HighlightDesign[design];
PipalUI.HighlightDesign[design, transform, PipalCore.GetObject[decoration, cell], viewer, GetDesignLabel[design]];
};
HighlightFlatWire: PUBLIC PROC [root: Core.CellType, flatWire: CoreFlat.FlatWireRec, design: PipalUI.DesignNIL, decoration: PipalCore.Decoration ← NIL, viewer: ViewerClasses.Viewer ← NIL, clearFirst: BOOLTRUE] = {
cell: Core.CellType ← CoreFlat.ResolveFlatCellType[root, flatWire.flatCell].cellType;
trans: Pipal.Transformation;
object: Pipal.Object;
[design, decoration] ← FindDesignAndDecoration[root, design, decoration];
[design, trans] ← FindFlatCellTransform[design, decoration, root, flatWire.flatCell, cell];
IF clearFirst THEN PipalUI.HighlightDesign[design];
PipalUI.HighlightDesign[design, trans, PipalCore.GetAllGeometry[decoration, cell, flatWire.wire], viewer, GetDesignLabel[design]];
};
FindFlatCellTransform: PROC [design: PipalUI.Design, decoration: PipalCore.Decoration, root: Core.CellType, flatCell: CoreFlat.FlatCellTypeRec, cell: Core.CellType] RETURNS [cellDesign: PipalUI.Design, transform: CD.Transformation ← []] = {
EachCDInstance: PROC [instance: CD.Instance] = {
transform ← CDBasics.ComposeTransform[instance.trans, transform];
};
cellDesign ← AllTogetherNow[design, decoration, root, flatCell, cell, EachCDInstance];
};
SelectFlatCellType: PUBLIC PROC [root: Core.CellType, flatCell: CoreFlat.FlatCellTypeRec, design: PipalUI.DesignNIL, decoration: PipalCore.Decoration ← NIL] = {
cell: Core.CellType ← CoreFlat.ResolveFlatCellType[root, flatCell].cellType;
trans: Pipal.Transformation; lastObject: Pipal.Object;
[design, decoration] ← FindDesignAndDecoration[root, design, decoration];
[design, trans, lastObject] ← PushToDesire[design, decoration, root, flatCell, cell];
IF PipalUI.SelectInstance[design, trans, lastObject] THEN CDOps.Redraw[design]; -- ERROR if not done? (BS)
};
SelectFlatWire: PUBLIC PROC [root: Core.CellType, flatWire: CoreFlat.FlatWireRec, design: PipalUI.DesignNIL, decoration: PipalCore.Decoration ← NIL] = {
cell: Core.CellType ← CoreFlat.ResolveFlatCellType[root, flatWire.flatCell].cellType;
trans: Pipal.Transformation; lastObject: Pipal.Object;
[design, decoration] ← FindDesignAndDecoration[root, design, decoration];
[design, trans, lastObject] ← PushToDesire[design, decoration, root, flatWire.flatCell, cell];
IF PipalUI.PushInstance[design, trans, lastObject] THEN {
SelectParents: PROC [parent: Core.Wire] RETURNS [yes: BOOLFALSE] = {
TurnOnSelected: PipalInt.EachChildProc = {
no ERROR if not done, because it might be a wire icon.
[] ← PipalUI.SelectInstance[design, PipalInt.Compose[transform, transformation], child];
};
TurnOnWire: CoreOps.EachWireProc = {
[] ← PipalMos.EnumerateAtomic[IF public THEN PipalCore.GetPort[decoration, wire] ELSE PipalCore.GetGeometry[decoration, wire], TurnOnSelected];
yes ← TRUE;
};
All this code stinks. There should be a simpler way (BS)
IF parent=flatWire.wire
THEN [] ← CoreOps.VisitWire[parent, TurnOnWire];
ELSE FOR wi: NAT IN [0 .. parent.size) DO
IF SelectParents[parent[wi]] THEN [] ← TurnOnWire[parent];
ENDLOOP;
};
public: BOOL ← cell.class#CoreClasses.recordCellClass;
[] ← SelectParents[cell.public];
IF cell.class=CoreClasses.recordCellClass THEN [] ← SelectParents[NARROW[cell.data, CoreClasses.RecordCellType].internal];
CDOps.Redraw[design];
}
ELSE ERROR CoreCDUserError["PipalCoreCDUser: Push failed"];
};
PushToDesire: PROC [design: PipalUI.Design, decoration: PipalCore.Decoration, root: Core.CellType, flatCell: CoreFlat.FlatCellTypeRec, cell: Core.CellType] RETURNS [cellDesign: PipalUI.Design, trans: Pipal.Transformation ← [], lastObject: Pipal.Object] = {
EachCDInstance: PROC [instance: CD.Instance] = {
instanceList ← CONS[instance, instanceList];
};
instanceList: LIST OF CD.Instance ← NIL;
reversed: LIST OF CD.Instance ← NIL;
cellDesign ← AllTogetherNow[design, decoration, root, flatCell, cell, EachCDInstance];
lastObject ← instanceList.first; -- needs CDToP!
instanceList ← instanceList.rest;
CDCellsInteractions.PopToTopLevel[cellDesign];
FOR il: LIST OF CD.Instance ← instanceList, il.rest UNTIL il=NIL DO
reversed ← CONS[il.first, reversed];
ENDLOOP;
FOR il: LIST OF CD.Instance ← reversed, il.rest UNTIL il=NIL DO
trans ← PipalInt.Compose[trans, il.first.trans]; -- needs CDToP!
IF NOT PipalUI.PushInstance[cellDesign, trans, il.first.ob]] THEN ERROR CoreCDUserError["PipalCoreCDUser: Push failed"];
ENDLOOP;
CDOps.DeselectAll[cellDesign];
};
AllTogetherNow: PROC [design: PipalUI.Design, decoration: PipalCore.Decoration, root: Core.CellType, flatCell: CoreFlat.FlatCellTypeRec, cell: Core.CellType, eachInstance: PROC [instance: CD.Instance]] RETURNS [cellDesign: PipalUI.Design] = {
IF PipalCore.HasObject[decoration, cell] THEN {
topInstances: PipalUI.TopInstanceLists ← PipalUI.GetTopInstances[design];
found: BOOLFALSE;
[cellDesign, found] ← FindInstances[ObjectTransitiveClosure[topInstances], topInstances, ListObjectsAndTransforms[decoration, root, flatCell], PipalCore.GetObject[decoration, cell], eachInstance];
IF NOT found THEN ERROR CoreCDUserError["PipalCoreCDUser: Cell type object is not reachable"];
}
ELSE ERROR CoreCDUserError["PipalCoreCDUser: Cell type to be used for selection or highlight has no object"];
};
FindInstances: PROC [closure: RefTab.Ref, instances: PipalUI.TopInstanceLists, searchList: LIST OF REF ANY, requiredObject: CD.Object, eachInstance: PROC [instance: CD.Instance]] RETURNS [cellDesign: PipalUI.Design, found: BOOLFALSE] = {
UNTIL searchList=NIL DO
FOR designInstances: PipalUI.TopInstanceLists ← instances, designInstances.rest UNTIL designInstances=NIL DO
cellDesign ← designInstances.first.design;
FOR topInstances: CD.InstanceList ← designInstances.first.instances, topInstances.rest UNTIL topInstances=NIL DO
cdObject: CD.Object ← topInstances.first.ob;
coreObject: CD.Object ← NARROW[searchList.first];
IF cdObject=coreObject THEN { -- BS: test used to be more sophisticated!
reachableFromTop: RefTab.Ref ← NARROW[RefTab.Fetch[closure, cdObject].val];
IF reachableFromTop#NIL AND RefTab.Fetch[reachableFromTop, requiredObject].found THEN {
eachInstance[topInstances.first];
DO
IF cdObject#NARROW[searchList.first] THEN RETURN; -- BS: test used to be more sophisticated!
IF searchList.rest=NIL THEN EXIT;
searchList ← searchList.rest;
UNTIL CDCells.IsCell[cdObject] DO
IF NOT cdObject.class.composed THEN RETURN;
cdObject ← CDDirectory.Expand1[cdObject].new;
ENDLOOP;
WITH searchList.first SELECT FROM
refTrans: REF CD.Transformation => {
Check: CDCells.InstEnumerator = {
quit ← inst.ob=NARROW[searchList.first] AND refTrans^=inst.trans; -- BS: test used to be more sophisticated!
IF quit THEN {
eachInstance[inst];
cdObject ← inst.ob;
};
};
searchList ← searchList.rest;
IF searchList=NIL OR NOT CDCells.EnumerateInstances[cdObject, Check] THEN RETURN;
};
coreObject: CD.Object => {
One: CDCells.InstEnumerator = {
IF inst.ob=NARROW[searchList.first] THEN { -- BS: test used to be more sophisticated!
quit ← oneFound;
oneFound ← TRUE;
eachInstance[inst];
cdObject ← inst.ob;
};
};
oneFound: BOOLFALSE;
IF CDCells.EnumerateInstances[cdObject, One] THEN RETURN;
};
ENDCASE;
ENDLOOP;
found ← TRUE;
RETURN;
};
};
ENDLOOP;
ENDLOOP;
searchList ← searchList.rest;
IF searchList#NIL AND ISTYPE[searchList.first, REF CD.Transformation] THEN searchList ← searchList.rest;
ENDLOOP;
};
ListObjectsAndTransforms: PROC [decoration: PipalCore.Decoration, root: Core.CellType, flatCellType: CoreFlat.FlatCellTypeRec] RETURNS [list: LIST OF REF ANYNIL]= {
ObjectInstanceScan: CoreFlat.UnboundFlatCellProc = {
CoreFlat.NextUnboundCellType[cell, target, flatCell, instance, index, parent, flatParent, data, ObjectInstanceScan];
IF PipalCore.HasObject[decoration, cell] THEN list ← CONS[PipalCore.GetObject[decoration, cell], list];
IF instance#NIL AND cell=instance.type AND PipalCore.HasTrans[decoration, instance] THEN list ← CONS[NEW[PipalCore.Transformation ← PipalCore.GetTrans[decoration, instance]], list];
};
ObjectInstanceScan[cell: root, target: flatCellType];
};
transitiveClosureCache: ATOM = $CoreCDUserTransitiveClosureCache;
Computes all objects reachable from the passed instance list. If this is the list of top level instances in the design then these are the objects which have top level instances, i.e. they are displayed in the design. closure maps objects to RefTab which then maps objects to their containing design (which may be NIL if an import is not yet bound). To pose the question "is A reachable from B" hash into closure with B and then hash into the resulting table with A. found => A is reachable from B. Every object is reachable from itself.
ObjectTransitiveClosure: PROC [topInstances: PipalUI.TopInstanceLists] RETURNS [closure: RefTab.Ref] = {
ComputeReachableObjects: PROC [design: PipalUI.Design, object: CD.Object] RETURNS [objects: RefTab.Ref ← NIL] = {
objects ← NARROW[RefTab.Fetch[closure, object].val];
IF objects=NIL AND NOT CDRects.IsSimpleRect[object] THEN {
objects ← RefTab.Create[];
IF NOT RefTab.Insert[objects, object, design] THEN ERROR;
IF object.class.composed THEN {
CombineObjects: PROC [subDesign: PipalUI.Design, subObject: CD.Object] = {
InsertObject: RefTab.EachPairAction = {
[] ← RefTab.Insert[objects, key, val];
};
subObjects: RefTab.Ref ← ComputeReachableObjects[subDesign, subObject];
IF subObjects#NIL THEN [] ← RefTab.Pairs[subObjects, InsertObject];
};
IF CDCells.IsCell[object] THEN {
InsertInstances: CDCells.InstEnumerator = {
CombineObjects[design, inst.ob];
};
[] ← CDCells.EnumerateInstances[object, InsertInstances];
}
ELSE CombineObjects[IF CDImports.IsImport[object] THEN NARROW[object.specific, CDImports.ImportSpecific].boundDesign ELSE design, CDDirectory.Expand1[object].new];
};
IF NOT RefTab.Insert[closure, object, objects] THEN ERROR;
};
};
closure ← NARROW[CDProperties.GetDesignProp[topInstances.first.design, transitiveClosureCache]];
IF closure=NIL THEN {
closure ← RefTab.Create[];
FOR designs: PipalUI.TopInstanceLists ← topInstances, designs.rest UNTIL designs=NIL DO
FOR designTopInstances: CD.InstanceList ← designs.first.instances, designTopInstances.rest UNTIL designTopInstances=NIL DO
[] ← ComputeReachableObjects[designs.first.design, designTopInstances.first.ob];
ENDLOOP;
ENDLOOP;
CDProperties.PutDesignProp[topInstances.first.design, transitiveClosureCache, closure];
};
};
CD To Core
Basic Operations
ignoreMeProp: PUBLIC ATOM ← $DAUserIgnoreForSelection; -- Fix CellLibraries some day to have this atom correspond to the package in which PipalCoreCDUser is contained.
EnumerateSelectedFlatWires: PUBLIC PROC [root: Core.CellType, eachSelectedFlatWire: EachSelectedFlatWireProc, cutSet: CoreFlat.CutSet ← NIL, design: PipalUI.DesignNIL, decoration: PipalCore.Decoration ← NIL] RETURNS [quit: BOOLFALSE] = {
ThisSelectedWire: EachSelectedWireProc = {
quit ← eachSelectedFlatWire[[
flatCell: flatCell,
wireRoot: IF publicWire THEN public ELSE internal,
wire: selectedWire]];
};
publicWire: BOOLFALSE;
cellType: Core.CellType ← NIL;
flatCell: CoreFlat.FlatCellTypeRec ← [];
[design, decoration] ← FindDesignAndDecoration[root, design, decoration];
[cellType, flatCell] ← FlatCellTypeFromPushed[design, decoration, root, cutSet];
publicWire ← cellType.class#CoreClasses.recordCellClass;
quit ← EnumerateSelectedWires[design, decoration, IF publicWire THEN cellType.public ELSE NARROW[cellType.data, CoreClasses.RecordCellType].internal, publicWire, ThisSelectedWire];
};
EachSelectedWireProc: TYPE = PROC [selectedWire: Core.Wire] RETURNS [quit: BOOLFALSE];
EnumerateSelectedWires: PROC [design: PipalUI.Design, decoration: PipalCore.Decoration, root: Core.Wire, public: BOOLFALSE, eachSelectedWire: EachSelectedWireProc] RETURNS [quit: BOOLFALSE] = {
ThisSelectedInstance: PipalInt.EachChildProc = {
ThisWire: CoreOps.EachWireProc = {
IF NOT PipalUI.Contains[IF public THEN PipalCore.GetPort[decoration, wire] ELSE PipalCore.Getgeometry[decoration, wire], transformation, child] THEN RETURN;
quit ← eachSelectedWire[wire];
someMatch ← TRUE;
};
someMatch: BOOLFALSE;
quit ← CoreOps.VisitWire[root, ThisWire];
There used to be some code for object which do not directly end up as decorations (such as well contacts). Of course this might now be bogus, since those objects are split directly after the CD -> Pipal conversion
IF NOT someMatch THEN ERROR CoreCDUserError["PipalCoreCDUser: Some selected instance does not correspond to any wire"];
};
quit ← PipalUI.EnumerateSelectedObjects[design, ThisSelectedInstance];
};
EnumerateSelectedFlatCells: PUBLIC PROC [root: Core.CellType, eachSelectedFlatCell: EachSelectedFlatCellProc, cutSet: CoreFlat.CutSet ← NIL, design: PipalUI.DesignNIL, decoration: PipalCore.Decoration ← NIL] RETURNS [quit: BOOLFALSE] = {
[design, decoration] ← FindDesignAndDecoration[root, design, decoration];
IF design.actual.rest=NIL THEN {
ThisSelectedInstance: PipalUI.EachSelectedProc = {
errorMessage: Rope.ROPENIL;
flatCellType: CoreFlat.FlatCellTypeRec ← [];
[errorMessage,,flatCellType] ← BuildFlatCell[cell: root, instances: LIST[object], pushData: pushData];
IF errorMessage#NIL THEN ERROR CoreCDUserError[errorMessage];
quit ← eachSelectedFlatCell[flatCellType]
};
pushData: DesignPushData ← GetPushData[design, decoration, root, cutSet];
quit ← PipalUI.EnumerateSelectedObjects[design, ThisSelectedInstance];
}
ELSE {
SelectedCellType: EachSelectedCellInstanceProc = {
quit ← eachSelectedFlatCell[[CoreFlat.ExtendPath[flatCell.path, selectedCellInstance, rct], 0]];
};
cellType: Core.CellType ← NIL;
flatCell: CoreFlat.FlatCellTypeRec ← [];
rct: CoreClasses.RecordCellType ← NIL;
[cellType, flatCell] ← FlatCellTypeFromPushed[design, decoration, root, cutSet];
rct ← NARROW[cellType.data]; -- All pushed in objects must be record cells so this must succeed
quit ← EnumerateSelectedCellInstances[design, decoration, rct, SelectedCellType];
};
};
EachSelectedCellInstanceProc: TYPE = PROC [selectedCellInstance: NAT] RETURNS [quit: BOOLFALSE];
EnumerateSelectedCellInstances: PROC [design: PipalUI.Design, decoration: PipalCore.Decoration, rct: CoreClasses.RecordCellType, eachSelectedCellInstance: EachSelectedCellInstanceProc] RETURNS [quit: BOOLFALSE] = {
ThisSelectedInstance: PipalExtractOps.EachSelectedProc = {
FOR i: NAT IN [0..rct.size) DO
IF PipalCore.HasTrans[decoration, rct[i]] AND PipalCore.HasObject[decoration, rct[i].type] AND PipalUI.SameInstances[PipalCore.GetTrans[decoration, rct[i]], PipalCore.GetObject[decoration, rct[i].type], transformation, object] THEN {
quit ← eachSelectedCellInstance[i];
EXIT;
};
REPEAT FINISHED => ERROR CoreCDUserError["PipalCoreCDUser: Some selected instance does not correspond to any cell type"];
ENDLOOP;
};
quit ← PipalUI.EnumerateSelectedObjects[design, ThisSelectedInstance];
};
pushDataAtom: ATOM = $CoreCDUserPushData;
CellPushData: TYPE = REF CellPushDataRec;
CellPushDataRec: TYPE = RECORD [
decoration: PipalCore.Decoration ← NIL,
root: Core.CellType ← NIL,
cutSet: CoreFlat.CutSet ← NIL,
selectionData: RefTab.Ref ← NIL,
transitiveClosure: RefTab.Ref ← NIL,
viewer: ViewerClasses.Viewer ← NIL,
doesNotMatterDesign: PipalUI.DesignNIL,
designPushData: LIST OF DesignPushData ← NIL];
DesignPushData: TYPE = REF DesignPushDataRec;
DesignPushDataRec: TYPE = RECORD [
design: PipalUI.DesignNIL,
cellPushData: CellPushData ← NIL,
cellType: Core.CellType ← NIL,
flatCellType: CoreFlat.FlatCellTypeRec ← [],
errorMessage: Rope.ROPENIL];
ResolveData: TYPE = REF ResolveDataRec;
ResolveDataRec: TYPE = RECORD [
cell: Core.CellType ← NIL,
instanceData: IntHashTable.Table ← NIL,
feedBackButton: TiogaButtons.TiogaButton ← NIL,
selectedInstance: NAT ← 0,
doesNotMatter: BOOLTRUE,
struckOut: BOOLFALSE];
InstanceData: TYPE = REF InstanceDataRec;
InstanceDataRec: TYPE = RECORD [
design: PipalUI.DesignNIL,
pushData: CellPushData ← NIL,
resolve: ResolveData ← NIL,
instance: NAT ← 0,
objects: LIST OF PipalCore.Object ← NIL, -- only needed for debug
cells: LIST OF Core.CellType ← NIL, -- only needed for debug
button: TiogaButtons.TiogaButton ← NIL];
pushDebug: BOOLFALSE;
FlatCellTypeFromPushed: PROC [design: PipalUI.Design, decoration: PipalCore.Decoration, root: Core.CellType, cutSet: CoreFlat.CutSet ← NIL] RETURNS [pushedCellType: Core.CellType ← NIL, pushedFlatCellType: CoreFlat.FlatCellTypeRec ← CoreFlat.rootCellType] = {
pushData: DesignPushData ← GetPushData[design, decoration, root, cutSet];
IF pushData.errorMessage#NIL THEN ERROR CoreCDUserError[pushData.errorMessage];
pushedCellType ← pushData.cellType;
pushedFlatCellType ← pushData.flatCellType;
IF pushedCellType=NIL THEN ERROR CoreCDUserError["PipalCoreCDUser: The object of the instance at the top of the push stack is not reachable from the root cell type"];
};
GetPushData: PROC [design: PipalUI.Design, decoration: PipalCore.Decoration, root: Core.CellType, cutSet: CoreFlat.CutSet ← NIL] RETURNS [pushData: DesignPushData] = {
pushData ← NARROW[CDProperties.GetDesignProp[design, pushDataAtom]];
IF pushData=NIL OR (pushData#NIL AND (pushData.cellPushData.root#root OR pushData.cellPushData.decoration#decoration)) THEN {
cellPushData: CellPushData ← NARROW[CoreProperties.GetCellTypeProp[root, pushDataAtom]];
IF cellPushData=NIL OR (cellPushData#NIL AND (cellPushData.root#root OR cellPushData.decoration#decoration)) THEN {
IF pushData#NIL AND pushData.cellPushData.viewer#NIL THEN ViewerOps.DestroyViewer[pushData.cellPushData.viewer];
cellPushData ← CreatePushData[design, root, decoration, cutSet];
CoreProperties.PutCellTypeProp[root, pushDataAtom, cellPushData];
};
pushData ← CreateDesignPushData[design, cellPushData];
RecomputePushedCellType[pushData];
}
ELSE IF pushData.cellPushData.doesNotMatterDesign#design THEN RecomputePushedCellType[pushData];
};
CreateDesignPushData: PROC [design: PipalUI.Design, cellPushData: CellPushData] RETURNS [pushData: DesignPushData] = {
pushData ← NEW[DesignPushDataRec];
pushData.design ← design;
pushData.cellPushData ← cellPushData;
cellPushData.designPushData ← CONS[pushData, cellPushData.designPushData];
CDProperties.PutDesignProp[design, pushDataAtom, pushData];
};
CreatePushData: PROC [design: PipalUI.Design, root: Core.CellType, decoration: PipalCore.Decoration, cutSet: CoreFlat.CutSet ← NIL] RETURNS [pushData: CellPushData] = {
RecordEachAncestor: EachLeastCommonObjectAncestorProc = {
resolveData: ResolveData ← NARROW[RefTab.Fetch[pushData.selectionData, ancestor].val];
instanceData: InstanceData ← NIL;
IF resolveData=NIL THEN {
resolveData ← NEW[ResolveDataRec];
IF NOT RefTab.Insert[pushData.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.pushData ← pushData;
instanceData.resolve ← resolveData;
instanceData.instance ← instance;
IF NOT IntHashTable.Insert[resolveData.instanceData, instance, instanceData] THEN ERROR;
};
IF object#NIL THEN FOR objects: LIST OF PipalCore.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;
};
resolvers: LIST OF ResolveData ← NIL;
pushData ← NEW[CellPushDataRec];
pushData.decoration ← decoration;
pushData.root ← root;
pushData.cutSet ← cutSet;
pushData.selectionData ← RefTab.Create[];
pushData.transitiveClosure ← EnumerateLeastCommonObjectAncestors[design, root, decoration, RecordEachAncestor, cutSet];
IF resolvers#NIL THEN {
externalViewer: ViewerClasses.Viewer ← Containers.Create[[ -- JMF: TiogaButtons hack
name: Rope.Cat[CoreOps.GetCellTypeName[root], " Selection"],
scrollable: FALSE,
iconic: TRUE,
column: left]];
viewer: ViewerClasses.Viewer ← TiogaButtons.CreateViewer[[ -- JMF: TiogaButtons hack
name: Rope.Cat[CoreOps.GetCellTypeName[root], " Selection"],
column: left,
border: FALSE,
parent: externalViewer]];
pushData.viewer ← viewer;
Containers.ChildXBound[externalViewer, viewer];
Containers.ChildYBound[externalViewer, viewer];
viewer: ViewerClasses.Viewer ← TiogaButtons.CreateViewer[[ -- JMF: TiogaButtons hack
name: Rope.Cat[CoreOps.GetCellTypeName[root], " Selection"],
iconic: FALSE,
column: left]];
pushData.viewer ← viewer;
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: BOOLTRUE;
IF pushDebug 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 pushDebug 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 PipalCore.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;
ViewerOps.OpenIcon[externalViewer]; -- JMF: TiogaButtoms hack
};
};
RecordInstanceNumber: TiogaButtons.TiogaButtonProc = {
instanceData: InstanceData ← NARROW[clientData];
oldInstanceData: InstanceData ← NARROW[IntHashTable.Fetch[table: instanceData.resolve.instanceData, key: instanceData.resolve.selectedInstance].value];
pushData: DesignPushData ← NARROW[CDProperties.GetDesignProp[ instanceData.pushData.doesNotMatterDesign, pushDataAtom]];
TiogaButtons.ChangeButtonLooks[oldInstanceData.button, NIL, "i"];
SetInstanceNumber[instanceData];
FOR dpd: LIST OF DesignPushData ← instanceData.pushData.designPushData, dpd.rest UNTIL dpd=NIL DO
IF dpd.first#pushData THEN RecomputePushedCellType[dpd.first];
ENDLOOP;
RecomputePushedCellType[pushData];
};
SetInstanceNumber: PROC [instanceData: InstanceData] = {
instanceData.resolve.selectedInstance ← instanceData.instance;
TiogaButtons.ChangeButtonLooks[instanceData.button, "i"];
instanceData ← instanceData;
};
PushPop: CDEvents.EventProc = {
pushData: DesignPushData ← NARROW[CDProperties.GetDesignProp[design, pushDataAtom]];
importerDesign: PipalUI.Design ← GetImporterDesign[design];
IF importerDesign#NIL THEN {
importerPushData: DesignPushData ← NARROW[CDProperties.GetDesignProp[importerDesign, pushDataAtom]];
IF importerPushData#NIL AND pushData=NIL THEN pushData ← CreateDesignPushData[design, importerPushData.cellPushData];
};
IF pushData#NIL THEN RecomputePushedCellType[pushData];
};
RecomputePushedCellType: PROC [pushData: DesignPushData] = {
design: PipalUI.Design ← pushData.design;
instanceStack: LIST OF CD.Instance ← NIL;
pushData.errorMessage ← NIL;
pushData.cellPushData.doesNotMatterDesign ← design;
IF design.actual.rest=NIL THEN pushData.errorMessage ← "PipalCoreCDUser: No currently pushed-in cell."
ELSE {
FOR stack: LIST OF CD.PushRec ← design.actual, stack.rest WHILE stack.rest#NIL DO
IF stack.first.specific.changed THEN {
pushData.errorMessage ← IO.PutFR["PipalCoreCDUser: Impossible to unwind stack, cell %g has been changed and not saved.", IO.rope[PW.Name[stack.first.mightReplace.ob]]];
EXIT;
};
instanceStack ← CONS[stack.first.mightReplace, instanceStack];
ENDLOOP;
IF pushData.errorMessage=NIL THEN {
IF RefTab.Pairs[pushData.cellPushData.selectionData, SetDoesNotMatter] THEN ERROR;
[pushData.errorMessage, pushData.cellType, pushData.flatCellType] ← BuildFlatCell[cell: pushData.cellPushData.root, instances: instanceStack, pushData: pushData];
IF pushData.errorMessage=NIL THEN IF RefTab.Pairs[pushData.cellPushData.selectionData, DisplayDoesNotMatter] THEN ERROR;
};
};
};
BuildFlatCell: PROC [cell: Core.CellType, flatCell: CoreFlat.FlatCellTypeRec ← CoreFlat.rootCellType, instance: CoreClasses.CellInstance ← NIL, instances: LIST OF CD.Instance, pushData: DesignPushData] RETURNS [errorMessage: Rope.ROPENIL, cellType: Core.CellType, flatCellType: CoreFlat.FlatCellTypeRec ← CoreFlat.rootCellType] = {
matchingObject: BOOLinstances.first.ob=PipalCore.GetObject[pushData.cellPushData.decoration, cell]; -- BS: test used to be more sophisticated!
SELECT TRUE FROM
matchingObject AND instances.rest=NIL => {
cellType ← cell;
flatCellType ← flatCell;
};
CoreFlat.CutSetMemberResolved[flatCell, instance, cell, pushData.cellPushData.cutSet] => errorMessage ← "PipalCoreCDUser: No such cell above current cut set";
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];
IF PipalUI.SameInstances[
instances.first.trans,
instances.rest.first,
PipalCore.GetTrans[pushData.cellPushData.decoration, thisInstance],
PipalCore.GetObject[pushData.cellPushData.decoration, thisInstance.type]
] THEN {
[errorMessage, cellType, flatCellType] ← BuildFlatCell[thisInstance.type, [CoreFlat.ExtendPath[flatCell.path, inst, rct], 0], thisInstance, instances.rest, pushData];
EXIT;
};
REPEAT FINISHED => ERROR; -- record cell with CD object and next instance does not match?
ENDLOOP
ELSE {
cdObject: CD.Object ← instances.first.ob;
found: BOOLFALSE;
multiple: BOOLFALSE;
inst: NATLAST[NAT];
WHILE CDImports.IsImport[cdObject] DO cdObject ← CDDirectory.Expand1[cdObject].new ENDLOOP;
FOR i: NAT IN [0..rct.size) DO
subCellTable: RefTab.Ref ← NARROW[RefTab.Fetch[ pushData.cellPushData.transitiveClosure, rct[i].type].val];
IF RefTab.Fetch[subCellTable, cdObject].found THEN {
multiple ← found;
found ← TRUE;
inst ← i;
IF multiple THEN EXIT;
};
ENDLOOP;
SELECT TRUE FROM
NOT found => errorMessage ← "PipalCoreCDUser: Cell cannot be reached with current selection viewer settings or selection viewer cannot disambiguate this object";
NOT multiple => {
thisInstance: CoreClasses.CellInstance ← rct[inst];
[errorMessage, cellType, flatCellType] ← BuildFlatCell[thisInstance.type, [CoreFlat.ExtendPath[flatCell.path, inst, rct], 0], thisInstance, instances, pushData];
};
ENDCASE => {
resolveData: ResolveData ← NARROW[RefTab.Fetch[pushData.cellPushData.selectionData, cell].val];
IF resolveData=NIL THEN errorMessage ← "PipalCoreCDUser: Cannot disambiguate this object"
ELSE {
thisInstance: CoreClasses.CellInstance ← rct[resolveData.selectedInstance];
resolveData.doesNotMatter ← FALSE;
[errorMessage, cellType, flatCellType] ← BuildFlatCell[thisInstance.type, [CoreFlat.ExtendPath[flatCell.path, resolveData.selectedInstance, rct], 0], thisInstance, instances, pushData];
};
};
};
};
ENDCASE => {
thisCell: Core.CellType ← CoreOps.Recast[cell];
[errorMessage, cellType, flatCellType] ← BuildFlatCell[thisCell, IF thisCell=cell THEN flatCell ELSE [flatCell.path, flatCell.recastCount+1], instance, IF matchingObject THEN instances.rest ELSE instances, pushData];
};
};
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;
};
};
Using the ignore bindings form of enumeration keep a hash table of objects and cell types reachable from a cell, including the cell itself and the object belonging to it. While combining the objects and cells reachable from a cell notice if an object or cell is inserted more than once, i.e. accessable through more than one instance. If it is then call eachLeastCommonAncestor for the current cell. This routine only understands record cells and therefore only record cells are passed to eachLeastCommonAncestor. eachLeastCommonAncestor may be called multiple times with the same arguments. It will be called with all of the multiple instances through which a cell or object may be reached. transitiveClosure maps CellType to RefTab which then maps Object or CellType to $DependsOn or REF NAT.
EachLeastCommonObjectAncestorProc: TYPE = PROC [ancestor: Core.CellType, instance: NAT, cell: Core.CellType ← NIL, object: PipalCore.Object ← NIL];
EnumerateLeastCommonObjectAncestors: PROC [design: PipalUI.Design, root: Core.CellType, decoration: PipalCore.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, ignoreMeProp]=NIL THEN {
IF NOT RefTab.Insert[cellObjects, cell, $DependsOn] THEN ERROR;
IF cell.class#CoreClasses.transistorCellClass AND PipalCore.HasObject[decoration, cell] THEN IF NOT RefTab.Insert[cellObjects, PipalCore.GetObject[ decoration, cell], $DependsOn] THEN ERROR;
SELECT TRUE FROM
CoreFlat.CutSetMemberResolved[flatCell, instance, cell, cutSet] => NULL;
cell.class=CoreClasses.recordCellClass => {
rct: CoreClasses.RecordCellType ← NARROW[cell.data];
rctHasObject: BOOL ← PipalCore.HasObject[decoration, cell];
FOR i: NAT IN [0..rct.size) DO
InsertRecordSubObject: RefTab.EachPairAction = {
subCell: Core.CellType ← NIL;
object: PipalCore.Object ← NIL;
IF NOT RefTab.Insert[cellObjects, key, NEW[NAT ← i]] THEN {
firstInstance: REF ANY ← RefTab.Fetch[cellObjects, key].val;
ambiguousMultipath: BOOLTRUE;
WITH key SELECT FROM
o: PipalCore.Object => {
object ← o;
IF rctHasObject THEN ambiguousMultipath ← RefTab.Fetch[topObjects, object].found;
};
s: Core.CellType => {
subCell ← s;
ambiguousMultipath ← NOT PipalCore.HasObject[decoration, subCell];
};
ENDCASE => ERROR;
IF ambiguousMultipath THEN {
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;
};
};
topObjects: RefTab.Ref ← RefTab.Create[];
FOR ti: PipalUI.TopInstanceLists ← PipalUI.GetTopInstances[design], ti.rest UNTIL ti=NIL DO
FOR il: CD.InstanceList ← ti.first.instances, il.rest UNTIL il=NIL DO
[] ← RefTab.Insert[topObjects, il.first.ob, $TopLevelInstance];
ENDLOOP;
ENDLOOP;
transitiveClosure ← RefTab.Create[];
[] ← ComputeCellObjectDependence[root];
};
Command Utilities
DoForSelectedFlatWires: PUBLIC PROC [root: Core.CellType, action: SelectedFlatWireActionProc, cutSet: CoreFlat.CutSet ← NIL, design: PipalUI.DesignNIL, decoration: PipalCore.Decoration ← NIL] = {
errorMsg: Rope.ROPE;
{
ENABLE {
CoreCDUserError => {errorMsg ← msg; GOTO Done};
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 {
action[flatWireRef];
someValueFound ← TRUE;
};
};
someValueFound: BOOLFALSE;
enumeratedWires: RefTab.Ref ← RefTab.Create[equal: CoreFlat.FlatWireEqual, hash: CoreFlat.FlatWireHash];
[] ← EnumerateSelectedFlatWires[root, DoAValue, cutSet, design, decoration];
IF NOT someValueFound THEN errorMsg ← "PipalCoreCDUser: No wire(s) found.";
EXITS
Done => NULL;
};
IF errorMsg#NIL THEN TerminalIO.PutRopes[errorMsg, "\n"];
};
DoForSelectedFlatCells: PUBLIC PROC [root: Core.CellType, action: SelectedFlatCellActionProc, cutSet: CoreFlat.CutSet ← NIL, design: PipalUI.DesignNIL, decoration: PipalCore.Decoration ← NIL] = {
errorMsg: Rope.ROPE;
{
ENABLE {
CoreCDUserError => {errorMsg ← msg; GOTO Done};
CoreFlat.PathError => {errorMsg ← msg; GOTO Done};
};
DoAValue: EachSelectedFlatCellProc = {
flatCellTypeRef: CoreFlat.FlatCellType ← NEW[CoreFlat.FlatCellTypeRec];
flatCellTypeRef^ ← selectedFlatCell;
action[flatCellTypeRef];
someValueFound ← TRUE;
};
someValueFound: BOOLFALSE;
[] ← EnumerateSelectedFlatCells[root, DoAValue, cutSet, design, decoration];
IF NOT someValueFound THEN errorMsg ← "PipalCoreCDUser: No cell type(s) found";
EXITS
Done => NULL;
};
IF errorMsg#NIL THEN TerminalIO.PutRopes[errorMsg, "\n"];
};
Start Code
CDEvents.RegisterEventProc[event: $AfterPush, proc: PushPop];
CDEvents.RegisterEventProc[event: $AfterPop, proc: PushPop];
END.