/******************************************************************************
    Copyright (c) 1998-2000 CoWare, Inc.    ALL RIGHTS RESERVED

The following code is derived, directly or indirectly, from the SystemC
source code released by Synopsys, Inc Copyright (c) 1996-2001, Synopsys,
Inc., CoWare, Inc., Frontier Design, Inc. and others. All Rights reserved.
The contents of this file are subject to the restrictions and limitations
set forth in the SystemC Open Source License Version 2.0 (the "License");
You may not use this file except in compliance with such restrictions and
limitations. You may obtain instructions on how to receive a copy of the
License at http://www.systemc.org/.  Software distributed by Contributors
under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
ANY KIND, either express or implied. See the License for the specific
language governing rights and limitations under the License."

******************************************************************************/

/****************************************************************
    sc_protocol -- classes for protocol, protocol- interface,
		   bus-interface

    Authors
	: Harish Sarin, CoWare Inc. (harish@coware.com)
	: Cesar Quiroz, CoWare Inc. (cesar@coware.com)
	: Vijay Kumar,  CoWare Inc. (vijay@coware.com)

    MODIFICATION LOG 
    Modifier Name & Affiliation:
    Description of Modification:

****************************************************************/

#ifndef SC_PROTOCOL_H
#define SC_PROTOCOL_H

#include "sc_link_mp_b.h"




class sc_link_protocol;
typedef sc_pvector<sc_async_process_handle> proc_list;

// base class for all singleton protocols, line sc_enableHandShake etc
class sc_protocol {
 public:
	//virtual sc_protocol* instance()=0; 
	virtual sc_link_protocol* make_link_protocol(const char *NAME)=0;
};

// base class for the real protocols like sc_inm_enableHandshake etc
class sc_port_protocol {
 public:
	virtual ~sc_port_protocol() { }
	//CTOR
	sc_port_protocol(sc_protocol* p)   {
		parent=p;
		sc_port_protocol::list_of_port_protocols.push_back(this);
		ps = PORT_STATUS_UNBOUND;
		to_link = 0;
		to_port = 0;
		leaf_node=true;
	}
	
	virtual BIND_STATUS bind(sc_link_mp_b& l) {
		to_link = &l;
		ps = PORT_STATUS_BOUND_SIGNAL;
		return l.bind(*this);
	};
	virtual BIND_STATUS bind(sc_link_protocol* l) { return BIND_STATUS_OK;}
	virtual BIND_STATUS bind(sc_port_protocol& p) {
		to_port = &p;
		ps = PORT_STATUS_BOUND_PORT;
		p.leaf_node=false;
		return BIND_STATUS_OK;
	}
        sc_pport_b* get_port() { return owner_port; }
        void set_port(sc_pport_b *port) { owner_port = port; }
	sc_protocol* get_parent() { return parent; }
	bool is_leaf() { return leaf_node; }
        const char * name() const; 

	virtual void p_add_procs(sc_async_process_handle h) { }
	virtual void make_sensitive() { }
	virtual void validate() {
		if(0==to_link && 0==to_port) {
			cerr << "SystemC Error: Port `"<<name() <<"\'  is unbound"
				 << endl;
			return;
		}
		
		if(to_port) {
			while(to_port->to_port) {
				to_port=to_port->to_port;
			}
			if(0==to_port->to_link) {
				cerr << "SystemC Error: Port `"<<name() <<"\'  is unbound"
					 << endl;
				return;
			}
			bind(*to_port->to_link);  // polymorphic
			//to_link = to_port->to_link;
		}
		make_sensitive(); // polymorphic, must be single inheritance
	}

	// run through the list of port protocols and add the senstivie
	// processess to the links they are connected to.
	static void validate_all();
	static sc_pvector<sc_port_protocol* > list_of_port_protocols;
	sc_protocol *parent;
	sc_link_mp_b *to_link;  // bound to link
	sc_port_protocol *to_port; // for port to port binding
	PORT_STATUS ps;
	// list of sensitive process attached to this port
	// All processess in this list will be transferred to
	// the 'to_link' just before simulation
	proc_list * sensitive_procs;
	bool leaf_node;
	sc_pport_b *owner_port;
        virtual sc_link_protocol* make_link_protocol(const char *NAME) {
          return parent->make_link_protocol(NAME);
        }
       
};


// base class for link protocols with RPC
class sc_rpc_link_b : public sc_link_protocol {
 public:
	sc_rpc_link_b(const char *NAME);
	
	// count of masters and slaves
	int in_masters,out_masters,inout_masters,masters;
	int in_slaves,out_slaves,inout_slaves,slaves;
	bool bWritten;
	void run(proc_list& list);
	
	void run_inslave()    { run(inSlaveList); }
	void run_outslave()   { run(outSlaveList); }
	void run_inoutslave() { run(inoutSlaveList); }
	void run_slave()      { run(slaveList); }
		
	void add_to_list(sc_async_process_handle& p,proc_list& list) {
		list.push_back(p);
	}
	void add_to_inslave(sc_async_process_handle& p) {
		add_to_list(p,inSlaveList);
	}
	void add_to_outslave(sc_async_process_handle& p) {
		add_to_list(p,outSlaveList);
	}
	void add_to_inoutslave(sc_async_process_handle& p) {
		add_to_list(p,inoutSlaveList);
	}
	void add_to_slave(sc_async_process_handle& p) {
		add_to_list(p,slaveList);
	}

	bool get_direction() { return dir; }
	void set_direction(bool d) { dir=d; }

 public:
	// list of slave ports connected to the channel
	mutable proc_list inSlaveList;
	mutable proc_list outSlaveList;
	mutable proc_list inoutSlaveList;
	mutable proc_list slaveList;  // pure slave without in,out,inout
	void display_error(char *);
	static void validate_all();
	bool validate();
	static sc_pvector<sc_rpc_link_b * > list_of_rpc_links; 
		
 private:
	bool dir; // was the last operation read write?, read=false, write=true
};


#endif
