Wednesday, July 1, 2015

UVM: how driver analysis port connect and write data to scoreboard port

 1) Create an uvm_analysis_port in driver or monitor. The uvm_analysis_port is inherited from uvm_port_base which extends uvm_tlm_if_base.
class uart_driver extends uvm_driver #(uart_transaction); uvm_analysis_port #(uart_transaction) drv2sb_port;
endclass

class uvm_analysis_port # (type T = int)
  extends uvm_port_base # (uvm_tlm_if_base #(T,T));
endclass

virtual class uvm_port_base #(type IF=uvm_void) extends IF;
endclass

2) Use macro uvm_analysis_imp_decl(SFX) to define a new uvm_analysis_imp class in scoreboard and then create an object of the class in the scoreboard. uvm_analysis_imp extends the class uvm_port_base.
`uvm_analysis_imp_decl(_rcvd_uart)
class uart_scoreboard extends uvm_scoreboard; uvm_analysis_imp_sent_uart #(uart_transaction, uart_scoreboard) drv2sb_port;
endclass

`define uvm_analysis_imp_decl(SFX) \
class uvm_analysis_imp``SFX #(type T=int, type IMP=int) \
 extends uvm_port_base #(uvm_tlm_if_base #(T,T)); \
 ...\
 \
 endclass

3) In the uvm_env, connect the driver uvm_analysis_port with scoreboard uvm_analysis_imp port.
In uvm_analysis_port, which is inherited from uvm_port_base, function resolve_bindings will automatically be called just before the start of the end_of_elaboration phase, which will add the scoreboard port in the list m_imp_list.
class uart_env extends uvm_env; uart_agent uart_agt;
uart_scoreboard uart_sb;
function void connect_phase(uvm_phase phase);
  super.connect_phase(phase);
  uart_agt.uart_drv.drv2sb_port.connect(uart_sb.drv2sb_port);
endfunction endclass

virtual class uvm_port_base #(type IF=uvm_void) extends IF;

  virtual function void connect (this_type provider);
                     ...
      m_provided_by[provider.get_full_name()] = provider;
      provider.m_provided_to[get_full_name()] = this;

  endfunction

  local function void m_add_list           (this_type provider);
    string sz;
    this_type imp;

    for (int i = 0; i < provider.size(); i++) begin
      imp = provider.get_if(i);
      if (!m_imp_list.exists(imp.get_full_name()))
        m_imp_list[imp.get_full_name()] = imp;
    end

  endfunction

  virtual function void resolve_bindings();
    if (m_resolved) // don't repeat ourselves
     return;

    if (is_imp()) begin
      m_imp_list[get_full_name()] = this;
    end
    else begin
      foreach (m_provided_by[nm]) begin
        this_type port;
        port = m_provided_by[nm];
        port.resolve_bindings();
        m_add_list(port);
      end
    end
                    ...
  endfunction

endclass

4) In the running phase, when driver call the write function of the uvm_analysis_port, it will go through all it's connected ports when connected in uvm_env and call the write function of the uvm_analysis_imp``SFX, which will call the m_imp.write``SFX( t) function in the scoreboard. In the example below m_imp.write``SFX( t) is write_sent_uart function.
class uart_driver extends uvm_driver #(uart_transaction);
forever begin
uart_transaction uart_tr; seq_item_port.get_next_item(uart_tr);          drv2sb_port.write(uart_tr); end
endtask endclass

class uvm_analysis_port # (type T = int)
  extends uvm_port_base # (uvm_tlm_if_base #(T,T));
                            ...
  function void write (input T t);
    uvm_tlm_if_base # (T, T) tif;
    for (int i = 0; i < this.size(); i++) begin
      tif = this.get_if (i);
      if ( tif == null )
        uvm_report_fatal ("NTCONN", {"No uvm_tlm interface is connected to ", get_full_name(), " for executing write()"}, UVM_NONE);
      tif.write (t);
    end
  endfunction

endclass

virtual class uvm_port_base #(type IF=uvm_void) extends IF;
  function int size ();
    return m_imp_list.num();
  endfunction

  function uvm_port_base #(IF) get_if(int index=0);
    string s;
    if (size()==0) begin
      m_comp.uvm_report_warning("get_if",
        "Port size is zero; cannot get interface at any index", UVM_NONE);
      return null;
    end
    if (index < 0 || index >= size()) begin
      $sformat(s, "Index %0d out of range [0,%0d]", index, size()-1);
      m_comp.uvm_report_warning(s_connection_error_id, s, UVM_NONE);
      return null;
    end
    foreach (m_imp_list[nm]) begin
      if (index == 0)
        return m_imp_list[nm];
      index--;
    end
  endfunction

endclass

`define uvm_analysis_imp_decl(SFX) class uvm_analysis_imp``SFX #(type T=int, type IMP=int) \
  extends uvm_port_base #(uvm_tlm_if_base #(T,T)); \        `UVM_IMP_COMMON(`UVM_TLM_ANALYSIS_MASK,`"uvm_analysis_imp``SFX`",IMP) \
  function void write( input T t); \
  m_imp.write``SFX( t); \
  endfunction \
  \
 endclass
`uvm_analysis_imp_decl(_rcvd_uart)

class uart_scoreboard extends uvm_scoreboard;


uvm_analysis_imp_sent_uart #(uart_transaction, uart_scoreboard) drv2sb_port;
    $cast(cb_uart_tr, uart_tr.clone());
endfunction
virtual function void write_sent_uart(input uart_transaction uart_tr);


endclass


No comments:

Post a Comment