天天看點

verilog 任意比例分頻電路的實作_面試題分析 時鐘分頻電路

老李這次又要來分析常考的面試題了,這次咱們聊聊時鐘分頻電路。這一類面試題很常見,難度其實不大,看了這一篇,老李保證你能夠在面試中自如應付。

先說什麼是時鐘分頻(clock divide),我們都知道現在的數字電路都是基于時鐘的,因為要存儲狀态就需要時序邏輯,就必須要時鐘clock。每個時鐘就是一個在0和1之間周期變化的信号。那麼我們在不同的場合可能需要不同的頻率的時鐘,很多時候我們可以在一個已有時鐘的基礎上對它進行分頻操作,進而得出一個另外更低頻率的時鐘。我們把這樣的電路叫做時鐘分頻電路,即clock divider。

好,先來看最簡單的最常見的一個例子,2分頻。假設給定輸入時鐘是100MHz,要求得到一個50MHz的時鐘。

verilog 任意比例分頻電路的實作_面試題分析 時鐘分頻電路

2分頻電路時序圖

相信這個大家都知道該怎麼做,我們把時序圖畫出來,即使你之前完全沒有聽說過clock divider,看着時序圖也可以很快想出來。2分頻的另外一個意思是,在clk_out的1個周期内,clk_in經過了2個周期(注意這個說法,之後我們還會用到,便于你了解)。在每次clk_in的上升沿來臨的時候,clk_out翻轉一下。是以電路很簡單,隻需要一個Flop加一個反相器即可。如果flop本身自帶Q反端,那連反相器都可以省下來,如下圖所示:

verilog 任意比例分頻電路的實作_面試題分析 時鐘分頻電路

那麼有了2分頻,那如果需要一個4分頻電路,怎麼辦呢?很簡單,給上面的clk_out再接一個2分頻電路呗,隻要你一直2分下去,你就可以得到4分頻,8分頻,16分頻,32分頻。。。這種辦法當然可以,但是裡面有個隐含的缺陷,我們之後再說。

那麼現在假設需求變一下,我們要求你輸出一個6分頻的電路,也就是在clk_out的1個周期内,clk_in經過了6個周期,那麼你沒有辦法利用上面2分頻級聯的辦法得到。那麼要怎麼做呢?更general的要求是,如果要求你做一個任意偶數的分頻,要如何做呢?

我們還是先以4分頻為例,看一下時序圖

verilog 任意比例分頻電路的實作_面試題分析 時鐘分頻電路

4分頻時序圖

可以看出,要求是clk_div4要保持2個clk_src周期為高,2個clk_src周期為低。自然而然,我們需要個計數器counter,counter 從0開始每個clk_src的上升沿到來的時候加1,加到3後傳回0,一直這樣循環下去。然後我們clk_div4就可以這樣産生:當counter值為0,1的時候,clk_div4為0, 當counter值為2,3的時候,clk_div4為1。

這個可以推廣到任意偶數倍2m的分頻(假設m為自然數),做法就是利用一個counter從0到2m-1不停計數,當counter值為0-m-1的時候,輸出0,當counter值為m到2m-1的時候,輸出1。RTL code老李就不寫了,留給大家自己做練習(注意,看到老李上面那樣說0到m-1,千萬不要用小于等于<=或者大于等于>=這類操作,最多用一個相等判斷操作就行了)。

于是問題就來了,能不能做一個奇數倍分頻的分頻器呢?最小的奇數倍分頻是3分頻。這裡我們要引入一個占空比(duty cycle)的概念。我們知道時鐘是一段時間為1,一段時間為0,我們把為1的這段時間占整個周期時間的比叫做占空比。以我們上面看到的clk_src為例,為1和為0的時間是相等的,也就是各占整個周期的一半,是以我們說占空比是50%。假設我們要做一個3分頻,意思是clk_out的一個周期内,clk_src經過了3個周期。如果還要求50%占空比的話,那麼clk_out為1和為0持續的時間是clk_src的1.5個周期,如下圖clk_div3所示:

verilog 任意比例分頻電路的實作_面試題分析 時鐘分頻電路

3分頻時序圖

可以看出,clk_div3的一個沿對應上去是clk_src的下降沿,不是上升沿!

那麼我們還能直接用之前偶數分頻的時候用counter計數來做嗎?可以,但是需要一點技巧。如果我們隻用上升沿觸發的flop,那麼我們隻能得到上圖中clk_div3_pos的波形。而要想在下降沿發生變化,我們隻能用一個下降沿觸發的flop,如上圖的clk_div3_neg的波形。然後我們将兩個再OR起來,就可以得到一個占空比50%的3分頻了。RTL code老李這裡就不放了,相信大家可以自己寫出來。

講到這裡,我們可以說掌握了最基本的分頻器做法,應付大多數公司的筆試題夠了,但是其實分頻器裡面還有一些更加深入的知識點,下面才是真正的幹貨内容。

首先,我們上面提到的分頻器都是基于flop的,也就是說輸出clock是直接來自于flop的Q(偶數分頻)或者來自于兩個flop的Q之後再加一個OR門(奇數分頻)。這樣做分頻的優缺點是什麼呢?優點很明顯,就是50%的占空比。但是由此帶來的一些問題:

  1. 因為驅動clk_out的flop是由clk_src作為時鐘的,那麼這個flop的Q端變化相比于clk_src有一個必不可少的clk-to-q延時
verilog 任意比例分頻電路的實作_面試題分析 時鐘分頻電路

clk-to-q延時

這個clk-to-q延時根據不同的工藝,值會不同。這個clk-to-q delay在做時鐘樹綜合的時候是要考慮進去的。特别是如果你還期望clk_src和clk_out是同步的時鐘,沿要對齊的話,在做clock tree的時候要給clk_src的tree加一些buffer來彌補這個clk-to-q。而如果你是用了好幾個分頻器級聯産生更低頻率,那麼每一級的分頻器都會貢獻一個clk-to-q延時,那麼你需要平衡時鐘的時候就需要插入更多的buffer,這部分buffer又占面積,又耗功耗,甚至可能導緻時鐘無法平衡。是以這是需要大家在設計的時候考慮進去的。

2. 奇數分頻需要在兩個flop之後再加一個組合邏輯門,這個組合邏輯門又會增加clk的delay,同時設計的時候要非常小心,否則可能出現毛刺。

那麼有沒有辦法解決上面的問題呢?這個時候大家要思考一個問題:我們為什麼需要50%占空比的時鐘?我們真的需要50%占空比的時鐘嗎?

回顧一下我們的設計,對于絕大多數的flop,我們隻需要用到時鐘的上升沿觸發,而并不會用到下降沿,甚至有的工藝庫裡面就不提供下降沿觸發的flop。大家如果不信,可以看看你的設計,是不是幾乎都是always_ff @(posedge clk)。在這種情況下,隻有上升沿和時鐘頻率有關系,什麼時候來下降沿不重要!如果你能保證你的子產品當中不存在下降沿觸發的flop,那麼50%的占空比不是必須的。這種情況下我們可以利用clock gater 來幫我們實作分頻。

關于clock gating的基本介紹,大家可以看我之前的一篇推送。Clock Gating 技術解析 (一), 對于一個clock gater來說,都有一個時鐘的使能端enable,當enable為1的時候,clock gater 是通的,會放過一個clk_src的pulse。是以,利用clock gater來分頻的思路其實也很簡單,如果要N分頻,就是在N個clk_src周期内,隻要使得clock gater使能1個周期即可。以3分頻為例,時序圖如下

verilog 任意比例分頻電路的實作_面試題分析 時鐘分頻電路

利用clock gating的3分頻

我們依然需要一個counter,從0計數到N-1, 當counter值等于N-1(其實等于0到N-1的任意一個值都行)的時候,enable clock gater,enable隻持續一個周期,這樣就會産生一個pulse,pulse的寬度為clk_src的半周期。電路圖也非常簡單,如下圖所示

verilog 任意比例分頻電路的實作_面試題分析 時鐘分頻電路

利用clock gater的分頻電路圖

好處當然是不需要區分奇數分頻還是偶數分頻,counter始終都是在clk_src的上升沿跳變的。

那麼基于clock gater的分頻器有什麼好處呢?首先解決的問題就是上面flop based分頻器clk-to-q延時大的問題。我們知道,clock gater裡面是有一個latch,而latch是在下降沿被enable的,是以一個clock gater傳遞那個pusle的延時隻是裡面的那個AND門,這個delay通常要比clk-to-q要小很多。在時鐘樹上有一個clock gater對于時鐘樹綜合(CTS)通常不是什麼問題。

更大的好處是分頻器的級聯,我們可以把分頻器設計成帶有輸入enable和輸出enable的子產品,如下圖所示

verilog 任意比例分頻電路的實作_面試題分析 時鐘分頻電路

帶有enable的clk divider

比如說我們已經有了一個2分頻的clock divider,那麼如果我們需要個4分頻,可以再級聯一個,如下圖所示

verilog 任意比例分頻電路的實作_面試題分析 時鐘分頻電路

兩級clock divider級聯

這樣做的好處在于clk_src到clk_div4依然隻有一個clock gater的delay,其實不管你級聯多少個,隻要利用enable來級聯,隻有最後一級的clock divider會引入一個clock gater延時,而不是累計的,而且每一級的輸出分頻clock 都各自對clk_src隻有一個clock gater delay,也就是說它們彼此之間幾乎是已經balance的,這對時鐘樹綜合大有幫助。還有一個好處就是clock gater的輸出可以保證沒有glitch。

好,那麼我們再進階繼續問下去,我們前面讨論的都是整數倍的分頻,也就是2,3,4....這樣分頻下去,那麼如果我想從一個3MHz的時鐘得到一個2MHz的時鐘,即1.5倍分頻,要怎麼做呢?

首先我們來看1.5倍分頻長什麼樣,時序圖如下

verilog 任意比例分頻電路的實作_面試題分析 時鐘分頻電路

1.5倍分頻50% duty cycle 的時序圖

那麼大家思考一下,隻用數字電路裡面基本的這些邏輯門和flop,我們能夠做到上面的時序嗎?

答案是做不到,注意紅圈标出來的地方,clk_div1p5要發生變化,但是clk_src那一時刻既沒有上升沿,也沒有下降沿,而我們數字電路是基于時鐘沿觸發的,在沒有時鐘沿的地方我們就無能為力了(如果我們非要達到50%的占空比,需要借助鎖相環PLL的幫助了)。

那麼如果我們把條件放寬一些,如果不要求50%的占空比,我們可以做到嗎?答案是可以,1.5倍分頻,換句話說,就是3個clk_src周期内,有2個clk_div1p5周期,如果基于clock gater做,無非就是在3個clk_src周期裡,讓clock gater enable 2個周期,放過去2個pulse就行了。時序圖如下

verilog 任意比例分頻電路的實作_面試題分析 時鐘分頻電路

利用clock gater 1.5分頻

看起來很簡單吧,但是這裡面有幾個需要注意的點:

  1. 如果上面clk_src是3MHz, 我們其實并沒有做出嚴格意義上的2MHz 的clock。注意上面圖中前兩個上升沿,它們之間的時間間隔是1個clk_src周期,而不是1.5個clk_src周期!是以在STA分析的時候,clk_div1p5的cycle還是要按照3MHz來。
  2. 我們雖然可以看到似乎整體上是3個clk_src周期裡,有兩個clk_div1p5的2個pulse,但是并不是任意3個連續的clk_src周期裡,你都能看到2個pulse,比如紅圈裡面的3個周期,你其實隻能看到1個clk_div1p5的pulse。這在整數分頻裡是不存在這個問題的。

上面兩個注意的點就會引出我們接下來要思考的問題,假設這次以2.5倍分頻為例,即5個周期裡産生2個pulse,那麼我們要在哪兩個周期裡面産生pulse呢?有下面幾種方式

verilog 任意比例分頻電路的實作_面試題分析 時鐘分頻電路

2.5倍分頻時序圖

分别對應

clk_1: counter在4和0的時候enable clock gater

clk_2: counter在4和1的時候enable clock gater

clk_3: counter在4和2的時候enable clock gater

clk_4: counter在4和3的時候enable clock gater

這幾種方式都實作了5個周期裡産生2個pulse,那麼請問大家,以上哪一個你覺得對時鐘來說更好呢?

老李覺得是clk_2和clk_3要比另外兩個好。為什麼呢?因為pulse的間隔比較均勻,clk_1和clk_4中最近的兩個pulse其實是挨着的,那麼STA裡面雖然進行了2.5分頻,但是你還是要按照分頻前的周期來進行限制。而clk_2和clk_3,它們最近的兩個pulse至少間隔了2個周期,這樣你可以按照clk_src周期的兩倍來進行限制,timing要容易close一些。

是以對于非整數的分頻,我們其實要找這麼一種解決辦法,就是要讓輸出時鐘的pulse間隔盡可能均勻,這才是時鐘分頻器裡最難的考點。

我們知道,任何有理數都可以表示為一個分數,分子分母都為整數。那麼我們把問題擴充為:設計一個M/N的分頻器,M, N互質,要求是在N個clk_src周期内産生M個pulse,且這M個pulse盡可能均勻分布。為什麼要求互質?因為不互質你就可以約分為互質的M/N。

回到上面的例子,我們設計一個2.5倍分頻器,即M=2,N=5, 如何做呢?思路是counter不能再在每個時鐘沿加1了,而是要按照一個巧妙的方式進行加,并循環。如下圖所示

verilog 任意比例分頻電路的實作_面試題分析 時鐘分頻電路

均勻分布2.5分頻

這裡counter加的辦法是,每次加2,如果counter值+2後大于等于5,那麼就減掉5,之後再每次加2。這樣counter值就是上面的0,2,4,1,3進行循環。在什麼時候enable clock gater呢,就是在每次要減5的那個周期,就是在counter等于4和3的周期enable,這樣我們就可以得到相對均勻的clock。

推廣一下,對于M/N分頻,假設counter初始值為0,counter的變化規則為

  1.  如果counter目前值加M大于等于N,則下個周期counter值為目前值+M-N
  2. 否則,counter值加M。

在當counter目前值加M大于等于N的周期enable clock,輸出pulse。

大家可以自己驗算一下,比如以2/7為例,看是否達到了均勻pulse的效果。

至此,關于clock divider在面試中可能被問到的部分老李講得差不多了,歡迎大家留言讨論。感謝閱讀到最後的你。如果你覺得老李的文章有用,不妨點個?和“在看”。如果能夠分享到群裡和朋友圈讓更多人看到,老李抱拳感謝。

最後再啰嗦一句,

如果你不想錯過老李之後的推送,那就點選最上面的藍字“IC加油站”,然後點右上的“。。。”,再點“設為星标”就可以啦。