Why does SystemVerilog think 0.001 == 0?

Viewed 49

I'm trying to take the absolute value of a number. C, Python, Matlab, etc. all have this kind of thing built in, but in Verilog you have to make your own. So I write this:

function abs(shortreal x);
    if (x >= 0.0) begin 
        abs = x;
    end else begin 
        abs = -1 * x;
    end
endfunction

Nothing to screw up, right?

For some reason that is mysterious to me, this function is returning 0 when passed 0.001. How is this possible? 0.001 is obviously > 0. Moreover, it's far enough away from 0 that rounding error should not be a factor. The if statement should evaluate to true and abs = 0.001.

Does anyone know what is going on? Is this one of those things where the SV standard leaves a lot to the imagination so different language implementations behave differently? Sim is running on ModelSim 2020.1_3 in case it matters.

1 Answers

Since you did not explicitly declare the return type of your function, it returns a 1-bit value of type logic. This means that abs can only be the integer values 0 or 1, not a floating-point value (ignoring values x and z for this discussion).

You should change it to the desired return type, presumably shortreal:

Change:

function abs(shortreal x);

to:

function shortreal abs(shortreal x);

This behavior is clearly defined in the standard. Refer to IEEE Std 1800-2017, section 13.4 Functions:

In particular, the implicit syntax can be empty, in which case the return type is a logic scalar.

This shows that abs(0.001) returns 0.001:

module tb;

function shortreal abs(shortreal x);
    if (x >= 0.0) begin 
        abs = x;
    end else begin 
        abs = -1 * x;
    end
endfunction

initial begin
    shortreal a;
    a = abs(0.001);
    #1 $display(a);
end

endmodule
Related