//------------------------------------------------------------------------------
//  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 "SifEtherCtrl.h"

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

#define ASSERT(cond)

extern CKernel *g_Kernel;

CSifEtherCtrl::CSifEtherCtrl(TEtherReg *etherReg, int txIntNo, int rxIntNo,
	int devNo)
{
	m_EtherReg = etherReg;
	m_TxIntNo = txIntNo;
	m_RxIntNo = rxIntNo;
	m_DevNo = devNo;

	InitializeCriticalSection(&m_Lock);

	m_SendTimer = -1;
	m_SendTerm = ecstIdle;
	m_RecvTimer = -1;
	m_RecvTerm = ecrtIdle;
	m_TxDsp = NULL;
	m_SendReq = false;
	m_SendBufPos = 0;
	m_RxDsp = NULL;
	m_RecvBuf = NULL;
	m_RecvBufPos = 0;

	// 初期値設定
	memset(m_EtherReg, 0, sizeof(*m_EtherReg));
	m_EtherReg->IPGT = 0x00000013;
	m_EtherReg->IPGR = 0x00000E13;
	m_EtherReg->CLRT = 0x0000380F;
	*((unsigned int *)&m_EtherReg->LMAX) = 0x00000600;
	*((unsigned int *)&m_EtherReg->INTMS) = 0x07000700;
	m_EtherReg->LSTTXDP = (TEtherDescriper *)0xFFFFFFFF;
	m_EtherReg->LSTRXDP = (TEtherDescriper *)0xFFFFFFFF;

	m_SendBuf = new unsigned char[m_EtherReg->LMAX.MAXF];
}

CSifEtherCtrl::~CSifEtherCtrl()
{
	TEtherCtrlDataNode *Node;

	while(!m_RecvQueue.empty()){
		// このブロックの終わりまで割り込み禁止
		Lock lock(this);

		// キューから次のメッセージを取得
		Node = m_RecvQueue.front();
		m_RecvQueue.pop_front();
		delete (unsigned char *)Node;
	}

	DeleteCriticalSection(&m_Lock);

	delete m_SendBuf;
}

unsigned char CSifEtherCtrl::GetByte(unsigned int Addr)
{
	throw 1;
}

void CSifEtherCtrl::SetByte(unsigned int Addr, unsigned char Value)
{
	throw 1;
}

unsigned short CSifEtherCtrl::GetUInt16(unsigned int Addr)
{
	throw 1;
}

void CSifEtherCtrl::SetUInt16(unsigned int Addr, unsigned short Value)
{
	throw 1;
}

unsigned int CSifEtherCtrl::GetUInt32(unsigned int Addr)
{
	unsigned int Value;
	unsigned int *Reg = (unsigned int *)m_EtherReg;
	int Index;

	Index = (int)Addr - (int)Reg;

	if((Index < 0) && (Index >= sizeof(TEtherReg))){
		throw 1;
	}

	Value = Reg[Index / sizeof(*Reg)];

	switch (Index)
	{
	case &((TEtherReg *)0)->MIIC:
		break;
	case &((TEtherReg *)0)->FSTATUS:
		m_EtherReg->FSTATUS = 0;
		break;
	case &((TEtherReg *)0)->TXSTATUS:
		*((unsigned int *)&m_EtherReg->TXSTATUS) = 0;
		break;
	case &((TEtherReg *)0)->RXSTATUS:
		*((unsigned int *)&m_EtherReg->RXSTATUS) = 0;
		break;
	case &((TEtherReg *)0)->INTMS:
		m_EtherReg->INTMS.RBEI = 0;
		m_EtherReg->INTMS.RECI = 0;
		m_EtherReg->INTMS.RXI = 0;
		m_EtherReg->INTMS.TBEI = 0;
		m_EtherReg->INTMS.TECI = 0;
		m_EtherReg->INTMS.TXI = 0;
		break;
	case &((TEtherReg *)0)->MRDD:
		((TEtherMRDDReg *)&Value)->PRSD = m_PhyReg[m_EtherReg->MADR.RGAD];
		break;
	default:
		break;
	}

	return Value;
}

void CSifEtherCtrl::SetUInt32(unsigned int Addr, unsigned int Value)
{
	unsigned int *Reg = (unsigned int *)m_EtherReg;
	int Index;

	Index = (int)Addr - (int)Reg;

	if((Index < 0) && (Index >= sizeof(TEtherReg))){
		throw 1;
	}

	switch (Index)
	{
	case &((TEtherReg *)0)->LMAX:
		{
			Lock lock(this);

			delete m_SendBuf;
			m_SendBuf = new unsigned char[((TEtherLMAXReg *)&Value)->MAXF];
		}
		break;
	case &((TEtherReg *)0)->LSA1:
		((unsigned short *)m_MacAddr)[2] = Value;
		break;
	case &((TEtherReg *)0)->LSA2:
		((unsigned int *)m_MacAddr)[0] = Value;
		break;
	case &((TEtherReg *)0)->MIIC:
		if(m_EtherReg->MIIC.MIRST != ((TEtherMIICReg *)&Value)->MIRST){
			m_MacReset = ((TEtherMIICReg *)&Value)->MIRST == 0;
		}
		break;
	case &((TEtherReg *)0)->MWTD:
		{
			unsigned short PhyReg = ((TEtherMWTDReg *)&Value)->CTLD;
			switch (m_EtherReg->MADR.RGAD)
			{
			// Basic Mode Control
			case 0:
				// Reset
				if((PhyReg & 0x8000) != 0)
				{
					PhyReg &= ~0x8000;
					m_PhyReg[1] = 0x7827;
				}
			default:
				break;
			}
			m_PhyReg[m_EtherReg->MADR.RGAD] = PhyReg;
		}
		break;
	case &((TEtherReg *)0)->RSTCNT:
		if(((TEtherRSTCNTReg *)&Value)->SFTRST == 1){
			m_FifoReset = true;
		}
		else if(((TEtherRSTCNTReg *)&Value)->RFFLSH == 1){
		}
		else if(((TEtherRSTCNTReg *)&Value)->TFFLSH == 1){
		}
		Value = 0;
		break;
	case &((TEtherReg *)0)->SFTRST:
		if(((TEtherSFTRSTReg *)&Value)->SFTRST == 1){
			m_SoftReset = true;
		}
		Value = 0;
		break;
	case &((TEtherReg *)0)->TRANSCTL:
		if(((TEtherTRANSCTLReg *)&Value)->TXEN == 0){
			((TEtherTRANSCTLReg *)&Value)->TXEN_STA = 0;
		}
		if(((TEtherTRANSCTLReg *)&Value)->RXEN == 0){
			((TEtherTRANSCTLReg *)&Value)->RXEN_STA = 0;
		}
		break;
	case &((TEtherReg *)0)->ETHMODE:
		if(((TEtherETHMODEReg *)&Value)->TXS != 0){
			// このブロックの終わりまで割り込み禁止
			Lock lock(this);

			m_SendReq = true;
			if(m_SendTerm == ecstIdle)
			{
				m_EtherReg->LSTTXDP = m_TxDsp;
				m_TxDsp = m_EtherReg->TXDP;
				m_SendTerm = ecstSend;
				m_SendTimer = 0;
				g_Kernel->OnSetEvent();
			}
		}
		if(((TEtherETHMODEReg *)&Value)->RXS != 0){
			// このブロックの終わりまで割り込み禁止
			Lock lock(this);
			if(m_RecvTerm != ecrtRecv)
			{
				m_EtherReg->LSTRXDP = m_RxDsp;
				m_RxDsp = m_EtherReg->RXDP;

				if((m_RecvBuf != NULL) && (m_RecvTerm == ecrtIdle)){
					m_RecvTerm = ecrtRecv;
					m_RecvTimer = 0;
					g_Kernel->OnSetEvent();
				}
			}
		}
		Value = 0;
		break;
	case &((TEtherReg *)0)->INTMS:
		Value &= 0x07000700;
		break;
	}

	Reg[Index / sizeof(*Reg)] = Value;

	return;
}

__int64 CSifEtherCtrl::GetTimer()
{
	__int64 timer = m_SendTimer;
	__int64 timer2 = m_RecvTimer;

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

	return timer;
}

void CSifEtherCtrl::Progress(__int64 Timer)
{
	if(m_SendTimer != -1){
		m_SendTimer -= Timer;
		if(m_SendTimer < 0){
			m_SendTimer = 0;
		}
	}
	if(m_RecvTimer != -1){
		m_RecvTimer -= Timer;
		if(m_RecvTimer < 0){
			m_RecvTimer = 0;
		}
	}
}

void CSifEtherCtrl::CallTimeOut(__int64 Frequency)
{
	CallSendTimeOut(Frequency);
	CallRecvTimeOut(Frequency);
}

void CSifEtherCtrl::CallSendTimeOut(__int64 Frequency)
{
	if(m_SendTimer != 0)
		return;

	// このブロックの終わりまで割り込み禁止
	Lock lock(this);

	switch(m_SendTerm){
	case ecstIdle:
		break;
	case ecstSend:
		for(;;){
			if(m_TxDsp == NULL)
			{
				m_EtherReg->INTMS.TECI = 1;
				if(g_Kernel->KernelFlag())
					g_Kernel->Interrupt(m_TxIntNo);
				m_SendTerm = ecstTxInt;
				m_SendTimer = 1;
				return;
			}
			// バッファ・ディスクリプタ
			if(m_TxDsp->T == 0){
				// 送信済みのバッファ・ディスクリプタ
				if(m_TxDsp->U == 1)
				{
					m_EtherReg->LSTTXDP = m_TxDsp;
					m_TxDsp = NULL;
					m_EtherReg->INTMS.TECI = 1;
					// 送信終了
					if(g_Kernel->KernelFlag())
						g_Kernel->Interrupt(m_TxIntNo);
					m_SendTerm = ecstTxInt;
					m_SendTimer = 1;
				}
				else{
					m_SendReq = false;

					unsigned short len = m_TxDsp->Size;
					if(m_SendBufPos + len > m_EtherReg->LMAX.MAXF)
						len = m_EtherReg->LMAX.MAXF - m_SendBufPos;
					// 送信
					memcpy(&m_SendBuf[m_SendBufPos], m_TxDsp->Pointer, len);
					m_SendBufPos += len;
					if(m_TxDsp->E == 1){
						g_Kernel->Output(m_DevNo, m_SendBuf, m_SendBufPos);
						m_SendBufPos = 0;
					}
					if(len != m_TxDsp->Size){
						m_EtherReg->TXSTATUS.TGNT = 1;
						m_EtherReg->TXSTATUS.TAB = 1;
					}
					m_TxDsp->U = 1;
					m_TxDsp++;

					m_EtherReg->INTMS.TXI = 1;
					if(g_Kernel->KernelFlag())
						g_Kernel->Interrupt(m_TxIntNo);
					m_SendTerm = ecstTxInt;
					m_SendTimer = 1;
				}
				return;
			}
			// リンク・ポインタ
			else if(m_TxDsp->E == 0){
				m_EtherReg->LSTTXDP = m_TxDsp;
				m_TxDsp = (TEtherDescriper *)m_TxDsp->Pointer;
			}
			// エンド・オブ・チェイン
			else{
				m_EtherReg->LSTTXDP = m_TxDsp;
				m_TxDsp = NULL;
			}
		}
		break;
	case ecstTxInt:
		// 割り込み処理が終了するまでスレッドスイッチ
		if((g_Kernel->InterruptEnabled(m_TxIntNo) || g_Kernel->InProcIntr(m_TxIntNo)) && g_Kernel->KernelFlag()){
			m_SendTimer = 0;
			m_SendTerm = ecstTxInt;
			return;
		}
		break;
	default:
		return;
	}

	// 送信処理あり
	if(m_SendReq) {
		if((m_TxDsp == NULL) || (m_TxDsp->U != 0)){
			m_EtherReg->LSTTXDP = m_TxDsp;
			m_TxDsp = m_EtherReg->TXDP;
		}
		m_SendTimer = 1;
		m_SendTerm = ecstSend;
	}
	else{
		m_SendTimer = -1;
		m_SendTerm = ecstIdle;
	}
}

void CSifEtherCtrl::CallRecvTimeOut(__int64 Frequency)
{
	if(m_RecvTimer != 0)
		return;

	// このブロックの終わりまで割り込み禁止
	Lock lock(this);

	switch(m_RecvTerm){
	case ecrtIdle:
		break;
	case ecrtRecv:
		for(;;){
			if(m_RxDsp == NULL)
			{
				m_EtherReg->INTMS.RECI = 1;
				if(g_Kernel->KernelFlag())
					g_Kernel->Interrupt(m_RxIntNo);
				m_RecvTerm = ecrtRxInt;
				m_RecvTimer = 1;
				return;
			}
			// バッファ・ディスクリプタ
			if(m_RxDsp->T == 0){
				// 受信済みのバッファ・ディスクリプタ
				if(m_RxDsp->U == 1)
				{
					m_EtherReg->LSTRXDP = m_RxDsp;
					m_RxDsp = NULL;
					m_EtherReg->INTMS.RECI = 1;
					// 受信終了
					if(g_Kernel->KernelFlag())
						g_Kernel->Interrupt(m_RxIntNo);
					m_RecvTerm = ecrtRxInt;
					m_RecvTimer = 1;
				}
				else{
					unsigned int len = m_RxDsp->Size;
					if(len > (m_RecvBuf->Size - m_RecvBufPos))
						len = m_RecvBuf->Size - m_RecvBufPos;
					m_RxDsp->Size = len;
					// 受信
					memcpy(m_RxDsp->Pointer, &m_RecvBuf->Data[m_RecvBufPos], len);
					m_RecvBufPos += len;
					if(m_RecvBufPos >= m_RecvBuf->Size){
						delete m_RecvBuf;
						if(m_RecvQueue.empty()){
							m_RecvBuf = NULL;
						}
						else{
							m_RecvBuf = m_RecvQueue.front();
							m_RecvQueue.pop_front();
						}
						m_RecvBufPos = 0;

						m_RxDsp->E = 1;
					}
					m_RxDsp->U = 1;
					m_RxDsp->Status = 0;
					m_RxDsp->S = 1;
					m_RxDsp++;

					m_EtherReg->INTMS.RXI = 1;
					if(g_Kernel->KernelFlag())
						g_Kernel->Interrupt(m_RxIntNo);
					m_RecvTerm = ecrtRxInt;
					m_RecvTimer = 1;
				}
				return;
			}
			// リンク・ポインタ
			else if(m_RxDsp->E == 0){
				m_EtherReg->LSTRXDP = m_RxDsp;
				m_RxDsp = (TEtherDescriper *)m_RxDsp->Pointer;
			}
			// エンド・オブ・チェイン
			else{
				m_EtherReg->LSTRXDP = m_RxDsp;
				m_RxDsp = NULL;
			}
		}
		break;
	case ecrtRxInt:
		// 割り込み処理が終了するまでスレッドスイッチ
		if((g_Kernel->InterruptEnabled(m_RxIntNo) || g_Kernel->InProcIntr(m_RxIntNo)) && g_Kernel->KernelFlag()){
			m_RecvTimer = 0;
			m_RecvTerm = ecrtRxInt;
			return;
		}
		break;
	default:
		return;
	}

	// 受信処理あり
	if((m_RecvBuf != NULL) && (m_RxDsp != NULL) && (m_RxDsp->U == 0)){
		m_RecvTimer = 1;
		m_RecvTerm = ecrtRecv;
	}
	else{
		m_RecvTimer = -1;
		m_RecvTerm = ecrtIdle;
	}
}

void CSifEtherCtrl::Receive(const void *Data, int Size)
{
	if(m_EtherReg->TRANSCTL.RXEN == 0)
		return;

	static const unsigned char BrodcastAddr[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
	TEtherCtrlDataNode *Node = (TEtherCtrlDataNode *)new unsigned char[(int)&((TEtherCtrlDataNode *)0)->Data + Size];

	Node->Size = Size;
	memcpy((unsigned char *)&Node->Data, Data, Size);

	bool recv = (m_EtherReg->AFR.PRO == 1);

	// MACアドレスを確認
	if(!recv
		&& (memcmp(Node->EthernetData.DstAddr, m_MacAddr, sizeof(m_MacAddr)) == 0))
	{
		recv = true;
	}

	// ブロードキャストアドレスを確認
	if(!recv && (m_EtherReg->AFR.ABC == 1)
		&& (memcmp(Node->EthernetData.DstAddr, BrodcastAddr, sizeof(BrodcastAddr)) == 0))
	{
		recv = true;
	}

	if(!recv)
	{
		delete Node;
		return;
	}

	// このブロックの終わりまで割り込み禁止
	Lock lock(this);

	if(m_RecvBuf == NULL){
		m_RecvBuf = Node;
		m_RecvBufPos = 0;
	}
	else{
		// メッセージをキューイング
		m_RecvQueue.push_back(Node);
	}

	if(m_RecvTerm == ecrtIdle){
		m_RecvTimer = 1;
		m_RecvTerm = ecrtRecv;
		g_Kernel->OnSetEvent();
	}
}
