验证平台加入virtual interface
加入virtual interface
top_tb.rxd <= 8'b0;
top_tb.rx_dv <= 1'b0;
@(posedge top_tb.clk);
- 之前driver中等待时钟事件、给DUT中输入端口赋值都是使用绝对路径
- 绝对路径的使用大大减弱了验证平台的可移植性
- 避免在验证平台中使用绝对路径
- 方法1:使用宏
使用场景有限`define TOP top_tb
- 避免绝对路径的另外一种方式是使用interface
- 使用interface来连接验证平台与DUT的端口
代码分析
interface定义
`ifndef MY_IF__SV
`define MY_IF__SV
interface my_if(input clk, input rst_n);
logic [7:0] data;
logic valid;
endinterface
`endif
在TB中例化使用interface
`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);
//在TB中例化两个interface,一个输入,一个输出
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));
//例化DUT时,使用interface连接dut
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");
//通过run_test语句创建了一个my_driver的实例,但此处driver实例的层次结构不在top_tb中,无法通过直接赋值把tb中的interface与driver中vif连接起来
//无论传递给run_test的参数是什么,创建的实例的名字都为uvm_test_top
end
initial begin
uvm_config_db#(virtual my_if)::set(null, "uvm_test_top", "vif", input_if);
//uvm引入config_db机制,在top_tb中实行set操作
//使用双冒号是因为这两个函数都是静态函数,而uvm_config_db#(virtual my_if)则是一个参数化的类
//可以传递不同类型的数据,也可以传递相同类型的不同数据
end
endmodule
在driver中使用virtual interface
- driver是一个类,在类中不能声明一个interface,在module中可以。在类中使用virtual interface
`ifndef MY_DRIVER__SV
`define MY_DRIVER__SV
class my_driver extends uvm_driver;
virtual my_if vif;
//在类中使用virtual interface
`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!!!")
//uvm中的config_db机制,在driver中使用get操作。与top_tb中get操作相连接
endfunction
//build_phase在new函数之后main_phase之前执行
//在build_phase中主要通过config_db的set和get操作来传递一些数据,以及实例化成员变量等
//build_phase为function phase,不消耗仿真时间
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;
//声明了virtual interface后,在main_phase中使用vif的信号。代码中的绝对路径已经消除,提高可移植性和可重用性
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
仿真截图
仿真界面
可以看出,模块里已经有两个interface了。output interface在top_tb中进行了声明,但没有通过config_db进行配置