打造IC人才
科技生态圈

SystemVerilog中的类型转换有哪些?

发布时间:2022-09-28

来源:IC修真院

在SystemVerilog中,经常会用到$cast对数据类型进行转换,其实在实际使用过程中除了这种明摆着的数据类型转换外,SystemVerilog中还有一些“隐性”的数据类型转换,本文将通过示例说明SystemVerilog中的数据类型转换。

在SystemVerilog中,类型按照的兼容性分为5各层级,分别是匹配(matching)、相同类型(equivalent)、赋值兼容(assignment compatible)、转换兼容(cast compatible)和不相同类型(non-equivalent),其中匹配、相同类型其实也属于赋值兼容的一部分,所有的赋值兼容和所有的可以使用显式转换的不相同类型都属于可转换类型。

因此,可以知道,其实隐式转换主要存在于匹配和相同的数据类型之间,而显式转换存在于其他不同数据类型或者赋值兼容的数据类型之中。而隐式数据类型转换,显式数据类型转换的主要区别是转换是否“肉眼可见”,隐式转换一般会“静默”完成,而显式需要用户使用特殊的语法结构才能实现,下面通过示例具体看看两种转换的用法。

01 隐 式 转 换

隐式转换一般情况下下表中的数据类型变量相互之间进行赋值时会自动完成类型转换的,例如四值逻辑变量和二值逻辑逻辑变量之间的相互赋值、不同位宽变量之间的相互赋值等等。

隐 式 转 换

【示例】

2

【仿真结果】

3

示例中,将var4赋值为不定态之后在赋值给var3,虽然var4具有四值数据类型,但是因为var3是二值数据类型,当var4赋值给var3时,其中的不定态自动转换为了0,这个转换过程是隐式自动完成的。var2是一个byte类型,为有符号数,示例中其最高位为1,因为var4位宽比var2宽,所以再将其赋值给var4时,需要对高位进行补位操作,这时的补位操作将根据var2最高位的特点进行补位,并且这个过程是隐式自动完成的。其实在进行具有上表中数据类型特点的数据进行隐式数据类型转换时,为了避免这种“悄无声息”的转换发生,需要注意进行操作的数据对象的以下几点:

ü操作数的位宽;

ü操作数的符号特性;

ü操作数的数据类型;

02 显 式 转 换

显示的类型转换主要有两种方式,格式分别如下:

显 式 转 换

静态转换一般发生于编译阶段,在编译阶段完成类型的检查,而动态转换一般位于仿真运行阶段。下面将分别对两种转换进行示例说明。

2.1 static静态转换

静态转换不会对转换值做检查,在编译阶如果发生转换失败则会报错,但是对于一般的“integer data types”之间在转换是产生的截位等问题则不会有相应的警告信息。

【示例】

4

【仿真结果】

5

示例中,企图将packet通过静态转换为int型,此时在代码编译阶段已经报错,即不支持将class对象转换为int型变量,其实在SystemVerilog中class对象不支持这种转换,基本上所有的不以连续位方式进行存储的变量在使用静态转换是都会报错。关于具体转换可查阅IEEE1800相关章节内容。下面我们将分别示例常用的静态转换都有哪些。

2.1.1 类型转换

在SystemVerilog中,可以通过静态转换完成一些赋值兼容的数据类型之间转换,如果转换的数据类型赋值不兼容,将会产生一些不期望的结果,特别是在枚举类型和数据流中。数据类型转换的语法格式如下:

casting_type’(expression)

【示例】

6

【仿真结果】

7

示例中,给int型变量赋值为十进制64,然后通过”string’(vart)”的方式将整数值64转换成字符,此时的仿真结果将按照ASCII码表中整数64对应的字符进行显示,显示的结果字符为”@”,在示例中实现了整数类型与字符串类型的转换,当然也可以进行其他数据类型之间的转换,但是需要注意转换数据类型的赋值兼容性以及数据位宽和符号特性等问题,否则转换后的结果可能与期望不一致,所以,从安全性考虑,进行建模时尽量采用统一的数据类型之间的相互操作,尽量避免不同数据类型之间的相互转换。

2.1.2位宽转换

在SystemVerilog中可以将一个表达式结果的位宽转换为指定的位宽,这里需要注意不要转换的表达式位于括号中,要转换为的位宽必须为正数,不能为0或者负数。其语法格式如下:

dst_size’(expression)

【示例】

8

【仿真结果】

9

示例中src_vector是8位宽,通过10’(src_vector)将src_vector位宽转换为10位宽。当然示例中的src_vector为无符号数,无符号数在位宽扩展时高位补0,如果src_vector为有符号数,那么此时将src_vector转换成宽位宽的数时,此时需要注意该有符号数的符号位,此时的补位将会按照符号位进行补位,如下例。

【示例】

10

【仿真结果】

11

示例中src_vector是8位宽byte有符号数,通过10’(src_vector)将src_vector位宽转换为10位宽,此时因为src_vector为有符号数,所以此时转换时高位补位使用了其符号位进行了补位,结果为10’b11_1010_1010。

2.1.3符号转换

除了示例中通过静态转换可以转换表达式结果位宽外,在SystemVerilog中还可以通过指定符号特性影响表达式结果的符号特性,其使用格式如下:

signed’(expression) 和unsigned’(expression)

【示例】

12

【仿真结果】

13

示例中,value0为有符号数,并且初值为”-8”,首先将该数以二进制和十进制方式分别显示,然后通过unsigned将value0的符号特性转换为无符号数,并且通过二进制和十进制方式分别显示,显示结果中,因为value0为32位数,所以改变后其二进制显示将会保留未改变符号特性时数据在内存中的存储格式,但是此时十进制显示的结果就是该数转换为无符号数后对应的结果。其实除了上述使用静态转换实现符号特性的转换外,在SystemVerilog中还可以通过系统函数$signed和$unsigned实现一样的功能,再次就不再赘述了,大家可以将示例中的代码进行替换仿真。

2.2 dynamic动态转换

在SystemVerilog中,与静态转换对应的是动态转换,动态转换可以通过使用系统方法$cast实现数据类型的转换,这个动态转换的过程相较于静态转换主要区别在于该转换和检查发生在仿真运行阶段。同时$cast在SystemVerilog中有两种存在形式,这两种形式的格式如下:

function int $cast(singular dest_var,singular src_exp);

task $cast(singular dest_var,singular src_exp);

两种形式实现的功能都是将源表达式src_exp转换给目标变量dest_var,那么既生瑜何生亮,实现的功能都一样,在具体使用时仿真工具或者用户如何知道使用的是$cast的那种形式呢?下面我们通过示例说明两者使用上的差异。

2.2.1 $cast作为任务task

【示例】

14

【仿真结果】

15

示例中,虽然子类scobj是从父类cobj拓展派生而来的,两个属于不同的类型,但是父类句柄是可以直接指向子类对象,子类句柄是不能直接指向父类对象的(关于句柄之间类型转换可参考《硅心思见:【113】SystemVerilog中不同句柄之间的动态类型转换》)。本示例中企图通过$cast将子类句柄sp指向父类句柄指向的对象(此时父类句柄指向对象的类型为cobj),并且代码的编译已经通过,但是在程序运行时调用$cast时,检测类型不匹配,仿真器直接报错停止,并且给出报错信息。可以看到,示例中$cast的用法与task相同,都没有返回值,仿真器会根据该方法使用的上下文确定该方法按照task进行解析。

2.2.2 $cast作为函数function

【示例】

16

【仿真结果】

示例中,两次调用$cast,都将$cast赋值给了tmp,即此时$cast有返回值,根据上下文可以此时$cast被作为一个有返回值的方法,此时的$cast被仿真器按照function解析处理。第一次调用$cast时,因为子类句柄sp指向父类句柄p指向的对象(因为此时父类句柄指向对象的类型为cobj),当仿真运行调用$cast时检测到类型不匹配,函数返回0给tmp,条件判断语句根据tmp值执行了对应分支的$display语句,同时我们注意到仿真并没有因为这次不匹配报出任何提示信息和停止仿真;第二次调用$cast时,因为句柄p指向子类句柄sp指向的对象(父类句柄可以直接指向子类对象),当仿真运行调用$cast时检测到类型匹配兼容,函数返回1给tmp,条件判断语句根据tmp值执行了对应分支的$display语句。

通过上述示例可以汇总如下几点:

ü当将$cast作为任务使用时,如果源对象的数据类型与目的对象的数据类型不匹配不兼容仿真时会报错,并且仿真停止;

ü当将$cast作为函数使用时,如果源对象的数据类型与目的对象的数据类型不匹配不兼容仿真时,该函数仅返回值0,并且仿真不会停止也不会给出任何提示,如果类型兼容匹配,转换成功,那么函数返回非零值;

ü$cast具体作为函数还是任务,取决于用户在编码时按照如何的方式对$cast进行使用,如果期望类型不匹配不兼容时能够给出信息并且停止仿真,那么用户应该像任务一样使用$cast,如果想根据类型转换的结果进行特定的操作并不自动停止时,那么用户应该像函数一样使用$cast。


推荐阅读

换一换