In the previous few articles, we have seen what a register model is and how it can be used to access registers in a given design. Let us see a complete example of how such a model can be written for a given design, how it can be integrated into the environment and how it can be used to write and read into design fields.
The following design has the following registers and fields that are accessible through an APB interface. The design essentially represents a traffic light controller which can be configured by writing into certain control registers.
The ctl register contains fields to start the module, and configure it to be in the blink yellow or blink red mode. The state register is read-only and returns current state of the design - yellow, red or green. The two timer registers stores the time between transition from each state. The profile bit allows the user to choose between the two programmed timer values. This can be useful for peak and off-peak times.
This is not a complete design since our purpose is simply to show how registers in this design can be read/written using a UVM register model. All the signals listed as the module ports belong to APB specification.
module traffic ( input pclk,
input presetn,
input [31:0] paddr,
input [31:0] pwdata,
input psel,
input pwrite,
input penable,
// Outputs
output [31:0] prdata);
reg [3:0] ctl_reg; // profile, blink_red, blink_yellow, mod_en RW
reg [1:0] stat_reg; // state[1:0]
reg [31:0] timer_0; // timer_g2y[31:20], timer_r2g[19:8], timer_y2r[7:0] RW
reg [31:0] timer_1; // timer_g2y[31:20], timer_r2g[19:8], timer_y2r[7:0] RW
reg [31:0] data_in;
reg [31:0] rdata_tmp;
// Set all registers to default values
always @ (posedge pclk) begin
if (!presetn) begin
data_in <= 0;
ctl_reg <= 0;
stat_reg <= 0;
timer_0 <= 32'hcafe_1234;
timer_1 <= 32'hface_5678;
end
end
// Capture write data
always @ (posedge pclk) begin
if (presetn & psel & penable)
if (pwrite)
case (paddr)
'h0 : ctl_reg <= pwdata;
'h4 : timer_0 <= pwdata;
'h8 : timer_1 <= pwdata;
'hc : stat_reg <= pwdata;
endcase
end
// Provide read data
always @ (penable) begin
if (psel & !pwrite)
case (paddr)
'h0 : rdata_tmp <= ctl_reg;
'h4 : rdata_tmp <= timer_0;
'h8 : rdata_tmp <= timer_1;
'hc : rdata_tmp <= stat_reg;
endcase
end
assign prdata = (psel & penable & !pwrite) ? rdata_tmp : 'hz;
endmodule
Interface
Let us declare an interface with signals in the APB protocol and this interface can be passed to the testbench as a virtual interface for the driver to drive some values to the design. To keep things simple, let us not declare clocking blocks and modports, although they are recommended in a real project.
SystemVerilog also has many other 2-state data types in addition to all the data types supported by Verilog. Most commonly used data types in modern testbenches are bit, int, logic and byte.
Integer
Integers are numbers without a fractional part or in other words, they are whole numbers. SystemVerilog has three new signed data types to hold integer values each with a different size. The smallest is shortint which can range from -32768 to 32767, and the largest is longint. The sign can be explicitly defined using the keywords signed and unsigned. Also they can be converted into one another by casting.
// ubyte is converted to signed type and assigned to si
si = signed' (ubyte);
Signed
By default, integer variables are signed in nature and hence can hold both positive and negative values.
module tb;
// By default int data types are signed which means
// that MSB is the sign bit and the integer variables can
// also store negative numbers
shortint var_a;
int var_b;
longint var_c;
initial begin
// Print initial values of the integer variables
$display ("Sizes var_a=%0d var_b=%0d var_c=%0d", $bits(var_a), $bits(var_b), $bits(var_c));
// Assign the maximum value for each of the variables
// MSB of each variable represents the sign bit and is set to 0
// Rest of the bit positions are filled with 1 and hence you
// get the maximum value that these variables can hold
#1 var_a = 'h7FFF;
var_b = 'h7FFF_FFFF;
var_c = 'h7FFF_FFFF_FFFF_FFFF;
// When added a 1, the sign changes to negative because this is a signed variable
#1 var_a += 1; // Value becomes 'h8000 => which is a rollover from + sign to - sign
var_b += 1; // Value becomes 'h8000_0000 => which is a rollover from + sign to - sign
var_c += 1;
end
// Start a monitor to print out values of each variables as they change
initial
$monitor ("var_a=%0d var_b=%0d var_c=%0d", var_a, var_b, var_c);
endmodule
The $bits system task returns the number of bits in a variable. Note that var_a, var_b and var_c roll over to the negative side.
SystemVerilog is an extension to Verilog and is also used as an HDL. Verilog has reg and wire data-types to describe hardware behavior. Since verification of hardware can become more complex and demanding, datatypes in Verilog are not sufficient to develop efficient testbenches and testcases. Hence SystemVerilog has extended Verilog by adding more C like data-types for better encapsulation and compactness.
There are many built-in methods in SystemVerilog to help in array searching and ordering.
Array manipulation methods simply iterate through the array elements and each element is used to evaluate the expression specified by the with clause. The iterator argument specifies a local variable that can be used within the with expression to refer to the current element in the iteration. If an argument is not provided, item is the name used by default.
Specifying an iterator argument without the with clause is illegal.
Array Locator Methods
The with clause and expresison is mandatory for some of these methods and for some others its optional.
Mandatory 'with' clause
These methods are used to filter out certain elements from an existing array based on a given expression. All such elements that satisfy the given expression is put into an array and returned. Hence the with clause is mandatory for the following methods.
Method name
Description
find()
Returns all elements satisfying the given expression
find_index()
Returns the indices of all elements satisfying the given expression
find_first()
Returns the first element satisfying the given expression
find_first_index()
Returns the index of the first element satisfying the given expression
find_last()
Returns the last element satisfying the given expression
find_last_index()
Returns the index of the last element satisfying the given expression
Example
module tb;
int array[9] = '{4, 7, 2, 5, 7, 1, 6, 3, 1};
int res[$];
initial begin
res = array.find(x) with (x > 3);
$display ("find(x) : %p", res);
res = array.find_index with (item == 4);
$display ("find_index : res[%0d] = 4", res[0]);
res = array.find_first with (item < 5 & item >= 3);
$display ("find_first : %p", res);
res = array.find_first_index(x) with (x > 5);
$display ("find_first_index: %p", res);
res = array.find_last with (item <= 7 & item > 3);
$display ("find_last : %p", res);
res = array.find_last_index(x) with (x < 3);
$display ("find_last_index : %p", res);
end
endmodule
Hardware Description Languages (HDL) like Verilog and VHDL are used to describe hardware behavior so that it can be converted to digital blocks made up of combinational gates and sequential elements. In order to verify that the hardware description in HDL is correct, there is a need for a language with more features in OOP that will support complicated testing procedures and is often called a Hardware Verification Language.
SystemVerilog is an extension of Verilog with many such verification features that allow engineers to verify the design using complex testbench structures and random stimuli in simulation.
Why is Verilog not preferred ?
Back in the 1990's, Verilog was the primary language to verify functionality of designs that were small, not very complex and had less features. As design complexity increases, so does the requirement of better tools to design and verify it. SystemVerilog is far superior to Verilog because of its ability to perform constrained random stimuli, use OOP features in testbench construction, functional coverage, assertions among many others.
What is verification ?
Verification is the process of ensuring that a given hardware design works as expected. Chip design is a very extensive and time consuming process and costs millions to fabricate. Functional defects in the design if caught at an earlier stage in the design process will help save costs. If a bug is found later on in the design flow, then all of the design steps have to be repeated again which will use up more resources, money and time. If the entire design flow has to be repeated, then its called a respin of the chip.
What about Vera, e, and other similar HVL ?
They have been in use for some time. SystemVerilog can be considered an extension of Verilog (the most popular HDL), and it makes sense to verify a Verilog design in SystemVerilog. Also SystemVerilog supports OOP which makes verification of designs at a higher level of abstraction possible.