fabianschuiki / moore

A hardware compiler based on LLHD and CIRCT
http://www.llhd.io
Apache License 2.0
246 stars 31 forks source link

How to generate reg primitive? #215

Closed wbouillo closed 3 years ago

wbouillo commented 3 years ago

In my examples of using moore to generate LLHD, I can't successfully generate the reg primitive. I expected a SystemVerilog reg to generate a LLHD reg, but that did not happen for me. Can someone provide an example of an HDL that will generate a reg primitive via moore?

fabianschuiki commented 3 years ago

There are a couple of things at play here. Moore itself never emits a reg instruction directly, since SystemVerilog itself has no register construct. The reg keyword is just an alias for logic, and always_ff is just an always process with a few additional warnings enabled. The thing responsible for converting the always_ff processes to reg is the desequentialization transformation in LLHD.

However, in trying to throw together an example for you I realized that the transformation chain currently has a bug in LLHD. Thanks for pointing me at that :+1:. Here's an example that should work, but doesn't:

// reg.sv
module foo (input clk, d, output q);
    always_ff @(posedge clk) q <= d;
endmodule

Compiling this with moore reg.sv -e foo > reg.llhd yields:

; reg.llhd
proc %foo.always_ff.31.0 (i1$ %clk, i1$ %d) -> (i1$ %q) {
init:
    %clk.prb = prb i1$ %clk
    wait %check, %clk
check:
    %clk.prb1 = prb i1$ %clk
    %0 = const i1 0
    %1 = eq i1 %clk.prb, %0
    %2 = neq i1 %clk.prb1, %0
    %posedge = and i1 %1, %2
    br %posedge, %init, %event
event:
    %3 = const time 0s 1d
    %d.prb = prb i1$ %d
    drv i1$ %q, %d.prb, %3
    br %init
}

entity @foo (i1$ %clk, i1$ %d) -> (i1$ %q) {
    inst %foo.always_ff.31.0 (i1$ %clk, i1$ %d) -> (i1$ %q)
}

At this point llhd-opt reg.llhd -l should actually pick this up and map to a reg, but it produces an error and generates:

proc %foo.always_ff.31.0 (i1$ %clk, i1$ %d) -> (i1$ %q) {
init:
    %clk.prb = prb i1$ %clk
    %0 = const i1 0
    %1 = eq i1 %clk.prb, %0
    %2 = const time 0s 1d
    wait %check, %clk
check:
    %d.prb = prb i1$ %d
    %clk.prb1 = prb i1$ %clk
    %3 = neq i1 %clk.prb1, %0
    %posedge = and i1 %1, %3
    drv i1$ %q if %posedge, %d.prb, %2
    br %posedge, %init, %event
event:
    %d.prb = prb i1$ %d  ; <--- this should have been removed (it's inserted in check)
    br %init
}

If you remove the offending line and run it through llhd-opt again, you get what you are looking for:

entity %foo.always_ff.31.0 (i1$ %clk, i1$ %d) -> (i1$ %q) {
    %d.prb = prb i1$ %d
    %0 = prb i1$ %clk
    reg i1$ %q, [%d.prb, rise %0]  ; <--- voila!
}

entity @foo (i1$ %clk, i1$ %d) -> (i1$ %q) {
    inst %foo.always_ff.31.0 (i1$ %clk, i1$ %d) -> (i1$ %q)
}

This is likely a bug in the Common Subexpression Elimination code of LLHD, which leaves the prb i1$ %d inserted in two places -- and an issue in the verifier not asserting that the instruction is not inserted twice.

At a later stage (once the LLHD transformation become more mature), Moore will run these transformations automatically on the output (unless you specify -O0).

fabianschuiki commented 3 years ago

Will be fixed by https://github.com/fabianschuiki/llhd/issues/145.

fabianschuiki commented 3 years ago

Has been fixed as part of llhd v0.14.3.