【UVM】-- UVM测试平台搭建与调试

这篇具有很好参考价值的文章主要介绍了【UVM】-- UVM测试平台搭建与调试。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1、明确DUT功能

《UVM》实战中这个DUT的功能比较简单:

DUT要完成的功能

  • 在clk的上升沿,且rst不为低电平的时候,将输入的信号直接发送出去,并且输出输入的使能信号;
  • 在clk上升沿,如果rst为低电平,复位输出信号和使能信号

DUT对外接口及接口功能

  • clk 时钟输入信号
  • rst_n 复位输入信号
  •  rxd 8bit输入数据信号
  • rx_dv 输入使能信号
  • txd 8bit输出数据信号
  • tx_en 输出是能信号

2、测试计划

验证复位功能正常

  • 输入:复位信号rst_n为低电平,rxd输入数据,rx_dv输入数据--》输出端输出数据和使能均为0
  • 输入:复位信号rst_n为低电平,rxd无输入数据,rx_dv无输入数据--》输出端输出数据和使能均为0

验证数据传输功能正常

  • 输入:复位信号rst_n为高电平,rxd无输入数据,rx_dv无输入数据--》输出端无输出数据和使能数据
  • 输入:复位信号rst_n为高电平,rxd有输入数据,rx_dv有输入数据--》输出端输出数据和使能数据与输入保持一致

验证状态转换 

  • 输入数据和使能信号一直有效,复位信号从高电平跳转到低电平--》输出端在复位后输出0
  • 输入数据和使能信号一直有效,复位信号从低电平跳转到高电平--》输出端在复位时间输出0,复位结束后恢复输出

接口数据范围测试

  • rxd 可以正常发送0-8bit大小的数据;
  • rx_dv可以正常发送0/1

3、测试用例

case1

复位信号rst_n为低电平,rxd输入数据8'b1000_0010,rx_dv输入数据1'b1--》输出端输出数据和使能均为0

case2

复位信号rst_n为低电平,rxd无输入数据,rx_dv无输入数据--》输出端输出数据和使能均为0

case3

复位信号rst_n为高电平,rxd无输入数据,rx_dv无输入数据--》输出端无输出数据和使能数据

case4

复位信号rst_n为高电平,rxd有输入数据8'b1010_0010,rx_dv有输入数据1'b0--》输出端输出数据和使能数据与输入保持一致

case5

输入数据8'b1010_0010和使能信号1‘b1一直有效,复位信号从高电平跳转到低电平--》输出端在复位后输出0

case6

输入数据8'b1010_0010和使能信号1‘b1一直有效,复位信号从低电平跳转到高电平--》输出端在复位时间输出0,复位结束后恢复输出

case7

输入数据rxd在0-255之间随机产生,使能信号在0-1之间随机,复位信号为高电平,输出跟随输入变化

4、搭建测试平台

开始一步一步调试UVM测试

测试平台需求

  • 产生DUT输入信号
  • 监控DUT输出信号
  • 和预期比对,判断用例执行成功和失败

测试平台进化

dut的代码:

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) begin
   if(!rst_n) begin
      txd <= 8'b0;
      tx_en <= 1'b0;
   end
   else begin
      txd <= rxd;
      tx_en <= rx_dv;
   end
end
endmodule

top中将DUT和测试信号线进行连接,然后产生clk和rst

test1.0

定义一个专门用于产生激励信号的类,在该类中修改top模块中的输入信号,然后在top中调用这个类中的方法,实现激励信号的生成。

具体代码如下:

top代码如下:

`include "dut_driver.sv"
`include "dut.sv"

module top;

reg clk;
reg rst_n;
reg [7:0] rxd;
reg rx_dv;
wire [7:0] txd;
wire tx_en;


//connect to dut
dut dut_t(
           .clk(clk),
           .rst_n(rst_n),
           .rxd(rxd),
           .rx_dv(rx_dv),
           .txd(txd),
           .tx_en(tx_en)
);

//clk generate
initial begin
   clk = 0;
   rst_n = 0;
   forever begin
      #100 clk = ~clk;
   end
end

//rst_n generate

initial begin
   #1000
   rst_n = ~rst_n;
   #8000
   rst_n = ~rst_n;
   #1000
   rst_n = ~rst_n;
end

//driver generate signal
initial begin
   //实例dut_driver
   dut_driver m_drv;
   m_drv = new();
   m_drv.run();
   #1000;
   $finish();
end

initial begin
   $fsdbDumpfile("tb.fsdb");
   $fsdbDumpvars;
end

endmodule

dut_driver类如下:

综合所有的用例场景:rxd一直存在且变化,rx_dv一直存在且变化,rst_n从不复位到复位,从复位到不复位

/*
*
dut_driver类
产生dut激励信号
修改top中的rxd和rx_dv信号
*/

class dut_driver;
   task run;
      top.rxd <= 8'b0;
      top.rx_dv <= 1'b0;

      for(int i = 0; i < 256; i++) begin
         @(posedge top.clk);
         top.rxd <= $urandom_range(0,255);
         top.rx_dv <= $urandom_range(0,1);
      end

   endtask

endclass

 仿真:输出跟随输入变化

uvm 测试平台,数字IC,单片机,fpga开发,嵌入式硬件

uvm 测试平台,数字IC,单片机,fpga开发,嵌入式硬件

 test2.0

引入UVM可以自动实例driver,并且自动运行driver中的主函数。

top中引入uvm包,自动执行类调用run_test()

`include "uvm_macros.svh"
import uvm_pkg::*;

`include "dut_driver.sv"
`include "dut.sv"

module top;

reg clk;
reg rst_n;
reg [7:0] rxd;
reg rx_dv;
wire [7:0] txd;
wire tx_en;


//connect to dut
dut dut_t(
           .clk(clk),
           .rst_n(rst_n),
           .rxd(rxd),
           .rx_dv(rx_dv),
           .txd(txd),
           .tx_en(tx_en)
);

//clk generate
initial begin
   clk = 0;
   rst_n = 0;
   forever begin
      #100 clk = ~clk;
   end
end

//rst_n generate

initial begin
   #1000
   rst_n = ~rst_n;
   #8000
   rst_n = ~rst_n;
   #1000
   rst_n = ~rst_n;
end

//driver generate signal
initial begin
   run_test("dut_driver");
end

initial begin
   $fsdbDumpfile("tb.fsdb");
   $fsdbDumpvars;
end

endmodule

dut_driver修改:

  • 继承uvm_driver
  • 注册类到factory
  • 添加new,构造uvm树,现在只有driver,他是最高层,parent为null,
  • 将主函数移动到main_phase中,这样调用run_test就会自动实例化driver并自动执行mian_phase中的内容;
  • main_phase中要添加raise_objection,这样进入main_phase后uvm才知道里面有要执行的代码,否则它就进入直接退出了;最后要drop_objection. 
/*
*
dut_driver类
产生dut激励信号
修改top中的rxd和rx_dv信号
*/

class dut_driver extends uvm_driver;

   `uvm_component_utils(dut_driver);//注册factory

   function new(string name = "dut_driver", uvm_component parent = null);
      super.new(name, parent);//用于构建UVM树
      `uvm_info("dut_driver", "dut_driver is created!", UVM_LOW);
   endfunction

   extern virtual task main_phase(uvm_phase phase);//主函数,注册完factory后可以自动运行
endclass

task dut_driver :: main_phase(uvm_phase phase);
   phase.raise_objection(this);//需要起一个objection才能继续运行正常的代码,否则直接进来就退出了   
   top.rxd <= 8'b0;
   top.rx_dv <= 1'b0;

   for(int i = 0; i < 256; i++) begin
      @(posedge top.clk);
      top.rxd <= $urandom_range(0,255);
      top.rx_dv <= $urandom_range(0,1);
      `uvm_info("dut_driver", "driver generate once", UVM_LOW);
   end

   phase.drop_objection(this);
endtask

 test3.0

解耦top和dut_driver,消除dut_driver中信号中的top层次。

  • 定义interface接口,使用接口连接dut
  • 引入虚拟接口,使用接口消除dut_driver中的top层次
  • 在uvm中top和component之间的通信使用config_db来进行配置打通接口

interface:

interface my_if(input clk, input rst_n);
   logic [7:0] data;
   logic en_data;
endinterface

top中使用接口:

`include "uvm_macros.svh"
import uvm_pkg::*;
`include "my_if.sv"
`include "dut_driver.sv"
`include "dut.sv"

module top;
reg clk;
reg rst_n;

my_if input_if(clk, rst_n);
my_if output_if(clk, rst_n);

//connect to dut
dut dut_t(
           .clk(clk),
           .rst_n(rst_n),
           .rxd(input_if.data),
           .rx_dv(input_if.en_data),
           .txd(output_if.data),
           .tx_en(output_if.en_data)
);

//clk generate
initial begin
   clk = 0;
   rst_n = 0;
   forever begin
      #100 clk = ~clk;
   end
end

//rst_n generate

initial begin
   #1000
   rst_n = ~rst_n;
   #8000
   rst_n = ~rst_n;
   #1000
   rst_n = ~rst_n;
end

initial begin
   uvm_config_db #(virtual my_if)::set(null, "uvm_test_top", "vif", input_if);//将input_if传给dut_driver中的指定的vif
end

//driver generate signal
initial begin
   run_test("dut_driver");
end

initial begin
   $fsdbDumpfile("tb.fsdb");
   $fsdbDumpvars;
end

endmodule

 driver中引入虚接口

/*
*
dut_driver类
产生dut激励信号
修改top中的rxd和rx_dv信号
*/

class dut_driver extends uvm_driver;

   virtual my_if vif;//使用虚接口
   `uvm_component_utils(dut_driver);//注册factory

   function new(string name = "dut_driver", uvm_component parent = null);
      super.new(name, parent);//用于构建UVM树
      `uvm_info("dut_driver", "dut_driver is created!", UVM_LOW);
   endfunction

   extern virtual function void build_phase(uvm_phase phase);
   extern virtual task main_phase(uvm_phase phase);//主函数,注册完factory后可以自动运行
endclass

function void dut_driver::build_phase(uvm_phase phase);
   super.build_phase(phase);
   `uvm_info("dut_driver", "config_db connect top-if and driver-if", UVM_LOW);
   if(!uvm_config_db #(virtual my_if)::get(this, "", "vif", vif)) begin
      `uvm_fatal("dut_driver", "get interface fail");//如果没有获得vif的配置就报错直接退出仿真
   end
endfunction

task dut_driver :: main_phase(uvm_phase phase);
   phase.raise_objection(this);//需要起一个objection才能继续运行正常的代码,否则直接进来就退出了   
   vif.data <= 8'b0;
   vif.en_data <= 1'b0;

   for(int i = 0; i < 256; i++) begin
      @(posedge vif.clk);
      vif.data <= $urandom_range(0,255);
      vif.en_data <= $urandom_range(0,1);
      `uvm_info("dut_driver", "driver generate once", UVM_LOW);
   end

   phase.drop_objection(this);
endtask

 test4.0

加入transaction,由transaction生成要传输的数据包,一个transaction类对应一种协议数据包。

  • 定义transaction类,定义数据包
  • 在driver类中实例化transaction,将transaction发送到接口送出
  • 在top中引入transaction

 transaction:

class dut_transaction extends uvm_sequence_item;
   rand 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'h0000;
   endfunction

   function void post_randomize();//这个会在randomize后自动调用
      crc = calc_crc;
   endfunction

   function new(string name = "dut_transaction");
      super.new(name);
   endfunction

   `uvm_object_utils(dut_transaction);//注册transaction的factory

endclass
~        

driver中添加transaction并将transaction转换成接口数据驱动出去:文章来源地址https://www.toymoban.com/news/detail-611126.html

/*
*
dut_driver类
产生dut激励信号
修改top中的rxd和rx_dv信号
*/

class dut_driver extends uvm_driver;

   virtual my_if vif;//使用虚接口
   dut_transaction my_trs;//定义transaction

   `uvm_component_utils(dut_driver);//注册factory

   function new(string name = "dut_driver", uvm_component parent = null);
      super.new(name, parent);//用于构建UVM树
      `uvm_info("dut_driver", "dut_driver is created!", UVM_LOW);
   endfunction

   extern virtual function void build_phase(uvm_phase phase);
   extern virtual task main_phase(uvm_phase phase);//主函数,注册完factory后可以自动运行
   extern virtual task drive_pkg(dut_transaction tr);
endclass

function void dut_driver::build_phase(uvm_phase phase);
   super.build_phase(phase);

   `uvm_info("dut_driver", "config_db connect top-if and driver-if", UVM_LOW);
   if(!uvm_config_db #(virtual my_if)::get(this, "", "vif", vif)) begin
      `uvm_fatal("dut_driver", "get interface fail");//如果没有获得vif的配置就报错直接退出仿真
   end
endfunction

task dut_driver :: main_phase(uvm_phase phase);
   phase.raise_objection(this);//需要起一个objection才能继续运行正常的代码,否则直接进来就退出了   

   //测试三组
   for(int i = 0; i < 3; i++) begin
      my_trs = new("my_tr");//实例化transaction
      assert(my_trs.randomize());//随机来一个数据包
      drive_pkg(my_trs);//将这个数据包送出去
   end
   phase.drop_objection(this);
endtask

task dut_driver::drive_pkg(d

到了这里,关于【UVM】-- UVM测试平台搭建与调试的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 基于vcs+uvm+xilinx ip的仿真平台的半自动化搭建

    系 统:ubuntu 18.04 仿真平台:vcs_2018.09-SP2 开发平台:vivado 2019.2 本文的主要目的是自动化搭建基于vcs+uvm+xilinx ip的仿真平台,节省平台搭建的时间与精力。 拿到一个项目,一般的平台搭建的步骤:去网上找一个makefile脚本(或者使用原项目脚本),修改相应的软件路径,添加

    2024年01月18日
    浏览(48)
  • 基于UVM+VCS基本平台,运行《UVM实战》中的第一个UVM代码并输出结果

    (1)下载puvm.tar.gz和uvm-1.1d.tar.gz压缩包 ,使用分别使用tar zxvf puvm.tar.gz和 tar zxvf uvm-1.1d.tar.gz解压到当前目录下 (2)找到puvm-src-ch2-dut-dut.sv文件,将该文件拷贝到puvm-src-ch2-section2.2-2.2.1目录下 (3)打开puvm-src-ch2-section2.2-2.2.1-Makefile.vcs文件并按照下面的方法进行编辑,编辑完后

    2024年02月09日
    浏览(47)
  • 诙谐有趣的《UVM实战》笔记——第二章 一个简单的UVM验证平台

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

    2024年02月08日
    浏览(61)
  • 【从零开始学习 UVM】6.4、UVM 激励产生 —— uvm_do 宏详解

    请注意, start 方法的 call_pre_post 字段设置为0, 这意味着在使用这些序列宏时,序列的pre_body和post_body方法将永远不会被调用 。否则,执行流程与通过start方法执行序列时类似。 使用序列宏的优点是可以使用内联约束,但是您失去了控制执行sequence中 pre_body 和 post_body 方法调

    2023年04月08日
    浏览(75)
  • 【从零开始学习 UVM】9.2、UVM Config DB —— UVM config database 详解【重要】

    UVM有一个内部数据库表,可以将值存储在给定名称下,并且稍后可以由其他TestBench组件检索。 uvm_config_db 类提供了一个方便的接口,位于 uvm_resource_db 之上,以简化用于uvm_component实例的基本接口。 请注意,所有函数都是静态的,并且必须使用 :: 作用域运算符调用 。 这样的配

    2023年04月09日
    浏览(78)
  • UVM实战_5_UVM中的寄存器模型

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 本章节主要介绍UVM实战第7章寄存器模型的内容 通常来说,DUT中会有一组 控制端口 ,通过控制端口,可以配置DUT中的寄存器,DUT可以根据寄存器的值来改变行为,这组控制端口就是寄存器配置总线。 暂

    2024年01月23日
    浏览(58)
  • 【从零开始学习 UVM】8.2、Reporting Infrastructure —— uvm_printer 详解

    在一个随机验证环境中,数据对象不断地由不同的组件生成和操作, 如果能够显示对象的内容,则调试会变得更加容易 。 传统上,这是通过将值打印到日志文件或屏幕上的 $display 语句和自定义打印函数来完成的。

    2023年04月09日
    浏览(39)
  • UVM实战--加法器

    这里以UVM实战(张强)第二章为基础修改原有的DUT,将DUT修改为加法器,从而修改代码以使得更加深入的了解各个组件的类型和使用。 和第二章的平台的主要区别点 (1)有两个transaction,一个为transaction_i,一个为transaction_o,由于DUT的输入输出值并不相同,输入为a,b,cin,输

    2024年02月06日
    浏览(44)
  • UVM重点归纳(一)

    1.1 利用工厂机制的一般实现步骤: 1.继承 范式: class comp_type/obj_type extends uvm_component/uvm_object; 实例: class comp1/obj1 extends uvm_component/uvm_object; 2.注册 范式: ​​​​​​​ `uvm_component/object_utils(comp_type/obj_type); 实例: `uvm_component/object_untils(comp1/obj1); 3.new函数声明 范式: func

    2024年02月14日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包