<> <> <> <<>> DIRECTORY CD, CDBasics, CDDesignRules, PW, Stix, StixCompact, StixParser, TerminalIO; StixCompactImpl: CEDAR PROGRAM IMPORTS CDDesignRules, PW, Stix, StixParser EXPORTS StixCompact = BEGIN OPEN Stix, StixCompact; <> x: BOOL = TRUE; y: BOOL = ~x; GetCoord: PROC [pos: Position, inX: BOOL] RETURNS [INT] ~ { RETURN [IF inX THEN pos.x ELSE pos.y]}; <> SimpleExpand: PUBLIC PROC [from, to: CD.Design, stCell: Object] RETURNS [mosOb: Object] = { cellType: CellType _ StixParser.InputStix[stCell, from]; stickCell: StickPtr _ GetStickPtr[cellType]; dr: CDDesignRules.DesignRules _ CDDesignRules.FindRules[from.technology.key]; Stix.ConvertToDR[cellType, dr]; mosOb _ Stix.Layout[stickPtr: stickCell, cell: NIL, dr: dr].ob; PW.IncludeInDirectory[to, mosOb, "Brand-New"]; }; <> <> <> <> <> <> <> <> <<};>> <> <<-- First cut: the virtual grid! All nodes with the same coordinate make a group>> MakeGraph: PROC [cellType: CellType, inX: BOOL] RETURNS [graph: Graph] = { InsertInGroup: EachStickPtrProc = { SELECT stickPtr.class FROM contactClass, transistorClass => { c: INT _ GetCoord[Origin[stickPtr].pos, inX]; graph[c].insts _ CONS[stickPtr, graph[c].insts]; }; wireClass => { c: INT _ GetCoord[Origin[stickPtr].pos, inX]; graph[c].insts _ CONS[stickPtr, graph[c].insts]; c _ GetCoord[OtherEnd[stickPtr].pos, inX]; graph[c].insts _ CONS[stickPtr, graph[c].insts]; }; ENDCASE => ERROR; }; graph _ NEW[GraphRec[1000]]; -- adjust with IRect FOR l: Nodes _ AllNodes[GetStickPtr[cellType]], l.rest WHILE l#NIL DO node: Node _ l.first; coord: INT _ GetCoord[node.pos, inX]; IF graph[coord]=NIL THEN graph[coord] _ NEW [GroupRec _ [coord: coord]]; graph[coord].nodes _ CONS[node, graph[coord].nodes]; ENDLOOP; [] _ EnumerateInsts[cellType, InsertInGroup]; }; <> CompactXCmd: PUBLIC PROC [from, to: CD.Design, stCell: Object] RETURNS [mosOb: Object] = { cellType: CellType _ StixParser.InputStix[stCell, from]; stickCell: StickPtr _ GetStickPtr[cellType]; dr: CDDesignRules.DesignRules _ CDDesignRules.FindRules[from.technology.key]; Stix.ConvertToDR[cellType, dr]; CompactX[cellType, dr]; mosOb _ Stix.Layout[stickPtr: stickCell, cell: NIL, dr: dr].ob; PW.IncludeInDirectory[to, mosOb, "Compacted-X"]; }; CompactX: PUBLIC CompactProc = { <<[cellType: CellType, dr: DRules]>> xFirst: BOOL _ TRUE; graph: Graph _ MakeGraph[cellType, x]; Stix.Explode[GetStickPtr[cellType], dr]; CompactStickCell[dr, graph, cellType, x, xFirst]; }; <<>> <> <> <> <<>> <> <> <> <<>> <> <> <> <<};>> <<>> <<-- From left to right, compute the minimum separation between groups and update the nodes>> CompactStickCell: PROC [dr: DRules, graph: Graph _ NIL, cellType: CellType, inX, xFirst: BOOL] = { <<-- Compute the coordinate of each group>> tab: Tab _ NARROW[GetStickPtr[cellType].data, StickCell].tab; FOR i: NAT IN [0..graph.size) DO dist, formerCoord, max: INT; group: Group _ graph[i]; IF group=NIL THEN LOOP; dist _ 0; formerCoord _ group.coord; max _ 0; <<-- coord[i] = max of coord[j]+minDist[i, j] over all pred. j >> FOR pred: NAT DECREASING IN [0..i) DO IF graph[pred]=NIL THEN LOOP; IF graph[pred].coord>=group.coord THEN EXIT; dist _ MinSepGroup[dr, graph[pred], group, tab, inX, xFirst]; <> max _ MAX[max, graph[pred].newCoord+dist]; ENDLOOP; group.newCoord _ max; ENDLOOP; <<-- and update the nodes which have to be updated!>> FOR i: NAT IN [0..graph.size) DO group: Group _ graph[i]; IF group=NIL THEN LOOP; FOR l: Nodes _ group.nodes, l.rest WHILE l#NIL DO Update[l.first, group.coord, group.newCoord, inX]; ENDLOOP; ENDLOOP; <<-- special hack for the transistors>> <> <> <> <> <> <> <> <> <> <> }; Update: PROC [n: Node, former, new: INT, inX: BOOL] = { IF n=NIL THEN RETURN; IF inX THEN {IF n.pos.x=former THEN n.pos.x _ new} ELSE {IF n.pos.y=former THEN n.pos.y _ new}}; <<-- The distance between the two centerlines>> MinSepGroup: PROC [dr: DRules, group1, group2: Group, tab: Tab, inX, xFirst: BOOL] RETURNS [d: INT _ 0] = { FOR l1: StickPtrs _ group1.insts, l1.rest WHILE l1#NIL DO FOR l2: StickPtrs _ group2.insts, l2.rest WHILE l2#NIL DO IF l1.first#l2.first THEN d _ MAX[d, MinSepPlates[dr, l1.first.plates, l2.first.plates, group1.coord, group2.coord, tab, inX, xFirst]]; ENDLOOP; ENDLOOP; }; MinSepPlates: PROC [dr: DRules, plates1, plates2: Plates, g1Coord, g2Coord: INT, tab: Tab, inX, xFirst: BOOL] RETURNS [dist: INT _ 0] = { FOR l1: Plates _ plates1, l1.rest WHILE l1#NIL DO FOR l2: Plates _ plates2, l2.rest WHILE l2#NIL DO dist _ MAX[dist, MinSepPlate[dr, l1.first, l2.first, g1Coord, g2Coord, tab, inX, xFirst]]; ENDLOOP; ENDLOOP; }; <<-- Rules: sep is distance between layers; 0 means they can overlap>> < 0>> < sep+1/2 size>> MinSepPlate: PROC [dr: DRules, plate1, plate2: Plate, g1Coord, g2Coord: INT, tab: Tab, inX, xFirst: BOOL] RETURNS [dist: INT _ 0] = { connected: BOOL _ PlatesAreConnected[plate1, plate2, tab]; r1: CD.Rect _ plate1.dr.r; r2: CD.Rect _ plate2.dr.r; lay1: Layer _ plate1.dr.lev; lay2: Layer _ plate2.dr.lev; sep, thickness: INT; sep _ IF connected THEN CDDesignRules.MinConnectedDist[dr, lay1, lay2] ELSE CDDesignRules.MinDist[dr, lay1, lay2]; IF ~Facing[r1, r2, sep, inX, xFirst] THEN RETURN; -- not facing each other thickness _ IF inX THEN (r1.x2-g1Coord+g2Coord-r2.x1) ELSE (r1.y2-g1Coord+g2Coord-r2.y1); dist _ IF sep=0 THEN 0 ELSE sep+thickness; <> <> }; <<-- X compaction: Just facing from left to right>> <<-- Y compaction: Facing from top to bottom, but corner checking as well by extending r1 by "diagonal" on both sides.>> Facing: PROC [r1, r2: CD.Rect, diagSep: INT, inX, xFirst: BOOL] RETURNS [BOOL] ~ { delta: INT _ IF inX#xFirst THEN diagSep ELSE 0; IF inX THEN RETURN [r1.y2+delta>r2.y1 AND r2.y2>r1.y1-delta] ELSE RETURN [r1.x2+delta>r2.x1 AND r2.x2>r1.x1-delta]; }; <<>> END. <<>> <<>> <<>> <> <> <> <> <> <> <> <> <> <> <> <> <<};>> <> <<-- Bragging about the new-born cell>> Brag: PROC [newCell: Object] ~ { size: CD.Position _ CD.InterestSize[newCell]; TerminalIO.WriteRope["The new cell: dx="]; TerminalIO.WriteInt[size.x/lambda]; TerminalIO.WriteRope[" lambda, dy="]; TerminalIO.WriteInt[size.y/lambda]; TerminalIO.WriteRope[" lambda, area="]; TerminalIO.WriteInt[size.x*size.y/(lambda*lambda)]; TerminalIO.WriteLn[]; }; << >>