Functions Cant Contain Non-Blocking Assignments Discovery

The difference between Verilog reg and Verilog wire frequently confuses many programmers just starting with the language (certainly confused me!). As a beginner, I was told to follow these guidelines, which seemed to generally work:

  • Use Verilog reg for left hand side (LHS) of signals assigned inside in always blocks
  • Use Verilog wire for LHS of signals assigned outside always blocks

Then when I adopted SystemVerilog for writing RTL designs, I was told everything can now be “type logic”. That again generally worked, but every now and then I would run into a cryptic error message about variables, nets, and assignment.

So I decided to find out exactly how these data types worked to write this article. I dug into the language reference manual, searched for the now-defunct Verilog-2005 standard document, and got into a bit of history lesson. Read on for my discovery of the differences between Verilog reg, Verilog wire, and SystemVerilog logic.

Verilog data types, Verilog reg, Verilog wire

Verilog data types are divided into two main groups: nets and variables. The distinction comes from how they are intended to represent different hardware structures.

A net data type represents a physical connection between structural entities (think a plain wire), such as between gates or between modules. It does not store any value. Its value is derived from what is being driven from its driver(s). Verilog wire is probably the most common net data type, although there are many other net data types such as tri, wand, supply0.

A variable data type generally represents a piece of storage. It holds a value assigned to it until the next assignment. Verilog reg is probably the most common variable data type. Verilog reg is generally used to model hardware registers (although it can also represent combinatorial logic, like inside an always@(*) block). Other variable data types include integer, time, real, realtime.

Almost all Verilog data types are 4-state, which means they can take on 4 values:

  • 0 represents a logic zero, or a false condition
  • 1 represents a logic one, or a true condition
  • X represents an unknown logic value
  • Z represents a high-impedance state

Verilog rule of thumb 1: use Verilog reg when you want to represent a piece of storage, and use Verilog wire when you want to represent a physical connection.

Assigning values to Verilog reg, Verilog wire

Verilog net data types can only be assigned values by continuous assignments. This means using constructs like continuous assignment statement (assign statement), or drive it from an output port. A continuous assignment drives a net similar to how a gate drives a net. The expression on the right hand side can be thought of as a combinatorial circuit that drives the net continuously.

Verilog variable data types can only be assigned values using procedural assignments. This means inside an always block, an initial block, a task, a function. The assignment occurs on some kind of trigger (like the posedge of a clock), after which the variable retains its value until the next assignment (at the next trigger). This makes variables ideal for modeling storage elements like flip-flops.

Verilog rule of thmb 2: drive a Verilog wire with assign statement or port output, and drive a Verilog reg from an always block. If you want to drive a physical connection with combinatorial logic inside an always@(*) block, then you have to declare the physical connection as Verilog reg.

SystemVerilog logic, data types, and data objects

SystemVerilog introduces a new 2-state data type—where only logic 0 and logic 1 are allowed, not X or Z—for testbench modeling. To distinguish the old Verilog 4-state behaviour, a new SystemVerilog logic data type is added to describe a generic 4-state data type.

What used to be data types in Verilog, like wire, reg, wand, are now called data objects in SystemVerilog. Wire, reg, wand (and almost all previous Verilog data types) are 4-state data objects. Bit, byte, shortint, int, longint are the new SystemVerilog 2-state data objects.

There are still the two main groups of data objects: nets and variables. All the Verilog data types (now data objects) that we are familiar with, since they are 4-state, should now properly also contain the SystemVerilog logic keyword.

There is a new way to declare variables, beginning with the keyword var. If the data type (2-state or 4-state) is not specified, then it is implicitly declared as logic. Below are some variable declaration examples. Although some don’t seem to be fully supported by tools.

Don’t worry too much about the var keyword. It was added for language preciseness (it’s what happens as a language evolves and language gurus strive to maintain backward-compatibility), and you’ll likely not see it in an RTL design.

I’m confused… Just tell me how I should use SystemVerilog logic!

After all that technical specification gobbledygook, I have good news if you’re using SystemVerilog for RTL design. For everyday usage in RTL design, you can pretty much forget all of that!

The SystemVerilog logic keyword standalone will declare a variable, but the rules have been rewritten such that you can pretty much use a variable everywhere in RTL design. Hence, you see in my example code from other articles, I use SystemVerilog logic to declare variables and ports.

When you use SystemVerilog logic standalone this way, there is another advantage of improved checking for unintended multiple drivers. Multiple assignments, or mixing continuous and procedural (always block) assignments, to a SystemVerilog variable is an error, which means you will most likely see a compile time error. Mixing and multiple assignments is allowed for a net. So if you really want a multiply-driven net you will need to declare it a wire.

In Verilog it was legal to have an assignment to a module output port (declared as Verilog wire or Verilog reg) from outside the module, or to have an assignment inside the module to a net declared as an input port. Both of these are frequently unintended wiring mistakes, causing contention. With SystemVerilog, an output port declared as SystemVerilog logic variable prohibits multiple drivers, and an assignment to an input port declared as SystemVerilog logic variable is also illegal. So if you make this kind of wiring mistake, you will likely again get a compile time error.

If you follow this rule, you can pretty much forget about the differences between Verilog reg and Verilog wire! (well, most of the time)


When I first wondered why it was possible to always write RTL using SystemVerilog logic keyword, I never expected it to become a major undertaking that involved reading and interpreting two different specifications, understanding complex language rules, and figuring out their nuances. At least I can say that the recommendations are easy to remember.

I hope this article gives you a good summary of Verilog reg, Verilog wire, SystemVerilog logic, their history, and a useful set of recommendations for RTL coding. I do not claim to be a Verilog or SystemVerilog language expert, so please do correct me if you felt I misinterpreted anything in the specifications.


Sample Source Code

The accompanying source code for this article is a SystemVerilog design and testbench toy example that demonstrates the difference between using Verilog reg, Verilog wire, and SystemVerilog logic to code design modules. Download the code to see how it works!

Download Article Companion Source Code

Get the FREE, EXECUTABLE test bench and source code for this article, notification of new articles, and more!



wire my_wire;                       // implicitly means "wire logic my_wire"

wire logic my_wire;                 // you can also declare it this way

wire[7:0]my_wire_bus;             // implicitly means "wire logic[15:0] my_wire_bus"

wire logic[7:0]my_wire_logic_bus;// you can also declare it this way

reg[15:0]my_reg_bus;              // implicitly means "reg logic[15:0] my_reg_bus"

//reg logic [15:0] my_reg_bus;        // but if you declare it fully, VCS 2014.10 doesn't like it

  // From the SV-2012 LRM Section 6.8

  varbytemy_byte;    // byte is 2-state, so this is a variable

  //  var v;           // implicitly means "var logic v;", but VCS 2014.10 doesn't like this

  varlogicv;         // this is okay

  //  var [15:0] vw;   // implicitly means "var logic [15:0] vw;", but VCS 2014.10 doesn't like this

  varlogic[15:0]vw;// this is okay

  varenumbit{clear,error}status;// variable of enumerated type

  varregr;                          // variable reg























module my_systemverilog_module


  input  logic       clk,

  input  logic       rst_n,

  input  logic       data_in_valid,

  input  logic[7:0]data_in_bus,

  output logic       data_out_valid,// driven by always_ff, it is a variable

  output logic[7:0]data_out_bus,   // driven by always_comb, it is a variable

  output logic       data_out_err    // also a variable, driven by continuous assignment (allowed in SV)



  assign data_out_err=1'b1; // continuous assignment to a variable (allowed in SV)

//  always_comb data_out_err = 1'b0;// multiple drivers to variable not allowed, get compile time error


  always_comb data_out_bus=<data_out_bus logic expression>;

  always_ff@(posedge clk,negedge rst_n)




      data_out_valid<=<data_out_valid logic expression>;



Jason Yu

SoC Design Engineer at Intel Corporation

Jason has 10 years' experience in the semiconductor industry, designing and verifying Solid State Drive controller SoC. His areas of workinclude microarchitecture and RTL design, dynamic and formal verification using UVM and Cadence JasperGold, and full-chip low power verification with UPF. Thoughts and opinions expressed in articles are personal and do not reflect that of Intel Corporation in any way.

Latest posts by Jason Yu (see all)

Categories SystemVerilog, VerilogTags data type

Cell Array Limitations for Code Generation

When you use cell arrays in MATLAB® code that is intended for code generation, you must adhere to these restrictions:

Cell Array Element Assignment

You must assign a cell array element on all execution paths before you use it. For example:

The code generator considers passing a cell array to a function or returning it from a function as a use of all elements of the cell array. Therefore, before you pass a cell array to a function or return it from a function, you must assign all of its elements. For example, the following code is not allowed because it does not assign a value to and is a function output.

The assignment of values to elements must be consistent on all execution paths. The following code is not allowed because is double on one execution path and char on the other execution path.

function z = foo(n) %#codegen c = cell(1,3); if n < 1 c{2} = 1; else c{2} = n; end z = c{2}; end
function c = foo() %#codegen c = cell(1,3); c{1} = 1; c{3} = 3; end
function y = foo(n) y = cell(1,3) if n > 1; y{1} = 1 y{2} = 2; y{3} = 3; else y{1} = 10; y{2} = 'a'; y{3} = 30; end

Definition of Variable-Size Cell Array by Using

For code generation, before you use a cell array element, you must assign a value to it. When you use to create a variable-size cell array, for example, , MATLAB assigns an empty matrix to each element. However, for code generation, the elements are unassigned. For code generation, after you use to create a variable-size cell array, you must assign all elements of the cell array before any use of the cell array. For example:

The code generator analyzes your code to determine whether all elements are assigned before the first use of the cell array. If the code generator detects that some elements are not assigned, code generation fails with a message like this message:

Unable to determine that every element of 'y' is assigned before this line.

Sometimes, even though your code assigns all elements of the cell array, the code generator reports this message because the analysis does not detect that all elements are assigned. See Unable to Determine That Every Element of Cell Array Is Assigned.

To avoid this error, follow these guidelines:

  • When you use to define a variable-size cell array, write code that follows this pattern:

    Here is the pattern for a multidimensional cell array:

    function z = mycell(n, j) %#codegen assert(n < 100); x = cell(1,n); for i = 1:n x{i} = i; end z = x{j}; end
    function z = mycell(m,n,p) %#codegen assert(m < 100); assert(n < 100); assert(p < 100); x = cell(m,n,p); for i = 1:m for j =1:n for k = 1:p x{i,j,k} = i+j+k; endendend z = x{m,n,p}; end
  • Increment or decrement the loop counter by .

  • Define the cell array within one loop or one set of nested loops. For example, this code is not allowed:

    function z = mycell(n, j) assert(n < 50); assert(j < 50); x = cell(1,n); for i = 1:5 x{i} = 5; endfor i = 6:n x{i} = 5; end z = x{j}; end
  • Use the same variables for the cell dimensions and loop initial and end values. For example, code generation fails for the following code because the cell creation uses and the loop end value uses :

    Rewrite the code to use for the cell creation and the loop end value:

    function z = mycell(n, j) assert(n < 50); assert(j < 50); x = cell(1,n); m = n; for i = 1:m x{i} = 2; end z = x{j}; end
    function z = mycell(n, j) assert(n < 50); assert(j < 50); x = cell(1,n); for i = 1:n x{i} = 2; end z = x{j}; end
  • Create the cell array with this pattern:

    Do not assign the cell array to a field of a structure or a property of an object. For example, this code is not allowed:

    Do not use the function inside the cell array constructor . For example, this code is not allowed:

    myobj.prop = cell(1,n) for i = 1:n ...end
  • The cell array creation and the loop that assigns values to the cell array elements must be together in a unique execution path. For example, the following code is not allowed.

    To fix this code, move the assignment loop inside the code block that creates the cell array.

    function z = mycell(n) assert(n < 100); if n > 3 c = cell(1,n); else c = cell(n,1); endfor i = 1:n c{i} = i; end z = c{n}; end
    function z = cellerr(n) assert(n < 100); if n > 3 c = cell( 1,n); for i = 1:n c{i} = i; endelse c = cell(n,1); for i = 1:n c{i} = i; endend z = c{n}; end
function z = mycell(n, j) %#codegen assert(n < 100); x = cell(1,n); for i = 1:n x{i} = i; end z = x{j}; end

Cell Array Indexing

  • You cannot index cell arrays by using smooth parentheses. Consider indexing cell arrays by using curly braces to access the contents of the cell.

  • You must index into heterogeneous cell arrays by using constant indices or by using -loops with constant bounds.

    For example, the following code is not allowed.

    You can index into a heterogeneous cell array in a -loop with constant bounds because the code generator unrolls the loop. Unrolling creates a separate copy of the loop body for each loop iteration, which makes the index in each loop iteration constant. However, if the -loop has a large body or it has many iterations, the unrolling can increase compile time and generate inefficient code.

    If and are constant, the following code shows indexing into a heterogeneous cell array in a -loop with constant bounds.

    x = {1, 'mytext'}; disp(x{randi});
    x = {1, 'mytext'}; for i = A:B disp(x{i}); end

Growing a Cell Array by Using {end + 1}

To grow a cell array , you can use . For example:

When you use to grow a cell array, follow these restrictions:

  • In a MATLAB Function block, do not use in a -loop.

  • Use only . Do not use , , and so on.

  • Use with vectors only. For example, the following code is not allowed because is a matrix, not a vector:

    ... X = {1 2; 3 4}; X{end + 1} = 5; ...
  • Use only with a variable. In the following code, does not cause to grow. In this case, the code generator treats as an out-of-bounds index into .

    ... X = {'a' { 1 2 3 }}; X{2}{end + 1} = 4; ...
  • When grows a cell array in a loop, the cell array must be variable-size. Therefore, the cell array must be homogeneous.

    This code is allowed because is homogeneous.

    This code is not allowed because is heterogeneous.

    ... X = {1 2}; for i=1:n X{end + 1} = 3; end...
    ... X = {1 'a' 2 'b'}; for i=1:n X{end + 1} = 3; end...
... X = {1 2}; X{end + 1} = 'a'; ...

Variable-Size Cell Arrays

  • Heterogeneous cell arrays cannot be variable-size.

  • If you use to make a variable-size cell array, define the cell array with curly braces. For example:

    Do not use the function. For example, this code is not allowed:

    ... c = {1 [2 3]}; coder.varsize('c') ...
    ... c = cell(1,3); coder.varsize('c') ...

Cell Array Contents

Cell arrays cannot contain . In a cell array, you cannot store a value that an extrinsic function returns.

Passing Cell Arrays to External C/C++ Functions

You cannot pass a cell array to . If a variable is an input argument to , define the variable as an array or structure instead of as a cell array.

Use in MATLAB Function Block

You cannot use cell arrays for Simulink® signals, parameters, or data store memory.

Related Topics

0 thoughts on “Functions Cant Contain Non-Blocking Assignments Discovery

Leave a Reply

Your email address will not be published. Required fields are marked *