Verilog语法回顾--用户定义原语

目录

用户定义原语

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.状态表的每一行都由一些字符组成,用于指出输入值和输出状态,支持01x,不支持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

  • 14
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值