#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <stdint.h>
#include <time.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 int8_decimal_to_binary(char* p, uint8_t n)
{
	int c;
  uint8_t  d, t;

  t = 0;

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

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

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

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

  return 0;
}

int main (int argc, char ** argv) {
	int i,j;
	uint32_t A;
	int ran, XL, XS, rd, wr, busy;
	uint8_t R[4];
	uint8_t W[4];
	int mode;
	FILE* output;
	FILE* input;
	char str[40];
	char A_IN[40];
	char WR_str[4][10];
	char RD_str[4][10];
	char* zero = "00000000";
	char* one = "11111111";
	char* dc = "--------";
	output = fopen("./testdata/output.txt", "w");
	input = fopen("./testdata/input.txt", "w"); 	
	srand(time(NULL));


	

	for (i = 1; i < 100; i++) { 
		fprintf(input,"%d\n", i);
		fprintf(output,"%d\n", i);

		for (j = 0; j < 4; j++) {
			R[j] = (uint8_t) rand();
			W[j] = (uint8_t) rand();
		}

		A = (uint32_t) rand();
		unsigned_decimal_to_binary(A_IN, A);
	
		busy = rand() % 2;
		mode = rand() % 5;
		ran = rand() % 5;
		rd = 0;
		wr = 0;
		switch (ran) {
			case 0: fprintf(input, "0\n0\n"); 
				break;
			case 1: 
			case 2: fprintf(input, "1\n0\n"); rd = 1; break;
				
			case 3: 
			case 4: fprintf(input, "0\n1\n"); wr = 1;break;
		} 

		switch(mode) {
			case 0: fputs("MEM_B\n", input); break;
			case 1: fputs("MEM_BU\n", input); break;
			case 2: fputs("MEM_H\n", input); break;
			case 3: fputs("MEM_HU\n", input); break;
			case 4: fputs("MEM_W\n", input); break;
		}

		fputs(A_IN, input);
		
		for (j = 0; j < 4; j++) {
			int8_decimal_to_binary(WR_str[j], W[j]);
			int8_decimal_to_binary(RD_str[j], R[j]);
		}
		
		fprintf(input, "%s %s %s %s\n", WR_str[3], WR_str[2], WR_str[1], WR_str[0]);

		fprintf(input, "%s %s %s %s\n", RD_str[3], RD_str[2], RD_str[1], RD_str[0]);

		if (mode == 0) { //MEM_B
			XL = 0;
			XS = 0;
			if (A_IN[30] == '0') { //determine byte type
				if (A_IN[31] == '0') {
					j = 3;
				}
				else {
					j = 2;
				}
			}
			else {
				if (A_IN[31] == '0') {
					j = 1;
				}
				else {
					j = 0;
				}
			}

			

			if (RD_str[j][0] == '1') { //print R
				fprintf(output, "%s %s %s %s\n", one, one, one, RD_str[j]);
			}
			else {
				fprintf(output, "%s %s %s %s\n", zero, zero, zero, RD_str[j]);
			}

			fprintf(output, "%d\n%d\n", XL, XS); //print XL, XS

			short_decimal_to_binary(str, (uint16_t) A); //print A_OUT
			fputs(str, output);

			if (XL == 0) { //print rd and wr
				fprintf(output, "%d\n", rd); 
			}
			else{
				fprintf(output, "%d\n", 0);
			}
			if (XS == 0) {
				fprintf(output, "%d\n", wr);
			}
			else{
				fprintf(output, "%d\n", 0);
			}

			

			if (j == 3) { //print wrdata
				fputs("1000\n", output);
				fprintf(output, "%s %s %s %s\n", WR_str[0], dc, dc, dc);
			}
			else if (j == 2) {
				fputs("0100\n", output);
				fprintf(output, "%s %s %s %s\n", dc, WR_str[0], dc, dc);
			}
			else if (j == 1) {
				fputs("0010\n", output);
				fprintf(output, "%s %s %s %s\n", dc, dc, WR_str[0], dc);
			}
			else if (j == 0) {
				fputs("0001\n", output);
				fprintf(output, "%s %s %s %s\n", dc, dc, dc, WR_str[0]);
			}
		}
		else if (mode == 1) { //MEM_BU
			XL = 0;
			XS = 0;
			if (A_IN[30] == '0') { //determine byte type
				if (A_IN[31] == '0') {
					j = 3;
				}
				else {
					j = 2;
				}
			}
			else {
				if (A_IN[31] == '0') {
					j = 1;
				}
				else {
					j = 0;
				}
			}

			
			fprintf(output, "%s %s %s %s\n", zero, zero, zero, RD_str[j]); //print R

			fprintf(output, "%d\n%d\n", XL, XS); //print XL, XS

			short_decimal_to_binary(str, (uint16_t) A); //print A_OUT
			fputs(str, output);

			if (XL == 0) { //print rd and wr
				fprintf(output, "%d\n", rd); 
			}
			else{
				fprintf(output, "%d\n", 0);
			}
			if (XS == 0) {
				fprintf(output, "%d\n", wr);
			}
			else{
				fprintf(output, "%d\n", 0);
			}

			

			if (j == 3) { //print wrdata
				fputs("1000\n", output);
				fprintf(output, "%s %s %s %s\n", WR_str[0], dc, dc, dc);
			}
			else if (j == 2) {
				fputs("0100\n", output);
				fprintf(output, "%s %s %s %s\n", dc, WR_str[0], dc, dc);
			}
			else if (j == 1) {
				fputs("0010\n", output);
				fprintf(output, "%s %s %s %s\n", dc, dc, WR_str[0], dc);
			}
			else if (j == 0) {
				fputs("0001\n", output);
				fprintf(output, "%s %s %s %s\n", dc, dc, dc, WR_str[0]);
			}
		}
		else if (mode == 2) { //MEM_H
			XL = 0;
			XS = 0;
			if (A_IN[30] == '0') { //determine byte type
				j = 3;
				if (A_IN[31] == '1') {
					XL = rd;
					XS = wr;	
				}
			}
			else {
				j = 1;
				if (A_IN[31] == '1') {
					XL = rd;
					XS = wr;	
				}
			}


			if (RD_str[j-1][0] == '1') { //print R
				fprintf(output, "%s %s %s %s\n", one, one, RD_str[j-1], RD_str[j]);
			}
			else {
				fprintf(output, "%s %s %s %s\n", zero, zero, RD_str[j-1], RD_str[j]);
			}

			fprintf(output, "%d\n%d\n", XL, XS); //print XL, XS

			short_decimal_to_binary(str, (uint16_t) A); //print A_OUT
			fputs(str, output);

			if (XL == 0) { //print rd and wr
				fprintf(output, "%d\n", rd); 
			}
			else{
				fprintf(output, "%d\n", 0);
			}
			if (XS == 0) {
				fprintf(output, "%d\n", wr);
			}
			else{
				fprintf(output, "%d\n", 0);
			}

			

			if (j == 3) { //print wrdata
				fputs("1100\n", output);
				fprintf(output, "%s %s %s %s\n", WR_str[0], WR_str[1], dc, dc);
			}
			else if (j == 1) {
				fputs("0011\n", output);
				fprintf(output, "%s %s %s %s\n", dc, dc, WR_str[0], WR_str[1]);
			}
		}
		else if (mode == 3) { //MEM_HU
			XL = 0;
			XS = 0;
			if (A_IN[30] == '0') { //determine byte type
				j = 3;
				if (A_IN[31] == '1') {
					XL = rd;
					XS = wr;	
				}
			}
			else {
				j = 1;
				if (A_IN[31] == '1') {
					XL = rd;
					XS = wr;	
				}
			}



			fprintf(output, "%s %s %s %s\n", zero, zero, RD_str[j-1], RD_str[j]); //print R


			fprintf(output, "%d\n%d\n", XL, XS); //print XL, XS

			short_decimal_to_binary(str, (uint16_t) A); //print A_OUT
			fputs(str, output);

			if (XL == 0) { //print rd and wr
				fprintf(output, "%d\n", rd); 
			}
			else{
				fprintf(output, "%d\n", 0);
			}
			if (XS == 0) {
				fprintf(output, "%d\n", wr);
			}
			else{
				fprintf(output, "%d\n", 0);
			}
			

			if (j == 3) { //print wrdata
				fputs("1100\n", output);
				fprintf(output, "%s %s %s %s\n", WR_str[0], WR_str[1], dc, dc);
			}
			else if (j == 1) {
				fputs("0011\n", output);
				fprintf(output, "%s %s %s %s\n", dc, dc, WR_str[0], WR_str[1]);
			}
		}
		else if (mode == 4) { //MEM_W
			XL = 0;
			XS = 0;
			if (A_IN[30] == '0') { //determine byte type
				if (A_IN[31] == '1') {
					XL = rd;
					XS = wr;	
				}
			}
			else {
				XL = rd;
				XS = wr;	
			}
			



			fprintf(output, "%s %s %s %s\n", RD_str[0], RD_str[1], RD_str[2], RD_str[3]); //print R


			fprintf(output, "%d\n%d\n", XL, XS); //print XL, XS

			short_decimal_to_binary(str, (uint16_t) A); //print A_OUT
			fputs(str, output);

			if (XL == 0) { //print rd and wr
				fprintf(output, "%d\n", rd); 
			}
			else{
				fprintf(output, "%d\n", 0);
			}
			if (XS == 0) {
				fprintf(output, "%d\n", wr);
			}
			else{
				fprintf(output, "%d\n", 0);
			}

			fputs("1111\n", output); //print wrdata
			fprintf(output, "%s %s %s %s\n", WR_str[0], WR_str[1], WR_str[2], WR_str[3]);

		
		}

		if ((rd == 1 && XL == 0) || busy == 1) {
			fputs("1\n", output);
		}
		else {
			fputs("0\n", output);
		}

		fprintf(input, "%d\n", busy);

		if (i < 99) {
			fputs("\n", input);
			fputs("\n", output);
		}
	}
	fclose(output);
	fclose(input);
}

