diff options
Diffstat (limited to 'src/main.c')
-rw-r--r-- | src/main.c | 494 |
1 files changed, 268 insertions, 226 deletions
@@ -1,12 +1,12 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (c) 2021 Bad Diode | 2 | Copyright (c) 2021 Bad Diode |
3 | 3 | ||
4 | Permission to use, copy, modify, and distribute this software for any | 4 | Permission to use, copy, modify, and distribute this software for any |
5 | purpose with or without fee is hereby granted, provided that the above | 5 | purpose with or without fee is hereby granted, provided that the above |
6 | copyright notice and this permission notice appear in all copies. | 6 | copyright notice and this permission notice appear in all copies. |
7 | 7 | ||
8 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | 8 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
9 | WITH 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 | ||
95 | EWRAM_BSS | ||
96 | static u8 umem[0x10300]; | ||
97 | |||
98 | static Uxn u; | ||
93 | static Ppu ppu; | 99 | static Ppu ppu; |
94 | static Device *devscreen; | ||
95 | static Device *devctrl; | ||
96 | static Device *devmouse; | ||
97 | static Device *devaudio; | ||
98 | 100 | ||
99 | static Mouse mouse = {SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2}; | 101 | static Mouse mouse = {SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2}; |
100 | 102 | ||
101 | void | 103 | int |
102 | nil_talk(Device *d, u8 b0, u8 w) { | 104 | uxn_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); | |
108 | void | 110 | while (true); |
109 | console_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 | ||
122 | void | 113 | IWRAM_CODE |
123 | system_talk(Device *d, u8 b0, u8 w) { | 114 | u8 |
124 | if(!w) { | 115 | screen_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 | ||
133 | IWRAM_CODE | 125 | IWRAM_CODE |
134 | void | 126 | void |
135 | screen_talk(Device *d, u8 b0, u8 w) { | 127 | screen_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 | ||
191 | static void | 172 | u8 |
192 | audio_talk(Device *d, u8 b0, u8 w) { | 173 | audio_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 | ||
212 | void | 186 | void |
213 | datetime_talk(Device *d, u8 b0, u8 w) { | 187 | audio_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 | |||
204 | u8 | ||
205 | datetime_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 | ||
229 | void | 223 | u8 |
230 | file_talk(Device *d, u8 b0, u8 w) { | 224 | file_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 | ||
276 | void | 238 | void |
277 | init_uxn(Uxn *u) { | 239 | file_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. | 283 | void |
282 | init_sound(); | 284 | console_deo(u8 *d, u8 port) { |
285 | txt_printf("%c", d[port]); | ||
286 | } | ||
287 | |||
288 | void | ||
289 | system_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 | |||
296 | u8 | ||
297 | emu_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 | |||
313 | void | ||
314 | emu_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 | |||
334 | void | ||
335 | init_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 | ||
308 | IWRAM_CODE | 345 | IWRAM_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 | ||
476 | static Uxn u; | 518 | int |
477 | EWRAM_BSS | 519 | main(void) { |
478 | static u8 umem[KB(64)]; | ||
479 | |||
480 | int 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); |