Skip to content

Commit

Permalink
# This is a combination of 2 commits.
Browse files Browse the repository at this point in the history
# This is the 1st commit message:

UPF Generation [ci skip]

# This is the commit message #2:

UPF Generation + docs

UPF Generation + docs
  • Loading branch information
Sriram Sridhar authored and abejgonzalez committed Jul 12, 2023
1 parent 07fc230 commit 4a38f71
Show file tree
Hide file tree
Showing 8 changed files with 430 additions and 1 deletion.
3 changes: 2 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,8 @@ lazy val rocketchip = freshProject("rocketchip", rocketChipDir)
libraryDependencies ++= Seq(
"org.scala-lang" % "scala-reflect" % scalaVersion.value,
"org.json4s" %% "json4s-jackson" % "3.6.6",
"org.scalatest" %% "scalatest" % "3.2.0" % "test"
"org.scalatest" %% "scalatest" % "3.2.0" % "test",
"org.scala-graph" %% "graph-core" % "1.13.5"
)
)
.settings( // Settings for scalafix
Expand Down
1 change: 1 addition & 0 deletions common.mk
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ $(FIRRTL_FILE) $(ANNO_FILE) $(CHISEL_LOG_FILE) &: $(CHIPYARD_CLASSPATH_TARGETS)
--name $(long_name) \
--top-module $(MODEL_PACKAGE).$(MODEL) \
--legacy-configs $(CONFIG_PACKAGE):$(CONFIG) \
$(UPF_ASPECT) \
$(EXTRA_CHISEL_OPTIONS)) | tee $(CHISEL_LOG_FILE))

define mfc_extra_anno_contents
Expand Down
15 changes: 15 additions & 0 deletions docs/VLSI/Advanced-Usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,18 @@ With the Synopsys plugin, hierarchical RTL and gate-level simulation is supporte
* ``-$(VLSI_TOP)`` suffixes denote simulations/power analysis on a submodule in a hierarchical flow (remember to override this variable). Note that you must provide the testbenches for these modules since the default testbench only simulates a Chipyard-based ``ChipTop`` DUT instance.

The simulation configuration (e.g. binaries) can be edited for your design. See the ``Makefile`` and refer to Hammer's documentation for how to set up simulation parameters for your design.

UPF Generation Flow
-------------------------------
To generate UPF for any design, first modify the UPFInputs in generators/chipyard/src/main/scala/upf/UPFInputs.scala to fit your design power specifications.

This involves filling in the upfInfo list with PowerDomainInput objects representing all the power domains you want in your design, along with specifying hierarchy and domain attributes.

The given example in UPFInputs corresponds to a dual-core Rocket config with 3 power domains (1 parent and 2 children).

To run the flow:

.. code-block:: shell
cd chipyard/vlsi
make verilog ASPECTS=chipyard.upf.ChipTopUPFAspect
91 changes: 91 additions & 0 deletions generators/chipyard/src/main/scala/upf/ChipTopUPF.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// See LICENSE for license details
package chipyard.upf

import chipyard.TestHarness
import freechips.rocketchip.diplomacy.LazyModule

import scala.collection.mutable.ListBuffer

import scalax.collection.mutable.Graph
import scalax.collection.GraphPredef._, scalax.collection.GraphEdge._

object ChipTopUPF {

def default: UPFFunc.UPFFunction = {
case top: LazyModule => {
val modulesList = getLazyModules(top)
val pdList = createPowerDomains(modulesList)
val g = connectPDHierarchy(pdList)
traverseGraph(g, UPFGenerator.generateUPF)
}
}

def getLazyModules(top: LazyModule): ListBuffer[LazyModule] = {
var i = 0
var result = new ListBuffer[LazyModule]()
result.append(top)
while (i < result.length) {
val lazyMod = result(i)
for (child <- lazyMod.getChildren) {
result.append(child)
}
i += 1
}
return result
}

def createPowerDomains(modulesList: ListBuffer[LazyModule]): ListBuffer[PowerDomain] = {
var pdList = ListBuffer[PowerDomain]()
for (pdInput <- UPFInputs.upfInfo) {
val pd = new PowerDomain(name=pdInput.name, modules=getPDModules(pdInput, modulesList),
isTop=pdInput.isTop, isGated=pdInput.isGated,
highVoltage=pdInput.highVoltage, lowVoltage=pdInput.lowVoltage)
pdList.append(pd)
}
return pdList
}

def getPDModules(pdInput: PowerDomainInput, modulesList: ListBuffer[LazyModule]): ListBuffer[LazyModule] = {
var pdModules = ListBuffer[LazyModule]()
for (moduleName <- pdInput.moduleList) {
var module = modulesList.filter(_.module.name == moduleName)
if (module.length == 1) { // filter returns a collection
pdModules.append(module(0))
} else {
module = modulesList.filter(_.module.instanceName == moduleName)
if (module.length == 1) {
pdModules.append(module(0))
} else {
module = modulesList.filter(_.module.pathName == moduleName)
if (module.length == 1) {
pdModules.append(module(0))
} else {
throw new Exception(s"PowerDomainInput module list doesn't exist in design.")
}
}
}
}
return pdModules
}

def connectPDHierarchy(pdList: ListBuffer[PowerDomain]): Graph[PowerDomain, DiEdge] = {
var g = Graph[PowerDomain, DiEdge]()
for (pd <- pdList) {
val pdInput = UPFInputs.upfInfo.filter(_.name == pd.name)(0)
val childPDs = pdList.filter(x => pdInput.childrenPDs.contains(x.name))
for (childPD <- childPDs) {
g += (pd ~> childPD) // directed edge from pd to childPD
}
}
return g
}

def traverseGraph(g: Graph[PowerDomain, DiEdge], action: (PowerDomain, Graph[PowerDomain, DiEdge]) => Unit): Unit = {
for (node <- g.nodes.filter(_.diPredecessors.isEmpty)) { // all nodes without parents
g.outerNodeTraverser(node).foreach(pd => action(pd, g))
}
}

}

case object ChipTopUPFAspect extends UPFAspect[chipyard.TestHarness](ChipTopUPF.default)
24 changes: 24 additions & 0 deletions generators/chipyard/src/main/scala/upf/UPFAspect.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// See LICENSE for license details
package chipyard.upf

import chisel3.aop.Aspect
import firrtl.{AnnotationSeq}
import chipyard.TestHarness
import freechips.rocketchip.stage.phases.TargetDirKey

import freechips.rocketchip.diplomacy.LazyModule

abstract class UPFAspect[T <: TestHarness](upf: UPFFunc.UPFFunction) extends Aspect[T] {

final override def toAnnotation(top: T): AnnotationSeq = {
UPFFunc.UPFPath = top.p(TargetDirKey) + "/upf"
upf(top.lazyDut)
AnnotationSeq(Seq()) // noop
}

}

object UPFFunc {
type UPFFunction = PartialFunction[LazyModule, Unit]
var UPFPath = "" // output dir path
}
Loading

0 comments on commit 4a38f71

Please sign in to comment.