tilelink2: connect abstract register-based modules to TileLink
This commit is contained in:
parent
917a9c8e5d
commit
18e149098a
29
uncore/src/main/scala/tilelink2/GPIO.scala
Normal file
29
uncore/src/main/scala/tilelink2/GPIO.scala
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// See LICENSE for license details.
|
||||||
|
|
||||||
|
package uncore.tilelink2
|
||||||
|
|
||||||
|
import Chisel._
|
||||||
|
|
||||||
|
case class GPIOParams(num: Int, address: Option[BigInt] = None)
|
||||||
|
|
||||||
|
trait GPIOBundle
|
||||||
|
{
|
||||||
|
val params: GPIOParams
|
||||||
|
val gpio = UInt(width = params.num)
|
||||||
|
}
|
||||||
|
|
||||||
|
trait GPIOModule extends HasRegMap
|
||||||
|
{
|
||||||
|
val params: GPIOParams
|
||||||
|
val io: GPIOBundle
|
||||||
|
|
||||||
|
val state = RegInit(UInt(0))
|
||||||
|
io.gpio := state
|
||||||
|
|
||||||
|
regmap(0 -> Seq(RegField(params.num, state)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a concrete TL2 version of the abstract GPIO slave
|
||||||
|
class TLGPIO(p: GPIOParams) extends TLRegisterRouter(p.address)(
|
||||||
|
new TLRegBundle(p, _) with GPIOBundle)(
|
||||||
|
new TLRegModule(p, _, _) with GPIOModule)
|
@ -5,6 +5,10 @@ package uncore.tilelink2
|
|||||||
import Chisel._
|
import Chisel._
|
||||||
|
|
||||||
case class RegField(width: Int, read: RegField.ReadFn, write: RegField.WriteFn)
|
case class RegField(width: Int, read: RegField.ReadFn, write: RegField.WriteFn)
|
||||||
|
{
|
||||||
|
require (width > 0)
|
||||||
|
}
|
||||||
|
|
||||||
object RegField
|
object RegField
|
||||||
{
|
{
|
||||||
type ReadFn = Bool => (Bool, UInt)
|
type ReadFn = Bool => (Bool, UInt)
|
||||||
|
122
uncore/src/main/scala/tilelink2/RegisterRouter.scala
Normal file
122
uncore/src/main/scala/tilelink2/RegisterRouter.scala
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
// See LICENSE for license details.
|
||||||
|
|
||||||
|
package uncore.tilelink2
|
||||||
|
|
||||||
|
import Chisel._
|
||||||
|
|
||||||
|
class TLRegisterNode(address: AddressSet, beatBytes: Int = 4)
|
||||||
|
extends TLManagerNode(beatBytes, TLManagerParameters(
|
||||||
|
address = Seq(address),
|
||||||
|
supportsGet = TransferSizes(1, beatBytes),
|
||||||
|
supportsPutPartial = TransferSizes(1, beatBytes),
|
||||||
|
supportsPutFull = TransferSizes(1, beatBytes),
|
||||||
|
fifoId = Some(0))) // requests are handled in order
|
||||||
|
{
|
||||||
|
require (!address.strided)
|
||||||
|
|
||||||
|
// Calling this method causes the matching TL2 bundle to be
|
||||||
|
// configured to route all requests to the listed RegFields.
|
||||||
|
def regmap(mapping: RegField.Map*) = {
|
||||||
|
val regmap = mapping.toList
|
||||||
|
require (!regmap.isEmpty)
|
||||||
|
|
||||||
|
// Flatten the regmap into (Reg:Int, Offset:Int, field:RegField)
|
||||||
|
val flat = regmap.map { case (reg, fields) =>
|
||||||
|
val offsets = fields.scanLeft(0)(_ + _.width).init
|
||||||
|
(offsets zip fields) map { case (o, f) => (reg, o, f) }
|
||||||
|
}.flatten
|
||||||
|
|
||||||
|
// Confirm that no register is too big
|
||||||
|
require (flat.map(_._2).max <= beatBytes*8)
|
||||||
|
|
||||||
|
// All registers must fit inside the device address space
|
||||||
|
val maxIndex = regmap.map(_._1).max
|
||||||
|
require (address.mask >= maxIndex*beatBytes)
|
||||||
|
|
||||||
|
// Which register is touched?
|
||||||
|
val alignBits = log2Ceil(beatBytes)
|
||||||
|
val addressBits = log2Up(maxIndex+1)
|
||||||
|
val a = bundleIn(0).a // Must apply Queue !!! (so no change once started)
|
||||||
|
val d = bundleIn(0).d
|
||||||
|
val regIdx = a.bits.address(addressBits+alignBits-1, alignBits)
|
||||||
|
val regSel = UIntToOH(regIdx)
|
||||||
|
|
||||||
|
// What is the access?
|
||||||
|
val opcode = a.bits.opcode
|
||||||
|
val read = a.valid && opcode === TLMessages.Get
|
||||||
|
val write = a.valid && (opcode === TLMessages.PutFullData || opcode === TLMessages.PutPartialData)
|
||||||
|
val wmaskWide = Vec.tabulate(beatBytes*8) { i => a.bits.wmask(i/8) } .toBits.asUInt
|
||||||
|
val dataIn = a.bits.data & wmaskWide // zero undefined bits
|
||||||
|
|
||||||
|
// The output values for each register
|
||||||
|
val dataOutAcc = Array.tabulate(maxIndex+1) { _ => UInt(0) }
|
||||||
|
// The ready state for read and write
|
||||||
|
val rReadyAcc = Array.tabulate(maxIndex+1) { _ => Bool(true) }
|
||||||
|
val wReadyAcc = Array.tabulate(maxIndex+1) { _ => Bool(true) }
|
||||||
|
|
||||||
|
// Apply all the field methods
|
||||||
|
flat.foreach { case (reg, low, field) =>
|
||||||
|
val high = low + field.width - 1
|
||||||
|
val rfire = wmaskWide(high, low).orR()
|
||||||
|
val wfire = wmaskWide(high, low).andR()
|
||||||
|
val sel = regSel(reg)
|
||||||
|
val ren = read && sel && rfire
|
||||||
|
val wen = write && sel && wfire
|
||||||
|
val (rReady, rResult) = field.read(ren)
|
||||||
|
val wReady = field.write(wen, dataIn(high, low))
|
||||||
|
dataOutAcc(reg) = dataOutAcc(reg) | (rResult << low)
|
||||||
|
rReadyAcc(reg) = rReadyAcc(reg) && (!rfire || rReady)
|
||||||
|
wReadyAcc(reg) = wReadyAcc(reg) && (!wfire || wReady)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the output data signal
|
||||||
|
val dataOut = Vec(dataOutAcc)(regIdx)
|
||||||
|
val rReady = Vec(rReadyAcc)(regIdx)
|
||||||
|
val wReady = Vec(wReadyAcc)(regIdx)
|
||||||
|
|
||||||
|
val ready = (read && rReady) || (write && wReady)
|
||||||
|
a.ready := ready && d.ready
|
||||||
|
d.valid := a.valid && ready
|
||||||
|
|
||||||
|
val edge = edgesIn(0)
|
||||||
|
d.bits := edge.AccessAck(a.bits.source, a.bits.size)
|
||||||
|
// avoid a Mux on the data bus by manually overriding two fields
|
||||||
|
d.bits.data := dataOut
|
||||||
|
d.bits.opcode := Mux(opcode === TLMessages.Get, TLMessages.AccessAck, TLMessages.AccessAckData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object TLRegisterNode
|
||||||
|
{
|
||||||
|
def apply(address: AddressSet, beatBytes: Int = 4) = new TLRegisterNode(address, beatBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// These convenience methods below combine to make it possible to create a TL2
|
||||||
|
// register mapped device from a totally abstract register mapped device.
|
||||||
|
// See GPIO.scala in this directory for an example
|
||||||
|
|
||||||
|
abstract class TLRegFactory(address: AddressSet, beatBytes: Int) extends TLFactory
|
||||||
|
{
|
||||||
|
val node = TLRegisterNode(address, beatBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
class TLRegBundle[P](val params: P, val tl_in: Vec[TLBundle]) extends Bundle
|
||||||
|
|
||||||
|
class TLRegModule[P, B <: Bundle](val params: P, val io: B, factory: TLRegFactory)
|
||||||
|
extends TLModule(factory) with HasRegMap
|
||||||
|
{
|
||||||
|
def regmap(mapping: RegField.Map*) = factory.node.regmap(mapping:_*)
|
||||||
|
}
|
||||||
|
|
||||||
|
class TLRegisterRouter[B <: Bundle, M <: TLModule]
|
||||||
|
(address: Option[BigInt] = None, size: BigInt = 4096, beatBytes: Int = 4)
|
||||||
|
(bundleBuilder: Vec[TLBundle] => B)
|
||||||
|
(moduleBuilder: (B, TLRegFactory) => M)
|
||||||
|
extends TLRegFactory(AddressSet(size-1, address), beatBytes)
|
||||||
|
{
|
||||||
|
require (size % 4096 == 0) // devices should be 4K aligned
|
||||||
|
require (isPow2(size))
|
||||||
|
require (size >= 4096)
|
||||||
|
|
||||||
|
lazy val module = Module(moduleBuilder(bundleBuilder(node.bundleIn), this))
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user