http://www.cnblogs.com/maqingbiao/archive/2010/07/27/1786187.html
本例程采用加法器数乘法器实现17位有符号数相乘。参考《基于Verilog HDL 的数字系统应用设计》,王钿 ,桌兴旺 编著
1
module
signed_mult17b_addtree (
2
mul_a,
3
mul_b,
4
mul_out,
5
clk,
6
rst_n,
7
);
8
9
parameter
MUL_WIDTH
=
17
;
10
parameter
MUL_RESULT
=
33
;
11
12
input
[MUL_WIDTH
-
1
:
0
] mul_a;
13
input
[MUL_WIDTH
-
1
:
0
] mul_b;
14
input
clk;
15
input
rst_n;
16
17
output
[MUL_RESULT
-
1
:
0
] mul_out;
18
19
reg
[MUL_RESULT
-
1
:
0
] mul_out;
20
reg
[MUL_RESULT
-
1
:
0
] mul_out_reg;
21
reg
msb;
22
reg
msb_reg_0;
23
reg
msb_reg_1;
24
reg
msb_reg_2;
25
reg
msb_reg_3;
26
reg
[MUL_WIDTH
-
1
:
0
] mul_a_reg;
27
reg
[MUL_WIDTH
-
1
:
0
] mul_b_reg;
28
29
reg
[MUL_RESULT
-
2
:
0
] stored0;
30
reg
[MUL_RESULT
-
2
:
0
] stored1;
31
reg
[MUL_RESULT
-
2
:
0
] stored2;
32
reg
[MUL_RESULT
-
2
:
0
] stored3;
33
reg
[MUL_RESULT
-
2
:
0
] stored4;
34
reg
[MUL_RESULT
-
2
:
0
] stored5;
35
reg
[MUL_RESULT
-
2
:
0
] stored6;
36
reg
[MUL_RESULT
-
2
:
0
] stored7;
37
reg
[MUL_RESULT
-
2
:
0
] stored8;
38
reg
[MUL_RESULT
-
2
:
0
] stored9;
39
reg
[MUL_RESULT
-
2
:
0
] stored10;
40
reg
[MUL_RESULT
-
2
:
0
] stored11;
41
reg
[MUL_RESULT
-
2
:
0
] stored12;
42
reg
[MUL_RESULT
-
2
:
0
] stored13;
43
reg
[MUL_RESULT
-
2
:
0
] stored14;
44
reg
[MUL_RESULT
-
2
:
0
] stored15;
45
46
reg
[MUL_RESULT
-
2
:
0
] add0_0;
47
reg
[MUL_RESULT
-
2
:
0
] add0_1;
48
reg
[MUL_RESULT
-
2
:
0
] add0_2;
49
reg
[MUL_RESULT
-
2
:
0
] add0_3;
50
reg
[MUL_RESULT
-
2
:
0
] add0_4;
51
reg
[MUL_RESULT
-
2
:
0
] add0_5;
52
reg
[MUL_RESULT
-
2
:
0
] add0_6;
53
reg
[MUL_RESULT
-
2
:
0
] add0_7;
54
55
reg
[MUL_RESULT
-
2
:
0
] add1_0;
56
reg
[MUL_RESULT
-
2
:
0
] add1_1;
57
reg
[MUL_RESULT
-
2
:
0
] add1_2;
58
reg
[MUL_RESULT
-
2
:
0
] add1_3;
59
60
reg
[MUL_RESULT
-
2
:
0
] add2_0;
61
reg
[MUL_RESULT
-
2
:
0
] add2_1;
62
63
reg
[MUL_RESULT
-
1
:
0
] add3_0;
64
65
always
@ (
posedge
clk
or
negedge
rst_n )
66
begin
67
if
(
!
rst_n )
68
begin
69
mul_a_reg
<=
17
'
b0;
70
mul_b_reg
<=
17
'
b0;
71
72
stored0
<=
32
'
b0;
73
stored1
<=
32
'
b0;
74
stored2
<=
32
'
b0;
75
stored3
<=
32
'
b0;
76
stored4
<=
32
'
b0;
77
stored5
<=
32
'
b0;
78
stored6
<=
32
'
b0;
79
stored7
<=
32
'
b0;
80
stored8
<=
32
'
b0;
81
stored9
<=
32
'
b0;
82
stored10
<=
32
'
b0;
83
stored11
<=
32
'
b0;
84
stored12
<=
32
'
b0;
85
stored13
<=
32
'
b0;
86
stored14
<=
32
'
b0;
87
stored15
<=
32
'
b0;
88
89
add0_0
<=
32
'
b0;
90
add0_1
<=
32
'
b0;
91
add0_2
<=
32
'
b0;
92
add0_3
<=
32
'
b0;
93
add0_4
<=
32
'
b0;
94
add0_5
<=
32
'
b0;
95
add0_6
<=
32
'
b0;
96
add0_7
<=
32
'
b0;
97
98
99
add1_0
<=
32
'
b0;
100
add1_1
<=
32
'
b0;
101
add1_2
<=
32
'
b0;
102
add1_3
<=
32
'
b0;
103
104
add2_0
<=
32
'
b0;
105
add2_1
<=
32
'
b0;
106
107
add3_0
<=
32
'
b0;
108
109
msb
<=
1
'
b0;
110
msb_reg_0
<=
1
'
b0;
111
msb_reg_1
<=
1
'
b0;
112
msb_reg_2
<=
1
'
b0;
113
msb_reg_3
<=
1
'
b0;
114
115
mul_out_reg
<=
33
'
b0;
116
mul_out
<=
33
'
b0;
117
118
end
119
else
120
begin
121
mul_a_reg
<=
(mul_a[
16
]
==
0
)
?
mul_a : {mul_a[
16
],
~
mul_a[
15
:
0
]
+
1
'
b1};
122
mul_b_reg
<=
(mul_b[
16
]
==
0
)
?
mul_b : {mul_b[
16
],
~
mul_b[
15
:
0
]
+
1
'
b1};
123
124
msb_reg_0
<=
mul_a_reg[
16
]
^
mul_b_reg[
16
];
125
msb_reg_1
<=
msb_reg_0;
126
msb_reg_2
<=
msb_reg_1;
127
msb_reg_3
<=
msb_reg_2;
128
msb
<=
msb_reg_3;
129
130
stored0
<=
mul_b_reg[
0
]
?
{
16
'
b0,mul_a_reg[15:0]} : 32
'
b0;
131
stored1
<=
mul_b_reg[
1
]
?
{
15
'
b0,mul_a_reg[15:0],1
'
b0} :
32
'
b0;
132
stored2
<=
mul_b_reg[
2
]
?
{
14
'
b0,mul_a_reg[15:0],2
'
b0} :
32
'
b0;
133
stored3
<=
mul_b_reg[
3
]
?
{
13
'
b0,mul_a_reg[15:0],3
'
b0} :
32
'
b0;
134
stored4
<=
mul_b_reg[
4
]
?
{
12
'
b0,mul_a_reg[15:0],4
'
b0} :
32
'
b0;
135
stored5
<=
mul_b_reg[
5
]
?
{
11
'
b0,mul_a_reg[15:0],5
'
b0} :
32
'
b0;
136
stored6
<=
mul_b_reg[
6
]
?
{
10
'
b0,mul_a_reg[15:0],6
'
b0} :
32
'
b0;
137
stored7
<=
mul_b_reg[
7
]
?
{
9
'
b0,mul_a_reg[15:0],7
'
b0} :
32
'
b0;
138
stored8
<=
mul_b_reg[
8
]
?
{
8
'
b0,mul_a_reg[15:0],8
'
b0} :
32
'
b0;
139
stored9
<=
mul_b_reg[
9
]
?
{
7
'
b0,mul_a_reg[15:0],9
'
b0} :
32
'
b0;
140
stored10
<=
mul_b_reg[
10
]
?
{
6
'
b0,mul_a_reg[15:0],10
'
b0} :
32
'
b0;
141
stored11
<=
mul_b_reg[
11
]
?
{
5
'
b0,mul_a_reg[15:0],11
'
b0} :
32
'
b0;
142
stored12
<=
mul_b_reg[
12
]
?
{
4
'
b0,mul_a_reg[15:0],12
'
b0} :
32
'
b0;
143
stored13
<=
mul_b_reg[
13
]
?
{
3
'
b0,mul_a_reg[15:0],13
'
b0} :
32
'
b0;
144
stored14
<=
mul_b_reg[
14
]
?
{
2
'
b0,mul_a_reg[15:0],14
'
b0} :
32
'
b0;
145
stored15
<=
mul_b_reg[
15
]
?
{
1
'
b0,mul_a_reg[15:0],15
'
b0} :
32
'
b0;
146
147
add0_0
<=
stored0
+
stored1;
148
add0_1
<=
stored2
+
stored3;
149
add0_2
<=
stored4
+
stored5;
150
add0_3
<=
stored6
+
stored7;
151
add0_4
<=
stored8
+
stored9;
152
add0_5
<=
stored10
+
stored11;
153
add0_6
<=
stored12
+
stored13;
154
add0_7
<=
stored14
+
stored15;
155
156
add1_0
<=
add0_0
+
add0_1;
157
add1_1
<=
add0_2
+
add0_3;
158
add1_2
<=
add0_4
+
add0_5;
159
add1_3
<=
add0_6
+
add0_7;
160
161
add2_0
<=
add1_0
+
add1_1;
162
add2_1
<=
add1_2
+
add1_3;
163
164
add3_0
<=
add2_0
+
add2_1;
165
166
mul_out_reg
<=
{msb,add3_0[
31
:
0
]};
167
mul_out
<=
(mul_out_reg[
32
]
==
0
)
?
mul_out_reg : {mul_out_reg[
32
],
~
mul_out_reg[
31
:
0
]
+
1
'
b1};
168
169
end
170
end
171
172
endmodule
173
174
调试小结:本例程采用了5级流水线技术,以至于能在一个时钟周期内完成一次乘法运算输出。参考的范例为4位无符号输入,采用2级流水线技术。
由于是有符号运算,符号位要单独处理,也就是把两个数的最高位相异或,即可得到乘积的符号位。如:
1
msb_reg_0
<=
mul_a_reg[
16
]
^
mul_b_reg[
16
];
有符号数是以补码形式存放在内存的,所以必须要将补码转换为原码后再进行运算,运算后的结果再根据乘积符号位判断最终结果是正还是负,若为负,还需将运算后的结果还原为补码,之后加入一位符号位,便可得到33位的有符号最终结果。(无论是整数还是小数都适用)
1
mul_a_reg
<=
(mul_a[
16
]
==
0
)
?
mul_a : {mul_a[
16
],
~
mul_a[
15
:
0
]
+
1
'
b1};
2
mul_b_reg
<=
(mul_b[
16
]
==
0
)
?
mul_b : {mul_b[
16
],
~
mul_b[
15
:
0
]
+
1
'
b1};
3
mul_out
<=
(mul_out_reg[
32
]
==
0
)
?
mul_out_reg : {mul_out_reg[
32
],
~
mul_out_reg[
31
:
0
]
+
1
'
b1};
由于采用流水线技术,所以有可能会出现时序不一致,该例程出现的问题就是符号位的运算和数据位的运算时序不一致,所以添增了几层赋值运算,确保二则时序一致,不然将会运算出错。
1
msb_reg_1
<=
msb_reg_0;
2
msb_reg_2
<=
msb_reg_1;
3
msb_reg_3
<=
msb_reg_2;
4
msb
<=
msb_reg_3;
本例程只用了一个always,里面有很多的运算,最初,我心里想,我在一个always里面进行那么多的运算,一个时钟周期怎么能处理完呢,如果一个时钟周期处理不完,那么不是有些变量的值会丢失吗,最初没有调试成功,我一直都怀疑是这个原因,所以我就把always里的每一个运算都单独拿出来,放到一个always里面,也就是每个always里只有一个运算,一共写了好几十个always,程序写得相当的长,但问题还是没有解决,然后再一次仔细研究,才发现是符号位运算的时序跟数据位运算不一致,所以就想办法延时符号位运算结果送至最终乘积结果的时间,现在想出的办法是多加几层的赋值,来拖延符号运算结果送至最终乘积结果的时间。这时才发现,原来我一直没有搞明白always是怎样一步一步执行的,现在明白了,时钟触发always语句里面一般都用非阻塞赋值,非阻塞赋值就是第二个赋值语句,不需要等待第一个赋值语句完成后才进行,这样的结果是,第二个赋值语句不能以第一个语句的最新结果参与运算,而是以前一状态的值参与运算。他们几乎是同时进行的,也就是在每个时钟内,always里面的语句都将执行一次,不存在一个时钟内,有些语句还未执行到。最初,我学Verilog的时候就把非阻塞语句和阻塞语句区别开了的,但似乎并没有真正理解并会应用。我为这个,付出了很多很多,现在终于解决了!
改正一处:
原来:
1
mul_out_reg
<=
{msb,add3_0[
31
:
0
]};
2
mul_out
<=
(mul_out_reg[
32
]
==
0
)
?
mul_out_reg :
3
{mul_out_reg[
32
],
~
mul_out_reg[
31
:
0
]
+
1
'
b1};
更改为:
1
mul_out_reg
<=
(add3_0
==
0
)
?
33
'
b0 : {msb,add3_0[31:0]};
2
mul_out
<=
(mul_out_reg
==
0
)
?
33
'
b0 : (mul_out_reg[32]==0)? mul_out_reg :
3
{mul_out_reg[32
],
~
mul_out_reg[31
:
0
]
+
1
'
b1};
4
更改原因:当输入的两个数,一个为0,另一个为负数时,按原来的代码运算乘积并不是0,而是-1,所以需要改正,改正后不会出现这样的错误。
回复 引用 查看
#2楼[楼主] 2010-09-09 20:14
@我不是劫匪
现在正在进行广西区电子竞赛 忙碌中,赛后在给你回复 回复 引用 查看
#3楼[楼主] 2010-09-17 21:41
@我不是劫匪
“我用modeisim仿了你这个程序,乘法运算结果相对于输入貌似是延迟了7个时钟啊。”这个延迟是肯定会有的,但这只是延迟而已,每个时钟周期还是可以完成一个运算的,也就是每个时钟周期都会有运算结果输出。
“1、我的做法(把负数先当成正数进行运算)是否妥当?”这个我倒也试过,但没有成功,仿真出来的结果不正确,你可以输入多几个仿真数据,看一下是不是每种情况都能正确输出,感觉我现在那样处理时绕了一圈才回到原点的。
“2,运算结果延迟的时钟个数是不是会随着乘法器位数的增加而增加的?” 这个肯定会这样的 肯定会增加延时,但也是能做到每个周期出一个数据,这种延时对于大多数的处理时没有多大影响的 回复 引用 查看
#1楼 2010-09-09 20:11