IC/FPGA設計——跨時鐘域處理之握手(1)






點擊上方「藍字」,學習更多幹貨!

在數字電路中,跨時鐘域處理是個很龐大的問題,所以將會做爲一個專題來陸續分享。今天先來從處理單bit跨時鐘域信號同步問題來入手。

01


握手(handshake)是用來處理單bit信號的跨時鐘域傳遞的一個有效的方法。在從快時鐘向慢時鐘傳遞時,因爲輸入信號變化較快,輸出一側可能跟不上輸入的變化,從而致使「漏採「現象。php


圖1 「漏採」現象演示web



在圖1中,因爲兩個時鐘的速度差距,來自快時鐘域的脈衝信號還未到達慢時鐘的採樣邊沿便消失了,致使了「漏採」。微信


在這種狀況下,如何讓脈衝信號準確無誤地傳遞過去呢?一個方法是將脈衝信號展寬,待輸出一側檢測到信號並將其解析爲脈衝信號後,再向輸入一側發送應答信號,代表接收到信號而且傳輸完成。這個過程被稱之爲「握手」。網絡



02


先來看一個最基本的握手協議,下邊是它的電路圖。                                                     less

圖2   「握手」電路演示
編輯器


在上圖中 src_clk和dst_clk分別爲輸入和輸出側的時鐘,src_pulse爲輸入的脈衝信號,dst_pulse爲同步到輸出端的脈衝信號。能夠看到,脈衝信號被同步到輸出端後,輸出端便當即向輸入端發送了應答信號,表示收到信號。而當輸出端的應答信號同步到輸入端後,輸入端才能夠同步下一個信號。如下爲這個電路的verilog描述。學習


module Sync_Pulse ( input wire src_clk, input wire dst_clk, input wire rst_n, input wire src_pulse,  output wire dst_pulse );
reg req_state_dly1, req_state_dly2,dst_req_state,src_sync_req; reg ack_state_dly1,src_sync_ack; wire dst_sync_ack; always @ (posedge src_clk or negedge rst_n) begin if (rst_n == 1'b0) src_sync_req <= 1'b0; else if (src_pulse) src_sync_req <= 1'b1; else if (src_sync_ack) src_sync_req <= 1'b0; else; end always @ (posedge dst_clk or negedge rst_n) begin if (rst_n == 1'b0) begin req_state_dly1 <= 1'b0; req_state_dly2 <= 1'b0; dst_req_state <= 1'b0; end else begin req_state_dly1 <= src_sync_req; req_state_dly2 <= req_state_dly1; dst_req_state <= req_state_dly2; end end assign dst_sync_ack = req_state_dly2; always @ (posedge src_clk or negedge rst_n) begin if (rst_n == 1'b0) begin ack_state_dly1 <= 1'b0; src_sync_ack <= 1'b0; end else begin ack_state_dly1 <= dst_sync_ack; src_sync_ack <= ack_state_dly1; end end assign dst_pulse = dst_req_state & (~req_state_dly2); endmodule


03


上述電路雖然能夠完整的同步信號,可是若在同步一個脈衝的過程當中,輸入端又接收到一個輸入進來的脈衝,那麼此時剛剛輸入進來的脈衝將會同步失敗。更糟糕的是該電路沒有同步失敗的反饋,致使使用者誤覺得正確同步了信號。鑑於此,將上述電路進行改進,當同步失敗後將輸出src_sync_fail信號來指示同步失敗。如下爲該電路的verilog描述(此代碼來源於網絡):flex


module handshake_pulse_sync( src_clk , //source clock src_rst_n , //source clock reset (0: reset) src_pulse , //source clock pulse in src_sync_fail , //source clock sync state: 1 clock pulse if sync fail. dst_clk , //destination clock dst_rst_n , //destination clock reset (0:reset) dst_pulse //destination pulse out); //PARA DECLARATION //INPUT DECLARATION input src_clk ; //source clock input src_rst_n ; //source clock reset (0: reset) input src_pulse ; //source clock pulse in input dst_clk ; //destination clock input dst_rst_n ; //destination clock reset (0:reset) //OUTPUT DECLARATION output src_sync_fail ; //source clock sync state: 1 clock pulse if sync fail. output dst_pulse ; //destination pulse out //INTER DECLARATION   wire dst_pulse ; wire src_sync_idle ; reg src_sync_fail ; reg src_sync_req ; reg src_sync_ack ; reg ack_state_dly1 ; reg ack_state_dly2 ; reg req_state_dly1 ; reg req_state_dly2 ; reg dst_req_state ; reg dst_sync_ack ;   //--========================MODULE SOURCE CODE==========================-- //--=========================================-- // DST Clock : // 1. generate src_sync_fail; // 2. generate sync req // 3. sync dst_sync_ack //--=========================================-- assign src_sync_idle = ~(src_sync_req | src_sync_ack );  //report an error if src_pulse when sync busy ; always @(posedge src_clk or negedge src_rst_n) begin if(src_rst_n == 1'b0) src_sync_fail <= 1'b0 ; else if (src_pulse & (~src_sync_idle)) src_sync_fail <= 1'b1 ; else src_sync_fail <= 1'b0 ; end   //set sync req if src_pulse when sync idle ; always @(posedge src_clk or negedge src_rst_n) begin if(src_rst_n == 1'b0) src_sync_req <= 1'b0 ; else if (src_pulse & src_sync_idle) src_sync_req <= 1'b1 ; else if (src_sync_ack) src_sync_req <= 1'b0 ; end   always @(posedge src_clk or negedge src_rst_n) begin if(src_rst_n == 1'b0) begin ack_state_dly1 <= 1'b0 ; ack_state_dly2 <= 1'b0 ; src_sync_ack <= 1'b0 ; end else begin ack_state_dly1 <= dst_sync_ack ; ack_state_dly2 <= ack_state_dly1 ; src_sync_ack <= ack_state_dly2 ; end end   //--=========================================-- // DST Clock : // 1. sync src sync req // 2. generate dst pulse // 3. generate sync ack //--=========================================-- always @(posedge dst_clk or negedge dst_rst_n) begin if(dst_rst_n == 1'b0) begin req_state_dly1 <= 1'b0 ; req_state_dly2 <= 1'b0 ; dst_req_state <= 1'b0 ; end else begin req_state_dly1 <= src_sync_req ; req_state_dly2 <= req_state_dly1 ; dst_req_state <= req_state_dly2 ; end end  //Rising Edge of dst_state generate a dst_pulse; assign dst_pulse = (~dst_req_state) & req_state_dly2 ; //set sync ack when src_req = 1 , clear it when src_req = 0 ;   always @(posedge dst_clk or negedge dst_rst_n) begin if(dst_rst_n == 1'b0) dst_sync_ack <= 1'b0; else if (req_state_dly2) dst_sync_ack <= 1'b1; else dst_sync_ack <= 1'b0; endendmodule


從代碼能夠得知,在同步信號的過程當中,src_sync_idle會拉低,此時若再有輸入脈衝,則會輸出同步失敗信號。url


仿真結果以下spa



圖3 電路仿真結果


從仿真結果能夠看到,該設計達到了同步信號要求。


對該部分有興趣的,或者有問題想要探討,歡迎點擊「閱讀原文」進行留言,也能夠直接向公衆號發送消息,歡迎你們的來信!


最後,創做不易,若是對你有幫助的話,點個「在看」再走唄!




IC/FPGA設計之分頻器設計及Verilog代碼(1)

IC/FPGA設計之分頻器設計及Verilog代碼(2)

IC/FPGA設計之複雜序列檢測


你點的每一個贊,我都認真當成了喜歡


本文分享自微信公衆號 - 數字積木(ggreat-top)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索