verilog中两种写流水线的方法,哪种更好?
Two ways to write pipeline in verilog, which one is better?
学习了两种pipeline的写法(unblocking和blocking),不知道哪个更好?
我个人认为第二个很乏味,我不明白为什么需要那么多wire
。
另外,在verilog中有没有像FSM这样的流水线的标准写法(模板)?
提前致谢。
module simplePipeline
#(
parameter WIDTH = 100
)
(
input clk,
input [WIDTH - 1 : 0] datain,
output [WIDTH - 1: 0] dataout
);
reg [WIDTH - 1 : 0] piprData1;
reg [WIDTH - 1 : 0] piprData2;
reg [WIDTH - 1 : 0] piprData3;
always @(posedge clk) begin
piprData1 <= datain;
end
always @(posedge clk) begin
piprData2 <= piprData1;
end
always @(posedge clk) begin
piprData3 <= piprData2;
end
assign dataout = piprData3;
endmodule
module blockingPipeline#2
(
parameter WIDTH = 100
)
(
input clk,
input rst,
input validIn,
input [WIDTH - 1 : 0] dataIn,
input outAllow,
output wire validOut,
output wire [WIDTH - 1 : 0] dataOut
);
reg pipe1Valid;
reg [WIDTH - 1 : 0] pipe1Data;
reg pipe2Valid;
reg [WIDTH - 1 : 0] pipe2Data;
reg pipe3Valid;
reg [WIDTH - 1 : 0] pipe3Data;
/*------------------------PIPE1 LOGIC------------------------*/
wire pipe1AllowIn;
wire pipe1ReadyGo;
wire pipe1ToPipe2Valid;
assign pipe1ReadyGo = 1'b1
assign pipe1AllowIn = ! pipe1Valid || pipe1ReadyGo && pipe2AllowIn;
assign pipe1ToPipe2Valid = pipe1Valid && pipe1ReadyGo
always @(posedge clk)begin
if( rst ) begin
pipe1Vali <= 1'b0;
end
else if(pipe1AllowIn)begin
pipe1Valid <= validIn;
end
ifvalidIn && pipe1AllowIn)begin
pipe1Data <= dataIn;
end
end
/*------------------------PIPE2 LOGIC------------------------*/
wire pipe2AllowIn;
wire pipe2ReadyGo;
wire pipe2ToPipe3Valid;
assign pipe2ReadyGo = 1'b1;
assign pipe2AllowIn = ! pipe2Valid || pipe2ReadyGo && pipe3AllowIn;
assign pipe2ToPipe3Valid = pipe2Valid && pipe3ReadyGo;
always @(posedge clk)begin
if( rst ) begin
pipe2Valid <= 1'b0;
end
else if(pipe2AllowIn)begin
pipe2Valid <= pipe1ToPipe2Valid;
end
if(pipe1ToPipe2Valid && pipe2AllowIn)begin
pipe2Data <= pipe1Data;
end
end
/*------------------------PIPE3 LOGIC------------------------*/
wire pipe3AllowIn;
wire pipe3ReadyGo;
assign pipe3ReadyGo = 1'b1;
assign pipe3AllowIn = ! pipe3Valid || pipe3ReadyGo && outAllow;
always @(posedge clk)begin
if( rst ) begin
pipe3Valid <= 1'b0;
end
else if(pipe3AllowIn)begin
pipe3Valid <= pipe2ToPipe3Valid;
end
if(pipe2ToPipe3Valid && pipe3AllowIn)begin
pipe3Data <= pipe2Data;
end
end
assign validOut = pipe3Valid && pipe3ReadyGo;
assign dataOut = pipe3Data;
endmodule
作为良好实践,第二个似乎 "better" 从某种意义上说,当您设计硬件电路部件时,您可能希望提供很好的控制可能性。一般来说,由于您的代码将永远在硅片中实现(或在您的 FPGA 中进行痛苦的重新配置),因此没有足够的控制能力将是一个真正的问题,因为您之后无法真正添加一些。
举个例子,您在评论中已经提到您必须停止管道,因此您当然需要更多的电线来完成它。有时您还需要重置管道,这就是 rst
信号的目的。
然而,更多的信号意味着更多的硅表面(或使用更多的 FPGA 资源),这通常需要更高的价格。有人可能会争辩说,只有一根或两根电线不会对芯片产生如此大的影响,这是事实,但如果你在电路上重复使用你的管道一千次,它会更重要。
对我来说,第一个实现可能只与电路级非常强的优化要求相关,例如 ASIC,您完全知道整体所需的行为。
第一个版本的问题是似乎根本没有时钟门。除非您的时钟在更高级别上得到很好的门控,或者每个周期都使用管道,否则您将通过(不必要地)在每个周期切换管道的每个阶段来浪费大量功率。
学习了两种pipeline的写法(unblocking和blocking),不知道哪个更好?
我个人认为第二个很乏味,我不明白为什么需要那么多wire
。
另外,在verilog中有没有像FSM这样的流水线的标准写法(模板)? 提前致谢。
module simplePipeline
#(
parameter WIDTH = 100
)
(
input clk,
input [WIDTH - 1 : 0] datain,
output [WIDTH - 1: 0] dataout
);
reg [WIDTH - 1 : 0] piprData1;
reg [WIDTH - 1 : 0] piprData2;
reg [WIDTH - 1 : 0] piprData3;
always @(posedge clk) begin
piprData1 <= datain;
end
always @(posedge clk) begin
piprData2 <= piprData1;
end
always @(posedge clk) begin
piprData3 <= piprData2;
end
assign dataout = piprData3;
endmodule
module blockingPipeline#2
(
parameter WIDTH = 100
)
(
input clk,
input rst,
input validIn,
input [WIDTH - 1 : 0] dataIn,
input outAllow,
output wire validOut,
output wire [WIDTH - 1 : 0] dataOut
);
reg pipe1Valid;
reg [WIDTH - 1 : 0] pipe1Data;
reg pipe2Valid;
reg [WIDTH - 1 : 0] pipe2Data;
reg pipe3Valid;
reg [WIDTH - 1 : 0] pipe3Data;
/*------------------------PIPE1 LOGIC------------------------*/
wire pipe1AllowIn;
wire pipe1ReadyGo;
wire pipe1ToPipe2Valid;
assign pipe1ReadyGo = 1'b1
assign pipe1AllowIn = ! pipe1Valid || pipe1ReadyGo && pipe2AllowIn;
assign pipe1ToPipe2Valid = pipe1Valid && pipe1ReadyGo
always @(posedge clk)begin
if( rst ) begin
pipe1Vali <= 1'b0;
end
else if(pipe1AllowIn)begin
pipe1Valid <= validIn;
end
ifvalidIn && pipe1AllowIn)begin
pipe1Data <= dataIn;
end
end
/*------------------------PIPE2 LOGIC------------------------*/
wire pipe2AllowIn;
wire pipe2ReadyGo;
wire pipe2ToPipe3Valid;
assign pipe2ReadyGo = 1'b1;
assign pipe2AllowIn = ! pipe2Valid || pipe2ReadyGo && pipe3AllowIn;
assign pipe2ToPipe3Valid = pipe2Valid && pipe3ReadyGo;
always @(posedge clk)begin
if( rst ) begin
pipe2Valid <= 1'b0;
end
else if(pipe2AllowIn)begin
pipe2Valid <= pipe1ToPipe2Valid;
end
if(pipe1ToPipe2Valid && pipe2AllowIn)begin
pipe2Data <= pipe1Data;
end
end
/*------------------------PIPE3 LOGIC------------------------*/
wire pipe3AllowIn;
wire pipe3ReadyGo;
assign pipe3ReadyGo = 1'b1;
assign pipe3AllowIn = ! pipe3Valid || pipe3ReadyGo && outAllow;
always @(posedge clk)begin
if( rst ) begin
pipe3Valid <= 1'b0;
end
else if(pipe3AllowIn)begin
pipe3Valid <= pipe2ToPipe3Valid;
end
if(pipe2ToPipe3Valid && pipe3AllowIn)begin
pipe3Data <= pipe2Data;
end
end
assign validOut = pipe3Valid && pipe3ReadyGo;
assign dataOut = pipe3Data;
endmodule
作为良好实践,第二个似乎 "better" 从某种意义上说,当您设计硬件电路部件时,您可能希望提供很好的控制可能性。一般来说,由于您的代码将永远在硅片中实现(或在您的 FPGA 中进行痛苦的重新配置),因此没有足够的控制能力将是一个真正的问题,因为您之后无法真正添加一些。
举个例子,您在评论中已经提到您必须停止管道,因此您当然需要更多的电线来完成它。有时您还需要重置管道,这就是 rst
信号的目的。
然而,更多的信号意味着更多的硅表面(或使用更多的 FPGA 资源),这通常需要更高的价格。有人可能会争辩说,只有一根或两根电线不会对芯片产生如此大的影响,这是事实,但如果你在电路上重复使用你的管道一千次,它会更重要。
对我来说,第一个实现可能只与电路级非常强的优化要求相关,例如 ASIC,您完全知道整体所需的行为。
第一个版本的问题是似乎根本没有时钟门。除非您的时钟在更高级别上得到很好的门控,或者每个周期都使用管道,否则您将通过(不必要地)在每个周期切换管道的每个阶段来浪费大量功率。