|
楼主 |
发表于 2021-9-8 09:08:21
|
显示全部楼层
import chisel3._
import chisel3.iotesters._
import com.joe.stu.RegFifo
class FIFOTest(dut:RegFifo[UInt]) extends PeekPokeTester (dut){
poke(dut.io.enq.bits.asUInt(),0xab) //为什么要asUnit()??????
poke(dut.io.enq.valid,0) //io.enq端口收到valid无效
poke(dut.io.deq.ready,0) //io.deq端口发出ready无效
var ready = peek(dut.io.enq.ready) //1
var valid = peek(dut.io.deq.valid) //0
step(1) //因为enq.valid=0所以0xab数据无效
var ready1 = peek(dut.io.enq.ready) //1 io.enq.ready := !fullReg
var valid1 = peek(dut.io.deq.valid) // 0 io.deq.valid := !emptyReg
//write one value and expect it on the deq side
poke(dut.io.enq.bits.asUInt(),0x123) //enq的数据输入0x123
poke(dut.io.enq.valid,1) //enq的对面Master发出valid数据有效
step(1) //每个step(1)表示一个时钟上升的到来
//执行到此表示这个上升沿之后的电路
poke(dut.io.enq.bits.asUInt(),0xab) //enq再次收到master发来的数据
poke(dut.io.enq.valid,0) //但enq.valid却是无效指示 下次step(1)之后0xab数据不会存入FIFO
step(12) // 不管多少时钟,enq收到的数据都是无效的,deq应该会发出了deq.valid,但因为deq.ready没有收到指示所以deq.bits不会输出数据
expect(dut.io.enq.ready,1) //只要fifo不满enq就会发出ready准备好接收数据指示
expect(dut.io.deq.valid,1) //只要fifo不空deq就会发valid数据有效指示
expect(dut.io.deq.bits.asUInt(),0x123) //第一个数据是0x123
//read it out
poke(dut.io.deq.ready,1) //deq对面是slave,所以deq的ready是input,deq的valid是output。所以此句ready置1表示slave已准备好接收数据
step(1)
expect(dut.io.deq.valid,0) //前面代码:enq.valid无效则enq不会收新的数据,而deq.valid=1数据有效了,deq.ready=1指示deq可以发数据,所以执行到本行代码时因FIFO是空所以deq.valid为0
poke(dut.io.deq.ready,0) //deq对面的slave不再接收数据了
step(1)
var cnt = 1
poke(dut.io.enq.valid,1) //enq的对面是MASTER,enq.valid是input,表示MASTER发来的数据有效
for(i <- 0 until 12) {
poke(dut.io.enq.bits.asUInt(),cnt.U) //模拟enq对面的MASTER发来的数据
if(peek(dut.io.enq.ready) != 0) { //enq发出ready,表示本enq接口已经将数据接收了 源码中:io.enq.ready := !fullReg
//因为在ChiselFlatSpec的实现类中用的深度是depth=3,所以0 until 12次写数据到FIFO,只能是写3次,后面都full
cnt += 1
}
step(1)
}
println(s"Wrote ${cnt-1} words") //所以显示3
expect(dut.io.enq.ready,0) //enq接收完数据之后ready复位为0吗? 源码中是:io.enq.ready := !fullReg 因depth=3,所以fullReg是满的,当然io.enq.ready不会发出指示了
expect(dut.io.deq.valid,1) //源码中:io.deq.valid := !emptyReg
expect(dut.io.deq.bits.asUInt(),1)//第一次写/读0x123之后读指针readPtr=1,writePtr=1,后面0 until12 多次写不会影响readPtr,但这12次中第一次写时数据是1,writePtr=1,而io.deq.bits:=memReg(readPtr),所以第一个数据1就会
//now read it back
var expected = 1
poke(dut.io.enq.valid,0) //enq的对方即master数据无效
poke(dut.io.deq.ready,1) //deq的对方即slave准备好接收数据
for(i <- 0 until 12) {
if(peek(dut.io.deq.valid) != 0) { //deq.valid为1 (deq发给slave的数据有效) 源码中:不空就valid有效, io.deq.valid :=!emptyReg
expect(dut.io.deq.bits.asUInt(),expected)
expected += 1
}
step(1)
}
//Do the speed test
poke(dut.io.enq.valid,1) //enq的对方master发valid数据有效指示
poke(dut.io.deq.ready,1) //deq的对方slave发ready数据已准备好接好指示
cnt = 0
expect(dut.io.deq.ready,1)
for(i <- 0 until 100) {
poke(dut.io.enq.bits.asUInt(),i.U) //enq端口接收到master发来的新数据
if(peek(dut.io.enq.ready) != 0) { //enq发ready给master说明enq端口已接收好数据 前面已将deq.reaqdy置为1表示slave始终处于接收数据准备好状态,所以enq只要有数据都能发给deq的slave
//其实每次进到这里,mmemReg(writePtr) := io.enq.bits并没有真正执行,只是到下面step(1)发出时钟上升沿之后才是表示真的执行完数据接收完毕
cnt += 1
println(s"cnt=$cnt")
}
step(1)
}
val cycles = 100.0 /cnt //1
println(s"$cnt words in 100 clock cycles,$cycles clock cycles per word")
assert(cycles >= 0.99,"cannot be faster than on clock cycle per word")
}
class FIFOTestSpec extends ChiselFlatSpec {
"FIFOTest" should "pass" in {
iotesters.Driver(()=>new RegFifo(UInt(16.W),3))(t=>new FIFOTest(t)) //注意:测试FIFO的深度是3
}
}
|
|