原创地址:http://www.cnblogs.com/oomusou/archive/2007/11/25/971509.html
Abstract
有號數(signed operation)由於需要2's complement,所以乘加運算方式和無號數(unsigned operation)不同,該如何實現這兩種運算呢?
Introduction
欲設計一個電路計算a * b + c,當mode=0時,採用unsigned operation,當mode=1時,採用signed operation。
Verilog
1
/*
2
(C) OOMusou 2007
http://oomusou.cnblogs.com
3
4
Filename : Signed_unsigned_arithmetic.v
5
Compiler : ModelSim SE 6.1f
6
Description : Demo how to do unsigned operation and signed operation
7
Release : 11/24/2007 1.0
8
02/09/2008 2.0
9
*/
10
`timescale
1
ns
/
1
ns
11
12
module Signed_unsigned_arithmetic (
13
i_a,
14
i_b,
15
i_c,
16
i_mode,
17
o_answer
18
);
19
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;
33
34
endmodule
27行為unsigned operation
assign answer_unsigned
=
i_a
*
i_b
+
{
4
'
h0, i_c};
由於i_a, i_b, i_c均為4 bit,運算最多可能出現8 bit,故在21行已經宣告了answer_unsigned和answer_signed為8 bit,乘法a * b自動為8 bit,所以沒問題,但加法 + i_c時,i_c原本為4 bit,要變成8 bit,只要在左邊補4個0即可,如此8 bit + 8 bit = 8 bit。
39行為signed operation
assign answer_signed
=
{{
4
{i_a[
3
]}}, i_a}
*
{{
4
{i_b[
3
]}}, i_b}
+
{{
4
{i_c[
3
]}}, i_c};
一個很重要的觀念:要做signed operation時,須先將所有數字做sign extension後才能相加相乘。什麼是signed extension呢?將最高位元向左補滿,如原來是0就用0補滿,如原來是1就用1補滿。因為結果是8 bit,所以i_a、i_b和i_c都必須做signed extension成8 bit才能相加相乘。
表示取i_a的最高位元i_a[3]『重複』4次後,再與原來的i_a『合併』,i_b和i_c的原理一樣。
Testbench
1
/*
2
(C) OOMusou 2007
http://oomusou.cnblogs.com
3
4
Filename : Signed_unsigned_arithmetic_tb.v
5
Simulator : ModelSim SE 6.1f
6
Description : Testbench for signed_unsigend_arithmetic.v
7
Release : 11/24/2007 1.0
8
02/09/2008 2.0
9
*/
10
11
`timescale
1
ns
/
1
ns
12
13
module Signed_unsigned_arithmetic_tb;
14
reg [
3
:
0
] i_a, i_b, i_c;
15
reg i_mode;
16
wire [
7
:
0
] o_answer;
17
18
Signed_unsigned_arithmetic u0 (
19
.i_a(i_a),
20
.i_b(i_b),
21
.i_c(i_c),
22
.i_mode(i_mode),
23
.o_answer(o_answer)
24
);
25
26
initial begin
27
i_mode
=
0
;
//
unsigned operation
28
i_a
=
4
'
b0010; // 2
29
i_b
=
4
'
b0011; // 3
30
i_c
=
4
'
b0100; // 4
31
//
answer = 8'b0000_1010
//
10
32
33
#
50
;
34
i_mode
=
1
;
//
signed operation
35
i_a
=
4
'
b1111; // -1
36
i_b
=
4
'
b1110; // -2
37
i_c
=
4
'
b0011; // 3
38
//
answer = 8'0000_0101
//
5
39
end
40
41
endmodule
Waveform

Conclusion
在本例,我們看到硬體在實現算數運算時,牽涉到負數的麻煩。軟體方面,在Linux kernel中,我們會發現他們很小心的使用unsigned int,若以記憶體而言,unsigned int和int都是4 byte,其實省不到記憶體,我推測可能因為執行速度的關係。在本例,我們看到unsigned operation和signed operation在數位電路的差異,signed operation明顯比較複雜,也就是說若在C/C++只使用int,在硬體會跑signed operation,而unsigned int會跑unsigned operation,速度較快,所以推估是因為速度考量使用unsigned int。
Reference
Verilog 數位電路設計範例寶典(基礎篇),鄭羽伸,儒林圖書公司,2006
See Also
(原創) 如何用管線(Pipeline)實作無號數乘加運算? (IC Design) (Verilog)
(原創) 如何處理signed integer的加法運算與overflow? (SOC) (Verilog)
(原創) 如何設計2數相加的電路? (SOC) (Verilog)
(原創) 如何設計乘加電路? (SOC) (Verilog) (MegaCore)