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

/*
File: Debugger.h
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.h: interface for the CDebugger class.
//


#pragma once

#include "DisasmCtrl.h"
#include "BreakPoint.h"
#include "CPU.h"

class CMotherBoard;

#define COLORED_TAG "<HLC>"
#define COLORED_TAG_LENGTH 5


#define SRC             2
#define DST             0

#define SYS_PORT_177660 0
#define SYS_PORT_177662_IN 1
#define SYS_PORT_177662_OUT 2
#define SYS_PORT_177664 3
#define SYS_PORT_177700 4
#define SYS_PORT_177702 5
#define SYS_PORT_177704 6
#define SYS_PORT_177706 7
#define SYS_PORT_177710 8
#define SYS_PORT_177712 9
#define SYS_PORT_177714_IN 10
#define SYS_PORT_177714_OUT 11
#define SYS_PORT_177716_IN 12
#define SYS_PORT_177716_OUT_TAP 13
#define SYS_PORT_177716_OUT_MEM 14


enum {MARK_COLUMN = 0, ADDR_COLUMN, INSTR_COLUMN, ARG_COLUMN, COM_COLUMN};
//массив цветов для подсветки синтаксиса
enum { HLCOLOR_DEFAULT = 0, HLCOLOR_ADDRESS, HLCOLOR_MNEMONIC, HLCOLOR_REGISTER, HLCOLOR_NUMBER, HLCOLOR_SYMBOL };
static COLORREF g_crDebugColorHighLighting[] =
{
	RGB(0, 0, 0), //HLCOLOR_DEFAULT
	RGB(0x66, 0, 0), //HLCOLOR_ADDRESS
	RGB(0, 0, 0xcc), //HLCOLOR_MNEMONIC
	RGB(0, 0x66, 0xcc), //HLCOLOR_REGISTER
	RGB(0xff, 0x66, 0), //HLCOLOR_NUMBER
	RGB(0x33, 0x33, 0x33) //HLCOLOR_SYMBOL
};


class CDebugger
{
		typedef int (CDebugger::*CalcInstrLenRef)(); //в качестве аргумента - значение в m_wInstr, результат - возвращаемое значение
		typedef bool (CDebugger::*CalcNextAddrRef)(); //в качестве аргумента - значение в m_wInstr, результат - в m_wNextAddr, возвращает: true - m_wNextAddr актуально, false - нет
		typedef int (CDebugger::*DisassembleInstrRef)(WORD *codes); //в качестве аргумента - значение в m_wInstr и m_wPC, результат - в m_strInstr и m_strArg, возвращает кол-во доп.слов инструкции
		struct InstrFuncRefs
		{
			CString Mnemonic;
			CalcInstrLenRef InstrLenRef;
			CalcNextAddrRef NextAddrRef;
			DisassembleInstrRef DisasmInstrRef;
		};
		InstrFuncRefs *m_pInstrRefsMap;
		void RegisterMethodRef(WORD start, WORD end, CString &mnemonic, CalcInstrLenRef ilenmref, CalcNextAddrRef nxamref, DisassembleInstrRef dsimref);
		void InitMaps();

		HICON               m_hBPIcon, m_hCurrIcon;

		static int          m_outLevel;
		static const CString m_strRegNames[8];
		static const CString m_strAddrFormat[8];
		static const CString m_strAddrFormat_PC[8];
		static const CString m_strArgFormat_Addr;
		static const CString m_strArgFormat_Number;
		static const CString m_strArgFormat_Comma;

		CMotherBoard       *m_pChip;
		CDisasmCtrl        *m_pCtrl;
		CBreakPointList     m_breakpointList;

		WORD                m_wAddress;  //адрес самой первой строки для дизассемблирвоания
		int                 m_nLines;   //количество строк в списке для дизассемблирования
		bool                m_bPrevCmdC;    //флаг, как дизассемблировать BCC/BHIS BCS/BLO
		bool                m_bPrevCmdCp;   //после команды CMP - сравнение, иначе - битС

		//для того, чтобы не передавать функциям кучу лишней информации, заведём глобальные переменные

		WORD                m_wPC;   //текущий адрес текущей инструкции
		WORD                m_wInstr; //сама инструкция
		WORD                m_wNextAddr; //расчётный следующий адрес
		CString             m_strInstr;     //мнемоника
		CString             m_strArg;       //аргументы, если есть

		WORD                GetLineAddress(int nNum);
		int                 ConvertArgToString(int arg, WORD pc, CString &strSrc, WORD &code);
		void                DrawMarker(WORD address, CDC *pDC, CRect &rc);

		// Breakpoint managment methods
		bool                IsBpeakpointExists(CBreakPoint &breakpoint);
		bool                IsBpeakpointAtAddress(WORD addr);

		int                 GetArg(int type);
		int                 GetArgAddr(int meth, int reg);
		int                 CalcArgLength(int pos);

		int                 CalcLenOneWord();
		int                 CalcLenTwoFields();
		int                 CalcLenFourFields();

		bool                CalcNextAddrRegular();
		bool                CalcNextAddrUNKNOWN();
		bool                CalcNextAddrRTI();
		bool                CalcNextAddrRTS();
		bool                CalcNextAddrJMP();
		bool                CalcNextAddrMARK();
		bool                CalcNextAddrSOB();

		bool                CalcNextAddrBR();
		bool                CalcNextAddrBNE();
		bool                CalcNextAddrBEQ();
		bool                CalcNextAddrBGE();
		bool                CalcNextAddrBLT();
		bool                CalcNextAddrBGT();
		bool                CalcNextAddrBLE();
		bool                CalcNextAddrBPL();
		bool                CalcNextAddrBMI();
		bool                CalcNextAddrBHI();
		bool                CalcNextAddrBLOS();
		bool                CalcNextAddrBVC();
		bool                CalcNextAddrBVS();
		bool                CalcNextAddrBCC();
		bool                CalcNextAddrBCS();

		int                 DisassembleNoArgs(WORD *codes);
		int                 DisassembleUnknown(WORD *codes);
		int                 DisassembleCLS(WORD *codes);
		int                 DisassembleSET(WORD *codes);
		int                 DisassembleRTS(WORD *codes);
		int                 DisassembleOneField(WORD *codes);
		int                 DisassembleTwoField(WORD *codes);
		int                 DisassembleFourField(WORD *codes);
		int                 DisassembleMARK(WORD *codes);
		int                 DisassembleEMT(WORD *codes);
		int                 DisassembleBR(WORD *codes);
		int                 DisassembleBCC(WORD *codes);
		int                 DisassembleBCS(WORD *codes);
		int                 DisassembleJSR(WORD *codes);
		int                 DisassembleMUL(WORD *codes);
		int                 DisassembleXOR(WORD *codes);
		int                 DisassembleSOB(WORD *codes);
		int                 DisassembleCMP(WORD *codes);

	public:
		CDebugger();
		virtual ~CDebugger();
		inline CMotherBoard *GetChip() const
		{
			return m_pChip;
		}
		bool                GetDebugPCBreak(WORD value);

		bool                CalcNextAddr(WORD pc, WORD &addr);

		int                 CalcInstructionLength(WORD instr);
		static void         InitOutMode()
		{
			m_outLevel = 0;
		}
		static bool         IsInstructionOut(WORD instruction);
		bool                IsInstructionOver(WORD instruction);

		void                AttachChip(CMotherBoard *pChip);
		inline void         AttachWnd(CDisasmCtrl *pCtrl)
		{
			m_pCtrl = pCtrl;
		}
		inline void         SetLinesNum(int nNum)
		{
			m_nLines = nNum;
		}
		inline int          GetLinesNum()
		{
			return m_nLines;
		}
		void                SetCurrentAddress(WORD address)
		{
			m_wAddress = address;
			m_pCtrl->Invalidate(FALSE);
		}
		inline WORD         GetCurrentAddress()
		{
			return m_wAddress;
		}

		int                 DebugInstruction(WORD pc, CString &strInstr, CString &strArg, WORD *codes);
		void                DrawDebuggerLine(int nNum, CDC *pDC, CRect *pRcSubs);
		void                DrawColoredText(CDC *pDC, CRect &rect, CString &str);

		void                StepForward();
		void                StepBackward();

		WORD                GetCursorAddress();
		WORD                GetBottomAddress();

		WORD                GetPSW();
		WORD                GetRegister(int reg);
		WORD                GetPortValue(int addr);
		WORD                GetAltProData(int reg);
		WORD                GetFDDData(int reg);
		WORD                GetDebugHDDRegs(int nDrive, int num, bool bReadMode);
		WORD                GetDebugMemDumpWord(WORD addr);
		BYTE                GetDebugMemDumpByte(WORD addr);

		bool                OnDebugModify_Regs(int nAddress, WORD nValue);
		bool                OnDebugModify_Ports(int nAddress, WORD nValue);
		bool                OnDebugModify_Memory(int nAddress, WORD nValue);
		bool                OnDebugModify_Memory(int nAddress, BYTE nValue);
		bool                OnDebugModify_AltProData(int nAddress, WORD nValue);
		// Breakpoint managment methods
		bool                SetSimpleBreakpoint(WORD addr);
		bool                SetSimpleBreakpoint();
		bool                RemoveBreakpoint(WORD addr);
		bool                RemoveBreakpoint();
		void                ClearBreakpointList()
		{
			m_breakpointList.RemoveAll();
		}
};
