// Made by Jessica Codr (jmc5@cec.wustl.edu or jmc5@arl.wustl.edu)
// as a collection of additional methods that might be helpful
// for plugin creation.


#include "plugin_api.h"
#include "plugin_dl.h"

void dl_sink_message_sram(unsigned int sink, __declspec(sram) unsigned int *msg);
void sram_ring_put_buffer_nwords_sram(unsigned int ring_number, __declspec(sram) unsigned int* in, unsigned int n);
void onl_api_long2decstr_sram(__declspec(sram) unsigned long val, __declspec(sram) char valcalc[9]);

__forceinline void onl_api_intarr2str_sram(__declspec(sram) unsigned int intarr[7], __declspec(sram) char msg[28])
{
  msg[0] = (intarr[0] >> 24) & 0xff;
  msg[1] = (intarr[0] >> 16) & 0xff;
  msg[2] = (intarr[0] >> 8) & 0xff;
  msg[3] = (intarr[0]) & 0xff;

  msg[4] = (intarr[1] >> 24) & 0xff;
  msg[5] = (intarr[1] >> 16) & 0xff;
  msg[6] = (intarr[1] >> 8) & 0xff;
  msg[7] = (intarr[1]) & 0xff;

  msg[8] = (intarr[2] >> 24) & 0xff;
  msg[9] = (intarr[2] >> 16) & 0xff;
  msg[10] = (intarr[2] >> 8) & 0xff;
  msg[11] = (intarr[2]) & 0xff;

  msg[12] = (intarr[3] >> 24) & 0xff;
  msg[13] = (intarr[3] >> 16) & 0xff;
  msg[14] = (intarr[3] >> 8) & 0xff;
  msg[15] = (intarr[3]) & 0xff;

  msg[16] = (intarr[4] >> 24) & 0xff;
  msg[17] = (intarr[4] >> 16) & 0xff;
  msg[18] = (intarr[4] >> 8) & 0xff;
  msg[19] = (intarr[4]) & 0xff;

  msg[20] = (intarr[5] >> 24) & 0xff;
  msg[21] = (intarr[5] >> 16) & 0xff;
  msg[22] = (intarr[5] >> 8) & 0xff;
  msg[23] = (intarr[5]) & 0xff;

  msg[24] = (intarr[6] >> 24) & 0xff;
  msg[25] = (intarr[6] >> 16) & 0xff;
  msg[26] = (intarr[6] >> 8) & 0xff;
  msg[27] = (intarr[6]) & 0xff;
}

unsigned int sram_ring_get_buffer_1word_sram(unsigned int ring_number)
{
  SIGNAL ring_signal;
  __declspec(sram_read_reg) unsigned int data[1];

  __declspec(sram) void* ring_addr =
       (__declspec(sram) void *) ((SRAM_CONTROL_RING_CHANNEL<<QDESC_CHANNEL_BITPOS) | (ring_number<<2));

  sram_get_ring(data, ring_addr, sizeof(data) / sizeof(data[0]), ctx_swap, &ring_signal);

  return data[0];
}

// fills valstr with the decimal representation of val
__forceinline void onl_api_int2decstr(__declspec(gp_reg) unsigned int val, __declspec(local_mem) char valcalc[9])
{
  __declspec(gp_reg) unsigned int i = 0;
  __declspec(gp_reg) unsigned int j = 0;
  __declspec(gp_reg) unsigned int addVal = 1;
  __declspec(gp_reg) unsigned int addValCopy = 1;
  __declspec(gp_reg) unsigned int numDigits = 1;
  __declspec(gp_reg) unsigned int nine = 57;
  __declspec(gp_reg) unsigned int zero = 48;

  valcalc[i] = 48;

  while(val > 0){
  
 	if(val & 0x1){
		addValCopy = addVal;
		while(addValCopy >= 196){ //to avoid wrap-arounds w/ chars
			i = numDigits - 1;
			valcalc[i] = valcalc[i] + 196;  
			while(valcalc[i] > nine){
				if(i==0){ 
					j = numDigits;
					while(j>0){ 
						valcalc[j] = valcalc[j-1];
						j = j - 1;
					}
					valcalc[0] = zero;
					i = 1;
					numDigits = numDigits + 1;
				}	
				valcalc[i] -= 10;
				valcalc[i-1] += 1;
				if(valcalc[i] <= nine && i > 0){
					i -= 1;
				}
			}
			addValCopy = addValCopy - 196;
		}
		i = numDigits - 1;
		valcalc[i] = valcalc[i] + addValCopy; 
		while(valcalc[i] > nine){
			if(i==0){ 
			// shift digits over for more space if needed. 
				j = numDigits;
				while(j>0){ //remember that j is unsigned!!!!
					valcalc[j] = valcalc[j-1];
					j = j - 1;
				}
				valcalc[0] = zero;
				i = 1;
				numDigits = numDigits + 1;
			}	
			valcalc[i] -= 10;
			valcalc[i-1] += 1;
			if(valcalc[i] <= nine && i > 0){
				i -= 1;
			}
		}
  	}
	val = val >> 1;
  	addVal = addVal * 2;
  }
  valcalc[numDigits] = '\0';
}


// fills valstr with the decimal representation of val
void onl_api_int2decstr_sram(__declspec(sram) unsigned int val, __declspec(sram) char valcalc[9])
{
  __declspec(sram) unsigned int i = 0;
  __declspec(sram) unsigned int j = 0;
  __declspec(sram) unsigned int addVal = 1;
  __declspec(sram) unsigned int addValCopy = 1;
  __declspec(sram) unsigned int numDigits = 1;
  __declspec(sram) unsigned int nine = 57;
  __declspec(sram) unsigned int zero = 48;

  valcalc[i] = 48;

  while(val > 0){
  
 	if(val & 0x1){
		addValCopy = addVal;
		while(addValCopy >= 196){ 
			i = numDigits - 1;
			valcalc[i] = valcalc[i] + 196;  
			while(valcalc[i] > nine){
				if(i==0){ 
					j = numDigits;
					while(j>0){ 
						valcalc[j] = valcalc[j-1];
						j = j - 1;
					}
					valcalc[0] = zero;
					i = 1;
					numDigits = numDigits + 1;
				}	
				valcalc[i] -= 10;
				valcalc[i-1] += 1;
				if(valcalc[i] <= nine && i > 0){
					i -= 1;
				}
			}
			addValCopy = addValCopy - 196;
		
		}
		i = numDigits - 1;
		valcalc[i] = valcalc[i] + addValCopy; 
		while(valcalc[i] > nine){
			if(i==0){
				j = numDigits;
				while(j>0){ //remember that j is unsigned!!!!
					valcalc[j] = valcalc[j-1];
					j = j - 1;
				}
				valcalc[0] = zero;
				i = 1;
				numDigits = numDigits + 1;
			}	
			valcalc[i] -= 10;
			valcalc[i-1] += 1;
			if(valcalc[i] <= nine && i > 0){
				i -= 1;
			}
		}
  	}
	val = val >> 1;
  	addVal = addVal * 2;
  }
  valcalc[numDigits] = '\0';
}

// fills valstr with the decimal representation of val
void onl_api_long2decstr_sram(__declspec(sram) unsigned long val, __declspec(sram) char valcalc[9])
{
  __declspec(sram) unsigned int i = 0;
  __declspec(sram) unsigned int j = 0;
  __declspec(sram) unsigned int addVal = 1;
  __declspec(sram) unsigned int addValCopy = 1;
  __declspec(sram) unsigned int numDigits = 1;
  __declspec(sram) unsigned int nine = 57;
  __declspec(sram) unsigned int zero = 48;

  valcalc[i] = 48;

  while(val > 0){
  
 	if(val & 0x1){
		addValCopy = addVal;
		while(addValCopy >= 196){ 
			i = numDigits - 1;
			valcalc[i] = valcalc[i] + 196;  
			while(valcalc[i] > nine){
				if(i==0){ 
					j = numDigits;
					while(j>0){ 
						valcalc[j] = valcalc[j-1];
						j = j - 1;
					}
					valcalc[0] = zero;
					i = 1;
					numDigits = numDigits + 1;
				}	
				valcalc[i] -= 10;
				valcalc[i-1] += 1;
				if(valcalc[i] <= nine && i > 0){
					i -= 1;
				}
			}
			addValCopy = addValCopy - 196;
		
		}
		i = numDigits - 1;
		valcalc[i] = valcalc[i] + addValCopy; 
		while(valcalc[i] > nine){
			if(i==0){
				j = numDigits;
				while(j>0){ //remember that j is unsigned!!!!
					valcalc[j] = valcalc[j-1];
					j = j - 1;
				}
				valcalc[0] = zero;
				i = 1;
				numDigits = numDigits + 1;
			}	
			valcalc[i] -= 10;
			valcalc[i-1] += 1;
			if(valcalc[i] <= nine && i > 0){
				i -= 1;
			}
		}
  	}
	val = val >> 1;
  	addVal = addVal * 2;
  }
  valcalc[numDigits] = '\0';
}


// fills valstr with the hexadecimal representation of val
void onl_api_int2hstr_sram(__declspec(sram) unsigned int val, __declspec(sram) char valstr[9])
{
  __declspec(sram) unsigned int c;
  __declspec(sram) unsigned int i = 0;
  __declspec(sram) unsigned int found_non_zero = 0;
  __declspec(sram) signed int shift = 28;

  valstr[i++] = '0';
  valstr[i++] = 'x';

  while(shift >= 0){
  	c = (val >> shift) & 0xf;
  	if(found_non_zero == 1 || c != 0)
  	{
  		found_non_zero = 1;
    		if(c > 9) { valstr[i++] = c - 10 + 'a'; }
    		else { valstr[i++] = c + '0'; }
  	}
	shift = shift - 4;
  }
  if(i == 2){
	valstr[i++] = '0';
  }
  valstr[i] = '\0';
}


int onl_api_str2intarr_sram(__declspec(sram) char *msg, __declspec(sram) unsigned int intarr[7])
{
  __declspec(sram) unsigned int msglen;
  __declspec(sram) int i,j;
  __declspec(sram) char padmsg[28];

  msglen = strlen_sram(msg);
  if(msglen > 27)
  {
    return -1;
  }

  for(i=0; i<msglen; ++i)
  {
    padmsg[i] = msg[i];
  }
  padmsg[i] = '\0';
  for(i=msglen+1; i<28; ++i)
  {
    padmsg[i] = 0xff;
  }

  j = 0;
  for(i=0; i<7; ++i)
  {
  	intarr[i] = //(unsigned int)(padmsg[j]); //does this alone work? - nope
		((((unsigned int)(padmsg[j])) & 0xff) << 24) | 
		((((unsigned int)(padmsg[j+1])) & 0xff) << 16) | 
		((((unsigned int)(padmsg[j+2])) & 0xff) << 8) | 
		(((unsigned int)(padmsg[j+3])) & 0xff);
 	j=j+4;
  }

  return 0;
}


int onl_api_debug_message_sram(unsigned int sink, __declspec(sram) char *msg)
{
  __declspec(sram) unsigned int message[8];
  __declspec(sram) onl_api_ctrl_msg_hdr msghdr;

  msghdr.response_requested = 0;
  msghdr.type = CM_DEBUGMSG;
  msghdr.num_words = 7;
  msghdr.mid = 0;
  message[0] = msghdr.value;

  if(onl_api_str2intarr_sram(msg, &message[1]) < 0)
  {
    return -1;
  }

  dl_sink_message_sram(sink, message);

  return 0;
}

void dl_source_message_sram(unsigned int source, __declspec(sram) unsigned int *msg)
{
  __declspec(gp_reg) unsigned int sring;
  __declspec(gp_reg) unsigned int i;
  __declspec(gp_reg) unsigned int n;

  // only procede once the lock is available
  while(dl_source_message_lock == LOCKED)
  {
    ctx_swap();
  }
  dl_source_message_lock = LOCKED;

  if(source == MESSAGE_IN_RING_0)
  {
    sring = ONL_XSCALE_TO_PLUGIN_0_CTRL_SRAM_RING;
  }
  else if(source == MESSAGE_IN_RING_1)
  {
    sring = ONL_XSCALE_TO_PLUGIN_1_CTRL_SRAM_RING;
  }
  else if(source == MESSAGE_IN_RING_2)
  {
    sring = ONL_XSCALE_TO_PLUGIN_2_CTRL_SRAM_RING;
  }
  else if(source == MESSAGE_IN_RING_3)
  {
    sring = ONL_XSCALE_TO_PLUGIN_3_CTRL_SRAM_RING;
  }
  else if(source == MESSAGE_IN_RING_4)
  {
    sring = ONL_XSCALE_TO_PLUGIN_4_CTRL_SRAM_RING;
  }
  else
  {
    return;
  }

  msg[0] = sram_ring_get_buffer_1word_sram(sring);
  while(msg[0] == 0)
  {
    ctx_swap();
    msg[0] = sram_ring_get_buffer_1word_sram(sring);
  }

  n = (msg[0]>>16) & 0xFF;

  if(n >= 1)
  {
    msg[1] = sram_ring_get_buffer_1word_sram(sring);
    while(msg[1] == 0)
    {
      ctx_swap();
      msg[1] = sram_ring_get_buffer_1word_sram(sring);
    }
  }
  if(n >= 2)
  {
    msg[2] = sram_ring_get_buffer_1word_sram(sring);
    while(msg[2] == 0)
    {
      ctx_swap();
      msg[2] = sram_ring_get_buffer_1word_sram(sring);
    }
  }
  if(n >= 3)
  {
    msg[3] = sram_ring_get_buffer_1word_sram(sring);
    while(msg[3] == 0)
    {
      ctx_swap();
      msg[3] = sram_ring_get_buffer_1word_sram(sring);
    }
  }
  if(n >= 4)
  {
    msg[4] = sram_ring_get_buffer_1word_sram(sring);
    while(msg[4] == 0)
    {
      ctx_swap();
      msg[4] = sram_ring_get_buffer_1word_sram(sring);
    }
  }
  if(n >= 5)
  {
    msg[5] = sram_ring_get_buffer_1word_sram(sring);
    while(msg[5] == 0)
    {
      ctx_swap();
      msg[5] = sram_ring_get_buffer_1word_sram(sring);
    }
  }
  if(n >= 6)
  {
    msg[6] = sram_ring_get_buffer_1word_sram(sring);
    while(msg[6] == 0)
    {
      ctx_swap();
      msg[6] = sram_ring_get_buffer_1word_sram(sring);
    }
  }
  if(n >= 7)
  {
    msg[7] = sram_ring_get_buffer_1word_sram(sring);
    while(msg[7] == 0)
    {
      ctx_swap();
      msg[7] = sram_ring_get_buffer_1word_sram(sring);
    }
  }

  dl_source_message_lock = UNLOCKED;
}


void dl_sink_message_sram(unsigned int sink, __declspec(sram) unsigned int *msg)
{
  __declspec(sram) unsigned int sring;

  // only procede once the lock is available
  while(dl_sink_message_lock == LOCKED)
  {
    ctx_swap();
  }
  dl_sink_message_lock = LOCKED;

  if(sink == MESSAGE_OUT_RING_0)
  {
    sring = ONL_PLUGIN_0_TO_XSCALE_CTRL_SRAM_RING;
  }
  else if(sink == MESSAGE_OUT_RING_1)
  {
    sring = ONL_PLUGIN_1_TO_XSCALE_CTRL_SRAM_RING;
  }
  else if(sink == MESSAGE_OUT_RING_2)
  {
    sring = ONL_PLUGIN_2_TO_XSCALE_CTRL_SRAM_RING;
  }
  else if(sink == MESSAGE_OUT_RING_3)
  {
    sring = ONL_PLUGIN_3_TO_XSCALE_CTRL_SRAM_RING;
  }
  else if(sink == MESSAGE_OUT_RING_4)
  {
    sring = ONL_PLUGIN_4_TO_XSCALE_CTRL_SRAM_RING;
  }
  else
  {
    dl_sink_message_lock = UNLOCKED; //?? This wasn't there, but I think it should be
    return;
  }

  //IMPORTANT NOTE:  STILL NEED TO IMPLEMENT FOLLOWING METHOD!

  sram_ring_put_buffer_nwords_sram(sring, &msg[0], (((msg[0]>>16) & 0xFF)+1));

  dl_sink_message_lock = UNLOCKED;
}

void sram_ring_put_buffer_nwords_sram(unsigned int ring_number, __declspec(sram) unsigned int* in, unsigned int n)
{
  int i;
  SIGNAL_PAIR ring_signal;
  __declspec(sram_write_reg) unsigned int data[8];

  // The compiler is associating the size of the put data with the size of the returned status
  __declspec(sram_read_reg) unsigned int status[8];

  __declspec(sram) void* ring_addr =
       (__declspec(sram) void *) ((SRAM_CONTROL_RING_CHANNEL<<QDESC_CHANNEL_BITPOS) | (ring_number<<2));

  data[0] = in[0];
  data[1] = in[1];
  data[2] = in[2];
  data[3] = in[3];
  data[4] = in[4];
  data[5] = in[5];
  data[6] = in[6];
  data[7] = in[7];

  do
  {
    sram_put_ring(&status[0], data, ring_addr, n, sig_done, &ring_signal);
    wait_for_all(&ring_signal);
  }
  while(!(status[0] & 0xf0000000));
}


//Following two functions taken from Dr. Wong, but changed
//to make not use sram and to use ints instead of longs

// convert ascii string to unsigned long
//
static __forceinline __declspec(local_mem) unsigned int
kenw_atoi(__declspec(local_mem) char *p ) {
    __declspec(gp_reg) unsigned int x = 0;
    __declspec(gp_reg) int	     y;

    //added && *p != ' ' to keep from adding digits after ' ' -jmc5
    while( *p != '\0' && *p != ' ') {
    	if( *p != ' ' )	{
    	    x *= 10;
    	    y = *p - '0';
	    if( (y<0) || (y>9) )	return 0;
	    x += y;
	}
	p++;
    }
    return x;
}

static __forceinline __declspec(local_mem) char *
nxt_token(__declspec(local_mem) char *p ) {

    while( *p != '\0' ) {  //find SP char
    	if( *p == ' ' )	break;
	p++;
    }
    if( *p == '\0' )	return 0;
    ++p;

    while(*p != '\0' ) {		// scan past SP characters
    	if( *p == ' ' )	++p;
	else		break;
    }

    if( *p == '\0' )	return 0;
    else		return p;
}





