admin管理员组

文章数量:1533099

2023年12月13日发(作者:)

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,用于生成时钟和复位信号(后续文章会对该部分进行进一步描述),本文工程简单起见直接使用该代码,不

做改动。

二、代码的补全

*括号内为文件路径

ace

interface

1.1.i_agent_(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_(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_(/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");

(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");

(name);

endfunction : new

`endif // I_SEQ_ITEM_SV

_

该文件中进行dut的例化,接口的传递。

自动生成的代码如下(后面文章不再贴出原代码)

`timescale 1ns/1ns

module add_tb;

`include "uvm_"

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_ck;

assign sysresetn = m_cr_etn;

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_),

.cout(m_o_agent_),

.sum(m_o_agent_)

);

添加vcs dump波形代码

initial begin

$fsdbDumpfile("");

$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;

=;

@(posedge ck);

endtask : do_drive

_(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文件夹新建add_文件。

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");

(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_

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

package seq_pkg;

import uvm_pkg::*;

import i_agent_pkg::*;

`include "uvm_"

`include "add_"

endpackage

6.3 add_

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

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);

(name,parent);

endfunction

task add_test::main_phase(uvm_phase phase);

_objection(this);

_seq=new("tc_seq");

tc_(m_env.m_vsequencer.m_i_seqer);

#20;

_objection(this);

endtask

6.4 test_

test文件夹新建test_,方便管理test文件。

package test_pkg;

import uvm_pkg::*;

`include "uvm_"

`include "add_test_"

`include "add_"

endpackage

7 待后续更新

总结:

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

也会介绍如何使用脚本使用vcs仿真。

本文标签: 代码脚本文件生成