8000 assignment of combinatorial values with delayed assignment gives incorrect results when referencing same signal · Issue #303 · m-labs/migen · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

assignment of combinatorial values with delayed assignment gives incorrect results when referencin 8000 g same signal #303

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

Open
jwise opened this issue Mar 11, 2025 · 3 comments

Comments

@jwise
Copy link
jwise commented Mar 11, 2025

I designed a small priority encoder in a LiteX framework, and found that the post-synthesis results were not as I had specified in my Migen input. I specified the following:

class Fx3Mux(LiteXModule):
    def __init__(self, platform, inputs = [ 2048, 512, 2048, 512 ], pktdepth = 4):
        # ...
        inp_available = Signal(len(inputs))
        inp_priority = Signal(len(inputs))
        # ...
        for input,depth in enumerate(inputs):
            # ... set up pktlenfifo ...
            self.comb += inp_available[input].eq(pktlenfifo.source.valid)
            if input == 0:
                self.comb += inp_priority[input].eq(pktlenfifo.source.valid)
            else:
                self.comb += inp_priority[input].eq(pktlenfifo.source.valid & ~inp_priority[input-1])
        # ...

This synthesized down to:

always @(*) begin
    mux_inp_available <= 4'd0;
    mux_inp_available[0] <= mux_syncfifo0_source_valid1;
    mux_inp_available[1] <= mux_syncfifo1_source_valid1;
    mux_inp_available[2] <= mux_syncfifo2_source_valid1;
    mux_inp_available[3] <= mux_syncfifo3_source_valid1;
end
always @(*) begin
    mux_inp_priority <= 4'd0;
    mux_inp_priority[0] <= mux_syncfifo0_source_valid1;
    mux_inp_priority[1] <= (mux_syncfifo1_source_valid1 & (~mux_inp_priority[0]));
    mux_inp_priority[2] <= (mux_syncfifo2_source_valid1 & (~mux_inp_priority[1]));
    mux_inp_priority[3] <= (mux_syncfifo3_source_valid1 & (~mux_inp_priority[2]));
end

This is not correct, and indeed, in hardware, post-synthesis on Efinix, my gateware periodically had a 5 show up in inp_priority if two sources were ready at the same moment.

This is clearly illegal because the output of that always block would cause that block to retrigger; in an event-based model, this would loop forever, so it does not have a meaningful synthesis equivalent (even though it looks like it should!). This would be fixed either by continuous assignment, or by splitting each into its own always block (note that leaving the default would infer a latch, though!).

@jwise
Copy link
Author
jwise commented Mar 11, 2025

I should say also that fixing it in this way seems to work:

        # migen's obsession with delayed-assigns gets this priority encoder wrong!
        # inp_priority = Signal(len(inputs))
        inp_priority = [Signal(name=f"inp_priority_{n}") for n,_ in enumerate(inputs)]

@sbourdeauducq
Copy link
Member

No, this should be fixed by outputting VHDL. This sort of issue is basically intractable in Verilog and your suggestions are naive.

But in practice, most synthesizers do not have an issue with the Verilog code as generated above, and Migen is designed for these. See if you can get the Efinix compiler to behave itself.

@sbourdeauducq
Copy link
Member

Migen's "obsession" is there for good reason, see https://www.sigasi.com/opinion/jan/vhdls-crown-jewel/ - and this isn't the only problem of this kind that Verilog has.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants
0