/*************************************************
*           BK Emulator v3.9 for Windows         *
*************************************************/

/*
File: Board_EXT32.cpp
Version: 1.0.0
Written by: Yuriy Kalmykov <kalmykov@stoik.com>
    Copyright (c) 2002-2004 Yuriy Kalmykov

    BK Emulator is a program emulated hardware environment for running
code for BK 0010(01) in different configurations.

    This code may be used in compiled form in any way you desire.
This file or it's parts can't be redistributed without the authors
written consent, but can be modified for your private needs.
    Providing that this notice and the authors name and all copyright
notices remains intact.

    Please, an email me to know how you are using it and where. You can
ask me for any information about this below code or any attendant
knowledge.

    This file is provided "as is" with no expressed or implied warranty.
The author accepts no liability for any damage or loss of business that
this product may cause.
*/


// Board_EXT32.cpp: implementation of the CMotherBoard_EXT32 class.
//


#include "stdafx.h"
#include "Board_EXT32.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction


CMotherBoard_EXT32::CMotherBoard_EXT32()
	: CMotherBoard()
{
	m_nBKPortsIOArea = BK_PORTSIO_AREA;
	// Инициализация модуля памяти, 64 кб + 32 кб доп.
	SAFE_DELETE_ARRAY(m_pMemory);
	m_pMemory = new BYTE [0300000];
	ZeroMemory(m_pMemory, 0300000);
}

CMotherBoard_EXT32::~CMotherBoard_EXT32()
{}

DWORD CMotherBoard_EXT32::GetConfiguration()
{
	return MSF_CONF_BK1001_EXT32;
}

bool CMotherBoard_EXT32::InitMemoryModules()
{
	bool bRes = true;
	bRes = bRes && LoadRomModule(IDS_INI_BK10_RE2_017_MONITOR, BRD_10_MON10_BNK);
	m_nPage = 3;

	//и проинициализируем карту памяти
	if (bRes)
	{
		MemoryManager();
	}

	return bRes;
}

void CMotherBoard_EXT32::MemoryManager()
{
	for (int i = 0; i < 020; i++)
	{
		m_MemoryMap[i].bReadable = true;
		m_MemoryMap[i].bWritable = true;
		m_MemoryMap[i].nBank = i;
		m_MemoryMap[i].nPage = i >> 2;
		m_MemoryMap[i].nOffset = i << 12;
	}

	m_MemoryMap[010].bWritable = false;
	m_MemoryMap[011].bWritable = false;

	//10, 11 банк - доп. озу.
	//12-15 банки - пусто, хотя туда можно было подрубать доп озу. кто придумал такую нерациональную схему, непонятно.
	for (int i = 014; i <= 017; i++)
	{
		m_MemoryMap[i].bReadable = false;
		m_MemoryMap[i].bWritable = false;
	}

	int ab = m_nPage * 2 + 020;

	for (int i = 012; i <= 013; i++)
	{
		m_MemoryMap[i].nBank = ab;
		m_MemoryMap[i].nPage = ab >> 2;
		m_MemoryMap[i].nOffset = ab << 12;
	}
}


void CMotherBoard_EXT32::SetMemoryPage(int nPage)
{
	m_nPage = nPage & 3;
	//и диспетчер памяти, мы тут должны поменять в 10м и 11м банках нужные нам банки
	MemoryManager();
}


void CMotherBoard_EXT32::SetByte(WORD addr, BYTE value)
{
	int nBank = (addr >> 12) & 0x0f;

	// Сперва проверим, на системные регистры
	if ((nBank == 15) && (addr >= m_nBKPortsIOArea))
	{
		if (OnSetSystemRegister(addr, value, true))
		{
			return;
		}
		else
		{
			throw CExceptionHalt(addr, _T("Can't write this address."));
		}
	}

	// monitor on 0100000 - 0120000
	if (010 <= nBank && nBank <= 011)
	{
		SetMemoryPage(value);
		return;
	}

	if (m_MemoryMap[nBank].bWritable)
	{
		m_pMemory[m_MemoryMap[nBank].nOffset + (addr & 007777)] = value;
	}
	else
	{
		throw CExceptionHalt(addr, _T("Can't write this address."));
	}
}


void CMotherBoard_EXT32::SetWord(WORD addr, WORD value)
{
	int nBank = (addr >> 12) & 0x0f;
	addr &= 0177776;

	// Сперва проверим, на системные регистры
	if ((nBank == 15) && (addr >= m_nBKPortsIOArea))
	{
		if (OnSetSystemRegister(addr, value, false))
		{
			return;
		}
		else
		{
			throw CExceptionHalt(addr, _T("Can't write this address."));
		}
	}

	// monitor on 0100000 - 0120000
	if (010 <= nBank && nBank <= 011)
	{
		SetMemoryPage(value);
		return;
	}

	if (m_MemoryMap[nBank].bWritable)
	{
		*(WORD *)&m_pMemory[m_MemoryMap[nBank].nOffset + (addr & 007777)] = value;
	}
	else
	{
		throw CExceptionHalt(addr, _T("Can't write this address."));
	}
}


bool CMotherBoard_EXT32::RestoreState(CMSFManager &msf, HBITMAP hScreenshot)
{
	if (RestorePreview(msf, hScreenshot))
	{
		if (RestoreConfig(msf))
		{
			if (RestoreRegisters(msf))
			{
				if (RestoreMemoryMap(msf))
				{
					if (RestoreMemory(msf))
					{
						if (msf.IsLoad())
						{
							if (msf.GetBlockExt32Memory(&m_nPage, m_pMemory + 65536))
							{
								return true;
							}
						}
						else
						{
							if (msf.SetBlockExt32Memory(m_nPage, m_pMemory + 65536))
							{
								return true;
							}
						}
					}
				}
			}
		}
	}

	return false;
}
