MikePopoloski / slang

SystemVerilog compiler and language services
MIT License
550 stars 117 forks source link

Potential Misinterpretation of Assignment Types in Task Calls within Always Blocks #895

Closed yanggeorge closed 3 months ago

yanggeorge commented 3 months ago

Describe the bug The issue appears to be a potential misinterpretation in how the light task's output argument data2 is assigned within an always block in SystemVerilog. According to the provided code and context, the user expects the assignment to data2 in the light task to be non-blocking (due to the use of <=). However, slang's AST json interprets this assignment as a blocking assignment when light is called within the always block.

To Reproduce

module top;
  wire clk_40m;
  reg data2;
  wire [1:0] data1;

  always @(posedge clk_40m) begin
    light(data1, data2); // Call to task light
  end

  task light;
    input data1;
    output data2;

    begin
      data2 <= !data1; // Intended as non-blocking assignment in task
    end
  endtask
endmodule

Using slang --ast-json can generate an AST (Abstract Syntax Tree)

Additional context Below is a snippet of the AST JSON generated by the slang.

{
  "kind": "ExpressionStatement",
  "expr": {
    "kind": "Call",
    "type": "void",
    "subroutine": "3074964259656 light",
    "arguments": [
      {
        "kind": "Conversion",
        "type": "logic",
        "operand": {
          "kind": "NamedValue",
          "type": "logic[1:0]",
          "symbol": "3074964259176 data1"
        }
      },
      {
        "kind": "Assignment",
        "type": "reg",
        "left": {
          "kind": "NamedValue",
          "type": "reg",
          "symbol": "3074964258832 data2"
        },
        "right": {
          "kind": "EmptyArgument",
          "type": "logic"
        },
        "isNonBlocking": false // <-- Why is it always blocking here?
      }
    ]
  }
}
furkanusta commented 3 months ago

I've recently had something similar reported by Synopsys Spyglass linting tool where it considered task calls blocking even though all the assignments were non-blocking.

The reason given for it was that, output ports in a task are assigned back their values at the end of the task body. So even if you have a non-blacking assignment to data2 within the task, when the task finishes there is an additional blocking assignment to it even though in this case, in my case too there were no value change

yanggeorge commented 3 months ago

@furkanusta Thanks for your help. Additionally, there is another issue.

In this case, the always block is a timing process, which can be changed to always_ff. Doing so, the slang-tidy's AlwaysFFBlocking Check will issue a diagnostic warning under these circumstances.

source:7:3: warning: use of a blocking assignment for non-local variables inside always_ff
always_ff @(posedge clk_40m) begin
^

Therefore, I'm unsure how to modify this code to avoid triggering the warning.

MikePopoloski commented 3 months ago

furkanusta's answer is correct here. The lint check from slang-tidy is probably not considering this case and I wouldn't put much stock in the warning. In general the slang-tidy checks come with the risk of false positives, which is why they aren't put into the main slang tool.