Search code examples
simulationchisel

Printf in Chisel PeekPokeTester behaves differently from verilator on the same RTL


Printing in Chisel's iotester seems to output the updated version of register value, which makes the same Chisel printing code behaves differently in Chisel backend and verilator backend.

When with Chisel backend, the printing seems just to record the reference of the hardware object, but execute printing after the logic simulation of current step, then the reference replies with an updated value.

I have searched through Chisel repo's issues and chisel-user groups, but find few discussions on this topic.

Here is a self-contained code example op top of chisel-template repo.

package myrtl

import chisel3._
import chisel3.iotesters._

class Foo extends Module {

  val io = IO(new Bundle {
    val in = Input(UInt(32.W))
    val out = Output(UInt(32.W))
  })

  val v = Wire(UInt(32.W))
  when (v === 0.U) {
    printf(p"v $v\n")
  }

  val reg = RegInit(0.U(32.W))
  reg := io.in
  io.out := reg
  v := reg
}

class FooTester(dut: Foo) extends PeekPokeTester(dut) {
  poke(dut.io.in, 32)
  step(1)
}

object TestMain extends App {
  iotesters.Driver.execute(args, () => new Foo)(dut => new FooTester(dut))
}

Notice the condition of printf. It is ridiculous that a printing is enabled by v === 0.U but output this v as value of 32.


Solution

  • I believe this was a reported bug where printf statements were not having their dependencies properly computed (and was fixed).

    There were a number of refactors over the past year which are likely responsible for fixing this:

    Can you try switching to the 1.3-SNAPSHOT on sonatype and retesting?

    diff --git a/build.sbt b/build.sbt
    index 6d18fe7..c13d44d 100644
    --- a/build.sbt
    +++ b/build.sbt
    @@ -41,11 +41,10 @@ resolvers ++= Seq(
    
     // Provide a managed dependency on X if -DXVersion="" is supplied on the command line.
     val defaultVersions = Map(
    -  "chisel3" -> "3.1.+",
    -  "chisel-iotesters" -> "[1.2.5,1.3.0["
    +  "chisel-iotesters" -> "1.3-SNAPSHOT"
       )
    
    -libraryDependencies ++= Seq("chisel3","chisel-iotesters").map {
    +libraryDependencies ++= Seq("chisel-iotesters").map {
       dep: String => "edu.berkeley.cs" %% dep % sys.props.getOrElse(dep + "Version", defaultVersions(dep)) }
    
     scalacOptions ++= scalacOptionsVersion(scalaVersion.value)
    

    With these modifications to build.sbt, I'm able to see expected behavior of nothing printing. This does differ from Verilator which has one print seemingly before the simulation starts. Using 1.3-SNAPSHOT:

    sbt:chisel-module-template> test:runMain myrtl.TestMain --backend-name treadle
    [warn] Multiple main classes detected.  Run 'show discoveredMainClasses' to see the list
    [info] Running myrtl.TestMain --backend-name treadle
    [info] [0.001] Elaborating design...
    [info] [0.108] Done elaborating.
    Total FIRRTL Compile Time: 408.8 ms
    file loaded in 0.071117471 seconds, 15 symbols, 12 statements
    [info] [0.001] SEED 1568033935603
    test Foo Success: 0 tests passed in 6 cycles in 0.012474 seconds 481.00 Hz
    [info] [0.003] RAN 1 CYCLES PASSED
    [success] Total time: 2 s, completed Sep 9, 2019 8:58:56 AM
    

    And when using verilator (with some snipping of the output):

    sbt:chisel-module-template> test:runMain myrtl.TestMain --backend-name verilator
    [warn] Multiple main classes detected.  Run 'show discoveredMainClasses' to see the list
    [info] Running myrtl.TestMain --backend-name verilator
    [info] [0.001] Elaborating design...
    [info] [0.108] Done elaborating.
    Total FIRRTL Compile Time: 440.6 ms
    [info] [0.001] SEED 1568034082729
    [info] [0.007] v          0
    [info] [0.007]          0
    Enabling waves..
    Exit Code: 0
    [info] [0.011] RAN 1 CYCLES PASSED
    [success] Total time: 4 s, completed Sep 9, 2019 9:01:25 AM