引言

本专栏的博客均与 UVM 的学习相关,学习参考:

【1】UVM Tutorial

【2】张强著,UVM实战 (卷 Ⅰ)

【3】Download UVM (Standard Universal Verification Methodology)

本专栏的学习基本依照 资料【2】的主线,以【1】【3】资料作为参考。特别是【3】是官方的UVM手册,具有很高的可参考性以及权威性。

本文则先搭建一个简单的 UVM 平台,了解其思想和机制。

UVM 平台:Questa Sim - 64 10.6c (Win 10)


验证平台的组成有哪些?

验证的对象是前端设计工程师提交的硬件设计代码(Verilog),验证的目的就是设计各种验证case,观察前端工程师设计的电路是否符合spec里要求的各项指标以及功能。简单的验证平台结构如下图所示,driver 负责将相同的激励同时给到 DUT 和参考模型,monitor 负责接收 DUT的各个响应结果送至计分板将二者的结果进行比对,给出验证结果,pass or fail。

在 UVM 中,引入了 agent 和  sequence 的概念,因此UVM中验证平台的典型框图:

只有 driver 的验证平台

搭建最简单的验证平台

假设待分析的设计为数据转发模块:

Design

module Design(
input clk,
input rstn,
input [7:0] rxd,
input rxval,
output reg tx_en,
output reg [7:0] txd
);always @ (posedge clk)
beginif(~rstn)begintxd <= 0;tx_en <= 0;endelsebegintx_en <= rxval;txd <= rxd;end
end
endmodule

Driver

class Driver extends uvm_driver;function new(string name = "Driver",uvm_component parent = null);super.new(name,parent);endfunctionextern virtual task main_phase(uvm_phase phase);
endclass task Driver::main_phase(uvm_phase phase); Top_tb.rxd <= 8'd0;  Top_tb.rx_val <= 1'b0;  while(~Top_tb.rstn)//等待复位完成  begin @(posedge Top_tb.clk); end// 随机数激励for(int k = 0;k<256;k++) begin@(posedge Top_tb.clk);Top_tb.rxd <= $urandom_range(0,255);Top_tb.rx_val <= 1'b1;  `uvm_info("Driver",$sformatf("Random data is drived ,data = %0d",Top_tb.rxd),UVM_LOW)     end// 有效信号拉低@(posedge Top_tb.clk);Top_tb.rx_val <= 1'b0;
endtask

对于 `uvm_info 宏的使用,这里建议查阅 UVM 的使用手册,很详细:

Top_tb

`timescale 1ns/1ns
`include "uvm_macros.svh"import uvm_pkg::*;
`include "Driver.sv"module Top_tb ();
reg clk;
reg rstn;
reg [7:0] rxd;
reg rx_val;
wire tx_en;
wire [7:0] txd;Design inst_Design (.clk(clk), .rstn(rstn), .rxd(rxd), .rx_val(rx_val), .tx_en(tx_en), .txd(txd));initial
beginDriver drv;drv = new("Driver",null);drv.main_phase(null);$finish;
endinitial clk = 0;
always #10 clk = ~clk;initial
beginrstn = 1'b0;#138 rstn = 1'b1;
end
endmodule

在 Questa Sim 中,仅需要对 顶层仿真文件编译,不需要对各个组件编译:

`include "uvm_macros.svh"     

将对应的宏定义文件读取进来,这在编译开始之前进行的操作。

import uvm_pkg::*     

将整个uvm_pkg 导入验证平台,这样才能在自己的验证平台使用 uvm的各种库。

以上这两个操作在后续的所有验证平台的顶层都应包括进去。

仿真

编译完成后,在脚本处,执行仿真:

vsim -voptargs=+acc work.Top_tb +UVM_NO_RELNOTES

文件加载完成后 ,在脚本处 执行 run 命令,即可看到仿真结果:

加入 factory 机制

factory 机制,使用 uvm_component_utils 宏来实现。此宏会根据类型,自动创建一个实例并且这个类的 main_phase 会被自动调用。

Driver 文件作如下改动:

class Driver extends uvm_driver;`uvm_component_utils(Driver)function new(string name = "Driver",uvm_component parent = null);super.new(name,parent);`uvm_info("Driver","new is called",UVM_LOW)endfunctionextern virtual task main_phase(uvm_phase phase);
endclass task Driver::main_phase(uvm_phase phase);`uvm_info("Driver","main_phase is called",UVM_LOW)Top_tb.rxd <= 8'd0;  Top_tb.rx_val <= 1'b0;  while(~Top_tb.rstn)//等待复位完成  begin @(posedge Top_tb.clk); end// 随机数激励for(int k = 0;k<256;k++) begin@(posedge Top_tb.clk);Top_tb.rxd <= $urandom_range(0,255);Top_tb.rx_val <= 1'b1;    `uvm_info("Driver",$sformatf("Random data is drived ,data = %0d",Top_tb.rxd),UVM_LOW)     end// 有效信号拉低@(posedge Top_tb.clk);Top_tb.rx_val <= 1'b0;
endtask

顶层文件 Top_tb 改动后的结果:

一个run_test语句会创建一个my_driver的实例,并且会自动调用my_driver的main_phase。

`timescale 1ns/1ns
`include "uvm_macros.svh"import uvm_pkg::*;
`include "Driver.sv"module Top_tb ();
reg clk;
reg rstn;
reg [7:0] rxd;
reg rx_val;
wire tx_en;
wire [7:0] txd;Design Inst_Design (.clk(clk), .rstn(rstn), .rxd(rxd), .rx_val(rx_val), .tx_en(tx_en), .txd(txd)
);initial
begin // Driver drv;                                        // drv = new("Driver",null);                                     // drv.main_phase(null);                                        run_test("Driver");                                       // $finish;
end                             initial clk = 0;
always #10 clk = ~clk;initial
beginrstn = 1'b0;#138 rstn = 1'b1;
end
endmodule

上图是 run_test 的使用说明。

编译后执行仿真:

发现仿真结果中,只打印到 main_phased is called,后面的随机数激励部分没有执行。此处引出了 UVM 的objection 机制。

加入objection机制

UVM中通过objection机制来控制验证平台的关闭。在每个phase中,UVM会检查是否有objection被提起 (raise_objection),如果有,那么等待这个objection被撤销(drop_objection)后停止仿真;如果没有,则马上结束当前phase。

可以简单地将drop_objection语句当成是finish函数的替代者,只是在drop_objection语句之前必须先调用 raise_objection语句,raise_objection和drop_objection总是成对出现。

加入 objection 机制的 Driver 代码:

class Driver extends uvm_driver;`uvm_component_utils(Driver)function new(string name = "Driver",uvm_component parent = null);super.new(name,parent);`uvm_info("Driver","new is called",UVM_LOW)endfunctionextern virtual task main_phase(uvm_phase phase);
endclass task Driver::main_phase(uvm_phase phase);phase.raise_objection(this);`uvm_info("Driver","main_phase is called",UVM_LOW)               Top_tb.rxd <= 8'd0;                  Top_tb.rx_val <= 1'b0;                 while(~Top_tb.rstn)//等待复位完成                 begin              @(posedge Top_tb.clk);                 end                // 随机数激励for(int k = 0;k<256;k++) begin@(posedge Top_tb.clk);Top_tb.rxd <= $urandom_range(0,255);Top_tb.rx_val <= 1'b1;  `uvm_info("Driver",$sformatf("Random data is drived ,data = %0d",Top_tb.rxd),UVM_LOW)     end// 有效信号拉低@(posedge Top_tb.clk);Top_tb.rx_val <= 1'b0;phase.drop_objection(this);
endtask

编译后执行仿真:

raise_objection 语句必须在 main_phase 中第一个消耗仿真时间的语句之前。如$display语句是不消耗仿真时间的,这些语句可 以放在raise_objection之前,但是类似@(posedge top.clk)等语句是要消耗仿真时间的。按照如下的方式使用raise_objection是无法起到作用的。

Driver 类的代码修改:

class Driver extends uvm_driver;`uvm_component_utils(Driver)function new(string name = "Driver",uvm_component parent = null);super.new(name,parent);`uvm_info("Driver","new is called",UVM_LOW)endfunctionextern virtual task main_phase(uvm_phase phase);
endclass task Driver::main_phase(uvm_phase phase);@(posedge Top_tb.clk);phase.raise_objection(this);`uvm_info("Driver","main_phase is called",UVM_LOW)                Top_tb.rxd <= 8'd0;                  Top_tb.rx_val <= 1'b0;                 while(~Top_tb.rstn)//等待复位完成                 begin              @(posedge Top_tb.clk);                 end                // 随机数激励for(int k = 0;k<256;k++) begin@(posedge Top_tb.clk);Top_tb.rxd <= $urandom_range(0,255);Top_tb.rx_val <= 1'b1;  `uvm_info("Driver",$sformatf("Random data is drived ,data = %0d",Top_tb.rxd),UVM_LOW)     end// 有效信号拉低@(posedge Top_tb.clk);Top_tb.rx_val <= 1'b0;phase.drop_objection(this);
endtask

仿真结果:

加入 virtual interface

未引入 虚拟接口 时,验证平台的端口索引是通过模块之间层级的绝对路径来索引,比如上面的Driver类内的 Top_tb.rx_val <= 1'b0; 这种接口的索引很不利于验证平台的移植。使用宏定义也可以在一定程度缓解这种问题,但是最根本的解决方案还是要引入虚拟接口。

在类内引入非虚拟接口,在编译时会报语法错误。在模块(module)内可以引入非虚拟接口。虚拟接口在实例化时需要声明 virtual 。

interface 文件:

interface Interface (input clk,input rstn);logic [7:0] data;logic val;
endinterface

接口引入的目的就是方便驱动 Driver 和 仿真顶层 Top_tb 之间更友好地(代码可移植性更高)连接。那么二者之间具体如何连接?UVM引进了config_db 机制。在config_db机制中,分为set和get两步操作。所谓set操作,读者可以简单地理解成是“寄信”,而get则相当于是“收信”。可以向驱动器 Driver 寄同类型的不同实例对应的“信”,也可以寄不同类型的“信”。对于收侧也一样。

Driver 中需要引入 build_phase 。与main_phase一样,build_phase也是UVM中内建的一个phase。当UVM启动后,会自动执行 build_phase。build_phase在new函数之后main_phase之前执行。在build_phase中主要通过config_db的 set 和 get 操作来传递一些数据, 以及实例化成员变量等

Driver 类的改变:

class Driver extends uvm_driver;virtual Interface Virtual_Driver_if;`uvm_component_utils(Driver)function new(string name = "Driver",uvm_component parent = null);super.new(name,parent);`uvm_info("Driver","new is called",UVM_LOW)endfunctionvirtual function void build_phase(uvm_phase phase);super.build_phase(phase);`uvm_info("Driver", "build_phase is called", UVM_LOW);if(!uvm_config_db#(virtual Interface)::get(this, "", "vif", Virtual_Driver_if))`uvm_fatal("Driver", "virtual interface must be set for vif!!!")endfunction   extern virtual task main_phase(uvm_phase phase);
endclass task Driver::main_phase(uvm_phase phase);                                  phase.raise_objection(this);                                    `uvm_info("Driver","main_phase is called",UVM_LOW)                                                 Virtual_Driver_if.data <= 8'd0;                                                      Virtual_Driver_if.val <= 1'b0;                                                     while(~Virtual_Driver_if.rstn)//等待复位完成                                                      begin              @(posedge Virtual_Driver_if.clk);              end                // 随机数激励for(int k = 0;k<256;k++) begin@(posedge Virtual_Driver_if.clk);Virtual_Driver_if.data <= $urandom_range(0,255);Virtual_Driver_if.val <= 1'b1;   `uvm_info("Driver",$sformatf("Random data is drived ,data = %0d",Virtual_Driver_if.data),UVM_LOW)     end// 有效信号拉低@(posedge Virtual_Driver_if.clk);Virtual_Driver_if.val <= 1'b0;phase.drop_objection(this);
endtask

上面的代码用到了 uvm_fatal 。与uvm_info宏不同的是,当它打印第二个参数所示的信息后,会直接调用Verilog的finish函数来结束仿真。uvm_fatal的出现表示验证平台出现了重大问题而无法继续下去,必须停止仿真并做相应的检查。所以对于uvm_fatal来 说,uvm_info中出现的第三个参数的冗余度级别是完全没有意义的,只要是uvm_fatal打印的信息,就一定是非常关键的,所以无需设置第三个参数。

关于 uvm_config_db :

与之有关的函数均为静态函数,所以在调用时要用 :: 操作符。

config_db的 set 和 get 函数都有四个参数,这两个函数的第三个参数必须完全一致。

set函数的第四个参数表示要将哪个interface 通过config_db传递给my_driver,get函数的第四个参数表示把得到的interface传递给哪个my_driver的成员变量。

set函数的第二个参数表示的是路径索引,即在前面介绍uvm_info宏时提及的路径索引。在top_tb中通过run_test创建了一个my_driver的实例,那么 这个实例的名字是什么呢?答案是uvm_test_top:UVM通过run_test语句创建一个名字为uvm_test_top的实例。无论传递给run_test 的参数是什么,创建的实例的名字都为 uvm_test_top。由于set操作的目标是my_driver,所以set函数的第二个参数就是uvm_test_top。set函数的第一个参数null以及get函数的第一和第二个参数可以暂时放在一边,后文会详细说明。

uvm_config_db#(virtual Interface)则是一个参数化的类,其参数就是要寄信的类型,这里是virtual my_if。

手册的具体说明:

Top_tb 的变动:

`timescale 1ns/1ns
`include "uvm_macros.svh"import uvm_pkg::*;
`include "Interface.sv"
`include "Driver.sv"module Top_tb ();
reg clk;
reg rstn;
// reg [7:0] rxd;
// reg rx_val;
// wire tx_en;
// wire [7:0] txd;Interface Input_if( clk, rstn);
Interface Output_if( clk, rstn);Design Inst_Design (.clk(clk), .rstn(rstn), .rxd(Input_if.data), .rx_val(Input_if.val), .tx_en(Output_if.data), .txd(Output_if.val)
);initial
begin // Driver drv;                                        // drv = new("Driver",null);                                     // drv.main_phase(null);                                        run_test("Driver");                                       // $finish;
end                             initial clk = 0;
always #10 clk = ~clk;initial
beginrstn = 1'b0;#138 rstn = 1'b1;
endinitial beginuvm_config_db#(virtual Interface)::set(null, "uvm_test_top", "vif", Input_if);
endendmodule

编译后执行仿真:

给验证平台加入其他组件

加入 transaction

transaction 的翻译为事务。那么到底什么是事务?这其实是一个很抽象的概念。通俗来讲,可以将 transaction 理解为一次完整的激励。一般驱动器的数据激励都是基于 transaction 进行传输。

此处,参考书以以太网协议的数据包为例,做一个说明。


class Transaction extends  uvm_sequence_item;rand bit [47:0] dmac;rand bit [47:0] smac;rand bit [47: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;endfunctionfunction void post_randomize();crc = calc_crc;endfunction`uvm_object_utils(Transaction);function new (string name = "Transaction");super.new(name);endfunction
endclass 

post_randomize是SystemVerilog中提供的一个函数,当某个类的实例的randomize函数被调用后,post_randomize会紧随其后无条件 地被调用。

Transaction的基类是uvm_sequence_item。在UVM中,所有的 transaction都 要从uvm_sequence_item派生,只有从uvm_sequence_item派生的transaction才可以使用UVM中sequence机制。

这里没有使用 uvm_component_utils 宏来实现factory机制,而是使用了uvm_object_utils。从本质上来说,my_transaction与 my_driver是有区别的,在整个仿真期间,my_driver是一直存在的,my_transaction不同,它有生命周期。它在仿真的某一时间产 生,经过driver驱动,再经过reference model处理,最终由scoreboard比较完成后,其生命周期就结束了。一般来说,这种类都是派 生自uvm_object或者uvm_object的派生类,uvm_sequence_item的祖先就是uvm_object。UVM中具有这种特征的类都要使用 uvm_object_utils宏来实现。

Driver 程序:

class Driver extends uvm_driver;virtual Interface Virtual_Driver_if;`uvm_component_utils(Driver)function new(string name = "Driver",uvm_component parent = null);super.new(name,parent);`uvm_info("Driver","new is called",UVM_LOW)endfunctionvirtual function void build_phase(uvm_phase phase);super.build_phase(phase);`uvm_info("Driver", "build_phase is called", UVM_LOW);if(!uvm_config_db#(virtual Interface)::get(this, "", "vif", Virtual_Driver_if))`uvm_fatal("Driver", "virtual interface must be set for vif!!!")endfunction   extern  task main_phase(uvm_phase phase);extern  task drive_one_pkt(Transaction tr);
endclass  task Driver::main_phase(uvm_phase phase); Transaction tr;                         phase.raise_objection(this);                                    `uvm_info("Driver","main_phase is called",UVM_LOW)                                                 Virtual_Driver_if.data <= 8'd0;                                                      Virtual_Driver_if.val <= 1'b0;                                                     while(~Virtual_Driver_if.rstn)//等待复位完成                                                      begin              @(posedge Virtual_Driver_if.clk);              end                // 随机数激励for(int k = 0;k<1;k++) begintr = new("tr");assert(tr.randomize() with{pload.size == 200;});drive_one_pkt(tr);`uvm_info("Driver",$sformatf("Randomize successfully ! "),UVM_LOW) end// 有效信号拉低repeat(10) @(posedge Virtual_Driver_if.clk);phase.drop_objection(this);
endtasktask Driver::drive_one_pkt(Transaction tr);bit [47:0] tmp_data;bit [7:0] data_q[$];`uvm_info("Driver", "Random Package Data Generate Start ...", UVM_LOW);//push dmac to data_qtmp_data = tr.dmac;`uvm_info("Driver",$sformatf("dmac = 0x%0h",tr.dmac),UVM_LOW)for(int i = 0; i < 6; i++) begindata_q.push_back(tmp_data[7:0]);tmp_data = (tmp_data >> 8);end//push smac to data_qtmp_data = tr.smac;`uvm_info("Driver",$sformatf("smac = 0x%0h",tr.smac),UVM_LOW)for(int i = 0; i < 6; i++) begindata_q.push_back(tmp_data[7:0]);tmp_data = (tmp_data >> 8);end//push ether_type to data_qtmp_data = tr.ether_type;`uvm_info("Driver",$sformatf("ether_type = 0x%0h",tr.ether_type),UVM_LOW)for(int i = 0; i < 2; i++) begindata_q.push_back(tmp_data[7:0]);tmp_data = (tmp_data >> 8);end//push payload to data_qfor(int i = 0; i < tr.pload.size; i++) begindata_q.push_back(tr.pload[i]);`uvm_info("Driver",$sformatf("pload[%0d] = 0x%0h",i,tr.pload[i]),UVM_LOW)end//push crc to data_qtmp_data = tr.crc;`uvm_info("Driver",$sformatf("crc = 0x%0h",tr.crc),UVM_LOW)for(int i = 0; i < 4; i++) begindata_q.push_back(tmp_data[7:0]);tmp_data = (tmp_data >> 8);end`uvm_info("Driver", "Random Package Data Generate end ...", UVM_LOW);`uvm_info("Driver", "begin to drive one pkt", UVM_LOW);repeat(3) @(posedge Virtual_Driver_if.clk);while(data_q.size() > 0) begin@(posedge Virtual_Driver_if.clk);Virtual_Driver_if.val <= 1'b1;Virtual_Driver_if.data <= data_q.pop_front(); endrepeat (10) @(posedge Virtual_Driver_if.clk);Virtual_Driver_if.val <= 1'b0;`uvm_info("Driver", "end drive one pkt", UVM_LOW);
endtask

在main_phase中,先使用randomize将tr随机化,之后通过drive_one_pkt任务将tr的内容驱动到DUT的端口上。在drive_one_pkt 中,先将tr中所有的数据压入队列data_q中,之后再将data_q中所有的数据弹出并驱动。将tr中的数据压入队列data_q中的过程相当 于打包成一个byte流的过程。

编译后执行仿真:

加入 environment

environment 就像是一个大的容器内部包含了 计分板、参考模型、监视器、驱动器等组件。在调用 run_test时,传递的参数不再是my_driver,而是这个容器类,即让UVM自动创建这个容器类的实例。在UVM中,这个容器类称为 uvm_env。


class Environment extends  uvm_env;Driver drv;function new(string name = "env",uvm_component parent);super.new(name,parent);endfunctionvirtual function void build_phase(uvm_phase phase);super.build_phase(phase);drv = Driver::type_id::create("drv",this);endfunction`uvm_component_utils(Environment)
endclass

所有的 environment 应该派生自uvm_env,且与Driver一样,容器类在仿真中也是一直存在的,使用uvm_component_utils宏来实现 factory的注册。

在my_env的定义中,最让人难以理解的是第14行drv的实例化。这里没有直接调用my_driver的new函数,而是使用了一种古怪 的方式。这种方式就是factory机制带来的独特的实例化方式。只有使用factory机制注册过的类才能使用这种方式实例化;只有使 用这种方式实例化的实例,才能使用后文要讲述的factory机制中最为强大的重载功能。验证平台中的组件在实例化时都应该使用 type_name::type_id::create的方式。

new函数有两个参数,第一个参数是实例的名字,第二个则是parent。由于my_driver在uvm_env中实例化,所以my_driver 的父结点(parent)就是my_env。通过parent的形式,UVM建立起了树形的组织结构。在这种树形的组织结构中,由run_test创建 的实例是树根(这里是my_env),并且树根的名字是固定的,为uvm_test_top,这在前文中已经讲述过;在树根之后会生长出枝 叶(这里只有my_driver),长出枝叶的过程需要在my_env的build_phase中手动实现。无论是树根还是树叶,都必须由 uvm_component或者其派生类继承而来。整棵UVM树的结构如图所示。

当加入了my_env后,整个验证平台中存在两个build_phase,一个是my_env的,一个是my_driver的。那么这两个build_phase按 照何种顺序执行呢?在UVM的树形结构中,build_phase的执行遵照从树根到树叶的顺序,即先执行my_env的build_phase,再执行 my_driver的build_phase。当把整棵树的build_phase都执行完毕后,再执行后面的phase。

my_driver在验证平台中的层次结构发生了变化,它从树根变成了树叶,所以在Top_tb中使用config_db机制传递virtual Interface时,要改变相应的路径;同时,run_test的参数也从Driver变为了Environment:

`timescale 1ns/1ns
`include "uvm_macros.svh"import uvm_pkg::*;
`include "Interface.sv"
`include "Transaction.sv"
`include "Driver.sv"
`include "Environment.sv"module Top_tb ();
reg clk;
reg rstn;
// reg [7:0] rxd;
// reg rx_val;
// wire tx_en;
// wire [7:0] txd;Interface Input_if( clk, rstn);
Interface Output_if( clk, rstn);Design Inst_Design (.clk(clk), .rstn(rstn), .rxd(Input_if.data), .rx_val(Input_if.val), .tx_en(Output_if.data), .txd(Output_if.val)
);initial
begin // Driver drv;                                        // drv = new("Driver",null);                                     // drv.main_phase(null);                                        // run_test("Driver");    run_test("Environment");                                          // $finish;
end                             initial clk = 0;
always #10 clk = ~clk;initial
beginrstn = 1'b0;#138 rstn = 1'b1;
endinitial beginuvm_config_db#(virtual Interface)::set(null, "uvm_test_top.drv", "vif", Input_if);
endendmodule

set函数的第二个参数从uvm_test_top变为了uvm_test_top.drv,其中uvm_test_top是UVM自动创建的树根的名字,而drv则是在 my_env的build_phase中实例化drv时传递过去的名字。如果在实例化drv时传递的名字是my_drv,那么set函数的第二个参数中也应该是my_drv

加入 monitor

monitor 存在的意义就是将 DUT 输出的响应结果送入计分板,判断其响应的正确性。

验证平台中实现监测DUT行为的组件是monitor。driver负责把transaction级别的数据转变成DUT的端口级别,并驱动给DUT, monitor的行为与其相对,用于收集DUT的端口数据,并将其转换成transaction交给后续的组件如reference model、scoreboard等处理。

Monitor:


class Monitor extends  uvm_monitor;virtual Interface vif;`uvm_component_utils(Monitor)function new (string name = "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 Interface)::get(this,"","vif",vif))`uvm_fatal("Monitor","virtual interface must be set for vif !")endfunctionextern task main_phase(uvm_phase phase);extern task collect_one_pkt(Transaction tr);endclass task Monitor::main_phase(uvm_phase phase);Transaction tr;while(1)begintr = new("tr");collect_one_pkt(tr);endendtask task Monitor::collect_one_pkt(Transaction tr);bit[7:0] data_q[$];int psize;while(1)begin@(posedge vif.clk);if(vif.val) break;end`uvm_info("Monitor","begin to collect one package",UVM_LOW);while(vif.val)begindata_q.push_back(vif.data);@(posedge vif.clk);end`uvm_info("Monitor",$sformatf("collect one package,size=%0d",data_q.size()),UVM_LOW);// pop out to trfor (int i=0;i<6;i++)begintr.dmac = {tr.dmac[39:0],data_q.pop_front()};endfor (int i=0;i<6;i++)begintr.smac = {tr.smac[39:0],data_q.pop_front()};endfor (int i=0;i<2;i++)begintr.dmac = {tr.dmac[39:0],data_q.pop_front()};endpsize = data_q.size() - 4;`uvm_info("Monitor",$sformatf("pload data size=%0d",psize),UVM_LOW);tr.pload = new[psize];//pop payloadfor(int i = 0; i < psize; i++) begintr.pload[i] = data_q.pop_front();end//pop crcfor(int i = 0; i < 4; i++) begintr.crc = {tr.crc[23:0], data_q.pop_front()};end`uvm_info("Monitor", "end collect one package, print it:", UVM_LOW);tr.Print();
endtask 

第一,所有的monitor类应该派生自uvm_monitor

第二,与driver类似,在my_monitor中也需要有一个virtual Interface;

第三,uvm_monitor在整个仿真中是一直存在的,所以它是一个component,要使用uvm_component_utils宏注册;

第四,由于monitor需要时刻收集数据,永不停歇,所以在main_phase中使用while(1)循环来实现这一目的。

Transaction 部分修改:


class 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;endfunctionfunction void post_randomize();crc = calc_crc;endfunction`uvm_object_utils(Transaction);function new (string name = "Transaction");super.new(name);endfunctionfunction void Print ();$display("dmac = 0x%0h",dmac);$display("smac = 0x%0h",smac);$display("ether type = 0x%0h",ether_type);for(int i=0;i<pload.size;i++)$display("pload[%0d] = 0x%0h",i,pload[i]);$display("crc = 0x%0h",crc);endfunction
endclass 

增加 Print 打印输出函数。

Environment 部分修改:


class Environment extends  uvm_env;Driver drv;Monitor i_mon,o_mon;function new(string name = "env",uvm_component parent);super.new(name,parent);endfunctionvirtual function void build_phase(uvm_phase phase);super.build_phase(phase);drv = Driver::type_id::create("drv",this);i_mon=Monitor::type_id::create("i_mon",this);o_mon=Monitor::type_id::create("o_mon",this);endfunction`uvm_component_utils(Environment)
endclass

这里实例化了两个monitor,一个用于监测DUT的输入口,一个用于监测DUT的输出口。DUT的输出口设置一个monitor没有任何疑问,但是在DUT的输入口设置一个monitor有必要吗?由于transaction是由driver产生并输出到DUT的端口上,所以driver可以直接将其交给后面的reference model。在2.1节所示的框图中,也是使用这样的策略。所以是否使用monitor,这个答案仁者见仁,智者见智。这里还是推荐使用monitor,原因是:第一,在一个大型的项目中,driver根据某一协议发送数据,而monitor根据这种协议收集数据,如果driver和monitor由不同人员实现,那么可以大大减少其中任何一方对协议理解的错误;第
二,在后文将会看到,在实现代码重用时,使用monitor是非常有必要的。

environment 中树形结构:

Top_tb 部分修改:

`timescale 1ns/1ns
`include "uvm_macros.svh"import uvm_pkg::*;
`include "Interface.sv"
`include "Transaction.sv"
`include "Driver.sv"
`include "Monitor.sv"
`include "Environment.sv"module Top_tb ();
reg clk;
reg rstn;
// reg [7:0] rxd;
// reg rx_val;
// wire tx_en;
// wire [7:0] txd;Interface Input_if( clk, rstn);
Interface Output_if( clk, rstn);Design Inst_Design (.clk(clk), .rstn(rstn), .rxd(Input_if.data), .rx_val(Input_if.val), .tx_en(Output_if.val), .txd(Output_if.data)
);initial
begin // Driver drv;                                        // drv = new("Driver",null);                                     // drv.main_phase(null);                                        // run_test("Driver");    run_test("Environment");                                          // $finish;
end                             initial clk = 0;
always #10 clk = ~clk;initial
beginrstn = 1'b0;#138 rstn = 1'b1;
endinitial beginuvm_config_db#(virtual Interface)::set(null, "uvm_test_top.drv", "vif", Input_if);uvm_config_db#(virtual Interface)::set(null, "uvm_test_top.i_mon", "vif", Input_if);uvm_config_db#(virtual Interface)::set(null, "uvm_test_top.o_mon", "vif", Output_if);
endendmodule

编译后执行仿真:

# ----------------------------------------------------------------
# UVM-1.1d
# (C) 2007-2013 Mentor Graphics Corporation
# (C) 2007-2013 Cadence Design Systems, Inc.
# (C) 2006-2013 Synopsys, Inc.
# (C) 2011-2013 Cypress Semiconductor Corp.
# ----------------------------------------------------------------
#
#   ***********       IMPORTANT RELEASE NOTES         ************
#
#   You are using a version of the UVM library that has been compiled
#   with `UVM_NO_DEPRECATED undefined.
#   See http://www.eda.org/svdb/view.php?id=3313 for more details.
#
#   You are using a version of the UVM library that has been compiled
#   with `UVM_OBJECT_MUST_HAVE_CONSTRUCTOR undefined.
#   See http://www.eda.org/svdb/view.php?id=3770 for more details.
#
#       (Specify +UVM_NO_RELNOTES to turn off this notice)
#
# UVM_INFO verilog_src/questa_uvm_pkg-1.2/src/questa_uvm_pkg.sv(215) @ 0: reporter [Questa UVM] QUESTA_UVM-1.2.3
# UVM_INFO verilog_src/questa_uvm_pkg-1.2/src/questa_uvm_pkg.sv(217) @ 0: reporter [Questa UVM]  questa_uvm::init(+struct)
# UVM_INFO @ 0: reporter [RNTST] Running test Environment...
# UVM_INFO Driver.sv(7) @ 0: uvm_test_top.drv [Driver] new is called
# UVM_INFO Driver.sv(12) @ 0: uvm_test_top.drv [Driver] build_phase is called
# UVM_INFO Driver.sv(24) @ 0: uvm_test_top.drv [Driver] main_phase is called
# UVM_INFO Driver.sv(48) @ 150: uvm_test_top.drv [Driver] Random Package Data Generate Start ...
# UVM_INFO Driver.sv(51) @ 150: uvm_test_top.drv [Driver] dmac = 0xf4bfbad01b03
# UVM_INFO Driver.sv(59) @ 150: uvm_test_top.drv [Driver] smac = 0x26df69099fc0
# UVM_INFO Driver.sv(67) @ 150: uvm_test_top.drv [Driver] ether_type = 0xa67a
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[0] = 0x4a
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[1] = 0x60
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[2] = 0x23
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[3] = 0x24
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[4] = 0x90
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[5] = 0xaf
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[6] = 0xce
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[7] = 0x23
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[8] = 0xb1
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[9] = 0xd3
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[10] = 0x45
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[11] = 0xf
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[12] = 0x60
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[13] = 0x5f
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[14] = 0xee
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[15] = 0x5c
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[16] = 0x3e
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[17] = 0xee
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[18] = 0x99
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[19] = 0x30
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[20] = 0xbf
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[21] = 0xbb
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[22] = 0x8b
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[23] = 0x92
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[24] = 0x3b
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[25] = 0x53
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[26] = 0x23
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[27] = 0x27
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[28] = 0xc8
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[29] = 0x9
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[30] = 0x82
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[31] = 0x9b
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[32] = 0x48
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[33] = 0x76
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[34] = 0xfb
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[35] = 0x32
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[36] = 0xcc
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[37] = 0xcb
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[38] = 0x5
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[39] = 0xc2
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[40] = 0xa2
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[41] = 0x6
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[42] = 0x4c
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[43] = 0xe9
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[44] = 0x1c
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[45] = 0x79
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[46] = 0xf4
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[47] = 0x65
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[48] = 0xa7
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[49] = 0x8d
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[50] = 0x3d
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[51] = 0xac
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[52] = 0xb9
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[53] = 0xe4
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[54] = 0x11
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[55] = 0x99
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[56] = 0x44
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[57] = 0xca
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[58] = 0xe5
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[59] = 0xa1
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[60] = 0xea
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[61] = 0x11
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[62] = 0xc4
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[63] = 0x52
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[64] = 0xc4
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[65] = 0x9a
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[66] = 0x36
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[67] = 0x15
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[68] = 0x1
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[69] = 0x6f
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[70] = 0x62
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[71] = 0xe1
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[72] = 0x79
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[73] = 0xa9
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[74] = 0x75
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[75] = 0x62
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[76] = 0x89
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[77] = 0xda
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[78] = 0x56
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[79] = 0xe8
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[80] = 0x3
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[81] = 0xf9
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[82] = 0x4f
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[83] = 0x7a
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[84] = 0x6d
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[85] = 0x6a
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[86] = 0x49
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[87] = 0x3e
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[88] = 0xc0
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[89] = 0x6a
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[90] = 0xd4
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[91] = 0xa5
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[92] = 0x86
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[93] = 0xac
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[94] = 0x10
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[95] = 0xce
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[96] = 0xd4
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[97] = 0x83
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[98] = 0xbc
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[99] = 0x6e
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[100] = 0x36
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[101] = 0xfc
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[102] = 0xf8
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[103] = 0x80
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[104] = 0xd
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[105] = 0x7b
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[106] = 0xde
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[107] = 0xd1
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[108] = 0x7e
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[109] = 0x75
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[110] = 0xea
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[111] = 0xe0
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[112] = 0xed
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[113] = 0xbf
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[114] = 0xba
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[115] = 0x2a
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[116] = 0x8a
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[117] = 0x5b
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[118] = 0x9a
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[119] = 0x57
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[120] = 0x17
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[121] = 0x14
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[122] = 0xd0
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[123] = 0x21
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[124] = 0xca
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[125] = 0x6a
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[126] = 0x74
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[127] = 0x34
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[128] = 0x58
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[129] = 0xbc
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[130] = 0x94
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[131] = 0x7e
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[132] = 0x7c
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[133] = 0xb3
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[134] = 0xd8
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[135] = 0x8b
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[136] = 0xef
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[137] = 0xb5
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[138] = 0x41
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[139] = 0x6c
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[140] = 0x2
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[141] = 0x46
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[142] = 0x71
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[143] = 0x1a
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[144] = 0x9c
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[145] = 0x22
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[146] = 0x27
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[147] = 0x52
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[148] = 0x26
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[149] = 0x90
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[150] = 0x43
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[151] = 0xc3
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[152] = 0x1a
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[153] = 0x12
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[154] = 0x87
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[155] = 0x71
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[156] = 0xf
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[157] = 0x9c
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[158] = 0xd6
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[159] = 0x64
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[160] = 0xac
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[161] = 0x3
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[162] = 0xd5
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[163] = 0x43
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[164] = 0x33
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[165] = 0xb
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[166] = 0xf3
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[167] = 0x4f
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[168] = 0x22
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[169] = 0x9
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[170] = 0xe5
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[171] = 0x46
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[172] = 0x17
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[173] = 0x39
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[174] = 0x20
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[175] = 0x99
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[176] = 0xd1
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[177] = 0x2a
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[178] = 0x9
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[179] = 0x87
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[180] = 0xbf
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[181] = 0x69
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[182] = 0x6a
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[183] = 0xcc
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[184] = 0xa8
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[185] = 0xd3
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[186] = 0x4
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[187] = 0xa2
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[188] = 0x81
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[189] = 0x9e
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[190] = 0xe5
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[191] = 0x29
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[192] = 0x5c
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[193] = 0xf9
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[194] = 0xb5
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[195] = 0x50
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[196] = 0x51
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[197] = 0x3c
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[198] = 0x9e
# UVM_INFO Driver.sv(76) @ 150: uvm_test_top.drv [Driver] pload[199] = 0x43
# UVM_INFO Driver.sv(80) @ 150: uvm_test_top.drv [Driver] crc = 0x0
# UVM_INFO Driver.sv(86) @ 150: uvm_test_top.drv [Driver] Random Package Data Generate end ...
# UVM_INFO Driver.sv(88) @ 150: uvm_test_top.drv [Driver] begin to drive one pkt
# UVM_INFO Monitor.sv(39) @ 250: uvm_test_top.i_mon [Monitor] begin to collect one package
# UVM_INFO Monitor.sv(39) @ 270: uvm_test_top.o_mon [Monitor] begin to collect one package
# UVM_INFO Driver.sv(100) @ 4590: uvm_test_top.drv [Driver] end drive one pkt
# UVM_INFO Driver.sv(37) @ 4590: uvm_test_top.drv [Driver] Randomize successfully !
# UVM_INFO Monitor.sv(45) @ 4610: uvm_test_top.i_mon [Monitor] collect one package,size=218
# UVM_INFO Monitor.sv(60) @ 4610: uvm_test_top.i_mon [Monitor] pload data size=200
# UVM_INFO Monitor.sv(70) @ 4610: uvm_test_top.i_mon [Monitor] end collect one package, print it:
# dmac = 0xd0babff47aa6
# smac = 0xc09f0969df26
# ether type = 0x0
# pload[0] = 0x4a
# pload[1] = 0x60
# pload[2] = 0x23
# pload[3] = 0x24
# pload[4] = 0x90
# pload[5] = 0xaf
# pload[6] = 0xce
# pload[7] = 0x23
# pload[8] = 0xb1
# pload[9] = 0xd3
# pload[10] = 0x45
# pload[11] = 0xf
# pload[12] = 0x60
# pload[13] = 0x5f
# pload[14] = 0xee
# pload[15] = 0x5c
# pload[16] = 0x3e
# pload[17] = 0xee
# pload[18] = 0x99
# pload[19] = 0x30
# pload[20] = 0xbf
# pload[21] = 0xbb
# pload[22] = 0x8b
# pload[23] = 0x92
# pload[24] = 0x3b
# pload[25] = 0x53
# pload[26] = 0x23
# pload[27] = 0x27
# pload[28] = 0xc8
# pload[29] = 0x9
# pload[30] = 0x82
# pload[31] = 0x9b
# pload[32] = 0x48
# pload[33] = 0x76
# pload[34] = 0xfb
# pload[35] = 0x32
# pload[36] = 0xcc
# pload[37] = 0xcb
# pload[38] = 0x5
# pload[39] = 0xc2
# pload[40] = 0xa2
# pload[41] = 0x6
# pload[42] = 0x4c
# pload[43] = 0xe9
# pload[44] = 0x1c
# pload[45] = 0x79
# pload[46] = 0xf4
# pload[47] = 0x65
# pload[48] = 0xa7
# pload[49] = 0x8d
# pload[50] = 0x3d
# pload[51] = 0xac
# pload[52] = 0xb9
# pload[53] = 0xe4
# pload[54] = 0x11
# pload[55] = 0x99
# pload[56] = 0x44
# pload[57] = 0xca
# pload[58] = 0xe5
# pload[59] = 0xa1
# pload[60] = 0xea
# pload[61] = 0x11
# pload[62] = 0xc4
# pload[63] = 0x52
# pload[64] = 0xc4
# pload[65] = 0x9a
# pload[66] = 0x36
# pload[67] = 0x15
# pload[68] = 0x1
# pload[69] = 0x6f
# pload[70] = 0x62
# pload[71] = 0xe1
# pload[72] = 0x79
# pload[73] = 0xa9
# pload[74] = 0x75
# pload[75] = 0x62
# pload[76] = 0x89
# pload[77] = 0xda
# pload[78] = 0x56
# pload[79] = 0xe8
# pload[80] = 0x3
# pload[81] = 0xf9
# pload[82] = 0x4f
# pload[83] = 0x7a
# pload[84] = 0x6d
# pload[85] = 0x6a
# pload[86] = 0x49
# pload[87] = 0x3e
# pload[88] = 0xc0
# pload[89] = 0x6a
# pload[90] = 0xd4
# pload[91] = 0xa5
# pload[92] = 0x86
# pload[93] = 0xac
# pload[94] = 0x10
# pload[95] = 0xce
# pload[96] = 0xd4
# pload[97] = 0x83
# pload[98] = 0xbc
# pload[99] = 0x6e
# pload[100] = 0x36
# pload[101] = 0xfc
# pload[102] = 0xf8
# pload[103] = 0x80
# pload[104] = 0xd
# pload[105] = 0x7b
# pload[106] = 0xde
# pload[107] = 0xd1
# pload[108] = 0x7e
# pload[109] = 0x75
# pload[110] = 0xea
# pload[111] = 0xe0
# pload[112] = 0xed
# pload[113] = 0xbf
# pload[114] = 0xba
# pload[115] = 0x2a
# pload[116] = 0x8a
# pload[117] = 0x5b
# pload[118] = 0x9a
# pload[119] = 0x57
# pload[120] = 0x17
# pload[121] = 0x14
# pload[122] = 0xd0
# pload[123] = 0x21
# pload[124] = 0xca
# pload[125] = 0x6a
# pload[126] = 0x74
# pload[127] = 0x34
# pload[128] = 0x58
# pload[129] = 0xbc
# pload[130] = 0x94
# pload[131] = 0x7e
# pload[132] = 0x7c
# pload[133] = 0xb3
# pload[134] = 0xd8
# pload[135] = 0x8b
# pload[136] = 0xef
# pload[137] = 0xb5
# pload[138] = 0x41
# pload[139] = 0x6c
# pload[140] = 0x2
# pload[141] = 0x46
# pload[142] = 0x71
# pload[143] = 0x1a
# pload[144] = 0x9c
# pload[145] = 0x22
# pload[146] = 0x27
# pload[147] = 0x52
# pload[148] = 0x26
# pload[149] = 0x90
# pload[150] = 0x43
# pload[151] = 0xc3
# pload[152] = 0x1a
# pload[153] = 0x12
# pload[154] = 0x87
# pload[155] = 0x71
# pload[156] = 0xf
# pload[157] = 0x9c
# pload[158] = 0xd6
# pload[159] = 0x64
# pload[160] = 0xac
# pload[161] = 0x3
# pload[162] = 0xd5
# pload[163] = 0x43
# pload[164] = 0x33
# pload[165] = 0xb
# pload[166] = 0xf3
# pload[167] = 0x4f
# pload[168] = 0x22
# pload[169] = 0x9
# pload[170] = 0xe5
# pload[171] = 0x46
# pload[172] = 0x17
# pload[173] = 0x39
# pload[174] = 0x20
# pload[175] = 0x99
# pload[176] = 0xd1
# pload[177] = 0x2a
# pload[178] = 0x9
# pload[179] = 0x87
# pload[180] = 0xbf
# pload[181] = 0x69
# pload[182] = 0x6a
# pload[183] = 0xcc
# pload[184] = 0xa8
# pload[185] = 0xd3
# pload[186] = 0x4
# pload[187] = 0xa2
# pload[188] = 0x81
# pload[189] = 0x9e
# pload[190] = 0xe5
# pload[191] = 0x29
# pload[192] = 0x5c
# pload[193] = 0xf9
# pload[194] = 0xb5
# pload[195] = 0x50
# pload[196] = 0x51
# pload[197] = 0x3c
# pload[198] = 0x9e
# pload[199] = 0x43
# crc = 0x0
# UVM_INFO Monitor.sv(45) @ 4630: uvm_test_top.o_mon [Monitor] collect one package,size=218
# UVM_INFO Monitor.sv(60) @ 4630: uvm_test_top.o_mon [Monitor] pload data size=200
# UVM_INFO Monitor.sv(70) @ 4630: uvm_test_top.o_mon [Monitor] end collect one package, print it:
# dmac = 0xd0babff47aa6
# smac = 0xc09f0969df26
# ether type = 0x0
# pload[0] = 0x4a
# pload[1] = 0x60
# pload[2] = 0x23
# pload[3] = 0x24
# pload[4] = 0x90
# pload[5] = 0xaf
# pload[6] = 0xce
# pload[7] = 0x23
# pload[8] = 0xb1
# pload[9] = 0xd3
# pload[10] = 0x45
# pload[11] = 0xf
# pload[12] = 0x60
# pload[13] = 0x5f
# pload[14] = 0xee
# pload[15] = 0x5c
# pload[16] = 0x3e
# pload[17] = 0xee
# pload[18] = 0x99
# pload[19] = 0x30
# pload[20] = 0xbf
# pload[21] = 0xbb
# pload[22] = 0x8b
# pload[23] = 0x92
# pload[24] = 0x3b
# pload[25] = 0x53
# pload[26] = 0x23
# pload[27] = 0x27
# pload[28] = 0xc8
# pload[29] = 0x9
# pload[30] = 0x82
# pload[31] = 0x9b
# pload[32] = 0x48
# pload[33] = 0x76
# pload[34] = 0xfb
# pload[35] = 0x32
# pload[36] = 0xcc
# pload[37] = 0xcb
# pload[38] = 0x5
# pload[39] = 0xc2
# pload[40] = 0xa2
# pload[41] = 0x6
# pload[42] = 0x4c
# pload[43] = 0xe9
# pload[44] = 0x1c
# pload[45] = 0x79
# pload[46] = 0xf4
# pload[47] = 0x65
# pload[48] = 0xa7
# pload[49] = 0x8d
# pload[50] = 0x3d
# pload[51] = 0xac
# pload[52] = 0xb9
# pload[53] = 0xe4
# pload[54] = 0x11
# pload[55] = 0x99
# pload[56] = 0x44
# pload[57] = 0xca
# pload[58] = 0xe5
# pload[59] = 0xa1
# pload[60] = 0xea
# pload[61] = 0x11
# pload[62] = 0xc4
# pload[63] = 0x52
# pload[64] = 0xc4
# pload[65] = 0x9a
# pload[66] = 0x36
# pload[67] = 0x15
# pload[68] = 0x1
# pload[69] = 0x6f
# pload[70] = 0x62
# pload[71] = 0xe1
# pload[72] = 0x79
# pload[73] = 0xa9
# pload[74] = 0x75
# pload[75] = 0x62
# pload[76] = 0x89
# pload[77] = 0xda
# pload[78] = 0x56
# pload[79] = 0xe8
# pload[80] = 0x3
# pload[81] = 0xf9
# pload[82] = 0x4f
# pload[83] = 0x7a
# pload[84] = 0x6d
# pload[85] = 0x6a
# pload[86] = 0x49
# pload[87] = 0x3e
# pload[88] = 0xc0
# pload[89] = 0x6a
# pload[90] = 0xd4
# pload[91] = 0xa5
# pload[92] = 0x86
# pload[93] = 0xac
# pload[94] = 0x10
# pload[95] = 0xce
# pload[96] = 0xd4
# pload[97] = 0x83
# pload[98] = 0xbc
# pload[99] = 0x6e
# pload[100] = 0x36
# pload[101] = 0xfc
# pload[102] = 0xf8
# pload[103] = 0x80
# pload[104] = 0xd
# pload[105] = 0x7b
# pload[106] = 0xde
# pload[107] = 0xd1
# pload[108] = 0x7e
# pload[109] = 0x75
# pload[110] = 0xea
# pload[111] = 0xe0
# pload[112] = 0xed
# pload[113] = 0xbf
# pload[114] = 0xba
# pload[115] = 0x2a
# pload[116] = 0x8a
# pload[117] = 0x5b
# pload[118] = 0x9a
# pload[119] = 0x57
# pload[120] = 0x17
# pload[121] = 0x14
# pload[122] = 0xd0
# pload[123] = 0x21
# pload[124] = 0xca
# pload[125] = 0x6a
# pload[126] = 0x74
# pload[127] = 0x34
# pload[128] = 0x58
# pload[129] = 0xbc
# pload[130] = 0x94
# pload[131] = 0x7e
# pload[132] = 0x7c
# pload[133] = 0xb3
# pload[134] = 0xd8
# pload[135] = 0x8b
# pload[136] = 0xef
# pload[137] = 0xb5
# pload[138] = 0x41
# pload[139] = 0x6c
# pload[140] = 0x2
# pload[141] = 0x46
# pload[142] = 0x71
# pload[143] = 0x1a
# pload[144] = 0x9c
# pload[145] = 0x22
# pload[146] = 0x27
# pload[147] = 0x52
# pload[148] = 0x26
# pload[149] = 0x90
# pload[150] = 0x43
# pload[151] = 0xc3
# pload[152] = 0x1a
# pload[153] = 0x12
# pload[154] = 0x87
# pload[155] = 0x71
# pload[156] = 0xf
# pload[157] = 0x9c
# pload[158] = 0xd6
# pload[159] = 0x64
# pload[160] = 0xac
# pload[161] = 0x3
# pload[162] = 0xd5
# pload[163] = 0x43
# pload[164] = 0x33
# pload[165] = 0xb
# pload[166] = 0xf3
# pload[167] = 0x4f
# pload[168] = 0x22
# pload[169] = 0x9
# pload[170] = 0xe5
# pload[171] = 0x46
# pload[172] = 0x17
# pload[173] = 0x39
# pload[174] = 0x20
# pload[175] = 0x99
# pload[176] = 0xd1
# pload[177] = 0x2a
# pload[178] = 0x9
# pload[179] = 0x87
# pload[180] = 0xbf
# pload[181] = 0x69
# pload[182] = 0x6a
# pload[183] = 0xcc
# pload[184] = 0xa8
# pload[185] = 0xd3
# pload[186] = 0x4
# pload[187] = 0xa2
# pload[188] = 0x81
# pload[189] = 0x9e
# pload[190] = 0xe5
# pload[191] = 0x29
# pload[192] = 0x5c
# pload[193] = 0xf9
# pload[194] = 0xb5
# pload[195] = 0x50
# pload[196] = 0x51
# pload[197] = 0x3c
# pload[198] = 0x9e
# pload[199] = 0x43
# crc = 0x0
# 

封装为 agent

driver和monitor之间的联系:两者之间的代码高度相似。其本质是因为二者处理的是同一种协议,在同样一套既定的规则下做着不同的事情。由于二者的这种相似性,UVM中通常将二者封装在一起,成为 一个agent。因此,不同的agent就代表了不同的协议。


class Agent extends  uvm_agent;Driver  drv;Monitor mon;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(Agent)
endclass function void Agent::build_phase(uvm_phase phase); super.build_phase(phase);if (is_active == UVM_ACTIVE)begindrv = Driver::type_id::create("drv",this);endmon = Monitor::type_id::create("mon",this);
endfunction function void Agent::connect_phase(uvm_phase phase);super.connect_phase(phase);
endfunction

所有的agent都要派生自uvm_agent类,且其本身是一个component,应该使用uvm_component_utils 宏来实现factory注册。

is_active是uvm_agent的一 个成员变量,从UVM的源代码中可以找到它的原型如下:

这个枚举变量仅有两个值:UVM_PASSIVE和UVM_ACTIVE。在uvm_agent中,is_active的值默认为UVM_ACTIVE,在这种模 式下,是需要实例化driver的。那么什么是UVM_PASSIVE 模式呢?以本章的DUT为例,如图2-5所示,在输出端口上不需要驱动任 何信号,只需要监测信号。在这种情况下,端口上是只需要monitor的,所以driver可以不用实例化。

在把driver和monitor封装成agent后,在env中需要实例化agent,而不需要直接实例化driver和monitor了:


class Environment extends  uvm_env;// Driver drv;// Monitor i_mon,o_mon;Agent i_agt,o_agt;function new(string name = "env",uvm_component parent);super.new(name,parent);endfunctionvirtual function void build_phase(uvm_phase phase);super.build_phase(phase);i_agt = Agent::type_id::create("i_agt",this);o_agt = Agent::type_id::create("o_agt",this);i_agt.is_active = UVM_ACTIVE;o_agt.is_active = UVM_PASSIVE;endfunction`uvm_component_utils(Environment)
endclass

完成i_agt和o_agt的声明后,在my_env的build_phase中对它们进行实例化后,需要指定各自的工作模式是active模式还是passive 模式。现在,整棵UVM树变为了如所示形式。

由于agent的加入,driver和monitor的层次结构改变了,在top_tb中使用config_db设置virtual my_if时要注意改变路径:

在加入了my_agent后,UVM的树形结构越来越清晰。首先,只有uvm_component才能作为树的结点,像my_transaction这种使 用uvm_object_utils宏实现的类是不能作为UVM树的结点的。其次,在my_env的build_phase中,创建i_agt和o_agt的实例是在 build_phase中;在agent中,创建driver和monitor的实例也是在build_phase中。按照前文所述的build_phase的从树根到树叶的执行顺序,可以建立一棵完整的UVM树。UVM要求UVM树最晚在build_phase时段完成,如果在build_phase后的某个phase实例化一个 component:


class Environment extends  uvm_env;// Driver drv;// Monitor i_mon,o_mon;Agent i_agt,o_agt;function new(string name = "env",uvm_component parent);super.new(name,parent);endfunctionvirtual function void build_phase(uvm_phase phase);super.build_phase(phase);// i_agt = Agent::type_id::create("i_agt",this);// o_agt = Agent::type_id::create("o_agt",this);// i_agt.is_active = UVM_ACTIVE;// o_agt.is_active = UVM_PASSIVE;endfunctionvirtual task main_phase(uvm_phase phase);i_agt = Agent::type_id::create("i_agt",this);o_agt = Agent::type_id::create("o_agt",this);i_agt.is_active = UVM_ACTIVE;o_agt.is_active = UVM_PASSIVE;endtask`uvm_component_utils(Environment)
endclass

如上所示,将在my_env的build_phase中的实例化工作移动到main_phase中,UVM会给出如下错误提示:

那么是不是只能在build_phase中执行实例化的动作呢?答案是否定的。其实还可以在new函数中执行实例化的动作。如可以在 my_agent的new函数中实例化driver和monitor:

UVM中约定俗成的还是在build_phase中完成实例化工作。因此,强烈建议仅在build_phase中完成实例化。

加入reference model

reference model用于完成和DUT相同的功能。reference model的输出被scoreboard 接收,用于和DUT的输出相比较。DUT如果很复杂,那么reference model也会相当复杂:



根据学习进度会更新……

UVM学习——搭建简单的UVM平台相关推荐

  1. 用OpenStack搭建简单的云平台并启动云主机

    OpenStack OpenStack简介 OpenStack重要集成组件 OpenStack平台部署 部署环境 建立虚拟机 配置时间同步 安装OpenStack 安装 RabbitMQ 消息队列服务 ...

  2. 从零开始,搭建一个简单的UVM验证平台(一)

    前言: 这篇系列将从0开始搭建一个UVM验证平台,来帮助一些学习了SV和UVM知识,但对搭建完整的验证环境没有概念的朋友. UVM前置基础: 1.UVM基础-factory机制.phase机制 2.U ...

  3. 诙谐有趣的《UVM实战》笔记——第二章 一个简单的UVM验证平台

    前言 某天白天在地铁上听鬼故事,结果晚上要睡觉时,故事里的情节都历历在目,给我鸡皮疙瘩起的~ 不过我倒是没有吓得睡不着,而是转念一想,为啥我学知识忘得很快,随便听的鬼故事却记得这么清楚咧? 那如果能像 ...

  4. UVM学习之路(4)— 基本的UVM验证平台

    UVM学习之路(4)- 基本的UVM验证平台 一.前言 一般我们将设计输出的文件称为DUT(Design Under Test),即待测设计,验证是来找出DUT中的bug, 这个过程通常是把DUT放入 ...

  5. UVM学习之路(5)— 完整的UVM验证平台

    UVM学习之路(5)- 完整的UVM验证平台 一.前言 一个完整的UVM验证平台还应该加入寄存器模型,对应的设计文件中也应该存在寄存器及其控制端口, 通过该控制端口可以配置DUT中的寄存器. 二.设计 ...

  6. UVM学习之路(6)— 基于MCDF的验证平台

    UVM学习之路(6)- 基于MCDF的验证平台 一.前言 MCDF即多通道数据整形器(Multi-Channel Data Formatter)可以将多个通道是数据经过打包后以数据包的形式发送出去,其 ...

  7. 一个简单的UVM验证平台

    2.1 验证平台的组成 2.1.1. 何谓验证平台 何谓验证平台?验证最基本的目的在于测试 DUT 的正确性,其最常使用的方法就是给 DUT 施加不同的输入(激励),所以一个验证平台最重要的的功能在于 ...

  8. UVM验证方法学之一验证平台

    UVM验证方法学之一验证平台 在现代IC设计流程中,当设计人员根据设计规格说明书完成RTL代码之后,验证人员开始验证这些代码(通常称其为DUT,Design Under Test).验证工作主要保证从 ...

  9. UVM学习笔记—快速入门篇

    UVM指的是验证方法学,是学习数字验证的入门课程.它是至关重要的,有不少人往IC验证方向发展的,多多少少都会去了解UVM.但UVM并不是简单的翻个书就可以学会的,还是要掌握学习方法或者跟着老师学习的. ...

最新文章

  1. 生成ssh key (Mac Linux )
  2. 【放置奇兵】踩坑记录( 白字、红字、黄字)tips 小技巧
  3. Arraylist gossip
  4. css 实现app图标样式_uni-app开发一个小视频应用(一)
  5. Ubuntu/Fedora高版本安装海思SDK的方法
  6. HihoCoder - 1879 Rikka with Triangles(极角排序求所有锐角三角形的面积)
  7. 限制ul显示高度_HP Envy 34寸超宽曲屏 显示器评测
  8. Android中shape中的属性大全
  9. creo图纸管理系统 creo企业图纸管理方案
  10. Java生成简单的验证码图片
  11. 在iPhone设置一个快捷指令,一键将PDF转为图片
  12. iOS安装ipa文件
  13. 不懂APS系统?十个问答让你瞬间了解APS高级计划与排程系统
  14. Mac删除文件提示“不能删除xx项目,正在使用中”
  15. 【CF833D】Red-Black Cobweb(点分治)
  16. 多径效应和多普勒效应
  17. 【netcore】MiniExcel轻量级开源组件使用
  18. Python可以用来做什么?
  19. 织梦插件织梦CMS百度收录查询及批量推送未收录插件
  20. [BZOJ5197] [CERC2017]Gambling Guide

热门文章

  1. AVFoundation Programming Guide(官方文档翻译5)Still and Video Media Capture - 静态视频媒体捕获。
  2. php根据经纬度计算距离大小,PHP 根据经纬度计算距离的简单示例
  3. Mysql常见的日期、时间函数
  4. Android布局中gravity、layout_gravity与layout_centerHorizontal属性区别介绍
  5. css实现雪花背景图
  6. 5——7-2 动物世界 (15分)
  7. 产品的痛点、爽点和痒点
  8. 一些快捷键要熟悉---idea vscode
  9. js es6 新特性
  10. laravel mysql 分表_laravel分库分表