2.8 interfaces
前言
本文以uvm-1.2/examples/simple/interfaces为例,通过代码了解UVM中的一些用法。通过这个例子可以基本了解以下知识点:
- interface的作用
- 如何创建一个interface
- 如何使用modport封装信号
- resource_db机制及其dump
- 如何interface实现验证环境与待测设计DUT之间的连接
一、基本介绍
interface翻译过来就是接口的意思,interface的作用就是将接口单独封装出来,用于验证环境与待测设计DUT之间的连接。将接口单独封装出来的好处是,避免接口很多的时候,连接的时候容易出错,另外,当接口有改动的时候,只需要改变一个文件即可,不用在每个接口例化的地方全部改一遍。
在这个测试用例中,将通过interface封装一个接口,在接口内部再通过modport关键字,对接口进行分类,最后通过interface,实现验证环境和待测设计DUT之间的连接。
二、代码分析
代码比较简单,只有一个interface.sv文件
1、interface.sv
/*
About: uvm_exmples/mechanism/interfaces
This example will illustrate how to create a pin interface and mod port interfaces for a simple dut.
Connect a component "driver" to the pin interfaces, then to the dut.
*/
//----------------------------------------------------------------------
// interface mem_pins_if
//----------------------------------------------------------------------
interface pin_if (input clk);
bit [15:0] address;
bit [7:0] wr_data;
bit [7:0] rd_data;
bit rst;
bit rw;
bit req;
bit ack;
bit err;
modport master_mp(
input clk,
input rst,
output address,
output wr_data,
input rd_data,
output req,
output rw,
input ack,
input err );
modport slave_mp(
input clk,
input rst,
input address,
input wr_data,
output rd_data,
input req,
input rw,
output ack,
output err );
modport monitor_mp(
input clk,
input rst,
input address,
input wr_data,
input rd_data,
input req,
input rw ,
input ack,
input err );
endinterface
import uvm_pkg::*;
package top_pkg;
typedef virtual pin_if pin_vif;
endpackage
package user_pkg;
import uvm_pkg::*;
import top_pkg::*;
`include "uvm_macros.svh"
//---------------------------------------------------------------------
// component driver
//----------------------------------------------------------------------
class driver extends uvm_component;
pin_vif pif;
function new(string name, uvm_component parent = null);
super.new(name, parent);
endfunction
function void connect_phase(uvm_phase phase);
assert(uvm_resource_db#(pin_vif)::read_by_name(get_full_name(),
"pif", pif));
endfunction
task run_phase(uvm_phase phase);
forever begin
@(posedge pif.clk);
`uvm_info("driver", "posedge clk", UVM_NONE);
//...
end
endtask
endclass
//----------------------------------------------------------------------
// environment env
//----------------------------------------------------------------------
class env extends uvm_env;
local pin_vif pif;
driver d;
function new(string name, uvm_component parent = null);
super.new(name, parent);
d = new("driver", this);
endfunction
task run_phase(uvm_phase phase);
phase.raise_objection(this);
#100;
phase.drop_objection(this);
endtask
endclass
endpackage
//import user_pkg::*;
//----------------------------------------------------------------------
// module dut
//----------------------------------------------------------------------
module dut(pin_if pif);
always @(posedge pif.clk) begin
`uvm_info("dut", "posedge clk", UVM_NONE);
//...
end
endmodule
//----------------------------------------------------------------------
// module clkgen
//----------------------------------------------------------------------
module clkgen(output bit clk);
initial begin
forever begin
#5 clk = 1;
#5 clk = 0;
end
end
endmodule
//----------------------------------------------------------------------
// module top
//----------------------------------------------------------------------
module top;
import top_pkg::*;
import user_pkg::*;
bit clk;
clkgen ck(clk);
pin_if pif(clk);
env e;
dut d(pif.slave_mp);
initial begin
e = new("env");
uvm_resource_db#(pin_vif)::set("env.driver", "pif", pif);
uvm_resource_db#(pin_vif)::dump();
run_test();
//$finish;
end
endmodule
第14到56行,利用interface——endinterface关键字封装了一组接口。
14行interface封装的名字是pin_if,参数clk。
15到22行利用bit声明了一系列的端口名,其实这里用logic声明端口名会更好,因为logic声明的变量支持四个状态,包括0、1、x、z,而bit声明的变量只支持两个状态,包括0和1。
24到55行利用modport关键字,将信号进行了分组,并指定了每组中变量的输入输出状态。这里分了三组,包括master_mp、slave_mp和monitor_mp,前两组用于驱动,最后一组用于监控。
60到62行,通过package封装了top_pkg,在top_pkg中,利用typedef关键字,将virtual pin_if取名叫pin_vif。
65行到117行,通过package封装了user_pkg,在user_pkg中,声明了driver和env。
73到94行声明了dirver组件,其中关键的是81到84行的connect_phase,通过调用uvm_resource_db实现验证环境和待测设计DUT的连接,resource_db机制中,存在一个资源池,在顶层将interface放入这个资源池,这里将资源池里面的interface按照名字读出来,从而实现连接。assert关键字是断言,用于判断uvm_resource_db连接是否成功,如果连接失败,断言就会报错。
99到115行声明了env组件,env中声明并例化了drver组件,另外,在109到113的run_phase中,通过“举手”和“放手”来保证仿真执行的时间。这里的举手和放手可以参考张强《UVM实战》的5.2节objection机制。
123到143行,声明了两个简单的dut和clkgen模块。dut模块带interface参数,clkgen模块带时钟clk参数。
148到168行,声明了顶层top模块。在该模块中例化了interface、dut、clkgen以及env模块。
其中,153到158行,clkgen用于产生时钟信号,interface封装了端口信号,env构成了验证环境,dut是待测设计(design under test)。clkgen产生的时钟信号,送入了interface;interface封装的slave_mp送入了dut。
160到166行,先例化了env,再通过uvm_resource_db的set函数,将interface送入resource_db机制的资源池中,这里set函数的第一个参数是路径,第二个参数是标识符,第三个参数是变量。
163行调用uvm_resource_db的dump函数,打印资源池中的信号用于debug调试。打印的结果如下所示:
UVM_INFO ../../../src/base/uvm_resource.svh(1347) @ 0: reporter [UVM/RESOURCE/DUMP]
=== resource pool ===
pif [/^env\.driver$/] : (virtual interface pin_if) '{clk:'h0, address:'h0, wr_data:'h0, rd_data:'h0, rst:'h0, rw:'h0, req:'h0, ack:'h0, err:'h0}
164行执行仿真。
2、仿真结果
UVM_INFO ../../../src/base/uvm_resource.svh(1347) @ 0: reporter [UVM/RESOURCE/DUMP]
=== resource pool ===
pif [/^env\.driver$/] : (virtual interface pin_if) '{clk:'h0, address:'h0, wr_data:'h0, rd_data:'h0, rst:'h0, rw:'h0, req:'h0, ack:'h0, err:'h0}
UVM_INFO ../../../src/base/uvm_resource.svh(1354) @ 0: reporter [UVM/RESOURCE/DUMP] === end of resource pool ===
UVM_INFO @ 0: reporter [RNTST] Running test ...
UVM_INFO interface.sv(89) @ 5: env.driver [driver] posedge clk
UVM_INFO interface.sv(126) @ 5: reporter [dut] posedge clk
UVM_INFO interface.sv(89) @ 15: env.driver [driver] posedge clk
UVM_INFO interface.sv(126) @ 15: reporter [dut] posedge clk
UVM_INFO interface.sv(89) @ 25: env.driver [driver] posedge clk
UVM_INFO interface.sv(126) @ 25: reporter [dut] posedge clk
UVM_INFO interface.sv(89) @ 35: env.driver [driver] posedge clk
UVM_INFO interface.sv(126) @ 35: reporter [dut] posedge clk
UVM_INFO interface.sv(89) @ 45: env.driver [driver] posedge clk
UVM_INFO interface.sv(126) @ 45: reporter [dut] posedge clk
UVM_INFO interface.sv(89) @ 55: env.driver [driver] posedge clk
UVM_INFO interface.sv(126) @ 55: reporter [dut] posedge clk
UVM_INFO interface.sv(89) @ 65: env.driver [driver] posedge clk
UVM_INFO interface.sv(126) @ 65: reporter [dut] posedge clk
UVM_INFO interface.sv(89) @ 75: env.driver [driver] posedge clk
UVM_INFO interface.sv(126) @ 75: reporter [dut] posedge clk
UVM_INFO interface.sv(89) @ 85: env.driver [driver] posedge clk
UVM_INFO interface.sv(126) @ 85: reporter [dut] posedge clk
UVM_INFO interface.sv(89) @ 95: env.driver [driver] posedge clk
UVM_INFO interface.sv(126) @ 95: reporter [dut] posedge clk
UVM_INFO ../../../src/base/uvm_objection.svh(1270) @ 100: reporter [TEST_DONE] 'run' phase is ready to proceed to the 'extract' phase
UVM_INFO ../../../src/base/uvm_report_server.svh(847) @ 100: reporter [UVM/REPORT/SERVER]
--- UVM Report Summary ---
** Report counts by severity
UVM_INFO : 25
UVM_WARNING : 0
UVM_ERROR : 0
UVM_FATAL : 0
** Report counts by id
[RNTST] 1
[TEST_DONE] 1
[UVM/RELNOTES] 1
[UVM/RESOURCE/DUMP] 2
[driver] 10
[dut] 10
$finish called from file "../../../src/base/uvm_root.svh", line 517.
$finish at simulation time 100
V C S S i m u l a t i o n R e p o r t
Time: 100 ns
通过log可以看到,首先在82行设定的断言没有报错,其次driver打印一个posedge clk,同一时刻dut也打印了一个posedge clk,这说明验证环境和dut已经完成连接。
总结
这个测试用例非常简单,利用resource_db实现了验证环境与待测设计之间,通过interface进行连接。其实,还可以利用config_db机制进行连接,具体可以参考张强的《UVM实战》3.5节config_db机制。