目录

  • top_tb.sv
    • my_dut.sv
    • my_if.sv
    • basic_test.sv、my_case0.sv、my_case1.sv
      • my_env.sv
      • my_agent.sv
        • my_sequencer.sv
          • my_sequence.sv
            • my_transaction.sv
        • my_driver.sv
        • my_monitor.sv
      • my_model.sv
      • my_scoreboard.sv
  • 1. 使用Questasim搭建UVM验证环境

本文代码均来自于《UVM实战(卷I)》2.5.2节 UVM中测试用例的启动 这一模块的代码

本文涉及的UVM树如下图所示


top_tb.sv

`timescale 1ns/1ps
`include "uvm_macros.svh"                        //uvm宏import uvm_pkg::*;
`include "my_dut.sv"
`include "my_if.sv"
`include "my_transaction.sv"
`include "my_sequencer.sv"
`include "my_driver.sv"
`include "my_monitor.sv"
`include "my_agent.sv"
`include "my_model.sv"
`include "my_scoreboard.sv"
`include "my_env.sv"
`include "base_test.sv"
`include "my_case0.sv"
`include "my_case1.sv"module top_tb;reg clk;
reg rst_n;
reg[7:0] rxd;
reg rx_dv;
wire[7:0] txd;
wire tx_en;my_if input_if(clk, rst_n);                      //与i_agent的接口的例化
my_if output_if(clk, rst_n);                    //与o_agent的接口的例化dut my_dut(.clk(clk),.rst_n(rst_n),.rxd(input_if.data),.rx_dv(input_if.valid),.txd(output_if.data),.tx_en(output_if.valid));initial beginclk = 0;forever begin#100 clk = ~clk;end
endinitial beginrst_n = 1'b0;#1000;rst_n = 1'b1;
endinitial beginrun_test("my_case0");                             //运行测试用例,或者在questasim的tcl命令行写入"+UVM_TEST_NAME = my_case0"
endinitial beginuvm_config_db#(virtual my_if)::set(null, "uvm_test_top.env.i_agt.drv", "vif", input_if);                //config_db机制,用于参数传递uvm_config_db#(virtual my_if)::set(null, "uvm_test_top.env.i_agt.mon", "vif", input_if);uvm_config_db#(virtual my_if)::set(null, "uvm_test_top.env.o_agt.mon", "vif", output_if);
endendmodule

上述代码中uvm_config_db#(virtual my_if)::set(null, "uvm_test_top.env.i_agt.drv", "vif", input_if);my_driver中的uvm_config_db#(virtual my_if)::get(this, "", "vif", vif)是一对,表示模块间的参数传递

my_dut.sv

简单的带有复位功能的同步收发

module dut(clk,rst_n, rxd,rx_dv,txd,tx_en);
input           clk;
input           rst_n;
input   [7:0]   rxd;
input           rx_dv;
output  [7:0]   txd;
output          tx_en;reg       [7:0]   txd;
reg             tx_en;always @(posedge clk) beginif(!rst_n) begintxd <= 8'b0;tx_en <= 1'b0;endelse begintxd <= rxd;tx_en <= rx_dv;end
end
endmodule

my_if.sv

接口

`ifndef MY_IF__SV
`define MY_IF__SVinterface my_if(input clk, input rst_n);logic [7:0] data;logic valid;
endinterface
`endif

basic_test.sv、my_case0.sv、my_case1.sv

包含了继承于uvm_test的基本测试平台类base_test,以及继承于base_test的两个测试平台my_case0 和my_case1

my_case0和my_case1使用不同的sequence

`ifndef BASE_TEST__SV                                       //条件编译,表示如果未定义宏BASE_TEST_SV,无分号
`define BASE_TEST__SV                                      //宏定义BASE_TEST_SV,无分号class base_test extends uvm_test;my_env         env;function new(string name = "base_test", uvm_component parent = null);super.new(name,parent);endfunctionextern virtual function void build_phase(uvm_phase phase);   //实例化phase,该类被注册后,build_phase可自动被调用,用于创建UVM树extern virtual function void report_phase(uvm_phase phase);    //打印报告phase,该类被注册后,build_phase可自动被调用`uvm_component_utils(base_test)                              //factory机制,将base_test类注册到UVM内部的一张表中,可自动调用各种phase
endclassfunction void base_test::build_phase(uvm_phase phase);super.build_phase(phase);env  =  my_env::type_id::create("env", this);                 //factory机制的实例化方式,仅限于被注册过的类
endfunctionfunction void base_test::report_phase(uvm_phase phase);uvm_report_server server;int err_num;super.report_phase(phase);server = get_report_server();err_num = server.get_severity_count(UVM_ERROR);if (err_num != 0) begin$display("TEST CASE FAILED");endelse begin$display("TEST CASE PASSED");end
endfunction
`endif
class my_case0 extends base_test;function new(string name = "my_case0", uvm_component parent = null);super.new(name,parent);endfunction extern virtual function void build_phase(uvm_phase phase); `uvm_component_utils(my_case0)
endclassfunction void my_case0::build_phase(uvm_phase phase);super.build_phase(phase);uvm_config_db#(uvm_object_wrapper)::set(this, "env.i_agt.sqr.main_phase", "default_sequence", case0_sequence::type_id::get());                    //表示my_case0测试环境下使用case0_sequence
endfunction`endif
class my_case1 extends base_test;function new(string name = "my_case1", uvm_component parent = null);super.new(name,parent);endfunction extern virtual function void build_phase(uvm_phase phase); `uvm_component_utils(my_case1)
endclassfunction void my_case1::build_phase(uvm_phase phase);super.build_phase(phase);uvm_config_db#(uvm_object_wrapper)::set(this, "env.i_agt.sqr.main_phase", "default_sequence", case1_sequence::type_id::get());
endfunction`endif

my_env.sv

`ifndef MY_ENV__SV
`define MY_ENV__SVclass my_env extends uvm_env;my_agent   i_agt;                                           //dut输入端agentmy_agent   o_agt;                                          //dut输出端agentmy_model   mdl;                                                //dut参考模型my_scoreboard scb;                                         //计分板,或是checkeruvm_tlm_analysis_fifo #(my_transaction) agt_scb_fifo;     //TLM通信FIFOuvm_tlm_analysis_fifo #(my_transaction) agt_mdl_fifo;uvm_tlm_analysis_fifo #(my_transaction) mdl_scb_fifo;function new(string name = "my_env", uvm_component parent);super.new(name, parent);endfunctionvirtual function void build_phase(uvm_phase phase);super.build_phase(phase);i_agt = my_agent::type_id::create("i_agt", this);o_agt = my_agent::type_id::create("o_agt", this);i_agt.is_active = UVM_ACTIVE;                                //UVM_ACTIVE表示该agent包含driver和sequencero_agt.is_active = UVM_PASSIVE;                           //UVM_PASSIVE表示该agent只有一个monitor,不包含drivermdl = my_model::type_id::create("mdl", this);scb = my_scoreboard::type_id::create("scb", this);agt_scb_fifo = new("agt_scb_fifo", this);                  //TLM fifo不属于uvm_component因此只能new例化agt_mdl_fifo = new("agt_mdl_fifo", this);mdl_scb_fifo = new("mdl_scb_fifo", this);endfunctionextern virtual function void connect_phase(uvm_phase phase);`uvm_component_utils(my_env)
endclassfunction void my_env::connect_phase(uvm_phase phase);super.connect_phase(phase);i_agt.ap.connect(agt_mdl_fifo.analysis_export);                         //i_agt到mdl的TLM FIFO通信mdl.port.connect(agt_mdl_fifo.blocking_get_export);mdl.ap.connect(mdl_scb_fifo.analysis_export);                          //mdl到scb的TLM FIFO通信scb.exp_port.connect(mdl_scb_fifo.blocking_get_export);o_agt.ap.connect(agt_scb_fifo.analysis_export);                          //o_agt到scb的TLM FIFO通信scb.act_port.connect(agt_scb_fifo.blocking_get_export);
endfunction`endif

my_agent.sv

注意my_agent中并未定义虚接口

`ifndef MY_AGENT__SV
`define MY_AGENT__SVclass my_agent extends uvm_agent ;my_sequencer  sqr;my_driver     drv;my_monitor    mon;uvm_analysis_port #(my_transaction)  ap;                                           //端口function new(string name, uvm_component parent);super.new(name, parent);endfunction extern virtual function void build_phase(uvm_phase phase);extern virtual function void connect_phase(uvm_phase phase);`uvm_component_utils(my_agent)
endclass function void my_agent::build_phase(uvm_phase phase);super.build_phase(phase);if (is_active == UVM_ACTIVE) beginsqr = my_sequencer::type_id::create("sqr", this);drv = my_driver::type_id::create("drv", this);endmon = my_monitor::type_id::create("mon", this);
endfunction function void my_agent::connect_phase(uvm_phase phase);super.connect_phase(phase);if (is_active == UVM_ACTIVE) begindrv.seq_item_port.connect(sqr.seq_item_export);                       //将端口成员变量uvm_driver::seq_item_port与端口成员变量uvm_sequencer::seq_item_export连接,用于sequence的传输endap = mon.ap;                                                              //agent发送端口与monitor的发送端口是同一个
endfunction`endif

my_sequencer.sv

用于打包、发送trans。

sequencer像一把枪,sequence就是弹夹,里面的子弹就是transaction。

而sequencer将transaction发射给driver

`ifndef MY_SEQUENCER__SV
`define MY_SEQUENCER__SVclass my_sequencer extends uvm_sequencer #(my_transaction);function new(string name, uvm_component parent);super.new(name, parent);endfunction `uvm_component_utils(my_sequencer)
endclass`endif
my_sequence.sv

两种sequence,case0_sequence 和case1_sequence 分别对应着两种测试平台my_case0和my_case1

class case0_sequence extends uvm_sequence #(my_transaction);my_transaction m_trans;function  new(string name= "case0_sequence");super.new(name);endfunction virtual task body();                                                  //sequence启动后会自动调用body()if(starting_phase != null) starting_phase.raise_objection(this);repeat (10) begin`uvm_do(m_trans)                                             //实例化m_trans并随机化,并传给sequencerend#100;if(starting_phase != null) starting_phase.drop_objection(this);endtask`uvm_object_utils(case0_sequence)                                       //factory注册,uvm_sequence继承自uvm_object
endclass
class case1_sequence extends uvm_sequence #(my_transaction);my_transaction m_trans;function  new(string name= "case1_sequence");super.new(name);endfunction virtual task body();if(starting_phase != null) starting_phase.raise_objection(this);                             //提起和撤销objection,starting_phase来自于uvm_sequence类repeat (10) begin`uvm_do_with(m_trans, { m_trans.pload.size() == 60;})                //加了硬约束的`uvm_doend#100;if(starting_phase != null) starting_phase.drop_objection(this);endtask`uvm_object_utils(case1_sequence)
endclass
my_transaction.sv
`ifndef MY_TRANSACTION__SV
`define MY_TRANSACTION__SVclass my_transaction extends uvm_sequence_item;                          //派生自uvm_sequence_item而不是uvm_transactionrand bit[47:0] dmac;rand bit[47:0] smac;rand bit[15:0] ether_type;rand byte      pload[];rand bit[31:0] crc;constraint pload_cons{pload.size >= 46;pload.size <= 1500;}function bit[31:0] calc_crc();return 32'h0;endfunctionfunction void post_randomize();crc = calc_crc;endfunction`uvm_object_utils_begin(my_transaction)                            //factory注册,注册后可直接调用copy,compare,print等函数,无需再手动定义`uvm_field_int(dmac, UVM_ALL_ON)`uvm_field_int(smac, UVM_ALL_ON)`uvm_field_int(ether_type, UVM_ALL_ON)`uvm_field_array_int(pload, UVM_ALL_ON)`uvm_field_int(crc, UVM_ALL_ON)`uvm_object_utils_endfunction new(string name = "my_transaction");super.new();endfunctionendclass
`endif

my_driver.sv

通过uvm_driver::seq_item_port.get_next_item(req);获取trans,并驱动dut,驱动完成后告知sequencer,以进行下一次uvm_sequencer::uvm_do()

`ifndef MY_DRIVER__SV
`define MY_DRIVER__SV
class my_driver extends uvm_driver#(my_transaction);virtual my_if vif;`uvm_component_utils(my_driver)function new(string name = "my_driver", uvm_component parent = null);super.new(name, parent);endfunctionvirtual function void build_phase(uvm_phase phase);super.build_phase(phase);if(!uvm_config_db#(virtual my_if)::get(this, "", "vif", vif))`uvm_fatal("my_driver", "virtual interface must be set for vif!!!")endfunctionextern task main_phase(uvm_phase phase);extern task drive_one_pkt(my_transaction tr);
endclasstask my_driver::main_phase(uvm_phase phase);vif.data <= 8'b0;vif.valid <= 1'b0;while(!vif.rst_n)@(posedge vif.clk);while(1) beginseq_item_port.get_next_item(req);                       //获取trans,这好像有点问题drive_one_pkt(req);seq_item_port.item_done();                           //驱动完成,通知sequencer可使uvm_do()结束end
endtasktask my_driver::drive_one_pkt(my_transaction tr);byte unsigned     data_q[];int  data_size;data_size = tr.pack_bytes(data_q) / 8; `uvm_info("my_driver", "begin to drive one pkt", UVM_LOW);repeat(3) @(posedge vif.clk);for ( int i = 0; i < data_size; i++ ) begin@(posedge vif.clk);vif.valid <= 1'b1;vif.data <= data_q[i]; end@(posedge vif.clk);vif.valid <= 1'b0;`uvm_info("my_driver", "end drive one pkt", UVM_LOW);
endtask`endif

my_monitor.sv

`ifndef MY_MONITOR__SV
`define MY_MONITOR__SV
class my_monitor extends uvm_monitor;virtual my_if vif;uvm_analysis_port #(my_transaction)  ap;`uvm_component_utils(my_monitor)function new(string name = "my_monitor", uvm_component parent = null);super.new(name, parent);endfunctionvirtual function void build_phase(uvm_phase phase);super.build_phase(phase);if(!uvm_config_db#(virtual my_if)::get(this, "", "vif", vif))`uvm_fatal("my_monitor", "virtual interface must be set for vif!!!")ap = new("ap", this);endfunctionextern task main_phase(uvm_phase phase);extern task collect_one_pkt(my_transaction tr);
endclasstask my_monitor::main_phase(uvm_phase phase);my_transaction tr;while(1) begintr = new("tr");collect_one_pkt(tr);ap.write(tr);end
endtasktask my_monitor::collect_one_pkt(my_transaction tr);byte unsigned data_q[$];byte unsigned data_array[];logic [7:0] data;logic valid = 0;int data_size;while(1) begin@(posedge vif.clk);if(vif.valid) break;end`uvm_info("my_monitor", "begin to collect one pkt", UVM_LOW);while(vif.valid) begindata_q.push_back(vif.data);@(posedge vif.clk);enddata_size  = data_q.size();   data_array = new[data_size];for ( int i = 0; i < data_size; i++ ) begindata_array[i] = data_q[i]; endtr.pload = new[data_size - 18]; //da sa, e_type, crcdata_size = tr.unpack_bytes(data_array) / 8; `uvm_info("my_monitor", "end collect one pkt", UVM_LOW);
endtask`endif

my_model.sv

`ifndef MY_MODEL__SV
`define MY_MODEL__SVclass my_model extends uvm_component;uvm_blocking_get_port #(my_transaction)  port;uvm_analysis_port #(my_transaction)  ap;extern function new(string name, uvm_component parent);extern function void build_phase(uvm_phase phase);extern virtual  task main_phase(uvm_phase phase);`uvm_component_utils(my_model)
endclass function my_model::new(string name, uvm_component parent);super.new(name, parent);
endfunction function void my_model::build_phase(uvm_phase phase);super.build_phase(phase);port = new("port", this);ap = new("ap", this);
endfunctiontask my_model::main_phase(uvm_phase phase);my_transaction tr;my_transaction new_tr;super.main_phase(phase);while(1) beginport.get(tr);new_tr = new("new_tr");new_tr.copy(tr);`uvm_info("my_model", "get one transaction, copy and print it:", UVM_LOW)new_tr.print();ap.write(new_tr);end
endtask
`endif

my_scoreboard.sv

`ifndef MY_SCOREBOARD__SV
`define MY_SCOREBOARD__SV
class my_scoreboard extends uvm_scoreboard;my_transaction  expect_queue[$];uvm_blocking_get_port #(my_transaction)  exp_port;uvm_blocking_get_port #(my_transaction)  act_port;`uvm_component_utils(my_scoreboard)extern function new(string name, uvm_component parent = null);extern virtual function void build_phase(uvm_phase phase);extern virtual task main_phase(uvm_phase phase);
endclass function my_scoreboard::new(string name, uvm_component parent = null);super.new(name, parent);
endfunction function void my_scoreboard::build_phase(uvm_phase phase);super.build_phase(phase);exp_port = new("exp_port", this);act_port = new("act_port", this);
endfunction task my_scoreboard::main_phase(uvm_phase phase);my_transaction  get_expect,  get_actual, tmp_tran;bit result;super.main_phase(phase);fork while (1) beginexp_port.get(get_expect);expect_queue.push_back(get_expect);endwhile (1) beginact_port.get(get_actual);if(expect_queue.size() > 0) begintmp_tran = expect_queue.pop_front();result = get_actual.compare(tmp_tran);if(result) begin `uvm_info("my_scoreboard", "Compare SUCCESSFULLY", UVM_LOW);endelse begin`uvm_error("my_scoreboard", "Compare FAILED");$display("the expect pkt is");tmp_tran.print();$display("the actual pkt is");get_actual.print();endendelse begin`uvm_error("my_scoreboard", "Received from DUT, while Expect Queue is empty");$display("the unexpected pkt is");get_actual.print();end endjoin
endtask
`endif

1. 使用Questasim搭建UVM验证环境

可参考

UVM系统验证基础知识0(Questasim搭建第一个UVM环境)

其中sim.do文件可加入一行view transcript 查看questasim命令行

UVM:一个简易验证平台例子相关推荐

  1. PHP服务器脚本实例,Shell脚本实现的一个简易Web服务器例子分享_linux shell

    这篇文章主要介绍了Shell脚本实现的一个简易Web服务器例子分享,本文实现的Web服务器非常简单实用,可以在你不想安装nginx.apache等大型WEB服务器时使用,需要的朋友可以参考下 假设你想 ...

  2. IC验证工程师高效战斗手册--高效验证平台搭建和冒烟测试要注意什么?

    前面我们一起探讨了"如何制定高效的验证方案",方案和战略有了,便到了具体执行.执行的第一步,即是验证平台的搭建和冒烟测试,本篇我们就一起聊聊,高效的搭建验证平台和冒烟过程中需要注意 ...

  3. 【UVM实战】第二章:一个简单的UVM验证平台(4)UVM 的终极大作:sequence

    文章目录 2.4.1.在验证平台中加入sequencer 2.4.2.sequence机制 2.4.3.default_sequence的使用 2.4.1.在验证平台中加入sequencer sequ ...

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

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

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

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

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

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

  7. uvm 形式验证_验证平台自动化篇之二:UVM Framework

    原标题:验证平台自动化篇之二:UVM Framework 一个UVM使用者,从新手到精通大致会经历三年的时间,而在经过这三年之后,verifier会有倦怠期.除了不可避免地在80%以上工作处于重复性劳 ...

  8. UVM实战 卷I学习笔记8——UVM验证平台的运行(2)

    目录 *build阶段出现UVM_ERROR停止仿真 *phase的跳转 phase机制的必要性 phase的调试 超时退出 *build阶段出现UVM_ERROR停止仿真 之前的代码中,如果使用co ...

  9. UVM验证方法学之一验证平台

    UVM验证方法学之一验证平台 在现代IC设计流程中,当设计人员根据设计规格说明书完成RTL代码之后,验证人员开始验证这些代码(通常称其为DUT,Design Under Test).验证工作主要保证从 ...

最新文章

  1. 韩梦飞沙-屏幕录像专家 win10 含注册机
  2. .NET Core 使用Dapper 操作MySQL
  3. 关于登录linux时,/etc/profile、~/.bash_profile等几个文件的执行过程
  4. 基于python的图形化邮件发送程序(支持添加附件)
  5. 弹性碰撞后速度方向_两物体发生弹性碰撞后.相对速度大小不变.方向相反. ,也可以说两物体的速度之和保持不变.即 ....
  6. sonar 中质量指标(度量)
  7. Kafka核心源码解析 - SocketServer源码解析
  8. svn常用命令与分支操作
  9. OpenShift 4 之Istio-Tutorial (8) 在服务之间配置Mutual TLS双向传输安全
  10. 如何计算一组数据的波动幅度_如何用Excel计算一个投资组合(双资产/三资产)的波动率?...
  11. 图像处理(MATLAB及FPGA)实现基础原理(持续更新)
  12. Uva 12063 Zero and Ones
  13. 【OneNote】同时设置中英文字体显示(雅黑+Consolas)
  14. 功率单位dBm与W间的换算
  15. 关于牛顿迭代求根的笔记
  16. ScreenToGif 2.15 简体中文版-GIF录制工具
  17. 文明重启哪个服务器最多,文明重启攻略 新手快速霸服技巧分享[多图]
  18. C语言简单编程案例——(五)
  19. php 如何获取真实的客户端ip
  20. Android来电,显示悬浮窗

热门文章

  1. navicat点击连接出现2059catching_sha2_password错误
  2. 《极光征文》颁奖 | 恭喜你完成 2019 第一个小目标
  3. win7计算机组策略打不开,Win7系统组策略打不开怎么办?组策略被锁住了怎么处理?...
  4. element-ui——timeline时间线组件+自动滚动+v-infinite-scroll无限滚动+动态加载——技能提升
  5. 海克斯康三坐标模块化c语言编程,海克斯康三坐标编程手册_海克斯康三坐标教程...
  6. kubernetes—ConfigMap 与 Secret
  7. excel 设置隔行变色功能
  8. 如何在 Unity 中制作一个道具系统
  9. Cannot load C:\Users\12778\AppData\Local\JetBrains\IntelliJIdea2021.1\tomcat\c0cf5d96-4221-48ee-b343
  10. centos7/win7 双系统安装教程