LR35902: Add disassembler

This commit is contained in:
Jeffrey Pfau 2017-01-05 00:02:12 -08:00
parent 68985d88e9
commit 7fe7749797
4 changed files with 726 additions and 1 deletions

View File

@ -6,6 +6,7 @@ Features:
- Sprite viewer
- Debugging console
- Improved memory viewer
- GB: LR35902/GB-Z80 disassembler
Bugfixes:
- LR35902: Fix core never exiting with certain event patterns
- GB Timer: Improve DIV reset behavior

View File

@ -0,0 +1,111 @@
/* 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/. */
#ifndef LR35902_DECODER_H
#define LR35902_DECODER_H
#include <mgba-util/common.h>
CXX_GUARD_START
enum LR35902Condition {
LR35902_COND_NONE = 0x0,
LR35902_COND_C = 0x1,
LR35902_COND_Z = 0x2,
LR35902_COND_NC = 0x3,
LR35902_COND_NZ = 0x4
};
enum LR35902Mnemonic {
LR35902_MN_ILL = 0,
LR35902_MN_ADC,
LR35902_MN_ADD,
LR35902_MN_AND,
LR35902_MN_BIT,
LR35902_MN_CALL,
LR35902_MN_CCF,
LR35902_MN_CP,
LR35902_MN_CPL,
LR35902_MN_DAA,
LR35902_MN_DEC,
LR35902_MN_DI,
LR35902_MN_EI,
LR35902_MN_HALT,
LR35902_MN_INC,
LR35902_MN_JP,
LR35902_MN_JR,
LR35902_MN_LD,
LR35902_MN_NOP,
LR35902_MN_OR,
LR35902_MN_POP,
LR35902_MN_PUSH,
LR35902_MN_RES,
LR35902_MN_RET,
LR35902_MN_RETI,
LR35902_MN_RL,
LR35902_MN_RLC,
LR35902_MN_RR,
LR35902_MN_RRC,
LR35902_MN_RST,
LR35902_MN_SBC,
LR35902_MN_SCF,
LR35902_MN_SET,
LR35902_MN_SLA,
LR35902_MN_SRA,
LR35902_MN_SRL,
LR35902_MN_STOP,
LR35902_MN_SUB,
LR35902_MN_SWAP,
LR35902_MN_XOR,
LR35902_MN_MAX
};
enum LR35902Register {
LR35902_REG_B = 1,
LR35902_REG_C,
LR35902_REG_D,
LR35902_REG_E,
LR35902_REG_H,
LR35902_REG_L,
LR35902_REG_A,
LR35902_REG_F,
LR35902_REG_BC,
LR35902_REG_DE,
LR35902_REG_HL,
LR35902_REG_AF,
LR35902_REG_SP,
LR35902_REG_PC
};
enum {
LR35902_OP_FLAG_IMPLICIT = 1,
LR35902_OP_FLAG_MEMORY = 2,
LR35902_OP_FLAG_INCREMENT = 4,
LR35902_OP_FLAG_DECREMENT = 8,
};
struct LR35902Operand {
uint8_t reg;
uint8_t flags;
uint16_t immediate;
};
struct LR35902InstructionInfo {
uint8_t opcode[3];
uint8_t opcodeSize;
struct LR35902Operand op1;
struct LR35902Operand op2;
unsigned mnemonic;
unsigned condition;
};
size_t LR35902Decode(uint8_t opcode, struct LR35902InstructionInfo* info);
int LR35902Disassemble(struct LR35902InstructionInfo* info, char* buffer, int blen);
CXX_GUARD_END
#endif

View File

@ -7,10 +7,14 @@
#include <mgba/core/core.h>
#include <mgba/internal/debugger/cli-debugger.h>
#include <mgba/internal/lr35902/decoder.h>
#include <mgba/internal/lr35902/lr35902.h>
static void _printStatus(struct CLIDebuggerSystem*);
static void _disassemble(struct CLIDebuggerSystem* debugger, struct CLIDebugVector* dv);
static uint32_t _printLine(struct CLIDebugger* debugger, uint16_t address, int segment);
static struct CLIDebuggerCommandSummary _lr35902Commands[] = {
{ 0, 0, 0, 0 }
};
@ -23,6 +27,51 @@ static inline void _printFlags(struct CLIDebuggerBackend* be, union FlagRegister
f.c ? 'C' : '-');
}
static void _disassemble(struct CLIDebuggerSystem* debugger, struct CLIDebugVector* dv) {
struct LR35902Core* cpu = debugger->p->d.core->cpu;
uint16_t address;
size_t size;
if (!dv || dv->type != CLIDV_INT_TYPE) {
address = cpu->pc;
} else {
address = dv->intValue;
dv = dv->next;
}
if (!dv || dv->type != CLIDV_INT_TYPE) {
size = 1;
} else {
size = dv->intValue;
dv = dv->next; // TODO: Check for excess args
}
size_t i;
for (i = 0; i < size; ++i) {
address += _printLine(debugger->p, address, -1);
}
}
static inline uint32_t _printLine(struct CLIDebugger* debugger, uint16_t address, int segment) {
struct CLIDebuggerBackend* be = debugger->backend;
struct LR35902InstructionInfo info = {};
char disassembly[48];
char* disPtr = disassembly;
uint8_t instruction;
size_t bytesRemaining = 1;
for (bytesRemaining = 1; bytesRemaining; --bytesRemaining) {
instruction = debugger->d.core->rawRead8(debugger->d.core, address, segment);
disPtr += snprintf(disPtr, sizeof(disassembly) - (disPtr - disassembly), "%02X", instruction);
++address;
bytesRemaining += LR35902Decode(instruction, &info);
};
disPtr[0] = '\t';
++disPtr;
LR35902Disassemble(&info, disPtr, sizeof(disassembly) - (disPtr - disassembly));
be->printf(be, "%s\n", disassembly);
return address;
}
static void _printStatus(struct CLIDebuggerSystem* debugger) {
struct CLIDebuggerBackend* be = debugger->p->backend;
struct LR35902Core* cpu = debugger->p->d.core->cpu;
@ -32,6 +81,7 @@ static void _printStatus(struct CLIDebuggerSystem* debugger) {
be->printf(be, "H: %02X L: %02X (HL: %04X)\n", cpu->h, cpu->l, cpu->hl);
be->printf(be, "PC: %04X SP: %04X\n", cpu->pc, cpu->sp);
_printFlags(be, cpu->f);
_printLine(debugger->p, cpu->pc, -1);
}
static uint32_t _lookupPlatformIdentifier(struct CLIDebuggerSystem* debugger, const char* name, struct CLIDebugVector* dv) {
@ -84,7 +134,7 @@ static uint32_t _lookupPlatformIdentifier(struct CLIDebuggerSystem* debugger, co
void LR35902CLIDebuggerCreate(struct CLIDebuggerSystem* debugger) {
debugger->printStatus = _printStatus;
debugger->disassemble = NULL;
debugger->disassemble = _disassemble;
debugger->lookupPlatformIdentifier = _lookupPlatformIdentifier;
debugger->platformName = "GB-Z80";
debugger->platformCommands = _lr35902Commands;

563
src/lr35902/decoder.c Normal file
View File

@ -0,0 +1,563 @@
/* 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 <mgba/internal/lr35902/decoder.h>
#include <mgba/internal/lr35902/emitter-lr35902.h>
#include <mgba/internal/lr35902/lr35902.h>
typedef size_t (*LR35902Decoder)(uint8_t opcode, struct LR35902InstructionInfo* info);
#define DEFINE_DECODER_LR35902(NAME, BODY) \
static size_t _LR35902Decode ## NAME (uint8_t opcode, struct LR35902InstructionInfo* info) { \
UNUSED(opcode); \
info->mnemonic = LR35902_MN_RST; \
BODY; \
return 0; \
}
DEFINE_DECODER_LR35902(NOP, info->mnemonic = LR35902_MN_NOP;)
#define DEFINE_LD_DECODER_LR35902_NOHL(NAME) \
DEFINE_DECODER_LR35902(LD ## NAME ## _A, \
info->mnemonic = LR35902_MN_LD; \
info->op1.reg = LR35902_REG_ ## NAME; \
info->op2.reg = LR35902_REG_A) \
DEFINE_DECODER_LR35902(LD ## NAME ## _B, \
info->mnemonic = LR35902_MN_LD; \
info->op1.reg = LR35902_REG_ ## NAME; \
info->op2.reg = LR35902_REG_B) \
DEFINE_DECODER_LR35902(LD ## NAME ## _C, \
info->mnemonic = LR35902_MN_LD; \
info->op1.reg = LR35902_REG_ ## NAME; \
info->op2.reg = LR35902_REG_C) \
DEFINE_DECODER_LR35902(LD ## NAME ## _D, \
info->mnemonic = LR35902_MN_LD; \
info->op1.reg = LR35902_REG_ ## NAME; \
info->op2.reg = LR35902_REG_D) \
DEFINE_DECODER_LR35902(LD ## NAME ## _E, \
info->mnemonic = LR35902_MN_LD; \
info->op1.reg = LR35902_REG_ ## NAME; \
info->op2.reg = LR35902_REG_E) \
DEFINE_DECODER_LR35902(LD ## NAME ## _H, \
info->mnemonic = LR35902_MN_LD; \
info->op1.reg = LR35902_REG_ ## NAME; \
info->op2.reg = LR35902_REG_H) \
DEFINE_DECODER_LR35902(LD ## NAME ## _L, \
info->mnemonic = LR35902_MN_LD; \
info->op1.reg = LR35902_REG_ ## NAME; \
info->op2.reg = LR35902_REG_L)
#define DEFINE_LD_DECODER_LR35902_MEM(NAME, REG) \
DEFINE_DECODER_LR35902(LD ## NAME ## _ ## REG, info->mnemonic = LR35902_MN_LD; \
info->op1.reg = LR35902_REG_ ## A; \
info->op2.reg = LR35902_REG_ ## REG; \
info->op2.flags = LR35902_OP_FLAG_MEMORY;)
#define DEFINE_LD_DECODER_LR35902_MEM_2(NAME, REG) \
DEFINE_DECODER_LR35902(LD ## REG ## _ ## NAME, info->mnemonic = LR35902_MN_LD; \
info->op1.reg = LR35902_REG_ ## REG; \
info->op1.flags = LR35902_OP_FLAG_MEMORY; \
info->op2.reg = LR35902_REG_ ## NAME;)
#define DEFINE_LD_DECODER_LR35902(NAME) \
DEFINE_LD_DECODER_LR35902_MEM(NAME, HL) \
DEFINE_LD_DECODER_LR35902_MEM_2(NAME, HL) \
DEFINE_DECODER_LR35902(LD ## NAME ## _, info->mnemonic = LR35902_MN_LD; \
info->op1.reg = LR35902_REG_A; \
info->op1.flags = LR35902_OP_FLAG_IMPLICIT; \
return 1;) \
DEFINE_LD_DECODER_LR35902_NOHL(NAME)
#define DEFINE_LD_2_DECODER_LR35902(NAME) \
DEFINE_DECODER_LR35902(LD ## NAME, info->mnemonic = LR35902_MN_LD; \
info->op1.reg = LR35902_REG_ ## NAME; \
return 2;)
DEFINE_LD_DECODER_LR35902(B);
DEFINE_LD_DECODER_LR35902(C);
DEFINE_LD_DECODER_LR35902(D);
DEFINE_LD_DECODER_LR35902(E);
DEFINE_LD_DECODER_LR35902(H);
DEFINE_LD_DECODER_LR35902(L);
DEFINE_LD_DECODER_LR35902(A);
DEFINE_LD_DECODER_LR35902_MEM(A, BC);
DEFINE_LD_DECODER_LR35902_MEM(A, DE);
DEFINE_LD_2_DECODER_LR35902(BC);
DEFINE_LD_2_DECODER_LR35902(DE);
DEFINE_LD_2_DECODER_LR35902(HL);
DEFINE_LD_2_DECODER_LR35902(SP);
DEFINE_DECODER_LR35902(LDHL_, \
info->mnemonic = LR35902_MN_LD; \
info->op1.reg = LR35902_REG_HL; \
info->op1.flags = LR35902_OP_FLAG_MEMORY; \
return 1;)
DEFINE_DECODER_LR35902(LDHL_SP, \
info->mnemonic = LR35902_MN_LD; \
info->op1.reg = LR35902_REG_HL; \
info->op2.reg = LR35902_REG_SP; \
return 1;)
DEFINE_DECODER_LR35902(LDSP_HL, \
info->mnemonic = LR35902_MN_LD; \
info->op1.reg = LR35902_REG_SP; \
info->op2.reg = LR35902_REG_HL;)
DEFINE_DECODER_LR35902(LDAIOC, \
info->mnemonic = LR35902_MN_LD; \
info->op1.reg = LR35902_REG_A; \
info->op2.reg = LR35902_REG_C; \
info->op2.immediate = 0xFF00; \
info->op2.flags = LR35902_OP_FLAG_MEMORY;)
DEFINE_DECODER_LR35902(LDIOCA, \
info->mnemonic = LR35902_MN_LD; \
info->op1.reg = LR35902_REG_C; \
info->op1.immediate = 0xFF00; \
info->op1.flags = LR35902_OP_FLAG_MEMORY; \
info->op2.reg = LR35902_REG_A;)
DEFINE_DECODER_LR35902(LDAIO, \
info->mnemonic = LR35902_MN_LD; \
info->op1.reg = LR35902_REG_A; \
info->op2.immediate = 0xFF00; \
info->op2.flags = LR35902_OP_FLAG_MEMORY; \
return 1;)
DEFINE_DECODER_LR35902(LDIOA, \
info->mnemonic = LR35902_MN_LD; \
info->op1.immediate = 0xFF00; \
info->op1.flags = LR35902_OP_FLAG_MEMORY; \
info->op2.reg = LR35902_REG_A; \
return 1;)
#define DEFINE_ALU_DECODER_LR35902_NOHL(NAME) \
DEFINE_DECODER_LR35902(NAME ## A, info->mnemonic = LR35902_MN_ ## NAME; info->op1.reg = LR35902_REG_A) \
DEFINE_DECODER_LR35902(NAME ## B, info->mnemonic = LR35902_MN_ ## NAME; info->op1.reg = LR35902_REG_B) \
DEFINE_DECODER_LR35902(NAME ## C, info->mnemonic = LR35902_MN_ ## NAME; info->op1.reg = LR35902_REG_C) \
DEFINE_DECODER_LR35902(NAME ## D, info->mnemonic = LR35902_MN_ ## NAME; info->op1.reg = LR35902_REG_D) \
DEFINE_DECODER_LR35902(NAME ## E, info->mnemonic = LR35902_MN_ ## NAME; info->op1.reg = LR35902_REG_E) \
DEFINE_DECODER_LR35902(NAME ## H, info->mnemonic = LR35902_MN_ ## NAME; info->op1.reg = LR35902_REG_H) \
DEFINE_DECODER_LR35902(NAME ## L, info->mnemonic = LR35902_MN_ ## NAME; info->op1.reg = LR35902_REG_L)
#define DEFINE_ALU_DECODER_LR35902_MEM(NAME, REG) \
DEFINE_DECODER_LR35902(NAME ## REG, info->mnemonic = LR35902_MN_ ## NAME; \
info->op1.reg = LR35902_REG_HL; \
info->op1.flags = LR35902_OP_FLAG_MEMORY;)
#define DEFINE_ALU_DECODER_LR35902(NAME) \
DEFINE_ALU_DECODER_LR35902_MEM(NAME, HL) \
DEFINE_DECODER_LR35902(NAME, info->mnemonic = LR35902_MN_ ## NAME; \
info->op1.reg = LR35902_REG_A; \
info->op1.flags = LR35902_OP_FLAG_IMPLICIT; \
return 1;) \
DEFINE_ALU_DECODER_LR35902_NOHL(NAME)
DEFINE_ALU_DECODER_LR35902_NOHL(INC);
DEFINE_ALU_DECODER_LR35902_NOHL(DEC);
DEFINE_ALU_DECODER_LR35902(AND);
DEFINE_ALU_DECODER_LR35902(XOR);
DEFINE_ALU_DECODER_LR35902(OR);
DEFINE_ALU_DECODER_LR35902(CP);
DEFINE_ALU_DECODER_LR35902(ADD);
DEFINE_ALU_DECODER_LR35902(ADC);
DEFINE_ALU_DECODER_LR35902(SUB);
DEFINE_ALU_DECODER_LR35902(SBC);
#define DEFINE_ALU_DECODER_LR35902_ADD_HL(REG) \
DEFINE_DECODER_LR35902(ADDHL_ ## REG, info->mnemonic = LR35902_MN_ADD; \
info->op1.reg = LR35902_REG_HL; \
info->op2.reg = LR35902_REG_ ## REG;)
DEFINE_ALU_DECODER_LR35902_ADD_HL(BC)
DEFINE_ALU_DECODER_LR35902_ADD_HL(DE)
DEFINE_ALU_DECODER_LR35902_ADD_HL(HL)
DEFINE_ALU_DECODER_LR35902_ADD_HL(SP)
DEFINE_DECODER_LR35902(ADDSP, info->mnemonic = LR35902_MN_ADD; \
info->op1.reg = LR35902_REG_SP; \
return 1;)
#define DEFINE_CONDITIONAL_DECODER_LR35902(NAME) \
DEFINE_ ## NAME ## _INSTRUCTION_LR35902(, 0) \
DEFINE_ ## NAME ## _INSTRUCTION_LR35902(C, LR35902_COND_C) \
DEFINE_ ## NAME ## _INSTRUCTION_LR35902(Z, LR35902_COND_Z) \
DEFINE_ ## NAME ## _INSTRUCTION_LR35902(NC, LR35902_COND_NC) \
DEFINE_ ## NAME ## _INSTRUCTION_LR35902(NZ, LR35902_COND_NZ)
#define DEFINE_JP_INSTRUCTION_LR35902(CONDITION_NAME, CONDITION) \
DEFINE_DECODER_LR35902(JP ## CONDITION_NAME, \
info->mnemonic = LR35902_MN_JP; \
info->condition = CONDITION; \
return 2;)
#define DEFINE_JR_INSTRUCTION_LR35902(CONDITION_NAME, CONDITION) \
DEFINE_DECODER_LR35902(JR ## CONDITION_NAME, \
info->mnemonic = LR35902_MN_JR; \
info->condition = CONDITION; \
return 1;)
#define DEFINE_CALL_INSTRUCTION_LR35902(CONDITION_NAME, CONDITION) \
DEFINE_DECODER_LR35902(CALL ## CONDITION_NAME, \
info->mnemonic = LR35902_MN_CALL; \
info->condition = CONDITION; \
return 2;)
#define DEFINE_RET_INSTRUCTION_LR35902(CONDITION_NAME, CONDITION) \
DEFINE_DECODER_LR35902(RET ## CONDITION_NAME, \
info->mnemonic = LR35902_MN_RET; \
info->condition = CONDITION;)
DEFINE_CONDITIONAL_DECODER_LR35902(JP);
DEFINE_CONDITIONAL_DECODER_LR35902(JR);
DEFINE_CONDITIONAL_DECODER_LR35902(CALL);
DEFINE_CONDITIONAL_DECODER_LR35902(RET);
DEFINE_DECODER_LR35902(JPHL, \
info->mnemonic = LR35902_MN_JP; \
info->op1.reg = LR35902_REG_HL)
DEFINE_DECODER_LR35902(RETI, info->mnemonic = LR35902_MN_RETI)
DEFINE_DECODER_LR35902(LDBC_A, \
info->mnemonic = LR35902_MN_LD; \
info->op1.reg = LR35902_REG_BC; \
info->op1.flags = LR35902_OP_FLAG_MEMORY; \
info->op2.reg = LR35902_REG_A;)
DEFINE_DECODER_LR35902(LDDE_A, \
info->mnemonic = LR35902_MN_LD; \
info->op1.reg = LR35902_REG_DE; \
info->op1.flags = LR35902_OP_FLAG_MEMORY; \
info->op2.reg = LR35902_REG_A;)
DEFINE_DECODER_LR35902(LDIA, \
info->mnemonic = LR35902_MN_LD; \
info->op1.flags = LR35902_OP_FLAG_MEMORY; \
info->op2.reg = LR35902_REG_A; \
return 2;)
DEFINE_DECODER_LR35902(LDAI, \
info->mnemonic = LR35902_MN_LD; \
info->op1.reg = LR35902_REG_A; \
info->op2.flags = LR35902_OP_FLAG_MEMORY; \
return 2;)
DEFINE_DECODER_LR35902(LDISP, \
info->mnemonic = LR35902_MN_LD; \
info->op1.flags = LR35902_OP_FLAG_MEMORY; \
info->op2.reg = LR35902_REG_SP; \
return 2;)
DEFINE_DECODER_LR35902(LDIHLA, \
info->mnemonic = LR35902_MN_LD; \
info->op1.reg = LR35902_REG_HL; \
info->op1.flags = LR35902_OP_FLAG_INCREMENT | LR35902_OP_FLAG_MEMORY; \
info->op2.reg = LR35902_REG_A;)
DEFINE_DECODER_LR35902(LDDHLA, \
info->mnemonic = LR35902_MN_LD; \
info->op1.reg = LR35902_REG_HL; \
info->op1.flags = LR35902_OP_FLAG_DECREMENT | LR35902_OP_FLAG_MEMORY; \
info->op2.reg = LR35902_REG_A;)
DEFINE_DECODER_LR35902(LDA_IHL, \
info->mnemonic = LR35902_MN_LD; \
info->op1.reg = LR35902_REG_A; \
info->op2.reg = LR35902_REG_HL; \
info->op2.flags = LR35902_OP_FLAG_INCREMENT | LR35902_OP_FLAG_MEMORY;)
DEFINE_DECODER_LR35902(LDA_DHL, \
info->mnemonic = LR35902_MN_LD; \
info->op1.reg = LR35902_REG_A; \
info->op2.reg = LR35902_REG_HL; \
info->op2.flags = LR35902_OP_FLAG_DECREMENT | LR35902_OP_FLAG_MEMORY;)
#define DEFINE_INCDEC_WIDE_INSTRUCTION_LR35902(REG) \
DEFINE_DECODER_LR35902(INC ## REG, info->mnemonic = LR35902_MN_INC; info->op1.reg = LR35902_REG_ ## REG) \
DEFINE_DECODER_LR35902(DEC ## REG, info->mnemonic = LR35902_MN_DEC; info->op1.reg = LR35902_REG_ ## REG)
DEFINE_INCDEC_WIDE_INSTRUCTION_LR35902(BC);
DEFINE_INCDEC_WIDE_INSTRUCTION_LR35902(DE);
DEFINE_INCDEC_WIDE_INSTRUCTION_LR35902(HL);
DEFINE_INCDEC_WIDE_INSTRUCTION_LR35902(SP);
DEFINE_DECODER_LR35902(INC_HL,
info->mnemonic = LR35902_MN_INC;
info->op1.reg = LR35902_REG_HL;
info->op1.flags = LR35902_OP_FLAG_MEMORY;)
DEFINE_DECODER_LR35902(DEC_HL,
info->mnemonic = LR35902_MN_DEC;
info->op1.reg = LR35902_REG_HL;
info->op1.flags = LR35902_OP_FLAG_MEMORY;)
DEFINE_DECODER_LR35902(SCF, info->mnemonic = LR35902_MN_SCF)
DEFINE_DECODER_LR35902(CCF, info->mnemonic = LR35902_MN_CCF)
DEFINE_DECODER_LR35902(CPL_, info->mnemonic = LR35902_MN_CPL)
DEFINE_DECODER_LR35902(DAA, info->mnemonic = LR35902_MN_DAA)
#define DEFINE_POPPUSH_DECODER_LR35902(REG) \
DEFINE_DECODER_LR35902(POP ## REG, \
info->mnemonic = LR35902_MN_POP; \
info->op1.reg = LR35902_REG_ ## REG;) \
DEFINE_DECODER_LR35902(PUSH ## REG, \
info->mnemonic = LR35902_MN_PUSH; \
info->op1.reg = LR35902_REG_ ## REG;) \
DEFINE_POPPUSH_DECODER_LR35902(BC);
DEFINE_POPPUSH_DECODER_LR35902(DE);
DEFINE_POPPUSH_DECODER_LR35902(HL);
DEFINE_POPPUSH_DECODER_LR35902(AF);
#define DEFINE_CB_2_DECODER_LR35902(NAME, BODY) \
DEFINE_DECODER_LR35902(NAME ## B, info->op1.reg = LR35902_REG_B; BODY) \
DEFINE_DECODER_LR35902(NAME ## C, info->op1.reg = LR35902_REG_C; BODY) \
DEFINE_DECODER_LR35902(NAME ## D, info->op1.reg = LR35902_REG_D; BODY) \
DEFINE_DECODER_LR35902(NAME ## E, info->op1.reg = LR35902_REG_E; BODY) \
DEFINE_DECODER_LR35902(NAME ## H, info->op1.reg = LR35902_REG_H; BODY) \
DEFINE_DECODER_LR35902(NAME ## L, info->op1.reg = LR35902_REG_L; BODY) \
DEFINE_DECODER_LR35902(NAME ## HL, info->op1.reg = LR35902_REG_HL; BODY) \
DEFINE_DECODER_LR35902(NAME ## A, info->op1.reg = LR35902_REG_A; BODY)
#define DEFINE_CB_DECODER_LR35902(NAME, BODY) \
DEFINE_CB_2_DECODER_LR35902(NAME ## 0, info->op2.immediate = 1; BODY) \
DEFINE_CB_2_DECODER_LR35902(NAME ## 1, info->op2.immediate = 2; BODY) \
DEFINE_CB_2_DECODER_LR35902(NAME ## 2, info->op2.immediate = 4; BODY) \
DEFINE_CB_2_DECODER_LR35902(NAME ## 3, info->op2.immediate = 8; BODY) \
DEFINE_CB_2_DECODER_LR35902(NAME ## 4, info->op2.immediate = 16; BODY) \
DEFINE_CB_2_DECODER_LR35902(NAME ## 5, info->op2.immediate = 32; BODY) \
DEFINE_CB_2_DECODER_LR35902(NAME ## 6, info->op2.immediate = 64; BODY) \
DEFINE_CB_2_DECODER_LR35902(NAME ## 7, info->op2.immediate = 128; BODY)
DEFINE_CB_DECODER_LR35902(BIT, info->mnemonic = LR35902_MN_BIT)
DEFINE_CB_DECODER_LR35902(RES, info->mnemonic = LR35902_MN_RES)
DEFINE_CB_DECODER_LR35902(SET, info->mnemonic = LR35902_MN_SET)
#define DEFINE_CB_X_DECODER_LR35902(NAME) \
DEFINE_CB_2_DECODER_LR35902(NAME, info->mnemonic = LR35902_MN_ ## NAME) \
DEFINE_DECODER_LR35902(NAME ## A_, info->mnemonic = LR35902_MN_ ## NAME; info->op1.reg = LR35902_REG_A)
DEFINE_CB_X_DECODER_LR35902(RL)
DEFINE_CB_X_DECODER_LR35902(RLC)
DEFINE_CB_X_DECODER_LR35902(RR)
DEFINE_CB_X_DECODER_LR35902(RRC)
DEFINE_CB_2_DECODER_LR35902(SLA, info->mnemonic = LR35902_MN_SLA)
DEFINE_CB_2_DECODER_LR35902(SRA, info->mnemonic = LR35902_MN_SRA)
DEFINE_CB_2_DECODER_LR35902(SRL, info->mnemonic = LR35902_MN_SRL)
DEFINE_CB_2_DECODER_LR35902(SWAP, info->mnemonic = LR35902_MN_SWAP)
DEFINE_DECODER_LR35902(DI, info->mnemonic = LR35902_MN_DI)
DEFINE_DECODER_LR35902(EI, info->mnemonic = LR35902_MN_EI)
DEFINE_DECODER_LR35902(HALT, info->mnemonic = LR35902_MN_HALT)
DEFINE_DECODER_LR35902(ILL, info->mnemonic = LR35902_MN_ILL)
DEFINE_DECODER_LR35902(STOP, info->mnemonic = LR35902_MN_STOP; return 1)
#define DEFINE_RST_DECODER_LR35902(VEC) \
DEFINE_DECODER_LR35902(RST ## VEC, info->op1.immediate = 0x ## VEC;)
DEFINE_RST_DECODER_LR35902(00);
DEFINE_RST_DECODER_LR35902(08);
DEFINE_RST_DECODER_LR35902(10);
DEFINE_RST_DECODER_LR35902(18);
DEFINE_RST_DECODER_LR35902(20);
DEFINE_RST_DECODER_LR35902(28);
DEFINE_RST_DECODER_LR35902(30);
DEFINE_RST_DECODER_LR35902(38);
DEFINE_DECODER_LR35902(CB, return 1)
const LR35902Decoder _lr35902DecoderTable[0x100] = {
DECLARE_LR35902_EMITTER_BLOCK(_LR35902Decode)
};
const LR35902Decoder _lr35902CBDecoderTable[0x100] = {
DECLARE_LR35902_CB_EMITTER_BLOCK(_LR35902Decode)
};
size_t LR35902Decode(uint8_t opcode, struct LR35902InstructionInfo* info) {
if (info->opcodeSize == sizeof(info->opcode)) {
return 0;
}
info->opcode[info->opcodeSize] = opcode;
LR35902Decoder decoder;
switch (info->opcodeSize) {
case 0:
decoder = _lr35902DecoderTable[opcode];
break;
case 1:
if (info->opcode[0] == 0xCB) {
decoder = _lr35902CBDecoderTable[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* _lr35902Conditions[] = {
NULL,
"c",
"z",
"nc",
"nz",
};
static const char* _lr35902Registers[] = {
"",
"b",
"c",
"d",
"e",
"h",
"l",
"a",
"f",
"bc",
"de",
"hl",
"af",
"sp",
"pc",
};
static const char* _lr35902MnemonicStrings[] = {
"--",
"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 LR35902Operand op, char* buffer, int blen) {
int total = 0;
if (op.flags & LR35902_OP_FLAG_IMPLICIT) {
return 0;
}
if (op.flags & LR35902_OP_FLAG_MEMORY) {
strncpy(buffer, "(", blen - 1);
ADVANCE(1);
}
if (op.immediate) {
int written = snprintf(buffer, blen - 1, "$%02X", op.immediate);
ADVANCE(written);
if (op.reg) {
strncpy(buffer, "+", blen - 1);
ADVANCE(1);
}
}
if (op.reg) {
int written = snprintf(buffer, blen - 1, "%s", _lr35902Registers[op.reg]);
ADVANCE(written);
}
if (op.flags & LR35902_OP_FLAG_INCREMENT) {
strncpy(buffer, "+", blen - 1);
ADVANCE(1);
}
if (op.flags & LR35902_OP_FLAG_DECREMENT) {
strncpy(buffer, "-", blen - 1);
ADVANCE(1);
}
if (op.flags & LR35902_OP_FLAG_MEMORY) {
strncpy(buffer, ")", blen - 1);
ADVANCE(1);
}
return total;
}
int LR35902Disassemble(struct LR35902InstructionInfo* info, char* buffer, int blen) {
const char* mnemonic = _lr35902MnemonicStrings[info->mnemonic];
int written;
int total = 0;
const char* cond = _lr35902Conditions[info->condition];
written = snprintf(buffer, blen - 1, "%s ", mnemonic);
ADVANCE(written);
if (cond) {
written = snprintf(buffer, blen - 1, "%s", cond);
ADVANCE(written);
if (info->op1.reg || info->op1.immediate || info->op2.reg || info->op2.immediate) {
strncpy(buffer, ", ", blen - 1);
ADVANCE(2);
}
}
written = _decodeOperand(info->op1, buffer, blen);
ADVANCE(written);
if (info->op2.reg || info->op2.immediate) {
if (written) {
strncpy(buffer, ", ", blen - 1);
ADVANCE(2);
}
written = _decodeOperand(info->op2, buffer, blen);
ADVANCE(written);
}
buffer[blen - 1] = '\0';
return total;
}