commit 3280c2031b3ded001bb16754b16cafd17f2be4a0
parent 0450ed7fe76c2b135484f73b119f38ae39e51e9c
Author: neauoire <aliceffekt@gmail.com>
Date: Sun, 14 Mar 2021 13:30:17 -0700
Started implementing macros
Diffstat:
5 files changed, 215 insertions(+), 77 deletions(-)
diff --git a/README.md b/README.md
@@ -74,6 +74,14 @@ RTS
- Jump helpers
- Don't brk when return stack is not zeroed
- LDRS should load from the zeropage?
+- Keep ref counts in macros
+
+### Macros
+
+```
+&RTS { RSW JMP }
+&JSR { PRG WSR JMP }
+```
## Notes
diff --git a/assembler.c b/assembler.c
@@ -17,6 +17,11 @@ typedef unsigned short Uint16;
typedef signed short Sint16;
typedef struct {
+ char name[64], items[16][64];
+ Uint8 len;
+} Macro;
+
+typedef struct {
char name[64];
unsigned int size;
} Map;
@@ -29,9 +34,10 @@ typedef struct {
} Label;
typedef struct {
- Uint8 data[256 * 256], llen;
+ Uint8 data[256 * 256], llen, mlen;
Uint16 ptr;
Label labels[256];
+ Macro macros[256];
} Program;
Program p;
@@ -42,7 +48,7 @@ char ops[][4] = {
"BRK", "NOP", "LIT", "LDR", "STR", "JMP", "JSR", "RTS",
"EQU", "NEQ", "GTH", "LTH", "AND", "XOR", "ROL", "ROR",
"POP", "DUP", "SWP", "OVR", "ROT", "---", "WSR", "RSW",
- "ADD", "SUB", "MUL", "DIV", "---", "---", "---", "---"
+ "ADD", "SUB", "MUL", "DIV", "---", "---", "---", "PRG"
};
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)
while((c = s[i++])) pushbyte(c, 0);
}
+Macro *
+findmacro(char *name)
+{
+ int i;
+ for(i = 0; i < p.mlen; ++i)
+ if(scmp(p.macros[i].name, name, 64))
+ return &p.macros[i];
+ return NULL;
+}
+
Label *
findlabel(char *s)
{
@@ -167,6 +183,28 @@ error(char *name, char *id)
}
int
+makemacro(char *name, FILE *f)
+{
+ Macro *m;
+ char word[64];
+ if(findmacro(name))
+ return error("Macro duplicate", name);
+ if(sihx(name) && slen(name) % 2 == 0)
+ return error("Macro name is hex number", name);
+ if(findopcode(name))
+ return error("Macro name is invalid", name);
+ m = &p.macros[p.mlen++];
+ scpy(name, m->name, 64);
+ while(fscanf(f, "%s", word)) {
+ if(word[0] == '{') continue;
+ if(word[0] == '}') break;
+ scpy(word, m->items[m->len++], 64);
+ }
+ printf("New macro: %s(%d items)\n", m->name, m->len);
+ return 1;
+}
+
+int
makelabel(char *name, Uint16 addr)
{
Label *l;
@@ -197,8 +235,7 @@ makevariable(char *name, Uint16 *addr, FILE *f)
if(word[0] == '}') break;
scpy(word, l->map[l->maps].name, 64);
fscanf(f, "%u", &l->map[l->maps].size);
- *addr += l->map[l->maps].size;
- l->maps++;
+ *addr += l->map[l->maps++].size;
}
return 1;
}
@@ -216,6 +253,119 @@ skipblock(char *w, int *cap, char a, char b)
}
int
+walktoken(char *w)
+{
+ Macro *m;
+ if((m = findmacro(w))) {
+ int i, res = 0;
+ for(i = 0; i < m->len; ++i)
+ res += walktoken(m->items[i]);
+ return res;
+ }
+ if(findopcode(w) || scmp(w, "BRK", 4))
+ return 1;
+ switch(w[0]) {
+ case '=': return 4; /* STR helper (lit addr-hb addr-lb str) */
+ case '~': return 4; /* LDR helper (lit addr-hb addr-lb ldr) */
+ case ',': return 3; /* lit2 addr-hb addr-lb */
+ case '.': return 2; /* addr-hb addr-lb */
+ case '^': return 2; /* Relative jump: lit addr-offset */
+ case '+': /* signed positive */
+ case '-': /* signed negative */
+ case '#': return (slen(w + 1) == 2 ? 2 : 3);
+ }
+ return error("Unknown label in first pass", w);
+}
+
+int
+parsetoken(char *w)
+{
+ Uint8 op = 0;
+ Label *l;
+ Macro *m;
+
+ if(w[0] == '^' && (l = findlabel(w + 1))) {
+ int off = l->addr - p.ptr - 3;
+ if(off < -126 || off > 126) {
+ printf("Address %s is too far(%d).\n", w, off);
+ return 0;
+ }
+ pushbyte((Sint8)(l->addr - p.ptr - 3), 1);
+ l->refs++;
+ return 1;
+ }
+ if(w[0] == '=' && (l = findlabel(w + 1))) {
+ if(!findlabellen(w + 1) || findlabellen(w + 1) > 2)
+ return error("Invalid load helper", w);
+ pushshort(findlabeladdr(w + 1), 1);
+ pushbyte(findopcode(findlabellen(w + 1) == 2 ? "STR2" : "STR"), 0);
+ l->refs++;
+ return 1;
+ }
+ if(w[0] == '~' && (l = findlabel(w + 1))) {
+ if(!findlabellen(w + 1) || findlabellen(w + 1) > 2)
+ return error("Invalid load helper", w);
+ pushshort(findlabeladdr(w + 1), 1);
+ pushbyte(findopcode(findlabellen(w + 1) == 2 ? "LDR2" : "LDR"), 0);
+ l->refs++;
+ return 1;
+ }
+ if((op = findopcode(w)) || scmp(w, "BRK", 4)) {
+ pushbyte(op, 0);
+ return 1;
+ }
+ if(w[0] == '.' && (l = findlabel(w + 1))) {
+ pushshort(findlabeladdr(w + 1), 0);
+ l->refs++;
+ return 1;
+ }
+ if(w[0] == ',' && (l = findlabel(w + 1))) {
+ pushshort(findlabeladdr(w + 1), 1);
+ l->refs++;
+ return 1;
+ }
+ if(w[0] == '#' && sihx(w + 1)) {
+ if(slen(w + 1) == 2)
+ pushbyte(shex(w + 1), 1);
+ else if(slen(w + 1) == 4)
+ pushshort(shex(w + 1), 1);
+ else
+ return 0;
+ return 1;
+ }
+
+ if(w[0] == '+' && sihx(w + 1)) {
+ if(slen(w + 1) == 2)
+ pushbyte((Sint8)shex(w + 1), 1);
+ else if(slen(w + 1) == 4)
+ pushshort((Sint16)shex(w + 1), 1);
+ else
+ return 0;
+ }
+
+ if(w[0] == '-' && sihx(w + 1)) {
+ if(slen(w + 1) == 2)
+ pushbyte((Sint8)(shex(w + 1) * -1), 1);
+ else if(slen(w + 1) == 4)
+ pushshort((Sint16)(shex(w + 1) * -1), 1);
+ else
+ return 0;
+ return 1;
+ }
+
+ if((m = findmacro(w))) {
+ int i, res = 0;
+ for(i = 0; i < m->len; ++i) {
+ if(!parsetoken(m->items[i]))
+ return 0;
+ }
+ return 1;
+ }
+
+ return 0;
+}
+
+int
pass1(FILE *f)
{
int ccmnt = 0, cbits = 0;
@@ -231,6 +381,10 @@ pass1(FILE *f)
addr += slen(w) == 4 ? 2 : 1;
else
addr += slen(w);
+ } else if(w[0] == '%') {
+ if(!makemacro(w + 1, f))
+ return error("Pass1 failed", w);
+ scpy(w + 1, scope, 64);
} else if(w[0] == '@') {
if(!makelabel(w + 1, addr))
return error("Pass1 failed", w);
@@ -241,25 +395,12 @@ pass1(FILE *f)
} else if(w[0] == ';') {
if(!makevariable(w + 1, &addr, f))
return error("Pass1 failed", w);
- } else if(findopcode(w) || scmp(w, "BRK", 4))
- addr += 1;
- else {
- switch(w[0]) {
- case '|':
- if(shex(w + 1) < addr)
- return error("Memory Overlap", w);
- addr = shex(w + 1);
- break;
- case '=': addr += 4; break; /* STR helper (lit addr-hb addr-lb str) */
- case '~': addr += 4; break; /* LDR helper (lit addr-hb addr-lb ldr) */
- case ',': addr += 3; break;
- case '.': addr += 2; break;
- case '^': addr += 2; break; /* Relative jump: lit addr-offset */
- case '+': /* signed positive */
- case '-': /* signed negative */
- case '#': addr += (slen(w + 1) == 2 ? 2 : 3); break;
- default: return error("Unknown label in first pass", w);
- }
+ } else if(w[0] == '|') {
+ if(shex(w + 1) < addr)
+ return error("Memory Overwrite", w);
+ addr = shex(w + 1);
+ } else {
+ addr += walktoken(w);
}
}
rewind(f);
@@ -273,52 +414,33 @@ pass2(FILE *f)
char w[64], scope[64], subw[64];
printf("Pass 2\n");
while(fscanf(f, "%s", w) == 1) {
- Uint8 op = 0;
- Label *l;
if(w[0] == ';') continue;
if(w[0] == '$') continue;
+ if(w[0] == '%') continue;
if(skipblock(w, &ccmnt, '(', ')')) continue;
if(skipblock(w, &ctemplate, '{', '}')) continue;
+ if(w[0] == '|') {
+ p.ptr = shex(w + 1);
+ continue;
+ }
if(w[0] == '@') {
scpy(w + 1, scope, 64);
continue;
}
if(w[1] == '$') {
- sublabel(subw, scope, w + 2);
- scpy(subw, w + 1, 64);
+ scpy(sublabel(subw, scope, w + 2), w + 1, 64);
}
- /* clang-format off */
if(skipblock(w, &cbits, '[', ']')) {
if(w[0] == '[' || w[0] == ']') { continue; }
- if(slen(w) == 4 && sihx(w)) pushshort(shex(w), 0);
- else if(slen(w) == 2 && sihx(w)) pushbyte(shex(w), 0);
- else pushtext(w, 0);
- }
- else if(w[0] == '^' && (l = findlabel(w + 1))) {
- int off = l->addr - p.ptr - 3;
- if(off < -126 || off > 126){ printf("Address %s is too far(%d).\n", w, off); return 0; }
- pushbyte((Sint8)(l->addr - p.ptr - 3), 1); l->refs++;
+ if(slen(w) == 4 && sihx(w))
+ pushshort(shex(w), 0);
+ else if(slen(w) == 2 && sihx(w))
+ pushbyte(shex(w), 0);
+ else
+ pushtext(w, 0);
+ } else if(!parsetoken(w)) {
+ return error("Unknown label in second pass", w);
}
- else if(w[0] == '=' && (l = findlabel(w + 1))) {
- if(!findlabellen(w + 1) || findlabellen(w + 1) > 2)
- return error("Invalid load helper", w);
- pushshort(findlabeladdr(w + 1), 1); pushbyte(findopcode(findlabellen(w + 1) == 2 ? "STR2" : "STR"), 0); l->refs++;}
- else if(w[0] == '~' && (l = findlabel(w + 1))) {
- if(!findlabellen(w + 1) || findlabellen(w + 1) > 2)
- return error("Invalid load helper", w);
- pushshort(findlabeladdr(w + 1), 1); pushbyte(findopcode(findlabellen(w + 1) == 2 ? "LDR2" : "LDR"), 0); l->refs++;}
- else if(w[0] == '|') p.ptr = shex(w + 1);
- else if((op = findopcode(w)) || scmp(w, "BRK", 4)) pushbyte(op, 0);
- else if(w[0] == '.' && (l = findlabel(w + 1))) { pushshort(findlabeladdr(w + 1), 0); l->refs++; }
- else if(w[0] == ',' && (l = findlabel(w + 1))) { pushshort(findlabeladdr(w + 1), 1); l->refs++; }
- else if(w[0] == '#' && sihx(w + 1) && slen(w + 1) == 2) pushbyte(shex(w + 1), 1);
- else if(w[0] == '#' && sihx(w + 1) && slen(w + 1) == 4) pushshort(shex(w + 1), 1);
- else if(w[0] == '+' && sihx(w + 1) && slen(w + 1) == 2) pushbyte((Sint8)shex(w + 1), 1);
- else if(w[0] == '+' && sihx(w + 1) && slen(w + 1) == 4) pushshort((Sint16)shex(w + 1), 1);
- else if(w[0] == '-' && sihx(w + 1) && slen(w + 1) == 2) pushbyte((Sint8)(shex(w + 1) * -1), 1);
- else if(w[0] == '-' && sihx(w + 1) && slen(w + 1) == 4) pushshort((Sint16)(shex(w + 1) * -1), 1);
- else return error("Unknown label in second pass", w);
- /* clang-format on */
}
return 1;
}
diff --git a/projects/tests/jump.usm b/projects/tests/jump.usm
@@ -1,9 +1,12 @@
( tests/jump )
-|0100 @RESET
+%RTS { RSW2 JMP }
+%JSR2 { PRG WSR2 JMP2 }
+%JMC { JMP2? POP2 }
+|0100 @RESET
+
,test1 JSR2
- ,test2 JSR2
BRK
@@ -23,7 +26,7 @@ BRK
#33 =Console.byte
- ,skip1 #12 #34 LTH JMP2? POP2
+ ,skip1 #12 #34 LTH JMC
#ff =Console.byte
@skip1
@@ -48,7 +51,6 @@ RTS
@end
- ^label1 JMPS
RTS
|c000 @FRAME
diff --git a/projects/tests/loop.usm b/projects/tests/loop.usm
@@ -1,41 +1,46 @@
-( hello world )
+( Loop )
-&Console { pad 8 char 1 byte 1 short 2 }
-
-;a 1 ;b 1 ;c 1
+;a { byte 1 } ;b { byte 1 } ;c { byte 1 }
|0100 @RESET
- ( type: padded muljmp )
- @part1
+ ,type1 JSR2
+ ,type2 JSR2
+ ,type3 JSR2
+
+BRK
+
+@type1 ( type: padded muljmp )
+
$loop NOP
~a #01 ADD =a
~a #d0 LTH ^$loop MUL JMPS
+ ~a =Console.byte
- ( type: jmppop )
+RTS
- @part2
+@type2 ( type: jmppop )
+
$loop
~b #01 ADD =b
,$loop ~b #d0 LTH JMP2? POP2
+ ~b =Console.byte
+
+RTS
- ( type: padded jmppop )
+@type3 ( type: padded jmppop )
- @part3
$loop NOP
~c #01 ADD =c
~c #d0 LTH ^$loop SWP JMPS? POP
+ ~c =Console.byte
- ~a =dev/console.byte
- ~b =dev/console.byte
- ~c =dev/console.byte
-
-BRK
+RTS
|c000 @FRAME
|d000 @ERROR
-|FF00 ;dev/console Console
+|FF00 ;Console { pad 8 char 1 byte 1 short 2 }
|FFF0 .RESET .FRAME .ERROR ( vectors )
|FFF8 [ 13fd 1ef3 1bf2 ] ( palette )
\ No newline at end of file
diff --git a/uxn.c b/uxn.c
@@ -34,6 +34,7 @@ void op_brk(Uxn *u) { setflag(&u->status, FLAG_HALT, 1); }
void op_lit(Uxn *u) { u->literal += 1; }
void op_nop(Uxn *u) { (void)u; }
void op_jmp(Uxn *u) { Uint8 a = pop8(&u->wst); u->ram.ptr += getflag(&u->status, FLAG_SIGN) ? (Sint8)a : a; }
+void op_prg(Uxn *u) { push16(&u->wst, u->ram.ptr); }
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; }
void op_rts(Uxn *u) { u->ram.ptr = pop16(&u->rst); }
void op_ldr(Uxn *u) { Uint16 a = pop16(&u->wst); push8(&u->wst, mempeek8(u, a)); }
@@ -95,7 +96,7 @@ void (*ops[])(Uxn *u) = {
op_pop, op_dup, op_swp, op_ovr, op_rot, op_nop, op_wsr, op_rsw,
op_add, op_sub, op_mul, op_div, op_nop, op_nop, op_nop, op_nop,
/* 16-bit */
- op_brk, op_nop16, op_lit16, op_ldr16, op_str16, op_jmp16, op_jsr16, op_rts,
+ op_brk, op_nop16, op_lit16, op_ldr16, op_str16, op_jmp16, op_jsr16, op_rts,
op_equ16, op_neq16, op_gth16, op_lth16, op_and16, op_xor16, op_rol16, op_ror16,
op_pop16, op_dup16, op_swp16, op_ovr16, op_rot16, op_nop, op_wsr16, op_rsw16,
op_add16, op_sub16, op_mul16, op_div16, op_nop, op_nop, op_nop, op_nop