UVM验证——demo

目录

1.定义dut

2.验证功能

2.1 验证计划

 2.2 定义virtual interface

2.3 sequence_item

2.4 sequence

2.5 driver

2.6 monitor

2.7 scoreboard

2.8 agent

2.9 env

2.10 test

2.11 top

2.12 运行

3.总结


1.定义dut

由于是demo,这里简单的写了一个dut,其实就是一个计数器。代码如下:

`timescale 1ns/1ps
module counter(
    input clk,
    input rst_n,
    input cnt_en,
    output reg [7:0] out
);
    always @(posedge clk or negedge rst_n)
    begin
        if(~rst_n) begin
            out<=8'b0;
        end
        else if(cnt_en) begin
            if(out != 10) begin
                out<=out + 1'b1;
            end
            else begin
                out<=8'b0;
            end
        end
        else begin
            out<=8'b0;
        end
    end
endmodule

代码完成后,我们编写相关的dut_tb去测试相关功能是否符合。

module counter_tb();
    reg clk;
    reg rst_n;
    reg cnt_en;
    wire [6:0] out;

    counter t_cnt(.clk(clk), .rst_n(rst_n), .cnt_en(cnt_en), .out(out));

    initial
    begin
        clk = 1;
        rst_n = 0;
        cnt_en = 0;
        #10 rst_n = 1;
        cnt_en = 1;
        #100 cnt_en = 0;
        #200 cnt_en = 1;
        #1000 cnt_en = 0;
    end

    always #10 clk = ~clk;
endmodule

仿真后查看波形。

至此,我们的dut准备完毕。

2.验证功能

2.1 验证计划

  1. 定义uvm_sequence_item,用于生成相应的激励。并通过driver发送给dut。
  2. driver接收到item后,通过virtual interface发送给dut。
  3. monitor捕获 dut的输入和输出的值,并发送到scoreboard。
  4. scoreboard主要负责根据从monitor接收的输入和输出值检查设计的功能正确性。

 2.2 定义virtual interface

根据dut分析,定义相关interface如下:

  1. 以时钟clk为输入
  2. 有1位的rst_n,cnt_en和8位的data。
`ifndef COUNTER_IF__SV
`define COUNTER_IF__SV

interface counter_if(input clk);
    logic rst_n;
    logic cnt_en;
    logic [7:0] data;
endinterface

`endif

2.3 sequence_item

`ifndef COUNTER_ITEM__SV
`define COUNTER_ITEM__SV

class counter_item extends uvm_sequence_item;
    `uvm_object_utils(counter_item)

    rand bit count_en;
    rand bit rst_n;
    logic[7:0] counter_out;

    //将内容转成字符串,方便调试打印信息
    virtual function string convert2str();
        return $sformatf("count_en %d,rst_n %d, counter_out %d", count_en, rst_n, counter_out);
    endfunction

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

    //限定约束
    // constraint c1 { count_en dist {0:/10, 1:/90};}
    constraint c1 { count_en == 1;}
    constraint c2 {rst_n == 1;}
endclass

`endif

2.4 sequence

`ifndef COUNTER_SEQUENCE__SV
`define COUNTER_SEQUENCE__SV

class counter_item_seq extends uvm_sequence;
    `uvm_object_utils(counter_item_seq)

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

    rand int num;

    //约束发送激励的数量
    constraint c1 {soft num inside {[10:50]};}

    virtual task body();
        for (int i = 0; i < num; i++) begin
            counter_item item = counter_item::type_id::create("counter_item");
            start_item(item);
            item.randomize();
            `uvm_info("SEQ", $sformatf("generate new item %s", item.convert2str()), UVM_HIGH);
            finish_item(item);
        end

        `uvm_info("SEQ", $sformatf("Done generation of %d items.", num), UVM_LOW);
    endtask


endclass

`endif

2.5 driver

`ifndef COUNTER_DRIVER__SV
`define COUNTER_DRIVER__SV

class counter_driver extends uvm_driver #(counter_item);
    `uvm_component_utils(counter_driver)

    function new(string name="counter_driver", uvm_component parent = null);
        super.new(name, parent);
    endfunction

    //连接的interface
    virtual counter_if vif;

    virtual function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        //通过uvm_config_db获取到相应的vif
        if (!uvm_config_db#(virtual counter_if)::get(this, "", "counter_vif", vif))
            `uvm_fatal("DRV", "could not get vif")
    endfunction

    virtual task run_phase(uvm_phase phase);
        super.run_phase(phase);

        forever begin
            counter_item item;
            `uvm_info("DRV", $sformatf("wait for item from sequencer"), UVM_HIGH)
            //获取item;发送;通知完成(可以获取下一个item)
            seq_item_port.get_next_item(item);
            drive_item(item);
            seq_item_port.item_done();
        end
    endtask

    virtual task drive_item(counter_item item);
        @(vif.clk);
        vif.cnt_en <= item.count_en;
        vif.rst_n <= item.rst_n;
    endtask
endclass

`endif

2.6 monitor

`ifndef COUNTER_MONITOR__SV
`define COUNTER_MONITOR__SV

class counter_monitor extends uvm_monitor;
    `uvm_component_utils(counter_monitor)

    function new(string name="counter_monitor", uvm_component parent=null);
        super.new(name, parent);
    endfunction

    //定义uvm_analysis_port 
    uvm_analysis_port #(counter_item) mon_analysis_port;
    //需要连接的interface
    virtual counter_if vif;

    virtual function void build_phase(uvm_phase phase);
        //通过uvm_config_db获取到interface句柄
        if(!uvm_config_db#(virtual counter_if)::get(this, "", "counter_vif", vif))
            `uvm_fatal("MON", "Could not get vif")
        //创建analysis port
        mon_analysis_port = new("mon_analysis_port", this);
    endfunction

    virtual task run_phase(uvm_phase phase);
        super.run_phase(phase);

        forever begin
            @(posedge vif.clk);
            if(vif.cnt_en)begin
                //从interface获取相应的输出
                counter_item item = counter_item::type_id::create("item");
                item.count_en = vif.cnt_en;
                item.counter_out = vif.data;
                //发送给scoreboard
                mon_analysis_port.write(item);
            //`uvm_info("MON", $sformatf("Saw item %s", item.convert2str()), UVM_HIGH);
            end
        end
    endtask

endclass

`endif

2.7 scoreboard

`ifndef COUNTER_SCOREBOARD__SV
`define COUNTER_SCOREBOARD__SV

class counter_scoreboard extends uvm_scoreboard;
    `uvm_component_utils(counter_scoreboard)

    function new(string name="counter_scoreboard", uvm_component parent=null);
        super.new(name, parent);
    endfunction
    //期望输出
    bit[7:0] exp_cout = 8'b0;
    //定义analysis port的接收端
    uvm_analysis_imp#(counter_item, counter_scoreboard) m_analysis_imp;

    virtual function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        //创建
        m_analysis_imp = new("m_analysis_imp", this);
        // if(!uvm_config_db#)
    endfunction

    virtual function write(counter_item item);

        if(item.counter_out != exp_cout)begin
            `uvm_error("SCBD", $sformatf("ERROR! out %d exp %d", item.counter_out, exp_cout))
        end
        else begin
            `uvm_info("SCBD", $sformatf("PASS ! out %d exp %d", item.counter_out, exp_cout), UVM_LOW)
        end

        if(item.count_en == 0) begin
            exp_cout = 8'b0;
        end
        else begin
            if(exp_cout != 10) begin
                exp_cout ++;
            end
            else begin
                exp_cout = 0;
            end
        end
    endfunction
endclass

`endif

2.8 agent

`ifndef COUNTER_AGENT__SV
`define COUNTER_AGENT__SV

class counter_agent extends uvm_agent;
    `uvm_component_utils(counter_agent)

    function new(string name="counter_agent", uvm_component parent=null);
        super.new(name, parent);
    endfunction
    //agent内部包含了sequencer,driver,mon;
    uvm_sequencer #(counter_item) sqr;
    counter_driver    drv;
    counter_monitor   mon;

    extern virtual function void build_phase(uvm_phase phase);
    extern virtual function void connect_phase(uvm_phase phase);

endclass

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

    sqr = uvm_sequencer #(counter_item)::type_id::create("sqr", this);
    drv = counter_driver::type_id::create("drv", this);
    mon = counter_monitor::type_id::create("mon", this);
endfunction

function void counter_agent::connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    //将sequencer的seq_tem_export和driver的seq_item_port连接记起来,用于发送激励
    drv.seq_item_port.connect(sqr.seq_item_export);
endfunction

`endif

2.9 env

`ifndef COUNTER_ENV__SV
`define COUNTER_ENV__SV

class counter_env extends uvm_env;
    `uvm_component_utils(counter_env)
    function new(string name = "counter_env", uvm_component parent);
        super.new(name, parent);
    endfunction
    //整个验证环境,包含agent和scoreboard。
    //由于agent包含sequencer,driver,monitor,实际是将他们包含进来。
    counter_agent agt;
    counter_scoreboard scb;


    virtual function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        agt = counter_agent::type_id::create("agt", this);
        scb = counter_scoreboard::type_id::create("scb", this);
    endfunction

    extern virtual function void connect_phase(uvm_phase phase);
endclass

function void counter_env::connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    //将monitor的analysis_port和scoreboard的analysis_port接收端连接
    agt.mon.mon_analysis_port.connect(scb.m_analysis_imp);
endfunction

`endif

2.10 test

`ifndef BASE_TEST__SV
`define BASE_TEST__SV

class base_test extends uvm_test;
    `uvm_component_utils(base_test)
    function new(string name = "base_test", uvm_component parent = null);
        super.new(name, parent);
    endfunction

    //test包含了env和sequence以及相应的interface
    counter_env env;
    counter_item_seq seq;

    virtual counter_if vif;

    extern virtual function void build_phase(uvm_phase phase);
    //run_phase时执行相应的激励
    virtual task run_phase(uvm_phase phase);
        phase.raise_objection(this);
        seq.start(env.agt.sqr);
        #1000;
        phase.drop_objection(this);
    endtask


endclass

function void base_test::build_phase(uvm_phase phase);
    super.build_phase(phase);
    env = counter_env::type_id::create("env", this);
    //通过uvm_config_db获取interface
    if (!uvm_config_db#(virtual counter_if)::get(this, "", "counter_vif", vif)) begin
        `uvm_fatal("TEST", "Did not get vif")
    end

    //通过uvm_config_db注册interface
    uvm_config_db#(virtual counter_if)::set(this, "env.agt.*", "couter_vif", vif);

    seq = counter_item_seq::type_id::create("seq");
    seq.randomize();
endfunction

`endif
`ifndef COUNTER_CASE0__SV
`define COUNTER_CASE0__SV

class counter_case0 extends base_test;
    function new(string name = "counter_case0", uvm_component parent = null);
        super.new(name, parent);
    endfunction

    extern virtual function void build_phase(uvm_phase phase);
    `uvm_component_utils(counter_case0)
endclass

function void counter_case0::build_phase(uvm_phase phase);
    super.build_phase(phase);
    seq.randomize();
endfunction

`endif

2.11 top

`ifndef TOP__SV
`define TOP__SV

import uvm_pkg::*;
//包含相关文件
`include "dut.v"
`include "counter_item.sv"
`include "counter_if.sv"
`include "counter_driver.sv"
`include "counter_monitor.sv"
`include "counter_scoreboard.sv"
`include "counter_agent.sv"

`include "counter_env.sv"
`include "counter_sequence.sv"
`include "base_test.sv"
`include "counter_case0.sv"

module tb;
    //时钟信号
    reg clk;
    always #10 clk = ~clk;
    //使用clk创建相应的interface
    counter_if cif(clk);
    //实例化counter,通过interface连接
    counter cnt(.clk(clk), .rst_n(cif.rst_n), .cnt_en(cif.cnt_en), .out(cif.data));

    initial begin
        clk <= 0;
        //通过uvm_config_db注册interface
        uvm_config_db#(virtual counter_if)::set(null, "", "counter_vif", cif);//uvm_test_top.*
        //运行相应case
        run_test("counter_case0");
    end


endmodule

`endif

2.12 运行

vcs -debug -full64 -sverilog -timescale=1ns/1ns -ntb_opts uvm-1.1 +incdir+. top.sv -l comp.log
./simv

3.总结

本文只是给出demo的一些说明,具体其他的相关概念会在其他文章进行说明。

相关代码:https://github.com/zljuft/verify


 

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值