aboutsummaryrefslogtreecommitdiffstats
path: root/src/devices.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices.c')
-rw-r--r--src/devices.c303
1 files changed, 303 insertions, 0 deletions
diff --git a/src/devices.c b/src/devices.c
new file mode 100644
index 0000000..6a1ed28
--- /dev/null
+++ b/src/devices.c
@@ -0,0 +1,303 @@
1static time_t seconds = 1693475007;
2
3#define RAM_PAGES 0x10
4
5void
6deo_console(u8 *dev, u8 port) {
7 switch(port) {
8 case 0x8:
9 txt_putc(dev[port]);
10 return;
11 case 0x9:
12 txt_printf("ERROR: %c");
13 txt_putc(dev[port]);
14 return;
15 }
16}
17
18u16
19dei_screen(u8 *dev, u8 port) {
20 switch(port) {
21 case 0x0:
22 case 0x8:
23 case 0xa:
24 case 0xc: return PEEK2(dev + port);
25 case 0x2: return SCREEN_WIDTH;
26 case 0x4: return SCREEN_HEIGHT;
27 default: return dev[port];
28 }
29}
30
31u16
32dei_mouse(u8 *dev, u8 port) {
33 switch(port) {
34 case 0x0:
35 case 0x2:
36 case 0x4:
37 case 0xa:
38 case 0xc: return PEEK2(dev + port);
39 default: return dev[port];
40 }
41}
42
43void
44deo_screen(u8 *dev, u8 port) {
45 switch(port) {
46 case 0xe: {
47 u8 ctrl = dev[0xe];
48 u8 color = ctrl & 0x3;
49 u16 x0 = PEEK2(dev + 0x8);
50 u16 y0 = PEEK2(dev + 0xa);
51 u8 *layer = (ctrl & 0x40) ? FG_BACK : BG_BACK;
52 if(ctrl & 0x80) {
53 u16 x1 = SCREEN_WIDTH - 1;
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 u8 ctrl = dev[0xf];
67 u8 move = dev[0x6];
68 u8 length = move >> 4;
69 u8 twobpp = !!(ctrl & 0x80);
70 u8 *layer = (dev[0xf] & 0x40) ? FG_BACK : BG_BACK;
71 u8 color = ctrl & 0xf;
72 u16 x = PEEK2(dev + 0x8), dx = (move & 0x1) << 3;
73 u16 y = PEEK2(dev + 0xa), dy = (move & 0x2) << 2;
74 u16 addr = PEEK2(dev + 0xc), addr_incr = (move & 0x4) << (1 + twobpp);
75 int flipx = (ctrl & 0x10), fx = flipx ? -1 : 1;
76 int flipy = (ctrl & 0x20), fy = flipy ? -1 : 1;
77 for(size_t i = 0; i <= length; i++) {
78 u8 *sprite = &uxn_ram[addr];
79 if (twobpp) {
80 PROF(ppu_2bpp(layer,
81 x + dy * i * fx,
82 y + dx * i * fy,
83 sprite,
84 color,
85 flipx, flipy), ppu_chr_cycles);
86 } else {
87 PROF(ppu_1bpp(layer,
88 x + dy * i * fx,
89 y + dx * i * fy,
90 sprite,
91 color,
92 flipx, flipy), ppu_icn_cycles);
93 }
94 addr += addr_incr;
95 }
96 if(move & 0x1) POKE2(dev + 0x8, x + dx * fx); /* auto x+8 */
97 if(move & 0x2) POKE2(dev + 0xa, y + dy * fy); /* auto y+8 */
98 if(move & 0x4) POKE2(dev + 0xc, addr); /* auto addr+length */
99 break;
100 }
101 }
102}
103
104void
105deo_system(u8 *dev, u8 port) {
106 switch(port) {
107 case 0x2: {
108 // Rom bank switching.
109 u16 addr = PEEK2(dev + port);
110 if(uxn_ram[addr] == 0x01) {
111 u16 length = PEEK2(uxn_ram + addr + 1);
112 u16 a_page = PEEK2(uxn_ram + addr + 1 + 2);
113 u16 a_addr = PEEK2(uxn_ram + addr + 1 + 4);
114 u16 b_page = PEEK2(uxn_ram + addr + 1 + 6);
115 u16 b_addr = PEEK2(uxn_ram + addr + 1 + 8);
116 u8 *ram = uxn_ram + (b_page % RAM_PAGES) * 0x10000;
117 u8 *rom = uxn_rom + (a_page % RAM_PAGES) * 0x10000 - PAGE_PROGRAM;
118 for(size_t i = 0; i < length; i++) {
119 ram[b_addr + i] = rom[a_addr + i];
120 }
121 }
122 } break;
123 case 0x4: {
124 // TODO: Set wst_ptr, but is it the offset instead?
125 } break;
126 case 0x5: {
127 // TODO: Set rst_ptr, but is it the offset instead?
128 } break;
129 case 0x8:
130 case 0x9:
131 case 0xa:
132 case 0xb:
133 case 0xc:
134 case 0xd: {
135 // Setup RGB palette.
136 putcolors(&dev[0x8]);
137 } break;
138 case 0xe: {
139 // TODO: System inspect.
140 } break;
141 }
142}
143
144u16
145dei_system(u8 *dev, u8 port) {
146 switch (port) {
147 case 0x0:
148 case 0x2:
149 case 0x6:
150 case 0x8:
151 case 0xa:
152 case 0xc: return PEEK2(dev + port);
153 case 0x4: {
154 // TODO: Return wst_ptr, but is it the offset instead?
155 } break;
156 case 0x5: {
157 // TODO: Return rst_ptr, but is it the offset instead?
158 } break;
159 }
160 return dev[port];
161}
162
163u16
164dei_datetime(u8 *dev, u8 port) {
165 struct tm *t = gmtime(&seconds);
166 switch(port) {
167 case 0x0: return (t->tm_year + 1900);
168 case 0x1: return (t->tm_year + 1900) >> 8;
169 case 0x2: return t->tm_mon;
170 case 0x3: return t->tm_mday;
171 case 0x4: return t->tm_hour;
172 case 0x5: return t->tm_min;
173 case 0x6: return t->tm_sec;
174 case 0x7: return t->tm_wday;
175 case 0x8: return t->tm_yday;
176 case 0x9: return t->tm_yday >> 8;
177 case 0xa: return t->tm_isdst;
178 }
179 return dev[port];
180}
181
182u16
183dei_audio(u8 *dev, u8 port) {
184 size_t idx = (dev - (device_data + 0x30)) / 16;
185 AudioChannel *c = &channels[idx];
186 switch(port) {
187 case 0x0:
188 case 0x8:
189 case 0xa:
190 case 0x2: // TODO: return the position
191 case 0xc: return PEEK2(dev + port);
192 // case 0x2: {
193 // POKE2(d + 0x2, c->pos);
194 // c->pos <<= 12; // fixed point.
195 // break;
196 // }
197 // case 0x4: return apu_get_vu(idx);
198 // TODO: return the current envelope loudness (0x00-0xff).
199 default: return dev[port];
200 }
201 return dev[port];
202}
203
204void
205deo_audio(u8 *dev, u8 port) {
206 size_t idx = (dev - (device_data + 0x30)) / 16;
207 txt_printf("IDX: %d\n", idx);
208 AudioChannel *c = &channels[idx];
209 if (port == 0xf) {
210 u16 length = 0;
211 u16 adsr = 0;
212 u16 addr = 0;
213 u8 pitch = dev[0xf] & 0x7f;
214 adsr = PEEK2(dev + 0x8);
215 length = PEEK2(dev + 0xa);
216 addr = PEEK2(dev + 0xc);
217 u8 *data = &uxn_ram[addr];
218 u32 vol = MAX(dev[0xe] >> 4, dev[0xe] & 0xf) * 4 / 3;
219 bool loop = !(dev[0xf] & 0x80);
220 update_channel(c, data, length, pitch, adsr, vol, loop);
221 }
222}
223
224u16
225dei_file(u8 *dev, u8 port) {
226 size_t idx = (dev - (device_data + 0xa0)) / 16;
227 UxnFile *c = &uxn_file[idx];
228 switch(port) {
229 case 0x0:
230 case 0x2:
231 case 0x4:
232 case 0x8:
233 case 0xa:
234 case 0xe: return PEEK2(dev + port);
235 case 0xc:
236 case 0xd: {
237 u16 res = file_read(c, &dev[port], 1);
238 POKE2(dev + 0x2, res);
239 return res;
240 }
241 }
242 return dev[port];
243}
244
245void
246deo_file(u8 *dev, u8 port) {
247 size_t idx = (dev - (device_data + 0xa0)) / 16;
248 u16 a, b, res;
249 UxnFile *f = &uxn_file[idx];
250 switch(port) {
251 case 0x5: {
252 a = PEEK2(dev + 0x4);
253 b = PEEK2(dev + 0xa);
254 if(b > 0x10000 - a) {
255 b = 0x10000 - a;
256 }
257 res = file_stat(f, &uxn_ram[a], b);
258 POKE2(dev + 0x2, res);
259 } break;
260 case 0x6: {
261 // TODO: no file deletion for now
262 // res = file_delete();
263 // POKE2(dev + 0x2, res);
264 } break;
265 case 0x9: {
266 a = PEEK2(dev + 0x8);
267 res = file_init(f, &uxn_ram[a]);
268 POKE2(dev + 0x2, res);
269 } break;
270 case 0xd: {
271 a = PEEK2(dev + 0xc);
272 b = PEEK2(dev + 0xa);
273 if(b > 0x10000 - a) {
274 b = 0x10000 - a;
275 }
276 res = file_read(f, &uxn_ram[a], b);
277 POKE2(dev + 0x2, res);
278 } break;
279 case 0xf: {
280 a = PEEK2(dev + 0xe);
281 b = PEEK2(dev + 0xa);
282 if(b > 0x10000 - a) {
283 b = 0x10000 - a;
284 }
285 res = file_write(f, &uxn_ram[a], b, dev[0x7]);
286 POKE2(dev + 0x2, res);
287 } break;
288 }
289}
290
291void
292deo_stub(u8 *dev, u8 port) {
293 (void)dev;
294 (void)port;
295}
296
297u16
298dei_stub(u8 *dev, u8 port) {
299 if (port == 0) {
300 return PEEK2(dev);
301 }
302 return dev[port];
303}