- Passes Klaus Dormann's functional testsv2
| @@ -0,0 +1,20 @@ | |||
| #CROSS_COMPILE = arm-none-eabi- | |||
| CC = $(CROSS_COMPILE)gcc | |||
| LD = $(CC) | |||
| #CFLAGS = -mcpu=cortex-m33 -mthumb | |||
| CFLAGS += -Wall -Werror -Wshadow | |||
| CFLAGS += -g -Ofast | |||
| CFLAGS += -DF6502_FLAT | |||
| CFLAGS += -DF6502_TEST | |||
| CFLAGS += -DF6502_HCF | |||
| #CFLAGS += -DF6502_TRACE | |||
| OBJS = src/f6502.o src/f6502_opcodes.o test.o | |||
| all: test | |||
| test: $(OBJS) | |||
| $(LD) $(LDFLAGS) -o $@ $^ | |||
| clean: | |||
| rm -rf $(OBJS) | |||
| @@ -0,0 +1,65 @@ | |||
| #ifndef F6502_H_ | |||
| #define F6502_H_ | |||
| #include <stdint.h> | |||
| #define F6502_RAM_SIZE (0x2000U) | |||
| typedef enum { | |||
| f6502_Status_C = 0b00000001, | |||
| f6502_Status_Z = 0b00000010, | |||
| f6502_Status_I = 0b00000100, | |||
| f6502_Status_D = 0b00001000, | |||
| f6502_Status_B = 0b00010000, | |||
| f6502_Status_1 = 0b00100000, | |||
| f6502_Status_V = 0b01000000, | |||
| f6502_Status_N = 0b10000000, | |||
| } f6502_Status_Flag; | |||
| #define f6502_Base_Stack (0x0100U) | |||
| #define f6502_Vector_IRQ (0xFFFEU) | |||
| #define f6502_Vector_Reset (0xFFFCU) | |||
| #define f6502_Vector_NMI (0xFFFAU) | |||
| typedef struct __attribute__ ((__packed__)) { | |||
| uint16_t PC; | |||
| uint8_t S; | |||
| uint8_t A; | |||
| uint8_t X; | |||
| uint8_t Y; | |||
| uint8_t P; | |||
| } f6502_Registers; | |||
| typedef enum { | |||
| f6502_Int_NMI = 0b01, | |||
| f6502_Int_IRQ = 0b10, | |||
| } f6502_Interrupt; | |||
| typedef struct __attribute__ ((__packed__)) { | |||
| #ifdef F6502_FLAT | |||
| uint8_t ram[65536]; | |||
| #else | |||
| uint8_t ram[F6502_RAM_SIZE / 4]; // Mirrored 3x | |||
| uint8_t *sram_bank; | |||
| uint8_t *rom_bank[4]; | |||
| // TODO | |||
| #endif | |||
| } f6502_Memory; | |||
| typedef struct __attribute__ ((__packed__)) { | |||
| f6502_Registers registers; | |||
| f6502_Interrupt int_state:2; | |||
| f6502_Interrupt int_wiring:2; | |||
| f6502_Memory memory; | |||
| } f6502_Core; | |||
| void f6502_init(f6502_Core*); | |||
| void f6502_reset(f6502_Core*); | |||
| int f6502_step(f6502_Core*, int clocks); | |||
| void f6502_wire_interrupts(f6502_Core*, f6502_Interrupt ints); | |||
| #endif // F6502_H_ | |||
| @@ -0,0 +1,390 @@ | |||
| static const uint8_t table_test[256] = { | |||
| [0] = f6502_Status_Z, | |||
| [128] = f6502_Status_N, | |||
| [129] = f6502_Status_N, | |||
| [130] = f6502_Status_N, | |||
| [131] = f6502_Status_N, | |||
| [132] = f6502_Status_N, | |||
| [133] = f6502_Status_N, | |||
| [134] = f6502_Status_N, | |||
| [135] = f6502_Status_N, | |||
| [136] = f6502_Status_N, | |||
| [137] = f6502_Status_N, | |||
| [138] = f6502_Status_N, | |||
| [139] = f6502_Status_N, | |||
| [140] = f6502_Status_N, | |||
| [141] = f6502_Status_N, | |||
| [142] = f6502_Status_N, | |||
| [143] = f6502_Status_N, | |||
| [144] = f6502_Status_N, | |||
| [145] = f6502_Status_N, | |||
| [146] = f6502_Status_N, | |||
| [147] = f6502_Status_N, | |||
| [148] = f6502_Status_N, | |||
| [149] = f6502_Status_N, | |||
| [150] = f6502_Status_N, | |||
| [151] = f6502_Status_N, | |||
| [152] = f6502_Status_N, | |||
| [153] = f6502_Status_N, | |||
| [154] = f6502_Status_N, | |||
| [155] = f6502_Status_N, | |||
| [156] = f6502_Status_N, | |||
| [157] = f6502_Status_N, | |||
| [158] = f6502_Status_N, | |||
| [159] = f6502_Status_N, | |||
| [160] = f6502_Status_N, | |||
| [161] = f6502_Status_N, | |||
| [162] = f6502_Status_N, | |||
| [163] = f6502_Status_N, | |||
| [164] = f6502_Status_N, | |||
| [165] = f6502_Status_N, | |||
| [166] = f6502_Status_N, | |||
| [167] = f6502_Status_N, | |||
| [168] = f6502_Status_N, | |||
| [169] = f6502_Status_N, | |||
| [170] = f6502_Status_N, | |||
| [171] = f6502_Status_N, | |||
| [172] = f6502_Status_N, | |||
| [173] = f6502_Status_N, | |||
| [174] = f6502_Status_N, | |||
| [175] = f6502_Status_N, | |||
| [176] = f6502_Status_N, | |||
| [177] = f6502_Status_N, | |||
| [178] = f6502_Status_N, | |||
| [179] = f6502_Status_N, | |||
| [180] = f6502_Status_N, | |||
| [181] = f6502_Status_N, | |||
| [182] = f6502_Status_N, | |||
| [183] = f6502_Status_N, | |||
| [184] = f6502_Status_N, | |||
| [185] = f6502_Status_N, | |||
| [186] = f6502_Status_N, | |||
| [187] = f6502_Status_N, | |||
| [188] = f6502_Status_N, | |||
| [189] = f6502_Status_N, | |||
| [190] = f6502_Status_N, | |||
| [191] = f6502_Status_N, | |||
| [192] = f6502_Status_N, | |||
| [193] = f6502_Status_N, | |||
| [194] = f6502_Status_N, | |||
| [195] = f6502_Status_N, | |||
| [196] = f6502_Status_N, | |||
| [197] = f6502_Status_N, | |||
| [198] = f6502_Status_N, | |||
| [199] = f6502_Status_N, | |||
| [200] = f6502_Status_N, | |||
| [201] = f6502_Status_N, | |||
| [202] = f6502_Status_N, | |||
| [203] = f6502_Status_N, | |||
| [204] = f6502_Status_N, | |||
| [205] = f6502_Status_N, | |||
| [206] = f6502_Status_N, | |||
| [207] = f6502_Status_N, | |||
| [208] = f6502_Status_N, | |||
| [209] = f6502_Status_N, | |||
| [210] = f6502_Status_N, | |||
| [211] = f6502_Status_N, | |||
| [212] = f6502_Status_N, | |||
| [213] = f6502_Status_N, | |||
| [214] = f6502_Status_N, | |||
| [215] = f6502_Status_N, | |||
| [216] = f6502_Status_N, | |||
| [217] = f6502_Status_N, | |||
| [218] = f6502_Status_N, | |||
| [219] = f6502_Status_N, | |||
| [220] = f6502_Status_N, | |||
| [221] = f6502_Status_N, | |||
| [222] = f6502_Status_N, | |||
| [223] = f6502_Status_N, | |||
| [224] = f6502_Status_N, | |||
| [225] = f6502_Status_N, | |||
| [226] = f6502_Status_N, | |||
| [227] = f6502_Status_N, | |||
| [228] = f6502_Status_N, | |||
| [229] = f6502_Status_N, | |||
| [230] = f6502_Status_N, | |||
| [231] = f6502_Status_N, | |||
| [232] = f6502_Status_N, | |||
| [233] = f6502_Status_N, | |||
| [234] = f6502_Status_N, | |||
| [235] = f6502_Status_N, | |||
| [236] = f6502_Status_N, | |||
| [237] = f6502_Status_N, | |||
| [238] = f6502_Status_N, | |||
| [239] = f6502_Status_N, | |||
| [240] = f6502_Status_N, | |||
| [241] = f6502_Status_N, | |||
| [242] = f6502_Status_N, | |||
| [243] = f6502_Status_N, | |||
| [244] = f6502_Status_N, | |||
| [245] = f6502_Status_N, | |||
| [246] = f6502_Status_N, | |||
| [247] = f6502_Status_N, | |||
| [248] = f6502_Status_N, | |||
| [249] = f6502_Status_N, | |||
| [250] = f6502_Status_N, | |||
| [251] = f6502_Status_N, | |||
| [252] = f6502_Status_N, | |||
| [253] = f6502_Status_N, | |||
| [254] = f6502_Status_N, | |||
| [255] = f6502_Status_N, | |||
| }; | |||
| static const uint8_t table_asl[256] = { | |||
| f6502_Status_Z, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| 0, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_Z, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| f6502_Status_C | f6502_Status_N, | |||
| }; | |||
| @@ -0,0 +1,422 @@ | |||
| #include <stdint.h> | |||
| #include <stdio.h> | |||
| #include "f6502.h" | |||
| #include "f6502_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* op, | |||
| char* str, int max) { | |||
| return snprintf(str, max, "$%04X,%c", *(uint16_t*)op, 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 | |||
| } f6502_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 f6502_Instruction f6502_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 f6502_fprintf_instr(FILE* file, | |||
| uint8_t opcode, uint8_t* operand) { | |||
| int ret = 0; | |||
| const f6502_Instruction* instr = &f6502_instructions[opcode]; | |||
| if (NULL == instr->operator) { | |||
| 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; | |||
| } | |||
| static int f6502_instr_size(uint8_t opcode) { | |||
| const f6502_Instruction* instr = &f6502_instructions[opcode]; | |||
| if ( instr->mode == adr_imp || | |||
| instr->mode == adr_acc) { | |||
| return 1; | |||
| } else if ( instr->mode == adr_abs || | |||
| instr->mode == adr_abs_x || | |||
| instr->mode == adr_abs_y) { | |||
| return 3; | |||
| } else { | |||
| return 2; | |||
| } | |||
| } | |||
| void f6502_dump_instr(f6502_Core* core, uint16_t addr) { | |||
| uint8_t opcode = core->memory.ram[addr]; | |||
| int size = f6502_instr_size(opcode); | |||
| printf("$%02x", opcode); | |||
| if (size == 2) { | |||
| printf(" $%02x", core->memory.ram[addr + 1]); | |||
| } else if (size == 3) { | |||
| printf(" $%04x", core->memory.ram[addr + 1] | | |||
| ((uint16_t)core->memory.ram[addr + 2] << 8)); | |||
| } | |||
| } | |||
| @@ -0,0 +1,13 @@ | |||
| #ifndef F6502_OPCODES_H_ | |||
| #define F6502_OPCODES_H_ | |||
| #include <stdio.h> | |||
| int f6502_fprintf_instr(FILE* file, | |||
| uint8_t opcode, uint8_t* operand); | |||
| void f6502_dump_instr(f6502_Core* core, uint16_t addr); | |||
| #endif // F6502_OPCODES_H_ | |||
| @@ -0,0 +1,47 @@ | |||
| #include <stdio.h> | |||
| #include "src/f6502.h" | |||
| int load(uint8_t* mem, FILE* file) { | |||
| return fread(mem, 65536, 1, file); | |||
| } | |||
| void print_registers(const f6502_Registers* regs, | |||
| FILE* file) { | |||
| fprintf(file, "PC: $%04x\n", regs->PC); | |||
| fprintf(file, " S: $%02x\n", regs->S); | |||
| fprintf(file, " A: $%02x\n", regs->A); | |||
| fprintf(file, " X: $%02x\n", regs->X); | |||
| fprintf(file, " Y: $%02x\n", regs->Y); | |||
| fprintf(file, " P: $%02x\n", regs->P); | |||
| } | |||
| static f6502_Core core = {0}; | |||
| int main(int argc, char* argv[]) { | |||
| f6502_init(&core); | |||
| if (load(core.memory.ram, stdin) != 1) { | |||
| fprintf(stderr, "Failed to load e6502 memory\n"); | |||
| return 1; | |||
| } | |||
| core.memory.ram[0xbffc] = 0; | |||
| f6502_reset(&core); | |||
| core.registers.PC = 0x400; | |||
| int total_clocks = 0; | |||
| int clocks_elapsed = 1; | |||
| while (clocks_elapsed > 0) { | |||
| clocks_elapsed = f6502_step(&core, 1000); | |||
| if (clocks_elapsed < 0) total_clocks -= clocks_elapsed; | |||
| else total_clocks += clocks_elapsed; | |||
| } | |||
| fprintf(stdout, "Ran %d\n", total_clocks); | |||
| print_registers(&core.registers, stdout); | |||
| return 0; | |||
| } | |||
| @@ -0,0 +1 @@ | |||
| 0.2.0 | |||