sanity checking of ram allocation (if the algorithm is correct it's not necessary...
[xorcyst.git] / xlnk.c
blob66504d152cb21a8d869cf8338215b4b545868d72
1 /*
2 * $Id: xlnk.c,v 1.20 2007/11/11 22:35:22 khansen Exp $
3 * $Log: xlnk.c,v $
4 * Revision 1.20 2007/11/11 22:35:22 khansen
5 * compile on mac
7 * Revision 1.19 2007/08/12 19:01:11 khansen
8 * xorcyst 1.5.0
10 * Revision 1.18 2007/08/07 22:43:01 khansen
11 * version
13 * Revision 1.17 2007/07/22 13:33:26 khansen
14 * convert tabs to whitespaces
16 * Revision 1.16 2005/01/09 11:19:41 kenth
17 * xorcyst 1.4.5
18 * prints code/data addresses of public symbols when --verbose
20 * Revision 1.15 2005/01/05 09:33:37 kenth
21 * xorcyst 1.4.4
22 * fixed RAM allocator bug
23 * print RAM statistics when --verbose
25 * Revision 1.14 2005/01/05 01:52:19 kenth
26 * xorcyst 1.4.3
28 * Revision 1.13 2005/01/04 21:35:58 kenth
29 * return error code from main() when error count > 0
31 * Revision 1.12 2004/12/29 21:43:55 kenth
32 * xorcyst 1.4.2
34 * Revision 1.11 2004/12/27 06:42:05 kenth
35 * fixed bug in alloc_ram()
37 * Revision 1.10 2004/12/25 02:23:28 kenth
38 * xorcyst 1.4.1
40 * Revision 1.9 2004/12/19 19:58:54 kenth
41 * xorcyst 1.4.0
43 * Revision 1.8 2004/12/18 19:10:39 kenth
44 * relocation improved (I hope)
46 * Revision 1.7 2004/12/18 17:02:00 kenth
47 * CMD_LINE*, CMD_FILE handling, error location printing
48 * CMD_DSW, CMD_DSD gone
50 * Revision 1.6 2004/12/16 13:20:41 kenth
51 * xorcyst 1.3.5
53 * Revision 1.5 2004/12/14 01:50:21 kenth
54 * xorcyst 1.3.0
56 * Revision 1.4 2004/12/11 02:06:18 kenth
57 * xorcyst 1.2.0
59 * Revision 1.3 2004/12/06 04:53:18 kenth
60 * xorcyst 1.1.0
62 * Revision 1.2 2004/06/30 23:38:22 kenth
63 * replaced argp with something else
65 * Revision 1.1 2004/06/30 07:56:04 kenth
66 * Initial revision
68 * Revision 1.1 2004/06/30 07:42:03 kenth
69 * Initial revision
73 /**
74 * (C) 2004 Kent Hansen
76 * The XORcyst is free software; you can redistribute it and/or modify
77 * it under the terms of the GNU General Public License as published by
78 * the Free Software Foundation; either version 2 of the License, or
79 * (at your option) any later version.
81 * The XORcyst is distributed in the hope that it will be useful,
82 * but WITHOUT ANY WARRANTY; without even the implied warranty of
83 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
84 * GNU General Public License for more details.
86 * You should have received a copy of the GNU General Public License
87 * along with The XORcyst; if not, write to the Free Software
88 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
91 /**
92 * This is the 6502 linker program. It takes one or more object files generated
93 * by the 6502 assembler program, and then (rough list)
94 * - maps all data labels to physical 6502 RAM
95 * - relocates code to 6502 address space
96 * - resolves external references
97 * - writes everything to a final binary
99 * The input to the linker is a script file which describes the layout and
100 * contents of the final binary.
103 #include <stdio.h>
104 #include <stdlib.h>
105 #include <stdarg.h>
106 #include <string.h>
107 #include <assert.h>
108 #include "getopt.h"
109 #include "objdef.h"
110 #include "opcode.h"
111 #include "script.h"
112 #include "unit.h"
113 #include "hashtab.h"
115 #define SAFE_FREE(m) if ((m) != NULL) { free(m); m = NULL; }
118 * Parses a string to an integer.
119 * @param s String
120 * @return Integer
122 static int str_to_int(char *s)
124 if (s[0] == '$') {
125 return strtol(&s[1], NULL, 16);
127 else if (s[0] == '%') {
128 return strtol(&s[1], NULL, 2);
130 return strtol(s, NULL, 0);
133 /*--------------------------------------------------------------------------*/
134 /* Argument parsing stuff. */
136 static char program_version[] = "xlnk 1.5.0";
138 struct tag_arguments {
139 char *input_file;
140 int silent;
141 int verbose;
144 typedef struct tag_arguments arguments;
146 /* Argument variables set by arg parser. */
147 static arguments program_args;
149 /* Long options for getopt_long(). */
150 static struct option long_options[] = {
151 { "quiet", no_argument, 0, 'q' },
152 { "silent", no_argument, 0, 's' },
153 { "verbose", no_argument, 0, 'v' },
154 { "help", no_argument, 0, 0 },
155 { "usage", no_argument, 0, 0 },
156 { "version", no_argument, 0, 'V' },
157 { 0 }
160 /* Prints usage message and exits. */
161 static void usage()
163 printf("\
164 Usage: xlnk [-qsvV] [--quiet] [--silent] [--verbose] [--help] [--usage]\n\
165 [--version] FILE\n\
167 exit(0);
170 /* Prints help message and exits. */
171 static void help()
173 printf("\
174 Usage: xlnk [OPTION...] FILE\n\
175 The XORcyst Linker -- it creates quite a stir\n\
177 -q, -s, --quiet, --silent Don't produce any output\n\
178 -v, --verbose Produce verbose output\n\
179 --help Give this help list\n\
180 --usage Give a short usage message\n\
181 -V, --version Print program version\n\
183 Report bugs to <dev@null>.\n\
185 exit(0);
188 /* Prints version and exits. */
189 static void version()
191 printf("%s\n", program_version);
192 exit(0);
195 /* Parses program arguments. */
196 static void
197 parse_arguments (int argc, char **argv)
199 int key;
200 /* getopt_long stores the option index here. */
201 int index = 0;
203 /* Set default values. */
204 program_args.silent = 0;
205 program_args.verbose = 0;
206 program_args.input_file = NULL;
208 /* Parse options. */
209 while ((key = getopt_long(argc, argv, "qsvV", long_options, &index)) != -1) {
210 switch (key) {
211 case 'q': case 's':
212 program_args.silent = 1;
213 break;
215 case 'v':
216 ++program_args.verbose;
217 break;
219 case 0:
220 /* Use index to differentiate between options */
221 if (strcmp(long_options[index].name, "usage") == 0) {
222 usage();
224 else if (strcmp(long_options[index].name, "help") == 0) {
225 help();
227 break;
229 case 'V':
230 version();
231 break;
233 case '?':
234 /* Error message has been printed by getopt_long */
235 exit(1);
236 break;
238 default:
239 /* Forgot to handle a short option, most likely */
240 exit(1);
241 break;
245 /* Must be one additional argument, which is the input file. */
246 if (argc-1 != optind) {
247 printf("Usage: xlnk [OPTION...] FILE\nTry `xlnk --help' or `xlnk --usage' for more information.\n");
248 exit(1);
250 else {
251 program_args.input_file = argv[optind];
255 /*--------------------------------------------------------------------------*/
256 /* Data structures. */
258 /* Describes a local label in the unit. */
259 struct tag_local
261 char *name; /* NULL if not exported */
262 int resolved; /* 0 initially, set to 1 when phys_addr has been assigned */
263 int virt_addr;
264 int phys_addr;
265 int ref_count;
266 int size;
267 struct tag_xunit *owner;
268 unsigned short align;
269 unsigned char flags;
272 typedef struct tag_local local;
274 /* Describes an array of local labels. */
275 struct tag_local_array
277 local *entries;
278 int size;
281 typedef struct tag_local_array local_array;
284 * eXtended unit, has extra info built from basic unit ++
286 struct tag_xunit
288 unit _unit_; /* NB!!! "Superclass", must be first field for casting to work */
289 local_array data_locals;
290 local_array code_locals;
291 int bank_id;
292 int data_size;
293 int code_origin;
294 int code_size;
295 int loaded;
298 typedef struct tag_xunit xunit;
301 * Describes a 6502 RAM block available for allocation.
303 struct tag_avail_ram_block
305 int start; /* Start address in 6502 space */
306 int end; /* End address in 6502 space (not inclusive) */
307 struct tag_avail_ram_block *next;
310 typedef struct tag_avail_ram_block avail_ram_block;
312 /** */
313 struct tag_calc_address_args
315 xunit *xu;
316 int index;
319 typedef struct tag_calc_address_args calc_address_args;
321 /** */
322 struct tag_write_binary_args
324 xunit *xu;
325 FILE *fp;
328 typedef struct tag_write_binary_args write_binary_args;
330 /*--------------------------------------------------------------------------*/
332 /** Array containing the units to link. */
333 static xunit *units;
334 /* Number of units in above array. */
335 static int unit_count;
337 /** Holds the current memory address. */
338 static int pc;
340 /** Hash tables used to lookup symbols. */
341 static hashtab *label_hash;
342 static hashtab *constant_hash;
343 static hashtab *unit_hash;
345 /** Number of errors and warnings during linking */
346 static int err_count;
347 static int warn_count;
349 static int suppress;
351 /* Head of the list of available 6502 RAM blocks (for data allocation). */
352 static avail_ram_block *ram_block_head = NULL;
354 /* Total amount of 6502 RAM (bytes) that was registered */
355 static int total_ram = 0;
357 /* Bank info */
358 static int bank_offset;
359 static int bank_size;
360 static int bank_origin;
361 static int bank_id;
363 /* Debug info */
364 static unsigned char *unit_file = NULL; /* length byte followed by chars */
365 static int unit_line = -1;
367 /*--------------------------------------------------------------------------*/
370 * If the object file contains FILE and LINE bytecodes (assembled with
371 * --debug switch), unit_file and unit_line will contain the current
372 * source location. In that case, this function prints the location.
374 static void maybe_print_location()
376 char *str;
377 int len;
378 if (unit_file != NULL) {
379 /* Print source location */
380 len = unit_file[0] + 1;
381 str = (char *)malloc(len + 1);
382 strncpy(str, (char *)&unit_file[1], len);
383 str[len] = '\0';
384 fprintf(stderr, "%s:%d: ", str, unit_line);
385 free(str);
390 * If the object doesn't contain FILE and LINE bytecodes,
391 * unit_file will be <code>NULL</code>. In that case, this
392 * function prints a tip about reassembling with --debug switch.
394 static void maybe_print_debug_tip()
396 if (unit_file == NULL) {
397 fprintf(stderr, "\treassemble with --debug switch to obtain source location\n");
402 * Issues an error.
403 * @param fmt format string for printf
405 static void err(char *fmt, ...)
407 va_list ap;
408 va_start(ap, fmt);
409 if (!suppress) {
410 /* Print error message */
411 fprintf(stderr, "error: ");
412 maybe_print_location();
413 vfprintf(stderr, fmt, ap);
414 fprintf(stderr, "\n");
415 maybe_print_debug_tip();
416 /* Increase total error count */
417 err_count++;
419 va_end(ap);
423 * Issues a warning.
424 * @param fmt format string for printf
426 static void warn(char *fmt, ...)
428 va_list ap;
429 va_start(ap, fmt);
430 if (!suppress) {
431 /* Print warning message */
432 fprintf(stderr, "warning: ");
433 maybe_print_location();
434 vfprintf(stderr, fmt, ap);
435 fprintf(stderr, "\n");
436 maybe_print_debug_tip();
437 /* Increase total warning count */
438 warn_count++;
440 va_end(ap);
444 * Prints a message if --verbose switch was given.
445 * @param level verbosity level
446 * @param fmt format string for printf
448 static void verbose(int level, char *fmt, ...)
450 va_list ap;
451 va_start(ap, fmt);
452 if (!suppress && program_args.verbose >= level) {
453 vfprintf(stdout, fmt, ap);
454 fprintf(stdout, "\n");
456 va_end(ap);
459 /*--------------------------------------------------------------------------*/
460 /* Functions to manage 6502 RAM blocks. */
461 /* The RAM allocator maintains a list of these blocks that are used to
462 map the contents of the units' data segments to memory.
466 * Calculates number of bytes of 6502 RAM left for allocation.
468 static int ram_left()
470 int sum;
471 avail_ram_block *b;
472 for (sum = 0, b = ram_block_head; b != NULL; b = b->next) {
473 sum += b->end - b->start;
475 return sum;
479 * Adds a block of 6502 memory to the list of available memory regions.
480 * When adding multiple blocks they should be added in prioritized order.
481 * @param start Start address of the block
482 * @param end End address of the block (non-inclusive!)
484 static void add_ram_block(int start, int end)
486 avail_ram_block *b;
487 /* Allocate a block struct */
488 avail_ram_block *new_block = (avail_ram_block *)malloc( sizeof(avail_ram_block) );
489 if (new_block != NULL) {
490 /* Set the fields */
491 new_block->start = start;
492 new_block->end = end;
493 new_block->next = NULL;
494 /* Add it to list */
495 if (ram_block_head == NULL) {
496 /* Start the list */
497 ram_block_head = new_block;
499 else {
500 /* Add to end */
501 for (b = ram_block_head; b->next != NULL; b = b->next) ;
502 b->next = new_block;
504 verbose(1, " added RAM block: %.4X-%.4X", new_block->start, new_block->end);
509 * Allocates a chunk of 6502 RAM to a local.
510 * @param l Local
511 * @return 0 if there isn't enough RAM to satisfy the request (fail), 1 otherwise (success)
513 static int alloc_ram(local *l)
515 /* Try the available blocks in order. */
516 /* Use the first one that's sufficient. */
517 avail_ram_block *b;
518 avail_ram_block *p = NULL;
519 for (b = ram_block_head; b != NULL; p = b, b = b->next) {
520 int left;
521 int pad;
522 avail_ram_block *n;
523 /* Check if zero page block required */
524 if (l->flags & LABEL_FLAG_ZEROPAGE) {
525 if (b->start >= 0x100) {
526 continue; /* This block is no good */
529 /* Calculate the # of bytes left in this block */
530 left = b->end - b->start;
531 /* See if it's enough */
532 if (left < l->size) {
533 continue; /* Not enough, sorry */
535 /* Check if alignment required */
536 if (l->flags & LABEL_FLAG_ALIGN) {
537 pad = b->start & ((1 << l->align) - 1);
538 if (pad != 0) {
539 /* This block doesn't match the alignment */
540 /* Break it into two blocks if possible */
541 pad = (1 << l->align) - pad;
542 pad = (left < pad) ? left : pad;
543 if (pad < left) {
544 n = (avail_ram_block *)malloc(sizeof(avail_ram_block));
545 n->start = b->start;
546 n->end = n->start + pad;
547 b->start += pad;
548 n->next = b;
549 if (b == ram_block_head) {
550 ram_block_head = n; /* New head */
552 b = n;
554 continue;
557 /* Pick this one. */
558 l->phys_addr = b->start;
559 /* Decrease block size by moving start address ahead */
560 b->start += l->size;
561 /* If there's no more space left in this block, discard it */
562 if (left == l->size) {
563 /* Remove from linked list */
564 if (p == NULL) {
565 /* Set successor block as new head */
566 ram_block_head = b->next;
568 else {
569 /* Squeeze out */
570 p->next = b->next;
572 /* Free associated memory */
573 SAFE_FREE(b);
575 /* Return with success */
576 return 1;
578 /* Couldn't find a block large enough, return with failure */
579 return 0;
583 * Frees up memory associated with list of RAM blocks.
585 static void finalize_ram_blocks()
587 avail_ram_block *b;
588 avail_ram_block *t;
589 for (b = ram_block_head; b != NULL; b = t) {
590 t = b->next;
591 SAFE_FREE(b);
595 /*--------------------------------------------------------------------------*/
596 /* Functions to get big-endian values from byte buffer. */
598 /* Gets single byte from buffer and increments index. */
599 static unsigned char get_1(unsigned char *b, int *i)
601 return b[(*i)++];
603 /* Gets big-endian short from buffer and increments index. */
604 static unsigned short get_2(unsigned char *b, int *i)
606 unsigned short result = get_1(b, i) << 8;
607 result |= get_1(b, i);
608 return result;
610 /* Gets big-endian 24-bit integer from buffer and increments index. */
611 static unsigned int get_3(unsigned char *b, int *i)
613 unsigned int result = get_2(b, i) << 8;
614 result |= get_1(b, i);
615 return result;
617 /* Gets big-endian int from buffer and increments index. */
618 /*static unsigned int get_4(unsigned char *b, int *i)
620 unsigned int result = get_2(b, i) << 16;
621 result |= get_2(b, i);
622 return result;
625 /*--------------------------------------------------------------------------*/
628 * Calculates the storage occupied by a CMD_LABEL bytecode's arguments.
630 static int label_cmd_args_size(unsigned char *bytes)
632 int size = 1; /* Smallest possible: flag byte */
633 int flags = bytes[0];
634 if (flags & LABEL_FLAG_EXPORT) { size += bytes[1] + 1 + 1; } /* Length byte + string */
635 if (flags & LABEL_FLAG_ALIGN) { size += 1; } /* Alignment */
636 if (flags & LABEL_FLAG_ADDR) { size += 2; } /* Address */
637 return size;
640 /** Signature for procedure to process a bytecode */
641 typedef void (*bytecodeproc)(unsigned char *, void *);
644 * Walks an array of bytecodes, calling corresponding bytecode handlers
645 * along the way.
646 * @param bytes Array of bytecodes, terminated by CMD_END
647 * @param handlers Array of bytecode handlers (entries can be NULL)
648 * @param arg Argument passed to bytecode handler, can be anything
650 static void bytecode_walk(unsigned char *bytes, bytecodeproc *handlers, void *arg)
652 int i;
653 unsigned char cmd;
654 unit_file = NULL;
655 unit_line = -1;
656 if (bytes == NULL) { return; }
657 i = 0;
658 do {
659 /* Get a command */
660 cmd = get_1(bytes, &i);
662 /* Check if debug command */
663 if (cmd < CMD_END) {
664 switch (cmd) {
665 case CMD_FILE:
666 unit_file = &bytes[i];
667 i += get_1(bytes, &i) + 1; /* Skip count and array of bytes */
668 break;
669 case CMD_LINE8: unit_line = get_1(bytes, &i); break;
670 case CMD_LINE16: unit_line = get_2(bytes, &i); break;
671 case CMD_LINE24: unit_line = get_3(bytes, &i); break;
672 case CMD_LINE_INC: unit_line++; break;
674 continue;
677 /* Call bytecode handler if one is present */
678 if (handlers[cmd-CMD_END] != NULL) {
679 handlers[cmd-CMD_END](&bytes[i-1], arg);
681 /* Skip any bytecode arguments */
682 switch (cmd) {
683 case CMD_END: break;
684 case CMD_BIN8: i += get_1(bytes, &i) + 1; break; /* Skip count and array of bytes */
685 case CMD_BIN16: i += get_2(bytes, &i) + 1; break; /* Skip count and array of bytes */
686 case CMD_LABEL: i += label_cmd_args_size(&bytes[i]); break; /* Skip flag byte and possibly name and alignment */
687 case CMD_INSTR: i += 3; break; /* Skip 6502 opcode and 16-bit expr id */
688 case CMD_DB: i += 2; break; /* Skip 16-bit expr id */
689 case CMD_DW: i += 2; break; /* Skip 16-bit expr id */
690 case CMD_DD: i += 2; break; /* Skip 16-bit expr id */
691 case CMD_DSI8: i += 1; break; /* Skip 8-bit count */
692 case CMD_DSI16: i += 2; break; /* Skip 16-bit count */
693 case CMD_DSB: i += 2; break; /* Skip 16-bit expr id */
695 default:
696 /* Invalid opcode */
697 err("invalid bytecode");
698 break;
700 } while (cmd != CMD_END);
703 /*--------------------------------------------------------------------------*/
704 /* Functions for expression evaluation. */
707 * Finalizes a constant.
708 * @param c Constant to finalize
710 static void finalize_constant(constant *c)
712 if (c->type == STRING_CONSTANT) {
713 SAFE_FREE(c->string);
718 * Gets string representation of an operator (OP_*, see objdef.h).
719 * @param op Operator
720 * @return String representation of operator
722 static const char *operator_to_string(int op)
724 switch (op) {
725 case OP_PLUS: return "+";
726 case OP_MINUS: return "-";
727 case OP_MUL: return "*";
728 case OP_DIV: return "/";
729 case OP_MOD: return "%";
730 case OP_SHL: return "<<";
731 case OP_SHR: return ">>";
732 case OP_AND: return "&";
733 case OP_OR: return "|";
734 case OP_XOR: return "^";
735 case OP_EQ: return "==";
736 case OP_NE: return "!=";
737 case OP_LT: return "<";
738 case OP_GT: return ">";
739 case OP_LE: return "<=";
740 case OP_GE: return ">=";
741 case OP_NOT: return "!";
742 case OP_NEG: return "~";
743 case OP_LO: return "<";
744 case OP_HI: return ">";
745 case OP_UMINUS: return "-";
746 case OP_BANK: return "^";
748 return "";
752 * Evaluates an expression recursively.
753 * The result will either be a integer or string literal, indicating successful
754 * evaluation; or an invalid type indicating that a symbol could not be translated
755 * to a constant (in other words, it could not be resolved). In this case,
756 * result->string contains the name of the symbol which couldn't be evaluated.
757 * @param u The unit where the expression is contained
758 * @param e The expression to evaluate
759 * @param result Pointer to resulting value
761 static void eval_recursive(xunit *u, expression *e, constant *result)
763 char *s;
764 local *l;
765 constant *c;
766 constant lhs_result, rhs_result;
767 switch (e->type) {
768 case OPERATOR_EXPRESSION:
769 switch (e->op_expr.operator) {
770 /* Binary operators */
771 case OP_PLUS:
772 case OP_MINUS:
773 case OP_MUL:
774 case OP_DIV:
775 case OP_MOD:
776 case OP_SHL:
777 case OP_SHR:
778 case OP_AND:
779 case OP_OR:
780 case OP_XOR:
781 case OP_EQ:
782 case OP_NE:
783 case OP_LT:
784 case OP_GT:
785 case OP_LE:
786 case OP_GE:
787 /* Evaluate both sides */
788 eval_recursive(u, e->op_expr.lhs, &lhs_result);
789 eval_recursive(u, e->op_expr.rhs, &rhs_result);
790 /* If either side is unresolved, then result is unresolved. */
791 if ((lhs_result.type == -1) || (rhs_result.type == -1)) {
792 result->type = -1;
794 /* If both sides are integer, then result is integer. */
795 else if ((lhs_result.type == INTEGER_CONSTANT) &&
796 (rhs_result.type == INTEGER_CONSTANT)) {
797 result->type = INTEGER_CONSTANT;
798 /* Perform the proper operation to obtain result. */
799 switch (e->op_expr.operator) {
800 case OP_PLUS: result->integer = lhs_result.integer + rhs_result.integer; break;
801 case OP_MINUS: result->integer = lhs_result.integer - rhs_result.integer; break;
802 case OP_MUL: result->integer = lhs_result.integer * rhs_result.integer; break;
803 case OP_DIV: result->integer = lhs_result.integer / rhs_result.integer; break;
804 case OP_MOD: result->integer = lhs_result.integer % rhs_result.integer; break;
805 case OP_SHL: result->integer = lhs_result.integer << rhs_result.integer; break;
806 case OP_SHR: result->integer = lhs_result.integer >> rhs_result.integer; break;
807 case OP_AND: result->integer = lhs_result.integer & rhs_result.integer; break;
808 case OP_OR: result->integer = lhs_result.integer | rhs_result.integer; break;
809 case OP_XOR: result->integer = lhs_result.integer ^ rhs_result.integer; break;
810 case OP_EQ: result->integer = lhs_result.integer == rhs_result.integer; break;
811 case OP_NE: result->integer = lhs_result.integer != rhs_result.integer; break;
812 case OP_LT: result->integer = lhs_result.integer < rhs_result.integer; break;
813 case OP_GT: result->integer = lhs_result.integer > rhs_result.integer; break;
814 case OP_LE: result->integer = lhs_result.integer <= rhs_result.integer; break;
815 case OP_GE: result->integer = lhs_result.integer >= rhs_result.integer; break;
818 /* If both sides are string... */
819 else if ((lhs_result.type == STRING_CONSTANT) &&
820 (rhs_result.type == STRING_CONSTANT)) {
821 switch (e->op_expr.operator) {
822 case OP_PLUS:
823 /* Concatenate */
824 result->string = (char *)malloc(strlen(lhs_result.string)+strlen(rhs_result.string)+1);
825 if (result->string != NULL) {
826 strcpy(result->string, lhs_result.string);
827 strcat(result->string, rhs_result.string);
828 result->type = STRING_CONSTANT;
830 break;
832 /* String comparison: using strcmp() */
833 case OP_EQ: result->integer = strcmp(lhs_result.string, rhs_result.string) == 0; break;
834 case OP_NE: result->integer = strcmp(lhs_result.string, rhs_result.string) != 0; break;
835 case OP_LT: result->integer = strcmp(lhs_result.string, rhs_result.string) < 0; break;
836 case OP_GT: result->integer = strcmp(lhs_result.string, rhs_result.string) > 0; break;
837 case OP_LE: result->integer = strcmp(lhs_result.string, rhs_result.string) <= 0; break;
838 case OP_GE: result->integer = strcmp(lhs_result.string, rhs_result.string) >= 0; break;
840 default:
841 /* Not defined operator for string operation... */
842 break;
845 else {
846 /* Error, operands are incompatible */
847 result->type = -1;
848 err("incompatible operands to `%s' in expression", operator_to_string(e->op_expr.operator) );
850 /* Discard the operands */
851 finalize_constant(&lhs_result);
852 finalize_constant(&rhs_result);
853 break; /* Binary operator */
855 /* Unary operators */
856 case OP_NOT:
857 case OP_NEG:
858 case OP_LO:
859 case OP_HI:
860 case OP_UMINUS:
861 /* Evaluate the single operand */
862 eval_recursive(u, e->op_expr.lhs, &lhs_result);
863 /* If operand is unresolved then result is unresolved. */
864 if (lhs_result.type == -1) {
865 result->type = -1;
867 /* If operand is integer then result is integer. */
868 else if (lhs_result.type == INTEGER_CONSTANT) {
869 result->type = INTEGER_CONSTANT;
870 /* Perform the proper operation to obtain result. */
871 switch (e->op_expr.operator) {
872 case OP_NOT: result->integer = !lhs_result.integer; break;
873 case OP_NEG: result->integer = ~lhs_result.integer; break;
874 case OP_LO: result->integer = lhs_result.integer & 0xFF; break;
875 case OP_HI: result->integer = (lhs_result.integer >> 8) & 0xFF; break;
876 case OP_UMINUS: result->integer = -lhs_result.integer; break;
879 else {
880 /* Error, invalid operand */
881 err("incompatible operand to `%s' in expression", operator_to_string(e->op_expr.operator) );
882 result->type = -1;
884 /* Discard the operand */
885 finalize_constant(&lhs_result);
886 break; /* Unary operator */
888 case OP_BANK:
889 switch (e->op_expr.lhs->type) {
890 case LOCAL_EXPRESSION:
891 /* Simple, it must be in the same (current) bank */
892 result->integer = bank_id;
893 result->type = INTEGER_CONSTANT;
894 break;
896 case EXTERNAL_EXPRESSION:
897 /* Get the name of the external */
898 s = u->_unit_.externals[e->op_expr.lhs->extrn_id].name;
899 /* Look it up */
900 if ((l = (local *)hashtab_get(label_hash, s)) != NULL) {
901 /* It's a label */
902 result->integer = l->owner->bank_id;
903 result->type = INTEGER_CONSTANT;
905 else if ((c = (constant *)hashtab_get(constant_hash, s)) != NULL) {
906 /* It's a constant */
907 result->integer = ((xunit *)c->unit)->bank_id;
908 result->type = INTEGER_CONSTANT;
910 else {
911 result->type = -1;
913 break;
915 default:
916 result->type = -1;
917 break;
919 break;
921 break;
923 case INTEGER_EXPRESSION:
924 /* Copy value to result */
925 result->type = INTEGER_CONSTANT;
926 result->integer = e->integer;
927 break;
929 case STRING_EXPRESSION:
930 /* Copy value to result */
931 result->string = (char *)malloc(strlen(e->string) + 1);
932 if (result->string != NULL) {
933 strcpy(result->string, e->string);
934 result->type = STRING_CONSTANT;
936 break;
938 case LOCAL_EXPRESSION:
939 if (e->local_id >= u->data_locals.size) {
940 /* It's a code local */
941 l = &u->code_locals.entries[e->local_id - u->data_locals.size];
943 else {
944 /* It's a data local */
945 l = &u->data_locals.entries[e->local_id];
947 /* Test if it's resolved */
948 if (l->resolved) {
949 /* Copy address to result */
950 result->type = INTEGER_CONSTANT;
951 result->integer = l->phys_addr;
953 else {
954 /* Not resolved (yet, at least) */
955 result->type = -1;
957 break;
959 case EXTERNAL_EXPRESSION:
960 /* Get the name of the external */
961 s = u->_unit_.externals[e->extrn_id].name;
962 /* Look it up */
963 if ((l = (local *)hashtab_get(label_hash, s)) != NULL) {
964 /* It's a label */
965 /* Test if it's resolved */
966 if (l->resolved) {
967 /* Copy address to result */
968 result->type = INTEGER_CONSTANT;
969 result->integer = l->phys_addr;
971 else {
972 /* Not resolved (yet) */
973 result->type = -1;
976 else if ((c = (constant *)hashtab_get(constant_hash, s)) != NULL) {
977 /* It's a constant */
978 /* Copy value to result */
979 switch (c->type) {
980 case INTEGER_CONSTANT:
981 result->type = INTEGER_CONSTANT;
982 result->integer = c->integer;
983 break;
985 case STRING_CONSTANT:
986 result->string = (char *)malloc(strlen(c->string) + 1);
987 if (result->string != NULL) {
988 strcpy(result->string, c->string);
989 result->type = STRING_CONSTANT;
991 break;
994 else {
995 /* Error */
996 result->type = -1;
997 err("unknown symbol `%s' referenced from %s", s, u->_unit_.name);
999 break;
1001 case PC_EXPRESSION:
1002 /* Copy current PC to result */
1003 result->type = INTEGER_CONSTANT;
1004 result->integer = pc;
1005 break;
1010 * Evaluates an expression.
1011 * @param u The unit where the expression is contained
1012 * @param exid The unique ID of the expression
1013 * @param result Where to store the result of the evaluation
1015 static void eval_expression(xunit *u, int exid, constant *result)
1017 /* Get the expression with id exid */
1018 expression *exp = u->_unit_.expressions[exid];
1019 /* Evaluate recursively */
1020 eval_recursive(u, exp, result);
1023 /*--------------------------------------------------------------------------*/
1024 /* Functions for incrementing PC, with error handling for wraparound. */
1027 * Increases PC by amount.
1028 * Issues error if the PC wraps around.
1030 static void inc_pc(int amount, void *arg)
1032 calc_address_args *aargs;
1033 /* Check for 16-bit overflow */
1034 if ((pc <= 0x10000) && ((pc+amount) > 0x10000)) {
1035 aargs = (calc_address_args *)arg;
1036 err("PC went beyond 64K when linking `%s'", aargs->xu->_unit_.name);
1038 /* Add! */
1039 pc += amount;
1043 * Increases PC by 8-bit value immediately following bytecode command.
1045 static void inc_pc_count8(unsigned char *b, void *arg)
1047 int i = 1;
1048 inc_pc( get_1(b, &i) + 1, arg );
1052 * Increases PC by 16-bit value immediately following bytecode command.
1054 static void inc_pc_count16(unsigned char *b, void *arg)
1056 int i = 1;
1057 inc_pc( get_2(b, &i) + 1, arg );
1061 * Increases PC by 1.
1063 static void inc_pc_1(unsigned char *b, void *arg)
1065 inc_pc( 1, arg );
1069 * Increases PC by 2.
1071 static void inc_pc_2(unsigned char *b, void *arg)
1073 inc_pc( 2, arg );
1077 * Increases PC by 4.
1079 static void inc_pc_4(unsigned char *b, void *arg)
1081 inc_pc( 4, arg );
1085 * Increases PC according to size of define data command.
1087 static void inc_pc_dsb(unsigned char *b, void *arg)
1089 constant c;
1090 int exid;
1091 calc_address_args *args = (calc_address_args *)arg;
1092 int i = 1;
1093 /* Get expression ID */
1094 exid = get_2(b, &i);
1095 /* Evaluate expression */
1096 eval_expression(args->xu, exid, &c);
1097 /* Handle the result */
1098 if (c.type == INTEGER_CONSTANT) {
1099 /* An array of bytes will be located here */
1100 /* Advance PC appropriately */
1101 inc_pc( c.integer, arg );
1103 else if (c.type == STRING_CONSTANT) {
1104 /* Error, doesn't make sense here */
1105 err("unexpected string operand (`%s') to storage directive", c.string);
1107 else {
1108 /* Error, unresolved */
1109 //err("unresolved symbol");
1112 finalize_constant(&c);
1116 * Increments PC according to the length of this instruction.
1118 static void inc_pc_instr(unsigned char *b, void *arg)
1120 constant c;
1121 unsigned char op, t;
1122 int exid;
1123 calc_address_args *args = (calc_address_args *)arg;
1124 /* Get opcode */
1125 int i = 1;
1126 op = get_1(b, &i);
1127 /* Get expression ID */
1128 exid = get_2(b, &i);
1129 /* Evaluate it */
1130 eval_expression(args->xu, exid, &c);
1131 /* Handle the result */
1132 if (c.type == INTEGER_CONSTANT) {
1133 /* See if it can be reduced to ZP instruction */
1134 if ((c.integer < 0x100) &&
1135 ((t = opcode_zp_equiv(op)) != 0xFF)) {
1136 /* replace op by ZP-version */
1137 op = t;
1138 b[1] = t;
1141 else if (c.type == STRING_CONSTANT) {
1142 /* Error, string operand doesn't make sense here */
1143 err("invalid instruction operand (string)");
1145 else {
1146 /* Address not available yet (forward reference). */
1147 //err("unresolved symbol");
1149 /* Advance PC */
1150 inc_pc( opcode_length(op), arg );
1153 /*--------------------------------------------------------------------------*/
1154 /* Functions for writing pure 6502 binary from bytecodes. */
1157 * Writes an array of bytes.
1159 static void write_bin8(unsigned char *b, void *arg)
1161 int count;
1162 int i;
1163 write_binary_args *args = (write_binary_args *)arg;
1164 /* Get 8-bit count */
1165 i = 1;
1166 count = get_1(b, &i) + 1;
1167 /* Write data */
1168 fwrite(&b[i], 1, count, args->fp);
1169 /* Advance PC */
1170 inc_pc( count, arg );
1174 * Writes an array of bytes.
1176 static void write_bin16(unsigned char *b, void *arg)
1178 int count;
1179 int i;
1180 write_binary_args *args = (write_binary_args *)arg;
1181 /* Get 16-bit count */
1182 i = 1;
1183 count = get_2(b, &i) + 1;
1184 /* Write data */
1185 fwrite(&b[i], 1, count, args->fp);
1186 /* Advance PC */
1187 inc_pc( count, arg );
1191 * Writes an instruction.
1193 static void write_instr(unsigned char *b, void *arg)
1195 constant c;
1196 unsigned char op;
1197 int i;
1198 int exid;
1199 write_binary_args *args = (write_binary_args *)arg;
1200 /* Get opcode */
1201 i = 1;
1202 op = get_1(b, &i);
1203 /* Get expression ID */
1204 exid = get_2(b, &i);
1205 /* Evaluate expression */
1206 eval_expression(args->xu, exid, &c);
1208 /* Write the opcode */
1209 fputc(op, args->fp);
1211 if (opcode_length(op) == 2) {
1212 /* Operand must fit in 1 byte */
1213 /* Check if it's a relative jump */
1214 switch (op) {
1215 case 0x10:
1216 case 0x30:
1217 case 0x50:
1218 case 0x70:
1219 case 0x90:
1220 case 0xB0:
1221 case 0xD0:
1222 case 0xF0:
1223 /* Calculate difference between target and address of next instruction */
1224 c.integer = c.integer - (pc + 2);
1225 /* Make sure jump is in range */
1226 if ( (c.integer < -128) || (c.integer > 127) ) {
1227 err("branch out of range");
1229 /* Make it a byte value */
1230 c.integer &= 0xFF;
1231 break;
1233 if (c.integer >= 0x100) {
1234 err("instruction operand doesn't fit in 1 byte");
1236 else {
1237 /* Write it */
1238 fputc(c.integer, args->fp);
1241 else {
1242 /* Operand must fit in 2 bytes */
1243 if (c.integer >= 0x10000) {
1244 err("instruction operand doesn't fit in 2 bytes");
1246 else {
1247 /* Write it, low byte first */
1248 fputc(c.integer, args->fp);
1249 fputc(c.integer >> 8, args->fp);
1252 /* Advance PC */
1253 inc_pc( opcode_length(op), arg );
1257 * Writes a byte, word or dword.
1259 static void write_dx(unsigned char *b, void *arg)
1261 constant c;
1262 int i;
1263 int exid;
1264 write_binary_args *args = (write_binary_args *)arg;
1265 /* Get expression ID */
1266 i = 1;
1267 exid = get_2(b, &i);
1268 /* Evaluate expression */
1269 eval_expression(args->xu, exid, &c);
1271 if (c.type == INTEGER_CONSTANT) {
1272 /* Write low byte */
1273 fputc(c.integer, args->fp);
1274 /* If 2+ bytes, write high ones */
1275 switch (b[0]) {
1276 case CMD_DB:
1277 if (c.integer > 0xFF) {
1278 warn("`.DB' operand $%X out of range; truncated", c.integer);
1280 break;
1282 case CMD_DW:
1283 fputc(c.integer >> 8, args->fp);
1284 if (c.integer > 0xFFFF) {
1285 warn("`.DW' operand $%X out of range; truncated", c.integer);
1287 break;
1289 case CMD_DD:
1290 fputc(c.integer >> 8, args->fp);
1291 fputc(c.integer >> 16, args->fp);
1292 fputc(c.integer >> 24, args->fp);
1293 break;
1295 /* Advance PC */
1296 switch (b[0]) {
1297 case CMD_DB: inc_pc( 1, arg ); break;
1298 case CMD_DW: inc_pc( 2, arg ); break;
1299 case CMD_DD: inc_pc( 4, arg ); break;
1302 else if (c.type == STRING_CONSTANT) {
1303 /* Write sequence of characters */
1304 for (i=0; i<strlen(c.string); i++) {
1305 /* Write low byte */
1306 fputc(c.string[i], args->fp);
1307 /* If 2+ bytes, write high ones */
1308 switch (b[0]) {
1309 case CMD_DW:
1310 fputc(0, args->fp);
1311 break;
1313 case CMD_DD:
1314 fputc(0, args->fp);
1315 fputc(0, args->fp);
1316 fputc(0, args->fp);
1317 break;
1319 /* Advance PC */
1320 switch (b[0]) {
1321 case CMD_DB: inc_pc( 1, arg ); break;
1322 case CMD_DW: inc_pc( 2, arg ); break;
1323 case CMD_DD: inc_pc( 4, arg ); break;
1328 finalize_constant(&c);
1332 * Writes a series of zeroes.
1334 static void write_dsi8(unsigned char *b, void *arg)
1336 int count;
1337 int i;
1338 write_binary_args *args = (write_binary_args *)arg;
1339 /* Get 8-bit count */
1340 i = 1;
1341 count = get_1(b, &i) + 1;
1342 /* Write zeroes */
1343 for (i=0; i<count; i++) {
1344 fputc(0, args->fp);
1346 /* Advance PC */
1347 inc_pc( count, arg );
1351 * Writes a series of zeroes.
1353 static void write_dsi16(unsigned char *b, void *arg)
1355 int count;
1356 int i;
1357 write_binary_args *args = (write_binary_args *)arg;
1358 /* Get 16-bit count */
1359 i = 1;
1360 count = get_2(b, &i) + 1;
1361 /* Write zeroes */
1362 for (i=0; i<count; i++) {
1363 fputc(0, args->fp);
1365 /* Advance PC */
1366 inc_pc( count, arg );
1370 * Writes a series of zeroes.
1372 static void write_dsb(unsigned char *b, void *arg)
1374 constant c;
1375 int i;
1376 int exid;
1377 write_binary_args *args = (write_binary_args *)arg;
1378 /* Get expression ID */
1379 i = 1;
1380 exid = get_2(b, &i);
1381 /* Evaluate expression */
1382 eval_expression(args->xu, exid, &c);
1383 if (c.integer < 0) {
1384 err("negative count");
1386 else if (c.integer > 0) {
1387 /* Write zeroes */
1388 for (i=0; i<c.integer; i++) {
1389 fputc(0, args->fp);
1391 /* Advance PC */
1392 inc_pc( c.integer, arg );
1397 * Writes a code segment as fully native 6502 code.
1398 * @param fp File handle
1399 * @param u Unit whose code to write
1401 static void write_as_binary(FILE *fp, xunit *u)
1403 write_binary_args args;
1404 /* Table of callback functions for our purpose. */
1405 bytecodeproc handlers[] =
1407 NULL, /* CMD_END */
1408 write_bin8, /* CMD_BIN8 */
1409 write_bin16, /* CMD_BIN16 */
1410 NULL, /* CMD_LABEL */
1411 write_instr, /* CMD_INSTR */
1412 write_dx, /* CMD_DB */
1413 write_dx, /* CMD_DW */
1414 write_dx, /* CMD_DD */
1415 write_dsi8, /* CMD_DSI8 */
1416 write_dsi16, /* CMD_DSI16 */
1417 write_dsb /* CMD_DSB */
1419 /* Fill in args */
1420 args.xu = u;
1421 args.fp = fp;
1422 /* Reset PC */
1423 pc = u->code_origin;
1424 /* Do the walk */
1425 bytecode_walk(u->_unit_.codeseg.bytes, handlers, (void *)&args);
1428 #define XLNK_NO_DEBUG
1429 #ifndef XLNK_NO_DEBUG
1431 /*--------------------------------------------------------------------------*/
1432 /* Functions for debugging bytecodes. */
1435 * Gets string representation of bytecode command.
1436 * @param cmd CMD_*
1437 * @return String representation ("CMD_*")
1439 static const char *bytecode_to_string(unsigned char cmd)
1441 switch (cmd) {
1442 case CMD_FILE: return "CMD_FILE";
1443 case CMD_LINE8: return "CMD_LINE8";
1444 case CMD_LINE16:return "CMD_LINE16";
1445 case CMD_LINE24:return "CMD_LINE24";
1446 case CMD_LINE_INC: return "CMD_LINE_INC";
1447 case CMD_END: return "CMD_END";
1448 case CMD_BIN8: return "CMD_BIN8";
1449 case CMD_BIN16: return "CMD_BIN16";
1450 case CMD_LABEL: return "CMD_LABEL";
1451 case CMD_INSTR: return "CMD_INSTR";
1452 case CMD_DB: return "CMD_DB";
1453 case CMD_DW: return "CMD_DW";
1454 case CMD_DD: return "CMD_DD";
1455 case CMD_DSI8: return "CMD_DSI8";
1456 case CMD_DSI16: return "CMD_DSI16";
1457 case CMD_DSB: return "CMD_DSB";
1459 return "bytecode_to_string: invalid bytecode";
1463 * Print a bytecode.
1464 * @param b Bytecodes
1465 * @param arg Not used
1467 static void print_it(unsigned char *b, void *arg)
1469 printf("%s\n", bytecode_to_string(b[0]) );
1473 * Prints bytecodes.
1474 * @param bytes Bytecodes
1476 static void print_bytecodes(unsigned char *bytes)
1478 bytecodeproc handlers[] =
1480 print_it,print_it,print_it,print_it,print_it,
1481 print_it,print_it,print_it,print_it,print_it,
1482 print_it,print_it,print_it
1484 bytecode_walk(bytes, handlers, NULL);
1488 * Prints a unit.
1489 * @param u Unit
1491 static void print_unit(unit *u)
1493 print_bytecodes(u->dataseg.bytes);
1494 print_bytecodes(u->codeseg.bytes);
1497 #endif /* !XLNK_NO_DEBUG */
1499 /*--------------------------------------------------------------------------*/
1500 /* Functions for managing arrays of unit locals. */
1503 * Creates array of locals.
1504 * @param size Number of locals
1505 * @param la Local array
1507 static void create_local_array(int size, local_array *la)
1509 la->size = size;
1510 /* Allocate space for entries */
1511 if (size > 0) {
1512 la->entries = (local *)malloc(sizeof(local) * size);
1514 else {
1515 la->entries = NULL;
1520 * Finalizes array of locals.
1522 static void finalize_local_array(local_array *la)
1524 int i;
1525 /* Free entry attributes */
1526 for (i=0; i<la->size; i++) {
1527 SAFE_FREE(la->entries[i].name);
1529 /* Free array itself */
1530 SAFE_FREE(la->entries);
1533 /*--------------------------------------------------------------------------*/
1534 /* Functions for counting and registering locals in a unit. */
1535 /* In bytecode expressions, locals are referred to by their index.
1536 In order to not have to go through the bytecodes every time to
1537 find a label definition, the following functions build an array
1538 of structures that can be indexed by the local ID to obtain its
1539 information.
1543 * Counts this local.
1545 static void count_one_local(unsigned char *b, void *arg)
1547 /* Argument points to the counter */
1548 int *count = (int *)arg;
1549 /* Increment count */
1550 (*count)++;
1554 * Counts the number of locals (labels) in an array of bytecodes.
1555 * @param b Bytecodes, terminated by CMD_END
1556 * @return Number of locals counted
1558 static int count_locals(unsigned char *b)
1560 int count;
1561 /* Table of callback functions for our purpose. */
1562 bytecodeproc handlers[] =
1564 NULL, /* CMD_END */
1565 NULL, /* CMD_BIN8 */
1566 NULL, /* CMD_BIN16 */
1567 count_one_local, /* CMD_LABEL */
1568 NULL, /* CMD_INSTR */
1569 NULL, /* CMD_DB */
1570 NULL, /* CMD_DW */
1571 NULL, /* CMD_DD */
1572 NULL, /* CMD_DSI8 */
1573 NULL, /* CMD_DSI16 */
1574 NULL /* CMD_DSB */
1576 /* Reset count */
1577 count = 0;
1578 /* Count the locals now */
1579 bytecode_walk(b, handlers, (void *)&count);
1580 /* Return the number of locals counted */
1581 return count;
1585 * Variable that points to the unit that locals are being registered for.
1587 static xunit *reg_unit = NULL;
1590 * Puts this local into array of locals for current unit.
1592 static void register_one_local(unsigned char *b, void *arg)
1594 int len;
1595 int i= 1;
1596 /* Argument points to a pointer which points to the local struct to fill in */
1597 local **lpptr = (local **)arg;
1598 local *lptr = *lpptr;
1599 /* Initialize some fields */
1600 lptr->resolved = 0;
1601 lptr->ref_count = 0;
1602 lptr->name = NULL;
1603 lptr->align = 1;
1604 lptr->owner = reg_unit;
1605 /* Get flag byte */
1606 lptr->flags = get_1(b, &i);
1607 /* Test export flag */
1608 if (lptr->flags & LABEL_FLAG_EXPORT) {
1609 /* Get the length of the name */
1610 len = get_1(b, &i) + 1;
1611 /* Allocate space for name */
1612 lptr->name = (char *)malloc( len + 1 );
1613 if (lptr->name != NULL) {
1614 /* Copy name from bytecodes */
1615 memcpy(lptr->name, &b[i], len);
1616 /* Zero-terminate string */
1617 lptr->name[len] = '\0';
1619 i += len;
1621 /* Test align flag */
1622 if (lptr->flags & LABEL_FLAG_ALIGN) {
1623 lptr->align = get_1(b, &i);
1625 /* Test address flag */
1626 if (lptr->flags & LABEL_FLAG_ADDR) {
1627 lptr->phys_addr = get_2(b, &i);
1628 lptr->resolved = 1;
1630 #if 0
1631 if (program_args.verbose) {
1632 verbose(1, " %s align=%d resolved=%d",
1633 lptr->name ? lptr->name : "(anonymous)",
1634 lptr->align, lptr->resolved);
1636 #endif
1637 /* Point to next local in array */
1638 *lpptr += 1;
1642 * Puts all locals found in the array of bytecodes into array.
1643 * @param b Bytecodes, terminated by CMD_END
1644 * @param la Pointer to array to receive locals
1645 * @param xu Owner unit
1647 static void register_locals(unsigned char *b, local_array *la, xunit *xu)
1649 local *lptr;
1650 local **lpptr;
1651 /* Table of callback functions for our purpose. */
1652 bytecodeproc handlers[] =
1654 NULL, /* CMD_END */
1655 NULL, /* CMD_BIN8 */
1656 NULL, /* CMD_BIN16 */
1657 register_one_local, /* CMD_LABEL */
1658 NULL, /* CMD_INSTR */
1659 NULL, /* CMD_DB */
1660 NULL, /* CMD_DW */
1661 NULL, /* CMD_DD */
1662 NULL, /* CMD_DSI8 */
1663 NULL, /* CMD_DSI16 */
1664 NULL /* CMD_DSB */
1666 /* Create array of locals */
1667 create_local_array(count_locals(b), la);
1668 /* Prepare args */
1669 lptr = la->entries;
1670 lpptr = &lptr;
1671 reg_unit = xu;
1672 /* Go! */
1673 bytecode_walk(b, handlers, (void *)lpptr);
1676 /*--------------------------------------------------------------------------*/
1677 /* Functions for entering exported symbols into proper hash table. */
1680 * Enters an exported symbol into a hash table.
1681 * @param tab Hash table to enter it into
1682 * @param key Key
1683 * @param data Data
1684 * @param u Owner unit
1686 static void enter_exported_symbol(hashtab *tab, void *key, void *data, unit *u)
1688 /* Make sure symbol doesn't already exist */
1689 if ((hashtab_get(label_hash, key) != NULL)
1690 || (hashtab_get(constant_hash, key) != NULL) ) {
1691 /* Error, duplicate symbol */
1692 err("duplicate symbol `%s' exported from unit `%s'", (char *)key, u->name);
1694 else {
1695 verbose(1, " %s", (char*)key);
1696 /* Enter it */
1697 hashtab_put(tab, key, data);
1702 * Enters all constants in a unit into the proper hash table.
1703 * @param u Unit whose constants to enter
1705 static void enter_exported_constants(unit *u)
1707 int i;
1708 constant *c;
1709 /* Go through all constants in unit */
1710 for (i=0; i<u->const_count; i++) {
1711 c = &u->constants[i];
1712 enter_exported_symbol(constant_hash, (void *)c->name, (void *)c, u);
1717 * Enters locals which should be globally visible into the proper hash table.
1718 * @param la Array of locals
1719 * @param u Owner unit
1721 static void enter_exported_locals(local_array *la, unit *u)
1723 int i;
1724 local *l;
1725 /* Go through all locals */
1726 for (i=0; i<la->size; i++) {
1727 l = &la->entries[i];
1728 /* If it has a name, it is exported */
1729 if (l->name != NULL) {
1730 enter_exported_symbol(label_hash, (void *)l->name, (void *)l, u);
1735 /*--------------------------------------------------------------------------*/
1736 /* Functions for calculating addresses of data labels in a unit. */
1739 * Sets the virtual address of this local to current PC value.
1741 static void set_data_address(unsigned char *b, void *arg)
1743 calc_address_args *args = (calc_address_args *)arg;
1744 /* Get the label */
1745 local *l = &args->xu->data_locals.entries[args->index];
1746 if (!l->resolved) {
1747 /* Set the virtual address */
1748 l->virt_addr = pc;
1749 verbose(2, " %.4X %s", l->virt_addr, l->name ? l->name : "");
1751 /* Increase label index */
1752 args->index++;
1756 * Calculates addresses of labels in a data segment relative to 0.
1757 * Only a small set of bytecode commands are allowed in a data segment:
1758 * - label (which we want to assign a virtual address)
1759 * - storage (constant or variable)
1761 static void calc_data_addresses(xunit *u)
1763 calc_address_args args;
1764 /* Table of callback functions for our purpose. */
1765 bytecodeproc handlers[] =
1767 NULL, /* CMD_END */
1768 NULL, /* CMD_BIN8 */
1769 NULL, /* CMD_BIN16 */
1770 set_data_address, /* CMD_LABEL */
1771 NULL, /* CMD_INSTR */
1772 NULL, /* CMD_DB */
1773 NULL, /* CMD_DW */
1774 NULL, /* CMD_DD */
1775 inc_pc_count8, /* CMD_DSI8 */
1776 inc_pc_count16, /* CMD_DSI16 */
1777 inc_pc_dsb /* CMD_DSB */
1779 /* Fill in args */
1780 args.xu = u;
1781 args.index = 0;
1782 /* Reset PC */
1783 pc = 0;
1784 verbose(1, " %s", u->_unit_.name);
1785 /* Map away! */
1786 bytecode_walk(u->_unit_.dataseg.bytes, handlers, (void *)&args);
1787 /* Store the end address, which is the total size of data */
1788 u->data_size = pc;
1791 /*--------------------------------------------------------------------------*/
1793 /* Constructs 32-bit sort key for local. */
1794 #define SORT_KEY(l) (unsigned long)((((l)->flags & LABEL_FLAG_ZEROPAGE) << 30) | ((l)->align << 24) | (0x10000-(l)->size))
1797 * Array is sorted from high to low value.
1799 static int label_partition(local **a, int p, int r)
1801 int x;
1802 int i;
1803 int j;
1804 x = SORT_KEY(a[r]);
1805 i = p - 1;
1806 local *temp;
1807 for (j=p; j<r; j++) {
1808 if (SORT_KEY(a[j]) >= x) {
1809 i = i + 1;
1810 temp = a[i];
1811 a[i] = a[j];
1812 a[j] = temp;
1815 temp = a[i+1];
1816 a[i+1] = a[r];
1817 a[r] = temp;
1818 return i + 1;
1822 * Quicksort implementation used to sort array of pointers to locals.
1824 static void label_qsort(local **a, int p, int r)
1826 int q;
1827 if (p < r) {
1828 q = label_partition(a, p, r);
1829 label_qsort(a, p, q-1);
1830 label_qsort(a, q+1, r);
1835 * Maps all data labels to 6502 RAM locations.
1836 * This is a very important function. It takes all the data labels from all
1837 * the loaded units and attempts to assign them unique physical addresses.
1838 * The list of target RAM blocks given in the linker script is the premise.
1840 static void map_data_to_ram()
1842 int i, k;
1843 local **total_order;
1844 local *l;
1845 int count;
1846 /* Use a bit array to keep track of allocations,
1847 to ensure that there is no overlap */
1848 unsigned char *allocated;
1849 int ram_base, ram_end;
1851 avail_ram_block *b;
1852 ram_base = 10000000;
1853 ram_end = -10000000;
1854 for (b = ram_block_head; b != NULL; b = b->next) {
1855 if (b->start < ram_base)
1856 ram_base = b->start;
1857 if (b->end > ram_end)
1858 ram_end = b->end;
1861 allocated = (unsigned char *)malloc(((ram_end - ram_base) + 7) / 8);
1862 memset(allocated, 0, ((ram_end - ram_base) + 7) / 8);
1863 /* Calculate total number of labels to map */
1864 count = 0;
1865 for (i=0; i<unit_count; i++) {
1866 count += units[i].data_locals.size;
1868 /* Put pointers to all data labels in one big array */
1869 total_order = (local **)malloc( count * sizeof(local *) );
1870 for (i=0, k=0; i<unit_count; i++) {
1871 int j;
1872 local_array *la;
1873 la = &units[i].data_locals;
1874 for (j=0; j<la->size; j++) {
1875 int size;
1876 /* Use virtual addresses to calculate size from this label to next */
1877 if (j == la->size-1) {
1878 size = units[i].data_size;
1880 else {
1881 size = la->entries[j+1].virt_addr;
1883 la->entries[j].size = size - la->entries[j].virt_addr;
1884 /* Put pointer in array */
1885 total_order[k++] = &la->entries[j];
1888 /* Sort them */
1889 label_qsort(total_order, 0, count-1);
1890 /* Map them */
1891 for (i=0; i<count; i++) {
1892 l = total_order[i];
1893 /* Try to allocate it */
1894 if (alloc_ram(l) == 1) {
1895 /* Good, label mapped successfully */
1896 l->resolved = 1;
1897 verbose(1, " %.4X-%.4X %s (%s)", l->phys_addr,
1898 l->phys_addr + l->size-1, l->name ? l->name : "",
1899 l->owner->_unit_.name);
1901 /* Verify that there's no overlap with other variable */
1902 int a;
1903 for (a = l->phys_addr; a < l->phys_addr + l->size; ++a) {
1904 assert((allocated[(a - ram_base) / 8] & (1 << (a & 7))) == 0);
1905 allocated[(a - ram_base) / 8] |= 1 << (a & 7);
1909 else {
1910 /* Error, couldn't allocate */
1911 err("out of 6502 RAM while allocating unit `%s'", l->owner->_unit_.name);
1912 return;
1915 free(total_order);
1916 free(allocated);
1919 /*--------------------------------------------------------------------------*/
1920 /* Functions for calculating offsets of code labels in a unit. */
1923 * Sets the address of this code label to current PC.
1925 static void set_code_address(unsigned char *b, void *arg)
1927 calc_address_args *args = (calc_address_args *)arg;
1928 /* Get the label */
1929 local *l = &args->xu->code_locals.entries[args->index];
1930 if (!l->resolved) {
1931 /* Set the physical address to current PC */
1932 l->phys_addr = pc;
1933 l->resolved = 1;
1934 if (program_args.verbose) {
1935 fprintf(stdout, " %.4X %s (%s)\n", l->phys_addr,
1936 l->name ? l->name : "", l->owner->_unit_.name);
1939 /* Increase label index */
1940 args->index++;
1944 * Calculates addresses of code labels in a segment.
1945 * NOTE: Only the virtual addresses (relative to 0) are calculated.
1946 * The labels then need to be relocated to obtain the physical address (see below).
1947 * @param u Unit
1949 static void calc_code_addresses(xunit *u)
1951 calc_address_args args;
1952 /* Table of callback functions for our purpose. */
1953 bytecodeproc handlers[] =
1955 NULL, /* CMD_END */
1956 inc_pc_count8, /* CMD_BIN8 */
1957 inc_pc_count16, /* CMD_BIN16 */
1958 set_code_address, /* CMD_LABEL */
1959 inc_pc_instr, /* CMD_INSTR */
1960 inc_pc_1, /* CMD_DB -- TODO, error if string */
1961 inc_pc_2, /* CMD_DW */
1962 inc_pc_4, /* CMD_DD */
1963 inc_pc_count8, /* CMD_DSI8 */
1964 inc_pc_count16, /* CMD_DSI16 */
1965 inc_pc_dsb /* CMD_DSB */
1967 /* Fill in args */
1968 args.xu = u;
1969 args.index = 0;
1970 /* Do the walk */
1971 bytecode_walk(u->_unit_.codeseg.bytes, handlers, (void *)&args);
1972 /* Store the total size of code */
1973 u->code_size = pc - u->code_origin;
1976 /*--------------------------------------------------------------------------*/
1979 * Issues a script error.
1981 static void scripterr(script *s, script_command *c, char *fmt, ...)
1983 va_list ap;
1984 va_start(ap, fmt);
1986 if (!suppress) {
1987 /* Print error message */
1988 fprintf(stderr, "error: %s:%d: `%s': ", s->name, c->line, script_command_type_to_string(c->type) );
1989 vfprintf(stderr, fmt, ap);
1990 fprintf(stderr, "\n");
1991 /* Increase error count */
1992 err_count++;
1994 va_end(ap);
1997 #define require_arg(s, c, a, d) { \
1998 d = script_get_command_arg(c, a); \
1999 if (d == NULL) { \
2000 scripterr(s, c, "missing argument `%s'", a); \
2001 return; \
2005 #define require_arg_in_range(s, c, a, v, l, h) { \
2006 if (((v) < (l)) || ((v) > (h))) { \
2007 scripterr(s, c, "value of argument `%s' is out of range", a); \
2008 return; \
2012 /*--------------------------------------------------------------------------*/
2013 /* Functions for registering RAM blocks in script. */
2016 * Registers one RAM block based on 'ram' script command.
2017 * @param s Linker script
2018 * @param c Command of type RAM_COMMAND
2019 * @param arg Not used
2021 static void register_one_ram_block(script *s, script_command *c, void *arg)
2023 int start;
2024 int end;
2025 char *start_str;
2026 char *end_str;
2027 /* Get arguments */
2028 require_arg(s, c, "start", start_str);
2029 require_arg(s, c, "end", end_str);
2030 /* Convert to integers */
2031 start = str_to_int(start_str);
2032 end = str_to_int(end_str);
2033 /* Check that they are sane */
2034 require_arg_in_range(s, c, "start", start, 0x0000, 0xFFFF);
2035 require_arg_in_range(s, c, "end", end, 0x0000, 0xFFFF);
2036 if (end <= start) {
2037 scripterr(s, c, "`end' is smaller than `start'");
2039 /* Add block */
2040 add_ram_block(start, end);
2044 * Registers RAM blocks based on 'ram' commands in a script.
2045 * @param sc Linker script
2047 static void register_ram_blocks(script *sc)
2049 /* Table of mappings for our purpose */
2050 static script_commandprocmap map[] = {
2051 { RAM_COMMAND, register_one_ram_block },
2052 { BAD_COMMAND, NULL }
2054 /* Do the walk */
2055 script_walk(sc, map, NULL);
2056 /* Calculate total RAM size */
2057 total_ram = ram_left();
2060 /*--------------------------------------------------------------------------*/
2061 /* Functions for loading and initial processing of units in script. */
2064 * Registers (parses etc.) one unit based on 'link' script command.
2065 * @param s Linker script
2066 * @param c Command of type LINK_COMMAND
2067 * @param arg Pointer to unit index
2069 static void register_one_unit(script *s, script_command *c, void *arg)
2071 char *file;
2072 int *i;
2073 xunit *xu;
2074 /* Get unit filename */
2075 require_arg(s, c, "file", file);
2076 /* arg is pointer to unit index */
2077 i = (int *)arg;
2078 /* Get pointer to xunit to fill in */
2079 xu = &units[*i];
2080 /* Read basic unit from file */
2081 if (unit_read(file, &xu->_unit_) == 0) {
2082 /* Something bad happened when trying to read unit */
2083 scripterr(s, c, "failed to load unit `%s'", file);
2084 xu->loaded = 0;
2085 return;
2087 xu->loaded = 1;
2088 verbose(1, " unit `%s' loaded", file);
2089 /* Register locals for both segments */
2090 verbose(1, " registering local symbols...");
2091 register_locals(xu->_unit_.dataseg.bytes, &xu->data_locals, xu);
2092 register_locals(xu->_unit_.codeseg.bytes, &xu->code_locals, xu);
2093 /* Enter exported symbols into hash tables */
2094 verbose(1, " registering public symbols...");
2095 enter_exported_constants(&xu->_unit_);
2096 enter_exported_locals(&xu->data_locals, &xu->_unit_);
2097 enter_exported_locals(&xu->code_locals, &xu->_unit_);
2098 /* Put unit in hash table */
2099 hashtab_put(unit_hash, file, xu);
2100 /* Increment unit index */
2101 (*i)++;
2105 * Registers units based on 'link' commands in script.
2106 * @param sc Linker script
2108 static void register_units(script *sc)
2110 /* Table of mappings for our purpose */
2111 static script_commandprocmap map[] = {
2112 { LINK_COMMAND, register_one_unit },
2113 { BAD_COMMAND, NULL }
2115 int i = 0;
2116 /* Do the walk */
2117 script_walk(sc, map, (void *)&i);
2120 /*--------------------------------------------------------------------------*/
2121 /* Functions for composing a binary file based on a sequential list of
2122 script commands. */
2125 * Sets the output file according to 'output' script command.
2126 * @param s Linker script
2127 * @param c Command of type OUTPUT_COMMAND
2128 * @param arg Pointer to file handle
2130 static void set_output(script *s, script_command *c, void *arg)
2132 char *file;
2133 FILE **fpp;
2134 /* Get the name of new output file */
2135 require_arg(s, c, "file", file);
2136 /* Arg is pointer to file handle pointer */
2137 fpp = (FILE **)arg;
2138 /* Close current file */
2139 if (*fpp != NULL) {
2140 fclose(*fpp);
2142 /* Attempt to open new file */
2143 *fpp = fopen(file, "wb");
2144 if (*fpp == NULL) {
2145 scripterr(s, c, "could not open `%s' for writing", file);
2147 else {
2148 verbose(1, " output goes to `%s'", file);
2153 * Copies a file to output according to 'copy' script command.
2154 * @param s Linker script
2155 * @param c Command of type COPY_COMMAND
2156 * @param arg Pointer to file handle
2158 static void copy_to_output(script *s, script_command *c, void *arg)
2160 char *file;
2161 FILE **fpp;
2162 FILE *cf;
2163 unsigned char k;
2164 /* Arg is pointer to file handle pointer */
2165 fpp = (FILE **)arg;
2166 /* Make sure there is a file to write to */
2167 if (*fpp == NULL) {
2168 scripterr(s, c, "no output open");
2170 else {
2171 /* Get the name of file to copy */
2172 require_arg(s, c, "file", file);
2173 /* Attempt to open the file to copy */
2174 cf = fopen(file, "rb");
2175 if (cf == NULL) {
2176 scripterr(s, c, "could not open `%s' for reading", file);
2178 else {
2179 verbose(1, " copying `%s' to output at position %ld...", file, ftell(*fpp) );
2180 /* Copy it to output, byte for byte */
2181 for (k = fgetc(cf); !feof(cf); k = fgetc(cf) ) {
2182 fputc(k, *fpp);
2184 /* Advance offset */
2185 bank_offset += ftell(cf);
2186 pc += ftell(cf);
2187 /* Close the copied file */
2188 fclose(cf);
2189 /* Check if exceeded bank size */
2190 if (bank_offset > bank_size) {
2191 scripterr(s, c, "bank size (%d) exceeded by %d bytes", bank_size, bank_offset - bank_size);
2198 * Starts a new bank according to 'bank' script command.
2199 * @param s Linker script
2200 * @param c Command of type BANK_COMMAND
2201 * @param arg Pointer to file handle
2203 static void start_bank(script *s, script_command *c, void *arg)
2205 char *size_str;
2206 char *origin_str;
2207 /* See if size specified */
2208 size_str = script_get_command_arg(c, "size");
2209 if (size_str != NULL) {
2210 /* Set new bank size */
2211 bank_size = str_to_int(size_str);
2212 /* Sanity check */
2213 if (bank_size <= 0) {
2214 scripterr(s, c, "invalid size");
2217 else {
2218 /* Use bank size of previous bank if there was one */
2219 /* Otherwise issue error */
2220 if (bank_size == 0x7FFFFFFF) {
2221 scripterr(s, c, "no bank size set");
2224 /* See if origin specified */
2225 origin_str = script_get_command_arg(c, "origin");
2226 if (origin_str != NULL) {
2227 /* Set new bank origin */
2228 bank_origin = str_to_int(origin_str);
2229 /* Sanity check */
2230 require_arg_in_range(s, c, "origin", bank_origin, 0x0000, 0xFFFF);
2232 else {
2233 /* Use old bank origin */
2235 bank_id++;
2236 /* Reset bank offset and PC */
2237 bank_offset = 0;
2238 pc = bank_origin;
2242 * Writes unit according to 'link' script command.
2243 * @param s Linker script
2244 * @param c Command of type LINK_COMMAND
2245 * @param arg Pointer to file handle
2247 static void write_unit(script *s, script_command *c, void *arg)
2249 FILE **fpp;
2250 xunit *xu;
2251 char *file;
2252 /* Arg is pointer to file handle pointer */
2253 fpp = (FILE **)arg;
2254 /* Make sure there is a file to write to */
2255 if (*fpp == NULL) {
2256 scripterr(s, c, "no output open");
2258 else {
2259 /* Get the name of the unit */
2260 require_arg(s, c, "file", file);
2261 /* Look it up */
2262 xu = (xunit *)hashtab_get(unit_hash, file);
2263 /* Write it */
2264 verbose(1, " appending unit `%s' to output at position %ld...", file, ftell(*fpp));
2265 write_as_binary(*fpp, xu);
2266 /* Advance offset */
2267 bank_offset += xu->code_size;
2268 /* Check if exceeded bank size */
2269 if (bank_offset > bank_size) {
2270 scripterr(s, c, "bank size (%d) exceeded by %d bytes", bank_size, bank_offset - bank_size);
2276 * Pads output file according to 'pad' script command.
2277 * @param s Linker script
2278 * @param c Command of type PAD_COMMAND
2279 * @param arg Pointer to file handle
2281 static void write_pad(script *s, script_command *c, void *arg)
2283 FILE **fpp;
2284 int i;
2285 int count;
2286 int offset;
2287 int origin;
2288 char *offset_str;
2289 char *origin_str;
2290 char *size_str;
2291 /* Arg is pointer to file handle pointer */
2292 fpp = (FILE **)arg;
2293 /* Make sure there is a file to write to */
2294 if (*fpp == NULL) {
2295 scripterr(s, c, "no output open");
2297 else {
2298 if ((offset_str = script_get_command_arg(c, "offset")) != NULL) {
2299 offset = str_to_int(offset_str);
2300 /* Calculate number of zeroes to write */
2301 count = offset - bank_offset;
2303 else if ((origin_str = script_get_command_arg(c, "origin")) != NULL) {
2304 origin = str_to_int(origin_str);
2305 /* Calculate number of zeroes to write */
2306 count = origin - pc;
2308 else if ((size_str = script_get_command_arg(c, "size")) != NULL) {
2309 count = str_to_int(size_str);
2311 else {
2312 scripterr(s, c, "missing argument");
2313 count = 0;
2315 /* Sanity check */
2316 if (count < 0) {
2317 scripterr(s, c, "cannot pad backwards");
2318 count = 0;
2320 else if (count > 0) {
2321 verbose(1, " padding %d bytes...", count);
2323 /* Write zeroes */
2324 for (i=0; i<count; i++) {
2325 fputc(0, *fpp);
2327 /* Advance offset */
2328 bank_offset += count;
2329 pc += count;
2330 /* Check if exceeded bank size */
2331 if (bank_offset > bank_size) {
2332 scripterr(s, c, "bank size (%d) exceeded by %d bytes", bank_size, bank_offset - bank_size);
2338 * Pads to end of bank in file if bank size not reached.
2339 * @param s Linker script
2340 * @param c Command of type BANK_COMMAND
2341 * @param fp File handle
2343 static void maybe_pad_bank(script *s, script_command *c, FILE *fp)
2345 int i;
2346 if ( (bank_size != 0x7FFFFFFF) && (bank_offset < bank_size) ) {
2347 /* Make sure there is a file to write to */
2348 if (fp == NULL) {
2349 scripterr(s, c, "no output open");
2351 else {
2352 /* Pad until bank size */
2353 for (i=bank_offset; i<bank_size; i++) {
2354 fputc(0, fp);
2361 * Finishes old bank in output and starts new bank.
2362 * @param s Linker script
2363 * @param c Command of type BANK_COMMAND
2364 * @param arg Pointer to file handle
2366 static void write_bank(script *s, script_command *c, void *arg)
2368 FILE **fpp;
2369 /* Arg is pointer to file handle pointer */
2370 fpp = (FILE **)arg;
2371 /* Pad bank if necessary */
2372 maybe_pad_bank(s, c, *fpp);
2373 /* Start new bank */
2374 start_bank(s, c, arg);
2378 * Generates the final binary output from the linker.
2379 * @param sc Linker script
2381 static void generate_output(script *sc)
2383 FILE *fp = NULL;
2384 /* Table of mappings for our purpose */
2385 static script_commandprocmap map[] = {
2386 { OUTPUT_COMMAND, set_output },
2387 { COPY_COMMAND, copy_to_output },
2388 { BANK_COMMAND, write_bank },
2389 { LINK_COMMAND, write_unit },
2390 { PAD_COMMAND, write_pad },
2391 { BAD_COMMAND, NULL }
2393 /* Reset offsets */
2394 bank_size = 0x7FFFFFFF;
2395 bank_offset = 0;
2396 bank_origin = 0;
2397 bank_id = -1;
2398 pc = 0;
2399 /* Do the walk */
2400 script_walk(sc, map, (void *)&fp);
2401 /* Pad last bank if necessary */
2402 maybe_pad_bank(sc, sc->first_command, fp);
2405 /*--------------------------------------------------------------------------*/
2408 * Increases bank offset and PC according to size of the file specified by
2409 * 'copy' script command.
2410 * @param s Linker script
2411 * @param c Command of type COPY_COMMAND
2412 * @param arg Not used
2414 static void inc_offset_copy(script *s, script_command *c, void *arg)
2416 char *file;
2417 FILE *fp;
2418 /* Get the name of the file */
2419 require_arg(s, c, "file", file);
2420 /* Attempt to it */
2421 fp = fopen(file, "rb");
2422 if (fp == NULL) {
2423 scripterr(s, c, "could not open `%s' for reading", file);
2425 else {
2426 /* Seek to end */
2427 fseek(fp, 0, SEEK_END);
2428 /* Advance offset */
2429 bank_offset += ftell(fp);
2430 pc += ftell(fp);
2431 /* Close the file */
2432 fclose(fp);
2433 /* Check if exceeded bank size */
2434 if (bank_offset > bank_size) {
2435 scripterr(s, c, "bank size (%d) exceeded by %d bytes", bank_size, bank_offset - bank_size);
2441 * Sets the origin of a unit and relocates its code to this location.
2442 * @param s Linker script
2443 * @param c Command of type LINK_COMMAND
2444 * @param arg Not used
2446 static void set_unit_origin(script *s, script_command *c, void *arg)
2448 xunit *xu;
2449 char *file;
2450 char *origin_str;
2451 int origin;
2452 /* Get the unit filename */
2453 require_arg(s, c, "file", file);
2454 /* Look it up */
2455 xu = (xunit *)hashtab_get(unit_hash, file);
2456 /* Check if origin specified */
2457 origin_str = script_get_command_arg(c, "origin");
2458 if (origin_str != NULL) {
2459 origin = str_to_int(origin_str);
2460 require_arg_in_range(s, c, "origin", origin, 0x0000, 0xFFFF);
2461 xu->code_origin = origin;
2462 pc = origin;
2464 else {
2465 /* No origin specified. Set to PC. */
2466 xu->code_origin = pc;
2468 xu->bank_id = bank_id;
2469 /* Now we can calculate the physical code addresses of the unit. */
2470 calc_code_addresses(xu);
2471 /* Print info if verbose mode */
2472 verbose(1, " unit `%s' relocated to %.4X", xu->_unit_.name, xu->code_origin);
2473 /* Increase bank offset */
2474 bank_offset += xu->code_size;
2478 * Increases bank offset and PC according to 'pad' script command.
2479 * @param s Linker script
2480 * @param c Command of type PAD_COMMAND
2481 * @param arg Not used
2483 static void inc_offset_pad(script *s, script_command *c, void *arg)
2485 int count;
2486 int offset;
2487 int origin;
2488 char *offset_str;
2489 char *origin_str;
2490 char *size_str;
2491 if ((offset_str = script_get_command_arg(c, "offset")) != NULL) {
2492 offset = str_to_int(offset_str);
2493 /* Calculate number of zeroes to write */
2494 count = offset - bank_offset;
2496 else if ((origin_str = script_get_command_arg(c, "origin")) != NULL) {
2497 origin = str_to_int(origin_str);
2498 /* Calculate number of zeroes to write */
2499 count = origin - pc;
2501 else if ((size_str = script_get_command_arg(c, "size")) != NULL) {
2502 count = str_to_int(size_str);
2504 else {
2505 /* Error */
2506 scripterr(s, c, "missing argument");
2507 count = 0;
2509 /* Sanity check */
2510 if (count < 0) {
2511 scripterr(s, c, "cannot pad %d bytes backwards", -count);
2512 count = 0;
2514 /* Advance offset */
2515 bank_offset += count;
2516 pc += count;
2517 /* Check if exceeded bank size */
2518 if (bank_offset > bank_size) {
2519 scripterr(s, c, "bank size (%d) exceeded by %d bytes", bank_size, bank_offset - bank_size);
2524 * Relocates code of all units according to script commands and/or their position
2525 * in the final binary.
2526 * @param sc Linker script
2528 static void relocate_units(script *sc)
2530 /* Table of mappings for our purpose */
2531 static script_commandprocmap map[] = {
2532 { COPY_COMMAND, inc_offset_copy },
2533 { BANK_COMMAND, start_bank },
2534 { LINK_COMMAND, set_unit_origin },
2535 { PAD_COMMAND, inc_offset_pad },
2536 { BAD_COMMAND, NULL }
2538 /* Reset offsets */
2539 bank_size = 0x7FFFFFFF;
2540 bank_offset = 0;
2541 bank_origin = 0;
2542 bank_id = -1;
2543 pc = 0;
2544 /* Do the walk */
2545 script_walk(sc, map, NULL);
2551 static void maybe_print_ram_statistics()
2553 int used;
2554 int left;
2555 if (total_ram > 0) {
2556 left = ram_left();
2557 used = total_ram - left;
2558 verbose(1, " total RAM: %d bytes", total_ram);
2559 verbose(1, " RAM used: %d bytes (%d%%)", used, (int)(((float)used / (float)total_ram)*100.0f) );
2560 verbose(1, " RAM left: %d bytes (%d%%)", left, (int)(((float)left / (float)total_ram)*100.0f) );
2564 /*--------------------------------------------------------------------------*/
2567 * Program entrypoint.
2569 int main(int argc, char **argv)
2571 int i;
2572 script sc;
2574 /* Parse our arguments. */
2575 parse_arguments(argc, argv);
2577 suppress = 0;
2578 /* Reset error and warning count */
2579 err_count = 0;
2580 warn_count = 0;
2582 /* Parse the linker script */
2583 verbose(1, "parsing linker script...");
2584 if (script_parse(program_args.input_file, &sc) == 0) {
2585 /* Something bad happened when parsing script, halt */
2586 return(1);
2589 /* Process all ram commands */
2590 verbose(1, "registering RAM blocks...");
2591 register_ram_blocks(&sc);
2593 /* Create hash tables to hold symbols */
2594 constant_hash = hashtab_create(23, HASHTAB_STRKEYHSH, HASHTAB_STRKEYCMP);
2595 label_hash = hashtab_create(23, HASHTAB_STRKEYHSH, HASHTAB_STRKEYCMP);
2596 unit_hash = hashtab_create(11, HASHTAB_STRKEYHSH, HASHTAB_STRKEYCMP);
2598 /* Count units. One unit per link command. */
2599 unit_count = script_count_command_type(&sc, LINK_COMMAND);
2600 /* Allocate array of xunits */
2601 if (unit_count > 0) {
2602 units = (xunit *)malloc( sizeof(xunit) * unit_count );
2604 else {
2605 units = NULL;
2607 /* Process link commands */
2608 verbose(1, "loading units...");
2609 register_units(&sc);
2610 /* Make sure all units were loaded */
2611 if (err_count != 0) {
2612 // TODO
2613 assert(0);
2616 /* Only continue with processing if no unresolved symbols */
2617 if (err_count == 0) {
2618 /* Calculate 0-relative addresses of data labels */
2619 verbose(1, "calculating data addresses...");
2620 for (i=0; i<unit_count; i++) {
2621 calc_data_addresses(&units[i]);
2624 /* TODO: Count references: go through all instructions, find EXTRN and LOCAL operands in expressions */
2625 /* TODO: Find modes of access for each DATA label (i.e. label MUST be allocated in zero page) */
2627 /* Map all data labels to 6502 RAM locations */
2628 verbose(1, "mapping data to RAM...");
2629 map_data_to_ram();
2630 maybe_print_ram_statistics();
2632 /* Only continue with processing if all data labels were mapped */
2633 if (err_count == 0) {
2634 verbose(1, "relocating code...");
2635 suppress = 1;
2636 relocate_units(&sc);
2637 suppress = 0;
2638 relocate_units(&sc);
2640 /* Only continue with processing if all code labels were mapped */
2641 if (err_count == 0) {
2642 verbose(1, "generating output...");
2643 generate_output(&sc);
2648 /* Cleanup */
2649 verbose(1, "cleaning up...");
2651 /* Finalize units */
2652 for (i=0; i<unit_count; i++) {
2653 if (units[i].loaded) {
2654 finalize_local_array( &units[i].data_locals );
2655 finalize_local_array( &units[i].code_locals );
2656 unit_finalize( &units[i]._unit_ );
2659 /* Finalize hash tables */
2660 hashtab_finalize(label_hash);
2661 hashtab_finalize(constant_hash);
2662 hashtab_finalize(unit_hash);
2663 /* Finalize RAM blocks */
2664 finalize_ram_blocks();
2665 /* Finalize the script */
2666 script_finalize(&sc);
2668 /* All done. */
2669 return (err_count == 0) ? 0 : 1;