基于FPGA的流水线设计
0赞FPGA/CPLD重要设计思想及工程应用
流水线设计篇
概述
流水线设计是高速电路设计中的一个常用设计手段。如果某个设计的处理流程分为若干步骤,而且整个数据处理是“单流向”的,即没有反馈或者迭代运算,前一个步骤的输出是下一个步骤的输入,则可以考虑采用流水线设计方法来提高系统的工作频率。
流水线处理的应用
在很多领域的高速电子系统中都运用了流水线处理的方法,如高速通信系统、高速采集系统、高速导航系统、高速搜索系统等等。流水线处理方式之所以能够很大程度上提高数据流的处理速度,是因为复制了处理模块,它是面积换取速度思想的又一种具体体现。
流水线设计应用实验
假设该设计为某实时通信系统的一个模块,该系统采样频率为5MHz,采样精度为32位。我们需要设计的内容为:对采样数据先进行加减偏移量的运算,假设需要加十六进制数00000077h的偏移量,然后把该数据压缩为16位数据,便于采样后的信号处理运算,压缩数据时保持精度相对高些。这里我们假设信号处理运算很简单,就是将压缩后的数据先减去十六进制数00ffh,然后取差值的低八位数据值做为该设计的输出。
在程序里,进行了四步的流水线作业。所以在功能仿真出来的波形图中可以看到,在en使能(粗黄线)后的三个时钟周期(也即第四个时钟上升沿)后(细黄线)en_out拉高了,dout端开始有输出的数据,而且输出的数据是每一个时钟周期来一个,和输入的数据是同步的。所谓流水作业,在实际硬件电路中就是把一个大的组合逻辑分成各个小的组合逻辑,每一个输入的信号都必须顺次通过各个阶段的操作,而各个阶段的操作又是同步进行的,这就像工厂的生产流水线一样,会有源源不断的数据信号从输出端送出。另外,从这个实验中也可以更深刻的体会到Verilog的并行性。
另外从综合后的RTL视图中可以看到四级的流水结构:
程序:
module liu_shui(clk,rst,data,en,en_out,dout);
input clk;//时钟信号
input rst;//复位信号
input[31:0] data;//输入信号
input en;//输入信号使能,如果为1说明有信号输入
output en_out;//输出信号使能,如果为1说明输出经过处理的信号
output[7:0] dout;//输出信号
wire en_1,en_2,en_3;
wire[31:0] dout_1;
wire[15:0] dout_2,dout_3;
liu_1 liu_1(clk,rst,data,en,en_1,dout_1);
liu_2 liu_2(clk,rst,dout_1,en_1,en_2,dout_2);
liu_3 liu_3(clk,rst,dout_2,en_2,en_3,dout_3);
liu_4 liu_4(clk,rst,dout_3,en_3,en_out,dout);
endmodule
module liu_1(clk,rst,data,en,en_1,dout_1);
input clk;
input rst;
input[31:0] data;
input en;
output en_1;
output[31:0] dout_1;
reg[31:0] dout_1;
reg en_1;
always@(posedge clk)
begin
if(!rst) begin dout_1 <= 32'h00000000;en_1 <= 0; end
else if(en) begin dout_1 <= data+32'h00000077;en_1 <= 1; end
else en_1 <= 0;
end
endmodule
module liu_2(clk,rst,dout_1,en_1,en_2,dout_2);
input clk;
input rst;
input[31:0] dout_1;
input en_1;
output en_2;
output[15:0] dout_2;
reg[15:0] dout_2;
reg en_2;
always@(posedge clk)
begin
if(!rst) begin dout_2 <= 16'h0000;en_2 <= 0; end
else if(en_1) begin dout_2 <= dout_1[31:16];en_2 <= 1; end
else en_2 <= 0;
end
endmodule
module liu_3(clk,rst,dout_2,en_2,en_3,dout_3);
input clk;
input rst;
input[15:0] dout_2;
input en_2;
output en_3;
output[15:0] dout_3;
reg[15:0] dout_3;
reg en_3;
parameter num="16"'h00ff;
always@(posedge clk)
begin
if(!rst) begin dout_3 <= 16'h0000;en_3 <= 0; end
else if(en_2) begin dout_3 <= dout_2-num;en_3 <= 1; end
else en_3 <= 0;
end
endmodule
module liu_4(clk,rst,dout_3,en_3,en_out,dout);
input clk;
input rst;
input[15:0] dout_3;
input en_3;
output en_out;
output[7:0] dout;
reg[7:0] dout;
reg en_out;
always@(posedge clk)
begin
if(!rst) begin dout <= 8'h00;en_out <= 0; end
else if(en_3) begin dout <= dout_3[7:0];en_out <= 1; end
else en_out <= 0;
end
endmodule