2015-11-19 05:53:19 +01:00
|
|
|
package groundtest
|
|
|
|
|
|
|
|
import Chisel._
|
|
|
|
|
2016-02-18 21:41:04 +01:00
|
|
|
// ============
|
|
|
|
// Static timer
|
|
|
|
// ============
|
|
|
|
|
|
|
|
// Timer with a statically-specified period.
|
2016-07-01 02:39:10 +02:00
|
|
|
// Can take multiple inflight start-stop events with ID
|
|
|
|
// Will continue to count down so long as at least one inflight event
|
2016-02-18 21:41:04 +01:00
|
|
|
|
2016-07-01 02:39:10 +02:00
|
|
|
class Timer(initCount: Int, maxInflight: Int) extends Module {
|
2015-11-19 05:53:19 +01:00
|
|
|
val io = new Bundle {
|
2016-07-01 02:39:10 +02:00
|
|
|
val start = Valid(UInt(width = log2Up(maxInflight))).flip
|
|
|
|
val stop = Valid(UInt(width = log2Up(maxInflight))).flip
|
2015-11-19 05:53:19 +01:00
|
|
|
val timeout = Bool(OUTPUT)
|
|
|
|
}
|
|
|
|
|
2016-07-01 02:39:10 +02:00
|
|
|
val inflight = Reg(init = Vec.fill(maxInflight) { Bool(false) })
|
2015-11-19 05:53:19 +01:00
|
|
|
val countdown = Reg(UInt(width = log2Up(initCount)))
|
2016-07-01 02:39:10 +02:00
|
|
|
val active = inflight.reduce(_ || _)
|
2015-11-19 05:53:19 +01:00
|
|
|
|
2016-07-01 02:39:10 +02:00
|
|
|
when (active) {
|
|
|
|
countdown := countdown - UInt(1)
|
2015-11-19 05:53:19 +01:00
|
|
|
}
|
2016-07-01 02:39:10 +02:00
|
|
|
|
|
|
|
when (io.start.valid) {
|
|
|
|
inflight(io.start.bits) := Bool(true)
|
|
|
|
countdown := UInt(initCount - 1)
|
2015-11-19 05:53:19 +01:00
|
|
|
}
|
2016-07-01 02:39:10 +02:00
|
|
|
when (io.stop.valid) {
|
|
|
|
inflight(io.stop.bits) := Bool(false)
|
2015-11-19 05:53:19 +01:00
|
|
|
}
|
|
|
|
|
2015-11-19 07:53:50 +01:00
|
|
|
io.timeout := countdown === UInt(0) && active
|
2015-11-19 05:53:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
object Timer {
|
|
|
|
def apply(initCount: Int, start: Bool, stop: Bool): Bool = {
|
2016-07-01 02:39:10 +02:00
|
|
|
val timer = Module(new Timer(initCount, 1))
|
|
|
|
timer.io.start.valid := start
|
|
|
|
timer.io.start.bits := UInt(0)
|
|
|
|
timer.io.stop.valid := stop
|
|
|
|
timer.io.stop.bits := UInt(0)
|
2015-11-19 05:53:19 +01:00
|
|
|
timer.io.timeout
|
|
|
|
}
|
|
|
|
}
|
2016-02-18 21:41:04 +01:00
|
|
|
|
|
|
|
// =============
|
|
|
|
// Dynamic timer
|
|
|
|
// =============
|
|
|
|
|
|
|
|
// Timer with a dynamically-settable period.
|
|
|
|
|
2016-07-05 22:50:17 +02:00
|
|
|
class DynamicTimer(w: Int) extends Module {
|
2016-02-18 21:41:04 +01:00
|
|
|
val io = new Bundle {
|
|
|
|
val start = Bool(INPUT)
|
2016-07-05 22:50:17 +02:00
|
|
|
val period = UInt(INPUT, w)
|
2016-02-18 21:41:04 +01:00
|
|
|
val stop = Bool(INPUT)
|
|
|
|
val timeout = Bool(OUTPUT)
|
|
|
|
}
|
|
|
|
|
2016-07-05 22:50:17 +02:00
|
|
|
val countdown = Reg(init = UInt(0, w))
|
2016-02-18 21:41:04 +01:00
|
|
|
val active = Reg(init = Bool(false))
|
|
|
|
|
|
|
|
when (io.start) {
|
|
|
|
countdown := io.period
|
|
|
|
active := Bool(true)
|
|
|
|
}
|
2016-03-10 13:50:03 +01:00
|
|
|
.elsewhen (io.stop) {
|
|
|
|
active := Bool(false)
|
|
|
|
}
|
2016-02-18 21:41:04 +01:00
|
|
|
.elsewhen (active) {
|
|
|
|
countdown := countdown - UInt(1)
|
|
|
|
}
|
|
|
|
|
|
|
|
io.timeout := countdown === UInt(0) && active
|
|
|
|
}
|
|
|
|
|
|
|
|
// ============
|
|
|
|
// LCG16 module
|
|
|
|
// ============
|
|
|
|
|
|
|
|
// A 16-bit psuedo-random generator based on a linear conguential
|
|
|
|
// generator (LCG). The state is stored in an unitialised register.
|
|
|
|
// When using the C++ backend, it is straigtforward to arrange a
|
|
|
|
// random initial value for each uninitialised register, effectively
|
|
|
|
// seeding each LCG16 instance with a different seed.
|
|
|
|
|
|
|
|
class LCG16 extends Module {
|
|
|
|
val io = new Bundle {
|
|
|
|
val out = UInt(OUTPUT, 16)
|
|
|
|
}
|
|
|
|
val state = Reg(UInt(width = 32))
|
|
|
|
state := state * UInt(1103515245, 32) + UInt(12345, 32)
|
|
|
|
io.out := state(30, 15)
|
|
|
|
}
|
|
|
|
|
|
|
|
// ==========
|
|
|
|
// LCG module
|
|
|
|
// ==========
|
|
|
|
|
|
|
|
// An n-bit psuedo-random generator made from many instances of a
|
|
|
|
// 16-bit LCG. Parameter 'width' must be larger than 0.
|
|
|
|
|
2016-07-05 22:50:17 +02:00
|
|
|
class LCG(val w : Int) extends Module {
|
2016-02-18 21:41:04 +01:00
|
|
|
val io = new Bundle {
|
2016-07-05 22:50:17 +02:00
|
|
|
val out = UInt(OUTPUT, w)
|
2016-02-18 21:41:04 +01:00
|
|
|
}
|
2016-07-05 22:50:17 +02:00
|
|
|
require(w > 0)
|
|
|
|
val numLCG16s : Int = (w+15)/16
|
2016-02-18 21:41:04 +01:00
|
|
|
val outs = List.fill(numLCG16s)(Module(new LCG16()).io.out)
|
2016-07-05 22:50:17 +02:00
|
|
|
io.out := Cat( outs(0)((w%16)-1, 0)
|
2016-02-18 21:41:04 +01:00
|
|
|
, outs.drop(1) : _*)
|
|
|
|
}
|
|
|
|
|
|
|
|
// ======================
|
|
|
|
// Frequency distribution
|
|
|
|
// ======================
|
|
|
|
|
|
|
|
// Given a list of (frequency, value) pairs, return a random value
|
|
|
|
// according to the frequency distribution. The sum of the
|
|
|
|
// frequencies in the distribution must be a power of two.
|
|
|
|
|
|
|
|
object Frequency {
|
|
|
|
def apply(dist : List[(Int, Bits)]) : Bits = {
|
|
|
|
// Distribution must be non-empty
|
|
|
|
require(dist.length > 0)
|
|
|
|
|
|
|
|
// Require that the frequencies sum to a power of two
|
|
|
|
val (freqs, vals) = dist.unzip
|
|
|
|
val total = freqs.sum
|
|
|
|
require(isPow2(total))
|
|
|
|
|
|
|
|
// First item in the distribution
|
|
|
|
val (firstFreq, firstVal) = dist.head
|
|
|
|
|
|
|
|
// Result wire
|
|
|
|
val result = Wire(Bits(width = firstVal.getWidth))
|
|
|
|
result := UInt(0)
|
|
|
|
|
|
|
|
// Random value
|
|
|
|
val randVal = Module(new LCG(log2Up(total))).io.out
|
|
|
|
|
|
|
|
// Pick return value
|
|
|
|
var count = firstFreq
|
|
|
|
var select = when (randVal < UInt(firstFreq)) { result := firstVal }
|
|
|
|
for (p <- dist.drop(1)) {
|
|
|
|
count = count + p._1
|
|
|
|
select = select.elsewhen(randVal < UInt(count)) { result := p._2 }
|
|
|
|
}
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
}
|
2016-07-12 01:41:55 +02:00
|
|
|
|
|
|
|
object ValidMux {
|
|
|
|
def apply[T <: Data](v1: ValidIO[T], v2: ValidIO[T]*): ValidIO[T] = {
|
|
|
|
apply(v1 +: v2.toSeq)
|
|
|
|
}
|
|
|
|
def apply[T <: Data](valids: Seq[ValidIO[T]]): ValidIO[T] = {
|
|
|
|
val out = Wire(Valid(valids.head.bits))
|
|
|
|
out.valid := valids.map(_.valid).reduce(_ || _)
|
|
|
|
out.bits := MuxCase(valids.head.bits,
|
|
|
|
valids.map(v => (v.valid -> v.bits)))
|
|
|
|
out
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
object DebugCombiner {
|
|
|
|
def apply(debugs: Seq[GroundTestStatus]): GroundTestStatus = {
|
|
|
|
val out = Wire(new GroundTestStatus)
|
|
|
|
out.finished := debugs.map(_.finished).reduce(_ || _)
|
|
|
|
out.timeout := ValidMux(debugs.map(_.timeout))
|
|
|
|
out.error := ValidMux(debugs.map(_.error))
|
|
|
|
out
|
|
|
|
}
|
|
|
|
}
|