Verilog 時(shí)序邏輯UDP

2022-05-20 14:33 更新

時(shí)序邏輯 UDP 與組合邏輯 UDP 在定義形式和行為功能上均有不同,主要區(qū)別如下:

  • 時(shí)序邏輯 UDP 的輸出端必須聲明為 reg 型。
  • 時(shí)序邏輯 UDP 可以用 initial 語句初始化。
  • 狀態(tài)表格式也稍有不同:
  • ...    :  <current_state>  :  <next_state>  ;
  • 時(shí)序邏輯 UDP 狀態(tài)表每行由 3 部分組成:輸入部分、當(dāng)前狀態(tài)和輸出狀態(tài),用冒號(hào)":"隔開。
  • current_state 就是輸出寄存器的當(dāng)前值, next_state 就是輸出寄存器的新值。next_state 由輸入和 current_state 共同決定。
  • 狀態(tài)表的輸入項(xiàng)可以是電平,也可以是跳邊沿的形式。

表示時(shí)序邏輯的 UDP 主要分為 2 種:電平觸發(fā) UDP 與 邊沿觸發(fā) UDP。

電平觸發(fā) UDP

電平觸發(fā) UDP 的輸出是根據(jù)輸入電平狀態(tài)的改變而改變。

帶有清零端的 D 鎖存器的功能描述為:

  • 清零端為 1 時(shí),輸出端恒為 0 ;
  • 清零端為 0 、使能控制端為 1 時(shí),鎖存器透明,輸出端等于輸入端;
  • 清零端為 0 、使能控制端為 0 時(shí),鎖存器呈保持狀態(tài),輸出端保持不變。

其真值表為(q 表示當(dāng)前狀態(tài),q+ 表示下一個(gè)狀態(tài)):


其實(shí)編寫 UDP 的過程,可以理解為換一種格式編寫真值表的過程。

帶有清零端的 D 鎖存器的 UDP 可以描述如下:

primitive d_latch(q, clear, en, d);
   output       q ;
   reg          q ;
   input        d, en, clear ;

   initial
     q = 0 ;

   table
    //clear     en      d       :q      :q+ ;
      1         ?       ?       :?      :0 ;    //clear
      0         0       ?       :?      :- ;    //"-" means stable

      0         1       0       :?      :0 ;    //q = d
      0         1       1       :?      :1 ;
   endtable
endprimitive

當(dāng)然,也可以在羅列端口信號(hào)時(shí)就聲明其類型,并且賦初值。

primitive d_latch2(
   output reg   q = 0,
   input        clear, en, d);
   ......
endprimitive

邊沿觸發(fā) UDP

邊沿觸發(fā) UDP 的輸出是根據(jù)輸入跳邊沿和(或)輸入電平狀態(tài)的改變而改變。

直接給出帶有異步復(fù)位端(RST)且在時(shí)鐘下降沿采集信號(hào)的 D 觸發(fā)器的"真值表":


可見此"真值表"中還加入了上下沿的概念,是為了方便編寫 UDP 代碼。

此 D 觸發(fā)器的時(shí)序邏輯 UDP 描述如下:

primitive D_TRI(
            output reg  Q = 0,
            input       RST, CP, D);
   table
    //RST       CP      D       :Q      :Q+ ;
      //(1) 清零
      1         ?       ?       :?      :0 ;  //RST=1 時(shí)清零
      (??)      ?       ?       :?      :- ;  //忽略 RST 邊沿變化
      //(2) 時(shí)鐘下降沿采集
      0         (10)    0       :?      :0 ;  //時(shí)鐘下降沿采集信號(hào)
      0         (10)    1       :?      :1 ;
      //possible negedge
      0         (1x)    ?       :?      :- ;  //可能是時(shí)鐘下降沿時(shí)保持
      0         (x0)    ?       :?      :- ;
      //(3) 時(shí)鐘上升沿保持
      0         (0?)    ?       :?      :- ;  //時(shí)鐘上升沿時(shí)保持
      //possible posedge
      0         (x1)    ?       :?      :- ;  //可能是時(shí)鐘上升沿時(shí)保持
      //(4) 非時(shí)鐘沿變化時(shí),即便數(shù)據(jù)有跳變,輸出仍然保持
      0         ?       (??)    :?      :- ;  
   endtable
endprimitive // D_TRI

對(duì)此觸發(fā)器進(jìn)行簡(jiǎn)單的仿真,testbench 描述如下。

`timescale 1ns/1ps
module test ;
   reg  D, CP = 0 ;
   reg  RST ;
   wire Q ;
   always #5 CP = ~CP ;
   //data driver
   initial begin
      D = 0 ;
      #12 D = 1 ;
      #10 D = 0 ;
      #14  D = 1 ;
      #3  D = 0 ;
      #18  D = 0 ;
   end
   //reset driver
   initial begin
      RST = 0 ;
      #3        RST = 1 ;
      #2        RST = 0 ;
      #22       RST = 1 ;
      #1        RST = 0 ;
   end
   D_TRI u_d_trigger(Q, RST, CP, D);
   initial begin
      forever begin
         #100;
         //$display("---gyc---%d", $time);
         if ($time >= 1000) begin
            $finish ;
         end
      end
   end
endmodule // test

仿真結(jié)果如下。

由圖可知,在 cap1 時(shí)刻,Q 端被復(fù)位清零;在 cap2 時(shí)刻,即時(shí)鐘下降沿時(shí),輸出端采集到 D 端輸入 1;在 cap3 時(shí)刻,Q 端又被清零。符合設(shè)計(jì)。


需要注意的是:

狀態(tài)表每行多個(gè)輸入部分,最多只能有一個(gè)跳邊沿,例如下面狀態(tài)表的表述是錯(cuò)誤的。

   table
      ......
      (10)     (10)    1       :?      :1 ;
   endtable

電平觸發(fā)的狀態(tài)表輸入項(xiàng),其優(yōu)先級(jí)高于邊沿觸發(fā)的狀態(tài)表輸入項(xiàng)。若兩者在同一時(shí)刻出現(xiàn),則輸出端的狀態(tài)由電平觸發(fā)的狀態(tài)表決定。

例如上述 D 觸發(fā)器中,RST 可以看做是電平觸發(fā),CP 可以看做是邊沿觸發(fā)。當(dāng) RST 上升沿與 CP 端下降沿同時(shí)刻來臨時(shí),輸出端會(huì)變?yōu)?nbsp;0 ,如下圖 cap 時(shí)刻。當(dāng)然,實(shí)際的時(shí)序應(yīng)該避免時(shí)鐘和復(fù)位邊沿同時(shí)到來。


邊沿觸發(fā) UDP 中,必須為每一個(gè)輸入信號(hào)都指定邊沿變化時(shí)輸出信號(hào)的變化情況,否則在該信號(hào)的跳變沿處可能會(huì)造成輸出端為 X 。

例如缺少 RST 邊沿變化的說明:

    //(??)    ?       ?       :?      :- ; //忽略 RST 邊沿變化

則在 RST 下降沿輸出會(huì)變?yōu)?nbsp;x。


再例如缺少時(shí)鐘穩(wěn)定、D 端數(shù)據(jù)變化時(shí)的說明:

    //(4) 非時(shí)鐘沿變化時(shí),即便數(shù)據(jù)有跳變,輸出仍然保持
    //0         ?       (??)    :?      :- ;

則 D 端數(shù)據(jù)變化的邊沿處也會(huì)使輸出為 x。


UDP 狀態(tài)表符號(hào)縮寫

UDP 狀態(tài)表的電平和跳變沿縮寫符號(hào)及說明如下表所示。

縮寫符 含義 說明
0, 1, x 只能用于輸入
b 1, 1 只能用于輸入
- 保持原值不變 只能用于輸出
(ab) 信號(hào)由 a 變 b 用作輸入端邊沿的指示
r (01) 信號(hào)的上升沿
f (10) 信號(hào)的下降沿
p (01), (0x) 或 (x1) 可能是信號(hào)的上升沿
n (10), (1x) 或 (x0) 可能是信號(hào)的下降沿
* (??) 信號(hào)任意邊沿的變化

UDP 設(shè)計(jì)指導(dǎo)

針對(duì)數(shù)字設(shè)計(jì)時(shí)是選擇使用 module 還是 primitive,要從設(shè)計(jì)需求、復(fù)雜度等方面進(jìn)行綜合考慮。下面給出一些指導(dǎo)性的建議。

  • UDP 只能進(jìn)行功能性建模,不能對(duì)電路時(shí)序和制造工藝(例如 CMOS,TTL等)進(jìn)行建模。使用 UDP 的主要目的是以類似于真值表的簡(jiǎn)潔形式對(duì)數(shù)字設(shè)計(jì)進(jìn)行建模,而 module 可以包含電路時(shí)序,并指定制造工藝。
  • UDP 只能完成有一個(gè)輸出端口的數(shù)字設(shè)計(jì)。當(dāng)輸出端口大于一個(gè)時(shí),只能用 module。
  • UDP 是使用內(nèi)存中的查找表實(shí)現(xiàn)的,當(dāng)輸入端口較多時(shí),輸入端口的組合將會(huì)呈指數(shù)增長(zhǎng)。UDP 輸入端口的數(shù)量也會(huì)受到仿真器的限制。因此輸入端口較多時(shí)不宜使用 UDP。
  • 選擇使用 UDP 以后,一定要盡可能的用縮寫符完整的描述 UDP 狀態(tài)表。漏掉輸入的組合情況,輸出端可能會(huì)出現(xiàn) X 的狀態(tài),造成設(shè)計(jì)錯(cuò)誤。

點(diǎn)擊這里下載源碼


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

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)