RegisterRouter: compress register mapping for sparse devices
This commit is contained in:
parent
6b1c57aedc
commit
30fa4ea956
@ -28,8 +28,8 @@ class RegMapperOutput(params: RegMapperParams) extends GenericParameterizedBundl
|
|||||||
object RegMapper
|
object RegMapper
|
||||||
{
|
{
|
||||||
// Create a generic register-based device
|
// Create a generic register-based device
|
||||||
def apply(bytes: Int, concurrency: Option[Int], in: DecoupledIO[RegMapperInput], mapping: RegField.Map*) = {
|
def apply(bytes: Int, concurrency: Option[Int], undefZero: Boolean, in: DecoupledIO[RegMapperInput], mapping: RegField.Map*) = {
|
||||||
val regmap = mapping.toList
|
val regmap = mapping.toList.filter(!_._2.isEmpty)
|
||||||
require (!regmap.isEmpty)
|
require (!regmap.isEmpty)
|
||||||
|
|
||||||
// Ensure no register appears twice
|
// Ensure no register appears twice
|
||||||
@ -37,15 +37,31 @@ object RegMapper
|
|||||||
require (reg1 != reg2)
|
require (reg1 != reg2)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flatten the regmap into (Reg:Int, Offset:Int, field:RegField)
|
// Convert to and from Bits
|
||||||
val flat = regmap.map { case (reg, fields) =>
|
def toBits(x: Int, tail: List[Boolean] = List.empty): List[Boolean] =
|
||||||
val offsets = fields.scanLeft(0)(_ + _.width).init
|
if (x == 0) tail.reverse else toBits(x >> 1, ((x & 1) == 1) :: tail)
|
||||||
(offsets zip fields) map { case (o, f) => (reg, o, f) }
|
def ofBits(bits: List[Boolean]) = bits.foldRight(0){ case (x,y) => (if (x) 1 else 0) | y << 1 }
|
||||||
}.flatten
|
|
||||||
require (!flat.isEmpty)
|
|
||||||
|
|
||||||
|
// Find the minimal mask that can decide the register map
|
||||||
|
val mask = AddressDecoder(regmap.map(_._1))
|
||||||
|
val maskFilter = toBits(mask)
|
||||||
|
val maskBits = maskFilter.filter(x => x).size
|
||||||
|
|
||||||
|
// Calculate size and indexes into the register map
|
||||||
val endIndex = 1 << log2Ceil(regmap.map(_._1).max+1)
|
val endIndex = 1 << log2Ceil(regmap.map(_._1).max+1)
|
||||||
val params = RegMapperParams(log2Up(endIndex), bytes, in.bits.params.extraBits)
|
val params = RegMapperParams(log2Up(endIndex), bytes, in.bits.params.extraBits)
|
||||||
|
val regSize = 1 << maskBits
|
||||||
|
def regIndexI(x: Int) = ofBits((maskFilter zip toBits(x)).filter(_._1).map(_._2))
|
||||||
|
def regIndexU(x: UInt) = if (maskBits == 0) UInt(0) else
|
||||||
|
Cat((maskFilter zip x.toBools).filter(_._1).map(_._2).reverse)
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
// 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) }
|
||||||
|
}.flatten
|
||||||
|
|
||||||
val out = Wire(Irrevocable(new RegMapperOutput(params)))
|
val out = Wire(Irrevocable(new RegMapperOutput(params)))
|
||||||
val front = Wire(Irrevocable(new RegMapperInput(params)))
|
val front = Wire(Irrevocable(new RegMapperInput(params)))
|
||||||
@ -69,13 +85,13 @@ object RegMapper
|
|||||||
val woready = Wire(Vec(flat.size, Bool()))
|
val woready = Wire(Vec(flat.size, Bool()))
|
||||||
|
|
||||||
// Per-register list of all control signals needed for data to flow
|
// Per-register list of all control signals needed for data to flow
|
||||||
val rifire = Array.tabulate(endIndex) { i => Seq(Bool(true)) }
|
val rifire = Array.tabulate(regSize) { i => Seq(Bool(true)) }
|
||||||
val wifire = Array.tabulate(endIndex) { i => Seq(Bool(true)) }
|
val wifire = Array.tabulate(regSize) { i => Seq(Bool(true)) }
|
||||||
val rofire = Array.tabulate(endIndex) { i => Seq(Bool(true)) }
|
val rofire = Array.tabulate(regSize) { i => Seq(Bool(true)) }
|
||||||
val wofire = Array.tabulate(endIndex) { i => Seq(Bool(true)) }
|
val wofire = Array.tabulate(regSize) { i => Seq(Bool(true)) }
|
||||||
|
|
||||||
// The output values for each register
|
// The output values for each register
|
||||||
val dataOut = Array.tabulate(endIndex) { _ => UInt(0) }
|
val dataOut = Array.tabulate(regSize) { _ => UInt(0) }
|
||||||
|
|
||||||
// Which bits are touched?
|
// Which bits are touched?
|
||||||
val frontMask = FillInterleaved(8, front.bits.mask)
|
val frontMask = FillInterleaved(8, front.bits.mask)
|
||||||
@ -110,8 +126,10 @@ object RegMapper
|
|||||||
val wifireMux = Vec(wifire.map(_.reduce(_ && _)))
|
val wifireMux = Vec(wifire.map(_.reduce(_ && _)))
|
||||||
val rofireMux = Vec(rofire.map(_.reduce(_ && _)))
|
val rofireMux = Vec(rofire.map(_.reduce(_ && _)))
|
||||||
val wofireMux = Vec(wofire.map(_.reduce(_ && _)))
|
val wofireMux = Vec(wofire.map(_.reduce(_ && _)))
|
||||||
val iready = Mux(front.bits.read, rifireMux(front.bits.index), wifireMux(front.bits.index))
|
val iindex = regIndexU(front.bits.index)
|
||||||
val oready = Mux(back .bits.read, rofireMux(back .bits.index), wofireMux(back .bits.index))
|
val oindex = regIndexU(back .bits.index)
|
||||||
|
val iready = Mux(front.bits.read, rifireMux(iindex), wifireMux(iindex))
|
||||||
|
val oready = Mux(back .bits.read, rofireMux(oindex), wofireMux(oindex))
|
||||||
|
|
||||||
// Connect the pipeline
|
// Connect the pipeline
|
||||||
in.ready := front.ready && iready
|
in.ready := front.ready && iready
|
||||||
@ -120,11 +138,11 @@ object RegMapper
|
|||||||
out.valid := back.valid && oready
|
out.valid := back.valid && oready
|
||||||
|
|
||||||
// Which register is touched?
|
// Which register is touched?
|
||||||
val frontSel = UIntToOH(front.bits.index)
|
val frontSel = UIntToOH(iindex)
|
||||||
val backSel = UIntToOH(back.bits.index)
|
val backSel = UIntToOH(oindex)
|
||||||
|
|
||||||
// Include the per-register one-hot selected criteria
|
// Include the per-register one-hot selected criteria
|
||||||
for (reg <- 0 until endIndex) {
|
for (reg <- 0 until regSize) {
|
||||||
rifire(reg) = (in.valid && front.ready && front.bits.read && frontSel(reg)) +: rifire(reg)
|
rifire(reg) = (in.valid && front.ready && front.bits.read && frontSel(reg)) +: rifire(reg)
|
||||||
wifire(reg) = (in.valid && front.ready && !front.bits.read && frontSel(reg)) +: wifire(reg)
|
wifire(reg) = (in.valid && front.ready && !front.bits.read && frontSel(reg)) +: wifire(reg)
|
||||||
rofire(reg) = (back.valid && out.ready && back .bits.read && backSel (reg)) +: rofire(reg)
|
rofire(reg) = (back.valid && out.ready && back .bits.read && backSel (reg)) +: rofire(reg)
|
||||||
@ -141,7 +159,7 @@ object RegMapper
|
|||||||
}
|
}
|
||||||
|
|
||||||
out.bits.read := back.bits.read
|
out.bits.read := back.bits.read
|
||||||
out.bits.data := Vec(dataOut)(back.bits.index)
|
out.bits.data := Vec(dataOut)(oindex)
|
||||||
out.bits.extra := back.bits.extra
|
out.bits.extra := back.bits.extra
|
||||||
|
|
||||||
(endIndex, out)
|
(endIndex, out)
|
||||||
|
@ -4,7 +4,7 @@ package uncore.tilelink2
|
|||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
|
|
||||||
class TLRegisterNode(address: AddressSet, concurrency: Option[Int] = None, beatBytes: Int = 4)
|
class TLRegisterNode(address: AddressSet, concurrency: Option[Int] = None, beatBytes: Int = 4, undefZero: Boolean = true)
|
||||||
extends TLManagerNode(beatBytes, TLManagerParameters(
|
extends TLManagerNode(beatBytes, TLManagerParameters(
|
||||||
address = Seq(address),
|
address = Seq(address),
|
||||||
supportsGet = TransferSizes(1, beatBytes),
|
supportsGet = TransferSizes(1, beatBytes),
|
||||||
@ -36,7 +36,7 @@ class TLRegisterNode(address: AddressSet, concurrency: Option[Int] = None, beatB
|
|||||||
in.bits.extra := Cat(edge.addr_lo(a.bits), a.bits.source, a.bits.size)
|
in.bits.extra := Cat(edge.addr_lo(a.bits), a.bits.source, a.bits.size)
|
||||||
|
|
||||||
// Invoke the register map builder
|
// Invoke the register map builder
|
||||||
val (endIndex, out) = RegMapper(beatBytes, concurrency, in, mapping:_*)
|
val (endIndex, out) = RegMapper(beatBytes, concurrency, undefZero, in, mapping:_*)
|
||||||
|
|
||||||
// All registers must fit inside the device address space
|
// All registers must fit inside the device address space
|
||||||
require (address.mask >= (endIndex-1)*beatBytes)
|
require (address.mask >= (endIndex-1)*beatBytes)
|
||||||
@ -67,17 +67,17 @@ class TLRegisterNode(address: AddressSet, concurrency: Option[Int] = None, beatB
|
|||||||
|
|
||||||
object TLRegisterNode
|
object TLRegisterNode
|
||||||
{
|
{
|
||||||
def apply(address: AddressSet, concurrency: Option[Int] = None, beatBytes: Int = 4) =
|
def apply(address: AddressSet, concurrency: Option[Int] = None, beatBytes: Int = 4, undefZero: Boolean = true) =
|
||||||
new TLRegisterNode(address, concurrency, beatBytes)
|
new TLRegisterNode(address, concurrency, beatBytes, undefZero)
|
||||||
}
|
}
|
||||||
|
|
||||||
// These convenience methods below combine to make it possible to create a TL2
|
// These convenience methods below combine to make it possible to create a TL2
|
||||||
// register mapped device from a totally abstract register mapped device.
|
// register mapped device from a totally abstract register mapped device.
|
||||||
// See GPIO.scala in this directory for an example
|
// See GPIO.scala in this directory for an example
|
||||||
|
|
||||||
abstract class TLRegisterRouterBase(address: AddressSet, interrupts: Int, concurrency: Option[Int], beatBytes: Int) extends LazyModule
|
abstract class TLRegisterRouterBase(address: AddressSet, interrupts: Int, concurrency: Option[Int], beatBytes: Int, undefZero: Boolean) extends LazyModule
|
||||||
{
|
{
|
||||||
val node = TLRegisterNode(address, concurrency, beatBytes)
|
val node = TLRegisterNode(address, concurrency, beatBytes, undefZero)
|
||||||
val intnode = IntSourceNode(name + s" @ ${address.base}", interrupts)
|
val intnode = IntSourceNode(name + s" @ ${address.base}", interrupts)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,10 +100,10 @@ class TLRegModule[P, B <: TLRegBundleBase](val params: P, bundleBuilder: => B, r
|
|||||||
}
|
}
|
||||||
|
|
||||||
class TLRegisterRouter[B <: TLRegBundleBase, M <: LazyModuleImp]
|
class TLRegisterRouter[B <: TLRegBundleBase, M <: LazyModuleImp]
|
||||||
(val base: BigInt, val interrupts: Int = 0, val size: BigInt = 4096, val concurrency: Option[Int] = None, val beatBytes: Int = 4)
|
(val base: BigInt, val interrupts: Int = 0, val size: BigInt = 4096, val concurrency: Option[Int] = None, val beatBytes: Int = 4, undefZero: Boolean = true)
|
||||||
(bundleBuilder: TLRegBundleArg => B)
|
(bundleBuilder: TLRegBundleArg => B)
|
||||||
(moduleBuilder: (=> B, TLRegisterRouterBase) => M)
|
(moduleBuilder: (=> B, TLRegisterRouterBase) => M)
|
||||||
extends TLRegisterRouterBase(AddressSet(base, size-1), interrupts, concurrency, beatBytes)
|
extends TLRegisterRouterBase(AddressSet(base, size-1), interrupts, concurrency, beatBytes, undefZero)
|
||||||
{
|
{
|
||||||
require (isPow2(size))
|
require (isPow2(size))
|
||||||
// require (size >= 4096) ... not absolutely required, but highly recommended
|
// require (size >= 4096) ... not absolutely required, but highly recommended
|
||||||
|
Loading…
Reference in New Issue
Block a user