blob: 64769dc4deec6a9fd26cedc4b0f8a05ecfe686ff [file] [log] [blame]
swissChilidbbd5402020-08-07 15:07:39 -07001#include "gui.h"
swissChili1970cb82020-08-10 13:22:39 -07002#include "common.h"
swissChilidbbd5402020-08-07 15:07:39 -07003
4#include <GL/glew.h>
5#include <SDL2/SDL.h>
6#include <SDL2/SDL_opengl.h>
7
8#define NK_INCLUDE_FIXED_TYPES
9#define NK_INCLUDE_STANDARD_IO
10#define NK_INCLUDE_STANDARD_VARARGS
11#define NK_INCLUDE_DEFAULT_ALLOCATOR
12#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
13#define NK_INCLUDE_FONT_BAKING
14#define NK_INCLUDE_DEFAULT_FONT
15#define NK_IMPLEMENTATION
16#define NK_SDL_GL3_IMPLEMENTATION
17#include "nuklear/nuklear.h"
18#include "nuklear/demo/sdl_opengl3/nuklear_sdl_gl3.h"
swissChili94ba1f52020-08-08 11:39:10 -070019#undef SCREEN_ONLY_SDL
swissChilibb478f12020-08-07 20:45:07 -070020#include "screen.h"
swissChilidbbd5402020-08-07 15:07:39 -070021
22#define WINDOW_WIDTH 720
23#define WINDOW_HEIGHT 640
24#define MAX_VERTEX_MEMORY 512 * 1024
25#define MAX_ELEMENT_MEMORY 128 * 1024
26
swissChilic6b4f7e2020-08-09 16:36:36 -070027typedef struct
swissChilidbbd5402020-08-07 15:07:39 -070028{
swissChilic6b4f7e2020-08-09 16:36:36 -070029 cpu_t *cpu;
30 mqd_t mq;
31} gui_arg_t;
32
swissChili1970cb82020-08-10 13:22:39 -070033static void cmd(mqd_t mq, char *msg)
34{
35 mq_send(mq, msg, strlen(msg) + 1, 2);
36}
37
swissChili90db50a2020-08-11 14:17:14 -070038#define cmdf(mq, buffer, pattern, args...) \
39 { \
40 sprintf(buffer, pattern, ##args); \
41 cmd(mq, buffer); \
42 }
43
swissChilic6b4f7e2020-08-09 16:36:36 -070044void gui(gui_arg_t *arg)
45{
46 cpu_t *cpu = arg->cpu;
47 mqd_t mq = arg->mq;
48
49 free(arg);
50
swissChilidbbd5402020-08-07 15:07:39 -070051 SDL_Window *win;
52 SDL_GLContext glContext;
53 int win_width, win_height;
54 bool running = true;
55 bool cpu_running = false;
56
57 struct nk_context *ctx;
swissChilic51e9222020-08-07 16:09:14 -070058 struct nk_colorf bg =
59 {
60 .r = 0.29f,
61 .g = 0.28f,
62 .b = 0.50f,
63 .a = 1.0f,
64 };
swissChilie7ee6da2020-08-08 16:14:21 -070065 struct nk_color
66 selected = nk_rgb(28, 234, 79),
67 red = nk_rgb(226, 56, 76);
swissChilic51e9222020-08-07 16:09:14 -070068
swissChilibb478f12020-08-07 20:45:07 -070069 uint16_t disas_start = 0x600,
70 disas_end = 0x600 + 32;
71
72 uint8_t screen_scale = 4;
swissChilidbbd5402020-08-07 15:07:39 -070073
74 SDL_SetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED, "0");
75 SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_EVENTS);
76 SDL_GL_SetAttribute (SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG);
77 SDL_GL_SetAttribute (SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
78 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
79 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
80 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
81 win = SDL_CreateWindow("6502",
82 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
swissChiliabccdfc2021-01-08 21:39:12 -080083 WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_OPENGL|SDL_WINDOW_SHOWN|SDL_WINDOW_ALLOW_HIGHDPI|SDL_WINDOW_RESIZABLE);
swissChilidbbd5402020-08-07 15:07:39 -070084 glContext = SDL_GL_CreateContext(win);
85 SDL_GetWindowSize(win, &win_width, &win_height);
86
87 /* OpenGL setup */
88 glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
89 glewExperimental = 1;
90 if (glewInit() != GLEW_OK) {
swissChili1970cb82020-08-10 13:22:39 -070091 THROW("Failed to setup GLEW\n");
swissChilidbbd5402020-08-07 15:07:39 -070092 }
93
94 ctx = nk_sdl_init(win);
95
96 struct nk_font_atlas *atlas;
97 nk_sdl_font_stash_begin(&atlas);
98 struct nk_font *font = nk_font_atlas_add_default(atlas, 16, NULL);
99 nk_sdl_font_stash_end();
100 //nk_style_load_all_cursors(ctx, atlas->cursors);
101 nk_style_set_font(ctx, &font->handle);
102
swissChilidbbd5402020-08-07 15:07:39 -0700103 while (running)
104 {
105 SDL_Event evt;
106 nk_input_begin(ctx);
107 while (SDL_PollEvent(&evt))
108 {
swissChili4bccd442020-08-11 13:55:10 -0700109 if (evt.type == SDL_QUIT)
110 goto cleanup;
swissChilidbbd5402020-08-07 15:07:39 -0700111 nk_sdl_handle_event(&evt);
112 }
113 nk_input_end(ctx);
114
swissChilidbbd5402020-08-07 15:07:39 -0700115 if (!cpu->running)
116 cpu_running = false;
117
swissChilibb478f12020-08-07 20:45:07 -0700118 if (nk_begin(ctx, "Registers", nk_rect(50, 300, 500, 90),
swissChilidbbd5402020-08-07 15:07:39 -0700119 NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
120 NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
121 {
122 nk_layout_row_dynamic(ctx, 30, 4);
swissChili1970cb82020-08-10 13:22:39 -0700123 uint16_t pc = nk_propertyi(ctx, "PC", 0, cpu->pc, 0xFFFF, 1, 20.0f);
124 uint8_t rega = nk_propertyi(ctx, "A", 0, cpu->regs[A], 0xFF, 1, 20.0f),
125 regx = nk_propertyi(ctx, "X", 0, cpu->regs[X], 0xFF, 1, 20.0f),
126 regy = nk_propertyi(ctx, "Y", 0, cpu->regs[Y], 0xFF, 1, 20.0f);
swissChili90db50a2020-08-11 14:17:14 -0700127
128 char buffer[64];
129
130 if (pc != cpu->pc)
131 cmdf(mq, buffer, "set PC #$%x", pc);
132 if (rega != cpu->regs[A])
133 cmdf(mq, buffer, "set A #$%x", rega);
134 if (regx != cpu->regs[X])
135 cmdf(mq, buffer, "set X #$%x", regx);
136 if (regy != cpu->regs[Y])
137 cmdf(mq, buffer, "set Y #$%x", regy);
swissChilidbbd5402020-08-07 15:07:39 -0700138 }
139 nk_end(ctx);
140
swissChilibb478f12020-08-07 20:45:07 -0700141 if (nk_begin(ctx, "Screen", nk_rect(50, 400, 150, 220),
142 NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
143 NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
144 {
145 nk_layout_row_dynamic(ctx, 24, 1);
swissChili1970cb82020-08-10 13:22:39 -0700146 screen_scale = nk_propertyi(ctx, "Scale", 1, screen_scale, 16, 1, 1);
swissChili94ba1f52020-08-08 11:39:10 -0700147
swissChilibb478f12020-08-07 20:45:07 -0700148 nk_layout_row_static(ctx, screen_scale * 32, screen_scale * 32, 1);
149 screen(ctx, cpu->mem + CPU_FB_ADDR, screen_scale);
150 }
151 nk_end(ctx);
152
153 if (nk_begin(ctx, "Disassembler", nk_rect(330, 50, 300, 200),
swissChilic51e9222020-08-07 16:09:14 -0700154 NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
155 NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
156 {
157 nk_layout_row_dynamic(ctx, 30, 2);
158 disas_start = nk_propertyi(ctx, "Start", 0, disas_start, 0xFFFF, 1, 20.0f);
159 disas_end = nk_propertyi(ctx, "End", 0, disas_end, 0xFFFF, 1, 20.0f);
160
swissChili1970cb82020-08-10 13:22:39 -0700161 for (uint16_t pc = disas_start; pc < disas_end;)
swissChilic51e9222020-08-07 16:09:14 -0700162 {
163 nk_layout_row_begin(ctx, NK_STATIC, 24, 2);
164
swissChili1970cb82020-08-10 13:22:39 -0700165 uint16_t cpu_pc = cpu->pc,
166 this_pc = pc;
swissChilic51e9222020-08-07 16:09:14 -0700167
168 char addr[6];
swissChili1970cb82020-08-10 13:22:39 -0700169 sprintf(addr, "$%x", pc);
swissChilic51e9222020-08-07 16:09:14 -0700170
171 nk_layout_row_push(ctx, 48);
172 nk_label(ctx, addr, NK_TEXT_LEFT);
173
174 nk_layout_row_push(ctx, 120);
swissChili1970cb82020-08-10 13:22:39 -0700175 char *line = disas_step(cpu, &pc);
176 if (cpu_pc == this_pc)
swissChilic51e9222020-08-07 16:09:14 -0700177 {
178 nk_label_colored(ctx, line, NK_TEXT_LEFT, selected);
179 }
180 else
181 {
182 nk_label(ctx, line, NK_TEXT_LEFT);
183 }
184 free(line);
185 }
swissChilic51e9222020-08-07 16:09:14 -0700186 }
187 nk_end(ctx);
188
swissChilie7ee6da2020-08-08 16:14:21 -0700189 if (nk_begin(ctx, "Stack", nk_rect(250, 250, 230, 350),
190 NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
191 NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
192 {
193 nk_layout_row_static(ctx, 24, 48, 2);
swissChilib04a4022020-08-09 12:51:00 -0700194 for (int i = 0xFF; i >= 0; i--)
swissChilie7ee6da2020-08-08 16:14:21 -0700195 {
196 char line[6];
197 sprintf(line, "$%x", 0x100 + i);
198 nk_label(ctx, line, NK_TEXT_LEFT);
199
200 sprintf(line, "$%x", cpu->mem[0x100 + i]);
201 if (i == cpu->regs[SP])
202 {
203 nk_label_colored(ctx, line, NK_TEXT_LEFT, selected);
204 }
205 else
206 {
207 nk_label(ctx, line, NK_TEXT_LEFT);
208 }
209 }
210 }
211 nk_end(ctx);
212
swissChilidbbd5402020-08-07 15:07:39 -0700213 if (nk_begin(ctx, "Debugger", nk_rect(50, 50, 230, 150),
214 NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
215 NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
216 {
217 nk_layout_row_dynamic(ctx, 30, 2);
218 nk_label(ctx, cpu->running ? "CPU Running" : "CPU Halted", NK_TEXT_LEFT);
219 if (nk_button_label(ctx, "Reset"))
220 {
221 puts("cpu reset");
swissChili1970cb82020-08-10 13:22:39 -0700222 cmd(mq, "reset");
swissChilidbbd5402020-08-07 15:07:39 -0700223 }
224
225 nk_layout_row_dynamic(ctx, 30, 2);
226 if (nk_button_label(ctx, "Step"))
227 {
228 printf("step pressed!\n");
swissChili1970cb82020-08-10 13:22:39 -0700229 cmd(mq, "step");
swissChilidbbd5402020-08-07 15:07:39 -0700230 }
231
232 if (nk_button_label(ctx, cpu_running ? "Stop" : "Run"))
233 {
swissChili1970cb82020-08-10 13:22:39 -0700234 cmd(mq, cpu_running ? "pause" : "run");
swissChilidbbd5402020-08-07 15:07:39 -0700235 cpu_running = !cpu_running;
236 puts(cpu_running ? "cpu running" : "cpu stopped");
237 }
238 }
239 nk_end(ctx);
240
241 SDL_GetWindowSize(win, &win_width, &win_height);
242 glViewport(0, 0, win_width, win_height);
243 glClear(GL_COLOR_BUFFER_BIT);
244 glClearColor(bg.r, bg.g, bg.b, bg.a);
245 nk_sdl_render(NK_ANTI_ALIASING_ON, MAX_VERTEX_MEMORY, MAX_ELEMENT_MEMORY);
246 SDL_GL_SwapWindow(win);
247 }
248
249cleanup:
250 nk_sdl_shutdown();
251 SDL_GL_DeleteContext(glContext);
252 SDL_DestroyWindow(win);
253 SDL_Quit();
swissChili1970cb82020-08-10 13:22:39 -0700254
255 cmd(mq, "quit");
swissChili4bccd442020-08-11 13:55:10 -0700256
257 printf("Cleaned up GUI\n");
swissChilidbbd5402020-08-07 15:07:39 -0700258}
swissChilic6b4f7e2020-08-09 16:36:36 -0700259
260
261void start_gui(mqd_t mq, cpu_t *cpu)
262{
263 pthread_t gui_thread;
264 gui_arg_t *arg = malloc(sizeof(gui_arg_t));
265 arg->cpu = cpu;
266 arg->mq = mq;
267 pthread_create(&gui_thread, NULL, (void *(*)(void *))&gui, arg);
268}