[SEQREQZMB] 跑reset test出现的UVM_ERROR原因及解决方法

本文详细记录了解决UVM_ERROR:[SEQREQZMB]Thetaskresponsibleforrequestingawait_for_grantonsequencer...的过程中遇到的问题及解决方法。错误源于在resettest时,sequence在仲裁队列中的状态变为KILLED,导致死锁。通过阅读UVM源码,发现可以使用`stop_sequences()`方法在reset后清除队列,从而避免错误发生。该方法有效地清除了KILLED状态的sequence,使系统恢复正常运行。

今日调试reset test时,出现了如下UVM_ERROR:

[SEQREQZMB] The task responsible for requesting a wait_for_grant on
sequencer ‘uvm_test_top.m_env.m_xxx_agent.m_sequencer’ for sequence
‘case_rstn_rand_vseq’ has been killed, to avoid a deadlock the
sequence will be removed from the arbitration queues.

在网上搜索了该ERROR的信息,发现均与将sequence强行停止有关,但并没有特别契合我的案例,总之依旧未能够找到合适的解决方法。经过自己的摸索后,解决了这个问题,因此将该过程记录下来,以便之后再遇能够快速解决。如果恰好能帮上你的忙,那将是意外收获!

出现的原因

  1. 出现error首先应当查看原代码,因此我读了一下UVM源码中该error的出处:
function int uvm_sequencer_base::m_choose_next_request();
  int i, temp;
  int avail_sequence_count;
  int sum_priority_val;
  integer avail_sequences[$];
  integer highest_sequences[$];
  int highest_pri;
  string  s;
 
  avail_sequence_count = 0;
 
  grant_queued_locks();
 
  for (i = 0; i < arb_sequence_q.size(); i++) begin
 
    if((arb_sequence_q[i].process_id.status == process::KILLED)||
       (arb_sequence_q[i].process_id.status == process::FINISHED))begin
      `uvm_error("SEQREQZMB",$sformatf("The task reponsible for requesting a wait_for_grant on sequencer '%s' for sequence '%s' has been killed,to avoid a deadlock the sequence will be removed from the arbitration queues",this,get_full_name(),arb_sequence_q[i].sequence_ptr.get_full_name))
     
      remove_sequence_from_queues(arb_sequence_q[i].sequence_ptr);
      continue;
    end
    
    //the rest content is omitted
    ...
    
endfunction

该function后续代码由于与本文讨论的问题无关,因此省略。从代码中可见,这个UVM_ERROR是由于arb_sequence_q的成员status为KILLED或FINISHED,为了避免死锁deadlock的产生,强行将该成员从queue中移除。

继续往前追溯,m_choose_next_request()这个函数在task m_select_sequence中被调用,而这个task又被task get_next_item所调用。

看到这里,问题的原因已经比较清晰:

  1. 我的case所定义的item,会进入sequencer的一个仲裁队列中。sequencer在driver要求get_next_item时,对队列中的request进行仲裁,再将request item发送给driver。
  2. 仲裁队列中的item,在reset生效时被kill掉,从而满足了该ERROR的条件。当reset释放时,driver重新要求get_next_item就会引发该UVM_ERROR。

解决的方法

sequencer在发现该ERROR后,采取了remove_sequence_from_queues的做法,将KILLED状态的item从队列中清除掉。

那么,我是否可以在reset生效后,就将队列中的item人为清除掉,从而避免该UVM_ERROR的产生呢?

于是,查看UVM sequencer的源码,其提供了如下的方法:

// Function- stop_sequences
//
// Tells the sequencer to kill all sequences and child sequences currently
// operating on the sequencer, and remove all requests, locks and responses
// that are currently queued.  This essentially resets the sequencer to an
// idle state.
//
function void uvm_sequencer::stop_sequences();
  REQ t;
  super.stop_sequences();
  sequence_item_requested  = 0;
  get_next_item_called     = 0;
  // Empty the request fifo
  if (m_req_fifo.used()) begin
    uvm_report_info(get_full_name(), "Sequences stopped.  Removing request from sequencer fifo");
    while (m_req_fifo.try_get(t));
  end
endfunction

这个方法可以同时完成将sequences kill掉并从队列中remove的行为。

的确,这样做之后这个UVM_ERROR不再出现了。

`ifndef TC_UART_TEST_CASE2 `define TC_UART_TEST_CASE2 class uart_test_case2_seq extends uart_base_seq; string class_name; int debug_flg; int PKG_NUM; int PKG_SUM = 1; `uvm_object_utils(uart_test_case2_seq) uart_seq_item uart_act; write_word_seq write_word; read_word_seq read_word; extern function new(string class_name = "uart_test_case2_seq", uvm_component parent = null); extern task body(); endclass function uart_test_case2_seq::new(string class_name = "uart_test_case2_seq", uvm_component parent = null); super.new(class_name); endfunction task uart_test_case2_seq::body(); int timer; uart_seq_item req; uvm_report_info("uart_test_case2_seq", "-----------------uart_test_case2_seq start------------------", UVM_LOW); uart_act = uart_seq_item::type_id::create("uart_act"); get_starting_phase.raise_objection(this, {"Running sequence ", get_full_name(), ""}); repeat (PKG_SUM) begin PKG_NUM++; fork begin: run_work uvm_report_info("uart_test_case2_seq", "-----------------uart_test_case2_seq run work start!------------------", UVM_LOW); //uart_sequencer.uart_sqr.uart_intf.presetn = 1; //`uvm_do_on_with(write_word, p_sequencer.bus_sqr, {addr == 32'h0000_0004; data == 32'h1234_5678;}) // `uvm_do_on_with(read_word, p_sequencer.bus_sqr, {addr == 32'h0000_0004;}) //`uvm_do_on_with(read_word, p_sequencer.bus_sqr, {addr == 32'hc;}) uvm_report_info("uart_test_case2_seq", "-----------------uart_test_case2_seq run work end!------------------", UVM_LOW); disable wdt_time; end begin: wdt_time uvm_report_info("uart_test_case2_seq", "-----------------uart_test_case2_seq wdt time start!------------------", UVM_LOW); timer = 0; while (1) begin #1ns; timer = timer + 1; if (timer % 1_000_000 == 0) begin `uvm_info("uart_test_case2_seq", $psprintf("===========%0d CLK PASS! ============", timer), UVM_LOW); end if (timer == 10_000_00000) begin show_result(PKG_NUM, 1); break; end end disable run_work; uvm_report_info("uart_test_case2_seq", "-----------------uart_test_case2_seq wdt time end!------------------", UVM_LOW); end join `uvm_info("uart_test_case2_seq", $psprintf("===========PKG NUM is %0d PASS! ============", PKG_NUM), UVM_LOW); end get_starting_phase.drop_objection(this, {"Completed sequence ", get_full_name(), ""}); uvm_report_info("uart_test_case2_seq", "-----------------uart_test_case2_seq end------------------", UVM_LOW); endtask: body class tc_uart_test_case2 extends uart_case_base; string class_name; int debug_flg; `uvm_component_utils(tc_uart_test_case2) uart_test_case2_seq uart_seq; function new(string class_name = "tc_uart_test_case2", uvm_component parent = null); super.new(class_name, parent); this.debug_flg = 0; this.class_name = class_name; endfunction function void build_phase(uvm_phase phase); super.build_phase(phase); uvm_config_db#(uvm_object_wrapper)::set(this, "env.uart_vsqr.main_phase", "default_sequence", uart_test_case2_seq::type_id::get()); endfunction endclass `endif我想测Presetn复位后,寄存器应回到默认值
最新发布
07-08
评论 10
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值