commit ac45af6
neauoire
·
2022-03-27 01:32:46 +0000 UTC
parent b88531d
Updated screen device to latest specs
+6,
-0
1@@ -4,6 +4,12 @@ An assembler and emulator for the [Uxn stack-machine](https://wiki.xxiivv.com/si
2
3 More docs coming soon.
4
5+If you wish to build the emulator without graphics mode:
6+
7+```sh
8+cc src/devices/datetime.c src/devices/system.c src/devices/file.c src/uxn.c -DNDEBUG -Os -g0 -s src/uxncli.c -o bin/uxncli
9+```
10+
11 ## Contributing
12
13 Submit patches using [`git send-email`](https://git-send-email.io/) to the [~rabbits/public-inbox mailing list](https://lists.sr.ht/~rabbits/public-inbox).
M
build.sh
+2,
-2
1@@ -1,13 +1,13 @@
2 #!/bin/sh -e
3
4-clang-format -i uxn11.c
5+clang-format -i src/uxn11.c
6
7 echo "Cleaning.."
8 rm -f ./bin/*
9
10 echo "Building.."
11 mkdir -p bin
12-gcc uxn.c devices/ppu.c uxn11.c -o bin/uxn11 -lX11
13+gcc -std=c89 -DDEBUG -Wall -Wno-unknown-pragmas -Wpedantic -Wshadow -Wextra -Werror=implicit-int -Werror=incompatible-pointer-types -Werror=int-conversion -Wvla -g -Og -fsanitize=address -fsanitize=undefined src/uxn.c src/devices/system.c src/devices/screen.c src/uxn11.c -o bin/uxn11 -lX11
14
15 echo "Running.."
16 bin/uxn11 etc/screen.rom
+0,
-139
1@@ -1,139 +0,0 @@
2-#include "../uxn.h"
3-#include "file.h"
4-
5-/*
6-Copyright (c) 2021 Devine Lu Linvega
7-Copyright (c) 2021 Andrew Alderwick
8-
9-Permission to use, copy, modify, and distribute this software for any
10-purpose with or without fee is hereby granted, provided that the above
11-copyright notice and this permission notice appear in all copies.
12-
13-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14-WITH REGARD TO THIS SOFTWARE.
15-*/
16-
17-#define _POSIX_C_SOURCE 200809L
18-
19-#include <stdio.h>
20-#include <dirent.h>
21-#include <string.h>
22-#include <sys/stat.h>
23-#include <unistd.h>
24-
25-static FILE *f;
26-static DIR *d;
27-static char *current_filename = "";
28-static enum { IDLE,
29- FILE_READ,
30- FILE_WRITE,
31- DIR_READ } state;
32-static struct dirent *de;
33-
34-static void
35-reset(void)
36-{
37- if(f != NULL) {
38- fclose(f);
39- f = NULL;
40- }
41- if(d != NULL) {
42- closedir(d);
43- d = NULL;
44- }
45- de = NULL;
46- state = IDLE;
47-}
48-
49-static Uint16
50-get_entry(char *p, Uint16 len, const char *pathname, const char *basename, int fail_nonzero)
51-{
52- struct stat st;
53- if(len < strlen(basename) + 7)
54- return 0;
55- if(stat(pathname, &st))
56- return fail_nonzero ? snprintf(p, len, "!!!! %s\n", basename) : 0;
57- else if(S_ISDIR(st.st_mode))
58- return snprintf(p, len, "---- %s\n", basename);
59- else if(st.st_size < 0x10000)
60- return snprintf(p, len, "%04x %s\n", (Uint16)st.st_size, basename);
61- else
62- return snprintf(p, len, "???? %s\n", basename);
63-}
64-
65-static Uint16
66-file_read_dir(char *dest, Uint16 len)
67-{
68- static char pathname[4096];
69- char *p = dest;
70- if(de == NULL) de = readdir(d);
71- for(; de != NULL; de = readdir(d)) {
72- Uint16 n;
73- if(de->d_name[0] == '.' && de->d_name[1] == '\0')
74- continue;
75- snprintf(pathname, sizeof(pathname), "%s/%s", current_filename, de->d_name);
76- n = get_entry(p, len, pathname, de->d_name, 1);
77- if(!n) break;
78- p += n;
79- len -= n;
80- }
81- return p - dest;
82-}
83-
84-Uint16
85-file_init(void *filename)
86-{
87- reset();
88- current_filename = filename;
89- return 0;
90-}
91-
92-Uint16
93-file_read(void *dest, Uint16 len)
94-{
95- if(state != FILE_READ && state != DIR_READ) {
96- reset();
97- if((d = opendir(current_filename)) != NULL)
98- state = DIR_READ;
99- else if((f = fopen(current_filename, "rb")) != NULL)
100- state = FILE_READ;
101- }
102- if(state == FILE_READ)
103- return fread(dest, 1, len, f);
104- if(state == DIR_READ)
105- return file_read_dir(dest, len);
106- return 0;
107-}
108-
109-Uint16
110-file_write(void *src, Uint16 len, Uint8 flags)
111-{
112- Uint16 ret = 0;
113- if(state != FILE_WRITE) {
114- reset();
115- if((f = fopen(current_filename, (flags & 0x01) ? "ab" : "wb")) != NULL)
116- state = FILE_WRITE;
117- }
118- if(state == FILE_WRITE) {
119- if((ret = fwrite(src, 1, len, f)) > 0 && fflush(f) != 0)
120- ret = 0;
121- }
122- return ret;
123-}
124-
125-Uint16
126-file_stat(void *dest, Uint16 len)
127-{
128- char *basename = strrchr(current_filename, '/');
129- if(basename != NULL)
130- ++basename;
131- else
132- basename = current_filename;
133- return get_entry(dest, len, current_filename, basename, 0);
134-}
135-
136-Uint16
137-file_delete(void)
138-{
139- return unlink(current_filename);
140-}
+0,
-37
1@@ -1,37 +0,0 @@
2-#ifdef __aarch64__
3-#include <arm_neon.h>
4-#include "ppu.h"
5-
6-void
7-ppu_redraw(Ppu *p, Uint32 *screen)
8-{
9- uint8x16x4_t pal = vld4q_u8((Uint8*)p->palette);
10- Uint8 *fg = p->fg.pixels;
11- Uint8 *bg = p->bg.pixels;
12- int i;
13-
14- p->fg.changed = p->bg.changed = 0;
15-
16-#ifdef __has_builtin
17-#if __has_builtin(__builtin_assume)
18- __builtin_assume(p->width > 0 && p->height > 0);
19-#endif
20-#endif
21-
22- for(i = 0; i < (p->width * p->height & ~15); i += 16, fg += 16, bg += 16, screen += 16) {
23- uint8x16_t fg8 = vld1q_u8(fg);
24- uint8x16_t bg8 = vld1q_u8(bg);
25- uint8x16_t px8 = vbslq_u8(vceqzq_u8(fg8), bg8, fg8);
26- uint8x16x4_t px = {
27- vqtbl1q_u8(pal.val[0], px8),
28- vqtbl1q_u8(pal.val[1], px8),
29- vqtbl1q_u8(pal.val[2], px8),
30- vdupq_n_u8(0xff),
31- };
32- vst4q_u8((uint8_t*)screen, px);
33- }
34-
35- for(; i < p->width * p->height; i++)
36- screen[i] = p->palette[*fg ? *fg : *bg];
37-}
38-#endif
+0,
-0
R devices/apu.c =>
src/devices/apu.c
+0,
-0
R devices/apu.h =>
src/devices/apu.h
+0,
-0
+40,
-0
1@@ -0,0 +1,40 @@
2+#include <time.h>
3+
4+#include "../uxn.h"
5+#include "datetime.h"
6+
7+/*
8+Copyright (c) 2021 Devine Lu Linvega
9+Copyright (c) 2021 Andrew Alderwick
10+
11+Permission to use, copy, modify, and distribute this software for any
12+purpose with or without fee is hereby granted, provided that the above
13+copyright notice and this permission notice appear in all copies.
14+
15+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
16+WITH REGARD TO THIS SOFTWARE.
17+*/
18+
19+Uint8
20+datetime_dei(Device *d, Uint8 port)
21+{
22+ time_t seconds = time(NULL);
23+ struct tm zt = {0};
24+ struct tm *t = localtime(&seconds);
25+ if(t == NULL)
26+ t = &zt;
27+ switch(port) {
28+ case 0x0: return (t->tm_year + 1900) >> 8;
29+ case 0x1: return (t->tm_year + 1900);
30+ case 0x2: return t->tm_mon;
31+ case 0x3: return t->tm_mday;
32+ case 0x4: return t->tm_hour;
33+ case 0x5: return t->tm_min;
34+ case 0x6: return t->tm_sec;
35+ case 0x7: return t->tm_wday;
36+ case 0x8: return t->tm_yday >> 8;
37+ case 0x9: return t->tm_yday;
38+ case 0xa: return t->tm_isdst;
39+ default: return d->dat[port];
40+ }
41+}
+13,
-0
1@@ -0,0 +1,13 @@
2+/*
3+Copyright (c) 2021 Devine Lu Linvega
4+Copyright (c) 2021 Andrew Alderwick
5+
6+Permission to use, copy, modify, and distribute this software for any
7+purpose with or without fee is hereby granted, provided that the above
8+copyright notice and this permission notice appear in all copies.
9+
10+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11+WITH REGARD TO THIS SOFTWARE.
12+*/
13+
14+Uint8 datetime_dei(Device *d, Uint8 port);
+211,
-0
1@@ -0,0 +1,211 @@
2+#include "../uxn.h"
3+#include "file.h"
4+
5+/*
6+Copyright (c) 2021 Devine Lu Linvega
7+Copyright (c) 2021 Andrew Alderwick
8+
9+Permission to use, copy, modify, and distribute this software for any
10+purpose with or without fee is hereby granted, provided that the above
11+copyright notice and this permission notice appear in all copies.
12+
13+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14+WITH REGARD TO THIS SOFTWARE.
15+*/
16+
17+#include <stdio.h>
18+#include <dirent.h>
19+#include <string.h>
20+#include <sys/stat.h>
21+#include <unistd.h>
22+
23+typedef struct {
24+ FILE *f;
25+ DIR *dir;
26+ char current_filename[4096];
27+ struct dirent *de;
28+ enum { IDLE,
29+ FILE_READ,
30+ FILE_WRITE,
31+ DIR_READ } state;
32+} UxnFile;
33+
34+static UxnFile uxn_file[POLYFILEY];
35+
36+static void
37+reset(UxnFile *c)
38+{
39+ if(c->f != NULL) {
40+ fclose(c->f);
41+ c->f = NULL;
42+ }
43+ if(c->dir != NULL) {
44+ closedir(c->dir);
45+ c->dir = NULL;
46+ }
47+ c->de = NULL;
48+ c->state = IDLE;
49+}
50+
51+static Uint16
52+get_entry(char *p, Uint16 len, const char *pathname, const char *basename, int fail_nonzero)
53+{
54+ struct stat st;
55+ if(len < strlen(basename) + 7)
56+ return 0;
57+ if(stat(pathname, &st))
58+ return fail_nonzero ? sprintf(p, "!!!! %s\n", basename) : 0;
59+ else if(S_ISDIR(st.st_mode))
60+ return sprintf(p, "---- %s\n", basename);
61+ else if(st.st_size < 0x10000)
62+ return sprintf(p, "%04x %s\n", (unsigned int)st.st_size, basename);
63+ else
64+ return sprintf(p, "???? %s\n", basename);
65+}
66+
67+static Uint16
68+file_read_dir(UxnFile *c, char *dest, Uint16 len)
69+{
70+ static char pathname[4352];
71+ char *p = dest;
72+ if(c->de == NULL) c->de = readdir(c->dir);
73+ for(; c->de != NULL; c->de = readdir(c->dir)) {
74+ Uint16 n;
75+ if(c->de->d_name[0] == '.' && c->de->d_name[1] == '\0')
76+ continue;
77+ if(strlen(c->current_filename) + 1 + strlen(c->de->d_name) < sizeof(pathname))
78+ sprintf(pathname, "%s/%s", c->current_filename, c->de->d_name);
79+ else
80+ pathname[0] = '\0';
81+ n = get_entry(p, len, pathname, c->de->d_name, 1);
82+ if(!n) break;
83+ p += n;
84+ len -= n;
85+ }
86+ return p - dest;
87+}
88+
89+static Uint16
90+file_init(UxnFile *c, char *filename, size_t max_len)
91+{
92+ char *p = c->current_filename;
93+ size_t len = sizeof(c->current_filename);
94+ reset(c);
95+ if(len > max_len) len = max_len;
96+ while(len) {
97+ if((*p++ = *filename++) == '\0')
98+ return 0;
99+ len--;
100+ }
101+ c->current_filename[0] = '\0';
102+ return 0;
103+}
104+
105+static Uint16
106+file_read(UxnFile *c, void *dest, Uint16 len)
107+{
108+ if(c->state != FILE_READ && c->state != DIR_READ) {
109+ reset(c);
110+ if((c->dir = opendir(c->current_filename)) != NULL)
111+ c->state = DIR_READ;
112+ else if((c->f = fopen(c->current_filename, "rb")) != NULL)
113+ c->state = FILE_READ;
114+ }
115+ if(c->state == FILE_READ)
116+ return fread(dest, 1, len, c->f);
117+ if(c->state == DIR_READ)
118+ return file_read_dir(c, dest, len);
119+ return 0;
120+}
121+
122+static Uint16
123+file_write(UxnFile *c, void *src, Uint16 len, Uint8 flags)
124+{
125+ Uint16 ret = 0;
126+ if(c->state != FILE_WRITE) {
127+ reset(c);
128+ if((c->f = fopen(c->current_filename, (flags & 0x01) ? "ab" : "wb")) != NULL)
129+ c->state = FILE_WRITE;
130+ }
131+ if(c->state == FILE_WRITE) {
132+ if((ret = fwrite(src, 1, len, c->f)) > 0 && fflush(c->f) != 0)
133+ ret = 0;
134+ }
135+ return ret;
136+}
137+
138+static Uint16
139+file_stat(UxnFile *c, void *dest, Uint16 len)
140+{
141+ char *basename = strrchr(c->current_filename, '/');
142+ if(basename != NULL)
143+ basename++;
144+ else
145+ basename = c->current_filename;
146+ return get_entry(dest, len, c->current_filename, basename, 0);
147+}
148+
149+static Uint16
150+file_delete(UxnFile *c)
151+{
152+ return unlink(c->current_filename);
153+}
154+
155+/* IO */
156+
157+void
158+file_i_deo(int instance, Device *d, Uint8 port)
159+{
160+ UxnFile *c = &uxn_file[instance];
161+ Uint16 addr, len, res;
162+ switch(port) {
163+ case 0x5:
164+ DEVPEEK16(addr, 0x4);
165+ DEVPEEK16(len, 0xa);
166+ if(len > 0x10000 - addr)
167+ len = 0x10000 - addr;
168+ res = file_stat(c, &d->u->ram[addr], len);
169+ DEVPOKE16(0x2, res);
170+ break;
171+ case 0x6:
172+ res = file_delete(c);
173+ DEVPOKE16(0x2, res);
174+ break;
175+ case 0x9:
176+ DEVPEEK16(addr, 0x8);
177+ res = file_init(c, (char *)&d->u->ram[addr], 0x10000 - addr);
178+ DEVPOKE16(0x2, res);
179+ break;
180+ case 0xd:
181+ DEVPEEK16(addr, 0xc);
182+ DEVPEEK16(len, 0xa);
183+ if(len > 0x10000 - addr)
184+ len = 0x10000 - addr;
185+ res = file_read(c, &d->u->ram[addr], len);
186+ DEVPOKE16(0x2, res);
187+ break;
188+ case 0xf:
189+ DEVPEEK16(addr, 0xe);
190+ DEVPEEK16(len, 0xa);
191+ if(len > 0x10000 - addr)
192+ len = 0x10000 - addr;
193+ res = file_write(c, &d->u->ram[addr], len, d->dat[0x7]);
194+ DEVPOKE16(0x2, res);
195+ break;
196+ }
197+}
198+
199+Uint8
200+file_i_dei(int instance, Device *d, Uint8 port)
201+{
202+ UxnFile *c = &uxn_file[instance];
203+ Uint16 res;
204+ switch(port) {
205+ case 0xc:
206+ case 0xd:
207+ res = file_read(c, &d->dat[port], 1);
208+ DEVPOKE16(0x2, res);
209+ break;
210+ }
211+ return d->dat[port];
212+}
R devices/file.h =>
src/devices/file.h
+4,
-5
1@@ -10,8 +10,7 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
2 WITH REGARD TO THIS SOFTWARE.
3 */
4
5-Uint16 file_init(void *filename);
6-Uint16 file_read(void *dest, Uint16 len);
7-Uint16 file_write(void *src, Uint16 len, Uint8 flags);
8-Uint16 file_stat(void *dest, Uint16 len);
9-Uint16 file_delete(void);
10+#define POLYFILEY 2
11+
12+void file_i_deo(int instance, Device *d, Uint8 port);
13+Uint8 file_i_dei(int instance, Device *d, Uint8 port);
R devices/ppu.c =>
src/devices/ppu.c
+0,
-0
R devices/ppu.h =>
src/devices/ppu.h
+0,
-0
+181,
-0
1@@ -0,0 +1,181 @@
2+#include <stdlib.h>
3+
4+#include "../uxn.h"
5+#include "screen.h"
6+
7+/*
8+Copyright (c) 2021 Devine Lu Linvega
9+Copyright (c) 2021 Andrew Alderwick
10+
11+Permission to use, copy, modify, and distribute this software for any
12+purpose with or without fee is hereby granted, provided that the above
13+copyright notice and this permission notice appear in all copies.
14+
15+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
16+WITH REGARD TO THIS SOFTWARE.
17+*/
18+
19+UxnScreen uxn_screen;
20+
21+static Uint8 blending[5][16] = {
22+ {0, 0, 0, 0, 1, 0, 1, 1, 2, 2, 0, 2, 3, 3, 3, 0},
23+ {0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3},
24+ {1, 2, 3, 1, 1, 2, 3, 1, 1, 2, 3, 1, 1, 2, 3, 1},
25+ {2, 3, 1, 2, 2, 3, 1, 2, 2, 3, 1, 2, 2, 3, 1, 2},
26+ {1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0}};
27+
28+static void
29+screen_write(UxnScreen *p, Layer *layer, Uint16 x, Uint16 y, Uint8 color)
30+{
31+ if(x < p->width && y < p->height) {
32+ Uint32 i = x + y * p->width;
33+ if(color != layer->pixels[i]) {
34+ layer->pixels[i] = color;
35+ layer->changed = 1;
36+ }
37+ }
38+}
39+
40+static void
41+screen_blit(UxnScreen *p, Layer *layer, Uint16 x, Uint16 y, Uint8 *sprite, Uint8 color, Uint8 flipx, Uint8 flipy, Uint8 twobpp)
42+{
43+ int v, h, opaque = blending[4][color];
44+ for(v = 0; v < 8; v++) {
45+ Uint16 c = sprite[v] | (twobpp ? sprite[v + 8] : 0) << 8;
46+ for(h = 7; h >= 0; --h, c >>= 1) {
47+ Uint8 ch = (c & 1) | ((c >> 7) & 2);
48+ if(opaque || ch)
49+ screen_write(p,
50+ layer,
51+ x + (flipx ? 7 - h : h),
52+ y + (flipy ? 7 - v : v),
53+ blending[ch][color]);
54+ }
55+ }
56+}
57+
58+void
59+screen_palette(UxnScreen *p, Uint8 *addr)
60+{
61+ int i, shift;
62+ for(i = 0, shift = 4; i < 4; ++i, shift ^= 4) {
63+ Uint8
64+ r = (addr[0 + i / 2] >> shift) & 0x0f,
65+ g = (addr[2 + i / 2] >> shift) & 0x0f,
66+ b = (addr[4 + i / 2] >> shift) & 0x0f;
67+ p->palette[i] = 0x0f000000 | r << 16 | g << 8 | b;
68+ p->palette[i] |= p->palette[i] << 4;
69+ }
70+ p->fg.changed = p->bg.changed = 1;
71+}
72+
73+void
74+screen_resize(UxnScreen *p, Uint16 width, Uint16 height)
75+{
76+ Uint8
77+ *bg = realloc(p->bg.pixels, width * height),
78+ *fg = realloc(p->fg.pixels, width * height);
79+ Uint32
80+ *pixels = realloc(p->pixels, width * height * sizeof(Uint32));
81+ if(bg) p->bg.pixels = bg;
82+ if(fg) p->fg.pixels = fg;
83+ if(pixels) p->pixels = pixels;
84+ if(bg && fg && pixels) {
85+ p->width = width;
86+ p->height = height;
87+ screen_clear(p, &p->bg);
88+ screen_clear(p, &p->fg);
89+ }
90+}
91+
92+void
93+screen_clear(UxnScreen *p, Layer *layer)
94+{
95+ Uint32 i, size = p->width * p->height;
96+ for(i = 0; i < size; i++)
97+ layer->pixels[i] = 0x00;
98+ layer->changed = 1;
99+}
100+
101+void
102+screen_redraw(UxnScreen *p, Uint32 *pixels)
103+{
104+ Uint32 i, size = p->width * p->height, palette[16];
105+ for(i = 0; i < 16; i++)
106+ palette[i] = p->palette[(i >> 2) ? (i >> 2) : (i & 3)];
107+ for(i = 0; i < size; i++)
108+ pixels[i] = palette[p->fg.pixels[i] << 2 | p->bg.pixels[i]];
109+ p->fg.changed = p->bg.changed = 0;
110+}
111+
112+int
113+clamp(int val, int min, int max)
114+{
115+ return (val >= min) ? (val <= max) ? val : max : min;
116+}
117+
118+/* IO */
119+
120+Uint8
121+screen_dei(Device *d, Uint8 port)
122+{
123+ switch(port) {
124+ case 0x2: return uxn_screen.width >> 8;
125+ case 0x3: return uxn_screen.width;
126+ case 0x4: return uxn_screen.height >> 8;
127+ case 0x5: return uxn_screen.height;
128+ default: return d->dat[port];
129+ }
130+}
131+
132+void
133+screen_deo(Device *d, Uint8 port)
134+{
135+ switch(port) {
136+ case 0x3:
137+ if(!FIXED_SIZE) {
138+ Uint16 w;
139+ DEVPEEK16(w, 0x2);
140+ screen_resize(&uxn_screen, clamp(w, 1, 1024), uxn_screen.height);
141+ }
142+ break;
143+ case 0x5:
144+ if(!FIXED_SIZE) {
145+ Uint16 h;
146+ DEVPEEK16(h, 0x4);
147+ screen_resize(&uxn_screen, uxn_screen.width, clamp(h, 1, 1024));
148+ }
149+ break;
150+ case 0xe: {
151+ Uint16 x, y;
152+ Uint8 layer = d->dat[0xe] & 0x40;
153+ DEVPEEK16(x, 0x8);
154+ DEVPEEK16(y, 0xa);
155+ screen_write(&uxn_screen, layer ? &uxn_screen.fg : &uxn_screen.bg, x, y, d->dat[0xe] & 0x3);
156+ if(d->dat[0x6] & 0x01) DEVPOKE16(0x8, x + 1); /* auto x+1 */
157+ if(d->dat[0x6] & 0x02) DEVPOKE16(0xa, y + 1); /* auto y+1 */
158+ break;
159+ }
160+ case 0xf: {
161+ Uint16 x, y, dx, dy, addr;
162+ Uint8 i, n, twobpp = !!(d->dat[0xf] & 0x80);
163+ Layer *layer = (d->dat[0xf] & 0x40) ? &uxn_screen.fg : &uxn_screen.bg;
164+ DEVPEEK16(x, 0x8);
165+ DEVPEEK16(y, 0xa);
166+ DEVPEEK16(addr, 0xc);
167+ n = d->dat[0x6] >> 4;
168+ dx = (d->dat[0x6] & 0x01) << 3;
169+ dy = (d->dat[0x6] & 0x02) << 2;
170+ if(addr > 0x10000 - ((n + 1) << (3 + twobpp)))
171+ return;
172+ for(i = 0; i <= n; i++) {
173+ screen_blit(&uxn_screen, layer, x + dy * i, y + dx * i, &d->u->ram[addr], d->dat[0xf] & 0xf, d->dat[0xf] & 0x10, d->dat[0xf] & 0x20, twobpp);
174+ addr += (d->dat[0x6] & 0x04) << (1 + twobpp);
175+ }
176+ DEVPOKE16(0xc, addr); /* auto addr+length */
177+ DEVPOKE16(0x8, x + dx); /* auto x+8 */
178+ DEVPOKE16(0xa, y + dy); /* auto y+8 */
179+ break;
180+ }
181+ }
182+}
+34,
-0
1@@ -0,0 +1,34 @@
2+/*
3+Copyright (c) 2021 Devine Lu Linvega
4+Copyright (c) 2021 Andrew Alderwick
5+
6+Permission to use, copy, modify, and distribute this software for any
7+purpose with or without fee is hereby granted, provided that the above
8+copyright notice and this permission notice appear in all copies.
9+
10+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11+WITH REGARD TO THIS SOFTWARE.
12+*/
13+
14+#define FIXED_SIZE 0
15+
16+typedef struct Layer {
17+ Uint8 *pixels, changed;
18+} Layer;
19+
20+typedef struct UxnScreen {
21+ Uint32 palette[4], *pixels;
22+ Uint16 width, height;
23+ Layer fg, bg;
24+} UxnScreen;
25+
26+extern UxnScreen uxn_screen;
27+
28+void screen_palette(UxnScreen *p, Uint8 *addr);
29+void screen_resize(UxnScreen *p, Uint16 width, Uint16 height);
30+void screen_clear(UxnScreen *p, Layer *layer);
31+void screen_redraw(UxnScreen *p, Uint32 *pixels);
32+
33+Uint8 screen_dei(Device *d, Uint8 port);
34+void screen_deo(Device *d, Uint8 port);
35+int clamp(int val, int min, int max);
+73,
-0
1@@ -0,0 +1,73 @@
2+#include "../uxn.h"
3+#include "system.h"
4+
5+#include <stdio.h>
6+
7+/*
8+Copyright (c) 2022 Devine Lu Linvega, Andrew Alderwick
9+
10+Permission to use, copy, modify, and distribute this software for any
11+purpose with or without fee is hereby granted, provided that the above
12+copyright notice and this permission notice appear in all copies.
13+
14+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
15+WITH REGARD TO THIS SOFTWARE.
16+*/
17+
18+static const char *errors[] = {
19+ "Working-stack underflow",
20+ "Return-stack underflow",
21+ "Working-stack overflow",
22+ "Return-stack overflow",
23+ "Working-stack division by zero",
24+ "Return-stack division by zero"};
25+
26+static void
27+system_print(Stack *s, char *name)
28+{
29+ Uint8 i;
30+ fprintf(stderr, "<%s>", name);
31+ for(i = 0; i < s->ptr; i++)
32+ fprintf(stderr, " %02x", s->dat[i]);
33+ if(!i)
34+ fprintf(stderr, " empty");
35+ fprintf(stderr, "\n");
36+}
37+
38+void
39+system_inspect(Uxn *u)
40+{
41+ system_print(&u->wst, "wst");
42+ system_print(&u->rst, "rst");
43+}
44+
45+int
46+uxn_halt(Uxn *u, Uint8 error, Uint16 addr)
47+{
48+ system_inspect(u);
49+ fprintf(stderr, "Halted: %s#%04x, at 0x%04x\n", errors[error], u->ram[addr], addr);
50+ return 0;
51+}
52+
53+/* IO */
54+
55+Uint8
56+system_dei(Device *d, Uint8 port)
57+{
58+ switch(port) {
59+ case 0x2: return d->u->wst.ptr;
60+ case 0x3: return d->u->rst.ptr;
61+ default: return d->dat[port];
62+ }
63+}
64+
65+void
66+system_deo(Device *d, Uint8 port)
67+{
68+ switch(port) {
69+ case 0x2: d->u->wst.ptr = d->dat[port]; break;
70+ case 0x3: d->u->rst.ptr = d->dat[port]; break;
71+ case 0xe: system_inspect(d->u); break;
72+ default: system_deo_special(d, port);
73+ }
74+}
+21,
-0
1@@ -0,0 +1,21 @@
2+/*
3+Copyright (c) 2022 Devine Lu Linvega, Andrew Alderwick
4+
5+Permission to use, copy, modify, and distribute this software for any
6+purpose with or without fee is hereby granted, provided that the above
7+copyright notice and this permission notice appear in all copies.
8+
9+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10+WITH REGARD TO THIS SOFTWARE.
11+*/
12+
13+typedef struct SystemDevice {
14+ Device device;
15+ struct UxnScreen *screen;
16+} SystemDevice;
17+
18+void system_inspect(Uxn *u);
19+
20+Uint8 system_dei(Device *d, Uint8 port);
21+void system_deo(Device *d, Uint8 port);
22+void system_deo_special(Device *d, Uint8 port);
+124,
-0
1@@ -0,0 +1,124 @@
2+#include "uxn.h"
3+
4+/*
5+Copyright (u) 2022 Devine Lu Linvega, Andrew Alderwick, Andrew Richards
6+
7+Permission to use, copy, modify, and distribute this software for any
8+purpose with or without fee is hereby granted, provided that the above
9+copyright notice and this permission notice appear in all copies.
10+
11+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12+WITH REGARD TO THIS SOFTWARE.
13+*/
14+
15+/* clang-format off */
16+
17+#define PUSH8(s, x) { if(s->ptr == 0xff) { errcode = 2; goto err; } s->dat[s->ptr++] = (x); }
18+#define PUSH16(s, x) { if((j = s->ptr) >= 0xfe) { errcode = 2; goto err; } k = (x); s->dat[j] = k >> 8; s->dat[j + 1] = k; s->ptr = j + 2; }
19+#define PUSH(s, x) { if(bs) { PUSH16(s, (x)) } else { PUSH8(s, (x)) } }
20+#define POP8(o) { if(!(j = *sp)) { errcode = 0; goto err; } o = (Uint16)src->dat[--j]; *sp = j; }
21+#define POP16(o) { if((j = *sp) <= 1) { errcode = 0; goto err; } o = src->dat[j - 1]; o += src->dat[j - 2] << 8; *sp = j - 2; }
22+#define POP(o) { if(bs) { POP16(o) } else { POP8(o) } }
23+#define POKE(x, y) { if(bs) { u->ram[(x)] = (y) >> 8; u->ram[(x) + 1] = (y); } else { u->ram[(x)] = y; } }
24+#define PEEK16(o, x) { o = (u->ram[(x)] << 8) + u->ram[(x) + 1]; }
25+#define PEEK(o, x) { if(bs) { PEEK16(o, x) } else { o = u->ram[(x)]; } }
26+#define DEVR(o, d, x) { dev = (d); o = dev->dei(dev, (x) & 0x0f); if(bs) { o = (o << 8) + dev->dei(dev, ((x) + 1) & 0x0f); } }
27+#define DEVW8(x, y) { dev->dat[(x) & 0xf] = y; dev->deo(dev, (x) & 0x0f); }
28+#define DEVW(d, x, y) { dev = (d); if(bs) { DEVW8((x), (y) >> 8); DEVW8((x) + 1, (y)); } else { DEVW8((x), (y)) } }
29+#define WARP(x) { if(bs) pc = (x); else pc += (Sint8)(x); }
30+
31+int
32+uxn_eval(Uxn *u, Uint16 pc)
33+{
34+ unsigned int a, b, c, j, k, bs, instr, errcode;
35+ Uint8 kptr, *sp;
36+ Stack *src, *dst;
37+ Device *dev;
38+ if(!pc || u->dev[0].dat[0xf]) return 0;
39+ while((instr = u->ram[pc++])) {
40+ /* Return Mode */
41+ if(instr & 0x40) {
42+ src = &u->rst; dst = &u->wst;
43+ } else {
44+ src = &u->wst; dst = &u->rst;
45+ }
46+ /* Keep Mode */
47+ if(instr & 0x80) {
48+ kptr = src->ptr;
49+ sp = &kptr;
50+ } else {
51+ sp = &src->ptr;
52+ }
53+ /* Short Mode */
54+ bs = instr & 0x20 ? 1 : 0;
55+ switch(instr & 0x1f) {
56+ /* Stack */
57+ case 0x00: /* LIT */ if(bs) { PEEK16(a, pc) PUSH16(src, a) pc += 2; }
58+ else { a = u->ram[pc]; PUSH8(src, a) pc++; } break;
59+ case 0x01: /* INC */ POP(a) PUSH(src, a + 1) break;
60+ case 0x02: /* POP */ POP(a) break;
61+ case 0x03: /* DUP */ POP(a) PUSH(src, a) PUSH(src, a) break;
62+ case 0x04: /* NIP */ POP(a) POP(b) PUSH(src, a) break;
63+ case 0x05: /* SWP */ POP(a) POP(b) PUSH(src, a) PUSH(src, b) break;
64+ case 0x06: /* OVR */ POP(a) POP(b) PUSH(src, b) PUSH(src, a) PUSH(src, b) break;
65+ case 0x07: /* ROT */ POP(a) POP(b) POP(c) PUSH(src, b) PUSH(src, a) PUSH(src, c) break;
66+ /* Logic */
67+ case 0x08: /* EQU */ POP(a) POP(b) PUSH8(src, b == a) break;
68+ case 0x09: /* NEQ */ POP(a) POP(b) PUSH8(src, b != a) break;
69+ case 0x0a: /* GTH */ POP(a) POP(b) PUSH8(src, b > a) break;
70+ case 0x0b: /* LTH */ POP(a) POP(b) PUSH8(src, b < a) break;
71+ case 0x0c: /* JMP */ POP(a) WARP(a) break;
72+ case 0x0d: /* JCN */ POP(a) POP8(b) if(b) WARP(a) break;
73+ case 0x0e: /* JSR */ POP(a) PUSH16(dst, pc) WARP(a) break;
74+ case 0x0f: /* STH */ POP(a) PUSH(dst, a) break;
75+ /* Memory */
76+ case 0x10: /* LDZ */ POP8(a) PEEK(b, a) PUSH(src, b) break;
77+ case 0x11: /* STZ */ POP8(a) POP(b) POKE(a, b) break;
78+ case 0x12: /* LDR */ POP8(a) PEEK(b, pc + (Sint8)a) PUSH(src, b) break;
79+ case 0x13: /* STR */ POP8(a) POP(b) c = pc + (Sint8)a; POKE(c, b) break;
80+ case 0x14: /* LDA */ POP16(a) PEEK(b, a) PUSH(src, b) break;
81+ case 0x15: /* STA */ POP16(a) POP(b) POKE(a, b) break;
82+ case 0x16: /* DEI */ POP8(a) DEVR(b, &u->dev[a >> 4], a) PUSH(src, b) break;
83+ case 0x17: /* DEO */ POP8(a) POP(b) DEVW(&u->dev[a >> 4], a, b) break;
84+ /* Arithmetic */
85+ case 0x18: /* ADD */ POP(a) POP(b) PUSH(src, b + a) break;
86+ case 0x19: /* SUB */ POP(a) POP(b) PUSH(src, b - a) break;
87+ case 0x1a: /* MUL */ POP(a) POP(b) PUSH(src, (Uint32)b * a) break;
88+ case 0x1b: /* DIV */ POP(a) POP(b) if(a == 0) { errcode = 4; goto err; } PUSH(src, b / a) break;
89+ case 0x1c: /* AND */ POP(a) POP(b) PUSH(src, b & a) break;
90+ case 0x1d: /* ORA */ POP(a) POP(b) PUSH(src, b | a) break;
91+ case 0x1e: /* EOR */ POP(a) POP(b) PUSH(src, b ^ a) break;
92+ case 0x1f: /* SFT */ POP8(a) POP(b) c = b >> (a & 0x0f) << ((a & 0xf0) >> 4); PUSH(src, c) break;
93+ }
94+ }
95+ return 1;
96+
97+err:
98+ /* set 1 in errcode if it involved the return stack instead of the working stack */
99+ /* (stack overflow & ( opcode was STH / JSR )) ^ Return Mode */
100+ errcode |= ((errcode >> 1 & ((instr & 0x1e) == 0x0e)) ^ instr >> 6) & 1;
101+ return uxn_halt(u, errcode, pc - 1);
102+}
103+
104+/* clang-format on */
105+
106+int
107+uxn_boot(Uxn *u, Uint8 *ram)
108+{
109+ Uint32 i;
110+ char *cptr = (char *)u;
111+ for(i = 0; i < sizeof(*u); i++)
112+ cptr[i] = 0x00;
113+ u->ram = ram;
114+ return 1;
115+}
116+
117+Device *
118+uxn_port(Uxn *u, Uint8 id, Uint8 (*deifn)(Device *d, Uint8 port), void (*deofn)(Device *d, Uint8 port))
119+{
120+ Device *d = &u->dev[id];
121+ d->u = u;
122+ d->dei = deifn;
123+ d->deo = deofn;
124+ return d;
125+}
R uxn.h =>
src/uxn.h
+19,
-17
1@@ -1,3 +1,6 @@
2+#ifndef UXN_UXN_H
3+#define UXN_UXN_H
4+
5 /*
6 Copyright (c) 2021 Devine Lu Linvega
7
8@@ -17,34 +20,33 @@ typedef unsigned int Uint32;
9
10 #define PAGE_PROGRAM 0x0100
11
12-typedef struct {
13- Uint8 ptr, kptr, error;
14- Uint8 dat[256];
15-} Stack;
16+/* clang-format off */
17+
18+#define DEVPEEK16(o, x) { (o) = (d->dat[(x)] << 8) + d->dat[(x) + 1]; }
19+#define DEVPOKE16(x, y) { d->dat[(x)] = (y) >> 8; d->dat[(x) + 1] = (y); }
20+#define GETVECTOR(d) ((d)->dat[0] << 8 | (d)->dat[1])
21+
22+/* clang-format on */
23
24 typedef struct {
25- Uint16 ptr;
26- Uint8 dat[65536];
27-} Memory;
28+ Uint8 ptr, dat[255];
29+} Stack;
30
31 typedef struct Device {
32 struct Uxn *u;
33- Uint8 addr, dat[16], *mem;
34- Uint16 vector;
35+ Uint8 dat[16];
36 Uint8 (*dei)(struct Device *d, Uint8);
37 void (*deo)(struct Device *d, Uint8);
38 } Device;
39
40 typedef struct Uxn {
41- Stack wst, rst, *src, *dst;
42- Memory ram;
43+ Uint8 *ram;
44+ Stack wst, rst;
45 Device dev[16];
46 } Uxn;
47
48-void poke16(Uint8 *m, Uint16 a, Uint16 b);
49-Uint16 peek16(Uint8 *m, Uint16 a);
50-
51-int uxn_boot(Uxn *c);
52-int uxn_eval(Uxn *u, Uint16 vec);
53-int uxn_halt(Uxn *u, Uint8 error, char *name, int id);
54+int uxn_boot(Uxn *u, Uint8 *ram);
55+int uxn_eval(Uxn *u, Uint16 pc);
56+int uxn_halt(Uxn *u, Uint8 error, Uint16 addr);
57 Device *uxn_port(Uxn *u, Uint8 id, Uint8 (*deifn)(Device *, Uint8), void (*deofn)(Device *, Uint8));
58+#endif /* UXN_UXN_H */
+151,
-0
1@@ -0,0 +1,151 @@
2+#include <stdio.h>
3+#include <time.h>
4+#include <unistd.h>
5+
6+#include <X11/Xlib.h>
7+#include <stdlib.h>
8+#include <string.h>
9+
10+#define WIDTH 64 * 8
11+#define HEIGHT 40 * 8
12+
13+#include "uxn.h"
14+#include "devices/system.h"
15+#include "devices/screen.h"
16+
17+static Device *devsystem, *devconsole, *devscreen;
18+
19+static int
20+error(char *msg, const char *err)
21+{
22+ fprintf(stderr, "Error %s: %s\n", msg, err);
23+ return 0;
24+}
25+
26+static int
27+set_size(Uint16 width, Uint16 height, int is_resize)
28+{
29+ screen_resize(&uxn_screen, width, height);
30+ return 1;
31+}
32+
33+void
34+system_deo_special(Device *d, Uint8 port)
35+{
36+ if(port > 0x7 && port < 0xe)
37+ screen_palette(&uxn_screen, &d->dat[0x8]);
38+}
39+
40+static void
41+console_deo(Device *d, Uint8 port)
42+{
43+ FILE *fd = port == 0x8 ? stdout : port == 0x9 ? stderr
44+ : 0;
45+ if(fd) {
46+ fputc(d->dat[port], fd);
47+ fflush(fd);
48+ }
49+}
50+
51+static Uint8
52+nil_dei(Device *d, Uint8 port)
53+{
54+ return d->dat[port];
55+}
56+
57+static void
58+nil_deo(Device *d, Uint8 port)
59+{
60+ (void)d;
61+ (void)port;
62+}
63+
64+static int
65+load(Uxn *u, char *filepath)
66+{
67+ FILE *f;
68+ int r;
69+ if(!(f = fopen(filepath, "rb"))) return 0;
70+ r = fread(u->ram + PAGE_PROGRAM, 1, 0x10000 - PAGE_PROGRAM, f);
71+ fclose(f);
72+ if(r < 1) return 0;
73+ fprintf(stderr, "Loaded %s\n", filepath);
74+ return 1;
75+}
76+
77+void
78+processEvent(Display *display, Window window, XImage *ximage, int width, int height)
79+{
80+ XEvent ev;
81+ XNextEvent(display, &ev);
82+ switch(ev.type) {
83+ case Expose:
84+ XPutImage(display, window, DefaultGC(display, 0), ximage, 0, 0, 0, 0, width, height);
85+ break;
86+ case ButtonPress:
87+ exit(0);
88+ }
89+}
90+
91+static int
92+start(Uxn *u)
93+{
94+ if(!uxn_boot(u, (Uint8 *)calloc(0x10000, sizeof(Uint8))))
95+ return error("Boot", "Failed");
96+ /* system */ devsystem = uxn_port(u, 0x0, system_dei, system_deo);
97+ /* console */ devconsole = uxn_port(u, 0x1, nil_dei, console_deo);
98+ /* screen */ devscreen = uxn_port(u, 0x2, screen_dei, screen_deo);
99+ /* empty */ uxn_port(u, 0x3, nil_dei, nil_deo);
100+ /* empty */ uxn_port(u, 0x4, nil_dei, nil_deo);
101+ /* empty */ uxn_port(u, 0x5, nil_dei, nil_deo);
102+ /* empty */ uxn_port(u, 0x6, nil_dei, nil_deo);
103+ /* empty */ uxn_port(u, 0x7, nil_dei, nil_deo);
104+ /* empty */ uxn_port(u, 0x8, nil_dei, nil_deo);
105+ /* empty */ uxn_port(u, 0x9, nil_dei, nil_deo);
106+ /* file */ uxn_port(u, 0xa, nil_dei, nil_deo);
107+ /* datetime */ uxn_port(u, 0xb, nil_dei, nil_deo);
108+ /* empty */ uxn_port(u, 0xc, nil_dei, nil_deo);
109+ /* empty */ uxn_port(u, 0xd, nil_dei, nil_deo);
110+ /* empty */ uxn_port(u, 0xe, nil_dei, nil_deo);
111+ /* empty */ uxn_port(u, 0xf, nil_dei, nil_deo);
112+ return 1;
113+}
114+
115+int
116+main(int argc, char **argv)
117+{
118+ Uxn u;
119+
120+ if(argc < 2)
121+ return error("Usage", "uxncli game.rom args");
122+ if(!start(&u))
123+ return error("Start", "Failed");
124+ if(!load(&u, argv[1]))
125+ return error("Load", "Failed");
126+
127+ if(!set_size(WIDTH, HEIGHT, 0))
128+ return error("Window", "Failed to set window size.");
129+
130+ if(!uxn_eval(&u, PAGE_PROGRAM))
131+ return error("Boot", "Failed to start rom.");
132+
133+ screen_redraw(&uxn_screen, uxn_screen.pixels);
134+
135+ XImage *ximage;
136+ Display *display = XOpenDisplay(NULL);
137+ Visual *visual = DefaultVisual(display, 0);
138+ Window window = XCreateSimpleWindow(display, RootWindow(display, 0), 0, 0, uxn_screen.width, uxn_screen.height, 1, 0, 0);
139+ if(visual->class != TrueColor) {
140+ fprintf(stderr, "Cannot handle non true color visual ...\n");
141+ exit(1);
142+ }
143+
144+ ximage = XCreateImage(display, visual, DefaultDepth(display, DefaultScreen(display)), ZPixmap, 0, (char *)uxn_screen.pixels, uxn_screen.width, uxn_screen.height, 32, 0);
145+
146+ XSelectInput(display, window, ButtonPressMask | ExposureMask);
147+ XMapWindow(display, window);
148+ while(1) {
149+ processEvent(display, window, ximage, uxn_screen.width, uxn_screen.height);
150+ }
151+ return 0;
152+}
+148,
-0
1@@ -0,0 +1,148 @@
2+#include <stdio.h>
3+#include <stdlib.h>
4+
5+#include "uxn.h"
6+#include "devices/system.h"
7+#include "devices/file.h"
8+#include "devices/datetime.h"
9+
10+/*
11+Copyright (c) 2021 Devine Lu Linvega
12+
13+Permission to use, copy, modify, and distribute this software for any
14+purpose with or without fee is hereby granted, provided that the above
15+copyright notice and this permission notice appear in all copies.
16+
17+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
18+WITH REGARD TO THIS SOFTWARE.
19+*/
20+
21+static Device *devfile0;
22+
23+static int
24+error(char *msg, const char *err)
25+{
26+ fprintf(stderr, "Error %s: %s\n", msg, err);
27+ return 0;
28+}
29+
30+void
31+system_deo_special(Device *d, Uint8 port)
32+{
33+ (void)d;
34+ (void)port;
35+}
36+
37+static void
38+console_deo(Device *d, Uint8 port)
39+{
40+ FILE *fd = port == 0x8 ? stdout : port == 0x9 ? stderr
41+ : 0;
42+ if(fd) {
43+ fputc(d->dat[port], fd);
44+ fflush(fd);
45+ }
46+}
47+
48+static void
49+file_deo(Device *d, Uint8 port)
50+{
51+ file_i_deo(d - devfile0, d, port);
52+}
53+
54+static Uint8
55+file_dei(Device *d, Uint8 port)
56+{
57+ return file_i_dei(d - devfile0, d, port);
58+}
59+
60+static Uint8
61+nil_dei(Device *d, Uint8 port)
62+{
63+ return d->dat[port];
64+}
65+
66+static void
67+nil_deo(Device *d, Uint8 port)
68+{
69+ (void)d;
70+ (void)port;
71+}
72+
73+static int
74+console_input(Uxn *u, char c)
75+{
76+ Device *d = &u->dev[1];
77+ d->dat[0x2] = c;
78+ return uxn_eval(u, GETVECTOR(d));
79+}
80+
81+static void
82+run(Uxn *u)
83+{
84+ Device *d = &u->dev[0];
85+ while(!d->dat[0xf]) {
86+ int c = fgetc(stdin);
87+ if(c != EOF)
88+ console_input(u, (Uint8)c);
89+ }
90+}
91+
92+static int
93+load(Uxn *u, char *filepath)
94+{
95+ FILE *f;
96+ int r;
97+ if(!(f = fopen(filepath, "rb"))) return 0;
98+ r = fread(u->ram + PAGE_PROGRAM, 1, 0x10000 - PAGE_PROGRAM, f);
99+ fclose(f);
100+ if(r < 1) return 0;
101+ fprintf(stderr, "Loaded %s\n", filepath);
102+ return 1;
103+}
104+
105+static int
106+start(Uxn *u)
107+{
108+ if(!uxn_boot(u, (Uint8 *)calloc(0x10000, sizeof(Uint8))))
109+ return error("Boot", "Failed");
110+ /* system */ uxn_port(u, 0x0, system_dei, system_deo);
111+ /* console */ uxn_port(u, 0x1, nil_dei, console_deo);
112+ /* empty */ uxn_port(u, 0x2, nil_dei, nil_deo);
113+ /* empty */ uxn_port(u, 0x3, nil_dei, nil_deo);
114+ /* empty */ uxn_port(u, 0x4, nil_dei, nil_deo);
115+ /* empty */ uxn_port(u, 0x5, nil_dei, nil_deo);
116+ /* empty */ uxn_port(u, 0x6, nil_dei, nil_deo);
117+ /* empty */ uxn_port(u, 0x7, nil_dei, nil_deo);
118+ /* empty */ uxn_port(u, 0x8, nil_dei, nil_deo);
119+ /* empty */ uxn_port(u, 0x9, nil_dei, nil_deo);
120+ /* file0 */ devfile0 = uxn_port(u, 0xa, file_dei, file_deo);
121+ /* file1 */ uxn_port(u, 0xb, file_dei, file_deo);
122+ /* datetime */ uxn_port(u, 0xc, datetime_dei, nil_deo);
123+ /* empty */ uxn_port(u, 0xd, nil_dei, nil_deo);
124+ /* empty */ uxn_port(u, 0xe, nil_dei, nil_deo);
125+ /* empty */ uxn_port(u, 0xf, nil_dei, nil_deo);
126+ return 1;
127+}
128+
129+int
130+main(int argc, char **argv)
131+{
132+ Uxn u;
133+ int i;
134+ if(argc < 2)
135+ return error("Usage", "uxncli game.rom args");
136+ if(!start(&u))
137+ return error("Start", "Failed");
138+ if(!load(&u, argv[1]))
139+ return error("Load", "Failed");
140+ if(!uxn_eval(&u, PAGE_PROGRAM))
141+ return error("Init", "Failed");
142+ for(i = 2; i < argc; i++) {
143+ char *p = argv[i];
144+ while(*p) console_input(&u, *p++);
145+ console_input(&u, '\n');
146+ }
147+ run(&u);
148+ return 0;
149+}
D
uxn.c
+0,
-158
1@@ -1,158 +0,0 @@
2-#include "uxn.h"
3-
4-/*
5-Copyright (u) 2021 Devine Lu Linvega
6-Copyright (u) 2021 Andrew Alderwick
7-
8-Permission to use, copy, modify, and distribute this software for any
9-purpose with or without fee is hereby granted, provided that the above
10-copyright notice and this permission notice appear in all copies.
11-
12-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13-WITH REGARD TO THIS SOFTWARE.
14-*/
15-
16-#define MODE_SHORT 0x20
17-#define MODE_RETURN 0x40
18-#define MODE_KEEP 0x80
19-
20-#pragma mark - Operations
21-
22-/* clang-format off */
23-
24-/* Utilities */
25-static void (*push)(Stack *s, Uint16 a);
26-static Uint16 (*pop8)(Stack *s);
27-static Uint16 (*pop)(Stack *s);
28-static void (*poke)(Uint8 *m, Uint16 a, Uint16 b);
29-static Uint16 (*peek)(Uint8 *m, Uint16 a);
30-static void (*devw)(Device *d, Uint8 a, Uint16 b);
31-static Uint16 (*devr)(Device *d, Uint8 a);
32-static void (*warp)(Uxn *u, Uint16 a);
33-static void (*pull)(Uxn *u);
34-/* byte mode */
35-static void push8(Stack *s, Uint16 a) { if(s->ptr == 0xff) { s->error = 2; return; } s->dat[s->ptr++] = a; }
36-static Uint16 pop8k(Stack *s) { if(s->kptr == 0) { s->error = 1; return 0; } return s->dat[--s->kptr]; }
37-static Uint16 pop8d(Stack *s) { if(s->ptr == 0) { s->error = 1; return 0; } return s->dat[--s->ptr]; }
38-static void poke8(Uint8 *m, Uint16 a, Uint16 b) { m[a] = b; }
39-static Uint16 peek8(Uint8 *m, Uint16 a) { return m[a]; }
40-static void devw8(Device *d, Uint8 a, Uint16 b) { d->dat[a & 0xf] = b; d->deo(d, a & 0x0f); }
41-static Uint16 devr8(Device *d, Uint8 a) { return d->dei(d, a & 0x0f); }
42-static void warp8(Uxn *u, Uint16 a){ u->ram.ptr += (Sint8)a; }
43-static void pull8(Uxn *u){ push8(u->src, peek8(u->ram.dat, u->ram.ptr++)); }
44-/* short mode */
45-static void push16(Stack *s, Uint16 a) { push8(s, a >> 8); push8(s, a); }
46-static Uint16 pop16(Stack *s) { Uint8 a = pop8(s), b = pop8(s); return a + (b << 8); }
47- void poke16(Uint8 *m, Uint16 a, Uint16 b) { poke8(m, a, b >> 8); poke8(m, a + 1, b); }
48- Uint16 peek16(Uint8 *m, Uint16 a) { return (peek8(m, a) << 8) + peek8(m, a + 1); }
49-static void devw16(Device *d, Uint8 a, Uint16 b) { devw8(d, a, b >> 8); devw8(d, a + 1, b); }
50-static Uint16 devr16(Device *d, Uint8 a) { return (devr8(d, a) << 8) + devr8(d, a + 1); }
51-static void warp16(Uxn *u, Uint16 a){ u->ram.ptr = a; }
52-static void pull16(Uxn *u){ push16(u->src, peek16(u->ram.dat, u->ram.ptr++)); u->ram.ptr++; }
53-
54-#pragma mark - Core
55-
56-int
57-uxn_eval(Uxn *u, Uint16 vec)
58-{
59- Uint8 instr;
60- Uint16 a,b,c;
61- if(!vec || u->dev[0].dat[0xf])
62- return 0;
63- u->ram.ptr = vec;
64- if(u->wst.ptr > 0xf8) u->wst.ptr = 0xf8;
65- while((instr = u->ram.dat[u->ram.ptr++])) {
66- /* Return Mode */
67- if(instr & MODE_RETURN) {
68- u->src = &u->rst;
69- u->dst = &u->wst;
70- } else {
71- u->src = &u->wst;
72- u->dst = &u->rst;
73- }
74- /* Keep Mode */
75- if(instr & MODE_KEEP) {
76- pop8 = pop8k;
77- u->src->kptr = u->src->ptr;
78- } else {
79- pop8 = pop8d;
80- }
81- /* Short Mode */
82- if(instr & MODE_SHORT) {
83- push = push16; pop = pop16;
84- poke = poke16; peek = peek16;
85- devw = devw16; devr = devr16;
86- warp = warp16; pull = pull16;
87- } else {
88- push = push8; pop = pop8;
89- poke = poke8; peek = peek8;
90- devw = devw8; devr = devr8;
91- warp = warp8; pull = pull8;
92- }
93- switch(instr & 0x1f){
94- /* Stack */
95- case 0x00: /* LIT */ pull(u); break;
96- case 0x01: /* INC */ a = pop(u->src); push(u->src, a + 1); break;
97- case 0x02: /* POP */ pop(u->src); break;
98- case 0x03: /* DUP */ a = pop(u->src); push(u->src, a); push(u->src, a); break;
99- case 0x04: /* NIP */ a = pop(u->src); pop(u->src); push(u->src, a); break;
100- case 0x05: /* SWP */ a = pop(u->src), b = pop(u->src); push(u->src, a); push(u->src, b); break;
101- case 0x06: /* OVR */ a = pop(u->src), b = pop(u->src); push(u->src, b); push(u->src, a); push(u->src, b); break;
102- case 0x07: /* ROT */ a = pop(u->src), b = pop(u->src), c = pop(u->src); push(u->src, b); push(u->src, a); push(u->src, c); break;
103- /* Logic */
104- case 0x08: /* EQU */ a = pop(u->src), b = pop(u->src); push8(u->src, b == a); break;
105- case 0x09: /* NEQ */ a = pop(u->src), b = pop(u->src); push8(u->src, b != a); break;
106- case 0x0a: /* GTH */ a = pop(u->src), b = pop(u->src); push8(u->src, b > a); break;
107- case 0x0b: /* LTH */ a = pop(u->src), b = pop(u->src); push8(u->src, b < a); break;
108- case 0x0c: /* JMP */ a = pop(u->src); warp(u, a); break;
109- case 0x0d: /* JCN */ a = pop(u->src); if(pop8(u->src)) warp(u, a); break;
110- case 0x0e: /* JSR */ a = pop(u->src); push16(u->dst, u->ram.ptr); warp(u, a); break;
111- case 0x0f: /* STH */ a = pop(u->src); push(u->dst, a); break;
112- /* Memory */
113- case 0x10: /* LDZ */ a = pop8(u->src); push(u->src, peek(u->ram.dat, a)); break;
114- case 0x11: /* STZ */ a = pop8(u->src); b = pop(u->src); poke(u->ram.dat, a, b); break;
115- case 0x12: /* LDR */ a = pop8(u->src); push(u->src, peek(u->ram.dat, u->ram.ptr + (Sint8)a)); break;
116- case 0x13: /* STR */ a = pop8(u->src); b = pop(u->src); poke(u->ram.dat, u->ram.ptr + (Sint8)a, b); break;
117- case 0x14: /* LDA */ a = pop16(u->src); push(u->src, peek(u->ram.dat, a)); break;
118- case 0x15: /* STA */ a = pop16(u->src); b = pop(u->src); poke(u->ram.dat, a, b); break;
119- case 0x16: /* DEI */ a = pop8(u->src); push(u->src, devr(&u->dev[a >> 4], a)); break;
120- case 0x17: /* DEO */ a = pop8(u->src); b = pop(u->src); devw(&u->dev[a >> 4], a, b); break;
121- /* Arithmetic */
122- case 0x18: /* ADD */ a = pop(u->src), b = pop(u->src); push(u->src, b + a); break;
123- case 0x19: /* SUB */ a = pop(u->src), b = pop(u->src); push(u->src, b - a); break;
124- case 0x1a: /* MUL */ a = pop(u->src), b = pop(u->src); push(u->src, (Uint32)b * a); break;
125- case 0x1b: /* DIV */ a = pop(u->src), b = pop(u->src); if(a == 0) { u->src->error = 3; a = 1; } push(u->src, b / a); break;
126- case 0x1c: /* AND */ a = pop(u->src), b = pop(u->src); push(u->src, b & a); break;
127- case 0x1d: /* ORA */ a = pop(u->src), b = pop(u->src); push(u->src, b | a); break;
128- case 0x1e: /* EOR */ a = pop(u->src), b = pop(u->src); push(u->src, b ^ a); break;
129- case 0x1f: /* SFT */ a = pop8(u->src), b = pop(u->src); push(u->src, b >> (a & 0x0f) << ((a & 0xf0) >> 4)); break;
130- }
131- if(u->wst.error) return uxn_halt(u, u->wst.error, "Working-stack", instr);
132- if(u->rst.error) return uxn_halt(u, u->rst.error, "Return-stack", instr);
133- }
134- return 1;
135-}
136-
137-/* clang-format on */
138-
139-int
140-uxn_boot(Uxn *u)
141-{
142- Uint32 i;
143- char *cptr = (char *)u;
144- for(i = 0; i < sizeof(*u); ++i)
145- cptr[i] = 0x00;
146- return 1;
147-}
148-
149-Device *
150-uxn_port(Uxn *u, Uint8 id, Uint8 (*deifn)(Device *d, Uint8 port), void (*deofn)(Device *d, Uint8 port))
151-{
152- Device *d = &u->dev[id];
153- d->addr = id * 0x10;
154- d->u = u;
155- d->mem = u->ram.dat;
156- d->dei = deifn;
157- d->deo = deofn;
158- return d;
159-}
D
uxn11.c
+0,
-266
1@@ -1,266 +0,0 @@
2-#include <stdio.h>
3-#include <time.h>
4-#include <unistd.h>
5-
6-#include <X11/Xlib.h>
7-#include <stdlib.h>
8-#include <string.h>
9-
10-#define WIDTH 64 * 8
11-#define HEIGHT 40 * 8
12-#define FIXED_SIZE 0
13-
14-#include "uxn.h"
15-
16-#include "devices/ppu.h"
17-static Ppu ppu;
18-
19-static Device *devsystem, *devconsole, *devscreen;
20-static Uint32 *ppu_screen;
21-
22-static int
23-error(char *msg, const char *err)
24-{
25- fprintf(stderr, "Error %s: %s\n", msg, err);
26- return 0;
27-}
28-
29-static int
30-set_size(Uint16 width, Uint16 height, int is_resize)
31-{
32- ppu_resize(&ppu, width, height);
33- if(!(ppu_screen =
34- realloc(ppu_screen, ppu.width * ppu.height * sizeof(Uint32))))
35- return error("ppu_screen", "Memory failure");
36- memset(ppu_screen, 0, ppu.width * ppu.height * sizeof(Uint32));
37- printf("%d x %d(%d)\n", width, height, is_resize);
38- return 1;
39-}
40-
41-static Uint8
42-system_dei(Device *d, Uint8 port)
43-{
44- switch(port) {
45- case 0x2:
46- return d->u->wst.ptr;
47- case 0x3:
48- return d->u->rst.ptr;
49- default:
50- return d->dat[port];
51- }
52-}
53-
54-static void
55-system_deo(Device *d, Uint8 port)
56-{
57- switch(port) {
58- case 0x2:
59- d->u->wst.ptr = d->dat[port];
60- break;
61- case 0x3:
62- d->u->rst.ptr = d->dat[port];
63- break;
64- }
65- if(port > 0x7 && port < 0xe)
66- ppu_palette(&ppu, &d->dat[0x8]);
67-}
68-
69-static void
70-console_deo(Device *d, Uint8 port)
71-{
72- if(port == 0x1)
73- d->vector = peek16(d->dat, 0x0);
74- if(port > 0x7)
75- write(port - 0x7, (char *)&d->dat[port], 1);
76-}
77-
78-static Uint8
79-screen_dei(Device *d, Uint8 port)
80-{
81- switch(port) {
82- case 0x2:
83- return ppu.width >> 8;
84- case 0x3:
85- return ppu.width;
86- case 0x4:
87- return ppu.height >> 8;
88- case 0x5:
89- return ppu.height;
90- default:
91- return d->dat[port];
92- }
93-}
94-
95-static void
96-screen_deo(Device *d, Uint8 port)
97-{
98- switch(port) {
99- case 0x1:
100- d->vector = peek16(d->dat, 0x0);
101- break;
102- case 0x5:
103- if(!FIXED_SIZE)
104- set_size(peek16(d->dat, 0x2), peek16(d->dat, 0x4), 1);
105- break;
106- case 0xe: {
107- Uint16 x = peek16(d->dat, 0x8);
108- Uint16 y = peek16(d->dat, 0xa);
109- Uint8 layer = d->dat[0xe] & 0x40;
110- ppu_write(&ppu, layer ? &ppu.fg : &ppu.bg, x, y, d->dat[0xe] & 0x3);
111- if(d->dat[0x6] & 0x01)
112- poke16(d->dat, 0x8, x + 1); /* auto x+1 */
113- if(d->dat[0x6] & 0x02)
114- poke16(d->dat, 0xa, y + 1); /* auto y+1 */
115- break;
116- }
117- case 0xf: {
118- Uint16 x = peek16(d->dat, 0x8);
119- Uint16 y = peek16(d->dat, 0xa);
120- Layer *layer = (d->dat[0xf] & 0x40) ? &ppu.fg : &ppu.bg;
121- Uint8 *addr = &d->mem[peek16(d->dat, 0xc)];
122- Uint8 twobpp = !!(d->dat[0xf] & 0x80);
123- ppu_blit(&ppu, layer, x, y, addr, d->dat[0xf] & 0xf, d->dat[0xf] & 0x10, d->dat[0xf] & 0x20, twobpp);
124- if(d->dat[0x6] & 0x04)
125- poke16(d->dat, 0xc, peek16(d->dat, 0xc) + 8 + twobpp * 8); /* auto addr+8 / auto addr+16 */
126- if(d->dat[0x6] & 0x01)
127- poke16(d->dat, 0x8, x + 8); /* auto x+8 */
128- if(d->dat[0x6] & 0x02)
129- poke16(d->dat, 0xa, y + 8); /* auto y+8 */
130- break;
131- }
132- }
133-}
134-
135-static Uint8
136-nil_dei(Device *d, Uint8 port)
137-{
138- return d->dat[port];
139-}
140-
141-static void
142-nil_deo(Device *d, Uint8 port)
143-{
144- if(port == 0x1)
145- d->vector = peek16(d->dat, 0x0);
146-}
147-
148-static const char *errors[] = {"underflow", "overflow", "division by zero"};
149-
150-int
151-uxn_halt(Uxn *u, Uint8 error, char *name, int id)
152-{
153- fprintf(stderr, "Halted: %s %s#%04x, at 0x%04x\n", name, errors[error - 1], id, u->ram.ptr);
154- return 0;
155-}
156-
157-static int
158-load(Uxn *u, char *filepath)
159-{
160- FILE *f;
161- int r;
162- if(!(f = fopen(filepath, "rb")))
163- return 0;
164- r = fread(u->ram.dat + PAGE_PROGRAM, 1, sizeof(u->ram.dat) - PAGE_PROGRAM, f);
165- fclose(f);
166- if(r < 1)
167- return 0;
168- fprintf(stderr, "Loaded %s\n", filepath);
169- return 1;
170-}
171-
172-// ---------------------------
173-
174-void
175-processEvent(Display *display, Window window, XImage *ximage, int width, int height)
176-{
177- static char *tir = "This is red";
178- static char *tig = "This is green";
179- static char *tib = "This is blue";
180- XEvent ev;
181- XNextEvent(display, &ev);
182- switch(ev.type) {
183- case Expose:
184- XPutImage(display, window, DefaultGC(display, 0), ximage, 0, 0, 0, 0, width, height);
185- XSetForeground(display, DefaultGC(display, 0), 0x00ff0000); // red
186- XDrawString(display, window, DefaultGC(display, 0), 32, 32, tir, strlen(tir));
187- XDrawString(display, window, DefaultGC(display, 0), 32 + 256, 32, tir, strlen(tir));
188- XDrawString(display, window, DefaultGC(display, 0), 32 + 256, 32 + 256, tir, strlen(tir));
189- XDrawString(display, window, DefaultGC(display, 0), 32, 32 + 256, tir, strlen(tir));
190- XSetForeground(display, DefaultGC(display, 0), 0x0000ff00); // green
191- XDrawString(display, window, DefaultGC(display, 0), 32, 52, tig, strlen(tig));
192- XDrawString(display, window, DefaultGC(display, 0), 32 + 256, 52, tig, strlen(tig));
193- XDrawString(display, window, DefaultGC(display, 0), 32 + 256, 52 + 256, tig, strlen(tig));
194- XDrawString(display, window, DefaultGC(display, 0), 32, 52 + 256, tig, strlen(tig));
195- XSetForeground(display, DefaultGC(display, 0), 0x000000ff); // blue
196- XDrawString(display, window, DefaultGC(display, 0), 32, 72, tib, strlen(tib));
197- XDrawString(display, window, DefaultGC(display, 0), 32 + 256, 72, tib, strlen(tib));
198- XDrawString(display, window, DefaultGC(display, 0), 32 + 256, 72 + 256, tib, strlen(tib));
199- XDrawString(display, window, DefaultGC(display, 0), 32, 72 + 256, tib, strlen(tib));
200- break;
201- case ButtonPress:
202- exit(0);
203- }
204-}
205-
206-int
207-main(int argc, char **argv)
208-{
209-
210- Uxn u;
211- int i, loaded = 0;
212-
213- if(!uxn_boot(&u))
214- return error("Boot", "Failed");
215-
216- /* system */ devsystem = uxn_port(&u, 0x0, system_dei, system_deo);
217- /* console */ devconsole = uxn_port(&u, 0x1, nil_dei, console_deo);
218- /* screen */ devscreen = uxn_port(&u, 0x2, screen_dei, screen_deo);
219- /* empty */ uxn_port(&u, 0x3, nil_dei, nil_deo);
220- /* empty */ uxn_port(&u, 0x4, nil_dei, nil_deo);
221- /* empty */ uxn_port(&u, 0x5, nil_dei, nil_deo);
222- /* empty */ uxn_port(&u, 0x6, nil_dei, nil_deo);
223- /* empty */ uxn_port(&u, 0x7, nil_dei, nil_deo);
224- /* empty */ uxn_port(&u, 0x8, nil_dei, nil_deo);
225- /* empty */ uxn_port(&u, 0x9, nil_dei, nil_deo);
226- /* file */ uxn_port(&u, 0xa, nil_dei, nil_deo);
227- /* datetime */ uxn_port(&u, 0xb, nil_dei, nil_deo);
228- /* empty */ uxn_port(&u, 0xc, nil_dei, nil_deo);
229- /* empty */ uxn_port(&u, 0xd, nil_dei, nil_deo);
230- /* empty */ uxn_port(&u, 0xe, nil_dei, nil_deo);
231- /* empty */ uxn_port(&u, 0xf, nil_dei, nil_deo);
232-
233- for(i = 1; i < argc; ++i) {
234- if(!loaded++) {
235- if(!load(&u, argv[i]))
236- return error("Load", "Failed");
237- if(!uxn_eval(&u, PAGE_PROGRAM))
238- return error("Init", "Failed");
239- }
240- }
241- if(!loaded)
242- return error("Input", "Missing");
243-
244- if(!set_size(WIDTH, HEIGHT, 0))
245- return error("Window", "Failed to set window size.");
246-
247- if(!uxn_eval(&u, PAGE_PROGRAM))
248- return error("Boot", "Failed to start rom.");
249- ppu_redraw(&ppu, ppu_screen);
250-
251- XImage *ximage;
252- Display *display = XOpenDisplay(NULL);
253- Visual *visual = DefaultVisual(display, 0);
254- Window window = XCreateSimpleWindow(display, RootWindow(display, 0), 0, 0, ppu.width, ppu.height, 1, 0, 0);
255- if(visual->class != TrueColor) {
256- fprintf(stderr, "Cannot handle non true color visual ...\n");
257- exit(1);
258- }
259-
260- ximage = XCreateImage(display, visual, DefaultDepth(display, DefaultScreen(display)), ZPixmap, 0, (Uint8 *)ppu_screen, ppu.width, ppu.height, 32, 0);
261-
262- XSelectInput(display, window, ButtonPressMask | ExposureMask);
263- XMapWindow(display, window);
264- while(1) {
265- processEvent(display, window, ximage, ppu.width, ppu.height);
266- }
267-}
D
uxncli.c
+0,
-214
1@@ -1,214 +0,0 @@
2-#include <stdio.h>
3-#include <unistd.h>
4-#include <time.h>
5-#include "uxn.h"
6-#include "devices/file.h"
7-
8-/*
9-Copyright (c) 2021 Devine Lu Linvega
10-
11-Permission to use, copy, modify, and distribute this software for any
12-purpose with or without fee is hereby granted, provided that the above
13-copyright notice and this permission notice appear in all copies.
14-
15-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
16-WITH REGARD TO THIS SOFTWARE.
17-*/
18-
19-#pragma mark - Core
20-
21-static Device *devsystem, *devconsole;
22-
23-static int
24-error(char *msg, const char *err)
25-{
26- fprintf(stderr, "Error %s: %s\n", msg, err);
27- return 0;
28-}
29-
30-static void
31-inspect(Stack *s, char *name)
32-{
33- Uint8 x, y;
34- fprintf(stderr, "\n%s\n", name);
35- for(y = 0; y < 0x04; ++y) {
36- for(x = 0; x < 0x08; ++x) {
37- Uint8 p = y * 0x08 + x;
38- fprintf(stderr,
39- p == s->ptr ? "[%02x]" : " %02x ",
40- s->dat[p]);
41- }
42- fprintf(stderr, "\n");
43- }
44-}
45-
46-#pragma mark - Devices
47-
48-static Uint8
49-system_dei(Device *d, Uint8 port)
50-{
51- switch(port) {
52- case 0x2: return d->u->wst.ptr;
53- case 0x3: return d->u->rst.ptr;
54- default: return d->dat[port];
55- }
56-}
57-
58-static void
59-system_deo(Device *d, Uint8 port)
60-{
61- switch(port) {
62- case 0x2: d->u->wst.ptr = d->dat[port]; break;
63- case 0x3: d->u->rst.ptr = d->dat[port]; break;
64- case 0xe:
65- inspect(&d->u->wst, "Working-stack");
66- inspect(&d->u->rst, "Return-stack");
67- break;
68- }
69-}
70-
71-static void
72-console_deo(Device *d, Uint8 port)
73-{
74- if(port == 0x1)
75- d->vector = peek16(d->dat, 0x0);
76- if(port > 0x7)
77- write(port - 0x7, (char *)&d->dat[port], 1);
78-}
79-
80-static void
81-file_deo(Device *d, Uint8 port)
82-{
83- switch(port) {
84- case 0x1: d->vector = peek16(d->dat, 0x0); break;
85- case 0x9: poke16(d->dat, 0x2, file_init(&d->mem[peek16(d->dat, 0x8)])); break;
86- case 0xd: poke16(d->dat, 0x2, file_read(&d->mem[peek16(d->dat, 0xc)], peek16(d->dat, 0xa))); break;
87- case 0xf: poke16(d->dat, 0x2, file_write(&d->mem[peek16(d->dat, 0xe)], peek16(d->dat, 0xa), d->dat[0x7])); break;
88- case 0x5: poke16(d->dat, 0x2, file_stat(&d->mem[peek16(d->dat, 0x4)], peek16(d->dat, 0xa))); break;
89- case 0x6: poke16(d->dat, 0x2, file_delete()); break;
90- }
91-}
92-
93-static Uint8
94-datetime_dei(Device *d, Uint8 port)
95-{
96- time_t seconds = time(NULL);
97- struct tm zt = {0};
98- struct tm *t = localtime(&seconds);
99- if(t == NULL)
100- t = &zt;
101- switch(port) {
102- case 0x0: return (t->tm_year + 1900) >> 8;
103- case 0x1: return (t->tm_year + 1900);
104- case 0x2: return t->tm_mon;
105- case 0x3: return t->tm_mday;
106- case 0x4: return t->tm_hour;
107- case 0x5: return t->tm_min;
108- case 0x6: return t->tm_sec;
109- case 0x7: return t->tm_wday;
110- case 0x8: return t->tm_yday >> 8;
111- case 0x9: return t->tm_yday;
112- case 0xa: return t->tm_isdst;
113- default: return d->dat[port];
114- }
115-}
116-
117-static Uint8
118-nil_dei(Device *d, Uint8 port)
119-{
120- return d->dat[port];
121-}
122-
123-static void
124-nil_deo(Device *d, Uint8 port)
125-{
126- if(port == 0x1) d->vector = peek16(d->dat, 0x0);
127-}
128-
129-#pragma mark - Generics
130-
131-static const char *errors[] = {"underflow", "overflow", "division by zero"};
132-
133-int
134-uxn_halt(Uxn *u, Uint8 error, char *name, int id)
135-{
136- fprintf(stderr, "Halted: %s %s#%04x, at 0x%04x\n", name, errors[error - 1], id, u->ram.ptr);
137- return 0;
138-}
139-
140-static int
141-console_input(Uxn *u, char c)
142-{
143- devconsole->dat[0x2] = c;
144- return uxn_eval(u, devconsole->vector);
145-}
146-
147-static void
148-run(Uxn *u)
149-{
150- Uint16 vec;
151- while((!u->dev[0].dat[0xf]) && (read(0, &devconsole->dat[0x2], 1) > 0)) {
152- vec = peek16(devconsole->dat, 0);
153- if(!vec) vec = u->ram.ptr; /* continue after last BRK */
154- uxn_eval(u, vec);
155- }
156-}
157-
158-static int
159-load(Uxn *u, char *filepath)
160-{
161- FILE *f;
162- int r;
163- if(!(f = fopen(filepath, "rb"))) return 0;
164- r = fread(u->ram.dat + PAGE_PROGRAM, 1, sizeof(u->ram.dat) - PAGE_PROGRAM, f);
165- fclose(f);
166- if(r < 1) return 0;
167- fprintf(stderr, "Loaded %s\n", filepath);
168- return 1;
169-}
170-
171-int
172-main(int argc, char **argv)
173-{
174- Uxn u;
175- int i, loaded = 0;
176-
177- if(!uxn_boot(&u))
178- return error("Boot", "Failed");
179-
180- /* system */ devsystem = uxn_port(&u, 0x0, system_dei, system_deo);
181- /* console */ devconsole = uxn_port(&u, 0x1, nil_dei, console_deo);
182- /* empty */ uxn_port(&u, 0x2, nil_dei, nil_deo);
183- /* empty */ uxn_port(&u, 0x3, nil_dei, nil_deo);
184- /* empty */ uxn_port(&u, 0x4, nil_dei, nil_deo);
185- /* empty */ uxn_port(&u, 0x5, nil_dei, nil_deo);
186- /* empty */ uxn_port(&u, 0x6, nil_dei, nil_deo);
187- /* empty */ uxn_port(&u, 0x7, nil_dei, nil_deo);
188- /* empty */ uxn_port(&u, 0x8, nil_dei, nil_deo);
189- /* empty */ uxn_port(&u, 0x9, nil_dei, nil_deo);
190- /* file */ uxn_port(&u, 0xa, nil_dei, file_deo);
191- /* datetime */ uxn_port(&u, 0xb, datetime_dei, nil_deo);
192- /* empty */ uxn_port(&u, 0xc, nil_dei, nil_deo);
193- /* empty */ uxn_port(&u, 0xd, nil_dei, nil_deo);
194- /* empty */ uxn_port(&u, 0xe, nil_dei, nil_deo);
195- /* empty */ uxn_port(&u, 0xf, nil_dei, nil_deo);
196-
197- for(i = 1; i < argc; ++i) {
198- if(!loaded++) {
199- if(!load(&u, argv[i]))
200- return error("Load", "Failed");
201- if(!uxn_eval(&u, PAGE_PROGRAM))
202- return error("Init", "Failed");
203- } else {
204- char *p = argv[i];
205- while(*p) console_input(&u, *p++);
206- console_input(&u, '\n');
207- }
208- }
209- if(!loaded)
210- return error("Input", "Missing");
211-
212- run(&u);
213-
214- return 0;
215-}
D
uxnemu.c
+0,
-577
1@@ -1,577 +0,0 @@
2-#include <stdio.h>
3-#include <unistd.h>
4-#include <time.h>
5-#include "uxn.h"
6-
7-#pragma GCC diagnostic push
8-#pragma clang diagnostic push
9-#pragma GCC diagnostic ignored "-Wpedantic"
10-#pragma clang diagnostic ignored "-Wtypedef-redefinition"
11-#include <SDL.h>
12-#include "devices/ppu.h"
13-#include "devices/apu.h"
14-#include "devices/file.h"
15-#pragma GCC diagnostic pop
16-#pragma clang diagnostic pop
17-
18-/*
19-Copyright (c) 2021 Devine Lu Linvega
20-
21-Permission to use, copy, modify, and distribute this software for any
22-purpose with or without fee is hereby granted, provided that the above
23-copyright notice and this permission notice appear in all copies.
24-
25-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
26-WITH REGARD TO THIS SOFTWARE.
27-*/
28-
29-#define WIDTH 64 * 8
30-#define HEIGHT 40 * 8
31-#define PAD 4
32-#define FIXED_SIZE 0
33-#define POLYPHONY 4
34-#define BENCH 0
35-
36-static SDL_Window *gWindow;
37-static SDL_Texture *gTexture;
38-static SDL_Renderer *gRenderer;
39-static SDL_AudioDeviceID audio_id;
40-static SDL_Rect gRect;
41-/* devices */
42-static Ppu ppu;
43-static Apu apu[POLYPHONY];
44-static Device *devsystem, *devscreen, *devmouse, *devctrl, *devaudio0, *devconsole;
45-static Uint8 zoom = 1;
46-static Uint32 *ppu_screen, stdin_event, audio0_event;
47-
48-static int
49-error(char *msg, const char *err)
50-{
51- fprintf(stderr, "%s: %s\n", msg, err);
52- return 0;
53-}
54-
55-#pragma mark - Generics
56-
57-static void
58-audio_callback(void *u, Uint8 *stream, int len)
59-{
60- int i, running = 0;
61- Sint16 *samples = (Sint16 *)stream;
62- SDL_memset(stream, 0, len);
63- for(i = 0; i < POLYPHONY; ++i)
64- running += apu_render(&apu[i], samples, samples + len / 2);
65- if(!running)
66- SDL_PauseAudioDevice(audio_id, 1);
67- (void)u;
68-}
69-
70-void
71-apu_finished_handler(Apu *c)
72-{
73- SDL_Event event;
74- event.type = audio0_event + (c - apu);
75- SDL_PushEvent(&event);
76-}
77-
78-static int
79-stdin_handler(void *p)
80-{
81- SDL_Event event;
82- event.type = stdin_event;
83- while(read(0, &event.cbutton.button, 1) > 0)
84- SDL_PushEvent(&event);
85- return 0;
86- (void)p;
87-}
88-
89-static void
90-set_window_size(SDL_Window *window, int w, int h)
91-{
92- SDL_Point win, win_old;
93- SDL_GetWindowPosition(window, &win.x, &win.y);
94- SDL_GetWindowSize(window, &win_old.x, &win_old.y);
95- SDL_SetWindowPosition(window, (win.x + win_old.x / 2) - w / 2, (win.y + win_old.y / 2) - h / 2);
96- SDL_SetWindowSize(window, w, h);
97-}
98-
99-static void
100-set_zoom(Uint8 scale)
101-{
102- zoom = SDL_clamp(scale, 1, 3);
103- set_window_size(gWindow, (ppu.width + PAD * 2) * zoom, (ppu.height + PAD * 2) * zoom);
104-}
105-
106-static int
107-set_size(Uint16 width, Uint16 height, int is_resize)
108-{
109- ppu_resize(&ppu, width, height);
110- gRect.x = PAD;
111- gRect.y = PAD;
112- gRect.w = ppu.width;
113- gRect.h = ppu.height;
114- if(!(ppu_screen = realloc(ppu_screen, ppu.width * ppu.height * sizeof(Uint32))))
115- return error("ppu_screen", "Memory failure");
116- memset(ppu_screen, 0, ppu.width * ppu.height * sizeof(Uint32));
117- if(gTexture != NULL) SDL_DestroyTexture(gTexture);
118- SDL_RenderSetLogicalSize(gRenderer, ppu.width + PAD * 2, ppu.height + PAD * 2);
119- gTexture = SDL_CreateTexture(gRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, ppu.width + PAD * 2, ppu.height + PAD * 2);
120- if(gTexture == NULL || SDL_SetTextureBlendMode(gTexture, SDL_BLENDMODE_NONE))
121- return error("gTexture", SDL_GetError());
122- if(SDL_UpdateTexture(gTexture, NULL, ppu_screen, sizeof(Uint32)) != 0)
123- return error("SDL_UpdateTexture", SDL_GetError());
124- if(is_resize)
125- set_window_size(gWindow, (ppu.width + PAD * 2) * zoom, (ppu.height + PAD * 2) * zoom);
126- return 1;
127-}
128-
129-static void
130-capture_screen(void)
131-{
132- const Uint32 format = SDL_PIXELFORMAT_RGB24;
133- time_t t = time(NULL);
134- char fname[64];
135- int w, h;
136- SDL_Surface *surface;
137- SDL_GetRendererOutputSize(gRenderer, &w, &h);
138- surface = SDL_CreateRGBSurfaceWithFormat(0, w, h, 24, format);
139- SDL_RenderReadPixels(gRenderer, NULL, format, surface->pixels, surface->pitch);
140- strftime(fname, sizeof(fname), "screenshot-%Y%m%d-%H%M%S.bmp", localtime(&t));
141- SDL_SaveBMP(surface, fname);
142- SDL_FreeSurface(surface);
143- fprintf(stderr, "Saved %s\n", fname);
144-}
145-
146-static void
147-redraw(Uxn *u)
148-{
149- if(devsystem->dat[0xe])
150- ppu_debug(&ppu, u->wst.dat, u->wst.ptr, u->rst.ptr, u->ram.dat);
151- ppu_redraw(&ppu, ppu_screen);
152- if(SDL_UpdateTexture(gTexture, &gRect, ppu_screen, ppu.width * sizeof(Uint32)) != 0)
153- error("SDL_UpdateTexture", SDL_GetError());
154- SDL_RenderClear(gRenderer);
155- SDL_RenderCopy(gRenderer, gTexture, NULL, NULL);
156- SDL_RenderPresent(gRenderer);
157-}
158-
159-static int
160-init(void)
161-{
162- SDL_AudioSpec as;
163- SDL_zero(as);
164- as.freq = SAMPLE_FREQUENCY;
165- as.format = AUDIO_S16;
166- as.channels = 2;
167- as.callback = audio_callback;
168- as.samples = 512;
169- as.userdata = NULL;
170- if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) {
171- error("sdl", SDL_GetError());
172- if(SDL_Init(SDL_INIT_VIDEO) < 0)
173- return error("sdl", SDL_GetError());
174- } else {
175- audio_id = SDL_OpenAudioDevice(NULL, 0, &as, NULL, 0);
176- if(!audio_id)
177- error("sdl_audio", SDL_GetError());
178- }
179- gWindow = SDL_CreateWindow("Uxn", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, (WIDTH + PAD * 2) * zoom, (HEIGHT + PAD * 2) * zoom, SDL_WINDOW_SHOWN);
180- if(gWindow == NULL)
181- return error("sdl_window", SDL_GetError());
182- gRenderer = SDL_CreateRenderer(gWindow, -1, 0);
183- if(gRenderer == NULL)
184- return error("sdl_renderer", SDL_GetError());
185- stdin_event = SDL_RegisterEvents(1);
186- audio0_event = SDL_RegisterEvents(POLYPHONY);
187- SDL_CreateThread(stdin_handler, "stdin", NULL);
188- SDL_StartTextInput();
189- SDL_ShowCursor(SDL_DISABLE);
190- SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
191- return 1;
192-}
193-
194-static void
195-domouse(SDL_Event *event)
196-{
197- Uint8 flag = 0x00;
198- Uint16 x = SDL_clamp(event->motion.x - PAD, 0, ppu.width - 1);
199- Uint16 y = SDL_clamp(event->motion.y - PAD, 0, ppu.height - 1);
200- if(event->type == SDL_MOUSEWHEEL) {
201- devmouse->dat[7] = event->wheel.y;
202- return;
203- }
204- poke16(devmouse->dat, 0x2, x);
205- poke16(devmouse->dat, 0x4, y);
206- devmouse->dat[7] = 0x00;
207- switch(event->button.button) {
208- case SDL_BUTTON_LEFT: flag = 0x01; break;
209- case SDL_BUTTON_RIGHT: flag = 0x10; break;
210- }
211- switch(event->type) {
212- case SDL_MOUSEBUTTONDOWN:
213- devmouse->dat[6] |= flag;
214- break;
215- case SDL_MOUSEBUTTONUP:
216- devmouse->dat[6] &= (~flag);
217- break;
218- }
219-}
220-
221-#pragma mark - Devices
222-
223-static Uint8
224-system_dei(Device *d, Uint8 port)
225-{
226- switch(port) {
227- case 0x2: return d->u->wst.ptr;
228- case 0x3: return d->u->rst.ptr;
229- default: return d->dat[port];
230- }
231-}
232-
233-static void
234-system_deo(Device *d, Uint8 port)
235-{
236- switch(port) {
237- case 0x2: d->u->wst.ptr = d->dat[port]; break;
238- case 0x3: d->u->rst.ptr = d->dat[port]; break;
239- }
240- if(port > 0x7 && port < 0xe)
241- ppu_palette(&ppu, &d->dat[0x8]);
242-}
243-
244-static void
245-console_deo(Device *d, Uint8 port)
246-{
247- if(port == 0x1)
248- d->vector = peek16(d->dat, 0x0);
249- if(port > 0x7)
250- write(port - 0x7, (char *)&d->dat[port], 1);
251-}
252-
253-static Uint8
254-screen_dei(Device *d, Uint8 port)
255-{
256- switch(port) {
257- case 0x2: return ppu.width >> 8;
258- case 0x3: return ppu.width;
259- case 0x4: return ppu.height >> 8;
260- case 0x5: return ppu.height;
261- default: return d->dat[port];
262- }
263-}
264-
265-static void
266-screen_deo(Device *d, Uint8 port)
267-{
268- switch(port) {
269- case 0x1: d->vector = peek16(d->dat, 0x0); break;
270- case 0x5:
271- if(!FIXED_SIZE) set_size(peek16(d->dat, 0x2), peek16(d->dat, 0x4), 1);
272- break;
273- case 0xe: {
274- Uint16 x = peek16(d->dat, 0x8);
275- Uint16 y = peek16(d->dat, 0xa);
276- Uint8 layer = d->dat[0xe] & 0x40;
277- ppu_write(&ppu, layer ? &ppu.fg : &ppu.bg, x, y, d->dat[0xe] & 0x3);
278- if(d->dat[0x6] & 0x01) poke16(d->dat, 0x8, x + 1); /* auto x+1 */
279- if(d->dat[0x6] & 0x02) poke16(d->dat, 0xa, y + 1); /* auto y+1 */
280- break;
281- }
282- case 0xf: {
283- Uint16 x = peek16(d->dat, 0x8);
284- Uint16 y = peek16(d->dat, 0xa);
285- Layer *layer = (d->dat[0xf] & 0x40) ? &ppu.fg : &ppu.bg;
286- Uint8 *addr = &d->mem[peek16(d->dat, 0xc)];
287- Uint8 twobpp = !!(d->dat[0xf] & 0x80);
288- ppu_blit(&ppu, layer, x, y, addr, d->dat[0xf] & 0xf, d->dat[0xf] & 0x10, d->dat[0xf] & 0x20, twobpp);
289- if(d->dat[0x6] & 0x04) poke16(d->dat, 0xc, peek16(d->dat, 0xc) + 8 + twobpp*8); /* auto addr+8 / auto addr+16 */
290- if(d->dat[0x6] & 0x01) poke16(d->dat, 0x8, x + 8); /* auto x+8 */
291- if(d->dat[0x6] & 0x02) poke16(d->dat, 0xa, y + 8); /* auto y+8 */
292- break;
293- }
294- }
295-}
296-
297-static void
298-file_deo(Device *d, Uint8 port)
299-{
300- switch(port) {
301- case 0x1: d->vector = peek16(d->dat, 0x0); break;
302- case 0x9: poke16(d->dat, 0x2, file_init(&d->mem[peek16(d->dat, 0x8)])); break;
303- case 0xd: poke16(d->dat, 0x2, file_read(&d->mem[peek16(d->dat, 0xc)], peek16(d->dat, 0xa))); break;
304- case 0xf: poke16(d->dat, 0x2, file_write(&d->mem[peek16(d->dat, 0xe)], peek16(d->dat, 0xa), d->dat[0x7])); break;
305- case 0x5: poke16(d->dat, 0x2, file_stat(&d->mem[peek16(d->dat, 0x4)], peek16(d->dat, 0xa))); break;
306- case 0x6: poke16(d->dat, 0x2, file_delete()); break;
307- }
308-}
309-
310-static Uint8
311-audio_dei(Device *d, Uint8 port)
312-{
313- Apu *c = &apu[d - devaudio0];
314- if(!audio_id) return d->dat[port];
315- switch(port) {
316- case 0x4: return apu_get_vu(c);
317- case 0x2: poke16(d->dat, 0x2, c->i); /* fall through */
318- default: return d->dat[port];
319- }
320-}
321-
322-static void
323-audio_deo(Device *d, Uint8 port)
324-{
325- Apu *c = &apu[d - devaudio0];
326- if(!audio_id) return;
327- if(port == 0xf) {
328- SDL_LockAudioDevice(audio_id);
329- c->len = peek16(d->dat, 0xa);
330- c->addr = &d->mem[peek16(d->dat, 0xc)];
331- c->volume[0] = d->dat[0xe] >> 4;
332- c->volume[1] = d->dat[0xe] & 0xf;
333- c->repeat = !(d->dat[0xf] & 0x80);
334- apu_start(c, peek16(d->dat, 0x8), d->dat[0xf] & 0x7f);
335- SDL_UnlockAudioDevice(audio_id);
336- SDL_PauseAudioDevice(audio_id, 0);
337- }
338-}
339-
340-static Uint8
341-datetime_dei(Device *d, Uint8 port)
342-{
343- time_t seconds = time(NULL);
344- struct tm zt = {0};
345- struct tm *t = localtime(&seconds);
346- if(t == NULL)
347- t = &zt;
348- switch(port) {
349- case 0x0: return (t->tm_year + 1900) >> 8;
350- case 0x1: return (t->tm_year + 1900);
351- case 0x2: return t->tm_mon;
352- case 0x3: return t->tm_mday;
353- case 0x4: return t->tm_hour;
354- case 0x5: return t->tm_min;
355- case 0x6: return t->tm_sec;
356- case 0x7: return t->tm_wday;
357- case 0x8: return t->tm_yday >> 8;
358- case 0x9: return t->tm_yday;
359- case 0xa: return t->tm_isdst;
360- default: return d->dat[port];
361- }
362-}
363-
364-static Uint8
365-nil_dei(Device *d, Uint8 port)
366-{
367- return d->dat[port];
368-}
369-
370-static void
371-nil_deo(Device *d, Uint8 port)
372-{
373- if(port == 0x1) d->vector = peek16(d->dat, 0x0);
374-}
375-
376-/* Boot */
377-
378-static int
379-load(Uxn *u, char *rom)
380-{
381- SDL_RWops *f;
382- int r;
383- if(!(f = SDL_RWFromFile(rom, "rb"))) return 0;
384- r = f->read(f, u->ram.dat + PAGE_PROGRAM, 1, sizeof(u->ram.dat) - PAGE_PROGRAM);
385- f->close(f);
386- if(r < 1) return 0;
387- fprintf(stderr, "Loaded %s\n", rom);
388- SDL_SetWindowTitle(gWindow, rom);
389- return 1;
390-}
391-
392-static int
393-start(Uxn *u, char *rom)
394-{
395- if(!uxn_boot(u))
396- return error("Boot", "Failed to start uxn.");
397- if(!load(u, rom))
398- return error("Boot", "Failed to load rom.");
399-
400- /* system */ devsystem = uxn_port(u, 0x0, system_dei, system_deo);
401- /* console */ devconsole = uxn_port(u, 0x1, nil_dei, console_deo);
402- /* screen */ devscreen = uxn_port(u, 0x2, screen_dei, screen_deo);
403- /* audio0 */ devaudio0 = uxn_port(u, 0x3, audio_dei, audio_deo);
404- /* audio1 */ uxn_port(u, 0x4, audio_dei, audio_deo);
405- /* audio2 */ uxn_port(u, 0x5, audio_dei, audio_deo);
406- /* audio3 */ uxn_port(u, 0x6, audio_dei, audio_deo);
407- /* unused */ uxn_port(u, 0x7, nil_dei, nil_deo);
408- /* control */ devctrl = uxn_port(u, 0x8, nil_dei, nil_deo);
409- /* mouse */ devmouse = uxn_port(u, 0x9, nil_dei, nil_deo);
410- /* file */ uxn_port(u, 0xa, nil_dei, file_deo);
411- /* datetime */ uxn_port(u, 0xb, datetime_dei, nil_deo);
412- /* unused */ uxn_port(u, 0xc, nil_dei, nil_deo);
413- /* unused */ uxn_port(u, 0xd, nil_dei, nil_deo);
414- /* unused */ uxn_port(u, 0xe, nil_dei, nil_deo);
415- /* unused */ uxn_port(u, 0xf, nil_dei, nil_deo);
416-
417- if(!uxn_eval(u, PAGE_PROGRAM))
418- return error("Boot", "Failed to start rom.");
419-
420- return 1;
421-}
422-
423-static void
424-restart(Uxn *u)
425-{
426- set_size(WIDTH, HEIGHT, 1);
427- start(u, "boot.rom");
428-}
429-
430-static void
431-doctrl(Uxn *u, SDL_Event *event, int z)
432-{
433- Uint8 flag = 0x00;
434- SDL_Keymod mods = SDL_GetModState();
435- devctrl->dat[2] &= 0xf8;
436- if(mods & KMOD_CTRL) devctrl->dat[2] |= 0x01;
437- if(mods & KMOD_ALT) devctrl->dat[2] |= 0x02;
438- if(mods & KMOD_SHIFT) devctrl->dat[2] |= 0x04;
439- /* clang-format off */
440- switch(event->key.keysym.sym) {
441- case SDLK_ESCAPE: flag = 0x08; break;
442- case SDLK_UP: flag = 0x10; break;
443- case SDLK_DOWN: flag = 0x20; break;
444- case SDLK_LEFT: flag = 0x40; break;
445- case SDLK_RIGHT: flag = 0x80; break;
446- case SDLK_F1: if(z) set_zoom(zoom > 2 ? 1 : zoom + 1); break;
447- case SDLK_F2: if(z) devsystem->dat[0xe] = !devsystem->dat[0xe]; ppu_clear(&ppu, &ppu.fg); break;
448- case SDLK_F3: if(z) capture_screen(); break;
449- case SDLK_AC_BACK:
450- case SDLK_F4: if(z) restart(u); break;
451- }
452- /* clang-format on */
453- if(z) {
454- devctrl->dat[2] |= flag;
455- if(event->key.keysym.sym < 0x20 || event->key.keysym.sym == SDLK_DELETE)
456- devctrl->dat[3] = event->key.keysym.sym;
457- else if((mods & KMOD_CTRL) && event->key.keysym.sym >= SDLK_a && event->key.keysym.sym <= SDLK_z)
458- devctrl->dat[3] = event->key.keysym.sym - (mods & KMOD_SHIFT) * 0x20;
459- } else
460- devctrl->dat[2] &= ~flag;
461-}
462-
463-static const char *errors[] = {"underflow", "overflow", "division by zero"};
464-
465-int
466-uxn_halt(Uxn *u, Uint8 error, char *name, int id)
467-{
468- fprintf(stderr, "Halted: %s %s#%04x, at 0x%04x\n", name, errors[error - 1], id, u->ram.ptr);
469- return 0;
470-}
471-
472-static int
473-console_input(Uxn *u, char c)
474-{
475- devconsole->dat[0x2] = c;
476- return uxn_eval(u, devconsole->vector);
477-}
478-
479-static int
480-run(Uxn *u)
481-{
482- redraw(u);
483- while(!devsystem->dat[0xf]) {
484- SDL_Event event;
485- double elapsed, begin = 0;
486- int ksym;
487- if(!BENCH)
488- begin = SDL_GetPerformanceCounter();
489- while(SDL_PollEvent(&event) != 0) {
490- switch(event.type) {
491- case SDL_DROPFILE:
492- set_size(WIDTH, HEIGHT, 0);
493- start(u, event.drop.file);
494- SDL_free(event.drop.file);
495- break;
496- case SDL_QUIT:
497- return error("Run", "Quit.");
498- case SDL_TEXTINPUT:
499- devctrl->dat[3] = event.text.text[0]; /* fall-thru */
500- case SDL_KEYDOWN:
501- case SDL_KEYUP:
502- doctrl(u, &event, event.type == SDL_KEYDOWN);
503- uxn_eval(u, devctrl->vector);
504- devctrl->dat[3] = 0;
505-
506- if(event.type == SDL_KEYDOWN) {
507- ksym = event.key.keysym.sym;
508- if(SDL_PeepEvents(&event, 1, SDL_PEEKEVENT, SDL_KEYUP, SDL_KEYUP) == 1 && ksym == event.key.keysym.sym)
509- goto breakout;
510- }
511- break;
512- case SDL_MOUSEWHEEL:
513- case SDL_MOUSEBUTTONUP:
514- case SDL_MOUSEBUTTONDOWN:
515- case SDL_MOUSEMOTION:
516- domouse(&event);
517- uxn_eval(u, devmouse->vector);
518- break;
519- case SDL_WINDOWEVENT:
520- if(event.window.event == SDL_WINDOWEVENT_EXPOSED)
521- redraw(u);
522- break;
523- default:
524- if(event.type == stdin_event) {
525- console_input(u, event.cbutton.button);
526- } else if(event.type >= audio0_event && event.type < audio0_event + POLYPHONY)
527- uxn_eval(u, peek16((devaudio0 + (event.type - audio0_event))->dat, 0));
528- }
529- }
530- breakout:
531- uxn_eval(u, devscreen->vector);
532- if(ppu.fg.changed || ppu.bg.changed || devsystem->dat[0xe])
533- redraw(u);
534- if(!BENCH) {
535- elapsed = (SDL_GetPerformanceCounter() - begin) / (double)SDL_GetPerformanceFrequency() * 1000.0f;
536- SDL_Delay(SDL_clamp(16.666f - elapsed, 0, 1000));
537- }
538- }
539- return error("Run", "Ended.");
540-}
541-
542-int
543-main(int argc, char **argv)
544-{
545- SDL_DisplayMode DM;
546- Uxn u;
547- int i, loaded = 0;
548-
549- if(!init())
550- return error("Init", "Failed to initialize emulator.");
551- if(!set_size(WIDTH, HEIGHT, 0))
552- return error("Window", "Failed to set window size.");
553-
554- /* set default zoom */
555- if(SDL_GetCurrentDisplayMode(0, &DM) == 0)
556- set_zoom(DM.w / 1280);
557- for(i = 1; i < argc; ++i) {
558- /* get default zoom from flags */
559- if(strcmp(argv[i], "-s") == 0) {
560- if(i < argc - 1)
561- set_zoom(atoi(argv[++i]));
562- else
563- return error("Opt", "-s No scale provided.");
564- } else if(!loaded++) {
565- if(!start(&u, argv[i]))
566- return error("Boot", "Failed to boot.");
567- } else {
568- char *p = argv[i];
569- while(*p) console_input(&u, *p++);
570- console_input(&u, '\n');
571- }
572- }
573- if(!loaded && !start(&u, "boot.rom"))
574- return error("usage", "uxnemu [-s scale] file.rom");
575- run(&u);
576- SDL_Quit();
577- return 0;
578-}