UDP-User Defined Primitives
在使用Verilog构建模型时除了可以使用Verilog提供的大量内置基本门之外,用户还可以使用大量的自定义有用户特点的原语,即自定义原语(UDP:User Defined Primitive)这些原语的结构和使用方法与基本门类似。在构建原语时需要注意,UDP只能有一个输出端口,可以有一个或者多个输入,其中可以使用的状态只有三种“0,1,x”,如果输入端口出现了“z”,那么在原语内部该值将被当做“x”处理。常用的自定义原语可以分为两类:
-
组合逻辑UDP:输出由输入决定;
- 时序逻辑UDP:输出由输入和当前输出状态决定;
1 UDP基本概念
1.1 UDP的定义
UDP与module在Verilog中处于同一级别,不依赖于其他module的定义,即UDP不能再module中定义(即不能出现在“module-endmodule”之间),但是可以像module一样在其他地方定义然后被例化引用。
1.2 UDP格式
在具体使用和定义UDP时需要注意以下几点:
-
UDP只能包含一个输出端口和多个输入端口(时序逻辑UDP最多可以有9个输入端口,组合逻辑UDP最多可以有10个输入端口);
-
UDP中不存在双向端口,即端口列表中不存在inout;
-
UDP端口都是标量类型,不能是向量类型;
-
时序逻辑UDP必须对输出端口增加reg类型声明,组合逻辑UDP中不能出现reg声明;
-
时序逻辑UDP可以包含“initial-end”用来对输出端口初始化;
-
UDP的行为是通过“table-endtable”描述的,表格中描述的行为符号来自UDP符号表(下文给出),table的输入与UDP端口列表中输入端口的顺序一致,切记不是端口声明顺序;
-
table中如果没有对应匹配的输入组合模式,则输出“x”;
-
table中相同的输入如果对应不同的输出是矛盾非法的;
-
UDP的例化类似于其他Verilog中内置的基本门,例化名可有可无;
-
符号汇总
符号 | 意义 | 备注 |
0 | 逻辑0 | |
1 | 逻辑1 | |
X | 未知值 | 可以出现在输入和当前状态中 |
? | 0、1或者x | 不允许出现在输出域 |
b | 0或者1 | 同上 |
- | 保持不变 | 只能出现在输出域 |
(ab) | 由a变化到b | a和b只能为“0、1、x、b、?”,只能出现在输入域 |
* | 与(??)相同 | 输入的任何变化 |
r | 上跳沿与(01)相同 | 上升沿变化 |
f | 下调沿与(10)相同 | 下降沿变化 |
p | (01)、(0x)或者(x1) | 上升沿变化 |
n | (10)、(1x)或者(x0) | 下降沿变化 |
2 组合逻辑UDP
组合逻辑UDP的输出由当前的输入决定,当输入状态发生变化时,UDP根据变化的值在UDP中定义的table中查找对应的状态,从而产生对应的输出,当table中没有对应的状态,那么输出为“x”。其中table格式如下:
【示例】
仿真结果如下:
输入b和c为不定态时,因为table中并没有对应的状态,所以输出为不定态;
当输入b为1,c为不定态时,因为table中存在对应状态“1 ?”,所以输出位“1”;
当输入b和c均为“1”时,因为table中存在对应状态,所以输出为“1”,注意此时有两个条件同时满足,但是两个条件的输出是一致的,所以不会报错;
3 时序逻辑UDP
3.1 电平敏感UDP
电平敏感UDP的行为描述与组合逻辑类似,只是电平敏感UDP输出需要声明为reg类型,且在table中增加了一列当前状态域。这里需要注意这个当前状态域位于table的输入与输出之间,它代表的是一个UDP中的内部状态,因为是时序元件,所以这里可以将这个当前状态理解为上一仿真时间槽最后输出的数据,而当前时间槽最后的输出由table最后一列的状态表示。
【示例】
仿真结果如下:
data为“x”时,因为此时clk为“0”,table中没有对应的状态,所以输出为“x”;
当clk从“0”变为“1”,data此时仍然为“x”,满足table中最后一行,此时输出保持之前的状态不变,即“x”;
当clk和data都为0时,满足table中第二行,此时输出变为“0”;
3.2 边沿敏感UDP
边沿敏感UDP的输入在table中转换成了输入的变化,该变化的描述方式为将变化状态置于一对小括号中。这里需要注意,任何未指定的状态对应的输出均为不定态,建议在table中实现所有的变化状态,否则对于不存在的状态输出将会出现“x”。
【示例】
仿真结果如下:
输入均为“0”时,因为table中没有对应状态,所以输出为“x”;
当clk从“0”变为“1”,时,如果data在此时为“0”,则输出为“0”,如果data_在此时为“1”,则输出为“1”
当clk从“0”变为“x”,如果data在此时为“1”,则输出为“1”,如果data在此时为“0”,则输出为“0”(这里需要注意这时的data为上次操作保存在data中的值),仿真波形在6ns处保存在输出的数据位1,在9ns处,clk再次从“0”变为“x”,虽然在7ns处对data进行了更改,但是table中最后一行状态表示此时输出保持之前状态,所以q的当前状态为6ns操作完了之后保存在其中的值“1”,即此时table中第四行状态中的当前状态“0”并没有满足,所以在9ns处输出的值为“x”;
这里需要注意,在table中所有的输入跳变在一行只能出现一次,即如果table中出现下述情况,仿真器将报出非法操作:
3.3 混合UDP(边沿与电平混合)
混合时序UDP包含边沿敏感UDP和电平敏感UDP的特征,例如经常使用的带有置位或者清零功能的触发器等。下例为带有清零功能的UDP描述。
仿真结果如下:
3.4 时序UDP中的initial
时序逻辑UDP中的initial用于对输出的初始化,但是后续电路触发的输入状态在table中没有对应的状态,那么初始化后的输出会被修改为不定态,除非状态表中明确保持之前状态。这里还需要注意UDP中的initial和module中initial的区别,如下表:
UDP | module |
仅有一条过程性赋值语句,因为UDP只有一个输出 | 可以有多条赋值语句 |
被赋值的reg类型变量与输出端口名同名 | 可以给任何reg类型变量赋值,不局限于输出等 |
过程性赋值语句中被修改变量只能是一位变量,其值只能是“1'b0,1'b1,1'bx” | 过程性赋值语句中被修改的变量可以是任何大小或者数值 |