StixCompactImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Louis Monier December 6, 1985 2:08:45 pm PST
DIRECTORY
CD, CDBasics, CDDesignRules, PW, Stix, StixCompact, StixParser, TerminalIO;
StixCompactImpl: CEDAR PROGRAM
IMPORTS CDDesignRules, PW, Stix, StixParser
EXPORTS StixCompact =
BEGIN OPEN Stix, StixCompact;
Convenient for axis-independance
x: BOOL = TRUE;
y: BOOL = ~x;
GetCoord: PROC [pos: Position, inX: BOOL] RETURNS [INT] ~ {
RETURN [IF inX THEN pos.x ELSE pos.y]};
Commands
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"];
};
CompactXYCmd: PUBLIC PROC [from, to: CD.Design, stCell: Object] RETURNS [mosOb: Object] = {
cellType: CellType ← StixParser.InputStix[stCell, from];
stickCell: StickPtr ← NARROW[CoreProperties.GetCellTypeProp[cellType, layoutProp]];
dr: CDDesignRules.DesignRules ← CDDesignRules.FindRules[from.technology.key];
Stix.ConvertToDR[stickCell, dr];
CompactXY[stickCell, dr];
mosOb ← Stix.Layout[stickPtr: stickCell, cell: NIL, dr: dr].ob;
PW.IncludeInDirectory[to, mosOb, "Brand-New"];
};
Group formation
-- 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];
};
Compaction
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: BOOLTRUE;
graph: Graph ← MakeGraph[cellType, x];
Stix.Explode[GetStickPtr[cellType], dr];
CompactStickCell[dr, graph, cellType, x, xFirst];
};
CompactXY: PUBLIC CompactProc = {
groups: Groups;
xFirst: BOOLTRUE;
groups ← FormGroups[cell, x];
Stix.Explode[cell, dr];
CompactStickCell[dr, groups, cell, x, xFirst];
groups ← FormGroups[cell, y];
Stix.Explode[cell, dr];
CompactStickCell[dr, groups, cell, y, 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, IF dist=0 AND ~l.first.hasPinOnexternalEdge THEN 0 ELSE preds.first.newCoord+dist];
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
FOR stickPtrs: StickPtrs ← stickCell.insts, stickPtrs.rest WHILE stickPtrs#NIL DO
stickPtr: StickPtr ← stickPtrs.first;
IF stickPtr.type#transistor THEN LOOP;
IF stickPtr.isVertical THEN {
stickPtr.node2.pos ← CDBasics.SubPoints[stickPtr.node1.pos, [0, gateSDNodeSpacing]];
stickPtr.node3.pos ← CDBasics.AddPoints[stickPtr.node1.pos, [0, gateSDNodeSpacing]];}
ELSE {
stickPtr.node2.pos ← CDBasics.SubPoints[stickPtr.node1.pos, [gateSDNodeSpacing, 0]];
stickPtr.node3.pos ← CDBasics.AddPoints[stickPtr.node1.pos, [gateSDNodeSpacing, 0]];};
ENDLOOP;
};
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
sep=0 OR (sep#0, same layer, connected) => 0
sep#0, different layers OR (same layer, not connected) => 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;
IF sep=0 OR (connected AND lay1=lay2) THEN dist ← 0
ELSE dist ← 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: INTIF 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.
CompactYX: PUBLIC CompactProc = {
groups: Groups;
stickCell: StickCell ← InputStix[stCell, to];
xFirst: BOOLFALSE;
Extract[stickCell];
groups ← FormGroups[stickCell, y];
CompactStickCell[groups, stickCell, y, xFirst];
Extract[stickCell];
groups ← FormGroups[stickCell, x];
CompactStickCell[groups, stickCell, x, xFirst];
mosCell ← LayoutStickCell[stickCell, to];
Brag[mosCell];
};
Utilities
-- 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[];
};