/* * NewOswan * nec_debugger.c: * 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_CALL = 2, OP_GP2_CALLF = 3, OP_GP2_JMP = 4, OP_GP2_JMPF = 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[8] = { "es", "cs", "ss", "ds", "ILLEGAL", "ILLEGAL", "ILLEGAL", "ILLEGAL" }; 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_CALL: if (opcode == 0xFF) { strncat(buffer, "call", bufferSize); } else { strncat(buffer, "illegal", bufferSize); opcodeParams = PR_NONE; } break; case OP_GP2_CALLF: if (opcode == 0xFF) { strncat(buffer, "call far", bufferSize); } else { strncat(buffer, "illegal", bufferSize); opcodeParams = PR_NONE; } break; case OP_GP2_JMP: if (opcode == 0xFF) { strncat(buffer, "jmp", bufferSize); } else { strncat(buffer, "illegal", bufferSize); opcodeParams = PR_NONE; } break; case OP_GP2_JMPF: if (opcode == 0xFF) { strncat(buffer, "jmp far", 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: 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); param1 = (cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 1)) << 8) | cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); currentOffset += 2; snprintf(buf, 63, ", %s", segmentRegList[reg]); strncat(buffer, buf, bufferSize); break; case PR_SEG_RM16: param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset)); currentOffset++; get_mod_reg_rm(param1, NULL, ®, NULL, &modrm); snprintf(buf, 63, ", %s", segmentRegList[reg]); 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; strncat(buffer, buf, bufferSize); 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; }