summaryrefslogtreecommitdiff
path: root/lab_4/SRC/tb.sv
blob: 2e453842bb621e135c4ffbef4cdbf0d184f0328c (plain) (blame)
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