1
0

RegMapper: regmap(...) now takes BYTE addresses

If a device has configurable bus-width, we need a stable way of
enumerating registers. The byte offset stays unchanged.

This change also makes it possible to put an arbitrary number of RegFields
starting at some address which are then chopped up into appropriately bus-
sized registers.
This commit is contained in:
Wesley W. Terpstra 2016-09-22 19:49:29 -07:00
parent 972ca06729
commit 5e34b313ee
5 changed files with 49 additions and 36 deletions

View File

@ -74,14 +74,11 @@ trait CoreplexLocalInterrupterModule extends Module with HasRegMap with MixCorep
* bff8 mtime lo * bff8 mtime lo
* bffc mtime hi * bffc mtime hi
*/ */
val ipi_base = 0
val timecmp_base = c.timecmpOffset(0) / c.beatBytes
val time_base = c.timeOffset / c.beatBytes
regmap(( regmap(
RegField.split(makeRegFields(ipi), ipi_base, c.beatBytes) ++ 0 -> makeRegFields(ipi),
RegField.split(makeRegFields(timecmp.flatten), timecmp_base, c.beatBytes) ++ c.timecmpOffset(0) -> makeRegFields(timecmp.flatten),
RegField.split(makeRegFields(time), time_base, c.beatBytes)):_*) c.timeOffset -> makeRegFields(time))
def makeRegFields(s: Seq[UInt]) = s.map(r => RegField(regWidth, r)) def makeRegFields(s: Seq[UInt]) = s.map(r => RegField(regWidth, r))
} }

View File

@ -27,7 +27,7 @@ trait ExampleModule extends HasRegMap
regmap( regmap(
0 -> Seq( 0 -> Seq(
RegField(params.num, state)), RegField(params.num, state)),
1 -> Seq( 4 -> Seq(
RegField.w1ToClear(4, pending, state))) RegField.w1ToClear(4, pending, state)))
} }

View File

@ -85,7 +85,9 @@ case class RegField(width: Int, read: RegReadFn, write: RegWriteFn)
object RegField object RegField
{ {
// Byte address => sequence of bitfields, lowest index => lowest address
type Map = (Int, Seq[RegField]) type Map = (Int, Seq[RegField])
def apply(n: Int) : RegField = apply(n, (), ()) def apply(n: Int) : RegField = apply(n, (), ())
def apply(n: Int, rw: UInt) : RegField = apply(n, rw, rw) def apply(n: Int, rw: UInt) : RegField = apply(n, rw, rw)
def r(n: Int, r: RegReadFn) : RegField = apply(n, r, ()) def r(n: Int, r: RegReadFn) : RegField = apply(n, r, ())

View File

@ -29,26 +29,35 @@ object RegMapper
{ {
// Create a generic register-based device // Create a generic register-based device
def apply(bytes: Int, concurrency: Int, undefZero: Boolean, in: DecoupledIO[RegMapperInput], mapping: RegField.Map*) = { def apply(bytes: Int, concurrency: Int, undefZero: Boolean, in: DecoupledIO[RegMapperInput], mapping: RegField.Map*) = {
val regmap = mapping.toList.filter(!_._2.isEmpty) val bytemap = mapping.toList
require (!regmap.isEmpty)
// Ensure no register appears twice
regmap.combinations(2).foreach { case Seq((reg1, _), (reg2, _)) =>
require (reg1 != reg2)
}
// Don't be an asshole... // Don't be an asshole...
regmap.foreach { reg => require (reg._1 >= 0) } bytemap.foreach { byte => require (byte._1 >= 0) }
// Transform all fields into bit offsets Seq[(bit, field)]
val bitmap = bytemap.map { case (byte, fields) =>
val bits = fields.scanLeft(byte * 8)(_ + _.width).init
bits zip fields
}.flatten.sortBy(_._1)
// Detect overlaps
(bitmap.init zip bitmap.tail) foreach { case ((lbit, lfield), (rbit, rfield)) =>
require (lbit + lfield.width <= rbit, s"Register map overlaps at bit ${rbit}.")
}
// Group those fields into bus words Map[word, List[(bit, field)]]
val wordmap = bitmap.groupBy(_._1 / (8*bytes))
// Make sure registers fit // Make sure registers fit
val inParams = in.bits.params val inParams = in.bits.params
val inBits = inParams.indexBits val inBits = inParams.indexBits
assert (regmap.map(_._1).max < (1 << inBits)) assert (wordmap.keySet.max < (1 << inBits), "Register map does not fit in device")
val out = Wire(Irrevocable(new RegMapperOutput(inParams))) val out = Wire(Irrevocable(new RegMapperOutput(inParams)))
val front = Wire(Irrevocable(new RegMapperInput(inParams))) val front = Wire(Irrevocable(new RegMapperInput(inParams)))
front.bits := in.bits front.bits := in.bits
// Must this device pipeline the control channel? // Must this device pipeline the control channel?
val pipelined = regmap.map(_._2.map(_.pipelined)).flatten.reduce(_ || _) val pipelined = wordmap.values.map(_.map(_._2.pipelined)).flatten.reduce(_ || _)
val depth = concurrency val depth = concurrency
require (depth >= 0) require (depth >= 0)
require (!pipelined || depth > 0, "Register-based device with request/response handshaking needs concurrency > 0") require (!pipelined || depth > 0, "Register-based device with request/response handshaking needs concurrency > 0")
@ -60,7 +69,7 @@ object RegMapper
def ofBits(bits: List[Boolean]) = bits.foldRight(0){ case (x,y) => (if (x) 1 else 0) | y << 1 } def ofBits(bits: List[Boolean]) = bits.foldRight(0){ case (x,y) => (if (x) 1 else 0) | y << 1 }
// Find the minimal mask that can decide the register map // Find the minimal mask that can decide the register map
val mask = AddressDecoder(regmap.map(_._1)) val mask = AddressDecoder(wordmap.keySet.toList)
val maskMatch = ~UInt(mask, width = inBits) val maskMatch = ~UInt(mask, width = inBits)
val maskFilter = toBits(mask) val maskFilter = toBits(mask)
val maskBits = maskFilter.filter(x => x).size val maskBits = maskFilter.filter(x => x).size
@ -75,17 +84,22 @@ object RegMapper
val iRightReg = Array.fill(regSize) { Bool(true) } val iRightReg = Array.fill(regSize) { Bool(true) }
val oRightReg = Array.fill(regSize) { Bool(true) } val oRightReg = Array.fill(regSize) { Bool(true) }
// Flatten the regmap into (RegIndex:Int, Offset:Int, field:RegField) // Transform the wordmap into minimal decoded indexes, Seq[(index, bit, field)]
val flat = regmap.map { case (reg, fields) => val flat = wordmap.toList.map { case (word, fields) =>
val offsets = fields.scanLeft(0)(_ + _.width).init val index = regIndexI(word)
val index = regIndexI(reg) val uint = UInt(word, width = inBits)
val uint = UInt(reg, width = inBits)
if (undefZero) { if (undefZero) {
iRightReg(index) = ((front.bits.index ^ uint) & maskMatch) === UInt(0) iRightReg(index) = ((front.bits.index ^ uint) & maskMatch) === UInt(0)
oRightReg(index) = ((back .bits.index ^ uint) & maskMatch) === UInt(0) oRightReg(index) = ((back .bits.index ^ uint) & maskMatch) === UInt(0)
} }
// println("mapping 0x%x -> 0x%x for 0x%x/%d".format(reg, index, mask, maskBits)) // Confirm that no field spans a word boundary
(offsets zip fields) map { case (o, f) => (index, o, f) } fields foreach { case (bit, field) =>
val off = bit - 8*bytes*word
// println(s"Reg ${word}: [${off}, ${off+field.width})")
require (off + field.width <= bytes * 8, s"Field at word ${word}*(${bytes}B) has bits [${off}, ${off+field.width}), which exceeds word limit.")
}
// println("mapping 0x%x -> 0x%x for 0x%x/%d".format(word, index, mask, maskBits))
fields.map { case (bit, field) => (index, bit-8*bytes*word, field) }
}.flatten }.flatten
// Forward declaration of all flow control signals // Forward declaration of all flow control signals

View File

@ -184,13 +184,13 @@ object RRTest0Map
// All fields must respect byte alignment, or else it won't behave like an SRAM // All fields must respect byte alignment, or else it won't behave like an SRAM
val map = Seq( val map = Seq(
0 -> Seq(aa(8), ar(8), ad(8), ae(8)), 0 -> Seq(aa(8), ar(8), ad(8), ae(8)),
1 -> Seq(ra(8), rr(8), rd(8), re(8)), 4 -> Seq(ra(8), rr(8), rd(8), re(8)),
2 -> Seq(da(8), dr(8), dd(8), de(8)), 8 -> Seq(da(8), dr(8), dd(8), de(8)),
3 -> Seq(ea(8), er(8), ed(8), ee(8)), 12 -> Seq(ea(8), er(8), ed(8), ee(8)),
4 -> Seq(aa(3), ar(5), ad(1), ae(7), ra(2), rr(6), rd(4), re(4)), 16 -> Seq(aa(3), ar(5), ad(1), ae(7), ra(2), rr(6), rd(4), re(4)),
5 -> Seq(da(3), dr(5), dd(1), de(7), ea(2), er(6), ed(4), ee(4)), 20 -> Seq(da(3), dr(5), dd(1), de(7), ea(2), er(6), ed(4), ee(4)),
6 -> Seq(aa(8), rr(8), dd(8), ee(8)), 24 -> Seq(aa(8), rr(8), dd(8), ee(8)),
7 -> Seq(ar(8), rd(8), de(8), ea(8))) 28 -> Seq(ar(8), rd(8), de(8), ea(8)))
} }
object RRTest1Map object RRTest1Map
@ -203,8 +203,8 @@ object RRTest1Map
def bb(bits: Int) = request(bits, busy, busy) def bb(bits: Int) = request(bits, busy, busy)
val map = RRTest0Map.map.take(6) ++ Seq( val map = RRTest0Map.map.take(6) ++ Seq(
6 -> Seq(pp(8), pb(8), bp(8), bb(8)), 24 -> Seq(pp(8), pb(8), bp(8), bb(8)),
7 -> Seq(pp(3), pb(5), bp(1), bb(7), pb(5), bp(3), pp(4), bb(4))) 28 -> Seq(pp(3), pb(5), bp(1), bb(7), pb(5), bp(3), pp(4), bb(4)))
} }
trait RRTest0Bundle trait RRTest0Bundle