文章目录

  • 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

上诉代码信号驱动使用的是绝对路径,大大降低平台可移植性。

避免绝对路径的两个方法:

  1. 使用宏定义。修改路径只需要修改宏定义。
  2. 使用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验证平台相关推荐

  1. 从零开始,搭建一个简单的UVM验证平台(一)

    前言: 这篇系列将从0开始搭建一个UVM验证平台,来帮助一些学习了SV和UVM知识,但对搭建完整的验证环境没有概念的朋友. UVM前置基础: 1.UVM基础-factory机制.phase机制 2.U ...

  2. UVM验证平台搭建三:spi_mst_agent-spi_slv_agent

    UVM验证平台搭建三:spi_mst_agent/spi_slv_agent 一.概述 二.spi mst transaction 三.spi mst sequencer 四.spi mst driv ...

  3. (3)UVM验证平台搭建之介绍

    年轻人的第一个UVM验证平台搭建之介绍 验证平台的组成 UVM验证平台的框图 验证平台介绍 目录 验证平台的组成 验证用于找出DUT中的bug,这个过程通常是把DUT放入一个验证平台中来实现的.一个验 ...

  4. UART UVM验证平台平台搭建总结

    UART UVM验证平台平台搭建总结 tb_top是整个UVM验证平台的最顶层:tb_top中例化dut,提供时钟和复位信号,定义接口以及设置driver和monitor的virual interfa ...

  5. UVM验证平台搭建一:reg model 生成

    UVM验证平台搭建一:reg model 生成 一.概述 二.寄存器描述表格 三.生成.ralf寄存器文件 四.ralgen生成寄存器模型 一.概述 在做验证时,寄存器模型是验证平台中必不可少的,而且 ...

  6. 从VHDL到UVM验证平台转变的优点评估

    路科验证官网:路科验证 - 专注于数字芯片验证的系统思想和前沿工程领域 EETOP路科首页: EETOP - 路科验证 - IC验证培训 CSDN路科首页:CSDN - 路科验证 - IC验证培训 由 ...

  7. 诙谐有趣的《UVM实战》笔记——第二章 一个简单的UVM验证平台

    前言 某天白天在地铁上听鬼故事,结果晚上要睡觉时,故事里的情节都历历在目,给我鸡皮疙瘩起的~ 不过我倒是没有吓得睡不着,而是转念一想,为啥我学知识忘得很快,随便听的鬼故事却记得这么清楚咧? 那如果能像 ...

  8. 一个简单的UVM验证平台

    2.1 验证平台的组成 2.1.1. 何谓验证平台 何谓验证平台?验证最基本的目的在于测试 DUT 的正确性,其最常使用的方法就是给 DUT 施加不同的输入(激励),所以一个验证平台最重要的的功能在于 ...

  9. UVM(一)——UVM验证平台

    UVM(一)--UVM验证平台 UVM验证平台组成 driver组件 factory机制 objection机制 virtual interface config_db机制 transaction e ...

  10. UVM学习之路(5)— 完整的UVM验证平台

    UVM学习之路(5)- 完整的UVM验证平台 一.前言 一个完整的UVM验证平台还应该加入寄存器模型,对应的设计文件中也应该存在寄存器及其控制端口, 通过该控制端口可以配置DUT中的寄存器. 二.设计 ...

最新文章

  1. [转载]逐步建设企业DevOps能力
  2. 禁止直接在浏览器输入网址访问的代码
  3. 三阶魔方自动还原 vc实现
  4. 神策数据陈宁:前端国际化技术需求及模型实现
  5. ITK:在一张图像中设置像素值
  6. 10.21 crond定时任务练习
  7. 华为云服务器密码修改,华为云鲲鹏云服务器安装MySQL 5.7.30
  8. linux shell 切割文件,linux shell 将文件按照行数以及顺序拆分成多个文件
  9. 配置文件服务器实训报告,文件服务器的配置实训报告
  10. 辞去美国终身教职!顶尖学者,加盟“双一流”高校
  11. Ubuntu下超实用的命令
  12. Sentinel降级_异常比例_分布式系统集群限流_线程数隔离_削峰填谷_流量控制_速率控制_服务熔断_服务降级---微服务升级_SpringCloud Alibaba工作笔记0040
  13. javascript 未来新方法的介绍
  14. Halcon自定义直线卡尺rake
  15. 性能优化:要2个月才跑完的程序我是如何优化到到4小时的?
  16. 获取微信公众号地址的图片不能正常显示的问题
  17. 自制Anki选择题模板(支持桌面版/移动版)
  18. 如何解决VMware Workstation上ubuntu出现Host SMbus controller not enabled
  19. 切比雪夫不等式例题讲解_浅谈|f(x)|最大值的最小值问题--切比雪夫最佳逼近直线在高考中的应用...
  20. Java集合 HashSet 和 HashMap

热门文章

  1. 使用iMazing给苹果手机设置专属来电铃声
  2. 修改 植物大战僵尸 存档信息
  3. TPshop项目步骤(二)
  4. 华为手机主界面的返回键怎么调出来_华为手机怎么调出来下面返回键
  5. QT 错误:Unable to create a debugging engine解决
  6. 科普一下bl锁的知识,没解锁的必看!
  7. 索迪斯携手喜茶致敬白衣天使、慰问抗疫英雄
  8. android 屏蔽电源键,home键
  9. 0基础学Java(2)
  10. vue3中的Suspense