[Edit of Image1]
Hey it's a me again @drifter1!
Today we continue with the Logic Design series on SystemVerilog in order to cover some of the additional Control Flow that it provides. Many are directly derived from Verilog. Therefore, only those that are unique to SystemVerilog will be covered rigorously.
So, without further ado, let's dive straight into it!
Let's start off with the procedural blocks, which are similar to Verilog's.
Procedural statements can only be specified within procedural blocks, which in SystemVerilog are the following:
initial: Executes once at the beginning of the simulation
final: Executes once at the end of the simulation (unique to SystemVerilog)
- always blocks :
always_ff(unique to SystemVerilog)
task: Executed whenever the task is called
function: Executed whenever the function is called, and also returns an optional value
A final block is defined using the
final keyword. It specifies a procedural block of statements which is executed at the end of the simulation without delays. So, it's common to use it in order to display statistics about the simulation.
The syntax is:
final begin // statements to execute at // the end of the simulation end
always block in Verilog can be used for both combinational and sequential logic. This may lead to some unintended latches and design mistakes in general. In order to fix this issue SystemVerilog adds specialized always blocks that indicate the exact type of always block that is intented for simulation, synthesis and verification:
always_comb: combinational logic
always_latch: latch logic
always_ff: sequential logic
For all of them keep in mind that:
- the left hand-side variables can't be written to by other processes
- the blocks are automatically triggered at time zero after the initial and always blocks, so that the outputs are consistent with the inputs
When specifying combinational logic the sensitivity list can be omitted as it is inferred automatically from the expressions defined.
In order execute a section of code for more than once, loops are defined. It's also typical to specify a termination condition, so that the simulation doesn't run indefinitely.
SystemVerilog provides the following looping blocks:
forever: Executes the statements forever
repeat: Executes / repeats the statements for a given number of times
while: Executes the statements as long as a specified condition is true
for: Similar to a while loop, but it allows specifying the starting value and incremental expression.
do while: Executes the statements at least once and then loops as long as a specified condition is true
foreach: Iterates through all the elements of an array
The loops that are unique to SystemVerilog are thus the do while and foreach loops. Additionally, the for loop is enhanced allowing the for loop control variable to be declared within the for loop.
The enhanced SystemVerilog
for loop is exactly like a C for loop:
for (int i = 0; i < 4; i++) begin // loop code end
Do While Loop
do while loop is defined as:
do begin // loop code end while ([condition]);
foreach loop has the following syntax:
foreach (array[index]) begin // what to execute on each element end
For example, initializing each element of a 1D array
arr, to the value of their index can be done as follows:
foreach (arr[i]) begin arr[i] = i; end
SystemVerilog also adds the C-like jump statements:
break: break out of loop
continue: skip current and move to next loop iteration
return expression: exit from a function with a return value
return: exit from a task or a void function
All of these are statements and thus must be followed by an semicolon (
;) to be syntactically correct.
In addition to the usual
case conditional statements that Verilog provides, SystemVerilog also adds some additional forms that can report violations. Those are the
priority versions, which operate as follows:
unique: reports an error if none of the conditions match (and there is no explicit else) or more than one of the conditions match.
unique0: reports an error if more than one of the conditions match.
priority: reports an error if none of the conditions match (which are evaluated in sequential order). In the case of the if statement there's no else clause to the final if.
The syntax is simple. Add these keywords before the
case keyword respectively:
unique if ([condition]) unique case ([var]) // error when no condition matches // OR // more than one conditions match unique0 if ([condition]) unique0 case ([var]) // error when more than one conditions match priority if ([condition]) priority case ([var]) // error when no condition matches
Functions and Tasks
Functions and Tasks in SystemVerilog are the same as in Verilog, but some additional features are added, such as:
- Declare task and function ports like modules
- Function output and inout ports
- Void Functions
- Declare automatic variables with static tasks and functions, or static variables with automatic tasks and functions
- Passing arguments by reference, value, name and position
- Default argument values and optional arguments
- Multiple statements within a task or function without the need of fork-join logic
- Return from task or function before the end of the task or function
In Verilog the only way of passing a variable was by value, which basically meant that the argument's value was copied to the task or function memory space. In SystemVerilog this is done by simply specifying the name of the variable as the argument in both the definition and the call of the function or task:
function func_name; input var_name; // main body endfunction ... func_name (arg_name);
SystemVerilog also adds passing by reference, which is done by adding the keyword
ref in the argument definition:
function func_name(ref var_name) // main body endfunction
With this we also showcased the module-like definition of functions.
Next up is, SystemVerilog also allows passing arguments by name or by position. This is the same as connecting module ports using explicit mapping when instantiating them, allowing us to mix up the position and name of the arguments in the task or function call. So, this is basically done using the familiar
function func_name(ref var1, ref var2) // main body endfunction func_name(.var2(arg2), .var1(arg1));
Specifying a default value for each argument is as simple as adding an assigment statement to its definition:
function func_name(ref var_name = value) // main body endfunction
When there is such a default value specified then the argument can be omitted, basically becoming optional. It's also possible to have just empty parentheses
() when all arguments have defaults specified.
Block diagrams and other visualizations were made using draw.io
Previous articles of the series
- Introduction → Basic Syntax, Data Types, Operators, Modules
- Combinational Logic → Assign Statement, Always Block, Control Blocks, Gate-Level Modeling and Primitives, User-Defined Primitives
- Combinational Logic Examples → One Circuit - Four Implementations, Encoder, Decoder, Multiplexer
- Sequential Logic → Procedural Blocks (Initial, Always), Blocking and Non-Blocking Assignments, Statement Groups
- Sequential Logic Examples → Flip Flops (DFF, TFF, JKFF, SRFF), N-bit Counter, Single-Port RAM
- Finite-State Machines → Finite-State Machine (FSM), FSM Types, State Encoding, Modeling FSMs in Verilog
- Finite-State Machine Examples → Moore FSM Example (1 and 2 always blocks), Mealy FSM Example (1, 2 and 3 always blocks)
- Testbenches and Simulation → Testbenches (DUT / UUT, Syntax, Test Cases), System Tasks, Simulation Tools
- Combinational Logic Testbench Example → Half Adder Implementation, Testbench and Simulation
- Sequential Logic Testbench Example → Sequence Detector FSM Implementation, Testbench and Simulation
- Functions and Tasks → Function and Task Syntax, Calling, Rules, Examples
- Module Parameters and Generate Block → Parameterized Module (Parameters, Instantiation and Overriding Parameters), Generate Blocks (For, If, Case)
- Compiler Directives → Summary of Verilog's Compiler Directives (Include, Macros, Timescale, Conditional Compilation, etc.)
- Switch Level Modeling → Transistors, Switch Primitives (NMOS, PMOS, CMOS, Bidirectional, Resistive), Signal Strengths
- From Verilog To SystemVerilog → Data Types, Arrays, Structures, Operators and Expressions
Final words | Next up
And this is actually it for today's post!
Of course, there are more features in SystemVerilog that can be used to control the flow of the program, but these are the most common ones.
Next up are Processes, and maybe even Events...
Keep on drifting!
Posted with STEMGeeks