File size: 4,893 Bytes
2b4ae64
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
115
116
117
118
119
120
121
122
123
124
125
126
`timescale 1ns/1ps

module tb_fp16_adder;
    reg  [15:0] a, b;
    wire [15:0] result;

    integer pass_count = 0;
    integer fail_count = 0;

    fp16_adder dut (.a(a), .b(b), .result(result));

    // FP16 constants
    // Format: 1 sign | 5 exponent | 10 mantissa
    localparam FP16_0p0    = 16'h0000;  //  0.0
    localparam FP16_1p0    = 16'h3C00;  //  1.0
    localparam FP16_2p0    = 16'h4000;  //  2.0
    localparam FP16_3p0    = 16'h4200;  //  3.0
    localparam FP16_4p0    = 16'h4400;  //  4.0
    localparam FP16_5p0    = 16'h4500;  //  5.0
    localparam FP16_6p0    = 16'h4600;  //  6.0
    localparam FP16_0p5    = 16'h3800;  //  0.5
    localparam FP16_1p5    = 16'h3E00;  //  1.5
    localparam FP16_0p25   = 16'h3400;  //  0.25
    localparam FP16_1p75   = 16'h3F00;  //  1.75
    localparam FP16_2p5    = 16'h4100;  //  2.5
    localparam FP16_3p5    = 16'h4300;  //  3.5
    localparam FP16_N1p0   = 16'hBC00;  // -1.0
    localparam FP16_N2p0   = 16'hC000;  // -2.0
    localparam FP16_N0p5   = 16'hB800;  // -0.5
    localparam FP16_INF    = 16'h7C00;  // +Inf
    localparam FP16_NINF   = 16'hFC00;  // -Inf
    localparam FP16_QNAN   = 16'h7E00;  // canonical quiet NaN

    task check;
        input [15:0] expected;
        input [63:0] test_id;
        begin
            #1;
            if (result === expected) begin
                $display("PASS: test %0d — a=0x%04h b=0x%04h result=0x%04h",
                         test_id, a, b, result);
                pass_count = pass_count + 1;
            end else begin
                $display("FAIL: test %0d — a=0x%04h b=0x%04h got=0x%04h expected=0x%04h",
                         test_id, a, b, result, expected);
                fail_count = fail_count + 1;
            end
        end
    endtask

    // Check NaN: any exponent=31 non-zero mantissa is acceptable
    task check_nan;
        input [63:0] test_id;
        begin
            #1;
            if (result[14:10] == 5'h1F && result[9:0] != 10'h0) begin
                $display("PASS: test %0d — NaN result=0x%04h (any NaN accepted)", test_id, result);
                pass_count = pass_count + 1;
            end else begin
                $display("FAIL: test %0d — expected NaN got=0x%04h (exp[14:10] should be 5'h1F with non-zero mantissa)",
                         test_id, result);
                fail_count = fail_count + 1;
            end
        end
    endtask

    initial begin
        // --- Basic same-sign additions ---
        a=FP16_1p0;  b=FP16_1p0;  check(FP16_2p0,  1);  // 1+1=2
        a=FP16_1p0;  b=FP16_0p5;  check(FP16_1p5,  2);  // 1+0.5=1.5
        a=FP16_1p5;  b=FP16_0p25; check(FP16_1p75, 3);  // 1.5+0.25=1.75
        a=FP16_2p0;  b=FP16_1p0;  check(FP16_3p0,  4);  // 2+1=3
        a=FP16_3p0;  b=FP16_3p0;  check(FP16_6p0,  5);  // 3+3=6 (carry-out → normalize)

        // --- Subtraction (opposite signs) ---
        a=FP16_1p0;  b=FP16_N1p0; check(FP16_0p0,  6);  // 1-1=0 (cancellation)
        a=FP16_2p0;  b=FP16_N1p0; check(FP16_1p0,  7);  // 2-1=1
        a=FP16_3p5;  b=FP16_N0p5; check(FP16_3p0,  8);  // 3.5-0.5=3 (normalization needed)
        a=FP16_2p5;  b=FP16_N1p0; check(FP16_1p5,  9);  // 2.5-1=1.5
        a=FP16_4p0;  b=FP16_N2p0; check(FP16_2p0, 10);  // 4-2=2

        // --- Zero operands ---
        a=FP16_0p0;  b=FP16_5p0;  check(FP16_5p0, 11);  // 0+5=5
        a=FP16_5p0;  b=FP16_0p0;  check(FP16_5p0, 12);  // 5+0=5
        a=FP16_0p0;  b=FP16_0p0;  check(FP16_0p0, 13);  // 0+0=0

        // --- Large exponent difference (alignment) ---
        // 4.0 (exp=17) + 0.25 (exp=13) — difference=4, shift 0.25 right by 4
        // 4.0 = 1.0000000000 × 2^2, 0.25 = 1.0000000000 × 2^-2
        // 0.25 aligned to exp=2: 1.0000000000 >> 4 = 0.0001000000
        // sum: 1.0000000000 + 0.0001000000 = 1.0001000000 × 2^2 = 4.25
        // 4.25 = 0_10001_0001000000 = 0x4440
        a=FP16_4p0;  b=FP16_0p25; check(16'h4440, 14);

        // --- Commutativity ---
        a=FP16_0p5;  b=FP16_1p0;  check(FP16_1p5,  15); // 0.5+1 same as 1+0.5

        // --- Negative + Negative ---
        a=FP16_N1p0; b=FP16_N1p0; check(FP16_N2p0, 16); // -1-1=-2

        // --- Special cases: Infinity ---
        a=FP16_1p0;  b=FP16_INF;  check(FP16_INF,  17); // finite+inf=inf
        a=FP16_INF;  b=FP16_1p0;  check(FP16_INF,  18); // inf+finite=inf
        a=FP16_NINF; b=FP16_1p0;  check(FP16_NINF, 19); // -inf+finite=-inf

        // --- Special case: inf - inf = NaN ---
        a=FP16_INF;  b=FP16_NINF;
        check_nan(20);

        // --- NaN propagation ---
        a=FP16_QNAN; b=FP16_1p0;
        check_nan(21);
        a=FP16_1p0;  b=FP16_QNAN;
        check_nan(22);

        $display("SUMMARY: %0d passed, %0d failed", pass_count, fail_count);
        $finish;
    end

    initial #10000 begin
        $display("FAIL: timeout");
        $finish;
    end

endmodule