FPGA定點數轉換成雙精度浮點數(IEEE754)
阿新 • • 發佈:2021-01-27
本文利用一個例子,簡單的介紹了,FPGA定點數轉換成雙精度浮點數(IEEE754協議),文章後,貼有實現程式碼和模擬檔案,我用的是quartus II 13.1。
一:雙精度浮點數格式
雙精度的指數部分(E)採用的偏置碼為1023
假設待轉換的資料是11(二進位制)
第一步:將其擴充套件成64位2進位制數
0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0011
第二步:計算首1是第幾位
2
第三步:計算階碼
偏移值是1023
Code=1023+2-1=1024
第四步:計算尾數
4.1:因為首1是第2位,所以資料往左移52-2=50位
Pre_尾數=1100_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000
4.2:將首1隱藏 Pre_尾數,往左移動一位
第五步:組合成新的浮點數
Double_Float=0100_0000_0000_1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000
0x4008000000000000
在這裡插入程式碼片
module int_to_double_float
(
input clk,
input rst_n,
input signed [31:0]int_number, //輸入進來的是32位整型資料,能表示到浮點數21474836648
output reg [63:0]double_float
);
//變數宣告
reg [63:0]int_number_64; //輸入的整型變數
reg [9:0]cnt; //計數器,進行時序約束
reg [5:0]first_one; //首1,所在的位置
reg [10:0]code; //11位的階碼
reg [31:0]pre_mantissa; //擴充套件後的資料,其中有效資料部分的首1,移位到第53位時的尾數
reg sign; //資料的符號位
//建立一個計數器,進行時序約束
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
cnt <= 10'd0;
else begin
if(cnt < 6)
cnt<= cnt + 1'b1;
else
cnt<= 10'd0;
end
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
sign<= 1'd0;
else begin
sign<=int_number[31];
end
end
//第一步取符號位
//第一步擴寬輸出的整型,先將其擴充套件成64位數
always @(posedge clk or negedge rst_n )
begin
if(!rst_n)
begin
int_number_64<=64'd0;
end
else
begin
int_number_64<={32'd0,int_number};
end
end
//第一步計算首1在那個位置
always @(posedge clk or negedge rst_n )
begin
if(!rst_n)
begin
first_one<=6'd0;
end
else if(int_number>=32'd1073741824)
begin
first_one=31;
end
else if(int_number>=32'd536870912)
begin
first_one=30;
end
else if(int_number>=32'd268435456)
begin
first_one=29;
end
else if(int_number>=32'd134217728)
begin
first_one=28;
end
else if(int_number>=32'd67108864)
begin
first_one=27;
end
else if(int_number>=32'd33554432)
begin
first_one=26;
end
else if(int_number>=32'd16777216)
begin
first_one=25;
end
else if(int_number>=32'd8388608)
begin
first_one=24;
end
else if(int_number>=32'd4194304)
begin
first_one=23;
end
else if(int_number>=32'd2097152)
begin
first_one=22;
end
else if(int_number>=32'd1048576)
begin
first_one=21;
end
else if(int_number>=32'd524288)
begin
first_one=20;
end
else if(int_number>=32'd262144)
begin
first_one=19;
end
else if(int_number>=32'd131072)
begin
first_one=18;
end
else if(int_number>=32'd65536)
begin
first_one=17;
end
else if(int_number>=32'd32768)
begin
first_one=16;
end
else if(int_number>=32'd32768)
begin
first_one=15;
end
else if(int_number>=32'd8192)
begin
first_one=14;
end
else if(int_number>=32'd4096)
begin
first_one=13;
end
else if(int_number>=32'd2048)
begin
first_one=12;
end
else if(int_number>=32'd1024)
begin
first_one=11;
end
else if(int_number>=32'd512)
begin
first_one=10;
end
else if(int_number>=32'd256)
begin
first_one=9;
end
else if(int_number>=32'd128)
begin
first_one=8;
end
else if(int_number>=32'd64)
begin
first_one=7;
end
else if(int_number>=32'd32)
begin
first_one=6;
end
else if(int_number>=32'd16)
begin
first_one=5;
end
else if(int_number>=32'd8)
begin
first_one=4;
end
else if(int_number>=32'd4)
begin
first_one=3;
end
else if(int_number>=32'd2)
begin
first_one<=6'd2;
end
else if(int_number>=32'd1)
begin
first_one=1;
end
else
begin
first_one=0;
end
end
//第二步計算階碼
always @(posedge clk or negedge rst_n )
begin
if(!rst_n)
begin
code<=11'b0;
end
else if(cnt==3)
begin
code<=1022+first_one;
end
else
code<=code;
end
//第二步計算尾數
always @(posedge clk or negedge rst_n )
begin
if(!rst_n)
begin
pre_mantissa<=32'd0;
end
else if(cnt==3)
begin
pre_mantissa<= int_number<<(33-first_one); //要將首1隱藏,取剩下的部分
end
else
pre_mantissa<= pre_mantissa;
end
//第三步計算結果
always @(posedge clk or negedge rst_n )
begin
if(!rst_n)
begin
double_float<=64'd0;
end
else if(cnt==4)
begin
double_float<= {sign,code,pre_mantissa,20'd0} ; //要將首1隱藏,取剩下的部分
end
else
double_float<=double_float;
end
endmodule
模擬檔案
`timescale 1ns/1ns
`define time_period 20
module int_to_double_float_tb;
reg clk;
reg rst_n;
reg [31:0]int_number;
always #(`time_period/2)clk=~clk;
initial begin
clk=1'b0;
rst_n=1'b0;
#(`time_period/2)
rst_n =1'b1;
int_number<=32'd536870912;
#((`time_period/2)*100000 );
$stop;
end
int_to_double_float int_to_double_float_u1(
.clk(clk),
.rst_n(rst_n),
.int_number(int_number), //能表示到無浮點數4294967296
.double_float(double_float)
);
endmodule