First, Let's try to understand what actually is “Constrained Random verification”.
As chip designs get more complex day by day, Traditional verification methods started failing the main verification objective of catching bugs.
This is because it is nearly impossible to simulate all the permutations and combinations of the inputs because of the time-market frame and resource utilization etc. This is when Constrained Random verification started gaining attention.
Let's take an example of a 5:7 decoder, which is going to be our DUT(Design Under Test). Now let's say we try to do the testing in the traditional method using a testbench, we will have to test out all the possible cases (that is 25 = 32 combinations) to make sure that there are no bugs in the design.It will be a little tedious to test them all.
Here is where the concept of “constrained random verification” comes in handy.
This concept will allow us to generate random inputs. For 32 combinations it wouldn’t matter as its trivial but when it comes to 1000’s sequences in the case of SoC’s/ASIC, we can’t afford to do all the sequences, we can’t just blindly randomize everything hence the concept of “Constrained” to cover all the corner cases, which gives us more confidence.
With the below RTL design of the 5:7 decoder, we are assigning whenever an invalid input(Data_in) is given - we get a 0 at all the output ports else the valid cases.
Verification of circuit design takes place by comparing the desired result with passing the test input to the DUT. But, if we observe we have only 7 valid test cases rest are invalid, so constraining and checking randomly is more efficient to get a confirmation of the design’s functionality.
module decoder5to7(
input [5:0] Data_in, // inputs
output reg [6:0] Data_out // outputs
);
//Whenever there is a change in the Data_in, execute the always block.
always @(Data_in)
case (Data_in)
5'b00000 : Data_out = 7'b0000001;
5'b01001 : Data_out = 7'b0000010;
5'b10010 : Data_out = 7'b0000100;
5'b00011 : Data_out = 7'b0001000;
5'b10100 : Data_out = 7'b0010000;
5'b01101 : Data_out = 7'b0100000;
5'b10110 : Data_out = 7'b1000000;
//To make sure that latches are not created.
default : Data_out = 7'b0000000;
endcase
endmodule
A 5:7 decoder is simple and just requires hardly a few minutes to test its functionality. Think of some complex circuits like finite state machines that do some complex task or 32-bit adders, which require many test cases to be tested upon. Manually verifying the logic by giving a set of inputs and comparing it with the expected one is tedious in this case because there are many
different cases to test on with a lot of input bits, and even if we randomize we have a lot of cases to consider which is again time-consuming, so constraining the randomized inputs and checking for critical corner cases will help the verification team a lot.
We got an understanding with respect to a combinational block, now lets look with a perspective of a sequential block, let us consider the importance of randomization via an erroneous Finite State Machine (FSM) specification.
In creating an FSM, the design methodology, broadly identified, is as follows.
- Identifying distinct states.
- Creating a state transition diagram.
- Choosing state encoding.
- Writing combinational logic for next-state logic.
- Writing combinational logic for output signals.
A very accessible resource for an in-depth discussion on the topic of FSMs, is Finite State Machines in Hardware, by Volnei A. Pedroni.
FSMs based on complex algorithms inherit that complexity in their implementation. Therefore, for a designer, modeling the transitions correctly is difficult and their designed state diagrams might deviate from the valid state diagrams.
In a diligent verification process, it is important for us to look into all the possible transitions with different transition sequences, preferably in a random but traceable fashion, i.e., pseudo-random. We will cover this a little later, again in this blog.
Let us take a practical example of state diagram under specification,
There’s an integer ‘t’, produced by a counter to represent the time, which is a transition control signal in our case.