2014-07-23 17:52:56 +00:00
|
|
|
/**************************************************************/
|
|
|
|
/* DCC6502.c -> Main module of: */
|
|
|
|
/* Disassembler and Cycle Counter for the 6502 microprocessor */
|
|
|
|
/* */
|
2014-07-23 19:08:55 +00:00
|
|
|
/* (C) 1998-2014 Tennessee Carmel-Veilleux(veilleux@ameth.org)*/
|
2014-07-23 17:52:56 +00:00
|
|
|
/* This code is offered as FREEware. You cannot modify nor */
|
|
|
|
/* distribute modified versions of this software without */
|
|
|
|
/* prior written consent of the author(s). The author shall */
|
|
|
|
/* NOT be responsible for ANY damage purely physical, */
|
2014-07-23 17:59:14 +00:00
|
|
|
/* emotional, material and magical to either you or anyone. */
|
2014-07-23 17:52:56 +00:00
|
|
|
/**************************************************************/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
2014-07-23 18:57:21 +00:00
|
|
|
#include <stdlib.h>
|
2014-07-23 17:52:56 +00:00
|
|
|
#include <string.h>
|
|
|
|
|
2014-07-23 18:57:21 +00:00
|
|
|
#define VERSION_INFO "v1.6"
|
2014-07-23 17:52:56 +00:00
|
|
|
#define NUMBER_OPCODES 151
|
|
|
|
|
|
|
|
/* The 6502's 13 addressing modes */
|
|
|
|
#define IMMED 0 /* Immediate */
|
2014-07-23 18:57:21 +00:00
|
|
|
#define ABSOL 1 /* Absolute */
|
2014-07-23 17:52:56 +00:00
|
|
|
#define ZEROP 2 /* Zero Page */
|
|
|
|
#define IMPLI 3 /* Implied */
|
|
|
|
#define INDIA 4 /* Indirect Absolute */
|
|
|
|
#define ABSIX 5 /* Absolute indexed with X */
|
|
|
|
#define ABSIY 6 /* Absolute indexed with Y */
|
|
|
|
#define ZEPIX 7 /* Zero page indexed with X */
|
|
|
|
#define ZEPIY 8 /* Zero page indexed with Y */
|
|
|
|
#define INDIN 9 /* Indexed indirect (with x) */
|
|
|
|
#define ININD 10 /* Indirect indexed (with y) */
|
|
|
|
#define RELAT 11 /* Relative */
|
|
|
|
#define ACCUM 12 /* Accumulator */
|
|
|
|
|
|
|
|
#define LSB_FIRST
|
|
|
|
|
|
|
|
typedef struct OPcode {
|
2014-07-23 18:57:21 +00:00
|
|
|
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 */
|
2014-07-23 17:52:56 +00:00
|
|
|
} OPcode;
|
|
|
|
|
|
|
|
typedef union
|
|
|
|
{
|
|
|
|
#ifdef LSB_FIRST
|
2014-07-23 19:07:19 +00:00
|
|
|
struct { unsigned char l, h; } B;
|
2014-07-23 17:52:56 +00:00
|
|
|
#else
|
2014-07-23 19:07:19 +00:00
|
|
|
struct { byte h, l; } B;
|
2014-07-23 17:52:56 +00:00
|
|
|
#endif
|
2014-07-23 18:57:21 +00:00
|
|
|
unsigned short W;
|
2014-07-23 17:52:56 +00:00
|
|
|
} word;
|
|
|
|
|
|
|
|
char name_table[56][4]={
|
2014-07-23 19:07:19 +00:00
|
|
|
"ADC", "AND", "ASL", "BCC", "BCS", "BEQ", "BIT", "BMI", "BNE", "BPL",
|
|
|
|
"BRK", "BVC", "BVS", "CLC", "CLD", "CLI", "CLV", "CMP", "CPX", "CPY",
|
|
|
|
"DEC", "DEX", "DEY", "EOR", "INC", "INX", "INY", "JMP", "JSR", "LDA",
|
|
|
|
"LDX", "LDY", "LSR", "NOP", "ORA", "PHA", "PHP", "PLA", "PLP", "ROL",
|
|
|
|
"ROR", "RTI", "RTS", "SBC", "SEC", "SED", "SEI", "STA", "STX", "STY",
|
|
|
|
"TAX", "TAY", "TSX", "TXA", "TXS", "TYA"};
|
2014-07-23 17:52:56 +00:00
|
|
|
|
|
|
|
/* Opcode table */
|
|
|
|
OPcode opcode_table[NUMBER_OPCODES] = {
|
2014-07-23 19:07:19 +00:00
|
|
|
{0x69, 0, IMMED, 2, 1}, /* ADC */
|
|
|
|
{0x65, 0, ZEROP, 3, 1},
|
|
|
|
{0x75, 0, ZEPIX, 4, 1},
|
|
|
|
{0x6D, 0, ABSOL, 4, 1},
|
|
|
|
{0x7D, 0, ABSIX, 4, 1},
|
|
|
|
{0x79, 0, ABSIY, 4, 1},
|
|
|
|
{0x61, 0, INDIN, 6, 1},
|
|
|
|
{0x71, 0, ININD, 5, 1},
|
2014-07-23 17:52:56 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0x29, 1, IMMED, 2, 1}, /* AND */
|
|
|
|
{0x25, 1, ZEROP, 3, 1},
|
|
|
|
{0x35, 1, ZEPIX, 4, 1},
|
|
|
|
{0x2D, 1, ABSOL, 4, 1},
|
|
|
|
{0x3D, 1, ABSIX, 4, 1},
|
|
|
|
{0x39, 1, ABSIY, 4, 1},
|
|
|
|
{0x21, 1, INDIN, 6, 1},
|
|
|
|
{0x31, 1, ININD, 5, 1},
|
2014-07-23 17:52:56 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0x0A, 2, ACCUM, 2, 0}, /* ASL */
|
|
|
|
{0x06, 2, ZEROP, 5, 0},
|
|
|
|
{0x16, 2, ZEPIX, 6, 0},
|
|
|
|
{0x0E, 2, ABSOL, 6, 0},
|
|
|
|
{0x1E, 2, ABSIX, 6, 0},
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0x90, 3, RELAT, 4, 1}, /* BCC */
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0xB0, 4, RELAT, 4, 1}, /* BCS */
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0xF0, 5, RELAT, 4, 1}, /* BEQ */
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0x24, 6, ZEROP, 3, 0}, /* BIT */
|
|
|
|
{0x2C, 6, ABSOL, 4, 0},
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0x30, 7, RELAT, 4, 1}, /* BMI */
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0xD0, 8, RELAT, 4, 1}, /* BNE */
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0x10, 9, RELAT, 4, 1}, /* BPL */
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0x00, 10, IMPLI, 7, 0}, /* BRK */
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0x50, 11, RELAT, 4, 1}, /* BVC */
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0x70, 12, RELAT, 4, 1}, /* BVS */
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0x18, 13, IMPLI, 2, 0}, /* CLC */
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0xD8, 14, IMPLI, 2, 0}, /* CLD */
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0x58, 15, IMPLI, 2, 0}, /* CLI */
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0xB8, 16, IMPLI, 2, 0}, /* CLV */
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0xC9, 17, IMMED, 2, 0}, /* CMP */
|
|
|
|
{0xC5, 17, ZEROP, 3, 0},
|
|
|
|
{0xD5, 17, ZEPIX, 4, 0},
|
|
|
|
{0xCD, 17, ABSOL, 4, 0},
|
|
|
|
{0xDD, 17, ABSIX, 4, 0},
|
|
|
|
{0xD9, 17, ABSIY, 4, 0},
|
|
|
|
{0xC1, 17, INDIN, 6, 0},
|
|
|
|
{0xD1, 17, ININD, 5, 0},
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0xE0, 18, IMMED, 2, 0}, /* CPX */
|
|
|
|
{0xE4, 18, ZEROP, 3, 0},
|
|
|
|
{0xEC, 18, ABSOL, 4, 0},
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0xC0, 19, IMMED, 2, 0}, /* CPY */
|
|
|
|
{0xC4, 19, ZEROP, 3, 0},
|
|
|
|
{0xCC, 19, ABSOL, 4, 0},
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0xC6, 20, ZEROP, 5, 0}, /* DEC */
|
|
|
|
{0xD6, 20, ZEPIX, 6, 0},
|
|
|
|
{0xCE, 20, ABSOL, 6, 0},
|
|
|
|
{0xDE, 20, ABSIX, 6, 0},
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0xCA, 21, IMPLI, 2, 0}, /* DEX */
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0x88, 22, IMPLI, 2, 0}, /* DEY */
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0x49, 23, IMMED, 2, 1}, /* EOR */
|
|
|
|
{0x45, 23, ZEROP, 3, 1},
|
|
|
|
{0x55, 23, ZEPIX, 4, 1},
|
|
|
|
{0x4D, 23, ABSOL, 4, 1},
|
|
|
|
{0x5D, 23, ABSIX, 4, 1},
|
|
|
|
{0x59, 23, ABSIY, 4, 1},
|
|
|
|
{0x41, 23, INDIN, 6, 1},
|
|
|
|
{0x51, 23, ININD, 5, 1},
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0xE6, 24, ZEROP, 5, 0}, /* INC */
|
|
|
|
{0xF6, 24, ZEPIX, 6, 0},
|
|
|
|
{0xEE, 24, ABSOL, 6, 0},
|
|
|
|
{0xFE, 24, ABSIX, 6, 0},
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0xE8, 25, IMPLI, 2, 0}, /* INX */
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0xC8, 26, IMPLI, 2, 0}, /* INY */
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0x4C, 27, ABSOL, 3, 0}, /* JMP */
|
|
|
|
{0x6C, 27, INDIA, 5, 0},
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0x20, 28, ABSOL, 6, 0}, /* JSR */
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0xA9, 29, IMMED, 2, 1}, /* LDA */
|
|
|
|
{0xA5, 29, ZEROP, 3, 1},
|
|
|
|
{0xB5, 29, ZEPIX, 4, 1},
|
|
|
|
{0xAD, 29, ABSOL, 4, 1},
|
|
|
|
{0xBD, 29, ABSIX, 4, 1},
|
|
|
|
{0xB9, 29, ABSIY, 4, 1},
|
|
|
|
{0xA1, 29, INDIN, 6, 1},
|
|
|
|
{0xB1, 29, ININD, 5, 1},
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0xA2, 30, IMMED, 2, 1}, /* LDX */
|
|
|
|
{0xA6, 30, ZEROP, 3, 1},
|
|
|
|
{0xB6, 30, ZEPIY, 4, 1},
|
|
|
|
{0xAE, 30, ABSOL, 4, 1},
|
|
|
|
{0xBE, 30, ABSIY, 4, 1},
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0xA0, 31, IMMED, 2, 1}, /* LDY */
|
|
|
|
{0xA4, 31, ZEROP, 3, 1},
|
|
|
|
{0xB4, 31, ZEPIX, 4, 1},
|
|
|
|
{0xAC, 31, ABSOL, 4, 1},
|
|
|
|
{0xBC, 31, ABSIX, 4, 1},
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0x4A, 32, ACCUM, 2, 0}, /* LSR */
|
|
|
|
{0x46, 32, ZEROP, 5, 0},
|
|
|
|
{0x56, 32, ZEPIX, 6, 0},
|
|
|
|
{0x4E, 32, ABSOL, 6, 0},
|
|
|
|
{0x5E, 32, ABSIX, 6, 0},
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0xEA, 33, IMPLI, 2, 0}, /* NOP */
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0x09, 34, IMMED, 2, 0}, /* ORA */
|
|
|
|
{0x05, 34, ZEROP, 3, 0},
|
|
|
|
{0x15, 34, ZEPIX, 4, 0},
|
|
|
|
{0x0D, 34, ABSOL, 4, 0},
|
|
|
|
{0x1D, 34, ABSIX, 4, 0},
|
|
|
|
{0x19, 34, ABSIY, 4, 0},
|
|
|
|
{0x01, 34, INDIN, 6, 0},
|
|
|
|
{0x11, 34, ININD, 5, 0},
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0x48, 35, IMPLI, 3, 0}, /* PHA */
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0x08, 36, IMPLI, 3, 0}, /* PHP */
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0x68, 37, IMPLI, 4, 0}, /* PLA */
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0x28, 38, IMPLI, 4, 0}, /* PLP */
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0x2A, 39, ACCUM, 2, 0}, /* ROL */
|
|
|
|
{0x26, 39, ZEROP, 5, 0},
|
|
|
|
{0x36, 39, ZEPIX, 6, 0},
|
|
|
|
{0x2E, 39, ABSOL, 6, 0},
|
|
|
|
{0x3E, 39, ABSIX, 6, 0},
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0x6A, 40, ACCUM, 2, 0}, /* ROR */
|
|
|
|
{0x66, 40, ZEROP, 5, 0},
|
|
|
|
{0x76, 40, ZEPIX, 6, 0},
|
|
|
|
{0x6E, 40, ABSOL, 6, 0},
|
|
|
|
{0x7E, 40, ABSIX, 6, 0},
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0x40, 41, IMPLI, 6, 0}, /* RTI */
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0x60, 42, IMPLI, 6, 0}, /* RTS */
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0xE9, 43, IMMED, 2, 1}, /* SBC */
|
|
|
|
{0xE5, 43, ZEROP, 3, 1},
|
|
|
|
{0xF5, 43, ZEPIX, 4, 1},
|
|
|
|
{0xED, 43, ABSOL, 4, 1},
|
|
|
|
{0xFD, 43, ABSIX, 4, 1},
|
|
|
|
{0xF9, 43, ABSIY, 4, 1},
|
|
|
|
{0xE1, 43, INDIN, 6, 1},
|
|
|
|
{0xF1, 43, ININD, 5, 1},
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0x38, 44, IMPLI, 2, 0}, /* SEC */
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0xF8, 45, IMPLI, 2, 0}, /* SED */
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0x78, 46, IMPLI, 2, 0}, /* SEI */
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0x85, 47, ZEROP, 3, 0}, /* STA */
|
|
|
|
{0x95, 47, ZEPIX, 4, 0},
|
|
|
|
{0x8D, 47, ABSOL, 4, 0},
|
|
|
|
{0x9D, 47, ABSIX, 4, 0},
|
|
|
|
{0x99, 47, ABSIY, 4, 0},
|
|
|
|
{0x81, 47, INDIN, 6, 0},
|
|
|
|
{0x91, 47, ININD, 5, 0},
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0x86, 48, ZEROP, 3, 0}, /* STX */
|
|
|
|
{0x96, 48, ZEPIY, 4, 0},
|
|
|
|
{0x8E, 48, ABSOL, 4, 0},
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0x84, 49, ZEROP, 3, 0}, /* STY */
|
|
|
|
{0x94, 49, ZEPIX, 4, 0},
|
|
|
|
{0x8C, 49, ABSOL, 4, 0},
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0xAA, 50, IMPLI, 2, 0}, /* TAX */
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0xA8, 51, IMPLI, 2, 0}, /* TAY */
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0xBA, 52, IMPLI, 2, 0}, /* TSX */
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0x8A, 53, IMPLI, 2, 0}, /* TXA */
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0x9A, 54, IMPLI, 2, 0}, /* TXS */
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
{0x98, 55, IMPLI, 2, 0} /* TYA */
|
2014-07-23 17:52:56 +00:00
|
|
|
};
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 17:52:56 +00:00
|
|
|
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 */
|
|
|
|
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 */
|
|
|
|
char line[512];
|
|
|
|
|
|
|
|
/* This function emits a comment header with information about the file
|
2014-07-23 18:57:21 +00:00
|
|
|
being disassembled */
|
2014-07-23 17:52:56 +00:00
|
|
|
|
|
|
|
void emit_header(char *filename, int fsize, unsigned short org) {
|
2014-07-23 19:07:19 +00:00
|
|
|
fprintf(stdout, "; Source generated by DCC6502 version %s\n", VERSION_INFO);
|
|
|
|
fprintf(stdout, "; For more info about DCC6502, e-mail veilleux@ameth.org\n;\n");
|
|
|
|
fprintf(stdout, "; FILENAME: %s, File Size: %d, ORG: $%04X\n", filename, fsize, org);
|
|
|
|
if (hex_output) fprintf(stdout, "; -> Hex output enabled\n");
|
|
|
|
if (cycle_counting) fprintf(stdout, "; -> Cycle counting enabled\n");
|
|
|
|
if (nes_mode) fprintf(stdout, "; -> NES mode enabled\n");
|
|
|
|
fprintf(stdout, ";---------------------------------------------------------------------------\n");
|
2014-07-23 17:52:56 +00:00
|
|
|
}
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 17:52:56 +00:00
|
|
|
/* This function appends cycle counting to the comment block */
|
|
|
|
void append_cycle(char *input, unsigned char entry, unsigned short arg, unsigned short cur_PC) {
|
2014-07-23 18:57:21 +00:00
|
|
|
char tmpstr[256];
|
|
|
|
int cycles = 0;
|
2014-07-23 17:52:56 +00:00
|
|
|
|
2014-07-23 18:57:21 +00:00
|
|
|
cycles = opcode_table[entry].cycles;
|
2014-07-23 17:52:56 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
sprintf(tmpstr, " Cycles: %d ", cycles);
|
|
|
|
if (opcode_table[entry].cross_page) strcat(tmpstr, "*!* ");
|
|
|
|
strcat(input, tmpstr);
|
2014-07-23 17:52:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void add_nes_str(char *instr, char *instr2) {
|
2014-07-23 19:07:19 +00:00
|
|
|
strcat(instr, " [NES] ");
|
|
|
|
strcat(instr, instr2);
|
2014-07-23 17:52:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* This function put NES-specific info in the comment block */
|
|
|
|
void append_nes(char *input, unsigned short arg) {
|
2014-07-23 18:57:21 +00:00
|
|
|
switch(arg) {
|
2014-07-23 19:07:19 +00:00
|
|
|
case 0x2000: add_nes_str(input, "PPU setup #1"); break;
|
|
|
|
case 0x2001: add_nes_str(input, "PPU setup #2"); break;
|
|
|
|
case 0x2002: add_nes_str(input, "PPU status"); break;
|
|
|
|
case 0x2003: add_nes_str(input, "SPR-RAM address select"); break;
|
|
|
|
case 0x2004: add_nes_str(input, "SPR-RAM data"); break;
|
|
|
|
case 0x2005: add_nes_str(input, "PPU scroll"); break;
|
|
|
|
case 0x2006: add_nes_str(input, "VRAM address select"); break;
|
|
|
|
case 0x2007: add_nes_str(input, "VRAM data"); break;
|
|
|
|
case 0x4000: add_nes_str(input, "Audio -> Square 1"); break;
|
|
|
|
case 0x4001: add_nes_str(input, "Audio -> Square 1"); break;
|
|
|
|
case 0x4002: add_nes_str(input, "Audio -> Square 1"); break;
|
|
|
|
case 0x4003: add_nes_str(input, "Audio -> Square 1"); break;
|
|
|
|
case 0x4004: add_nes_str(input, "Audio -> Square 2"); break;
|
|
|
|
case 0x4005: add_nes_str(input, "Audio -> Square 2"); break;
|
|
|
|
case 0x4006: add_nes_str(input, "Audio -> Square 2"); break;
|
|
|
|
case 0x4007: add_nes_str(input, "Audio -> Square 2"); break;
|
|
|
|
case 0x4008: add_nes_str(input, "Audio -> Triangle"); break;
|
|
|
|
case 0x4009: add_nes_str(input, "Audio -> Triangle"); break;
|
|
|
|
case 0x400a: add_nes_str(input, "Audio -> Triangle"); break;
|
|
|
|
case 0x400b: add_nes_str(input, "Audio -> Triangle"); break;
|
|
|
|
case 0x400c: add_nes_str(input, "Audio -> Noise control reg"); break;
|
|
|
|
case 0x400e: add_nes_str(input, "Audio -> Noise Frequency reg #1"); break;
|
|
|
|
case 0x400f: add_nes_str(input, "Audio -> Noise Frequency reg #2"); break;
|
|
|
|
case 0x4010: add_nes_str(input, "Audio -> DPCM control"); break;
|
|
|
|
case 0x4011: add_nes_str(input, "Audio -> DPCM D/A data"); break;
|
|
|
|
case 0x4012: add_nes_str(input, "Audio -> DPCM address"); break;
|
|
|
|
case 0x4013: add_nes_str(input, "Audio -> DPCM data length"); break;
|
|
|
|
case 0x4014: add_nes_str(input, "Sprite DMA trigger"); break;
|
|
|
|
case 0x4015: add_nes_str(input, "IRQ status / Sound enable"); break;
|
|
|
|
case 0x4016: add_nes_str(input, "Joypad & I/O port for port #1"); break;
|
|
|
|
case 0x4017: add_nes_str(input, "Joypad & I/O port for port #2"); break;
|
2014-07-23 18:57:21 +00:00
|
|
|
}
|
2014-07-23 17:52:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* This function disassembles the opcode at the PC and outputs it in *output */
|
2014-07-23 18:57:21 +00:00
|
|
|
void disassemble(char *output) {
|
|
|
|
unsigned char tmp_byte1, tmp_byte2, opcode;
|
|
|
|
char argument_signed;
|
|
|
|
word tmp_word;
|
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
char tmpstr[256], tmpstr2[256], tmpstr3[256];
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
int i, j, entry, found = 0;
|
2014-07-23 18:57:21 +00:00
|
|
|
|
|
|
|
opcode = buffer[PC];
|
|
|
|
|
|
|
|
for (i = 0; i < NUMBER_OPCODES; i++) {
|
|
|
|
if (opcode == opcode_table[i].number) {
|
|
|
|
found = 1; /* Found the opcode */
|
|
|
|
entry = i; /* Note the entry number in the table */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!found) {
|
|
|
|
if (hex_output) {
|
2014-07-23 19:07:19 +00:00
|
|
|
sprintf(tmpstr, "$%04X> %02X:\t.byte $%02x\t\t; INVALID OPCODE !!!\n", org+PC, opcode, opcode);
|
2014-07-23 18:57:21 +00:00
|
|
|
strncpy(output, tmpstr, 254);
|
|
|
|
} else {
|
2014-07-23 19:07:19 +00:00
|
|
|
sprintf(tmpstr, "$%04X\t.byte $%02x\t; INVALID OPCODE !!!\n", org+PC, opcode);
|
2014-07-23 18:57:21 +00:00
|
|
|
strncpy(output, tmpstr, 254);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
switch (opcode_table[entry].addressing) {
|
|
|
|
case IMMED:
|
|
|
|
PC++;
|
|
|
|
tmp_byte1 = buffer[PC]; /* Get immediate value */
|
|
|
|
if (hex_output)
|
2014-07-23 19:07:19 +00:00
|
|
|
sprintf(tmpstr, "$%04X> %02X %02X:\t%s #$%02x\t;", org+PC-1, opcode, tmp_byte1, name_table[opcode_table[entry].name], tmp_byte1);
|
2014-07-23 18:57:21 +00:00
|
|
|
else
|
2014-07-23 19:07:19 +00:00
|
|
|
sprintf(tmpstr, "$%04X\t%s #$%02x\t;", org+PC-1, name_table[opcode_table[entry].name], tmp_byte1);
|
2014-07-23 18:57:21 +00:00
|
|
|
|
|
|
|
/* Add cycle count if necessary */
|
2014-07-23 19:07:19 +00:00
|
|
|
if (cycle_counting) append_cycle(tmpstr, entry, org+PC-1, org+PC-1);
|
|
|
|
strncpy(output, tmpstr, 254);
|
2014-07-23 18:57:21 +00:00
|
|
|
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 */
|
|
|
|
|
|
|
|
if (hex_output)
|
2014-07-23 19:07:19 +00:00
|
|
|
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);
|
2014-07-23 18:57:21 +00:00
|
|
|
else
|
2014-07-23 19:07:19 +00:00
|
|
|
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);
|
2014-07-23 18:57:21 +00:00
|
|
|
|
|
|
|
/* Add cycle count if necessary */
|
2014-07-23 19:07:19 +00:00
|
|
|
if (cycle_counting) append_cycle(tmpstr, entry, tmp_word.W, org+PC-2);
|
2014-07-23 18:57:21 +00:00
|
|
|
|
|
|
|
/* Add NES port info if necessary */
|
2014-07-23 19:07:19 +00:00
|
|
|
if (nes_mode) append_nes(tmpstr, tmp_word.W);
|
|
|
|
strncpy(output, tmpstr, 254);
|
2014-07-23 18:57:21 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case ZEROP:
|
|
|
|
PC++;
|
|
|
|
tmp_byte1 = buffer[PC]; /* Get low byte of address */
|
|
|
|
|
|
|
|
if (hex_output)
|
2014-07-23 19:07:19 +00:00
|
|
|
sprintf(tmpstr, "$%04X> %02X %02X:\t%s $%02X\t\t;", org+PC-1, opcode, tmp_byte1, name_table[opcode_table[entry].name], tmp_byte1);
|
2014-07-23 18:57:21 +00:00
|
|
|
else
|
2014-07-23 19:07:19 +00:00
|
|
|
sprintf(tmpstr, "$%04X\t%s $%02X\t\t;", org+PC-1, name_table[opcode_table[entry].name], tmp_byte1);
|
2014-07-23 18:57:21 +00:00
|
|
|
|
|
|
|
/* Add cycle count if necessary */
|
2014-07-23 19:07:19 +00:00
|
|
|
if (cycle_counting) append_cycle(tmpstr, entry, org+PC-1, org+PC-1);
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
strncpy(output, tmpstr, 254);
|
2014-07-23 18:57:21 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case IMPLI:
|
|
|
|
if (hex_output)
|
2014-07-23 19:07:19 +00:00
|
|
|
sprintf(tmpstr, "$%04X> %02X:\t%s\t\t;", org+PC, opcode, name_table[opcode_table[entry].name]);
|
2014-07-23 18:57:21 +00:00
|
|
|
else
|
2014-07-23 19:07:19 +00:00
|
|
|
sprintf(tmpstr, "$%04X\t%s\t\t;", org+PC, name_table[opcode_table[entry].name]);
|
2014-07-23 18:57:21 +00:00
|
|
|
|
|
|
|
/* Add cycle count if necessary */
|
2014-07-23 19:07:19 +00:00
|
|
|
if (cycle_counting) append_cycle(tmpstr, entry, org+PC, org+PC);
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
strncpy(output, tmpstr, 254);
|
2014-07-23 18:57:21 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
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 */
|
|
|
|
|
|
|
|
if (hex_output)
|
2014-07-23 19:07:19 +00:00
|
|
|
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);
|
2014-07-23 18:57:21 +00:00
|
|
|
else
|
2014-07-23 19:07:19 +00:00
|
|
|
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);
|
2014-07-23 18:57:21 +00:00
|
|
|
|
|
|
|
/* Add cycle count if necessary */
|
2014-07-23 19:07:19 +00:00
|
|
|
if (cycle_counting) append_cycle(tmpstr, entry, tmp_word.W, org+PC-2);
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
strncpy(output, tmpstr, 254);
|
2014-07-23 18:57:21 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
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 */
|
|
|
|
|
|
|
|
if (hex_output)
|
2014-07-23 19:07:19 +00:00
|
|
|
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);
|
2014-07-23 18:57:21 +00:00
|
|
|
else
|
2014-07-23 19:07:19 +00:00
|
|
|
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);
|
2014-07-23 18:57:21 +00:00
|
|
|
|
|
|
|
/* Add cycle count if necessary */
|
2014-07-23 19:07:19 +00:00
|
|
|
if (cycle_counting) append_cycle(tmpstr, entry, tmp_word.W, org+PC-2);
|
2014-07-23 18:57:21 +00:00
|
|
|
|
|
|
|
/* Add NES port info if necessary */
|
2014-07-23 19:07:19 +00:00
|
|
|
if (nes_mode) append_nes(tmpstr, tmp_word.W);
|
|
|
|
strncpy(output, tmpstr, 254);
|
2014-07-23 18:57:21 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
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 */
|
|
|
|
|
|
|
|
if (hex_output)
|
2014-07-23 19:07:19 +00:00
|
|
|
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);
|
2014-07-23 18:57:21 +00:00
|
|
|
else
|
2014-07-23 19:07:19 +00:00
|
|
|
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);
|
2014-07-23 18:57:21 +00:00
|
|
|
|
|
|
|
/* Add cycle count if necessary */
|
2014-07-23 19:07:19 +00:00
|
|
|
if (cycle_counting) append_cycle(tmpstr, entry, tmp_word.W, org+PC-2);
|
2014-07-23 18:57:21 +00:00
|
|
|
|
|
|
|
/* Add NES port info if necessary */
|
2014-07-23 19:07:19 +00:00
|
|
|
if (nes_mode) append_nes(tmpstr, tmp_word.W);
|
|
|
|
strncpy(output, tmpstr, 254);
|
2014-07-23 18:57:21 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case ZEPIX:
|
|
|
|
PC++;
|
|
|
|
tmp_byte1 = buffer[PC]; /* Get low byte of address */
|
|
|
|
|
|
|
|
if (hex_output)
|
2014-07-23 19:07:19 +00:00
|
|
|
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);
|
2014-07-23 18:57:21 +00:00
|
|
|
else
|
2014-07-23 19:07:19 +00:00
|
|
|
sprintf(tmpstr, "$%04X\t%s $%02X,X\t;", org+PC-1, name_table[opcode_table[entry].name], tmp_byte1);
|
2014-07-23 18:57:21 +00:00
|
|
|
|
|
|
|
/* Add cycle count if necessary */
|
2014-07-23 19:07:19 +00:00
|
|
|
if (cycle_counting) append_cycle(tmpstr, entry, org+PC-1, org+PC-1);
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
strncpy(output, tmpstr, 254);
|
2014-07-23 18:57:21 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case ZEPIY:
|
|
|
|
PC++;
|
|
|
|
tmp_byte1 = buffer[PC]; /* Get low byte of address */
|
|
|
|
|
|
|
|
if (hex_output)
|
2014-07-23 19:07:19 +00:00
|
|
|
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);
|
2014-07-23 18:57:21 +00:00
|
|
|
else
|
2014-07-23 19:07:19 +00:00
|
|
|
sprintf(tmpstr, "$%04X\t%s $%02X,Y\t;", org+PC-1, name_table[opcode_table[entry].name], tmp_byte1);
|
2014-07-23 18:57:21 +00:00
|
|
|
|
|
|
|
/* Add cycle count if necessary */
|
2014-07-23 19:07:19 +00:00
|
|
|
if (cycle_counting) append_cycle(tmpstr, entry, org+PC-1, org+PC-1);
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
strncpy(output, tmpstr, 254);
|
2014-07-23 18:57:21 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case INDIN:
|
|
|
|
PC++;
|
|
|
|
tmp_byte1 = buffer[PC]; /* Get low byte of address */
|
|
|
|
|
|
|
|
if (hex_output)
|
2014-07-23 19:07:19 +00:00
|
|
|
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);
|
2014-07-23 18:57:21 +00:00
|
|
|
else
|
2014-07-23 19:07:19 +00:00
|
|
|
sprintf(tmpstr, "$%04X\t%s ($%02X,X)\t;", org+PC-1, name_table[opcode_table[entry].name], tmp_byte1);
|
2014-07-23 18:57:21 +00:00
|
|
|
|
|
|
|
/* Add cycle count if necessary */
|
2014-07-23 19:07:19 +00:00
|
|
|
if (cycle_counting) append_cycle(tmpstr, entry, org+PC-1, org+PC-1);
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
strncpy(output, tmpstr, 254);
|
2014-07-23 18:57:21 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case ININD:
|
|
|
|
PC++;
|
|
|
|
tmp_byte1 = buffer[PC]; /* Get low byte of address */
|
|
|
|
|
|
|
|
if (hex_output)
|
2014-07-23 19:07:19 +00:00
|
|
|
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);
|
2014-07-23 18:57:21 +00:00
|
|
|
else
|
2014-07-23 19:07:19 +00:00
|
|
|
sprintf(tmpstr, "$%04X\t%s ($%02X),Y\t;", org+PC-1, name_table[opcode_table[entry].name], tmp_byte1);
|
2014-07-23 18:57:21 +00:00
|
|
|
|
|
|
|
/* Add cycle count if necessary */
|
2014-07-23 19:07:19 +00:00
|
|
|
if (cycle_counting) append_cycle(tmpstr, entry, org+PC-1, org+PC-1);
|
2014-07-23 17:52:56 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
strncpy(output, tmpstr, 254);
|
2014-07-23 18:57:21 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case RELAT:
|
|
|
|
PC++;
|
|
|
|
tmp_byte1 = buffer[PC]; /* Get relative modifier */
|
|
|
|
|
|
|
|
if (hex_output)
|
2014-07-23 19:07:19 +00:00
|
|
|
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);
|
2014-07-23 18:57:21 +00:00
|
|
|
else
|
2014-07-23 19:07:19 +00:00
|
|
|
sprintf(tmpstr, "$%04X\t%s $%04X\t;", org+PC-1, name_table[opcode_table[entry].name], (org+PC)+(signed char)(tmp_byte1)+1);
|
2014-07-23 18:57:21 +00:00
|
|
|
|
|
|
|
/* Add cycle count if necessary */
|
2014-07-23 19:07:19 +00:00
|
|
|
if (cycle_counting) append_cycle(tmpstr, entry, org+PC, org+PC);
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
strncpy(output, tmpstr, 254);
|
2014-07-23 18:57:21 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case ACCUM:
|
|
|
|
if (hex_output)
|
2014-07-23 19:07:19 +00:00
|
|
|
sprintf(tmpstr, "$%04X> %02X:\t%s A\t\t;", org+PC, opcode, name_table[opcode_table[entry].name]);
|
2014-07-23 18:57:21 +00:00
|
|
|
else
|
2014-07-23 19:07:19 +00:00
|
|
|
sprintf(tmpstr, "$%04X\t%s A\t\t;", org+PC, name_table[opcode_table[entry].name]);
|
2014-07-23 18:57:21 +00:00
|
|
|
|
|
|
|
/* Add cycle count if necessary */
|
2014-07-23 19:07:19 +00:00
|
|
|
if (cycle_counting) append_cycle(tmpstr, entry, org+PC, org+PC);
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
strncpy(output, tmpstr, 254);
|
2014-07-23 18:57:21 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2014-07-23 17:52:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void version(void) {
|
2014-07-23 19:08:55 +00:00
|
|
|
fprintf(stderr, "DCC6502 %s (C)1998-2014 Tennessee Carmel-Veilleux\n", VERSION_INFO);
|
2014-07-23 19:07:19 +00:00
|
|
|
fprintf(stderr, "This is free software. To see the LICENSE, use the -v parameter\n");
|
2014-07-23 17:52:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void usage_helper(char *str) {
|
2014-07-23 19:07:19 +00:00
|
|
|
fprintf(stderr, "\t%s\n", str);
|
2014-07-23 17:52:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void usage(void) {
|
2014-07-23 18:57:21 +00:00
|
|
|
usage_helper("-? -> Show this help message");
|
|
|
|
usage_helper("-oXXXX -> Set the origin (ORG) [dfl: $8000]");
|
|
|
|
usage_helper("-h -> Get hex info about disassembly");
|
|
|
|
usage_helper("-mXXXX -> Only disassemble the first XXXX bytes");
|
|
|
|
usage_helper("-n -> Enable NES mode");
|
|
|
|
usage_helper("-v -> Get only version information");
|
|
|
|
usage_helper("-c -> Get cycle counting info");
|
2014-07-23 19:07:19 +00:00
|
|
|
fprintf(stderr, "\n");
|
2014-07-23 17:52:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void license(void) {
|
2014-07-23 19:08:55 +00:00
|
|
|
fprintf(stderr, "(C) 1998-2014 Tennessee Carmel-Veilleux(veilleux@ameth.org)\n");
|
2014-07-23 19:07:19 +00:00
|
|
|
fprintf(stderr, "This code is offered as FREEware. You cannot modify nor\n");
|
|
|
|
fprintf(stderr, "distribute modified versions of this software without\n");
|
|
|
|
fprintf(stderr, "prior written consent of the author(s). The author shall\n");
|
|
|
|
fprintf(stderr, "NOT be responsible for ANY damage purely physical,\n");
|
|
|
|
fprintf(stderr, "emotional, material and magical to either you or anyone.\n");
|
2014-07-23 17:52:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned short hex2int (char *str, unsigned short dfl) {
|
2014-07-23 19:07:19 +00:00
|
|
|
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;
|
2014-07-23 18:57:21 +00:00
|
|
|
unsigned short tmp=0;
|
|
|
|
|
|
|
|
shift = 0;
|
|
|
|
for (i = 5; i >= 2; i--) {
|
|
|
|
if (!isxdigit(str[i])) {
|
|
|
|
tmp = dfl;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
c = toupper(str[i]);
|
|
|
|
for (j = 0; j < 16; j++) {
|
|
|
|
if (c == HEX_digits[j]) k = j;
|
|
|
|
}
|
2014-07-23 19:07:19 +00:00
|
|
|
tmp |= ((k & 0xf) << shift);
|
2014-07-23 18:57:21 +00:00
|
|
|
shift += 4;
|
|
|
|
}
|
|
|
|
return tmp;
|
2014-07-23 17:52:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void set_org(char *str) {
|
2014-07-23 18:57:21 +00:00
|
|
|
if (strlen(str) < 6) {
|
2014-07-23 19:07:19 +00:00
|
|
|
fprintf(stderr, "WARNING -> %s is not a valid ORG switch, defaulting to $8000\n", str);
|
2014-07-23 18:57:21 +00:00
|
|
|
org = 0x8000;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
org = hex2int(str, 0x8000);
|
2014-07-23 17:52:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void set_max(char *str) {
|
2014-07-23 18:57:21 +00:00
|
|
|
if (strlen(str) != 6) {
|
|
|
|
max = 0xFFFF-org;
|
2014-07-23 19:07:19 +00:00
|
|
|
fprintf(stderr, "WARNING -> %s is not a valid MAX switch, defaulting to $%04X\n", str, max);
|
2014-07-23 18:57:21 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
max = hex2int(str, 0xFFFF);
|
2014-07-23 17:52:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char *argv[]) {
|
2014-07-23 18:57:21 +00:00
|
|
|
int i = 0;
|
|
|
|
char c;
|
|
|
|
char tmpstring[512];
|
|
|
|
char filename[512];
|
|
|
|
|
|
|
|
cycle_counting = 0;
|
|
|
|
hex_output = 0;
|
|
|
|
org = 0x8000;
|
|
|
|
|
|
|
|
if (argc < 2) {
|
|
|
|
version();
|
|
|
|
usage();
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (argc > 2) {
|
|
|
|
for (i = 1; i < argc - 1; i++) {
|
|
|
|
if (argv[i][0] != '-') {
|
|
|
|
version();
|
|
|
|
usage();
|
2014-07-23 19:07:19 +00:00
|
|
|
fprintf(stderr, "Unrecognized switch: %s\n", argv[i]);
|
2014-07-23 18:57:21 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
switch (argv[i][1]) {
|
|
|
|
case '?':
|
|
|
|
version();
|
|
|
|
usage();
|
|
|
|
license();
|
|
|
|
exit(0);
|
|
|
|
break;
|
|
|
|
case 'n':
|
|
|
|
nes_mode = 1;
|
|
|
|
break;
|
|
|
|
case 'c':
|
|
|
|
cycle_counting = 1;
|
|
|
|
break;
|
|
|
|
case 'h':
|
|
|
|
hex_output = 1;
|
|
|
|
break;
|
|
|
|
case 'v':
|
|
|
|
version();
|
|
|
|
license();
|
|
|
|
exit(0);
|
|
|
|
break;
|
|
|
|
case 'o':
|
|
|
|
set_org(argv[i]);
|
|
|
|
break;
|
|
|
|
case 'm':
|
|
|
|
set_max(argv[i]);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
version();
|
|
|
|
usage();
|
|
|
|
fprintf(stderr, "Unrecognized switch: %s\n", argv[i]);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (argv[1][0] != '-') {
|
2014-07-23 19:07:19 +00:00
|
|
|
strncpy(filename, argv[1], 511);
|
2014-07-23 18:57:21 +00:00
|
|
|
} else {
|
|
|
|
switch (argv[1][1]) {
|
|
|
|
case '?':
|
|
|
|
version();
|
|
|
|
usage();
|
|
|
|
license();
|
|
|
|
exit(0);
|
|
|
|
break;
|
|
|
|
case 'v':
|
|
|
|
version();
|
|
|
|
license();
|
|
|
|
exit(0);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
version();
|
|
|
|
usage();
|
|
|
|
fprintf(stderr, "Unrecognized switch: %s\n", argv[1]);
|
|
|
|
exit(1);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
strncpy(filename, argv[argc - 1], 511);
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
f = fopen(filename, "rb");
|
2014-07-23 18:57:21 +00:00
|
|
|
|
2014-07-23 19:07:19 +00:00
|
|
|
if (NULL == f) {
|
2014-07-23 18:57:21 +00:00
|
|
|
version();
|
2014-07-23 19:07:19 +00:00
|
|
|
fprintf(stderr, "File not found or invalid filename : %s\n", filename);
|
2014-07-23 18:57:21 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
while(!feof(f) && ((i + org) < 65535)) {
|
|
|
|
fread(&buffer[i], 1, 1, f);
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
emit_header(filename, i, org);
|
|
|
|
PC = 0;
|
|
|
|
while(((PC + org) < 65535) && (PC <= max) && (PC < i)) {
|
|
|
|
disassemble(tmpstring);
|
2014-07-23 19:07:19 +00:00
|
|
|
fprintf(stdout, "%s\n", tmpstring);
|
2014-07-23 18:57:21 +00:00
|
|
|
PC++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2014-07-23 17:52:56 +00:00
|
|
|
}
|