Add disassembler window
diff --git a/cpu.c b/cpu.c
index cd2b253..40fb567 100644
--- a/cpu.c
+++ b/cpu.c
@@ -528,55 +528,59 @@
 	}
 }
 
-void dump_inst(cpu_t *cpu, const char *mn, uint16_t addr, uint8_t am)
+int dump_inst(cpu_t *cpu, char *buf, const char *mn, uint16_t addr, uint8_t am)
 {
-	printf("\t%s\t", mn);
+	char *end = buf;
+	end += sprintf(end, "%s ", mn);
 
 	switch (am)
 	{
 		case AM_IMM:
-			printf("#");
+			end += sprintf(end, "#");
 		case AM_REL:
 		case AM_ABS:
 		case AM_ZP:
-			printf("$%x", addr);
+			end += sprintf(end, "$%x", addr);
 			break;
 
 		case AM_IND:
-			printf("($%x)", addr);
+			end += sprintf(end, "($%x)", addr);
 			break;
 
 		case AM_AX:
 		case AM_ZPX:
-			printf("$%x, X", addr);
+			end += sprintf(end, "$%x, X", addr);
 			break;
 
 		case AM_AY:
 		case AM_ZPY:
-			printf("$%x, Y", addr);
+			end += sprintf(end, "$%x, Y", addr);
 			break;
 
 		case AM_ZIX:
-			printf("($%x, X)", addr);
+			end += sprintf(end, "($%x, X)", addr);
 			break;
 
 		case AM_ZIY:
-			printf("($%x), Y", addr);
+			end += sprintf(end, "($%x), Y", addr);
 			break;
 	}
 
-	printf("\n");
+	return end - buf;
 }
 
-void disas_step(cpu_t *cpu)
+char *disas_step(cpu_t *cpu)
 {
-	printf("$%x", cpu->pc);
+	char *buffer = malloc(80);
+	char *end = buffer;
+
+	// end += sprintf(buffer, "$%x", cpu->pc);
 	uint8_t op = cpu->mem[cpu->pc++];
 	switch (op)
 	{
 #define INST(mn, am, op) \
 		case op: \
-			dump_inst(cpu, #mn, \
+			end += dump_inst(cpu, end, #mn, \
 				fetch_addr(cpu, am, FETCH_NO_INDIRECTION).ptr, am); \
 			break;
 
@@ -585,26 +589,41 @@
 #undef INST
 
 		default:
-			warn("\tUndefined opcode %x", op);
+			end += sprintf(end, "Undefined opcode %x", op);
 	}
+
+	*end = 0;
+
+	return buffer;
 }
 
 void disas_num(cpu_t *cpu, uint16_t num)
 {
+	uint16_t pc = cpu->pc;
 	for (int i = 0; i < num; i++)
 	{
-		disas_step(cpu);
+		uint16_t last_pc = cpu->pc;
+		char *line = disas_step(cpu);
+		printf("$%x\t%s\n", last_pc, line);
+		free(line);
 	}
+	cpu->pc = pc;
 }
 
 void disas(cpu_t *cpu)
 {
+	uint16_t pc = cpu->pc;
 	// Raw binary, no way to know what's code what isn't
 	while (cpu->pc < 0xFFFF)
 	{
-		disas_step(cpu);
+		uint16_t last_pc = cpu->pc;
+		char *line = disas_step(cpu);
+		printf("$%x\t%s\n", last_pc, line);
+		free(line);
 	}
+	cpu->pc = pc;
 }
+
 void run(cpu_t *cpu)
 {
 	while (cpu->running)
diff --git a/cpu.h b/cpu.h
index afaae30..4629b14 100644
--- a/cpu.h
+++ b/cpu.h
@@ -139,8 +139,8 @@
 void free_cpu(cpu_t *cpu);
 void die(const char *message);
 void reset(cpu_t *cpu);
-// IMPORTANT: all disassembly functions mess with the PC
 void disas(cpu_t *cpu);
 void disas_num(cpu_t *cpu, uint16_t num);
-void disas_step(cpu_t *cpu);
+// Buffer must be freed by user
+char *disas_step(cpu_t *cpu);
 void run(cpu_t *cpu);
diff --git a/gui.c b/gui.c
index 7fe5d69..a03d948 100644
--- a/gui.c
+++ b/gui.c
@@ -30,7 +30,23 @@
 	bool cpu_running = false;
 
 	struct nk_context *ctx;
-	struct nk_colorf bg;
+	struct nk_colorf bg =
+	{
+		.r = 0.29f,
+		.g = 0.28f,
+		.b = 0.50f,
+		.a = 1.0f,
+	};
+	struct nk_color selected =
+	{
+		.r = 28,
+		.g = 234,
+		.b = 79,
+		.a = 255,
+	};
+
+	uint16_t disas_start = 0,
+		disas_end = 32;
 
 	SDL_SetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED, "0");
 	SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_EVENTS);
@@ -62,8 +78,6 @@
 	//nk_style_load_all_cursors(ctx, atlas->cursors);
 	nk_style_set_font(ctx, &font->handle);
 
-	bg.r = 0.29f, bg.g = 0.28f, bg.b = 0.50f, bg.a = 1.0f;
-
 	while (running)
 	{
 		SDL_Event evt;
@@ -86,14 +100,6 @@
 			NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
 		{
 			nk_layout_row_dynamic(ctx, 30, 4);
-			char regpc[12],
-				rega[12],
-				regx[12],
-				regy[12];
-			sprintf(regpc, "PC: $%x", cpu->pc);
-			sprintf(rega, "A: $%x", cpu->regs[A]);
-			sprintf(regx, "X: $%x", cpu->regs[X]);
-			sprintf(regy, "Y: $%x", cpu->regs[Y]);
 			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);
@@ -101,6 +107,45 @@
 		}
 		nk_end(ctx);
 
+		if (nk_begin(ctx, "Disassembler", nk_rect(330, 50, 250, 200),
+			NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
+			NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
+		{
+			nk_layout_row_dynamic(ctx, 30, 2);
+			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;)
+			{
+				nk_layout_row_begin(ctx, NK_STATIC, 24, 2);
+
+				uint16_t this_pc = cpu->pc;
+			
+				char addr[6];
+				sprintf(addr, "$%x", this_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)
+				{
+					nk_label_colored(ctx, line, NK_TEXT_LEFT, selected);
+				}
+				else
+				{
+					nk_label(ctx, line, NK_TEXT_LEFT);
+				}
+				free(line);
+			}
+
+			cpu->pc = pc;
+		}
+		nk_end(ctx);
+
 		if (nk_begin(ctx, "Debugger", nk_rect(50, 50, 230, 150),
 			NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
 			NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
diff --git a/main.c b/main.c
index b4b05e7..9a03f95 100644
--- a/main.c
+++ b/main.c
@@ -88,7 +88,7 @@
 	}
 	else if (disflag)
 	{
-		disas(&cpu);
+		disas_num(&cpu, 12);
 	}
 	else if (runflag)
 	{