-
Notifications
You must be signed in to change notification settings - Fork 175
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Another example of RTLIL failing BMC while Verilog succeeds. #540
Comments
I haven't looked yet at the rest of your issue but just to be clear: formal integration in nMigen is immature and it's fairly likely that you will find more cases like this. |
Oh, no worries -- I am pretty happy with the state of formal right now. I've been able to formally verify two processors (6800, Z80) just through nMigen. I just found this one case where I'm pretty sure I should be doing one thing, when I'm actually doing another. |
Hmm... I pared down the clock generation a little and reduced the signal size from 32 to 1 to make the RTLIL smaller and easier to understand. from nmigen import Signal, Module, Elaboratable, ClockDomain
from nmigen.asserts import Assert, Assume
from nmigen.back import rtlil
from nmigen.hdl import Fragment
class Buggy(Elaboratable):
def __init__(self):
self.data_in = Signal()
self.do_write = Signal()
self.mem = Signal()
def elaborate(self, _):
m = Module()
with m.If(self.do_write):
m.d.ph2 += self.mem.eq(self.data_in)
return m
@classmethod
def formal(cls):
m = Module()
buggy = Buggy()
m.submodules += buggy
ph2 = ClockDomain("ph2")
m.domains += ph2
m.d.sync += ph2.clk.eq(~ph2.clk)
# We expect that the data in mem does not change,
# except when it is written to.
saved_data = Signal()
# Apparently "initial" is a reserved word, so I changed this to "fafa"
fafa = Signal(reset=1, reset_less=True)
m.d.sync += fafa.eq(0)
with m.If(buggy.do_write):
m.d.ph2 += saved_data.eq(buggy.data_in)
with m.If(fafa):
m.d.comb += Assume(saved_data == buggy.mem)
with m.Else():
m.d.comb += Assert(saved_data == buggy.mem)
return m, [buggy.do_write, buggy.data_in, buggy.mem, saved_data, ph2.clk]
if __name__ == "__main__":
design, ports = Buggy.formal()
fragment = Fragment.get(design, None)
output = rtlil.convert(fragment, ports=ports)
with open("toplevel.il", "w") as f:
f.write(output) We get this trace: So I wanted to know why Here's toplevel.il.zip.
So |
Interestingly, generating to Verilog (and adding |
Looks like there's some fundamental misunderstanding I have about the way SymbiYosys works. Unfortunately its internals are effectively undocumented. |
:< The real reason I'm generating to RTLIL is that you told me once that the translation to Verilog when doing formal wasn't accurate or didn't work or something. I could just stick to generating to Verilog and editing to add (* gclk *) as a workaround. |
That means things will remain subtly broken in a way that happens to pass BMC for you, not that it will actually fix everything. What's necessary is to figure out why the behavior differs, not to switch to the easiest workaround without understanding why it appears to work. |
Looks to me like the problem here is I think |
BTW, I changed back to generating RTLIL, but without the sby workaround provided in #526, and then BMC passed. |
I verified that both this example and the example in #526 work correctly with |
@RobertBaruch Yeah, @daveshah1 is right. The proper fix to this is to not use sketchy workarounds but address #505. |
@whitequark It's true! I'm not enough of an expert to help, but I can send you support, sympathy, thanks, and some currency if you want :D |
@RobertBaruch After the recent discussion of multiclock, I actually think that getting multiclock to work is easier than I expected. The |
Høly Ødin, you weren't wrong there :< |
I have a case which MAY be caused by bad use of
Initial
andAssume
. If this is a bad use, I'd kind of expect a complaint to be shown. Instead, I get a BMC trace that shows a signal is changed not on its clock.My goal is to have a test Signal,
saved_data
which is initialized to the value of another Signal,mem
(assumed to be randomly initialized on startup by formal) on startup. I use anInitial
andAssume
in the comb domain for this. However, the test Signal then should change on the positive edge of my clock signal.Is that the wrong way to do what I want?
The code:
The sby:
The toplevel.il: toplevel.il.zip
Assert fails in line 70 (
m.d.comb += Assert(saved_data == buggy.mem)
)The anomalous trace:
The text was updated successfully, but these errors were encountered: