diff options
author | Bad Diode <bd@badd10de.dev> | 2021-05-20 22:18:28 +0200 |
---|---|---|
committer | Bad Diode <bd@badd10de.dev> | 2021-05-20 22:18:28 +0200 |
commit | ab6fdd0347920cdcda9c4c3c9c3f01996adc48db (patch) | |
tree | 02f714fdf9a10be96e1eb82b5ebc5834d04c9259 /src | |
parent | 1d6395f1b6aafce4e2e05bcf60f335bec0a8d4b3 (diff) | |
download | uxngba-ab6fdd0347920cdcda9c4c3c9c3f01996adc48db.tar.gz uxngba-ab6fdd0347920cdcda9c4c3c9c3f01996adc48db.zip |
Apply asie's first performance patch
Diffstat (limited to 'src')
-rw-r--r-- | src/bd-font.c | 2 | ||||
-rw-r--r-- | src/common.h | 10 | ||||
-rw-r--r-- | src/main.c | 15 | ||||
-rw-r--r-- | src/small-font.c | 2 | ||||
-rw-r--r-- | src/text.h | 5 | ||||
-rw-r--r-- | src/uxn/devices/ppu.c | 13 | ||||
-rw-r--r-- | src/uxn/uxn.c | 234 | ||||
-rw-r--r-- | src/uxn/uxn.h | 8 | ||||
-rw-r--r-- | src/uxn/uxn/opcodes.c | 373 |
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 | |||
9 | WITH REGARD TO THIS SOFTWARE. | 9 | WITH REGARD TO THIS SOFTWARE. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | u32 bd_font[] = { | 12 | static 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 | ||
669 | const char * note_names[] = { | 669 | static 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 | ||
679 | const u32 sound_rates[] = { | 679 | static 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 |
@@ -61,6 +61,7 @@ system_talk(Device *d, Uint8 b0, Uint8 w) { | |||
61 | (void)b0; | 61 | (void)b0; |
62 | } | 62 | } |
63 | 63 | ||
64 | IWRAM_CODE | ||
64 | void | 65 | void |
65 | screen_talk(Device *d, Uint8 b0, Uint8 w) { | 66 | screen_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 | ||
185 | static Uxn u; | ||
186 | EWRAM_BSS | ||
187 | static Uint8 umem[65536]; | ||
188 | |||
184 | int main(void) { | 189 | int 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 | |||
9 | WITH REGARD TO THIS SOFTWARE. | 9 | WITH REGARD TO THIS SOFTWARE. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | u32 small_font[] = { | 12 | static 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, |
@@ -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 | ||
145 | u32 *backbuffer_bg0; | 145 | EWRAM_BSS |
146 | u32 *backbuffer_bg1; | 146 | static u32 *backbuffer_bg0[30 * 20 * sizeof(Tile) / 4]; |
147 | EWRAM_BSS | ||
148 | static u32 *backbuffer_bg1[30 * 20 * sizeof(Tile) / 4]; | ||
147 | static u32 dirty_tiles[20] = {0}; | 149 | static u32 dirty_tiles[20] = {0}; |
148 | 150 | ||
149 | void | 151 | void |
@@ -161,6 +163,7 @@ putcolors(Ppu *p, Uint8 *addr) { | |||
161 | } | 163 | } |
162 | } | 164 | } |
163 | 165 | ||
166 | IWRAM_CODE | ||
164 | void | 167 | void |
165 | putpixel(Ppu *p, Uint32 *layer, Uint16 x, Uint16 y, Uint8 color) { | 168 | putpixel(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 | ||
182 | IWRAM_CODE | ||
179 | void | 183 | void |
180 | puticn(Ppu *p, Uint32 *layer, Uint16 x, Uint16 y, Uint8 *sprite, Uint8 color, | 184 | puticn(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 | ||
237 | IWRAM_CODE | ||
233 | void | 238 | void |
234 | putchr(Ppu *p, Uint32 *layer, Uint16 x, Uint16 y, Uint8 *sprite, Uint8 color, | 239 | putchr(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 | ||
257 | IWRAM_CODE | ||
252 | void | 258 | void |
253 | flipbuf(Ppu *p) { | 259 | flipbuf(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 | /* |
5 | Copyright (u) 2021 Devine Lu Linvega | 5 | Copyright (u) 2021 Devine Lu Linvega |
6 | Copyright (u) 2021 Adrian Siekierka | ||
6 | 7 | ||
7 | Permission to use, copy, modify, and distribute this software for any | 8 | 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 | purpose 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 | |||
12 | WITH REGARD TO THIS SOFTWARE. | 13 | WITH REGARD TO THIS SOFTWARE. |
13 | */ | 14 | */ |
14 | 15 | ||
15 | #pragma mark - Operations | ||
16 | |||
17 | /* clang-format off */ | 16 | /* clang-format off */ |
18 | void push8(Stack *s, Uint8 a) { if (s->ptr == 0xff) { s->error = 2; return; } s->dat[s->ptr++] = a; } | 17 | |
19 | Uint8 pop8_keep(Stack *s) { if (s->kptr == 0) { s->error = 1; return 0; } return s->dat[--s->kptr]; } | 18 | static inline void push8(Stack *s, Uint8 a) { |
20 | Uint8 pop8_nokeep(Stack *s) { if (s->ptr == 0) { s->error = 1; return 0; } return s->dat[--s->ptr]; } | 19 | #ifdef CPU_ERROR_CHECKING |
21 | static Uint8 (*pop8)(Stack *s); | 20 | if (s->ptr == 0xff) { s->error = 2; return; } |
22 | void mempoke8(Uint8 *m, Uint16 a, Uint8 b) { m[a] = b; } | 21 | #endif |
23 | Uint8 mempeek8(Uint8 *m, Uint16 a) { return m[a]; } | 22 | s->dat[s->ptr++] = a; |
24 | void devpoke8(Device *d, Uint8 a, Uint8 b) { d->dat[a & 0xf] = b; d->talk(d, a & 0x0f, 1); } | 23 | } |
25 | Uint8 devpeek8(Device *d, Uint8 a) { d->talk(d, a & 0x0f, 0); return d->dat[a & 0xf]; } | 24 | static inline Uint8 pop8_keep(Stack *s) { |
26 | void push16(Stack *s, Uint16 a) { push8(s, a >> 8); push8(s, a); } | 25 | #ifdef CPU_ERROR_CHECKING |
27 | Uint16 pop16(Stack *s) { return pop8(s) + (pop8(s) << 8); } | 26 | if (s->kptr == 0) { s->error = 1; return 0; } |
28 | void mempoke16(Uint8 *m, Uint16 a, Uint16 b) { mempoke8(m, a, b >> 8); mempoke8(m, a + 1, b); } | 27 | #endif |
29 | Uint16 mempeek16(Uint8 *m, Uint16 a) { return (mempeek8(m, a) << 8) + mempeek8(m, a + 1); } | 28 | return s->dat[--s->kptr]; |
30 | void devpoke16(Device *d, Uint8 a, Uint16 b) { devpoke8(d, a, b >> 8); devpoke8(d, a + 1, b); } | 29 | } |
31 | Uint16 devpeek16(Device *d, Uint16 a) { return (devpeek8(d, a) << 8) + devpeek8(d, a + 1); } | 30 | static inline Uint8 pop8_nokeep(Stack *s) { |
32 | /* Stack */ | 31 | #ifdef CPU_ERROR_CHECKING |
33 | void op_brk(Uxn *u) { u->ram.ptr = 0; } | 32 | if (s->ptr == 0) { s->error = 1; return 0; } |
34 | void op_nop(Uxn *u) { (void)u; } | 33 | #endif |
35 | void op_lit(Uxn *u) { push8(u->src, mempeek8(u->ram.dat, u->ram.ptr++)); } | 34 | return s->dat[--s->ptr]; |
36 | void op_pop(Uxn *u) { pop8(u->src); } | 35 | } |
37 | void op_dup(Uxn *u) { Uint8 a = pop8(u->src); push8(u->src, a); push8(u->src, a); } | 36 | static inline void devpoke8(Device *d, Uint8 a, Uint8 b) { d->dat[a & 0xf] = b; d->talk(d, a & 0x0f, 1); } |
38 | void op_swp(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, a); push8(u->src, b); } | 37 | static inline Uint8 devpeek8(Device *d, Uint8 a) { d->talk(d, a & 0x0f, 0); return d->dat[a & 0xf]; } |
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); } | 38 | static inline void push16(Stack *s, Uint16 a) { push8(s, a >> 8); push8(s, a); } |
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); } | 39 | static inline void devpoke16(Device *d, Uint8 a, Uint16 b) { devpoke8(d, a, b >> 8); devpoke8(d, a + 1, b); } |
41 | /* Logic */ | 40 | static inline Uint16 devpeek16(Device *d, Uint16 a) { return (devpeek8(d, a) << 8) + devpeek8(d, a + 1); } |
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 | 41 | ||
115 | /* clang-format on */ | 42 | /* clang-format on */ |
116 | 43 | ||
117 | #pragma mark - Core | 44 | #pragma mark - Core |
118 | 45 | ||
119 | void | 46 | int |
47 | haltuxn(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 | |||
54 | IWRAM_CODE | ||
55 | static inline void | ||
120 | opcuxn(Uxn *u, Uint8 instr) | 56 | opcuxn(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 | ||
153 | IWRAM_CODE | ||
134 | int | 154 | int |
135 | evaluxn(Uxn *u, Uint16 vec) | 155 | evaluxn(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 | ||
29 | typedef struct { | 29 | typedef struct { |
30 | Uint16 ptr; | 30 | Uint16 ptr; |
31 | Uint8 dat[KB(16)]; | 31 | Uint8 *dat; |
32 | } Memory; | 32 | } Memory; |
33 | 33 | ||
34 | typedef struct Device { | 34 | typedef struct Device { |
@@ -45,8 +45,10 @@ typedef struct Uxn { | |||
45 | 45 | ||
46 | struct Uxn; | 46 | struct Uxn; |
47 | 47 | ||
48 | void mempoke16(Uint8 *m, Uint16 a, Uint16 b); | 48 | static inline void mempoke8(Uint8 *m, Uint16 a, Uint8 b) { m[a] = b; } |
49 | Uint16 mempeek16(Uint8 *m, Uint16 a); | 49 | static inline Uint8 mempeek8(Uint8 *m, Uint16 a) { return m[a]; } |
50 | static inline void mempoke16(Uint8 *m, Uint16 a, Uint16 b) { mempoke8(m, a, b >> 8); mempoke8(m, a + 1, b); } | ||
51 | static inline Uint16 mempeek16(Uint8 *m, Uint16 a) { return (mempeek8(m, a) << 8) + mempeek8(m, a + 1); } | ||
50 | 52 | ||
51 | int loaduxn(Uxn *c, char *filepath); | 53 | int loaduxn(Uxn *c, char *filepath); |
52 | int bootuxn(Uxn *c); | 54 | int 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 | /* | ||
2 | Copyright (u) 2021 Devine Lu Linvega | ||
3 | Copyright (c) 2021 Adrian "asie" Siekierka | ||
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 | /* 8-BIT OPCODES */ | ||
14 | |||
15 | case UXN_OPC(0x00): | ||
16 | case UXN_OPC(0x20): { // brk | ||
17 | u->ram.ptr = 0; | ||
18 | } break; | ||
19 | case UXN_OPC(0x01): { // lit | ||
20 | push8(UXN_SRC, mempeek8(u->ram.dat, u->ram.ptr++)); | ||
21 | } break; | ||
22 | case UXN_OPC(0x02): | ||
23 | case UXN_OPC(0x22): { // nop | ||
24 | } break; | ||
25 | case UXN_OPC(0x03): { // pop | ||
26 | UXN_KEEP_SYNC; | ||
27 | pop8(UXN_SRC); | ||
28 | } break; | ||
29 | case 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; | ||
35 | case 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; | ||
42 | case 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; | ||
50 | case 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; | ||
59 | case 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; | ||
65 | case 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; | ||
71 | case 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; | ||
77 | case 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; | ||
83 | case UXN_OPC(0x0C): { // jmp | ||
84 | UXN_KEEP_SYNC; | ||
85 | Uint8 a = pop8(UXN_SRC); | ||
86 | u->ram.ptr += (Sint8)a; | ||
87 | } break; | ||
88 | case 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; | ||
94 | case 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; | ||
100 | case UXN_OPC(0x0F): { // sth | ||
101 | UXN_KEEP_SYNC; | ||
102 | Uint8 a = pop8(UXN_SRC); | ||
103 | push8(UXN_DST, a); | ||
104 | } break; | ||
105 | case 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; | ||
110 | case 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; | ||
116 | case 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; | ||
121 | case 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; | ||
127 | case 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; | ||
132 | case 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; | ||
138 | case 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; | ||
143 | case 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; | ||
149 | case 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; | ||
155 | case 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; | ||
161 | case 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; | ||
167 | case 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; | ||
173 | case 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; | ||
179 | case 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; | ||
185 | case 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; | ||
191 | case 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 | |||
200 | case UXN_OPC(0x21): { // lit | ||
201 | push16(UXN_SRC, mempeek16(u->ram.dat, u->ram.ptr)); | ||
202 | u->ram.ptr += 2; | ||
203 | } break; | ||
204 | case UXN_OPC(0x23): { // pop | ||
205 | UXN_KEEP_SYNC; | ||
206 | pop16(UXN_SRC); | ||
207 | } break; | ||
208 | case 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; | ||
214 | case 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; | ||
221 | case 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; | ||
229 | case 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; | ||
238 | case 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; | ||
244 | case 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; | ||
250 | case 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; | ||
256 | case 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; | ||
262 | case UXN_OPC(0x2C): { // jmp | ||
263 | UXN_KEEP_SYNC; | ||
264 | u->ram.ptr = pop16(UXN_SRC); | ||
265 | } break; | ||
266 | case 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; | ||
272 | case UXN_OPC(0x2E): { // jsr | ||
273 | UXN_KEEP_SYNC; | ||
274 | push16(UXN_DST, u->ram.ptr); | ||
275 | u->ram.ptr = pop16(UXN_SRC); | ||
276 | } break; | ||
277 | case UXN_OPC(0x2F): { // sth | ||
278 | UXN_KEEP_SYNC; | ||
279 | Uint16 a = pop16(UXN_SRC); | ||
280 | push16(UXN_DST, a); | ||
281 | } break; | ||
282 | case 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; | ||
287 | case 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; | ||
293 | case 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; | ||
298 | case 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; | ||
304 | case 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; | ||
309 | case 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; | ||
315 | case 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; | ||
320 | case 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; | ||
326 | case 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; | ||
332 | case 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; | ||
338 | case 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; | ||
344 | case 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; | ||
350 | case 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; | ||
356 | case 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; | ||
362 | case 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; | ||
368 | case 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; | ||