【SystemVerilog 验证】第六章 随机化 📅 2026/7/22 9:06:15 一、本章概述1. 本章学习目标本章是 SystemVerilog 约束随机测试完整核心章节全书共 45 张配图分层讲解随机语法、约束、回调、内联随机、软硬约束、数组随机、种子管理、工程架构承接第五章面向对象类基础是 UVM 激励生成底层核心。 完整学习目标区分rand/randc掌握静态 / 动态数组、队列的随机修饰规则掌握randomize()返回逻辑、SV_RAND_CHECK工程校验宏吃透全部约束语法inside、蕴含-、双向-、dist权重、solve before优先级区分硬约束 hard constraint、软约束 soft constraint掌握内联约束with学会randomize with()内联随机、std::randomize()局部无类随机掌握随机回调函数pre_randomize()/post_randomize()执行时机与工程用法理解约束函数、约束块重载、子类重写父类约束的语法掌握rand_mode()/constraint_mode()进阶开关、局部关闭约束数组、动态队列、结构体的约束随机写法遍历类 randc 数组特性对象独立 PRNG 随机流、srandom()种子控制、多线程随机隔离Cfg 分层配置类工业标准架构约束冲突排查、随机失败调试方法。2. 核心术语对照表术语全称工程作用CRTConstraint Random Test 约束随机测试自动生成海量合法激励替代定向用例rand普通随机变量每次随机独立取值允许重复randc周期随机变量遍历全部取值后循环保证全覆盖Hard Constraint硬约束强制满足冲突直接 randomize 失败Soft Constraint软约束优先满足无解时自动放弃不会报错Inline Randomize内联随机单次随机临时覆盖约束不修改类原生代码PRNG伪随机数发生器每个类实例独立随机流互不干扰Pre/Post Randomize随机前后回调函数随机前初始化、随机后数据修正、打印std::randomize局部随机函数无需定义 class直接随机局部变量二、随机变量基础1. rand 基础随机变量特性每次randomize()独立生成数值无遍历逻辑允许重复适用于数据包、随机延时、无全覆盖要求信号。class Packet; rand bit [7:0] data; // 普通随机字节 rand bit [3:0] delay; endclass2. randc 周期随机变量核心规则缓存变量全部合法取值一轮内不重复全部数值遍历完成后重置序列重新循环若取值集合数组、枚举动态修改遍历序列立刻清空重置。 适用场景指令枚举、通道号、端口选择保证功能全覆盖。typedef enum {RD,WR,ERR,IDLE} cmd_e; class Trans; randc cmd_e cmd; // 循环遍历4种指令不重复 endclass3. 数组 / 动态队列 rand/randc 修饰定长数组rand bit [7:0] payload[8];数组每个元素独立随机randc 动态数组randc bit [2:0] port[$];队列内数值全局遍历静态变量禁止 rand/randc 修饰静态变量全局共享随机流冲突4. rand vs randc 完整对比表类型取值规则动态数组行为适用场景缺陷rand独立随机可重复元素互不影响数据载荷、延时无法全覆盖场景randc一轮无重复遍历循环整个队列统一遍历枚举、指令、通道数组修改重置序列三、randomize () 函数与随机校验宏1. randomize () 返回规则返回 1全部硬约束满足随机成功返回 0硬约束冲突、无解、无 rand 变量、约束矛盾禁止在new()构造函数内调用randomize()破坏种子初始化。2. SV_RAND_CHECK 工程校验宏随机失败自动打印文件名、代码行号直接终止仿真快速定位约束冲突。define SV_RAND_CHECK(r) do begin if(!(r)) begin $display(%s:%0d 随机化失败,__FILE__,__LINE__); $finish(1); end end while(0) // 使用示例 Trans tr new(); SV_RAND_CHECK(tr.randomize());3. std::randomize () 局部无类随机无需创建 class直接随机函数内局部变量适合简单临时激励。bit [15:0] addr; if(!std::randomize(addr) with {addr inside {[0:1024]};}) begin $error(局部随机失败); end四、约束完整语法体系1. inside 范围约束限定变量合法取值支持连续区间、离散集合、取反排除constraint c_len { pkt_len inside {[16:1024]}; // 连续区间 port inside {0,1,3,5}; // 离散端口 !(addr inside {[512:1024]});// 取反排除区间 }2. 条件蕴含约束-/-A - BA 成立时 B 必须满足A 不成立无限制-双向等价A、B 真假完全同步constraint c_write { // 写使能为1时地址最高位必须为1 wr_en - addr[31]1b1; // 双向等价err信号和cmdERR同时生效 err - (cmd ERR); }等价 if 写法constraint c_write { if(wr_en) addr[31]1b1; }3. dist 权重概率约束两种分配符控制不同数值出现概率用于构造异常测试场景:区间内每个数值分配对应权重:/整个区间整体分配权重内部均分rand bit [2:0] cmd; constraint c_dist { cmd dist { WR : 10, RD : 10, ERR : 2 // 错误指令低概率边界测试 }; }4. solve...before 求解优先级仅改变随机组合出现概率不会新增 / 删除合法解增加仿真运算开销谨慎使用。solve cmd before data; // 优先随机cmd再求解data5. 并行约束核心特性约束块内所有表达式并行同时求解不存在代码上下执行顺序不能用顺序逻辑书写约束。五、硬约束 vs 软约束1. Hard Constraint 硬约束所有常规约束均为硬约束求解器必须满足若存在冲突randomize()直接返回 0随机失败。2. Soft Constraint 软约束soft语法soft 表达式;规则优先满足软约束若无同时满足软硬约束的解求解器自动放弃软约束仅保证硬约束成立不会随机失败。 典型用途期望数值、推荐延时、优选地址不强制卡死。constraint c_delay { soft delay inside {[1:10]}; // 优先1~10无解则允许任意值 pkt_len inside {[8:2048]}; // 硬约束必须遵守 }六、内联随机 with 临时约束无需修改类内部原生约束单次随机临时叠加 / 覆盖约束灵活生成特殊测试用例。1. randomize () with 基础用法Packet pkt new(); // 本次随机强制data0xff仅单次生效不修改类约束 SV_RAND_CHECK(pkt.randomize() with {data 8hff;});2. 内联约束覆盖原有 dist 权重tr.randomize() with { cmd dist {ERR:20}; }; // 临时拉高错误指令概率七、随机回调函数 pre_randomize /post_randomize1. 完整执行时序随机执行完整流程randomize()调用 → pre_randomize () 执行 → 求解约束随机变量 → post_randomize () 执行 → 返回结果2. pre_randomize()随机前预处理清空队列、初始化标记、重置状态virtual function void pre_randomize(); super.pre_randomize(); payload.delete(); // 随机前清空数据包队列 endfunction3. post_randomize()随机后数据修正、格式对齐、打印随机信息、计算衍生信号virtual function void post_randomize(); crc calc_crc(data); // 根据随机data计算校验值 $display(随机数据包 data%h,data); endfunction关键特性子类可重写回调函数必须调用super.xxx()保留父类逻辑八、约束控制开关rand_mode constraint_mode1. rand_mode () 变量随机开关控制单个 rand 变量是否参与随机关闭后变量值固定仅校验约束。obj.var.rand_mode(1)开启默认obj.var.rand_mode(0)关闭随机pkt.data.rand_mode(0); // data不再随机固定原值 pkt.randomize();2. constraint_mode () 约束块开关全局 / 单独关闭某一组约束块快速切换正常 / 边界测试场景tr.c_err.constraint_mode(0); // 关闭错误指令约束只生成正常激励九、约束重载与子类重写约束子类可定义同名约束块直接覆盖父类约束逻辑父类约束无法删除仅能重写或通过constraint_mode(0)关闭class ErrTrans extends Trans; constraint c_cmd { cmd ERR; } // 重写父类cmd约束只生成错误指令 endclass十、数组、动态队列约束随机foreach 循环约束数组每个元素范围动态队列可约束长度、内部元素取值rand bit [7:0] payload[$]; constraint c_pkt { payload.size() inside {[4:16]}; // 队列长度约束 foreach(payload[i]) payload[i] inside {[0:255]}; }十一、独立 PRNG 随机流与种子管理1. 独立随机流机制每个 class 实例、并行 fork 线程自带独立 PRNGA 对象随机操作完全不影响 B 对象多端口并行激励无干扰。2. srandom () 手动固定种子为对象单独指定种子固定随机序列100% 复现仿真 bug 激励Trans tr new(); tr.srandom(6688); // 固定当前对象随机种子3. 层次化种子工程规范顶层传入全局种子所有子对象自动衍生独立种子固定顶层种子整套仿真激励完全可复现。十二、Cfg 分层配置类工业完整架构承接第六章工程实践章节UVM config_db 底层原型分离配置参数与激励生成平台高复用。1. 完整分层代码// 1.配置类封装所有可随机DUT参数 class EthCfg; rand bit [3:0] port_en; rand bit [47:0] mac[4]; rand uint frame_num; constraint c_mac { foreach(mac[i]) mac[i][41:40]2b00; } constraint c_frame { frame_num inside {[1:100]}; } endclass // 2.环境类管理配置、激励发生器 class Env; EthCfg cfg; EthGen gen[4]; function new(); cfg new(); endfunction function void gen_cfg(); SV_RAND_CHECK(cfg.randomize()); endfunction function void build(); foreach(gen[i]) gen[i] new(); endfunction task run(); foreach(gen[i]) if(cfg.port_en[i]) fork gen[i].run(); join_none endtask endclass // 顶层测试程序 program test; Env env; initial begin env new(); env.gen_cfg(); env.cfg.port_en 1; // 手动覆盖配置参数 env.build(); env.run(); end endprogram2. 工程强制规范所有 Cfg 参数修改必须在build()函数执行前build 完成后驱动实例已创建修改失效。十三、随机化失败调试、约束冲突排查1. 常见失败原因硬约束互相矛盾无合法解randc 数组动态修改遍历序列清空导致无解solve before 优先级过度限制无匹配组合约束内变量未加 rand/randc 修饰。2. 调试方法使用SV_RAND_CHECK定位报错代码行临时关闭部分约束块constraint_mode (0)二分定位冲突约束改用软约束规避无解场景打印 pre/post 随机函数查看变量初始值干扰。十四、本章全部易错点汇总randc 数组、队列修改元素后遍历序列直接重置约束块并行求解不能按上下顺序书写依赖逻辑solve before 仅改变概率无法增减合法解仿真速度下降soft 软约束仅在硬约束无解时自动失效不会触发随机失败内联 randomize with 仅单次生效不永久修改类约束pre/post_randomize 重写必须调用 super 父类函数否则父类逻辑丢失Cfg 配置参数修改必须放在 build 阶段之前全局共用 PRNG 会造成多通道激励互相干扰必须使用对象独立种子。