#include<cdefBF537.h>
#include<ccblkfn.h>
#include<sys/exception.h>

#define SystemCLK	 100000		//Value in KHz
#define VCO_CoreCLK  1			//Value of VCO/CCLK - value can be 1, 2, 4, 8
#define VCO			 500000		//Value in KHz
#define CLKin		 27000

//#define HostWrite

void ConfigurePLL(void);
void SetUpInterrupts(void);
void ConfigureAsyncMem(void);
short StatusRead(void);
void SetUpMemDMAHRead(void);
void SetUpMemDMAHWrite(void);
void ConfigureHDMA(void);
void DataTransfer(void);
void SetUpWriteData(void);

EX_INTERRUPT_HANDLER (MemDMA);


int Status;
short ConfigurationWord[7] = {0x00A9, 0x060, 0xFF90, 0x20, 0x4, 0x0, 0x0};
short DataIn[64];
short DataOut[64];
/*
HOST_CONFIG - 0x00A9 = Host Read Operation, 1D DMA, Stop Mode; 0x00AB for writes
START_ADDR.L - 0x0060
START_ADDR.H - 0xFF90
XCOUNT - 0x20 - equal to 32 32-bit words.
XMODIFY - 0x4
YCOUNT - 0x0
YMODIFY - 0x0
*/

section("hdma_command") short Command;
section("hdma_data") short Data[64];

void main()
{
	int j;
	
	ConfigurePLL();
	SetUpInterrupts();
	ConfigureAsyncMem();
	#ifdef HostWrite
		SetUpWriteData();
		SetUpMemDMAHWrite();
		ConfigurationWord[0] = 0x00AB;
	#else
		SetUpMemDMAHRead();
	#endif
	
	do		//Poll on the ALLOW_CONFIG bit. Do configuration only if this bit is set.
	{
		Status = StatusRead();	
	}while((Status & 0x80)!=0x80);
	
	ConfigureHDMA();
	ssync();
	
	do
	{
		Status = StatusRead();	
	} while((Status & 0x1)!=0x1);
	
		
	DataTransfer();
	
	while(1);
}

void ConfigurePLL()
{
	*pSIC_IWR = 0x1;
	*pPLL_CTL = SET_MSEL(VCO / CLKin);
	ssync();
	idle();
	*pPLL_DIV = SET_SSEL(VCO / SystemCLK) | ((VCO_CoreCLK)&0x30);
	asm("ssync;");
}

void SetUpInterrupts()
{
	register_handler(ik_ivg13,MemDMA);
    *pSIC_IMASK |= 0x20000000;
}

void ConfigureAsyncMem()
{
	*pEBIU_AMBCTL1 = 0xFFC355C0;
	*pEBIU_AMGCTL = 0xFF;
}

short StatusRead(void)
{
	short temp;
	temp = Command;
	return temp;
}

void SetUpWriteData()
{
	int i;
	for(i=0;i<64; i++)
	{
		DataOut[i] = i & 0xF;
	}
}

void SetUpMemDMAHRead()
{
	*pMDMA_S0_CONFIG = 0x0000 | 0x4;
	*pMDMA_S0_X_COUNT = 64;
	*pMDMA_S0_X_MODIFY = 2;
	*pMDMA_S0_START_ADDR = Data;
	
	*pMDMA_D0_CONFIG = 0x0000 | 0x4 | WNR;
	*pMDMA_D0_X_COUNT = 64;
	*pMDMA_D0_X_MODIFY = 2;
	*pMDMA_D0_START_ADDR = DataIn;
}

void SetUpMemDMAHWrite()
{
	*pMDMA_S0_CONFIG = 0x0000 | 0x4;
	*pMDMA_S0_X_COUNT = 64;
	*pMDMA_S0_X_MODIFY = 2;
	*pMDMA_S0_START_ADDR = DataOut;
	
	*pMDMA_D0_CONFIG = 0x0000 | 0x4 | WNR;
	*pMDMA_D0_X_COUNT = 64;
	*pMDMA_D0_X_MODIFY = 2;
	*pMDMA_D0_START_ADDR = Data;
}

void ConfigureHDMA()
{
	int i;
	for(i=0; i<7; i++)
	{
		Command = ConfigurationWord[i];
	}
}

void DataTransfer()
{
	*pMDMA_S0_CONFIG |= DMAEN;
	*pMDMA_D0_CONFIG |= DMAEN;
}

EX_INTERRUPT_HANDLER (MemDMA)
{
	*pMDMA_D0_IRQ_STATUS = 0x1;
	*pMDMA_S0_IRQ_STATUS = 0x1;
	ssync();
}

