本页内容
旧数组录制上限失效:显式控制记录项数
编译断点 日志/调试变化
影响范围
运行参数含 +UVM_ARRAY_NUM_LIMIT,或自定义 recorder/字段操作调用 verdi_get_array_limit()、访问 max_array_limit_check/max_array_num_limit。
具体差异
VCS 1.2 的 recorder 读取 +UVM_ARRAY_NUM_LIMIT,数组/队列 field 宏调用 verdi_get_array_limit() 选择记录项数;目标 recorder 与 Accellera 2.0 相同,已无该方法和配置字段,旧 plusarg 没有原来的消费路径。直接调用旧方法会报成员不存在;只留下 plusarg 通常不能通过编译报错发现失效。此项是 VCS 旧版定制的移除,不是所有 recorder 的通用数组限制。
修改方案
先确认需要记录全部元素还是限定元素;需要上限时,给对应字段的 field FLAG 加 UVM_NORECORD,在 do_record(uvm_recorder recorder) 中按显式上限调用 record_field_int/record_object 等对应接口。调用旧 getter 的代码改读自己维护的配置;验证记录内容后再删除旧 plusarg。已有手工录制字段不要同时启用自动录制。
旧写法通过仿真参数控制自动录制:+UVM_ARRAY_NUM_LIMIT=2。下面给出整数数组只记录前两项的显式写法;data 若仍注册 field 宏,应在原 FLAG 上增加 UVM_NORECORD,保留所需 copy/compare/pack 操作。
class bounded_record_item extends uvm_object ;
int data [] = '{ 11 , 22 , 33 , 44 };
int unsigned record_limit = 2 ;
function new ( string name = "bounded_record_item" ); super . new ( name ); endfunction
// This example does not register data with a field macro.
function void do_record ( uvm_recorder recorder );
super . do_record ( recorder );
foreach ( data [ i ]) begin
if ( i >= record_limit ) break ;
recorder . record_field_int ($ sformatf ( "data[%0d]" , i ), data [ i ], 32 , UVM_DEC );
end
endfunction
endclass
这里的上限 0 表示不记录任何元素,与旧开关的 0 分支不同;迁移配置时明确转换含义。对象数组用相应的 record_object 并单独验证对象身份和递归。
兼容措施与范围 :deprecated 、legacy field 开关和 compat 包都不恢复这套 VCS 数组上限;显式 do_record 的上限由用户配置维护。
迁移后验证
用超过上限的数组检查记录项数、索引和值;也覆盖空数组、短数组及所用元素类型。确认没有自动录制叠加,并检查实际后端输出与所需的文件体积;不能把文本 recorder 实验扩展到全部 Verdi 工作流。
记录本条结果 :M02-016 · 状态与证据 。
已有实测与复现
vendor_compile_probe 的旧 getter 调用在 1.2 编译通过,2.0 报 Error-[MFNF]。vendor_migration_probe 两库对四项整数数组均记录两项,值之和为 33,最后字段为 data[1];只验证手工 do_record 与文本 recorder 调用,不代表所有 field 宏或 Verdi 文件格式等价。
补充查阅
扫描定位与记录结果
有扫描规则,覆盖部分可识别写法 。脚本检查名称、参数和部分 FLAG 表达式,并对少数直接声明关联使用点;未做完整类型解析或预处理,行为结果仍需验证。
uv run tools/uvm_migration_scan.py <SoC代码目录> --rules D13
核对命中对象及生效分支后,在条目清单记录修改与验证证据;扫描规则记录用于整理命中位置。
扫描器下载、输入范围与报告说明
源码与标准依据
核查方式:源码与实测核对 。实测仅覆盖本条所列场景。
补充定位
VCS 内置 UVM-1.2 :uvm_recorder.svh:124–155 ;uvm_object_defines.svh:2668–2740
VCS 内置 uvm-ieee-2020-2.0 :src/vcs-uvm-ieee-2020-2.0/src/base/uvm_recorder.svh 全文件不含旧方法和字段;uvm_recorder_defines.svh:237–262
标准依据 :VCS 1.2 私有扩展;两侧 Accellera recorder 无该 getter,不作为 IEEE 标准要求。
标为“源码标注”或未注明原文核对的条款仅作定位;具体库行为以源码和实测为准。
引用代码(高亮为引用行);上方行号链接可直接定位。
src/vcs-uvm-1.2/base/uvm_recorder.svh uvm_recursion_policy_enum policy = UVM_DEFAULT_POLICY ;
// Modified by Verdi 9001505562
bit max_array_limit_check = 0 ;
longint max_array_num_limit = - 1 ;
// end
// Variable- m_ids_by_recorder
// An associative array of integers, indexed by uvm_recorders. This
// provides a unique 'id' or 'handle' for each recorder, which can be
// used to identify the recorder.
//
// By default, neither ~m_ids_by_recorder~ or ~m_recorders_by_id~ are
// used. Recorders are only placed in the arrays when the user
// attempts to determine the id for a recorder.
local static integer m_ids_by_recorder [ uvm_recorder ];
function new ( string name = "uvm_recorder" );
super . new ( name );
m_stream_dap = new ( "stream_dap" );
m_warn_null_stream = 1 ;
endfunction
// Modified by Verdi 9001505562
function longint verdi_get_array_limit ();
if ( max_array_limit_check == 0 ) begin
string val_str = "" ;
max_array_limit_check = 1 ;
if ($ value $ plusargs ( "UVM_ARRAY_NUM_LIMIT=%s" , val_str ))
max_array_num_limit = val_str . atoi ();
end
return max_array_num_limit ;
endfunction
//
// Group: Configuration API
// Function: get_stream
// Returns a reference to the stream which created
完整源码 · SHA256:c27078db07e6a49a9e91f17c4c41251a60b1d6f1bad2c8adbc959a5f7322f6c1
src/vcs-uvm-1.2/macros/uvm_object_defines.svh // --------------------
// Modified by Verdi 9001505562
`define m_uvm_record_qda_int(ARG, FLAG, SZ) \
begin \
if(!((FLAG)&UVM_NORECORD)) begin \
int sz__ = SZ; \
int max_array_num_limit = __m_uvm_status_container.recorder.verdi_get_array_limit(); \
if (max_array_num_limit < 0) begin \
if(sz__ == 0) begin \
__m_uvm_status_container.recorder.record_field_int(`"ARG`", 0, 32, UVM_DEC); \
end \
else if(sz__ < 10) begin \
foreach(ARG[i]) begin \
__m_uvm_status_container.scope.set_arg_element(`"ARG`",i); \
if ($bits(ARG[i]) > 64) \
__m_uvm_status_container.recorder.record_field(__m_uvm_status_container.scope.get(), ARG[i], $bits(ARG[i]), uvm_radix_enum'((FLAG)&UVM_RADIX)); \
else \
__m_uvm_status_container.recorder.record_field_int(__m_uvm_status_container.scope.get(), ARG[i], $bits(ARG[i]), uvm_radix_enum'((FLAG)&UVM_RADIX)); \
end \
end \
else begin \
for(int i=0; i<5; ++i) begin \
__m_uvm_status_container.scope.set_arg_element(`"ARG`", i); \
if ($bits(ARG[i]) > 64) \
__m_uvm_status_container.recorder.record_field(__m_uvm_status_container.scope.get(), ARG[i], $bits(ARG[i]), uvm_radix_enum'((FLAG)&UVM_RADIX)); \
else \
__m_uvm_status_container.recorder.record_field_int(__m_uvm_status_container.scope.get(), ARG[i], $bits(ARG[i]), uvm_radix_enum'((FLAG)&UVM_RADIX)); \
end \
for(int i=sz__-5; i<sz__; ++i) begin \
__m_uvm_status_container.scope.set_arg_element(`"ARG`", i); \
if ($bits(ARG[i]) > 64) \
__m_uvm_status_container.recorder.record_field(__m_uvm_status_container.scope.get(), ARG[i], $bits(ARG[i]), uvm_radix_enum'((FLAG)&UVM_RADIX)); \
else \
__m_uvm_status_container.recorder.record_field_int(__m_uvm_status_container.scope.get(), ARG[i], $bits(ARG[i]), uvm_radix_enum'((FLAG)&UVM_RADIX)); \
end \
end \
end \
else begin \
if(sz__ == 0) begin \
__m_uvm_status_container.recorder.record_field(`"ARG`", 0, 32, UVM_DEC); \
end \
else begin \
if (max_array_num_limit == 0) begin \
foreach(ARG[i]) begin \
__m_uvm_status_container.scope.set_arg_element(`"ARG`",i); \
if ($bits(ARG[i]) > 64) \
__m_uvm_status_container.recorder.record_field(__m_uvm_status_container.scope.get(), ARG[i], $bits(ARG[i]), uvm_radix_enum'((FLAG)&UVM_RADIX)); \
else \
__m_uvm_status_container.recorder.record_field_int(__m_uvm_status_container.scope.get(), ARG[i], $bits(ARG[i]), uvm_radix_enum'((FLAG)&UVM_RADIX)); \
end \
end \
else begin \
if (sz__ >= max_array_num_limit) begin \
for(int i=0; i<max_array_num_limit; ++i) begin \
__m_uvm_status_container.scope.set_arg_element(`"ARG`", i); \
if ($bits(ARG[i]) > 64) \
__m_uvm_status_container.recorder.record_field(__m_uvm_status_container.scope.get(), ARG[i], $bits(ARG[i]), uvm_radix_enum'((FLAG)&UVM_RADIX)); \
else \
__m_uvm_status_container.recorder.record_field_int(__m_uvm_status_container.scope.get(), ARG[i], $bits(ARG[i]), uvm_radix_enum'((FLAG)&UVM_RADIX)); \
end \
end \
else begin \
for(int i=0; i<sz__; ++i) begin \
__m_uvm_status_container.scope.set_arg_element(`"ARG`", i); \
if ($bits(ARG[i]) > 64) \
__m_uvm_status_container.recorder.record_field(__m_uvm_status_container.scope.get(), ARG[i], $bits(ARG[i]), uvm_radix_enum'((FLAG)&UVM_RADIX)); \
else \
__m_uvm_status_container.recorder.record_field_int(__m_uvm_status_container.scope.get(), ARG[i], $bits(ARG[i]), uvm_radix_enum'((FLAG)&UVM_RADIX)); \
end \
end \
end \
end \
end \
end \
end
完整源码 · SHA256:fad4b0a983286e771a025f28de582e35b21fd1dc49d8fcc5c1b2be9f4ebe99d1
src/vcs-uvm-ieee-2020-2.0/macros/uvm_recorder_defines.svh // uvm_record_qda_int
// ------------------
`define uvm_record_qda_int(ARG, RADIX,RECORDER=recorder) \
begin \
int sz__ = $size(ARG); \
if(sz__ == 0) begin \
`uvm_record_int(`"ARG`", 0, 32, UVM_DEC,RECORDER) \
end \
else if(sz__ < 10) begin \
foreach(ARG[i]) begin \
string nm__ = $sformatf("%s[%0d]", `"ARG`", i); \
`uvm_record_int(nm__, ARG[i], $bits(ARG[i]), RADIX, RECORDER) \
end \
end \
else begin \
for(int i=0; i<5; ++i) begin \
string nm__ = $sformatf("%s[%0d]", `"ARG`", i); \
`uvm_record_int(nm__, ARG[i], $bits(ARG[i]), RADIX, RECORDER) \
end \
for(int i=sz__-5; i<sz__; ++i) begin \
string nm__ = $sformatf("%s[%0d]", `"ARG`", i); \
`uvm_record_int(nm__, ARG[i], $bits(ARG[i]), RADIX, RECORDER) \
end \
end \
end
// uvm_record_qda_object
// ---------------------
完整源码 · SHA256:182dfa5e33826150d5ad29527498a0dfb0418ab868e578332308841cb4c84c00
src/vcs-uvm-ieee-2020-2.0/macros/uvm_object_defines.svh `m_uvm_field_op_begin ( UNPACK , FLAG ) \
`uvm_unpack_ ` `TYPE `` ( ARG , __local_packer__ ) \
`m_uvm_field_op_end ( UNPACK ) \
`m_uvm_field_op_begin ( RECORD , FLAG ) \
`uvm_record_qda_int ( ARG , `m_uvm_field_radix ( FLAG ), __local_recorder__ ) \
`m_uvm_field_op_end ( RECORD ) \
`m_uvm_field_op_begin ( PRINT , FLAG ) \
`uvm_print_qda_int ( TYPE , ARG , `m_uvm_field_radix ( FLAG ),, __local_printer__ ) \
`m_uvm_field_op_end ( PRINT ) \
`m_uvm_field_op_begin ( SET , FLAG ) \
if ( local_rsrc_name__ == ` "ARG`" ) begin \
`uvm_resource_builtin_int_read ( local_success__ , \
local_rsrc__ , \
local_size__ , \
this ) \
if ( local_success__ ) \
`m_uvm_ ` `TYPE ` `_resize ( ARG , local_size__ ) \
end \
else begin \
完整源码 · SHA256:072baece05e653f6811936de05739a8ff55c02651d89a9278f39cca11372a260
术语解释 · 兼容配置
返回Comparer / Printer / Packer / Recorder · 迁移清单
版本适用范围