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

/*
File: Debugger.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.
*/


// Debugger.cpp: implementation of the CDebugger class.
//


#include "stdafx.h"
#include "Debugger.h"
#include "Defines.h"
#include "Globals.h"
#include "Board.h"
#include "BKErrMsgSys.h"

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

int CDebugger::m_outLevel = 0;

const CString CDebugger::m_strRegNames[8] =
{
	_T(COLORED_TAG)_T("3R0"),
	_T(COLORED_TAG)_T("3R1"),
	_T(COLORED_TAG)_T("3R2"),
	_T(COLORED_TAG)_T("3R3"),
	_T(COLORED_TAG)_T("3R4"),
	_T(COLORED_TAG)_T("3R5"),
	_T(COLORED_TAG)_T("3SP"),
	_T(COLORED_TAG)_T("3PC")
};
// Формат отображения режимов адресации
const CString CDebugger::m_strAddrFormat[8] =
{
	_T("%s"),
	_T(COLORED_TAG)_T("5(%s")_T(COLORED_TAG)_T("5)"),
	_T(COLORED_TAG)_T("5(%s")_T(COLORED_TAG)_T("5)+"),
	_T(COLORED_TAG)_T("5@(%s")_T(COLORED_TAG)_T("5)+"),
	_T(COLORED_TAG)_T("5-(%s")_T(COLORED_TAG)_T("5)"),
	_T(COLORED_TAG)_T("5@-(%s")_T(COLORED_TAG)_T("5)"),
	_T(COLORED_TAG)_T("4%o")_T(COLORED_TAG)_T("5(%s")_T(COLORED_TAG)_T("5)"),
	_T(COLORED_TAG)_T("5@")_T(COLORED_TAG)_T("4%o")_T(COLORED_TAG)_T("5(%s")_T(COLORED_TAG)_T("5)")
};
// Формат отображения режимов адресации, если регистр PC
const CString CDebugger::m_strAddrFormat_PC[8] =
{
	_T(COLORED_TAG)_T("3PC"),
	_T(COLORED_TAG)_T("5(")_T(COLORED_TAG)_T("3PC")_T(COLORED_TAG)_T("5)"),
	_T(COLORED_TAG)_T("5#")_T(COLORED_TAG)_T("4%o"),
	_T(COLORED_TAG)_T("5@#")_T(COLORED_TAG)_T("1%o"),
	_T(COLORED_TAG)_T("5-(")_T(COLORED_TAG)_T("3PC")_T(COLORED_TAG)_T("5)"),
	_T(COLORED_TAG)_T("5@-(")_T(COLORED_TAG)_T("3PC")_T(COLORED_TAG)_T("5)"),
	_T(COLORED_TAG)_T("1%o"),
	_T(COLORED_TAG)_T("5@")_T(COLORED_TAG)_T("1%o")
};
// Формат отображения аргумента - адрес
const CString CDebugger::m_strArgFormat_Addr = _T(COLORED_TAG)_T("1%06o");
// Формат отображения аргумента - число
const CString CDebugger::m_strArgFormat_Number = _T(COLORED_TAG)_T("4%o");
//запятая между аргументом 1 и 2
const CString CDebugger::m_strArgFormat_Comma = _T(COLORED_TAG)_T("5,");
//////////////////////////////////////////////////////////////////////
// Construction/Destruction


CDebugger::CDebugger()
	: m_pChip(nullptr)
	, m_pCtrl(nullptr)
	, m_pInstrRefsMap(nullptr)
	, m_wAddress(g_Config.m_nAdrAsm)
	, m_bPrevCmdC(false)
	, m_wPC(0)
	, m_wInstr(0)
	, m_wNextAddr(0)
{
	m_hBPIcon = ::LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_DBG_BPT));
	m_hCurrIcon = ::LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_DBG_CUR));
	InitMaps();
}

CDebugger::~CDebugger()
{
	g_Config.m_nAdrAsm = m_wAddress;

	if (m_hBPIcon)
	{
		DestroyIcon(m_hBPIcon);
	}

	if (m_hCurrIcon)
	{
		DestroyIcon(m_hCurrIcon);
	}

	SAFE_DELETE_ARRAY(m_pInstrRefsMap);
}

void CDebugger::AttachChip(CMotherBoard *pChip)
{
	m_pChip = pChip;

	if (m_pChip)
	{
		m_pChip->AttachDebugger(this);
	}
}

//поиск в списке точек останова, заданной точки останова
bool CDebugger::IsBpeakpointExists(CBreakPoint &breakpoint)
{
	if (m_breakpointList.GetCount())
	{
		POSITION pos = m_breakpointList.GetHeadPosition();

		while (pos)
		{
			CBreakPoint &curr = m_breakpointList.GetNext(pos);

			if ((curr.GetType() == breakpoint.GetType())
			        && (curr.GetAddress() == breakpoint.GetAddress()))
			{
				return true;
			}
		}
	}

	return false;
}


//поиск в списке точек останова, точки с заданным адресом
bool CDebugger::GetDebugPCBreak(WORD addr)
{
	//оставим это излишество на случай, если решим алгортимы поменять
	return IsBpeakpointAtAddress(addr);
}

//поиск в списке точек останова, точки с заданным адресом
bool CDebugger::IsBpeakpointAtAddress(WORD addr)
{
	if (m_breakpointList.GetCount())
	{
		POSITION pos = m_breakpointList.GetHeadPosition();

		while (pos)
		{
			CBreakPoint &curr = m_breakpointList.GetNext(pos);

			if (curr.IsAddress() && curr.GetAddress() == addr)
			{
				return true;
			}
		}
	}

	return false;
}


bool CDebugger::SetSimpleBreakpoint(WORD addr)
{
	CBreakPoint breakpoint(addr);

	if (IsBpeakpointExists(breakpoint))
	{
		return false;
	}

	m_breakpointList.AddTail(breakpoint);
	return true;
}


bool CDebugger::SetSimpleBreakpoint()
{
	return SetSimpleBreakpoint(GetCursorAddress());
}


bool CDebugger::RemoveBreakpoint(WORD addr)
{
	POSITION pos = m_breakpointList.GetHeadPosition();

	while (pos)
	{
		POSITION oldPos = pos;
		CBreakPoint &curr = m_breakpointList.GetNext(pos);

		if (curr.IsAddress() && curr.GetAddress() == addr)
		{
			m_breakpointList.RemoveAt(oldPos);
			return true;
		}
	}

	return false;
}


bool CDebugger::RemoveBreakpoint()
{
	return RemoveBreakpoint(GetCursorAddress());
}


void CDebugger::ClearBreakpointList()
{
	m_breakpointList.RemoveAll();
}

void CDebugger::DrawDebuggerLine(int nNum, CDC *pDC, CRect *pRcSubs)
{
	if (!m_pChip) // Нет чипа - нечего рисовать
	{
		return;
	}

	// Дизассемблируем машинный код
	WORD instrOpcode[3];
	CString strInstruction;
	CString strArgument;
	register WORD wLineAddr = GetLineAddress(nNum);
	register int len = DebugInstruction(wLineAddr, strInstruction, strArgument, instrOpcode);
	// Выводим маркер
	DrawMarker(wLineAddr, pDC, pRcSubs[MARK_COLUMN]);
	// Выводим адрес
	pDC->SetTextColor(g_crDebugColorHighLighting[HLCOLOR_ADDRESS]);
	pDC->DrawText(WordToOctString(wLineAddr), &pRcSubs[ADDR_COLUMN], DT_LEFT | DT_VCENTER | DT_END_ELLIPSIS);
	// Выводим мнемонику
	pDC->SetTextColor(g_crDebugColorHighLighting[HLCOLOR_MNEMONIC]);
	pDC->DrawText(strInstruction, &pRcSubs[INSTR_COLUMN], DT_LEFT | DT_VCENTER | DT_END_ELLIPSIS);
	// Выводим аргументы мнемоники
	DrawColoredText(pDC, pRcSubs[ARG_COLUMN], strArgument);
	// Выводим комментарий. Это у нас просто машинные инструкции ассемблерной команды
	CString strCode = WordToOctString(instrOpcode[0]); //код инструкции у нас по любому всегда есть

	//а дальше от 0 до 2-х слов аргументов
	for (int i = 1; i < len; ++i)
	{
		strCode += _T(' ') + WordToOctString(instrOpcode[i]);
	}

	pDC->SetTextColor(g_crDebugColorHighLighting[HLCOLOR_DEFAULT]);
	pDC->DrawText(strCode, &pRcSubs[COM_COLUMN], DT_LEFT | DT_VCENTER | DT_END_ELLIPSIS);
}

void CDebugger::DrawColoredText(CDC *pDC, CRect &rect, CString &str)
{
	CRect pos = rect;
	bool bEnd = false;
	register int beginpos = str.Find(_T(COLORED_TAG), 0); //находим позицию тега
	TCHAR clrbuf[2] = {0, 0};

	if (beginpos < 0 || str.IsEmpty())
	{
		//не надо ничего рисовать
		//pDC->DrawText(str, &pos, DT_LEFT | DT_VCENTER);
	}
	else
	{
		while (!bEnd)
		{
			register int clpos = beginpos + COLORED_TAG_LENGTH;
			clrbuf[0] = str.GetAt(clpos); //номер цвета
			register int colornum = _ttoi(clrbuf);
			register int endpos = str.Find(_T(COLORED_TAG), clpos++); //находим позицию следующего тега, всё что между ними - рисовать заданным цветом

			if (endpos == -1) //если не нашли, то конец строки
			{
				endpos = str.GetLength();
				bEnd = true;
			}

			pDC->SetTextColor(g_crDebugColorHighLighting[colornum]);
			CString substr = str.Mid(clpos, endpos - clpos);
			CSize size = pDC->GetTextExtent(substr); //текущая позиция вывода текста
			pDC->DrawText(substr, &pos, DT_LEFT | DT_VCENTER);
			pos.left += size.cx;

			if (pos.left >= rect.right)
			{
				bEnd = true;
			}

			beginpos = endpos;
		}
	}
}


void CDebugger::DrawMarker(WORD address, CDC *pDC, CRect &rc)
{
	if (IsBpeakpointAtAddress(address))
	{
		::DrawIconEx(pDC->m_hDC, rc.left, rc.top, m_hBPIcon, 16, 16, 0, nullptr, DI_NORMAL);
	}

	if (address == m_pChip->GetRON(CCPU::R_PC))
	{
		::DrawIconEx(pDC->m_hDC, rc.left, rc.top, m_hCurrIcon, 16, 16, 0, nullptr, DI_NORMAL);
	}
}


void CDebugger::StepForward()
{
	m_wAddress += CalcInstructionLength(m_pChip->GetWordIndirect(m_wAddress));
}


void CDebugger::StepBackward()
{
	m_wAddress -= sizeof(WORD);
}


bool CDebugger::IsInstructionOut(WORD instruction)
{
	// No fields
	switch (instruction)
	{
		case PI_BPT:
		case PI_IOT:
			m_outLevel++;
			return false;
	}

	// Branchs & interrupts
	switch (instruction & ~0377)
	{
		case PI_EMT:
		case PI_TRAP:
			m_outLevel++;
			return false;
	}

	// Three fields
	switch (instruction & ~0777)
	{
		case PI_JSR:
			m_outLevel++;
			return false;
	}

	if (
	    // No fields
	    (instruction == PI_RTI || instruction == PI_RTT) ||
	    // One field
	    ((instruction & ~7) == PI_RTS)
	)
	{
		if (--m_outLevel == -1)
		{
			return true;
		}
	}

	return false;
}


bool CDebugger::IsInstructionOver(WORD instruction)
{
	// No fields
	switch (instruction)
	{
		case PI_BPT:
		case PI_IOT:
			return true;
	}

	// Branchs & interrupts
	switch (instruction & ~0377)
	{
		case PI_EMT:
		case PI_TRAP:
			return true;
	}

	// Three fields
	switch (instruction & ~0777)
	{
		case PI_JSR:
		case PI_SOB:
			return true;
	}

	return false;
}


WORD CDebugger::GetCursorAddress()
{
	ASSERT(m_pCtrl);
	int nLine = m_pCtrl->GetSelectionMark();
	return GetLineAddress(nLine);
}


WORD CDebugger::GetBottomAddress()
{
	ASSERT(m_pCtrl);
	int nLast = m_pCtrl->GetItemCount();
	return GetLineAddress(nLast);
}


WORD CDebugger::GetPSW()
{
	ASSERT(m_pChip);

	if (m_pChip)
	{
		return m_pChip->GetRON(CCPU::R_PSW);
	}

	return 0;
}

WORD CDebugger::GetRegister(int reg)
{
	ASSERT(m_pChip);

	if (m_pChip)
	{
		return m_pChip->GetRON(reg);
	}

	return 0;
}

//////////////////////////////////////////////////////////////////////
//используется для получения значений портов и только
WORD CDebugger::GetPortValue(int addr)
{
	ASSERT(m_pChip);

	if (m_pChip)
	{
		switch (addr)
		{
			case SYS_PORT_177660:
				return m_pChip->m_reg177660;

			case SYS_PORT_177662_IN:
				return m_pChip->m_reg177662in;

			case SYS_PORT_177662_OUT:
				return m_pChip->m_reg177662out;

			case SYS_PORT_177664:
				return m_pChip->m_reg177664;

			case SYS_PORT_177700:
				return m_pChip->GetWordIndirect(0177700);

			case SYS_PORT_177702:
				return m_pChip->GetWordIndirect(0177702);

			case SYS_PORT_177704:
				return m_pChip->GetWordIndirect(0177704);

			case SYS_PORT_177706:
				return m_pChip->GetWordIndirect(0177706);

			case SYS_PORT_177710:
				return m_pChip->GetWordIndirect(0177710);

			case SYS_PORT_177712:
				return m_pChip->GetWordIndirect(0177712);

			case SYS_PORT_177714_IN:
				return m_pChip->m_reg177714in;

			case SYS_PORT_177714_OUT:
				return m_pChip->m_reg177714out;

			case SYS_PORT_177716_IN:
				return m_pChip->m_reg177716in;

			case SYS_PORT_177716_OUT_TAP:
				return m_pChip->m_reg177716out_tap;

			case SYS_PORT_177716_OUT_MEM:
				return m_pChip->m_reg177716out_mem;
		}

		ASSERT(FALSE);
	}

	return 0;
}
//получение состояния режимов контроллера АльтПро
WORD CDebugger::GetAltProData(int reg)
{
	ASSERT(m_pChip);

	if (m_pChip)
	{
		switch (reg)
		{
			case 0:
				return m_pChip->GetAltProMode();

			case 1:
				return m_pChip->GetAltProCode();
		}

		ASSERT(FALSE);
	}

	return 0;
}
//получение состояния режимов контроллера FDD
WORD CDebugger::GetFDDData(int reg)
{
	ASSERT(m_pChip);

	if (m_pChip)
	{
		switch (reg)
		{
			case 0:
				return m_pChip->GetFDD()->GetStateDebug();

			case 1:
				return m_pChip->GetFDD()->GetCmdDebug();

			case 2:
				return m_pChip->GetFDD()->GetDataDebug();

			case 3:
				return m_pChip->GetFDD()->GetWriteDataDebug();
		}

		ASSERT(FALSE);
	}

	return 0;
}
WORD CDebugger::GetDebugHDDRegs(int nDrive, int num, bool bReadMode)
{
	ASSERT(m_pChip);

	if (m_pChip)
	{
		return m_pChip->GetFDD()->ReadDebugHDDRegisters(nDrive, static_cast<HDD_REGISTERS>(num), bReadMode);
	}

	return 0;
}

WORD CDebugger::GetDebugMemDumpWord(WORD addr)
{
	if (m_pChip)
	{
		return m_pChip->GetWordIndirect(addr & 0177776);
	}

	return 0;
}
BYTE CDebugger::GetDebugMemDumpByte(WORD addr)
{
	if (m_pChip)
	{
		return m_pChip->GetByteIndirect(addr);
	}

	return 0;
}


WORD CDebugger::GetLineAddress(int nNum)
{
	if (nNum < 0)
	{
		return 0;
	}

	WORD wCurAddr = m_wAddress;

	while (nNum--)
	{
		wCurAddr += CalcInstructionLength(m_pChip->GetWordIndirect(wCurAddr));
	}

	return wCurAddr;
}


int CDebugger::CalcInstructionLength(WORD instr)
{
	m_wInstr = instr; //фиксируем опкод инструкции, длину которой подсчитываем
	CalcInstrLenRef &methodref = m_pInstrRefsMap[instr].InstrLenRef; //считаем
	return (this->*methodref)();
}

int CDebugger::CalcLenOneWord()
{
	return 2;
}

int CDebugger::CalcLenTwoFields()
{
	return 2 + CalcArgLength(DST);
}

int CDebugger::CalcLenFourFields()
{
	return 2 + CalcArgLength(DST) + CalcArgLength(SRC);
}


int CDebugger::CalcArgLength(int pos)
{
	register int reg = GetDigit(m_wInstr, pos++);
	register int meth = GetDigit(m_wInstr, pos);
	register int arg = 0;

	switch (meth)
	{
		/*
		case 0: // R0,      PC
		case 1: // (R0),    (PC)
		case 4: // -(R0),   -(PC)
		case 5: // @-(R0),  @-(PC)
		    break;
		*/
		case 2: // (R0)+,   #012345
		case 3: // @(R0)+,  @#012345
			if (reg == CCPU::R_PC)
			{
				arg = 2;
			}

			break;

		case 6: // 345(R0), 345
		case 7: // @345(R0),@345
			arg = 2;
			break;
	}

	return arg;
}


int CDebugger::DebugInstruction(WORD pc, CString &strInstr, CString &strArg, WORD *codes)
{
	ASSERT(m_pChip);
	int length = 1;

	if (m_pChip)
	{
		m_bPrevCmdCp = m_bPrevCmdC;
		m_bPrevCmdC = false;
		m_wPC = pc;
		m_wInstr = m_pChip->GetWordIndirect(pc);
		codes[0] = m_wInstr;
		m_strArg = _T("");
		m_strInstr = m_pInstrRefsMap[m_wInstr].Mnemonic;
		DisassembleInstrRef methodref = m_pInstrRefsMap[m_wInstr].DisasmInstrRef;
		length += (this->*methodref)(codes); //эта функция ещё формирует m_strInstr и m_strArg
		strInstr = m_strInstr;
		strArg = m_strArg;
	}

	return length;
}

int CDebugger::DisassembleNoArgs(WORD *codes)
{
	return 0;
}

int CDebugger::DisassembleUnknown(WORD *codes)
{
	m_strArg.Format(m_strArgFormat_Addr, m_wInstr);
	return 0;
}

int CDebugger::DisassembleCLS(WORD *codes)
{
	if (m_wInstr == PI_CCC)
	{
		m_strInstr = _T("CCC");
	}
	else if (m_wInstr & 0xf) //если признаки есть
	{
		m_strInstr = _T("CL");

		if (m_wInstr & PSW_N)
		{
			m_strInstr += _T('N');
		}

		if (m_wInstr & PSW_Z)
		{
			m_strInstr += _T('Z');
		}

		if (m_wInstr & PSW_V)
		{
			m_strInstr += _T('V');
		}

		if (m_wInstr & PSW_C)
		{
			m_strInstr += _T('C');
		}
	}

	return 0;
}

int CDebugger::DisassembleSET(WORD *codes)
{
	if (m_wInstr == PI_SCC)
	{
		m_strInstr = _T("SCC");
	}
	else if (m_wInstr & 0xf) //если признаки есть
	{
		m_strInstr = _T("SE");

		if (m_wInstr & PSW_N)
		{
			m_strInstr += _T('N');
		}

		if (m_wInstr & PSW_Z)
		{
			m_strInstr += _T('Z');
		}

		if (m_wInstr & PSW_V)
		{
			m_strInstr += _T('V');
		}

		if (m_wInstr & PSW_C)
		{
			m_strInstr += _T('C');
		}
	}

	return 0;
}

int CDebugger::DisassembleRTS(WORD *codes)
{
	int r = GetDigit(m_wInstr, 0);

	if (r == CCPU::R_PC)
	{
		m_strInstr = _T("RETURN");
	}
	else
	{
		m_strArg = m_strRegNames[r];
	}

	return 0;
}

int CDebugger::DisassembleOneField(WORD *codes)
{
	m_strArg = m_strRegNames[GetDigit(m_wInstr, 0)];
	return 0;
}

int CDebugger::DisassembleTwoField(WORD *codes)
{
	return ConvertArgToString(DST, m_wPC + 2, m_strArg, codes[1]);
}

int CDebugger::DisassembleMARK(WORD *codes)
{
	m_strArg.Format(m_strArgFormat_Number, m_wInstr & 077);
	return 0;
}

int CDebugger::DisassembleEMT(WORD *codes)
{
	m_strArg.Format(m_strArgFormat_Number, LOBYTE(m_wInstr));
	return 0;
}

int CDebugger::DisassembleBR(WORD *codes)
{
	m_strArg.Format(m_strArgFormat_Addr, m_wPC + ((short)(char)LOBYTE(m_wInstr) * 2) + 2);
	return 0;
}

int CDebugger::DisassembleBCC(WORD *codes)
{
	if (m_bPrevCmdCp)
	{
		m_strInstr = _T("BHIS");
	}

	return DisassembleBR(codes);
}

int CDebugger::DisassembleBCS(WORD *codes)
{
	if (m_bPrevCmdCp)
	{
		m_strInstr = _T("BLO");
	}

	return DisassembleBR(codes);
}

int CDebugger::DisassembleJSR(WORD *codes)
{
	int r = GetDigit(m_wInstr, 2);
	CString strDst;
	int length = ConvertArgToString(DST, m_wPC + 2, strDst, codes[1]);

	if (r == CCPU::R_PC)
	{
		m_strInstr = _T("CALL");
		m_strArg = strDst;
	}
	else
	{
		m_strArg = m_strRegNames[r] + m_strArgFormat_Comma + strDst;
	}

	return length;
}

int CDebugger::DisassembleMUL(WORD *codes)
{
	CString strDst;
	int length = ConvertArgToString(DST, m_wPC + 2, strDst, codes[1]);
	m_strArg = strDst + m_strArgFormat_Comma + m_strRegNames[GetDigit(m_wInstr, 2)];
	return length;
}

int CDebugger::DisassembleXOR(WORD *codes)
{
	CString strDst;
	int length = ConvertArgToString(DST, m_wPC + 2, strDst, codes[1]);
	m_strArg = m_strRegNames[GetDigit(m_wInstr, 2)] + m_strArgFormat_Comma + strDst;
	return length;
}

int CDebugger::DisassembleSOB(WORD *codes)
{
	CString strDst;
	strDst.Format(m_strArgFormat_Addr, m_wPC - (m_wInstr & 077) * 2 + 2);
	m_strArg = m_strRegNames[GetDigit(m_wInstr, 2)] + m_strArgFormat_Comma + strDst;
	return 0;
}

int CDebugger::DisassembleFourField(WORD *codes)
{
	CString strSrc;
	CString strDst;
	int length = ConvertArgToString(SRC, m_wPC + 2, strSrc, codes[1]);
	length += ConvertArgToString(DST, m_wPC + 2 + length * 2, strDst, codes[length + 1]);
	m_strArg = strSrc + m_strArgFormat_Comma + strDst;
	return length;
}

int CDebugger::DisassembleCMP(WORD *codes)
{
	m_bPrevCmdC = true;
	return DisassembleFourField(codes);
}

int CDebugger::ConvertArgToString(int arg, WORD pc, CString &strSrc, WORD &code)
{
	ASSERT(m_pChip);
	register int reg = GetDigit(m_wInstr, arg++);
	register int param = GetDigit(m_wInstr, arg);

	if (CCPU::R_R0 <= reg && reg <= CCPU::R_SP)
	{
		if (param >= 6)
		{
			register WORD word = m_pChip->GetWordIndirect(pc);
			strSrc.Format(m_strAddrFormat[param], word, m_strRegNames[reg]);
			code = word;
			return 1;
		}
		else
		{
			strSrc.Format(m_strAddrFormat[param], m_strRegNames[reg]);
		}
	}
	else
	{
		if (param == 2 || param == 3)
		{
			register WORD word = m_pChip->GetWordIndirect(pc);
			strSrc.Format(m_strAddrFormat_PC[param], word);
			code = word;
			return 1;
		}
		else if (param >= 6)
		{
			register WORD word = m_pChip->GetWordIndirect(pc);
			strSrc.Format(m_strAddrFormat_PC[param], (WORD)(pc + word + 2));
			code = word;
			return 1;
		}
		else
		{
			strSrc = m_strAddrFormat_PC[param];
		}
	}

	return 0;
}

/*
расчёт следующего адреса, который будет после выполнения текущей инструкции.
вход: pc - текущий адрес.
выход:
    true - если адрес можно рассчитать
    addr - расчётный адрес.
    false - если адрес не получается рассчитать
    addr = адрес следующий за инструкцией
*/
bool CDebugger::CalcNextAddr(WORD pc, WORD &addr)
{
	m_wPC = pc;
	m_wInstr = m_pChip->GetWordIndirect(pc);
	m_wNextAddr = m_wPC + CalcInstructionLength(m_wInstr);
	CalcNextAddrRef &methodref = m_pInstrRefsMap[m_wInstr].NextAddrRef;
	bool bRet = (this->*methodref)();
	addr = m_wNextAddr;
	return bRet;
}

bool CDebugger::CalcNextAddrRegular()
{
	//тут перехватываем и обрабатываем ситуации типа MOV xxx,PC
	register WORD opcode = m_wInstr & 0170077;

	switch (opcode)
	{
		case 010007:
			m_wNextAddr = GetArg(0);
			break;

		case 060007:
			m_wNextAddr = m_wPC + 2 + GetArg(0);
			break;

		case 0160007:
			m_wNextAddr = m_wPC + 2 - GetArg(0);
			break;
	}

	return true;
}

bool CDebugger::CalcNextAddrUNKNOWN()
{
	return false;
}

bool CDebugger::CalcNextAddrRTI()
{
	m_wNextAddr = m_pChip->GetWordIndirect(GetRegister(CCPU::R_SP));
	return true;
}

bool CDebugger::CalcNextAddrRTS()
{
	register int reg = GetDigit(m_wInstr, 0);

	if (reg == 7)
	{
		m_wNextAddr = m_pChip->GetWordIndirect(GetRegister(CCPU::R_SP));
	}
	else
	{
		m_wNextAddr = GetRegister(reg);
	}

	return true;
}

bool CDebugger::CalcNextAddrJMP()
{
	register int meth = GetDigit(m_wInstr, 1);

	if (meth == 0)
	{
		return false;
	}
	else
	{
		m_wNextAddr = GetArgAddr(meth, GetDigit(m_wInstr, 0));
	}

	return true;
}

//вход: type = 0 - источник, 1 - приёмник
// нужно, чтобы высчитать адрес перехода для команд типа mov xxx,PC
// необходимо учесть, что когда сюда попадаем у нас PC на 2 меньше чем надо.
int CDebugger::GetArg(int type)
{
	register int reg = GetDigit(m_wInstr, (type == 0) ? 2 : 0);
	register WORD offs = (reg == CCPU::R_PC) ? 2 : 0;
	register WORD r = GetRegister(reg); //содержимое регистра
	register int meth = GetDigit(m_wInstr, (type == 0) ? 3 : 1);
	register int arg = 0;
	register WORD index;

	switch (meth)
	{
		case 0: // R0,      PC
			arg = r;
			break;

		case 1: // (R0),    (PC)
		case 2: // (R0)+,   #012345
			arg = m_pChip->GetWordIndirect(r + offs);
			break;

		case 3: // @(R0)+,  @#012345
			arg = m_pChip->GetWordIndirect(r + offs);
			arg = m_pChip->GetWordIndirect(arg);
			break;

		case 4: // -(R0),   -(PC)
			arg = m_pChip->GetWordIndirect(r + offs - 2);
			break;

		case 5: // @-(R0),  @-(PC)
			arg = m_pChip->GetWordIndirect(r + offs - 2);
			arg = m_pChip->GetWordIndirect(arg);
			break;

		case 6: // 345(R0), 345
			index = m_pChip->GetWordIndirect(GetRegister(CCPU::R_PC) + 2);
			arg = m_pChip->GetWordIndirect((WORD)(index + r + offs + offs));
			break;

		case 7: // @345(R0),@345
			index = m_pChip->GetWordIndirect(GetRegister(CCPU::R_PC) + 2);
			arg = m_pChip->GetWordIndirect((WORD)(index + r + offs + offs)); //offs удвоенное, т.к. после чтения индекса PC ещё увеличивается на 2
			arg = m_pChip->GetWordIndirect(arg);
			break;
	}

	return arg;
}


//нужно, чтобы высчитать адрес перехода для JMP и JSR
// необходимо учесть, что когда сюда попадаем у нас PC на 2 меньше чем надо.
int CDebugger::GetArgAddr(int meth, int reg)
{
	register WORD offs = (reg == CCPU::R_PC) ? 2 : 0;
	register WORD r = GetRegister(reg);
	register int arg = 0;
	register WORD index;

	switch (meth)
	{
		case 0: // R0,      PC
			arg = reg;
			break;

		case 1: // (R0),    (PC)
		case 2: // (R0)+,   #012345
			arg = r + offs;
			break;

		case 3: // @(R0)+,  @#012345
			arg = m_pChip->GetWordIndirect(r + offs);
			break;

		case 4: // -(R0),   -(PC)
			arg = r + offs - 2;
			break;

		case 5: // @-(R0),  @-(PC)
			arg = m_pChip->GetWordIndirect(r + offs - 2);
			break;

		case 6: // 345(R0), 345
			index = m_pChip->GetWordIndirect(GetRegister(CCPU::R_PC) + 2);
			arg = index + r + offs + offs;
			break;

		case 7: // @345(R0),@345
			index = m_pChip->GetWordIndirect(GetRegister(CCPU::R_PC) + 2);
			arg = m_pChip->GetWordIndirect((WORD)(index + r + offs + offs)); //offs удвоенное, т.к. после чтения индекса PC ещё увеличивается на 2
			break;
	}

	return arg;
}

bool CDebugger::CalcNextAddrMARK()
{
	m_wNextAddr = GetRegister(CCPU::R_R5);
	return true;
}

bool CDebugger::CalcNextAddrSOB()
{
	register int reg = GetDigit(m_wInstr, 2);
	m_wNextAddr -= ((GetRegister(reg) - 1) ? (m_wInstr & (WORD)077) * 2 : 0);
	return true;
}

bool CDebugger::CalcNextAddrBR()
{
	register short br = ((short)(char)LOBYTE(m_wInstr)) * 2;
	m_wNextAddr += br;
	return true;
}

bool CDebugger::CalcNextAddrBNE()
{
	register short br = ((short)(char)LOBYTE(m_wInstr)) * 2;
	m_wNextAddr += ((GetPSW() & PSW_Z) ? 0 : br);
	return true;
}

bool CDebugger::CalcNextAddrBEQ()
{
	register short br = ((short)(char)LOBYTE(m_wInstr)) * 2;
	m_wNextAddr += ((GetPSW() & PSW_Z) ? br : 0);
	return true;
}

bool CDebugger::CalcNextAddrBGE()
{
	register WORD psw = GetPSW();
	register bool bn = (psw & PSW_N) != 0;
	register bool bv = (psw & PSW_V) != 0;
	register short br = ((short)(char)LOBYTE(m_wInstr)) * 2;
	m_wNextAddr += ((bn == bv) ? br : 0);
	return true;
}

bool CDebugger::CalcNextAddrBLT()
{
	register WORD psw = GetPSW();
	register bool bn = (psw & PSW_N) != 0;
	register bool bv = (psw & PSW_V) != 0;
	register short br = ((short)(char)LOBYTE(m_wInstr)) * 2;
	m_wNextAddr += ((bn != bv) ? br : 0);
	return true;
}

bool CDebugger::CalcNextAddrBGT()
{
	register WORD psw = GetPSW();
	register bool bn = (psw & PSW_N) != 0;
	register bool bz = (psw & PSW_Z) != 0;
	register bool bv = (psw & PSW_V) != 0;
	register short br = ((short)(char)LOBYTE(m_wInstr)) * 2;
	m_wNextAddr += (((bn != bv) || bz) ? 0 : br);
	return true;
}

bool CDebugger::CalcNextAddrBLE()
{
	register WORD psw = GetPSW();
	register bool bn = (psw & PSW_N) != 0;
	register bool bz = (psw & PSW_Z) != 0;
	register bool bv = (psw & PSW_V) != 0;
	register short br = ((short)(char)LOBYTE(m_wInstr)) * 2;
	m_wNextAddr += (((bn != bv) || bz) ? br : 0);
	return true;
}

bool CDebugger::CalcNextAddrBPL()
{
	register short br = ((short)(char)LOBYTE(m_wInstr)) * 2;
	m_wNextAddr += ((GetPSW() & PSW_N) ? 0 : br);
	return true;
}

bool CDebugger::CalcNextAddrBMI()
{
	register short br = ((short)(char)LOBYTE(m_wInstr)) * 2;
	m_wNextAddr += ((GetPSW() & PSW_N) ? br : 0);
	return true;
}

bool CDebugger::CalcNextAddrBHI()
{
	register WORD psw = GetPSW();
	register bool bz = (psw & PSW_Z) != 0;
	register bool bc = (psw & PSW_C) != 0;
	register short br = ((short)(char)LOBYTE(m_wInstr)) * 2;
	m_wNextAddr += ((bz || bc) ? 0 : br);
	return true;
}

bool CDebugger::CalcNextAddrBLOS()
{
	register WORD psw = GetPSW();
	register bool bz = (psw & PSW_Z) != 0;
	register bool bc = (psw & PSW_C) != 0;
	register short br = ((short)(char)LOBYTE(m_wInstr)) * 2;
	m_wNextAddr += ((bz || bc) ? br : 0);
	return true;
}

bool CDebugger::CalcNextAddrBVC()
{
	register short br = ((short)(char)LOBYTE(m_wInstr)) * 2;
	m_wNextAddr += ((GetPSW() & PSW_V) ? 0 : br);
	return true;
}

bool CDebugger::CalcNextAddrBVS()
{
	register short br = ((short)(char)LOBYTE(m_wInstr)) * 2;
	m_wNextAddr += ((GetPSW() & PSW_V) ? br : 0);
	return true;
}

bool CDebugger::CalcNextAddrBCC()
{
	register short br = ((short)(char)LOBYTE(m_wInstr)) * 2;
	m_wNextAddr += ((GetPSW() & PSW_C) ? 0 : br);
	return true;
}

bool CDebugger::CalcNextAddrBCS()
{
	register short br = ((short)(char)LOBYTE(m_wInstr)) * 2;
	m_wNextAddr += ((GetPSW() & PSW_C) ? br : 0);
	return true;
}

void CDebugger::RegisterMethodRef(WORD start, WORD end, CString &mnemonic, CalcInstrLenRef ilenmref, CalcNextAddrRef nxamref, DisassembleInstrRef dsimref)
{
	for (int opcode = start; opcode <= end; ++opcode)
	{
		m_pInstrRefsMap[opcode].Mnemonic = mnemonic;
		m_pInstrRefsMap[opcode].InstrLenRef = ilenmref;
		m_pInstrRefsMap[opcode].NextAddrRef = nxamref;
		m_pInstrRefsMap[opcode].DisasmInstrRef = dsimref;
	}
}

void CDebugger::InitMaps()
{
	if (m_pInstrRefsMap)
	{
		return;
	}

	m_pInstrRefsMap = new CDebugger::InstrFuncRefs[65536];

	if (m_pInstrRefsMap)
	{
		RegisterMethodRef(0000000, 0177777, CString(_T("WORD")),   &CDebugger::CalcLenOneWord,    &CDebugger::CalcNextAddrUNKNOWN, &CDebugger::DisassembleUnknown);   //WORD
		RegisterMethodRef(0000000, 0000000, CString(_T("HALT")),   &CDebugger::CalcLenOneWord,    &CDebugger::CalcNextAddrUNKNOWN, &CDebugger::DisassembleNoArgs);    //HALT
		RegisterMethodRef(0000001, 0000001, CString(_T("WAIT")),   &CDebugger::CalcLenOneWord,    &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleNoArgs);    //WAIT
		RegisterMethodRef(0000002, 0000002, CString(_T("RTI")),    &CDebugger::CalcLenOneWord,    &CDebugger::CalcNextAddrRTI,     &CDebugger::DisassembleNoArgs);    //RTI
		RegisterMethodRef(0000003, 0000003, CString(_T("BPT")),    &CDebugger::CalcLenOneWord,    &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleNoArgs);    //BPT
		RegisterMethodRef(0000004, 0000004, CString(_T("IOT")),    &CDebugger::CalcLenOneWord,    &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleNoArgs);    //IOT
		RegisterMethodRef(0000005, 0000005, CString(_T("RESET")),  &CDebugger::CalcLenOneWord,    &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleNoArgs);    //RESET
		RegisterMethodRef(0000006, 0000006, CString(_T("RTT")),    &CDebugger::CalcLenOneWord,    &CDebugger::CalcNextAddrRTI,     &CDebugger::DisassembleNoArgs);    //RTT
		RegisterMethodRef(0000010, 0000013, CString(_T("START")),  &CDebugger::CalcLenOneWord,    &CDebugger::CalcNextAddrUNKNOWN, &CDebugger::DisassembleNoArgs);    //START
		RegisterMethodRef(0000014, 0000017, CString(_T("STEP")),   &CDebugger::CalcLenOneWord,    &CDebugger::CalcNextAddrUNKNOWN, &CDebugger::DisassembleNoArgs);    //STEP
		RegisterMethodRef(0000100, 0000177, CString(_T("JMP")),    &CDebugger::CalcLenTwoFields,  &CDebugger::CalcNextAddrJMP,     &CDebugger::DisassembleTwoField);  //JMP
		RegisterMethodRef(0000200, 0000207, CString(_T("RTS")),    &CDebugger::CalcLenOneWord,    &CDebugger::CalcNextAddrRTS,     &CDebugger::DisassembleRTS);       // RTS / RETURN
		RegisterMethodRef(0000240, 0000257, CString(_T("NOP")),    &CDebugger::CalcLenOneWord,    &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleCLS);       //CLS
		RegisterMethodRef(0000260, 0000277, CString(_T("NOP260")), &CDebugger::CalcLenOneWord,    &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleSET);       //SET
		RegisterMethodRef(0000300, 0000377, CString(_T("SWAB")),   &CDebugger::CalcLenTwoFields,  &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleTwoField);  //SWAB
		RegisterMethodRef(0000400, 0000777, CString(_T("BR")),     &CDebugger::CalcLenOneWord,    &CDebugger::CalcNextAddrBR,      &CDebugger::DisassembleBR);        //BR
		RegisterMethodRef(0001000, 0001377, CString(_T("BNE")),    &CDebugger::CalcLenOneWord,    &CDebugger::CalcNextAddrBNE,     &CDebugger::DisassembleBR);        //BNE
		RegisterMethodRef(0001400, 0001777, CString(_T("BEQ")),    &CDebugger::CalcLenOneWord,    &CDebugger::CalcNextAddrBEQ,     &CDebugger::DisassembleBR);        //BEQ
		RegisterMethodRef(0002000, 0002377, CString(_T("BGE")),    &CDebugger::CalcLenOneWord,    &CDebugger::CalcNextAddrBGE,     &CDebugger::DisassembleBR);        //BGE
		RegisterMethodRef(0002400, 0002777, CString(_T("BLT")),    &CDebugger::CalcLenOneWord,    &CDebugger::CalcNextAddrBLT,     &CDebugger::DisassembleBR);        //BLT
		RegisterMethodRef(0003000, 0003377, CString(_T("BGT")),    &CDebugger::CalcLenOneWord,    &CDebugger::CalcNextAddrBGT,     &CDebugger::DisassembleBR);        //BGT
		RegisterMethodRef(0003400, 0003777, CString(_T("BLE")),    &CDebugger::CalcLenOneWord,    &CDebugger::CalcNextAddrBLE,     &CDebugger::DisassembleBR);        //BLE
		RegisterMethodRef(0004000, 0004777, CString(_T("JSR")),    &CDebugger::CalcLenTwoFields,  &CDebugger::CalcNextAddrJMP,     &CDebugger::DisassembleJSR);       // JSR / CALL
		RegisterMethodRef(0005000, 0005077, CString(_T("CLR")),    &CDebugger::CalcLenTwoFields,  &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleTwoField);  //CLR
		RegisterMethodRef(0005100, 0005177, CString(_T("COM")),    &CDebugger::CalcLenTwoFields,  &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleTwoField);  //COM
		RegisterMethodRef(0005200, 0005277, CString(_T("INC")),    &CDebugger::CalcLenTwoFields,  &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleTwoField);  //INC
		RegisterMethodRef(0005300, 0005377, CString(_T("DEC")),    &CDebugger::CalcLenTwoFields,  &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleTwoField);  //DEC
		RegisterMethodRef(0005400, 0005477, CString(_T("NEG")),    &CDebugger::CalcLenTwoFields,  &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleTwoField);  //NEG
		RegisterMethodRef(0005500, 0005577, CString(_T("ADC")),    &CDebugger::CalcLenTwoFields,  &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleTwoField);  //ADC
		RegisterMethodRef(0005600, 0005677, CString(_T("SBC")),    &CDebugger::CalcLenTwoFields,  &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleTwoField);  //SBC
		RegisterMethodRef(0005700, 0005777, CString(_T("TST")),    &CDebugger::CalcLenTwoFields,  &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleTwoField);  //TST
		RegisterMethodRef(0006000, 0006077, CString(_T("ROR")),    &CDebugger::CalcLenTwoFields,  &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleTwoField);  //ROR
		RegisterMethodRef(0006100, 0006177, CString(_T("ROL")),    &CDebugger::CalcLenTwoFields,  &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleTwoField);  //ROL
		RegisterMethodRef(0006200, 0006277, CString(_T("ASR")),    &CDebugger::CalcLenTwoFields,  &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleTwoField);  //ASR
		RegisterMethodRef(0006300, 0006377, CString(_T("ASL")),    &CDebugger::CalcLenTwoFields,  &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleTwoField);  //ASL
		RegisterMethodRef(0006400, 0006477, CString(_T("MARK")),   &CDebugger::CalcLenOneWord,    &CDebugger::CalcNextAddrMARK,    &CDebugger::DisassembleMARK);      //MARK
		RegisterMethodRef(0006500, 0006577, CString(_T("MFPI")),   &CDebugger::CalcLenTwoFields,  &CDebugger::CalcNextAddrUNKNOWN, &CDebugger::DisassembleTwoField);  //MFPI
		RegisterMethodRef(0006600, 0006677, CString(_T("MTPI")),   &CDebugger::CalcLenTwoFields,  &CDebugger::CalcNextAddrUNKNOWN, &CDebugger::DisassembleTwoField);  //MTPI
		RegisterMethodRef(0006700, 0006777, CString(_T("SXT")),    &CDebugger::CalcLenTwoFields,  &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleTwoField);  //SXT
		RegisterMethodRef(0010000, 0017777, CString(_T("MOV")),    &CDebugger::CalcLenFourFields, &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleFourField); //MOV
		RegisterMethodRef(0020000, 0027777, CString(_T("CMP")),    &CDebugger::CalcLenFourFields, &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleCMP);       //CMP
		RegisterMethodRef(0030000, 0037777, CString(_T("BIT")),    &CDebugger::CalcLenFourFields, &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleFourField); //BIT
		RegisterMethodRef(0040000, 0047777, CString(_T("BIC")),    &CDebugger::CalcLenFourFields, &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleFourField); //BIC
		RegisterMethodRef(0050000, 0057777, CString(_T("BIS")),    &CDebugger::CalcLenFourFields, &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleFourField); //BIS
		RegisterMethodRef(0060000, 0067777, CString(_T("ADD")),    &CDebugger::CalcLenFourFields, &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleFourField); //ADD
		RegisterMethodRef(0070000, 0070777, CString(_T("MUL")),    &CDebugger::CalcLenTwoFields,  &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleMUL);       //MUL
		RegisterMethodRef(0071000, 0071777, CString(_T("DIV")),    &CDebugger::CalcLenTwoFields,  &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleMUL);       //DIV
		RegisterMethodRef(0072000, 0072777, CString(_T("ASH")),    &CDebugger::CalcLenTwoFields,  &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleMUL);       //ASH
		RegisterMethodRef(0073000, 0073777, CString(_T("ASHC")),   &CDebugger::CalcLenTwoFields,  &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleMUL);       //ASHC
		RegisterMethodRef(0074000, 0074777, CString(_T("XOR")),    &CDebugger::CalcLenTwoFields,  &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleXOR);       //XOR
		RegisterMethodRef(0075000, 0075007, CString(_T("FADD")),   &CDebugger::CalcLenOneWord,    &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleOneField);  //FADD
		RegisterMethodRef(0075010, 0075017, CString(_T("FSUB")),   &CDebugger::CalcLenOneWord,    &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleOneField);  //FSUB
		RegisterMethodRef(0075020, 0075027, CString(_T("FMUL")),   &CDebugger::CalcLenOneWord,    &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleOneField);  //FMUL
		RegisterMethodRef(0075030, 0075037, CString(_T("FDIV")),   &CDebugger::CalcLenOneWord,    &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleOneField);  //FDIV
		RegisterMethodRef(0077000, 0077777, CString(_T("SOB")),    &CDebugger::CalcLenOneWord,    &CDebugger::CalcNextAddrSOB,     &CDebugger::DisassembleSOB);       //SOB
		RegisterMethodRef(0100000, 0100377, CString(_T("BPL")),    &CDebugger::CalcLenOneWord,    &CDebugger::CalcNextAddrBPL,     &CDebugger::DisassembleBR);        //BPL
		RegisterMethodRef(0100400, 0100777, CString(_T("BMI")),    &CDebugger::CalcLenOneWord,    &CDebugger::CalcNextAddrBMI,     &CDebugger::DisassembleBR);        //BMI
		RegisterMethodRef(0101000, 0101377, CString(_T("BHI")),    &CDebugger::CalcLenOneWord,    &CDebugger::CalcNextAddrBHI,     &CDebugger::DisassembleBR);        //BHI
		RegisterMethodRef(0101400, 0101777, CString(_T("BLOS")),   &CDebugger::CalcLenOneWord,    &CDebugger::CalcNextAddrBLOS,    &CDebugger::DisassembleBR);        //BLOS
		RegisterMethodRef(0102000, 0102377, CString(_T("BVC")),    &CDebugger::CalcLenOneWord,    &CDebugger::CalcNextAddrBVC,     &CDebugger::DisassembleBR);        //BVC
		RegisterMethodRef(0102400, 0102777, CString(_T("BVS")),    &CDebugger::CalcLenOneWord,    &CDebugger::CalcNextAddrBVS,     &CDebugger::DisassembleBR);        //BVS
		RegisterMethodRef(0103000, 0103377, CString(_T("BCC")),    &CDebugger::CalcLenOneWord,    &CDebugger::CalcNextAddrBCC,     &CDebugger::DisassembleBCC);       //BHIS/BCC
		RegisterMethodRef(0103400, 0103777, CString(_T("BCS")),    &CDebugger::CalcLenOneWord,    &CDebugger::CalcNextAddrBCS,     &CDebugger::DisassembleBCS);       //BLO/BCS
		RegisterMethodRef(0104000, 0104377, CString(_T("EMT")),    &CDebugger::CalcLenOneWord,    &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleEMT);       //EMT
		RegisterMethodRef(0104400, 0104777, CString(_T("TRAP")),   &CDebugger::CalcLenOneWord,    &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleEMT);       //TRAP
		RegisterMethodRef(0105000, 0105077, CString(_T("CLRB")),   &CDebugger::CalcLenTwoFields,  &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleTwoField);  //CLRB
		RegisterMethodRef(0105100, 0105177, CString(_T("COMB")),   &CDebugger::CalcLenTwoFields,  &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleTwoField);  //COMB
		RegisterMethodRef(0105200, 0105277, CString(_T("INCB")),   &CDebugger::CalcLenTwoFields,  &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleTwoField);  //INCB
		RegisterMethodRef(0105300, 0105377, CString(_T("DECB")),   &CDebugger::CalcLenTwoFields,  &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleTwoField);  //DECB
		RegisterMethodRef(0105400, 0105477, CString(_T("NEGB")),   &CDebugger::CalcLenTwoFields,  &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleTwoField);  //NEGB
		RegisterMethodRef(0105500, 0105577, CString(_T("ADCB")),   &CDebugger::CalcLenTwoFields,  &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleTwoField);  //ADCB
		RegisterMethodRef(0105600, 0105677, CString(_T("SBCB")),   &CDebugger::CalcLenTwoFields,  &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleTwoField);  //SBCB
		RegisterMethodRef(0105700, 0105777, CString(_T("TSTB")),   &CDebugger::CalcLenTwoFields,  &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleTwoField);  //TSTB
		RegisterMethodRef(0106000, 0106077, CString(_T("RORB")),   &CDebugger::CalcLenTwoFields,  &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleTwoField);  //RORB
		RegisterMethodRef(0106100, 0106177, CString(_T("ROLB")),   &CDebugger::CalcLenTwoFields,  &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleTwoField);  //ROLB
		RegisterMethodRef(0106200, 0106277, CString(_T("ASRB")),   &CDebugger::CalcLenTwoFields,  &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleTwoField);  //ASRB
		RegisterMethodRef(0106300, 0106377, CString(_T("ASLB")),   &CDebugger::CalcLenTwoFields,  &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleTwoField);  //ASLB
		RegisterMethodRef(0106400, 0106477, CString(_T("MTPS")),   &CDebugger::CalcLenTwoFields,  &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleTwoField);  //MTPS
		RegisterMethodRef(0106500, 0106577, CString(_T("MFPD")),   &CDebugger::CalcLenTwoFields,  &CDebugger::CalcNextAddrUNKNOWN, &CDebugger::DisassembleTwoField);  //MFPD
		RegisterMethodRef(0106600, 0106677, CString(_T("MTPD")),   &CDebugger::CalcLenTwoFields,  &CDebugger::CalcNextAddrUNKNOWN, &CDebugger::DisassembleTwoField);  //MTPD
		RegisterMethodRef(0106700, 0106777, CString(_T("MFPS")),   &CDebugger::CalcLenTwoFields,  &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleTwoField);  //MFPS
		RegisterMethodRef(0110000, 0117777, CString(_T("MOVB")),   &CDebugger::CalcLenFourFields, &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleFourField); //MOVB
		RegisterMethodRef(0120000, 0127777, CString(_T("CMPB")),   &CDebugger::CalcLenFourFields, &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleCMP);       //CMPB
		RegisterMethodRef(0130000, 0137777, CString(_T("BITB")),   &CDebugger::CalcLenFourFields, &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleFourField); //BITB
		RegisterMethodRef(0140000, 0147777, CString(_T("BICB")),   &CDebugger::CalcLenFourFields, &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleFourField); //BICB
		RegisterMethodRef(0150000, 0157777, CString(_T("BISB")),   &CDebugger::CalcLenFourFields, &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleFourField); //BISB
		RegisterMethodRef(0160000, 0167777, CString(_T("SUB")),    &CDebugger::CalcLenFourFields, &CDebugger::CalcNextAddrRegular, &CDebugger::DisassembleFourField); //SUB
	}
	else
	{
		CBKMessageBox(g_pstrErrors[BK_ERROR_NOTENMEMR], MB_OK);
	}
}


bool CDebugger::OnDebugModify_Regs(int nAddress, WORD nValue)
{
	if (m_pChip)
	{
		if (CCPU::R_R0 <= nAddress && nAddress <= CCPU::R_PSW)
		{
			m_pChip->SetRON(nAddress, nValue);
		}
		else
		{
			ASSERT(FALSE);
		}

		if (nAddress == CCPU::R_PC)
		{
			SetCurrentAddress(nValue);
		}
	}

	return true;
}

bool CDebugger::OnDebugModify_Ports(int nAddress, WORD nValue)
{
	if (m_pChip)
	{
		switch (nAddress)
		{
			case SYS_PORT_177660:
				m_pChip->m_reg177660 = nValue;
				break;

			case SYS_PORT_177662_IN:
				m_pChip->m_reg177662in = nValue;
				break;

			case SYS_PORT_177662_OUT:
				m_pChip->SetWordIndirect(0177662, nValue);
				break;

			case SYS_PORT_177664:
				m_pChip->SetWordIndirect(0177664, nValue);
				break;

			case SYS_PORT_177700:
				m_pChip->SetWordIndirect(0177700, nValue);
				break;

			case SYS_PORT_177702:
				m_pChip->SetWordIndirect(0177702, nValue);
				break;

			case SYS_PORT_177704:
				m_pChip->SetWordIndirect(0177704, nValue);
				break;

			case SYS_PORT_177706:
				m_pChip->SetWordIndirect(0177706, nValue);
				break;

			case SYS_PORT_177710:
				m_pChip->SetWordIndirect(0177710, nValue);
				break;

			case SYS_PORT_177712:
				m_pChip->SetWordIndirect(0177712, nValue);
				break;

			case SYS_PORT_177714_IN:
				m_pChip->m_reg177714in = nValue;
				break;

			case SYS_PORT_177714_OUT:
				m_pChip->SetWordIndirect(0177714, nValue);
				break;

			case SYS_PORT_177716_IN:
				m_pChip->m_reg177716in = nValue;
				break;

			case SYS_PORT_177716_OUT_TAP:
				m_pChip->m_reg177716out_tap = nValue;
				break;

			case SYS_PORT_177716_OUT_MEM:
				m_pChip->Set177716RegMem(nValue);
				break;

			default:
				ASSERT(FALSE);
		}
	}

	return true;
}

bool CDebugger::OnDebugModify_Memory(int nAddress, WORD nValue)
{
	if (m_pChip)
	{
		m_pChip->SetWordIndirect(nAddress, nValue);
	}

	return true;
}

bool CDebugger::OnDebugModify_Memory(int nAddress, BYTE nValue)
{
	if (m_pChip)
	{
		m_pChip->SetByteIndirect(nAddress, nValue);
	}

	return true;
}

bool CDebugger::OnDebugModify_AltProData(int nAddress, WORD nValue)
{
	if (m_pChip)
	{
		switch (nAddress)
		{
			case 0:
				m_pChip->SetAltProMode(nValue);
				break;

			case 1:
				m_pChip->SetAltProCode(nValue);
				break;
		}
	}

	return true;
}


