Browse code

(uxnasm) Rewrite

neauoire authored on 27/11/2021 19:33:22
Showing 1 changed files
... ...
@@ -14,6 +14,7 @@ WITH REGARD TO THIS SOFTWARE.
14 14
 #define TRIM 0x0100
15 15
 #define LENGTH 0x10000
16 16
 
17
+#define REFERENCES 2048
17 18
 #define LABELS 512
18 19
 #define MACROS 256
19 20
 
... ...
@@ -31,15 +32,21 @@ typedef struct {
31 32
 	Uint16 addr, refs;
32 33
 } Label;
33 34
 
35
+typedef struct {
36
+	char name[64], rune;
37
+	Uint16 addr;
38
+} Reference;
39
+
34 40
 typedef struct {
35 41
 	Uint8 data[LENGTH];
36
-	Uint16 ptr, length, llen, mlen;
42
+	Uint16 ptr, length, llen, mlen, rlen;
37 43
 	Label labels[LABELS];
38 44
 	Macro macros[MACROS];
45
+	Reference refs[REFERENCES];
46
+	char scope[64];
39 47
 } Program;
40 48
 
41 49
 Program p;
42
-static Uint16 addr = 0;
43 50
 
44 51
 /* clang-format off */
45 52
 
... ...
@@ -50,7 +57,6 @@ static char ops[][4] = {
50 57
 	"ADD", "SUB", "MUL", "DIV", "AND", "ORA", "EOR", "SFT"
51 58
 };
52 59
 
53
-static int   cpos(char *s, char a){ int i = 0; char c; while((c = s[i++])) if(c == a) return i; return -1; }
54 60
 static int   scmp(char *a, char *b, int len) { int i = 0; while(a[i] == b[i]) if(!a[i] || ++i >= len) return 1; return 0; } /* string compare */
55 61
 static int   sihx(char *s) { int i = 0; char c; while((c = s[i++])) if(!(c >= '0' && c <= '9') && !(c >= 'a' && c <= 'f')) return 0; return i > 1; } /* string is hexadecimal */
56 62
 static int   shex(char *s) { int n = 0, i = 0; char c; while((c = s[i++])) if(c >= '0' && c <= '9') n = n * 16 + (c - '0'); else if(c >= 'a' && c <= 'f') n = n * 16 + 10 + (c - 'a'); return n; } /* string to num */
... ...
@@ -58,11 +64,16 @@ static int   slen(char *s) { int i = 0; while(s[i]) ++i; return i; } /* string l
58 64
 static char *scpy(char *src, char *dst, int len) { int i = 0; while((dst[i] = src[i]) && i < len - 2) i++; dst[i + 1] = '\0'; return dst; } /* string copy */
59 65
 static char *scat(char *dst, const char *src) { char *ptr = dst + slen(dst); while(*src) *ptr++ = *src++; *ptr = '\0'; return dst; } /* string cat */
60 66
 
61
-#pragma mark - Helpers
62
-
63 67
 /* clang-format on */
64 68
 
65
-#pragma mark - I/O
69
+static int tokenize(char *w, FILE *f);
70
+
71
+static int
72
+error(const char *name, const char *msg)
73
+{
74
+	fprintf(stderr, "%s: %s\n", name, msg);
75
+	return 0;
76
+}
66 77
 
67 78
 static Macro *
68 79
 findmacro(char *name)
... ...
@@ -109,45 +120,6 @@ findopcode(char *s)
109 120
 	return 0;
110 121
 }
111 122
 
112
-static void
113
-pushbyte(Uint8 b, int lit)
114
-{
115
-	if(lit) pushbyte(findopcode("LIT"), 0);
116
-	p.data[p.ptr++] = b;
117
-	p.length = p.ptr;
118
-}
119
-
120
-static void
121
-pushshort(Uint16 s, int lit)
122
-{
123
-	if(lit) pushbyte(findopcode("LIT2"), 0);
124
-	pushbyte((s >> 8) & 0xff, 0);
125
-	pushbyte(s & 0xff, 0);
126
-}
127
-
128
-static void
129
-pushword(char *s)
130
-{
131
-	int i = 0;
132
-	char c;
133
-	while((c = s[i++])) pushbyte(c, 0);
134
-}
135
-
136
-static char *
137
-sublabel(char *src, char *scope, char *name)
138
-{
139
-	return scat(scat(scpy(scope, src, 64), "/"), name);
140
-}
141
-
142
-#pragma mark - Parser
143
-
144
-static int
145
-error(const char *name, const char *msg)
146
-{
147
-	fprintf(stderr, "%s: %s\n", name, msg);
148
-	return 0;
149
-}
150
-
151 123
 static int
152 124
 makemacro(char *name, FILE *f)
153 125
 {
... ...
@@ -186,216 +158,199 @@ makelabel(char *name)
186 158
 	if(p.llen == LABELS)
187 159
 		return error("Too many labels", name);
188 160
 	l = &p.labels[p.llen++];
189
-	l->addr = addr;
161
+	l->addr = p.ptr;
190 162
 	l->refs = 0;
191 163
 	scpy(name, l->name, 64);
192 164
 	return 1;
193 165
 }
194 166
 
195 167
 static int
196
-addref(Label *l, Uint8 rel)
168
+doinclude(const char *filename)
197 169
 {
198
-	if(rel) {
199
-		int pos = cpos(l->name, '/');
200
-		if(pos != -1) {
201
-			char parent[64];
202
-			Label *rl = findlabel(scpy(l->name, parent, pos));
203
-			if(rl)
204
-				++rl->refs;
205
-		}
206
-	}
207
-	return ++l->refs;
170
+	FILE *f;
171
+	char w[64];
172
+	if(!(f = fopen(filename, "r")))
173
+		return error("Include failed to open", filename);
174
+	while(fscanf(f, "%63s", w) == 1)
175
+		if(!tokenize(w, f))
176
+			return error("Unknown token", w);
177
+	fclose(f);
178
+	return 1;
208 179
 }
209 180
 
210
-static int
211
-skipblock(char *w, int *cap, char a, char b)
181
+static void
182
+writebyte(Uint8 b, int lit)
212 183
 {
213
-	if(w[0] == b) {
214
-		*cap = 0;
215
-		return 1;
216
-	}
217
-	if(w[0] == a) *cap = 1;
218
-	if(*cap) return 1;
219
-	return 0;
184
+	if(lit) writebyte(findopcode("LIT"), 0);
185
+	p.data[p.ptr++] = b;
186
+	p.length = p.ptr;
220 187
 }
221 188
 
222
-static int
223
-walktoken(char *w)
189
+static void
190
+writeshort(Uint16 s, int lit)
224 191
 {
225
-	Macro *m;
226
-	if(findopcode(w) || scmp(w, "BRK", 4))
227
-		return 1;
228
-	switch(w[0]) {
229
-	case '[': return 0;
230
-	case ']': return 0;
231
-	case '\'': return 1;
232
-	case '.': return 2; /* zero-page: LIT addr-lb */
233
-	case ',': return 2; /* relative:  LIT addr-rel */
234
-	case ':': return 2; /* absolute:      addr-hb addr-lb */
235
-	case ';': return 3; /* absolute:  LIT addr-hb addr-lb */
236
-	case '$': return shex(w + 1);
237
-	case '#': return slen(w + 1) == 4 ? 3 : 2;
238
-	case '"': return slen(w + 1);
239
-	}
240
-	if((m = findmacro(w))) {
241
-		int i, res = 0;
242
-		for(i = 0; i < m->len; ++i)
243
-			res += walktoken(m->items[i]);
244
-		return res;
245
-	}
246
-	if(sihx(w) && slen(w) == 2)
247
-		return 1;
248
-	else if(sihx(w) && slen(w) == 4)
249
-		return 2;
250
-	return error("Invalid token", w);
192
+	if(lit) writebyte(findopcode("LIT2"), 0);
193
+	writebyte((s >> 8) & 0xff, 0);
194
+	writebyte(s & 0xff, 0);
251 195
 }
252 196
 
253
-static int
254
-parsetoken(char *w)
197
+static char *
198
+sublabel(char *src, char *scope, char *name)
255 199
 {
256
-	Label *l;
257
-	Macro *m;
258
-	if(w[0] == '.' && (l = findlabel(w + 1))) { /* zero-page */
259
-		if(l->addr > 0xff)
260
-			return error("Address is not in zero page", w);
261
-		pushbyte(l->addr, 1);
262
-		return addref(l, 1);
263
-	} else if(w[0] == ',' && (l = findlabel(w + 1))) { /* relative */
264
-		int off = l->addr - p.ptr - 3;
265
-		if(off < -126 || off > 126)
266
-			return error("Address is too far", w);
267
-		pushbyte((Sint8)off, 1);
268
-		return addref(l, 0);
269
-	} else if(w[0] == ':' && (l = findlabel(w + 1))) { /* raw */
270
-		pushshort(l->addr, 0);
271
-		return addref(l, 1);
272
-	} else if(w[0] == ';' && (l = findlabel(w + 1))) { /* absolute */
273
-		pushshort(l->addr, 1);
274
-		return addref(l, 1);
275
-	} else if(findopcode(w) || scmp(w, "BRK", 4)) { /* opcode */
276
-		pushbyte(findopcode(w), 0);
277
-		return 1;
278
-	} else if(w[0] == '"') { /* string */
279
-		pushword(w + 1);
280
-		return 1;
281
-	} else if(w[0] == '\'') { /* char */
282
-		pushbyte((Uint8)w[1], 0);
283
-		return 1;
284
-	} else if(w[0] == '#') { /* immediate */
285
-		if(sihx(w + 1) && slen(w + 1) == 2)
286
-			pushbyte(shex(w + 1), 1);
287
-		else if(sihx(w + 1) && slen(w + 1) == 4)
288
-			pushshort(shex(w + 1), 1);
289
-		else
290
-			return error("Invalid hexadecimal literal", w);
291
-		return 1;
292
-	} else if(sihx(w)) { /* raw */
293
-		if(slen(w) == 2)
294
-			pushbyte(shex(w), 0);
295
-		else if(slen(w) == 4)
296
-			pushshort(shex(w), 0);
297
-		else
298
-			return error("Invalid hexadecimal value", w);
299
-		return 1;
300
-	} else if((m = findmacro(w))) {
301
-		int i;
302
-		for(i = 0; i < m->len; ++i)
303
-			if(!parsetoken(m->items[i]))
304
-				return error("Invalid macro", m->name);
305
-		return 1;
306
-	}
307
-	return error("Invalid token", w);
200
+	return scat(scat(scpy(scope, src, 64), "/"), name);
308 201
 }
309 202
 
310
-static int
311
-doinclude(const char *filename, int (*pass)(FILE *))
203
+static void
204
+prefill(char *scope, char *label, Uint16 addr)
312 205
 {
313
-	FILE *f;
314
-	int ret;
315
-	if(!(f = fopen(filename, "r")))
316
-		return error("Include failed to open", filename);
317
-	ret = pass(f);
318
-	fclose(f);
319
-	return ret;
206
+	char subw[64];
207
+	Reference *r = &p.refs[p.rlen++];
208
+	if(label[1] == '&')
209
+		scpy(sublabel(subw, scope, label + 2), r->name, 64);
210
+	else
211
+		scpy(label + 1, r->name, 64);
212
+	r->rune = label[0];
213
+	r->addr = addr;
320 214
 }
321 215
 
322 216
 static int
323
-pass1(FILE *f)
217
+tokenize(char *w, FILE *f)
324 218
 {
325
-	int ccmnt = 0;
326
-	char w[64], scope[64], subw[64];
327
-	scope[0] = 0;
328
-	while(fscanf(f, "%63s", w) == 1) {
329
-		if(skipblock(w, &ccmnt, '(', ')')) continue;
330
-		if(slen(w) >= 63)
331
-			return error("Pass 1 - Invalid token", w);
332
-		if(w[0] == '|') {
333
-			if(!sihx(w + 1))
334
-				return error("Pass 1 - Invalid padding", w);
335
-			addr = shex(w + 1);
336
-		} else if(w[0] == '%') {
337
-			if(!makemacro(w + 1, f))
338
-				return error("Pass 1 - Invalid macro", w);
339
-		} else if(w[0] == '@') {
340
-			if(!makelabel(w + 1))
341
-				return error("Pass 1 - Invalid label", w);
342
-			scpy(w + 1, scope, 64);
343
-		} else if(w[0] == '&') {
344
-			if(!makelabel(sublabel(subw, scope, w + 1)))
345
-				return error("Pass 1 - Invalid sublabel", w);
346
-		} else if(w[0] == '~') {
347
-			if(!doinclude(w + 1, pass1))
348
-				return 0;
349
-		} else if(sihx(w))
350
-			addr += slen(w) / 2;
351
-		else
352
-			addr += walktoken(w);
219
+	char word[64];
220
+	char subw[64];
221
+	char c;
222
+	Macro *m;
223
+	int i = 0;
224
+	if(slen(w) >= 63)
225
+		return error("Invalid token", w);
226
+	switch(w[0]) {
227
+	case '(': /* comment */
228
+		while(fscanf(f, "%63s", word) == 1)
229
+			if(word[0] == ')') break;
230
+		break;
231
+	case '~': /* include */
232
+		if(!doinclude(w + 1))
233
+			return error("Invalid include", w);
234
+		break;
235
+	case '%': /* macro */
236
+		if(!makemacro(w + 1, f))
237
+			return error("Invalid macro", w);
238
+		break;
239
+	case '|': /* pad-absolute */
240
+		if(!sihx(w + 1))
241
+			return error("Invalid padding", w);
242
+		p.ptr = shex(w + 1);
243
+		break;
244
+	case '$': /* pad-relative */
245
+		if(!sihx(w + 1))
246
+			return error("Invalid padding", w);
247
+		p.ptr += shex(w + 1);
248
+		break;
249
+	case '@': /* label */
250
+		if(!makelabel(w + 1))
251
+			return error("Invalid label", w);
252
+		scpy(w + 1, p.scope, 64);
253
+		break;
254
+	case '&': /* sublabel */
255
+		if(!makelabel(sublabel(subw, p.scope, w + 1)))
256
+			return error("Invalid sublabel", w);
257
+		break;
258
+	case '#': /* literals hex */
259
+		if(!sihx(w + 1) || (slen(w) != 3 && slen(w) != 5))
260
+			return error("Invalid hex literal", w);
261
+		if(slen(w) == 3)
262
+			writebyte(shex(w + 1), 1);
263
+		else if(slen(w) == 5)
264
+			writeshort(shex(w + 1), 1);
265
+		break;
266
+	case '.': /* literal byte zero-page */
267
+	case ',': /* literal byte relative */
268
+		prefill(p.scope, w, p.ptr);
269
+		writebyte(0xff, 1);
270
+		break;
271
+	case ';': /* literal short absolute */
272
+		prefill(p.scope, w, p.ptr);
273
+		writeshort(0xffff, 1);
274
+		break;
275
+	case ':': /* raw short absolute */
276
+		prefill(p.scope, w, p.ptr);
277
+		writeshort(0xffff, 0);
278
+		break;
279
+	case '\'': /* raw char */
280
+		writebyte((Uint8)w[1], 0);
281
+		break;
282
+	case '"': /* raw string */
283
+		i = 0;
284
+		while((c = w[++i]))
285
+			writebyte(c, 0);
286
+		break;
287
+	case '[': break; /* ignored */
288
+	case ']': break; /* ignored */
289
+	default:
290
+		/* opcode */
291
+		if(findopcode(w) || scmp(w, "BRK", 4))
292
+			writebyte(findopcode(w), 0);
293
+		/* raw byte */
294
+		else if(sihx(w) && slen(w) == 2)
295
+			writebyte(shex(w), 0);
296
+		/* raw short */
297
+		else if(sihx(w) && slen(w) == 4)
298
+			writeshort(shex(w), 0);
299
+		/* macro */
300
+		else if((m = findmacro(w))) {
301
+			for(i = 0; i < m->len; ++i)
302
+				if(!tokenize(m->items[i], f))
303
+					return 0;
304
+			return 1;
305
+		} else
306
+			return error("Unknown token", w);
353 307
 	}
354
-	rewind(f);
355 308
 	return 1;
356 309
 }
357 310
 
358 311
 static int
359
-pass2(FILE *f)
312
+resolve(void)
360 313
 {
361
-	int ccmnt = 0, cmacr = 0;
362
-	char w[64], scope[64], subw[64];
363
-	scope[0] = 0;
364
-	while(fscanf(f, "%63s", w) == 1) {
365
-		if(w[0] == '%') continue;
366
-		if(w[0] == '&') continue;
367
-		if(w[0] == '[') continue;
368
-		if(w[0] == ']') continue;
369
-		if(skipblock(w, &ccmnt, '(', ')')) continue;
370
-		if(skipblock(w, &cmacr, '{', '}')) continue;
371
-		if(w[0] == '|') {
372
-			if(p.length && (Uint16)shex(w + 1) < p.ptr)
373
-				return error("Pass 2 - Memory overwrite", w);
374
-			p.ptr = shex(w + 1);
375
-			continue;
376
-		} else if(w[0] == '$') {
377
-			if(p.length && (Uint16)(p.ptr + shex(w + 1)) < p.ptr)
378
-				return error("Pass 2 - Memory overwrite", w);
379
-			p.ptr += shex(w + 1);
380
-			continue;
381
-		} else if(w[0] == '@') {
382
-			scpy(w + 1, scope, 64);
383
-			continue;
384
-		} else if(w[0] == '~') {
385
-			if(!doinclude(w + 1, pass2))
386
-				return 0;
387
-			continue;
314
+	Label *l;
315
+	int i;
316
+	for(i = 0; i < p.rlen; ++i) {
317
+		Reference *r = &p.refs[i];
318
+		switch(r->rune) {
319
+		case '.':
320
+			if(!(l = findlabel(r->name)))
321
+				return error("Unknown zero-page reference", r->name);
322
+			p.data[r->addr + 1] = l->addr & 0xff;
323
+			l->refs++;
324
+			break;
325
+		case ',':
326
+			if(!(l = findlabel(r->name)))
327
+				return error("Unknown relative reference", r->name);
328
+			p.data[r->addr + 1] = (Sint8)(l->addr - r->addr - 3);
329
+			l->refs++;
330
+			break;
331
+		case ';':
332
+			if(!(l = findlabel(r->name)))
333
+				return error("Unknown absolute reference", r->name);
334
+			p.data[r->addr + 1] = l->addr >> 0x8;
335
+			p.data[r->addr + 2] = l->addr & 0xff;
336
+			l->refs++;
337
+			break;
338
+		case ':':
339
+			if(!(l = findlabel(r->name)))
340
+				return error("Unknown absolute reference", r->name);
341
+			p.data[r->addr + 0] = l->addr >> 0x8;
342
+			p.data[r->addr + 1] = l->addr & 0xff;
343
+			l->refs++;
344
+			break;
345
+		default:
346
+			return error("Unknown reference", r->name);
388 347
 		}
389
-		if(w[1] == '&' && (w[0] == '.' || w[0] == ',' || w[0] == ';' || w[0] == ':'))
390
-			scpy(sublabel(subw, scope, w + 2), w + 1, 64);
391
-		if(!parsetoken(w))
392
-			return error("Pass 2 - Unknown label", w);
393 348
 	}
394 349
 	return 1;
395 350
 }
396 351
 
397 352
 static void
398
-cleanup(char *filename)
353
+review(char *filename)
399 354
 {
400 355
 	int i;
401 356
 	for(i = 0; i < p.llen; ++i)
... ...
@@ -406,6 +361,18 @@ cleanup(char *filename)
406 361
 	fprintf(stderr, "Assembled %s in %d bytes(%.2f%% used), %d labels, %d macros.\n", filename, p.length - TRIM, p.length / 652.80, p.llen, p.mlen);
407 362
 }
408 363
 
364
+static int
365
+assemble(FILE *f)
366
+{
367
+	char w[64];
368
+	scpy("on-reset", p.scope, 64);
369
+	while(fscanf(f, "%63s", w) == 1)
370
+		if(!tokenize(w, f))
371
+			return error("Unknown token", w);
372
+	resolve();
373
+	return 1;
374
+}
375
+
409 376
 int
410 377
 main(int argc, char *argv[])
411 378
 {
... ...
@@ -414,11 +381,11 @@ main(int argc, char *argv[])
414 381
 		return !error("usage", "input.tal output.rom");
415 382
 	if(!(src = fopen(argv[1], "r")))
416 383
 		return !error("Invalid Input", argv[1]);
417
-	if(!pass1(src) || !pass2(src))
384
+	if(!assemble(src))
418 385
 		return !error("Assembly", "Failed to assemble rom.");
419 386
 	if(!(dst = fopen(argv[2], "wb")))
420 387
 		return !error("Invalid Output", argv[2]);
421 388
 	fwrite(p.data + TRIM, p.length - TRIM, 1, dst);
422
-	cleanup(argv[2]);
389
+	review(argv[2]);
423 390
 	return 0;
424 391
 }