Preface
最近有个小课设,需要设计一个流水线加法器,老师说企业面试也会考,网上的4位加法器大多是2级流水线,我整了一个4位的(其实如果只是4位加法器的话,用4级流水不一定更好,主要是练习一下流水线写法),写的可能不是很好,请大家批判性参考。一般位数很多的话可以使用超前进位加法器和串行加法器结合或者就通过流水线来进行设计,提高频率。
可以参考的几个资料:
- 这个写的还是可以的,一个两级流水线:
verilog流水线加法器 - 流水线定义请看这篇,讲的还蛮详细:
Verilog十大基本功1(流水线设计Pipeline Design)
4位加法器4级流水线代码
- 头文件,common.v
/* Used in unblocking */
/* Just to be convenient to watch the waves in RTL level */
`define DEL 1
/* Define your own macro here */
- 功能文件,pipelineadder.v
//*************************************************************
//
//*@File name: pipelineadder.v
//
//*@File type: verilog
//
//*@Version : 0.0.1
//
//*@Author : Zehua Dong, HITWH
//
//*@E-mail : hitdongzh@163.com
//
//*@Date : 2020-12-12 09:48:26
//
//*@Function : 4 bit adder in 3 steps pipeline
//
//*************************************************************
//
// Head files
`include "common.v"
//
// Module definition
//
module pipelineadder(
clk ,
rst_n ,
a ,
b ,
cin ,
cout ,
sout
);
//===========================================================
//* Input and output ports
//===========================================================
//
input clk ;
input rst_n ;
input [3:0] a ;
input [3:0] b ;
input cin ;
output cout ;
output [3:0] sout ;
//===========================================================
//* Internal signals
//===========================================================
//
// The middle registers used to store the addend
reg [3:0] a_tmp;
reg [2:0] a_tmp1;
reg [1:0] a_tmp2;
reg [0:0] a_tmp3;
// The middle registers used to store the augend
reg [3:0] b_tmp;
reg [2:0] b_tmp1;
reg [1:0] b_tmp2;
reg [0:0] b_tmp3;
// The middle registers used to store the carry in bit
reg cin_tmp;
// The middle registers used to store the carry out bit
reg cout_tmp1;
reg cout_tmp2;
reg cout_tmp3;
reg cout_tmp4;
// The middle registers used to store the sum
reg sout_tmp1;
reg sout_tmp2;
reg sout_tmp3;
reg sout_tmp4;
reg [2:0] s_reg1;
reg [1:0] s_reg2;
reg s_reg3;
// 1st clk
// Load the addend and augend
always @( posedge clk or negedge rst_n ) begin
if( ~rst_n ) begin
a_tmp <= #`DEL 4'd0;
b_tmp <= #`DEL 4'd0;
cin_tmp <= #`DEL 1'b0;
end
else begin
a_tmp <= #`DEL a;
b_tmp <= #`DEL b;
cin_tmp <= #`DEL cin;
end
end
// 2nd clk
// First step pipeline
always @( posedge clk or negedge rst_n ) begin
if( ~rst_n ) begin
cout_tmp1 <= #`DEL 1'b0;
sout_tmp1 <= #`DEL 1'b0;
a_tmp1 <= #`DEL 3'd0;
b_tmp1 <= #`DEL 3'd0;
end
else begin
// sum of 0 bit
{cout_tmp1, sout_tmp1} <= #`DEL a_tmp[0] + b_tmp[0] + cin_tmp;
// Store the remaining bits of addend and augend
a_tmp1 <= #`DEL a_tmp[3:1];
b_tmp1 <= #`DEL b_tmp[3:1];
end
end
// 3rd clk
// Second step pipeline
always @( posedge clk or negedge rst_n ) begin
if( ~rst_n ) begin
cout_tmp2 <= #`DEL 1'b0;
sout_tmp2 <= #`DEL 1'b0;
a_tmp2 <= #`DEL 2'd0;
b_tmp2 <= #`DEL 2'd0;
s_reg1 <= #`DEL 3'b0;
end
else begin
// sum of 1 bit
{cout_tmp2, sout_tmp2} <= #`DEL a_tmp1[0] + b_tmp1[0] + cout_tmp1;
// Store the remaining bits of addend and augend
a_tmp2 <= #`DEL a_tmp1[2:1];
b_tmp2 <= #`DEL b_tmp1[2:1];
// Store the sum result
s_reg1 <= #`DEL {s_reg1[1:0], sout_tmp1};
end
end
// 4th clk
// Third step pipeline
always @( posedge clk or negedge rst_n ) begin
if( ~rst_n ) begin
cout_tmp3 <= #`DEL 1'b0;
sout_tmp3 <= #`DEL 1'b0;
a_tmp3 <= #`DEL 1'd0;
b_tmp3 <= #`DEL 1'd0;
s_reg2 <= #`DEL 1'b0;
end
else begin
// sum of 2 bit
{cout_tmp3, sout_tmp3} <= #`DEL a_tmp2[0] + b_tmp2[0] + cout_tmp2;
// Store the remaining bits of addend and augend
a_tmp3 <= #`DEL a_tmp2[1];
b_tmp3 <= #`DEL b_tmp2[1];
// Store the sum result
s_reg2 <= #`DEL {s_reg2[0], sout_tmp2};
end
end
// 5th clk
// Forth step pipeline
always @( posedge clk or negedge rst_n ) begin
if( ~rst_n ) begin
cout_tmp4 <= #`DEL 1'b0;
sout_tmp4 <= #`DEL 1'b0;
end
else begin
// sum of 3 bit
{cout_tmp4, sout_tmp4} <= #`DEL a_tmp3 + b_tmp3 + cout_tmp3;
// Store the sum result
s_reg3 <= #`DEL sout_tmp3;
end
end
// Output cout and sout
assign {cout, sout} = {cout_tmp4, {sout_tmp4, s_reg3, s_reg2[1], s_reg1[2]}};
endmodule
- 激励文件,pipelineadder_tb.v
//*************************************************************
//
//*@File name: pipelineadder_tb.v
//
//*@File type: testbench
//
//*@Version : 0.0.1
//
//*@Author : Zehua Dong, HITWH
//
//*@E-mail : hitdongzh@163.com
//
//*@Date : 2020-12-12 10:56:37
//
//*@Function :
//
//*************************************************************
// Module definition
//
module pipelineadder_tb();
reg tb_clk ;
reg tb_rst_n ;
reg [3:0] tb_a ;
reg [3:0] tb_b ;
reg tb_cin ;
wire tb_cout ;
wire [3:0] tb_sout ;
task delay;
input [31:0] num;
begin
repeat(num) @(posedge tb_clk);
#1;
end
endtask
initial begin
tb_clk = 0;
end
always #10 tb_clk = ~tb_clk;
initial begin
tb_rst_n = 1;
delay(1);
tb_rst_n = 0;
delay(1);
tb_rst_n = 1;
end
initial begin
$dumpfile(" pipelineadder_tb.vcd ");
$dumpvars();
end
initial begin
tb_a = 4'b0000;
tb_b = 4'b0000;
tb_cin = 1'b0;
delay(3);
// 1_0000
tb_a = 4'b1111;
tb_b = 4'b0001;
tb_cin = 1'b0;
delay(1);
// 1_0111
tb_a = 4'b1101;
tb_b = 4'b1001;
tb_cin = 1'b1;
delay(1);
// 0_1110
tb_a = 4'b1100;
tb_b = 4'b0001;
tb_cin = 1'b1;
delay(1);
// 1_0110
tb_a = 4'b1111;
tb_b = 4'b0111;
tb_cin = 1'b0;
delay(10);
$finish;
end
pipelineadder pipelineadder_u1(
.clk ( tb_clk ) ,
.rst_n ( tb_rst_n ) ,
.a ( tb_a ) ,
.b ( tb_b ) ,
.cin ( tb_cin ) ,
.cout ( tb_cout ) ,
.sout ( tb_sout )
);
endmodule
- 仿真结果
- 综合后的RTL视图(感觉奇奇怪怪的,大家再优化一下代码叭)
补充
后来感觉4位加法器用4级流水不太好,又弄了一下2级流水的以及32位8级流水线加法器。
4位加法器2级流水线
- 功能文件
//*************************************************************
//
//*@File name: pipeline_adder_4bit_2steps.v
//
//*@File type: verilog
//
//*@Version : 0.0.1
//
//*@Author : Zehua Dong, HITWH
//
//*@E-mail : hitdongzh@163.com
//
//*@Date : 2020-12-15 12:42:00
//
//*@Function :
//
//*************************************************************
//
// Head files
`include "common.v"
//
// Module definition
//
module pipeline_adder_4bit_2steps(
s,
co,
a,
b,
ci,
clk,
rst_n,
debug_low_voltage,
debug_high_voltage
);
input clk;
input rst_n;
input [3:0] a;
input [3:0] b;
input ci;
output [3:0] s;
output co;
output [3:0] debug_low_voltage;
output [3:0] debug_high_voltage;
reg [3:0] s;
reg co;
assign debug_low_voltage = 4'b0000;
assign debug_high_voltage = 4'b1111;
reg [3:0] a_tmp;
reg [3:0] b_tmp;
reg ci_tmp;
reg [1:0] s_tmp;
reg co_low;
reg [1:0] s_low;
reg co_hign;
reg [1:0] s_hign;
always@(posedge clk or negedge rst_n) begin
if(!rst_n) begin
co_low <= #`DEL 1'b0;
s_low <= #`DEL 2'b0;
a_tmp <= #`DEL 2'b0;
b_tmp <= #`DEL 2'b0;
end
else begin //低两位相加,缓存高两位
{co_low,s_low} <= #`DEL a[1:0] + b[1:0] + ci;
a_tmp <= #`DEL a[3:2];
b_tmp <= #`DEL b[3:2];
end
end
always@(posedge clk or negedge rst_n) begin
if(!rst_n) begin
co_hign <= #`DEL 2'b0;
s_hign <= #`DEL 2'b0;
end
else begin //高两位相加及与之间的低两位一并输出
{co_hign,s_hign} <= #`DEL a_tmp + b_tmp + co_low;
s_tmp <= #`DEL s_low; //寄存上一级的结果
end
end
always@(posedge clk or negedge rst_n) begin
if(!rst_n) begin
co <= #`DEL 1'b0;
s <= #`DEL 4'b0;
end
else begin
{co,s} <= #`DEL {co_hign,s_hign,s_tmp}; //合并上两级计算结果,输出结果
end
end
endmodule
- 仿真文件
//*************************************************************
//
//*@File name: pipeline_adder_4bit_2steps_tb.v
//
//*@File type: testbench
//
//*@Version : 0.0.1
//
//*@Author : Zehua Dong, HITWH
//
//*@E-mail : hitdongzh@163.com
//
//*@Date : 2020-12-15 13:14:47
//
//*@Function :
//
//*************************************************************
//
// Module definition
//
module pipeline_adder_4bit_2steps_tb;
wire [3:0] s;
wire co;
reg [3:0] a;
reg [3:0] b;
reg ci;
reg clk;
reg rst_n;
wire [3:0] low_voltage;
wire [3:0] high_voltage;
initial
begin
clk = 0;
rst_n = 0;
@(posedge clk) rst_n = 1;
a = 4'b0000; b = 4'b0000; ci = 0; // 0_0000
@(posedge clk) a = 4'b1111; b = 4'b1111; ci = 0; // 1_1110
@(posedge clk) a = 4'b1100; b = 4'b1001; ci = 0; // 1_0101
@(posedge clk) a = 4'b0111; b = 4'b0110; ci = 0; // 0_1101
@(posedge clk) a = 4'b0101; b = 4'b0101; ci = 1; // 0_1011
@(posedge clk) a = 4'b1110; b = 4'b1001; ci = 1; // 1_1000
@(posedge clk) a = 4'b0010; b = 4'b0110; ci = 1; // 0_1001
@(posedge clk) a = 4'b0110; b = 4'b1101; ci = 1; // 1_0100
repeat(10) @(posedge clk);
$finish;
end
always #10 clk = ~clk;
initial begin
$dumpfile(" 4bit_2steps_tb.vcd ");
$dumpvars();
end
pipeline_adder_4bit_2steps pipeline_adder_4bit_2steps_u1(
.s(s),
.co(co),
.a(a),
.b(b),
.ci(ci),
.clk(clk),
.rst_n(rst_n),
.debug_low_voltage(low_voltage),
.debug_high_voltage(high_voltage)
);
endmodule
- 仿真结果
- RTL视图
32位加法器8级流水线
- 功能文件
//*************************************************************
//
//*@File name: pipeline_adder_32bit_8steps.v
//
//*@File type: verilog
//
//*@Version : 0.0.1
//
//*@Author : Zehua Dong, HITWH
//
//*@E-mail : hitdongzh@163.com
//
//*@Date : 2020-12-15 14:57:47
//
//*@Function :
//
//*************************************************************
//
// Head files
`include "common.v"
//
// Module definition
//
module pipeline_adder_32bit_8steps(
clk ,
rst_n ,
a ,
b ,
ci ,
co ,
so
);
//===========================================================
//* Input and output ports
//===========================================================
//
input clk ;
input rst_n ;
input [31:0] a ;
input [31:0] b ;
input ci ;
output co ;
output [31:0] so ;
reg co ;
reg [31:0] so ;
//===========================================================
//* Internal signals
//===========================================================
//
reg [27:0] a_tmp1;
reg [23:0] a_tmp2;
reg [19:0] a_tmp3;
reg [15:0] a_tmp4;
reg [11:0] a_tmp5;
reg [07:0] a_tmp6;
reg [03:0] a_tmp7;
reg [27:0] b_tmp1;
reg [23:0] b_tmp2;
reg [19:0] b_tmp3;
reg [15:0] b_tmp4;
reg [11:0] b_tmp5;
reg [07:0] b_tmp6;
reg [03:0] b_tmp7;
reg co_tmp1;
reg co_tmp2;
reg co_tmp3;
reg co_tmp4;
reg co_tmp5;
reg co_tmp6;
reg co_tmp7;
reg co_tmp8;
reg [3:0] so_tmp1;
reg [3:0] so_tmp2;
reg [3:0] so_tmp3;
reg [3:0] so_tmp4;
reg [3:0] so_tmp5;
reg [3:0] so_tmp6;
reg [3:0] so_tmp7;
reg [3:0] so_tmp8;
reg [27:0] so_reg1;
reg [23:0] so_reg2;
reg [19:0] so_reg3;
reg [15:0] so_reg4;
reg [11:0] so_reg5;
reg [07:0] so_reg6;
reg [03:0] so_reg7;
// 1step
always @( posedge clk or negedge rst_n ) begin
if( ~rst_n ) begin
co_tmp1 <= #`DEL 1'b0;
so_tmp1 <= #`DEL 4'd0;
a_tmp1 <= #`DEL 28'd0;
b_tmp1 <= #`DEL 28'd0;
end
else begin
{co_tmp1, so_tmp1} <= #`DEL a[3:0] + b[3:0] + ci;
a_tmp1 <= #`DEL a[31:4];
b_tmp1 <= #`DEL b[31:4];
end
end
//2step
always @( posedge clk or negedge rst_n ) begin
if( ~rst_n ) begin
co_tmp2 <= #`DEL 1'b0;
so_tmp2 <= #`DEL 4'd0;
a_tmp2 <= #`DEL 24'd0;
b_tmp2 <= #`DEL 24'd0;
so_reg1 <= #`DEL 28'd0;
end
else begin
{co_tmp2, so_tmp2} <= #`DEL a_tmp1[3:0] + b_tmp1[3:0] + co_tmp1;
a_tmp2 <= #`DEL a_tmp1[27:4];
b_tmp2 <= #`DEL b_tmp1[27:4];
so_reg1 <= #`DEL {so_reg1[23:0], so_tmp1};
end
end
//3step
always @( posedge clk or negedge rst_n ) begin
if( ~rst_n ) begin
co_tmp3 <= #`DEL 1'b0;
so_tmp3 <= #`DEL 4'd0;
a_tmp3 <= #`DEL 20'd0;
b_tmp3 <= #`DEL 20'd0;
so_reg2 <= #`DEL 24'd0;
end
else begin
{co_tmp3, so_tmp3} <= #`DEL a_tmp2[3:0] + b_tmp2[3:0] + co_tmp2;
a_tmp3 <= #`DEL a_tmp2[23:4];
b_tmp3 <= #`DEL b_tmp2[23:4];
so_reg2 <= #`DEL {so_reg2[19:0], so_tmp2};
end
end
//4step
always @( posedge clk or negedge rst_n ) begin
if( ~rst_n ) begin
co_tmp4 <= #`DEL 1'b0;
so_tmp4 <= #`DEL 4'd0;
a_tmp4 <= #`DEL 16'd0;
b_tmp4 <= #`DEL 16'd0;
so_reg3 <= #`DEL 20'd0;
end
else begin
{co_tmp4, so_tmp4} <= #`DEL a_tmp3[3:0] + b_tmp3[3:0] + co_tmp3;
a_tmp4 <= #`DEL a_tmp3[19:4];
b_tmp4 <= #`DEL b_tmp3[19:4];
so_reg3 <= #`DEL {so_reg3[15:0], so_tmp3};
end
end
//5step
always @( posedge clk or negedge rst_n ) begin
if( ~rst_n ) begin
co_tmp5 <= #`DEL 1'b0;
so_tmp5 <= #`DEL 4'd0;
a_tmp5 <= #`DEL 12'd0;
b_tmp5 <= #`DEL 12'd0;
so_reg4 <= #`DEL 16'd0;
end
else begin
{co_tmp5, so_tmp5} <= #`DEL a_tmp4[3:0] + b_tmp4[3:0] + co_tmp4;
a_tmp5 <= #`DEL a_tmp4[15:4];
b_tmp5 <= #`DEL b_tmp4[15:4];
so_reg4 <= #`DEL {so_reg4[11:0], so_tmp4};
end
end
//6step
always @( posedge clk or negedge rst_n ) begin
if( ~rst_n ) begin
co_tmp6 <= #`DEL 1'b0;
so_tmp6 <= #`DEL 4'd0;
a_tmp6 <= #`DEL 8'd0;
b_tmp6 <= #`DEL 8'd0;
so_reg5 <= #`DEL 12'd0;
end
else begin
{co_tmp6, so_tmp6} <= #`DEL a_tmp5[3:0] + b_tmp5[3:0] + co_tmp5;
a_tmp6 <= #`DEL a_tmp5[11:4];
b_tmp6 <= #`DEL b_tmp5[11:4];
so_reg5 <= #`DEL {so_reg5[7:0], so_tmp5};
end
end
//7step
always @( posedge clk or negedge rst_n ) begin
if( ~rst_n ) begin
co_tmp7 <= #`DEL 1'b0;
so_tmp7 <= #`DEL 4'd0;
a_tmp7 <= #`DEL 4'd0;
b_tmp7 <= #`DEL 4'd0;
so_reg6 <= #`DEL 8'd0;
end
else begin
{co_tmp7, so_tmp7} <= #`DEL a_tmp6[3:0] + b_tmp6[3:0] + co_tmp6;
a_tmp7 <= #`DEL a_tmp6[7:4];
b_tmp7 <= #`DEL b_tmp6[7:4];
so_reg6 <= #`DEL {so_reg6[3:0], so_tmp6};
end
end
//8step
always @( posedge clk or negedge rst_n ) begin
if( ~rst_n ) begin
co_tmp8 <= #`DEL 1'b0;
so_tmp8 <= #`DEL 4'd0;
so_reg7 <= #`DEL 4'd0;
end
else begin
{co_tmp8, so_tmp8} <= #`DEL a_tmp7[3:0] + b_tmp7[3:0] + co_tmp7;
so_reg7 <= #`DEL so_tmp7;
end
end
always @( posedge clk or negedge rst_n ) begin
if( ~rst_n ) begin
co <= #`DEL 1'b0;
so <= #`DEL 32'd0;
end
else begin
{co, so} <= #`DEL {co_tmp8, {so_tmp8, so_reg7, so_reg6[7:4], so_reg5[11:8], so_reg4[15:12], so_reg3[19:16], so_reg2[23:20], so_reg1[27:24]}};
end
end
endmodule
- 仿真文件
//*************************************************************
//
//*@File name: pipeline_adder_32bit_8steps_tb.v
//
//*@File type: testbench
//
//*@Version : 0.0.1
//
//*@Author : Zehua Dong, HITWH
//
//*@E-mail : hitdongzh@163.com
//
//*@Date :2020-12-15 14:41:59
//
//*@Function :
//
//*************************************************************
// Module definition
//
module pipeline_adder_32bit_8steps_tb();
reg tb_clk ;
reg tb_rst_n ;
reg [31:0] tb_a ;
reg [31:0] tb_b ;
reg tb_ci ;
wire tb_co ;
wire [31:0] tb_so ;
task delay;
input [31:0] num;
begin
repeat(num) @(posedge tb_clk);
#1;
end
endtask
initial begin
tb_clk = 0;
end
always #10 tb_clk = ~tb_clk;
initial begin
tb_rst_n = 1;
delay(1);
tb_rst_n = 0;
delay(1);
tb_rst_n = 1;
end
initial begin
$dumpfile(" 32bit_8steps_tb.vcd ");
$dumpvars();
end
initial begin
tb_a = 32'd0;
tb_b = 32'd0;
tb_ci = 1'b0;
delay(3);
// 1_0000_0000
tb_a = 32'hffff_ffff;
tb_b = 32'h1;
tb_ci = 1'b0;
delay(1);
// 1 2300 1247
tb_a = 32'hffff_0012;
tb_b = 32'h2301_1234;
tb_ci = 1'b1;
delay(1);
// 1 A9EE 1295
tb_a = 32'haf10_0090;
tb_b = 32'hfade_1204;
tb_ci = 1'b1;
delay(1);
// 0 19B0 9D8A
tb_a = 32'h0987_6543;
tb_b = 32'h1029_3847;
tb_ci = 1'b0;
delay(1);
// 1 FFFF FFFE
tb_a = 32'hffff_ffff;
tb_b = 32'hffff_ffff;
tb_ci = 1'b0;
delay(1);
// 0 BB61 572D
tb_a = 32'h0138_4709;
tb_b = 32'hba29_1023;
tb_ci = 1'b1;
delay(1);
// 0 2AC9 D17B
tb_a = 32'h2937_4dfb;
tb_b = 32'h0192_8380;
tb_ci = 1'b0;
delay(1);
// 0 DCDC BBBC
tb_a = 32'h0101_1010;
tb_b = 32'hdbdb_abab;
tb_ci = 1'b1;
delay(10);
$finish;
end
pipeline_adder_32bit_8steps pipeline_adder_32bit_8steps_u1(
.clk ( tb_clk ) ,
.rst_n ( tb_rst_n ) ,
.a ( tb_a ) ,
.b ( tb_b ) ,
.ci ( tb_ci ) ,
.co ( tb_co ) ,
.so ( tb_so )
);
endmodule
- 仿真结果