<> <> <> <> <> <> <<>> 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; <> <> <> <> <> <> <> <> <> <<>> <> <<>> < 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.>> <> 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] = { 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]; <> 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] = { 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] = { <> 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.