Fixed cycle counting and finished 2.0

* Added rules for branch taken/not taken
* Fixed incorrect adding of cycles for many ALU instructions
* Fixed timing for ASL, DEC, INC, LSR, ROL, and ROR
* Renamed global opcode_table to g_opcode_table
* Normalized all hex output to be capitals
This commit is contained in:
Tennessee Carmel-Veilleux 2014-07-24 23:00:31 -04:00
parent d8869a8d28
commit aa6c897c1a
1 changed files with 123 additions and 98 deletions

221
dcc6502.c
View File

@ -34,6 +34,10 @@
#define VERSION_INFO "v2.0" #define VERSION_INFO "v2.0"
#define NUMBER_OPCODES 151 #define NUMBER_OPCODES 151
/* Exceptions for cycle counting */
#define CYCLES_CROSS_PAGE_ADDS_ONE (1 << 0)
#define CYCLES_BRANCH_TAKEN_ADDS_ONE (1 << 1)
/* The 6502's 13 addressing modes */ /* The 6502's 13 addressing modes */
typedef enum { typedef enum {
IMMED = 0, /* Immediate */ IMMED = 0, /* Immediate */
@ -61,7 +65,7 @@ typedef struct opcode_s {
const char *mnemonic; /* Index in the name table */ const char *mnemonic; /* Index in the name table */
addressing_mode_e addressing; /* Addressing mode */ addressing_mode_e addressing; /* Addressing mode */
unsigned int cycles; /* Number of cycles */ unsigned int cycles; /* Number of cycles */
unsigned int cross_page; /* 1 if cross-page boundaries affect cycles */ unsigned int cycles_exceptions; /* Mask of cycle-counting exceptions */
} opcode_t; } opcode_t;
typedef struct options_s { typedef struct options_s {
@ -73,53 +77,52 @@ typedef struct options_s {
uint16_t org; /* Origin of addresses */ uint16_t org; /* Origin of addresses */
} options_t; } options_t;
/* Opcode table */ /* Opcode table */
opcode_t opcode_table[NUMBER_OPCODES] = { static opcode_t g_opcode_table[NUMBER_OPCODES] = {
{0x69, "ADC", IMMED, 2, 1}, /* ADC */ {0x69, "ADC", IMMED, 2, 0}, /* ADC */
{0x65, "ADC", ZEROP, 3, 1}, {0x65, "ADC", ZEROP, 3, 0},
{0x75, "ADC", ZEPIX, 4, 1}, {0x75, "ADC", ZEPIX, 4, 0},
{0x6D, "ADC", ABSOL, 4, 1}, {0x6D, "ADC", ABSOL, 4, 0},
{0x7D, "ADC", ABSIX, 4, 1}, {0x7D, "ADC", ABSIX, 4, CYCLES_CROSS_PAGE_ADDS_ONE},
{0x79, "ADC", ABSIY, 4, 1}, {0x79, "ADC", ABSIY, 4, CYCLES_CROSS_PAGE_ADDS_ONE},
{0x61, "ADC", INDIN, 6, 1}, {0x61, "ADC", INDIN, 6, 0},
{0x71, "ADC", ININD, 5, 1}, {0x71, "ADC", ININD, 5, CYCLES_CROSS_PAGE_ADDS_ONE},
{0x29, "AND", IMMED, 2, 1}, /* AND */ {0x29, "AND", IMMED, 2, 0}, /* AND */
{0x25, "AND", ZEROP, 3, 1}, {0x25, "AND", ZEROP, 3, 0},
{0x35, "AND", ZEPIX, 4, 1}, {0x35, "AND", ZEPIX, 4, 0},
{0x2D, "AND", ABSOL, 4, 1}, {0x2D, "AND", ABSOL, 4, 0},
{0x3D, "AND", ABSIX, 4, 1}, {0x3D, "AND", ABSIX, 4, CYCLES_CROSS_PAGE_ADDS_ONE},
{0x39, "AND", ABSIY, 4, 1}, {0x39, "AND", ABSIY, 4, CYCLES_CROSS_PAGE_ADDS_ONE},
{0x21, "AND", INDIN, 6, 1}, {0x21, "AND", INDIN, 6, 0},
{0x31, "AND", ININD, 5, 1}, {0x31, "AND", ININD, 5, CYCLES_CROSS_PAGE_ADDS_ONE},
{0x0A, "ASL", ACCUM, 2, 0}, /* ASL */ {0x0A, "ASL", ACCUM, 2, 0}, /* ASL */
{0x06, "ASL", ZEROP, 5, 0}, {0x06, "ASL", ZEROP, 5, 0},
{0x16, "ASL", ZEPIX, 6, 0}, {0x16, "ASL", ZEPIX, 6, 0},
{0x0E, "ASL", ABSOL, 6, 0}, {0x0E, "ASL", ABSOL, 6, 0},
{0x1E, "ASL", ABSIX, 6, 0}, {0x1E, "ASL", ABSIX, 7, 0},
{0x90, "BCC", RELAT, 4, 1}, /* BCC */ {0x90, "BCC", RELAT, 2, CYCLES_CROSS_PAGE_ADDS_ONE | CYCLES_BRANCH_TAKEN_ADDS_ONE}, /* BCC */
{0xB0, "BCS", RELAT, 4, 1}, /* BCS */ {0xB0, "BCS", RELAT, 2, CYCLES_CROSS_PAGE_ADDS_ONE | CYCLES_BRANCH_TAKEN_ADDS_ONE}, /* BCS */
{0xF0, "BEQ", RELAT, 4, 1}, /* BEQ */ {0xF0, "BEQ", RELAT, 2, CYCLES_CROSS_PAGE_ADDS_ONE | CYCLES_BRANCH_TAKEN_ADDS_ONE}, /* BEQ */
{0x24, "BIT", ZEROP, 3, 0}, /* BIT */ {0x24, "BIT", ZEROP, 3, 0}, /* BIT */
{0x2C, "BIT", ABSOL, 4, 0}, {0x2C, "BIT", ABSOL, 4, 0},
{0x30, "BMI", RELAT, 4, 1}, /* BMI */ {0x30, "BMI", RELAT, 2, CYCLES_CROSS_PAGE_ADDS_ONE | CYCLES_BRANCH_TAKEN_ADDS_ONE}, /* BMI */
{0xD0, "BNE", RELAT, 4, 1}, /* BNE */ {0xD0, "BNE", RELAT, 2, CYCLES_CROSS_PAGE_ADDS_ONE | CYCLES_BRANCH_TAKEN_ADDS_ONE}, /* BNE */
{0x10, "BPL", RELAT, 4, 1}, /* BPL */ {0x10, "BPL", RELAT, 2, CYCLES_CROSS_PAGE_ADDS_ONE | CYCLES_BRANCH_TAKEN_ADDS_ONE}, /* BPL */
{0x00, "BRK", IMPLI, 7, 0}, /* BRK */ {0x00, "BRK", IMPLI, 7, 0}, /* BRK */
{0x50, "BVC", RELAT, 4, 1}, /* BVC */ {0x50, "BVC", RELAT, 2, CYCLES_CROSS_PAGE_ADDS_ONE | CYCLES_BRANCH_TAKEN_ADDS_ONE}, /* BVC */
{0x70, "BVS", RELAT, 4, 1}, /* BVS */ {0x70, "BVS", RELAT, 2, CYCLES_CROSS_PAGE_ADDS_ONE | CYCLES_BRANCH_TAKEN_ADDS_ONE}, /* BVS */
{0x18, "CLC", IMPLI, 2, 0}, /* CLC */ {0x18, "CLC", IMPLI, 2, 0}, /* CLC */
@ -133,10 +136,10 @@ opcode_t opcode_table[NUMBER_OPCODES] = {
{0xC5, "CMP", ZEROP, 3, 0}, {0xC5, "CMP", ZEROP, 3, 0},
{0xD5, "CMP", ZEPIX, 4, 0}, {0xD5, "CMP", ZEPIX, 4, 0},
{0xCD, "CMP", ABSOL, 4, 0}, {0xCD, "CMP", ABSOL, 4, 0},
{0xDD, "CMP", ABSIX, 4, 0}, {0xDD, "CMP", ABSIX, 4, CYCLES_CROSS_PAGE_ADDS_ONE},
{0xD9, "CMP", ABSIY, 4, 0}, {0xD9, "CMP", ABSIY, 4, CYCLES_CROSS_PAGE_ADDS_ONE},
{0xC1, "CMP", INDIN, 6, 0}, {0xC1, "CMP", INDIN, 6, 0},
{0xD1, "CMP", ININD, 5, 0}, {0xD1, "CMP", ININD, 5, CYCLES_CROSS_PAGE_ADDS_ONE},
{0xE0, "CPX", IMMED, 2, 0}, /* CPX */ {0xE0, "CPX", IMMED, 2, 0}, /* CPX */
{0xE4, "CPX", ZEROP, 3, 0}, {0xE4, "CPX", ZEROP, 3, 0},
@ -149,25 +152,25 @@ opcode_t opcode_table[NUMBER_OPCODES] = {
{0xC6, "DEC", ZEROP, 5, 0}, /* DEC */ {0xC6, "DEC", ZEROP, 5, 0}, /* DEC */
{0xD6, "DEC", ZEPIX, 6, 0}, {0xD6, "DEC", ZEPIX, 6, 0},
{0xCE, "DEC", ABSOL, 6, 0}, {0xCE, "DEC", ABSOL, 6, 0},
{0xDE, "DEC", ABSIX, 6, 0}, {0xDE, "DEC", ABSIX, 7, 0},
{0xCA, "DEX", IMPLI, 2, 0}, /* DEX */ {0xCA, "DEX", IMPLI, 2, 0}, /* DEX */
{0x88, "DEY", IMPLI, 2, 0}, /* DEY */ {0x88, "DEY", IMPLI, 2, 0}, /* DEY */
{0x49, "EOR", IMMED, 2, 1}, /* EOR */ {0x49, "EOR", IMMED, 2, 0}, /* EOR */
{0x45, "EOR", ZEROP, 3, 1}, {0x45, "EOR", ZEROP, 3, 0},
{0x55, "EOR", ZEPIX, 4, 1}, {0x55, "EOR", ZEPIX, 4, 0},
{0x4D, "EOR", ABSOL, 4, 1}, {0x4D, "EOR", ABSOL, 4, 0},
{0x5D, "EOR", ABSIX, 4, 1}, {0x5D, "EOR", ABSIX, 4, CYCLES_CROSS_PAGE_ADDS_ONE},
{0x59, "EOR", ABSIY, 4, 1}, {0x59, "EOR", ABSIY, 4, CYCLES_CROSS_PAGE_ADDS_ONE},
{0x41, "EOR", INDIN, 6, 1}, {0x41, "EOR", INDIN, 6, 1},
{0x51, "EOR", ININD, 5, 1}, {0x51, "EOR", ININD, 5, CYCLES_CROSS_PAGE_ADDS_ONE},
{0xE6, "INC", ZEROP, 5, 0}, /* INC */ {0xE6, "INC", ZEROP, 5, 0}, /* INC */
{0xF6, "INC", ZEPIX, 6, 0}, {0xF6, "INC", ZEPIX, 6, 0},
{0xEE, "INC", ABSOL, 6, 0}, {0xEE, "INC", ABSOL, 6, 0},
{0xFE, "INC", ABSIX, 6, 0}, {0xFE, "INC", ABSIX, 7, 0},
{0xE8, "INX", IMPLI, 2, 0}, /* INX */ {0xE8, "INX", IMPLI, 2, 0}, /* INX */
@ -178,32 +181,32 @@ opcode_t opcode_table[NUMBER_OPCODES] = {
{0x20, "JSR", ABSOL, 6, 0}, /* JSR */ {0x20, "JSR", ABSOL, 6, 0}, /* JSR */
{0xA9, "LDA", IMMED, 2, 1}, /* LDA */ {0xA9, "LDA", IMMED, 2, 0}, /* LDA */
{0xA5, "LDA", ZEROP, 3, 1}, {0xA5, "LDA", ZEROP, 3, 0},
{0xB5, "LDA", ZEPIX, 4, 1}, {0xB5, "LDA", ZEPIX, 4, 0},
{0xAD, "LDA", ABSOL, 4, 1}, {0xAD, "LDA", ABSOL, 4, 0},
{0xBD, "LDA", ABSIX, 4, 1}, {0xBD, "LDA", ABSIX, 4, CYCLES_CROSS_PAGE_ADDS_ONE},
{0xB9, "LDA", ABSIY, 4, 1}, {0xB9, "LDA", ABSIY, 4, CYCLES_CROSS_PAGE_ADDS_ONE},
{0xA1, "LDA", INDIN, 6, 1}, {0xA1, "LDA", INDIN, 6, 0},
{0xB1, "LDA", ININD, 5, 1}, {0xB1, "LDA", ININD, 5, CYCLES_CROSS_PAGE_ADDS_ONE},
{0xA2, "LDX", IMMED, 2, 1}, /* LDX */ {0xA2, "LDX", IMMED, 2, 0}, /* LDX */
{0xA6, "LDX", ZEROP, 3, 1}, {0xA6, "LDX", ZEROP, 3, 0},
{0xB6, "LDX", ZEPIY, 4, 1}, {0xB6, "LDX", ZEPIY, 4, 0},
{0xAE, "LDX", ABSOL, 4, 1}, {0xAE, "LDX", ABSOL, 4, 0},
{0xBE, "LDX", ABSIY, 4, 1}, {0xBE, "LDX", ABSIY, 4, CYCLES_CROSS_PAGE_ADDS_ONE},
{0xA0, "LDY", IMMED, 2, 1}, /* LDY */ {0xA0, "LDY", IMMED, 2, 0}, /* LDY */
{0xA4, "LDY", ZEROP, 3, 1}, {0xA4, "LDY", ZEROP, 3, 0},
{0xB4, "LDY", ZEPIX, 4, 1}, {0xB4, "LDY", ZEPIX, 4, 0},
{0xAC, "LDY", ABSOL, 4, 1}, {0xAC, "LDY", ABSOL, 4, 0},
{0xBC, "LDY", ABSIX, 4, 1}, {0xBC, "LDY", ABSIX, 4, CYCLES_CROSS_PAGE_ADDS_ONE},
{0x4A, "LSR", ACCUM, 2, 0}, /* LSR */ {0x4A, "LSR", ACCUM, 2, 0}, /* LSR */
{0x46, "LSR", ZEROP, 5, 0}, {0x46, "LSR", ZEROP, 5, 0},
{0x56, "LSR", ZEPIX, 6, 0}, {0x56, "LSR", ZEPIX, 6, 0},
{0x4E, "LSR", ABSOL, 6, 0}, {0x4E, "LSR", ABSOL, 6, 0},
{0x5E, "LSR", ABSIX, 6, 0}, {0x5E, "LSR", ABSIX, 7, 0},
{0xEA, "NOP", IMPLI, 2, 0}, /* NOP */ {0xEA, "NOP", IMPLI, 2, 0}, /* NOP */
@ -211,10 +214,10 @@ opcode_t opcode_table[NUMBER_OPCODES] = {
{0x05, "ORA", ZEROP, 3, 0}, {0x05, "ORA", ZEROP, 3, 0},
{0x15, "ORA", ZEPIX, 4, 0}, {0x15, "ORA", ZEPIX, 4, 0},
{0x0D, "ORA", ABSOL, 4, 0}, {0x0D, "ORA", ABSOL, 4, 0},
{0x1D, "ORA", ABSIX, 4, 0}, {0x1D, "ORA", ABSIX, 4, CYCLES_CROSS_PAGE_ADDS_ONE},
{0x19, "ORA", ABSIY, 4, 0}, {0x19, "ORA", ABSIY, 4, CYCLES_CROSS_PAGE_ADDS_ONE},
{0x01, "ORA", INDIN, 6, 0}, {0x01, "ORA", INDIN, 6, 0},
{0x11, "ORA", ININD, 5, 0}, {0x11, "ORA", ININD, 5, CYCLES_CROSS_PAGE_ADDS_ONE},
{0x48, "PHA", IMPLI, 3, 0}, /* PHA */ {0x48, "PHA", IMPLI, 3, 0}, /* PHA */
@ -228,26 +231,26 @@ opcode_t opcode_table[NUMBER_OPCODES] = {
{0x26, "ROL", ZEROP, 5, 0}, {0x26, "ROL", ZEROP, 5, 0},
{0x36, "ROL", ZEPIX, 6, 0}, {0x36, "ROL", ZEPIX, 6, 0},
{0x2E, "ROL", ABSOL, 6, 0}, {0x2E, "ROL", ABSOL, 6, 0},
{0x3E, "ROL", ABSIX, 6, 0}, {0x3E, "ROL", ABSIX, 7, 0},
{0x6A, "ROR", ACCUM, 2, 0}, /* ROR */ {0x6A, "ROR", ACCUM, 2, 0}, /* ROR */
{0x66, "ROR", ZEROP, 5, 0}, {0x66, "ROR", ZEROP, 5, 0},
{0x76, "ROR", ZEPIX, 6, 0}, {0x76, "ROR", ZEPIX, 6, 0},
{0x6E, "ROR", ABSOL, 6, 0}, {0x6E, "ROR", ABSOL, 6, 0},
{0x7E, "ROR", ABSIX, 6, 0}, {0x7E, "ROR", ABSIX, 7, 0},
{0x40, "RTI", IMPLI, 6, 0}, /* RTI */ {0x40, "RTI", IMPLI, 6, 0}, /* RTI */
{0x60, "RTS", IMPLI, 6, 0}, /* RTS */ {0x60, "RTS", IMPLI, 6, 0}, /* RTS */
{0xE9, "SBC", IMMED, 2, 1}, /* SBC */ {0xE9, "SBC", IMMED, 2, 0}, /* SBC */
{0xE5, "SBC", ZEROP, 3, 1}, {0xE5, "SBC", ZEROP, 3, 0},
{0xF5, "SBC", ZEPIX, 4, 1}, {0xF5, "SBC", ZEPIX, 4, 0},
{0xED, "SBC", ABSOL, 4, 1}, {0xED, "SBC", ABSOL, 4, 0},
{0xFD, "SBC", ABSIX, 4, 1}, {0xFD, "SBC", ABSIX, 4, CYCLES_CROSS_PAGE_ADDS_ONE},
{0xF9, "SBC", ABSIY, 4, 1}, {0xF9, "SBC", ABSIY, 4, CYCLES_CROSS_PAGE_ADDS_ONE},
{0xE1, "SBC", INDIN, 6, 1}, {0xE1, "SBC", INDIN, 6, 0},
{0xF1, "SBC", ININD, 5, 1}, {0xF1, "SBC", ININD, 5, CYCLES_CROSS_PAGE_ADDS_ONE},
{0x38, "SEC", IMPLI, 2, 0}, /* SEC */ {0x38, "SEC", IMPLI, 2, 0}, /* SEC */
@ -258,10 +261,10 @@ opcode_t opcode_table[NUMBER_OPCODES] = {
{0x85, "STA", ZEROP, 3, 0}, /* STA */ {0x85, "STA", ZEROP, 3, 0}, /* STA */
{0x95, "STA", ZEPIX, 4, 0}, {0x95, "STA", ZEPIX, 4, 0},
{0x8D, "STA", ABSOL, 4, 0}, {0x8D, "STA", ABSOL, 4, 0},
{0x9D, "STA", ABSIX, 4, 0}, {0x9D, "STA", ABSIX, 4, CYCLES_CROSS_PAGE_ADDS_ONE},
{0x99, "STA", ABSIY, 4, 0}, {0x99, "STA", ABSIY, 4, CYCLES_CROSS_PAGE_ADDS_ONE},
{0x81, "STA", INDIN, 6, 0}, {0x81, "STA", INDIN, 6, 0},
{0x91, "STA", ININD, 5, 0}, {0x91, "STA", ININD, 5, CYCLES_CROSS_PAGE_ADDS_ONE},
{0x86, "STX", ZEROP, 3, 0}, /* STX */ {0x86, "STX", ZEROP, 3, 0}, /* STX */
{0x96, "STX", ZEPIY, 4, 0}, {0x96, "STX", ZEPIY, 4, 0},
@ -286,7 +289,7 @@ opcode_t opcode_table[NUMBER_OPCODES] = {
/* This function emits a comment header with information about the file /* This function emits a comment header with information about the file
being disassembled */ being disassembled */
void emit_header(options_t *options, int fsize) { static void emit_header(options_t *options, int fsize) {
fprintf(stdout, "; Source generated by DCC6502 version %s\n", VERSION_INFO); fprintf(stdout, "; Source generated by DCC6502 version %s\n", VERSION_INFO);
fprintf(stdout, "; For more info about DCC6502, see https://github.com/tcarmelveilleux/dcc6502\n"); fprintf(stdout, "; For more info about DCC6502, see https://github.com/tcarmelveilleux/dcc6502\n");
fprintf(stdout, "; FILENAME: %s, File Size: %d, ORG: $%04X\n", options->filename, fsize, options->org); fprintf(stdout, "; FILENAME: %s, File Size: %d, ORG: $%04X\n", options->filename, fsize, options->org);
@ -296,15 +299,36 @@ void emit_header(options_t *options, int fsize) {
fprintf(stdout, ";---------------------------------------------------------------------------\n"); fprintf(stdout, ";---------------------------------------------------------------------------\n");
} }
/* This function appends cycle counting to the comment block */ /* This function appends cycle counting to the comment block. See following
char *append_cycle(char *input, uint8_t entry) { * for methods used:
* "Nick Bensema's Guide to Cycle Counting on the Atari 2600"
* http://www.alienbill.com/2600/cookbook/cycles/nickb.txt
*/
static char *append_cycle(char *input, uint8_t entry, uint16_t pc, uint16_t new_pc) {
char tmpstr[256]; char tmpstr[256];
int cycles = opcode_table[entry].cycles; int cycles = g_opcode_table[entry].cycles;
int exceptions = g_opcode_table[entry].cycles_exceptions;
int crosses_page = ((pc & 0xff00u) != (new_pc & 0xff00u)) ? 1 : 0;
// On page boundary crossing, instruction will take an extra cycle // On some exceptional conditions, instruction will take an extra cycle, or even two
if (opcode_table[entry].cross_page) { if (exceptions != 0) {
sprintf(tmpstr, " Cycles: %d/%d", cycles, cycles + 1); if ((exceptions & CYCLES_BRANCH_TAKEN_ADDS_ONE) && (exceptions & CYCLES_CROSS_PAGE_ADDS_ONE)) {
/* Branch case: check for page crossing, since it can be determined
* statically from the relative offset and current PC.
*/
if (crosses_page) {
/* Crosses page, always at least 1 extra cycle, two times */
sprintf(tmpstr, " Cycles: %d/%d", cycles + 1, cycles + 2);
} else {
/* Does not cross page, maybe one extra cycle if branch taken */
sprintf(tmpstr, " Cycles: %d/%d", cycles, cycles + 1);
}
} else {
/* One exception: two times, can't tell in advance whether page crossing occurs */
sprintf(tmpstr, " Cycles: %d/%d", cycles, cycles + 1);
}
} else { } else {
/* No exceptions, no extra time */
sprintf(tmpstr, " Cycles: %d", cycles); sprintf(tmpstr, " Cycles: %d", cycles);
} }
@ -312,13 +336,13 @@ char *append_cycle(char *input, uint8_t entry) {
return (input + strlen(input)); return (input + strlen(input));
} }
void add_nes_str(char *instr, char *instr2) { static void add_nes_str(char *instr, char *instr2) {
strcat(instr, " [NES] "); strcat(instr, " [NES] ");
strcat(instr, instr2); strcat(instr, instr2);
} }
/* This function put NES-specific info in the comment block */ /* This function put NES-specific info in the comment block */
void append_nes(char *input, uint16_t arg) { static void append_nes(char *input, uint16_t arg) {
switch(arg) { switch(arg) {
case 0x2000: add_nes_str(input, "PPU setup #1"); break; case 0x2000: add_nes_str(input, "PPU setup #1"); break;
case 0x2001: add_nes_str(input, "PPU setup #2"); break; case 0x2001: add_nes_str(input, "PPU setup #2"); break;
@ -354,13 +378,14 @@ void append_nes(char *input, uint16_t arg) {
} }
} }
/* Helper macros for disassemble() function */
#define DUMP_FORMAT (options->hex_output ? "%-16s%-16s;" : "%-8s%-16s;") #define DUMP_FORMAT (options->hex_output ? "%-16s%-16s;" : "%-8s%-16s;")
#define HIGH_PART(val) (((val) >> 8) & 0xFFu) #define HIGH_PART(val) (((val) >> 8) & 0xFFu)
#define LOW_PART(val) ((val) & 0xFFu) #define LOW_PART(val) ((val) & 0xFFu)
#define LOAD_WORD(buffer, current_pc) ((uint16_t)buffer[(current_pc) + 1] | (((uint16_t)buffer[(current_pc) + 2]) << 8)) #define LOAD_WORD(buffer, current_pc) ((uint16_t)buffer[(current_pc) + 1] | (((uint16_t)buffer[(current_pc) + 2]) << 8))
/* 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, uint8_t *buffer, options_t *options, uint16_t *pc) { static void disassemble(char *output, uint8_t *buffer, options_t *options, uint16_t *pc) {
char opcode_repr[256], hex_dump[256]; char opcode_repr[256], hex_dump[256];
int opcode_idx; int opcode_idx;
int len = 0; int len = 0;
@ -377,17 +402,16 @@ void disassemble(char *output, uint8_t *buffer, options_t *options, uint16_t *pc
// Linear search for opcode // Linear search for opcode
for (opcode_idx = 0; opcode_idx < NUMBER_OPCODES; opcode_idx++) { for (opcode_idx = 0; opcode_idx < NUMBER_OPCODES; opcode_idx++) {
if (opcode == opcode_table[opcode_idx].number) { if (opcode == g_opcode_table[opcode_idx].number) {
/* Found the opcode, record its table index */ /* Found the opcode, record its table index */
found = 1; found = 1;
entry = opcode_idx; entry = opcode_idx;
} }
} }
// TODO: Normalize %02x versus %02X
// For opcode not found, terminate early // For opcode not found, terminate early
if (!found) { if (!found) {
sprintf(opcode_repr, ".byte $%02x", opcode); sprintf(opcode_repr, ".byte $%02X", opcode);
if (options->hex_output) { if (options->hex_output) {
sprintf(hex_dump, "$%04X> %02X:", current_addr, opcode); sprintf(hex_dump, "$%04X> %02X:", current_addr, opcode);
sprintf(output, "%-16s%-16s; INVALID OPCODE !!!\n", hex_dump, opcode_repr); sprintf(output, "%-16s%-16s; INVALID OPCODE !!!\n", hex_dump, opcode_repr);
@ -399,19 +423,19 @@ void disassemble(char *output, uint8_t *buffer, options_t *options, uint16_t *pc
} }
// Opcode found in table: disassemble properly according to addressing mode // Opcode found in table: disassemble properly according to addressing mode
mnemonic = opcode_table[entry].mnemonic; mnemonic = g_opcode_table[entry].mnemonic;
// Set hex dump to default single address format. Will be overwritten // Set hex dump to default single address format. Will be overwritten
// by more complex output in case of hex dump mode enabled // by more complex output in case of hex dump mode enabled
sprintf(hex_dump, "$%04X", current_addr); sprintf(hex_dump, "$%04X", current_addr);
switch (opcode_table[entry].addressing) { switch (g_opcode_table[entry].addressing) {
case IMMED: case IMMED:
/* Get immediate value operand */ /* Get immediate value operand */
byte_operand = buffer[*pc + 1]; byte_operand = buffer[*pc + 1];
*pc += 1; *pc += 1;
sprintf(opcode_repr, "%s #$%02x", mnemonic, byte_operand); sprintf(opcode_repr, "%s #$%02X", mnemonic, byte_operand);
if (options->hex_output) { if (options->hex_output) {
sprintf(hex_dump, "$%04X> %02X %02X:", current_addr, opcode, byte_operand); sprintf(hex_dump, "$%04X> %02X %02X:", current_addr, opcode, byte_operand);
} }
@ -554,16 +578,17 @@ void disassemble(char *output, uint8_t *buffer, options_t *options, uint16_t *pc
break; break;
} }
// Emit disassembly line content, prior to annotation comments
len = sprintf(output, DUMP_FORMAT, hex_dump, opcode_repr); len = sprintf(output, DUMP_FORMAT, hex_dump, opcode_repr);
output += len; output += len;
/* Add cycle count if necessary */ /* Add cycle count if necessary */
if (options->cycle_counting) { if (options->cycle_counting) {
output = append_cycle(output, entry); output = append_cycle(output, entry, *pc + 1, word_operand);
} }
/* Add NES port info if necessary */ /* Add NES port info if necessary */
switch (opcode_table[entry].addressing) { switch (g_opcode_table[entry].addressing) {
case ABSOL: case ABSOL:
case ABSIX: case ABSIX:
case ABSIY: case ABSIY:
@ -577,13 +602,13 @@ void disassemble(char *output, uint8_t *buffer, options_t *options, uint16_t *pc
} }
} }
void version(void) { static void version(void) {
fprintf(stderr, "DCC6502 %s (C)1998-2014 Tennessee Carmel-Veilleux <veilleux@tentech.ca>\n", VERSION_INFO); fprintf(stderr, "DCC6502 %s (C)1998-2014 Tennessee Carmel-Veilleux <veilleux@tentech.ca>\n", VERSION_INFO);
fprintf(stderr, "This software is licensed under the MIT license. See the LICENSE file.\n"); fprintf(stderr, "This software is licensed under the MIT license. See the LICENSE file.\n");
fprintf(stderr, "See source on github: https://github.com/tcarmelveilleux/dcc6502.\n"); fprintf(stderr, "See source on github: https://github.com/tcarmelveilleux/dcc6502.\n");
} }
void usage(void) { static void usage(void) {
fprintf(stderr, "Usage: dcc6502 [options] FILENAME"); fprintf(stderr, "Usage: dcc6502 [options] FILENAME");
fprintf(stderr, " -?/-h : Show this help message\n"); fprintf(stderr, " -?/-h : Show this help message\n");
fprintf(stderr, " -o ORIGIN : Set the origin (base address of disassembly) [default: 0x8000]\n"); fprintf(stderr, " -o ORIGIN : Set the origin (base address of disassembly) [default: 0x8000]\n");
@ -595,7 +620,7 @@ void usage(void) {
fprintf(stderr, "\n"); fprintf(stderr, "\n");
} }
unsigned long str_arg_to_ulong(char *str, unsigned long default_val) { static unsigned long str_arg_to_ulong(char *str, unsigned long default_val) {
uint32_t tmp = 0; uint32_t tmp = 0;
errno = EOK; errno = EOK;
@ -609,7 +634,7 @@ unsigned long str_arg_to_ulong(char *str, unsigned long default_val) {
} }
} }
void usage_and_exit(int exit_code, const char *message) { static void usage_and_exit(int exit_code, const char *message) {
version(); version();
usage(); usage();
if (NULL != message) { if (NULL != message) {
@ -618,7 +643,7 @@ void usage_and_exit(int exit_code, const char *message) {
exit(exit_code); exit(exit_code);
} }
void parse_args(int argc, char *argv[], options_t *options) { static void parse_args(int argc, char *argv[], options_t *options) {
int arg_idx = 1; int arg_idx = 1;
options->cycle_counting = 0; options->cycle_counting = 0;