sv标准研读第十章-赋值语句
书接上回:
sv标准研读第三章-设计和验证的building block
第10章 赋值语句
10.1 大纲
本章主要内容:
1.连续赋值
2.过程阻塞赋值和过程非阻塞赋值
3.过程连续赋值(assign/deassign/force/release)
4.net混叠
10.2 概述
两种赋值形式:
1.连续赋值:给net/var赋值
2.过程赋值:给var赋值
连续赋值可以理解为连续驱动,过程赋值可以理解为将值放入变量中,因此过程赋值可以保存值。
过程连续赋值有两种:assign/deassign和force/release。
赋值表达式有以下要求:
在赋值语句中也可以添加delay,如下:
10.3连续赋值
特点:只要右边的值变化,就进行赋值
有两种连续赋值:net声明赋值和连续赋值语句
10.3.1 net 声明赋值
格式如下:
因为net只能声明一次,所以net声明时的赋值也只能出现一次。
Interconnect类型的net不能在声明时赋值。
10.3.2 连续赋值语句
连续赋值语句和net声明赋值的最大区别是:前者可以出现多次。
只要右边表达式的值改变,就会进行赋值操作。
Net可以被多次连续赋值驱动,也可以被原语output/module output/连续赋值混合驱动,但是var只能被驱动一次,否则会报错。
10.3.3 连续赋值delay
连续赋值里的delay表示的是右侧表达式值的变化和左侧赋值生效之前的时间;如果左边是一个标量net,此时delay的作用就相当于一个门电路delay,因此可以为上升沿、下降沿或者变成z态施加不同的delay。
如果左边是一个矢量net,那么最多只能施加3个delay,且要满足下面的规则:
- 如果右边表达式是从非0变成0,那么生效的就是下降沿delay;
- 如果右边表达式是变成z态,那么生效的就是关断delay;
- 其他情况下,生效的都是上升沿delay
如果左侧是一个用户自定义nettype的net,或者net的数组,那么只能应用一个delay,只要net值发生改变,该delay就会生效。
声明net时添加delay的方式如下:
这种方式叫net delay,作用是当wireA发生变化时,实际生效的时间要在10个时间单位之后。
连续赋值delay和net delay的作用不同,前者的作用是右侧值变化时,与左边值变化之间的时间间隔。连续赋值delay作用的步骤如下:
- 计算右边表达式的值
- 如果右边的值和左边不一样,那么就会安排一个传播事件;
- 如果右边的值和左边一样,不会有事件安排;
- 如果有delay,那么该传播事件会安排在delay对应的时间之后的将来。
10.3.4 连续赋值强度
连续分配的驱动强度可以由用户指定。这只适用于对标量net的赋值,但类型为supply0和supply1的net除外。
连续赋值驱动强度可以在net声明中指定,也可以使用assign关键字在独立赋值中指定。强度规格如有规定,应紧跟着关键字(net关键字或指定关键字),并在规定的任何延迟之前。每当连续赋值驱动net时,应按规定模拟值的强度。
驱动器强度规格应包含一个强度值,当赋值给net的值为1时适用,当赋值的值为0时适用第二个强度值。当赋值为1时,以下关键字应指定强度值:
当赋值为0时,以下关键字需要指定强度值:
两种强度规格的顺序可以任意。以下两条规则应约束驱动器强度规格的使用:
—强度规格(highz1, highz0)和(highz0, highz1)应被视为非法结构。
—如果不指定驱动器强度,则默认为(strong1, strong0)。
10.4 过程赋值
过程赋值发生在过程中,如always、initial(见9.2)、task和function(见第13章),可以被认为是“触发的”分配。当模拟中的执行流达到过程中的赋值时,触发器就会发生。到达赋值值可以通过条件语句来控制。事件控件、延迟控件、if语句、case语句和循环语句都可以用来控制是否对赋值进行求值。第12章给出了细节和例子。
过程赋值的右侧可以是任何求值的表达式,但是左侧的变量类型可以限制右侧的合法表达式。左边应该是一个从右边接受赋值的变量。过程赋值的左侧可以采用以下形式之一:
—单一变量,如第6.4节所述
—聚合变量,如第7节所述
—packed数组的bit select/part select
—unpacked数组的slice
SystemVerilog包含以下三种类型的过程性赋值语句:
-阻塞过程性赋值语句(见10.4.1)
-非阻塞过程性赋值语句(见10.4.2)
-赋值操作符(见11.4.1)
阻塞和非阻塞过程性赋值语句指定为阻塞和非阻塞过程性赋值语句,这些语句指定为阻塞和非阻塞过程性赋值语句。
10.4.1 阻塞过程赋值
阻塞过程赋值语句应该在顺序块中紧随其后的语句执行之前执行(参见9.3.1)。阻塞过程赋值语句不能阻止并行块中紧随其后的语句的执行(参见9.3.2)。
格式如下:
=符号可以用在阻塞过程赋值、过程连续赋值和连续赋值
阻塞过程赋值举例:
+=的作用见11.4.1
10.4.2 非阻塞过程赋值
作用:在同一个time slot如果要同时做几件事,且这几件事之间的执行顺序不固定,那么就可以使用非阻塞过程赋值。
语法:
非阻塞赋值的过程可以分为两个步骤,如下:
Step1:在c的上升沿,会在active域评估非阻塞赋值右侧表达式的值
Step2:在NBA域将右侧的值赋值给左侧表达式
加了延迟后的非阻塞赋值和加了延迟后的阻塞赋值有些许不同,如下:
上面加了延迟的3个非阻塞赋值都在同一个begin end块里,彼此之间不会阻塞,所以3个表达式右侧值的评估都在同一个time slot,即0时刻,而左侧表达式的赋值取决于各自delay,而和前面的语句没有关系。
如果同一个begin end块里用非阻塞赋值先后给同一个变量进行了赋值,那么该变量最终的值和代码顺序是有关系的,举例:
但是如果不同begin end块里用非阻塞赋值给同一个变量进行了赋值,那么该变量最终的值是不确定的,举例:
但是如果在不同begin end块里使用不同的delay,则结果是确定的,如下:
上面的例子中,第一个begin end块会在时刻8对该表达式做评估,但是在时刻12第二个beginend块会对该表达式做评估,因此会刷新8时刻的评估,因此,最后在时刻16, a的值为0。
10.5 变量声明赋值(变量初始化)
在声明时给变量赋值相当于给变量赋初始值,变量值的变化会持续到下一次赋值。且声明时的赋值要比任何initial块和always块执行的早。
10.6 过程连续赋值
过程连续赋值需要使用关键字:assign/force。对应的解除过程连续赋值的关键字是:deassign/release。
过程连续赋值的作用是:一旦右侧值发生了变化,左侧值立刻跟着变化。
10.6.1 assign和deassign
Assign赋值会override掉所有过程赋值,deassign则相反,会终止过程连续赋值。
Assign赋值语句的左侧可以是单一变量或者多个变量的{,}形式,但是不能出现bit-select或者part-select。
10.6.2 force和release
Force和release、assign和deassign这两组的区别是:前者操作的对象既可以是net也可以是var,而后者只能是var。
Force赋值语句的左侧可以是单一变量、单一net、变量/net的bit-select、变量/net的part-select或者{,}的形式,或者是使用nettype自定义的net。但是force/release语句的左侧不可以是被连续赋值和过程赋值同时作用的变量。
Force语句会override掉所有的赋值,包括assign的赋值,直到release语句解除。
10.7 赋值位宽拓展和截断
赋值左侧的size评估有以下几个步骤:
- 左侧size和右侧size的决定法则参考11.8.1介绍;
- 如果右侧size小于左侧size,那么右侧值的size会填充到左侧size大小。如果右侧是unsigned,那么会进行0填充,如果右侧是signed,会进行符号位填充。
- 如果右侧size大于左侧size,那么会发生截断。MSB会被截断,工具要报warning或者error。如果符号位发生了截断,那么可以使得最终的结果的符号发生改变。
举例:
10.8 assignment-like contexts
assignment-like contexts指的是:
- 连续赋值或者过程赋值;
- 显式类型声明的参数:
Module、interface、program里的参数赋值;
Module、interface、program、class实例里被override 的参数值;
- Module、interface、program的input、output的端口连接;
- Function里的return语句;
- Tagged union表达式;
下面的语句不是assignment-like contexts:
- 静态cast;
- Module、interface、program的inout、ref端口
10.9 赋值patterns
赋值pattern指的是赋值语句结构里的某些单元。
10.9.1 数组assignment patterns
此时需要使用{}拼接符,且拼接的元素个数要和数组的维度匹配。还可以使用重复操作符,如下:
还可以写上default值,如下:
在结构体里,数据类型可以是不一样但match的多个数据,如下:
10.9.2 结构体assignment patterns
结构体在赋值时,既可以按照位置赋值,也可以按照名字赋值,举例:
还可以不依据位置和名字给结构体里的元素赋值,此时需要使用关键字default,如下:
10.10 unpacked 数组拼接
10.10.1 unpacked数组拼接和数组赋值patterns的比较
写法不同,举例:
数组赋值pattern里的元素不允许出现自定义的数据类型,但是unpacked数组拼接允许;unpacked数组拼接不允许出现重复操作符,而数组赋值pattern里允许。如下:
10.10.2 其他使用拼接操作符的结构之间的关系
在向量拼接和字符串拼接过程中都可以使用拼接操作符。举例:
10.10.3 unpacked数组拼接的内嵌
举例:
上面最后一句的效果就会变成:
10.11 net aliasing
作用是给net声明多个不同的名字。
Alias语句可以用于双向短路连接模型中,在这样的模型中,所有信号都可以共享相同的物理nets。
下面的例子展示了使用alias实现A和B之间的byte序交换
使用alias的各个成员和packed union一样,每个成员都必须有相同的size,且类型兼容。Alias只对net适用,对var和层次引用不适用。
相同的nets可以出现在不同的alias语句中,作用是累积的。举例:
上面这两种写法的作用是一样的,即high12[7:0]和low12[11:4]共享wire。
但是,在alias语句中不允许出现alias多次,例如下面的例子在msb4bit和lsb4bit就出现了多次,是非法的语句:
也不能和自己alias,如下也是非法的:
原文地址:https://blog.csdn.net/yunduor909/article/details/142716025
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!