這篇文章是探討對(duì)接收端進(jìn)行時(shí)序優(yōu)化(即ready打拍,或稱backward打拍)的方式。
ready本身是不攜帶任何隨路信息的,但如果因此就覺(jué)得可以簡(jiǎn)單把ready打一拍來(lái)進(jìn)行時(shí)序優(yōu)化那就大錯(cuò)特錯(cuò)了,要不然可以試一試看看錯(cuò)的多離譜。
無(wú)論valid打拍還是ready打拍,都需要將控制信號(hào)(valie或ready)和傳輸信息(data)進(jìn)行寄存,因此二者的資源消耗是沒(méi)有明顯區(qū)別的。因此我們還是要借助兩個(gè)寄存器:
module dffse #(
parameter WIDTH = 1
)(
input clk,
input rst_n,
input [WIDTH -1:0] d,
input en,
output reg[WIDTH -1:0] q
);
always @(posedge clk or negedge rst_n)begin
if(~rst_n) q <={WIDTH{1'b1}};
else if(en) q <= d;
end
endmodule
module dffe#(
parameter WIDTH = 1
)(
input clk,
input [WIDTH -1:0] d,
input en,
output reg[WIDTH -1:0] q
);
always @(posedge clk)begin
if(en) q <= d;
end
endmodule
這次用了dffse寄存器,說(shuō)白了就是復(fù)位值為全1寄存器,沒(méi)什么稀奇的。
那么對(duì)于ready打拍,關(guān)鍵點(diǎn)顯然就是data_in_ready的控制邏輯,不過(guò)這個(gè)邏輯不是太容易理解,所以咱們鏡像著data_in_valid的打拍來(lái)看。還記得fw_pipe中對(duì)data_in_valid打拍的方法么:
wire in_valid_en = data_in_ready;
wire in_valid_d = data_in_valid;
wire in_valid_q;
dffre #(.WIDTH(1))
u_in_valid_dffre(
.clk(clk),
.rst_n(rst_n),
.d(in_valid_d),
.en(in_valid_en),
.q(in_valid_q)
);
assign data_in_ready = data_out_ready || (~in_valid_q);
assign data_out_valid = in_valid_q;
那咱們鏡像的來(lái)做bw_pipe中data_in_ready的邏輯應(yīng)該是:
wire out_ready_en = data_out_valid;
wire out_ready_d = data_out_ready;
wire out_ready_q;
dffse #(.WIDTH(1))
u_out_ready_dffse(
.clk(clk),
.rst_n(rst_n),
.d(out_ready_d),
.en(out_ready_en),
.q(out_ready_q)
);
assign data_out_valid = data_in_valid || (~out_ready_q);
assign data_in_ready = out_ready_q;
深深地感受下代碼的對(duì)稱之美!那么在fw_pipe中u_in_valid_dffre寄存的狀態(tài)是發(fā)送端是否有發(fā)送數(shù)據(jù)的請(qǐng)求,那么對(duì)應(yīng)的bw_pipe中u_out_ready_dffse寄存的狀態(tài)是什么呢?自然是接收端是否有接收數(shù)據(jù)的能力,因此這個(gè)寄存器的復(fù)位值應(yīng)該為1(就算上來(lái)下游就堵住了,pipe里至少能緩存一拍數(shù))。
因此當(dāng)該寄存器值為1時(shí)表明pipe內(nèi)是空的,為0時(shí)表示pipe內(nèi)有一筆數(shù),所以也就構(gòu)成了data_out_valid的一部分邏輯。
data_out_valid雖然是我們通過(guò)鏡像對(duì)稱得到的,但是也要理解所以然。當(dāng)out_ready_q == 0時(shí)表明pipe中有一筆數(shù)那么data_out_valid必然為1,此外無(wú)論out_ready_q什么狀態(tài)只要data_in_valid == 1那么也表明向下游傳輸?shù)臄?shù)據(jù)已經(jīng)準(zhǔn)備好了,data_out_valid也需要為1(對(duì)ready打拍,那么必然valid是存在bypass通路的。你想想在對(duì)valid進(jìn)行打拍時(shí),ready是不是有一條bypass通路)。
而out_ready_d = data_out_ready就需要感受一下了,如果這拍向下游握手成功了那么無(wú)論如何下一拍bw_pipe也是空的了。你結(jié)合data_out的邏輯一起品一品:
wire data_en = data_in_valid && data_in_ready;
wire [WIDTH -1:0]data_d = data_in;
wire [WIDTH -1:0]data_q;
dffe #(.WIDTH(WIDTH))
u_in_data_dffe(
.clk(clk),
.d(data_d),
.en(data_en),
.q(data_q)
);
assign data_out = out_ready_q ? data_in : data_q;
如果當(dāng)拍out_ready_q == 0(bw_pipe內(nèi)有數(shù))則取走data_q,否則直接通過(guò)bypass通路取走data_in。那是不是意味著,只有對(duì)下游握手了,下一拍的bw_pipe中就一定沒(méi)有數(shù)了!
問(wèn)題解決啦,最后的代碼就完整的出來(lái)了呀:
module bw_pipe #(
parameter WIDTH = 8)
(
input clk,
input rst_n,
input [WIDTH -1:0]data_in,
input data_in_valid,
output data_in_ready,
output[WIDTH -1:0]data_out,
output data_out_valid,
input data_out_ready
);
wire out_ready_en = data_out_valid;
wire out_ready_d = data_out_ready;
wire out_ready_q;
dffse #(.WIDTH(1))
u_out_ready_dffse(
.clk(clk),
.rst_n(rst_n),
.d(out_ready_d),
.en(out_ready_en),
.q(out_ready_q)
);
wire data_en = data_in_valid && data_in_ready;
wire [WIDTH -1:0]data_d = data_in;
wire [WIDTH -1:0]data_q;
dffe #(.WIDTH(WIDTH))
u_in_data_dffe(
.clk(clk),
.d(data_d),
.en(data_en),
.q(data_q)
);
assign data_out_valid = data_in_valid || (~out_ready_q);
assign data_out = out_ready_q ? data_in : data_q;
assign data_in_ready = out_ready_q;
endmodule
當(dāng)然了我們會(huì)發(fā)現(xiàn)一個(gè)特性,bw_pipe不像fw_pipe那樣會(huì)至少對(duì)數(shù)據(jù)打一拍,bw_pipe在通路暢通時(shí)data_in_valid/data_in是直接bypass到下游的,而通路阻塞時(shí)才會(huì)將數(shù)據(jù)在bw_pipe中寄存。
最后仍然借助auto_testbench驗(yàn)證一下代碼:
-
寄存器
+關(guān)注
關(guān)注
31文章
5294瀏覽量
119814 -
時(shí)序優(yōu)化
+關(guān)注
關(guān)注
0文章
4瀏覽量
1446
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論