1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
// Contains the FAIL_UNLESS_EQUAL and RND_CHECK macros.
`include "macro.svh"
module testbench;
// [Step 1] Declare signals that connect to DUV. Intialize the clk signal with a value of 1'b0.
import typedef_pkg::*;
logic clk = 1'b0;
logic op_start;
logic [ 1:0] operation;
logic [ 7:0] operand_a;
logic [ 7:0] operand_b;
logic [15:0] result;
// [Step 2] Declare the scoreboard that holds the operation, operand_a, operand_b, and results values.
typedef struct {
operation_t operation;
logic [7:0] operand_a;
logic [7:0] operand_b;
logic [15:0] result;
} scoreboard_t;
// [Step 3] Instantiate the DUV module.
duv ALU0 (
.clk(clk),
.op_start(op_start),
.operation(operation),
.operand_a(operand_a),
.operand_b(operand_b),
.result(result)
);
// [Step 4] Always block to generate the clock.
always #1ns clk = ~clk;
// [Step 5] Implement the check task to check the scoreboard.
task check(input scoreboard_t sb);
automatic logic [15:0] expected_result;
case (sb.operation)
ADD: begin
expected_result = (sb.operand_a + sb.operand_b) & 16'h01FF;
`FAIL_UNLESS_EQUAL(expected_result, sb.result & 16'h01FF, $sformatf(
"ADD a=%0d b=%0d", sb.operand_a, sb.operand_b))
end
MULT: begin
expected_result = sb.operand_a * sb.operand_b;
`FAIL_UNLESS_EQUAL(expected_result, sb.result, $sformatf(
"MULT a=%0d b=%0d", sb.operand_a, sb.operand_b))
end
OR: begin
expected_result = (sb.operand_a | sb.operand_b) & 16'h00FF;
`FAIL_UNLESS_EQUAL(expected_result, sb.result & 16'h00FF, $sformatf(
"OR a=%0d b=%0d", sb.operand_a, sb.operand_b))
end
AND: begin
expected_result = (sb.operand_a & sb.operand_b) & 16'h00FF;
`FAIL_UNLESS_EQUAL(expected_result, sb.result & 16'h00FF, $sformatf(
"AND a=%0d b=%0d", sb.operand_a, sb.operand_b))
end
endcase
endtask
// [Step 6] Test the DUV using an initial block. Be sure to initialize all DUV input variables,
// and use the $finish system task to halt simulation at the end of the test.
initial begin
automatic scoreboard_t sb;
automatic int test_count = 0;
automatic logic [1:0] rnd_op;
automatic logic [7:0] rnd_a;
automatic logic [7:0] rnd_b;
// Initialise all inputs
op_start = 1'b0;
operation = ADD;
operand_a = 8'h00;
operand_b = 8'h00;
// Wait for initial setup
repeat (3) @(posedge clk);
// Randomised test loop
repeat (100) begin
`RND_CHECK(std::randomize(rnd_op, rnd_a, rnd_b))
// Log inputs to scoreboard
sb.operation = operation_t'(rnd_op);
sb.operand_a = rnd_a;
sb.operand_b = rnd_b;
// Drive DUV inputs and execute operation
operation = rnd_op;
operand_a = rnd_a;
operand_b = rnd_b;
op_start = 1'b1;
@(posedge clk);
op_start = 1'b0;
// Wait exactly two clock cycles for result
@(posedge clk);
@(posedge clk);
sb.result = result;
check(sb);
test_count += 1;
end
$display("All tests passed! Total tests: %0d", test_count);
$display("Finished Successfully!");
$finish;
end //:initial
endmodule : testbench
|