//------------------------------------------------------------------------------
// Copyright 2008 Mentor Graphics Corporation
// 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: OVM Producers
//
// This file defines the following OVM producer components.
//
//------------------------------------------------------------------------------


//------------------------------------------------------------------------------
//
// Group: ovm_producer
//
// Generic generator, inheriting from ovm_random_stimulus #(T), that produces
// transactions of the parameterized type, T, and puts them out the inherited
// blocking put port.
//
// This class extends ~ovm_random_stimulus~ by providing the ability for users
// to specify the number and type of transactions produced. It also implements
// the run task to start generating stimulus without need for an explicit call
// ~generate_stimulus~.
//------------------------------------------------------------------------------

// (begin inline source)
class ovm_producer #(type T=int) extends ovm_random_stimulus #(T);

  typedef ovm_producer #(T) this_type;

  `ovm_component_param_utils(this_type)

  // Function: new
  //
  // Creates a new instance of ~ovm_producer~.

  function new (string name, ovm_component parent);
     super.new(name,parent);
  endfunction

  // The object to produce; can be any extension of T.
  T prototype;

  // The number of transactions to generate
  int num_trans=5;

  // Function: build
  // 
  // Grabs any config settings for the number of transactions
  // to generate and the particular extension of the transaction
  // type to generate.

  virtual function void build();
    ovm_object obj;
    void'(get_config_int("num_trans",num_trans));
    void'(get_config_object("prototype",obj));
    if (!$cast(prototype,obj))
      ovm_report_error("Bad Object",
          "configured prototype not compatible");
  endfunction

  // Task: run
  //
  // Calls ~generate_stimulus~ from the base class to
  // produce ~num_trans~ transactions of a type given
  // by ~prototype~.

  virtual task run();
    super.run();
    generate_stimulus(prototype,num_trans);
  endtask
  
  const string type_name = {"ovm_producer #(",T::type_name,")"};

  virtual function string get_type_name();
    return type_name;
  endfunction

endclass
// (end inline source)



//----------------------------------------------------------------------------------
//
// Group: ovm_publish
//
// Uses an ~ovm_analysis_port~ to broadcast transactions to all its subscribers.
//
//----------------------------------------------------------------------------------

// (begin inline source)
class ovm_publish #(type T=int) extends ovm_component;

   typedef ovm_publish #(T) this_type;
  `ovm_component_utils(this_type)

  // Port: out
  //
  // This component uses this analysis port to publish transactions.

  ovm_analysis_port #(T) out;


  // Function: new
  //
  // Creates a new instance of ~ovm_pubish~.

  function new(string name, ovm_component parent=null);
    super.new(name,parent);
    out = new("out",this);
  endfunction

  virtual task run();
    T t;
    t = new();
    assert(t.randomize());
//    #0;
    ovm_report_info("publishing", t.convert2string());
    out.write(t);
  endtask

endclass
// (end inline source)

//------------------------------------------------------------------------------
//
// Group: ovm_blocking_transport_producer
//
//------------------------------------------------------------------------------

// (begin inline source)
class ovm_blocking_transport_producer extends ovm_component;

  typedef ovm_blocking_transport_producer this_type;

  `ovm_component_param_utils(this_type)

  ovm_blocking_transport_port #(ovm_apb_rw, 
                                ovm_apb_rw) blocking_transport_port;

  // Function: new
  //
  // Creates a new instance of ~ovm_producer~.

  function new (string name, ovm_component parent);
     super.new(name,parent);
     blocking_transport_port=new("blocking_transport_port", this);
  endfunction

  // The object to produce; can be any extension of ovm_apb_rw.
  ovm_apb_rw prototype;

  // The number of transactions to generate
  int num_trans=5;

  // Function: build
  // 
  // Grabs any config settings for the number of transactions
  // to generate and the particular extension of the transaction
  // type to generate.

  virtual function void build();
    ovm_object obj;
    void'(get_config_int("num_trans",num_trans));
    void'(get_config_object("prototype",obj));
    if (!$cast(prototype,obj))
      `OVM_REPORT_ERROR("Bad Object",
          "configured prototype not compatible");
  endfunction

  // Task: run
  //
  // Calls ~generate_stimulus~ from the base class to
  // produce ~num_trans~ transactions of a type given
  // by ~prototype~.

  virtual task run();
    int rsp_num;
    ovm_apb_rw req, rsp;
    super.run();
    rsp_num=0;
    for (int i=0; i<num_trans; i++) begin
      #10;
      req=new(); 
      assert(req.randomize() with {req.cmd==ovm_apb_rw::RD;});
      fork
      begin
        ovm_report_info("ovm_producer", $psprintf("Send #%0d req transaction\n%s", i, req.convert2string()));
        blocking_transport_port.transport(req, rsp);
        ovm_report_info("ovm_producer", $psprintf("Get #%0d rsp transaction\n%s", rsp_num, rsp.convert2string()));
        rsp_num++;
      end
      join_none
    end
  endtask
  
  const string type_name = {"ovm_blocking_transport_producer #(",ovm_apb_rw::type_name,")"};

  virtual function string get_type_name();
    return type_name;
  endfunction

endclass
// (end inline source)

//------------------------------------------------------------------------------
//
// Group: ovm_passive_producer
//
//------------------------------------------------------------------------------

// (begin inline source)
class ovm_passive_producer #(type T=int) extends ovm_component ;

  typedef ovm_passive_producer #(T) this_type;

  `ovm_component_param_utils(this_type)

  //ovm_blocking_get_peek_imp #(T, T) get_peek_export;
  ovm_blocking_get_peek_imp #(T, this_type) get_peek_export;
  ovm_analysis_imp #(T, this_type) analysis_export;
  event get_request_e;

  // Function: new
  //
  // Creates a new instance of ~ovm_producer~.

  function new (string name, ovm_component parent);
     super.new(name,parent);
     get_peek_export=new("get_peek_export", this);
     analysis_export=new("analysis_export", this);
  endfunction

  // The object to produce; can be any extension of T.
  T prototype;

  // The number of transactions to generate
  int num_trans=5;

  // Function: build
  // 
  // Grabs any config settings for the number of transactions
  // to generate and the particular extension of the transaction
  // type to generate.

  virtual function void build();
    ovm_object obj;
    void'(get_config_int("num_trans",num_trans));
    void'(get_config_object("prototype",obj));
    if (!$cast(prototype,obj))
      `OVM_REPORT_ERROR("Bad Object",
          "configured prototype not compatible");
  endfunction

  // Task: run
  //
  virtual task run();
    super.run();
  endtask

  virtual task get(output T obj);
    this.peek(obj);
    prototype = null;
  endtask

  virtual task peek(output T obj);
    bit s;
      wait(prototype != null)
      obj = prototype;
  endtask
      
  virtual function void write(T obj);
    bit s;
    if (obj.cmd == ovm_apb_rw::RD)
      obj.data = 32'hdeadbeef;   
    prototype=obj;
  endfunction
  const string type_name = {"ovm_passive_producer #(",T::type_name,")"};

  virtual function string get_type_name();
    return type_name;
  endfunction

endclass
// (end inline source)

