|
|
|
@@ -0,0 +1,395 @@ |
|
|
|
#include <stdint.h> |
|
|
|
#include <stdio.h> |
|
|
|
|
|
|
|
#include "opcodes.h" |
|
|
|
|
|
|
|
|
|
|
|
#define adr_imp (NULL) |
|
|
|
|
|
|
|
static int adr_imm(const uint8_t* operand, char* str, int max) { |
|
|
|
return snprintf(str, max, "#$%02X", *operand); |
|
|
|
} |
|
|
|
|
|
|
|
static int adr_acc(const uint8_t* operand, char* str, int max) { |
|
|
|
return snprintf(str, max, "A"); |
|
|
|
} |
|
|
|
|
|
|
|
static int adr_ind(const uint8_t* operand, char* str, int max) { |
|
|
|
return snprintf(str, max, "($%04X)", *(uint16_t*)operand); |
|
|
|
} |
|
|
|
|
|
|
|
static int adr_abs(const uint8_t* operand, char* str, int max) { |
|
|
|
return snprintf(str, max, "$%04X", *(uint16_t*)operand); |
|
|
|
} |
|
|
|
|
|
|
|
static inline int adr_abs_reg(char reg, const uint8_t* operand, |
|
|
|
char* str, int max) { |
|
|
|
return snprintf(str, max, "$%04X,%c", *operand, reg); |
|
|
|
} |
|
|
|
|
|
|
|
static int adr_abs_x(const uint8_t* operand, char* str, int max) { |
|
|
|
return adr_abs_reg('X', operand, str, max); |
|
|
|
} |
|
|
|
|
|
|
|
static int adr_abs_y(const uint8_t* operand, char* str, int max) { |
|
|
|
return adr_abs_reg('Y', operand, str, max); |
|
|
|
} |
|
|
|
|
|
|
|
#define adr_rel adr_zp |
|
|
|
static int adr_zp(const uint8_t* operand, char* str, int max) { |
|
|
|
return snprintf(str, max, "$%02X", *operand); |
|
|
|
} |
|
|
|
|
|
|
|
static inline int adr_zp_reg(char reg, const uint8_t* operand, |
|
|
|
char* str, int max) { |
|
|
|
return snprintf(str, max, "$%02X,%c", *operand, reg); |
|
|
|
} |
|
|
|
|
|
|
|
static int adr_zp_x(const uint8_t* operand, char* str, int max) { |
|
|
|
return adr_zp_reg('X', operand, str, max); |
|
|
|
} |
|
|
|
|
|
|
|
static int adr_zp_y(const uint8_t* operand, char* str, int max) { |
|
|
|
return adr_zp_reg('Y', operand, str, max); |
|
|
|
} |
|
|
|
|
|
|
|
static inline int adr_ind_reg(char reg, const uint8_t* op, |
|
|
|
char* str, int max) { |
|
|
|
return snprintf(str, max, "($%04X,%c)", *(uint16_t*)op, reg); |
|
|
|
} |
|
|
|
|
|
|
|
static int adr_ind_x(const uint8_t* operand, char* str, int max) { |
|
|
|
return adr_ind_reg('X', operand, str, max); |
|
|
|
} |
|
|
|
|
|
|
|
static int adr_ind_y(const uint8_t* operand, char* str, int max) { |
|
|
|
return adr_ind_reg('Y', operand, str, max); |
|
|
|
} |
|
|
|
|
|
|
|
typedef int(*adr_Mode)(const uint8_t*, char*, int); |
|
|
|
|
|
|
|
typedef struct { |
|
|
|
const char *operator; |
|
|
|
int(*mode)(const uint8_t*, char*, int); |
|
|
|
int cycles; // Unused |
|
|
|
} e6502_Instruction; |
|
|
|
|
|
|
|
#define brk "BRK" |
|
|
|
#define ora "ORA" |
|
|
|
#define asl "ASL" |
|
|
|
#define asl_a asl |
|
|
|
#define php "PHP" |
|
|
|
#define bpl "BPL" |
|
|
|
#define clc "CLC" |
|
|
|
#define jsr "JSR" |
|
|
|
#define bit "BIT" |
|
|
|
#define and "AND" |
|
|
|
#define rol "ROL" |
|
|
|
#define rol_a rol |
|
|
|
#define plp "PLP" |
|
|
|
#define bmi "BMI" |
|
|
|
#define sec "SEC" |
|
|
|
#define rti "RTI" |
|
|
|
#define eor "EOR" |
|
|
|
#define lsr "LSR" |
|
|
|
#define lsr_a lsr |
|
|
|
#define pha "PHA" |
|
|
|
#define jmp "JMP" |
|
|
|
#define bvc "BVC" |
|
|
|
#define cli "CLI" |
|
|
|
#define rts "RTS" |
|
|
|
#define adc "ADC" |
|
|
|
#define ror "ROR" |
|
|
|
#define ror_a ror |
|
|
|
#define pla "PLA" |
|
|
|
#define bvs "BVS" |
|
|
|
#define sei "SEI" |
|
|
|
#define sta "STA" |
|
|
|
#define stx "STX" |
|
|
|
#define sty "STY" |
|
|
|
#define txa "TXA" |
|
|
|
#define dey "DEY" |
|
|
|
#define bcc "BCC" |
|
|
|
#define tya "TYA" |
|
|
|
#define txs "TXS" |
|
|
|
#define lda "LDA" |
|
|
|
#define ldx "LDX" |
|
|
|
#define ldy "LDY" |
|
|
|
#define tax "TAX" |
|
|
|
#define tay "TAY" |
|
|
|
#define bcs "BCS" |
|
|
|
#define clv "CLV" |
|
|
|
#define tsx "TSX" |
|
|
|
#define cpy "CPY" |
|
|
|
#define cpa "CPA" |
|
|
|
#define iny "INY" |
|
|
|
#define dec "DEC" |
|
|
|
#define dex "DEX" |
|
|
|
#define bne "BNE" |
|
|
|
#define cld "CLD" |
|
|
|
#define cpx "CPX" |
|
|
|
#define sbc "SBC" |
|
|
|
#define inc "INC" |
|
|
|
#define inx "INX" |
|
|
|
#define nop "NOP" |
|
|
|
#define beq "BEQ" |
|
|
|
#define sed "SED" |
|
|
|
|
|
|
|
static const e6502_Instruction e6502_instructions[256] = { |
|
|
|
// 0x00 |
|
|
|
[0b00000000] = {brk, adr_imp, 7}, |
|
|
|
|
|
|
|
[0b00000001] = {ora, adr_ind_x, 6}, |
|
|
|
[0b00000101] = {ora, adr_zp, 3}, |
|
|
|
[0b00001001] = {ora, adr_imm, 2}, |
|
|
|
[0b00001101] = {ora, adr_abs, 4}, |
|
|
|
|
|
|
|
[0b00000110] = {asl, adr_zp, 5}, |
|
|
|
[0b00001010] = {asl_a, adr_acc, 2}, |
|
|
|
[0b00001110] = {asl, adr_abs, 6}, |
|
|
|
|
|
|
|
[0b00001000] = {php, adr_imp, 3}, |
|
|
|
|
|
|
|
// 0x10 |
|
|
|
[0b00010000] = {bpl, adr_rel, 2}, |
|
|
|
|
|
|
|
[0b00010001] = {ora, adr_ind_y, 5}, |
|
|
|
[0b00010101] = {ora, adr_zp_x, 4}, |
|
|
|
[0b00011001] = {ora, adr_abs_y, 4}, |
|
|
|
[0b00011101] = {ora, adr_abs_x, 4}, |
|
|
|
|
|
|
|
[0b00011000] = {clc, adr_imp, 2}, |
|
|
|
|
|
|
|
[0b00010110] = {asl, adr_zp_x, 6}, |
|
|
|
[0b00011110] = {asl, adr_abs_x, 7}, |
|
|
|
|
|
|
|
// 0x20 |
|
|
|
[0b00100000] = {jsr, adr_abs, 6}, |
|
|
|
|
|
|
|
[0b00100100] = {bit, adr_zp, 3}, |
|
|
|
[0b00101100] = {bit, adr_abs, 4}, |
|
|
|
|
|
|
|
[0b00100001] = {and, adr_ind_x, 6}, |
|
|
|
[0b00100101] = {and, adr_zp, 3}, |
|
|
|
[0b00101001] = {and, adr_imm, 2}, |
|
|
|
[0b00101101] = {and, adr_abs, 4}, |
|
|
|
|
|
|
|
[0b00100110] = {rol, adr_zp, 5}, |
|
|
|
[0b00101010] = {rol_a, adr_acc, 2}, |
|
|
|
[0b00101110] = {rol, adr_abs, 6}, |
|
|
|
|
|
|
|
[0b00101000] = {plp, adr_imp, 4}, |
|
|
|
|
|
|
|
// 0x30 |
|
|
|
[0b00110000] = {bmi, adr_rel, 2}, |
|
|
|
|
|
|
|
[0b00110001] = {and, adr_ind_y, 5}, |
|
|
|
[0b00110101] = {and, adr_zp_x, 4}, |
|
|
|
[0b00111001] = {and, adr_abs_y, 3}, |
|
|
|
[0b00111101] = {and, adr_abs_x, 3}, |
|
|
|
|
|
|
|
[0b00110110] = {rol, adr_zp_x, 6}, |
|
|
|
[0b00111110] = {rol, adr_abs_x, 7}, |
|
|
|
|
|
|
|
[0b00111000] = {sec, adr_imp, 2}, |
|
|
|
|
|
|
|
// 0x40 |
|
|
|
[0b01000000] = {rti, adr_imp, 6}, |
|
|
|
|
|
|
|
[0b01000001] = {eor, adr_ind_x, 6}, |
|
|
|
[0b01000101] = {eor, adr_zp, 3}, |
|
|
|
[0b01001001] = {eor, adr_imm, 2}, |
|
|
|
[0b01001101] = {eor, adr_abs, 4}, |
|
|
|
|
|
|
|
[0b01000110] = {lsr, adr_zp, 5}, |
|
|
|
[0b01001010] = {lsr_a, adr_acc, 2}, |
|
|
|
[0b01001110] = {lsr, adr_abs, 6}, |
|
|
|
|
|
|
|
[0b01001000] = {pha, adr_imp, 3}, |
|
|
|
|
|
|
|
[0b01001100] = {jmp, adr_abs, 3}, |
|
|
|
|
|
|
|
// 0x50 |
|
|
|
[0b01010000] = {bvc, adr_rel, 2}, |
|
|
|
|
|
|
|
[0b01010001] = {eor, adr_ind_y, 5}, |
|
|
|
[0b01010101] = {eor, adr_zp_x, 4}, |
|
|
|
[0b01011001] = {eor, adr_abs_y, 4}, |
|
|
|
[0b01011101] = {eor, adr_abs_x, 4}, |
|
|
|
|
|
|
|
[0b01010110] = {lsr, adr_zp_x, 6}, |
|
|
|
[0b01011110] = {lsr, adr_abs_x, 7}, |
|
|
|
|
|
|
|
[0b01011000] = {cli, adr_imp, 2}, |
|
|
|
|
|
|
|
// 0x60 |
|
|
|
[0b01100000] = {rts, adr_imp, 6}, |
|
|
|
|
|
|
|
[0b01100001] = {adc, adr_ind_x, 6}, |
|
|
|
[0b01100101] = {adc, adr_zp, 3}, |
|
|
|
[0b01101001] = {adc, adr_imm, 2}, |
|
|
|
[0b01101101] = {adc, adr_abs, 4}, |
|
|
|
|
|
|
|
[0b01100110] = {ror, adr_zp, 5}, |
|
|
|
[0b01101010] = {ror_a, adr_acc, 2}, |
|
|
|
[0b01101110] = {ror, adr_abs, 6}, |
|
|
|
|
|
|
|
[0b01101000] = {pla, adr_imp, 4}, |
|
|
|
|
|
|
|
[0b01101100] = {jmp, adr_ind, 5}, |
|
|
|
|
|
|
|
// 0x70 |
|
|
|
[0b01110000] = {bvs, adr_rel, 2}, |
|
|
|
|
|
|
|
[0b01110001] = {adc, adr_ind_y, 5}, |
|
|
|
[0b01110101] = {adc, adr_zp_x, 4}, |
|
|
|
[0b01111001] = {adc, adr_abs_y, 4}, |
|
|
|
[0b01111101] = {adc, adr_abs_x, 4}, |
|
|
|
|
|
|
|
[0b01110110] = {ror, adr_zp_x, 6}, |
|
|
|
[0b01111110] = {ror, adr_abs_x, 7}, |
|
|
|
|
|
|
|
[0b01111000] = {sei, adr_imp, 2}, |
|
|
|
|
|
|
|
// 0x80 |
|
|
|
[0b10000001] = {sta, adr_ind_x, 6}, |
|
|
|
[0b10000101] = {sta, adr_zp, 3}, |
|
|
|
[0b10001101] = {sta, adr_abs, 4}, |
|
|
|
|
|
|
|
[0b10000110] = {stx, adr_zp, 3}, |
|
|
|
[0b10001110] = {stx, adr_abs, 4}, |
|
|
|
|
|
|
|
[0b10000100] = {sty, adr_zp, 3}, |
|
|
|
[0b10001100] = {sty, adr_abs, 4}, |
|
|
|
|
|
|
|
[0b10001000] = {dey, adr_imp, 2}, |
|
|
|
|
|
|
|
[0b10001010] = {txa, adr_imp, 2}, |
|
|
|
|
|
|
|
// 0x90 |
|
|
|
[0b10010000] = {bcc, adr_rel, 2}, |
|
|
|
|
|
|
|
[0b10010001] = {sta, adr_ind_y, 6}, |
|
|
|
[0b10010101] = {sta, adr_zp_x, 4}, |
|
|
|
[0b10011001] = {sta, adr_abs_y, 5}, |
|
|
|
[0b10011101] = {sta, adr_abs_x, 5}, |
|
|
|
|
|
|
|
[0b10010110] = {stx, adr_zp_y, 4}, |
|
|
|
|
|
|
|
[0b10010100] = {sty, adr_zp_x, 4}, |
|
|
|
|
|
|
|
[0b10011000] = {tya, adr_imp, 2}, |
|
|
|
[0b10011010] = {txs, adr_imp, 2}, |
|
|
|
|
|
|
|
// 0xA0 |
|
|
|
[0b10100001] = {lda, adr_ind_x, 6}, |
|
|
|
[0b10100101] = {lda, adr_zp, 3}, |
|
|
|
[0b10101001] = {lda, adr_imm, 2}, |
|
|
|
[0b10101101] = {lda, adr_abs, 4}, |
|
|
|
|
|
|
|
[0b10100010] = {ldx, adr_imm, 2}, |
|
|
|
[0b10100110] = {ldx, adr_zp, 3}, |
|
|
|
[0b10101110] = {ldx, adr_abs, 4}, |
|
|
|
|
|
|
|
[0b10100000] = {ldy, adr_imm, 2}, |
|
|
|
[0b10100100] = {ldy, adr_zp, 3}, |
|
|
|
[0b10101100] = {ldy, adr_abs, 4}, |
|
|
|
|
|
|
|
[0b10101010] = {tax, adr_imp, 2}, |
|
|
|
[0b10101000] = {tay, adr_imp, 2}, |
|
|
|
|
|
|
|
// 0xB0 |
|
|
|
[0b10110000] = {bcs, adr_rel, 2}, |
|
|
|
|
|
|
|
[0b10110001] = {lda, adr_ind_y, 5}, |
|
|
|
[0b10110101] = {lda, adr_zp_x, 4}, |
|
|
|
[0b10111001] = {lda, adr_abs_y, 4}, |
|
|
|
[0b10111101] = {lda, adr_abs_x, 4}, |
|
|
|
|
|
|
|
[0b10110110] = {ldx, adr_zp_y, 4}, |
|
|
|
[0b10111110] = {ldx, adr_abs_y, 4}, |
|
|
|
|
|
|
|
[0b10110100] = {ldy, adr_zp_x, 4}, |
|
|
|
[0b10111100] = {ldy, adr_abs_x, 4}, |
|
|
|
|
|
|
|
[0b10111000] = {clv, adr_imp, 2}, |
|
|
|
|
|
|
|
[0b10111010] = {tsx, adr_imp, 2}, |
|
|
|
|
|
|
|
// 0xC0 |
|
|
|
[0b11000000] = {cpy, adr_imm, 2}, |
|
|
|
[0b11000100] = {cpy, adr_zp, 3}, |
|
|
|
[0b11001100] = {cpy, adr_abs, 4}, |
|
|
|
|
|
|
|
[0b11000001] = {cpa, adr_ind_x, 6}, |
|
|
|
[0b11000101] = {cpa, adr_zp, 3}, |
|
|
|
[0b11001001] = {cpa, adr_imm, 2}, |
|
|
|
[0b11001101] = {cpa, adr_abs, 4}, |
|
|
|
|
|
|
|
[0b11001000] = {iny, adr_imp, 2}, |
|
|
|
|
|
|
|
[0b11000110] = {dec, adr_zp, 5}, |
|
|
|
[0b11001110] = {dec, adr_abs, 6}, |
|
|
|
[0b11010110] = {dec, adr_zp_x, 6}, |
|
|
|
[0b11011110] = {dec, adr_abs_x, 7}, |
|
|
|
|
|
|
|
[0b11001010] = {dex, adr_imp, 2}, |
|
|
|
|
|
|
|
// 0xD0 |
|
|
|
[0b11010000] = {bne, adr_rel, 2}, |
|
|
|
|
|
|
|
[0b11011000] = {cld, adr_imp, 2}, |
|
|
|
|
|
|
|
[0b11010001] = {cpa, adr_ind_y, 5}, |
|
|
|
[0b11010101] = {cpa, adr_zp_x, 4}, |
|
|
|
[0b11011001] = {cpa, adr_abs_y, 4}, |
|
|
|
[0b11011101] = {cpa, adr_abs_x, 4}, |
|
|
|
|
|
|
|
// 0xE0 |
|
|
|
[0b11100000] = {cpx, adr_imm, 2}, |
|
|
|
[0b11100100] = {cpx, adr_zp, 3}, |
|
|
|
[0b11101100] = {cpx, adr_abs, 4}, |
|
|
|
|
|
|
|
[0b11100001] = {sbc, adr_ind_x, 6}, |
|
|
|
[0b11100101] = {sbc, adr_zp, 3}, |
|
|
|
[0b11101001] = {sbc, adr_imm, 2}, |
|
|
|
[0b11101101] = {sbc, adr_abs, 4}, |
|
|
|
|
|
|
|
[0b11100110] = {inc, adr_zp, 5}, |
|
|
|
[0b11101110] = {inc, adr_abs, 6}, |
|
|
|
|
|
|
|
[0b11101000] = {inx, adr_imp, 2}, |
|
|
|
|
|
|
|
[0b11101010] = {nop, adr_imp, 2}, |
|
|
|
|
|
|
|
// 0xF0 |
|
|
|
[0b11110000] = {beq, adr_rel, 2}, |
|
|
|
|
|
|
|
[0b11110001] = {sbc, adr_ind_y, 5}, |
|
|
|
[0b11110101] = {sbc, adr_zp_x, 4}, |
|
|
|
[0b11111001] = {sbc, adr_abs_y, 4}, |
|
|
|
[0b11111101] = {sbc, adr_abs_x, 4}, |
|
|
|
|
|
|
|
[0b11110110] = {inc, adr_zp_x, 6}, |
|
|
|
[0b11111110] = {inc, adr_abs_x, 7}, |
|
|
|
|
|
|
|
[0b11111000] = {sed, adr_imp, 2}, |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
int e6502_fprintf_instr(FILE* file, |
|
|
|
uint8_t opcode, uint8_t* operand) { |
|
|
|
int ret = 0; |
|
|
|
const e6502_Instruction* instr = &e6502_instructions[opcode]; |
|
|
|
if (NULL == instr) { |
|
|
|
ret += fprintf(file, "ILLEGAL: $%02x", opcode); |
|
|
|
} else { |
|
|
|
ret += fputs(instr->operator, file); |
|
|
|
if (NULL != instr->mode) { |
|
|
|
char str[16] = {0}; |
|
|
|
int len = instr->mode(operand, str, sizeof(str) - 1); |
|
|
|
ret += fprintf(file, " %.*s", len, str); |
|
|
|
} |
|
|
|
} |
|
|
|
return ret; |
|
|
|
} |