make unit tests local to the packages being tested
This commit is contained in:
163
junctions/src/main/scala/unittests/MiscNastiTests.scala
Normal file
163
junctions/src/main/scala/unittests/MiscNastiTests.scala
Normal file
@ -0,0 +1,163 @@
|
||||
package junctions.unittests
|
||||
|
||||
import Chisel._
|
||||
import junctions._
|
||||
import junctions.NastiConstants._
|
||||
import cde.Parameters
|
||||
|
||||
class NastiDriver(dataWidth: Int, burstLen: Int, nBursts: Int)
|
||||
(implicit p: Parameters) extends NastiModule {
|
||||
val io = new Bundle {
|
||||
val nasti = new NastiIO
|
||||
val finished = Bool(OUTPUT)
|
||||
val start = Bool(INPUT)
|
||||
}
|
||||
|
||||
val dataBytes = dataWidth / 8
|
||||
val nastiDataBytes = nastiXDataBits / 8
|
||||
|
||||
val (write_cnt, write_done) = Counter(io.nasti.w.fire(), burstLen)
|
||||
val (read_cnt, read_done) = Counter(io.nasti.r.fire(), burstLen)
|
||||
val (req_cnt, reqs_done) = Counter(read_done, nBursts)
|
||||
|
||||
val req_addr = Cat(req_cnt, UInt(0, log2Up(burstLen * dataBytes)))
|
||||
|
||||
val write_data = UInt(0x10000000L, dataWidth) | Cat(req_cnt, write_cnt)
|
||||
val expected_data = UInt(0x10000000L, dataWidth) | Cat(req_cnt, read_cnt)
|
||||
|
||||
val (s_idle :: s_write_addr :: s_write_data :: s_write_stall :: s_write_resp ::
|
||||
s_read_addr :: s_read_data :: s_read_stall :: s_done :: Nil) = Enum(Bits(), 9)
|
||||
val state = Reg(init = s_idle)
|
||||
|
||||
val (stall_cnt, stall_done) = Counter(state === s_read_stall, 2)
|
||||
|
||||
io.nasti.aw.valid := (state === s_write_addr)
|
||||
io.nasti.aw.bits := NastiWriteAddressChannel(
|
||||
id = UInt(0),
|
||||
addr = req_addr,
|
||||
size = UInt(log2Up(dataBytes)),
|
||||
len = UInt(burstLen - 1))
|
||||
|
||||
io.nasti.w.valid := (state === s_write_data)
|
||||
io.nasti.w.bits := NastiWriteDataChannel(
|
||||
data = Cat(write_data, write_data),
|
||||
last = (write_cnt === UInt(burstLen - 1)))
|
||||
|
||||
io.nasti.b.ready := (state === s_write_resp)
|
||||
|
||||
io.nasti.ar.valid := (state === s_read_addr)
|
||||
io.nasti.ar.bits := NastiReadAddressChannel(
|
||||
id = UInt(0),
|
||||
addr = req_addr,
|
||||
size = UInt(log2Up(dataBytes)),
|
||||
len = UInt(burstLen - 1))
|
||||
|
||||
io.nasti.r.ready := (state === s_read_data)
|
||||
|
||||
io.finished := (state === s_done)
|
||||
|
||||
when (state === s_idle && io.start) { state := s_write_addr }
|
||||
when (io.nasti.aw.fire()) { state := s_write_data }
|
||||
when (io.nasti.w.fire()) { state := s_write_stall }
|
||||
when (state === s_write_stall) { state := s_write_data }
|
||||
when (write_done) { state := s_write_resp }
|
||||
when (io.nasti.b.fire()) { state := s_read_addr }
|
||||
when (io.nasti.ar.fire()) { state := s_read_data }
|
||||
when (io.nasti.r.fire()) { state := s_read_stall }
|
||||
when (stall_done) { state := s_read_data }
|
||||
when (read_done) { state := s_write_addr }
|
||||
when (reqs_done) { state := s_done }
|
||||
|
||||
val full_addr = req_addr + (read_cnt << UInt(log2Up(dataBytes)))
|
||||
val byteshift = full_addr(log2Up(nastiDataBytes) - 1, 0)
|
||||
val bitshift = Cat(byteshift, UInt(0, 3))
|
||||
val read_data = (io.nasti.r.bits.data >> bitshift) & Fill(dataWidth, UInt(1, 1))
|
||||
|
||||
assert(!io.nasti.r.valid || read_data === expected_data,
|
||||
s"NastiDriver got wrong data")
|
||||
}
|
||||
|
||||
|
||||
class AtosConverterTestBackend(implicit p: Parameters) extends NastiModule()(p) {
|
||||
val io = new Bundle {
|
||||
val nasti = (new NastiIO).flip
|
||||
val finished = Bool(OUTPUT)
|
||||
}
|
||||
|
||||
val (s_waddr :: s_wdata :: s_wresp ::
|
||||
s_raddr :: s_rresp :: s_done :: Nil) = Enum(Bits(), 6)
|
||||
val state = Reg(init = s_waddr)
|
||||
|
||||
val n_words = 4
|
||||
val test_data = Reg(Vec(n_words, UInt(width = nastiXDataBits)))
|
||||
val req_id = Reg(UInt(width = nastiXIdBits))
|
||||
|
||||
val (w_count, w_last) = Counter(io.nasti.w.fire(), n_words)
|
||||
val (r_count, r_last) = Counter(io.nasti.r.fire(), n_words)
|
||||
|
||||
when (io.nasti.aw.fire()) {
|
||||
req_id := io.nasti.aw.bits.id
|
||||
state := s_wdata
|
||||
}
|
||||
when (io.nasti.w.fire()) {
|
||||
test_data(w_count) := io.nasti.w.bits.data
|
||||
when (io.nasti.w.bits.last) { state := s_wresp }
|
||||
}
|
||||
when (io.nasti.b.fire()) { state := s_raddr }
|
||||
when (io.nasti.ar.fire()) {
|
||||
req_id := io.nasti.ar.bits.id
|
||||
state := s_rresp
|
||||
}
|
||||
when (io.nasti.r.fire() && io.nasti.r.bits.last) { state := s_done }
|
||||
|
||||
io.nasti.aw.ready := (state === s_waddr)
|
||||
io.nasti.w.ready := (state === s_wdata)
|
||||
io.nasti.ar.ready := (state === s_raddr)
|
||||
|
||||
io.nasti.b.valid := (state === s_wresp)
|
||||
io.nasti.b.bits := NastiWriteResponseChannel(id = req_id)
|
||||
|
||||
io.nasti.r.valid := (state === s_rresp)
|
||||
io.nasti.r.bits := NastiReadDataChannel(
|
||||
id = req_id,
|
||||
data = test_data(r_count),
|
||||
last = r_last)
|
||||
|
||||
io.finished := (state === s_done)
|
||||
}
|
||||
|
||||
class AtosConverterTest(implicit val p: Parameters) extends UnitTest
|
||||
with HasNastiParameters {
|
||||
val frontend = Module(new NastiDriver(nastiXDataBits, 4, 1))
|
||||
val backend = Module(new AtosConverterTestBackend)
|
||||
|
||||
val serdes = Module(new AtosSerdes(8))
|
||||
val desser = Module(new AtosDesser(8))
|
||||
|
||||
val client_conv = Module(new AtosClientConverter)
|
||||
val manager_conv = Module(new AtosManagerConverter)
|
||||
|
||||
client_conv.io.nasti <> frontend.io.nasti
|
||||
serdes.io.wide <> client_conv.io.atos
|
||||
desser.io.narrow <> serdes.io.narrow
|
||||
manager_conv.io.atos <> desser.io.wide
|
||||
backend.io.nasti <> manager_conv.io.nasti
|
||||
frontend.io.start := io.start
|
||||
|
||||
io.finished := frontend.io.finished && backend.io.finished
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
85
junctions/src/main/scala/unittests/MultiWidthFifoTest.scala
Normal file
85
junctions/src/main/scala/unittests/MultiWidthFifoTest.scala
Normal file
@ -0,0 +1,85 @@
|
||||
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")
|
||||
}
|
||||
|
||||
|
111
junctions/src/main/scala/unittests/NastiDemuxTest.scala
Normal file
111
junctions/src/main/scala/unittests/NastiDemuxTest.scala
Normal file
@ -0,0 +1,111 @@
|
||||
package junctions.unittests
|
||||
|
||||
import Chisel._
|
||||
import junctions._
|
||||
import junctions.NastiConstants._
|
||||
import cde.Parameters
|
||||
|
||||
class NastiDemuxDriver(n: Int)(implicit p: Parameters) extends Module {
|
||||
val io = new Bundle {
|
||||
val start = Bool(INPUT)
|
||||
val finished = Bool(OUTPUT)
|
||||
val nasti = new NastiIO
|
||||
val select = UInt(OUTPUT, log2Up(n))
|
||||
}
|
||||
|
||||
val (s_idle :: s_write_addr :: s_write_data :: s_write_resp ::
|
||||
s_read_addr :: s_read_resp :: s_done :: Nil) = Enum(Bits(), 7)
|
||||
val state = Reg(init = s_idle)
|
||||
|
||||
val select = Reg(init = UInt(0, log2Up(n)))
|
||||
|
||||
when (state === s_idle && io.start) { state := s_write_addr }
|
||||
when (io.nasti.aw.fire()) { state := s_write_data }
|
||||
when (io.nasti.w.fire()) { state := s_write_resp }
|
||||
when (io.nasti.b.fire()) { state := s_read_addr }
|
||||
when (io.nasti.ar.fire()) { state := s_read_resp }
|
||||
when (io.nasti.r.fire()) {
|
||||
when (select === UInt(n - 1)) {
|
||||
state := s_done
|
||||
} .otherwise {
|
||||
select := select + UInt(1)
|
||||
state := s_write_addr
|
||||
}
|
||||
}
|
||||
|
||||
io.nasti.aw.valid := (state === s_write_addr)
|
||||
io.nasti.aw.bits := NastiWriteAddressChannel(
|
||||
id = UInt(0),
|
||||
addr = UInt(0),
|
||||
size = UInt("b011"))
|
||||
io.nasti.w.valid := (state === s_write_data)
|
||||
io.nasti.w.bits := NastiWriteDataChannel(data = select)
|
||||
io.nasti.b.ready := (state === s_write_resp)
|
||||
io.nasti.ar.valid := (state === s_read_addr)
|
||||
io.nasti.ar.bits := NastiReadAddressChannel(
|
||||
id = UInt(0),
|
||||
addr = UInt(0),
|
||||
size = UInt("b011"))
|
||||
io.nasti.r.ready := (state === s_read_resp)
|
||||
|
||||
io.finished := (state === s_done)
|
||||
io.select := select
|
||||
|
||||
assert(!io.nasti.r.valid || io.nasti.r.bits.data === select,
|
||||
"NASTI DeMux test: Read data did not match")
|
||||
}
|
||||
|
||||
class NastiDemuxSlave(implicit p: Parameters) extends NastiModule()(p) {
|
||||
val io = (new NastiIO).flip
|
||||
|
||||
val (s_write_wait :: s_write_data :: s_write_resp ::
|
||||
s_read_wait :: s_read_resp :: s_done :: Nil) = Enum(Bits(), 6)
|
||||
val state = Reg(init = s_write_wait)
|
||||
|
||||
val value = Reg(UInt(width = 64))
|
||||
val id = Reg(UInt(width = nastiXIdBits))
|
||||
|
||||
when (io.aw.fire()) {
|
||||
id := io.aw.bits.id
|
||||
state := s_write_data
|
||||
}
|
||||
|
||||
when (io.w.fire()) {
|
||||
value := io.w.bits.data
|
||||
state := s_write_resp
|
||||
}
|
||||
|
||||
when (io.b.fire()) { state := s_read_wait }
|
||||
|
||||
when (io.ar.fire()) {
|
||||
id := io.ar.bits.id
|
||||
state := s_read_resp
|
||||
}
|
||||
|
||||
when (io.r.fire()) { state := s_done }
|
||||
|
||||
io.aw.ready := (state === s_write_wait)
|
||||
io.w.ready := (state === s_write_data)
|
||||
io.b.valid := (state === s_write_resp)
|
||||
io.b.bits := NastiWriteResponseChannel(id = id)
|
||||
io.ar.ready := (state === s_read_wait)
|
||||
io.r.valid := (state === s_read_resp)
|
||||
io.r.bits := NastiReadDataChannel(id = id, data = value)
|
||||
}
|
||||
|
||||
class NastiMemoryDemuxTest(implicit p: Parameters) extends UnitTest {
|
||||
val nSlaves = 4
|
||||
|
||||
val driver = Module(new NastiDemuxDriver(nSlaves))
|
||||
driver.io.start := io.start
|
||||
io.finished := driver.io.finished
|
||||
|
||||
val demux = Module(new NastiMemoryDemux(nSlaves))
|
||||
demux.io.master <> driver.io.nasti
|
||||
demux.io.select := driver.io.select
|
||||
|
||||
for (i <- 0 until nSlaves) {
|
||||
val slave = Module(new NastiDemuxSlave)
|
||||
slave.io <> demux.io.slaves(i)
|
||||
}
|
||||
}
|
63
junctions/src/main/scala/unittests/UnitTest.scala
Normal file
63
junctions/src/main/scala/unittests/UnitTest.scala
Normal file
@ -0,0 +1,63 @@
|
||||
package junctions.unittests
|
||||
|
||||
import Chisel._
|
||||
import junctions._
|
||||
import cde.{Field, Parameters}
|
||||
|
||||
abstract class UnitTest extends Module {
|
||||
val io = new Bundle {
|
||||
val finished = Bool(OUTPUT)
|
||||
val start = Bool(INPUT)
|
||||
}
|
||||
|
||||
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(1000, tests.size))
|
||||
|
||||
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 AtosConverterTest),
|
||||
Module(new NastiMemoryDemuxTest),
|
||||
Module(new HastiTest))
|
||||
}
|
@ -312,3 +312,54 @@ class MultiWidthFifo(inW: Int, outW: Int, n: Int) extends Module {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user