反壓機制指的是在輸出(或者輸入)端連接的模塊不能接收數據(或者沒有輸入數據),此時自己的模塊的運行狀態需要暫停運行。
反壓機制適用于所有擁有握手協議的模塊,且強烈建議使用反壓機制用于自己模塊設計。
反壓機制在公眾號最開始也有寫過,但是過去了很長時間,對設計有了新的理解,這篇文章會細述一對一、多對一、一對多、多對多之間反壓機制的細節和設計。
以下具體示例可以參見我的GitHub:back-pressure-mechanism
git@github.com:lookout1992/back-pressure-mechanism.git
一、一對一
一對一反壓是反壓機制中的基礎,也是最常見的結構。
如上圖,如果模塊內部由一個寄存器組成,那模塊的輸出信號din.ready和dout.valid就可以如下設計:
logic switch_en;
assign switch_en = !dout.valid | dout.ready;
logic r_valid;
always @ (posedge clk or negedge rst_n)begin
if(!rst_n)begin
r_valid <= 'd0;
end
else if(switch_en)begin
r_valid <= din.valid;
end
end
assign dout.valid = r_valid;
assign din.ready = switch_en
增加switch_en信號,代表輸出端沒有準備好輸出數據 ,或者是連接輸出端的模塊已經 準備好接收數據。
總結一句話就是模塊(寄存器)的數據可以流動起來。因此switch_en也是輸出口i_ready的賦值信號。
關于valid(或者沒有顯示的data計算部分),只有在switch_en有效時,可以向下傳遞。
如果圖中模塊中由多級一對一的寄存器組成,那么最優的設計思路是像上面設計一樣,一級級拼接起來,也是最復雜的。(而不是原始公眾號文章中,用一個switch_en控制所有的流水使能)
在實際設計中,有可能會在時序和資源之間平衡,需要把流水線拆開,分時復用運算邏輯。因此會出現一筆輸入,但是有兩筆輸出,且運算時需要使用兩次輸入數據(即不允許輸入寄存器更新太快)。這個時候需要添加新的使能(或者counter)等用于額外的判斷條件
以上具體示例可以參見我的GitHub:back-pressure-mechanism/one2one
二、多對一
多對一反壓是處理一對一之外最常見的結構,多用于多個輸入數據運算輸出一個信號。
處理這種結構,主要思路是 所有輸入有效 ,對于switch2_en 和 switch3_en見上面一對一反壓設計,主要描述switch1_en和輸入輸出之間的關系:
// din0 和din1 相遇前各自一組寄存器。
logic r_reg_din0_valid;
logic w_reg_din0_ready;
logic r_reg_din1_valid;
logic w_reg_din1_ready;
logic switch1_en;
logic w_reg_din_valid;
logic r_reg_dout_valid;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
r_reg_dout_valid <= 'd0;
end
else if(switch1_en)begin
r_reg_dout_valid<= w_reg_din_valid;
end
end
assign switch1_en = !dout.valid | dout.ready;
assign w_reg_din0_ready = r_reg_din1_valid & switch_en;
assign w_reg_din1_ready = r_reg_din0_valid & switch_en;
assign w_reg_din_valid = r_reg_din0_valid & r_reg_din1_valid;
以上具體示例可以參見GitHub:back-pressure-mechanism/more2one
三、一對多
以一輸入、二輸出為例:
輸入的ready和輸出的valid將會取決于所有輸出端口是否 準備好 。
logic switch_en;
logic r_din_valid;
assign switch_en = (!dout0.valid | dout0.ready)&
(!dout1.valid | dout1.ready);
assign din.ready = switch_en;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
r_din_valid<= 'd0;
end
else if(switch_en)begin
r_din_valid<= din.valid;
end
end
assign dout0.valid = r_din_valid & dout1.ready;
assign dout1.valid = r_din_valid & dout0.ready;
四、多對多
多對多的反壓設計可以看做多對一和一對多反壓的集合。
五、總結
反壓設計的目的是模塊可以在輸入或者輸出沒有準備好是可以自動停止運算,好的反壓機制的作用是可以在運算因為輸入或者輸出的原因停止和啟動時減少其中的空檔期。
六、快速迭代
如果在設計中時間緊張,要求快速迭代出一版可以使用的反壓機制代碼,那么就不能再按照上面的設計思路扣細活。
可以直接以模塊輸出端的valid&ready作為全部寄存器的switch_en,這就會造成一個問題在停止時,所有運算都將停止,這會在啟動時有流水中會有一些空擋(氣泡)。
使用switch_en信號給所有輸入信號ready賦值,中間所有寄存器也都由switch_en控制或者由輸入信號的valid&ready控制。
logic switch_en = !dout.valid | dout.ready
assign din.ready = switch_en;
logic r_din_valid;
logic r_din_valid_d1;
logic r_din_valid_d2;
logic [DW-1:0] r_din_data;
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
r_din_data <= 'd0;
end
else if(din.valid & din.ready) begin
r_din_data <= din.data;
end
end
...
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
r_din_valid <= 'd0;
r_din_valid_d1 <= 'd0;
r_din_valid_d2 <= 'd0;
end
else if(switch_en) begin
r_din_valid <= din.valid;
r_din_valid_d1 <= r_din_valid;
r_din_valid_d2 <= r_din_valid_d1;
end
end
assign dout.valid = r_din_valid_d2;
-
模塊
+關注
關注
7文章
2695瀏覽量
47433 -
IC
+關注
關注
36文章
5944瀏覽量
175501 -
寄存器
+關注
關注
31文章
5336瀏覽量
120235 -
GitHub
+關注
關注
3文章
469瀏覽量
16428
發布評論請先 登錄
相關推薦
評論