blob: 1d72d97fa5301271be3ae689eca815495182809f [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"
24#define RESET "\033[0m"
swissChilidab15a62020-08-17 15:41:27 -070025#define MAX_LEN (0xFFFF - 0x600)
26#define MAX_INSTS (MAX_LEN / 2)
swissChili7acb4ce2020-08-16 20:16:10 -070027
swissChili97b5d8b2020-08-15 20:00:54 -070028typedef struct
29{
30 uint8_t opcode;
31 uint8_t arg_type;
swissChili7acb4ce2020-08-16 20:16:10 -070032 uint16_t line;
swissChili97b5d8b2020-08-15 20:00:54 -070033 union
34 {
35 char label[32];
36 uint16_t long_arg;
37 uint8_t byte_arg;
38 int8_t rel_arg;
39 };
40} inst_t;
41
swissChilidab15a62020-08-17 15:41:27 -070042typedef struct ll_node
43{
44 struct ll_node *last;
45 char name[32];
46 uint16_t addr;
47} ll_node_t;
48
swissChili7acb4ce2020-08-16 20:16:10 -070049// Normal strtok() counts 2 seperators as one, ie asdf\n\njlk is 2 lines.
50// This functions counts that as 3 lines, and will return an empty line in between.
51char *strtok_fix(char *string, const char *token)
52{
53 static char *pos;
54 if (string)
55 pos = string;
56 else
57 string = pos;
58
59 if (*pos == 0)
60 return NULL;
61
62 for (; *string; string++)
63 {
64 for (int i = 0; i < strlen(token); i++)
65 {
66 if (*string == token[i])
67 {
68 *string = 0;
69 char *old_pos = pos;
70 pos = string + 1;
71
72 return old_pos;
73 }
74 }
75 }
76 return pos;
77}
78
swissChilidab15a62020-08-17 15:41:27 -070079void putshort(uint16_t a, FILE *out)
80{
81 uint16_t le = htole16(a);
82 fwrite(&le, sizeof(uint16_t), 1, out);
83}
84
swissChili97b5d8b2020-08-15 20:00:54 -070085void print_inst(inst_t *arg)
86{
87 char *arg_types =
88 "16 8 8RELREL ABS IMP ";
89
90 printf("\033[33mInst: %.4s $%x ", arg_types + arg->arg_type * 4, arg->opcode);
91
92 switch (arg->arg_type)
93 {
94 case ARG_16:
95 printf("%x", arg->long_arg);
96 break;
97 case ARG_8:
98 printf("%x", arg->byte_arg);
99 break;
100 case ARG_8REL:
101 printf("%d", arg->rel_arg);
102 break;
103 case ARG_REL:
104 case ARG_ABS:
105 printf("%s", arg->label);
106 break;
107 }
108
109 printf("\033[0m\n");
110}
111
112bool is_ident(char c)
113{
swissChilia4f49b52020-08-16 17:35:37 -0700114 return c && (isalpha(c) || isdigit(c)
115 || c == '_' || c == '-'
116 || c == '$' || c == '.');
swissChili97b5d8b2020-08-15 20:00:54 -0700117}
118
119uint32_t skip_ws(char **code)
120{
121 uint32_t len = 0;
122
swissChilia4f49b52020-08-16 17:35:37 -0700123 for (; **code == ' ' || **code == '\t'; (*code)++, len++)
swissChili97b5d8b2020-08-15 20:00:54 -0700124 {}
125
126 return len;
127}
128
129uint32_t skip_to_eol(char **code)
130{
131 uint32_t len = 0;
132
133 for (; **code && **code != '\n'; (*code)++, len++)
134 {}
135
136 if (**code)
137 (*code)++;
138
139 return len;
140}
141
142char *parse_label_name(char **code)
143{
144 char *start = *code;
145 for (; is_ident(**code); (*code)++)
146 {}
147
148 if (start == *code)
149 return false;
150
151 **code = 0;
152 return start;
153}
154
155char *parse_label(char **code)
156{
157 char *start = *code;
158
159 for (; is_ident(**code); (*code)++)
160 {}
161
162 skip_ws(code);
163
swissChilia4f49b52020-08-16 17:35:37 -0700164 if (*code != start && **code == ':')
swissChili97b5d8b2020-08-15 20:00:54 -0700165 {
166 **code = 0;
167 (*code)++;
168 return start;
169 }
swissChilidab15a62020-08-17 15:41:27 -0700170 printf(">> lkl: **code == %c %x\n", **code, **code);
swissChili97b5d8b2020-08-15 20:00:54 -0700171
172 *code = start;
173
174 return NULL;
175}
176
177char *parse_inst(char **code)
178{
179 char *start = *code;
180
181 for (; isalpha(**code); (*code)++)
182 {}
183
swissChili97b5d8b2020-08-15 20:00:54 -0700184 if (start == *code)
185 return NULL;
186
swissChilia4f49b52020-08-16 17:35:37 -0700187 // If code is incremented when it points to \0, it will wrap to the next line
188 // returned by strtok(), which causes a bug where instructions followed immediately
189 // by a newline and no arguments causes the next instruction to parse the entire
190 // program as its argument (not good)
191 if (**code)
192 {
193 **code = 0;
194 (*code)++;
195 }
196
swissChili97b5d8b2020-08-15 20:00:54 -0700197 return start;
198}
199
200bool is_eol(char c)
201{
202 return c == ';' ||
203 c == '\n' ||
swissChili97b5d8b2020-08-15 20:00:54 -0700204 c == '\0';
205}
206
207bool skip(char **code, const char *p)
208{
209 for (; *p && *p == **code; p++, (*code)++)
210 {}
211
212 if (!*p)
213 return true;
214 return false;
215}
216
217bool parse_num(char **code, uint64_t *num)
218{
219 char *start = *code;
220 int base = 10;
221 if (**code == '$')
222 {
223 base = 16;
224 (*code)++;
225 }
226
227 skip_ws(code);
228
229 char *endptr = *code;
230 int64_t val = strtol(*code, &endptr, base);
231
232 if (*code == endptr)
233 {
234 *code = start;
235 return false;
236 }
237 *num = val;
238 *code = endptr;
239 return true;
240}
241
242bool parse_num_max(char **code, uint64_t *num, uint64_t max)
243{
244 uint64_t n;
245 if (parse_num(code, &n))
246 {
247 if (n > max)
248 return false;
249
250 *num = n;
251 return true;
252 }
253 else return false;
254}
255
256bool parse_u8(char **code, uint8_t *num)
257{
258 uint64_t n;
259 if (!parse_num_max(code, &n, 0xFF))
260 return false;
261
262 *num = n & 0xFF;
263 return true;
264}
265
266bool parse_u16(char **code, uint16_t *num)
267{
268 uint64_t n;
269 if (!parse_num_max(code, &n, 0xFFFF))
270 return false;
271
272 *num = n & 0xFFFF;
273 return true;
274}
275
276bool ws_end(char **code)
277{
278 skip_ws(code);
279 return is_eol(**code);
280}
281
282bool parse_arg(char *code, int am, inst_t *inst)
283{
284 skip_ws(&code);
285
286 uint16_t num;
287 uint8_t num8;
288 char *lbl;
289
290 switch (am)
291 {
292 case AM_ACC:
293 case AM_IMP:
294 printf("Trying AM_IMP on '%.8s'\n", code);
295 skip_ws(&code);
296 if (is_eol(*code))
297 {
298 inst->arg_type = ARG_IMP;
299 return ws_end(&code);
300 }
301 break;
302
303 case AM_IMM:
304 printf("Trying AM_IMM on '%.8s'\n", code);
305 if (!skip(&code, "#"))
306 return false;
307 skip_ws(&code);
308 case AM_ZP:
309 if (parse_u8(&code, &num8))
310 {
311 inst->arg_type = ARG_8;
312 inst->byte_arg = num8;
313
314 return ws_end(&code);
315 }
316 break;
317
318 case AM_ABS:
319 if (parse_u16(&code, &num))
320 {
321 inst->arg_type = ARG_16;
322 inst->long_arg = num;
swissChilidab15a62020-08-17 15:41:27 -0700323 return ws_end(&code);
swissChili97b5d8b2020-08-15 20:00:54 -0700324 }
325 else if ((lbl = parse_label_name(&code)))
326 {
327 inst->arg_type = ARG_ABS;
328 strncpy(inst->label, lbl, 32);
swissChilidab15a62020-08-17 15:41:27 -0700329 return ws_end(&code);
swissChili97b5d8b2020-08-15 20:00:54 -0700330 }
331 break;
332
333 case AM_REL:
334 if (parse_u8(&code, &num8))
335 {
336 inst->arg_type = ARG_8REL;
337 inst->rel_arg = num;
338 return ws_end(&code);
339 }
340 else if ((lbl = parse_label_name(&code)))
341 {
342 inst->arg_type = ARG_REL;
343 strncpy(inst->label, lbl, 32);
344 return ws_end(&code);
345 }
346 break;
347
348 case AM_IND:
349 if (!skip(&code,"("))
350 return false;
351
352 if (!parse_u16(&code, &num))
353 return false;
354
355 if (!skip(&code, ")"))
356 return false;
357
358 inst->arg_type = ARG_16;
359 inst->long_arg = num;
swissChilidab15a62020-08-17 15:41:27 -0700360 return ws_end(&code);
swissChili97b5d8b2020-08-15 20:00:54 -0700361
362 case AM_AX:
363 case AM_ZPX:
364 case AM_AY:
365 case AM_ZPY:
366 if (am == AM_AX || am == AM_AY)
367 {
368 if (!parse_u16(&code, &num))
369 return false;
370 inst->arg_type = ARG_16;
371 inst->long_arg = num;
372 }
373 else
374 {
375 if (!parse_u8(&code, &num8))
376 return false;
377 inst->arg_type = ARG_8;
378 inst->byte_arg = num8;
379 }
swissChilidab15a62020-08-17 15:41:27 -0700380 printf("Parsing AM_* worked, now parsing ,\n");
swissChili97b5d8b2020-08-15 20:00:54 -0700381 if (!skip(&code, ","))
382 return false;
383
384 skip_ws(&code);
swissChilidab15a62020-08-17 15:41:27 -0700385 printf(", worked yup\n");
386 char reg = (am == AM_AY || am == AM_ZPY ? 'y' : 'x');
387 printf("reg is %c, *code is %c %x\n", reg, tolower(*code), tolower(*code));
388 if (tolower(*code) != reg)
swissChili97b5d8b2020-08-15 20:00:54 -0700389 return false;
swissChilidab15a62020-08-17 15:41:27 -0700390 (code)++;
swissChili97b5d8b2020-08-15 20:00:54 -0700391 return ws_end(&code);
392
393 case AM_ZIX:
394 if (!skip(&code, "("))
395 break;
396 skip_ws(&code);
397 if (!parse_u8(&code, &num8))
398 break;
399 skip_ws(&code);
400 if (!skip(&code, ","))
401 break;
402 skip_ws(&code);
403 if (tolower(*code) != 'x')
404 return false;
405 skip_ws(&code);
406
407 if (!skip(&code, ")"))
408 break;
409
410 inst->arg_type = ARG_8;
411 inst->byte_arg = num8;
412 return ws_end(&code);
413
414 case AM_ZIY:
415 if (!skip(&code, "("))
416 break;
417 skip_ws(&code);
418 if (!parse_u8(&code, &num8))
419 break;
420 skip_ws(&code);
421 if (!skip(&code, ")"))
422 break;
423 skip_ws(&code);
424 if (!skip(&code, ","))
425 break;
426 skip_ws(&code);
427 if (tolower(*code) != 'x')
428 break;
429
430 inst->arg_type = ARG_8;
431 inst->byte_arg = num8;
432 return ws_end(&code);
433 }
434 return false;
435}
436
swissChilidab15a62020-08-17 15:41:27 -0700437// Since program counter can never be < $600, return 0 on failure
438uint16_t ll_find(ll_node_t *head, char *name)
439{
440 ll_node_t *last = head;
441 while (last)
442 {
443 head = last;
444 if (!strcasecmp(head->name, name))
445 return head->addr;
446 last = head->last;
447 }
448 return 0;
449}
450
swissChili97b5d8b2020-08-15 20:00:54 -0700451uint32_t assemble(char *code, FILE *out)
452{
swissChilidab15a62020-08-17 15:41:27 -0700453 uint16_t num_insts = 0;
454 uint16_t pc = 0x600;
swissChili97b5d8b2020-08-15 20:00:54 -0700455 uint32_t line_no = 1;
swissChilidab15a62020-08-17 15:41:27 -0700456 ll_node_t *last_node = NULL;
swissChili7acb4ce2020-08-16 20:16:10 -0700457 char *line,
458 *orig_line,
459 *line_start;
swissChilidab15a62020-08-17 15:41:27 -0700460 inst_t **insts = calloc(sizeof(inst_t), MAX_INSTS);
swissChili97b5d8b2020-08-15 20:00:54 -0700461
462 printf("Assembling File\n");
463 printf("%s\n", code);
464
swissChili7acb4ce2020-08-16 20:16:10 -0700465 orig_line = strtok_fix(code, "\n");
466
467 while (orig_line)
swissChili97b5d8b2020-08-15 20:00:54 -0700468 {
swissChili7acb4ce2020-08-16 20:16:10 -0700469 line = strdup(orig_line);
470 line_start = line;
471
472 if (*line == 0)
473 goto end_of_line;
swissChili7acb4ce2020-08-16 20:16:10 -0700474
swissChili97b5d8b2020-08-15 20:00:54 -0700475 skip_ws(&line);
swissChilidab15a62020-08-17 15:41:27 -0700476
477 printf("line %d: \033[36m%.12s\033[0m\n", line_no, line);
478
swissChili7acb4ce2020-08-16 20:16:10 -0700479 if (is_eol(*line))
480 {
481 printf("skip_ws() brought us to EOL\n");
482 goto end_of_line;
483 }
swissChili97b5d8b2020-08-15 20:00:54 -0700484
swissChilia4f49b52020-08-16 17:35:37 -0700485 char *label = parse_label(&line);
swissChilidab15a62020-08-17 15:41:27 -0700486 printf(">> label == %.5s %p\n", label, label);
swissChili7acb4ce2020-08-16 20:16:10 -0700487 skip_ws(&code);
swissChilidab15a62020-08-17 15:41:27 -0700488 //if (is_eol(*line))
489 // goto end_of_line;
swissChilia4f49b52020-08-16 17:35:37 -0700490 char *mn = parse_inst(&line);
swissChilia4f49b52020-08-16 17:35:37 -0700491
492 bool no_argument = false;
swissChilia4f49b52020-08-16 17:35:37 -0700493 if (is_eol(*line))
494 {
495 no_argument = true;
swissChilia4f49b52020-08-16 17:35:37 -0700496 }
swissChili97b5d8b2020-08-15 20:00:54 -0700497 int32_t mnemonic = -1;
498
499 if (label)
500 {
swissChilidab15a62020-08-17 15:41:27 -0700501 printf("Storing label %s\n", label);
502 ll_node_t *head = malloc(sizeof(ll_node_t));
503 head->last = last_node;
504 strncpy(head->name, label, 32);
505 // strncpy won't zero the last byte if its over 32 bytes long
506 head->name[31] = 0;
507 head->addr = pc;
508 last_node = head;
509 printf("Set label %s at $%x\n", label, pc);
swissChili97b5d8b2020-08-15 20:00:54 -0700510 }
511
512 if (mn)
513 {
514#define MN(a) if (!strcasecmp(mn, #a)) \
swissChilica0d2e22020-08-16 15:09:25 -0700515 { \
swissChili97b5d8b2020-08-15 20:00:54 -0700516 mnemonic = a; \
swissChilica0d2e22020-08-16 15:09:25 -0700517 } \
swissChili97b5d8b2020-08-15 20:00:54 -0700518 else
519
swissChili7acb4ce2020-08-16 20:16:10 -0700520 MNEMONICS
521 {
522 printf(ERR "Could not parse instruction on line %d\n%s\n" RESET, line_no, orig_line);
swissChilidab15a62020-08-17 15:41:27 -0700523 free(line_start);
swissChili7acb4ce2020-08-16 20:16:10 -0700524 goto cleanup;
525 }
swissChili97b5d8b2020-08-15 20:00:54 -0700526#undef MN
527
528 printf("Got instruction %s %d\n", mn, mnemonic);
529
swissChilidab15a62020-08-17 15:41:27 -0700530 inst_t *arg = malloc(sizeof(inst_t));
531 arg->line = line_no;
swissChili97b5d8b2020-08-15 20:00:54 -0700532 // printf("Parsing '%s'\n", line);
533#define INST(_mn, am, op, len) \
swissChilia4f49b52020-08-16 17:35:37 -0700534 if ((no_argument && (_mn == AM_IMP || _mn == AM_ACC)) \
swissChilidab15a62020-08-17 15:41:27 -0700535 || (mnemonic == _mn && parse_arg(line, am, arg))) \
swissChilia4f49b52020-08-16 17:35:37 -0700536 { \
swissChilidab15a62020-08-17 15:41:27 -0700537 printf("AM_ succeeded: %s\n", #am); \
538 arg->opcode = op; \
swissChilia4f49b52020-08-16 17:35:37 -0700539 pc += len; \
swissChilidab15a62020-08-17 15:41:27 -0700540 print_inst(arg); \
swissChilia4f49b52020-08-16 17:35:37 -0700541 } \
swissChili97b5d8b2020-08-15 20:00:54 -0700542 else
543
544 INSTRUCTIONS
545 {
546 printf("\033[31mCould not be parsed: %s '%s'\033[0m\n", mn, line);
swissChilidab15a62020-08-17 15:41:27 -0700547 free(line_start);
548 goto cleanup;
swissChili97b5d8b2020-08-15 20:00:54 -0700549 }
550#undef INST
swissChilidab15a62020-08-17 15:41:27 -0700551
552 insts[num_insts++] = arg;
swissChili97b5d8b2020-08-15 20:00:54 -0700553 }
swissChili7acb4ce2020-08-16 20:16:10 -0700554 end_of_line:
555 line_no++;
swissChili7acb4ce2020-08-16 20:16:10 -0700556 orig_line = strtok_fix(NULL, "\n");
557 free(line_start);
swissChili97b5d8b2020-08-15 20:00:54 -0700558 }
559
swissChilidab15a62020-08-17 15:41:27 -0700560 // Generate machine code
561 for (int i = 0, curr_pc = 0x600; insts[i]; i++)
562 {
563 putc(insts[i]->opcode, out);
564
565 switch (insts[i]->arg_type)
566 {
567 case ARG_8:
568 putc(insts[i]->byte_arg, out);
569 curr_pc += 2;
570 break;
571 case ARG_16:
572 putshort(insts[i]->long_arg, out);
573 curr_pc += 3;
574 break;
575 case ARG_8REL:
576 putc(insts[i]->rel_arg, out);
577 curr_pc += 2;
578 break;
579 case ARG_ABS:
580 {
581 uint16_t lbl;
582 if (!(lbl = ll_find(last_node, insts[i]->label)))
583 {
584 printf(ERR "Error on line %d: label '%s' is not defined" RESET "\n", insts[i]->line, insts[i]->label);
585 goto cleanup;
586 }
587 curr_pc += 3;
588
589 putshort(lbl, out);
590 break;
591 }
592 case ARG_REL:
593 {
594 uint16_t lbl;
595 if (!(lbl = ll_find(last_node, insts[i]->label)))
596 {
597 printf(ERR "Error on line %d: label '%s' is not defined" RESET "\n", insts[i]->line, insts[i]->label);
598 goto cleanup;
599 }
600 curr_pc += 2;
601 int16_t diff = lbl - curr_pc;
602 printf("ARG_REL, pc (after) == %x, diff = %d\n", curr_pc, diff);
603 if ((diff < 0 ? -diff : diff) > 0xFF)
604 {
605 printf(ERR "Error on line %d: label '%s' is too far away for a relative jump" RESET "\n", insts[i]->line, insts[i]->label);
606 printf("pc == %hx, label is at %hx\n", curr_pc, lbl);
607 goto cleanup;
608 }
609 putshort((uint8_t) diff, out);
610 break;
611 }
612 default:
613 curr_pc++;
614 }
615 }
616
swissChili7acb4ce2020-08-16 20:16:10 -0700617cleanup:
swissChilidab15a62020-08-17 15:41:27 -0700618 printf("-----\n");
619 printf("At end, there are %d instructions\n", num_insts);
620 while (last_node)
621 {
622 ll_node_t *curr_node = last_node;
623 last_node = curr_node->last;
624 free(curr_node);
625 }
626 for (int i = 0; insts[i]; i++)
627 free(insts[i]);
628 free(insts);
629 fflush(out);
swissChili97b5d8b2020-08-15 20:00:54 -0700630
631 return num_insts;
632}