class基础+继承的专项训练

训练一:最简单的class(热身)

题目

定义一个类 Counter,要求:

  • 有一个成员变量 int count。

  • 构造函数 new() 把 count 初始化为0。

  • 有一个方法 increment(),每次调用让 count 加1。

  • 有一个方法 show(),打印当前 count 值。

在 initial 里创建对象,调用 increment() 3次,然后 show(),期望输出 count=3。

你自己写(先别看下面)

systemverilog

Copy

Download

复制代码
// 在这里写你的代码

参考答案

systemverilog

Copy

Download

复制代码
class Counter;
  int count;

  function new();
    count = 0;
  endfunction

  function void increment();
    count = count + 1;
  endfunction

  function void show();
    $display("count=%0d", count);
  endfunction
endclass

module tb;
  initial begin
    Counter c;
    c = new();       // 必须new!
    c.increment();
    c.increment();
    c.increment();
    c.show();        // 输出 count=3
  end
endmodule

老师点评

  • 这是最基础的封装:数据(count) + 操作(increment/show) 打包在一起。

  • UVM对应 :UVM里所有组件都是这样,比如uvm_driver里有seq_item_port(数据)和run_phase(操作)。

  • 小白坑 :Counter c; 后忘了 c = new();,仿真直接报null。


训练二:带参数的构造函数

题目

定义一个类 Student,要求:

  • 成员变量 string name 和 int age。

  • 构造函数 new(string n, int a),把name和age赋值。

  • 方法 show() 打印 name is X years old。

创建两个对象:("Tom", 20) 和 ("Jerry", 22),分别show。

参考答案

systemverilog

Copy

Download

复制代码
class Student;
  string name;
  int age;

  function new(string n, int a);
    name = n;
    age = a;
  endfunction

  function void show();
    $display("%s is %0d years old", name, age);
  endfunction
endclass

module tb;
  initial begin
    Student s1 = new("Tom", 20);
    Student s2 = new("Jerry", 22);
    s1.show();
    s2.show();
  end
endmodule

老师点评

  • 构造函数可以带参数,也可以重载(不同参数列表)。

  • UVM对应 :uvm_component的构造函数固定是 new(string name, uvm_component parent),你必须写这两个参数,UVM框架自动传入。

  • 记住这个格式,写UVM组件时无脑套:

    systemverilog

    Copy

    Download

    复制代码
    function new(string name = "my_comp", uvm_component parent = null);
      super.new(name, parent);
    endfunction

训练三:继承入门(extends + super)

题目

  1. 定义父类 Animal:

    • 成员 string name。

    • 构造函数 new(string n),赋值name。

    • 方法 speak(),打印 Animal X makes a sound。

  2. 定义子类 Dog extends Animal:

    • 构造函数 new(string n),调用父类构造函数。

    • 重写 speak(),打印 Dog X says Woof。

  3. 定义子类 Cat extends Animal:

    • 构造函数 new(string n)。

    • 重写 speak(),打印 Cat X says Meow。

创建 Dog("WangCai") 和 Cat("Mimi"),分别speak。

参考答案

systemverilog

Copy

Download

复制代码
class Animal;
  string name;

  function new(string n);
    name = n;
  endfunction

  virtual function void speak();
    $display("Animal %s makes a sound", name);
  endfunction
endclass

class Dog extends Animal;
  function new(string n);
    super.new(n);       // 调用父类构造函数
  endfunction

  virtual function void speak();
    $display("Dog %s says Woof", name);
  endfunction
endclass

class Cat extends Animal;
  function new(string n);
    super.new(n);
  endfunction

  virtual function void speak();
    $display("Cat %s says Meow", name);
  endfunction
endclass

module tb;
  initial begin
    Dog d = new("WangCai");
    Cat c = new("Mimi");
    d.speak();   // Dog WangCai says Woof
    c.speak();   // Cat Mimi says Meow
  end
endmodule

老师点评

  • 三要素 :extends(继承)、super.new()(调父类构造)、virtual(可重写)。

  • UVM对应 :这就是UVM工厂机制的本质!uvm_driver extends uvm_component,my_driver extends uvm_driver,层层继承。

  • 小白坑1 :忘了 super.new(n),父类的name不会被初始化。

  • 小白坑2 :virtual忘了加,子类的speak不会生效(后面训练五会演示)。


训练四:多态(父类句柄指向子类对象)

题目

用训练三的Animal/Dog/Cat,写下面的代码,先猜输出,再跑:

systemverilog

Copy

Download

复制代码
module tb;
  initial begin
    Animal a;
    Dog d = new("WangCai");
    Cat c = new("Mimi");

    a = d;
    a.speak();    // 输出??

    a = c;
    a.speak();    // 输出??
  end
endmodule

答案

text

Copy

Download

复制代码
Dog WangCai says Woof
Cat Mimi says Meow

老师点评

  • 这就是多态 :父类句柄a运行时才知道指向Dog还是Cat,调用的是子类重写的方法。

  • 前提 :父类方法必须是virtual,否则调用的是父类的speak。

  • UVM对应 :工厂覆盖(factory override)就靠多态。你把my_driver换成err_driver,UVM用父类句柄创建,实际得到err_driver的行为。

  • 这就是UVM最核心的魔法! 一定要理解。

训练五:故意不加virtual,看会发生什么(反例)

题目

把训练三的Animal.speak()的virtual去掉,其他不变,跑训练四的代码,看输出。

答案

text

Copy

Download

复制代码
Animal WangCai makes a sound
Animal Mimi makes a sound

老师点评

  • 没加virtual,多态失效! 父类句柄调用的是父类方法。

  • 这就是为什么UVM里所有方法几乎都带virtual。

  • 死记:要被子类重写的方法,必须加virtual。


训练六:子类扩展父类(加新成员)

题目

  1. 父类 Shape:

    • 成员 string color。

    • 构造函数 new(string c)。

    • 方法 area() 返回 real,打印"Shape area unknown",返回0。

  2. 子类 Rectangle extends Shape:

    • 新增成员 real width, height。

    • 构造函数 new(string c, real w, real h),先调super.new(c),再赋值width/height。

    • 重写 area(),返回 width * height。

  3. 子类 Circle extends Shape:

    • 新增成员 real radius。

    • 构造函数 new(string c, real r)。

    • 重写 area(),返回 3.14159 * radius * radius。

创建 Rectangle("red", 3.0, 4.0) 和 Circle("blue", 2.0),打印各自area,期望12.0和12.566。

参考答案

systemverilog

Copy

Download

复制代码
class Shape;
  string color;
  function new(string c);
    color = c;
  endfunction
  virtual function real area();
    $display("Shape area unknown");
    return 0;
  endfunction
endclass

class Rectangle extends Shape;
  real width, height;
  function new(string c, real w, real h);
    super.new(c);
    width = w;
    height = h;
  endfunction
  virtual function real area();
    return width * height;
  endfunction
endclass

class Circle extends Shape;
  real radius;
  function new(string c, real r);
    super.new(c);
    radius = r;
  endfunction
  virtual function real area();
    return 3.14159 * radius * radius;
  endfunction
endclass

module tb;
  initial begin
    Rectangle r = new("red", 3.0, 4.0);
    Circle c = new("blue", 2.0);
    $display("Rectangle area = %0.2f", r.area());  // 12.00
    $display("Circle area = %0.2f", c.area());     // 12.57
  end
endmodule

老师点评

  • 子类可以在父类基础上加新成员 (width/height/radius),这叫扩展。

  • UVM对应 :my_transaction extends uvm_sequence_item,你会加rand字段;my_driver extends uvm_driver #(my_transaction),你会加virtual interface。

  • 记住顺序:先super.new(),再初始化自己的成员。


训练七(综合大作业):模拟UVM的component树

题目

模仿UVM的层次结构,写三个类:

  1. Component(基类):

    • 成员 string name,Component parent。

    • 构造函数 new(string n, Component p)。

    • virtual function void show():打印自己的name。

  2. Driver extends Component:

    • 构造函数 new(string n, Component p),调super。

    • 重写 show():打印 Driver: X。

  3. Monitor extends Component:

    • 构造函数同上。

    • 重写 show():打印 Monitor: X。

在tb里:

systemverilog

Copy

Download

复制代码
Component env = new("env", null);
Driver drv = new("drv", env);
Monitor mon = new("mon", env);
drv.show();
mon.show();

期望输出:

text

Copy

Download

复制代码
Driver: drv
Monitor: mon

参考答案

systemverilog

Copy

Download

复制代码
class Component;
  string name;
  Component parent;
  function new(string n, Component p);
    name = n;
    parent = p;
  endfunction
  virtual function void show();
    $display("Component: %s", name);
  endfunction
endclass

class Driver extends Component;
  function new(string n, Component p);
    super.new(n, p);
  endfunction
  virtual function void show();
    $display("Driver: %s", name);
  endfunction
endclass

class Monitor extends Component;
  function new(string n, Component p);
    super.new(n, p);
  endfunction
  virtual function void show();
    $display("Monitor: %s", name);
  endfunction
endclass

module tb;
  initial begin
    Component env = new("env", null);
    Driver drv = new("drv", env);
    Monitor mon = new("mon", env);
    drv.show();
    mon.show();
  end
endmodule

老师点评

  • 这个结构就是UVM的component树 !env是父,drv/mon是子。

  • UVM里 new(string name, uvm_component parent) 的两个参数,正是来自这里。

  • 一旦你理解这个,uvm_component的构造函数、build_phase的层次调用,全都通了。


训练八(进阶):理解UVM工厂的本质

题目

不改tb代码,只改一处,让 Driver 被创建时实际得到 ErrDriver。

提示:用父类句柄 + 工厂函数 。写一个函数 Component create_driver(string n, Component p),在函数里根据某个标志返回Driver或ErrDriver。

systemverilog

Copy

Download

复制代码
class ErrDriver extends Component;
  function new(string n, Component p);
    super.new(n, p);
  endfunction
  virtual function void show();
    $display("ErrDriver: %s", name);
  endfunction
endclass

参考答案

systemverilog

Copy

Download

复制代码
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工厂机制的简化版 !UVM通过type_id::create()和set_type_override实现同样的事。

  • 关键点:

    1. static 函数/变量属于类本身,不用new就能用。

    2. 返回值类型是父类Component,实际返回子类对象(多态)。

    3. 用标志决定创建哪个子类。

  • 学到这里,你就懂了UVM工厂的灵魂。


训练总结与自测表

做完上面8题,用下表自测,全部打勾才算过关:

技能 会 不会
定义class、成员变量、方法 ☐ ☐
用new创建对象 ☐ ☐
带参数的构造函数 ☐ ☐
extends继承 ☐ ☐
super.new()调父类构造 ☐ ☐
virtual方法重写 ☐ ☐
父类句柄指向子类对象(多态) ☐ ☐
子类新增成员 ☐ ☐
理解工厂本质 ☐ ☐
相关推荐
NamoAmitabha1285 天前
sequence.sv路科验证--deepseek
systemverilog·uvm
NamoAmitabha12812 天前
第2章:一个简单的UVM验证平台 —— 这是全书的精华!--deepseek
systemverilog·uvm
NamoAmitabha12812 天前
书中2.2.4virtual interface,config_db机制---deepseek
systemverilog·uvm
NamoAmitabha12818 天前
UVM在时间维度上也做了规范,phase机制----deepseek讲解
systemverilog·uvm
NamoAmitabha12818 天前
SystemVerilog 中的 :: 作用域解析运算符详解--deepseek讲解
systemverilog·uvm
NamoAmitabha12820 天前
rand/randc/constraint 练习
systemverilog
Salt & Light1 个月前
UVM 字段自动化 Field Automation:让打印、复制、比较自动化
学习·systemverilog·uvm
北方孤寂的灵魂2 个月前
关于AXI协议详解
verilog·systemverilog·sv·数字验证
Salt & Light3 个月前
SV基础之连接设计和测试平台
systemverilog