一.编写只有driver的uvm平台
首先写一个简单的dut程序,代码如下
/*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 [7:0] txd;
output tx_en;
reg[7:0] txd;
reg tx_en;
always @(posedge clk) begin
if(!rst_n) begin
txd <= 8'b0;
tx_en <= 1'b0;
end
else begin
txd <= rxd;
tx_en <= rx_dv;
end
end
endmodule
编写driver
/*my_driver.sv*/
`include "uvm_macros.svh"
`include "dut.sv"
import uvm_pkg::*;
class my_driver extends uvm_driver;
function new(string name = "my_driver", uvm_component parent = null);
super.new(name, parent);
endfunction
extern virtual task main_phase(uvm_phase phase);
endclass
task my_driver::main_phase(uvm_phase phase);
top_tb.rxd <= 8'b0;
top_tb.rx_dv <= 1'b0;
while(!top_tb.rst_n)
@(posedge top_tb.clk);
for(int i = 0; i < 256; i++)begin
@(posedge top_tb.clk);
top_tb.rxd <= $urandom_range(0, 255);
top_tb.rx_dv <= 1'b1;
`uvm_info("my_driver", "data is drived", UVM_LOW)
`uvm_info("my_driver",
$psprintf(" questa_uvm::init(%d)", i), UVM_LOW)
end
@(posedge top_tb.clk);
top_tb.rx_dv <= 1'b0;
endtask
function new()指明实例的名字和位于uvm树的节点,在main_phase中实现需要的操作
顶层模块如下
`timescale 1ns/1ps
`include "uvm_macros.svh"
`include "dut.sv"
import uvm_pkg::*;
`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;
dut my_dut(.clk(clk),
.rst_n(rst_n),
.rxd(rxd),
.rx_dv(rx_dv),
.txd(txd),
.tx_en(tx_en));
initial begin
my_driver drv;
drv = new("drv", null);
drv.main_phase(null);
$finish();
end
initial begin
clk = 0;
forever begin
#1 clk = ~clk;
end
end
initial begin
rst_n = 1'b0;
#10;
rst_n = 1'b1;
end
endmodule
因为driver上没有封装其他模块,所以parent为null
仿真程序
vlog +incdir+E:/modelsim10.5/verilog_src/uvm-1.1d/src -L mtiAvm -L mtiOvm -L mtiUvm -L mtiUPF top_tb.sv
vsim -ldflags "-lregex" -t 1ns -c -sv_lib E:/modelsim10.5/uvm-1.1d/win64/uvm_dpi work.top_tb
run 600
二.逐步添加机制
1.加入factory机制
在dut中使用宏 `uvm_component_utils(my_driver),通过这个宏告诉uvm定义了my_driver这个类。
这样在top_tb中例化my_driver时就比较简单 run_test("my_driver");这样写会自动创建my_driver实例并调用里面的函数和方法。
2.为防止phase的动作提前结束,加入objection机制
task my_driver::main_phase(uvm_phase phase);
phase.raise_objection(this);
`uvm_info("my_driver","main_phase is called",UVM_LOW);
top_tb.rxd <= 8'b0;
top_tb.rx_dv <= 1'b0;
while(!top_tb.rst_n)
@(posedge top_tb.clk);
for(int i = 0; i < 256; i++)begin
@(posedge top_tb.clk);
top_tb.rxd <= $urandom_range(0, 255);
top_tb.rx_dv <= 1'b1;
`uvm_info("my_driver", "data is drived", UVM_LOW)
`uvm_info("my_driver",
$psprintf(" questa_uvm::init(%d)", i), UVM_LOW)
end
@(posedge top_tb.clk);
top_tb.rx_dv <= 1'b0;
phase.drop_objection(this);
endtask
raise_objection必须站在第一个消耗仿真时间的语句之前(例如@(posedge top.clk))
3.加入virtual interface
interface可以简化模块之间的连接,实现类和模块之间的通信。
加入interface模块后,通过config_db机制将顶层和driver中的信号连接起来,top_tb中执行set操作,在my_driver中的build_phase中执行get操作。