//------------------------------------------------------------------------------
//  TOPPERS/ASP Windows Debug Environment
//  Copyright (C) 2010-2013 Cores Co., Ltd. Japan
//------------------------------------------------------------------------------
// $Id: UnitSim.cs 115 2013-02-11 02:13:05Z nagasima $
#include "StdAfx.h"
#include "WinKernel.h"
#include "SifV850ESJX3E.h"
#include <time.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

extern CKernel *g_Kernel;

//------------------------------------------------------------------------------
// CSifV850ESJX3E
//	概要：
//	引数：
//	pKernel
//	戻り値：
//------------------------------------------------------------------------------
CSifV850ESJX3E::CSifV850ESJX3E(TV850Reg *CPUReg)
	: UARTC0(&CPUReg->UC0, PIC_NO_INTUC0T, PIC_NO_INTUC0R, -1),
		UARTC1(&CPUReg->UC1, PIC_NO_INTUC1T, PIC_NO_INTUC1R, -2),
		UARTC2(&CPUReg->UC2, PIC_NO_INTUC2T, PIC_NO_INTUC2R, -3),
		UARTC3(&CPUReg->UC3, PIC_NO_INTUC3T, PIC_NO_INTUC3R, -4),
		UARTC4(&CPUReg->UC4, PIC_NO_INTUC4T, PIC_NO_INTUC4R, -5),
		UARTC5(&CPUReg->UC5, PIC_NO_INTUC5T, PIC_NO_INTUC5R, -6),
		UARTC6(&CPUReg->UC6, PIC_NO_INTUC6T, PIC_NO_INTUC6R, -7),
		UARTC7(&CPUReg->UC7, PIC_NO_INTUC7T, PIC_NO_INTUC7R, -8),
		UARTB0(&CPUReg->UB0, PIC_NO_INTUB0TIT, PIC_NO_INTUB0TIR, -9),
		UARTB1(&CPUReg->UB1, PIC_NO_INTUB1TIT, PIC_NO_INTUB1TIR, -10)

{
	m_CPUReg = CPUReg;
	m_Lock = 0;
	m_Term = ttInterrupt;
	m_Timer = -1;

	for(int i = 0; i < sizeof(m_CPUReg->PIC) / sizeof(m_CPUReg->PIC[0]); i++){
		*(unsigned char *)&m_CPUReg->PIC[i] = 0x47;
	}
}

//------------------------------------------------------------------------------
//	概要：
//	引数：
//	戻り値：
//------------------------------------------------------------------------------
CSifV850ESJX3E::~CSifV850ESJX3E()
{
}

void CSifV850ESJX3E::OnTerminate()
{
}

unsigned char CSifV850ESJX3E::GetByte2(uintptr_t Addr)
{
	unsigned char *Reg = (unsigned char *)m_CPUReg;
	intptr_t Index;

	Index = Addr - (uintptr_t)Reg;

	if((Index < 0) || (Index >= sizeof(TV850Reg))){
		throw 1;
	}

	if((Index >= (intptr_t)&((TV850Reg *)0)->IMR[0])
		&& (Index <= (intptr_t)&((TV850Reg *)0)->IMR[7])){
		TPIC *pic = &m_CPUReg->PIC[8 * (Index - (intptr_t)&((TV850Reg *)0)->IMR[0])];
		unsigned char Value = pic[0].PMK;
		Value |= pic[1].PMK << 1;
		Value |= pic[2].PMK << 2;
		Value |= pic[3].PMK << 3;
		Value |= pic[4].PMK << 4;
		Value |= pic[5].PMK << 5;
		Value |= pic[6].PMK << 6;
		Value |= pic[7].PMK << 7;
		Reg[Index] = Value;
	}
	else if((Index >= (intptr_t)&((TV850Reg *)0)->UC0)
		&& (Index < (intptr_t)&(&((TV850Reg *)0)->UC0)[1])){
		return UARTC0.GetByte2(Index - (intptr_t)&((TV850Reg *)0)->UC0);
	}
	else if((Index >= (intptr_t)&((TV850Reg *)0)->UC1)
		&& (Index < (intptr_t)&(&((TV850Reg *)0)->UC1)[1])){
		return UARTC1.GetByte2(Index - (intptr_t)&((TV850Reg *)0)->UC1);
	}
	else if((Index >= (intptr_t)&((TV850Reg *)0)->UC2)
		&& (Index < (intptr_t)&(&((TV850Reg *)0)->UC2)[1])){
		return UARTC2.GetByte2(Index - (intptr_t)&((TV850Reg *)0)->UC2);
	}
	else if((Index >= (intptr_t)&((TV850Reg *)0)->UC3)
		&& (Index < (intptr_t)&(&((TV850Reg *)0)->UC3)[1])){
		return UARTC3.GetByte2(Index - (intptr_t)&((TV850Reg *)0)->UC3);
	}
	else if((Index >= (intptr_t)&((TV850Reg *)0)->UC4)
		&& (Index < (intptr_t)&(&((TV850Reg *)0)->UC4)[1])){
		return UARTC4.GetByte2(Index - (intptr_t)&((TV850Reg *)0)->UC4);
	}
	else if((Index >= (intptr_t)&((TV850Reg *)0)->UC5)
		&& (Index < (intptr_t)&(&((TV850Reg *)0)->UC5)[1])){
		return UARTC5.GetByte2(Index - (intptr_t)&((TV850Reg *)0)->UC5);
	}
	else if((Index >= (intptr_t)&((TV850Reg *)0)->UC6)
		&& (Index < (intptr_t)&(&((TV850Reg *)0)->UC6)[1])){
		return UARTC6.GetByte2(Index - (intptr_t)&((TV850Reg *)0)->UC6);
	}
	else if((Index >= (intptr_t)&((TV850Reg *)0)->UC7)
		&& (Index < (intptr_t)&(&((TV850Reg *)0)->UC7)[1])){
		return UARTC7.GetByte2(Index - (intptr_t)&((TV850Reg *)0)->UC7);
	}
	else if((Index >= (intptr_t)&((TV850Reg *)0)->UB0)
		&& (Index < (intptr_t)&(&((TV850Reg *)0)->UB0)[1])){
		return UARTB0.GetByte2(Index - (intptr_t)&((TV850Reg *)0)->UB0);
	}
	else if((Index >= (intptr_t)&((TV850Reg *)0)->UB1)
		&& (Index < (intptr_t)&(&((TV850Reg *)0)->UB1)[1])){
		return UARTB1.GetByte2(Index - (intptr_t)&((TV850Reg *)0)->UB1);
	}
	else if((Index >= (intptr_t)&((TV850Reg *)0)->RC1)
		&& (Index < (intptr_t)&(&((TV850Reg *)0)->RC1)[1])){
		TRCPort *RCPort = &m_CPUReg->RC1;
		__int64 now, freq;
		static __int64 prev = 0;

		g_Kernel->GetSystemTime(&now, &freq);

		bool update = (now - prev) > (freq / 1000);
		prev = now;

		if(update){
			if((Index >= (intptr_t)&((TV850Reg *)0)->RC1.SUBC)
				&& (Index < (intptr_t)&(&((TV850Reg *)0)->RC1.SUBC)[1])){
				__int64 subc = now % freq;
				RCPort->SUBC	= (32768 * subc) / freq;
			}
			else{
				time_t sec = now / freq;
				tm *tm = localtime(&sec);
				tm->tm_year -= 100;

				RCPort->SEC		= ((tm->tm_sec		/ 10) << 4) | (tm->tm_sec		% 10);
				RCPort->MIN		= ((tm->tm_min		/ 10) << 4) | (tm->tm_min		% 10);
				RCPort->HOUR	= ((tm->tm_hour		/ 10) << 4) | (tm->tm_hour		% 10);
				RCPort->WEEK	= tm->tm_wday;
				RCPort->DAY		= ((tm->tm_mday		/ 10) << 4) | (tm->tm_mday		% 10);
				RCPort->MONTH	= ((tm->tm_mon		/ 10) << 4) | (tm->tm_mon		% 10);
				RCPort->YEAR	= ((tm->tm_year		/ 10) << 4) | (tm->tm_year		% 10);
			}
		}
	}

	return Reg[Index];
}

void CSifV850ESJX3E::SetByte2(uintptr_t Addr, unsigned char Value)
{
	unsigned char *Reg = (unsigned char *)m_CPUReg;
	intptr_t Index;

	Index = Addr - (uintptr_t)Reg;

	if((Index < 0) || (Index >= sizeof(TV850Reg))){
		throw 1;
	}

	Reg[Index] = Value;

	// 受信バッファを読み込まれたら
	if((Index >= (intptr_t)&((TV850Reg *)0)->UC0)
		&& (Index < (intptr_t)&(&((TV850Reg *)0)->UC0)[1])){
		UARTC0.SetByte2(Index - (intptr_t)&((TV850Reg *)0)->UC0, Value);
	}
	else if((Index >= (intptr_t)&((TV850Reg *)0)->UC1)
		&& (Index < (intptr_t)&(&((TV850Reg *)0)->UC1)[1])){
		UARTC1.SetByte2(Index - (intptr_t)&((TV850Reg *)0)->UC1, Value);
	}
	else if((Index >= (intptr_t)&((TV850Reg *)0)->UC2)
		&& (Index < (intptr_t)&(&((TV850Reg *)0)->UC2)[1])){
		UARTC2.SetByte2(Index - (intptr_t)&((TV850Reg *)0)->UC2, Value);
	}
	else if((Index >= (intptr_t)&((TV850Reg *)0)->UC3)
		&& (Index < (intptr_t)&(&((TV850Reg *)0)->UC3)[1])){
		UARTC3.SetByte2(Index - (intptr_t)&((TV850Reg *)0)->UC3, Value);
	}
	else if((Index >= (intptr_t)&((TV850Reg *)0)->UC4)
		&& (Index < (intptr_t)&(&((TV850Reg *)0)->UC4)[1])){
		UARTC4.SetByte2(Index - (intptr_t)&((TV850Reg *)0)->UC4, Value);
	}
	else if((Index >= (intptr_t)&((TV850Reg *)0)->UC5)
		&& (Index < (intptr_t)&(&((TV850Reg *)0)->UC5)[1])){
		UARTC5.SetByte2(Index - (intptr_t)&((TV850Reg *)0)->UC5, Value);
	}
	else if((Index >= (intptr_t)&((TV850Reg *)0)->UC6)
		&& (Index < (intptr_t)&(&((TV850Reg *)0)->UC6)[1])){
		UARTC6.SetByte2(Index - (intptr_t)&((TV850Reg *)0)->UC6, Value);
	}
	else if((Index >= (intptr_t)&((TV850Reg *)0)->UC7)
		&& (Index < (intptr_t)&(&((TV850Reg *)0)->UC7)[1])){
		UARTC7.SetByte2(Index - (intptr_t)&((TV850Reg *)0)->UC7, Value);
	}
	else if((Index >= (intptr_t)&((TV850Reg *)0)->UB0)
		&& (Index < (intptr_t)&(&((TV850Reg *)0)->UB0)[1])){
		UARTB0.SetByte2(Index - (intptr_t)&((TV850Reg *)0)->UB0, Value);
	}
	else if((Index >= (intptr_t)&((TV850Reg *)0)->UB1)
		&& (Index < (intptr_t)&(&((TV850Reg *)0)->UB1)[1])){
		UARTB1.SetByte2(Index - (intptr_t)&((TV850Reg *)0)->UB1, Value);
	}
	// TimerM
	else if(Index == (intptr_t)&((TV850Reg *)0)->TM0){
		g_Kernel->OnSetEvent();
	}
	else if(Index == (intptr_t)&((TV850Reg *)0)->TM1){
		g_Kernel->OnSetEvent();
	}
	else if(Index == (intptr_t)&((TV850Reg *)0)->TM2){
		g_Kernel->OnSetEvent();
	}
	else if(Index == (intptr_t)&((TV850Reg *)0)->TM3){
		g_Kernel->OnSetEvent();
	}
	// 割り込みマスクレジスタ
	else if((Index >= (intptr_t)&((TV850Reg *)0)->IMR[0])
		&& (Index <= (intptr_t)&((TV850Reg *)0)->IMR[7])){
		TPIC *pic = &m_CPUReg->PIC[8 * (Index - (intptr_t)&((TV850Reg *)0)->IMR[0])];
		pic[0].PMK = Value;
		pic[1].PMK = (Value >> 1);
		pic[2].PMK = (Value >> 2);
		pic[3].PMK = (Value >> 3);
		pic[4].PMK = (Value >> 4);
		pic[5].PMK = (Value >> 5);
		pic[6].PMK = (Value >> 6);
		pic[7].PMK = (Value >> 7);
	}
}

unsigned char CSifV850ESJX3E::GetByte(uintptr_t Addr)
{
	unsigned char Result;

	Result = GetByte2(Addr);

	return Result;
}

void CSifV850ESJX3E::SetByte(uintptr_t Addr, unsigned char Value)
{
	SetByte2(Addr, Value);
}

unsigned short CSifV850ESJX3E::GetUInt16(uintptr_t Addr)
{
	unsigned short Result;

	((unsigned char *)&Result)[0] = GetByte2(Addr);
	((unsigned char *)&Result)[1] = GetByte2(Addr + 1);

	return Result;
}

void CSifV850ESJX3E::SetUInt16(uintptr_t Addr, unsigned short Value)
{
	SetByte2(Addr, ((unsigned char *)&Value)[0]);
	SetByte2(Addr + 1, ((unsigned char *)&Value)[1]);
}

unsigned int CSifV850ESJX3E::GetUInt32(uintptr_t Addr)
{
	unsigned int Result;

	((unsigned char *)&Result)[0] = GetByte2(Addr);
	((unsigned char *)&Result)[1] = GetByte2(Addr + 1);
	((unsigned char *)&Result)[2] = GetByte2(Addr + 2);
	((unsigned char *)&Result)[3] = GetByte2(Addr + 3);

	return Result;
}

void CSifV850ESJX3E::SetUInt32(uintptr_t Addr, unsigned int Value)
{
	SetByte2(Addr, ((unsigned char *)&Value)[0]);
	SetByte2(Addr + 1, ((unsigned char *)&Value)[1]);
	SetByte2(Addr + 2, ((unsigned char *)&Value)[2]);
	SetByte2(Addr + 3, ((unsigned char *)&Value)[3]);
}

__int64 CSifV850ESJX3E::GetTimer()
{
	__int64 timer = m_Timer;
	__int64 timer2 = UARTC0.GetTimer();

	if((timer == -1) || ((timer2 != -1) && (timer > timer2)))
		timer = timer2;

	timer2 = UARTC1.GetTimer();

	if((timer == -1) || ((timer2 != -1) && (timer > timer2)))
		timer = timer2;

	timer2 = UARTC2.GetTimer();

	if((timer == -1) || ((timer2 != -1) && (timer > timer2)))
		timer = timer2;

	timer2 = UARTC3.GetTimer();

	if((timer == -1) || ((timer2 != -1) && (timer > timer2)))
		timer = timer2;

	timer2 = UARTC4.GetTimer();

	if((timer == -1) || ((timer2 != -1) && (timer > timer2)))
		timer = timer2;

	timer2 = UARTC5.GetTimer();

	if((timer == -1) || ((timer2 != -1) && (timer > timer2)))
		timer = timer2;

	timer2 = UARTC6.GetTimer();

	if((timer == -1) || ((timer2 != -1) && (timer > timer2)))
		timer = timer2;

	timer2 = UARTC7.GetTimer();

	if((timer == -1) || ((timer2 != -1) && (timer > timer2)))
		timer = timer2;

	timer2 = UARTB0.GetTimer();
	if((timer == -1) || ((timer2 != -1) && (timer > timer2)))
		timer = timer2;

	timer2 = UARTB1.GetTimer();
	if((timer == -1) || ((timer2 != -1) && (timer > timer2)))
		timer = timer2;

	return timer;
}

void CSifV850ESJX3E::Progress(__int64 Timer)
{
	UARTC0.Progress(Timer);
	UARTC1.Progress(Timer);
	UARTC2.Progress(Timer);
	UARTC3.Progress(Timer);
	UARTC4.Progress(Timer);
	UARTC5.Progress(Timer);
	UARTC6.Progress(Timer);
	UARTC7.Progress(Timer);
	UARTB0.Progress(Timer);
	UARTB1.Progress(Timer);

	if(m_Timer == -1)
		return;

	m_Timer -= Timer;
	if(m_Timer < 0){
		m_Timer = 0;
	}
}

void CSifV850ESJX3E::CallTimeOut(__int64 Frequency)
{
	UARTC0.CallTimeOut(Frequency);
	UARTC1.CallTimeOut(Frequency);
	UARTC2.CallTimeOut(Frequency);
	UARTC3.CallTimeOut(Frequency);
	UARTC4.CallTimeOut(Frequency);
	UARTC5.CallTimeOut(Frequency);
	UARTC6.CallTimeOut(Frequency);
	UARTC7.CallTimeOut(Frequency);
	UARTB0.CallTimeOut(Frequency);
	UARTB1.CallTimeOut(Frequency);

	if((m_Timer == -1) && (m_CPUReg->TM0.CTL0.CE != 0))
		m_Timer = 0;

	if(m_Timer != 0)
		return;

	switch(m_Term){
	case ttInterrupt:
		g_Kernel->Interrupt(PIC_NO_INTTM0EQ0);
		m_Timer = 0;
		m_Term = ttWait;
		break;
	case ttWait:
		// Timer割り込み処理が終了するまでスレッドスイッチ
		if((g_Kernel->InterruptEnabled(PIC_NO_INTTM0EQ0) || g_Kernel->InProcIntr(PIC_NO_INTTM0EQ0)) && g_Kernel->KernelFlag()){
			m_Timer = 0;
			m_Term = ttWait;
			break;
		}
		TTMMPort *TM0 = &m_CPUReg->TM0;
		if(TM0->CTL0.CE != 0)
			m_Timer = ((TM0->CMP0 << TM0->CTL0.CKS) * Frequency) / g_Kernel->Frequency;
		else
			m_Timer = -1;
		m_Term = ttInterrupt;
		break;
	}
}

bool CSifV850ESJX3E::InterruptEnabled(int IntNo)
{
	return (m_CPUReg->PIC[IntNo].PIF != 0) && (m_CPUReg->PIC[IntNo].PMK == 0);
}

void CSifV850ESJX3E::ClearInterrupt(int IntNo)
{
	SpinLock();
	__try{
		m_CPUReg->PIC[IntNo].PIF = 0;
	}
	__finally{
		SpinUnlock();
	}
}

void CSifV850ESJX3E::SetInterrupt(int IntNo)
{
	SpinLock();
	__try{
		m_CPUReg->PIC[IntNo].PIF = 1;
	}
	__finally{
		SpinUnlock();
	}
}

unsigned int CSifV850ESJX3E::InterruptPriority(int IntNo)
{
	return m_CPUReg->PIC[IntNo].PPR;
}

void CSifV850ESJX3E::ChangeInterruptControlRegister(int IntNo, uint8_t icrcmd)
{
	*((unsigned char *)&m_CPUReg->PIC[IntNo]) = icrcmd;
}
