2016-11-28 01:16:37 +01:00
|
|
|
// See LICENSE.SiFive for license details.
|
|
|
|
|
2016-09-10 02:16:35 +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._
|
2016-09-10 02:16:35 +02:00
|
|
|
|
2016-09-13 01:55:29 +02:00
|
|
|
class IDMapGenerator(numIds: Int) extends Module {
|
|
|
|
val w = log2Up(numIds)
|
|
|
|
val io = new Bundle {
|
|
|
|
val free = Decoupled(UInt(width = w)).flip
|
|
|
|
val alloc = Decoupled(UInt(width = w))
|
|
|
|
}
|
|
|
|
|
|
|
|
// True indicates that the id is available
|
2016-09-22 20:33:40 +02:00
|
|
|
val bitmap = RegInit(UInt((BigInt(1) << numIds) - 1, width = numIds))
|
2016-09-13 01:55:29 +02:00
|
|
|
|
|
|
|
io.free.ready := Bool(true)
|
2016-09-22 20:33:40 +02:00
|
|
|
assert (!io.free.valid || !bitmap(io.free.bits)) // No double freeing
|
2016-09-13 01:55:29 +02:00
|
|
|
|
2016-10-11 19:29:31 +02:00
|
|
|
val select = ~(leftOR(bitmap) << 1) & bitmap
|
2016-09-13 01:55:29 +02:00
|
|
|
io.alloc.bits := OHToUInt(select)
|
2016-09-22 20:33:40 +02:00
|
|
|
io.alloc.valid := bitmap.orR()
|
2016-09-13 01:55:29 +02:00
|
|
|
|
2016-09-22 20:33:40 +02:00
|
|
|
val clr = Wire(init = UInt(0, width = numIds))
|
|
|
|
when (io.alloc.fire()) { clr := UIntToOH(io.alloc.bits) }
|
2016-09-13 01:55:29 +02:00
|
|
|
|
2016-09-22 20:33:40 +02:00
|
|
|
val set = Wire(init = UInt(0, width = numIds))
|
|
|
|
when (io.free.fire()) { set := UIntToOH(io.free.bits) }
|
|
|
|
|
|
|
|
bitmap := (bitmap & ~clr) | set
|
2016-09-13 01:55:29 +02:00
|
|
|
}
|
|
|
|
|
2016-09-10 02:16:35 +02:00
|
|
|
object LFSR64
|
|
|
|
{
|
2017-03-11 11:53:11 +01:00
|
|
|
def apply(increment: Bool = Bool(true)): UInt =
|
2016-09-10 02:16:35 +02:00
|
|
|
{
|
|
|
|
val wide = 64
|
2017-03-13 21:16:17 +01:00
|
|
|
val lfsr = Reg(UInt(width = wide)) // random initial value based on simulation seed
|
2016-09-10 02:16:35 +02:00
|
|
|
val xor = lfsr(0) ^ lfsr(1) ^ lfsr(3) ^ lfsr(4)
|
2017-03-13 21:16:17 +01:00
|
|
|
when (increment) {
|
|
|
|
lfsr := Mux(lfsr === UInt(0), UInt(1), Cat(xor, lfsr(wide-1,1)))
|
|
|
|
}
|
2016-09-10 02:16:35 +02:00
|
|
|
lfsr
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-13 21:25:57 +02:00
|
|
|
trait HasNoiseMakerIO
|
2016-09-10 02:16:35 +02:00
|
|
|
{
|
2016-09-13 21:25:57 +02:00
|
|
|
val io = new Bundle {
|
|
|
|
val inc = Bool(INPUT)
|
|
|
|
val random = UInt(OUTPUT)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class LFSRNoiseMaker(wide: Int) extends Module with HasNoiseMakerIO
|
|
|
|
{
|
|
|
|
val lfsrs = Seq.fill((wide+63)/64) { LFSR64(io.inc) }
|
|
|
|
io.random := Cat(lfsrs)(wide-1,0)
|
|
|
|
}
|
|
|
|
|
|
|
|
object LFSRNoiseMaker {
|
2016-09-10 02:16:35 +02:00
|
|
|
def apply(wide: Int, increment: Bool = Bool(true)): UInt = {
|
2016-09-13 21:25:57 +02:00
|
|
|
val nm = Module(new LFSRNoiseMaker(wide))
|
|
|
|
nm.io.inc := increment
|
|
|
|
nm.io.random
|
2016-09-10 02:16:35 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-13 21:25:57 +02:00
|
|
|
/** TLFuzzer drives test traffic over TL2 links. It generates a sequence of randomized
|
|
|
|
* requests, and issues legal ones into the DUT. TODO: Currently the fuzzer only generates
|
|
|
|
* memory operations, not permissions transfers.
|
|
|
|
* @param nOperations is the total number of operations that the fuzzer must complete for the test to pass
|
|
|
|
* @param inFlight is the number of operations that can be in-flight to the DUT concurrently
|
|
|
|
* @param noiseMaker is a function that supplies a random UInt of a given width every time inc is true
|
|
|
|
*/
|
|
|
|
class TLFuzzer(
|
|
|
|
nOperations: Int,
|
|
|
|
inFlight: Int = 32,
|
2016-10-06 22:20:13 +02:00
|
|
|
noiseMaker: (Int, Bool, Int) => UInt = {
|
|
|
|
(wide: Int, increment: Bool, abs_values: Int) =>
|
|
|
|
LFSRNoiseMaker(wide=wide, increment=increment)
|
2017-02-13 00:18:47 +01:00
|
|
|
},
|
2017-05-04 00:29:14 +02:00
|
|
|
noModify: Boolean = false,
|
|
|
|
overrideAddress: Option[AddressSet] = None)(implicit p: Parameters) extends LazyModule
|
2016-09-10 02:16:35 +02:00
|
|
|
{
|
2016-09-13 01:55:29 +02:00
|
|
|
val node = TLClientNode(TLClientParameters(sourceId = IdRange(0,inFlight)))
|
2016-09-10 02:16:35 +02:00
|
|
|
|
|
|
|
lazy val module = new LazyModuleImp(this) {
|
|
|
|
val io = new Bundle {
|
|
|
|
val out = node.bundleOut
|
|
|
|
val finished = Bool()
|
|
|
|
}
|
|
|
|
|
|
|
|
val out = io.out(0)
|
|
|
|
val edge = node.edgesOut(0)
|
2016-09-13 21:25:57 +02:00
|
|
|
|
|
|
|
// Extract useful parameters from the TL edge
|
2016-09-13 01:55:29 +02:00
|
|
|
val maxTransfer = edge.manager.maxTransfer
|
|
|
|
val beatBytes = edge.manager.beatBytes
|
|
|
|
val maxLgBeats = log2Up(maxTransfer/beatBytes)
|
2017-05-09 03:48:40 +02:00
|
|
|
val addressBits = log2Up(overrideAddress.map(_.max).getOrElse(edge.manager.maxAddress))
|
2016-09-13 01:55:29 +02:00
|
|
|
val sizeBits = edge.bundle.sizeBits
|
|
|
|
val dataBits = edge.bundle.dataBits
|
|
|
|
|
|
|
|
// Progress through operations
|
2016-12-16 04:10:53 +01:00
|
|
|
val num_reqs = Reg(init = UInt(nOperations, log2Up(nOperations+1)))
|
|
|
|
val num_resps = Reg(init = UInt(nOperations, log2Up(nOperations+1)))
|
2016-12-08 01:22:05 +01:00
|
|
|
if (nOperations>0) {
|
|
|
|
io.finished := num_resps === UInt(0)
|
|
|
|
} else {
|
|
|
|
io.finished := Bool(false)
|
|
|
|
}
|
2016-09-13 01:55:29 +02:00
|
|
|
|
|
|
|
// Progress within each operation
|
|
|
|
val a = out.a.bits
|
2016-11-14 20:56:48 +01:00
|
|
|
val (a_first, a_last, req_done) = edge.firstlast(out.a)
|
2016-09-13 01:55:29 +02:00
|
|
|
|
|
|
|
val d = out.d.bits
|
2016-11-14 20:56:48 +01:00
|
|
|
val (d_first, d_last, resp_done) = edge.firstlast(out.d)
|
2016-09-13 01:55:29 +02:00
|
|
|
|
|
|
|
// Source ID generation
|
|
|
|
val idMap = Module(new IDMapGenerator(inFlight))
|
|
|
|
val alloc = Queue.irrevocable(idMap.io.alloc, 1, pipe = true)
|
|
|
|
val src = alloc.bits
|
|
|
|
alloc.ready := req_done
|
|
|
|
idMap.io.free.valid := resp_done
|
|
|
|
idMap.io.free.bits := out.d.bits.source
|
|
|
|
|
|
|
|
// Increment random number generation for the following subfields
|
2016-09-10 02:16:35 +02:00
|
|
|
val inc = Wire(Bool())
|
2016-09-13 01:55:29 +02:00
|
|
|
val inc_beat = Wire(Bool())
|
2016-10-06 22:20:13 +02:00
|
|
|
val arth_op_3 = noiseMaker(3, inc, 0)
|
2016-09-21 21:35:57 +02:00
|
|
|
val arth_op = Mux(arth_op_3 > UInt(4), UInt(4), arth_op_3)
|
2016-10-06 22:20:13 +02:00
|
|
|
val log_op = noiseMaker(2, inc, 0)
|
|
|
|
val amo_size = UInt(2) + noiseMaker(1, inc, 0) // word or dword
|
|
|
|
val size = noiseMaker(sizeBits, inc, 0)
|
2017-05-09 20:12:17 +02:00
|
|
|
val rawAddr = noiseMaker(addressBits, inc, 2)
|
|
|
|
val addr = overrideAddress.map(_.legalize(rawAddr)).getOrElse(rawAddr) & ~UIntToOH1(size, addressBits)
|
2016-10-06 22:20:13 +02:00
|
|
|
val mask = noiseMaker(beatBytes, inc_beat, 2) & edge.mask(addr, size)
|
|
|
|
val data = noiseMaker(dataBits, inc_beat, 2)
|
2016-09-13 21:25:57 +02:00
|
|
|
|
|
|
|
// Actually generate specific TL messages when it is legal to do so
|
2016-09-10 02:16:35 +02:00
|
|
|
val (glegal, gbits) = edge.Get(src, addr, size)
|
|
|
|
val (pflegal, pfbits) = if(edge.manager.anySupportPutFull) {
|
|
|
|
edge.Put(src, addr, size, data)
|
|
|
|
} else { (glegal, gbits) }
|
|
|
|
val (pplegal, ppbits) = if(edge.manager.anySupportPutPartial) {
|
2016-09-13 01:55:29 +02:00
|
|
|
edge.Put(src, addr, size, data, mask)
|
2016-09-10 02:16:35 +02:00
|
|
|
} else { (glegal, gbits) }
|
|
|
|
val (alegal, abits) = if(edge.manager.anySupportArithmetic) {
|
|
|
|
edge.Arithmetic(src, addr, size, data, arth_op)
|
|
|
|
} else { (glegal, gbits) }
|
|
|
|
val (llegal, lbits) = if(edge.manager.anySupportLogical) {
|
|
|
|
edge.Logical(src, addr, size, data, log_op)
|
|
|
|
} else { (glegal, gbits) }
|
|
|
|
val (hlegal, hbits) = if(edge.manager.anySupportHint) {
|
|
|
|
edge.Hint(src, addr, size, UInt(0))
|
|
|
|
} else { (glegal, gbits) }
|
|
|
|
|
2016-09-18 02:07:21 +02:00
|
|
|
val legal_dest = edge.manager.containsSafe(addr)
|
|
|
|
|
2016-09-13 21:25:57 +02:00
|
|
|
// Pick a specific message to try to send
|
2016-10-06 22:20:13 +02:00
|
|
|
val a_type_sel = noiseMaker(3, inc, 0)
|
2016-09-10 02:16:35 +02:00
|
|
|
|
2016-09-18 02:07:21 +02:00
|
|
|
val legal = legal_dest && MuxLookup(a_type_sel, glegal, Seq(
|
2016-09-10 02:16:35 +02:00
|
|
|
UInt("b000") -> glegal,
|
2017-02-13 00:18:47 +01:00
|
|
|
UInt("b001") -> (pflegal && !Bool(noModify)),
|
|
|
|
UInt("b010") -> (pplegal && !Bool(noModify)),
|
|
|
|
UInt("b011") -> (alegal && !Bool(noModify)),
|
|
|
|
UInt("b100") -> (llegal && !Bool(noModify)),
|
2016-09-10 02:16:35 +02:00
|
|
|
UInt("b101") -> hlegal))
|
|
|
|
|
|
|
|
val bits = MuxLookup(a_type_sel, gbits, Seq(
|
|
|
|
UInt("b000") -> gbits,
|
|
|
|
UInt("b001") -> pfbits,
|
|
|
|
UInt("b010") -> ppbits,
|
|
|
|
UInt("b011") -> abits,
|
|
|
|
UInt("b100") -> lbits,
|
|
|
|
UInt("b101") -> hbits))
|
|
|
|
|
2016-09-13 21:25:57 +02:00
|
|
|
// Wire both the used and un-used channel signals
|
2016-12-08 01:22:05 +01:00
|
|
|
if (nOperations>0) {
|
|
|
|
out.a.valid := legal && alloc.valid && num_reqs =/= UInt(0)
|
|
|
|
} else {
|
|
|
|
out.a.valid := legal && alloc.valid
|
|
|
|
}
|
2016-09-10 02:16:35 +02:00
|
|
|
out.a.bits := bits
|
|
|
|
out.b.ready := Bool(true)
|
|
|
|
out.c.valid := Bool(false)
|
|
|
|
out.d.ready := Bool(true)
|
|
|
|
out.e.valid := Bool(false)
|
|
|
|
|
2016-09-13 21:25:57 +02:00
|
|
|
// Increment the various progress-tracking states
|
2016-09-13 01:55:29 +02:00
|
|
|
inc := !legal || req_done
|
|
|
|
inc_beat := !legal || out.a.fire()
|
|
|
|
|
2016-12-08 01:22:05 +01:00
|
|
|
if (nOperations>0) {
|
|
|
|
when (out.a.fire() && a_last) {
|
|
|
|
num_reqs := num_reqs - UInt(1)
|
|
|
|
}
|
2016-09-13 01:55:29 +02:00
|
|
|
|
2016-12-08 01:22:05 +01:00
|
|
|
when (out.d.fire() && d_last) {
|
|
|
|
num_resps := num_resps - UInt(1)
|
|
|
|
}
|
2016-09-10 02:16:35 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-29 00:11:05 +02:00
|
|
|
/** Synthesizeable integration test */
|
|
|
|
import unittest._
|
|
|
|
|
2017-05-17 20:56:01 +02:00
|
|
|
class TLFuzzRAM(txns: Int)(implicit p: Parameters) extends LazyModule
|
2016-09-10 02:16:35 +02:00
|
|
|
{
|
2016-10-12 07:32:06 +02:00
|
|
|
val model = LazyModule(new TLRAMModel("TLFuzzRAM"))
|
2016-09-18 01:13:46 +02:00
|
|
|
val ram = LazyModule(new TLRAM(AddressSet(0x800, 0x7ff)))
|
|
|
|
val ram2 = LazyModule(new TLRAM(AddressSet(0, 0x3ff), beatBytes = 16))
|
2016-09-13 06:41:36 +02:00
|
|
|
val gpio = LazyModule(new RRTest1(0x400))
|
2016-09-10 02:16:35 +02:00
|
|
|
val xbar = LazyModule(new TLXbar)
|
2016-09-18 01:13:46 +02:00
|
|
|
val xbar2= LazyModule(new TLXbar)
|
2017-05-17 20:56:01 +02:00
|
|
|
val fuzz = LazyModule(new TLFuzzer(txns))
|
2016-09-14 01:35:06 +02:00
|
|
|
val cross = LazyModule(new TLAsyncCrossing)
|
2016-09-10 02:16:35 +02:00
|
|
|
|
2016-09-13 01:55:29 +02:00
|
|
|
model.node := fuzz.node
|
2016-09-22 02:09:24 +02:00
|
|
|
xbar2.node := TLAtomicAutomata()(model.node)
|
2016-09-23 02:45:42 +02:00
|
|
|
ram2.node := TLFragmenter(16, 256)(xbar2.node)
|
|
|
|
xbar.node := TLWidthWidget(16)(TLHintHandler()(xbar2.node))
|
2016-10-08 08:38:36 +02:00
|
|
|
cross.node := TLFragmenter(4, 256)(TLBuffer()(xbar.node))
|
|
|
|
val monitor = (ram.node := cross.node)
|
2016-09-23 02:45:42 +02:00
|
|
|
gpio.node := TLFragmenter(4, 32)(TLBuffer()(xbar.node))
|
2016-09-10 02:16:35 +02:00
|
|
|
|
|
|
|
lazy val module = new LazyModuleImp(this) with HasUnitTestIO {
|
|
|
|
io.finished := fuzz.module.io.finished
|
2016-09-14 01:35:06 +02:00
|
|
|
|
|
|
|
// Shove the RAM into another clock domain
|
2016-09-29 00:11:05 +02:00
|
|
|
val clocks = Module(new util.Pow2ClockDivider(2))
|
2016-09-14 01:35:06 +02:00
|
|
|
ram.module.clock := clocks.io.clock_out
|
|
|
|
|
|
|
|
// ... and safely cross TL2 into it
|
|
|
|
cross.module.io.in_clock := clock
|
|
|
|
cross.module.io.in_reset := reset
|
|
|
|
cross.module.io.out_clock := clocks.io.clock_out
|
2016-09-22 05:17:32 +02:00
|
|
|
cross.module.io.out_reset := reset
|
2016-09-21 21:08:05 +02:00
|
|
|
|
|
|
|
// Push the Monitor into the right clock domain
|
|
|
|
monitor.foreach { m =>
|
|
|
|
m.module.clock := clocks.io.clock_out
|
|
|
|
m.module.reset := reset
|
|
|
|
}
|
2016-09-10 02:16:35 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-17 20:56:01 +02:00
|
|
|
class TLFuzzRAMTest(txns: Int = 5000, timeout: Int = 500000)(implicit p: Parameters) extends UnitTest(timeout) {
|
|
|
|
val dut = Module(LazyModule(new TLFuzzRAM(txns)).module)
|
2016-09-10 02:16:35 +02:00
|
|
|
io.finished := dut.io.finished
|
|
|
|
}
|