。
什么是握手協議
說起握手,首先查了一下百度百科。握手是一種禮儀,起源于中世紀的歐洲,順序為長幼有序,女士優先。(PS:所以握手的時候,男士記得要紳士一點哦)。
在芯片中,握手是最古老的跨時鐘域之間傳輸數據的方式。握手機制通過將脈沖信號展寬,待輸出一側檢測到信號并將其解析為脈沖信號后,再向輸入一側發送應答信號,表明接收到信號并且傳輸完成。
為什么要握手
在人類的進化史中,握手作為一種善意的表達方式,可以增進人與人之間的和諧。言歸正傳,那么數字電路中為什么也需要握手機制呢?這是因為在數字電路中,跨時鐘域處理是個較為常見的問題。關于跨時鐘域,我們公眾號之前有介紹過,想復習一下的同學可以查看一下之前寫的文章。
在從快時鐘向慢時鐘傳遞時,由于輸入信號變化較快,輸出一側可能跟不上輸入的變化,從而導致“漏采“現象。由于兩個時鐘之間的頻率不同,來自快時鐘域的脈沖信號,還沒來得及被慢時鐘的采到,便轉瞬即逝,從而導致信號被漏采。此時,握手機制便可以大顯神通。
握手機制的原理
(1)發送端在t_clk時鐘域下將需要發送的數據準備好后,將t_rdy信號置為有效,該信號必須在tclk下降沿輸出。接收端在rclk時鐘域下同步r_rdy信號,同步后的信號命名為t_rdy_rclk。
(2)接收端在t_rdy_rclk有效期間,對t_data進行采樣,得到t_data_rclk。
(3)接收端將r_ack信號置為1,信號必須在rclk下降沿輸出。發送端將r_ack同步為r_ack_tclk。
至此,已經完成“半握手”,發送端在輸出下一數據前,不會等到r_ack_tclk被置為0。半握手機制工作速度快,但是使用不當有可能會導致操作錯誤。然而,如果要從高頻時鐘向低頻時鐘傳輸數據,則需要采用全握手機制。
(4)當r_ack_tclk為高電平時,發送端將t_rdy置為0。
(5)當t_rdy_rclk為低電平時,接收端將r_ack置為0。
(6)當r_ack_tclk為低電平時,發送端將t_rdy重新置為1發送端可以發送新的數據。
至此,全握手完成。顯然,全握手過程耗時較長,數據傳輸較慢。但是全握手機制穩定可靠,可以在兩個任意頻率的時鐘域中安全地進行數據傳輸。需要注意一點的是,數據應該在發送時鐘域內穩定至少兩個時鐘上升沿,請求信號req的寬度應該超過兩個時鐘周期,否則從高速時鐘向低速時鐘傳遞可能無法捕捉到該信號,也就是信號“失聯”了。
握手機制的代碼實現
發送端狀態機:
module transmit(tclk,reset_tclk,t_rdy,data_avail,transmit_data,t_data,r_ack);
input tclk;
input reset_tclk;
input data_avail;
input [31:0]transmit_data;
input r_ack;
output t_rdy;
output t_data;
localparam IDLE_T = 2'd0,
ASSERT_T_RDY = 2'd1,
DEASSERT_T_RDY = 2'd2;
reg [1:0] t_hndshk_state,t_hndshk_state_nxt;
reg t_rdy,t_rdy_nxt;
reg [31:0] t_data,t_data_nxt;
reg r_ack_tclk;
always@(*)begin
t_hndshk_state_nxt = t_hndshk_state;
t_rdy_nxt = 1'b0;
t_data_nxt = t_data;
case(t_hndshk_state)
IDLE_T:begin
if(data_avail) begin
t_rdy_nxt = 1'b1;
t_hndshk_state_nxt = ASSERT_T_RDY;
t_data_nxt = transmit_data;
end
end
ASSERT_T_RDY:begin
if(r_ack_tclk)begin
t_rdy_nxt = 1'b0;
t_hndshk_state_nxt = DEASSERT_T_RDY;
t_data_nxt = 'd0;
end
else begin
t_rdy_nxt = 1'b1;
t_data_nxt = transmit_data;
end
end
DEASSERT_T_RDY:begin
if(!r_ack_tclk)begin
if(data_avail)begin
t_rdy_nxt = 1'b1;
t_hndshk_state_nxt = ASSERT_T_RDY;
t_data_nxt = transmit_data;
end
else begin
t_hndshk_state_nxt = IDLE_T;
end
end
end
endcase
end
always@(posedge tclk or negedge reset_tclk)begin
if(!reset_tclk)begin
t_rdy <= 1'b0;
t_hndshk_state <= IDLE_T;
t_data <= 32'h00000000;
r_ack_tclk <= 1'b0;
end
else begin
t_rdy <= t_rdy_nxt;
t_hndshk_state <= t_hndshk_state_nxt;
t_data <= t_data_nxt;
r_ack_tclk <= r_ack;
end
end
endmodule
接收端狀態機:
module receiver(rclk,reset_rclk,t_rdy,t_data,r_ack);
input rclk,reset_rclk;
input t_rdy;
input[31:0] t_data;
output r_ack;
reg r_hndshk_state,r_hndshk_state_nxt;
reg t_rdy_rclk;
reg[31:0] t_data_rclk,t_data_rclk_nxt;
reg r_ack,r_ack_nxt;
localparam IDLE_R = 1'b0,
ASSERT_ACK = 1'b1;
always@(*)begin
r_hndshk_state_nxt = r_hndshk_state;
r_ack_nxt = 1'b0;
t_data_rclk_nxt = t_data_rclk;
case(r_hndshk_state)
IDLE_R:begin
if(t_rdy_rclk)begin
r_hndshk_state_nxt = ASSERT_ACK;
t_data_rclk_nxt = t_data;
r_ack_nxt = 1'b1;
end
end
ASSERT_ACK:begin
if(!t_rdy_rclk)begin
r_hndshk_state_nxt = IDLE_R;
r_ack_nxt = 1'b0;
end
else begin
r_ack_nxt = 1'b1;
end
end
endcase
end
always@(posedge rclk or negedge reset_rclk)begin
if(!reset_rclk)begin
r_hndshk_state <= IDLE_R;
t_data_rclk <= 1'b0;
t_rdy_rclk <= 1'b0;
r_ack <= 1'b0;
end
else begin
r_hndshk_state <= r_hndshk_state_nxt;
t_data_rclk <= t_data_rclk_nxt;
t_rdy_rclk <= t_rdy;
r_ack <= r_ack_nxt;
end
end
endmodule
握手機制的缺點
一個字:慢。
好了,希望本文對大家有所幫助。
審核編輯 :李倩
-
數字電路
+關注
關注
193文章
1608瀏覽量
80682 -
代碼
+關注
關注
30文章
4799瀏覽量
68728 -
脈沖信號
+關注
關注
6文章
399瀏覽量
37009
原文標題:談談數字芯片中的握手協議
文章出處:【微信號:IP與SoC設計,微信公眾號:IP與SoC設計】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論