1
0

Merge pull request #584 from ucb-bar/ahb-in

AHB master port support
This commit is contained in:
Wesley W. Terpstra 2017-03-14 19:28:09 -07:00 committed by GitHub
commit 625919722c
9 changed files with 392 additions and 61 deletions

View File

@ -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 =>

View File

@ -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

View 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
}
}

View File

@ -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

View File

@ -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 {

View File

@ -8,33 +8,60 @@ 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 {
val in = node.bundleIn
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
}

View File

@ -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(

View 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
}

View File

@ -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),