目录
用户定义原语
UDP定义
UDP状态表
状态表符号
组合UDP
电平敏感UDP
沿敏感时序UDP
参考《Verilog 编程艺术》魏家明著
用户定义原语
用户定义原语(User-defined primitive,UDP)是一种模拟硬件技术,可以通过设计新的原语单元扩大门原语集合。UDP可以和门原语一样使用,用于表示要模拟的电路。
UDP分为两种:
1.组合UDP:使用输入值决定下一个输出值。
2.时序UDP:使用输入值和当前值决定下一个输出值,他可以模拟边沿敏感和电平敏感的行为,所以可以用来模拟触发器和锁存器。
每个UDP只能有一个输出,只能有3种状态:0,1和x。不支持z,如果输入值是z,那就就被当作x。对于时序UDP,输出值总是和内部状态保持一致。
UDP定义
UDP的定义独立于模块,它们和模块定义具有同样的语法层次,不能出现在关键字 module 和 endmodule 之间。
1.使用 primitive 和 endprimitive 定义UDP
2.使用与模块一样的方式声明端口和内部变量
3.使用内部状态表(State table)模拟UDP行为
4.UDP的实例化与模块的实例化类似,但是实例名是可选的,还可以使用延迟值。
UDP状态表
用于定义UDP的行为
1.状态表处于关键字 table 和 endtable 之间,每一行要用分号 ;结束。
2.状态表的每一行都由一些字符组成,用于指出输入值和输出状态,支持0,1和x,不支持z。
3.状态表每一行输入状态的顺序要和UDP端口列表的顺序保持一致。
4.对于组合UDP,输入信号一个区,输出信号一个区,输入区和输出区要用:分开。每一行用于定义在特定输入下的输出
5.对于时序UDP,在输入区和输出区之间要插入一个附加区。附加区用于表示当前UDP的状态,等价于当前输出值。这三个区同样用:分开。每一行用于定义在当前状态和特定输入组合下的输出。
6.如果所有输入都是x,那么输出值也是x。
7.没有必要清晰地列出所有输入组合,因为对于没有列出的输入组合,输出值默认x
8.不能对同样输入值的组合指定不同的输出值。
状态表符号
组合UDP
primitive tsmc_mux(q, d0, d1, s);
output q;
input d0, d1, s;
table
// d0 d1 s q
0 ? 0 : 0;
1 ? 0 : 1;
? 0 1 : 0;
? 1 1 : 1;
0 0 X : 0;
1 1 X : 1;
endtable
endprimitive
电平敏感UDP
与组合UDP的行为类似,只不过输出是reg类型,而且状态表表中要增加一个附加区。附加区用于表示当前UDP的状态,输出区用于表示UDP的下一个状态。
例子:简单的latch
primitive simple_latch(q, clock, data);
output reg q;
input clock, data;
table
//clock data q q+
0 1 : ? : 1;
0 0 : ? : 0;
1 ? : ? : -;
endtable
endprimitive
例子: 带有复位和置位的Latch
primitive complex_latch(q, d, e, cdn, sdn, notifier);
output reg q;
input d, e, cdn, sdn, notifier;
table
1 1 1 ? ? : ? : 1;
0 1 ? 1 ? : ? : 0;
0 (10) 1 1 ? : ? : 0;
1 (10) 1 1 ? : ? : 1;
* 0 ? ? ? : ? : -;
? ? ? 0 ? : ? : 1;
? 0 1 * ? : 1 : 1;
1 ? 1 * ? : 1 : 1;
1 * 1 ? ? : 1 : 1;
? ? 0 1 ? : ? : 0;
? 0 * 1 ? : 0 : 0;
0 ? * 1 ? : 0 : 0;
0 * ? 1 ? : 0 : 0;
? ? ? ? * : ? : x;
endtable
endprimitive
沿敏感时序UDP
1.表中每一行最多只能有一个输入信号发生变化,(01) (10) 0 : 0 : 1,非法
2.对于所有没有指明的转换,输出默认为x
3.对于所有不改变输出状态的转换都要清晰的指明,否则就会导致输出变成x
4.如果时序UDP对每个输入的沿都敏感,那么这些沿在表中都要列出来
5.对于时序UDP,可以使用initial语句给输出状态一个初始值。
例子:简单的触发器
primitive simple_dff (q, clock, data);
output reg q;
input clock, data;
table
//clock data q q+
// obtain output on rising edge of clock
(01) 0 : ? : 0;
(01) 1 : ? : 1;
(0?) 1 : 1 : 1;
(0?) 0 : 0 : 0;
// ignore negative edge of clock
(?0) ? : ? : -;
// ignore data changes on steady clock
? (??) : ? : -;
endtable
endprimitive
UDP允许把沿敏感和电平敏感混合在一起使用。当输入变化时,沿敏感的变化先处理,电平敏感的变化后处理,所以当沿敏感和电平敏感的变化得出不同状态时,最后结果由电平敏感变化的结果决定。
例子:复杂JK触发器
primitive complex_jk_ff(q, clock, j, k, preset, clear);
output reg q;
input clock, j, k, preset, clear;
table
// clock jk pc state ouptut/next state
? ?? 01 : ? : 1;
? ?? *1 : 1 : 1;
? ?? 10 : ? : 0;
? ?? 1* : 0 : 0;
x 00 00 : 0 : 1;
x 00 11 : ? : -;
x 01 11 : ? : 0;
x 10 11 : ? : 1;
x 11 11 : 0 : 1;
x 11 11 : 1 : 0;
f ?? ?? : ? : -;
b *? ?? : ? : -;
b ?* ?? : ? : -;
endtable
endprimitive