在 SystemVerilog(SV)中,find 是动态数组(dynamic array)和队列(queue)的内置方法,用于从集合中筛选出满足指定条件的元素,并返回一个包含这些元素的新动态数组。它是数据筛选的核心工具,语法简洁且支持灵活的条件判断,广泛用于验证中对事务、信号等数据的快速过滤。
一、find 方法的基本语法
find 方法仅适用于动态数组(type arr[])和队列(type q[$]),语法格式如下:
// 基础格式:筛选满足条件的所有元素,返回动态数组
dynamic_array_type result = collection.find(condition);
// 简化格式:若条件仅判断“元素是否满足某属性”,可省略显式变量
dynamic_array_type result = collection.find(item) with (item.属性 条件);
collection:待筛选的动态数组或队列(如trans_q[$]、data_arr[])。condition:筛选条件(使用with子句指定,支持任意布尔表达式)。result:返回值,是一个动态数组(即使原集合是队列,返回结果也为动态数组),包含所有满足条件的元素。
二、核心用法分类与示例
以下基于 “存储数据包的队列” 和 “普通数据数组” 两种场景,介绍 find 的常见用法(假设数据包类 my_trans 包含 id、addr、data 字段)。
1. 基础用法:筛选满足条件的所有元素
从集合中筛选出所有符合条件的元素,返回包含这些元素的动态数组。
import uvm_pkg::*;
`include "uvm_macros.svh"
class my_trans extends uvm_sequence_item;
rand int id;
rand bit [31:0] addr;
rand bit [31:0] data;
`uvm_object_utils(my_trans)
function new(string name="my_trans"); super.new(name); endfunction
endclass
module test;
initial begin
// 1. 初始化数据包队列(待筛选)
my_trans trans_q[$];
for (int i=0; i<5; i++) begin
my_trans t = my_trans::type_id::create($sformatf("t_%0d", i));
void'(t.randomize() with {id = i; addr = 32'h1000 + i*10;});
trans_q.push_back(t);
end
// 2. 使用find筛选:addr >= 32'h1020 的数据包
my_trans filtered_trans[]; // 存储筛选结果(动态数组)
filtered_trans = trans_q.find(t) with (t.addr >= 32'h1020);
// 3. 打印筛选结果
$display("筛选出 addr >= 0x1020 的数据包(共 %0d 个):", filtered_trans.size());
foreach (filtered_trans[i]) begin
$display(" 索引[%0d]:id=%0d, addr=0x%0h", i, filtered_trans[i].id, filtered_trans[i].addr);
end
end
endmodule
输出结果(筛选出 id=2,3,4 的数据包,对应 addr=0x1020, 0x1030, 0x1040):
筛选出 addr >= 0x1020 的数据包(共 3 个):
索引[0]:id=2, addr=0x1020
索引[1]:id=3, addr=0x1030
索引[2]:id=4, addr=0x1040
2. 进阶用法:结合元素索引与复杂条件
find 支持在 with 子句中通过 item.index 引用元素在原集合中的索引,实现更精细的筛选(如 “筛选索引为偶数的元素”“筛选前 3 个元素中满足条件的项”)。
initial begin
int data_arr[] = '{10, 25, 15, 30, 20}; // 普通动态数组
// 筛选:索引为偶数(0、2、4)且元素值 >15 的元素
int result[] = data_arr.find(item, idx) with (idx % 2 == 0 && item > 15);
$display("原数组:%p", data_arr);
$display("筛选结果(索引偶数且值>15):%p", result); // 输出:'{20}(对应索引4,值20)
end
3. 特殊用法:筛选 “满足条件的元素的属性”
若只需筛选元素的某个属性(而非整个元素),可在 with 子句中返回该属性,最终结果数组的类型会自动匹配属性类型。
initial begin
my_trans trans_q[$];
// 初始化队列(同前,包含5个数据包)
// 筛选:id < 3 的数据包的 addr 属性,返回动态数组(类型为 bit [31:0])
bit [31:0] filtered_addr[] = trans_q.find(t) with (t.id < 3).addr;
$display("id < 3 的数据包的 addr:%p", filtered_addr); // 输出:'{32'h1000, 32'h1010, 32'h1020}
end
三、find 的变种方法
除了基础的 find,SV 还提供了 3 个变种方法,用于更特定的筛选场景:
| 方法名 | 功能描述 | 示例(筛选 data_arr[] = '{10,25,15,30,20}) | 结果 |
|---|---|---|---|
find_first | 筛选第一个满足条件的元素,返回单个元素(非数组) | data_arr.find_first(item) with (item > 15) | 25 |
find_last | 筛选最后一个满足条件的元素,返回单个元素(非数组) | data_arr.find_last(item) with (item > 15) | 20 |
find_index | 筛选满足条件的元素在原集合中的索引,返回索引的动态数组 | data_arr.find_index(item) with (item > 15) | '{1,3,4} |
示例:find_first 与 find_index 结合使用
initial begin
my_trans trans_q[$];
// 初始化队列(同前)
// 1. 找到第一个 addr > 0x1010 的数据包
my_trans first_trans = trans_q.find_first(t) with (t.addr > 32'h1010);
$display("第一个 addr>0x1010 的数据包:id=%0d, addr=0x%0h", first_trans.id, first_trans.addr); // id=2, addr=0x1020
// 2. 找到所有 id 为偶数的数据包的索引
int even_id_idx[] = trans_q.find_index(t) with (t.id % 2 == 0);
$display("id为偶数的数据包索引:%p", even_id_idx); // 输出:'{0,2,4}
end
四、注意事项
- 适用范围限制:
find及其变种仅支持动态数组和队列,不支持固定数组(type arr[5])、关联数组(type arr[int])或结构体数组(需先转为动态数组)。 - 返回值类型:
find/find_index返回动态数组(即使原集合是队列)。find_first/find_last返回单个元素(若无满足条件的元素,返回该类型的默认值,如int为 0,对象句柄为null)。
- 空集合处理:若原集合为空或无满足条件的元素,
find/find_index返回空动态数组(size()=0),需通过size()判断是否有结果。 - 性能考虑:
find会遍历整个集合,对于超大型集合(如百万级元素),需注意性能损耗,可结合排序(sort)后再筛选优化。
五、典型应用场景
在 UVM 验证中,find 常用于以下场景:
- 从 “实际数据包队列” 中筛选出与 “期望数据包”
id匹配的项,用于比对。 - 从 “错误事务队列” 中筛选出
addr超出范围的数据包,统计错误类型。 - 从 “寄存器配置队列” 中筛选出
write_en=1的配置项,生成配置报告。
通过 find 及其变种,可大幅简化数据筛选代码,避免手动编写 foreach 循环,提升代码可读性和效率。
2260

被折叠的 条评论
为什么被折叠?



