Introduction to SystemVerilog #
SystemVerilog is an extension of the Verilog hardware description language (HDL) widely used in the design and verification of digital systems. It combines the features of Verilog with new constructs to provide a more powerful and efficient language for designing complex digital systems.
Background #
-
Originally introduced as an extension to Verilog in 2002, SystemVerilog has become the industry standard for hardware design and verification.
-
One of the key features of SystemVerilog is its support for both design and verification. It provides an enhanced set of constructs for specifying the behavior, structure, and timing of digital systems.
-
On the verification side, SystemVerilog offers advanced features for creating testbenches and verifying a design. It provides constructs for specifying test scenarios, checking assertions, and generating random stimuli to thoroughly test the functionality and performance of a design.
-
SystemVerilog also incorporates object-oriented programming (OOP) concepts, allowing for the creation of reusable and modular code. It introduces new data types, such as classes and structures, that enable designers and verification engineers to build more sophisticated and scalable models.
Quickstart #
Modules and Ports #
In SystemVerilog, a module is a fundamental building block used to describe a hardware component. It encapsulates the functionality and behavior of a digital circuit or sub-circuit. Modules can be interconnected to form larger systems.
Here’s an example of a simple module that represents a 2-to-1 multiplexer:
module mux2to1(input wire a, b, sel, output reg y);
always @(a, b, sel)
case (sel)
1'b0: y = a;
1'b1: y = b;
endcase
endmodule
In this example, the mux2to1
module takes three input wires (a
, b
, and sel
) and one output register (y
). The always
block describes the behavior of the module using a case statement. Depending on the value of the sel
signal, either a
or b
is selected as the output y
.
Data Types #
SystemVerilog provides various data types to represent different types of signals and values. Some commonly used data types include:
-
wire
:- Wires are used to represent connections between different modules.
- They can be used for both input and output signals.
- Wires are typically used for continuous assignments or connecting modules.
-
reg
:- Unlike its name suggests, reg is not limited to sequential storage elements.
reg
can represent combinational logic or storage elements, depending on the context.- It is commonly used for representing state variables or outputs of procedural blocks.
-
integer
:integer
is a 32-bit signed data type, used for representing signed or unsigned integer values.- It can be used for variables that require mathematical operations or counting.
- Unlike
wire
orreg
,integer
is not directly used for connecting modules but rather for internal computations.
-
bit
:bit
is a single-bit data type, allowing only two values: 0 or 1.- It is often used for representing control signals or flags.
bit
data type is useful when precise control is required over a single binary value.
-
logic
:- logic is a flexible and versatile data type that supports a wide range of bit-vector operations.
- It allows the representation of multiple bits or vectors.
logic
supports a 4-state value system: 0, 1, X (unknown), and Z (high-impedance).- It is commonly used for designing complex digital circuits and modeling bus structures.
module data_types_example;
wire a, b;
reg [7:0] data;
integer count;
bit enable;
logic [3:0] vector;
...
endmodule
Continuous Assignments #
Continuous assignments in SystemVerilog allow you to describe combinational logic. They assign values to wires based on Boolean expressions or connections to other signals.
Here’s an example of a simple AND gate implemented using continuous assignments:
module and_gate(input wire a, b, output wire y);
assign y = a & b;
endmodule
In this example, the assign
statement assigns the logical AND of input signals a
and b
to the output signal y
.
Behavioral Modeling #
SystemVerilog allows for behavioral modeling using procedural blocks such as always
and initial
. These blocks describe the behavior of the design based on certain conditions and events.
Here’s an example that demonstrates a basic counter using a procedural always
block:
module counter(input wire clk, input wire reset, output reg [3:0] count);
always @(posedge clk or posedge reset) begin
if (reset)
count <= 4'b0;
else
count <= count + 1;
endmodule
In this example, the always
block triggers on the positive edge of the clk
signal or the positive edge of the reset
signal. If the reset
signal is asserted, the counter is reset to zero. Otherwise, the counter increments by one on each clock cycle.
More about always
#
The always
block is a fundamental construct in SystemVerilog, allowing designers to specify the behavior of digital circuits.
- Sensitivity List:
The sensitivity list determines when the
always
block is triggered. It specifies the signals or events that the block depends on. SystemVerilog provides several options for specifying the sensitivity list:always @(*)
: This sensitivity list includes all signals in the block and triggers whenever any of those signals change.always @(posedge clk)
: This sensitivity list triggers the block on the positive edge of the clock signal.always @(a, b)
: This sensitivity list triggers when the signalsa
orb
change.
It is important to select an appropriate sensitivity list to ensure accurate modeling of the circuit’s behavior.
- Blocking vs. Non-Blocking Assignments:
SystemVerilog provides two types of assignments within the
always
block: blocking (=
) and non-blocking (<=
). It is crucial to understand the difference between them to ensure proper modeling of sequential logic.
- Blocking assignments: A blocking assignment (
=
) executes immediately, blocking the execution of subsequent statements until it completes. It is used for combinational logic or when the order of execution matters. - Non-blocking assignments: A non-blocking assignment (
<=
) schedules the assignment to occur at the end of the time step, allowing all other assignments in thealways
block to occur concurrently. It is typically used for modeling sequential elements, such as flip-flops or registers.
Understanding the distinction between blocking and non-blocking assignments is essential for accurately modeling sequential behavior.
example below demonstrates the usage of the always
block for modeling a D flip-flop:
module d_flip_flop(input wire d, clk, reset, output reg q);
always @(posedge clk or posedge reset) begin
if (reset)
q <= 1'b0; // Reset the output to 0 when reset signal is asserted
else
q <= d; // Assign the input to the output on the positive edge of the clock
end
endmodule
Conditional Statements, Loops, and Initial Blocks #
These constructs are essential for controlling the flow of execution and initializing variables in hardware description languages.
If-Else Statements #
The if-else statement allows you to make decisions based on conditions. Here’s the syntax:
if (condition1) begin
// code block executed when condition1 is true
end
else if (condition2) begin
// code block executed when condition2 is true
end
else begin
// code block executed when none of the conditions are true
end
While Loops #
The while loop allows you to repeat a set of statements while a condition is true. Here’s the syntax:
while (condition) begin
// code block to be repeated while condition is true
end
For Loops #
The for loop allows you to repeat a set of statements for a specified range. Here’s the syntax:
for (initialization; condition; increment) begin
// code block to be repeated
end
Case Statements #
The case statement allows you to perform different actions based on the value of a variable. Here’s the syntax:
case (variable)
value1: begin
// code block executed when variable matches value1
end
value2: begin
// code block executed when variable matches value2
end
default: begin
// code block executed when none of the values match
end
endcase
Repeat Loops #
The repeat loop allows you to repeat a set of statements a specific number of times. Here’s the syntax:
repeat (n) begin
// code block to be repeated n times
end
Initial Blocks #
The initial block is used to initialize variables at the beginning of simulation. Here’s the syntax:
initial begin
// code block containing initialization statements
end
Notes on what is Synthesizable #
initial
blocks are not synthesizable in SystemVerilog. Initial blocks are used for simulation purposes and are not meant to be synthesized into hardware. They are typically used to initialize variables and perform testbench-related tasks during simulation.
The repeat
statement is also not synthesizable in SystemVerilog. The repeat statement is used for specifying a fixed number of iterations in a simulation loop. It is not intended to be used for describing hardware behavior.
During synthesis, the synthesizer converts the hardware description written in RTL (Register Transfer Level) into a gate-level representation. The purpose of synthesis is to generate the actual hardware implementation of the design.
Operators #
Operator | Description |
---|---|
+ | Addition |
- | Subtraction |
* | Multiplication |
/ | Division |
% | Modulo (Remainder) |
** | Exponentiation |
+ 1 | Increment by 1 |
- 1 | Decrement by 1 |
++ | Pre-increment |
– | Pre-decrement |
+= | Addition assignment |
-= | Subtraction assignment |
*= | Multiplication assignment |
/= | Division assignment |
%= | Modulo assignment |
~ | Bitwise NOT |
& | Bitwise AND |
| | Bitwise OR |
^ | Bitwise XOR |
~^ | Bitwise XNOR |
<< |
Bitwise left shift |
>> |
Bitwise right shift |
<<< |
Logical left shift |
>>> |
Logical right shift |
&~ | Bitwise AND NOT |
~& | Bitwise NAND |
|~ | Bitwise OR NOT |
~| | Bitwise NOR |
=== | Case equality |
!== | Case inequality |