#include "pch.h"

#include "RegDumpViewCPU.h"
#include "Platform.h"
#include "Screen_Sizes.h"

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


CUSTOMVIEW_MODE_PARAM CRegDumpViewCPU::m_cvArray[CUSTOMVIEW_REGS_NUM] =
{
	{ CV_DEC_VIEW, IDS_REGDUMPCPU_DEC },
	{ CV_HEX_VIEW, IDS_REGDUMPCPU_HEX }
};

constexpr auto COLUMN_WIDTH_PRT = 78;
constexpr auto COLUMN_WIDTH_REG = 38;
constexpr auto COLUMN_WIDTH_TXT = 70;


constexpr auto COLNUM_CPU = 3;
constexpr auto COLNUM_SYS = 4;

constexpr auto ROWNUM_CPU = 9;
constexpr auto ROWNUM_SYS = 9;
constexpr auto ROWNUM_SMK = 2;


static const CRegDumpDocPaneDlgViewHelper::ColParam_t arLSTCPUCols[COLNUM_CPU] =
{
	{COL_WIDTH | COL_COLOR, COLUMN_WIDTH_REG, BG_COLOR},
	{COL_WIDTH | COL_EDITABLE, COLUMN_WIDTH, 0},
	{COL_WIDTH | COL_EDITABLE, COLUMN_WIDTH_TXT, 0}
};

static const CRegDumpDocPaneDlgViewHelper::CellParam_t arCPURows[ROWNUM_CPU][COLNUM_CPU] =
{
	{ {COL_VALUE | COL_COLOR, IDS_MEMORY_R0,  BG_COLOR}, {COL_EDITABLE, 0, 0}, {COL_EDITABLE, 0, 0} },
	{ {COL_VALUE | COL_COLOR, IDS_MEMORY_R1,  BG_COLOR}, {COL_EDITABLE, 0, 0}, {COL_EDITABLE, 0, 0} },
	{ {COL_VALUE | COL_COLOR, IDS_MEMORY_R2,  BG_COLOR}, {COL_EDITABLE, 0, 0}, {COL_EDITABLE, 0, 0} },
	{ {COL_VALUE | COL_COLOR, IDS_MEMORY_R3,  BG_COLOR}, {COL_EDITABLE, 0, 0}, {COL_EDITABLE, 0, 0} },
	{ {COL_VALUE | COL_COLOR, IDS_MEMORY_R4,  BG_COLOR}, {COL_EDITABLE, 0, 0}, {COL_EDITABLE, 0, 0} },
	{ {COL_VALUE | COL_COLOR, IDS_MEMORY_R5,  BG_COLOR}, {COL_EDITABLE, 0, 0}, {COL_EDITABLE, 0, 0} },
	{ {COL_VALUE | COL_COLOR, IDS_MEMORY_SP,  BG_COLOR}, {COL_EDITABLE, 0, 0}, {COL_EDITABLE, 0, 0} },
	{ {COL_VALUE | COL_COLOR, IDS_MEMORY_PC,  BG_COLOR}, {COL_EDITABLE, 0, 0}, {COL_EDITABLE, 0, 0} },
	{ {COL_VALUE | COL_COLOR, IDS_MEMORY_PSW, BG_COLOR}, {COL_EDITABLE, 0, 0}, {COL_EDITABLE, 0, 0} }
};

static const CRegDumpDocPaneDlgViewHelper::ColParam_t arLSTSYSCols[COLNUM_SYS] =
{
	{COL_WIDTH | COL_COLOR, COLUMN_WIDTH_PRT, BG_COLOR},
	{COL_WIDTH | COL_EDITABLE, COLUMN_WIDTH, 0},
	{COL_WIDTH | COL_COLOR, COLUMN_WIDTH, BG_COLOR},
	{COL_WIDTH | COL_EDITABLE, COLUMN_WIDTH, 0}
};

static const CRegDumpDocPaneDlgViewHelper::CellParam_t arSYSRows[ROWNUM_SYS][COLNUM_SYS] =
{
	{ {COL_VALUE | COL_COLOR, IDS_MEMORY_177660,        BG_COLOR}, {COL_EDITABLE, 0, 0}, {COL_VALUE | COL_COLOR, IDS_MEMORY_177700, BG_COLOR}, {COL_EDITABLE, 0, 0} },
	{ {COL_VALUE | COL_COLOR, IDS_MEMORY_177662IN,      BG_COLOR}, {COL_EDITABLE, 0, 0}, {COL_VALUE | COL_COLOR, IDS_MEMORY_177702, BG_COLOR}, {COL_EDITABLE, 0, 0} },
	{ {COL_VALUE | COL_COLOR, IDS_MEMORY_177662OUT,     BG_COLOR}, {COL_EDITABLE, 0, 0}, {COL_VALUE | COL_COLOR, IDS_MEMORY_177704, BG_COLOR}, {COL_EDITABLE, 0, 0} },
	{ {COL_VALUE | COL_COLOR, IDS_MEMORY_177664,        BG_COLOR}, {COL_EDITABLE, 0, 0}, {COL_VALUE | COL_COLOR, IDS_MEMORY_177706, BG_COLOR}, {COL_EDITABLE, 0, 0} },
	{ {COL_VALUE | COL_COLOR, IDS_MEMORY_177714IN,      BG_COLOR}, {COL_EDITABLE, 0, 0}, {COL_VALUE | COL_COLOR, IDS_MEMORY_177710, BG_COLOR}, {COL_EDITABLE, 0, 0} },
	{ {COL_VALUE | COL_COLOR, IDS_MEMORY_177714OUT,     BG_COLOR}, {COL_EDITABLE, 0, 0}, {COL_VALUE | COL_COLOR, IDS_MEMORY_177712, BG_COLOR}, {COL_EDITABLE, 0, 0} },
	{ {COL_VALUE | COL_COLOR, IDS_MEMORY_177716IN,      BG_COLOR}, {COL_EDITABLE, 0, 0}, {            COL_COLOR, 0,                 BG_COLOR}, {0, 0, 0} },
	{ {COL_VALUE | COL_COLOR, IDS_MEMORY_177716OUT_TAP, BG_COLOR}, {COL_EDITABLE, 0, 0}, {            COL_COLOR, 0,                 BG_COLOR}, {0, 0, 0} },
	{ {COL_VALUE | COL_COLOR, IDS_MEMORY_177716OUT_MEM, BG_COLOR}, {COL_EDITABLE, 0, 0}, {            COL_COLOR, 0,                 BG_COLOR}, {0, 0, 0} }
};

static const CRegDumpDocPaneDlgViewHelper::ColParam_t arLSTSMKCols[COLNUM_STD] =
{
	{COL_WIDTH | COL_COLOR, COLUMN_WIDTH_PRT, BG_COLOR},
	{COL_WIDTH | COL_EDITABLE, COLUMN_WIDTH, 0},
};

static const CRegDumpDocPaneDlgViewHelper::CellParam_t arSMKRows[ROWNUM_SMK][COLNUM_STD] =
{
	{ {COL_VALUE | COL_COLOR, IDS_ALTPRO_MODE,  BG_COLOR}, {COL_EDITABLE, 0, 0} },
	{ {COL_VALUE | COL_COLOR, IDS_ALTPRO_CODE,  BG_COLOR}, {COL_EDITABLE, 0, 0} },
};


const UINT CRegDumpViewCPU::m_pListSysRegs[2][LISTSYS_L::SYS_L_NUM] =
{
	{
		SYS_PORT_177660, SYS_PORT_177662_IN, SYS_PORT_177662_OUT, SYS_PORT_177664,
		SYS_PORT_177714_IN, SYS_PORT_177714_OUT, SYS_PORT_177716_IN, SYS_PORT_177716_OUT_TAP,
		SYS_PORT_177716_OUT_MEM
	},
	{
		SYS_PORT_177700, SYS_PORT_177702, SYS_PORT_177704, SYS_PORT_177706,
		SYS_PORT_177710, SYS_PORT_177712, 0, 0, 0
	}
};


/////////////////////////////////////////////////////////////////////////////
// CRegDumpViewCPU
IMPLEMENT_DYNAMIC(CRegDumpViewCPU, CRegDumpDocPaneDlgViewHelper)

CRegDumpViewCPU::CRegDumpViewCPU()
	: m_nCurrCPUFreq(0)
	, m_nCurrentCVM(CV_DEC_VIEW)
{
}

CRegDumpViewCPU::~CRegDumpViewCPU()
    = default;

void CRegDumpViewCPU::DoDataExchange(CDataExchange *pDX)
{
	CRegDumpDocPaneDlgViewHelper::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_LIST_RDC_CPUREGS, m_listCPU);
	DDX_Control(pDX, IDC_LIST_RDC_SYSREGS, m_listSys);
	DDX_Control(pDX, IDC_LIST_RDC_ALTPRO_DATA, m_listAltPro);
	DDX_Text(pDX, IDC_EDIT_RDC_CPUFREQ, m_nCurrCPUFreq);
	DDX_Control(pDX, IDC_SPIN_RDC_CPUFREQ, m_spinCPUFreq);
}

BEGIN_MESSAGE_MAP(CRegDumpViewCPU, CRegDumpDocPaneDlgViewHelper)
	ON_MESSAGE(WM_INITDIALOG, &CRegDumpViewCPU::HandleInitDialog)
	ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST_RDC_CPUREGS, &CRegDumpViewCPU::OnLvnItemchangedMdCpuRegisters)
	ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST_RDC_SYSREGS, &CRegDumpViewCPU::OnLvnItemchangedMdSysRegisters)
	ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST_RDC_ALTPRO_DATA, &CRegDumpViewCPU::OnLvnItemchangedMdAltProData)
	ON_EN_CHANGE(IDC_EDIT_RDC_CPUFREQ, &CRegDumpViewCPU::OnEnChangeEditDbg1Cpufreq)
	ON_COMMAND(IDC_BUTTON_RDC_CPUFREQ_DEC, &CRegDumpViewCPU::OnBnClickedButtonDbg1CpufreqDec)
	ON_COMMAND(IDC_BUTTON_RDC_CPUFREQ_INC, &CRegDumpViewCPU::OnBnClickedButtonDbg1CpufreqInc)
	ON_COMMAND(IDC_BUTTON_RDC_CPUFREQ_BASESET, &CRegDumpViewCPU::OnBnClickedButtonDbg1CpufreqBaseset)
	ON_COMMAND(IDC_BUTTON_RDC_CPUFREQ_MAXSET, &CRegDumpViewCPU::OnBnClickedButtonDbg1CpufreqMaxset)
	ON_COMMAND(IDC_BUTTON_RDC_CVMODE, &CRegDumpViewCPU::OnBnClickedRegdumpCvmode)
	ON_UPDATE_COMMAND_UI(IDC_BUTTON_RDC_CPUFREQ_DEC, &CRegDumpViewCPU::OnUpdateButtonDbg1CpufreqDec)
	ON_UPDATE_COMMAND_UI(IDC_BUTTON_RDC_CPUFREQ_INC, &CRegDumpViewCPU::OnUpdateButtonDbg1CpufreqInc)
	ON_UPDATE_COMMAND_UI(IDC_BUTTON_RDC_CPUFREQ_BASESET, &CRegDumpViewCPU::OnUpdateButtonDbg1CpufreqBaseset)
	ON_UPDATE_COMMAND_UI(IDC_BUTTON_RDC_CPUFREQ_MAXSET, &CRegDumpViewCPU::OnUpdateButtonDbg1CpufreqMaxset)
	ON_UPDATE_COMMAND_UI(IDC_BUTTON_RDC_CVMODE, &CRegDumpViewCPU::OnUpdateRegdumpCvmode)

END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// обработчики сообщений CRegDumpViewCPU
LRESULT CRegDumpViewCPU::HandleInitDialog(WPARAM wp, LPARAM lp)
{
	CRegDumpDocPaneDlgViewHelper::HandleInitDialog(wp, lp);
	m_ToolTip.AddTool(GetDlgItem(IDC_BUTTON_RDC_CPUFREQ_DEC), ID_CPU_SLOWDOWN);
	m_ToolTip.AddTool(GetDlgItem(IDC_BUTTON_RDC_CPUFREQ_INC), ID_CPU_ACCELERATE);
	m_ToolTip.AddTool(GetDlgItem(IDC_BUTTON_RDC_CPUFREQ_BASESET), ID_CPU_NORMALSPEED);
	m_ToolTip.AddTool(GetDlgItem(IDC_BUTTON_RDC_CVMODE), IDS_TOOLTIP_BUTTON_RDC_CVMODE);
	m_ToolTip.AddTool(GetDlgItem(IDC_EDIT_RDC_CPUFREQ), IDS_TOOLTIP_EDIT_RDC_CPUFREQ);
	m_ToolTip.AddTool(GetDlgItem(IDC_BUTTON_RDC_CPUFREQ_MAXSET), ID_CPU_MAXSPEED);
	// Подготовим ленту с иконками и имаджлист
	CBitmap m_bmparr;
	m_bmparr.LoadBitmap(IDR_MAINFRAME_256);
	CImageList m_imagelist;
	m_imagelist.Create(16, 15, ILC_COLORDDB | ILC_MASK, 0, 0);
	// Наложим ленту на имаджлист, учитывая фон/прозрачность (в нашем случае какой-то серый)
	m_imagelist.Add(&m_bmparr, RGB(192, 192, 192));
	// Вытаскиваем на кнопки по одной иконке из имаджлиста
	(reinterpret_cast<CButton *>(GetDlgItem(IDC_BUTTON_RDC_CPUFREQ_DEC)))->SetIcon(m_imagelist.ExtractIcon(7));
	(reinterpret_cast<CButton *>(GetDlgItem(IDC_BUTTON_RDC_CPUFREQ_INC)))->SetIcon(m_imagelist.ExtractIcon(5));
	(reinterpret_cast<CButton *>(GetDlgItem(IDC_BUTTON_RDC_CPUFREQ_BASESET)))->SetIcon(m_imagelist.ExtractIcon(8));
	(reinterpret_cast<CButton *>(GetDlgItem(IDC_BUTTON_RDC_CPUFREQ_MAXSET)))->SetIcon(m_imagelist.ExtractIcon(6));
	// Уничтожим ненужное более
	m_imagelist.DeleteImageList();
	m_bmparr.DeleteObject();

	std::vector <ListParam_t> vList;
	// Создадим список регистров CPU
	// 3 колонки, 1-я - имя регистра, 2-я - его значение, 3-я - кастомное значение
	vList.push_back({ COLNUM_CPU, ROWNUM_CPU, IDC_STATIC_RDC_CPUREGTITLE, &m_listCPU, &arLSTCPUCols[0], &arCPURows[0][0], true });
	// Создадим список портов и системных регистров
	// 4 колонки, 1-я и 3-я - адрес порта/регистра, 2-я и 4-я - их значения
	vList.push_back({ COLNUM_SYS, ROWNUM_SYS, IDC_STATIC_RDC_SYSREGTITLE, &m_listSys, &arLSTSYSCols[0], &arSYSRows[0][0], true });
	// создание списка режимов AltPro
	vList.push_back({ COLNUM_STD, ROWNUM_SMK, IDC_STATIC_RDC_SMKREGTITLE, &m_listAltPro, &arLSTSMKCols[0], &arSMKRows[0][0], true });
	// Оказалось, что в Windows XP и Windows 7 пользовательский интерфейс выглядит по разному,
	// и размеры списков различаются. В одной винде больше, в другой - меньше. Поэтому диалоги
	// со списками выглядят криво или там, или там, нельзя сделать, чтобы везде было одинаково красиво.
	// Из за этого их приходится динамически подгонять по размерам одного элемента списка.
	// Ну и заодно и расставлять в окне диалога красиво.
	int nMaxGrpWidth = 0;
	CPoint ptLT{ 0, 0 };

	for (auto &i : vList)
	{
		CreateList(i);
		ResizeList(i, ptLT, nMaxGrpWidth);  // и сразу подвинем
	}

	// теперь сделаем группы все одной ширины
	for (auto &i : vList)
	{
		SetGrpWidth(GetDlgItem(i.nGrpId), nMaxGrpWidth);
	}

	// ещё надо запретить редактировать свободные ячейки в 3-м столбце
	for (int i = LISTSYS_L2::LINE_REG177712 + 1; i <= LISTSYS_L::LINE_REG177716OUT_MEM; ++i)
	{
		m_listSys.EnableEdit(false, i, LISTSYS_C::COL_VALUE2);
	}

	// и пододвинем кнопку на место
	CRect rect, btnRect;
	m_listCPU.GetWindowRect(&rect);     // текущие размеры списка
	ScreenToClient(&rect);
	GetDlgItem(IDC_BUTTON_RDC_CVMODE)->GetWindowRect(btnRect);
	rect.left = rect.right + m_padX;
	GetDlgItem(IDC_BUTTON_RDC_CVMODE)->SetWindowPos(nullptr, rect.left, rect.top, btnRect.Width(), btnRect.Height(), SWP_SHOWWINDOW);
	SetDlgItemText(IDC_BUTTON_RDC_CVMODE, CString(MAKEINTRESOURCE(m_cvArray[m_nCurrentCVM].strID)));
	//и под конец изменим размеры самого окна
	GetWindowRect(&rect);
	ScreenToClient(&rect);
	rect.bottom = ptLT.y - ::GetSystemMetrics(SM_CYCAPTION) / 2;
	rect.right = ptLT.x + nMaxGrpWidth;
	m_sizeDefault = rect.Size();
	return TRUE; // return TRUE unless you set the focus to a control
	// EXCEPTION: OCX Property Pages should return FALSE
}

CString CRegDumpViewCPU::FormatPSW(uint16_t value)
{
	//                   012345678
	CString strPSW = _T("--------");
	TCHAR *pStr = strPSW.GetBuffer();

	if (value & (1 << static_cast<int>(PSW_BIT::HALT)))
	{
		pStr[0] = _T('H');
	}

	if (value & (1 << static_cast<int>(PSW_BIT::MASKI)))
	{
		pStr[1] = _T('M');
	}

	if (value & (1 << static_cast<int>(PSW_BIT::P)))
	{
		pStr[2] = _T('P');
	}

	if (value & (1 << static_cast<int>(PSW_BIT::T)))
	{
		pStr[3] = _T('T');
	}

	if (value & (1 << static_cast<int>(PSW_BIT::N)))
	{
		pStr[4] = _T('N');
	}

	if (value & (1 << static_cast<int>(PSW_BIT::Z)))
	{
		pStr[5] = _T('Z');
	}

	if (value & (1 << static_cast<int>(PSW_BIT::V)))
	{
		pStr[6] = _T('V');
	}

	if (value & (1 << static_cast<int>(PSW_BIT::C)))
	{
		pStr[7] = _T('C');
	}

	return strPSW;
}


uint16_t CRegDumpViewCPU::GetPSW(CString &strPSW)
{
	uint16_t psw = 0;
	strPSW.Trim();
	strPSW.MakeUpper();
	int nStrLen = strPSW.GetLength();
	const TCHAR *pStr = strPSW.GetString();

	// все символы могут быть любыми, но воспринимаются только те, что нужны.
	// причём порядок следования не важен, количество символов не важно
	for (int i = 0; i < nStrLen; ++i)
	{
		switch (pStr[i])
		{
			case _T('C'):
				psw |= (1 << static_cast<int>(PSW_BIT::C));
				break;

			case _T('V'):
				psw |= (1 << static_cast<int>(PSW_BIT::V));
				break;

			case _T('Z'):
				psw |= (1 << static_cast<int>(PSW_BIT::Z));
				break;

			case _T('N'):
				psw |= (1 << static_cast<int>(PSW_BIT::N));
				break;

			case _T('T'):
				psw |= (1 << static_cast<int>(PSW_BIT::T));
				break;

			case _T('P'):
				psw |= (1 << static_cast<int>(PSW_BIT::P));
				break;

			case _T('M'):
				psw |= (1 << static_cast<int>(PSW_BIT::MASKI));
				break;

			case _T('H'):
				psw |= (1 << static_cast<int>(PSW_BIT::HALT));
				break;
		}
	}

	return psw;
}

void CRegDumpViewCPU::DisplayPortRegs()
{
	for (int i = LISTSYS_L::LINE_REG177660; i <= LISTSYS_L::LINE_REG177716OUT_MEM; ++i)
	{
		m_listSys.SetItemWithModified(g_Platform.GetDebuggerPtr()->GetPortValue(m_pListSysRegs[0][i]), i, LISTSYS_C::COL_VALUE1);
	}

	for (int i = LISTSYS_L2::LINE_REG177700; i <= LISTSYS_L2::LINE_REG177712; ++i)
	{
		m_listSys.SetItemWithModified(g_Platform.GetDebuggerPtr()->GetPortValue(m_pListSysRegs[1][i]), i, LISTSYS_C::COL_VALUE2);
	}
}

void CRegDumpViewCPU::DisplayRegisters()
{
	for (int i = LISTCPU_L::LINE_R0; i <= LISTCPU_L::LINE_PC; ++i)
	{
		uint16_t val = g_Platform.GetDebuggerPtr()->GetRegister(static_cast<CCPU::REGISTER>(i));
		// выводим первую колонку
		m_listCPU.SetItemWithModified(val, i, LISTCPU_C::COL_VALUE);
		// вторую колонку
		CString str = WordToCustom(val);
		m_listCPU.SetItemWithModifiedASCII(str, i, LISTCPU_C::COL_CUSTOM);
	}

	m_listCPU.SetItemWithModified(g_Platform.GetDebuggerPtr()->GetRegister(static_cast<CCPU::REGISTER>(LISTCPU_L::LINE_PSW)), LISTCPU_L::LINE_PSW, LISTCPU_C::COL_VALUE);
	SetPSW(g_Platform.GetCPUPtr()->GetPSW());
}

void CRegDumpViewCPU::SetPSW(uint16_t value)
{
	CString str = FormatPSW(value);
	m_listCPU.SetItemWithModifiedASCII(str, LISTCPU_L::LINE_PSW, LISTCPU_C::COL_CUSTOM);
}

void CRegDumpViewCPU::DisplayAltProData()
{
	m_listAltPro.SetItemWithModified(g_Platform.GetDebuggerPtr()->GetAltProData(LISTALTPRO_L::LINE_MODE), LISTALTPRO_L::LINE_MODE, LSTSTD_COL::VALUE);
	m_listAltPro.SetItemWithModified(g_Platform.GetDebuggerPtr()->GetAltProData(LISTALTPRO_L::LINE_CODE), LISTALTPRO_L::LINE_CODE, LSTSTD_COL::VALUE);
}


void CRegDumpViewCPU::OnLvnItemchangedMdCpuRegisters(NMHDR *pNMHDR, LRESULT *pResult)
{
	auto pNMListView = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
	*pResult = S_OK;
	int nSubItem = pNMListView->iSubItem;
	int pos = pNMListView->iItem;
	auto reg = static_cast<CCPU::REGISTER>(pos);
	ASSERT(reg <= CCPU::REGISTER::PSW);
	uint16_t value;

	if (nSubItem == LISTCPU_C::COL_VALUE)
	{
		auto pStr = reinterpret_cast<CString *>(pNMListView->lParam);
		value = Global::OctStringToWord(*pStr);
	}
	else if (nSubItem == LISTCPU_C::COL_CUSTOM)
	{
		auto pStr = reinterpret_cast<CString *>(pNMListView->lParam);
		value = (reg == CCPU::REGISTER::PSW) ? GetPSW(*pStr) : CustomToWord(*pStr);
	}
	else
	{
		return; // nSubItem может быть и другое значение
	}

	g_Platform.GetDebuggerPtr()->SetDebugRegs(reg, value);

	if (reg == CCPU::REGISTER::PSW)
	{
		m_listCPU.SetItemWithModified(value, LISTCPU_L::LINE_PSW, LISTCPU_C::COL_VALUE);
		SetPSW(value);
	}
	else
	{
		m_listCPU.SetItemWithModified(value, pos, LISTCPU_C::COL_VALUE);
		CString str = WordToCustom(value);
		m_listCPU.SetItemWithModifiedASCII(str, pos, LISTCPU_C::COL_CUSTOM);
	}
}

CString CRegDumpViewCPU::WordToCustom(uint16_t value)
{
	CString str;

	switch (m_nCurrentCVM)
	{
		case CV_DEC_VIEW:
			str.Format(_T("%05d"), value);
			break;

		case CV_HEX_VIEW:
			str.Format(_T("0x%04x"), value);
			break;
	}

	return str;
}

uint16_t CRegDumpViewCPU::CustomToWord(const CString &str)
{
	uint16_t res = 0;

	switch (m_nCurrentCVM)
	{
		case CV_DEC_VIEW:
			res = _ttoi(str);
			break;

		case CV_HEX_VIEW:
			res = uint16_t(_tcstol(str, nullptr, 16));
			break;
	}

	return res;
}

void CRegDumpViewCPU::OnLvnItemchangedMdAltProData(NMHDR *pNMHDR, LRESULT *pResult)
{
	auto pNMListView = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
	int nSubItem = pNMListView->iSubItem;

	if (nSubItem == LISTALTPRO_L::LINE_CODE)
	{
		int pos = pNMListView->iItem;
		auto pStr = reinterpret_cast<CString *>(pNMListView->lParam);
		uint16_t value = Global::OctStringToWord(*pStr);
		g_Platform.GetDebuggerPtr()->SetDebugAltProData(pos, value);
		m_listAltPro.SetItemWithModified(value, pos, nSubItem);
		// Тут надо принудительно обновить содержимое дампера
		GetParentFrame()->PostMessage(WM_MEMDUMP_NEED_UPDATE);
	}

	*pResult = S_OK;
}


void CRegDumpViewCPU::OnLvnItemchangedMdSysRegisters(NMHDR *pNMHDR, LRESULT *pResult)
{
	auto pNMListView = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
	*pResult = S_OK;
	int pos = -1;
	int nSubItem = pNMListView->iSubItem;
	int nitem = pNMListView->iItem;

	switch (nSubItem)
	{
		case LISTSYS_C::COL_VALUE1:
			ASSERT(nitem <= LISTSYS_L::LINE_REG177716OUT_MEM);
			pos = m_pListSysRegs[0][nitem];
			break;

		case LISTSYS_C::COL_VALUE2:
			ASSERT(nitem <= LISTSYS_L2::LINE_REG177712);
			pos = m_pListSysRegs[1][nitem];
			break;

		default:
			return;
	}

	auto pStr = reinterpret_cast<CString *>(pNMListView->lParam);
	uint16_t value = Global::OctStringToWord(*pStr);
	g_Platform.GetDebuggerPtr()->SetDebugPorts(pos, value);
	m_listSys.SetItemWithModified(value, nitem, nSubItem);
}

void CRegDumpViewCPU::OnEnChangeEditDbg1Cpufreq()
{
	UpdateData(TRUE);
	g_Platform.SetCPUFreq(m_nCurrCPUFreq);
}

void CRegDumpViewCPU::OnBnClickedButtonDbg1CpufreqDec()
{
	GetParentFrame()->PostMessage(WM_COMMAND, ID_CPU_SLOWDOWN);
}

void CRegDumpViewCPU::OnBnClickedButtonDbg1CpufreqInc()
{
	GetParentFrame()->PostMessage(WM_COMMAND, ID_CPU_ACCELERATE);
}

void CRegDumpViewCPU::OnBnClickedButtonDbg1CpufreqBaseset()
{
	GetParentFrame()->PostMessage(WM_COMMAND, ID_CPU_NORMALSPEED);
}

void CRegDumpViewCPU::OnBnClickedButtonDbg1CpufreqMaxset()
{
	GetParentFrame()->PostMessage(WM_COMMAND, ID_CPU_MAXSPEED);
}

void CRegDumpViewCPU::OnUpdateButtonDbg1CpufreqDec(CCmdUI *pCmdUI)
{
	bool bOn = g_Platform.CanSlowDown();
	pCmdUI->Enable(bOn);
}

void CRegDumpViewCPU::OnUpdateButtonDbg1CpufreqInc(CCmdUI *pCmdUI)
{
	bool bOn = g_Platform.CanAccelerate();
	pCmdUI->Enable(bOn);
}

void CRegDumpViewCPU::OnUpdateButtonDbg1CpufreqMaxset(CCmdUI *pCmdUI)
{
	bool bChk = (g_Config.m_nCPUTempFreq >= 0);
	pCmdUI->SetCheck(bChk);
}

void CRegDumpViewCPU::OnUpdateButtonDbg1CpufreqBaseset(CCmdUI *pCmdUI)
{
	pCmdUI->Enable(true);
}

void CRegDumpViewCPU::OnUpdateRegdumpCvmode(CCmdUI *pCmdUI)
{
	pCmdUI->Enable(true);
}

// отобразим текущую частоту
void CRegDumpViewCPU::SetFreqParam()
{
	m_nCurrCPUFreq = g_Platform.GetCPUFreq();
	m_spinCPUFreq.SetRange32(g_Platform.GetLowBound(), g_Platform.GetHighBound());
	m_spinCPUFreq.SetPos32(m_nCurrCPUFreq);
	m_spinCPUFreq.SetBuddy(GetDlgItem(IDC_EDIT_RDC_CPUFREQ));
	UpdateData(FALSE);
}

void CRegDumpViewCPU::UpdateFreq()
{
	m_nCurrCPUFreq = g_Platform.GetCPUFreq();
	UpdateData(FALSE);
}

void CRegDumpViewCPU::DisplayRegDump()
{
	if (IsWindowVisible())
	{
		DisplayRegisters();
		DisplayPortRegs();
		if (g_Platform.GetPlatformStatus() & CONFPLATFORM_ALTPRO)
		{
			DisplayAltProData();
		}
		// выводим на экран данные FDD
	}
}

void CRegDumpViewCPU::OnBnClickedRegdumpCvmode()
{
	if (++m_nCurrentCVM >= CUSTOMVIEW_REGS_NUM)
	{
		m_nCurrentCVM = 0;
	}

	SetDlgItemText(IDC_BUTTON_RDC_CVMODE, CString(MAKEINTRESOURCE(m_cvArray[m_nCurrentCVM].strID)));

	// если мы в отладочном останове, то
	if (g_Platform.IsCPUBreaked())
	{
		DisplayRegisters(); // надо вручную обновить регистры
	}
}

