From a3454219633169928fd45bd093d45a7ed74f60ea Mon Sep 17 00:00:00 2001
From: Lauchmelder <robert.trololo@gmail.com>
Date: Sat, 23 Oct 2021 00:47:33 +0200
Subject: [PATCH] added more instructions

---
 NES Emulator/bus.c       |  19 ++
 NES Emulator/bus.h       |   1 +
 NES Emulator/cartridge.c |   2 +-
 NES Emulator/cpu.c       | 554 ++++++++++++++++++++++++++++++++++++---
 NES Emulator/cpu.h       |  11 +-
 NES Emulator/log.c       |  10 +-
 6 files changed, 558 insertions(+), 39 deletions(-)

diff --git a/NES Emulator/bus.c b/NES Emulator/bus.c
index cbce8d5..9144e5a 100644
--- a/NES Emulator/bus.c	
+++ b/NES Emulator/bus.c	
@@ -1,6 +1,7 @@
 #include "bus.h"
 #include <stdlib.h>
 #include <stdio.h>
+#include <memory.h>
 
 #include "cpu.h"
 #include "cartridge.h"
@@ -21,6 +22,15 @@ struct Bus* createBus()
 		fprintf(stderr, "Failed to allocate memory for NES RAM, aborting.");
 		exit(1);
 	}
+	memset(bus->ram, 0x00, 0x800);
+
+	bus->io = (Byte*)malloc(0x18);
+	if (bus->io == NULL)
+	{
+		fprintf(stderr, "Failed to allocate memory for NES I/O, aborting.");
+		exit(1);
+	}
+	memset(bus->ram, 0x00, 0x18);
 
 	// Create CPU and attach it
 	bus->cpu = createCPU(bus);
@@ -38,6 +48,7 @@ void destroyBus(struct Bus* bus)
 	destroyCartridge(bus->cartridge);
 	destroyCPU(bus->cpu);
 	
+	free(bus->io);
 	free(bus->ram);
 	free(bus);
 }
@@ -51,6 +62,10 @@ Byte readBus(struct Bus* bus, Word addr)
 	{
 		val = bus->ram[addr & 0x7FF];
 	}
+	else if (0x4000 <= addr && addr <= 0x4017)	// I/O space
+	{
+		val = bus->io[addr - 0x4000];
+	}
 	else if (0x4020 <= addr && addr <= 0xFFFF)	// Cartridge space
 	{
 		val = readCartridge(bus->cartridge, addr);
@@ -71,6 +86,10 @@ void writeBus(struct Bus* bus, Word addr, Byte val)
 	{
 		bus->ram[addr & 0x7FF] = val;
 	}
+	else if (0x4000 <= addr && addr <= 0x4017)	// I/O space
+	{
+		bus->io[addr - 0x4000] = val;
+	}
 	else if (0x4020 <= addr && addr <= 0xFFFF)	// Cartridge space
 	{
 		writeCartridge(bus->cartridge, addr, val);
diff --git a/NES Emulator/bus.h b/NES Emulator/bus.h
index 93cc9ad..ceafd6a 100644
--- a/NES Emulator/bus.h	
+++ b/NES Emulator/bus.h	
@@ -10,6 +10,7 @@ struct Cartridge;
 struct Bus
 {
 	Byte* ram;
+	Byte* io;
 
 	struct CPU* cpu;
 	struct Cartridge* cartridge;
diff --git a/NES Emulator/cartridge.c b/NES Emulator/cartridge.c
index 5cc1f40..828a837 100644
--- a/NES Emulator/cartridge.c	
+++ b/NES Emulator/cartridge.c	
@@ -85,7 +85,7 @@ Byte readCartridge(struct Cartridge* cartridge, Word addr)
 	}
 	else if (0x8000 <= addr && addr <= 0xFFFF)	// PRG ROM
 	{
-		val = cartridge->prg_rom[addr & 0x1FFF];
+		val = cartridge->prg_rom[addr & 0x3FFF];
 	}
 
 	return val;
diff --git a/NES Emulator/cpu.c b/NES Emulator/cpu.c
index 0e5e191..1202b3f 100644
--- a/NES Emulator/cpu.c	
+++ b/NES Emulator/cpu.c	
@@ -5,6 +5,16 @@
 #include "log.h"
 #include "bus.h"
 
+inline void Push(struct Bus* bus, Byte val)
+{
+	writeBus(bus, 0x0100 + (bus->cpu->sp--), val);
+}
+
+inline Byte Pop(struct Bus* bus)
+{
+	return readBus(bus, 0x0100 + (++bus->cpu->sp));
+}
+
 struct CPU* createCPU(struct Bus* parent)
 {
 	struct CPU* cpu = (struct CPU*)malloc(sizeof(struct CPU));
@@ -15,12 +25,13 @@ struct CPU* createCPU(struct Bus* parent)
 	}
 
 	// TODO: THIS IS JUST FOR THE TEST ROM
-	cpu->pc = 0xC000;
+	cpu->pc.word = 0xC000;
 
 	cpu->status.raw = 0x34;
 	cpu->acc = 0;
 	cpu->x = 0;
 	cpu->y = 0;
+	cpu->sp = 0xFD;
 
 	cpu->remainingCycles = 7;
 	cpu->totalCycles = 0;
@@ -56,34 +67,35 @@ void tickInstr(struct CPU* cpu)
 
 void fetch(struct CPU* cpu)
 {
-	Byte opcodeVal = readBus(cpu->bus, cpu->pc++);
+	Byte opcodeVal = readBus(cpu->bus, cpu->pc.word);
 	cpu->currentOpcode = OPCODE_TABLE + opcodeVal;
 
 	if (cpu->currentOpcode->op == XXX)
 	{
-		fprintf(stderr, "Unknown opcode: %x", opcodeVal);
+		fprintf(stderr, "Unknown opcode: %02X", opcodeVal);
 		exit(1);
 	}
 
+	cpu->pc.word++;
 	cpu->remainingCycles = cpu->currentOpcode->cycles;
 
 	switch (cpu->currentOpcode->addr)
 	{
 	case ACC:
 		cpu->fetchedVal = cpu->acc;
-		break;
+		return;
 
 	case ABS:
 	{
-		Byte lo = readBus(cpu->bus, cpu->pc++);
-		Byte hi = readBus(cpu->bus, cpu->pc++);
+		Byte lo = readBus(cpu->bus, cpu->pc.word++);
+		Byte hi = readBus(cpu->bus, cpu->pc.word++);
 		cpu->fetchedAddress = ((Word)hi << 8) | lo;
 	} break;
 
 	case ABX:
 	{
-		Byte lo = readBus(cpu->bus, cpu->pc++);
-		Byte hi = readBus(cpu->bus, cpu->pc++);
+		Byte lo = readBus(cpu->bus, cpu->pc.word++);
+		Byte hi = readBus(cpu->bus, cpu->pc.word++);
 		Word addr = ((Word)hi << 8) | lo;
 
 		cpu->fetchedAddress = addr + cpu->x;
@@ -95,8 +107,8 @@ void fetch(struct CPU* cpu)
 
 	case ABY:
 	{
-		Byte lo = readBus(cpu->bus, cpu->pc++);
-		Byte hi = readBus(cpu->bus, cpu->pc++);
+		Byte lo = readBus(cpu->bus, cpu->pc.word++);
+		Byte hi = readBus(cpu->bus, cpu->pc.word++);
 		Word addr = ((Word)hi << 8) | lo;
 
 		cpu->fetchedAddress = addr + cpu->y;
@@ -107,40 +119,38 @@ void fetch(struct CPU* cpu)
 	} break;
 	
 	case IMM:
-		cpu->fetchedVal = readBus(cpu->bus, cpu->pc++);
-		break;
+		cpu->fetchedVal = readBus(cpu->bus, cpu->pc.word++);
+		return;
 
 	case IMP:
-		break;
+		return;
 
 	case IND:
 	{
-		Byte lo = readBus(cpu->bus, cpu->pc++);
-		Byte hi = readBus(cpu->bus, cpu->pc++);
-		Word addr = ((Word)hi << 8) | lo;
+		Byte lo = readBus(cpu->bus, cpu->pc.word++);
+		Byte hi = readBus(cpu->bus, cpu->pc.word++);
+		Word addr = ((Word)hi << 8);
 
-		cpu->fetchedAddress = readBus(cpu->bus, addr);
+		cpu->fetchedAddress = ((Word)readBus(cpu->bus, addr | ((lo + 1) & 0xFF)) << 8) | readBus(cpu->bus, addr | lo);
 
 	} break;
 
 	case INDX:
 	{
-		Byte op = readBus(cpu->bus, cpu->pc++);
-		Byte lo = readBus(cpu->bus, op + cpu->x);
-		Byte hi = readBus(cpu->bus, op + cpu->x + 1);
-		Word addr = ((Word)hi << 8) | lo;
+		Byte op = readBus(cpu->bus, cpu->pc.word++);
+		Byte lo = readBus(cpu->bus, (op + cpu->x) & 0xFF);
+		Byte hi = readBus(cpu->bus, (op + cpu->x + 1) & 0xFF);
 
-		cpu->fetchedAddress = readBus(cpu->bus, addr);
+		cpu->fetchedAddress = ((Word)hi << 8) | lo;
 
 	} break;
 
 	case INDY:
 	{
-		Byte op = readBus(cpu->bus, cpu->pc++);
+		Byte op = readBus(cpu->bus, cpu->pc.word++);
 		Byte lo = readBus(cpu->bus, op);
-		Byte hi = readBus(cpu->bus, op + 1);
+		Byte hi = readBus(cpu->bus, (op + 1) & 0xFF);
 		Word addr = ((Word)hi << 8) | lo;
-		addr = readBus(cpu->bus, addr);
 
 		cpu->fetchedAddress = addr + cpu->y;
 
@@ -151,26 +161,26 @@ void fetch(struct CPU* cpu)
 
 	case REL:
 	{
-		cpu->fetchedRelAddress = readBus(cpu->bus, cpu->pc++);
+		cpu->fetchedRelAddress = readBus(cpu->bus, cpu->pc.word++);
 	} break;
 
 	case ZPG:
-		cpu->fetchedAddress = readBus(cpu->bus, cpu->pc++);
+		cpu->fetchedAddress = readBus(cpu->bus, cpu->pc.word++);
 		break;
 
 	case ZPX:
 	{
-		cpu->fetchedAddress = readBus(cpu->bus, cpu->pc++) + cpu->x;
-		cpu->fetchedAddress |= 0xFF;
+		cpu->fetchedAddress = (readBus(cpu->bus, cpu->pc.word++) + cpu->x) & 0xFF;
 	} break;
 
 	case ZPY:
 	{
-		cpu->fetchedAddress = readBus(cpu->bus, cpu->pc++) + cpu->y;
-		cpu->fetchedAddress |= 0xFF;
+		cpu->fetchedAddress = (readBus(cpu->bus, cpu->pc.word++) + cpu->y) & 0xFF;
 	} break;
 
 	}
+
+	cpu->fetchedVal = readBus(cpu->bus, cpu->fetchedAddress);
 }
 
 void execute(struct CPU* cpu)
@@ -179,9 +189,489 @@ void execute(struct CPU* cpu)
 
 	switch (cpu->currentOpcode->op)
 	{
+	case ADC:
+	{
+		Word result = cpu->acc + cpu->fetchedVal + cpu->status.carry;
+
+		cpu->status.carry = (result > 0xFF);
+		cpu->status.overflow = ((~(cpu->acc ^ cpu->fetchedVal) & (cpu->acc ^ result) & 0x80) == 0x80);
+		cpu->status.negative = (result >> 7);
+		cpu->status.zero = ((result & 0xFF) == 0x00);
+
+		cpu->acc = result & 0xFF;
+	} break;
+
+	case AND:
+	{
+		cpu->acc &= cpu->fetchedVal;
+
+		cpu->status.negative = (cpu->acc >> 7);
+		cpu->status.zero = (cpu->acc == 0x00);
+	} break;
+
+	case ASL:
+	{
+		cpu->status.carry = ((cpu->fetchedVal & 0x80) == 0x80);
+
+		cpu->fetchedVal <<= 1;
+
+		cpu->status.negative = ((cpu->fetchedVal & 0x80) == 0x80);
+		cpu->status.zero = (cpu->fetchedVal == 0x00);
+
+		if (!cpu->currentOpcode->addr == ACC)
+			writeBus(cpu->bus, cpu->fetchedAddress, cpu->fetchedVal);
+		else
+			cpu->acc = cpu->fetchedVal;
+	} break;
+
+	case BCC:
+	{
+		if (!cpu->status.carry)
+		{
+			Word target = cpu->pc.word + cpu->fetchedRelAddress;
+
+			cpu->remainingCycles++;
+			if ((target & 0xFF00) != (cpu->pc.word & 0xFF00))
+				cpu->remainingCycles++;
+
+			cpu->pc.word = target;
+		}
+	} break;
+
+	case BCS:
+	{
+		if (cpu->status.carry)
+		{
+			Word target = cpu->pc.word + cpu->fetchedRelAddress;
+
+			cpu->remainingCycles++;
+			if ((target & 0xFF00) != (cpu->pc.word & 0xFF00))
+				cpu->remainingCycles++;
+
+			cpu->pc.word = target;
+		}
+	} break;
+
+	case BEQ:
+	{
+		if (cpu->status.zero)
+		{
+			Word target = cpu->pc.word + cpu->fetchedRelAddress;
+
+			cpu->remainingCycles++;
+			if ((target & 0xFF00) != (cpu->pc.word & 0xFF00))
+				cpu->remainingCycles++;
+
+			cpu->pc.word = target;
+		}
+	} break;
+
+	case BMI:
+	{
+		if (cpu->status.negative)
+		{
+			Word target = cpu->pc.word + cpu->fetchedRelAddress;
+
+			cpu->remainingCycles++;
+			if ((target & 0xFF00) != (cpu->pc.word & 0xFF00))
+				cpu->remainingCycles++;
+
+			cpu->pc.word = target;
+		}
+	} break;
+
+	case BPL:
+	{
+		if (!cpu->status.negative)
+		{
+			Word target = cpu->pc.word + cpu->fetchedRelAddress;
+
+			cpu->remainingCycles++;
+			if ((target & 0xFF00) != (cpu->pc.word & 0xFF00))
+				cpu->remainingCycles++;
+
+			cpu->pc.word = target;
+		}
+	} break;
+
+	case BVC:
+	{
+		if (!cpu->status.overflow)
+		{
+			Word target = cpu->pc.word + cpu->fetchedRelAddress;
+
+			cpu->remainingCycles++;
+			if ((target & 0xFF00) != (cpu->pc.word & 0xFF00))
+				cpu->remainingCycles++;
+
+			cpu->pc.word = target;
+		}
+	} break;
+
+	case BVS:
+	{
+		if (cpu->status.overflow)
+		{
+			Word target = cpu->pc.word + cpu->fetchedRelAddress;
+
+			cpu->remainingCycles++;
+			if ((target & 0xFF00) != (cpu->pc.word & 0xFF00))
+				cpu->remainingCycles++;
+
+			cpu->pc.word = target;
+		}
+	} break;
+
+	case BIT:
+	{
+		cpu->status.negative = (cpu->fetchedVal >> 7);
+		cpu->status.overflow = (cpu->fetchedVal >> 6);
+		cpu->status.zero = ((cpu->acc & cpu->fetchedVal) == 0x00);
+	} break;
+
+	case BNE:
+	{
+		if (!cpu->status.zero)
+		{
+			Word target = cpu->pc.word + cpu->fetchedRelAddress;
+
+			cpu->remainingCycles++;
+			if ((target & 0xFF00) != (cpu->pc.word & 0xFF00))
+				cpu->remainingCycles++;
+
+			cpu->pc.word = target;
+		}
+	} break;
+
+	case CLC:
+	{
+		cpu->status.carry = 0;
+	} break;
+
+	case CLD:
+	{
+		cpu->status.decimal = 0;
+	} break;
+
+	case CLV:
+	{
+		cpu->status.overflow = 0;
+	} break;
+
+	case CMP:
+	{
+		Byte result = cpu->acc - cpu->fetchedVal;
+
+		cpu->status.negative = (result >> 7);
+		cpu->status.zero = (result == 0x00);
+		cpu->status.carry = (cpu->fetchedVal <= cpu->acc);
+	} break;
+
+	case CPX:
+	{
+		Byte result = cpu->x - cpu->fetchedVal;
+
+		cpu->status.negative = (result >> 7);
+		cpu->status.zero = (result == 0x00);
+		cpu->status.carry = (cpu->fetchedVal <= cpu->x);
+	} break;
+
+	case CPY:
+	{
+		Byte result = cpu->y - cpu->fetchedVal;
+
+		cpu->status.negative = (result >> 7);
+		cpu->status.zero = (result == 0x00);
+		cpu->status.carry = (cpu->fetchedVal <= cpu->y);
+	} break;
+
+	case DEC:
+	{
+		cpu->fetchedVal--;
+
+		cpu->status.negative = ((cpu->fetchedVal & 0x80) == 0x80);
+		cpu->status.zero = (cpu->fetchedVal == 0x00);
+
+		writeBus(cpu->bus, cpu->fetchedAddress, cpu->fetchedVal);
+	} break;
+
+	case DEX:
+	{
+		cpu->x--;
+
+		cpu->status.negative = ((cpu->x & 0x80) == 0x80);
+		cpu->status.zero = (cpu->x == 0x80);
+	} break;
+
+	case DEY:
+	{
+		cpu->y--;
+
+		cpu->status.negative = ((cpu->y & 0x80) == 0x80);
+		cpu->status.zero = (cpu->y == 0x80);
+	} break;
+
+	case EOR:
+	{
+		cpu->acc ^= cpu->fetchedVal;
+
+		cpu->status.negative = (cpu->acc >> 7);
+		cpu->status.zero = (cpu->acc == 0x00);
+	} break;
+
+	case INC:
+	{
+		cpu->fetchedVal++;
+
+		cpu->status.negative = ((cpu->fetchedVal & 0x80) == 0x80);
+		cpu->status.zero = (cpu->fetchedVal == 0x00);
+
+		writeBus(cpu->bus, cpu->fetchedAddress, cpu->fetchedVal);
+	} break;
+
+	case INX:
+	{
+		cpu->x++;
+
+		cpu->status.negative = ((cpu->x & 0x80) == 0x80);
+		cpu->status.zero = (cpu->x == 0x00);
+	} break;
+
+	case INY:
+	{
+		cpu->y++;
+
+		cpu->status.negative = ((cpu->y & 0x80) == 0x80);
+		cpu->status.zero = (cpu->y == 0x00);
+	} break;
+
 	case JMP:
 	{
-		cpu->pc = cpu->fetchedAddress;
+		cpu->pc.word = cpu->fetchedAddress;
+	} break;
+
+	case JSR:
+	{
+		cpu->pc.word--;
+		Push(cpu->bus, cpu->pc.hi);
+		Push(cpu->bus, cpu->pc.lo);
+
+		cpu->pc.word = cpu->fetchedAddress;
+	} break;
+
+	case LDA:
+	{
+		cpu->acc = cpu->fetchedVal;
+
+		cpu->status.negative = (cpu->acc >> 7);
+		cpu->status.zero = (cpu->acc == 0x00);
+	} break;
+
+	case LDX:
+	{
+		cpu->x = cpu->fetchedVal;
+
+		cpu->status.negative = (cpu->x >> 7);
+		cpu->status.zero = (cpu->x == 0x00);
+	} break;
+
+	case LDY:
+	{
+		cpu->y = cpu->fetchedVal;
+
+		cpu->status.negative = (cpu->y >> 7);
+		cpu->status.zero = (cpu->y == 0x00);
+	} break;
+
+	case LSR:
+	{
+		cpu->status.negative = 0;
+		cpu->status.carry = ((cpu->fetchedVal & 0x01) == 0x01);
+
+		cpu->fetchedVal >>= 1;
+
+		cpu->status.zero = (cpu->fetchedVal == 0x00);
+
+		if (!cpu->currentOpcode->addr == ACC)
+			writeBus(cpu->bus, cpu->fetchedAddress, cpu->fetchedVal);
+		else
+			cpu->acc = cpu->fetchedVal;
+	} break;
+
+	case NOP:
+	{
+
+	} break;
+
+	case ORA:
+	{
+		cpu->acc |= cpu->fetchedVal;
+
+		cpu->status.negative = (cpu->acc >> 7);
+		cpu->status.zero = (cpu->acc == 0x00);
+	} break;
+
+	case PHA:
+	{
+		Push(cpu->bus, cpu->acc);
+	} break;
+
+	case PHP:
+	{
+		Push(cpu->bus, cpu->status.raw | 0b00110000);
+
+	} break;
+
+	case PLA:
+	{
+		cpu->acc = Pop(cpu->bus);
+
+		cpu->status.negative = (cpu->acc >> 7);
+		cpu->status.zero = (cpu->acc == 0x00);
+	} break;
+
+	case PLP:
+	{
+		cpu->status.raw = Pop(cpu->bus) | 0b00110000;
+	} break;
+
+	case ROL:
+	{
+		Byte oldCarry = cpu->status.carry;
+		cpu->status.carry = ((cpu->fetchedVal & 0x80) == 0x80);
+
+		cpu->fetchedVal <<= 1;
+		cpu->fetchedVal |= oldCarry;
+
+		cpu->status.negative = ((cpu->fetchedVal & 0x80) == 0x80);
+		cpu->status.zero = (cpu->fetchedVal == 0x00);
+
+		if (!cpu->currentOpcode->addr == ACC)
+			writeBus(cpu->bus, cpu->fetchedAddress, cpu->fetchedVal);
+		else
+			cpu->acc = cpu->fetchedVal;
+	} break;
+
+	case ROR:
+	{
+		Byte oldCarry = cpu->status.carry;
+		cpu->status.negative = oldCarry;
+		cpu->status.carry = ((cpu->fetchedVal & 0x01) == 0x01);
+
+		cpu->fetchedVal >>= 1;
+		cpu->fetchedVal |= (oldCarry << 7);
+
+		cpu->status.zero = (cpu->fetchedVal == 0x00);
+
+		if (!cpu->currentOpcode->addr == ACC)
+			writeBus(cpu->bus, cpu->fetchedAddress, cpu->fetchedVal);
+		else
+			cpu->acc = cpu->fetchedVal;
+	} break;
+
+	case RTI:
+	{
+		cpu->status.raw = Pop(cpu->bus) | 0b00110000;
+
+		cpu->pc.lo = Pop(cpu->bus);
+		cpu->pc.hi = Pop(cpu->bus);
+	} break;
+
+	case RTS:
+	{
+		cpu->pc.lo = Pop(cpu->bus);
+		cpu->pc.hi = Pop(cpu->bus);
+		cpu->pc.word++;
+	} break;
+
+	case SBC:
+	{
+		Word result = cpu->acc + ~cpu->fetchedVal + cpu->status.carry;
+
+		cpu->status.carry = ((result & 0x8000) != 0x8000);
+		cpu->status.overflow = ((~(cpu->acc ^ ~cpu->fetchedVal) & (cpu->acc ^ result) & 0x80) == 0x80);
+		cpu->status.negative = ((result & 0x80) == 0x80);
+		cpu->status.zero = ((result & 0xFF) == 0x00);
+
+		cpu->acc = result & 0xFF;
+	} break;
+
+	case SEC:
+	{
+		cpu->status.carry = 1;
+	} break;
+
+	case SED:
+	{
+		cpu->status.decimal = 1;
+	} break;
+
+	case SEI:
+	{
+		cpu->status.id = 1;
+	} break;
+
+	case STA:
+	{
+		writeBus(cpu->bus, cpu->fetchedAddress, cpu->acc);
+		cpu->remainingCycles = cpu->currentOpcode->cycles;	// Correct "oops" cycle (store instr. always have it)
+	} break;
+
+	case STX:
+	{
+		writeBus(cpu->bus, cpu->fetchedAddress, cpu->x);
+		cpu->remainingCycles = cpu->currentOpcode->cycles;	// Correct "oops" cycle (store instr. always have it)
+	} break;
+
+	case STY:
+	{
+		writeBus(cpu->bus, cpu->fetchedAddress, cpu->y);
+		cpu->remainingCycles = cpu->currentOpcode->cycles;	// Correct "oops" cycle (store instr. always have it)
+	} break;
+
+	case TAX:
+	{
+		cpu->x = cpu->acc;
+
+		cpu->status.negative = ((cpu->x & 0x80) == 0x80);
+		cpu->status.zero = (cpu->x == 0x00);
+	} break;
+
+	case TAY:
+	{
+		cpu->y = cpu->acc;
+
+		cpu->status.negative = ((cpu->y & 0x80) == 0x80);
+		cpu->status.zero = (cpu->y == 0x00);
+	} break;
+
+	case TSX:
+	{
+		cpu->x = cpu->sp;
+
+		cpu->status.negative = ((cpu->x & 0x80) == 0x80);
+		cpu->status.zero = (cpu->x == 0x00);
+	} break;
+
+	case TXA:
+	{
+		cpu->acc = cpu->x;
+
+		cpu->status.negative = ((cpu->acc & 0x80) == 0x80);
+		cpu->status.zero = (cpu->acc == 0x00);
+	} break;
+
+	case TXS:
+	{
+		cpu->sp = cpu->x;
+	} break;
+
+	case TYA:
+	{
+		cpu->acc = cpu->y;
+
+		cpu->status.negative = ((cpu->acc & 0x80) == 0x80);
+		cpu->status.zero = (cpu->acc == 0x00);
 	} break;
 
 	default:
diff --git a/NES Emulator/cpu.h b/NES Emulator/cpu.h
index ac92e4f..4996b0c 100644
--- a/NES Emulator/cpu.h	
+++ b/NES Emulator/cpu.h	
@@ -57,7 +57,16 @@ struct CPU
 		Byte raw;
 	} status;
 
-	Word pc;
+	union
+	{
+		struct
+		{
+			Byte lo;
+			Byte hi;
+		};
+
+		Word word;
+	} pc;
 
 	Byte remainingCycles;
 	size_t totalCycles;
diff --git a/NES Emulator/log.c b/NES Emulator/log.c
index d91304c..f923fd5 100644
--- a/NES Emulator/log.c	
+++ b/NES Emulator/log.c	
@@ -8,7 +8,7 @@ void logBusState(struct Bus* bus)
 {
 	const char buffer[32];
 
-	Word oldPC = bus->cpu->pc - bus->cpu->currentOpcode->length;
+	Word oldPC = bus->cpu->pc.word - bus->cpu->currentOpcode->length;
 
 	printf("%04X  ", oldPC);
 
@@ -27,11 +27,11 @@ void logBusState(struct Bus* bus)
 	case ABS: sprintf(buffer, "$%04X",					bus->cpu->fetchedAddress); break;
 	case ABX: sprintf(buffer, "$%04X, X -> $%04X",		(instructionBytes[2] << 8) | instructionBytes[1], bus->cpu->fetchedAddress); break;
 	case ABY: sprintf(buffer, "$%04X, Y -> $%04X",		(instructionBytes[2] << 8) | instructionBytes[1], bus->cpu->fetchedAddress); break;
-	case IMM: sprintf(buffer, "#$%04X",					bus->cpu->fetchedVal); break;
+	case IMM: sprintf(buffer, "#$%02X",					bus->cpu->fetchedVal); break;
 	case IMP: sprintf(buffer, ""); break;
-	case IND: sprintf(buffer, "($%04X) -> $%04x",		(instructionBytes[2] << 8) | instructionBytes[1], bus->cpu->fetchedAddress); break;
-	case INDX: sprintf(buffer, "($%04X, X) -> $%04x",	(instructionBytes[2] << 8) | instructionBytes[1], bus->cpu->fetchedAddress); break;
-	case INDY: sprintf(buffer, "($%04X), Y -> $%04x",	(instructionBytes[2] << 8) | instructionBytes[1], bus->cpu->fetchedAddress); break;
+	case IND: sprintf(buffer, "($%04X) -> $%04X",		(instructionBytes[2] << 8) | instructionBytes[1], bus->cpu->fetchedAddress); break;
+	case INDX: sprintf(buffer, "($%02X, X) -> $%04X",	instructionBytes[1], bus->cpu->fetchedAddress); break;
+	case INDY: sprintf(buffer, "($%02X), Y -> $%04X",	instructionBytes[1], bus->cpu->fetchedAddress); break;
 	case REL: sprintf(buffer, "$%02X",					bus->cpu->fetchedRelAddress); break;
 	case ZPG: sprintf(buffer, "$%02X",					bus->cpu->fetchedAddress); break;
 	case ZPX: sprintf(buffer, "$%02X, X -> $%02X",		instructionBytes[1], bus->cpu->fetchedAddress); break;