com.sun.electric.database.geometry.merge.LayoutMergerFactoryImpl.scala Maven / Gradle / Ivy
/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: LayoutMergerFactoryImpl.scala
* Written by Dmitry Nadezhin, Sun Microsystems.
*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
*
* Electric(tm) is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* Electric(tm) is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Electric(tm); see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, Mass 02111-1307, USA.
*/
package com.sun.electric.database.geometry.merge
import com.sun.electric.database.CellTree
import com.sun.electric.database.geometry.PolyBase
import com.sun.electric.database.geometry.bool.LayoutMerger
import com.sun.electric.database.geometry.bool.LayoutMergerFactory
import com.sun.electric.database.geometry.bool.UnloadPolys
import com.sun.electric.database.geometry.bool.VectorCache
import com.sun.electric.database.hierarchy.Cell;
import com.sun.electric.database.id.CellId
import com.sun.electric.technology.Layer
import com.sun.electric.util.ElapseTimer
import com.sun.electric.util.TextUtils
import com.sun.electric.util.math.Orientation
import com.sun.electric.util.math.Orientation
import java.io.BufferedInputStream
import java.io.BufferedOutputStream
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.io.DataInputStream
import java.io.DataOutputStream
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import scala.collection.JavaConversions
import scala.collection.immutable.VectorBuilder
import scala.collection.mutable.LinkedHashMap
import scala.collection.mutable.LinkedHashSet
class LayoutMergerFactoryImpl extends LayoutMergerFactory {
def newMerger(topCell: Cell) = new LayoutMergerScalaImpl(topCell)
}
class LayoutMergerScalaImpl(topCell: Cell) extends LayoutMerger {
val TMP_FILE_THRESHOLD = 1000000
val vectorCache = new VectorCache(topCell.getDatabase.backup)
vectorCache.scanLayers(topCell.getId)
override def getLayers = vectorCache.getLayers
override def canMerge(layer: Layer) = !vectorCache.isBadLayer(layer)
def downTop(top: CellTree): Seq[CellTree] = {
val result = LinkedHashSet[CellTree]()
def downTop(t: CellTree): Unit = {
if (!result.contains(t)) {
for (subTree <- t.getSubTrees) {
if (subTree != null) downTop(subTree)
}
result.add(t)
}
}
downTop(top)
result.toSeq
}
def mergeLocalLayerToByteArray(cellId: CellId, layer: Layer): Array[Byte] = {
val numBoxes = vectorCache.getNumBoxes(cellId, layer)
if (numBoxes == 0) null else {
val boxCoords = new Array[Int](4)
val ps = new PointsSorter
for (val i <- 0 until numBoxes) {
vectorCache.getBoxes(cellId, layer, i, 1, boxCoords)
val lx = boxCoords(0)
val ly = boxCoords(1)
val hx = boxCoords(2)
val hy = boxCoords(3)
ps.put(lx, ly, hx, hy)
}
val get = ps.fix
val dm = new DeltaMerge
val bout = new ByteArrayOutputStream
val out = new DataOutputStream(bout)
dm.loop(get, out)
val ba = bout.toByteArray
out.close
ba
}
}
def byteArray2coordArray(ba: Array[Byte]): Array[Int] = {
val inpS = new DataInputStream(new ByteArrayInputStream(ba))
val pos = new VectorBuilder[Int]
val neg = new VectorBuilder[Int]
while (inpS.readBoolean) {
val x = inpS.readInt
val count = inpS.readInt
for (val i <- 0 until count) {
val yp = inpS.readInt
val y = yp >> 1
val positive = (yp&1) != 0
val b = if (positive) pos else neg
b += x
b += y
}
}
val posV = pos.result
val negV = neg.result
assert(posV.size == negV.size)
(posV ++ negV).toArray
}
def mergeLayer(mergedCoords: CellId => Array[Int], topCellId: CellId, layer: Layer, rotate: Boolean,
out: DataOutputStream) = {
val ps = new PointsSorter
var coordsBuf = new Array[Int](1024)
def collectLayer(cellId: CellId, x: Int, y: Int, orient: Orientation): Unit = {
val coords = mergedCoords(cellId)
if (!coords.isEmpty) {
if (coordsBuf.length < coords.length) {
var newLen = coordsBuf.length; while (newLen < coords.length) newLen *= 2
coordsBuf = new Array[Int](newLen)
}
val numPoints = coords.length/2
assert(numPoints%2 == 0)
orient.transformPoints(numPoints, coords, coordsBuf)
val orientRot = orient.getCAngle != 0 && orient.getCAngle != 1800
var positive = !orientRot
for (val i <- 0 until numPoints) {
if (i*2 == numPoints) positive = !positive
ps.put(x + coordsBuf(i*2 + 0), y + coordsBuf(i*2 + 1), positive)
}
}
val subCells = vectorCache.getSubcells(cellId);
if (!subCells.isEmpty) {
for (val n <- JavaConversions.asIterable(subCells)) {
assert(n.orient.isManhattan)
coordsBuf(0) = n.anchor.getGridX.asInstanceOf[Int]
coordsBuf(1) = n.anchor.getGridY.asInstanceOf[Int]
orient.transformPoints(1, coordsBuf)
val subOrient = orient.concatenate(n.orient).canonic
val subCellId = n.protoId.asInstanceOf[CellId]
collectLayer(subCellId, x + coordsBuf(0), y + coordsBuf(1), subOrient)
}
}
}
val topOrient = (if (rotate) Orientation.XR else Orientation.IDENT).canonic
val timer1 = ElapseTimer.createInstance.start
val startTime1 = System.currentTimeMillis
collectLayer(topCellId, 0, 0, topOrient)
val get = ps.fix
timer1.end
val timer2 = ElapseTimer.createInstance.start
val dm = new DeltaMerge
val outPoints = dm.loop(get, out)
timer2.end
println(layer + " " + ps.size + "->" + outPoints + " points" +
", merge=" + timer1 + " sec" +
", tree=" + timer2 + " sec");
}
def flattenAndMergeLayer(layer: Layer, out: DataOutputStream) = {
val dt = downTop(topCell.tree)
val mergedCoords = new LinkedHashMap[CellId,Array[Int]]()
for (val t <- dt) {
val cellId = t.top.cellRevision.d.cellId
val ba = mergeLocalLayerToByteArray(cellId, layer)
if (ba != null) {
mergedCoords.put(cellId, byteArray2coordArray(ba))
} else {
mergedCoords.put(cellId, Array.empty)
}
}
val rotate = false
mergeLayer(mergedCoords, topCell.getId, layer, rotate, out)
}
def mergeInMemory(layer: Layer): Array[Byte] = {
val bout = new ByteArrayOutputStream
val out = new DataOutputStream(bout)
flattenAndMergeLayer(layer, out)
out.close
bout.toByteArray
}
def mergeInFile(layer: Layer): File = {
val file = File.createTempFile("Electric", "DRC")
val out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file)))
flattenAndMergeLayer(layer, out)
out.close
file
}
override def merge(layer: Layer): java.lang.Iterable[PolyBase.PolyBaseTree] = {
val inMemory = vectorCache.getNumFlatBoxes(topCell.getId(), layer) <= TMP_FILE_THRESHOLD;
if (inMemory) {
val ba = mergeInMemory(layer)
val inpS = new DataInputStream(new ByteArrayInputStream(ba))
val up = new UnloadPolys
val trees = up.loop(inpS, false)
inpS.close
trees
} else {
val file = mergeInFile(layer)
val inpS = new DataInputStream(new BufferedInputStream(new FileInputStream(file)))
val up = new UnloadPolys
val trees = up.loop(inpS, false)
inpS.close
file.delete
trees
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy