RisingEdge 示例不适用于 Chisel3 中的模块输入信号
RisingEdge example doesn't work for module input signal in Chisel3
在 Chisel 文档中,我们有一个上升沿检测方法的示例,定义如下:
def risingedge(x: Bool) = x && !RegNext(x)
我的 github project blp 上提供了所有示例代码。
如果我在如下声明的输入信号上使用它:
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)
}
有了这个 icarus/cocotb 测试台:
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
我永远不会在 io.redge 和 io.fedge 上得到上升脉冲。为了获得脉冲,我必须如下更改上升沿的定义:
def risingedge(x: Bool) = x && !RegNext(RegNext(x))
双 RegNext() :
使用简单的 RegNext() :
这是正常行为吗?
[编辑:我用上面给出的 github 示例修改了源示例]
我不确定 Icarus,但使用默认的 Treadle 模拟器进行这样的测试。
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)
}
}
}
}
}
我看到了输出
[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
波形看起来像
你能解释一下你认为这应该是什么样子吗。
不要在时钟的上升沿更改模块输入值。
好的,我找到了我的错误。在 cocotb 测试台中,我在同步时钟的同一边缘切换输入值。如果我们这样做,输入在 D-Latch 的设置时间内被修改,那么行为是未定义的!
然后,问题是cocotb testbench bug而不是Chisel bug。为了解决这个问题,我们只需要更改时钟边沿来切换像这样的值:
@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
在 Chisel 文档中,我们有一个上升沿检测方法的示例,定义如下:
def risingedge(x: Bool) = x && !RegNext(x)
我的 github project blp 上提供了所有示例代码。
如果我在如下声明的输入信号上使用它:
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)
}
有了这个 icarus/cocotb 测试台:
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
我永远不会在 io.redge 和 io.fedge 上得到上升脉冲。为了获得脉冲,我必须如下更改上升沿的定义:
def risingedge(x: Bool) = x && !RegNext(RegNext(x))
双 RegNext() :
使用简单的 RegNext() :
这是正常行为吗?
[编辑:我用上面给出的 github 示例修改了源示例]
我不确定 Icarus,但使用默认的 Treadle 模拟器进行这样的测试。
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)
}
}
}
}
}
我看到了输出
[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
波形看起来像
你能解释一下你认为这应该是什么样子吗。
不要在时钟的上升沿更改模块输入值。
好的,我找到了我的错误。在 cocotb 测试台中,我在同步时钟的同一边缘切换输入值。如果我们这样做,输入在 D-Latch 的设置时间内被修改,那么行为是未定义的!
然后,问题是cocotb testbench bug而不是Chisel bug。为了解决这个问题,我们只需要更改时钟边沿来切换像这样的值:
@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