前言
今天在網(wǎng)上看筆試題發(fā)現(xiàn)有個(gè)設(shè)計(jì)浮點(diǎn)累加器的題目,看了下題目說(shuō)明感覺不太清楚,恰好記得之前做過(guò)浮點(diǎn)數(shù)的加法運(yùn)算的設(shè)計(jì),索性就改了下題目需求,作為一個(gè)小練習(xí)在重新設(shè)計(jì)一遍。具體設(shè)計(jì)要求如下:
設(shè)計(jì)需求
設(shè)計(jì)一個(gè)32bit浮點(diǎn)的加法器,out = A + B,假設(shè)AB均為無(wú)符號(hào)位,或者換個(gè)說(shuō)法都為正數(shù)。
clk為系統(tǒng)時(shí)鐘;rst_n為系統(tǒng)復(fù)位,低有效;en信號(hào)控制數(shù)據(jù)輸入;busy指示模塊工作狀態(tài),busy拉高時(shí),輸入無(wú)效;aIn和bIn是數(shù)據(jù)輸入,out_vld,指示輸出數(shù)據(jù)有效。
設(shè)計(jì)的信號(hào)列表如下:
module float_adder(
input clk,
input rst_n,
input en,
input [31:0] aIn,
input [31:0] bIn,
output reg busy,
output reg out_vld,
output reg [31:0] out
);
32bit的浮點(diǎn)格式
EE標(biāo)準(zhǔn)754規(guī)定了三種浮點(diǎn)數(shù)格式:?jiǎn)尉取㈦p精度、擴(kuò)展精度。前兩者正好對(duì)應(yīng)C語(yǔ)言里頭的float、double或者FORTRAN里頭的real、double精度類型。本文設(shè)計(jì)實(shí)現(xiàn)的為單精度。

單精度:N共32位,其中S占1位,E占8位,M占23位。

雙精度:N共64位,其中S占1位,E占11位,M占52位。
浮點(diǎn)數(shù)的加法過(guò)程
運(yùn)算過(guò)程:對(duì)階、尾數(shù)求和、規(guī)格化、舍入、溢出判斷
對(duì)階:
和定點(diǎn)數(shù)不相同的是,浮點(diǎn)數(shù)的指數(shù)量級(jí)不一定是一樣的,所以這也就意味著,尾數(shù)直接進(jìn)行加法運(yùn)算時(shí)會(huì)存在問題,也就需要首先對(duì)階數(shù)進(jìn)行處理。該過(guò)程有點(diǎn)像科學(xué)計(jì)數(shù)法的加法處理,把科學(xué)計(jì)數(shù)法的指數(shù)化為一致,求出來(lái)指數(shù)相差多少,然后移位處理后再進(jìn)行加法減法。所以這里處理也要先求階差。
如果把階碼大的向階碼小的看齊,就要把階碼大的數(shù)的尾數(shù)部分左移,階碼減小。這個(gè)操作有可能在移位過(guò)程中把尾數(shù)的高位部分移掉,這樣就引發(fā)了數(shù)據(jù)的錯(cuò)誤,所以,尾數(shù)左移在計(jì)算機(jī)運(yùn)算中不可取。
如果把階碼小的向階碼大的看齊,在移位過(guò)程中如果發(fā)生數(shù)據(jù)丟失,也是最右邊的數(shù)據(jù)位發(fā)生丟失,最右邊的數(shù)據(jù)位丟失,只會(huì)影響數(shù)據(jù)的精度,不會(huì)影響數(shù)據(jù)的大小。
尾數(shù)求和:
這里就是常規(guī)的補(bǔ)碼加法。
規(guī)格化:
右規(guī)(尾數(shù)的絕對(duì)值太大時(shí),右規(guī))尾數(shù)右移一位,階碼加1。當(dāng)尾數(shù)溢出( >1 )時(shí),需要右規(guī)。是否溢出,可以通過(guò)兩位的符號(hào)位得出:即尾數(shù)出現(xiàn)01.xx…xx或10.xx…xx(兩位符號(hào)位不同)
提高浮點(diǎn)數(shù)的表示精度,這里設(shè)計(jì)考慮比較簡(jiǎn)單,我只考慮了同號(hào)數(shù)據(jù)相加的情況,所以這里只設(shè)計(jì)了右規(guī)的情況,不考慮符號(hào)位。
舍入判斷:
這里直接用截?cái)嗵幚淼姆绞剑槍?duì)數(shù)據(jù)相加上溢的情況,規(guī)定了運(yùn)算后上溢后將數(shù)據(jù)規(guī)定為最大值。
實(shí)現(xiàn)代碼
module float_adder(
input clk,
input rst_n,
input en,
input [31:0] aIn,
input [31:0] bIn,
output reg busy,
output reg out_vld,
output reg [31:0] out
);
//運(yùn)算過(guò)程:對(duì)階、尾數(shù)求和、規(guī)格化、舍入、溢出判斷
//分離階數(shù)、尾數(shù)
wire signal_bit = aIn[31];
wire [7:0] pow_a = aIn[30:23];
wire [7:0] pow_b = bIn[30:23];
wire [22:0] val_a = aIn[22:0];
wire [22:0] val_b = bIn[22:0];
//找到輸入指數(shù)階數(shù)較大,和階數(shù)差
//對(duì)階:在計(jì)算機(jī)中,采用小階向大階看齊的方法,實(shí)現(xiàn)對(duì)階。即右移
reg [22:0] pow_max ;
reg [23:0] pow_dif ;
reg [22:0] val_max ;
reg [22:0] val_min ;
reg en_dly0;
always @(posedge clk or negedge rst_n) begin
if(rst_n==0)begin
pow_max <= 'd0;
val_max <= 'd0;
val_min <= 'd0;
pow_dif <= 'd0;
en_dly0 <= 'd0;
end
else if( en == 1 && busy == 0)begin
if(pow_a >= pow_b)begin
pow_max <= pow_a;
val_max <= val_a;
val_min <= val_b;
en_dly0 <= 'd1;
if ( pow_a - pow_b > 'd23) begin
pow_dif <= 'd23;
end
else begin
pow_dif <= pow_a - pow_b;
end
end
else begin
pow_max <= pow_b;
val_max <= val_b;
val_min <= val_a;
en_dly0 <= 'd1;
if ( pow_b - pow_a > 'd23) begin
pow_dif <= 'd23;
end
else begin
pow_dif <= pow_b - pow_a;
end
end
end
else begin
pow_max <= pow_max;
val_max <= val_max;
val_min <= val_min;
pow_dif <= pow_dif;
en_dly0 <= 'd0;
end
end
//移位忙指示信號(hào)
reg shift_busy;
reg [4:0] shift_cnt;
always @(posedge clk or negedge rst_n) begin
if (rst_n==0) begin
shift_busy<='d0;
end
else if(en_dly0 == 1 )begin
shift_busy <='d1;
end
else if(shift_cnt == pow_dif)begin
shift_busy <= 0;
end
end
//移位計(jì)數(shù)
always @(posedge clk or negedge rst_n) begin
if(rst_n == 0)begin
shift_cnt <= 'd0;
end
else if (shift_busy ==1) begin
if (shift_cnt == pow_dif) begin
shift_cnt <= shift_cnt;
end
else begin
shift_cnt <= shift_cnt + 1'b1;
end
end
else begin
shift_cnt <= 'd0;
end
end
reg [22:0] val_shift;
always @(posedge clk or negedge rst_n) begin
if(rst_n == 0)begin
val_shift <= 'd0;
end
else if (en_dly0==1'b1) begin
val_shift <= val_min;
end
else if (shift_busy == 1) begin
val_shift <= {1'b0,val_shift[22:1]};
end
else begin
val_shift <= val_shift;
end
end
//尾數(shù)求和
wire val_add_flag = (shift_cnt == pow_dif)&&(shift_busy ==1);
reg [23:0] val_sum;
reg val_sum_vld;
always @(posedge clk or negedge rst_n) begin
if (rst_n==0) begin
val_sum<='d0;
val_sum_vld<='d0;
end
else if(val_add_flag == 1)begin
val_sum <= val_max + val_shift;
val_sum_vld<='d1;
end
else begin
val_sum <= val_sum;
val_sum_vld<='d0;
end
end
//規(guī)范
always @(posedge clk or negedge rst_n) begin
if (rst_n==0) begin
out<='d0;
out_vld<='d0;
end
else if(val_sum_vld == 1)begin
//尾數(shù)求和有溢出
out_vld<='d1;
out[31]<= signal_bit;
if(val_sum[23] == 1 && out[30:23] == 8'hFF)begin
out[30:23]<= 8'hFF;
out[22:0] <= 23'h7F_FFFF;
end
else if(val_sum[23] == 1)begin
out[30:23]<= pow_max + 1;
out[22:0] <= val_sum[23:1];
end
else begin
out[30:23]<= pow_max;
out[22:0] <= val_sum[22:0];
end
end
else begin
out <= out;
out_vld<='d0;
end
end
//運(yùn)算忙指示
always @(posedge clk or negedge rst_n) begin
if (rst_n==0) begin
busy<='d0;
end
else if(en == 1 && busy == 0)begin
busy<='d1;
end
else if(out_vld == 1 )begin
busy<='d0;
end
else begin
busy <= busy;
end
end
endmodule
仿真代碼
這里簡(jiǎn)單測(cè)試了下代碼的功能,模擬了連續(xù)輸入多個(gè)數(shù)據(jù),核查是否數(shù)據(jù)會(huì)影響正常計(jì)算過(guò)程。
`timescale 1ns/1ps
module float_adder_tb;
// Parameters
// Ports
reg clk = 1;
reg rst_n = 0;
reg en = 0;
reg [31:0] aIn;
reg [31:0] bIn;
wire busy;
wire out_vld;
wire [31:0] out;
float_adder float_adder_dut (
.clk (clk ),
.rst_n (rst_n ),
.en (en ),
.aIn (aIn ),
.bIn (bIn ),
.busy (busy ),
.out_vld (out_vld ),
.out ( out)
);
always
#5 clk = ! clk ;
initial begin
rst_n = 0;
#100;
rst_n = 1;
#100;
aIn = {1'b0,8'd2,23'd7};
bIn = {1'b0,8'd2,23'd8};
en = 1 ;
#10;
aIn = {1'b0,8'd0,23'd7};
bIn = {1'b0,8'd2,23'd8};
en = 1 ;
#1000;
$finish;
end
endmodule
仿真測(cè)試
從仿真測(cè)試中可以看出,當(dāng)輸入信號(hào)連續(xù)輸入兩個(gè)浮點(diǎn)數(shù)時(shí),在busy拉高狀態(tài)下,第二次輸入的數(shù)據(jù)無(wú)效,數(shù)據(jù)使能信號(hào)常為1,也不會(huì)影響正常模塊運(yùn)算過(guò)程,只有在該次運(yùn)算完成busy拉低后數(shù)據(jù)可重新加載。

小結(jié)
本文的設(shè)計(jì)方法對(duì)于對(duì)階移位的操作需要循環(huán)操作,也即當(dāng)階數(shù)相差較小時(shí),結(jié)果輸出延遲較小,在極端情況下,比如階數(shù)差大于10,輸出延時(shí)會(huì)比階數(shù)差為0時(shí),多10個(gè)周期,上限為23。如在實(shí)際使用時(shí),對(duì)延時(shí)要求較小的情況,可針對(duì)移位操作部分,使用更多的資源來(lái)?yè)Q取性能的提升。可使用case語(yǔ)句對(duì)具體情況進(jìn)行遍歷。
針對(duì)原始題目中的累加操作,可將任意一個(gè)輸入和輸出相接,即可實(shí)現(xiàn)累加操作。此外,如果要實(shí)現(xiàn)異號(hào)加法情況,則需要仔細(xì)考慮對(duì)階,規(guī)格化等情況進(jìn)行進(jìn)一步設(shè)計(jì)。
-
模塊
+關(guān)注
關(guān)注
7文章
2783瀏覽量
49483 -
數(shù)據(jù)
+關(guān)注
關(guān)注
8文章
7239瀏覽量
90962 -
加法器
+關(guān)注
關(guān)注
6文章
183瀏覽量
30588
原文標(biāo)題:小結(jié)
文章出處:【微信號(hào):處芯積律,微信公眾號(hào):處芯積律】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
小弟新人一枚 求一份32bit浮點(diǎn)乘法器設(shè)計(jì)源代碼 謝謝各位大哥大姐
McASP采集這樣的時(shí)序,是按照16bit采集,還是32bit采集?從Linux用戶空間看,采集進(jìn)來(lái)的數(shù)據(jù)是16bit還是32bit?
32bit MCU與16bit MCU的區(qū)別是什么
功能:浮點(diǎn)BCD碼轉(zhuǎn)換成格式化浮點(diǎn)數(shù)
華邦針對(duì)SiP市場(chǎng)推出32bit SDR/DDR利基型內(nèi)存
淘汰32bit不只iOS 11 明年開始擴(kuò)展至Mac 32bit應(yīng)用程序
32bit MCU 與 16bit MCU 的 區(qū)別

單片機(jī)里面“”32bit地址“”與所指向的“8bit數(shù)據(jù)“的關(guān)系

8bit 8051/32bit Cortex-M0 Flash單片機(jī)產(chǎn)品選型手冊(cè)

RABPS 32bit by 3dmaniack 3dtoday (ARM BluePill Shield)已修復(fù)

怎么設(shè)計(jì)一個(gè)32bit浮點(diǎn)的加法器呢?

使用STM32C0輕松實(shí)現(xiàn)從8bit到32bit的平臺(tái)升級(jí)

毫米波雷達(dá)半精度浮點(diǎn)存儲(chǔ)格式分析

評(píng)論