3.2.1 如何将uvm_object应用到实际的验证项目中?


前言

在 UVM(Universal Verification Methodology)中,uvm_object 是一个非常基础且重要的类。它为验证项目提供了灵活且强大的功能,通过从 uvm_object 派生,可以创建各种用于验证的类和对象,如事务类、配置类、寄存器模型等。以下通过示例代码详细讲解如何将 uvm_object 应用到实际的验证项目中。


一、定义事务类

在验证项目中,事务(transaction)是验证平台与设计之间交互的基本单元。以下是一个从 uvm_object 派生定义的事务类示例:

class my_transaction extends uvm_object;
  // 定义事务的属性
  rand bit [7:0] data;    // 数据字段
  rand bit [3:0] addr;    // 地址字段
  bit           valid;    // 有效位

  // 注册类到 UVM 工厂
  `uvm_object_utils(my_transaction)

  // 构造函数
  function new(string name = "my_transaction");
    super.new(name);
  endfunction

  // 实现 copy 方法
  virtual function void do_copy(uvm_object rhs);
    my_transaction tx;
    if (!$cast(tx, rhs)) begin
      `uvm_fatal("COPY", "Copy failed: wrong type")
    end
    this.data  = tx.data;
    this.addr  = tx.addr;
    this.valid = tx.valid;
  endfunction

  // 实现 compare 方法
  virtual function bit do_compare(uvm_object rhs, uvm_comparer comparer);
    my_transaction tx;
    if (!$cast(tx, rhs)) return 0;
    return (this.data == tx.data) && (this.addr == tx.addr) && (this.valid == tx.valid);
  endfunction

  // 实现 print 方法
  virtual function void do_print(uvm_printer printer);
    printer.print_field("data",  this.data,  8);
    printer.print_field("addr",  this.addr,  4);
    printer.print_field("valid", this.valid, 1);
  endfunction
endclass
  1. 属性定义
    data 和 addr 是随机化的寄存器类型,它们的值可以通过随机化生成。
    valid 用来表示数据的有效性。
  2. uvm_object_utils 宏
    这个宏的作用是将类注册到 UVM 工厂,使得可以通过工厂创建对象,并且可以支持对象的复制、比较和打印。
  3. 构造函数
    构造函数调用了父类的构造函数,并传递了对象的名称。
  4. do_copy 方法
    这个方法用于对象的复制。它首先将输入对象强制转换为 my_transaction 类型,然后将属性值复制到当前对象。
  5. do_compare 方法
    这个方法用于对象的比较。它首先将输入对象强制转换为 my_transaction 类型,然后比较各个属性的值。
  6. do_print 方法
    这个方法用于打印对象的属性。它通过 uvm_printer 打印字段的名称和值。

二、使用事务类

在测试平台中,可以使用事务类来创建、随机化、复制和比较对象:

module testbench;
  initial begin
    my_transaction tx1, tx2;

    // 创建事务对象
    tx1 = my_transaction::type_id::create("tx1");
    tx2 = my_transaction::type_id::create("tx2");

    // 随机化事务对象
    if (!tx1.randomize()) `uvm_error("RAND", "Randomization failed")
    if (!tx2.randomize()) `uvm_error("RAND", "Randomization failed")

    // 打印事务对象
    tx1.print();
    tx2.print();

    // 复制事务对象
    tx2.copy(tx1);

    // 比较事务对象
    if (tx2.compare(tx1)) begin
      `uvm_info("COMPARE", "Transaction matched", UVM_LOW)
    end else begin
      `uvm_error("COMPARE", "Transaction mismatch")
    end
  end
endmodule
  1. 创建事务对象
    使用 type_id::create 方法通过工厂创建对象,传递对象的名称。
  2. 随机化事务对象
    调用对象的 randomize 方法,为随机化的寄存器属性赋值。
  3. 打印事务对象
    调用对象的 print 方法,打印对象的属性。
  4. 复制事务对象
    调用对象的 copy 方法,将一个对象的值复制到另一个对象。
  5. 比较事务对象
    调用对象的 compare 方法,比较两个对象的值。

三、配置验证平台

uvm_object 还可以用于定义配置类,用于规范验证平台的行为方式:

class my_config extends uvm_object;
  // 定义配置参数
  bit [3:0] bus_width;
  bit        clk_freq;

  // 注册类到 UVM 工厂
  `uvm_object_utils(my_config)

  // 构造函数
  function new(string name = "my_config");
    super.new(name);
  endfunction

  // 实现 copy 方法
  virtual function void do_copy(uvm_object rhs);
    my_config cfg;
    if (!$cast(cfg, rhs)) begin
      `uvm_fatal("COPY", "Copy failed: wrong type")
    end
    this.bus_width = cfg.bus_width;
    this.clk_freq  = cfg.clk_freq;
  endfunction

  // 实现 compare 方法
  virtual function bit do_compare(uvm_object rhs, uvm_comparer comparer);
    my_config cfg;
    if (!$cast(cfg, rhs)) return 0;
    return (this.bus_width == cfg.bus_width) && (this.clk_freq == cfg.clk_freq);
  endfunction

  // 实现 print 方法
  virtual function void do_print(uvm_printer printer);
    printer.print_field("bus_width", this.bus_width, 4);
    printer.print_field("clk_freq",  this.clk_freq,  1);
  endfunction
endclass
  1. 配置参数
    bus_width 和 clk_freq 是配置参数,用于描述验证平台的行为。
  2. 使用配置类
    在验证平台中,可以通过 config_db 将配置类设置给各个组件:
initial begin
  my_config cfg = new("cfg");
  cfg.bus_width = 8;
  cfg.clk_freq  = 1;

  // 设置配置类
  uvm_config_db#(my_config)::set(null, "*", "my_config", cfg);
end

四、寄存器模型

uvm_object 还可以用于定义寄存器模型中的类,如 uvm_reg:

class my_reg extends uvm_reg;
  // 定义寄存器的属性
  rand bit [7:0] data;

  // 注册类到 UVM 工厂
  `uvm_object_utils(my_reg)

  // 构造函数
  function new(string name = "my_reg");
    super.new(name, 8);
  endfunction
endclass
  1. 定义寄存器
    my_reg 是从 uvm_reg 派生的类,用于描述寄存器的行为和结构。
  2. 使用寄存器模型
    在验证平台中,可以创建寄存器对象并对其进行操作:
initial begin
  my_reg reg = my_reg::type_id::create("reg");

  // 随机化寄存器对象
  if (!reg.randomize()) `uvm_error("RAND", "Randomization failed")

  // 打印寄存器对象
  reg.print();
end

五、工厂模式

uvm_object 还可以用于实现工厂模式,动态创建对象:

class my_factory extends uvm_object;
  // 注册类到 UVM 工厂
  `uvm_object_utils(my_factory)

  // 构造函数
  function new(string name = "my_factory");
    super.new(name);
  endfunction
endclass

initial begin
  uvm_factory factory = uvm_factory::get();
  factory.register_type_by_name("my_factory", my_factory::get_type());
end
  1. 工厂模式
    通过工厂模式,可以动态选择创建对象的类型。

六、派生类

1. 定义派生自 uvm_object 的类

在验证项目中,我们常常需要自定义一些类来封装数据或配置信息,这些类可以派生自 uvm_object

示例代码:定义 my_transaction

class my_transaction extends uvm_sequence_item;
    // 定义成员变量,封装事务信息
    rand bit [47:0] dst_mac;
    rand bit [47:0] src_mac;
    rand bit [15:0] frame_type;
    rand byte data[];
    bit [31:0] fcs;

    // 工厂注册,方便 UVM 工厂管理对象创建
    `uvm_object_utils_begin(my_transaction)
        `uvm_field_int(dst_mac, UVM_ALL_ON)
        `uvm_field_int(src_mac, UVM_ALL_ON)
        `uvm_field_int(frame_type, UVM_ALL_ON)
        `uvm_field_array_int(data, UVM_ALL_ON)
        `uvm_field_int(fcs, UVM_ALL_ON)
    `uvm_object_utils_end

    // 构造函数
    function new(string name = "my_transaction");
        super.new(name);
    endfunction
endclass

解释

  • my_transaction 类派生自 uvm_sequence_item,而 uvm_sequence_item 又派生自 uvm_object,用于封装一个 MAC 帧的相关信息。
  • uvm_object_utils_beginuvm_object_utils_end 是 UVM 提供的宏,用于将类注册到 UVM 工厂,方便后续创建对象和实现多态。
  • uvm_field_* 宏用于指定类的成员变量参与 UVM 的自动化操作,如打印、复制、比较等。

2. 使用 uvm_object 进行数据传输

在验证平台中,uvm_object 常用于在不同组件之间传输数据。例如,sequence 生成 sequence_item(派生自 uvm_object),并通过 sequencer 传递给 driver

示例代码:定义 my_sequence

class my_sequence extends uvm_sequence #(my_transaction);
    // 工厂注册
    `uvm_object_utils(my_sequence)

    // 构造函数
    function new(string name = "my_sequence");
        super.new(name);
    endfunction

    // body 任务,生成事务并发送
    virtual task body();
        my_transaction tr;
        repeat (10) begin
            // 创建事务对象
            tr = my_transaction::type_id::create("tr");
            // 随机化事务
            assert(tr.randomize());
            // 发送事务
            start_item(tr);
            finish_item(tr);
        end
    endtask
endclass

解释

  • my_sequence 类派生自 uvm_sequence,并指定了事务类型为 my_transaction
  • body 任务中,通过 create 方法创建 my_transaction 对象,然后对其进行随机化,最后使用 start_itemfinish_item 方法将事务发送给 sequencer

3. 利用 uvm_object 的自动化功能

uvm_object 提供了许多自动化功能,如打印、复制、比较等,可以方便我们进行调试和验证。

示例代码:使用自动化功能

module test;
    import uvm_pkg::*;
    `include "uvm_macros.svh"
    `include "my_transaction.sv"
    `include "my_sequence.sv"

    initial begin
        my_transaction tr1, tr2;
        // 创建事务对象
        tr1 = my_transaction::type_id::create("tr1");
        // 随机化事务
        assert(tr1.randomize());

        // 打印事务信息
        $display("Transaction 1:");
        tr1.print();

        // 复制事务
        tr2 = tr1.clone();
        $display("Transaction 2 (cloned from tr1):");
        tr2.print();

        // 比较事务
        if (tr1.compare(tr2)) begin
            $display("Transactions are equal.");
        end else begin
            $display("Transactions are not equal.");
        end
    end
endmodule

解释

  • print 方法用于打印事务的详细信息,方便调试。
  • clone 方法用于复制一个事务对象,创建一个新的对象并复制其成员变量的值。
  • compare 方法用于比较两个事务对象的成员变量是否相等。

4. 定义配置类(派生自 uvm_object

在验证项目中,我们常常需要定义一些配置类来管理验证平台的参数和行为。这些配置类可以派生自 uvm_object,并通过 config_db 进行配置传递。

示例代码:定义 my_config

class my_config extends uvm_object;
    // 定义配置参数
    bit [7:0] addr_width;
    bit [7:0] data_width;

    // 工厂注册
    `uvm_object_utils_begin(my_config)
        `uvm_field_int(addr_width, UVM_ALL_ON)
        `uvm_field_int(data_width, UVM_ALL_ON)
    `uvm_object_utils_end

    // 构造函数
    function new(string name = "my_config");
        super.new(name);
    endfunction
endclass

示例代码:使用 config_db 进行配置传递

module test;
    import uvm_pkg::*;
    `include "uvm_macros.svh"
    `include "my_config.sv"

    initial begin
        my_config cfg;
        // 创建配置对象
        cfg = my_config::type_id::create("cfg");
        // 设置配置参数
        cfg.addr_width = 8;
        cfg.data_width = 32;

        // 将配置对象存储到 config_db 中
        uvm_config_db#(my_config)::set(null, "*", "my_config", cfg);

        // 从 config_db 中获取配置对象
        my_config get_cfg;
        if (!uvm_config_db#(my_config)::get(null, "*", "my_config", get_cfg)) begin
            `uvm_fatal("CFG_GET", "Failed to get configuration object.")
        end

        // 打印配置信息
        $display("Address width: %0d", get_cfg.addr_width);
        $display("Data width: %0d", get_cfg.data_width);
    end
endmodule

解释

  • my_config 类派生自 uvm_object,用于封装验证平台的配置参数。
  • uvm_config_db 是 UVM 提供的一个全局数据库,用于在不同组件之间传递配置信息。通过 set 方法将配置对象存储到数据库中,通过 get 方法从数据库中获取配置对象。

通过以上步骤,我们可以将 uvm_object 应用到实际的验证项目中,实现数据封装、传输、自动化操作和配置管理等功能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值