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

Continuous assignment from argumentless functions #67

Open
sifferman opened this issue Aug 2, 2023 · 2 comments
Open

Continuous assignment from argumentless functions #67

sifferman opened this issue Aug 2, 2023 · 2 comments

Comments

@sifferman
Copy link
Contributor

sifferman commented Aug 2, 2023

This is a dedicated location to discuss a potential addition to the style guide to cover the following edge case:

VCS (2020.12) will currently not run this correctly:

module test;

function automatic [7:0] test_func;
    test_func = 1;
endfunction

wire [7:0] test_wire = test_func();

initial begin
    #1;
    $display("Expected %h, Recieved %h", test_func(), test_wire);
    // Will fail because test_func() is never run
    $finish;
end

endmodule

Possible solutions

This is a summary of the discussion made in #66.

  • Disallow calling of functions from assign/wire. always_comb should be used instead. By @sifferman and @marnovandermaas
  • Disallow all wire assignments during declaration, (wire [7:0] test = test_func()). By @GregAC
  • Disallow argumentless functions. By @nbdd0121

Full explanation by @GregAC in #66 (comment)

I think I'd prefer to outright ban wire [7:0] test = test_func() type statements. This is because their semantics varies depending upon the net type. For wire you do get the equivilent to a continuous assignment but for logic it's just an initial value setting (much like an initial block though not identical! Those initial assignments are made before any initial blocks are run). Switching wire to logic may otherwise appear innocuous so better to avoid the complexity altogether. I note we explicitly allowed this currently:

It is permissible to use wire as a short-hand to both declare a net and perform
continuous assignment. Take care not to confuse continuous assignment with
initialization. For example:
👍
```systemverilog {.good}
wire [7:0] sum = a + b; // Continuous assignment
```
👎
```systemverilog {.bad}
logic [7:0] sum = a + b; // Initialization (not synthesizable)
```
`sum` is initialized to sum of initial values of a and b.
👍
```systemverilog {.good}
logic [7:0] acc = '0; // Initialization (synthesizable on some FPGA tools)
```
There are exceptions for places where `logic` is inappropriate. For example,
nets that connect to bidirectional (`inout`) ports must be declared with `wire`.
These exceptions should be justified with a short comment.

Initial assignments can be useful in FPGA but are deadly for ASIC synthesis as it's a great way to get simulation/synthesis mismatch where the FPGA version agrees with the simulation but the ASIC synthesis doesn't. If you confine them to an 'initial block at least it makes it far obvious you have one. We could consider saying initial blocks are only allowed in RTL that is strictly for FPGA usage (e.g. top-levels and wrappers etc that we may use on FPGA to instantiate IP)

@sifferman
Copy link
Contributor Author

@nbdd0121 Disallowing argumentless functions would work. I don't see many people using them. It seems the best use-case is just for style consistency for a group of related functions.

For example: https:/pulp-platform/riscv-dbg/blob/138d74bcaa90c70180c12215db3776813d2a95f2/src/dm_pkg.sv#L420-L437

 function automatic logic [31:0] csrr (csr_reg_t   csr,
                                        logic [4:0] dest);
    // rs1, CSRRS, rd, OpCode System
    return {csr, 5'h0, 3'h2, dest, 7'h73};
  endfunction

  function automatic logic [31:0] branch(logic [4:0]  src2,
                                         logic [4:0]  src1,
                                         logic [2:0]  funct3,
                                         logic [11:0] offset);
    // OpCode Branch
    return {offset[11], offset[9:4], src2, src1, funct3,
        offset[3:0], offset[10], 7'b11_000_11};
  endfunction

  function automatic logic [31:0] ebreak ();
    return 32'h00100073;
  endfunction

@sifferman
Copy link
Contributor Author

By @a-will in #66 (comment)

// Equivalent variable declarations with initial values.
logic foo = bar;
var logic foo = bar;

// Equivalent net declarations with continuous assignment.
wire foo = bar;
wire logic foo = bar;

Wow, I didn't know you could do this. I think this example should be added to the "Use logic for synthesis" section. It may help stress the importance of the rule a bit more

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant