Add step 1 of assembler
diff --git a/.gitignore b/.gitignore
index 798ef86..9f27f48 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,5 @@
.~*
build
+#*#
+*~
+~*
\ No newline at end of file
diff --git a/.gitmodules b/.gitmodules
index 6dc59b1..747fb4d 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,6 @@
[submodule "nuklear"]
path = nuklear
url = https://github.com/Immediate-Mode-UI/Nuklear.git
+[submodule "as/libcollect"]
+ path = as/libcollect
+ url = https://github.com/swissChili/libcollect
diff --git a/CMakeLists.txt b/CMakeLists.txt
index cfb97fe..5a27b55 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,9 +3,12 @@
project(6502 VERSION 0.1.0 LANGUAGES C)
option(GEN_INSTRUCTIONS_HEADER ON)
+option(BUILD_ASSEMBLER ON)
include_directories(nuklear)
+subdirs(as)
+
if (${GEN_INSTRUCTIONS_HEADER})
add_custom_command(
OUTPUT instructions.h
diff --git a/README.md b/README.md
index 924f97d..2d9e8ed 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
-# 6502 Toolchain
+# [6502 Toolchain](https://6502.swisschili.sh)
-[![Screenshot](screenshot.png)](colors.webm)
+[![Screenshot](screenshot.png)](https://6502.swisschili.sh)
This project aims to create a portable toolchain for developing,
testing and debugging programs for the 6502 processor. An assembler
diff --git a/as/CMakeLists.txt b/as/CMakeLists.txt
new file mode 100644
index 0000000..e2062c2
--- /dev/null
+++ b/as/CMakeLists.txt
@@ -0,0 +1,9 @@
+cmake_minimum_required(VERSION 3.0)
+
+project(6502 VERSION 0.1.0 LANGUAGES C)
+
+subdirs(libcollect)
+include_directories(libcollect/include)
+
+add_executable(6502-as main.c as.h as.c)
+target_link_libraries(6502-as collect)
diff --git a/as/as.c b/as/as.c
new file mode 100644
index 0000000..61ad6bd
--- /dev/null
+++ b/as/as.c
@@ -0,0 +1,439 @@
+#include "as.h"
+#include "../cpu.h"
+#include "../instructions.h"
+#include "../mnemonics.h"
+
+#include <collect/map.h>
+#include <collect/vector.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdbool.h>
+
+enum
+{
+ ARG_16, /* Absolute 16 bit argument */
+ ARG_8, /* Absolute 8 bit argument */
+ ARG_8REL, /* Relative 8 bit argument */
+ ARG_REL, /* Relative label */
+ ARG_ABS, /* Absolute label */
+ ARG_IMP, /* Implied argument */
+};
+
+typedef struct
+{
+ uint8_t opcode;
+ uint8_t arg_type;
+ union
+ {
+ char label[32];
+ uint16_t long_arg;
+ uint8_t byte_arg;
+ int8_t rel_arg;
+ };
+} inst_t;
+
+void print_inst(inst_t *arg)
+{
+ char *arg_types =
+ "16 8 8RELREL ABS IMP ";
+
+ printf("\033[33mInst: %.4s $%x ", arg_types + arg->arg_type * 4, arg->opcode);
+
+ switch (arg->arg_type)
+ {
+ case ARG_16:
+ printf("%x", arg->long_arg);
+ break;
+ case ARG_8:
+ printf("%x", arg->byte_arg);
+ break;
+ case ARG_8REL:
+ printf("%d", arg->rel_arg);
+ break;
+ case ARG_REL:
+ case ARG_ABS:
+ printf("%s", arg->label);
+ break;
+ }
+
+ printf("\033[0m\n");
+}
+
+bool is_ident(char c)
+{
+ return c && (isalpha(c) || isdigit(c));
+}
+
+uint32_t skip_ws(char **code)
+{
+ uint32_t len = 0;
+
+ for (; isspace(**code); (*code)++, len++)
+ {}
+
+ return len;
+}
+
+uint32_t skip_to_eol(char **code)
+{
+ uint32_t len = 0;
+
+ for (; **code && **code != '\n'; (*code)++, len++)
+ {}
+
+ if (**code)
+ (*code)++;
+
+ return len;
+}
+
+char *parse_label_name(char **code)
+{
+ char *start = *code;
+ for (; is_ident(**code); (*code)++)
+ {}
+
+ if (start == *code)
+ return false;
+
+ **code = 0;
+ return start;
+}
+
+char *parse_label(char **code)
+{
+ char *start = *code;
+
+ for (; is_ident(**code); (*code)++)
+ {}
+
+ skip_ws(code);
+
+ if (**code == ':')
+ {
+ **code = 0;
+ (*code)++;
+ return start;
+ }
+
+ *code = start;
+
+ return NULL;
+}
+
+char *parse_inst(char **code)
+{
+ char *start = *code;
+
+ for (; isalpha(**code); (*code)++)
+ {}
+
+ **code = 0;
+
+ if (start == *code)
+ return NULL;
+
+ (*code)++;
+ return start;
+}
+
+bool is_eol(char c)
+{
+ return c == ';' ||
+ c == '\n' ||
+ c == '\r' ||
+ c == '\0';
+}
+
+bool skip(char **code, const char *p)
+{
+ for (; *p && *p == **code; p++, (*code)++)
+ {}
+
+ if (!*p)
+ return true;
+ return false;
+}
+
+bool parse_num(char **code, uint64_t *num)
+{
+ char *start = *code;
+ int base = 10;
+ if (**code == '$')
+ {
+ base = 16;
+ (*code)++;
+ }
+
+ skip_ws(code);
+
+ char *endptr = *code;
+ int64_t val = strtol(*code, &endptr, base);
+
+ if (*code == endptr)
+ {
+ *code = start;
+ return false;
+ }
+ *num = val;
+ *code = endptr;
+ return true;
+}
+
+bool parse_num_max(char **code, uint64_t *num, uint64_t max)
+{
+ uint64_t n;
+ if (parse_num(code, &n))
+ {
+ if (n > max)
+ return false;
+
+ *num = n;
+ return true;
+ }
+ else return false;
+}
+
+bool parse_u8(char **code, uint8_t *num)
+{
+ uint64_t n;
+ if (!parse_num_max(code, &n, 0xFF))
+ return false;
+
+ *num = n & 0xFF;
+ return true;
+}
+
+bool parse_u16(char **code, uint16_t *num)
+{
+ uint64_t n;
+ if (!parse_num_max(code, &n, 0xFFFF))
+ return false;
+
+ *num = n & 0xFFFF;
+ return true;
+}
+
+bool ws_end(char **code)
+{
+ skip_ws(code);
+ return is_eol(**code);
+}
+
+bool parse_arg(char *code, int am, inst_t *inst)
+{
+ skip_ws(&code);
+
+ uint16_t num;
+ uint8_t num8;
+ char *lbl;
+
+ switch (am)
+ {
+ case AM_ACC:
+ case AM_IMP:
+ printf("Trying AM_IMP on '%.8s'\n", code);
+ skip_ws(&code);
+ if (is_eol(*code))
+ {
+ inst->arg_type = ARG_IMP;
+ return ws_end(&code);
+ }
+ break;
+
+ case AM_IMM:
+ printf("Trying AM_IMM on '%.8s'\n", code);
+ if (!skip(&code, "#"))
+ return false;
+ skip_ws(&code);
+ case AM_ZP:
+ if (parse_u8(&code, &num8))
+ {
+ inst->arg_type = ARG_8;
+ inst->byte_arg = num8;
+
+ return ws_end(&code);
+ }
+ break;
+
+ case AM_ABS:
+ if (parse_u16(&code, &num))
+ {
+ inst->arg_type = ARG_16;
+ inst->long_arg = num;
+ return true;
+ }
+ else if ((lbl = parse_label_name(&code)))
+ {
+ inst->arg_type = ARG_ABS;
+ strncpy(inst->label, lbl, 32);
+ return true;
+ }
+ break;
+
+ case AM_REL:
+ if (parse_u8(&code, &num8))
+ {
+ inst->arg_type = ARG_8REL;
+ inst->rel_arg = num;
+ return ws_end(&code);
+ }
+ else if ((lbl = parse_label_name(&code)))
+ {
+ inst->arg_type = ARG_REL;
+ strncpy(inst->label, lbl, 32);
+ return ws_end(&code);
+ }
+ break;
+
+ case AM_IND:
+ if (!skip(&code,"("))
+ return false;
+
+ if (!parse_u16(&code, &num))
+ return false;
+
+ if (!skip(&code, ")"))
+ return false;
+
+ inst->arg_type = ARG_16;
+ inst->long_arg = num;
+ return true;
+
+ case AM_AX:
+ case AM_ZPX:
+ case AM_AY:
+ case AM_ZPY:
+ if (am == AM_AX || am == AM_AY)
+ {
+ if (!parse_u16(&code, &num))
+ return false;
+ inst->arg_type = ARG_16;
+ inst->long_arg = num;
+ }
+ else
+ {
+ if (!parse_u8(&code, &num8))
+ return false;
+ inst->arg_type = ARG_8;
+ inst->byte_arg = num8;
+ }
+ if (!skip(&code, ","))
+ return false;
+
+ skip_ws(&code);
+
+ if (tolower(*code) != (am == AM_AY || am == AM_ZPY ? 'y' : 'x'))
+ return false;
+
+ return ws_end(&code);
+
+ case AM_ZIX:
+ if (!skip(&code, "("))
+ break;
+ skip_ws(&code);
+ if (!parse_u8(&code, &num8))
+ break;
+ skip_ws(&code);
+ if (!skip(&code, ","))
+ break;
+ skip_ws(&code);
+ if (tolower(*code) != 'x')
+ return false;
+ skip_ws(&code);
+
+ if (!skip(&code, ")"))
+ break;
+
+ inst->arg_type = ARG_8;
+ inst->byte_arg = num8;
+ return ws_end(&code);
+
+ case AM_ZIY:
+ if (!skip(&code, "("))
+ break;
+ skip_ws(&code);
+ if (!parse_u8(&code, &num8))
+ break;
+ skip_ws(&code);
+ if (!skip(&code, ")"))
+ break;
+ skip_ws(&code);
+ if (!skip(&code, ","))
+ break;
+ skip_ws(&code);
+ if (tolower(*code) != 'x')
+ break;
+
+ inst->arg_type = ARG_8;
+ inst->byte_arg = num8;
+ return ws_end(&code);
+ }
+ return false;
+}
+
+uint32_t assemble(char *code, FILE *out)
+{
+ uintptr_t num_insts = 0;
+ uint32_t line_no = 1;
+ map *labels = new_map();
+ vector *insts = new_vector();
+ char *line;
+
+ printf("Assembling File\n");
+ printf("%s\n", code);
+
+ line = strtok(code, "\r\n");
+
+ while (line)
+ {
+ skip_ws(&line);
+
+ printf("\033[36m%.9s\033[0m\n", line);
+
+ char *label = parse_label(&line),
+ *mn = parse_inst(&line);
+ int32_t mnemonic = -1;
+
+ if (label)
+ {
+ map_set(labels, label, (void *)num_insts);
+ printf("Set label %s at %lu\n", label, num_insts);
+ }
+
+ if (mn)
+ {
+#define MN(a) if (!strcasecmp(mn, #a)) \
+ mnemonic = a; \
+ else
+
+ MNEMONICS;
+#undef MN
+
+ printf("Got instruction %s %d\n", mn, mnemonic);
+
+ inst_t arg;
+ // printf("Parsing '%s'\n", line);
+#define INST(_mn, am, op, len) \
+ if (mnemonic == _mn && parse_arg(line, am, &arg)) \
+ { \
+ arg.opcode = op; \
+ print_inst(&arg); \
+ } \
+ else
+
+ INSTRUCTIONS
+ {
+ printf("\033[31mCould not be parsed: %s '%s'\033[0m\n", mn, line);
+ }
+#undef INST
+ }
+
+ num_insts++;
+ line = strtok(NULL, "\r\n");
+ }
+
+ free_map(labels);
+
+ return num_insts;
+}
diff --git a/as/as.h b/as/as.h
new file mode 100644
index 0000000..4e167dd
--- /dev/null
+++ b/as/as.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include <stdio.h>
+#include <stdint.h>
+
+/*
+ * @returns NULL on failure, printing info to stderr
+ */
+uint32_t assemble(char *code, FILE *out);
diff --git a/as/libcollect b/as/libcollect
new file mode 160000
index 0000000..e9ee522
--- /dev/null
+++ b/as/libcollect
@@ -0,0 +1 @@
+Subproject commit e9ee5221d307378150d2119939025b8709da178a
diff --git a/as/main.c b/as/main.c
new file mode 100644
index 0000000..cf966f8
--- /dev/null
+++ b/as/main.c
@@ -0,0 +1,44 @@
+#include "as.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <bits/getopt_core.h>
+#include <unistd.h>
+
+int main(int argc, char **argv)
+{
+ char c;
+ FILE *in = stdin,
+ *out = stdout;
+
+ while ((c = getopt(argc, argv, "i:o:")) != -1)
+ {
+ switch (c)
+ {
+ case 'i':
+ in = fopen(optarg, "r");
+ break;
+ case 'o':
+ out = fopen(optarg, "w");
+ break;
+ case 'h':
+ case '?':
+ printf("6502 assembler\n"
+ "Usage:\n"
+ " -i <input> set input file (default stdin)\n"
+ " -o <output> set output file (default stdout)\n");
+ }
+ }
+
+ fseek(in, 0, SEEK_END);
+ ssize_t len = ftell(in);
+ fseek(in, 0, SEEK_SET);
+
+ char *text = malloc(len + 1);
+ fread(text, len, 1, in);
+ text[len] = 0;
+
+ uint32_t built = assemble(text, out);
+
+ free(text);
+}
diff --git a/as/test/test.s b/as/test/test.s
new file mode 100644
index 0000000..edca24a
--- /dev/null
+++ b/as/test/test.s
@@ -0,0 +1,5 @@
+start:
+ lda #$32 ; Store $32 in a
+ tax ; Transfer a to x
+ stx $200 ; Store x at $200
+ jmp ($FFAA) ; Jump to the address at $FFAA
diff --git a/cpu.c b/cpu.c
index 12f9af7..ce489cc 100644
--- a/cpu.c
+++ b/cpu.c
@@ -11,9 +11,6 @@
#include <stdlib.h>
#include <string.h>
-#define die(m, ...) \
- printf("\033[31m" m "\033[0m\n", ##__VA_ARGS__); \
- exit(1);
#define warn(m, ...) \
printf("\033[33m" m "\033[0m\n", ##__VA_ARGS__);
@@ -534,7 +531,7 @@
uint8_t op = cpu->mem[cpu->pc++];
switch (op)
{
-#define INST(mn, am, op) \
+#define INST(mn, am, op, len) \
case op: \
execute(cpu, #mn, mn, fetch_addr(cpu, am, 0, &cpu->pc), am); \
break;
@@ -599,7 +596,7 @@
uint8_t op = cpu->mem[(*pc)++];
switch (op)
{
-#define INST(mn, am, op) \
+#define INST(mn, am, op, len) \
case op: \
end += dump_inst(cpu, end, #mn, \
fetch_addr(cpu, am, FETCH_NO_INDIRECTION, pc).ptr, am); \
diff --git a/cpu.h b/cpu.h
index 130ef05..05acebc 100644
--- a/cpu.h
+++ b/cpu.h
@@ -1,5 +1,7 @@
#pragma once
+#include "mnemonics.h"
+
#include <stdint.h>
#include <stdbool.h>
#include <mqueue.h>
@@ -48,62 +50,9 @@
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,
+#define MN(name) name,
+ MNEMONICS
+#undef MN
};
enum // Fetch flags
diff --git a/csv2h.awk b/csv2h.awk
index f98ba9e..dfebaec 100755
--- a/csv2h.awk
+++ b/csv2h.awk
@@ -6,5 +6,5 @@
}
/0x.+/ {
- print " INST(" $2 ", AM_" $3 ", " $1" ) \\"
+ print " INST(" $2 ", AM_" $3 ", " $1", " $4 ") \\"
}
diff --git a/instructions.h b/instructions.h
index ba3d99d..082016f 100644
--- a/instructions.h
+++ b/instructions.h
@@ -2,160 +2,160 @@
// 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 ) \
+ INST(ADC, AM_IMM, 0x69, 2) \
+ INST(ADC, AM_ZP, 0x65, 2) \
+ INST(ADC, AM_ZPX, 0x75, 2) \
+ INST(ADC, AM_ABS, 0x6d, 3) \
+ INST(ADC, AM_AX, 0x7d, 3) \
+ INST(ADC, AM_AY, 0x79, 3) \
+ INST(ADC, AM_ZIX, 0x61, 2) \
+ INST(ADC, AM_ZIY, 0x71, 2) \
+ INST(AND, AM_IMM, 0x29, 2) \
+ INST(AND, AM_ZP, 0x25, 2) \
+ INST(AND, AM_ZPX, 0x35, 2) \
+ INST(AND, AM_ABS, 0x2d, 3) \
+ INST(AND, AM_AX, 0x3d, 3) \
+ INST(AND, AM_AY, 0x39, 3) \
+ INST(AND, AM_ZIX, 0x21, 2) \
+ INST(AND, AM_ZIY, 0x31, 2) \
+ INST(ASL, AM_ACC, 0x0a, 1) \
+ INST(ASL, AM_ZP, 0x06, 2) \
+ INST(ASL, AM_ZPX, 0x16, 2) \
+ INST(ASL, AM_ABS, 0x0e, 3) \
+ INST(ASL, AM_AX, 0x1e, 3) \
+ INST(BCC, AM_REL, 0x90, 2) \
+ INST(BCS, AM_REL, 0xB0, 2) \
+ INST(BEQ, AM_REL, 0xF0, 2) \
+ INST(BMI, AM_REL, 0x30, 2) \
+ INST(BNE, AM_REL, 0xD0, 2) \
+ INST(BPL, AM_REL, 0x10, 2) \
+ INST(BVC, AM_REL, 0x50, 2) \
+ INST(BVS, AM_REL, 0x70, 2) \
+ INST(BIT, AM_ZP, 0x24, 2) \
+ INST(BIT, AM_ABS, 0x2c, 3) \
+ INST(BIT, AM_IMM, 0x89, 2) \
+ INST(BIT, AM_ZPX, 0x34, 2) \
+ INST(BIT, AM_AX, 0x3c, 3) \
+ INST(BRK, AM_IMP, 0x00, 1) \
+ INST(CLC, AM_IMP, 0x18, 1) \
+ INST(CLD, AM_IMP, 0xd8, 1) \
+ INST(CLI, AM_IMP, 0x58, 1) \
+ INST(CLV, AM_IMP, 0xb8, 1) \
+ INST(NOP, AM_IMP, 0xea, 1) \
+ INST(PHA, AM_IMP, 0x48, 1) \
+ INST(PLA, AM_IMP, 0x68, 1) \
+ INST(PHP, AM_IMP, 0x08, 1) \
+ INST(PLP, AM_IMP, 0x28, 1) \
+ INST(RTI, AM_IMP, 0x40, 1) \
+ INST(RTS, AM_IMP, 0x60, 1) \
+ INST(SEC, AM_IMP, 0x38, 1) \
+ INST(SED, AM_IMP, 0xf8, 1) \
+ INST(SEI, AM_IMP, 0x78, 1) \
+ INST(TAX, AM_IMP, 0xaa, 1) \
+ INST(TXA, AM_IMP, 0x8a, 1) \
+ INST(TAY, AM_IMP, 0xa8, 1) \
+ INST(TYA, AM_IMP, 0x98, 1) \
+ INST(TSX, AM_IMP, 0xba, 1) \
+ INST(TXS, AM_IMP, 0x9a, 1) \
+ INST(CMP, AM_IMM, 0xc9, 2) \
+ INST(CMP, AM_ZP, 0xc5, 2) \
+ INST(CMP, AM_ZPX, 0xd5, 2) \
+ INST(CMP, AM_ABS, 0xcd, 3) \
+ INST(CMP, AM_AX, 0xdd, 3) \
+ INST(CMP, AM_AY, 0xd9, 3) \
+ INST(CMP, AM_ZIX, 0xc1, 2) \
+ INST(CMP, AM_ZIY, 0xd1, 2) \
+ INST(CPX, AM_IMM, 0xe0, 2) \
+ INST(CPX, AM_ZP, 0xe4, 2) \
+ INST(CPX, AM_ABS, 0xec, 3) \
+ INST(CPY, AM_IMM, 0xc0, 2) \
+ INST(CPY, AM_ZP, 0xc4, 2) \
+ INST(CPY, AM_ABS, 0xcc, 3) \
+ INST(DEC, AM_ZP, 0xc6, 2) \
+ INST(DEC, AM_ZPX, 0xd6, 2) \
+ INST(DEC, AM_ABS, 0xce, 3) \
+ INST(DEC, AM_AX, 0xde, 3) \
+ INST(DEC, AM_ACC, 0x3a, 1) \
+ INST(DEX, AM_IMP, 0xca, 1) \
+ INST(DEY, AM_IMP, 0x88, 1) \
+ INST(INX, AM_IMP, 0xe8, 1) \
+ INST(INY, AM_IMP, 0xc8, 1) \
+ INST(EOR, AM_IMM, 0x49, 2) \
+ INST(EOR, AM_ZP, 0x45, 2) \
+ INST(EOR, AM_ZPX, 0x55, 2) \
+ INST(EOR, AM_ABS, 0x4d, 3) \
+ INST(EOR, AM_AX, 0x5d, 3) \
+ INST(EOR, AM_AY, 0x59, 3) \
+ INST(EOR, AM_ZIX, 0x41, 2) \
+ INST(EOR, AM_ZIY, 0x51, 2) \
+ INST(INC, AM_ZP, 0xe6, 2) \
+ INST(INC, AM_ZPX, 0xf6, 2) \
+ INST(INC, AM_ABS, 0xee, 3) \
+ INST(INC, AM_AX, 0xfe, 3) \
+ INST(INC, AM_ACC, 0x1a, 1) \
+ INST(JMP, AM_ABS, 0x4c, 3) \
+ INST(JMP, AM_IND, 0x6c, 3) \
+ INST(JMP, AM_AX, 0x7c, 3) \
+ INST(JSR, AM_ABS, 0x20, 3) \
+ INST(LDA, AM_IMM, 0xa9, 2) \
+ INST(LDA, AM_ZP, 0xa5, 2) \
+ INST(LDA, AM_ZPX, 0xb5, 2) \
+ INST(LDA, AM_ABS, 0xad, 3) \
+ INST(LDA, AM_AX, 0xbd, 3) \
+ INST(LDA, AM_AY, 0xb9, 3) \
+ INST(LDA, AM_ZIX, 0xa1, 2) \
+ INST(LDA, AM_ZIY, 0xb1, 2) \
+ INST(LDX, AM_IMM, 0xa2, 2) \
+ INST(LDX, AM_ZP, 0xa6, 2) \
+ INST(LDX, AM_ZPY, 0xb6, 2) \
+ INST(LDX, AM_ABS, 0xae, 3) \
+ INST(LDX, AM_AY, 0xbe, 3) \
+ INST(LDY, AM_IMM, 0xa0, 2) \
+ INST(LDY, AM_ZP, 0xa4, 2) \
+ INST(LDY, AM_ZPX, 0xb4, 2) \
+ INST(LDY, AM_ABS, 0xac, 3) \
+ INST(LDY, AM_AX, 0xbc, 3) \
+ INST(LSR, AM_ACC, 0x4a, 1) \
+ INST(LSR, AM_ZP, 0x46, 2) \
+ INST(LSR, AM_ZPX, 0x56, 2) \
+ INST(LSR, AM_ABS, 0x4e, 3) \
+ INST(LSR, AM_AX, 0x5e, 3) \
+ INST(ORA, AM_IMM, 0x09, 2) \
+ INST(ORA, AM_ZP, 0x05, 2) \
+ INST(ORA, AM_ZPX, 0x15, 2) \
+ INST(ORA, AM_ABS, 0x0d, 3) \
+ INST(ORA, AM_AX, 0x1d, 3) \
+ INST(ORA, AM_AY, 0x19, 3) \
+ INST(ORA, AM_ZIX, 0x01, 2) \
+ INST(ORA, AM_ZIY, 0x11, 2) \
+ INST(ROL, AM_ACC, 0x2a, 1) \
+ INST(ROL, AM_ZP, 0x26, 2) \
+ INST(ROL, AM_ZPX, 0x36, 2) \
+ INST(ROL, AM_ABS, 0x2e, 3) \
+ INST(ROL, AM_AX, 0x3e, 3) \
+ INST(ROR, AM_ACC, 0x6a, 1) \
+ INST(ROR, AM_ZP, 0x66, 2) \
+ INST(ROR, AM_ZPX, 0x76, 2) \
+ INST(ROR, AM_ABS, 0x7e, 3) \
+ INST(ROR, AM_AX, 0x6e, 3) \
+ INST(SBC, AM_IMM, 0xe9, 2) \
+ INST(SBC, AM_ZP, 0xe5, 2) \
+ INST(SBC, AM_ZPX, 0xf5, 2) \
+ INST(SBC, AM_ABS, 0xed, 3) \
+ INST(SBC, AM_AX, 0xfd, 3) \
+ INST(SBC, AM_AY, 0xf9, 3) \
+ INST(SBC, AM_ZIX, 0xe1, 2) \
+ INST(SBC, AM_ZIY, 0xf1, 2) \
+ INST(STA, AM_ZP, 0x85, 2) \
+ INST(STA, AM_ZPX, 0x95, 2) \
+ INST(STA, AM_ABS, 0x8d, 3) \
+ INST(STA, AM_AX, 0x9d, 3) \
+ INST(STA, AM_AY, 0x99, 3) \
+ INST(STA, AM_ZIX, 0x81, 2) \
+ INST(STA, AM_ZIY, 0x91, 2) \
+ INST(STX, AM_ZP, 0x86, 2) \
+ INST(STX, AM_ZPY, 0x96, 2) \
+ INST(STX, AM_ABS, 0x8e, 3) \
+ INST(STY, AM_ZP, 0x84, 2) \
+ INST(STY, AM_ZPX, 0x94, 2) \
+ INST(STY, AM_ABS, 0x8c, 3) \
diff --git a/mnemonics.h b/mnemonics.h
new file mode 100644
index 0000000..e9d6dfe
--- /dev/null
+++ b/mnemonics.h
@@ -0,0 +1,62 @@
+
+#pragma once
+
+// File not auto generated (unfortunately), needs to be kept up to date manually
+
+#define MNEMONICS \
+ MN(LDA) \
+ MN(LDX) \
+ MN(LDY) \
+ MN(STA) \
+ MN(STX) \
+ MN(STY) \
+ MN(ADC) \
+ MN(SBC) \
+ MN(INC) \
+ MN(INX) \
+ MN(INY) \
+ MN(DEC) \
+ MN(DEX) \
+ MN(DEY) \
+ MN(ASL) \
+ MN(LSR) \
+ MN(ROL) \
+ MN(ROR) \
+ MN(AND) \
+ MN(ORA) \
+ MN(EOR) \
+ MN(CMP) \
+ MN(CPX) \
+ MN(CPY) \
+ MN(BIT) \
+ MN(BCC) \
+ MN(BCS) \
+ MN(BNE) \
+ MN(BEQ) \
+ MN(BPL) \
+ MN(BMI) \
+ MN(BVC) \
+ MN(BVS) \
+ MN(TAX) \
+ MN(TXA) \
+ MN(TAY) \
+ MN(TYA) \
+ MN(TSX) \
+ MN(TXS) \
+ MN(PHA) \
+ MN(PLA) \
+ MN(PHP) \
+ MN(PLP) \
+ MN(JMP) \
+ MN(JSR) \
+ MN(RTS) \
+ MN(RTI) \
+ MN(CLC) \
+ MN(SEC) \
+ MN(CLD) \
+ MN(SED) \
+ MN(CLI) \
+ MN(SEI) \
+ MN(CLV) \
+ MN(BRK) \
+ MN(NOP)