基於FPGA的小數計算學習

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.浮點數運算程序設計

前面已經對浮點數進行了介紹,本章節開始展開程序設計。我們分爲兩部分設計:

  1.  實現小數部分數據轉換成二進制的程序設計
  2.  實現定點數的小數運算程序設計

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的故事》!

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章