Convertir IEEE doble a entero - Verilog

0

Quiero convertir el valor doble de IEEE calculado en mi código a entero.

Por ejemplo, He calculado: X = 64'hxxxxxxxxxxxxxxxx; Ahora quiero usarlo como índice de una matriz como: some_array [X];

¿Cómo puedo hacerlo? ¿Hay algún IP-Core o algún otro Core de terceros para esta conversión? ¿O algún método / algoritmo capaz de síntesis?

    
pregunta user263210

4 respuestas

1

Suponiendo que su número está normalizado, es positivo y no es un NaN o infinito o algún otro patrón no convertible, debe tomar la mantisa, agregar un bit "1" a la izquierda y tomar tantos bits de Es como dice el valor en el exponente. El número resultante es la versión entera de su número. Para redondearlo, verifique el primer bit descartado (el que se encuentra a la derecha del último bit tomado de la mantisa) y agréguelo al entero (usando la suma de enteros)

Algo como esto:

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

He usado esto para probar el módulo. Solo use esta página web para encontrar la representación hexadecimal de un número dado y colóquela en el código fuente del banco de pruebas. Simule el circuito y obtendrá el valor binario simple del entero más cercano a su número doble:

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
    
respondido por el mcleod_ideafix
1

Si desea truncar el valor al siguiente entero más bajo, primero observe si el exponente hace que el número sea menor que 1.0 o mayor que el tamaño de su matriz, y maneje esos valores adecuadamente.

Si el exponente se encuentra entre esos valores, alimente la parte más a la izquierda de la mantisa, con un "1" concatenado a su izquierda, en un desplazador de modo que el máximo exponente no produzca ningún cambio, un exponente que sea uno más pequeño cambiaría en un lugar, etc. La salida de la palanca de cambios será el índice de la matriz.

Si desea aproximar el redondeo, debe aumentar su valor de índice deseado en un factor de dos; después de calcular el valor escalado, agregue uno y divida por dos. Esto redondeará 0.5 a 1, 1.5 a 2 y 2.5 a 3.

Si desea admitir el redondeo exacto de IEEE, además de lo anterior, deberá "O" agrupar todos los bits que eran demasiado pequeños como para que valga la pena incluirlos en el desplazamiento, así como los bits que " Se cayó del final "de la palanca de cambios. En lugar de agregar uno incondicionalmente al valor escalado, solo agregue uno si el "OR" mencionado anteriormente es verdadero. Esto hará 0.5 redondeado a 0, y tanto 1.5 como 2.5 redondearán a 2.

    
respondido por el supercat
0

He usado vectores como puntero a matrices todo el tiempo ... nunca tuve que lidiar con un puntero de 64b de ancho. ¿Cuál es la profundidad de tu matriz?

Por ejemplo:

wire [7:0] buffer [255:0]; // Here we have an array of say 256 bytes
wire [7:0] ptr; // here's out pointer into that array (needs to be log2(256))
wire [7:0] byte_read;

assign ptr = 8'h05;
assign byte_read = buff[ptr]; // grab the 5th byte from the array
    
respondido por el ajcrm125
0

Debe convertir el número de precisión doble de 64 bits en un índice entero dentro de los límites de su índice de matriz. Depende de usted, el rango de sus números reales y los límites de some_array cómo definir la función de conversión. Lo ideal es que desee una asignación de uno a uno, pero si el valor de su índice es pequeño, obviamente tendrá superposiciones.

Supongamos que define some_array como:

logic [N-1:0] some_array;

Luego, más adelante en tu código:

index = ConvertToIndex(X);
some_array[index] = 1'b1;

ConvertToIndex es una función. Por ejemplo, puede simplemente multiplicar la entrada por un valor constante y luego redondearlo al entero más cercano, que se ajusta al índice de su matriz.

function logic [$clog2(N)-1:0] ConvertToIndex (real doubleInput);
    logic [$clog2(N)-1:0] returnValue;
    real modifiedInput;
    modifiedInput = doubleInput * 10;
    returnValue = modifiedInput; //rounding happens here
endfunction

Utilicé el tipo de datos real que creo que es compatible con doble precisión IEEE 754.

Para que esto se pueda sintetizar, realmente necesita decidir cómo se debe realizar la conversión y qué hacer en caso de superposiciones.

    
respondido por el Ari

Lea otras preguntas en las etiquetas