#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <stdint.h>
#include <time.h>
#include <arpa/inet.h>

int decimal_to_binary(char* p, int32_t n)
{
  int32_t c, d, t;

  t = 0;

  if (p == NULL)
    exit(EXIT_FAILURE);

  for (c = 31 ; c >= 0 ; c--)
  {
    d = n >> c;

    if (d & 1)
      *(p+t) = 1 + '0';
    else
      *(p+t) = 0 + '0';

    t++;
  }
  *(p+t) = '\n';
  *(p+t+1) = '\0';

  return 0;
}

int unsigned_decimal_to_binary(char* p, uint32_t n)
{
	int c;
  uint32_t  d, t;

  t = 0;

  if (p == NULL)
    exit(EXIT_FAILURE);

  for (c = 31 ; c >= 0 ; c--)
  {
    d = n >> c;

    if (d & 1)
      *(p+t) = 1 + '0';
    else
      *(p+t) = 0 + '0';

    t++;
  }
  *(p+t) = '\n';
  *(p+t+1) = '\0';

  return 0;
}

int short_decimal_to_binary(char* p, uint16_t n)
{
	int c;
  uint16_t  d, t;

  t = 0;

  if (p == NULL)
    exit(EXIT_FAILURE);

  for (c = 15 ; c >= 0 ; c--)
  {
    d = n >> c;

    if (d & 1)
      *(p+t) = 1 + '0';
    else
      *(p+t) = 0 + '0';

    t++;
  }
  *(p+t) = '\n';
  *(p+t+1) = '\0';

  return 0;
}

int main (int argc, char ** argv) {
	int i = 0;
	int32_t r;
	uint16_t s, old_s;	
	FILE* output;
	FILE* input;
	char str[40];
	output = fopen("./testdata/output.txt", "w");
	input = fopen("./testdata/input.txt", "w"); 	
	srand(time(NULL));

	sprintf(str, "%d\n", i);
	fputs(str, input);
	fputs(str, output);
	fputs("0\n0\n", input);
	short_decimal_to_binary(str, (uint16_t) i << 2);
	fputs(str, output);
	i = 1;
	unsigned_decimal_to_binary(str, htonl(i));
	fputs(str, output);

	fputs("0\n", input); //pc_src
	short_decimal_to_binary(str, 0);
	fputs(str, input); //pc_in

	fputs("\n", output);
	fputs("\n", input);

	for (i = 1; i < 50; i++) { //random inputs without branch
		sprintf(str, "%d\n", i);
		
		fputs(str, input);
		fputs(str, output);
		r = (int32_t) rand() % 5;
		if (r == 1)  {
			
			fputs("1\n0\n", input); // stall case
			short_decimal_to_binary(str, (uint16_t) i << 2);
			fputs(str, output);
			unsigned_decimal_to_binary(str, htonl((int32_t)i));
			fputs(str, output);
			i--;
		}
		else if (r == 2) {
			
			fputs("0\n1\n", input); // flush case
			short_decimal_to_binary(str, (uint16_t) i << 2);
			fputs(str, output);
			unsigned_decimal_to_binary(str, 0x00000013);
			fputs(str, output);
			
		}
		else {
			fputs("0\n0\n", input);
			short_decimal_to_binary(str, (uint16_t) i << 2);
			fputs(str, output);
			unsigned_decimal_to_binary(str, htonl((int32_t)i));
			fputs(str, output);
		}

		fputs("0\n", input); //pc_src
		short_decimal_to_binary(str, 0);
		fputs(str, input); //pc_in

		fputs("\n", output);
		fputs("\n", input);
	}

	sprintf(str, "%d\n", i);
	fputs(str, input);
	fputs(str, output);
	fputs("0\n0\n", input);
	short_decimal_to_binary(str, (uint16_t) i << 2);
	fputs(str, output);
	unsigned_decimal_to_binary(str, htonl((int32_t)i));
	fputs(str, output);

	s = ((uint16_t) rand() % 10) << 2;
	fputs("1\n", input); //pc_src
	short_decimal_to_binary(str, s);
	fputs(str, input); //pc_in

	fputs("\n", output);
	fputs("\n", input);


	for (i = 0; i < 50; i++) {
		r = (int32_t) rand() % 5;
		sprintf(str, "%d\n", i);
		fputs(str, input);
		fputs(str, output);
		if (r == 1) {
			old_s = s;
			fputs("1\n0\n", input); // stall case
			short_decimal_to_binary(str, (uint16_t) s);
			fputs(str, output);
			unsigned_decimal_to_binary(str, htonl((int32_t)s >> 2));
			fputs(str, output);
			
		}
		else if (r == 2) {
			old_s = s;
			fputs("0\n1\n", input); // flush case
			short_decimal_to_binary(str, (uint16_t) s);
			fputs(str, output);
			unsigned_decimal_to_binary(str, 0x00000013);
			fputs(str, output);
			
		}
		else {
			fputs("0\n0\n", input);
			short_decimal_to_binary(str, (uint16_t) s);
			fputs(str, output);
			unsigned_decimal_to_binary(str, htonl((int32_t)s >> 2));
			fputs(str, output);
		}

		s = ((uint16_t) rand() % 10) << 2;
		fputs("1\n", input); //pc_src
		short_decimal_to_binary(str, s);
		fputs(str, input); //pc_in

		if (r == 1) s = old_s;

		if (i != 49) {
			fputs("\n", output);
			fputs("\n", input);
		}
		
	}
	
	fclose(output);
	fclose(input);
}
