《UVM实战》代码示例

首先是top_tb:

  

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

import uvm_pkg::*;
`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);
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();
end

initial begin
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

endmodule

主要实例化了DUT,和输入输出inf,

定义了时钟频率,传递了接口以链接TB,

和一个run_test()。

然后是base_test:

`ifndef BASE_TEST__SV
`define BASE_TEST__SV

class base_test extends uvm_test;

my_env env;

function new(string name = "base_test", uvm_component parent = null);
super.new(name,parent);
endfunction

extern virtual function void build_phase(uvm_phase phase);
extern virtual function void report_phase(uvm_phase phase);
`uvm_component_utils(base_test)
endclass

function void base_test::build_phase(uvm_phase phase);
super.build_phase(phase);
env = my_env::type_id::create("env", this);
endfunction

function void base_test::report_phase(uvm_phase phase);
uvm_report_server server;
int err_num;
super.report_phase(phase);

server = get_report_server();
err_num = server.get_severity_count(UVM_ERROR);

if (err_num != 0) begin
$display("TEST CASE FAILED");
end
else begin
$display("TEST CASE PASSED");
end
endfunction

`endif

就算是build_phase中例化一个env,以及report_phase中进行get_severity_count(UVM_ERROR),

汇报测试结果

然后是env:

`ifndef MY_ENV__SV
`define MY_ENV__SV

class my_env extends uvm_env;

my_agent i_agt;
my_agent o_agt;
my_model mdl;
my_scoreboard scb;

uvm_tlm_analysis_fifo #(my_transaction) agt_scb_fifo;
uvm_tlm_analysis_fifo #(my_transaction) agt_mdl_fifo;
uvm_tlm_analysis_fifo #(my_transaction) mdl_scb_fifo;

function new(string name = "my_env", uvm_component parent);
super.new(name, parent);
endfunction

virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
i_agt = my_agent::type_id::create("i_agt", this);
o_agt = my_agent::type_id::create("o_agt", this);
i_agt.is_active = UVM_ACTIVE;
o_agt.is_active = UVM_PASSIVE;
mdl = my_model::type_id::create("mdl", this);
scb = my_scoreboard::type_id::create("scb", this);
agt_scb_fifo = new("agt_scb_fifo", this);
agt_mdl_fifo = new("agt_mdl_fifo", this);
mdl_scb_fifo = new("mdl_scb_fifo", this);

endfunction

extern virtual function void connect_phase(uvm_phase phase);

`uvm_component_utils(my_env)
endclass

function void my_env::connect_phase(uvm_phase phase);
super.connect_phase(phase);
i_agt.ap.connect(agt_mdl_fifo.analysis_export);
mdl.port.connect(agt_mdl_fifo.blocking_get_export);
mdl.ap.connect(mdl_scb_fifo.analysis_export);
scb.exp_port.connect(mdl_scb_fifo.blocking_get_export);
o_agt.ap.connect(agt_scb_fifo.analysis_export);
scb.act_port.connect(agt_scb_fifo.blocking_get_export);
endfunction

`endif

主要是哥哥模块,和三个tlm_analysis_fifo,

然后build_phase中type::create模块,配置i/o_agent,new三个fifo,

之后connect_phase中.connect analysis_export和blocking_get_export。

要传送的transcation:

`ifndef MY_TRANSACTION__SV
`define MY_TRANSACTION__SV

class my_transaction extends uvm_sequence_item;

rand bit[47:0] dmac;
rand bit[47:0] smac;
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

function void post_randomize();
crc = calc_crc;
endfunction

`uvm_object_utils_begin(my_transaction)
`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

主要各种内容及uvm_object_utils,uvm_field_int注册,

约数参数,和在post_randomize()中处理内容。

发送transaction的sequencer:

`ifndef MY_SEQUENCER__SV
`define MY_SEQUENCER__SV

class my_sequencer extends uvm_sequencer #(my_transaction);

function new(string name, uvm_component parent);
super.new(name, parent);
endfunction

`uvm_component_utils(my_sequencer)
endclass

`endif

很简单,就是一个注册和new()

比较复杂的Driver:

`ifndef MY_DRIVER__SV
`define MY_DRIVER__SV
class my_driver extends uvm_driver#(my_transaction);

virtual my_if vif;

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

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

extern task main_phase(uvm_phase phase);
extern task drive_one_pkt(my_transaction tr);
endclass

task my_driver::main_phase(uvm_phase phase);
vif.data <= 8‘b0;
vif.valid <= 1‘b0;
while(!vif.rst_n)
@(posedge vif.clk);
while(1) begin
seq_item_port.get_next_item(req);
drive_one_pkt(req);
seq_item_port.item_done();
end
endtask

task my_driver::drive_one_pkt(my_transaction tr);
byte unsigned data_q[];
int data_size;

data_size = tr.pack_bytes(data_q) / 8;
`uvm_info("my_driver", "begin to drive one pkt", UVM_LOW);
repeat(3) @(posedge vif.clk);
for ( int i = 0; i < data_size; i++ ) begin
@(posedge vif.clk);
vif.valid <= 1‘b1;
vif.data <= data_q[i];
end

@(posedge vif.clk);
vif.valid <= 1‘b0;
`uvm_info("my_driver", "end drive one pkt", UVM_LOW);
endtask

`endif

首先是virtual inf和build_phase中接受接口,否则fatal,

然后main_phase中while(1)循环的get_next_item(req),调用发送函数发送req,返回item_done()。

而在monitor中:

`ifndef MY_MONITOR__SV
`define MY_MONITOR__SV
class my_monitor extends uvm_monitor;

virtual my_if vif;

uvm_analysis_port #(my_transaction) ap;

`uvm_component_utils(my_monitor)
function new(string name = "my_monitor", uvm_component parent = null);
super.new(name, parent);
endfunction

virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
if(!uvm_config_db#(virtual my_if)::get(this, "", "vif", vif))
`uvm_fatal("my_monitor", "virtual interface must be set for vif!!!")
ap = new("ap", this);
endfunction

extern task main_phase(uvm_phase phase);
extern task collect_one_pkt(my_transaction tr);
endclass

task my_monitor::main_phase(uvm_phase phase);
my_transaction tr;
while(1) begin
tr = new("tr");
collect_one_pkt(tr);
ap.write(tr);
end
endtask

task my_monitor::collect_one_pkt(my_transaction tr);
byte unsigned data_q[$];
byte unsigned data_array[];
logic [7:0] data;
logic valid = 0;
int data_size;

while(1) begin
@(posedge vif.clk);
if(vif.valid) break;
end

`uvm_info("my_monitor", "begin to collect one pkt", UVM_LOW);
while(vif.valid) begin
data_q.push_back(vif.data);
@(posedge vif.clk);
end
data_size = data_q.size();
data_array = new[data_size];
for ( int i = 0; i < data_size; i++ ) begin
data_array[i] = data_q[i];
end
tr.pload = new[data_size - 18]; //da sa, e_type, crc
data_size = tr.unpack_bytes(data_array) / 8;
`uvm_info("my_monitor", "end collect one pkt", UVM_LOW);
endtask

`endif

主要是virtual inf和analysis_port,在build_phase中接受接口,

mian_phase中while(1)的调用接受函数和和ap.write(tr)。

在agent中:

`ifndef MY_AGENT__SV
`define MY_AGENT__SV

class my_agent extends uvm_agent ;
my_sequencer sqr;
my_driver drv;
my_monitor mon;

uvm_analysis_port #(my_transaction) ap;

function new(string name, uvm_component parent);
super.new(name, parent);
endfunction

extern virtual function void build_phase(uvm_phase phase);
extern virtual function void connect_phase(uvm_phase phase);

`uvm_component_utils(my_agent)
endclass

function void my_agent::build_phase(uvm_phase phase);
super.build_phase(phase);
if (is_active == UVM_ACTIVE) begin
sqr = my_sequencer::type_id::create("sqr", this);
drv = my_driver::type_id::create("drv", this);
end
mon = my_monitor::type_id::create("mon", this);
endfunction

function void my_agent::connect_phase(uvm_phase phase);
super.connect_phase(phase);
if (is_active == UVM_ACTIVE) begin
drv.seq_item_port.connect(sqr.seq_item_export);
end
ap = mon.ap;
endfunction

`endif

含有driver和monitor,在build_phase中如果UVM_ACTIVE,就例化drv和sqr,但都例化mont,

在build_phase中如果UVM_ACTIVE就链接drv和sqr的接口。

而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

而reference_model中:

`ifndef MY_MODEL__SV
`define MY_MODEL__SV

class my_model extends uvm_component;

uvm_blocking_get_port #(my_transaction) port;
uvm_analysis_port #(my_transaction) ap;

extern function new(string name, uvm_component parent);
extern function void build_phase(uvm_phase phase);
extern virtual task main_phase(uvm_phase phase);

`uvm_component_utils(my_model)
endclass

function my_model::new(string name, uvm_component parent);
super.new(name, parent);
endfunction

function void my_model::build_phase(uvm_phase phase);
super.build_phase(phase);
port = new("port", this);
ap = new("ap", this);
endfunction

task my_model::main_phase(uvm_phase phase);
my_transaction tr;
my_transaction new_tr;
super.main_phase(phase);
while(1) begin
port.get(tr);
new_tr = new("new_tr");
new_tr.copy(tr);
`uvm_info("my_model", "get one transaction, copy and print it:", UVM_LOW)
new_tr.print();
ap.write(new_tr);
end
endtask
`endif

需要进的blocking_get_port和出的analysis_port两个,在build_phase中连接他们,

在main_phase中则while1的,如藕藕get_port.get()收到,就ana_port.write()这个tr,

之后的scroreboard中:

`ifndef MY_SCOREBOARD__SV
`define MY_SCOREBOARD__SV
class my_scoreboard extends uvm_scoreboard;
my_transaction expect_queue[$];
uvm_blocking_get_port #(my_transaction) exp_port;
uvm_blocking_get_port #(my_transaction) act_port;
`uvm_component_utils(my_scoreboard)

extern function new(string name, uvm_component parent = null);
extern virtual function void build_phase(uvm_phase phase);
extern virtual task main_phase(uvm_phase phase);
endclass

function my_scoreboard::new(string name, uvm_component parent = null);
super.new(name, parent);
endfunction

function void my_scoreboard::build_phase(uvm_phase phase);
super.build_phase(phase);
exp_port = new("exp_port", this);
act_port = new("act_port", this);
endfunction

task my_scoreboard::main_phase(uvm_phase phase);
my_transaction get_expect, get_actual, tmp_tran;
bit result;

super.main_phase(phase);
fork
while (1) begin
exp_port.get(get_expect);
expect_queue.push_back(get_expect);
end
while (1) begin
act_port.get(get_actual);
if(expect_queue.size() > 0) begin
tmp_tran = expect_queue.pop_front();
result = get_actual.compare(tmp_tran);
if(result) begin
`uvm_info("my_scoreboard", "Compare SUCCESSFULLY", UVM_LOW);
end
else begin
`uvm_error("my_scoreboard", "Compare FAILED");
$display("the expect pkt is");
tmp_tran.print();
$display("the actual pkt is");
get_actual.print();
end
end
else begin
`uvm_error("my_scoreboard", "Received from DUT, while Expect Queue is empty");
$display("the unexpected pkt is");
get_actual.print();
end
end
join
endtask
`endif

是两个get_port,在build_phase中new它们,

首先对于exp端,while(1)的,只要get一个tr,就要在tr_queue中push进去一个,

同时对于act端,while(1)的。只要get一个tr,就要从tr_queue中pop一个出来,进行比较。

这个两个是fork join的,互补影响。

case0中:

`ifndef MY_CASE0__SV
`define MY_CASE0__SV
class case0_sequence extends uvm_sequence #(my_transaction);
my_transaction m_trans;

function new(string name= "case0_sequence");
super.new(name);
endfunction

virtual task body();
if(starting_phase != null)
starting_phase.raise_objection(this);
repeat (10) begin
`uvm_do(m_trans)
end
#100;
if(starting_phase != null)
starting_phase.drop_objection(this);
endtask

`uvm_object_utils(case0_sequence)
endclass

class my_case0 extends base_test;

function new(string name = "my_case0", uvm_component parent = null);
super.new(name,parent);
endfunction
extern virtual function void build_phase(uvm_phase phase);
`uvm_component_utils(my_case0)
endclass

function void my_case0::build_phase(uvm_phase phase);
super.build_phase(phase);

uvm_config_db#(uvm_object_wrapper)::set(this,
"env.i_agt.sqr.main_phase",
"default_sequence",
case0_sequence::type_id::get());
endfunction

`endif

设定了sequece,task_body中uvm_do(my_trans),在之前和之后要starting_phase.raise_objection(this)和starting_phase.drop_objection(this);

在case0的build_phase中传递sequence。

case1也类似的:

`ifndef MY_CASE1__SV
`define MY_CASE1__SV
class case1_sequence extends uvm_sequence #(my_transaction);
my_transaction m_trans;

function new(string name= "case1_sequence");
super.new(name);
endfunction

virtual task body();
if(starting_phase != null)
starting_phase.raise_objection(this);
repeat (10) begin
`uvm_do_with(m_trans, { m_trans.pload.size() == 60;})
end
#100;
if(starting_phase != null)
starting_phase.drop_objection(this);
endtask

`uvm_object_utils(case1_sequence)
endclass

class my_case1 extends base_test;

function new(string name = "my_case1", uvm_component parent = null);
super.new(name,parent);
endfunction

extern virtual function void build_phase(uvm_phase phase);
`uvm_component_utils(my_case1)
endclass

function void my_case1::build_phase(uvm_phase phase);
super.build_phase(phase);

uvm_config_db#(uvm_object_wrapper)::set(this,
"env.i_agt.sqr.main_phase",
"default_sequence",
case1_sequence::type_id::get());
endfunction

`endif

原文地址:https://www.cnblogs.com/liheng369/p/8536861.html

时间: 2024-10-06 10:14:23

《UVM实战》代码示例的相关文章

Python Web框架Tornado的异步处理代码示例

1. What is Tornado Tornado是一个轻量级但高性能的Python web框架,与另一个流行的Python web框架Django相比,tornado不提供操作数据库的ORM接口及严格的MVC开发模式,但可以提供基本的web server功能,故它是轻量级的:它借助non-blocking and event-driven的I/O模型(epoll或kqueue)实现了一套异步网络库,故它是高性能的. Tornado的轻量级+高性能特性使得它特别适用于提供web api的场合,

计算DXFReader中多边形的面积代码示例

在DXFReader中, 一般的多边形的面积计算绝对值 其中K表是顶点的数目,它们的坐标,用于在求和和, 所以用下面的代码就可以计算出一个封闭的多段线的区域: view source print? 01 Dim Vertex As Object 02 Dim Entity As Object 03 Dim k As Long 04 Dim i As Long 05 Dim Area As Single 06 07 With DXFReader1 08 09  For Each Entity In

代码示例:一些简单技巧优化JavaScript编译器工作详解,让你写出高性能运行的更快JavaScript代码

告诉你一些简单的技巧来优化JavaScript编译器工作,从而让你的JavaScript代码运行的更快.尤其是在你游戏中发现帧率下降或是当垃圾回收器有大量的工作要完成的时候. 单一同态: 当你定义了一个两个参数的函数,编译器会接受你的定义,如果函数参数的类型.个数或者返回值的类型改变编译器的工作会变得艰难.通常情况下,单一同态的数据结构和个数相同的参数会让你的程序会更好的工作. function example(a, b) { // 期望a,b都为数值类型 console.log(++a * +

jquery操作单选钮代码示例

jquery操作单选钮代码示例:radio单选按钮是最重要的表单元素之一,下面介绍一下常用的几个jquery对radio单选按钮操作.一.取消选中: $(".theclass").each(function(){ if($(this).attr('checked')) { $(this).attr('checked',false); } }); 以上代码可以将class属性值为theclass的被选中单选按钮取消选中.二.获取被选中的单选按钮的值: var val=$('.thecla

Python实现各种排序算法的代码示例总结

Python实现各种排序算法的代码示例总结 作者:Donald Knuth 字体:[增加 减小] 类型:转载 时间:2015-12-11我要评论 这篇文章主要介绍了Python实现各种排序算法的代码示例总结,其实Python是非常好的算法入门学习时的配套高级语言,需要的朋友可以参考下 在Python实践中,我们往往遇到排序问题,比如在对搜索结果打分的排序(没有排序就没有Google等搜索引擎的存在),当然,这样的例子数不胜数.<数据结构>也会花大量篇幅讲解排序.之前一段时间,由于需要,我复习了

领域驱动开发推荐代码示例 — Microsoft NLayerApp

简介: Microsoft NLayerApp是由微软西班牙团队出品的基于.NET 4.0的“面向领域N层分布式架构”代码示例,在codeplex上的地址是:http://microsoftnlayerapp.codeplex.com/. 架构图: 点击查看大图 代码下载:http://microsoftnlayerapp.codeplex.com/releases/view/56660 所用到的软件: - Microsoft Visual Studio 2010  - Microsoft Ex

Aspectj快速上手代码示例之Before,After,Around

本文不打算解释AOP的相关专业名词和概念,仅通过几个代码示例来展示Aspectj(对AOP实现的)的基本使用,并且使用的Aspectj是目前最新版本. 1.搭建环境 本文使用Maven来构建工程,通过aspectj-maven-plugin插件来编译*.aj文件至.class. Maven的具体配置: <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>aspectj-maven-plugin&

jxl创建Excel文件java代码示例

记得要下载 并 导入 jxl.jar 包,免积分下载地址:http://download.csdn.net/detail/u010011052/7561041 package Test; import java.io.*; import jxl.*; import jxl.format.Colour; import jxl.write.*; public class JXLTest { private static WritableWorkbook book; private static Wr

java 翻盖hashCode()深入探讨 代码示例

package org.rui.collection2.hashcode; /** * 覆盖hashcode * 设计HashCode时最重要的因素 就是:无论何时,对同一个对象调用HashCode都应该产生同样的值, * 如果你的HashCode方法依赖于对象中易变的数据,用户就要当心了,因为此数据发生变化 时 * HashCode就会生成一个不同的散列码,相当于产生一个不同的健 * 此外 也不应该使HashCode依赖于具有唯一性的对象信息,尤其是使用this的值,这只能很糟糕, * 因为这

python 之初学者的代码示例(短小精悍)(一)

学习Python也有个把月了,最近整理自己初学的代码示例,一个是为了增加自己对细节的把握,一个是让像我一样的初学者能够熟练地使用基础,基础的重要性就不说了,我希望自己能够把这些精巧的小而短的示例分享给大家,共同进步 #help(execfile) Help on built-in function execfile in module __builtin__: execfile(...) execfile(filename[, globals[, locals]]) Read and execu