2016-11-28 01:16:37 +01:00
|
|
|
// See LICENSE.SiFive for license details.
|
2016-08-27 00:48:48 +02:00
|
|
|
|
|
|
|
package uncore.tilelink2
|
|
|
|
|
|
|
|
import Chisel._
|
2016-12-02 02:46:52 +01:00
|
|
|
import config._
|
2016-10-04 00:17:36 +02:00
|
|
|
import diplomacy._
|
|
|
|
import regmapper._
|
2016-09-23 00:36:13 +02:00
|
|
|
import scala.math.{min,max}
|
2016-08-27 00:48:48 +02:00
|
|
|
|
2016-10-28 03:38:14 +02:00
|
|
|
class TLRegisterNode(address: AddressSet, concurrency: Int = 0, beatBytes: Int = 4, undefZero: Boolean = true, executable: Boolean = false)
|
2017-01-30 00:17:52 +01:00
|
|
|
extends TLManagerNode(Seq(TLManagerPortParameters(
|
2016-09-28 21:56:03 +02:00
|
|
|
Seq(TLManagerParameters(
|
|
|
|
address = Seq(address),
|
2016-10-28 03:38:14 +02:00
|
|
|
executable = executable,
|
2016-09-28 21:56:03 +02:00
|
|
|
supportsGet = TransferSizes(1, beatBytes),
|
|
|
|
supportsPutPartial = TransferSizes(1, beatBytes),
|
|
|
|
supportsPutFull = TransferSizes(1, beatBytes),
|
|
|
|
fifoId = Some(0))), // requests are handled in order
|
|
|
|
beatBytes = beatBytes,
|
2017-01-30 00:17:52 +01:00
|
|
|
minLatency = min(concurrency, 1)))) // the Queue adds at most one cycle
|
2016-08-27 00:48:48 +02:00
|
|
|
{
|
2016-09-18 00:31:35 +02:00
|
|
|
require (address.contiguous)
|
2016-08-27 00:48:48 +02:00
|
|
|
|
|
|
|
// Calling this method causes the matching TL2 bundle to be
|
|
|
|
// configured to route all requests to the listed RegFields.
|
|
|
|
def regmap(mapping: RegField.Map*) = {
|
2016-08-30 00:33:10 +02:00
|
|
|
val a = bundleIn(0).a
|
2016-08-27 00:48:48 +02:00
|
|
|
val d = bundleIn(0).d
|
2016-08-30 00:33:10 +02:00
|
|
|
val edge = edgesIn(0)
|
2016-09-07 08:46:44 +02:00
|
|
|
|
|
|
|
// Please forgive me ...
|
|
|
|
val baseEnd = 0
|
|
|
|
val (sizeEnd, sizeOff) = (edge.bundle.sizeBits + baseEnd, baseEnd)
|
|
|
|
val (sourceEnd, sourceOff) = (edge.bundle.sourceBits + sizeEnd, sizeEnd)
|
2016-09-16 07:13:08 +02:00
|
|
|
val (addrLoEnd, addrLoOff) = (log2Up(beatBytes) + sourceEnd, sourceEnd)
|
2016-09-07 08:46:44 +02:00
|
|
|
|
2016-09-16 23:54:30 +02:00
|
|
|
val params = RegMapperParams(log2Up((address.mask+1)/beatBytes), beatBytes, addrLoEnd)
|
2016-08-31 22:37:20 +02:00
|
|
|
val in = Wire(Decoupled(new RegMapperInput(params)))
|
2016-08-30 00:33:10 +02:00
|
|
|
in.bits.read := a.bits.opcode === TLMessages.Get
|
2016-10-14 23:09:39 +02:00
|
|
|
in.bits.index := edge.addr_hi(a.bits)
|
2016-08-30 00:33:10 +02:00
|
|
|
in.bits.data := a.bits.data
|
2016-08-31 00:06:37 +02:00
|
|
|
in.bits.mask := a.bits.mask
|
2016-09-07 08:46:44 +02:00
|
|
|
in.bits.extra := Cat(edge.addr_lo(a.bits), a.bits.source, a.bits.size)
|
2016-08-30 00:33:10 +02:00
|
|
|
|
2016-10-13 03:10:07 +02:00
|
|
|
// Invoke the register map builder
|
|
|
|
val out = RegMapper(beatBytes, concurrency, undefZero, in, mapping:_*)
|
2016-08-27 00:48:48 +02:00
|
|
|
|
2016-08-30 00:33:10 +02:00
|
|
|
// No flow control needed
|
|
|
|
in.valid := a.valid
|
|
|
|
a.ready := in.ready
|
|
|
|
d.valid := out.valid
|
|
|
|
out.ready := d.ready
|
2016-08-27 00:48:48 +02:00
|
|
|
|
2016-09-07 08:46:44 +02:00
|
|
|
// We must restore the size and addr_lo to enable width adapters to work
|
|
|
|
d.bits := edge.AccessAck(
|
|
|
|
fromAddress = out.bits.extra(addrLoEnd-1, addrLoOff),
|
|
|
|
fromSink = UInt(0), // our unique sink id
|
|
|
|
toSource = out.bits.extra(sourceEnd-1, sourceOff),
|
|
|
|
lgSize = out.bits.extra(sizeEnd-1, sizeOff))
|
|
|
|
|
2016-08-27 00:48:48 +02:00
|
|
|
// avoid a Mux on the data bus by manually overriding two fields
|
2016-08-30 00:33:10 +02:00
|
|
|
d.bits.data := out.bits.data
|
|
|
|
d.bits.opcode := Mux(out.bits.read, TLMessages.AccessAckData, TLMessages.AccessAck)
|
2016-09-05 01:47:18 +02:00
|
|
|
|
|
|
|
// Tie off unused channels
|
|
|
|
bundleIn(0).b.valid := Bool(false)
|
|
|
|
bundleIn(0).c.ready := Bool(true)
|
|
|
|
bundleIn(0).e.ready := Bool(true)
|
2016-08-27 00:48:48 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
object TLRegisterNode
|
|
|
|
{
|
2016-10-28 03:38:14 +02:00
|
|
|
def apply(address: AddressSet, concurrency: Int = 0, beatBytes: Int = 4, undefZero: Boolean = true, executable: Boolean = false) =
|
|
|
|
new TLRegisterNode(address, concurrency, beatBytes, undefZero, executable)
|
2016-08-27 00:48:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
2016-12-02 02:46:52 +01:00
|
|
|
abstract class TLRegisterRouterBase(val address: AddressSet, interrupts: Int, concurrency: Int, beatBytes: Int, undefZero: Boolean, executable: Boolean)(implicit p: Parameters) extends LazyModule
|
2016-08-27 00:48:48 +02:00
|
|
|
{
|
2016-10-28 03:38:14 +02:00
|
|
|
val node = TLRegisterNode(address, concurrency, beatBytes, undefZero, executable)
|
2016-09-17 22:56:35 +02:00
|
|
|
val intnode = IntSourceNode(interrupts)
|
2016-08-27 00:48:48 +02:00
|
|
|
}
|
|
|
|
|
2017-02-23 02:05:22 +01:00
|
|
|
case class TLRegBundleArg(interrupts: util.HeterogeneousBag[Vec[Bool]], in: util.HeterogeneousBag[TLBundle])(implicit val p: Parameters)
|
2016-08-27 00:48:48 +02:00
|
|
|
|
2016-09-09 00:17:30 +02:00
|
|
|
class TLRegBundleBase(arg: TLRegBundleArg) extends Bundle
|
|
|
|
{
|
2016-12-02 02:46:52 +01:00
|
|
|
implicit val p = arg.p
|
2016-09-09 00:17:30 +02:00
|
|
|
val interrupts = arg.interrupts
|
|
|
|
val in = arg.in
|
|
|
|
}
|
|
|
|
|
2016-12-02 02:46:52 +01:00
|
|
|
class TLRegBundle[P](val params: P, arg: TLRegBundleArg)(implicit p: Parameters) extends TLRegBundleBase(arg)
|
2016-09-09 00:17:30 +02:00
|
|
|
|
|
|
|
class TLRegModule[P, B <: TLRegBundleBase](val params: P, bundleBuilder: => B, router: TLRegisterRouterBase)
|
2016-08-31 19:25:46 +02:00
|
|
|
extends LazyModuleImp(router) with HasRegMap
|
2016-08-27 00:48:48 +02:00
|
|
|
{
|
2016-08-29 20:08:37 +02:00
|
|
|
val io = bundleBuilder
|
2016-09-09 00:17:30 +02:00
|
|
|
val interrupts = if (io.interrupts.isEmpty) Vec(0, Bool()) else io.interrupts(0)
|
2016-10-29 06:20:49 +02:00
|
|
|
val address = router.address
|
2016-08-31 19:25:46 +02:00
|
|
|
def regmap(mapping: RegField.Map*) = router.node.regmap(mapping:_*)
|
2016-08-27 00:48:48 +02:00
|
|
|
}
|
|
|
|
|
2016-09-09 00:17:30 +02:00
|
|
|
class TLRegisterRouter[B <: TLRegBundleBase, M <: LazyModuleImp]
|
2016-10-28 03:38:14 +02:00
|
|
|
(val base: BigInt, val interrupts: Int = 0, val size: BigInt = 4096, val concurrency: Int = 0, val beatBytes: Int = 4, undefZero: Boolean = true, executable: Boolean = false)
|
2016-09-09 00:17:30 +02:00
|
|
|
(bundleBuilder: TLRegBundleArg => B)
|
2016-12-02 02:46:52 +01:00
|
|
|
(moduleBuilder: (=> B, TLRegisterRouterBase) => M)(implicit p: Parameters)
|
2016-10-28 03:38:14 +02:00
|
|
|
extends TLRegisterRouterBase(AddressSet(base, size-1), interrupts, concurrency, beatBytes, undefZero, executable)
|
2016-08-27 00:48:48 +02:00
|
|
|
{
|
|
|
|
require (isPow2(size))
|
2016-09-12 00:43:04 +02:00
|
|
|
// require (size >= 4096) ... not absolutely required, but highly recommended
|
2016-08-27 00:48:48 +02:00
|
|
|
|
2016-09-09 00:17:30 +02:00
|
|
|
lazy val module = moduleBuilder(bundleBuilder(TLRegBundleArg(intnode.bundleOut, node.bundleIn)), this)
|
2016-08-27 00:48:48 +02:00
|
|
|
}
|