• Verilog 时序逻辑 UDP


    时序逻辑 UDP 与组合逻辑 UDP 在定义形式和行为功能上均有不同,主要区别如下:

    • 1、时序逻辑 UDP 的输出端必须声明为 reg 型
    • 2、时序逻辑 UDP 可以用 initial 语句初始化
    • 3、状态表格式也稍有不同
      ...    :  <current_state>  :  <next_state>  ;
    • 4、时序逻辑 UDP 状态表每行由 3 部分组成:输入部分、当前状态和输出状态,用冒号":"隔开
    • 5、current_state 就是输出寄存器的当前值, next_state 就是输出寄存器的新值。next_state 由输入和 current_state 共同决定。
    • 6、状态表的输入项可以是电平,也可以是跳边沿的形式

    表示时序逻辑的 UDP 主要分为 2 种:电平触发 UDP 与 边沿触发 UDP

    电平触发 UDP

    电平触发 UDP 的输出是根据输入电平状态的改变而改变。

    带有清零端的 D 锁存器的功能描述为:

    • 清零端为 1 时,输出端恒为 0 ;
    • 清零端为 0 、使能控制端为 1 时,锁存器透明,输出端等于输入端;
    • 清零端为 0 、使能控制端为 0 时,锁存器呈保持状态,输出端保持不变。

    真值表为(q 表示当前状态,q+ 表示下一个状态):

    其实编写 UDP 的过程,可以理解为换一种格式编写真值表的过程。

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

    1. primitive d_latch(q, clear, en, d);
    2.    output       q ;
    3.    reg          q ;
    4.    input        d, en, clear ;
    5.    initial
    6.      q = 0 ;
    7.    table
    8.     //clear     en      d       :q      :q+ ;
    9.       1         ?       ?       :?      :0 ;    //clear
    10.       0         0       ?       :?      :- ;    //"-" means stable
    11.       0         1       0       :?      :0 ;    //q = d
    12.       0         1       1       :?      :1 ;
    13.    endtable
    14. endprimitive

    当然,也可以在罗列端口信号时就声明其类型,并且赋初值。

    1. primitive d_latch2(
    2.    output reg   q = 0,
    3.    input        clear, en, d);
    4.    ......
    5. endprimitive

    边沿触发 UDP

    边沿触发 UDP 的输出是根据输入跳边沿和(或)输入电平状态的改变而改变。

    直接给出带有异步复位端(RST)且在时钟下降沿采集信号的 D 触发器的"真值表":

    可见此"真值表"中还加入了上下沿的概念,是为了方便编写 UDP 代码。

    此 D 触发器的时序逻辑 UDP 描述如下:

    1. primitive D_TRI(
    2.             output reg  Q = 0,
    3.             input       RST, CP, D);
    4.    table
    5.     //RST       CP      D       :Q      :Q+ ;
    6.       //(1) 清零
    7.       1         ?       ?       :?      :0 ;  //RST=1 时清零
    8.       (??)      ?       ?       :?      :- ;  //忽略 RST 边沿变化
    9.       //(2) 时钟下降沿采集
    10.       0         (10)    0       :?      :0 ;  //时钟下降沿采集信号
    11.       0         (10)    1       :?      :1 ;
    12.       //possible negedge
    13.       0         (1x)    ?       :?      :- ;  //可能是时钟下降沿时保持
    14.       0         (x0)    ?       :?      :- ;
    15.       //(3) 时钟上升沿保持
    16.       0         (0?)    ?       :?      :- ;  //时钟上升沿时保持
    17.       //possible posedge
    18.       0         (x1)    ?       :?      :- ;  //可能是时钟上升沿时保持
    19.       //(4) 非时钟沿变化时,即便数据有跳变,输出仍然保持
    20.       0         ?       (??)    :?      :- ;  
    21.    endtable
    22. endprimitive // D_TRI

    对此触发器进行简单的仿真,testbench 描述如下。

    实例

    1. `timescale 1ns/1ps
    2. module test ;
    3.    reg  D, CP = 0 ;
    4.    reg  RST ;
    5.    wire Q ;
    6.    always #5 CP = ~CP ;
    7.    //data driver
    8.    initial begin
    9.       D = 0 ;
    10.       #12 D = 1 ;
    11.       #10 D = 0 ;
    12.       #14  D = 1 ;
    13.       #3  D = 0 ;
    14.       #18  D = 0 ;
    15.    end
    16.    //reset driver
    17.    initial begin
    18.       RST = 0 ;
    19.       #3        RST = 1 ;
    20.       #2        RST = 0 ;
    21.       #22       RST = 1 ;
    22.       #1        RST = 0 ;
    23.    end
    24.    D_TRI u_d_trigger(Q, RST, CP, D);
    25.    initial begin
    26.       forever begin
    27.          #100;
    28.          //$display("---gyc---%d", $time);
    29.          if ($time >= 1000) begin
    30.             $finish ;
    31.          end
    32.       end
    33.    end
    34. endmodule // test

    需要注意的是:

    状态表每行多个输入部分,最多只能有一个跳边沿,例如下面状态表的表述是错误的。

    1.    table
    2.       ......
    3.       (10)     (10)    1       :?      :1 ;
    4.    endtable

    电平触发的状态表输入项,其优先级高于边沿触发的状态表输入项。若两者在同一时刻出现,则输出端的状态由电平触发的状态表决定。

    例如上述 D 触发器中,RST 可以看做是电平触发,CP 可以看做是边沿触发。当 RST 上升沿与 CP 端下降沿同时刻来临时,输出端会变为 0 ,如下图 cap 时刻。当然,实际的时序应该避免时钟和复位边沿同时到来。

    边沿触发 UDP 中,必须为每一个输入信号都指定边沿变化时输出信号的变化情况,否则在该信号的跳变沿处可能会造成输出端为 X 。

    例如缺少 RST 边沿变化的说明:

        //(??)    ?       ?       :?      :- ; //忽略 RST 边沿变化

    则在 RST 下降沿输出会变为 x。

    再例如缺少时钟稳定、D 端数据变化时的说明:

    1. //(4) 非时钟沿变化时,即便数据有跳变,输出仍然保持
    2. //0 ? (??) :? :- ;

    则 D 端数据变化的边沿处也会使输出为 x。


    UDP 状态表符号缩写

    UDP 状态表的电平和跳变沿缩写符号及说明如下表所示。

    缩写符含义说明
    0, 1, x只能用于输入
    b1, 1只能用于输入
    -保持原值不变只能用于输出
    (ab)信号由 a 变 b用作输入端边沿的指示
    r(01)信号的上升沿
    f(10)信号的下降沿
    p(01), (0x) 或 (x1)可能是信号的上升沿
    n(10), (1x) 或 (x0)可能是信号的下降沿
    *(??)信号任意边沿的变化

    UDP 设计指导

    针对数字设计时是选择使用 module 还是 primitive,要从设计需求、复杂度等方面进行综合考虑。下面给出一些指导性的建议。

    • UDP 只能进行功能性建模,不能对电路时序和制造工艺(例如 CMOS,TTL等)进行建模。使用 UDP 的主要目的是以类似于真值表的简洁形式对数字设计进行建模,而 module 可以包含电路时序,并指定制造工艺。
    • UDP 只能完成有一个输出端口的数字设计。当输出端口大于一个时,只能用 module。
    • UDP 是使用内存中的查找表实现的,当输入端口较多时,输入端口的组合将会呈指数增长。UDP 输入端口的数量也会受到仿真器的限制。因此输入端口较多时不宜使用 UDP。
    • 选择使用 UDP 以后,一定要尽可能的用缩写符完整的描述 UDP 状态表。漏掉输入的组合情况,输出端可能会出现 X 的状态,造成设计错误。
  • 相关阅读:
    Clover引导都支持哪些.efi文件
    2022年密码测评理论与关键技术前沿论坛|海泰方圆分享密码应用改造典型方案
    Remote Sensing投稿经验分享
    [GXYCTF2019]禁止套娃 无回显 RCE 过滤__FILE__ dirname等
    Linux输入设备应用编程(键盘,按键,触摸屏,鼠标)
    Educational Codeforces Round 122 (Rated for Div. 2) D. Make Them Equal
    # 研究杂感 × 多元线性回归
    Linux文本处理三剑客(grep,sed,awk)
    从真实案例出发,全方位解读 NebulaGraph 中的执行计划
    力扣370周赛 -- 第三题(树形DP)
  • 原文地址:https://blog.csdn.net/qq_33300585/article/details/127944268