diff options
-rw-r--r-- | src/main.c | 254 | ||||
m--------- | src/uxn | 0 |
2 files changed, 140 insertions, 114 deletions
@@ -52,12 +52,10 @@ static OSMesgQueue audio_msg_queue; | |||
52 | 52 | ||
53 | #define CLAMP(X, MIN, MAX) ((X) <= (MIN) ? (MIN) : (X) > (MAX) ? (MAX): (X)) | 53 | #define CLAMP(X, MIN, MAX) ((X) <= (MIN) ? (MIN) : (X) > (MAX) ? (MAX): (X)) |
54 | 54 | ||
55 | static u8 uxn_ram[0x10000]; | 55 | static u8 uxn_ram[0x80000]; |
56 | static Uxn u; | 56 | static Uxn u; |
57 | static Device *devscreen; | 57 | u16 deo_mask[] = {0xff08, 0x0300, 0xc028, 0x8000, 0x8000, 0x8000, 0x8000, 0x0000, 0x0000, 0x0000, 0xa260, 0xa260, 0x0000, 0x0000, 0x0000, 0x0000}; |
58 | static Device *devctrl; | 58 | u16 dei_mask[] = {0x0000, 0x0000, 0x003c, 0x0014, 0x0014, 0x0014, 0x0014, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x07ff, 0x0000, 0x0000, 0x0000}; |
59 | static Device *devmouse; | ||
60 | static Device *devaudio; | ||
61 | 59 | ||
62 | #define MOUSE_DELTA 1 | 60 | #define MOUSE_DELTA 1 |
63 | typedef struct Mouse { | 61 | typedef struct Mouse { |
@@ -71,9 +69,10 @@ static Mouse mouse = {0}; | |||
71 | static size_t seconds = 0; | 69 | static size_t seconds = 0; |
72 | 70 | ||
73 | int | 71 | int |
74 | uxn_halt(Uxn *u, u8 error, u16 addr) { | 72 | uxn_halt(Uxn *u, u8 instr, u8 err, u16 addr) { |
75 | (void)u; | 73 | (void)u; |
76 | (void)error; | 74 | (void)instr; |
75 | (void)err; | ||
77 | (void)addr; | 76 | (void)addr; |
78 | for (;;) {} | 77 | for (;;) {} |
79 | } | 78 | } |
@@ -83,39 +82,44 @@ uxn_interrupt(void) { | |||
83 | return 1; | 82 | return 1; |
84 | } | 83 | } |
85 | 84 | ||
86 | static u8 | ||
87 | nil_dei(Device *d, u8 port) { | ||
88 | return d->dat[port]; | ||
89 | } | ||
90 | |||
91 | u8 | 85 | u8 |
92 | datetime_dei(Device *d, u8 port) { | 86 | datetime_dei(Uxn *u, u8 addr) { |
93 | (void)port; | 87 | (void)u; |
94 | size_t minutes = seconds / 60; | 88 | (void)addr; |
95 | size_t hours = minutes / 60; | 89 | // size_t minutes = seconds / 60; |
96 | DEVPOKE16(0x0, 0); | 90 | // size_t hours = minutes / 60; |
97 | d->dat[0x2] = 0; | 91 | // POKE2(d + 0x0, 0); |
98 | d->dat[0x3] = 0; | 92 | // d[0x2] = 0; |
99 | d->dat[0x4] = hours; | 93 | // d[0x3] = 0; |
100 | d->dat[0x5] = minutes; | 94 | // d[0x4] = hours; |
101 | d->dat[0x6] = seconds % 60; | 95 | // d[0x5] = minutes; |
102 | d->dat[0x7] = 0; | 96 | // d[0x6] = seconds % 60; |
103 | DEVPOKE16(0x08, 0); | 97 | // d[0x7] = 0; |
104 | d->dat[0xa] = 0; | 98 | // // POKE2(d + 0x08, 0); |
105 | } | 99 | // d[0xa] = 0; |
106 | 100 | // switch(addr) { | |
107 | static void | 101 | // case 0xc0: return 0; |
108 | nil_deo(Device *d, u8 port) { | 102 | // case 0xc1: return 0; |
109 | (void)d; | 103 | // case 0xc2: return 0; |
110 | (void)port; | 104 | // case 0xc3: return 0; |
105 | // case 0xc4: return hours; | ||
106 | // case 0xc5: return minutes; | ||
107 | // case 0xc6: return seconds % 60; | ||
108 | // case 0xc7: return 0; | ||
109 | // case 0xc8: return 0; | ||
110 | // case 0xc9: return 0; | ||
111 | // case 0xca: return 0; | ||
112 | // default: return u->dev[addr]; | ||
113 | // } | ||
114 | // return 0; | ||
111 | } | 115 | } |
112 | 116 | ||
113 | static void | 117 | static void |
114 | screen_palette(Device *d) { | 118 | screen_palette(u8 *d) { |
115 | for(size_t i = 0; i < 4; ++i) { | 119 | for(size_t i = 0; i < 4; ++i) { |
116 | u8 r = ((d->dat[0x8 + i / 2] >> (!(i % 2) << 2)) & 0x0f) * 0x11; | 120 | u8 r = ((*(d + i / 2) >> (!(i % 2) << 2)) & 0x0f) * 0x11; |
117 | u8 g = ((d->dat[0xa + i / 2] >> (!(i % 2) << 2)) & 0x0f) * 0x11; | 121 | u8 g = ((*(d + 2 + i / 2) >> (!(i % 2) << 2)) & 0x0f) * 0x11; |
118 | u8 b = ((d->dat[0xc + i / 2] >> (!(i % 2) << 2)) & 0x0f) * 0x11; | 122 | u8 b = ((*(d + 4 + i / 2) >> (!(i % 2) << 2)) & 0x0f) * 0x11; |
119 | 123 | ||
120 | palette[i] = GPACK_RGBA5551(r, g, b, 1); | 124 | palette[i] = GPACK_RGBA5551(r, g, b, 1); |
121 | } | 125 | } |
@@ -128,107 +132,110 @@ screen_palette(Device *d) { | |||
128 | redraw_screen(); | 132 | redraw_screen(); |
129 | } | 133 | } |
130 | 134 | ||
131 | u8 | 135 | #define RAM_PAGES 0x10 |
132 | system_dei(Device *d, u8 port) { | 136 | |
133 | switch(port) { | 137 | static void |
134 | case 0x2: return d->u->wst.ptr; | 138 | system_cmd(Uint8 *ram, Uint16 addr) { |
135 | case 0x3: return d->u->rst.ptr; | 139 | if(ram[addr] == 0x01) { |
136 | default: return d->dat[port]; | 140 | Uint16 i, length = PEEK2(ram + addr + 1); |
141 | Uint16 a_page = PEEK2(ram + addr + 1 + 2), a_addr = PEEK2(ram + addr + 1 + 4); | ||
142 | Uint16 b_page = PEEK2(ram + addr + 1 + 6), b_addr = PEEK2(ram + addr + 1 + 8); | ||
143 | int src = (a_page % RAM_PAGES) * 0x10000, dst = (b_page % RAM_PAGES) * 0x10000; | ||
144 | for(i = 0; i < length; i++) | ||
145 | ram[dst + (Uint16)(b_addr + i)] = ram[src + (Uint16)(a_addr + i)]; | ||
137 | } | 146 | } |
138 | } | 147 | } |
139 | 148 | ||
140 | void | 149 | void |
141 | system_deo(Device *d, u8 port) { | 150 | system_deo(Uxn *u, u8 *d, u8 port) { |
142 | switch(port) { | 151 | switch(port) { |
143 | case 0x2: d->u->wst.ptr = d->dat[port]; break; | 152 | case 0x3: |
144 | case 0x3: d->u->rst.ptr = d->dat[port]; break; | 153 | system_cmd(u->ram, PEEK2(d + 2)); |
145 | case 0xe: break; | 154 | break; |
146 | default: { | 155 | // case 0xe: |
147 | if(port > 0x7 && port < 0xe) { | 156 | // system_inspect(u); |
148 | screen_palette(d); | 157 | // break; |
149 | } | ||
150 | } break; | ||
151 | } | 158 | } |
152 | } | 159 | } |
153 | 160 | ||
154 | static void | 161 | static void |
155 | console_deo(Device *d, u8 port) { | 162 | console_deo(u8 *d, u8 port) { |
156 | (void)d; | 163 | (void)d; |
157 | (void)port; | 164 | (void)port; |
158 | } | 165 | } |
159 | 166 | ||
160 | u8 | 167 | u8 |
161 | screen_dei(Device *d, u8 port) { | 168 | screen_dei(u8 *d, u8 port) { |
162 | switch(port) { | 169 | switch(port) { |
163 | case 0x2: return screen_width >> 8; | 170 | case 0x2: return screen_width >> 8; |
164 | case 0x3: return screen_width; | 171 | case 0x3: return screen_width; |
165 | case 0x4: return screen_height >> 8; | 172 | case 0x4: return screen_height >> 8; |
166 | case 0x5: return screen_height; | 173 | case 0x5: return screen_height; |
167 | default: return d->dat[port]; | 174 | default: return d[port]; |
168 | } | 175 | } |
169 | } | 176 | } |
170 | 177 | ||
171 | void | 178 | void |
172 | screen_deo(Device *d, u8 port) { | 179 | screen_deo(u8 *ram, u8 *d, u8 port) { |
173 | switch(port) { | 180 | switch(port) { |
174 | case 0xe: { | 181 | case 0xe: { |
175 | u16 x, y; | 182 | u16 x, y; |
176 | u8 layer = d->dat[0xe] & 0x40; | 183 | u8 layer = d[0xe] & 0x40; |
177 | DEVPEEK16(x, 0x8); | 184 | x = PEEK2(d + 0x8); |
178 | DEVPEEK16(y, 0xa); | 185 | y = PEEK2(d + 0xa); |
179 | ppu_pixel(layer ? pixels_fg : pixels_bg, x, y, d->dat[0xe] & 0x3); | 186 | ppu_pixel(layer ? pixels_fg : pixels_bg, x, y, d[0xe] & 0x3); |
180 | if(d->dat[0x6] & 0x01) DEVPOKE16(0x8, x + 1); /* auto x+1 */ | 187 | if(d[0x6] & 0x01) POKE2(d + 0x8, x + 1); /* auto x+1 */ |
181 | if(d->dat[0x6] & 0x02) DEVPOKE16(0xa, y + 1); /* auto y+1 */ | 188 | if(d[0x6] & 0x02) POKE2(d + 0xa, y + 1); /* auto y+1 */ |
182 | } break; | 189 | break; |
190 | } | ||
183 | case 0xf: { | 191 | case 0xf: { |
184 | u16 x, y, dx, dy, addr; | 192 | u16 x, y, dx, dy, addr; |
185 | u8 twobpp = !!(d->dat[0xf] & 0x80); | 193 | u8 n, twobpp = !!(d[0xf] & 0x80); |
186 | DEVPEEK16(x, 0x8); | 194 | x = PEEK2(d + 0x8); |
187 | DEVPEEK16(y, 0xa); | 195 | y = PEEK2(d + 0xa); |
188 | DEVPEEK16(addr, 0xc); | 196 | addr = PEEK2(d + 0xc); |
189 | u8 n = d->dat[0x6] >> 4; | 197 | n = d[0x6] >> 4; |
190 | dx = (d->dat[0x6] & 0x01) << 3; | 198 | dx = (d[0x6] & 0x01) << 3; |
191 | dy = (d->dat[0x6] & 0x02) << 2; | 199 | dy = (d[0x6] & 0x02) << 2; |
192 | if(addr > 0x10000 - ((n + 1) << (3 + twobpp))) { | 200 | if(addr > 0x10000 - ((n + 1) << (3 + twobpp))) { |
193 | return; | 201 | return; |
194 | } | 202 | } |
195 | u8 *layer = (d->dat[0xf] & 0x40) ? pixels_fg : pixels_bg; | 203 | u8 *layer = (d[0xf] & 0x40) ? pixels_fg : pixels_bg; |
196 | u8 color = d->dat[0xf] & 0xf; | 204 | u8 color = d[0xf] & 0xf; |
197 | u8 flipx = d->dat[0xf] & 0x10; | 205 | u8 flipx = d[0xf] & 0x10; |
198 | u8 flipy = d->dat[0xf] & 0x20; | 206 | u8 flipy = d[0xf] & 0x20; |
199 | for(size_t i = 0; i <= n; i++) { | 207 | for(size_t i = 0; i <= n; i++) { |
200 | u8 *sprite = &d->u->ram[addr]; | 208 | u8 *sprite = &ram[addr]; |
201 | if (twobpp) { | 209 | if (twobpp) { |
202 | ppu_2bpp(layer, x + dy * i, y + dx * i, sprite, color, flipx, flipy); | 210 | ppu_2bpp(layer, x + dy * i, y + dx * i, sprite, color, flipx, flipy); |
203 | } else { | 211 | } else { |
204 | ppu_1bpp(layer, x + dy * i, y + dx * i, sprite, color, flipx, flipy); | 212 | ppu_1bpp(layer, x + dy * i, y + dx * i, sprite, color, flipx, flipy); |
205 | } | 213 | } |
206 | addr += (d->dat[0x6] & 0x04) << (1 + twobpp); | 214 | addr += (d[0x6] & 0x04) << (1 + twobpp); |
207 | } | 215 | } |
208 | DEVPOKE16(0xc, addr); /* auto addr+length */ | 216 | POKE2(d + 0xc, addr); /* auto addr+length */ |
209 | DEVPOKE16(0x8, x + dx); /* auto x+8 */ | 217 | POKE2(d + 0x8, x + dx); /* auto x+8 */ |
210 | DEVPOKE16(0xa, y + dy); /* auto y+8 */ | 218 | POKE2(d + 0xa, y + dy); /* auto y+8 */ |
211 | } break; | 219 | break; |
220 | } | ||
212 | } | 221 | } |
213 | reqdraw = 1; | 222 | reqdraw = 1; |
214 | } | 223 | } |
215 | 224 | ||
216 | static u8 | 225 | static u8 |
217 | audio_dei(Device *d, u8 port) { | 226 | audio_dei(int instance, u8 *d, u8 port) { |
218 | int instance = d - devaudio; | ||
219 | switch(port) { | 227 | switch(port) { |
220 | case 0x4: return audio_get_vu(instance); | 228 | case 0x4: return audio_get_vu(instance); |
221 | case 0x2: DEVPOKE16(0x2, audio_get_position(instance)); /* fall through */ | 229 | case 0x2: POKE2(d + 0x2, audio_get_position(instance)); /* fall through */ |
222 | default: return d->dat[port]; | 230 | default: return d[port]; |
223 | } | 231 | } |
224 | } | 232 | } |
225 | 233 | ||
226 | static void | 234 | static void |
227 | audio_deo(Device *d, u8 port) { | 235 | audio_deo(int instance, u8 *d, u8 port, Uxn *u) { |
228 | int instance = d - devaudio; | ||
229 | if(port == 0xf) { | 236 | if(port == 0xf) { |
230 | // TODO: stop the audio before audio_start | 237 | // TODO: stop the audio before audio_start |
231 | audio_start(instance, d); | 238 | audio_start(instance, d, u); |
232 | pause_audio = 0; | 239 | pause_audio = 0; |
233 | } | 240 | } |
234 | } | 241 | } |
@@ -263,8 +270,9 @@ handle_input(int i) { | |||
263 | bool update_mouse = false; | 270 | bool update_mouse = false; |
264 | 271 | ||
265 | // Check for controller changes. | 272 | // Check for controller changes. |
273 | u8 *devctrl = &u.dev[0x80]; | ||
266 | if (prev_pad.button != current_pad.button) { | 274 | if (prev_pad.button != current_pad.button) { |
267 | u8 *uxn_ctrl = &devctrl->dat[2]; | 275 | u8 *uxn_ctrl = &devctrl[2]; |
268 | if (current_pad.button & U_JPAD || current_pad.button & U_CBUTTONS) { | 276 | if (current_pad.button & U_JPAD || current_pad.button & U_CBUTTONS) { |
269 | *uxn_ctrl |= 0x10; | 277 | *uxn_ctrl |= 0x10; |
270 | update_ctrl = true; | 278 | update_ctrl = true; |
@@ -340,28 +348,28 @@ handle_input(int i) { | |||
340 | } | 348 | } |
341 | 349 | ||
342 | // Check for "mouse" x/y changes. | 350 | // Check for "mouse" x/y changes. |
351 | u8 *devmouse = &u.dev[0x90]; | ||
343 | if (current_pad.stick_x != 0 || current_pad.stick_y != 0) { | 352 | if (current_pad.stick_x != 0 || current_pad.stick_y != 0) { |
344 | Device *d = devmouse; | ||
345 | mouse.x = CLAMP(mouse.x + prev_pad.stick_x / 8, 0, (s32)screen_width); | 353 | mouse.x = CLAMP(mouse.x + prev_pad.stick_x / 8, 0, (s32)screen_width); |
346 | mouse.y = CLAMP(mouse.y - prev_pad.stick_y / 8, 0, (s32)screen_height); | 354 | mouse.y = CLAMP(mouse.y - prev_pad.stick_y / 8, 0, (s32)screen_height); |
347 | DEVPOKE16(0x2, mouse.x); | 355 | POKE2(devmouse + 0x2, mouse.x); |
348 | DEVPOKE16(0x4, mouse.y); | 356 | POKE2(devmouse + 0x4, mouse.y); |
349 | update_mouse = true; | 357 | update_mouse = true; |
350 | } | 358 | } |
351 | 359 | ||
352 | if (update_ctrl) { | 360 | if (update_ctrl) { |
353 | uxn_eval(&u, GETVECTOR(devctrl)); | 361 | uxn_eval(&u, PEEK2(devctrl)); |
354 | devctrl->dat[3] = 0; | 362 | devctrl[3] = 0; |
355 | } | 363 | } |
356 | if (update_mouse) { | 364 | if (update_mouse) { |
357 | devmouse->dat[6] = mouse.buttons; | 365 | devmouse[6] = mouse.buttons; |
358 | if(mouse.buttons == 0x10 && (devmouse->dat[6] & 0x01)) { | 366 | if(mouse.buttons == 0x10 && (devmouse[6] & 0x01)) { |
359 | devmouse->dat[7] = 0x01; | 367 | devmouse[7] = 0x01; |
360 | } | 368 | } |
361 | if(mouse.buttons == 0x01 && (devmouse->dat[6] & 0x10)) { | 369 | if(mouse.buttons == 0x01 && (devmouse[6] & 0x10)) { |
362 | devmouse->dat[7] = 0x10; | 370 | devmouse[7] = 0x10; |
363 | } | 371 | } |
364 | uxn_eval(&u, GETVECTOR(devmouse)); | 372 | uxn_eval(&u, PEEK2(devmouse)); |
365 | } | 373 | } |
366 | } | 374 | } |
367 | 375 | ||
@@ -385,6 +393,40 @@ poll_input() { | |||
385 | } | 393 | } |
386 | } | 394 | } |
387 | 395 | ||
396 | u8 | ||
397 | uxn_dei(Uxn *u, u8 addr) { | ||
398 | u8 p = addr & 0x0f, d = addr & 0xf0; | ||
399 | switch(d) { | ||
400 | case 0x20: return screen_dei(&u->dev[d], p); | ||
401 | case 0x30: return audio_dei(0, &u->dev[d], p); | ||
402 | case 0x40: return audio_dei(1, &u->dev[d], p); | ||
403 | case 0x50: return audio_dei(2, &u->dev[d], p); | ||
404 | case 0x60: return audio_dei(3, &u->dev[d], p); | ||
405 | case 0xc0: return datetime_dei(u, p); | ||
406 | } | ||
407 | return u->dev[addr]; | ||
408 | } | ||
409 | |||
410 | void | ||
411 | uxn_deo(Uxn *u, u8 addr) { | ||
412 | u8 p = addr & 0x0f, d = addr & 0xf0; | ||
413 | switch(d) { | ||
414 | case 0x00: | ||
415 | system_deo(u, &u->dev[d], p); | ||
416 | if(p > 0x7 && p < 0xe) | ||
417 | screen_palette(&u->dev[0x8]); | ||
418 | break; | ||
419 | case 0x10: console_deo(&u->dev[d], p); break; | ||
420 | case 0x20: screen_deo(u->ram, &u->dev[d], p); break; | ||
421 | case 0x30: audio_deo(0, &u->dev[d], p, u); break; | ||
422 | case 0x40: audio_deo(1, &u->dev[d], p, u); break; | ||
423 | case 0x50: audio_deo(2, &u->dev[d], p, u); break; | ||
424 | case 0x60: audio_deo(3, &u->dev[d], p, u); break; | ||
425 | // case 0xa0: file_deo_2(0, u->ram, &u->dev[d], p); break; | ||
426 | // case 0xb0: file_deo_2(1, u->ram, &u->dev[d], p); break; | ||
427 | } | ||
428 | } | ||
429 | |||
388 | void | 430 | void |
389 | init_uxn(Uxn *u) { | 431 | init_uxn(Uxn *u) { |
390 | // Setup UXN memory. | 432 | // Setup UXN memory. |
@@ -401,22 +443,6 @@ init_uxn(Uxn *u) { | |||
401 | } | 443 | } |
402 | 444 | ||
403 | // Prepare devices. | 445 | // Prepare devices. |
404 | /* system */ uxn_port(u, 0x0, system_dei, system_deo); | ||
405 | /* console */ uxn_port(u, 0x1, nil_dei, console_deo); | ||
406 | /* screen */ devscreen = uxn_port(u, 0x2, screen_dei, screen_deo); | ||
407 | /* audio0 */ devaudio = uxn_port(u, 0x3, audio_dei, audio_deo); | ||
408 | /* audio1 */ uxn_port(u, 0x4, audio_dei, audio_deo); | ||
409 | /* audio2 */ uxn_port(u, 0x5, audio_dei, audio_deo); | ||
410 | /* audio3 */ uxn_port(u, 0x6, audio_dei, audio_deo); | ||
411 | /* unused */ uxn_port(u, 0x7, nil_dei, nil_deo); | ||
412 | /* control */ devctrl = uxn_port(u, 0x8, nil_dei, nil_deo); | ||
413 | /* mouse */ devmouse = uxn_port(u, 0x9, nil_dei, nil_deo); | ||
414 | /* file0 */ uxn_port(u, 0xa, nil_dei, nil_deo); | ||
415 | /* file1 */ uxn_port(u, 0xb, nil_dei, nil_deo); | ||
416 | /* datetime */ uxn_port(u, 0xc, datetime_dei, nil_deo); | ||
417 | /* unused */ uxn_port(u, 0xd, nil_dei, nil_deo); | ||
418 | /* unused */ uxn_port(u, 0xe, nil_dei, nil_deo); | ||
419 | /* unused */ uxn_port(u, 0xf, nil_dei, nil_deo); | ||
420 | uxn_eval(u, PAGE_PROGRAM); | 446 | uxn_eval(u, PAGE_PROGRAM); |
421 | } | 447 | } |
422 | 448 | ||
@@ -454,7 +480,7 @@ main_proc(void *arg) { | |||
454 | u8 frame_counter = 0; | 480 | u8 frame_counter = 0; |
455 | while (true) { | 481 | while (true) { |
456 | poll_input(); | 482 | poll_input(); |
457 | uxn_eval(&u, GETVECTOR(devscreen)); | 483 | uxn_eval(&u, PEEK2(&u.dev[0x20])); |
458 | blit_framebuffer(); | 484 | blit_framebuffer(); |
459 | swap_buffers(); | 485 | swap_buffers(); |
460 | osYieldThread(); | 486 | osYieldThread(); |
diff --git a/src/uxn b/src/uxn | |||
Subproject 5496712ae1b231ea31be68151d2cfd10e933969 | Subproject 344c5c99040206b0f06d0a34a77569956c62231 | ||