diff options
author | Bad Diode <bd@badd10de.dev> | 2021-05-18 16:40:24 +0200 |
---|---|---|
committer | Bad Diode <bd@badd10de.dev> | 2021-05-18 16:40:24 +0200 |
commit | 0c7265cf0de9d4ec95d28c5e103c00a63f4a1697 (patch) | |
tree | 4a1145e849e078395430a8d718c4bd69a06fb29f /src/uxn | |
download | uxngba-0c7265cf0de9d4ec95d28c5e103c00a63f4a1697.tar.gz uxngba-0c7265cf0de9d4ec95d28c5e103c00a63f4a1697.zip |
Proof of concept of UXN on the GBA
Diffstat (limited to 'src/uxn')
-rw-r--r-- | src/uxn/devices/ppu.c | 180 | ||||
-rw-r--r-- | src/uxn/devices/ppu.h | 36 | ||||
-rw-r--r-- | src/uxn/roms/console.c | 5 | ||||
-rw-r--r-- | src/uxn/roms/dvd.c | 22 | ||||
-rw-r--r-- | src/uxn/uxn.c | 196 | ||||
-rw-r--r-- | src/uxn/uxn.h | 55 |
6 files changed, 494 insertions, 0 deletions
diff --git a/src/uxn/devices/ppu.c b/src/uxn/devices/ppu.c new file mode 100644 index 0000000..b977f97 --- /dev/null +++ b/src/uxn/devices/ppu.c | |||
@@ -0,0 +1,180 @@ | |||
1 | #include "ppu.h" | ||
2 | |||
3 | /* | ||
4 | Copyright (c) 2021 Devine Lu Linvega | ||
5 | Copyright (c) 2021 Andrew Alderwick | ||
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 | static Uint8 font[][8] = { | ||
16 | {0x00, 0x7c, 0x82, 0x82, 0x82, 0x82, 0x82, 0x7c}, | ||
17 | {0x00, 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}, | ||
18 | {0x00, 0x7c, 0x82, 0x02, 0x7c, 0x80, 0x80, 0xfe}, | ||
19 | {0x00, 0x7c, 0x82, 0x02, 0x1c, 0x02, 0x82, 0x7c}, | ||
20 | {0x00, 0x0c, 0x14, 0x24, 0x44, 0x84, 0xfe, 0x04}, | ||
21 | {0x00, 0xfe, 0x80, 0x80, 0x7c, 0x02, 0x82, 0x7c}, | ||
22 | {0x00, 0x7c, 0x82, 0x80, 0xfc, 0x82, 0x82, 0x7c}, | ||
23 | {0x00, 0x7c, 0x82, 0x02, 0x1e, 0x02, 0x02, 0x02}, | ||
24 | {0x00, 0x7c, 0x82, 0x82, 0x7c, 0x82, 0x82, 0x7c}, | ||
25 | {0x00, 0x7c, 0x82, 0x82, 0x7e, 0x02, 0x82, 0x7c}, | ||
26 | {0x00, 0x7c, 0x82, 0x02, 0x7e, 0x82, 0x82, 0x7e}, | ||
27 | {0x00, 0xfc, 0x82, 0x82, 0xfc, 0x82, 0x82, 0xfc}, | ||
28 | {0x00, 0x7c, 0x82, 0x80, 0x80, 0x80, 0x82, 0x7c}, | ||
29 | {0x00, 0xfc, 0x82, 0x82, 0x82, 0x82, 0x82, 0xfc}, | ||
30 | {0x00, 0x7c, 0x82, 0x80, 0xf0, 0x80, 0x82, 0x7c}, | ||
31 | {0x00, 0x7c, 0x82, 0x80, 0xf0, 0x80, 0x80, 0x80}}; | ||
32 | |||
33 | Uint8 | ||
34 | readpixel(Uint8 *sprite, Uint8 h, Uint8 v) | ||
35 | { | ||
36 | Uint8 ch1 = ((sprite[v] >> h) & 0x1); | ||
37 | Uint8 ch2 = (((sprite[v + 8] >> h) & 0x1) << 1); | ||
38 | return ch1 + ch2; | ||
39 | } | ||
40 | |||
41 | void | ||
42 | clear(Ppu *p) | ||
43 | { | ||
44 | int i, sz = p->height * p->width, rows = sz / 4; | ||
45 | for(i = 0; i < sz; ++i) | ||
46 | p->output[i] = p->colors[0]; | ||
47 | for(i = 0; i < rows; i++) { | ||
48 | p->fg[i] = 0; | ||
49 | p->bg[i] = 0; | ||
50 | } | ||
51 | } | ||
52 | |||
53 | void | ||
54 | putcolors(Ppu *p, Uint8 *addr) | ||
55 | { | ||
56 | int i; | ||
57 | for(i = 0; i < 4; ++i) { | ||
58 | Uint8 | ||
59 | r = (*(addr + i / 2) >> (!(i % 2) << 2)) & 0x0f, | ||
60 | g = (*(addr + 2 + i / 2) >> (!(i % 2) << 2)) & 0x0f, | ||
61 | b = (*(addr + 4 + i / 2) >> (!(i % 2) << 2)) & 0x0f; | ||
62 | p->colors[i] = rgb15(r,g,b); | ||
63 | } | ||
64 | // p->colors[0] = COLOR_BLUE; | ||
65 | // p->colors[1] = COLOR_WHITE; | ||
66 | // p->colors[2] = COLOR_RED; | ||
67 | // p->colors[3] = COLOR_CYAN; | ||
68 | } | ||
69 | |||
70 | void | ||
71 | putpixel(Ppu *p, Uint8 *layer, Uint16 x, Uint16 y, Uint8 color) | ||
72 | { | ||
73 | Uint16 row = (y % 8) + ((x / 8 + y / 8 * p->hor) * 16), col = 7 - (x % 8); | ||
74 | if(x >= p->hor * 8 || y >= p->ver * 8 || row > (p->hor * p->ver * 16) - 8) | ||
75 | return; | ||
76 | if(color == 0 || color == 2) | ||
77 | layer[row] &= ~(1UL << col); | ||
78 | else | ||
79 | layer[row] |= 1UL << col; | ||
80 | if(color == 0 || color == 1) | ||
81 | layer[row + 8] &= ~(1UL << col); | ||
82 | else | ||
83 | layer[row + 8] |= 1UL << col; | ||
84 | } | ||
85 | |||
86 | void | ||
87 | puticn(Ppu *p, Uint8 *layer, Uint16 x, Uint16 y, Uint8 *sprite, Uint8 color, Uint8 flipx, Uint8 flipy) | ||
88 | { | ||
89 | Uint16 v, h; | ||
90 | for(v = 0; v < 8; v++) | ||
91 | for(h = 0; h < 8; h++) { | ||
92 | Uint8 ch1 = ((sprite[v] >> (7 - h)) & 0x1); | ||
93 | if(ch1 == 1 || (color != 0x05 && color != 0x0a && color != 0x0f)) | ||
94 | putpixel(p, | ||
95 | layer, | ||
96 | x + (flipx ? 7 - h : h), | ||
97 | y + (flipy ? 7 - v : v), | ||
98 | ch1 ? color % 4 : color / 4); | ||
99 | } | ||
100 | } | ||
101 | |||
102 | void | ||
103 | putchr(Ppu *p, Uint8 *layer, Uint16 x, Uint16 y, Uint8 *sprite, Uint8 color, Uint8 flipx, Uint8 flipy) | ||
104 | { | ||
105 | Uint16 v, h; | ||
106 | for(v = 0; v < 8; v++) | ||
107 | for(h = 0; h < 8; h++) { | ||
108 | Uint8 ch1 = ((sprite[v] >> (7 - h)) & 0x1) * color; | ||
109 | Uint8 ch2 = ((sprite[v + 8] >> (7 - h)) & 0x1) * color; | ||
110 | putpixel(p, | ||
111 | layer, | ||
112 | x + (flipx ? 7 - h : h), | ||
113 | y + (flipy ? 7 - v : v), | ||
114 | (((ch1 + ch2 * 2) + color / 4) & 0x3)); | ||
115 | } | ||
116 | } | ||
117 | |||
118 | /* output */ | ||
119 | |||
120 | void | ||
121 | drawpixel(Ppu *p, Uint16 x, Uint16 y, Uint8 color) | ||
122 | { | ||
123 | if(x >= p->pad && x <= p->width - p->pad - 1 && y >= p->pad && y <= p->height - p->pad - 1) | ||
124 | p->output[y * p->width + x] = p->colors[color]; | ||
125 | } | ||
126 | |||
127 | void | ||
128 | drawdebugger(Ppu *p, Uint8 *stack, Uint8 ptr) | ||
129 | { | ||
130 | Uint8 i, x, y, b; | ||
131 | for(i = 0; i < 0x20; ++i) { /* memory */ | ||
132 | x = ((i % 8) * 3 + 1) * 8, y = (i / 8 + 1) * 8, b = stack[i]; | ||
133 | puticn(p, p->bg, x, y, font[(b >> 4) & 0xf], 1 + (ptr == i) * 0x7, 0, 0); | ||
134 | puticn(p, p->bg, x + 8, y, font[b & 0xf], 1 + (ptr == i) * 0x7, 0, 0); | ||
135 | } | ||
136 | for(x = 0; x < 0x20; ++x) { | ||
137 | drawpixel(p, x, p->height / 2, 2); | ||
138 | drawpixel(p, p->width - x, p->height / 2, 2); | ||
139 | drawpixel(p, p->width / 2, p->height - x, 2); | ||
140 | drawpixel(p, p->width / 2, x, 2); | ||
141 | drawpixel(p, p->width / 2 - 16 + x, p->height / 2, 2); | ||
142 | drawpixel(p, p->width / 2, p->height / 2 - 16 + x, 2); | ||
143 | } | ||
144 | } | ||
145 | |||
146 | void | ||
147 | drawppu(Ppu *p) | ||
148 | { | ||
149 | Uint16 x, y; | ||
150 | for(y = 0; y < p->ver; ++y) | ||
151 | for(x = 0; x < p->hor; ++x) { | ||
152 | Uint8 v, h; | ||
153 | Uint16 key = (y * p->hor + x) * 16; | ||
154 | for(v = 0; v < 8; v++) | ||
155 | for(h = 0; h < 8; h++) { | ||
156 | Uint8 color = readpixel(&p->fg[key], h, v); | ||
157 | if(color == 0) | ||
158 | color = readpixel(&p->bg[key], h, v); | ||
159 | drawpixel(p, x * 8 + p->pad + 7 - h, y * 8 + p->pad + v, color); | ||
160 | } | ||
161 | } | ||
162 | } | ||
163 | |||
164 | int | ||
165 | initppu(Ppu *p, Uint8 hor, Uint8 ver, Uint8 pad) | ||
166 | { | ||
167 | p->hor = hor; | ||
168 | p->ver = ver; | ||
169 | p->pad = pad; | ||
170 | p->width = (8 * p->hor + p->pad * 2); | ||
171 | p->height = (8 * p->ver + p->pad * 2); | ||
172 | if(!(p->output = malloc(p->width * p->height * sizeof(Uint16)))) | ||
173 | return 0; | ||
174 | if(!(p->bg = malloc(p->width * p->height * sizeof(Uint8) / 4))) | ||
175 | return 0; | ||
176 | if(!(p->fg = malloc(p->width * p->height * sizeof(Uint8) / 4))) | ||
177 | return 0; | ||
178 | clear(p); | ||
179 | return 1; | ||
180 | } | ||
diff --git a/src/uxn/devices/ppu.h b/src/uxn/devices/ppu.h new file mode 100644 index 0000000..187d364 --- /dev/null +++ b/src/uxn/devices/ppu.h | |||
@@ -0,0 +1,36 @@ | |||
1 | #ifndef UXNGBA_PPU_H | ||
2 | #define UXNGBA_PPU_H | ||
3 | |||
4 | #include <stdio.h> | ||
5 | #include <stdlib.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 | typedef unsigned char Uint8; | ||
20 | typedef unsigned short Uint16; | ||
21 | typedef unsigned int Uint32; | ||
22 | |||
23 | typedef struct Ppu { | ||
24 | Uint8 *bg, *fg; | ||
25 | Uint16 hor, ver, pad, width, height; | ||
26 | Uint16 *output, colors[4]; | ||
27 | } Ppu; | ||
28 | |||
29 | int initppu(Ppu *p, Uint8 hor, Uint8 ver, Uint8 pad); | ||
30 | void putcolors(Ppu *p, Uint8 *addr); | ||
31 | void putpixel(Ppu *p, Uint8 *layer, Uint16 x, Uint16 y, Uint8 color); | ||
32 | void puticn(Ppu *p, Uint8 *layer, Uint16 x, Uint16 y, Uint8 *sprite, Uint8 color, Uint8 flipx, Uint8 flipy); | ||
33 | void putchr(Ppu *p, Uint8 *layer, Uint16 x, Uint16 y, Uint8 *sprite, Uint8 color, Uint8 flipx, Uint8 flipy); | ||
34 | void drawppu(Ppu *p); | ||
35 | void drawdebugger(Ppu *p, Uint8 *stack, Uint8 ptr); | ||
36 | #endif // UXNGBA_PPU_H | ||
diff --git a/src/uxn/roms/console.c b/src/uxn/roms/console.c new file mode 100644 index 0000000..13d669a --- /dev/null +++ b/src/uxn/roms/console.c | |||
@@ -0,0 +1,5 @@ | |||
1 | u16 uxn_rom[] = { | ||
2 | 0x0121, 0x9411, 0x1801, 0x2117, 0x0100, 0x9438, 0xf401, 0x230d, | ||
3 | 0x4800, 0x6c65, 0x6f6c, 0x5720, 0x726f, 0x646c, 0x6620, 0x6f72, | ||
4 | 0x206d, 0x5855, 0x214e, 0x000d | ||
5 | }; | ||
diff --git a/src/uxn/roms/dvd.c b/src/uxn/roms/dvd.c new file mode 100644 index 0000000..2cccc84 --- /dev/null +++ b/src/uxn/roms/dvd.c | |||
@@ -0,0 +1,22 @@ | |||
1 | u16 uxn_rom[] = { | ||
2 | 0x4c21, 0x01fd, 0x3708, 0x4c21, 0x01f3, 0x370a, 0xdc21, 0x01f2, | ||
3 | 0x370c, 0x0121, 0x0133, 0x3720, 0x2201, 0x2136, 0x0200, 0x013b, | ||
4 | 0x3100, 0x2401, 0x2136, 0x0200, 0x013b, 0x3102, 0x2101, 0x0121, | ||
5 | 0x2eb2, 0x0100, 0x2120, 0xb201, 0x012e, 0x3000, 0x2201, 0x2136, | ||
6 | 0x2000, 0x2839, 0x0001, 0x2130, 0x0000, 0x2128, 0x0000, 0x0128, | ||
7 | 0x0d09, 0x0401, 0x0110, 0x0800, 0x0401, 0x0111, 0x3002, 0x2401, | ||
8 | 0x2136, 0x1000, 0x2839, 0x0201, 0x2130, 0x0000, 0x2128, 0x0000, | ||
9 | 0x0128, 0x0d09, 0x0501, 0x0110, 0x0800, 0x0501, 0x0111, 0x3000, | ||
10 | 0x0021, 0x0101, 0x0100, 0x1004, 0x0001, 0x2108, 0xfeff, 0x383a, | ||
11 | 0x0138, 0x3100, 0x0201, 0x2130, 0x0100, 0x0001, 0x0501, 0x0110, | ||
12 | 0x0800, 0xff21, 0x3afe, 0x3838, 0x0201, 0x0131, 0x2121, 0xb201, | ||
13 | 0x002e, 0x210f, 0xfd01, 0x2c01, 0x0137, 0x3002, 0x0201, 0x2130, | ||
14 | 0x1000, 0x2638, 0x2a01, 0x0137, 0x3000, 0x0001, 0x2130, 0x2000, | ||
15 | 0x2638, 0x2801, 0xcf37, 0x2e01, 0x0117, 0x362c, 0x0021, 0x3808, | ||
16 | 0x2c01, 0x2537, 0x0021, 0x3808, 0xab25, 0xe401, 0x230d, 0x2523, | ||
17 | 0x0021, 0x3808, 0xab25, 0xca01, 0x230d, 0x4323, 0x006c, 0x3f1f, | ||
18 | 0x3838, 0x7838, 0x007f, 0xfefe, 0x777e, 0xe377, 0x00c3, 0x1f0f, | ||
19 | 0x7b3b, 0xe777, 0x00c7, 0xfefc, 0x878f, 0x0e07, 0x7ffc, 0x0000, | ||
20 | 0xff0f, 0x077f, 0x0300, 0x0001, 0xf0ff, 0xfff8, 0x8700, 0x0000, | ||
21 | 0x7fff, 0xff7f, 0xf000, 0x0000, 0xfce0, 0x80fc, 0x0a00, | ||
22 | }; | ||
diff --git a/src/uxn/uxn.c b/src/uxn/uxn.c new file mode 100644 index 0000000..796a980 --- /dev/null +++ b/src/uxn/uxn.c | |||
@@ -0,0 +1,196 @@ | |||
1 | #include <stdio.h> | ||
2 | #include "uxn.h" | ||
3 | |||
4 | /* | ||
5 | Copyright (u) 2021 Devine Lu Linvega | ||
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 | #pragma mark - Operations | ||
16 | |||
17 | /* clang-format off */ | ||
18 | void push8(Stack *s, Uint8 a) { if (s->ptr == 0xff) { s->error = 2; return; } s->dat[s->ptr++] = a; } | ||
19 | Uint8 pop8_keep(Stack *s) { if (s->kptr == 0) { s->error = 1; return 0; } return s->dat[--s->kptr]; } | ||
20 | Uint8 pop8_nokeep(Stack *s) { if (s->ptr == 0) { s->error = 1; return 0; } return s->dat[--s->ptr]; } | ||
21 | static Uint8 (*pop8)(Stack *s); | ||
22 | void mempoke8(Uint8 *m, Uint16 a, Uint8 b) { m[a] = b; } | ||
23 | Uint8 mempeek8(Uint8 *m, Uint16 a) { return m[a]; } | ||
24 | void devpoke8(Device *d, Uint8 a, Uint8 b) { d->dat[a & 0xf] = b; d->talk(d, a & 0x0f, 1); } | ||
25 | Uint8 devpeek8(Device *d, Uint8 a) { d->talk(d, a & 0x0f, 0); return d->dat[a & 0xf]; } | ||
26 | void push16(Stack *s, Uint16 a) { push8(s, a >> 8); push8(s, a); } | ||
27 | Uint16 pop16(Stack *s) { return pop8(s) + (pop8(s) << 8); } | ||
28 | void mempoke16(Uint8 *m, Uint16 a, Uint16 b) { mempoke8(m, a, b >> 8); mempoke8(m, a + 1, b); } | ||
29 | Uint16 mempeek16(Uint8 *m, Uint16 a) { return (mempeek8(m, a) << 8) + mempeek8(m, a + 1); } | ||
30 | void devpoke16(Device *d, Uint8 a, Uint16 b) { devpoke8(d, a, b >> 8); devpoke8(d, a + 1, b); } | ||
31 | Uint16 devpeek16(Device *d, Uint16 a) { return (devpeek8(d, a) << 8) + devpeek8(d, a + 1); } | ||
32 | /* Stack */ | ||
33 | void op_brk(Uxn *u) { u->ram.ptr = 0; } | ||
34 | void op_nop(Uxn *u) { (void)u; } | ||
35 | void op_lit(Uxn *u) { push8(u->src, mempeek8(u->ram.dat, u->ram.ptr++)); } | ||
36 | void op_pop(Uxn *u) { pop8(u->src); } | ||
37 | void op_dup(Uxn *u) { Uint8 a = pop8(u->src); push8(u->src, a); push8(u->src, a); } | ||
38 | void op_swp(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, a); push8(u->src, b); } | ||
39 | void op_ovr(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b); push8(u->src, a); push8(u->src, b); } | ||
40 | void op_rot(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src), c = pop8(u->src); push8(u->src, b); push8(u->src, a); push8(u->src, c); } | ||
41 | /* Logic */ | ||
42 | void op_equ(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b == a); } | ||
43 | void op_neq(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b != a); } | ||
44 | void op_gth(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b > a); } | ||
45 | void op_lth(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b < a); } | ||
46 | void op_jmp(Uxn *u) { Uint8 a = pop8(u->src); u->ram.ptr += (Sint8)a; } | ||
47 | void op_jnz(Uxn *u) { Uint8 a = pop8(u->src); if (pop8(u->src)) u->ram.ptr += (Sint8)a; } | ||
48 | void op_jsr(Uxn *u) { Uint8 a = pop8(u->src); push16(u->dst, u->ram.ptr); u->ram.ptr += (Sint8)a; } | ||
49 | void op_sth(Uxn *u) { Uint8 a = pop8(u->src); push8(u->dst, a); } | ||
50 | /* Memory */ | ||
51 | void op_pek(Uxn *u) { Uint8 a = pop8(u->src); push8(u->src, mempeek8(u->ram.dat, a)); } | ||
52 | void op_pok(Uxn *u) { Uint8 a = pop8(u->src); Uint8 b = pop8(u->src); mempoke8(u->ram.dat, a, b); } | ||
53 | void op_ldr(Uxn *u) { Uint8 a = pop8(u->src); push8(u->src, mempeek8(u->ram.dat, u->ram.ptr + (Sint8)a)); } | ||
54 | void op_str(Uxn *u) { Uint8 a = pop8(u->src); Uint8 b = pop8(u->src); mempoke8(u->ram.dat, u->ram.ptr + (Sint8)a, b); } | ||
55 | void op_lda(Uxn *u) { Uint16 a = pop16(u->src); push8(u->src, mempeek8(u->ram.dat, a)); } | ||
56 | void op_sta(Uxn *u) { Uint16 a = pop16(u->src); Uint8 b = pop8(u->src); mempoke8(u->ram.dat, a, b); } | ||
57 | void op_dei(Uxn *u) { Uint8 a = pop8(u->src); push8(u->src, devpeek8(&u->dev[a >> 4], a)); } | ||
58 | void op_deo(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); devpoke8(&u->dev[a >> 4], a, b); } | ||
59 | /* Arithmetic */ | ||
60 | void op_add(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b + a); } | ||
61 | void op_sub(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b - a); } | ||
62 | void op_mul(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b * a); } | ||
63 | void op_div(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b / a); } | ||
64 | void op_and(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b & a); } | ||
65 | void op_ora(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b | a); } | ||
66 | void op_eor(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b ^ a); } | ||
67 | void op_sft(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b >> (a & 0x07) << ((a & 0x70) >> 4)); } | ||
68 | /* Stack */ | ||
69 | void op_lit16(Uxn *u) { push16(u->src, mempeek16(u->ram.dat, u->ram.ptr++)); u->ram.ptr++; } | ||
70 | void op_pop16(Uxn *u) { pop16(u->src); } | ||
71 | void op_dup16(Uxn *u) { Uint16 a = pop16(u->src); push16(u->src, a); push16(u->src, a); } | ||
72 | void op_swp16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->src, a); push16(u->src, b); } | ||
73 | void op_ovr16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->src, b); push16(u->src, a); push16(u->src, b); } | ||
74 | void op_rot16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src), c = pop16(u->src); push16(u->src, b); push16(u->src, a); push16(u->src, c); } | ||
75 | /* Logic(16-bits) */ | ||
76 | void op_equ16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push8(u->src, b == a); } | ||
77 | void op_neq16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push8(u->src, b != a); } | ||
78 | void op_gth16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push8(u->src, b > a); } | ||
79 | void op_lth16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push8(u->src, b < a); } | ||
80 | void op_jmp16(Uxn *u) { u->ram.ptr = pop16(u->src); } | ||
81 | void op_jnz16(Uxn *u) { Uint16 a = pop16(u->src); if (pop8(u->src)) u->ram.ptr = a; } | ||
82 | void op_jsr16(Uxn *u) { push16(u->dst, u->ram.ptr); u->ram.ptr = pop16(u->src); } | ||
83 | void op_sth16(Uxn *u) { Uint16 a = pop16(u->src); push16(u->dst, a); } | ||
84 | /* Memory(16-bits) */ | ||
85 | void op_pek16(Uxn *u) { Uint8 a = pop8(u->src); push16(u->src, mempeek16(u->ram.dat, a)); } | ||
86 | void op_pok16(Uxn *u) { Uint8 a = pop8(u->src); Uint16 b = pop16(u->src); mempoke16(u->ram.dat, a, b); } | ||
87 | void op_ldr16(Uxn *u) { Uint8 a = pop8(u->src); push16(u->src, mempeek16(u->ram.dat, u->ram.ptr + (Sint8)a)); } | ||
88 | void op_str16(Uxn *u) { Uint8 a = pop8(u->src); Uint16 b = pop16(u->src); mempoke16(u->ram.dat, u->ram.ptr + (Sint8)a, b); } | ||
89 | void op_lda16(Uxn *u) { Uint16 a = pop16(u->src); push16(u->src, mempeek16(u->ram.dat, a)); } | ||
90 | void op_sta16(Uxn *u) { Uint16 a = pop16(u->src); Uint16 b = pop16(u->src); mempoke16(u->ram.dat, a, b); } | ||
91 | void op_dei16(Uxn *u) { Uint8 a = pop8(u->src); push16(u->src, devpeek16(&u->dev[a >> 4], a)); } | ||
92 | void op_deo16(Uxn *u) { Uint8 a = pop8(u->src); Uint16 b = pop16(u->src); devpoke16(&u->dev[a >> 4], a, b); } | ||
93 | /* Arithmetic(16-bits) */ | ||
94 | void op_add16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->src, b + a); } | ||
95 | void op_sub16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->src, b - a); } | ||
96 | void op_mul16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->src, b * a); } | ||
97 | void op_div16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->src, b / a); } | ||
98 | void op_and16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->src, b & a); } | ||
99 | void op_ora16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->src, b | a); } | ||
100 | void op_eor16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->src, b ^ a); } | ||
101 | void op_sft16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->src, b >> (a & 0x000f) << ((a & 0x00f0) >> 4)); } | ||
102 | |||
103 | void (*ops[])(Uxn *u) = { | ||
104 | op_brk, op_lit, op_nop, op_pop, op_dup, op_swp, op_ovr, op_rot, | ||
105 | op_equ, op_neq, op_gth, op_lth, op_jmp, op_jnz, op_jsr, op_sth, | ||
106 | op_pek, op_pok, op_ldr, op_str, op_lda, op_sta, op_dei, op_deo, | ||
107 | op_add, op_sub, op_mul, op_div, op_and, op_ora, op_eor, op_sft, | ||
108 | /* 16-bit */ | ||
109 | op_brk, op_lit16, op_nop, op_pop16, op_dup16, op_swp16, op_ovr16, op_rot16, | ||
110 | op_equ16, op_neq16, op_gth16, op_lth16, op_jmp16, op_jnz16, op_jsr16, op_sth16, | ||
111 | op_pek16, op_pok16, op_ldr16, op_str16, op_lda16, op_sta16, op_dei16, op_deo16, | ||
112 | op_add16, op_sub16, op_mul16, op_div16, op_and16, op_ora16, op_eor16, op_sft16 | ||
113 | }; | ||
114 | |||
115 | /* clang-format on */ | ||
116 | |||
117 | #pragma mark - Core | ||
118 | |||
119 | int | ||
120 | haltuxn(Uxn *u, char *name, int id) | ||
121 | { | ||
122 | txt_printf("Halted: %s#%04x, at 0x%04x\n", name, id, u->ram.ptr); | ||
123 | u->ram.ptr = 0; | ||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | void | ||
128 | opcuxn(Uxn *u, Uint8 instr) | ||
129 | { | ||
130 | Uint8 op = instr & 0x3f, freturn = instr & 0x40, fkeep = instr & 0x80; | ||
131 | u->src = freturn ? &u->rst : &u->wst; | ||
132 | u->dst = freturn ? &u->wst : &u->rst; | ||
133 | if(fkeep) { | ||
134 | pop8 = pop8_keep; | ||
135 | u->src->kptr = u->src->ptr; | ||
136 | } else { | ||
137 | pop8 = pop8_nokeep; | ||
138 | } | ||
139 | (*ops[op])(u); | ||
140 | } | ||
141 | |||
142 | int | ||
143 | stepuxn(Uxn *u, Uint8 instr) | ||
144 | { | ||
145 | opcuxn(u, instr); | ||
146 | if(u->wst.error) | ||
147 | return haltuxn(u, u->wst.error == 1 ? "Working-stack underflow" : "Working-stack overflow", instr); | ||
148 | if(u->rst.error) | ||
149 | return haltuxn(u, u->rst.error == 1 ? "Return-stack underflow" : "Return-stack overflow", instr); | ||
150 | return 1; | ||
151 | } | ||
152 | |||
153 | int | ||
154 | evaluxn(Uxn *u, Uint16 vec) | ||
155 | { | ||
156 | u->ram.ptr = vec; | ||
157 | u->wst.error = 0; | ||
158 | u->rst.error = 0; | ||
159 | while(u->ram.ptr) | ||
160 | if(!stepuxn(u, u->ram.dat[u->ram.ptr++])) | ||
161 | return 0; | ||
162 | return 1; | ||
163 | } | ||
164 | |||
165 | int | ||
166 | bootuxn(Uxn *u) | ||
167 | { | ||
168 | size_t i; | ||
169 | char *cptr = (char *)u; | ||
170 | for(i = 0; i < sizeof(*u); i++) | ||
171 | cptr[i] = 0; | ||
172 | return 1; | ||
173 | } | ||
174 | |||
175 | int | ||
176 | loaduxn(Uxn *u, char *filepath) | ||
177 | { | ||
178 | FILE *f; | ||
179 | if(!(f = fopen(filepath, "rb"))) | ||
180 | return haltuxn(u, "Missing input rom.", 0); | ||
181 | fread(u->ram.dat + PAGE_PROGRAM, sizeof(u->ram.dat) - PAGE_PROGRAM, 1, f); | ||
182 | txt_printf("Uxn loaded[%s].\n", filepath); | ||
183 | return 1; | ||
184 | } | ||
185 | |||
186 | Device * | ||
187 | portuxn(Uxn *u, Uint8 id, char *name, void (*talkfn)(Device *d, Uint8 b0, Uint8 w)) | ||
188 | { | ||
189 | Device *d = &u->dev[id]; | ||
190 | d->addr = id * 0x10; | ||
191 | d->u = u; | ||
192 | d->mem = u->ram.dat; | ||
193 | d->talk = talkfn; | ||
194 | txt_printf("Device added #%02x: %s, at 0x%04x \n", id, name, d->addr); | ||
195 | return d; | ||
196 | } | ||
diff --git a/src/uxn/uxn.h b/src/uxn/uxn.h new file mode 100644 index 0000000..b2c90ac --- /dev/null +++ b/src/uxn/uxn.h | |||
@@ -0,0 +1,55 @@ | |||
1 | #ifndef UXNGBA_UXN_H | ||
2 | #define UXNGBA_UXN_H | ||
3 | |||
4 | #include <stdio.h> | ||
5 | |||
6 | /* | ||
7 | Copyright (c) 2021 Devine Lu Linvega | ||
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 | typedef unsigned char Uint8; | ||
18 | typedef signed char Sint8; | ||
19 | typedef unsigned short Uint16; | ||
20 | typedef signed short Sint16; | ||
21 | |||
22 | #define PAGE_PROGRAM 0x0100 | ||
23 | |||
24 | typedef struct { | ||
25 | Uint8 ptr, kptr, error; | ||
26 | Uint8 dat[256]; | ||
27 | } Stack; | ||
28 | |||
29 | typedef struct { | ||
30 | Uint16 ptr; | ||
31 | Uint8 dat[KB(16)]; | ||
32 | } Memory; | ||
33 | |||
34 | typedef struct Device { | ||
35 | struct Uxn *u; | ||
36 | Uint8 addr, dat[16], *mem; | ||
37 | void (*talk)(struct Device *d, Uint8, Uint8); | ||
38 | } Device; | ||
39 | |||
40 | typedef struct Uxn { | ||
41 | Stack wst, rst, *src, *dst; | ||
42 | Memory ram; | ||
43 | Device dev[16]; | ||
44 | } Uxn; | ||
45 | |||
46 | struct Uxn; | ||
47 | |||
48 | void mempoke16(Uint8 *m, Uint16 a, Uint16 b); | ||
49 | Uint16 mempeek16(Uint8 *m, Uint16 a); | ||
50 | |||
51 | int loaduxn(Uxn *c, char *filepath); | ||
52 | int bootuxn(Uxn *c); | ||
53 | int evaluxn(Uxn *u, Uint16 vec); | ||
54 | Device *portuxn(Uxn *u, Uint8 id, char *name, void (*talkfn)(Device *, Uint8, Uint8)); | ||
55 | #endif // UXNGBA_UXN_H | ||