文档艾米电子算术运算电路Verilog.docx
《文档艾米电子算术运算电路Verilog.docx》由会员分享,可在线阅读,更多相关《文档艾米电子算术运算电路Verilog.docx(18页珍藏版)》请在冰点文库上搜索。
文档艾米电子算术运算电路Verilog
[文档].艾米电子-算术运算电路,Verilog
1算术电路
VerilogHDL中,+、-、*、/、%都是可以综合的,其消耗的资源视器件资源不同而不同。
譬如:
+、-都会被综合成Adder,每一位大约消耗一个LE(CycloneII);*则会被综合成乘法器,若器件内含有乘法器,则底层被映射成乘法器,否则使用LE实现。
下面慢慢讨论。
1.1加法运算+
代码1.1加法运算(可综合)
1
2
3
4
5
6
7
modulearithmetic(
input[7:
0]iA,
input[7:
0]iB,
output[8:
0]oAdd
);
assignoAdd=iA+iB;
endmodule
图1.1加法运算综合的RTL视图及资源消耗
如图1.1所示加法运算被综合成ADDER,其资源消耗约1LE/位(对应CycloneII的LUT-4结构的LE)。
代码1.2加法运算的testbench(不可综合,仅用于仿真)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
`timescale1ns/1ns
modulearithmetic_tb;
reg[7:
0]i_a=8'b1011_0111;
reg[7:
0]i_b=8'b0100_1000;
wire[8:
0]o_add;
initial#100$stop;
arithmeticarithmetic_inst(
.iA(i_a),
.iB(i_b),
.oAdd(o_add)
);
endmodule
图1.2加法运算的功能仿真
1.2乘法运算*
代码1.3乘法运算代码
1
2
3
4
5
6
7
modulearithmetic(
input[7:
0]iA,
input[7:
0]iB,
output[15:
0]oMul
);
assignoMul=iA*iB;
endmodule
图1.3乘法运算直接调用lpm_mult
图1.4乘法运算综合的RTL视图及资源消耗
观察综合后的结果,我们发现,CyloneII的x被直接映射到了乘法器。
此处为EmbeddedMultiplier9-bitelements,实际上CycloneII嵌入的乘法器为18位的,每一个乘法器又可以拆成2个9位的乘法器使用。
代码1.4乘法运算的testbench
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
`timescale1ns/1ns
modulearithmetic_tb;
reg[7:
0]i_a=8'b1011_0111;
reg[7:
0]i_b=8'b0100_1000;
wire[15:
0]o_mul;
initial#100$stop;
arithmeticarithmetic_inst(
.iA(i_a),
.iB(i_b),
.oMul(o_mul)
);
endmodule
图1.5乘法运算的功能仿真波形
1.3除法运算/
代码1.5除法运算
1
2
3
4
5
6
7
modulearithmetic(
input[7:
0]iA,
input[7:
0]iB,
output[7:
0]oDiv
);
assignoDiv=iA/iB;
endmodule
综合之后,我们发现除法运算是直接调用的lpm_divide来实现的。
图1.5除法运算直接调用lpm_divide
图1.6除法运算综合的RTL视图及资源消耗
由图1.6所示,除法运算虽然可以直接调用宏,但是其资源消耗也是非常巨大,大约每一位除法消耗10个LE。
代码1.6除法运算的testbench
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
`timescale1ns/1ns
modulearithmetic_tb;
reg[7:
0]i_a=8'b1011_0111;
reg[7:
0]i_b=8'b0100_1000;
wire[7:
0]o_div;
initial#100$stop;
arithmeticarithmetic_inst(
.iA(i_a),
.iB(i_b),
.oDiv(o_div)
);
endmodule
图1.7除法运算的功能仿真波形
1.4取余运算%
代码1.7取余运算
1
2
3
4
5
6
7
modulearithmetic(
input[7:
0]iA,
input[7:
0]iB,
output[7:
0]oMod
);
assignoMod=iA%iB;
endmodule
同除法运算一样,取余运算也是直接调用的lpm_divide来实现的。
图1.8取余运算直接调用宏实现
图1.9取余运算综合的RTL视图及资源消耗
代码1.8取余运算的testbench
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
`timescale1ns/1ns
modulearithmetic_tb;
reg[7:
0]i_a=8'b1011_0111;
reg[7:
0]i_b=8'b0100_1000;
wire[7:
0]o_mod;
initial#100$stop;
arithmeticarithmetic_inst(
.iA(i_a),
.iB(i_b),
.oMod(o_mod)
);
endmodule
图1.10取余运算的功能仿真波形
2数据比较器
代码2.1数据比较器(可综合)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
modulearithmetic(
input[3:
0]iA,
input[3:
0]iB,
outputoEQ,//等于
outputoNEQ,//不等于
outputoGT,//大于
outputoGT_EQ,//大于等于
outputoLT,//小于
outputoLT_EQ//小于等于
);
assignoEQ=(iA==iB),
oNEQ=(iA!
=iB),
oGT=(iA>iB),
oGT_EQ=(iA>=iB),
oLT=(iAoLT_EQ=(iA<=iB);
endmodule
观察第12~17行,数据比较器的描述方法与C语言非常一致。
1
2
3
4
5
6
assignoEQ=(iA==iB),
oNEQ=(iA!
=iB),
oGT=(iA>iB),
oGT_EQ=(iA>=iB),
oLT=(iAoLT_EQ=(iA<=iB);
图2.1综合后的数据比较器的RTL视图
代码2.2数据比较器的testbench(不可综合,仅用于仿真)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
`timescale1ns/1ns
modulearithmetic_tb;
reg[3:
0]i_a;
reg[3:
0]i_b;
wireo_eq,
o_neq,
o_gt,
o_gt_eq,
o_lt,
o_lt_eq;
initialbegin
i_a=5;
i_b=5;
#20i_a=6;
#20i_a=4;
#20$stop;
end
arithmeticarithmetic_inst(
.iA(i_a),
.iB(i_b),
.oEQ(o_eq),
.oNEQ(o_neq),
.oGT(o_gt),
.oGT_EQ(o_gt_eq),
.oLT(o_lt),
.oLT_EQ(o_lt_eq)
);
endmodule
图2.2数据比较器的功能仿真波形
3移位运算
VeirlogHDL2001支持逻辑移位及算术移位。
3.1逻辑移位
代码3.1逻辑移位(可综合)
1
2
3
4
5
6
7
8
9
10
11
modulearithmetic(
input[7:
0]iA,
input[2:
0]iBit,//移位的位数0~7
output[7:
0]oSLL,//逻辑左移
output[7:
0]oSRL//逻辑右移
);
assignoSLL=(iA<oSRL=(iA>>iBit);
endmodule
第8~9行,逻辑移位的符号和C语言也是一致的:
>>(逻辑右移,shiftrightlogical);<<(逻辑左移,shiftleftlogical)。
assign关键字后,若有多条语句,则可以使用逗号隔开;也可以分开使用两个assign语句来描述。
1
2
assignoSLL=(iA<oSRL=(iA>>iBit);
图3.1逻辑移位的RTL视图
代码3.2逻辑移位的testbench
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
`timescale1ns/1ns
modulearithmetic_tb;
reg[7:
0]i_a=8'b1011_0111;
reg[2:
0]i_bit=0;
wire[7:
0]o_sll,
o_srl;
initialwhile(i_bit<7)#20i_bit=i_bit+1'b1;
initial#160$stop;
arithmeticarithmetic_inst(
.iA(i_a),
.iBit(i_bit),
.oSLL(o_sll),
.oSRL(o_srl)
);
endmodule
1
第3~4行,在声明reg类型的信号时,同时赋初值。
1
2
reg[7:
0]i_a=8'b1011_0111;
reg[2:
0]i_bit=0;
1
第6~7行,同一类型及等位宽的信号,可以使用逗号隔开声明,也可以分开声明。
1
2
wire[7:
0]o_sll,
o_srl;
1
第9行,采用while语句来生成激励,其用法与C语言一致。
1
initialwhile(i_bit<7)#20i_bit=i_bit+1'b1;
右键所需观察的信号,选择Radix>Unsigned,以无符号十进制形式查看i_bit。
如图3.2所示。
图3.2以无符号十进制形式查看i_bit
图3.3逻辑移位的功能仿真波形
3.2算术移位
算术移位与逻辑移位的区别见参考3。
代码3.3有符号数的逻辑移位与算术移位(可综合)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
modulearithmetic(
inputsigned[7:
0]iA,
input[2:
0]iBit,//移位的位数0~7
outputsigned[7:
0]oSLL,//逻辑左移
outputsigned[7:
0]oSRL,//逻辑右移
outputsigned[7:
0]oASL,//算术左移
outputsigned[7:
0]oASR//算术右移
);
assignoSLL=(iA<oSRL=(iA>>iBit),
oASL=(iA<<oASR=(iA>>>iBit);
endmodule
第2~7行,移位的位数被声明成无符号数,而移位的数据及其结果被声明成有符号数。
1
2
3
4
5
6
inputsigned[7:
0]iA,
input[2:
0]iBit,//移位的位数0~7
outputsigned[7:
0]oSLL,//逻辑左移
outputsigned[7:
0]oSRL,//逻辑右移
outputsigned[7:
0]oASL,//算术左移
outputsigned[7:
0]oASR//算术右移
第10~13行,与逻辑移位不同,算术移位的运算符是:
<<<(算术左移,arithmeticshiftleft);>>>(算术右移,arithmeticshiftright)。
1
2
3
4
assignoSLL=(iA<oSRL=(iA>>iBit),
oASL=(iA<<oASR=(iA>>>iBit);
图3.4有符号数的逻辑移位与算术移位的RTL视图
代码3.4有符号数的逻辑移位与算术移位的testbench(不可综合,仅用于仿真)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
`timescale1ns/1ns
modulearithmetic_tb;
regsigned[7:
0]i_a=8'sb1011_0111;
regsigned[2:
0]i_bit=0;
wiresigned[7:
0]o_sll,
o_srl,
o_asl,
o_asr;
initialwhile(i_bit<7)#20i_bit=i_bit+1'b1;
initial#160$stop;
arithmeticarithmetic_inst(
.iA(i_a),
.iBit(i_bit),
.oSLL(o_sll),
.oSRL(o_srl),
.oASL(o_asl),
.oASR(o_asr)
);
endmodule
全选所有信号,右键选择Radix>Binary,以二进制形式查看。
如图3.5所示。
图3.5以二进制形式查看所有信号
图3.6有符号数的逻辑移位与算术移位的功能仿真波形
小结:
算术左移和逻辑左移的效果一致;算术右移移出的数据填充的是符号位,而逻辑右移移出的数据填充的是0。