【SystemVerilog】 $cast动态强制类型转换

前言

会经常用到$cast,但因为一直没理解透彻,每次使用都得现找内容再消化。今天自己重新总结整理一下。

强制类型转换

我们可以使用强制类型转换操作符(')来改变一个表达式的数据类型。需要进行强制类型转换的表达式必须包含在圆括号内,或者必须包含在串联或复制花括号内,并且它们必须是自决的。

int'(2.0*3.0);
shortint'{8'hFA,8'hCE};

如果将一个正的十进制数作为数据类型,那么这意味着需要改变数据的位数。

17'(x - 2);

数据的符号也可以改变。

signed'(x);

也可以使用用户定义的数据类型。

mytype'(foo);

变量/数据类型的$cast动态强制类型转换

在由于不同的数据类型而导致变量不能正常赋值的情况下, SystemVerilog提供了$cast系统任务来进行赋值操作。$cast可以作为任务或函数来调用。

$cast的语法如下:

function int $cast(singular dest_var, singular source_exp);
或者
task $cast(singular dest_var, singular source_exp);

dest_var是需要赋值的变量,source_exp是将要赋值到目的变量的表达式。

将$cast 作为任务还是函数调用确定了无效赋值是如何处理的
当作为任务调用时, $cast 试图将源表达式赋值给目的变量。如果赋值是无效的,会出现运行时错误并且目的变量保持不变。
当作为函数调用时, $cast 试图将源表达式赋值给目的变量,如果赋值成功则返回 1。如果赋值失败, $cast 不会进行赋值操作而是返回 0。当作为函数调用时,不会出现运行时错误,并且目的变量保持不变。
必须注意: $cast 执行的是运行时检查。除了检查目的变量和源表达式是否为单一类型外,编译器不会进行类型检查。

例如:

typedef enum {red, green, blue, yellow, white, black} Colors;
Colors col;
$cast(col, 2+3);

这个例子将表达式(5, black)赋值给枚举类型。如果不使用$cast 或者下面描述的静态编译时强制类型转换,这种类型的赋值是无效的。
下面的例子显示了如何使用$cast 检查一个赋值操作是否成功:

if (!$cast(col, 2+8)) // 10: 无效的强制类型转换
$display("Error in cast");

作为一种选择,前一个例子还可以使用静态 SystemVerilog 强制类型转换操作符来进行类型转换,例如:

col = Colors'(2+3);

然而,这是一种编译时的强制类型转换,也就是说,它在运行时总是成功的,并且即使表达式不在枚举值的范围之内,它也不会提供错误检查或警告。

这两种类型的强制类型转换为用户提供了完全的控制能力。如果用户知道将某个表达式赋值给一个枚举变量是安全的,那么可以使用较快的静态编译时强制类型转换。如果用户需要检查表达式是否位于枚举值范围内,那么用户没有必要手工编写一个冗长的开关语句,通过使用$cast 函数,编译器自动提供了这种功能。通过这两种类型的强制类型转换,用户能够控制时间和安全性之间的平衡。
 

类句柄的强制类型转换

将一个子类变量赋值给层次树中较高的类变量是合法的。将一个超类变量直接赋值给一个子类变量则是非法的。然而,如果超类句柄引用了指定子类的句柄,那么将一个超类句柄赋值给一个子类变量则是合法的。为了检查赋值是否合法,需要使用动态强制类型转换函数$cast。

语法和上面数据类型强制转换一样:

task $cast(singular dest_handle, singular source_handle);
或者
function int $cast(singular dest_handle, singular source_handle);

类句柄的转换涉及到父类和子类。可以想象一下,父类和子类相当于一个金字塔,父类在塔尖,只占一部分,子类继承父类在塔底。父类站的高,子类在底下。

从父类向子类的转换称为向下类型转换 (即 child_handle = father_handle,直接这样复制是不行的)。反之则称为向上类型转换(即 father_handle = handle_handle)

         $cast 则是用于向下类型转换。在向下类型转换时,只有当父类指针/句柄指向的对象和待转换的类型一致时,cast才会成功。

【注】:这里的向上和向下有时候理解的有点儿绕,我们只要记住源是父类,目的是子类,即,父类赋值给子类,就是从上往下,就是向下转换。反之是向上。
​​​​​

  • 类型向上转换: 将扩展类句柄(child_handle) 赋给 基类(father_handle)

        father_handle = child_handle

        向上类型转换没问题,可以直接将父类句柄指向子类对象。

base_clase   bc;
sub_class    sc = new();
bc = sc;               //父类句柄指向子类对象,这是正确的
  • 类型向下转换 :将父类句柄(father_handle) 赋给 扩展类(child_handle)

        child_handle = father_handle

        只有父类句柄指向的对象是真正的子类对象时,可以用$cast使新的子类句柄指向该子类对象。

base_class bc;
sub_class   sc;
bc = new();
sc = bc;                // 子类句柄指向父类对象(这是错误的);
$cast(sc,bc);           // 此时通过cast方式仍然不行;

base_class bc;
sub_class  sc1,sc2;
sc2 = new();
bc = sc2;
sc1 = bc;        // 不行
$cast(sc1,bc);   // 通过cast方式可以实现,可以看到bc的句柄类型虽然是父类,但其指的对象类型是子类

你可能感兴趣的:(SV,开发语言)