master
uxn.c
1#if 0
2gcc -s -O2 -Wno-unused-result -fwrapv main.c `sdl-config --cflags --libs`
3exit
4#endif
5
6// This file is public domain.
7
8#include "SDL/SDL.h"
9#include <dirent.h>
10#include <fcntl.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14#include <sys/stat.h>
15#include <sys/types.h>
16#include <time.h>
17#include <unistd.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21#include <sys/types.h>
22
23static ssize_t getline(char **line, size_t *cap, FILE *fp)
24{
25 if (!line || !cap || !fp)
26 return -1;
27
28 size_t len = 0;
29 int c;
30
31 if (*line == NULL || *cap == 0) {
32 *cap = 128;
33 *line = malloc(*cap);
34 if (!*line) {
35 *cap = 0;
36 return -1;
37 }
38 }
39
40 while ((c = fgetc(fp)) != EOF) {
41 if (len + 1 >= *cap) {
42 size_t newcap = *cap * 2;
43 char *tmp = realloc(*line, newcap);
44 if (!tmp)
45 return -1;
46 *line = tmp;
47 *cap = newcap;
48 }
49
50 (*line)[len++] = (char)c;
51
52 if (c == '\n')
53 break;
54 }
55
56 if (len == 0 && c == EOF)
57 return -1;
58
59 (*line)[len] = '\0';
60 return (ssize_t)len;
61}
62
63void warn(const char *fmt, ...)
64{
65 va_list args;
66 va_start(args, fmt);
67
68 vprintf(fmt, args);
69 printf("\n");
70
71 va_end(args);
72}
73
74static void err(int e, char* str){
75 show_msgbox("Error", str);
76 exit(e);
77}
78
79static const Uint8 fontdata[]={ // font for built-in menus
80 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x78,0x78,0x30,0x30,0x00,0x30,0x00,
81 0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00,0x6C,0x6C,0xFE,0x6C,0xFE,0x6C,0x6C,0x00,
82 0x30,0x7C,0xC0,0x78,0x0C,0xF8,0x30,0x00,0x00,0xC6,0xCC,0x18,0x30,0x66,0xC6,0x00,
83 0x38,0x6C,0x38,0x76,0xDC,0xCC,0x76,0x00,0x60,0x60,0xC0,0x00,0x00,0x00,0x00,0x00,
84 0x18,0x30,0x60,0x60,0x60,0x30,0x18,0x00,0x60,0x30,0x18,0x18,0x18,0x30,0x60,0x00,
85 0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00,0x00,0x30,0x30,0xFC,0x30,0x30,0x00,0x00,
86 0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x60,0x00,0x00,0x00,0xFC,0x00,0x00,0x00,0x00,
87 0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x00,
88 0x7C,0xC6,0xCE,0xDE,0xF6,0xE6,0x7C,0x00,0x30,0x70,0x30,0x30,0x30,0x30,0xFC,0x00,
89 0x78,0xCC,0x0C,0x38,0x60,0xCC,0xFC,0x00,0x78,0xCC,0x0C,0x38,0x0C,0xCC,0x78,0x00,
90 0x1C,0x3C,0x6C,0xCC,0xFE,0x0C,0x1E,0x00,0xFC,0xC0,0xF8,0x0C,0x0C,0xCC,0x78,0x00,
91 0x38,0x60,0xC0,0xF8,0xCC,0xCC,0x78,0x00,0xFC,0xCC,0x0C,0x18,0x30,0x30,0x30,0x00,
92 0x78,0xCC,0xCC,0x78,0xCC,0xCC,0x78,0x00,0x78,0xCC,0xCC,0x7C,0x0C,0x18,0x70,0x00,
93 0x00,0x30,0x30,0x00,0x00,0x30,0x30,0x00,0x00,0x30,0x30,0x00,0x00,0x30,0x30,0x60,
94 0x18,0x30,0x60,0xC0,0x60,0x30,0x18,0x00,0x00,0x00,0xFC,0x00,0x00,0xFC,0x00,0x00,
95 0x60,0x30,0x18,0x0C,0x18,0x30,0x60,0x00,0x78,0xCC,0x0C,0x18,0x30,0x00,0x30,0x00,
96 0x7C,0xC6,0xDE,0xDE,0xDE,0xC0,0x78,0x00,0x30,0x78,0xCC,0xCC,0xFC,0xCC,0xCC,0x00,
97 0xFC,0x66,0x66,0x7C,0x66,0x66,0xFC,0x00,0x3C,0x66,0xC0,0xC0,0xC0,0x66,0x3C,0x00,
98 0xF8,0x6C,0x66,0x66,0x66,0x6C,0xF8,0x00,0xFE,0x62,0x68,0x78,0x68,0x62,0xFE,0x00,
99 0xFE,0x62,0x68,0x78,0x68,0x60,0xF0,0x00,0x3C,0x66,0xC0,0xC0,0xCE,0x66,0x3E,0x00,
100 0xCC,0xCC,0xCC,0xFC,0xCC,0xCC,0xCC,0x00,0x78,0x30,0x30,0x30,0x30,0x30,0x78,0x00,
101 0x1E,0x0C,0x0C,0x0C,0xCC,0xCC,0x78,0x00,0xE6,0x66,0x6C,0x78,0x6C,0x66,0xE6,0x00,
102 0xF0,0x60,0x60,0x60,0x62,0x66,0xFE,0x00,0xC6,0xEE,0xFE,0xFE,0xD6,0xC6,0xC6,0x00,
103 0xC6,0xE6,0xF6,0xDE,0xCE,0xC6,0xC6,0x00,0x38,0x6C,0xC6,0xC6,0xC6,0x6C,0x38,0x00,
104 0xFC,0x66,0x66,0x7C,0x60,0x60,0xF0,0x00,0x78,0xCC,0xCC,0xCC,0xDC,0x78,0x1C,0x00,
105 0xFC,0x66,0x66,0x7C,0x6C,0x66,0xE6,0x00,0x78,0xCC,0xE0,0x70,0x1C,0xCC,0x78,0x00,
106 0xFC,0xB4,0x30,0x30,0x30,0x30,0x78,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xFC,0x00,
107 0xCC,0xCC,0xCC,0xCC,0xCC,0x78,0x30,0x00,0xC6,0xC6,0xC6,0xD6,0xFE,0xEE,0xC6,0x00,
108 0xC6,0xC6,0x6C,0x38,0x38,0x6C,0xC6,0x00,0xCC,0xCC,0xCC,0x78,0x30,0x30,0x78,0x00,
109 0xFE,0xC6,0x8C,0x18,0x32,0x66,0xFE,0x00,0x78,0x60,0x60,0x60,0x60,0x60,0x78,0x00,
110 0xC0,0x60,0x30,0x18,0x0C,0x06,0x02,0x00,0x78,0x18,0x18,0x18,0x18,0x18,0x78,0x00,
111 0x10,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,
112 0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x0C,0x7C,0xCC,0x76,0x00,
113 0xE0,0x60,0x60,0x7C,0x66,0x66,0xDC,0x00,0x00,0x00,0x78,0xCC,0xC0,0xCC,0x78,0x00,
114 0x1C,0x0C,0x0C,0x7C,0xCC,0xCC,0x76,0x00,0x00,0x00,0x78,0xCC,0xFC,0xC0,0x78,0x00,
115 0x38,0x6C,0x60,0xF0,0x60,0x60,0xF0,0x00,0x00,0x00,0x76,0xCC,0xCC,0x7C,0x0C,0xF8,
116 0xE0,0x60,0x6C,0x76,0x66,0x66,0xE6,0x00,0x30,0x00,0x70,0x30,0x30,0x30,0x78,0x00,
117 0x0C,0x00,0x0C,0x0C,0x0C,0xCC,0xCC,0x78,0xE0,0x60,0x66,0x6C,0x78,0x6C,0xE6,0x00,
118 0x70,0x30,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0xCC,0xFE,0xFE,0xD6,0xC6,0x00,
119 0x00,0x00,0xF8,0xCC,0xCC,0xCC,0xCC,0x00,0x00,0x00,0x78,0xCC,0xCC,0xCC,0x78,0x00,
120 0x00,0x00,0xDC,0x66,0x66,0x7C,0x60,0xF0,0x00,0x00,0x76,0xCC,0xCC,0x7C,0x0C,0x1E,
121 0x00,0x00,0xDC,0x76,0x66,0x60,0xF0,0x00,0x00,0x00,0x7C,0xC0,0x78,0x0C,0xF8,0x00,
122 0x10,0x30,0x7C,0x30,0x30,0x34,0x18,0x00,0x00,0x00,0xCC,0xCC,0xCC,0xCC,0x76,0x00,
123 0x00,0x00,0xCC,0xCC,0xCC,0x78,0x30,0x00,0x00,0x00,0xC6,0xD6,0xFE,0xFE,0x6C,0x00,
124 0x00,0x00,0xC6,0x6C,0x38,0x6C,0xC6,0x00,0x00,0x00,0xCC,0xCC,0xCC,0x7C,0x0C,0xF8,
125 0x00,0x00,0xFC,0x98,0x30,0x64,0xFC,0x00,0x1C,0x30,0x30,0xE0,0x30,0x30,0x1C,0x00,
126 0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x00,0xE0,0x30,0x30,0x1C,0x30,0x30,0xE0,0x00,
127 0x76,0xDC,0x00,0x00,0x00,0x00,0x00,0x00,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,
128};
129
130#define EXPANDED_MEMORY 8
131#define MEMSIZE ((EXPANDED_MEMORY+1)*0x10000)
132
133#define GET16(p) (((p)[0]<<8)|(p)[1])
134#define PUT16(p,q) ((p)[0]=(q)>>8,(p)[1]=(q))
135
136typedef struct {
137 Uint8 p;
138 Uint8 d[256];
139} Stack;
140
141typedef struct Device {
142 Uint8 d[16];
143 Uint8(*in)(struct Device*,Uint8);
144 void(*out)(struct Device*,Uint8);
145 void(*exp)(struct Device*,Uint16);
146 void*aux;
147} Device;
148
149typedef struct {
150 FILE*file;
151 DIR*dir;
152 char name[4096];
153 struct dirent*de;
154 Uint8 mode;
155} UxnFile;
156
157typedef struct {
158 Uint8*data;
159 Uint32 addr;
160 Uint16 len;
161 Uint8 kind,stage;
162} Script;
163
164static SDL_Color colors[64]={
165 // 0
166 {0xFF,0xFF,0xFF,0},
167 {0x00,0x00,0x00,0},
168 {0x00,0xFF,0xFF,0},
169 {0xFF,0x00,0x00,0},
170 {0xAA,0xAA,0xAA,0},
171 {0x43,0x43,0x33,0},
172 {0x43,0xAA,0xAA,0},
173 {0xAA,0x43,0x33,0},
174 // 1
175 {0x00,0x00,0x00,0},
176 {0xFF,0xFF,0xFF,0},
177 {0x00,0xFF,0xFF,0},
178 {0xFF,0x00,0x00,0},
179 {0x43,0x43,0x33,0},
180 {0xAA,0xAA,0xAA,0},
181 {0x43,0xAA,0xAA,0},
182 {0xAA,0x43,0x33,0},
183 // 2
184 {0x10,0x30,0x10,0},
185 {0x60,0xE0,0x60,0},
186 {0x60,0x60,0xE0,0},
187 {0xE0,0x60,0x60,0},
188 {0x10,0x80,0x10,0},
189 {0x38,0xFF,0xF8,0},
190 {0xF8,0x38,0xFF,0},
191 {0xFF,0xF8,0x38,0},
192 // 3
193 {0x55,0x55,0x55,0},
194 {0xFF,0x55,0x00,0},
195 {0x00,0x00,0x00,0},
196 {0xFF,0xFF,0xFF,0},
197 {0x55,0x55,0x55,0},
198 {0xFF,0x55,0x00,0},
199 {0x00,0x00,0x00,0},
200 {0xFF,0xFF,0xFF,0},
201 // 4
202 {0x55,0x55,0x55,0},
203 {0xFF,0x55,0x00,0},
204 {0xFF,0xFF,0xFF,0},
205 {0x00,0x00,0x00,0},
206 {0x55,0x55,0x55,0},
207 {0xFF,0x55,0x00,0},
208 {0xFF,0xFF,0xFF,0},
209 {0x00,0x00,0x00,0},
210 // 5
211 {0xFF,0xFF,0xFF,0},
212 {0xAA,0xAA,0xAA,0},
213 {0x55,0x55,0x55,0},
214 {0x00,0x00,0x00,0},
215 {0xFF,0x80,0x00,0},
216 {0xC6,0x60,0x00,0},
217 {0x94,0x40,0x00,0},
218 {0x72,0x20,0x00,0},
219 // 6
220 {0xAA,0xAA,0xAA,0},
221 {0x00,0x00,0x00,0},
222 {0xAA,0xAA,0xAA,0},
223 {0x00,0x00,0x00,0},
224 {0x91,0xAA,0x9A,0},
225 {0x0D,0x0E,0x0E,0},
226 {0x91,0xAA,0x9A,0},
227 {0x19,0x15,0x00,0},
228 // 7
229 {0xFF,0xFF,0xFF,0},
230 {0x00,0x00,0x00,0},
231 {0x77,0xCC,0xAA,0},
232 {0x99,0x22,0x44,0},
233 {0xFF,0xFF,0xFF,0},
234 {0x00,0x00,0x00,0},
235 {0x77,0xCC,0xAA,0},
236 {0x99,0x22,0x44,0},
237};
238
239static Uint8 blend[4][16]={
240 {4,0,0,0,1,4,1,1,2,2,4,2,3,3,3,4},
241 {0,1,2,3,0,1,2,3,0,1,2,3,0,1,2,3},
242 {1,2,3,1,1,2,3,1,1,2,3,1,1,2,3,1},
243 {2,3,1,2,2,3,1,2,2,3,1,2,2,3,1,2},
244};
245
246static const Uint32 notes[12]={
247 0x20000000,0x21e71f26,0x23eb3588,0x260dfc14,0x285145f3,0x2ab70212,
248 0x2d413ccd,0x2ff221af,0x32cbfd4a,0x35d13f33,0x39047c0f,0x3c686fce,
249};
250
251static Uint8 mem[MEMSIZE];
252static Stack ds,rs;
253static Device device[16];
254static Uint16 scr_w,scr_h;
255static Uint8*bglayer;
256static Uint8*fglayer;
257static UxnFile uxnfile0;
258static UxnFile uxnfile1;
259static FILE*inf;
260static FILE*outf;
261
262static const char*rom_name;
263static Uint8 use_console=0;
264static Uint8 use_screen=1;
265static Uint8 use_mouse=0;
266static Uint8 use_debug=0;
267static Uint8 use_utc=0;
268static Uint8 use_extension=1;
269static Uint8 use_thread=0;
270static Uint8 hide_cursor=0;
271static Uint8 allow_write=0;
272static Uint8 joypad_repeat=0;
273static Uint16 scroll_size=1;
274static Uint8 zoom=1;
275static Uint8 disallow_size_change=1; /* fixed 320x240 res */
276static Sint16 default_width=320;
277static Sint16 default_height=240;
278static Uint32 scrflags=SDL_SWSURFACE;
279static Uint16 timer_rate=16;
280static Uint8 paused=0;
281static Uint8 picture_changed=0;
282static Uint8 size_changed=0;
283static volatile Uint8 timer_expired=0;
284static SDL_Surface*screen;
285static Uint8 layers=0;
286static Uint8 palet=7;
287static Uint8 touch_mode=0;
288static Uint8 screencompat=0x03;
289
290static Uint16 scriptc;
291static Script*scriptv;
292static FILE*scriptf;
293
294static Uint8 joy_mask;
295static Uint8 joy_player[4];
296static Uint8 joy_hat,joy_hat_mode;
297static Uint8 joy_axis_x,joy_axis_y,joy_axis_mode;
298static Uint8 joy_button_map[128];
299static Uint16 joy_sensitivity=8192;
300
301static Uint8 debugger=0;
302static Uint16 breakpoint=0;
303static Uint16 break_pc=0x0100;
304static Uint32 last_tick = 0;
305static Uint8 debug_op=0;
306static const touchpad_info_t *tpinfo=NULL;
307
308static void debug(int i) {
309 int j;
310 if(i) fprintf(stderr,"Debug(%02X)\n",i);
311 fprintf(stderr,"ds:");
312 for(i=0;i<ds.p;i++) fprintf(stderr," %02X",ds.d[i]);
313 fputc('\n',stderr);
314 fprintf(stderr,"rs:");
315 for(i=0;i<rs.p;i++) fprintf(stderr," %02X",rs.d[i]);
316 fputc('\n',stderr);
317 fprintf(stderr," 0. 1. 2. 3. 4. 5. 6. 7. 8. 9. A. B. C. D. E. F.\n");
318 for(i=0;i<16;i++) {
319 fprintf(stderr,"%1X:",i);
320 for(j=0;j<16;j++) fprintf(stderr," %02X",device[i].d[j]);
321 if(device[i].aux) fprintf(stderr," *");
322 fputc('\n',stderr);
323 }
324}
325
326static void uxnerr(int n,int pc) {
327 if(use_debug) debug(-1);
328 fflush(outf);
329 fflush(stderr);
330 err(2,"Uxn error");
331}
332
333#define Push8(z) ({ s->d[s->p++]=(z); })
334#define Push16(z) ({ s->d[s->p++]=(z)>>8; s->d[s->p++]=(z); })
335#define Push(z) ({ if(v&0x20) s->d[s->p++]=(z)>>8; s->d[s->p++]=(z); })
336#define Pop8(z) ({ z=s->d[0xFF&--k]; if(v<0x80) s->p=k; })
337#define Pop16(z) ({ z=s->d[0xFF&--k]; z|=s->d[0xFF&--k]<<8; if(v<0x80) s->p=k; })
338#define Pop(z) ({ if(v&0x20) Pop16(z); else Pop8(z); })
339
340static void run(Uint16 pc) {
341 Stack*s;
342 Uint8 k,v;
343 Uint16 x,y,z;
344 if(!pc) return;
345 start:
346 while(v=mem[pc++]) {
347 if(pc==breakpoint && use_screen) goto stop;
348 s=(v&0x40?&rs:&ds);
349 k=s->p;
350 switch(v&0x1F?:v) {
351 case 0x01: Pop(x); Push(x+1); break;
352 case 0x02: Pop(x); break;
353 case 0x03: Pop(x); Pop(y); Push(x); break;
354 case 0x04: Pop(x); Pop(y); Push(x); Push(y); break;
355 case 0x05: Pop(z); Pop(y); Pop(x); Push(y); Push(z); Push(x); break;
356 case 0x06: Pop(x); Push(x); Push(x); break;
357 case 0x07: Pop(x); Pop(y); Push(y); Push(x); Push(y); break;
358 case 0x08: Pop(x); Pop(y); Push8(y==x?1:0); break;
359 case 0x09: Pop(x); Pop(y); Push8(y!=x?1:0); break;
360 case 0x0A: Pop(x); Pop(y); Push8(y>x?1:0); break;
361 case 0x0B: Pop(x); Pop(y); Push8(y<x?1:0); break;
362 case 0x0C: Pop(x); jump: if(v&0x20) pc=x; else pc+=(Sint8)x; break;
363 case 0x0D: Pop(x); Pop8(y); if(y) goto jump; break;
364 case 0x0E: Pop(x); y=pc; goto stash;
365 case 0x0F: Pop(x); goto stash;
366 case 0x10: Pop8(x); peek: if(v&0x20) x=GET16(mem+x); else x=mem[x]; Push(x); break;
367 case 0x11: Pop8(x); Pop(y); poke: if(v&0x20) PUT16(mem+x,y); else mem[x]=y; break;
368 case 0x12: Pop8(x); x=pc+(Sint8)x; goto peek; break;
369 case 0x13: Pop8(x); Pop(y); x=pc+(Sint8)x; goto poke; break;
370 case 0x14: Pop16(x); goto peek; break;
371 case 0x15: Pop16(x); Pop(y); goto poke; break;
372 case 0x16:
373 Pop8(x);
374 z=(x>>4)&15; x&=15;
375 y=device[z].in(device+z,x);
376 if(v&0x20) y=(y<<8)|device[z].in(device+z,x+1);
377 Push(y);
378 break;
379 case 0x17:
380 Pop8(x); Pop(y);
381 z=(x>>4)&15; x&=15;
382 if(v&0x20) {
383 device[z].d[x]=y>>8;
384 device[z].d[(x+1)&15]=y;
385 device[z].out(device+z,x);
386 device[z].out(device+z,x+1);
387 } else {
388 device[z].d[x]=y;
389 device[z].out(device+z,x);
390 }
391 break;
392 case 0x18: Pop(x); Pop(y); Push(y+x); break;
393 case 0x19: Pop(x); Pop(y); Push(y-x); break;
394 case 0x1A: Pop(x); Pop(y); Push(y*x); break;
395 case 0x1B: Pop(x); Pop(y); Push(x?y/x:0); break;
396 case 0x1C: Pop(x); Pop(y); Push(y&x); break;
397 case 0x1D: Pop(x); Pop(y); Push(y|x); break;
398 case 0x1E: Pop(x); Pop(y); Push(y^x); break;
399 case 0x1F: Pop8(x); Pop(y); z=x>>4; x&=15; Push((y>>x)<<z); break;
400 case 0x20: Pop8(x); pc+=x?GET16(mem+pc)+2:2; break;
401 case 0x40: pc+=GET16(mem+pc)+2; break;
402 case 0x60: Push16(pc+2); pc+=GET16(mem+pc)+2; break;
403 case 0x80: case 0xC0: Push8(mem[pc++]); break;
404 case 0xA0: case 0xE0: Push8(mem[pc++]); Push8(mem[pc++]); break;
405 }
406 continue;
407 stash:
408 s=(v&0x40?&ds:&rs);
409 if(v&1) {
410 Push(x);
411 } else {
412 Push16(y);
413 if(v&0x20) pc=x; else pc+=(Sint8)x;
414 }
415 }
416 if(pc==breakpoint && use_screen) {
417 stop:
418 paused=debugger=picture_changed=1;
419 break_pc=pc-1;
420 }
421 fflush(outf);
422}
423
424static void load_rom(void) {
425 FILE*fp=fopen(rom_name,"r");
426 if(!fp){
427 err(1, "Cannot load program file");
428 }
429 memset(mem,0,MEMSIZE);
430 fread(mem+0x0100,1,MEMSIZE-0x0100,fp);
431 if(ferror(fp)){
432 err(1, "Cannot load program file");
433 };
434 fclose(fp);
435}
436
437static Uint8 default_in(Device*misc1,Uint8 misc2) { return misc1->d[misc2&15]; }
438static void default_out(Device*misc1,Uint8 misc2) {}
439static void default_exp(Device*misc1,Uint16 misc2) {}
440
441static Uint8 system_in(Device*dev,Uint8 id) {
442 switch(id) {
443 case 4: return ds.p;
444 case 5: return rs.p;
445 default: return dev->d[id];
446 }
447}
448
449static void system_out(Device*dev,Uint8 id) {
450 Uint16 x;
451 switch(id) {
452 case 3:
453 x=GET16(dev->d+2);
454 device[mem[x]>>4].exp(device+(mem[x]>>4),x);
455 break;
456 case 4:
457 ds.p=dev->d[4];
458 break;
459 case 5:
460 rs.p=dev->d[5];
461 break;
462 case 8 ... 13:
463 colors[070].r=colors[074].r=(dev->d[8]>>4)*0x11;
464 colors[071].r=colors[075].r=(dev->d[8]&15)*0x11;
465 colors[072].r=colors[076].r=(dev->d[9]>>4)*0x11;
466 colors[073].r=colors[077].r=(dev->d[9]&15)*0x11;
467 colors[070].g=colors[074].g=(dev->d[10]>>4)*0x11;
468 colors[071].g=colors[075].g=(dev->d[10]&15)*0x11;
469 colors[072].g=colors[076].g=(dev->d[11]>>4)*0x11;
470 colors[073].g=colors[077].g=(dev->d[11]&15)*0x11;
471 colors[070].b=colors[074].b=(dev->d[12]>>4)*0x11;
472 colors[071].b=colors[075].b=(dev->d[12]&15)*0x11;
473 colors[072].b=colors[076].b=(dev->d[13]>>4)*0x11;
474 colors[073].b=colors[077].b=(dev->d[13]&15)*0x11;
475 if(screen && palet==7) {
476 SDL_SetColors(screen,colors+palet*8,0,8);
477 picture_changed=1;
478 }
479 break;
480 case 14: if(dev->d[14] && use_debug) debug(dev->d[14]); break;
481 case 15: if(dev->d[15]) exit(dev->d[15]&0x7F); break;
482 }
483}
484
485// Subprocess support
486// End of subprocess support
487
488static void console_out(Device*dev,Uint8 id) {
489 switch(id) {
490 case 8: break;
491 case 9: break;
492 }
493}
494
495static Uint16 files_stat(int fd,char*name,Uint16 len,Uint8*out) {
496 struct stat st;
497 if(strlen(name)+7>len || stat(name,&st)) return 0;
498 if(S_ISDIR(st.st_mode)) return snprintf(out,len,"---- %s\n",name);
499 else if(st.st_size<0x10000) return snprintf(out,len,"%04x %s\n",(unsigned int)st.st_size,name);
500 else return snprintf(out,len,"???? %s\n",name);
501 return 0;
502}
503
504static Uint32 files_seek(UxnFile*uf,Uint8 mode,Uint32 len) {
505 switch(uf->mode) {
506 case 1: case 2: case 4:
507 switch(mode) {
508 case 0: fseek(uf->file,len,SEEK_SET); break;
509 case 1: fseek(uf->file,(Sint32)len,SEEK_CUR); break;
510 case 2: fseek(uf->file,(Sint32)len,SEEK_END); break;
511 case 3: return ftell(uf->file);
512 }
513 break;
514 case 3:
515 // if(!mode && !len) rewinddir(uf->dir);
516 uf->de=0;
517 break;
518 }
519 return 0;
520}
521
522static int files_set(Device*dev,int rw) {
523 // rw: 0(close) 1(read) 2(write) 3(both)
524 // return: 1 if file opened, 0 if not opened
525 Uint8 m=dev->d[7];
526 UxnFile*uf=dev->aux;
527 if(uf->file) fclose(uf->file);
528 if(uf->dir) closedir(uf->dir);
529 uf->file=0;
530 uf->dir=0;
531 uf->de=0;
532 uf->mode=0;
533 dev->d[2]=dev->d[3]=0;
534 if(!uf->name[0]) return 0;
535 if(rw==1) {
536 if(uf->dir=opendir(uf->name)) {
537 uf->mode=3;
538 return 1;
539 } else if(uf->file=fopen(uf->name,"r")) {
540 uf->mode=1;
541 return 1;
542 } else {
543 warn("Cannot open file '%s' for reading",uf->name);
544 }
545 } else if(rw==2 && allow_write) {
546 if(uf->file=fopen(uf->name,m?"a":"w")) {
547 uf->mode=2;
548 return 1;
549 } else {
550 warn("Cannot open file '%s' for writing",uf->name);
551 }
552 } else if(rw==3) {
553 if(allow_write && (uf->file=fopen(uf->name,"r+"))) {
554 uf->mode=4;
555 return 1;
556 } else if(uf->file=fopen(uf->name,"r")) {
557 uf->mode=1;
558 return 1;
559 } else {
560 warn("Cannot open file '%s' for reading/writing",uf->name);
561 }
562 }
563 return 0;
564}
565
566static void files_out(Device*dev,Uint8 id) {
567 UxnFile*uf=dev->aux;
568 Uint16 len=GET16(dev->d+10);
569 Uint16 addr,x,y;
570 int i;
571 switch(id) {
572 case 5:
573 addr=GET16(dev->d+4);
574 dev->d[2]=dev->d[3]=0;
575 if(!uf->name[0]) break;
576 y=files_stat(AT_FDCWD,uf->name,len,mem+addr);
577 if(y<=len) PUT16(dev->d+2,y);
578 break;
579 case 7:
580 if(use_extension) files_set(dev,0);
581 break;
582 case 9:
583 addr=GET16(dev->d+8);
584 files_set(dev,0);
585 x=GET16(dev->d+8);
586 for(i=0;i<4095;i++) {
587 if(!(uf->name[i]=mem[x+i])) break;
588 // if(mem[x+i]=='/') uf->name[i]=0;
589 }
590 if(use_debug) fprintf(stderr,"! File: %s\n",uf->name);
591 break;
592 case 13:
593 addr=GET16(dev->d+12);
594 dev->d[2]=dev->d[3]=0;
595 read:
596 if(uf->mode==1 || uf->mode==4) {
597 if(!len) break;
598 x=fread(mem+addr,1,len,uf->file);
599 PUT16(dev->d+2,x);
600 if(ferror(uf->file)) {
601 warn("Error reading file '%s'",uf->name);
602 clearerr(uf->file);
603 }
604 } else if(uf->mode==3) {
605 do {
606 /*
607 if(uf->de) {
608 if(x=files_stat(dirfd(uf->dir),uf->de->d_name,len,mem+addr)) {
609 addr+=x;
610 len-=x;
611 } else {
612 break;
613 }
614 }*/
615 } while(uf->de=readdir(uf->dir));
616 PUT16(dev->d+2,addr-GET16(dev->d+12));
617 } else {
618 if(files_set(dev,1)) goto read;
619 }
620 break;
621 case 15:
622 addr=GET16(dev->d+14);
623 dev->d[2]=dev->d[3]=0;
624 if(!allow_write) {
625 disallow:
626 warn("Not allowed to write to file '%s'.",uf->name);
627 break;
628 }
629 write:
630 if(uf->mode==2 || uf->mode==4) {
631 if(!len) break;
632 x=fwrite(mem+addr,1,len,uf->file);
633 PUT16(dev->d+2,x);
634 if(ferror(uf->file)) {
635 warn("Error writing file '%s'",uf->name);
636 clearerr(uf->file);
637 }
638 } else {
639 if(files_set(dev,2)) goto write;
640 }
641 break;
642 }
643}
644
645static Uint8 files_in(Device*dev,Uint8 id) {
646 UxnFile*uf=dev->aux;
647 int c;
648 switch(id) {
649 case 12: case 13:
650 dev->d[2]=dev->d[3]=0;
651 read:
652 if(uf->mode==1 || uf->mode==4) {
653 c=fgetc(uf->file);
654 if(c==EOF) {
655 if(ferror(uf->file)) {
656 warn("Error reading file '%s'",uf->name);
657 clearerr(uf->file);
658 }
659 c=0;
660 } else {
661 dev->d[3]=1;
662 }
663 return c;
664 } else if(uf->mode==3) {
665 return 0;
666 } else {
667 if(files_set(dev,1)) goto read;
668 }
669 return 0;
670 default: return dev->d[id];
671 }
672}
673
674static void files_exp(Device*dev,Uint16 addr) {
675 UxnFile*uf=dev->aux;
676 Uint32 x;
677 if(use_extension) switch(mem[addr]&15) {
678 case 0 ... 2:
679 x=GET16(mem+addr+1)<<16;
680 x|=GET16(mem+addr+3);
681 if(!uf->mode) files_set(dev,3);
682 files_seek(uf,mem[addr]&15,x);
683 break;
684 case 3:
685 x=files_seek(uf,3,0);
686 PUT16(mem+addr+1,x>>16);
687 PUT16(mem+addr+3,x);
688 break;
689 }
690}
691
692static Uint8 datetime_in(Device*dev,Uint8 id) {
693 time_t t=time(0);
694 struct tm r;
695 if(use_utc) gmtime_r(&t,&r); else localtime_r(&t,&r);
696 switch(id) {
697 case 0: return (r.tm_year+1900)>>8;
698 case 1: return r.tm_year+1900;
699 case 2: return r.tm_mon;
700 case 3: return r.tm_mday;
701 case 4: return r.tm_hour;
702 case 5: return r.tm_min;
703 case 6: return r.tm_sec;
704 case 7: return r.tm_wday;
705 case 8: return r.tm_yday>>8;
706 case 9: return r.tm_yday;
707 case 10: return r.tm_isdst;
708 default: return dev->d[id];
709 }
710}
711
712/*
713static Uint8 random_in(Device*dev,Uint8 id) {
714 Uint8 x[1];
715 if(read(randomfd,x,1)!=1) err(1,"Cannot read random numbers");
716 return *x;
717 }*/
718
719static Uint8 random_in(Device *dev, Uint8 id)
720{
721 (void)dev; (void)id;
722 return (Uint8)(rand() & 0xFF);
723}
724
725static void set_cursor(void) {
726 if(hide_cursor) SDL_ShowCursor(paused || !use_mouse);
727}
728
729static void set_screen_mode(int w,int h) {
730 picture_changed=size_changed=0;
731 free(bglayer);
732 if(screen) SDL_FreeSurface(screen);
733 w=320; h=240;
734 scr_w=w;
735 scr_h=h;
736
737 screen=SDL_SetVideoMode(w*zoom,h*zoom,8,SDL_SWSURFACE);
738 if(!screen) { err(1, "Cannot set screen mode"); }
739 SDL_SetColors(screen,colors+palet*8,0,8);
740 bglayer=calloc(w*h,2);
741 if(!bglayer) { err(1, "Memory allocation error"); }
742 fglayer=bglayer+w*h;
743
744 PUT16(device[2].d + 2, scr_w);
745 PUT16(device[2].d + 4, scr_h);
746}
747
748static void screen_fill(Uint8*p,Uint8 v,Uint16 x0,Uint16 y0,Uint16 x1,Uint16 y1) {
749 if(y1>scr_h) y1=scr_h;
750 if(x1>scr_w) x1=scr_w;
751 if(y0>=y1 || x0>=x1) return;
752 p+=y0*scr_w+x0;
753 x1-=x0;
754 while(y0++<y1) memset(p,v,x1),p+=scr_w;
755}
756
757static void draw_sprite(Uint16 x,Uint16 y,Uint16 addr,Uint8 v) {
758 Uint8 b=v&0x80;
759 Uint8 u;
760 Uint16 c;
761 Uint8*p=v&0x40?fglayer:bglayer;
762 Uint8*m;
763 if(x+8>scr_w || y+8>scr_h || addr>0x10000-(b?16:8)) return;
764 p+=y*scr_w+x;
765 m=mem+addr;
766 for(y=0;y<8;y++) {
767 c=m[y]|(b?m[y+8]<<8:0);
768 for(x=0;x<8;x++) {
769 u=(c&1)|((c>>7)&2);
770 c>>=1;
771 if((u=blend[u][v&0x0F])!=4) p[(y^(v&0x20?7:0))*scr_w+(x^(v&0x10?0:7))]=u;
772 }
773 }
774}
775
776static void screen_out(Device*dev,Uint8 id) {
777 int i,fx,fy;
778 Uint16 w;
779 Uint16 x=GET16(dev->d+8);
780 Uint16 y=GET16(dev->d+10);
781 Uint8 z=dev->d[id];
782 if(id<6 && disallow_size_change) {
783 PUT16(dev->d+2,scr_w);
784 PUT16(dev->d+4,scr_h);
785 return;
786 }
787 switch(id) {
788 case 2: case 3:
789 x=GET16(dev->d+2);
790 if(x!=scr_w) scr_w=x,size_changed=1;
791 break;
792 case 4: case 5:
793 x=GET16(dev->d+4);
794 if(x!=scr_h) scr_h=x,size_changed=1;
795 break;
796 case 14:
797 if(size_changed) set_screen_mode(scr_w,scr_h);
798 picture_changed=1;
799 if(z<0x80) {
800 if(x<scr_w && y<scr_h) (z&0x40?fglayer:bglayer)[x+y*scr_w]=z&3;
801 if(dev->d[6]&0x01) PUT16(dev->d+8,x+1);
802 if(dev->d[6]&0x02) PUT16(dev->d+10,y+1);
803 } else {
804 screen_fill(z&0x40?fglayer:bglayer,z&3,dev->d[14]&0x10?0:x,dev->d[14]&0x20?0:y,dev->d[14]&0x10?x:scr_w,dev->d[14]&0x20?y:scr_h);
805 }
806 break;
807 case 15:
808 if(size_changed) set_screen_mode(scr_w,scr_h);
809 picture_changed=1;
810 w=GET16(dev->d+12);
811 fx=((z&0x10)&&(screencompat&0x02)?-8:8);
812 fy=((z&0x20)&&(screencompat&0x02)?-8:8);
813 for(i=0;i<=(dev->d[6]>>4);i++) {
814 draw_sprite(x+i*(dev->d[6]&0x02?fx:0),y+i*(dev->d[6]&0x01?fy:0),w,z);
815 if(dev->d[6]&0x04) w+=z&0x80?16:8;
816 }
817 if(dev->d[6]&0x01) PUT16(dev->d+8,x+fx);
818 if(dev->d[6]&0x02) PUT16(dev->d+10,y+fy);
819 if(dev->d[6]&0x04) PUT16(dev->d+12,w);
820 break;
821 }
822}
823
824static void system_exp(Device *dev, Uint16 addr)
825{
826 Uint32 src, dst;
827 Uint16 len, n;
828 switch (mem[addr]) {
829 case 0x00:
830 len = GET16(mem + addr + 1);
831 dst = (GET16(mem + addr + 3) << 16L) | GET16(mem + addr + 5);
832 if (dst < MEMSIZE && dst + len <= MEMSIZE)
833 memset(mem + dst, mem[addr + 7], len);
834 break;
835 case 0x01: case 0x02:
836 len = GET16(mem + addr + 1);
837 src = (GET16(mem + addr + 3) << 16L) | GET16(mem + addr + 5);
838 dst = (GET16(mem + addr + 7) << 16L) | GET16(mem + addr + 9);
839 if (dst < MEMSIZE && src + len <= MEMSIZE && dst + len <= MEMSIZE) {
840 if (mem[addr] == 0x01)
841 for (n = 0; n < len; n++) mem[dst + n] = mem[src + n];
842 else
843 for (n = len; n; n--) mem[dst + n - 1] = mem[src + n - 1];
844 }
845 break;
846 case 0x04:
847 if (use_extension) PUT16(mem + addr + 1, EXPANDED_MEMORY);
848 break;
849 }
850}
851
852static void debug_screen(Uint8*s,Uint8 k) {
853 static Sint8 page=0;
854 static Uint8 port=0;
855 static Uint8 din;
856 static Uint32 addr=0;
857 static Uint32 scrol=0;
858 static const char opname[]=
859 "?IPNSRDOENGLJJJSLSLSLSDDASMDAOES"
860 "?NOIWOUVQETTMCSTDTDTDTEEDUUINROF"
861 "?CPPPTPRUQHHPNRHZZRRAAIODBLVDART"
862 ;
863 char buf[81];
864 int i,j;
865 Stack*z;
866 FILE*f;
867 UxnFile*u;
868 if(s) {
869 memset(s,32,80*25);
870 show:
871 switch(page) {
872 case 0:
873 memcpy(s+80*0,buf,snprintf(buf,81,"* %s",rom_name));
874 memcpy(s+80*1,buf,snprintf(buf,81,"<c> Console: %s",use_console?"On":"Off"));
875 memcpy(s+80*2,buf,snprintf(buf,81,"<d> Debug: %s",use_debug?"On":"Off"));
876 memcpy(s+80*4,buf,snprintf(buf,81,"<F3> Mouse: %s",use_mouse?"On":"Off"));
877 memcpy(s+80*5,buf,snprintf(buf,81,"<F4> Layers: %s",layers?(layers==1?"fg":"bg"):"fg/bg"));
878 memcpy(s+80*6,buf,snprintf(buf,81,"<F6/F7> Palette: %d",palet));
879 memcpy(s+80*7,buf,snprintf(buf,81,"<F9> Restart"));
880 memcpy(s+80*8,buf,snprintf(buf,81,"<F10> Quit"));
881 memcpy(s+80*10,buf,snprintf(buf,81,"<PAUSE> Resume"));
882 memcpy(s+80*13,buf,snprintf(buf,81,"Pages: CTRL+"));
883 memcpy(s+80*14,buf,snprintf(buf,81," A:Stack B:Return C:Device D:Memory E:Files "));
884 memcpy(s+80*15,buf,snprintf(buf,81," F:Code G: N: O: P: "));
885 memcpy(s+80*16,buf,snprintf(buf,81," Q: R: S: T: U: "));
886 memcpy(s+80*17,buf,snprintf(buf,81," V: W: X: Y: Z:Main "));
887 break;
888 case 1: case 2:
889 if(page==1) z=&ds; else z=&rs;
890 memcpy(s,buf,snprintf(buf,81,"%s Stack (%02x)",page==1?"Data":"Return",z->p));
891 for(i=0;i<256;i++) memcpy(s+80*(i/16+1)+(i&15)*4,buf,snprintf(buf,81,"%c%02x%c",z->p==i?'[':' ',z->d[i],z->p==i?']':' '));
892 break;
893 case 3:
894 memcpy(s,buf,snprintf(buf,81,"-- -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -a -b -c -d -e -f"));
895 for(i=0;i<16;i++) memcpy(s+80*(i+1),buf,snprintf(buf,81,"%x0:",i));
896 for(i=0;i<256;i++) memcpy(s+80*(i/16+1)+(i&15)*4+4,buf,snprintf(buf,81,"%c%02x%c",port==i?'[':' ',device[i>>4].d[i&15],port==i?']':' '));
897 memcpy(s+80*17,buf,snprintf(buf,81,"<i> In=%02x <o> Out <x> Execute",din));
898 break;
899 case 4:
900 if(addr<0) addr=0;
901 if(addr>=MEMSIZE) addr=MEMSIZE-1;
902 if(scrol<0) scrol=0;
903 if(addr>=0x100 && scrol<addr-0xF0) scrol=(addr-0xF0)&~15;
904 if(scrol>addr) scrol=addr&~15;
905 memcpy(s,buf,snprintf(buf,81,"----- -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -a -b -c -d -e -f"));
906 for(i=0;i<16;i++) memcpy(s+80*(i+1),buf,snprintf(buf,81,"%05x:",i*16+scrol));
907 for(i=0;i<256;i++) if(i+scrol<MEMSIZE) memcpy(s+80*(i/16+1)+(i&15)*4+7,buf,snprintf(buf,81,"%c%02x%c",addr==i+scrol?'[':' ',mem[i+scrol],addr==i+scrol?']':' '));
908 memcpy(s+80*17,buf,snprintf(buf,81,"<x> Execute <s> Save"));
909 break;
910 case 5:
911 for(i=0;i<2;i++) {
912 u=i?&uxnfile1:&uxnfile0;
913 memcpy(s+80*(7*i+1),buf,snprintf(buf,81,"[File%d]",i));
914 memcpy(s+80*(7*i+2),buf,snprintf(buf,81," name=%s",u->name));
915 if(u->file) memcpy(s+80*(7*i+3),buf,snprintf(buf,81," File fd=%d offset=0x%lX",fileno(u->file),ftell(u->file)));
916 // if(u->dir) memcpy(s+80*(7*i+4),buf,snprintf(buf,81," Dir fd=%d offset=0x%lX",dirfd(u->dir),telldir(u->dir)));
917 memcpy(s+80*(7*i+5),buf,snprintf(buf,81," mode=0x%02X",u->mode));
918 memcpy(s+80*(7*i+6),buf,snprintf(buf,81," <%c> Close <%c> Rewind","cC"[i],"rR"[i]));
919 }
920 break;
921 case 6:
922 j=break_pc;
923 for(i=0;i<16 && j<0x10000;i++) {
924 memcpy(s+80*i,buf,snprintf(buf,81,"%04x: %c%c %c%c%c%c%c%c",j,breakpoint==j+1?'*':' ',i?' ':'>',
925 opname[mem[j]&0x1F],opname[(mem[j]&0x1F)+0x20],opname[(mem[j]&0x1F)+0x40]
926 ,mem[j]&0x20?'2':'_',mem[j]&0x40?'r':'_',mem[j]&0x80?'k':'_' ));
927 if(mem[j]==0x80 || mem[j]==0xC0) {
928 memcpy(s+80*i+9,buf,snprintf(buf,81,"LIT_%c %02x",mem[j]&0x40?'r':'_',mem[j+1]));
929 j+=2;
930 } else if(mem[j]==0xA0 || mem[j]==0xE0) {
931 memcpy(s+80*i+9,buf,snprintf(buf,81,"LIT2%c %02x%02x",mem[j]&0x40?'r':'_',mem[j+1],mem[j+2]));
932 j+=3;
933 } else {
934 if(!mem[j]) memcpy(s+80*i+9,"BRK",3);
935 j++;
936 }
937 }
938 memcpy(s+80*17,buf,snprintf(buf,81,"ds:%02x rs:%02x",ds.p,rs.p));
939 memcpy(s+80*19,buf,snprintf(buf,81,"<SPACE> Step <RET> Continue <x> Execute"));
940 memcpy(s+80*20,buf,snprintf(buf,81,"<,> Set Breakpoint <.> Clear Breakpoint"));
941 break;
942 default:
943 if(page<0) page=6; else page=0;
944 goto show;
945 }
946 } else {
947 if(k==9 || k==']') {
948 ++page;
949 } else if(k=='[') {
950 --page;
951 } else if(k>=1 && k<=7) {
952 page=k;
953 } else if(k>=14 && k<=25) {
954 page=k-6;
955 } else if(k==26) {
956 page=0;
957 } else if(k==27) {
958 debugger=0;
959 return;
960 } else switch(page) {
961 case 0:
962 if(k=='c') use_console^=1;
963 if(k=='d') use_debug^=1;
964 break;
965 case 1: case 2:
966 if(page==1) z=&ds; else z=&rs;
967 if(k==8) z->p--;
968 if(k==12) z->p++;
969 if(k==10) z->p+=16;
970 if(k==11) z->p-=16;
971 if(k>='0' && k<='9') z->d[z->p]=(z->d[z->p]<<4)+(k-'0');
972 if(k>='a' && k<='f') z->d[z->p]=(z->d[z->p]<<4)+(k+10-'a');
973 break;
974 case 3:
975 i=port;
976 if(k==8) port--;
977 if(k==12) port++;
978 if(k==10) port+=16;
979 if(k==11) port-=16;
980 if(k>='0' && k<='9') device[i>>4].d[i&15]=(device[i>>4].d[i&15]<<4)+(k-'0');
981 if(k>='a' && k<='f') device[i>>4].d[i&15]=(device[i>>4].d[i&15]<<4)+(k+10-'a');
982 if(k=='i') din=device[i>>4].in(device+(i>>4),i&15);
983 if(k=='o') device[i>>4].out(device+(i>>4),i&15);
984 if(k=='x') run(GET16(device[i>>4].d));
985 break;
986 case 4:
987 if(k==8) addr--;
988 if(k==12) addr++;
989 if(k==10) addr+=16;
990 if(k==11) addr-=16;
991 if(k==',') scrol-=0x10,addr-=0x10;
992 if(k=='.') scrol+=0x10,addr+=0x10;
993 if(k=='<') scrol-=0x100,addr-=0x100;
994 if(k=='>') scrol+=0x100,addr+=0x100;
995 if(k=='q') scrol-=0x1000,addr-=0x1000;
996 if(k=='w') scrol+=0x1000,addr+=0x1000;
997 if(k=='Q') scrol-=0x10000,addr-=0x10000;
998 if(k=='W') scrol+=0x10000,addr+=0x10000;
999 if(k=='=') scrol=addr=0;
1000 if(addr>=MEMSIZE+0x1000) scrol=addr=0;
1001 if(k>='0' && k<='9') mem[addr]=(mem[addr]<<4)+(k-'0');
1002 if(k>='a' && k<='f') mem[addr]=(mem[addr]<<4)+(k+10-'a');
1003 if(k=='x' && addr<0x10000) run(addr);
1004 if(k=='s') {
1005 f=fopen("_uxn_memory","w");
1006 if(f) {
1007 fwrite(mem,1,MEMSIZE,f);
1008 fprintf(stderr,"Saved 0x%X bytes to file _uxn_memory\n",(int)(MEMSIZE));
1009 fclose(f);
1010 } else {
1011 warn("Cannot open file _uxn_memory");
1012 }
1013 }
1014 break;
1015 case 5:
1016 if(k=='c') files_set(device+10,0);
1017 if(k=='C') files_set(device+11,0);
1018 if(k=='r') files_seek(&uxnfile0,0,0);
1019 if(k=='R') files_seek(&uxnfile1,0,0);
1020 break;
1021 case 6:
1022 if(k==8 || k==11) --break_pc;
1023 if(k==12 || k==10) ++break_pc;
1024 if(k>='0' && k<='9') break_pc=(break_pc<<4)+(k-'0');
1025 if(k>='a' && k<='f') break_pc=(break_pc<<4)+(k+10-'a');
1026 if(k==',') breakpoint=break_pc+1;
1027 if(k=='.') breakpoint=0;
1028 if(k=='x') run(break_pc);
1029 if(k==' ') {
1030 j=breakpoint;
1031 breakpoint=break_pc+2;
1032 i=mem[break_pc];
1033 if(i==0x80 || i==0xC0) {
1034 breakpoint=break_pc+3;
1035 } else if(i==0xA0 || i==0xE0) {
1036 breakpoint=break_pc+4;
1037 } else if((i&0x1F)==0x0C || (i&0x1F)==0x0D || (i&0x1F)==0x0E) {
1038 if((i&0x1F)==0x0D) {
1039 i&=0x60;
1040 if(i==0x00 && ds.p>1 && !ds.d[ds.p-2]) goto no_jump;
1041 if(i==0x20 && ds.p>2 && !ds.d[ds.p-3]) goto no_jump;
1042 if(i==0x40 && rs.p>1 && !rs.d[rs.p-2]) goto no_jump;
1043 if(i==0x60 && rs.p>2 && !rs.d[rs.p-3]) goto no_jump;
1044 }
1045 i&=0x60;
1046 if(i==0x00 && ds.p) breakpoint=break_pc+((Sint8)ds.d[ds.p-1])+2;
1047 else if(i==0x20 && ds.p>1) breakpoint=GET16(ds.d+ds.p-2)+1;
1048 else if(i==0x40 && rs.p) breakpoint=break_pc+((Sint8)rs.d[rs.p-1])+2;
1049 else if(i==0x60 && rs.p>1) breakpoint=GET16(rs.d+rs.p-2)+1;
1050 else goto no_run;
1051 } else if(i) {
1052 no_jump:
1053 breakpoint=break_pc+2;
1054 } else {
1055 goto no_run;
1056 }
1057 run(break_pc);
1058 no_run:
1059 breakpoint=j;
1060 break;
1061 }
1062 if(k==13) {
1063 paused=debugger=0;
1064 run(break_pc);
1065 return;
1066 }
1067 break;
1068 }
1069 }
1070}
1071
1072static void redraw(void) {
1073 static Uint8*s=0;
1074 int a,r,u,v,x,y;
1075 Uint8*p;
1076
1077 if(debugger) {
1078 if(!s) s=calloc(80,26);
1079 if(!s) err(1,"Allocation failed");
1080 debug_screen(s,0);
1081 }
1082 if(size_changed) set_screen_mode(scr_w,scr_h);
1083 picture_changed=0;
1084 SDL_LockSurface(screen);
1085 a=0;
1086 p=screen->pixels;
1087 r=screen->pitch;
1088
1089 /*
1090 if(debugger) {
1091 for(y=0;y<scr_h*zoom;y++) {
1092 for(x=0;x<scr_w*zoom;x++) {
1093 if(y>=25*8-7 || x>=80*8 || (v=s[(y/8)*80+x/8]-32)<=0) p[x]=0;
1094 else p[x]=(fontdata[v*8+(y&7)]>>(7&~x))&1;
1095 }
1096 p+=r;
1097 }
1098 if(scr_h*zoom>9) {
1099 p=screen->pixels+r*(scr_h*zoom-8);
1100 for(y=0;y<8;y++) {
1101 for(a=0;a<scr_w*zoom;a++) p[a]=(a>>4)&7;
1102 p+=r;
1103 }
1104 }
1105 } else */ if(layers) {
1106 for(y=0;y<scr_h;y++) {
1107 for(x=0;x<scr_w;x++) {
1108 u=(layers==1?fglayer:bglayer)[a];
1109 for(v=0;v<zoom;v++) memset(p+v*r+x*zoom,u,zoom);
1110 a++;
1111 }
1112 p+=r*zoom;
1113 }
1114 } else {
1115 for(y=0;y<scr_h;y++) {
1116 for(x=0;x<scr_w;x++) {
1117 u=fglayer[a]?fglayer[a]+4:bglayer[a];
1118 for(v=0;v<zoom;v++) memset(p+v*r+x*zoom,u,zoom);
1119 a++;
1120 }
1121 p+=r*zoom;
1122 }
1123 }
1124 SDL_UnlockSurface(screen);
1125 SDL_Flip(screen);
1126}
1127
1128static inline int select_joystick(Uint8 n) {
1129 if((joy_mask&1) && n==joy_player[0]) return 2;
1130 if((joy_mask&2) && n==joy_player[1]) return 5;
1131 if((joy_mask&4) && n==joy_player[2]) return 6;
1132 if((joy_mask&8) && n==joy_player[3]) return 7;
1133 return 0;
1134}
1135
1136static Sint16 last_x = -1, last_y = -1;
1137
1138#define SENSITIVITY 4
1139void update_mouse_from_touchpad(void) {
1140 if (!tpinfo) {
1141 tpinfo = touchpad_getinfo();
1142 if (!tpinfo) return;
1143 }
1144
1145 touchpad_report_t report;
1146 if (touchpad_scan(&report) != 0) return;
1147
1148 if (!report.contact) {
1149 device[9].d[6] = 0;
1150 last_x = -1; last_y = -1;
1151 return;
1152 }
1153
1154 if (last_x < 0) {
1155 last_x = report.x; last_y = report.y;
1156 return;
1157 }
1158
1159 /* relative delta */
1160 Sint16 dx = (Sint16)report.x - last_x;
1161 Sint16 dy = last_y - (Sint16)report.y;
1162 last_x = report.x;
1163 last_y = report.y;
1164 dx /= SENSITIVITY; /* higher divisor, higher sensitivity */
1165 dy /= SENSITIVITY;
1166
1167 Uint16 mx = (device[9].d[2] << 8) | device[9].d[3];
1168 Uint16 my = (device[9].d[4] << 8) | device[9].d[5];
1169
1170 /* apply delta to actual mouse coords */
1171 if (dx < 0 && mx < (Uint16)(-dx)) mx = 0;
1172 else mx += dx;
1173 if (dy < 0 && my < (Uint16)(-dy)) my = 0;
1174 else my += dy;
1175
1176 if (mx >= scr_w) mx = scr_w - 1;
1177 if (my >= scr_h) my = scr_h - 1;
1178
1179 device[9].d[2] = mx >> 8;
1180 device[9].d[3] = mx & 0xff;
1181 device[9].d[4] = my >> 8;
1182 device[9].d[5] = my & 0xff;
1183
1184 run(GET16(device[9].d));
1185}
1186
1187static int run_screen(void) {
1188 SDL_Event e;
1189 int i,j,k;
1190 last_tick = SDL_GetTicks();
1191
1192 while (1) {
1193 Uint32 now = SDL_GetTicks();
1194 if (now - last_tick >= timer_rate) {
1195 last_tick = now;
1196 if (!paused) run(GET16(device[2].d));
1197 }
1198
1199 while(SDL_PollEvent(&e)) {
1200 switch(e.type) {
1201 case SDL_QUIT: return 0;
1202 case SDL_VIDEOEXPOSE: redraw(); break;
1203 case SDL_KEYDOWN:
1204 i=0;
1205 switch(e.key.keysym.sym) {
1206 case SDLK_ESCAPE: return 0; break;
1207 case SDLK_7: case SDLK_LCTRL: case SDLK_END: i=0x01; break;
1208 case SDLK_9: case SDLK_LSHIFT: i=0x02; break;
1209 case SDLK_5: i=0x08; break;
1210 case SDLK_8: case SDLK_UP: i=0x10; break;
1211 case SDLK_2: case SDLK_DOWN: i=0x20; break;
1212 case SDLK_4: case SDLK_LEFT: i=0x40; break;
1213 case SDLK_6: case SDLK_RIGHT: i=0x80; break;
1214 case SDLK_PAGEUP: i=-scroll_size; goto scroll;
1215 case SDLK_PAGEDOWN: i=scroll_size; goto scroll;
1216 case SDLK_F1: run(GET16(device[2].d)); break;
1217 case SDLK_1: device[9].d[6] = 0x01; break;
1218 case SDLK_PERIOD: device[9].d[6] = 0x03; break;
1219 case SDLK_3: device[9].d[6] = 0x02; break;
1220 case SDLK_F3: use_mouse^=1; set_cursor(); picture_changed=debugger; break;
1221 case SDLK_F4: layers=(layers+1)%3; redraw(); break;
1222 case SDLK_F5: redraw(); if(SDL_GetModState()&KMOD_RSHIFT) debug(-1); break;
1223 case SDLK_F6: palet=(palet+1)&7; SDL_SetColors(screen,colors+palet*8,0,8); redraw(); break;
1224 case SDLK_F7: palet=(palet-1)&7; SDL_SetColors(screen,colors+palet*8,0,8); redraw(); break;
1225 case SDLK_F8: paused=picture_changed=debugger=1; break;
1226 case SDLK_F9: return 1;
1227 case SDLK_F10: return 0;
1228 case SDLK_PAUSE: debugger=0; paused^=1; set_cursor(); picture_changed=1; break;
1229 }
1230 if(i) {
1231 if(joypad_repeat || !(device[8].d[2]&i)) {
1232 device[8].d[2]|=i;
1233 run(GET16(device[8].d));
1234 }
1235 } else if(i=e.key.keysym.unicode) {
1236 device[8].d[3]=i;
1237 run(GET16(device[8].d));
1238 if(!debugger) device[8].d[3]=0; else debug_op=8;
1239 }
1240 break;
1241 scroll:
1242 if(paused || !i) break;
1243 PUT16(device[9].d+12,i);
1244 run(GET16(device[9].d));
1245 if(!debugger) PUT16(device[9].d+12,0); else debug_op=9;
1246 break;
1247 case SDL_KEYUP:
1248 if(paused) break;
1249 i=0;
1250 switch(e.key.keysym.sym) {
1251 case SDLK_7: case SDLK_LCTRL: case SDLK_END: i=0x01; break;
1252 case SDLK_9: case SDLK_LSHIFT: i=0x02; break;
1253 case SDLK_5: i=0x08; break;
1254 case SDLK_8: case SDLK_UP: i=0x10; break;
1255 case SDLK_2: case SDLK_DOWN: i=0x20; break;
1256 case SDLK_4: case SDLK_LEFT: i=0x40; break;
1257 case SDLK_6: case SDLK_RIGHT: i=0x80; break;
1258 case SDLK_PERIOD: case SDLK_3: case SDLK_1: device[9].d[6] = 0x00; break;
1259 }
1260 if(device[8].d[2]&i) {
1261 device[8].d[2]&=~i;
1262 run(GET16(device[8].d));
1263 }
1264 break;
1265 }
1266 }
1267 if(picture_changed) {
1268 redraw();
1269 picture_changed=0;
1270 }
1271 update_mouse_from_touchpad();
1272 SDL_Delay(1);
1273 }
1274 return 0;
1275}
1276
1277int main(int argc, char **argv)
1278{
1279 int i;
1280
1281 /* seed RNG */
1282 srand(SDL_GetTicks() ^ (unsigned)time(NULL));
1283
1284 /* initialise devices */
1285 for (i = 0; i < 16; i++) {
1286 device[i].in = default_in;
1287 device[i].out = default_out;
1288 device[i].exp = default_exp;
1289 }
1290 device[0].in = system_in;
1291 device[0].out = system_out;
1292 device[0].exp = system_exp;
1293 device[10].aux = &uxnfile0;
1294 device[11].aux = &uxnfile1;
1295 device[10].out = files_out;
1296 device[10].in = files_in;
1297 device[10].exp = files_exp;
1298 device[11].out = files_out;
1299 device[11].in = files_in;
1300 device[11].exp = files_exp;
1301 device[12].in = datetime_in;
1302
1303 /* optional random device on port 0xE */
1304 device[0xE].in = random_in;
1305
1306 if (use_console) device[1].out = console_out;
1307
1308 use_screen = 1;
1309 use_console = 0;
1310 use_mouse = 0;
1311 allow_write = 0;
1312 zoom = 1;
1313 disallow_size_change = 1;
1314 timer_rate = 16;
1315 scr_w = 320; scr_h = 240;
1316 tpinfo=touchpad_getinfo();
1317
1318 if (argc > 1) rom_name = argv[1];
1319
1320 load_rom();
1321
1322 if (use_screen) {
1323 if (SDL_Init(SDL_INIT_VIDEO) < 0)
1324 show_msgbox("SDL Error", "SDL_Init failed");
1325 atexit(SDL_Quit);
1326
1327 device[2].out = screen_out;
1328 PUT16(device[2].d + 2, scr_w);
1329 PUT16(device[2].d + 4, scr_h);
1330 size_changed = 1;
1331 set_screen_mode(scr_w, scr_h);
1332 }
1333
1334restart:
1335 size_changed = 1;
1336 ds.p = rs.p = 0;
1337 memset(device[1].d, 0, 16);
1338 run(0x0100);
1339
1340 if (use_screen) {
1341 while (run_screen()) {
1342 /* restart requested (F9) */
1343 for (i = 0; i < 15; i++)
1344 memset(device[i].d, 0, 16);
1345 load_rom();
1346 goto restart;
1347 }
1348 SDL_Quit();
1349 }
1350
1351 return 0;
1352}