Verification with Verilog
Table of Contents
-
4-bit Counter DUT Verification
- wire vs. reg
- Blocking vs. Non-blocking
- Synchronous vs. Asynchronous
- Verification Plan
- Manual Verification
- Test Bench -
256-bit Counter DUT Verification
- Verification Plan
- Manual Verification
- Test Bench
- Tasks and Functions
- System Tasks and Functions
Why are we doing verification with Verilog?
The RTL is in Verilog. Generally the flow of learning is Digitals -> RTL intro through Verilog -> Verifying the RTL using a TB. So, it is only logical to try to verify using what's already known until we hit a point where what we know is not enough (or probably not efficient at all) anymore!
4-bit Counter DUT Verification
module dut_4_bit_counter(
input clk,
input rstn,
output reg[3:0] c_out
);
always @ (posedge clk) begin
if(!rstn)
c_out <= 0; //synchronous active low reset
else
c_out <= c_out + 1; //non-blocking
end
In case of Verilog, the value a variable holds at any instant is determined by:
- whether multiple drivers driving this variable. In which case, the final value will depend on the resolution functions.
- how the variable is synced to the clock
wire vs. reg
- wire and reg are two different data types defined in Verilog.
- wire represents a connection between two concurrent processes (physically, it'll manifest as a net between two components). It should be continously driven (in verilog, it is done using 'assign' keyword), and it can't store values. It can be driven by multiple drivers simultaneously and the value on the wire at any instant is determined by the underlying resolution function(verilog provide option to decide strength of the driver).
- reg is a 1-bit 4-state variable. It is generally used to store data.
- It's not allowed to drive a reg type variable using 'assign' keyword. Instead, reg variables are assigned values using = or <= within procedural blocks (always, initial, task, function).
- A reg type will synthesize to a register only if it's linked to edge of clock. If it is linked to ALL the input signals and not clock, it'll synthesize to a combinational circuit. However, if all paths are not defined, it can inadvertently infer a latch, which is often undesirable.
To understand how this code is interpreted at synthesis level (without any optimizations), refer below block diagram:
module reg_wire_example( input clk, input a, input b, output c, output d ); wire temp_wire; reg i; // 1. Continuous assignment to wire 'temp_wire' assign temp_wire = a & b; // 2. Procedural block (sequential logic) always @(posedge clk) begin i <= a | b; end // 3. Assign 'c' (output) from 'temp_wire' (wire) assign c = temp_wire; // 4. Assign 'd' (output) from 'i' (reg) assign d = i; endmodule