-
Notifications
You must be signed in to change notification settings - Fork 182
Description
It seems I can write something like m.d.comb += Assert(Past(signal) == 0)
. If multiclock
is off in the sby file, what exactly is Past
?
Here's an example. First, example.py
:
from nmigen import Signal, Module, Elaboratable, ClockDomain, Mux
from nmigen.build import Platform
from nmigen.asserts import Assert, Fell, Past, Cover
from nmigen.cli import main_parser, main_runner
# Simple example that clocks data in into data out when the
# independent signal -- assumed to be asynchrnous with any
# other clock in the system -- has a negative edge.
#
# Run with:
#
# python example.py generate -t il > toplevel.il
# sby -f example.sby
class Example(Elaboratable):
def __init__(self):
self.data_in = Signal(32)
self.data_out = Signal(32)
self.le = Signal()
def elaborate(self, _: Platform) -> Module:
m = Module()
internal_clk = ClockDomain("internal_clk", clk_edge="neg", local=True)
m.domains.internal_clk = internal_clk
internal_clk.clk = self.le
m.d.internal_clk += self.data_out.eq(self.data_in)
return m
def formal():
"""Formal verification for the example."""
parser = main_parser()
args = parser.parse_args()
m = Module()
m.submodules.example = example = Example()
m.d.comb += Cover((example.data_out == 0xAAAAAAAA) & (example.le == 0)
& (Past(example.data_out) == 0xBBBBBBBB)
& (Past(example.le) == 0))
with m.If(Fell(example.le)):
m.d.comb += Assert(example.data_out == Past(example.data_in))
main_runner(parser, args, m, ports=[
example.data_in,
example.le,
])
if __name__ == "__main__":
formal()
And, the sby file:
[tasks]
cover
bmc
[options]
bmc: mode bmc
cover: mode cover
depth 10
# With this on, BMC fails.
# With this off, it passes, but cover looks odd.
multiclock on
[engines]
smtbmc z3
[script]
read_ilang toplevel.il
prep -top top
[files]
toplevel.il
This fails BMC when multiclock is on, which kind of makes sense to me, if Past is relative to the last cycle of the global clock. In this case I probably shouldn't be using Past, because really what I want to assert is that data_out
is equal to what data_in
was, when le
was last high.
In that case, do I have to effectively make my own version of Past for the internal clock of the example module?
BMC succeeds when multiclock is off, which also kind of makes sense to me, if signals are not allowed to change except on the positive edge of the global clock. However, now the cover trace looks distinctly odd:
data_out
did change on the negative edge of 'le'... but it also changed when le
was stable. Is that because I've violated the assumption that there is only one clock in the system and therefore yosys does unspecified behavior?