1. 程式人生 > >異步脈沖同步2:雙握手法

異步脈沖同步2:雙握手法

perl tle sig provided 場景 rop 關系 復制代碼 分享

https://www.cnblogs.com/digital-wei/p/6014450.html

一、前言

  上一篇文章中已經描述了簡單的脈沖同步器,它可以實現簡單應用場景下的同步功能,同時也存在不少應用限制或缺陷,例如:

  (1) 對src_clk域dst_clk關系較為敏感,當src_clk與dst_clk時鐘頻率差別很大時可能不適應;

  (2) 由於沒有完整的握手機制,當多個src_pulse之間間隔較短時,可能存在脈沖同步丟失情況。

  (3) 當dst_clk時鐘域出現無時鐘或復位時,src_clk時鐘域將丟失。

  本文將對該同步器進行改進以滿足更多異步脈沖同步場景。

二、原理

  回顧上一篇文章中的同步器的基本設計原理:

  (1)源時鐘域脈沖轉換為源時鐘域電平信號;

  (2)對單bit電平信號進行打拍的異步處理;

  (3)在目的時鐘域中進行脈沖還原。

  從以上設計原理中,我們可以發現該同步器的控制傳遞是單向的,即僅從源時鐘域到目的時鐘域,目的時鐘域並沒有狀態反饋。假設存在如下應用:

  (1) 源時鐘域中的第一個脈沖和第二個脈沖間隔過短,第一個脈沖未完成同步,第二脈沖又將狀態清空,導致最終脈沖同步丟失。

  技術分享圖片

  要解決以上同步問題,需要引入異步握手機制,保證每個脈沖都同步成功,同步成功後再進行下一個脈沖同步。握手原理如下:

  sync_req: 源時鐘域同步請求信號,高電平表示當前脈沖需要同步;

  sync_ack: 目的時鐘域應答信號,高電平表示當前已收到同步請求;

  技術分享圖片

  完整同步過程分為以下4個步驟:

  (1) 同步請求產生;當同步器處於空閑(即上一次已同步完成)時,源同步脈沖到達時產生同步請求信號sync_req;

  (2) 同步請求信號sync_req同步到目的時鐘域,目的時鐘域產生脈沖信號並將產生應答信號sync_ack;

  (3) 同步應答信號sync_ack同步到源時鐘域,源時鐘域檢測到同步應答信號sync_ack後,清除同步請求信號;

  (4) 目的時鐘域檢測到sync_req撤銷後,清除sync_ack應答;源時鐘域將到sync_ack清除後,認為一次同步完成,可以同步下一個脈沖。

三、代碼

技術分享圖片
//--====================================================================================--
// THIS FILE IS PROVIDED IN SOURCE FORM FOR FREE EVALUATION, FOR EDUCATIONAL USE OR FOR 
// PEACEFUL RESEARCH.  DO NOT USE IT IN A COMMERCIAL PRODUCT . IF YOU PLAN ON USING THIS 
// CODE IN A COMMERCIAL PRODUCT, PLEASE CONTACT [email protected] TO PROPERLY LICENSE 
// ITS USE IN YOUR PRODUCT. 
// 
// Project      : Verilog Common Module
// File Name    : handshake_pulse_sync.v
// Creator(s)   : [email protected]
// Date         : 2015/12/01
// Description  : A handshake pulse sync 
//
// Modification :
// (1) Initial design  2015-12-01
//
//
//--====================================================================================--

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 == 1b0)
        src_sync_fail   <= 1b0 ;
    else if (src_pulse & (~src_sync_idle)) 
        src_sync_fail   <= 1b1 ;
    else 
        src_sync_fail   <= 1b0 ;
end

//set sync req if src_pulse when sync idle ;
always @(posedge src_clk or negedge src_rst_n)
begin
    if(src_rst_n == 1b0)
        src_sync_req    <= 1b0 ;
    else if (src_pulse & src_sync_idle) 
        src_sync_req    <= 1b1 ;
    else if (src_sync_ack)
        src_sync_req    <= 1b0 ;
end

always @(posedge src_clk or negedge src_rst_n)
begin
    if(src_rst_n == 1b0)
        begin
            ack_state_dly1  <= 1b0 ;
            ack_state_dly2  <= 1b0 ;
            src_sync_ack    <= 1b0 ;         
        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 == 1b0)
        begin
            req_state_dly1  <= 1b0 ;
            req_state_dly2  <= 1b0 ;
            dst_req_state   <= 1b0 ;
        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;
end


endmodule
技術分享圖片

異步脈沖同步2:雙握手法