aboutsummaryrefslogtreecommitdiffstats
path: root/src/devices.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices.c')
-rw-r--r--src/devices.c497
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 @@
1static time_t seconds = 0;
2
3typedef enum {
4 CONTROL_CONTROLLER,
5 CONTROL_MOUSE,
6 CONTROL_KEYBOARD,
7} ControlMethod;
8
9const ControlMethod ctrl_methods[] = {
10 CONTROL_METHODS
11};
12static ControlMethod ctrl_idx = 0;
13
14#define MOUSE_DELTA 1
15typedef struct Mouse {
16 int x;
17 int y;
18} Mouse;
19
20// static Uxn u;
21
22static Mouse mouse = {SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2};
23
24int
25uxn_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
34IWRAM_CODE
35u8
36screen_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
46IWRAM_CODE
47void
48screen_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
112u8
113audio_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
126void
127audio_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
144u8
145datetime_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
163u8
164file_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
178void
179file_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
223void
224console_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
238static void
239system_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
266void
267system_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
275u8
276uxn_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
291void
292uxn_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
312IWRAM_CODE
313void
314handle_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