最近在弄一个流水结构的加法器,查阅了一些书籍,也在网上搜了一些资料,今天花点时间整理了一下。
(首先说明一点,也是自己对流水线的一点理解:当我们处理数据流的时候可以用流水线的方式处理,但当我们处理的不是数据流,我们要根据情况来考虑流水线结构的“填满”和“排空”。个人觉得,流水线的结构只有在处理数据流时才能显现出它的速度优势)(如需转载请注明出处)
一、4位超前进位加法器
先把代码帖出来:
module fast_adder4b(ina,inb,carry_in,sum_out,clk,rst);
parameter ADDRE_WIDTH =4;
parameter SUM_WIDTH =5;
input [ADDRE_WIDTH-1:0] ina;
input [ADDRE_WIDTH-1:0] inb;
input carry_in;
input rst;
input clk;
output [SUM_WIDTH-1:0] sum_out;
reg [SUM_WIDTH-1:0] sum_out;
wire [ADDRE_WIDTH-1:0] sg;
wire [ADDRE_WIDTH-1:0] sp;
wire [ADDRE_WIDTH-1:0] sc;
assign sg[0] = ina[0]&inb[0];
assign sg[1] = ina[1]&inb[1];
assign sg[2] = ina[2]&inb[2];
assign sg[3] = ina[3]&inb[3];
assign sp[0] = ina[0]^inb[0];
assign sp[1] = ina[1]^inb[1];
assign sp[2] = ina[2]^inb[2];
assign sp[3] = ina[3]^inb[3];
assign sc[0] = sg[0]|(sp[0] & carry_in);
assign sc[1] = sg[1]|(sp[1] & (sg[0]|(sp[0] & carry_in)));
assign sc[2] = sg[2]|(sp[2] & (sg[1]|(sp[1] & (sg[0]|(sp[0] & carry_in)))));
assign sc[3] = sg[3]|(sp[3] & (sg[2]|(sp[2] & (sg[1]|(sp[1] & (sg[0]|(sp[0] & carry_in)))))));
always@ (posedge clk or negedge rst)
begin
if(!rst)
sum_out <= 5'b00000;
else
begin
sum_out[0] <=sp[0] ^ carry_in;
sum_out[1] <=sp[1] ^ sc[0];
sum_out[2] <=sp[2] ^ sc[1];
sum_out[3] <=sp[3] ^ sc[2];
sum_out[4] <=sc[3];
end
end
endmodule
首先要明确几个概念:
sp表示进位否决信号(pass),如果p为0就否决调前一级的进位输入。否决的意思就是即使前一级有进位,本级也不会向后一级产生进位输出。
sg表示进位产生信号(generate),如果g为1就表示一定会向后一级产生进位输出。
sp[n] =ina[n] ^ inb[n]
这句话的意思是说,当ina=1,inb=0或ina=0,inb=1时前一级的进位输入信号不能否决。这样就有个问题了,即当ina=1,inb=1时前一级的进位输入信号也不能否决啊,怎么没有体现出来?其实当ina=1,inb=1时产生了进位产生信号sg,它的优先级高于sp信号,就忽略了sp信号,直接产生了向后一级产生进位输出,是没有逻辑错误的。
sg[n] = ina[n] & inb[n]
这句话的意思是说,如果ina=1,inb=1时就直接向后一级产生进位输出信号,而不用考虑其它的任何因素。
这一句可以这样理解,它是嵌套了几层的:
1. 如果sg[3]=1,即最高位要产生进位位,则表示本模块一定会向后一级模块产生进位输出。
2. 如果sg[3]=0,但是sp[3]=1(表示不能否决掉前一级的进位)。
3. 以下层次的关系依此类推。
总之,可以看出几个规律:
1. 用于模块内部的sp和sg信号,它们的产生都不依赖于模块内部各位之间的进位信号,而是由输入信号ina和inb直接得到的。
2. 当进位产生信号sg为1时,一定向后一级产生进位输出,此时不需要等待前一级进位信号的输入,速度得以加快。
3. 当进位产生信号sg为0时,向不向后一级产生进位输出就不好说了。我们能肯定的是如果此时进位否决信号sp为0,则一定不会向后一级产生进位输出,这种情况也不需要等待前一级进位信号的输入,速度还是得以加快。
4. 如果进位产生信号sg为0,并且进位否决信号sp为1,向不向后一级产生进位输出就完全取决于前一级进位信号的输入了,这时花的时间最长。
二、流水结构加法器
还是先把代码帖出来
module pipe_adder8b(ina,inb,sum_out,clk,rst);
parameter ADDRE_WIDTH =8;
parameter SUM_WIDTH =9;
parameter HALF_ADDRE_WIDTH =4;
input [ADDRE_WIDTH-1:0] ina;
input [ADDRE_WIDTH-1:0] inb;
input rst;
input clk;
output [SUM_WIDTH-1:0] sum_out;
reg [SUM_WIDTH-1:0] sum_out;
reg [HALF_ADDRE_WIDTH-1:0] ina_lsb;
reg [HALF_ADDRE_WIDTH-1:0] ina_msb;
reg [HALF_ADDRE_WIDTH-1:0] inb_lsb;
reg [HALF_ADDRE_WIDTH-1:0] inb_msb;
reg [HALF_ADDRE_WIDTH-1:0] ina_msb1;
reg [HALF_ADDRE_WIDTH-1:0] inb_msb1;
reg [HALF_ADDRE_WIDTH:0] sum11;
wire [HALF_ADDRE_WIDTH:0] sum1;
wire [HALF_ADDRE_WIDTH:0] sum2;
always@ (posedge clk or negedge rst)
begin
if(!rst)
begin
ina_lsb <= 4'b0000;
ina_msb <= 4'b0000;
inb_lsb <= 4'b0000;
inb_msb <= 4'b0000;
end
else
begin
ina_lsb <= ina[3:0];
ina_msb <= ina[7:4];
inb_lsb <= inb[3:0];
inb_msb <= inb[7:4];
end
end
fast_adder4b u1 (ina_lsb,inb_lsb,1'b0,sum1,clk,rst);
always@ (posedge clk or negedge rst)
begin
if(!rst)
begin
ina_msb1 <= 4'b0000;
inb_msb1 <= 4'b0000;
end
else
begin
ina_msb1 <= ina_msb;
inb_msb1 <= inb_msb;
end
end
fast_adder4b u2 (ina_msb1,inb_msb1,sum1[4],sum2,clk,rst);
always@ (posedge clk or negedge rst)
begin
if(!rst)
sum11 <= 4'b0000;
else
sum11 <= sum1;
end
always@ (posedge clk or negedge rst)
begin
if(!rst)
sum_out <= 9'b00000_0000;
else
sum_out <= {sum2,sum11[3:0]};
end
endmodule
上面程序内部调用的加法器采用的是我上面介绍的四位超前进位加法器实现的。
当采用超前进位加法时速度快,但随着加法器倍数的增加,消耗的门也越来越多,门延迟也戟来戟大。为解决这个问题,我们可以利用FPGA丰富的触发器资源。流水线结构每一步的中间结果都需要用寄存器暂存,尽管单个运算需要多个时钟才能出结果,但由于操作数是不断送到运算输入端的,所以总的效果是每个加法运算平均消耗一个时钟周期,大大提高了系统的处理速度和吞吐量。
额~~不会帖图片,所以仿真结果就先不帖出来了~~