#include "config.h" #include #include #include #include #ifdef HAVE_LIBGEN_H # include #endif /* HAVE_LIBGEN_H */ #include "lib/op.h" #define OP_ADDR_MODE (OP_ADDR_IMPL | OP_ADDR_REL | OP_ADDR_IND \ | OP_ADDR_IMM | OP_ADDR_ABS) char *prg_name; FILE *input; FILE *output; uint8_t readu8(void) { uint8_t val; if (fread(&val, 1, 1, input) != 1) { return (-1); /* XXX: TODO */ } return (val); } uint16_t readu16(void) { uint16_t val; if (fread(&val, 1, 2, input) != 2) { return (-1); /* XXX: TODO */ } return (val); } uint32_t readu32(void) { uint32_t val; if (fread(&val, 1, 4, input) != 4) { return (-1); /* XXX: TODO */ } return (val); } int16_t read16(void) { int16_t val; if (fread(&val, 1, 2, input) != 2) { return (-1); /* XXX: TODO */ } return (val); } int32_t read32(void) { int32_t val; if (fread(&val, 1, 4, input) != 4) { return (-1); /* XXX: TODO */ } return (val); } void fatal(const char *str, ...) { va_list ap; fprintf(stderr, "%s: ", prg_name); va_start(ap, str); vfprintf(stderr, str, ap); va_end(ap); fprintf(stderr, "\n"); exit(EXIT_FAILURE); } void decode_target_suffix(uint8_t attr) { fprintf(output, "."); if (IS_TARGET_ZEXT(attr)) { fprintf(output, "U"); } switch (GET_TARGET_SIZE(attr)) { case SIZE_BYTE: fprintf(output, "B"); break; case SIZE_WORD: fprintf(output, "W"); break; case SIZE_LONG: fprintf(output, "L"); break; } } void decode_address(uint8_t attr) { switch (GET_ADDRESS_SIZE(attr)) { case SIZE_BYTE: fprintf(output, " %%%X", readu8()); break; case SIZE_WORD: fprintf(output, " %%%hX", readu16()); break; case SIZE_LONG: fprintf(output, " %%%X", readu32()); break; default: break; } } void decode_imm(uint8_t opcode) { uint8_t attr; attr = readu8(); fprintf(output, "%s", opcode_str[opcode]); decode_target_suffix(attr); switch (GET_TARGET_SIZE(attr)) { case SIZE_BYTE: fprintf(output, " #$%X\n", readu8()); break; case SIZE_WORD: fprintf(output, " #$%hX\n", readu16()); break; case SIZE_LONG: fprintf(output, " #$%X\n", readu32()); break; default: break; } } void decode_ind(uint8_t opcode) { uint8_t attr; fprintf(output, "%s", opcode_str[opcode]); attr = readu8(); if (opcode != OP_JMP_ind) { decode_target_suffix(attr); } if (opcode_addr[opcode] & (OP_ADDR_X | OP_ADDR_Y)) { fprintf(output, " ("); } else { fprintf(output, " "); } decode_address(attr); if (opcode_addr[opcode] & OP_ADDR_X) { fprintf(output, ", X)"); } else if (opcode_addr[opcode] & OP_ADDR_Y) { fprintf(output, "), Y"); } fprintf(output, "\n"); } void decode_abs(uint8_t opcode) { uint8_t attr; fprintf(output, "%s", opcode_str[opcode]); attr = readu8(); if (opcode != OP_JSR_abs || opcode != OP_JMP_abs) { decode_target_suffix(attr); } decode_address(attr); if (opcode_addr[opcode] & OP_ADDR_X) { fprintf(output, ", X"); } else if (opcode_addr[opcode] & OP_ADDR_Y) { fprintf(output, ", Y"); } fprintf(output, "\n"); } void decode(void) { uint8_t opcode; int16_t relative; do { opcode = readu8(); if (feof(input)) return; switch (opcode_addr[opcode] & OP_ADDR_MODE) { case OP_ADDR_IMPL: if (opcode_addr[opcode] & OP_ADDR_A) { fprintf(output, "%s A\n", opcode_str[opcode]); } else { fprintf(output, "%s\n", opcode_str[opcode]); } break; case OP_ADDR_REL: relative = read16(); fprintf(output, "%s $%hX\n", opcode_str[opcode], relative); break; case OP_ADDR_IMM: decode_imm(opcode); break; case OP_ADDR_IND: decode_ind(opcode); break; case OP_ADDR_ABS: decode_abs(opcode); break; default: fprintf(output, "???\n", opcode); break; } } while (!feof(input)); } void usage(int retcode) { if (retcode == EXIT_FAILURE) { fprintf(stderr, "Try '%s -h' for more information.\n", prg_name); } else { printf("Usage: %s [-hV] [INPUT] [OUTPUT]\n", prg_name); printf("Disassemble INPUT to OUTPUT\n\n"); printf("With no INPUT read standard input.\n"); printf("With no OUTPUT write standard output.\n\n"); printf("\t-h\tdisplay this help and exit\n"); printf("\t-V\toutput version information\n"); printf("\nReport bugs to <%s>\n", PACKAGE_BUGREPORT); } exit(retcode); } void version(void) { printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION); exit(EXIT_SUCCESS); } int main(int argc, char **argv) { #ifdef HAVE_LIBGEN_H prg_name = basename(argv[0]); #else prg_name = argv[0]; #endif /* HAVE_LIBGEN_H */ input = stdin; output = stdout; while ((argc > 1) && (argv[1][0] == '-')) { switch (argv[1][1]) { case 'h': usage(EXIT_SUCCESS); break; case 'V': version(); break; default: usage(EXIT_FAILURE); break; } argv++; argc--; } if (argc > 2) { output = fopen(argv[2], "w"); if (output == NULL) fatal("can't open %s.", argv[2]); } if (argc > 1) { input = fopen(argv[1], "rb"); if (input == NULL) fatal("can't open %s.", argv[1]); } decode(); return (EXIT_SUCCESS); }