ucb-bar / chiseltest

The batteries-included testing and formal verification library for Chisel-based RTL designs.
Other
220 stars 73 forks source link

`poke` in `ChiselScalatestTester` occurs on falling clock edge in traces #646

Open yupferris opened 1 year ago

yupferris commented 1 year ago

This is surprising; I would have expected pokes to happen "immediately", typically aligned with the rising edge of the clock in a trace. Is there an option to enable this? As it is now, it's quite an adjustment to read traces this way.

ekiwi commented 1 year ago

This is actually a often requested feature. It is a little difficult to implement since it would need to work for all our backends and there might be unexpected interactions with Verilog blackboxes, but it would definitely be possible to implement.

You want pokes to occur a delta cycle after the rising edge, correct? Not a delta cycle before the rising edge.

yupferris commented 1 year ago

You want pokes to occur a delta cycle after the rising edge, correct? Not a delta cycle before the rising edge.

I'm not entirely sure what a "delta cycle" is, but I think I can relatively easily articulate what I expect. Consider the following design and test:

class Hello extends Module {
  val io = IO(new Bundle {
    val input = Input(Bool())
    val output = Output(Bool())
  })

  io.output := RegNext(io.input, false.B)
}

class HelloTests extends AnyFlatSpec with ChiselScalatestTester {
  behavior of "Hello"

  it should "demonstrate poke edges" in {
    test(new Hello).withAnnotations(Seq(chiseltest.simulator.WriteVcdAnnotation)) { dut =>
      dut.io.input.poke(false)
      dut.clock.step(1)
      dut.io.input.poke(true)
      dut.clock.step(2)
      dut.io.input.poke(false)
      dut.clock.step(2)
    }
  }
}

Running this test, I get the following trace:

image

Importantly, changes to io_output_REG (and correspondingly, io_output) are aligned with rising clock edges, which makes sense, as the clock edge should trigger those updates "immediately" (combinational logic propagation delay is not modeled, as expected). Subsequent changes to io_input, however, are aligned with the following falling clock edge.

I would have expected changes from pokes to also be aligned with the most recent rising clock edge, as if these changes were also triggered by that rising edge, and propagated "immediately". This would look like the following:

image

I'm currently working around this with a python script that shifts all of the non-clock changes to the most recent rising edge in the .vcd output (which is what I used to produce the second trace above). This is obviously less than ideal, but it does work :)

ekiwi commented 1 year ago

OK, I think you want all pokes to apply right after the rising clock edge.

A "delta cycle" is a Verilog term for the smallest possible time-step in simulation. A rising clock edge is an instantaneous event, so you cannot really have an input change "during" the rising edge. They either have to change a litter (i.e. a delta cycle) before or after the rising edge.

yupferris commented 1 year ago

Ok, right. Then yeah, a delta cycle after the rising edge.