/* store.h - Global memory accesses without acks (store)
 *           Implementation dependent definitions and declarations.
 */
/* see copyright.txt for usage terms */

#ifndef __STORE_H__
#define __STORE_H__

#include <tic.h>

/* .....................
 *
 * Profiling information
 *
 * .....................
 */

extern ti_hsl_t Store_mutex;

/* .....................
 *
 * Keep track of STORESs
 *
 * .....................
 */

void store_init(void);
void all_store_sync(void);
void all_store_sync_ctr(Counter *rbytes, Counter *sbytes);

/* A local variable which is incremented and then we wait for it to go to zero.
   Used as the implicit flag in all non-blocking operations */
extern Counter recvBytes;
extern Counter sentBytes;

/* Forget about all stores */
TI_INLINE(reset_store_sync) 
void reset_store_sync(void) {
	ti_hsl_lock(&Store_mutex);
	sentBytes -= recvBytes;
	recvBytes = 0;
	ti_hsl_unlock(&Store_mutex);
}


/* Wait for all stores *to* this processor to complete */
TI_INLINE(store_sync) 
void store_sync(int expecting) {
	tic_poll_while(recvBytes < expecting);
	ti_hsl_lock(&Store_mutex);
	sentBytes -= expecting;
	recvBytes -= expecting;
        assert(recvBytes >= 0);
	ti_hsl_unlock(&Store_mutex);
}

TI_INLINE(store_sync_ctr) 
void store_sync_ctr(int expecting, Counter *rBytes, Counter *sBytes) {
	tic_poll_while(*rBytes < expecting);
	ti_hsl_lock(&Store_mutex);
	*sBytes -= expecting;
	*rBytes -= expecting;
        assert(*rBytes >= 0);
	ti_hsl_unlock(&Store_mutex);
}


/* Check whether all stores *to* this processor have completed */
TI_INLINE(is_store_sync) 
int is_store_sync(int expecting) {
	tic_poll();
	return recvBytes >= expecting;
}

TI_INLINE(is_store_sync_ctr) 
int is_store_sync_ctr(int expecting, Counter *rbytes, Counter *sbytes) {
	tic_poll();
	return *rbytes >= expecting;
}

#ifdef DEPRECATED
TI_INLINE(store_rcvd_bytes) 
int store_rcvd_bytes(void) {
	return recvBytes;
}
#endif

TI_INLINE(__incr_ctr_size) 
void __incr_ctr_size(Counter *ctr, int size) {
  ti_hsl_lock(&Store_mutex);
  (*ctr) += size;
  ti_hsl_unlock(&Store_mutex);
}


/* ............................
 *
 * STOREs with explicit counter
 *
 * ............................
 */

#ifdef COMM_AM2
/* Handlers on the remote end to store value */
TIC_AMSHORT_DECLARE(store_b_request, 3, 5);
TIC_AMSHORT_DECLARE(store_sh_request, 3, 5);
TIC_AMSHORT_DECLARE(store_i_request, 3, 5);
TIC_AMSHORT_DECLARE(store_f_request, 3, 5);
TIC_AMSHORT_DECLARE(store_d_request, 4, 6);
TIC_AMSHORT_DECLARE(store_l_request, 4, 6);
TIC_AMSHORT_DECLARE(store_lp_request, 3, 6);
TIC_AMSHORT_DECLARE(store_gp_request, 4, 7);

#endif /* COMM_AM2 */

/* STORE character */
TI_INLINE(__b_store_ctr) 
void __b_store_ctr(jGPointer gPtr, jbyte val, Counter *rbytes, Counter *sbytes) {
#ifdef COMM_AM2
       int box = tobox(gPtr);
       jbyte *addr    = tolocal(gPtr);

       if(box == MYBOX) {
	 __incr_ctr_size(sbytes, sizeof(jbyte));
	 *addr = val;
	 __incr_ctr_size(rbytes, sizeof(jbyte));
       }
       else {
	 __incr_ctr_size(sbytes, sizeof(jbyte));
	 tic_AMRequest(3,5,(box, TIC_AMIDX(store_b_request), TIC_AMSEND_PTR(addr), 
		     val, TIC_AMSEND_PTR(rbytes)));
       }
#else
       jbyte *addr    = tolocal(gPtr);
       __incr_ctr_size(sbytes, sizeof(jbyte));
       *addr = val;
       __incr_ctr_size(rbytes, sizeof(jbyte));
#endif /* COMM_AM2 */
}

/* STORE short */
TI_INLINE(__sh_store_ctr) 
void __sh_store_ctr(jGPointer gPtr, jshort val, Counter *rbytes, Counter *sbytes) {
#ifdef COMM_AM2
       int box = tobox(gPtr);
       jshort *addr   = tolocal(gPtr);

       if(box == MYBOX) {
	 __incr_ctr_size(sbytes, sizeof(jshort));
	 *addr = val;
	 __incr_ctr_size(rbytes, sizeof(jshort));
       } 
       else {
	 __incr_ctr_size(sbytes, sizeof(jshort));
	 tic_AMRequest(3,5,(box, TIC_AMIDX(store_sh_request), TIC_AMSEND_PTR(addr), 
		     val, TIC_AMSEND_PTR(rbytes)));
       }
#else
       jshort *addr   = tolocal(gPtr);
       __incr_ctr_size(sbytes, sizeof(jshort));
       *addr = val;
       __incr_ctr_size(rbytes, sizeof(jshort));
#endif /* COMM_AM2 */
}

/* STORE int */
TI_INLINE(__i_store_ctr) 
void __i_store_ctr(jGPointer gPtr, int val, Counter *rbytes, Counter *sbytes) {
#ifdef COMM_AM2
       int box = tobox(gPtr);
       jint *addr     = tolocal(gPtr);

       if(box == MYBOX) {
	 __incr_ctr_size(sbytes, sizeof(jint));
	 *addr = val;
	 __incr_ctr_size(rbytes, sizeof(jint));
       } 
       else {
	 __incr_ctr_size(sbytes, sizeof(jint));
	 tic_AMRequest(3,5,(box, TIC_AMIDX(store_i_request), TIC_AMSEND_PTR(addr), 
		     val, TIC_AMSEND_PTR(rbytes)));
       }
#else
       jint *addr     = tolocal(gPtr);
       __incr_ctr_size(sbytes, sizeof(jint));
       *addr = val;
       __incr_ctr_size(rbytes, sizeof(jint));
#endif /* COMM_AM2 */
}

/* STORE float */
TI_INLINE(__f_store_ctr) 
void __f_store_ctr(jGPointer gPtr, jfloat val, Counter *rbytes, Counter *sbytes) {
#ifdef COMM_AM2
       int box = tobox(gPtr);
       jfloat *addr   = tolocal(gPtr);

       if(box == MYBOX) {
	 __incr_ctr_size(sbytes, sizeof(jfloat));
	 *addr = val;
	 __incr_ctr_size(rbytes, sizeof(jfloat));
       } 
       else {
	 __incr_ctr_size(sbytes, sizeof(jfloat));
	 /* pass unsigned so that it won't pass in fp registers */
	 tic_AMRequest(3,5,(box, TIC_AMIDX(store_f_request), TIC_AMSEND_PTR(addr), 
		     TIC_AMSEND_JFLOAT(val), TIC_AMSEND_PTR(rbytes)));
       }
#else
       jfloat *addr   = tolocal(gPtr);
       __incr_ctr_size(sbytes, sizeof(jfloat));
       *addr = val;
       __incr_ctr_size(rbytes, sizeof(jfloat));
#endif /* COMM_AM2 */
}

/* STORE double */
TI_INLINE(__d_store_ctr) 
void __d_store_ctr(jGPointer gPtr, jdouble val, Counter *rbytes, Counter *sbytes) {
#ifdef COMM_AM2
       int box = tobox(gPtr);
       jdouble *addr   = tolocal(gPtr);

       if(box == MYBOX) {
	 __incr_ctr_size(sbytes, sizeof(jdouble));
	 *addr = val;
	 __incr_ctr_size(rbytes, sizeof(jdouble));
       } 
       else {
	 __incr_ctr_size(sbytes, sizeof(jdouble));
	 /* pass unsigned so it will not pass in fp regs */
	 tic_AMRequest(4,6,(box, TIC_AMIDX(store_d_request), TIC_AMSEND_PTR(addr),
                       TIC_AMSEND_JDOUBLE(val), TIC_AMSEND_PTR(rbytes)));
       }
#else
       jdouble *addr   = tolocal(gPtr);
       __incr_ctr_size(sbytes, sizeof(jdouble));
       *addr = val;
       __incr_ctr_size(rbytes, sizeof(jdouble));
#endif /* COMM_AM2 */     
}


/* STORE long long */
TI_INLINE(__l_store_ctr) 
void __l_store_ctr(jGPointer gPtr, jlong val, Counter *rbytes, Counter *sbytes) {
#ifdef COMM_AM2
       int box = tobox(gPtr);
       jlong *addr   = tolocal(gPtr);

       if(box == MYBOX) {
	 __incr_ctr_size(sbytes, sizeof(jlong));
	 *addr = val;
	 __incr_ctr_size(rbytes, sizeof(jlong));
       } 
       else {
	 __incr_ctr_size(sbytes, sizeof(jdouble));
	 /* pass unsigned so it will not pass in fp regs */
	 tic_AMRequest(4,6,(box, TIC_AMIDX(store_l_request), TIC_AMSEND_PTR(addr), 
		     TIC_AMSEND_JLONG(val), TIC_AMSEND_PTR(rbytes)));
       }
#else
       jlong *addr   = tolocal(gPtr);
       __incr_ctr_size(sbytes, sizeof(jlong));
       *addr = val;
       __incr_ctr_size(rbytes, sizeof(jlong));
#endif /* COMM_AM2 */     
}

/* STORE local pointer */
TI_INLINE(__lp_store_ctr) 
void __lp_store_ctr(jGPointer gPtr, void *val, Counter *rbytes, Counter *sbytes) {
#ifdef COMM_AM2
       int box = tobox(gPtr);
       void **addr   = tolocal(gPtr);

       if(box == MYBOX) {
	 __incr_ctr_size(sbytes, sizeof(void *));
	 *addr = val;
	 __incr_ctr_size(rbytes, sizeof(void *));
       } 
       else {
	 __incr_ctr_size(sbytes, sizeof(void *));
	 tic_AMRequest(3,6,(box, TIC_AMIDX(store_lp_request), TIC_AMSEND_PTR(addr),
			TIC_AMSEND_PTR(val), TIC_AMSEND_PTR(rbytes)));
       }
#else
       void **addr   = tolocal(gPtr);
       __incr_ctr_size(sbytes, sizeof(void *));
       *addr = val;
       __incr_ctr_size(rbytes, sizeof(void *));
#endif /* COMM_AM2 */     
}

/* STORE global pointer */
TI_INLINE(__gp_store_ctr) 
void __gp_store_ctr(jGPointer gPtr, jGPointer val, Counter *rbytes, Counter *sbytes) {
#ifdef COMM_AM2
       int box = tobox(gPtr);
       jGPointer *addr   = tolocal(gPtr);
       Box boxData;
       void *addrData;

       if(box == MYBOX) {
	 __incr_ctr_size(sbytes, sizeof(jGPointer));
	 *addr = val;
	 __incr_ctr_size(rbytes, sizeof(jGPointer));
       } 
       else {
	 boxData = tobox(val);
	 addrData = tolocal(val);
	 __incr_ctr_size(sbytes, sizeof(jGPointer));
	 tic_AMRequest(4,7,(box, TIC_AMIDX(store_gp_request), TIC_AMSEND_PTR(addr),
			boxData, TIC_AMSEND_PTR(addrData), TIC_AMSEND_PTR(rbytes)));
       }
#else
       jGPointer *addr   = tolocal(gPtr);
       __incr_ctr_size(sbytes, sizeof(jGPointer));
       *addr = val;
       __incr_ctr_size(rbytes, sizeof(jGPointer));
#endif /* COMM_AM2 */     
}

/* ............................
 *
 * STOREs with implicit counter
 *
 * ............................
 */

TI_INLINE(__b_store) void __b_store(jGPointer gPtr, jbyte val)
{ __b_store_ctr (gPtr, val, TIC_TRANSLATE_CSTATIC_ADDR(&recvBytes,tobox(gPtr)), &sentBytes); }

TI_INLINE(__sh_store) void __sh_store(jGPointer gPtr, jshort val)
{ __sh_store_ctr (gPtr, val, TIC_TRANSLATE_CSTATIC_ADDR(&recvBytes,tobox(gPtr)), &sentBytes); }

TI_INLINE(__i_store) void __i_store(jGPointer gPtr, jint val)
{ __i_store_ctr (gPtr, val, TIC_TRANSLATE_CSTATIC_ADDR(&recvBytes,tobox(gPtr)), &sentBytes); }

TI_INLINE(__f_store) void __f_store(jGPointer gPtr, jfloat val)
{ __f_store_ctr (gPtr, val, TIC_TRANSLATE_CSTATIC_ADDR(&recvBytes,tobox(gPtr)), &sentBytes); }

TI_INLINE(__d_store) void __d_store(jGPointer gPtr, jdouble val)
{ __d_store_ctr (gPtr, val, TIC_TRANSLATE_CSTATIC_ADDR(&recvBytes,tobox(gPtr)), &sentBytes); }

TI_INLINE(__l_store) void __l_store(jGPointer gPtr, jlong val)
{ __l_store_ctr (gPtr, val, TIC_TRANSLATE_CSTATIC_ADDR(&recvBytes,tobox(gPtr)), &sentBytes); }

TI_INLINE(__lp_store) void __lp_store(jGPointer gPtr, void * val)
{ __lp_store_ctr (gPtr, val, TIC_TRANSLATE_CSTATIC_ADDR(&recvBytes,tobox(gPtr)), &sentBytes); }

TI_INLINE(__gp_store) void __gp_store(jGPointer gPtr, jGPointer val)
{ __gp_store_ctr (gPtr, val, TIC_TRANSLATE_CSTATIC_ADDR(&recvBytes,tobox(gPtr)), &sentBytes); }

extern void __store(jGPointer gPtr, void *lPtr, int len);

#endif /* __STORE_H__ */