自学内容网 自学内容网

sv标准研读第十章-赋值语句

书接上回:

sv标准研读第一章-综述

sv标准研读第二章-标准引用

sv标准研读第三章-设计和验证的building block

sv标准研读第四章-时间调度机制

sv标准研读第五章-词法

sv标准研读第六章-数据类型

sv标准研读第七章-聚合数据类型

sv标准研读第八章-class

sv标准解读第九章-进程

第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,且要满足下面的规则:

  1. 如果右边表达式是从非0变成0,那么生效的就是下降沿delay;
  2. 如果右边表达式是变成z态,那么生效的就是关断delay;
  3. 其他情况下,生效的都是上升沿delay

如果左侧是一个用户自定义nettype的net,或者net的数组,那么只能应用一个delay,只要net值发生改变,该delay就会生效。

声明net时添加delay的方式如下:

这种方式叫net delay,作用是当wireA发生变化时,实际生效的时间要在10个时间单位之后。

连续赋值delay和net delay的作用不同,前者的作用是右侧值变化时,与左边值变化之间的时间间隔。连续赋值delay作用的步骤如下:

  1. 计算右边表达式的值
  2. 如果右边的值和左边不一样,那么就会安排一个传播事件;
  3. 如果右边的值和左边一样,不会有事件安排;
  4. 如果有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评估有以下几个步骤:

  1. 左侧size和右侧size的决定法则参考11.8.1介绍;
  2. 如果右侧size小于左侧size,那么右侧值的size会填充到左侧size大小。如果右侧是unsigned,那么会进行0填充,如果右侧是signed,会进行符号位填充。
  3. 如果右侧size大于左侧size,那么会发生截断。MSB会被截断,工具要报warning或者error。如果符号位发生了截断,那么可以使得最终的结果的符号发生改变。

举例:

10.8 assignment-like contexts

assignment-like contexts指的是:

  1. 连续赋值或者过程赋值;
  2. 显式类型声明的参数:

Module、interface、program里的参数赋值;

Module、interface、program、class实例里被override 的参数值;

  1. Module、interface、program的input、output的端口连接;
  2. Function里的return语句;
  3. Tagged union表达式;

下面的语句不是assignment-like contexts:

  1. 静态cast;
  2. 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)!