diplomacy: add DeviceTree renderer
This commit is contained in:
parent
c01a74f4a0
commit
e322692d16
117
src/main/scala/diplomacy/DeviceTree.scala
Normal file
117
src/main/scala/diplomacy/DeviceTree.scala
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
|
package diplomacy
|
||||||
|
|
||||||
|
import Chisel._
|
||||||
|
import config._
|
||||||
|
|
||||||
|
case object DTSModel extends Field[String]
|
||||||
|
case object DTSCompat extends Field[Seq[String]] // -dev, -soc
|
||||||
|
case object DTSTimebase extends Field[BigInt] // Clock frequency of clint RTC (use 0 if you don't know it)
|
||||||
|
|
||||||
|
object DTS
|
||||||
|
{
|
||||||
|
def apply(res: ResourceValue): String = "/dts-v1/;\n\n" + helper(res, "", defaultCells).mkString("")
|
||||||
|
|
||||||
|
private val nodeStartChars = (('a' to 'z') ++ ('A' to 'Z')).toSet
|
||||||
|
private val nodeChars = (('a' to 'z') ++ ('A' to 'Z') ++ ('0' to '9') ++ Seq(',', '.', '_', '+', '-', '@')).toSet
|
||||||
|
def legalNode(x: String): Boolean =
|
||||||
|
x == "/" || (!x.isEmpty && x.size < 32 && nodeStartChars.contains(x(0)) && x.forall(nodeChars.contains(_)))
|
||||||
|
|
||||||
|
// the DTS spec does not list '-', but uses it everywhere ...
|
||||||
|
private val propChars = (('a' to 'z') ++ ('A' to 'Z') ++ ('0' to '9') ++ Seq(',', '.', '_', '+', '?', '#', '-')).toSet
|
||||||
|
def legalProperty(x: String): Boolean =
|
||||||
|
x == "/" || (!x.isEmpty && x.size < 32 && x.forall(propChars.contains(_)))
|
||||||
|
|
||||||
|
// The DTS spec doesn't say what is allowed in a string, so just use our own judgement
|
||||||
|
private val strChars = (('#' to '[') ++ (']' to '~') ++ Seq(' ', '!')).toSet
|
||||||
|
def legalString(x: String): Boolean = x.forall(strChars.contains(_))
|
||||||
|
|
||||||
|
private case class Cells(
|
||||||
|
parentAddress: Int,
|
||||||
|
parentSize: Int,
|
||||||
|
selfAddress: Int,
|
||||||
|
selfSize: Int)
|
||||||
|
private val defaultCells = Cells(2, 1, 2, 1)
|
||||||
|
|
||||||
|
private def fmtCell(x: BigInt, cells: Int): Seq[String] = {
|
||||||
|
val cellbits = 32
|
||||||
|
val mask = (BigInt(1) << cellbits) - 1
|
||||||
|
(0 until cells).reverse map { case i => "0x%x".format((x >> (i*cellbits)) & mask) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private def fmtAddress(x: ResourceAddress, cells: Cells): Seq[String] = {
|
||||||
|
val ranges = AddressRange.fromSets(x.address)
|
||||||
|
ranges.flatMap { case AddressRange(base, size) =>
|
||||||
|
fmtCell(base, cells.parentAddress) ++ fmtCell(size, cells.parentSize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private def fmtMapping(x: ResourceMapping, cells: Cells): Seq[String] = {
|
||||||
|
val ranges = AddressRange.fromSets(x.address)
|
||||||
|
ranges.flatMap { case AddressRange(base, size) =>
|
||||||
|
fmtCell(base+x.offset, cells.selfAddress) ++ fmtCell(base, cells.parentAddress) ++ fmtCell(size, cells.selfSize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private def fmtString(x: ResourceString): Seq[String] = {
|
||||||
|
require (legalString(x.value), s"The string '${x.value}' contains chars probably unwise for use in a DTS string")
|
||||||
|
Seq("\"" + x.value + "\"")
|
||||||
|
}
|
||||||
|
|
||||||
|
private def fmtMap(x: ResourceMap, indent: String, cells: Cells): Seq[String] = {
|
||||||
|
val (nodes, props) = x.value.partition(_ match {
|
||||||
|
case (_, Seq(ResourceMap(_, _))) => true
|
||||||
|
case _ => false
|
||||||
|
})
|
||||||
|
|
||||||
|
def getInt(x: ResourceValue) = x match {
|
||||||
|
case ResourceInt(value) => Some(value.toInt)
|
||||||
|
case _ => None
|
||||||
|
}
|
||||||
|
val selfAddress = x.value.getOrElse("#address-cells", Nil).headOption.flatMap(getInt)
|
||||||
|
val selfSize = x.value.getOrElse("#size-cells", Nil).headOption.flatMap(getInt)
|
||||||
|
|
||||||
|
val myCells = Cells(
|
||||||
|
parentAddress = cells.selfAddress,
|
||||||
|
parentSize = cells.selfSize,
|
||||||
|
selfAddress = selfAddress.getOrElse(defaultCells.selfAddress),
|
||||||
|
selfSize = selfSize .getOrElse(defaultCells.selfSize))
|
||||||
|
|
||||||
|
props.flatMap { case (k, seq) =>
|
||||||
|
require (legalProperty(k), s"The string '${k}' is not a legal DTS property name")
|
||||||
|
seq.headOption match {
|
||||||
|
case None => Seq(indent, k, ";\n")
|
||||||
|
case Some(ResourceString(_)) => {
|
||||||
|
seq.foreach { r => r match {
|
||||||
|
case ResourceString(_) => Unit
|
||||||
|
case _ => require(false, s"The property '${k}' has values of conflicting type: ${seq}")
|
||||||
|
} }
|
||||||
|
Seq(indent, k, " = ", seq.flatMap(z => helper(z, "", myCells)).mkString(", "), ";\n")
|
||||||
|
}
|
||||||
|
case Some(_) => {
|
||||||
|
seq.foreach { r => r match {
|
||||||
|
case ResourceMap(_, _) => require(false, s"The property '${k}' has values of conflicting type: ${seq}")
|
||||||
|
case ResourceString(_) => require(false, s"The property '${k}' has values of conflicting type: ${seq}")
|
||||||
|
case _ => Unit
|
||||||
|
} }
|
||||||
|
Seq(indent, k, " = <", seq.flatMap(z => helper(z, "", myCells)).mkString(" "), ">;\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.toList ++
|
||||||
|
nodes.flatMap { case (k, Seq(s: ResourceMap)) =>
|
||||||
|
require (legalNode(k), s"The string '${k}' is not a legal DTS node name")
|
||||||
|
Seq(indent) ++ s.labels.map(_ + ": ").filter(_ => !indent.isEmpty) ++ // labels on root not allowed
|
||||||
|
Seq(k, " {\n") ++ helper(s, indent + "\t", myCells) ++ Seq(indent, "};\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private def helper(res: ResourceValue, indent: String, cells: Cells): Seq[String] = res match {
|
||||||
|
case x: ResourceAddress => fmtAddress(x, cells)
|
||||||
|
case x: ResourceMapping => fmtMapping(x, cells)
|
||||||
|
case x: ResourceInt => Seq(x.value.toString)
|
||||||
|
case x: ResourceString => fmtString(x)
|
||||||
|
case x: ResourceReference => Seq("&" + x.value)
|
||||||
|
case x: ResourceMap => fmtMap(x, indent, cells)
|
||||||
|
}
|
||||||
|
}
|
@ -20,6 +20,10 @@ import DefaultTestSuites._
|
|||||||
import config._
|
import config._
|
||||||
|
|
||||||
class BasePlatformConfig extends Config((site, here, up) => {
|
class BasePlatformConfig extends Config((site, here, up) => {
|
||||||
|
// DTS descriptive parameters
|
||||||
|
case DTSModel => "ucbbar,rocketchip-unknown"
|
||||||
|
case DTSCompat => Nil
|
||||||
|
case DTSTimebase => BigInt(0)
|
||||||
// TileLink connection parameters
|
// TileLink connection parameters
|
||||||
case TLMonitorBuilder => (args: TLMonitorArgs) => Some(LazyModule(new TLMonitor(args)))
|
case TLMonitorBuilder => (args: TLMonitorArgs) => Some(LazyModule(new TLMonitor(args)))
|
||||||
case TLFuzzReadyValid => false
|
case TLFuzzReadyValid => false
|
||||||
@ -139,6 +143,11 @@ class WithExtMemSize(n: Long) extends Config((site, here, up) => {
|
|||||||
case ExtMem => up(ExtMem, site).copy(size = n)
|
case ExtMem => up(ExtMem, site).copy(size = n)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
class WithDTS(model: String, compat: Seq[String]) extends Config((site, here, up) => {
|
||||||
|
case DTSModel => model
|
||||||
|
case DTSCompat => compat
|
||||||
|
})
|
||||||
|
|
||||||
class WithScratchpad extends Config(new WithNMemoryChannels(0) ++ new WithDataScratchpad(16384))
|
class WithScratchpad extends Config(new WithNMemoryChannels(0) ++ new WithDataScratchpad(16384))
|
||||||
|
|
||||||
class DefaultFPGASmallConfig extends Config(new WithNSmallCores(1) ++ new DefaultFPGAConfig)
|
class DefaultFPGASmallConfig extends Config(new WithNSmallCores(1) ++ new DefaultFPGAConfig)
|
||||||
|
Loading…
Reference in New Issue
Block a user