2013年5月16日 星期四

adding performance monitor to your design

the UVM monitor can play not only a functional checker but also a performance checker which means, user can use it more quickly to find out where is their design bottleneck without waveform tracing. in this topic, we focused on how to use UVM monitor to point out the collected transactions had timing violation immediately when the simulation was running.

we write a UVM SystemVerilog "req happened until grant received" to our demo case.

 
// spawn sub procs(threads)                                                                                                       
task run_phase(uvm_phase);
  fork
    sent_req();
    sent_grant();

    collected_req();
    collected_grant();

    check_performance();
    check_protocol();
  join
endtask : run_phase


// sent req 
task sent_req();

  forever begin
    // random  wait ....
    repeat($urandom_range(8,16)) @(posedge m_vif.CLK);

    // sent req 
    `delay(conf.half_cycle);
    m_vif.REQ <= `TRUE;
    @(posedge m_vif.CLK);

    // wait until grant received
    while(!m_vif.GRANT) @(posedge m_vif.CLK);

    // free req 
    `delay(conf.half_cycle);
    m_vif.REQ <= `FALSE;
    @(posedge m_vif.CLK);

  end

endtask : sent_req


// snet grant
task sent grant();

  forever begin

    // sent unvalid grant
    `delay(conf.half_cycle);
    m_vif.GRANT <= `FALSE;
    @(posedge m_vif.CLK);

    // wait until req received
    while(!m_vif.REQ) @(posedge m_vif.CLK);

    // random wait ...
    repeat($urandom_range(8,16)) @(posedge m_vif.CLK);

    // sent valid grant to free req
    `delay(conf.half_cycle);
    m_vif.GRANT <= `TRUE;
    @(posedge m_vif.CLK);

  end

endtask : sent grant                                                                                                              


task collected_req();

  forever begin
     // @ neg edge check
      @(negedge m_vif.CLK iff m_vif.REQ);

      // assert only one fifo deep when req/grant case
      assert(m_trx_q.size() < 1);

      // collect trx
      TRX m_trx = new();
      m_trx.REQ = m_vif.REQ;
      m_trx.TIME = $time;
      m_trx_q.push_back(m_trx);

  end
endtask : collected_req


task collected_grant();

  forever begin
    // @ neg edge cehck
    @(negedge m_vif.CLK iff m_vif.GRANT);

    //assert the queue size must be 1, means the req has been stored in the queue
    assert(m_trx.q.size() == 1);

    // free queue
    m_trx_q.pop_front();

  end
                                                                                                                                  
endtask : collected_grant


task check_performance();
  forever begin
    // at each pos edge check
    @(posedge m_vif.CLK);

    //assert queue
    if (m_trx_q.size() == 1) begin
        if ($time - m_trx_q[0].TIME > conf.min_offset) begin
          `uvm_error(get_full_name(), {$psprintf("out of time %d"), conf.min_offset}, UVM_LOW)
        end else begin
          `uvm_error(get_full_name(), {$psprintf("req/grant seuence is not valid")}, UVM_LOW)
        end
    end
  end

endtask             

沒有留言:

張貼留言