calyxir / calyx

Intermediate Language (IL) for Hardware Accelerator Generators
https://calyxir.org
MIT License
502 stars 51 forks source link

Verilator Error: Circular Combinational Logic #2331

Closed polybeandip closed 4 weeks ago

polybeandip commented 1 month ago

Consider the following snippet of Calyx code from this Zulip thread:

# bad.futil
import "primitives/core.futil";

component store(val: 32) -> () {
  cells {
    ref refreg = std_reg(32);
  }
  wires {
   group write {
     refreg.write_en = 1'b1;
     refreg.in = val;
     write[done] = refreg.done;
   }
  }
  control {
      write;
  }
}

component main() -> () {
  cells {
    storage = std_reg(32);
    propogate = std_reg(32);
    store = store();
    one = std_const(32, 1);
  }
  wires {
    group read {
      propogate.in = storage.out;
      propogate.write_en = 1'b1;
      read[done] = propogate.done;
    }
  }
  control {
      seq {
        invoke store[refreg=storage](val=one.out)();
        read;
      }
  }
}

This tries to store 32'b1 into the storage register and then move that data into the propogate register.

It appears Calyx compiles this to malformed Verilog since running this with

fud exec bad.futil --to dat --through verilog

gives the following Verilator error:

[fud] ERROR: `/opt/verilator/bin/verilator --trace /tmp/tmpx7bk5crd /scratch/ad739/calyx/fud/icarus/tb.sv --binary --top-module toplevel --Mdir /tmp/tmpj8622ain -fno-inline>&2' failed:
=====STDERR=====
%Warning-UNOPTFLAT: /tmp/tmpx7bk5crd:388:7: Signal unoptimizable: Circular combinational logic: 'toplevel.main.store_refreg_done'
                                          : ... In instance toplevel.main
  388 | logic store_refreg_done;
      |       ^~~~~~~~~~~~~~~~~
                    ... For warning description see https://verilator.org/warn/UNOPTFLAT?v=5.006
                    ... Use "/* verilator lint_off UNOPTFLAT */" and lint_on around source to disable this message.
                    /tmp/tmpx7bk5crd:388:7:      Example path: toplevel.main.store_refreg_done
                    /tmp/tmpx7bk5crd:555:22:      Example path: ASSIGNW
                    /tmp/tmpx7bk5crd:396:7:      Example path: toplevel.main.invoke0_go_in
                    /tmp/tmpx7bk5crd:565:26:      Example path: ASSIGNW
                    /tmp/tmpx7bk5crd:388:7:      Example path: toplevel.main.store_refreg_done
%Error: Exiting due to 1 warning(s)

=====STDOUT=====

In contrast, running our code with cider2 yields the correct result:

 cargo run -- circ.futil -l ../../ --dump-registers | ../../target/debug/cider-data-converter --to json
    Finished `dev` profile [unoptimized] target(s) in 0.09s
     Running `/Users/griffin/research/calyx/target/debug/cider bad.futil -l ../../ --dump-registers`
{
  "storage": [
    1
  ],
  "propogate": [
    1
  ]
}

(run locally by @EclecticGriffin)

rachitnigam commented 1 month ago

https://github.com/calyxir/calyx/issues/2198 is the cause.

polybeandip commented 4 weeks ago

Apologies, I should've found that issue before posting. I'll close this one to avoid duplicates.

rachitnigam commented 4 weeks ago

No worries! It is a tricky one!