Fixes #3 - Implement 65C02 Instructions

This commit is contained in:
Stefan Arentz 2016-11-23 16:35:41 -05:00
parent 15be191d05
commit a6f16e3643
10 changed files with 718 additions and 54 deletions

View File

@ -25,7 +25,7 @@ CFLAGS=-std=c11 -O2 -Wpedantic -Wall -Wshadow -Werror -Wshadow -Wno-gnu-binary-
LDFLAGS=-g
EWM_EXECUTABLE=ewm
EWM_SOURCES=cpu.c ins.c pia.c mem.c ewm.c fmt.c mmu.c dsk.c
EWM_SOURCES=cpu.c ins.c pia.c mem.c ewm.c fmt.c
EWM_OBJECTS=$(EWM_SOURCES:.c=.o)
EWM_LIBS=-lcurses

18
cpu.c
View File

@ -110,7 +110,7 @@ static int cpu_execute_instruction(struct cpu_t *cpu) {
}
/* Fetch instruction */
cpu_instruction_t *i = &instructions[mem_get_byte(cpu, cpu->state.pc)];
struct cpu_instruction_t *i = &cpu->instructions[mem_get_byte(cpu, cpu->state.pc)];
if (i->handler == NULL) {
return EWM_CPU_ERR_UNIMPLEMENTED_INSTRUCTION;
}
@ -165,8 +165,8 @@ static int cpu_execute_instruction(struct cpu_t *cpu) {
snprintf(bytes, sizeof bytes, "%.2X %.2X %.2X", mem_get_byte(cpu, pc), mem_get_byte(cpu, pc+1), mem_get_byte(cpu, pc+2));
break;
}
fprintf(cpu->trace, "%.4X: %-8s %-11s %-20s %s\n",
fprintf(cpu->trace, "%.4X: %-8s %-14s %-20s %s\n",
pc, bytes, trace_instruction, trace_state, trace_stack);
}
@ -175,8 +175,18 @@ static int cpu_execute_instruction(struct cpu_t *cpu) {
/* Public API */
void cpu_init(struct cpu_t *cpu) {
void cpu_setup() {
for (int i = 0; i <= 255; i++) {
if (instructions_65C02[i].handler == NULL) {
instructions_65C02[i] = instructions[i];
}
}
}
void cpu_init(struct cpu_t *cpu, int model) {
memset(cpu, 0x00, sizeof(struct cpu_t));
cpu->model = model;
cpu->instructions = (cpu->model == EWM_CPU_MODEL_6502) ? instructions : instructions_65C02;
}
void cpu_shutdown(struct cpu_t *cpu) {

11
cpu.h
View File

@ -27,6 +27,9 @@
#include <stdint.h>
#include <stdio.h>
#define EWM_CPU_MODEL_6502 0
#define EWM_CPU_MODEL_65C02 1
#define EWM_CPU_ERR_UNIMPLEMENTED_INSTRUCTION (-1)
#define EWM_CPU_ERR_STACK_OVERFLOW (-2)
#define EWM_CPU_ERR_STACK_UNDERFLOW (-3)
@ -35,6 +38,8 @@
#define EWM_VECTOR_RES 0xfffc
#define EWM_VECTOR_IRQ 0xfffe
struct cpu_instruction_t;
struct cpu_state_t {
uint8_t a, x, y, s, sp;
uint16_t pc;
@ -42,11 +47,13 @@ struct cpu_state_t {
};
struct cpu_t {
int model;
struct cpu_state_t state;
FILE *trace;
bool strict;
struct mem_t *mem;
uint8_t *memory; // This is pointing to the first 2 pages of memory, zero page and stack.
struct cpu_instruction_t *instructions;
};
#define MEM_TYPE_RAM 0
@ -79,7 +86,9 @@ uint8_t _cpu_stack_used(struct cpu_t *cpu);
uint8_t _cpu_get_status(struct cpu_t *cpu);
void _cpu_set_status(struct cpu_t *cpu, uint8_t status);
void cpu_init(struct cpu_t *cpu);
void cpu_setup();
void cpu_init(struct cpu_t *cpu, int model);
void cpu_shutdown(struct cpu_t *cpu);
void cpu_add_mem(struct cpu_t *cpu, struct mem_t *mem);

View File

@ -27,29 +27,35 @@
#include "cpu.h"
#include "mem.h"
int main(int argc, char **argv) {
int test(int model, uint16_t start_addr, uint16_t success_addr, char *rom_path) {
struct cpu_t cpu;
cpu_init(&cpu);
cpu_add_ram_file(&cpu, 0x0000, "roms/6502_functional_test.bin");
cpu_init(&cpu, model);
cpu_add_ram_file(&cpu, 0x0000, rom_path);
cpu_reset(&cpu);
cpu.state.pc = 0x0400;
cpu.state.pc = start_addr;
uint16_t last_pc = cpu.state.pc;
while (true) {
int ret = cpu_step(&cpu);
if (ret != 0) {
fprintf(stderr, "TEST Unexpected error %d\n", ret);
exit(1);
switch (ret) {
case EWM_CPU_ERR_UNIMPLEMENTED_INSTRUCTION:
fprintf(stderr, "TEST Unimplemented instruction 0x%.2x at 0x%.4x\n",
mem_get_byte(&cpu, cpu.state.pc), cpu.state.pc);
return -1;
default:
fprintf(stderr, "TEST Unexpected error %d\n", ret);
return -1;
}
}
// End of the tests is at 0x3399. This is hard coded and not
// ideal. Is there a better way to detect this?
if (cpu.state.pc == 0x3399) {
fprintf(stderr, "TEST Success\n");
exit(1);
if (cpu.state.pc == success_addr) {
fprintf(stderr, "TEST Success\n");
return 0;
}
// We detect a test failure because we are in a branch deadlock,
@ -60,8 +66,8 @@ int main(int argc, char **argv) {
uint8_t i = mem_get_byte(&cpu, cpu.state.pc);
if (i == 0x10 || i == 0x30 || i == 0x50 || i == 0x70 || i == 0x90 || i == 0xb0 || i == 0xd0 || i == 0xf0) {
if (mem_get_byte(&cpu, cpu.state.pc + 1) == 0xfe) {
fprintf(stderr, "TEST Failure at 0x%.4x \n", cpu.state.pc);
exit(1);
fprintf(stderr, "TEST Failure at 0x%.4x \n", cpu.state.pc);
return -1;
}
}
}
@ -69,3 +75,11 @@ int main(int argc, char **argv) {
last_pc = cpu.state.pc;
}
}
int main(int argc, char **argv) {
cpu_setup();
fprintf(stderr, "TEST Running 6502 tests\n");
test(EWM_CPU_MODEL_6502, 0x0400, 0x3399, "roms/6502_functional_test.bin");
fprintf(stderr, "TEST Running 65C02 tests\n");
test(EWM_CPU_MODEL_65C02, 0x0400, 0x24a8, "roms/65C02_extended_opcodes_test.bin");
}

16
ewm.c
View File

@ -31,9 +31,10 @@
#include "mem.h"
#include "pia.h"
// Apple 1 / 8K RAM / WOZ Monitor
// Apple 1 / 6502 / 8K RAM / WOZ Monitor
static int setup_apple1(struct cpu_t *cpu) {
cpu_init(cpu, EWM_CPU_MODEL_6502);
struct pia_t *pia = malloc(sizeof(struct pia_t));
pia_init(pia);
cpu_add_ram(cpu, 0x0000, 8 * 1024 - 1);
@ -42,9 +43,10 @@ static int setup_apple1(struct cpu_t *cpu) {
return 0;
}
// Replica 1 / 32K RAM / Krusader Assembler & Monitor
// Replica 1 / 65C02 / 32K RAM / Krusader Assembler & Monitor
static int setup_replica1(struct cpu_t *cpu) {
cpu_init(cpu, EWM_CPU_MODEL_65C02);
struct pia_t *pia = malloc(sizeof(struct pia_t));
pia_init(pia);
cpu_add_ram(cpu, 0x0000, 32 * 1024 - 1);
@ -53,9 +55,10 @@ static int setup_replica1(struct cpu_t *cpu) {
return 0;
}
// Apple ][+ / 48K RAM / Original ROMs
// Apple ][+ / 6502 / 48K RAM / Original ROMs
static int setup_apple2plus(struct cpu_t *cpu) {
cpu_init(cpu, EWM_CPU_MODEL_6502);
cpu_add_ram(cpu, 0x0000, 48 * 1024);
cpu_add_rom_file(cpu, 0xd000, "roms/a2p.rom");
return 0;
@ -122,12 +125,13 @@ int main(int argc, char **argv) {
exit(1);
}
cpu_setup();
struct cpu_t cpu;
cpu_init(&cpu);
cpu_strict(&cpu, strict);
cpu_trace(&cpu, trace_path);
machine->setup(&cpu);
cpu_strict(&cpu, strict);
cpu_trace(&cpu, trace_path);
cpu_reset(&cpu);

109
fmt.c
View File

@ -63,51 +63,113 @@ void cpu_format_stack(struct cpu_t *cpu, char buffer[764]) {
void cpu_format_instruction(struct cpu_t *cpu, char *buffer) {
*buffer = 0x00;
cpu_instruction_t *i = &instructions[mem_get_byte(cpu, cpu->state.pc)];
uint8_t opcode = mem_get_byte(cpu, cpu->state.pc);
struct cpu_instruction_t *i = &cpu->instructions[opcode];
if (i->handler == NULL) {
sprintf(buffer, "???");
return;
}
/* Single byte instructions */
if (i->bytes == 1) {
sprintf(buffer, "%s", i->name);
sprintf(buffer, "%-4s", i->name);
}
/* 65C02 ADC, AND, CMP, EOR, LDA, ORA, SBC, STA */
else if ((opcode & 0b00011111) == 0b00010010) {
sprintf(buffer, "%-4s $%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+1));
}
/* 65C02 RMB / SMB */
else if ((opcode & 0b00001111) == 0b00000111) {
sprintf(buffer, "%s%d $%.2X",
(opcode & 0b10000000) == 0b00000000 ? "RMB" : "SMB",
(opcode & 0b01110000) >> 4,
mem_get_byte(cpu, cpu->state.pc+1));
}
/* 65C02 BBR / BBS */
else if ((opcode & 0b00001111) == 0b00001111) {
sprintf(buffer, "%s%d $%.2X,$%.4X",
(opcode & 0b10000000) == 0b00000000 ? "BBR" : "BBS",
(opcode & 0b01110000) >> 4,
mem_get_byte(cpu, cpu->state.pc+1),
cpu->state.pc + 2 + (int8_t) mem_get_byte(cpu, cpu->state.pc+2));
}
/* 65C02 JMP (ABS,X) */
else if (opcode == 0x7c) {
sprintf(buffer, "JMP ($%.4X,X)", mem_get_word(cpu, cpu->state.pc+1));
}
/* 65C02 BRA */
else if (opcode == 0x80) {
sprintf(buffer, "BRA $%.4X", cpu->state.pc + 2 + (int8_t) mem_get_byte(cpu, cpu->state.pc+1));
}
/* 65C02 STZ ABS */
else if (opcode == 0x9c) {
sprintf(buffer, "JMP $%.4X", mem_get_word(cpu, cpu->state.pc+1));
}
/* 65C02 TRB ZP */
else if (opcode == 0x14) {
sprintf(buffer, "TRB $%.2X", mem_get_byte(cpu, cpu->state.pc+1));
}
/* 65C02 TRB ABS */
else if (opcode == 0x1c) {
sprintf(buffer, "TRB $%.4X", mem_get_word(cpu, cpu->state.pc+1));
}
/* 65C02 TSB ZP */
else if (opcode == 0x04) {
sprintf(buffer, "TSB $%.2X", mem_get_byte(cpu, cpu->state.pc+1));
}
/* 65C02 TSB ABS */
else if (opcode == 0x0c) {
sprintf(buffer, "TSB $%.4X", mem_get_word(cpu, cpu->state.pc+1));
}
/* JSR is the only exception */
else if (opcode == 0x20) {
sprintf(buffer, "%s $%.4X", i->name, mem_get_word(cpu, cpu->state.pc+1));
sprintf(buffer, "%-4s $%.4X", i->name, mem_get_word(cpu, cpu->state.pc+1));
}
/* Branches */
else if ((opcode & 0b00011111) == 0b00010000) {
int8_t offset = (int8_t) mem_get_byte(cpu, cpu->state.pc+1);
uint16_t addr = cpu->state.pc + 2 + offset;
sprintf(buffer, "%s $%.4X", i->name, addr);
sprintf(buffer, "%-4s $%.4X", i->name, addr);
}
else if ((opcode & 0b00000011) == 0b00000001) {
switch ((opcode & 0b00011100) >> 2) {
case 0b000:
sprintf(buffer, "%s ($%.2X,X)", i->name, mem_get_byte(cpu, cpu->state.pc+1));
sprintf(buffer, "%-4s ($%.2X,X)", i->name, mem_get_byte(cpu, cpu->state.pc+1));
break;
case 0b001:
sprintf(buffer, "%s $%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+1));
sprintf(buffer, "%-4s $%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+1));
break;
case 0b010:
sprintf(buffer, "%s #$%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+1));
sprintf(buffer, "%-4s #$%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+1));
break;
case 0b011:
sprintf(buffer, "%s $%.2X%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+2), mem_get_byte(cpu, cpu->state.pc+1));
sprintf(buffer, "%-4s $%.2X%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+2), mem_get_byte(cpu, cpu->state.pc+1));
break;
case 0b100:
sprintf(buffer, "%s ($%.2X),Y", i->name, mem_get_byte(cpu, cpu->state.pc+1));
sprintf(buffer, "%-4s ($%.2X),Y", i->name, mem_get_byte(cpu, cpu->state.pc+1));
break;
case 0b101:
sprintf(buffer, "%s $%.2X,X", i->name, mem_get_byte(cpu, cpu->state.pc+1));
sprintf(buffer, "%-4s $%.2X,X", i->name, mem_get_byte(cpu, cpu->state.pc+1));
break;
case 0b110:
sprintf(buffer, "%s $%.2X%.2X,Y", i->name, mem_get_byte(cpu, cpu->state.pc+2), mem_get_byte(cpu, cpu->state.pc+1));
sprintf(buffer, "%-4s $%.2X%.2X,Y", i->name, mem_get_byte(cpu, cpu->state.pc+2), mem_get_byte(cpu, cpu->state.pc+1));
break;
case 0b111:
sprintf(buffer, "%s $%.2X%.2X,X", i->name, mem_get_byte(cpu, cpu->state.pc+2), mem_get_byte(cpu, cpu->state.pc+1));
sprintf(buffer, "%-4s $%.2X%.2X,X", i->name, mem_get_byte(cpu, cpu->state.pc+2), mem_get_byte(cpu, cpu->state.pc+1));
break;
}
}
@ -115,22 +177,22 @@ void cpu_format_instruction(struct cpu_t *cpu, char *buffer) {
else if ((opcode & 0b00000011) == 0b00000010) {
switch ((opcode & 0b00011100) >> 2) {
case 0b000:
sprintf(buffer, "%s #$%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+1));
sprintf(buffer, "%-4s #$%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+1));
break;
case 0b001:
sprintf(buffer, "%s $%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+1));
sprintf(buffer, "%-4s $%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+1));
break;
case 0b010:
sprintf(buffer, "%s", i->name);
sprintf(buffer, "%-4s", i->name);
break;
case 0b011:
sprintf(buffer, "%s $%.2X%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+2), mem_get_byte(cpu, cpu->state.pc+1));
sprintf(buffer, "%-4s $%.2X%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+2), mem_get_byte(cpu, cpu->state.pc+1));
break;
case 0b101:
sprintf(buffer, "%s $%.2X,X", i->name, mem_get_byte(cpu, cpu->state.pc+1));
sprintf(buffer, "%-4s $%.2X,X", i->name, mem_get_byte(cpu, cpu->state.pc+1));
break;
case 0b111:
sprintf(buffer, "%s $%.2X%.2X,X", i->name, mem_get_byte(cpu, cpu->state.pc+2), mem_get_byte(cpu, cpu->state.pc+1));
sprintf(buffer, "%-4s $%.2X%.2X,X", i->name, mem_get_byte(cpu, cpu->state.pc+2), mem_get_byte(cpu, cpu->state.pc+1));
break;
}
}
@ -138,19 +200,20 @@ void cpu_format_instruction(struct cpu_t *cpu, char *buffer) {
else if ((opcode & 0b00000011) == 0b00000000) {
switch ((opcode & 0b00011100) >> 2) {
case 0b000:
sprintf(buffer, "%s #$%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+1));
sprintf(buffer, "%-4s #$%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+1));
break;
case 0b001:
sprintf(buffer, "%s $%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+1));
sprintf(buffer, "%-4s $%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+1));
break;
case 0b011:
sprintf(buffer, "%s $%.2X%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+2), mem_get_byte(cpu, cpu->state.pc+1));
sprintf(buffer, "%-4s $%.2X%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+2), mem_get_byte(cpu, cpu->state.pc+1));
break;
case 0b101:
sprintf(buffer, "%s $%.2X,X", i->name, mem_get_byte(cpu, cpu->state.pc+1));
sprintf(buffer, "%-4s $%.2X,X", i->name, mem_get_byte(cpu, cpu->state.pc+1));
break;
case 0b111:
sprintf(buffer, "%s $%.2X%.2X,X", i->name, mem_get_byte(cpu, cpu->state.pc+2), mem_get_byte(cpu, cpu->state.pc+1));
sprintf(buffer, "%-4s $%.2X%.2X,X", i->name, mem_get_byte(cpu, cpu->state.pc+2), mem_get_byte(cpu, cpu->state.pc+1));
break;
}
}

561
ins.c
View File

@ -32,6 +32,8 @@ static void update_zn(struct cpu_t *cpu, uint8_t v) {
cpu->state.n = (v & 0x80);
}
// EWM_CPU_MODEL_6502
/* ADC */
static void adc(struct cpu_t *cpu, uint8_t m) {
@ -55,7 +57,7 @@ static void adc(struct cpu_t *cpu, uint8_t m) {
cpu->state.c = (high > 15);
cpu->state.z = (r == 0);
cpu->state.n = 0;
cpu->state.n = (r & 0b10000000); // TODO Only on 6502? Does the 6502 test still pass?
cpu->state.v = 0;
cpu->state.a = r;
@ -241,6 +243,9 @@ static void bvs(struct cpu_t *cpu, uint8_t oper) {
static void brk(struct cpu_t *cpu) {
cpu->state.b = 1;
if (cpu->model == EWM_CPU_MODEL_65C02) {
cpu->state.d = 0;
}
cpu_irq(cpu);
}
@ -734,7 +739,7 @@ static void sbc(struct cpu_t *cpu, uint8_t m) {
uint8_t c = cpu->state.c ? 1 : 0;
if (cpu->state.d) {
uint8_t cb = 0;
if (c == 0) {
c = 1;
} else {
@ -758,7 +763,7 @@ static void sbc(struct cpu_t *cpu, uint8_t m) {
cpu->state.c = (high & 0xff) < 15;
cpu->state.z = (result == 0);
cpu->state.n = 0;
cpu->state.n = (result & 0b10000000); // TODO Only on 6502? Does the 6502 test still pass?
cpu->state.v = 0;
cpu->state.a = result;
@ -904,7 +909,7 @@ static void tya(struct cpu_t *cpu) {
/* Instruction dispatch table */
cpu_instruction_t instructions[256] = {
struct cpu_instruction_t instructions[256] = {
/* 0x00 */ { "BRK", 0x00, 1, 2, 3, (void*) brk },
/* 0x01 */ { "ORA", 0x01, 2, 6, 0, (void*) ora_indx },
/* 0x02 */ { "???", 0x02, 1, 2, 0, (void*) NULL },
@ -1169,3 +1174,551 @@ cpu_instruction_t instructions[256] = {
/* 0xfe */ { "INC", 0xfe, 3, 7, 0, (void*) inc_absx },
/* 0xff */ { "???", 0xff, 1, 2, 0, (void*) NULL }
};
// EWM_CPU_MODEL_65C02
static void ora_ind(struct cpu_t *cpu, uint8_t oper) {
ora(cpu, mem_get_byte_ind(cpu, oper));
}
static void and_ind(struct cpu_t *cpu, uint8_t oper) {
and(cpu, mem_get_byte_ind(cpu, oper));
}
static void eor_ind(struct cpu_t *cpu, uint8_t oper) {
eor(cpu, mem_get_byte_ind(cpu, oper));
}
static void adc_ind(struct cpu_t *cpu, uint8_t oper) {
adc(cpu, mem_get_byte_ind(cpu, oper));
}
static void sta_ind(struct cpu_t *cpu, uint8_t oper) {
mem_set_byte_ind(cpu, oper, cpu->state.a);
}
static void lda_ind(struct cpu_t *cpu, uint8_t oper) {
cpu->state.a = mem_get_byte_ind(cpu, oper);
update_zn(cpu, cpu->state.a);
}
static void cmp_ind(struct cpu_t *cpu, uint8_t oper) {
cmp(cpu, mem_get_byte_ind(cpu, oper));
}
static void sbc_ind(struct cpu_t *cpu, uint8_t oper) {
sbc(cpu, mem_get_byte_ind(cpu, oper));
}
static void bit_imm(struct cpu_t *cpu, uint8_t oper) {
uint8_t t = cpu->state.a & oper;
cpu->state.z = (t == 0);
}
static void bit_zpgx(struct cpu_t *cpu, uint8_t oper) {
bit(cpu, mem_get_byte_zpgx(cpu, oper));
}
static void bit_absx(struct cpu_t *cpu, uint16_t oper) {
bit(cpu, mem_get_byte_absx(cpu, oper));
}
static void dec_acc(struct cpu_t *cpu) {
cpu->state.a--;
update_zn(cpu, cpu->state.a);
}
static void inc_acc(struct cpu_t *cpu) {
cpu->state.a++;
update_zn(cpu, cpu->state.a);
}
static void jmp_absx(struct cpu_t *cpu, uint16_t oper) {
cpu->state.pc = mem_get_word(cpu, oper + cpu->state.x);
}
static void bra(struct cpu_t *cpu, uint8_t oper) {
cpu->state.pc += (int8_t) oper;
}
static void phx(struct cpu_t *cpu) {
_cpu_push_byte(cpu, cpu->state.x);
}
static void phy(struct cpu_t *cpu) {
_cpu_push_byte(cpu, cpu->state.y);
}
static void plx(struct cpu_t *cpu) {
cpu->state.x = _cpu_pull_byte(cpu);
update_zn(cpu, cpu->state.x);
}
static void ply(struct cpu_t *cpu) {
cpu->state.y = _cpu_pull_byte(cpu);
update_zn(cpu, cpu->state.y);
}
static void stz_zpg(struct cpu_t *cpu, uint8_t oper) {
mem_set_byte_zpg(cpu, oper, 0x00);
}
static void stz_zpgx(struct cpu_t *cpu, uint8_t oper) {
mem_set_byte_zpgx(cpu, oper, 0x00);
}
static void stz_abs(struct cpu_t *cpu, uint16_t oper) {
mem_set_byte_abs(cpu, oper, 0x00);
}
static void stz_absx(struct cpu_t *cpu, uint16_t oper) {
mem_set_byte_absx(cpu, oper, 0x00);
}
static void trb_zpg(struct cpu_t *cpu, uint8_t oper) {
cpu->state.z = (mem_get_byte(cpu, oper) & cpu->state.a) == 0;
uint8_t r = mem_get_byte(cpu, oper) & ~cpu->state.a;
mem_set_byte_zpg(cpu, oper, r);
}
static void trb_abs(struct cpu_t *cpu, uint16_t oper) {
cpu->state.z = (mem_get_byte(cpu, oper) & cpu->state.a) == 0;
uint8_t r = mem_get_byte(cpu, oper) & (cpu->state.a ^ 0xff);
mem_set_byte_abs(cpu, oper, r);
}
static void tsb_zpg(struct cpu_t *cpu, uint8_t oper) {
cpu->state.z = (mem_get_byte(cpu, oper) & cpu->state.a) == 0;
uint8_t r = mem_get_byte(cpu, oper) | cpu->state.a;
mem_set_byte_zpg(cpu, oper, r);
}
static void tsb_abs(struct cpu_t *cpu, uint16_t oper) {
cpu->state.z = (mem_get_byte(cpu, oper) & cpu->state.a) == 0;
uint8_t r = mem_get_byte(cpu, oper) | cpu->state.a;
mem_set_byte_abs(cpu, oper, r);
}
static void bbr(struct cpu_t *cpu, uint8_t bit, uint8_t zp, int8_t label) {
if ((mem_get_byte_zpg(cpu, zp) & bit) == 0) {
cpu->state.pc += label;
}
}
static void bbr0(struct cpu_t *cpu, uint16_t oper) {
bbr(cpu, 0b00000001, oper & 0x00ff, oper >> 8);
}
static void bbr1(struct cpu_t *cpu, uint16_t oper) {
bbr(cpu, 0b00000010, oper & 0x00ff, oper >> 8);
}
static void bbr2(struct cpu_t *cpu, uint16_t oper) {
bbr(cpu, 0b00000100, oper & 0x00ff, oper >> 8);
}
static void bbr3(struct cpu_t *cpu, uint16_t oper) {
bbr(cpu, 0b00001000, oper & 0x00ff, oper >> 8);
}
static void bbr4(struct cpu_t *cpu, uint16_t oper) {
bbr(cpu, 0b00010000, oper & 0x00ff, oper >> 8);
}
static void bbr5(struct cpu_t *cpu, uint16_t oper) {
bbr(cpu, 0b00100000, oper & 0x00ff, oper >> 8);
}
static void bbr6(struct cpu_t *cpu, uint16_t oper) {
bbr(cpu, 0b01000000, oper & 0x00ff, oper >> 8);
}
static void bbr7(struct cpu_t *cpu, uint16_t oper) {
bbr(cpu, 0b10000000, oper & 0x00ff, oper >> 8);
}
static void bbs(struct cpu_t *cpu, uint8_t bit, uint8_t zp, int8_t label) {
if ((mem_get_byte_zpg(cpu, zp) & bit) != 0) {
cpu->state.pc += label;
}
}
static void bbs0(struct cpu_t *cpu, uint16_t oper) {
bbs(cpu, 0b00000001, oper & 0x00ff, oper >> 8);
}
static void bbs1(struct cpu_t *cpu, uint16_t oper) {
bbs(cpu, 0b00000010, oper & 0x00ff, oper >> 8);
}
static void bbs2(struct cpu_t *cpu, uint16_t oper) {
bbs(cpu, 0b00000100, oper & 0x00ff, oper >> 8);
}
static void bbs3(struct cpu_t *cpu, uint16_t oper) {
bbs(cpu, 0b00001000, oper & 0x00ff, oper >> 8);
}
static void bbs4(struct cpu_t *cpu, uint16_t oper) {
bbs(cpu, 0b00010000, oper & 0x00ff, oper >> 8);
}
static void bbs5(struct cpu_t *cpu, uint16_t oper) {
bbs(cpu, 0b00100000, oper & 0x00ff, oper >> 8);
}
static void bbs6(struct cpu_t *cpu, uint16_t oper) {
bbs(cpu, 0b01000000, oper & 0x00ff, oper >> 8);
}
static void bbs7(struct cpu_t *cpu, uint16_t oper) {
bbs(cpu, 0b10000000, oper & 0x00ff, oper >> 8);
}
static void rmb(struct cpu_t *cpu, uint8_t bit, uint8_t zp) {
mem_set_byte_zpg(cpu, zp, mem_get_byte(cpu, zp) & ~bit);
}
static void rmb0(struct cpu_t *cpu, uint8_t oper) {
rmb(cpu, 0b00000001, oper);
}
static void rmb1(struct cpu_t *cpu, uint8_t oper) {
rmb(cpu, 0b00000010, oper);
}
static void rmb2(struct cpu_t *cpu, uint8_t oper) {
rmb(cpu, 0b00000100, oper);
}
static void rmb3(struct cpu_t *cpu, uint8_t oper) {
rmb(cpu, 0b00001000, oper);
}
static void rmb4(struct cpu_t *cpu, uint8_t oper) {
rmb(cpu, 0b00010000, oper);
}
static void rmb5(struct cpu_t *cpu, uint8_t oper) {
rmb(cpu, 0b00100000, oper);
}
static void rmb6(struct cpu_t *cpu, uint8_t oper) {
rmb(cpu, 0b01000000, oper);
}
static void rmb7(struct cpu_t *cpu, uint8_t oper) {
rmb(cpu, 0b10000000, oper);
}
static void smb(struct cpu_t *cpu, uint8_t bit, uint8_t zp) {
mem_set_byte_zpg(cpu, zp, mem_get_byte(cpu, zp) | bit);
}
static void smb0(struct cpu_t *cpu, uint8_t oper) {
smb(cpu, 0b00000001, oper);
}
static void smb1(struct cpu_t *cpu, uint8_t oper) {
smb(cpu, 0b00000010, oper);
}
static void smb2(struct cpu_t *cpu, uint8_t oper) {
smb(cpu, 0b00000100, oper);
}
static void smb3(struct cpu_t *cpu, uint8_t oper) {
smb(cpu, 0b00001000, oper);
}
static void smb4(struct cpu_t *cpu, uint8_t oper) {
smb(cpu, 0b00010000, oper);
}
static void smb5(struct cpu_t *cpu, uint8_t oper) {
smb(cpu, 0b00100000, oper);
}
static void smb6(struct cpu_t *cpu, uint8_t oper) {
smb(cpu, 0b01000000, oper);
}
static void smb7(struct cpu_t *cpu, uint8_t oper) {
smb(cpu, 0b10000000, oper);
}
/* Instruction dispatch table */
struct cpu_instruction_t instructions_65C02[256] = {
/* 0x00 */ { "???", 0x00, 0, 0, 0, NULL },
/* 0x01 */ { "???", 0x01, 0, 0, 0, NULL },
/* 0x02 */ { "NOP", 0x02, 2, 2, 0, (void*) nop },
/* 0x03 */ { "NOP", 0x03, 1, 1, 0, (void*) nop },
/* 0x04 */ { "TSB", 0x04, 2, 5, 0, (void*) tsb_zpg },
/* 0x05 */ { "???", 0x05, 0, 0, 0, NULL },
/* 0x06 */ { "???", 0x06, 0, 0, 0, NULL },
/* 0x07 */ { "RMB", 0x07, 2, 5, 0, (void*) rmb0 },
/* 0x08 */ { "???", 0x08, 0, 0, 0, NULL },
/* 0x09 */ { "???", 0x09, 0, 0, 0, NULL },
/* 0x0a */ { "???", 0x0a, 0, 0, 0, NULL },
/* 0x0b */ { "NOP", 0x0b, 1, 1, 0, (void*) nop },
/* 0x0c */ { "TSB", 0x0c, 3, 6, 0, (void*) tsb_abs },
/* 0x0d */ { "???", 0x0d, 0, 0, 0, NULL },
/* 0x0e */ { "???", 0x0e, 0, 0, 0, NULL },
/* 0x0f */ { "BBR", 0x0f, 3, 5, 0, (void*) bbr0 },
/* 0x10 */ { "???", 0x10, 0, 0, 0, NULL },
/* 0x11 */ { "???", 0x12, 0, 0, 0, NULL },
/* 0x12 */ { "ORA", 0x12, 2, 5, 0, (void*) ora_ind },
/* 0x13 */ { "NOP", 0x03, 1, 1, 0, (void*) nop },
/* 0x14 */ { "TRB", 0x14, 2, 5, 0, (void*) trb_zpg },
/* 0x15 */ { "???", 0x15, 0, 0, 0, NULL },
/* 0x16 */ { "???", 0x16, 0, 0, 0, NULL },
/* 0x17 */ { "RMB", 0x17, 2, 5, 0, (void*) rmb1 },
/* 0x18 */ { "???", 0x18, 0, 0, 0, NULL },
/* 0x19 */ { "???", 0x19, 0, 0, 0, NULL },
/* 0x1a */ { "INC", 0x1a, 1, 2, 0, (void*) inc_acc },
/* 0x1b */ { "NOP", 0x1b, 1, 1, 0, (void*) nop },
/* 0x1c */ { "TRB", 0x1c, 3, 6, 0, (void*) trb_abs },
/* 0x1d */ { "???", 0x1d, 0, 0, 0, NULL },
/* 0x1e */ { "???", 0x1e, 0, 0, 0, NULL },
/* 0x1f */ { "BBR", 0x1f, 3, 5, 0, (void*) bbr1 },
/* 0x20 */ { "???", 0x20, 0, 0, 0, NULL },
/* 0x21 */ { "???", 0x21, 0, 0, 0, NULL },
/* 0x22 */ { "NOP", 0x22, 2, 2, 0, (void*) nop },
/* 0x23 */ { "NOP", 0x03, 1, 1, 0, (void*) nop },
/* 0x24 */ { "???", 0x24, 0, 0, 0, NULL },
/* 0x25 */ { "???", 0x25, 0, 0, 0, NULL },
/* 0x26 */ { "???", 0x26, 0, 0, 0, NULL },
/* 0x27 */ { "RMB", 0x27, 2, 5, 0, (void*) rmb2 },
/* 0x28 */ { "???", 0x28, 0, 0, 0, NULL },
/* 0x29 */ { "???", 0x29, 0, 0, 0, NULL },
/* 0x2a */ { "???", 0x2a, 0, 0, 0, NULL },
/* 0x2b */ { "NOP", 0x2b, 1, 1, 0, (void*) nop },
/* 0x2c */ { "???", 0x2c, 0, 0, 0, NULL },
/* 0x2d */ { "???", 0x2d, 0, 0, 0, NULL },
/* 0x2e */ { "???", 0x2e, 0, 0, 0, NULL },
/* 0x2f */ { "BBR", 0x2f, 3, 5, 0, (void*) bbr2 },
/* 0x30 */ { "???", 0x30, 0, 0, 0, NULL },
/* 0x31 */ { "???", 0x31, 0, 0, 0, NULL },
/* 0x32 */ { "AND", 0x32, 2, 5, 0, (void*) and_ind },
/* 0x33 */ { "NOP", 0x03, 1, 1, 0, (void*) nop },
/* 0x34 */ { "BIT", 0x34, 2, 4, 0, (void*) bit_zpgx },
/* 0x35 */ { "???", 0x35, 0, 0, 0, NULL },
/* 0x36 */ { "???", 0x36, 0, 0, 0, NULL },
/* 0x37 */ { "RMB", 0x37, 2, 5, 0, (void*) rmb3 },
/* 0x38 */ { "???", 0x38, 0, 0, 0, NULL },
/* 0x39 */ { "???", 0x39, 0, 0, 0, NULL },
/* 0x3a */ { "DEC", 0x3a, 1, 2, 0, (void*) dec_acc },
/* 0x3b */ { "NOP", 0x3b, 1, 1, 0, (void*) nop },
/* 0x3c */ { "BIT", 0x3c, 3, 4, 0, (void*) bit_absx },
/* 0x3d */ { "???", 0x3d, 0, 0, 0, NULL },
/* 0x3e */ { "???", 0x3e, 0, 0, 0, NULL },
/* 0x3f */ { "BBR", 0x3f, 3, 5, 0, (void*) bbr3 },
/* 0x40 */ { "???", 0x40, 0, 0, 0, NULL },
/* 0x41 */ { "???", 0x41, 0, 0, 0, NULL },
/* 0x42 */ { "NOP", 0x42, 2, 2, 0, (void*) nop },
/* 0x43 */ { "NOP", 0x03, 1, 1, 0, (void*) nop },
/* 0x44 */ { "NOP", 0x44, 2, 3, 0, (void*) nop },
/* 0x45 */ { "???", 0x45, 0, 0, 0, NULL },
/* 0x46 */ { "???", 0x46, 0, 0, 0, NULL },
/* 0x47 */ { "RMB", 0x47, 2, 5, 0, (void*) rmb4 },
/* 0x48 */ { "???", 0x48, 0, 0, 0, NULL },
/* 0x49 */ { "???", 0x49, 0, 0, 0, NULL },
/* 0x4a */ { "???", 0x4a, 0, 0, 0, NULL },
/* 0x4b */ { "NOP", 0x4b, 1, 1, 0, (void*) nop },
/* 0x4c */ { "???", 0x4c, 0, 0, 0, NULL },
/* 0x4d */ { "???", 0x4d, 0, 0, 0, NULL },
/* 0x4e */ { "???", 0x4e, 0, 0, 0, NULL },
/* 0x4f */ { "BBR", 0x4f, 3, 5, 0, (void*) bbr4 },
/* 0x50 */ { "???", 0x50, 0, 0, 0, NULL },
/* 0x51 */ { "???", 0x51, 0, 0, 0, NULL },
/* 0x52 */ { "EOR", 0x52, 2, 5, 0, (void*) eor_ind },
/* 0x53 */ { "NOP", 0x03, 1, 1, 0, (void*) nop },
/* 0x54 */ { "NOP", 0x54, 2, 4, 0, (void*) nop },
/* 0x55 */ { "???", 0x55, 0, 0, 0, NULL },
/* 0x56 */ { "???", 0x56, 0, 0, 0, NULL },
/* 0x57 */ { "RMB", 0x57, 2, 5, 0, (void*) rmb5 },
/* 0x58 */ { "???", 0x58, 0, 0, 0, NULL },
/* 0x59 */ { "???", 0x59, 0, 0, 0, NULL },
/* 0x5a */ { "PHY", 0x5a, 1, 3, 0, (void*) phy },
/* 0x5b */ { "NOP", 0x5b, 1, 1, 0, (void*) nop },
/* 0x5c */ { "NOP", 0x5c, 3, 8, 0, (void*) nop },
/* 0x5d */ { "???", 0x5d, 0, 0, 0, NULL },
/* 0x5e */ { "???", 0x5e, 0, 0, 0, NULL },
/* 0x5f */ { "BBR", 0x5f, 3, 5, 0, (void*) bbr5 },
/* 0x60 */ { "???", 0x60, 0, 0, 0, NULL },
/* 0x61 */ { "???", 0x61, 0, 0, 0, NULL },
/* 0x62 */ { "NOP", 0x62, 2, 2, 0, (void*) nop },
/* 0x63 */ { "NOP", 0x03, 1, 1, 0, (void*) nop },
/* 0x64 */ { "STZ", 0x64, 2, 3, 0, (void*) stz_zpg },
/* 0x65 */ { "???", 0x65, 0, 0, 0, NULL },
/* 0x66 */ { "???", 0x66, 0, 0, 0, NULL },
/* 0x67 */ { "RMB", 0x67, 2, 5, 0, (void*) rmb6 },
/* 0x68 */ { "???", 0x68, 0, 0, 0, NULL },
/* 0x69 */ { "???", 0x69, 0, 0, 0, NULL },
/* 0x6a */ { "???", 0x6a, 0, 0, 0, NULL },
/* 0x6b */ { "NOP", 0x6b, 1, 1, 0, (void*) nop },
/* 0x6c */ { "???", 0x6c, 0, 0, 0, NULL },
/* 0x6d */ { "???", 0x6d, 0, 0, 0, NULL },
/* 0x6e */ { "???", 0x6e, 0, 0, 0, NULL },
/* 0x6f */ { "BBR", 0x6f, 3, 5, 0, (void*) bbr6 },
/* 0x70 */ { "???", 0x70, 0, 0, 0, NULL },
/* 0x71 */ { "???", 0x71, 0, 0, 0, NULL },
/* 0x72 */ { "ADC", 0x72, 2, 5, 0, (void*) adc_ind },
/* 0x73 */ { "NOP", 0x03, 1, 1, 0, (void*) nop },
/* 0x74 */ { "STZ", 0x74, 2, 4, 0, (void*) stz_zpgx },
/* 0x75 */ { "???", 0x75, 0, 0, 0, NULL },
/* 0x76 */ { "???", 0x76, 0, 0, 0, NULL },
/* 0x77 */ { "RMB", 0x77, 2, 5, 0, (void*) rmb7 },
/* 0x78 */ { "???", 0x78, 0, 0, 0, NULL },
/* 0x79 */ { "???", 0x79, 0, 0, 0, NULL },
/* 0x7a */ { "PLY", 0x7a, 1, 4, 0, (void*) ply },
/* 0x7b */ { "NOP", 0x7b, 1, 1, 0, (void*) nop },
/* 0x7c */ { "JMP", 0x7c, 3, 6, 0, (void*) jmp_absx },
/* 0x7d */ { "???", 0x7d, 0, 0, 0, NULL },
/* 0x7e */ { "???", 0x7e, 0, 0, 0, NULL },
/* 0x7f */ { "BBR", 0x7f, 3, 5, 0, (void*) bbr7 },
/* 0x80 */ { "BRA", 0x80, 2, 3, 0, (void*) bra },
/* 0x81 */ { "???", 0x81, 0, 0, 0, NULL },
/* 0x82 */ { "NOP", 0x82, 2, 2, 0, (void*) nop },
/* 0x83 */ { "NOP", 0x03, 1, 1, 0, (void*) nop },
/* 0x84 */ { "???", 0x84, 0, 0, 0, NULL },
/* 0x85 */ { "???", 0x85, 0, 0, 0, NULL },
/* 0x86 */ { "???", 0x86, 0, 0, 0, NULL },
/* 0x87 */ { "SMB", 0x87, 2, 5, 0, (void*) smb0 },
/* 0x88 */ { "???", 0x88, 0, 0, 0, NULL },
/* 0x89 */ { "BIT", 0x89, 2, 2, 0, (void*) bit_imm },
/* 0x8a */ { "???", 0x8a, 0, 0, 0, NULL },
/* 0x8b */ { "NOP", 0x8b, 1, 1, 0, (void*) nop },
/* 0x8c */ { "???", 0x8c, 0, 0, 0, NULL },
/* 0x8d */ { "???", 0x8d, 0, 0, 0, NULL },
/* 0x8e */ { "???", 0x8e, 0, 0, 0, NULL },
/* 0x8f */ { "BBS", 0x8f, 3, 5, 0, (void*) bbs0 },
/* 0x90 */ { "???", 0x90, 0, 0, 0, NULL },
/* 0x91 */ { "???", 0x91, 0, 0, 0, NULL },
/* 0x92 */ { "STA", 0x92, 2, 5, 0, (void*) sta_ind },
/* 0x93 */ { "NOP", 0x03, 1, 1, 0, (void*) nop },
/* 0x94 */ { "???", 0x94, 0, 0, 0, NULL },
/* 0x95 */ { "???", 0x95, 0, 0, 0, NULL },
/* 0x96 */ { "???", 0x96, 0, 0, 0, NULL },
/* 0x97 */ { "SMB", 0x97, 2, 5, 0, (void*) smb1 },
/* 0x98 */ { "???", 0x98, 0, 0, 0, NULL },
/* 0x99 */ { "???", 0x99, 0, 0, 0, NULL },
/* 0x9a */ { "???", 0x9a, 0, 0, 0, NULL },
/* 0x9b */ { "NOP", 0x9b, 1, 1, 0, (void*) nop },
/* 0x9c */ { "STZ", 0x9c, 3, 4, 0, (void*) stz_abs },
/* 0x9d */ { "???", 0x9d, 0, 0, 0, NULL },
/* 0x9e */ { "STZ", 0x9e, 3, 5, 0, (void*) stz_absx },
/* 0x9f */ { "BBS", 0x9f, 3, 5, 0, (void*) bbs1 },
/* 0xa0 */ { "???", 0xa0, 0, 0, 0, NULL },
/* 0xa1 */ { "???", 0xa1, 0, 0, 0, NULL },
/* 0xa2 */ { "???", 0xa2, 0, 0, 0, NULL },
/* 0xa3 */ { "NOP", 0x03, 1, 1, 0, (void*) nop },
/* 0xa4 */ { "???", 0xa4, 0, 0, 0, NULL },
/* 0xa5 */ { "???", 0xa5, 0, 0, 0, NULL },
/* 0xa6 */ { "???", 0xa6, 0, 0, 0, NULL },
/* 0xa7 */ { "SMB", 0xa7, 2, 5, 0, (void*) smb2 },
/* 0xa8 */ { "???", 0xa8, 0, 0, 0, NULL },
/* 0xa9 */ { "???", 0xa9, 0, 0, 0, NULL },
/* 0xaa */ { "???", 0xaa, 0, 0, 0, NULL },
/* 0xab */ { "NOP", 0xab, 1, 1, 0, (void*) nop },
/* 0xac */ { "???", 0xac, 0, 0, 0, NULL },
/* 0xad */ { "???", 0xad, 0, 0, 0, NULL },
/* 0xae */ { "???", 0xae, 0, 0, 0, NULL },
/* 0xaf */ { "BBS", 0xaf, 3, 5, 0, (void*) bbs2 },
/* 0xb0 */ { "???", 0xb0, 0, 0, 0, NULL },
/* 0xb1 */ { "???", 0xb1, 0, 0, 0, NULL },
/* 0xb2 */ { "LDA", 0xb2, 2, 5, 0, (void*) lda_ind },
/* 0xb3 */ { "NOP", 0x03, 1, 1, 0, (void*) nop },
/* 0xb4 */ { "???", 0xb4, 0, 0, 0, NULL },
/* 0xb5 */ { "???", 0xb5, 0, 0, 0, NULL },
/* 0xb6 */ { "???", 0xb6, 0, 0, 0, NULL },
/* 0xb7 */ { "SMB", 0xb7, 2, 5, 0, (void*) smb3 },
/* 0xb8 */ { "???", 0xb8, 0, 0, 0, NULL },
/* 0xb9 */ { "???", 0xb9, 0, 0, 0, NULL },
/* 0xba */ { "???", 0xba, 0, 0, 0, NULL },
/* 0xbb */ { "NOP", 0xbb, 1, 1, 0, (void*) nop },
/* 0xbc */ { "???", 0xbc, 0, 0, 0, NULL },
/* 0xbd */ { "???", 0xbd, 0, 0, 0, NULL },
/* 0xbe */ { "???", 0xbe, 0, 0, 0, NULL },
/* 0xbf */ { "BBS", 0xbf, 3, 5, 0, (void*) bbs3 },
/* 0xc0 */ { "???", 0xc0, 0, 0, 0, NULL },
/* 0xc1 */ { "???", 0xc1, 0, 0, 0, NULL },
/* 0xc2 */ { "NOP", 0xc2, 2, 2, 0, (void*) nop },
/* 0xc3 */ { "NOP", 0x03, 1, 1, 0, (void*) nop },
/* 0xc4 */ { "???", 0xc4, 0, 0, 0, NULL },
/* 0xc5 */ { "???", 0xc5, 0, 0, 0, NULL },
/* 0xc6 */ { "???", 0xc6, 0, 0, 0, NULL },
/* 0xc7 */ { "SMB", 0xc7, 2, 5, 0, (void*) smb4 },
/* 0xc8 */ { "???", 0xc8, 0, 0, 0, NULL },
/* 0xc9 */ { "???", 0xc9, 0, 0, 0, NULL },
/* 0xca */ { "???", 0xca, 0, 0, 0, NULL },
/* 0xcb */ { "NOP", 0xcb, 1, 1, 0, (void*) nop },
/* 0xcc */ { "???", 0xcc, 0, 0, 0, NULL },
/* 0xcd */ { "???", 0xcd, 0, 0, 0, NULL },
/* 0xce */ { "???", 0xce, 0, 0, 0, NULL },
/* 0xcf */ { "BBS", 0xcf, 3, 5, 0, (void*) bbs4 },
/* 0xd0 */ { "???", 0xd0, 0, 0, 0, NULL },
/* 0xd1 */ { "???", 0xd1, 0, 0, 0, NULL },
/* 0xd2 */ { "CMP", 0xd2, 2, 5, 0, (void*) cmp_ind },
/* 0xd3 */ { "NOP", 0x03, 1, 1, 0, (void*) nop },
/* 0xd4 */ { "NOP", 0xd4, 2, 4, 0, (void*) nop },
/* 0xd5 */ { "???", 0xd5, 0, 0, 0, NULL },
/* 0xd6 */ { "???", 0xd6, 0, 0, 0, NULL },
/* 0xd7 */ { "SMB", 0xd7, 2, 5, 0, (void*) smb5 },
/* 0xd8 */ { "???", 0xd8, 0, 0, 0, NULL },
/* 0xd9 */ { "???", 0xd9, 0, 0, 0, NULL },
/* 0xda */ { "PHX", 0xda, 1, 3, 0, (void*) phx },
/* 0xdb */ { "NOP", 0xdb, 1, 1, 0, (void*) nop },
/* 0xdc */ { "NOP", 0xdc, 3, 4, 0, (void*) nop },
/* 0xdd */ { "???", 0xdd, 0, 0, 0, NULL },
/* 0xde */ { "???", 0xde, 0, 0, 0, NULL },
/* 0xdf */ { "BBS", 0xdf, 3, 5, 0, (void*) bbs5 },
/* 0xe0 */ { "???", 0xe0, 0, 0, 0, NULL },
/* 0xe1 */ { "???", 0xe1, 0, 0, 0, NULL },
/* 0xe2 */ { "NOP", 0xe2, 2, 2, 0, (void*) nop },
/* 0xe3 */ { "NOP", 0x03, 1, 1, 0, (void*) nop },
/* 0xe4 */ { "???", 0xe4, 0, 0, 0, NULL },
/* 0xe5 */ { "???", 0xe5, 0, 0, 0, NULL },
/* 0xe6 */ { "???", 0xe6, 0, 0, 0, NULL },
/* 0xe7 */ { "SMB", 0xe7, 2, 5, 0, (void*) smb6 },
/* 0xe8 */ { "???", 0xe8, 0, 0, 0, NULL },
/* 0xe9 */ { "???", 0xe9, 0, 0, 0, NULL },
/* 0xea */ { "???", 0xea, 0, 0, 0, NULL },
/* 0xeb */ { "NOP", 0xeb, 1, 1, 0, (void*) nop },
/* 0xec */ { "???", 0xec, 0, 0, 0, NULL },
/* 0xed */ { "???", 0xed, 0, 0, 0, NULL },
/* 0xee */ { "???", 0xee, 0, 0, 0, NULL },
/* 0xef */ { "BBS", 0xef, 3, 5, 0, (void*) bbs6 },
/* 0xf0 */ { "???", 0xf0, 0, 0, 0, NULL },
/* 0xf1 */ { "???", 0xf1, 0, 0, 0, NULL },
/* 0xf2 */ { "SBC", 0xf2, 2, 5, 0, (void*) sbc_ind },
/* 0xf3 */ { "NOP", 0x03, 1, 1, 0, (void*) nop },
/* 0xf4 */ { "NOP", 0xf4, 2, 4, 0, (void*) nop },
/* 0xf5 */ { "???", 0xf5, 0, 0, 0, NULL },
/* 0xf6 */ { "???", 0xf6, 0, 0, 0, NULL },
/* 0xf7 */ { "SMB", 0xf7, 2, 5, 0, (void*) smb7 },
/* 0xf8 */ { "???", 0xf8, 0, 0, 0, NULL },
/* 0xf9 */ { "???", 0xf9, 0, 0, 0, NULL },
/* 0xfa */ { "PLX", 0xfa, 1, 4, 0, (void*) plx },
/* 0xfb */ { "NOP", 0xfb, 1, 1, 0, (void*) nop },
/* 0xfc */ { "NOP", 0xfc, 3, 4, 0, (void*) nop },
/* 0xfd */ { "???", 0xfd, 0, 0, 0, NULL },
/* 0xfe */ { "???", 0xfe, 0, 0, 0, NULL },
/* 0xff */ { "BBS", 0xff, 3, 5, 0, (void*) bbs7 }
};

7
ins.h
View File

@ -25,15 +25,16 @@
#include <stdint.h>
typedef struct {
struct cpu_instruction_t {
char *name;
uint8_t opcode;
uint8_t bytes;
uint8_t cycles;
int8_t stack; // How much stack does this instruction need. Negative means pull, positive push
void *handler;
} cpu_instruction_t;
};
extern cpu_instruction_t instructions[256];
extern struct cpu_instruction_t instructions[256];
extern struct cpu_instruction_t instructions_65C02[256];
#endif

8
mem.c
View File

@ -109,6 +109,10 @@ uint8_t mem_get_byte_indy(struct cpu_t *cpu, uint8_t addr) {
return mem_get_byte(cpu, mem_get_word(cpu, addr) + cpu->state.y);
}
uint8_t mem_get_byte_ind(struct cpu_t *cpu, uint8_t addr) {
return mem_get_byte(cpu, mem_get_word(cpu, addr));
}
uint16_t mem_get_word(struct cpu_t *cpu, uint16_t addr) {
// TODO Did I do this right?
return ((uint16_t) mem_get_byte(cpu, addr+1) << 8) | (uint16_t) mem_get_byte(cpu, addr);
@ -149,6 +153,10 @@ void mem_set_byte_indy(struct cpu_t *cpu, uint8_t addr, uint8_t v) {
mem_set_byte(cpu, mem_get_word(cpu, addr)+cpu->state.y, v);
}
void mem_set_byte_ind(struct cpu_t *cpu, uint8_t addr, uint8_t v) {
mem_set_byte(cpu, mem_get_word(cpu, addr), v);
}
void mem_set_word(struct cpu_t *cpu, uint16_t addr, uint16_t v) {
mem_set_byte(cpu, addr+0, (uint8_t) v); // TODO Did I do this right?
mem_set_byte(cpu, addr+1, (uint8_t) (v >> 8));

2
mem.h
View File

@ -36,6 +36,7 @@ uint8_t mem_get_byte_zpgx(struct cpu_t *cpu, uint8_t addr);
uint8_t mem_get_byte_zpgy(struct cpu_t *cpu, uint8_t addr);
uint8_t mem_get_byte_indx(struct cpu_t *cpu, uint8_t addr);
uint8_t mem_get_byte_indy(struct cpu_t *cpu, uint8_t addr);
uint8_t mem_get_byte_ind(struct cpu_t *cpu, uint8_t addr);
void mem_set_byte(struct cpu_t *cpu, uint16_t addr, uint8_t v);
void mem_set_byte_zpg(struct cpu_t *cpu, uint8_t addr, uint8_t v);
@ -46,6 +47,7 @@ void mem_set_byte_absx(struct cpu_t *cpu, uint16_t addr, uint8_t v);
void mem_set_byte_absy(struct cpu_t *cpu, uint16_t addr, uint8_t v);
void mem_set_byte_indx(struct cpu_t *cpu, uint8_t addr, uint8_t v);
void mem_set_byte_indy(struct cpu_t *cpu, uint8_t addr, uint8_t v);
void mem_set_byte_ind(struct cpu_t *cpu, uint8_t addr, uint8_t v);
void mem_mod_byte_zpg(struct cpu_t *cpu, uint8_t addr, mem_mod_t op);
void mem_mod_byte_zpgx(struct cpu_t *cpu, uint8_t addr, mem_mod_t op);