
核心测试类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 是否应被忽略Dont 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等无法正确读回的字段 // 将它们标记为 dc1在后续测试中跳过[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 总结fields[$]队列在body()任务中通过rg.get_fields(fields)填充用于遍历寄存器中的所有字段获取它们的访问属性get_access和位置信息get_lsb_pos从而构建出dc_mask数组和mode数组。string mode[]数组是一个以位索引为键的关联数组大小为UVM_REG_DATA_WIDTH。它记录了寄存器中每个 bit的访问类型如 RO, RW, WO主要用于日志输出和可能的扩展判断。这个数组是在遍历fields[$]的过程中被填充的。测试核心bash_kth_bit任务通过“读镜像值 - 翻转特定位 - 前门写入 - 前门读回 - 比对应用dc_mask”的流程逐个验证每个位的独立读写功能从而发现位粘连或地址粘连问题。跳过逻辑通过uvm_resource_db中的NO_REG_TESTS或NO_REG_BIT_BASH_TEST标记跳过整个寄存器或block通过遍历fields[$]计算出的dc_mask跳过不可测试的位如只写、无检查字段。