Add disassembler
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b0d1121
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+~*
+build
diff --git "a/.~lock.6502.csv\043" "b/.~lock.6502.csv\043"
new file mode 100644
index 0000000..66010a7
--- /dev/null
+++ "b/.~lock.6502.csv\043"
@@ -0,0 +1 @@
+,ch,lk,28.07.2020 15:28,file:///home/ch/.config/libreoffice/4;
\ No newline at end of file
diff --git a/6502.csv b/6502.csv
new file mode 100644
index 0000000..ce8ec0d
--- /dev/null
+++ b/6502.csv
@@ -0,0 +1,182 @@
+opcode,mnemonic,addressing mode,bytes,cycles,flags
+,,,,,
+0x69,ADC,IMM,2,2,CZidbVN
+0x65,ADC,ZP,2,3,CZidbVN
+0x75,ADC,ZPX,2,4,CZidbVN
+0x6d,ADC,ABS,3,4,CZidbVN
+0x7d,ADC,AX,3,4,CZidbVN
+0x79,ADC,AY,3,4,CZidbVN
+0x61,ADC,ZIX,2,6,CZidbVN
+0x71,ADC,ZIY,2,5,CZidbVN
+,,,,,
+0x29,AND,IMM,2,2,cZidbvN
+0x25,AND,ZP,2,3,cZidbvN
+0x35,AND,ZPX,2,4,cZidbvN
+0x2d,AND,ABS,3,4,cZidbvN
+0x3d,AND,AX,3,4,cZidbvN
+0x39,AND,AY,3,4,cZidbvN
+0x21,AND,ZIX,2,6,cZidbvN
+0x31,AND,ZIY,2,5,cZidbvN
+,,,,,
+0x0a,ASL,ACC,1,2,CZidbvN
+0x06,ASL,ZP,2,5,CZidbvN
+0x16,ASL,ZPX,2,6,CZidbvN
+0x0e,ASL,ABS,3,6,CZidbvN
+0x1e,ASL,AX,3,6/7,CZidbvN
+,,,,,
+0x90,BCC,REL,2,2/3,czidbvn
+0xB0,BCS,REL,2,2/3,czidbvn
+0xF0,BEQ,REL,2,2/3,czidbvn
+0x30,BMI,REL,2,2/3,czidbvn
+0xD0,BNE,REL,2,2/3,czidbvn
+0x10,BPL,REL,2,2/3,czidbvn
+0x50,BVC,REL,2,2/3,czidbvn
+0x70,BVS,REL,2,2/3,czidbvn
+,,,,,
+0x24,BIT,ZP,2,3,cZidbVN
+0x2c,BIT,ABS,3,4,cZidbVN
+0x89,BIT,IMM,2,2,cZidbvn
+0x34,BIT,ZPX,2,4,cZidbVN
+0x3c,BIT,AX,3,4,cZidbVN
+,,,,,
+0x00,BRK,IMP,1,7,cziDBvn
+0x18,CLC,IMP,1,2,Czidbvn
+0xd8,CLD,IMP,1,2,cziDbvn
+0x58,CLI,IMP,1,2,czIdbvn
+0xb8,CLV,IMP,1,2,czidbVn
+0xea,NOP,IMP,1,2,czidbvn
+0x48,PHA,IMP,1,3,czidbvn
+0x68,PLA,IMP,1,4,cZidbvN
+0x08,PHP,IMP,1,3,czidbvn
+0x28,PLP,IMP,1,4,CZIDBVN
+0x40,RTI,IMP,1,6,czidbvn
+0x60,RTS,IMP,1,6,czidbvn
+0x38,SEC,IMP,1,2,Czidbvn
+0xf8,SED,IMP,1,2,cziDbvn
+0x78,SEI,IMP,1,2,czIdbvn
+0xaa,TAX,IMP,1,2,cZidbvN
+0x8a,TXA,IMP,1,2,cZidbvN
+0xa8,TAY,IMP,1,2,cZidbvN
+0x98,TYA,IMP,1,2,cZidbvN
+0xba,TSX,IMP,1,2,cZidbvN
+0x9a,TXS,IMP,1,2,czidbvn
+,,,,,
+0xc9,CMP,IMM,2,2,CZidbvN
+0xc5,CMP,ZP,2,3,CZidbvN
+0xd5,CMP,ZPX,2,4,CZidbvN
+0xcd,CMP,ABS,3,4,CZidbvN
+0xdd,CMP,AX,3,4,CZidbvN
+0xd9,CMP,AY,3,4,CZidbvN
+0xc1,CMP,ZIX,2,6,CZidbvN
+0xd1,CMP,ZIY,2,5,CZidbvN
+,,,,,
+0xe0,CPX,IMM,2,2,CZidbvN
+0xe4,CPX,ZP,2,3,CZidbvN
+0xec,CPX,ABS,3,4,CZidbvN
+,,,,,
+0xc0,CPY,IMM,2,2,CZidbvN
+0xc4,CPY,ZP,2,3,CZidbvN
+0xcc,CPY,ABS,3,4,CZidbvN
+,,,,,
+0xc6,DEC,ZP,2,5,cZidbvN
+0xd6,DEC,ZPX,2,6,cZidbvN
+0xce,DEC,ABS,3,6,cZidbvN
+0xde,DEC,AX,3,7,cZidbvN
+0x3a,DEC,ACC,1,2,cZidbvN
+,,,,,
+0xca,DEX,IMP,1,2,cZidbvN
+0x88,DEY,IMP,1,2,cZidbvN
+0xe8,INX,IMP,1,2,cZidbvN
+0xc8,INY,IMP,1,2,cZidbvN
+,,,,,
+0x49,EOR,IMM,2,2,cZidbvN
+0x45,EOR,ZP,2,3,cZidbvN
+0x55,EOR,ZPX,2,4,cZidbvN
+0x4d,EOR,ABS,3,4,cZidbvN
+0x5d,EOR,AX,3,4,cZidbvN
+0x59,EOR,AY,3,4,cZidbvN
+0x41,EOR,ZIX,2,6,cZidbvN
+0x51,EOR,ZIY,2,5,cZidbvN
+,,,,,
+0xe6,INC,ZP,2,5,cZidbvN
+0xf6,INC,ZPX,2,6,cZidbvN
+0xee,INC,ABS,3,6,cZidbvN
+0xfe,INC,AX,3,7,cZidbvN
+0x1a,INC,ACC,1,2,cZidbvN
+,,,,,
+0x4c,JMP,ABS,3,3,czidbvn
+0x6c,JMP,IND,3,5,czidbvn
+0x7c,JMP,AX,3,6,czidbvn
+0x20,JSR,ABS,3,6,czidbvn
+,,,,,
+0xa9,LDA,IMM,2,2,cZidbvN
+0xa5,LDA,ZP,2,3,cZidbvN
+0xb5,LDA,ZPX,2,4,cZidbvN
+0xad,LDA,ABS,3,4,cZidbvN
+0xbd,LDA,AX,3,4,cZidbvN
+0xb9,LDA,AY,3,4,cZidbvN
+0xa1,LDA,ZIX,2,6,cZidbvN
+0xb1,LDA,ZIY,2,5,cZidbvN
+,,,,,
+0xa2,LDX,IMM,2,2,cZidbvN
+0xa6,LDX,ZP,2,3,cZidbvN
+0xb6,LDX,ZPY,2,4,cZidbvN
+0xae,LDX,ABS,3,4,cZidbvN
+0xbe,LDX,AY,3,4,cZidbvN
+,,,,,
+0xa0,LDY,IMM,2,2,cZidbvN
+0xa4,LDY,ZP,2,3,cZidbvN
+0xb4,LDY,ZPX,2,4,cZidbvN
+0xac,LDY,ABS,3,4,cZidbvN
+0xbc,LDY,AX,3,4,cZidbvN
+,,,,,
+0x4a,LSR,ACC,1,2,cZidbvN
+0x46,LSR,ZP,2,5,cZidbvN
+0x56,LSR,ZPX,2,6,cZidbvN
+0x4e,LSR,ABS,3,6,cZidbvN
+0x5e,LSR,AX,3,6/7,cZidbvN
+,,,,,
+0x09,ORA,IMM,2,2,cZidbvN
+0x05,ORA,ZP,2,3,cZidbvN
+0x15,ORA,ZPX,2,4,cZidbvN
+0x0d,ORA,ABS,3,4,cZidbvN
+0x1d,ORA,AX,3,4,cZidbvN
+0x19,ORA,AY,3,4,cZidbvN
+0x01,ORA,ZIX,2,6,cZidbvN
+0x11,ORA,ZIY,2,5,cZidbvN
+,,,,,
+0x2a,ROL,ACC,1,2,CZidbvN
+0x26,ROL,ZP,2,5,CZidbvN
+0x36,ROL,ZPX,2,6,CZidbvN
+0x2e,ROL,ABS,3,6,CZidbvN
+0x3e,ROL,AX,3,6/7,CZidbvN
+,,,,,
+0x6a,ROR,ACC,1,2,CZidbvN
+0x66,ROR,ZP,2,5,CZidbvN
+0x76,ROR,ZPX,2,6,CZidbvN
+0x7e,ROR,ABS,3,6,CZidbvN
+0x6e,ROR,AX,3,6/7,CZidbvN
+,,,,,
+0xe9,SBC,IMM,2,2,CZidbVN
+0xe5,SBC,ZP,2,3,CZidbVN
+0xf5,SBC,ZPX,2,4,CZidbVN
+0xed,SBC,ABS,3,4,CZidbVN
+0xfd,SBC,AX,3,4,CZidbVN
+0xf9,SBC,AY,3,4,CZidbVN
+0xe1,SBC,ZIX,2,6,CZidbVN
+0xf1,SBC,ZIY,2,5,CZidbVN
+,,,,,
+0x85,STA,ZP,2,3,czidbvn
+0x95,STA,ZPX,2,4,czidbvn
+0x8d,STA,ABS,3,4,czidbvn
+0x9d,STA,AX,3,5,czidbvn
+0x99,STA,AY,3,5,czidbvn
+0x81,STA,ZIX,2,6,czidbvn
+0x91,STA,ZIY,2,6,czidbvn
+,,,,,
+0x86,STX,ZP,2,3,czidbvn
+0x96,STX,ZPY,2,4,czidbvn
+0x8e,STX,ABS,3,4,czidbvn
+0x84,STY,ZP,2,3,czidbvn
+0x94,STY,ZPX,2,4,czidbvn
+0x8c,STY,ABS,3,4,czidbvn
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..8c4167f
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,15 @@
+cmake_minimum_required(VERSION 3.0)
+
+project(6502 VERSION 0.1.0 LANGUAGES C)
+
+option(GEN_INSTRUCTIONS_HEADER ON)
+
+if (${GEN_INSTRUCTIONS_HEADER})
+ add_custom_command(
+ OUTPUT instructions.h
+ DEPENDS csv2h.awk 6502.csv
+ COMMAND awk -f csv2h.awk 6502.csv > instructions.h
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
+endif()
+
+add_executable(emu-6502 main.c cpu.c cpu.h instructions.h)
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..11e1de0
--- /dev/null
+++ b/README.md
@@ -0,0 +1,10 @@
+# 6502 Toolchain
+
+This project aims to create a portable toolchain for developing,
+testing and debugging programs for the 6502 processor. An assembler
+may be implemented in the future but no work has been done on that
+yet.
+
+The `instructions.h` header is generated from `6502.csv` and contains
+definitions of every 6502 opcode, its mnemonic and addressing mode.
+It is built automatically by cmake.
\ No newline at end of file
diff --git a/cpu.c b/cpu.c
new file mode 100644
index 0000000..f0d7d68
--- /dev/null
+++ b/cpu.c
@@ -0,0 +1,204 @@
+#include "cpu.h"
+#include "instructions.h"
+
+#include <endian.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define die(m, ...) \
+ printf("\033[31mError: " m "\033[0m\n", ##__VA_ARGS__); \
+ exit(1);
+
+cpu_t new_cpu()
+{
+ cpu_t cpu = { 0 };
+ cpu.regs[SR] = UNUSED; // unused flag always set
+ cpu.regs[SP] = 0xFD; // stack at is 0x100 + SP
+ cpu.pc = 0; // arbitrary program counter start
+ cpu.mem = malloc(0xFFFF);
+ memset(cpu.mem, 0, 0xFFFF);
+
+ if (!cpu.mem)
+ {
+ die("Could not allocate memory for CPU");
+ }
+
+ return cpu;
+}
+
+void free_cpu(cpu_t *cpu)
+{
+ free(cpu->mem);
+}
+
+void execute(cpu_t *cpu, const char *mnemonic, uint8_t op, uint16_t addr)
+{
+
+}
+
+uint16_t le_to_native(uint8_t a, uint8_t b)
+{
+#ifdef LITTLE_ENDIAN
+ return a << 8 | b;
+#else
+ return b << 8 | a;
+#endif
+}
+
+uint16_t fetch_le(cpu_t *cpu)
+{
+ uint8_t a = cpu->mem[cpu->pc++];
+ uint8_t b = cpu->mem[cpu->pc++];
+ return le_to_native(a, b);
+}
+
+uint16_t fetch_addr(cpu_t *cpu, uint8_t am)
+{
+ switch (am)
+ {
+ case AM_ACC:
+ case AM_IMP:
+ return 0;
+
+ // In both cases return immediate 8 bit value
+ case AM_IMM:
+ case AM_ZP:
+ return cpu->mem[cpu->pc++];
+
+ case AM_ABS:
+ return fetch_le(cpu);
+
+ case AM_REL:
+ {
+ // PC should point to the opcode
+ // braces needed to avoid c stupidity
+ uint16_t pc = cpu->pc - 1;
+ return cpu->mem[cpu->pc++] + pc;
+ }
+
+ case AM_IND:
+ {
+ uint16_t addr = fetch_le(cpu);
+ uint8_t low = cpu->mem[addr],
+ high = cpu->mem[addr + 1];
+
+ return le_to_native(low, high);
+ }
+
+ case AM_AX:
+ return fetch_le(cpu) + cpu->regs[X];
+
+ case AM_AY:
+ return fetch_le(cpu) + cpu->regs[Y];
+
+ case AM_ZPX:
+ return cpu->mem[cpu->pc++] + cpu->regs[X];
+
+ case AM_ZPY:
+ return cpu->mem[cpu->pc++] + cpu->regs[Y];
+
+ case AM_ZIX:
+ {
+ uint8_t zp = cpu->mem[cpu->pc++];
+ return le_to_native(cpu->mem[zp + cpu->regs[X]], cpu->mem[zp + cpu->regs[X] + 1]);
+ }
+
+ case AM_ZIY:
+ {
+ uint8_t zp = cpu->mem[cpu->pc++];
+ uint16_t base = le_to_native(cpu->mem[zp], cpu->mem[zp + 1]);
+ return base + cpu->regs[Y];
+ }
+
+ default:
+ die("Unknown address mode %x", am);
+ return -1; // unreachable
+ }
+}
+
+void step(cpu_t *cpu)
+{
+ switch (cpu->mem[cpu->pc++])
+ {
+#define INST(mn, am, op) \
+ case op: \
+ execute(cpu, #mn, mn, fetch_addr(cpu, am)); \
+ break;
+
+ INSTRUCTIONS
+
+#undef INST
+
+ default:
+ die("Undefined opcode");
+ }
+}
+
+void dump_inst(cpu_t *cpu, const char *mn, uint16_t addr, uint8_t am)
+{
+ printf("\t%s\t", mn);
+
+ switch (am)
+ {
+ case AM_IMM:
+ printf("#");
+ case AM_REL:
+ case AM_ABS:
+ case AM_ZP:
+ printf("$%x", addr);
+ break;
+
+ case AM_IND:
+ printf("($%x)", addr);
+ break;
+
+ case AM_AX:
+ case AM_ZPX:
+ printf("$%x, X", addr);
+ break;
+
+ case AM_AY:
+ case AM_ZPY:
+ printf("$%x, Y", addr);
+ break;
+
+ case AM_ZIX:
+ printf("($%x, X)", addr);
+ break;
+
+ case AM_ZIY:
+ printf("($%x), Y", addr);
+ break;
+ }
+
+ printf("\n");
+}
+
+void disas_step(cpu_t *cpu)
+{
+ printf("%x", cpu->pc);
+ uint8_t op = cpu->mem[cpu->pc++];
+ switch (op)
+ {
+#define INST(mn, am, op) \
+ case op: \
+ dump_inst(cpu, #mn, fetch_addr(cpu, am), am); \
+ break;
+
+ INSTRUCTIONS
+
+#undef INST
+
+ default:
+ die("Undefined opcode %x", op);
+ }
+}
+
+void disas(cpu_t *cpu)
+{
+ while (cpu->pc < 0xFFFF)
+ {
+ disas_step(cpu);
+ }
+}
diff --git a/cpu.h b/cpu.h
new file mode 100644
index 0000000..bbe6c60
--- /dev/null
+++ b/cpu.h
@@ -0,0 +1,117 @@
+#pragma once
+
+#include <stdint.h>
+
+enum // Registers
+{
+ A, X, Y, SR, SP
+};
+
+enum // Flags
+{
+ CARRY = 1 << 0,
+ ZERO = 1 << 1,
+ NO_INT = 1 << 2,
+ DECIMAL = 1 << 3,
+ BREAK = 1 << 4,
+ UNUSED = 1 << 5,
+ OVERFLW = 1 << 6,
+ NEGATIV = 1 << 7,
+};
+
+enum // Address Modes
+{
+ AM_ACC, // Accumulator implied as operand
+ AM_IMP, // Implied operand
+ AM_IMM, // Immediate operand (8 bit)
+ AM_ABS, // Absolute operand (16 bit)
+ AM_ZP, // Zero-page operand
+ AM_REL, // Relative operand (signed 8 bit)
+ AM_IND, // Absolute indirect operand (16 bit address of 16 bit address)
+ AM_AX, // Absolute indexed with X
+ AM_AY, // Absolute indexed with Y
+ AM_ZPX, // Zero-page indexed with X
+ AM_ZPY, // Zero-page indexed with Y
+ AM_ZIX, // Zero-page indexed indirect (zp,x)
+ AM_ZIY, // Zero-page indirect indexed (zp),y
+};
+
+enum // Opcodes
+{
+ LDA,
+ LDX,
+ LDY,
+ STA,
+ STX,
+ STY,
+ ADC,
+ SBC,
+ INC,
+ INX,
+ INY,
+ DEC,
+ DEX,
+ DEY,
+ ASL,
+ LSR,
+ ROL,
+ ROR,
+ AND,
+ ORA,
+ EOR,
+ CMP,
+ CPX,
+ CPY,
+ BIT,
+ BCC,
+ BCS,
+ BNE,
+ BEQ,
+ BPL,
+ BMI,
+ BVC,
+ BVS,
+ TAX,
+ TXA,
+ TAY,
+ TYA,
+ TSX,
+ TXS,
+ PHA,
+ PLA,
+ PHP,
+ PLP,
+ JMP,
+ JSR,
+ RTS,
+ RTI,
+ CLC,
+ SEC,
+ CLD,
+ SED,
+ CLI,
+ SEI,
+ CLV,
+ BRK,
+ NOP,
+};
+
+// Emulator instance, create with new_cpu()
+typedef struct
+{
+ uint8_t regs[5]; // A, X, Y, SP and SR registers
+ uint16_t pc;
+ uint8_t *mem;
+} cpu_t;
+
+// Argument type, includes both pointer and its value
+typedef struct
+{
+ uint16_t val; // Value at pointer (used by most instructions)
+ uint16_t ptr; // Pointer (used by jumps, etc)
+} arg_t;
+
+cpu_t new_cpu();
+void free_cpu(cpu_t *cpu);
+void die(const char *message);
+void disas(cpu_t *cpu);
diff --git a/csv2h.awk b/csv2h.awk
new file mode 100755
index 0000000..f98ba9e
--- /dev/null
+++ b/csv2h.awk
@@ -0,0 +1,10 @@
+BEGIN {
+ FS = ","
+ print "#pragma once\n"
+ print "// AUTO GENERATED FILE, DO NOT EDIT BY HAND"
+ print "#define INSTRUCTIONS \\"
+}
+
+/0x.+/ {
+ print " INST(" $2 ", AM_" $3 ", " $1" ) \\"
+}
diff --git a/instructions.h b/instructions.h
new file mode 100644
index 0000000..ba3d99d
--- /dev/null
+++ b/instructions.h
@@ -0,0 +1,161 @@
+#pragma once
+
+// AUTO GENERATED FILE, DO NOT EDIT BY HAND
+#define INSTRUCTIONS \
+ INST(ADC, AM_IMM, 0x69 ) \
+ INST(ADC, AM_ZP, 0x65 ) \
+ INST(ADC, AM_ZPX, 0x75 ) \
+ INST(ADC, AM_ABS, 0x6d ) \
+ INST(ADC, AM_AX, 0x7d ) \
+ INST(ADC, AM_AY, 0x79 ) \
+ INST(ADC, AM_ZIX, 0x61 ) \
+ INST(ADC, AM_ZIY, 0x71 ) \
+ INST(AND, AM_IMM, 0x29 ) \
+ INST(AND, AM_ZP, 0x25 ) \
+ INST(AND, AM_ZPX, 0x35 ) \
+ INST(AND, AM_ABS, 0x2d ) \
+ INST(AND, AM_AX, 0x3d ) \
+ INST(AND, AM_AY, 0x39 ) \
+ INST(AND, AM_ZIX, 0x21 ) \
+ INST(AND, AM_ZIY, 0x31 ) \
+ INST(ASL, AM_ACC, 0x0a ) \
+ INST(ASL, AM_ZP, 0x06 ) \
+ INST(ASL, AM_ZPX, 0x16 ) \
+ INST(ASL, AM_ABS, 0x0e ) \
+ INST(ASL, AM_AX, 0x1e ) \
+ INST(BCC, AM_REL, 0x90 ) \
+ INST(BCS, AM_REL, 0xB0 ) \
+ INST(BEQ, AM_REL, 0xF0 ) \
+ INST(BMI, AM_REL, 0x30 ) \
+ INST(BNE, AM_REL, 0xD0 ) \
+ INST(BPL, AM_REL, 0x10 ) \
+ INST(BVC, AM_REL, 0x50 ) \
+ INST(BVS, AM_REL, 0x70 ) \
+ INST(BIT, AM_ZP, 0x24 ) \
+ INST(BIT, AM_ABS, 0x2c ) \
+ INST(BIT, AM_IMM, 0x89 ) \
+ INST(BIT, AM_ZPX, 0x34 ) \
+ INST(BIT, AM_AX, 0x3c ) \
+ INST(BRK, AM_IMP, 0x00 ) \
+ INST(CLC, AM_IMP, 0x18 ) \
+ INST(CLD, AM_IMP, 0xd8 ) \
+ INST(CLI, AM_IMP, 0x58 ) \
+ INST(CLV, AM_IMP, 0xb8 ) \
+ INST(NOP, AM_IMP, 0xea ) \
+ INST(PHA, AM_IMP, 0x48 ) \
+ INST(PLA, AM_IMP, 0x68 ) \
+ INST(PHP, AM_IMP, 0x08 ) \
+ INST(PLP, AM_IMP, 0x28 ) \
+ INST(RTI, AM_IMP, 0x40 ) \
+ INST(RTS, AM_IMP, 0x60 ) \
+ INST(SEC, AM_IMP, 0x38 ) \
+ INST(SED, AM_IMP, 0xf8 ) \
+ INST(SEI, AM_IMP, 0x78 ) \
+ INST(TAX, AM_IMP, 0xaa ) \
+ INST(TXA, AM_IMP, 0x8a ) \
+ INST(TAY, AM_IMP, 0xa8 ) \
+ INST(TYA, AM_IMP, 0x98 ) \
+ INST(TSX, AM_IMP, 0xba ) \
+ INST(TXS, AM_IMP, 0x9a ) \
+ INST(CMP, AM_IMM, 0xc9 ) \
+ INST(CMP, AM_ZP, 0xc5 ) \
+ INST(CMP, AM_ZPX, 0xd5 ) \
+ INST(CMP, AM_ABS, 0xcd ) \
+ INST(CMP, AM_AX, 0xdd ) \
+ INST(CMP, AM_AY, 0xd9 ) \
+ INST(CMP, AM_ZIX, 0xc1 ) \
+ INST(CMP, AM_ZIY, 0xd1 ) \
+ INST(CPX, AM_IMM, 0xe0 ) \
+ INST(CPX, AM_ZP, 0xe4 ) \
+ INST(CPX, AM_ABS, 0xec ) \
+ INST(CPY, AM_IMM, 0xc0 ) \
+ INST(CPY, AM_ZP, 0xc4 ) \
+ INST(CPY, AM_ABS, 0xcc ) \
+ INST(DEC, AM_ZP, 0xc6 ) \
+ INST(DEC, AM_ZPX, 0xd6 ) \
+ INST(DEC, AM_ABS, 0xce ) \
+ INST(DEC, AM_AX, 0xde ) \
+ INST(DEC, AM_ACC, 0x3a ) \
+ INST(DEX, AM_IMP, 0xca ) \
+ INST(DEY, AM_IMP, 0x88 ) \
+ INST(INX, AM_IMP, 0xe8 ) \
+ INST(INY, AM_IMP, 0xc8 ) \
+ INST(EOR, AM_IMM, 0x49 ) \
+ INST(EOR, AM_ZP, 0x45 ) \
+ INST(EOR, AM_ZPX, 0x55 ) \
+ INST(EOR, AM_ABS, 0x4d ) \
+ INST(EOR, AM_AX, 0x5d ) \
+ INST(EOR, AM_AY, 0x59 ) \
+ INST(EOR, AM_ZIX, 0x41 ) \
+ INST(EOR, AM_ZIY, 0x51 ) \
+ INST(INC, AM_ZP, 0xe6 ) \
+ INST(INC, AM_ZPX, 0xf6 ) \
+ INST(INC, AM_ABS, 0xee ) \
+ INST(INC, AM_AX, 0xfe ) \
+ INST(INC, AM_ACC, 0x1a ) \
+ INST(JMP, AM_ABS, 0x4c ) \
+ INST(JMP, AM_IND, 0x6c ) \
+ INST(JMP, AM_AX, 0x7c ) \
+ INST(JSR, AM_ABS, 0x20 ) \
+ INST(LDA, AM_IMM, 0xa9 ) \
+ INST(LDA, AM_ZP, 0xa5 ) \
+ INST(LDA, AM_ZPX, 0xb5 ) \
+ INST(LDA, AM_ABS, 0xad ) \
+ INST(LDA, AM_AX, 0xbd ) \
+ INST(LDA, AM_AY, 0xb9 ) \
+ INST(LDA, AM_ZIX, 0xa1 ) \
+ INST(LDA, AM_ZIY, 0xb1 ) \
+ INST(LDX, AM_IMM, 0xa2 ) \
+ INST(LDX, AM_ZP, 0xa6 ) \
+ INST(LDX, AM_ZPY, 0xb6 ) \
+ INST(LDX, AM_ABS, 0xae ) \
+ INST(LDX, AM_AY, 0xbe ) \
+ INST(LDY, AM_IMM, 0xa0 ) \
+ INST(LDY, AM_ZP, 0xa4 ) \
+ INST(LDY, AM_ZPX, 0xb4 ) \
+ INST(LDY, AM_ABS, 0xac ) \
+ INST(LDY, AM_AX, 0xbc ) \
+ INST(LSR, AM_ACC, 0x4a ) \
+ INST(LSR, AM_ZP, 0x46 ) \
+ INST(LSR, AM_ZPX, 0x56 ) \
+ INST(LSR, AM_ABS, 0x4e ) \
+ INST(LSR, AM_AX, 0x5e ) \
+ INST(ORA, AM_IMM, 0x09 ) \
+ INST(ORA, AM_ZP, 0x05 ) \
+ INST(ORA, AM_ZPX, 0x15 ) \
+ INST(ORA, AM_ABS, 0x0d ) \
+ INST(ORA, AM_AX, 0x1d ) \
+ INST(ORA, AM_AY, 0x19 ) \
+ INST(ORA, AM_ZIX, 0x01 ) \
+ INST(ORA, AM_ZIY, 0x11 ) \
+ INST(ROL, AM_ACC, 0x2a ) \
+ INST(ROL, AM_ZP, 0x26 ) \
+ INST(ROL, AM_ZPX, 0x36 ) \
+ INST(ROL, AM_ABS, 0x2e ) \
+ INST(ROL, AM_AX, 0x3e ) \
+ INST(ROR, AM_ACC, 0x6a ) \
+ INST(ROR, AM_ZP, 0x66 ) \
+ INST(ROR, AM_ZPX, 0x76 ) \
+ INST(ROR, AM_ABS, 0x7e ) \
+ INST(ROR, AM_AX, 0x6e ) \
+ INST(SBC, AM_IMM, 0xe9 ) \
+ INST(SBC, AM_ZP, 0xe5 ) \
+ INST(SBC, AM_ZPX, 0xf5 ) \
+ INST(SBC, AM_ABS, 0xed ) \
+ INST(SBC, AM_AX, 0xfd ) \
+ INST(SBC, AM_AY, 0xf9 ) \
+ INST(SBC, AM_ZIX, 0xe1 ) \
+ INST(SBC, AM_ZIY, 0xf1 ) \
+ INST(STA, AM_ZP, 0x85 ) \
+ INST(STA, AM_ZPX, 0x95 ) \
+ INST(STA, AM_ABS, 0x8d ) \
+ INST(STA, AM_AX, 0x9d ) \
+ INST(STA, AM_AY, 0x99 ) \
+ INST(STA, AM_ZIX, 0x81 ) \
+ INST(STA, AM_ZIY, 0x91 ) \
+ INST(STX, AM_ZP, 0x86 ) \
+ INST(STX, AM_ZPY, 0x96 ) \
+ INST(STX, AM_ABS, 0x8e ) \
+ INST(STY, AM_ZP, 0x84 ) \
+ INST(STY, AM_ZPX, 0x94 ) \
+ INST(STY, AM_ABS, 0x8c ) \
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..8e6ec52
--- /dev/null
+++ b/main.c
@@ -0,0 +1,50 @@
+#include "cpu.h"
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int main(int argc, char **argv)
+{
+ printf("6502 Emulator\n");
+
+ uint8_t disflag = 0,
+ runflag = 0,
+ helpflag = 0;
+
+ char c;
+
+ while ((c = getopt(argc, argv, "drh")) != -1)
+ {
+ switch (c)
+ {
+ case 'd':
+ disflag = 1;
+ break;
+ case 'r':
+ runflag = 1;
+ break;
+ case 'h':
+ case '?':
+ helpflag = 1;
+ break;
+ }
+ }
+
+ if (helpflag)
+ {
+ printf("-r to run, -d to disassemble");
+ return 0;
+ }
+
+ cpu_t cpu = new_cpu();
+ fread(cpu.mem, 0xFFFF, 1, stdin);
+
+ if (disflag)
+ {
+ disas(&cpu);
+ }
+
+ free_cpu(&cpu);
+}
diff --git a/test.dat b/test.dat
new file mode 100644
index 0000000..0d6ba15
--- /dev/null
+++ b/test.dat
Binary files differ