UPF Generation
This commit is contained in:
committed by
abejgonzalez
parent
07fc230a1c
commit
6f8041bf82
@@ -126,7 +126,8 @@ lazy val rocketchip = freshProject("rocketchip", rocketChipDir)
|
|||||||
libraryDependencies ++= Seq(
|
libraryDependencies ++= Seq(
|
||||||
"org.scala-lang" % "scala-reflect" % scalaVersion.value,
|
"org.scala-lang" % "scala-reflect" % scalaVersion.value,
|
||||||
"org.json4s" %% "json4s-jackson" % "3.6.6",
|
"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
|
.settings( // Settings for scalafix
|
||||||
|
|||||||
@@ -20,7 +20,8 @@ HELP_COMPILATION_VARIABLES += \
|
|||||||
" ENABLE_YOSYS_FLOW = if set, add compilation flags to enable the vlsi flow for yosys(tutorial flow)" \
|
" ENABLE_YOSYS_FLOW = if set, add compilation flags to enable the vlsi flow for yosys(tutorial flow)" \
|
||||||
" EXTRA_CHISEL_OPTIONS = additional options to pass to the Chisel compiler" \
|
" EXTRA_CHISEL_OPTIONS = additional options to pass to the Chisel compiler" \
|
||||||
" EXTRA_BASE_FIRRTL_OPTIONS = additional options to pass to the Scala FIRRTL compiler" \
|
" EXTRA_BASE_FIRRTL_OPTIONS = additional options to pass to the Scala FIRRTL compiler" \
|
||||||
" MFC_BASE_LOWERING_OPTIONS = override lowering options to pass to the MLIR FIRRTL compiler"
|
" MFC_BASE_LOWERING_OPTIONS = override lowering options to pass to the MLIR FIRRTL compiler" \
|
||||||
|
" ASPECTS = comma separated list of Chisel aspect flows to run (e.x. chipyard.upf.ChipTopUPFAspect)"
|
||||||
|
|
||||||
EXTRA_GENERATOR_REQS ?= $(BOOTROM_TARGETS)
|
EXTRA_GENERATOR_REQS ?= $(BOOTROM_TARGETS)
|
||||||
EXTRA_SIM_CXXFLAGS ?=
|
EXTRA_SIM_CXXFLAGS ?=
|
||||||
@@ -29,6 +30,11 @@ EXTRA_SIM_SOURCES ?=
|
|||||||
EXTRA_SIM_REQS ?=
|
EXTRA_SIM_REQS ?=
|
||||||
ENABLE_CUSTOM_FIRRTL_PASS += $(ENABLE_YOSYS_FLOW)
|
ENABLE_CUSTOM_FIRRTL_PASS += $(ENABLE_YOSYS_FLOW)
|
||||||
|
|
||||||
|
ifneq ($(ASPECTS), )
|
||||||
|
comma = ,
|
||||||
|
ASPECT_ARGS = $(foreach aspect, $(subst $(comma), , $(ASPECTS)), --with-aspect $(aspect))
|
||||||
|
endif
|
||||||
|
|
||||||
#----------------------------------------------------------------------------
|
#----------------------------------------------------------------------------
|
||||||
HELP_SIMULATION_VARIABLES += \
|
HELP_SIMULATION_VARIABLES += \
|
||||||
" EXTRA_SIM_FLAGS = additional runtime simulation flags (passed within +permissive)" \
|
" EXTRA_SIM_FLAGS = additional runtime simulation flags (passed within +permissive)" \
|
||||||
@@ -134,6 +140,7 @@ $(FIRRTL_FILE) $(ANNO_FILE) $(CHISEL_LOG_FILE) &: $(CHIPYARD_CLASSPATH_TARGETS)
|
|||||||
--name $(long_name) \
|
--name $(long_name) \
|
||||||
--top-module $(MODEL_PACKAGE).$(MODEL) \
|
--top-module $(MODEL_PACKAGE).$(MODEL) \
|
||||||
--legacy-configs $(CONFIG_PACKAGE):$(CONFIG) \
|
--legacy-configs $(CONFIG_PACKAGE):$(CONFIG) \
|
||||||
|
$(ASPECT_ARGS) \
|
||||||
$(EXTRA_CHISEL_OPTIONS)) | tee $(CHISEL_LOG_FILE))
|
$(EXTRA_CHISEL_OPTIONS)) | tee $(CHISEL_LOG_FILE))
|
||||||
|
|
||||||
define mfc_extra_anno_contents
|
define mfc_extra_anno_contents
|
||||||
|
|||||||
@@ -106,3 +106,22 @@ 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.
|
* ``-$(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.
|
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
|
||||||
|
-------------------------------
|
||||||
|
This VLSI flow experimentally supports generating Chisel-based `UPF <https://vlsitutorials.com/upf-low-power-vlsi/>`__ files using `Chisel Aspects <https://javadoc.io/doc/edu.berkeley.cs/chisel3_2.13/latest/chisel3/aop/Aspect.html>`__.
|
||||||
|
|
||||||
|
To generate UPF for any design, first modify the ``UPFInputs`` object 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 domain with all uncore modules and 2 children corresponding to the Rocket tiles).
|
||||||
|
|
||||||
|
To run the flow:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
cd chipyard/vlsi
|
||||||
|
make verilog ASPECTS=chipyard.upf.ChipTopUPFAspect
|
||||||
|
|
||||||
|
The output UPF files will be dumped in ``vlsi/generated-src/upf``.
|
||||||
|
|||||||
90
generators/chipyard/src/main/scala/upf/ChipTopUPF.scala
Normal file
90
generators/chipyard/src/main/scala/upf/ChipTopUPF.scala
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
// See LICENSE for license details
|
||||||
|
package chipyard.upf
|
||||||
|
|
||||||
|
import scala.collection.mutable.ListBuffer
|
||||||
|
import scalax.collection.mutable.Graph
|
||||||
|
import scalax.collection.GraphPredef._, scalax.collection.GraphEdge._
|
||||||
|
|
||||||
|
import chipyard.TestHarness
|
||||||
|
import freechips.rocketchip.diplomacy.LazyModule
|
||||||
|
|
||||||
|
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)
|
||||||
23
generators/chipyard/src/main/scala/upf/UPFAspect.scala
Normal file
23
generators/chipyard/src/main/scala/upf/UPFAspect.scala
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
// 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
|
||||||
|
}
|
||||||
264
generators/chipyard/src/main/scala/upf/UPFGen.scala
Normal file
264
generators/chipyard/src/main/scala/upf/UPFGen.scala
Normal file
@@ -0,0 +1,264 @@
|
|||||||
|
// See LICENSE for license details
|
||||||
|
package chipyard.upf
|
||||||
|
|
||||||
|
import java.io.FileWriter
|
||||||
|
import java.nio.file.{Paths, Files}
|
||||||
|
import scala.collection.mutable.ListBuffer
|
||||||
|
import scalax.collection.mutable.Graph
|
||||||
|
import scalax.collection.GraphPredef._, scalax.collection.GraphEdge._
|
||||||
|
|
||||||
|
import freechips.rocketchip.diplomacy.LazyModule
|
||||||
|
|
||||||
|
case class PowerDomain (val name: String, val modules: ListBuffer[LazyModule],
|
||||||
|
val isTop: Boolean, val isGated: Boolean,
|
||||||
|
val highVoltage: Double, val lowVoltage: Double) {
|
||||||
|
val mainVoltage = isGated match {
|
||||||
|
case true => highVoltage // gated nets should have access to high voltage rail (since they are being gated to optimize power)
|
||||||
|
case false => lowVoltage // currently assuming non-gated nets are on low voltage rail
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object UPFGenerator {
|
||||||
|
|
||||||
|
def generateUPF(pd: PowerDomain, g: Graph[PowerDomain, DiEdge]): Unit = {
|
||||||
|
val node = g.get(pd)
|
||||||
|
val children = node.diSuccessors.map(x => x.toOuter).toList
|
||||||
|
val pdList = g.nodes.map(x => x.toOuter).toList
|
||||||
|
val filePath = UPFFunc.UPFPath
|
||||||
|
val fileName = s"${pd.name}.upf"
|
||||||
|
writeFile(filePath, fileName, createMessage(pd, children, pdList))
|
||||||
|
}
|
||||||
|
|
||||||
|
def createMessage(pd: PowerDomain, children: List[PowerDomain], pdList: List[PowerDomain]): String = {
|
||||||
|
var message = ""
|
||||||
|
message += loadUPF(pd, children)
|
||||||
|
message += createPowerDomains(pd)
|
||||||
|
message += createSupplyPorts(pd)
|
||||||
|
message += createSupplyNets(pd)
|
||||||
|
message += connectSupplies(pd)
|
||||||
|
message += setDomainNets(pd)
|
||||||
|
message += createPowerSwitches(pd)
|
||||||
|
message += createPowerStateTable(pd, getPorts(pd, children))
|
||||||
|
message += createLevelShifters(pd, pdList)
|
||||||
|
return message
|
||||||
|
}
|
||||||
|
|
||||||
|
def writeFile(filePath: String, fileName: String, message: String): Unit = {
|
||||||
|
if (!Files.exists(Paths.get(filePath))) {
|
||||||
|
Files.createDirectories(Paths.get(filePath))
|
||||||
|
}
|
||||||
|
val fw = new FileWriter(s"${filePath}/${fileName}", false)
|
||||||
|
fw.write(message)
|
||||||
|
fw.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
def getPorts(pd: PowerDomain, children: List[PowerDomain]): ListBuffer[String] = {
|
||||||
|
var portsList = ListBuffer[String]()
|
||||||
|
portsList += "VDDH"
|
||||||
|
portsList += "VDDL"
|
||||||
|
if (pd.isGated) {
|
||||||
|
portsList += s"VDD_${pd.name}"
|
||||||
|
}
|
||||||
|
for (child <- children) {
|
||||||
|
if (child.isGated) {
|
||||||
|
portsList += s"VDD_${child.name}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return portsList
|
||||||
|
}
|
||||||
|
|
||||||
|
def loadUPF(pd: PowerDomain, children: List[PowerDomain]): String = {
|
||||||
|
var message = "##### Set Scope and Load UPF #####\n"
|
||||||
|
var subMessage = s"set_scope /${pd.modules(0).module.name}\n" //
|
||||||
|
children.foreach{
|
||||||
|
child => {
|
||||||
|
subMessage += s"load_upf ${child.name}.upf -scope ${child.modules(0).module.name}\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
message += subMessage
|
||||||
|
message += "\n"
|
||||||
|
return message
|
||||||
|
}
|
||||||
|
|
||||||
|
def createPowerDomains(pd: PowerDomain): String = {
|
||||||
|
var message = "##### Create Power Domains #####\n"
|
||||||
|
var subMessage = ""
|
||||||
|
pd.isTop match {
|
||||||
|
case true => subMessage += s"create_power_domain ${pd.name} -include_scope\n"
|
||||||
|
case false => {
|
||||||
|
subMessage += s"create_power_domain ${pd.name} -elements { "
|
||||||
|
for (module <- pd.modules) {
|
||||||
|
subMessage += s"${module.module.name} "
|
||||||
|
}
|
||||||
|
subMessage += "}\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
message += subMessage
|
||||||
|
message += "\n"
|
||||||
|
return message
|
||||||
|
}
|
||||||
|
|
||||||
|
def createSupplyPorts(pd: PowerDomain): String = {
|
||||||
|
if (!pd.isTop) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
var message = "##### Create Supply Ports #####\n"
|
||||||
|
var subMessage = pd.isTop match {
|
||||||
|
case true => {
|
||||||
|
s"create_supply_port VDDH -direction in -domain ${pd.name}\n" +
|
||||||
|
s"create_supply_port VDDL -direction in -domain ${pd.name}\n" +
|
||||||
|
s"create_supply_port VSS -direction in -domain ${pd.name}\n"
|
||||||
|
}
|
||||||
|
case false => ""
|
||||||
|
}
|
||||||
|
message += subMessage
|
||||||
|
message += "\n"
|
||||||
|
return message
|
||||||
|
}
|
||||||
|
|
||||||
|
def createSupplyNets(pd: PowerDomain): String = {
|
||||||
|
var message = "##### Create Supply Nets #####\n"
|
||||||
|
var subMessage = pd.isTop match {
|
||||||
|
case true => {
|
||||||
|
s"create_supply_net VDDH -domain ${pd.name}\n" +
|
||||||
|
s"create_supply_net VDDL -domain ${pd.name}\n" +
|
||||||
|
s"create_supply_net VSS -domain ${pd.name}\n"
|
||||||
|
}
|
||||||
|
case false => {
|
||||||
|
s"create_supply_net VDDH -domain ${pd.name} -reuse\n" +
|
||||||
|
s"create_supply_net VDDL -domain ${pd.name} -reuse\n" +
|
||||||
|
s"create_supply_net VSS -domain ${pd.name} -reuse\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pd.isGated) {
|
||||||
|
subMessage += s"create_supply_net VDD_${pd.name} -domain ${pd.name}\n"
|
||||||
|
}
|
||||||
|
message += subMessage
|
||||||
|
message += "\n"
|
||||||
|
return message
|
||||||
|
}
|
||||||
|
|
||||||
|
def connectSupplies(pd: PowerDomain): String = {
|
||||||
|
var message = "##### Connect Supply Nets and Ports #####\n"
|
||||||
|
var subMessage = "connect_supply_net VDDH -ports VDDH\n" +
|
||||||
|
"connect_supply_net VDDL -ports VDDL\n" +
|
||||||
|
"connect_supply_net VSS -ports VSS\n"
|
||||||
|
message += subMessage
|
||||||
|
message += "\n"
|
||||||
|
return message
|
||||||
|
}
|
||||||
|
|
||||||
|
def setDomainNets(pd: PowerDomain): String = {
|
||||||
|
var message = "##### Set Domain Supply Nets #####\n"
|
||||||
|
var subMessage = pd.isGated match {
|
||||||
|
case true => s"set_domain_supply_net ${pd.name} -primary_power_net VDD_${pd.name} -primary_ground_net VSS\n"
|
||||||
|
case false => s"set_domain_supply_net ${pd.name} -primary_power_net VDDL -primary_ground_net VSS\n"
|
||||||
|
}
|
||||||
|
message += subMessage
|
||||||
|
message += "\n"
|
||||||
|
return message
|
||||||
|
}
|
||||||
|
|
||||||
|
def createPowerSwitches(pd: PowerDomain): String = {
|
||||||
|
if (!pd.isGated) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
var message = "##### Power Switches #####\n"
|
||||||
|
var subMessage = pd.isGated match {
|
||||||
|
case true => s"""create_power_switch sw_${pd.name} -domain ${pd.name} -input_supply_port "psw_VDDH VDDH" """ +
|
||||||
|
s"""-output_supply_port "psw_VDD_${pd.name} VDD_${pd.name}" """ +
|
||||||
|
s"""-control_port "psw_${pd.name}_en ${pd.modules(0).module.name}/${pd.modules(0).module.name}_en" """ +
|
||||||
|
s"""-on_state "psw_${pd.name}_ON psw_VDDH { !psw_${pd.name}_en }"""" + "\n"
|
||||||
|
case false => ""
|
||||||
|
}
|
||||||
|
message += subMessage
|
||||||
|
message += "\n"
|
||||||
|
return message
|
||||||
|
}
|
||||||
|
|
||||||
|
def createPowerStateTable(pd: PowerDomain, portsList: ListBuffer[String]): String = {
|
||||||
|
if (!pd.isTop) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
var message = "##### Power State Table #####\n"
|
||||||
|
var portStates = ""
|
||||||
|
var createPST = "create_pst pst_table -supplies { "
|
||||||
|
|
||||||
|
for (port <- portsList) {
|
||||||
|
createPST += s"${port} "
|
||||||
|
if (port == "VDDH") {
|
||||||
|
portStates += s"add_port_state ${port} -state { HighVoltage ${pd.highVoltage} }\n"
|
||||||
|
} else if (port == "VDDL") {
|
||||||
|
portStates += s"add_port_state ${port} -state { LowVoltage ${pd.lowVoltage} }\n"
|
||||||
|
} else { // gated
|
||||||
|
portStates += s"add_port_state ${port} -state { HighVoltage ${pd.highVoltage } -state { ${port}_OFF off }\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
portStates += "\n"
|
||||||
|
createPST += "}\n\n"
|
||||||
|
|
||||||
|
var pstStates = ""
|
||||||
|
for (state <- UPFInputs.states.keys) {
|
||||||
|
val stateVal = getStateVal(pd, state)
|
||||||
|
pstStates += s"add_pst_state ${state} -pst pst_table -state { "
|
||||||
|
for (port <- portsList) {
|
||||||
|
if (port == "VDDH") {
|
||||||
|
pstStates += s"HighVoltage "
|
||||||
|
} else if (port == "VDDL") {
|
||||||
|
pstStates += s"LowVoltage "
|
||||||
|
} else { // gated
|
||||||
|
stateVal match {
|
||||||
|
case 0 => pstStates += s"${port}_OFF "
|
||||||
|
case 1 => pstStates += s"HighVoltage "
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pstStates += "}\n"
|
||||||
|
}
|
||||||
|
message += portStates
|
||||||
|
message += createPST
|
||||||
|
message += pstStates
|
||||||
|
message += "\n"
|
||||||
|
return message
|
||||||
|
}
|
||||||
|
|
||||||
|
def getStateVal(pd: PowerDomain, state: String): Int = {
|
||||||
|
val stateVals = UPFInputs.states(state).split(",").map(_.trim.toInt)
|
||||||
|
val index = UPFInputs.domains.indexOf(pd.name)
|
||||||
|
return stateVals(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
// current strategy: for each power domain, create level shifters for outputs going to all other pds
|
||||||
|
// not creating level shifters for inputs since every pd will already shift its outputs
|
||||||
|
// creating level shifters going to every other pd since not sure how to check if there is communication or not between any 2
|
||||||
|
def createLevelShifters(pd: PowerDomain, pdList: List[PowerDomain]): String = {
|
||||||
|
var message = "##### Level Shifters #####\n"
|
||||||
|
for (pd2 <- pdList) {
|
||||||
|
if (pd != pd2) {
|
||||||
|
val voltage1 = pd.mainVoltage
|
||||||
|
val voltage2 = pd2.mainVoltage
|
||||||
|
var subMessage = voltage1 match {
|
||||||
|
case x if x < voltage2 => {
|
||||||
|
s"set_level_shifter LtoH_${pd.name}_to_${pd2.name} " +
|
||||||
|
s"-domain ${pd.name} " +
|
||||||
|
"-applies_to outputs " +
|
||||||
|
"rule low_to_high " +
|
||||||
|
"-location self\n"
|
||||||
|
}
|
||||||
|
case y if y > voltage2 => {
|
||||||
|
s"set_level_shifter HtoL_${pd.name}_to_${pd2.name} " +
|
||||||
|
s"-domain ${pd.name} " +
|
||||||
|
"-applies_to outputs " +
|
||||||
|
"rule high_to_low " +
|
||||||
|
"-location self\n"
|
||||||
|
}
|
||||||
|
case _ => ""
|
||||||
|
}
|
||||||
|
message += subMessage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
message += "\n"
|
||||||
|
return message
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
54
generators/chipyard/src/main/scala/upf/UPFInputs.scala
Normal file
54
generators/chipyard/src/main/scala/upf/UPFInputs.scala
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
// See LICENSE for license details
|
||||||
|
package chipyard.upf
|
||||||
|
|
||||||
|
// outputs are dumped in vlsi/generated-src/upf
|
||||||
|
object UPFInputs {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UPF info
|
||||||
|
* each PowerDomainInput represents a desired power domain
|
||||||
|
* each input will contain all the necessary info to describe a power domain in UPF, including hierarchy
|
||||||
|
*/
|
||||||
|
val upfInfo = List(
|
||||||
|
PowerDomainInput(name="PD_top", isTop=true, moduleList=List("DigitalTop"),
|
||||||
|
parentPD="", childrenPDs=List("PD_RocketTile1", "PD_RocketTile2"),
|
||||||
|
isGated=false, highVoltage=3.9, lowVoltage=3.4),
|
||||||
|
PowerDomainInput(name="PD_RocketTile1", isTop=false, moduleList=List("RocketTile"),
|
||||||
|
parentPD="PD_top", childrenPDs=List(),
|
||||||
|
isGated=false, highVoltage=3.9, lowVoltage=3.1),
|
||||||
|
PowerDomainInput(name="PD_RocketTile2", isTop=false, moduleList=List("RocketTile_1"),
|
||||||
|
parentPD="PD_top", childrenPDs=List(),
|
||||||
|
isGated=false, highVoltage=3.9, lowVoltage=3.2),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PST info
|
||||||
|
* experimental Power State Table input, used to gate power domains based on specified power states
|
||||||
|
* place names of all power domains to be gated in the domains list
|
||||||
|
* states will map different keywords (arbitrary strings) to a binary on or off (1 or 0) to form a power state
|
||||||
|
* order of domains in list corresponds to order of values in each states mapping
|
||||||
|
*/
|
||||||
|
val domains = List("PD_top", "PD_RocketTile1", "PD_RocketTile2")
|
||||||
|
val states = Map(
|
||||||
|
"ON" -> "1, 1, 1",
|
||||||
|
"OFF" -> "0, 0, 0"
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Representation of a power domain used to generate UPF.
|
||||||
|
*
|
||||||
|
* @param name name of the power domain.
|
||||||
|
* @param isTop if the power domain is the top level or not.
|
||||||
|
* @param moduleList refers to all the Verilog modules belonging to this power domain. Can be module name, instance name, or full path name.
|
||||||
|
* @param parentPD the name of the parent power domain to this one.
|
||||||
|
* @param childrenPDs names of all the children power domains to this one.
|
||||||
|
* @param isGated if the power domain is gated or not.
|
||||||
|
* @param highVoltage voltage value of the high voltage rail (currently, gated nets have access to high voltage since they are optimized to save power).
|
||||||
|
* @param lowVoltage voltage value of the low voltage rail (currently, non-gated nets default to the low voltage rail).
|
||||||
|
*/
|
||||||
|
case class PowerDomainInput(name: String, isTop: Boolean, moduleList: List[String],
|
||||||
|
parentPD: String, childrenPDs: List[String],
|
||||||
|
isGated: Boolean, highVoltage: Double, lowVoltage: Double)
|
||||||
Reference in New Issue
Block a user