1
0

Gracefully handle empty ports in AddressDecoder

This commit is contained in:
Andrew Waterman 2017-03-11 19:28:59 -08:00
parent c847559853
commit 90b5cc96cb

View File

@ -19,25 +19,27 @@ object AddressDecoder
// Find the minimum subset of bits needed to disambiguate port addresses. // Find the minimum subset of bits needed to disambiguate port addresses.
// ie: inspecting only the bits in the output, you can look at an address // ie: inspecting only the bits in the output, you can look at an address
// and decide to which port (outer Seq) the address belongs. // and decide to which port (outer Seq) the address belongs.
def apply(ports: Ports, givenBits: BigInt = BigInt(0)): BigInt = if (ports.size <= 1) givenBits else { def apply(ports: Ports, givenBits: BigInt = BigInt(0)): BigInt = {
// Every port must have at least one address! val nonEmptyPorts = ports.filter(_.nonEmpty)
ports.foreach { p => require (!p.isEmpty) } if (nonEmptyPorts.size <= 1) {
givenBits
} else {
// Verify the user did not give us an impossible problem // Verify the user did not give us an impossible problem
ports.combinations(2).foreach { case Seq(x, y) => nonEmptyPorts.combinations(2).foreach { case Seq(x, y) =>
x.foreach { a => y.foreach { b => x.foreach { a => y.foreach { b =>
require (!a.overlaps(b)) // it must be possible to disambiguate ports! require (!a.overlaps(b)) // it must be possible to disambiguate ports!
} } } }
} }
val maxBits = log2Ceil(ports.map(_.map(_.base).max).max) val maxBits = log2Ceil(nonEmptyPorts.map(_.map(_.base).max).max)
val (bitsToTry, bitsToTake) = (0 to maxBits).map(BigInt(1) << _).partition(b => (givenBits & b) == 0) val (bitsToTry, bitsToTake) = (0 to maxBits).map(BigInt(1) << _).partition(b => (givenBits & b) == 0)
val partitions = Seq(ports.map(_.sorted).sorted(portOrder)) val partitions = Seq(nonEmptyPorts.map(_.sorted).sorted(portOrder))
val givenPartitions = bitsToTake.foldLeft(partitions) { (p, b) => partitionPartitions(p, b) } val givenPartitions = bitsToTake.foldLeft(partitions) { (p, b) => partitionPartitions(p, b) }
val selected = recurse(givenPartitions, bitsToTry.toSeq) val selected = recurse(givenPartitions, bitsToTry.toSeq)
val output = selected.reduceLeft(_ | _) | givenBits val output = selected.reduceLeft(_ | _) | givenBits
// Modify the AddressSets to allow the new wider match functions // Modify the AddressSets to allow the new wider match functions
val widePorts = ports.map { _.map { _.widen(~output) } } val widePorts = nonEmptyPorts.map { _.map { _.widen(~output) } }
// Verify that it remains possible to disambiguate all ports // Verify that it remains possible to disambiguate all ports
widePorts.combinations(2).foreach { case Seq(x, y) => widePorts.combinations(2).foreach { case Seq(x, y) =>
x.foreach { a => y.foreach { b => x.foreach { a => y.foreach { b =>
@ -47,6 +49,7 @@ object AddressDecoder
output output
} }
}
// A simpler version that works for a Seq[Int] // A simpler version that works for a Seq[Int]
def apply(keys: Seq[Int]): Int = { def apply(keys: Seq[Int]): Int = {