#include "system.h"
#include <io.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


#define BUF_SIZE (50)


extern int read_device_id();
extern int read_status_register();
extern int read_flag_status_register();
extern void write_enable();
extern void enter_4byte_addressing_mode();// No this resigter in EPCQL256
extern void clear_flag_status_register();// No this resigter in EPCQL256
//extern int read_bank_register();
//extern void write_bank_register_enter4byte();
//extern void write_bank_register_exit4byte();
extern int read_config_register();
//extern void write_config_register();
extern void clear_status_register();
//extern void write_evcr_quad();
//extern void write_evcr_dual();
extern void erase_sector_cypress();
//extern void erase_sector_intel();
extern void erase_sector_micron();
extern int read_memory(long offset);
extern int read_memory_3byte();
//extern int cypress_four_byte_fast_read();
//extern int intel_four_byte_fast_read();
extern void write_memory();
extern void write_memory_3byte();
//extern void write_memory_4byte();
extern void write_register_for_sector_protect_cypress();
extern void write_register_for_sector_unprotect_cypress();
extern void write_register_for_sector_unprotect_micron();
extern void write_status_register_for_block_protect_micron();
//extern void write_register_for_sector_protect_intel();
//extern void write_status_register_for_block_protect_intel();
void	read_gflish_data();




int main(){

		//IDENTIFY FLASH DEVICE IDENTITY
	int cypress_flash = 0x4d200201;
//	int EPCQL256_flash = 0x1019bb20;
	//FILE *fp_ascii = NULL;
	//FILE *fp_bin = NULL;
	//char buffer[BUF_SIZE];
	//int read_size=1;

#if 0
	/* Reading ASCII File from the host*/
	fp_ascii = fopen("/mnt/host/abc.txt", "r");
	if (fp_ascii == NULL)
	{
	    printf("Cannot open the file\n");
	    exit(1);
	}
	fgets(buffer, sizeof(buffer), fp_ascii);
	printf("%s", buffer);
	fclose(fp_ascii);


	/* WriteASCII File from the host*/
	fp_ascii = fopen("/mnt/host/abc.txt", "w");
	if (fp_ascii == NULL)
	{
	    printf("Cannot open the file\n");
	    exit(1);
	}
	strcpy(buffer, "Hellow from NIOS II");
	fputs(buffer, fp_ascii);
	fclose(fp_ascii);


#endif

	if (read_device_id()== cypress_flash) {
//	if (read_device_id()== EPCQL256_flash) {

		printf("Flash Device: Cypress flash S70FL01G\n");
//		printf("Flash Device: Intel flash EPCQ-L256\n");
		printf("Device ID: %x\n",read_device_id());

		int mask_wip = 0x00000001; //set mask to check Write in Progress (WIP) bit to determine device busy or ready
		int block_protect_cr = 0x00000020; //set BP starts at bottom
		int block_protect_sr = 0x0000001c; //set BP2-0 in status register to protect all sectors
		int mask_wel = 0x00000002; //set mask to check write enable latch
		int mask_sr = 0x000000e3; // set mask to check bit 4:2 of status register
		int mask_e_err = 0x00000020; //set mask to check erase error bit

			//PERFORM SECTOR PROTECT CONFIGURATION DEVICE


		if ((read_status_register()| mask_sr) == mask_sr) {

			printf("All sectors in this configuration device is not protected\n");
			printf("Now performing sector protection...\n");
			write_enable();
			write_register_for_sector_protect_cypress(); //sector protect all sector(BP2:BP1:BP0=1:1:1)

			int mask_wip = 0x00000001; //set mask to check Write in Progress (WIP) bit to determine device busy or ready

			while ((read_status_register() & mask_wip) == mask_wip){
					//printf("Write register for sector protect in progress...\n");
					//usleep(1000);
			}

				//Check Status Register and Configuration Register to see whether both of them set to perform sector protect

			if ( ((read_status_register()& block_protect_sr) != block_protect_sr) && ((read_config_register() & block_protect_cr)!= block_protect_cr)) {
				printf("Setor protection failed due to error in setting status and configuration register");
				printf("Status Register: %08x\n",read_status_register());
				printf("Configuration Register: %08x\n",read_config_register());
				printf("Check datasheet to find out");
				return 0;
			}
		}

		printf("All sectors in this configuration device is now successfully protected\n");
			//PERFORM SECTOR ERASE ON PROTECTED SECTOR

		write_enable();

		if ((read_status_register()& mask_wel) != mask_wel) { //check if write enable latch is set
			printf("Sector erase cannot be executed as write enable latch do not set\n");
			return 0;
		}

		printf("Trying to erase sector 0...\n");

		erase_sector_cypress();
//		erase_sector_intel();

		if ((read_status_register()& mask_e_err)!= mask_e_err) {
			printf("ERASE ERROR do not occur. Check status register for more details.\n");
			return 0;
		}

		printf("ERASE ERROR as sector is protected!\n");
		clear_status_register(); //clear erase error bit

			//UNPROTECT ALL SECTORS IN CONFIGURATION DEVICE
		printf("Now perform sector unprotect...\n");

		write_enable();

		if ((read_status_register()& mask_wel) != mask_wel) { //check if write enable latch is set
			printf("Sector unprotect cannot be executed as write enable latch do not set\n");
			return 0;
		}

		write_register_for_sector_unprotect_cypress();


		while ((read_status_register() & mask_wip) == mask_wip){
			usleep(1000);
		}

		if ((read_status_register()| mask_sr) != mask_sr) {
			printf("Sector unprotect not successful! :(\n");
			return 0;
		}

		printf("Sector unprotect successfully! :)\n");


			//READ AND WRTIE DATA

		printf("Reading data at address 0...\n");
		printf("Memory content at address 0: %x\n",read_memory_3byte());
		int empty_data = 0xffffffff;

		if (read_memory_3byte()!= empty_data) {

				//PERFORM SECTOR ERASE to clear sector 0

			write_enable();

			if ((read_status_register()& mask_wel) != mask_wel) { //check if write enable latch is set
				printf("Sector erase cannot be executed as write enable latch do not set\n");
			}

			printf("Trying to erase sector 0...\n");
			erase_sector_cypress();
//				erase_sector_intel();

		}


			//WRITING DATA

		printf("Address 0 not containing data...\n");
		printf("Writing data to address 0...\n");

		write_memory_3byte();

		while ((read_status_register() & mask_wip) == mask_wip){
					//printf("Write data in progress...\n");
			usleep(10000000);
		}

			//READ BACK DATA
		printf("Read back data from address 0...\n");

		int data1 = 0xabcd1234;

		if(read_memory_3byte() != data1) {
			printf("Current memory in address 0: %x\n",read_memory_3byte());
			printf("Something is wrong...");
			return 0;
		}

		printf("Current memory in address 0: %x\n",read_memory_3byte());
		printf("Read data match with data written. Write memory successful.");

			//SECTOR PROTECT

		printf("Now performing sector protection...\n");
		write_enable();
		write_register_for_sector_protect_cypress();
//			write_register_for_sector_protect_intel();

		while ((read_status_register() & mask_wip) == mask_wip){
				//printf("Write register for sector protect in progress...\n");
				//usleep(1000);
		}

			//Check Status Register and Configuration Register to see whether both of them set to perform sector protect


		if ( ((read_status_register()& block_protect_sr) == block_protect_sr) && ((read_config_register() & block_protect_cr)!= block_protect_cr)) {
			printf("Setor protection failed due to error in setting status and configuration register");
			printf("Status Register: %08x\n",read_status_register());
			printf("Configuration Register: %08x\n",read_config_register());
			printf("Check datasheet to find out");
			return 0;
		}

		printf("All sectors in this configuration device is now successfully protected\n");

			//PERFORM SECTOR ERASE ON PROTECTED SECTOR

		write_enable();

		if ((read_status_register()& mask_wel) != mask_wel) { //check if write enable latch is set
			printf("Sector erase cannot be executed as write enable latch do not set\n");
			return 0;
		}

		printf("Trying to erase sector 0...\n");
		erase_sector_cypress();
//			erase_sector_intel();


		if ((read_status_register()& mask_e_err)!= mask_e_err) {
			printf("ERASE ERROR do not occur. Check status register for more details.\n");
			return 0;
		}
		printf("ERASE ERROR as sector is protected!\n");
		clear_status_register(); //clear erase error bit

		if(read_memory_3byte() == data1) {
			printf("Current memory in address 0: %x\n",read_memory_3byte());
			printf("Read data match with data written previously. Sector erase does not perform during sector is protected.");

		}	else {
			printf("Current memory in address 0: %x\n",read_memory_3byte());
			printf("Something is wrong...");
			return 0;
		}



//MICRON FLASH

	} else {

		if (read_device_id() == 0x1021ba20) {

			printf("Flash Device: Micron flash MT25Q1G\n");
			printf("Device ID: %x\n",read_device_id());
		} else if  (read_device_id() == 0x1020ba20) {

			printf("Flash Device: Micron flash MT25Q512\n");
			printf("Device ID: %x\n",read_device_id());
		} else if  (read_device_id() == 0x1019ba20) {

			printf("Flash Device: Intel FPGA EPCQ256\n");
			printf("Device ID: %x\n",read_device_id());

		} else {

			printf("Configuration Device: Unknown by system...");
			printf("Device ID: %x\n",read_device_id());
			return 0;
		}

		int mask_wip2 = 0x00000001; //set mask to check Write in Progress (WIP) bit to determine device busy or ready
		int mask_sr2 = 0x00000083; // set mask to check bit 6,4:2 of status register
		int block_protect_sr_m = 0x0000007c; //set BP3-0 and TB bit in status register to protect all sectors
		int mask_e_err2 = 0x00000020; //set mask to check erase error bit in flag status register
		int mask_wel2 = 0x00000002; //set mask to check write enable latch
		int empty_data2 = 0xffffffff;



		//PERFORM SECTOR PROTECT CONFIGURATION DEVICE


		//enter_4byte_addressing_mode();	// EPCQL256 has not this setting
		//clear_flag_status_register();		// EPCQL256 has not this setting


#if 0
		if ((read_status_register()| mask_sr2) == mask_sr2) { // check if any sector of the flash is in protecting

			printf("All sectors in this configuration device is not protected\n");
			printf("Now performing sector protection...\n");

			write_enable();
			write_status_register_for_block_protect_micron(); //sector protect all sector(BP3:BP2:BP1:BP0=1:1:1:1)
				//clear_flag_status_register();
			usleep(1000000);

			while ((read_status_register() & mask_wip2) == mask_wip2){
			//printf("Write register for sector protect in progress...\n");
			//usleep(1000);
			}
		}
#endif

		//Check Status Register to confirm whether all of its sector already protected
#if 0
		if ((read_status_register() & block_protect_sr_m)!= block_protect_sr_m)  {

			printf("Setor protection failed due to error in setting status register\n");
			printf("Status Register: %08x\n",read_status_register());
			printf("Check datasheet to find out");
			return 0;
		}
		printf("All sectors in this configuration device is now successfully protected\n");
		printf("Trying to erase sector 0...\n");

		write_enable();
		erase_sector_micron();

		while ((read_status_register() & mask_wip2) == mask_wip2){   //wait sector erase to end before proceed to next
				//printf("Sector erase in progress...\n");
				//usleep(1000);
		}

			//start of skip

		if ((read_flag_status_register()& mask_e_err2)!= mask_e_err2) {
			printf("ERASE ERROR do not occur. Check status register for more details.\n");
			return 0;
		}

		printf("Erase Error as erase is not allow during sector is protected!\n");

		clear_flag_status_register(); // clear erase error bit


			//UNPROTECT ALL SECTORS IN CONFIGURATION DEVICE
		printf("Now perform sector unprotect...\n");
		write_enable();



		if ((read_status_register() & mask_wel2) != mask_wel2) { //check if write enable latch is set
			printf("Sector erase cannot be executed as write enable latch do not set\n");
			return 0;
		}

		write_register_for_sector_unprotect_micron();
		usleep(1000000);

		while ((read_status_register() & mask_wip2) == mask_wip2){
				//printf("Write register for sector unprotect in progress...\n");
				//usleep(1000);
		}

		if ((read_status_register()| mask_sr2) != mask_sr2) {
			printf("Sector unprotect not successful! :(\n");
			printf("Status Register: %08x\n",read_status_register());
			printf("Status Register: %08x\n",read_flag_status_register());
			return 0;
		}
		printf("Sector unprotect successfully! :) \n");


			//READ AND WRTIE DATA

		printf("Reading data at address 0...\n");
		printf("Memory content at address 0: %x\n",read_memory());


		if (read_memory()!= empty_data2) {

		//PERFORM SECTOR ERASE to clear sector 0
			printf("Address 0 containing data, it is not empty.\n");
			printf("Trying to erase sector 0...\n");


			write_enable();

			if ((read_status_register()& mask_wel2) != mask_wel2) { //check if write enable latch is set
				printf("Sector erase cannot be executed as write enable latch do not set\n");
				return 0;
			}

			erase_sector_micron();


			while ((read_status_register() & mask_wip2) == mask_wip2){
					//printf("Erase sector in progress...\n");
					//usleep(1000);
			}

			if (read_memory()!= empty_data2) {
				printf("Sector erase failed. Sector 0 is still having data.\n");
			}
			 printf("Sector erase successfully. Sector 0 is now empty.\n");
		}

			//WRITE DATA INTO EMPTY MEMORY

		printf("Address 0 not containing data...\n");

		printf("Writing data to address 0...\n");

		write_memory();
		usleep(1000000);



		while ((read_status_register() & mask_wip2) == mask_wip2){
				//printf("Write data in progress...\n");
			usleep(1000000);
		}
			//READ BACK DATA

		printf("Read back data from address 0...\n");

		int data1 = 0xabcd1234;

		if(read_memory() != data1) {
			printf("Current memory in address 0: %x\n",read_memory());
			printf("Something is wrong...");
			return 0;
		}
		printf("Current memory in address 0: %x\n",read_memory());
		printf("Read data match with data written. Write memory successful.\n");

		printf("Now performing sector protection...\n");

		write_enable();

		write_status_register_for_block_protect_micron();
		usleep(1000000);


			//int mask_wip = 0x00000001; //set mask to check Write in Progress (WIP) bit to determine device busy or ready
		while ((read_status_register() & mask_wip2) == mask_wip2) {
				//printf("Write register for sector protect in progress...\n");
				//usleep(1000);

		}

			//Check Status Register to see whether it is set to perform sector protect

			//int block_protect_sr = 0x0000007c; //set BP3-0 and TB bit in status register to protect all sectors


		if ((read_status_register() & block_protect_sr_m) != block_protect_sr_m) {
			printf("Setor protection failed due to error in setting status register\n");
			printf("Status Register: %08x\n",read_status_register());
			printf("Check datasheet to find out");
			return 0;
		}

		printf("All sectors in this configuration device is now successfully protected\n");

			//PERFORM SECTOR ERASE ON PROTECTED SECTOR
			//int mask_wel = 0x00000002; //set mask to check write enable latch
		write_enable();

		if ((read_status_register()& mask_wel2) != mask_wel2) { //check if write enable latch is set
			printf("Sector erase cannot be executed as write enable latch do not set\n");
			return 0;
		}

		printf("Trying to erase sector 0...\n");
		erase_sector_micron();

		while ((read_status_register() & mask_wip2) == mask_wip2){   //wait sector erase to end before proceed to next
				//printf("Sector erase in progress...\n");
				//usleep(1000);
		}


			//int mask_e_err = 0x00000020; //set mask to check protection error bit
		if ((read_status_register()& mask_e_err2)!= mask_e_err2) {
			printf("ERASE ERROR do not occur. Check status register for more details.\n");
			return 0;
		}
		printf("ERASE ERROR as sector is protected!\n");
		clear_flag_status_register(); //clear erase error bit

		if(read_memory() == data1) {
			printf("Current memory in address 0: %x\n",read_memory());
			printf("Read data match with data written previously. Sector erase does not perform during sector is protected.");
		} else {
			printf("Current memory in address 0: %x\n",read_memory());
			printf("Something is wrong...");
			return 0;
		}
#endif
		read_gflish_data();
	}

}

void	read_gflish_data()
{
	FILE	*fp=NULL;
	int		i,j;
	int		rddata;
	char 	buffer[4];


	fp = fopen("/mnt/host/epcql256.bin", "w");

	for(i = 0; i < 278435456; i+=4){
		rddata = read_memory(i);
		for(j=0; j < 4; j++){
			buffer[j] = (rddata >> j) & 0xff;
		}
		fputs(buffer, fp);
	}
	fclose(fp);

}
















