|
|
|
|
|
|
|
|
|
|
|
Adding Reset Logic
|
|
|
Once we have the basic logic to allow us to see what our testbench is doing, we can next add the reset logic. If we look at the testcases, we see that we had added a constraint that it should be possible to activate reset anytime during simulation. To achieve this we have many approaches, but I am going to teach something that will go long way. There is something called 'events' in Verilog: events can be triggered, and also monitored, to see if an event has occurred. |
|
|
|
|
|
Let's code our reset logic in such a way that it waits for the trigger event "reset_trigger": when this event happens, reset logic asserts reset at negative edge of clock and de-asserts on next negative edge as shown in the code below. Also after de-asserting the reset, reset logic triggers another event called "reset_done_trigger". This trigger event can then be used somewhere else in the testbench to sync up. |
|
|
|
|
|
Code of reset logic
|
|
|
|
|
|
1 event reset_trigger;
2 event reset_done_trigger;
3
4 initial begin
5 forever begin
6 @ (reset_trigger);
7 @ (negedge clk);
8 reset = 1;
9 @ (negedge clk);
10 reset = 0;
11 -> reset_done_trigger;
12 end
13 end
You could download file counter_tb4.v here
|
|
|
|
|
|
|
|
|
|
|
|
Adding test case logic
|
|
|
Moving forward, let's add logic to generate the test cases, ok we have three testcases as in the first part of this tutorial. Let's list them again. |
|
|
|
|
|
- Reset Test : We can start with reset de-asserted, followed by asserting reset for few clock ticks and de-asserting the reset, See if counter sets its output to zero.
- Enable Test : Assert/de-assert enable after reset is applied.
- Random Assert/de-assert of enable and reset.
|
|
|
|
|
|
Repeating it again: "There are many ways" to code a test case, it all depends on the creativity of the Test bench designer. Let's take a simple approach and then slowly build upon it. |
|
|
|
|
|
Test Case 1 - Asserting/ De-asserting reset
|
|
|
In this test case, we will just trigger the event reset_trigger after 10 simulation units. |
|
|
|
|
|
1 initial
2 begin: TEST_CASE
3 #10 -> reset_trigger;
4 end
You could download file counter_tb5.v here
|
|
|
|
|
|
Test Case 2 - Assert/ De-assert enable after reset is applied.
|
|
|
In this test case, we will trigger the reset logic and wait for the reset logic to complete its operation, before we start driving the enable signal to logic 1. |
|
|
|
|
|
1 initial
2 begin: TEST_CASE
3 #10 -> reset_trigger;
4 @ (reset_done_trigger);
5 @ (negedge clk);
6 enable = 1;
7 repeat (10) begin
8 @ (negedge clk);
9 end
10 enable = 0;
11 end
You could download file counter_tb6.v here
|
|
|
|
|
|
Test Case 3 - Assert/De-assert enable and reset randomly.
|
|
|
In this testcase we assert the reset, and then randomly drive values on to enable and reset signal. |
|
|
|
|
|
1 initial
2 begin : TEST_CASE
3 #10 -> reset_trigger;
4 @ (reset_done_trigger);
5 fork
6 repeat (10) begin
7 @ (negedge clk);
8 enable = $random;
9 end
10 repeat (10) begin
11 @ (negedge clk);
12 reset = $random;
13 end
14 join
15 end
You could download file counter_tb7.v here
|
|
|
|
|
|
Well you might ask, do all this three test case exist in same file? Well, the answer is no. If we try to have all three test cases on one file, then we end up having race conditions due to three initial blocks driving reset and enable signal. So normally, once test bench coding is done, test cases are coded separately and included in testbench with `include directives as shown below. (There are better ways to do this, but you have to think how you want to do it). |
|
|
|
|
|
If you look closely at all the three test cases, you will find that even though test case execution is not complete, simulation terminates. To have better control, what we can do is adding an event like "terminate_sim" and execute $finish only when this event is triggered. We can trigger this event at the end of test case execution. The code for $finish now could look as shown below. |
|
|
|
|
|
1 event terminate_sim;
2 initial begin
3 @ (terminate_sim);
4 #5 $finish;
5 end
You could download file counter_tb8.v here
|
|
|
|
|
|
The modified test case #2 would be like: |
|
|
|
|
|
1 initial
2 begin: TEST_CASE
3 #10 -> reset_trigger;
4 @ (reset_done_trigger);
5 @ (negedge clk);
6 enable = 1;
7 repeat (10) begin
8 @ (negedge clk);
9 end
10 enable = 0;
11 #5 -> terminate_sim;
12 end
13
You could download file counter_tb9.v here
|
|
|
|
|
|
Second problem with the approach that we have taken till now is that we need to manually check the waveform and also the simulator output on the screen to see if the DUT is working correctly. Part IV shows how to automate this. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|