newoswan/source/nec/nec_debugger.c

1249 lines
48 KiB
C

/*
* NewOswan
* nec_debugger.c:
* Created by Manoël Trapier on 14/04/2021.
* Copyright (c) 2014-2021 986-Studio. All rights reserved.
*
*/
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#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, &reg, 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, &reg, 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, &reg, 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, &reg, 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, &reg, 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, &reg, 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, &reg, NULL, &modrm);
currentOffset += decode_modrm(segment, currentOffset, modrm, false, buffer, bufferSize);
snprintf(buf, 63, ", %s", modrmReg16List[reg]);
strncat(buffer, buf, bufferSize);
break;
case PR_R_RM8:
param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
currentOffset++;
get_mod_reg_rm(param1, NULL, &reg, NULL, &modrm);
snprintf(buf, 63, " %s,", modrmReg8List[reg]);
strncat(buffer, buf, bufferSize);
currentOffset += decode_modrm(segment, currentOffset, modrm, true, buffer, bufferSize);
break;
case PR_R_RM16:
param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
currentOffset++;
get_mod_reg_rm(param1, NULL, &reg, NULL, &modrm);
snprintf(buf, 63, " %s,", modrmReg16List[reg]);
strncat(buffer, buf, bufferSize);
currentOffset += decode_modrm(segment, currentOffset, modrm, false, buffer, bufferSize);
break;
case PR_RM16_SEG:
param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
currentOffset++;
get_mod_reg_rm(param1, NULL, &reg, 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, &reg, 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;
}