很早之前就说写一个简单的uvm环境

首先是一个简单的dut

`timescale lns/10fs
module mul( 
    clk, 
    rst_n, 
    num_a, 
    num_b, 
    num_c
);

    input  clk;
    input  rst__n;
    input  [7:0] num__a;
    input  [7:0] num__b;
    output [7:0] num__c;

    reg    [7:0] a;
    reg    [7:0] b;
    reg    [7:0] c;

    assign num_c = c;

    always @(posedge clk or negedge rst_n)begin
        if (!rst_n == l'bl)begin
            c <= 8'h0; 
        end else begin
            c <= num_a + num_b;
        end
    end

endmodule
`timescale lns/10fs
module top(
    clk,
    rst_n,
    num_a,
    num_b,
    num_c
);
    input  clk;
    input  rst_n;
    input  [7:0] num_a;
    input  [7:0] num_b;
    output [7:0] num_c;
    mul U_MUL(
    . clk(clk),
    . rst_n(rst_n), 
    . num_a(num_a), 
    . num_b(num_b), 
    . num_c(num_c) 
    );
endmodule

之后是harness

module harness;
    logic elk; 
    logic rst_n; 
    logic [7:0] num_a; 
    logic [7:0] num_b; 
    logic [7:0] num_c;

    initial begin
        clk = 0; 
        rst_n = 0;
        #100ns rst_n = 1;
    end

    always begin
        #5ns clk = ~clk;
    end

    my_interface tx_if(clk,rst_n); 
    my_interface rx_if(clk,rst_n);

    top dut(
        .clk(clk),
        .rst_n(rst_n), 
        .num_a(num_a), 
        .num_b(num_b), 
        .num_c(num_c) 
    );

    initial begin
        uvm_config_db #(virtual my_interface) :: set(null, "uvm_test_top.env_.rx_agt*", "vif", rx_if);
        uvm_config_db #(virtual my_interface) :: set(null, "uvm_test_top.env_.tx_agt*", "vif", tx_if);
    end

    initial begin
        run_test();
    end

    assign num_a = tx_if.a; 
    assign num_b = tx_if.b; 
    assign rx_if.c = num_c;

    initial begin
        $vcdpluson;
        $fsdbDumpon;
    end

endmodule

之后是interface

interface my_interface(input bit clk,input bit rst_n);

    logic [7:0] a; 
    logic [7:0] b; 
    logic [7:0] c;

    clocking mon_cb@(posedge clk); 
        inout a; 
        inout b; 
        inout c;
    endclocking

endinterface

之后是transaction

class my_transaction extends extends uvm_sequence_item; 
    rand bit  [7:0] a; 
    rand bit  [7:0] b; 
    rand bit  [7:0] c; 
    rand byte kk[];
    
    constraint k_cons{ 
        kk.size >= 10; 
        kk.size <= 90;
    }

    `uvm_object_utils_begin(my_transaction)
        //'uvm_field_int(a,UVM_ALL_0N)
        //'uvm_field_int(b,UVM_ALL_0N)
        `uvm_field_int(c,UVM_ALL_0N)
        `uvm_field_array_int(kk,UVM_ALL_0N)
    `uvm_object_utils_end
    
    extern function new(string name = "my_transaction"); 

endclass

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

之后是sequencer

class my_sequencer extends uvm_sequencer #(my_transaction);

    `uvm_component_utils(my_sequencer)
    extern function new(string name, uvm_component parent); 

endclass

function my_sequencer::new(string name, uvm_component parent);
    super.new(name,parent); 
endfunction

之后是tx部分

class tx_driver extends uvm_driver #(my_transaction); 

    virtual my_interface vif;

    `uvm_component_utils(tx_driver)

    extern function new(string name, uvm_component parent); 
    extern function void build_phase(uvm_phase phase); 
    extern virtual task reset_phase(uvm_phase phase); 
    extern virtual task main_phase(uvm_phase phase);

endclass

function tx_driver::new(string name, uvm_component parent);
    super.new(name,parent); 
endfunction

function void tx_driver::build_phase(uvm_phase phase); 
    super.build_phase(phase);
    if (!uvm_config_db#(virtual my_interface)::get(this,"","vif",vif))
        `uvm_fatal("tx_driver","virtual interface get fail !"); 
endfunction

task tx_driver::reset_phase(uvm_phase phase);

    vif.a <= $urandom_range(8'hff,8'h0); 
    vif.b <= $urandom_range(8'hff,8'h0);

endtask

task tx_driver::main_phase(uvm_phase phase); 

    my_transaction tx_tr; 

    super.main_phase(phase); 

    while(l)begin
        seq_item_port.get_next_item(req);
        tx_tr = req;
        vif.a <= tx_tr.a;
        vif.b <= tx_tr.b;
        seq_item_port.item_done();
    end

endtask
class tx_monitor extends uvm_monitor;

    virtual my_interface vif;
    uvm_analysis_port #(my_transaction) tx_mon_ap;
    `uvm_component_utils(tx_monitor)

    extern function new(string name, uvm_component parent);
    extern function void build_phase(uvm_phase phase); 
    extern virtual task main_phase(uvm_phase phase);

endclass

function tx_monitor::new(string name, uvm_component parent);
    super.new(name,parent); 
endfunction

function void tx_monitor::build_phase(uvm_phase phase); 

    super.build_phase(phase); 
    tx_mon_ap = new("tx_mon_ap", this);
    if (!uvm_config_db#(virtual my_interface)::get(this,"","vif",vif)) 
        `uvm_fatal("tx_monitor","virtual interface get fail !"); 

endfunction

task tx_monitor::main_phase(uvm_phase phase); 

    my_transaction tx_tr; 
    super.main_phase(phase);

    while(l)begin
        tx_tr = new(); 
        tx_tr.a = vif.a; 
        tx_tr.b = vif.b; 
        tx_mon_ap.write(tx_tr);
        @(posedge vif.clk);
    end

endtask
class tx_agent extends uvm_agent;

    tx_monitor mon;
    tx_driver  drv;
    my_sequencer sqr;
    uvm_analysis_port #(my_transaction) ap;
    `uvm_component_utils(tx_agent)

    extern function new(string name, uvm_component parent); 
    extern function void build_phase(uvm_phase phase); 
    extern function void connect_phase(uvm_phase phase); 
    extern virtual task main_phase(uvm_phase phase);
    
endclass

function tx_agent::new(string name, uvm_component parent);
super.new(name,parent); 
endfunction

function void tx_agent::build_phase(uvm_phase phase); 
    super.build_phase(phase);
    mon = tx_monitor   ::type_id:: create ("mon", this); 
    drv = tx_driver    ::type_id:: create ("drv", this);
    sqr = my_sequencer ::type_id:: create ("sqr", this);
endfunction

function void tx_agent::connect_phase(uvm_phase phase); 
    super.connect_phase(phase); 
    ap = mon.tx_mon_ap;
    drv.seq_item_port.connect(sqr.seq_item_export); 
endfunction

task tx_agent::main_phase(uvm_phase phase);
super.main_phase(phase); 
endtask

之后是rx部分

class rx_monitor extends uvm_monitor; 

    virtual my_interface vif;
    uvm_analysis_port #(my_transaction) rx_mon_ap;
    `uvm_component_utils(rx_monitor)

    extern function new(string name, uvm_component parent); 
    extern function void build_phase(uvm_phase phase); 
    extern virtual task main_phase(uvm_phase phase);

endclass

function rx_monitor::new(string new(string name, uvm_component parent);
    super.new(name,parent); 
endfunction

function void rx_monitor::build_phase(uvm_phase phase); 
    super.build_phase(phase); 
    rx_mon_ap = new("rx_mon_ap", this);
    if (!uvm_config_db#(virtual my_interface)::get(this,"","vif",vif)) 
        'uvm_fatal("rx_monitor","virtual interface get fail !"); 
endfunction

task rx_monitor::main_phase(uvm_phase phase); 
    my_transaction rx_tr; 
    super.main_phase(phase);
    while(l)begin
        rx_tr=new();
        @(posedge vif.clk); 
        rx_tr.c = vif.c; 
        rx_mon_ap.write (rx_tr);
    end
endtask
class rx_agent extends uvm_agent; 

    rx_monitor mon;
    uvm_analysis_port #(my_transaction) ap;
    `uvm_component_utils(rx_agent)

    extern function new(string name, uvm_component parent); 
    extern function void build_phase(uvm_phase phase); 
    extern function void connect_phase(uvm_phase phase); 
    extern virtual task main_phase(uvm_phase phase);

endclass

function rx_agent::new(string name, uvm_component parent);
    super.new(name,parent); 
endfunction

function void rx_agent::build_phase(uvm_phase phase); 
    super.build_phase(phase);
    mon = rx_monitor::type_id::create("mon",this); 
endfunction

function void rx_agent::connect_phase(uvm_phase phase); 
    super.connect_phase(phase); 
    ap = mon.rx_mon_ap; 
endfunction

task rx_agent::main_phase(uvm_phase phase);
    super.main_phase(phase); 
endtask

之后是env

class env extends uvm_env;

    rx_agent   rx_agt; 
    tx_agent   tx_agt; 
    rm         rm_;
    scoreboard sc;
    `uvm_component_utils(env)

    uvm_tlm_analysis_fifo #(my_transaction) mon_rm_fifo; 
    uvm_tlm_analysis_fifo #(my_transaction) rm_sc_fifo; 
    uvm_tlm_analysis_fifo #(my_transaction) sc_mon_fifo;

    extern function new(string name, uvm_component parent); 
    extern function void build_phase(uvm_phase phase); 
    extern function void connect_phase(uvm_phase phase); 
    extern virtual task configure_phase(uvm_phase phase); 
    extern virtual task main_phase(uvm_phase phase);

endclass

function env::new(string name, uvm_component parent);
    super.new(name,parent);
endfunction

function void env::build_phase(uvm_phase phase); 

    super.build_phase(phase);

    rx_agt = rx_agent   ::type_id:: create ("rx_agt", this);
    tx_agt = tx_agent   ::type_id:: create ("tx_agt", this);
    rm_    = rm         ::type_id:: create ("rm_ "  , this);
    sc     = scoreboard ::type_id:: create ("sc "   , this);
    mon_rm_fifo = new("mon_rm_fifo", this); 
    rm_sc_fifo  = new("rm_sc_fifo",  this); 
    sc_mon_fifo = new("sc_mon_fifo", this);

endfunction

function void env::connect_phase(uvm_phase phase); 

    super.connect_phase(phase);

    tx_agt.ap.  connect(mon_rm_fifo.analysis_export); 
    rm_.port.   connect(mon_rm_fifo.blocking_get_export);
    rm_.rm_ap.  connect (rm_sc_fifo.analysis_export); 
    sc.rm_port. connect (rm_sc_fifo.blocking_get_export);
    rx_agt.ap.  connect(sc_mon_fifo.analysis_export);
    sc.dut_port.connect(sc_mon_fifo.blocking_get_export);

endfunction

task env::configure_phase(uvm_phase phase);
    super.configure_phase(phase); 
endtask

task env::main_phase(uvm_phase phase);
    super,main_phase(phase); 
endtask

之后是rm

class rm extends uvm_component;

    uvm_blocking_get_port #(my_transaction) port; 
    uvm_analysis_port #(my_transaction) rm_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(rm)

endclass

function rm::new(string name, uvm_component parent);
    super.new(name,parent); 
endfunction

function void rm::build_phase(uvm_phase phase); 
super.build_phase(phase); 
port  = new("port", this); 
rm_ap = new("rm_ap",this); 
endfunction

task rm::main_phase(uvm_phase phase); 

    my_transaction tr; 
    my_transaction send_tr;

    super.main_phase(phase);

    while(l)begin
        port.get(tr);
        send_tr = new("send_tr");
        send_tr = tr;
        send_tr.c = send_tr.a + send_tr.b; 
        rm_ap.write(send_tr);
    end

endtask
class scoreboard extends extends uvm_scoreboard; 

    my_transaction rm_queue[$];
    uvm_blocking_get_port #(my_transaction) rm_port; 
    uvm_blocking_get_port #(my_transaction) dut_port;
    `uvm_component_utils(scoreboard)

    extern function new(string name, uvm_component parent); 
    extern function void build_phase(uvm_phase phase); 
    extern function void connect_phase(uvm_phase phase); 
    extern virtual task main_phase(uvm_phase phase); 

endclass

function scoreboard::new(string name, uvm_component parent);
    super.new(name,parent); 
endfunction

function void scoreboard::build_phase(uvm_phase phase); 
    super.build_phase(phase); 
    rm_port  = new("rm_port ",this);
    dut_port = new("dut_port", this); 
endfunction

function void scoreboard::connect_phase(uvm_phase phase);
    super.connect_phase(phase); 
endfunction

task scoreboard::main_phase(uvm_phase phase); 

    my_transaction rm_tr, dut_tr, chk_tr; 

    super.main_phase(phase); 

    fork

    while(l)begin
        rm_port.get(rm_tr); 
        rm_queue.push_back(rm_tr);
    end

    while(l)begin
        dut_port.get(dut_tr);
        if (rm_queue.size() > 0)begin
            chk_tr = rm_queue.pop_front(); 
        if(dut_tr.compare(chk_tr)) begin
            `uvm_info("scoreboard", "ok", UVM_L0W); 
            dut_tr.print (); 
            chk_tr.print (); 
        end else begin
            `uvm_error("scoreboard", "fail");
        end
    end

    join

endtask

标签: UVM, SV

仅有一条评论

  1. [...]很久之前写过一个非常简单的uvm_model文章地址但是没有提编译的一些细节:这里面一部分是封装在package中的,一部分则是直接在.f文件直接加载的。组件主要是通过package封装的,至于case以及sequence则采用,直接加载的方式。这样做的原因是,如果case以及sequence也采用package封装的话,会给调用rtl中的hierarchy造成很多的麻烦。../tc/vcs_pk[...]

添加新评论