<> <> <> <> <> <> <> <> DIRECTORY CD USING [Error, ErrorCode, Instance, Number, Object, Orientation, Position, Rect], CDBasics USING [BaseOfRect, Extend, Intersect, Intersection, NonEmpty, ToRect], CDOrient USING [ComposeOrient, DeMapRect, MapRect, original, RectAt, rotate180, rotate270, rotate90], CStitching USING [Area, IsEmpty, ChangeRect, Rect, EEdge, EN, EnumerateArea, ResetTesselation, ChangeEnumerateArea, ListArea, NE, NewTesselation, NEdge, RectProc, TileProc, Region, SEdge, SW, Tesselation, Tile, FindTile, WEdge, WS], PrincOpsUtils USING [], SX USING [AdjustNode, Circuit, CircuitNode, Constraint, ConstraintResolution, FindRootNode, GeometricRule, LogicalCell, LookupNode, MergeNode, nodeIndex, NormalizeCircuit, spaceIndex, SpinifexLayerIndex], SXAccess USING [design, stopFlag, sxTech], SXAccessInternal USING [GetLogicalCell, PutError], SXLayers USING [], SXQuadTree USING [AreaSplit, Create, Dimension, Enumerate, PerRectProc, QuadTree, QuadTreeRoot, Rectangle, Rectangles], TerminalIO USING [WriteRope]; SXLayersImpl: CEDAR PROGRAM IMPORTS CD, CDBasics, CDOrient, CStitching, SX, SXAccess, SXAccessInternal, SXQuadTree, TerminalIO EXPORTS SXLayers = BEGIN <> TilePtr: TYPE = CStitching.Tile; nothing: REF INT ~ NEW [INT]; Constraint: TYPE = SX.Constraint; Rectangle: TYPE = SXQuadTree.Rectangle; Node: TYPE = SX.CircuitNode; ConflictWorlds: TYPE = ARRAY SX.SpinifexLayerIndex OF CStitching.Tesselation; <> GeometryWorlds: TYPE = ARRAY SX.SpinifexLayerIndex OF CStitching.Tesselation; <> ConstraintQueue: TYPE = ARRAY SX.SpinifexLayerIndex OF LIST OF REF CStitching.Region _ ALL[NIL]; <> conflictWorlds: ConflictWorlds; <> geometryWorlds: GeometryWorlds; <> <> saveTesselations: BOOL _ FALSE; freeTesselations: BOOL _ FALSE; <> UseLevelOrderHeuristic: PROC [clipRect: CD.Rect, old, new: SXQuadTree.Rectangles] RETURNS [BOOLEAN] = BEGIN <> ThinLimit: CD.Number = SXAccess.design.technology.lambda * 10; RETURN [(clipRect.x2 - clipRect.x1 > ThinLimit) AND (clipRect.y2 - clipRect.y1 > ThinLimit)] END; -- UseLevelOrderHeuristic ComputeConflicts: PROC [ qt: REF SXQuadTree.QuadTree, conflictWorld: CStitching.Tesselation, layer: SX.SpinifexLayerIndex, cir: REF SX.Circuit] = BEGIN <> descentDepth: INT _ 1; <<4 things are put into the conflictWorld they are:>> <> <> <> <> OccupyByNode: CStitching.RectProc = BEGIN <<[plane: REF Tesselation, rect: Rect, new: REF _ NIL] >> WITH oldValue SELECT FROM a: ATOM => IF a # $Conflict THEN CD.Error [ec: other, explanation: "Tesselation screwed up (alien tile)"]; <> r: REF Rectangle => IF data # r THEN <> CStitching.ChangeRect [conflictWorld, rect, $Conflict]; s: SXQuadTree.Rectangles => <> IF data # s.first THEN BEGIN CStitching.ChangeRect [conflictWorld, rect, data]; Flatten [rect, s] END ELSE CD.Error [ec: other, explanation: "Quad-tree screwed up (subcell found twice)"]; c: REF Constraint => IF NOT SameConstraints [ResolveConstraints [c, data, SXAccess.sxTech.constraintResolutions[layer]], data] THEN CStitching.ChangeRect [conflictWorld, rect, $Conflict]; <> ENDCASE => IF oldValue = NIL THEN <> CStitching.ChangeRect [conflictWorld, rect, data] ELSE CD.Error [ec: other, explanation: "Tesselation screwed up (alien tile)"] END; -- OccupyByNode OccupyByConstr: CStitching.RectProc = BEGIN <<[plane: REF Tesselation, rect: Rect, new: REF _ NIL] >> WITH oldValue SELECT FROM a: ATOM => IF a # $Conflict THEN CD.Error [ec: other, explanation: "Tesselation screwed up (alien tile)"]; <> r: REF Rectangle => IF NOT SameConstraints [ResolveConstraints[NARROW[data], r, SXAccess.sxTech.constraintResolutions[layer]], r] THEN CStitching.ChangeRect [conflictWorld, rect, $Conflict]; s: SXQuadTree.Rectangles => BEGIN conflictWorld.ChangeRect[rect, data]; Flatten [rect, s] END; c: REF Constraint => BEGIN <> resolution: REF ANY = ResolveConstraints [c, data, SXAccess.sxTech.constraintResolutions [layer]]; IF (NOT SameConstraints[resolution, c] AND NOT SameConstraints[resolution, data]) THEN CStitching.ChangeRect [conflictWorld, rect, $Conflict] ELSE IF NOT SameConstraints[resolution, c] THEN CStitching.ChangeRect [conflictWorld, rect, resolution]; END; ENDCASE => <> IF oldValue = NIL THEN <> CStitching.ChangeRect [conflictWorld, rect, data] ELSE CD.Error [ec: other, explanation: "Tesselation screwed up (alien tile)"] END; -- OccupyByConstr OccupyByAppl: CStitching.RectProc = BEGIN <<[plane: REF Tesselation, rect: Rect, new: REF _ NIL] >> <> WITH oldValue SELECT FROM a: ATOM => IF a # $Conflict THEN CD.Error [ec: other, explanation: "Tesselation screwed up (alien tile)"]; <> r: REF Rectangle => BEGIN IF NARROW[data, SXQuadTree.Rectangles].first = r THEN CD.Error [ec: other, explanation: "Rectangle has already been processed"]; Flatten [rect, NARROW[data]] END; s: SXQuadTree.Rectangles => IF data # s THEN IF UseLevelOrderHeuristic [rect, s, NARROW[data]] THEN DescendOneLevel [rect, s, NARROW[data]] ELSE BEGIN <> CStitching.ChangeRect [conflictWorld, rect, NIL]; <> Flatten [rect, s]; Flatten [rect, NARROW[data]] END; <> c: REF Constraint => Flatten [rect, NARROW[data]]; ENDCASE => IF oldValue = NIL THEN <> CStitching.ChangeRect [conflictWorld, rect, data] ELSE CD.Error [ec: other, explanation: "Tesselation screwed up (alien tile)"] END; -- OccupyByAppl Flatten: PROC [clipRect: CD.Rect, applRef: SXQuadTree.Rectangles] = BEGIN appl: CD.Instance = NARROW [applRef.first.nodeInformation]; FlattenCell: PROC [appl: CD.Instance, pos: CD.Position, orient: CD.Orientation] = BEGIN MapRect: PROC [inCellRect: CD.Rect] RETURNS [inWorldRect: CD.Rect] = INLINE BEGIN inWorldRect _ CDBasics.Intersection [ CDOrient.MapRect [itemInCell: inCellRect, cellSize: appl.ob.size, cellInstOrient: orient, cellInstPos: pos], clipRect] END; -- MapRect FlattenTree: PROC [qt: REF SXQuadTree.QuadTree] = BEGIN <<(local of FlattenCell, local of Flatten)>> FOR boxes: SXQuadTree.Rectangles _ qt.boxes, boxes.rest WHILE boxes#NIL DO WITH boxes.first.nodeInformation SELECT FROM node: REF Node => { r: CD.Rect = MapRect [boxes.first.interestBound]; IF CDBasics.NonEmpty[r] THEN CStitching.ChangeEnumerateArea [conflictWorld, r, OccupyByNode, applRef.first, nothing] }; constr: REF Constraint => { r: CD.Rect = MapRect[boxes.first.interestBound]; IF CDBasics.NonEmpty[r] THEN CStitching.ChangeEnumerateArea [conflictWorld, r, OccupyByConstr, constr, nothing] }; subAppl: CD.Instance => IF CDBasics.Intersect [boxes.first.interestBound, mappedClip] THEN { FlattenCell [ subAppl, CDBasics.BaseOfRect [CDOrient.MapRect [ itemInCell: CDOrient.RectAt [pos: subAppl.location, size: subAppl.ob.size, orient: subAppl.orientation], cellSize: appl.ob.size, cellInstOrient: orient, cellInstPos: pos]], CDOrient.ComposeOrient [subAppl.orientation, orient]] }; ENDCASE => ERROR; -- Quad tree srewed up ENDLOOP; <> IF SXAccess.stopFlag^ THEN ERROR ABORTED; IF mappedClip.y2>qt.midY AND qt.subTrees[north]#NIL THEN FlattenTree[qt.subTrees[north]]; IF mappedClip.y1qt.midX AND qt.subTrees[east]#NIL THEN FlattenTree[qt.subTrees[east]]; IF mappedClip.x1> levelCount: INT; BidByNode: CStitching.RectProc = BEGIN <<[plane: REF Tesselation, rect: Rect, oldValue: REF, data: REF] >> WITH oldValue SELECT FROM a: ATOM => IF a # $Conflict THEN CD.Error [ec: other, explanation: "Tesselation screwed up (alien tile)"]; r: REF Rectangle => IF data # r THEN CD.Error [ec: other, explanation: "Tesselation screwed up"]; s: SXQuadTree.Rectangles => CStitching.ChangeRect [conflictWorld, rect, data]; c: REF Constraint => CStitching.ChangeRect [conflictWorld, rect, data]; ENDCASE => ERROR END; -- BidByNode BidByConstr: CStitching.RectProc = BEGIN <<[plane: REF Tesselation, rect: Rect, oldValue: REF, data: REF] >> WITH oldValue SELECT FROM a: ATOM => IF a # $Conflict THEN CD.Error [ec: other, explanation: "Tesselation screwed up (alien tile)"]; r: REF Rectangle => IF new.first # r THEN CD.Error [ec: other, explanation: "Tesselation screwed up"]; s: SXQuadTree.Rectangles => IF s # new THEN CStitching.ChangeRect [conflictWorld, rect, data]; c: REF Constraint => BEGIN resolution: REF ANY = ResolveConstraints [c, data, SXAccess.sxTech.constraintResolutions [layer]]; IF NOT SameConstraints [resolution, c] THEN CStitching.ChangeRect [conflictWorld, rect, resolution]; END; ENDCASE => ERROR; END; -- BidByConstr BidByAppl: CStitching.RectProc = BEGIN <<[plane: REF Tesselation, rect: Rect, oldValue: REF, data: REF] >> WITH oldValue SELECT FROM a: ATOM => IF a # $Conflict THEN CD.Error [ec: other, explanation: "Tesselation screwed up (alien tile)"]; r: REF Rectangle => IF NARROW[data, SXQuadTree.Rectangles].first # r THEN CD.Error [ec: other, explanation: "Tesselation screwed up"]; s: SXQuadTree.Rectangles => IF data # s THEN CStitching.ChangeRect [conflictWorld, rect, data]; c: REF Constraint => CStitching.ChangeRect [conflictWorld, rect, data]; ENDCASE => ERROR; END; -- BidByAppl DescendCell: PROC [appl: CD.Instance, pos: CD.Position, orient: CD.Orientation] = BEGIN MapRect: PROC [inCellRect: CD.Rect] RETURNS [inWorldRect: CD.Rect] = INLINE BEGIN <<(local of DescendCell, local of DescendOneLevel)>> inWorldRect _ CDBasics.Intersection [ CDOrient.MapRect [ itemInCell: inCellRect, cellSize: appl.ob.size, cellInstOrient: orient, cellInstPos: pos], clipRect] END; -- MapRect DescendTree: PROC [qt: REF SXQuadTree.QuadTree] = BEGIN <<(local of DescendCell, local of DescendOneLevel)>> IF qt=NIL THEN RETURN; FOR boxes: SXQuadTree.Rectangles _ qt.boxes, boxes.rest WHILE boxes#NIL DO WITH boxes.first.nodeInformation SELECT FROM node: REF Node => { r: CD.Rect = MapRect [boxes.first.interestBound]; IF CDBasics.NonEmpty[r] THEN CStitching.ChangeEnumerateArea [conflictWorld, r, BidByNode, new.first, nothing] }; constr: REF Constraint => { r: CD.Rect = MapRect [boxes.first.interestBound]; IF CDBasics.NonEmpty[r] THEN CStitching.ChangeEnumerateArea [conflictWorld, r, BidByConstr, constr, nothing] }; subAppl: CD.Instance => IF CDBasics.Intersect [boxes.first.interestBound, mappedClip] THEN { IF levelCount > 0 THEN DescendCell [ subAppl, CDBasics.BaseOfRect [CDOrient.MapRect [ itemInCell: CDOrient.RectAt [pos: subAppl.location, size: subAppl.ob.size, orient: subAppl.orientation], cellSize: appl.ob.size, cellInstOrient: orient, cellInstPos: pos]], CDOrient.ComposeOrient [subAppl.orientation, orient]] ELSE { r: CD.Rect = MapRect [boxes.first.interestBound]; IF CDBasics.NonEmpty[r] THEN CStitching.ChangeEnumerateArea [conflictWorld, r, BidByAppl, new, nothing] } }; ENDCASE => ERROR; ENDLOOP; IF mappedClip.y2 > qt.midY AND qt.subTrees[north] # NIL THEN DescendTree [qt.subTrees[north]]; IF mappedClip.y1qt.midX AND qt.subTrees[east]#NIL THEN DescendTree [qt.subTrees[east]]; IF mappedClip.x1> cellQt: REF SXQuadTree.QuadTree; mappedClip: CD.Rect = CDOrient.DeMapRect [itemInWorld: clipRect, cellSize: appl.ob.size, cellInstOrient: orient, cellInstPos: pos]; cellQt _ SXAccessInternal.GetLogicalCell[appl.ob].circuit.spinifexLayers[layer].geometry; levelCount _ levelCount-1; DescendTree [cellQt]; levelCount _ levelCount+1; END; -- DescendCell appl: CD.Instance = NARROW [new.first.nodeInformation]; descentDepth _ descentDepth + 1; levelCount _ descentDepth/2; -- Descend until levelCount = 0 DescendCell [appl, appl.location, appl.orientation]; CStitching.ChangeEnumerateArea [conflictWorld, clipRect, OccupyByAppl, old, nothing]; descentDepth _ descentDepth -1 END; -- DescendOneLevel <
> <> IF qt = NIL THEN RETURN; FOR boxes: SXQuadTree.Rectangles _ qt.boxes, boxes.rest WHILE boxes#NIL DO WITH boxes.first.nodeInformation SELECT FROM node: REF Node => <> CStitching.ChangeEnumerateArea [conflictWorld, boxes.first.interestBound, OccupyByNode, boxes.first, nothing]; constr: REF Constraint => CStitching.ChangeEnumerateArea [conflictWorld, boxes.first.interestBound, OccupyByConstr, constr, nothing]; appl: CD.Instance => CStitching.ChangeEnumerateArea [conflictWorld, boxes.first.interestBound, OccupyByAppl, boxes, nothing]; <> ENDCASE => ERROR; ENDLOOP; FOR quad: SXQuadTree.AreaSplit IN SXQuadTree.AreaSplit DO ComputeConflicts [qt.subTrees[quad], conflictWorld, layer, cir] <> ENDLOOP; IF descentDepth#1 THEN CD.Error [ec: other, explanation: "ComputeConflicts: descentDepth#1"] END; -- ComputeConflicts SameConstraints: PROC [c1, c2: REF ANY] RETURNS [BOOLEAN] = { IF c1 = c2 THEN RETURN[TRUE]; WITH c1 SELECT FROM con1: REF Constraint => { WITH c2 SELECT FROM con2: REF Constraint => RETURN [con1.name = con2.name]; ENDCASE => RETURN [FALSE]; }; ENDCASE => RETURN[FALSE]; }; -- SameConstraints ResolveConstraints: PROC [newConstraint: REF Constraint, oldValue: REF ANY, resolution: REF SX.ConstraintResolution] RETURNS [REF ANY] = BEGIN <> <> WITH oldValue SELECT FROM oldConstraint: REF Constraint => { specificNode: REF SX.CircuitNode _ NIL; result: REF Constraint _ resolution[newConstraint.index][oldConstraint.index]; IF result=NIL THEN CD.Error[ec~ other, explanation~ "Invalid ConstraintResolution"]; specificNode _ IF newConstraint.specificCorrespondingNode # NIL THEN newConstraint.specificCorrespondingNode ELSE oldConstraint.specificCorrespondingNode; <> <> IF specificNode # NIL THEN { result _ NEW[Constraint _ result^]; result.specificCorrespondingNode _ specificNode}; RETURN [result] }; -- end oldConstraint: REF CircuitConstraint node: REF Node => { result: REF Constraint _ resolution[newConstraint.index][SX.nodeIndex]; IF result=NIL THEN RETURN [node] ELSE { IF newConstraint.specificCorrespondingNode # NIL THEN { result _ NEW[Constraint _ result^]; result.specificCorrespondingNode _ newConstraint.specificCorrespondingNode}; RETURN [result]}; }; rect: REF Rectangle => { result: REF Constraint _ resolution[newConstraint.index][SX.nodeIndex]; IF result=NIL THEN RETURN [rect] ELSE { IF newConstraint.specificCorrespondingNode # NIL THEN { result _ NEW[Constraint _ result^]; result.specificCorrespondingNode _ newConstraint.specificCorrespondingNode}; RETURN [result]}; }; ENDCASE => ERROR END; -- ResolveConstraints <> <<[BloatConflictsIntoAOIs (AOI = Area Of Interest)]>> BloatConflictsIntoAOIs: PROC [ cir: REF SX.Circuit, layer: SX.SpinifexLayerIndex, conflictWorld: CStitching.Tesselation] RETURNS [cleanedConflictWorld: CStitching.Tesselation] = BEGIN <> CopyBloated: CStitching.TileProc = BEGIN <<[tile: TilePtr, data: REF ANY] RETURNS [REF ANY] >> IF tile.value = $Conflict THEN cleanedConflicts.ChangeRect [ rect: CDBasics.Extend[tile.Area, bloatValue], new: $AOI]; END; -- CopyBloated bloatValue: INT _ SXAccess.sxTech.layerInterestBloat [layer]; cleanedConflicts: CStitching.Tesselation _ CStitching.NewTesselation []; [] _ conflictWorld.EnumerateArea [cir.spinifexLayers[layer].size, CopyBloated]; CStitching.ResetTesselation [conflictWorld]; cleanedConflictWorld _ cleanedConflicts; END; -- BloatConflictsIntoAOIs InstantiateAOIs: PROC [ cir: REF SX.Circuit, qt: REF SXQuadTree.QuadTree, cellBBox: CD.Rect, flatLoc: CD.Position _ [0, 0], flatOrient: CD.Orientation _ CDOrient.original, appl: CD.Instance _ NIL, nameQualifier: LIST OF CD.Instance _ NIL, layer: SX.SpinifexLayerIndex, conflictWorld: CStitching.Tesselation, geometryWorld: CStitching.Tesselation, constraintQueue: ConstraintQueue] RETURNS [newConstraintQueue: ConstraintQueue] = BEGIN <> InstantiateTree: PROC [qt: REF SXQuadTree.QuadTree, qtBranchBox: CD.Rect] = BEGIN EnqueueConstraintRegion: PROC [cc: REF Constraint, r: CStitching.Rect] = BEGIN constraintQueue[layer] _ CONS [ NEW [CStitching.Region _ [rect: r, value: cc]], constraintQueue[layer]] END; -- EnqueueConstraintRegion <> branchBox: CD.Rect = CDOrient.MapRect [itemInCell: qtBranchBox, cellSize: (IF appl=NIL THEN [0, 0] ELSE appl.ob.size), cellInstOrient: flatOrient, cellInstPos: flatLoc]; IF conflictWorld.IsEmpty [branchBox] THEN RETURN; FOR boxes: SXQuadTree.Rectangles _ qt.boxes, boxes.rest WHILE boxes#NIL DO mappedDim: CD.Rect = CDOrient.MapRect [ itemInCell: SXQuadTree.Dimension [boxes.first], cellSize: (IF appl=NIL THEN [0, 0] ELSE appl.ob.size), cellInstOrient: flatOrient, cellInstPos: flatLoc]; IF NOT conflictWorld.IsEmpty[mappedDim] THEN { WITH boxes.first.nodeInformation SELECT FROM subAppl: CD.Instance => { cellQt: REF SXQuadTree.QuadTree; subcellBBox: CD.Rect; rect: CD.Rect = CDOrient.RectAt [pos: subAppl.location, size: subAppl.ob.size, orient: subAppl.orientation]; mappedRect: CD.Rect = CDOrient.MapRect [itemInCell: rect, cellSize: (IF appl=NIL THEN [0, 0] ELSE appl.ob.size), cellInstOrient: flatOrient, cellInstPos: flatLoc]; orient: CD.Orientation = CDOrient.ComposeOrient [ itemOrientInCell: subAppl.orientation, cellOrientInWorld: flatOrient]; [size: subcellBBox, geometry: cellQt] _ SXAccessInternal.GetLogicalCell[subAppl.ob].circuit.spinifexLayers[layer]; IF cellQt = NIL THEN LOOP; constraintQueue _ InstantiateAOIs [qt: cellQt, cellBBox: subcellBBox, flatLoc: CDBasics.BaseOfRect [mappedRect], flatOrient: orient, appl: subAppl, nameQualifier: CONS [subAppl, nameQualifier], -- following are the parameters added in the restructuration: -- cir: cir, layer: layer, conflictWorld: conflictWorld, geometryWorld: geometryWorld, constraintQueue: constraintQueue]; }; -- end rectangle is a subcell cNode: REF SX.CircuitNode => { <> name: REF SX.CircuitNode = IF (nameQualifier=NIL) THEN cNode ELSE cir.FindRootNode [subcircuitNode: cNode, qualifier: nameQualifier, insertIfNotInCircuit: TRUE].node; occupants: LIST OF REF CStitching.Region _ NARROW[geometryWorld.ListArea[mappedDim] ]; newList: LIST OF REF SX.CircuitNode _ LIST[name]; geometryWorld.ChangeRect [rect: mappedDim, new: newList]; WHILE occupants # NIL DO IF NOT conflictWorld.IsEmpty[occupants.first.rect] THEN WITH occupants.first.value SELECT FROM oldList: LIST OF REF SX.CircuitNode => -- oldList forms shared tail in all multiply occupied areas. Subsequent processing allows this. We must ensure that each node appears only once and that the list head is unique. IF ~(oldList.first = name AND oldList.rest=NIL) THEN { old: LIST OF REF SX.CircuitNode _ oldList; replaceList: LIST OF REF SX.CircuitNode; WHILE old#NIL DO <> IF old.first = name THEN EXIT; old _ old.rest; ENDLOOP; replaceList _ IF old#NIL THEN CONS [oldList.first, oldList.rest] ELSE CONS [name, oldList]; geometryWorld.ChangeRect [rect: occupants.first.rect, new: replaceList] }; ENDCASE => ERROR; occupants _ occupants.rest; ENDLOOP; }; -- end rectangle is a node cc: REF Constraint => EnqueueConstraintRegion[cc, mappedDim]; ENDCASE => ERROR -- This type not expected in quad tree } ENDLOOP; -- instantiate all rectangles in this Quad Tree node { IF qt.subTrees[north] # NIL THEN InstantiateTree [qt.subTrees[north], [x1: qtBranchBox.x1, y1: qt.midY, x2: qtBranchBox.x2, y2: qtBranchBox.y2]]; IF qt.subTrees[south] # NIL THEN InstantiateTree [qt.subTrees[south], [x1: qtBranchBox.x1, y1: qtBranchBox.y1, x2: qtBranchBox.x2, y2: qt.midY]]; IF qt.subTrees[east] # NIL THEN InstantiateTree [qt.subTrees[east], [x1: qt.midX, y1: qtBranchBox.y1, x2: qtBranchBox.x2, y2: qtBranchBox.y2]]; IF qt.subTrees[west] # NIL THEN InstantiateTree [qt.subTrees[west], [x1: qtBranchBox.x1, y1: qtBranchBox.y1, x2: qt.midX, y2: qtBranchBox.y2]]; } END; -- InstantiateTree <<>> <
> InstantiateTree [qt, cellBBox]; newConstraintQueue _ constraintQueue END; -- InstantiateAOIs AnalyzeNodesInAOIs: PROC [ cir: REF SX.Circuit, layer: SX.SpinifexLayerIndex, geometryWorld: CStitching.Tesselation] = BEGIN <> MergeNodeTiles: CStitching.TileProc = BEGIN <<[tile: TilePtr, data: REF ANY] RETURNS [REF ANY]>> <> <> CountEdge: PROC [nl1, nl2: LIST OF REF SX.CircuitNode] RETURNS [INT] = BEGIN <> InAButNotB: PROC [a,b: LIST OF REF SX.CircuitNode] RETURNS [c: INT _ 0] = BEGIN FOR s1: LIST OF REF SX.CircuitNode _ a, s1.rest WHILE s1#NIL DO s2: LIST OF REF SX.CircuitNode _ b; WHILE s2#NIL DO IF s1.first=s2.first THEN EXIT; -- Shared sources. s2 _ s2.rest; ENDLOOP; IF s2=NIL THEN c _ c+1; -- node in s1 not in s2 ENDLOOP; END; -- InAButNotB RETURN [InAButNotB[a: nl1, b: nl2] + InAButNotB[a: nl2, b: nl1]] END; -- CountEdge <> IF SXAccess.stopFlag^ THEN ERROR ABORTED; WITH tile.value SELECT FROM cnList: LIST OF REF SX.CircuitNode => { <> list: LIST OF REF SX.CircuitNode _ cnList.rest; eastBound: INT = tile.EEdge; northBound: INT = tile.NEdge; westBound: INT = tile.WEdge; southBound: INT = tile.SEdge; r: CD.Rect = tile.Area; extraNodes: INT _ 0; n1: REF SX.CircuitNode = SX.LookupNode [cnList.first]; WHILE list # NIL DO n2: REF SX.CircuitNode = SX.LookupNode [list.first]; IF n1 # n2 THEN cir.MergeNode [to: n1, from: n2]; <> SX.AdjustNode [node: n1, layer: layer, area: -((r.x2 - r.x1)*(r.y2 - r.y1)), perim: 0]; extraNodes _ extraNodes+1; list _ list.rest; ENDLOOP; <> <> FOR tileSouth: TilePtr _ tile.WS, tileSouth.NE WHILE tileSouth.WEdge < eastBound DO IF tileSouth.value#NIL THEN WITH tileSouth.value SELECT FROM cnSouthList: LIST OF REF SX.CircuitNode => { n2: REF SX.CircuitNode = SX.LookupNode [cnSouthList.first]; IF n1 # n2 THEN cir.MergeNode [to: n1, from: n2]; SX.AdjustNode [node: n1, layer: layer, area: 0, perim: -(CountEdge[cnList, cnSouthList] * (MIN[eastBound, tileSouth.EEdge] - MAX[westBound, tileSouth.WEdge]))] }; constraint: REF Constraint => NULL; -- Ignore ENDCASE => ERROR ELSE -- tileSouth.value=NIL IF extraNodes > 0 THEN SX.AdjustNode [node: n1, layer: layer, area: 0, perim: -(extraNodes * (MIN[eastBound, tileSouth.EEdge] - MAX[westBound, tileSouth.WEdge]))] ENDLOOP; -- end FOR tileSouth FOR tileWest: TilePtr _ tile.SW, tileWest.EN WHILE tileWest.SEdge < northBound DO IF tileWest.value#NIL THEN WITH tileWest.value SELECT FROM cnWestList: LIST OF REF SX.CircuitNode => { n2: REF SX.CircuitNode; IF n1 # (n2_SX.LookupNode[cnWestList.first]) THEN cir.MergeNode [to: n1, from: n2]; SX.AdjustNode [node: n1, layer: layer, area: 0, perim: -(CountEdge[cnList, cnWestList] * (MIN[northBound, tileWest.NEdge] - MAX[southBound, tileWest.SEdge]))] }; constraint: REF Constraint => NULL; -- Ignore ENDCASE => ERROR ELSE IF extraNodes > 0 THEN SX.AdjustNode [node: n1, layer: layer, area: 0, perim: -(extraNodes * (MIN[northBound,tileWest.NEdge] - MAX[southBound,tileWest.SEdge]))] ENDLOOP; -- tileWest FOR tileNorth: TilePtr _ tile.EN, tileNorth.SW WHILE tileNorth.EEdge > westBound DO IF (tileNorth.value = NIL) AND (extraNodes > 0) THEN SX.AdjustNode [node: n1, layer: layer, area: 0, perim: -(extraNodes * (MIN[eastBound, tileNorth.EEdge] - MAX[westBound, tileNorth.WEdge]))] ENDLOOP; -- tileNorth FOR tileEast: TilePtr _ tile.NE, tileEast.WS WHILE tileEast.NEdge > southBound DO IF (tileEast.value=NIL) AND (extraNodes > 0) THEN SX.AdjustNode [node: n1, layer: layer, area: 0, perim: -(extraNodes * (MIN[northBound, tileEast.NEdge] - MAX[southBound, tileEast.SEdge]))] ENDLOOP; -- tileEast }; ENDCASE => ERROR END; -- MergeNodeTiles <> [] _ geometryWorld.EnumerateArea [rect: cir.spinifexLayers[layer].size, eachTile: MergeNodeTiles]; END; -- AnalyzeNodesInAOIs <> MixRec: TYPE = RECORD [newConstraint: REF Constraint, rect: CD.Rect, resolution: REF SX.ConstraintResolution, tilesToPaint: LIST OF REF CStitching.Region]; CheckRec: TYPE = RECORD [conflictWorld: CStitching.Tesselation, geometryWorld: CStitching.Tesselation, rules: LIST OF REF SX.GeometricRule, cell: REF SX.LogicalCell, cir: REF SX.Circuit]; DesignRuleCheckAOIs: PROC [ cir: REF SX.Circuit, cell: REF SX.LogicalCell, constraintQueue: ConstraintQueue, layer: SX.SpinifexLayerIndex, geometryWorld: CStitching.Tesselation, conflictWorld: CStitching.Tesselation] = BEGIN <> <> <> <> <> mixRef: REF MixRec = NEW [MixRec]; -- used to transfer parameters to MixConstraints checkRef: REF CheckRec = NEW[CheckRec]; -- used to transfer parameters to CheckTile << First add the constraint regions to the geometry.>> FOR newCc: LIST OF REF CStitching.Region _ constraintQueue[layer], newCc.rest WHILE newCc#NIL DO mixRef^ _ [newConstraint: NARROW [newCc.first.value], rect: newCc.first.rect, resolution: SXAccess.sxTech.constraintResolutions[layer], tilesToPaint: NIL]; [] _ geometryWorld.EnumerateArea [rect: mixRef.rect, eachTile: MixConstraints, skip: $Nothing, data: mixRef]; FOR tilesToPaint: LIST OF REF CStitching.Region _ mixRef.tilesToPaint, tilesToPaint.rest WHILE tilesToPaint#NIL DO geometryWorld.ChangeRect [rect: tilesToPaint.first.rect, new: tilesToPaint.first.value] ENDLOOP; ENDLOOP; <> checkRef^ _ [conflictWorld: conflictWorld, geometryWorld: geometryWorld, cell: cell, cir: cir, rules: SXAccess.sxTech.rules[layer]]; [] _ geometryWorld.EnumerateArea [rect: cir.spinifexLayers[layer].size, eachTile: CheckTile, skip: $Nothing, data: checkRef] END; -- DesignRuleCheckAOIs MixConstraints: CStitching.TileProc = BEGIN <> <<[tile: TilePtr, data: REF ANY] RETURNS [REF ANY] >> mixRef: REF MixRec = NARROW [data]; newval: REF ANY _ mixRef.newConstraint; IF (tile.value = NIL) OR (tile.value # (newval _ ResolveConstraints [mixRef.newConstraint, tile.value, mixRef.resolution])) THEN mixRef.tilesToPaint _ CONS [ NEW [CStitching.Region _ [rect: CDBasics.Intersection [mixRef.rect, tile.Area], value: newval]], mixRef.tilesToPaint] END; -- MixConstraints FindNode: PROC [handle: REF CheckRec, nodeLayer: SX.SpinifexLayerIndex, r: CD.Rect] RETURNS [REF ANY] = BEGIN <> node: REF SX.CircuitNode; FoundIt: SIGNAL [n: REF SX.CircuitNode]; { ENABLE FoundIt => {node _ n; GOTO Done}; FindNodeInner: PROC [circuit: REF SX.Circuit, rect: CD.Rect, aChain: LIST OF CD.Instance] = BEGIN SearchForNode: SXQuadTree.PerRectProc = BEGIN <<[r: REF SXQuadTree.Rectangle, data: REF ANY]>> <<(local of FindNodeInner, local of FindNode, local of DesignRuleCheckAOIs, local of AnalyzeGeometry)>> WITH r.nodeInformation SELECT FROM n: REF SX.CircuitNode => IF CDBasics.Intersect[r.Dimension, rect] THEN { parentNode: REF SX.CircuitNode; newChain: LIST OF CD.Instance; [parentNode, newChain] _ handle.cir.FindRootNode[n, aChain]; IF newChain=NIL THEN SIGNAL FoundIt[parentNode] }; a: CD.Instance => { <> subcir: REF SX.Circuit = SXAccessInternal.GetLogicalCell[a.ob].circuit; subR: CD.Rect = CDOrient.DeMapRect [itemInWorld: rect, cellSize: a.ob.size, cellInstOrient: a.orientation, cellInstPos: a.location ]; FindNodeInner[subcir, subR, CONS[a, aChain]]; }; ENDCASE; END; -- SearchForNode <> SXQuadTree.Enumerate [circuit.spinifexLayers[nodeLayer], rect, SearchForNode, NIL] END; -- FindNodeInner FindNodeInner[handle.cir, r, NIL]; RETURN [NEW[INT]]; EXITS Done => RETURN [node]; } END; -- FindNode CheckTile: CStitching.TileProc = BEGIN <<[tile: TilePtr, data: REF ANY] RETURNS [REF ANY] >> <> Quadrants: TYPE = {ne, nw, sw, se}; DesignRuleCheckCorner: PROC [quadVals: ARRAY Quadrants OF REF ANY, pos: CD.Position] = BEGIN CheckArea: PROC [rule: REF SX.GeometricRule, orient: CD.Orientation, flavour: { convex, concave}] = BEGIN FindNodeAtCorner: PROC [n: REF ANY] RETURNS [REF ANY] = BEGIN WITH n SELECT FROM cn: REF SX.CircuitNode => RETURN [cn]; cc: REF Constraint => { IF cc.specificCorrespondingNode # NIL THEN RETURN[SX.LookupNode[cc.specificCorrespondingNode]]; --Bowers, September 4, 1985 2:10:58 pm PDT IF ~cc.hasCorrespondingNode THEN CD.Error[ec: other, explanation: "FindNodeAtCorner: ~cc.hasCorrespondingNode"]; RETURN [FindNode[handle, cc.correspondingNodeLayer, CDBasics.Extend[CDBasics.ToRect[pos, pos], 1]] ] }; ENDCASE => RETURN [NEW[INT]]; END; FindNodeInTile: PROC [n: REF ANY, area: CD.Rect] RETURNS [REF ANY] = BEGIN WITH n SELECT FROM cn: REF SX.CircuitNode => RETURN [cn]; cc: REF Constraint => { IF ~cc.hasCorrespondingNode THEN CD.Error[ec: other, explanation: "FindNodeInTile: ~cc.hasCorrespondingNode"]; RETURN [FindNode[handle, cc.correspondingNodeLayer, area]] }; ENDCASE => RETURN [NEW[INT]]; END; CheckTileValue: CStitching.TileProc = BEGIN <> CheckValue[tile.value, tile.Area] END; CheckValue: PROC [value: REF ANY, area: CD.Rect] = BEGIN <> <> <> <> IF SXAccess.stopFlag^ THEN ERROR ABORTED; WITH value SELECT FROM cn: REF SX.CircuitNode => { IF ~rule.trigger2[SX.nodeIndex] THEN RETURN; IF (rule.okIfConnected AND nodeAtCorner#NIL AND FindNodeAtCorner[nodeAtCorner] = SX.LookupNode[cn]) THEN RETURN; }; cc: REF Constraint => { IF ~rule.trigger2[cc.index] THEN RETURN; IF (rule.okIfConnected AND nodeAtCorner#NIL AND cc.hasCorrespondingNode AND FindNodeAtCorner[nodeAtCorner] = FindNodeInTile[cc, area] OR (cc.specificCorrespondingNode # NIL AND FindNodeAtCorner[nodeAtCorner] = SX.LookupNode[cc.specificCorrespondingNode])) THEN RETURN; }; cnList: LIST OF REF SX.CircuitNode => CD.Error[ec: other, explanation: "CheckValue: found a list of circuit nodes where a single one was expected"]; ENDCASE => { IF value=NIL THEN { IF ~rule.trigger2[SX.spaceIndex] THEN RETURN; } ELSE CD.Error [ec: other, explanation: "CheckValue: value # NIL"] }; <> IF notReportedYet AND conflictWorld.IsEmpty[ rect: CDOrient.MapRect[ itemInCell: [x1: -delta, y1: -delta, x2: len, y2: len], cellSize: [0, 0], cellInstOrient: orient, cellInstPos: pos ], skip: $AOI] THEN { -- FOUND AN ERROR rect: CD.Rect = CDOrient.MapRect [ itemInCell: [x1: 0, y1: 0, x2: rule.extent, y2: rule.extent], cellSize: [0, 0], cellInstOrient: orient, cellInstPos: pos]; SXAccessInternal.PutError [ob: handle.cell.cellObj, r: rect, message: rule.message]; notReportedYet _ FALSE } END; -- CheckValue notReportedYet: BOOLEAN _ TRUE; len: INT = rule.extent; delta: INT = 1; IF len = 0 THEN { <> IF notReportedYet THEN CheckValue[quadVals[ne], [pos.x, pos.y, pos.x+delta, pos.y+delta]]; IF notReportedYet THEN CheckValue[quadVals[nw], [pos.x, pos.y-delta, pos.x+delta, pos.y]]; IF notReportedYet THEN CheckValue[quadVals[sw], [pos.x-delta, pos.y-delta, pos.x, pos.y]]; IF notReportedYet THEN CheckValue[quadVals[se], [pos.x-delta, pos.y, pos.x, pos.y+delta]]; } ELSE { SELECT flavour FROM convex => { [] _ handle.geometryWorld.EnumerateArea [ rect: CDOrient.MapRect [itemInCell: [x1: -delta, y1: 0, x2: len, y2: len], cellSize: [0, 0], cellInstOrient: orient, cellInstPos: pos], eachTile: CheckTileValue, skip: $Nix]; [] _ handle.geometryWorld.EnumerateArea [ rect: CDOrient.MapRect [itemInCell: [x1: 0, y1: -delta, x2: len, y2: 0], cellSize: [0, 0], cellInstOrient: orient, cellInstPos: pos], eachTile: CheckTileValue, skip: $Nix]; }; concave => { [] _ handle.geometryWorld.EnumerateArea [ rect: CDOrient.MapRect [itemInCell: [x1: 0, y1: 0, x2: len, y2: len], cellSize: [0, 0], cellInstOrient: orient, cellInstPos: pos], eachTile: CheckTileValue, skip: $Nix]; }; ENDCASE } END; -- CheckArea <> or0: CD.Orientation = CDOrient.original; or90: CD.Orientation = CDOrient.rotate90; or180: CD.Orientation = CDOrient.rotate180; or270: CD.Orientation = CDOrient.rotate270; nodeAtCorner: REF ANY _ NIL; IF SXAccess.stopFlag^ THEN ERROR ABORTED; FOR ruleList: LIST OF REF SX.GeometricRule _ handle.rules, ruleList.rest WHILE ruleList#NIL DO rule: REF SX.GeometricRule = ruleList.first; bitIndex: ARRAY Quadrants OF INTEGER = [8, 4, 2, 1]; quadBits: INTEGER _ 0; nodeAtCorner _ NIL; <> FOR q: Quadrants IN Quadrants DO WITH quadVals[q] SELECT FROM cn: REF SX.CircuitNode => { IF rule.trigger1[SX.nodeIndex] THEN { quadBits _ quadBits + bitIndex[q]; nodeAtCorner _ cn } }; cc: REF Constraint => { IF rule.trigger1[cc.index] THEN { quadBits _ quadBits + bitIndex[q]; IF cc.hasCorrespondingNode AND nodeAtCorner=NIL THEN nodeAtCorner _ cc } }; cnList: LIST OF REF SX.CircuitNode => { CD.Error [ec: other, explanation: "DesignRuleCheckCorner: 'LIST OF REF SX.CircuitNode' should have been squashed to 'REF SX.CircuitNode' in `AnalyzeNodesInAOIs'.\nPLEASE save a copy of this design and make it available to Giordano. Thanks"] }; ENDCASE => { IF quadVals[q]=NIL THEN { IF rule.trigger1[SX.spaceIndex] THEN quadBits _ quadBits + bitIndex[q] } ELSE CD.Error[ec: other, explanation: "DesignRuleCheckCorner: quadVals[q]#NIL"] }; ENDLOOP; -- end Translate the quadrant contents into bit vector values <> <> <> SELECT quadBits FROM 0 => NULL; 1 => CheckArea[rule, or90, convex]; 2 => CheckArea[rule, or0, convex]; 3 => NULL; 4 => CheckArea[rule, or270, convex]; 5 => { CheckArea[rule, or90, convex]; CheckArea[rule, or270, convex] }; 6 => NULL; 7 => CheckArea[rule, or0, concave]; 8 => CheckArea[rule, or180, convex]; 9 => NULL; 10 => { CheckArea[rule, or0, convex]; CheckArea[rule, or180, convex] }; 11 => CheckArea[rule, or90, concave]; 12 => NULL; 13 => CheckArea[rule, or180, concave]; 14 => CheckArea[rule, or270, concave]; 15 => NULL; ENDCASE => ERROR; ENDLOOP; END; -- DesignRuleCheckCorner <> <> handle: REF CheckRec = NARROW[data]; conflictWorld: CStitching.Tesselation = handle.conflictWorld; tileBound: CD.Rect = tile.Area; <> IF conflictWorld.FindTile[[x: tileBound.x1, y: tileBound.y1]].value = $AOI THEN { IF tile.SW.SEdge = tileBound.y1 THEN { IF tile.WS.WEdge = tileBound.x1 THEN NULL -- This is a (rare I suspect) 4 way corner it is handled at the NE corner. ELSE { IF tile.value = tile.SW.value THEN CD.Error[ec: other, explanation: "CheckTile: violated Max horz rule"]; <> DesignRuleCheckCorner[ [ne: tile.value, nw: tile.SW.value, sw: tile.WS.value, se: tile.WS.value], [tileBound.x1, tileBound.y1] ]; } } ELSE { -- tile.WS.WEdge = tileBound.x1 IMPLICITLY IF tile.value = tile.WS.value THEN NULL -- No corner really ELSE { <> DesignRuleCheckCorner [ [ne: tile.value, nw: tile.SW.value, sw: tile.SW.value, se: tile.WS.value], [tileBound.x1, tileBound.y1]]; } } }; <> IF conflictWorld.FindTile[[x: tileBound.x2, y: tileBound.y2]].value = $AOI THEN { IF tile.NE.NEdge = tileBound.y2 THEN { IF tile.EN.EEdge = tileBound.x2 THEN { <<4 way corner, damn it>> neQTile: TilePtr _ tile.EN.NE; WHILE neQTile.SEdge > tileBound.y2 DO neQTile _ neQTile.WS; ENDLOOP; DesignRuleCheckCorner [ [ne: neQTile.value, nw: tile.EN.value, sw: tile.value, se: tile.NE.value], [tileBound.x2, tileBound.y2]]; } ELSE { IF tile.value = tile.NE.value THEN CD.Error[ec: other, explanation: "CheckTile: violated Max horz rule NEast"]; <> DesignRuleCheckCorner [ [ne: tile.EN.value, nw: tile.EN.value, sw: tile.value, se: tile.NE.value], [tileBound.x2, tileBound.y2]]; } } ELSE { -- tile.EN.EEdge = tileBound.x2 IMPLICITLY IF tile.value = tile.EN.value THEN NULL -- No corner really ELSE { <> DesignRuleCheckCorner [ [ne: tile.NE.value, nw: tile.EN.value, sw: tile.value, se: tile.NE.value], [tileBound.x2, tileBound.y2]]; } } } END; -- CheckTile <
> AnalyzeGeometry: PUBLIC PROC [cell: REF SX.LogicalCell] = BEGIN <> cir: REF SX.Circuit = cell.circuit; constraintQueue: ConstraintQueue; IF freeTesselations THEN FreeTesselations[circuit: cir]; <> FOR layer: SX.SpinifexLayerIndex IN [0 .. SXAccess.sxTech.numSpinifexLayers) DO conflictWorld: CStitching.Tesselation _ conflictWorlds[layer] _ CStitching.NewTesselation[]; geometryWorld: CStitching.Tesselation _ geometryWorlds[layer] _ CStitching.NewTesselation[]; cir.spinifexLayers[layer] _ SXQuadTree.Create [cir.spinifexLayers[layer]]; IF cir.spinifexLayers[layer].geometry = NIL THEN LOOP; IF SXAccess.stopFlag^ THEN ERROR ABORTED; ComputeConflicts [cir.spinifexLayers[layer].geometry, conflictWorld, layer, cir]; <> <> <> <> conflictWorld _ conflictWorlds[layer] _ BloatConflictsIntoAOIs [cir, layer, conflictWorld]; <> <> constraintQueue _ InstantiateAOIs [cir: cir, qt: cir.spinifexLayers[layer].geometry, cellBBox: cir.spinifexLayers[layer].size, layer: layer, conflictWorld: conflictWorld, geometryWorld: geometryWorld, constraintQueue: constraintQueue]; <> AnalyzeNodesInAOIs [cir, layer, geometryWorld]; ENDLOOP; -- end of FOR "layer: SX.SpinifexLayerIndex IN [0..SXAccess.sxTech.numSpinifexLayers) DO" TerminalIO.WriteRope [". "]; <> <> <> <> <> <> <> FOR layer: SX.SpinifexLayerIndex IN [0..SXAccess.sxTech.numSpinifexLayers) DO geometryWorld: CStitching.Tesselation _ geometryWorlds[layer]; IF SXAccess.stopFlag^ THEN ERROR ABORTED; FOR tiles: LIST OF REF CStitching.Region _ NARROW[geometryWorld.ListArea[rect: cir.spinifexLayers[layer].size]], tiles.rest WHILE tiles#NIL DO geometryWorld.ChangeRect [rect: tiles.first.rect, new: SX.LookupNode[NARROW[tiles.first.value, LIST OF REF SX.CircuitNode].first]] ENDLOOP; ENDLOOP; SX.NormalizeCircuit [cir]; TerminalIO.WriteRope [". "]; <> FOR layer: SX.SpinifexLayerIndex IN [0..SXAccess.sxTech.numSpinifexLayers) DO conflictWorld: CStitching.Tesselation _ conflictWorlds[layer]; geometryWorld: CStitching.Tesselation _ geometryWorlds[layer]; DesignRuleCheckAOIs [cir, cell, constraintQueue, layer, geometryWorld, conflictWorld]; ENDLOOP; TerminalIO.WriteRope [". "]; IF saveTesselations THEN freeTesselations _ TRUE ELSE FreeTesselations [circuit: cir]; END; -- AnalyzeGeometry <> SaveTesselations: PUBLIC PROC [save: BOOL _ FALSE] = BEGIN saveTesselations _ save END; GetTesselation: PUBLIC PROC [conflicts: BOOL _ TRUE, layer: SX.SpinifexLayerIndex] RETURNS [CStitching.Tesselation] = BEGIN RETURN [IF conflicts THEN conflictWorlds[layer] ELSE geometryWorlds[layer]] END; FreeTesselations: PROC [circuit: REF SX.Circuit] = BEGIN FOR layer: SX.SpinifexLayerIndex IN [0..SXAccess.sxTech.numSpinifexLayers) DO CStitching.ResetTesselation [conflictWorlds[layer]]; CStitching.ResetTesselation [geometryWorlds[layer]]; ENDLOOP; TerminalIO.WriteRope [". "]; freeTesselations _ FALSE END; END. <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <<>> <<>>