What is the difference between new() and new[] in SystemVerilog?
The function new() is the class constructor function in SystemVerilog. It is defined in a class to initialize data members of the class. The new[] operator is used to allocate memory for a dynamic array. The size of the dynamic array that needs to be created is passed as an argument to the new[] .
What is the concept of forward declaration of a class in SystemVerilog?
Sometimes a class might reference another class which is not fully defined in the compile order. This can cause a compile error. For Example: If two classes Statistics and Packet are defined in following order, then while compiling Statistics class, the definition of packet is not yet seen and compiler will fail.
class Statistics;
Packet p1;
endclass
class Packet;
//full definition here
endclass
To avoid this problem, the Packet Class can be forward declared before the full definition.
This concept is called forward declaration.
typedef Packet; //forward declaration
class Statistics;
Packet p1;
endclass
class Packet;
//full definition here
endclass
What is the difference between private, public and protected data
members of a SystemVerilog class?
1) Private data members of a class can only be accessed from within the class.
These data members will not be visible in derived classes.
2) Public members can be accessed from within the class as well as outside the
class also. These are also visible in derived classes.
3) Protected data members are similar to private members in the sense that they
are only accessible within the class. However, unlike private members, these are
also visible in derived classes.
Are SystemVerilog class members public or private by default ?
SystemVerilog class members are public by-default, unlike other languages like C++/Java which have default data members as private.
What is a nested class and when would you use a nested class?
When the definition of a class contains another class definition, then that class is called a nested class. For example: In the code below, the StringList class definition contains
definition for another class Node.
class StringList;
class Node; // Nested class for a node in a linked list.
string name;
Node link;
endclass
endclass
Nesting allows hiding of local names and local allocation of resources. This is useful when a new type is needed as part of the implementation of a class.
What are interfaces in SystemVerilog?
The interface construct in SystemVerilog is a named bundle of nets of variables which helps in encapsulating communication between multiple design blocks. An interface can be instantiated in a design and can be connected using a single name instead of having all the port names and connections.
In addition to connectivity, functionality can also be abstracted in an interface as it supports defining functions that can be called by instantiating design for communication. Interfaces also support procedural ( always/initial blocks) and continuous assignments which are useful for verification in terms of adding protocol checks and assertions. Following is a simple example on how an interface can be defined.
interface ex_bus; // Define the interface
logic req, gnt;
logic [7:0] addr, data;
logic [1:0] mode;
logic start, rdy,idle;
endinterface: ex_bus
What is a modport construct in an interface?
modport (short form for module port) is a construct in an interface that let you group signals and specify directions. Following is an example of how an interface can be further grouped using modports for connecting to different components.
interface arb_if(input bit clk);
logic [1:0] grant, request;
logic reset;
modport TEST (output request, reset, input grant, clk);
modport DUT (input request, reset, clk, output grant);
modport MONITOR (input request, grant, reset, clk);
end interface
In this example, you can see that the same signals are given different directions in different modports. A monitor component needs all signals as input and hence the modport MONITOR of interface can be used to connect to monitor. A test or a driver will need to drive some signals and sample other signals and above example shows a modport TEST
that can be used
What is a clocking block and what are the benefits of using clocking
blocks inside an interface?
A clocking block is a construct that assembles all the signals that are sampled or synchronized by a common clock and define their timing behaviors with respect to the clock. Following example illustrates a simple clocking block.
clocking sample_cb @(posedge clk);
default input #1ns output #2ns;
input a1, a2;
output b1;
endclocking
In above example, we have defined a clocking block with name sample_cb and the clock associated with this clocking block is clk. The default keyword defines the default skew for inputs (2 ns) and output (3 ns). The input skew defines how many time units before the clock event the signal is sampled. The output skew defines how many time units after the clock event the signal will be driven.
A clocking block can be declared only inside a module or an interface.
What is the difference between following two ways of specifying skews
in a clocking block?
1) input #1 step req1;
2) input #1ns req1;
The clocking skew determines how many time units away from the clock event a signal is to be sampled (input skew) or driven (output skew). A skew can be specified in two forms – either explicitly in terms of time as in case 2) above, where the signal is sampled 1ns before the clock, OR in terms of time step as in case 1) above, where the step corresponds to global time precision (defined using `timescale directive)
What are the main regions inside a SystemVerilog simulation time step?
A SystemVerilog simulator is an event driven simulator and as the simulator advances in time, it needs to have a well-defined manner in which all events are scheduled and executed. In any event simulation, all the scheduled events at a specific time defines a time slot. A time slot is divided into a set of ordered regions to provide predictable interactions between the design and testbench code. A timeslot can be broadly divided into 5 major regions as shown below and each of the regions can be further subdivided into sub-regions.
1) Prepone: The preponed region is executed only once and is the first phase of
current time slot after advancing the simulation time. Sampling of signals from
design for testbench input happens in this region.
2) Active: The active region set consists of following sub regions – Active,
Inactive and the NBA (Nonblocking assignment) regions. RTL code and behavioral
code is scheduled in Active region. All blocking assignments are executed in
Active region. For nonblocking assignments, evaluation of RHS happens in Active region, while assignment happens in the NBA region. If there are any assignments with #0 delays, those happen in the Inactive region.
3) Observed: The Observed region is for evaluation of property expressions (used in concurrent assertions) when they are triggered. During property evaluation, pass/fail code is scheduled for later in the Reactive region of the current time slot
4) Reactive: The reactive region set (Re-active, Re-Inactive and Re-NBA) is used to schedule blocking assignments, #0 blocking assignments and nonblocking assignments included in SystemVerilog “program” blocks. This separate Reactive region ensures that all the design code evaluation (in Active region set) stabilizes before the testbench code in the program blocks is evaluated. With OVM/UVM
methodologies, there is no need of program blocks (with standard phasing of
testbench code) and hence Reactive region may not be used much.
5) Postponed: There is also a postponed region which is the last phase of current time slot. $monitor, $strobe and other similar events are scheduled for execution in this region. $display events are scheduled for execution in Active and Reactive regions (if called in program blocks).
What is a unique constraint in SystemVerilog?
A unique constraint is used to randomize a group of variables such that no two members of the group have the same value. Following shows an example: Here a class has a random array of bytes ( a ) and one another byte ( b ). The unique constraint in this example shows how unique values can be generated for all of these.
class Test;
rand byte unique[5];
rand byte b;
constraint ab_cons { unique {b, unique[0:5]}; }
endclass
How can we disable or enable constraints selectively in a class?
class ABC;
rand int length;
rand byte SA;
constraint c_length { length inside [1:64];}
constraint c_sa {SA inside [1:16];}
endclass
ABC abc = new();
abc.constraint_mode(0) // will turn off all constraints
abc.c_length.constraint_mode(0) // will turn off only length constraint
Given a Packet class with following constraints, how can we generate a
packet object with address value greater than 100?
class Packet;
rand bit[31:0] addr;
constraint c_addr { addr inside [0:100];}
endclass
Since default constraint restricts address to be less than 100, we will need to use inline
constraints and turn off default constraint as below:
Packet p = new();
p.c_addr.constraint_mode(0);
p.randomize with {addr > 100;};
What are pre_randomize() and post_randomize() functions?
These are built-in callback functions supported in SystemVerilog language to perform an action immediately either before every randomizecall or immediately after randomize call. A pre_randomize() is useful for setting or overriding any constraints while a post_randomize() is useful to override results of a randomization.
Given a 32 bit address field as a class member, write a constraint to
generate a random value such that it always has 10 bits as 1 and no two
bits next to each other should be 1
class packet;
rand bit[31:0] addr;
constraint c_addr {
$countones(addr) ==10;
foreach (addr[i])
if(addr[i] && i>0)
addr[i] != addr[i-1];
}
endclass
What is the difference between “fork – join”, “fork – join_any” and
“fork – join_none”?
SystemVerilog supports three types of dynamic processes that can be created at run-time
and executed as independent threads from the processes that spawned them.
1) fork .. join: Processes that are created using “fork .. join” run as separate
threads but the parent process that spawned them stall until a point where all
threads join back together. If we look at the example below: there are three
processes – task1, task2 and task3, that will run in-parallel and only after all three
of these complete, the $display() after the join statement will execute.
initial begin
fork
task1; // Process 1
task2; // Process 2
task3; // Process 3
join
$display(“All tasks finished”);
end
2) fork .. join_any: Processes that are created using “fork … join_any” run as
separate threads but the parent process that spawned those stalls only until any one
of the threads complete. Further, the remaining threads and the parent process can
run parallely. If we look at the example below: there are three processes – task1,
task2 and task3 that will run parallely. When one of task1/task2/task3 completes,
the join_any will complete and cause the $display() to execute while other tasks
might still be running.
initial begin
fork
task1; // Process 1
task2; // Process 2
task3; // Process 3
join_any
$display(“Any one of task1/2/3 finished”);
end
3) fork .. join_none: Processes that are created using “fork … join_none” run as
separate threads but the parent process that spawned them doesn’t stall and also
proceed parallely. Refer to the following example and there are three processes –
task1, task2 and task3 that will run parallely with the parent process. .
initial begin
fork
task1; // Process 1
task2; // Process 2
task3; // Process 3
join_none
$display(“All tasks launched and running”);
end
What is the use of “ wait fork” and “ disable fork” constructs?
When using a “ fork..join_none” or a “ fork..join_any”, sometimes we will want to synchronize the parent process with the dynamic threads running parallely and this can be
done using wait fork construct as follows:
initial begin
fork
task1; // Process 1
task2; // Process 2
join_none
$display(“All tasks launched and running”);
wait fork;
$display(“All sub-tasks finished now”);
end
Similarly, a disable fork can be used to prematurely stop the child forked dynamic
processes as shown below:
initial begin
fork
task1; // Process 1
task2; // Process 2
join_any
$display(“One of task1/2 completed ”);
disable fork;
$display(“All other tasks disable now”);
end
What is the difference between hard and soft constraints?
The normal constraints that are written in SystemVerilog classes are known as hard constraints, and the constraint solver need to always solve them or result in a failure if it cannot be solved. On the other hand, if a constraint is defined as soft, then the solver will try to satisfy it unless contradicted by another hard constraint or another soft constraint with a higher priority. Soft constraints are generally used to specify default values and distributions for random variables and can be overridden by specialized constraints.
class Packet;
rand int length;
constraint length_default_c { soft length inside {1,1024}; }
endclass
Packet p = new();
p.randomize() with { length == 1300; }
In the above example, if the default constraint was not defined as soft, then the call to randomize would have failed.