uvm_bit_bash源码解析
2026/7/10 9:10:17 网站建设 项目流程

核心测试类:uvm_reg_single_bit_bash_seq

这个类包含了对一个寄存器进行 bit bash 测试的所有逻辑。bash_kth_bit任务实现了核心的读写校验流程。

systemverilog

// 文件: uvm_reg_bit_bash_seq.svh (概念性示意) //------------------------------------------------------------------------------ // 类: uvm_reg_single_bit_bash_seq // 功能: 对单个寄存器执行 bit bash 测试。 //------------------------------------------------------------------------------ class uvm_reg_single_bit_bash_seq extends uvm_reg_sequence #(uvm_sequence #(uvm_reg_item)); // 变量: rg // 待测试的寄存器句柄 uvm_reg rg; // 任务: body // 序列执行入口 virtual task body(); uvm_reg_field fields[$]; // 【关键队列1】存放寄存器所有字段的句柄 string mode[`UVM_REG_DATA_WIDTH]; // 【关键数组2】记录每个 bit 的访问属性 uvm_reg_map maps[$]; // 存放寄存器所在的所有地址映射 bit dc_mask[`UVM_REG_DATA_WIDTH]; // 记录每个 bit 是否应被忽略(Don't Care) int n_bits; string field_access; if (rg == null) begin `uvm_error("UVMRegBitBashSeq", "No register specified") return; end // 1. 检查资源数据库,跳过该寄存器的测试[citation:2][citation:4] if (uvm_resource_db#(bit)::get_by_name({"REG::", rg.get_full_name()}, "NO_REG_TESTS", 0) != null || uvm_resource_db#(bit)::get_by_name({"REG::", rg.get_full_name()}, "NO_REG_BIT_BASH_TEST", 0) != null) return; n_bits = rg.get_n_bytes() * 8; // 计算寄存器总位数 // 2. 获取寄存器所有字段的句柄,存入 fields[$] 队列[citation:1] rg.get_fields(fields); // 3. 获取寄存器所在的所有地址映射,存入 maps[$] 队列[citation:1] rg.get_maps(maps); // 4. 遍历每个地址映射进行测试 foreach (maps[j]) begin int next_lsb = 0; // 清空 mode 和 dc_mask 数组 // ... // 5. 分析该寄存器在每个 map 中的字段布局 foreach (fields[k]) begin // 获取当前字段的访问策略(如 RO, RW, WO 等)[citation:8] field_access = fields[k].get_access(maps[j]); // 获取当前字段是否被标记为不进行比较(UVM_NO_CHECK)[citation:1][citation:8] int dc = (fields[k].get_compare() == UVM_NO_CHECK); // 获取字段最低位(LSB)的位置[citation:8] int lsb = fields[k].get_lsb_pos(); // 获取字段的位宽[citation:8] int w = fields[k].get_n_bits(); // 【关键】处理只写(WO)等无法正确读回的字段 // 将它们标记为 dc=1,在后续测试中跳过[citation:1][citation:8] if (field_access inside {"WO", "WOC", "WOS", "WO1", "NOACCESS"}) begin dc = 1; end // 填充字段之间的未定义位(通常视为只读 "RO")[citation:1] while (next_lsb < lsb) begin mode[next_lsb] = "RO"; next_lsb++; end // 填充该字段的所有位 for (int b = 0; b < w; b++) begin // mode 数组记录每个 bit 的访问类型[citation:1] mode[next_lsb] = field_access; // dc_mask 数组记录每个 bit 是否应被忽略[citation:1][citation:8] dc_mask[next_lsb] = dc; next_lsb++; end end // 填充字段之后的剩余未定义位 while (next_lsb < `UVM_REG_DATA_WIDTH) begin mode[next_lsb] = "RO"; next_lsb++; end `uvm_info("UVMRegBitBashSeq", $sformatf("Verifying bits in register %s in map \"%s\"...", rg.get_full_name(), maps[j].get_full_name()), UVM_LOW) // 6. 对寄存器的每个 bit 执行 bash 操作 for (int k = 0; k < n_bits; k++) begin // 如果该 bit 被标记为 dc_mask,则跳过测试[citation:1][citation:8] if (dc_mask[k]) continue; // 将 dc_mask 数组转换为位掩码(便于与读回值进行 & 操作) uvm_reg_data_t dc_mask_int = 0; for (int i = 0; i < `UVM_REG_DATA_WIDTH; i++) dc_mask_int |= (dc_mask[i] << i); // 调用核心 bit bash 任务[citation:1][citation:8] bash_kth_bit(rg, k, mode[k], maps[j], dc_mask_int); end end endtask // 任务: bash_kth_bit // 功能: 对寄存器 rg 的第 k 个 bit 执行一次完整的 0->1 和 1->0 测试[citation:1][citation:8] virtual task bash_kth_bit(uvm_reg rg, int k, string mode, uvm_reg_map map, uvm_reg_data_t dc_mask); uvm_status_e status; uvm_reg_data_t val, exp, v; bit bit_val; `uvm_info("UVMRegBitBashSeq", $sformatf("...Bashing %s bit #%0d", mode, k), UVM_HIGH) // 执行两次循环:第一次将该位写 1,第二次写 0[citation:1][citation:8] repeat (2) begin // 1. 获取当前寄存器的镜像值(期望值)[citation:1][citation:8] val = rg.get(); v = val; // 保存初始值,用于错误报告 exp = val; // 保存期望值 // 2. 翻转第 k 位,生成新值[citation:1][citation:8] val ^= (1 << k); // 等价于 val[k] = ~val[k] bit_val = (val >> k) & 1; // 记录翻转后的位值 // 3. 通过前门(FRONTDOOR)将新值写入硬件寄存器[citation:1][citation:8] rg.write(status, val, UVM_FRONTDOOR, map, this); if (status != UVM_IS_OK) begin `uvm_error("UVMRegBitBashSeq", $sformatf("Write failed...")) end // 4. 获取写入后的期望值(模型镜像值不会自动更新) // 这里将期望值与 dc_mask 的取反进行 & 操作,忽略不检查的位[citation:1][citation:8] exp = rg.get() & ~dc_mask; // 5. 通过前门从硬件寄存器读回实际值[citation:1][citation:8] rg.read(status, val, UVM_FRONTDOOR, map, this); if (status != UVM_IS_OK) begin `uvm_error("UVMRegBitBashSeq", $sformatf("Read failed...")) end // 6. 将读回的实际值也应用 dc_mask,然后与期望值比对[citation:1][citation:8] val &= ~dc_mask; if (val !== exp) begin `uvm_error("UVMRegBitBashSeq", $sformatf("Mismatch! Writing %b to bit #%0d of register %s (initial 'h%h) yielded 'h%h instead of 'h%h", bit_val, k, rg.get_full_name(), v, val, exp)) end end endtask endclass

💎 总结

  1. fields[$]队列:在body()任务中通过rg.get_fields(fields)填充,用于遍历寄存器中的所有字段,获取它们的访问属性(get_access)和位置信息(get_lsb_pos),从而构建出dc_mask数组和mode数组。

  2. string mode[]数组:是一个以位索引为键的关联数组(大小为UVM_REG_DATA_WIDTH)。它记录了寄存器中每个 bit的访问类型(如 "RO", "RW", "WO"),主要用于日志输出和可能的扩展判断。这个数组是在遍历fields[$]的过程中被填充的。

  3. 测试核心bash_kth_bit任务通过“读镜像值 -> 翻转特定位 -> 前门写入 -> 前门读回 -> 比对(应用dc_mask)”的流程,逐个验证每个位的独立读写功能,从而发现位粘连或地址粘连问题。

  4. 跳过逻辑:通过uvm_resource_db中的NO_REG_TESTSNO_REG_BIT_BASH_TEST标记跳过整个寄存器或block;通过遍历fields[$]计算出的dc_mask跳过不可测试的位(如只写、无检查字段)。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询