Verilog 時鐘簡介

2022-05-20 14:49 更新

關鍵詞:時鐘源,時鐘偏移,時鐘抖動,時鐘轉(zhuǎn)換時間,時鐘延時,時鐘樹,雙邊沿時鐘

幾乎稍微復雜的數(shù)字設計都離不開時鐘。時鐘也是所有時序邏輯建立的基礎。前面介紹建立時間和保持時間時也涉及過時鐘偏移的概念。下面將總結(jié)下時鐘的相關知識,以便更好的進行數(shù)字設計。

時鐘源

根據(jù)時鐘源在數(shù)字設計模塊中位置的不同,可以將時鐘源分為外部時鐘源和內(nèi)部時鐘源。

外部時鐘源

RC/LC 振蕩電路:利用正反饋或負反饋電路產(chǎn)生周期性變化時鐘信號。此類時鐘源電路簡單,頻率變化范圍大,但工作頻率較低,穩(wěn)定度不高。

無源/有源晶體振蕩器:利用石英晶體的壓電效應(壓力和電信號可以相互轉(zhuǎn)換)產(chǎn)生諧振信號。此類時鐘源頻率精度高,穩(wěn)定性好,噪聲低,溫漂小。有源晶振中,往往還加入了壓控或溫度補償,時鐘的相位和頻率都有較好的特性。但電路實現(xiàn)相對復雜,頻帶較窄,頻率基本不能調(diào)節(jié)。


調(diào)試特定電路時,往往也會使用一些搭建的特定電路(例如施密特觸發(fā)器)或信號發(fā)生器設備產(chǎn)生的時鐘源。

內(nèi)部時鐘源

鎖相環(huán)(PLL, Phase Locked Loop):

利用外部輸入的參考信號控制環(huán)路內(nèi)部振蕩信號的頻率和相位,實現(xiàn)輸出信號頻率對輸入信號頻率的自動跟蹤,通過反饋通路將信號倍頻到一個較高的固定頻率。


一般晶振由于工藝與成本原因,做不到很高的頻率,利用 PLL 電路就可以實現(xiàn)穩(wěn)定且高頻的時鐘。PLL 集成到設計模塊的內(nèi)部,可以保證數(shù)字電路具有較好的延遲和穩(wěn)定性。

時鐘分頻

有些模塊工作頻率會低于系統(tǒng)時鐘頻率,此時就需要對系統(tǒng)時鐘進行一定的分頻得到頻率較低的時鐘。

通過在 always 語句塊中計數(shù)并輸出時鐘信號,是分頻器常用的方法。任意分頻比的實現(xiàn)邏輯詳見下一節(jié)《Verilog 時鐘分頻》。

時鐘切換

系統(tǒng)或某些模塊的工作頻率有時候會在特定狀況下改變,例如低功耗模式下需要降頻,提高計算能力時需要升頻。此時系統(tǒng)往往會有多個時鐘源,以備有需求時進行時鐘切換。

時鐘切換邏輯如果不進行優(yōu)化,在切換的過度時間內(nèi),大概率會出現(xiàn)尖峰脈沖干擾,對電路產(chǎn)生不利影響。安全的切換邏輯,詳見后面章節(jié):《Verilog 時鐘切換》。

數(shù)字系統(tǒng)往往會采用外部晶振輸入、內(nèi)部 PLL 進行倍頻的方案。再根據(jù)設計需求進行時鐘分頻或時鐘切換。

時鐘特性

仿真時,所有同步的時鐘都是理想的:時鐘的翻轉(zhuǎn)是在瞬間完成的,模塊之間的時鐘沿都是對齊的,沒有延遲,沒有抖動。實際電路中,時鐘在傳輸、翻轉(zhuǎn)時都會有延遲。完美的數(shù)字設計,也應該考慮這些不完美的時鐘特性,否則也會造成設計時序不滿足的狀況。

下面對時鐘的一些特性進行簡單說明。

時鐘偏移(skew)

由于線網(wǎng)的延遲,時鐘信號在到達觸發(fā)器端口時,不能保證不同觸發(fā)器端口的時鐘沿是對齊的,即不同觸發(fā)器端口的時鐘相位存在差異。這種差異稱為時鐘偏移。示意圖如下:


一般時鐘偏移與時鐘頻率沒有直接的關系,與走線長度、負載電容、負載數(shù)量等因素有關。

時鐘抖動(jitter)

相對于理想時鐘沿,實際時鐘中存在的不隨時間積累的、時而超前、時而滯后的偏移稱為時鐘抖動??梢杂枚秳宇l率和抖動幅度對時鐘抖動進行定量描述。數(shù)字設計中,時鐘抖動都是用時間來描述,示意圖如下。


時鐘抖動可分為隨機抖動和固定抖動。

隨機抖動的來源為熱噪聲、半導體工藝等。

固定抖動的來源為開關電源、電磁干擾或其他不合理的布局布線等。

在綜合工具 Design Compiler 中,時鐘的偏移和抖動統(tǒng)一用不確定度 uncertainty 來統(tǒng)一表示。

轉(zhuǎn)換時間(transition)

時鐘從上升沿跳變到下降沿,或者從下降沿跳變到上升沿時,并不是"直上直下"不需要時間完成電平跳變,而是"斜坡式"需要一個過渡時間完成電平跳變。這個過渡時間稱之為時鐘的轉(zhuǎn)換時間,示意圖如下。


轉(zhuǎn)換時間大小與單元庫工藝、電容負載等有關。

時鐘延時(lantency)

時鐘從時鐘源(例如晶振、PLL 或分頻器輸出端)出發(fā)到達觸發(fā)器端口的延遲時間,稱為時鐘延時。時鐘延時包括時鐘源延遲(source latency)和時鐘網(wǎng)絡延遲(network latency),如下圖所示。


時鐘源延時,是時鐘信號從實際時鐘原點到設計模塊時鐘定義點的傳輸時間。上圖所示為 3ns。

時鐘網(wǎng)絡延時,是從設計模塊時鐘定義點到模塊內(nèi)觸發(fā)器時鐘端的傳輸時間,傳輸路徑上可能經(jīng)過緩沖器(buffer)。上圖所示為 1ns。

時鐘源延時(source latency)是設計模塊內(nèi)所有觸發(fā)器共有的延時,所以不會影響時鐘偏移(skew)。

時鐘樹

數(shù)字設計時各個模塊應當使用同步時鐘電路,同步電路中被相同時鐘信號驅(qū)動的觸發(fā)器共同組成一個時鐘域。理想電路中,時鐘信號會同時到達同時鐘域所有觸發(fā)器的時鐘端。但是實際中因為各種延遲的存在,這種無延遲的時鐘特性是很難實現(xiàn)的。而且時鐘信號的驅(qū)動能力有限,難以獨立的為一個包含較多的觸發(fā)器的時鐘域提供有效扇出。為解決時鐘延遲與驅(qū)動的問題,就需要采用時鐘樹系統(tǒng)對時鐘信號進行管理,來確保良好的時序和驅(qū)動能力。

時鐘樹,是個由許多緩沖單元 (buffer cell) 平衡搭建的網(wǎng)狀結(jié)構(gòu)。一般由一個時鐘源點,經(jīng)一級一級的緩沖單元搭建而成。增加 clock buffer(圖中橙色三角模塊) 的實際時鐘樹結(jié)構(gòu)如下所示。


藍色的上升沿符號表示時鐘的轉(zhuǎn)換時間(transition),紅色的實線則表示時鐘延時 (latency),包含 network delay 和 source latency,綠色的虛線表示時鐘不確定度(uncertainty),包括時鐘偏移(skew)和時鐘抖動(jitter)。

時鐘樹并不是來減少時鐘信號到達各個觸發(fā)器的時間,而是減少到達各個觸發(fā)器之間的時間差異。一般是后端設計人員通過插入 clock buffer 完成時鐘樹的設計。前端設計人員,往往需要保證時鐘方案與數(shù)字邏輯的功能正確性。

其他時鐘分類:

同步、異步時鐘

《Verilog 同步與異步》中有詳細說明,當時鐘同源且滿足整數(shù)倍關系是,一般可以認為時鐘是同步的。數(shù)字設計中同步時鐘的定義比較寬泛。同時鐘域下的邏輯不需要進行同步處理。

下面從同步電路的角度來理解同步時鐘的概念。

同步電路是由時序和組合邏輯電路構(gòu)成的電路。同步電路的特點是各觸發(fā)器的時鐘端全部連接在一起,并接在系統(tǒng)時鐘端。只有當時鐘脈沖到來時,電路的狀態(tài)才能改變。改變后的狀態(tài)將一直保持到下一個時鐘脈沖的到來。這期間無論外部輸入 x 有無變化,狀態(tài)表中的每個狀態(tài)都是穩(wěn)定的。

門控時鐘

門控時鐘的基本原理:使能信號有效的時候,打開時鐘。使能信號無效的時候,關閉時鐘。


由于門控時鐘可以將工作時鐘在適合的時間關閉,所以門控時鐘在低功耗設計中有著廣泛應用。門控時鐘最簡單是實現(xiàn)邏輯是將使能信號直接與時鐘信號做"與"操作,但這樣是不安全的,容易出現(xiàn)毛刺現(xiàn)象。詳細門控時鐘介紹請參考《Verilog RTL 級低功耗設計(下)》。

雙邊沿時鐘

某些模塊可以在時鐘的上升沿和下降沿都進行數(shù)據(jù)傳輸,達到速率增倍的效果。

DDR (Double Data Rate) SDRAM 是典型的采用雙邊沿傳輸數(shù)據(jù)的例子。

典型 DDR 數(shù)據(jù)傳輸示意圖如下:


下面對時鐘雙邊沿傳輸數(shù)據(jù)的行為進行一個簡單的仿真。

基本設計思路是,利用時鐘雙邊沿對數(shù)據(jù)進行讀取,然后通過與時鐘相反的片選信號對數(shù)據(jù)進行選擇輸出,完成數(shù)據(jù)在時鐘雙邊沿的傳輸。

Verilog 代碼描述如下 :

module double_rate(
    input               rstn ,
    input               clk,
    input               csn,

    input [7:0]         din,
    input               din_en,
    output [7:0]        dout,
    output              dout_en);

   //capture at posedge
   reg [7:0]            datap_r ;
   reg                  datap_en_r ;
   always @(posedge clk or negedge rstn) begin
      if (!rstn) begin
         datap_r        <= 'b0 ;
         datap_en_r     <= 1'b0 ;
      end
      else if (din_en) begin
         datap_r        <= din ;
         datap_en_r     <= 1'b1 ;
      end
      else begin
         datap_en_r     <= 1'b0 ;
      end
   end

   //capture at negedge
   reg [7:0]            datan_r ;
   reg                  datan_en_r ;
   always @(negedge clk or negedge rstn) begin
      if (!rstn) begin
         datan_r        <= 'b0 ;
         datan_en_r     <= 1'b0 ;
      end
      else if (din_en) begin
         datan_r        <= din ;
         datan_en_r     <= 1'b1 ;
      end
      else begin
         datan_en_r     <= 1'b0 ;
      end
   end

   assign dout = !csn ? datap_r : datan_r ;
   assign dout_en = datan_en_r | datap_en_r ;
endmodule

testbench 描述如下,其中雙邊沿數(shù)據(jù)傳輸模塊的時鐘頻率為 100MHz,但輸入的數(shù)據(jù)速率為 200MHz。

`timescale 1ns/1ps

module test ;
   reg          clk_100mhz, clk_200mhz ;
   reg          rstn ;
   reg          csn ;
   reg [7:0]    din ;
   reg          din_en ;
   wire [7:0]   dout ;
   wire         dout_en ;

   always #(2.5)    clk_200mhz  = ~clk_200mhz ;
   always @(posedge clk_200mhz)
                    clk_100mhz  = ~clk_100mhz ;

   initial begin
      clk_100mhz  = 0 ;
      clk_200mhz  = 0 ;
      rstn        = 0 ;
      din         = 0 ;
      din_en      = 0 ;
      csn         = 0 ;
      //start work
      #11 rstn    = 1 ;
      @(negedge clk_100mhz) ;
      din_en      = 1 ;
      #0.2 ;
      csn         = 1 ; //csn=1 時輸出下降沿采集的數(shù)據(jù)
      //generate csn
      forever begin
         @(posedge clk_100mhz) ;
         #0.2 ;         //增加些許延遲確保數(shù)據(jù)采集正確
         csn = 0 ;      //csn=0 時輸出上升沿采集的數(shù)據(jù)
         @(negedge clk_100mhz) ;
         #0.2 ;
         csn = 1 ;      //csn=1 時輸出下降沿采集的數(shù)據(jù)
      end
   end

   always @(negedge clk_200mhz) begin
      din <= {$random()} % 8'hFF ;  //產(chǎn)生傳輸?shù)碾S機數(shù)據(jù)
   end

   double_rate u_double_rate(
     .rstn      (rstn),
     .clk       (clk_100mhz),
     .csn       (csn),
     .din       (din),
     .din_en    (din_en),
     .dout      (dout),
     .dout_en   (dout_en));

   initial begin
      forever begin
         #100;
         if ($time >= 10000)  $finish ;
      end
   end

endmodule // test

前幾個數(shù)據(jù)的仿真結(jié)果如下。

由圖可知,數(shù)據(jù)傳輸正常,且速率為時鐘頻率的 2 倍。


本次只是對時鐘雙邊沿傳輸數(shù)據(jù)進行簡單的仿真,并不是仿真 DDR 的工作原理。DDR 雙倍速率傳輸數(shù)據(jù)的工作原理遠比此次仿真復雜的多。

但是一般情況下,不建議使用雙邊沿時鐘邏輯,主要有以下幾點原因。

always 塊中,不能同時使用上升沿和下降沿作為敏感列表,也不能在 2 個always 塊中為同一個變量賦值,例如下列描述就是錯誤的。雖然 RTL 編譯可能不會報錯,但也不能綜合成實際電路。這就導致了信號間通信的難度。

   always @(posedge clk or negedge clk) begin

數(shù)據(jù)傳輸速率是數(shù)據(jù)時鐘頻率的兩倍,如果使用時鐘上升沿和下降沿邏輯進行 RTL 建模,則還需要翻轉(zhuǎn)速率和時鐘一致的片選信號;如果不使用片選信號,模塊內(nèi)應該引入數(shù)據(jù)時鐘頻率 2 倍的同源時鐘信號,才可以正常對數(shù)據(jù)進行選擇。

當使用的雙邊沿時鐘邏輯之后,需要對上升沿和下降沿都進行合理的約束。時鐘約束就會變得復雜,布局布線要求更加嚴格,調(diào)試難度增加。

使用時鐘雙邊沿進行設計,要求時鐘的質(zhì)量很高,設計時鐘樹時也需要考慮眾多因素。

點擊這里下載源碼


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號