From 7f7410c8f8b0734343984dca57d984214ade46d1 Mon Sep 17 00:00:00 2001 From: Godzil Date: Thu, 15 Apr 2021 23:07:13 +0100 Subject: [PATCH] First step to get a debugger: Decode instructions. I now have an headache. A couple of instruction are still not properly decoded. I need to find proper documentation on them. --- source/nec/CMakeLists.txt | 4 +- source/nec/nec.c | 42 +- source/nec/nec_debugger.c | 1219 +++++++++++++++++++++++++++++++++++++ source/nec/nec_debugger.h | 16 + 4 files changed, 1254 insertions(+), 27 deletions(-) create mode 100644 source/nec/nec_debugger.c create mode 100644 source/nec/nec_debugger.h diff --git a/source/nec/CMakeLists.txt b/source/nec/CMakeLists.txt index 2adfabd..d4dcf97 100644 --- a/source/nec/CMakeLists.txt +++ b/source/nec/CMakeLists.txt @@ -1,5 +1,5 @@ -set(SOURCES nec.c) -set(HEADERS nec.h necea.h necinstr.h necintrf.h necmodrm.h) +set(SOURCES nec.c nec_debugger.c) +set(HEADERS nec.h necea.h necinstr.h necintrf.h necmodrm.h nec_debugger.h) add_library(nec_v30 ${SOURCES} ${HEADERS}) diff --git a/source/nec/nec.c b/source/nec/nec.c index d26004a..22d95e8 100644 --- a/source/nec/nec.c +++ b/source/nec/nec.c @@ -41,6 +41,7 @@ #include "nec.h" #include "necintrf.h" +#include "nec_debugger.h" /***************************************************************************/ /* cpu state */ @@ -4209,28 +4210,6 @@ void nec_set_reg(int regnum, uint32_t val) } } -const char *instructionsName[256] = { - "ADD ", "ADD ", "ADD ", "ADD ", "ADD ", "ADD ", "PUSH", "POP ", "OR ", "OR ", "OR ", "OR ", "OR ", "OR ", - "PUSH", "----", "ADC ", "ADC ", "ADC ", "ADC ", "ADC ", "ADC ", "PUSH", "POP ", "SBB ", "SBB ", "SBB ", "SBB ", - "SBB ", "SBB ", "PUSH", "POP ", "AND ", "AND ", "AND ", "AND ", "AND ", "AND ", "ES: ", "DAA ", "SUB ", "SUB ", - "SUB ", "SUB ", "SUB ", "SUB ", "CS: ", "DAS ", "XOR ", "XOR ", "XOR ", "XOR ", "XOR ", "XOR ", "SS: ", "AAA ", - "CMP ", "CMP ", "CMP ", "CMP ", "CMP ", "CMP ", "ES: ", "AAS ", "INC ", "INC ", "INC ", "INC ", "INC ", "INC ", - "INC ", "DEC ", "DEC ", "DEC ", "DEC ", "DEC ", "DEC ", "DEC ", "DEC ", "DEC ", "PUSH", "PUSH", "PUSH", "PUSH", - "PUSH", "PUSH", "PUSH", "PUSH", "POP ", "POP ", "POP ", "POP ", "POP ", "POP ", "POP ", "POP ", "PUSA", "POPA", - "BOND", "----", "----", "----", "----", "----", "PUSH", "IMUL", "PUSH", "IMUL", "INS ", "INS ", "OUTS", "OUTS", - "JO ", "JNO ", "JB ", "JNB ", "JZ ", "JNZ ", "JBE ", "JA ", "JS ", "JNS ", "JPE ", "JPO ", "JL ", "JGE ", - "JLE ", "JG ", "GPR1", "GPR1", "GPR1", "GPR1", "TEST", "TEST", "XCHG", "XCHG", "MOV ", "MOV ", "MOV ", "MOV ", - "MOV ", "LEA ", "MOV ", "POP ", "NOP ", "XCHA", "XCHA", "XCHA", "XCHA", "XCHA", "XCHA", "XCHA", "CBW ", "CWD ", - "CALL", "WAIT", "PSHF", "POPF", "SAHF", "LAHF", "MOV ", "MOV ", "MOV ", "MOV ", "MOVS", "MOVS", "CMPS", "CMPS", - "TEST", "TEST", "STOS", "STOS", "LODS", "LODS", "SCAS", "SCAS", "MOV ", "MOV ", "MOV ", "MOV ", "MOV ", "MOV ", - "MOV ", "MOV ", "MOV ", "MOV ", "MOV ", "MOV ", "MOV ", "MOV ", "MOV ", "MOV ", "GRP2", "GRP2", "RETN", "RETN", - "LES ", "LDS ", "MOV ", "MOV ", "ENTR", "LEAV", "RETF", "RETF", "INT3", "INT ", "INTO", "IRET", "GRP2", "GRP2", - "GRP2", "GRP2", "AAM ", "AAD ", "----", "XLAT", "----", "----", "----", "----", "----", "----", "----", "----", - "LPNZ", "LPZ ", "LOOP", "JCXZ", "IN ", "IN ", "OUT ", "OUT ", "CALL", "JMP ", "JMP ", "JMP ", "IN ", "IN ", - "OUT ", "OUT ", "LOCK", "----", "RPNZ", "REP ", "HLT ", "CMC ", "GP3A", "GP3B", "CLC ", "STC ", "CLI ", "STI ", - "CLD ", "STD ", "GPR4", "GRP5" -}; - int nec_execute(int cycles) { @@ -4242,9 +4221,22 @@ int nec_execute(int cycles) while (nec_ICount > 0) { #if 0 - uint8_t op = cpu_readmem20((I.sregs[CS]<<4) + I.ip); - Log(TLOG_NORMAL, "NEC v30", "[%04x:%04xh] %02xh '%s' - I=%d\n", I.sregs[CS], I.ip, - op, instructionsName[op], I.IF); + if ((I.sregs[CS] == 0x0600) /* && (I.ip > 0x0050) */) + { + int tmp; + char buffer[256]; + uint8_t op = cpu_readmem20((I.sregs[CS] << 4) + I.ip); + //Log(TLOG_NORMAL, "NEC v30", "[%04x:%04xh] %02xh '%s' - I=%d\n", I.sregs[CS], I.ip, op, instructionsName[op], I.IF); + printf("AX: %04X, BX: %04X, CX: %04X, DX: %04X, SI: %04X, DI: %04X, SP: %04X\n", + I.regs.w[AW], I.regs.w[BW], I.regs.w[CW], I.regs.w[DW], + I.regs.w[IX], I.regs.w[IY], I.regs.w[SP]); + printf("CS: %04X, DS: %04X, SS: %04X, ES: %04X\n", + I.sregs[CS], I.sregs[DS], I.sregs[SS], I.sregs[ES]); + memset(buffer, 0, 256); + nec_decode_instruction(I.sregs[CS], I.ip, buffer, 255); + printf("[%04x:%04xh] %02xh '%s' - I=%d\n", I.sregs[CS], I.ip, op, buffer, I.IF); + tmp = getchar(); + } #endif nec_instruction[FETCHOP](); // nec_ICount++; diff --git a/source/nec/nec_debugger.c b/source/nec/nec_debugger.c new file mode 100644 index 0000000..335c5b6 --- /dev/null +++ b/source/nec/nec_debugger.c @@ -0,0 +1,1219 @@ +/* + * NewOswan + * nec_debugger.c: + * Based on the original Oswan-unix + * Created by Manoël Trapier on 14/04/2021. + * Copyright (c) 2014-2021 986-Studio. All rights reserved. + * + */ + +#include +#include +#include +#include + +#include "log.h" +#include "nec_debugger.h" +#include "necintrf.h" + +/*** + * Note: the while code to decode instruction is not meant to be optimised, but to be easy to maintain. + * It probably could be more concise, but this is code for the debugger, not runtime, so optimisation does + * not really matter here. + */ + +typedef enum operandParameterTypes +{ + PR_RM_R8, /**< reg8/mem8, reg8 */ + PR_RM_R16, /**< reg16/mem16, reg16 */ + PR_AL_IM8, /**< AL, immed8 */ + PR_AX_IM16, /**< AX, immed16 */ + PR_ES, /**< ES */ + PR_R_RM8, /**< reg8, reg8/mem8 */ + PR_R_RM16, /**< reg16, ret16/mem16 */ + PR_CS, /**< CS */ + PR_SS, /**< SS */ + PR_DS, /**< DS */ + PR_NONE, /**< No parameter or Prefix */ + PR_AX, /**< AX */ + PR_CX, /**< CX */ + PR_DX, /**< DX */ + PR_BX, /**< BX */ + PR_SP, /**< SP */ + PR_BP, /**< BP */ + PR_SI, /**< SI */ + PR_DI, /**< DI */ + PR_IM16, /**< immediate 16 */ + PR_REL8, /**< short label */ + PR_RM_IM8, /**< reg8/mem8, immediate8 */ + PR_RM_IM16, /**< reg16/mem16, immed16 */ + PR_RM16_SEG, /**< reg16/mem16, SegReg */ + PR_SEG_RM16, /**< SegReg, reg16/mem16 */ + PR_AX_CX, /**< AX, CX */ + PR_AX_DX, /**< AX, DX */ + PR_AX_BX, /**< AX, BX */ + PR_AX_SP, /**< AX, SP */ + PR_AX_BP, /**< AX, BP */ + PR_AX_SI, /**< AX, SI */ + PR_AX_DI, /**< AX, DI */ + PR_ABS32, /**< far proc */ + PR_AL_M8, /**< AL, mem8 */ + PR_AX_M16, /**< AX, mem16 */ + PR_M8_AL, /**< mem8, AL */ + PR_M16_AX, /**< mem16, AX */ + PR_CL_IM8, /**< CL, immed8 */ + PR_DL_IM8, /**< DL, immed8 */ + PR_BL_IM8, /**< BL, immed8 */ + PR_AH_IM8, /**< AH, immed8 */ + PR_CH_IM8, /**< CH, immed8 */ + PR_DH_IM8, /**< DH, immed8 */ + PR_BH_IM8, /**< BH, immed8 */ + PR_CX_IM16, /**< CX, immed16 */ + PR_DX_IM16, /**< DX, immed16 */ + PR_BX_IM16, /**< BX, immed16 */ + PR_SP_IM16, /**< SP, immed16 */ + PR_BP_IM16, /**< BP, immed16 */ + PR_SI_IM16, /**< SI, immed16 */ + PR_DI_IM16, /**< DI, immed16 */ + PR_RM16_IM8, /**< reg16/mem16, immed8 */ + PR_IM16_IM8, /**< immed16, immed8 */ + PR_IM8, /**< immed8 */ + PR_RM8_1, /**< reg8/mem8, 1 */ + PR_RM16_1, /**< reg16/mem16, 1 */ + PR_RM8_CL, /**< reg8/mem8, CL */ + PR_RM16_CL, /**< reg16/mem16, CL */ + PR_AX_IM8, /**< AX, immed8 */ + PR_AL_DX, /**< AL, DX */ + PR_NONE8, /**< No param, work in 8 bit */ + PR_NONE16, /**< No param, work in 16 bits */ + PR_PREFIX, /**< No param, but is a prefix */ + PR_REL16, /**< near label */ + PR_IM8_AL, /**< immed8, AL */ + PR_IM8_AX, /**< immed8, AX */ + PR_DX_AL, /**< DX, AL */ + PR_DX_AX, /**< DX, AX */ + PR_RM8, /**< reg8/mem8 */ + PR_RM16, /**< reg16/mem16 */ + PR_NONEFAR, /**< no opcode but far related */ +} operandParameterTypes; + +typedef enum operandTypes +{ + OP_ILEG = 0, + OP_ADD, OP_PUSH, OP_POP, OP_OR, OP_ADC, OP_SBB, OP_AND, OP_DAA, OP_SUB, OP_DAS, OP_XOR, OP_AAA, OP_CMP, + OP_AAS, OP_INC, OP_DEC, OP_PUSHA, OP_POPA, OP_IMUL, OP_INS, OP_OUTS, OP_JO, OP_JNO, OP_JB, OP_JNB, + OP_JE, OP_JNE, OP_JBE, OP_JNBE, OP_JS, OP_JNS, OP_JP, OP_JNP, OP_JL, OP_JNL, OP_JLE, OP_JNLE, OP_TEST, + OP_XCHG, OP_MOV, OP_LEA, OP_NOP, OP_WAIT, OP_PUSHF, OP_POPF, OP_SAHF, OP_LAHF, OP_MOVS, OP_CMPS, + OP_STOS, OP_LODS, OP_SCAS, OP_LDS, OP_LES, OP_ENTER, OP_LEAVE, OP_RET, OP_INT3, OP_INT, OP_INTO, + OP_IRET, OP_XLAT, OP_LOOPNZ, OP_LOOPE, OP_LOOP, OP_JCXZ, OP_IN, OP_OUT, OP_CALL, OP_JMP, OP_HLT, + OP_CLC, OP_STC, OP_CLI, OP_STI, OP_CLS, OP_STD, OP_IMMED, OP_SHIFT, OP_GRP1, OP_GRP2, OP_BOUND, + OP_CBW, OP_CWD, OP_AAM, OP_AAD, OP_LOCK, OP_REP, OP_REPNZ, OP_CMC, OP_CS, OP_DS, OP_ES, OP_SS, OP_MOVG +} operandTypes; + +const char *operandTypeNameTable[] = +{ + [OP_ILEG] = "Illegal", + [OP_ADD] = "add", + [OP_PUSH] = "push", + [OP_POP] = "pop", + [OP_OR] = "or", + [OP_ADC] = "adc", + [OP_SBB] = "sbb", + [OP_AND] = "and", + [OP_DAA] = "daa", + [OP_SUB] = "sub", + [OP_DAS] = "das", + [OP_XOR] = "xor", + [OP_AAA] = "aaa", + [OP_CMP] = "cmp", + [OP_AAS] = "aas", + [OP_INC] = "inc", + [OP_DEC] = "dec", + [OP_PUSHA] = "pusha", + [OP_POPA] = "popa", + [OP_IMUL] = "imul", + [OP_INS] = "ins", + [OP_OUTS] = "outs", + [OP_JO] = "jo", + [OP_JNO] = "jno", + [OP_JB] = "jb", + [OP_JNB] = "inb", + [OP_JE] = "je", + [OP_JNE] = "jne", + [OP_JBE] = "jbe", + [OP_JNBE] = "jnbe", + [OP_JS] = "js", + [OP_JNS] = "jns", + [OP_JP] = "jo", + [OP_JNP] = "jno", + [OP_JL] = "jl", + [OP_JNL] = "jnl", + [OP_JLE] = "jle", + [OP_JNLE] = "jnle", + [OP_TEST] = "test", + [OP_XCHG] = "xchg", + [OP_MOV] = "mov", + [OP_LEA] = "lea", + [OP_NOP] = "nop", + [OP_WAIT] = "wait", + [OP_PUSHF] = "pushf", + [OP_POPF] = "popf", + [OP_SAHF] = "sahf", + [OP_LAHF] = "lahf", + [OP_MOVS] = "movs", + [OP_CMPS] = "cmps", + [OP_STOS] = "stos", + [OP_LODS] = "lods", + [OP_SCAS] = "scas", + [OP_LDS] = "lds", + [OP_LES] = "led", + [OP_ENTER] = "enter", + [OP_LEAVE] = "leave", + [OP_RET] = "ret", + [OP_INT3] = "int3", + [OP_INT] = "int", + [OP_INTO] = "into", + [OP_IRET] = "iret", + [OP_XLAT] = "xlat", + [OP_LOOPNZ] = "loopnz", + [OP_LOOPE] = "loope", + [OP_LOOP] = "loop", + [OP_JCXZ] = "jcxz", + [OP_IN] = "in", + [OP_OUT] = "out", + [OP_CALL] = "call", + [OP_JMP] = "jmp", + [OP_HLT] = "hlt", + [OP_CLC] = "clc", + [OP_STC] = "stc", + [OP_CLI] = "cli", + [OP_STI] = "sti", + [OP_CLS] = "cls", + [OP_STD] = "std", + [OP_IMMED] = "", + [OP_SHIFT] = "", + [OP_GRP1] = "", + [OP_GRP2] = "", + [OP_CS] = "cs:", + [OP_ES] = "es:", + [OP_DS] = "ds:", + [OP_SS] = "ss:", + [OP_BOUND] = "bound", + [OP_CBW] = "cbw", + [OP_CWD] = "cwd", + [OP_AAM] = "aam", + [OP_AAD] = "aad", + [OP_LOCK] = "lock", + [OP_REP] = "rep", + [OP_REPNZ] = "repnz", + [OP_CMC] = "cmc", + [OP_MOVG] = "", +}; + +operandTypes opcodeTypeTable[256] = +{ + /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_PUSH, OP_POP, OP_OR, OP_OR, OP_OR, OP_OR, OP_OR, OP_OR, OP_PUSH, OP_ILEG, /* 0 */ + OP_ADC, OP_ADC, OP_ADC, OP_ADC, OP_ADC, OP_ADC, OP_PUSH, OP_POP, OP_SBB, OP_SBB, OP_SBB, OP_SBB, OP_SBB, OP_SBB, OP_PUSH, OP_POP, /* 1 */ + OP_AND, OP_AND, OP_AND, OP_AND, OP_AND, OP_AND, OP_ES, OP_DAA, OP_SUB, OP_SUB, OP_SUB, OP_SUB, OP_SUB, OP_SUB, OP_CS, OP_DAS, /* 2 */ + OP_XOR, OP_XOR, OP_XOR, OP_XOR, OP_XOR, OP_XOR, OP_SS, OP_AAA, OP_CMP, OP_CMP, OP_CMP, OP_CMP, OP_CMP, OP_CMP, OP_DS, OP_AAS, /* 3 */ + OP_INC, OP_INC, OP_INC, OP_INC, OP_INC, OP_INC, OP_INC, OP_INC, OP_DEC, OP_DEC, OP_DEC, OP_DEC, OP_DEC, OP_DEC, OP_DEC, OP_DEC, /* 4 */ + OP_PUSH, OP_PUSH, OP_PUSH, OP_PUSH, OP_PUSH, OP_PUSH, OP_PUSH, OP_PUSH, OP_POP, OP_POP, OP_POP, OP_POP, OP_POP, OP_POP, OP_POP, OP_POP, /* 5 */ + OP_PUSHA, OP_POPA, OP_BOUND, OP_ILEG, OP_ILEG, OP_ILEG, OP_ILEG, OP_ILEG, OP_PUSH, OP_IMUL, OP_PUSH, OP_IMUL, OP_INS, OP_INS, OP_OUTS, OP_OUTS, /* 6 */ + OP_JO, OP_JNO, OP_JB, OP_JNB, OP_JE, OP_JNE, OP_JBE, OP_JNBE, OP_JS, OP_JNS, OP_JP, OP_JNP, OP_JL, OP_JNL, OP_JLE, OP_JNLE, /* 7 */ + OP_IMMED, OP_IMMED, OP_IMMED, OP_IMMED, OP_TEST, OP_TEST, OP_XCHG, OP_XCHG, OP_MOV, OP_MOV, OP_MOV, OP_MOV, OP_MOV, OP_LEA, OP_MOV, OP_POP, /* 8 */ + OP_NOP, OP_XCHG, OP_XCHG, OP_XCHG, OP_XCHG, OP_XCHG, OP_XCHG, OP_XCHG, OP_CBW, OP_CWD, OP_CALL, OP_WAIT, OP_PUSHF, OP_POPF, OP_SAHF, OP_LAHF, /* 9 */ + OP_MOV, OP_MOV, OP_MOV, OP_MOV, OP_MOVS, OP_MOVS, OP_CMPS, OP_CMPS, OP_TEST, OP_TEST, OP_STOS, OP_STOS, OP_LODS, OP_LODS, OP_SCAS, OP_SCAS, /* A */ + OP_MOV, OP_MOV, OP_MOV, OP_MOV, OP_MOV, OP_MOV, OP_MOV, OP_MOV, OP_MOV, OP_MOV, OP_MOV, OP_MOV, OP_MOV, OP_MOV, OP_MOV, OP_MOV, /* B */ + OP_SHIFT, OP_SHIFT, OP_RET, OP_RET, OP_LES, OP_LDS, OP_MOVG, OP_MOVG, OP_ENTER, OP_LEAVE, OP_RET, OP_RET, OP_INT3, OP_INT, OP_INTO, OP_IRET, /* C */ + OP_SHIFT, OP_SHIFT, OP_SHIFT, OP_SHIFT, OP_AAM, OP_AAD, OP_ILEG, OP_XLAT, OP_ILEG, OP_ILEG, OP_ILEG, OP_ILEG, OP_ILEG, OP_ILEG, OP_ILEG, OP_ILEG, /* D */ + OP_LOOPNZ, OP_LOOPE, OP_LOOP, OP_JCXZ, OP_IN, OP_IN, OP_OUT, OP_OUT, OP_CALL, OP_JMP, OP_JMP, OP_JMP, OP_IN, OP_IN, OP_OUT, OP_OUT, /* E */ + OP_LOCK, OP_ILEG, OP_REPNZ, OP_REP, OP_HLT, OP_CMC, OP_GRP1, OP_GRP1, OP_CLC, OP_STC, OP_CLI, OP_STI, OP_CLS, OP_STD, OP_GRP2, OP_GRP2, /* F */ + /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ +}; + +operandParameterTypes opcodeParamTypeTable[256] = +{ + /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + PR_RM_R8, PR_RM_R16, PR_R_RM8, PR_R_RM16, PR_AL_IM8, PR_AX_IM16, PR_ES, PR_ES, PR_RM_R8, PR_RM_R16, PR_R_RM8, PR_R_RM16, PR_AL_IM8, PR_AX_IM16, PR_CS, PR_NONE, /* 0 */ + PR_RM_R8, PR_RM_R16, PR_R_RM8, PR_R_RM16, PR_AL_IM8, PR_AX_IM16, PR_SS, PR_SS, PR_RM_R8, PR_RM_R16, PR_R_RM8, PR_R_RM16, PR_AL_IM8, PR_AX_IM16, PR_DS, PR_DS, /* 1 */ + PR_RM_R8, PR_RM_R16, PR_R_RM8, PR_R_RM16, PR_AL_IM8, PR_AX_IM16, PR_PREFIX, PR_NONE, PR_RM_R8, PR_RM_R16, PR_R_RM8, PR_R_RM16, PR_AL_IM8, PR_AX_IM16, PR_PREFIX, PR_NONE, /* 2 */ + PR_RM_R8, PR_RM_R16, PR_R_RM8, PR_R_RM16, PR_AL_IM8, PR_AX_IM16, PR_PREFIX, PR_NONE, PR_RM_R8, PR_RM_R16, PR_R_RM8, PR_R_RM16, PR_AL_IM8, PR_AX_IM16, PR_PREFIX, PR_NONE, /* 3 */ + PR_AX, PR_CX, PR_DX, PR_BX, PR_SP, PR_BP, PR_SI, PR_DI, PR_AX, PR_CX, PR_DX, PR_BX, PR_SP, PR_BP, PR_SI, PR_DI, /* 4 */ + PR_AX, PR_CX, PR_DX, PR_BX, PR_SP, PR_BP, PR_SI, PR_DI, PR_AX, PR_CX, PR_DX, PR_BX, PR_SP, PR_BP, PR_SI, PR_DI, /* 5 */ + PR_NONE, PR_NONE, PR_R_RM16, PR_NONE, PR_NONE, PR_NONE, PR_NONE, PR_NONE, PR_IM16, PR_RM_IM16, PR_IM8, PR_RM16_IM8, PR_NONE8, PR_NONE16, PR_NONE8, PR_NONE16, /* 6 */ + PR_REL8, PR_REL8, PR_REL8, PR_REL8, PR_REL8, PR_REL8, PR_REL8, PR_REL8, PR_REL8, PR_REL8, PR_REL8, PR_REL8, PR_REL8, PR_REL8, PR_REL8, PR_REL8, /* 7 */ + PR_RM_IM8, PR_RM_IM16, PR_RM_IM8, PR_RM16_IM8, PR_RM_R8, PR_RM_R16, PR_R_RM8, PR_R_RM16, PR_RM_R8, PR_RM_R16, PR_R_RM8, PR_R_RM16, PR_RM16_SEG, PR_R_RM16, PR_SEG_RM16, PR_NONE, /* 8 */ + PR_NONE, PR_AX_CX, PR_AX_DX, PR_AX_BX, PR_AX_SP, PR_AX_BP, PR_AX_SI, PR_AX_DI, PR_NONE, PR_NONE, PR_ABS32, PR_NONE, PR_NONE, PR_NONE, PR_NONE, PR_NONE, /* 9 */ + PR_AL_M8, PR_AX_M16, PR_M8_AL, PR_M16_AX, PR_NONE8, PR_NONE16, PR_NONE8, PR_NONE16, PR_AL_IM8, PR_AX_IM16, PR_NONE8, PR_NONE16, PR_NONE8, PR_NONE16, PR_NONE8, PR_NONE16, /* A */ + PR_AL_IM8, PR_CL_IM8, PR_DL_IM8, PR_BL_IM8, PR_AH_IM8, PR_CH_IM8, PR_DH_IM8, PR_BH_IM8, PR_AX_IM16, PR_CX_IM16, PR_DX_IM16, PR_BX_IM16, PR_SP_IM16, PR_BP_IM16, PR_SI_IM16, PR_DI_IM16, /* B */ + PR_RM_IM8, PR_RM16_IM8, PR_IM16, PR_NONE, PR_R_RM16, PR_R_RM16, PR_RM_IM8, PR_RM_IM16, PR_IM16_IM8, PR_NONE, PR_IM16, PR_NONEFAR, PR_NONE, PR_IM8, PR_NONE, PR_NONE, /* C */ + PR_RM8_1, PR_RM16_1, PR_RM8_CL, PR_RM16_CL, PR_NONE, PR_NONE, PR_NONE, PR_NONE, PR_NONE, PR_NONE, PR_NONE, PR_NONE, PR_NONE, PR_NONE, PR_NONE, PR_NONE, /* D */ + PR_REL8, PR_REL8, PR_REL8, PR_REL8, PR_AL_IM8, PR_AX_IM8, PR_IM8_AL, PR_IM8_AX, PR_REL16, PR_REL16, PR_ABS32, PR_REL8, PR_AL_DX, PR_AX_DX, PR_DX_AL, PR_DX_AX, /* E */ + PR_PREFIX, PR_NONE, PR_PREFIX, PR_PREFIX, PR_NONE, PR_NONE, PR_RM8, PR_RM16, PR_NONE, PR_NONE, PR_NONE, PR_NONE, PR_NONE, PR_NONE, PR_RM8, PR_RM16, /* F */ + /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ +}; + +enum extendedOpcodes +{ + OP_IMD_ADD = 0, + OP_IMD_OR = 1, + OP_IMD_ADC = 2, + OP_IMD_SBB = 3, + OP_IMD_AND = 4, + OP_IMD_SUB = 5, + OP_IMD_XOR = 6, + OP_IMD_CMP = 7, + + OP_SFT_ROL = 0, + OP_SFT_ROR = 1, + OP_SFT_RCL = 2, + OP_SFT_RCR = 3, + OP_SFT_SHL = 4, + OP_SFT_SHR = 5, + OP_SFT_SAR = 7, + + OP_GP1_TEST = 0, + OP_GP1_NOT = 2, + OP_GP1_NEG = 3, + OP_GP1_MUL = 4, + OP_GP1_IMUL = 5, + OP_GP1_DIV = 6, + OP_GP1_IDIV = 7, + + OP_GP2_INC = 0, + OP_GP2_DEC = 1, + OP_GP2_CALL1 = 2, + OP_GP2_CALL2 = 3, + OP_GP2_JMP1 = 4, + OP_GP2_JMP2 = 5, + OP_GP2_PUSH = 6, +}; + +typedef enum modrmValues +{ + MR_BX_SI = 0, /**< [BX + SI] */ + MR_BX_DI, /**< [BX + DI] */ + MR_BP_SI, /**< [BP + SI] */ + MR_BP_DI, /**< [BP + DI] */ + MR_SI, /**< [SI] */ + MR_DI, /**< [DI] */ + MR_DISP16, /**< disp16 */ + MR_BX, /**< [BX] */ + MR_BX_SI_D8, /**< [BX + SI] + disp8 */ + MR_BX_DI_D8, /**< [BX + DI] + disp8 */ + MR_BP_SI_D8, /**< [BP + SI] + disp8 */ + MR_BP_DI_D8, /**< [BP + DI] + disp8 */ + MR_SI_D8, /**< [SI] + disp8 */ + MR_DI_D8, /**< [DI] + disp8 */ + MR_BP_D8, /**< [BX] + disp8 */ + MR_BX_D8, /**< [BP] + disp8 */ + MR_BX_SI_D16, /**< [BX + SI] + disp16 */ + MR_BX_DI_D16, /**< [BX + DI] + disp16 */ + MR_BP_SI_D16, /**< [BP + SI] + disp16 */ + MR_BP_DI_D16, /**< [BP + DI] + disp16 */ + MR_SI_D16, /**< [SI] + disp16 */ + MR_DI_D16, /**< [DI] + disp16 */ + MR_BP_D16, /**< [BX] + disp16 */ + MR_BX_D16, /**< [Bp] + disp16 */ + MR_AX_AL, /**< AX or AL */ + MR_CX_CL, /**< CX or CL */ + MR_DX_DL, /**< DX or DL */ + MR_BX_BL, /**< BC or BL */ + MR_SP_AH, /**< SP or AH */ + MR_BP_CH, /**< BP or CH */ + MR_SI_DH, /**< SI or DH */ + MR_DI_BH, /**< DI or BH */ +} modrmValues; + +const char *modrmReg8List[8] = { "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh" }; +const char *modrmReg16List[8] = { "ax", "cx", "dx", "bx", "sp", "bp", "si", "di" }; +const char *segmentRegList[4] = { "ds", "cs", "ss", "es" }; +static inline void get_mod_reg_rm(uint8_t value, uint8_t *mod, uint8_t *reg, uint8_t *rm, uint8_t *modrm) +{ + if (mod) + { + *mod = (value >> 6) & 0x3; + } + if (reg) + { + *reg = (value >> 3) & 0x7; + } + if (rm) + { + *rm = (value) & 0x7; + } + if (modrm) + { + *modrm = (value) & 0x7; + *modrm = ((value & 0xC0) >> 3) | (*modrm); + } +} + +#define MAKE_LINEAR(_seg, _off) ( ((_seg) << 4) + (_off) ) + +static int decode_modrm(uint16_t segment, uint16_t offset, modrmValues modrm, bool is8bit, char *buffer, uint32_t bufferLength) +{ + uint8_t disp8 = cpu_readmem20(MAKE_LINEAR(segment, offset)); + uint16_t disp16 = (cpu_readmem20(MAKE_LINEAR(segment, offset + 1)) << 8) | disp8; + char buf[63]; + int offsetReturn = 0; + + switch (modrm) + { + case MR_BX_SI: + snprintf(buf, 63, " %s [bx + si]", is8bit?"byte":"word"); + strncat(buffer, buf, bufferLength); + break; + + case MR_BX_DI: + snprintf(buf, 63, " %s [bx + di]", is8bit?"byte":"word"); + strncat(buffer, buf, bufferLength); + break; + + case MR_BP_SI: + snprintf(buf, 63, " %s [bp + si]", is8bit?"byte":"word"); + strncat(buffer, buf, bufferLength); + break; + + case MR_BP_DI: + snprintf(buf, 63, " %s [bx + di]", is8bit?"byte":"word"); + strncat(buffer, buf, bufferLength); + break; + + case MR_SI: + snprintf(buf, 63, " %s [si]", is8bit?"byte":"word"); + strncat(buffer, buf, bufferLength); + break; + + case MR_DI: + snprintf(buf, 63, " %s [di]", is8bit?"byte":"word"); + strncat(buffer, buf, bufferLength); + break; + + case MR_DISP16: + snprintf(buf, 63, " %s [0%Xh]", is8bit?"byte":"word", disp16); + strncat(buffer, buf, bufferLength); + offsetReturn = 2; + break; + + case MR_BX: + snprintf(buf, 63, " %s [bx]", is8bit?"byte":"word"); + strncat(buffer, buf, bufferLength); + break; + + case MR_BX_SI_D8: + snprintf(buf, 63, " %s [bx + si] + 0%Xh", is8bit?"byte":"word", disp8); + strncat(buffer, buf, bufferLength); + offsetReturn = 1; + break; + + case MR_BX_DI_D8: + snprintf(buf, 63, " %s [bx + di] + 0%Xh", is8bit?"byte":"word", disp8); + strncat(buffer, buf, bufferLength); + offsetReturn = 1; + break; + + case MR_BP_SI_D8: + snprintf(buf, 63, " %s [bp + si] + 0%Xh", is8bit?"byte":"word", disp8); + strncat(buffer, buf, bufferLength); + offsetReturn = 1; + break; + + case MR_BP_DI_D8: + snprintf(buf, 63, " %s [bp + di] + 0%Xh", is8bit?"byte":"word", disp8); + strncat(buffer, buf, bufferLength); + offsetReturn = 1; + break; + + case MR_SI_D8: + snprintf(buf, 63, " %s [si] + 0%Xh", is8bit?"byte":"word", disp8); + strncat(buffer, buf, bufferLength); + offsetReturn = 1; + break; + + case MR_DI_D8: + snprintf(buf, 63, " %s [di] + 0%Xh", is8bit?"byte":"word", disp8); + strncat(buffer, buf, bufferLength); + offsetReturn = 1; + break; + + case MR_BP_D8: + snprintf(buf, 63, " %s [bp] + 0%Xh", is8bit?"byte":"word", disp8); + strncat(buffer, buf, bufferLength); + offsetReturn = 1; + break; + + case MR_BX_D8: + snprintf(buf, 63, " %s [bx] + 0%Xh", is8bit?"byte":"word", disp8); + strncat(buffer, buf, bufferLength); + offsetReturn = 1; + break; + + case MR_BX_SI_D16: + snprintf(buf, 63, " %s [bx + si] + 0%Xh", is8bit?"byte":"word", disp16); + strncat(buffer, buf, bufferLength); + offsetReturn = 2; + break; + + case MR_BX_DI_D16: + snprintf(buf, 63, " %s [bx + di] + 0%Xh", is8bit?"byte":"word", disp16); + strncat(buffer, buf, bufferLength); + offsetReturn = 2; + break; + + case MR_BP_SI_D16: + snprintf(buf, 63, " %s [bp + si] + 0%Xh", is8bit?"byte":"word", disp16); + strncat(buffer, buf, bufferLength); + offsetReturn = 2; + break; + + case MR_BP_DI_D16: + snprintf(buf, 63, " %s [bp + di] + 0%Xh", is8bit?"byte":"word", disp16); + strncat(buffer, buf, bufferLength); + offsetReturn = 2; + break; + + case MR_SI_D16: + snprintf(buf, 63, " %s [si] + 0%Xh", is8bit?"byte":"word", disp16); + strncat(buffer, buf, bufferLength); + offsetReturn = 2; + break; + + case MR_DI_D16: + snprintf(buf, 63, " %s [di] + 0%Xh", is8bit?"byte":"word", disp16); + strncat(buffer, buf, bufferLength); + offsetReturn = 2; + break; + + case MR_BP_D16: + snprintf(buf, 63, " %s [bp] + 0%Xh", is8bit?"byte":"word", disp16); + strncat(buffer, buf, bufferLength); + offsetReturn = 2; + break; + + case MR_BX_D16: + snprintf(buf, 63, " %s [bx] + 0%Xh", is8bit?"byte":"word", disp16); + strncat(buffer, buf, bufferLength); + offsetReturn = 2; + break; + + case MR_AX_AL: + snprintf(buf, 63, " %s", is8bit?"al":"ax"); + strncat(buffer, buf, bufferLength); + break; + + case MR_CX_CL: + snprintf(buf, 63, " %s", is8bit?"cl":"cx"); + strncat(buffer, buf, bufferLength); + break; + + case MR_DX_DL: + snprintf(buf, 63, " %s", is8bit?"dl":"dx"); + strncat(buffer, buf, bufferLength); + break; + + case MR_BX_BL: + snprintf(buf, 63, " %s", is8bit?"bl":"bx"); + strncat(buffer, buf, bufferLength); + break; + + case MR_SP_AH: + snprintf(buf, 63, " %s", is8bit?"ah":"sp"); + strncat(buffer, buf, bufferLength); + break; + + case MR_BP_CH: + snprintf(buf, 63, " %s", is8bit?"ch":"bp"); + strncat(buffer, buf, bufferLength); + break; + + case MR_SI_DH: + snprintf(buf, 63, " %s", is8bit?"dh":"si"); + strncat(buffer, buf, bufferLength); + break; + + case MR_DI_BH: + snprintf(buf, 63, " %s", is8bit?"bh":"di"); + strncat(buffer, buf, bufferLength); + break; + } + + return offsetReturn; +} + + +int nec_decode_instruction(uint16_t segment, uint16_t offset, char *buffer, unsigned int bufferSize) +{ + uint8_t opcode = cpu_readmem20(MAKE_LINEAR(segment, offset)); + uint16_t currentOffset = offset; + int16_t param1, param2; + uint8_t modrm, reg; + + char buf[64]; + + bool isPrefix = false; + operandTypes opcodeType = opcodeTypeTable[opcode]; + const char *opcodeName = operandTypeNameTable[opcodeType]; + operandParameterTypes opcodeParams = opcodeParamTypeTable[opcode]; + + currentOffset++; + + switch(opcodeType) + { + /* Need to handle opcode group */ + case OP_IMMED: + param1 = cpu_readmem20(MAKE_LINEAR(segment, offset + 1)); + get_mod_reg_rm(param1, NULL, ®, NULL, NULL); + switch (reg) + { + case OP_IMD_ADD: + strncat(buffer, "add", bufferSize); + break; + + case OP_IMD_OR: + /* This is not available in B2 and B3 */ + if (opcode > 0xB1) + { + strncat(buffer, "illegal", bufferSize); + opcodeParams = PR_NONE; + currentOffset++; + } + else + { + strncat(buffer, "or", bufferSize); + } + break; + + case OP_IMD_ADC: + strncat(buffer, "adc", bufferSize); + break; + + case OP_IMD_SBB: + strncat(buffer, "sbb", bufferSize); + break; + + case OP_IMD_AND: + /* This is not available in B2 and B3 */ + if (opcode > 0xB1) + { + strncat(buffer, "illegal", bufferSize); + opcodeParams = PR_NONE; + currentOffset++; + } + else + { + strncat(buffer, "and", bufferSize); + } + break; + + case OP_IMD_SUB: + strncat(buffer, "sub", bufferSize); + break; + + case OP_IMD_XOR: + /* This is not available in B2 and B3 */ + if (opcode > 0xB1) + { + strncat(buffer, "illegal", bufferSize); + opcodeParams = PR_NONE; + currentOffset++; + } + else + { + strncat(buffer, "xor", bufferSize); + } + break; + + case OP_IMD_CMP: + strncat(buffer, "cmp", bufferSize); + break; + } + break; + + case OP_SHIFT: + param1 = cpu_readmem20(MAKE_LINEAR(segment, offset + 1)); + get_mod_reg_rm(param1, NULL, ®, NULL, NULL); + switch (reg) + { + case OP_SFT_ROL: + strncat(buffer, "rol", bufferSize); + break; + case OP_SFT_ROR: + strncat(buffer, "ror", bufferSize); + break; + case OP_SFT_RCL: + strncat(buffer, "rcl", bufferSize); + break; + case OP_SFT_RCR: + strncat(buffer, "rcr", bufferSize); + break; + case OP_SFT_SHL: + strncat(buffer, "shl", bufferSize); + break; + case OP_SFT_SHR: + strncat(buffer, "shr", bufferSize); + break; + case OP_SFT_SAR: + strncat(buffer, "sar", bufferSize); + break; + + default: + strncat(buffer, "illegal", bufferSize); + opcodeParams = PR_NONE; + currentOffset++; + break; + } + break; + + case OP_GRP1: + param1 = cpu_readmem20(MAKE_LINEAR(segment, offset + 1)); + get_mod_reg_rm(param1, NULL, ®, NULL, NULL); + switch (reg) + { + case OP_GP1_TEST: + strncat(buffer, "test", bufferSize); + /* Special case, test is IM_I not just IM */ + if (opcodeParams == PR_RM8) + { + opcodeParams = PR_RM_IM8; + } + else + { + opcodeParams = PR_RM_IM16; + } + break; + + case OP_GP1_NOT: + strncat(buffer, "not", bufferSize); + break; + case OP_GP1_NEG: + strncat(buffer, "neg", bufferSize); + break; + case OP_GP1_MUL: + strncat(buffer, "mul", bufferSize); + break; + case OP_GP1_IMUL: + strncat(buffer, "imul", bufferSize); + break; + case OP_GP1_DIV: + strncat(buffer, "div", bufferSize); + break; + case OP_GP1_IDIV: + strncat(buffer, "idiv", bufferSize); + break; + + default: + strncat(buffer, "illegal", bufferSize); + opcodeParams = PR_NONE; + currentOffset++; + break; + } + break; + + case OP_GRP2: + param1 = cpu_readmem20(MAKE_LINEAR(segment, offset + 1)); + get_mod_reg_rm(param1, NULL, ®, NULL, NULL); + switch (reg) + { + case OP_GP2_INC: + strncat(buffer, "inc", bufferSize); + break; + case OP_GP2_DEC: + strncat(buffer, "dec", bufferSize); + break; + case OP_GP2_CALL1: + if (opcode == 0xFF) + { + // TODO: Understand this opcode + strncat(buffer, "call", bufferSize); + } + else + { + strncat(buffer, "illegal", bufferSize); + opcodeParams = PR_NONE; + } + break; + case OP_GP2_CALL2: + if (opcode == 0xFF) + { + // TODO: Understand this opcode + strncat(buffer, "call", bufferSize); + } + else + { + strncat(buffer, "illegal", bufferSize); + opcodeParams = PR_NONE; + } + break; + case OP_GP2_JMP1: + if (opcode == 0xFF) + { + // TODO: Understand this opcode + strncat(buffer, "jmp", bufferSize); + } + else + { + strncat(buffer, "illegal", bufferSize); + opcodeParams = PR_NONE; + } + break; + case OP_GP2_JMP2: + if (opcode == 0xFF) + { + // TODO: Understand this opcode + strncat(buffer, "jmp", bufferSize); + } + else + { + strncat(buffer, "illegal", bufferSize); + opcodeParams = PR_NONE; + } + break; + case OP_GP2_PUSH: + if (opcode == 0xFF) + { + strncat(buffer, "push", bufferSize); + } + else + { + strncat(buffer, "illegal", bufferSize); + opcodeParams = PR_NONE; + } + break; + + default: + strncat(buffer, "illegal", bufferSize); + opcodeParams = PR_NONE; + currentOffset++; + break; + } + break; + + case OP_MOVG: + /* Special case for C6 and C7, they are valid ONLY if reg == 0 */ + param1 = cpu_readmem20(MAKE_LINEAR(segment, offset + 1)); + get_mod_reg_rm(param1, NULL, ®, NULL, NULL); + if (reg > 0) + { + strncat(buffer, "illegal", bufferSize); + opcodeParams = PR_NONE; + currentOffset++; + } + else + { + strncat(buffer, "mov", bufferSize); + } + + default: + strncat(buffer, opcodeName, bufferSize); + break; + } + + switch(opcodeParams) + { + /******************************************************************************************************************* + *********************************************** Trivials parameters *********************************************** + ******************************************************************************************************************/ + + /*----------------------------- Prefix have nothing to display, but need to be known -----------------------------*/ + case PR_PREFIX: isPrefix = true; break; + + /*---------------------------------------------- Nothing to display ----------------------------------------------*/ + case PR_NONE: break; + + /*------------------------------------------------ Only registers ------------------------------------------------*/ + case PR_AX: strncat(buffer, " ax", bufferSize); break; + case PR_BX: strncat(buffer, " bx", bufferSize); break; + case PR_CX: strncat(buffer, " cx", bufferSize); break; + case PR_DX: strncat(buffer, " dx", bufferSize); break; + case PR_SI: strncat(buffer, " si", bufferSize); break; + case PR_DI: strncat(buffer, " di", bufferSize); break; + case PR_BP: strncat(buffer, " bp", bufferSize); break; + case PR_SP: strncat(buffer, " sp", bufferSize); break; + case PR_SS: strncat(buffer, " ss", bufferSize); break; + case PR_DS: strncat(buffer, " ds", bufferSize); break; + case PR_ES: strncat(buffer, " es", bufferSize); break; + case PR_CS: strncat(buffer, " cs", bufferSize); break; + case PR_AX_CX: strncat(buffer, " ax, cx", bufferSize); break; + case PR_AX_DX: strncat(buffer, " ax, dx", bufferSize); break; + case PR_AX_BX: strncat(buffer, " ax, bx", bufferSize); break; + case PR_AX_BP: strncat(buffer, " ax, bp", bufferSize); break; + case PR_AX_SI: strncat(buffer, " ax, si", bufferSize); break; + case PR_AX_DI: strncat(buffer, " ax, di", bufferSize); break; + case PR_AX_SP: strncat(buffer, " ax, sp", bufferSize); break; + case PR_AL_DX: strncat(buffer, " al, dx", bufferSize); break; + case PR_DX_AL: strncat(buffer, " dx, al", bufferSize); break; + case PR_DX_AX: strncat(buffer, " dx, ax", bufferSize); break; + + /*------------------------------- opcode name alteration to match their specifics --------------------------------*/ + case PR_NONE8: strncat(buffer, "b", bufferSize); break; /* working on byte */ + case PR_NONE16: strncat(buffer, "w", bufferSize); break; /* working on word */ + case PR_NONEFAR: strncat(buffer, "f", bufferSize); break; /* far pointer related */ + + /******************************************************************************************************************* + ********************************************** Somewhat simple cases ********************************************** + ******************************************************************************************************************/ + + /******* Immediate values *******/ + case PR_IM8: + param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + snprintf(buf, 63, " 0%Xh", param1 & 0xFF); + strncat(buffer, buf, bufferSize); + currentOffset++; + break; + + case PR_IM16: + param1 = (cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 1)) << 8) | + cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + snprintf(buf, 63, " 0%Xh", param1 & 0xFF); + strncat(buffer, buf, bufferSize); + currentOffset += 2; + break; + + /******* Register / Immediate *******/ + case PR_AL_IM8: + param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + snprintf(buf, 63, " al, 0%Xh", param1 & 0xFF); + strncat(buffer, buf, bufferSize); + currentOffset++; + break; + + case PR_AH_IM8: + param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + snprintf(buf, 63, " ah, 0%Xh", param1 & 0xFF); + strncat(buffer, buf, bufferSize); + currentOffset++; + break; + + case PR_AX_IM8: + param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + snprintf(buf, 63, " ax, 0%Xh", param1 & 0xFF); + strncat(buffer, buf, bufferSize); + currentOffset++; + break; + + case PR_AX_IM16: + param1 = (cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 1)) << 8) | + cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + snprintf(buf, 63, " ax, 0%Xh", param1 & 0xFF); + strncat(buffer, buf, bufferSize); + currentOffset += 2; + break; + + case PR_IM8_AL: + param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + snprintf(buf, 63, " 0%Xh, al", param1 & 0xFF); + strncat(buffer, buf, bufferSize); + currentOffset++; + break; + + case PR_IM8_AX: + param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + snprintf(buf, 63, " 0%Xh, ax", param1 & 0xFF); + strncat(buffer, buf, bufferSize); + currentOffset++; + break; + + case PR_BL_IM8: + param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + snprintf(buf, 63, " bl, 0%Xh", param1 & 0xFF); + strncat(buffer, buf, bufferSize); + currentOffset++; + break; + + case PR_BH_IM8: + param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + snprintf(buf, 63, " bh, 0%Xh", param1 & 0xFF); + strncat(buffer, buf, bufferSize); + currentOffset++; + break; + + case PR_BX_IM16: + param1 = (cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 1)) << 8) | + cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + snprintf(buf, 63, " bx, 0%Xh", param1 & 0xFF); + strncat(buffer, buf, bufferSize); + currentOffset += 2; + break; + + case PR_CL_IM8: + param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + snprintf(buf, 63, " cl, 0%Xh", param1 & 0xFF); + strncat(buffer, buf, bufferSize); + currentOffset++; + break; + + case PR_CH_IM8: + param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + snprintf(buf, 63, " ch, 0%Xh", param1 & 0xFF); + strncat(buffer, buf, bufferSize); + currentOffset++; + break; + + case PR_CX_IM16: + param1 = (cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 1)) << 8) | + cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + snprintf(buf, 63, " cx, 0%Xh", param1 & 0xFF); + strncat(buffer, buf, bufferSize); + currentOffset += 2; + break; + + case PR_DL_IM8: + param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + snprintf(buf, 63, " dl, 0%Xh", param1 & 0xFF); + strncat(buffer, buf, bufferSize); + currentOffset++; + break; + + case PR_DH_IM8: + param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + snprintf(buf, 63, " dh, 0%Xh", param1 & 0xFF); + strncat(buffer, buf, bufferSize); + currentOffset++; + break; + + case PR_DX_IM16: + param1 = (cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 1)) << 8) | + cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + snprintf(buf, 63, " dx, 0%Xh", param1 & 0xFF); + strncat(buffer, buf, bufferSize); + currentOffset += 2; + break; + + case PR_SP_IM16: + param1 = (cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 1)) << 8) | + cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + snprintf(buf, 63, " sp, 0%Xh", param1 & 0xFF); + strncat(buffer, buf, bufferSize); + currentOffset += 2; + break; + + case PR_BP_IM16: + param1 = (cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 1)) << 8) | + cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + snprintf(buf, 63, " bp, 0%Xh", param1 & 0xFF); + strncat(buffer, buf, bufferSize); + currentOffset += 2; + break; + + case PR_DI_IM16: + param1 = (cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 1)) << 8) | + cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + snprintf(buf, 63, " di, 0%Xh", param1 & 0xFF); + strncat(buffer, buf, bufferSize); + currentOffset += 2; + break; + + case PR_SI_IM16: + param1 = (cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 1)) << 8) | + cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + snprintf(buf, 63, " si, 0%Xh", param1 & 0xFF); + strncat(buffer, buf, bufferSize); + currentOffset += 2; + break; + + /******* Register / Memory *******/ + case PR_M8_AL: + param1 = (cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 1)) << 8) | + cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + /* TODO: If having a list of known label, try to match and display label instead of value */ + snprintf(buf, 63, " byte [0%Xh], al", param1 & 0xFF); + strncat(buffer, buf, bufferSize); + currentOffset += 2; + break; + + case PR_M16_AX: + param1 = (cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 1)) << 8) | + cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + /* TODO: If having a list of known label, try to match and display label instead of value */ + snprintf(buf, 63, " word [0%Xh], ax", param1 & 0xFF); + strncat(buffer, buf, bufferSize); + currentOffset += 2; + break; + + case PR_AL_M8: + param1 = (cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 1)) << 8) | + cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + /* TODO: If having a list of known label, try to match and display label instead of value */ + snprintf(buf, 63, " al, byte [0%Xh]", param1 & 0xFF); + strncat(buffer, buf, bufferSize); + currentOffset += 2; + break; + + case PR_AX_M16: + param1 = (cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 1)) << 8) | + cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + /* TODO: If having a list of known label, try to match and display label instead of value */ + snprintf(buf, 63, " ax, word [0%Xh]", param1 & 0xFF); + strncat(buffer, buf, bufferSize); + currentOffset += 2; + break; + + /******* Address calculation *******/ + case PR_REL8: + param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + currentOffset++; + param1 = currentOffset + (int8_t)param1; + /* TODO: If having a list of known label, try to match and display label instead of value */ + snprintf(buf, 63, " 0%Xh", param1); + strncat(buffer, buf, bufferSize); + + break; + + case PR_REL16: + param1 = (cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 1)) << 8) | + cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + currentOffset += 2; + param1 = currentOffset + (int16_t) param1; + + /* TODO: If having a list of known label, try to match and display label instead of value */ + snprintf(buf, 63, " 0%Xh", param1); + strncat(buffer, buf, bufferSize); + + break; + + case PR_ABS32: + param1 = (cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 1)) << 8) | + cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + param2 = (cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 3)) << 8) | + cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 2)); + /* TODO: If having a list of known label, try to match and display label instead of value */ + snprintf(buf, 63, " 0%Xh:0%Xh", param2, param1); + strncat(buffer, buf, bufferSize); + currentOffset += 4; + break; + + /******* Other cases *******/ + case PR_IM16_IM8: + param1 = (cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 1)) << 8) | + cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + param2 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 2)); + snprintf(buf, 63, " 0%Xh:0%Xh", param1, param2); + strncat(buffer, buf, bufferSize); + currentOffset += 3; + break; + + /******************************************************************************************************************* + ************************************************ Complicated cases ************************************************ + ******************************************************************************************************************/ + case PR_RM8: + param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + currentOffset++; + get_mod_reg_rm(param1, NULL, NULL, NULL, &modrm); + currentOffset += decode_modrm(segment, currentOffset, modrm, true, buffer, bufferSize); + break; + + case PR_RM16: + param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + currentOffset++; + get_mod_reg_rm(param1, NULL, NULL, NULL, &modrm); + currentOffset += decode_modrm(segment, currentOffset, modrm, false, buffer, bufferSize); + break; + + case PR_RM_IM8: + param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + currentOffset++; + get_mod_reg_rm(param1, NULL, NULL, NULL, &modrm); + currentOffset += decode_modrm(segment, currentOffset, modrm, true, buffer, bufferSize); + param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + currentOffset++; + snprintf(buf, 63, ", 0%Xh", param1); + strncat(buffer, buf, bufferSize); + break; + + case PR_RM16_IM8: + param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + currentOffset++; + get_mod_reg_rm(param1, NULL, NULL, NULL, &modrm); + currentOffset += decode_modrm(segment, currentOffset, modrm, false, buffer, bufferSize); + param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + currentOffset ++; + snprintf(buf, 63, ", 0%Xh", param1 & 0xFF); + strncat(buffer, buf, bufferSize); + break; + + case PR_RM_IM16: + param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + currentOffset++; + get_mod_reg_rm(param1, NULL, NULL, NULL, &modrm); + currentOffset += decode_modrm(segment, currentOffset, modrm, false, buffer, bufferSize); + param1 = (cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 1)) << 8) | + cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + currentOffset += 2; + snprintf(buf, 63, ", 0%Xh", param1); + strncat(buffer, buf, bufferSize); + break; + + case PR_RM8_1: + param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + currentOffset++; + get_mod_reg_rm(param1, NULL, NULL, NULL, &modrm); + currentOffset += decode_modrm(segment, currentOffset, modrm, true, buffer, bufferSize); + strncat(buffer, ", 1", bufferSize); + break; + + case PR_RM16_1: + param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + currentOffset++; + get_mod_reg_rm(param1, NULL, NULL, NULL, &modrm); + currentOffset += decode_modrm(segment, currentOffset, modrm, false, buffer, bufferSize); + strncat(buffer, ", 1", bufferSize); + break; + + case PR_RM8_CL: + param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + currentOffset++; + get_mod_reg_rm(param1, NULL, NULL, NULL, &modrm); + currentOffset += decode_modrm(segment, currentOffset, modrm, true, buffer, bufferSize); + strncat(buffer, ", cl", bufferSize); + break; + + case PR_RM16_CL: + param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + currentOffset++; + get_mod_reg_rm(param1, NULL, NULL, NULL, &modrm); + currentOffset += decode_modrm(segment, currentOffset, modrm, false, buffer, bufferSize); + strncat(buffer, ", cl", bufferSize); + break; + + case PR_RM_R8: + param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + currentOffset++; + get_mod_reg_rm(param1, NULL, ®, NULL, &modrm); + currentOffset += decode_modrm(segment, currentOffset, modrm, true, buffer, bufferSize); + snprintf(buf, 63, ", %s", modrmReg8List[reg]); + strncat(buffer, buf, bufferSize); + break; + + case PR_RM_R16: + param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); + currentOffset++; + get_mod_reg_rm(param1, NULL, ®, NULL, &modrm); + currentOffset += decode_modrm(segment, currentOffset, modrm, false, buffer, bufferSize); + snprintf(buf, 63, ", %s", modrmReg16List[reg]); + strncat(buffer, buf, bufferSize); + break; + + case PR_RM16_SEG: + // TODO: Find how to decode the segment value + break; + + case PR_SEG_RM16: + // TODO: Find how to decode the segment value + break; + + default: + Log(TLOG_ERROR, "debugger", "Unsupported opcode param type: %d for opcode %02X (%s)", opcodeParams, opcode, opcodeName); + break; + } + + if (isPrefix) + { + /* call this function from the next byte */ + strncat(buffer, " ", bufferSize); + nec_decode_instruction(segment, currentOffset, buffer, bufferSize); + } + + return currentOffset - offset; +} diff --git a/source/nec/nec_debugger.h b/source/nec/nec_debugger.h new file mode 100644 index 0000000..f76611f --- /dev/null +++ b/source/nec/nec_debugger.h @@ -0,0 +1,16 @@ +/* + * NewOswan + * nec_debugger.h: + * Based on the original Oswan-unix + * Created by Manoël Trapier on 14/04/2021. + * Copyright (c) 2014-2021 986-Studio. All rights reserved. + * + */ + +#ifndef NEWOSWAN_SOURCE_NEC_NEC_DEBUGGER_H +#define NEWOSWAN_SOURCE_NEC_NEC_DEBUGGER_H + + +int nec_decode_instruction(uint16_t segment, uint16_t offset, char *buffer, unsigned int bufferSize); + +#endif /* NEWOSWAN_SOURCE_NEC_NEC_DEBUGGER_H */