Bläddra i källkod

First commit of functioning 6502 emulator

- Passes Klaus Dormann's functional tests
 - Internal memory must be polled
 - Registers not named by convention
master
Nathaniel Walizer 1 år sedan
incheckning
1e9070ecd3
2 ändrade filer med 936 tillägg och 0 borttagningar
  1. +842
    -0
      e6502.c
  2. +94
    -0
      e6502.h

+ 842
- 0
e6502.c Visa fil

@@ -0,0 +1,842 @@
#include "e6502.h"


// Instruction Addressing

typedef uint8_t* e6502_Address;

static inline e6502_Address e6502_mem_adr(e6502_Core* core,
e6502_Mem_Addr adr) {
return &core->memory[adr];
}

static inline e6502_Mem_Addr e6502_adr_mem(e6502_Core* core,
e6502_Address adr) {
return (adr - core->memory);
}



static inline uint8_t e6502_adr_r8(e6502_Core*,
e6502_Address adr) {
return *adr;
}

static inline uint8_t e6502_adr_r16(e6502_Core*,
e6502_Address adr) {
return *(uint16_t*)adr;
}

static inline void e6502_adr_w8(e6502_Core*,
e6502_Address adr,
uint8_t val) {
*adr = val;
}

static inline void e6502_adr_w16(e6502_Core*,
e6502_Address adr,
uint16_t val) {
*(uint16_t*)adr = val;
}


// Read values after opcodes

static inline uint8_t arg8(e6502_Core* core) {
return e6502_r8(core, core->registers.PC++);
}

static inline uint16_t arg16(e6502_Core* core) {
return (arg8(core) | ((uint16_t)arg8(core) << 8));
}


// Interpret opcode values

static inline e6502_Address adr_none(e6502_Core*) {
return 0;
}

static inline e6502_Address adr_ind(e6502_Core* core) {
return e6502_mem_adr(core, e6502_r16(core, arg16(core)));
}

static inline e6502_Address adr_ind_x(e6502_Core* core) {
return e6502_mem_adr(core, e6502_r16(
core,
(uint8_t)(core->registers.X + arg8(core))
));
}

static inline e6502_Address adr_ind_y(e6502_Core* core) {
uint16_t zp_adr = e6502_r16(core, arg8(core));
uint8_t old_page = zp_adr >> 8;
uint16_t new_adr = core->registers.Y + zp_adr;
if (new_adr >> 8 != old_page) core->cycle++;
return e6502_mem_adr(core, new_adr);
}

static inline e6502_Address adr_abs_i(e6502_Core* core,
uint8_t i) {
uint16_t abs_adr = arg16(core);
uint8_t old_page = abs_adr >> 8;
uint16_t new_adr = i + abs_adr;
if (new_adr >> 8 != old_page) core->cycle++;
return e6502_mem_adr(core, new_adr);
}

static inline e6502_Address adr_abs_x(e6502_Core* core) {
return adr_abs_i(core, core->registers.X);
}

static inline e6502_Address adr_abs_y(e6502_Core* core) {
return adr_abs_i(core, core->registers.Y);
}

static inline e6502_Address adr_zp(e6502_Core* core) {
return e6502_mem_adr(core, arg8(core));
}

static inline e6502_Address adr_zp_x(e6502_Core* core) {
return e6502_mem_adr(
core, (uint8_t)(arg8(core) + core->registers.X)
);
}

static inline e6502_Address adr_zp_y(e6502_Core* core) {
return e6502_mem_adr(
core, (uint8_t)(arg8(core) + core->registers.Y)
);
}

static inline e6502_Address adr_abs(e6502_Core* core) {
return e6502_mem_adr(core, arg16(core));
}

static inline e6502_Address adr_imm(e6502_Core* core) {
return e6502_mem_adr(core, core->registers.PC++);
}

static inline e6502_Address adr_rel(e6502_Core* core) {
return e6502_mem_adr(
core, (int8_t)arg8(core) + core->registers.PC
);
}

static inline e6502_Address adr_reg_a (e6502_Core* core) {
return &core->registers.A;
}

static inline e6502_Address adr_reg_x (e6502_Core* core) {
return &core->registers.X;
}

static inline e6502_Address adr_reg_y (e6502_Core* core) {
return &core->registers.Y;
}

static inline e6502_Address adr_reg_s (e6502_Core* core) {
return &core->registers.S;
}

static inline e6502_Address adr_reg_sp (e6502_Core* core) {
return &core->registers.SP;
}

// Instructions

static inline void nop(e6502_Core*, e6502_Address) {
// NOP
}

static inline void brk(e6502_Core *core, e6502_Address) {
e6502_push16(core, core->registers.PC + 1);
e6502_push8(core, core->registers.S |
e6502_Status_1 |
e6502_Status_B);
core->registers.S |= e6502_Status_I;
core->registers.PC = e6502_r16(core, e6502_IRQ_Vec);
}

static inline void rti(e6502_Core *core, e6502_Address) {
core->registers.S = e6502_pop8(core) & ~(e6502_Status_B);
core->registers.PC = e6502_pop16(core);
}

static inline void ora(e6502_Core *core, e6502_Address adr) {
core->registers.A |= e6502_adr_r8(core, adr);
core->registers.S &= ~(e6502_Status_Z | e6502_Status_N);
core->registers.S |= (core->registers.A & e6502_Status_N);
if (!core->registers.A) core->registers.S |= e6502_Status_Z;
}

static inline void eor(e6502_Core *core, e6502_Address adr) {
core->registers.A ^= e6502_adr_r8(core, adr);
core->registers.S &= ~(e6502_Status_Z | e6502_Status_N);
core->registers.S |= (core->registers.A & e6502_Status_N);
if (!core->registers.A) core->registers.S |= e6502_Status_Z;
}

static inline void asl(e6502_Core *core, e6502_Address adr) {
uint8_t val = e6502_adr_r8(core, adr);
core->registers.S &= ~(e6502_Status_C |
e6502_Status_Z |
e6502_Status_N);
if (val & 0x80) core->registers.S |= e6502_Status_C;
val <<= 1;
core->registers.S |= (val & e6502_Status_N);
if (!val) core->registers.S |= e6502_Status_Z;
e6502_adr_w8(core, adr, val);
}

static inline void lsr(e6502_Core *core, e6502_Address adr) {
uint8_t val = e6502_adr_r8(core, adr);
core->registers.S &= ~(e6502_Status_C |
e6502_Status_Z |
e6502_Status_N);
core->registers.S |= (val & e6502_Status_C);
val >>= 1;
core->registers.S |= (val & e6502_Status_N);
if (!val) core->registers.S |= e6502_Status_Z;
e6502_adr_w8(core, adr, val);
}

static inline void rol(e6502_Core *core, e6502_Address adr) {
uint8_t val = e6502_adr_r8(core, adr);
uint8_t new_c = (val & 0x80) ? e6502_Status_C : 0;
val <<= 1;
val |= (core->registers.S & e6502_Status_C);
core->registers.S &= ~(e6502_Status_C |
e6502_Status_Z |
e6502_Status_N);
core->registers.S |= new_c;
if (!val) core->registers.S |= e6502_Status_Z;
core->registers.S |= (val & e6502_Status_N);
e6502_adr_w8(core, adr, val);
}

static inline void ror(e6502_Core *core, e6502_Address adr) {
uint8_t val = e6502_adr_r8(core, adr);
uint8_t new_c = (val & e6502_Status_C);
val >>= 1;
if (core->registers.S & e6502_Status_C) val |= e6502_Status_N;
core->registers.S &= ~(e6502_Status_C |
e6502_Status_Z |
e6502_Status_N);
core->registers.S |= new_c;
if (!val) core->registers.S |= e6502_Status_Z;
core->registers.S |= (val & e6502_Status_N);
e6502_adr_w8(core, adr, val);
}

static inline void pha(e6502_Core *core, e6502_Address adr) {
e6502_push8(core, core->registers.A);
}

static inline void php(e6502_Core *core, e6502_Address adr) {
e6502_push8(core, core->registers.S |
e6502_Status_1 |
e6502_Status_B);
}

static inline void pla(e6502_Core *core, e6502_Address adr) {
core->registers.A = e6502_pop8(core);
core->registers.S &= ~(e6502_Status_Z | e6502_Status_N);
if (!core->registers.A) core->registers.S |= e6502_Status_Z;
core->registers.S |= (core->registers.A & e6502_Status_N);
}

static inline void plp(e6502_Core *core, e6502_Address adr) {
core->registers.S = (e6502_pop8(core) |
e6502_Status_1 |
e6502_Status_B);
}

static inline void b(e6502_Core *core, e6502_Address adr) {
uint8_t old_page = core->registers.PC >> 8;
uint16_t new_addr = e6502_adr_mem(core, adr);
if (old_page != (new_addr >> 8)) core->cycle++;
core->registers.PC = new_addr;
core->cycle++;
}

static inline void bpl(e6502_Core *core, e6502_Address adr) {
if (!(core->registers.S & e6502_Status_N)) {
b(core, adr);
}
}

static inline void bmi(e6502_Core *core, e6502_Address adr) {
if (core->registers.S & e6502_Status_N) {
b(core, adr);
}
}

static inline void bcc(e6502_Core *core, e6502_Address adr) {
if (!(core->registers.S & e6502_Status_C)) {
b(core, adr);
}
}

static inline void bcs(e6502_Core *core, e6502_Address adr) {
if (core->registers.S & e6502_Status_C) {
b(core, adr);
}
}

static inline void bvc(e6502_Core *core, e6502_Address adr) {
if (!(core->registers.S & e6502_Status_V)) {
b(core, adr);
}
}

static inline void bvs(e6502_Core *core, e6502_Address adr) {
if (core->registers.S & e6502_Status_V) {
b(core, adr);
}
}

static inline void bne(e6502_Core *core, e6502_Address adr) {
if (!(core->registers.S & e6502_Status_Z)) {
b(core, adr);
}
}

static inline void beq(e6502_Core *core, e6502_Address adr) {
if (core->registers.S & e6502_Status_Z) {
b(core, adr);
}
}

static inline void clc(e6502_Core *core, e6502_Address) {
core->registers.S &= ~e6502_Status_C;
}

static inline void cli(e6502_Core *core, e6502_Address) {
core->registers.S &= ~e6502_Status_I;
}

static inline void cld(e6502_Core *core, e6502_Address) {
core->registers.S &= ~e6502_Status_D;
}

static inline void clv(e6502_Core *core, e6502_Address) {
core->registers.S &= ~e6502_Status_V;
}

static inline void sec(e6502_Core *core, e6502_Address) {
core->registers.S |= e6502_Status_C;
}

static inline void sei(e6502_Core *core, e6502_Address) {
core->registers.S |= e6502_Status_I;
}

static inline void sed(e6502_Core *core, e6502_Address) {
core->registers.S |= e6502_Status_D;
}

static inline void jsr(e6502_Core *core, e6502_Address adr) {
e6502_push16(core, core->registers.PC - 1);
core->registers.PC = e6502_adr_mem(core, adr);
}

static inline void rts(e6502_Core *core, e6502_Address) {
core->registers.PC = e6502_pop16(core) + 1;
}

static inline void jmp(e6502_Core *core, e6502_Address adr) {
core->registers.PC = e6502_adr_mem(core, adr);
}

static inline void bit(e6502_Core *core, e6502_Address adr) {
uint8_t val = e6502_adr_r8(core, adr);
core->registers.S &= ~(e6502_Status_Z |
e6502_Status_V |
e6502_Status_N);
core->registers.S |= (val & (e6502_Status_V |
e6502_Status_N));
if (!(val & core->registers.A)) {
core->registers.S |= e6502_Status_Z;
}
}

static inline void cmp(e6502_Core *core,
e6502_Address adr,
uint8_t minuend) {
uint8_t val = e6502_adr_r8(core, adr);
uint8_t diff = minuend - val;
core->registers.S &= ~(e6502_Status_C |
e6502_Status_Z |
e6502_Status_N);
if (minuend >= val) core->registers.S |= e6502_Status_C;
if (diff == 0) core->registers.S |= e6502_Status_Z;
core->registers.S |= (diff & e6502_Status_N);
}

static inline void cpa(e6502_Core *core, e6502_Address adr) {
cmp(core, adr, core->registers.A);
}

static inline void cpx(e6502_Core *core, e6502_Address adr) {
cmp(core, adr, core->registers.X);
}

static inline void cpy(e6502_Core *core, e6502_Address adr) {
cmp(core, adr, core->registers.Y);
}

static inline void and(e6502_Core *core, e6502_Address adr) {
core->registers.A &= e6502_adr_r8(core, adr);
core->registers.S &= ~(e6502_Status_Z | e6502_Status_N);
core->registers.S |= (core->registers.A & e6502_Status_N);
if (!core->registers.A) core->registers.S |= e6502_Status_Z;
}

static inline void adc(e6502_Core *core, e6502_Address adr) {
uint8_t addend = e6502_adr_r8(core, adr);
uint32_t sum = core->registers.A +
addend +
(core->registers.S & e6502_Status_C);
core->registers.S &= ~(e6502_Status_C | e6502_Status_Z |
e6502_Status_V | e6502_Status_N);
if (sum > 0xFF) core->registers.S |= e6502_Status_C;
if (!(uint8_t)sum) core->registers.S |= e6502_Status_Z;
if ( (addend & 0x80) == (core->registers.A & 0x80) &&
(sum & 0x80) != (addend & 0x80)) {
core->registers.S |= e6502_Status_V;
}
core->registers.S |= (sum & e6502_Status_N);
core->registers.A = sum;
}

static inline void sbc(e6502_Core *core, e6502_Address adr) {
uint8_t addend = e6502_adr_r8(core, adr);
uint32_t sum = core->registers.A -
addend -
(1 - (core->registers.S & e6502_Status_C));
core->registers.S &= ~(e6502_Status_C | e6502_Status_Z |
e6502_Status_V | e6502_Status_N);
if (sum < 0x100) core->registers.S |= e6502_Status_C;
if (!(uint8_t)sum) core->registers.S |= e6502_Status_Z;
if ( (sum & 0x80) != (core->registers.A & 0x80) &&
(addend & 0x80) != (core->registers.A & 0x80)) {
core->registers.S |= e6502_Status_V;
}
core->registers.S |= (sum & e6502_Status_N);
core->registers.A = sum;
}

static inline void inc(e6502_Core *core, e6502_Address adr) {
uint8_t val = e6502_adr_r8(core, adr) + 1;
core->registers.S &= ~(e6502_Status_Z | e6502_Status_N);
core->registers.S |= (val & e6502_Status_N);
if (!val) core->registers.S |= e6502_Status_Z;
e6502_adr_w8(core, adr, val);
}

static inline void dec(e6502_Core *core, e6502_Address adr) {
uint8_t val = e6502_adr_r8(core, adr) - 1;
core->registers.S &= ~(e6502_Status_Z | e6502_Status_N);
core->registers.S |= (val & e6502_Status_N);
if (!val) core->registers.S |= e6502_Status_Z;
e6502_adr_w8(core, adr, val);
}

static inline void sta(e6502_Core *core, e6502_Address adr) {
e6502_adr_w8(core, adr, core->registers.A);
}

static inline void stx(e6502_Core *core, e6502_Address adr) {
e6502_adr_w8(core, adr, core->registers.X);
}

static inline void sty(e6502_Core *core, e6502_Address adr) {
e6502_adr_w8(core, adr, core->registers.Y);
}

static inline void t(e6502_Core *core,
e6502_Address adr,
uint8_t reg) {
core->registers.S &= ~(e6502_Status_Z | e6502_Status_N);
core->registers.S |= (reg & e6502_Status_N);
if (!reg) core->registers.S |= e6502_Status_Z;
e6502_adr_w8(core, adr, reg);
}

static inline void ta(e6502_Core *core, e6502_Address adr) {
t(core, adr, core->registers.A);
}

static inline void txs(e6502_Core *core, e6502_Address adr) {
core->registers.SP = core->registers.X;
}

static inline void txa(e6502_Core *core, e6502_Address adr) {
t(core, &core->registers.A, core->registers.X);
}

static inline void ty(e6502_Core *core, e6502_Address adr) {
t(core, adr, core->registers.Y);
}

static inline void ts(e6502_Core *core, e6502_Address adr) {
t(core, adr, core->registers.SP);
}

static inline void lda(e6502_Core *core, e6502_Address adr) {
t(core, &core->registers.A, e6502_adr_r8(core, adr));
}

static inline void ldx(e6502_Core *core, e6502_Address adr) {
t(core, &core->registers.X, e6502_adr_r8(core, adr));
}

static inline void ldy(e6502_Core *core, e6502_Address adr) {
t(core, &core->registers.Y, e6502_adr_r8(core, adr));
}


typedef struct {
void(*operator)(e6502_Core*, e6502_Address);
e6502_Address(*address)(e6502_Core*);
uint16_t cycles;
} e6502_Instruction;

static e6502_Instruction e6502_instructions[256] = {
// 0x00
[0b00000000] = {brk, adr_none, 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, adr_reg_a, 2},
[0b00001110] = {asl, adr_abs, 6},

[0b00001000] = {php, adr_none, 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_none, 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, adr_reg_a, 2},
[0b00101110] = {rol, adr_abs, 6},

[0b00101000] = {plp, adr_none, 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_none, 2},

// 0x40
[0b01000000] = {rti, adr_none, 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, adr_reg_a, 2},
[0b01001110] = {lsr, adr_abs, 6},

[0b01001000] = {pha, adr_none, 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_none, 2},

// 0x60
[0b01100000] = {rts, adr_none, 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, adr_reg_a, 2},
[0b01101110] = {ror, adr_abs, 6},

[0b01101000] = {pla, adr_none, 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_none, 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] = {dec, adr_reg_y, 2},

[0b10001010] = {txa, adr_none, 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] = {ty, adr_reg_a, 2},
[0b10011010] = {txs, adr_none, 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] = {ta, adr_reg_x, 2},
[0b10101000] = {ta, adr_reg_y, 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_none, 2},

[0b10111010] = {ts, adr_reg_x, 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] = {inc, adr_reg_y, 2},

[0b11000110] = {dec, adr_zp, 5},
[0b11001110] = {dec, adr_abs, 6},
[0b11010110] = {dec, adr_zp_x, 6},
[0b11011110] = {dec, adr_abs_x, 7},

[0b11001010] = {dec, adr_reg_x, 2},

// 0xD0
[0b11010000] = {bne, adr_rel, 2},

[0b11011000] = {cld, adr_none, 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] = {inc, adr_reg_x, 2},

[0b11101010] = {nop, adr_none, 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_none, 2},

};

int e6502_instr_size(uint8_t opcode) {
e6502_Instruction* instr = &e6502_instructions[opcode];
if ( instr->address == adr_none ||
instr->address == adr_reg_a ||
instr->address == adr_reg_x ||
instr->address == adr_reg_y ||
instr->address == adr_reg_s ||
instr->address == adr_reg_sp) {
return 1;
} else if ( instr->address == adr_abs ||
instr->address == adr_abs_x ||
instr->address == adr_abs_y) {
return 3;
} else {
return 2;
}
}

/*
int e6502_dump_instr(e6502_Core* core, e6502_Mem_Addr addr,
FILE* file) {
uint8_t opcode = e6502_r8(core, addr);
int size = e6502_instr_size(opcode);
fprintf(file, "$%02x", opcode);
if (size == 2) {
fprintf(file, " $%02x", e6502_r8(core, addr + 1));
} else if (size == 3) {
fprintf(file, " $%04x", e6502_r16(core, addr + 1));
}
fputc('\n', file);
}

int e6502_dump_regs(e6502_Core* core, FILE* file) {
fprintf(file, "S:%02x A:%02x X:%02x Y:%02x P:%02x\n",
core->registers.SP, core->registers.A,
core->registers.X, core->registers.Y,
core->registers.S);
}
*/

int e6502_run(e6502_Core* core,
int remaining,
int* run,
int instructions) {
int status = 0;
int start = (instructions ? core->instr : core->cycle);
int end = start + remaining;
int last_pc = -1;
while ((instructions ? core->instr : core->cycle) < end) {
if (core->registers.PC == last_pc) {
// Trapped.
status = -2;
break;
}
last_pc = core->registers.PC;
uint8_t opcode = e6502_r8(core, core->registers.PC);
e6502_Instruction* instr = &e6502_instructions[opcode];
if (!instr->operator) {
/*
fprintf(stdout, "$%04x: %02x\n", last_pc, opcode);
*/
status = -1;
break;
} else {
core->registers.PC++;
e6502_Address adr = instr->address(core);
/*
uint16_t size = core->registers.PC - last_pc;
*/
instr->operator(core, adr);
core->cycle += instr->cycles;
core->instr++;
/*
fprintf(stdout, "$%04x: $%02x", last_pc, opcode);
if (size == 2) {
fprintf(stdout, " $%02x", e6502_r8(core, last_pc + 1));
} else if (size == 3) {
fprintf(stdout, " $%02x%02x", e6502_r8(core, last_pc + 2), e6502_r8(core, last_pc + 1));
}
fputc('\n', stdout);
e6502_dump_regs(core, stdout);
*/
}
}
if (run) {
*run = (instructions ? core->instr : core->cycle) - start;
}
return status;
}

int e6502_reset(e6502_Core* core) {
core->registers.PC = e6502_r16(core, e6502_Reset_Vec);
core->registers.SP -= 3;
core->registers.S |= (e6502_Status_B | e6502_Status_1);
}

+ 94
- 0
e6502.h Visa fil

@@ -0,0 +1,94 @@
#include <stdint.h>


typedef enum {
e6502_Status_C = 0b00000001,
e6502_Status_Z = 0b00000010,
e6502_Status_I = 0b00000100,
e6502_Status_D = 0b00001000,
e6502_Status_B = 0b00010000,
e6502_Status_1 = 0b00100000,
e6502_Status_V = 0b01000000,
e6502_Status_N = 0b10000000,
} e6502_Status_Flag_Bit;

typedef struct {
uint16_t PC;
uint8_t SP;
uint8_t A;
uint8_t X;
uint8_t Y;
uint8_t S;
} e6502_Registers;

typedef struct {
e6502_Registers registers;
int cycle;
int instr;
uint8_t memory[65536];
} e6502_Core;

#define e6502_Memory_Stack (0x0100U)

#define e6502_IRQ_Vec (0xFFFEU)
#define e6502_Reset_Vec (0xFFFCU)
#define e6502_NMI_Vec (0xFFFAU)


typedef uint16_t e6502_Mem_Addr;

/*
uint8_t e6502_r8(e6502_Core* core, e6502_Mem_Addr adr);

void e6502_w8(e6502_Core* core, e6502_Mem_Addr adr, uint8_t val);
*/

static inline uint8_t e6502_r8(e6502_Core* core,
e6502_Mem_Addr adr) {
return core->memory[adr];
}

static inline void e6502_w8(e6502_Core* core,
e6502_Mem_Addr adr,
uint8_t val) {
core->memory[adr] = val;
}

static inline uint16_t e6502_r16(e6502_Core* core,
e6502_Mem_Addr adr) {
return e6502_r8(core, adr) |
((uint16_t)e6502_r8(core, adr + 1) << 8);
}

static inline void e6502_w16(e6502_Core* core,
e6502_Mem_Addr adr,
uint16_t val) {
e6502_w8(core, adr, val);
e6502_w8(core, adr + 1, val >> 8);
}

static inline void e6502_push8(e6502_Core* core, uint8_t val) {
e6502_w8(core, e6502_Memory_Stack + core->registers.SP--, val);
}

static inline void e6502_push16(e6502_Core* core, uint16_t val) {
e6502_push8(core, val >> 8);
e6502_push8(core, val & 0xFF);
}

static inline uint8_t e6502_pop8(e6502_Core* core) {
return e6502_r8(core, e6502_Memory_Stack +
++core->registers.SP);
}

static inline uint16_t e6502_pop16(e6502_Core* core) {
return (e6502_pop8(core) | ((uint16_t)e6502_pop8(core) << 8));
}


int e6502_run(e6502_Core* core,
int remaining,
int* run,
int instructions);

int e6502_reset(e6502_Core* core);

Laddar…
Avbryt
Spara