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
* bffc mtime hi
*/
val ipi_base = 0
val timecmp_base = c.timecmpOffset(0) / c.beatBytes
val time_base = c.timeOffset / c.beatBytes
regmap((
RegField.split(makeRegFields(ipi), ipi_base, c.beatBytes) ++
RegField.split(makeRegFields(timecmp.flatten), timecmp_base, c.beatBytes) ++
RegField.split(makeRegFields(time), time_base, c.beatBytes)):_*)
regmap(
0 -> makeRegFields(ipi),
c.timecmpOffset(0) -> makeRegFields(timecmp.flatten),
c.timeOffset -> makeRegFields(time))
def makeRegFields(s: Seq[UInt]) = s.map(r => RegField(regWidth, r))
}

View File

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

View File

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

View File

@ -29,26 +29,35 @@ object RegMapper
{
// Create a generic register-based device
def apply(bytes: Int, concurrency: Int, undefZero: Boolean, in: DecoupledIO[RegMapperInput], mapping: RegField.Map*) = {
val regmap = mapping.toList.filter(!_._2.isEmpty)
require (!regmap.isEmpty)
// Ensure no register appears twice
regmap.combinations(2).foreach { case Seq((reg1, _), (reg2, _)) =>
require (reg1 != reg2)
}
val bytemap = mapping.toList
// 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
val inParams = in.bits.params
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 front = Wire(Irrevocable(new RegMapperInput(inParams)))
front.bits := in.bits
// 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
require (depth >= 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 }
// 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 maskFilter = toBits(mask)
val maskBits = maskFilter.filter(x => x).size
@ -75,17 +84,22 @@ object RegMapper
val iRightReg = Array.fill(regSize) { Bool(true) }
val oRightReg = Array.fill(regSize) { Bool(true) }
// Flatten the regmap into (RegIndex:Int, Offset:Int, field:RegField)
val flat = regmap.map { case (reg, fields) =>
val offsets = fields.scanLeft(0)(_ + _.width).init
val index = regIndexI(reg)
val uint = UInt(reg, width = inBits)
// Transform the wordmap into minimal decoded indexes, Seq[(index, bit, field)]
val flat = wordmap.toList.map { case (word, fields) =>
val index = regIndexI(word)
val uint = UInt(word, width = inBits)
if (undefZero) {
iRightReg(index) = ((front.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))
(offsets zip fields) map { case (o, f) => (index, o, f) }
// Confirm that no field spans a word boundary
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
// Forward declaration of all flow control signals

View File

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