diplomacy: AddressMapEntry and BindingScope.collect
This commit is contained in:
parent
2489a08328
commit
3cb9e57b5e
75
src/main/scala/diplomacy/AddressRange.scala
Normal file
75
src/main/scala/diplomacy/AddressRange.scala
Normal file
@ -0,0 +1,75 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package freechips.rocketchip.diplomacy
|
||||
|
||||
import Chisel._
|
||||
|
||||
// Use AddressSet instead -- this is just for pretty printing
|
||||
case class AddressRange(base: BigInt, size: BigInt) extends Ordered[AddressRange]
|
||||
{
|
||||
val end = base + size
|
||||
|
||||
require (base >= 0, s"AddressRange base must be positive, got: $base")
|
||||
require (size > 0, s"AddressRange size must be > 0, got: $size")
|
||||
|
||||
def compare(x: AddressRange) = {
|
||||
val primary = (this.base - x.base).signum
|
||||
val secondary = (x.size - this.size).signum
|
||||
if (primary != 0) primary else secondary
|
||||
}
|
||||
|
||||
def contains(x: AddressRange) = base <= x.base && x.end <= end
|
||||
def union(x: AddressRange): Option[AddressRange] = {
|
||||
if (base > x.end || x.base > end) {
|
||||
None
|
||||
} else {
|
||||
val obase = if (base < x.base) base else x.base
|
||||
val oend = if (end > x.end) end else x.end
|
||||
Some(AddressRange(obase, oend-obase))
|
||||
}
|
||||
}
|
||||
|
||||
private def helper(base: BigInt, end: BigInt) =
|
||||
if (base < end) Seq(AddressRange(base, end-base)) else Nil
|
||||
def subtract(x: AddressRange) =
|
||||
helper(base, end min x.base) ++ helper(base max x.end, end)
|
||||
|
||||
// We always want to see things in hex
|
||||
override def toString() = "AddressRange(0x%x, 0x%x)".format(base, size)
|
||||
}
|
||||
|
||||
object AddressRange
|
||||
{
|
||||
def fromSets(seq: Seq[AddressSet]): Seq[AddressRange] = unify(seq.flatMap(_.toRanges))
|
||||
def unify(seq: Seq[AddressRange]): Seq[AddressRange] = {
|
||||
if (seq.isEmpty) return Nil
|
||||
val ranges = seq.sorted
|
||||
ranges.tail.foldLeft(Seq(ranges.head)) { case (head :: tail, x) =>
|
||||
head.union(x) match {
|
||||
case Some(z) => z :: tail
|
||||
case None => x :: head :: tail
|
||||
}
|
||||
}.reverse
|
||||
}
|
||||
// Set subtraction... O(n*n) b/c I am lazy
|
||||
def subtract(from: Seq[AddressRange], take: Seq[AddressRange]): Seq[AddressRange] =
|
||||
take.foldLeft(from) { case (left, r) => left.flatMap { _.subtract(r) } }
|
||||
}
|
||||
|
||||
case class AddressMapEntry(range: AddressRange, permissions: ResourcePermissions, names: Seq[String]) {
|
||||
val ResourcePermissions(r, w, x, c, a) = permissions
|
||||
|
||||
def toString(aw: Int) = s"\t%${aw}x - %${aw}x %c%c%c%c%c %s".format(
|
||||
range.base,
|
||||
range.base+range.size,
|
||||
if (a) 'A' else ' ',
|
||||
if (r) 'R' else ' ',
|
||||
if (w) 'W' else ' ',
|
||||
if (x) 'X' else ' ',
|
||||
if (c) 'C' else ' ',
|
||||
names.mkString(", "))
|
||||
|
||||
def serialize = s"""{"base":[${range.base}],"size":[${range.size}],""" +
|
||||
s""""r":[$r],"w":[$w],"x":[$x],"c":[$c],"a":[$a],""" +
|
||||
s""""names":[${names.map('"'+_+'"').mkString(",")}]}"""
|
||||
}
|
@ -104,40 +104,6 @@ object TransferSizes {
|
||||
implicit def asBool(x: TransferSizes) = !x.none
|
||||
}
|
||||
|
||||
// Use AddressSet instead -- this is just for pretty printing
|
||||
case class AddressRange(base: BigInt, size: BigInt) extends Ordered[AddressRange]
|
||||
{
|
||||
val end = base + size
|
||||
|
||||
require (base >= 0, s"AddressRange base must be positive, got: $base")
|
||||
require (size > 0, s"AddressRange size must be > 0, got: $size")
|
||||
|
||||
def compare(x: AddressRange) = {
|
||||
val primary = (this.base - x.base).signum
|
||||
val secondary = (x.size - this.size).signum
|
||||
if (primary != 0) primary else secondary
|
||||
}
|
||||
|
||||
def contains(x: AddressRange) = base <= x.base && x.end <= end
|
||||
def union(x: AddressRange): Option[AddressRange] = {
|
||||
if (base > x.end || x.base > end) {
|
||||
None
|
||||
} else {
|
||||
val obase = if (base < x.base) base else x.base
|
||||
val oend = if (end > x.end) end else x.end
|
||||
Some(AddressRange(obase, oend-obase))
|
||||
}
|
||||
}
|
||||
|
||||
private def helper(base: BigInt, end: BigInt) =
|
||||
if (base < end) Seq(AddressRange(base, end-base)) else Nil
|
||||
def subtract(x: AddressRange) =
|
||||
helper(base, end min x.base) ++ helper(base max x.end, end)
|
||||
|
||||
// We always want to see things in hex
|
||||
override def toString() = "AddressRange(0x%x, 0x%x)".format(base, size)
|
||||
}
|
||||
|
||||
// AddressSets specify the address space managed by the manager
|
||||
// Base is the base address, and mask are the bits consumed by the manager
|
||||
// e.g: base=0x200, mask=0xff describes a device managing 0x200-0x2ff
|
||||
@ -210,24 +176,6 @@ case class AddressSet(base: BigInt, mask: BigInt) extends Ordered[AddressSet]
|
||||
}
|
||||
}
|
||||
|
||||
object AddressRange
|
||||
{
|
||||
def fromSets(seq: Seq[AddressSet]): Seq[AddressRange] = unify(seq.flatMap(_.toRanges))
|
||||
def unify(seq: Seq[AddressRange]): Seq[AddressRange] = {
|
||||
if (seq.isEmpty) return Nil
|
||||
val ranges = seq.sorted
|
||||
ranges.tail.foldLeft(Seq(ranges.head)) { case (head :: tail, x) =>
|
||||
head.union(x) match {
|
||||
case Some(z) => z :: tail
|
||||
case None => x :: head :: tail
|
||||
}
|
||||
}.reverse
|
||||
}
|
||||
// Set subtraction... O(n*n) b/c I am lazy
|
||||
def subtract(from: Seq[AddressRange], take: Seq[AddressRange]): Seq[AddressRange] =
|
||||
take.foldLeft(from) { case (left, r) => left.flatMap { _.subtract(r) } }
|
||||
}
|
||||
|
||||
object AddressSet
|
||||
{
|
||||
val everything = AddressSet(0, -1)
|
||||
|
@ -251,6 +251,15 @@ trait BindingScope
|
||||
}
|
||||
}
|
||||
|
||||
private def collect(path: List[String], value: ResourceValue): List[(String, ResourceAddress)] = {
|
||||
value match {
|
||||
case r: ResourceAddress => List((path(1), r))
|
||||
case b: ResourceMapping => List((path(1), ResourceAddress(b.address, b.permissions)))
|
||||
case ResourceMap(value, _) => value.toList.flatMap { case (key, seq) => seq.flatMap(r => collect(key :: path, r)) }
|
||||
case _ => Nil
|
||||
}
|
||||
}
|
||||
|
||||
/** Generate the device tree. */
|
||||
def bindingTree: ResourceMap = {
|
||||
eval
|
||||
@ -263,6 +272,9 @@ trait BindingScope
|
||||
expand(tokens, Seq(ResourceMap(mapping, Seq(d.label)))) })
|
||||
ResourceMap(SortedMap("/" -> tree))
|
||||
}
|
||||
|
||||
/** Collect resource addresses from tree. */
|
||||
def collectResourceAddresses = collect(Nil, bindingTree)
|
||||
}
|
||||
|
||||
object BindingScope
|
||||
|
@ -97,39 +97,22 @@ abstract class BaseSubsystem(implicit p: Parameters) extends BareSubsystem {
|
||||
}
|
||||
}
|
||||
|
||||
abstract class BaseSubsystemModuleImp[+L <: BaseSubsystem](_outer: L) extends BareSubsystemModuleImp(_outer) {
|
||||
println("Generated Address Map")
|
||||
private val aw = (outer.sbus.busView.bundle.addressBits-1)/4 + 1
|
||||
private val fmt = s"\t%${aw}x - %${aw}x %c%c%c%c%c %s"
|
||||
|
||||
private def collect(path: List[String], value: ResourceValue): List[(String, ResourceAddress)] = {
|
||||
value match {
|
||||
case r: ResourceAddress => List((path(1), r))
|
||||
case b: ResourceMapping => List((path(1), ResourceAddress(b.address, b.permissions)))
|
||||
case ResourceMap(value, _) => value.toList.flatMap { case (key, seq) => seq.flatMap(r => collect(key :: path, r)) }
|
||||
case _ => Nil
|
||||
}
|
||||
}
|
||||
private val ranges = collect(Nil, outer.bindingTree).groupBy(_._2).toList.flatMap { case (key, seq) =>
|
||||
AddressRange.fromSets(key.address).map { r => (r, key.permissions, seq.map(_._1)) }
|
||||
}.sortBy(_._1)
|
||||
private val json = ranges.map { case (range, ResourcePermissions(r, w, x, c, a), names) =>
|
||||
println(fmt.format(
|
||||
range.base,
|
||||
range.base+range.size,
|
||||
if (a) 'A' else ' ',
|
||||
if (r) 'R' else ' ',
|
||||
if (w) 'W' else ' ',
|
||||
if (x) 'X' else ' ',
|
||||
if (c) 'C' else ' ',
|
||||
names.mkString(", ")))
|
||||
s"""{"base":[${range.base}],"size":[${range.size}],"r":[$r],"w":[$w],"x":[$x],"c":[$c],"a":[$a],"names":[${names.map('"'+_+'"').mkString(",")}]}"""
|
||||
abstract class BaseSubsystemModuleImp[+L <: BaseSubsystem](_outer: L) extends BareSubsystemModuleImp(_outer) {
|
||||
private val mapping: Seq[AddressMapEntry] = {
|
||||
outer.collectResourceAddresses.groupBy(_._2).toList.flatMap { case (key, seq) =>
|
||||
AddressRange.fromSets(key.address).map { r => AddressMapEntry(r, key.permissions, seq.map(_._1)) }
|
||||
}.sortBy(_.range)
|
||||
}
|
||||
|
||||
println("Generated Address Map")
|
||||
mapping.map(entry => println(entry.toString((outer.sbus.busView.bundle.addressBits-1)/4 + 1)))
|
||||
println("")
|
||||
ElaborationArtefacts.add("memmap.json", s"""{"mapping":[${json.mkString(",")}]}""")
|
||||
|
||||
ElaborationArtefacts.add("memmap.json", s"""{"mapping":[${mapping.map(_.serialize).mkString(",")}]}""")
|
||||
|
||||
// Confirm that all of memory was described by DTS
|
||||
private val dtsRanges = AddressRange.unify(ranges.map(_._1))
|
||||
private val dtsRanges = AddressRange.unify(mapping.map(_.range))
|
||||
private val allRanges = AddressRange.unify(outer.topManagers.get.flatMap { m => AddressRange.fromSets(m.address) })
|
||||
|
||||
if (dtsRanges != allRanges) {
|
||||
|
Loading…
Reference in New Issue
Block a user