FPGA設計--數字的表示形式(程式碼+波形圖)

兔美醬xz發表於2014-10-15

在數字邏輯系統中,只存在高電平和低電平,因此用其表示數字只有整數形式,並存在3種表示方法,即:原碼錶示法(符號加絕對值)、反碼錶示法(符號加反碼)和補碼錶示法(符號加補碼)。這三種在FPGA開發中都有著廣泛的應用,下面分別討論。

1、原碼錶示法

原碼錶示法是機器數的一種簡單的表示法,採用符號位級聯絕對值的方法表示數字。其最高位為符號位,用0表示正數,1表示負數;其餘部分為絕對數值部分。原碼一般用二進位制形式表示。

例如,X1 = +1010110,X2 = -1001010,則其原碼分別為:01010110和11001010

原碼錶示數的範圍與二進位制位數有關。當用8位二進位制來表示小數原碼時,其表示範圍:最大值為0.1111111,其真值約為10進位制中的0.99;最小值為1.1111111,其真值約為十進位制的-0.99。當用8位二進位制來表示整數原碼時,其表示範圍:最大值為01111111,其真值為十進位制的127;最小值為11111111,其真值為十進位制的-127。

在原碼錶示法中,對0有兩種表示形式,分別記為+0和-0,以8位元資料為例,其相應的表示為:+0=00000000、-0=10000000。

2、反碼錶示法

反碼可由原碼得到。如果數字是正數,則其反碼與原碼一樣;如果數字是負數,則其反碼是對它的原碼(符號位除外)各位取反而得到的。

例如:X1 = +1010110, X2=-1001010,則其相應的反碼為01010110、10110101。

3、補碼錶示法

補碼錶示法師實際中應用最廣泛的數字表示法,其表示規則如下:若是正數,補碼、反碼和原碼的表示是一樣的;若是負數,補碼、反碼和原碼的表示都不一樣。

由反碼與原碼之間的關鍵,負數的補碼等於其反碼在最低位加1。

4、各類表示方法小結

原碼的優點就是乘除運算方便,不論正負數,乘除運算都一樣,並以符號位決定結果的正負號;若做加法則需要判斷兩數符號是否相同;若作減法,還需要判斷兩數絕對值的大小,以使大數減小數。

補碼的優點是,加法運算方便,不論數的正負都可直接相加,而符號位同樣參加運算。

例:給出各類碼字表示法的基本加法運算例項,並說明各自特點

(1)首先給出原碼的運算示例,其中()d代表十進位制數。首先給出一個原碼的減法計算例項,完成“1 + (-1)= 0“”的操作。

(1)d + (-1)d = (0)d

如果讀者直接利用原碼來完成上式運算,會發現用符號位的原碼進行在加減運算的時候就會出現問題,將資料以8位元的表示形式為例,

(00000001)原 + (10000001)原 = (10000001)原 = (-2)d

計算結果是不對的,問題在於兩點:首先,負數的符號位直接改變了計算結果符號;其次,絕對值部分計算也不正確。這說明原碼無法直接完成正數和負數的加法。

(2)既然,原碼不能完成正、負數相加,那麼反碼形式可以完成此操作嗎?仍然以”1 + (-1) = 0“ 為例,其相應的反碼錶達式如下:

(00000000)反 + (11111110)反 = (11111111)反 = (-0)d

則發現問題出現在+0和-0上,因為實際的計算中的零沒有正負之分的。但上式標明瞭反碼完成正、負數相加後,其絕對值部分是正確的,因此能正確完成正、負數相加的表達形式必定包含反碼的特性。

(3)最後給出補碼的相關特性說明,負數的補碼就是對反碼加1,而正數不變。以8位元資料為例,通過(-128)d代替了(-10)d,所以其表示範圍為【-128,127】。從直觀上,補碼消除了(+0)和(-0),並且具備反碼特點,那麼究竟其能完成正、負加法運算嗎?答案是肯定的,下面給出具體例項,所示

(00000001)補 + (11111111)補 = (00000000)補 = (0)d

基於以上討論,可以得到一個基本結論:只有補碼才能正確完成正負加法運算,並將減法運算轉化為加法運算,從而簡化運算規則。

但對於乘法操作,則以原碼形式計算是最方便的,下面有例項。


演示1:原碼進行乘法運算 -2 * 2 = -4

module mul(
		input clk,
		input rstn,
		input [7:0] a,
		input [7:0] b,
		
		output [14:0] q_mul,
		output reg [8:0] q_add,
		output reg[7:0] ra,
    output reg[7:0] rb
    );
    
    
    reg [13:0] rmul;
    
    always @(posedge clk or negedge rstn)
    		if(!rstn)
    			begin
    				q_add <= 0;
    				ra <= 0;
    				rb <= 0;
    				
    				rmul <= 0;
    			end
    		else begin
    			
    			//q_mul <= a*b;
    			if(a[7]==1)
    				ra = {a[7],~a[6:0] + 1};
    			else
    				ra = a;
    			if(b[7]==1)
    				rb = {b[7],~b[6:0] + 1};
    			else
    				rb = b;
    			rmul <= ra[6:0]*rb[6:0];
    			
    			
    			q_add <= {a[7],a} + {b[7],b};
    		end
    		
    		assign q_mul = {a[7]^b[7],rmul};
    		
endmodule

演示2:通過reg signed實現

module signedMul(
		input clk,
		input rstn,
		input [7:0] a,
		input [7:0] b,
		output [15:0] q
    );
    
     reg signed[7:0] ra;
     reg signed[7:0] rb;
    
    always @(posedge clk or negedge rstn) begin
    		if(~rstn) begin
    			ra <= 0;
    			rb <= 0;
    		end
    		else begin
    			ra <= a;
    			rb <= b;
    		end
    end
		assign q = ra * rb;

endmodule



























相關文章