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 nameint 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_componentmy_driver extends uvm_driver,层层继承。

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

  • 小白坑2virtual忘了加,子类的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.012.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 nameComponent 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方法重写
父类句柄指向子类对象(多态)
子类新增成员
理解工厂本质
相关推荐
NamoAmitabha1286 小时前
rand/randc/constraint 练习
systemverilog
Salt & Light22 天前
UVM 字段自动化 Field Automation:让打印、复制、比较自动化
学习·systemverilog·uvm
北方孤寂的灵魂2 个月前
关于AXI协议详解
verilog·systemverilog·sv·数字验证
Salt & Light2 个月前
SV基础之连接设计和测试平台
systemverilog
fei_sun3 个月前
【SystemVerilog】连接设计和测试平台(待补充)
systemverilog
fei_sun3 个月前
【SystemVerilog验证】数据类型(待补充)
数据结构·systemverilog
不会武功的火柴3 个月前
SystemVerilog语法(11)-面向对象编程下篇
面向对象·fpga·systemverilog·ic验证
Ether IC Verifier3 个月前
SystemVerilog 数据类型详解
php·systemverilog·uvm·ic验证
Ether IC Verifier4 个月前
IC 验证工程师新手入门指南
systemverilog·ic验证·dpu