diff --git a/src/main/scala/diplomacy/Parameters.scala b/src/main/scala/diplomacy/Parameters.scala index fd9d9f0b..ccad3fbb 100644 --- a/src/main/scala/diplomacy/Parameters.scala +++ b/src/main/scala/diplomacy/Parameters.scala @@ -76,6 +76,32 @@ 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) + require (size > 0) + + 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)) + } + } +} + // 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 @@ -132,6 +158,32 @@ case class AddressSet(base: BigInt, mask: BigInt) extends Ordered[AddressSet] "AddressSet(0x%x, ~0x%x)".format(base, ~mask) } } + + def toRanges = { + require (finite) + val size = alignment + val fragments = mask & ~(size-1) + val bits = bitIndexes(fragments) + (BigInt(0) until (BigInt(1) << bits.size)).map { i => + val off = bitIndexes(i).foldLeft(base) { case (a, b) => a.setBit(bits(b)) } + AddressRange(off, 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 + } } object AddressSet diff --git a/src/main/scala/diplomacy/package.scala b/src/main/scala/diplomacy/package.scala index 12fd0bfd..5b9d4944 100644 --- a/src/main/scala/diplomacy/package.scala +++ b/src/main/scala/diplomacy/package.scala @@ -9,4 +9,14 @@ package object diplomacy case SourceLine(filename, line, col) => s"$prefix$filename:$line:$col$suffix" case _ => "" } + + def bitIndexes(x: BigInt, tail: Seq[Int] = Nil): Seq[Int] = { + require (x >= 0) + if (x == 0) { + tail.reverse + } else { + val lowest = x.lowestSetBit + bitIndexes(x.clearBit(lowest), lowest +: tail) + } + } }