UVM入门系列(一)----通过uvm_gen脚本快速搭建一般验证平台(上)

UVM入门系列(一)----通过uvm_gen脚本快速搭建一般验证平台(上)


前言

文中所有代码已上传,可通过以下链接下载:
代码链接

待测设计:简单的8bit加法器;
仿真工具:vcs+verdi
DUT代码如下:

`timescale 1ns/1ps
module add(
    input clk,
    input rst,
    input [7:0] a,
    input [7:0] b,
    input cin,
    output reg cout,
    output reg [7:0] sum
);
always@(posedge clk or negedge rst) begin
    if(!rst) begin
        cout<=1'b0;
        sum<=8'b0;
    end
    else begin 
        {cout,sum}<=cin+a+b;
    end
end
endmodule

一、uvm_gen脚本

代码生成

首先介绍一下本文使用的uvm_gen脚本,通过使用该脚本会自动生成一个标准的UVM结构框架,针对本文DUT使用该脚本工具会生成如下图所示的基本框架代码。
在这里插入图片描述

图中可以看出脚本已经完成了验证平台的部分基础代码,接下来的工作是针对验证方案进行代码的补全。

cr_agent

脚本会自动生成一个cr_agent,用于生成时钟和复位信号(后续文章会对该部分进行进一步描述),本文工程简单起见直接使用该代码,不做改动。

二、代码的补全

*括号内为文件路径

1.interface

interface

1.1.i_agent_if.sv(verf/tb/agent/i)

脚本生成代码如下:

`ifndef I_AGENT_IF_SV
`define I_AGENT_IF_SV

interface i_agent_if();
//
endinterface : i_agent_if 

`endif // I_AGENT_IF_SV

加入DUT输入端口,代码完成如下:

`ifndef I_AGENT_IF_SV
`define I_AGENT_IF_SV

interface i_agent_if();
	logic [7:0] a;
	logic [7:0] b;
	logic cin;
endinterface : i_agent_if 

`endif // I_AGENT_IF_SV

1.2.o_agent_if.sv(verf/tb/agent/o)

同上操作,加入DUT输出端口:

`ifndef O_AGENT_IF_SV
`define O_AGENT_IF_SV

interface o_agent_if();
    logic cout;
    logic [7:0] sum;
endinterface : o_agent_if 

`endif // O_AGENT_IF_SV

2.i_seq_item.sv(/verf/tb/agent/i)

i_seq_item即为驱动入DUT的数据包。
脚本生成的代码如下

`ifndef I_SEQ_ITEM_SV
`define I_SEQ_ITEM_SV

class i_seq_item extends uvm_sequence_item;

	`uvm_object_utils(i_seq_item)
	
  extern function new(string name = "i_seq_item");
endclass : i_seq_item 

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

`endif // I_SEQ_ITEM_SV

添加激励信息和注册域的自动化:

`ifndef I_SEQ_ITEM_SV
`define I_SEQ_ITEM_SV

class i_seq_item extends uvm_sequence_item;
    rand bit [7:0] a;
    rand bit [7:0] b;
    rand bit       cin;

	`uvm_object_utils_begin(i_seq_item)
        `uvm_field_int(a,UVM_DEFAULT)
        `uvm_field_int(b,UVM_DEFAULT)
        `uvm_field_int(cin,UVM_DEFAULT)
    `uvm_object_utils_end

  extern function new(string name = "i_seq_item");
endclass : i_seq_item 

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

`endif // I_SEQ_ITEM_SV

3.add_tb.sv

该文件中进行dut的例化,接口的传递。
自动生成的代码如下(后面文章不再贴出原代码)

`timescale 1ns/1ns
module add_tb;


  `include "uvm_macros.svh"

  import uvm_pkg::*;

  import i_agent_pkg::*;
  import o_agent_pkg::*;
  import cr_agent_pkg::*;
  import add_env_pkg::*;

  logic  sysclock;
  logic  sysresetn;
  cr_if  m_cr_if();
  assign sysclock  = m_cr_if.sysclock;
  assign sysresetn = m_cr_if.sysresetn;

  i_agent_if   m_i_agent_if();
  o_agent_if   m_o_agent_if();
  //
  //dut
  //
  initial
  begin
      uvm_config_db #(virtual cr_if)::set(null,"\*", "m_cr_if", m_cr_if);
      uvm_config_db #(virtual i_agent_if)::set(null,"\*", "m_i_agent_if", m_i_agent_if);
      uvm_config_db #(virtual o_agent_if)::set(null,"\*", "m_o_agent_if", m_o_agent_if);

    run_test();
  end

endmodule

自动生成的代码只需要进行例化的DUT即可。
添加例化:

 add dut(
      .clk(sysclock),
      .rst(sysresetn),
      .a(m_i_agent_if.a),
      .b(m_i_agent_if.b),
      .cin(m_i_agent_if.cin),
      .cout(m_o_agent_if.cout),
      .sum(m_o_agent_if.sum)
  );

添加vcs dump波形代码

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

4.i_driver(verf/tb/agent/i)

1、例化时钟接口

 virtual interface cr_if cvif;

2、get时钟接口(接口从env传递,后面会说明如何在env中向i_driver传递该接口)

 if (!uvm_config_db #(virtual cr_if)::get(this, "", "cvif", cvif))
    `uvm_error("NOVIF", {"virtual interface must be set for: ",get_full_name(),".cvif"})

3、驱动激励信号

task i_driver::do_drive(i_seq_item req);
	vif.a=req.a;
	vif.b=req.b;
	vif.cin=req.cin;
	@(posedge cvif.sysclock);
endtask : do_drive

5.add_env.sv(verf/tb/env)

传递接口至上文所述i_driver,

	uvm_config_db#(virtual cr_if)::set(this, "m_i_agent.*", "cvif", m_cr_if);

6.构造sequence

在/verf/testcase/ 新建文件夹seq和test,

6.1 add_seq.sv

在seq文件夹新建add_seq.sv文件。
add_seq继承自自动生成的i_base_seq,具体代码如下:

class add_seq extends i_base_seq;
    `uvm_object_utils(add_seq)
    uvm_event seq_begin_ev;
    extern function new(string name="add_seq");
    extern task body();
endclass

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

task add_seq::body();
    seq_begin_ev=uvm_event_pool::get_global("seq_begin_ev");
    `uvm_info(get_type_name(),"Default sequence starting",UVM_HIGH)
    repeat(100) begin
        `uvm_do(req);
    end
    `uvm_info(get_type_name(),"Default sequence end",UVM_HIGH)
endtask

启动该sequence会发送100个随机激励包给driver。

6.2 seq_pkg.sv

seq文件夹新建seq_pkg.sv文件,方便后续扩展seq文件的管理。代码如下:

package seq_pkg;
    import uvm_pkg::*;
    import i_agent_pkg::*;
    `include "uvm_macros.svh"
    `include "add_seq.sv"
endpackage

6.3 add_test.sv

test文件夹新建test.sv文件,用于启动激励,控制仿真。


class add_test extends add_test_base;
    `uvm_component_utils(add_test)
    add_seq tc_seq;
    extern function new(string name,uvm_component parent=null);
    extern task main_phase(uvm_phase phase);
endclass

function add_test::new(string name,uvm_component parent=null);
    super.new(name,parent);
endfunction

task add_test::main_phase(uvm_phase phase);
    phase.raise_objection(this);
    this.tc_seq=new("tc_seq");
    tc_seq.start(m_env.m_vsequencer.m_i_seqer);
    #20;
    phase.drop_objection(this);
endtask

6.4 test_pkg.sv

test文件夹新建test_pkg.sv,方便管理test文件。

package test_pkg;
    import uvm_pkg::*;
    `include "uvm_macros.svh"
    `include "add_test_base.sv"
    `include "add_test.sv"
endpackage

7 待后续更新

总结:

至此,现在验证平台已经可以通过仿真并查看波形,monitor、reference model 和scoreboard部分的代码会在后续更新继续介绍,后续也会介绍如何使用脚本使用vcs仿真。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值