/***************************************************************
	CPUバス初期化処理
***************************************************************/

//#include <stdarg.h>

/* CPU固有レジスタ定義ヘッダ */
//#include "cpu.h"
#include "SH7262.h"

/* CPU初期化/割り込み制御関数ヘッダ */
#include "cpu_init.h"

/* FatFs関数ヘッダ */
#include "diskio.h"
#include "ff.h"


volatile int IntCount;
volatile int SysTimer;	// とりあえずのTimer代わり（GealEngine用）



/*---------------------------------------------------------*/
/* FatFsモジュール サンプルプログラム (C)T.AKAMATSU, 2010  */
/*---------------------------------------------------------*/
#define	_USE_FAT	// 使用時にdefineすること KOU


//BYTE Buff[32768];			/* データバッファ */

volatile UINT Timer;		/* パフォーマンスタイマ (1kHz加算) */


/* CPU固有初期化処理 */
void CPU_BusInitialize()
{
	/* クロック設定 */
	FRQCR  = 0x1104;	/* Bφ=48M Iφ=144M Pφ=24M */
}


/* CPU割り込み初期化処理 */
void CPU_IRQInitialize(void)
{
	/* 外部割り込み入力有効 */
//	*PECR0 = (*PECR0 & 0x0000) | 0x3333; /* IRQ3〜0 */

	/* 割り込みレベル設定(0:最低 15:最高) */
	/*       IRQ0     IRQ1     IRQ2   IRQ3 */
//	*IPR01 = (15<<12)|(15<<8)|(15<<4)| 15;
	/* 割り込み入力信号設定(0:'L'レベル) */
	/* 割り込み入力信号設定(1:立ち下りエッジ) */
	/* 割り込み入力信号設定(2:立ち上りエッジ) */
	/*       IRQ3     IRQ2     IRQ1   IRQ0 */
//	*ICR1  = ( 2<<6)|( 2<<4)|( 1<<2)| 1;

	/* エッジ割り込み設定時 */
#ifndef	_ORG		//  PushSwから追加
	/* 割り込み要求クリア(エッジ割り込み設定時のみ) */
	IRQRR = 0x00F0;	/* IRQ3〜0クリア */
#else
//	*IRQRR = 0x00F0;	/* IRQ3〜0割り込みクリア */
#endif

}

/* CPU割り込み処理 */
void CPU_IRQInterrupt(void)
{
	int stat;
	stat = IRQRR;
//	if (stat & 1) { /* IRQ0割り込み発生 */
//	if (stat & 2) { /* IRQ1割り込み発生 */
//	if (stat & 4) { /* IRQ2割り込み発生 */
//	if (stat & 8) { /* IRQ3割り込み発生 */

		/* 割り込み処理関数呼び出し */

//	}
	/* 割り込み要求クリア(エッジ割り込み設定時のみ) */
	IRQRR = 0x00F0;	/* IRQ3〜0クリア */
}


/* DMA転送実行 */
void CPU_DMAtransfer(unsigned int sar, unsigned int dar, unsigned int word)
{
	unsigned int stat;

//	if (word == 0) return;

//	*DMA_SAR = sar;
//	*DMA_DAR = dar;
//	*DMA_TCR = word;
	SAR_15 = sar ;
	DAR_15 = dar ;
	DMATCR_15 = word;
	/* TC=1,先元アドレス増加,オートリクエスト,TB=1,TS=10,DMA起動 */
//	DMA_CHCR= 0x80005431;
//	DMA_DMAOR = 1;
	CHCR_15= 0x80005431;
	DMAOR = 1;
	while(1){
//		if (DMA_CHCR & 2) {
//			DMA_CHCR= 0x80005430;
		if (CHCR_15 & 2) {
			CHCR_15 = 0x80005430;
			break;
		}
	}
	/* ↑バースト転送かつポーリングで完了待ち */
	/* マルチタスク処理時は要改良 */
}



/* 割り込み許可(CPU割り込み受け付けレベル14固定/多重割り込み無し) */
void CPU_EnableInterrupt(void)
{
	int IntLvOld;
	int IntLvNew;
	asm volatile ("stc sr,%0" : "=r" (IntLvOld));
	IntLvNew = (IntLvOld & ~0xF0) | (14<<4);
	asm volatile ("ldc %0,sr" : : "r" (IntLvNew));
}

/* 割り込み禁止(CPU割り込み受け付けレベル14固定/多重割り込み無し) */
int CPU_DisableInterrupt(void)
{
	int IntLvOld;
	int IntLvNew;
	asm volatile ("stc sr,%0" : "=r" (IntLvOld));
	IntLvNew = IntLvOld | 0xF0;
	asm volatile ("ldc %0,sr" : : "r" (IntLvNew));
	return IntLvOld;
}


/*==============================================================================
	LCD拡張ボード搭載タッチパネル制御 
==============================================================================*/

/* CPU基板上LED点灯制御初期化 */
void LED_Initialize(void)
{
	/* ポートC8 出力設定 */
	PCDR0  = PCDR0  & 0xFFFF;	/* PC8='H' */
	PCIOR0 = PCIOR0 | 0x100;	/* PC8=出力 */
	PCCR2  = PCCR2  & 0xFFF0;	/* ポート選択 */
}

/* CPU基板上LED点灯制御 */
void LED_Ctrl(int i)
{
	if (i) PCDR0 = PCDR0 & 0xFEFF; /* PC8='L'(点灯) */
	else   PCDR0 = PCDR0 | 0x0100; /* PC8='H'(消灯) */
}

/* コンペアマッチタイマ0 初期化 */
void CMT0_Initialize(void)
{
	/* CMTイネーブル */
	STBCR7 = STBCR7 & 0xFB;

	SysTimer = IntCount = 0;

	/* コンペアマッチタイマ0 割り込みレベル15 */
	IPR10 = (IPR10 & 0xFF0F) | (15 << 4);

	CMSTR  = 0;	/* カウント停止 */
	/* 割り込みイネーブル Pφ/32分周 */
	CMCSR_0 = 0x0041;
	CMCNT_0 = 0;
	CMCOR_0 = 1923;	/* 2.5ms */
	CMSTR  = 1;	/* チャネル0カウント開始 */

	/* CPU基板上LED点灯制御初期化 */
	LED_Initialize();
	/* CPU基板上LED点灯制御 */
	LED_Ctrl(1);	/* 点灯 */
}

/* コンペアマッチタイマ0 周期再設定 */
void CMT0_TimerSet(int i)
{
	CMSTR  = 0;	/* カウント停止 */
	if (i <= 0) i = 1;
	CMCNT_0 = 0;
	CMCOR_0 = 1923*i; /* 2.5ms×n倍 */
	CMSTR  = 1;	/* チャネル0カウント開始 */
}


/* ms単位のディレイ */
void delay_ms (	UINT ms )
{
	ms = ms * 2/5  ;	//現在2.5msなので
	for (Timer = 0; Timer < ms; ) ;
}

/* コンペアマッチタイマ0 割り込み処理 */
void CMT0_Interrupt(void)
{
	unsigned short int sts;
#ifdef	_USE_FAT
	static int div10 ;
#endif

	/* タッチパネル割り込み処理 */
	TOUCH_Interrupt();

	/* 割り込みクリア */
	sts = CMCSR_0;
	CMCSR_0 = 0x0041;

	SysTimer++ ;
	IntCount++;
	if (IntCount == 40) {
		LED_Ctrl(0);	/* 消灯 */
	}
	if (IntCount >= 80) {
		LED_Ctrl(1);	/* 点灯 */
		IntCount=0;
	}

#ifdef	_USE_FAT
	Timer++;

//	if (++div10 >= 10) {	// Original
	if (++div10 >= 4) {
		div10 = 0;
		/* ディスク制御タイマ (100Hz) だが、現在2.5msだからx4 */
		disk_timerproc();
	}
#endif
}


/*============================================================
	cq_sh7262_gcc main.c より
============================================================*/
/*==============================================================================
	Fat関連
	FatFsモジュール サンプルプログラム (C)T.AKAMATSU, 2010  より
==============================================================================*/

DWORD acc_size;				/* ワーク変数 (fsコマンド) */
WORD acc_files, acc_dirs;

FILINFO Finfo;				/* ワーク変数 (fs/flコマンド) */
#if _USE_LFN
char Lfname[_MAX_LFN + 1];
#endif

FATFS Fatfs;				/* ファイルシステムオブジェクト */
FIL File1, File2;			/* ファイルオブジェクト */
DIR Dir;					/* ディレクトリオブジェクト */

#define	xputs	CPU_UartPuts
#define	xputc	CPU_UartPutch

#define	scif2_test	CPU_UartRecvCheck
#define	scif2_get	CPU_UartGetch

#define	xprintf	t_printf

/*----------------------------------------------------*/
/* 現在時刻取得関数                                   */
/*----------------------------------------------------*/
/* FatFsから呼ばれる下位レイヤ関数の一つで、現在時刻を
/  DWORD値にパッキングして返す。Read only構成では不要。
*/

DWORD get_fattime(void)
{
	/* RTC機能無し。固定値を返す 2010/4/26 0:00:00 */
	return	  ((DWORD)(2010 - 1980) << 25)	/* Y */
			| ((DWORD)4  << 21)				/* M */
			| ((DWORD)26 << 16)				/* D */
			| ((DWORD)0  << 11)				/* H */
			| ((DWORD)0  << 5)				/* M */
			| ((DWORD)0  >> 1);				/* S */
}



/*--------------------------------------------------------------------------*/
/* モニタ                                                                   */
/*--------------------------------------------------------------------------*/
/* ディレクトリの中を調べる */
/* パス名ワークエリアへのポインタ */
static FRESULT scan_files( char* path )
{
	DIR dirs;
	FRESULT res;
	BYTE i;
	char *fn;

	res = f_opendir(&dirs, path);	/* ディレクトリを開く */
	if (res == FR_OK) {
		i = xstrlen(path);
		while (((res = f_readdir(&dirs, &Finfo)) == FR_OK) && Finfo.fname[0]) {	/* ディレクトリ項目読み出し*/
			if (_FS_RPATH && Finfo.fname[0] == '.') continue;	/* ドットエントリは棄てる */
#if _USE_LFN
			fn = *Finfo.lfname ? Finfo.lfname : Finfo.fname;	/* LFNがあるときはそれを使う */
#else
			fn = Finfo.fname;	/* 非LFN構成では常にSFN */
#endif
			if (Finfo.fattrib & AM_DIR) {	/* ディレクトリ */
				acc_dirs++;									/* ディレクトリ数++ */
				*(path+i) = '/'; xstrcpy(path+i+1, fn);		/* そのディレクトリの中をさらに辿る */
				res = scan_files(path);
				*(path+i) = '\0';
				if (res != FR_OK) break;
			} else {
				/* ファイル名 */
				xprintf("[%s/%s]\n", path, fn); 
				acc_files++;								/* ファイル数++ */
				acc_size += Finfo.fsize;					/* ファイルサイズの積算(バイト単位) */
			}
		}
	}

	return res;
}

/* ファイル関数のリザルトコードを省略形とともに表示 */
static void put_rc(	FRESULT rc )
{
	const char *str =
		"OK\0" "DISK_ERR\0" "INT_ERR\0" "NOT_READY\0" "NO_FILE\0" "NO_PATH\0"
		"INVALID_NAME\0" "DENIED\0" "EXIST\0" "INVALID_OBJECT\0" "WRITE_PROTECTED\0"
		"INVALID_DRIVE\0" "NOT_ENABLED\0" "NO_FILE_SYSTEM\0" "MKFS_ABORTED\0" "TIMEOUT\0"
		"LOCKED\0" "NOT_ENOUGH_CORE\0" "TOO_MANY_OPEN_FILES\0";
	FRESULT i;

	for (i = 0; i != rc && *str; i++) {
		while (*str++) ;
	}
	xprintf("rc=%u FR_%s\n", (UINT)rc, str);
}


/* ドライブステータスの表示 */
static void show_disk_status ( BYTE drv )
{
	DWORD dw;
	WORD w;
	BYTE b, buf[64];
	char *ty, *am;

	if (disk_ioctl(drv, GET_SECTOR_COUNT, &dw) == RES_OK)
		xprintf("Drive size: %lu sectors\n", dw);
	else
		xputs("GET_SECTOR_COUNT Error\n") ;

	if (disk_ioctl(drv, GET_SECTOR_SIZE, &w) == RES_OK)
		xprintf("Sector size: %u\n", w);
	else
		xputs("GET_SECTOR_SIZE Error\n") ;

	if (disk_ioctl(drv, GET_BLOCK_SIZE, &dw) == RES_OK)
		xprintf("Erase block size: %lu sectors\n", dw);
	else
		xputs("GET_BLOCK_SIZE Error\n") ;

	if (disk_ioctl(drv, MMC_GET_TYPE, &b) == RES_OK) {
		ty = "Unknown"; am = "";
		if (b & CT_MMC) ty = "MMC";
		if (b & CT_SD1) ty = "SDv1";
		if (b & CT_SD2) {
			ty = "SDv2";
			am = (b & CT_BLOCK) ? "(Block)" : "(Byte)";
		}
		xprintf("Card type: %s%s\n", ty, am);
	}
	else
		xputs("MMC_GET_TYPE Error\n") ;

	if (disk_ioctl(drv, MMC_GET_CSD, buf) == RES_OK) {
		xputs("CSD:\n"); put_dump(buf, 0, 16);
	}
	else
		xputs("MMC_GET_CSD Error\n") ;

	if (disk_ioctl(drv, MMC_GET_CID, buf) == RES_OK) {
		xputs("CID:\n"); put_dump(buf, 0, 16);
	}
	else
		xputs("MMC_GET_CID Error\n") ;

	if (disk_ioctl(drv, MMC_GET_OCR, buf) == RES_OK) {
		xputs("OCR:\n"); put_dump(buf, 0, 4);
	}
	else
		xputs("MMC_GET_OCR Error\n") ;

	if (disk_ioctl(drv, MMC_GET_SDSTAT, buf) == RES_OK) {
		xputs("SD Status:\n");
		for (w = 0; w < 64; w += 16)
			put_dump(buf+w, w, 16);
	}
	else
		xputs("MMC_GET_SDSTAT Error\n") ;
}



/* ボリュームステータスの表示 */

static void show_fs_status( char *path )
{
	FRESULT res;
	DWORD dw;
	FATFS *fs;
	static const BYTE ft[] = {0, 12, 16, 32};

#if !_FS_READONLY
	res = f_getfree(path, &dw, &fs);
	if (res != FR_OK) {
		 put_rc(res);
		 return ;
	}
#endif
	xprintf("FAT type = FAT%u\n", ft[fs->fs_type & 3]);
	xprintf("Bytes/Cluster = %lu\nNumber of FATs = %u\n", fs->csize * 512UL, fs->n_fats);
	if (fs->fs_type != FS_FAT32) xprintf("Root DIR entries = %u\n", fs->n_rootdir);
	xprintf("Sectors/FAT = %lu\nNumber of clusters = %lu\n", fs->fsize, fs->n_fatent - 2);
	xprintf("FAT start (lba) = %lu\nDIR start (lba,clustor) = %lu\nData start (lba) = %lu\n...\n",
			fs->fatbase, fs->dirbase, fs->database);

	acc_size = acc_files = acc_dirs = 0;
	res = scan_files(path);
	if (res == FR_OK) {
		xprintf("\r   \n%u files, %lu bytes.\n%u folders.\n"
				"%lu KB total disk space.\n%lu KB available.\n",
				acc_files, acc_size, acc_dirs,
				(fs->n_fatent - 2) * (fs->csize / 2), dw * (fs->csize / 2)
		);
	} else {
		 put_rc(res);
	}
}


/*============================================================
	FS関連関数
============================================================*/
void init_fs( void )
{
#if _USE_LFN
	Finfo.lfname = Lfname;
	Finfo.lfsize = sizeof(Lfname);
#endif
}


int GetFileList( char* path, char *list, int fnamemax, int flistmax )
{
	int num ;
	FRESULT res;
	DIR dirs;
	char *fn;

	*list = '\0' ;

	if (disk_status(0) & STA_NODISK) return 0 ;
	if (disk_initialize(0) & STA_NOINIT) return 0 ;

	f_mount(0, &Fatfs);

	res = f_opendir(&dirs, path );	/* ディレクトリを開く */
	if (res != FR_OK) return 0 ;

	/* ディレクトリ項目読み出し*/
	num = 0 ;
	while (((res = f_readdir(&dirs, &Finfo)) == FR_OK) && Finfo.fname[0]) {	
		if (_FS_RPATH && Finfo.fname[0] == '.') continue;	/* ドットエントリは棄てる */
#if _USE_LFN
		fn = *Finfo.lfname ? Finfo.lfname : Finfo.fname;	/* LFNがあるときはそれを使う */
#else
		fn = Finfo.fname;	/* 非LFN構成では常にSFN */
#endif
		/* ディレクトリならパス */
		if (Finfo.fattrib & AM_DIR) continue ;

		/* ファイル名 Get */
		xprintf("[%s/%s]\n", path, fn); 
		xstrcpy( list + (fnamemax * num ), fn ) ;

		/* flist のMAX */
		if (++num >= flistmax ) break ;
	}
	return num ;
}

/*============================================================
	SDカード test 
============================================================*/
void auto_test(void)	/* 自動テスト */
{
	char *p;
	BYTE res, buf[512];
	UINT i, c;

//	for (;;) {
		xputs("\n**** Insert a memory card then Type any key to start ****\n");
		c = 50;
		do {
			delay_ms(1);
			if (scif2_test()) {
				scif2_get();
//				xputs("Canceled.\n");
//				return;
			}
			if (disk_status(0) & STA_NODISK)
				c = 50;
		} while (--c);
		xputs("Card detected.\nInitializing...");

		if (disk_initialize(0) & STA_NOINIT) {
			xputs("failed.\n\n");
//			continue;
		}
		else xputs("succeeded.\n");

		xputs("\n\n---- Physical drive status ---------------------------------------------\n\n");

		show_disk_status(0);
/*
		xputs("\n\n---- Physical sector 0 (MBR) dump ------------------------------------\n\n");

		res = disk_read(0, buf, 0, 1);
		if (res == RES_OK) {
			for (i = 0; i < 0x200; i += 16)
				put_dump(buf+i, i, 16);
		} else {
			xprintf("rc=%u\n", res);
		}
*/
		xputs("\n\n---- FAT volume status ----------------------------------------------\n\n");

		f_mount(0, &Fatfs);
		p = (char*)buf;
		*p = 0;
		show_fs_status(p);
/*
		xputs("\n\n**** Remove memory card ****\n");
		c = 50;
		do {
			delay_ms(10);
			if (!(disk_status(0) & STA_NODISK))
				c = 50;
		} while (--c);
	}
*/
}



/*----------------------------------------------*/
/* Simple string functions                      */
/*----------------------------------------------*/
int xstrlen (const char *str)
{
	int n = 0;

	while (*str++) n++;
	return n;
}


char *xstrcpy(char* dst, const char* src)
{
	char c, *d = dst;

	do {
		c = *src++;
		*d++ = c;
	} while (c);

	*d = '\0' ;	// Add by KOU for terminator
	return dst;
}

/*----------------------------------------------*/
/* Dump a block of byte array                   */
/*----------------------------------------------*/

void put_dump (
	const void* buff,		/* Pointer to the byte array to be dumped */
	unsigned long addr,		/* Heading address value */
	int cnt					/* Number of bytes to be dumped */
)
{
	int i;
	const unsigned char *p = buff;


	xprintf("%08lX ", addr);		/* address */

	for (i = 0; i < cnt; i++)		/* data (hexdecimal) */
		xprintf(" %02X", p[i]);

	xputc(' ');
	for (i = 0; i < cnt; i++)		/* data (ascii) */
		xputc((p[i] >= ' ' && p[i] <= '~') ? p[i] : '.');

	xputc('\n');
}

