转载 关于有符号数的加法

先总结一下,做signed运算的步骤1.将每个输入扩展到与输出同样位宽2.运算3.取运算结果的最后几个位宽,位宽大小是输出位宽的大小。为防止溢出,事先应确定好输出位宽的大小。

Abstract
若要將原本用軟體實現的演算法用硬體電路實現,馬上會遇到2個很基本的問題:一個是如何處理負數?另一個是如何處理overflow?雖然很基本,但一旦有問題卻很難debug。

Introduction
使用環境:NC-Verilog 5.4 + Debussy 5.4 v9

一般在開發演算法階段,我們會使用C/C++這些高階語言開發,C/C++處理負數乘加運算都很方便與直覺,也不用太擔心overflow的問題,主要是int是4 byte(32 bit)夠大,要overflow也不太容易,若一旦要用硬體電路實現,馬上就面臨2個基本的問題,硬體要怎麼處理負數?要怎麼處理overflow?

Verilog在宣告reg與wire時,雖然能使用+ – * /,並合成出相對的加法器、乘法器與除法器,但這些都是無號數(unsigned integer)運算,也就是說只能做大於或等於0的整數加減乘除運算,無法處理負數運算;除此之外,不像C/C++的int就是32 bit,為了節省硬體cost,我們會根據值域,小心的宣告reg與wire的bit數,如只有4 bit或8 bit而已,這樣經過運算後,可能在某個boundary test pattern下,一不小心就overflow了。

(原創) 無號數及有號數的乘加運算電路設計 (IC Design) (Verilog) (OS) (Linux)(原創) 如何設計乘加電路? (SOC) (Verilog) (MegaCore)中,我都曾經討論過這個問題,這次打算更仔細重新討論,並將overflow議題一並考慮。

本文先討論加法運算部分,乘法部分將另開專文討論之?

Verilog的運算
Verilog所提供的運算分unsigned與signed兩種:

  • Unsigned:不含signed bit

    • 以4 bit來說,值域從0000~1111,也就是0 ~ 15
  • Signed:含signed bit(MSB為signed bit,1為負,0為正,負數使用2補數表示)
    • 以4 bit來說,值域從1000~0111,也就是-8 ~ +7

二進位signed加法運算
在真正開始使用Verilog做signed加法運算前,我們先來看看實際上二進位singed加法是如何運算?

Normal Condition (沒有Overflow)
(+6) + (-3) = (+3)

為了節省resource,我們故意使用4 bit的+6與3 bit的-3相加,若直接將兩個signed值相加,答案為-7,很顯然答案並不正確?

因為4 bit與3 bit相加,結果可能進位到5 bit,正確的作法是將4 bit的+6做signed extension到5 bit,且3 bit的-3也要做signed extension到5 bit後,然後才相加,若最後進位到6 bit,則不考慮6 bit的值?

在此補充一下何謂Singed Extension?簡單的說,當以較多bit顯示signed型態的值時,重複signed bit補齊?

就意義上來說,就是3 bit的signed值若要以5 bit表示時,必須補上signed bit才能在5 bit表示,所以101要變成11101?

Boundary Condition (正Overflow)
(+7) + (+3) = (+10)

為了節省resource,我們一樣故意使用4 bit的+7與3 bit的+3相加,若直接將兩個signed值相加,答案為-6,很顯然答案並不正確。

根據上個例子的經驗,+7與+3必須做signed extension才能相加,這樣才能得到正確答案+10?

不過現在問題來了,+10必須動到5 bit才能顯示,若輸出的值域為4 bit,只能-8 ~ +7,+10很顯然已經正overflow了?

若只能以4 bit表示,因為是正的,MSB必須是0(SUM[3]=0),所以若MSB是1就表示由進位而來,也就是正overflow了(此例的SUM[3]為1,所以已經正overflow),再加上因為目前運算結果為5 bit,且是正,所以SUM[5]必須為0。

也就是說,若SUM[5]=0且SUM[4]=1時,為正overflow,所以01010對於4 bit來說,是正overflow。

Boundary Condition (負Overflow)
(-5) + (-4) = (-9)

同樣為了節省resource,我們故意使用4 bit的-5與3 bit的-4相加,若直接將兩個signed值相加,答案為-1,很顯然的答案並不正確?

根據前面兩個例子,-5與-4一樣必須做signed extension才能相加,這樣才能得到正確答案-9?進位到6 bit的1要捨去,所以答案是10111?

問題一樣來了,-9必須動到5 bit才能顯示,若輸出的值域是4 bit,只能-8 ~ +7,-9很顯然已經是負overflow了?

若只能以4 bit表示,因為是負的,MSB必須是1(SUM[3]=1),所以若MSB是0就表示由進位而來,也就是負overflow了(此例的SUM[3]為0,所以已經負overflow),再加上因為目前運算結果為5 bit,且是負,所以SUM[5]必須為1?

也就是說,若SUM[5]為1且SUM[4]為0時,為負overflow,所以10111對於4 bit來說,是負overflow?

二進位Signed加法運算Summary

根據之前三個實際的例子,我們得到以下結論

  • m bit + m bit => (m+1) bit
  • m bit + n bit => (m+1) bit,其中n < m
    • m bit與n bit都必須先做signed extension到(m+1) bit才能相加
    • 若結果有到(m+2) bit則忽略之,實際的結果為(m+1) bit
  • 若Sum[m+1] ^ Sum[m]為1,表示有overflow
    • 若Sum[m+1]為0且Sum[m]為1,則為正overflow
    • 若Sum[m+1]為1且Sum[m]為0,則為負overflow

使用Verilog實現
signed_add.v / Verilog

1 /* 
2 (C) OOMusou 2009 http://oomusou.cnblogs.com

4 Filename    : signed_add.v
5 Simulator   : NC-Verilog 5.4 + Debussy 5.4 v9
6 Description : signed add & overflow
7 Release     : Oct/24/2009 1.0
8 */

10 module signed_add (
11   clk,
12   rst_n,
13   a_i,
14   b_i,
15   sum_o
16 );
17 
18 input clk;
19 input rst_n;
20 input [3:0] a_i;
21 input [2:0] b_i;
22 output [3:0] sum_o;
23 
24 reg [4:0] sum_t;
25 [email protected](posedge clk or negedge rst_n)
26   if (~rst_n)
27     sum_t <= 5‘h0;
28   else
29     sum_t <= {a_i[3], a_i} + {{2{b_i[2]}}, b_i};
30     
31 assign sum_o = (~sum_t[4] &  sum_t[3]) ? 4‘b0111 : // + overflow
32                ( sum_t[4] & ~sum_t[3]) ? 4‘b1000 : // - overflow
33                sum_t[3:0];
34 endmodule

20 ~ 22行

input [3:0] a_i;
input [2:0] b_i;
output [3:0] sum_o;

輸入一個為3 bit,一個為4 bit,輸出為4 bit,與之前舉的例子一樣?

29行

sum_t <= {a_i[3], a_i} + {{2{b_i[2]}}, b_i};

將4 bit的a_i做signed extension到5 bit,將3 bit的b_i做signed extension到5 bit?

31行

(~sum_t[4] &  sum_t[3]) ? 4‘b0111 : // + overflow

判斷是否為正overflow,若sum_t[4]為0且sum_t[3]為1,則為正overflow?

32行

( sum_t[4] & ~sum_t[3]) ? 4‘b1000 : // - overflow

判斷是否為負overflow,若sum_t[4]為1且sum_t[3]為0,則為負overflow?

Testbench
signed_add_tb.v / Verilog 

1 /* 
2 (C) OOMusou 2009 http://oomusou.cnblogs.com

4 Filename    : signed_add_tb.v
5 Simulator   : NC-Verilog 5.4 + Debussy 5.4 v9
6 Description : signed add & overflow testbench
7 Release     : Oct/24/2009 1.0
8 */

10 `include "signed_add.v"
11 
12 module signed_add_tb;
13 
14 reg clk;
15 reg rst_n;
16 reg [3:0] a_i;
17 reg [2:0] b_i;
18 wire [3:0] sum_o;
19 
20 // 4 bit
21 // -8 ~ +7
22 // 3 bit
23 // -4 ~ +3
24 initial begin
25   //a_i <= 4‘b0000;
26   //b_i <= 3‘b000;
27   a_i <= 4‘d0;
28   b_i <= 3‘d0;
29   
30   // normal
31   // (+6) + (-3) 
32   #10;
33   //a_i <= 4‘b0110; 
34   //b_i <= 3‘b101;
35   a_i <= 4‘d6;
36   b_i <= -3‘d3;
37   
38   // overflow
39   // 7 + 3 = 10
40   #20;
41   //a_i <= 4‘b0111;
42   //b_i <= 3‘b011;
43   a_i <= 4‘d7;
44   b_i <= 3‘d3;
45   
46   // underflow
47   // (-5) + (-4)
48   #20;
49   //a_i <= 4‘b1011;
50   //b_i <= 3‘b100; 
51   a_i <= -4‘d5;
52   b_i <= -3‘d4;
53   
54   #20;
55   //a_i <= 4‘b0000;
56   //b_i <= 3‘b000;
57   a_i <= 4‘d0;
58   b_i <= 3‘d0;
59 end
60 
61 
62 initial clk = 1‘b0;
63 always #10 clk = ~clk;
64 
65 initial begin
66   rst_n = 1‘b0;
67   #5;
68   rst_n = 1‘b1;
69 end
70 
71 initial begin
72   $fsdbDumpfile("signed_add.fsdb");
73   $fsdbDumpvars(0, signed_add_tb);
74   #100;
75   $finish;
76 end
77 
78 signed_add signed_add0 (
79   .clk(clk),
80   .rst_n(rst_n),
81   .a_i(a_i),
82   .b_i(b_i),
83   .sum_o(sum_o)
84 );
85 
86 
87 endmodule

模擬結果

7 + 3 = 10,因為已經正overflow,所以使用4 bit最大值+7表示?
(-5) + (-4) = (-9),因為已經負overflow,所以使用4 bit最小值-8表示?

完整程式碼下載
signed_add.7z

Conclusion
本文詳細討論了在數位電路與Verilog中,如何執行帶負數的加法,以及如何判斷overflow等課題,雖然非常基本,但在使用硬體實現演算法時卻非常重要,下一次將討論如何在數位電路與Verilog實現帶負數的乘法?

时间: 2024-08-13 22:34:26

转载 关于有符号数的加法的相关文章

关于有符号数和无符号数的转换 - C/C++

转载自:http://www.94cto.com/index/Article/content/id/59973.html 1.引例: 今天在做了一道关于有符号数和无符号数相互转换及其左移/右移的问题,被它们之间的转换原理和位移原理搞得头大了.真的很后悔本科的时候没有认真学习<计算机组成原理>/<计算机操作系统>等计算机基础课程.以下是我根据相关知识回顾和整理的材料,如有和某某的文章有雷同之处,请勿见怪.另外也希望看到这篇文章的同志们能够有所收获吧. #include <cst

有符号数的加减法 和无符号数的加减法,和,系统是如何识别有符号数和无符号数的

一.有符号数的加减法 1.符号数与无符号数的人为规定性: 一个数,是有符号数还是无符号数都是人为规定的.进行二进制运算时用无符号数或是补码运算时,结果都是正确的. 10000100+00001110 若规定为无符号数,即 132+146=146D . 若规定为符号数,则为-124+14=-110,而[-110]补=10010010.解释:10000100是 -124的补码,0001110是14的补码,在机器中运算后得出的结果是[-110]的补码.机器中的有符号数的运算一般就是补码的运算. 2.补

FPGA中的有符号数和无符号数的运算

在FPGA设计中,所有的算数运算符都是按照无符号数进行的.如果要完成有符号数计算,对于加.减操作通过补码处理即可用无符号加法完成.对于乘法操作,无符号数直接采用“*”运算符,有符号数运算可通过定义输出为 signed 来处理. 需要注意的是,尽量不要使有符号数与无符号数进行混合计算.因为只要有一个无符号数的运算单元,整个算式将被将成无符号数进行计算.   总之,正数和负数处理时都是按照补码的形式处理,具体究竟把这些补码理解为符号型还是无符号型,这就要看reg signed这样的声明了.如果声明了

理解有符号数和无符号数

负数在计算机中如何表示呢? 一种是教科书,它会告诉你:计算机用"补码"表示负数.可是有关"补码"的概念一说就得一节课,这一些我们需要在第6章中用一章的篇幅讲2进制的一切.再者,用"补码"表示负数,其实一种公式,公式的作用在于告诉你,想得问题的答案,应该如何计算.却并没有告诉你为什么用这个公式就可以和答案? 另一种是一些程序员告诉你的:用二进制数的最高位表示符号,最高位是0,表示正数,最高位是1,表示负数.这种说法本身没错,可是如果没有下文,那么它

fpga中有符号数的计算

在fpga设计中,所有的算数运算符都是按照无符号数进行的.最近用FPGA做了有符号的计算,来记录一下 1.如果要完成有符号数计算,对于加.减操作通过补码处理即可用无符号加法完成.不过在计算的时候要考虑位数的限制,不管在做加法还是减法,结果的位数要比原来的数据多出一位, 这样计算的时候才不会出现量程的错误. example1: module signed_yz( input clk,rst_n, input signed [7:0]data, input signed [7:0]datb, out

关于有符号数和无符号数的转换

1.引例: 今天在做了一道关于有符号数和无符号数相互转换及其左移/右移的问题,被它们之间的转换原理和位移原理搞得头大了.真的很后悔本科的时候没有认真学习<计算机组成原理>/<计算机操作系统>等计算机基础课程.以下是我根据相关知识回顾和整理的材料,如有和某某的文章有雷同之处,请勿见怪.另外也希望看到这篇文章的同志们能够有所收获吧. #include <cstdio> #include <iostream> using namespace std; int ma

Booth算法(有符号数的乘法)

求 M3M2M1M0×Q3Q2Q1Q0 :  0110×0101  (有符号数用补码表示,最高位表示正负) 1.添加辅助位:A=0000     Q-1=0 2.控制逻辑判断: ①Q0Q-1=01 时:A=A+M 然后 A.Q.Q-1算术右移 (两步) ②Q0Q-1=10 时:A=A-M  然后 A.Q.Q-1算术右移 (两步) 补码加减:(A-M)补码=A补码+(-M)补码 ③Q0Q-1=00或11 时:A.Q.Q-1算术右移 (一步) 补码右移:空位填1 3.Q有几位就做几次右移运算.(如:

有符号数和无符号数负数(转)

有符号数和无符号数负数 理解有符号数和无符号数负数在计算机中如何表示呢? 这一点,你可能听过两种不同的回答. 一种是教科书,它会告诉你:计算机用"补码"表示负数.可是有关"补码"的概念一说就得一节课,这一些我们需要在第6章中用一章的篇幅讲2进制的一切.再者,用"补码"表示负数,其实一种公式,公式的作用在于告诉你,想得问题的答案,应该如何计算.却并没有告诉你为什么用这个公式就可以和答案? 另一种是一些程序员告诉你的:用二进制数的最高位表示符号,最高

有符号数和无符号数

摘抄自:http://www.cnblogs.com/glacierh/archive/2013/07/16/3194658.html 1.      补码 在计算机中无符号数用原码表示,有符号数用补码表示.w位补码表示的值为: 最高位 也称符号位,1表示负数,0表示正数,符号位为0时,和无符号数的表示是相同的,以下是4位补码的示例: 0101 = -0*23 + 1*22 + 0*21 + 1*20 = 5 1101 = -1*23 + 1*22 + 0*21 + 1*20 = -3 w位的补