RisingEdge example doesn't work for module input signal in Chisel3

648 Views Asked by At

In Chisel documentation we have an example of rising edge detection method defined as following :

      def risingedge(x: Bool) = x && !RegNext(x)

All example code is available on my github project blp.

If I use it on an Input signal declared as following :

class RisingEdge extends Module {
  val io = IO(new Bundle{
    val sclk = Input(Bool())
    val redge = Output(Bool())
    val fedge = Output(Bool())
  })

  // seems to not work with icarus + cocotb
  def risingedge(x: Bool) = x && !RegNext(x)
  def fallingedge(x: Bool) = !x && RegNext(x)
  // works with icarus + cocotb
  //def risingedge(x: Bool) = x && !RegNext(RegNext(x))
  //def fallingedge(x: Bool) = !x && RegNext(RegNext(x))

  io.redge :=  risingedge(io.sclk)
  io.fedge := fallingedge(io.sclk)
}

With this icarus/cocotb testbench :

class RisingEdge(object):
    def __init__(self, dut, clock):
        self._dut = dut
        self._clock_thread = cocotb.fork(clock.start())

    @cocotb.coroutine
    def reset(self):
        short_per = Timer(100, units="ns")
        self._dut.reset <= 1
        self._dut.io_sclk <= 0
        yield short_per
        self._dut.reset <= 0
        yield short_per

@cocotb.test()
def test_rising_edge(dut):
    dut._log.info("Launching RisingEdge test")
    redge = RisingEdge(dut, Clock(dut.clock, 1, "ns")) 
    yield redge.reset()
    cwait = Timer(10, "ns")
    for i in range(100):
        dut.io_sclk <= 1
        yield cwait
        dut.io_sclk <= 0
        yield cwait

I will never get rising pulses on io.redge and io.fedge. To get the pulse I have to change the definition of risingedge as following :

  def risingedge(x: Bool) = x && !RegNext(RegNext(x))

With dual RegNext() : Dual RegNext screenshot

With simple RegNext() : Simple RegNext screenshot

Is it a normal behavior ?

[Edit: I modified source example with the github example given above]

2

There are 2 best solutions below

0
On BEST ANSWER

Do not change module input value on rising edge of clock.

Ok I found my bug. In the cocotb testbench I toggled input values on the same edge of synchronous clock. If we do that, the input is modified exactly under the setup time of D-Latch, then the behavior is undefined !

Then, the problem was a cocotb testbench bug and not Chisel bug. To solve it we just have to change the clock edge for toggling values like it :

@cocotb.test()
def test_rising_edge(dut):
    dut._log.info("Launching RisingEdge test")
    redge = RisingEdge(dut, Clock(dut.clock, 1, "ns")) 
    yield redge.reset()
    cwait = Timer(4, "ns")
    yield FallingEdge(dut.clock) #   <--- 'synchronize' on falling edge
    for i in range(5):
        dut.io_sclk <= 1
        yield cwait
        dut.io_sclk <= 0
        yield cwait
5
On

I'm not sure about Icarus, but using the default Treadle simulator for a test like this.

class RisingEdgeTest extends FreeSpec {
  "debug should toggle" in {
    iotesters.Driver.execute(Array("-tiwv"), () => new SlaveSpi) { c =>
      new PeekPokeTester(c) {
        for (i <- 0 until 10) {
          poke(c.io.csn, i % 2)
          println(s"debug is ${peek(c.io.debug)}")
          step(1)
        }
      }
    }
  }
}

I see the output

[info] [0.002] debug is 0
[info] [0.002] debug is 1
[info] [0.002] debug is 0
[info] [0.003] debug is 1
[info] [0.003] debug is 0
[info] [0.003] debug is 1
[info] [0.004] debug is 0
[info] [0.004] debug is 1
[info] [0.005] debug is 0
[info] [0.005] debug is 1

And the wave form looks like enter image description here

Can you explain what you think this should look like.