//Compile the simulator
val compiled = SimConfig.withWave.allOptimisation.compile(
rtl = new StreamFifoCC(
dataType = Bits(32 bits),
depth = 32,
pushClock = ClockDomain.external("clkA"),
popClock = ClockDomain.external("clkB")
)
)
//Run the simulation
compiled.doSimUntilVoid{dut =>
val queueModel = mutable.Queue[Long]()
//Fork a thread to manage the clock domains signals
val clocksThread = fork{
//Clear clock domains signals, to be sure the simulation capture their first edge.
dut.pushClock.fallingEdge()
dut.popClock.fallingEdge()
dut.pushClock.disassertReset()
dut.popClock.disassertReset()
sleep(0)
//Do the resets
dut.pushClock.assertReset()
dut.popClock.assertReset()
sleep(10)
dut.pushClock.disassertReset()
dut.popClock.disassertReset()
sleep(1)
//Forever, randomly toggle one of the clocks (will create asynchronous clocks without fixed frequencies)
while(true){
if(Random.nextBoolean()) {
dut.pushClock.clockToggle()
} else {
dut.popClock.clockToggle()
}
sleep(1)
}
}
//Push data randomly and fill the queueModel with pushed transactions
val pushThread = fork{
while(true){
dut.io.push.valid.randomize()
dut.io.push.payload.randomize()
dut.pushClock.waitSampling()
if(dut.io.push.valid.toBoolean && dut.io.push.ready.toBoolean){
queueModel.enqueue(dut.io.push.payload.toLong)
}
}
}
//Pop data randomly and check that it match with the queueModel
val popThread = fork{
for(i <- 0 until 100000){
dut.io.pop.ready.randomize()
dut.popClock.waitSampling()
if(dut.io.pop.valid.toBoolean && dut.io.pop.ready.toBoolean){
assert(dut.io.pop.payload.toLong == queueModel.dequeue())
}
}
simSuccess()
}
}