#include "cpu.h"
#include "cpu_opcodes.h"

struct cpu6502_t
{
	int pc;	/* Program counter */
	int sp;	/* Stack pointer */
	int a;	/* Accumulator */
	int x;	/* X Index */
	int y;	/* Y Index */
	int p;	/* Processor status */
	
	mapper_t* mapper;
	
	opcode_t opcodes[256];
	
	int irq_requested;
	int irq_type;
};

/* Private funcs prototypes */
void cpu_push(cpu6502_t* cpu, int value);
int cpu_pop(cpu6502_t* cpu);
void cpu_stackwrap(cpu6502_t* cpu);
void cpu_fill_opcode(cpu6502_t* cpu, int inst, int op, int addr_mode, int size, int cycles);
void cpu_create_opcodes(cpu6502_t* cpu);

void cpu_init(cpu6502_t** cpu)
{
	cpu6502_t* pThis = NULL;

	(*cpu) = (cpu6502_t*)malloc(sizeof(cpu6502_t));
	assert((*cpu));
	pThis = (*cpu);
	
	pThis->mapper = NULL;
	
	cpu_create_opcodes(pThis);
}

void cpu_kill(cpu6502_t* cpu)
{
	cpu6502_t* pThis = cpu;
	
	assert(pThis);
	
	free(pThis);
}

void cpu_reset(cpu6502_t* cpu)
{
	cpu6502_t* pThis = cpu;
	
	assert(pThis);
	
	pThis->pc = 0x7FFF; /* 0x8000 - 1 */
	pThis->sp = 0x01FF;
	pThis->a = 0x0;
	pThis->x = 0x0;
	pThis->y = 0x0;
	pThis->p = FLAG_UNUSED | FLAG_BREAK | FLAG_DECIMAL | FLAG_INTERRUPT | FLAG_ZERO;
	
	pThis->irq_requested = 0;
	pThis->irq_type = 0;
	
	printf("MSG: CPU reset.\n");
}

void cpu_set_mapper(cpu6502_t* cpu, mapper_t* mapper)
{
	assert(cpu && mapper);
	cpu->mapper = mapper;
}

void cpu_request_irq(cpu6502_t* cpu, int type)
{
	cpu6502_t* pThis = cpu;
	
	assert(pThis);

	if (pThis->irq_requested) {
		if (type == IRQ_NORMAL) {
			return;
		}
		printf("ERR: IRQ too fast!\n");
	}
	
	pThis->irq_requested = 1;
	pThis->irq_type = type;
}

int cpu_emulate(cpu6502_t* cpu)
{
	cpu6502_t* pThis = cpu;
	opcode_t opcode;
	int opaddress = 0x0;
	int address = 0x0;
	int cycles = 0;
	int extra_cycle = 0;

	assert(pThis);
	assert(pThis->mapper);
	
	if (pThis->irq_requested) {
		switch (pThis->irq_type) {
			case IRQ_NORMAL: {
				int tpc;
				
				printf("MSG: IRQ_NORMAL.\n");
				
				if ((pThis->p >> 2) & 0x1) {
					printf("MSG: Interrupt masked.\n");
					break;
				}
				
				tpc = pThis->pc + 1;
				cpu_push(pThis, (tpc >> 8) & 0xFF);
				cpu_push(pThis, tpc & 0xFF);
				cpu_push(pThis, pThis->p);
				
				pThis->p |= FLAG_INTERRUPT;
				pThis->p = (pThis->p & ~FLAG_BREAK);
				
				tpc = mapper_read16(pThis->mapper, 0xFFFE);
				pThis->pc = tpc - 1;
				
				break;
			}
			
			case IRQ_NMI: {
				if (mapper_read(pThis->mapper, 0x2000) & 0x80) {
					int tpc;
					
					printf("MSG: IRQ_NMI.\n");
					
					tpc = pThis->pc + 1;
					cpu_push(pThis, (tpc >> 8) & 0xFF);
					cpu_push(pThis, tpc & 0xFF);
					cpu_push(pThis, pThis->p);
					
					tpc = mapper_read16(pThis->mapper, 0xFFFA);
					pThis->pc = tpc - 1;
				}

				break;
			}
			
			case IRQ_RESET: {
				printf("MSG: IRQ_RESET.\n");
				pThis->pc = mapper_read16(pThis->mapper, 0xFFFC);
				pThis->pc--;
				break;
			}
		}
	}
	
	/* Fetch op from memory */
	opcode = pThis->opcodes[mapper_read(pThis->mapper, pThis->pc + 1)];
	if (opcode.inst == 0xFF) {
		/* TODO: Add kill code? */
		printf("Crash: Invalid opcode at $%04X!\n", pThis->pc + 1);
		return 0;
	}
	
	/* Increment program counter */
	opaddress = pThis->pc;
	pThis->pc += opcode.size;
	
	/* Store cycles */
	cycles = opcode.cycles;

	/* Find address */
	switch (opcode.addr_mode) {
		case ADDRMODE_ZP: {
			/* Zero Page. Address is given, no high byte. */
			address = mapper_read(pThis->mapper, opaddress + 2);
			break;
		};
		
		case ADDRMODE_REL: {
			/* Relative. */
			address = mapper_read(pThis->mapper, opaddress + 2);
			if (address < 0x80) {
				address += pThis->pc;
			}
			else {
				address += pThis->pc - 0xFF;
			}
			break;
		};

		case ADDRMODE_IMP: {
			/* Implied. Ignore. */
			break;
		};

		case ADDRMODE_ABS: {
			/* Absolute. Use the next two bytes as an address. */
			address = mapper_read16(pThis->mapper, opaddress + 2);
			break;
		};

		case ADDRMODE_ACC: {
			/* Accumulator. */
			address = pThis->a;
			break;
		};

		case ADDRMODE_IMM: {
			/* Immediate. */
			address = pThis->pc;
			break;
		};

		case ADDRMODE_ZPX: {
			/* Zero Page Index. Use address from opcode then add X register. */
			address = (mapper_read(pThis->mapper, opaddress + 2) + pThis->x) & 0xFF;
			break;
		};
		case ADDRMODE_ZPY: {
			/* Zero Page Index. Use address from opcode then add Y register. */
			address = (mapper_read(pThis->mapper, opaddress + 2) + pThis->y) & 0xFF;
			break;
		};

		case ADDRMODE_ABSX: {
			/* Absolute Index. Same as Zero Page but with the high byte. */
			address = mapper_read16(pThis->mapper, opaddress + 2);
			if ((address & 0xFF00) != ((address + pThis->x) & 0xFF00)) {
				extra_cycle = 1;
			}
			address += pThis->x;
			break;
		};
		
		case ADDRMODE_ABSY: {
			/* Absolute Index. Same as Zero Page but with the high byte. */
			address = mapper_read16(pThis->mapper, opaddress + 2);
			if ((address & 0xFF00) != ((address + pThis->y) & 0xFF00)) {
				extra_cycle = 1;
			}
			address += pThis->y;
			break;
		};

		case ADDRMODE_PREIDXIND: {
			/* Pre-indexed Indirect. Find the 16-bit address starting
			   at the given location in Zero Page plus the X register.
			   Value is the contents of that address. */
			address = mapper_read(pThis->mapper, opaddress + 2);
			if ((address & 0xFF00) != ((address + pThis->x) & 0xFF00)) {
				extra_cycle = 1;
			}
			address += pThis->x;
			address &= 0xFF;
			address = mapper_read16(pThis->mapper, address);
			break;
		};

		case ADDRMODE_POSTIDXIND: {
			/* Post-indexed Indirect. Find the 16-bit address contained
			   in the given location in Zero Page. Add to that address the contents
			   of the Y register. Fetch value stored at that address. */
			address = mapper_read16(pThis->mapper, mapper_read(pThis->mapper, opaddress + 2));
			if ((address & 0xFF00) != ((address + pThis->y) & 0xFF00)) {
				extra_cycle = 1;
			}
			address += pThis->y;
			break;
		};

		case ADDRMODE_INDABS: {
			/* Indirect Absolute. Value of 16-bit address is the sought for 16-bit
			   address. */
			
			address = mapper_read16(pThis->mapper, opaddress + 2);
			address = mapper_read16(pThis->mapper, address);
			break;
		};
	}
	
	address &= 0xFFFF;
	
	printf("$%04X: %s $%04X (= $%2X).\n", opaddress + 1, instnames[opcode.inst], address, mapper_read(pThis->mapper, address));
	
	switch(opcode.inst) {
		case INST_ADC: {
			int t;
			t = pThis->a + mapper_read(pThis->mapper, address) + (pThis->p & 0x1);
			
			/* OVERFLOW */
			if (pThis->a <= 0x7F && t > 0x7F) {
				pThis->p |= FLAG_OVERFLOW;
			}
			else {
				pThis->p = pThis->p & ~FLAG_OVERFLOW;
			}
			/* OVERFLOW */
			pThis->p = (pThis->p & ~FLAG_CARRY) | (t > 0xFF ? 1 : 0);
			pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((t >> 7) & 0x1) << 7;
			pThis->p = (pThis->p & ~FLAG_ZERO) | (t ? 0 : 1) << 1;
			pThis->a = t & 0xFF;
			
			cycles += extra_cycle;
			break;
		}

		case INST_AND: {
			pThis->a = (pThis->a & mapper_read(pThis->mapper, address)) & 0xFF;
			pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((pThis->a >> 7) & 0x1) << 7;
			pThis->p = (pThis->p & ~FLAG_ZERO) | (pThis->a ? 0 : 1) << 1;

			if (opcode.addr_mode == ADDRMODE_POSTIDXIND) {
				cycles += extra_cycle;
			}
			break;
		}

		case INST_ASL: {
			if (opcode.addr_mode == ADDRMODE_ACC) {
				pThis->p = (pThis->p & ~FLAG_CARRY) | ((pThis->a >> 7) & 0x1);
				pThis->a = (pThis->a << 1) & 0xFF;
				pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((pThis->a >> 7) & 0x1);
				pThis->p = (pThis->p & ~FLAG_ZERO) | (pThis->a ? 0 : 1) << 1;
			}
			else {
				int t = mapper_read(pThis->mapper, address);
				pThis->p = (pThis->p & ~FLAG_CARRY) | ((t >> 7) & 0x1);
				t = (t << 1) & 0xFF;
				pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((t >> 7) & 0x1);
				pThis->p = (pThis->p & ~FLAG_ZERO) | (t ? 0 : 1) << 1;
				mapper_write(pThis->mapper, address, t);
			}
			break;
		}

		case INST_BCC: {
			if (!(pThis->p & 0x1)) {
				if ((opaddress & 0xFF00) != (address & 0xFF00)) {
					cycles += 2;
				}
				else {
					cycles += 1;
				}
				pThis->pc = address;
			}
			break;
		}

		case INST_BCS: {
			if (pThis->p & 0x1) {
				/* Yet another mystery, investigate */
				if ((opaddress & 0xFF00) != (address & 0xFF00)) {
					cycles += 2;
				}
				else {
					cycles += 1;
				}
				pThis->pc = address;
			}
			break;
		}

		case INST_BEQ: {
			if ((pThis->p >> 1) & 0x1) {
				if ((opaddress & 0xFF00) != (address & 0xFF00)) {
					cycles += 2;
				}
				else {
					cycles += 1;
				}
				pThis->pc = address;
			}
			break;
		}

		case INST_BIT: {
			int t = mapper_read(pThis->mapper, address);
			pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((t >> 7) & 0x1);
			pThis->p = (pThis->p & ~FLAG_OVERFLOW) | ((t >> 6) & 0x1);
			t &= pThis->a;
			pThis->p = (pThis->p & ~FLAG_ZERO) | (t ? 0 : 1) << 1;
			break;
		}

		case INST_BMI: {
			if ((pThis->p >> 7) & 0x1) {
				cycles++;
				pThis->pc = address;
			}
			break;
		}

		case INST_BNE: {
			if (!((pThis->p >> 1) & 0x1)) {
				if ((opaddress & 0xFF00) != (address & 0xFF00)) {
					cycles += 2;
				}
				else {
					cycles += 1;
				}
				pThis->pc = address;
			}
			break;
		}

		case INST_BPL: {
			if (!((pThis->p >> 7) & 0x1)) {
				if ((opaddress & 0xFF00) != (address & 0xFF00)) {
					cycles += 2;
				}
				else {
					cycles += 1;
				}
				pThis->pc = address;
			}
			break;
		}

		case INST_BRK: {
			pThis->pc += 2;
			cpu_push(pThis, (pThis->pc >> 8) & 0xFF);
			cpu_push(pThis, pThis->pc & 0xFF);
			
			pThis->p |= FLAG_BREAK;
			cpu_push(pThis, pThis->p);
			
			pThis->p |= FLAG_INTERRUPT;
			pThis->pc = mapper_read16(pThis->mapper, 0xFFFE);
			pThis->pc--;
			break;
		}

		case INST_BVC: {
			if (!((pThis->p >> 6) & 0x1)) {
				if ((opaddress & 0xFF00) != (address & 0xFF00)) {
					cycles += 2;
				}
				else {
					cycles += 1;
				}
				pThis->pc = address;
			}
			break;
		}

		case INST_BVS: {
			if ((pThis->p >> 6) & 0x1) {
				if ((opaddress & 0xFF00) != (address & 0xFF00)) {
					cycles += 2;
				}
				else {
					cycles += 1;
				}
				pThis->pc = address;
			}
			break;
		}

		case INST_CLC: {
			pThis->p = (pThis->p & ~FLAG_CARRY);
			break;
		}

		case INST_CLD: {
			pThis->p = (pThis->p & ~FLAG_DECIMAL);
			break;
		}

		case INST_CLI: {
			pThis->p = (pThis->p & ~FLAG_INTERRUPT);
			break;
		}

		case INST_CLV: {
			pThis->p = (pThis->p & ~FLAG_OVERFLOW);
			break;
		}

		case INST_CMP: {
			int t;
			t = pThis->a - mapper_read(pThis->mapper, address);
			pThis->p = (pThis->p & ~FLAG_CARRY) | (t >= 0x0 ? 1 : 0);
			pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((t >> 7) & 0x1) << 7;
			pThis->p = (pThis->p & ~FLAG_ZERO) | (t ? 0 : 1) << 1;
			break;
		}

		case INST_CPX: {
			int t;
			t = pThis->x - mapper_read(pThis->mapper, address);
			pThis->p = (pThis->p & ~FLAG_CARRY) | (t >= 0x0 ? 1 : 0);
			pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((t >> 7) & 0x1) << 7;
			pThis->p = (pThis->p & ~FLAG_ZERO) | (t ? 0 : 1) << 1;
			break;
		}

		case INST_CPY: {
			int t;
			t = pThis->y - mapper_read(pThis->mapper, address);
			pThis->p = (pThis->p & ~FLAG_CARRY) | (t >= 0x0 ? 1 : 0);
			pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((t >> 7) & 0x1) << 7;
			pThis->p = (pThis->p & ~FLAG_ZERO) | (t ? 0 : 1) << 1;
			break;
		}

		case INST_DEC: {
			int t;
			t = (mapper_read(pThis->mapper, address) - 1) & 0xFF;
			pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((pThis->x >> 7) & 0x1) << 7;
			pThis->p = (pThis->p & ~FLAG_ZERO) | (pThis->x ? 0 : 1) << 1;
			mapper_write(pThis->mapper, address, t);
			break;
		}

		case INST_DEX: {
			pThis->x = (pThis->x - 1) & 0xFF;
			pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((pThis->x >> 7) & 0x1) << 7;
			pThis->p = (pThis->p & ~FLAG_ZERO) | (pThis->x ? 0 : 1) << 1;
			break;
		}

		case INST_DEY: {
			pThis->y = (pThis->y - 1) & 0xFF;
			pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((pThis->y >> 7) & 0x1) << 7;
			pThis->p = (pThis->p & ~FLAG_ZERO) | (pThis->y ? 0 : 1) << 1;
			break;
		}

		case INST_EOR: {
			pThis->a = (pThis->a ^ mapper_read(pThis->mapper, address)) & 0xFF;
			pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((pThis->a >> 7) & 0x1) << 7;
			pThis->p = (pThis->p & ~FLAG_ZERO) | (pThis->a ? 0 : 1) << 1;
			cycles += extra_cycle;
			break;
		}

		case INST_INC: {
			int t;
			t = (mapper_read(pThis->mapper, address) + 1) & 0xFF;
			pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((pThis->x >> 7) & 0x1) << 7;
			pThis->p = (pThis->p & ~FLAG_ZERO) | (pThis->x ? 0 : 1) << 1;
			mapper_write(pThis->mapper, address, t);
			break;
		}

		case INST_INX: {
			pThis->x = (pThis->x + 1) & 0xFF;
			pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((pThis->x >> 7) & 0x1) << 7;
			pThis->p = (pThis->p & ~FLAG_ZERO) | (pThis->x ? 0 : 1) << 1;
			break;
		}

		case INST_INY: {
			pThis->y = (pThis->y + 1) & 0xFF;
			pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((pThis->y >> 7) & 0x1) << 7;
			pThis->p = (pThis->p & ~FLAG_ZERO) | (pThis->y ? 0 : 1) << 1;
			break;
		}

		case INST_JMP: {
			pThis->pc = address - 1;
			break;
		}

		case INST_JSR: {
			cpu_push(pThis, (pThis->pc >> 8) & 0xFF);
			cpu_push(pThis, pThis->pc & 0xFF);
			pThis->pc = address - 1;
			break;
		}

		case INST_LDA: {
			pThis->a = mapper_read(pThis->mapper, address);
			pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((pThis->a >> 7) & 0x1) << 7;
			pThis->p = (pThis->p & ~FLAG_ZERO) | (pThis->a ? 0 : 1) << 1;
			cycles += extra_cycle;
			break;
		}

		case INST_LDX: {
			pThis->x = mapper_read(pThis->mapper, address);
			pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((pThis->x >> 7) & 0x1) << 7;
			pThis->p = (pThis->p & ~FLAG_ZERO) | (pThis->x ? 0 : 1) << 1;
			cycles += extra_cycle;
			break;
		}

		case INST_LDY: {
			pThis->y = mapper_read(pThis->mapper, address);
			pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((pThis->y >> 7) & 0x1) << 7;
			pThis->p = (pThis->p & ~FLAG_ZERO) | (pThis->y ? 0 : 1) << 1;
			cycles += extra_cycle;
			break;
		}

		case INST_LSR: {
			if (opcode.addr_mode == ADDRMODE_ACC) {
				pThis->p = (pThis->p & ~FLAG_CARRY) | ((pThis->a >> 7) & 0x1);
				pThis->a >>= 1;
				pThis->p = (pThis->p & ~FLAG_ZERO) | (pThis->a ? 0 : 1) << 1;
			}
			else {
				int t = mapper_read(pThis->mapper, address);
				pThis->p = (pThis->p & ~FLAG_CARRY) | ((t >> 7) & 0x1);
				t >>= 1;
				pThis->p = (pThis->p & ~FLAG_ZERO) | (t ? 0 : 1) << 1;
				mapper_write(pThis->mapper, address, t);
			}
			pThis->p = (pThis->p & ~FLAG_NEGATIVE);
			break;
		}

		case INST_NOP: {
			/* No OPeration */
			break;
		}

		case INST_ORA: {
			pThis->a = (pThis->a | mapper_read(pThis->mapper, address)) & 0xFF;
			pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((pThis->a >> 7) & 0x1) << 7;
			pThis->p = (pThis->p & ~FLAG_ZERO) | (pThis->a ? 0 : 1) << 1;

			if (opcode.addr_mode == ADDRMODE_POSTIDXIND) {
				cycles += extra_cycle;
			}
			break;
		}

		case INST_PHA: {
			cpu_push(pThis, pThis->a);
			break;
		}

		case INST_PHP: {
			pThis->p |= FLAG_BREAK;
			cpu_push(pThis, pThis->p);
			break;
		}

		case INST_PLA: {
			pThis->a = cpu_pop(pThis);
			pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((pThis->a >> 7) & 0x1) << 7;
			pThis->p = (pThis->p & ~FLAG_ZERO) | (pThis->a ? 0 : 1) << 1;
			break;
		}

		case INST_PLP: {
			pThis->p = cpu_pop(pThis) | FLAG_UNUSED;
			break;
		}

		case INST_ROL: {
			int val;
			int t;
			
			if (opcode.addr_mode == ADDRMODE_ACC) {
				val = pThis->a;
			}
			else {
				val = mapper_read(pThis->mapper, address);
			}
			
			t = (val >> 7) & 0x1;
			val <<= 1;
			val |= (pThis->p & 0x1);
			pThis->p = (pThis->p & ~FLAG_CARRY) | (t & 0x1);
			pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((val >> 7) & 0x1) << 7;
			pThis->p = (pThis->p & ~FLAG_ZERO) | (val ? 0 : 1) << 1;

			if (opcode.addr_mode == ADDRMODE_ACC) {
				pThis->a = val;
			}
			else {
				mapper_write(pThis->mapper, address, val);
			}
			break;
		}

		case INST_ROR: {
			int val;
			int t;
			
			if (opcode.addr_mode == ADDRMODE_ACC) {
				val = pThis->a;
			}
			else {
				val = mapper_read(pThis->mapper, address);
			}
			
			t = val & 0x1;
			val >>= 1;
			val |= (pThis->p & 0x1) ? 0x80 : 0x00;
			pThis->p = (pThis->p & ~FLAG_CARRY) | (t & 0x1);
			pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((val >> 7) & 0x1) << 7;
			pThis->p = (pThis->p & ~FLAG_ZERO) | (val ? 0 : 1) << 1;

			if (opcode.addr_mode == ADDRMODE_ACC) {
				pThis->a = val;
			}
			else {
				mapper_write(pThis->mapper, address, val);
			}
			break;
		}

		case INST_RTI: {
			pThis->p = cpu_pop(pThis) | FLAG_UNUSED;
			
			pThis->pc = cpu_pop(pThis);
			pThis->pc += cpu_pop(pThis) << 8;
			if (pThis->pc == 0xFFFF) {
				return 0;
			}
			pThis->pc--;
			break;
		}

		case INST_RTS: {
			pThis->pc = cpu_pop(pThis);
			pThis->pc += cpu_pop(pThis) << 8;
			if (pThis->pc == 0xFFFF) {
				return 0; /* W00t? End of mem, of course, but... */
			}
			break;
		}

		case INST_SBC: {
			int t;
			t = pThis->a - mapper_read(pThis->mapper, address) - (1 - (pThis->p & 0x1));
			
			/* OVERFLOW */
			if (pThis->a > 0x7F && t <= 0x7F) {
				pThis->p |= FLAG_OVERFLOW;
			}
			else {
				pThis->p = pThis->p & ~FLAG_OVERFLOW;
			}
			/* OVERFLOW */
			pThis->p = (pThis->p & ~FLAG_CARRY) | (t < 0x0 ? 0 : 1);
			pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((t >> 7) & 0x1) << 7;
			pThis->p = (pThis->p & ~FLAG_ZERO) | (t ? 0 : 1) << 1;
			pThis->a = t & 0xFF;
			
			if (opcode.addr_mode == ADDRMODE_POSTIDXIND) {/* Why? */
				cycles += extra_cycle;
			}
			break;
		}

		case INST_SEC: {
			pThis->p |= FLAG_CARRY;
			break;
		}

		case INST_SED: {
			pThis->p |= FLAG_DECIMAL;
			break;
		}

		case INST_SEI: {
			pThis->p |= FLAG_INTERRUPT;
			break;
		}

		case INST_STA: {
			mapper_write(pThis->mapper, address, pThis->a);
			break;
		}

		case INST_STX: {
			mapper_write(pThis->mapper, address, pThis->x);
			break;
		}

		case INST_STY: {
			mapper_write(pThis->mapper, address, pThis->y);
			break;
		}

		case INST_TAX: {
			pThis->x = pThis->a;
			pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((pThis->x >> 7) & 0x1) << 7;
			pThis->p = (pThis->p & ~FLAG_ZERO) | (pThis->x ? 0 : 1) << 1;
			break;
		}

		case INST_TAY: {
			pThis->y = pThis->a;
			pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((pThis->y >> 7) & 0x1) << 7;
			pThis->p = (pThis->p & ~FLAG_ZERO) | (pThis->y ? 0 : 1) << 1;
			break;
		}

		case INST_TSX: {
			pThis->x = pThis->sp - 0x0100;
			pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((pThis->x >> 7) & 0x1) << 7;
			pThis->p = (pThis->p & ~FLAG_ZERO) | (pThis->x ? 0 : 1) << 1;
			break;
		}

		case INST_TXA: {
			pThis->a = pThis->x;
			pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((pThis->a >> 7) & 0x1) << 7;
			pThis->p = (pThis->p & ~FLAG_ZERO) | (pThis->a ? 0 : 1) << 1;
			break;
		}

		case INST_TXS: {
			pThis->sp = pThis->x + 0x0100;
			cpu_stackwrap(pThis);
			break;
		}

		case INST_TYA: {
			pThis->a = pThis->y;
			pThis->p = (pThis->p & ~FLAG_NEGATIVE) | ((pThis->a >> 7) & 0x1) << 7;
			pThis->p = (pThis->p & ~FLAG_ZERO) | (pThis->a ? 0 : 1) << 1;
			break;
		}
	}

	/* DEBUG OUTPUT */
	printf("DBG: PC=$%04X A=$%02X X=$%02X Y=$%02X SP=$%04X", pThis->pc, pThis->a, pThis->x, pThis->y, pThis->sp);
	printf(" P=%d%d%d%d%d%d%d%d\n", (pThis->p >> 7) & 0x1, (pThis->p >> 6) & 0x1,
										(pThis->p >> 5) & 0x1, (pThis->p >> 4) & 0x1,
										(pThis->p >> 3) & 0x1, (pThis->p >> 2) & 0x1,
										(pThis->p >> 1) & 0x1, pThis->p & 0x1);
	/* DEBUG OUTPUT */
	return cycles;
}

void cpu_dump_instructiontable(cpu6502_t* cpu)
{
	int x, y;
	cpu6502_t* pThis = cpu;
	
	assert(pThis);
	
	printf("   ");
	for (x = 0x0; x < 0x10; x++) {
		printf("%c  %X  ", 179, x);
	}
	printf("\n");

	for (y = 0x0; y < 0x10; y++) {
		printf("%c%c%c", 196, 196, 196);
		for (x = 0x0; x < 0x10; x++) {
			printf("%c%c%c%c%c%c", 197, 196, 196, 196, 196, 196);
		}
		printf("\n");
		
		printf(" %X ", y);
		for (x = 0x0; x < 0x10; x++) {
			int op = ((y << 4) | x) & 0xFF;
			int inst = pThis->opcodes[op].inst;
			
			if (inst == 0xFF) {
				printf("%c     ", 179);
			}
			else {
				printf("%c %s ", 179, instnames[inst]);
			}
		}
		printf("\n");
	}
}

int cpu_get_pc(cpu6502_t* cpu)
{
	cpu6502_t* pThis = cpu;
	
	assert(pThis);
	
	return pThis->pc + 1;
}

int cpu_get_a(cpu6502_t* cpu)
{
	cpu6502_t* pThis = cpu;
	
	assert(pThis);
	
	return pThis->a;
}

int cpu_get_x(cpu6502_t* cpu)
{
	cpu6502_t* pThis = cpu;
	
	assert(pThis);
	
	return pThis->x;
}

int cpu_get_y(cpu6502_t* cpu)
{
	cpu6502_t* pThis = cpu;
	
	assert(pThis);
	
	return pThis->y;
}

opcode_t cpu_get_op(cpu6502_t* cpu, int hex)
{
	cpu6502_t* pThis = cpu;
	
	assert(pThis);
	
	return pThis->opcodes[mapper_read(pThis->mapper, hex)];
}

/* Private funcs */
void cpu_push(cpu6502_t* cpu, int value)
{
	cpu6502_t* pThis = cpu;
	
	assert(pThis);

	mapper_write(pThis->mapper, pThis->sp, value);
	pThis->sp--;
	cpu_stackwrap(pThis);
}

int cpu_pop(cpu6502_t* cpu)
{
	cpu6502_t* pThis = cpu;
	
	assert(pThis);

	pThis->sp++;
	cpu_stackwrap(pThis);
	
	return mapper_read(pThis->mapper, pThis->sp);
}

void cpu_stackwrap(cpu6502_t* cpu)
{
	cpu6502_t* pThis = cpu;
	
	assert(pThis);

	pThis->sp = 0x0100 | (pThis->sp & 0xFF);
}

void cpu_fill_opcode(cpu6502_t* cpu, int inst, int op, int addr_mode, int size, int cycles)
{
	cpu6502_t* pThis = cpu;
	
	assert(pThis);

	pThis->opcodes[op].inst = inst & 0xFF;
	pThis->opcodes[op].addr_mode = addr_mode & 0xFF;
	pThis->opcodes[op].size = size & 0xFF;
	pThis->opcodes[op].cycles = cycles & 0xFF;
	
	pThis->opcodes[op].inst_name = instnames[inst];
}

void cpu_create_opcodes(cpu6502_t* cpu)
{
	int t;
	cpu6502_t* pThis = cpu;

	assert(pThis);
	
	for (t = 0; t < 256; t++) {
		pThis->opcodes[t].inst = 0xFF;
		pThis->opcodes[t].addr_mode = 0x0;
		pThis->opcodes[t].size = 0x0;
		pThis->opcodes[t].cycles = 0x0;
		pThis->opcodes[t].inst_name = NULL;
	}
	
	/* ADC */
	cpu_fill_opcode(pThis, INST_ADC, 0x69, ADDRMODE_IMM, 2, 2);
	cpu_fill_opcode(pThis, INST_ADC, 0x65, ADDRMODE_ZP, 2, 3);
	cpu_fill_opcode(pThis, INST_ADC, 0x75, ADDRMODE_ZPX, 2, 4);
	cpu_fill_opcode(pThis, INST_ADC, 0x6D, ADDRMODE_ABS, 3, 4);
	cpu_fill_opcode(pThis, INST_ADC, 0x7D, ADDRMODE_ABSX, 3, 4);
	cpu_fill_opcode(pThis, INST_ADC, 0x79, ADDRMODE_ABSY, 3, 4);
	cpu_fill_opcode(pThis, INST_ADC, 0x61, ADDRMODE_PREIDXIND, 2, 6);
	cpu_fill_opcode(pThis, INST_ADC, 0x71, ADDRMODE_POSTIDXIND, 2, 5);

	/* AND */
	cpu_fill_opcode(pThis, INST_AND, 0x29, ADDRMODE_IMM, 2, 2);
	cpu_fill_opcode(pThis, INST_AND, 0x25, ADDRMODE_ZP, 2, 3);
	cpu_fill_opcode(pThis, INST_AND, 0x35, ADDRMODE_ZPX, 2, 4);
	cpu_fill_opcode(pThis, INST_AND, 0x2D, ADDRMODE_ABS, 3, 4);
	cpu_fill_opcode(pThis, INST_AND, 0x3D, ADDRMODE_ABSX, 3, 4);
	cpu_fill_opcode(pThis, INST_AND, 0x39, ADDRMODE_ABSY, 3, 4);
	cpu_fill_opcode(pThis, INST_AND, 0x21, ADDRMODE_PREIDXIND, 2, 6);
	cpu_fill_opcode(pThis, INST_AND, 0x31, ADDRMODE_POSTIDXIND, 2, 5);
	
	/* ASL */
	cpu_fill_opcode(pThis, INST_ASL, 0x0A, ADDRMODE_ACC, 1, 2);
	cpu_fill_opcode(pThis, INST_ASL, 0x06, ADDRMODE_ZP, 2, 5);
	cpu_fill_opcode(pThis, INST_ASL, 0x16, ADDRMODE_ZPX, 2, 6);
	cpu_fill_opcode(pThis, INST_ASL, 0x0E, ADDRMODE_ABS, 3, 6);
	cpu_fill_opcode(pThis, INST_ASL, 0x1E, ADDRMODE_ABSX, 3, 7);
	
	/* BCC */
	cpu_fill_opcode(pThis, INST_BCC, 0x90, ADDRMODE_REL, 2, 2);
	
	/* BCS */
	cpu_fill_opcode(pThis, INST_BCS, 0xB0, ADDRMODE_REL, 2, 2);
	
	/* BEQ */
	cpu_fill_opcode(pThis, INST_BEQ, 0xF0, ADDRMODE_REL, 2, 2);
	
	/* BIT */
	cpu_fill_opcode(pThis, INST_BIT, 0x24, ADDRMODE_ZP, 2, 3);
	cpu_fill_opcode(pThis, INST_BIT, 0x2C, ADDRMODE_ABS, 3, 4);
	
	/* BMI */
	cpu_fill_opcode(pThis, INST_BMI, 0x30, ADDRMODE_REL, 2, 2);
	
	/* BNE */
	cpu_fill_opcode(pThis, INST_BNE, 0xD0, ADDRMODE_REL, 2, 2);
	
	/* BPL */
	cpu_fill_opcode(pThis, INST_BPL, 0x10, ADDRMODE_REL, 2, 2);
	
	/* BRK */
	cpu_fill_opcode(pThis, INST_BRK, 0x00, ADDRMODE_IMP, 1, 7);
	
	/* BVC */
	cpu_fill_opcode(pThis, INST_BVC, 0x50, ADDRMODE_REL, 2, 2);
	
	/* BVS */
	cpu_fill_opcode(pThis, INST_BVS, 0x70, ADDRMODE_REL, 2, 2);
	
	/* CLC */
	cpu_fill_opcode(pThis, INST_CLC, 0x18, ADDRMODE_IMP, 1, 2);
	
	/* CLD */
	cpu_fill_opcode(pThis, INST_CLD, 0xD8, ADDRMODE_IMP, 1, 2);
	
	/* CLI */
	cpu_fill_opcode(pThis, INST_CLI, 0x58, ADDRMODE_IMP, 1, 2);
	
	/* CLV */
	cpu_fill_opcode(pThis, INST_CLV, 0xB8, ADDRMODE_IMP, 1, 2);
	
	/* CMP */
	cpu_fill_opcode(pThis, INST_CMP, 0xC9, ADDRMODE_IMM, 2, 2);
	cpu_fill_opcode(pThis, INST_CMP, 0xC5, ADDRMODE_ZP, 2, 3);
	cpu_fill_opcode(pThis, INST_CMP, 0xD5, ADDRMODE_ZPX, 2, 4);
	cpu_fill_opcode(pThis, INST_CMP, 0xCD, ADDRMODE_ABS, 3, 4);
	cpu_fill_opcode(pThis, INST_CMP, 0xDD, ADDRMODE_ABSX, 3, 4);
	cpu_fill_opcode(pThis, INST_CMP, 0xD9, ADDRMODE_ABSY, 3, 4);
	cpu_fill_opcode(pThis, INST_CMP, 0xC1, ADDRMODE_PREIDXIND, 2, 6);
	cpu_fill_opcode(pThis, INST_CMP, 0xD1, ADDRMODE_POSTIDXIND, 2, 5);
	
	/* CPX */
	cpu_fill_opcode(pThis, INST_CPX, 0xE0, ADDRMODE_IMM, 2, 2);
	cpu_fill_opcode(pThis, INST_CPX, 0xE4, ADDRMODE_ZP, 2, 3);
	cpu_fill_opcode(pThis, INST_CPX, 0xEC, ADDRMODE_ABS, 3, 4);

	/* CPY */
	cpu_fill_opcode(pThis, INST_CPY, 0xC0, ADDRMODE_IMM, 2, 2);
	cpu_fill_opcode(pThis, INST_CPY, 0xC4, ADDRMODE_ZP, 2, 3);
	cpu_fill_opcode(pThis, INST_CPY, 0xCC, ADDRMODE_ABS, 3, 4);
	
	/* DEC */
	cpu_fill_opcode(pThis, INST_DEC, 0xC6, ADDRMODE_ZP, 2, 5);
	cpu_fill_opcode(pThis, INST_DEC, 0xD6, ADDRMODE_ZPX, 2, 6);
	cpu_fill_opcode(pThis, INST_DEC, 0xCE, ADDRMODE_ABS, 3, 6);
	cpu_fill_opcode(pThis, INST_DEC, 0xDE, ADDRMODE_ABSX, 3, 7);

	/* DEX */
	cpu_fill_opcode(pThis, INST_DEX, 0xCA, ADDRMODE_IMP, 1, 2);

	/* DEY */
	cpu_fill_opcode(pThis, INST_DEY, 0x88, ADDRMODE_IMP, 1, 2);
	
	/* EOR */
	cpu_fill_opcode(pThis, INST_EOR, 0x49, ADDRMODE_IMM, 2, 2);
	cpu_fill_opcode(pThis, INST_EOR, 0x45, ADDRMODE_ZP, 2, 3);
	cpu_fill_opcode(pThis, INST_EOR, 0x55, ADDRMODE_ZPX, 2, 4);
	cpu_fill_opcode(pThis, INST_EOR, 0x4D, ADDRMODE_ABS, 3, 4);
	cpu_fill_opcode(pThis, INST_EOR, 0x5D, ADDRMODE_ABSX, 3, 4);
	cpu_fill_opcode(pThis, INST_EOR, 0x59, ADDRMODE_ABSY, 3, 4);
	cpu_fill_opcode(pThis, INST_EOR, 0x41, ADDRMODE_PREIDXIND, 2, 6);
	cpu_fill_opcode(pThis, INST_EOR, 0x51, ADDRMODE_POSTIDXIND, 2, 5);
	
	/* INC */
	cpu_fill_opcode(pThis, INST_INC, 0xE6, ADDRMODE_ZP, 2, 5);
	cpu_fill_opcode(pThis, INST_INC, 0xF6, ADDRMODE_ZPX, 2, 6);
	cpu_fill_opcode(pThis, INST_INC, 0xEE, ADDRMODE_ABS, 3, 6);
	cpu_fill_opcode(pThis, INST_INC, 0xFE, ADDRMODE_ABSX, 3, 7);

	/* INX */
	cpu_fill_opcode(pThis, INST_INX, 0xE8, ADDRMODE_IMP, 1, 2);
	
	/* INY */
	cpu_fill_opcode(pThis, INST_INY, 0xC8, ADDRMODE_IMP, 1, 2);
	
	/* JMP */
	cpu_fill_opcode(pThis, INST_JMP, 0x4C, ADDRMODE_ABS, 3, 3);
	cpu_fill_opcode(pThis, INST_JMP, 0x6C, ADDRMODE_INDABS, 3, 5);
	
	/* JSR */
	cpu_fill_opcode(pThis, INST_JSR, 0x20, ADDRMODE_ABS, 3, 6);
	
	/* LDA */
	cpu_fill_opcode(pThis, INST_LDA, 0xA9, ADDRMODE_IMM, 2, 2);
	cpu_fill_opcode(pThis, INST_LDA, 0xA5, ADDRMODE_ZP, 2, 3);
	cpu_fill_opcode(pThis, INST_LDA, 0xB5, ADDRMODE_ZPX, 2, 4);
	cpu_fill_opcode(pThis, INST_LDA, 0xAD, ADDRMODE_ABS, 3, 4);
	cpu_fill_opcode(pThis, INST_LDA, 0xBD, ADDRMODE_ABSX, 3, 4);
	cpu_fill_opcode(pThis, INST_LDA, 0xB9, ADDRMODE_ABSY, 3, 4);
	cpu_fill_opcode(pThis, INST_LDA, 0xA1, ADDRMODE_PREIDXIND, 2, 6);
	cpu_fill_opcode(pThis, INST_LDA, 0xB1, ADDRMODE_POSTIDXIND, 2, 5);
	
	/* LDX */
	cpu_fill_opcode(pThis, INST_LDX, 0xA2, ADDRMODE_IMM, 2, 2);
	cpu_fill_opcode(pThis, INST_LDX, 0xA6, ADDRMODE_ZP, 2, 3);
	cpu_fill_opcode(pThis, INST_LDX, 0xB6, ADDRMODE_ZPY, 2, 4);
	cpu_fill_opcode(pThis, INST_LDX, 0xAE, ADDRMODE_ABS, 3, 4);
	cpu_fill_opcode(pThis, INST_LDX, 0xBE, ADDRMODE_ABSY, 3, 4);
	
	/* LDY */
	cpu_fill_opcode(pThis, INST_LDY, 0xA0, ADDRMODE_IMM, 2, 2);
	cpu_fill_opcode(pThis, INST_LDY, 0xA4, ADDRMODE_ZP, 2, 3);
	cpu_fill_opcode(pThis, INST_LDY, 0xB4, ADDRMODE_ZPY, 2, 4);
	cpu_fill_opcode(pThis, INST_LDY, 0xAC, ADDRMODE_ABS, 3, 4);
	cpu_fill_opcode(pThis, INST_LDY, 0xBC, ADDRMODE_ABSY, 3, 4);
	
	/* LSR */
	cpu_fill_opcode(pThis, INST_LSR, 0x4A, ADDRMODE_ACC, 1, 2);
	cpu_fill_opcode(pThis, INST_LSR, 0x46, ADDRMODE_ZP, 2, 5);
	cpu_fill_opcode(pThis, INST_LSR, 0x56, ADDRMODE_ZPX, 2, 6);
	cpu_fill_opcode(pThis, INST_LSR, 0x4E, ADDRMODE_ABS, 3, 6);
	cpu_fill_opcode(pThis, INST_LSR, 0x5E, ADDRMODE_ABSX, 3, 7);
	
	/* NOP */
	cpu_fill_opcode(pThis, INST_NOP, 0xEA, ADDRMODE_IMP, 1, 2);
	
	/* ORA */
	cpu_fill_opcode(pThis, INST_ORA, 0x09, ADDRMODE_IMM, 2, 2);
	cpu_fill_opcode(pThis, INST_ORA, 0x05, ADDRMODE_ZP, 2, 3);
	cpu_fill_opcode(pThis, INST_ORA, 0x15, ADDRMODE_ZPX, 2, 4);
	cpu_fill_opcode(pThis, INST_ORA, 0x0D, ADDRMODE_ABS, 3, 4);
	cpu_fill_opcode(pThis, INST_ORA, 0x1D, ADDRMODE_ABSX, 3, 4);
	cpu_fill_opcode(pThis, INST_ORA, 0x19, ADDRMODE_ABSY, 3, 4);
	cpu_fill_opcode(pThis, INST_ORA, 0x01, ADDRMODE_PREIDXIND, 2, 6);
	cpu_fill_opcode(pThis, INST_ORA, 0x11, ADDRMODE_POSTIDXIND, 2, 5);
	
	/* PHA */
	cpu_fill_opcode(pThis, INST_PHA, 0x48, ADDRMODE_IMP, 1, 3);
	
	/* PHP */
	cpu_fill_opcode(pThis, INST_PHP, 0x08, ADDRMODE_IMP, 1, 3);
	
	/* PLA */
	cpu_fill_opcode(pThis, INST_PLA, 0x68, ADDRMODE_IMP, 1, 4);
	
	/* PLP */
	cpu_fill_opcode(pThis, INST_PLP, 0x28, ADDRMODE_IMP, 1, 4);
	
	/* ROL */
	cpu_fill_opcode(pThis, INST_ROL, 0x2A, ADDRMODE_ACC, 1, 2);
	cpu_fill_opcode(pThis, INST_ROL, 0x26, ADDRMODE_ZP, 2, 5);
	cpu_fill_opcode(pThis, INST_ROL, 0x36, ADDRMODE_ZPX, 2, 6);
	cpu_fill_opcode(pThis, INST_ROL, 0x2E, ADDRMODE_ABS, 3, 6);
	cpu_fill_opcode(pThis, INST_ROL, 0x3E, ADDRMODE_ABSX, 3, 7);
	
	/* ROR */
	cpu_fill_opcode(pThis, INST_ROR, 0x6A, ADDRMODE_ACC, 1, 2);
	cpu_fill_opcode(pThis, INST_ROR, 0x66, ADDRMODE_ZP, 2, 5);
	cpu_fill_opcode(pThis, INST_ROR, 0x76, ADDRMODE_ZPX, 2, 6);
	cpu_fill_opcode(pThis, INST_ROR, 0x6E, ADDRMODE_ABS, 3, 6);
	cpu_fill_opcode(pThis, INST_ROR, 0x7E, ADDRMODE_ABSX, 3, 7);
	
	/* RTI */
	cpu_fill_opcode(pThis, INST_RTI, 0x40, ADDRMODE_IMP, 1, 6);
	
	/* RTS */
	cpu_fill_opcode(pThis, INST_RTS, 0x60, ADDRMODE_IMP, 1, 6);
	
	/* SBC */
	cpu_fill_opcode(pThis, INST_SBC, 0xE9, ADDRMODE_IMM, 2, 2);
	cpu_fill_opcode(pThis, INST_SBC, 0xE5, ADDRMODE_ZP, 2, 3);
	cpu_fill_opcode(pThis, INST_SBC, 0xF5, ADDRMODE_ZPX, 2, 4);
	cpu_fill_opcode(pThis, INST_SBC, 0xED, ADDRMODE_ABS, 3, 4);
	cpu_fill_opcode(pThis, INST_SBC, 0xFD, ADDRMODE_ABSX, 3, 4);
	cpu_fill_opcode(pThis, INST_SBC, 0xF9, ADDRMODE_ABSY, 3, 4);
	cpu_fill_opcode(pThis, INST_SBC, 0xE1, ADDRMODE_PREIDXIND, 2, 6);
	cpu_fill_opcode(pThis, INST_SBC, 0xF1, ADDRMODE_POSTIDXIND, 2, 5);
	
	/* SEC */
	cpu_fill_opcode(pThis, INST_SEC, 0x38, ADDRMODE_IMP, 1, 2);
	
	/* SED */
	cpu_fill_opcode(pThis, INST_SED, 0xF8, ADDRMODE_IMP, 1, 2);
	
	/* SEI */
	cpu_fill_opcode(pThis, INST_SEI, 0x78, ADDRMODE_IMP, 1, 2);
	
	/* STA */
	cpu_fill_opcode(pThis, INST_STA, 0x85, ADDRMODE_ZP, 2, 3);
	cpu_fill_opcode(pThis, INST_STA, 0x95, ADDRMODE_ZPX, 2, 4);
	cpu_fill_opcode(pThis, INST_STA, 0x8D, ADDRMODE_ABS, 3, 4);
	cpu_fill_opcode(pThis, INST_STA, 0x9D, ADDRMODE_ABSX, 3, 5);
	cpu_fill_opcode(pThis, INST_STA, 0x99, ADDRMODE_ABSY, 3, 5);
	cpu_fill_opcode(pThis, INST_STA, 0x81, ADDRMODE_PREIDXIND, 2, 6);
	cpu_fill_opcode(pThis, INST_STA, 0x91, ADDRMODE_POSTIDXIND, 2, 6);
	
	/* STX */
	cpu_fill_opcode(pThis, INST_STX, 0x86, ADDRMODE_ZP, 2, 3);
	cpu_fill_opcode(pThis, INST_STX, 0x96, ADDRMODE_ZPY, 2, 4);
	cpu_fill_opcode(pThis, INST_STX, 0x8E, ADDRMODE_ABS, 3, 4);
	
	/* STY */
	cpu_fill_opcode(pThis, INST_STY, 0x84, ADDRMODE_ZP, 2, 3);
	cpu_fill_opcode(pThis, INST_STY, 0x94, ADDRMODE_ZPY, 2, 4);
	cpu_fill_opcode(pThis, INST_STY, 0x8C, ADDRMODE_ABS, 3, 4);
	
	/* TAX */
	cpu_fill_opcode(pThis, INST_TAX, 0xAA, ADDRMODE_IMP, 1, 2);
	
	/* TAY */
	cpu_fill_opcode(pThis, INST_TAY, 0xA8, ADDRMODE_IMP, 1, 2);
	
	/* TSX */
	cpu_fill_opcode(pThis, INST_TSX, 0xBA, ADDRMODE_IMP, 1, 2);
	
	/* TXA */
	cpu_fill_opcode(pThis, INST_TXA, 0x8A, ADDRMODE_IMP, 1, 2);
	
	/* TXS */
	cpu_fill_opcode(pThis, INST_TXS, 0x9A, ADDRMODE_IMP, 1, 2);
	
	/* TYA */
	cpu_fill_opcode(pThis, INST_TYA, 0x98, ADDRMODE_IMP, 1, 2);
}