// rev 1.00
#include "stdafx.h"
#include "tboard.h"


tboard::tboard()
	: m_pCMNB(nullptr)
	, m_pCPU(nullptr)
	, m_pVP1037(nullptr)
	, m_pROMModule(nullptr)
	, m_pIRPS(nullptr)
	, m_nClk(0)
	, m_fdStartSeq(nullptr)
{
	for (int i = 0; i < 64 * 1024; ++i)
	{
		m_abReadAccess[i] = (i < (0100000 + MEM_SIZE10_B)) ? true : false;
	}

	for (int i = 0177560; i < 0177570; ++i)
	{
		m_abReadAccess[i] = true;
	}

	for (int i = 0177700; i < 0177720; ++i)
	{
		m_abReadAccess[i] = true;
	}
}

bool tboard::init()
{
	m_pScreen = new CScreen(1); //3 - D3D не работает.
	CRect rectScr(0, 40, 512 + GetSystemMetrics(SM_CXDLGFRAME) * 2, 384 + GetSystemMetrics(SM_CYSMCAPTION) + GetSystemMetrics(SM_CYDLGFRAME) * 2);

	if (m_pScreen == nullptr)
	{
		AfxMessageBox(_T("Не создался класс Экран"));
		return false;
	}

	if (!m_pScreen->CreateEx(WS_EX_TOOLWINDOW, nullptr, _T("BKScreen"), WS_VISIBLE | WS_POPUP | WS_OVERLAPPEDWINDOW, rectScr, nullptr, 0))
	{
		TRACE0("Не удалось создать панель Screen View\n");
		AfxMessageBox(_T("Не удалось создать панель Screen View"));
		return false;      // не удалось создать
	}

	m_pScreen->AdjustLayout();
	m_pCMNB = new CCommonBus();

	if (m_pCMNB)
	{
		m_pCMNB->RegisterSignal(&m_PIN_DCLO, CCommonBus::MPI_LINE_nDCLO);
		m_pCMNB->RegisterSignal(&m_PIN_ACLO, CCommonBus::MPI_LINE_nACLO);
		m_pCMNB->SetSignal(&m_PIN_DCLO, true); //далее инициализация стартовой последовательности
		m_pCMNB->SetSignal(&m_PIN_ACLO, true);
		//начальная инициализация процессора
		m_pCPU = new C1801VM1();

		if (m_pCPU)
		{
			m_pCPU->m_IOPins.pin_pa = 0; //номер процессора на шине (0..3)
			m_pCPU->m_IOPins.pin_sp = false; //резервный вход ВЕ-таймера
			m_pCPU->m_IOPins.pin_ena = true; //разрешающий сигнал
			m_pCPU->RegisterDevice(m_pCMNB);
		}
		else
		{
			return false;
		}

#if (BOARDMODEL11)
		m_pVP1037 = new CVP1_037_014_BK11();
		m_pROMModule = new QBUS_Memory11();
#else
		m_pVP1037 = new CVP1_037_014();
		m_pROMModule = new QBUS_Memory10();
#endif

		if (m_pROMModule)
		{
			m_pROMModule->RegisterDevice(m_pCMNB);
		}
		else
		{
			return false;
		}

		if (m_pVP1037)
		{
			m_pVP1037->RegisterDevice(m_pCMNB);
		}
		else
		{
			return false;
		}

		m_pIRPS = new QBUS_IRPS();

		if (m_pIRPS)
		{
			m_pIRPS->RegisterDevice(m_pCMNB);
		}
		else
		{
			return false;
		}
	}
	else
	{
		return false;
	}

	return true;
}

void tboard::AttachDebugger(CDebugger *pDbg)
{
	m_pCPU->AttachDebugger(pDbg);
	m_pVP1037->AttachDebugger(pDbg);
	m_pROMModule->AttachDebugger(pDbg);
	pDbg->AttachMemoryAccessMap(m_abReadAccess);
}

tboard::~tboard()
{
	if (m_pCMNB)
	{
		delete m_pCMNB;
	}

	if (m_pCPU)
	{
		delete m_pCPU;
	}

	if (m_pVP1037)
	{
		delete m_pVP1037;
	}

	if (m_pIRPS)
	{
		delete m_pIRPS;
	}

	if (m_pROMModule)
	{
		delete m_pROMModule;
	}

	if (m_pScreen)
	{
		m_pScreen->DestroyWindow();
	}

	SAFE_DELETE(m_pScreen);
}

void tboard::cpuInit()
{
	m_nClk = 0;
	m_pCMNB->SetSignal(&m_PIN_DCLO, false); //далее инициализация стартовой последовательности
	m_pCMNB->SetSignal(&m_PIN_ACLO, false);
	m_fdStartSeq = fastdelegate::MakeDelegate(this, &tboard::START_SEQ_0);
	m_nPhaseCounter = 16;    //минимум 8 тактов на начальную инициализацию, после которой можно снимать DCLO
}


void tboard::START_SEQ_0()
{
	if (--m_nPhaseCounter < 0)
	{
		m_pCMNB->SetSignal(&m_PIN_DCLO, true);  //снимаем DCLO
		m_fdStartSeq = fastdelegate::MakeDelegate(this, &tboard::START_SEQ_1);
		m_nPhaseCounter = 16;    //минимум 8 тактов, после чего можно снимать ACLO
	}
}

void tboard::START_SEQ_1()
{
	if (--m_nPhaseCounter < 0)
	{
		m_pCMNB->SetSignal(&m_PIN_ACLO, true);   //снимаем ACLO
		m_fdStartSeq = nullptr;
		m_nPhaseCounter = 16;
	}
}


int tboard::mainCycle()
{
	if (m_fdStartSeq)   //обработчик стартовой последовательности.
	{
		m_fdStartSeq();
	}

#if (OUT_CMNBUS_DBG_LOG)
	m_pCMNB->OutLog(m_nClk, "\\>");
#endif

	m_pCPU->eval_n(m_nClk); //отработаем передний фронт ТЧ

#if (OUT_CMNBUS_DBG_LOG)
	m_pCMNB->OutLog(m_nClk, "\\<");
#endif

	screenCycle();

#if !(ONE_CLK_PERIPHERY_PROCESSING)
	m_pIRPS->eval();
#endif

#if (OUT_CMNBUS_DBG_LOG)
	m_pCMNB->OutLog(m_nClk, "/>");
#endif

	m_pCPU->eval_p(m_nClk); //отработаем задний фронт ТЧ

#if (OUT_CMNBUS_DBG_LOG)
	m_pCMNB->OutLog(m_nClk, "/<");
#endif

	screenCycle();
	m_pIRPS->eval();
	m_pROMModule->eval();
	return m_nClk++;
}

void tboard::screenCycle()
{
	m_pVP1037->eval(m_nClk);

#if (OUT_CMNBUS_DBG_LOG)
	m_pCMNB->OutLog(m_nClk, "s>");
#endif

	m_pVP1037->memPostProc(m_pScreen);

#if (OUT_CMNBUS_DBG_LOG)
	m_pCMNB->OutLog(m_nClk, "m>");
#endif

	m_pVP1037->videoProc(m_pScreen);

#if (OUT_CMNBUS_DBG_LOG)
	m_pCMNB->OutLog(m_nClk, "v>");
#endif
}

int tboard::mainCycle_n()
{
	if (m_fdStartSeq)   //обработчик стартовой последовательности.
	{
		m_fdStartSeq();
	}

#if (OUT_CMNBUS_DBG_LOG)
	m_pCMNB->OutLog(m_nClk, "\\>");
#endif

	m_pCPU->eval_n(m_nClk); //отработаем передний фронт ТЧ

#if (OUT_CMNBUS_DBG_LOG)
	m_pCMNB->OutLog(m_nClk, "\\<");
#endif

	screenCycle();

#if !(ONE_CLK_PERIPHERY_PROCESSING)
	m_pIRPS->eval();
#endif

	return m_nClk;
}


int tboard::mainCycle_p()
{

#if (OUT_CMNBUS_DBG_LOG)
	m_pCMNB->OutLog(m_nClk, "/>");
#endif
	m_pCPU->eval_p(m_nClk); //отработаем задний фронт ТЧ
#if (OUT_CMNBUS_DBG_LOG)
	m_pCMNB->OutLog(m_nClk, "/<");
#endif
	screenCycle();
	m_pIRPS->eval();
	return m_nClk++;
}




