当前位置: 首页 > 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.gsyq.cn/news/1418715.html

相关文章:

  • IPv4 和 IPv6 在地址结构、表示方式、地址空间大小及计算逻辑上存在根本性差异
  • 如何安全备份微信聊天记录:完整指南与实用工具推荐
  • UE4半透明材质性能优化全指南:从Surface模式选择到RTGI参数调优
  • 形式化验证赋能可解释AI:ViTaX框架如何保证解释的鲁棒性与必要性
  • 模型迁移的“翻译官”——AMCT异构计算管理实战与自定义算子解决方案
  • QiLink 项目的发起人徐玉生孤岛筑塔与温柔渗透
  • [智能体-106]:在相同的输入的情况下,每次调用,大模型具有相同的输出或具有不同的输出的原理?
  • 【OpenClaw篇】OpenClaw 实战入门:在 VMware 虚拟机里部署第一个本地 AI Agent
  • BarTender 2022 Print Portal安装踩坑实录:从‘无法访问localhost’到成功部署的完整排错
  • 第4章:寄生虫时代——当AI学会呼吸
  • PCA降维后数据还能‘还原’吗?用Python实战带你理解信息损失与重构误差(附避坑指南)
  • Axure RP安装(已汉化)附下载地址
  • PyEcharts常用图
  • Mermaid Live Editor:免费在线图表编辑器的终极解决方案,轻松创建专业图表
  • AutoCAD 2024 + Visual Studio 2022 ARX 二次开发从零到 Hello World 保姆级教程——001环境搭建
  • 从《星露谷物语》到你的项目:用Unity ScriptableObject设计一个可扩展的合成与交易系统
  • PLC数据对接MES,有哪几种方式?HTTP、MQTT、OPC UA怎么选
  • 探访TeraWulf 750MW AI数据中心:建设速度达到“中国水平“
  • 免费服务器指南:GitHub Pages搭建静态网站全攻略
  • 26HVV护网行动 初 中 高 级人员招聘
  • 测试左移 + 右移 + 自动化,三位一体构建质量护城河
  • 别再只仿真了!用100个三极管在面包板上还原4位加法器,我总结了这些避坑指南
  • CentOS环境下手动升级openssl、openssh
  • RTX51 Tiny调试技巧与C源代码显示问题解析
  • RTX51 Tiny在SiLABS SFR分页机制下的移植优化
  • 深入UGUI底层:手把手教你用OnPopulateMesh和顶点偏移,实现Image的任意变形(不只是倾斜)
  • 用 Nerfstudio 和手机照片,5分钟快速生成你的第一个 3D 数字手办(Nerfacto 模型实战)
  • 从一次“幻觉”到一次“进化”:AI事实核查错误的深度剖析与系统改进启示
  • 从状态检查到数据备份:仓储PLC控制器保养周期与实操清单
  • 效率拉满!VS Code 安装 Qoder CN(原通义灵码)详细教程