1.前言
在展開學習之前,我先回答網友的一些提問,問題如下所示:
No.1:ARM、DSP、FPGA到底學習哪個好?
這個問題也是我上大學期間遇到過的問題,當年我的做法像小學的一篇文章《小貓釣魚》中的小花貓一樣,一會兒撲蝴蝶,一會兒抓魚,總是三心二意,最後沒有任何收穫。
我想現在有很多大學生或者研究生還是有同樣的問題,不知道到底學習哪個方向,在渾渾噩噩中度過了大學或者研究生時光,畢業時就變成了失業....
首先,我們把這三個嵌入式在工程中的應用方向介紹一下:ARM一般做控制用的比較多,DSP適合做算法運算、FPGA適合做大數據流的處理;所以說沒有學哪個好,我們應該選擇適合自己的就可以了。
然後,我們講一下現在企業是如何做項目的。一般情況,像做通信方向都會採用DSP+FPGA的設計來做;像控制方向都會採用ARM+FPGA的設計來做,FPGA的應用方向就比較多了,例如,控制、通信、醫療、安防、圖像等。
最後,我們來說一下將來的發展趨勢。我個人覺得目前的電子行業繞不開的兩個因素(無論哪個專業方向都一樣):一個是數據量越來越多,另一個是處理速度要求越來越快。誰能夠從容的應對這兩個問題,那麼就會生存下去。我個人覺得處理速度是更重要的,就像電影《功夫》裏終級殺人王說的一樣:“天下武功,唯快不破!”
說了半天到底選擇哪個嵌入式呢?我覺的就兩點:第一點,就是選擇一個方向學習,不要三心二意;第二點,選擇適合你以及適合將來發展的就行了。
如果讓我重新選擇的話,我仍然會選擇FPGA,因爲我對它愛的深沉,哈哈!(絕對不能讓我老婆知道,不然就讓我跪搓衣板了。)
No.2 FPGA可以進行小數運算嗎?
FPGA完全可以進行小數運算。在平時工作,我遇到過一些路人說FPGA搞不了小數運算(也稱作浮點數運算),我只能說他們是外行人,不懂胡說;我只當亂風過耳,不予理睬。
當年我上學期間,由於自己學藝不精,當時也覺得FPGA不能做浮點數運算,不能像C語言那樣,但是工作後通過做項目以及和大神們交流,發現原來FPGA也是可以做浮點數運算的。當年和和一位大神聊天,問他同樣的問題;他的回答
一下點醒了我!(原話核心意思是無論什麼類型的數據在計算機裏永遠都是“0”或“1”) 聽完後我腦子裏就想到了一句古話:“聽君一席話,勝讀十年書啊!
這篇文章就專門對FPGA的小數運算(浮點數運算)進行介紹,希望能對大家有所幫助!
2.浮點數運算方法介紹
2.1用標準浮點數形式計算小數
浮點數說的通俗點就是我們說的小數,如果按照官方定義一堆名詞(我這裏不介紹,可以上網查閱),例如C語言中的float類型等。浮點數有單精度和雙精度之分,它們的格式如下所示:
- 1. 單精度和雙精度的浮點數說明
名稱 |
符號位 |
價碼 |
尾數 |
單精度浮點數 |
31bit:1代表負數;0代表正數 |
[30:23] |
[22:0] |
雙精度浮點數 |
63bit:1代表負數;0代表正數 |
[62:52] |
[51:0] |
這種格式的通俗理解就是小學數學學習的指數表達式,例如1500可以表示爲1.5*10^3,下面我們以單精度浮點數爲例,做個說明吧。
單精度浮點數共32bit,最高位代表的是符號位,30-23bit代表的是價碼值(通俗就是指數值)默認的空值爲十進制127;尾數就是有效數值了。例如,現在有個數據爲1500,變成指數形式爲1.5*10^3,如何用單精度表示呢?該數據是正數,所以符號位填寫“0”,指數次冪爲3,價碼值=127+3=130(如果是負指數就執行減法);有效數據爲1.5可以分爲整數部分和小數部分,整數部分是按照2^N來計算,1=2^0;小數部分按照2^(-N)來計算,0.5=2^(-1);所以整個表達數爲1100_0000_0000_0000_0000_000
2.2用FPGA自帶的IP覈計算小數
Xilinx或者Altera公司都帶有浮點數運算的IP核,直接調用IP進行計算相對方便,使用者不用關心浮點數的轉化格式。例如,XIlinx的IP如下圖所示。
2.3放大法計算小數
這種方式在實際工程中最常用的,就是先把參與運算的小數放大N倍後,讓它變成整數參與運算,最後,將運算結果除以放大倍數就可以了。
例如,25*2.123運算,如下步驟所示:
第一步:2.123*1000變爲2123;
第二步:25*2123;
第三步:結果除以1000,獲取整數部分即可。
2.4定點數計算小數
定點數其實和單精度浮點數相似,但是去除了那種複雜的格式,如下圖所示。
符號位 | 整數部分 | 小數部分 |
在實際操作中,一般需要數據交互雙方溝通,主要溝通負數是不是要遵循通用的負數形式(一般是取反加1);在實際項目中,爲了簡便操作一般就是改符號位,有效數據直接用正數據的值代表。
注意:如果不用標準模式,一定要雙方溝通好,不然就容易出現問題!!!!
總結:這幾種方式都可以在實踐中應用,大家可以根據實際情況選擇方法。當然,我個人只瞭解這幾種方式,可能還有其他方式,大家可以上網查下資料。
3.浮點數運算程序設計
前面已經對浮點數進行了介紹,本章節開始展開程序設計。我們分爲兩部分設計:
- 實現小數部分數據轉換成二進制的程序設計
- 實現定點數的小數運算程序設計
3.1小數部分十進制數據轉成二進數據程序設計
在數字世界裏,任何的數字表示都用0或者1表示的,所以我們要把小數部分的十進制數據先轉化爲二進制。在二進制世界裏,數據的表示是用2的指數進行表示,整數部分的數據表示是按照2的正指數表示,小數部分是按照2的負指數表示的。
例如,一個數據爲3.75,該數據包含整數部分和小數部分。
整數部分用二進制表示爲 :11
小數部分用二進制表示爲 :11
這裏我重點把小數部分轉二進制詳細說一下:
第一步:0.75可以看作是0.5+0.25組成;
第二步:0.5相當於是1/(2^1),0.25相當於是1/(2^2)
第三步:根據第二步將對應的位置上填寫1或0;1/(2^1)是表示有效數據的所以填寫爲1,同理1/(2^2)表示有有效數據填寫爲1
我們要遵循這個整數部分的數據表示是按照2的正指數表示,小數部分是按照2的負指數表示的的原則來設計程序。在程序設計中轉化的小數二進制位數設計爲可變模式(使用者可以設計轉化的二進制位數)
名稱 |
方向 |
位寬 |
說明 |
clk |
Input |
1 |
工作時鐘 |
start_en |
Input |
1 |
計算信號 |
data_in |
Input |
32 |
輸入數據 |
dout_out |
Output |
size |
結果數據,該數據位寬根據需求可以轉換對應的位數 |
done_out |
Output |
1 |
計算完成信號 |
module flaot_cal_top#(
parameter SIZE=24,//輸出的二進制位數設置
parameter FLOAT_mulit=1000//轉換倍數設置
)
(
input [31:0] data_in ,//輸入的小數部分的整數表示
input start_en ,//啓動信號
input clk ,//時鐘信號
output [SIZE-1:0] data_out ,//計算的結果
output done_out //計算完成標誌信號
);
wire [31:0] data_reg[SIZE:0] ;//數組表達格式
wire done[SIZE:0] ;//數組表達格式
wire [SIZE:0] data_out_reg ;
assign done_out = done[SIZE];
assign data_out = data_out_reg[SIZE-1:0];
//------------------------------採用generate語法編寫代碼------------------
genvar i;
generate
for(i=0;i<SIZE+1;i=i+1)
begin:cal
if(i==0)begin
cal_top_one #(
.FLOAT_mulit(FLOAT_mulit)
)
inst_cal_tops (
.clk (clk ),
.start_en (start_en ),
.data_in (data_in ),
.data_out (data_reg[i] ),
.done (done[i] ),
.data_bit (data_out_reg[SIZE-i] )
);
end
else begin
cal_top_one
#(
.FLOAT_mulit(FLOAT_mulit)
)
inst_cal_topsf(
.clk (clk ),
.data_in (data_reg[i-1] ),
.start_en (done[i-1] ),
.done (done[i] ),
.data_out (data_reg[i] ),
.data_bit (data_out_reg[SIZE-i] )
);
end
end
endmodule
測試文件:
測試兩個小數部分數據:0.142和0.751
如上圖黃色的高電平信號處爲算出的0.142和0.751的二進制數據,它們分別爲24位的二進制表示;該程序計算結果和理論值相同。
可以關注微信公衆號《FPGA的故事》!