inline void MOESIF_protocol::do_cache_I (Mreq *request)
{
	switch (request->msg) {
    /* In I, we simply initiate the transition to either S or M 
	*/
    case LOAD:
		send_GETS(request->addr);
		state = MOESIF_CACHE_IS;
		/* This is a cache miss */
		Sim->cache_misses++;
    	break;
    case STORE:
    	/* Line up the GETM in the Bus' queue */
    	send_GETM(request->addr);
    	/* The IM state means that we have sent the GET message and we are now waiting
    	 * on DATA
    	 */
    	state = MOESIF_CACHE_IM;
    	/* This is a cache miss */
    	Sim->cache_misses++;
    	break;
    default:
        request->print_msg (my_table->moduleID, "ERROR");
        fatal_error ("Client: I state shouldn't see this message\n");
    }
}
inline void MOESI_protocol::do_cache_I (Mreq *request)
{
  switch (request->msg)
  {
    // If we get a request from the processor we need to get the data
    case LOAD:
      /* Line up the GETS in the Bus' queue */
    	send_GETS(request->addr);
    	/* The IS state means that we have sent the GET message and we are now waiting
    	 * on DATA
    	 */
    	state = MOESI_CACHE_IS;
    	/* This is a cache Miss */
    	Sim->cache_misses++;
    	break;

    case STORE:
    	/* Line up the GETM in the Bus' queue */
    	send_GETM(request->addr);
    	/* The IM state means that we have sent the GET message and we are now waiting
    	 * on DATA
    	 */
    	state = MOESI_CACHE_IM;
    	/* This is a cache Miss */
    	Sim->cache_misses++;
    	break;

    default:
        request->print_msg (my_table->moduleID, "ERROR");
        fatal_error ("Client: I state shouldn't see this message\n");
  }
}
inline void MESI_protocol::do_cache_S (Mreq *request)
{
    switch (request->msg) {
    /* The S state means we have the data.  Therefore any request
     * from the processor (read or write) can be immediately satisfied.
     */
    case LOAD:
    /* This is how you send data back to the processor to finish the request        	
     * Note: There was no need to send anything on the bus on a hit.
     */
        send_DATA_to_proc(request->addr);
    	break;
    case STORE:
    /* You are in S state. If you encounter STORE, you give a GetM command
     * And invalidate the other processors
     */
        send_GETM(request->addr);
        state = MESI_CACHE_SM;
        Sim->cache_misses++;
        break;
    default:
        request->print_msg (my_table->moduleID, "ERROR");
        fatal_error ("Client: M state shouldn't see this message\n");
    }
}
inline void MSI_protocol::do_cache_S (Mreq *request){
	switch (request->msg) {
    case LOAD:
		send_DATA_to_proc(request->addr);
		break;
    case STORE:
    	send_GETM(request->addr);
    	state = MSI_CACHE_SM;
    	Sim->cache_misses++;											// USED TO SHOW COHERENCE MISSES
    	break;
    default:
        request->print_msg (my_table->moduleID, "ERROR");
        fatal_error ("Client: S state shouldn't see this message\n");
    }
}
inline void MOESI_protocol::do_cache_O (Mreq *request)
{
	switch (request->msg) {
		case LOAD:	
			send_DATA_to_proc(request->addr);
			break;
		case STORE:
			send_GETM(request->addr);
			state = MOESI_CACHE_OM;
			break;
		default:
		    request->print_msg (my_table->moduleID, "ERROR");
		    fatal_error ("Client: O state shouldn't see this message\n");
	}
}
inline void MSI_protocol::do_cache_I (Mreq *request){
	switch (request->msg) {
    case LOAD:
		send_GETS(request->addr);
		state = MSI_CACHE_IS;
		Sim->cache_misses++;											//ACTUAL CACHE MISSES
    	break;
    case STORE:
    	send_GETM(request->addr);
    	state = MSI_CACHE_IM;
    	Sim->cache_misses++;											//ACTUAL CACHE MISSES
    	break;
    default:
        request->print_msg (my_table->moduleID, "ERROR");
        fatal_error ("Client: I state shouldn't see this message\n");
    }
}
inline void MOESIF_protocol::do_cache_O (Mreq *request)
{
	/* In O, we act the same as S for cache accesses
	*/
	switch (request->msg) {
    case LOAD:
		send_DATA_to_proc(request->addr);
		break;
    case STORE:
    	send_GETM(request->addr);
    	state = MOESIF_CACHE_OM;
		Sim->cache_misses++;
    	break;
    default:
        request->print_msg (my_table->moduleID, "ERROR");
        fatal_error ("Client: O state shouldn't see this message\n");
    }
}
inline void MESI_protocol::do_cache_S (Mreq *request)
{
    switch(request->msg) {
        case LOAD:
            // already have it, send it
            send_DATA_to_proc(request->addr);
            break;
        case STORE:
            // move to the intermediate state, another miss
            send_GETM(request->addr);
            state = MESI_CACHE_SM;
            Sim->cache_misses++;
            break;
        default:
            request->print_msg (my_table->moduleID, "ERROR");
            fatal_error ("Client: CacheS state shouldn't see this message\n");
    }
}
inline void MOESI_protocol::do_cache_O (Mreq *request)
{
    switch (request->msg) {
    case LOAD:
    	//data is clean and can be sent to the processor
        send_DATA_to_proc(request->addr);
        break;
    case STORE:
    	//put the request on the bus for block with the intent to modify
    	//this will lead to a cache miss
        send_GETM(request->addr);
        state = MOESI_CACHE_OM_Intermediate;
        Sim->cache_misses++;
        break;
    default:
        request->print_msg (my_table->moduleID, "ERROR");
        fatal_error ("Client: I state shouldn't see this message\n");
    }
}
inline void MOESIF_protocol::do_cache_F (Mreq *request)
{
	/* In forwarder mode, we act the same as S when a LOAD is requested
	and similar to S when M is requested, but go to the FM state instead
	*/
	switch (request->msg) {
    case LOAD:
		send_DATA_to_proc(request->addr);
    	break;
    case STORE:
		send_GETM(request->addr);
		state = MOESIF_CACHE_FM;
		Sim->cache_misses++;
		break;
    default:
        request->print_msg (my_table->moduleID, "ERROR");
        fatal_error ("Client: S state shouldn't see this message\n");
    }
}
inline void MOESIF_protocol::do_cache_S (Mreq *request)
{
	/* In S we provide data when LOAD requested
	and transition to M when STORE requested
	*/
	switch (request->msg) {
    case LOAD:
		send_DATA_to_proc(request->addr);
    	break;
    case STORE:
    	send_GETM(request->addr);
    	state = MOESIF_CACHE_SM;
		Sim->cache_misses++;
		break;
    default:
        request->print_msg (my_table->moduleID, "ERROR");
        fatal_error ("Client: S state shouldn't see this message\n");
    }
}
inline void TYPE(_protocol)::do_cache_O (Mreq *request)
{
	switch (request->msg) {
	/* 
	  Like F but now its dirty
	*/
	case LOAD://we can haz data, so yay!
		send_DATA_to_proc(request->addr);
		break;
	case STORE://we can haz dataz, But cant use the dataz we can haz
		send_GETM(request->addr);
		state = TYPE(_CACHE_FM);
		/* This is a cache miss */
		Sim->cache_misses++;
		break;
	default:
		request->print_msg (my_table->moduleID, "ERROR");
		fatal_error ("Client: O state shouldn't see this message\n");
	}
}
inline void MESI_protocol::do_cache_I (Mreq *request)
{
    switch(request->msg) {
        case LOAD:
            // Go to the intermediate state, it's a miss
            send_GETS(request->addr);
            state = MESI_CACHE_IS;
            Sim->cache_misses++;
            break;
        case STORE:
            // Go to the intermediate state, it's a miss
            send_GETM(request->addr);
            state = MESI_CACHE_IM;
            Sim->cache_misses++;
            break;
        default:
            request->print_msg (my_table->moduleID, "ERROR");
            fatal_error ("Client: CacheI state shouldn't see this message\n");
    }
}
inline void MOESI_protocol::do_cache_I (Mreq *request)
{
    switch (request->msg) {
    case LOAD:
        //this will lead to a cache miss
    	//get the data first from the memory with the intent to share
        send_GETS(request->addr);
        state = MOESI_CACHE_IS_Intermediate;
        Sim->cache_misses++;
        break;
    case STORE:
    	//this will lead to a cache miss
    	//get the data first from the memory with the intent to modify
        send_GETM(request->addr);
        state = MOESI_CACHE_IM_Intermediate;
        Sim->cache_misses++;
        break;
    default:
        request->print_msg (my_table->moduleID, "ERROR");
        fatal_error ("Client: I state shouldn't see this message\n");
    }
}
inline void MOESI_protocol::do_cache_S (Mreq *request)
{
  switch (request->msg)
  {
    case LOAD:
      //Data is already there in cache line
      send_DATA_to_proc(request->addr);
    	break;

    case STORE:
    	/* Line up the GETM in the Bus' queue */
    	send_GETM(request->addr);
    	/* Move to M-state*/
    	state = MOESI_CACHE_SM;
    	// We will still get data from memory as we have placed GetM on memory
    	Sim->cache_misses++;
    	break;

    default:
        request->print_msg (my_table->moduleID, "ERROR");
        fatal_error ("Client: I state shouldn't see this message\n");
  }
}
inline void TYPE(_protocol)::do_cache_I (Mreq *request)
{
	switch (request->msg) {
	/* 
	  No datas
	*/
	case LOAD:
		send_GETS(request->addr);
		state = TYPE(_CACHE_IE);
		/* This is a cache miss */
		Sim->cache_misses++;
		break;
	case STORE:
		send_GETM(request->addr);
		state = TYPE(_CACHE_IM);
		/* This is a cache miss */
		Sim->cache_misses++;
		break;
	default:
		request->print_msg (my_table->moduleID, "ERROR");
		fatal_error ("Client: I state shouldn't see this message\n");
	}
}
inline void MOESI_protocol::do_cache_O (Mreq *request)
{
  switch (request->msg)
  {
    case LOAD:
      //Data is already there in cache line
      send_DATA_to_proc(request->addr);
    	break;

    case STORE:
      Owner_nodeID = request->src_mid.nodeID;
    	/* Line up the GETM in the Bus' queue */
    	send_GETM(request->addr);
    	/* Move to M-state*/
    	state = MOESI_CACHE_SM;
    	// Owner has the data. Still it is treated as coherence miss.
    	Sim->cache_misses++;
    	break;

    default:
        request->print_msg (my_table->moduleID, "ERROR");
        fatal_error ("Client: I state shouldn't see this message\n");
  }
}
inline void TYPE(_protocol)::do_cache_S (Mreq *request)
{
	switch (request->msg) {
	/* 
	  This is like F but not 
	  allowed to send datas
	*/
	case LOAD: 
		//can haz datas, so no problemz
		send_DATA_to_proc(request->addr);
		break;
	case STORE: 
		//same as F, we can haz dataz, but have to 
		//pretend that we not can haz datas.
		send_GETM(request->addr);
		state = TYPE(_CACHE_SM);
		/* This is a cache miss */
		Sim->cache_misses++;
		break;
	default:
		request->print_msg (my_table->moduleID, "ERROR");
		fatal_error ("Client: S state shouldn't see this message\n");
	}
}