#include <stdio.h>
#include <mpl.h>


int  init_matrix_a();
int  init_matrix_b();
void get_matrix_c();
void transpose_matrix_xnet();
void transpose_matrix_router();
void show_matrix_c();
void check_matrix();
void rearrange_a_and_b(); 
void good_method();
void matrix_multiply();

       void dpuTimerStart();
       unsigned long dpuTimerTicks();
       double dpuTimerConst();

plural int dt;
plural int c, a, b;
int A[64][64];
int B[64][64];
int C[64][64]; /* C = A . B */
main()
{
	init_matrix_a();	
	init_matrix_b();	

	dpuTimerStart();
	matrix_multiply();
  printf("MATRIX MULTIPLICATION 64x64 DPU cycles: %d\n", dpuTimerTicks());
  printf("MATRIX MULTIPLICATION 64x64 DPU time:   %f\n", (float)dpuTimerTicks() * (float)dpuTimerConst());


	good_method();
	get_matrix_c();
/*
	show_matrix_c();
*/

}

void get_matrix_c(void)
{
	int i,j,no;
	/* on the front end */

	for(i=0;i<nxproc;i++)
		for(j = 0;j< nyproc; j++)
		{
			no = i*nxproc + j;
			C[i][j] = proc[no].c;
		}
	
}

void get_matrix_a(void)
{
	int i,j,no;
	/* on the front end */

	for(i=0;i<nxproc;i++)
		for(j = 0;j< nyproc; j++)
		{
			no = i*nxproc + j;
			A[i][j] = proc[no].a;
		}
	
}

void get_matrix_b(void)
{
	int i,j,no;
	/* on the front end */

	for(i=0;i<nxproc;i++)
		for(j = 0;j< nyproc; j++)
		{
			no = i*nxproc + j;
			B[i][j] = proc[no].b;
		}
	
}

int init_matrix_a(void)
{
	a = ixproc* 3 + iyproc;
}

int init_matrix_b(void)
{
	b = ixproc + iyproc;
}

void transpose_matrix_xnet()
{
	int hop;
	plural int temp; /* temporary storage */

	

	for (hop=1;hop<nxproc+1; hop++)
	{
		if ((iyproc-ixproc) == hop)
		{
			temp = xnetNE[hop].dt;
			xnetNE[hop].dt = dt;
			dt = temp;
		}
	}
}

void rearrange_a_and_b() 
{
	int i;
		
	for(i=0;i<nxproc+1;i++) /* does n+1 times */
	{
		if (i >= iyproc)
			xnetE[1].a = a;
		if (i >= ixproc)
			xnetS[1].b = b;
	}

}

void transpose_matrix_router()
{
	plural int other_no, temp;

	other_no = ixproc * nxproc + iyproc ;

	temp = router[other_no].dt;
	dt = temp; 

}

void show_matrix_c()
{
int i,j;

	for(i=0;i<nxproc;i++)
		for(j = 0;j< nyproc; j++)
		{
			printf("C[%d][%d] = %d\n", i,j,C[i][j]);
		}
	
}

void show_matrix_a()
{
int i,j;

	for(i=0;i<nxproc;i++)
		for(j = 0;j< nyproc; j++)
		{
			if(((i < 16)&&(j < 16))|| (i== nxproc - 1))
			printf("A[%d][%d] = %d\n", i,j,A[i][j]);
		}
	
}

void show_matrix_b()
{
int i,j;

	for(i=0;i<nxproc;i++)
		for(j = 0;j< nyproc; j++)
		{
			if((i < 16)&&(j < 16))
			printf("B[%d][%d] = %d\n", i,j,B[i][j]);
		}
	
}


void check_matrix()
{
int i,j;

	for(i=0;i<nxproc;i++)
		for(j = 0;j< nyproc; j++)
		{
			if(A[i][j] != i*nxproc + j)
			printf(" PANIC!!! A[%d][%d] = %d\n", i,j,A[i][j]);
		}
	
}

void good_method() /* from MASPAR manual */
{
	int i;
	for (i=0;i<nxproc-1;i++)
	{
		if (iyproc > i)
			xnetW[1].a = a;
		if (ixproc > i)
			xnetN[1].b = b;
	}

	c = 0;
	for (i=0;i<nxproc;i++)	
	{
		c += a*b;
		xnetW[1].a = a;
		xnetN[1].b = b;
	}
}
	
			

void matrix_multiply() /* from the book */
{
	int iteration =0;
	plural int count = 0;

	rearrange_a_and_b();

	c = 0;
	for(iteration=0;iteration < 3*nxproc - 2; iteration ++)
	{
		if ((iteration >= ixproc)&&(iteration >= iyproc))
		{
			count ++;
			if (count <= nxproc)
				c += a*b;
/*
			if((iproc < 5)||(iproc == 63*64+1) ||(iproc == 4095))
			{
				printf("it = %d************\n", iteration);
				p_printf("iproc = %d, a = %d, b = %d, c=%d\n", iproc, a, b, c);
			}
*/
		}
		xnetE[1].a = a;
		xnetS[1].b = b;
	}

}
