uvm_config_db内部代码功能解析

typedef class uvm_phase; // uvm_phase 类的类型定义


class m_uvm_waiter; // 定义一个内部等待器类
  string inst_name; // 实例名称
  string field_name; // 字段名称
  event trigger; // 触发事件

  function new (string inst_name, string field_name); // 构造函数
    this.inst_name = inst_name; // 初始化实例名称
    this.field_name = field_name; // 初始化字段名称
  endfunction
endclass

typedef class uvm_config_db_options; // uvm_config_db_options 类的类型定义


//----------------------------------------------------------------------
// 类:uvm_config_db
//
// uvm_config_db#(T) 中的所有函数都是静态的,因此必须使用 :: 运算符调用它们。例如:
//
//|  uvm_config_db#(int)::set(this, "*", "A");
//
// 参数值“int”将配置类型标识为 int 属性。
//
// <set> 和 <get> 方法提供与 <uvm_component> 中的 set/get_config_* 函数相同的 API 和语义。
//----------------------------------------------------------------------
class uvm_config_db#(type T=int) extends uvm_resource_db#(T); // 定义一个名为 uvm_config_db 的类,参数化类型为 T (默认是 int),继承自 uvm_resource_db#(T)

  // 内部查找配置设置,以便可以重复使用
  // 上下文具有一个池,该池以实例/字段名称为键。
  static uvm_pool#(string,uvm_resource#(T)) m_rsc[uvm_component]; // 静态资源池,存储配置信息

  // 用于 wait_modified 的内部等待器列表
  static local uvm_queue#(m_uvm_waiter) m_waiters[string]; // 静态队列,存储等待器


  // 函数:get
  //
  // 获取 ~inst_name~ 中 ~field_name~ 的值,使用组件 ~cntxt~ 作为起始搜索点。~inst_name~
  // 是相对于 ~cntxt~ 的显式实例名称,如果 ~cntxt~ 是配置对象适用的实例,则可以为空字符串。
  // ~field_name~ 是正在搜索的范围内的特定字段。
  //
  // <uvm_component> 中的基本 get_config_* 方法映射到此函数:
  //
  //| get_config_int(...) => uvm_config_db#(uvm_bitstream_t)::get(cntxt,...)
  //| get_config_string(...) => uvm_config_db#(string)::get(cntxt,...)
  //| get_config_object(...) => uvm_config_db#(uvm_object)::get(cntxt,...)

  static function bit get(uvm_component cntxt, // 获取配置信息的上下文
                          string inst_name, // 实例名称
                          string field_name, // 字段名称
                          inout T value); // 配置值
//TBD: add file/line
    int unsigned p;
    uvm_resource#(T) r, rt;
    uvm_resource_pool rp = uvm_resource_pool::get(); // 获取资源池
    uvm_resource_types::rsrc_q_t rq; // 资源队列

    if(cntxt == null) // 如果上下文为空,则使用根组件
      cntxt = uvm_root::get();
    if(inst_name == "") // 如果实例名称为空,则使用当前组件的完整名称
      inst_name = cntxt.get_full_name();
    else if(cntxt.get_full_name() != "") // 如果实例名称不为空且上下文有完整名称,则组合名称
      inst_name = {cntxt.get_full_name(), ".", inst_name};

    rq = rp.lookup_regex_names(inst_name, field_name, uvm_resource#(T)::get_type()); // 在资源池中查找配置信息
    r = uvm_resource#(T)::get_highest_precedence(rq); // 获取优先级最高的资源

    if(uvm_config_db_options::is_tracing()) // 如果开启了跟踪
      m_show_msg("CFGDB/GET", "Configuration","read", inst_name, field_name, cntxt, r); // 显示获取信息

    if(r == null) // 如果未找到配置信息
      return 0; // 返回失败

    value = r.read(cntxt); // 读取配置值

    return 1; // 返回成功
  endfunction

  // 函数:set
  //
  // 创建新的或更新 ~cntxt~ 中 ~inst_name~ 的 ~field_name~ 的现有配置设置。
  // 设置在 ~cntxt~ 处进行,设置的完整范围为{~cntxt~,".",~inst_name~}。如果 ~cntxt~ 为
  // null,则 ~inst_name~ 提供设置的完整范围信息。~field_name~ 是目标字段。~inst_name~
  // 和 ~field_name~ 都可以是 glob 样式或正则表达式样式的表达式。
  //
  // 如果在构建时进行设置,则使用 ~cntxt~ 层次结构来确定数据库中设置的优先级。
  // 层次结构较高的级别的设置具有较高的优先级。来自同一层次结构级别的设置具有
  // 最后设置获胜的语义。<uvm_resource_base::default_precedence> 用于 uvm_top,
  // top 下方的每个层次结构级别递减 1。
  //
  // 构建时间之后,所有设置都使用默认优先级,因此具有最后获胜的语义。因此,如果在运行时,
  // 低级组件对某个字段进行运行时设置,则该设置将优先于在仿真中较早进行的测试级别设置。
  //
  // <uvm_component> 中的基本 set_config_* 方法映射到此函数:
  //
  //| set_config_int(...) => uvm_config_db#(uvm_bitstream_t)::set(cntxt,...)
  //| set_config_string(...) => uvm_config_db#(string)::set(cntxt,...)
  //| set_config_object(...) => uvm_config_db#(uvm_object)::set(cntxt,...)

  static function void set(uvm_component cntxt, // 设置配置信息的上下文
                           string inst_name, // 实例名称
                           string field_name, // 字段名称
                           T value); // 配置值

    uvm_root top;
    uvm_phase curr_phase;
    uvm_resource#(T) r;
    bit exists;
    string lookup;
    uvm_pool#(string,uvm_resource#(T)) pool;

    // 处理随机数稳定性
    process p = process::self();
    string rstate = p.get_randstate();
    top = uvm_root::get(); // 获取根组件
    curr_phase = top.m_current_phase; // 获取当前阶段

    if(cntxt == null) // 如果上下文为空,则使用根组件
      cntxt = top;
    if(inst_name == "") // 如果实例名称为空,则使用当前组件的完整名称
      inst_name = cntxt.get_full_name();
    else if(cntxt.get_full_name() != "") // 如果实例名称不为空且上下文有完整名称,则组合名称
      inst_name = {cntxt.get_full_name(), ".", inst_name};

    if(!m_rsc.exists(cntxt)) begin // 如果资源池不存在,则创建
      m_rsc[cntxt] = new;
    end
    pool = m_rsc[cntxt]; // 获取资源池

    // 插入标记以防止缓存异常
    lookup = {inst_name, "__M_UVM__", field_name}; // 组合查找键

    if(!pool.exists(lookup)) begin // 如果配置信息不存在,则创建新的资源
       r = new(field_name, inst_name);
       pool.add(lookup, r);
    end
    else begin // 如果配置信息已存在
      r = pool.get(lookup); // 获取资源
      exists = 1; // 设置已存在标志
    end

    if(curr_phase != null && curr_phase.get_name() == "build") // 如果当前阶段是构建阶段
      r.precedence = uvm_resource_base::default_precedence - (cntxt.get_depth()); // 设置优先级
    else
      r.precedence = uvm_resource_base::default_precedence; // 设置默认优先级

    r.write(value, cntxt); // 写入配置值

    if(exists) begin // 如果配置信息已存在
      uvm_resource_pool rp = uvm_resource_pool::get(); // 获取资源池
      rp.set_priority_name(r, uvm_resource_types::PRI_HIGH); // 设置高优先级
    end
    else begin // 如果配置信息不存在
      // 不存在,则将其放入资源数据库的头部。
      r.set_override(); // 设置覆盖
    end

    // 触发任何等待器
    if(m_waiters.exists(field_name)) begin // 如果有等待器
      m_uvm_waiter w;
      for(int i=0; i<m_waiters[field_name].size(); ++i) begin // 遍历所有等待器
        w = m_waiters[field_name].get(i); // 获取等待器
        if(uvm_re_match(uvm_glob_to_re(inst_name),w.inst_name) == 0) // 判断实例名称是否匹配
           ->w.trigger;  // 触发事件
      end
    end

    p.set_randstate(rstate); // 恢复随机数状态

    if(uvm_config_db_options::is_tracing()) // 如果开启了跟踪
      m_show_msg("CFGDB/SET", "Configuration","set", inst_name, field_name, cntxt, r); // 显示设置信息
  endfunction


  // 函数:exists
  //
  // 检查 ~inst_name~ 中是否可用于 ~field_name~ 的值,使用组件 ~cntxt~ 作为起始搜索点。
  // ~inst_name~ 是相对于 ~cntxt~ 的显式实例名称,如果 ~cntxt~ 是配置对象适用的实例,则可以为空字符串。
  // ~field_name~ 是正在搜索的范围内的特定字段。如果预期数据库中应该存在该字段,则可以将 ~spell_chk~
  // 参数设置为 1 以打开拼写检查。如果存在配置参数,则函数返回 1;如果不存在,则返回 0。

  static function bit exists(uvm_component cntxt, string inst_name, // 检查配置信息是否存在
      string field_name, bit spell_chk=0); // 实例名、字段名,拼写检查标志

    if(cntxt == null) // 如果上下文为空,则使用根组件
      cntxt = uvm_root::get();
    if(inst_name == "") // 如果实例名称为空,则使用当前组件的完整名称
      inst_name = cntxt.get_full_name();
    else if(cntxt.get_full_name() != "") // 如果实例名称不为空且上下文有完整名称,则组合名称
      inst_name = {cntxt.get_full_name(), ".", inst_name};

    return (uvm_resource_db#(T)::get_by_name(inst_name,field_name,spell_chk) != null); // 检查资源是否存在
  endfunction


  // 函数:wait_modified
  //
  // 等待在 ~cntxt~ 和 ~inst_name~ 中为 ~field_name~ 设置配置设置。该任务阻塞,直到应用影响指定字段的新配置设置。

  static task wait_modified(uvm_component cntxt, string inst_name, // 等待配置信息被修改
      string field_name); // 实例名、字段名

    process p = process::self();
    string rstate = p.get_randstate(); // 保存随机数状态
    m_uvm_waiter waiter; // 创建等待器

    if(cntxt == null) // 如果上下文为空,则使用根组件
      cntxt = uvm_root::get();
    if(cntxt != uvm_root::get()) begin // 如果上下文不是根组件
      if(inst_name != "") // 如果实例名称不为空
        inst_name = {cntxt.get_full_name(),".",inst_name}; // 组合实例名称
      else
        inst_name = cntxt.get_full_name(); // 使用当前组件的完整名称
    end

    waiter = new(inst_name, field_name); // 创建等待器

    if(!m_waiters.exists(field_name)) // 如果等待器队列不存在,则创建
      m_waiters[field_name] = new;
    m_waiters[field_name].push_back(waiter); // 将等待器添加到队列

    p.set_randstate(rstate); // 恢复随机数状态

    // 等待等待器触发
    @waiter.trigger;

    // 从等待器列表中删除等待器
    for(int i=0; i<m_waiters[field_name].size(); ++i) begin // 遍历等待器队列
      if(m_waiters[field_name].get(i) == waiter) begin // 找到等待器
        m_waiters[field_name].delete(i); // 删除等待器
        break;
      end
    end
  endtask


endclass

typedef uvm_config_db#(uvm_object_wrapper) uvm_config_wrapper; // uvm_config_wrapper 的类型定义


//----------------------------------------------------------------------
// 类:uvm_config_db_options
//
// 提供用于管理配置 DB 功能选项的命名空间。此类中唯一允许的是静态局部数据成员和用于
// 操作和检索数据成员值的静态函数。静态局部数据成员表示控制配置 DB 功能行为的选项和设置。
//
// 选项包括:
//
//  * tracing:开启/关闭
//
//    跟踪的默认值为关闭。
//
//----------------------------------------------------------------------
class uvm_config_db_options;

  static local bit ready; // 初始化标志
  static local bit tracing; // 跟踪标志

  // 函数:turn_on_tracing
  //
  // 为配置数据库打开跟踪。这会导致所有对数据库的读取和写入都显示有关访问的信息。
  // 跟踪默认情况下是关闭的。
  //
  // 此方法由 ~+UVM_CONFIG_DB_TRACE~ 隐式调用。

  static function void turn_on_tracing();
     if (!ready) init(); // 如果未初始化,则进行初始化
    tracing = 1; // 打开跟踪
  endfunction

  // 函数:turn_off_tracing
  //
  // 关闭配置数据库的跟踪。

  static function void turn_off_tracing();
     if (!ready) init(); // 如果未初始化,则进行初始化
    tracing = 0; // 关闭跟踪
  endfunction

  // 函数:is_tracing
  //
  // 如果跟踪功能已打开,则返回 1;如果已关闭,则返回 0。

  static function bit is_tracing();
    if (!ready) init(); // 如果未初始化,则进行初始化
    return tracing; // 返回跟踪状态
  endfunction


  static local function void init(); // 初始化函数
     uvm_cmdline_processor clp; // 命令行处理器
     string trace_args[$]; // 跟踪参数

     clp = uvm_cmdline_processor::get_inst(); // 获取命令行处理器实例

     if (clp.get_arg_matches("+UVM_CONFIG_DB_TRACE", trace_args)) begin // 检查命令行参数
        tracing = 1; // 如果存在 "+UVM_CONFIG_DB_TRACE" 参数,则打开跟踪
     end

     ready = 1; // 设置初始化标志
  endfunction

endclass

endclass

这段代码实现了一个 UVM 配置数据库 (uvm_config_db),它允许用户在 UVM 验证环境中设置和获取配置参数。让我们深入分析其代码逻辑和功能:

一、核心数据结构:

m_rsc[uvm_component]: 这是一个静态的 uvm_pool,它是配置数据库的核心。它使用 uvm_component 作为键,值为另一个 uvm_pool#(string, uvm_resource#(T))。 这意味着对于每个 UVM 组件,都维护一个独立的配置参数池。 内部的 uvm_pool 使用字符串作为键,表示配置参数的完整路径(包括实例名和字段名),值为 uvm_resource#(T),存储实际的配置参数值。 这种分层结构使得能够在不同的组件层次上设置不同的配置参数,并且可以根据层次结构解决优先级冲突。

m_waiters[string]: 这是一个静态的 uvm_queue,用于管理等待配置参数修改的等待器 (m_uvm_waiter)。键为配置参数的字段名,值为一个 m_uvm_waiter 队列。当一个配置参数被修改时,相应的等待器会被触发。

m_uvm_waiter: 这是一个简单的类,用于表示一个等待配置参数修改的等待器。它包含实例名 (inst_name)、字段名 (field_name) 和一个触发事件 (trigger)。

二、核心函数分析:

set(cntxt, inst_name, field_name, value): 这个函数用于设置配置参数。

确定范围: 它首先确定配置参数的完整范围,结合 cntxt (上下文组件)、inst_name (实例名) 和 field_name (字段名)。 如果 cntxt 为空,则使用 uvm_root。 如果 inst_name 为空,则使用 cntxt 的完整名称。

获取或创建资源: 它在 m_rsc 中查找对应的 uvm_resource#(T) 对象。如果不存在,则创建一个新的。 为了避免缓存冲突,它使用了特殊的字符串 lookup 作为键。

设置优先级: 在构建阶段 (build_phase),优先级根据组件的层次深度递减,层次高的组件优先级高。在运行阶段,所有设置都使用默认优先级,后设置的优先级高。

写入值: 它使用 r.write(value, cntxt) 将值写入 uvm_resource 对象。

设置覆盖: 如果该配置项是新创建的,则设置 override 标志,这表示该配置项覆盖了其它同名配置项。

触发等待器: 它检查是否有等待器在等待此字段的修改,如果有则触发相应的事件。

跟踪: 如果开启了跟踪 (uvm_config_db_options::is_tracing()),则显示设置信息。

get(cntxt, inst_name, field_name, value): 这个函数用于获取配置参数。

确定范围: 类似于 set 函数,它首先确定配置参数的完整范围。

查找资源: 它使用 uvm_resource_pool::lookup_regex_names 根据范围查找所有匹配的 uvm_resource 对象。

选择最高优先级: 它从找到的所有资源中选择优先级最高的资源。

读取值: 它使用 r.read(cntxt) 读取资源的值。

跟踪: 如果开启了跟踪,则显示获取信息。

exists(cntxt, inst_name, field_name, spell_chk): 这个函数用于检查配置参数是否存在。

确定范围: 类似于 set 和 get 函数,它首先确定配置参数的完整范围。

查找资源: 它使用 uvm_resource_db#(T)::get_by_name 查找配置参数,如果找到则返回 true,否则返回 false。 spell_chk 参数控制是否进行拼写检查。

wait_modified(cntxt, inst_name, field_name): 这个函数用于等待配置参数被修改。

创建等待器: 创建一个 m_uvm_waiter 对象,并将其添加到 m_waiters 队列中。

等待触发: 使用 @waiter.trigger 阻塞当前进程,直到 trigger 事件被触发(由 set 函数触发)。

移除等待器: 在等待结束后,从 m_waiters 队列中移除等待器。

三、uvm_config_db_options 类:

这个类用于管理配置数据库的跟踪选项。它提供 turn_on_tracing()、turn_off_tracing() 和 is_tracing() 函数来控制跟踪的开关,并通过 init() 函数在初始化时检查命令行参数 +UVM_CONFIG_DB_TRACE 来设置跟踪选项。

四、总结:

uvm_config_db 提供了一个强大的机制来管理 UVM 验证环境中的配置参数。它支持层次化的配置、优先级管理、以及等待配置修改的功能。 它利用了 UVM 的 uvm_pool 和 uvm_queue 等数据结构,并通过事件机制实现了异步等待。 其设计考虑了效率和线程安全,并允许灵活的配置管理。 uvm_config_db_options 类则提供了控制跟踪的便利接口。 通过合理地使用 set,get,exists 和 wait_modified 等函数,可以方便地进行参数配置和管理,提高代码的可读性和可维护性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值