-
Notifications
You must be signed in to change notification settings - Fork 50
Using the PeekPokeTester
This will be a brief walk-through of the PeekPokeTester. We will look at the src/test/scala/examples/GCDSpec.scala example.
import chisel3._
import chisel3.util._
import chisel3.iotesters._
import org.scalatest.{Matchers, FlatSpec}
For the purposes of this discussion we are focused on the IO ports of the circuit or device under test (DUT).
object RealGCD2 {
val num_width = 16
}
class RealGCD2Input extends Bundle {
val a = Bits(width = RealGCD2.num_width)
val b = Bits(width = RealGCD2.num_width)
}
class RealGCD2 extends Module {
val io = new Bundle {
val in = Decoupled(new RealGCD2Input()).flip()
val out = Valid(UInt(width = RealGCD2.num_width))
}
...
The test harness API allows 4 interactions with the DUT
- To set the DUT'S inputs: poke
- To look at the DUT'S outputs: peek
- To test one of the DUT's outputs: expect
- To advance the clock of the DUT: step
The tester is constructed by subclassing PeekPokeTester
class GCDPeekPokeTester(c: RealGCD2) extends PeekPokeTester(c) {
for {
i <- 1 to 10
j <- 1 to 10
} {
val (gcd_value, cycles) = GCDCalculator.computeGcdResultsAndCycles(i, j)
poke(c.io.in.bits.a, i)
poke(c.io.in.bits.b, j)
poke(c.io.in.valid, 1)
var count = 0
while(peek(c.io.out.valid) == BigInt(0) && count < 20) {
step(1)
count += 1
}
if(count > 30) {
println(s"Waited $count cycles on gcd inputs $i, $j, giving up")
System.exit(0)
}
expect(c.io.out.bits, gcd_value)
step(1)
}
}
The GCD test pushes two numbers into the inputs and then checks that the returned GCD value is correct. There is some complexity here in the code that waits for the c.io.out.valid
to become high a sign that the GCD computation is complete.
The test (a subclass of a PeekPokeTester) is now ready to run. The simplest way is to embed the invocation of the test in a scala test.
class GCDSpec extends FlatSpec with Matchers {
behavior of "GCDSpec"
it should "compute gcd excellently" in {
chisel3.iotesters.Driver(() => new RealGCD2) { c =>
new GCDPeekPokeTester(c)
} should be(true)
}
}
The test can now be executed via sbt.
sbt
> test-only examples.GCDSpec
The test-only command will report with much text the result of your actions. The main types of output are
- Success. Everything worked, there is a lot's of output showing the progress of the test and a summary of the result
- Problem in the design. There is some error in the design of your circuit that caused either Chisel or Firrtl to error.
- Problem in the execution of the circuit. The circuit was successfully compiled into a simulatable state, but there is some problem with the execution. Typically this involves some error in the circuit logic, but can also result from an incorrect test with peek or expect.
The full scope of Chisel/Firrtl error reporting is a broad area that we are working hard to provide more materials for. As a simple illustration here. I have introduced a bad connection io.in := 7777.U
at line 40 of GCDSpec.scala.
The error message in this case looks like
[info] - should compute gcd excellently *** FAILED ***
[info] chisel3.internal.ChiselException: cannot connect chisel3.util.DecoupledIO@10 and chisel3.core.UInt@2f
[info] at chisel3.internal.throwException$.apply(Error.scala:13)
[info] at chisel3.core.Data.badConnect(Data.scala:50)
[info] at chisel3.core.Bundle.$less$greater(Aggregate.scala:288)
[info] at chisel3.core.Bundle.$colon$eq(Aggregate.scala:292)
[info] at examples.RealGCD2.<init>(GCDSpec.scala:40)
[info] at examples.GCDSpec$$anonfun$5$$anonfun$apply$mcV$sp$3.apply(GCDSpec.scala:86)
[info] at examples.GCDSpec$$anonfun$5$$anonfun$apply$mcV$sp$3.apply(GCDSpec.scala:86)
[info] at chisel3.core.Module$.do_apply(Module.scala:30)
[info] at chisel3.Driver$$anonfun$elaborate$1.apply(Driver.scala:117)
[info] at chisel3.Driver$$anonfun$elaborate$1.apply(Driver.scala:117)
A good place to start when confronted with an error message like this is to look at the earliest line in your code listed in the stack trace. In this case
[info] at examples.RealGCD2.<init>(GCDSpec.scala:40)
Find and fix the error and try again.