Greatly simplified disassembly code

This commit is contained in:
Tennessee Carmel-Veilleux 2014-07-24 17:22:40 -04:00
parent 4c9a2daeb4
commit 0ffacd9e5d
1 changed files with 163 additions and 160 deletions

323
dcc6502.c
View File

@ -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;
} }
} }