//
//----------------------------------------------------------------------
//   Copyright 2007-2011 Mentor Graphics Corporation
//   Copyright 2007-2011 Cadence Design Systems, Inc.
//   Copyright 2010 Synopsys, Inc.
//   All Rights Reserved Worldwide
//
//   Licensed under the Apache License, Version 2.0 (the
//   "License"); you may not use this file except in
//   compliance with the License.  You may obtain a copy of
//   the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in
//   writing, software distributed under the License is
//   distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
//   CONDITIONS OF ANY KIND, either express or implied.  See
//   the License for the specific language governing
//   permissions and limitations under the License.
//----------------------------------------------------------------------


//------------------------------------------------------------------------------
// Title: TLM Channel Classes
//------------------------------------------------------------------------------
// This section defines built-in TLM channel classes.
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
//
// CLASS: uvm_tlm_req_rsp_channel #(REQ,RSP)
//
// The uvm_tlm_req_rsp_channel contains a request FIFO of type ~REQ~ and a response
// FIFO of type ~RSP~. These FIFOs can be of any size. This channel is
// particularly useful for dealing with pipelined protocols where the request
// and response are not tightly coupled.
//
// Type parameters:
//
// REQ - Type of the request transactions conveyed by this channel.
// RSP - Type of the response transactions conveyed by this channel.
//
//------------------------------------------------------------------------------

class [docs]uvm_tlm_req_rsp_channel #(type REQ=int, type RSP=REQ) extends uvm_component;

  typedef uvm_tlm_req_rsp_channel #(REQ, RSP) this_type;

  const static string type_name = "uvm_tlm_req_rsp_channel #(REQ,RSP)";

  // Port: put_request_export
  //
  // The put_export provides both the blocking and non-blocking put interface
  // methods to the request FIFO:
  //
  //|  task put (input T t);
  //|  function bit can_put ();
  //|  function bit try_put (input T t);
  //
  // Any put port variant can connect and send transactions to the request FIFO
  // via this export, provided the transaction types match.

  uvm_put_export #(REQ) put_request_export;


  // Port: get_peek_response_export
  //
  // The get_peek_response_export provides all the blocking and non-blocking get
  // and peek interface methods to the response FIFO:
  //
  //|  task get (output T t);
  //|  function bit can_get ();
  //|  function bit try_get (output T t);
  //|  task peek (output T t);
  //|  function bit can_peek ();
  //|  function bit try_peek (output T t);
  //
  // Any get or peek port variant can connect to and retrieve transactions from
  // the response FIFO via this export, provided the transaction types match.

  uvm_get_peek_export #(RSP) get_peek_response_export;


  // Port: get_peek_request_export
  //
  // The get_peek_export provides all the blocking and non-blocking get and peek
  // interface methods to the response FIFO:
  //
  //|  task get (output T t);
  //|  function bit can_get ();
  //|  function bit try_get (output T t);
  //|  task peek (output T t);
  //|  function bit can_peek ();
  //|  function bit try_peek (output T t);
  //
  // Any get or peek port variant can connect to and retrieve transactions from
  // the response FIFO via this export, provided the transaction types match.


  uvm_get_peek_export #(REQ) get_peek_request_export;


  // Port: put_response_export
  //
  // The put_export provides both the blocking and non-blocking put interface
  // methods to the response FIFO:
  //
  //|  task put (input T t);
  //|  function bit can_put ();
  //|  function bit try_put (input T t);
  //
  // Any put port variant can connect and send transactions to the response FIFO
  // via this export, provided the transaction types match.

  uvm_put_export #(RSP) put_response_export;


  // Port: request_ap
  //
  // Transactions passed via ~put~ or ~try_put~ (via any port connected to the
  // put_request_export) are sent out this port via its write method.
  //
  //|  function void write (T t);
  //
  // All connected analysis exports and imps will receive these transactions.

  uvm_analysis_port #(REQ) request_ap;


  // Port: response_ap
  //
  // Transactions passed via ~put~ or ~try_put~ (via any port connected to the
  // put_response_export) are sent out this port via its write method.
  //
  //|  function void write (T t);
  //
  // All connected analysis exports and imps will receive these transactions.

  uvm_analysis_port   #(RSP) response_ap;


  // Port: master_export
  //
  // Exports a single interface that allows a master to put requests and get or
  // peek responses. It is a combination of the put_request_export and
  // get_peek_response_export.

  uvm_master_imp #(REQ, RSP, this_type, uvm_tlm_fifo #(REQ), uvm_tlm_fifo #(RSP)) master_export;


  // Port: slave_export
  //
  // Exports a single interface that allows a slave to get or peek requests and
  // to put responses. It is a combination of the get_peek_request_export
  // and put_response_export.

  uvm_slave_imp  #(REQ, RSP, this_type, uvm_tlm_fifo #(REQ), uvm_tlm_fifo #(RSP)) slave_export;

  // port aliases for backward compatibility
  uvm_put_export      #(REQ) blocking_put_request_export,
                             nonblocking_put_request_export;
  uvm_get_peek_export #(REQ) get_request_export,
                             blocking_get_request_export,
                             nonblocking_get_request_export,
                             peek_request_export,
                             blocking_peek_request_export,
                             nonblocking_peek_request_export,
                             blocking_get_peek_request_export,
                             nonblocking_get_peek_request_export;

  uvm_put_export      #(RSP) blocking_put_response_export,
                             nonblocking_put_response_export;
  uvm_get_peek_export #(RSP) get_response_export,
                             blocking_get_response_export,
                             nonblocking_get_response_export,
                             peek_response_export,
                             blocking_peek_response_export,
                             nonblocking_peek_response_export,
                             blocking_get_peek_response_export,
                             nonblocking_get_peek_response_export;

  uvm_master_imp #(REQ, RSP, this_type, uvm_tlm_fifo #(REQ), uvm_tlm_fifo #(RSP))
                             blocking_master_export, 
                             nonblocking_master_export;

  uvm_slave_imp  #(REQ, RSP, this_type, uvm_tlm_fifo #(REQ), uvm_tlm_fifo #(RSP))
                             blocking_slave_export, 
                             nonblocking_slave_export;
  // internal fifos
  protected uvm_tlm_fifo #(REQ) m_request_fifo;
  protected uvm_tlm_fifo #(RSP) m_response_fifo;


  // Function: new
  //
  // The ~name~ and ~parent~ are the standard <uvm_component> constructor arguments.
  // The ~parent~ must be ~null~ if this component is defined within a static
  // component such as a module, program block, or interface. The last two
  // arguments specify the request and response FIFO sizes, which have default
  // values of 1.

  function [docs]new (string name, uvm_component parent=null, 
                int request_fifo_size=1,
                int response_fifo_size=1);

    super.new (name, parent);

    m_request_fifo  = new ("request_fifo",  this, request_fifo_size);
    m_response_fifo = new ("response_fifo", this, response_fifo_size);

    request_ap      = new ("request_ap",  this);
    response_ap     = new ("response_ap", this);
            
    put_request_export       = new ("put_request_export",       this);
    get_peek_request_export  = new ("get_peek_request_export",  this);

    put_response_export      = new ("put_response_export",      this); 
    get_peek_response_export = new ("get_peek_response_export", this);

    master_export   = new ("master_export", this, m_request_fifo, m_response_fifo);
    slave_export    = new ("slave_export",  this, m_request_fifo, m_response_fifo);

    create_aliased_exports();

    set_report_id_action_hier(s_connection_error_id, UVM_NO_ACTION);

  endfunction

  virtual function void [docs]connect_phase(uvm_phase phase);
    put_request_export.connect       (m_request_fifo.put_export);
    get_peek_request_export.connect  (m_request_fifo.get_peek_export);
    m_request_fifo.put_ap.connect    (request_ap);
    put_response_export.connect      (m_response_fifo.put_export);
    get_peek_response_export.connect (m_response_fifo.get_peek_export);
    m_response_fifo.put_ap.connect   (response_ap);
  endfunction

  function void [docs]create_aliased_exports();
    // request
    blocking_put_request_export         = put_request_export;
    nonblocking_put_request_export      = put_request_export;
    get_request_export                  = get_peek_request_export;
    blocking_get_request_export         = get_peek_request_export;
    nonblocking_get_request_export      = get_peek_request_export;
    peek_request_export                 = get_peek_request_export;
    blocking_peek_request_export        = get_peek_request_export;
    nonblocking_peek_request_export     = get_peek_request_export;
    blocking_get_peek_request_export    = get_peek_request_export;
    nonblocking_get_peek_request_export = get_peek_request_export;
  
    // response
    blocking_put_response_export         = put_response_export;
    nonblocking_put_response_export      = put_response_export;
    get_response_export                  = get_peek_response_export;
    blocking_get_response_export         = get_peek_response_export;
    nonblocking_get_response_export      = get_peek_response_export;
    peek_response_export                 = get_peek_response_export;
    blocking_peek_response_export        = get_peek_response_export;
    nonblocking_peek_response_export     = get_peek_response_export;
    blocking_get_peek_response_export    = get_peek_response_export;
    nonblocking_get_peek_response_export = get_peek_response_export;
  
    // master/slave
    blocking_master_export    = master_export; 
    nonblocking_master_export = master_export;
    blocking_slave_export     = slave_export;
    nonblocking_slave_export  = slave_export;
  endfunction
  
  // get_type_name
  // -------------

  function string [docs]get_type_name ();
    return type_name;
  endfunction


  // create
  // ------
  
  function uvm_object [docs]create (string name=""); 
    this_type v;
    v=new(name);
    return v;
  endfunction


endclass


//------------------------------------------------------------------------------
//
// CLASS: uvm_tlm_transport_channel #(REQ,RSP)
//
// A uvm_tlm_transport_channel is a <uvm_tlm_req_rsp_channel #(REQ,RSP)> that implements
// the transport interface. It is useful when modeling a non-pipelined bus at
// the transaction level. Because the requests and responses have a tightly
// coupled one-to-one relationship, the request and response FIFO sizes are both
// set to one.
//
//------------------------------------------------------------------------------

class [docs]uvm_tlm_transport_channel #(type REQ=int, type RSP=REQ) 
                                     extends uvm_tlm_req_rsp_channel #(REQ, RSP);

  typedef uvm_tlm_transport_channel #(REQ, RSP) this_type;

  // Port: transport_export
  //
  // The put_export provides both the blocking and non-blocking transport
  // interface methods to the response FIFO:
  //
  //|  task transport(REQ request, output RSP response);
  //|  function bit nb_transport(REQ request, output RSP response);
  //
  // Any transport port variant can connect to and send requests and retrieve
  // responses via this export, provided the transaction types match. Upon
  // return, the response argument carries the response to the request.

  uvm_transport_imp #(REQ, RSP, this_type) transport_export;


  // Function: new
  //
  // The ~name~ and ~parent~ are the standard <uvm_component> constructor
  // arguments. The ~parent~ must be ~null~ if this component is defined within a
  // statically elaborated construct such as a module, program block, or
  // interface.

  function [docs]new (string name, uvm_component parent=null);
    super.new(name, parent, 1, 1);
    transport_export = new("transport_export", this);
  endfunction

  task [docs]transport (REQ request, output RSP response );
    this.m_request_fifo.put( request );
    this.m_response_fifo.get( response );
  endtask

  function bit [docs]nb_transport (REQ req, output RSP rsp );
    if(this.m_request_fifo.try_put(req)) 
      return this.m_response_fifo.try_get(rsp);
    else
      return 0;
  endfunction

endclass