Commit f0013921 authored by Jens Korinth's avatar Jens Korinth
Browse files

Add signal generator from separate package

* separate package for SignalGenerator can be removed
* unit test included
parent 5adfb62d
package chisel.miscutils
import Chisel._
sealed case class Signal(value: Boolean, periods: Int = 1) extends Ordered[Signal] {
import scala.math.Ordered.orderingToOrdered
def compare(that: Signal): Int = periods compare that.periods
}
object SignalGenerator {
type Waveform = List[Signal]
implicit def makeSignal(sd: (Boolean, Int)): Signal = Signal(sd._1, sd._2)
implicit def makeWaveform(ls: List[(Boolean, Int)]): Waveform = ls map makeSignal
}
class SignalGenerator(signals: SignalGenerator.Waveform, useInputAsClock: Boolean = false) extends Module {
require (signals.length > 0, "Waveform must not be empty.")
require (signals map (_.periods > 1) reduce (_&&_),
"All signals must have at least two clock cycles length.")
val io = new Bundle { val v = Bool(OUTPUT); val in = Bool(INPUT) }
val cnts_rom = Vec(signals map (n => UInt(n.periods - 1)))
val vals_rom = Vec(signals map (n => Bool(n.value)))
val cnt = Reg(UInt(width = log2Up(signals.max.periods)))
val curr_idx = Reg(UInt(width = log2Up(signals.length)))
val vreg = Reg(Bool())
io.v := vreg
when (reset) {
curr_idx := UInt(0)
cnt := cnts_rom(0)
vreg := UInt(0)
}
.otherwise {
vreg := vals_rom(curr_idx)
// trigger on either clock or pos input edge
when (if (useInputAsClock) io.in && !RegNext(io.in) else Bool(true)) {
when (cnt === UInt(0)) {
val next_idx = Mux(curr_idx < UInt(signals.length - 1), curr_idx + UInt(1), UInt(0))
curr_idx := next_idx
cnt := cnts_rom(next_idx)
}
.otherwise {
cnt := cnt - UInt(1)
}
}
}
}
package chisel.miscutils
import Chisel._
import SignalGenerator._
import org.scalatest.junit.JUnitSuite
import org.junit.Test
import org.junit.Assert._
class SignalGeneratorComposition1 extends Module {
val waveform: SignalGenerator.Waveform =
(for (i <- 2 until 30) yield List((false, 5), (true, i))) reduce (_++_)
val clock_sg = Module(new SignalGenerator(List((true, 2), (false, 2))))
val test_sg = Module(new SignalGenerator(waveform, true))
val io = new Bundle { val v = Bool(OUTPUT) }
test_sg.io.in := clock_sg.io.v
io.v := test_sg.io.v
}
class SignalGeneratorSuite extends JUnitSuite {
@Test def test1 {
val waveform: SignalGenerator.Waveform =
(for (i <- 2 until 30) yield List((false, 5), (true, i))) reduce (_++_)
chiselMainTest(Array("--genHarness", "--backend", "c", "--vcd", "--targetDir", "test/signalgenerator", "--compile", "--test"), () =>
Module(new SignalGenerator(waveform))
) { m => new SignalGeneratorTest(m) }
}
@Test def test2 { // same as test1, but with user supplied clock
chiselMainTest(Array("--genHarness", "--backend", "c", "--vcd", "--targetDir", "test/signalgenerator", "--compile", "--test"), () =>
Module(new SignalGeneratorComposition1)
) { m => new SignalGeneratorComposition1Test(m) }
}
}
class SignalGeneratorTest(sg: SignalGenerator) extends Tester(sg, false) {
import scala.util.Properties.{lineSeparator => NL}
private var cc = 0
// re-define step to output progress info
override def step(n: Int) {
super.step(n)
cc += n
if (cc % 1000 == 0) println("clock cycle: " + cc)
}
// waits for next positive edge on signal
def waitForPosEdge[T <: Chisel.Bits](s: T) {
while(peek(s) > 0) step(1)
while(peek(s) == 0) step(1)
}
// waits for next positive edge on signal
def waitForNegEdge[T <: Chisel.Bits](s: T) {
while(peek(s) == 0) step(1)
while(peek(s) > 0) step(1)
}
// the actual test: wait until reset is off
waitForNegEdge(sg.reset)
for (j <- 0 to 1) {
for (i <- 2 until 30) {
waitForPosEdge(sg.io.v)
val cc_start = cc
waitForNegEdge(sg.io.v)
assertTrue (cc - cc_start == i)
}
}
}
class SignalGeneratorComposition1Test(sg: SignalGeneratorComposition1) extends Tester(sg, false) {
private var cc = 0
// re-define step to output progress info
override def step(n: Int) {
super.step(n)
cc += n
if (cc % 1000 == 0) println("clock cycle: " + cc)
}
// waits for next positive edge on signal
def waitForPosEdge[T <: Chisel.Bits](s: T) {
while(peek(s) > 0) step(1)
while(peek(s) == 0) step(1)
}
// waits for next positive edge on signal
def waitForNegEdge[T <: Chisel.Bits](s: T) {
while(peek(s) == 0) step(1)
while(peek(s) > 0) step(1)
}
// the actual test: wait until reset is off
waitForNegEdge(sg.reset)
for (j <- 0 to 1) {
for (i <- 2 until 30) {
waitForPosEdge(sg.io.v)
val cc_start = cc
waitForNegEdge(sg.io.v)
assertTrue (cc - cc_start == i * 4)
}
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment