域名买好了怎么建网站,wordpress前端页面,珠海品牌设计公司,沧州大型企业网站建设#x1f3af; 一、两张图的关系#xff1a;整体 vs 局部
图1 图2中run_phase的放大镜
图2 (总览)对应的图1 (详细分解)run_phase (一个大盒子)拆成12个小phase#xff1a;pre_reset → reset → post_reset → pre_configure → … → post_shutdown
这就像是… 一、两张图的关系整体 vs 局部图1图2中run_phase的放大镜图2 (总览)对应的图1 (详细分解)run_phase(一个大盒子)拆成12个小phasepre_reset→reset→post_reset→pre_configure→ … →post_shutdown这就像是图2是“学校一天的作息时间表”图1是“上午8:00-11:30的语文课上老师具体怎么安排45分钟” 二、为什么需要这么多Phase生活问题如果让你一天只做一件事会怎样没法边吃饭边睡觉功能冲突没法先写作业再起床顺序混乱没法不刷牙就出门状态不对验证平台同理reset必须先让DUT被测设计复位到初始状态才能发数据configure必须先配置寄存器再启动功能main必须先完成配置再跑核心业务shutdown必须先停止数据流再检查最终结果 三、技术代码示例示例1DUT初始化对应reset系列phaseclass my_test extends uvm_test;// 1. pre_reset复位前的准备工作不耗时taskpre_reset_phase(uvm_phase phase);uvm_info(PRE_RESET,⚠️ 准备拉低复位信号...,UVM_LOW);// 配置复位信号初始为高电平dut_vif.reset1b1;endtask// 2. reset真正的复位操作消耗仿真时间taskreset_phase(uvm_phase phase);phase.raise_objection(this);uvm_info(RESET, 复位DUT开始持续100ns,UVM_LOW);(posedge dut_vif.clk);// 等待时钟上升沿dut_vif.reset1b0;// 拉低复位repeat(10)(posedge dut_vif.clk);// 保持10个周期dut_vif.reset1b1;// 释放复位phase.drop_objection(this);endtask// 3. post_reset复位后的检查不耗时taskpost_reset_phase(uvm_phase phase);uvm_info(POST_RESET,✅ 检查DUT是否从复位状态恢复,UVM_LOW);if(dut_vif.state!IDLE)begin uvm_error(POST_RESET,DUT未回到IDLE状态);end endtask endclass示例2配置寄存器对应configure系列phaseclass uart_test extends uvm_test;// pre_configure计算配置参数taskpre_configure_phase(uvm_phase phase);uvm_info(PRE_CFG, 计算波特率分频系数...,UVM_LOW);// 假设系统时钟50MHz波特率9600baud_divisor50_000_000/9600;// 结果5208endtask// configure通过总线配置DUT耗时taskconfigure_phase(uvm_phase phase);phase.raise_objection(this);uvm_info(CONFIGURE, 配置UART寄存器...,UVM_LOW);// 写波特率寄存器reg_model.baud_div.write(status,baud_divisor);// 配置8位数据无校验reg_model.ctrl.write(status,h03);phase.drop_objection(this);endtask// post_configure读取回显确认taskpost_configure_phase(uvm_phase phase);uvm_reg_data_tread_val;reg_model.baud_div.read(status,read_val);if(read_val!baud_divisor)begin uvm_error(POST_CFG,寄存器配置失败);end endtask endclass示例3主测试main_phasetaskmain_phase(uvm_phase phase);phase.raise_objection(this);uvm_info(MAIN, 开始压力测试,UVM_LOW);// 创建并启动测试序列就像运动员按指令跑步uart_tx_seq seq;sequart_tx_seq::type_id::create(seq);// 发送1000个随机数据包seq.num_trans1000;seq.start(env.agent.sequencer);// 等待所有传输完成wait(env.scoreboard.packet_count1000);uvm_info(MAIN,✅ 1000个数据包发送完成,UVM_LOW);phase.drop_objection(this);endtask场景测试一个FIFO先进先出缓冲区完整示例class fifo_test extends uvm_test;fifo_env env;// 环境包含driver, monitor, scoreboard// 1️⃣ build_phase造人、造设备functionvoidbuild_phase(uvm_phase phase);super.build_phase(phase);uvm_info(BUILD, 造FIFO测试环境 ,UVM_LOW);envfifo_env::type_id::create(env,this);// 配置FIFO深度32数据宽度32位uvm_config_db#(int)::set(this,env,fifo_depth,32);endfunction// 2️⃣ connect_phase连电线functionvoidconnect_phase(uvm_phase phase);super.connect_phase(phase);uvm_info(CONNECT, 连接monitor和scoreboard ,UVM_LOW);env.agent.monitor.item_port.connect(env.scoreboard.item_export);endfunction// 3️⃣ run_phase的12个子phase重点// reset_phase复位DUTtaskreset_phase(uvm_phase phase);phase.raise_objection(this);// 说我要干活uvm_info(RESET, 拉低复位信号100ns ,UVM_LOW);env.driver.reset_dut();// 驱动器拉低reset_n信号#100ns;// 等待100nsphase.drop_objection(this);// 说我干完了endtask// ⚙️ configure_phase配置FIFOtaskconfigure_phase(uvm_phase phase);phase.raise_objection(this);uvm_info(CONFIGURE, 配置FIFO工作模式 ,UVM_LOW);env.driver.write_reg(CONFIG_REG,8h01);// 使能FIFO#10ns;phase.drop_objection(this);endtask// main_phase压力测试核心taskmain_phase(uvm_phase phase);phase.raise_objection(this);uvm_info(MAIN, 开始疯狂写数据 ,UVM_LOW);// 连续写1000个随机数据for(inti0;i1000;i)begin env.driver.push_data($random());#5ns;end #100ns;// 等待FIFO处理完phase.drop_objection(this);endtask// report_phase打印成绩单functionvoidreport_phase(uvm_phase phase);super.report_phase(phase);uvm_info(REPORT, FIFO测试报告 ,UVM_LOW);uvm_info(REPORT,$sformatf(写入: %0d个,env.scoreboard.push_count),UVM_LOW);uvm_info(REPORT,$sformatf(读出: %0d个,env.scoreboard.pop_count),UVM_LOW);uvm_info(REPORT,$sformatf(错误: %0d个,env.scoreboard.error_count),UVM_LOW);endfunction endclass 四、时序解剖精确到ns时间轴可视化时间: 0ns 50ns 100ns 150ns 200ns 250ns |-------|-------|-------|-------|-------|→ Phase: [build,connect,start_of_simulation] (瞬间完成) [ reset_phase: 0-50ns ] // 复位信号 [ post_reset, pre_configure ] (各5ns) [ configure_phase: 60-80ns ] // 寄存器配置 [ post_configure, pre_main ] (各5ns) [ main_phase: 90-240ns ] // 核心测试 ❗最长❗ [ post_main, pre_shutdown ] (各5ns) [ shutdown_phase: 250-300ns ] // 收尾 [ extract,check,report,final ] (瞬间完成)关键观察build/connect在0ns就瞬间做完了main_phase占据了**80%**的仿真时间其他phase都是准备工作或收尾工作⚠️ 五、常见错误与调试技巧错误1在reset_phase发数据taskreset_phase(uvm_phase phase);phase.raise_objection(this);driver.send_data();// ❌ 错误DUT还没准备好#100ns;phase.drop_objection(this);endtask后果数据丢失测试无意义正确做法taskmain_phase(uvm_phase phase);phase.raise_objection(this);driver.send_data();// ✅ 正确在main_phase发数据phase.drop_objection(this);endtask错误2多个组件同时raise objection// env.driver:taskmain_phase(uvm_phase phase);phase.raise_objection(this);// 1#100ns;phase.drop_objection(this);// -1endtask// env.scoreboard:taskmain_phase(uvm_phase phase);phase.raise_objection(this);// 1 (现在总数2!)#50ns;phase.drop_objection(this);// -1 (还剩1个)endtask结果仿真跑到150ns才结束等所有objection都drop调试技巧打印objection计数uvm_info(OBJ, $sformatf(Objections: %0d, phase.get_objection_count()), UVM_DEBUG);错误3为什么要拆这么细为什么不直接用一个大run_phase搞定所有事设计哲学答案为了可重用性和可维护性场景对比❌ 粗暴方式所有代码塞在run_phasetaskrun_phase(uvm_phase phase);phase.raise_objection(this);// 复位100行代码dut_vif.reset0;#100;dut_vif.reset1;// 配置200行代码reg_model.baud_div.write(...);reg_model.ctrl.write(...);// 测试300行代码seq.start(...);phase.drop_objection(this);endtask问题如果10个测试都要复位代码重复10次哪天复位信号从低有效改成高有效要改10个地方✅ 优雅方式按phase拆分// 定义一个base_test专门处理复位和配置class base_test extends uvm_test;taskreset_phase(uvm_phase phase);// 统一复位逻辑1处维护endtask taskconfigure_phase(uvm_phase phase);// 统一配置逻辑1处维护endtask endclass// 具体测试只关心main_phaseclass test1 extends base_test;taskmain_phase(uvm_phase phase);// 只写test1特有的测试endtask endclass class test2 extends base_test;taskmain_phase(uvm_phase phase);// 只写test2特有的测试endtask endclass好处修改复位逻辑只改base_test所有子类自动生效 六、设计模式如何优雅地使用Phase通用测试模板class your_test extends uvm_test;your_env env;// 构建环境functionvoidbuild_phase(uvm_phase phase);super.build_phase(phase);envyour_env::type_id::create(env,this);endfunction// 复位DUT必需taskreset_phase(uvm_phase phase);phase.raise_objection(this);uvm_info(RESET, 复位DUT ,UVM_LOW);// TODO: 拉低复位信号#100ns;phase.drop_objection(this);endtask// 配置DUT可选taskconfigure_phase(uvm_phase phase);phase.raise_objection(this);uvm_info(CONFIGURE, 配置DUT ,UVM_LOW);// TODO: 写寄存器phase.drop_objection(this);endtask// 主测试核心taskmain_phase(uvm_phase phase);phase.raise_objection(this);uvm_info(MAIN, 开始测试 ,UVM_LOW);// TODO: 启动sequenceyour_sequence seq;seqyour_sequence::type_id::create(seq);seq.start(env.agent.sequencer);// 等待完成wait(env.scoreboard.all_done());phase.drop_objection(this);endtask// 打印报告functionvoidreport_phase(uvm_phase phase);super.report_phase(phase);uvm_info(REPORT, 测试完成 ,UVM_LOW);// TODO: 统计结果endfunction endclass推荐模板适用于90%的项目class my_base_test extends uvm_test;// 1. 【固定套路】在base_test中实现通用逻辑virtual taskreset_phase(uvm_phase phase);// 所有测试都需要的复位endtask virtual taskconfigure_phase(uvm_phase phase);// 所有测试都需要的配置endtask// 2. 【留空给子类】main_phase声明为virtual但不实现virtual taskmain_phase(uvm_phase phase);uvm_fatal(MAIN,子类必须重写main_phase);endtask endclass// 具体测试只需关注main_phaseclass test_tx_only extends my_base_test;taskmain_phase(uvm_phase phase);// 只测试发送功能endtask endclass class test_rx_only extends my_base_test;taskmain_phase(uvm_phase phase);// 只测试接收功能endtask endclass 七、互动题目检验掌握程度选择题DUT必须在哪个phase后处于ready状态A) build_phaseB) reset_phaseC) main_phaseD) report_phase答案B) reset_phase后DUT才复位完成核心业务逻辑应该放在哪个phaseA) configure_phaseB) main_phaseC) shutdown_phaseD) final_phase答案B) main_phase是核心测试阶段提取仿真结果应该在哪个phaseA) extract_phaseB) check_phaseC) report_phaseD) final_phase答案A) extract_phase专门收集数据 八、终极记忆口诀“Build环境Connect线路Reset清零Configure配置Main干活Report汇报” 记忆卡片打印贴墙上Phase类型作用耗时常见用途build创建❌ 不耗时new()组件connect连接❌ 不耗时port.connect()reset复位✅ 耗时拉低复位信号configure配置✅ 耗时写寄存器main测试✅ 耗时发激励、收响应extract提取❌ 不耗时收集覆盖率check检查❌ 不耗时assert检查report报告❌ 不耗时打印日志