Browse Source

Add V2 6502 core emulation and basic test support

- Passes Klaus Dormann's functional tests
v2
Nathaniel Walizer 9 months ago
parent
commit
63e2e129d1
8 changed files with 2363 additions and 0 deletions
  1. +20
    -0
      Makefile
  2. +1405
    -0
      src/f6502.c
  3. +65
    -0
      src/f6502.h
  4. +390
    -0
      src/f6502_consts.h
  5. +422
    -0
      src/f6502_opcodes.c
  6. +13
    -0
      src/f6502_opcodes.h
  7. +47
    -0
      test.c
  8. +1
    -0
      version

+ 20
- 0
Makefile View File

@@ -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)

+ 1405
- 0
src/f6502.c
File diff suppressed because it is too large
View File


+ 65
- 0
src/f6502.h View File

@@ -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_

+ 390
- 0
src/f6502_consts.h View File

@@ -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,
};

+ 422
- 0
src/f6502_opcodes.c View File

@@ -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));
}
}

+ 13
- 0
src/f6502_opcodes.h View File

@@ -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_

+ 47
- 0
test.c View File

@@ -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;
}

+ 1
- 0
version View File

@@ -0,0 +1 @@
0.2.0

Loading…
Cancel
Save