(1)在FPGA綜合成電路的時候最底層都是以補碼的形式在運算,正數的補碼就是本身,負數的補碼要取反+1。
(2)編譯器高的版本都支援verilog有符号運算的綜合了。在定義時直接加上signed即可,如下:
input signed [7:0 ] a,b;
output signed [15:0] c;
wire signed [15:0] x;
reg signed [15:0] y;
很明顯,這種采用signed定義的情況,可以避免手動轉換帶來的麻煩,同時可以節省很多開發時間。
(3)當使用移位運算“>>”進行1/2倍運算時,需注意:
verilog中最簡單的加減乘除運算對于有符号數和無符号數其實是有很大差別的,現總結幾點如下:
例子:對輸入a,b取平均值,然後指派給c輸出
always @(posedge clk)
c<=(a+b)>>1;
1)a,b均為無符号數,結果正确
2)a,b中一個為有符号數(a),另一個為無符号數(b),編譯器會自動将無符号數(b)轉換成有符号數,這樣就成了2個有符号數之間的運算了,結果是個有符号數,此時
1>如果a+b結果為正數(最高位為0),那麼結果正确;
2>如果a+b結果為負數(最高位為1),那麼結果錯誤,因為移位運算新移入的位将用0來填補,此時負數将變為正數,顯然錯誤。
是以綜上,在進行有符号數運算的時候,最好像如下這樣寫:
reg signed [3:0] a;
reg signed [3:0] b;
reg signed [3:0] c;
always @(posedge clk)
c<=(a+b)/2;
這樣就可以避免不必要的錯誤。
淩波微步心得:可以--> 用補碼,或擴充符号位。
//-----------------------------------------------
20 input [3:0] i_a, i_b, i_c;
21 input i_mode;
22 output [7:0] o_answer;
23
24 wire [7:0] answer_unsigned, answer_signed;
25
26 // for unsigned operation
27 assign answer_unsigned = i_a * i_b + {4'h0, i_c};
28
29 // for singed operation
30 assign answer_signed = {{4{i_a[3]}}, i_a} * {{4{i_b[3]}}, i_b} + {{4{i_c[3]}}, i_c};
31
32 assign o_answer = (i_mode == 1'b0) ? answer_unsigned : answer_signed;
//------------------------------------------------------------------------------
39行為signedoperation
assign answer_signed = {{ 4 {i_a[ 3 ]}}, i_a} * {{ 4 {i_b[ 3 ]}}, i_b} + {{ 4 {i_c[ 3 ]}}, i_c};
一個很重要的觀念:要做signed operation時,須先将所有數字做signextension後才能相加相乘。什麼是signedextension呢?将最高位向左補滿,如原來是0就用0補滿,如原來是1就用1補滿。因為結果是8bit,是以i_a、i_b和i_c都必須做signed extension成8 bit才能相加相乘。
轉自:
http://www.cnblogs.com/lanlingshan/archive/2012/05/01/2478004.html
http://www.cnblogs.com/oomusou/archive/2007/11/25/971509.html