aboutsummaryrefslogtreecommitdiffstats
path: root/src/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.c')
-rw-r--r--src/main.c494
1 files changed, 268 insertions, 226 deletions
diff --git a/src/main.c b/src/main.c
index a2661cd..beb65e3 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,12 +1,12 @@
1/* 1/*
2Copyright (c) 2021 Bad Diode 2 Copyright (c) 2021 Bad Diode
3 3
4Permission to use, copy, modify, and distribute this software for any 4 Permission to use, copy, modify, and distribute this software for any
5purpose with or without fee is hereby granted, provided that the above 5 purpose with or without fee is hereby granted, provided that the above
6copyright notice and this permission notice appear in all copies. 6 copyright notice and this permission notice appear in all copies.
7 7
8THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9WITH REGARD TO THIS SOFTWARE. 9 WITH REGARD TO THIS SOFTWARE.
10*/ 10*/
11 11
12#include <string.h> 12#include <string.h>
@@ -39,8 +39,10 @@ WITH REGARD TO THIS SOFTWARE.
39 39
40#ifdef PROF_ENABLE 40#ifdef PROF_ENABLE
41#if PROF_ENABLE == 0 41#if PROF_ENABLE == 0
42#define TEXT_ENABLE 1
42#define PROF(F,VAR) (profile_start(),(F),(VAR) = profile_stop()) 43#define PROF(F,VAR) (profile_start(),(F),(VAR) = profile_stop())
43#elif PROF_ENABLE == 1 44#elif PROF_ENABLE == 1
45#define TEXT_ENABLE 1
44#define PROF(F,VAR) (profile_start(),(F),(VAR) = MAX(profile_stop(), (VAR))) 46#define PROF(F,VAR) (profile_start(),(F),(VAR) = MAX(profile_stop(), (VAR)))
45#endif 47#endif
46#ifndef PROF_SHOW_X 48#ifndef PROF_SHOW_X
@@ -90,219 +92,254 @@ typedef struct Mouse {
90 int y; 92 int y;
91} Mouse; 93} Mouse;
92 94
95EWRAM_BSS
96static u8 umem[0x10300];
97
98static Uxn u;
93static Ppu ppu; 99static Ppu ppu;
94static Device *devscreen;
95static Device *devctrl;
96static Device *devmouse;
97static Device *devaudio;
98 100
99static Mouse mouse = {SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2}; 101static Mouse mouse = {SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2};
100 102
101void 103int
102nil_talk(Device *d, u8 b0, u8 w) { 104uxn_halt(Uxn *u, u8 instr, u8 err, u16 addr) {
103 (void)d; 105 (void)u;
104 (void)b0; 106 txt_printf("HALTED\n");
105 (void)w; 107 txt_printf("I: %lu\n", instr);
106} 108 txt_printf("E: %lu\n", err);
107 109 txt_printf("A: %lu\n", addr);
108void 110 while (true);
109console_talk(Device *d, u8 b0, u8 w) {
110 char stmp[2];
111 if(!w) {
112 return;
113 }
114 switch(b0) {
115 case 0x8: stmp[0] = d->dat[0x8]; stmp[1] = 0; txt_printf(stmp); break;
116 case 0x9: txt_printf("0x%02x", d->dat[0x9]); break;
117 case 0xb: txt_printf("0x%04x", mempeek16(d->dat, 0xa)); break;
118 case 0xd: txt_printf("%s", &d->mem[mempeek16(d->dat, 0xc)]); break;
119 }
120} 111}
121 112
122void 113IWRAM_CODE
123system_talk(Device *d, u8 b0, u8 w) { 114u8
124 if(!w) { 115screen_dei(u8 *d, u8 port) {
125 d->dat[0x2] = d->u->wst.ptr; 116 switch(port) {
126 d->dat[0x3] = d->u->rst.ptr; 117 case 0x2: return (SCREEN_WIDTH >> 8);
127 } else { 118 case 0x3: return (SCREEN_WIDTH);
128 putcolors(&d->dat[0x8]); 119 case 0x4: return (SCREEN_HEIGHT >> 8);
120 case 0x5: return (SCREEN_HEIGHT);
121 default: return d[port];
129 } 122 }
130 (void)b0;
131} 123}
132 124
133IWRAM_CODE 125IWRAM_CODE
134void 126void
135screen_talk(Device *d, u8 b0, u8 w) { 127screen_deo(u8 *ram, u8 *d, u8 port) {
136 if (!w) { 128 switch(port) {
137 switch(b0) { 129 case 0xe: {
138 case 0x2: d->dat[b0] = (SCREEN_WIDTH >> 8); break; 130 u16 x, y;
139 case 0x3: d->dat[b0] = (SCREEN_WIDTH); break; 131 u8 layer = d[0xe] & 0x40;
140 case 0x4: d->dat[b0] = (SCREEN_HEIGHT >> 8); break; 132 PEKDEV(x, 0x8);
141 case 0x5: d->dat[b0] = (SCREEN_HEIGHT); break; 133 PEKDEV(y, 0xa);
134 ppu_pixel(layer ? ppu.fg : ppu.bg, x, y, d[0xe] & 0x3);
135 if(d[0x6] & 0x01) POKDEV(0x8, x + 1); /* auto x+1 */
136 if(d[0x6] & 0x02) POKDEV(0xa, y + 1); /* auto y+1 */
137 break;
142 } 138 }
143 } else { 139 case 0xf: {
144 switch (b0) { 140 u16 x, y, dx, dy, addr;
145 case 0x1: { 141 u8 n, twobpp = !!(d[0xf] & 0x80);
146 d->vector = mempeek16(d->dat, 0x0); 142 PEKDEV(x, 0x8);
147 } break; 143 PEKDEV(y, 0xa);
148 case 0xe: { 144 PEKDEV(addr, 0xc);
149 u16 x, y; 145 n = d[0x6] >> 4;
150 u8 layer = d->dat[0xe] & 0x40; 146 dx = (d[0x6] & 0x01) << 3;
151 DEVPEEK16(x, 0x8); 147 dy = (d[0x6] & 0x02) << 2;
152 DEVPEEK16(y, 0xa); 148 if(addr > 0x10000 - ((n + 1) << (3 + twobpp))) {
153 ppu_pixel(layer ? ppu.fg : ppu.bg, x, y, d->dat[0xe] & 0x3); 149 return;
154 if(d->dat[0x6] & 0x01) DEVPOKE16(0x8, x + 1); /* auto x+1 */ 150 }
155 if(d->dat[0x6] & 0x02) DEVPOKE16(0xa, y + 1); /* auto y+1 */ 151 u8 *layer = (d[0xf] & 0x40) ? ppu.fg : ppu.bg;
156 } break; 152 u8 color = d[0xf] & 0xf;
157 case 0xf: { 153 u8 flipx = d[0xf] & 0x10;
158 u16 x, y, dx, dy, addr; 154 u8 flipy = d[0xf] & 0x20;
159 u8 twobpp = !!(d->dat[0xf] & 0x80); 155 for(size_t i = 0; i <= n; i++) {
160 DEVPEEK16(x, 0x8); 156 u8 *sprite = &ram[addr];
161 DEVPEEK16(y, 0xa); 157 if (twobpp) {
162 DEVPEEK16(addr, 0xc); 158 ppu_2bpp(layer, x + dy * i, y + dx * i, sprite, color, flipx, flipy);
163 u8 n = d->dat[0x6] >> 4; 159 } else {
164 dx = (d->dat[0x6] & 0x01) << 3; 160 ppu_1bpp(layer, x + dy * i, y + dx * i, sprite, color, flipx, flipy);
165 dy = (d->dat[0x6] & 0x02) << 2;
166 if(addr > 0x10000 - ((n + 1) << (3 + twobpp))) {
167 return;
168 }
169 u8 *layer = (d->dat[0xf] & 0x40) ? ppu.fg : ppu.bg;
170 u8 color = d->dat[0xf] & 0xf;
171 u8 flipx = d->dat[0xf] & 0x10;
172 u8 flipy = d->dat[0xf] & 0x20;
173 for(size_t i = 0; i <= n; i++) {
174 u8 *sprite = &d->mem[addr];
175 if (twobpp) {
176 ppu_2bpp(layer, x + dy * i, y + dx * i, sprite, color, flipx, flipy);
177 } else {
178 ppu_1bpp(layer, x + dy * i, y + dx * i, sprite, color, flipx, flipy);
179 }
180 addr += (d->dat[0x6] & 0x04) << (1 + twobpp);
181 } 161 }
182 DEVPOKE16(0xc, addr); /* auto addr+length */ 162 addr += (d[0x6] & 0x04) << (1 + twobpp);
183 DEVPOKE16(0x8, x + dx); /* auto x+8 */ 163 }
184 DEVPOKE16(0xa, y + dy); /* auto y+8 */ 164 POKDEV(0xc, addr); /* auto addr+length */
185 } break; 165 POKDEV(0x8, x + dx); /* auto x+8 */
186 default: break; 166 POKDEV(0xa, y + dy); /* auto y+8 */
167 break;
187 } 168 }
188 } 169 }
189} 170}
190 171
191static void 172u8
192audio_talk(Device *d, u8 b0, u8 w) { 173audio_dei(int instance, u8 *d, u8 port) {
193 AudioChannel *c = &channels[d - devaudio]; 174 AudioChannel *c = &channels[instance];
194 if(!w) { 175 switch(port) {
195 if(b0 == 0x2) { 176 // case 0x4: return apu_get_vu(instance);
196 mempoke16(d->dat, 0x2, c->pos); 177 case 0x2: {
178 POKDEV(0x2, c->pos);
197 c->pos <<= 12; // fixed point. 179 c->pos <<= 12; // fixed point.
198 } else if(b0 == 0x4) { 180 break;
199 // d->dat[0x4] = apu_get_vu(c);
200 } 181 }
201 } else if(b0 == 0xf) {
202 u16 length = mempeek16(d->dat, 0xa);
203 u8 *data = &d->mem[mempeek16(d->dat, 0xc)];
204 u8 pitch = d->dat[0xf] & 0x7f;
205 u16 adsr = mempeek16(d->dat, 0x8);
206 u32 vol = MAX(d->dat[0xe] >> 4, d->dat[0xe] & 0xf) * 4 / 3;
207 bool loop = !(d->dat[0xf] & 0x80);
208 update_channel(c, data, length, pitch, adsr, vol, loop);
209 } 182 }
183 return d[port];
210} 184}
211 185
212void 186void
213datetime_talk(Device *d, u8 b0, u8 w) { 187audio_deo(int instance, u8 *d, u8 port, Uxn *u) {
214 (void)b0; 188 AudioChannel *c = &channels[instance];
215 (void)w; 189 if (port == 0xf) {
190 u16 length = 0;
191 u16 adsr = 0;
192 u16 addr = 0;
193 u8 pitch = d[0xf] & 0x7f;
194 PEKDEV(adsr, 0x8);
195 PEKDEV(length, 0xa);
196 PEKDEV(addr, 0xc);
197 u8 *data = &u->ram[addr];
198 u32 vol = MAX(d[0xe] >> 4, d[0xe] & 0xf) * 4 / 3;
199 bool loop = !(d[0xf] & 0x80);
200 update_channel(c, data, length, pitch, adsr, vol, loop);
201 }
202}
203
204u8
205datetime_dei(u8 *d, u8 port) {
216 struct tm *t = gmtime(&seconds); 206 struct tm *t = gmtime(&seconds);
217 t->tm_year += 1900; 207 switch(port) {
218 DEVPOKE16(0x0, t->tm_year); 208 case 0x0: return (t->tm_year + 1900) >> 8;
219 d->dat[0x2] = t->tm_mon; 209 case 0x1: return (t->tm_year + 1900);
220 d->dat[0x3] = t->tm_mday; 210 case 0x2: return t->tm_mon;
221 d->dat[0x4] = t->tm_hour; 211 case 0x3: return t->tm_mday;
222 d->dat[0x5] = t->tm_min; 212 case 0x4: return t->tm_hour;
223 d->dat[0x6] = t->tm_sec; 213 case 0x5: return t->tm_min;
224 d->dat[0x7] = t->tm_wday; 214 case 0x6: return t->tm_sec;
225 DEVPOKE16(0x08, t->tm_yday); 215 case 0x7: return t->tm_wday;
226 d->dat[0xa] = t->tm_isdst; 216 case 0x8: return t->tm_yday >> 8;
217 case 0x9: return t->tm_yday;
218 case 0xa: return t->tm_isdst;
219 default: return d[port];
220 }
227} 221}
228 222
229void 223u8
230file_talk(Device *d, u8 b0, u8 w) { 224file_dei(u8 id, u8 *d, u8 port) {
231 if (w) { 225 UxnFile *c = &uxn_file[id];
232 u16 a, b, res; 226 u16 res;
233 UxnFile *f = &uxn_file[d - &d->u->dev[0xa]]; 227 switch(port) {
234 switch(b0) { 228 case 0xc:
235 case 0x5: { 229 case 0xd: {
236 DEVPEEK16(a, 0x4); 230 res = file_read(c, &d[port], 1);
237 DEVPEEK16(b, 0xa); 231 POKDEV(0x2, res);
238 if(b > 0x10000 - a) { 232 break;
239 b = 0x10000 - a;
240 }
241 res = file_stat(f, &d->mem[a], b);
242 DEVPOKE16(0x2, res);
243 } break;
244 case 0x6: {
245 // TODO: no file deletion for now
246 // res = file_delete();
247 // DEVPOKE16(0x2, res);
248 } break;
249 case 0x9: {
250 DEVPEEK16(a, 0x8);
251 res = file_init(f, &d->mem[a]);
252 DEVPOKE16(0x2, res);
253 } break;
254 case 0xd: {
255 DEVPEEK16(a, 0xc);
256 DEVPEEK16(b, 0xa);
257 if(b > 0x10000 - a) {
258 b = 0x10000 - a;
259 }
260 res = file_read(f, &d->mem[a], b);
261 DEVPOKE16(0x2, res);
262 } break;
263 case 0xf: {
264 DEVPEEK16(a, 0xe);
265 DEVPEEK16(b, 0xa);
266 if(b > 0x10000 - a) {
267 b = 0x10000 - a;
268 }
269 res = file_write(f, &d->mem[a], b, d->dat[0x7]);
270 DEVPOKE16(0x2, res);
271 } break;
272 } 233 }
273 } 234 }
235 return d[port];
274} 236}
275 237
276void 238void
277init_uxn(Uxn *u) { 239file_deo(u8 id, u8 *ram, u8 *d, u8 port) {
278 // Initialize PPU. 240 u16 a, b, res;
279 initppu(&ppu, 30, 20); 241 UxnFile *f = &uxn_file[id];
242 switch(port) {
243 case 0x5: {
244 PEKDEV(a, 0x4);
245 PEKDEV(b, 0xa);
246 if(b > 0x10000 - a) {
247 b = 0x10000 - a;
248 }
249 res = file_stat(f, &ram[a], b);
250 POKDEV(0x2, res);
251 } break;
252 case 0x6: {
253 // TODO: no file deletion for now
254 // res = file_delete();
255 // POKDEV(0x2, res);
256 } break;
257 case 0x9: {
258 PEKDEV(a, 0x8);
259 res = file_init(f, &ram[a]);
260 POKDEV(0x2, res);
261 } break;
262 case 0xd: {
263 PEKDEV(a, 0xc);
264 PEKDEV(b, 0xa);
265 if(b > 0x10000 - a) {
266 b = 0x10000 - a;
267 }
268 res = file_read(f, &ram[a], b);
269 POKDEV(0x2, res);
270 } break;
271 case 0xf: {
272 PEKDEV(a, 0xe);
273 PEKDEV(b, 0xa);
274 if(b > 0x10000 - a) {
275 b = 0x10000 - a;
276 }
277 res = file_write(f, &ram[a], b, d[0x7]);
278 POKDEV(0x2, res);
279 } break;
280 }
281}
280 282
281 // Enable sound. 283void
282 init_sound(); 284console_deo(u8 *d, u8 port) {
285 txt_printf("%c", d[port]);
286}
287
288void
289system_deo(Uxn *u, u8 *d, u8 port) {
290 switch(port) {
291 case 0x2: u->wst = (Stack *)(u->ram + (d[port] ? (d[port] * 0x100) : 0x10000)); break;
292 case 0x3: u->rst = (Stack *)(u->ram + (d[port] ? (d[port] * 0x100) : 0x10100)); break;
293 }
294}
295
296u8
297emu_dei(Uxn *u, u8 addr) {
298 u8 p = addr & 0x0f, d = addr & 0xf0;
299 switch(d) {
300 case 0x20: return screen_dei(&u->dev[d], p);
301 case 0x30: return audio_dei(0, &u->dev[d], p);
302 case 0x40: return audio_dei(1, &u->dev[d], p);
303 case 0x50: return audio_dei(2, &u->dev[d], p);
304 case 0x60: return audio_dei(3, &u->dev[d], p);
305 case 0xa0: return file_dei(0, &u->dev[d], p);
306 case 0xb0: return file_dei(1, &u->dev[d], p);
307 case 0xc0: return datetime_dei(&u->dev[d], p);
308 }
309 return u->dev[addr];
310 return 0;
311}
312
313void
314emu_deo(Uxn *u, u8 addr, u8 v) {
315 u8 p = addr & 0x0f, d = addr & 0xf0;
316 u->dev[addr] = v;
317 switch(d) {
318 case 0x00:
319 system_deo(u, &u->dev[d], p);
320 if(p > 0x7 && p < 0xe)
321 putcolors(&u->dev[0x8]);
322 break;
323 case 0x10: console_deo(&u->dev[d], p); break;
324 case 0x20: screen_deo(u->ram, &u->dev[d], p); break;
325 case 0x30: audio_deo(0, &u->dev[d], p, u); break;
326 case 0x40: audio_deo(1, &u->dev[d], p, u); break;
327 case 0x50: audio_deo(2, &u->dev[d], p, u); break;
328 case 0x60: audio_deo(3, &u->dev[d], p, u); break;
329 case 0xa0: file_deo(0, u->ram, &u->dev[d], p); break;
330 case 0xb0: file_deo(1, u->ram, &u->dev[d], p); break;
331 }
332}
333
334void
335init_uxn(Uxn *u) {
336 // Initialize uxn.
337 u32 fill = 0;
338 dma_fill(umem, fill, 0x10300, 3);
339 uxn_boot(u, umem, emu_dei, emu_deo);
283 340
284 // Copy rom to VM. 341 // Copy rom to VM.
285 memcpy(u->ram.dat + PAGE_PROGRAM, uxn_rom, sizeof(uxn_rom)); 342 memcpy(u->ram + PAGE_PROGRAM, uxn_rom, sizeof(uxn_rom));
286
287 // Prepare devices.
288 uxn_port(u, 0x0, "system", system_talk);
289 uxn_port(u, 0x1, "console", console_talk);
290 devscreen = uxn_port(u, 0x2, "screen", screen_talk);
291 devaudio = uxn_port(u, 0x3, "audio0", audio_talk);
292 uxn_port(u, 0x4, "audio1", audio_talk);
293 uxn_port(u, 0x5, "audio2", audio_talk);
294 uxn_port(u, 0x6, "audio3", audio_talk);
295 uxn_port(u, 0x7, "---", nil_talk);
296 devctrl = uxn_port(u, 0x8, "controller", nil_talk);
297 devmouse = uxn_port(u, 0x9, "mouse", nil_talk);
298 uxn_port(u, 0xa, "file1", file_talk);
299 uxn_port(u, 0xb, "file2", file_talk); // TODO: support second file device
300 uxn_port(u, 0xc, "datetime", datetime_talk);
301 uxn_port(u, 0xd, "---", nil_talk);
302 uxn_port(u, 0xe, "---", nil_talk);
303 uxn_port(u, 0xf, "---", nil_talk);
304 mempoke16(devscreen->dat, 2, ppu.hor * 8);
305 mempoke16(devscreen->dat, 4, ppu.ver * 8);
306} 343}
307 344
308IWRAM_CODE 345IWRAM_CODE
@@ -313,16 +350,18 @@ handle_input(Uxn *u) {
313 // Reset control variables on method switch. 350 // Reset control variables on method switch.
314 switch (ctrl_methods[ctrl_idx]) { 351 switch (ctrl_methods[ctrl_idx]) {
315 case CONTROL_CONTROLLER: { 352 case CONTROL_CONTROLLER: {
316 devctrl->dat[2] = 0; 353 u8 *d = &u->dev[0x80];
317 uxn_eval(u, mempeek16(devctrl->dat, 0)); 354 d[2] = 0;
318 devctrl->dat[3] = 0; 355 uxn_eval(u, GETVEC(d));
356 d[3] = 0;
319 } break; 357 } break;
320 case CONTROL_MOUSE: { 358 case CONTROL_MOUSE: {
321 devmouse->dat[6] = 0; 359 u8 *d = &u->dev[0x90];
322 devmouse->dat[7] = 0; 360 d[6] = 0;
323 mempoke16(devmouse->dat, 0x2, -10); 361 d[7] = 0;
324 mempoke16(devmouse->dat, 0x4, -10); 362 POKDEV(0x2, -10);
325 uxn_eval(u, mempeek16(devmouse->dat, 0)); 363 POKDEV(0x4, -10);
364 uxn_eval(u, GETVEC(d));
326 } break; 365 } break;
327 case CONTROL_KEYBOARD: { 366 case CONTROL_KEYBOARD: {
328 toggle_keyboard(); 367 toggle_keyboard();
@@ -339,9 +378,10 @@ handle_input(Uxn *u) {
339 } 378 }
340 379
341 if (ctrl_methods[ctrl_idx] == CONTROL_CONTROLLER) { 380 if (ctrl_methods[ctrl_idx] == CONTROL_CONTROLLER) {
342 // TODO: We don't need ifs if we use KEY_INPUTS directly and mayvbe just 381 u8 *d = &u->dev[0x80];
382 // TODO: We don't need ifs if we use KEY_INPUTS directly and maybe just
343 // swap some things if needed. 383 // swap some things if needed.
344 u8 *flag = &devctrl->dat[2]; 384 u8 *flag = &d[2];
345 if (key_tap(KEY_A)) { 385 if (key_tap(KEY_A)) {
346 *flag |= 0x01; 386 *flag |= 0x01;
347 } else { 387 } else {
@@ -383,11 +423,12 @@ handle_input(Uxn *u) {
383 *flag &= ~0x80; 423 *flag &= ~0x80;
384 } 424 }
385 425
386 uxn_eval(u, mempeek16(devctrl->dat, 0)); 426 uxn_eval(u, GETVEC(d));
387 devctrl->dat[3] = 0; 427 d[3] = 0;
388 } else if (ctrl_methods[ctrl_idx] == CONTROL_MOUSE) { 428 } else if (ctrl_methods[ctrl_idx] == CONTROL_MOUSE) {
429 u8 *d = &u->dev[0x90];
389 // Detect "mouse key press". 430 // Detect "mouse key press".
390 u8 flag = devmouse->dat[6]; 431 u8 flag = d[6];
391 if (key_tap(KEY_B)) { 432 if (key_tap(KEY_B)) {
392 flag |= 0x01; 433 flag |= 0x01;
393 } else if (key_released(KEY_B)) { 434 } else if (key_released(KEY_B)) {
@@ -400,12 +441,12 @@ handle_input(Uxn *u) {
400 } 441 }
401 442
402 // Handle chording. 443 // Handle chording.
403 devmouse->dat[6] = flag; 444 d[6] = flag;
404 if(flag == 0x10 && (devmouse->dat[6] & 0x01)) { 445 if(flag == 0x10 && (d[6] & 0x01)) {
405 devmouse->dat[7] = 0x01; 446 d[7] = 0x01;
406 } 447 }
407 if(flag == 0x01 && (devmouse->dat[6] & 0x10)) { 448 if(flag == 0x01 && (d[6] & 0x10)) {
408 devmouse->dat[7] = 0x10; 449 d[7] = 0x10;
409 } 450 }
410 451
411 // Detect mouse movement. 452 // Detect mouse movement.
@@ -421,10 +462,11 @@ handle_input(Uxn *u) {
421 } 462 }
422 463
423 // Eval mouse. 464 // Eval mouse.
424 mempoke16(devmouse->dat, 0x2, mouse.x); 465 POKDEV(0x2, mouse.x);
425 mempoke16(devmouse->dat, 0x4, mouse.y); 466 POKDEV(0x4, mouse.y);
426 uxn_eval(u, mempeek16(devmouse->dat, 0)); 467 uxn_eval(u, GETVEC(d));
427 } else if (ctrl_methods[ctrl_idx] == CONTROL_KEYBOARD) { 468 } else if (ctrl_methods[ctrl_idx] == CONTROL_KEYBOARD) {
469 u8 *d = &u->dev[0x80];
428 if (key_tap(KEY_LEFT)) { 470 if (key_tap(KEY_LEFT)) {
429 update_cursor(cursor_position - 1); 471 update_cursor(cursor_position - 1);
430 } else if (key_tap(KEY_RIGHT)) { 472 } else if (key_tap(KEY_RIGHT)) {
@@ -441,43 +483,40 @@ handle_input(Uxn *u) {
441 switch (symbol) { 483 switch (symbol) {
442 case 0x7f: { 484 case 0x7f: {
443 // Backspace. 485 // Backspace.
444 devctrl->dat[3] = 0x08; 486 d[3] = 0x08;
445 } break; 487 } break;
446 case 0x14: { 488 case 0x14: {
447 // New line. 489 // New line.
448 devctrl->dat[3] = 0x0d; 490 d[3] = 0x0d;
449 } break; 491 } break;
450 case 0x18: { 492 case 0x18: {
451 // Arrow up. 493 // Arrow up.
452 devctrl->dat[2] = 0x10; 494 d[2] = 0x10;
453 } break; 495 } break;
454 case 0x19: { 496 case 0x19: {
455 // Arrow down. 497 // Arrow down.
456 devctrl->dat[2] = 0x20; 498 d[2] = 0x20;
457 } break; 499 } break;
458 case 0x1b: { 500 case 0x1b: {
459 // Arrow left. 501 // Arrow left.
460 devctrl->dat[2] = 0x40; 502 d[2] = 0x40;
461 } break; 503 } break;
462 case 0x1a: { 504 case 0x1a: {
463 // Arrow right. 505 // Arrow right.
464 devctrl->dat[2] = 0x80; 506 d[2] = 0x80;
465 } break; 507 } break;
466 default: { 508 default: {
467 devctrl->dat[3] = symbol; 509 d[3] = symbol;
468 } break; 510 } break;
469 } 511 }
470 uxn_eval(u, mempeek16(devctrl->dat, 0)); 512 uxn_eval(u, GETVEC(d));
471 devctrl->dat[3] = 0; 513 d[3] = 0;
472 } 514 }
473 } 515 }
474} 516}
475 517
476static Uxn u; 518int
477EWRAM_BSS 519main(void) {
478static u8 umem[KB(64)];
479
480int main(void) {
481 // Adjust system wait times. 520 // Adjust system wait times.
482 SYSTEM_WAIT = SYSTEM_WAIT_CARTRIDGE; 521 SYSTEM_WAIT = SYSTEM_WAIT_CARTRIDGE;
483 522
@@ -488,16 +527,19 @@ int main(void) {
488 irq_init(); 527 irq_init();
489 irs_set(IRQ_VBLANK, sound_vsync); 528 irs_set(IRQ_VBLANK, sound_vsync);
490 529
491 // Initialize VM. 530 // Initialize PPU.
492 dma_fill(&u, 0, sizeof(u), 3); 531 initppu(&ppu, 30, 20);
493 u.ram.dat = umem;
494 init_uxn(&u);
495 532
496 // Initialize text engine. 533 // Initialize text engine.
534#ifdef TEXT_ENABLE
497 txt_init(1, TEXT_LAYER); 535 txt_init(1, TEXT_LAYER);
498 txt_position(0,0); 536 txt_position(0,0);
537#endif
538
539 // Initialize UXN.
540 init_uxn(&u);
499 541
500 // Initialize sound mixer. 542 // Enable sound.
501 init_sound(); 543 init_sound();
502 544
503 // Main loop. 545 // Main loop.
@@ -507,7 +549,7 @@ int main(void) {
507 while(true) { 549 while(true) {
508 bios_vblank_wait(); 550 bios_vblank_wait();
509 PROF(handle_input(&u), input_cycles); 551 PROF(handle_input(&u), input_cycles);
510 PROF(uxn_eval(&u, mempeek16(devscreen->dat, 0)), eval_cycles); 552 PROF(uxn_eval(&u, GETVEC(&u.dev[0x20])), eval_cycles);
511 PROF(sound_mix(), mix_cycles); 553 PROF(sound_mix(), mix_cycles);
512 PROF_SHOW(); 554 PROF_SHOW();
513 PROF(flipbuf(&ppu), flip_cycles); 555 PROF(flipbuf(&ppu), flip_cycles);