1
0

First cut at refactoring unittests into a top-level utility. Individual tests co-located with their DUT. No functional changes.

This commit is contained in:
Henry Cook
2016-09-13 15:37:29 -07:00
committed by Howard Mao
parent dfd6bfb454
commit 7dd4492abb
24 changed files with 353 additions and 364 deletions

View File

@ -0,0 +1,158 @@
package junctions
import Chisel._
import unittest.UnitTest
class MultiWidthFifo(inW: Int, outW: Int, n: Int) extends Module {
val io = new Bundle {
val in = Decoupled(Bits(width = inW)).flip
val out = Decoupled(Bits(width = outW))
val count = UInt(OUTPUT, log2Up(n + 1))
}
if (inW == outW) {
val q = Module(new Queue(Bits(width = inW), n))
q.io.enq <> io.in
io.out <> q.io.deq
io.count := q.io.count
} else if (inW > outW) {
val nBeats = inW / outW
require(inW % outW == 0, s"MultiWidthFifo: in: $inW not divisible by out: $outW")
require(n % nBeats == 0, s"Cannot store $n output words when output beats is $nBeats")
val wdata = Reg(Vec(n / nBeats, Bits(width = inW)))
val rdata = Vec(wdata.flatMap { indat =>
(0 until nBeats).map(i => indat(outW * (i + 1) - 1, outW * i)) })
val head = Reg(init = UInt(0, log2Up(n / nBeats)))
val tail = Reg(init = UInt(0, log2Up(n)))
val size = Reg(init = UInt(0, log2Up(n + 1)))
when (io.in.fire()) {
wdata(head) := io.in.bits
head := head + UInt(1)
}
when (io.out.fire()) { tail := tail + UInt(1) }
size := MuxCase(size, Seq(
(io.in.fire() && io.out.fire()) -> (size + UInt(nBeats - 1)),
io.in.fire() -> (size + UInt(nBeats)),
io.out.fire() -> (size - UInt(1))))
io.out.valid := size > UInt(0)
io.out.bits := rdata(tail)
io.in.ready := size < UInt(n)
io.count := size
} else {
val nBeats = outW / inW
require(outW % inW == 0, s"MultiWidthFifo: out: $outW not divisible by in: $inW")
val wdata = Reg(Vec(n * nBeats, Bits(width = inW)))
val rdata = Vec.tabulate(n) { i =>
Cat(wdata.slice(i * nBeats, (i + 1) * nBeats).reverse)}
val head = Reg(init = UInt(0, log2Up(n * nBeats)))
val tail = Reg(init = UInt(0, log2Up(n)))
val size = Reg(init = UInt(0, log2Up(n * nBeats + 1)))
when (io.in.fire()) {
wdata(head) := io.in.bits
head := head + UInt(1)
}
when (io.out.fire()) { tail := tail + UInt(1) }
size := MuxCase(size, Seq(
(io.in.fire() && io.out.fire()) -> (size - UInt(nBeats - 1)),
io.in.fire() -> (size + UInt(1)),
io.out.fire() -> (size - UInt(nBeats))))
io.count := size >> UInt(log2Up(nBeats))
io.out.valid := io.count > UInt(0)
io.out.bits := rdata(tail)
io.in.ready := size < UInt(n * nBeats)
}
}
class MultiWidthFifoTest extends UnitTest {
val big2little = Module(new MultiWidthFifo(16, 8, 8))
val little2big = Module(new MultiWidthFifo(8, 16, 4))
val bl_send = Reg(init = Bool(false))
val lb_send = Reg(init = Bool(false))
val bl_recv = Reg(init = Bool(false))
val lb_recv = Reg(init = Bool(false))
val bl_finished = Reg(init = Bool(false))
val lb_finished = Reg(init = Bool(false))
val bl_data = Vec.tabulate(4){i => UInt((2 * i + 1) * 256 + 2 * i, 16)}
val lb_data = Vec.tabulate(8){i => UInt(i, 8)}
val (bl_send_cnt, bl_send_done) = Counter(big2little.io.in.fire(), 4)
val (lb_send_cnt, lb_send_done) = Counter(little2big.io.in.fire(), 8)
val (bl_recv_cnt, bl_recv_done) = Counter(big2little.io.out.fire(), 8)
val (lb_recv_cnt, lb_recv_done) = Counter(little2big.io.out.fire(), 4)
big2little.io.in.valid := bl_send
big2little.io.in.bits := bl_data(bl_send_cnt)
big2little.io.out.ready := bl_recv
little2big.io.in.valid := lb_send
little2big.io.in.bits := lb_data(lb_send_cnt)
little2big.io.out.ready := lb_recv
val bl_recv_data_idx = bl_recv_cnt >> UInt(1)
val bl_recv_data = Mux(bl_recv_cnt(0),
bl_data(bl_recv_data_idx)(15, 8),
bl_data(bl_recv_data_idx)(7, 0))
val lb_recv_data = Cat(
lb_data(Cat(lb_recv_cnt, UInt(1, 1))),
lb_data(Cat(lb_recv_cnt, UInt(0, 1))))
when (io.start) {
bl_send := Bool(true)
lb_send := Bool(true)
}
when (bl_send_done) {
bl_send := Bool(false)
bl_recv := Bool(true)
}
when (lb_send_done) {
lb_send := Bool(false)
lb_recv := Bool(true)
}
when (bl_recv_done) {
bl_recv := Bool(false)
bl_finished := Bool(true)
}
when (lb_recv_done) {
lb_recv := Bool(false)
lb_finished := Bool(true)
}
io.finished := bl_finished && lb_finished
val bl_start_recv = Reg(next = bl_send_done)
val lb_start_recv = Reg(next = lb_send_done)
assert(!little2big.io.out.valid || little2big.io.out.bits === lb_recv_data,
"Little to Big data mismatch")
assert(!big2little.io.out.valid || big2little.io.out.bits === bl_recv_data,
"Bit to Little data mismatch")
assert(!lb_start_recv || little2big.io.count === UInt(4),
"Little to Big count incorrect")
assert(!bl_start_recv || big2little.io.count === UInt(8),
"Big to Little count incorrect")
}

View File

@ -1,8 +1,6 @@
package junctions.unittests
package junctions
import Chisel._
import junctions._
import junctions.NastiConstants._
import cde.Parameters
class NastiDemuxDriver(n: Int)(implicit p: Parameters) extends Module {
@ -93,7 +91,7 @@ class NastiDemuxSlave(implicit p: Parameters) extends NastiModule()(p) {
io.r.bits := NastiReadDataChannel(id = id, data = value)
}
class NastiMemoryDemuxTest(implicit p: Parameters) extends UnitTest {
class NastiMemoryDemuxTest(implicit p: Parameters) extends unittest.UnitTest {
val nSlaves = 4
val driver = Module(new NastiDemuxDriver(nSlaves))

View File

@ -1,8 +1,6 @@
package junctions.unittests
package junctions
import Chisel._
import junctions._
import junctions.NastiConstants._
import cde.Parameters
class NastiDriver(dataWidth: Int, burstLen: Int, nBursts: Int)
@ -76,16 +74,3 @@ class NastiDriver(dataWidth: Int, burstLen: Int, nBursts: Int)
assert(!io.nasti.r.valid || read_data === expected_data,
s"NastiDriver got wrong data")
}
class HastiTest(implicit p: Parameters) extends UnitTest {
val sram = Module(new HastiTestSRAM(8))
val bus = Module(new HastiBus(Seq(a => Bool(true))))
val conv = Module(new HastiMasterIONastiIOConverter)
val driver = Module(new NastiDriver(32, 8, 2))
bus.io.slaves(0) <> sram.io
bus.io.master <> conv.io.hasti
conv.io.nasti <> driver.io.nasti
io.finished := driver.io.finished
driver.io.start := io.start
}

View File

@ -2,6 +2,7 @@ package junctions
import Chisel._
import cde.{Parameters, Field}
import unittest.UnitTest
object HastiConstants
{
@ -547,3 +548,16 @@ class HastiTestSRAM(depth: Int)(implicit p: Parameters) extends HastiModule()(p)
io.hready := ready
io.hresp := HRESP_OKAY
}
class HastiTest(implicit p: Parameters) extends UnitTest {
val sram = Module(new HastiTestSRAM(8))
val bus = Module(new HastiBus(Seq(a => Bool(true))))
val conv = Module(new HastiMasterIONastiIOConverter)
val driver = Module(new NastiDriver(32, 8, 2))
bus.io.slaves(0) <> sram.io
bus.io.master <> conv.io.hasti
conv.io.nasti <> driver.io.nasti
io.finished := driver.io.finished
driver.io.start := io.start
}

View File

@ -1,85 +0,0 @@
package junctions.unittests
import Chisel._
import junctions._
import junctions.NastiConstants._
class MultiWidthFifoTest extends UnitTest {
val big2little = Module(new MultiWidthFifo(16, 8, 8))
val little2big = Module(new MultiWidthFifo(8, 16, 4))
val bl_send = Reg(init = Bool(false))
val lb_send = Reg(init = Bool(false))
val bl_recv = Reg(init = Bool(false))
val lb_recv = Reg(init = Bool(false))
val bl_finished = Reg(init = Bool(false))
val lb_finished = Reg(init = Bool(false))
val bl_data = Vec.tabulate(4){i => UInt((2 * i + 1) * 256 + 2 * i, 16)}
val lb_data = Vec.tabulate(8){i => UInt(i, 8)}
val (bl_send_cnt, bl_send_done) = Counter(big2little.io.in.fire(), 4)
val (lb_send_cnt, lb_send_done) = Counter(little2big.io.in.fire(), 8)
val (bl_recv_cnt, bl_recv_done) = Counter(big2little.io.out.fire(), 8)
val (lb_recv_cnt, lb_recv_done) = Counter(little2big.io.out.fire(), 4)
big2little.io.in.valid := bl_send
big2little.io.in.bits := bl_data(bl_send_cnt)
big2little.io.out.ready := bl_recv
little2big.io.in.valid := lb_send
little2big.io.in.bits := lb_data(lb_send_cnt)
little2big.io.out.ready := lb_recv
val bl_recv_data_idx = bl_recv_cnt >> UInt(1)
val bl_recv_data = Mux(bl_recv_cnt(0),
bl_data(bl_recv_data_idx)(15, 8),
bl_data(bl_recv_data_idx)(7, 0))
val lb_recv_data = Cat(
lb_data(Cat(lb_recv_cnt, UInt(1, 1))),
lb_data(Cat(lb_recv_cnt, UInt(0, 1))))
when (io.start) {
bl_send := Bool(true)
lb_send := Bool(true)
}
when (bl_send_done) {
bl_send := Bool(false)
bl_recv := Bool(true)
}
when (lb_send_done) {
lb_send := Bool(false)
lb_recv := Bool(true)
}
when (bl_recv_done) {
bl_recv := Bool(false)
bl_finished := Bool(true)
}
when (lb_recv_done) {
lb_recv := Bool(false)
lb_finished := Bool(true)
}
io.finished := bl_finished && lb_finished
val bl_start_recv = Reg(next = bl_send_done)
val lb_start_recv = Reg(next = lb_send_done)
assert(!little2big.io.out.valid || little2big.io.out.bits === lb_recv_data,
"Little to Big data mismatch")
assert(!big2little.io.out.valid || big2little.io.out.bits === bl_recv_data,
"Bit to Little data mismatch")
assert(!lb_start_recv || little2big.io.count === UInt(4),
"Little to Big count incorrect")
assert(!bl_start_recv || big2little.io.count === UInt(8),
"Big to Little count incorrect")
}

View File

@ -1,66 +0,0 @@
package junctions.unittests
import Chisel._
import junctions._
import cde.{Field, Parameters}
trait HasUnitTestIO {
val io = new Bundle {
val finished = Bool(OUTPUT)
val start = Bool(INPUT)
}
}
abstract class UnitTest extends Module with HasUnitTestIO {
when (io.start) {
printf(s"Started UnitTest ${this.getClass.getSimpleName}\n")
}
}
case object UnitTests extends Field[Parameters => Seq[UnitTest]]
class UnitTestSuite(implicit p: Parameters) extends Module {
val io = new Bundle {
val finished = Bool(OUTPUT)
}
val tests = p(UnitTests)(p)
val s_idle :: s_start :: s_wait :: s_done :: Nil = Enum(Bits(), 4)
val state = Reg(init = s_idle)
val test_idx = Reg(init = UInt(0, log2Up(tests.size)))
val test_finished = Vec(tests.map(_.io.finished))
when (state === s_idle) { state := s_start }
when (state === s_start) { state := s_wait }
when (state === s_wait && test_finished(test_idx)) {
state := s_start
test_idx := test_idx + UInt(1)
state := Mux(test_idx === UInt(tests.size - 1), s_done, s_start)
}
val timer = Module(new Timer(500000, tests.size))
timer.io.start.valid := Bool(false)
timer.io.stop.valid := Bool(false)
tests.zipWithIndex.foreach { case (mod, i) =>
mod.io.start := (state === s_start) && test_idx === UInt(i)
when (test_idx === UInt(i)) {
timer.io.start.valid := mod.io.start
timer.io.start.bits := UInt(i)
timer.io.stop.valid := mod.io.finished
timer.io.stop.bits := UInt(i)
}
}
io.finished := (state === s_done)
assert(!timer.io.timeout.valid, "UnitTest timed out")
}
object JunctionsUnitTests {
def apply(implicit p: Parameters): Seq[UnitTest] =
Seq(
Module(new MultiWidthFifoTest),
Module(new NastiMemoryDemuxTest),
Module(new HastiTest))
}

View File

@ -244,128 +244,3 @@ class DecoupledHelper(val rvs: Seq[Bool]) {
(rvs.filter(_ ne exclude) ++ includes).reduce(_ && _)
}
}
class MultiWidthFifo(inW: Int, outW: Int, n: Int) extends Module {
val io = new Bundle {
val in = Decoupled(Bits(width = inW)).flip
val out = Decoupled(Bits(width = outW))
val count = UInt(OUTPUT, log2Up(n + 1))
}
if (inW == outW) {
val q = Module(new Queue(Bits(width = inW), n))
q.io.enq <> io.in
io.out <> q.io.deq
io.count := q.io.count
} else if (inW > outW) {
val nBeats = inW / outW
require(inW % outW == 0, s"MultiWidthFifo: in: $inW not divisible by out: $outW")
require(n % nBeats == 0, s"Cannot store $n output words when output beats is $nBeats")
val wdata = Reg(Vec(n / nBeats, Bits(width = inW)))
val rdata = Vec(wdata.flatMap { indat =>
(0 until nBeats).map(i => indat(outW * (i + 1) - 1, outW * i)) })
val head = Reg(init = UInt(0, log2Up(n / nBeats)))
val tail = Reg(init = UInt(0, log2Up(n)))
val size = Reg(init = UInt(0, log2Up(n + 1)))
when (io.in.fire()) {
wdata(head) := io.in.bits
head := head + UInt(1)
}
when (io.out.fire()) { tail := tail + UInt(1) }
size := MuxCase(size, Seq(
(io.in.fire() && io.out.fire()) -> (size + UInt(nBeats - 1)),
io.in.fire() -> (size + UInt(nBeats)),
io.out.fire() -> (size - UInt(1))))
io.out.valid := size > UInt(0)
io.out.bits := rdata(tail)
io.in.ready := size < UInt(n)
io.count := size
} else {
val nBeats = outW / inW
require(outW % inW == 0, s"MultiWidthFifo: out: $outW not divisible by in: $inW")
val wdata = Reg(Vec(n * nBeats, Bits(width = inW)))
val rdata = Vec.tabulate(n) { i =>
Cat(wdata.slice(i * nBeats, (i + 1) * nBeats).reverse)}
val head = Reg(init = UInt(0, log2Up(n * nBeats)))
val tail = Reg(init = UInt(0, log2Up(n)))
val size = Reg(init = UInt(0, log2Up(n * nBeats + 1)))
when (io.in.fire()) {
wdata(head) := io.in.bits
head := head + UInt(1)
}
when (io.out.fire()) { tail := tail + UInt(1) }
size := MuxCase(size, Seq(
(io.in.fire() && io.out.fire()) -> (size - UInt(nBeats - 1)),
io.in.fire() -> (size + UInt(1)),
io.out.fire() -> (size - UInt(nBeats))))
io.count := size >> UInt(log2Up(nBeats))
io.out.valid := io.count > UInt(0)
io.out.bits := rdata(tail)
io.in.ready := size < UInt(n * nBeats)
}
}
// ============
// Static timer
// ============
// 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(_ || _)
when (active) {
countdown := countdown - UInt(1)
}
when (io.start.valid) {
inflight(io.start.bits) := Bool(true)
countdown := UInt(initCount - 1)
}
when (io.stop.valid) {
inflight(io.stop.bits) := Bool(false)
}
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")
}
object Timer {
def apply(initCount: Int, start: Bool, stop: Bool): Bool = {
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)
timer.io.timeout.valid
}
}