Greatly simplified disassembly code
This commit is contained in:
parent
4c9a2daeb4
commit
0ffacd9e5d
323
dcc6502.c
323
dcc6502.c
|
@ -369,8 +369,9 @@ void append_nes(char *input, uint16_t arg) {
|
||||||
// FIXME: Refactor code to reduce line duplication and make more readable
|
// FIXME: Refactor code to reduce line duplication and make more readable
|
||||||
/* This function disassembles the opcode at the PC and outputs it in *output */
|
/* This function disassembles the opcode at the PC and outputs it in *output */
|
||||||
void disassemble(char *output) {
|
void disassemble(char *output) {
|
||||||
char tmpstr[256], opcode_repr[256], hex_dump[256];
|
char opcode_repr[256], hex_dump[256];
|
||||||
int i;
|
int i;
|
||||||
|
int len = 0;
|
||||||
int entry = 0;
|
int entry = 0;
|
||||||
int found = 0;
|
int found = 0;
|
||||||
uint8_t tmp_byte1, opcode;
|
uint8_t tmp_byte1, opcode;
|
||||||
|
@ -378,14 +379,20 @@ void disassemble(char *output) {
|
||||||
uint16_t current_addr = org + PC;
|
uint16_t current_addr = org + PC;
|
||||||
|
|
||||||
opcode = buffer[current_addr - org];
|
opcode = buffer[current_addr - org];
|
||||||
|
opcode_repr[0] = '\0';
|
||||||
|
hex_dump[0] = '\0';
|
||||||
|
|
||||||
|
// Linear search for opcode
|
||||||
for (i = 0; i < NUMBER_OPCODES; i++) {
|
for (i = 0; i < NUMBER_OPCODES; i++) {
|
||||||
if (opcode == opcode_table[i].number) {
|
if (opcode == opcode_table[i].number) {
|
||||||
found = 1; /* Found the opcode */
|
/* Found the opcode, record its table index */
|
||||||
entry = i; /* Note the entry number in the table */
|
found = 1;
|
||||||
|
entry = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Normalize %02x versus %02X
|
||||||
|
// For opcode not found, terminate early
|
||||||
if (!found) {
|
if (!found) {
|
||||||
sprintf(opcode_repr, ".byte $%02x", opcode);
|
sprintf(opcode_repr, ".byte $%02x", opcode);
|
||||||
if (hex_output) {
|
if (hex_output) {
|
||||||
|
@ -395,188 +402,184 @@ void disassemble(char *output) {
|
||||||
sprintf(hex_dump, "$%04X", current_addr);
|
sprintf(hex_dump, "$%04X", current_addr);
|
||||||
sprintf(output, "%-8s%-16s; INVALID OPCODE !!!\n", hex_dump, opcode_repr);
|
sprintf(output, "%-8s%-16s; INVALID OPCODE !!!\n", hex_dump, opcode_repr);
|
||||||
}
|
}
|
||||||
} else {
|
return;
|
||||||
switch (opcode_table[entry].addressing) {
|
}
|
||||||
case IMMED:
|
|
||||||
tmp_byte1 = buffer[PC + 1]; /* Get immediate value */
|
|
||||||
|
|
||||||
sprintf(opcode_repr, "%s #$%02x", name_table[opcode_table[entry].name], tmp_byte1);
|
// Opcode found in table: disassemble properly according to addressing mode
|
||||||
if (hex_output) {
|
|
||||||
sprintf(hex_dump, "$%04X> %02X %02X:", current_addr, opcode, tmp_byte1);
|
|
||||||
} else {
|
|
||||||
sprintf(hex_dump, "$%04X", current_addr);
|
|
||||||
}
|
|
||||||
sprintf(output, DUMP_FORMAT, hex_dump, opcode_repr);
|
|
||||||
|
|
||||||
PC++;
|
// Set hex dump to default single address format. Will be overwritten
|
||||||
break;
|
// by more complex output in case of hex dump mode enabled
|
||||||
case ABSOL:
|
sprintf(hex_dump, "$%04X", current_addr);
|
||||||
/* Get address */
|
|
||||||
tmp_word = LOAD_WORD(buffer, PC);
|
|
||||||
|
|
||||||
sprintf(opcode_repr, "%s $%02X%02X", name_table[opcode_table[entry].name], HIGH_PART(tmp_word), LOW_PART(tmp_word));
|
switch (opcode_table[entry].addressing) {
|
||||||
if (hex_output) {
|
case IMMED:
|
||||||
sprintf(hex_dump, "$%04X> %02X %02X%02X:", current_addr, opcode, LOW_PART(tmp_word), HIGH_PART(tmp_word));
|
/* Get immediate value operand */
|
||||||
} else {
|
tmp_byte1 = buffer[PC + 1];
|
||||||
sprintf(hex_dump, "$%04X", current_addr);
|
PC++;
|
||||||
}
|
|
||||||
sprintf(output, DUMP_FORMAT, hex_dump, opcode_repr);
|
|
||||||
|
|
||||||
PC += 2;
|
sprintf(opcode_repr, "%s #$%02x", name_table[opcode_table[entry].name], tmp_byte1);
|
||||||
break;
|
if (hex_output) {
|
||||||
case ZEROP:
|
sprintf(hex_dump, "$%04X> %02X %02X:", current_addr, opcode, tmp_byte1);
|
||||||
PC++;
|
}
|
||||||
tmp_byte1 = buffer[PC]; /* Get low byte of address */
|
|
||||||
|
|
||||||
if (hex_output) {
|
break;
|
||||||
sprintf(tmpstr, "$%04X> %02X %02X:\t%s $%02X\t\t;", org+PC-1, opcode, tmp_byte1, name_table[opcode_table[entry].name], tmp_byte1);
|
case ABSOL:
|
||||||
} else {
|
/* Get absolute address operand */
|
||||||
sprintf(tmpstr, "$%04X\t%s $%02X\t\t;", org+PC-1, name_table[opcode_table[entry].name], tmp_byte1);
|
tmp_word = LOAD_WORD(buffer, PC);
|
||||||
}
|
PC += 2;
|
||||||
strncpy(output, tmpstr, 254);
|
|
||||||
break;
|
|
||||||
case IMPLI:
|
|
||||||
if (hex_output) {
|
|
||||||
sprintf(tmpstr, "$%04X> %02X:\t%s\t\t;", org+PC, opcode, name_table[opcode_table[entry].name]);
|
|
||||||
} else {
|
|
||||||
sprintf(tmpstr, "$%04X\t%s\t\t;", org+PC, name_table[opcode_table[entry].name]);
|
|
||||||
}
|
|
||||||
|
|
||||||
strncpy(output, tmpstr, 254);
|
sprintf(opcode_repr, "%s $%02X%02X", name_table[opcode_table[entry].name], HIGH_PART(tmp_word), LOW_PART(tmp_word));
|
||||||
break;
|
if (hex_output) {
|
||||||
case INDIA:
|
sprintf(hex_dump, "$%04X> %02X %02X%02X:", current_addr, opcode, LOW_PART(tmp_word), HIGH_PART(tmp_word));
|
||||||
PC++;
|
}
|
||||||
PC++;
|
|
||||||
tmp_word = LOAD_WORD(buffer, PC-2);
|
|
||||||
|
|
||||||
if (hex_output) {
|
break;
|
||||||
sprintf(tmpstr, "$%04X> %02X %02X%02X:\t%s ($%02X%02X)\t;", org+PC-2, opcode, LOW_PART(tmp_word), HIGH_PART(tmp_word), name_table[opcode_table[entry].name], HIGH_PART(tmp_word), LOW_PART(tmp_word));
|
case ZEROP:
|
||||||
} else {
|
/* Get zero page address */
|
||||||
sprintf(tmpstr, "$%04X\t%s ($%02X%02X)\t;", org+PC-2, name_table[opcode_table[entry].name], HIGH_PART(tmp_word), LOW_PART(tmp_word));
|
tmp_byte1 = buffer[PC + 1];
|
||||||
}
|
PC++;
|
||||||
|
|
||||||
strncpy(output, tmpstr, 254);
|
sprintf(opcode_repr, "%s $%02X", name_table[opcode_table[entry].name], tmp_byte1);
|
||||||
break;
|
if (hex_output) {
|
||||||
case ABSIX:
|
sprintf(hex_dump, "$%04X> %02X %02X:", current_addr, opcode, tmp_byte1);
|
||||||
PC++;
|
}
|
||||||
PC++;
|
|
||||||
tmp_word = LOAD_WORD(buffer, PC-2);
|
|
||||||
|
|
||||||
if (hex_output) {
|
break;
|
||||||
sprintf(tmpstr, "$%04X> %02X %02X%02X:\t%s $%02X%02X,X\t;", org+PC-2, opcode, LOW_PART(tmp_word), HIGH_PART(tmp_word), name_table[opcode_table[entry].name], HIGH_PART(tmp_word), LOW_PART(tmp_word));
|
case IMPLI:
|
||||||
} else {
|
sprintf(opcode_repr, "%s", name_table[opcode_table[entry].name]);
|
||||||
sprintf(tmpstr, "$%04X\t%s $%02X%02X,X\t;", org+PC-2, name_table[opcode_table[entry].name], HIGH_PART(tmp_word), LOW_PART(tmp_word));
|
if (hex_output) {
|
||||||
}
|
sprintf(hex_dump, "$%04X> %02X:", current_addr, opcode);
|
||||||
|
}
|
||||||
|
|
||||||
strncpy(output, tmpstr, 254);
|
break;
|
||||||
break;
|
case INDIA:
|
||||||
case ABSIY:
|
/* Get indirection address */
|
||||||
PC++;
|
tmp_word = LOAD_WORD(buffer, PC);
|
||||||
PC++;
|
PC += 2;
|
||||||
tmp_word = LOAD_WORD(buffer, PC-2);
|
|
||||||
|
|
||||||
if (hex_output) {
|
sprintf(opcode_repr, "%s ($%02X%02X)", name_table[opcode_table[entry].name], HIGH_PART(tmp_word), LOW_PART(tmp_word));
|
||||||
sprintf(tmpstr, "$%04X> %02X %02X%02X:\t%s $%02X%02X,Y\t;", org+PC-2, opcode, LOW_PART(tmp_word), HIGH_PART(tmp_word), name_table[opcode_table[entry].name], HIGH_PART(tmp_word), LOW_PART(tmp_word));
|
if (hex_output) {
|
||||||
} else {
|
sprintf(hex_dump, "$%04X> %02X %02X%02X:", current_addr, opcode, LOW_PART(tmp_word), HIGH_PART(tmp_word));
|
||||||
sprintf(tmpstr, "$%04X\t%s $%02X%02X,Y\t;", org+PC-2, name_table[opcode_table[entry].name], HIGH_PART(tmp_word), LOW_PART(tmp_word));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
strncpy(output, tmpstr, 254);
|
|
||||||
break;
|
|
||||||
case ZEPIX:
|
|
||||||
PC++;
|
|
||||||
tmp_byte1 = buffer[PC]; /* Get low byte of address */
|
|
||||||
|
|
||||||
if (hex_output) {
|
break;
|
||||||
sprintf(tmpstr, "$%04X> %02X %02X:\t%s $%02X,X\t\t;", org+PC-1, opcode, tmp_byte1, name_table[opcode_table[entry].name], tmp_byte1);
|
case ABSIX:
|
||||||
} else {
|
/* Get base address */
|
||||||
sprintf(tmpstr, "$%04X\t%s $%02X,X\t;", org+PC-1, name_table[opcode_table[entry].name], tmp_byte1);
|
tmp_word = LOAD_WORD(buffer, PC);
|
||||||
}
|
PC += 2;
|
||||||
|
|
||||||
strncpy(output, tmpstr, 254);
|
sprintf(opcode_repr, "%s $%02X%02X,X", name_table[opcode_table[entry].name], HIGH_PART(tmp_word), LOW_PART(tmp_word));
|
||||||
break;
|
if (hex_output) {
|
||||||
case ZEPIY:
|
sprintf(hex_dump, "$%04X> %02X %02X%02X:", current_addr, opcode, LOW_PART(tmp_word), HIGH_PART(tmp_word));
|
||||||
PC++;
|
}
|
||||||
tmp_byte1 = buffer[PC]; /* Get low byte of address */
|
|
||||||
|
|
||||||
if (hex_output) {
|
break;
|
||||||
sprintf(tmpstr, "$%04X> %02X %02X:\t%s $%02X,Y\t\t;", org+PC-1, opcode, tmp_byte1, name_table[opcode_table[entry].name], tmp_byte1);
|
case ABSIY:
|
||||||
} else {
|
/* Get baser address */
|
||||||
sprintf(tmpstr, "$%04X\t%s $%02X,Y\t;", org+PC-1, name_table[opcode_table[entry].name], tmp_byte1);
|
tmp_word = LOAD_WORD(buffer, PC);
|
||||||
}
|
PC += 2;
|
||||||
|
|
||||||
strncpy(output, tmpstr, 254);
|
sprintf(opcode_repr, "%s $%02X%02X,Y", name_table[opcode_table[entry].name], HIGH_PART(tmp_word), LOW_PART(tmp_word));
|
||||||
break;
|
if (hex_output) {
|
||||||
case INDIN:
|
sprintf(hex_dump, "$%04X> %02X %02X%02X:", current_addr, opcode, LOW_PART(tmp_word), HIGH_PART(tmp_word));
|
||||||
PC++;
|
}
|
||||||
tmp_byte1 = buffer[PC]; /* Get low byte of address */
|
|
||||||
|
|
||||||
if (hex_output) {
|
break;
|
||||||
sprintf(tmpstr, "$%04X> %02X %02X:\t%s ($%02X,X)\t\t;", org+PC-1, opcode, tmp_byte1, name_table[opcode_table[entry].name], tmp_byte1);
|
case ZEPIX:
|
||||||
} else {
|
/* Get zero-page base address */
|
||||||
sprintf(tmpstr, "$%04X\t%s ($%02X,X)\t;", org+PC-1, name_table[opcode_table[entry].name], tmp_byte1);
|
tmp_byte1 = buffer[PC + 1];
|
||||||
}
|
PC++;
|
||||||
|
|
||||||
strncpy(output, tmpstr, 254);
|
sprintf(opcode_repr, "%s $%02X,X", name_table[opcode_table[entry].name], tmp_byte1);
|
||||||
break;
|
if (hex_output) {
|
||||||
case ININD:
|
sprintf(hex_dump, "$%04X> %02X %02X:", current_addr, opcode, tmp_byte1);
|
||||||
PC++;
|
}
|
||||||
tmp_byte1 = buffer[PC]; /* Get low byte of address */
|
|
||||||
|
|
||||||
if (hex_output) {
|
break;
|
||||||
sprintf(tmpstr, "$%04X> %02X %02X:\t%s ($%02X),Y\t\t;", org+PC-1, opcode, tmp_byte1, name_table[opcode_table[entry].name], tmp_byte1);
|
case ZEPIY:
|
||||||
} else {
|
/* Get zero-page base address */
|
||||||
sprintf(tmpstr, "$%04X\t%s ($%02X),Y\t;", org+PC-1, name_table[opcode_table[entry].name], tmp_byte1);
|
tmp_byte1 = buffer[PC + 1];
|
||||||
}
|
PC++;
|
||||||
|
|
||||||
strncpy(output, tmpstr, 254);
|
sprintf(opcode_repr, "%s $%02X,Y", name_table[opcode_table[entry].name], tmp_byte1);
|
||||||
break;
|
if (hex_output) {
|
||||||
case RELAT:
|
sprintf(hex_dump, "$%04X> %02X %02X:", current_addr, opcode, tmp_byte1);
|
||||||
PC++;
|
}
|
||||||
tmp_byte1 = buffer[PC]; /* Get relative modifier */
|
|
||||||
|
|
||||||
// FIXME: Resolve undefined behavior of cast for signed relative addressing
|
break;
|
||||||
if (hex_output) {
|
case INDIN:
|
||||||
sprintf(tmpstr, "$%04X> %02X %02X:\t%s $%04X\t\t;", org+PC-1, opcode, tmp_byte1, name_table[opcode_table[entry].name], (org+PC)+(signed char)(tmp_byte1)+1);
|
/* Get zero-page base address */
|
||||||
} else {
|
tmp_byte1 = buffer[PC + 1];
|
||||||
sprintf(tmpstr, "$%04X\t%s $%04X\t;", org+PC-1, name_table[opcode_table[entry].name], (org+PC)+(signed char)(tmp_byte1)+1);
|
PC++;
|
||||||
}
|
|
||||||
|
|
||||||
strncpy(output, tmpstr, 254);
|
sprintf(opcode_repr, "%s ($%02X,X)", name_table[opcode_table[entry].name], tmp_byte1);
|
||||||
break;
|
if (hex_output) {
|
||||||
case ACCUM:
|
sprintf(hex_dump, "$%04X> %02X %02X:", current_addr, opcode, tmp_byte1);
|
||||||
if (hex_output) {
|
}
|
||||||
sprintf(tmpstr, "$%04X> %02X:\t%s A\t\t;", org+PC, opcode, name_table[opcode_table[entry].name]);
|
|
||||||
} else {
|
|
||||||
sprintf(tmpstr, "$%04X\t%s A\t\t;", org+PC, name_table[opcode_table[entry].name]);
|
|
||||||
}
|
|
||||||
|
|
||||||
strncpy(output, tmpstr, 254);
|
break;
|
||||||
break;
|
case ININD:
|
||||||
default:
|
/* Get zero-page base address */
|
||||||
break;
|
tmp_byte1 = buffer[PC + 1];
|
||||||
}
|
PC++;
|
||||||
|
|
||||||
output += strlen(output);
|
sprintf(opcode_repr, "%s ($%02X),Y", name_table[opcode_table[entry].name], tmp_byte1);
|
||||||
|
if (hex_output) {
|
||||||
|
sprintf(hex_dump, "$%04X> %02X %02X:", current_addr, opcode, tmp_byte1);
|
||||||
|
}
|
||||||
|
|
||||||
/* Add cycle count if necessary */
|
break;
|
||||||
if (cycle_counting) {
|
case RELAT:
|
||||||
output = append_cycle(output, entry);
|
/* Get relative modifier */
|
||||||
}
|
tmp_byte1 = buffer[PC + 1];
|
||||||
|
PC++;
|
||||||
|
|
||||||
/* Add NES port info if necessary */
|
// Compute displacement from first byte after full instruction.
|
||||||
switch (opcode_table[entry].addressing) {
|
tmp_word = current_addr + 2;
|
||||||
case ABSOL:
|
if (tmp_byte1 > 0x7Fu) {
|
||||||
case ABSIX:
|
tmp_word -= ((~tmp_byte1 & 0x7Fu) + 1);
|
||||||
case ABSIY:
|
} else {
|
||||||
if (nes_mode) {
|
tmp_word += tmp_byte1 & 0x7Fu;
|
||||||
append_nes(output, tmp_word);
|
}
|
||||||
}
|
|
||||||
break;
|
sprintf(opcode_repr, "%s $%04X", name_table[opcode_table[entry].name], tmp_word);
|
||||||
default:
|
if (hex_output) {
|
||||||
/* Other addressing modes: not enough info to add NES register annotation */
|
sprintf(hex_dump, "$%04X> %02X %02X:", current_addr, opcode, tmp_byte1);
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
|
break;
|
||||||
|
case ACCUM:
|
||||||
|
sprintf(opcode_repr, "%s A", name_table[opcode_table[entry].name]);
|
||||||
|
if (hex_output) {
|
||||||
|
sprintf(hex_dump, "$%04X> %02X:", current_addr, opcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Will not happen since each entry in opcode_table has address mode set
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = sprintf(output, DUMP_FORMAT, hex_dump, opcode_repr);
|
||||||
|
output += len;
|
||||||
|
|
||||||
|
/* Add cycle count if necessary */
|
||||||
|
if (cycle_counting) {
|
||||||
|
output = append_cycle(output, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add NES port info if necessary */
|
||||||
|
switch (opcode_table[entry].addressing) {
|
||||||
|
case ABSOL:
|
||||||
|
case ABSIX:
|
||||||
|
case ABSIY:
|
||||||
|
if (nes_mode) {
|
||||||
|
append_nes(output, tmp_word);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Other addressing modes: not enough info to add NES register annotation */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue