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 11:16:36 pm PDT
Barth, February 18, 1987 8:19:50 pm PST
Jean-Marc Frailong January 17, 1988 5:41:55 pm PST
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;
Short Cuts
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;
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
layoutDecoration: PUBLIC Decoration ← CreateDecoration["Layout", TRUE];
schematicsDecoration: PUBLIC Decoration ← CreateDecoration["Schematic", TRUE];
rawLayoutDecoration: PUBLIC Decoration ← CreateDecoration["RawLayout", TRUE];
CreateDecoration: PUBLIC PROC [name: ROPE, coreSave: BOOLFALSE] 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]]};
Ports
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] = {
IF port=NIL THEN ERROR;
PutPort[decoration, public, Pipal.CreateOv[LIST [port, GetPort[decoration, public]]]];
};
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];
We avoid duplicates
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];
};
Object
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];
};
Geometry
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] = {
IF geometry=NIL THEN ERROR;
PutGeometry[decoration, wire, Pipal.CreateOv[LIST [geometry, GetGeometry[decoration, wire]]]];
};
EnumerateFlatGeometry: PUBLIC PROC [decoration: Decoration, root: CellType, target: FlatCellTypeRec ← CoreFlat.allFlatCells, leafProc: LeafProc, eachFlatWire: EachFlatWireProc ← NIL, eachFlatCell: EachFlatCellProc ← NIL] RETURNS [quit: BOOLFALSE] = {
We came from that one from a RecordCell [vertical move]
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: BOOLFALSE] = {
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 = {
Enumerates next level instances.
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];
};
Transformation
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]];
};
Enumeration of Sides for Routers
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]]];
};
bbox is the rectangle expressing the AbutBox of the pin in the outer coordinate system.
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 REFNIL;
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: BOOLTRUE;
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 REFNIL;
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];
sortedList.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;
};
Fabrication of Shells for Routers or for IO
font: Imager.Font ← ImagerFont.Modify[
ImagerFont.Find["Xerox/TiogaFonts/Helvetica8"], ImagerTransformation.Scale[4]
];
Font used for the text labels
CreateShell: PUBLIC PROC [decoration: Decoration, cellType: CellType, withCuteFonts: BOOLFALSE] 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];
};
Checking of Decorations
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;
};
Neighbors
EnumerateNeighbors: PUBLIC PROC [decoration: Decoration, touch: PipalMos.TouchProc, inX: BOOL, ct1, ct2: CellType, eachPair: PROC [Wire, Wire] RETURNS [quit: BOOLFALSE]] 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: BOOLFALSE] = {
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];
};
Initialization
RegisterRoutingLayer[PipalMos.commentLayer];
END.