在看《计算机原理和设计:verilog HDL版》时,看到书中的先行进位加法,可是仿真下来却不对,书中的代码如下:
看过书很久了,发现这个东西一下子没有弄明白,从源头开始,重新整理,
s = a ^ b ^ c;
co = a & b | (a|b) & c;
主要看进位相关的 co = a & b | (a|b) & c;
令
P = a | b;
G = a & b;
对于每位的进位表示成
C(i) = G(i) | P(i) & C(i-1);
根据上式求出 C(i+1) 位
C(i+1) = G(i+1) | P(i+1) & C(i)
= G(i+1) | P(i+1) & G(i) | P(i+1) & P(i) & C(i-1);
令:
mg[i+1,i] = G(i+1) | P(i+1) & G(i);
mp[i+1,i] = P(i+1) & P(i);
则 C(i+1) 可以表求为:
C(i+1) = mg[i+1,i] | mp[i+1,i] & C(i-1);
再进一步求得 C(i+2) :
C(i+2) = G(i+2) | P(i+2) & C(i+1);
= G(i+2) | P(i+2) & (G(i+1) | P(i+1) & G(i) | P(i+1) & P(i) & C(i-1));
= G(i+2) | P(i+2) & G(i+1) | P(i+2) & P(i+1) & G(i) | P(i+2) & P(i+1) & P(i) & C(i-1);
那么:
mg[i+2,i] = G(i+2) | P(i+2) & G(i+1) | P(i+2) & P(i+1) & G(i)
= G(i+2) | P(i+2) & mg[i+1,i]
mp[i+2,i] = P(i+2) & P(i+1) & P(i)
= P(i+2) & mp[i+1,i]
上面就是一个递归式,代入小数 0 和 1 就更好的看明白其中的关系
mg[1,0] = G(1) | P(1) & G(0);
mp[1,0] = P(1) & P(0);
mg[2,1] = G(2) | P(2) & G(1);
mp[2,1] = P(2) & P(1);
mg[2,0] = G(2) | P(2) & mg[1,0]
mp[2,0] = P(2) & mp[1,0]
现在再来看代码就容易很多
module add(
input a,
input b,
input c_in,
output g,
output p,
output s
);
assign g = a & b;
assign p = a | b;
assign s = a ^ b ^ c_in;
endmodule
module g_p(
input [1:0] g,
input [1:0] p,
input c_in,
output g_out,
output p_out,
output c_out
);
//c_out = c1 = g0 + p0c0;
// c2 = g1 + p1c1
// c2 = g1 + p1g0 + p1p0c0;
// g_out= G(1,0) = g1+p1g0
// c_out= P(1,0) = p1p0
assign c_out = g[0] | p[0] & c[0];
assign g_out = g[1] | p[1] & g[0];
assign p_out = p[1] & p[0];
endmodule
module cal_2(
input [1:0] a,
input [1:0] b,
input c_in,
output g_out,
output p_out,
output [1:0] s,
);
wire c_out;
wire [1:0] p;
wire [1:0] g;
add a(a.(a[0]), .b(b[0]), .c_in(c_in), .g(g[0]), .p(p[0]), .s(s[0]));
add b(a.(a[1]), .b(b[1]), .c_in(c_out), .g(g[1]), .p(p[1]), .s(s[1]));
g_p c(.g(g),.p(p),c_in,.g_out(g_out),.p_out(p_out),.c_out(c_out));
endmodule
module cal_4(
input [3:0] a,
input [3:0] b,
input c_in,
output g_out,
output p_out,
output [3:0] s,
);
wire c_out;
wire [1:0] p;
wire [1:0] g;
cal_2 a(.a(a[1:0]), .b(b[1:0]), .c_in(c_in), .g(g[0]), .p(p[0]), .s(s[1:0]));
cal_2 b(.a(a[3:2]), .b(b[3:2]), .c_in(c_out), .g(g[1]), .p(p[1]), .s(s[3:2]));
g_p c(.g(g),.p(p),c_in,.g_out(g_out),.p_out(p_out),.c_out(c_out));
endmodule
仔细才发现,这代码其实只把进1,3,5,9,17,33位进位算对了,也就是最高位的进位是对了。
这个没有办法,只好写了一个不科学的方法,代码和上面一样, 只是路径太长有 32步,没有起到真正的并发效果,也没有缩短路径,还是32步。
module add32_ab(a, b, ci, co);
input a, b, ci;
wire g, p;
output co;
assign g = a & b;
assign p = a | b;
assign co = g | p & ci;
endmodule
module cal2_ab(a, b, ci, co);
input [1:0] a, b;
input ci;
output [1:0] co;
add32_ab ander1(a[0], b[0], ci, co[0]);
add32_ab ander2(a[1], b[1], co[0], co[1]);
endmodule
module cal4_ab(a, b, ci, co);
input [3:0] a, b;
input ci;
output [3:0] co;
cal2_ab ander2(a[1:0], b[1:0], ci, co[1:0]);
cal2_ab ander1(a[3:2], b[3:2], co[1], co[3:2]);
endmodule
module cal8_ab(a, b, ci, co);
input [7:0] a, b;
input ci;
output [7:0] co;
cal4_ab ander2(a[3:0], b[3:0], ci, co[3:0]);
cal4_ab ander1(a[7:4], b[7:4], co[3], co[7:4]);
endmodule
module cal16_ab(a, b, ci, co);
input [15:0] a, b;
input ci;
output [15:0] co;
cal8_ab ander2(a[7:0], b[7:0], ci, co[7:0]);
cal8_ab ander1(a[15:8], b[15:8], co[7], co[15:8]);
endmodule
module cal32_ab(a, b, ci, co);
input [31:0] a, b;
input ci;
output [31:0] co;
cal16_ab ander2(a[15:0], b[15:0], ci, co[15:0]);
cal16_ab ander1(a[31:16], b[31:16], co[15], co[31:16]);
endmodule
module add_ab(a, b, ci, s, c_out);
input [31:0] a, b;
input ci;
output [31:0] s;
output c_out;
wire [31:0] co;
cal32_ab caler(a, b, ci, co);
assign c_out = co[31];
assign s = a ^ b ^ {co[30:0], ci};
endmodule
暂时没有想到好的解决办法