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

False Signal unoptimizable: circular logic warning #63

Open
veripoolbot opened this issue Jan 30, 2009 · 15 comments
Open

False Signal unoptimizable: circular logic warning #63

veripoolbot opened this issue Jan 30, 2009 · 15 comments
Labels
area: scheduling Issue involves scheduling/ordering of events effort: weeks Expect this issue to require weeks or more of invested effort to resolve type: feature-IEEE Request to add new feature, described in IEEE 1800 type: feature-non-IEEE Request to add new feature, outside IEEE 1800

Comments

@veripoolbot
Copy link
Contributor


Author Name: Lane Brooks
Original Redmine Issue: 63 from https://www.veripool.org
Original Date: 2009-01-30


See attached test case showing the problem. This example shows how bit 0 of a bus is used to generate bit 1 of the same bus. Verilator is falsly detecting this as circular logic. Also shown in this test case is that this example works if the signals are not part of a bus (the `ifdef T_WORKS section).

@veripoolbot
Copy link
Contributor Author


Original Redmine Comment
Author Name: Wilson Snyder (@wsnyder)
Original Date: 2010-10-25T20:07:27Z


Similar UNOPTFLAT woes are also discussed in http://www.veripool.org/boards/2/topics/show/373-UNOPTFLAT-Error

@veripoolbot
Copy link
Contributor Author


Original Redmine Comment
Author Name: Keith Campbell
Original Date: 2016-05-27T22:14:42Z


Also ran into this problem. I can contribute a very simple reproduction case (attached).
Any known workarounds for building a regular binary tree network? (e.g. a network that sums an input array with parametrizable size)

@veripoolbot veripoolbot added area: scheduling Issue involves scheduling/ordering of events effort: weeks Expect this issue to require weeks or more of invested effort to resolve type: feature-IEEE Request to add new feature, described in IEEE 1800 type: feature-non-IEEE Request to add new feature, outside IEEE 1800 labels Dec 22, 2019
@trosenkranz
Copy link
Contributor

Is this issue still valid? If yes, can you post the mentioned attached file of the post here?

@wsnyder
Copy link
Member

wsnyder commented Jan 31, 2020

module transmit(output out, input in);
    wire [1:0] jumper;
    assign jumper[1] = in;
    assign jumper[0] = jumper[1];
    assign out = jumper[0];
endmodule

#2066 is an in-flight workaround for these sort of issues.

@fsiegle
Copy link

fsiegle commented Feb 1, 2020

Will these patches also fix UNOPTFLAT warnings related to packed structs? In the meanwhile, is it safe to just use /* verilator lint_off UNOPTFLAT */ ?

@wsnyder
Copy link
Member

wsnyder commented Feb 1, 2020

Will these patches also fix UNOPTFLAT warnings related to packed structs? In the meanwhile, is it safe to just use /* verilator lint_off UNOPTFLAT */ ?

Yes & yes. UNOPTFLAT is only performance; see the manual.

@jalcim
Copy link

jalcim commented Apr 5, 2021

I have reproduce the problem with a Dlatch at gate_level.
More !!! I have provoked a crash !!! (all these design work on icarus and the first work on verilator, not the second...)
When i use </* verilator lint_off UNOPTFLAT */> and <wire [7:0] line> the code compile but crash with error

then for demonstrate i have writed 2x the code with only change

example 1 (no crash)

module Dlatch (a, clk, reset, s1, s2);
   input a, clk, reset;
   output s1, s2;
   wire   line0;
   wire   line1;
   wire   line2;
   wire   line3;
   /* verilator lint_off UNOPTFLAT */
   wire   line4;
   wire   line5;
   wire   line6;
   wire   line7;

   gate_xor xor1(a, reset, line5);
   gate_and and1(a, line5, line6);

   gate_nand nand1(line6, clk, line0);
   gate_not not1(line6, line1);
   gate_nand nand2(line1, clk, line2);

   gate_nand nand3(line0, line7, line3);
   gate_nand nand4(line2, line3, line4);

   gate_or or1(reset, line4, line7);

   gate_buf buf1(line3, s1);
   gate_buf buf2(line4, s2);
endmodule

example 2 (crash)

module Dlatch (a, clk, reset, s1, s2);                                                                                                               
   input a, clk, reset;                                                                                                                               
   /* verilator lint_off UNOPTFLAT */                                                                                                                 
   wire [7:0] line;                                                                                                                                   
   output     s1, s2;                                                                                                                                 
                                                                                                                                                      
   gate_xor xor1(a, reset, line[5]);                                                                                                                  
   gate_and and1(a, line[5], line[6]);                                                                                                                
                                                                                                                                                      
   gate_nand nand1(line[6], clk, line[0]);                                                                                                            
   gate_not not1(line[6], line[1]);                                                                                                                   
   gate_nand nand2(line[1], clk, line[2]);                                                                                                            
                                                                                                                                                      
   gate_nand nand3(line[0], line[7], line[3]);                                                                                                        
   gate_nand nand4(line[2], line[3], line[4]);                                                                                                        
                                                                                                                                                      
   gate_or or1(reset, line[4], line[7]);                                                                                                              
                                                                                                                                                      
   gate_buf buf1(line[3], s1);                                                                                                                        
   gate_buf buf2(line[4], s2);                                                                                                                        
                                                                                                                                                      
endmodule

the message of crash

- Verilated::debug attempted, but compiled without VL_DEBUG, so messages suppressed.
- Suggest remake using 'make ... CPPFLAGS=-DVL_DEBUG'
%Error: PSyPdP:2: Verilated model didn't DC converge
- See DIDNOTCONVERGE in the Verilator manual
Aborting...
Abandon

@wsnyder
Copy link
Member

wsnyder commented Apr 5, 2021

Thanks for tracking this down. Strictly speaking DIDNOTCONVERGE is an error not a crash. You might get around this by de-vectorizing "line", but then you'll likely find incorrect results. Verilator doesn't support making latches out of individual primitives using Verilator, you must use a behavioral latch construct. I will update the documentation to mention this.

@jalcim
Copy link

jalcim commented Apr 5, 2021

Thanks for tracking this down. Strictly speaking DIDNOTCONVERGE is an error not a crash. You might get around this by de-vectorizing "line", but then you'll likely find incorrect results. Verilator doesn't support making latches out of individual primitives using Verilator, you must use a behavioral latch construct. I will update the documentation to mention this.

Thanks for your response, if you indicate me where i can start my analyze for implementing primitive support maybe can i make an pull request for adding this (essential) functionalities.

@wsnyder
Copy link
Member

wsnyder commented Apr 5, 2021

Primitives are supported, UDPs are not (yet), the problem is the loop between primitives or UDPs. We need to first get the event model working, then this will be fairly easy. If you'd like to help with UDPs or event, or other issues that would certainly be welcome.

@seldridge
Copy link

seldridge commented Feb 3, 2023

We're getting burned by this pretty badly now in CIRCT. Specifically, we're working towards emitting Verilog from Chisel which preserves the structure of aggregate types described in Chisel. This is intended to be available for any front-end language that uses CIRCT infra, e.g., PyCDE or Calyx.

We have our own bit-level combinational loop detection implemented so we are extremely confident that we don't have combinational cycles. However, there is a lot of concern about globally disabling UNOPTFLAT.

Is there any possibility of improvements to Verilator that will do the bit-level analysis to avoid the UNOPTFLAT warnings here and/or automatically split variables when necessary?

An example of something showing this:

Chisel Source

Contents of Foo.scala:

//> using scala "2.13.10"
//> using lib "edu.berkeley.cs::chisel3::3.6.0-M2"
//> using plugin "edu.berkeley.cs:::chisel3-plugin::3.6.0-M2"

import chisel3._
import circt.stage.ChiselStage

class Foo extends RawModule {
  val a = IO(Input(Bool()))
  val b = IO(Output(Bool()))

  val w = Wire(Vec(2, Bool()))
  dontTouch(w)
  w(0) := a
  w(1) := w(0)
  b := w(1)
}

object Main extends App {
  println(
    ChiselStage.emitSystemVerilog(
      new Foo,
      Array(),
      Array("-preserve-aggregate=1d-vec", "-strip-debug-info")
    )
  )
}

For the curious, you can run this if you install Scala CLI and run:

scala-cli Foo.scala

We're producing Verilog like the following:

module Foo(
  input  a,
  output b);

  wire [1:0] w;
  assign w = {{w[1'h0]}, {a}};
  assign b = w[1'h1];
endmodule

We are reluctant to investigate options that involve split_var or local application of lint_on/lint_off as that relies on CIRCT needing to grok the algorithm that Verilator is using here. Specifically, there doesn't appear to be a simple solution that works and different, equivalent Verilog formulations require different strategies of mitigation. The following are all on Verilator 5.002.

E.g., the following errors, but can be escaped with wire [1:0 w /*verilator split_var*/;:

module Foo(
  input  a,
  output b);

  wire [1:0] w;
  assign w[0] = a;
  assign w[1] = w[0];
  assign b = w[1];
endmodule

E.g., the following (which is what we produce now with an added split_var) still needs lint_on/lint_off around wire [1:0] w;:

module Foo(
  input  a,
  output b);

  wire [1:0] w /*verilator split_var*/;
  assign w = {{w[1'h0]}, {a}};
  assign b = w[1'h1];
endmodule

@wsnyder
Copy link
Member

wsnyder commented Feb 3, 2023

Chisel should be able to use

wire [1:0] w /*verilator split_var*/

and verilator will bitblast that signal and so you won't get UNOPTFLAT. Don't use that where you don't need it or the signal count would explode.

@seldridge
Copy link

seldridge commented Feb 3, 2023

🤔 We tried split_var and it didn't work for the output we are generating now (last example):

module Foo(
  input  a,
  output b);

  wire [1:0] w /*verilator split_var*/;
  assign w = {{w[1'h0]}, {a}};
  assign b = w[1'h1];
endmodule

This is still throwing the UNOPTFLAT warning:

# verilator -version && verilator -lint-only FalseCycle.sv
Verilator 5.002 2022-10-29 rev UNKNOWN.REV
%Warning-UNOPTFLAT: FalseCycle.sv:5:14: Signal unoptimizable: Circular combinational logic: 'Foo.w'
    5 |   wire [1:0] w /*verilator split_var*/ ;
      |              ^
                    ... For warning description see https://verilator.org/warn/UNOPTFLAT?v=5.002
                    ... Use "/* verilator lint_off UNOPTFLAT */" and lint_on around source to disable this message.
                    FalseCycle.sv:5:14:      Example path: Foo.w
                    FalseCycle.sv:6:12:      Example path: ASSIGNW
                    FalseCycle.sv:5:14:      Example path: Foo.w
%Error: Exiting due to 1 warning(s)

Is this supposed to work?

@seldridge
Copy link

seldridge commented Feb 3, 2023

Our main concern with selective application of the split_var is that we need to know when to do it based on when Verilator needs it. Verilator appears to need it in sometimes and it doesn't work in all situations. If we rewrite the above into multiple assignments, Verilator is happy with:

module Foo(
  input  a,
  output b);

  wire [1:0] w /*verilator split_var*/;
  assign w[0] = a;
  assign w[1] = w[0];
  assign b = w[1];
endmodule
# verilator --version && verilator -lint-only FalseCycle2.sv
Verilator 5.002 2022-10-29 rev UNKNOWN.REV

@wsnyder
Copy link
Member

wsnyder commented Feb 3, 2023

The split_var isn't operating because it sees the single assignment and doesn't see any point, that's probably generally the right decision but not here. Splitting the assigns fixes that problem. We could improve split_var but that doesn't seem to solve your larger problem. Even adding bit-by-bit unopt flat processing would still result in the statement executing multiple times - that is what event based simulators are doing too. I don't have any good recommendations beyond not creating code like this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: scheduling Issue involves scheduling/ordering of events effort: weeks Expect this issue to require weeks or more of invested effort to resolve type: feature-IEEE Request to add new feature, described in IEEE 1800 type: feature-non-IEEE Request to add new feature, outside IEEE 1800
Projects
None yet
Development

No branches or pull requests

6 participants