... | ... |
@@ -16,6 +16,11 @@ typedef signed char Sint8; |
16 | 16 |
typedef unsigned short Uint16; |
17 | 17 |
typedef signed short Sint16; |
18 | 18 |
|
19 |
+typedef struct { |
|
20 |
+ char name[64], items[16][64]; |
|
21 |
+ Uint8 len; |
|
22 |
+} Macro; |
|
23 |
+ |
|
19 | 24 |
typedef struct { |
20 | 25 |
char name[64]; |
21 | 26 |
unsigned int size; |
... | ... |
@@ -29,9 +34,10 @@ typedef struct { |
29 | 34 |
} Label; |
30 | 35 |
|
31 | 36 |
typedef struct { |
32 |
- Uint8 data[256 * 256], llen; |
|
37 |
+ Uint8 data[256 * 256], llen, mlen; |
|
33 | 38 |
Uint16 ptr; |
34 | 39 |
Label labels[256]; |
40 |
+ Macro macros[256]; |
|
35 | 41 |
} Program; |
36 | 42 |
|
37 | 43 |
Program p; |
... | ... |
@@ -42,7 +48,7 @@ char ops[][4] = { |
42 | 48 |
"BRK", "NOP", "LIT", "LDR", "STR", "JMP", "JSR", "RTS", |
43 | 49 |
"EQU", "NEQ", "GTH", "LTH", "AND", "XOR", "ROL", "ROR", |
44 | 50 |
"POP", "DUP", "SWP", "OVR", "ROT", "---", "WSR", "RSW", |
45 |
- "ADD", "SUB", "MUL", "DIV", "---", "---", "---", "---" |
|
51 |
+ "ADD", "SUB", "MUL", "DIV", "---", "---", "---", "PRG" |
|
46 | 52 |
}; |
47 | 53 |
|
48 | 54 |
int scin(char *s, char c) { int i = 0; while(s[i]) if(s[i++] == c) return i - 1; return -1; } /* string char index */ |
... | ... |
@@ -82,6 +88,16 @@ pushtext(char *s, int lit) |
82 | 88 |
while((c = s[i++])) pushbyte(c, 0); |
83 | 89 |
} |
84 | 90 |
|
91 |
+Macro * |
|
92 |
+findmacro(char *name) |
|
93 |
+{ |
|
94 |
+ int i; |
|
95 |
+ for(i = 0; i < p.mlen; ++i) |
|
96 |
+ if(scmp(p.macros[i].name, name, 64)) |
|
97 |
+ return &p.macros[i]; |
|
98 |
+ return NULL; |
|
99 |
+} |
|
100 |
+ |
|
85 | 101 |
Label * |
86 | 102 |
findlabel(char *s) |
87 | 103 |
{ |
... | ... |
@@ -166,6 +182,28 @@ error(char *name, char *id) |
166 | 182 |
return 0; |
167 | 183 |
} |
168 | 184 |
|
185 |
+int |
|
186 |
+makemacro(char *name, FILE *f) |
|
187 |
+{ |
|
188 |
+ Macro *m; |
|
189 |
+ char word[64]; |
|
190 |
+ if(findmacro(name)) |
|
191 |
+ return error("Macro duplicate", name); |
|
192 |
+ if(sihx(name) && slen(name) % 2 == 0) |
|
193 |
+ return error("Macro name is hex number", name); |
|
194 |
+ if(findopcode(name)) |
|
195 |
+ return error("Macro name is invalid", name); |
|
196 |
+ m = &p.macros[p.mlen++]; |
|
197 |
+ scpy(name, m->name, 64); |
|
198 |
+ while(fscanf(f, "%s", word)) { |
|
199 |
+ if(word[0] == '{') continue; |
|
200 |
+ if(word[0] == '}') break; |
|
201 |
+ scpy(word, m->items[m->len++], 64); |
|
202 |
+ } |
|
203 |
+ printf("New macro: %s(%d items)\n", m->name, m->len); |
|
204 |
+ return 1; |
|
205 |
+} |
|
206 |
+ |
|
169 | 207 |
int |
170 | 208 |
makelabel(char *name, Uint16 addr) |
171 | 209 |
{ |
... | ... |
@@ -197,8 +235,7 @@ makevariable(char *name, Uint16 *addr, FILE *f) |
197 | 235 |
if(word[0] == '}') break; |
198 | 236 |
scpy(word, l->map[l->maps].name, 64); |
199 | 237 |
fscanf(f, "%u", &l->map[l->maps].size); |
200 |
- *addr += l->map[l->maps].size; |
|
201 |
- l->maps++; |
|
238 |
+ *addr += l->map[l->maps++].size; |
|
202 | 239 |
} |
203 | 240 |
return 1; |
204 | 241 |
} |
... | ... |
@@ -215,6 +252,119 @@ skipblock(char *w, int *cap, char a, char b) |
215 | 252 |
return 0; |
216 | 253 |
} |
217 | 254 |
|
255 |
+int |
|
256 |
+walktoken(char *w) |
|
257 |
+{ |
|
258 |
+ Macro *m; |
|
259 |
+ if((m = findmacro(w))) { |
|
260 |
+ int i, res = 0; |
|
261 |
+ for(i = 0; i < m->len; ++i) |
|
262 |
+ res += walktoken(m->items[i]); |
|
263 |
+ return res; |
|
264 |
+ } |
|
265 |
+ if(findopcode(w) || scmp(w, "BRK", 4)) |
|
266 |
+ return 1; |
|
267 |
+ switch(w[0]) { |
|
268 |
+ case '=': return 4; /* STR helper (lit addr-hb addr-lb str) */ |
|
269 |
+ case '~': return 4; /* LDR helper (lit addr-hb addr-lb ldr) */ |
|
270 |
+ case ',': return 3; /* lit2 addr-hb addr-lb */ |
|
271 |
+ case '.': return 2; /* addr-hb addr-lb */ |
|
272 |
+ case '^': return 2; /* Relative jump: lit addr-offset */ |
|
273 |
+ case '+': /* signed positive */ |
|
274 |
+ case '-': /* signed negative */ |
|
275 |
+ case '#': return (slen(w + 1) == 2 ? 2 : 3); |
|
276 |
+ } |
|
277 |
+ return error("Unknown label in first pass", w); |
|
278 |
+} |
|
279 |
+ |
|
280 |
+int |
|
281 |
+parsetoken(char *w) |
|
282 |
+{ |
|
283 |
+ Uint8 op = 0; |
|
284 |
+ Label *l; |
|
285 |
+ Macro *m; |
|
286 |
+ |
|
287 |
+ if(w[0] == '^' && (l = findlabel(w + 1))) { |
|
288 |
+ int off = l->addr - p.ptr - 3; |
|
289 |
+ if(off < -126 || off > 126) { |
|
290 |
+ printf("Address %s is too far(%d).\n", w, off); |
|
291 |
+ return 0; |
|
292 |
+ } |
|
293 |
+ pushbyte((Sint8)(l->addr - p.ptr - 3), 1); |
|
294 |
+ l->refs++; |
|
295 |
+ return 1; |
|
296 |
+ } |
|
297 |
+ if(w[0] == '=' && (l = findlabel(w + 1))) { |
|
298 |
+ if(!findlabellen(w + 1) || findlabellen(w + 1) > 2) |
|
299 |
+ return error("Invalid load helper", w); |
|
300 |
+ pushshort(findlabeladdr(w + 1), 1); |
|
301 |
+ pushbyte(findopcode(findlabellen(w + 1) == 2 ? "STR2" : "STR"), 0); |
|
302 |
+ l->refs++; |
|
303 |
+ return 1; |
|
304 |
+ } |
|
305 |
+ if(w[0] == '~' && (l = findlabel(w + 1))) { |
|
306 |
+ if(!findlabellen(w + 1) || findlabellen(w + 1) > 2) |
|
307 |
+ return error("Invalid load helper", w); |
|
308 |
+ pushshort(findlabeladdr(w + 1), 1); |
|
309 |
+ pushbyte(findopcode(findlabellen(w + 1) == 2 ? "LDR2" : "LDR"), 0); |
|
310 |
+ l->refs++; |
|
311 |
+ return 1; |
|
312 |
+ } |
|
313 |
+ if((op = findopcode(w)) || scmp(w, "BRK", 4)) { |
|
314 |
+ pushbyte(op, 0); |
|
315 |
+ return 1; |
|
316 |
+ } |
|
317 |
+ if(w[0] == '.' && (l = findlabel(w + 1))) { |
|
318 |
+ pushshort(findlabeladdr(w + 1), 0); |
|
319 |
+ l->refs++; |
|
320 |
+ return 1; |
|
321 |
+ } |
|
322 |
+ if(w[0] == ',' && (l = findlabel(w + 1))) { |
|
323 |
+ pushshort(findlabeladdr(w + 1), 1); |
|
324 |
+ l->refs++; |
|
325 |
+ return 1; |
|
326 |
+ } |
|
327 |
+ if(w[0] == '#' && sihx(w + 1)) { |
|
328 |
+ if(slen(w + 1) == 2) |
|
329 |
+ pushbyte(shex(w + 1), 1); |
|
330 |
+ else if(slen(w + 1) == 4) |
|
331 |
+ pushshort(shex(w + 1), 1); |
|
332 |
+ else |
|
333 |
+ return 0; |
|
334 |
+ return 1; |
|
335 |
+ } |
|
336 |
+ |
|
337 |
+ if(w[0] == '+' && sihx(w + 1)) { |
|
338 |
+ if(slen(w + 1) == 2) |
|
339 |
+ pushbyte((Sint8)shex(w + 1), 1); |
|
340 |
+ else if(slen(w + 1) == 4) |
|
341 |
+ pushshort((Sint16)shex(w + 1), 1); |
|
342 |
+ else |
|
343 |
+ return 0; |
|
344 |
+ } |
|
345 |
+ |
|
346 |
+ if(w[0] == '-' && sihx(w + 1)) { |
|
347 |
+ if(slen(w + 1) == 2) |
|
348 |
+ pushbyte((Sint8)(shex(w + 1) * -1), 1); |
|
349 |
+ else if(slen(w + 1) == 4) |
|
350 |
+ pushshort((Sint16)(shex(w + 1) * -1), 1); |
|
351 |
+ else |
|
352 |
+ return 0; |
|
353 |
+ return 1; |
|
354 |
+ } |
|
355 |
+ |
|
356 |
+ if((m = findmacro(w))) { |
|
357 |
+ int i, res = 0; |
|
358 |
+ for(i = 0; i < m->len; ++i) { |
|
359 |
+ if(!parsetoken(m->items[i])) |
|
360 |
+ return 0; |
|
361 |
+ } |
|
362 |
+ return 1; |
|
363 |
+ } |
|
364 |
+ |
|
365 |
+ return 0; |
|
366 |
+} |
|
367 |
+ |
|
218 | 368 |
int |
219 | 369 |
pass1(FILE *f) |
220 | 370 |
{ |
... | ... |
@@ -231,6 +381,10 @@ pass1(FILE *f) |
231 | 381 |
addr += slen(w) == 4 ? 2 : 1; |
232 | 382 |
else |
233 | 383 |
addr += slen(w); |
384 |
+ } else if(w[0] == '%') { |
|
385 |
+ if(!makemacro(w + 1, f)) |
|
386 |
+ return error("Pass1 failed", w); |
|
387 |
+ scpy(w + 1, scope, 64); |
|
234 | 388 |
} else if(w[0] == '@') { |
235 | 389 |
if(!makelabel(w + 1, addr)) |
236 | 390 |
return error("Pass1 failed", w); |
... | ... |
@@ -241,25 +395,12 @@ pass1(FILE *f) |
241 | 395 |
} else if(w[0] == ';') { |
242 | 396 |
if(!makevariable(w + 1, &addr, f)) |
243 | 397 |
return error("Pass1 failed", w); |
244 |
- } else if(findopcode(w) || scmp(w, "BRK", 4)) |
|
245 |
- addr += 1; |
|
246 |
- else { |
|
247 |
- switch(w[0]) { |
|
248 |
- case '|': |
|
249 |
- if(shex(w + 1) < addr) |
|
250 |
- return error("Memory Overlap", w); |
|
251 |
- addr = shex(w + 1); |
|
252 |
- break; |
|
253 |
- case '=': addr += 4; break; /* STR helper (lit addr-hb addr-lb str) */ |
|
254 |
- case '~': addr += 4; break; /* LDR helper (lit addr-hb addr-lb ldr) */ |
|
255 |
- case ',': addr += 3; break; |
|
256 |
- case '.': addr += 2; break; |
|
257 |
- case '^': addr += 2; break; /* Relative jump: lit addr-offset */ |
|
258 |
- case '+': /* signed positive */ |
|
259 |
- case '-': /* signed negative */ |
|
260 |
- case '#': addr += (slen(w + 1) == 2 ? 2 : 3); break; |
|
261 |
- default: return error("Unknown label in first pass", w); |
|
262 |
- } |
|
398 |
+ } else if(w[0] == '|') { |
|
399 |
+ if(shex(w + 1) < addr) |
|
400 |
+ return error("Memory Overwrite", w); |
|
401 |
+ addr = shex(w + 1); |
|
402 |
+ } else { |
|
403 |
+ addr += walktoken(w); |
|
263 | 404 |
} |
264 | 405 |
} |
265 | 406 |
rewind(f); |
... | ... |
@@ -273,52 +414,33 @@ pass2(FILE *f) |
273 | 414 |
char w[64], scope[64], subw[64]; |
274 | 415 |
printf("Pass 2\n"); |
275 | 416 |
while(fscanf(f, "%s", w) == 1) { |
276 |
- Uint8 op = 0; |
|
277 |
- Label *l; |
|
278 | 417 |
if(w[0] == ';') continue; |
279 | 418 |
if(w[0] == '$') continue; |
419 |
+ if(w[0] == '%') continue; |
|
280 | 420 |
if(skipblock(w, &ccmnt, '(', ')')) continue; |
281 | 421 |
if(skipblock(w, &ctemplate, '{', '}')) continue; |
422 |
+ if(w[0] == '|') { |
|
423 |
+ p.ptr = shex(w + 1); |
|
424 |
+ continue; |
|
425 |
+ } |
|
282 | 426 |
if(w[0] == '@') { |
283 | 427 |
scpy(w + 1, scope, 64); |
284 | 428 |
continue; |
285 | 429 |
} |
286 | 430 |
if(w[1] == '$') { |
287 |
- sublabel(subw, scope, w + 2); |
|
288 |
- scpy(subw, w + 1, 64); |
|
431 |
+ scpy(sublabel(subw, scope, w + 2), w + 1, 64); |
|
289 | 432 |
} |
290 |
- /* clang-format off */ |
|
291 | 433 |
if(skipblock(w, &cbits, '[', ']')) { |
292 | 434 |
if(w[0] == '[' || w[0] == ']') { continue; } |
293 |
- if(slen(w) == 4 && sihx(w)) pushshort(shex(w), 0); |
|
294 |
- else if(slen(w) == 2 && sihx(w)) pushbyte(shex(w), 0); |
|
295 |
- else pushtext(w, 0); |
|
296 |
- } |
|
297 |
- else if(w[0] == '^' && (l = findlabel(w + 1))) { |
|
298 |
- int off = l->addr - p.ptr - 3; |
|
299 |
- if(off < -126 || off > 126){ printf("Address %s is too far(%d).\n", w, off); return 0; } |
|
300 |
- pushbyte((Sint8)(l->addr - p.ptr - 3), 1); l->refs++; |
|
435 |
+ if(slen(w) == 4 && sihx(w)) |
|
436 |
+ pushshort(shex(w), 0); |
|
437 |
+ else if(slen(w) == 2 && sihx(w)) |
|
438 |
+ pushbyte(shex(w), 0); |
|
439 |
+ else |
|
440 |
+ pushtext(w, 0); |
|
441 |
+ } else if(!parsetoken(w)) { |
|
442 |
+ return error("Unknown label in second pass", w); |
|
301 | 443 |
} |
302 |
- else if(w[0] == '=' && (l = findlabel(w + 1))) { |
|
303 |
- if(!findlabellen(w + 1) || findlabellen(w + 1) > 2) |
|
304 |
- return error("Invalid load helper", w); |
|
305 |
- pushshort(findlabeladdr(w + 1), 1); pushbyte(findopcode(findlabellen(w + 1) == 2 ? "STR2" : "STR"), 0); l->refs++;} |
|
306 |
- else if(w[0] == '~' && (l = findlabel(w + 1))) { |
|
307 |
- if(!findlabellen(w + 1) || findlabellen(w + 1) > 2) |
|
308 |
- return error("Invalid load helper", w); |
|
309 |
- pushshort(findlabeladdr(w + 1), 1); pushbyte(findopcode(findlabellen(w + 1) == 2 ? "LDR2" : "LDR"), 0); l->refs++;} |
|
310 |
- else if(w[0] == '|') p.ptr = shex(w + 1); |
|
311 |
- else if((op = findopcode(w)) || scmp(w, "BRK", 4)) pushbyte(op, 0); |
|
312 |
- else if(w[0] == '.' && (l = findlabel(w + 1))) { pushshort(findlabeladdr(w + 1), 0); l->refs++; } |
|
313 |
- else if(w[0] == ',' && (l = findlabel(w + 1))) { pushshort(findlabeladdr(w + 1), 1); l->refs++; } |
|
314 |
- else if(w[0] == '#' && sihx(w + 1) && slen(w + 1) == 2) pushbyte(shex(w + 1), 1); |
|
315 |
- else if(w[0] == '#' && sihx(w + 1) && slen(w + 1) == 4) pushshort(shex(w + 1), 1); |
|
316 |
- else if(w[0] == '+' && sihx(w + 1) && slen(w + 1) == 2) pushbyte((Sint8)shex(w + 1), 1); |
|
317 |
- else if(w[0] == '+' && sihx(w + 1) && slen(w + 1) == 4) pushshort((Sint16)shex(w + 1), 1); |
|
318 |
- else if(w[0] == '-' && sihx(w + 1) && slen(w + 1) == 2) pushbyte((Sint8)(shex(w + 1) * -1), 1); |
|
319 |
- else if(w[0] == '-' && sihx(w + 1) && slen(w + 1) == 4) pushshort((Sint16)(shex(w + 1) * -1), 1); |
|
320 |
- else return error("Unknown label in second pass", w); |
|
321 |
- /* clang-format on */ |
|
322 | 444 |
} |
323 | 445 |
return 1; |
324 | 446 |
} |
... | ... |
@@ -1,9 +1,12 @@ |
1 | 1 |
( tests/jump ) |
2 | 2 |
|
3 |
-|0100 @RESET |
|
3 |
+%RTS { RSW2 JMP } |
|
4 |
+%JSR2 { PRG WSR2 JMP2 } |
|
5 |
+%JMC { JMP2? POP2 } |
|
4 | 6 |
|
7 |
+|0100 @RESET |
|
8 |
+ |
|
5 | 9 |
,test1 JSR2 |
6 |
- ,test2 JSR2 |
|
7 | 10 |
|
8 | 11 |
BRK |
9 | 12 |
|
... | ... |
@@ -23,7 +26,7 @@ BRK |
23 | 26 |
|
24 | 27 |
#33 =Console.byte |
25 | 28 |
|
26 |
- ,skip1 #12 #34 LTH JMP2? POP2 |
|
29 |
+ ,skip1 #12 #34 LTH JMC |
|
27 | 30 |
#ff =Console.byte |
28 | 31 |
@skip1 |
29 | 32 |
|
... | ... |
@@ -48,7 +51,6 @@ RTS |
48 | 51 |
|
49 | 52 |
@end |
50 | 53 |
|
51 |
- ^label1 JMPS |
|
52 | 54 |
RTS |
53 | 55 |
|
54 | 56 |
|c000 @FRAME |
... | ... |
@@ -1,41 +1,46 @@ |
1 |
-( hello world ) |
|
1 |
+( Loop ) |
|
2 | 2 |
|
3 |
-&Console { pad 8 char 1 byte 1 short 2 } |
|
4 |
- |
|
5 |
-;a 1 ;b 1 ;c 1 |
|
3 |
+;a { byte 1 } ;b { byte 1 } ;c { byte 1 } |
|
6 | 4 |
|
7 | 5 |
|0100 @RESET |
8 | 6 |
|
9 |
- ( type: padded muljmp ) |
|
10 |
- @part1 |
|
7 |
+ ,type1 JSR2 |
|
8 |
+ ,type2 JSR2 |
|
9 |
+ ,type3 JSR2 |
|
10 |
+ |
|
11 |
+BRK |
|
12 |
+ |
|
13 |
+@type1 ( type: padded muljmp ) |
|
14 |
+ |
|
11 | 15 |
$loop NOP |
12 | 16 |
~a #01 ADD =a |
13 | 17 |
~a #d0 LTH ^$loop MUL JMPS |
18 |
+ ~a =Console.byte |
|
14 | 19 |
|
15 |
- ( type: jmppop ) |
|
20 |
+RTS |
|
16 | 21 |
|
17 |
- @part2 |
|
22 |
+@type2 ( type: jmppop ) |
|
23 |
+ |
|
18 | 24 |
$loop |
19 | 25 |
~b #01 ADD =b |
20 | 26 |
,$loop ~b #d0 LTH JMP2? POP2 |
27 |
+ ~b =Console.byte |
|
28 |
+ |
|
29 |
+RTS |
|
21 | 30 |
|
22 |
- ( type: padded jmppop ) |
|
31 |
+@type3 ( type: padded jmppop ) |
|
23 | 32 |
|
24 |
- @part3 |
|
25 | 33 |
$loop NOP |
26 | 34 |
~c #01 ADD =c |
27 | 35 |
~c #d0 LTH ^$loop SWP JMPS? POP |
36 |
+ ~c =Console.byte |
|
28 | 37 |
|
29 |
- ~a =dev/console.byte |
|
30 |
- ~b =dev/console.byte |
|
31 |
- ~c =dev/console.byte |
|
32 |
- |
|
33 |
-BRK |
|
38 |
+RTS |
|
34 | 39 |
|
35 | 40 |
|c000 @FRAME |
36 | 41 |
|d000 @ERROR |
37 | 42 |
|
38 |
-|FF00 ;dev/console Console |
|
43 |
+|FF00 ;Console { pad 8 char 1 byte 1 short 2 } |
|
39 | 44 |
|
40 | 45 |
|FFF0 .RESET .FRAME .ERROR ( vectors ) |
41 | 46 |
|FFF8 [ 13fd 1ef3 1bf2 ] ( palette ) |
42 | 47 |
\ No newline at end of file |
... | ... |
@@ -34,6 +34,7 @@ void op_brk(Uxn *u) { setflag(&u->status, FLAG_HALT, 1); } |
34 | 34 |
void op_lit(Uxn *u) { u->literal += 1; } |
35 | 35 |
void op_nop(Uxn *u) { (void)u; } |
36 | 36 |
void op_jmp(Uxn *u) { Uint8 a = pop8(&u->wst); u->ram.ptr += getflag(&u->status, FLAG_SIGN) ? (Sint8)a : a; } |
37 |
+void op_prg(Uxn *u) { push16(&u->wst, u->ram.ptr); } |
|
37 | 38 |
void op_jsr(Uxn *u) { Uint8 a = pop8(&u->wst); push16(&u->rst, u->ram.ptr); u->ram.ptr += getflag(&u->status, FLAG_SIGN) ? (Sint8)a : a; } |
38 | 39 |
void op_rts(Uxn *u) { u->ram.ptr = pop16(&u->rst); } |
39 | 40 |
void op_ldr(Uxn *u) { Uint16 a = pop16(&u->wst); push8(&u->wst, mempeek8(u, a)); } |
... | ... |
@@ -95,7 +96,7 @@ void (*ops[])(Uxn *u) = { |
95 | 96 |
op_pop, op_dup, op_swp, op_ovr, op_rot, op_nop, op_wsr, op_rsw, |
96 | 97 |
op_add, op_sub, op_mul, op_div, op_nop, op_nop, op_nop, op_nop, |
97 | 98 |
/* 16-bit */ |
98 |
- op_brk, op_nop16, op_lit16, op_ldr16, op_str16, op_jmp16, op_jsr16, op_rts, |
|
99 |
+ op_brk, op_nop16, op_lit16, op_ldr16, op_str16, op_jmp16, op_jsr16, op_rts, |
|
99 | 100 |
op_equ16, op_neq16, op_gth16, op_lth16, op_and16, op_xor16, op_rol16, op_ror16, |
100 | 101 |
op_pop16, op_dup16, op_swp16, op_ovr16, op_rot16, op_nop, op_wsr16, op_rsw16, |
101 | 102 |
op_add16, op_sub16, op_mul16, op_div16, op_nop, op_nop, op_nop, op_nop |