blob: 989b83cb8ed99d9d99a8513d0ff2fb160b63b1e3 [file] [log] [blame]
swissChili97b5d8b2020-08-15 20:00:54 -07001#include "as.h"
2#include "../cpu.h"
3#include "../instructions.h"
4#include "../mnemonics.h"
swissChilica0d2e22020-08-16 15:09:25 -07005#include "map.h"
swissChili97b5d8b2020-08-15 20:00:54 -07006
swissChilidab15a62020-08-17 15:41:27 -07007#include <endian.h>
8#include <stdio.h>
swissChili97b5d8b2020-08-15 20:00:54 -07009#include <string.h>
10#include <ctype.h>
11#include <stdbool.h>
12
13enum
14{
15 ARG_16, /* Absolute 16 bit argument */
16 ARG_8, /* Absolute 8 bit argument */
17 ARG_8REL, /* Relative 8 bit argument */
18 ARG_REL, /* Relative label */
19 ARG_ABS, /* Absolute label */
20 ARG_IMP, /* Implied argument */
21};
22
swissChili7acb4ce2020-08-16 20:16:10 -070023#define ERR "\033[31m"
swissChili6a923012020-08-18 17:47:27 -070024#define GREEN "\033[32m"
swissChili7acb4ce2020-08-16 20:16:10 -070025#define RESET "\033[0m"
swissChilidab15a62020-08-17 15:41:27 -070026#define MAX_LEN (0xFFFF - 0x600)
27#define MAX_INSTS (MAX_LEN / 2)
swissChili7acb4ce2020-08-16 20:16:10 -070028
swissChili97b5d8b2020-08-15 20:00:54 -070029typedef struct
30{
31 uint8_t opcode;
32 uint8_t arg_type;
swissChili7acb4ce2020-08-16 20:16:10 -070033 uint16_t line;
swissChili97b5d8b2020-08-15 20:00:54 -070034 union
35 {
36 char label[32];
37 uint16_t long_arg;
38 uint8_t byte_arg;
39 int8_t rel_arg;
40 };
41} inst_t;
42
swissChilidab15a62020-08-17 15:41:27 -070043typedef struct ll_node
44{
45 struct ll_node *last;
46 char name[32];
47 uint16_t addr;
48} ll_node_t;
49
swissChili7acb4ce2020-08-16 20:16:10 -070050// Normal strtok() counts 2 seperators as one, ie asdf\n\njlk is 2 lines.
51// This functions counts that as 3 lines, and will return an empty line in between.
52char *strtok_fix(char *string, const char *token)
53{
54 static char *pos;
55 if (string)
56 pos = string;
57 else
58 string = pos;
59
60 if (*pos == 0)
61 return NULL;
62
63 for (; *string; string++)
64 {
65 for (int i = 0; i < strlen(token); i++)
66 {
67 if (*string == token[i])
68 {
69 *string = 0;
70 char *old_pos = pos;
71 pos = string + 1;
72
73 return old_pos;
74 }
75 }
76 }
77 return pos;
78}
79
swissChilidab15a62020-08-17 15:41:27 -070080void putshort(uint16_t a, FILE *out)
81{
82 uint16_t le = htole16(a);
83 fwrite(&le, sizeof(uint16_t), 1, out);
84}
85
swissChili97b5d8b2020-08-15 20:00:54 -070086void print_inst(inst_t *arg)
87{
88 char *arg_types =
89 "16 8 8RELREL ABS IMP ";
90
91 printf("\033[33mInst: %.4s $%x ", arg_types + arg->arg_type * 4, arg->opcode);
92
93 switch (arg->arg_type)
94 {
95 case ARG_16:
96 printf("%x", arg->long_arg);
97 break;
98 case ARG_8:
99 printf("%x", arg->byte_arg);
100 break;
101 case ARG_8REL:
102 printf("%d", arg->rel_arg);
103 break;
104 case ARG_REL:
105 case ARG_ABS:
106 printf("%s", arg->label);
107 break;
108 }
109
110 printf("\033[0m\n");
111}
112
113bool is_ident(char c)
114{
swissChilia4f49b52020-08-16 17:35:37 -0700115 return c && (isalpha(c) || isdigit(c)
116 || c == '_' || c == '-'
117 || c == '$' || c == '.');
swissChili97b5d8b2020-08-15 20:00:54 -0700118}
119
120uint32_t skip_ws(char **code)
121{
122 uint32_t len = 0;
123
swissChilia4f49b52020-08-16 17:35:37 -0700124 for (; **code == ' ' || **code == '\t'; (*code)++, len++)
swissChili97b5d8b2020-08-15 20:00:54 -0700125 {}
126
127 return len;
128}
129
130uint32_t skip_to_eol(char **code)
131{
132 uint32_t len = 0;
133
134 for (; **code && **code != '\n'; (*code)++, len++)
135 {}
136
137 if (**code)
138 (*code)++;
139
140 return len;
141}
142
143char *parse_label_name(char **code)
144{
145 char *start = *code;
146 for (; is_ident(**code); (*code)++)
147 {}
148
149 if (start == *code)
150 return false;
151
152 **code = 0;
153 return start;
154}
155
156char *parse_label(char **code)
157{
158 char *start = *code;
159
160 for (; is_ident(**code); (*code)++)
161 {}
162
163 skip_ws(code);
164
swissChilia4f49b52020-08-16 17:35:37 -0700165 if (*code != start && **code == ':')
swissChili97b5d8b2020-08-15 20:00:54 -0700166 {
167 **code = 0;
168 (*code)++;
169 return start;
170 }
swissChilidab15a62020-08-17 15:41:27 -0700171 printf(">> lkl: **code == %c %x\n", **code, **code);
swissChili97b5d8b2020-08-15 20:00:54 -0700172
173 *code = start;
174
175 return NULL;
176}
177
178char *parse_inst(char **code)
179{
180 char *start = *code;
181
182 for (; isalpha(**code); (*code)++)
183 {}
184
swissChili97b5d8b2020-08-15 20:00:54 -0700185 if (start == *code)
186 return NULL;
187
swissChilia4f49b52020-08-16 17:35:37 -0700188 // If code is incremented when it points to \0, it will wrap to the next line
189 // returned by strtok(), which causes a bug where instructions followed immediately
190 // by a newline and no arguments causes the next instruction to parse the entire
191 // program as its argument (not good)
192 if (**code)
193 {
194 **code = 0;
195 (*code)++;
196 }
197
swissChili97b5d8b2020-08-15 20:00:54 -0700198 return start;
199}
200
201bool is_eol(char c)
202{
203 return c == ';' ||
204 c == '\n' ||
swissChili97b5d8b2020-08-15 20:00:54 -0700205 c == '\0';
206}
207
208bool skip(char **code, const char *p)
209{
210 for (; *p && *p == **code; p++, (*code)++)
211 {}
212
213 if (!*p)
214 return true;
215 return false;
216}
217
218bool parse_num(char **code, uint64_t *num)
219{
220 char *start = *code;
221 int base = 10;
222 if (**code == '$')
223 {
224 base = 16;
225 (*code)++;
226 }
227
228 skip_ws(code);
229
230 char *endptr = *code;
231 int64_t val = strtol(*code, &endptr, base);
232
233 if (*code == endptr)
234 {
235 *code = start;
236 return false;
237 }
238 *num = val;
239 *code = endptr;
240 return true;
241}
242
243bool parse_num_max(char **code, uint64_t *num, uint64_t max)
244{
245 uint64_t n;
246 if (parse_num(code, &n))
247 {
248 if (n > max)
249 return false;
250
251 *num = n;
252 return true;
253 }
254 else return false;
255}
256
257bool parse_u8(char **code, uint8_t *num)
258{
259 uint64_t n;
260 if (!parse_num_max(code, &n, 0xFF))
261 return false;
262
263 *num = n & 0xFF;
264 return true;
265}
266
267bool parse_u16(char **code, uint16_t *num)
268{
269 uint64_t n;
270 if (!parse_num_max(code, &n, 0xFFFF))
271 return false;
272
273 *num = n & 0xFFFF;
274 return true;
275}
276
277bool ws_end(char **code)
278{
279 skip_ws(code);
280 return is_eol(**code);
281}
282
283bool parse_arg(char *code, int am, inst_t *inst)
284{
285 skip_ws(&code);
286
287 uint16_t num;
288 uint8_t num8;
289 char *lbl;
290
291 switch (am)
292 {
293 case AM_ACC:
294 case AM_IMP:
295 printf("Trying AM_IMP on '%.8s'\n", code);
296 skip_ws(&code);
297 if (is_eol(*code))
298 {
299 inst->arg_type = ARG_IMP;
300 return ws_end(&code);
301 }
302 break;
303
304 case AM_IMM:
305 printf("Trying AM_IMM on '%.8s'\n", code);
306 if (!skip(&code, "#"))
307 return false;
308 skip_ws(&code);
309 case AM_ZP:
310 if (parse_u8(&code, &num8))
311 {
312 inst->arg_type = ARG_8;
313 inst->byte_arg = num8;
314
315 return ws_end(&code);
316 }
317 break;
318
319 case AM_ABS:
320 if (parse_u16(&code, &num))
321 {
322 inst->arg_type = ARG_16;
323 inst->long_arg = num;
swissChilidab15a62020-08-17 15:41:27 -0700324 return ws_end(&code);
swissChili97b5d8b2020-08-15 20:00:54 -0700325 }
326 else if ((lbl = parse_label_name(&code)))
327 {
328 inst->arg_type = ARG_ABS;
329 strncpy(inst->label, lbl, 32);
swissChilidab15a62020-08-17 15:41:27 -0700330 return ws_end(&code);
swissChili97b5d8b2020-08-15 20:00:54 -0700331 }
332 break;
333
334 case AM_REL:
335 if (parse_u8(&code, &num8))
336 {
337 inst->arg_type = ARG_8REL;
338 inst->rel_arg = num;
339 return ws_end(&code);
340 }
341 else if ((lbl = parse_label_name(&code)))
342 {
343 inst->arg_type = ARG_REL;
344 strncpy(inst->label, lbl, 32);
345 return ws_end(&code);
346 }
347 break;
348
349 case AM_IND:
350 if (!skip(&code,"("))
351 return false;
352
353 if (!parse_u16(&code, &num))
354 return false;
355
356 if (!skip(&code, ")"))
357 return false;
358
359 inst->arg_type = ARG_16;
360 inst->long_arg = num;
swissChilidab15a62020-08-17 15:41:27 -0700361 return ws_end(&code);
swissChili97b5d8b2020-08-15 20:00:54 -0700362
363 case AM_AX:
364 case AM_ZPX:
365 case AM_AY:
366 case AM_ZPY:
367 if (am == AM_AX || am == AM_AY)
368 {
369 if (!parse_u16(&code, &num))
370 return false;
371 inst->arg_type = ARG_16;
372 inst->long_arg = num;
373 }
374 else
375 {
376 if (!parse_u8(&code, &num8))
377 return false;
378 inst->arg_type = ARG_8;
379 inst->byte_arg = num8;
380 }
swissChilidab15a62020-08-17 15:41:27 -0700381 printf("Parsing AM_* worked, now parsing ,\n");
swissChili97b5d8b2020-08-15 20:00:54 -0700382 if (!skip(&code, ","))
383 return false;
384
385 skip_ws(&code);
swissChilidab15a62020-08-17 15:41:27 -0700386 printf(", worked yup\n");
387 char reg = (am == AM_AY || am == AM_ZPY ? 'y' : 'x');
388 printf("reg is %c, *code is %c %x\n", reg, tolower(*code), tolower(*code));
389 if (tolower(*code) != reg)
swissChili97b5d8b2020-08-15 20:00:54 -0700390 return false;
swissChilidab15a62020-08-17 15:41:27 -0700391 (code)++;
swissChili97b5d8b2020-08-15 20:00:54 -0700392 return ws_end(&code);
393
394 case AM_ZIX:
395 if (!skip(&code, "("))
396 break;
397 skip_ws(&code);
398 if (!parse_u8(&code, &num8))
399 break;
400 skip_ws(&code);
401 if (!skip(&code, ","))
402 break;
403 skip_ws(&code);
404 if (tolower(*code) != 'x')
405 return false;
406 skip_ws(&code);
407
408 if (!skip(&code, ")"))
409 break;
410
411 inst->arg_type = ARG_8;
412 inst->byte_arg = num8;
413 return ws_end(&code);
414
415 case AM_ZIY:
416 if (!skip(&code, "("))
417 break;
418 skip_ws(&code);
419 if (!parse_u8(&code, &num8))
420 break;
421 skip_ws(&code);
422 if (!skip(&code, ")"))
423 break;
424 skip_ws(&code);
425 if (!skip(&code, ","))
426 break;
427 skip_ws(&code);
428 if (tolower(*code) != 'x')
429 break;
430
431 inst->arg_type = ARG_8;
432 inst->byte_arg = num8;
433 return ws_end(&code);
434 }
435 return false;
436}
437
swissChilidab15a62020-08-17 15:41:27 -0700438// Since program counter can never be < $600, return 0 on failure
439uint16_t ll_find(ll_node_t *head, char *name)
440{
441 ll_node_t *last = head;
442 while (last)
443 {
444 head = last;
445 if (!strcasecmp(head->name, name))
446 return head->addr;
447 last = head->last;
448 }
449 return 0;
450}
451
swissChili97b5d8b2020-08-15 20:00:54 -0700452uint32_t assemble(char *code, FILE *out)
453{
swissChilidab15a62020-08-17 15:41:27 -0700454 uint16_t num_insts = 0;
455 uint16_t pc = 0x600;
swissChili97b5d8b2020-08-15 20:00:54 -0700456 uint32_t line_no = 1;
swissChilidab15a62020-08-17 15:41:27 -0700457 ll_node_t *last_node = NULL;
swissChili7acb4ce2020-08-16 20:16:10 -0700458 char *line,
459 *orig_line,
460 *line_start;
swissChilidab15a62020-08-17 15:41:27 -0700461 inst_t **insts = calloc(sizeof(inst_t), MAX_INSTS);
swissChili97b5d8b2020-08-15 20:00:54 -0700462
463 printf("Assembling File\n");
464 printf("%s\n", code);
465
swissChili7acb4ce2020-08-16 20:16:10 -0700466 orig_line = strtok_fix(code, "\n");
467
468 while (orig_line)
swissChili97b5d8b2020-08-15 20:00:54 -0700469 {
swissChili7acb4ce2020-08-16 20:16:10 -0700470 line = strdup(orig_line);
471 line_start = line;
472
473 if (*line == 0)
474 goto end_of_line;
swissChili7acb4ce2020-08-16 20:16:10 -0700475
swissChili97b5d8b2020-08-15 20:00:54 -0700476 skip_ws(&line);
swissChilidab15a62020-08-17 15:41:27 -0700477
478 printf("line %d: \033[36m%.12s\033[0m\n", line_no, line);
479
swissChili7acb4ce2020-08-16 20:16:10 -0700480 if (is_eol(*line))
481 {
482 printf("skip_ws() brought us to EOL\n");
483 goto end_of_line;
484 }
swissChili97b5d8b2020-08-15 20:00:54 -0700485
swissChilia4f49b52020-08-16 17:35:37 -0700486 char *label = parse_label(&line);
swissChilidab15a62020-08-17 15:41:27 -0700487 printf(">> label == %.5s %p\n", label, label);
swissChili7acb4ce2020-08-16 20:16:10 -0700488 skip_ws(&code);
swissChilidab15a62020-08-17 15:41:27 -0700489 //if (is_eol(*line))
490 // goto end_of_line;
swissChilia4f49b52020-08-16 17:35:37 -0700491 char *mn = parse_inst(&line);
swissChilia4f49b52020-08-16 17:35:37 -0700492
493 bool no_argument = false;
swissChilia4f49b52020-08-16 17:35:37 -0700494 if (is_eol(*line))
495 {
496 no_argument = true;
swissChilia4f49b52020-08-16 17:35:37 -0700497 }
swissChili97b5d8b2020-08-15 20:00:54 -0700498 int32_t mnemonic = -1;
499
500 if (label)
501 {
swissChilidab15a62020-08-17 15:41:27 -0700502 printf("Storing label %s\n", label);
503 ll_node_t *head = malloc(sizeof(ll_node_t));
504 head->last = last_node;
505 strncpy(head->name, label, 32);
506 // strncpy won't zero the last byte if its over 32 bytes long
507 head->name[31] = 0;
508 head->addr = pc;
509 last_node = head;
510 printf("Set label %s at $%x\n", label, pc);
swissChili97b5d8b2020-08-15 20:00:54 -0700511 }
512
513 if (mn)
514 {
515#define MN(a) if (!strcasecmp(mn, #a)) \
swissChilica0d2e22020-08-16 15:09:25 -0700516 { \
swissChili97b5d8b2020-08-15 20:00:54 -0700517 mnemonic = a; \
swissChilica0d2e22020-08-16 15:09:25 -0700518 } \
swissChili97b5d8b2020-08-15 20:00:54 -0700519 else
520
swissChili7acb4ce2020-08-16 20:16:10 -0700521 MNEMONICS
522 {
523 printf(ERR "Could not parse instruction on line %d\n%s\n" RESET, line_no, orig_line);
swissChilidab15a62020-08-17 15:41:27 -0700524 free(line_start);
swissChili7acb4ce2020-08-16 20:16:10 -0700525 goto cleanup;
526 }
swissChili97b5d8b2020-08-15 20:00:54 -0700527#undef MN
528
529 printf("Got instruction %s %d\n", mn, mnemonic);
530
swissChilidab15a62020-08-17 15:41:27 -0700531 inst_t *arg = malloc(sizeof(inst_t));
532 arg->line = line_no;
swissChili97b5d8b2020-08-15 20:00:54 -0700533 // printf("Parsing '%s'\n", line);
534#define INST(_mn, am, op, len) \
swissChilia4f49b52020-08-16 17:35:37 -0700535 if ((no_argument && (_mn == AM_IMP || _mn == AM_ACC)) \
swissChilidab15a62020-08-17 15:41:27 -0700536 || (mnemonic == _mn && parse_arg(line, am, arg))) \
swissChilia4f49b52020-08-16 17:35:37 -0700537 { \
swissChili6a923012020-08-18 17:47:27 -0700538 printf(GREEN "AM_ succeeded: %s at pc=$%x\n" RESET, \
539 #am, pc); \
swissChilidab15a62020-08-17 15:41:27 -0700540 arg->opcode = op; \
swissChilia4f49b52020-08-16 17:35:37 -0700541 pc += len; \
swissChilidab15a62020-08-17 15:41:27 -0700542 print_inst(arg); \
swissChilia4f49b52020-08-16 17:35:37 -0700543 } \
swissChili97b5d8b2020-08-15 20:00:54 -0700544 else
545
546 INSTRUCTIONS
547 {
548 printf("\033[31mCould not be parsed: %s '%s'\033[0m\n", mn, line);
swissChilidab15a62020-08-17 15:41:27 -0700549 free(line_start);
550 goto cleanup;
swissChili97b5d8b2020-08-15 20:00:54 -0700551 }
552#undef INST
swissChilidab15a62020-08-17 15:41:27 -0700553
554 insts[num_insts++] = arg;
swissChili97b5d8b2020-08-15 20:00:54 -0700555 }
swissChili7acb4ce2020-08-16 20:16:10 -0700556 end_of_line:
557 line_no++;
swissChili7acb4ce2020-08-16 20:16:10 -0700558 orig_line = strtok_fix(NULL, "\n");
559 free(line_start);
swissChili97b5d8b2020-08-15 20:00:54 -0700560 }
561
swissChilidab15a62020-08-17 15:41:27 -0700562 // Generate machine code
563 for (int i = 0, curr_pc = 0x600; insts[i]; i++)
564 {
565 putc(insts[i]->opcode, out);
566
567 switch (insts[i]->arg_type)
568 {
569 case ARG_8:
570 putc(insts[i]->byte_arg, out);
571 curr_pc += 2;
572 break;
573 case ARG_16:
574 putshort(insts[i]->long_arg, out);
575 curr_pc += 3;
576 break;
577 case ARG_8REL:
578 putc(insts[i]->rel_arg, out);
579 curr_pc += 2;
580 break;
581 case ARG_ABS:
582 {
583 uint16_t lbl;
584 if (!(lbl = ll_find(last_node, insts[i]->label)))
585 {
586 printf(ERR "Error on line %d: label '%s' is not defined" RESET "\n", insts[i]->line, insts[i]->label);
587 goto cleanup;
588 }
589 curr_pc += 3;
590
591 putshort(lbl, out);
592 break;
593 }
594 case ARG_REL:
595 {
596 uint16_t lbl;
597 if (!(lbl = ll_find(last_node, insts[i]->label)))
598 {
599 printf(ERR "Error on line %d: label '%s' is not defined" RESET "\n", insts[i]->line, insts[i]->label);
600 goto cleanup;
601 }
602 curr_pc += 2;
603 int16_t diff = lbl - curr_pc;
swissChili6a923012020-08-18 17:47:27 -0700604 printf("ARG_REL, pc (after) == %x, diff = %hx\n", curr_pc, (uint8_t) diff);
swissChilidab15a62020-08-17 15:41:27 -0700605 if ((diff < 0 ? -diff : diff) > 0xFF)
606 {
607 printf(ERR "Error on line %d: label '%s' is too far away for a relative jump" RESET "\n", insts[i]->line, insts[i]->label);
608 printf("pc == %hx, label is at %hx\n", curr_pc, lbl);
609 goto cleanup;
610 }
swissChili6a923012020-08-18 17:47:27 -0700611 putc((uint8_t) diff, out);
swissChilidab15a62020-08-17 15:41:27 -0700612 break;
613 }
614 default:
615 curr_pc++;
616 }
617 }
swissChili6a923012020-08-18 17:47:27 -0700618
swissChili7acb4ce2020-08-16 20:16:10 -0700619cleanup:
swissChilidab15a62020-08-17 15:41:27 -0700620 printf("-----\n");
621 printf("At end, there are %d instructions\n", num_insts);
622 while (last_node)
623 {
624 ll_node_t *curr_node = last_node;
625 last_node = curr_node->last;
626 free(curr_node);
627 }
628 for (int i = 0; insts[i]; i++)
629 free(insts[i]);
630 free(insts);
631 fflush(out);
swissChili97b5d8b2020-08-15 20:00:54 -0700632
633 return num_insts;
634}