// FDDStd326.cpp: implementation of the CFDD_Std class.
//


#include "pch.h"
#include "resource.h"
#include "FDDStd326.h"

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

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

// Маска флагов, сохраняемых в m_flags
constexpr auto FLOPPY_CMD_MASKSTORED = (FLOPPY_CMD_SELECT_DRIVE_A | FLOPPY_CMD_SELECT_DRIVE_B | FLOPPY_CMD_SELECT_DRIVE_C | FLOPPY_CMD_SELECT_DRIVE_D | \
                                        FLOPPY_CMD_ENGINESTART | FLOPPY_CMD_SIDEUP | FLOPPY_CMD_DIR | FLOPPY_CMD_STEP | FLOPPY_CMD_READDATA | \
                                        FLOPPY_CMD_WRITEMARKER | FLOPPY_CMD_PRECORRECTION);

/////////////////////////////////////////////////////////////////////////////
// Construction/Destruction
IMPLEMENT_DYNAMIC(CFDDStd326, CBKMPIDevice)

CFDDStd326::CFDDStd326()
	: m_pDrive(nullptr)
	, m_drive(FDD_DRIVE::NONE)
	, m_pFloppy{nullptr, nullptr, nullptr, nullptr}
{
	ini_crc_16_rd();
	InitVariables();
#ifdef _DEBUG
	m_msec = GetTickCount();
	m_nFrame = 0;
#endif
}

CFDDStd326::~CFDDStd326()
{
	DetachDrives();
}

bool CFDDStd326::InitialSetDevice()
{
	m_nMemorySize = 0100000;

	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>();
		m_pFloppy[static_cast<int>(FDD_DRIVE::C)] = std::make_unique<CFloppyDrive>();
		m_pFloppy[static_cast<int>(FDD_DRIVE::D)] = std::make_unique<CFloppyDrive>();
		return true;
	}

	return false;
}

bool CFDDStd326::InitDevice(uint16_t addrStart)
{
	// выключаем ПЗУ бейсика БК10
	if (g_Platform.GetBoardPtr())
	{
		g_Platform.GetBoardPtr()->BasicRomOFF(true);
	}

	// инициализация карты памяти
	bool bRet = OnInitDevice();

	if (bRet)
	{
		// 326 прошивка
		g_Platform.SetInterseptAddress(0160372, 0161564);
	}

	Reset();
	return bRet;
}

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

void CFDDStd326::InitVariables()
{
	m_side = m_track = 0;
	m_datareg = m_writereg = m_shiftreg = 0;
	m_bSearchSyncTrigger = false;
	m_bWriteMode = m_writemarker = m_shiftmarker = m_bCRCCalc = false;
	m_bSearchSync = true;
	m_writeflag = m_shiftflag = false;
	m_status = 0;
	m_flags = FLOPPY_CMD_SIDEUP | FLOPPY_CMD_DIR | FLOPPY_CMD_WRITEMARKER;
}

void CFDDStd326::DetachDrives()
{
	for (int drive = 0; drive < static_cast<int>(FDD_DRIVE::NUM_FDD); ++drive)
	{
		DetachImage(static_cast<FDD_DRIVE>(drive));
	}
}


void CFDDStd326::OnReset()
{
	for (auto &flp : m_pFloppy)
	{
		if (flp)
		{
			flp->FlushChanges();
		}
	}

	m_pDrive = nullptr;
	m_drive = FDD_DRIVE::NONE;
	InitVariables();
}

bool CFDDStd326::GetByteT(const uint16_t addr, uint8_t *pValue, int &nTC)
{
	uint16_t w;
	bool b = GetWordT(addr, &w, nTC);
	*pValue = ((addr & 1) ? (w >> 8) : w) & 0377;
	return b;
}

bool CFDDStd326::GetWordT(const uint16_t addr, uint16_t *pValue, int &nTC)
{
	if (0160000 <= addr && addr < m_nBKPortsIOArea)
	{
		nTC = m_pMemoryMap[KNGMD_FDDROM_BNK].nTimingCorrection;
		*pValue = *(reinterpret_cast<uint16_t *>(&m_pMemory[addr & 077776]));
		return true;
	}

	switch (addr & 0177776)
	{
		case 0177130:
			*pValue = GetState();
			// TRACE(_T("Rd 177130: %06o\n"), *pValue);
			break;

		case 0177132:
			*pValue = GetData();
			// TRACE(_T("fdr - pos:%06d  %06o\n"), m_drivedata[m_drive].dataptr, *pValue);
			break;

		default:
			nTC = RAM_TIMING_CORR_VALUE_D;
			*pValue = 0;
			return false;
	}

	nTC = REG_TIMING_CORR_VALUE;
	return true;
}

bool CFDDStd326::SetByteT(const uint16_t addr, uint8_t value, int &nTC)
{
	// запись в старший байт просто теряется, но RPLY выдаётся
	// запись в младший байт работает
	switch (addr & 0177776)
	{
		case 0177130:
			if (!(addr & 1))
			{
				SetCommand(value);
			}

			break;

		case 0177132:
			if (!(addr & 1))
			{
				WriteData(value);
			}

			break;

		default:
			nTC = RAM_TIMING_CORR_VALUE_D;
			return false;
	}

	nTC = REG_TIMING_CORR_VALUE;
	return true;
}

bool CFDDStd326::SetWordT(const uint16_t addr, uint16_t value, int &nTC)
{
	switch (addr & 0177776)
	{
		case 0177130:
			SetCommand(value);
			break;

		case 0177132:
			WriteData(value);
			break;

		default:
			nTC = RAM_TIMING_CORR_VALUE_D;
			return false;
	}

	nTC = REG_TIMING_CORR_VALUE;
	return true;
}

bool CFDDStd326::GetByteTInternal(const uint16_t addr, uint8_t *pValue, int &nTC)
{
	uint16_t w;
	bool b = CFDDStd326::GetWordTInternal(addr, &w, nTC);
	*pValue = ((addr & 1) ? (w >> 8) : w) & 0377;
	return b;
}

bool CFDDStd326::GetWordTInternal(const uint16_t addr, uint16_t *pValue, int &nTC)
{
	if (0160000 <= addr && addr < m_nBKPortsIOArea)
	{
		nTC = m_pMemoryMap[KNGMD_FDDROM_BNK].nTimingCorrection;
		*pValue = *(reinterpret_cast<uint16_t *>(&m_pMemory[addr & 077776]));
		return true;
	}

	switch (addr & 0177776)
	{
		case 0177130:
			*pValue = GetStateDebug();
			// TRACE(_T("Rd 177130: %06o\n"), *pValue);
			break;

		case 0177132:
			*pValue = GetDataDebug();
			// TRACE(_T("fdr - pos:%06d  %06o\n"), m_drivedata[m_drive].dataptr, *pValue);
			break;

		default:
			nTC = RAM_TIMING_CORR_VALUE_D;
			*pValue = 0;
			return false;
	}

	nTC = REG_TIMING_CORR_VALUE;
	return true;
}



void CFDDStd326::AttachDrives()
{
	for (int i = 0; i < static_cast<int>(FDD_DRIVE::NUM_FDD); ++i)
	{
		const auto d = static_cast<FDD_DRIVE>(i);
		fs::path strImgName = g_Config.GetDriveImgName(d);

		if (!Global::isEmptyUnit(strImgName))
		{
			// если ничего не было подключено, то подключаем
			AttachImage(d, strImgName);
		}
		else
		{
			// если что-то было подключено - отключаем
			DetachImage(d);
		}
	}
}

bool CFDDStd326::IsAttached(FDD_DRIVE eDrive) const
{
	const int nDrive = static_cast<int>(eDrive) & 3;
	return m_pFloppy[nDrive] && m_pFloppy[nDrive]->isAttached();
}


CFloppyDrive *CFDDStd326::GetFloppyDrive(int drive) const
{
	return m_pFloppy[drive].get();
}

bool CFDDStd326::IsReadOnly(FDD_DRIVE eDrive) const
{
	const int nDrive = static_cast<int>(eDrive) & 3;
	return m_pFloppy[nDrive] && m_pFloppy[nDrive]->isReadOnly();
}

bool CFDDStd326::GetDriveState(FDD_DRIVE eDrive) const
{
	const int nDrive = static_cast<int>(eDrive) & 3;
	return !!m_pFloppy[nDrive]; // true - привод есть, false - привода нет. для разных типов контроллеров
}

bool CFDDStd326::AttachImage(FDD_DRIVE eDrive, const fs::path &strFileName)
{
	const int nDrive = static_cast<int>(eDrive) & 3;
	CFloppyDrive *pFD = GetFloppyDrive(nDrive);

	if (pFD)
	{
		if (pFD->Attach(strFileName, g_Config.m_bExclusiveOpenImages))
		{
			InitVariables();
			m_status = FLOPPY_STATUS_TRACK0;

			if (pFD->isReadOnly())
			{
				m_status |= FLOPPY_STATUS_WRITEPROTECT;
			}

			pFD->PrepareTrack(m_track, m_side);
		}

		return true;
	}

	return false;
}

void CFDDStd326::DetachImage(FDD_DRIVE eDrive)
{
	const int nDrive = static_cast<int>(eDrive) & 3;

	if (m_pFloppy[nDrive])
	{
		m_pFloppy[nDrive]->Detach();
	}
}

inline bool CFDDStd326::IsEngineOn() const
{
	return !!(m_flags & FLOPPY_CMD_ENGINESTART);
}

uint16_t CFDDStd326::GetState()
{
	if (m_pDrive == nullptr)    // если привод не выбран
	{
		return 0;               // то возвращаем 0
	}

	if (!m_pDrive->isAttached())    // если файл не открыт - аналог того, что в дисководе нет диска
	{
		return FLOPPY_STATUS_INDEXMARK | (m_status & FLOPPY_STATUS_TRACK0);
	}

	std::lock_guard<std::mutex> lk(m_mutPeriodicBusy);

	// далее, формируем возвращаемый статус, для выбранного привода.
	// если двигатель включён, то выставим флаг готовности.
	if (IsEngineOn())
	{
		m_status |= FLOPPY_STATUS_RDY;
	}
	else
	{
		m_status &= ~(FLOPPY_STATUS_RDY | FLOPPY_STATUS_MOREDATA | FLOPPY_STATUS_CHECKSUMOK);
	}

	return m_status;
}

void CFDDStd326::SetCommand(uint16_t cmd)
{
	// Копируем новые флаги в m_flags
	m_flags &= ~FLOPPY_CMD_MASKSTORED;
	m_flags |= cmd & FLOPPY_CMD_MASKSTORED;
	bool okPrepareTrack = false;  // Нужно ли считывать дорожку в буфер
	// Проверить, не сменился ли текущий привод
	// тут выбирается текущий привод, чем более младший бит, тем больше приоритет
	// если установлено несколько битов - выбирается тот, что младше.
	FDD_DRIVE newdrive = (cmd & 1) ? FDD_DRIVE::A : (cmd & 2) ? FDD_DRIVE::B : (cmd & 4) ? FDD_DRIVE::C : (cmd & 8) ? FDD_DRIVE::D : FDD_DRIVE::NONE;

	if (m_drive != newdrive)
	{
		if (m_pDrive)
		{
			m_pDrive->FlushChanges();
		}

		m_drive = newdrive;
		m_pDrive = (newdrive == FDD_DRIVE::NONE) ? nullptr : m_pFloppy[static_cast<int>(m_drive)].get();
		okPrepareTrack = true;
	}

	if (m_drive == FDD_DRIVE::NONE || m_pDrive == nullptr) // если привод не выбран или выбран не существующий
	{
		return; // нечего и делать
	}

	// Проверяем, не сменилась ли сторона
	if (m_flags & FLOPPY_CMD_SIDEUP)  // Выбор стороны: 0 - нижняя, 1 - верхняя
	{
		if (m_side == 0)
		{
			m_side = 1;
			okPrepareTrack = true;
		}
	}
	else
	{
		if (m_side == 1)
		{
			m_side = 0;
			okPrepareTrack = true;
		}
	}

	if (m_flags & FLOPPY_CMD_STEP)  // Двигаем головки в заданном направлении
	{
		if (m_flags & FLOPPY_CMD_DIR)
		{
			if (m_track < 82)
			{
				m_track++;
				okPrepareTrack = true;
			}
		}
		else
		{
			if (m_track >= 1)
			{
				m_track--;
				okPrepareTrack = true;
			}
		}

		if (m_track == 0)
		{
			m_status |= FLOPPY_STATUS_TRACK0;
		}
		else
		{
			m_status &= ~FLOPPY_STATUS_TRACK0;
		}
	}

	if (okPrepareTrack)
	{
		m_pDrive->PrepareTrack(m_track, m_side);
	}

	if (m_flags & FLOPPY_CMD_READDATA)  // Поиск маркера
	{
		m_bSearchSyncTrigger = true;    // если бит FLOPPY_CMD_READDATA == 1, взводим триггер
	}
	else if (m_bSearchSyncTrigger)      // если бит FLOPPY_CMD_READDATA == 0 и триггер взведён
	{
		m_bSearchSyncTrigger = false;   // переходим в режим поиска маркера
		m_bSearchSync = true;
		m_status &= ~(FLOPPY_STATUS_CHECKSUMOK | FLOPPY_STATUS_MOREDATA);
		m_bCrcOK = false;
	}

	if (m_bWriteMode && (m_flags & FLOPPY_CMD_WRITEMARKER))  // Запись маркера
	{
		m_writemarker = true;
		m_status &= ~(FLOPPY_STATUS_CHECKSUMOK | FLOPPY_STATUS_MOREDATA);
		m_bCrcOK = false;
	}
}

uint16_t CFDDStd326::GetDataDebug() const // Получить значение порта 177132 - данные для отладки
{
	return m_datareg;
}

uint16_t CFDDStd326::GetStateDebug() const // Получить значение порта 177130 - состояние устройства для отладки
{
	return m_status;
}

uint16_t CFDDStd326::GetWriteDataDebug() const // Получить значение порта 177132 - переданные данные для отладки
{
	return m_writereg;
}

uint16_t CFDDStd326::GetCmdDebug() const // Получить значение порта 177130 - переданные команды для отладки
{
	return m_flags;
}


bool CFDDStd326::InitMemory(uint16_t wHighLim)
{
	m_nBKPortsIOArea = wHighLim;
	m_pMemory.clear();

	if (m_nMemorySize)
	{
		m_pMemory.resize(m_nMemorySize);

		if (m_pMemory.data())
		{
			ZeroMemory(m_pMemory.data(), m_nMemorySize);
			return true;
		}

		g_BKMsgBox.Show(IDS_BK_ERROR_NOTENMEMR, MB_OK);
		throw;
	}

	return false;
}

void CFDDStd326::OnLoadRomModule(const int nSize, const int nBank)
{
	// у ПЗУ RE326 RE253 работает только 4кБ, выше - RPLY не выдаётся
	// если > 4кб, то m_nBKPortsIOArea = BK_PORTSIO_AREA
	// если <= 4кб, то m_nBKPortsIOArea = 0170000
	if (nBank == KNGMD_FDDROM_BNK)
	{
		if (nSize <= 010000)
		{
			m_nBKPortsIOArea = 0170000;
		}
	}
}

void CFDDStd326::MemoryManager()
{
	CBKMPIDevice::MemoryManager();
	m_pMemoryMap[KNGMD_FDDROM_BNK].bReadable = !!(m_nROMPresent & (1 << KNGMD_FDDROM_BNK));
	m_pMemoryMap[KNGMD_FDDROM_BNK].nTimingCorrection = ROM_TIMING_CORR_VALUE;
}

bool CFDDStd326::RestoreRegisters(DWORD id, CMSFManager *pMsf)
{
	// тут можно реализовать сохранение/восстановление регистров
	return true;
}

bool CFDDStd326::RestoreMemory(DWORD id, CMSFManager *pMsf)
{
	if (pMsf->IsLoad())
	{
		return pMsf->GetBlockBaseMemory(id, GetMainMemory(), m_nMemorySize);
	}

	return pMsf->SetBlockBaseMemory(id, GetMainMemory(), m_nMemorySize);
}

bool CFDDStd326::RestoreMemoryMap(DWORD id, CMSFManager *pMsf)
{
	if (pMsf->IsLoad())
	{
		return pMsf->GetBlockMemMap(id, m_pMemoryMap.data(), DEC_BANKS_NUM, m_nROMPresent);
	}

	return pMsf->SetBlockMemMap(id, m_pMemoryMap.data(), DEC_BANKS_NUM, m_nROMPresent);
}


uint16_t CFDDStd326::GetData()
{
	std::lock_guard<std::mutex> lk(m_mutPeriodicBusy);
	m_status &= ~(FLOPPY_STATUS_MOREDATA);
	m_bWriteMode = m_bSearchSync = false;
	m_writeflag = m_shiftflag = false;

	if (m_pDrive && m_pDrive->isAttached())
	{
		return m_datareg;
	}

	return 0;
}

void CFDDStd326::WriteData(uint16_t data)
{
	std::lock_guard<std::mutex> lk(m_mutPeriodicBusy);
	m_bWriteMode = true;  // Переключаемся в режим записи, если ещё не переключились
	m_bSearchSync = false;

	if (!m_writeflag && !m_shiftflag)  // оба регистра пустые
	{
		m_shiftreg = data;
		m_shiftflag = true;
		m_status |= FLOPPY_STATUS_MOREDATA;
	}
	else if (!m_writeflag && m_shiftflag)  // Регистр записи пуст
	{
		m_writereg = data;
		m_writeflag = true;
		m_status &= ~FLOPPY_STATUS_MOREDATA;
	}
	else if (m_writeflag && !m_shiftflag)  // Регистр сдвига пуст
	{
		m_shiftreg = m_writereg;
		m_shiftflag = m_writeflag;
		m_writereg = data;
		m_writeflag = true;
		m_status &= ~FLOPPY_STATUS_MOREDATA;
	}
	else // Оба регистра не пусты
	{
		m_writereg = data;
	}
}

void CFDDStd326::Periodic() // сдвиг на 1 RAW слово на дорожке
{
	if (!IsEngineOn())
	{
		return;    // Вращаем дискеты только если включён мотор
	}

	{
		// область действия мутекса
		std::lock_guard<std::mutex> lk(m_mutPeriodicBusy);

		// Вращаем дискеты во всех приводах сразу
		for (auto &flp : m_pFloppy)
		{
			if (flp)
			{
				flp->MovePtr();
			}
		}

		// Далее обрабатываем чтение/запись на текущем приводе
		if (m_pDrive && IsAttached(m_drive))
		{
			if (m_pDrive->isIndex())
			{
				m_status |= FLOPPY_STATUS_INDEXMARK;
			}
			else
			{
				m_status &= ~FLOPPY_STATUS_INDEXMARK;
			}

			if (m_bWriteMode)   // Режим записи
			{
				if (m_shiftflag)
				{
					m_pDrive->WrData(m_shiftreg);
					m_shiftflag = false;

					if (m_shiftmarker)
					{
						m_pDrive->setMarker(true);
						m_shiftmarker = false;
						m_bCRCCalc = true;  // Начинаем считать CRC
						ini_crc_16_rd();
					}
					else
					{
						m_pDrive->setMarker(false);
					}

					if (m_bCRCCalc)
					{
						add_crc_16(m_shiftreg & 0377);
						add_crc_16((m_shiftreg >> 8) & 0377);
					}

					if (m_writeflag)
					{
						m_shiftreg = m_writereg;
						m_shiftflag = m_writeflag;
						m_writeflag = false;
						m_shiftmarker = m_writemarker;
						m_writemarker = false;
						m_status |= FLOPPY_STATUS_MOREDATA;
					}
					else
					{
						if (m_bCRCCalc)  // Прекращаем считать CRC
						{
							m_shiftreg = (m_nCRCAcc << 8) | (m_nCRCAcc >> 8) & 0377;  // вот она, наша рассчитанная CRC, пока так.
							m_shiftflag = true;
							m_shiftmarker = false;
							m_bCRCCalc = false;
							m_status |= FLOPPY_STATUS_CHECKSUMOK;
						}
					}
				}
			}
			else    // Режим чтения
			{
				m_datareg = m_pDrive->RdData();

				if (m_bCRCCalc)
				{
					add_crc_16_rd((m_shiftreg >> 8) & 0377);
					add_crc_16_rd(m_shiftreg & 0377);
				}

				if (m_status & FLOPPY_STATUS_MOREDATA)
				{
					if (m_bCRCCalc)  // Прекращаем считать CRC
					{
						m_bCRCCalc = false;

						// Сравниваем рассчитанную CRC с m_datareg
						if (m_bCrcOK)
						{
							m_status |= FLOPPY_STATUS_CHECKSUMOK;
						}
					}
				}
				else
				{
					m_shiftreg = m_datareg;

					if (m_bSearchSync)  // Поиск маркера
					{
						if (m_pDrive->getMarker())  // Нашли маркер
						{
							m_status |= FLOPPY_STATUS_MOREDATA;
							m_bSearchSync = false;
							m_bCRCCalc = true;
							ini_crc_16_rd();
						}
					}
					else  // Просто чтение
					{
						m_status |= FLOPPY_STATUS_MOREDATA;
					}
				}
			}
		}
	}   // область действия мутекса

#ifdef _DEBUG
	// Посчитаем FPS, в норме должно быть 15625 в сек. == 300 об/мин == 5 об/сек
	m_nFrame++; // сколько раз в секунду вызывается эта функция
	DWORD mtmpsec;

	if ((mtmpsec = GetTickCount()) - m_msec >= 1000)
	{
		m_msec = mtmpsec;
		TRACE(_T("FDD Frames %d\n"), m_nFrame);
		m_nFrame = 0;
	}

#endif
}

void CFDDStd326::ini_crc_16_rd()
{
	m_nCRCAcc = 0xffff; // начальное значение CRC
	m_bCrcOK = false;   // флаг, что CRC совпала
	m_nA1Cnt = 0;       // счётчик A1
	m_nCrcCnt = 0;      // счётчик байтов данных
	m_nCrcSecSz = FLOPPY_SECTOR_TYPE;   // тип размера сектора
	m_bHdrMk = false;   // флаг маркера заголовка сектора
	m_bCrcMarker = true; // флаг анализа маркера
}

void CFDDStd326::add_crc_16(uint8_t val)
{
	m_nCRCAcc ^= val << 8;

	for (int i = 0; i < 8; ++i)
	{
		if ((m_nCRCAcc <<= 1) & 0x10000)
		{
			m_nCRCAcc ^= 0x1021;
		}
	}
}

void CFDDStd326::add_crc_16_rd(uint8_t val)
{
	if (m_bCrcMarker)               // если анализируем маркер
	{
		if (val == 0xa1)            // если A1,
		{
			m_nA1Cnt++;             // то посчитаем её
			m_nCrcCnt = 1;          // пока будет 1 байт
		}
		else if (m_nA1Cnt == 3)     // если не A1, но их уже было три подряд
		{
			m_nA1Cnt = 0;           // всё, это условие больше не нужно

			if (val == 0xfe)        // это маркер заголовка?
			{
				m_bHdrMk = true;    // да
				m_nCrcCnt = 4;      // размер данных заголовка
			}
			else
			{
				m_bHdrMk = false;   // это не маркер заголовка

				if (val == 0xfb || val == 0xf8) // это маркер данных?
				{
					m_nCrcCnt = CFloppyDrive::m_nSectorSizes[m_nCrcSecSz]; // да, вот размер данных сектора
				}
			}

			m_nCrcCnt++;            // учтём в подсчёте байт маркера
			m_bCrcMarker = false;   // всё, анализ маркера закончен, чтобы не было ложных срабатываний при подсчёте CRC
		}
		else // если A1 было не три подряд, то это и не маркер
		{
			m_bCrcMarker = false; // не надо больше анализировать
		}
	}

	if (m_nCrcCnt <= 0)     // рассчёт окончен?
	{
		return;             // да - игнорируем данные
	}

	if (m_bHdrMk && m_nCrcCnt == 1) // это заголовок и его последний байт?
	{
		m_bHdrMk = false;           // да - всё, больше это условие не нужно
		m_nCrcSecSz = val;          // вот это тип размера сектора
		ASSERT(m_nCrcSecSz < 4);

		if (m_nCrcSecSz >= 4)       // чтобы прога не падала
		{
			m_nCrcSecSz = FLOPPY_SECTOR_TYPE; // подкорректируем некорректное значение
		}
	}

	add_crc_16(val);    // считаем CRC
	m_nCrcCnt--;    // уменьшаем счётчик байтов

	if (m_nCrcCnt == 0) // если это был последний байт,
	{
		// то проверяем, совпадает ли прочитанная CRC с рассчётной
		m_bCrcOK = !(m_datareg - (m_nCRCAcc & 0xffff));
		// больше мы сюда не попадём, и этот флаг останется в этом состоянии
		// пока не будет сброшен.
	}
}


bool CFDDStd326::Interception() const
{
	/*
	эмуляция работы с дисководом. Если мы работаем стандартными методами,
	а если нестандартными - то у нас есть полная эмуляция работы с дисководом через порты.
	*/
	return g_Platform.EmulateFDD();
}

