// rev 1.03
#include "stdafx.h"
#include "qbus_device.h"

QBUS_Device::QBUS_Device()
	: m_pCMNB(nullptr)
	, m_nState(MPI_WAIT_SYNC_SET)
	, m_nAddr(0)
	, m_bAdOut_Ena(false)
	, m_bRplyOut_Ena(false)
	, m_nRplyDelay(0)
	, bAddr_OK(false)
{
	m_IOPins.clear();
}


QBUS_Device::~QBUS_Device()
{
}


void QBUS_Device::RegisterDevice(CCommonBus *pCMNB)
{
	m_pCMNB = pCMNB;
	ASSERT(m_pCMNB);
	m_pCMNB->RegisterSignal(&m_PIN_nAD, CCommonBus::MPI_DATA_nAD);
	m_pCMNB->RegisterSignal(&m_PIN_nRPLY, CCommonBus::MPI_LINE_nRPLY);
}

void QBUS_Device::getMPI() //присваисваем значения MPI -> Mem
{
	m_IOPins.pin_ad   = ~LOWORD(m_pCMNB->GetSignal(CCommonBus::MPI_DATA_nAD));      //inout[15:0]   // inverted address/data bus
	m_IOPins.pin_sync = !m_pCMNB->GetSignal(CCommonBus::MPI_LINE_nSYNC);    //input         // address strobe
	m_IOPins.pin_din  = !m_pCMNB->GetSignal(CCommonBus::MPI_LINE_nDIN);     //input         // data input strobe
	m_IOPins.pin_dout = !m_pCMNB->GetSignal(CCommonBus::MPI_LINE_nDOUT);    //input         // data output strobe
	m_IOPins.pin_wtbt = !m_pCMNB->GetSignal(CCommonBus::MPI_LINE_nWTBT);    //input         // write/byte status
	m_IOPins.pin_init = !m_pCMNB->GetSignal(CCommonBus::MPI_LINE_nINIT);
}

void QBUS_Device::setMPI() //присваисваем значения Mem -> MPI
{
	m_pCMNB->SetSignalOE(&m_PIN_nAD, m_bAdOut_Ena, ~m_IOPins.pin_ad);
	m_pCMNB->SetSignalOE(&m_PIN_nRPLY, m_bRplyOut_Ena); //output  transaction reply
}


void QBUS_Device::IO_FSM()
{
	switch (m_nState)
	{
		case MPI_WAIT_SYNC_SET:    //ведущий при начале обмена устанавливает сигнал SYNC, а мы его тут ждём
		{
			if (m_IOPins.pin_sync)      //дождались
			{
				if (DecodeAddr())
				{
					//переходим в следующее состояние, ждём сигналов дин/доут
					//m_nState = m_IOPins.pin_wtbt ? MPI_WAIT_DOUT : MPI_WAIT_DIN; //это работает только для выборки каждый полутакт
					m_nState = MPI_WAIT_DIN_DOUT; //для выборки раз в такт нужен другой алгоритм, т.к. мы не успеваем прочесть верное значение wtbt
				}
				else
				{
					//если адрес не наш, то идём ожидать, окончания всего цикла
					m_nState = MPI_WAIT_SYNC_CLR;
				}
			}
			else
			{
				m_nAddr = m_IOPins.pin_ad;  //принимаем адрес
			}

			break;
		}

		case MPI_WAIT_SYNC_CLR: //ждём сброса SYNC, для конца записи
		{
			if (!m_IOPins.pin_sync)
			{
				m_bRplyOut_Ena = false; //освобождаем магистраль
				m_bAdOut_Ena = false;
				m_nState = MPI_WAIT_SYNC_SET; //и начинаем всё сначала
			}

			break;
		}

		case MPI_WAIT_DIN_DOUT:
		{
			if (m_IOPins.pin_din)   //дождались DIN
			{
				m_bAdOut_Ena = true;
				ReadOp();   //в ответ на DIN, выдаём данные

				if (m_nAddr != 0177716)
				{
					m_bRplyOut_Ena = true; //и RPLY, если это не регистры ВМ1. тут кроме 177716 и остальные регистры надо
				}

				m_nState = MPI_WAIT_DIN_CLR;   //переходим в следующее состояние, ждать сброса DIN
			}

			if (m_IOPins.pin_dout) //дождались DOUT
			{
				WriteOp();  //после DOUT сперва принимаем данные
				m_bRplyOut_Ena = true; //а затем выставляем RPLY
				m_nState = MPI_WAIT_DOUT_CLR;  //переходим в следующее состояние, ждать сброса DOUT
			}

			break;
		}

		case MPI_WAIT_DIN_CLR: //ждём сброса DIN
		{
			if (!m_IOPins.pin_din) //дождались
			{
				m_bRplyOut_Ena = false;  //в ответ на сброс DIN сбрасываем RPLY и ad
				m_bAdOut_Ena = false;
				m_IOPins.pin_ad = 0;
				m_nState = MPI_WAIT_SYNC_CLR_DIN; //идём ждать конца процедуры чтения
			}

			break;
		}

		case MPI_WAIT_SYNC_CLR_DIN: //ждём сброса SYNC, для конца чтения
		{
			if (!m_IOPins.pin_sync)
			{
				m_bRplyOut_Ena = false; //освобождаем магистраль
				m_nState = MPI_WAIT_SYNC_SET; //и начинаем всё сначала
			}
			else if (m_IOPins.pin_dout) //если вместо сброса SYNC вдруг установился DOUT - то это цикл чтение-модификация-запись
			{
				WriteOp();  //после DOUT сперва принимаем данные
				m_bRplyOut_Ena = true; //а затем выставляем RPLY
				m_nState = MPI_WAIT_DOUT_CLR;  //переходим в следующее состояние, ждать сброса DOUT
			}

			break;
		}

		case MPI_WAIT_DOUT_CLR: //ждём сброса DOUT
		{
			if (!m_IOPins.pin_dout) //дождались
			{
				m_bRplyOut_Ena = false;  //в ответ на сброс DOUT сбрасываем RPLY
				m_nState = MPI_WAIT_SYNC_CLR_DOUT;
			}

			break;
		}

		case MPI_WAIT_SYNC_CLR_DOUT:
		{
			if (!m_IOPins.pin_sync)
			{
				m_bRplyOut_Ena = false;      //освобождаем магистраль
				m_nState = MPI_WAIT_SYNC_SET; //и начинаем всё сначала
			}

			break;
		}
	}
}


void QBUS_Device::eval()
{
	getMPI();

	if (m_IOPins.pin_init)
	{
		InitOp();
	}
	else
	{
		IO_FSM();
	}

	setMPI();
}

