#include "StdAfx.h"
#include "Defines.h"
#include "HDD.h"

CHDD::CHDD(const CString &name, bool bSlave)
{
	attach_hdd(name, bSlave);
	int_init();
}

CHDD::CHDD()
{
	attach_hdd(_T(""), false);
	int_init();
}

CHDD::~CHDD()
{
	//если в буфере есть данные нужно сделать flush buffer;
	write_file();
	detach_hdd();
#ifdef THREADED_MODEL
	StopExecuteThread();
#endif // THREADED_MODEL
}


#ifdef THREADED_MODEL

void CHDD::StopExecuteThread()
{
	if (!m_lockThreadTerminate.IsLocked())
	{
		m_lockThreadTerminate.Lock();
		m_pExecuteThread->ResumeThread();

		while (m_lockThreadTerminate.IsLocked())
		{
			Sleep(100);
		}
	}

	m_lockThreadTerminate.UnLock();
}

bool CHDD::StartExecuteThread()
{
	if ((m_pExecuteThread = AfxBeginThread(
	                            ExecuteThreadWrapper,
	                            (void *)this,
	                            THREAD_PRIORITY_NORMAL,
	                            0,
	                            CREATE_SUSPENDED)
	    ) == nullptr)
	{
		return false;
	}

	m_pExecuteThread->m_bAutoDelete = true;
	return true;
}

UINT CHDD::ExecuteThreadWrapper(LPVOID lpParam)
{
	CHDD *pThis = reinterpret_cast<CHDD *>(lpParam);
	return pThis->ExecuteThreadFunc();
}

UINT CHDD::ExecuteThreadFunc()
{
	while (1)
	{
		if (m_lockThreadTerminate.IsLocked()) //сигнал к остановке потока получен?
		{
			m_lockThreadTerminate.UnLock(); //говорим, что поток больше не работает
			return 0;   //и выходим
		}

		execute_command(static_cast<HDD_IDE_COMMAND>(m_nCommandReg_1f7));
		m_nStatusReg_1f7 &= ~STATUS_BSY;
		m_pExecuteThread->SuspendThread();
	}
}

#endif // THREADED_MODEL


void CHDD::int_init()
{
	m_nDataReg_1f0 = 0;
	m_nErrorReg_1f1 = 0;
	m_nFeaturesReg_1f1 = 0;
	m_nSectorCountReg_1f2 = 0;
	m_nSectorNumberReg_1f3 = 0;
	m_nCylNumberLowReg_1f4 = 0;
	m_nCylNumberHiReg_1f5 = 0;
	m_nDrvHeadReg_1f6 = 0;// 0x20;
	m_nStatusReg_1f7 = 0;
	m_nCommandReg_1f7 = 0;
	m_nControlReg_3f6 = 0;
	m_nDriveAddrReg_3f7 = 0;
	memset(m_pSectorBuffer.b, 0, SECTOR_SIZE);
	m_bChangeBuffer = false;
	m_bReadOnly = true;
#ifdef THREADED_MODEL
	StartExecuteThread();
#endif // THREADED_MODEL
}

bool CHDD::attach_hdd(const CString &name, bool bSlave)
{
	detach_hdd();
	m_strImageFileName = name;
	m_nMasterSlave = bSlave ? 0x10 : 0;

	if (open_file())
	{
		return configure();
	}

	return false;
}

void CHDD::detach_hdd()
{
	if (is_attached())
	{
		m_fHDDImageFile.Close();
		m_strImageFileName.Empty();
	}
}

bool CHDD::is_attached()
{
	return (m_fHDDImageFile.m_hFile != CFile::hFileNull);
}

bool CHDD::open_file()
{
	bool bRet = false;

	if (!m_strImageFileName.IsEmpty()) //если имя файла не пустое
	{
		if (bRet = (m_fHDDImageFile.Open(m_strImageFileName, CFile::modeReadWrite | CFile::shareDenyWrite) == TRUE))
		{
			m_bReadOnly = false;
		}
		else if (bRet = (m_fHDDImageFile.Open(m_strImageFileName, CFile::modeRead | CFile::shareDenyWrite) == TRUE))
		{
			m_bReadOnly = true;
		}
	}

	return bRet;
}

bool CHDD::configure()
{
	m_nPhase = HDD_IDE_PHASE_FAILURE;

	if (is_attached())
	{
		/* перемещаемся к началу файла */
		if (m_fHDDImageFile.Seek(0, CFile::begin) != 0)
		{
			return false;
		}

		/* читаем служебный сектор */
		if (m_fHDDImageFile.Read(m_pSectorBuffer.b, SECTOR_SIZE) != SECTOR_SIZE)
		{
			return false;    /* read error */
		}

		// проверим данные на валидность
		BYTE cs = 0;

		for (int i = 0; i < 511; ++i)
		{
			cs += m_pSectorBuffer.b[i];
		}

		cs = -cs;

		if (m_pSectorBuffer.b[511] == cs && m_pSectorBuffer.b[510] == 0xA5)
		{
			m_nCylinders = m_pSectorBuffer.w[1];
			m_nHeads = m_pSectorBuffer.w[3];
			m_nSectors = m_pSectorBuffer.w[6];
			command_ok();
			return true;
		}
	}

	return false;
}

void CHDD::command_ok()
{
	m_nPhase = HDD_IDE_PHASE_READY;
	m_nSectorPos_Word = -1;
	m_nErrorReg_1f1 = 0;
	m_nStatusReg_1f7 = STATUS_DRDY | STATUS_DSC;
}

void CHDD::write_regs(HDD_REGISTERS reg, WORD data)
{
	if (!is_attached())
	{
		return;
	}

	switch (reg)
	{
		case REG_1F0:
			if ((m_nDrvHeadReg_1f6 ^ m_nMasterSlave) & 0x10)
			{
				return;
			}

			if (m_nStatusReg_1f7 & STATUS_DRQ)
			{
				write_data(data);
			}

			break;

		case REG_1F1:
			if ((m_nStatusReg_1f7 & (STATUS_BSY | STATUS_DRQ)) == 0)
			{
				m_nFeaturesReg_1f1 = LOBYTE(data);
			}

			break;

		case REG_1F2:
			if ((m_nStatusReg_1f7 & (STATUS_BSY | STATUS_DRQ)) == 0)
			{
				m_nSectorCountReg_1f2 = LOBYTE(data);
			}

			break;

		case REG_1F3:
			if ((m_nStatusReg_1f7 & (STATUS_BSY | STATUS_DRQ)) == 0)
			{
				m_nSectorNumberReg_1f3 = LOBYTE(data);
			}

			break;

		case REG_1F4:
			if ((m_nStatusReg_1f7 & (STATUS_BSY | STATUS_DRQ)) == 0)
			{
				m_nCylNumberLowReg_1f4 = LOBYTE(data);
			}

			break;

		case REG_1F5:
			if ((m_nStatusReg_1f7 & (STATUS_BSY | STATUS_DRQ)) == 0)
			{
				m_nCylNumberHiReg_1f5 = LOBYTE(data);
			}

			break;

		case REG_1F6:
			if ((m_nStatusReg_1f7 & (STATUS_BSY | STATUS_DRQ)) == 0)
			{
				m_nDrvHeadReg_1f6 = LOBYTE(data); // | 0x20;
				BYTE hs = (m_nDrvHeadReg_1f6 & HDD_IDE_HEAD_HEAD) << 2;
				m_nDriveAddrReg_3f7 &= ~HDD_DRVADDR_HS;
				m_nDriveAddrReg_3f7 |= hs;

				if (m_nDrvHeadReg_1f6 & HDD_IDE_HEAD_DEV)
				{
					m_nDriveAddrReg_3f7 |= HDD_DRVADDR_DS1;
					m_nDriveAddrReg_3f7 &= ~HDD_DRVADDR_DS0;
				}
				else
				{
					m_nDriveAddrReg_3f7 |= HDD_DRVADDR_DS0;
					m_nDriveAddrReg_3f7 &= ~HDD_DRVADDR_DS1;
				}
			}

			break;

		case REG_1F7:
			if (((m_nDrvHeadReg_1f6 ^ m_nMasterSlave) & 0x10) && (data != 0x90))
			{
				return;
			}

			if ((m_nStatusReg_1f7 & (STATUS_BSY | STATUS_DRQ)) == 0)
			{
				m_nCommandReg_1f7 = LOBYTE(data);
#ifdef THREADED_MODEL
				m_nStatusReg_1f7 |= STATUS_BSY; //выставляем статус BSY, он снимается после выполнения команды
				m_pExecuteThread->ResumeThread();
#else
				execute_command(static_cast<HDD_IDE_COMMAND>(m_nCommandReg_1f7));
#endif // THREADED_MODEL
			}

			break;

		case REG_3F6:
			m_nControlReg_3f6 = LOBYTE(data);

			if (m_nControlReg_3f6 & CONTROL_SRST)
			{
				reset(false);
			}

			break;

		case REG_3F7:
			//не используется
			break;
			//запись в остальные значения надо просто игнорировать
	}
}

void CHDD::write_data(WORD data)
{
	if (!is_attached())
	{
		return;
	}

	/* Data register can only be written in PIO output phase */
	if (m_nPhase != HDD_IDE_PHASE_PIO_OUT)
	{
		return;
	}

	m_nStatusReg_1f7 |= STATUS_BSY;
	m_nDataReg_1f0 = data;
	m_pSectorBuffer.w[m_nSectorPos_Word++] = data; //пишем данные в буфер
	m_bChangeBuffer = true;

	if (m_nSectorPos_Word >= SECTOR_SIZEW) //если пришла пора сохранять буфер
	{
		m_nDriveAddrReg_3f7 |= HDD_DRVADDR_WG;

		if (!write_file())
		{
			m_nStatusReg_1f7 |= STATUS_ERR | STATUS_DWF;
			m_nErrorReg_1f1 = ERR_ABRT | ERR_AMNF;
		}

		if (m_nSectorCountReg_1f2)
		{
			writesector();
		}
		else
		{
			/* all sectors done */
			command_ok();
		}

		m_nDriveAddrReg_3f7 &= ~HDD_DRVADDR_WG;
	}

	m_nStatusReg_1f7 &= ~STATUS_BSY;
}

/* Execute the WRITE SECTOR command */
void CHDD::writesector()
{
	if (!is_attached())
	{
		return;
	}

	if (!seek())
	{
		m_nStatusReg_1f7 |= STATUS_ERR;
		m_nErrorReg_1f1 = ERR_ABRT | ERR_IDNF;
		return;
	}

	/* Initiate the PIO output phase */
	m_nPhase = HDD_IDE_PHASE_PIO_OUT;
	m_nStatusReg_1f7 |= STATUS_DRQ;
	m_nErrorReg_1f1 = 0;
	m_nSectorPos_Word = 0;
}

bool CHDD::write_file()
{
	if (!is_attached())
	{
		return false;
	}

	if (!m_bChangeBuffer) //если буфер не изменялся, то и записывать нечего.
	{
		return true;
	}

	long sector_position = DATA_OFFSET + (SECTOR_SIZE * m_nSectorNumber);

	/* перемещаемся к нужной позиции */
	if (m_fHDDImageFile.Seek(sector_position, CFile::begin) != sector_position)
	{
		return false;
	}

	/* Сохраняем сектор */
	try
	{
		m_fHDDImageFile.Write(m_pSectorBuffer.b, SECTOR_SIZE);
	}
	catch (...) //единственный способ узнать, произошла ли ошибка при записи
	{
		/* write error */
		return false;
	}

	m_bChangeBuffer = false;
	return true;
}

WORD CHDD::read_regs(HDD_REGISTERS reg)
{
	WORD dret = 0xffff;

	if (!is_attached())
	{
		return dret;
	}

	if ((m_nDrvHeadReg_1f6 ^ m_nMasterSlave) & 0x10)
	{
		return dret;
	}

	switch (reg)
	{
		case REG_1F0:
			if (m_nStatusReg_1f7 & STATUS_DRQ)
			{
				return read_data();
			}

			break;

		case REG_1F1:
			//if (((m_nStatusReg_1f7 & (STATUS_BSY | STATUS_DRQ)) == 0) && (m_nStatusReg_1f7 & STATUS_ERR)) //будем выдавать всегда.
			return (WORD)m_nErrorReg_1f1;
			break;

		case REG_1F2:
			if ((m_nStatusReg_1f7 & STATUS_BSY) == 0)
			{
				return (WORD)m_nSectorCountReg_1f2;
			}

			break;

		case REG_1F3:
			if ((m_nStatusReg_1f7 & STATUS_BSY) == 0)
			{
				return (WORD)m_nSectorNumberReg_1f3;
			}

			break;

		case REG_1F4:
			if ((m_nStatusReg_1f7 & STATUS_BSY) == 0)
			{
				return (WORD)m_nCylNumberLowReg_1f4;
			}

			break;

		case REG_1F5:
			if ((m_nStatusReg_1f7 & STATUS_BSY) == 0)
			{
				return (WORD)m_nCylNumberHiReg_1f5;
			}

			break;

		case REG_1F6:
			if ((m_nStatusReg_1f7 & STATUS_BSY) == 0)
			{
				return (WORD)m_nDrvHeadReg_1f6;
			}

			break;

		case REG_1F7:
			return (WORD)m_nStatusReg_1f7;

		case REG_3F6:
			return (WORD)m_nStatusReg_1f7;

		case REG_3F7:
			if ((m_nStatusReg_1f7 & STATUS_BSY) == 0)
			{
				return (WORD)m_nDriveAddrReg_3f7;
			}

			break;
	}

	return dret;
}

WORD CHDD::read_data()
{
	if (!is_attached())
	{
		return 0xffff;
	}

	if (m_nPhase != HDD_IDE_PHASE_PIO_IN)
	{
		return 0xffff;
	}

	m_nStatusReg_1f7 |= STATUS_BSY;
	m_nDataReg_1f0 = m_pSectorBuffer.w[m_nSectorPos_Word++];

	if (m_nSectorPos_Word >= SECTOR_SIZEW)
	{
		if (m_nSectorCountReg_1f2)
		{
			/* more sectors to read */
			readsector(false);
		}
		else
		{
			/* all sectors done */
			command_ok();
		}
	}

	m_nStatusReg_1f7 &= ~STATUS_BSY;
	return m_nDataReg_1f0;
}

void CHDD::read_verify_sector()
{
	if (!is_attached())
	{
		return;
	}

	if (m_nPhase != HDD_IDE_PHASE_READY)
	{
		return;
	}

#ifndef THREADED_MODEL
	m_nStatusReg_1f7 |= STATUS_BSY;
#endif

	while (m_nSectorCountReg_1f2 && ((m_nStatusReg_1f7 & STATUS_ERR) == 0))
	{
		/* more sectors to read */
		readsector(true);
	}

	/* all sectors done */
	m_nPhase = HDD_IDE_PHASE_READY;
	m_nSectorPos_Word = -1;
	m_nErrorReg_1f1 = 0;
#ifndef THREADED_MODEL
	m_nStatusReg_1f7 &= ~STATUS_BSY;
#endif
	return;
}
/* Execute the READ SECTOR command */
void CHDD::readsector(bool bVerify)
{
	if (!is_attached())
	{
		return;
	}

	if (!seek())
	{
		m_nStatusReg_1f7 |= STATUS_ERR;
		m_nErrorReg_1f1 = ERR_ABRT | ERR_IDNF;
		return;
	}

	/* Read data from disk */
	if (!read_file())
	{
		m_nStatusReg_1f7 |= STATUS_ERR;
		m_nErrorReg_1f1 = ERR_ABRT | ERR_AMNF | ERR_UNC;
	}
	else
	{
		/* Initiate the PIO input phase */
		m_nPhase = HDD_IDE_PHASE_PIO_IN;

		if (!bVerify)
		{
			m_nStatusReg_1f7 |= STATUS_DRQ;
		}

		m_nErrorReg_1f1 = 0;
		m_nSectorPos_Word = 0;
	}
}

bool CHDD::read_file()
{
	if (!is_attached())
	{
		return false;
	}

	long sector_position = DATA_OFFSET + (SECTOR_SIZE * m_nSectorNumber);

	/* Seek to the correct file position */
	if (m_fHDDImageFile.Seek(sector_position, CFile::begin) != sector_position)
	{
		return false;
	}

	/* Read the packed data into a temporary buffer */
	if (m_fHDDImageFile.Read(m_pSectorBuffer.b, SECTOR_SIZE) != SECTOR_SIZE)
	{
		return false;    /* read error */
	}

	m_bChangeBuffer = false;
	return true;
}

/* Seek to the addressed sector */
bool CHDD::seek()
{
	if (!is_attached())
	{
		return false;
	}

	int sectornumber;
	int next_head;

	/* Calculate sector number, depending upon LBA/CHS mode. */
	if (m_nDrvHeadReg_1f6 & HDD_IDE_HEAD_LBA)
	{
		sectornumber = (m_nDrvHeadReg_1f6 & HDD_IDE_HEAD_HEAD << 24) +
		               (m_nCylNumberHiReg_1f5 << 16) +
		               (m_nCylNumberLowReg_1f4 << 8) +
		               (m_nSectorNumberReg_1f3);
	}
	else
	{
		int cylinder = ((int)m_nCylNumberHiReg_1f5 << 8) | (m_nCylNumberLowReg_1f4);
		int head = (m_nDrvHeadReg_1f6 & HDD_IDE_HEAD_HEAD);
		int sector = (m_nSectorNumberReg_1f3 - 1);

		if (cylinder >= m_nCylinders || head >= m_nHeads ||
		        sector < 0 || sector >= m_nSectors)
		{
			sectornumber = -1;
		}
		else
		{
			sectornumber = (((cylinder * m_nHeads) + head) * m_nSectors) + sector;
		}
	}

	/* Seek to the correct position */
	if (sectornumber < 0 ||
	        sectornumber >= (m_nCylinders * m_nHeads * m_nSectors))
	{
		m_nStatusReg_1f7 |= STATUS_ERR;
		m_nErrorReg_1f1 = ERR_ABRT | ERR_IDNF;
		return false;
	}

	m_nSectorNumber = sectornumber;

	/* advance registers to next sector, for multiple sector accesses */
	if (--m_nSectorCountReg_1f2)
	{
		if (m_nDrvHeadReg_1f6 & HDD_IDE_HEAD_LBA)
		{
			/* increment using LBA scheme */
			m_nSectorNumberReg_1f3 = (m_nSectorNumberReg_1f3 + 1) & 0xff;

			if (!m_nSectorNumberReg_1f3)
			{
				m_nCylNumberLowReg_1f4 = (m_nCylNumberLowReg_1f4 + 1) & 0xff;

				if (!m_nCylNumberLowReg_1f4)
				{
					m_nCylNumberHiReg_1f5 = (m_nCylNumberHiReg_1f5 + 1) & 0xff;

					if (!m_nCylNumberHiReg_1f5)
					{
						next_head = ((m_nDrvHeadReg_1f6 & HDD_IDE_HEAD_HEAD) + 1) & HDD_IDE_HEAD_HEAD;
						m_nDrvHeadReg_1f6 = (m_nDrvHeadReg_1f6 & ~HDD_IDE_HEAD_HEAD) | next_head;
					}
				}
			}
		}
		else
		{
			/* increment using CHS scheme */
			m_nSectorNumberReg_1f3 = (m_nSectorNumberReg_1f3 % m_nSectors) + 1;

			/* NB sector number is 1-based */
			if (m_nSectorNumberReg_1f3 == 1)
			{
				next_head = ((m_nDrvHeadReg_1f6 & HDD_IDE_HEAD_HEAD) + 1) % m_nHeads;
				m_nDrvHeadReg_1f6 = (m_nDrvHeadReg_1f6 & ~HDD_IDE_HEAD_HEAD) | next_head;

				if (!next_head)
				{
					m_nCylNumberLowReg_1f4 = (m_nCylNumberLowReg_1f4 + 1) & 0xff;

					if (!m_nCylNumberLowReg_1f4)
					{
						m_nCylNumberHiReg_1f5++;
					}
				}
			}
		}
	}

	m_nStatusReg_1f7 |= STATUS_DSC;
	return true;
}

void CHDD::execute_command(HDD_IDE_COMMAND cmd)
{
	if (!is_attached())
	{
		return;
	}

	bool bRet = true;
	m_nErrorReg_1f1 = 0;
#ifdef THREADED_MODEL
	m_nStatusReg_1f7 &= STATUS_BSY; //очищаем всё кроме BSY
#else
	m_nStatusReg_1f7 = 0;
#endif // THREADED_MODEL
	TRACE1("HDD: Execute comand %02x\n", cmd);

	switch (cmd)
	{
		case HDD_IDE_COMMAND_NOP:
		case HDD_IDE_COMMAND_IDLE:
		case HDD_IDE_COMMAND_IDLE_IMMEDIATE:
		case HDD_IDE_COMMAND_RECALIBRATE:
		case HDD_IDE_SLEEP:
		case HDD_IDE_STANDBY:
		case HDD_IDE_STANBY_IMMEDIATE:
			command_ok();
			break;

		case HDD_IDE_COMMAND_READ_VERIFY_SECTOR_RETRY:
		case HDD_IDE_COMMAND_READ_VERIFY_SECTOR_NORETRY:
			read_verify_sector();
			break;

		case HDD_IDE_COMMAND_SEEK:
			if (!seek())
			{
				bRet = false;
			}
			else
			{
				command_ok();
			}

			break;

		case HDD_IDE_COMMAND_FORMAT_TRACK:
			command_ok();
			m_nStatusReg_1f7 |= STATUS_DRQ;
			break;

		case HDD_IDE_COMMAND_EXECUTE_DEVICE_DIAGNOSTICS:
			reset_signature(false);
			return;

		case HDD_IDE_COMMAND_READ_SECTOR_RETRY:
		case HDD_IDE_COMMAND_READ_SECTOR_NORETRY:
			readsector(false);
			break;

//пока непонятно как считать ecc и как принимать
//  case HDD_IDE_COMMAND_READ_LONG_SECTOR_RETRY:
//  case HDD_IDE_COMMAND_READ_LONG_SECTOR_NORETRY:
//      return;
		case HDD_IDE_COMMAND_WRITE_SECTOR_RETRY:
		case HDD_IDE_COMMAND_WRITE_SECTOR_NORETRY:
		case HDD_IDE_COMMAND_WRITE_VERIFY_SECTOR:
			if (m_bReadOnly)
			{
				m_nStatusReg_1f7 = STATUS_DWF;
			}
			else
			{
				writesector();
			}

			break;

//пока непонятно как считать ecc и как передавать
//  case HDD_IDE_COMMAND_WRITE_LONG_SECTOR_RETRY:
//  case HDD_IDE_COMMAND_WRITE_LONG_SECTOR_NORETRY:
//      return;
//ещё не реализовано.
//  case HDD_IDE_COMMAND_WRITE_SAME:
//  case HDD_IDE_COMMAND_READ_BUFFER:
//  case HDD_IDE_COMMAND_WRITE_BUFFER:
//  case HDD_IDE_COMMAND_INITIALIZE_DEVICE_PARAMETERS:
		case HDD_IDE_COMMAND_IDENTIFY_DEVICE:
			identifydevice();
			break;

		default:
			TRACE1("HDD: Unknown command %02x\n", cmd);
			bRet = false;
	}

	if (bRet)
	{
		m_nStatusReg_1f7 |= STATUS_DSC | STATUS_DRDY;
	}
	else
	{
		m_nStatusReg_1f7 |= STATUS_DSC | STATUS_DRDY | STATUS_ERR;
		m_nErrorReg_1f1 |= ERR_ABRT;
		m_nPhase = HDD_IDE_PHASE_READY;
	}
}

bool CHDD::identifydevice()
{
	if (is_attached())
	{
		/* перемещаемся к началу файла */
		if (m_fHDDImageFile.Seek(0, CFile::begin) == 0)
		{
			/* читаем служебный сектор */
			if (m_fHDDImageFile.Read(m_pSectorBuffer.b, SECTOR_SIZE) == SECTOR_SIZE)
			{
				m_nSectorCountReg_1f2 = 0;
				//в регистры CHS поместим геометрию диска
				//m_nSectorNumberReg_1f3 = m_nSectors;
				//m_nCylNumberLowReg_1f4 = LOBYTE(m_nCylinders); //LBA 15..8
				//m_nCylNumberHiReg_1f5 = HIBYTE(m_nCylinders); //LBA 23..16
				//m_nDrvHeadReg_1f6 &= ~HDD_IDE_HEAD_HEAD;
				//m_nDrvHeadReg_1f6 |= ((m_nHeads-1) & HDD_IDE_HEAD_HEAD);
				//в регистры CHS поместим начало диска
				m_nSectorNumberReg_1f3 = 1;
				m_nCylNumberLowReg_1f4 = 0; //LBA 15..8
				m_nCylNumberHiReg_1f5 = 0; //LBA 23..16
				m_nDrvHeadReg_1f6 &= ~HDD_IDE_HEAD_HEAD;
				/* Initiate the PIO input phase */
				m_nPhase = HDD_IDE_PHASE_PIO_IN;
				m_nStatusReg_1f7 |= STATUS_DRQ;
				m_nSectorPos_Word = 0;
				return true;
			}
		}
	}

	memset(m_pSectorBuffer.b, 0, SECTOR_SIZE);
	m_nSectorCountReg_1f2 = 0;
	/* Initiate the PIO input phase */
	m_nPhase = HDD_IDE_PHASE_FAILURE;
	m_nStatusReg_1f7 |= STATUS_ERR;
	m_nErrorReg_1f1 = ERR_ABRT | ERR_UNC;
	m_nSectorPos_Word = 0;
	return false;
}

void CHDD::reset(bool reset_hard)
{
	m_nControlReg_3f6 = 0;
	reset_signature(reset_hard);

	if (is_attached())
	{
		if (reset_hard)
		{
			command_ok();
		}
		else
		{
			m_nPhase = HDD_IDE_PHASE_READY;
			m_nSectorPos_Word = -1;
		}
	}
}

void CHDD::reset_signature(bool reset_hard)
{
	if (is_attached())
	{
		m_nSectorCountReg_1f2 = m_nSectorNumberReg_1f3 = m_nErrorReg_1f1 = 0x01;
		m_nCylNumberLowReg_1f4 = m_nCylNumberHiReg_1f5 = 0;
		m_nDrvHeadReg_1f6 = 0; // 0x20; //бит 5 всегда 1
		m_nStatusReg_1f7 = (reset_hard) ? 0 : STATUS_DRDY;
	}
	else
	{
		m_nPhase = HDD_IDE_PHASE_FAILURE;
		m_nDataReg_1f0 = 0xffff;
		m_nErrorReg_1f1 = m_nFeaturesReg_1f1 = m_nSectorCountReg_1f2 = m_nSectorNumberReg_1f3 =
		                                                                   m_nCylNumberLowReg_1f4 = m_nCylNumberHiReg_1f5 = m_nDrvHeadReg_1f6 = m_nStatusReg_1f7 =
		                                                                               m_nCommandReg_1f7 = m_nControlReg_3f6 = m_nDriveAddrReg_3f7 = 0xff;
	}
}

bool CATA_IDE::attach_master(const CString &name)
{
	bool bRet = m_mDrive[0].attach_hdd(name, false);
	m_mDrive[0].reset(true);
	return bRet;
}

bool CATA_IDE::attach_slave(const CString &name)
{
	bool bRet = m_mDrive[1].attach_hdd(name, true);
	m_mDrive[1].reset(true);
	return bRet;
}

void CATA_IDE::reset()
{
	m_mDrive[0].reset(true);
	m_mDrive[1].reset(true);
}

void CATA_IDE::write_regs(HDD_REGISTERS reg, WORD data)
{
	m_mDrive[0].write_regs(reg, data);
	m_mDrive[1].write_regs(reg, data);
}

WORD CATA_IDE::read_regs(HDD_REGISTERS reg)
{
	register WORD r0 = m_mDrive[0].read_regs(reg);
	register WORD r1 = m_mDrive[1].read_regs(reg);
	register WORD r = r0 & r1;
	return r;
}

// void CATA_IDE::write_data(WORD data)
// {
//  m_mDrive[0].write_data(data);
//  m_mDrive[1].write_data(data);
// }
//
// WORD CATA_IDE::read_data()
// {
//  return m_mDrive[0].read_data() & m_mDrive[1].read_data();
// }

//выдача отладчику содержимого регистров

WORD CHDD::get_debug_regs(HDD_REGISTERS reg, bool bReadMode)
{
	if (bReadMode)
	{
		//регистры по чтению
		switch (reg)
		{
			case REG_1F0:
				return m_nDataReg_1f0;

			case REG_1F1:
				return (WORD)m_nErrorReg_1f1;   //по чтению

			case REG_1F2:
				return (WORD)m_nSectorCountReg_1f2;

			case REG_1F3:
				return (WORD)m_nSectorNumberReg_1f3;

			case REG_1F4:
				return (WORD)m_nCylNumberLowReg_1f4;

			case REG_1F5:
				return (WORD)m_nCylNumberHiReg_1f5;

			case REG_1F6:
				return (WORD)m_nDrvHeadReg_1f6;

			case REG_1F7:
				return (WORD)m_nStatusReg_1f7;  //по чтению

			case REG_3F6:
				return (WORD)m_nStatusReg_1f7;  //по чтению

			case REG_3F7:
				return (WORD)m_nDriveAddrReg_3f7;
		}
	}
	else
	{
		//регистры по записи
		switch (reg)
		{
			case REG_1F0:
				return m_nDataReg_1f0;

			case REG_1F1:
				return (WORD)m_nFeaturesReg_1f1; //по записи

			case REG_1F2:
				return (WORD)m_nSectorCountReg_1f2;

			case REG_1F3:
				return (WORD)m_nSectorNumberReg_1f3;

			case REG_1F4:
				return (WORD)m_nCylNumberLowReg_1f4;

			case REG_1F5:
				return (WORD)m_nCylNumberHiReg_1f5;

			case REG_1F6:
				return (WORD)m_nDrvHeadReg_1f6;

			case REG_1F7:
				return (WORD)m_nCommandReg_1f7; //по записи

			case REG_3F6:
				return (WORD)m_nControlReg_3f6; //по записи

			case REG_3F7:
				return (WORD)m_nDriveAddrReg_3f7;
		}
	}

	return -1;
}

WORD CATA_IDE::get_debug_regs(int nDrive, HDD_REGISTERS reg, bool bReadMode)
{
	return m_mDrive[nDrive].get_debug_regs(reg, bReadMode);
}

