Skip to content

[HoistSignals] Multiple drives to same signal are handled incorrectly #9420

@fabianschuiki

Description

@fabianschuiki

Consider a simple clock generator which uses an infinite loop to toggle a clock:

hw.module @Foo(out clock : i1) {
  %0 = llhd.constant_time <5000000fs, 0d, 0e>
  %1 = llhd.constant_time <10000000fs, 0d, 0e>
  %false = hw.constant false
  %true = hw.constant true
  %clock = llhd.sig %false : i1
  llhd.process {
    cf.br ^bb1
  ^bb1:  // 2 preds: ^bb0, ^bb2
    llhd.drv %clock, %false after %0 : i1
    llhd.drv %clock, %true after %1 : i1
    llhd.wait delay %0, ^bb2
  ^bb2:  // pred: ^bb1
    cf.br ^bb1
  }
  %2 = llhd.prb %clock : i1
  hw.output %2 : i1
}

Running this through circt-opt --llhd-hoist-signals yields this:

hw.module @Foo(out clock : i1) {
  %0 = llhd.constant_time <5000000fs, 0d, 0e>
  %1 = llhd.constant_time <10000000fs, 0d, 0e>
  %false = hw.constant false
  %true = hw.constant true
  %clock = llhd.sig %false : i1
  llhd.process {
    cf.br ^bb1
  ^bb1:  // 2 preds: ^bb0, ^bb2
    llhd.drv %clock, %false after %0 : i1
    llhd.wait delay %0, ^bb2
  ^bb2:  // pred: ^bb1
    cf.br ^bb1
  }
  llhd.drv %clock, %true after %1 : i1  // <--- drive moved
  %2 = llhd.prb %clock : i1
  hw.output %2 : i1
}

For some reason, the second drive to %clock got moved out of the process, which is clearly wrong.

The original input comes from circt-verilog --ir-llhd on this:

module Foo (output logic clock);
  initial begin
    forever begin
      clock <= #5ns 0;   // schedule clock = 0 in 5ns
      clock <= #10ns 1;  // schedule clock = 1 in 10ns
      #10ns;             // wait 10ns
    end
  end
endmodule

Metadata

Metadata

Assignees

Labels

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions