blob: f85bc213f875df18da3705bc9d17be67bdcc2d89 [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
swissChilidab15a62020-08-17 15:41:27 -070023#define MAX_LEN (0xFFFF - 0x600)
24#define MAX_INSTS (MAX_LEN / 2)
swissChili7acb4ce2020-08-16 20:16:10 -070025
swissChili97b5d8b2020-08-15 20:00:54 -070026typedef struct
27{
28 uint8_t opcode;
29 uint8_t arg_type;
swissChili7acb4ce2020-08-16 20:16:10 -070030 uint16_t line;
swissChili97b5d8b2020-08-15 20:00:54 -070031 union
32 {
33 char label[32];
34 uint16_t long_arg;
35 uint8_t byte_arg;
36 int8_t rel_arg;
37 };
38} inst_t;
39
swissChilidab15a62020-08-17 15:41:27 -070040typedef struct ll_node
41{
42 struct ll_node *last;
43 char name[32];
44 uint16_t addr;
45} ll_node_t;
46
swissChili7acb4ce2020-08-16 20:16:10 -070047// Normal strtok() counts 2 seperators as one, ie asdf\n\njlk is 2 lines.
48// This functions counts that as 3 lines, and will return an empty line in between.
49char *strtok_fix(char *string, const char *token)
50{
51 static char *pos;
52 if (string)
53 pos = string;
54 else
55 string = pos;
56
57 if (*pos == 0)
58 return NULL;
59
60 for (; *string; string++)
61 {
62 for (int i = 0; i < strlen(token); i++)
63 {
64 if (*string == token[i])
65 {
66 *string = 0;
67 char *old_pos = pos;
68 pos = string + 1;
69
70 return old_pos;
71 }
72 }
73 }
74 return pos;
75}
76
swissChilidab15a62020-08-17 15:41:27 -070077void putshort(uint16_t a, FILE *out)
78{
79 uint16_t le = htole16(a);
80 fwrite(&le, sizeof(uint16_t), 1, out);
81}
82
swissChili97b5d8b2020-08-15 20:00:54 -070083void print_inst(inst_t *arg)
84{
85 char *arg_types =
86 "16 8 8RELREL ABS IMP ";
87
88 printf("\033[33mInst: %.4s $%x ", arg_types + arg->arg_type * 4, arg->opcode);
89
90 switch (arg->arg_type)
91 {
92 case ARG_16:
93 printf("%x", arg->long_arg);
94 break;
95 case ARG_8:
96 printf("%x", arg->byte_arg);
97 break;
98 case ARG_8REL:
99 printf("%d", arg->rel_arg);
100 break;
101 case ARG_REL:
102 case ARG_ABS:
103 printf("%s", arg->label);
104 break;
105 }
106
107 printf("\033[0m\n");
108}
109
110bool is_ident(char c)
111{
swissChilia4f49b52020-08-16 17:35:37 -0700112 return c && (isalpha(c) || isdigit(c)
113 || c == '_' || c == '-'
114 || c == '$' || c == '.');
swissChili97b5d8b2020-08-15 20:00:54 -0700115}
116
117uint32_t skip_ws(char **code)
118{
119 uint32_t len = 0;
120
swissChilia4f49b52020-08-16 17:35:37 -0700121 for (; **code == ' ' || **code == '\t'; (*code)++, len++)
swissChili97b5d8b2020-08-15 20:00:54 -0700122 {}
123
124 return len;
125}
126
127uint32_t skip_to_eol(char **code)
128{
129 uint32_t len = 0;
130
131 for (; **code && **code != '\n'; (*code)++, len++)
132 {}
133
134 if (**code)
135 (*code)++;
136
137 return len;
138}
139
140char *parse_label_name(char **code)
141{
142 char *start = *code;
143 for (; is_ident(**code); (*code)++)
144 {}
145
146 if (start == *code)
147 return false;
148
149 **code = 0;
150 return start;
151}
152
153char *parse_label(char **code)
154{
155 char *start = *code;
156
157 for (; is_ident(**code); (*code)++)
158 {}
159
160 skip_ws(code);
161
swissChilia4f49b52020-08-16 17:35:37 -0700162 if (*code != start && **code == ':')
swissChili97b5d8b2020-08-15 20:00:54 -0700163 {
164 **code = 0;
165 (*code)++;
166 return start;
167 }
swissChilidab15a62020-08-17 15:41:27 -0700168 printf(">> lkl: **code == %c %x\n", **code, **code);
swissChili97b5d8b2020-08-15 20:00:54 -0700169
170 *code = start;
171
172 return NULL;
173}
174
175char *parse_inst(char **code)
176{
177 char *start = *code;
178
179 for (; isalpha(**code); (*code)++)
180 {}
181
swissChili97b5d8b2020-08-15 20:00:54 -0700182 if (start == *code)
183 return NULL;
184
swissChilia4f49b52020-08-16 17:35:37 -0700185 // If code is incremented when it points to \0, it will wrap to the next line
186 // returned by strtok(), which causes a bug where instructions followed immediately
187 // by a newline and no arguments causes the next instruction to parse the entire
188 // program as its argument (not good)
189 if (**code)
190 {
191 **code = 0;
192 (*code)++;
193 }
194
swissChili97b5d8b2020-08-15 20:00:54 -0700195 return start;
196}
197
198bool is_eol(char c)
199{
200 return c == ';' ||
201 c == '\n' ||
swissChili97b5d8b2020-08-15 20:00:54 -0700202 c == '\0';
203}
204
205bool skip(char **code, const char *p)
206{
207 for (; *p && *p == **code; p++, (*code)++)
208 {}
209
210 if (!*p)
211 return true;
212 return false;
213}
214
215bool parse_num(char **code, uint64_t *num)
216{
217 char *start = *code;
218 int base = 10;
219 if (**code == '$')
220 {
221 base = 16;
222 (*code)++;
223 }
224
225 skip_ws(code);
226
227 char *endptr = *code;
228 int64_t val = strtol(*code, &endptr, base);
229
230 if (*code == endptr)
231 {
232 *code = start;
233 return false;
234 }
235 *num = val;
236 *code = endptr;
237 return true;
238}
239
240bool parse_num_max(char **code, uint64_t *num, uint64_t max)
241{
242 uint64_t n;
243 if (parse_num(code, &n))
244 {
245 if (n > max)
246 return false;
247
248 *num = n;
249 return true;
250 }
251 else return false;
252}
253
254bool parse_u8(char **code, uint8_t *num)
255{
256 uint64_t n;
257 if (!parse_num_max(code, &n, 0xFF))
258 return false;
259
260 *num = n & 0xFF;
261 return true;
262}
263
264bool parse_u16(char **code, uint16_t *num)
265{
266 uint64_t n;
267 if (!parse_num_max(code, &n, 0xFFFF))
268 return false;
269
270 *num = n & 0xFFFF;
271 return true;
272}
273
274bool ws_end(char **code)
275{
276 skip_ws(code);
277 return is_eol(**code);
278}
279
280bool parse_arg(char *code, int am, inst_t *inst)
281{
282 skip_ws(&code);
283
284 uint16_t num;
285 uint8_t num8;
286 char *lbl;
287
288 switch (am)
289 {
290 case AM_ACC:
291 case AM_IMP:
292 printf("Trying AM_IMP on '%.8s'\n", code);
293 skip_ws(&code);
294 if (is_eol(*code))
295 {
296 inst->arg_type = ARG_IMP;
297 return ws_end(&code);
298 }
299 break;
300
301 case AM_IMM:
302 printf("Trying AM_IMM on '%.8s'\n", code);
303 if (!skip(&code, "#"))
304 return false;
305 skip_ws(&code);
306 case AM_ZP:
307 if (parse_u8(&code, &num8))
308 {
309 inst->arg_type = ARG_8;
310 inst->byte_arg = num8;
311
312 return ws_end(&code);
313 }
314 break;
315
316 case AM_ABS:
317 if (parse_u16(&code, &num))
318 {
319 inst->arg_type = ARG_16;
320 inst->long_arg = num;
swissChilidab15a62020-08-17 15:41:27 -0700321 return ws_end(&code);
swissChili97b5d8b2020-08-15 20:00:54 -0700322 }
323 else if ((lbl = parse_label_name(&code)))
324 {
325 inst->arg_type = ARG_ABS;
326 strncpy(inst->label, lbl, 32);
swissChilidab15a62020-08-17 15:41:27 -0700327 return ws_end(&code);
swissChili97b5d8b2020-08-15 20:00:54 -0700328 }
329 break;
330
331 case AM_REL:
332 if (parse_u8(&code, &num8))
333 {
334 inst->arg_type = ARG_8REL;
335 inst->rel_arg = num;
336 return ws_end(&code);
337 }
338 else if ((lbl = parse_label_name(&code)))
339 {
340 inst->arg_type = ARG_REL;
341 strncpy(inst->label, lbl, 32);
342 return ws_end(&code);
343 }
344 break;
345
346 case AM_IND:
347 if (!skip(&code,"("))
348 return false;
349
350 if (!parse_u16(&code, &num))
351 return false;
352
353 if (!skip(&code, ")"))
354 return false;
355
356 inst->arg_type = ARG_16;
357 inst->long_arg = num;
swissChilidab15a62020-08-17 15:41:27 -0700358 return ws_end(&code);
swissChili97b5d8b2020-08-15 20:00:54 -0700359
360 case AM_AX:
361 case AM_ZPX:
362 case AM_AY:
363 case AM_ZPY:
364 if (am == AM_AX || am == AM_AY)
365 {
366 if (!parse_u16(&code, &num))
367 return false;
368 inst->arg_type = ARG_16;
369 inst->long_arg = num;
370 }
371 else
372 {
373 if (!parse_u8(&code, &num8))
374 return false;
375 inst->arg_type = ARG_8;
376 inst->byte_arg = num8;
377 }
swissChilidab15a62020-08-17 15:41:27 -0700378 printf("Parsing AM_* worked, now parsing ,\n");
swissChili97b5d8b2020-08-15 20:00:54 -0700379 if (!skip(&code, ","))
380 return false;
381
382 skip_ws(&code);
swissChilidab15a62020-08-17 15:41:27 -0700383 printf(", worked yup\n");
384 char reg = (am == AM_AY || am == AM_ZPY ? 'y' : 'x');
385 printf("reg is %c, *code is %c %x\n", reg, tolower(*code), tolower(*code));
386 if (tolower(*code) != reg)
swissChili97b5d8b2020-08-15 20:00:54 -0700387 return false;
swissChilidab15a62020-08-17 15:41:27 -0700388 (code)++;
swissChili97b5d8b2020-08-15 20:00:54 -0700389 return ws_end(&code);
390
391 case AM_ZIX:
392 if (!skip(&code, "("))
393 break;
394 skip_ws(&code);
395 if (!parse_u8(&code, &num8))
396 break;
397 skip_ws(&code);
398 if (!skip(&code, ","))
399 break;
400 skip_ws(&code);
401 if (tolower(*code) != 'x')
402 return false;
403 skip_ws(&code);
404
405 if (!skip(&code, ")"))
406 break;
407
408 inst->arg_type = ARG_8;
409 inst->byte_arg = num8;
410 return ws_end(&code);
411
412 case AM_ZIY:
413 if (!skip(&code, "("))
414 break;
415 skip_ws(&code);
416 if (!parse_u8(&code, &num8))
417 break;
418 skip_ws(&code);
419 if (!skip(&code, ")"))
420 break;
421 skip_ws(&code);
422 if (!skip(&code, ","))
423 break;
424 skip_ws(&code);
425 if (tolower(*code) != 'x')
426 break;
427
428 inst->arg_type = ARG_8;
429 inst->byte_arg = num8;
430 return ws_end(&code);
431 }
432 return false;
433}
434
swissChilidab15a62020-08-17 15:41:27 -0700435// Since program counter can never be < $600, return 0 on failure
436uint16_t ll_find(ll_node_t *head, char *name)
437{
438 ll_node_t *last = head;
439 while (last)
440 {
441 head = last;
442 if (!strcasecmp(head->name, name))
443 return head->addr;
444 last = head->last;
445 }
446 return 0;
447}
448
swissChili97b5d8b2020-08-15 20:00:54 -0700449uint32_t assemble(char *code, FILE *out)
450{
swissChilidab15a62020-08-17 15:41:27 -0700451 uint16_t num_insts = 0;
452 uint16_t pc = 0x600;
swissChili97b5d8b2020-08-15 20:00:54 -0700453 uint32_t line_no = 1;
swissChilidab15a62020-08-17 15:41:27 -0700454 ll_node_t *last_node = NULL;
swissChili7acb4ce2020-08-16 20:16:10 -0700455 char *line,
456 *orig_line,
457 *line_start;
swissChilidab15a62020-08-17 15:41:27 -0700458 inst_t **insts = calloc(sizeof(inst_t), MAX_INSTS);
swissChili97b5d8b2020-08-15 20:00:54 -0700459
460 printf("Assembling File\n");
461 printf("%s\n", code);
462
swissChili7acb4ce2020-08-16 20:16:10 -0700463 orig_line = strtok_fix(code, "\n");
464
465 while (orig_line)
swissChili97b5d8b2020-08-15 20:00:54 -0700466 {
swissChili7acb4ce2020-08-16 20:16:10 -0700467 line = strdup(orig_line);
468 line_start = line;
469
470 if (*line == 0)
471 goto end_of_line;
swissChili7acb4ce2020-08-16 20:16:10 -0700472
swissChili97b5d8b2020-08-15 20:00:54 -0700473 skip_ws(&line);
swissChilidab15a62020-08-17 15:41:27 -0700474
475 printf("line %d: \033[36m%.12s\033[0m\n", line_no, line);
476
swissChili7acb4ce2020-08-16 20:16:10 -0700477 if (is_eol(*line))
478 {
479 printf("skip_ws() brought us to EOL\n");
480 goto end_of_line;
481 }
swissChili97b5d8b2020-08-15 20:00:54 -0700482
swissChilia4f49b52020-08-16 17:35:37 -0700483 char *label = parse_label(&line);
swissChilidab15a62020-08-17 15:41:27 -0700484 printf(">> label == %.5s %p\n", label, label);
swissChili7acb4ce2020-08-16 20:16:10 -0700485 skip_ws(&code);
swissChilidab15a62020-08-17 15:41:27 -0700486 //if (is_eol(*line))
487 // goto end_of_line;
swissChilia4f49b52020-08-16 17:35:37 -0700488 char *mn = parse_inst(&line);
swissChilia4f49b52020-08-16 17:35:37 -0700489
490 bool no_argument = false;
swissChilia4f49b52020-08-16 17:35:37 -0700491 if (is_eol(*line))
492 {
493 no_argument = true;
swissChilia4f49b52020-08-16 17:35:37 -0700494 }
swissChili97b5d8b2020-08-15 20:00:54 -0700495 int32_t mnemonic = -1;
496
497 if (label)
498 {
swissChilidab15a62020-08-17 15:41:27 -0700499 printf("Storing label %s\n", label);
500 ll_node_t *head = malloc(sizeof(ll_node_t));
501 head->last = last_node;
502 strncpy(head->name, label, 32);
503 // strncpy won't zero the last byte if its over 32 bytes long
504 head->name[31] = 0;
505 head->addr = pc;
506 last_node = head;
507 printf("Set label %s at $%x\n", label, pc);
swissChili97b5d8b2020-08-15 20:00:54 -0700508 }
509
510 if (mn)
511 {
512#define MN(a) if (!strcasecmp(mn, #a)) \
swissChilica0d2e22020-08-16 15:09:25 -0700513 { \
swissChili97b5d8b2020-08-15 20:00:54 -0700514 mnemonic = a; \
swissChilica0d2e22020-08-16 15:09:25 -0700515 } \
swissChili97b5d8b2020-08-15 20:00:54 -0700516 else
517
swissChili7acb4ce2020-08-16 20:16:10 -0700518 MNEMONICS
519 {
520 printf(ERR "Could not parse instruction on line %d\n%s\n" RESET, line_no, orig_line);
swissChilidab15a62020-08-17 15:41:27 -0700521 free(line_start);
swissChili7acb4ce2020-08-16 20:16:10 -0700522 goto cleanup;
523 }
swissChili97b5d8b2020-08-15 20:00:54 -0700524#undef MN
525
526 printf("Got instruction %s %d\n", mn, mnemonic);
527
swissChilidab15a62020-08-17 15:41:27 -0700528 inst_t *arg = malloc(sizeof(inst_t));
529 arg->line = line_no;
swissChili97b5d8b2020-08-15 20:00:54 -0700530 // printf("Parsing '%s'\n", line);
531#define INST(_mn, am, op, len) \
swissChilia4f49b52020-08-16 17:35:37 -0700532 if ((no_argument && (_mn == AM_IMP || _mn == AM_ACC)) \
swissChilidab15a62020-08-17 15:41:27 -0700533 || (mnemonic == _mn && parse_arg(line, am, arg))) \
swissChilia4f49b52020-08-16 17:35:37 -0700534 { \
swissChili6a923012020-08-18 17:47:27 -0700535 printf(GREEN "AM_ succeeded: %s at pc=$%x\n" RESET, \
536 #am, pc); \
swissChilidab15a62020-08-17 15:41:27 -0700537 arg->opcode = op; \
swissChilia4f49b52020-08-16 17:35:37 -0700538 pc += len; \
swissChilidab15a62020-08-17 15:41:27 -0700539 print_inst(arg); \
swissChilia4f49b52020-08-16 17:35:37 -0700540 } \
swissChili97b5d8b2020-08-15 20:00:54 -0700541 else
542
543 INSTRUCTIONS
544 {
545 printf("\033[31mCould not be parsed: %s '%s'\033[0m\n", mn, line);
swissChilidab15a62020-08-17 15:41:27 -0700546 free(line_start);
547 goto cleanup;
swissChili97b5d8b2020-08-15 20:00:54 -0700548 }
549#undef INST
swissChilidab15a62020-08-17 15:41:27 -0700550
551 insts[num_insts++] = arg;
swissChili97b5d8b2020-08-15 20:00:54 -0700552 }
swissChili7acb4ce2020-08-16 20:16:10 -0700553 end_of_line:
554 line_no++;
swissChili7acb4ce2020-08-16 20:16:10 -0700555 orig_line = strtok_fix(NULL, "\n");
556 free(line_start);
swissChili97b5d8b2020-08-15 20:00:54 -0700557 }
558
swissChilidab15a62020-08-17 15:41:27 -0700559 // Generate machine code
560 for (int i = 0, curr_pc = 0x600; insts[i]; i++)
561 {
562 putc(insts[i]->opcode, out);
563
564 switch (insts[i]->arg_type)
565 {
566 case ARG_8:
567 putc(insts[i]->byte_arg, out);
568 curr_pc += 2;
569 break;
570 case ARG_16:
571 putshort(insts[i]->long_arg, out);
572 curr_pc += 3;
573 break;
574 case ARG_8REL:
575 putc(insts[i]->rel_arg, out);
576 curr_pc += 2;
577 break;
578 case ARG_ABS:
579 {
580 uint16_t lbl;
581 if (!(lbl = ll_find(last_node, insts[i]->label)))
582 {
swissChilic3829942020-09-06 19:36:04 -0700583 printf(ERR "Error on line %d: label '%s' is not defined" RESET "\n",
584 insts[i]->line, insts[i]->label);
swissChilidab15a62020-08-17 15:41:27 -0700585 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 {
swissChilic3829942020-09-06 19:36:04 -0700597 printf(ERR "Error on line %d: label '%s' is not defined" RESET "\n",
598 insts[i]->line, insts[i]->label);
swissChilidab15a62020-08-17 15:41:27 -0700599 goto cleanup;
600 }
601 curr_pc += 2;
602 int16_t diff = lbl - curr_pc;
swissChili6a923012020-08-18 17:47:27 -0700603 printf("ARG_REL, pc (after) == %x, diff = %hx\n", curr_pc, (uint8_t) diff);
swissChilidab15a62020-08-17 15:41:27 -0700604 if ((diff < 0 ? -diff : diff) > 0xFF)
605 {
swissChilic3829942020-09-06 19:36:04 -0700606 printf(ERR "Error on line %d: label '%s' is too far away for a relative jump" RESET "\n",
607 insts[i]->line, insts[i]->label);
swissChilidab15a62020-08-17 15:41:27 -0700608 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}