Debugging with the Interpreter REPL 1 - lu-ping/chisel3 GitHub Wiki
Debugging using the Interpreter REPL
This page describes a simple debugging technique using the Firrtl-Interpreter REPL. It's a Scala based circuit simulator that consumes a low Firrtl file and provides a simple command line interface for poking and peeking values, single and multi-stepping the program and otherwise controlling and monitoring the circuit's execution.
Getting Started
This tutorial assumes you have already followed the Chisel3 installation procedures and are able to use Chisel to construct a circuit and a Unit test. Specifically, we shall use a clone of the the chisel-template. Clone that repository and, if you are feeling attentive to detail follow the instructions in the README.
Testing the setup
This should be easy. In the repo, run sbt, and run the unit tests.
sbt
testOnly gcd.GCDTester -- -z "calculate proper greatest common"
This runs the first test, with both the interpreter and verilator backends. The -- -z "string" limits it to the first test in the suite. By the way, you are now one of the few people in the universe who knows how to run a specific scalatest from the sbt command line.
You should see something like this:
[info] [0.083] RAN 1102 CYCLES PASSED
[info] GCDTester:
[info] GCD
[info] - should calculate proper greatest common denominator (with firrtl)
[info] GCD
[info] - should calculate proper greatest common denominator (with verilator)
[info] Basic test using Driver.execute
[info] using --backend-name verilator
[info] running with --is-verbose creats a lot
[info] running with --fint-write-vcd
[info] using --help
[info] ScalaTest
[info] Run completed in 4 seconds, 427 milliseconds.
[info] Total number of tests run: 2
[info] Suites: completed 1, aborted 0
[info] Tests: succeeded 2, failed 0, canceled 0, ignored 0, pending 0
[info] All tests passed.
[info] Passed: Total 2, Failed 0, Errors 0, Passed 2
[success] Total time: 5 s, completed Sep 27, 2017 5:11:56 PM
If you don't you need to go back to check your setup. This is outside the scope of this tutorial
Let's break something
The GCD module as of this writing looks like this:
class GCD extends Module {
val io = IO(new Bundle {
val value1 = Input(UInt(16.W))
val value2 = Input(UInt(16.W))
val loadingValues = Input(Bool())
val outputGCD = Output(UInt(16.W))
val outputValid = Output(Bool())
})
val x = Reg(UInt())
val y = Reg(UInt())
when(x > y) { x := x - y }
.otherwise { y := y - x }
when(io.loadingValues) {
x := io.value1
y := io.value2
}
io.outputGCD := x
io.outputValid := y === 0.U
}
Using your favorite code editor, let's break it as follows.
Currently the declarations of the x
and y
are using Chisel's width inference to determine their number of bits.
Change them to a fixed size:
val x = Reg(UInt(4.W))
val y = Reg(UInt(4.W))
This is not a particularly imaginative break, but it should do the trick. Width problems are a debugging stable of circuit design, and Chisel flags this, there are many use cases where not warning on implicit truncation is behavior expected by designers.
Now run the test again.
testOnly gcd.GCDTester -- -z "calculate proper greatest common"
Now you will see
[info] GCD
[info] - should calculate proper greatest common denominator (with firrtl) *** FAILED ***
[info] false was not true (GCDUnitTest.scala:71)
[info] GCD
[info] - should calculate proper greatest common denominator (with verilator) *** FAILED ***
[info] false was not true (GCDUnitTest.scala:71)
[info] Basic test using Driver.execute
We have breakage! An error like this would probably entail turning on verbose mode in the tests. See the test labelled:
"running with --is-verbose" should "show more about what's going on in your tester" in {
You also might put printf's in the module and look at what's going on in there. But we are going to us the REPL, so let's get too it.
Launching the REPL
Conveniently the chisel-template project includes a GCDMain.scala which, along with a basic command line way of calling tester, includes the following code that launches the REPL
/**
* This provides a way to ruin the firrtl-interpreter REPL (or shell)
* on the lowered firrtl generated by your circuit. You will be placed
* in an interactive shell. This can be very helpful as a debugging
* technique. Type help to see a list of commands.
*/
object GCDRepl extends App {
iotesters.Driver.executeFirrtlRepl(args, () => new GCD)
}
So let's fire it up. From sbt run the following command
test:runMain example.test.GCDMain
You should see:
> test:runMain gcd.GCDRepl
[info] Running gcd.GCDRepl
[info] [0.002] Elaborating design...
[info] [0.109] Done elaborating.
End of dependency graph
Circuit state created
Flags: allow-cycles: false ordered-exec: false
dependency graph 21 elements 36 statements 48 nodes
firrtl>>
If you do, things are going well. Please proceed to Debugging with the Interpreter-REPL-2