154 lines
3.5 KiB
Scala
154 lines
3.5 KiB
Scala
package groundtest
|
|
|
|
import Chisel._
|
|
|
|
// ============
|
|
// Static timer
|
|
// ============
|
|
|
|
// Timer with a statically-specified period.
|
|
|
|
class Timer(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(init = Bool(false))
|
|
|
|
when (io.start) {
|
|
countdown := UInt(initCount - 1)
|
|
active := Bool(true)
|
|
}
|
|
|
|
when (io.stop) {
|
|
active := Bool(false)
|
|
}
|
|
|
|
when (active) {
|
|
countdown := countdown - UInt(1)
|
|
}
|
|
|
|
io.timeout := countdown === UInt(0) && active
|
|
}
|
|
|
|
object Timer {
|
|
def apply(initCount: Int, start: Bool, stop: Bool): Bool = {
|
|
val timer = Module(new Timer(initCount))
|
|
timer.io.start := start
|
|
timer.io.stop := stop
|
|
timer.io.timeout
|
|
}
|
|
}
|
|
|
|
// =============
|
|
// Dynamic timer
|
|
// =============
|
|
|
|
// Timer with a dynamically-settable period.
|
|
|
|
class DynamicTimer(width: Int) extends Module {
|
|
val io = new Bundle {
|
|
val start = Bool(INPUT)
|
|
val period = UInt(INPUT, width)
|
|
val stop = Bool(INPUT)
|
|
val timeout = Bool(OUTPUT)
|
|
}
|
|
|
|
val countdown = Reg(init = UInt(0, width))
|
|
val active = Reg(init = Bool(false))
|
|
|
|
when (io.start) {
|
|
countdown := io.period
|
|
active := Bool(true)
|
|
}
|
|
.elsewhen (active) {
|
|
countdown := countdown - UInt(1)
|
|
}
|
|
|
|
when (io.stop) {
|
|
active := Bool(false)
|
|
}
|
|
|
|
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.
|
|
|
|
class LCG(val width : Int) extends Module {
|
|
val io = new Bundle {
|
|
val out = UInt(OUTPUT, width)
|
|
}
|
|
require(width > 0)
|
|
val numLCG16s : Int = (width+15)/16
|
|
val outs = List.fill(numLCG16s)(Module(new LCG16()).io.out)
|
|
io.out := Cat( outs(0)((width%16)-1, 0)
|
|
, 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
|
|
}
|
|
}
|