/* Copyright (c) 2013-2017 Jeffrey Pfau * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include #include #include typedef size_t (*SM83Decoder)(uint8_t opcode, struct SM83InstructionInfo* info); #define DEFINE_DECODER_SM83(NAME, BODY) \ static size_t _SM83Decode ## NAME (uint8_t opcode, struct SM83InstructionInfo* info) { \ UNUSED(opcode); \ info->mnemonic = SM83_MN_RST; \ BODY; \ return 0; \ } DEFINE_DECODER_SM83(NOP, info->mnemonic = SM83_MN_NOP;) #define DEFINE_LD_DECODER_SM83_NOHL(NAME) \ DEFINE_DECODER_SM83(LD ## NAME ## _A, \ info->mnemonic = SM83_MN_LD; \ info->op1.reg = SM83_REG_ ## NAME; \ info->op2.reg = SM83_REG_A) \ DEFINE_DECODER_SM83(LD ## NAME ## _B, \ info->mnemonic = SM83_MN_LD; \ info->op1.reg = SM83_REG_ ## NAME; \ info->op2.reg = SM83_REG_B) \ DEFINE_DECODER_SM83(LD ## NAME ## _C, \ info->mnemonic = SM83_MN_LD; \ info->op1.reg = SM83_REG_ ## NAME; \ info->op2.reg = SM83_REG_C) \ DEFINE_DECODER_SM83(LD ## NAME ## _D, \ info->mnemonic = SM83_MN_LD; \ info->op1.reg = SM83_REG_ ## NAME; \ info->op2.reg = SM83_REG_D) \ DEFINE_DECODER_SM83(LD ## NAME ## _E, \ info->mnemonic = SM83_MN_LD; \ info->op1.reg = SM83_REG_ ## NAME; \ info->op2.reg = SM83_REG_E) \ DEFINE_DECODER_SM83(LD ## NAME ## _H, \ info->mnemonic = SM83_MN_LD; \ info->op1.reg = SM83_REG_ ## NAME; \ info->op2.reg = SM83_REG_H) \ DEFINE_DECODER_SM83(LD ## NAME ## _L, \ info->mnemonic = SM83_MN_LD; \ info->op1.reg = SM83_REG_ ## NAME; \ info->op2.reg = SM83_REG_L) #define DEFINE_LD_DECODER_SM83_MEM(NAME, REG) \ DEFINE_DECODER_SM83(LD ## NAME ## _ ## REG, info->mnemonic = SM83_MN_LD; \ info->op1.reg = SM83_REG_ ## NAME; \ info->op2.reg = SM83_REG_ ## REG; \ info->op2.flags = SM83_OP_FLAG_MEMORY;) #define DEFINE_LD_DECODER_SM83_MEM_2(NAME, REG) \ DEFINE_DECODER_SM83(LD ## REG ## _ ## NAME, info->mnemonic = SM83_MN_LD; \ info->op1.reg = SM83_REG_ ## REG; \ info->op1.flags = SM83_OP_FLAG_MEMORY; \ info->op2.reg = SM83_REG_ ## NAME;) #define DEFINE_LD_DECODER_SM83(NAME) \ DEFINE_LD_DECODER_SM83_MEM(NAME, HL) \ DEFINE_LD_DECODER_SM83_MEM_2(NAME, HL) \ DEFINE_DECODER_SM83(LD ## NAME ## _, info->mnemonic = SM83_MN_LD; \ info->op1.reg = SM83_REG_ ## NAME; \ return 1;) \ DEFINE_LD_DECODER_SM83_NOHL(NAME) #define DEFINE_LD_2_DECODER_SM83(NAME) \ DEFINE_DECODER_SM83(LD ## NAME, info->mnemonic = SM83_MN_LD; \ info->op1.reg = SM83_REG_ ## NAME; \ return 2;) DEFINE_LD_DECODER_SM83(B); DEFINE_LD_DECODER_SM83(C); DEFINE_LD_DECODER_SM83(D); DEFINE_LD_DECODER_SM83(E); DEFINE_LD_DECODER_SM83(H); DEFINE_LD_DECODER_SM83(L); DEFINE_LD_DECODER_SM83(A); DEFINE_LD_DECODER_SM83_MEM(A, BC); DEFINE_LD_DECODER_SM83_MEM(A, DE); DEFINE_LD_2_DECODER_SM83(BC); DEFINE_LD_2_DECODER_SM83(DE); DEFINE_LD_2_DECODER_SM83(HL); DEFINE_LD_2_DECODER_SM83(SP); DEFINE_DECODER_SM83(LDHL_, \ info->mnemonic = SM83_MN_LD; \ info->op1.reg = SM83_REG_HL; \ info->op1.flags = SM83_OP_FLAG_MEMORY; \ return 1;) DEFINE_DECODER_SM83(LDHL_SP, \ info->mnemonic = SM83_MN_LD; \ info->op1.reg = SM83_REG_HL; \ info->op2.reg = SM83_REG_SP; \ return 1;) DEFINE_DECODER_SM83(LDSP_HL, \ info->mnemonic = SM83_MN_LD; \ info->op1.reg = SM83_REG_SP; \ info->op2.reg = SM83_REG_HL;) DEFINE_DECODER_SM83(LDAIOC, \ info->mnemonic = SM83_MN_LD; \ info->op1.reg = SM83_REG_A; \ info->op2.reg = SM83_REG_C; \ info->op2.immediate = 0xFF00; \ info->op2.flags = SM83_OP_FLAG_MEMORY;) DEFINE_DECODER_SM83(LDIOCA, \ info->mnemonic = SM83_MN_LD; \ info->op1.reg = SM83_REG_C; \ info->op1.immediate = 0xFF00; \ info->op1.flags = SM83_OP_FLAG_MEMORY; \ info->op2.reg = SM83_REG_A;) DEFINE_DECODER_SM83(LDAIO, \ info->mnemonic = SM83_MN_LD; \ info->op1.reg = SM83_REG_A; \ info->op2.immediate = 0xFF00; \ info->op2.flags = SM83_OP_FLAG_MEMORY; \ return 1;) DEFINE_DECODER_SM83(LDIOA, \ info->mnemonic = SM83_MN_LD; \ info->op1.immediate = 0xFF00; \ info->op1.flags = SM83_OP_FLAG_MEMORY; \ info->op2.reg = SM83_REG_A; \ return 1;) #define DEFINE_ALU_DECODER_SM83_NOHL(NAME) \ DEFINE_DECODER_SM83(NAME ## A, info->mnemonic = SM83_MN_ ## NAME; info->op1.reg = SM83_REG_A) \ DEFINE_DECODER_SM83(NAME ## B, info->mnemonic = SM83_MN_ ## NAME; info->op1.reg = SM83_REG_B) \ DEFINE_DECODER_SM83(NAME ## C, info->mnemonic = SM83_MN_ ## NAME; info->op1.reg = SM83_REG_C) \ DEFINE_DECODER_SM83(NAME ## D, info->mnemonic = SM83_MN_ ## NAME; info->op1.reg = SM83_REG_D) \ DEFINE_DECODER_SM83(NAME ## E, info->mnemonic = SM83_MN_ ## NAME; info->op1.reg = SM83_REG_E) \ DEFINE_DECODER_SM83(NAME ## H, info->mnemonic = SM83_MN_ ## NAME; info->op1.reg = SM83_REG_H) \ DEFINE_DECODER_SM83(NAME ## L, info->mnemonic = SM83_MN_ ## NAME; info->op1.reg = SM83_REG_L) #define DEFINE_ALU_DECODER_SM83_MEM(NAME, REG) \ DEFINE_DECODER_SM83(NAME ## REG, info->mnemonic = SM83_MN_ ## NAME; \ info->op1.reg = SM83_REG_HL; \ info->op1.flags = SM83_OP_FLAG_MEMORY;) #define DEFINE_ALU_DECODER_SM83(NAME) \ DEFINE_ALU_DECODER_SM83_MEM(NAME, HL) \ DEFINE_DECODER_SM83(NAME, info->mnemonic = SM83_MN_ ## NAME; \ info->op1.reg = SM83_REG_A; \ info->op1.flags = SM83_OP_FLAG_IMPLICIT; \ return 1;) \ DEFINE_ALU_DECODER_SM83_NOHL(NAME) DEFINE_ALU_DECODER_SM83_NOHL(INC); DEFINE_ALU_DECODER_SM83_NOHL(DEC); DEFINE_ALU_DECODER_SM83(AND); DEFINE_ALU_DECODER_SM83(XOR); DEFINE_ALU_DECODER_SM83(OR); DEFINE_ALU_DECODER_SM83(CP); DEFINE_ALU_DECODER_SM83(ADD); DEFINE_ALU_DECODER_SM83(ADC); DEFINE_ALU_DECODER_SM83(SUB); DEFINE_ALU_DECODER_SM83(SBC); #define DEFINE_ALU_DECODER_SM83_ADD_HL(REG) \ DEFINE_DECODER_SM83(ADDHL_ ## REG, info->mnemonic = SM83_MN_ADD; \ info->op1.reg = SM83_REG_HL; \ info->op2.reg = SM83_REG_ ## REG;) DEFINE_ALU_DECODER_SM83_ADD_HL(BC) DEFINE_ALU_DECODER_SM83_ADD_HL(DE) DEFINE_ALU_DECODER_SM83_ADD_HL(HL) DEFINE_ALU_DECODER_SM83_ADD_HL(SP) DEFINE_DECODER_SM83(ADDSP, info->mnemonic = SM83_MN_ADD; \ info->op1.reg = SM83_REG_SP; \ return 1;) #define DEFINE_CONDITIONAL_DECODER_SM83(NAME) \ DEFINE_ ## NAME ## _INSTRUCTION_SM83(, 0) \ DEFINE_ ## NAME ## _INSTRUCTION_SM83(C, SM83_COND_C) \ DEFINE_ ## NAME ## _INSTRUCTION_SM83(Z, SM83_COND_Z) \ DEFINE_ ## NAME ## _INSTRUCTION_SM83(NC, SM83_COND_NC) \ DEFINE_ ## NAME ## _INSTRUCTION_SM83(NZ, SM83_COND_NZ) #define DEFINE_JP_INSTRUCTION_SM83(CONDITION_NAME, CONDITION) \ DEFINE_DECODER_SM83(JP ## CONDITION_NAME, \ info->mnemonic = SM83_MN_JP; \ info->condition = CONDITION; \ return 2;) #define DEFINE_JR_INSTRUCTION_SM83(CONDITION_NAME, CONDITION) \ DEFINE_DECODER_SM83(JR ## CONDITION_NAME, \ info->mnemonic = SM83_MN_JR; \ info->condition = CONDITION; \ info->op1.flags = SM83_OP_FLAG_RELATIVE; \ return 1;) #define DEFINE_CALL_INSTRUCTION_SM83(CONDITION_NAME, CONDITION) \ DEFINE_DECODER_SM83(CALL ## CONDITION_NAME, \ info->mnemonic = SM83_MN_CALL; \ info->condition = CONDITION; \ return 2;) #define DEFINE_RET_INSTRUCTION_SM83(CONDITION_NAME, CONDITION) \ DEFINE_DECODER_SM83(RET ## CONDITION_NAME, \ info->mnemonic = SM83_MN_RET; \ info->condition = CONDITION;) DEFINE_CONDITIONAL_DECODER_SM83(JP); DEFINE_CONDITIONAL_DECODER_SM83(JR); DEFINE_CONDITIONAL_DECODER_SM83(CALL); DEFINE_CONDITIONAL_DECODER_SM83(RET); DEFINE_DECODER_SM83(JPHL, \ info->mnemonic = SM83_MN_JP; \ info->op1.reg = SM83_REG_HL) DEFINE_DECODER_SM83(RETI, info->mnemonic = SM83_MN_RETI) DEFINE_DECODER_SM83(LDBC_A, \ info->mnemonic = SM83_MN_LD; \ info->op1.reg = SM83_REG_BC; \ info->op1.flags = SM83_OP_FLAG_MEMORY; \ info->op2.reg = SM83_REG_A;) DEFINE_DECODER_SM83(LDDE_A, \ info->mnemonic = SM83_MN_LD; \ info->op1.reg = SM83_REG_DE; \ info->op1.flags = SM83_OP_FLAG_MEMORY; \ info->op2.reg = SM83_REG_A;) DEFINE_DECODER_SM83(LDIA, \ info->mnemonic = SM83_MN_LD; \ info->op1.flags = SM83_OP_FLAG_MEMORY; \ info->op2.reg = SM83_REG_A; \ return 2;) DEFINE_DECODER_SM83(LDAI, \ info->mnemonic = SM83_MN_LD; \ info->op1.reg = SM83_REG_A; \ info->op2.flags = SM83_OP_FLAG_MEMORY; \ return 2;) DEFINE_DECODER_SM83(LDISP, \ info->mnemonic = SM83_MN_LD; \ info->op1.flags = SM83_OP_FLAG_MEMORY; \ info->op2.reg = SM83_REG_SP; \ return 2;) DEFINE_DECODER_SM83(LDIHLA, \ info->mnemonic = SM83_MN_LD; \ info->op1.reg = SM83_REG_HL; \ info->op1.flags = SM83_OP_FLAG_INCREMENT | SM83_OP_FLAG_MEMORY; \ info->op2.reg = SM83_REG_A;) DEFINE_DECODER_SM83(LDDHLA, \ info->mnemonic = SM83_MN_LD; \ info->op1.reg = SM83_REG_HL; \ info->op1.flags = SM83_OP_FLAG_DECREMENT | SM83_OP_FLAG_MEMORY; \ info->op2.reg = SM83_REG_A;) DEFINE_DECODER_SM83(LDA_IHL, \ info->mnemonic = SM83_MN_LD; \ info->op1.reg = SM83_REG_A; \ info->op2.reg = SM83_REG_HL; \ info->op2.flags = SM83_OP_FLAG_INCREMENT | SM83_OP_FLAG_MEMORY;) DEFINE_DECODER_SM83(LDA_DHL, \ info->mnemonic = SM83_MN_LD; \ info->op1.reg = SM83_REG_A; \ info->op2.reg = SM83_REG_HL; \ info->op2.flags = SM83_OP_FLAG_DECREMENT | SM83_OP_FLAG_MEMORY;) #define DEFINE_INCDEC_WIDE_INSTRUCTION_SM83(REG) \ DEFINE_DECODER_SM83(INC ## REG, info->mnemonic = SM83_MN_INC; info->op1.reg = SM83_REG_ ## REG) \ DEFINE_DECODER_SM83(DEC ## REG, info->mnemonic = SM83_MN_DEC; info->op1.reg = SM83_REG_ ## REG) DEFINE_INCDEC_WIDE_INSTRUCTION_SM83(BC); DEFINE_INCDEC_WIDE_INSTRUCTION_SM83(DE); DEFINE_INCDEC_WIDE_INSTRUCTION_SM83(HL); DEFINE_INCDEC_WIDE_INSTRUCTION_SM83(SP); DEFINE_DECODER_SM83(INC_HL, info->mnemonic = SM83_MN_INC; info->op1.reg = SM83_REG_HL; info->op1.flags = SM83_OP_FLAG_MEMORY;) DEFINE_DECODER_SM83(DEC_HL, info->mnemonic = SM83_MN_DEC; info->op1.reg = SM83_REG_HL; info->op1.flags = SM83_OP_FLAG_MEMORY;) DEFINE_DECODER_SM83(SCF, info->mnemonic = SM83_MN_SCF) DEFINE_DECODER_SM83(CCF, info->mnemonic = SM83_MN_CCF) DEFINE_DECODER_SM83(CPL_, info->mnemonic = SM83_MN_CPL) DEFINE_DECODER_SM83(DAA, info->mnemonic = SM83_MN_DAA) #define DEFINE_POPPUSH_DECODER_SM83(REG) \ DEFINE_DECODER_SM83(POP ## REG, \ info->mnemonic = SM83_MN_POP; \ info->op1.reg = SM83_REG_ ## REG;) \ DEFINE_DECODER_SM83(PUSH ## REG, \ info->mnemonic = SM83_MN_PUSH; \ info->op1.reg = SM83_REG_ ## REG;) \ DEFINE_POPPUSH_DECODER_SM83(BC); DEFINE_POPPUSH_DECODER_SM83(DE); DEFINE_POPPUSH_DECODER_SM83(HL); DEFINE_POPPUSH_DECODER_SM83(AF); #define DEFINE_CB_OP_DECODER_SM83(NAME, BODY, OP) \ DEFINE_DECODER_SM83(NAME ## B, info->OP.reg = SM83_REG_B; BODY) \ DEFINE_DECODER_SM83(NAME ## C, info->OP.reg = SM83_REG_C; BODY) \ DEFINE_DECODER_SM83(NAME ## D, info->OP.reg = SM83_REG_D; BODY) \ DEFINE_DECODER_SM83(NAME ## E, info->OP.reg = SM83_REG_E; BODY) \ DEFINE_DECODER_SM83(NAME ## H, info->OP.reg = SM83_REG_H; BODY) \ DEFINE_DECODER_SM83(NAME ## L, info->OP.reg = SM83_REG_L; BODY) \ DEFINE_DECODER_SM83(NAME ## HL, info->OP.reg = SM83_REG_HL; info->OP.flags = SM83_OP_FLAG_MEMORY; BODY) \ DEFINE_DECODER_SM83(NAME ## A, info->OP.reg = SM83_REG_A; BODY) #define DEFINE_CB_2_DECODER_SM83(NAME, BODY) \ DEFINE_CB_OP_DECODER_SM83(NAME, BODY, op2) #define DEFINE_CB_1_DECODER_SM83(NAME, BODY) \ DEFINE_CB_OP_DECODER_SM83(NAME, BODY, op1) #define DEFINE_CB_DECODER_SM83(NAME, BODY) \ DEFINE_CB_2_DECODER_SM83(NAME ## 0, info->op1.immediate = 0; BODY) \ DEFINE_CB_2_DECODER_SM83(NAME ## 1, info->op1.immediate = 1; BODY) \ DEFINE_CB_2_DECODER_SM83(NAME ## 2, info->op1.immediate = 2; BODY) \ DEFINE_CB_2_DECODER_SM83(NAME ## 3, info->op1.immediate = 3; BODY) \ DEFINE_CB_2_DECODER_SM83(NAME ## 4, info->op1.immediate = 4; BODY) \ DEFINE_CB_2_DECODER_SM83(NAME ## 5, info->op1.immediate = 5; BODY) \ DEFINE_CB_2_DECODER_SM83(NAME ## 6, info->op1.immediate = 6; BODY) \ DEFINE_CB_2_DECODER_SM83(NAME ## 7, info->op1.immediate = 7; BODY) DEFINE_CB_DECODER_SM83(BIT, info->mnemonic = SM83_MN_BIT) DEFINE_CB_DECODER_SM83(RES, info->mnemonic = SM83_MN_RES) DEFINE_CB_DECODER_SM83(SET, info->mnemonic = SM83_MN_SET) #define DEFINE_CB_X_DECODER_SM83(NAME) \ DEFINE_CB_1_DECODER_SM83(NAME, info->mnemonic = SM83_MN_ ## NAME) \ DEFINE_DECODER_SM83(NAME ## A_, info->mnemonic = SM83_MN_ ## NAME; \ info->op1.flags = SM83_OP_FLAG_IMPLICIT; \ info->op1.reg = SM83_REG_A;) DEFINE_CB_X_DECODER_SM83(RL) DEFINE_CB_X_DECODER_SM83(RLC) DEFINE_CB_X_DECODER_SM83(RR) DEFINE_CB_X_DECODER_SM83(RRC) DEFINE_CB_1_DECODER_SM83(SLA, info->mnemonic = SM83_MN_SLA) DEFINE_CB_1_DECODER_SM83(SRA, info->mnemonic = SM83_MN_SRA) DEFINE_CB_1_DECODER_SM83(SRL, info->mnemonic = SM83_MN_SRL) DEFINE_CB_1_DECODER_SM83(SWAP, info->mnemonic = SM83_MN_SWAP) DEFINE_DECODER_SM83(DI, info->mnemonic = SM83_MN_DI) DEFINE_DECODER_SM83(EI, info->mnemonic = SM83_MN_EI) DEFINE_DECODER_SM83(HALT, info->mnemonic = SM83_MN_HALT) DEFINE_DECODER_SM83(ILL, info->mnemonic = SM83_MN_ILL) DEFINE_DECODER_SM83(STOP, info->mnemonic = SM83_MN_STOP) #define DEFINE_RST_DECODER_SM83(VEC) \ DEFINE_DECODER_SM83(RST ## VEC, info->op1.immediate = 0x ## VEC;) DEFINE_RST_DECODER_SM83(00); DEFINE_RST_DECODER_SM83(08); DEFINE_RST_DECODER_SM83(10); DEFINE_RST_DECODER_SM83(18); DEFINE_RST_DECODER_SM83(20); DEFINE_RST_DECODER_SM83(28); DEFINE_RST_DECODER_SM83(30); DEFINE_RST_DECODER_SM83(38); DEFINE_DECODER_SM83(CB, return 1) const SM83Decoder _sm83DecoderTable[0x100] = { DECLARE_SM83_EMITTER_BLOCK(_SM83Decode) }; const SM83Decoder _sm83CBDecoderTable[0x100] = { DECLARE_SM83_CB_EMITTER_BLOCK(_SM83Decode) }; size_t SM83Decode(uint8_t opcode, struct SM83InstructionInfo* info) { if (info->opcodeSize == sizeof(info->opcode)) { return 0; } info->opcode[info->opcodeSize] = opcode; SM83Decoder decoder; switch (info->opcodeSize) { case 0: decoder = _sm83DecoderTable[opcode]; break; case 1: if (info->opcode[0] == 0xCB) { decoder = _sm83CBDecoderTable[opcode]; break; } // Fall through case 2: ++info->opcodeSize; if (info->op1.reg) { info->op2.immediate |= opcode << ((info->opcodeSize - 2) * 8); } else { info->op1.immediate |= opcode << ((info->opcodeSize - 2) * 8); } return 0; } ++info->opcodeSize; return decoder(opcode, info); } #define ADVANCE(AMOUNT) \ if (AMOUNT >= blen) { \ buffer[blen - 1] = '\0'; \ return total; \ } \ total += AMOUNT; \ buffer += AMOUNT; \ blen -= AMOUNT; static const char* _sm83Conditions[] = { NULL, "c", "z", "nc", "nz", }; static const char* _sm83Registers[] = { "", "b", "c", "d", "e", "h", "l", "a", "f", "bc", "de", "hl", "af", "sp", "pc", }; static const char* _sm83MnemonicStrings[] = { "--", "adc", "add", "and", "bit", "call", "ccf", "cp", "cpl", "daa", "dec", "di", "ei", "halt", "inc", "jp", "jr", "ld", "nop", "or", "pop", "push", "res", "ret", "reti", "rl", "rlc", "rr", "rrc", "rst", "sbc", "scf", "set", "sla", "sra", "srl", "stop", "sub", "swap", "xor", "ill" }; static int _decodeOperand(struct SM83Operand op, uint16_t pc, char* buffer, int blen) { int total = 0; if (op.flags & SM83_OP_FLAG_IMPLICIT) { return 0; } strlcpy(buffer, " ", blen); ADVANCE(1); if (op.flags & SM83_OP_FLAG_MEMORY) { strlcpy(buffer, "[", blen); ADVANCE(1); } if (op.reg) { int written = snprintf(buffer, blen, "%s", _sm83Registers[op.reg]); ADVANCE(written); } else { int written; if (op.flags & SM83_OP_FLAG_RELATIVE) { written = snprintf(buffer, blen, "$%04X", pc + (int8_t) op.immediate); } else { written = snprintf(buffer, blen, "$%02X", op.immediate); } ADVANCE(written); if (op.reg) { strlcpy(buffer, "+", blen); ADVANCE(1); } } if (op.flags & SM83_OP_FLAG_INCREMENT) { strlcpy(buffer, "+", blen); ADVANCE(1); } if (op.flags & SM83_OP_FLAG_DECREMENT) { strlcpy(buffer, "-", blen); ADVANCE(1); } if (op.flags & SM83_OP_FLAG_MEMORY) { strlcpy(buffer, "]", blen); ADVANCE(1); } return total; } int SM83Disassemble(struct SM83InstructionInfo* info, uint16_t pc, char* buffer, int blen) { const char* mnemonic = _sm83MnemonicStrings[info->mnemonic]; int written; int total = 0; const char* cond = _sm83Conditions[info->condition]; written = snprintf(buffer, blen, "%s", mnemonic); ADVANCE(written); if (cond) { written = snprintf(buffer, blen, " %s", cond); ADVANCE(written); if (info->op1.reg || info->op1.immediate || info->op2.reg || info->op2.immediate) { strlcpy(buffer, ",", blen); ADVANCE(1); } } if (info->op1.reg || info->op1.immediate || info->op2.reg || info->op2.immediate) { written = _decodeOperand(info->op1, pc, buffer, blen); ADVANCE(written); } if (info->op2.reg || (!info->op1.immediate && info->opcodeSize > 1 && info->opcode[0] != 0xCB)) { if (written) { strlcpy(buffer, ",", blen); ADVANCE(1); } written = _decodeOperand(info->op2, pc, buffer, blen); ADVANCE(written); } buffer[blen - 1] = '\0'; return total; }