【UVM基础】2、组件家族

组件家族

 

uvm_transaction

transaction是一个抽象的概念,一般来说物理协议中的数据交换都是以帧后者包为单位的,在一帧或者一个包中定义好各项参数,一个transaction就是一个包。

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

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

 transaction和driver之间还是有差别的,整个仿真期间driver都是存在的,而transaction不同,因为transaction有自己的生命周期,在仿真的某一段时间产生,经过driver驱动,reference model处理,他的生命周期也就结束了。

uvm_driver

从uvm_sequencer中获取事务,经过转换对DUT进行时序激励,该类是参数化的类,因此在定义的时候需要声明参数的类型,uvm_driver类的定义:

class uvm_driver # (type REQ=uvm_sequence_item , type RSP=REQ) entends uvm_component; 

在定义新的driver类的时候,应当声明该类所需要获得的事务参数REQ类型,默认情况下,RSP应当和REQ保持相同类型。uvm_driver 在uvm_component的基础上没有扩展新的函数,而是知识扩展了一些通信端口和变量

uvm_driver 示例

 

 uvm_monitor

uvm_monitor类的目的是检测接口数据,任何需要数据监测的monitor都应当继承于这个类,虽然uvm_monitor与它的父类相比,并没有增添新的成员和方法, 但将新定义的monitor类继承于uvm_monitor类会有助于实现父类  uvm monitor的方法和特性.uvm_monitor执行的功能包括:

● 观测DUT的interface,并且收集总线信息

●永远保持PASSIVE模式,即永远不会驱动DUT

●在总线协议或者内部信号协议观察时,可以做一些功能和时序的检查 。

●对干更加复杂的检查要求,它们可以将数据发送至其它验证组件,例如scoreboard  reference model或者coverage collector。

uvm_sequence机制

uvm_sequence

sequence不属于验证平台的任何一个地方,但是与sequencer之间有着密切的联系,sequence比喻成一个弹夹,transaction就是弹夹里面的子弹,sequencer就是一个手枪。需要注意的是sequence是一个uvm_object,而sequencer是一个uvm_component。

class my_sequence extends uvm_sequence #(my_transaction);
   my_transaction m_trans;

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

   virtual task body();
      repeat (10) begin
         `uvm_do(m_trans)
      end
      #1000;
   endtask

   `uvm_object_utils(my_sequence)
endclass

uvm_sequencer

uvm_sequencer就如同一个管道, 从这个管道中会产生连续的激励事务,并最终通过TLM端口送至driver—测。如果需要的话,uvm_Sequencer也可从uvm_driver那里获取随后的RSP对 象来得知数据通信是否正常(通过握手)。 uvm_sequencer类的定义来看,它同uvm_driver—样是个参数类,需要 在定义Sequencer时声明REQ的类型。

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

 uvm_agent

uvm_agemt 的存在是为了验证环 UVM Agent 境的复用。按照总线的传输方向划分可以分为master和slaveo 。Master agent是用来向DUT 发起transaction; Slave agent是用来响应 DUT  的event。

uvm_agent是一个标准的验证环境“单位”,这样的一个标准单位通常包含一个driver、一个monitor以及一个Sequencer 。同时为了复用,有的时候uvm_agent中只需要包含一个momitor,而不需要driver和sequencer,这就需要通过一个变量来进行有条件的例化。

uvm_active_passive_enum is_active = UVM_ACTIVE;

is_active可以理解为agent的一个成员,缺省值是UVM_ACTIVE,表示在active模式的agent需要例化driver、monitor和sequencer,而如果is_active的值是UVM_PASSIVE,这表示agent是passive模式,只可以例化monitor。 active模式的agent既有激励功能也有监测功能,passive模式的agent只具有监测功能。
通过is_active变量,agent需要在build_phase和connect_phase等函数中通过选择语句来对driver和sequencer进行有条件的例化和连接

 uvm_scoreboard

uvm_scoreboard担任着同SV中checker一样的功能进行数据比对和报告。  uvm_scoreboard本身没有添加额外的成员变量和方法,uvm_scoreboard会接收来自于多个monitor的监测据,从而进行比较。

uvm_scoreboard自带的两个用于数据比较的类:

uvm_in_order_comparator #(type T);
uvm_algorithm_comparator #(type BEFORE,type AFTER ,type TRANSFORMER);

第一个:输入输出是一个类型,直接比较。第二个:输入输出不同,因此需要一个类型转换,转变成相同的。在scoreboard中通常会声明TLM端口以供monitor传输数据。

uvm_env

从环境层次结构而言 , uvm_env可能包含多个  uvm_agent和其它 component,这些不同组件共同构成一个完整的验证环境,而这个环境在将来复用中可以作为子环境被进一步集成到更高的环境中。uvm env的角色就是一个结构化的容器,它可以容纳其它组件 ,同时它也可以作为子环境在更高层的集成中被嵌入。

 uvm_test

uvm_test类本身没有什么新成员,但是作为测试用例的代言人,它不但决定着环境的结构和连接关系,也决定着使用哪一个测试序列。 uvm_test是验证环境建立的唯一入口,只有通过它才能正常运转UVM的phase机制。在uvm_test中只例化一个顶层uvm_env,这便于提供一个唯一环境节点以形成树状的拓扑结构,而这种树状环境结朴也会对应着—种树状配置结构。

reference model

reference model和DUT完成相同的功能,reference model 的输出被scoreboard接收,用于和DUT进行比较。DUT简单,reference model就会简单,DUT复杂,reference model就会复杂

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.my_copy(tr);
      `uvm_info("my_model", "get one transaction, copy and print it:", UVM_LOW)
      new_tr.my_print();
      ap.write(new_tr);
   end
endtask

virtual interface

加入 virtual interface 的目的是为了增强验证平台的可移植性。

使用宏来避免绝对路径:

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)
   end
   @(posedge top_tb.clk);
   top_tb.rx_dv <= 1'b0;
endtask

使用interface来避免绝对路径:在类中使用的是virtual interface

task my_driver::main_phase(uvm_phase phase);
   phase.raise_objection(this);
   `uvm_info("my_driver", "main_phase is called", UVM_LOW);
   vif.data <= 8'b0; 
   vif.valid <= 1'b0;
   while(!vif.rst_n)
      @(posedge vif.clk);
   for(int i = 0; i < 256; i++)begin
      @(posedge vif.clk);
      vif.data <= $urandom_range(0, 255);
      vif.valid <= 1'b1;
      `uvm_info("my_driver", "data is drived", UVM_LOW);
   end
   @(posedge vif.clk);
   vif.valid <= 1'b0;
   phase.drop_objection(this);
endtask

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值