commit
625919722c
@ -43,10 +43,6 @@ case class AHBSlavePortParameters(
|
|||||||
// Check that the link can be implemented in AHB
|
// Check that the link can be implemented in AHB
|
||||||
require (maxTransfer <= beatBytes * AHBParameters.maxTransfer)
|
require (maxTransfer <= beatBytes * AHBParameters.maxTransfer)
|
||||||
|
|
||||||
lazy val routingMask = AddressDecoder(slaves.map(_.address))
|
|
||||||
def findSafe(address: UInt) = Vec(slaves.map(_.address.map(_.contains(address)).reduce(_ || _)))
|
|
||||||
def findFast(address: UInt) = Vec(slaves.map(_.address.map(_.widen(~routingMask)).distinct.map(_.contains(address)).reduce(_ || _)))
|
|
||||||
|
|
||||||
// Require disjoint ranges for addresses
|
// Require disjoint ranges for addresses
|
||||||
slaves.combinations(2).foreach { case Seq(x,y) =>
|
slaves.combinations(2).foreach { case Seq(x,y) =>
|
||||||
x.address.foreach { a => y.address.foreach { b =>
|
x.address.foreach { a => y.address.foreach { b =>
|
||||||
|
@ -16,10 +16,10 @@ class RRTest1(address: BigInt)(implicit p: Parameters) extends AHBRegisterRouter
|
|||||||
new AHBRegBundle((), _) with RRTest1Bundle)(
|
new AHBRegBundle((), _) with RRTest1Bundle)(
|
||||||
new AHBRegModule((), _, _) with RRTest1Module)
|
new AHBRegModule((), _, _) with RRTest1Module)
|
||||||
|
|
||||||
class AHBFuzzBridge()(implicit p: Parameters) extends LazyModule
|
class AHBFuzzNative()(implicit p: Parameters) extends LazyModule
|
||||||
{
|
{
|
||||||
val fuzz = LazyModule(new TLFuzzer(5000))
|
val fuzz = LazyModule(new TLFuzzer(5000))
|
||||||
val model = LazyModule(new TLRAMModel("AHBFuzzMaster"))
|
val model = LazyModule(new TLRAMModel("AHBFuzzNative"))
|
||||||
var xbar = LazyModule(new AHBFanout)
|
var xbar = LazyModule(new AHBFanout)
|
||||||
val ram = LazyModule(new AHBRAM(AddressSet(0x0, 0xff)))
|
val ram = LazyModule(new AHBRAM(AddressSet(0x0, 0xff)))
|
||||||
val gpio = LazyModule(new RRTest0(0x100))
|
val gpio = LazyModule(new RRTest0(0x100))
|
||||||
@ -34,6 +34,67 @@ class AHBFuzzBridge()(implicit p: Parameters) extends LazyModule
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AHBNativeTest()(implicit p: Parameters) extends UnitTest(500000) {
|
||||||
|
val dut = Module(LazyModule(new AHBFuzzNative).module)
|
||||||
|
io.finished := dut.io.finished
|
||||||
|
}
|
||||||
|
|
||||||
|
class AHBFuzzMaster()(implicit p: Parameters) extends LazyModule
|
||||||
|
{
|
||||||
|
val node = AHBOutputNode()
|
||||||
|
val fuzz = LazyModule(new TLFuzzer(5000))
|
||||||
|
val model = LazyModule(new TLRAMModel("AHBFuzzMaster"))
|
||||||
|
|
||||||
|
model.node := fuzz.node
|
||||||
|
node :=
|
||||||
|
TLToAHB()(
|
||||||
|
TLDelayer(0.2)(
|
||||||
|
TLBuffer(TLBufferParams.flow)(
|
||||||
|
TLDelayer(0.2)(
|
||||||
|
model.node))))
|
||||||
|
|
||||||
|
lazy val module = new LazyModuleImp(this) {
|
||||||
|
val io = new Bundle {
|
||||||
|
val out = node.bundleOut
|
||||||
|
val finished = Bool(OUTPUT)
|
||||||
|
}
|
||||||
|
|
||||||
|
io.finished := fuzz.module.io.finished
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AHBFuzzSlave()(implicit p: Parameters) extends LazyModule
|
||||||
|
{
|
||||||
|
val node = AHBInputNode()
|
||||||
|
val ram = LazyModule(new TLTestRAM(AddressSet(0x0, 0xfff)))
|
||||||
|
|
||||||
|
ram.node :=
|
||||||
|
TLFragmenter(4, 16)(
|
||||||
|
TLDelayer(0.2)(
|
||||||
|
TLBuffer(TLBufferParams.flow)(
|
||||||
|
TLDelayer(0.2)(
|
||||||
|
AHBToTL()(
|
||||||
|
node)))))
|
||||||
|
|
||||||
|
lazy val module = new LazyModuleImp(this) {
|
||||||
|
val io = new Bundle {
|
||||||
|
val in = node.bundleIn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AHBFuzzBridge()(implicit p: Parameters) extends LazyModule
|
||||||
|
{
|
||||||
|
val master = LazyModule(new AHBFuzzMaster)
|
||||||
|
val slave = LazyModule(new AHBFuzzSlave)
|
||||||
|
|
||||||
|
slave.node := master.node
|
||||||
|
|
||||||
|
lazy val module = new LazyModuleImp(this) with HasUnitTestIO {
|
||||||
|
io.finished := master.module.io.finished
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class AHBBridgeTest()(implicit p: Parameters) extends UnitTest(500000) {
|
class AHBBridgeTest()(implicit p: Parameters) extends UnitTest(500000) {
|
||||||
val dut = Module(LazyModule(new AHBFuzzBridge).module)
|
val dut = Module(LazyModule(new AHBFuzzBridge).module)
|
||||||
io.finished := dut.io.finished
|
io.finished := dut.io.finished
|
||||||
|
139
src/main/scala/uncore/ahb/ToTL.scala
Normal file
139
src/main/scala/uncore/ahb/ToTL.scala
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
|
package uncore.ahb
|
||||||
|
|
||||||
|
import Chisel._
|
||||||
|
import chisel3.internal.sourceinfo.SourceInfo
|
||||||
|
import config._
|
||||||
|
import diplomacy._
|
||||||
|
import uncore.tilelink2._
|
||||||
|
|
||||||
|
case class AHBToTLNode() extends MixedAdapterNode(AHBImp, TLImp)(
|
||||||
|
dFn = { case AHBMasterPortParameters(masters) =>
|
||||||
|
TLClientPortParameters(clients = masters.map { m =>
|
||||||
|
TLClientParameters(nodePath = m.nodePath)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
uFn = { mp => AHBSlavePortParameters(
|
||||||
|
slaves = mp.managers.map { m =>
|
||||||
|
def adjust(x: TransferSizes) = {
|
||||||
|
if (x.contains(mp.beatBytes)) {
|
||||||
|
TransferSizes(x.min, m.minAlignment.min(mp.beatBytes * AHBParameters.maxTransfer).toInt)
|
||||||
|
} else { // larger than beatBytes requires beatBytes if misaligned
|
||||||
|
x.intersect(TransferSizes(1, mp.beatBytes))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AHBSlaveParameters(
|
||||||
|
address = m.address,
|
||||||
|
resources = m.resources,
|
||||||
|
regionType = m.regionType,
|
||||||
|
executable = m.executable,
|
||||||
|
nodePath = m.nodePath,
|
||||||
|
supportsWrite = adjust(m.supportsPutFull),
|
||||||
|
supportsRead = adjust(m.supportsGet))},
|
||||||
|
beatBytes = mp.beatBytes)
|
||||||
|
})
|
||||||
|
|
||||||
|
class AHBToTL()(implicit p: Parameters) extends LazyModule
|
||||||
|
{
|
||||||
|
val node = AHBToTLNode()
|
||||||
|
|
||||||
|
lazy val module = new LazyModuleImp(this) {
|
||||||
|
val io = new Bundle {
|
||||||
|
val in = node.bundleIn
|
||||||
|
val out = node.bundleOut
|
||||||
|
}
|
||||||
|
|
||||||
|
((io.in zip io.out) zip (node.edgesIn zip node.edgesOut)) foreach { case ((in, out), (edgeIn, edgeOut)) =>
|
||||||
|
val beatBytes = edgeOut.manager.beatBytes
|
||||||
|
|
||||||
|
val d_send = RegInit(Bool(false))
|
||||||
|
val d_recv = RegInit(Bool(false))
|
||||||
|
val d_error = RegInit(Bool(false))
|
||||||
|
val d_pause = RegInit(Bool(false))
|
||||||
|
val d_write = RegInit(Bool(false))
|
||||||
|
val d_addr = Reg(in.haddr)
|
||||||
|
val d_size = Reg(in.hsize)
|
||||||
|
|
||||||
|
when (out.d.valid) { d_recv := Bool(false); d_error := d_error || out.d.bits.error }
|
||||||
|
when (out.a.ready) { d_send := Bool(false) }
|
||||||
|
|
||||||
|
val a_count = RegInit(UInt(0, width = 4))
|
||||||
|
val a_first = a_count === UInt(0)
|
||||||
|
val d_last = a_first
|
||||||
|
|
||||||
|
val burst_sizes = Seq(1, 1, 4, 4, 8, 8, 16, 16)
|
||||||
|
val a_burst_size = Vec(burst_sizes.map(beats => UInt(log2Ceil(beats * beatBytes))))(in.hburst)
|
||||||
|
val a_burst_mask = Vec(burst_sizes.map(beats => UInt(beats * beatBytes - 1)))(in.hburst)
|
||||||
|
|
||||||
|
val a_burst_ok =
|
||||||
|
in.htrans === AHBParameters.TRANS_NONSEQ && // only start burst on first AHB beat
|
||||||
|
in.hsize === UInt(log2Ceil(beatBytes)) && // not a narrow burst
|
||||||
|
(in.haddr & a_burst_mask) === UInt(0) && // address aligned to burst size
|
||||||
|
in.hburst =/= AHBParameters.BURST_INCR && // we know the burst length a priori
|
||||||
|
Mux(in.hwrite, // target device supports the burst
|
||||||
|
edgeOut.manager.supportsPutFullSafe(in.haddr, a_burst_size),
|
||||||
|
edgeOut.manager.supportsGetSafe (in.haddr, a_burst_size))
|
||||||
|
|
||||||
|
val beat = TransferSizes(1, beatBytes)
|
||||||
|
val a_legal = // Is the single-beat access allowed?
|
||||||
|
Mux(in.hwrite,
|
||||||
|
edgeOut.manager.supportsPutFullSafe(in.haddr, in.hsize, Some(beat)),
|
||||||
|
edgeOut.manager.supportsGetSafe (in.haddr, in.hsize, Some(beat)))
|
||||||
|
|
||||||
|
val a_access = in.htrans === AHBParameters.TRANS_NONSEQ || in.htrans === AHBParameters.TRANS_SEQ
|
||||||
|
val a_accept = in.hready && in.hsel && a_access
|
||||||
|
|
||||||
|
when (a_accept) {
|
||||||
|
a_count := a_count - UInt(1)
|
||||||
|
d_error := d_error || !a_legal
|
||||||
|
when ( in.hwrite) { d_send := Bool(true) }
|
||||||
|
when (!in.hwrite) { d_recv := Bool(true) }
|
||||||
|
when (a_first) {
|
||||||
|
a_count := Mux(a_burst_ok, a_burst_mask >> log2Ceil(beatBytes), UInt(0))
|
||||||
|
d_send := a_legal
|
||||||
|
d_recv := a_legal
|
||||||
|
d_error := !a_legal
|
||||||
|
d_pause := Bool(false)
|
||||||
|
d_write := in.hwrite
|
||||||
|
d_addr := in.haddr
|
||||||
|
d_size := Mux(a_burst_ok, a_burst_size, in.hsize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out.a.valid := d_send
|
||||||
|
out.a.bits.opcode := Mux(d_write, TLMessages.PutFullData, TLMessages.Get)
|
||||||
|
out.a.bits.param := UInt(0)
|
||||||
|
out.a.bits.size := d_size
|
||||||
|
out.a.bits.source := UInt(0)
|
||||||
|
out.a.bits.address := d_addr
|
||||||
|
out.a.bits.data := in.hwdata
|
||||||
|
out.a.bits.mask := maskGen(d_addr, d_size, beatBytes)
|
||||||
|
|
||||||
|
// Save the error for the last beat (so the master can't cancel the burst)
|
||||||
|
// When we report an error, we need to be hreadyout LOW for one cycle
|
||||||
|
val inject_error = d_last && (d_error || (out.d.valid && out.d.bits.error))
|
||||||
|
when (inject_error) { d_pause := Bool(true) }
|
||||||
|
|
||||||
|
out.d.ready := d_recv // backpressure AccessAckData arriving faster than AHB beats
|
||||||
|
in.hrdata := out.d.bits.data
|
||||||
|
in.hresp := inject_error
|
||||||
|
in.hreadyout := (!inject_error || d_pause) && Mux(d_write, (!d_send || out.a.ready) && (!d_last || !d_recv || out.d.valid), out.d.valid || !d_recv)
|
||||||
|
|
||||||
|
// Unused channels
|
||||||
|
out.b.ready := Bool(true)
|
||||||
|
out.c.valid := Bool(false)
|
||||||
|
out.e.valid := Bool(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object AHBToTL
|
||||||
|
{
|
||||||
|
def apply()(x: AHBOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = {
|
||||||
|
val tl = LazyModule(new AHBToTL)
|
||||||
|
tl.node := x
|
||||||
|
tl.node
|
||||||
|
}
|
||||||
|
}
|
@ -25,9 +25,14 @@ class APBFuzzBridge()(implicit p: Parameters) extends LazyModule
|
|||||||
val gpio = LazyModule(new RRTest0(0x100))
|
val gpio = LazyModule(new RRTest0(0x100))
|
||||||
|
|
||||||
model.node := fuzz.node
|
model.node := fuzz.node
|
||||||
xbar.node := TLToAPB()(TLDelayer(0.1)(model.node))
|
|
||||||
ram.node := xbar.node
|
ram.node := xbar.node
|
||||||
gpio.node := xbar.node
|
gpio.node := xbar.node
|
||||||
|
xbar.node :=
|
||||||
|
TLToAPB()(
|
||||||
|
TLDelayer(0.2)(
|
||||||
|
TLBuffer(TLBufferParams.flow)(
|
||||||
|
TLDelayer(0.2)(
|
||||||
|
model.node))))
|
||||||
|
|
||||||
lazy val module = new LazyModuleImp(this) with HasUnitTestIO {
|
lazy val module = new LazyModuleImp(this) with HasUnitTestIO {
|
||||||
io.finished := fuzz.module.io.finished
|
io.finished := fuzz.module.io.finished
|
||||||
|
@ -25,7 +25,7 @@ class AXI4LiteFuzzRAM()(implicit p: Parameters) extends LazyModule
|
|||||||
val ram = LazyModule(new AXI4RAM(AddressSet(0x0, 0x3ff)))
|
val ram = LazyModule(new AXI4RAM(AddressSet(0x0, 0x3ff)))
|
||||||
|
|
||||||
model.node := fuzz.node
|
model.node := fuzz.node
|
||||||
xbar.node := TLDelayer(0.1)(model.node)
|
xbar.node := TLDelayer(0.1)(TLBuffer(TLBufferParams.flow)(TLDelayer(0.2)(model.node)))
|
||||||
ram.node := AXI4Fragmenter(lite=true)(TLToAXI4(0, true )(xbar.node))
|
ram.node := AXI4Fragmenter(lite=true)(TLToAXI4(0, true )(xbar.node))
|
||||||
gpio.node := AXI4Fragmenter(lite=true)(TLToAXI4(0, false)(xbar.node))
|
gpio.node := AXI4Fragmenter(lite=true)(TLToAXI4(0, false)(xbar.node))
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ class AXI4FullFuzzRAM()(implicit p: Parameters) extends LazyModule
|
|||||||
val ram = LazyModule(new AXI4RAM(AddressSet(0x0, 0x3ff)))
|
val ram = LazyModule(new AXI4RAM(AddressSet(0x0, 0x3ff)))
|
||||||
|
|
||||||
model.node := fuzz.node
|
model.node := fuzz.node
|
||||||
xbar.node := TLDelayer(0.1)(model.node)
|
xbar.node := TLDelayer(0.1)(TLBuffer(TLBufferParams.flow)(TLDelayer(0.2)(model.node)))
|
||||||
ram.node := AXI4Fragmenter(lite=false, maxInFlight = 2)(TLToAXI4(4,false)(xbar.node))
|
ram.node := AXI4Fragmenter(lite=false, maxInFlight = 2)(TLToAXI4(4,false)(xbar.node))
|
||||||
gpio.node := AXI4Fragmenter(lite=false, maxInFlight = 5)(TLToAXI4(4,true )(xbar.node))
|
gpio.node := AXI4Fragmenter(lite=false, maxInFlight = 5)(TLToAXI4(4,true )(xbar.node))
|
||||||
|
|
||||||
@ -69,7 +69,12 @@ class AXI4FuzzMaster()(implicit p: Parameters) extends LazyModule
|
|||||||
val model = LazyModule(new TLRAMModel("AXI4FuzzMaster"))
|
val model = LazyModule(new TLRAMModel("AXI4FuzzMaster"))
|
||||||
|
|
||||||
model.node := fuzz.node
|
model.node := fuzz.node
|
||||||
node := TLToAXI4(4)(TLDelayer(0.1)(model.node))
|
node :=
|
||||||
|
TLToAXI4(4)(
|
||||||
|
TLDelayer(0.1)(
|
||||||
|
TLBuffer(TLBufferParams.flow)(
|
||||||
|
TLDelayer(0.1)(
|
||||||
|
model.node))))
|
||||||
|
|
||||||
lazy val module = new LazyModuleImp(this) {
|
lazy val module = new LazyModuleImp(this) {
|
||||||
val io = new Bundle {
|
val io = new Bundle {
|
||||||
@ -84,9 +89,16 @@ class AXI4FuzzMaster()(implicit p: Parameters) extends LazyModule
|
|||||||
class AXI4FuzzSlave()(implicit p: Parameters) extends LazyModule
|
class AXI4FuzzSlave()(implicit p: Parameters) extends LazyModule
|
||||||
{
|
{
|
||||||
val node = AXI4InputNode()
|
val node = AXI4InputNode()
|
||||||
val ram = LazyModule(new TLRAM(AddressSet(0x0, 0xfff)))
|
val ram = LazyModule(new TLTestRAM(AddressSet(0x0, 0xfff)))
|
||||||
|
|
||||||
ram.node := TLFragmenter(4, 16)(AXI4ToTL()(AXI4Fragmenter()(node)))
|
ram.node :=
|
||||||
|
TLFragmenter(4, 16)(
|
||||||
|
TLDelayer(0.1)(
|
||||||
|
TLBuffer(TLBufferParams.flow)(
|
||||||
|
TLDelayer(0.1)(
|
||||||
|
AXI4ToTL()(
|
||||||
|
AXI4Fragmenter()(
|
||||||
|
node))))))
|
||||||
|
|
||||||
lazy val module = new LazyModuleImp(this) {
|
lazy val module = new LazyModuleImp(this) {
|
||||||
val io = new Bundle {
|
val io = new Bundle {
|
||||||
|
@ -8,18 +8,37 @@ import config._
|
|||||||
import diplomacy._
|
import diplomacy._
|
||||||
import scala.math.{min,max}
|
import scala.math.{min,max}
|
||||||
|
|
||||||
// pipe is only used if a queue has depth = 1
|
case class TLBufferParams(depth: Int, flow: Boolean, pipe: Boolean)
|
||||||
class TLBuffer(a: Int = 2, b: Int = 2, c: Int = 2, d: Int = 2, e: Int = 2, pipe: Boolean = true)(implicit p: Parameters) extends LazyModule
|
|
||||||
{
|
{
|
||||||
require (a >= 0)
|
require (depth >= 0)
|
||||||
require (b >= 0)
|
def isDefined = depth > 0
|
||||||
require (c >= 0)
|
def latency = if (isDefined && !flow) 1 else 0
|
||||||
require (d >= 0)
|
}
|
||||||
require (e >= 0)
|
|
||||||
|
object TLBufferParams
|
||||||
|
{
|
||||||
|
implicit def apply(depth: Int): TLBufferParams = TLBufferParams(depth, false, false)
|
||||||
|
|
||||||
|
val default = TLBufferParams(2)
|
||||||
|
val none = TLBufferParams(0)
|
||||||
|
val flow = TLBufferParams(1, true, false)
|
||||||
|
val pipe = TLBufferParams(1, false, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
class TLBuffer(
|
||||||
|
a: TLBufferParams,
|
||||||
|
b: TLBufferParams,
|
||||||
|
c: TLBufferParams,
|
||||||
|
d: TLBufferParams,
|
||||||
|
e: TLBufferParams)(implicit p: Parameters) extends LazyModule
|
||||||
|
{
|
||||||
|
def this(ace: TLBufferParams, bd: TLBufferParams)(implicit p: Parameters) = this(ace, bd, ace, bd, ace)
|
||||||
|
def this(abcde: TLBufferParams)(implicit p: Parameters) = this(abcde, abcde)
|
||||||
|
def this()(implicit p: Parameters) = this(TLBufferParams.default)
|
||||||
|
|
||||||
val node = TLAdapterNode(
|
val node = TLAdapterNode(
|
||||||
clientFn = { p => p.copy(minLatency = p.minLatency + min(1,b) + min(1,c)) },
|
clientFn = { p => p.copy(minLatency = p.minLatency + b.latency + c.latency) },
|
||||||
managerFn = { p => p.copy(minLatency = p.minLatency + min(1,a) + min(1,d)) })
|
managerFn = { p => p.copy(minLatency = p.minLatency + a.latency + d.latency) })
|
||||||
|
|
||||||
lazy val module = new LazyModuleImp(this) {
|
lazy val module = new LazyModuleImp(this) {
|
||||||
val io = new Bundle {
|
val io = new Bundle {
|
||||||
@ -27,14 +46,22 @@ class TLBuffer(a: Int = 2, b: Int = 2, c: Int = 2, d: Int = 2, e: Int = 2, pipe:
|
|||||||
val out = node.bundleOut
|
val out = node.bundleOut
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def buffer[T <: Data](config: TLBufferParams, data: DecoupledIO[T]): DecoupledIO[T] = {
|
||||||
|
if (config.isDefined) {
|
||||||
|
Queue(data, config.depth, pipe=config.pipe, flow=config.flow)
|
||||||
|
} else {
|
||||||
|
data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
((io.in zip io.out) zip (node.edgesIn zip node.edgesOut)) foreach { case ((in, out), (edgeIn, edgeOut)) =>
|
((io.in zip io.out) zip (node.edgesIn zip node.edgesOut)) foreach { case ((in, out), (edgeIn, edgeOut)) =>
|
||||||
if (a>0) { out.a <> Queue(in .a, a, pipe && a<2) } else { out.a <> in.a }
|
out.a <> buffer(a, in .a)
|
||||||
if (d>0) { in .d <> Queue(out.d, d, pipe && d<2) } else { in.d <> out.d }
|
in .d <> buffer(d, out.d)
|
||||||
|
|
||||||
if (edgeOut.manager.anySupportAcquireB && edgeOut.client.anySupportProbe) {
|
if (edgeOut.manager.anySupportAcquireB && edgeOut.client.anySupportProbe) {
|
||||||
if (b>0) { in .b <> Queue(out.b, b, pipe && b<2) } else { in.b <> out.b }
|
in .b <> buffer(b, out.b)
|
||||||
if (c>0) { out.c <> Queue(in .c, c, pipe && c<2) } else { out.c <> in.c }
|
out.c <> buffer(c, in .c)
|
||||||
if (e>0) { out.e <> Queue(in .e, e, pipe && e<2) } else { out.e <> in.e }
|
out.e <> buffer(e, in .e)
|
||||||
} else {
|
} else {
|
||||||
in.b.valid := Bool(false)
|
in.b.valid := Bool(false)
|
||||||
in.c.ready := Bool(true)
|
in.c.ready := Bool(true)
|
||||||
@ -50,13 +77,16 @@ class TLBuffer(a: Int = 2, b: Int = 2, c: Int = 2, d: Int = 2, e: Int = 2, pipe:
|
|||||||
object TLBuffer
|
object TLBuffer
|
||||||
{
|
{
|
||||||
// applied to the TL source node; y.node := TLBuffer(x.node)
|
// applied to the TL source node; y.node := TLBuffer(x.node)
|
||||||
def apply() (x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = apply(2)(x)
|
def apply() (x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = apply(TLBufferParams.default)(x)
|
||||||
def apply(entries: Int) (x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = apply(entries, true)(x)
|
def apply(abcde: TLBufferParams) (x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = apply(abcde, abcde)(x)
|
||||||
def apply(entries: Int, pipe: Boolean) (x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = apply(entries, entries, pipe)(x)
|
def apply(ace: TLBufferParams, bd: TLBufferParams)(x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = apply(ace, bd, ace, bd, ace)(x)
|
||||||
def apply(ace: Int, bd: Int) (x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = apply(ace, bd, true)(x)
|
def apply(
|
||||||
def apply(ace: Int, bd: Int, pipe: Boolean)(x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = apply(ace, bd, ace, bd, ace, pipe)(x)
|
a: TLBufferParams,
|
||||||
def apply(a: Int, b: Int, c: Int, d: Int, e: Int, pipe: Boolean = true)(x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = {
|
b: TLBufferParams,
|
||||||
val buffer = LazyModule(new TLBuffer(a, b, c, d, e, pipe))
|
c: TLBufferParams,
|
||||||
|
d: TLBufferParams,
|
||||||
|
e: TLBufferParams)(x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = {
|
||||||
|
val buffer = LazyModule(new TLBuffer(a, b, c, d, e))
|
||||||
buffer.node := x
|
buffer.node := x
|
||||||
buffer.node
|
buffer.node
|
||||||
}
|
}
|
||||||
|
@ -118,37 +118,40 @@ case class TLManagerPortParameters(
|
|||||||
// Does this Port manage this ID/address?
|
// Does this Port manage this ID/address?
|
||||||
def containsSafe(address: UInt) = findSafe(address).reduce(_ || _)
|
def containsSafe(address: UInt) = findSafe(address).reduce(_ || _)
|
||||||
|
|
||||||
private def safe_helper(member: TLManagerParameters => TransferSizes)(address: UInt, lgSize: UInt) = {
|
private def supportHelper(
|
||||||
val allSame = managers.map(member(_) == member(managers(0))).reduce(_ && _)
|
safe: Boolean,
|
||||||
if (allSame) containsSafe(address) && member(managers(0)).containsLg(lgSize) else {
|
member: TLManagerParameters => TransferSizes,
|
||||||
Mux1H(findSafe(address), managers.map(member(_).containsLg(lgSize)))
|
address: UInt,
|
||||||
}
|
lgSize: UInt,
|
||||||
}
|
range: Option[TransferSizes]): Bool = {
|
||||||
private def fast_helper(member: TLManagerParameters => TransferSizes)(address: UInt, lgSize: UInt) = {
|
def trim(x: TransferSizes) = range.map(_.intersect(x)).getOrElse(x)
|
||||||
val allSame = managers.map(member(_) == member(managers(0))).reduce(_ && _)
|
val supportCases = managers.groupBy(m => trim(member(m))).mapValues(_.flatMap(_.address))
|
||||||
if (allSame) member(managers(0)).containsLg(lgSize) else {
|
val mask = if (safe) ~BigInt(0) else AddressDecoder(supportCases.values.toList)
|
||||||
Mux1H(findFast(address), managers.map(member(_).containsLg(lgSize)))
|
val simplified = supportCases.mapValues(seq => AddressSet.unify(seq.map(_.widen(~mask)).distinct))
|
||||||
}
|
simplified.map { case (s, a) =>
|
||||||
|
(Bool(Some(s) == range) || s.containsLg(lgSize)) &&
|
||||||
|
a.map(_.contains(address)).reduce(_||_)
|
||||||
|
}.foldLeft(Bool(false))(_||_)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for support of a given operation at a specific address
|
// Check for support of a given operation at a specific address
|
||||||
val supportsAcquireTSafe = safe_helper(_.supportsAcquireT) _
|
def supportsAcquireTSafe (address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(true, _.supportsAcquireT, address, lgSize, range)
|
||||||
val supportsAcquireBSafe = safe_helper(_.supportsAcquireB) _
|
def supportsAcquireBSafe (address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(true, _.supportsAcquireB, address, lgSize, range)
|
||||||
val supportsArithmeticSafe = safe_helper(_.supportsArithmetic) _
|
def supportsArithmeticSafe(address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(true, _.supportsArithmetic, address, lgSize, range)
|
||||||
val supportsLogicalSafe = safe_helper(_.supportsLogical) _
|
def supportsLogicalSafe (address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(true, _.supportsLogical, address, lgSize, range)
|
||||||
val supportsGetSafe = safe_helper(_.supportsGet) _
|
def supportsGetSafe (address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(true, _.supportsGet, address, lgSize, range)
|
||||||
val supportsPutFullSafe = safe_helper(_.supportsPutFull) _
|
def supportsPutFullSafe (address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(true, _.supportsPutFull, address, lgSize, range)
|
||||||
val supportsPutPartialSafe = safe_helper(_.supportsPutPartial) _
|
def supportsPutPartialSafe(address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(true, _.supportsPutPartial, address, lgSize, range)
|
||||||
val supportsHintSafe = safe_helper(_.supportsHint) _
|
def supportsHintSafe (address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(true, _.supportsHint, address, lgSize, range)
|
||||||
|
|
||||||
val supportsAcquireTFast = fast_helper(_.supportsAcquireT) _
|
def supportsAcquireTFast (address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(false, _.supportsAcquireT, address, lgSize, range)
|
||||||
val supportsAcquireBFast = fast_helper(_.supportsAcquireB) _
|
def supportsAcquireBFast (address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(false, _.supportsAcquireB, address, lgSize, range)
|
||||||
val supportsArithmeticFast = fast_helper(_.supportsArithmetic) _
|
def supportsArithmeticFast(address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(false, _.supportsArithmetic, address, lgSize, range)
|
||||||
val supportsLogicalFast = fast_helper(_.supportsLogical) _
|
def supportsLogicalFast (address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(false, _.supportsLogical, address, lgSize, range)
|
||||||
val supportsGetFast = fast_helper(_.supportsGet) _
|
def supportsGetFast (address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(false, _.supportsGet, address, lgSize, range)
|
||||||
val supportsPutFullFast = fast_helper(_.supportsPutFull) _
|
def supportsPutFullFast (address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(false, _.supportsPutFull, address, lgSize, range)
|
||||||
val supportsPutPartialFast = fast_helper(_.supportsPutPartial) _
|
def supportsPutPartialFast(address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(false, _.supportsPutPartial, address, lgSize, range)
|
||||||
val supportsHintFast = fast_helper(_.supportsHint) _
|
def supportsHintFast (address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(false, _.supportsHint, address, lgSize, range)
|
||||||
}
|
}
|
||||||
|
|
||||||
case class TLClientParameters(
|
case class TLClientParameters(
|
||||||
|
83
src/main/scala/uncore/tilelink2/TestRAM.scala
Normal file
83
src/main/scala/uncore/tilelink2/TestRAM.scala
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
|
package uncore.tilelink2
|
||||||
|
|
||||||
|
import Chisel._
|
||||||
|
import config._
|
||||||
|
import diplomacy._
|
||||||
|
import util._
|
||||||
|
|
||||||
|
// Do not use this for synthesis! Only for simulation.
|
||||||
|
class TLTestRAM(address: AddressSet, executable: Boolean = true, beatBytes: Int = 4)(implicit p: Parameters) extends LazyModule
|
||||||
|
{
|
||||||
|
val device = new MemoryDevice
|
||||||
|
|
||||||
|
val node = TLManagerNode(Seq(TLManagerPortParameters(
|
||||||
|
Seq(TLManagerParameters(
|
||||||
|
address = List(address),
|
||||||
|
resources = device.reg,
|
||||||
|
regionType = RegionType.UNCACHED,
|
||||||
|
executable = executable,
|
||||||
|
supportsGet = TransferSizes(1, beatBytes),
|
||||||
|
supportsPutPartial = TransferSizes(1, beatBytes),
|
||||||
|
supportsPutFull = TransferSizes(1, beatBytes),
|
||||||
|
fifoId = Some(0))), // requests are handled in order
|
||||||
|
beatBytes = beatBytes)))
|
||||||
|
|
||||||
|
// We require the address range to include an entire beat (for the write mask)
|
||||||
|
require ((address.mask & (beatBytes-1)) == beatBytes-1)
|
||||||
|
|
||||||
|
lazy val module = new LazyModuleImp(this) {
|
||||||
|
val io = new Bundle {
|
||||||
|
val in = node.bundleIn
|
||||||
|
}
|
||||||
|
|
||||||
|
def bigBits(x: BigInt, tail: List[Boolean] = List.empty[Boolean]): List[Boolean] =
|
||||||
|
if (x == 0) tail.reverse else bigBits(x >> 1, ((x & 1) == 1) :: tail)
|
||||||
|
val mask = bigBits(address.mask >> log2Ceil(beatBytes))
|
||||||
|
|
||||||
|
val in = io.in(0)
|
||||||
|
val edge = node.edgesIn(0)
|
||||||
|
|
||||||
|
val addrBits = (mask zip edge.addr_hi(in.a.bits).toBools).filter(_._1).map(_._2)
|
||||||
|
val memAddress = Cat(addrBits.reverse)
|
||||||
|
val mem = Mem(1 << addrBits.size, Vec(beatBytes, Bits(width = 8)))
|
||||||
|
|
||||||
|
// "Flow control"
|
||||||
|
in.a.ready := in.d.ready
|
||||||
|
in.d.valid := in.a.valid
|
||||||
|
|
||||||
|
val hasData = edge.hasData(in.a.bits)
|
||||||
|
val wdata = Vec.tabulate(beatBytes) { i => in.a.bits.data(8*(i+1)-1, 8*i) }
|
||||||
|
|
||||||
|
in.d.bits := edge.AccessAck(in.a.bits, UInt(0))
|
||||||
|
in.d.bits.data := Cat(mem(memAddress).reverse)
|
||||||
|
in.d.bits.opcode := Mux(hasData, TLMessages.AccessAck, TLMessages.AccessAckData)
|
||||||
|
when (in.a.fire() && hasData) { mem.write(memAddress, wdata, in.a.bits.mask.toBools) }
|
||||||
|
|
||||||
|
// Tie off unused channels
|
||||||
|
in.b.valid := Bool(false)
|
||||||
|
in.c.ready := Bool(true)
|
||||||
|
in.e.ready := Bool(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Synthesizeable unit testing */
|
||||||
|
import unittest._
|
||||||
|
|
||||||
|
class TLRAMZeroDelay(ramBeatBytes: Int)(implicit p: Parameters) extends LazyModule {
|
||||||
|
val fuzz = LazyModule(new TLFuzzer(5000))
|
||||||
|
val model = LazyModule(new TLRAMModel)
|
||||||
|
val ram = LazyModule(new TLTestRAM(AddressSet(0x0, 0x3ff), beatBytes = ramBeatBytes))
|
||||||
|
|
||||||
|
model.node := fuzz.node
|
||||||
|
ram.node := TLDelayer(0.25)(model.node)
|
||||||
|
|
||||||
|
lazy val module = new LazyModuleImp(this) with HasUnitTestIO {
|
||||||
|
io.finished := fuzz.module.io.finished
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TLRAMZeroDelayTest(ramBeatBytes: Int)(implicit p: Parameters) extends UnitTest(timeout = 500000) {
|
||||||
|
io.finished := Module(LazyModule(new TLRAMZeroDelay(ramBeatBytes)).module).io.finished
|
||||||
|
}
|
@ -13,6 +13,7 @@ class WithUncoreUnitTests extends Config((site, here, up) => {
|
|||||||
Seq(
|
Seq(
|
||||||
Module(new uncore.tilelink2.TLFuzzRAMTest),
|
Module(new uncore.tilelink2.TLFuzzRAMTest),
|
||||||
Module(new uncore.ahb.AHBBridgeTest),
|
Module(new uncore.ahb.AHBBridgeTest),
|
||||||
|
Module(new uncore.ahb.AHBNativeTest),
|
||||||
Module(new uncore.apb.APBBridgeTest),
|
Module(new uncore.apb.APBBridgeTest),
|
||||||
Module(new uncore.axi4.AXI4LiteFuzzRAMTest),
|
Module(new uncore.axi4.AXI4LiteFuzzRAMTest),
|
||||||
Module(new uncore.axi4.AXI4FullFuzzRAMTest),
|
Module(new uncore.axi4.AXI4FullFuzzRAMTest),
|
||||||
@ -28,6 +29,7 @@ class WithTLSimpleUnitTests extends Config((site, here, up) => {
|
|||||||
Module(new uncore.tilelink2.TLRAMSimpleTest(1)),
|
Module(new uncore.tilelink2.TLRAMSimpleTest(1)),
|
||||||
Module(new uncore.tilelink2.TLRAMSimpleTest(4)),
|
Module(new uncore.tilelink2.TLRAMSimpleTest(4)),
|
||||||
Module(new uncore.tilelink2.TLRAMSimpleTest(16)),
|
Module(new uncore.tilelink2.TLRAMSimpleTest(16)),
|
||||||
|
Module(new uncore.tilelink2.TLRAMZeroDelayTest(4)),
|
||||||
Module(new uncore.tilelink2.TLRR0Test),
|
Module(new uncore.tilelink2.TLRR0Test),
|
||||||
Module(new uncore.tilelink2.TLRR1Test),
|
Module(new uncore.tilelink2.TLRR1Test),
|
||||||
Module(new uncore.tilelink2.TLRAMRationalCrossingTest),
|
Module(new uncore.tilelink2.TLRAMRationalCrossingTest),
|
||||||
|
Loading…
Reference in New Issue
Block a user