Multithread gui, remove hard coded cpu->pc
diff --git a/a.out b/a.out
new file mode 100644
index 0000000..fded1f4
--- /dev/null
+++ b/a.out
Binary files differ
diff --git a/colors.dat b/colors.dat
index fc0ee0a..aea5970 100644
--- a/colors.dat
+++ b/colors.dat
Binary files differ
diff --git a/cpu.c b/cpu.c
index 8b5eda8..12f9af7 100644
--- a/cpu.c
+++ b/cpu.c
@@ -146,14 +146,6 @@
 	}
 }
 
-uint16_t scr_dirty(cpu_t *cpu, uint16_t mem)
-{
-	if (mem >= 0x200 && mem <= 0x200 + 32 * 32)
-		cpu->screen_dirty = true;
-
-	return mem;
-}
-
 void execute(cpu_t *cpu, const char *mnemonic, uint8_t op, arg_t a, uint8_t am)
 {
 	// used to save space
@@ -174,7 +166,7 @@
 
 		#define R(reg) \
 			case ST##reg: \
-				cpu->mem[scr_dirty(cpu, a.ptr)] = cpu->regs[reg]; \
+				cpu->mem[a.ptr] = cpu->regs[reg]; \
 				break; \
 
 			REGS
@@ -204,8 +196,8 @@
 		}
 
 		case INC:
-			cpu->mem[scr_dirty(cpu, scr_dirty(cpu, a.ptr))]++;
-			stat_nz(cpu, cpu->mem[scr_dirty(cpu, a.ptr)]);
+			cpu->mem[a.ptr]++;
+			stat_nz(cpu, cpu->mem[a.ptr]);
 			break;
 
 		case INX:
@@ -219,8 +211,8 @@
 			break;
 
 		case DEC:
-			cpu->mem[scr_dirty(cpu, a.ptr)]--;
-			stat_nz(cpu, cpu->mem[scr_dirty(cpu, a.ptr)]);
+			cpu->mem[a.ptr]--;
+			stat_nz(cpu, cpu->mem[a.ptr]);
 			break;
 
 		case DEX:
@@ -245,9 +237,9 @@
 			}
 			else
 			{
-				cpu->status.carry = cpu->mem[scr_dirty(cpu, a.val)] >> 7;
-				cpu->mem[scr_dirty(cpu, a.ptr)] <<= 1;
-				stat_nz(cpu, cpu->mem[scr_dirty(cpu, a.ptr)]);
+				cpu->status.carry = cpu->mem[a.val] >> 7;
+				cpu->mem[a.ptr] <<= 1;
+				stat_nz(cpu, cpu->mem[a.ptr]);
 			}
 			break;
 
@@ -260,9 +252,9 @@
 			}
 			else
 			{
-				cpu->status.carry = cpu->mem[scr_dirty(cpu, a.val)] & 7;
-				cpu->mem[scr_dirty(cpu, a.ptr)] >>= 1;
-				stat_nz(cpu, cpu->mem[scr_dirty(cpu, a.ptr)]);
+				cpu->status.carry = cpu->mem[a.val] & 7;
+				cpu->mem[a.ptr] >>= 1;
+				stat_nz(cpu, cpu->mem[a.ptr]);
 			}
 			break;
 
@@ -275,9 +267,9 @@
 			}
 			else
 			{
-				cpu->status.carry = cpu->mem[scr_dirty(cpu, a.val)] >> 7;
-				cpu->mem[scr_dirty(cpu, a.ptr)] = rol(a.val, 1);
-				stat_nz(cpu, cpu->mem[scr_dirty(cpu, a.ptr)]);
+				cpu->status.carry = cpu->mem[a.val] >> 7;
+				cpu->mem[a.ptr] = rol(a.val, 1);
+				stat_nz(cpu, cpu->mem[a.ptr]);
 			}
 			break;
 
@@ -290,9 +282,9 @@
 			}
 			else
 			{
-				cpu->status.carry = cpu->mem[scr_dirty(cpu, a.val)] & 1;
-				cpu->mem[scr_dirty(cpu, a.ptr)] = ror(a.val, 1);
-				stat_nz(cpu, cpu->mem[scr_dirty(cpu, a.ptr)]);
+				cpu->status.carry = cpu->mem[a.val] & 1;
+				cpu->mem[a.ptr] = ror(a.val, 1);
+				stat_nz(cpu, cpu->mem[a.ptr]);
 			}
 			break;
 
@@ -423,10 +415,10 @@
 	#undef REGS
 }
 
-uint16_t fetch_le(cpu_t *cpu)
+uint16_t fetch_le(cpu_t *cpu, uint16_t *pc)
 {
-	uint8_t a = cpu->mem[scr_dirty(cpu, cpu->pc++)];
-	uint8_t b = cpu->mem[scr_dirty(cpu, cpu->pc++)];
+	uint8_t a = cpu->mem[(*pc)++];
+	uint8_t b = cpu->mem[(*pc)++];
 	return le_to_native(a, b);
 }
 
@@ -448,7 +440,7 @@
 	return (arg_t){ v, a };
 }
 
-arg_t fetch_addr(cpu_t *cpu, uint8_t am, uint f)
+arg_t fetch_addr(cpu_t *cpu, uint8_t am, uint f, uint16_t *pc)
 {
 	switch (am)
 	{
@@ -459,59 +451,55 @@
 		// In both cases return immediate 8 bit value
 		case AM_IMM:
 		case AM_ZP:
-			return arg_imm(cpu->mem[scr_dirty(cpu, cpu->pc++)]);
+			return arg_imm(cpu->mem[(*pc)++]);
 
 		case AM_ABS:
-			return arg_ptr(cpu, f, fetch_le(cpu));
+			return arg_ptr(cpu, f, fetch_le(cpu, pc));
 
 		case AM_REL:
 		{
-			// Aparently, PC should will point to the NEXT opcode
-			// I can't find any documentation on this unfortunately, but
-			// I have discovered this through testing the output of other
-			// assemblers.
-			uint16_t pc = cpu->pc + 1;
-			return arg_ptr(cpu, f, (int8_t)cpu->mem[scr_dirty(cpu, cpu->pc++)] + pc);
+			uint16_t pc_hi = * pc + 1;
+			return arg_ptr(cpu, f, (int8_t)cpu->mem[(*pc)++] + pc_hi);
 		}
 
 		case AM_IND:
 		{
-			uint16_t addr = fetch_le(cpu);
+			uint16_t addr = fetch_le(cpu, pc);
 
 			if (f & FETCH_NO_INDIRECTION)
 				return arg_imm(addr);
 
-			uint8_t low = cpu->mem[scr_dirty(cpu, addr)],
-				high = cpu->mem[scr_dirty(cpu, addr + 1)];
+			uint8_t low = cpu->mem[addr],
+				high = cpu->mem[addr + 1];
 
 			return arg_ptr(cpu, f, le_to_native(low, high));
 		}
 
 		case AM_AX:
 			if (f & FETCH_NO_INDIRECTION)
-				return arg_ptr(cpu, f, fetch_le(cpu));
+				return arg_ptr(cpu, f, fetch_le(cpu, pc));
 
-			return arg_ptr(cpu, f, fetch_le(cpu) + cpu->regs[X]);
+			return arg_ptr(cpu, f, fetch_le(cpu, pc) + cpu->regs[X]);
 
 		case AM_AY:
 			if (f & FETCH_NO_INDIRECTION)
-				return arg_ptr(cpu, f, fetch_le(cpu));
+				return arg_ptr(cpu, f, fetch_le(cpu, pc));
 		
-			return arg_ptr(cpu, f, fetch_le(cpu) + cpu->regs[Y]);
+			return arg_ptr(cpu, f, fetch_le(cpu, pc) + cpu->regs[Y]);
 
 		case AM_ZPX:
 			if (f & FETCH_NO_INDIRECTION)
-				return arg_ptr(cpu, f, cpu->mem[cpu->pc++]);
-			return arg_ptr(cpu, f, cpu->mem[cpu->pc++] + cpu->regs[X]);
+				return arg_ptr(cpu, f, cpu->mem[(*pc)++]);
+			return arg_ptr(cpu, f, cpu->mem[(*pc)++] + cpu->regs[X]);
 
 		case AM_ZPY:
 			if (f & FETCH_NO_INDIRECTION)
-				return arg_ptr(cpu, f, cpu->mem[cpu->pc++]);
-			return arg_ptr(cpu, f, cpu->mem[cpu->pc++] + cpu->regs[Y]);
+				return arg_ptr(cpu, f, cpu->mem[(*pc)++]);
+			return arg_ptr(cpu, f, cpu->mem[(*pc)++] + cpu->regs[Y]);
 
 		case AM_ZIX:
 		{
-			uint8_t zp = cpu->mem[cpu->pc++];
+			uint8_t zp = cpu->mem[(*pc)++];
 
 			if (f & FETCH_NO_INDIRECTION)
 				return arg_imm(zp);
@@ -523,12 +511,12 @@
 
 		case AM_ZIY:
 		{
-			uint8_t zp = cpu->mem[scr_dirty(cpu, cpu->pc++)];
+			uint8_t zp = cpu->mem[(*pc)++];
 
 			if (f & FETCH_NO_INDIRECTION)
 				return arg_imm(zp);
 
-			uint16_t base = le_to_native(cpu->mem[zp], cpu->mem[scr_dirty(cpu, zp + 1)]);
+			uint16_t base = le_to_native(cpu->mem[zp], cpu->mem[zp + 1]);
 			return arg_ptr(cpu, f, base + cpu->regs[Y]);
 		}
 
@@ -548,7 +536,7 @@
 	{
 #define INST(mn, am, op) \
 		case op: \
-			execute(cpu, #mn, mn, fetch_addr(cpu, am, 0), am); \
+			execute(cpu, #mn, mn, fetch_addr(cpu, am, 0, &cpu->pc), am); \
 			break;
 
 		INSTRUCTIONS
@@ -602,19 +590,19 @@
 	return end - buf;
 }
 
-char *disas_step(cpu_t *cpu)
+char *disas_step(cpu_t *cpu, uint16_t *pc)
 {
 	char *buffer = malloc(80);
 	char *end = buffer;
 
 	// end += sprintf(buffer, "$%x", cpu->pc);
-	uint8_t op = cpu->mem[scr_dirty(cpu, cpu->pc++)];
+	uint8_t op = cpu->mem[(*pc)++];
 	switch (op)
 	{
 #define INST(mn, am, op) \
 		case op: \
 			end += dump_inst(cpu, end, #mn, \
-				fetch_addr(cpu, am, FETCH_NO_INDIRECTION).ptr, am); \
+				fetch_addr(cpu, am, FETCH_NO_INDIRECTION, pc).ptr, am); \
 			break;
 
 		INSTRUCTIONS
@@ -632,29 +620,27 @@
 
 void disas_num(cpu_t *cpu, uint16_t num)
 {
-	uint16_t pc = cpu->pc;
+	uint16_t pc = 0x600;
 	for (int i = 0; i < num; i++)
 	{
-		uint16_t last_pc = cpu->pc;
-		char *line = disas_step(cpu);
+		uint16_t last_pc = pc;
+		char *line = disas_step(cpu, &pc);
 		printf("$%x\t%s\n", last_pc, line);
 		free(line);
 	}
-	cpu->pc = pc;
 }
 
 void disas(cpu_t *cpu)
 {
-	uint16_t pc = cpu->pc;
+	uint16_t pc = 0x600;
 	// Raw binary, no way to know what's code what isn't
 	while (cpu->pc < 0xFFFF)
 	{
-		uint16_t last_pc = cpu->pc;
-		char *line = disas_step(cpu);
+		uint16_t last_pc = pc;
+		char *line = disas_step(cpu, &pc);
 		printf("$%x\t%s\n", last_pc, line);
 		free(line);
 	}
-	cpu->pc = pc;
 }
 
 void run(cpu_t *cpu)
diff --git a/cpu.h b/cpu.h
index 3c82c6c..130ef05 100644
--- a/cpu.h
+++ b/cpu.h
@@ -150,6 +150,6 @@
 void disas(cpu_t *cpu);
 void disas_num(cpu_t *cpu, uint16_t num);
 // Buffer must be freed by user
-char *disas_step(cpu_t *cpu);
+char *disas_step(cpu_t *cpu, uint16_t *pc);
 void run(cpu_t *cpu);
 void run_mq(cpu_t *cpu, mqd_t mq);
diff --git a/dbg.c b/dbg.c
index 577feee..fe1355d 100644
--- a/dbg.c
+++ b/dbg.c
@@ -52,6 +52,10 @@
 	{
 		*running = true;
 	}
+	else if (!strcmp(tok, "pause"))
+	{
+		*running = false;
+	}
 	else if (!strcmp(tok, "quit") || !strcmp(tok, "exit"))
 	{
 		printf("Bye\n");
diff --git a/disco.dat b/disco.dat
new file mode 100644
index 0000000..b004f7a
--- /dev/null
+++ b/disco.dat
Binary files differ
diff --git a/gui.c b/gui.c
index 7a9841f..f12ba77 100644
--- a/gui.c
+++ b/gui.c
@@ -1,4 +1,5 @@
 #include "gui.h"
+#include "common.h"
 
 #include <GL/glew.h>
 #include <SDL2/SDL.h>
@@ -29,6 +30,11 @@
 	mqd_t mq;
 } gui_arg_t;
 
+static void cmd(mqd_t mq, char *msg)
+{
+	mq_send(mq, msg, strlen(msg) + 1, 2);
+}
+
 void gui(gui_arg_t *arg)
 {
 	cpu_t *cpu = arg->cpu;
@@ -76,8 +82,7 @@
 	glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
 	glewExperimental = 1;
 	if (glewInit() != GLEW_OK) {
-		fprintf(stderr, "Failed to setup GLEW\n");
-		exit(1);
+		THROW("Failed to setup GLEW\n");
 	}
 
 	ctx = nk_sdl_init(win);
@@ -100,9 +105,6 @@
 		}
 		nk_input_end(ctx);
 
-		if (cpu_running && cpu->running)
-			step(cpu);
-
 		if (!cpu->running)
 			cpu_running = false;
 
@@ -111,10 +113,10 @@
 			NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
 		{
 			nk_layout_row_dynamic(ctx, 30, 4);
-			cpu->pc = nk_propertyi(ctx, "PC", 0, cpu->pc, 0xFFFF, 1, 20.0f);
-			cpu->regs[A] = nk_propertyi(ctx, "A", 0, cpu->regs[A], 0xFF, 1, 20.0f);
-			cpu->regs[X] = nk_propertyi(ctx, "X", 0, cpu->regs[X], 0xFF, 1, 20.0f);
-			cpu->regs[Y] = nk_propertyi(ctx, "Y", 0, cpu->regs[Y], 0xFF, 1, 20.0f);
+			uint16_t pc = nk_propertyi(ctx, "PC", 0, cpu->pc, 0xFFFF, 1, 20.0f);
+			uint8_t rega = nk_propertyi(ctx, "A", 0, cpu->regs[A], 0xFF, 1, 20.0f),
+				regx = nk_propertyi(ctx, "X", 0, cpu->regs[X], 0xFF, 1, 20.0f),
+				regy = nk_propertyi(ctx, "Y", 0, cpu->regs[Y], 0xFF, 1, 20.0f);
 		}
 		nk_end(ctx);
 
@@ -123,7 +125,7 @@
 			NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
 		{
 			nk_layout_row_dynamic(ctx, 24, 1);
-			screen_scale = nk_propertyi(ctx, "Scale", 1, screen_scale, 8, 1, 1);
+			screen_scale = nk_propertyi(ctx, "Scale", 1, screen_scale, 16, 1, 1);
 
 			nk_layout_row_static(ctx, screen_scale * 32, screen_scale * 32, 1);
 			screen(ctx, cpu->mem + CPU_FB_ADDR, screen_scale);
@@ -138,23 +140,22 @@
 			disas_start = nk_propertyi(ctx, "Start", 0, disas_start, 0xFFFF, 1, 20.0f);
 			disas_end = nk_propertyi(ctx, "End", 0, disas_end, 0xFFFF, 1, 20.0f);
 
-			uint16_t pc = cpu->pc;
-
-			for (cpu->pc = disas_start; cpu->pc < disas_end;)
+			for (uint16_t pc = disas_start; pc < disas_end;)
 			{
 				nk_layout_row_begin(ctx, NK_STATIC, 24, 2);
 
-				uint16_t this_pc = cpu->pc;
+				uint16_t cpu_pc = cpu->pc,
+					this_pc = pc;
 			
 				char addr[6];
-				sprintf(addr, "$%x", this_pc);
+				sprintf(addr, "$%x", pc);
 
 				nk_layout_row_push(ctx, 48);
 				nk_label(ctx, addr, NK_TEXT_LEFT);
 
 				nk_layout_row_push(ctx, 120);
-				char *line = disas_step(cpu);
-				if (pc == this_pc)
+				char *line = disas_step(cpu, &pc);
+				if (cpu_pc == this_pc)
 				{
 					nk_label_colored(ctx, line, NK_TEXT_LEFT, selected);
 				}
@@ -164,8 +165,6 @@
 				}
 				free(line);
 			}
-
-			cpu->pc = pc;
 		}
 		nk_end(ctx);
 
@@ -202,18 +201,19 @@
 			if (nk_button_label(ctx, "Reset"))
 			{
 				puts("cpu reset");
-				reset(cpu);
+				cmd(mq, "reset");
 			}
 
 			nk_layout_row_dynamic(ctx, 30, 2);
 			if (nk_button_label(ctx, "Step"))
 			{
 				printf("step pressed!\n");
-				step(cpu);
+				cmd(mq, "step");
 			}
 
 			if (nk_button_label(ctx, cpu_running ? "Stop" : "Run"))
 			{
+				cmd(mq, cpu_running ? "pause" : "run");
 				cpu_running = !cpu_running;
 				puts(cpu_running ? "cpu running" : "cpu stopped");
 			}
@@ -233,6 +233,8 @@
 	SDL_GL_DeleteContext(glContext);
 	SDL_DestroyWindow(win);
 	SDL_Quit();
+
+	cmd(mq, "quit");
 }
 
 
diff --git a/screen.c b/screen.c
index 4b01adc..7d09daf 100644
--- a/screen.c
+++ b/screen.c
@@ -26,18 +26,20 @@
 	if (!state)
 		return;
 
-	//nk_fill_rect(out, bounds, 0, nk_rgb(255, 0, 0));
+	nk_fill_rect(out, bounds, 0, nk_rgb(0, 0, 0));
 
-	//return;
 
 	for (int i = 0; i < CPU_FB_H; i++)
 	{
 		for (int j = 0; j < CPU_FB_W; j++)
 		{
-			nk_fill_rect(out,
-				nk_rect(bounds.x + i * size, bounds.y + j * size,
-					size, size), 0.0f,
-				byte_to_color(mem[i + CPU_FB_H * j]));
+			if (mem[i + CPU_FB_H * j])
+			{
+				nk_fill_rect(out,
+					nk_rect(bounds.x + i * size, bounds.y + j * size,
+						size, size), 0.0f,
+					byte_to_color(mem[i + CPU_FB_H * j]));
+			}
 		}
 	}
 }