Skip to content
This repository has been archived by the owner on Apr 20, 2024. It is now read-only.

Commit

Permalink
First pass of CalculatePlacementsPass
Browse files Browse the repository at this point in the history
  • Loading branch information
jwright6323 committed Aug 10, 2021
1 parent e5e10f1 commit 3bcdb5b
Show file tree
Hide file tree
Showing 7 changed files with 156 additions and 16 deletions.
17 changes: 15 additions & 2 deletions floorplan/src/main/scala/barstools/floorplan/IR.scala
Original file line number Diff line number Diff line change
Expand Up @@ -214,16 +214,29 @@ private[floorplan] final case class ConstrainedHierarchicalTop(
)
}

private[floorplan] final case class SizedHierarchicalTop(
name: String,
topGroup: String,
width: BigDecimal,
height: BigDecimal,
margins: Margins,
hardBoundary: Boolean
) extends Top with SizedRectLike {
final def level = 1
def mapNames(m: (String) => String): Element = this.copy(name = m(name), topGroup = m(topGroup))
def flatIndexOf(s: String): Int = if (topGroup == s) 0 else -1
}

private[floorplan] final case class PlacedHierarchicalTop(
name: String,
elements: Seq[String],
x: BigDecimal,
y: BigDecimal,
width: BigDecimal,
height: BigDecimal,
margins: Margins,
hardBoundary: Boolean
) extends Top with PlacedRectLike {
final def x = BigDecimal(0)
final def y = BigDecimal(0)
final def level = 0
def mapNames(m: (String) => String): Element = this.copy(name = m(name), elements.map(m))
def flatIndexOf(s: String): Int = elements.indexOf(s)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,86 @@ package barstools.floorplan.compiler

import barstools.floorplan._

import scala.collection.mutable.{ArrayBuffer}

class CalculatePlacementsPass(topMod: String) extends Pass {
def execute(state: FloorplanState): FloorplanState = state // TODO
def execute(state: FloorplanState): FloorplanState = {
val tree = new FloorplanTree(state, topMod)

val top = tree.topNode
assert(top.record.element.isInstanceOf[SizedHierarchicalTop], "PlacedHierarchicalTop not yet supported pre-CalculatePlacementsPass. Use SizedHierarchicalTop instead.")

val elementBuf = new ArrayBuffer[Element]()

// Custom traversal TODO should this go in the FloorplanTree code somehow?
def traverse(n: FloorplanTreeNode, x: BigDecimal, y: BigDecimal, placeTopOpt: Option[FloorplanTreeNode]) {
n.record.element match {
case e: SizedHierarchicalTop =>
assert(placeTopOpt.isEmpty)
// Note: we intentionally wait to add this until the end so we know all of the elements
val children = n.children
assert(children.length == 1) // should only be a topGroup here
children.foreach { cNode => traverse(cNode, x, y, Some(n)) }
n.replace(n.record.copy(element = PlacedHierarchicalTop(
e.name,
elementBuf.toSeq.map(_.name),
x,
y,
e.width,
e.height,
e.margins,
e.hardBoundary
)))
case e: SizedGrid =>
assert(placeTopOpt.isDefined)
// traverse down
val nodes: Seq[FloorplanTreeNode] = e.elements.map(name => tree.getNode(name))
val children: Seq[SizedRectLike] = nodes.map(_.record.element.asInstanceOf[SizedRectLike])
val widths: Seq[BigDecimal] = children.take(e.xDim).map(_.width).scanLeft(BigDecimal(0))(_+_).takeRight(e.xDim)
val heights: Seq[BigDecimal] = children.grouped(e.xDim).map(_(0).height).toSeq.scanLeft(BigDecimal(0))(_+_).takeRight(e.yDim)

nodes.zipWithIndex.foreach { case (node, idx) =>
val (iX, iY) = e.fromIdx(idx)
traverse(node, x + widths(iX), y + heights(iY), placeTopOpt)
}

// delete it
n.delete()
case e: SizedLogicRect =>
assert(placeTopOpt.isDefined)
n.replace(n.record.copy(element = PlacedLogicRect(
e.name,
e.parent,
x,
y,
e.width,
e.height,
e.hardBoundary
)))
n.reparent(placeTopOpt.get)
elementBuf.append(n.record.element)
case e: SizedSpacerRect =>
assert(placeTopOpt.isDefined)
// delete it
n.delete()
case e: SizedMacro =>
assert(placeTopOpt.isDefined)
n.replace(n.record.copy(element = PlacedMacro(
e.name,
e.parent,
x,
y,
e.width,
e.height
)))
n.reparent(placeTopOpt.get)
elementBuf.append(n.record.element)
case e => ??? // Shouldn't get here
}
}

traverse(top, BigDecimal(0), BigDecimal(0), None)

tree.toState
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ class ConstraintPropagationPass(val topMod: String) extends Pass {
val constraints: Constraints = node.parent.map(_.record.element match {
case e: ConstrainedHierarchicalTop =>
e.toConstraints
case e: SizedHierarchicalTop =>
Constraints() // These should be sized already
case e: PlacedHierarchicalTop =>
Constraints() // These should be sized already
case e: ConstrainedWeightedGrid =>
Expand Down Expand Up @@ -74,6 +76,8 @@ class ConstraintPropagationPass(val topMod: String) extends Pass {
case e: ConstrainedHierarchicalTop =>
val newElement = e.applyConstraints(node.children(0).record.element.toConstraints)
Some(node.record.copy(element = newElement))
case e: SizedHierarchicalTop =>
throw new Exception("Cannot propagate constraints to a SizedHierarchicalTop")
case e: PlacedHierarchicalTop =>
throw new Exception("Cannot propagate constraints to a PlacedHierarchicalTop")
case e: ConstrainedWeightedGrid =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,60 @@ package barstools.floorplan.compiler
import scala.collection.mutable.{ArrayBuffer, HashMap}
import barstools.floorplan._

// TODO this is required to give access to Node types outside FloorplanTree. Ideally we should move all that functionality into this class
// with some type-generic methods, but for now this works
sealed trait FloorplanTreeNode {

def parent: Option[FloorplanTreeNode]
def children: Seq[FloorplanTreeNode]
def record: FloorplanRecord
def addChildRecord(cRecord: FloorplanRecord): FloorplanTreeNode
def removeChild(n: FloorplanTreeNode): Unit
def delete(): Unit
def replace(r: FloorplanRecord): Unit
def reparent(p: FloorplanTreeNode): Unit

}

class FloorplanTree(val state: FloorplanState, val topMod: String) {

val allNodes = new HashMap[String, Node]()
val allNodes = new HashMap[String, FloorplanTreeNode]()

class Node(val parent: Option[Node], initialRecord: FloorplanRecord) {
val children = new ArrayBuffer[Node]()
class Node(val parent: Option[FloorplanTreeNode], initialRecord: FloorplanRecord) extends FloorplanTreeNode {
val _children = new ArrayBuffer[FloorplanTreeNode]()

// TODO this might be dangerous
private var _record = initialRecord

def children = _children.toSeq
def record = _record

def addChildRecord(cRecord: FloorplanRecord): Node = {
def addChildRecord(cRecord: FloorplanRecord): FloorplanTreeNode = {
val n = new Node(Some(this), cRecord)
children += n
_children += n
allNodes += (cRecord.element.name -> n)
n
}

def removeChild(n: FloorplanTreeNode) {
_children.remove(_children.indexOf(n))
}

def delete() {
assert(_children.isEmpty) // sanity check that we aren't orphaning nodes
parent.foreach(_.removeChild(this))
allNodes.remove(record.element.name)
}

def replace(r: FloorplanRecord) { _record = r }

def reparent(p: FloorplanTreeNode) {
this.delete()
p.addChildRecord(record)
}
}


def getUniqueName(suggestion: String): String = {
var i = 0
var tmp = suggestion + s"_${i}"
Expand All @@ -37,7 +69,7 @@ class FloorplanTree(val state: FloorplanState, val topMod: String) {
}

def getRecord(s: String): FloorplanRecord = getNode(s).record
def getNode(s: String): Node = allNodes(s)
def getNode(s: String): FloorplanTreeNode = allNodes(s)

// These are only used by the constructor
private val allRecords: Map[String, FloorplanRecord] = state.records.map({ x => (x.element.name -> x) }).toMap
Expand All @@ -50,7 +82,7 @@ class FloorplanTree(val state: FloorplanState, val topMod: String) {
assert(topRecords.length == 1, "Must be exactly one Top record")
val topRecord = topRecords(0)

private def dfs(parent: Option[Node], r: FloorplanRecord): Node = {
private def dfs(parent: Option[FloorplanTreeNode], r: FloorplanRecord): FloorplanTreeNode = {
r.element match {
case e: Top =>
assert(!parent.isDefined, "Cannot have multiple tops")
Expand All @@ -59,6 +91,8 @@ class FloorplanTree(val state: FloorplanState, val topMod: String) {
e match {
case e: ConstrainedHierarchicalTop =>
dfs(Some(n), _getRecord(e.topGroup))
case e: SizedHierarchicalTop =>
dfs(Some(n), _getRecord(e.topGroup))
case e: PlacedHierarchicalTop =>
e.elements.foreach(x => dfs(Some(n), _getRecord(x)))
}
Expand All @@ -82,15 +116,15 @@ class FloorplanTree(val state: FloorplanState, val topMod: String) {
// Option[FloorplanRecord] return
// None = do no modify
// Some(record) = modify node
def traverseMapPre(f: (Node => Option[FloorplanRecord])) { traverseMapPreHelper(topNode, f) }
def traverseMapPost(f: (Node => Option[FloorplanRecord])) { traverseMapPostHelper(topNode, f) }
def traverseMapPre(f: (FloorplanTreeNode => Option[FloorplanRecord])) { traverseMapPreHelper(topNode, f) }
def traverseMapPost(f: (FloorplanTreeNode => Option[FloorplanRecord])) { traverseMapPostHelper(topNode, f) }

private def traverseMapPreHelper(n: Node, f: (Node => Option[FloorplanRecord])) {
private def traverseMapPreHelper(n: FloorplanTreeNode, f: (FloorplanTreeNode => Option[FloorplanRecord])) {
f(n).foreach { r => n.replace(r) }
n.children.foreach { c => traverseMapPreHelper(c, f) }
}

private def traverseMapPostHelper(n: Node, f: (Node => Option[FloorplanRecord])) {
private def traverseMapPostHelper(n: FloorplanTreeNode, f: (FloorplanTreeNode => Option[FloorplanRecord])) {
n.children.foreach { c => traverseMapPostHelper(c, f) }
f(n).foreach { r => n.replace(r) }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ class OutOfBandAnnotationPass(val sbMap: Map[String, OutOfBandAnnotation]) exten
area = e.area.and(sb.areaConstraint)
)
).getOrElse(e)
case e: SizedHierarchicalTop =>
sbMap.get(ofModule).map({sb =>
e.copy(
width = sb.width.getOrElse(e.width),
height = sb.height.getOrElse(e.height)
)
}).getOrElse(e)
case e: PlacedHierarchicalTop =>
sbMap.get(ofModule).map({sb =>
e.copy(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class ReplaceHierarchicalPass(val topMod: String) extends Pass {
// Find HierarchicalTop records, then stitch them together
val topMaps = (state.records.flatMap(r => r.element match {
case e: ConstrainedHierarchicalTop => Some((r.fullPath -> r))
case e: SizedHierarchicalTop => Some((r.fullPath -> r))
case e: PlacedHierarchicalTop => Some((r.fullPath -> r))
case _ => None
})).toMap
Expand Down Expand Up @@ -78,6 +79,7 @@ class ReplaceHierarchicalPass(val topMod: String) extends Pass {
area = t.area,
aspectRatio = t.aspectRatio
))
case t: SizedHierarchicalTop => ??? // TODO not supported yet
case t: PlacedHierarchicalTop => ??? // TODO not supported yet
case _ => ???
}).map(newE => FloorplanRecord(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ class ResolveConstraintsPass(topMod: String) extends Pass {
)))
case e: ConstrainedHierarchicalTop =>
val (width, height) = resolveConstraints(e)
Some(node.record.copy(element = PlacedHierarchicalTop(
Some(node.record.copy(element = SizedHierarchicalTop(
e.name,
Seq(e.topGroup),
e.topGroup,
width,
height,
e.margins,
Expand Down

0 comments on commit 3bcdb5b

Please sign in to comment.