#include "plugin_api.h"

//-----------------------------------------------------------
// Some Useful Functions
//-----------------------------------------------------------


// zero plugin counter
//									<<<<<
static __forceinline void
helper_plugin_cntr_zero( int counter_id ) {
    get_pcntr( pluginId, counter_id );
    WU_loadGlobalRegister( stats_regnum, 0, stats_cerr );
}

// transfer debug msg from sram to local memory
//									<<<<<
static __forceinline void
helper_dbg_message( __declspec(local_mem) char *dbgmsg,
			__declspec(sram) char *mymsg, unsigned int nbytes ) {
    memcpy_lmem_sram( dbgmsg, mymsg, nbytes );
    onl_api_debug_message( msgNextBlock, dbgmsg );
}

//
// return difference of 2 timestamps in msec
//									<<<<<
static __forceinline unsigned long
diff_msec(	__declspec(local_mem) long long t2,
		__declspec(local_mem) long long t1 ) {
    __declspec(gp_reg)	  unsigned long msec;
    msec = ( ((t2 - t1)<<4) /100000)/14;		// 16*delta/10^5/14
    //XXX msec = (16*(t2 - t1)/100000)/14;		// 16*delta/10^5/14
    return msec;
}

// convert msec to #ME cycles assuming 1.4 GHz ME
//									<<<<<
// CAVEAT:  msec <= 49000 msec
//
static __forceinline unsigned long
msec2cycles ( __declspec(gp_reg) unsigned long msec ) {
    __declspec(gp_reg)	  unsigned long cycles;
    cycles = ( 14*msec*100000 );
    //XXX cycles = ( 14*msec*100000 ) && 0xfffffff0;
    return cycles;
}

// wait for the packet signal
//									<<<<<
static __forceinline void
wait_packet_signal(SIGNAL *s) {
    wait_for_all(s);
}

// send the packet signal
//									<<<<<
static __forceinline void
send_packet_signal(SIGNAL *s) {
    int c;
  
    c = ctx();
#if ( (FIRST_PACKET_THREAD) == (LAST_PACKET_THREAD) )
    if(c == FIRST_PACKET_THREAD)
    {
	signal_same_ME(__signal_number(s), FIRST_PACKET_THREAD);
	__implicit_write(s);
    }
#else
    if(c >= FIRST_PACKET_THREAD && c < LAST_PACKET_THREAD) 
    {
	signal_same_ME_next_ctx(__signal_number(s));
	__implicit_write(s);
    }
    else if(c == LAST_PACKET_THREAD)
    {
	signal_same_ME(__signal_number(s), FIRST_PACKET_THREAD);
	__implicit_write(s);
    }
#endif
}

// Same as dl_source_packet() but no pkt will be dequeued from the previous
//	processing block
//									<<<<<
void dl_source_nopacket( void )
{
#ifdef DL_ORDERED
    wait_packet_signal(&dl_source_packet_sig);
#endif

#ifdef DL_ORDERED
    send_packet_signal(&dl_source_packet_sig);
#endif
}

// Same as dl_sink_packet() but no pkt will be enqueued to the next
//	processing block
//
void dl_sink_nopacket( void )
{
#ifdef DL_ORDERED
    wait_packet_signal(&dl_sink_packet_sig);
#endif

#ifdef DL_ORDERED
    send_packet_signal(&dl_sink_packet_sig);
#endif  
}

//									<<<<<
// return address of next word following the current word where a word is
// 	any char sequence terminated by the space character.  Limit the
// 	search to n characters.  Return 0 if no word found.
// If the string is "xxx  yyy" with p pointing to the first 'x',
// 	nxt_token( p, 7 ) returns addr of first 'y'; nxt_token( p, 4 )
// 	returns 0.
//
static __forceinline __declspec(sram) char *
nxt_token( __declspec(sram) char *p, __declspec(gp_reg) int n ) {
    __declspec(sram) char *pend;

    pend = p + n;

    while( p<pend ) {		// find SP char
    	if( *p == ' ' )	break;
	p++;
    }
    if( p >= pend )	return 0;
    ++p;

    while( p<pend ) {		// scan past SP characters
    	if( *p == ' ' )	++p;
	else		break;
    }

    if( p >= pend )	return 0;
    else		return p;
}

//									<<<<<
// convert the unsigned long 'x' to the ascii string starting at 'p' which
// 	is 'n' bytes long.
// NOTE:  The string is right justified.  So, if n is 16, you are creating
// 		a 16-byte string with the null character at the rightmost
// 		byte.
//
static __forceinline __declspec(gp_reg) int
helper_ultoa_sram(	__declspec(sram) unsigned long x,
		__declspec(sram) char *p,
		__declspec(gp_reg) int n ) {
    __declspec(gp_reg) int k;
    __declspec(gp_reg) int K;
    __declspec(gp_reg) int r;
    __declspec(gp_reg) int ndigits;
    __declspec(sram) char *pend;

    ndigits = 0;
    pend = p + n - 1;
    *pend = '\0';
    --pend;

    while( pend >= p ) {
    	if( x > 0 ) {
    	    r = x%10;
	    *pend = '0' + r;
	    ++ndigits;
	} else if( ndigits == 0 ) {
	    *pend = '0';
	    ndigits = 1;
	} else {
	    *pend = ' ';
	}
	x = x/10;
    	--pend;
    }
    if( x > 0 )		return -1;

    K = ndigits + 1;
    pend = p + n - ndigits - 1;
    for( k=0; k<K; k++) {
    	*p = *pend;
	p++;
	pend++;
    }
    *p = '\0';
    return ndigits;
}

// convert ascii string to unsigned long
//									<<<<<
static __forceinline unsigned long
helper_atou_sram( __declspec(sram) char *p ) {
    __declspec(gp_reg) unsigned long x = 0;
    __declspec(gp_reg) int	     y;

    while( *p != '\0' ) {
    	if( *p != ' ' )	{
    	    x *= 10;
    	    y = *p - '0';
	    if( (y<0) || (y>9) )	return 0;
	    x += y;
	}
	p++;
    }
    return x;
}

// convert unsigned long to hex ascii
//									<<<<<
static __forceinline void
helper_ul2hex_sram( unsigned long x, char hexstr[8] ) {
    unsigned int c;

    c = x>>28;
    if( c < 10 )	hexstr[0] = '0' + c;
    else		hexstr[0] = 'a' + c - 10;
    c = x>>24 & 0xf;
    if( c < 10 )	hexstr[1] = '0' + c;
    else		hexstr[1] = 'a' + c - 10;
    c = x>>20 & 0xf;
    if( c < 10 )	hexstr[2] = '0' + c;
    else		hexstr[2] = 'a' + c - 10;
    c = x>>16 & 0xf;
    if( c < 10 )	hexstr[3] = '0' + c;
    else		hexstr[3] = 'a' + c - 10;
    c = x>>12 & 0xf;
    if( c < 10 )	hexstr[4] = '0' + c;
    else		hexstr[4] = 'a' + c - 10;
    c = x>>8 & 0xf;
    if( c < 10 )	hexstr[5] = '0' + c;
    else		hexstr[5] = 'a' + c - 10;
    c = x>>4 & 0xf;
    if( c < 10 )	hexstr[6] = '0' + c;
    else		hexstr[6] = 'a' + c - 10;
    c = x & 0xf;
    if( c < 10 )	hexstr[7] = '0' + c;
    else		hexstr[7] = 'a' + c - 10;
}

