SchematicSimulation.mesa
Copyright Ó 1987 by Xerox Corporation. All rights reserved.
Barth, March 20, 1987 2:34:19 pm PST
DIRECTORY BitOps, CD, CDBasics, CDCells, CDCommandOps, CDDirectory, CDEvents, CDProperties, CDSequencer, Core, CoreClasses, CoreFlat, CoreGeometry, CoreOps, CoreProperties, HashTable, IntHashTable, IO, Ports, Rope, Rosemary, RosemaryUser, Sisyph, TerminalIO, TiogaButtons, ViewerClasses, ViewerOps;
SchematicSimulation: CEDAR PROGRAM
IMPORTS BitOps, CDBasics, CDCells, CDCommandOps, CDDirectory, CDEvents, CDProperties, CoreClasses, CoreFlat, CoreGeometry, CoreOps, CoreProperties, HashTable, IntHashTable, IO, Ports, Rope, Rosemary, RosemaryUser, Sisyph, TerminalIO, TiogaButtons, ViewerOps
= BEGIN
SchSimError: ERROR [msg: Rope.ROPE] = CODE;
SchSimDebug: BOOLFALSE;
DAUser
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],
CoreOps.WireBits[flatWire.wire]]]];
};
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.ROPENIL];
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 HashTable.Insert[table: enumeratedWires, key: flatWireRef, value: $Enumerated] THEN {
errorMsg ← action[display, flatWireRef];
someValueFound ← TRUE;
quit ← errorMsg#NIL;
};
};
display: RosemaryUser.RoseDisplay ← NARROW [CDProperties.GetDesignProp[command.design, $DAUserRoseDisplay]];
someValueFound: BOOLFALSE;
enumeratedWires: HashTable.Table ← HashTable.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"];
};
SinixOps
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,
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: HashTable.Table ← NIL,
transitiveClosure: HashTable.Table ← NIL,
cellType: Core.CellType ← NIL,
flatCellType: CoreFlat.FlatCellTypeRec ← [],
errorMessage: Rope.ROPENIL];
CreateSelectionViewer: PROC [design: CD.Design, pushedData: PushedData, root: Core.CellType, decoration: CoreGeometry.Decoration, cutSet: CoreFlat.CutSet ← NIL] RETURNS [selectionData: HashTable.Table ← NIL, transitiveClosure: HashTable.Table ← NIL] = {
RecordEachAncestor: EachLeastCommonObjectAncestorProc = {
resolveData: ResolveData ← NARROW[HashTable.Fetch[selectionData, ancestor].value];
instanceData: InstanceData ← NIL;
IF resolveData=NIL THEN {
resolveData ← NEW[ResolveDataRec];
IF NOT HashTable.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 ← HashTable.Create[];
transitiveClosure ← EnumerateLeastCommonObjectAncestors[root, decoration, RecordEachAncestor, cutSet];
FOR resolveList: LIST OF ResolveData ← resolvers, resolveList.rest UNTIL resolveList=NIL DO
FindType: IntHashTable.EachPairAction = {
IF HashTable.Insert[table: finishedSubCells, key: data[key].type, value: $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: HashTable.Table ← HashTable.Create[];
firstChoice: BOOLTRUE;
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[" ", CDDirectory.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: BOOLFALSE;
multiple: BOOLFALSE;
inst: NATLAST[NAT];
FOR i: NAT IN [0..rct.size) DO
subCellTable: HashTable.Table ← NARROW[HashTable.Fetch[ pushedData.transitiveClosure, rct[i].type].value];
IF HashTable.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[HashTable.Fetch[pushedData.selectionData, cell].value];
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 HashTable.Pairs[pushedData.selectionData, SetDoesNotMatter] THEN ERROR;
BuildFlatCell[cell: pushedData.root, instances: instanceStack];
IF pushedData.errorMessage=NIL THEN IF HashTable.Pairs[pushedData.selectionData, DisplayDoesNotMatter] THEN ERROR;
EXITS Quit => NULL;
};
RecomputePushedCellType: PROC [design: CD.Design, pushedData: PushedData] = {
FilterSelections: EachSelectedFlatCellTypeProc = {
IF FilterUsingSelectionData[pushedData.root, flatCellType, pushedData.selectionData, instanceSelections] THEN {
IF alreadyCalled THEN {
quit ← TRUE;
pushedData.errorMessage ← "*** Selection data not enough to pick a flat cell.";
}
ELSE {
alreadyCalled ← TRUE;
pushedData.errorMessage ← NIL;
pushedData.cellType ← cellType;
pushedData.flatCellType ← flatCellType;
};
};
};
alreadyCalled: BOOLFALSE;
IF NOT EnumerateCellTypesForPushed[design, pushedData.decoration, pushedData.root, pushedData.cutSet, FilterSelections ! SchSimError => {pushedData.errorMessage ← msg; GOTO Quit}] THEN IF NOT alreadyCalled THEN pushedData.errorMessage ← "*** Selection data picks no cell.";
EXITS Quit => NULL;
};
FilterUsingSelectionData: PROC [root: Core.CellType, flatCell: CoreFlat.FlatCellTypeRec, selectionData: HashTable.Table, instanceSelections: HashTable.Table] RETURNS [pass: BOOLFALSE] = {
CheckSelection: CoreFlat.UnboundFlatCellProc = {
SELECT TRUE FROM
CoreFlat.FlatCellTypeEqualRec[flatCell, target] => pass ← TRUE;
cell.class=CoreClasses.recordCellClass => {
resolveData: ResolveData ← NARROW[HashTable.Fetch[selectionData, cell].value];
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 BOOLALL [FALSE];
thisIndex: NAT ← 0;
found: BOOLFALSE;
instanceSelect: InstanceSelectionData ← NARROW[HashTable.Fetch[instanceSelections, cell].value];
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 HashTable.Pairs[selectionData, SetDoesNotMatter] THEN ERROR;
CheckSelection[cell: root, target: flatCell];
IF pass THEN IF HashTable.Pairs[selectionData, DisplayDoesNotMatter] THEN ERROR;
};
SetDoesNotMatter: HashTable.EachPairAction = {
resolveData: ResolveData ← NARROW[value];
resolveData.doesNotMatter ← TRUE;
};
DisplayDoesNotMatter: HashTable.EachPairAction = {
resolveData: ResolveData ← NARROW[value];
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: HashTable.Table ← NIL] = {
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 HashTable which then maps Object or CellType to $DependsOn or REF NAT.
ComputeCellObjectDependence: PROC [cell: Core.CellType, flatCell: CoreFlat.FlatCellTypeRec ← CoreFlat.rootCellType, instance: CoreClasses.CellInstance ← NIL] RETURNS [cellObjects: HashTable.Table] = {
cellObjects ← NARROW[HashTable.Fetch[transitiveClosure, cell].value];
IF cellObjects=NIL THEN {
cellObjects ← HashTable.Create[];
IF CoreProperties.GetCellTypeProp[cell, $DAUserIgnoreForSelection]=NIL THEN {
IF NOT HashTable.Insert[cellObjects, cell, $DependsOn] THEN ERROR;
IF cell.class#CoreClasses.transistorCellClass AND CoreGeometry.HasObject[decoration, cell] THEN IF NOT HashTable.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: HashTable.EachPairAction = {
subCell: Core.CellType ← NIL;
object: CoreGeometry.Object ← NIL;
IF NOT HashTable.Insert[cellObjects, key, NEW[NAT ← i]] THEN {
firstInstance: REF ANY ← HashTable.Fetch[cellObjects, key].value;
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];
[] ← HashTable.Store[cellObjects, key, $DependsOn];
};
eachLeastCommonAncestor[cell, i, subCell, object];
};
};
subCellObjects: HashTable.Table ← ComputeCellObjectDependence[rct[i].type, [CoreFlat.ExtendPath[flatCell.path, i, rct], 0], rct[i]];
IF HashTable.Pairs[subCellObjects, InsertRecordSubObject] THEN ERROR;
ENDLOOP;
};
ENDCASE => {
InsertOtherSubObject: HashTable.EachPairAction = {
[] ← HashTable.Store[cellObjects, key, $DependsOn];
};
new: Core.CellType ← CoreOps.Recast[cell];
recastCellObjects: HashTable.Table ← IF cell=new THEN ComputeCellObjectDependence[cell, flatCell, instance] ELSE ComputeCellObjectDependence[new, [flatCell.path, flatCell.recastCount+1], instance];
IF HashTable.Pairs[recastCellObjects, InsertOtherSubObject] THEN ERROR;
};
};
IF NOT HashTable.Insert[transitiveClosure, cell, cellObjects] THEN ERROR;
};
};
transitiveClosure ← HashTable.Create[];
[] ← ComputeCellObjectDependence[root];
};
EachSelectedFlatWireProc: TYPE = PROC [selectedFlatWire: CoreFlat.FlatWireRec] RETURNS [quit: BOOLFALSE];
EnumerateSelectedFlatWires: PROC [design: CD.Design, decoration: CoreGeometry.Decoration, root: Core.CellType, cutSet: CoreFlat.CutSet ← NIL, eachSelectedFlatWire: EachSelectedFlatWireProc] RETURNS [quit: BOOLFALSE] = {
ThisSelectedWire: EachSelectedWireProc = {
quit ← eachSelectedFlatWire[[
flatCell: flatCell,
wireRoot: IF publicWire THEN public ELSE internal,
wire: selectedWire]];
};
publicWire: BOOLFALSE;
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: BOOLFALSE;
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: HashTable.Table] RETURNS [quit: BOOLFALSE];
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: BOOLFALSE] = {
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[HashTable.Fetch[instanceSelections, parent].value];
IF selectionData=NIL THEN {
selectionData ← NEW[InstanceSelectionDataRec];
IF NOT HashTable.Insert[instanceSelections, parent, selectionData] THEN ERROR;
};
};
instanceStack: LIST OF CD.Instance ← UnwindCDStack[design];
instanceSelections: HashTable.Table ← HashTable.Create[];
EnumerateCellTypes[cell: root, data: instanceStack ! UnwindEnumeration => GOTO Quit];
EXITS Quit => quit ← TRUE;
};
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: 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];
};
quit ← CoreOps.VisitWire[root, ThisWire]
};
quit ← EnumerateSelectedInstances[design, ThisSelectedInstance];
};
EachSelectedInstanceProc: TYPE = PROC [selectedInstance: CoreGeometry.Instance] RETURNS [quit: BOOLFALSE];
EnumerateSelectedInstances: PROC [design: CD.Design, eachInstance: EachSelectedInstanceProc] RETURNS [quit: BOOLFALSE] = {
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[CDDirectory.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];
CDEvents.RegisterEventProc[event: $AfterPush, proc: PushPop];
CDEvents.RegisterEventProc[event: $AfterPop, proc: PushPop];
END.