目录
**
一、整体的设计结构图
**
各个模块的基础介绍:
(1)DUT:待测平台,这里为数据接收后再传输模块的功能;
(2)sequence:创建一个my_straction的实例m_trans,将其随机化,最终将其送给sequencer;
(3)sequencer:uvm_sequencer就如同一个管道,从这个管道中产生连续的激励事务,并最终通过TLM端口送至driver一侧;
(4)driver:该类会从uvm_sequencer中获取事务(transaction),经过转化进而在接口中对DUT进行时序激励,负责把 transaction级别的数据转变为DUT的端口级别,并驱动给DUT。
(5)monitor:mointor的行为与driver相对,用于收集DUT的端口数据并将其转化成transaction交给后续的组件如reference model,scoreboard等处理;
(6)reference model:reference model用于完成和DUT相同的功能,通常使用更高抽象级别的描述语言;
(7)scoreboard:uvm_scoreboard担任和SV中的check一样的功能,即进行数据的对比和报告,这里要比较的一源于reference model,二源于o_agent的monitor;
(8)env:从环境层次结构而言,uvm_env包含多个uvm_agent和其他component,这些不同的组件共同构成一个完整的验证环境,uvm_env的角色就是一个结构化的容器,它可以容纳其它组件的同时它也可以作为子环境在更高层次集中被嵌入;
(9)interface:driver和DUT,monitor和DUT之间的通过interface来传递transaction,具体使用config_db set/get的方法;
(10)transaction:一笔transaction就是一个包,不同的验证平台中,transaction会不同,组件之间是通过包来进行数据传输的。
**
二、各个组件代码详解
**
2.1 DUT
module dut(clk,rst_n,rxd,rx_dv,txd,tx_en);
input clk;
input rst_n;
input[7:0] rxd; //rxd接收数据
input rx_dv; //发送数据有效指示
output [7:0] txd; //txd发送数据
output tx_en; //接收数据有效指示
reg[7:0] txd; //always赋值用reg
reg tx_en; //always赋值用reg
always @(posedge clk) begin
if(!rst_n) begin
txd <= 8'b0;
tx_en <= 1'b0;
end
else begin
txd <= rxd; //输出数据txd会打一拍
tx_en <= rx_dv;
end
end
endmodule
2.2 top_tb
`timescale 1ns/1ps
`include "uvm_macros.svh" //UVM中的一个文件,包含众多的宏定义
import uvm_pkg::*; //将整个uvm_pkg导入到验证平台中,编译器在编译my_driver.sv文件时才能认识uvm_driver其中的uvm_driver等类名
`include "my_if.sv"
`include "my_transaction.sv"
`include "my_sequencer.sv"
`include "my_driver.sv"
`include "my_monitor.sv"
`include "my_agent.sv"
`include "my_model.sv"
`include "my_scoreboard.sv"
`include "my_env.sv"
`include "base_test.sv"
`include "my_case0.sv"
`include "my_case1.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); //例化了两个interface input_if---输入接口用(i_agent中的组件使用)
my_if output_if(clk, rst_n); // input_if---输出接口用(o_agent中的组件使用)
dut my_dut(.clk(clk), //例化DUT
.rst_n(rst_n),
.rxd(input_if.data), //input_if接口
.rx_dv(input_if.valid), //input_if接口
.txd(output_if.data), //output_if接口
.tx_en(output_if.valid)); //output_if接口
//验证平台的时钟信号
initial begin
clk = 0;
forever begin
#100 clk = ~clk;
end
end
//验证平台的复位信号
initial begin
rst_n = 1'b0;
#1000;
rst_n = 1'b1;
end
//run_test() 启动验证平台,若不带字符串参数时,仿真时需要指定具体的用例test_case
initial begin
run_test();
end
//将接口传递链接到具体的使用组件中去,这些组件是class类型,只能使用virtual interface;
// interface 可以再module中例化,不能在class中例化;
initial begin
//(1) uvm_config_db::set
uvm_config_db#(virtual my_if)::set(null, "uvm_test_top.env.i_agt.drv", "vif", input_if);
uvm_config_db#(virtual my_if)::set(null, "uvm_test_top.env.i_agt.mon", "vif", input_if);
uvm_config_db#(virtual my_if)::set(null, "uvm_test_top.env.o_agt.mon", "vif", output_if);
end
// 分别向driver 和 in_monitor 都需要传入input_if;
// out_monitor 都需要传入input_if;
endmodule
(1)uvm_config_db::set
第一个参数:null,会自动转换为uvm_root::get() //第一个参数只有在类中华使用的时候才能用指针 this
第二个参数:“uvm_test_top.env.i_agt_drv”,表示路径索引
第三个参数:“vif”,和get的第三个参数必须完全一致
第四个参数:input_if,表示将哪个input_if这个interface通过config_db传递给my_driver
note: default_sequence 的时候也用到config_db,但是只需要使用set,而不需要对应的get。
2.3 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
**
2.4 my_transaction
**
`ifndef MY_TRANSACTION__SV
`define MY_TRANSACTION__SV
//(1)uvm_sequence_item
class my_transaction extends uvm_sequence_item;
rand bit[47:0] dmac;//48bit的以太网目的地址
rand bit[47:0] smac;//48bit的以太网源地址
rand bit[15:0] ether_type;//以太网类型
rand byte pload[];//携带数据的大小
rand bit[31:0] crc;//面所有数据的校验值
constraint pload_cons{
pload.size >= 46;
pload.size <= 1500;
}
function bit[31:0] calc_crc();
return 32'h0;
endfunction
//(2)post_randomize()
function void post_randomize();
crc = calc_crc;
endfunction
//(3)uvm_object_utils
`uvm_object_utils_begin(my_transaction)
//(4)域的自动化
`uvm_field_int(dmac, UVM_ALL_ON)
`uvm_field_int(smac, UVM_ALL_ON)
`uvm_field_int(ether_type, UVM_ALL_ON)
`uvm_field_array_int(pload, UVM_ALL_ON)
`uvm_field_int(crc, UVM_ALL_ON)
`uvm_object_utils_end
function new(string name = "my_transaction");
super.new();
endfunction
endclass
`endif
(1)uvm_sequence_item
my_transaction的基类是uvm_sequence_item。在UVM中,所有的transaction都要从uvm_sequence_item派生,只有从uvm_sequence_item派生的transaction才可以使用后文讲述的UVM中强大的sequence机制。注意不是派生自uvm_component。事实上,uvm_sequence_item是从uvm_object派生而来的,因此,uvm_sequence_item相对于uvm_transaction添加了许多实用的成员变量和函数/任务,从uvm_sequence_item直接派生,就可以使用这些新增加的成员变量和函数/任务。
(2)post_randomize()
post_randomize是SystemVerilog中提供的一个函数,当某个类的实例的randomize函数被调用后,post_randomize会紧随其后无条件
地被调用。
(3)uvm_object_utils
这里没有使用uvm_component_utils宏来实现factory机制,而是使用了uvm_object_utils。从本质上来说,my_transaction与my_driv