2016-09-14 00:37:29 +02:00
|
|
|
/// See LICENSE for license details.
|
|
|
|
package util
|
|
|
|
|
|
|
|
import Chisel._
|
|
|
|
|
|
|
|
/** Timer with a statically-specified period.
|
|
|
|
* Can take multiple inflight start-stop events with ID
|
|
|
|
* Will continue to count down as long as at least one event is inflight
|
|
|
|
*/
|
|
|
|
class Timer(initCount: Int, maxInflight: Int) extends Module {
|
|
|
|
val io = new Bundle {
|
|
|
|
val start = Valid(UInt(width = log2Up(maxInflight))).flip
|
|
|
|
val stop = Valid(UInt(width = log2Up(maxInflight))).flip
|
|
|
|
val timeout = Valid(UInt(width = log2Up(maxInflight)))
|
|
|
|
}
|
|
|
|
|
|
|
|
val inflight = Reg(init = Vec.fill(maxInflight) { Bool(false) })
|
|
|
|
val countdown = Reg(UInt(width = log2Up(initCount)))
|
|
|
|
val active = inflight.reduce(_ || _)
|
|
|
|
|
2016-09-21 22:05:22 +02:00
|
|
|
when (active) { countdown := countdown - UInt(1) }
|
2016-09-14 00:37:29 +02:00
|
|
|
|
|
|
|
when (io.start.valid) {
|
|
|
|
inflight(io.start.bits) := Bool(true)
|
|
|
|
countdown := UInt(initCount - 1)
|
|
|
|
}
|
2016-09-21 22:05:22 +02:00
|
|
|
|
|
|
|
when (io.stop.valid) { inflight(io.stop.bits) := Bool(false) }
|
2016-09-14 00:37:29 +02:00
|
|
|
|
|
|
|
io.timeout.valid := countdown === UInt(0) && active
|
|
|
|
io.timeout.bits := PriorityEncoder(inflight)
|
|
|
|
|
|
|
|
assert(!io.stop.valid || inflight(io.stop.bits),
|
|
|
|
"Timer stop for transaction that's not inflight")
|
|
|
|
}
|
|
|
|
|
2016-09-21 22:05:22 +02:00
|
|
|
/** Simplified Timer with a statically-specified period.
|
|
|
|
* Can be stopped repeatedly, even when not active.
|
|
|
|
*/
|
|
|
|
class SimpleTimer(initCount: Int) extends Module {
|
|
|
|
val io = new Bundle {
|
|
|
|
val start = Bool(INPUT)
|
|
|
|
val stop = Bool(INPUT)
|
|
|
|
val timeout = Bool(OUTPUT)
|
|
|
|
}
|
|
|
|
|
|
|
|
val countdown = Reg(UInt(width = log2Up(initCount)))
|
|
|
|
val active = Reg(Bool())
|
|
|
|
|
|
|
|
when (active) { countdown := countdown - UInt(1) }
|
|
|
|
|
|
|
|
when (io.start) {
|
|
|
|
active := Bool(true)
|
|
|
|
countdown := UInt(initCount - 1)
|
|
|
|
}
|
|
|
|
|
|
|
|
when (io.stop) { active := Bool(false) }
|
|
|
|
|
|
|
|
io.timeout := countdown === UInt(0) && active
|
|
|
|
}
|
|
|
|
|
|
|
|
object SimpleTimer {
|
2016-09-14 00:37:29 +02:00
|
|
|
def apply(initCount: Int, start: Bool, stop: Bool): Bool = {
|
2016-09-21 22:05:22 +02:00
|
|
|
val timer = Module(new SimpleTimer(initCount))
|
|
|
|
timer.io.start := start
|
|
|
|
timer.io.stop := stop
|
|
|
|
timer.io.timeout
|
2016-09-14 00:37:29 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-21 22:05:22 +02:00
|
|
|
/** Timer with a dynamically-specified period. */
|
2016-09-14 00:37:29 +02:00
|
|
|
class DynamicTimer(w: Int) extends Module {
|
|
|
|
val io = new Bundle {
|
|
|
|
val start = Bool(INPUT)
|
|
|
|
val period = UInt(INPUT, w)
|
|
|
|
val stop = Bool(INPUT)
|
|
|
|
val timeout = Bool(OUTPUT)
|
|
|
|
}
|
|
|
|
|
|
|
|
val countdown = Reg(init = UInt(0, w))
|
|
|
|
val active = Reg(init = Bool(false))
|
|
|
|
|
|
|
|
when (io.start) {
|
|
|
|
countdown := io.period
|
|
|
|
active := Bool(true)
|
|
|
|
} .elsewhen (io.stop || countdown === UInt(0)) {
|
|
|
|
active := Bool(false)
|
|
|
|
} .elsewhen (active) {
|
|
|
|
countdown := countdown - UInt(1)
|
|
|
|
}
|
|
|
|
|
|
|
|
io.timeout := countdown === UInt(0) && active
|
|
|
|
}
|