blob: 52a81379fb34b7018524612967c048f280368694 [file] [log] [blame]
`include "I2F_LZD.v"
module FPU_Int_to_Float(INT_TO_FLOAT_input_int, INT_TO_FLOAT_input_rm, INT_TO_FLOAT_input_opcode_IF, INT_TO_FLOAT_input_opcode_signed, INT_TO_FLOAT_input_opcode_unsigned, INT_TO_FLOAT_output_float, INT_TO_FLOAT_output_invalid_flag, INT_TO_FLOAT_output_inexact_flag, rst_l);
parameter std = 15; //Bfloat16 + IEEE16
//parameter std = 31; //IEEE32
//parameter std = 63; //IEEE64
//parameter man = 6; // bfloat16
parameter man = 9; // IEEE16
//parameter man = 22; // IEEE32
//parameter man = 51; //
parameter exp = 4; // IEEE16
//parameter exp = 7; // IEEE32 + Bfloat16
//parameter exp = 10 // IEEE64
//parameter bias = 127; // IEEE32 + Bfloat16
parameter bias = 15; // IEEE16
//parameter bias = 1023 // IEEE64
parameter lzd = 4; //Constant for all STD since LZD is dealing this INT and INT is always of 32 bit
parameter exp_cal = 31;
//INPUTS
input [31 : 0] INT_TO_FLOAT_input_int;
input [2 : 0] INT_TO_FLOAT_input_rm;
input INT_TO_FLOAT_input_opcode_IF, INT_TO_FLOAT_input_opcode_signed, INT_TO_FLOAT_input_opcode_unsigned;
input rst_l;
//OUTPUTS
output [std : 0]INT_TO_FLOAT_output_float;
output INT_TO_FLOAT_output_invalid_flag;
output INT_TO_FLOAT_output_inexact_flag;
//WIRES
wire [31 : 0] INT_TO_FLOAT_input_wire_int;
wire [31 : 0]INT_TO_FLOAT_reg_magnitude;
wire [lzd : 0]INT_TO_FLOAT_wire_shifts; wire INT_TO_FLOAT_wire_lzd_valid;
wire [31 : 0]INT_TO_FLOAT_wire_shifted_int;
wire INT_TO_FLOAT_wire_guard, INT_TO_FLOAT_wire_round, INT_TO_FLOAT_wire_sticky;
wire INT_TO_FLOAT_wire_condition_inf, INT_TO_FLOAT_wire_condition_rnte, INT_TO_FLOAT_wire_condition_rntmm;
wire INT_TO_FLOAT_wire_inc_or_trunc;
wire INT_TO_FLOAT_wire_carry_prediction;
wire [man+1 : 0]INT_TO_FLOAT_rounded_h_man; wire INT_TO_FLOAT_rounded_h_man_carry;
wire [51 : 0] INT_TO_FLOAT_wire_man_output_interim;
wire [lzd : 0]INT_TO_FLOAT_wire_shifts_for_exp_cal;
wire [exp : 0]INT_TO_FLOAT_wire_bias_toadd;
wire [lzd : 0] INT_TO_FLOAT_wire_exp_interm_1;
wire [exp : 0] INT_TO_FLOAT_wire_exp_output;
wire [51 : 0]INT_TO_FLOAT_wire_man_output;
wire INT_TO_FLOAT_wire_sign_output;
wire [63 : 0]INT_TO_FLOAT_wire_64std_output;
wire [std : 0]INT_TO_FLOAT_wire_rest_std_output;
//If rst_l is low and if opcode is low then input is set zero and so is the output.
assign INT_TO_FLOAT_input_wire_int = (INT_TO_FLOAT_input_opcode_IF && rst_l) ? INT_TO_FLOAT_input_int : 32'b0000_0000_0000_0000_0000_0000_0000_0000;
//Checking MSB to check whether the number is -ve or +ve and then converting negative number to magnitude
//Conversion is done only when unsigned opcode is high
assign INT_TO_FLOAT_reg_magnitude = (INT_TO_FLOAT_input_wire_int[31] & INT_TO_FLOAT_input_opcode_signed) ?
(~INT_TO_FLOAT_input_wire_int) + 1'b1 : INT_TO_FLOAT_input_wire_int;
//Converting to 2's compliment by taking 2's compliment if sign == 1
//Module instantiation of LZD
FPU_I2F_LZD LZD (.I2F_LZD_input_int(INT_TO_FLOAT_reg_magnitude), .I2F_LZD_output_pos(INT_TO_FLOAT_wire_shifts), .I2F_LZD_output_val(INT_TO_FLOAT_wire_lzd_valid));
assign INT_TO_FLOAT_wire_shifted_int = INT_TO_FLOAT_reg_magnitude << INT_TO_FLOAT_wire_shifts;
//man in case of double precision will be 51 and 31-man will be a negative no (2's compliment) this will be a trash value however it will not be effecting our actual result since for that std 0 will be selected for all G, R, and S
assign INT_TO_FLOAT_wire_guard = (std==63) ? 1'b0 : (INT_TO_FLOAT_wire_shifted_int[5'b11111 - (man+2'b10)]);
assign INT_TO_FLOAT_wire_round = (std==63) ? 1'b0 : (INT_TO_FLOAT_wire_shifted_int[5'b11111 - (man+2'b11)]);
assign INT_TO_FLOAT_wire_sticky = (std==63) ? 1'b0 : (|(INT_TO_FLOAT_wire_shifted_int[(5'b11111 - (man+3'b100)) : 0]));
assign INT_TO_FLOAT_wire_condition_inf = ((INT_TO_FLOAT_wire_round | INT_TO_FLOAT_wire_guard | (INT_TO_FLOAT_wire_sticky)) & ((INT_TO_FLOAT_input_rm == 3'b011 & ~(INT_TO_FLOAT_input_wire_int[31] & INT_TO_FLOAT_input_opcode_signed))|(INT_TO_FLOAT_input_rm == 3'b010 & (INT_TO_FLOAT_input_wire_int[31] & INT_TO_FLOAT_input_opcode_signed))));
assign INT_TO_FLOAT_wire_condition_rnte = (INT_TO_FLOAT_input_rm == 3'b000 & ((INT_TO_FLOAT_wire_guard & (INT_TO_FLOAT_wire_round | INT_TO_FLOAT_wire_sticky)) | (INT_TO_FLOAT_wire_guard & ((~INT_TO_FLOAT_wire_round) & ~(INT_TO_FLOAT_wire_sticky)) & INT_TO_FLOAT_wire_shifted_int[5'b11111 - (man+2'b01)])));
assign INT_TO_FLOAT_wire_condition_rntmm = (INT_TO_FLOAT_input_rm == 3'b100 & ((INT_TO_FLOAT_wire_guard & (INT_TO_FLOAT_wire_round | INT_TO_FLOAT_wire_sticky)) | (INT_TO_FLOAT_wire_guard & ((~INT_TO_FLOAT_wire_round) & (~INT_TO_FLOAT_wire_sticky)))));
assign INT_TO_FLOAT_wire_inc_or_trunc = INT_TO_FLOAT_wire_condition_inf | INT_TO_FLOAT_wire_condition_rnte | INT_TO_FLOAT_wire_condition_rntmm;
//man in case of double precision will be 51 and 31-man will be a negative no (2's compliment) this will be a trash value however it will not be effecting our actual result since for that std 0 will be selected for carry
assign INT_TO_FLOAT_wire_carry_prediction = (std == 64) ? (1'b0) : ((&INT_TO_FLOAT_wire_shifted_int[31 : 31-(man+1'b1)]) & (INT_TO_FLOAT_wire_inc_or_trunc));
//Extra zero is added to make the size of LHS == RHS
assign {INT_TO_FLOAT_rounded_h_man_carry, INT_TO_FLOAT_rounded_h_man} = {1'b0, INT_TO_FLOAT_wire_shifted_int[31 : 31-(man+1'b1)]} + INT_TO_FLOAT_wire_inc_or_trunc;
// ({(51-man)}{1'b0}) is used to add zero at the end to make the mantissa same size as mantissa of DOUBLE PRECISION
assign INT_TO_FLOAT_wire_man_output_interim = (std == 64) ?
({INT_TO_FLOAT_wire_shifted_int[30 : 0], 21'b0_0000_0000_0000_0000_0000}) :
({ (INT_TO_FLOAT_rounded_h_man[man : 0]), ({(51-man){1'b0}}) });
//In case data is all zero output of LZD is zero in this case exponent will be 31-0 which is not ok therfore setting the exponent to all 1 so that exp will be 31-31 = 0
assign INT_TO_FLOAT_wire_shifts_for_exp_cal = (!INT_TO_FLOAT_wire_lzd_valid) ? (exp_cal[lzd : 0]) : INT_TO_FLOAT_wire_shifts;
//Subtracting shifts from 31 and adding carry_prediction in it.
assign INT_TO_FLOAT_wire_exp_interm_1 = exp_cal[lzd : 0] - INT_TO_FLOAT_wire_shifts_for_exp_cal + INT_TO_FLOAT_wire_carry_prediction;
//In case data is all zero than bias is not added
assign INT_TO_FLOAT_wire_bias_toadd = (!INT_TO_FLOAT_wire_lzd_valid) ? ({(exp+1){1'b0}}) : (bias[exp : 0]);
// ({(exp-lzd)}{1'b0}) using this command 7-4 = 3 times zeros are added into the exp_interm_1 to make it of the same size as expoent and bias
assign INT_TO_FLOAT_wire_exp_output = ({ ({(exp-lzd){1'b0}}) ,INT_TO_FLOAT_wire_exp_interm_1}) + INT_TO_FLOAT_wire_bias_toadd;
assign INT_TO_FLOAT_wire_man_output = (&INT_TO_FLOAT_wire_exp_output) ? ({52{1'b0}}) : (INT_TO_FLOAT_wire_man_output_interim) ;
//Calculating sign of the output on the basis on input MSB and opcode, since incase of signed MSB is a negative number and is high only incase of negative number but this is not the case when dealing with unsigned numbers.
assign INT_TO_FLOAT_wire_sign_output = (INT_TO_FLOAT_input_wire_int[31] & INT_TO_FLOAT_input_opcode_signed);
assign INT_TO_FLOAT_output_float = {INT_TO_FLOAT_wire_sign_output, INT_TO_FLOAT_wire_exp_output, (INT_TO_FLOAT_wire_man_output[51 : (51-man)])};
//INT_TO_FLOAT_output_reg_invalid_flag = 1'b0;//valid flag will always be low for single precision as 32 wire int can easily be
//represented in single precision. flag will only come into play when deailing with IEEE16.
assign INT_TO_FLOAT_output_invalid_flag = (std == 15) & (&INT_TO_FLOAT_wire_exp_output) ;
//Inexact Flag
assign INT_TO_FLOAT_output_inexact_flag = INT_TO_FLOAT_wire_guard | INT_TO_FLOAT_wire_round | INT_TO_FLOAT_wire_sticky;
endmodule