~swisschili/toolchain-6502

97b5d8bfbd173dbe6eda51f3963877c1485b1a7b — swissChili 3 months ago 90db50a
Add step 1 of assembler
M .gitignore => .gitignore +3 -0
@@ 1,2 1,5 @@
.~*
build
#*#
*~
~*
\ No newline at end of file

M .gitmodules => .gitmodules +3 -0
@@ 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

M CMakeLists.txt => CMakeLists.txt +3 -0
@@ 3,9 3,12 @@ cmake_minimum_required(VERSION 3.0)
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

M README.md => README.md +2 -2
@@ 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

A as/CMakeLists.txt => as/CMakeLists.txt +9 -0
@@ 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)

A as/as.c => as/as.c +439 -0
@@ 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;
}

A as/as.h => as/as.h +9 -0
@@ 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);

A as/libcollect => as/libcollect +1 -0
@@ 0,0 1,1 @@
Subproject commit e9ee5221d307378150d2119939025b8709da178a

A as/main.c => as/main.c +44 -0
@@ 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);
}

A as/test/test.s => as/test/test.s +5 -0
@@ 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

M cpu.c => cpu.c +2 -5
@@ 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 @@ void step(cpu_t *cpu)
	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 @@ char *disas_step(cpu_t *cpu, uint16_t *pc)
	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); \

M cpu.h => cpu.h +5 -56
@@ 1,5 1,7 @@
#pragma once

#include "mnemonics.h"

#include <stdint.h>
#include <stdbool.h>
#include <mqueue.h>


@@ 48,62 50,9 @@ enum // Address Modes

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

M csv2h.awk => csv2h.awk +1 -1
@@ 6,5 6,5 @@ BEGIN {
}

/0x.+/ {
	print "	INST(" $2 ",	AM_" $3 ",	" $1" ) \\"
	print "	INST(" $2 ", AM_" $3 ", " $1", " $4 ") \\"
}

M instructions.h => instructions.h +157 -157
@@ 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) \

A mnemonics.h => mnemonics.h +62 -0
@@ 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)