aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2021-05-20 22:18:28 +0200
committerBad Diode <bd@badd10de.dev>2021-05-20 22:18:28 +0200
commitab6fdd0347920cdcda9c4c3c9c3f01996adc48db (patch)
tree02f714fdf9a10be96e1eb82b5ebc5834d04c9259
parent1d6395f1b6aafce4e2e05bcf60f335bec0a8d4b3 (diff)
downloaduxngba-ab6fdd0347920cdcda9c4c3c9c3f01996adc48db.tar.gz
uxngba-ab6fdd0347920cdcda9c4c3c9c3f01996adc48db.zip
Apply asie's first performance patch
-rw-r--r--src/bd-font.c2
-rw-r--r--src/common.h10
-rw-r--r--src/main.c15
-rw-r--r--src/small-font.c2
-rw-r--r--src/text.h5
-rw-r--r--src/uxn/devices/ppu.c13
-rw-r--r--src/uxn/uxn.c234
-rw-r--r--src/uxn/uxn.h8
-rw-r--r--src/uxn/uxn/opcodes.c373
9 files changed, 539 insertions, 123 deletions
diff --git a/src/bd-font.c b/src/bd-font.c
index 6913f78..0374496 100644
--- a/src/bd-font.c
+++ b/src/bd-font.c
@@ -9,7 +9,7 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9WITH REGARD TO THIS SOFTWARE. 9WITH REGARD TO THIS SOFTWARE.
10*/ 10*/
11 11
12u32 bd_font[] = { 12static const u32 bd_font[] = {
13 0x00000000, 0x00000000, 0x00002400, 0x423c0000, 13 0x00000000, 0x00000000, 0x00002400, 0x423c0000,
14 0x00002400, 0x3c420000, 0x0000363e, 0x3e1c0800, 14 0x00002400, 0x3c420000, 0x0000363e, 0x3e1c0800,
15 0x00081c3e, 0x3e1c0800, 0x001c1c3e, 0x363e081c, 15 0x00081c3e, 0x3e1c0800, 0x001c1c3e, 0x363e081c,
diff --git a/src/common.h b/src/common.h
index 2859b11..e293770 100644
--- a/src/common.h
+++ b/src/common.h
@@ -666,7 +666,7 @@ typedef enum {
666 NOTE_C_8 666 NOTE_C_8
667} Note; 667} Note;
668 668
669const char * note_names[] = { 669static const char * note_names[] = {
670 "C2", "C#2", "D2", "D#2", "E2", "F2", "F#2", "G2", "G#2", "A2", "A#2", "B2", 670 "C2", "C#2", "D2", "D#2", "E2", "F2", "F#2", "G2", "G#2", "A2", "A#2", "B2",
671 "C3", "C#3", "D3", "D#3", "E3", "F3", "F#3", "G3", "G#3", "A3", "A#3", "B3", 671 "C3", "C#3", "D3", "D#3", "E3", "F3", "F#3", "G3", "G#3", "A3", "A#3", "B3",
672 "C4", "C#4", "D4", "D#4", "E4", "F4", "F#4", "G4", "G#4", "A4", "A#4", "B4", 672 "C4", "C#4", "D4", "D#4", "E4", "F4", "F#4", "G4", "G#4", "A4", "A#4", "B4",
@@ -676,7 +676,7 @@ const char * note_names[] = {
676 "C8" 676 "C8"
677}; 677};
678 678
679const u32 sound_rates[] = { 679static const u32 sound_rates[] = {
680 44 , 156 , 262 , 363 , 457 , 547 , 631 , 710 , 785 , 856 , 923 , 986 , 680 44 , 156 , 262 , 363 , 457 , 547 , 631 , 710 , 785 , 856 , 923 , 986 ,
681 1046, 1102, 1155, 1205, 1252, 1297, 1339, 1379, 1416, 1452, 1485, 1517, 681 1046, 1102, 1155, 1205, 1252, 1297, 1339, 1379, 1416, 1452, 1485, 1517,
682 1547, 1575, 1601, 1626, 1650, 1672, 1693, 1713, 1732, 1750, 1766, 1782, 682 1547, 1575, 1601, 1626, 1650, 1672, 1693, 1713, 1732, 1750, 1766, 1782,
@@ -704,4 +704,10 @@ wait_vsync(void) {
704#define MAX(A, B) ((A) >= (B) ? (A) : (B)) 704#define MAX(A, B) ((A) >= (B) ? (A) : (B))
705#define CLAMP(X, MIN, MAX) ((X) <= (MIN) ? (MIN) : (X) > (MAX) ? (MAX): (X)) 705#define CLAMP(X, MIN, MAX) ((X) <= (MIN) ? (MIN) : (X) > (MAX) ? (MAX): (X))
706 706
707// IWRAM allocation macros for devkitARM.
708#define IWRAM_CODE __attribute__((section(".iwram"), long_call, target("arm")))
709#define IWRAM_DATA __attribute__((section(".iwram")))
710#define EWRAM_DATA __attribute__((section(".ewram")))
711#define EWRAM_BSS __attribute__((section(".sbss")))
712
707#endif // GBAEXP_COMMON_H 713#endif // GBAEXP_COMMON_H
diff --git a/src/main.c b/src/main.c
index 5edf71c..bdff100 100644
--- a/src/main.c
+++ b/src/main.c
@@ -61,6 +61,7 @@ system_talk(Device *d, Uint8 b0, Uint8 w) {
61 (void)b0; 61 (void)b0;
62} 62}
63 63
64IWRAM_CODE
64void 65void
65screen_talk(Device *d, Uint8 b0, Uint8 w) { 66screen_talk(Device *d, Uint8 b0, Uint8 w) {
66 if(w && b0 == 0xe) { 67 if(w && b0 == 0xe) {
@@ -181,6 +182,10 @@ handle_input(Uxn *u) {
181 devctrl->dat[3] = 0; 182 devctrl->dat[3] = 0;
182} 183}
183 184
185static Uxn u;
186EWRAM_BSS
187static Uint8 umem[65536];
188
184int main(void) { 189int main(void) {
185 // Register interrupts. 190 // Register interrupts.
186 irq_init(); 191 irq_init();
@@ -188,7 +193,8 @@ int main(void) {
188 193
189 194
190 // Initialize VM. 195 // Initialize VM.
191 Uxn u = {0}; 196 memset(&u, 0, sizeof(u));
197 u.ram.dat = umem;
192 init_uxn(&u); 198 init_uxn(&u);
193 199
194 // Initialize text engine. 200 // Initialize text engine.
@@ -208,10 +214,13 @@ int main(void) {
208 while(true) { 214 while(true) {
209 bios_vblank_wait(); 215 bios_vblank_wait();
210 handle_input(&u); 216 handle_input(&u);
217 profile_start();
211 evaluxn(&u, mempeek16(devscreen->dat, 0)); 218 evaluxn(&u, mempeek16(devscreen->dat, 0));
219 int eval_cycles = profile_stop();
212 flipbuf(&ppu); 220 flipbuf(&ppu);
213 // txt_position(0,0); 221 txt_position(0,0);
214 // txt_printf("FRAME: %d\n", frame_counter); 222 txt_printf("FRAME: %d\n", frame_counter);
223 txt_printf("EVAL: %d\n", eval_cycles);
215 time_seconds++; 224 time_seconds++;
216 frame_counter++; 225 frame_counter++;
217 } 226 }
diff --git a/src/small-font.c b/src/small-font.c
index e5adb35..6405f88 100644
--- a/src/small-font.c
+++ b/src/small-font.c
@@ -9,7 +9,7 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9WITH REGARD TO THIS SOFTWARE. 9WITH REGARD TO THIS SOFTWARE.
10*/ 10*/
11 11
12u32 small_font[] = { 12static const u32 small_font[] = {
13 0x00000000, 0x00000000, 0x00020202, 0x00020000, 13 0x00000000, 0x00000000, 0x00020202, 0x00020000,
14 0x000a0a00, 0x00000000, 0x000a1f0a, 0x1f0a0000, 14 0x000a0a00, 0x00000000, 0x000a1f0a, 0x1f0a0000,
15 0x02070107, 0x04070200, 0x00010402, 0x01040000, 15 0x02070107, 0x04070200, 0x00010402, 0x01040000,
diff --git a/src/text.h b/src/text.h
index 0b318bb..eb6149d 100644
--- a/src/text.h
+++ b/src/text.h
@@ -255,7 +255,10 @@ txt_printf(char *msg, ...) {
255 va_list arg_list; 255 va_list arg_list;
256 va_start(arg_list, msg); 256 va_start(arg_list, msg);
257 char buf[512] = {0}; 257 char buf[512] = {0};
258 vsprintf(buf, msg, arg_list); 258 // TODO: This call pulls in malloc() and a bunch of other things.
259 // To reduce memory usage and filesize, it would be advisable
260 // to replace it with something simpler.
261 vsiprintf(buf, msg, arg_list);
259 txt_puts(buf); 262 txt_puts(buf);
260} 263}
261 264
diff --git a/src/uxn/devices/ppu.c b/src/uxn/devices/ppu.c
index e9a94a6..60ede0a 100644
--- a/src/uxn/devices/ppu.c
+++ b/src/uxn/devices/ppu.c
@@ -142,8 +142,10 @@ static Uint32 unpack_icon_lut_flipx[256] = {
142 0x11111111 142 0x11111111
143}; 143};
144 144
145u32 *backbuffer_bg0; 145EWRAM_BSS
146u32 *backbuffer_bg1; 146static u32 *backbuffer_bg0[30 * 20 * sizeof(Tile) / 4];
147EWRAM_BSS
148static u32 *backbuffer_bg1[30 * 20 * sizeof(Tile) / 4];
147static u32 dirty_tiles[20] = {0}; 149static u32 dirty_tiles[20] = {0};
148 150
149void 151void
@@ -161,6 +163,7 @@ putcolors(Ppu *p, Uint8 *addr) {
161 } 163 }
162} 164}
163 165
166IWRAM_CODE
164void 167void
165putpixel(Ppu *p, Uint32 *layer, Uint16 x, Uint16 y, Uint8 color) { 168putpixel(Ppu *p, Uint32 *layer, Uint16 x, Uint16 y, Uint8 color) {
166 if(x >= 30 * 8 || y >= 20 * 8) { 169 if(x >= 30 * 8 || y >= 20 * 8) {
@@ -176,6 +179,7 @@ putpixel(Ppu *p, Uint32 *layer, Uint16 x, Uint16 y, Uint8 color) {
176 dirty_tiles[tile_y] |= 1 << tile_x; 179 dirty_tiles[tile_y] |= 1 << tile_x;
177} 180}
178 181
182IWRAM_CODE
179void 183void
180puticn(Ppu *p, Uint32 *layer, Uint16 x, Uint16 y, Uint8 *sprite, Uint8 color, 184puticn(Ppu *p, Uint32 *layer, Uint16 x, Uint16 y, Uint8 *sprite, Uint8 color,
181 Uint8 flipx, Uint8 flipy) { 185 Uint8 flipx, Uint8 flipy) {
@@ -230,6 +234,7 @@ puticn(Ppu *p, Uint32 *layer, Uint16 x, Uint16 y, Uint8 *sprite, Uint8 color,
230 } 234 }
231} 235}
232 236
237IWRAM_CODE
233void 238void
234putchr(Ppu *p, Uint32 *layer, Uint16 x, Uint16 y, Uint8 *sprite, Uint8 color, 239putchr(Ppu *p, Uint32 *layer, Uint16 x, Uint16 y, Uint8 *sprite, Uint8 color,
235 Uint8 flipx, Uint8 flipy) { 240 Uint8 flipx, Uint8 flipy) {
@@ -249,6 +254,7 @@ putchr(Ppu *p, Uint32 *layer, Uint16 x, Uint16 y, Uint8 *sprite, Uint8 color,
249 } 254 }
250} 255}
251 256
257IWRAM_CODE
252void 258void
253flipbuf(Ppu *p) { 259flipbuf(Ppu *p) {
254 Tile *mem_fg = &TILE_MEM[0]; 260 Tile *mem_fg = &TILE_MEM[0];
@@ -289,9 +295,6 @@ initppu(Ppu *p, Uint8 hor, Uint8 ver, Uint8 pad) {
289 BG_CTRL(0) = BG_CHARBLOCK(cb_fg) | BG_SCREENBLOCK(sb_idx) | BG_PRIORITY(1); 295 BG_CTRL(0) = BG_CHARBLOCK(cb_fg) | BG_SCREENBLOCK(sb_idx) | BG_PRIORITY(1);
290 BG_CTRL(1) = BG_CHARBLOCK(cb_bg) | BG_SCREENBLOCK(sb_idx) | BG_PRIORITY(2); 296 BG_CTRL(1) = BG_CHARBLOCK(cb_bg) | BG_SCREENBLOCK(sb_idx) | BG_PRIORITY(2);
291 297
292 backbuffer_bg0 = malloc(30 * 20 * sizeof(Tile));
293 backbuffer_bg1 = malloc(30 * 20 * sizeof(Tile));
294
295 // Clear tile memory. 298 // Clear tile memory.
296 p->fg = backbuffer_bg0; 299 p->fg = backbuffer_bg0;
297 p->bg = backbuffer_bg1; 300 p->bg = backbuffer_bg1;
diff --git a/src/uxn/uxn.c b/src/uxn/uxn.c
index 54d56d0..c1c564a 100644
--- a/src/uxn/uxn.c
+++ b/src/uxn/uxn.c
@@ -3,6 +3,7 @@
3 3
4/* 4/*
5Copyright (u) 2021 Devine Lu Linvega 5Copyright (u) 2021 Devine Lu Linvega
6Copyright (u) 2021 Adrian Siekierka
6 7
7Permission to use, copy, modify, and distribute this software for any 8Permission to use, copy, modify, and distribute this software for any
8purpose with or without fee is hereby granted, provided that the above 9purpose with or without fee is hereby granted, provided that the above
@@ -12,125 +13,144 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12WITH REGARD TO THIS SOFTWARE. 13WITH REGARD TO THIS SOFTWARE.
13*/ 14*/
14 15
15#pragma mark - Operations
16
17/* clang-format off */ 16/* clang-format off */
18void push8(Stack *s, Uint8 a) { if (s->ptr == 0xff) { s->error = 2; return; } s->dat[s->ptr++] = a; } 17
19Uint8 pop8_keep(Stack *s) { if (s->kptr == 0) { s->error = 1; return 0; } return s->dat[--s->kptr]; } 18static inline void push8(Stack *s, Uint8 a) {
20Uint8 pop8_nokeep(Stack *s) { if (s->ptr == 0) { s->error = 1; return 0; } return s->dat[--s->ptr]; } 19#ifdef CPU_ERROR_CHECKING
21static Uint8 (*pop8)(Stack *s); 20 if (s->ptr == 0xff) { s->error = 2; return; }
22void mempoke8(Uint8 *m, Uint16 a, Uint8 b) { m[a] = b; } 21#endif
23Uint8 mempeek8(Uint8 *m, Uint16 a) { return m[a]; } 22 s->dat[s->ptr++] = a;
24void devpoke8(Device *d, Uint8 a, Uint8 b) { d->dat[a & 0xf] = b; d->talk(d, a & 0x0f, 1); } 23}
25Uint8 devpeek8(Device *d, Uint8 a) { d->talk(d, a & 0x0f, 0); return d->dat[a & 0xf]; } 24static inline Uint8 pop8_keep(Stack *s) {
26void push16(Stack *s, Uint16 a) { push8(s, a >> 8); push8(s, a); } 25#ifdef CPU_ERROR_CHECKING
27Uint16 pop16(Stack *s) { return pop8(s) + (pop8(s) << 8); } 26 if (s->kptr == 0) { s->error = 1; return 0; }
28void mempoke16(Uint8 *m, Uint16 a, Uint16 b) { mempoke8(m, a, b >> 8); mempoke8(m, a + 1, b); } 27#endif
29Uint16 mempeek16(Uint8 *m, Uint16 a) { return (mempeek8(m, a) << 8) + mempeek8(m, a + 1); } 28 return s->dat[--s->kptr];
30void devpoke16(Device *d, Uint8 a, Uint16 b) { devpoke8(d, a, b >> 8); devpoke8(d, a + 1, b); } 29}
31Uint16 devpeek16(Device *d, Uint16 a) { return (devpeek8(d, a) << 8) + devpeek8(d, a + 1); } 30static inline Uint8 pop8_nokeep(Stack *s) {
32/* Stack */ 31#ifdef CPU_ERROR_CHECKING
33void op_brk(Uxn *u) { u->ram.ptr = 0; } 32 if (s->ptr == 0) { s->error = 1; return 0; }
34void op_nop(Uxn *u) { (void)u; } 33#endif
35void op_lit(Uxn *u) { push8(u->src, mempeek8(u->ram.dat, u->ram.ptr++)); } 34 return s->dat[--s->ptr];
36void op_pop(Uxn *u) { pop8(u->src); } 35}
37void op_dup(Uxn *u) { Uint8 a = pop8(u->src); push8(u->src, a); push8(u->src, a); } 36static inline void devpoke8(Device *d, Uint8 a, Uint8 b) { d->dat[a & 0xf] = b; d->talk(d, a & 0x0f, 1); }
38void op_swp(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, a); push8(u->src, b); } 37static inline Uint8 devpeek8(Device *d, Uint8 a) { d->talk(d, a & 0x0f, 0); return d->dat[a & 0xf]; }
39void 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); } 38static inline void push16(Stack *s, Uint16 a) { push8(s, a >> 8); push8(s, a); }
40void 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); } 39static inline void devpoke16(Device *d, Uint8 a, Uint16 b) { devpoke8(d, a, b >> 8); devpoke8(d, a + 1, b); }
41/* Logic */ 40static inline Uint16 devpeek16(Device *d, Uint16 a) { return (devpeek8(d, a) << 8) + devpeek8(d, a + 1); }
42void op_equ(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b == a); }
43void op_neq(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b != a); }
44void op_gth(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b > a); }
45void op_lth(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b < a); }
46void op_jmp(Uxn *u) { Uint8 a = pop8(u->src); u->ram.ptr += (Sint8)a; }
47void op_jnz(Uxn *u) { Uint8 a = pop8(u->src); if (pop8(u->src)) u->ram.ptr += (Sint8)a; }
48void op_jsr(Uxn *u) { Uint8 a = pop8(u->src); push16(u->dst, u->ram.ptr); u->ram.ptr += (Sint8)a; }
49void op_sth(Uxn *u) { Uint8 a = pop8(u->src); push8(u->dst, a); }
50/* Memory */
51void op_pek(Uxn *u) { Uint8 a = pop8(u->src); push8(u->src, mempeek8(u->ram.dat, a)); }
52void op_pok(Uxn *u) { Uint8 a = pop8(u->src); Uint8 b = pop8(u->src); mempoke8(u->ram.dat, a, b); }
53void op_ldr(Uxn *u) { Uint8 a = pop8(u->src); push8(u->src, mempeek8(u->ram.dat, u->ram.ptr + (Sint8)a)); }
54void op_str(Uxn *u) { Uint8 a = pop8(u->src); Uint8 b = pop8(u->src); mempoke8(u->ram.dat, u->ram.ptr + (Sint8)a, b); }
55void op_lda(Uxn *u) { Uint16 a = pop16(u->src); push8(u->src, mempeek8(u->ram.dat, a)); }
56void op_sta(Uxn *u) { Uint16 a = pop16(u->src); Uint8 b = pop8(u->src); mempoke8(u->ram.dat, a, b); }
57void op_dei(Uxn *u) { Uint8 a = pop8(u->src); push8(u->src, devpeek8(&u->dev[a >> 4], a)); }
58void op_deo(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); devpoke8(&u->dev[a >> 4], a, b); }
59/* Arithmetic */
60void op_add(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b + a); }
61void op_sub(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b - a); }
62void op_mul(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b * a); }
63void op_div(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b / a); }
64void op_and(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b & a); }
65void op_ora(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b | a); }
66void op_eor(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b ^ a); }
67void op_sft(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b >> (a & 0x07) << ((a & 0x70) >> 4)); }
68/* Stack */
69void op_lit16(Uxn *u) { push16(u->src, mempeek16(u->ram.dat, u->ram.ptr++)); u->ram.ptr++; }
70void op_pop16(Uxn *u) { pop16(u->src); }
71void op_dup16(Uxn *u) { Uint16 a = pop16(u->src); push16(u->src, a); push16(u->src, a); }
72void op_swp16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->src, a); push16(u->src, b); }
73void 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); }
74void 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) */
76void op_equ16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push8(u->src, b == a); }
77void op_neq16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push8(u->src, b != a); }
78void op_gth16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push8(u->src, b > a); }
79void op_lth16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push8(u->src, b < a); }
80void op_jmp16(Uxn *u) { u->ram.ptr = pop16(u->src); }
81void op_jnz16(Uxn *u) { Uint16 a = pop16(u->src); if (pop8(u->src)) u->ram.ptr = a; }
82void op_jsr16(Uxn *u) { push16(u->dst, u->ram.ptr); u->ram.ptr = pop16(u->src); }
83void op_sth16(Uxn *u) { Uint16 a = pop16(u->src); push16(u->dst, a); }
84/* Memory(16-bits) */
85void op_pek16(Uxn *u) { Uint8 a = pop8(u->src); push16(u->src, mempeek16(u->ram.dat, a)); }
86void op_pok16(Uxn *u) { Uint8 a = pop8(u->src); Uint16 b = pop16(u->src); mempoke16(u->ram.dat, a, b); }
87void op_ldr16(Uxn *u) { Uint8 a = pop8(u->src); push16(u->src, mempeek16(u->ram.dat, u->ram.ptr + (Sint8)a)); }
88void op_str16(Uxn *u) { Uint8 a = pop8(u->src); Uint16 b = pop16(u->src); mempoke16(u->ram.dat, u->ram.ptr + (Sint8)a, b); }
89void op_lda16(Uxn *u) { Uint16 a = pop16(u->src); push16(u->src, mempeek16(u->ram.dat, a)); }
90void op_sta16(Uxn *u) { Uint16 a = pop16(u->src); Uint16 b = pop16(u->src); mempoke16(u->ram.dat, a, b); }
91void op_dei16(Uxn *u) { Uint8 a = pop8(u->src); push16(u->src, devpeek16(&u->dev[a >> 4], a)); }
92void 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) */
94void op_add16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->src, b + a); }
95void op_sub16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->src, b - a); }
96void op_mul16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->src, b * a); }
97void op_div16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->src, b / a); }
98void op_and16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->src, b & a); }
99void op_ora16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->src, b | a); }
100void op_eor16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->src, b ^ a); }
101void op_sft16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->src, b >> (a & 0x000f) << ((a & 0x00f0) >> 4)); }
102
103void (*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 41
115/* clang-format on */ 42/* clang-format on */
116 43
117#pragma mark - Core 44#pragma mark - Core
118 45
119void 46int
47haltuxn(Uxn *u, char *name, int id)
48{
49 txt_printf("Halted: %s#%04x, at 0x%04x\n", name, id, u->ram.ptr);
50 u->ram.ptr = 0;
51 return 0;
52}
53
54IWRAM_CODE
55static inline void
120opcuxn(Uxn *u, Uint8 instr) 56opcuxn(Uxn *u, Uint8 instr)
121{ 57{
122 Uint8 op = instr & 0x3f, freturn = instr & 0x40, fkeep = instr & 0x80; 58#ifdef CPU_ERROR_CHECKING
123 u->src = freturn ? &u->rst : &u->wst; 59 // With CPU error checking enabled, the codebase becomes too large to fit in ITCM.
124 u->dst = freturn ? &u->wst : &u->rst; 60 // Therefore, we take some concessions.
125 if(fkeep) { 61 if (instr & 0x40) {
126 pop8 = pop8_keep; 62 u->src = &u->rst;
127 u->src->kptr = u->src->ptr; 63 u->dst = &u->wst;
128 } else { 64 } else {
129 pop8 = pop8_nokeep; 65 u->src = &u->wst;
66 u->dst = &u->rst;
67 }
68
69 switch (instr & 0xBF) {
70#define UXN_SRC (u->src)
71#define UXN_DST (u->dst)
72
73#define UXN_KEEP_SYNC {}
74#define pop8 pop8_nokeep
75#define pop16(s) (pop8((s)) + (pop8((s)) << 8))
76
77#define UXN_OPC(a) (a)
78#include "uxn/opcodes.c"
79#undef UXN_OPC
80
81#undef pop16
82#undef pop8
83#undef UXN_KEEP_SYNC
84
85#define UXN_KEEP_SYNC {(*(UXN_SRC)).kptr = (*(UXN_SRC)).ptr;}
86#define pop8 pop8_keep
87#define pop16(s) (pop8((s)) + (pop8((s)) << 8))
88
89#define UXN_OPC(a) (a | 0x80)
90#include "uxn/opcodes.c"
91#undef UXN_OPC
92
93#undef pop16
94#undef pop8
95#undef UXN_KEEP_SYNC
96
97#undef UXN_DST
98#undef UXN_SRC
99 }
100#else
101 switch (instr) {
102#define UXN_KEEP_SYNC {}
103#define pop8 pop8_nokeep
104#define pop16(s) (pop8((s)) + (pop8((s)) << 8))
105
106#define UXN_OPC(a) (a)
107#define UXN_SRC (&u->wst)
108#define UXN_DST (&u->rst)
109#include "uxn/opcodes.c"
110#undef UXN_DST
111#undef UXN_SRC
112#undef UXN_OPC
113
114#define UXN_OPC(a) (a | 0x40)
115#define UXN_SRC (&u->rst)
116#define UXN_DST (&u->wst)
117#include "uxn/opcodes.c"
118#undef UXN_DST
119#undef UXN_SRC
120#undef UXN_OPC
121
122#undef pop16
123#undef pop8
124#undef UXN_KEEP_SYNC
125
126#define UXN_KEEP_SYNC {(*(UXN_SRC)).kptr = (*(UXN_SRC)).ptr;}
127#define pop8 pop8_keep
128#define pop16(s) (pop8((s)) + (pop8((s)) << 8))
129
130#define UXN_OPC(a) (a | 0x80)
131#define UXN_SRC (&u->wst)
132#define UXN_DST (&u->rst)
133#include "uxn/opcodes.c"
134#undef UXN_DST
135#undef UXN_SRC
136#undef UXN_OPC
137
138#define UXN_OPC(a) (a | 0xC0)
139#define UXN_SRC (&u->rst)
140#define UXN_DST (&u->wst)
141#include "uxn/opcodes.c"
142#undef UXN_DST
143#undef UXN_SRC
144#undef UXN_OPC
145
146#undef pop16
147#undef pop8
148#undef UXN_KEEP_SYNC
130 } 149 }
131 (*ops[op])(u); 150#endif
132} 151}
133 152
153IWRAM_CODE
134int 154int
135evaluxn(Uxn *u, Uint16 vec) 155evaluxn(Uxn *u, Uint16 vec)
136{ 156{
diff --git a/src/uxn/uxn.h b/src/uxn/uxn.h
index b2c90ac..b24d058 100644
--- a/src/uxn/uxn.h
+++ b/src/uxn/uxn.h
@@ -28,7 +28,7 @@ typedef struct {
28 28
29typedef struct { 29typedef struct {
30 Uint16 ptr; 30 Uint16 ptr;
31 Uint8 dat[KB(16)]; 31 Uint8 *dat;
32} Memory; 32} Memory;
33 33
34typedef struct Device { 34typedef struct Device {
@@ -45,8 +45,10 @@ typedef struct Uxn {
45 45
46struct Uxn; 46struct Uxn;
47 47
48void mempoke16(Uint8 *m, Uint16 a, Uint16 b); 48static inline void mempoke8(Uint8 *m, Uint16 a, Uint8 b) { m[a] = b; }
49Uint16 mempeek16(Uint8 *m, Uint16 a); 49static inline Uint8 mempeek8(Uint8 *m, Uint16 a) { return m[a]; }
50static inline void mempoke16(Uint8 *m, Uint16 a, Uint16 b) { mempoke8(m, a, b >> 8); mempoke8(m, a + 1, b); }
51static inline Uint16 mempeek16(Uint8 *m, Uint16 a) { return (mempeek8(m, a) << 8) + mempeek8(m, a + 1); }
50 52
51int loaduxn(Uxn *c, char *filepath); 53int loaduxn(Uxn *c, char *filepath);
52int bootuxn(Uxn *c); 54int bootuxn(Uxn *c);
diff --git a/src/uxn/uxn/opcodes.c b/src/uxn/uxn/opcodes.c
new file mode 100644
index 0000000..947755f
--- /dev/null
+++ b/src/uxn/uxn/opcodes.c
@@ -0,0 +1,373 @@
1/*
2Copyright (u) 2021 Devine Lu Linvega
3Copyright (c) 2021 Adrian "asie" Siekierka
4
5Permission to use, copy, modify, and distribute this software for any
6purpose with or without fee is hereby granted, provided that the above
7copyright notice and this permission notice appear in all copies.
8
9THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10WITH REGARD TO THIS SOFTWARE.
11*/
12
13/* 8-BIT OPCODES */
14
15case UXN_OPC(0x00):
16case UXN_OPC(0x20): { // brk
17 u->ram.ptr = 0;
18} break;
19case UXN_OPC(0x01): { // lit
20 push8(UXN_SRC, mempeek8(u->ram.dat, u->ram.ptr++));
21} break;
22case UXN_OPC(0x02):
23case UXN_OPC(0x22): { // nop
24} break;
25case UXN_OPC(0x03): { // pop
26 UXN_KEEP_SYNC;
27 pop8(UXN_SRC);
28} break;
29case UXN_OPC(0x04): { // dup
30 UXN_KEEP_SYNC;
31 Uint8 a = pop8(UXN_SRC);
32 push8(UXN_SRC, a);
33 push8(UXN_SRC, a);
34} break;
35case UXN_OPC(0x05): { // swp
36 UXN_KEEP_SYNC;
37 Uint8 a = pop8(UXN_SRC);
38 Uint8 b = pop8(UXN_SRC);
39 push8(UXN_SRC, a);
40 push8(UXN_SRC, b);
41} break;
42case UXN_OPC(0x06): { // ovr
43 UXN_KEEP_SYNC;
44 Uint8 a = pop8(UXN_SRC);
45 Uint8 b = pop8(UXN_SRC);
46 push8(UXN_SRC, b);
47 push8(UXN_SRC, a);
48 push8(UXN_SRC, b);
49} break;
50case UXN_OPC(0x07): { // rot
51 UXN_KEEP_SYNC;
52 Uint8 a = pop8(UXN_SRC);
53 Uint8 b = pop8(UXN_SRC);
54 Uint8 c = pop8(UXN_SRC);
55 push8(UXN_SRC, b);
56 push8(UXN_SRC, a);
57 push8(UXN_SRC, c);
58} break;
59case UXN_OPC(0x08): { // equ
60 UXN_KEEP_SYNC;
61 Uint8 a = pop8(UXN_SRC);
62 Uint8 b = pop8(UXN_SRC);
63 push8(UXN_SRC, b == a);
64} break;
65case UXN_OPC(0x09): { // neg
66 UXN_KEEP_SYNC;
67 Uint8 a = pop8(UXN_SRC);
68 Uint8 b = pop8(UXN_SRC);
69 push8(UXN_SRC, b != a);
70} break;
71case UXN_OPC(0x0A): { // gth
72 UXN_KEEP_SYNC;
73 Uint8 a = pop8(UXN_SRC);
74 Uint8 b = pop8(UXN_SRC);
75 push8(UXN_SRC, b > a);
76} break;
77case UXN_OPC(0x0B): { // lth
78 UXN_KEEP_SYNC;
79 Uint8 a = pop8(UXN_SRC);
80 Uint8 b = pop8(UXN_SRC);
81 push8(UXN_SRC, b < a);
82} break;
83case UXN_OPC(0x0C): { // jmp
84 UXN_KEEP_SYNC;
85 Uint8 a = pop8(UXN_SRC);
86 u->ram.ptr += (Sint8)a;
87} break;
88case UXN_OPC(0x0D): { // jnz
89 UXN_KEEP_SYNC;
90 Uint8 a = pop8(UXN_SRC);
91 if (pop8(UXN_SRC))
92 u->ram.ptr += (Sint8)a;
93} break;
94case UXN_OPC(0x0E): { // jsr
95 UXN_KEEP_SYNC;
96 Uint8 a = pop8(UXN_SRC);
97 push16(UXN_DST, u->ram.ptr);
98 u->ram.ptr += (Sint8)a;
99} break;
100case UXN_OPC(0x0F): { // sth
101 UXN_KEEP_SYNC;
102 Uint8 a = pop8(UXN_SRC);
103 push8(UXN_DST, a);
104} break;
105case UXN_OPC(0x10): { // pek
106 UXN_KEEP_SYNC;
107 Uint8 a = pop8(UXN_SRC);
108 push8(UXN_SRC, mempeek8(u->ram.dat, a));
109} break;
110case UXN_OPC(0x11): { // pok
111 UXN_KEEP_SYNC;
112 Uint8 a = pop8(UXN_SRC);
113 Uint8 b = pop8(UXN_SRC);
114 mempoke8(u->ram.dat, a, b);
115} break;
116case UXN_OPC(0x12): { // ldr
117 UXN_KEEP_SYNC;
118 Uint8 a = pop8(UXN_SRC);
119 push8(UXN_SRC, mempeek8(u->ram.dat, u->ram.ptr + (Sint8)a));
120} break;
121case UXN_OPC(0x13): { // str
122 UXN_KEEP_SYNC;
123 Uint8 a = pop8(UXN_SRC);
124 Uint8 b = pop8(UXN_SRC);
125 mempoke8(u->ram.dat, u->ram.ptr + (Sint8)a, b);
126} break;
127case UXN_OPC(0x14): { // lda
128 UXN_KEEP_SYNC;
129 Uint16 a = pop16(UXN_SRC);
130 push8(UXN_SRC, mempeek8(u->ram.dat, a));
131} break;
132case UXN_OPC(0x15): { // sta
133 UXN_KEEP_SYNC;
134 Uint16 a = pop16(UXN_SRC);
135 Uint8 b = pop8(UXN_SRC);
136 mempoke8(u->ram.dat, a, b);
137} break;
138case UXN_OPC(0x16): { // dei
139 UXN_KEEP_SYNC;
140 Uint8 a = pop8(UXN_SRC);
141 push8(UXN_SRC, devpeek8(&u->dev[a >> 4], a));
142} break;
143case UXN_OPC(0x17): { // deo
144 UXN_KEEP_SYNC;
145 Uint8 a = pop8(UXN_SRC);
146 Uint8 b = pop8(UXN_SRC);
147 devpoke8(&u->dev[a >> 4], a, b);
148} break;
149case UXN_OPC(0x18): { // add
150 UXN_KEEP_SYNC;
151 Uint8 a = pop8(UXN_SRC);
152 Uint8 b = pop8(UXN_SRC);
153 push8(UXN_SRC, b + a);
154} break;
155case UXN_OPC(0x19): { // sub
156 UXN_KEEP_SYNC;
157 Uint8 a = pop8(UXN_SRC);
158 Uint8 b = pop8(UXN_SRC);
159 push8(UXN_SRC, b - a);
160} break;
161case UXN_OPC(0x1A): { // mul
162 UXN_KEEP_SYNC;
163 Uint8 a = pop8(UXN_SRC);
164 Uint8 b = pop8(UXN_SRC);
165 push8(UXN_SRC, b * a);
166} break;
167case UXN_OPC(0x1B): { // div
168 UXN_KEEP_SYNC;
169 Uint8 a = pop8(UXN_SRC);
170 Uint8 b = pop8(UXN_SRC);
171 push8(UXN_SRC, b / a);
172} break;
173case UXN_OPC(0x1C): { // and
174 UXN_KEEP_SYNC;
175 Uint8 a = pop8(UXN_SRC);
176 Uint8 b = pop8(UXN_SRC);
177 push8(UXN_SRC, b & a);
178} break;
179case UXN_OPC(0x1D): { // ora
180 UXN_KEEP_SYNC;
181 Uint8 a = pop8(UXN_SRC);
182 Uint8 b = pop8(UXN_SRC);
183 push8(UXN_SRC, b | a);
184} break;
185case UXN_OPC(0x1E): { // eor
186 UXN_KEEP_SYNC;
187 Uint8 a = pop8(UXN_SRC);
188 Uint8 b = pop8(UXN_SRC);
189 push8(UXN_SRC, b ^ a);
190} break;
191case UXN_OPC(0x1F): { // sft
192 UXN_KEEP_SYNC;
193 Uint8 a = pop8(UXN_SRC);
194 Uint8 b = pop8(UXN_SRC);
195 push8(UXN_SRC, b >> (a & 0x07) << ((a & 0x70) >> 4));
196} break;
197
198/* 16-BIT OPCODES */
199
200case UXN_OPC(0x21): { // lit
201 push16(UXN_SRC, mempeek16(u->ram.dat, u->ram.ptr));
202 u->ram.ptr += 2;
203} break;
204case UXN_OPC(0x23): { // pop
205 UXN_KEEP_SYNC;
206 pop16(UXN_SRC);
207} break;
208case UXN_OPC(0x24): { // dup
209 UXN_KEEP_SYNC;
210 Uint16 a = pop16(UXN_SRC);
211 push16(UXN_SRC, a);
212 push16(UXN_SRC, a);
213} break;
214case UXN_OPC(0x25): { // swp
215 UXN_KEEP_SYNC;
216 Uint16 a = pop16(UXN_SRC);
217 Uint16 b = pop16(UXN_SRC);
218 push16(UXN_SRC, a);
219 push16(UXN_SRC, b);
220} break;
221case UXN_OPC(0x26): { // ovr
222 UXN_KEEP_SYNC;
223 Uint16 a = pop16(UXN_SRC);
224 Uint16 b = pop16(UXN_SRC);
225 push16(UXN_SRC, b);
226 push16(UXN_SRC, a);
227 push16(UXN_SRC, b);
228} break;
229case UXN_OPC(0x27): { // rot
230 UXN_KEEP_SYNC;
231 Uint16 a = pop16(UXN_SRC);
232 Uint16 b = pop16(UXN_SRC);
233 Uint16 c = pop16(UXN_SRC);
234 push16(UXN_SRC, b);
235 push16(UXN_SRC, a);
236 push16(UXN_SRC, c);
237} break;
238case UXN_OPC(0x28): { // equ
239 UXN_KEEP_SYNC;
240 Uint16 a = pop16(UXN_SRC);
241 Uint16 b = pop16(UXN_SRC);
242 push8(UXN_SRC, b == a);
243} break;
244case UXN_OPC(0x29): { // neg
245 UXN_KEEP_SYNC;
246 Uint16 a = pop16(UXN_SRC);
247 Uint16 b = pop16(UXN_SRC);
248 push8(UXN_SRC, b != a);
249} break;
250case UXN_OPC(0x2A): { // gth
251 UXN_KEEP_SYNC;
252 Uint16 a = pop16(UXN_SRC);
253 Uint16 b = pop16(UXN_SRC);
254 push8(UXN_SRC, b > a);
255} break;
256case UXN_OPC(0x2B): { // lth
257 UXN_KEEP_SYNC;
258 Uint16 a = pop16(UXN_SRC);
259 Uint16 b = pop16(UXN_SRC);
260 push8(UXN_SRC, b < a);
261} break;
262case UXN_OPC(0x2C): { // jmp
263 UXN_KEEP_SYNC;
264 u->ram.ptr = pop16(UXN_SRC);
265} break;
266case UXN_OPC(0x2D): { // jnz
267 UXN_KEEP_SYNC;
268 Uint16 a = pop16(UXN_SRC);
269 if (pop8(UXN_SRC))
270 u->ram.ptr = a;
271} break;
272case UXN_OPC(0x2E): { // jsr
273 UXN_KEEP_SYNC;
274 push16(UXN_DST, u->ram.ptr);
275 u->ram.ptr = pop16(UXN_SRC);
276} break;
277case UXN_OPC(0x2F): { // sth
278 UXN_KEEP_SYNC;
279 Uint16 a = pop16(UXN_SRC);
280 push16(UXN_DST, a);
281} break;
282case UXN_OPC(0x30): { // pek
283 UXN_KEEP_SYNC;
284 Uint8 a = pop8(UXN_SRC);
285 push16(UXN_SRC, mempeek16(u->ram.dat, a));
286} break;
287case UXN_OPC(0x31): { // pok
288 UXN_KEEP_SYNC;
289 Uint8 a = pop8(UXN_SRC);
290 Uint16 b = pop16(UXN_SRC);
291 mempoke16(u->ram.dat, a, b);
292} break;
293case UXN_OPC(0x32): { // ldr
294 UXN_KEEP_SYNC;
295 Uint8 a = pop8(UXN_SRC);
296 push16(UXN_SRC, mempeek16(u->ram.dat, u->ram.ptr + (Sint8)a));
297} break;
298case UXN_OPC(0x33): { // str
299 UXN_KEEP_SYNC;
300 Uint8 a = pop8(UXN_SRC);
301 Uint16 b = pop16(UXN_SRC);
302 mempoke16(u->ram.dat, u->ram.ptr + (Sint8)a, b);
303} break;
304case UXN_OPC(0x34): { // lda
305 UXN_KEEP_SYNC;
306 Uint16 a = pop16(UXN_SRC);
307 push16(UXN_SRC, mempeek16(u->ram.dat, a));
308} break;
309case UXN_OPC(0x35): { // sta
310 UXN_KEEP_SYNC;
311 Uint16 a = pop16(UXN_SRC);
312 Uint16 b = pop16(UXN_SRC);
313 mempoke16(u->ram.dat, a, b);
314} break;
315case UXN_OPC(0x36): { // dei
316 UXN_KEEP_SYNC;
317 Uint8 a = pop8(UXN_SRC);
318 push16(UXN_SRC, devpeek16(&u->dev[a >> 4], a));
319} break;
320case UXN_OPC(0x37): { // deo
321 UXN_KEEP_SYNC;
322 Uint8 a = pop8(UXN_SRC);
323 Uint16 b = pop16(UXN_SRC);
324 devpoke16(&u->dev[a >> 4], a, b);
325} break;
326case UXN_OPC(0x38): { // add
327 UXN_KEEP_SYNC;
328 Uint16 a = pop16(UXN_SRC);
329 Uint16 b = pop16(UXN_SRC);
330 push16(UXN_SRC, b + a);
331} break;
332case UXN_OPC(0x39): { // sub
333 UXN_KEEP_SYNC;
334 Uint16 a = pop16(UXN_SRC);
335 Uint16 b = pop16(UXN_SRC);
336 push16(UXN_SRC, b - a);
337} break;
338case UXN_OPC(0x3A): { // mul
339 UXN_KEEP_SYNC;
340 Uint16 a = pop16(UXN_SRC);
341 Uint16 b = pop16(UXN_SRC);
342 push16(UXN_SRC, b * a);
343} break;
344case UXN_OPC(0x3B): { // div
345 UXN_KEEP_SYNC;
346 Uint16 a = pop16(UXN_SRC);
347 Uint16 b = pop16(UXN_SRC);
348 push16(UXN_SRC, b / a);
349} break;
350case UXN_OPC(0x3C): { // and
351 UXN_KEEP_SYNC;
352 Uint16 a = pop16(UXN_SRC);
353 Uint16 b = pop16(UXN_SRC);
354 push16(UXN_SRC, b & a);
355} break;
356case UXN_OPC(0x3D): { // ora
357 UXN_KEEP_SYNC;
358 Uint16 a = pop16(UXN_SRC);
359 Uint16 b = pop16(UXN_SRC);
360 push16(UXN_SRC, b | a);
361} break;
362case UXN_OPC(0x3E): { // eor
363 UXN_KEEP_SYNC;
364 Uint16 a = pop16(UXN_SRC);
365 Uint16 b = pop16(UXN_SRC);
366 push16(UXN_SRC, b ^ a);
367} break;
368case UXN_OPC(0x3F): { // sft
369 UXN_KEEP_SYNC;
370 Uint16 a = pop16(UXN_SRC);
371 Uint16 b = pop16(UXN_SRC);
372 push16(UXN_SRC, b >> (a & 0x000f) << ((a & 0x00f0) >> 4));
373} break;