Illustrate a few important considerations in Verilog simulation regressions.
Simulation regressions are a vital part of the design cycle for digital circuits. Simulation regressions involve running a wide range of tests on a circuit design to determine how it behaves under different conditions.
There are several important considerations to keep in mind when executing simulation regressions, including:
- Test Coverage: The goal of a simulation regression is to test the circuit design thoroughly to ensure that it meets the required specifications. Therefore, test coverage is crucial to ensure that all the possible scenarios are simulated.
- Scalability: As the design of a digital circuit becomes more complex, the number of tests required to verify its functionality increases. Therefore, it is essential to ensure that simulation regressions are scalable, and the testbench can be easily modified as per the design.
- Debugging Capabilities: It is essential to have a comprehensive debugging capability to identify the faults encountered during simulation regression.
- Simulation Accuracy: The accuracy of the simulation directly impacts the breadth and depth of test coverage.
Illustrate the side effect of specifying delays in assign statements.
Delays are not synthesizable and synthesis tools ignore any kind of delays specified in assignment, blocking or non-blocking procedural statements. If the functionality depends upon the presence of the delay, then a mismatch in functional simulation will be seen between the model and the synthesized netlist.
z <= #5 x; // #5 will be ignored
#10 z <= x; // #10 will be ignored
Illustrate the side effects of multiple processes writing to the same variable.
In simulation, two always or initial blocks that write the same variable in the same time step race: the language does not define which one runs first, so the final value can differ between simulators. In synthesis, a variable assigned from two always blocks has two drivers, which most synthesis and lint tools reject with an error.
Partial updates and deadlocks are software-threading problems and do not apply here, since each assignment updates the whole variable at once.
Same variable used in two loops running simultaneously
The following code will have functional problems as the same variable is used and updated by two concurrent blocks, although it is syntactically correct.
module tb;
integer i; // Same variable updated by different initial blocks
initial begin
for (i = 0; i < 5; i = i+1) begin
#5 $display("Loop#1 : i=%0d", i);
end
end
initial begin
for (i = 0; i < 10; i = i+1) begin
#10 $display("Loop#2 : i=%0d", i);
end
end
endmodule
SystemVerilog allows you to declare the variable within the for loop thereby creating two different variables with "local" scope.
module tb;
initial begin
for (int i = 0; i < 5; i++) begin
#5 $display("Loop#1 : i=%0d", i);
end
end
initial begin
for (int i = 0; i < 10; i++) begin
#10 $display("Loop#2 : i=%0d", i);
end
end
endmodule
Illustrate the side effect of an implicit 1 bit wire declaration of a multi-bit port during instantiation
In hardware description languages, it is common to connect multi-bit ports between modules through wires. However, if the connection is made without explicitly declaring a wire with the correct number of bits, the language may interpret the connection as an implicit 1-bit wire. This can have unintended consequences.
For example, suppose a 4-bit output of ModuleA should drive a 4-bit input of ModuleB, but the connecting net is never declared:
module top;
// "bus" is never declared, so it becomes an implicit 1-bit wire
ModuleA A (.out(bus));
ModuleB B (.in(bus));
endmodule
Only bit 0 of A's 4-bit output gets through; the other bits of B's input no longer follow A. Most tools only warn about the width mismatch. The fix is to declare the net with the correct width:
module top;
wire [3:0] bus;
ModuleA A (.out(bus));
ModuleB B (.in(bus));
endmodule
Adding `default_nettype none at the top of each file turns undeclared nets like this into compile errors.
Explain what happens when width of state registers is not increased as more states gets added in a state machine.
In a state machine, the state register is used to store the current state of the machine. The number of state bits required in the register depends on the number of states in the machine. Forgetting to increase the width of state registers as more states get added in a state machine can lead to unintended consequences.
For example, if the number of state bits in the register is less than the number of states in the machine, some state bits will be lost. This truncation will cause some states to have the same encoding, resulting in incorrect behavior. This phenomenon is called state overlap. State overlap may go unnoticed during simulation or synthesis, but it can cause significant problems in hardware. It can result in incorrect operation, and in worst cases, it may cause the system to fail completely.
// BUG! If cur_state is not updated to a 4-bit variable
// there will be functional failure
reg [2:0] cur_state;
...
case(cur_state)
4'b0100 : // Move into Write phase
4'b1100 : // Move into Read phase
...
To avoid state overlap, the width of the state register should be increased as more states get added in the state machine. The number of bits required for the state register can be calculated by using the formula 2n >= number of states, where n is the number of bits in the state register.
What is the purpose of DPI ? Give an example.
DPI stands for Direct Programming Interface, and it is a feature of SystemVerilog that allows communication between the hardware design being simulated and external software applications. The purpose of DPI is to enable the hardware design being simulated to interact with software modules.
One example of the use of DPI is in co-simulation, where a hardware design is simulated alongside a software application that interacts with it. The software application could be running on a different platform or operating system, and it communicates with the hardware through the DPI interface. This allows software engineers to test their application with the hardware design in a controlled environment.
Another example of the use of DPI is for modeling user-defined protocols or interfaces. A SystemVerilog design can have modules that interact with other modules using DPI, allowing users to implement their own communication protocols or interfaces.
For instance, let's assume a SystemVerilog design has a module that performs cryptographic operations. The design can have a DPI function that interacts with software modules written in C (other languages such as Python have to be reached through a C layer), which perform data input/output (I/O) for this design. In this case, the software modules perform I/O operations such as reading inputs like cryptography keys or plaintext data from the user at runtime, which are fed to the module using the DPI interface. Once the cryptographic module completes its operation, it can return the output to the software through the same interface, allowing for efficient and flexible communication.
What is a parameter in Verilog?
In Verilog, a parameter is a named constant that is used to simplify the design by allowing commonly used values to be defined once and then used throughout the code. Parameters are defined using the parameter keyword and are typically declared at the beginning of the Verilog module.
For example, consider the following Verilog code that defines a simple NAND gate:
module nand_gate(output reg y, input a, input b);
parameter delay = 1; // Delay value for the gate
always @(a, b) begin
#delay y = ~(a & b); // NAND output after the specified delay
end
endmodule
In this code, the delay parameter is defined with a value of 1, which is then used to delay the output by one time unit in the always block.
Read more on Verilog Parameters.
Illustrate the side effect of not connecting all the ports during instantiation
An unconnected port in a module is called a dangling port or floating port, and unconnected input ports have high impedance and are evaluated to Z. If the input port is used in if else conditions with == operator, then it will evaluate to a logical false.
Leaving a port unconnected can lead to excessive power consumption and unwanted coupling between nearby signals. Furthermore, it may lead to timing issues, such as setup and hold time violations, which can cause incorrect data transfer or latching.
Read more on Verilog Module Instantiations.
Illustrate the side effect of leaving an input port unconnected that influences a logic to an output port.
An input port that is unconnected will have high impedance or the logic level Z in functional simulation, and synthesis tools will optimize away the logic that propagates beyond a floating input.
module X (input a, b, output c, d);
assign c = a & b;
assign d = a | b;
endmodule
module Y (input m, n, output o, p);
X u_x ( .a (), // input is left floating
.b (n),
.c (o),
.d (p));
endmodule
The above example will get synthesized such that m is not connected to any logic within the module Y and b is directly connected to d in X.