diff options
author | Bad Diode <bd@badd10de.dev> | 2023-08-30 20:31:08 +0200 |
---|---|---|
committer | Bad Diode <bd@badd10de.dev> | 2023-08-30 20:31:08 +0200 |
commit | 874ae39b6074da2778b72bcbaf6c7c7ef19aa233 (patch) | |
tree | 5ed5989ac78df0fea75c88c0b63f9a1a5ead6f53 /src | |
parent | be57c62f4633623005b5ac463ce7f65e8761d9bd (diff) | |
download | uxngba-874ae39b6074da2778b72bcbaf6c7c7ef19aa233.tar.gz uxngba-874ae39b6074da2778b72bcbaf6c7c7ef19aa233.zip |
Remove previous uxn core
Diffstat (limited to 'src')
-rw-r--r-- | src/devices.c | 515 | ||||
-rw-r--r-- | src/main.c | 337 | ||||
-rw-r--r-- | src/uxn-core.c | 4 | ||||
-rw-r--r-- | src/uxn.c | 117 | ||||
-rw-r--r-- | src/uxn.h | 37 |
5 files changed, 291 insertions, 719 deletions
diff --git a/src/devices.c b/src/devices.c index e031a85..c65d79b 100644 --- a/src/devices.c +++ b/src/devices.c | |||
@@ -1,290 +1,305 @@ | |||
1 | static time_t seconds = 0; | 1 | static time_t seconds = 0; |
2 | 2 | ||
3 | int | 3 | #define RAM_PAGES 0x10 |
4 | uxn_halt(Uxn *u, u8 instr, u8 err, u16 addr) { | 4 | |
5 | (void)u; | 5 | void |
6 | txt_printf("HALTED\n"); | 6 | deo_console(u8 *dev, u8 port) { |
7 | txt_printf("I: %lu\n", instr); | 7 | switch(port) { |
8 | txt_printf("E: %lu\n", err); | 8 | case 0x8: |
9 | txt_printf("A: %lu\n", addr); | 9 | txt_putc(dev[port]); |
10 | while (true); | 10 | return; |
11 | case 0x9: | ||
12 | txt_printf("ERROR: %c"); | ||
13 | txt_putc(dev[port]); | ||
14 | return; | ||
15 | } | ||
11 | } | 16 | } |
12 | 17 | ||
13 | IWRAM_CODE | 18 | u16 |
14 | u8 | 19 | dei_screen(u8 *dev, u8 port) { |
15 | screen_dei(u8 *d, u8 port) { | 20 | switch(port) { |
16 | // switch(port) { | 21 | case 0x0: |
17 | // case 0x2: return (SCREEN_WIDTH >> 8); | 22 | case 0x8: |
18 | // case 0x3: return (SCREEN_WIDTH); | 23 | case 0xa: |
19 | // case 0x4: return (SCREEN_HEIGHT >> 8); | 24 | case 0xc: return PEEK2(dev + port); |
20 | // case 0x5: return (SCREEN_HEIGHT); | 25 | case 0x2: return SCREEN_WIDTH; |
21 | // default: return d[port]; | 26 | case 0x4: return SCREEN_HEIGHT; |
22 | // } | 27 | default: return dev[port]; |
28 | } | ||
23 | } | 29 | } |
24 | 30 | ||
25 | IWRAM_CODE | 31 | u16 |
26 | void | 32 | dei_mouse(u8 *dev, u8 port) { |
27 | screen_deo(u8 *ram, u8 *d, u8 port) { | 33 | switch(port) { |
28 | // switch(port) { | 34 | case 0x0: |
29 | // case 0xe: { | 35 | case 0x2: |
30 | // u8 ctrl = d[0xe]; | 36 | case 0x4: |
31 | // u8 color = ctrl & 0x3; | 37 | case 0xa: |
32 | // u16 x0 = PEEK2(d + 0x8); | 38 | case 0xc: return PEEK2(dev + port); |
33 | // u16 y0 = PEEK2(d + 0xa); | 39 | default: return dev[port]; |
34 | // u8 *layer = (ctrl & 0x40) ? FG_BACK : BG_BACK; | 40 | } |
35 | // if(ctrl & 0x80) { | ||
36 | // u16 x1 = SCREEN_WIDTH - 1; | ||
37 | // u16 y1 = SCREEN_HEIGHT - 1; | ||
38 | // if(ctrl & 0x10) x1 = x0, x0 = 0; | ||
39 | // if(ctrl & 0x20) y1 = y0, y0 = 0; | ||
40 | // PROF(screen_fill(layer, x0, y0, x1, y1, color), ppu_fill_cycles); | ||
41 | // } else { | ||
42 | // PROF(ppu_pixel(layer, x0, y0, color), ppu_pixel_cycles); | ||
43 | // if(d[0x6] & 0x1) POKE2(d + 0x8, x0 + 1); /* auto x+1 */ | ||
44 | // if(d[0x6] & 0x2) POKE2(d + 0xa, y0 + 1); /* auto y+1 */ | ||
45 | // } | ||
46 | // break; | ||
47 | // } | ||
48 | // case 0xf: { | ||
49 | // u16 x, y, dx, dy, addr; | ||
50 | // u8 n, twobpp = !!(d[0xf] & 0x80); | ||
51 | // x = PEEK2(d + 0x8); | ||
52 | // y = PEEK2(d + 0xa); | ||
53 | // addr = PEEK2(d + 0xc); | ||
54 | // n = d[0x6] >> 4; | ||
55 | // dx = (d[0x6] & 0x01) << 3; | ||
56 | // dy = (d[0x6] & 0x02) << 2; | ||
57 | // if(addr > 0x10000 - ((n + 1) << (3 + twobpp))) { | ||
58 | // return; | ||
59 | // } | ||
60 | // u8 *layer = (d[0xf] & 0x40) ? FG_BACK : BG_BACK; | ||
61 | // u8 color = d[0xf] & 0xf; | ||
62 | // u8 flipx = d[0xf] & 0x10; | ||
63 | // u8 flipy = d[0xf] & 0x20; | ||
64 | // for(size_t i = 0; i <= n; i++) { | ||
65 | // u8 *sprite = &ram[addr]; | ||
66 | // if (twobpp) { | ||
67 | // PROF(ppu_2bpp(layer, | ||
68 | // x + dy * i, | ||
69 | // y + dx * i, | ||
70 | // sprite, | ||
71 | // color, | ||
72 | // flipx, flipy), ppu_chr_cycles); | ||
73 | // } else { | ||
74 | // PROF(ppu_1bpp(layer, | ||
75 | // x + dy * i, | ||
76 | // y + dx * i, | ||
77 | // sprite, | ||
78 | // color, | ||
79 | // flipx, flipy), ppu_icn_cycles); | ||
80 | // } | ||
81 | // addr += (d[0x6] & 0x04) << (1 + twobpp); | ||
82 | // } | ||
83 | // POKE2(d + 0xc, addr); /* auto addr+length */ | ||
84 | // POKE2(d + 0x8, x + dx); /* auto x+8 */ | ||
85 | // POKE2(d + 0xa, y + dy); /* auto y+8 */ | ||
86 | // break; | ||
87 | // } | ||
88 | // } | ||
89 | } | 41 | } |
90 | 42 | ||
91 | u8 | 43 | void |
92 | audio_dei(int instance, u8 *d, u8 port) { | 44 | deo_screen(u8 *dev, u8 port) { |
93 | // AudioChannel *c = &channels[instance]; | 45 | switch(port) { |
94 | // switch(port) { | 46 | case 0xe: { |
95 | // // case 0x4: return apu_get_vu(instance); | 47 | u8 ctrl = dev[0xe]; |
96 | // case 0x2: { | 48 | u8 color = ctrl & 0x3; |
97 | // POKE2(d + 0x2, c->pos); | 49 | u16 x0 = PEEK2(dev + 0x8); |
98 | // c->pos <<= 12; // fixed point. | 50 | u16 y0 = PEEK2(dev + 0xa); |
99 | // break; | 51 | u8 *layer = (ctrl & 0x40) ? FG_BACK : BG_BACK; |
100 | // } | 52 | if(ctrl & 0x80) { |
101 | // } | 53 | u16 x1 = SCREEN_WIDTH - 1; |
102 | return d[port]; | 54 | u16 y1 = SCREEN_HEIGHT - 1; |
55 | if(ctrl & 0x10) x1 = x0, x0 = 0; | ||
56 | if(ctrl & 0x20) y1 = y0, y0 = 0; | ||
57 | PROF(screen_fill(layer, x0, y0, x1, y1, color), ppu_fill_cycles); | ||
58 | } else { | ||
59 | PROF(ppu_pixel(layer, x0, y0, color), ppu_pixel_cycles); | ||
60 | if(dev[0x6] & 0x1) POKE2(dev + 0x8, x0 + 1); /* auto x+1 */ | ||
61 | if(dev[0x6] & 0x2) POKE2(dev + 0xa, y0 + 1); /* auto y+1 */ | ||
62 | } | ||
63 | break; | ||
64 | } | ||
65 | case 0xf: { | ||
66 | u16 x, y, dx, dy, addr; | ||
67 | u8 n, twobpp = !!(dev[0xf] & 0x80); | ||
68 | x = PEEK2(dev + 0x8); | ||
69 | y = PEEK2(dev + 0xa); | ||
70 | addr = PEEK2(dev + 0xc); | ||
71 | n = dev[0x6] >> 4; | ||
72 | dx = (dev[0x6] & 0x01) << 3; | ||
73 | dy = (dev[0x6] & 0x02) << 2; | ||
74 | if(addr > 0x10000 - ((n + 1) << (3 + twobpp))) { | ||
75 | return; | ||
76 | } | ||
77 | u8 *layer = (dev[0xf] & 0x40) ? FG_BACK : BG_BACK; | ||
78 | u8 color = dev[0xf] & 0xf; | ||
79 | u8 flipx = dev[0xf] & 0x10; | ||
80 | u8 flipy = dev[0xf] & 0x20; | ||
81 | for(size_t i = 0; i <= n; i++) { | ||
82 | u8 *sprite = &uxn_ram[addr]; | ||
83 | if (twobpp) { | ||
84 | PROF(ppu_2bpp(layer, | ||
85 | x + dy * i, | ||
86 | y + dx * i, | ||
87 | sprite, | ||
88 | color, | ||
89 | flipx, flipy), ppu_chr_cycles); | ||
90 | } else { | ||
91 | PROF(ppu_1bpp(layer, | ||
92 | x + dy * i, | ||
93 | y + dx * i, | ||
94 | sprite, | ||
95 | color, | ||
96 | flipx, flipy), ppu_icn_cycles); | ||
97 | } | ||
98 | addr += (dev[0x6] & 0x04) << (1 + twobpp); | ||
99 | } | ||
100 | POKE2(dev + 0xc, addr); /* auto addr+length */ | ||
101 | POKE2(dev + 0x8, x + dx); /* auto x+8 */ | ||
102 | POKE2(dev + 0xa, y + dy); /* auto y+8 */ | ||
103 | break; | ||
104 | } | ||
105 | } | ||
103 | } | 106 | } |
104 | 107 | ||
105 | void | 108 | void |
106 | audio_deo(int instance, u8 *d, u8 port, Uxn *u) { | 109 | deo_system(u8 *dev, u8 port) { |
107 | // AudioChannel *c = &channels[instance]; | 110 | switch(port) { |
108 | // if (port == 0xf) { | 111 | case 0x3: { |
109 | // u16 length = 0; | 112 | // TODO: Rom bank switching (Needs testing). |
110 | // u16 adsr = 0; | 113 | u16 addr = PEEK2(dev + 0x2); |
111 | // u16 addr = 0; | 114 | if(uxn_ram[addr] == 0x01) { |
112 | // u8 pitch = d[0xf] & 0x7f; | 115 | u16 i, length = PEEK2(uxn_ram + addr + 1); |
113 | // adsr = PEEK2(d + 0x8); | 116 | u16 a_page = PEEK2(uxn_ram + addr + 1 + 2); |
114 | // length = PEEK2(d + 0xa); | 117 | u16 a_addr = PEEK2(uxn_ram + addr + 1 + 4); |
115 | // addr = PEEK2(d + 0xc); | 118 | u16 b_addr = PEEK2(uxn_ram + addr + 1 + 8); |
116 | // u8 *data = &u->ram[addr]; | 119 | u8 *rom = uxn_rom + (a_page % RAM_PAGES) * 0x10000; |
117 | // u32 vol = MAX(d[0xe] >> 4, d[0xe] & 0xf) * 4 / 3; | 120 | for(i = 0; i < length; i++) { |
118 | // bool loop = !(d[0xf] & 0x80); | 121 | uxn_ram[(u16)(b_addr + i)] = rom[(u16)(a_addr + i)]; |
119 | // update_channel(c, data, length, pitch, adsr, vol, loop); | 122 | } |
120 | // } | 123 | } |
124 | } break; | ||
125 | case 0x4: { | ||
126 | // TODO: Set wst_ptr, but is it the offset instead? | ||
127 | } break; | ||
128 | case 0x5: { | ||
129 | // TODO: Set rst_ptr, but is it the offset instead? | ||
130 | } break; | ||
131 | case 0x8: | ||
132 | case 0x9: | ||
133 | case 0xa: | ||
134 | case 0xb: | ||
135 | case 0xc: | ||
136 | case 0xd: { | ||
137 | // Setup RGB palette. | ||
138 | putcolors(&dev[0x8]); | ||
139 | } break; | ||
140 | case 0xe: { | ||
141 | // TODO: System inspect. | ||
142 | } break; | ||
143 | } | ||
121 | } | 144 | } |
122 | 145 | ||
123 | u8 | 146 | u16 |
124 | datetime_dei(u8 *d, u8 port) { | 147 | dei_system(u8 *dev, u8 port) { |
148 | switch (port) { | ||
149 | case 0x0: | ||
150 | case 0x2: | ||
151 | case 0x6: | ||
152 | case 0x8: | ||
153 | case 0xa: | ||
154 | case 0xc: return PEEK2(dev + port); | ||
155 | case 0x4: { | ||
156 | // TODO: Return wst_ptr, but is it the offset instead? | ||
157 | } break; | ||
158 | case 0x5: { | ||
159 | // TODO: Return rst_ptr, but is it the offset instead? | ||
160 | } break; | ||
161 | } | ||
162 | return dev[port]; | ||
163 | } | ||
164 | |||
165 | u16 | ||
166 | dei_datetime(u8 *dev, u8 port) { | ||
125 | struct tm *t = gmtime(&seconds); | 167 | struct tm *t = gmtime(&seconds); |
126 | switch(port) { | 168 | switch(port) { |
127 | case 0x0: return (t->tm_year + 1900) >> 8; | 169 | case 0x0: return (t->tm_year + 1900); |
128 | case 0x1: return (t->tm_year + 1900); | 170 | case 0x1: return (t->tm_year + 1900) >> 8; |
129 | case 0x2: return t->tm_mon; | 171 | case 0x2: return t->tm_mon; |
130 | case 0x3: return t->tm_mday; | 172 | case 0x3: return t->tm_mday; |
131 | case 0x4: return t->tm_hour; | 173 | case 0x4: return t->tm_hour; |
132 | case 0x5: return t->tm_min; | 174 | case 0x5: return t->tm_min; |
133 | case 0x6: return t->tm_sec; | 175 | case 0x6: return t->tm_sec; |
134 | case 0x7: return t->tm_wday; | 176 | case 0x7: return t->tm_wday; |
135 | case 0x8: return t->tm_yday >> 8; | 177 | case 0x8: return t->tm_yday; |
136 | case 0x9: return t->tm_yday; | 178 | case 0x9: return t->tm_yday >> 8; |
137 | case 0xa: return t->tm_isdst; | 179 | case 0xa: return t->tm_isdst; |
138 | default: return d[port]; | 180 | default: return dev[port]; |
139 | } | 181 | } |
140 | } | 182 | } |
141 | 183 | ||
142 | u8 | 184 | u16 |
143 | file_dei(u8 id, u8 *d, u8 port) { | 185 | dei_audio(u8 *dev, u8 port) { |
144 | // UxnFile *c = &uxn_file[id]; | 186 | size_t idx = (dev - (device_data + 0x30)) / 16; |
145 | // u16 res; | 187 | AudioChannel *c = &channels[idx]; |
146 | // switch(port) { | 188 | switch(port) { |
147 | // case 0xc: | 189 | case 0x0: |
148 | // case 0xd: { | 190 | case 0x8: |
149 | // res = file_read(c, &d[port], 1); | 191 | case 0xa: |
150 | // POKE2(d + 0x2, res); | 192 | case 0x2: // TODO: return the position |
151 | // break; | 193 | case 0xc: return PEEK2(dev + port); |
152 | // } | 194 | // case 0x2: { |
153 | // } | 195 | // POKE2(d + 0x2, c->pos); |
154 | return d[port]; | 196 | // c->pos <<= 12; // fixed point. |
155 | } | 197 | // break; |
156 | 198 | // } | |
157 | void | 199 | // case 0x4: return apu_get_vu(idx); |
158 | file_deo(u8 id, u8 *ram, u8 *d, u8 port) { | 200 | // TODO: return the current envelope loudness (0x00-0xff). |
159 | // u16 a, b, res; | 201 | default: return dev[port]; |
160 | // UxnFile *f = &uxn_file[id]; | 202 | } |
161 | // switch(port) { | 203 | return dev[port]; |
162 | // case 0x5: { | ||
163 | // a = PEEK2(d + 0x4); | ||
164 | // b = PEEK2(d + 0xa); | ||
165 | // if(b > 0x10000 - a) { | ||
166 | // b = 0x10000 - a; | ||
167 | // } | ||
168 | // res = file_stat(f, &ram[a], b); | ||
169 | // POKE2(d + 0x2, res); | ||
170 | // } break; | ||
171 | // case 0x6: { | ||
172 | // // TODO: no file deletion for now | ||
173 | // // res = file_delete(); | ||
174 | // // POKE2(d + 0x2, res); | ||
175 | // } break; | ||
176 | // case 0x9: { | ||
177 | // a = PEEK2(d + 0x8); | ||
178 | // res = file_init(f, &ram[a]); | ||
179 | // POKE2(d + 0x2, res); | ||
180 | // } break; | ||
181 | // case 0xd: { | ||
182 | // a = PEEK2(d + 0xc); | ||
183 | // b = PEEK2(d + 0xa); | ||
184 | // if(b > 0x10000 - a) { | ||
185 | // b = 0x10000 - a; | ||
186 | // } | ||
187 | // res = file_read(f, &ram[a], b); | ||
188 | // POKE2(d + 0x2, res); | ||
189 | // } break; | ||
190 | // case 0xf: { | ||
191 | // a = PEEK2(d + 0xe); | ||
192 | // b = PEEK2(d + 0xa); | ||
193 | // if(b > 0x10000 - a) { | ||
194 | // b = 0x10000 - a; | ||
195 | // } | ||
196 | // res = file_write(f, &ram[a], b, d[0x7]); | ||
197 | // POKE2(d + 0x2, res); | ||
198 | // } break; | ||
199 | // } | ||
200 | } | 204 | } |
201 | 205 | ||
202 | void | 206 | void |
203 | console_deo(u8 *d, u8 port) { | 207 | deo_audio(u8 *dev, u8 port) { |
204 | // switch(port) { | 208 | size_t idx = (dev - (device_data + 0x30)) / 16; |
205 | // case 0x8: | 209 | txt_printf("IDX: %d\n", idx); |
206 | // txt_putc(d[port]); | 210 | AudioChannel *c = &channels[idx]; |
207 | // return; | 211 | if (port == 0xf) { |
208 | // case 0x9: | 212 | u16 length = 0; |
209 | // txt_printf("ERROR: %c"); | 213 | u16 adsr = 0; |
210 | // txt_putc(d[port]); | 214 | u16 addr = 0; |
211 | // return; | 215 | u8 pitch = dev[0xf] & 0x7f; |
212 | // } | 216 | adsr = PEEK2(dev + 0x8); |
217 | length = PEEK2(dev + 0xa); | ||
218 | addr = PEEK2(dev + 0xc); | ||
219 | u8 *data = &uxn_ram[addr]; | ||
220 | u32 vol = MAX(dev[0xe] >> 4, dev[0xe] & 0xf) * 4 / 3; | ||
221 | bool loop = !(dev[0xf] & 0x80); | ||
222 | update_channel(c, data, length, pitch, adsr, vol, loop); | ||
223 | } | ||
213 | } | 224 | } |
214 | 225 | ||
215 | #define RAM_PAGES 0x10 | 226 | u16 |
216 | 227 | dei_file(u8 *dev, u8 port) { | |
217 | static void | 228 | size_t idx = (dev - (device_data + 0xa0)) / 16; |
218 | system_cmd(u8 *ram, u16 addr) { | 229 | UxnFile *c = &uxn_file[idx]; |
219 | if(ram[addr] == 0x01) { | 230 | switch(port) { |
220 | // NOTE: Handle rom paging on a case by case basis if a rom has to be | 231 | case 0x0: |
221 | // split in multiple chunks. The GBA compiler doesn't like allocating | 232 | case 0x2: |
222 | // big arrays, but it's fine if we split it into chunks of 64KB, for | 233 | case 0x4: |
223 | // example. | 234 | case 0x8: |
224 | // | 235 | case 0xa: |
225 | // u16 i, length = PEEK2(ram + addr + 1); | 236 | case 0xe: return PEEK2(dev + port); |
226 | // u16 a_page = PEEK2(ram + addr + 1 + 2); | 237 | case 0xc: |
227 | // u16 a_addr = PEEK2(ram + addr + 1 + 4); | 238 | case 0xd: { |
228 | // u16 b_addr = PEEK2(ram + addr + 1 + 8); | 239 | u16 res = file_read(c, &dev[port], 1); |
229 | // u8 *rom = uxn_rom; | 240 | POKE2(dev + 0x2, res); |
230 | // for(i = 0; i < length; i++) { | 241 | return res; |
231 | // switch (a_page % RAM_PAGES) { | 242 | } |
232 | // case 0: { rom = uxn_rom; } break; | ||
233 | // case 1: { rom = uxn_rom_2; } break; | ||
234 | // case 2: { rom = uxn_rom_3; } break; | ||
235 | // case 3: { rom = uxn_rom_4; } break; | ||
236 | // case 4: { rom = uxn_rom_5; } break; | ||
237 | // case 5: { rom = uxn_rom_6; } break; | ||
238 | // case 6: { rom = uxn_rom_7; } break; | ||
239 | // } | ||
240 | // ram[(u16)(b_addr + i)] = rom[(u16)(a_addr + i)]; | ||
241 | // } | ||
242 | } | 243 | } |
244 | return dev[port]; | ||
243 | } | 245 | } |
244 | 246 | ||
245 | void | 247 | void |
246 | system_deo(Uxn *u, u8 *d, u8 port) { | 248 | deo_file(u8 *dev, u8 port) { |
247 | // switch(port) { | 249 | size_t idx = (dev - (device_data + 0xa0)) / 16; |
248 | // case 0x3: { | 250 | u16 a, b, res; |
249 | // system_cmd(u->ram, PEEK2(d + 2)); | 251 | UxnFile *f = &uxn_file[idx]; |
250 | // } break; | 252 | switch(port) { |
251 | // } | 253 | case 0x5: { |
252 | } | 254 | a = PEEK2(dev + 0x4); |
253 | 255 | b = PEEK2(dev + 0xa); | |
254 | u8 | 256 | if(b > 0x10000 - a) { |
255 | uxn_dei(Uxn *u, u8 addr) { | 257 | b = 0x10000 - a; |
256 | u8 p = addr & 0x0f, d = addr & 0xf0; | 258 | } |
257 | switch(d) { | 259 | res = file_stat(f, &uxn_ram[a], b); |
258 | case 0x20: return screen_dei(&u->dev[d], p); | 260 | POKE2(dev + 0x2, res); |
259 | case 0x30: return audio_dei(0, &u->dev[d], p); | 261 | } break; |
260 | case 0x40: return audio_dei(1, &u->dev[d], p); | 262 | case 0x6: { |
261 | case 0x50: return audio_dei(2, &u->dev[d], p); | 263 | // TODO: no file deletion for now |
262 | case 0x60: return audio_dei(3, &u->dev[d], p); | 264 | // res = file_delete(); |
263 | case 0xa0: return file_dei(0, &u->dev[d], p); | 265 | // POKE2(dev + 0x2, res); |
264 | case 0xb0: return file_dei(1, &u->dev[d], p); | 266 | } break; |
265 | case 0xc0: return datetime_dei(&u->dev[d], p); | 267 | case 0x9: { |
268 | a = PEEK2(dev + 0x8); | ||
269 | res = file_init(f, &uxn_ram[a]); | ||
270 | POKE2(dev + 0x2, res); | ||
271 | } break; | ||
272 | case 0xd: { | ||
273 | a = PEEK2(dev + 0xc); | ||
274 | b = PEEK2(dev + 0xa); | ||
275 | if(b > 0x10000 - a) { | ||
276 | b = 0x10000 - a; | ||
277 | } | ||
278 | res = file_read(f, &uxn_ram[a], b); | ||
279 | POKE2(dev + 0x2, res); | ||
280 | } break; | ||
281 | case 0xf: { | ||
282 | a = PEEK2(dev + 0xe); | ||
283 | b = PEEK2(dev + 0xa); | ||
284 | if(b > 0x10000 - a) { | ||
285 | b = 0x10000 - a; | ||
286 | } | ||
287 | res = file_write(f, &uxn_ram[a], b, dev[0x7]); | ||
288 | POKE2(dev + 0x2, res); | ||
289 | } break; | ||
266 | } | 290 | } |
267 | return u->dev[addr]; | ||
268 | } | 291 | } |
269 | 292 | ||
270 | void | 293 | void |
271 | uxn_deo(Uxn *u, u8 addr) { | 294 | deo_stub(u8 *dev, u8 port) { |
272 | u8 p = addr & 0x0f, d = addr & 0xf0; | 295 | (void)dev; |
273 | switch(d) { | 296 | (void)port; |
274 | case 0x00: | ||
275 | system_deo(u, &u->dev[d], p); | ||
276 | if(p > 0x7 && p < 0xe) { | ||
277 | putcolors(&u->dev[0x8]); | ||
278 | } | ||
279 | break; | ||
280 | case 0x10: console_deo(&u->dev[d], p); break; | ||
281 | case 0x20: screen_deo(u->ram, &u->dev[d], p); break; | ||
282 | case 0x30: audio_deo(0, &u->dev[d], p, u); break; | ||
283 | case 0x40: audio_deo(1, &u->dev[d], p, u); break; | ||
284 | case 0x50: audio_deo(2, &u->dev[d], p, u); break; | ||
285 | case 0x60: audio_deo(3, &u->dev[d], p, u); break; | ||
286 | case 0xa0: file_deo(0, u->ram, &u->dev[d], p); break; | ||
287 | case 0xb0: file_deo(1, u->ram, &u->dev[d], p); break; | ||
288 | } | ||
289 | } | 297 | } |
290 | 298 | ||
299 | u16 | ||
300 | dei_stub(u8 *dev, u8 port) { | ||
301 | if (port == 0) { | ||
302 | return PEEK2(dev); | ||
303 | } | ||
304 | return dev[port]; | ||
305 | } | ||
@@ -17,13 +17,12 @@ | |||
17 | 17 | ||
18 | #include "uxn-core.c" | 18 | #include "uxn-core.c" |
19 | 19 | ||
20 | #include "uxn.c" | 20 | #include "rom.c" |
21 | #include "ppu.c" | 21 | #include "ppu.c" |
22 | #include "apu.c" | 22 | #include "apu.c" |
23 | #include "file.c" | 23 | #include "file.c" |
24 | #include "text.h" | 24 | #include "text.h" |
25 | 25 | ||
26 | #include "rom.c" | ||
27 | #include "config.c" | 26 | #include "config.c" |
28 | #include "profiling.c" | 27 | #include "profiling.c" |
29 | #include "input.c" | 28 | #include "input.c" |
@@ -31,297 +30,6 @@ | |||
31 | #include "debug.c" | 30 | #include "debug.c" |
32 | 31 | ||
33 | void | 32 | void |
34 | deo_console(u8 *dev, u8 port) { | ||
35 | switch(port) { | ||
36 | case 0x8: | ||
37 | txt_putc(dev[port]); | ||
38 | return; | ||
39 | case 0x9: | ||
40 | txt_printf("ERROR: %c"); | ||
41 | txt_putc(dev[port]); | ||
42 | return; | ||
43 | } | ||
44 | } | ||
45 | |||
46 | u16 | ||
47 | dei_screen(u8 *dev, u8 port) { | ||
48 | switch(port) { | ||
49 | case 0x0: | ||
50 | case 0x8: | ||
51 | case 0xa: | ||
52 | case 0xc: return PEEK2(dev + port); | ||
53 | case 0x2: return SCREEN_WIDTH; | ||
54 | case 0x4: return SCREEN_HEIGHT; | ||
55 | default: return dev[port]; | ||
56 | } | ||
57 | } | ||
58 | |||
59 | u16 | ||
60 | dei_mouse(u8 *dev, u8 port) { | ||
61 | switch(port) { | ||
62 | case 0x0: | ||
63 | case 0x2: | ||
64 | case 0x4: | ||
65 | case 0xa: | ||
66 | case 0xc: return PEEK2(dev + port); | ||
67 | default: return dev[port]; | ||
68 | } | ||
69 | } | ||
70 | |||
71 | void | ||
72 | deo_screen(u8 *dev, u8 port) { | ||
73 | switch(port) { | ||
74 | case 0xe: { | ||
75 | u8 ctrl = dev[0xe]; | ||
76 | u8 color = ctrl & 0x3; | ||
77 | u16 x0 = PEEK2(dev + 0x8); | ||
78 | u16 y0 = PEEK2(dev + 0xa); | ||
79 | u8 *layer = (ctrl & 0x40) ? FG_BACK : BG_BACK; | ||
80 | if(ctrl & 0x80) { | ||
81 | u16 x1 = SCREEN_WIDTH - 1; | ||
82 | u16 y1 = SCREEN_HEIGHT - 1; | ||
83 | if(ctrl & 0x10) x1 = x0, x0 = 0; | ||
84 | if(ctrl & 0x20) y1 = y0, y0 = 0; | ||
85 | PROF(screen_fill(layer, x0, y0, x1, y1, color), ppu_fill_cycles); | ||
86 | } else { | ||
87 | PROF(ppu_pixel(layer, x0, y0, color), ppu_pixel_cycles); | ||
88 | if(dev[0x6] & 0x1) POKE2(dev + 0x8, x0 + 1); /* auto x+1 */ | ||
89 | if(dev[0x6] & 0x2) POKE2(dev + 0xa, y0 + 1); /* auto y+1 */ | ||
90 | } | ||
91 | break; | ||
92 | } | ||
93 | case 0xf: { | ||
94 | u16 x, y, dx, dy, addr; | ||
95 | u8 n, twobpp = !!(dev[0xf] & 0x80); | ||
96 | x = PEEK2(dev + 0x8); | ||
97 | y = PEEK2(dev + 0xa); | ||
98 | addr = PEEK2(dev + 0xc); | ||
99 | n = dev[0x6] >> 4; | ||
100 | dx = (dev[0x6] & 0x01) << 3; | ||
101 | dy = (dev[0x6] & 0x02) << 2; | ||
102 | if(addr > 0x10000 - ((n + 1) << (3 + twobpp))) { | ||
103 | return; | ||
104 | } | ||
105 | u8 *layer = (dev[0xf] & 0x40) ? FG_BACK : BG_BACK; | ||
106 | u8 color = dev[0xf] & 0xf; | ||
107 | u8 flipx = dev[0xf] & 0x10; | ||
108 | u8 flipy = dev[0xf] & 0x20; | ||
109 | for(size_t i = 0; i <= n; i++) { | ||
110 | u8 *sprite = &uxn_ram[addr]; | ||
111 | if (twobpp) { | ||
112 | PROF(ppu_2bpp(layer, | ||
113 | x + dy * i, | ||
114 | y + dx * i, | ||
115 | sprite, | ||
116 | color, | ||
117 | flipx, flipy), ppu_chr_cycles); | ||
118 | } else { | ||
119 | PROF(ppu_1bpp(layer, | ||
120 | x + dy * i, | ||
121 | y + dx * i, | ||
122 | sprite, | ||
123 | color, | ||
124 | flipx, flipy), ppu_icn_cycles); | ||
125 | } | ||
126 | addr += (dev[0x6] & 0x04) << (1 + twobpp); | ||
127 | } | ||
128 | POKE2(dev + 0xc, addr); /* auto addr+length */ | ||
129 | POKE2(dev + 0x8, x + dx); /* auto x+8 */ | ||
130 | POKE2(dev + 0xa, y + dy); /* auto y+8 */ | ||
131 | break; | ||
132 | } | ||
133 | } | ||
134 | } | ||
135 | |||
136 | void | ||
137 | deo_system(u8 *dev, u8 port) { | ||
138 | switch(port) { | ||
139 | case 0x3: { | ||
140 | // TODO: Rom bank switching. | ||
141 | } break; | ||
142 | case 0x4: { | ||
143 | // TODO: Set wst_ptr, but is it the offset instead? | ||
144 | } break; | ||
145 | case 0x5: { | ||
146 | // TODO: Set rst_ptr, but is it the offset instead? | ||
147 | } break; | ||
148 | case 0x8: | ||
149 | case 0x9: | ||
150 | case 0xa: | ||
151 | case 0xb: | ||
152 | case 0xc: | ||
153 | case 0xd: { | ||
154 | // Setup RGB palette. | ||
155 | putcolors(&dev[0x8]); | ||
156 | } break; | ||
157 | case 0xe: { | ||
158 | // TODO: System inspect. | ||
159 | } break; | ||
160 | } | ||
161 | } | ||
162 | |||
163 | u16 | ||
164 | dei_system(u8 *dev, u8 port) { | ||
165 | switch (port) { | ||
166 | case 0x0: | ||
167 | case 0x2: | ||
168 | case 0x6: | ||
169 | case 0x8: | ||
170 | case 0xa: | ||
171 | case 0xc: return PEEK2(dev + port); | ||
172 | case 0x4: { | ||
173 | // TODO: Return wst_ptr, but is it the offset instead? | ||
174 | } break; | ||
175 | case 0x5: { | ||
176 | // TODO: Return rst_ptr, but is it the offset instead? | ||
177 | } break; | ||
178 | default: { return dev[port]; } break; | ||
179 | } | ||
180 | } | ||
181 | |||
182 | u16 | ||
183 | dei_datetime(u8 *dev, u8 port) { | ||
184 | struct tm *t = gmtime(&seconds); | ||
185 | switch(port) { | ||
186 | case 0x0: return (t->tm_year + 1900); | ||
187 | case 0x1: return (t->tm_year + 1900) >> 8; | ||
188 | case 0x2: return t->tm_mon; | ||
189 | case 0x3: return t->tm_mday; | ||
190 | case 0x4: return t->tm_hour; | ||
191 | case 0x5: return t->tm_min; | ||
192 | case 0x6: return t->tm_sec; | ||
193 | case 0x7: return t->tm_wday; | ||
194 | case 0x8: return t->tm_yday; | ||
195 | case 0x9: return t->tm_yday >> 8; | ||
196 | case 0xa: return t->tm_isdst; | ||
197 | default: return dev[port]; | ||
198 | } | ||
199 | } | ||
200 | |||
201 | u16 | ||
202 | dei_audio(u8 *dev, u8 port) { | ||
203 | size_t idx = (dev - (device_data + 0x30)) / 16; | ||
204 | AudioChannel *c = &channels[idx]; | ||
205 | switch(port) { | ||
206 | case 0x0: | ||
207 | case 0x8: | ||
208 | case 0xa: | ||
209 | case 0x2: // TODO: return the position | ||
210 | case 0xc: return PEEK2(dev + port); | ||
211 | // case 0x2: { | ||
212 | // POKE2(d + 0x2, c->pos); | ||
213 | // c->pos <<= 12; // fixed point. | ||
214 | // break; | ||
215 | // } | ||
216 | // case 0x4: return apu_get_vu(idx); | ||
217 | // TODO: return the current envelope loudness (0x00-0xff). | ||
218 | default: return dev[port]; | ||
219 | } | ||
220 | return dev[port]; | ||
221 | } | ||
222 | |||
223 | void | ||
224 | deo_audio(u8 *dev, u8 port) { | ||
225 | size_t idx = (dev - (device_data + 0x30)) / 16; | ||
226 | txt_printf("IDX: %d\n", idx); | ||
227 | AudioChannel *c = &channels[idx]; | ||
228 | if (port == 0xf) { | ||
229 | u16 length = 0; | ||
230 | u16 adsr = 0; | ||
231 | u16 addr = 0; | ||
232 | u8 pitch = dev[0xf] & 0x7f; | ||
233 | adsr = PEEK2(dev + 0x8); | ||
234 | length = PEEK2(dev + 0xa); | ||
235 | addr = PEEK2(dev + 0xc); | ||
236 | u8 *data = &uxn_ram[addr]; | ||
237 | u32 vol = MAX(dev[0xe] >> 4, dev[0xe] & 0xf) * 4 / 3; | ||
238 | bool loop = !(dev[0xf] & 0x80); | ||
239 | update_channel(c, data, length, pitch, adsr, vol, loop); | ||
240 | } | ||
241 | } | ||
242 | |||
243 | u16 | ||
244 | dei_file(u8 *dev, u8 port) { | ||
245 | size_t idx = (dev - (device_data + 0xa0)) / 16; | ||
246 | UxnFile *c = &uxn_file[idx]; | ||
247 | switch(port) { | ||
248 | case 0x0: | ||
249 | case 0x2: | ||
250 | case 0x4: | ||
251 | case 0x8: | ||
252 | case 0xa: | ||
253 | case 0xe: return PEEK2(dev + port); | ||
254 | case 0xc: | ||
255 | case 0xd: { | ||
256 | u16 res = file_read(c, &dev[port], 1); | ||
257 | POKE2(dev + 0x2, res); | ||
258 | return res; | ||
259 | } | ||
260 | } | ||
261 | return dev[port]; | ||
262 | } | ||
263 | |||
264 | void | ||
265 | deo_file(u8 *dev, u8 port) { | ||
266 | size_t idx = (dev - (device_data + 0xa0)) / 16; | ||
267 | u16 a, b, res; | ||
268 | UxnFile *f = &uxn_file[idx]; | ||
269 | switch(port) { | ||
270 | case 0x5: { | ||
271 | a = PEEK2(dev + 0x4); | ||
272 | b = PEEK2(dev + 0xa); | ||
273 | if(b > 0x10000 - a) { | ||
274 | b = 0x10000 - a; | ||
275 | } | ||
276 | res = file_stat(f, &uxn_ram[a], b); | ||
277 | POKE2(dev + 0x2, res); | ||
278 | } break; | ||
279 | case 0x6: { | ||
280 | // TODO: no file deletion for now | ||
281 | // res = file_delete(); | ||
282 | // POKE2(dev + 0x2, res); | ||
283 | } break; | ||
284 | case 0x9: { | ||
285 | a = PEEK2(dev + 0x8); | ||
286 | res = file_init(f, &uxn_ram[a]); | ||
287 | POKE2(dev + 0x2, res); | ||
288 | } break; | ||
289 | case 0xd: { | ||
290 | a = PEEK2(dev + 0xc); | ||
291 | b = PEEK2(dev + 0xa); | ||
292 | if(b > 0x10000 - a) { | ||
293 | b = 0x10000 - a; | ||
294 | } | ||
295 | res = file_read(f, &uxn_ram[a], b); | ||
296 | POKE2(dev + 0x2, res); | ||
297 | } break; | ||
298 | case 0xf: { | ||
299 | a = PEEK2(dev + 0xe); | ||
300 | b = PEEK2(dev + 0xa); | ||
301 | if(b > 0x10000 - a) { | ||
302 | b = 0x10000 - a; | ||
303 | } | ||
304 | res = file_write(f, &uxn_ram[a], b, dev[0x7]); | ||
305 | POKE2(dev + 0x2, res); | ||
306 | } break; | ||
307 | } | ||
308 | } | ||
309 | |||
310 | void | ||
311 | deo_stub(u8 *dev, u8 port) { | ||
312 | (void)dev; | ||
313 | (void)port; | ||
314 | } | ||
315 | |||
316 | u16 | ||
317 | dei_stub(u8 *dev, u8 port) { | ||
318 | if (port == 0) { | ||
319 | return PEEK2(dev); | ||
320 | } | ||
321 | return dev[port]; | ||
322 | } | ||
323 | |||
324 | void | ||
325 | init_uxn() { | 33 | init_uxn() { |
326 | // Initialize uxn. | 34 | // Initialize uxn. |
327 | u32 fill = 0; | 35 | u32 fill = 0; |
@@ -339,30 +47,29 @@ init_uxn() { | |||
339 | 47 | ||
340 | // Setup deo/dei maps. | 48 | // Setup deo/dei maps. |
341 | for (size_t i = 0; i < 16; i++) { | 49 | for (size_t i = 0; i < 16; i++) { |
342 | deo_map[i] = deo_stub; | 50 | deo_map[i] = (uintptr_t) deo_stub; |
343 | dei_map[i] = dei_stub; | 51 | dei_map[i] = (uintptr_t) dei_stub; |
344 | } | 52 | } |
345 | deo_map[0x0] = deo_system; | 53 | deo_map[0x0] = (uintptr_t) deo_system; |
346 | dei_map[0x0] = dei_system; | 54 | dei_map[0x0] = (uintptr_t) dei_system; |
347 | deo_map[0x1] = deo_console; | 55 | deo_map[0x1] = (uintptr_t) deo_console; |
348 | deo_map[0x2] = deo_screen; | 56 | deo_map[0x2] = (uintptr_t) deo_screen; |
349 | dei_map[0x2] = dei_screen; | 57 | dei_map[0x2] = (uintptr_t) dei_screen; |
350 | deo_map[0x3] = deo_audio; | 58 | deo_map[0x3] = (uintptr_t) deo_audio; |
351 | dei_map[0x3] = dei_audio; | 59 | dei_map[0x3] = (uintptr_t) dei_audio; |
352 | deo_map[0x4] = deo_audio; | 60 | deo_map[0x4] = (uintptr_t) deo_audio; |
353 | dei_map[0x4] = dei_audio; | 61 | dei_map[0x4] = (uintptr_t) dei_audio; |
354 | deo_map[0x5] = deo_audio; | 62 | deo_map[0x5] = (uintptr_t) deo_audio; |
355 | dei_map[0x5] = dei_audio; | 63 | dei_map[0x5] = (uintptr_t) dei_audio; |
356 | deo_map[0x6] = deo_audio; | 64 | deo_map[0x6] = (uintptr_t) deo_audio; |
357 | dei_map[0x6] = dei_audio; | 65 | dei_map[0x6] = (uintptr_t) dei_audio; |
358 | deo_map[0xa] = deo_file; | 66 | deo_map[0xa] = (uintptr_t) deo_file; |
359 | dei_map[0xa] = dei_file; | 67 | dei_map[0xa] = (uintptr_t) dei_file; |
360 | deo_map[0xb] = deo_file; | 68 | deo_map[0xb] = (uintptr_t) deo_file; |
361 | dei_map[0xb] = dei_file; | 69 | dei_map[0xb] = (uintptr_t) dei_file; |
362 | dei_map[0xc] = dei_datetime; | 70 | dei_map[0xc] = (uintptr_t) dei_datetime; |
363 | dei_map[0x9] = dei_mouse; | 71 | dei_map[0x9] = (uintptr_t) dei_mouse; |
364 | } | 72 | } |
365 | |||
366 | int | 73 | int |
367 | main(void) { | 74 | main(void) { |
368 | // Adjust system wait times. | 75 | // Adjust system wait times. |
diff --git a/src/uxn-core.c b/src/uxn-core.c index 6ff4c50..8a2c971 100644 --- a/src/uxn-core.c +++ b/src/uxn-core.c | |||
@@ -30,3 +30,7 @@ extern u8 device_data[256]; | |||
30 | 30 | ||
31 | EWRAM_BSS | 31 | EWRAM_BSS |
32 | u8 uxn_ram[KB(64)]; | 32 | u8 uxn_ram[KB(64)]; |
33 | |||
34 | #define PAGE_PROGRAM 0x0100 | ||
35 | #define POKE2(d, v) do { (d)[0] = (v) >> 8; (d)[1] = (v); } while(0) | ||
36 | #define PEEK2(d) ((d)[0] << 8 | (d)[1]) | ||
diff --git a/src/uxn.c b/src/uxn.c deleted file mode 100644 index d525ff1..0000000 --- a/src/uxn.c +++ /dev/null | |||
@@ -1,117 +0,0 @@ | |||
1 | #include "uxn.h" | ||
2 | |||
3 | /* | ||
4 | Copyright (u) 2022-2023 Devine Lu Linvega, Andrew Alderwick, Andrew Richards | ||
5 | |||
6 | Permission to use, copy, modify, and distribute this software for any | ||
7 | purpose with or without fee is hereby granted, provided that the above | ||
8 | copyright notice and this permission notice appear in all copies. | ||
9 | |||
10 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
11 | WITH REGARD TO THIS SOFTWARE. | ||
12 | */ | ||
13 | |||
14 | #define T s->dat[s->ptr - 1] | ||
15 | #define N s->dat[s->ptr - 2] | ||
16 | #define L s->dat[s->ptr - 3] | ||
17 | #define H2 PEEK2(s->dat + s->ptr - 3) | ||
18 | #define T2 PEEK2(s->dat + s->ptr - 2) | ||
19 | #define N2 PEEK2(s->dat + s->ptr - 4) | ||
20 | #define L2 PEEK2(s->dat + s->ptr - 6) | ||
21 | |||
22 | /* Registers | ||
23 | |||
24 | [ . ][ . ][ . ][ L ][ N ][ T ] < | ||
25 | [ . ][ . ][ . ][ H2 ][ T ] < | ||
26 | [ L2 ][ N2 ][ T2 ] < | ||
27 | |||
28 | */ | ||
29 | |||
30 | |||
31 | u16 deo_mask[] = {0xff08, 0x0300, 0xc028, 0x8000, 0x8000, 0x8000, 0x8000, 0x0000, 0x0000, 0x0000, 0xa260, 0xa260, 0x0000, 0x0000, 0x0000, 0x0000}; | ||
32 | u16 dei_mask[] = {0x0000, 0x0000, 0x003c, 0x0014, 0x0014, 0x0014, 0x0014, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x07ff, 0x0000, 0x0000, 0x0000}; | ||
33 | |||
34 | #define POKE2(d, v) { (d)[0] = (v) >> 8; (d)[1] = (v); } | ||
35 | #define PEEK2(d) ((d)[0] << 8 | (d)[1]) | ||
36 | #define HALT(c) { return uxn_halt(u, ins, (c), pc - 1); } | ||
37 | #define SET(mul, add) { if(mul > s->ptr) HALT(1) tmp = s->ptr + k * mul + add; if(tmp > 254) HALT(2) s->ptr = tmp; } | ||
38 | #define PUT(o, v) { s->dat[(u8)(s->ptr - 1 - (o))] = (v); } | ||
39 | #define PUT2(o, v) { tmp = (v); s->dat[(u8)(s->ptr - o - 2)] = tmp >> 8; s->dat[(u8)(s->ptr - o - 1)] = tmp; } | ||
40 | #define PUSH(stack, v) { if(s->ptr > 254) HALT(2) stack->dat[stack->ptr++] = (v); } | ||
41 | #define PUSH2(stack, v) { if(s->ptr > 253) HALT(2) tmp = (v); stack->dat[stack->ptr] = tmp >> 8; stack->dat[stack->ptr + 1] = tmp; stack->ptr += 2; } | ||
42 | #define DEO(a, b) { u->dev[(a)] = (b); if((deo_mask[(a) >> 4] >> ((a) & 0xf)) & 0x1) uxn_deo(u, (a)); } | ||
43 | #define DEI(a, b) { PUT((a), ((dei_mask[(b) >> 4] >> ((b) & 0xf)) & 0x1) ? uxn_dei(u, (b)) : u->dev[(b)]) } | ||
44 | |||
45 | IWRAM_CODE | ||
46 | int | ||
47 | uxn_eval(Uxn *u, u16 pc) { | ||
48 | u8 ins, opc, k; | ||
49 | u16 t, n, l, tmp; | ||
50 | Stack *s; | ||
51 | if(!pc || u->dev[0x0f]) return 0; | ||
52 | for(;;) { | ||
53 | ins = u->ram[pc++]; | ||
54 | k = !!(ins & 0x80); | ||
55 | s = ins & 0x40 ? u->rst : u->wst; | ||
56 | opc = !(ins & 0x1f) ? 0 - (ins >> 5) : ins & 0x3f; | ||
57 | switch(opc) { | ||
58 | /* IMM */ | ||
59 | case 0x00: /* BRK */ return 1; | ||
60 | case 0xff: /* JCI */ pc += !!s->dat[--s->ptr] * PEEK2(u->ram + pc) + 2; break; | ||
61 | case 0xfe: /* JMI */ pc += PEEK2(u->ram + pc) + 2; break; | ||
62 | case 0xfd: /* JSI */ PUSH2(u->rst, pc + 2) pc += PEEK2(u->ram + pc) + 2; break; | ||
63 | case 0xfc: /* LIT */ PUSH(s, u->ram[pc++]) break; | ||
64 | case 0xfb: /* LIT2 */ PUSH2(s, PEEK2(u->ram + pc)) pc += 2; break; | ||
65 | case 0xfa: /* LITr */ PUSH(s, u->ram[pc++]) break; | ||
66 | case 0xf9: /* LIT2r */ PUSH2(s, PEEK2(u->ram + pc)) pc += 2; break; | ||
67 | /* ALU */ | ||
68 | case 0x01: /* INC */ t=T; SET(1, 0) PUT(0, t + 1) break; case 0x21: t=T2; SET(2, 0) PUT2(0, t + 1) break; | ||
69 | case 0x02: /* POP */ SET(1,-1) break; case 0x22: SET(2,-2) break; | ||
70 | case 0x03: /* NIP */ t=T; SET(2,-1) PUT(0, t) break; case 0x23: t=T2; SET(4,-2) PUT2(0, t) break; | ||
71 | case 0x04: /* SWP */ t=T;n=N; SET(2, 0) PUT(0, n) PUT(1, t) break; case 0x24: t=T2;n=N2; SET(4, 0) PUT2(0, n) PUT2(2, t) break; | ||
72 | case 0x05: /* ROT */ t=T;n=N;l=L; SET(3, 0) PUT(0, l) PUT(1, t) PUT(2, n) break; case 0x25: t=T2;n=N2;l=L2; SET(6, 0) PUT2(0, l) PUT2(2, t) PUT2(4, n) break; | ||
73 | case 0x06: /* DUP */ t=T; SET(1, 1) PUT(0, t) PUT(1, t) break; case 0x26: t=T2; SET(2, 2) PUT2(0, t) PUT2(2, t) break; | ||
74 | case 0x07: /* OVR */ t=T;n=N; SET(2, 1) PUT(0, n) PUT(1, t) PUT(2, n) break; case 0x27: t=T2;n=N2; SET(4, 2) PUT2(0, n) PUT2(2, t) PUT2(4, n) break; | ||
75 | case 0x08: /* EQU */ t=T;n=N; SET(2,-1) PUT(0, n == t) break; case 0x28: t=T2;n=N2; SET(4,-3) PUT(0, n == t) break; | ||
76 | case 0x09: /* NEQ */ t=T;n=N; SET(2,-1) PUT(0, n != t) break; case 0x29: t=T2;n=N2; SET(4,-3) PUT(0, n != t) break; | ||
77 | case 0x0a: /* GTH */ t=T;n=N; SET(2,-1) PUT(0, n > t) break; case 0x2a: t=T2;n=N2; SET(4,-3) PUT(0, n > t) break; | ||
78 | case 0x0b: /* LTH */ t=T;n=N; SET(2,-1) PUT(0, n < t) break; case 0x2b: t=T2;n=N2; SET(4,-3) PUT(0, n < t) break; | ||
79 | case 0x0c: /* JMP */ t=T; SET(1,-1) pc += (s8)t; break; case 0x2c: t=T2; SET(2,-2) pc = t; break; | ||
80 | case 0x0d: /* JCN */ t=T;n=N; SET(2,-2) pc += !!n * (s8)t; break; case 0x2d: t=T2;n=L; SET(3,-3) if(n) pc = t; break; | ||
81 | case 0x0e: /* JSR */ t=T; SET(1,-1) PUSH2(u->rst, pc) pc += (s8)t; break; case 0x2e: t=T2; SET(2,-2) PUSH2(u->rst, pc) pc = t; break; | ||
82 | case 0x0f: /* STH */ t=T; SET(1,-1) PUSH((ins & 0x40 ? u->wst : u->rst), t) break; case 0x2f: t=T2; SET(2,-2) PUSH2((ins & 0x40 ? u->wst : u->rst), t) break; | ||
83 | case 0x10: /* LDZ */ t=T; SET(1, 0) PUT(0, u->ram[t]) break; case 0x30: t=T; SET(1, 1) PUT2(0, PEEK2(u->ram + t)) break; | ||
84 | case 0x11: /* STZ */ t=T;n=N; SET(2,-2) u->ram[t] = n; break; case 0x31: t=T;n=H2; SET(3,-3) POKE2(u->ram + t, n) break; | ||
85 | case 0x12: /* LDR */ t=T; SET(1, 0) PUT(0, u->ram[pc + (s8)t]) break; case 0x32: t=T; SET(1, 1) PUT2(0, PEEK2(u->ram + pc + (s8)t)) break; | ||
86 | case 0x13: /* STR */ t=T;n=N; SET(2,-2) u->ram[pc + (s8)t] = n; break; case 0x33: t=T;n=H2; SET(3,-3) POKE2(u->ram + pc + (s8)t, n) break; | ||
87 | case 0x14: /* LDA */ t=T2; SET(2,-1) PUT(0, u->ram[t]) break; case 0x34: t=T2; SET(2, 0) PUT2(0, PEEK2(u->ram + t)) break; | ||
88 | case 0x15: /* STA */ t=T2;n=L; SET(3,-3) u->ram[t] = n; break; case 0x35: t=T2;n=N2; SET(4,-4) POKE2(u->ram + t, n) break; | ||
89 | case 0x16: /* DEI */ t=T; SET(1, 0) DEI(0, t) break; case 0x36: t=T; SET(1, 1) DEI(1, t) DEI(0, t + 1) break; | ||
90 | case 0x17: /* DEO */ t=T;n=N; SET(2,-2) DEO(t, n) break; case 0x37: t=T;n=N;l=L; SET(3,-3) DEO(t, l) DEO(t + 1, n) break; | ||
91 | case 0x18: /* ADD */ t=T;n=N; SET(2,-1) PUT(0, n + t) break; case 0x38: t=T2;n=N2; SET(4,-2) PUT2(0, n + t) break; | ||
92 | case 0x19: /* SUB */ t=T;n=N; SET(2,-1) PUT(0, n - t) break; case 0x39: t=T2;n=N2; SET(4,-2) PUT2(0, n - t) break; | ||
93 | case 0x1a: /* MUL */ t=T;n=N; SET(2,-1) PUT(0, n * t) break; case 0x3a: t=T2;n=N2; SET(4,-2) PUT2(0, n * t) break; | ||
94 | case 0x1b: /* DIV */ t=T;n=N; SET(2,-1) PUT(0, n / t) break; case 0x3b: t=T2;n=N2; SET(4,-2) PUT2(0, n / t) break; | ||
95 | case 0x1c: /* AND */ t=T;n=N; SET(2,-1) PUT(0, n & t) break; case 0x3c: t=T2;n=N2; SET(4,-2) PUT2(0, n & t) break; | ||
96 | case 0x1d: /* ORA */ t=T;n=N; SET(2,-1) PUT(0, n | t) break; case 0x3d: t=T2;n=N2; SET(4,-2) PUT2(0, n | t) break; | ||
97 | case 0x1e: /* EOR */ t=T;n=N; SET(2,-1) PUT(0, n ^ t) break; case 0x3e: t=T2;n=N2; SET(4,-2) PUT2(0, n ^ t) break; | ||
98 | case 0x1f: /* SFT */ t=T;n=N; SET(2,-1) PUT(0, n >> (t & 0xf) << (t >> 4)) break; case 0x3f: t=T;n=H2; SET(3,-1) PUT2(0, n >> (t & 0xf) << (t >> 4)) break; | ||
99 | } | ||
100 | } | ||
101 | } | ||
102 | |||
103 | int | ||
104 | uxn_boot(Uxn *u, u8 *ram, Dei *dei, Deo *deo) | ||
105 | { | ||
106 | u32 i; | ||
107 | char *cptr = (char *)u; | ||
108 | for(i = 0; i < sizeof(*u); i++) | ||
109 | cptr[i] = 0x00; | ||
110 | u->wst = (Stack *)(ram + 0x10000); | ||
111 | u->rst = (Stack *)(ram + 0x10100); | ||
112 | u->dev = (u8 *)(ram + 0x10200); | ||
113 | u->ram = ram; | ||
114 | u->dei = dei; | ||
115 | u->deo = deo; | ||
116 | return 1; | ||
117 | } | ||
diff --git a/src/uxn.h b/src/uxn.h deleted file mode 100644 index 04aba84..0000000 --- a/src/uxn.h +++ /dev/null | |||
@@ -1,37 +0,0 @@ | |||
1 | #ifndef UXNGBA_UXN_H | ||
2 | #define UXNGBA_UXN_H | ||
3 | /* | ||
4 | Copyright (c) 2021 Devine Lu Linvega | ||
5 | |||
6 | Permission to use, copy, modify, and distribute this software for any | ||
7 | purpose with or without fee is hereby granted, provided that the above | ||
8 | copyright notice and this permission notice appear in all copies. | ||
9 | |||
10 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
11 | WITH REGARD TO THIS SOFTWARE. | ||
12 | */ | ||
13 | |||
14 | #define PAGE_PROGRAM 0x0100 | ||
15 | |||
16 | /* clang-format on */ | ||
17 | |||
18 | typedef struct { | ||
19 | u8 dat[255], ptr; | ||
20 | } Stack; | ||
21 | |||
22 | typedef struct Uxn { | ||
23 | u8 *ram, *dev; | ||
24 | Stack *wst, *rst; | ||
25 | u8 (*dei)(struct Uxn *u, u8 addr); | ||
26 | void (*deo)(struct Uxn *u, u8 addr, u8 value); | ||
27 | } Uxn; | ||
28 | |||
29 | typedef u8 Dei(Uxn *u, u8 addr); | ||
30 | typedef void Deo(Uxn *u, u8 addr, u8 value); | ||
31 | |||
32 | u8 uxn_dei(Uxn *u, u8 addr); | ||
33 | void uxn_deo(Uxn *u, u8 addr); | ||
34 | int uxn_halt(Uxn *u, u8 instr, u8 err, u16 addr); | ||
35 | int uxn_boot(Uxn *u, u8 *ram, Dei *dei, Deo *deo); | ||
36 | int uxn_eval(Uxn *u, u16 pc); | ||
37 | #endif // UXNGBA_UXN_H | ||