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:
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]]};
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:
BOOL ←
FALSE] = {
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:
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 = {
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 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;
};
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:
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];
};
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:
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];
};