1

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]

FabienM
  • 3,421
  • 23
  • 45

2 Answers2

3

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.

Chick Markley
  • 4,023
  • 16
  • 17
  • I modified the question to explain my problem. In my side I simulate the verilog generated, with treadle you simulate FIRRTL if I understand no ? – FabienM Sep 11 '19 at 15:36
  • I am working on setting up icarus so I can test directly. I have tested this against verilator and it seems to work. I also confirmed that the verilog generated for the ivl backend is the same as for the verilator backend. Maybe it would be a bit easier to see things if your io_csn toggling was not so much slower than the clock toggling. – Chick Markley Sep 11 '19 at 17:57
  • Yes done, I also added icarus and cocotb tag. It seems to be more icarus/cocotb bug (or misunderstanding) than chisel bug. – FabienM Sep 11 '19 at 19:01
  • Ok, Thanks for the question, let me know if there's more to do on my end. – Chick Markley Sep 11 '19 at 21:22
  • On my simulation, the input signal is toggled on rising edge of clock, and on your design on falling edge. Then we can see that io_debug is half period wide. – FabienM Sep 19 '19 at 10:00
1

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
FabienM
  • 3,421
  • 23
  • 45