[UVM] kill sequence

 

默认条件下,stop_sequence 会递归kill 掉子sequence,前提是已经建立了父子关系。

如何建立sequence的父子关系呢?

    1. 使用uvm_do/uvm_do_on启动sequence(自动建立父子关系);

    2. 如果使用start启动sequence,则需要手动指定parent_sequence;

   

         virtual task start (uvm_sequencer_base sequencer,  

                                      uvm_sequence_base    parent_sequence = null,

                                       int                                  this_priority = -1,

                                       bit                                  call_pre_post = 1     )

          

   

  my_seq.start(null,this);

 

 在调用stop_sequences 时要注意两点:

     1. 如果stop_sequences 在get_next_item 和 item_done 之间调用,则会导致error,

         建议使用下述方法,即等当前txn回完item_done再调用stop_sequence.

     2. 调用stop_sequences时最好把driver中当前get_next_item进程kill掉;否则可能导致error

       

         i.e.

             "The task responsible for requesting a wait_for_grant on sequencer for sequence 

         has been killed, to avoid a deadlock the sequence will be removed from the arbitration queues"

       上述error 是由于在do item 时会把request放入the arbitration queues,而call get_next_item时会查看request的进程是否被kill,若kill则报error;

      wait_for_grant 与get_next_item是两个并行的进程,request放入the arbitration queuescall get_next_itemstop_sequences三者可能会在同一时间发生,当request放入the arbitration queues后,在call get_next_item 过程中stop_sequences 就会导致上述error。

     

上述error在uvm -1.1c中才加进来的判断,在调用get_next_item时会间接调用到m_choose_next_request这个function,从而引入上述error。

---------------------------------------------------------------------------------------------------------------------------------

solution 1

   要从两方面入手:

  •     driver 端:当reset=0时,kill 当前driver 进程后要保证当前这笔transaction 的item_done回完;
  •    sequence端:当reset=0时,等收到当前这笔transaction 的item_done之后kill sequence;

   PS: 要保证是先kill 当前driver进程后再stop_sequence.

方案1:(等driver和sequencer handshake 完成再kill sequence)

//Sequence  

class idles_transmit extends uvm_sequence #(REQ= packet); 

     bit received_item_done; 

 

    virtualfunction void mid_do (uvm_sequence_itemthis_item);

        received_item_done=0;

    endfunction

 

    virtualfunction void post_do (uvm_sequence_itemthis_item);

       received_item_done=1;

   endfunction

 

   task body(); 

       `uvm_do(req)

         //wait_for_grant(); 

        //assert(req.randomize()); 

       //send_req(req); 

       //received_item_done = 0; 

       //wait_for_item_done(); 

      //received_item_done = 1; 

   endtask 

endclass 

------------------------------------------------------------------------------------------------------------- 

//Test 

begin 

      fork 

          begin 

             wait(rtl_linkup == 1); 

          end 

          forever begin

              idles_transmit.start(Sequencer);

          end 
     join_any 

     @(posedge idles_transmit.received_item_done); //收到当前txn的item_done

     disable fork; 

     Sequencer.stop_sequences(); 

end

------------------------------------------------------------------------------------------------------------------

driver :

virtual task main_phase(uvm_phase phase);

  forever begin
    fork
      wait(intf.rst_n === 1'b0);
      send_to_dut(phase);
    join_any
    disable fork;

    if(intf.rst_n ===1'b0)begin
      
      if((interrupt_flag1 == 1'b1) && (interrupt_flag2 == 1'b0))begin//reset时当前这边txn的item_done没有回
        seq_item_port.item_done();
      end
      reset_output();
      @(posedge intf.clk);
    end

    interrupt_flag1 == 1'b0;
    interrupt_flag2 == 1'b0;
  end

endtask

 

virtual task reset_output();
  wait(intf.rst_n === 1'b0);
  intf.irq_status <= 'd0;
  intf.valid      <= 'd0;
  wait(intf.rst_n === 1'b1);
endtask


virtual task send_to_dut(uvm_phase phase);
  seq_item_port.get_next_item(req);
  interrupt_flag1 = 1'b1;
  
  send(req);
  seq_item_port.item_done();
  interrupt_flag2 = 1'b1;

endtask

solution 2:(直接kill 进程)

  driver端:

virtual task main_phase(uvm_phase phase);

  forever begin
    fork
      wait(intf.rst_n === 1'b0);
      send_to_dut(phase);
    join_any
    disable fork;

    if(intf.rst_n ===1'b0)begin
      reset_output();
  
      wait(intf.rst_n ===1'b1);
      @(posedge intf.clk);
    end

  end

endtask

sequence 端

virtual task body();//L3 seq

  fork
    `uvm_do_on(slv_seq,slv_sqr) //slave sequence 无需reset
    reset_setting();//do reset sequence
  join_none


  fork
    begin
      fork
        `uvm_do(single_scenario_seq)// main sequence !!!!!!一定是最外层的seq,比如L2 SEQ
        wait(glb_cfg.irq_vif.rst_n === 1'b0);
      join_any
      disable fork;              //kill sequence进程(针对多次do sequence场景) 

      if(glb_cfg.irq_vif.rst_n === 1'b0)begin
        #0.01ns;                   //保证driver进程先kill              
        irq_sqr.stop_sequences();  //清空arb_sequence_q ,其他临时变量回到初始状态,kill当前sequence进程
        ral_model.reset();         //针对下Rigiser的场景
      end

    end
  join
  
  if(glb_cfg.irq_vif.rst_n === 1'b0)
    `uvm_do(single_scenario_seq)
endtask

kill `uvm_do(single_scenario_seq)进程导致seq 直接完成了body task,进而调用uvm_sequencer_base::remove_sequence_from_queues 函数 ,该函数会check arb_sequence_q是否empty,如果不为空,会判断是否descendent sequence item are processed but parent sequence has finished.进而报uvm_error.

//此函数会再body函数结束后调用
function void uvm_sequencer_base::m_sequence_exiting(uvm_sequence_base sequence_ptr);
  remove_sequence_from_queues(sequence_ptr);
endfunction


//此函数会再调用stop_sequences时调用
function void uvm_sequencer_base::kill_sequence(uvm_sequence_base sequence_ptr);
  remove_sequence_from_queues(sequence_ptr);
  sequence_ptr.m_kill();  //kill body task 进程
endfunction
function void uvm_sequencer_base::remove_sequence_from_queues(
                                       uvm_sequence_base sequence_ptr);
  int i;
  int seq_id;
  
  seq_id = sequence_ptr.m_get_sqr_sequence_id(m_sequencer_id, 0);
  
  // Remove all queued items for this sequence and any child sequences
  i = 0;
  do 
    begin
      if (arb_sequence_q.size() > i) begin
        if ((arb_sequence_q[i].sequence_id == seq_id) ||
            (is_child(sequence_ptr, arb_sequence_q[i].sequence_ptr))) begin
          if (sequence_ptr.get_sequence_state() == FINISHED)//m_sequence_state
            `uvm_error("SEQFINERR", $psprintf("Parent sequence '%s' should not finish before all items from itself and items from descendent sequences are processed.  The item request from the sequence '%s' is being removed.", sequence_ptr.get_full_name(), arb_sequence_q[i].sequence_ptr.get_full_name()))
          arb_sequence_q.delete(i);
          m_update_lists();
        end
        else begin
          i++;
        end
      end
    end
  while (i < arb_sequence_q.size());
...

 

记得disable fork 的是最外层的sequence ,这样可以直接终止start task进程,不会执行body之后的m_sequence_exiting,否则会遇到上述问题 !!!!!


如果是以下场景:

//L2 seq

virtual task body();

  hw_related_seq = l1_hw_related_vseq::type_id::create("hw_related_seq");
  hw_related_seq.randomize() with {};
  hw_related_seq.start(null,this);

  fork 
    hw_related_seq.sw_tick_setting();
  join_none

  ....
  //do other HW RG seq
endtask

run time reset时,可能也会导致:

由于调用stop_sequences 进而调用到uvm_sequencer_base::remove_sequence_from_queues 函数 ,该函数会check arb_sequence_q是否empty,如果不为空,会判断是否descendent sequence item are processed but parent sequence has finished.进而报uvm_error.

root cause :

         上述code中hw_related_seq start task 执行完后m_sequence_state = FINISHED,但后面仍然在调用它的task(sw_tick_setting,读写register),此时如果调用stop_sequences,子seq(读写register)还存在但parent seq已经被kill.

solution : 

         在调用sw_tick_setting之前,create hw_related_seq。

//L2 seq

virtual task body();

  hw_related_seq = l1_hw_related_vseq::type_id::create("hw_related_seq");
  hw_related_seq.randomize() with {};
  hw_related_seq.start(null,this);

  hw_related_seq = l1_hw_related_vseq::type_id::create("hw_related_seq");
  fork 
    hw_related_seq.sw_tick_setting();
  join_none

  ....
  //do other HW RG seq
endtask

第二种出现此种error的场景:

  

l2_seq:

   task body();
     fork 
       begin
         `uvm_do_on(l1_seq,sqr_1)
       end
       begin
         wait(rst_n === 1'b0);
       end
     join_any
     disable fork;//当reset时,l1_seq 被kill,该body函数结束
   endtask


l3_seq:

    task body();
      fork 
        l2_seq.start(null);
        `uvm_do_on(rst_seq,rst_sqr)
      join_any
      disable fork;
    endtask

当 reset active时l2_seq的body函数就结束了,此时该sequence的state会变为FINISHED,进入m_sequnce_exiting执行remove_seuqence_from_request

solution:

l2_seq:

   task body();
     
       begin
         `uvm_do_on(l1_seq,sqr_1)
       end

   endtask


l3_seq:

    task body();
      fork
        `uvm_do_on(rst_seq,rst_sqr)
      join_none
      fork
        fork 
          l2_seq.start(null);
          wait(rst_n === 1'b0);
        join_any
        disable fork;
      join
    endtask

disable fork 的是最外层的sequence ,这样可以直接终止start task进程,不会执行body之后的m_sequence_exiting

 

  • 15
    点赞
  • 95
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值