Started main clean-up of version 1.6
* Fixed all compiler warnings * Killed union usage * Started using C99 fixed width types * Started normalization of whitespace width in listing * Simplified internal addresses computations
This commit is contained in:
parent
e19fc4568c
commit
7985830ecd
156
dcc6502.c
156
dcc6502.c
|
@ -27,6 +27,8 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#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--) {
|
||||
|
|
Loading…
Reference in New Issue