diff --git a/src/main/scala/diplomacy/AddressRange.scala b/src/main/scala/diplomacy/AddressRange.scala new file mode 100644 index 00000000..9df91417 --- /dev/null +++ b/src/main/scala/diplomacy/AddressRange.scala @@ -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(",")}]}""" +} diff --git a/src/main/scala/diplomacy/Parameters.scala b/src/main/scala/diplomacy/Parameters.scala index 4133b52f..95110582 100644 --- a/src/main/scala/diplomacy/Parameters.scala +++ b/src/main/scala/diplomacy/Parameters.scala @@ -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) diff --git a/src/main/scala/diplomacy/Resources.scala b/src/main/scala/diplomacy/Resources.scala index 58ba6415..a8442d6f 100644 --- a/src/main/scala/diplomacy/Resources.scala +++ b/src/main/scala/diplomacy/Resources.scala @@ -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 diff --git a/src/main/scala/subsystem/BaseSubsystem.scala b/src/main/scala/subsystem/BaseSubsystem.scala index 8ff54586..2df929c7 100644 --- a/src/main/scala/subsystem/BaseSubsystem.scala +++ b/src/main/scala/subsystem/BaseSubsystem.scala @@ -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) {