流水线原理
原理
流水线设计就是将组合逻辑系统地分割,并在各个部分之间插入寄存器,并暂存中间数据的方法。目的是将一个大操作分解为若干个小操作,每一个小操作的时间变小并且并行执行,提高系统频率,所以能够提高数据的吞吐率。
个人理解
通俗一点的理解方法我们可以举个不是特别恰当的例子:假设我们要将刚生产出的手机进行包装,那么需要三个步骤:
1、将手机装入盒子里
2、盖上盒盖
3、封上塑膜
那么假设每个步骤需要5S的话,一位工人作业的情况下包装一部手机需要15S,1分钟可以包装4部。
那么假设我们有三位工人,每位工人只做一件事,那么我们每位工人的工期就变为5S,那么我们除了在第一部手机包装完成需要15S之外,每5S都能完成下一部手机的包装即1分钟可以包装1+9=10部。用图来看可能更方便理解一些:
举例
假设要算S= (A + B + C) * D 如同上文所述的情况,串行执行每个周期需要执行两次加法一次乘法,如下图:
此时每个周期为20ns(假设),频率为50MHZ
接下来进行流水线操作:将组合逻辑系统的分割,其实就是在每一次小运算后加入寄存器进行暂存,通过增大运算面积(寄存器增多)获得更高的频率。
可以看出,此时分割成两个小部分,每部分所占时钟都为10ns(若两部分不同取大者),那么可以认为此时我们的频率变为100Mhz,即通过流水线操作提高了100%的频率。
代码举例
always@(posedge clk)begin
Reg <= A+B+C;
end
always@(posedge clk)begin
Sum <= Reg * D;
end
理想情况下的流水线代码其实很简单,即分割部分后加入相应的寄存器即可,两部分always块并行执行,互不影响。
非理想(带阻塞)流水线
依然以上例举例。个人认为所谓的阻塞就是在各个小分割部分增加阀门,控制进出。所谓的阀门,即控制信号,通过设置允许接收和允许发送,实现流水线的阻塞功能。具体代码如下:
input data_valid,
input out_allow,
output out_data_valid,
wire reg_allow_in;
reg reg_valid;
wire reg_ready_go;
wire reg_to_sum_valid;
assign reg_ready_go = //此处可加判断条件,不阻塞默认为1
assign reg_allow_in = !reg_valid||reg_ready_go && sum_allow_in
//第一部分的允许输入信号 reg没有有效数据时允许输入,
//reg中有有效数据但是已经准备好输出并且下一级允许输入时,允许输入
assign reg_to_sum_valid = reg_valid && reg_ready_go;
//当第一部分有有效数据且准备好输出时,
//产生第一部分可以给到第二部分的标志信号
always@(posedge clk)begin
if(!rst_n)begin
reg_valid <= 1'b0;
end
else if(reg_allow_in)begin
reg_valid <= data_valid;
end
if(reg_allow_in && data_valid)begin
Reg <= A+B+C;
end
end
reg Sum_valid;
wire Sum_ready_out;
wire Sum_allow_in ;
assign Sum_ready_out =
assign Sum_allow_in = !Sum_valid || Sum_ready_out && out_allow;
always@(posedge clk)begin
if(!rst_n)begin
Sum_valid <= 1'b0;
end
else if(Sum_allow_in)begin
Sum_valid <= reg_to_sum_valid;
end
if(reg_to_sum_valid && Sum_allow_in)begin
Sum <= Reg * D;
end
end
assign out_data_valid = Sum_valid&&Sum_ready_out;
流水线会增加功耗和面积,换取速度。