如何在 systemverilog 中的相同扩展 类 之间进行向下转换?

How to do Down casting between same extended classes in systemverilog?

我正在尝试了解 uvm 中相同扩展 class 之间的情况,如下例所示,

  module test_module ();
  
class A; endclass
class B extends A; endclass
class C extends A; endclass

A a_h;
B b_h;
C c_h;

  initial begin

    c_h = new();
    b_h = c_h;
    $cast(c_h, b_h); 
  end
endmodule : test_module

我得到了 xrun:20.09-s003:(c) 版权所有 1995-2020 Cadence Design Systems, Inc. b_h = c_h; | xmvlog: *E,TYCMPAT (testbench.sv,20|12):赋值运算符类型检查失败(预期数据类型与 'class test_module::B' 兼容,但发现 'class test_module::C')。 错误信息。

我认为 b_h 和 c_h 由相同的 class 扩展。

但是 b_h 和 c_h 不一样 class 类型所以。

我分配b_h = c_h;

但是为什么赋值会出错?

你有以下方案:

     /--->B
A--->
     \--->C

A 和 B 或 A 和 C 之间存在直接依赖关系(A 是 B 和 C 的超类)。 B和C之间没有直接依赖关系。

因此您可以轻松做到:

a_h = b_h; // no casting needed to assign to superclass-A-type
$cast(b_h, a_h); // you need a cast to upcast the base pointer.

但是无法转换 $cast(b_h, c_h),因为它们不相关。

更正式:

When $cast is applied to class handles, it succeeds in only three cases:

  1. The source expression and the destination type are assignment compatible, that is, the destination is the same type or a superclass of the source expression.
  2. The type of the source expression is cast compatible with the destination type, that is, either: — the type of the source expression is a superclass of the destination type, or — the type of the source expression is an interface class (see 8.26) and the source is an object that is assignment compatible with the destination type. This type of assignment requires a run-time check as provided by $cast.
  3. The source expression is the literal constant null.

如果您在示例中添加 class 属性,会更容易理解您的问题。

module test_module ();
  
 class A; int p1; endclass
 class B extends A; int p2; endclass
 class C extends A; int p3; endclass

  A a_h;
  B b_h;
  C c_h;

  initial begin

    c_h = new();  
    b_h = c_h;       
    $cast(c_h, b_h);
  end
endmodule : test_module

语句 c_h = new(); 构造了一个具有 p1p3 属性的 class 对象。所以你应该能够引用 c_h.p1c_h.p3。您可以根据 class 变量的类型在 class 对象中引用任何 属性。

class 变量 b_h 允许您访问 b_h.p1b_h.p2。但是,如果您被允许执行语句 b_h = c_h; 然后尝试引用 b_h.p2,那将是一个问题,因为您放置在 b_h 中的对象从未构造过 p2 属性.

您的示例从不引用 p2 并不重要;编译器永远不会允许赋值。如果它们是相同的 class 类型,或者从扩展类型到基本类型 (upcast),则只能从一个 class 变量直接赋值给另一个变量.