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

Signed comparison -- difference between sim and Verilog generation #580

Closed
tcal-x opened this issue Jan 20, 2021 · 2 comments
Closed

Signed comparison -- difference between sim and Verilog generation #580

tcal-x opened this issue Jan 20, 2021 · 2 comments
Labels
Milestone

Comments

@tcal-x
Copy link

tcal-x commented Jan 20, 2021

This starts with a bug in my nMigen -- I perform a comparison between unsigned and signed values. If this means behavior is undefined, then we can just close this issue.

It seems that simulation treats this as an unsigned comparison, while the generated Verilog has a signed comparison.

On https://nmigen.info/nmigen/latest/lang.html, I found "Similar to arithmetic operations, if any operand of a comparison expression is signed, a signed comparison is performed." This is reflected in Verilog generation.

This is the example, with both simulation and Verilog generation:

from nmigen import *
from nmigen.sim import Simulator, Delay
from nmigen.back import rtlil, verilog


class DoubleCompareInstruction(Elaboratable):
    def __init__(self):
        self.in0 = Signal(32)
        self.out0 = Signal(1)
        self.signed_five = Const(5, signed(32))

    def elaborate(self, platform):
        m = Module()
        m.d.comb += [
            self.out0.eq((self.in0 < self.signed_five)),
        ]
        return m


if __name__ == "__main__":
    dut = DoubleCompareInstruction()
    sim = Simulator(dut)

    def process():
        for i in range(10):
            yield dut.in0.eq(i-2)
            yield Delay()
            print("(unsigned)", (yield dut.in0), "< (signed)5 --> ", (yield dut.out0))

    sim.add_process(process)
    sim.run()

    with open("dut.v", "w") as f:
        f.write(verilog.convert(dut, name='Dut', ports=[dut.in0, dut.out0]))

Simulation output; output values indicate an unsigned comparison:

(unsigned) 4294967294 < (signed)5 -->  0
(unsigned) 4294967295 < (signed)5 -->  0
(unsigned) 0 < (signed)5 -->  1
(unsigned) 1 < (signed)5 -->  1
(unsigned) 2 < (signed)5 -->  1
(unsigned) 3 < (signed)5 -->  1
(unsigned) 4 < (signed)5 -->  1
(unsigned) 5 < (signed)5 -->  0
(unsigned) 6 < (signed)5 -->  0
(unsigned) 7 < (signed)5 -->  0

Generated Verilog (note the signed comparison):

/* Generated by Yosys 0.9+3796 (git sha1 832f6aa7, clang 10.0.0-4ubuntu1 -fPIC -Os) */

(* \nmigen.hierarchy  = "Dut" *)
(* top =  1  *)
(* generator = "nMigen" *)
module Dut(out0, in0);
  (* src = "./bug.py:15" *)
  wire \$1 ;
  (* src = "./bug.py:8" *)
  input [31:0] in0;
  (* src = "./bug.py:9" *)
  output out0;
  assign \$1  = $signed(in0) < (* src = "./bug.py:15" *) $signed(32'd5);
  assign out0 = \$1 ;
endmodule
@whitequark whitequark added the bug label Jan 20, 2021
@whitequark
Copy link
Member

This is clearly a bug and should be fixed.

@whitequark
Copy link
Member

Thanks for the report!

@whitequark whitequark added this to the 0.3 milestone Dec 11, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

No branches or pull requests

2 participants