TransposerUnitTest.scala
package gemmini
import chisel3._
import chisel3.iotesters.{ChiselFlatSpec, PeekPokeTester}
import gemmini.TestUtils.{Matrix, consecutive, identity, rand}
// TODO: replace Transposer type parameter with wildcard (with LUB of Data)
class TransposerTester[+C <: Transposer[UInt]](c: C, mats: Seq[Matrix[Int]], dim: Int)
extends PeekPokeTesterC {
val rowsToPush = mats.flatten
val expectedCols = mats.map(_.transpose).flatten
val actualCols = collection.mutable.Buffer.empty[Seq[Int]]
val timeout = 1000
var cycles = 0
def checkTimeout() = {
if (cycles > timeout) {
println("TIMING OUT")
finish
throw new Exception("TIMING OUT")
}
}
reset()
poke(c.io.outCol.ready, 1)
rowsToPush.foreach { row =>
checkTimeout()
poke(c.io.inRow.valid, 1)
row.zipWithIndex.foreach { case(elem, i) =>
poke(c.io.inRow.bits(i), elem)
}
if (peek(c.io.inRow.ready) == 1) {
if (peek(c.io.outCol.valid) == 1) {
actualCols += peek(c.io.outCol.bits).map(.intValue)
}
step(1)
cycles += 1
}
else {
while(peek(c.io.inRow.ready) != 1) {
if (peek(c.io.outCol.valid) == 1) {
actualCols += peek(c.io.outCol.bits).map(.intValue)
}
step(1)
cycles += 1
checkTimeout()
}
step(1)
cycles += 1
}
}
poke(c.io.inRow.valid, 0)
while(peek(c.io.outCol.valid) != 0) {
actualCols += peek(c.io.outCol.bits).map(_.intValue)
step(1)
cycles += 1
checkTimeout()
}
assert(expectedCols == actualCols)
}
class TransposerUnitTest extends ChiselFlatSpec {
val testerArgs = Array(
"--backend-name", "treadle",
"--generate-vcd-output", "on",
"--target-dir", "test_run_dir/transposer",
"--top-name"
)
val dim = 4
behavior of "NaiveTransposer"
it should "transpose one matrix" in {
chisel3.iotesters.Driver.execute(testerArgs :+ "naive_transposer", () => new NaiveTransposer(dim, UInt(8.W))) {
c => new TransposerTester(c, Seq(identity(dim), rand(dim, 255), consecutive(dim)), dim)
} should be (true)
}
behavior of "PipelinedTransposer"
it should "transpose one matrix" in {
chisel3.iotesters.Driver.execute(testerArgs :+ "pipe_transposer", () => new PipelinedTransposer(dim, UInt(8.W))) {
c => new TransposerTester(c, Seq(consecutive(dim), consecutive(dim), consecutive(dim), consecutive(dim), rand(dim, 255)), dim)
} should be (true)
}
}
package gemmini
import chisel3._
import chisel3.iotesters.{ChiselFlatSpec, PeekPokeTester}
import gemmini.TestUtils.{Matrix, consecutive, identity, rand}
// TODO: replace Transposer type parameter with wildcard (with LUB of Data)
//NaiveTransposer是一种简单的转置器实现,它采用了基本的行列交换算法来实现矩阵转置
//PipelinedTransposer是一种优化的转置器实现,它采用了流水线技术来提高转置操作的效率
//使用不同类型和规模的输入矩阵,测试了NaiveTransposer和PipelinedTransposer模块的转置功能
class TransposerTester[+C <: Transposer[UInt]](c: C, mats: Seq[Matrix[Int]], dim: Int)
extends PeekPokeTester[C](c) {
//将一组矩阵序列展平
val rowsToPush = mats.flatten
//将该组矩阵的转置展平
val expectedCols = mats.map(_.transpose).flatten
//创建一个可变缓冲区,用于存储实际生成的数据
val actualCols = collection.mutable.Buffer.empty[Seq[Int]]
val timeout = 1000//时间限制
var cycles = 0//记录进行了多少个周期
//超时抛出异常
def checkTimeout() = {
if (cycles > timeout) {
println("TIMING OUT")
finish
throw new Exception("TIMING OUT")
}
}
//复位,重新接受数据
reset()
poke(c.io.outCol.ready, 1)
//遍历row中的每个元素,并将元素的值elem放入c.io.inRow.bits的对应位置
rowsToPush.foreach { row =>
checkTimeout()
poke(c.io.inRow.valid, 1)
row.zipWithIndex.foreach { case(elem, i) =>
poke(c.io.inRow.bits(i), elem)
}
//检查输出列是否有效如果有效,则将输出列的位值转换为Int并添加到actualCols中。然后调用step函数进行一次时钟周期的仿真,增加cycles计数器的值。
if (peek(c.io.inRow.ready) == 1) {
if (peek(c.io.outCol.valid) == 1) {
actualCols += peek(c.io.outCol.bits).map(_.intValue)
}
step(1)
cycles += 1
}
//输入行不就绪,则进入一个while循环,直到输入行就绪为止
else {
while(peek(c.io.inRow.ready) != 1) {
if (peek(c.io.outCol.valid) == 1) {
actualCols += peek(c.io.outCol.bits).map(_.intValue)
}
step(1)
cycles += 1
checkTimeout()
}
step(1)
cycles += 1
}
}
//所有行都被处理完毕后,将输入行端口的有效性设置为0,然后进入一个while循环,直到输出列端口的valid为0,即等待最后一个输出数据被处理完毕
//(确保在整个流水线中的所有数据都被正确处理和传输)
poke(c.io.inRow.valid, 0)
while(peek(c.io.outCol.valid) != 0) {
actualCols += peek(c.io.outCol.bits).map(_.intValue)
step(1)
cycles += 1
checkTimeout()
}
//比较期望的列数据和实际的列数据是否相等。
assert(expectedCols == actualCols)
}
class TransposerUnitTest extends ChiselFlatSpec {
val testerArgs = Array(
"--backend-name", "treadle",//指定后端,模拟器
"--generate-vcd-output", "on",//打开波形生成
"--target-dir", "test_run_dir/transposer",//输出文件
"--top-name"//顶层模块名称
)
val dim = 4
behavior of "NaiveTransposer"
it should "transpose one matrix" in {
chisel3.iotesters.Driver.execute(testerArgs :+ "naive_transposer", () => new NaiveTransposer(dim, UInt(8.W))) {
c => new TransposerTester(c, Seq(identity(dim), rand(dim, 255), consecutive(dim)), dim)
} should be (true)
}
behavior of "PipelinedTransposer"
it should "transpose one matrix" in {
chisel3.iotesters.Driver.execute(testerArgs :+ "pipe_transposer", () => new PipelinedTransposer(dim, UInt(8.W))) {
c => new TransposerTester(c, Seq(consecutive(dim), consecutive(dim), consecutive(dim), consecutive(dim), rand(dim, 255)), dim)
} should be (true)
}
}