DIRECTORY
Basics, 
Convert, 
Core, CoreClasses, CoreFlat, CoreIO, CoreOps, CoreProperties,
Imager, ImagerFont, ImagerTransformation,
List,
Pipal, PipalCore, PipalInstanceTable, PipalInt, PipalIO, PipalMos,
PrincOps, RefTab, Rope;

PipalCoreImpl: CEDAR PROGRAM
IMPORTS Basics, Convert, CoreClasses, CoreFlat, CoreIO, CoreOps, CoreProperties, ImagerFont, ImagerTransformation, List, Pipal, PipalInstanceTable, PipalInt, PipalIO, PipalMos, RefTab, Rope
EXPORTS PipalCore
 ~ BEGIN OPEN PipalCore;
CellType : TYPE = Core.CellType;
Properties : TYPE = Core.Properties;
ROPE: TYPE = Core.ROPE;
Wire: TYPE = Core.Wire;
CellInstance: TYPE = CoreClasses.CellInstance;
FlatWire: TYPE = CoreFlat.FlatWire;
FlatWireRec: TYPE = CoreFlat.FlatWireRec;
FlatCellType: TYPE = CoreFlat.FlatCellType;
FlatCellTypeRec: TYPE = CoreFlat.FlatCellTypeRec;
Bindings: TYPE = CoreFlat.Bindings;
InstancePath: TYPE = CoreFlat.InstancePath;
Object: TYPE = Pipal.Object;
Objects: TYPE = Pipal.Objects;
Transformation: TYPE = PipalInt.Transformation;
Rectangle: TYPE = PipalInt.Rectangle;
layoutDecoration: PUBLIC Decoration _ CreateDecoration["Layout", TRUE];
schematicsDecoration: PUBLIC Decoration _ CreateDecoration["Schematic", TRUE];
rawLayoutDecoration: PUBLIC Decoration _ CreateDecoration["RawLayout", TRUE];

CreateDecoration: PUBLIC PROC [name: ROPE, coreSave: BOOL _ FALSE] RETURNS [decoration: Decoration] ~ {
decoration _ NEW [DecorationRec _ [
name: name, 
portProp: CoreProperties.RegisterProperty[
Convert.AtomFromRope[Rope.Cat[name, "Port"]], 
CoreProperties.Props[[CoreProperties.propPrint, CoreProperties.PropDontPrint]]
], 
objectProp: CoreProperties.RegisterProperty[
Convert.AtomFromRope[Rope.Cat[name, "Object"]], 
CoreProperties.Props[[CoreProperties.propPrint, CoreProperties.PropDontPrint]]
], 
geometryProp: CoreProperties.RegisterProperty[
Convert.AtomFromRope[Rope.Cat[name, "Geometry"]], 
CoreProperties.Props[[CoreProperties.propPrint, CoreProperties.PropDontPrint]]
], 
transProp: CoreProperties.RegisterProperty[
Convert.AtomFromRope[Rope.Cat[name, "Trans"]], 
CoreProperties.Props[[CoreProperties.propPrint, CoreProperties.PropDontPrint]]
]
]];
IF NOT coreSave THEN RETURN;
[] _ CoreIO.RegisterProperty[decoration.objectProp, ObjectPropWrite, ObjectPropRead];
[] _ CoreIO.RegisterProperty[decoration.portProp, ObjectPropWrite, ObjectPropRead];
[] _ CoreIO.RegisterProperty[decoration.geometryProp, ObjectPropWrite, ObjectPropRead];
[] _ CoreIO.RegisterProperty[decoration.transProp, TransPropWrite, TransPropRead];
};

ObjectPropWrite: CoreIO.PropWriteProc = {PipalIO.WriteObject[stream, NARROW [value]]};
ObjectPropRead: CoreIO.PropReadProc = {value _ PipalIO.ReadObject[stream]};

TransPropWrite: CoreIO.PropWriteProc = {PipalIO.WriteIntTransformation[stream, NARROW [value, REF PipalInt.Transformation]^]};
TransPropRead: CoreIO.PropReadProc = {value _ NEW [PipalInt.Transformation _ PipalIO.ReadIntTransformation[stream]]};
HasPort: PUBLIC PROC [decoration: Decoration, public: Wire] RETURNS [BOOL] = {
RETURN [GetPort[decoration, public]#Pipal.void];
};

GetPort: PUBLIC PROC [decoration: Decoration, public: Wire] RETURNS [port: Object] = {
port _ CoreProperties.GetWireProp[public, decoration.portProp];
IF port=Pipal.void THEN ERROR;
IF port=NIL THEN port _ Pipal.void;
};
PutPort: PUBLIC PROC [decoration: Decoration, public: Wire, port: Object] = {
IF port=NIL THEN ERROR;
IF port=Pipal.void THEN port _ NIL;
CoreProperties.PutWireProp[public, decoration.portProp, port];
};

AddPort: PUBLIC PROC [decoration: Decoration, public: Wire, port: Object] = {
ports: Objects _ NIL;
IF port=NIL THEN ERROR;
IF port#Pipal.void THEN ports _ LIST [port];
port _ GetPort[decoration, public];
IF port#Pipal.void THEN ports _ CONS [port, ports];
PutPort[decoration, public, Pipal.CreateOv[ports]];
};

PutClippedPort: PUBLIC PROC [decoration: Decoration, public: Wire, abutBox: Rectangle, subPort: Object] = {
IF subPort=NIL THEN ERROR;
PutPort[decoration, public, PipalMos.CreateClipEnum[abutBox, subPort]];
};

TransWire: TYPE = RECORD [trans: Transformation, wire: Wire];

PutRecordPorts: PUBLIC PROC [decoration: Decoration, record: CellType, abutBox: Rectangle] = {
recData: CoreClasses.RecordCellType = NARROW [record.data];
table: RefTab.Ref _ RefTab.Create[record.public.size];
SetLazyPort: CoreOps.EachWireProc = {
subs: Objects _ NIL;
FOR list: LIST OF TransWire _ NARROW [RefTab.Fetch[table, wire].val], list.rest WHILE list#NIL DO
subs _ CONS [PipalMos.CreateClipEnum[abutBox, PipalInt.TransformObject[list.first.trans, GetPort[decoration, list.first.wire]]], subs];
ENDLOOP;
PutPort[decoration, wire, Pipal.CreateOv[subs]];
};
FOR i: NAT IN [0 .. recData.size) DO
cellInstance: CoreClasses.CellInstance = recData[i];
trans: Transformation = GetTrans[decoration, cellInstance];
EachBind: CoreOps.EachWirePairProc = {
list: LIST OF TransWire _ NARROW [RefTab.Fetch[table, actualWire].val];
FOR aux: LIST OF TransWire _ list, aux.rest WHILE aux#NIL DO
IF aux.first=[trans, publicWire] THEN RETURN;
ENDLOOP;
list _ CONS [[trans, publicWire], list];
[] _ RefTab.Store[table, actualWire, list];
};
IF NOT HasObject[decoration, cellInstance.type] THEN ERROR; -- this sub Cell has not been decorated
IF PipalInt.AtEdge[abutBox, trans, GetObject[decoration, cellInstance.type]] THEN 
[] _ CoreOps.VisitBindingSeq[cellInstance.actual, cellInstance.type.public, EachBind];
ENDLOOP;
[] _ CoreOps.VisitWireSeq[record.public, SetLazyPort];
};
HasObject: PUBLIC PROC [decoration: Decoration, cellType: CellType] RETURNS [BOOL] = {
RETURN [GetObject[decoration, cellType]#NIL];
};

GetObject: PUBLIC PROC [decoration: Decoration, cellType: CellType] RETURNS [object: Object] = {
object _ NARROW [CoreProperties.GetCellTypeProp[cellType, decoration.objectProp]];
};

PutObject: PUBLIC PROC [decoration: Decoration, cellType: CellType, object: Object] = {
CoreProperties.PutCellTypeProp[cellType, decoration.objectProp, object];
};
HasGeometry: PUBLIC PROC [decoration: Decoration, wire: Wire] RETURNS [BOOL] = {
RETURN [GetGeometry[decoration, wire]#Pipal.void];
};
GetGeometry: PUBLIC PROC [decoration: Decoration, wire: Wire] RETURNS [geometry: Object] = {
geometry _ CoreProperties.GetWireProp[wire, decoration.geometryProp];
IF geometry=Pipal.void THEN ERROR;
IF geometry=NIL THEN geometry _ Pipal.void;
};
PutGeometry: PUBLIC PROC [decoration: Decoration, wire: Wire, geometry: Object] = {
IF geometry=NIL THEN ERROR;
IF geometry=Pipal.void THEN geometry _ NIL;
CoreProperties.PutWireProp[wire, decoration.geometryProp, geometry];
};

AddGeometry: PUBLIC PROC [decoration: Decoration, wire: Wire, geometry: Object] = {
geometries: Objects _ NIL;
IF geometry=NIL THEN ERROR;
IF geometry#Pipal.void THEN geometries _ LIST [geometry];
geometry _ GetGeometry[decoration, wire];
IF geometry#Pipal.void THEN geometries _ CONS [geometry, geometries];
PutGeometry[decoration, wire, Pipal.CreateOv[geometries]];
};

EnumerateFlatGeometry: PUBLIC PROC [decoration: Decoration, root: CellType, target: FlatCellTypeRec _ CoreFlat.allFlatCells, leafProc: LeafProc, eachFlatWire: EachFlatWireProc _ NIL, eachFlatCell: EachFlatCellProc _ NIL] RETURNS [quit: BOOL _ FALSE] = {
TransBoundFlat: CoreFlat.BoundFlatCellProc = {
trans: Transformation = GetTrans[decoration, instance];
refTrans: REF Transformation = NARROW [data];
currentTrans: Transformation = PipalInt.Compose[refTrans^, trans];
BoundFlat[cell, target, flatCell, instance, index, parent, flatParent, NEW [Transformation _ currentTrans], bindings];
};
BoundFlat: CoreFlat.BoundFlatCellProc = {
refTrans: REF Transformation = NARROW [data];
IF CoreFlat.FlatCellTypeEqualRec[target, flatCell] THEN target _ CoreFlat.allFlatCells;
IF leafProc[cell, bindings] THEN {
IF target=CoreFlat.allFlatCells AND eachFlatCell#NIL THEN quit _ eachFlatCell[bindings: bindings, cell: cell, flatCell: flatCell, trans: refTrans^];
RETURN;
};
IF cell.class=CoreClasses.recordCellClass THEN {
RecordGeometry: CoreOps.EachWireProc = {
refBoundWire: FlatWire _ NARROW [RefTab.Fetch[bindings, wire].val];
IF NOT HasGeometry[decoration, wire] THEN RETURN;
quit _ eachFlatWire[wire, IF refBoundWire#NIL THEN refBoundWire^ ELSE [flatCell: flatCell, wire: wire], refTrans^];
};
rct: CoreClasses.RecordCellType = NARROW [cell.data];
IF target=CoreFlat.allFlatCells AND eachFlatWire#NIL THEN quit _ CoreOps.VisitWireSeq[rct.internal, RecordGeometry];
IF quit THEN RETURN;
CoreFlat.NextBoundCellType[cell, target, flatCell, instance, index, parent, flatParent, data, bindings, TransBoundFlat];
}
ELSE CoreFlat.NextBoundCellType[cell, target, flatCell, instance, index, parent, flatParent, data, bindings, BoundFlat];
};
BoundFlat[cell: root, target: target, bindings: CoreFlat.InitialBindingTable[root], data: NEW [Transformation _ []]];
};

EnumerateAllGeometry: PUBLIC PROC [decoration: Decoration, cell: CellType, wire: Wire, each: PipalInt.EachChildProc, trans: Transformation] RETURNS [quit: BOOL _ FALSE] = {
SELECT cell.class FROM
CoreClasses.recordCellClass => {
recordCell: CoreClasses.RecordCellType = NARROW [cell.data];
quit _ each[trans, GetGeometry[decoration, wire]];
FOR i: NAT IN [0 .. recordCell.size) UNTIL quit DO
EnumerateSubInstances: CoreOps.EachWirePairProc = {
IF actualWire = wire THEN 
quit _ EnumerateAllGeometry[decoration: decoration, cell: cellInstance.type, wire: publicWire, each: each, trans: thisTrans]
};
cellInstance: CoreClasses.CellInstance = recordCell[i];
thisTrans: Transformation = PipalInt.Compose[trans, GetTrans[decoration: decoration, cellInstance: cellInstance]];
quit _ CoreOps.VisitBinding[actual: cellInstance.actual, public: cellInstance.type.public, eachWirePair: EnumerateSubInstances].quit
ENDLOOP
};
CoreClasses.transistorCellClass =>
quit _ each[trans, GetGeometry[decoration, wire]];
ENDCASE => {
recastCell: CellType = CoreOps.Recast[me: cell];
wireTab: RefTab.Ref _ CoreOps.CreateBindingTable[wire1: cell.public, wire2: recastCell.public];
quit _ EnumerateAllGeometry[decoration: decoration, cell: recastCell, wire: NARROW [RefTab.Fetch[x: wireTab, key: wire].val], each: each, trans: trans]
};
};

GetAllGeometry: PUBLIC PROC [decoration: Decoration, cell: CellType, wire: Wire] RETURNS [geometry: Object] = {
geoms: Objects _ NIL;
ConsEach: PipalInt.EachChildProc = {
geoms _ CONS [PipalInt.TransformObject[transformation, child], geoms];
};
[] _ EnumerateAllGeometry[decoration, cell, wire, ConsEach, []];
geometry _ Pipal.CreateOv[geoms];
};
HasTrans: PUBLIC PROC [decoration: Decoration, cellInstance: CellInstance] RETURNS [BOOL] = {
RETURN [CoreProperties.GetCellInstanceProp[cellInstance, decoration.transProp]#NIL];
};
GetTrans: PUBLIC PROC [decoration: Decoration, cellInstance: CellInstance] RETURNS [trans: Transformation] = {
refTrans: REF Transformation _ NARROW [CoreProperties.GetCellInstanceProp[cellInstance, decoration.transProp]];
trans _ refTrans^;
};

PutTrans: PUBLIC PROC [decoration: Decoration, cellInstance: CellInstance, trans: Transformation] = {
CoreProperties.PutCellInstanceProp[cellInstance, decoration.transProp, NEW [Transformation _ trans]];
};
routingLayers: RefTab.Ref _ RefTab.Create[];

RegisterRoutingLayer: PUBLIC PROC [layer: PipalMos.Layer] = {
[] _ RefTab.Store[routingLayers, layer, $TRUE];
};

GetSides: PUBLIC PROC [abutBox: Rectangle, trans: Transformation, port: Pipal.Object] RETURNS [sides: Sides _ noSide] = {
sides _ PinIRSides[abutBox, PipalInt.TransformRectangle[trans, PipalInt.AbutBox[port]]]; 
};

PinIRSides: PROC [abutBox, bbox: Rectangle] RETURNS [sides: Sides _ noSide] = {
objSize: PipalInt.Size = abutBox.size;
pinIR: Rectangle = PipalInt.Translate[bbox, PipalInt.Neg[abutBox.base]];
sides[top] _ PipalInt.DoRectanglesIntersect[pinIR, [[0, objSize.y-1], [objSize.x, 1]]];
sides[bottom] _ PipalInt.DoRectanglesIntersect[pinIR, [[0, 0], [objSize.x, 1]]];
sides[left] _ PipalInt.DoRectanglesIntersect[pinIR, [[0, 0], [1, objSize.y]]];
sides[right] _ PipalInt.DoRectanglesIntersect[pinIR, [[objSize.x-1, 0], [1, objSize.y]]];
};

EnumerateSides: PUBLIC PROC [decoration: Decoration, cellType: CellType, wire: Wire, eachPin: EachPinProc] RETURNS [quit: BOOL] = {
EnumerateSeg: PipalMos.EachRectangleLayerProc = {
sides: Sides = PinIRSides[abutBox, rect];
IF NOT RefTab.Fetch[routingLayers, layer].found THEN RETURN;
FOR side: Side IN Side DO 
pinIR: Rectangle = PipalInt.Translate[rect, PipalInt.Neg[abutBox.base]]; -- rect of the pin in the obj coordinate system of the outer  
min, max: INT _ 0;
IF ~sides[side] THEN LOOP;
IF side=top OR side=bottom THEN {min _ pinIR.base.x; max _ pinIR.base.x+pinIR.size.x};
IF side=left OR side=right THEN {min _ pinIR.base.y; max _ pinIR.base.y+pinIR.size.y};
IF (quit _ eachPin[min, max, side, layer]) THEN RETURN;
ENDLOOP;
};
abutBox: Rectangle = PipalInt.AbutBox[GetObject[decoration, cellType]];
quit _ PipalMos.EnumerateRectangleLayers[GetPort[decoration, wire], EnumerateSeg];
};
EnumerateWireSides: PUBLIC PROC [decoration: Decoration, cellType: CellType, eachWirePin: EachWirePinProc] RETURNS [quit: BOOL] = {
EachWireSide: CoreOps.EachWireProc = {
EachPin: EachPinProc = {quit _ eachWirePin[wire, min, max, side, layer]};
IF ~RefTab.Store[visitOnceTab, wire, $TRUE] THEN RETURN; -- only once
quit _ EnumerateSides[decoration, cellType, wire, EachPin];
};
visitOnceTab: RefTab.Ref _ RefTab.Create[];
quit _ CoreOps.VisitWireSeq[cellType.public, EachWireSide];
};

WMMSL: TYPE = RECORD [wire: Wire, min, max: INT, side: Side, layer: PipalMos.Layer];

EnumerateNonOverlappingSides: PUBLIC PROC [decoration: Decoration, cellType: CellType, eachWirePin: EachWirePinProc] RETURNS [quit: BOOL] = {
list: LIST OF REF _ NIL;
sorted: LIST OF REF;
CompareWMMSL: List.CompareProc = {
wmmsl1: REF WMMSL = NARROW [ref1];
wmmsl2: REF WMMSL = NARROW [ref2];
RETURN [Basics.CompareInt[wmmsl1.min, wmmsl2.min]];
};
EachWirePin: EachWirePinProc = {
list _ CONS [NEW [WMMSL _ [wire, min, max, side, layer]], list];
};
[] _ EnumerateWireSides[decoration, cellType, EachWirePin];
sorted _ List.Sort[list, CompareWMMSL]; -- modifies the list for good
FOR wmmsls: LIST OF REF _ sorted, wmmsls.rest WHILE wmmsls#NIL DO
wmmsl1: REF WMMSL = NARROW [wmmsls.first];
merge: BOOL _ TRUE;
WHILE merge DO
FOR aux: LIST OF REF _ wmmsls, aux.rest WHILE aux#NIL AND aux.rest#NIL DO
wmmsl2: REF WMMSL = NARROW [aux.rest.first];
IF wmmsl1.wire=wmmsl2.wire AND wmmsl1.side=wmmsl2.side AND wmmsl1.layer=wmmsl2.layer AND wmmsl2.min<=wmmsl1.max  
THEN {wmmsl1.max _ MAX [wmmsl1.max, wmmsl2.max]; aux.rest _ aux.rest.rest; EXIT};
REPEAT FINISHED	=> merge _ FALSE;
ENDLOOP;
ENDLOOP;
ENDLOOP;
WHILE sorted#NIL DO
wmmsl: REF WMMSL = NARROW [sorted.first];
quit _ eachWirePin[wmmsl.wire, wmmsl.min, wmmsl.max, wmmsl.side, wmmsl.layer];
IF quit THEN EXIT;
sorted _ sorted.rest;
ENDLOOP;
};

WMML: TYPE = RECORD [wire: Wire, min, max: INT, layer: PipalMos.Layer];

EnumerateSortedSides: PUBLIC PROC [decoration: Decoration, cellType: CellType, side: Side, eachSortedPin: EachSortedPinProc] RETURNS [quit: BOOL] = {
list: LIST OF REF _ NIL;
sorted: LIST OF REF;
sideFilter: Side = side;
CompareWMML: List.CompareProc = {
wmml1: REF WMML = NARROW [ref1];
wmml2: REF WMML = NARROW [ref2];
RETURN [Basics.CompareInt[wmml1.min, wmml2.min]];
};
EachWirePin: EachWirePinProc = {
IF side=sideFilter THEN list _ CONS [NEW [WMML _ [wire, min, max, layer]], list];
};
[] _ EnumerateWireSides[decoration, cellType, EachWirePin];
sorted _ List.Sort[list, CompareWMML]; -- modifies the list for good
WHILE sorted#NIL DO
wmml: REF WMML = NARROW [list.first];
quit _ eachSortedPin[wmml.wire, wmml.min, wmml.max, wmml.layer];
IF quit THEN EXIT;
sorted _ sorted.rest;
ENDLOOP;
};
font: Imager.Font _ ImagerFont.Modify[
ImagerFont.Find["Xerox/TiogaFonts/Helvetica8"], ImagerTransformation.Scale[4]
];
CreateShell: PUBLIC PROC [decoration: Decoration, cellType: CellType, withCuteFonts: BOOL _ FALSE] RETURNS [shell: Object] = {
objects: Objects _ NIL;
visitOnceTab: RefTab.Ref _ RefTab.Create[];
ConstructEachWire: CoreOps.EachWireProc = {
name: ROPE _ CoreOps.GetFullWireName[cellType.public, wire];
IF ~RefTab.Store[visitOnceTab, wire, $TRUE] THEN RETURN; -- only once
objects _ CONS [
Pipal.CreateAnnotation[GetPort[decoration, wire], Pipal.nameProp, name],
objects];
IF withCuteFonts THEN {
ConstructFonts: EachPinProc = {
trans: Transformation = [
SELECT side FROM 
left => [-300, min], right => [iSize.x+10, min], 
top => [min, iSize.y+10], bottom => [min, -300], 
ENDCASE => ERROR, 
SELECT side FROM 
left, right => identity, top, bottom => rotate90, ENDCASE => ERROR
];
objects _ CONS [PipalInt.TransformObject[trans, text], objects];
};
text: Object _ PipalMos.CreateText[name, font];
[] _ EnumerateSides[decoration, cellType, wire, ConstructFonts];
};
};
abutBox: Rectangle = PipalInt.AbutBox[GetObject[decoration, cellType]];
iSize: PipalInt.Size _ abutBox.size;
[] _ CoreOps.VisitWireSeq[cellType.public, ConstructEachWire];
shell _ PipalInt.CreateAbutBoxAnnotation[Pipal.CreateOv[objects], abutBox];
};
CheckInterface: PUBLIC PROC [decoration: Decoration, cellType: CellType] RETURNS [ok: BOOL] = {
CheckPort: PROC [wire: Wire] = {IF NOT HasPort[decoration, wire] THEN ok _ FALSE};
ok _ HasObject[decoration, cellType];
CoreOps.VisitRootAtomics[cellType.public, CheckPort];
};
CheckInternal: PUBLIC PROC [decoration: Decoration, record: CellType] RETURNS [ok: BOOL] = {
data: CoreClasses.RecordCellType = NARROW [record.data];
IF NOT CheckInterface[decoration, record] THEN RETURN [FALSE];
FOR i: NAT IN [0 .. data.size)
DO [] _ GetTrans[decoration, data[i] ! ANY => ok _ FALSE] ENDLOOP;
};
EnumerateNeighbors: PUBLIC PROC [decoration: Decoration, touch: PipalMos.TouchProc, inX: BOOL, ct1, ct2: CellType, eachPair: PROC [Wire, Wire] RETURNS [quit: BOOL _ FALSE]] RETURNS [quit: BOOL] = {
obj1: Object = GetObject[decoration, ct1];
obj2: Object = GetObject[decoration, ct2];
abutBox1: Rectangle = PipalInt.AbutBox[obj1];
abutBox2: Rectangle = PipalInt.AbutBox[obj2];
basicTransl: PipalInt.Vector = IF inX THEN [abutBox1.size.x, 0] ELSE [0, abutBox1.size.y];
trans: Transformation = [PipalInt.Add[basicTransl, PipalInt.Sub[abutBox1.base, abutBox2.base]]];
table2: PipalInstanceTable.Table _ PipalInstanceTable.Create[PipalInt.Extend[PipalInt.BBox[obj2, trans], 1]];
EachPub2: CoreOps.EachWireProc = {
pin2: Object _ GetPort[decoration, wire];
IF PipalInt.AtEdge[abutBox1, trans, pin2] THEN PipalInstanceTable.Insert[table2, trans, pin2, wire];
};
EachPub1: CoreOps.EachWireProc ~ {
pin1: Object _ GetPort[decoration, wire];
rect1: Rectangle = PipalInt.BBox[pin1, []];
EachOverlap: PROC [trans2: Transformation, pin2: Object, value: REF ANY] ~ {
IF touch[touch, [], pin1, trans2, pin2] THEN quit _ eachPair[wire, NARROW [value]];
};
PipalInstanceTable.Enumerate[table2, EachOverlap, rect1];
};
[] _ CoreOps.VisitWireSeq[ct2.public, EachPub2];
quit _ CoreOps.VisitWireSeq[ct1.public, EachPub1];
};

CacheKeyRec: TYPE = RECORD [decoration: Decoration, touch: PipalMos.TouchProc, inX: BOOL, ct1, ct2: CellType];
EqualCacheKey: RefTab.EqualProc = {
ck1: REF CacheKeyRec _ NARROW [key1];
ck2: REF CacheKeyRec _ NARROW [key2];
RETURN [ck1^=ck2^];
};
Munch: PROC [CARD32] RETURNS [CARD16] = TRUSTED MACHINE CODE { PrincOps.zXOR };
MunchRef: PROC [ref: REF] RETURNS [WORD] = INLINE {RETURN [Munch[LOOPHOLE [ref]]]};
HashCacheKey: RefTab.HashProc = {
ck: REF CacheKeyRec _ NARROW [key];
RETURN [
Basics.BITXOR[
Basics.BITXOR[
Basics.BITXOR[MunchRef[ck.decoration], LOOPHOLE[ck.touch]], 
Basics.BITXOR[MunchRef[ck.ct1], MunchRef[ck.ct2]]
], 
ORD[ck.inX]
]
];
};
CreateNeighborsCache: PUBLIC PROC [] RETURNS [cache: RefTab.Ref] = {
cache _ RefTab.Create[2, EqualCacheKey, HashCacheKey];
};
CachedEnumerateNeighbors: PUBLIC PROC [decoration: Decoration, touch: PipalMos.TouchProc, inX: BOOL, ct1, ct2: CellType, cache: RefTab.Ref] RETURNS [pairs: LIST OF WirePair _ NIL] = {
EachPair: PROC [wire1, wire2: Wire] RETURNS [quit: BOOL _ FALSE] = {
FOR list: LIST OF WirePair _ pairs, list.rest WHILE list#NIL DO
IF list.first=[wire1, wire2] THEN RETURN;
ENDLOOP;
pairs _ CONS [[wire1, wire2], pairs];
};
ck: REF CacheKeyRec _ NEW [CacheKeyRec _ [decoration, touch, inX, ct1, ct2]];
pairs _ NARROW [RefTab.Fetch[cache, ck].val];
IF pairs#NIL THEN RETURN;
[] _ EnumerateNeighbors[decoration, touch, inX, ct1, ct2, EachPair];
[] _ RefTab.Store[cache, ck, pairs];
};
RegisterRoutingLayer[PipalMos.commentLayer];

END.
��

��PipalCoreImpl.mesa
Copyright Ó 1986, 1987, 1988 by Xerox Corporation.  All rights reserved.
Created by Bertrand Serlet, August 6, 1986 0:38:23 am PDT
Bertrand Serlet May 8, 1988 0:30:38 am PDT
Barth, February 18, 1987 8:19:50 pm PST
Jean-Marc Frailong January 17, 1988 5:41:55 pm PST

Short Cuts
Theory
Previous experience has shown that, if ports are stored in the trivial way [Instances], most of the memory goes into those ports, and that seriously limits the size of designs the DA system can handle.  Therefore, it is important to be able to store ports in a lazy way: every time the time penalty is not too important, recompute ports instead of storing them.  Enumerations are prefered to explicit lists for both storage efficiency [enumerations create less objects] and time efficiency [enumerations may return early].  
Common cases when ports can be recomputed:
Indirection: ports of a given wire are the same as the ones of some other wire.  This is heavily used in PWCore that generates lots of indirections.  The time penalty in that case is a constant time.
Indirection and transformation: ports of a given wire are the same as the ones of some other wire, once applied a geometrical transformation.  This case is very frequent for abuts (think of the vertical wires of lines).  The time penalty is a constant time.
Routing Cell: both ports and geometry can be deduced from the routing object itself.
RecordCell: ports of a public of a RecordCell can always be obtained by enumerating the instances to which the public is bound, assuming that some geometric transformations and some clipping are done.  This is of course a very common case, but the time penalty might be quite high (looping both on instances and bindings).
Common cases when ports can be recorded directly:
Small number of instances.

The implementation of this interface tries to make the best space/time trade-offs using those heuristics.  

Invariant: Port (/geometry) decoration=NIL <=> no pins (/no geometry).  Non-NIL port (/geometry) decoration have at least one atomic child. Therefore when we create a clipped enumeration, we must make sure it's non-empty.
Creating Decoration
Ports

We avoid duplicates 
Object
Geometry


We came from that one from a RecordCell [vertical move]
Enumerates next level instances.
Transformation

Enumeration of Sides for Routers
bbox is the rectangle expressing the AbutBox of the pin in the outer coordinate system.

Fabrication of Shells for Routers or for IO
Font used for the text labels

Checking of Decorations

Neighbors
Initialization
Êg��˜�codešœ™KšœH™HKšœ6Ïk™9Kšœ*™*Kšœ$™'Kšœ/™2—K™�š	˜	Kšœ˜K˜	J˜=Kšœ)˜)K˜KšœB˜BKšœ˜K˜�—šÏn
œœ˜Kšœ¶˜½Kšœ
˜Kšœœœ˜—head™
Kšœœ˜ Kšœ
œ˜$Kšœœœ˜Kšœœ
˜Kšœœ˜.Kšœ
œ˜#Kšœ
œ˜)Kšœœ˜+Kšœœ˜1Kšœ
œ˜#Kšœœ˜+Kšœœ˜Kšœ	œ˜Kšœœ˜/Kšœœ˜%—™bodyšœ´œÖ™ŒMšœ*™*Iitem™ÇN™N™TN™ÂMšœ1™1N™N™�™kM™�—Mšž	œœ"œŽ™Ý——šœ™Kšœœ)œ˜GKšœœ,œ˜Nšœœ,œ˜MK˜�—šžœœœœœœœ˜gšœ
œ˜#Kšœ˜šœ*˜*Kšœ.˜.KšœN˜NKšœ˜—šœ,˜,Kšœ0˜0KšœN˜NKšœ˜—šœ.˜.Kšœ2˜2KšœN˜NKšœ˜—šœ+˜+Kšœ/˜/KšœN˜NKšœ˜—K˜—Kšœœ
œœ˜KšœU˜UKšœS˜SKšœW˜WKšœR˜RK˜K˜�—Kšžœ6œ˜Všžœ=˜KK˜�—KšžœAœ	œ˜~Kšž
œ!œD˜u—™š
žœœœ(œœ˜NKšœ*˜0K˜K˜�—šžœœœ(œ˜VKšœ?˜?Kšœœœ˜Kšœœœ˜#K˜K™�—šžœœœ9˜MKšœœœœ˜Kšœœœ˜#Kšœ>˜>K˜K˜�—šžœœœ9˜MKšœœ˜Kšœœœœ˜Kšœœ	œ˜,Kšœ#˜#Kšœœ	œ˜3Kšœ3˜3K˜K˜�—šžœœœP˜kKšœ	œœœ˜KšœG˜GK˜K˜�—šœœœ%˜=K˜�—šžœœœC˜^Jšœ&œ˜;Jšœ6˜6šžœ˜%Jšœœ˜š
œœœ
œ,œœ˜aKšœœ|˜‡Jšœ˜—Jšœ0˜0J˜—šœœœ˜$Jšœ4˜4Jšœ;˜;šžœ˜&Jšœœœ
œ'˜GJšœ™šœœœœœ˜<Jšœœœ˜-Jšœ˜—Jšœœ˜(Jšœ+˜+Jšœ˜—Jš	œœ*œœÏc'˜cšœKœ˜RJšœV˜V—Jšœ˜—Jšœ6˜6K˜——™š
ž	œœœ.œœ˜VJšœ"œ˜-Kšœ˜K˜�—šž	œœœ.œ˜`Kšœ	œC˜RKšœ˜K˜�—šž	œœœA˜WKšœH˜HK˜——™š
žœœœ&œœ˜PKšœ,˜2K˜K™�—šžœœœ&œ˜\KšœE˜EKšœœœ˜"Kšœ
œœ˜+K˜K™�—šžœœœ;˜SKšœ
œœœ˜Kšœœœ˜+KšœD˜DK˜K˜�—šžœœœ;˜SKšœœ˜Kšœ
œœœ˜Kšœœœ˜9Kšœ)˜)Kšœœœ˜EKšœ:˜:K˜K˜�—šÐbnœœœœ#œœœœ˜ýKšœ7™7šžœ ˜.Jšœ7˜7Jšœ
œœ˜-JšœB˜BJšœGœ,˜vK˜—šž	œÏbœ˜)Jšœ
œœ˜-Kšœ1œ ˜Wšœœ˜"Kšœœœœ[˜”Kšœ˜K˜—šœ(œ˜0šžœ˜(Jšœœ$˜CJšœœœœ˜1Jš	œœœœœ.˜sJ˜—Jšœ"œ
˜5Jšœœœœ;˜tKšœœœ˜Kšœx˜xK˜—Kšœt˜xK˜—KšœZœ˜uK˜K˜�—šžœœœkœœœ˜¬šœ˜šœ ˜ Kšœ)œ
˜<Kšœ2˜2š	œœœœ˜2šžœ˜3K™ šœœ˜Kšœ|˜|—K˜—Kšœ7˜7Kšœr˜rKšœ„˜„Kš˜—Kšœ˜—šœ"˜"Kšœ2˜2—šœ˜Kšœ0˜0Kšœ_˜_KšœLœE˜—K˜——K˜K˜�—šžœœœ6œ˜oKšœœ˜šžœ˜$Kšœœ:˜FK˜—Kšœ@˜@Kšœ!˜!K˜——™š
žœœœ6œœ˜]KšœIœ˜TKšœ˜K™�—šžœœœ6œ˜nKšœ
œœJ˜oKšœ˜Kšœ˜K˜�—šžœœœP˜eKšœGœ˜eK˜——™ šœ,˜,J˜�—šžœœœ˜=Jšœ/˜/J˜J˜�—šžœœœAœ˜yJšœY˜YJ˜J˜�—JšœW™Wšž
œœœ˜OJšœ&˜&JšœH˜HJšœW˜WJšœP˜PJšœN˜NJšœY˜YJ˜J˜�—š
žœœœPœœ˜ƒšžœ%˜1Jšœ)˜)Jšœœ*œœ˜<šœœœ˜JšœIŸ>˜‡Jšœ
œ˜Jšœœœ˜Jšœ
œ
œ7˜VJšœœœ7˜VJšœ)œœ˜7Jšœ˜—J˜—JšœG˜GKšœR˜RJ˜J™�—š
žœœœLœœ˜ƒšžœ˜&KšžœB˜IKšœ*œœŸ˜EJšœ;˜;Jšœ˜—Kšœ+˜+Kšœ;˜;Jšœ˜K˜�—šœœœœ%˜TJ˜�—š
žœœœLœœ˜Jš	œœœœœ˜Jšœœœœ˜šžœ˜"Kšœœœœ˜"Kšœœœœ˜"Kšœ-˜3K˜—šžœ˜ Kšœœœœ)˜@J˜—Kšœ;˜;Kšœœ Ÿ˜Eš
œ	œœœœœ˜AKšœœœœ˜*Kšœœœ˜šœ˜šœœœœœœœ
œ˜IKšœœœœ˜,šœœœœ˜qJšœœ5œ˜Q—Jšœœœ˜!Jšœ˜—Jšœ˜—Kšœ˜—šœœ˜Kšœœœœ˜)KšœN˜NKšœœœ˜Kšœ˜Kšœ˜—K˜K˜�—šœœœœ˜GJ˜�—š
žœœœ\œœ˜•Jš	œœœœœ˜Jšœœœœ˜Jšœ˜šžœ˜!Kšœœœœ˜ Kšœœœœ˜ Kšœ+˜1K˜—šžœ˜ Jš
œœœœœ#˜QJ˜—Kšœ;˜;KšœœŸ˜Dšœœ˜Kšœœœœ˜%Kšœ@˜@Kšœœœ˜Kšœ˜Kšœ˜—K˜——šœ)™+šœ&˜&JšœM˜MJšœ˜J™J™�—šžœœœ=œœœ˜~Kšœœ˜Kšœ+˜+šžœ˜+Jšœœ2˜<Kšœ*œœŸ˜Ešœ
œ˜JšœH˜HJšœ	˜	—šœœ˜šžœ˜šœ˜šœœ˜Kšœ1˜1Kšœ1˜1Kšœœ˜—šœœ˜Kšœ2œ˜B—Kšœ˜—Kšœ
œ2˜@J˜—Jšœ/˜/Jšœ@˜@J˜—J˜—KšœG˜GKšœ$˜$Jšœ>˜>JšœK˜KK˜——™š
žœœœ.œœ˜_Kšž	œœœœœœ˜RKšœ%˜%Kšœ5˜5K˜K™�—š
ž
œœœ,œœ˜\Kšœ#œ˜8Kš
œœ$œœœ˜>šœœœ˜Kšœ%œ	œœ˜B—K˜——™	šžœœœ:œ œœœœœœ˜ÅKšœ*˜*Kšœ*˜*Kšœ-˜-Kšœ-˜-Kšœœœœ˜ZKšœ`˜`Kšœm˜mšžœ˜"Kšœ)˜)Kšœ(œ6˜dJ˜—šžœ˜"Kšœ)˜)Kšœ+˜+šžœœ/œœ˜LKšœ&œœ
˜SK˜—Kšœ9˜9K˜—Kšœ0˜0Kšœ2˜2K˜K˜�—Kšœ
œœ:œ˜nšž
œ˜#Kšœœœ˜%Kšœœœ˜%Kšœ
˜K˜—Kšžœœœœœœœœ˜OKšžœœœœœœœœ
˜Sšžœ˜!Kšœœœ˜#šœ˜šœœ˜šœœ˜Kšœœœ
˜<Kšœœ$˜1Kšœ˜—Kšœ˜K˜—Kšœ˜—K˜—šžœœœœ˜DKšœ6˜6K˜—šžœœœ:œ)œ	œœœ˜·š
žœœœœœ˜Dšœœœœœ˜?Kšœœœ˜)Kšœ˜—Kšœœ˜%K˜—Kšœœœ4˜MKšœœ˜-Kšœœœœ˜JšœD˜DKšœ$˜$K˜——™šœ,˜,K˜�——Kšœ˜—�…—����Of��m×��