diff --git a/dcc6502.c b/dcc6502.c index 031a657..00bc7f3 100644 --- a/dcc6502.c +++ b/dcc6502.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include #define VERSION_INFO "v1.6" #define NUMBER_OPCODES 151 @@ -46,26 +48,16 @@ #define RELAT 11 /* Relative */ #define ACCUM 12 /* Accumulator */ -#define LSB_FIRST - typedef struct OPcode { - unsigned char number; /* Number of the opcode */ - unsigned char name; /* Index in the name table */ - unsigned char addressing; /* Addressing mode */ - unsigned char cycles; /* Number of cycles */ - unsigned char cross_page; /* 1 if cross-page boundaries affect cycles */ + uint8_t number; /* Number of the opcode */ + unsigned int name; /* Index in the name table */ + // FIXME: Transform toe num + unsigned int addressing; /* Addressing mode */ + unsigned int cycles; /* Number of cycles */ + unsigned int cross_page; /* 1 if cross-page boundaries affect cycles */ } OPcode; -// FIXME: Stop using the needless union and become native-endianness-agnostic -typedef union -{ -#ifdef LSB_FIRST - struct { unsigned char l, h; } B; -#else - struct { byte h, l; } B; -#endif - unsigned short W; -} word; +typedef uint16_t word; char name_table[56][4] = { "ADC", "AND", "ASL", "BCC", "BCS", "BEQ", "BIT", "BMI", "BNE", "BPL", @@ -288,20 +280,20 @@ OPcode opcode_table[NUMBER_OPCODES] = { // FIXME: use stdint types // FIXME: use g_ nomenclature for globals -unsigned short org; /* Origin of addresses */ -char hex_output = 0; /* 1 if hex output is desired at beginning of line */ -char cycle_counting = 0; /* 1 if we want cycle counting */ -char nes_mode = 0; /* 1 if NES commenting and warnings are enabled */ +uint16_t org; /* Origin of addresses */ +int hex_output = 0; /* 1 if hex output is desired at beginning of line */ +int cycle_counting = 0; /* 1 if we want cycle counting */ +int nes_mode = 0; /* 1 if NES commenting and warnings are enabled */ FILE *f; /* Input file */ -unsigned char buffer[0xffff]; /* Memory buffer */ -unsigned short PC = 0; /* Program counter */ -unsigned short max = 0xffff; /* Maximum number of bytes to disassemble */ +uint8_t buffer[0xffff]; /* Memory buffer */ +uint16_t PC = 0; /* Program counter */ +uint16_t max = 0xffff; /* Maximum number of bytes to disassemble */ char line[512]; /* This function emits a comment header with information about the file being disassembled */ -void emit_header(char *filename, int fsize, unsigned short org) { +void emit_header(char *filename, int fsize, uint16_t org) { 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, "; FILENAME: %s, File Size: %d, ORG: $%04X\n", filename, fsize, org); @@ -312,16 +304,17 @@ void emit_header(char *filename, int fsize, unsigned short org) { } /* This function appends cycle counting to the comment block */ -void append_cycle(char *input, unsigned char entry, unsigned short arg, unsigned short cur_PC) { +void append_cycle(char *input, uint8_t entry, uint16_t arg, uint16_t cur_PC) { char tmpstr[256]; - int cycles = 0; + int cycles = opcode_table[entry].cycles; - cycles = opcode_table[entry].cycles; - - sprintf(tmpstr, " Cycles: %d ", cycles); + // On page boundary crossing, instruction will take an extra cycle if (opcode_table[entry].cross_page) { - strcat(tmpstr, "*!* "); + sprintf(tmpstr, " Cycles: %d/%d", cycles, cycles + 1); + } else { + sprintf(tmpstr, " Cycles: %d", cycles); } + strcat(input, tmpstr); } @@ -331,7 +324,7 @@ void add_nes_str(char *instr, char *instr2) { } /* This function put NES-specific info in the comment block */ -void append_nes(char *input, unsigned short arg) { +void append_nes(char *input, uint16_t arg) { switch(arg) { case 0x2000: add_nes_str(input, "PPU setup #1"); break; case 0x2001: add_nes_str(input, "PPU setup #2"); break; @@ -367,18 +360,24 @@ void append_nes(char *input, unsigned short arg) { } } +#define DUMP_FORMAT (hex_output ? "%-16s%-16s;" : "%-8s%-16s;") +#define HIGH_PART(val) (((val) >> 8) & 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)) + // FIXME: Refactor code to reduce line duplication and make more readable /* This function disassembles the opcode at the PC and outputs it in *output */ void disassemble(char *output) { - unsigned char tmp_byte1, tmp_byte2, opcode; - char argument_signed; + uint8_t tmp_byte1, opcode; + char tmpstr[256], opcode_repr[256], hex_dump[256]; word tmp_word; + int i; + int entry = 0; + int found = 0; + int len = 0; + unsigned int current_addr = org + PC; - char tmpstr[256], tmpstr2[256], tmpstr3[256]; - - int i, entry, found = 0; - - opcode = buffer[PC]; + opcode = buffer[current_addr - org]; for (i = 0; i < NUMBER_OPCODES; i++) { if (opcode == opcode_table[i].number) { @@ -388,52 +387,56 @@ void disassemble(char *output) { } if (!found) { + sprintf(opcode_repr, ".byte $%02x", opcode); if (hex_output) { - sprintf(tmpstr, "$%04X> %02X:\t.byte $%02x\t\t; INVALID OPCODE !!!\n", org+PC, opcode, opcode); - strncpy(output, tmpstr, 254); + sprintf(hex_dump, "$%04X> %02X:", current_addr, opcode); + len = sprintf(output, "%-16s%-16s; INVALID OPCODE !!!\n", hex_dump, opcode_repr); } else { - sprintf(tmpstr, "$%04X\t.byte $%02x\t; INVALID OPCODE !!!\n", org+PC, opcode); - strncpy(output, tmpstr, 254); + sprintf(hex_dump, "$%04X", current_addr); + len = sprintf(output, "%-8s%-16s; INVALID OPCODE !!!\n", hex_dump, opcode_repr); } + output += len; } else { switch (opcode_table[entry].addressing) { case IMMED: - PC++; - tmp_byte1 = buffer[PC]; /* Get immediate value */ + tmp_byte1 = buffer[PC + 1]; /* Get immediate value */ + + sprintf(opcode_repr, "%s #$%02x", name_table[opcode_table[entry].name], tmp_byte1); if (hex_output) { - sprintf(tmpstr, "$%04X> %02X %02X:\t%s #$%02x\t;", org+PC-1, opcode, tmp_byte1, name_table[opcode_table[entry].name], tmp_byte1); + sprintf(hex_dump, "$%04X> %02X %02X:", current_addr, opcode, tmp_byte1); } else { - sprintf(tmpstr, "$%04X\t%s #$%02x\t;", org+PC-1, name_table[opcode_table[entry].name], tmp_byte1); + sprintf(hex_dump, "$%04X", current_addr); } + len = sprintf(output, DUMP_FORMAT, hex_dump, opcode_repr); + output += len; /* Add cycle count if necessary */ if (cycle_counting) { - append_cycle(tmpstr, entry, org+PC-1, org+PC-1); + append_cycle(output, entry, current_addr, current_addr); } - strncpy(output, tmpstr, 254); + PC++; break; case ABSOL: - PC++; - tmp_word.B.l = buffer[PC]; /* Get low byte of address */ - PC++; - tmp_word.B.h = buffer[PC]; /* Get high byte of address */ + /* Get address */ + tmp_word = LOAD_WORD(buffer, PC); if (hex_output) - sprintf(tmpstr, "$%04X> %02X %02X%02X:\t%s $%02X%02X\t;", org+PC-2, opcode, tmp_word.B.l, tmp_word.B.h, name_table[opcode_table[entry].name], tmp_word.B.h, tmp_word.B.l); + sprintf(tmpstr, "$%04X> %02X %02X%02X:\t%s $%02X%02X\t;", current_addr, opcode, LOW_PART(tmp_word), HIGH_PART(tmp_word), name_table[opcode_table[entry].name], HIGH_PART(tmp_word), LOW_PART(tmp_word)); else - sprintf(tmpstr, "$%04X\t%s $%02X%02X\t;", org+PC-2, name_table[opcode_table[entry].name], tmp_word.B.h, tmp_word.B.l); + sprintf(tmpstr, "$%04X\t%s $%02X%02X\t;", current_addr, name_table[opcode_table[entry].name], HIGH_PART(tmp_word), LOW_PART(tmp_word)); /* Add cycle count if necessary */ if (cycle_counting) { - append_cycle(tmpstr, entry, tmp_word.W, org+PC-2); + append_cycle(tmpstr, entry, tmp_word, current_addr); } /* Add NES port info if necessary */ if (nes_mode) { - append_nes(tmpstr, tmp_word.W); + append_nes(tmpstr, tmp_word); } strncpy(output, tmpstr, 254); + PC += 2; break; case ZEROP: @@ -471,19 +474,18 @@ void disassemble(char *output) { case INDIA: PC++; - tmp_word.B.l = buffer[PC]; /* Get low byte of address */ PC++; - tmp_word.B.h = buffer[PC]; /* Get high byte of address */ + tmp_word = LOAD_WORD(buffer, PC-2); if (hex_output) { - sprintf(tmpstr, "$%04X> %02X %02X%02X:\t%s ($%02X%02X)\t;", org+PC-2, opcode, tmp_word.B.l, tmp_word.B.h, name_table[opcode_table[entry].name], tmp_word.B.h, tmp_word.B.l); + 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)); } else { - sprintf(tmpstr, "$%04X\t%s ($%02X%02X)\t;", org+PC-2, name_table[opcode_table[entry].name], tmp_word.B.h, tmp_word.B.l); + 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)); } /* Add cycle count if necessary */ if (cycle_counting) { - append_cycle(tmpstr, entry, tmp_word.W, org+PC-2); + append_cycle(tmpstr, entry, tmp_word, org+PC-2); } strncpy(output, tmpstr, 254); @@ -491,24 +493,23 @@ void disassemble(char *output) { case ABSIX: PC++; - tmp_word.B.l = buffer[PC]; /* Get low byte of address */ PC++; - tmp_word.B.h = buffer[PC]; /* Get high byte of address */ + tmp_word = LOAD_WORD(buffer, PC-2); if (hex_output) { - sprintf(tmpstr, "$%04X> %02X %02X%02X:\t%s $%02X%02X,X\t;", org+PC-2, opcode, tmp_word.B.l, tmp_word.B.h, name_table[opcode_table[entry].name], tmp_word.B.h, tmp_word.B.l); + 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)); } else { - sprintf(tmpstr, "$%04X\t%s $%02X%02X,X\t;", org+PC-2, name_table[opcode_table[entry].name], tmp_word.B.h, tmp_word.B.l); + 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)); } /* Add cycle count if necessary */ if (cycle_counting) { - append_cycle(tmpstr, entry, tmp_word.W, org+PC-2); + append_cycle(tmpstr, entry, tmp_word, org+PC-2); } /* Add NES port info if necessary */ if (nes_mode) { - append_nes(tmpstr, tmp_word.W); + append_nes(tmpstr, tmp_word); } strncpy(output, tmpstr, 254); @@ -516,24 +517,23 @@ void disassemble(char *output) { case ABSIY: PC++; - tmp_word.B.l = buffer[PC]; /* Get low byte of address */ PC++; - tmp_word.B.h = buffer[PC]; /* Get high byte of address */ + tmp_word = LOAD_WORD(buffer, PC-2); if (hex_output) { - sprintf(tmpstr, "$%04X> %02X %02X%02X:\t%s $%02X%02X,Y\t;", org+PC-2, opcode, tmp_word.B.l, tmp_word.B.h, name_table[opcode_table[entry].name], tmp_word.B.h, tmp_word.B.l); + 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)); } else { - sprintf(tmpstr, "$%04X\t%s $%02X%02X,Y\t;", org+PC-2, name_table[opcode_table[entry].name], tmp_word.B.h, tmp_word.B.l); + 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)); } /* Add cycle count if necessary */ if (cycle_counting) { - append_cycle(tmpstr, entry, tmp_word.W, org+PC-2); + append_cycle(tmpstr, entry, tmp_word, org+PC-2); } /* Add NES port info if necessary */ if (nes_mode) { - append_nes(tmpstr, tmp_word.W); + append_nes(tmpstr, tmp_word); } strncpy(output, tmpstr, 254); @@ -660,6 +660,7 @@ void usage_helper(char *str) { fprintf(stderr, "\t%s\n", str); } +// FIXME: add command line sample void usage(void) { usage_helper("-? -> Show this help message"); usage_helper("-oXXXX -> Set the origin (ORG) [dfl: $8000]"); @@ -672,11 +673,12 @@ void usage(void) { } // FIXME: DE-KLUDGIFY THIS :D -unsigned short hex2int (char *str, unsigned short dfl) { +uint16_t hex2int (char *str, uint16_t dfl) { char HEX_digits[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; int i, j; - char c, k, shift; - unsigned short tmp = 0; + char k = 0; + char c, shift; + uint16_t tmp = 0; shift = 0; for (i = 5; i >= 2; i--) {