Convert IEEE Double to Integer – Verilog

conversionfloating pointverilogxilinx

I want to convert the IEEE Double value computed in my code to Integer.

E.g. I have computed: X = 64'hxxxxxxxxxxxxxxxx; Now i want to use it as index of an array as: some_array[X];

How can I do it? Is there any IP-Core or any other third-party Core for this conversion? Or some synthesis-able method/algorithm?

Best Answer

Assuming your number is normalized, it's positive and it's not a NaN or infinity or some other non convertible pattern, you have to take the mantissa, add a "1" bit at the left of it, and take as many bits of it as the value in the exponent says. The reulting number is the integer version of your number. To round it, check the first bit discarded (the one at the right of the last bit taken from the mantissa) and add it to the integer (using integer addition)

Something like this:

module double2int(
    input clk,
    input rst,
    input [63:0] vin,
    output reg [52:0] vout,
    output reg done,
    output reg error
    );

    wire sign = vin[63];
    wire [10:0] exponent = vin[62:52];
    wire [51:0] binaryfraction = vin[51:0];
    wire [52:0] mantissa = {1'b1,binaryfraction};

    reg [5:0] cnt;
    reg start = 1'b0;
    reg round;
    always @(posedge clk) begin
        if (rst) begin
            if (sign==1'b0 && exponent >= 11'd1023 && exponent <= 11'd1075) begin
            // only convert positive numbers between 0 and 2^52
                cnt <= 52 - (exponent - 11'd1023); // how many bits to discard from mantissa
                {vout,round} <= {mantissa,1'b0};
                start <= 1'b1;
                done <= 1'b0;
                error <= 1'b0;
            end
            else begin
                start <= 1'b0;
                error <= 1'b1;
            end
        end
        else if (start) begin
            if (cnt != 0) begin  // not finished yet?
                cnt <= cnt - 1;  // count one bit to discard
                {vout,round} <= {1'b0, vout[52:0]}; // and discard it (bit just discarded goes into "round")
            end
            else begin  // finished discarding bits then?
                if (round)  // if last bit discarded was high, increment vout
                    vout <= vout + 1;
                start <= 1'b0;
                done <= 1'b1; // signal we're done
            end
        end
    end
endmodule

I've used this to test bench the module. Just use this webpage to find the hexadecimal representation of a given number and place it into the test bench source code. Simulate the circuit and you will get the plain binary value of the closest integer to your double number:

module tb_double2int;

    // Inputs
    reg clk;
    reg rst;
    reg [63:0] vin;

    // Outputs
    wire [52:0] vout;
    wire error;
    wire done;

    // Instantiate the Unit Under Test (UUT)
    double2int uut (
        .clk(clk), 
        .rst(rst), 
        .vin(vin), 
        .vout(vout), 
        .done(done),
        .error(error)
    );

    initial begin
        // Initialize Inputs
        clk = 0;
        rst = 0;
        vin = 0;

        // Add stimulus here
        vin = 64'h4058F22D0E560419;  // Example: 99.784 . Must return 100d in vout (binary 0000....00000001100100)
        rst = 1;
        #20;
        rst = 0;
        if (!error)
            @(posedge done);
        @(posedge clk);
        $finish;
    end

    always begin
        clk = #5 !clk;
    end      
endmodule