diff options
author | Bad Diode <bd@badd10de.dev> | 2023-08-27 22:52:43 +0200 |
---|---|---|
committer | Bad Diode <bd@badd10de.dev> | 2023-08-27 22:52:43 +0200 |
commit | 8357708a6f73401886bc2bdf405cb19adf419cbc (patch) | |
tree | ad9b1c3d2fed68bd3cadcff1f5fd868040598706 /src/devices.c | |
parent | 941ad8e28efb685e910b38b06f98bc79fb29677f (diff) | |
download | uxngba-8357708a6f73401886bc2bdf405cb19adf419cbc.tar.gz uxngba-8357708a6f73401886bc2bdf405cb19adf419cbc.zip |
Adjust add/sub instructions slightly
Diffstat (limited to 'src/devices.c')
-rw-r--r-- | src/devices.c | 497 |
1 files changed, 497 insertions, 0 deletions
diff --git a/src/devices.c b/src/devices.c new file mode 100644 index 0000000..48d062d --- /dev/null +++ b/src/devices.c | |||
@@ -0,0 +1,497 @@ | |||
1 | static time_t seconds = 0; | ||
2 | |||
3 | typedef enum { | ||
4 | CONTROL_CONTROLLER, | ||
5 | CONTROL_MOUSE, | ||
6 | CONTROL_KEYBOARD, | ||
7 | } ControlMethod; | ||
8 | |||
9 | const ControlMethod ctrl_methods[] = { | ||
10 | CONTROL_METHODS | ||
11 | }; | ||
12 | static ControlMethod ctrl_idx = 0; | ||
13 | |||
14 | #define MOUSE_DELTA 1 | ||
15 | typedef struct Mouse { | ||
16 | int x; | ||
17 | int y; | ||
18 | } Mouse; | ||
19 | |||
20 | // static Uxn u; | ||
21 | |||
22 | static Mouse mouse = {SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2}; | ||
23 | |||
24 | int | ||
25 | uxn_halt(Uxn *u, u8 instr, u8 err, u16 addr) { | ||
26 | (void)u; | ||
27 | txt_printf("HALTED\n"); | ||
28 | txt_printf("I: %lu\n", instr); | ||
29 | txt_printf("E: %lu\n", err); | ||
30 | txt_printf("A: %lu\n", addr); | ||
31 | while (true); | ||
32 | } | ||
33 | |||
34 | IWRAM_CODE | ||
35 | u8 | ||
36 | screen_dei(u8 *d, u8 port) { | ||
37 | // switch(port) { | ||
38 | // case 0x2: return (SCREEN_WIDTH >> 8); | ||
39 | // case 0x3: return (SCREEN_WIDTH); | ||
40 | // case 0x4: return (SCREEN_HEIGHT >> 8); | ||
41 | // case 0x5: return (SCREEN_HEIGHT); | ||
42 | // default: return d[port]; | ||
43 | // } | ||
44 | } | ||
45 | |||
46 | IWRAM_CODE | ||
47 | void | ||
48 | screen_deo(u8 *ram, u8 *d, u8 port) { | ||
49 | // switch(port) { | ||
50 | // case 0xe: { | ||
51 | // u8 ctrl = d[0xe]; | ||
52 | // u8 color = ctrl & 0x3; | ||
53 | // u16 x0 = PEEK2(d + 0x8); | ||
54 | // u16 y0 = PEEK2(d + 0xa); | ||
55 | // u8 *layer = (ctrl & 0x40) ? FG_BACK : BG_BACK; | ||
56 | // if(ctrl & 0x80) { | ||
57 | // u16 x1 = SCREEN_WIDTH - 1; | ||
58 | // u16 y1 = SCREEN_HEIGHT - 1; | ||
59 | // if(ctrl & 0x10) x1 = x0, x0 = 0; | ||
60 | // if(ctrl & 0x20) y1 = y0, y0 = 0; | ||
61 | // PROF(screen_fill(layer, x0, y0, x1, y1, color), ppu_fill_cycles); | ||
62 | // } else { | ||
63 | // PROF(ppu_pixel(layer, x0, y0, color), ppu_pixel_cycles); | ||
64 | // if(d[0x6] & 0x1) POKE2(d + 0x8, x0 + 1); /* auto x+1 */ | ||
65 | // if(d[0x6] & 0x2) POKE2(d + 0xa, y0 + 1); /* auto y+1 */ | ||
66 | // } | ||
67 | // break; | ||
68 | // } | ||
69 | // case 0xf: { | ||
70 | // u16 x, y, dx, dy, addr; | ||
71 | // u8 n, twobpp = !!(d[0xf] & 0x80); | ||
72 | // x = PEEK2(d + 0x8); | ||
73 | // y = PEEK2(d + 0xa); | ||
74 | // addr = PEEK2(d + 0xc); | ||
75 | // n = d[0x6] >> 4; | ||
76 | // dx = (d[0x6] & 0x01) << 3; | ||
77 | // dy = (d[0x6] & 0x02) << 2; | ||
78 | // if(addr > 0x10000 - ((n + 1) << (3 + twobpp))) { | ||
79 | // return; | ||
80 | // } | ||
81 | // u8 *layer = (d[0xf] & 0x40) ? FG_BACK : BG_BACK; | ||
82 | // u8 color = d[0xf] & 0xf; | ||
83 | // u8 flipx = d[0xf] & 0x10; | ||
84 | // u8 flipy = d[0xf] & 0x20; | ||
85 | // for(size_t i = 0; i <= n; i++) { | ||
86 | // u8 *sprite = &ram[addr]; | ||
87 | // if (twobpp) { | ||
88 | // PROF(ppu_2bpp(layer, | ||
89 | // x + dy * i, | ||
90 | // y + dx * i, | ||
91 | // sprite, | ||
92 | // color, | ||
93 | // flipx, flipy), ppu_chr_cycles); | ||
94 | // } else { | ||
95 | // PROF(ppu_1bpp(layer, | ||
96 | // x + dy * i, | ||
97 | // y + dx * i, | ||
98 | // sprite, | ||
99 | // color, | ||
100 | // flipx, flipy), ppu_icn_cycles); | ||
101 | // } | ||
102 | // addr += (d[0x6] & 0x04) << (1 + twobpp); | ||
103 | // } | ||
104 | // POKE2(d + 0xc, addr); /* auto addr+length */ | ||
105 | // POKE2(d + 0x8, x + dx); /* auto x+8 */ | ||
106 | // POKE2(d + 0xa, y + dy); /* auto y+8 */ | ||
107 | // break; | ||
108 | // } | ||
109 | // } | ||
110 | } | ||
111 | |||
112 | u8 | ||
113 | audio_dei(int instance, u8 *d, u8 port) { | ||
114 | // AudioChannel *c = &channels[instance]; | ||
115 | // switch(port) { | ||
116 | // // case 0x4: return apu_get_vu(instance); | ||
117 | // case 0x2: { | ||
118 | // POKE2(d + 0x2, c->pos); | ||
119 | // c->pos <<= 12; // fixed point. | ||
120 | // break; | ||
121 | // } | ||
122 | // } | ||
123 | return d[port]; | ||
124 | } | ||
125 | |||
126 | void | ||
127 | audio_deo(int instance, u8 *d, u8 port, Uxn *u) { | ||
128 | // AudioChannel *c = &channels[instance]; | ||
129 | // if (port == 0xf) { | ||
130 | // u16 length = 0; | ||
131 | // u16 adsr = 0; | ||
132 | // u16 addr = 0; | ||
133 | // u8 pitch = d[0xf] & 0x7f; | ||
134 | // adsr = PEEK2(d + 0x8); | ||
135 | // length = PEEK2(d + 0xa); | ||
136 | // addr = PEEK2(d + 0xc); | ||
137 | // u8 *data = &u->ram[addr]; | ||
138 | // u32 vol = MAX(d[0xe] >> 4, d[0xe] & 0xf) * 4 / 3; | ||
139 | // bool loop = !(d[0xf] & 0x80); | ||
140 | // update_channel(c, data, length, pitch, adsr, vol, loop); | ||
141 | // } | ||
142 | } | ||
143 | |||
144 | u8 | ||
145 | datetime_dei(u8 *d, u8 port) { | ||
146 | struct tm *t = gmtime(&seconds); | ||
147 | switch(port) { | ||
148 | case 0x0: return (t->tm_year + 1900) >> 8; | ||
149 | case 0x1: return (t->tm_year + 1900); | ||
150 | case 0x2: return t->tm_mon; | ||
151 | case 0x3: return t->tm_mday; | ||
152 | case 0x4: return t->tm_hour; | ||
153 | case 0x5: return t->tm_min; | ||
154 | case 0x6: return t->tm_sec; | ||
155 | case 0x7: return t->tm_wday; | ||
156 | case 0x8: return t->tm_yday >> 8; | ||
157 | case 0x9: return t->tm_yday; | ||
158 | case 0xa: return t->tm_isdst; | ||
159 | default: return d[port]; | ||
160 | } | ||
161 | } | ||
162 | |||
163 | u8 | ||
164 | file_dei(u8 id, u8 *d, u8 port) { | ||
165 | // UxnFile *c = &uxn_file[id]; | ||
166 | // u16 res; | ||
167 | // switch(port) { | ||
168 | // case 0xc: | ||
169 | // case 0xd: { | ||
170 | // res = file_read(c, &d[port], 1); | ||
171 | // POKE2(d + 0x2, res); | ||
172 | // break; | ||
173 | // } | ||
174 | // } | ||
175 | return d[port]; | ||
176 | } | ||
177 | |||
178 | void | ||
179 | file_deo(u8 id, u8 *ram, u8 *d, u8 port) { | ||
180 | // u16 a, b, res; | ||
181 | // UxnFile *f = &uxn_file[id]; | ||
182 | // switch(port) { | ||
183 | // case 0x5: { | ||
184 | // a = PEEK2(d + 0x4); | ||
185 | // b = PEEK2(d + 0xa); | ||
186 | // if(b > 0x10000 - a) { | ||
187 | // b = 0x10000 - a; | ||
188 | // } | ||
189 | // res = file_stat(f, &ram[a], b); | ||
190 | // POKE2(d + 0x2, res); | ||
191 | // } break; | ||
192 | // case 0x6: { | ||
193 | // // TODO: no file deletion for now | ||
194 | // // res = file_delete(); | ||
195 | // // POKE2(d + 0x2, res); | ||
196 | // } break; | ||
197 | // case 0x9: { | ||
198 | // a = PEEK2(d + 0x8); | ||
199 | // res = file_init(f, &ram[a]); | ||
200 | // POKE2(d + 0x2, res); | ||
201 | // } break; | ||
202 | // case 0xd: { | ||
203 | // a = PEEK2(d + 0xc); | ||
204 | // b = PEEK2(d + 0xa); | ||
205 | // if(b > 0x10000 - a) { | ||
206 | // b = 0x10000 - a; | ||
207 | // } | ||
208 | // res = file_read(f, &ram[a], b); | ||
209 | // POKE2(d + 0x2, res); | ||
210 | // } break; | ||
211 | // case 0xf: { | ||
212 | // a = PEEK2(d + 0xe); | ||
213 | // b = PEEK2(d + 0xa); | ||
214 | // if(b > 0x10000 - a) { | ||
215 | // b = 0x10000 - a; | ||
216 | // } | ||
217 | // res = file_write(f, &ram[a], b, d[0x7]); | ||
218 | // POKE2(d + 0x2, res); | ||
219 | // } break; | ||
220 | // } | ||
221 | } | ||
222 | |||
223 | void | ||
224 | console_deo(u8 *d, u8 port) { | ||
225 | // switch(port) { | ||
226 | // case 0x8: | ||
227 | // txt_putc(d[port]); | ||
228 | // return; | ||
229 | // case 0x9: | ||
230 | // txt_printf("ERROR: %c"); | ||
231 | // txt_putc(d[port]); | ||
232 | // return; | ||
233 | // } | ||
234 | } | ||
235 | |||
236 | #define RAM_PAGES 0x10 | ||
237 | |||
238 | static void | ||
239 | system_cmd(u8 *ram, u16 addr) { | ||
240 | if(ram[addr] == 0x01) { | ||
241 | // NOTE: Handle rom paging on a case by case basis if a rom has to be | ||
242 | // split in multiple chunks. The GBA compiler doesn't like allocating | ||
243 | // big arrays, but it's fine if we split it into chunks of 64KB, for | ||
244 | // example. | ||
245 | // | ||
246 | // u16 i, length = PEEK2(ram + addr + 1); | ||
247 | // u16 a_page = PEEK2(ram + addr + 1 + 2); | ||
248 | // u16 a_addr = PEEK2(ram + addr + 1 + 4); | ||
249 | // u16 b_addr = PEEK2(ram + addr + 1 + 8); | ||
250 | // u8 *rom = uxn_rom; | ||
251 | // for(i = 0; i < length; i++) { | ||
252 | // switch (a_page % RAM_PAGES) { | ||
253 | // case 0: { rom = uxn_rom; } break; | ||
254 | // case 1: { rom = uxn_rom_2; } break; | ||
255 | // case 2: { rom = uxn_rom_3; } break; | ||
256 | // case 3: { rom = uxn_rom_4; } break; | ||
257 | // case 4: { rom = uxn_rom_5; } break; | ||
258 | // case 5: { rom = uxn_rom_6; } break; | ||
259 | // case 6: { rom = uxn_rom_7; } break; | ||
260 | // } | ||
261 | // ram[(u16)(b_addr + i)] = rom[(u16)(a_addr + i)]; | ||
262 | // } | ||
263 | } | ||
264 | } | ||
265 | |||
266 | void | ||
267 | system_deo(Uxn *u, u8 *d, u8 port) { | ||
268 | // switch(port) { | ||
269 | // case 0x3: { | ||
270 | // system_cmd(u->ram, PEEK2(d + 2)); | ||
271 | // } break; | ||
272 | // } | ||
273 | } | ||
274 | |||
275 | u8 | ||
276 | uxn_dei(Uxn *u, u8 addr) { | ||
277 | u8 p = addr & 0x0f, d = addr & 0xf0; | ||
278 | switch(d) { | ||
279 | case 0x20: return screen_dei(&u->dev[d], p); | ||
280 | case 0x30: return audio_dei(0, &u->dev[d], p); | ||
281 | case 0x40: return audio_dei(1, &u->dev[d], p); | ||
282 | case 0x50: return audio_dei(2, &u->dev[d], p); | ||
283 | case 0x60: return audio_dei(3, &u->dev[d], p); | ||
284 | case 0xa0: return file_dei(0, &u->dev[d], p); | ||
285 | case 0xb0: return file_dei(1, &u->dev[d], p); | ||
286 | case 0xc0: return datetime_dei(&u->dev[d], p); | ||
287 | } | ||
288 | return u->dev[addr]; | ||
289 | } | ||
290 | |||
291 | void | ||
292 | uxn_deo(Uxn *u, u8 addr) { | ||
293 | u8 p = addr & 0x0f, d = addr & 0xf0; | ||
294 | switch(d) { | ||
295 | case 0x00: | ||
296 | system_deo(u, &u->dev[d], p); | ||
297 | if(p > 0x7 && p < 0xe) { | ||
298 | putcolors(&u->dev[0x8]); | ||
299 | } | ||
300 | break; | ||
301 | case 0x10: console_deo(&u->dev[d], p); break; | ||
302 | case 0x20: screen_deo(u->ram, &u->dev[d], p); break; | ||
303 | case 0x30: audio_deo(0, &u->dev[d], p, u); break; | ||
304 | case 0x40: audio_deo(1, &u->dev[d], p, u); break; | ||
305 | case 0x50: audio_deo(2, &u->dev[d], p, u); break; | ||
306 | case 0x60: audio_deo(3, &u->dev[d], p, u); break; | ||
307 | case 0xa0: file_deo(0, u->ram, &u->dev[d], p); break; | ||
308 | case 0xb0: file_deo(1, u->ram, &u->dev[d], p); break; | ||
309 | } | ||
310 | } | ||
311 | |||
312 | IWRAM_CODE | ||
313 | void | ||
314 | handle_input(Uxn *u) { | ||
315 | // poll_keys(); | ||
316 | // if (key_tap(KEY_SELECT)) { | ||
317 | // // Reset control variables on method switch. | ||
318 | // switch (ctrl_methods[ctrl_idx]) { | ||
319 | // case CONTROL_CONTROLLER: { | ||
320 | // u8 *d = &u->dev[0x80]; | ||
321 | // d[2] = 0; | ||
322 | // uxn_eval(u, PEEK2(d)); | ||
323 | // d[3] = 0; | ||
324 | // } break; | ||
325 | // case CONTROL_MOUSE: { | ||
326 | // u8 *d = &u->dev[0x90]; | ||
327 | // d[6] = 0; | ||
328 | // d[7] = 0; | ||
329 | // POKE2(d + 0x2, -10); | ||
330 | // POKE2(d + 0x4, -10); | ||
331 | // uxn_eval(u, PEEK2(d)); | ||
332 | // } break; | ||
333 | // case CONTROL_KEYBOARD: { | ||
334 | // toggle_keyboard(); | ||
335 | // } break; | ||
336 | // } | ||
337 | |||
338 | // // Update ctrl_idx. | ||
339 | // ctrl_idx = (ctrl_idx + 1 > (int)LEN(ctrl_methods) - 1) ? 0 : ctrl_idx + 1; | ||
340 | |||
341 | // // Initialize controller variables here. | ||
342 | // if (ctrl_methods[ctrl_idx] == CONTROL_KEYBOARD) { | ||
343 | // toggle_keyboard(); | ||
344 | // } | ||
345 | // } | ||
346 | |||
347 | // if (ctrl_methods[ctrl_idx] == CONTROL_CONTROLLER) { | ||
348 | // u8 *d = &u->dev[0x80]; | ||
349 | // // TODO: We don't need ifs if we use KEY_INPUTS directly and maybe just | ||
350 | // // swap some things if needed. | ||
351 | // u8 *flag = &d[2]; | ||
352 | // if (key_tap(KEY_A)) { | ||
353 | // *flag |= 0x01; | ||
354 | // } else { | ||
355 | // *flag &= ~0x01; | ||
356 | // } | ||
357 | // if (key_tap(KEY_B)) { | ||
358 | // *flag |= 0x02; | ||
359 | // } else { | ||
360 | // *flag &= ~0x02; | ||
361 | // } | ||
362 | // if (key_tap(KEY_L)) { | ||
363 | // *flag |= 0x04; | ||
364 | // } else { | ||
365 | // *flag &= ~0x04; | ||
366 | // } | ||
367 | // if (key_tap(KEY_R)) { | ||
368 | // *flag |= 0x08; | ||
369 | // } else { | ||
370 | // *flag &= ~0x08; | ||
371 | // } | ||
372 | // if (key_tap(KEY_UP)) { | ||
373 | // *flag |= 0x10; | ||
374 | // } else { | ||
375 | // *flag &= ~0x10; | ||
376 | // } | ||
377 | // if (key_tap(KEY_DOWN)) { | ||
378 | // *flag |= 0x20; | ||
379 | // } else { | ||
380 | // *flag &= ~0x20; | ||
381 | // } | ||
382 | // if (key_tap(KEY_LEFT)) { | ||
383 | // *flag |= 0x40; | ||
384 | // } else { | ||
385 | // *flag &= ~0x40; | ||
386 | // } | ||
387 | // if (key_tap(KEY_RIGHT)) { | ||
388 | // *flag |= 0x80; | ||
389 | // } else { | ||
390 | // *flag &= ~0x80; | ||
391 | // } | ||
392 | |||
393 | // if (key_prev != key_curr) { | ||
394 | // uxn_eval(u, PEEK2(d)); | ||
395 | // } | ||
396 | // d[3] = 0; | ||
397 | // } else if (ctrl_methods[ctrl_idx] == CONTROL_MOUSE) { | ||
398 | // u8 *d = &u->dev[0x90]; | ||
399 | // // Detect "mouse key press". | ||
400 | // u8 flag = d[6]; | ||
401 | // bool event = false; | ||
402 | // if (key_tap(KEY_B)) { | ||
403 | // event = true; | ||
404 | // flag |= 0x01; | ||
405 | // } else if (key_released(KEY_B)) { | ||
406 | // event = true; | ||
407 | // flag &= ~0x01; | ||
408 | // } | ||
409 | // if (key_tap(KEY_A)) { | ||
410 | // event = true; | ||
411 | // flag |= 0x10; | ||
412 | // } else if (key_released(KEY_A)) { | ||
413 | // event = true; | ||
414 | // flag &= ~0x10; | ||
415 | // } | ||
416 | |||
417 | // // Handle chording. | ||
418 | // d[6] = flag; | ||
419 | // if(flag == 0x10 && (d[6] & 0x01)) { | ||
420 | // d[7] = 0x01; | ||
421 | // } | ||
422 | // if(flag == 0x01 && (d[6] & 0x10)) { | ||
423 | // d[7] = 0x10; | ||
424 | // } | ||
425 | |||
426 | // // Detect mouse movement. | ||
427 | // if (key_pressed(KEY_UP)) { | ||
428 | // event = true; | ||
429 | // mouse.y = CLAMP(mouse.y - MOUSE_DELTA, 0, SCREEN_HEIGHT - 8); | ||
430 | // } else if (key_pressed(KEY_DOWN)) { | ||
431 | // event = true; | ||
432 | // mouse.y = CLAMP(mouse.y + MOUSE_DELTA, 0, SCREEN_HEIGHT - 8); | ||
433 | // } | ||
434 | // if (key_pressed(KEY_LEFT)) { | ||
435 | // event = true; | ||
436 | // mouse.x = CLAMP(mouse.x - MOUSE_DELTA, 0, SCREEN_WIDTH - 8); | ||
437 | // } else if (key_pressed(KEY_RIGHT)) { | ||
438 | // event = true; | ||
439 | // mouse.x = CLAMP(mouse.x + MOUSE_DELTA, 0, SCREEN_WIDTH - 8); | ||
440 | // } | ||
441 | |||
442 | // // Eval mouse. | ||
443 | // POKE2(d + 0x2, mouse.x); | ||
444 | // POKE2(d + 0x4, mouse.y); | ||
445 | // if (event) { | ||
446 | // uxn_eval(u, PEEK2(d)); | ||
447 | // } | ||
448 | // } else if (ctrl_methods[ctrl_idx] == CONTROL_KEYBOARD) { | ||
449 | // u8 *d = &u->dev[0x80]; | ||
450 | // if (key_tap(KEY_LEFT)) { | ||
451 | // update_cursor(cursor_position - 1); | ||
452 | // } else if (key_tap(KEY_RIGHT)) { | ||
453 | // update_cursor(cursor_position + 1); | ||
454 | // } | ||
455 | // if (key_tap(KEY_UP) && cursor_position >= KEYBOARD_ROW_SIZE) { | ||
456 | // update_cursor(cursor_position - KEYBOARD_ROW_SIZE); | ||
457 | // } else if (key_tap(KEY_DOWN) | ||
458 | // && cursor_position < LEN(keyboard) - KEYBOARD_ROW_SIZE) { | ||
459 | // update_cursor(cursor_position + KEYBOARD_ROW_SIZE); | ||
460 | // } | ||
461 | // if (key_tap(KEY_B)) { | ||
462 | // u8 symbol = keyboard[cursor_position].symbol; | ||
463 | // switch (symbol) { | ||
464 | // case 0x7f: { | ||
465 | // // Backspace. | ||
466 | // d[3] = 0x08; | ||
467 | // } break; | ||
468 | // case 0x14: { | ||
469 | // // New line. | ||
470 | // d[3] = 0x0d; | ||
471 | // } break; | ||
472 | // case 0x18: { | ||
473 | // // Arrow up. | ||
474 | // d[2] = 0x10; | ||
475 | // } break; | ||
476 | // case 0x19: { | ||
477 | // // Arrow down. | ||
478 | // d[2] = 0x20; | ||
479 | // } break; | ||
480 | // case 0x1b: { | ||
481 | // // Arrow left. | ||
482 | // d[2] = 0x40; | ||
483 | // } break; | ||
484 | // case 0x1a: { | ||
485 | // // Arrow right. | ||
486 | // d[2] = 0x80; | ||
487 | // } break; | ||
488 | // default: { | ||
489 | // d[3] = symbol; | ||
490 | // } break; | ||
491 | // } | ||
492 | // uxn_eval(u, PEEK2(d)); | ||
493 | // d[3] = 0; | ||
494 | // } | ||
495 | // } | ||
496 | } | ||
497 | |||