start constructing composable tilelink unit test drivers
This commit is contained in:
parent
c92732dcaa
commit
9c0fffdd1c
334
groundtest/src/main/scala/unittests/Drivers.scala
Normal file
334
groundtest/src/main/scala/unittests/Drivers.scala
Normal file
@ -0,0 +1,334 @@
|
|||||||
|
package groundtest.unittests
|
||||||
|
|
||||||
|
import Chisel._
|
||||||
|
import junctions._
|
||||||
|
import uncore.tilelink._
|
||||||
|
import uncore.constants._
|
||||||
|
import cde.Parameters
|
||||||
|
|
||||||
|
abstract class Driver(implicit p: Parameters) extends TLModule()(p) {
|
||||||
|
val io = new Bundle {
|
||||||
|
val mem = new ClientUncachedTileLinkIO
|
||||||
|
val start = Bool(INPUT)
|
||||||
|
val finished = Bool(OUTPUT)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that single-beat Gets of decreasing size return subsets of the
|
||||||
|
* data returned by larger Gets
|
||||||
|
*/
|
||||||
|
class GetMultiWidthDriver(implicit p: Parameters) extends Driver()(p) {
|
||||||
|
val s_start :: s_send :: s_recv :: s_done :: Nil = Enum(Bits(), 4)
|
||||||
|
val state = Reg(init = s_start)
|
||||||
|
|
||||||
|
val size = Reg(UInt(width = MT_SZ))
|
||||||
|
val ref = Reg(UInt(width = 64))
|
||||||
|
val bytemask = MuxLookup(size, UInt(0), Seq(
|
||||||
|
MT_D -> UInt("hff"),
|
||||||
|
MT_W -> UInt("h0f"),
|
||||||
|
MT_H -> UInt("h03"),
|
||||||
|
MT_B -> UInt("h01")))
|
||||||
|
val bitmask = FillInterleaved(8, bytemask)
|
||||||
|
|
||||||
|
io.mem.acquire.valid := (state === s_send)
|
||||||
|
io.mem.acquire.bits := Get(
|
||||||
|
client_xact_id = UInt(0),
|
||||||
|
addr_block = UInt(0),
|
||||||
|
addr_beat = UInt(0),
|
||||||
|
addr_byte = UInt(0),
|
||||||
|
operand_size = size,
|
||||||
|
alloc = Bool(false))
|
||||||
|
io.mem.grant.ready := (state === s_recv)
|
||||||
|
|
||||||
|
when (state === s_start && io.start) {
|
||||||
|
size := MT_D
|
||||||
|
state := s_send
|
||||||
|
}
|
||||||
|
|
||||||
|
when (io.mem.acquire.fire()) { state := s_recv }
|
||||||
|
when (io.mem.grant.fire()) {
|
||||||
|
when (size === MT_D) { ref := io.mem.grant.bits.data }
|
||||||
|
size := size - UInt(1)
|
||||||
|
state := Mux(size === MT_B, s_done, s_send)
|
||||||
|
}
|
||||||
|
|
||||||
|
io.finished := state === s_done
|
||||||
|
|
||||||
|
assert(!io.mem.grant.valid || size === MT_D ||
|
||||||
|
(io.mem.grant.bits.data & bitmask) === (ref & bitmask),
|
||||||
|
"GetMultiWidth: smaller get does not match larger get")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that single-beat Gets across a range of memory return
|
||||||
|
* the expected data.
|
||||||
|
* @param expected The values of the data expected to be read.
|
||||||
|
* Each element is the data for one beat.
|
||||||
|
*/
|
||||||
|
class GetSweepDriver(expected: Seq[BigInt])
|
||||||
|
(implicit p: Parameters) extends Driver()(p) {
|
||||||
|
|
||||||
|
val s_start :: s_send :: s_recv :: s_done :: Nil = Enum(Bits(), 4)
|
||||||
|
val state = Reg(init = s_start)
|
||||||
|
|
||||||
|
val nReqs = expected.size
|
||||||
|
val (req_cnt, req_done) = Counter(io.mem.grant.fire(), nReqs)
|
||||||
|
|
||||||
|
when (state === s_start && io.start) { state := s_send }
|
||||||
|
when (io.mem.acquire.fire()) { state := s_recv }
|
||||||
|
when (io.mem.grant.fire()) { state := s_send }
|
||||||
|
when (req_done) { state := s_done }
|
||||||
|
|
||||||
|
val (addr_block, addr_beat) = if (nReqs > tlDataBeats) {
|
||||||
|
(req_cnt(log2Up(nReqs) - 1, tlBeatAddrBits),
|
||||||
|
req_cnt(tlBeatAddrBits - 1, 0))
|
||||||
|
} else {
|
||||||
|
(UInt(0), req_cnt)
|
||||||
|
}
|
||||||
|
|
||||||
|
val exp_data = Vec(expected.map(e => UInt(e, tlDataBits)))
|
||||||
|
|
||||||
|
io.mem.acquire.valid := (state === s_send)
|
||||||
|
io.mem.acquire.bits := Get(
|
||||||
|
client_xact_id = UInt(0),
|
||||||
|
addr_block = addr_block,
|
||||||
|
addr_beat = addr_beat)
|
||||||
|
io.mem.grant.ready := (state === s_recv)
|
||||||
|
io.finished := state === s_done
|
||||||
|
|
||||||
|
assert(!io.mem.grant.valid || io.mem.grant.bits.data === exp_data(req_cnt),
|
||||||
|
"GetSweep: data does not match expected")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that multi-beat GetBlocks across a range of memory return
|
||||||
|
* the expected data.
|
||||||
|
* @param expected The values of the data expected to be read.
|
||||||
|
* Each element is the data for one beat.
|
||||||
|
*/
|
||||||
|
class GetBlockSweepDriver(expected: Seq[BigInt])
|
||||||
|
(implicit p: Parameters) extends Driver()(p) {
|
||||||
|
val s_start :: s_send :: s_recv :: s_done :: Nil = Enum(Bits(), 4)
|
||||||
|
val state = Reg(init = s_start)
|
||||||
|
|
||||||
|
val nReqs = ((expected.size - 1) / tlDataBeats + 1) * tlDataBeats
|
||||||
|
val (req_cnt, req_done) = Counter(io.mem.grant.fire(), nReqs)
|
||||||
|
val (addr_beat, beats_done) = Counter(io.mem.grant.fire(), tlDataBeats)
|
||||||
|
|
||||||
|
val tlBlockOffset = tlByteAddrBits + tlBeatAddrBits
|
||||||
|
val addr_block =
|
||||||
|
if (nReqs > tlDataBeats) req_cnt(log2Up(nReqs) - 1, tlBlockOffset)
|
||||||
|
else UInt(0)
|
||||||
|
|
||||||
|
io.mem.acquire.valid := (state === s_send)
|
||||||
|
io.mem.acquire.bits := GetBlock(
|
||||||
|
client_xact_id = UInt(0),
|
||||||
|
addr_block = addr_block)
|
||||||
|
io.mem.grant.ready := (state === s_recv)
|
||||||
|
io.finished := state === s_done
|
||||||
|
|
||||||
|
when (state === s_start && io.start) { state := s_send }
|
||||||
|
when (io.mem.acquire.fire()) { state := s_recv }
|
||||||
|
when (beats_done) { state := s_send }
|
||||||
|
when (req_done) { state := s_done }
|
||||||
|
|
||||||
|
val exp_data = Vec(expected.map(e => UInt(e, tlDataBits)))
|
||||||
|
|
||||||
|
assert(!io.mem.grant.valid || req_cnt >= UInt(expected.size) ||
|
||||||
|
io.mem.grant.bits.data === exp_data(req_cnt),
|
||||||
|
"GetBlockSweep: data does not match expected")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that single-beat Puts across a range of memory persists correctly.
|
||||||
|
* @param n the number of beats to put
|
||||||
|
*/
|
||||||
|
class PutSweepDriver(val n: Int)(implicit p: Parameters) extends Driver()(p) {
|
||||||
|
val (s_idle :: s_put_req :: s_put_resp ::
|
||||||
|
s_get_req :: s_get_resp :: s_done :: Nil) = Enum(Bits(), 6)
|
||||||
|
val state = Reg(init = s_idle)
|
||||||
|
|
||||||
|
val (put_cnt, put_done) = Counter(state === s_put_resp && io.mem.grant.valid, n)
|
||||||
|
val (get_cnt, get_done) = Counter(state === s_get_resp && io.mem.grant.valid, n)
|
||||||
|
|
||||||
|
val (put_block, put_beat) = if (n > tlDataBeats) {
|
||||||
|
(put_cnt(log2Up(n) - 1, tlBeatAddrBits),
|
||||||
|
put_cnt(tlBeatAddrBits - 1, 0))
|
||||||
|
} else {
|
||||||
|
(UInt(0), put_cnt)
|
||||||
|
}
|
||||||
|
val (get_block, get_beat) = if (n > tlDataBeats) {
|
||||||
|
(get_cnt(log2Up(n) - 1, tlBeatAddrBits),
|
||||||
|
get_cnt(tlBeatAddrBits - 1, 0))
|
||||||
|
} else {
|
||||||
|
(UInt(0), get_cnt)
|
||||||
|
}
|
||||||
|
|
||||||
|
val dataRep = tlDataBits / log2Up(n)
|
||||||
|
val put_data = Fill(dataRep, put_cnt)(tlDataBits - 1, 0)
|
||||||
|
val get_data = Fill(dataRep, get_cnt)(tlDataBits - 1, 0)
|
||||||
|
|
||||||
|
io.mem.acquire.valid := (state === s_put_req) || (state === s_get_req)
|
||||||
|
io.mem.acquire.bits := Mux(state === s_put_req,
|
||||||
|
Put(
|
||||||
|
client_xact_id = UInt(0),
|
||||||
|
addr_block = put_block,
|
||||||
|
addr_beat = put_beat,
|
||||||
|
data = put_data),
|
||||||
|
Get(
|
||||||
|
client_xact_id = UInt(0),
|
||||||
|
addr_block = get_block,
|
||||||
|
addr_beat = get_beat))
|
||||||
|
io.mem.grant.ready := (state === s_put_resp) || (state === s_get_resp)
|
||||||
|
|
||||||
|
when (state === s_idle && io.start) { state := s_put_req }
|
||||||
|
when (state === s_put_req && io.mem.acquire.ready) { state := s_put_resp }
|
||||||
|
when (state === s_put_resp && io.mem.grant.valid) {
|
||||||
|
state := Mux(put_done, s_get_req, s_put_req)
|
||||||
|
}
|
||||||
|
when (state === s_get_req && io.mem.acquire.ready) { state := s_get_resp }
|
||||||
|
when (state === s_get_resp && io.mem.grant.valid) {
|
||||||
|
state := Mux(get_done, s_done, s_get_req)
|
||||||
|
}
|
||||||
|
|
||||||
|
io.finished := (state === s_done)
|
||||||
|
|
||||||
|
assert(!io.mem.grant.valid || !io.mem.grant.bits.hasData() ||
|
||||||
|
io.mem.grant.bits.data === get_data,
|
||||||
|
"PutSweepDriver: data does not match")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that write-masked single-beat puts work correctly by putting
|
||||||
|
* data with steadily smaller write-masks to the same beat.
|
||||||
|
*/
|
||||||
|
class PutMaskDriver(implicit p: Parameters) extends Driver()(p) {
|
||||||
|
val (s_idle :: s_put_req :: s_put_resp ::
|
||||||
|
s_get_req :: s_get_resp :: s_done :: Nil) = Enum(Bits(), 6)
|
||||||
|
val state = Reg(init = s_idle)
|
||||||
|
val nbytes = Reg(UInt(width = log2Up(tlWriteMaskBits) + 1))
|
||||||
|
val wmask = (UInt(1) << nbytes) - UInt(1)
|
||||||
|
val wdata = Fill(tlDataBits / 8, Wire(UInt(width = 8), init = nbytes))
|
||||||
|
val expected = UInt("h0808080804040201")
|
||||||
|
|
||||||
|
when (state === s_idle && io.start) {
|
||||||
|
state := s_put_req
|
||||||
|
nbytes := UInt(8)
|
||||||
|
}
|
||||||
|
when (state === s_put_req && io.mem.acquire.ready) {
|
||||||
|
state := s_put_resp
|
||||||
|
}
|
||||||
|
when (state === s_put_resp && io.mem.grant.valid) {
|
||||||
|
nbytes := nbytes >> UInt(1)
|
||||||
|
state := Mux(nbytes === UInt(1), s_get_req, s_put_req)
|
||||||
|
}
|
||||||
|
when (state === s_get_req && io.mem.acquire.ready) {
|
||||||
|
state := s_get_resp
|
||||||
|
}
|
||||||
|
when (state === s_get_resp && io.mem.grant.valid) {
|
||||||
|
state := s_done
|
||||||
|
}
|
||||||
|
|
||||||
|
io.finished := (state === s_done)
|
||||||
|
io.mem.acquire.valid := (state === s_put_req) || (state === s_get_req)
|
||||||
|
io.mem.acquire.bits := Mux(state === s_put_req,
|
||||||
|
Put(
|
||||||
|
client_xact_id = UInt(0),
|
||||||
|
addr_block = UInt(0),
|
||||||
|
addr_beat = UInt(0),
|
||||||
|
data = wdata,
|
||||||
|
wmask = Some(wmask)),
|
||||||
|
Get(
|
||||||
|
client_xact_id = UInt(0),
|
||||||
|
addr_block = UInt(0),
|
||||||
|
addr_beat = UInt(0)))
|
||||||
|
io.mem.grant.ready := (state === s_put_resp) || (state === s_get_resp)
|
||||||
|
|
||||||
|
assert(!io.mem.grant.valid || state =/= s_get_resp ||
|
||||||
|
io.mem.grant.bits.data === expected,
|
||||||
|
"PutMask: data does not match expected")
|
||||||
|
}
|
||||||
|
|
||||||
|
class PutBlockSweepDriver(val n: Int)(implicit p: Parameters)
|
||||||
|
extends Driver()(p) {
|
||||||
|
val (s_idle :: s_put_req :: s_put_resp ::
|
||||||
|
s_get_req :: s_get_resp :: s_done :: Nil) = Enum(Bits(), 6)
|
||||||
|
val state = Reg(init = s_idle)
|
||||||
|
|
||||||
|
val (put_beat, put_beat_done) = Counter(
|
||||||
|
state === s_put_req && io.mem.acquire.ready, tlDataBeats)
|
||||||
|
val (put_cnt, put_done) = Counter(
|
||||||
|
state === s_put_resp && io.mem.grant.valid, n)
|
||||||
|
val (get_beat, get_beat_done) = Counter(
|
||||||
|
state === s_get_resp && io.mem.grant.valid, tlDataBeats)
|
||||||
|
val (get_cnt, get_done) = Counter(get_beat_done, n)
|
||||||
|
|
||||||
|
val dataRep = tlDataBits / (log2Up(n) + tlBeatAddrBits)
|
||||||
|
val put_data = Fill(dataRep, Cat(put_cnt, put_beat))(tlDataBits - 1, 0)
|
||||||
|
val get_data = Fill(dataRep, Cat(get_cnt, get_beat))(tlDataBits - 1, 0)
|
||||||
|
|
||||||
|
when (state === s_idle && io.start) { state := s_put_req }
|
||||||
|
when (put_beat_done) { state := s_put_resp }
|
||||||
|
when (state === s_put_resp && io.mem.grant.valid) {
|
||||||
|
state := Mux(put_done, s_get_req, s_put_req)
|
||||||
|
}
|
||||||
|
when (state === s_get_req && io.mem.acquire.ready) { state := s_get_resp }
|
||||||
|
when (get_beat_done) { state := Mux(get_done, s_done, s_get_req) }
|
||||||
|
|
||||||
|
val put_acquire = PutBlock(
|
||||||
|
client_xact_id = UInt(0),
|
||||||
|
addr_block = put_cnt,
|
||||||
|
addr_beat = put_beat,
|
||||||
|
data = put_data)
|
||||||
|
|
||||||
|
val get_acquire = GetBlock(
|
||||||
|
client_xact_id = UInt(0),
|
||||||
|
addr_block = get_cnt)
|
||||||
|
|
||||||
|
io.finished := (state === s_done)
|
||||||
|
io.mem.acquire.valid := (state === s_put_req) || (state === s_get_req)
|
||||||
|
io.mem.acquire.bits := Mux(state === s_put_req, put_acquire, get_acquire)
|
||||||
|
io.mem.grant.ready := (state === s_put_resp) || (state === s_get_resp)
|
||||||
|
|
||||||
|
assert(!io.mem.grant.valid || state =/= s_get_resp ||
|
||||||
|
io.mem.grant.bits.data === get_data,
|
||||||
|
"PutBlockSweep: data does not match expected")
|
||||||
|
}
|
||||||
|
|
||||||
|
class DriverSet(driverGen: Parameters => Seq[Driver])(implicit p: Parameters)
|
||||||
|
extends Driver()(p) {
|
||||||
|
val s_start :: s_run :: s_done :: Nil = Enum(Bits(), 3)
|
||||||
|
val state = Reg(init = s_start)
|
||||||
|
|
||||||
|
val drivers = driverGen(p)
|
||||||
|
val idx = Reg(init = UInt(0, log2Up(drivers.size)))
|
||||||
|
val finished = Wire(init = Bool(false))
|
||||||
|
|
||||||
|
when (state === s_start && io.start) { state := s_run }
|
||||||
|
when (state === s_run && finished) {
|
||||||
|
when (idx === UInt(drivers.size - 1)) { state := s_done }
|
||||||
|
idx := idx + UInt(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
io.finished := state === s_done
|
||||||
|
|
||||||
|
io.mem.acquire.valid := Bool(false)
|
||||||
|
io.mem.grant.ready := Bool(false)
|
||||||
|
|
||||||
|
drivers.zipWithIndex.foreach { case (driv, i) =>
|
||||||
|
val me = idx === UInt(i)
|
||||||
|
|
||||||
|
driv.io.start := me && state === s_run
|
||||||
|
driv.io.mem.acquire.ready := io.mem.acquire.ready && me
|
||||||
|
driv.io.mem.grant.valid := io.mem.grant.valid && me
|
||||||
|
driv.io.mem.grant.bits := io.mem.grant.bits
|
||||||
|
|
||||||
|
when (me) {
|
||||||
|
io.mem.acquire.valid := driv.io.mem.acquire.valid
|
||||||
|
io.mem.acquire.bits := driv.io.mem.acquire.bits
|
||||||
|
io.mem.grant.ready := driv.io.mem.grant.ready
|
||||||
|
finished := driv.io.finished
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user