流水线设计
一、流水线设计概述
流水线设计就是将组合逻辑系统地分割,并在各个部分(分级)之间插入寄存器,并暂存中间数据的方法。目的是提高数据吞吐率(提高处理速度)。
流水线缩短了在一个时钟周期内给的那个信号必须通过的通路长度,从而可以提高时钟频率。例如:一个2级组合逻辑,假定每级延迟相同为Tpd,
1.无流水线的总延迟就是2Tpd,可以在一个时钟周期完成,但是时钟周期受限制在2Tpd。
2.流水线:每一级加入寄存器(延迟为Tco)后,单级的延迟为Tpd+Tco,每级消耗一个时钟周期,流水线需要2个时钟周期来获得第一个计算结果,称为首次延迟,它要2*(Tpd+Tco),但是执行重复操作时,只要一个时钟周期来获得最后的计算结果,称为吞吐延迟(Tpd+Tco);可见只要Tco小于Tpd,流水线就可以提高速度。
推论:增加流水线长度可以节省更多延迟,流水线越长,首次延迟越大,如果流水线反复启动,则会损失速度(故流水线主要用在大量重复操作的工作上)。
实现流水线的代价:1.消耗寄存器——就是消耗硅片面积(想想20级流水线的某著名CPU吧);
2.流水线长则消耗更多时钟周期。(如果流水线反复启动,则会损失速度,想想某CPU著名的高频率低效能吧);
3. 采用流水线增加了数据吞吐量,但也导致了数据的延时;
4. 简单来讲,就是用多个周期来完成原来一个周期的事情,这样新的周期就短了很多,速度当然提高了,当然,你要分多个周期,就要多个寄存器来暂存,当然就耗了资源,也就所谓资源换主频。当主频本身低的时候,Tco之类的与周期比可以忽略,所以这样做性能非常明显,但当主频本身就很高的话,在这样做,Tco之类的不能忽略,性能提高自然不明显,这样付出的资源带价就不一定值了。
5. 使用流水线有好有坏
好:1)、优化Timing,另系统可以在更高的频率上运行。
2)、提高单位时间的处理能力,从而提升效能。
坏:1)、功耗增加。
2)、面积增加。
3)、硬件复杂度增加。
4)、由于复杂度的增加,令完成一个设计消耗的人力和时间增加,从而设计成本增加。
5)、流水先越深,发生需要hold 流水线或reset 流水线的情况时,时间损失越大。
结论:流水线的增加会令效能和成本同时增加,当效能的增加比成本的增加要大时,流水线是可取的,如果成本的增加比效能的增加大时,流水线就失去原来的意义。根据以往CPU 流水线的发展历程来看,通过加深流水线来提高效能存在极限。
6. 1)功能模块之间的流水线,用乒乓buffer来交互数据。代价是增加了memory的数量,但是和获得的巨大性能提升相比,可以忽略不计。
2)I/O瓶颈,比如某个运算需要输入8个数据,而memroy只能同时提供2个数据,如果通过适当划分运算步骤,使用流水线反而会减少面积。
3)片内sram的读操作,因为sram的读操作本身就是两极流水线,除非下一步操作依赖读结果,否则使用流水线是自然而然的事情。
4)组合逻辑太长,比如(a+b)*c,那么在加法和乘法之间插入寄存器是比较稳妥的做法。
二、流水线技术的工作原理
流水线能动态的提升器件性能,它的基本思想是对经过多级逻辑的长数据通路进行重新构造,把原来必须在一个时钟周期内完成的操作分成在多个周期内完成。这种方法允许更高的工作频率,因而提高了数据吞吐量。采用流水线后,数据通道将会变成多时钟周期,所以要特别考虑设计的其余部分,解决增加通路带来的延迟。
流水线的基本结构是将适当划分的N个操作步骤串联起来。流水线的最大特点是数据流在各个步骤的处理,从时间上看是连续的;其操作的关键在于时序设计的合理安排、前后级接口间数据的匹配。如果前级操作的时间等于后级操作的时间,直接输入即可;如果前级操作的时间小于后级操作的时间,则需要对前级操作的数据进行缓存,才能输入到后级;如果前级操作的时间大于后级操作的时间,则需要串并转换等方法进行数据分流,然后再输入到下一级。——《Xilinx FPGA开发实用教程》
三、流水线技术实例
使用verilog HDL实现的具有4级流水线结构的8位全加器。并与非流水线结构进行比较。
采用非流水线结构:
module adder8_4 ( clk, cina, cinb, cin, cout, sum);
input clk,cin;
input [7:0] cina,cinb;
output reg cout;
output reg [7:0] sum;
always @(posedge clk)
begin
{cout, sum} = cina+cinb+cin ;
end
endmodule
采用4级流水线结构:
module adder8_4 ( clk, cina, cinb, cin, cout, sum);
input clk,cin;
input [7:0] cina,cinb;
output cout;
output [7:0] sum;
reg cout;
reg cout1,cout2,cout3;
reg [7:0] tempa_d1,tempa_d2,tempa_d3;
reg [7:0] tempb_d1,tempb_d2,tempb_d3;
reg [1:0] sum1;
reg [3:0] sum2;
reg [5:0] sum3;
reg [7:0] sum;
//低2位相加
always @(posedge clk)
begin
{cout1 ,sum1} <= cina[1:0]+cinb[1:0]+cin;
end
//相加,并且将低4位拼接起来;
always @(posedge clk)
begin
tempa_d1<=cina;
tempb_d1<=cinb;
{cout2,sum2} <= {tempa_d1[3:2] + tempb_d1[3:2]+{2'b0,cout1},sum1};
end
//相加,并且将低6位拼接起来;
always @(posedge clk)
begin
tempa_d2 <= tempa_d1;
tempb_d2 <= tempb_d1;
{cout3,sum3} <= {tempa_d2[5:4] + tempb_d2[5:4] + {2'b0,cout2},sum2};
end
//相加,并且将8位拼接起来;
always @(posedge clk)
begin
tempa_d3 <= tempa_d2;
tempb_d3 <= tempb_d2;
{cout,sum} <= {tempa_d3[7:6] + tempb_d3[7:6] + {2'b0,cout3},sum3};
end
endmodule
文章评论(0条评论)
登录后参与讨论