SinixHighlightImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Jean-Marc Frailong May 30, 1986 11:00:50 pm PDT
Bertrand Serlet June 1, 1986 3:42:11 pm PDT
DIRECTORY
CD, CDCells, CDDirectory, CDInstances, CDMenus, CDOps, CDProperties, CDRects, CDSequencer, CDViewer, CDViewHighlight,
Core, CoreClasses, CoreOps, CoreProperties,
HashTable,
IO,
Rope, Sinix, SinixHighlight,
TerminalIO, ViewerClasses;
SinixHighlightImpl:
CEDAR
PROGRAM
IMPORTS CDCells, CDDirectory, CDInstances, CDMenus, CDOps, CDProperties, CDRects, CDViewer, CDViewHighlight, CoreClasses, CoreOps, CoreProperties, HashTable, IO, Sinix, TerminalIO
EXPORTS SinixHighlight =
BEGIN
OPEN Core, SinixHighlight;
WireSet: TYPE ~ Core.Wires;
inboundProp: ATOM ← CoreProperties.RegisterProperty[$SinixInBinding, CoreProperties.Props[[CoreProperties.propPrint, CoreProperties.PropDontPrint]]];
outboundProp: ATOM ← CoreProperties.RegisterProperty[$SinixOutBinding, CoreProperties.Props[[CoreProperties.propPrint, CoreProperties.PropDontPrint]]];
Wire utilities
Add a wire to a set of wires.
AddWireToSet:
PROC [w: Wire, set: WireSet]
RETURNS [WireSet] ~
INLINE {
RETURN [IF CoreOps.Member[set, w] THEN set ELSE CONS[w, set]];
};
Merge a set of wires into another set of wires
MergeWiresSets:
PROC [set, into: WireSet]
RETURNS [WireSet]~ {
WHILE set#
NIL
DO
into ← AddWireToSet[set.first, into];
set ← set.rest;
ENDLOOP;
RETURN [into];
};
Return all the atomic wires referred to in the set uniquely
FlattenWires:
PROC [in: WireSet]
RETURNS [out: WireSet ←
NIL] ~ {
ForEachAtomicWire: PROC [wire: Wire] ~ { out ← AddWireToSet[wire, out]; };
WHILE in#
NIL
DO
wire: Wire = in.first;
IF wire.size=0 THEN out ← AddWireToSet[wire, out]
ELSE [] ← CoreOps.VisitAtomicWires[wire, ForEachAtomicWire];
in ← in.rest;
ENDLOOP;
};
Enumerate the parents relative to root of all elements of the list
FindParents:
PROC [set: WireSet, root: Wire]
RETURNS [parents: WireSet ←
NIL] ~ {
AddIfParent:
PROC [wire: Wire]
RETURNS [isParent:
BOOL ←
FALSE] ~ {
IF wire.size=0 THEN RETURN [CoreOps.Member[set, wire]];
FOR i:
INT
IN [0 .. wire.size)
DO
IF AddIfParent[wire.elements[i]] THEN isParent ← TRUE;
ENDLOOP;
IF isParent THEN parents ← AddWireToSet[wire, parents];
};
[] ← AddIfParent[root];
};
Create the hash tables that gives the match from actual to public and back. The wires are assumed to match...
CreateBindingTables:
PROC [inst: CoreClasses.CellInstance]
RETURNS [inBound, outBound: HashTable.Table] ~ {
EachPair: CoreOps.EachWirePairProc ~ {
wires: Wires;
[] ← HashTable.Insert[table: outBound, key: publicWire, value: actualWire];
wires ← NARROW [HashTable.Fetch[table: inBound, key: actualWire].value];
IF NOT CoreOps.Member[wires, actualWire] THEN wires ← CONS [publicWire, wires];
[] ← HashTable.Store[table: inBound, key: actualWire, value: wires];
};
actual: Wire = inst.actual; public: Wire = inst.type.public;
inBound ← HashTable.Create[];
outBound ← HashTable.Create[];
FOR i:
NAT
IN [0 .. actual.size)
DO
[] ← CoreOps.VisitBinding[actual: actual.elements[i], public: public.elements[i], eachWirePair: EachPair];
ENDLOOP;
CoreProperties.PutCellInstanceProp[on: inst, prop: inboundProp, value: inBound];
CoreProperties.PutCellInstanceProp[on: inst, prop: outboundProp, value: outBound];
};
Propagate a set of wires into a core instance
WireSetIntoInstance:
PROC [out: WireSet, inst: CoreClasses.CellInstance]
RETURNS [in: WireSet ←
NIL] ~ {
table: HashTable.Table ← NARROW [CoreProperties.GetCellInstanceProp[from: inst, prop: inboundProp]];
IF table=NIL THEN table ← CreateBindingTables[inst].inBound;
WHILE out#
NIL
DO
found: BOOLEAN; binding: HashTable.Value;
[found, binding] ← HashTable.Fetch[table: table, key: out.first];
IF found
THEN
FOR wires: Wires ←
NARROW[binding], wires.rest
WHILE wires#
NIL
DO
in ← AddWireToSet[wires.first, in];
ENDLOOP;
out ← out.rest;
ENDLOOP;
};
Propagate a set of wires from a core instance
WireSetFromInstance:
PROC [in: WireSet, inst: CoreClasses.CellInstance]
RETURNS [out: WireSet ←
NIL] ~ {
table: HashTable.Table ← NARROW [CoreProperties.GetCellInstanceProp[from: inst, prop: outboundProp]];
IF table=NIL THEN table ← CreateBindingTables[inst].outBound;
WHILE in#
NIL
DO
found: BOOLEAN; binding: HashTable.Value;
[found, binding] ← HashTable.Fetch[table: table, key: in.first];
IF found THEN out ← AddWireToSet[NARROW[binding], out];
in ← in.rest;
ENDLOOP;
};
CD coordinates utilities
Check that two CD instances are logically the same
SameCDInstance:
PROC [i,j:
CD.Instance]
RETURNS [
BOOL] ~
INLINE {
RETURN [i.ob=j.ob AND i.location=j.location AND i.orientation=j.orientation]
};
Given inInst and outInst in world coordinates, return instance of inInst if it were in outInst. The basics code for this is found in CDInstances.DeComposed
RelocateInInstance:
PROC [inInst, outInst:
CD.Instance]
RETURNS [
CD.Instance] ~ {
RETURN [CDInstances.DeComposed[inst: inInst, cellPos: outInst.location, cellSize: outInst.ob.size, cellOrient: outInst.orientation]];
};
Links between Core and ChipNDale
Given in, an instance in out, recover the celltype for out and the right instance for in in it.
InstanceInRecordCell:
PROC [in, out:
CD.Instance, mode: Sinix.Mode]
RETURNS [coreInst: CoreClasses.CellInstance ←
NIL, cell: CellType ←
NIL] ~ {
record: CoreClasses.RecordCellType;
wire: Wire; category: ATOM;
[cell, wire, category] ← Extract[out.ob, mode];
IF cell=
NIL
OR cell.class#CoreClasses.recordCellClass
THEN
BEGIN
TerminalIO.WriteF["*** Cell %g does not extract to record cell\n", IO.rope[CDDirectory.Name[out.ob]]];
RETURN;
END;
record ← NARROW [cell.data];
FOR i:
INT
IN [0 .. record.size)
DO
possibleInst: CD.Instance = Sinix.GetInstanceTransformationProp[mode, record[i]];
IF SameCDInstance[possibleInst, in] THEN {coreInst ← record[i]; EXIT};
ENDLOOP;
};
This is a local version of Sinix.Extract that always gets value from the cache, as the top cell is supposed to have been extracted.
Extract:
PROC [obj:
CD.Object, mode: Sinix.Mode]
RETURNS [cellType: CellType ←
NIL, wire: Wire ←
NIL, category:
ATOM ← $Device] ~ {
ref: REF ← CDProperties.GetObjectProp[obj, mode.cacheProp];
WITH ref
SELECT
FROM
ct: CellType => cellType ← ct;
w: Wire => {wire ← w; category ← $Wire};
ENDCASE => ERROR;
};
Generation of highlighted objects
Convert object to highlighted object
HighLightOb:
PROC [ob:
CD.Object]
RETURNS [hob:
CD.Object] = {
SELECT ob.class.objectType
FROM
$Rect => hob ← CDRects.CreateRect[ob.size, CD.shadeLayer];
$Cell => {
cellPtr, hcellPtr: CD.CellPtr;
hob ← CDCells.CreateEmptyCell[];
cellPtr ← NARROW [ob.specificRef];
hcellPtr ← NARROW [hob.specificRef];
hcellPtr.contents ← HighLightListInst[cellPtr.contents];
hob.size ← ob.size;
};
ENDCASE => {
hob ← CDDirectory.Expand[ob, NIL, NIL].new;
IF hob=NIL THEN RETURN[CDRects.CreateRect[ob.size, CD.undefLayer]];
hob ← HighLightOb[hob];
};
};
Convert instance to highlighted instance
HighLightInst:
PROC [inst:
CD.Instance]
RETURNS [hinst:
CD.Instance] = {
hinst ←
NEW [
CD.InstanceRep ← [
ob: IF inst.ob.class.objectType=$PinOb0 THEN CDRects.CreateRect[inst.ob.size, CD.shadeLayer] ELSE HighLightOb[inst.ob],
location: inst.location, orientation: inst.orientation]];
};
Convert instance list to highlighted instance list
HighLightListInst:
PROC [instances:
LIST
OF
CD.Instance]
RETURNS [hlist:
LIST
OF
CD.Instance ←
NIL] = {
WHILE instances#
NIL
DO
hlist ← CONS[HighLightInst[instances.first], hlist]; instances ← instances.rest;
ENDLOOP;
};
Create a single object relative to an instance that contains a list of highlighted instances
CreateHighlightInstance:
PROC [hinsts:
CD.InstanceList, in:
CD.Instance]
RETURNS [highlight:
CD.Instance ←
NIL] ~ {
IF hinsts#
NIL
THEN
BEGIN
hob: CD.Object ← CDCells.CreateEmptyCell[];
hcellPtr: CD.CellPtr ← NARROW [hob.specificRef];
hob.size ← in.ob.size;
hcellPtr.contents ← hinsts;
hcellPtr.simplifyOn ← 0.0;
highlight ← NEW [CD.InstanceRep ← [ob: hob, location: in.location, orientation: in.orientation, properties: NIL]];
END;
};
Locating selected things
Return all instances that are selected in the topmost pushed-in instance, in its local reference frame. Actually, only a copy of the instances is returned as cells pushed-in change their coordinate system in CD... If the cell has been modified, you may get garbage.
SelectedInstancesInTopPushedInstance:
PROC [design:
CD.Design]
RETURNS [selectedList:
CD.InstanceList ←
NIL] ~ {
closed: CD.Instance = design.actual.first.mightReplace;
open: CD.Instance = design.actual.first.dummyCell;
IF design.actual.rest=NIL THEN RETURN;
FOR list:
CD.InstanceList ←
NARROW [open.ob.specificRef,
CD.CellPtr].contents, list.rest
WHILE list#
NIL
DO
IF list.first.selected
THEN
selectedList ← CONS [RelocateInInstance[list.first, closed], selectedList];
ENDLOOP;
};
For all the selected instances in the currently pushed-in CD instance, find all wires that touch and return the set. For instances that extract to wire, explore against all wires internal to the cell to find the matching ones. For instances that extract to a device, include all the actuals for the instance.
SelectedWires:
PROC [mode: Sinix.Mode, design:
CD.Design]
RETURNS [cellType: CellType, wires: WireSet] ~ {
top: CD.Instance = design.actual.first.mightReplace;
wireList: WireSet ← NIL;
dummyWire: Wire; dummyCellType: CellType; category: ATOM;
rec: CoreClasses.RecordCellType;
[cellType, dummyWire, category] ← Extract[top.ob, mode];
IF cellType=
NIL
OR cellType.class#CoreClasses.recordCellClass
THEN
BEGIN
TerminalIO.WriteF["*** Extraction must return a record cell\n"];
RETURN;
END;
rec ← NARROW [cellType.data];
FOR selectedList:
CD.InstanceList ← SelectedInstancesInTopPushedInstance[design], selectedList.rest
WHILE selectedList#
NIL
DO
[dummyCellType, dummyWire, category] ← Extract[selectedList.first.ob, mode];
SELECT category
FROM
$Wire =>
BEGIN
-- Relocate the wire geometry inside the instance, connect to internals
TouchesWire: CoreOps.EachWireProc ~ {
FOR client:
CD.InstanceList ← Sinix.GetWireGeometryProp[mode,wire], client.rest
WHILE client#
NIL
DO
FOR list:
CD.InstanceList ← target, list.rest
WHILE list#
NIL
DO
IF SameCDInstance[list.first, client.first]
THEN {
wireList ← AddWireToSet[wire, wireList];
RETURN [quit: TRUE];
};
ENDLOOP;
ENDLOOP;
};
target:
CD.InstanceList ← CDInstances.ComposedList[
il: NARROW [Sinix.GetPinsProp[mode, dummyWire]],
cellPos: selectedList.first.location,
cellSize: selectedList.first.ob.size,
cellOrient: selectedList.first.orientation];
[] ← CoreOps.VisitWire[rec.internal, TouchesWire];
END;
$Device =>
BEGIN
-- Add all the actuals to the list of selected wires
sel: CoreClasses.CellInstance;
cell: CellType;
[sel, cell] ← InstanceInRecordCell[in: selectedList.first, out: top, mode: mode];
IF sel#
NIL
THEN
FOR i:
NAT
IN [0 .. sel.actual.size)
DO
wireList ← AddWireToSet[sel.actual.elements[i], wireList];
ENDLOOP;
END;
ENDCASE => {};
ENDLOOP;
wires ← FlattenWires[wireList];
};
Highlight wires top-down
Add to hinsts the highlight for all the requested wires, return new highlight list.
HighlightWires:
PROC [wires: WireSet, hinsts:
CD.InstanceList, mode: Sinix.Mode]
RETURNS [
CD.InstanceList] ~ {
WHILE wires#
NIL
DO
FOR l:
CD.InstanceList ← Sinix.GetWireGeometryProp[mode, wires.first], l.rest
WHILE l#
NIL
DO
hinsts ← CONS [HighLightInst[l.first], hinsts];
ENDLOOP;
wires ← wires.rest;
ENDLOOP;
RETURN [hinsts];
};
Add to hinsts the highlight for all the requested pins, return new highlight list.
HighlightPins:
PROC [wires: WireSet, hinsts:
CD.InstanceList, mode: Sinix.Mode]
RETURNS [
CD.InstanceList] ~ {
WHILE wires#
NIL
DO
FOR l:
CD.InstanceList ← Sinix.GetPinsProp[mode, wires.first], l.rest
WHILE l#
NIL
DO
hinsts ← CONS [HighLightInst[l.first], hinsts];
ENDLOOP;
wires ← wires.rest;
ENDLOOP;
RETURN [hinsts];
};
Return a CD Instance that is a highlight for the given list of wires in the cellType, which is exactly the extraction of the cdInst. Everything is explored downwards, except for the special instance cell from which the net originated (if applicable). Hinsts is a list of pre-built highlighted instances to be included in the final object. The CD instance is used to remap the highlighted object at the right location.
HighlightWiresDownwards:
PROC [cdInst:
CD.Instance, cell: CellType, wires: WireSet, except: CoreClasses.CellInstance ←
NIL, hinsts:
CD.InstanceList ←
NIL, mode: Sinix.Mode]
RETURNS [highlight:
CD.Instance ←
NIL] ~ {
IF wires#
NIL
THEN
DO
SELECT cell.class
FROM
CoreClasses.recordCellClass => {
rec: CoreClasses.RecordCellType ← NARROW[cell.data];
-- Highlight in included cells
FOR i:
NAT
IN [0 .. rec.size)
DO
coreInst: CoreClasses.CellInstance = rec.instances[i];
IF coreInst#except
THEN
BEGIN
highlight:
CD.Instance = HighlightWiresDownwards[
cdInst: Sinix.GetInstanceTransformationProp[mode, coreInst],
cell: coreInst.type,
wires: WireSetIntoInstance[wires, coreInst],
mode: mode];
IF highlight#NIL THEN hinsts ← CONS[highlight, hinsts];
END;
ENDLOOP;
-- Highlight atomic wires
hinsts ← HighlightWires[wires, hinsts, mode];
-- Highlight parents in record cell
hinsts ← HighlightWires[FindParents[wires, rec.internal], hinsts, mode];
EXIT;
};
CoreClasses.transistorCellClass,
CoreClasses.identityCellClass => {
hinsts ← HighlightPins[wires, hinsts, mode];
EXIT;
};
ENDCASE => cell ← CoreOps.Recast[cell];
ENDLOOP;
highlight ← CreateHighlightInstance[hinsts, cdInst];
};
Propagate selected wires to the top and highlight
Given the stack and a list of wires in the topmost cell, highlight locally then proceed upwards to obtain finally the completely highlighted net. As wire connectivity is computed by Sinix only on a bottom-up basis, bottom-up exploration does not work straightforwardly: wires that are connected only through an enclosing cell will not be detected correctly! Hence, the process consists of computing wire propagation to the top, then going down to merge propagations downwards, finally redisplaying up...
HighlightWiresUpwards:
PROC [stack:
LIST
OF
CD.PushRec, cell: CellType, wires: WireSet, mode: Sinix.Mode]
RETURNS [highlight:
CD.Instance] ~ {
HighlightContext: TYPE ~ REF HighlightContextRep;
HighlightContextRep:
TYPE ~
RECORD [
from: CoreClasses.CellInstance,
in: CD.Instance,
cell: CellType,
wires: WireSet];
request, initialRequest: LIST OF HighlightContext;
First, build initialRequest by unwinding the CD stack
currentInst: CD.Instance ← stack.first.mightReplace;
stack ← stack.rest;
initialRequest ← LIST [NEW[HighlightContextRep ← [NIL, currentInst, cell, wires]]];
WHILE stack.rest#
NIL
DO
previousInst: CD.Instance = currentInst;
previousCoreInst: CoreClasses.CellInstance;
currentInst ← stack.first.mightReplace;
[previousCoreInst, cell] ← InstanceInRecordCell[
in: RelocateInInstance[previousInst, currentInst],
out: currentInst,
mode: mode];
IF previousCoreInst=NIL THEN RETURN [NIL];
wires ← WireSetFromInstance[wires, previousCoreInst];
initialRequest ←
CONS [
NEW[HighlightContextRep ← [previousCoreInst, currentInst, cell, wires]],
initialRequest];
stack ← stack.rest;
ENDLOOP;
Now, build request from initialRequest by propagating wires down again
request ← NIL;
wires ← NIL;
WHILE initialRequest#
NIL
DO
currentRequest: HighlightContext = initialRequest.first;
IF wires#NIL THEN currentRequest.wires ← MergeWiresSets[wires, currentRequest.wires];
request ← CONS [currentRequest, request];
wires ← IF currentRequest.from#NIL THEN WireSetIntoInstance[currentRequest.wires, currentRequest.from] ELSE NIL;
initialRequest ← initialRequest.rest;
ENDLOOP;
Finally, do the highlighting from request
highlight ← HighlightWiresDownwards[cdInst: request.first.in, cell: request.first.cell, wires: request.first.wires, mode: mode];
request ← request.rest;
WHILE request#
NIL
DO
highlight ← HighlightWiresDownwards[
cdInst: request.first.in,
cell: request.first.cell,
wires: request.first.wires,
mode: mode,
except: request.first.from,
hinsts: LIST [RelocateInInstance[highlight, request.first.in]]];
request ← request.rest;
ENDLOOP;
};
The real thing
Go up the stack, extract the topmost instance. From now on, refer to extraction only by using the cache... Return TRUE if in error, FALSE if all is OK.
ExtractOuterInstance:
PROC [design:
CD.Design, context: ExtractContext]
RETURNS [
BOOL] ~ {
result: REF;
extractibleInstance: CD.Instance ← NIL;
FOR stack:
LIST
OF
CD.PushRec ← design.actual, stack.rest
WHILE stack.rest#
NIL
DO
IF stack.first.changed
THEN {
TerminalIO.WriteF["*** Impossible to highlight, cell %g has been changed and not saved\n", IO.rope[CDDirectory.Name[stack.first.mightReplace.ob]]];
RETURN [TRUE];
};
extractibleInstance ← stack.first.mightReplace;
ENDLOOP;
IF extractibleInstance=
NIL
THEN {
TerminalIO.WriteF["*** No currently pushed-in cell\n"];
RETURN[TRUE];
};
[result] ← Sinix.Extract[
obj: extractibleInstance.ob,
mode: context.mode,
properties: extractibleInstance.properties,
userData: context.userData];
IF
NOT
ISTYPE [result, CellType]
THEN
BEGIN
TerminalIO.WriteF["*** Top cell does not extract to device\n"];
RETURN[TRUE];
END;
RETURN[FALSE];
};
Recover the extract context from the technology, or from the key if not found in technology.
GetExtractContext:
PROC [command: CDSequencer.Command]
RETURNS [ExtractContext] ~ {
contextCreator: REF ExtractContextCreator;
contextCreator ← NARROW [CDProperties.GetProp[command.design.technology, command.key]];
IF contextCreator=NIL THEN contextCreator ← NARROW [CDProperties.GetProp[$Context, command.key]];
RETURN [IF contextCreator#NIL THEN contextCreator^[command.design] ELSE NIL]
};
DeepHighLightSelected:
PROC [command: CDSequencer.Command] ~ {
highlight: CD.Instance;
context: ExtractContext;
selWires: WireSet; inCell: CellType;
mode: Sinix.Mode;
context ← GetExtractContext[command];
IF context=
NIL
THEN
BEGIN
TerminalIO.WriteF["*** Command not supported for this technology\n"];
RETURN;
END;
mode ← context.mode;
IF ExtractOuterInstance[command.design, context] THEN RETURN;
[inCell, selWires] ← SelectedWires[mode, command.design];
IF selWires=
NIL
THEN
BEGIN
TerminalIO.WriteF["*** No wires selected\n"];
RETURN;
END;
highlight ← HighlightWiresUpwards[command.design.actual, inCell, selWires, mode];
IF highlight#
NIL
THEN
FOR viewers:
LIST
OF ViewerClasses.Viewer ← CDViewer.ViewersOf[command.design], viewers.rest
WHILE viewers#
NIL
DO
CDViewHighlight.ShowInstance[viewers.first, highlight];
ENDLOOP;
};
ExtractSelected:
PROC [command: CDSequencer.Command] = {
context: ExtractContext;
first: CD.Instance; multiple: BOOL;
result: REF;
context ← GetExtractContext[command];
[first, multiple] ← CDOps.SelectedInstance[command.design];
IF multiple THEN {TerminalIO.WriteF["Multiple instances selected. No action.\n"]; RETURN};
IF first=NIL THEN {TerminalIO.WriteF["No instance selected. No action.\n"]; RETURN};
[result] ← Sinix.Extract[first.ob, context.mode, first.properties, context.userData];
IF result=
NIL
THEN TerminalIO.WriteF["*** Extraction returned NIL\n"]
ELSE CoreOps.Print[result, TerminalIO.TOS[]];
};
Registration
RegisterOtherProgramWithContext:
PROC [program:
PROC [CDSequencer.Command], technology:
CD.Technology, contextCreator: ExtractContextCreator, prompt: Rope.
ROPE, key:
ATOM] ~ {
[] ← CDProperties.RegisterProperty[key, $HighlightProperty];
CDProperties.PutProp[IF technology#NIL THEN technology ELSE $Context, key, NEW [ExtractContextCreator ← contextCreator]];
CDMenus.ImplementEntryCommand[menu: $OtherProgramMenu, entry: prompt, p: program, key: key, technology: technology];
};
RegisterHighlightCommand:
PUBLIC
PROC [technology:
CD.Technology ←
NIL, contextCreator: ExtractContextCreator, prompt: Rope.
ROPE, key:
ATOM] ~ {
RegisterOtherProgramWithContext[DeepHighLightSelected, technology, contextCreator, prompt, key];
};
RegisterExtractCommand:
PUBLIC
PROC [technology:
CD.Technology ←
NIL, contextCreator: ExtractContextCreator, prompt: Rope.
ROPE, key:
ATOM] ~ {
RegisterOtherProgramWithContext[ExtractSelected, technology, contextCreator, prompt, key];
};
RegisterDefaultLayoutMode:
PUBLIC
PROC [technology:
CD.Technology, contextCreator: ExtractContextCreator] ~ {
IF technology=NIL THEN ERROR;
RegisterExtractCommand[technology, contextCreator, "Extract layout", $ExtractLayout];
RegisterHighlightCommand[technology, contextCreator, "Highlight net in layout", $HighlightNetInLayout];
};
END.