记录

参考使用uvm白皮书内容

从根本上来说,应该杜绝在验证平台中使用绝对路径

避免绝对路径一个方法是使用宏

`define TOP top_tb

`define TOP top_tb
task my_driver::main_phase(uvm_phase phase);
   phase.raise_objection(this);
   `uvm_info("my_driver", "main_phase is called", UVM_LOW);
   `TOP.rxd <= 8'b0;
   `TOP.rx_dv <= 1'b0;
   while(!`TOP.rst_n)
      @(posedge `TOP.clk);
   for(int i = 0; i < 256; i++)begin
      @(posedge `TOP.clk);
      `TOP.rxd <= $urandom_range(0, 255);
      `TOP.rx_dv <= 1'b1;
      `uvm_info("my_driver", "data is drived", UVM_LOW);
   end
   @(posedge `TOP.clk);
   `TOP.rx_dv <= 1'b0;
   phase.drop_objection(this);
endtask

避免绝对路径的另外一种方式是使用interface。

注意点记录

class my_driver extends uvm_driver;
  my_if  drv_if;
  …
endclass

因为my_driver是一个类,在类中不能使用上述方式声明一个interface,只有在类似top_tb这样的模块(module)中才可以。

正确使用方式

文件:src/ch2/section2.2/2.2.4/my_driver.sv
3 class my_driver extends uvm_driver;
4 5   virtual my_if vif;

如何把top_tb中的input_if和my_driver中的vif对应起来呢?

最简单的方法莫过于直接赋值。此时一个新的问题又摆在了面前:在top_tb中,通过run_test语句建立了一个my_driver的实例,但是应该如何引用这个实例呢?不可能像引用my_dut那样直接引用my_driver中的变量:top_tb.my_dut.xxx是可以的,但是top_tb.my_ driver.xxx是不可以的。这个问题的终极原因在于UVM通过run_test语句实例化了一个脱离了top_tb层次结构的实例,建立了一个新的层次结构。

对于这种脱离了top_tb层次结构,同时又期望在top_tb中对其进行某些操作的实例,UVM引进了config_db机制。在config_db机制中,分为set和get两步操作。所谓set操作,可以简单地理解成是“寄信”,而get则相当于是“收信”。在top_tb中执行set操作

寄信
文件:src/ch2/section2.2/2.2.4/top_tb.sv
44 initial begin
45   uvm_config_db#(virtual my_if)::set(null,"uvm_test_top", "vif", input_if);
46 end
收信
文件:src/ch2/section2.2/2.2.4/my_driver.sv
13   virtual function void build_phase(uvm_phase phase);
14     super.build_phase(phase);
15     `uvm_info("my_driver", "build_phase is called", UVM_LOW);
16     if(!uvm_config_db#(virtual my_if)::get(this, "", "vif", vif))
17        `uvm_fatal("my_driver", "virtual interface must be set for vif!!!")
18   endfunction

config_db的set和get函数都有四个参数,这两个函数的第三个参数必须完全一致。

set函数的第四个参数表示要将哪个interface通过config_db传递给my_driver,

get函数的第四个参数表示把得到的interface传递给哪个my_driver的成员变量。

set函数的第二个参数表示的是路径索引

dut.sv

module dut (
    clk,
    rst_n,
    rxd,
    rx_dv,
    txd,
    tx_en
);
    input clk    ;   
    input rst_n  ;   
    input [7:0]rxd    ; 
    input rx_dv  ;   
    output txd   ;  
    output tx_en ; 

reg [7:0]   txd;
reg         tx_en;  

always @(posedge clk) begin
    if(!rst_n)begin
        txd     <=  8'h00;
        tx_en   <=  1'b0;
    end
    else begin
        txd     <=  rxd;
        tx_en   <=  rx_dv;
    end
end
endmodule

TB

my_driver.sv

`ifndef MY_DRIVER__SV
`define MY_DRIVER__SV
class my_driver extends uvm_driver;

   virtual my_if vif;

   `uvm_component_utils(my_driver)
   function new(string name = "my_driver", uvm_component parent = null);
      super.new(name, parent);
      `uvm_info("my_driver", "new is called", UVM_LOW);
   endfunction

   virtual function void build_phase(uvm_phase phase);
      super.build_phase(phase);
      `uvm_info("my_driver", "build_phase is called", UVM_LOW);
      if(!uvm_config_db#(virtual my_if)::get(this, "", "vif", vif))
         `uvm_fatal("my_driver", "virtual interface must be set for vif!!!")
   endfunction

   extern virtual task main_phase(uvm_phase phase);
endclass

task my_driver::main_phase(uvm_phase phase);
   phase.raise_objection(this);
   `uvm_info("my_driver", "main_phase is called", UVM_LOW);
   vif.data <= 8'b0; 
   vif.valid <= 1'b0;
   while(!vif.rst_n)
      @(posedge vif.clk);
   for(int i = 0; i < 256; i++)begin
      @(posedge vif.clk);
      vif.data <= $urandom_range(0, 255);
      vif.valid <= 1'b1;
      `uvm_info("my_driver", "data is drived", UVM_LOW);
   end
   @(posedge vif.clk);
   vif.valid <= 1'b0;
   phase.drop_objection(this);
endtask
`endif

my_if.sv

`ifndef MY_IF__SV
`define MY_IF__SV

interface my_if(input clk, input rst_n);

   logic [7:0] data;
   logic valid;
endinterface

`endif

top_tb.sv

`timescale 1ns/1ps
`include "uvm_macros.svh"

import uvm_pkg::*;
`include "my_if.sv"
`include "my_driver.sv"

module top_tb;

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

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

dut my_dut(.clk(clk),
           .rst_n(rst_n),
           .rxd(input_if.data),
           .rx_dv(input_if.valid),
           .txd(output_if.data),
           .tx_en(output_if.valid));

initial begin
   clk = 0;
   forever begin
      #100 clk = ~clk;
   end
end

initial begin
   rst_n = 1'b0;
   #1000;
   rst_n = 1'b1;
end

initial begin
   run_test("my_driver");
end

initial begin
   uvm_config_db#(virtual my_if)::set(null, "uvm_test_top", "vif", input_if);
end

endmodule

仿真结果

将发送激励改成了25次

UVM_INFO my_driver.sv(11) @ 0: uvm_test_top [my_driver] new is called
UVM_INFO @ 0: reporter [RNTST] Running test my_driver...

fsdbDumpfilrs is start at                    0
UVM_INFO my_driver.sv(16) @ 0: uvm_test_top [my_driver] virtual interface must be set for vif!!!
UVM_INFO my_driver.sv(36) @ 13000: uvm_test_top [my_driver] data is driver
UVM_INFO my_driver.sv(36) @ 15000: uvm_test_top [my_driver] data is driver
UVM_INFO my_driver.sv(36) @ 17000: uvm_test_top [my_driver] data is driver
UVM_INFO my_driver.sv(36) @ 19000: uvm_test_top [my_driver] data is driver
UVM_INFO my_driver.sv(36) @ 21000: uvm_test_top [my_driver] data is driver
UVM_INFO my_driver.sv(36) @ 23000: uvm_test_top [my_driver] data is driver
UVM_INFO my_driver.sv(36) @ 25000: uvm_test_top [my_driver] data is driver
UVM_INFO my_driver.sv(36) @ 27000: uvm_test_top [my_driver] data is driver
UVM_INFO my_driver.sv(36) @ 29000: uvm_test_top [my_driver] data is driver
UVM_INFO my_driver.sv(36) @ 31000: uvm_test_top [my_driver] data is driver
UVM_INFO my_driver.sv(36) @ 33000: uvm_test_top [my_driver] data is driver
UVM_INFO my_driver.sv(36) @ 35000: uvm_test_top [my_driver] data is driver
UVM_INFO my_driver.sv(36) @ 37000: uvm_test_top [my_driver] data is driver
UVM_INFO my_driver.sv(36) @ 39000: uvm_test_top [my_driver] data is driver
UVM_INFO my_driver.sv(36) @ 41000: uvm_test_top [my_driver] data is driver
UVM_INFO my_driver.sv(36) @ 43000: uvm_test_top [my_driver] data is driver
UVM_INFO my_driver.sv(36) @ 45000: uvm_test_top [my_driver] data is driver
UVM_INFO my_driver.sv(36) @ 47000: uvm_test_top [my_driver] data is driver
UVM_INFO my_driver.sv(36) @ 49000: uvm_test_top [my_driver] data is driver
UVM_INFO my_driver.sv(36) @ 51000: uvm_test_top [my_driver] data is driver
UVM_INFO my_driver.sv(36) @ 53000: uvm_test_top [my_driver] data is driver
UVM_INFO my_driver.sv(36) @ 55000: uvm_test_top [my_driver] data is driver
UVM_INFO my_driver.sv(36) @ 57000: uvm_test_top [my_driver] data is driver
UVM_INFO my_driver.sv(36) @ 59000: uvm_test_top [my_driver] data is driver
UVM_INFO my_driver.sv(36) @ 61000: uvm_test_top [my_driver] data is driver

--- UVM Report Summary ---

** Report counts by severity
UVM_INFO :   28
UVM_WARNING :    0
UVM_ERROR :    0
UVM_FATAL :    0
** Report counts by id
[RNTST]     1
[my_driver]    27
09-26 10:30