1
/* -*- tab-width: 4 -*-
3
* Electric(tm) VLSI Design System
6
* Written by: Dmitry Nadezhin, Sun Microsystems.
8
* Copyright (c) 2005 Sun Microsystems and Static Free Software
10
* Electric(tm) is free software; you can redistribute it and/or modify
11
* it under the terms of the GNU General Public License as published by
12
* the Free Software Foundation; either version 3 of the License, or
13
* (at your option) any later version.
15
* Electric(tm) is distributed in the hope that it will be useful,
16
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
* GNU General Public License for more details.
20
* You should have received a copy of the GNU General Public License
21
* along with Electric(tm); see the file COPYING. If not, write to
22
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
23
* Boston, Mass 02111-1307, USA.
25
package com.sun.electric.database;
27
import com.sun.electric.database.geometry.DBMath;
28
import com.sun.electric.database.geometry.ERectangle;
29
import com.sun.electric.database.id.CellId;
30
import com.sun.electric.database.id.CellUsage;
31
import com.sun.electric.database.text.ImmutableArrayList;
32
import com.sun.electric.technology.TechPool;
34
import java.awt.geom.Rectangle2D;
35
import java.util.Arrays;
36
import java.util.BitSet;
37
import java.util.Collections;
38
import java.util.HashSet;
39
import java.util.IdentityHashMap;
43
* CellTree consists of top CellBackup and all CellTrees for all subcells.
44
* It can compute Cell bounds and shape of Exports.
46
public class CellTree {
48
public static final CellTree[] NULL_ARRAY = {};
49
public static final ImmutableArrayList<CellTree> EMPTY_LIST = new ImmutableArrayList<CellTree>(NULL_ARRAY);
53
public final CellBackup top;
54
final CellTree[] subTrees;
56
* TechPool containing all Technologies used in this CellTree
58
public final TechPool techPool;
60
* All cells used in this CellTree
62
public final Set<CellId> allCells;
63
private ERectangle bounds;
65
private EquivPorts equivPorts;
67
private CellTree(CellBackup top, CellTree[] subTrees, TechPool techPool, Set<CellId> allCells) {
69
this.subTrees = subTrees;
70
this.techPool = techPool;
71
this.allCells = allCells;
74
public static CellTree newInstance(ImmutableCell d, TechPool techPool) {
75
CellBackup top = CellBackup.newInstance(d, techPool);
76
assert top.cellRevision.cellUsages.length == 0;
77
return new CellTree(top, NULL_ARRAY, top.techPool, Collections.singleton(top.cellRevision.d.cellId));
81
* Returns CellTree which differs from this CellTree.
82
* @param top new top CellBackup
83
* @param subTrees new subCellTrees
84
* @param superPool TechPool which contains
85
* @return CellTree which differs from this CellTree.
87
public CellTree with(CellBackup top, CellTree[] subTrees, TechPool superPool) {
89
if (Arrays.equals(this.subTrees, subTrees)) {
90
subTrees = this.subTrees;
92
subTrees = subTrees.clone();
93
int l = subTrees.length;
94
while (l > 0 && subTrees[l - 1] == null) {
98
subTrees = NULL_ARRAY;
99
} else if (l != subTrees.length) {
100
CellTree[] newSubTrees = null;
101
if (l == this.subTrees.length) {
102
newSubTrees = this.subTrees;
103
for (int i = 0; i < l; i++) {
104
if (newSubTrees[i] != subTrees[i]) {
110
if (newSubTrees == null) {
111
newSubTrees = new CellTree[l];
112
System.arraycopy(subTrees, 0, newSubTrees, 0, l);
114
subTrees = newSubTrees;
117
// Check if unchanged
118
if (this.top == top && this.subTrees == subTrees) {
122
// Check if subTrees match the top backup
123
// Check technologies against superPool
124
// Compute cells and technologies used in new tree
125
CellRevision cellRevision = top.cellRevision;
126
CellId cellId = cellRevision.d.cellId;
127
BitSet techUsages = new BitSet();
128
if (top.techPool != superPool.restrict(cellRevision.techUsages, top.techPool)) {
129
throw new IllegalArgumentException();
131
techUsages.or(cellRevision.techUsages);
132
HashSet<CellId> allCellsAccum = new HashSet<CellId>();
133
for (int i = 0; i < cellRevision.cellUsages.length; i++) {
134
CellRevision.CellUsageInfo cui = cellRevision.cellUsages[i];
135
CellTree subTree = subTrees[i];
137
if (subTree != null) {
138
throw new IllegalArgumentException();
142
BitSet subTechUsages = subTree.techPool.getTechUsages();
143
if (subTree.techPool != superPool.restrict(subTechUsages, subTree.techPool)) {
144
throw new IllegalArgumentException();
146
techUsages.or(subTechUsages);
147
allCellsAccum.addAll(subTree.allCells);
148
CellRevision subCellRevision = subTree.top.cellRevision;
149
if (subCellRevision.d.cellId != cellId.getUsageIn(i).protoId) {
150
throw new IllegalArgumentException();
152
cui.checkUsage(subCellRevision);
155
// Check for recursion
156
if (allCellsAccum.contains(cellId)) {
157
throw new IllegalArgumentException("Recursive " + cellId);
159
// Canonize new allCells
160
allCellsAccum.add(cellId);
161
Set<CellId> allCells;
162
if (allCellsAccum.equals(this.allCells)) {
163
allCells = this.allCells;
164
} else if (allCellsAccum.size() == 1) {
165
allCells = Collections.singleton(cellId);
167
allCells = Collections.unmodifiableSet(allCellsAccum);
169
assert allCellsAccum.equals(allCells);
171
// Construct new CellTree
172
TechPool techPool = superPool.restrict(techUsages, this.techPool);
173
CellTree newCellTree = new CellTree(top, subTrees, techPool, allCells);
175
if (this.top == top) {
176
// Try to reuse cell bounds
177
if (this.bounds != null) {
178
assert newCellTree.subTrees.length == this.subTrees.length;
179
ERectangle cellBounds = this.bounds;
180
for (int i = 0; i < this.subTrees.length; i++) {
181
CellTree oldSubTree = this.subTrees[i];
182
if (oldSubTree == null) continue;
183
assert oldSubTree.bounds != null;
184
if (!newCellTree.subTrees[i].getBounds().equals(oldSubTree.bounds)) {
189
if (cellBounds != null) {
190
newCellTree.bounds = cellBounds;
193
// Try to reuse NetCell
194
if (this.equivPorts != null) {
195
assert newCellTree.subTrees.length == this.subTrees.length;
196
EquivPorts netCell = this.equivPorts;
197
for (int i = 0; i < this.subTrees.length; i++) {
198
CellTree oldSubTree = this.subTrees[i];
199
if (oldSubTree == null) continue;
200
assert oldSubTree.equivPorts != null;
201
if (!newCellTree.subTrees[i].getEquivPorts().equalsPorts(oldSubTree.equivPorts)) {
206
if (netCell != null) {
207
newCellTree.equivPorts = netCell;
212
// Return the new CellTree
216
public boolean sameNetlist(CellTree that) {
217
if (this.top != that.top) {
220
for (int i = 0; i < this.subTrees.length; i++) {
221
CellTree thisSubTree = this.subTrees[i];
222
if (thisSubTree == null) continue;
223
if (!this.subTrees[i].getEquivPorts().equalsPorts(that.subTrees[i].getEquivPorts())) {
230
public CellTree[] getSubTrees() {
231
return subTrees.clone();
235
* Returns cell bounds of this CellTree
236
* @return cell bounds of this CellTree
238
public ERectangle getBounds() {
239
if (bounds == null) {
240
bounds = computeBounds(null);
245
private ERectangle computeBounds(ERectangle candidateBounds) {
246
CellRevision cellRevision = top.cellRevision;
248
// Collect subcell bounds
249
IdentityHashMap<CellId, ERectangle> subCellBounds = new IdentityHashMap<CellId, ERectangle>(cellRevision.cellUsages.length);
250
for (CellTree subTree : subTrees) {
251
if (subTree == null) {
254
subCellBounds.put(subTree.top.cellRevision.d.cellId, subTree.getBounds());
257
double cellLowX, cellHighX, cellLowY, cellHighY;
258
boolean boundsEmpty = true;
259
cellLowX = cellHighX = cellLowY = cellHighY = 0;
261
Rectangle2D.Double sb = new Rectangle2D.Double();
262
for (ImmutableNodeInst n : top.cellRevision.nodes) {
263
if (!(n.protoId instanceof CellId)) {
267
ERectangle b = subCellBounds.get((CellId) n.protoId);
268
n.orient.rectangleBounds(b.getMinX(), b.getMinY(), b.getMaxX(), b.getMaxY(),
269
n.anchor.getX(), n.anchor.getY(), sb);
271
double lowx = sb.getMinX();
272
double highx = sb.getMaxX();
273
double lowy = sb.getMinY();
274
double highy = sb.getMaxY();
282
if (lowx < cellLowX) {
285
if (highx > cellHighX) {
288
if (lowy < cellLowY) {
291
if (highy > cellHighY) {
296
long gridMinX = DBMath.lambdaToGrid(cellLowX);
297
long gridMinY = DBMath.lambdaToGrid(cellLowY);
298
long gridMaxX = DBMath.lambdaToGrid(cellHighX);
299
long gridMaxY = DBMath.lambdaToGrid(cellHighY);
301
ERectangle primitiveBounds = top.getPrimitiveBounds();
302
if (primitiveBounds != null) {
304
gridMinX = primitiveBounds.getGridMinX();
305
gridMaxX = primitiveBounds.getGridMaxX();
306
gridMinY = primitiveBounds.getGridMinY();
307
gridMaxY = primitiveBounds.getGridMaxY();
309
gridMinX = Math.min(gridMinX, primitiveBounds.getGridMinX());
310
gridMaxX = Math.max(gridMaxX, primitiveBounds.getGridMaxX());
311
gridMinY = Math.min(gridMinY, primitiveBounds.getGridMinY());
312
gridMaxY = Math.max(gridMaxY, primitiveBounds.getGridMaxY());
315
if (candidateBounds != null && gridMinX == candidateBounds.getGridMinX() && gridMinY == candidateBounds.getGridMinY()
316
&& gridMaxX == candidateBounds.getGridMaxX() && gridMaxY == candidateBounds.getGridMaxY()) {
317
return candidateBounds;
319
return ERectangle.fromGrid(gridMinX, gridMinY, gridMaxX - gridMinX, gridMaxY - gridMinY);
322
public EquivPorts getEquivPorts() {
323
if (equivPorts == null) {
324
equivPorts = new EquivPorts(this);
329
public EquivPorts computeEquivPorts() {
330
return new EquivPorts(this);
333
public void check() {
335
CellId cellId = top.cellRevision.d.cellId;
336
BitSet techUsages = new BitSet();
337
techUsages.or(top.cellRevision.techUsages);
338
assert subTrees.length == top.cellRevision.cellUsages.length;
339
HashSet<CellId> allCells = new HashSet<CellId>();
340
for (int i = 0; i < subTrees.length; i++) {
341
CellTree subTree = subTrees[i];
342
CellRevision.CellUsageInfo cui = top.cellRevision.cellUsages[i];
344
assert subTree == null;
347
CellRevision subCellRevision = subTree.top.cellRevision;
348
CellUsage cu = cellId.getUsageIn(i);
349
assert subCellRevision.d.cellId == cu.protoId;
350
cui.checkUsage(subCellRevision);
351
BitSet subTechUsage = subTree.techPool.getTechUsages();
352
assert subTree.techPool == techPool.restrict(subTechUsage, subTree.techPool);
353
techUsages.or(subTechUsage);
354
allCells.addAll(subTree.allCells);
356
assert top.techPool == techPool.restrict(top.cellRevision.techUsages, top.techPool);
357
assert techUsages.equals(techPool.getTechUsages());
358
assert !allCells.contains(cellId);
359
allCells.add(cellId);
360
assert allCells.equals(this.allCells);
361
if (bounds != null) {
362
assert bounds == computeBounds(bounds);
367
public String toString() {
368
return top.toString();