// RegDumpCPUDlg.cpp : implementation file
//

#include "stdafx.h"
#include "RegDumpCPUDlg.h"
#include "afxdialogex.h"
#include "Board.h"
#include "Debugger.h"

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

/////////////////////////////////////////////////////////////////////////////
// CRegDumpDlg dialog
CUSTOMVIEW_MODE_PARAM CRegDumpCPUDlg::m_cvArray[NUMBER_CUSTOMVIEWS_REGS] =
{
	{ CV_DEC_VIEW, _T("DEC") },
	{ CV_HEX_VIEW, _T("HEX") }
};

CRegDumpCPUDlg::CRegDumpCPUDlg(CWnd *pParent /*=NULL*/)
	: CDialogEx(CRegDumpCPUDlg::IDD, pParent)
	, m_pDebugger(nullptr)
	, m_hAccelTable(nullptr)
	, m_nCurrCPUFreq(0)
	, m_nCurrentCVM(CV_DEC_VIEW)
{
}

CRegDumpCPUDlg::~CRegDumpCPUDlg()
{
	hFont.DeleteObject();
}

void CRegDumpCPUDlg::DoDataExchange(CDataExchange *pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_MD_CPU_REGISTERS, m_listCPU);
	DDX_Control(pDX, IDC_MD_SYS_REGISTERS, m_listSys);
	DDX_Control(pDX, IDC_MD_ALTPRO_DATA, m_listAltPro);
	DDX_Text(pDX, IDC_EDIT_DBG1_CPUFREQ, m_nCurrCPUFreq);
	DDX_Control(pDX, IDC_SPIN_DBG1_CPUFREQ, m_spinCPUFreq);
}


BEGIN_MESSAGE_MAP(CRegDumpCPUDlg, CDialogEx)
	ON_WM_SIZE()
	ON_NOTIFY(LVN_ITEMCHANGED, IDC_MD_CPU_REGISTERS, &OnLvnItemchangedMdCpuRegisters)
	ON_NOTIFY(LVN_ITEMCHANGED, IDC_MD_SYS_REGISTERS, &OnLvnItemchangedMdSysRegisters)
	ON_NOTIFY(LVN_ITEMCHANGED, IDC_MD_ALTPRO_DATA, &OnLvnItemchangedMdAltProData)
	ON_EN_CHANGE(IDC_EDIT_DBG1_CPUFREQ, &OnEnChangeEditDbg1Cpufreq)
	ON_BN_CLICKED(IDC_BUTTON_DBG1_CPUFREQ_DEC, &OnBnClickedButtonDbg1CpufreqDec)
	ON_BN_CLICKED(IDC_BUTTON_DBG1_CPUFREQ_INC, &OnBnClickedButtonDbg1CpufreqInc)
	ON_BN_CLICKED(IDC_BUTTON_DBG1_CPUFREQ_BASESET, &OnBnClickedButtonDbg1CpufreqBaseset)
	ON_BN_CLICKED(IDC_BUTTON_REGDUMP_CVMODE, &OnBnClickedRegdumpCvmode)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CRegDumpDlg message handlers
const UINT CRegDumpCPUDlg::m_pListCpuIDs[9] =
{
	IDS_MEMORY_R0, IDS_MEMORY_R1, IDS_MEMORY_R2, IDS_MEMORY_R3,
	IDS_MEMORY_R4, IDS_MEMORY_R5, IDS_MEMORY_SP, IDS_MEMORY_PC,
	IDS_MEMORY_PSW
};

const UINT CRegDumpCPUDlg::m_pListSysIDs[2][9] =
{
	{
		IDS_MEMORY_177660, IDS_MEMORY_177662IN, IDS_MEMORY_177662OUT, IDS_MEMORY_177664,
		IDS_MEMORY_177714IN, IDS_MEMORY_177714OUT, IDS_MEMORY_177716IN, IDS_MEMORY_177716OUT_TAP,
		IDS_MEMORY_177716OUT_MEM
	},
	{
		IDS_MEMORY_177700, IDS_MEMORY_177702, IDS_MEMORY_177704, IDS_MEMORY_177706,
		IDS_MEMORY_177710, IDS_MEMORY_177712, 0, 0, 0
	}
};

const UINT CRegDumpCPUDlg::m_pListSysRegs[2][9] =
{
	{
		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
	}
};


const UINT CRegDumpCPUDlg::m_pListAltProIDs[2] =
{
	IDS_ALTPRO_MODE, IDS_ALTPRO_CODE
};


void CRegDumpCPUDlg::ResizeList(CMultiEditListCtrl *list, int height)
{
	CRect rect, itemRect;
	list->GetWindowRect(&rect);
	ScreenToClient(&rect);

	if (list->GetItemRect(0, itemRect, LVIR_BOUNDS))
	{
		register int cx = itemRect.Width() + GetSystemMetrics(SM_CXDLGFRAME);
		register int cy = itemRect.Height() * height + GetSystemMetrics(SM_CYDLGFRAME);
		list->SetWindowPos(nullptr, rect.left, rect.top, cx, cy, SWP_SHOWWINDOW);
	}
}

BOOL CRegDumpCPUDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();
	m_hAccelTable = LoadAccelerators(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_MAINFRAME));
	LOGFONT lf;
	::GetObject((HGDIOBJ)::SendMessage(GetSafeHwnd(), WM_GETFONT, 0, 0), sizeof(LOGFONT), &lf);
	_tcscpy_s(lf.lfFaceName, LF_FACESIZE, _T("Courier New\0"));

	if (!hFont.CreateFontIndirect(&lf))
	{
		_tcscpy_s(lf.lfFaceName, LF_FACESIZE, _T("Lucida Console\0"));
		hFont.CreateFontIndirect(&lf);
	}

	// Подсказки
	m_ToolTip.Create(this, WS_POPUP | TTS_NOPREFIX | TTS_USEVISUALSTYLE | TTS_ALWAYSTIP/* | TTS_BALLOON*/);
	m_ToolTip.SetDelayTime(TTDT_AUTOPOP, 20000);
	//*** you could change the defualt settings ***
	m_ToolTip.SetMaxTipWidth(200);
	//m_ToolTip.SetTipBkColor(RGB(121, 121, 121));
	//m_ToolTip.SetTipTextColor(RGB(255, 0, 0));
	m_ToolTip.AddTool(GetDlgItem(IDC_BUTTON_DBG1_CPUFREQ_DEC), ID_CPU_SLOWDOWN);
	m_ToolTip.AddTool(GetDlgItem(IDC_BUTTON_DBG1_CPUFREQ_INC), ID_CPU_ACCELERATE);
	m_ToolTip.AddTool(GetDlgItem(IDC_BUTTON_DBG1_CPUFREQ_BASESET), ID_CPU_NORMALSPEED);

	// Подготовим ленту с иконками и имаджлист
	CBitmap m_bmparr;
	m_bmparr.LoadBitmap(IDR_MAINFRAME_256);
	CImageList m_imagelist;
	m_imagelist.Create(16, 15, ILC_COLOR32 | ILC_MASK, 0, 0);
//	m_imagelist.SetBkColor(RGB(200, 200, 200));
	// Наложим ленту на имаджлист, учитывая фон/прозрачность (в нашем случае какой-то серый)
	m_imagelist.Add(&m_bmparr, RGB(192, 192, 192));

	// Вытаскиваем на кнопки по одной иконке из имаджлиста
	(reinterpret_cast<CButton *>(GetDlgItem(IDC_BUTTON_DBG1_CPUFREQ_DEC)))->SetIcon(m_imagelist.ExtractIcon(5));
	(reinterpret_cast<CButton *>(GetDlgItem(IDC_BUTTON_DBG1_CPUFREQ_INC)))->SetIcon(m_imagelist.ExtractIcon(4));
	(reinterpret_cast<CButton *>(GetDlgItem(IDC_BUTTON_DBG1_CPUFREQ_BASESET)))->SetIcon(m_imagelist.ExtractIcon(6));
	// Уничтожим ненужное более
	m_imagelist.DeleteImageList();
	m_bmparr.DeleteObject();

	int nPixelW = GetDeviceCaps(GetDC()->GetSafeHdc(), LOGPIXELSX);
	// Создадим список регистров CPU
	// 3 колонки, 1-я - имя регистра, 2-я - его значение, 3-я - кастомное значение
	CString strHeader;
	m_listCPU.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_DOUBLEBUFFER | LVS_EX_SNAPTOGRID);
	m_listCPU.SetFont(&hFont, FALSE);
	m_listCPU.AcceptDigits(false); //принимаем не только цифры
	m_listCPU.InsertColumn(LISTCPU_NAME_COL, LPSTR_TEXTCALLBACK, LVCFMT_LEFT, MulDiv(COLUMN_WIDTH_REG, nPixelW, 96));
	m_listCPU.InsertColumn(LISTCPU_VALUE_COL, LPSTR_TEXTCALLBACK, LVCFMT_LEFT, MulDiv(COLUMN_WIDTH, nPixelW, 96));
	m_listCPU.InsertColumn(LISTCPU_CUSTOM_VALUE_COL, LPSTR_TEXTCALLBACK, LVCFMT_RIGHT, MulDiv(COLUMN_WIDTH_TXT, nPixelW, 96));

	for (int i = R0_LINE; i <= PSW_LINE; ++i)
	{
		strHeader.LoadString(m_pListCpuIDs[i]);
		m_listCPU.InsertItem(i, strHeader);
		m_listCPU.SetItem(i, LISTCPU_VALUE_COL, LVIF_TEXT, LPSTR_TEXTCALLBACK, 0, 0, 0, 0);
		m_listCPU.SetItem(i, LISTCPU_CUSTOM_VALUE_COL, LVIF_TEXT, LPSTR_TEXTCALLBACK, 0, 0, 0, 0);
	}

	ResizeList(&m_listCPU, PSW_LINE + 1);
	m_listCPU.SetColumnBkColor(GetSysColor(COLOR_BTNFACE), LISTCPU_NAME_COL);
	m_listCPU.EnableColumnEdit(false, LISTCPU_NAME_COL);
	// Создадим список портов и системных регистров
	// 4 колонки, 1-я и 3-я - адрес порта/регистра, 2-я и 4-я - их значения
	m_listSys.SetFont(&hFont, FALSE);
	m_listSys.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_DOUBLEBUFFER | LVS_EX_SNAPTOGRID);
	m_listSys.InsertColumn(LISTSYS_NAME1_COL, LPSTR_TEXTCALLBACK, LVCFMT_LEFT, MulDiv(COLUMN_WIDTH_PRT, nPixelW, 96));
	m_listSys.InsertColumn(LISTSYS_VALUE1_COL, LPSTR_TEXTCALLBACK, LVCFMT_LEFT, MulDiv(COLUMN_WIDTH, nPixelW, 96));
	m_listSys.InsertColumn(LISTSYS_NAME2_COL, LPSTR_TEXTCALLBACK, LVCFMT_LEFT, MulDiv(COLUMN_WIDTH, nPixelW, 96));
	m_listSys.InsertColumn(LISTSYS_VALUE2_COL, LPSTR_TEXTCALLBACK, LVCFMT_LEFT, MulDiv(COLUMN_WIDTH, nPixelW, 96));

	for (int i = REG177660_LINE; i <= REG177716OUT_MEM_LINE; ++i)
	{
		strHeader.LoadString(m_pListSysIDs[0][i]);
		m_listSys.InsertItem(i, strHeader);
		m_listSys.SetItem(i, LISTSYS_VALUE1_COL, LVIF_TEXT, LPSTR_TEXTCALLBACK, 0, 0, 0, 0);

		if (m_pListSysIDs[1][i])
		{
			strHeader.LoadString(m_pListSysIDs[1][i]);
		}
		else
		{
			strHeader = _T("");
		}

		m_listSys.SetItem(i, LISTSYS_NAME2_COL, LVIF_TEXT, strHeader, 0, 0, 0, 0);
		m_listSys.SetItem(i, LISTSYS_VALUE2_COL, LVIF_TEXT, LPSTR_TEXTCALLBACK, 0, 0, 0, 0);
	}

	m_listSys.SetColumnBkColor(GetSysColor(COLOR_BTNFACE), LISTSYS_NAME1_COL);
	m_listSys.EnableColumnEdit(false, LISTSYS_NAME1_COL);
	m_listSys.SetColumnBkColor(GetSysColor(COLOR_BTNFACE), LISTSYS_NAME2_COL);
	m_listSys.EnableColumnEdit(false, LISTSYS_NAME2_COL);

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

	ResizeList(&m_listSys, REG177716OUT_MEM_LINE + 1);
	//создание списка режимов AltPro
	m_listAltPro.SetFont(&hFont, FALSE);
	m_listAltPro.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_DOUBLEBUFFER | LVS_EX_SNAPTOGRID);
	m_listAltPro.InsertColumn(LISTALTPRO_NAME_COL, LPSTR_TEXTCALLBACK, LVCFMT_LEFT, MulDiv(COLUMN_WIDTH_PRT, nPixelW, 96));
	m_listAltPro.InsertColumn(LISTALTPRO_VALUE_COL, LPSTR_TEXTCALLBACK, LVCFMT_LEFT, MulDiv(COLUMN_WIDTH, nPixelW, 96));

	for (int i = ALTPRO_MODE_LINE; i <= ALTPRO_CODE_LINE; ++i)
	{
		strHeader.LoadString(m_pListAltProIDs[i]);
		m_listAltPro.InsertItem(i, strHeader);
		m_listAltPro.SetItem(i, LISTALTPRO_VALUE_COL, LVIF_TEXT, nullptr, 0, 0, 0, 0);
	}

	m_listAltPro.SetColumnBkColor(GetSysColor(COLOR_BTNFACE), LISTALTPRO_NAME_COL);
	m_listAltPro.EnableColumnEdit(false, LISTALTPRO_NAME_COL);
	ResizeList(&m_listAltPro, ALTPRO_CODE_LINE + 1);
	SetDlgItemText(IDC_BUTTON_REGDUMP_CVMODE, m_cvArray[m_nCurrentCVM].name);
	// Create layout
	m_Resizer.Init(this);
	m_Resizer.AddCtrl(IDC_MD_CPU_REGISTERS, DT_LEFT | DT_TOP, TRUE, TRUE);
	m_Resizer.AddCtrl(IDC_MD_SYS_REGISTERS, DT_LEFT | DT_TOP, TRUE, TRUE);
	m_Resizer.AddCtrl(IDC_MD_ALTPRO_DATA, DT_LEFT | DT_TOP, TRUE, TRUE);
	m_Resizer.AddCtrl(IDC_BUTTON_REGDUMP_CVMODE, DT_LEFT | DT_TOP, TRUE, TRUE);

	m_ToolTip.Activate(TRUE);
	return TRUE; // return TRUE unless you set the focus to a control
	// EXCEPTION: OCX Property Pages should return FALSE
}

void CRegDumpCPUDlg::AttachDebugger(CDebugger *pDbgr)
{
	m_pDebugger = pDbgr;
}


//отменяем действие кнопок enter и esc в диалоге
void CRegDumpCPUDlg::OnOK()
{
}

void CRegDumpCPUDlg::OnCancel()
{
}


void CRegDumpCPUDlg::OnSize(UINT nType, int cx, int cy)
{
	CDialogEx::OnSize(nType, cx, cy);
	// Resize layout to current window size
	m_Resizer.OnSize(cx, cy);
}

CSize CRegDumpCPUDlg::GetMinSize()
{
	CSize size;
	MINMAXINFO mmi;
	m_Resizer.GetMinMaxInfo(&mmi);
	size.cx = mmi.ptMinTrackSize.x;
	size.cy = mmi.ptMinTrackSize.y;
	return size;
}


CString CRegDumpCPUDlg::FormatPSW(WORD value)
{
	//                   012345678
	CString strPSW = _T("--------");
	LPTSTR buf = strPSW.GetBuffer();

	if (value & (1 << PSW_HALT_POS))
	{
		buf[0] = _T('H');
	}

	if (value & (1 << PSW_MASKI_POS))
	{
		buf[1] = _T('M');
	}

	if (value & (1 << PSW_P_POS))
	{
		buf[2] = _T('P');
	}

	if (value & (1 << PSW_T_POS))
	{
		buf[3] = _T('T');
	}

	if (value & (1 << PSW_N_POS))
	{
		buf[4] = _T('N');
	}

	if (value & (1 << PSW_Z_POS))
	{
		buf[5] = _T('Z');
	}

	if (value & (1 << PSW_V_POS))
	{
		buf[6] = _T('V');
	}

	if (value & (1 << PSW_C_POS))
	{
		buf[7] = _T('C');
	}

	return strPSW;
}


WORD CRegDumpCPUDlg::GetPSW(CString &strPSW)
{
	strPSW.MakeUpper();
	strPSW.Trim();
	register int strLength = strPSW.GetLength();
	register WORD psw = 0;

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

			case _T('V'):
				psw |= (1 << PSW_V_POS);
				break;

			case _T('Z'):
				psw |= (1 << PSW_Z_POS);
				break;

			case _T('N'):
				psw |= (1 << PSW_N_POS);
				break;

			case _T('T'):
				psw |= (1 << PSW_T_POS);
				break;

			case _T('P'):
				psw |= (1 << PSW_P_POS);
				break;

			case _T('M'):
				psw |= (1 << PSW_MASKI_POS);
				break;

			case _T('H'):
				psw |= (1 << PSW_HALT_POS);
				break;
		}
	}

	return psw;
}

void CRegDumpCPUDlg::DisplayPortRegs()
{
	if (m_pDebugger)
	{
		for (int i = REG177660_LINE; i <= REG177716OUT_MEM_LINE; ++i)
		{
			m_listSys.SetItemWithModified(m_pDebugger->GetPortValue(m_pListSysRegs[0][i]), i, LISTSYS_VALUE1_COL);
		}

		for (int i = REG177700_LINE; i <= REG177712_LINE; ++i)
		{
			m_listSys.SetItemWithModified(m_pDebugger->GetPortValue(m_pListSysRegs[1][i]), i, LISTSYS_VALUE2_COL);
		}
	}
}

void CRegDumpCPUDlg::DisplayRegisters()
{
	if (m_pDebugger)
	{
		for (int i = R0_LINE; i <= PC_LINE; ++i)
		{
			WORD val = m_pDebugger->GetRegister(i);
			//выводим первую колонку
			m_listCPU.SetItemWithModified(val, i, LISTCPU_VALUE_COL);
			//вторую колонку
			m_listCPU.SetItemWithModifiedASCII(WordToCustom(val), i, LISTCPU_CUSTOM_VALUE_COL);
		}

		m_listCPU.SetItemWithModified(m_pDebugger->GetRegister(PSW_LINE), PSW_LINE, LISTCPU_VALUE_COL);
		SetPSW(m_pDebugger->GetChip()->GetPSW());
	}
}

void CRegDumpCPUDlg::SetPSW(WORD value)
{
	m_listCPU.SetItemWithModifiedASCII(FormatPSW(value), PSW_LINE, LISTCPU_CUSTOM_VALUE_COL);
}

void CRegDumpCPUDlg::DisplayAltProData()
{
	if (m_pDebugger)
	{
		m_listAltPro.SetItemWithModified(m_pDebugger->GetAltProData(ALTPRO_MODE_LINE), ALTPRO_MODE_LINE, LISTALTPRO_VALUE_COL);
		m_listAltPro.SetItemWithModified(m_pDebugger->GetAltProData(ALTPRO_CODE_LINE), ALTPRO_CODE_LINE, LISTALTPRO_VALUE_COL);
	}
}


void CRegDumpCPUDlg::OnLvnItemchangedMdCpuRegisters(NMHDR *pNMHDR, LRESULT *pResult)
{
	auto pNMListView = reinterpret_cast<LPNMLISTVIEW >(pNMHDR);
	ASSERT(pNMListView->iItem <= CCPU::R_PSW);
	*pResult = S_OK;
	register int nSubItem = pNMListView->iSubItem;
	register int addr = pNMListView->iItem;
	register WORD value;

	if (nSubItem == LISTCPU_VALUE_COL)
	{
		register auto str = reinterpret_cast<CString *>(pNMListView->lParam);
		value = OctStringToWord(*str);
	}
	else if (nSubItem == LISTCPU_CUSTOM_VALUE_COL)
	{
		register auto str = reinterpret_cast<CString *>(pNMListView->lParam);
		value = (addr == CCPU::R_PSW) ? GetPSW(*str) : CustomToWord(*str);
	}
	else
	{
		return; //nSubItem может быть и другое значение
	}

	m_listCPU.SetEndEdit(addr, nSubItem);

	if (m_pDebugger)
	{
		m_pDebugger->OnDebugModify_Regs(addr, value);
	}

	if (addr == CCPU::R_PSW)
	{
		m_listCPU.SetItemWithModified(value, PSW_LINE, LISTCPU_VALUE_COL);
		SetPSW(value);
	}
	else
	{
		m_listCPU.SetItemWithModified(value, addr, LISTCPU_VALUE_COL);
		m_listCPU.SetItemWithModifiedASCII(WordToCustom(value), addr, LISTCPU_CUSTOM_VALUE_COL);
	}
}

CString CRegDumpCPUDlg::WordToCustom(WORD 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;
}

WORD CRegDumpCPUDlg::CustomToWord(const CString &str)
{
	WORD res = 0;

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

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

	return res;
}

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

	if (nSubItem == ALTPRO_CODE_LINE)
	{
		register int addr = pNMListView->iItem;
		register auto str = reinterpret_cast<CString *>(pNMListView->lParam);
		register WORD value = OctStringToWord(*str);
		m_listAltPro.SetEndEdit(addr, nSubItem);

		if (m_pDebugger)
		{
			m_pDebugger->OnDebugModify_AltProData(addr, value);
		}

		m_listAltPro.SetItemWithModified(value, addr, nSubItem);
		//Тут надо принудительно обновить содержимое дампера
		::SendMessage(AfxGetMainWnd()->GetSafeHwnd(), WM_MEMDUMP_NEED_UPDATE, 0, 0);
	}

	*pResult = S_OK;
}


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

	switch (nSubItem)
	{
		case LISTSYS_VALUE1_COL:
			ASSERT(nitem <= REG177716OUT_MEM_LINE);
			addr = m_pListSysRegs[0][nitem];
			break;

		case LISTSYS_VALUE2_COL:
			ASSERT(nitem <= REG177712_LINE);
			addr = m_pListSysRegs[1][nitem];
			break;

		default:
			return;
	}

	register auto str = reinterpret_cast<CString *>(pNMListView->lParam);
	register WORD value = OctStringToWord(*str);
	m_listSys.SetEndEdit(nitem, nSubItem);

	if (m_pDebugger)
	{
		m_pDebugger->OnDebugModify_Ports(addr, value);
	}

	m_listSys.SetItemWithModified(value, nitem, nSubItem);
}


//для того, чтобы акселераторы работали, их надо загрузить и в этот диалог
//и передавать главному фрейму.
// способа проще найти не получилось.
BOOL CRegDumpCPUDlg::PreTranslateMessage(MSG *pMsg)
{
	if (m_hAccelTable)
	{
		if (::TranslateAccelerator(AfxGetMainWnd()->GetSafeHwnd(), m_hAccelTable, pMsg))
		{
			return TRUE;
		}
	}

	if (pMsg->message >= WM_MOUSEFIRST && pMsg->message <= WM_MOUSELAST)
	{
		m_ToolTip.RelayEvent(pMsg);
	}
	return CDialogEx::PreTranslateMessage(pMsg);
}


void CRegDumpCPUDlg::OnEnChangeEditDbg1Cpufreq()
{
	UpdateData(TRUE);
	register CMotherBoard *pChip = m_pDebugger->GetChip();
	ASSERT(pChip);

	if (pChip)
	{
		if (m_nCurrCPUFreq < pChip->GetLowBound())
		{
			m_nCurrCPUFreq = pChip->GetLowBound();
		}
		else if (m_nCurrCPUFreq > pChip->GetHighBound())
		{
			m_nCurrCPUFreq = pChip->GetHighBound();
		}

		pChip->SetCPUFreq(m_nCurrCPUFreq);
	}
}

void CRegDumpCPUDlg::OnBnClickedButtonDbg1CpufreqDec()
{
	register CMotherBoard *pChip = m_pDebugger->GetChip();
	ASSERT(pChip);

	if (pChip && pChip->CanSlowDown())
	{
		pChip->SlowdownCPU();
		m_nCurrCPUFreq = pChip->GetCPUFreq();
		UpdateData(FALSE);
	}
}

void CRegDumpCPUDlg::OnBnClickedButtonDbg1CpufreqInc()
{
	register CMotherBoard *pChip = m_pDebugger->GetChip();
	ASSERT(pChip);

	if (pChip && pChip->CanAccelerate())
	{
		pChip->AccelerateCPU();
		m_nCurrCPUFreq = pChip->GetCPUFreq();
		UpdateData(FALSE);
	}
}

void CRegDumpCPUDlg::OnBnClickedButtonDbg1CpufreqBaseset()
{
	register CMotherBoard *pChip = m_pDebugger->GetChip();
	ASSERT(pChip);

	if (pChip)
	{
		pChip->NormalizeCPU();
		m_nCurrCPUFreq = pChip->GetCPUFreq();
		UpdateData(FALSE);
	}
}

//отобразим текущую частоту
void CRegDumpCPUDlg::DisplayFreqParam()
{
	CMotherBoard *pChip = m_pDebugger->GetChip();
	ASSERT(pChip);
	m_nCurrCPUFreq = pChip->GetCPUFreq();
	m_spinCPUFreq.SetRange32(pChip->GetLowBound(), pChip->GetHighBound());
	m_spinCPUFreq.SetPos32(m_nCurrCPUFreq);
	m_spinCPUFreq.SetBuddy(GetDlgItem(IDC_EDIT_DBG1_CPUFREQ));
	UpdateData(FALSE);
}

void CRegDumpCPUDlg::UpdateFreq()
{
	CMotherBoard *pChip = m_pDebugger->GetChip();
	ASSERT(pChip);
	m_nCurrCPUFreq = pChip->GetCPUFreq();
	UpdateData(FALSE);
}


void CRegDumpCPUDlg::OnBnClickedRegdumpCvmode()
{
	if (++m_nCurrentCVM >= NUMBER_CUSTOMVIEWS_REGS)
	{
		m_nCurrentCVM = 0;
	}

	SetDlgItemText(IDC_BUTTON_REGDUMP_CVMODE, m_cvArray[m_nCurrentCVM].name);
	register CMotherBoard *pChip = m_pDebugger->GetChip();
	ASSERT(pChip);

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