UVM: Driver和Sequencer之间的握手机制(二)

UVM: Driver和Sequencer之间的握手机制(二)seq_item_port的方法Driver应该使用uvm_seq_item_pull_port内含的多种方法实现sequence->sequencer->driver的数据传输以及driver->sequence的反馈机制:taskget_next_item(outputREQreq_arg):采取blocking的方式等待从sequence获取下一个item。…

大家好,欢迎来到IT知识分享网。

seq_item_port的方法

Driver应该使用uvm_seq_item_pull_port内含的多种方法实现sequence->sequencer->driver的数据传输以及driver->sequence的反馈机制:

  • task get_next_item(output REQ req_arg):采取blocking的方式等待从sequence获取下一个item。
  • task try_next_item(output REQ req_arg):采取nonblocking的方式从sequencer获取item,如果立即返回的结果req_arg为null,则表示sequence还没有准备好。
  • function void item_done(input RSP rsp_arg=null):用来通知sequence当前的sequence
    item已经消化完毕,可以有选择性地传递RSP参数,返回状态值。
  • task wait_for_sequences():等待当前的sequence直到产生下一个有效的item。
  • function bit has_do_available():如果当前的sequence准备好而且可以获取下一个有效的item,则返回1,否则返回0。
  • function void put_response(input RSP rsp_arg):采取nonblocking方式发送response,如果成功返回1,否则返回0。
  • task get(output REQ req_arg):采用get方式获取item。
  • task peek(output REQ req_arg):采用peek方式获取item。
  • task put(input RSP rsp_arg):采取blocking方式将response发送回sequence。

driver可以进行哪些操作

uvm_driver实际上是一个具有TLM通信端口的uvm_component的子类,用来与Sequencer进行通信,将Sequence产生transaction通过Interface发送给DUT,需要时也会将transcation反馈给Sequence。

uvm_driver具有两个参数,一个request另一个是response,默认情况下这两个参数的类型是一致的,一般会被指定为用户定义的transaction类型。这两个参数也是uvm_driver自带的seq_item_port的参数类型。

在这里插入图片描述

如上所示,Driver与Sequencer进行通信主要就是依靠uvm_seq_item_pull_port派生的TLM端口seq_item_port的上述多种方法。所以其实也可以不用uvm_driver来派生Driver,只需要在Driver中自行定义seq_item_port并指定好参数类型,并与Sequencer的seq_item_export连接,进而调用seq_item_port的方法即可。

Driver调用get_next_item()时,Sequencer中的FIFO会Pop出一个transaction送给Driver,Driver将这个transaction的数据驱动给DUT后,需要和Sequence达成握手,告诉它这笔transaction已经使用完了,可以发送下一个transaction了(否则sequence会阻塞在`uvm_do或finish_item等指令上),所以它会调用seq_item_port的item_done()函数。

注意到item_done其实是一个参数类的函数,参数类型为RSP,这个是Driver和Sequence之间反馈所需要使用的。如果不加入输入参数,sequence就不会收到response。

Sequence可以进行哪些操作

Sequence是uvm_sequence的子类,它同样是参数化的类,一个参数是REQ,对应发送的transaction的类型,一个是RSP,对应Driver反馈的transaction类型,一般来说两种相同。

Sequence在与Driver的通信中负责发送transaction。很多Sequence使用`uvm_do等系列宏来操作,uvm_do宏实际上是将transaction的实例化、随机化、start_item、finish_item放在了一个操作里。其中最主要的是start_item,和finish_item任务,它们实际上又是由以下方法组成:
在这里插入图片描述
所以Sequence操作细分入下:

  • 创建item
  • 通过start_item(),等待获得sequence的授权许可,其后执行parent sequence的方法pre_do()。
  • 对item进行随机化处理
  • 通过finish_item(),在对item进行了随机化处理之后,执行parentsequence的mid_do(),以及调用uvm_sequencer::send_request()和uvm_sequencer::wait_for_item_done()来将item发送至sequencer再完成与driver之间的握手。最后,执行了parent_sequence的post_do()。

从上面可以看出其实也可以不用start_item和finish_item,直接使用send_request(item)等方法来达成通信。

使用get()和put()完成通信

在这里插入图片描述
上面提到Driver使用get_next_item()获得item,使用item_done()通知sequence使用完成。此外还有使用get()和put()达成接收transaction和反馈的操作:
在Driver中:

class my_driver extends uvm_driver #(my_data);
   `uvm_component_utils (my_driver)
 
   virtual task run_phase(uvm_phase phase);
      super.run_phase(phase);
 
    // 1. Get an item from the sequencer using "get" method
      seq_item_port.get(req);
 
    // 2. For simplicity, lets assume the driver drives the item and consumes 20ns of simulation time
      #20;
 
    // 3. After the driver is done, assume it gets back a read data called 8'hAA from the DUT
    // Assign the read data into the "request" sequence_item object
      req.data = 8'hAA;
 
    // 4. Call the "put" method to send the request item back to the sequencer
      seq_item_port.put(req);
   endtask
endclass

在Sequence中:

class my_sequence extends uvm_sequence #(my_data);
  `uvm_object_utils (my_sequence)
 
  // Create a sequence item object handle to store the sequence_item contents
  my_data tx;
 
  virtual task body();
    // 1. Create the sequence item using standard factory calls
    tx = my_data::type_id::create("tx");
 
    // 2. Start this item on the current sequencer
    start_item(tx);
 
    // 3. Do late randomization since the class handle pointers are the same
    tx.randomize();
 
    // 4. Finish executing the item from the sequence perspective
    // The driver could still be actively driving and waiting for response
    finish_item(tx);
 
    // 5. Because "finish_item" does not indicate that the driver has finished driving the item,
    // the sequence has to wait until the driver explicitly tells the sequencer that the item is over
    // So, wait unitl the sequence gets a response back from the sequencer.
    get_response(tx);
 
    `uvm_info ("SEQ", $sformatf("get_response() fn call done rsp addr=0x%0h data=0x%0h, exit seq", tx.addr, tx.data), UVM_MEDIUM)
  endtask
endclass 

首先在Driver中使用get()方法从Sequencer中获得了transaction,并进行了处理(比如驱动DUT)。事实上get()和get_next_item()的区别在于get()中调用了item_done()函数,所以可以发现在上面的代码中,get到了transaction后并没有item_done()操作。使用get()后,在Sequence中finish_item也紧接着结束。可以查看https://www.chipverify.com/uvm/driver-using-get-and-put中的举例的运行结果进行验证。

之后再使用put()方法将处理完的req返回给Sequence。需要注意两点:put()与put_response()的区别是,put()是阻塞的,而put_response()是非阻塞的,并且前者是任务,后者是由返回值的函数;此外上面代码中put()的反馈回去的参数是req,也是接收的transaction,实际上一般使用rsp,这会在下面的内容中讨论。

在Sequence中,其它部分和之前一样,主要差别是使用了get_response方法获得反馈的transaction,这是一个阻塞的方法,只有成功的获得返回数据后,它才会结束阻塞。

所以使用get()和put()加上get_response()建立的sequence->sequencer->driver通信主要是为了反馈机制。这种情况下,一个item的周期始于item creat,结束于get_response()。

response机制:Driver->Sequence的反馈

在这里插入图片描述
uvm_driver有两个参数,第一个是用户定义的transaction类型REQ,第二个是RSP,并且uvm_driver中分别定义了REQ和RSP的对象req和rsp。 req通常用作从Sequencer那里接收到的transaction,而rsp则是作为反馈回去的transaction。而且REQ和RSP默认是相同的类型,除非另外声明。

能够进行反馈的是seq_item_port的三个方法:item_done(input RSP rsp_arg), put_response(input RSP rsp_arg), put(input RSP rsp_arg)。其实从它们的参数上就可以看出只有这三种方法才能返回item给Sequence。

在Sequence中就只有一种方法获得返回的item: get_response()。

 seq_item_port.get_next_item(req);

     $cast(rsp,req.clone());

     drive_one_pkt(req); 

     rsp.set_id_info(req);//回response 一定要加上这句!!!

     seq_item_port.put(rsp);

     seq_item_port.item_done();
--------------------- 
  • 在多个sequence同时向sequencer发送item时,就需要有ID信息表明该item从哪个sequence来,这个ID信息在sequence创建item时就赋值了,而在到达driver以后,这个ID也能用来跟踪它的sequence信息

  • 如果使用rsp作为response的话,一定要加上rsp.set_id_info(req)这句,这个方法会将req中的信息复制给rsp,包括id信息。由于可能存在多个Sequence在同一个Sequencer上启动的情况,只有设置了rsp的id等信息,sequencer才知道将response返回给哪个Sequence。实际上这句话也可以用下面的代码替代:

    void’($cast (rsp, req.clone( ));
    rsp.set_sequence_id (req.get_sequence_id ( ));

  • response的机制原理是driver将rsp推送给Sequencer,而Sequencer内部维持一个队列,当有新的response进入时,就推入此队列,Sequence中的get_response()就是从这个队列中取出返回数据。这个队列的大小为8,当只有put的情况而没有get情况下,队列中存满了8个response时,会发出溢出错误提示。

  • 有时为了“简便”,会直接使用req作为反馈给Sequence的response transaction,这样做的好处是不用做set_id_info操作,也不用声明rsp。这么做看来,似乎节能环保,但实际上殊不知可能埋下隐患,一方面它延长了本来应该丢进垃圾桶的request item寿命,同时也无法再对request item原始生成数据做出有效记录。

  • 此外还能使用uvm_dirver中自带的rsp_port和uvm_sequence中对应的rsp_export来达成反馈机制。

参考文献:

https://www.chipverify.com/uvm/driver-using-get-and-put
https://blog.csdn.net/qq_41394155/article/details/82112632?utm_source=blogxgwz8
https://blog.csdn.net/qq_41394155/article/details/82112540
http://blog.sina.com.cn/s/blog_13f7886010102x39f.html
https://blog.csdn.net/lbt_dvshare/article/details/80633839

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/23563.html

(0)

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

关注微信