CoreCDUserImpl.mesa
Copyright Ó 1987 by Xerox Corporation. All rights reserved.
Barth, June 24, 1988 4:06:44 pm PDT
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
DIRECTORY CD, CDBasics, CDBasicsInline, CDCells, CDCellsInteractions, CDDirectory, CDEvents, CDImports, CDInstances, CDOps, CDProperties, CDRects, CDViewer, Containers, Core, CoreCDUser, CoreClasses, CoreFlat, CoreGeometry, CoreOps, CoreProperties, ExtractOps, IntHashTable, IO, PW, RefTab, Rope, Sinix, TerminalIO, TiogaButtons, ViewerClasses, ViewerOps;
CoreCDUserImpl: CEDAR PROGRAM
IMPORTS CD, CDBasics, CDBasicsInline, CDCells, CDCellsInteractions, CDDirectory, CDEvents, CDImports, CDInstances, CDOps, CDProperties, CDRects, CDViewer, Containers, CoreClasses, CoreFlat, CoreGeometry, CoreOps, CoreProperties, ExtractOps, IntHashTable, IO, PW, RefTab, Rope, TerminalIO, TiogaButtons, ViewerOps
EXPORTS CoreCDUser
SHARES CDImports
= BEGIN OPEN CoreCDUser;
CoreCDUserError: PUBLIC SIGNAL [msg: Rope.ROPE] = CODE;
Context
EnumerateSelectedCellTypes: PUBLIC PROC [design: CD.Design, eachRootCellType: EachRootCellTypeProc, mode: Sinix.Mode ← NIL] RETURNS [quit: BOOLFALSE] = {
originalSelectedInstances: CD.InstanceList ← CDInstances.OnlySelected[CDOps.InstList[design]];
originalSelectedInstances: CD.InstanceList ← NIL; -- JMF: It's already in ChipNDale
FOR instances: CD.InstanceList ← CDOps.InstList[design], instances.rest WHILE instances#NIL DO
IF instances.first.selected THEN {
originalSelectedInstances ← CONS[CDInstances.Copy[instances.first], originalSelectedInstances];
};
ENDLOOP;
IF originalSelectedInstances=NIL THEN TerminalIO.PutRope["CoreCDUser: Nothing selected\n"]
ELSE FOR instances: CD.InstanceList ← originalSelectedInstances, instances.rest WHILE instances#NIL DO
thisMode: Sinix.Mode ← IF mode=NIL THEN ExtractOps.GetExtractMode[design, instances.first.ob] ELSE mode; -- JMF: added parameter to GetExtractMode
root: Core.CellType ← ExtractOps.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: CD.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];
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: CD.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: CD.Design] = {
design ← NARROW[CoreProperties.GetCellTypeProp[root, designRootCellTypeProp]];
};
SetImporterDesign: PUBLIC PROC [importee: CD.Design, importer: CD.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
IF cl.first.importee#NIL THEN SetImporterDesign[cl.first.importee, importer];
ENDLOOP;
};
GetImporterDesign: PUBLIC PROC [importee: CD.Design] RETURNS [importer: CD.Design] = {
importer ← NARROW[CDProperties.GetDesignProp[importee, designImporterDesignProp]];
};
SetRootCellTypeDecoration: PUBLIC PROC [root: Core.CellType, decoration: CoreGeometry.Decoration] = {
CoreProperties.PutCellTypeProp[root, rootCellTypeDecorationProp, decoration];
};
GetRootCellTypeDecoration: PUBLIC PROC [root: Core.CellType] RETURNS [decoration: CoreGeometry.Decoration] = {
decoration ← NARROW[CoreProperties.GetCellTypeProp[root, rootCellTypeDecorationProp]];
};
FindDesignAndDecoration: PROC [root: Core.CellType, design: CD.Design, decoration: CoreGeometry.Decoration] RETURNS [outDesign: CD.Design, outDecoration: CoreGeometry.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: CD.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: CD.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: CD.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: CD.Design] RETURNS [label: Rope.ROPENIL] = {
importer: CD.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: CD.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: CD.Design ← NIL, decoration: CoreGeometry.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 ExtractOps.HighlightDesign[design];
ExtractOps.HighlightDesign[design, ExtractOps.HighlightInstance[[CoreGeometry.GetObject[decoration, cell], transform]], viewer, GetDesignLabel[design]];
};
HighlightFlatWire: PUBLIC PROC [root: Core.CellType, flatWire: CoreFlat.FlatWireRec, design: CD.Design ← NIL, decoration: CoreGeometry.Decoration ← NIL, viewer: ViewerClasses.Viewer ← NIL, clearFirst: BOOLTRUE] = {
cell: Core.CellType ← CoreFlat.ResolveFlatCellType[root, flatWire.flatCell].cellType;
instance: CD.Instance ← NEW[CD.InstanceRep];
[design, decoration] ← FindDesignAndDecoration[root, design, decoration];
[design, instance.trans] ← FindFlatCellTransform[design, decoration, root, flatWire.flatCell, cell];
PutWireHighlight[decoration, cell];
instance.ob ← NARROW[CoreProperties.GetWireProp[flatWire.wire, wireHighlightProp]];
IF clearFirst THEN ExtractOps.HighlightDesign[design];
ExtractOps.HighlightDesign[design, instance, viewer, GetDesignLabel[design]];
};
ClearHighlight: PUBLIC PROC [root: Core.CellType ← NIL, design: CD.Design ← NIL] = {
IF design=NIL THEN {
IF root=NIL THEN ERROR CoreCDUserError["Gimme a break!"];
design ← GetRootCellTypeDesign[root]};
ExtractOps.HighlightDesign[design];
RETURN};
FindFlatCellTransform: PROC [design: CD.Design, decoration: CoreGeometry.Decoration, root: Core.CellType, flatCell: CoreFlat.FlatCellTypeRec, cell: Core.CellType] RETURNS [cellDesign: CD.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: CD.Design ← NIL, decoration: CoreGeometry.Decoration ← NIL] = {
cell: Core.CellType ← CoreFlat.ResolveFlatCellType[root, flatCell].cellType;
lastInstance: CD.Instance ← NIL;
transform: CD.Transformation ← [];
cdInst: CD.Instance; -- JMF : bug fix
[design, decoration] ← FindDesignAndDecoration[root, design, decoration];
[design, lastInstance, transform] ← PushToDesire[design, decoration, root, flatCell, cell];
cdInst ← ExtractOps.FindSameInstance[design, lastInstance, transform]; -- JMF
IF cdInst#NIL THEN cdInst.selected ← TRUE; -- JMF
ExtractOps.FindSameInstance[design, lastInstance, transform].selected ← TRUE; -- JMF
CDOps.Redraw[design];
};
SelectFlatWire: PUBLIC PROC [root: Core.CellType, flatWire: CoreFlat.FlatWireRec, design: CD.Design ← NIL, decoration: CoreGeometry.Decoration ← NIL] = {
cell: Core.CellType ← CoreFlat.ResolveFlatCellType[root, flatWire.flatCell].cellType;
lastInstance: CD.Instance ← NIL;
cdInstance: CD.Instance ← NEW[CD.InstanceRep];
mayBeInst: CD.Instance; -- JMF: bug fix
transform: CD.Transformation ← [];
[design, decoration] ← FindDesignAndDecoration[root, design, decoration];
[design, lastInstance, transform] ← PushToDesire[design, decoration, root, flatWire.flatCell, cell];
mayBeInst ← ExtractOps.FindSameInstance[design, lastInstance, transform]; -- JMF
IF mayBeInst#NIL AND CDCellsInteractions.PushInCellInstance[design, mayBeInst] THEN {
SelectParents: PROC [parent: Core.Wire] RETURNS [yes: BOOLFALSE] = {
TurnOnSelected: CoreGeometry.EachInstanceProc = {
mayBeInst: CD.Instance; -- JMF: bug fix
cdInstance.ob ← instance.obj;
cdInstance.trans ← instance.trans;
mayBeInst ← ExtractOps.FindSameInstance[design, cdInstance, transform];
IF mayBeInst#NIL THEN mayBeInst.selected ← TRUE;
};
IF parent=flatWire.wire THEN {
TurnOnChild: CoreOps.EachWireProc = {
[] ← IF public THEN CoreGeometry.EnumeratePins[decoration, wire, TurnOnSelected] ELSE CoreGeometry.EnumerateGeometry[decoration, wire, TurnOnSelected];
};
[] ← CoreOps.VisitWire[parent, TurnOnChild];
yes ← TRUE;
}
ELSE {
FOR wi: NAT IN [0..parent.size) DO
IF SelectParents[parent[wi]] THEN {
[] ← IF public THEN CoreGeometry.EnumeratePins[decoration, parent, TurnOnSelected] ELSE CoreGeometry.EnumerateGeometry[decoration, parent, TurnOnSelected];
yes ← TRUE;
};
ENDLOOP;
};
};
public: BOOL ← cell.class#CoreClasses.recordCellClass;
transform ← CDBasics.ComposeTransform[lastInstance.trans, transform];
[] ← SelectParents[cell.public];
IF cell.class=CoreClasses.recordCellClass THEN [] ← SelectParents[NARROW[cell.data, CoreClasses.RecordCellType].internal];
CDOps.Redraw[design];
}
ELSE ERROR CoreCDUserError["CoreCDUser: Push failed"];
};
PushToDesire: PROC [design: CD.Design, decoration: CoreGeometry.Decoration, root: Core.CellType, flatCell: CoreFlat.FlatCellTypeRec, cell: Core.CellType] RETURNS [cellDesign: CD.Design, lastInstance: CD.Instance ← NIL, transform: CD.Transformation ← []] = {
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];
lastInstance ← instanceList.first;
instanceList ← instanceList.rest;
ExtractOps.PopTop[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
IF ~CDCellsInteractions.PushInCellInstance[cellDesign, ExtractOps.FindSameInstance[cellDesign, il.first, transform]] THEN ERROR CoreCDUserError["CoreCDUser: Push failed"];
transform ← CDBasics.ComposeTransform[il.first.trans, transform];
ENDLOOP;
CDOps.DeselectAll[cellDesign];
};
AllTogetherNow: PROC [design: CD.Design, decoration: CoreGeometry.Decoration, root: Core.CellType, flatCell: CoreFlat.FlatCellTypeRec, cell: Core.CellType, eachInstance: PROC [instance: CD.Instance]] RETURNS [cellDesign: CD.Design] = {
IF CoreGeometry.HasObject[decoration, cell] THEN {
topInstances: ExtractOps.TopInstanceLists ← ExtractOps.GetTopInstances[design];
found: BOOLFALSE;
[cellDesign, found] ← FindInstances[ObjectTransitiveClosure[topInstances], topInstances, ListObjectsAndTransforms[decoration, root, flatCell], CoreGeometry.GetObject[decoration, cell], eachInstance];
IF NOT found THEN ERROR CoreCDUserError["CoreCDUser: Cell type object is not reachable"];
}
ELSE ERROR CoreCDUserError["CoreCDUser: Cell type to be used for selection or highlight has no object"];
};
FindInstances: PROC [closure: RefTab.Ref, instances: ExtractOps.TopInstanceLists, searchList: LIST OF REF ANY, requiredObject: CD.Object, eachInstance: PROC [instance: CD.Instance]] RETURNS [cellDesign: CD.Design, found: BOOLFALSE] = {
UNTIL searchList=NIL DO
FOR designInstances: ExtractOps.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 ExtractOps.SameCDObject[cdObject, coreObject] THEN {
reachableFromTop: RefTab.Ref ← NARROW[RefTab.Fetch[closure, cdObject].val];
IF reachableFromTop#NIL AND RefTab.Fetch[reachableFromTop, requiredObject].found THEN {
eachInstance[topInstances.first];
DO
IF NOT ExtractOps.SameCDObject[cdObject, NARROW[searchList.first]] THEN RETURN;
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 ← ExtractOps.SameCDObject[inst.ob, NARROW[searchList.first]] AND refTrans^=inst.trans;
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 ExtractOps.SameCDObject[inst.ob, NARROW[searchList.first]] THEN {
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: CoreGeometry.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 CoreGeometry.HasObject[decoration, cell] THEN list ← CONS[CoreGeometry.GetObject[decoration, cell], list];
IF instance#NIL AND cell=instance.type AND CoreGeometry.HasTrans[decoration, instance] THEN list ← CONS[NEW[CoreGeometry.Transformation ← CoreGeometry.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: ExtractOps.TopInstanceLists] RETURNS [closure: RefTab.Ref] = {
ComputeReachableObjects: PROC [design: CD.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: CD.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: ExtractOps.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];
};
};
wireHighlightProp: ATOM ← $CoreCDUserWireHighlight;
wireHighlightClass: CD.ObjectClass ← NIL;
WireHighlights: TYPE = LIST OF WireHighlight;
WireHighlight: TYPE = REF WireHighlightRec;
WireHighlightRec: TYPE = RECORD [
public: BOOLFALSE,
decoration: CoreGeometry.Decoration ← NIL,
wire: Core.Wire ← NIL,
parents: WireHighlights ← NIL,
children: WireHighlights ← NIL,
bound: CoreGeometry.Instances ← NIL]; -- transformation from CellInstance, object from bound wire
WireHighlightDrawMe: CD.DrawProc = {
DrawInstance: CoreGeometry.EachInstanceProc = {
cdInstance.ob ← instance.obj;
cdInstance.trans ← instance.trans;
IF CDBasicsInline.IntersectRI[mapClip, cdInstance] THEN pr.drawChild[pr, cdInstance.ob, CDBasics.ComposeTransform[cdInstance.trans, trans]];
quit ← pr.stopFlag^;
};
mapClip: CD.Rect ← CDBasics.DeMapRect[pr.interestClip, trans].itemInCell;
cdInstance: CD.Instance ← NEW[CD.InstanceRep]; -- get rid of this by defining CDBasicsInline.IntersectRI that takes a record instead of a ref
wh: WireHighlight ← NARROW[ob.specific];
oldRectProc: REF CD.DrawRectProc ← NIL;
IF pr.drawRect#WireHighlightDrawRect THEN {
oldRectProc ← NEW[CD.DrawRectProc ← pr.drawRect];
pr.drawRect ← WireHighlightDrawRect;
CDProperties.PutPRefProp[pr.properties, drawRectProcProp, oldRectProc];
};
EnumerateWireHighlightInstances[wh, DrawInstance];
IF oldRectProc#NIL THEN pr.drawRect ← oldRectProc^;
};
EnumerateWireHighlightInstances: PROC [wh: WireHighlight, eachInstance: CoreGeometry.EachInstanceProc] = {
EnumerateUpward: PROC [wh: WireHighlight] RETURNS [quit: BOOLFALSE] = {
IF (IF wh.public THEN CoreGeometry.EnumeratePins[wh.decoration, wh.wire, eachInstance] ELSE CoreGeometry.EnumerateGeometry[wh.decoration, wh.wire, eachInstance]) THEN RETURN [TRUE];
FOR whl: WireHighlights ← wh.parents, whl.rest UNTIL whl=NIL DO
IF EnumerateUpward[whl.first] THEN RETURN [TRUE];
ENDLOOP;
};
EnumerateDownward: PROC [wh: WireHighlight, bound: BOOL] RETURNS [quit: BOOLFALSE] = {
IF bound THEN FOR t: CoreGeometry.Instances ← wh.bound, t.rest UNTIL t=NIL DO
IF eachInstance[t.first] THEN RETURN;
ENDLOOP;
FOR whl: WireHighlights ← wh.children, whl.rest UNTIL whl=NIL DO
IF (IF wh.public THEN CoreGeometry.EnumeratePins[whl.first.decoration, whl.first.wire, eachInstance] ELSE CoreGeometry.EnumerateGeometry[whl.first.decoration, whl.first.wire, eachInstance]) THEN RETURN [TRUE];
IF EnumerateDownward[whl.first, wh.bound=NIL] THEN RETURN [TRUE];
ENDLOOP;
};
IF EnumerateUpward[wh] THEN RETURN;
IF EnumerateDownward[wh, TRUE] THEN RETURN;
};
drawRectProcProp: Rope.ROPE ← "WireHighlightDrawRectProc";
WireHighlightDrawRect: CD.DrawRectProc = {
oldRectProc: REF CD.DrawRectProc ← NARROW[CDProperties.GetPRefProp[pr.properties, drawRectProcProp]];
oldRectProc^[pr, r, CD.shadeLayer];
};
PutWireHighlight: PROC [decoration: CoreGeometry.Decoration, cell: Core.CellType] = {
Put: PROC [wire: Core.Wire, parent: WireHighlight ← NIL] RETURNS [wh: WireHighlight] = {
object: CD.Object ← NARROW[CoreProperties.GetWireProp[wire, wireHighlightProp]];
IF object=NIL THEN {
wh ← NEW[WireHighlightRec];
wh.public ← cell.class#CoreClasses.recordCellClass;
wh.decoration ← decoration;
wh.wire ← wire;
wh.parents ← IF parent=NIL THEN NIL ELSE LIST[parent];
FOR wi: NAT IN [0..wire.size) DO
wh.children ← CONS[Put[wire[wi], wh], wh.children];
ENDLOOP;
object ← NEW[CD.ObjectRep];
object.class ← wireHighlightClass;
object.bbox ← CDBasics.empty;
object.specific ← wh;
CoreProperties.PutWireProp[wire, wireHighlightProp, object];
}
ELSE {
wh ← NARROW[object.specific];
IF parent#NIL THEN wh.parents ← CONS[parent, wh.parents];
};
};
PutWireSeq: PROC [wire: Core.Wire] = {
FOR wi: NAT IN [0..wire.size) DO
[] ← Put[wire[wi]];
ENDLOOP;
};
IF CoreProperties.GetCellTypeProp[cell, wireHighlightProp]=NIL THEN {
RecomputeBBox: CoreOps.EachWireProc = {
ResetBBox: CoreGeometry.EachInstanceProc = {
object.bbox ← CDBasics.Surround[object.bbox, CoreGeometry.InlineBBox[instance]];
};
object: CD.Object ← NARROW[CoreProperties.GetWireProp[wire, wireHighlightProp]];
wh: WireHighlight ← NARROW[object.specific];
EnumerateWireHighlightInstances[wh, ResetBBox];
};
PutWireSeq[cell.public];
IF CoreGeometry.HasObject[decoration, cell] AND cell.class=CoreClasses.recordCellClass THEN {
rct: CoreClasses.RecordCellType ← NARROW[cell.data];
PutWireSeq[rct.internal];
FOR ii: NAT IN [0..rct.size) DO
ci: CoreClasses.CellInstance ← rct[ii];
IF CoreGeometry.HasTrans[decoration, ci] THEN {
PutBound: CoreOps.EachWirePairProc = {
ao: CD.Object ← NARROW[CoreProperties.GetWireProp[actualWire, wireHighlightProp]];
awh: WireHighlight ← NARROW[ao.specific];
po: CD.Object ← NARROW[CoreProperties.GetWireProp[publicWire, wireHighlightProp]];
awh.bound ← CONS[[po, transform], awh.bound];
};
transform: CoreGeometry.Transformation ← CoreGeometry.GetTrans[decoration, ci];
PutWireHighlight[decoration, ci.type];
[] ← CoreOps.VisitBindingSeq[ci.actual, ci.type.public, PutBound];
};
ENDLOOP;
[] ← CoreOps.VisitWireSeq[rct.internal, RecomputeBBox];
};
[] ← CoreOps.VisitWireSeq[cell.public, RecomputeBBox];
CoreProperties.PutCellTypeProp[cell, wireHighlightProp, $Done];
};
};
CD To Core
Basic Operations
ignoreMeProp: PUBLIC ATOM ← $DAUserIgnoreForSelection; -- Fix CellLibraries some day to have this atom correspond to the package in which CoreCDUser is contained.
EnumerateSelectedFlatWires: PUBLIC PROC [root: Core.CellType, eachSelectedFlatWire: EachSelectedFlatWireProc, cutSet: CoreFlat.CutSet ← NIL, design: CD.Design ← NIL, decoration: CoreGeometry.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: CD.Design, decoration: CoreGeometry.Decoration, root: Core.Wire, public: BOOLFALSE, eachSelectedWire: EachSelectedWireProc] RETURNS [quit: BOOLFALSE] = {
ThisSelectedInstance: ExtractOps.EachSelectedInstanceProc = {
ThisWire: CoreOps.EachWireProc = {
ThisWireInstance: CoreGeometry.EachInstanceProc = {
quit ← instance=selectedInstance;
};
match: BOOLIF public THEN CoreGeometry.EnumeratePins[decoration, wire, ThisWireInstance] ELSE CoreGeometry.EnumerateGeometry[decoration, wire, ThisWireInstance];
IF match THEN {
quit ← eachSelectedWire[wire];
someMatch ← TRUE;
};
};
someMatch: BOOLFALSE;
quit ← CoreOps.VisitWire[root, ThisWire];
IF NOT someMatch AND NOT CDRects.IsBareRect[selectedInstance.obj] THEN {
EachFlatInstance: CoreGeometry.EachInstanceProc = {
ThisWire: CoreOps.EachWireProc = {
ThisWireInstance: CoreGeometry.EachInstanceProc = {
quit ← instance=flatInstance;
};
match: BOOLIF public THEN CoreGeometry.EnumeratePins[decoration, wire, ThisWireInstance] ELSE CoreGeometry.EnumerateGeometry[decoration, wire, ThisWireInstance];
IF match THEN {
quit ← eachSelectedWire[wire];
someMatch ← TRUE;
};
};
flatInstance: CoreGeometry.Instance ← instance;
quit ← CoreOps.VisitWire[root, ThisWire];
};
quit ← CoreGeometry.FlattenInstance[selectedInstance, EachFlatInstance];
};
IF NOT someMatch THEN ERROR CoreCDUserError["CoreCDUser: Some selected instance does not correspond to any wire"];
};
quit ← ExtractOps.EnumerateSelectedInstances[design, ThisSelectedInstance];
};
EnumerateSelectedFlatCells: PUBLIC PROC [root: Core.CellType, eachSelectedFlatCell: EachSelectedFlatCellProc, cutSet: CoreFlat.CutSet ← NIL, design: CD.Design ← NIL, decoration: CoreGeometry.Decoration ← NIL] RETURNS [quit: BOOLFALSE] = {
[design, decoration] ← FindDesignAndDecoration[root, design, decoration];
IF design.actual.rest=NIL THEN {
ThisSelectedInstance: ExtractOps.EachSelectedInstanceProc = {
errorMessage: Rope.ROPENIL;
flatCellType: CoreFlat.FlatCellTypeRec ← [];
cdInstance.trans ← selectedInstance.trans;
cdInstance.ob ← selectedInstance.obj;
[errorMessage,,flatCellType] ← BuildFlatCell[cell: root, instances: LIST[cdInstance], pushData: pushData];
IF errorMessage#NIL THEN ERROR CoreCDUserError[errorMessage];
quit ← eachSelectedFlatCell[flatCellType]
};
cdInstance: CD.Instance ← NEW[CD.InstanceRep];
pushData: DesignPushData ← GetPushData[design, decoration, root, cutSet];
quit ← ExtractOps.EnumerateSelectedInstances[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: CD.Design, decoration: CoreGeometry.Decoration, rct: CoreClasses.RecordCellType, eachSelectedCellInstance: EachSelectedCellInstanceProc] RETURNS [quit: BOOLFALSE] = {
ThisSelectedInstance: ExtractOps.EachSelectedInstanceProc = {
FOR i: NAT IN [0..rct.size) DO
IF CoreGeometry.HasTrans[decoration, rct[i]] AND CoreGeometry.HasObject[decoration, rct[i].type] THEN {
IF CoreGeometry.GetTrans[decoration, rct[i]]=selectedInstance.trans AND ExtractOps.SameCDObject[selectedInstance.obj, CoreGeometry.GetObject[decoration, rct[i].type]] THEN {
quit ← eachSelectedCellInstance[i];
EXIT;
};
};
REPEAT FINISHED => ERROR CoreCDUserError["CoreCDUser: Some selected instance does not correspond to any cell type"];
ENDLOOP;
};
quit ← ExtractOps.EnumerateSelectedInstances[design, ThisSelectedInstance];
};
pushDataAtom: ATOM = $CoreCDUserPushData;
CellPushData: TYPE = REF CellPushDataRec;
CellPushDataRec: TYPE = RECORD [
decoration: CoreGeometry.Decoration ← NIL,
root: Core.CellType ← NIL,
cutSet: CoreFlat.CutSet ← NIL,
selectionData: RefTab.Ref ← NIL,
transitiveClosure: RefTab.Ref ← NIL,
viewer: ViewerClasses.Viewer ← NIL,
doesNotMatterDesign: CD.Design ← NIL,
designPushData: LIST OF DesignPushData ← NIL];
DesignPushData: TYPE = REF DesignPushDataRec;
DesignPushDataRec: TYPE = RECORD [
design: CD.Design ← NIL,
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: CD.Design ← NIL,
pushData: CellPushData ← NIL,
resolve: ResolveData ← NIL,
instance: NAT ← 0,
objects: LIST OF CoreGeometry.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: CD.Design, decoration: CoreGeometry.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["CoreCDUser: The object of the instance at the top of the push stack is not reachable from the root cell type"];
};
GetPushData: PROC [design: CD.Design, decoration: CoreGeometry.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: CD.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: CD.Design, root: Core.CellType, decoration: CoreGeometry.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 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;
};
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 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;
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: CD.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: CD.Design ← pushData.design;
instanceStack: LIST OF CD.Instance ← NIL;
pushData.errorMessage ← NIL;
pushData.cellPushData.doesNotMatterDesign ← design;
IF design.actual.rest=NIL THEN pushData.errorMessage ← "CoreCDUser: 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["CoreCDUser: 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: BOOL ← ExtractOps.SameCDObject[instances.first.ob, CoreGeometry.GetObject[pushData.cellPushData.decoration, cell]];
SELECT TRUE FROM
matchingObject AND instances.rest=NIL => {
cellType ← cell;
flatCellType ← flatCell;
};
CoreFlat.CutSetMemberResolved[flatCell, instance, cell, pushData.cellPushData.cutSet] => errorMessage ← "CoreCDUser: 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];
possibleInst: CoreGeometry.Instance ← [CoreGeometry.GetObject[pushData.cellPushData.decoration, thisInstance.type], CoreGeometry.GetTrans[pushData.cellPushData.decoration, thisInstance]];
IF ExtractOps.SameCDInstance[instances.rest.first, instances.first.trans, possibleInst] 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 ← "CoreCDUser: 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 ← "CoreCDUser: 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: CoreGeometry.Object ← NIL];
EnumerateLeastCommonObjectAncestors: PROC [design: CD.Design, 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, ignoreMeProp]=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
CoreFlat.CutSetMemberResolved[flatCell, instance, cell, cutSet] => NULL;
cell.class=CoreClasses.recordCellClass => {
rct: CoreClasses.RecordCellType ← NARROW[cell.data];
rctHasObject: BOOL ← CoreGeometry.HasObject[decoration, cell];
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;
ambiguousMultipath: BOOLTRUE;
WITH key SELECT FROM
o: CoreGeometry.Object => {
object ← o;
IF rctHasObject THEN ambiguousMultipath ← RefTab.Fetch[topObjects, object].found;
};
s: Core.CellType => {
subCell ← s;
ambiguousMultipath ← NOT CoreGeometry.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: ExtractOps.TopInstanceLists ← ExtractOps.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: CD.Design ← NIL, decoration: CoreGeometry.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 ← "CoreCDUser: 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: CD.Design ← NIL, decoration: CoreGeometry.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 ← "CoreCDUser: No cell type(s) found";
EXITS
Done => NULL;
};
IF errorMsg#NIL THEN TerminalIO.PutRopes[errorMsg, "\n"];
};
Start Code
wireHighlightClass CD.FetchObjectClass[wireHighlightProp];
IF wireHighlightClass=NIL THEN wireHighlightClass ← CD.RegisterObjectClass[wireHighlightProp, [drawMe: WireHighlightDrawMe, description: "WireHighlight"]]
ELSE wireHighlightClass.drawMe ← WireHighlightDrawMe;
CDEvents.RegisterEventProc[event: $AfterPush, proc: PushPop];
CDEvents.RegisterEventProc[event: $AfterPop, proc: PushPop];
END.