---
# System prepended metadata

title: Clock Domain Crossing(CDC)
tags: [Digital IC Design]

---

# Clock Domain Crossing(CDC)
###### tags: `Digital IC Design`

[回到主頁面](https://hackmd.io/@derek8955/BkK2Nb5Jo/https%3A%2F%2Fhackmd.io%2FdpcBlBL8TlShpQ-wSi9Quw)


建議大家在看這個文章前，先把這個影片看完
https://www.youtube.com/watch?v=kz9NWmc2N6w&list=PLpCkjM331Aa8JNoZ1s1o1txve2wlf9pCP&index=7

### <font color="BLue" > Asynchronous vs. synchronous Clock</font>

Synchronous: Derived from same clock source(Known Edge Relationship)

Asynchronous: Derived from different clock source(No Edge Relationship)

### <font color="BLue" > Why Asynchronous Design is Needed </font>
- Multi-clock Domain: 每個子電路所需的頻率不同，對特定模塊就需給較高的頻率


### <font color="BLue" > What is CDC </font>
電路是由很多 block 組成，每個 block 根據其運算功能不同，而有著不同的 clock period。在整合至一個完整的電路後，一定會有不同 clock 訊號相接的情形，這個狀況稱之為 CDC
|![](https://i.imgur.com/d0GcCR1.png) |
|:---:|
|CDC Path|

### <font color="BLue" > Problem of CDC </font>

|![](https://i.imgur.com/DSzrAzj.png)|
|:---:|

在數位電路設計裡，透過 [STA](https://hackmd.io/BOMX17vmRBumB39IhTR3Eg) 來協助檢查所有 timing path 是否有 violation. 一個正確運作的 flip-flop 應在 clock edge 的前後一段時間內( Setup time & Hold time )都保持穩定的狀態才能確保 flip-flop 所儲存的數值。

以上圖為例，兩個 flip-flop 是由不同的 clock domain 所驅動的，當 adat 最後拉至 0 的瞬間時，由於 adat 的訊號驟降讓 bDFF 沒有足夠的準備時間來完成鎖值(setup time violation)，此時就會發生 <font color="red" > metastable (亞穩態) </font>。

### <font color="BLue" > Problem of metastability </font>

|![](https://i.imgur.com/OaNbfZ5.png)|
|:---:|

無法保證後方電路輸出狀態(輸入電流不穩定)，造成後方邏輯運算錯誤。


### <font color="BLue" > Resolution of metastability </font>
> 現今沒有個辦法可以完全解決 metastability, 要做的事是大幅度地降低 metastability 產生的概率。所以會使用 MTBF(mean time between failure) 這個指標來衡量電路情形。 MTBF意思是發生兩次錯誤之間的間隔，根據應用場景的不同有不同的要求標準。

針對 metastability 的處理電路可依輸入訊號分為 single/multiple bit，在文後會針對這個部分說明。

- (1) Double flip-flop synchronizer(Single bit)
    |![](https://i.imgur.com/T5kS4id.png)|
    |:---:|
    |新增一級由 bclk 所驅動的 flip-flop(bdat2) |

由於沒有足夠的準備時間，導致第二級的 flip-flop 產生 metastable，所以直接在後面多加一級 flip-flop，提共足夠的準備時間。但 double flip 沒辦法完全消除 metastability，只是在一般情況下就已經可以大幅降低 metastability 的產生。

> 第一級與第二級之間的 timing problem 就不需要在合成階段做檢查，可以輸入下方指令
> dc_shell>set_false_path –from aff/CK –to b1ff/D

不過這樣的 synchronizer 還是存在了一個問題，如下圖所示， adata 變化太快， bclk 還沒觸發就改變了，導致後方電路完全不知道 adata 有改變。

|![](https://i.imgur.com/AfafdyL.png)|
|:---:|
| Problem of double flip-flop synchronizer |

所以使用這個方法來同步，輸入訊號<font color="red" > 必須至少大於3個 destination clock domain edge</font>。以下圖為例，adata 一開始有個 pulse，但在 bclk domain 只碰到了2個 edge( 一個 falling edge 和 一個 rising edge)，所以導致 bata 看不到 adata 有個 pulse. 

|![](https://i.imgur.com/nYjxA3r.png)|
|:---:|
| Limitation of double flip-flop synchronizer|

:::success
所以如果本身 destination clock domain 是 source clock domain 的1.5倍以上，那儘管 input data 是一個很短的 pulse， destination clock domain 還是能偵測到。
:::

- (2) Pulse synchronizer(Single bit)

Double flip-flop synchronizer 對 pulse 的長度有限制，如果小於 destination domain 的 3 個 edge 就不會成功 sync 輸入訊號。

Pulse synchronizer 進而改善這個缺陷，整體流程分為以下三個部分:
1. 將 source clock domain 的 pulse 轉換至 long pulse
2. 同樣用 double flip-flop synchronizer 同步 long pulse
3. 轉換同步後的 long pulse 至 pulse

|![](https://i.imgur.com/e33tUDF.png)|
|:---:|
|Pulse synchronizer using XOR |
|![image](https://hackmd.io/_uploads/rk7nBqfwC.png)|
| Result |

雖然說 Pulse synchronizer 可以在 a_p_in 是個 single pulse 的情況也能同步，但轉換至 long pulse(Tq) 也必須要滿足 3 個 destination clock domain edge. 換句話說，就是<font color="red" > a_p_in 發生 pulse 的間隔不可以太近</font>。

確切的大小可以看下圖，a_p_in 最快產生 pulse 的情況即是隔了一個 clock cycle, 如此 a_p_in 則變成 aclk 的 1/2 倍頻， Tq 則變成 aclk 的 1/4 倍頻, 換句話說即是 <font color="red" >Tq 這個 long pulse 維持了 2 個 aclk clock cycle</font>，只要 destination 3個 clock edge 可以滿足在兩個 aclk clock cycle，就可以用這個電路實現

一般來說在 1個Clock Destination Period + Uncertainty(Destinatino Domain Setup Time + Hold Time + Clock Skew)即可滿足輸入pulse太近的問題。所以為了讓條件更寬鬆一點，會建議要間隔1個Sorce Clock Domain Period + 4個Destination Clock Domain Period

|![](https://i.imgur.com/ZGZLsw5.png)|
|:---:|
| Worst case |

:::success
講到這裡，我們知道了可以用 double flip-flop synchronizer 解決 CDC problem. 針對 single pulse, 可以在輸入與輸出加上 XOR gate並搭配轉換後的 long pulse 進行同步。

但以上講的兩個方法都只能在 single input signal(例如 flag, 記憶體讀寫狀態, enable signal ... 等) 的情況下做處理，為何 double flip-flop synchronizer 沒辦法同步 multiple bit ?

答案是因為 <font color = "red">double flip-flop synchronizer 同步到 destination clock domain 的 delay 是隨機的</font>，可能一個 cycle 就同步好，也可能需要 2 個 cycle. 

所以可以看到下圖，由於 bdata[0] 比較快同步完成，導致最終邏輯輸出不正確。
:::
|![](https://i.imgur.com/gOIuLpf.png)|
|:---:|

- (3) Asynchronus FIFO synchronizer(Multiple bit)

在講 Asynchronus FIFO 之前，先科普一下 FIFO。FIFO(First in First out) 即是一個有 入口/出口 的儲存空間，同步 FIFO 即表示在對 FIFO 寫入或讀取是基於同步訊號處裡，所以必須有 read/write 兩個指標。

下圖為 FIFO 操作流程，假設 FIFO 有 8 個 entry, rd_ptr / wr_ptr 皆為 4 bit. 

每當對 FIFO PUSH 時， wr_ptr 則會 + 1; 反之 FIFO POP 時，rd_ptr 則會 + 1。當 rd_ptr 追上 wr_ptr 表示目前 FIFO 是空的; 當 wr_ptr 領先 rd_ptr 一圈，表示目前 FIFO 是滿的。

|![](https://i.imgur.com/M3RrdCb.png)| ![](https://i.imgur.com/Vd4P6eF.png)|
|:---:|:---:|
| 1. FIFO initial state | 2. FIFO PUSH |
|rd_ptr = 4'b0000, wr_ptr = 4'b0000|rd_ptr = 4'b0000, wr_ptr = 4'b0001|
|![](https://i.imgur.com/FtKa3SU.png)|![](https://i.imgur.com/2esSFoS.png)|
| 3. FIFO POP| 4. FIFO full state( PUSH 8 次)|
|rd_ptr = 4'b0001, wr_ptr = 4'b0001|rd_ptr = 4'b0001, wr_ptr = 4'b1001|

但異步 FIFO 在 寫入/讀取 是於各自的 clock domain, 沒辦法像同步 FIFO 這樣判斷 FIFO 的儲存狀態(滿/空)，導致 FIFO 在 PUSH 時，可能原本的儲存空間已滿，進而導致電路異常; 或者是 FIFO 在 POP 時，可能原本的FIFO 是完全沒有任何東西，結果拿到空的值。所以必須有個方式能夠互相同步 rd_ptr 與 wr_ptr 的資訊給 read control / write control。

<font color="red">解決方法就是使用 gray code 並搭配 double flip-flop synchronizer</font>. 剛剛有提到 double flip-flop synchronizer 沒辦法對 multiple bit 進行同步，但由於 gray code 在相鄰大小之間只有 1 個 bit 不同，如果以 gray code 來當作 counter, 那每次訊號翻轉時，其實只有更動其中 1 個 bit, 這樣在進行同步的時候自然不會出現問題。

那異步 FIFO 要怎麼判斷目前是空或滿呢? 和同步 FIFO 相同，先假設 8 個 entry, rd_ptr / wr_ptr 用 4 bit 表示。

異步 FIFO 為空的判斷方法與同步 FIFO 相同，若 rd_ptr 等於 wr_ptr, 代表此時 FIFO 是空的。

當連續 PUSH 8 次後，此時 FIFO 已滿，且 wr_ptr 變為 4'b1100. 可以發現 wr_ptr 與 rd_ptr 在高 2 位元都不相同, 低 2 位元相同。 於是我們就可以用這個方式判斷 FIFO 的儲存空間是否已滿。

|![](https://i.imgur.com/na9LltV.png)|
|:---:|
| gray code |

講完所有基本知識後，就可以了解 AFIFO 是怎麼運作的，電路圖如下。

|![](https://i.imgur.com/gXBSheH.png)|
|:---:|
| AFIFO |

> 1. wptr / rptr 皆是 gray code
> 2. waddr / raddr 皆是 binary code. 因為如果以 gray code 來當作 counter 的時候，可以發現它其實是呈現一個不規律的計數情形，所以在 FIFO memory access 的時候都還是保留用 binary code.
> 3. 為什麼要使用 FIFO 這個 memory?
> 假設一個很快的 clock domain(A) 要同步到一個很慢的 clock domain(B), 但因為 B 處理速度實在太慢了，在當中傳遞可能會損失掉 A 所傳送的部分訊息。所以這裡的 FIFO 是提供了一個 buffer 的環境，讓資料先寫進去，之後 B 要用到的時候再讀出來。

:link: code 實現可以看這篇[文章](https://zhuanlan.zhihu.com/p/149988091)

### <font color="BLue" > Appendix </font>

Double Flip-Flop Sync 需要滿足3個desitination clock domain edge，但一般設計者沒辦法保證這件事情，所以有一個更好的保障方法Closed-Loop Solution

|![1000010178](https://hackmd.io/_uploads/rynLpzKNel.jpg)|
|:---:|

原理大致與原先相同，在Clock Sorce Domain多了兩個Flip Flop，接收Sync後的數值，當ap2_dat成功收到Sync後，再通知adat關閉控制訊號，以確保Destination Clock Domain接收成功。



### <font color="BLue" > Reference </font>
- [1] https://ithelp.ithome.com.tw/articles/10232234
- [2] https://anysilicon.com/clock-domain-crossing-cdc/
- <font color = "red">[3] https://www.zhihu.com/people/li-hong-jiang-54/posts (推推推)</font>
- [4] https://blog.csdn.net/guyefeng123321/article/details/80970207
- [5] https://funrtl.wordpress.com/2018/12/12/cdc-clock-domain-crossing/
- [6] http://www.sunburst-design.com/papers/CummingsSNUG2008Boston_CDC.pdf (很完整的Paper)
