48. Absolute Value

module abs8_func (
    input  signed [7:0] a,
    output       [7:0] abs
);
    function [7:0] abs8;
        input signed [7:0] x;
        begin
            abs8 = (x < 0) ? -x : x;
        end
    endfunction

    assign abs = abs8(a);
endmodule

💡Remember

  • Verilog functions: one return value, no timing controls, great for pure combinational helpers.
  • Mark inputs/temps signed when doing signed math.
  • Two’s complement quirk: |-128| in 8 bits is still 8'h80 (wraps), which is fine for this exercise.

Testbench Code

`timescale 1ns/1ps

module tb_abs8_func;
    // 1) Inputs
    reg  signed [7:0] a;

    // 2) DUT outputs
    wire [7:0] abs;

    // 3) Expected (prefixed expected_)
    reg  [7:0] expected_abs;

    // 4) Mismatch signal (HIGH if outputs do not match expected)
    reg  mismatch;
    wire mismatch_w = (abs !== expected_abs);

    // Accounting
    integer TOTAL_TEST_CASES        = 0;
    integer TOTAL_PASSED_TEST_CASES = 0;
    integer TOTAL_FAILED_TEST_CASES = 0;

    // VCD limit
    integer VCD_MAX_CASES = 32;

    // DUT
    abs8_func dut(.a(a), .abs(abs));

    // ---------- Golden model (TB-only) ----------
    function [7:0] f_abs8;
        input signed [7:0] x;
        begin
            // Same semantics as the spec; wraps on -128
            f_abs8 = (x < 0) ? -x : x;
        end
    endfunction

    // VCD dump (Inputs -> Outputs -> Expected -> Mismatch)
    initial begin
        $dumpfile("tb_abs8_func.vcd");
        $dumpvars(0,
            tb_abs8_func.a,          // Inputs
            tb_abs8_func.abs,        // Outputs
            tb_abs8_func.expected_abs, // Expected
            tb_abs8_func.mismatch    // Mismatch
        );
        $dumpon; // start at #0
    end

    // Header + init
    initial begin
        a = 0; expected_abs = 0; mismatch = 0;
        $display("    a    |  abs  | expected_abs | mismatch");
        $display("------------------------------------------");
    end

    // Apply + check (compute expected BEFORE wait)
    task apply_and_check;
        input signed [7:0] ta;
        begin
            a = ta;

            expected_abs = f_abs8(ta); // compute expected first
            #1;                        // let DUT settle
            mismatch = mismatch_w;

            TOTAL_TEST_CASES = TOTAL_TEST_CASES + 1;
            if (!mismatch) TOTAL_PASSED_TEST_CASES = TOTAL_PASSED_TEST_CASES + 1;
            else           TOTAL_FAILED_TEST_CASES = TOTAL_FAILED_TEST_CASES + 1;

            $display("0x%02h(%4d) | 0x%02h |     0x%02h     |   %0d",
                     a[7:0], a, abs, expected_abs, mismatch);

            if (TOTAL_TEST_CASES == VCD_MAX_CASES) $dumpoff;
        end
    endtask

    integer i;
    integer seed;
    initial begin
        seed = 32'hACED_BEEF ^ $time;

        // Directed edge cases (printable truth table, < 20 lines total)
        apply_and_check(  0);      //  0
        apply_and_check(  1);      // +1
        apply_and_check( -1);      // -1
        apply_and_check(  7'd127); // +127 (0x7F)
        apply_and_check( -7'd127); // -127 (0x81)
        apply_and_check( -8'sd128);// -128 (0x80) -> stays 0x80
        apply_and_check(  8'h55);
        apply_and_check( -8'sd85); // -85

        // Small sweep around zero
        for (i = -5; i <= 5; i = i + 1)
            apply_and_check(i[7:0]);

        // A few randoms (keep total rows <= 32)
        repeat (6) apply_and_check($random(seed));

        // Summary logs
        $display("------------------------------------------");
        $display("TOTAL_TEST_CASES=%0d", TOTAL_TEST_CASES);
        $display("TOTAL_PASSED_TEST_CASES=%0d", TOTAL_PASSED_TEST_CASES);
        $display("TOTAL_FAILED_TEST_CASES=%0d", TOTAL_FAILED_TEST_CASES);
        $display("ALL_TEST_CASES_PASSED=%s", (TOTAL_FAILED_TEST_CASES==0) ? "true" : "false");

        #2 $finish;
    end
endmodule