PipalConnectImpl.mesa
Copyright Ó 1988 by Xerox Corporation. All rights reserved.
Created by Bertrand Serlet, March 18, 1988 5:38:12 pm PST
Bertrand Serlet April 24, 1988 7:09:04 pm PDT
DIRECTORY
Basics, BasicTime, CedarProcess, IO, List, MessageWindow,
Pipal, PipalConnect, PipalInstanceTable, PipalInt, PipalMos,
Process, RefTab, TerminalIO;
PipalConnectImpl: CEDAR PROGRAM
IMPORTS Basics, BasicTime, CedarProcess, IO, List, MessageWindow, Pipal, PipalInstanceTable, PipalInt, PipalMos, Process, RefTab, TerminalIO
EXPORTS PipalConnect
~ BEGIN OPEN PipalConnect;
Short Cuts
ROPE: TYPE = Pipal.ROPE;
Object: TYPE = Pipal.Object;
Objects: TYPE = Pipal.Objects;
Transformation: TYPE = PipalInt.Transformation;
Rectangle: TYPE = PipalInt.Rectangle;
Connector Type
GetType: PUBLIC GetTypeProc = {
refProc: REF GetTypeProc ← NARROW [Pipal.ObjectMethod[object, mode.getTypeMethod]];
type ← (IF refProc=NIL THEN EnumerationType ELSE refProc^)[object, mode];
};
EnumerationType: PUBLIC GetTypeProc = {
nbChildren: NAT ← PipalInt.CountChildren[object];
EachChild: PipalInt.EachChildProc = {type ← GetType[child, mode]};
IF nbChildren=0 THEN RETURN [null];
IF nbChildren#1 THEN RETURN [composite];
[] ← PipalInt.Enumerate[object, EachChild];
};
NullType: PUBLIC GetTypeProc = {type ← null};
LeafType: PUBLIC GetTypeProc = {type ← leaf};
CompositeType: PUBLIC GetTypeProc = {type ← composite};
Ports Enumeration
EnumeratePorts: PUBLIC EnumeratePortsProc = {
refProc: REF EnumeratePortsProc ← NARROW [Pipal.ObjectMethod[object, mode.enumeratePortsMethod]];
IF GetType[object, mode]=null THEN SIGNAL CallerBug[];
quit ← (IF refProc=NIL THEN EnumerationEnumeratePorts ELSE refProc^)[object, mode, privateArea, eachPort, transformation];
};
CountPorts: PUBLIC PROC [object: Pipal.Object, mode: Mode, privateArea: PipalInt.Rectangle] RETURNS [count: NAT ← 0] = {
EachPort: EachPortProc = {
IF port=Pipal.void THEN SIGNAL InternalBug[]; count ← count + 1;
};
[] ← EnumeratePorts[object, mode, privateArea, EachPort];
};
EnumerationEnumeratePorts: PUBLIC EnumeratePortsProc = {
singleChild: Object ← NIL;
trans: Transformation;
EachChild: PipalInt.EachChildProc = {singleChild ← child; trans ← transformation};
IF PipalInt.CountChildren[object]#1 THEN SIGNAL CallerBug[];
[] ← PipalInt.Enumerate[object, EachChild, transformation];
quit ← EnumeratePorts[singleChild, mode, privateArea, eachPort, trans];
};
ComposerEnumeratePorts: PUBLIC EnumeratePortsProc = {
cc: Composer ← GetComposer[object, mode, privateArea];
FOR i: NAT IN [0 .. cc.ports.size) DO
quit ← eachPort[transformation, i, cc.ports[i]];
IF quit THEN RETURN;
ENDLOOP;
};
AtomicEnumeratePorts: PUBLIC EnumeratePortsProc = {
quit ← eachPort[transformation, 0, object];
};
BiAtomicEnumeratePorts: PUBLIC EnumeratePortsProc = {
EachRectLayer: PipalMos.EachRectangleLayerProc = {
box: Object ← PipalInt.TransformObject[[rect.base], PipalMos.CreateBox[rect.size, layer]];
IF PipalMos.IsWellLayer[layer]
THEN well ← CONS [box, well]
ELSE nonWell ← CONS [box, nonWell];
};
nonWell: Pipal.Objects ← NIL;
well: Pipal.Objects ← NIL;
[] ← PipalMos.EnumerateRectangleLayers[object: object, each: EachRectLayer];
IF well=NIL OR nonWell=NIL THEN SIGNAL InternalBug[];
quit ← eachPort[transformation, 0, Pipal.CreateOv[nonWell]] OR eachPort[transformation, 1, Pipal.CreateOv[well]];
};
TNodes
TNode: TYPE = REF TNodeRec; -- T stands for temporary
TNodeRec: TYPE = RECORD [
edgeObjects: Objects ← NIL,
bindings: LIST OF Binding ← NIL
];
CreateTNode: PROC [fused: RefTab.Ref] RETURNS [tNode: TNode] = {
tNode ← NEW [TNodeRec];
[] ← RefTab.Store[fused, tNode, NIL];
};
The following PROC implements Fisher-Galler fusion, not for efficiency, but for simplicity
RootTNode: PROC [fused: RefTab.Ref, tNode: TNode] RETURNS [rootTNode: TNode] = {
IF tNode=NIL THEN SIGNAL InternalBug[];
rootTNode ← NARROW [RefTab.Fetch[fused, tNode].val];
IF rootTNode=NIL THEN RETURN [tNode];
IF rootTNode=tNode THEN SIGNAL InternalBug[];
rootTNode ← RootTNode[fused, rootTNode];
[] ← RefTab.Replace[fused, tNode, rootTNode];
};
FuseTNodes: PROC [fused: RefTab.Ref, loser, winner: TNode] RETURNS [TNode] = {
loser ← RootTNode[fused, loser];
winner ← RootTNode[fused, winner];
IF loser=winner THEN RETURN [winner];
[] ← RefTab.Store[fused, loser, winner];
FOR list: Objects ← loser.edgeObjects, list.rest WHILE list#NIL DO
winner.edgeObjects ← CONS [list.first, winner.edgeObjects];
ENDLOOP;
FOR list: LIST OF Binding ← loser.bindings, list.rest WHILE list#NIL DO
winner.bindings ← CONS [list.first, winner.bindings];
ENDLOOP;
RETURN [winner];
};
EnumerateTNodes: PROC [fused: RefTab.Ref, each: PROC [TNode]] = {
EachPair: RefTab.EachPairAction = {IF val=NIL THEN each[NARROW [key]]};
[] ← RefTab.Pairs[fused, EachPair];
};
TTNode: TYPE = REF TTNodeRec;
TTNodeRec: TYPE = RECORD [edgeObjects: Objects, bindings: LIST OF REF];
bindings in a LORA for convenience, but denotes sorted list of bindings
CompareBinding: List.CompareProc = {
rb1: REF Binding = NARROW [ref1];
rb2: REF Binding = NARROW [ref2];
RETURN [IF rb1.childIndex=rb2.childIndex THEN Basics.CompareInt[rb1.nodeIndex, rb2.nodeIndex] ELSE Basics.CompareInt[rb1.childIndex, rb2.childIndex]];
};
CompareTTNodes: List.CompareProc = {
comparison: Basics.Comparison ← equal;
ttn1: TTNode = NARROW [ref1];
ttn2: TTNode = NARROW [ref2];
bindings1: LIST OF REF ← ttn1.bindings;
bindings2: LIST OF REF ← ttn2.bindings;
WHILE comparison=equal DO
IF bindings1=NIL THEN RETURN [less];
IF bindings2=NIL THEN RETURN [greater];
comparison ← CompareBinding[bindings1.first, bindings2.first];
bindings1 ← bindings1.rest; bindings2 ← bindings2.rest;
ENDLOOP;
RETURN [comparison];
};
CreateNode: PROC [ttNode: TTNode] RETURNS [node: Node] = {
bindings: LIST OF REF ← ttNode.bindings;
size: NAT ← List.Length[bindings];
node ← NEW [NodeRec[size]];
FOR i: NAT IN [0 .. size) DO
node[i] ← NARROW [bindings.first, REF Binding]^; bindings ← bindings.rest;
ENDLOOP;
IF bindings#NIL THEN SIGNAL InternalBug[];
};
in order to enumerate ports in the same order, it is important to sort nodes.
MakeComposer: PROC [fused: RefTab.Ref, object: Object, privateArea: Rectangle] RETURNS [cc: Composer] = {
portsSize, nodesSize, index: NAT ← 0;
ttNodes: LIST OF REFNIL;
CountNodes: PROC [tNode: TNode] = {
lora: LIST OF REFNIL;
ttNode: TTNode ← NEW [TTNodeRec];
nodesSize ← nodesSize + 1;
IF tNode.edgeObjects#NIL THEN portsSize ← portsSize + 1;
FOR bb: LIST OF Binding ← tNode.bindings, bb.rest WHILE bb#NIL DO
lora ← CONS [NEW [Binding ← bb.first], lora];
ENDLOOP;
ttNode.edgeObjects ← tNode.edgeObjects;
ttNode.bindings ← List.Sort[lora, CompareBinding];
ttNodes ← CONS [ttNode, ttNodes];
};
EnumerateTNodes[fused, CountNodes];
cc ← NEW [ComposerRec[nodesSize]]; cc.object ← object;
cc.ports ← NEW [PortsSequence[portsSize]];
ttNodes ← List.Sort[ttNodes, CompareTTNodes];
FOR list: LIST OF REF ← ttNodes, list.rest WHILE list#NIL DO
ttNode: TTNode ← NARROW [list.first];
IF ttNode.edgeObjects=NIL THEN LOOP; -- we first only deal with publics
cc[index] ← CreateNode[ttNode];
cc.ports[index] ← PipalMos.CreateClipEnum[privateArea, Pipal.CreateOv[ttNode.edgeObjects]];
index ← index+1;
ENDLOOP;
IF index#portsSize THEN SIGNAL InternalBug[];
FOR list: LIST OF REF ← ttNodes, list.rest WHILE list#NIL DO
ttNode: TTNode ← NARROW [list.first];
IF ttNode.edgeObjects#NIL THEN LOOP; -- we now only deal with the internal only
cc[index] ← CreateNode[ttNode];
index ← index+1;
ENDLOOP;
IF index#nodesSize THEN SIGNAL InternalBug[];
};
Multi-Layers InstanceTable
DefaultObjectLayer: PUBLIC PROC [Object] RETURNS [LayerRange] = {RETURN [[0, 0]]};
LayeredTable: TYPE = REF LayeredTableRec;
LayeredTableRec: TYPE = RECORD [
objectLayer: PROC [Pipal.Object] RETURNS [LayerRange],
rects: SEQUENCE nbOfLayers: NAT OF PipalInstanceTable.Table -- Association (per layer) [fusion geometry -> tNode]. TNode may or may not be a root.
];
LayeredTableCreate: PROC [object: Object, nbOfLayers: NAT, objectLayer: PROC [Pipal.Object] RETURNS [LayerRange]] RETURNS [table: LayeredTable] = {
bbox: Rectangle ← PipalInt.BBox[object, []];
table ← NEW [LayeredTableRec[nbOfLayers]];
FOR i: NAT IN [0 .. nbOfLayers) DO table[i] ← PipalInstanceTable.Create[bbox] ENDLOOP;
table.objectLayer ← IF objectLayer=NIL THEN DefaultObjectLayer ELSE objectLayer;
};
LayeredTableInsert: PROC [table: LayeredTable, transformation: Transformation, geometry: Object, tNode: TNode] = {
layers: LayerRange ← table.objectLayer[geometry];
FOR i: NAT IN [layers.min .. layers.max] DO
PipalInstanceTable.Insert[table[i], transformation, geometry, tNode];
ENDLOOP;
};
LayeredTableErase: PROC [table: LayeredTable] = {
FOR i: NAT IN [0 .. table.nbOfLayers) DO
PipalInstanceTable.DeleteOutside[table[i], PipalInt.emptyRectangle];
ENDLOOP;
};
Auxiliary Fusion functions
FusionData: TYPE = REF FusionDataRec;
FusionDataRec: TYPE = RECORD [
mode: Mode,      -- to avoid passing it around
privateArea: Rectangle,   -- Rectangles for which geometry that is strictly inside (edge excluded) is not promoted public
fused: RefTab.Ref,    -- Association [fused -> root] [TNode -> TNode]. If root=NIL, then this tNode is a root. Basically all the wires ever created belong to this table.
rects: LayeredTable    -- Association (per layer) [fusion geometry -> tNode]. TNode may or may not be a root.
];
rect: PROC [r: Rectangle] RETURNS [IO.Value] = {
RETURN [IO.rope[PipalInt.RectangleToRope[r]]];
};
IsGeometryAtEdge: PROC [privateArea: Rectangle, transformation: Transformation, geometry: Object] RETURNS [BOOL] = {
IsAtEdge: PipalInt.EachChildProc = {quit ← PipalInt.AtEdge[privateArea, transformation, child]};
RETURN [PipalMos.EnumerateAtomic[geometry, IsAtEdge, transformation]];
};
binding indicates if this geometry is only going to be used for fusion and does not have to figure in the geometry and pins properties (real geometry versus geometry at the level below).
InsertGeometry: PROC [fusionData: FusionData, transformation: Transformation, geometry: Object, tNode: TNode, binding: Binding] = {
IF ~RefTab.Fetch[fusionData.fused, tNode].found THEN SIGNAL InternalBug[];
IF RootTNode[fusionData.fused, tNode]#tNode THEN SIGNAL InternalBug[];
IF geometry=Pipal.void THEN SIGNAL InternalBug[];
LayeredTableInsert[fusionData.rects, transformation, geometry, tNode];
If a pin is found we just note that this is a public tNode
IF IsGeometryAtEdge[fusionData.privateArea, transformation, geometry] THEN
tNode.edgeObjects ← CONS [PipalInt.TransformObject[transformation, geometry], tNode.edgeObjects];
tNode.bindings ← CONS [binding, tNode.bindings];
};
FusionGeometry: PROC [fusionData: FusionData, transformation: Transformation, geometry: Object, binding: Binding] RETURNS [tNode: TNode ← NIL] = {
layers: LayerRange ← fusionData.rects.objectLayer[geometry];
rect: Rectangle ← PipalInt.BBox[geometry, transformation];
FindTouchingWires: PROC [trans: PipalInt.Transformation, geom: Pipal.Object, value: PipalInstanceTable.Value] = {
thisTNode: TNode ← RootTNode[fusionData.fused, NARROW [value]];
IF ~RefTab.Fetch[fusionData.fused, thisTNode].found THEN SIGNAL InternalBug[];
IF thisTNode=tNode THEN RETURN;
IF NOT fusionData.mode.touch[fusionData.mode.touch, trans, geom, transformation, geometry] THEN RETURN;
IF tNode=NIL THEN tNode ← thisTNode ELSE tNode ← FuseTNodes[fusionData.fused, thisTNode, tNode];
};
FOR i: NAT IN [layers.min .. layers.max] DO
PipalInstanceTable.Enumerate[fusionData.rects[i], FindTouchingWires, rect];
ENDLOOP;
IF tNode=NIL THEN tNode ← CreateTNode[fusionData.fused];
InsertGeometry[fusionData, transformation, geometry, tNode, binding];
};
Connectize
debugCache: BOOLFALSE;
composerCache: Pipal.ObjectCache ← Pipal.CreateObjectCache[];
Maps object -> LIST OF CacheData
CacheData: TYPE = RECORD [
mode: Mode, privateArea: PipalInt.Rectangle,
cc: Composer
];
Searches the cache. cc=NIL if not in cache
SearchCache: PROC [object: Object, mode: Mode, privateArea: PipalInt.Rectangle] RETURNS [cc: Composer ← NIL] = {
IF debugCache THEN RETURN;
FOR list: LIST OF CacheData ← NARROW [RefTab.Fetch[composerCache, object].val], list.rest WHILE list#NIL DO
IF list.first.mode=mode AND list.first.privateArea=privateArea
THEN RETURN [list.first.cc];
ENDLOOP;
};
We fill the cache
AddInCache: PROC [object: Object, mode: Mode, privateArea: PipalInt.Rectangle, cc: Composer] = {
cache: LIST OF CacheData ← NARROW [RefTab.Fetch[composerCache, object].val];
cache ← CONS [[mode: mode, privateArea: privateArea, cc: cc], cache];
[] ← RefTab.Store[composerCache, object, cache];
};
GetComposer: PUBLIC GetComposerProc = {
priority: CedarProcess.Priority ← CedarProcess.GetPriority[];
refProc: REF GetComposerProc ← NARROW [Pipal.ObjectMethod[object, mode.getComposerMethod]];
cc ← SearchCache[object, mode, privateArea];
IF cc#NIL THEN RETURN;
CedarProcess.CheckAbort[];
CedarProcess.SetPriority[background];
Process.Yield[];
IF GetType[object, mode]#composite THEN SIGNAL CallerBug[];
cc ← (IF refProc=NIL THEN EnumerationComposer ELSE refProc^)[object, mode, privateArea];
AddInCache[object, mode, privateArea, cc];
CedarProcess.SetPriority[priority];
};
unnecessary, but let's keep it for now. Bogus for AbutBoxAnnotation because the nodes number are the one of the child not the ones of the annotation.
GetNodeGeometry: PROC [object: Pipal.Object, mode: Mode, node: Node] RETURNS [geometry: Object] = {
index: NAT ← 0;
objects: Objects ← NIL;
bindingIndex: NAT ← 0;
EachChild: PipalInt.EachChildProc = {
SELECT GetType[child, mode] FROM
null    => {};
leaf, composite => {
EachPort: EachPortProc = {
IF port=Pipal.void THEN SIGNAL InternalBug[];
IF bindingIndex=node.size OR node[bindingIndex].childIndex>index THEN RETURN [TRUE]; -- unnecessary to continue!
IF node[bindingIndex].childIndex<index THEN SIGNAL InternalBug[];
IF node[bindingIndex].nodeIndex<portIndex THEN SIGNAL InternalBug[];
IF node[bindingIndex].nodeIndex=portIndex THEN {
objects ← CONS [PipalInt.TransformObject[transformation, port], objects];
bindingIndex ← bindingIndex + 1;
};
};
quit ← EnumeratePorts[child, mode, PipalInt.AbutBox[child], EachPort, transformation] AND bindingIndex=node.size;
};
ENDCASE    => SIGNAL InternalBug[];
index ← index + 1;
};
IF NOT PipalInt.Enumerate[object, EachChild] AND bindingIndex#node.size THEN SIGNAL InternalBug[];
geometry ← Pipal.CreateOv[objects];
};
Overlay/Enumerate and Abut Connectizeion
EnumerationComposer: PUBLIC GetComposerProc = {
index: NAT ← 0;
EachChild: PipalInt.EachChildProc = {
SELECT GetType[child, mode] FROM
null    => {};
leaf, composite => {
EachPort: EachPortProc = {
IF port=Pipal.void THEN SIGNAL InternalBug[];
[] ← FusionGeometry[fusionData, transformation, port, [index, portIndex]];
};
[] ← EnumeratePorts[child, mode, PipalInt.AbutBox[child], EachPort, transformation];
};
ENDCASE    => SIGNAL InternalBug[];
index ← index + 1;
};
fusionData: FusionData ← NEW [FusionDataRec ← [
mode: mode, privateArea: privateArea, fused: RefTab.Create[3],
rects: LayeredTableCreate[object, mode.nbOfLayers, mode.objectLayer]
]];
time: BasicTime.GMT = BasicTime.Now[];
PutF[
"Connectizeing [%g] cell (bbox: %g)\n",
IO.rope[mode.name],
rect[PipalInt.BBox[object, []]]];
[] ← PipalInt.Enumerate[object, EachChild];
cc ← MakeComposer[fusionData.fused, object, privateArea];
LayeredTableErase[fusionData.rects];
PutF["Connectizeed [%g] cell (%g instances, %g sec.)\n", IO.rope[mode.name], IO.int[index], IO.int[BasicTime.Period[time, BasicTime.Now[]]]];
};
AbutComposer: PUBLIC GetComposerProc = {
abut: PipalInt.Abut ← NARROW [object];
fusionData: FusionData ← NEW [FusionDataRec ← [
mode: mode, privateArea: privateArea, fused: RefTab.Create[3],
rects: LayeredTableCreate[object, mode.nbOfLayers, mode.objectLayer]
]];
nextRects: LayeredTable ← LayeredTableCreate[object, mode.nbOfLayers, mode.objectLayer];
index: NAT ← 0;
time: BasicTime.GMT = BasicTime.Now[];
EachChild: PipalInt.EachChildProc = {
SELECT GetType[child, mode] FROM
null    => {};
leaf, composite => {
EachPort: EachPortProc = {
tNode: TNode ← FusionGeometry[fusionData, transformation, port, [index, portIndex]];
IF port=Pipal.void THEN SIGNAL InternalBug[];
LayeredTableInsert[nextRects, transformation, port, tNode];
};
[] ← EnumeratePorts[child, mode, PipalInt.AbutBox[child], EachPort, transformation];
FOR i: NAT IN [0 .. mode.nbOfLayers) DO
table: PipalInstanceTable.Table ← fusionData.rects[i];
fusionData.rects[i] ← nextRects[i]; nextRects[i] ← table;
PipalInstanceTable.DeleteOutside[table, PipalInt.emptyRectangle];
ENDLOOP;
};
ENDCASE    => SIGNAL InternalBug[];
index ← index + 1;
};
PutF["Connectizeing [%g] abut (instances: %g)\n", IO.rope[mode.name], IO.int[abut.size]];
The main loop over "instances". Attention, we are assuming here that we are seing instances from left to right and bottom to top
[] ← PipalInt.Enumerate[object, EachChild];
cc ← MakeComposer[fusionData.fused, object, privateArea];
LayeredTableErase[fusionData.rects];
LayeredTableErase[nextRects];
PutF["Connectizeed [%g] abut (%g instances, %g sec.)\n", IO.rope[mode.name], IO.int[index], IO.int[BasicTime.Period[time, BasicTime.Now[]]]];
};
RoutingComposer: PUBLIC GetComposerProc = {
routing: PipalMos.Routing = NARROW [object];
bbox: Rectangle = PipalInt.BBox[routing, []];
PutF["Connectizeing [%g] routing (nodes: %g)\n", IO.rope[mode.name], IO.int[routing.size]];
We check if none of the objects contains well, and expand if not
FOR i: NAT IN [0 .. routing.size) DO
IF PipalMos.ContainsWell[routing[i]] THEN RETURN GetComposer[object, mode, privateArea]
ENDLOOP;
cc ← NEW [ComposerRec[routing.size]];
cc.object ← object;
cc.ports ← NEW [PortsSequence[routing.size]];
FOR i: NAT IN [0 .. routing.size) DO
node: Node ← NEW [NodeRec[1]];
cc.ports[i] ← PipalMos.CreateClipEnum[bbox, routing[i]];
cc[i] ← node; node[0] ← [i, 0];
ENDLOOP;
};
TileInstanceArray: TYPE = REF TileInstanceArrayRec;
TileInstanceArrayRec: TYPE = RECORD [c: SEQUENCE sizeY: NAT OF TileInstanceLine];
TileInstanceLine: TYPE = REF TileInstanceLineRec;
TileInstanceLineRec: TYPE = RECORD [c: SEQUENCE sizeX: NAT OF TileInstance];
TileInstance: TYPE = REF TileInstanceRec;
TileInstanceRec: TYPE = RECORD [
trans: Transformation,
obj: Object,
tNodes: SEQUENCE size: NAT OF TNode -- each of these corresponds to the ports of obj!
];
FuseNeighbors: PROC [mode: Mode, fused: RefTab.Ref, inX: BOOL, ti1, ti2: TileInstance] = {
EachPort2: EachPortProc = {
index2: NAT ← portIndex;
tt2: Transformation = transformation;
port2: Object = port;
EachPort1: EachPortProc = {
IF port=Pipal.void THEN SIGNAL InternalBug[];
IF mode.touch[mode.touch, transformation, port, tt2, port2]
THEN [] ← FuseTNodes[fused, ti1[portIndex], ti2[index2]];
};
IF port=Pipal.void THEN SIGNAL InternalBug[];
IF PipalInt.AtEdge[ab1, tt2, port2] THEN
[] ← EnumeratePorts[ti1.obj, mode, ab1, EachPort1, trans1];
};
ab1: Rectangle ← PipalInt.AbutBox[ti1.obj];
ab2: Rectangle ← PipalInt.AbutBox[ti2.obj];
basicTransl: PipalInt.Vector = IF inX THEN [ab1.size.x, 0] ELSE [0, ab1.size.y];
trans: Transformation = [PipalInt.Add[basicTransl, PipalInt.Sub[ab1.base, ab2.base]]];
trans1: Transformation = ti1.trans;
trans2: Transformation = PipalInt.Compose[trans, ti2.trans];
[] ← EnumeratePorts[ti2.obj, mode, ab2, EachPort2, trans2];
};
TilingComposer: PUBLIC GetComposerProc = {
tiling: PipalMos.Tiling ← NARROW [object];
insideIR: Rectangle = PipalInt.Extend[privateArea, -1];
tileInstances: TileInstanceArray;
fused: RefTab.Ref ← RefTab.Create[];
time: BasicTime.GMT = BasicTime.Now[];
index: NAT ← 0;
ConnectizeEachTile: PipalMos.EachTileProc = {
ab: Rectangle = PipalInt.AbutBox[tile];
trans: Transformation = [PipalInt.Sub[pos, ab.base]];
strictlyInside: BOOL ← PipalInt.IsInsideRectangle[insideIR, PipalInt.BBox[tile, trans]];
ti: TileInstance ← NEW [TileInstanceRec[CountPorts[tile, mode, ab]]];
EachPort: EachPortProc = {
tNode: TNode ← CreateTNode[fused];
IF port=Pipal.void THEN SIGNAL InternalBug[];
ti[portIndex] ← tNode;
IF NOT strictlyInside AND IsGeometryAtEdge[privateArea, transformation, port] THEN
tNode.edgeObjects ← LIST [PipalInt.TransformObject[transformation, port]];
tNode.bindings ← LIST [[index, portIndex]];
};
IF GetType[tile, mode]=null THEN SIGNAL CallerBug[];
tileInstances[y][x] ← ti;
ti.trans ← trans; ti.obj ← tile;
[] ← EnumeratePorts[tile, mode, ab, EachPort, trans];
index ← index + 1;
};
PutF["Connectizeing [%g] tiling (size: %g*%g)\n", IO.rope[mode.name], IO.int[tiling.sizeX], IO.int[tiling.sizeY]];
tileInstances ← NEW [TileInstanceArrayRec[tiling.sizeY]];
FOR y: NAT IN [0 .. tiling.sizeY) DO
tileInstances[y] ← NEW [TileInstanceLineRec[tiling.sizeX]];
ENDLOOP;
We connectize sub objects
[] ← PipalMos.EnumerateTiles[tiling, ConnectizeEachTile];
We fuse neighbors
FOR y: NAT IN [0 .. tiling.sizeY) DO
FOR x: NAT IN [1 .. tiling.sizeX) DO
FuseNeighbors[mode, fused, TRUE, tileInstances[y][x-1], tileInstances[y][x]];
ENDLOOP;
ENDLOOP;
FOR x: NAT IN [0 .. tiling.sizeX) DO
FOR y: NAT IN [1 .. tiling.sizeY) DO
FuseNeighbors[mode, fused, FALSE, tileInstances[y-1][x], tileInstances[y][x]];
ENDLOOP;
ENDLOOP;
IF index#tiling.sizeX*tiling.sizeY THEN SIGNAL InternalBug[];
cc ← MakeComposer[fused, object, privateArea];
PutF["Connectizeed [%g] tiling (%g sec.)\n", IO.rope[mode.name], IO.int[BasicTime.Period[time, BasicTime.Now[]]]];
};
Exceptions
InternalBug: PUBLIC SIGNAL [] = CODE;
CallerBug: PUBLIC SIGNAL [] = CODE;
Progress Report
OutputType: TYPE = {none, terminal, messageWindow};
outputFlag: OutputType ← terminal;
PutF: PUBLIC PROC [format: ROPE, v1, v2, v3, v4, v5: IO.Value ← [null[]]] = {
SELECT outputFlag FROM
terminal => TerminalIO.PutF[format, v1, v2, v3, v4, v5];
messageWindow => MessageWindow.Append[IO.PutFR[format, v1, v2, v3, v4, v5], TRUE];
ENDCASE => {};
};
Layout Methods
layoutMode: PUBLIC Mode ← NEW [ModeRec ← [
getTypeMethod: Pipal.RegisterMethod["LayoutGetType"],
enumeratePortsMethod: Pipal.RegisterMethod["LayoutEnumeratePorts"],
getComposerMethod: Pipal.RegisterMethod["LayoutGetComposer"],
name: "Layout",
touch: PipalMos.LayoutTouch,
nbOfLayers: nbOfInterestingLayers,
objectLayer: LayoutObjectLayer
]];
rawLayoutMode: PUBLIC Mode ← NEW [ModeRec ← [
getTypeMethod: Pipal.RegisterMethod["RawLayoutGetType"], -- maybe the same as layoutMode?
enumeratePortsMethod: Pipal.RegisterMethod["RawLayoutEnumeratePorts"], -- maybe the same as layoutMode?
getComposerMethod: Pipal.RegisterMethod["RawLayoutGetComposer"],
name: "RawLayout",
touch: PipalMos.LayoutTouch,
nbOfLayers: nbOfInterestingLayers,
objectLayer: LayoutObjectLayer
]];
nbOfInterestingLayers: NAT = 10;
defaultLayerRange: LayerRange = [min: 0, max: nbOfInterestingLayers-1];
interestingLayers: RefTab.Ref ← RefTab.Create[];
Maps [layer -> REF LayerRange]
Interestinglayers: PROC [layer: PipalMos.Layer] RETURNS [LayerRange] = {
refLayerRange: REF LayerRange ← NARROW [RefTab.Fetch[interestingLayers, layer].val];
RETURN [IF refLayerRange=NIL THEN defaultLayerRange ELSE refLayerRange^];
};
SetInterestinglayers: PROC [layer: PipalMos.Layer, range: LayerRange] = {
[] ← RefTab.Store[interestingLayers, layer, NEW [LayerRange ← range]];
};
LayoutObjectLayer: PROC [object: Pipal.Object] RETURNS [layerRange: LayerRange] = {
EachChild: PipalInt.EachChildProc = {
thisLayerRange: LayerRange ← WITH child SELECT FROM
box: PipalMos.Box   => Interestinglayers[box.layer],
marker: PipalMos.Marker => Interestinglayers[marker.layer],
text: PipalMos.Text   => [nbOfInterestingLayers-1, 0],
picture: PipalMos.Picture => [nbOfInterestingLayers-1, 0],
ENDCASE  => ERROR;
layerRange ← [min: MIN [thisLayerRange.min, layerRange.min], max: MAX [thisLayerRange.max, layerRange.max]];
IF layerRange=defaultLayerRange THEN quit ← TRUE;
};
layerRange ← [nbOfInterestingLayers-1, 0];
[] ← PipalMos.EnumerateAtomic[object, EachChild];
IF layerRange.min>layerRange.max THEN layerRange ← defaultLayerRange;
};
SetLayout: PROC [class: Pipal.Class, type: GetTypeProc, ports: EnumeratePortsProc ← NIL, composer: GetComposerProc ← NIL] = {
FOR modes: LIST OF Mode ← LIST [layoutMode, rawLayoutMode], modes.rest WHILE modes#NIL DO
mode: Mode ← modes.first;
Pipal.PutClassMethod[class, mode.getTypeMethod, NEW [GetTypeProc ← type]];
IF ports#NIL THEN Pipal.PutClassMethod[class, mode.enumeratePortsMethod, NEW [EnumeratePortsProc ← ports]];
IF composer#NIL THEN Pipal.PutClassMethod[class, mode.getComposerMethod, NEW [GetComposerProc ← composer]];
ENDLOOP;
};
LayoutBoxType: PUBLIC GetTypeProc = {
For boxes which connector type is leaf, except when the layer is PipalMos.errorLayer or PipalMos.commentLayer, in which case it is null.
box: PipalMos.Box = NARROW [object];
type ← IF box.layer=PipalMos.errorLayer OR box.layer=PipalMos.commentLayer
THEN null ELSE leaf;
};
LayoutAnnotationType: GetTypeProc = {
annotation: Pipal.Annotation = NARROW [object];
SELECT annotation.key FROM
PipalMos.atomicProp => RETURN [leaf];
PipalMos.biAtomicProp => RETURN [leaf];
PipalMos.transistorProp => RETURN [leaf];
ENDCASE => RETURN [GetType[annotation.child, mode]];
};
LayoutAnnotationEnumeratePorts: EnumeratePortsProc = {
annotation: Pipal.Annotation = NARROW [object];
proc: EnumeratePortsProc ← EnumeratePorts;
child: Object ← annotation.child;
SELECT annotation.key FROM
PipalMos.atomicProp  => proc ← AtomicEnumeratePorts;
PipalMos.biAtomicProp  => proc ← BiAtomicEnumeratePorts;
PipalMos.transistorProp => {proc ← TransistorEnumeratePorts; child ← object};
PipalInt.abutBoxProp => privateArea ← NARROW [annotation.value, REF Rectangle]^;
ENDCASE     => {};
RETURN [proc[child, mode, privateArea, eachPort, transformation]];
};
TransistorEnumeratePorts: EnumeratePortsProc = {
type: PipalMos.TransistorType;
ch1, ch2, gate, bulk: Object;
width, length: INT;
[type, ch1, ch2, gate, bulk, width, length] ← PipalMos.ExtractTransistor[object];
quit ← eachPort[transformation, 0, gate] OR eachPort[transformation, 1, ch1] OR eachPort[transformation, 2, ch2] OR (bulk#Pipal.void AND eachPort[transformation, 3, bulk]);
};
LayoutAnnotationComposer: PUBLIC GetComposerProc = {
annotation: Pipal.Annotation = NARROW [object];
IF annotation.key=PipalInt.abutBoxProp THEN privateArea ← NARROW [annotation.value, REF Rectangle]^;
RETURN [GetComposer[annotation.child, mode, privateArea]];
};
StarType: GetTypeProc = {
star: PipalMos.Star = NARROW [object];
RETURN [GetType[star.master, mode]];
};
StarEnumeratePorts: EnumeratePortsProc = {
star: PipalMos.Star = NARROW [object];
RETURN [EnumeratePorts[star.master, mode, PipalInt.AbutBox[star.master], eachPort, transformation]];
};
StarComposer: GetComposerProc = {
star: PipalMos.Star = NARROW [object];
RETURN [GetComposer[star.master, mode, PipalInt.AbutBox[star.master]]];
};
Schematic Methods
schematicMode: PUBLIC Mode ← NEW [ModeRec ← [
getTypeMethod: Pipal.RegisterMethod["SchematicGetType"],
enumeratePortsMethod: Pipal.RegisterMethod["SchematicEnumeratePorts"],
getComposerMethod: Pipal.RegisterMethod["SchematicGetComposer"],
name: "Schematic",
touch: PipalMos.SchematicTouch
]];
SetSchematic: PROC [class: Pipal.Class, type: GetTypeProc, ports: EnumeratePortsProc ← NIL, composer: GetComposerProc ← NIL] = {
Pipal.PutClassMethod[class, schematicMode.getTypeMethod, NEW [GetTypeProc ← type]];
IF ports#NIL THEN Pipal.PutClassMethod[class, schematicMode.enumeratePortsMethod, NEW [EnumeratePortsProc ← ports]];
IF composer#NIL THEN Pipal.PutClassMethod[class, schematicMode.getComposerMethod, NEW [GetComposerProc ← composer]];
};
SchematicBoxType: PUBLIC GetTypeProc = {
For boxes which connector type is leaf, except when the layer is PipalMos.errorLayer or PipalMos.commentLayer, in which case it is null.
box: PipalMos.Box = NARROW [object];
SELECT box.layer FROM
PipalMos.blueCommentLayer   => type ← null;
PipalMos.commentLayer    => type ← leaf;
ENDCASE         => SIGNAL CallerBug[];
};
SchematicAnnotationType: GetTypeProc = {
annotation: Pipal.Annotation = NARROW [object];
SELECT annotation.key FROM
PipalMos.atomicProp, PipalMos.biAtomicProp, PipalMos.transistorProp => SIGNAL CallerBug[];
ENDCASE => RETURN [GetType[annotation.child, mode]];
};
SchematicAnnotationEnumeratePorts: EnumeratePortsProc = {
annotation: Pipal.Annotation = NARROW [object];
SELECT annotation.key FROM
PipalMos.atomicProp, PipalMos.biAtomicProp, PipalMos.transistorProp => SIGNAL CallerBug[];
PipalInt.abutBoxProp => privateArea ← NARROW [annotation.value, REF Rectangle]^;
ENDCASE     => {};
RETURN [EnumeratePorts[annotation.child, mode, privateArea, eachPort, transformation]];
};
SchematicAnnotationComposer: PUBLIC GetComposerProc = {
annotation: Pipal.Annotation = NARROW [object];
IF annotation.key=PipalInt.abutBoxProp THEN privateArea ← NARROW [annotation.value, REF Rectangle]^;
RETURN [GetComposer[annotation.child, mode, privateArea]];
};
Layout Initialization
SetInterestinglayers[$Met2, [0, 0]];
SetInterestinglayers[$Met, [1, 1]];
SetInterestinglayers[$Pol, [2, 2]];
SetInterestinglayers[$Pdif, [3, 3]];
SetInterestinglayers[$Ndif, [4, 4]];
SetInterestinglayers[$Pwell, [5, 5]];
SetInterestinglayers[$Nwell, [6, 6]];
SetInterestinglayers[$Ovg, [0, 7]];
SetInterestinglayers[$PwellCont, [8, 8]];
SetInterestinglayers[$NwellCont, [9, 9]];
SetInterestinglayers[$Cut2, [0, 1]];
SetInterestinglayers[$Cut, [1, 4]];
SetLayout[PipalMos.textClass, NullType];
SetLayout[PipalMos.pictureClass, NullType];
SetLayout[PipalMos.boxClass, LayoutBoxType, AtomicEnumeratePorts];
SetLayout[PipalMos.markerClass, LeafType, AtomicEnumeratePorts];
SetLayout[Pipal.overlayClass, CompositeType, ComposerEnumeratePorts, EnumerationComposer];
SetLayout[PipalInt.abutClass, CompositeType, ComposerEnumeratePorts, AbutComposer];
SetLayout[PipalMos.routingClass, CompositeType, ComposerEnumeratePorts, RoutingComposer];
SetLayout[PipalMos.tilingClass, CompositeType, ComposerEnumeratePorts, TilingComposer];
SetLayout[Pipal.annotationClass, LayoutAnnotationType, LayoutAnnotationEnumeratePorts, LayoutAnnotationComposer];
SetLayout[PipalMos.starClass, StarType, StarEnumeratePorts, StarComposer];
Schematic Initialization
SetSchematic[PipalMos.textClass, NullType];
SetSchematic[PipalMos.pictureClass, NullType];
SetSchematic[PipalMos.boxClass, SchematicBoxType, AtomicEnumeratePorts];
SetSchematic[PipalMos.markerClass, LeafType, AtomicEnumeratePorts];
SetSchematic[Pipal.overlayClass, CompositeType, ComposerEnumeratePorts, EnumerationComposer];
SetSchematic[PipalInt.abutClass, CompositeType, ComposerEnumeratePorts, AbutComposer];
SetSchematic[PipalMos.tilingClass, CompositeType, ComposerEnumeratePorts, TilingComposer];
SetSchematic[Pipal.annotationClass, SchematicAnnotationType, SchematicAnnotationEnumeratePorts, SchematicAnnotationComposer];
SetSchematic[PipalMos.starClass, StarType, StarEnumeratePorts, StarComposer];
END.