Skip to content
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

Simulation-synthesis mismatch overriding value selected in a switch with a plain assignment #155

Closed
whitequark opened this issue Jul 18, 2019 · 0 comments

Comments

@whitequark
Copy link
Contributor

whitequark commented Jul 18, 2019

Repro:

from nmigen import *
from nmigen.back.pysim import *
from nmigen.back.rtlil import *


class Bug(Elaboratable):
    def __init__(self):
        self.i = Signal()
        self.o = Signal()

    def elaborate(self, platform):
        m = Module()
        with m.If(self.i):
            m.d.comb += self.o.eq(1)
        m.d.comb += self.o.eq(0)
        return m


if __name__ == "__main__":
    bug = Bug()
    with Simulator(bug) as sim:
        def process():
            yield bug.i.eq(1)
            yield Delay(1e-6)
            print("o =", (yield bug.o))
        sim.add_process(process)
        sim.run()
    with open("bug.il", "w") as f:
        f.write(convert(bug))
$ python3 bug.py
o = 0
$ yosys bug.il -p "proc; eval -set i 1 -show o"
Eval result: \o = 1'1.

The reason is because the following generated RTLIL (edited for clarity):

module \top
  wire width 1 input 0 \i
  wire width 1 \o
  process $group_0
    assign \o 1'0
    switch { \i }
      case 1'1
        assign \o 1'1
    end
    assign \o 1'0
  end
end

is actually transformed to the following on parsing:

module \top
  wire width 1 input 0 \i
  wire width 1 \o
  process $group_0
    assign \o 1'0
    assign \o 1'0
    switch { \i }
      case 1'1
        assign \o 1'1
    end
  end
end

The best way to fix this would be to adjust RTLIL so this doesn't happen. The second best way to fix this (and remain compatible with Yosys 0.9) is to adjust the emitted RTLIL so it looks like this:

module \top
  wire width 1 input 0 \i
  wire width 1 \o
  process $group_0
    assign \o 1'0
    switch { \i }
      case 1'1
        assign \o 1'1
    end
    switch { }
      case
        assign \o 1'0
    end
  end
end

This results in slightly uglier Verilog:

module top(i);
  input i;
  reg o;
  always @* begin
    o = 1'h0;
    casez (i)
      1'h1:
          o = 1'h1;
    endcase
    begin
        o = 1'h0;
    end
  end
endmodule
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant