📄 fp_int_to_float.v
字号:
//Legal Notice: (C)2006 Altera Corporation. All rights reserved. Your
//use of Altera Corporation's design tools, logic functions and other
//software and tools, and its AMPP partner logic functions, and any
//output files any of the foregoing (including device programming or
//simulation files), and any associated documentation or information are
//expressly subject to the terms and conditions of the Altera Program
//License Subscription Agreement or other applicable license agreement,
//including, without limitation, that your use is for the sole purpose
//of programming logic devices manufactured by Altera and sold by Altera
//or its authorized distributors. Please refer to the applicable
//agreement for further details.
// synthesis translate_off
`timescale 1ns / 1ps
// synthesis translate_on
// turn off superfluous verilog processor warnings
// altera message_level Level1
// altera message_off 10034 10035 10036 10037 10230 10240 10030
module fp_int_to_float(
reset,
clk,
clk_en,
input_data,
unsigned_operation, // input_unsigned 0 for signed int, 1 for unsigned int
output_data
);
/* floating point unit paramterization, base latency is 1, setting each below to true adds 1 to the latency */
parameter ENABLE_INPUT_PIPELINING = "false";
parameter ENABLE_OUTPUT_PIPELINING = "false";
parameter ENABLE_INTERNAL_PIPELINING = "false";
parameter DATA_WIDTH = 32; // maximum of 64
parameter EXPONENT_WIDTH = 8; // use 11 for double precision
parameter MANTISSA_WIDTH = 23; // use 52 for double precision
localparam BIAS_FACTOR = {(EXPONENT_WIDTH-1){1'b1}}; // 127 for SP, 1023 for DP
localparam SHIFT_WIDTH = 64 + 1 + MANTISSA_WIDTH; // 64 (treat input as 64 bit data) + implied 1 + MANTISSA_WIDTH
localparam ROUNDING_WIDTH = (DATA_WIDTH >= (MANTISSA_WIDTH + 1))? (DATA_WIDTH - (MANTISSA_WIDTH + 1)) : 0; // need to keep the bits that shift out of the mantissa, if mantissa is larger no rounding is necessary
input reset;
input clk;
input clk_en;
input [DATA_WIDTH-1:0] input_data;
input unsigned_operation;
output [EXPONENT_WIDTH + MANTISSA_WIDTH:0] output_data;
wire [EXPONENT_WIDTH + MANTISSA_WIDTH:0] output_data;
/* input data pipelining */
reg [DATA_WIDTH-1:0] input_data_d1;
wire [DATA_WIDTH-1:0] input_integer;
reg unsigned_operation_d1;
wire input_unsigned;
/* output data pipelining */
wire [EXPONENT_WIDTH + MANTISSA_WIDTH:0] temp_output_data;
reg [EXPONENT_WIDTH + MANTISSA_WIDTH:0] temp_output_data_d1;
/* treat all inputs as 64 bit data */
wire [63:0] sign_extended_input;
wire [63:0] absolute_input;
reg [63:0] absolute_input_d1;
wire [SHIFT_WIDTH-1 + ROUNDING_WIDTH:0] stage_A; // prime the inputs into the shifting logic
wire [SHIFT_WIDTH-1 + ROUNDING_WIDTH:0] stage_B; // holds the value after the first shift
wire [SHIFT_WIDTH-1 + ROUNDING_WIDTH:0] stage_C; // holds the value after the final shift
reg [SHIFT_WIDTH-1 + ROUNDING_WIDTH:0] stage_C_d1;
wire [5:0] leading_zeros; // how many zeros starting from the left of the long long
reg [5:0] leading_zeros_d1;
wire [6:0] shift_distance;
wire [EXPONENT_WIDTH-1:0] biased_exp; // holds the biased exponential
reg [EXPONENT_WIDTH-1:0] biased_exp_d1;
wire [EXPONENT_WIDTH-1:0] final_biased_exp; // holds the final biased exponential (rounding can cause this to increase by 1)
wire [MANTISSA_WIDTH-1:0] final_mantissa; // holds the final value of the mantissa after rounding
reg sign_bit;
reg sign_bit_d1;
reg input_unsigned_d1;
reg input_unsigned_d2;
/* these will be used to control the priority encoder logic (that finds the number
of leading zeros in the unsigned input */
wire [6:0] result [7:0]; // the values for result range between 0-63 (one per first stage mux)
wire [8:0] is_Zero; // if all the inputs into the first stage mux are zero this will be high (the 9th one is the second stage)
reg is_Zero_d1; // sync this so that it lines up with leading_zeros_d1
reg is_Zero_d2;
wire enable_rounding; // will be using round to nearest
always @(posedge clk or posedge reset)
begin
if(reset == 1)
begin
input_data_d1 <= 0;
unsigned_operation_d1 <= 0;
end
else
begin
if(clk_en == 1)
begin
input_data_d1 <= input_data;
unsigned_operation_d1 <= unsigned_operation;
end
end
end
// this generate statement will optimize away input registers depending on ENABLE_INPUT_PIPELINING
generate
if(ENABLE_INPUT_PIPELINING == "true")
begin
assign input_integer = input_data_d1;
assign input_unsigned = unsigned_operation_d1;
end
else
begin
assign input_integer = input_data;
assign input_unsigned = unsigned_operation;
end
endgenerate
/* sign extend input to a 64 bit value and create an unsigned copy */
assign sign_extended_input = (input_unsigned == 1)? {{(64-DATA_WIDTH){1'b0}} , input_integer} : // unsigned data so fill upper bits with 0
{{(64-DATA_WIDTH){input_integer[DATA_WIDTH-1]}} , input_integer}; // signed data so fill upper bits with the input sign bit
assign absolute_input = ((input_unsigned == 0) && (sign_extended_input[63] == 1))? ((~sign_extended_input) + 1) : sign_extended_input;
/* internal pipeling registers */
always @(posedge clk or posedge reset)
begin
if(reset == 1)
begin
sign_bit <= 0;
sign_bit_d1 <= 0;
input_unsigned_d1 <= 0;
input_unsigned_d2 <= 0;
absolute_input_d1 <= 0;
stage_C_d1 <= 0;
biased_exp_d1 <= 0;
end
else
begin
if(clk_en == 1)
begin
sign_bit <= input_integer[DATA_WIDTH-1];
sign_bit_d1 <= sign_bit;
input_unsigned_d1 <= input_unsigned;
input_unsigned_d2 <= input_unsigned_d1;
absolute_input_d1 <= absolute_input;
stage_C_d1 <= stage_C;
biased_exp_d1 <= biased_exp;
end
end
end
/* priority encoding to find the leading zero. The input is broken into eight pieces (of 8 bits)
and the leading zero is found in each. The "is_Zero" bit from each is used for the final
assignment of leading_zeros based on a one hot priority encoding (parallel implementation).
Think of this as a replacement of a 64 input (7 bit inputs) mux into two stages of mux logic.
*/
eight_one_hot first_mux
( .select(absolute_input[63:56]), .result(result[0]), .is_Zero(is_Zero[0]));
defparam first_mux.START_VALUE = 0;
eight_one_hot second_mux
( .select(absolute_input[55:48]), .result(result[1]), .is_Zero(is_Zero[1]));
defparam second_mux.START_VALUE = 8;
eight_one_hot third_mux
( .select(absolute_input[47:40]), .result(result[2]), .is_Zero(is_Zero[2]));
defparam third_mux.START_VALUE = 16;
eight_one_hot fourth_mux
( .select(absolute_input[39:32]), .result(result[3]), .is_Zero(is_Zero[3]));
defparam fourth_mux.START_VALUE = 24;
eight_one_hot fifth_mux
( .select(absolute_input[31:24]), .result(result[4]), .is_Zero(is_Zero[4]));
defparam fifth_mux.START_VALUE = 32;
eight_one_hot sixth_mux
( .select(absolute_input[23:16]), .result(result[5]), .is_Zero(is_Zero[5]));
defparam sixth_mux.START_VALUE = 40;
eight_one_hot seventh_mux
( .select(absolute_input[15:8]), .result(result[6]), .is_Zero(is_Zero[6]));
defparam seventh_mux.START_VALUE = 48;
eight_one_hot eighth_mux
( .select(absolute_input[7:0]), .result(result[7]), .is_Zero(is_Zero[7]));
defparam eighth_mux.START_VALUE = 56;
/* stick the first stage back together (9th mux using the first eight as inputs).
Remember if is_Zero is 1 then the leading one isn't contained in that particular
group of eight.
*/
assign leading_zeros = (is_Zero[0] == 0) ? result[0] :
(is_Zero[1] == 0) ? result[1] :
(is_Zero[2] == 0) ? result[2] :
(is_Zero[3] == 0) ? result[3] :
(is_Zero[4] == 0) ? result[4] :
(is_Zero[5] == 0) ? result[5] :
(is_Zero[6] == 0) ? result[6] : result[7];
assign is_Zero[8] = (is_Zero[7:0] == 8'b11111111)? 1 : 0; // this is one if absolute_input was zero
/* register the priority encoder results */
always @(posedge clk or posedge reset)
begin
if(reset == 1)
begin
leading_zeros_d1 <= 0;
is_Zero_d1 <= 0;
is_Zero_d2 <= 0;
end
else
begin
if(clk_en == 1)
begin
leading_zeros_d1 <= leading_zeros;
is_Zero_d1 <= is_Zero[8];
is_Zero_d2 <= is_Zero_d1;
end
end
end
/* a.k.a. furthest 1 from the right */
assign shift_distance = 64 - leading_zeros_d1;
/* the exponent is one less than the shift distance */
assign biased_exp = shift_distance - 1 + BIAS_FACTOR;
/* now that the shift distance is know time to barrelshift the long long.
The format is absoulte_input:0:mantissa. The zero in the middle is the placeholder
for the implied '1' mantissa bit (i.e. the leading one) */
assign stage_A = {{absolute_input_d1, 1'b0}, {(MANTISSA_WIDTH+ROUNDING_WIDTH){1'b0}}};
assign stage_B = (shift_distance[5:3] == 0)? stage_A:
(shift_distance[5:3] == 1)? stage_A >> 8:
(shift_distance[5:3] == 2)? stage_A >> 16:
(shift_distance[5:3] == 3)? stage_A >> 24:
(shift_distance[5:3] == 4)? stage_A >> 32:
(shift_distance[5:3] == 5)? stage_A >> 40:
(shift_distance[5:3] == 6)? stage_A >> 48: stage_A >> 56;
assign stage_C = (shift_distance[2:0] == 0)? stage_B:
(shift_distance[2:0] == 1)? stage_B >> 1:
(shift_distance[2:0] == 2)? stage_B >> 2:
(shift_distance[2:0] == 3)? stage_B >> 3:
(shift_distance[2:0] == 4)? stage_B >> 4:
(shift_distance[2:0] == 5)? stage_B >> 5:
(shift_distance[2:0] == 6)? stage_B >> 6: stage_B >> 7;
generate
if(ROUNDING_WIDTH > 0)
begin
if(ENABLE_INTERNAL_PIPELINING == "true")
begin
assign enable_rounding = (stage_C_d1[ROUNDING_WIDTH-1:0] > (1 << (ROUNDING_WIDTH-1)))? 1: // round up regardless
((stage_C_d1[ROUNDING_WIDTH-1:0] == (1 << (ROUNDING_WIDTH-1))) & (stage_C_d1[ROUNDING_WIDTH] == 1))? 1: 0; // it's a tie but we are rounding towards even, otherwise don't round
end
else
begin
assign enable_rounding = (stage_C[ROUNDING_WIDTH-1:0] > (1 << (ROUNDING_WIDTH-1)))? 1: // round up regardless
((stage_C[ROUNDING_WIDTH-1:0] == (1 << (ROUNDING_WIDTH-1))) & (stage_C[ROUNDING_WIDTH] == 1))? 1: 0; // it's a tie but we are rounding towards even, otherwise don't round
end
end
else
begin
assign enable_rounding = 0; // mantissa is large enough to hold input
end
endgenerate
generate
if(ENABLE_INTERNAL_PIPELINING == "true")
begin
assign final_mantissa = (enable_rounding == 1)? (stage_C_d1[MANTISSA_WIDTH+ROUNDING_WIDTH-1:ROUNDING_WIDTH] + 1) : stage_C_d1[MANTISSA_WIDTH+ROUNDING_WIDTH-1:ROUNDING_WIDTH]; // the bits we lost rounded us up
assign final_biased_exp = ((enable_rounding == 1) & (stage_C_d1[MANTISSA_WIDTH+ROUNDING_WIDTH-1:ROUNDING_WIDTH] == {MANTISSA_WIDTH{1'b1}}))? (biased_exp_d1 + 1) : biased_exp_d1; // rounding up caused the mantissa to roll over and our implied 1 just moved up a digit
assign temp_output_data = (is_Zero_d2 == 1)? 0 : /* special case where zero was passed to this hardware */
(input_unsigned_d2 == 0) ? {{sign_bit_d1, final_biased_exp}, final_mantissa} : /* signed case */
{{1'b0, final_biased_exp},final_mantissa}; /* unsigned case */
end
else
begin
assign final_mantissa = (enable_rounding == 1)? (stage_C[MANTISSA_WIDTH+ROUNDING_WIDTH-1:ROUNDING_WIDTH] + 1) : stage_C[MANTISSA_WIDTH+ROUNDING_WIDTH-1:ROUNDING_WIDTH]; // the bits we lost rounded us up
assign final_biased_exp = ((enable_rounding == 1) & (stage_C[MANTISSA_WIDTH+ROUNDING_WIDTH-1:ROUNDING_WIDTH] == {MANTISSA_WIDTH{1'b1}}))? (biased_exp + 1) : biased_exp; // rounding up caused the mantissa to roll over and our implied 1 just moved up a digit
assign temp_output_data = (is_Zero_d1 == 1)? 0 : /* special case where zero was passed to this hardware */
(input_unsigned_d1 == 0) ? {{sign_bit, final_biased_exp}, final_mantissa} : /* signed case */
{{1'b0, final_biased_exp},final_mantissa}; /* unsigned case */
end
endgenerate
always @(posedge clk or posedge reset)
begin
if(reset == 1)
begin
temp_output_data_d1 <= 0;
end
else
begin
if(clk_en == 1)
begin
temp_output_data_d1 <= temp_output_data;
end
end
end
// this will be synthesized away the output registers depending on ENABLE_OUTPUT_PIPELINING
generate
if(ENABLE_OUTPUT_PIPELINING == "true")
begin
assign output_data = temp_output_data_d1;
end
else
begin
assign output_data = temp_output_data;
end
endgenerate
endmodule
/* this mux finds the leading zero amungst eight inputs. If all zeros are feed into
this block are zero the result is START_VALUE+7 and is_Zero will be one. The 2nd stage mux
that combines these blocks together will ignore the value START_VALUE+7 if is_Zero
is one */
module eight_one_hot (
select,
result,
is_Zero);
parameter START_VALUE = 0;
input [7:0] select;
wire [5:0] result;
output [5:0] result;
wire is_Zero;
output is_Zero;
assign result = (select[7] == 1)? START_VALUE :
(select[6] == 1)? START_VALUE + 1 :
(select[5] == 1)? START_VALUE + 2 :
(select[4] == 1)? START_VALUE + 3 :
(select[3] == 1)? START_VALUE + 4 :
(select[2] == 1)? START_VALUE + 5 :
(select[1] == 1)? START_VALUE + 6 : START_VALUE + 7;
assign is_Zero = (select == 8'b00000000)? 1 : 0;
endmodule
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -