commit
625919722c
@ -43,10 +43,6 @@ case class AHBSlavePortParameters(
|
||||
// Check that the link can be implemented in AHB
|
||||
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
|
||||
slaves.combinations(2).foreach { case Seq(x,y) =>
|
||||
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 AHBRegModule((), _, _) with RRTest1Module)
|
||||
|
||||
class AHBFuzzBridge()(implicit p: Parameters) extends LazyModule
|
||||
class AHBFuzzNative()(implicit p: Parameters) extends LazyModule
|
||||
{
|
||||
val fuzz = LazyModule(new TLFuzzer(5000))
|
||||
val model = LazyModule(new TLRAMModel("AHBFuzzMaster"))
|
||||
val model = LazyModule(new TLRAMModel("AHBFuzzNative"))
|
||||
var xbar = LazyModule(new AHBFanout)
|
||||
val ram = LazyModule(new AHBRAM(AddressSet(0x0, 0xff)))
|
||||
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) {
|
||||
val dut = Module(LazyModule(new AHBFuzzBridge).module)
|
||||
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))
|
||||
|
||||
model.node := fuzz.node
|
||||
xbar.node := TLToAPB()(TLDelayer(0.1)(model.node))
|
||||
ram.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 {
|
||||
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)))
|
||||
|
||||
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))
|
||||
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)))
|
||||
|
||||
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))
|
||||
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"))
|
||||
|
||||
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) {
|
||||
val io = new Bundle {
|
||||
@ -84,9 +89,16 @@ class AXI4FuzzMaster()(implicit p: Parameters) extends LazyModule
|
||||
class AXI4FuzzSlave()(implicit p: Parameters) extends LazyModule
|
||||
{
|
||||
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) {
|
||||
val io = new Bundle {
|
||||
|
@ -8,18 +8,37 @@ import config._
|
||||
import diplomacy._
|
||||
import scala.math.{min,max}
|
||||
|
||||
// pipe is only used if a queue has depth = 1
|
||||
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
|
||||
case class TLBufferParams(depth: Int, flow: Boolean, pipe: Boolean)
|
||||
{
|
||||
require (a >= 0)
|
||||
require (b >= 0)
|
||||
require (c >= 0)
|
||||
require (d >= 0)
|
||||
require (e >= 0)
|
||||
require (depth >= 0)
|
||||
def isDefined = depth > 0
|
||||
def latency = if (isDefined && !flow) 1 else 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(
|
||||
clientFn = { p => p.copy(minLatency = p.minLatency + min(1,b) + min(1,c)) },
|
||||
managerFn = { p => p.copy(minLatency = p.minLatency + min(1,a) + min(1,d)) })
|
||||
clientFn = { p => p.copy(minLatency = p.minLatency + b.latency + c.latency) },
|
||||
managerFn = { p => p.copy(minLatency = p.minLatency + a.latency + d.latency) })
|
||||
|
||||
lazy val module = new LazyModuleImp(this) {
|
||||
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
|
||||
}
|
||||
|
||||
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)) =>
|
||||
if (a>0) { out.a <> Queue(in .a, a, pipe && a<2) } else { out.a <> in.a }
|
||||
if (d>0) { in .d <> Queue(out.d, d, pipe && d<2) } else { in.d <> out.d }
|
||||
out.a <> buffer(a, in .a)
|
||||
in .d <> buffer(d, out.d)
|
||||
|
||||
if (edgeOut.manager.anySupportAcquireB && edgeOut.client.anySupportProbe) {
|
||||
if (b>0) { in .b <> Queue(out.b, b, pipe && b<2) } else { in.b <> out.b }
|
||||
if (c>0) { out.c <> Queue(in .c, c, pipe && c<2) } else { out.c <> in.c }
|
||||
if (e>0) { out.e <> Queue(in .e, e, pipe && e<2) } else { out.e <> in.e }
|
||||
in .b <> buffer(b, out.b)
|
||||
out.c <> buffer(c, in .c)
|
||||
out.e <> buffer(e, in .e)
|
||||
} else {
|
||||
in.b.valid := Bool(false)
|
||||
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
|
||||
{
|
||||
// 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(entries: Int) (x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = apply(entries, true)(x)
|
||||
def apply(entries: Int, pipe: Boolean) (x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = apply(entries, entries, pipe)(x)
|
||||
def apply(ace: Int, bd: Int) (x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = apply(ace, bd, true)(x)
|
||||
def apply(ace: Int, bd: Int, pipe: Boolean)(x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = apply(ace, bd, ace, bd, ace, pipe)(x)
|
||||
def apply(a: Int, b: Int, c: Int, d: Int, e: Int, pipe: Boolean = true)(x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = {
|
||||
val buffer = LazyModule(new TLBuffer(a, b, c, d, e, pipe))
|
||||
def apply() (x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = apply(TLBufferParams.default)(x)
|
||||
def apply(abcde: TLBufferParams) (x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = apply(abcde, abcde)(x)
|
||||
def apply(ace: TLBufferParams, bd: TLBufferParams)(x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = apply(ace, bd, ace, bd, ace)(x)
|
||||
def apply(
|
||||
a: TLBufferParams,
|
||||
b: TLBufferParams,
|
||||
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
|
||||
}
|
||||
|
@ -118,37 +118,40 @@ case class TLManagerPortParameters(
|
||||
// Does this Port manage this ID/address?
|
||||
def containsSafe(address: UInt) = findSafe(address).reduce(_ || _)
|
||||
|
||||
private def safe_helper(member: TLManagerParameters => TransferSizes)(address: UInt, lgSize: UInt) = {
|
||||
val allSame = managers.map(member(_) == member(managers(0))).reduce(_ && _)
|
||||
if (allSame) containsSafe(address) && member(managers(0)).containsLg(lgSize) else {
|
||||
Mux1H(findSafe(address), managers.map(member(_).containsLg(lgSize)))
|
||||
}
|
||||
}
|
||||
private def fast_helper(member: TLManagerParameters => TransferSizes)(address: UInt, lgSize: UInt) = {
|
||||
val allSame = managers.map(member(_) == member(managers(0))).reduce(_ && _)
|
||||
if (allSame) member(managers(0)).containsLg(lgSize) else {
|
||||
Mux1H(findFast(address), managers.map(member(_).containsLg(lgSize)))
|
||||
}
|
||||
private def supportHelper(
|
||||
safe: Boolean,
|
||||
member: TLManagerParameters => TransferSizes,
|
||||
address: UInt,
|
||||
lgSize: UInt,
|
||||
range: Option[TransferSizes]): Bool = {
|
||||
def trim(x: TransferSizes) = range.map(_.intersect(x)).getOrElse(x)
|
||||
val supportCases = managers.groupBy(m => trim(member(m))).mapValues(_.flatMap(_.address))
|
||||
val mask = if (safe) ~BigInt(0) else AddressDecoder(supportCases.values.toList)
|
||||
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
|
||||
val supportsAcquireTSafe = safe_helper(_.supportsAcquireT) _
|
||||
val supportsAcquireBSafe = safe_helper(_.supportsAcquireB) _
|
||||
val supportsArithmeticSafe = safe_helper(_.supportsArithmetic) _
|
||||
val supportsLogicalSafe = safe_helper(_.supportsLogical) _
|
||||
val supportsGetSafe = safe_helper(_.supportsGet) _
|
||||
val supportsPutFullSafe = safe_helper(_.supportsPutFull) _
|
||||
val supportsPutPartialSafe = safe_helper(_.supportsPutPartial) _
|
||||
val supportsHintSafe = safe_helper(_.supportsHint) _
|
||||
def supportsAcquireTSafe (address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(true, _.supportsAcquireT, address, lgSize, range)
|
||||
def supportsAcquireBSafe (address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(true, _.supportsAcquireB, address, lgSize, range)
|
||||
def supportsArithmeticSafe(address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(true, _.supportsArithmetic, address, lgSize, range)
|
||||
def supportsLogicalSafe (address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(true, _.supportsLogical, address, lgSize, range)
|
||||
def supportsGetSafe (address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(true, _.supportsGet, address, lgSize, range)
|
||||
def supportsPutFullSafe (address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(true, _.supportsPutFull, address, lgSize, range)
|
||||
def supportsPutPartialSafe(address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(true, _.supportsPutPartial, address, lgSize, range)
|
||||
def supportsHintSafe (address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(true, _.supportsHint, address, lgSize, range)
|
||||
|
||||
val supportsAcquireTFast = fast_helper(_.supportsAcquireT) _
|
||||
val supportsAcquireBFast = fast_helper(_.supportsAcquireB) _
|
||||
val supportsArithmeticFast = fast_helper(_.supportsArithmetic) _
|
||||
val supportsLogicalFast = fast_helper(_.supportsLogical) _
|
||||
val supportsGetFast = fast_helper(_.supportsGet) _
|
||||
val supportsPutFullFast = fast_helper(_.supportsPutFull) _
|
||||
val supportsPutPartialFast = fast_helper(_.supportsPutPartial) _
|
||||
val supportsHintFast = fast_helper(_.supportsHint) _
|
||||
def supportsAcquireTFast (address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(false, _.supportsAcquireT, address, lgSize, range)
|
||||
def supportsAcquireBFast (address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(false, _.supportsAcquireB, address, lgSize, range)
|
||||
def supportsArithmeticFast(address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(false, _.supportsArithmetic, address, lgSize, range)
|
||||
def supportsLogicalFast (address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(false, _.supportsLogical, address, lgSize, range)
|
||||
def supportsGetFast (address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(false, _.supportsGet, address, lgSize, range)
|
||||
def supportsPutFullFast (address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(false, _.supportsPutFull, address, lgSize, range)
|
||||
def supportsPutPartialFast(address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(false, _.supportsPutPartial, address, lgSize, range)
|
||||
def supportsHintFast (address: UInt, lgSize: UInt, range: Option[TransferSizes] = None) = supportHelper(false, _.supportsHint, address, lgSize, range)
|
||||
}
|
||||
|
||||
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(
|
||||
Module(new uncore.tilelink2.TLFuzzRAMTest),
|
||||
Module(new uncore.ahb.AHBBridgeTest),
|
||||
Module(new uncore.ahb.AHBNativeTest),
|
||||
Module(new uncore.apb.APBBridgeTest),
|
||||
Module(new uncore.axi4.AXI4LiteFuzzRAMTest),
|
||||
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(4)),
|
||||
Module(new uncore.tilelink2.TLRAMSimpleTest(16)),
|
||||
Module(new uncore.tilelink2.TLRAMZeroDelayTest(4)),
|
||||
Module(new uncore.tilelink2.TLRR0Test),
|
||||
Module(new uncore.tilelink2.TLRR1Test),
|
||||
Module(new uncore.tilelink2.TLRAMRationalCrossingTest),
|
||||
|
Loading…
Reference in New Issue
Block a user