FPGA基於Verilog的有符號加法及有符號乘法運算
0 背景
最近所做的工作涉及到有符號數、無符號數之間的加法運算和乘法運算。例如:有些輸入資料是有符號資料,有些引數為無符號資料,它們之間進行算術運算,就會涉及到符號位的變化及運算結果位寬的變化,如果沒有總結出規律,很容易得不到正確的結果,下文將對有符號數加法及乘法的運算規律進行詳述。
1 有符號數加法運算
假設定義兩個8位資料,[7 : 0] A,B,其中A為無符號數,B為有符號資料;則A + B進行有符號加法運算的結果有4種可能;常見的程式設計思路是:通過比較|A|和|B|值大小,然後判定符號位及對應的程式設計,如|A| > |B|,則結果為A的符號位,結果為|A| - |B|;該思路在處理兩個資料運算尚可應對,例如當A、B、C、D等多個有符號資料進行同時運算時,該方法就會捉襟見肘了。
改進方案:將上述所有資料均擴充套件為有符號資料,然後就可以一起進行有符號數加法,得到正確的結果。因為當前FPGA的設計軟體均支援有符號數的加法和乘法運算,從而可以降低開發難度。具體程式見下文。
reg [7 : 0] din0, din1, din2; reg signed [8 : 0] din0_buf, din1_buf, din2_buf; reg signed [10 : 0] add_rslt; reg signed [26 : 0] mult_rslt; ////-------------------------------------------------------------- always@(posedge clk) if(en) begin en0 <= 1; din0 <= din0 + 1; din1 <= din1 + 1; din2 <= din2 + 1; end else begin en0 <= 0; din0 <= -15; din1 <= 4; din2 <= -9; end always@(posedge clk) if(en0) begin din0_buf <= {din0[7],din0}; din1_buf <= {din1[7],din1}; din2_buf <= {din2[7],din2}; en1 <= 1; end else begin din0_buf <= 0; din1_buf <= 0; din2_buf <= 0; en1 <= 0; end always@(posedge clk) if(en1) begin rslt_en <= 1; add_rslt <= din0_buf + din1_buf + din2_buf; mult_rslt <= din0_buf * din1_buf * din2_buf;; end else begin rslt_en <= 0; add_rslt <= 0; mult_rslt <= 0; end
結論: 由上述運算結果可知,該運算結果滿足設計要求。
2 有符號數乘法運算
有符號數和無符號數進行乘法混合運算,設計思路與加法運算相一致。主要是對無符號數進行有符號處理,即進行位擴充套件來新增符號位。 例如: input [7 : 0] din; 可以擴充套件為reg signed [8 : 0] din_buf,將所有待運算資料轉換後,即可進行乘法運算。
綜上所述: 通過新增符號位,進行位擴充套件,同時注意運算結果的最大位寬,則該方法均能得到正確的運算結果。
參考博文:
1. http://blog.sina.com.cn/s/blog_4b1046f80102wlf4.html;
2. http://blog.163.com/gcs_gcs/blog/static/1744860662010102082310910/;