流水线设计是指将组合逻辑延时路径系统地分割,并在各个部分(分级)之间插人寄存器暂存中间数据的方法.流水线缩短了在一个时钟周期内信号通过的组合逻辑电路延时路径长度,从而提高时钟频率.对于同步电路,其速度就是指同步电路时钟的频率,同步时钟愈快,电路处理数据的时间间隔越短,电路在单位时间内处理的数据量就愈大,即电路的吞吐量就越大,理论而言,采用流水线技术能够提高同步电路的运行。
蓝色部分所示,是将之前在一个时钟周期内完成的操作分成3个周期完成。虽然直到第3个周期后才会有第一个数据输出,但是在以后的每个时钟周期内都会有处理完成的数据输出。也就是说,流水线设计只在刚开始处理时需要一定的处理时间,以后就会源源不断的输出数据。
如图,意料之中,时钟的裕量为11.068,比之前的
9.785要大。这也体现了所谓的面积换速度的思想。
就拿一个简单的例子来说吧。最近在研究数字图像处理方面的技术,初步想完成一个从RGB空间转到Ycbcr空间的功能。下面是我写的两个代码,实现的功能相同,都是将RGB565转成Ycbcr565。不过第二个是采用流水线设计的方法。先贴出代码。
module rgb2ycbcr1(
input
clk_50m
,
input
reset_l
,
input
[4:0]
rgb_R
,
input
[5:0]
rgb_G
,
input
[4:0]
rgb_B
,
output [4:0] ycbcr_Y
,
output [5:0] ycbcr_cb
,
output [4:0] ycbcr_cr
);
reg [15:0]
ycbcr_Y_r1
;
reg [15:0]
ycbcr_cb_r1
;
reg [15:0]
ycbcr_cr_r1
;
always @ (posedge clk_50m or negedge reset_l)
begin
if(!reset_l)begin
ycbcr_Y_r1 <=16'd0;
ycbcr_cb_r1 <=16'd0;
ycbcr_cr_r1 <=16'd0;
end
else begin
ycbcr_Y_r1 =((77*rgb_R + 150*rgb_G +29*rgb_B + 16'd32768 )>>8) ;
ycbcr_cb_r1 =((16'd32768 - 43*rgb_R - 85*rgb_G + 128*rgb_B )>>8) ;
ycbcr_cr_r1 =((128*rgb_R - 107*rgb_G - 21*rgb_B + 16'd32768)>>8)
;
end
end
assign ycbcr_Y = ycbcr_Y_r1 [7:4]
;
assign ycbcr_cb = ycbcr_cb_r1[ 8
:4 ] ;
assign ycbcr_cr = ycbcr_cr_r1[
7:4 ]
;
endmodule
上述代码在一个时钟周期内完成红色部分的计算,这样的话传播延迟就很大了,有三个加法器和一个乘法器。下面是综合后的RTL图:
时序报告中可以看到时钟的裕量为9.785:
然后看看采用流水线结构设计的代码:
module rgb2ycbcr2(
input
clk_50m
,
input
reset_l
,
input
[4:0]
rgb_R
,
input
[5:0]
rgb_G
,
input
[4:0]
rgb_B
,
output [4:0] ycbcr_Y
,
output [5:0] ycbcr_cb
,
output [4:0] ycbcr_cr
);
/********************** The First Flow Line*************************/
reg [15:0]
rgb_R1
;
reg [15:0]
rgb_R2
;
reg [15:0]
rgb_R3
;
always @ (posedge clk_50m or negedge reset_l)
begin
if(reset_l==1'b0)begin
rgb_R1 <=16'd0;
rgb_R2 <=16'd0;
rgb_R3 <=16'd0;
end
else begin
rgb_R1 <= 77*rgb_R ;
rgb_R2 <= 43*rgb_R ;
rgb_R3 <= 128*rgb_R ;
end
end
reg [15:0]
rgb_G1
;
reg [15:0]
rgb_G2
;
reg [15:0]
rgb_G3
;
always @ (posedge clk_50m or negedge reset_l)
begin
if(reset_l==1'b0)begin
rgb_G1 <=16'd0;
rgb_G2 <=16'd0;
rgb_G3 <=16'd0;
end
else begin
rgb_G1 <= 150*rgb_G ;
rgb_G2 <= 85*rgb_G ;
rgb_G3 <= 107*rgb_G ;
end
end
reg [15:0]
rgb_B1
;
reg [15:0]
rgb_B2
;
reg [15:0]
rgb_B3
;
always @ (posedge clk_50m or negedge reset_l)
begin
if(reset_l==1'b0)begin
rgb_B1 <=16'd0;
rgb_B2 <=16'd0;
rgb_B3 <=16'd0;
end
else begin
rgb_B1 <= 29*rgb_B ;
rgb_B2 <= 128*rgb_B ;
rgb_B3 <= 21*rgb_B ;
end
end
/********************** The Second Flow Line*************************/
reg [15:0]
ycbcr_Y_r1
;
reg [15:0]
ycbcr_cb_r1
;
reg [15:0]
ycbcr_cr_r1
;
always @ (posedge clk_50m or negedge reset_l)
begin
if(reset_l==1'b0)begin
ycbcr_Y_r1 <=16'd0;
ycbcr_cb_r1 <=16'd0;
ycbcr_cr_r1 <=16'd0;
end
else begin
ycbcr_Y_r1 <= rgb_R1 + rgb_G1 +rgb_B1 + 16'd32768 ;
ycbcr_cb_r1 <= 16'd32768 - rgb_R2 - rgb_G2 + rgb_B2 ;
ycbcr_cr_r1 <= 16'd32768 + rgb_R3 - rgb_G3 - rgb_B3 ;
end
end
/********************** The Third Flow Line*************************/
reg [7:0]
ycbcr_Y_r2
;
reg [7:0]
ycbcr_cb_r2
;
reg [7:0]
ycbcr_cr_r2
;
always @ (posedge clk_50m or negedge reset_l)
begin
if(reset_l==1'b0)begin
ycbcr_Y_r2 <=8'd0;
ycbcr_cb_r2 <=8'd0;
ycbcr_cr_r2 <=8'd0;
end
else begin
ycbcr_Y_r2 <= ycbcr_Y_r1 >> 8 ;
ycbcr_cb_r2 <= ycbcr_cb_r1 >> 8 ;
ycbcr_cr_r2 <= ycbcr_cr_r1 >> 8 ;
end
end
/********************** To Ycbcr565 *************************/
assign ycbcr_Y = ycbcr_Y_r2 [7:3]
;
assign ycbcr_cb = ycbcr_cb_r2[7:2]
;
assign ycbcr_cr = ycbcr_cr_r2[7:3]
;
endmodule
下面是综合后的RTL图:
很明显,流水线方式增加了逻辑块的使用量,这是因为需要使用寄存器来构建流水线。这些寄存器使用逻辑块中的触发器实现。虽然多耗费了点资源,但可以使设计的时钟速率更快,从而满足时序约束条件。