Modelsim搭建只有driver的UVM验证平台
文章目录
- 1 验证平台的组成
- 1.1 简单验证平台
- 1.2 典型UVM验证平台
- 2 按照书本例程使用 Modelsim 搭建仿真环境
- 2.1 最简单的验证平台
- 2.2 加入factory机制
- 2.3 加入 Objection 机制
- 2.4 加入 virtual interface
记录一下《UVM实战(卷I)》学习笔记。
1 验证平台的组成
1.1 简单验证平台
- driver:模拟DUT的真实使用情况,给DUT施加各种激励,包括正常异常激励,不同模式激励。
- scoreboard:也被称为 checker 。根据DUT的输出判断DUT行为是否与预期符合。
- monitor:收集DUT的输出并将它们传递给scoreboard。
- reference model:给出预期的结果。
1.2 典型UVM验证平台
引入 agent 和 sequence 概念。
2 按照书本例程使用 Modelsim 搭建仿真环境
2.1 最简单的验证平台
参考文章:UVM学习-仿真环境的搭建
在上述参考文章的基础上,我们自己要去学习具体的原理,首先要了解Modelsim仿真流程及相关命令。
首先按照课本编写好相关代码:
待测设计DUT:这里按照个人代码风格抄了一遍。
//file name: dut.v
module dut(input I_sys_clk,input I_reset_n,input [7:0] I_rxd ,input I_rx_dv ,output reg [7:0] O_txd ,output reg O_tx_en
);always @(posedge I_sys_clk or negedge I_reset_n)
beginif(~I_reset_n) beginO_txd <= 8'b0;O_tx_en <= 1'b0;end elsebeginO_txd <= I_rxd;O_tx_en <= I_rx_dv;end
endendmodule
UVM是一个库,库中所有东西都是使用类(class)实现。验证平台中所有组件应该派生自UVM中的类。
类有函数(function)和任务(task),通过函数和任务可以完成driver输出激励,monitor监测,参考模型计算,scoreboard比较功能。
类有成员变量,通过成员变量可以控制类的行为。
添加driver类:
//file name: my_driver.sv
`ifndef MY_DRIVER__SV
`define MY_DRIVER__SVclass my_driver extends uvm_driver;function new(string name = "my_driver", uvm_component parent = null);super.new(name, parent);endfunction //new()extern virtual task main_phase(uvm_phase phase);
endclass //my_driver extends uvm_drivertask my_driver::main_phase(uvm_phase phase);top_tb.I_rxd <= 8'd0;top_tb.I_rx_dv <= 1'b0;while(!top_tb.I_reset_n)@(posedge top_tb.I_sys_clk);for (int i = 0; i < 256; i++) begin@(posedge top_tb.I_sys_clk)top_tb.I_rxd <= $urandom_range(0, 255);top_tb.I_rx_dv <= 1'b1;`uvm_info("my_driver", "data is drived", UVM_LOW);end@(posedge top_tb.I_sys_clk);top_tb.I_rx_dv <= 1'b0;endtask`endif
uvm_info宏的功能与verilog的display类似,但比display更强大。
第一个字符串参数把打印的信息归类,第二个字符串参数是需要打印的信息,第三个参数是冗余级别,有UVM_LOW、UVM_MEDIUM、UVM_HIGH。UVM默认只显示UVM_MEDIUM或者UVM_LOW的信息。
添加testbench的顶层:
//file name:top_tb.sv
`timescale 1ns/1ps
`include "uvm_macros.svh"import uvm_pkg::*;`include "my_driver.sv" module top_tb();parameter T = 10;reg I_sys_clk;
reg I_reset_n;
reg [7:0] I_rxd ;
reg I_rx_dv ;
wire[7:0] O_txd ;
wire O_tx_en ;dut my_dut(.I_sys_clk(I_sys_clk),.I_reset_n(I_reset_n),.I_rxd (I_rxd ),.I_rx_dv (I_rx_dv ),.O_txd (O_txd ),.O_tx_en (O_tx_en )
);initial beginmy_driver drv;drv = new("drv", null);drv.main_phase(null);$finish();
endinitial beginI_sys_clk <= 1'b1;I_reset_n <= 1'b0;#(T*10);I_reset_n <= 1'b1;
endalways #(T/2) I_sys_clk <= ~I_sys_clk;endmodule
按以往仿真FPGA设计的流程, 在modelsim新建工程然后添加这3个文件。
直接全部编译,是会报错的:
# Compile of top_tb.sv was successful.
# Compile of dut.v was successful.
# Compile of my_driver.sv failed with 2 errors.
# 3 compiles, 1 failed with 2 errors.
使用命令对my_driver.sv单独编译打印报错信息:vlog ./demo0/my_driver.sv
报这个错的原因是 uvm_driver 类的定义没有包含进来,而头文件的包含是在 top_tb.sv 中完成的,所以我们需要指定头文件的路径才能包含进来。vlog 中的 +incdir+<directory>
指令指定include文件路径。关于这个选项官方文档见《modelsim_se_reg.pdf》p817:
注:moselsim文档路径:[Modelsim安装路径]/docs/pdfdocs/
vlog +incdir+C:/software/FPGA/modeltech64_10.5/verilog_src/uvm-1.1d/src C:/software/FPGA/modeltech64_10.5/verilog_src/uvm-1.1d/src/uvm_pkg.sv ./demo0/dut.v ./demo0/top_tb.sv
当然,绝对路径比较长,可以先将路径设为变量
set UVM_PATH C:/software/FPGA/modeltech64_10.5/verilog_src/uvm-1.1d/src
set SRC_PATH ./demo0
vlog +incdir+$UVM_PATH $UVM_PATH/uvm_pkg.sv $SRC_PATH/dut.v $SRC_PATH/top_tb.sv
接下来添加wave信号,运行仿真命令或者在work库右击top_tb→simulate without optimization,进行仿真:
注:如果优化直接把DUT优化掉了,因为输出空载。
vsim -novopt -sv_lib C:/software/FPGA/modeltech64_10.5/uvm-1.1d/win64/uvm_dpi work.top_tb
仿真结果:
将上述过程汇总在一个.do文件中,方便后续更新调用
文件名:demo0.do
cd D:/prj/uvm_prj/demo0
vlib work
set UVM_PATH C:/software/FPGA/modeltech64_10.5/verilog_src/uvm-1.1d/src
set SRC_PATH .
vlog +incdir+$UVM_PATH $UVM_PATH/uvm_pkg.sv $SRC_PATH/dut.v $SRC_PATH/top_tb.sv
vsim -novopt -sv_lib C:/software/FPGA/modeltech64_10.5/uvm-1.1d/win64/uvm_dpi work.top_tb
add wave -position insertpoint sim:/top_tb/*
run 2us
因为do文件放在源文件相同路径,所以路径稍微改了一下。
将调用do文件的操作用批处理命令实现:
文件名:demo0_do.bat
vsim -do demo0.do
2.2 加入factory机制
引入 UVM 的 factory 机制 自动创建一个类的实例并调用其中的函数和任务。
my_driver.sv:
`ifndef MY_DRIVER__SV
`define MY_DRIVER__SVclass my_driver extends uvm_driver;`uvm_component_utils(my_driver);function new(string name = "my_driver", uvm_component parent = null);super.new(name, parent);`uvm_info("my_driver", "new is called", UVM_LOW);endfunction //new()extern virtual task main_phase(uvm_phase phase);
endclass //my_driver extends uvm_drivertask my_driver::main_phase(uvm_phase phase);`uvm_info("my_driver", "main_phase is called", UVM_LOW);top_tb.I_rxd <= 8'd0;top_tb.I_rx_dv <= 1'b0;while(!top_tb.I_reset_n)@(posedge top_tb.I_sys_clk);for (int i = 0; i < 256; i++) begin@(posedge top_tb.I_sys_clk)top_tb.I_rxd <= $urandom_range(0, 255);top_tb.I_rx_dv <= 1'b1;`uvm_info("my_driver", "data is drived", UVM_LOW);end@(posedge top_tb.I_sys_clk);top_tb.I_rx_dv <= 1'b0;endtask`endif
top_tb.sv:
`timescale 1ns/1ps
`include "uvm_macros.svh"import uvm_pkg::*;`include "my_driver.sv" module top_tb();parameter T = 10;reg I_sys_clk;
reg I_reset_n;
reg [7:0] I_rxd ;
reg I_rx_dv ;
wire[7:0] O_txd ;
wire O_tx_en ;dut my_dut(.I_sys_clk(I_sys_clk),.I_reset_n(I_reset_n),.I_rxd (I_rxd ),.I_rx_dv (I_rx_dv ),.O_txd (O_txd ),.O_tx_en (O_tx_en )
);initial begin// my_driver drv;// drv = new("drv", null);// drv.main_phase(null);run_test("my_driver");// $finish();
endinitial beginI_sys_clk <= 1'b1;I_reset_n <= 1'b0;#(T*10);I_reset_n <= 1'b1;
endalways #(T/2) I_sys_clk <= ~I_sys_clk;endmodule
demo0.do的路径改一下,如果改了do文件名字则批处理文件也要对应,改好之后执行,结果如下:
可以看到,run_test(“my_driver”); 语句完成了 my_driver 的实例化并调用了 main_phase task。但是没有驱动数据,这与作者说的符合。
笔记:
- factory机制的实现被集成在了一个宏中:uvm_component_utils。这个宏将 my_driver 类登记在 UVM 的一张表中,这张表是实现 factory 功能的基础。
- 所有派生自uvm_component及其派生类的类都应该使用uvm_component_utils宏注册。
- run_test(“my_driver”); 语句创建实例并调用 main_phase 。
2.3 加入 Objection 机制
UVM中通过objection机制来控制验证平台的关闭。
在每个phase中,UVM会检查是否有 objection 被提起(raise_objection),如果有,那么等待这 objection 被撤销(drop_objection)后停止仿真;如果没有,则马上结束当前phase。
所以虽然 top_tb 没有 $finish ,但是没有 raise_objection, 所以会马上结束当前 phase,还没来得及驱动信号输出。
加入 objection 机制,my_driver.sv:
`ifndef MY_DRIVER__SV
`define MY_DRIVER__SVclass my_driver extends uvm_driver;`uvm_component_utils(my_driver);function new(string name = "my_driver", uvm_component parent = null);super.new(name, parent);`uvm_info("my_driver", "new is called", UVM_LOW);endfunction //new()extern virtual task main_phase(uvm_phase phase);
endclass //my_driver extends uvm_drivertask my_driver::main_phase(uvm_phase phase);phase.raise_objection(this);`uvm_info("my_driver", "main_phase is called", UVM_LOW);top_tb.I_rxd <= 8'd0;top_tb.I_rx_dv <= 1'b0;while(!top_tb.I_reset_n)@(posedge top_tb.I_sys_clk);for (int i = 0; i < 256; i++) begin@(posedge top_tb.I_sys_clk)top_tb.I_rxd <= $urandom_range(0, 255);top_tb.I_rx_dv <= 1'b1;`uvm_info("my_driver", "data is drived", UVM_LOW);end@(posedge top_tb.I_sys_clk);top_tb.I_rx_dv <= 1'b0;phase.drop_objection(this);endtask`endif
修改do文件运行批处理程序,仿真结果:
笔记:
- raise_objection和drop_objection总是成对出现。
- raise_objection语句必须在main_phase中第一个消耗仿真时间的语句之前。 如$display语句是不消耗仿真时间的, 这些语句可以放在raise_objection之前, 但是类似@( posedge top.clk) 等语句是要消耗仿真时间的。
2.4 加入 virtual interface
上诉代码信号驱动使用的是绝对路径,大大降低平台可移植性。
避免绝对路径的两个方法:
- 使用宏定义。修改路径只需要修改宏定义。
- 使用interface。
可以在 top_tb 定义 interface 然后实例化,但是 my_driver 是一个类,不可以在类中使用这种方式声明 interface。在类中使用的是 virtual interface。
my_driver.sv:
`ifndef MY_DRIVER__SV
`define MY_DRIVER__SVclass my_driver extends uvm_driver;virtual my_if vif;`uvm_component_utils(my_driver);function new(string name = "my_driver", uvm_component parent = null);super.new(name, parent);`uvm_info("my_driver", "new is called", UVM_LOW);endfunction //new() virtual function void build_phase(uvm_phase phase);super.build_phase(phase); // 因为在其父类的build_phase中执行了一些必要的操
作, 这里必须显式地调用并执行它。`uvm_info("my_driver", "build_phase is called", UVM_LOW);if(!uvm_config_db#(virtual my_if)::get(this, "", "vif", vif)) // config_db`uvm_fatal("my_driver", "virtual interface must be set for vif!!!")endfunctionextern virtual task main_phase(uvm_phase phase);
endclass //my_driver extends uvm_drivertask my_driver::main_phase(uvm_phase phase);phase.raise_objection(this);`uvm_info("my_driver", "main_phase is called", UVM_LOW);vif.data <= 8'b0; vif.valid <= 1'b0;while(!vif.rst_n)@(posedge vif.clk);for(int i = 0; i < 256; i++)begin@(posedge vif.clk);vif.data <= $urandom_range(0, 255);vif.valid <= 1'b1;`uvm_info("my_driver", "data is drived", UVM_LOW);end@(posedge vif.clk);vif.valid <= 1'b0;phase.drop_objection(this);endtask`endif
top_tb.sv 增加:
// 模块内增加
initial beginuvm_config_db#(virtual my_if)::set(null, "uvm_test_top", "vif", input_if);
end// 模块外增肌
interface my_if(input clk, input rst_n);logic [7:0] data ;logic valid;
endinterface
- build_phase
与main_phase一样, build_phase也是UVM中内建的一个phase。
在build_phase中主要通过config_db的set和get操作来传递一些数据,以及实例化成员变量等。
build_phase与main_phase不同的一点在于,build_phase是一个函数phase,而main_phase是一个任务phase,build_phase是不消耗仿真时间的。build_phase总是在仿真时间($time函数打印出的时间)为0时执行。 - config_db
set和get函数都有四个参数, 这两个函数的第三个参数必须完全一致。 set函数的第四个参数表示要将哪个interface 通过config_db传递给my_driver, get函数的第四个参数表示把得到的interface传递给哪个my_driver的成员变量。- set:可以简单地理解成是“寄信”
- get: 可以简单地理解成是“收信”
仿真结果:
Modelsim搭建只有driver的UVM验证平台相关推荐
- 从零开始,搭建一个简单的UVM验证平台(一)
前言: 这篇系列将从0开始搭建一个UVM验证平台,来帮助一些学习了SV和UVM知识,但对搭建完整的验证环境没有概念的朋友. UVM前置基础: 1.UVM基础-factory机制.phase机制 2.U ...
- UVM验证平台搭建三:spi_mst_agent-spi_slv_agent
UVM验证平台搭建三:spi_mst_agent/spi_slv_agent 一.概述 二.spi mst transaction 三.spi mst sequencer 四.spi mst driv ...
- (3)UVM验证平台搭建之介绍
年轻人的第一个UVM验证平台搭建之介绍 验证平台的组成 UVM验证平台的框图 验证平台介绍 目录 验证平台的组成 验证用于找出DUT中的bug,这个过程通常是把DUT放入一个验证平台中来实现的.一个验 ...
- UART UVM验证平台平台搭建总结
UART UVM验证平台平台搭建总结 tb_top是整个UVM验证平台的最顶层:tb_top中例化dut,提供时钟和复位信号,定义接口以及设置driver和monitor的virual interfa ...
- UVM验证平台搭建一:reg model 生成
UVM验证平台搭建一:reg model 生成 一.概述 二.寄存器描述表格 三.生成.ralf寄存器文件 四.ralgen生成寄存器模型 一.概述 在做验证时,寄存器模型是验证平台中必不可少的,而且 ...
- 从VHDL到UVM验证平台转变的优点评估
路科验证官网:路科验证 - 专注于数字芯片验证的系统思想和前沿工程领域 EETOP路科首页: EETOP - 路科验证 - IC验证培训 CSDN路科首页:CSDN - 路科验证 - IC验证培训 由 ...
- 诙谐有趣的《UVM实战》笔记——第二章 一个简单的UVM验证平台
前言 某天白天在地铁上听鬼故事,结果晚上要睡觉时,故事里的情节都历历在目,给我鸡皮疙瘩起的~ 不过我倒是没有吓得睡不着,而是转念一想,为啥我学知识忘得很快,随便听的鬼故事却记得这么清楚咧? 那如果能像 ...
- 一个简单的UVM验证平台
2.1 验证平台的组成 2.1.1. 何谓验证平台 何谓验证平台?验证最基本的目的在于测试 DUT 的正确性,其最常使用的方法就是给 DUT 施加不同的输入(激励),所以一个验证平台最重要的的功能在于 ...
- UVM(一)——UVM验证平台
UVM(一)--UVM验证平台 UVM验证平台组成 driver组件 factory机制 objection机制 virtual interface config_db机制 transaction e ...
- UVM学习之路(5)— 完整的UVM验证平台
UVM学习之路(5)- 完整的UVM验证平台 一.前言 一个完整的UVM验证平台还应该加入寄存器模型,对应的设计文件中也应该存在寄存器及其控制端口, 通过该控制端口可以配置DUT中的寄存器. 二.设计 ...
最新文章
- [转载]逐步建设企业DevOps能力
- 禁止直接在浏览器输入网址访问的代码
- 三阶魔方自动还原 vc实现
- 神策数据陈宁:前端国际化技术需求及模型实现
- ITK:在一张图像中设置像素值
- 10.21 crond定时任务练习
- 华为云服务器密码修改,华为云鲲鹏云服务器安装MySQL 5.7.30
- linux shell 切割文件,linux shell 将文件按照行数以及顺序拆分成多个文件
- 配置文件服务器实训报告,文件服务器的配置实训报告
- 辞去美国终身教职!顶尖学者,加盟“双一流”高校
- Ubuntu下超实用的命令
- Sentinel降级_异常比例_分布式系统集群限流_线程数隔离_削峰填谷_流量控制_速率控制_服务熔断_服务降级---微服务升级_SpringCloud Alibaba工作笔记0040
- javascript 未来新方法的介绍
- Halcon自定义直线卡尺rake
- 性能优化:要2个月才跑完的程序我是如何优化到到4小时的?
- 获取微信公众号地址的图片不能正常显示的问题
- 自制Anki选择题模板(支持桌面版/移动版)
- 如何解决VMware Workstation上ubuntu出现Host SMbus controller not enabled
- 切比雪夫不等式例题讲解_浅谈|f(x)|最大值的最小值问题--切比雪夫最佳逼近直线在高考中的应用...
- Java集合 HashSet 和 HashMap