SystemVerilog 中的 :: 作用域解析运算符详解--deepseek讲解

class Factory;

static bit use_err = 0;

static function Component create_driver(string n, Component p);

if (use_err)

return new ErrDriver(n, p);

else

return new Driver(n, p);

endfunction

endclass

module tb;

initial begin

Component env = new("env", null);

Component drv;

Factory::use_err = 0;

drv = Factory::create_driver("drv", env);

drv.show(); // Driver: drv

Factory::use_err = 1;

drv = Factory::create_driver("drv", env);

drv.show(); // ErrDriver: drv

end

endmodule

我最近在琢磨uvm,systemverilog中有些语法不太熟悉, 为什么Factory::use_err这样写?::是什么时候使用,Factory::create_driver;说明一下哈,可以举一些例子强化一下这个薄弱项吗,老师,感谢您啦,

SystemVerilog 中的 :: 作用域解析运算符详解

一、:: 是什么?

:: 叫做 作用域解析运算符(scope resolution operator) 。它的作用是:告诉编译器"我要访问的是某个类/包/接口里面的东西",而不是当前作用域里的东西。

你可以把它理解成 C++ 里的 ::,或者 Java 里的 类名.静态成员,或者 Python 里的 类名.类属性

格式:

text

Copy

Download

复制代码
类名::成员名
包名::成员名

二、为什么 Factory::use_err 要这样写?

看你的代码:

systemverilog

Copy

Download

复制代码
class Factory;
  static bit use_err = 0;                    // 静态变量

  static function Component create_driver(...);  // 静态方法
    if (use_err) ...
  endfunction
endclass

注意两个关键字 static

  • static bit use_err ------ 这是类级别的变量,不属于任何一个对象,整个类只有一份。

  • static function create_driver ------ 这是类级别的方法,不需要 new 出对象就能调用。

对于 static 成员,你不需要、也不应该通过对象去访问 ,而是通过类名去访问。怎么把"类名"和"成员"连起来?就用 ::

systemverilog

Copy

Download

复制代码
Factory::use_err = 0;          // 直接改类里的静态变量
drv = Factory::create_driver(...);  // 直接调类里的静态方法

对比一下 :如果是非静态成员,你就得先 new 一个对象,用 . 访问:

systemverilog

Copy

Download

复制代码
Factory f = new();
f.use_err = 0;          // 非静态才这么写
f.create_driver(...);   // 非静态才这么写

所以简单记:

  • . → 通过对象访问(实例成员)

  • :: → 通过类/包名访问(静态成员、类型、参数等)


三、:: 的常见使用场景(举例强化)

场景 1:访问静态变量 / 静态方法

systemverilog

Copy

Download

复制代码
class Counter;
  static int count = 0;

  static function void inc();
    count++;
  endfunction
endclass

module tb;
  initial begin
    Counter::inc();              // 不需要 new
    Counter::inc();
    $display("count = %0d", Counter::count);  // 输出 2
  end
endmodule

这跟你的 Factory 例子一模一样。


场景 2:访问类里的 typedef / enum / parameter

类里面定义的类型、枚举、参数 ,也要用 :: 访问:

systemverilog

Copy

Download

复制代码
class Packet;
  typedef enum {READ, WRITE} cmd_e;   // 类内定义的类型
  parameter int WIDTH = 8;            // 类内参数
endclass

module tb;
  initial begin
    Packet::cmd_e c;                  // 用 :: 引用类型
    c = Packet::WRITE;                // 用 :: 引用枚举值
    $display("WIDTH = %0d", Packet::WIDTH);
  end
endmodule

这在 UVM 里非常常见,比如:

systemverilog

Copy

Download

复制代码
uvm_phase::uvm_phase_type
uvm_object::type_id

场景 3:访问包(package)里的内容

:: 也用于 。包里的类、函数、变量都可以用 包名:: 访问:

systemverilog

Copy

Download

复制代码
package my_pkg;
  int g_var = 100;
  function int add(int a, int b);
    return a + b;
  endfunction

  class MyClass;
    int x;
  endclass
endpackage

module tb;
  import my_pkg::*;          // 通配导入
  initial begin
    my_pkg::MyClass obj;     // 也可以显式用 :: 引用
    $display("%0d", my_pkg::g_var);
    $display("%0d", my_pkg::add(3, 4));
  end
endmodule

UVM 里到处都是这种:

systemverilog

Copy

Download

复制代码
uvm_pkg::uvm_component
uvm_macros::uvm_info

场景 4:UVM 里最经典的 type_id::create

你以后写 UVM 一定会见到:

systemverilog

Copy

Download

复制代码
class my_driver extends uvm_driver #(my_transaction);
  `uvm_component_utils(my_driver)   // 这行宏会生成 type_id 这个 typedef

  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction
endclass

// 在别的地方创建:
my_driver drv;
drv = my_driver::type_id::create("drv", this);
//    ^^^^^^^^^^^^^^^^^^^^^^^^
//    类名::type_id(类内类型)::create(静态方法)

这里连着用了两次 ::

  1. my_driver::type_id ------ 访问 my_driver 类里的 type_id 这个 typedef

  2. type_id::create ------ 调用 type_id 这个类里的静态方法 create

这就是 UVM factory 机制的核心写法 ,理解了 :: 你就能看懂它了。


场景 5:访问父类被覆盖的成员(super 场景的补充)

有时候子类想调用父类的静态方法:

systemverilog

Copy

Download

复制代码
class Base;
  static function void hello();
    $display("Base hello");
  endfunction
endclass

class Child extends Base;
  static function void hello();
    Base::hello();           // 显式调用父类的静态方法
    $display("Child hello");
  endfunction
endclass

四、总结对照表

写法 含义 什么时候用
obj.member 通过对象访问 实例变量、实例方法
Class::member 通过类名访问 静态变量、静态方法、typedef、enum、parameter
pkg::member 通过包名访问 包里的类、函数、变量
Class::type_id::create(...) 链式访问 UVM factory 创建对象

一句话记忆

左边是对象 就用 .,左边是类型/类/包的名字 就用 ::


五、回到你的代码

systemverilog

Copy

Download

复制代码
Factory::use_err = 0;                  // use_err 是 static,用类名 + ::
drv = Factory::create_driver("drv", env);  // create_driver 是 static,用类名 + ::

如果 use_errcreate_driver 前面没有 static,那你就必须先 Factory f = new();,然后 f.use_err = 0;f.create_driver(...)

正因为它们是 static(属于类本身,不属于某个对象),所以 SV 要求你用 Factory:: 来访问------这就是 :: 出现的根本原因。

希望这个解释帮你把这块补上了,UVM 里 :: 会天天见到,多看几次就习惯了 👍

相关推荐
NamoAmitabha1282 天前
class基础+继承的专项训练
systemverilog
NamoAmitabha1282 天前
rand/randc/constraint 练习
systemverilog
fei_sun22 天前
UVM中的sequence
uvm
Salt & Light24 天前
UVM 字段自动化 Field Automation:让打印、复制、比较自动化
学习·systemverilog·uvm
fei_sun1 个月前
UVM中的TLM1.0通信
运维·服务器·uvm
liuluyang5301 个月前
UVM学习-2
uvm
liuluyang5301 个月前
UVM入门和进阶实验2
uvm
啄缘之间1 个月前
5.1 uvm‑component 的层级结构管理? new (name,parent) 参数
开发语言·笔记·学习·ic·uvm·sv
北方孤寂的灵魂2 个月前
关于AXI协议详解
verilog·systemverilog·sv·数字验证