跳转至

输入查询内容

    本页内容

    uvm_printer emit() 必须配 flush(),新增 UVM/PRINT/NO_FLUSH 检查

    影响范围

    绕过 sprint、直接重复调用 printer.emit,或手工复用同一 printer。

    具体差异

    printer 内部由"m_rows 行队列"改为"uvm_printer_element 树 + 回收栈"。1.2 emit() 结束自动清行缓存;2.0 要求 emit 与 flush 配对,连续两次 emit 且无 flush 直接报 UVM_ERROR。uvm_object::sprint/print 在顶层会自动 flush(uvm_object.svh:886),常规 obj.print() 不受影响;自定义 printer 子类或手动 print_field+emit 拼输出的代码可能踩雷。

    修改方案

    直接拼装输出时,每次独立输出先 printer.flush(),再 print_field 等填入字段,最后保存 printer.emit() 返回值;下一次输出重新执行同样顺序。普通 obj.sprint(printer) 顶层已负责 flush,可保留该路径。

    p 为已构造的 uvm_table_printervalue 为 32 位数据,text 为 string。旧代码可能连续执行以下两行:

    p.print_field("value", value, 32, UVM_HEX);
    text = p.emit();
    

    目标版每次开始独立输出时清理状态:

    1
    2
    3
    p.flush();
    p.print_field("value", value, 32, UVM_HEX);
    text = p.emit();
    

    完成一次输出后,下一次仍从 flush 开始;不能在已填入字段后、emit 前 flush,否则会清掉本次内容。普通 obj.sprint(p) 顶层已负责 flush,可继续使用。

    兼容措施与范围:兼容措施不恢复 emit 后自动清空;手工输出遵循 flush → 填字段 → emit,普通 sprint 可保留。

    迁移后验证

    独立输出之间执行 flush,连续输出两次应无 NO_FLUSH 且无上一对象残留;普通 sprint 路径单独对照。

    记录本条结果M02-006 · 状态与证据

    已有实测与复现

    补充查阅

    扫描定位与记录结果

    有扫描规则,覆盖部分可识别写法。脚本检查名称、参数和部分 FLAG 表达式,并对少数直接声明关联使用点;未做完整类型解析或预处理,行为结果仍需验证。

    uv run tools/uvm_migration_scan.py <SoC代码目录> --rules S27
    

    核对命中对象及生效分支后,在条目清单记录修改与验证证据;扫描规则记录用于整理命中位置。

    扫描器下载、输入范围与报告说明

    源码与标准依据

    核查方式:源码与实测核对。实测仅覆盖本条所列场景。

    VCS 内置 UVM-1.2uvm_printer.svh:1046(table emit 内部清 m_rows)

    VCS 内置 uvm-ieee-2020-2.0uvm_printer.svh:1362uvm_printer.svh:1526(emit 内 uvm_error UVM/PRINT/NO_FLUSH)、uvm_printer.svh:195(flush 声明)

    标准依据:IEEE 1800.2-2020 §16.2.4(flush/emit)

    标为“源码标注”或未注明原文核对的条款仅作定位;具体库行为以源码和实测为准。

    引用代码(高亮为引用行);上方行号链接可直接定位。

    src/vcs-uvm-1.2/base/uvm_printer.svh
      string linefeed = {"\n", knobs.prefix};
    
      calculate_max_widths(); 
    
       begin
          int q[5];
          int m;
          int qq[$];
    
          q = '{m_max_name,m_max_type,m_max_size,m_max_value,100};
          qq = q.max;
          m = qq[0];
        if(dash.len()<m) begin
            dash = {m{"-"}};
            space = {m{" "}};
        end
      end
    

    完整源码 · SHA256:3a007c7a488ef1943aa1bfce8bb945eaa32c3023170f6c35ce6358f5f6f5a378

    src/vcs-uvm-ieee-2020-2.0/base/uvm_printer.svh
      extern virtual function string emit ();
    
      extern virtual function void flush ();
    
      // @uvm-ieee 1800.2-2020 auto 16.2.5.1
      extern virtual function void set_name_enabled (bit enabled);
      // @uvm-ieee 1800.2-2020 auto 16.2.5.1
      extern virtual function bit get_name_enabled ();
    
      // @uvm-ieee 1800.2-2020 auto 16.2.5.2
      extern virtual function void set_type_name_enabled (bit enabled);
      // @uvm-ieee 1800.2-2020 auto 16.2.5.2
      extern virtual function bit get_type_name_enabled ();
    
      // @uvm-ieee 1800.2-2020 auto 16.2.5.3
      extern virtual function void set_size_enabled (bit enabled);
      // @uvm-ieee 1800.2-2020 auto 16.2.5.3
      extern virtual function bit get_size_enabled ();
    

    src/vcs-uvm-ieee-2020-2.0/base/uvm_printer.svh
      string linefeed;
    
      if (!m_flushed) begin
         `uvm_error("UVM/PRINT/NO_FLUSH","printer emit() method called twice without intervening uvm_printer::flush()")
      end
      else m_flushed = 0 ;
      linefeed = {"\n", get_line_prefix()};
    
       begin
          int q[5];
          int m;
          int qq[$];
    
          q = '{m_max_name,m_max_type,m_max_size,m_max_value,100};
          qq = q.max;
          m = qq[0];
        if(dash.len()<m) begin
            dash = {m{"-"}};
            m_space = {m{" "}};
    

    src/vcs-uvm-ieee-2020-2.0/base/uvm_printer.svh
      uvm_printer_element element ;
    
      if (!m_flushed) begin
         `uvm_error("UVM/PRINT/NO_FLUSH","printer emit() method called twice without intervening uvm_printer::flush()")
      end
      else m_flushed = 0 ;
    
      s = get_line_prefix() ;
      m_linefeed = m_newline == "" || m_newline == " " ? m_newline : {m_newline, get_line_prefix()};
    
      // backward compatibility
      if (knobs.header) begin
        user_format = format_header();
        if (user_format != "")
          s = {s, user_format, m_linefeed};
      end
    
      s = {s,m_emit_element(get_bottom_element(),0)} ;
    

    完整源码 · SHA256:960f0c18aee9036a3261b2108183dc85b3cf572d1912605325c6b595f4b9aaef

    术语解释 · 兼容配置

    返回Comparer / Printer / Packer / Recorder · 迁移清单

    版本适用范围