verilog 刷题记录-牛客网-组合逻辑系列-加法器
一、四位数值比较器电路
某4位数值比较器的功能表如下。 请用Verilog语言采用门级描述方式,实现此4位数值比较器
根据图表写逻辑表达就可以
`timescale 1ns/1ns
module comparator_4(input [3:0] A ,
input [3:0] B ,
output wire Y2, //A>B
output wire Y1, //A = B
output wire Y0); //A<B
assign Y2 = (A[3]> B[3]) |((A[3] == B[3])&&(A[2]> B[2])) | ((A[3] == B[3])&&(A[2] == B[2])&&(A[1]> B[1])) |((A[3] == B[3])&&(A[2] == B[2])&&(A[1] == B[1])&&(A[0]> B[0]));
assign Y1 = ((A[3] == B[3])&&(A[2] == B[2])&&(A[1] == B[1])&&(A[0] == B[0]));
assign Y0 = (~Y1)& (~Y2);
endmodule
其实就是费时间,需要根据表格实现对应的逻辑
二、4bit超前进位加法器电路
在这里梳理一下加法器
对加法器进行梳理,首先加法器可以分为一位数加法器和多位加法器,而一位加法器又可以分为半加器和全加器,对于全加器和半加器,是在于有木有来自低位的进位
(1) 半加器
半加器是最简单的加法器,并不考虑进位输出,所以一般其verilog语言为
assign S = A ^ B;
assign C_out = A & B;
半加器的电路又是怎么样的呢
(2) 全加器
考虑来自低位的进位,就会有一种情况,大致的一个思路是,先根据真值表写出逻辑表达式,再根据逻辑表达式,进行电路的设计。
逻辑表达式
Si=Ai⊕Bi⊕Ci-1
电路图原理
可以利用其电路描述,即直接利用组合逻辑进行书写
assign s = A^B^C_i;
assign Cout = A & B | C_i & (A & B);
也可以利用结构性描述,利用两个半加器进行描述
wire w1,w2,w3;
adder_half u1(.a(a),.b(b),.sum(w1),.cout(w2));
adder_half u2(.a(cin),.b(w1),.sum(sum),.cout(w3));
assign cout = w2 | w3;
同时也可以使用行为级描述
assign {count, sum } = a+b+cin;
不过一开始学习还是要知道组合逻辑描述,基本上看到表达式就可以想到电路结构
(3)多位加法器
串行进位加法器
两个多位数相加时,每一位都是带进位相加的,因此必须使用全加器,所以只要依次将低位全加器的进位接到全加器的输入端,就可以构成多位加法器。
电路图
所以其写法也很简单,只需要将封装好的全加器模块进行调用即可。
将上面的全加器封装为fulladder
module serialadder(
output [3:0] s,
output co,
input [3:0] a,
input [3:0] b,
input ci
);
wire [3:0] co_tmp;
fulladder u_add0(
.s(s[0]), //sum
.co(co_tmp[0]), //carry to high bit
.a(a[0]),
.b(b[0]),
.ci(ci) //carry from low bit
);
fulladder u_add1(
.s(s[1]), //sum
.co(co_tmp[1]), //carry to high bit
.a(a[1]),
.b(b[1]),
.ci(co_tmp[0]) //carry from low bit
);
fulladder u_add2(
.s(s[2]), //sum
.co(co_tmp[2]), //carry to high bit
.a(a[2]),
.b(b[2]),
.ci(co_tmp[1]) //carry from low bit
);
fulladder u_add3(
.s(s[3]), //sum
.co(co_tmp[3]), //carry to high bit
.a(a[3]),
.b(b[3]),
.ci(co_tmp[2]) //carry from low bit
);
assign co = co_tmp[3];
endmodule
(4)超前进位加法器
其实现的逻辑为:串行进位加法器体现了电路设计的重复利用,同时降低了运算速度,如何才能够减少由于进位信号逐级传递的所消耗的时间呢。
先通过逻辑电路得到每一个全加器的进位输入信号,无需从最低位传递信号,大大缩减了计算时间。
其电路也会更加复杂。
`timescale 1ns / 1ps
// Description:
module Carry_Lookahead_Adder(
input [3:0] A ,
input [3:0] B ,
input Cin ,
output [3:0] S ,
output Cout
);
wire c1,c2,c3;
// 超前进位算法
assign c1 = (A[0]&B[0]) |((A[0]^B[0])&Cin) ;
assign c2 = (A[1]&B[1]) |((A[1]^B[1])&c1 ) ;
assign c3 = (A[2]&B[2]) |((A[2]^B[2])&c2 ) ;
assign Cout = (A[3]&B[3])|((A[3]^B[3])&c3 ) ;
assign S = {A[3]^B[3]^c3,A[2]^B[2]^c2,A[1]^B[1]^c1,A[0]^B[0]^Cin};
endmodule
最后S是实现上图中的逻辑式
或者利用这个
module carry_look_aheadadder(
output [3:0] s,
output co,
input [3:0] a,
input [3:0] b,
input ci
);
wire [3:0] co_tmp;
wire [3:0] cin;
assign cin[3:0] = {co_tmp[2:0],ci};
//计算中间进位
assign co_tmp[0] = a[0]&b[0] || (a[0] || b[0])&(cin[0]);
assign co_tmp[1] = a[1]&b[1] || (a[1] || b[1])&(cin[1]);
assign co_tmp[2] = a[2]&b[2] || (a[2] || b[2])&(cin[2]);
assign co_tmp[3] = a[3]&b[3] || (a[3] || b[3])&(cin[3]);
//计算和
assign s[0] = a[0] ^ b[0] ^ cin[0];
assign s[1] = a[1] ^ b[1] ^ cin[1];
assign s[2] = a[2] ^ b[2] ^ cin[2];
assign s[3] = a[3] ^ b[3] ^ cin[3];
assign co = co_tmp[3];
endmodule
然后搭建验证平台
module carry_look_aheadadder_tb;
wire [3:0] s;
wire co;
reg [3:0] a;
reg [3:0] b;
reg ci;
initial
begin
a = 4'b0000; b = 4'b0000; ci = 0;
#10 a = 4'b1111; b = 4'b1111; ci = 0;
#10 a = 4'b1100; b = 4'b1001; ci = 0;
#10 a = 4'b0111; b = 4'b0110; ci = 0;
#10 a = 4'b0101; b = 4'b0101; ci = 1;
#10 a = 4'b1110; b = 4'b1001; ci = 1;
#10 a = 4'b0010; b = 4'b0110; ci = 1;
#10 a = 4'b0110; b = 4'b1100; ci = 1;
#10 $finish;
end
initial begin
$fsdbDumpfile("test.fsdb");
$fsdbDumpvars();
end
carry_look_aheadadder u_carry_look_aheadadder(
.s(s),
.co(co),
.a(a),
.b(b),
.ci(ci)
);
endmodule
进行仿真模拟
对于这道题目是实现4bit超前进位加法器
就按照给的逻辑进行实现就可以
`timescale 1ns/1ns
module lca_4(
input [3:0] A_in ,
input [3:0] B_in ,
input C_1 ,
output wire CO ,
output wire [3:0] S
);
wire [3:0] G;
wire [3:0] P;
assign G[0] = A_in[0] & B_in[0];
assign G[1] = A_in[1] & B_in[1];
assign G[2] = A_in[2] & B_in[2];
assign G[3] = A_in[3] & B_in[3];
assign P[0] = A_in[0] ^ B_in[0];
assign P[1] = A_in[1] ^ B_in[1];
assign P[2] = A_in[2] ^ B_in[2];
assign P[3] = A_in[3] ^ B_in[3];
wire [3:0] C;
assign C[0] = G[0] | P[0]&C_1;
assign C[1] = G[1] | P[1]&C[0];
assign C[2] = G[2] | P[2]&C[1];
assign C[3] = G[3] | P[3]&C[2];
assign CO = C[3];
assign S[0] = P[0] ^ C_1;
assign S[1] = P[1] ^ C[0];
assign S[2] = P[2] ^ C[1];
assign S[3] = P[3] ^ C[2];
endmodule
参考资料
加法器