
#include "pch.h"
#include "resource.h"
#include "FDD_SMK512.h"

#include "Platform.h"
#include "BK001001.h"

// для AltPro, биты, кодирующие номер страницы
constexpr uint16_t BIT10 = 02000;
constexpr uint16_t BIT03 = 00010;
constexpr uint16_t BIT02 = 00004;
constexpr uint16_t BIT00 = 00001;

IMPLEMENT_DYNAMIC(CFDD_SMK512, CFDD_A16M)

CFDD_SMK512::CFDD_SMK512()
    = default;

CFDD_SMK512::~CFDD_SMK512()
    = default;

bool CFDD_SMK512::InitialSetDevice()
{
	// Инициализация модуля памяти, 512кб ОЗУ + 8кб ПЗУ (из них используется 4).
	m_nMemorySize = 02020000;

	if (CBKMPIDevice::InitialSetDevice())
	{
		m_pFloppy[static_cast<int>(FDD_DRIVE::A)] = std::make_unique<CFloppyDrive>();
		m_pFloppy[static_cast<int>(FDD_DRIVE::B)] = std::make_unique<CFloppyDrive>();

		for (int i = 0; i < 16; ++i) //заполним список окон
		{
			CString str;
			str.Format(_T("SMK:%02d (%s)"), i, g_arStrSMKPgNums[i].GetString());
			g_Platform.GetWndVectorPtr()->push_back({ str, 0100000, 0100000, GetMainMemory() + size_t(i) * 0100000 });
		}

		return true;
	}

	return false;
}


void CFDD_SMK512::OnReset()
{
	CFDD_A16M::OnReset();
	m_ATA_IDE.reset();
}

// специальная функция, тут номер банка слишком большой
bool CFDD_SMK512::InitMemoryModules(const BoardRomList_t arrBoardRomList[], int size)
{
	// проверяем загрузку всех ПЗУ в списке.
	// если чего-то нет, выдаёт сообщение, но продолжаем
	for (int n = 0; n < size; ++n)
	{
		if (LoadRomModule(arrBoardRomList[n].nResource, BANK_TO_OFFSET_ALTPRO(arrBoardRomList[n].nBank), arrBoardRomList[n].nBank))
		{
			m_nROMPresent |= (1 << 31); // !!! т.к. всего одно ПЗУ, то просто имеем константу
		}
		else
		{
			m_nROMPresent &= ~(1 << 31); // !!! т.к. всего одно ПЗУ, то просто имеем константу
		}
	}

	// в любом случае проинициализируем карту памяти
	MemoryManager();
	return true;
}

bool CFDD_SMK512::OnInitDevice()
{
	static const CBKMPIDevice::BoardRomList_t m_arrFDDSMK512RomList[FDDRomListSize] =
	{
		// инициализируем список загружаемых ПЗУ
		{ IDS_INI_FDR_SMK512, ALTPRO_SMK_FDDROM_BNK }
	};
	// инициализация карты памяти
	return InitMemoryModules(m_arrFDDSMK512RomList, FDDRomListSize);
}

void CFDD_SMK512::OnLoadRomModule(const int nSize, const int nBank)
{
	if (nBank == ALTPRO_SMK_FDDROM_BNK)
	{
		if (nSize <= 010000)
		{
			m_nBKPortsIOArea = 0170000;
		}
	}
}

static const A16Mode_t m_SMK512_MemStatus[8] =
{
	// здесь, ПЗУ монитора БК11М будем отключать и в режимах 160, 120, 100
	// потому что на реальном железе оно почему-то не влияет (по крайней мере на реплике с быстрой памятью).
	// и ещё в режиме 100 отключим ОЗУ в окне1, хотя ОЗУ как бы накладывается. Запись туда есть, RPLY выдаётся,
	// но чтение делается только из ОЗУ СМК, ОЗУ БК данные выдать не успевает.
	// Но это сэмулировать не получается пока с моими алгоритмами.

	{
		// режим 0      ALTPRO_SMK_HLT11_MODE
		true, true, false, false, true,
		{
			{ 0, BANK_MODE::OFF }, { 0, BANK_MODE::OFF }, { 0, BANK_MODE::OFF }, { 0, BANK_MODE::OFF }, { 4, BANK_MODE::RAM }, { 5, BANK_MODE::RAM }, { 6, BANK_MODE::RAM }, { 7, BANK_MODE::RAM }
		}
	},
	{
		// режим 20     ALTPRO_SMK_ALL_MODE
		true, true, true, true, false,
		{
			{ 4, BANK_MODE::RAM }, { 5, BANK_MODE::RAM }, { 6, BANK_MODE::RAM }, { 7, BANK_MODE::RAM }, { 0, BANK_MODE::RAM }, { 1, BANK_MODE::RAM }, { 2, BANK_MODE::RAM }, { 3, BANK_MODE::RAM },
		}
	},
	{
		// режим 40     ALTPRO_SMK_OZU11_MODE
		false, true, false, false, false,
		{
			{ 0, BANK_MODE::OFF }, { 0, BANK_MODE::OFF }, { 0, BANK_MODE::OFF }, { 0, BANK_MODE::OFF }, { 4, BANK_MODE::RAM }, { 5, BANK_MODE::RAM }, { 6, BANK_MODE::RAM }, { 7, BANK_MODE::RAM },
		}
	},
	{
		// режим 60     ALTPRO_SMK_STD10_MODE
		false, true, true, false, false,
		{
			{ 0, BANK_MODE::OFF }, { 0, BANK_MODE::OFF }, { 2, BANK_MODE::RAM }, { 3, BANK_MODE::RAM }, { 5, BANK_MODE::RAM }, { 4, BANK_MODE::RAM }, { 0, BANK_MODE::ROM }, { 7, BANK_MODE::RAM },
		}
	},
	{
		// режим 100    ALTPRO_SMK_HLT10_MODE
		true, true /*false*/, true /*false*/, false, true,
		{
			{ 0, BANK_MODE::RAM }, { 1, BANK_MODE::RAM }, { 2, BANK_MODE::RAM }, { 3, BANK_MODE::RAM }, { 4, BANK_MODE::RAM }, { 5, BANK_MODE::RAM }, { 6, BANK_MODE::RAM }, { 7, BANK_MODE::RAM },
		}
	},
	{
		// режим 120    ALTPRO_SMK_OZU10_MODE
		true, true /*false*/, true, false, false,
		{
			{ 0, BANK_MODE::RAM }, { 1, BANK_MODE::RAM }, { 2, BANK_MODE::RAM }, { 3, BANK_MODE::RAM }, { 4, BANK_MODE::RAM }, { 5, BANK_MODE::RAM }, { 6, BANK_MODE::RAM }, { 7, BANK_MODE::RAM },
		}
	},
	{
		// режим 140    ALTPRO_SMK_STD11_MODE
		false, false, false, false, false,
		{
			{ 0, BANK_MODE::OFF }, { 0, BANK_MODE::OFF }, { 0, BANK_MODE::OFF }, { 0, BANK_MODE::OFF }, { 0, BANK_MODE::OFF }, { 0, BANK_MODE::OFF }, { 0, BANK_MODE::ROM }, { 7, BANK_MODE::RAM },
		}
	},
	{
		// режим 160    ALTPRO_SMK_SYS_MODE
		false, true /*false*/, true, true, false,
		{
			{ 0, BANK_MODE::OFF }, { 0, BANK_MODE::OFF }, { 6, BANK_MODE::RAM }, { 7, BANK_MODE::RAM }, { 0, BANK_MODE::RAM }, { 1, BANK_MODE::RAM }, { 0, BANK_MODE::ROM }, { 0, BANK_MODE::ROM },
		}
	},
};


void CFDD_SMK512::MemoryManager()
{
	// устанавливаем новый режим работы
	const int nModeNumber = (m_sCustom.nAltProMode & ALTPRO_MODE_MASK) >> 4;
	const A16Mode_t &AMode = m_SMK512_MemStatus[nModeNumber];
	m_IOSegment.bReadable = AMode.bSMKIOSegR;
	m_IOSegment.bWritable = AMode.bSMKIOSegW;
	// теперь из массивов выберем нужные значения
	const auto brd = g_Platform.GetBoardPtr();
	brd->Mon10RomOFF(AMode.bMON10);
	brd->BOS11RomOFF(AMode.bBOS11);
	brd->RAM11Wn1OFF(AMode.bWND1);
	int nBaseSegment = 0;
	const int nCode = m_sCustom.nAltProMemBank;

	if (nCode & BIT10)
	{
		nBaseSegment += 010;
	}

	if (nCode & BIT02)
	{
		nBaseSegment += 020;
	}

	if (nCode & BIT03)
	{
		nBaseSegment += 040;
	}

	if (nCode & BIT00)
	{
		nBaseSegment += 0100;
	}

	SetBank(nModeNumber, nBaseSegment);

	// и обработаем дополнительные условия
	switch (nModeNumber)
	{
		case (ALTPRO_SMK_HLT10_MODE>>4):
			m_pMemoryMap[0].bWritable = FALSE; // банк 0 с защитой от записи
			break;
	}
}

// установка страницы ОЗУ в заданном банке
void CFDD_SMK512::SetBank(int nModeNumber, int nBaseSegment)
{
	const A16Mode_t &AMode = m_SMK512_MemStatus[nModeNumber];

	for (int nBank = 0; nBank < ALTPRO_BANKS_NUM; ++nBank)
	{
		const BankData_t &ABnkDta = AMode.aBankStatus[nBank];
		BKMEMBank_t &mb = m_pMemoryMap[nBank];

		switch (ABnkDta.nMode)
		{
			case BANK_MODE::OFF:
				mb.bReadable = FALSE;
				mb.bWritable = FALSE;
				mb.nBank = 0;
				mb.nOffset = 0;
				mb.nTimingCorrection = RAM_TIMING_CORR_VALUE_D;
				break;

			case BANK_MODE::RAM:
				mb.bReadable = TRUE;
				mb.bWritable = TRUE;
				mb.nBank = ABnkDta.nPage + nBaseSegment;
				mb.nOffset = BANK_TO_OFFSET_ALTPRO(mb.nBank);
				mb.nTimingCorrection = RAM_TIMING_CORR_VALUE_SMK;
				break;

			case BANK_MODE::ROM:
				mb.bReadable = !!(m_nROMPresent & (1 << 31));  //!!! т.к. всего одно ПЗУ, то просто имеем константу
				mb.bWritable = FALSE;
				mb.nBank = ALTPRO_SMK_FDDROM_BNK;
				mb.nOffset = BANK_TO_OFFSET_ALTPRO(ALTPRO_SMK_FDDROM_BNK);
				mb.nTimingCorrection = ROM_TIMING_CORR_VALUE_SMK;
				break;
		}
	}
}


CString CFDD_SMK512::GetMemoryMapViewData(const int seg)
{
	CString strRet;
	if (seg < DEC_BANKS_NUM)
	{
		int sa = (seg - 4) * 2; // начальный сегмент альтпро
		for (int j = 0; j < 2; ++j)
		{
			BKMEMBank_t &mb = m_pMemoryMap[sa];
			int n = 0;
			if (mb.bReadable) n |= 2;
			if (mb.bWritable) n |= 1;
			if (n == 2 && sa == 0) n = 4; // ОЗУ зз
			int page = mb.nBank / 8; int bank = mb.nBank % 8;
			CString strTmp;
			strTmp.Format(g_arStrMMVw_SMK[n], page, bank);
			if (j)
			{
				strRet += _T('/');
			}
			strRet += strTmp;
			sa++;
		}
	}
	else
	{
		BKMEMBank_t &mb = m_pMemoryMap[7];
		int n = 0;
		if (m_IOSegment.bReadable) n |= 2;
		if (m_IOSegment.bWritable) n |= 1;
		int page = mb.nBank / 8; int bank = mb.nBank % 8;
		if (n == 2 && bank == 3) n = 4; // ОЗУ зз
		strRet.Format(g_arStrMMVw_SMK[n], page, bank);
	}

	return strRet;

}


bool CFDD_SMK512::GetSystemRegister(const uint16_t addr, void *pDst, UINT dwFlags)
{
	if (CFDD_A16M::GetSystemRegister(addr, pDst, dwFlags))
	{
		return true;
	}

	uint16_t w = 0;
	const bool bReg = (dwFlags & GSSR_INTERNAL) ? ReadHDDRegistersInternal(addr, w) : ReadHDDRegisters(addr, w);

	if (dwFlags & GSSR_BYTEOP)
	{
		// auto pDst_B = reinterpret_cast<uint8_t *>(pDst);
		*(reinterpret_cast<uint8_t *>(pDst)) = ((addr & 1) ? (w >> 8) : w) & 0377;
	}
	else
	{
		// auto pDst_W = reinterpret_cast<uint16_t *>(pDst);
		*(reinterpret_cast<uint16_t *>(pDst)) = w;
	}

	return bReg;
}

bool CFDD_SMK512::SetSystemRegister(const uint16_t addr, uint16_t value, UINT dwFlags)
{
	if (CFDD_A16M::SetSystemRegister(addr, value, dwFlags))
	{
		return true;
	}

	return WriteHDDRegisters(addr, ~value);
}

bool CFDD_SMK512::GetByteT(const uint16_t addr, uint8_t *pValue, int &nTC)
{
	nTC = RAM_TIMING_CORR_VALUE_D;

	if (addr & 0100000)
	{
		const bool bReg = GetSystemRegister(addr, pValue, GSSR_BYTEOP);

		if (bReg)
		{
			nTC = max(nTC, REG_TIMING_CORR_VALUE);
		}

		bool bMem;

		// теперь проверим на чтение из банка памяти
		if (addr >= 0177000)
		{
			if (bMem = !!m_IOSegment.bReadable)  // это не сравнение, это присваивание
			{
				// если читать можно, читаем
				nTC = max(nTC, m_pMemoryMap[7].nTimingCorrection);
				*pValue |= m_pMemory[static_cast<size_t>(m_pMemoryMap[7].nOffset) + (addr & 07777)];
			}
		}
		else
		{
			const int nBank = ADDRESS_TO_BANK_ALTPRO(addr);

			if (bMem = !!m_pMemoryMap[nBank].bReadable)  // это не сравнение, это присваивание
			{
				// если читать можно, читаем
				nTC = max(nTC, m_pMemoryMap[nBank].nTimingCorrection);
				*pValue |= m_pMemory[static_cast<size_t>(m_pMemoryMap[nBank].nOffset) + (addr & 07777)];
			}
		}

		if (bReg || bMem)
		{
			return true;
		}
	}

	*pValue = 0;
	return false;
}

bool CFDD_SMK512::GetWordT(const uint16_t addr, uint16_t *pValue, int &nTC)
{
	nTC = RAM_TIMING_CORR_VALUE_D;

	if (addr & 0100000)
	{
		const bool bReg = GetSystemRegister(addr, pValue, GSSR_NONE);

		if (bReg)
		{
			nTC = max(nTC, REG_TIMING_CORR_VALUE);
		}

		bool bMem;

		// теперь проверим на чтение из банка памяти
		if (addr >= 0177000)
		{
			if (bMem = !!m_IOSegment.bReadable)  // это не сравнение, это присваивание
			{
				// если читать можно, читаем
				nTC = max(nTC, m_pMemoryMap[7].nTimingCorrection);
				*pValue |= *(uint16_t *)&m_pMemory[static_cast<size_t>(m_pMemoryMap[7].nOffset) + (addr & 07776)];
			}
		}
		else
		{
			const int nBank = ADDRESS_TO_BANK_ALTPRO(addr);

			if (bMem = !!m_pMemoryMap[nBank].bReadable) // это не сравнение, это присваивание
			{
				// если читать можно, читаем
				nTC = max(nTC, m_pMemoryMap[nBank].nTimingCorrection);
				*pValue |= *(uint16_t *)&m_pMemory[static_cast<size_t>(m_pMemoryMap[nBank].nOffset) + (addr & 07776)];
			}
		}

		if (bReg || bMem)
		{
			return true;
		}
	}

	*pValue = 0;
	return false;
}

bool CFDD_SMK512::SetByteT(const uint16_t addr, uint8_t value, int &nTC)
{
	nTC = RAM_TIMING_CORR_VALUE_D;

	if (addr & 0100000)
	{
		bool bMem, bReg = false;

		// теперь проверим на запись
		if (addr >= 0177000)
		{
			if (bMem = !!m_IOSegment.bWritable) // это не сравнение, это присваивание
			{
				// если писать можно, пишем
				nTC = max(nTC, m_pMemoryMap[7].nTimingCorrection);
				m_pMemory[static_cast<size_t>(m_pMemoryMap[7].nOffset) + (addr & 07777)] = value;
			}

			if (bReg = SetSystemRegister(addr, value, GSSR_BYTEOP)) // это не сравнение, это присваивание
			{
				nTC = max(nTC, REG_TIMING_CORR_VALUE);
			}
		}
		else
		{
			const int nBank = ADDRESS_TO_BANK_ALTPRO(addr);

			if (bMem = !!m_pMemoryMap[nBank].bWritable) // это не сравнение, это присваивание
			{
				// если писать можно, пишем
				nTC = max(nTC, m_pMemoryMap[nBank].nTimingCorrection);
				m_pMemory[static_cast<size_t>(m_pMemoryMap[nBank].nOffset) + (addr & 07777)] = value;
			}
		}

		if (bReg || bMem)
		{
			return true;
		}
	}

	return false;
}

bool CFDD_SMK512::SetWordT(const uint16_t addr, uint16_t value, int &nTC)
{
	nTC = RAM_TIMING_CORR_VALUE_D;

	if (addr & 0100000)
	{
		bool bMem, bReg = false;

		// теперь проверим на запись
		if (addr >= 0177000)
		{
			if (bMem = !!m_IOSegment.bWritable) // это не сравнение, это присваивание
			{
				// если писать можно, пишем
				nTC = max(nTC, m_pMemoryMap[7].nTimingCorrection);
				*(uint16_t *)&m_pMemory[static_cast<size_t>(m_pMemoryMap[7].nOffset) + (addr & 07776)] = value;
			}

			if (bReg = SetSystemRegister(addr, value, GSSR_NONE)) // это не сравнение, это присваивание
			{
				nTC = max(nTC, REG_TIMING_CORR_VALUE);
			}
		}
		else
		{
			const int nBank = ADDRESS_TO_BANK_ALTPRO(addr);

			if (bMem = !!m_pMemoryMap[nBank].bWritable) // это не сравнение, это присваивание
			{
				// если писать можно, пишем
				nTC = max(nTC, m_pMemoryMap[nBank].nTimingCorrection);
				*(uint16_t *)&m_pMemory[static_cast<size_t>(m_pMemoryMap[nBank].nOffset) + (addr & 07776)] = value;
			}
		}

		if (bReg || bMem)
		{
			return true;
		}
	}

	return false;
}

bool CFDD_SMK512::GetByteTInternal(const uint16_t addr, uint8_t *pValue, int &nTC)
{
	nTC = RAM_TIMING_CORR_VALUE_D;

	if (addr & 0100000)
	{
		const bool bReg = GetSystemRegister(addr, pValue, GSSR_INTERNAL | GSSR_BYTEOP);

		if (bReg)
		{
			nTC = max(nTC, REG_TIMING_CORR_VALUE);
		}

		bool bMem;

		// теперь проверим на чтение из банка памяти
		if (addr >= 0177000)
		{
			if (bMem = !!m_IOSegment.bReadable)  // это не сравнение, это присваивание
			{
				// если читать можно, читаем
				nTC = max(nTC, m_pMemoryMap[7].nTimingCorrection);
				*pValue |= m_pMemory[static_cast<size_t>(m_pMemoryMap[7].nOffset) + (addr & 07777)];
			}
		}
		else
		{
			int nBank = ADDRESS_TO_BANK_ALTPRO(addr);

			if (bMem = !!m_pMemoryMap[nBank].bReadable)  // это не сравнение, это присваивание
			{
				// если читать можно, читаем
				nTC = max(nTC, m_pMemoryMap[nBank].nTimingCorrection);
				*pValue |= m_pMemory[static_cast<size_t>(m_pMemoryMap[nBank].nOffset) + (addr & 07777)];
			}
		}

		if (bReg || bMem)
		{
			return true;
		}
	}

	*pValue = 0;
	return false;
}

bool CFDD_SMK512::GetWordTInternal(const uint16_t addr, uint16_t *pValue, int &nTC)
{
	nTC = RAM_TIMING_CORR_VALUE_D;

	if (addr & 0100000)
	{
		const bool bReg = GetSystemRegister(addr, pValue, GSSR_INTERNAL);

		if (bReg)
		{
			nTC = max(nTC, REG_TIMING_CORR_VALUE);
		}

		bool bMem;

		// теперь проверим на чтение из банка памяти
		if (addr >= 0177000)
		{
			if (bMem = !!m_IOSegment.bReadable)  // это не сравнение, это присваивание
			{
				// если читать можно, читаем
				nTC = max(nTC, m_pMemoryMap[7].nTimingCorrection);
				*pValue |= *(uint16_t *)&m_pMemory[static_cast<size_t>(m_pMemoryMap[7].nOffset) + (addr & 07776)];
			}
		}
		else
		{
			const int nBank = ADDRESS_TO_BANK_ALTPRO(addr);

			if (bMem = !!m_pMemoryMap[nBank].bReadable) // это не сравнение, это присваивание
			{
				// если читать можно, читаем
				nTC = max(nTC, m_pMemoryMap[nBank].nTimingCorrection);
				*pValue |= *(uint16_t *)&m_pMemory[static_cast<size_t>(m_pMemoryMap[nBank].nOffset) + (addr & 07776)];
			}
		}

		if (bReg || bMem)
		{
			return true;
		}
	}

	*pValue = 0;
	return false;
}



bool CFDD_SMK512::SetByteTInternal(const uint16_t addr, uint8_t value, int &nTC)
{
	nTC = RAM_TIMING_CORR_VALUE_D;

	if (addr & 0100000)
	{
		bool bMem, bReg = false;

		// теперь проверим на запись
		if (addr >= 0177000)
		{
			if (bMem = m_IOSegment.bWritable || m_IOSegment.bReadable) // это не сравнение, это присваивание
			{
				// если писать можно, пишем
				nTC = max(nTC, m_pMemoryMap[7].nTimingCorrection);
				m_pMemory[static_cast<size_t>(m_pMemoryMap[7].nOffset) + (addr & 07777)] = value;
			}

			if (bReg = SetSystemRegister(addr, value, GSSR_INTERNAL | GSSR_BYTEOP)) // это не сравнение, это присваивание
			{
				nTC = max(nTC, REG_TIMING_CORR_VALUE);
			}
		}
		else
		{
			const int nBank = ADDRESS_TO_BANK_ALTPRO(addr);

			if (bMem = m_pMemoryMap[nBank].bWritable || m_pMemoryMap[nBank].bReadable) // это не сравнение, это присваивание
			{
				// если писать можно, пишем
				nTC = max(nTC, m_pMemoryMap[nBank].nTimingCorrection);
				m_pMemory[static_cast<size_t>(m_pMemoryMap[nBank].nOffset) + (addr & 07777)] = value;
			}
		}

		if (bReg || bMem)
		{
			return true;
		}
	}

	return false;
}

bool CFDD_SMK512::SetWordTInternal(const uint16_t addr, uint16_t value, int &nTC)
{
	nTC = RAM_TIMING_CORR_VALUE_D;

	if (addr & 0100000)
	{
		bool bMem, bReg = false;

		// теперь проверим на запись
		if (addr >= 0177000)
		{
			if (bMem = m_IOSegment.bWritable || m_IOSegment.bReadable) // это не сравнение, это присваивание
			{
				// если писать можно, пишем
				nTC = max(nTC, m_pMemoryMap[7].nTimingCorrection);
				*(uint16_t *)&m_pMemory[static_cast<size_t>(m_pMemoryMap[7].nOffset) + (addr & 07776)] = value;
			}

			if (bReg = SetSystemRegister(addr, value, GSSR_INTERNAL))
			{
				nTC = max(nTC, REG_TIMING_CORR_VALUE);
			}
		}
		else
		{
			const int nBank = ADDRESS_TO_BANK_ALTPRO(addr);

			if (bMem = m_pMemoryMap[nBank].bWritable || m_pMemoryMap[nBank].bReadable) // это не сравнение, это присваивание
			{
				// если писать можно, пишем
				nTC = max(nTC, m_pMemoryMap[nBank].nTimingCorrection);
				*(uint16_t *)&m_pMemory[static_cast<size_t>(m_pMemoryMap[nBank].nOffset) + (addr & 07776)] = value;
			}
		}

		if (bReg || bMem)
		{
			return true;
		}
	}

	return false;
}

void CFDD_SMK512::AttachDrives()
{
	CFDDStd326::AttachDrives();
	fs::path strHDDImgName = g_Config.GetDriveImgName(HDD_MODE::MASTER);

	// если в канал Master что-то нужно примонтировать
	if (!Global::isEmptyUnit(strHDDImgName))
	{
		m_ATA_IDE.attach(strHDDImgName, HDD_MODE::MASTER);
	}
	else
	{
		m_ATA_IDE.detach(HDD_MODE::MASTER);
	}

	strHDDImgName = g_Config.GetDriveImgName(HDD_MODE::SLAVE);

	// если в канал Slave что-то нужно примонтировать
	if (!Global::isEmptyUnit(strHDDImgName))
	{
		m_ATA_IDE.attach(strHDDImgName, HDD_MODE::SLAVE);
	}
	else
	{
		m_ATA_IDE.detach(HDD_MODE::SLAVE);
	}

	m_ATA_IDE.reset();
}

void CFDD_SMK512::DetachDrives()
{
	CFDDStd326::DetachDrives();
	m_ATA_IDE.detach(HDD_MODE::MASTER);
	m_ATA_IDE.detach(HDD_MODE::SLAVE);
}

bool CFDD_SMK512::WriteHDDRegisters(uint16_t num, uint16_t data)
{
	const uint16_t addr = num & 0177776;

	// обработка регистров HDD SMK
	switch (addr)
	{
		case 0177740:
			m_ATA_IDE.write_regs((num & 1) ? HDD_REGISTER::H3F7 : HDD_REGISTER::H1F7, data);
			break;

		case 0177742:
			m_ATA_IDE.write_regs((num & 1) ? HDD_REGISTER::H3F6 : HDD_REGISTER::H1F6, data);
			break;

		case 0177744:
			m_ATA_IDE.write_regs(HDD_REGISTER::H1F5, data);
			break;

		case 0177746:
			m_ATA_IDE.write_regs(HDD_REGISTER::H1F4, data);
			break;

		case 0177750:
			m_ATA_IDE.write_regs(HDD_REGISTER::H1F3, data);
			break;

		case 0177752:
			m_ATA_IDE.write_regs(HDD_REGISTER::H1F2, data);
			break;

		case 0177754:
			m_ATA_IDE.write_regs(HDD_REGISTER::H1F1, data);
			break;

		case 0177756:
			m_ATA_IDE.write_regs(HDD_REGISTER::H1F0, data);
			break;

		default:
			return false;
	}

	return true;
}

bool CFDD_SMK512::ReadHDDRegisters(uint16_t num, uint16_t &data)
{
	uint16_t const addr = num & 0177776;
	uint16_t result;

	// обработка регистров HDD SMK
	// оказывается, есть ещё и байтовые обращения
	switch (addr)
	{
		case 0177740:
			result = m_ATA_IDE.read_regs((num & 1) ? HDD_REGISTER::H3F7 : HDD_REGISTER::H1F7);
			break;

		case 0177742:
			result = m_ATA_IDE.read_regs((num & 1) ? HDD_REGISTER::H3F6 : HDD_REGISTER::H1F6);
			break;

		case 0177744:
			result = m_ATA_IDE.read_regs(HDD_REGISTER::H1F5);
			break;

		case 0177746:
			result = m_ATA_IDE.read_regs(HDD_REGISTER::H1F4);
			break;

		case 0177750:
			result = m_ATA_IDE.read_regs(HDD_REGISTER::H1F3);
			break;

		case 0177752:
			result = m_ATA_IDE.read_regs(HDD_REGISTER::H1F2);
			break;

		case 0177754:
			result = m_ATA_IDE.read_regs(HDD_REGISTER::H1F1);
			break;

		case 0177756:
			result = m_ATA_IDE.read_regs(HDD_REGISTER::H1F0);
			break;

		default:
			data = 0;
			return false;
	}

	data = ~result;
	return true;
}
bool CFDD_SMK512::ReadHDDRegistersInternal(const uint16_t num, uint16_t &data) const
{
	uint16_t const addr = num & 0177776;
	uint16_t result;

	// обработка регистров HDD SMK
	// оказывается, есть ещё и байтовые обращения
	switch (addr)
	{
		case 0177740:
			result = m_ATA_IDE.read_regs_internal((num & 1) ? HDD_REGISTER::H3F7 : HDD_REGISTER::H1F7);
			break;

		case 0177742:
			result = m_ATA_IDE.read_regs_internal((num & 1) ? HDD_REGISTER::H3F6 : HDD_REGISTER::H1F6);
			break;

		case 0177744:
			result = m_ATA_IDE.read_regs_internal(HDD_REGISTER::H1F5);
			break;

		case 0177746:
			result = m_ATA_IDE.read_regs_internal(HDD_REGISTER::H1F4);
			break;

		case 0177750:
			result = m_ATA_IDE.read_regs_internal(HDD_REGISTER::H1F3);
			break;

		case 0177752:
			result = m_ATA_IDE.read_regs_internal(HDD_REGISTER::H1F2);
			break;

		case 0177754:
			result = m_ATA_IDE.read_regs_internal(HDD_REGISTER::H1F1);
			break;

		case 0177756:
			result = m_ATA_IDE.read_regs_internal(HDD_REGISTER::H1F0);
			break;

		default:
			data = 0;
			return false;
	}

	data = ~result;
	return true;
}

uint16_t CFDD_SMK512::ReadDebugHDDRegisters(const int nDrive, const HDD_REGISTER num, const bool bReadMode) const
{
	return m_ATA_IDE.get_debug_regs(nDrive, num, bReadMode);
}

// проверка и отлов кода режима
void CFDD_SMK512::Change_AltPro_Mode(const uint16_t w)
{
	// отловим nExtCodes
	m_sCustom.nExtCodes = w & 014;

	// подключение/отключение ПЗУ Бейсика
	// только на СМК с памятью < 256кб и А*
	if (g_Platform.GetBoardPtr() && GetBoardModel() != BK_DEV_MPI::SMK512)
	{
		// если бит 3 установлен, то бейсик включён
		g_Platform.GetBoardPtr()->BasicRomOFF(!(m_sCustom.nExtCodes & 010));
	}

	if (m_bA16M_Trigger) // если триггер взведён
	{
		m_nAltproMode = w & ALTPRO_MODE_MASK;       // вычленим режим
		m_nAltProMemBank = w & ALTPRO_CODE_MASK;    // вычленим код страницы памяти на СМК.

		// теперь проверим, не пора ли сбрасывать триггер
		if ((w & ALTPRO_BEGIN_STROB_TRIGGER) != ALTPRO_BEGIN_STROB_TRIGGER)
		{
			m_bA16M_Trigger = false;    // сбрасываем триггер
			m_sCustom.nAltProMode = m_nAltproMode; // сохраняем последние запомненные значения
			m_sCustom.nAltProMemBank = m_nAltProMemBank;
			MemoryManager();    // запускаем менеджер памяти для переключения банков
		}
	}
	else // если триггер не взведён, ловим строб
	{
		// ключевое отличие ПЛИС реплики - определение строб кода
		if ((w & 0xf) == ALTPRO_BEGIN_STROB_TRIGGER) // если строб-код
		{
			m_bA16M_Trigger = true; // взводим триггер, означающий, что любое следующее значение будет кодом режима
		}
	}
}


