当前位置: 首页 > news >正文

10.【学习】SPI UART 验证环境与测试用例

SPI & UART 完整UVM验证环境与测试用例

以下验证环境,包含:配置类+顶层Env+基础Test+5个实用测试用例,与之前提供的事务类、Driver、Monitor、Agent无缝对接。


一、配置类(Config)

用于统一配置SPI和UART的参数,支持在test中动态修改。

class spi_uart_config extends uvm_object;`uvm_object_utils(spi_uart_config)// SPI 配置参数bit spi_active=1'b1;// 是否启用SPI agentspi_transaction::spi_mode_e spi_default_mode=spi_transaction::MODE_0;intunsignedspi_default_clk_div=10;// 100MHz系统时钟 → 10MHz SPI时钟intunsignedspi_max_clk_div=255;intunsignedspi_min_clk_div=2;// UART 配置参数bit uart_active=1'b1;// 是否启用UART agentuart_transaction::parity_e uart_default_parity=uart_transaction::PARITY_NONE;intunsigneduart_default_baud_div=868;// 100MHz系统时钟 → 115200波特率intunsigneduart_default_stop_bits=1;functionnew(string name="spi_uart_config");super.new(name);endfunction endclass

二、顶层环境类(Env)

集成SPI和UART agent,以及可选的scoreboard和reference model。

class spi_uart_env extends uvm_env;`uvm_component_utils(spi_uart_env)// 配置对象spi_uart_config cfg;// Agentspi_agent spi_agt;uart_agent uart_agt;// 分析端口uvm_analysis_port #(spi_transaction)spi_ap;uvm_analysis_port #(uart_transaction)uart_ap;functionnew(string name="spi_uart_env",uvm_component parent=null);super.new(name,parent);spi_ap=new("spi_ap",this);uart_ap=new("uart_ap",this);endfunction virtual functionvoidbuild_phase(uvm_phase phase);super.build_phase(phase);// 获取配置对象if(!uvm_config_db#(spi_uart_config)::get(this,"","cfg",cfg))begin `uvm_fatal("NO_CFG","无法获取spi_uart_config配置对象")end// 创建SPI agentif(cfg.spi_active)begin spi_agt=spi_agent::type_id::create("spi_agt",this);uvm_config_db#(uvm_active_passive_enum)::set(this,"spi_agt","is_active",UVM_ACTIVE);end// 创建UART agentif(cfg.uart_active)begin uart_agt=uart_agent::type_id::create("uart_agt",this);uvm_config_db#(uvm_active_passive_enum)::set(this,"uart_agt","is_active",UVM_ACTIVE);end `uvm_info("ENV","SPI-UART验证环境构建完成",UVM_MEDIUM)endfunction virtual functionvoidconnect_phase(uvm_phase phase);super.connect_phase(phase);// 连接分析端口if(cfg.spi_active)begin spi_agt.mon.ap.connect(spi_ap);endif(cfg.uart_active)begin uart_agt.mon.ap.connect(uart_ap);end// 配置monitor参数if(cfg.spi_active)begin spi_agt.mon.set_config(cfg.spi_default_mode,cfg.spi_default_clk_div);endif(cfg.uart_active)begin uart_agt.mon.set_config(cfg.uart_default_baud_div,cfg.uart_default_parity,cfg.uart_default_stop_bits);end endfunction virtual functionvoidend_of_elaboration_phase(uvm_phase phase);super.end_of_elaboration_phase(phase);uvm_top.print_topology();// 打印UVM拓扑结构endfunction endclass

三、基础测试类(Base Test)

所有测试用例的基类,负责创建环境和配置。

class base_test extends uvm_test;`uvm_component_utils(base_test)spi_uart_env env;spi_uart_config cfg;functionnew(string name="base_test",uvm_component parent=null);super.new(name,parent);endfunction virtual functionvoidbuild_phase(uvm_phase phase);super.build_phase(phase);// 创建并设置配置对象cfg=spi_uart_config::type_id::create("cfg");uvm_config_db#(spi_uart_config)::set(this,"env","cfg",cfg);// 创建环境env=spi_uart_env::type_id::create("env",this);// 设置仿真超时时间(10ms)uvm_top.set_timeout(10ms);endfunction virtual functionvoidend_of_elaboration_phase(uvm_phase phase);super.end_of_elaboration_phase(phase);// 打印配置信息`uvm_info("TEST","测试配置信息:",UVM_MEDIUM)`uvm_info("TEST",$sformatf("SPI默认模式:%s",cfg.spi_default_mode.name()),UVM_MEDIUM)`uvm_info("TEST",$sformatf("UART默认波特率分频:%0d",cfg.uart_default_baud_div),UVM_MEDIUM)endfunction virtual taskrun_phase(uvm_phase phase);super.run_phase(phase);phase.raise_objection(this);// 等待复位完成#100ns;// 运行测试用例(子类重写)run_test_case();// 等待所有事务完成#1ms;phase.drop_objection(this);endtask// 测试用例入口(子类重写)virtual taskrun_test_case();`uvm_info("TEST","运行基础测试用例",UVM_MEDIUM)endtask endclass

四、实用测试用例集合

1. 冒烟测试(Smoke Test)

验证最基本的功能是否正常工作,是所有测试的第一步。

class smoke_test extends base_test;`uvm_component_utils(smoke_test)functionnew(string name="smoke_test",uvm_component parent=null);super.new(name,parent);endfunction virtual taskrun_test_case();spi_transaction spi_tr;uart_transaction uart_tr;`uvm_info("SMOKE_TEST","开始SPI冒烟测试",UVM_MEDIUM)// SPI 简单读写测试for(inti=0;i<5;i++)begin spi_tr=spi_transaction::type_id::create("spi_tr");// 固定参数,确保可重复性spi_tr.mode=cfg.spi_default_mode;spi_tr.clk_div=cfg.spi_default_clk_div;spi_tr.mosi_data=new[1];spi_tr.mosi_data[0]=8'hA5+i;spi_tr.data_delay=new[1];spi_tr.data_delay[0]=0;spi_tr.cs_low_delay=1;spi_tr.cs_high_delay=1;spi_tr.start(env.spi_agt.seqr);#1us;end `uvm_info("SMOKE_TEST","开始UART冒烟测试",UVM_MEDIUM)// UART 简单发送测试for(inti=0;i<5;i++)begin uart_tr=uart_transaction::type_id::create("uart_tr");uart_tr.dir=uart_transaction::TX;uart_tr.data=8'h5A+i;uart_tr.parity_type=cfg.uart_default_parity;uart_tr.stop_bits=cfg.uart_default_stop_bits;uart_tr.baud_rate_div=cfg.uart_default_baud_div;uart_tr.start(env.uart_agt.seqr);#100us;// 等待UART传输完成end `uvm_info("SMOKE_TEST","冒烟测试完成",UVM_MEDIUM)endtask endclass

2. SPI 全模式测试

验证SPI所有四种工作模式是否正常。

class spi_all_mode_test extends base_test;`uvm_component_utils(spi_all_mode_test)functionnew(string name="spi_all_mode_test",uvm_component parent=null);super.new(name,parent);endfunction virtual taskrun_test_case();spi_transaction spi_tr;spi_transaction::spi_mode_e modes[]={spi_transaction::MODE_0,spi_transaction::MODE_1,spi_transaction::MODE_2,spi_transaction::MODE_3};foreach(modes[i])begin `uvm_info("SPI_MODE_TEST",$sformatf("测试SPI模式:%s",modes[i].name()),UVM_MEDIUM)// 配置monitor为当前模式env.spi_agt.mon.set_config(modes[i],cfg.spi_default_clk_div);// 发送多个事务for(intj=0;j<10;j++)begin spi_tr=spi_transaction::type_id::create("spi_tr");spi_tr.randomize()with{mode==modes[i];clk_div==cfg.spi_default_clk_div;mosi_data.size()inside{[1:8]};};spi_tr.start(env.spi_agt.seqr);#1us;end end `uvm_info("SPI_MODE_TEST","SPI全模式测试完成",UVM_MEDIUM)endtask endclass

3. UART 全配置测试

验证UART所有波特率、校验方式和停止位的组合。

class uart_full_config_test extends base_test;`uvm_component_utils(uart_full_config_test)functionnew(string name="uart_full_config_test",uvm_component parent=null);super.new(name,parent);endfunction virtual taskrun_test_case();uart_transaction uart_tr;uart_transaction::parity_e parities[]={uart_transaction::PARITY_NONE,uart_transaction::PARITY_EVEN,uart_transaction::PARITY_ODD};intstop_bits[]={1,2,3};intbaud_divs[]={868,434,217,108};// 115200, 230400, 460800, 921600foreach(baud_divs[i])beginforeach(parities[j])beginforeach(stop_bits[k])begin `uvm_info("UART_CONFIG_TEST",$sformatf("测试UART配置:波特率分频=%0d, 校验=%s, 停止位=%0d",baud_divs[i],parities[j].name(),stop_bits[k]),UVM_MEDIUM)// 配置monitorenv.uart_agt.mon.set_config(baud_divs[i],parities[j],stop_bits[k]);// 发送多个字节for(intl=0;l<5;l++)begin uart_tr=uart_transaction::type_id::create("uart_tr");uart_tr.randomize()with{dir==uart_transaction::TX;parity_type==parities[j];stop_bits==stop_bits[k];baud_rate_div==baud_divs[i];};uart_tr.start(env.uart_agt.seqr);#200us;end end end end `uvm_info("UART_CONFIG_TEST","UART全配置测试完成",UVM_MEDIUM)endtask endclass

4. 随机测试(Random Test)

生成大量随机事务,快速覆盖各种场景。

class random_test extends base_test;`uvm_component_utils(random_test)// 测试参数intnum_spi_trans=100;intnum_uart_trans=100;functionnew(string name="random_test",uvm_component parent=null);super.new(name,parent);endfunction virtual taskrun_test_case();`uvm_info("RANDOM_TEST","开始随机测试",UVM_MEDIUM)// 并行运行SPI和UART随机测试forkrun_spi_random();run_uart_random();join `uvm_info("RANDOM_TEST","随机测试完成",UVM_MEDIUM)endtask virtual taskrun_spi_random();spi_transaction spi_tr;for(inti=0;i<num_spi_trans;i++)begin spi_tr=spi_transaction::type_id::create("spi_tr");// 完全随机,覆盖所有约束if(!spi_tr.randomize())begin `uvm_error("RANDOM_TEST","SPI事务随机化失败")end spi_tr.start(env.spi_agt.seqr);#1us;end endtask virtual taskrun_uart_random();uart_transaction uart_tr;for(inti=0;i<num_uart_trans;i++)begin uart_tr=uart_transaction::type_id::create("uart_tr");// 完全随机,覆盖所有约束if(!uart_tr.randomize())begin `uvm_error("RANDOM_TEST","UART事务随机化失败")end uart_tr.start(env.uart_agt.seqr);#100us;end endtask endclass

5. 错误注入测试(Error Injection Test)

验证DUT对各种错误情况的处理能力。

class error_injection_test extends base_test;`uvm_component_utils(error_injection_test)functionnew(string name="error_injection_test",uvm_component parent=null);super.new(name,parent);endfunction virtual taskrun_test_case();spi_transaction spi_tr;uart_transaction uart_tr;`uvm_info("ERROR_TEST","开始SPI错误注入测试",UVM_MEDIUM)// SPI 错误注入:不同时钟分频和模式的组合for(inti=0;i<20;i++)begin spi_tr=spi_transaction::type_id::create("spi_tr");spi_tr.randomize()with{clk_div inside{[2:20]};// 测试不同时钟频率mosi_data.size()inside{[1:16]};};spi_tr.start(env.spi_agt.seqr);#1us;end `uvm_info("ERROR_TEST","开始UART错误注入测试",UVM_MEDIUM)// UART 错误注入:校验错误和帧错误for(inti=0;i<10;i++)begin uart_tr=uart_transaction::type_id::create("uart_tr");uart_tr.randomize()with{dir==uart_transaction::TX;parity_type!=uart_transaction::PARITY_NONE;parity_error dist{0:=50,1:=50};// 50%概率注入校验错误frame_error dist{0:=70,1:=30};// 30%概率注入帧错误};uart_tr.start(env.uart_agt.seqr);#200us;end `uvm_info("ERROR_TEST","错误注入测试完成",UVM_MEDIUM)endtask endclass

五、完整文件结构

将所有文件按照以下结构组织,便于管理和编译:

spi_uart_uvm/ ├── src/ │ ├── spi/ │ │ ├── spi_transaction.sv │ │ ├── spi_interface.sv │ │ ├── spi_driver.sv │ │ ├── spi_monitor.sv │ │ ├── spi_sequencer.sv │ │ ├── spi_agent.sv │ │ └── spi_coverage.sv │ ├── uart/ │ │ ├── uart_transaction.sv │ │ ├── uart_interface.sv │ │ ├── uart_driver.sv │ │ ├── uart_monitor.sv │ │ ├── uart_sequencer.sv │ │ ├── uart_agent.sv │ │ └── uart_coverage.sv │ ├── env/ │ │ ├── spi_uart_config.sv │ │ └── spi_uart_env.sv │ └── test/ │ ├── base_test.sv │ ├── smoke_test.sv │ ├── spi_all_mode_test.sv │ ├── uart_full_config_test.sv │ ├── random_test.sv │ └── error_injection_test.sv └── tb/ └── top_tb.sv

六、编译与运行命令

VCS 编译命令

vcs-sverilog-ntb_optsuvm-1.2\+incdir+./src/spi+./src/uart+./src/env+./src/test\./src/spi/*.sv\./src/uart/*.sv\./src/env/*.sv\./src/test/*.sv\./tb/top_tb.sv\-osimv

运行指定测试用例

# 运行冒烟测试./simv +UVM_TESTNAME=smoke_test# 运行随机测试./simv +UVM_TESTNAME=random_test# 运行错误注入测试./simv +UVM_TESTNAME=error_injection_test# 生成覆盖率报告./simv +UVM_TESTNAME=random_test-cmline+cond+fsm+branch+tgl

七、最佳实践与扩展建议

1. 验证流程建议

  1. 先跑冒烟测试:确保基本功能正常
  2. 再跑全模式/全配置测试:覆盖所有接口配置
  3. 然后跑随机测试:快速提升覆盖率
  4. 最后跑错误注入测试:验证鲁棒性
  5. 根据覆盖率报告:编写定向测试用例覆盖剩余点

2. 扩展建议

  • 添加Scoreboard:用于比较DUT的输出和预期结果
  • 添加Reference Model:实现一个简单的SPI/UART参考模型
  • 添加Virtual Sequencer:用于协调SPI和UART的事务发送
  • 添加更多测试用例:如长包测试、背靠背传输测试、中断测试等

3. 常见问题解决

  • 覆盖率收敛慢:调整约束的权重分布,增加关键场景的概率
  • 随机化失败:检查约束是否有冲突,使用soft约束降低优先级
  • 时序问题:调整接口的时钟块延时,确保采样和驱动的时机正确
http://www.jsqmd.com/news/907412/

相关文章:

  • GeoServer数据源创建失败?别慌,可能是这个Windows文件命名‘潜规则’在捣鬼
  • 如何安全备份微信聊天记录:完整指南与实用工具推荐
  • WPF文本框的Placeholder效果,除了Watermark和Style,这几种实现方式你知道吗?
  • 别再踩坑了!手把手教你用YOLOv5 v6.0 + ONNX在Ubuntu 20.04的ROS上部署目标检测(附VMware虚拟机USB摄像头连接完整流程)
  • Python爬虫实战:极客实战 - 全自动化构建 GraphQL/REST API 结构化字典!
  • 别再折腾Docker了!Ubuntu 22.04上源码编译ZLMediaKit保姆级教程(含libsrtp/openssl避坑指南)
  • Midjourney Remix mode保姆级教程:手把手教你修改提示词,让AI更懂你
  • 脉冲神经网络与二进制权重的能效优化技术
  • UE4半透明材质性能优化全指南:从Surface模式选择到RTGI参数调优
  • 千问大模型在阿里生态中的核心应用场景与落地价值
  • 告别‘一大片爆红’:手把手教你用CMake-GUI无错配置VTK(Windows/VS2022版)
  • 避坑指南:DataSophon部署中那些官方文档没细说的坑(防火墙、MySQL、Nginx配置)
  • 模型迁移的“翻译官”——AMCT异构计算管理实战与自定义算子解决方案
  • 形式化验证赋能可解释AI:ViTaX框架如何保证解释的鲁棒性与必要性
  • 【评测】CSDN大模型热点洞察创作流程与评测
  • QiLink 项目的发起人徐玉生孤岛筑塔与温柔渗透
  • [智能体-106]:在相同的输入的情况下,每次调用,大模型具有相同的输出或具有不同的输出的原理?
  • 别再自己造轮子了!盘点那些能直接提升UniApp开发效率的34个原生插件
  • Vue+Element UI项目里,Table数据刷新后展开状态丢失?教你用expand-row-keys动态恢复
  • 【OpenClaw篇】OpenClaw 实战入门:在 VMware 虚拟机里部署第一个本地 AI Agent
  • BarTender 2022 Print Portal安装踩坑实录:从‘无法访问localhost’到成功部署的完整排错
  • 如何3分钟搞定QQ空间数据备份:GetQzonehistory终极指南 [特殊字符]
  • PCA降维后数据还能‘还原’吗?用Python实战带你理解信息损失与重构误差(附避坑指南)
  • 生成式AI重塑网络安全攻防:开发者如何构建AI增强型防御体系
  • 告别繁琐组态:用SVG+JavaScript手搓一个可复用的HMI仪表盘组件
  • 第4章:寄生虫时代——当AI学会呼吸
  • FlashAttention训练反向传播:梯度是怎么传回来的?
  • SAP推出AI智能体中枢,统一管理企业多厂商智能体
  • Axure RP安装(已汉化)附下载地址
  • 用DeepXDE搞定薛定谔方程:一个Python物理信息神经网络(PINN)实战教程