9 date 2007.08.12.18.58.12; author khansen; state Exp;
14 date 2007.08.09.20.33.48; author khansen; state Exp;
19 date 2007.08.07.22.42.17; author khansen; state Exp;
24 date 2007.08.07.21.23.24; author khansen; state Exp;
29 date 2007.07.22.13.33.26; author khansen; state Exp;
34 date 2004.12.19.19.58.37; author kenth; state Exp;
39 date 2004.12.18.16.58.52; author kenth; state Exp;
44 date 2004.12.14.01.49.14; author kenth; state Exp;
49 date 2004.12.06.04.52.36; author kenth; state Exp;
54 date 2004.06.30.07.55.38; author kenth; state Exp;
65 @ability to generate pure 6502 binary (--pure-binary switch)
69 * $Id: codegen.c,v 1.9 2007/08/09 20:33:48 khansen Exp khansen $
71 * Revision 1.9 2007/08/09 20:33:48 khansen
74 * Revision 1.8 2007/08/07 22:42:17 khansen
75 * make sure a CMD_FILE command is output at the start of each segment
77 * Revision 1.7 2007/08/07 21:23:24 khansen
80 * Revision 1.6 2007/07/22 13:33:26 khansen
81 * convert tabs to whitespaces
83 * Revision 1.5 2004/12/19 19:58:37 kenth
86 * Revision 1.4 2004/12/18 16:58:52 kenth
87 * outputs file and line info if --debug
88 * CMD_DSW, CMD_DSD gone
90 * Revision 1.3 2004/12/14 01:49:14 kenth
93 * Revision 1.2 2004/12/06 04:52:36 kenth
96 * Revision 1.1 2004/06/30 07:55:38 kenth
102 * (C) 2004 Kent Hansen
104 * The XORcyst is free software; you can redistribute it and/or modify
105 * it under the terms of the GNU General Public License as published by
106 * the Free Software Foundation; either version 2 of the License, or
107 * (at your option) any later version.
109 * The XORcyst is distributed in the hope that it will be useful,
110 * but WITHOUT ANY WARRANTY; without even the implied warranty of
111 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
112 * GNU General Public License for more details.
114 * You should have received a copy of the GNU General Public License
115 * along with The XORcyst; if not, write to the Free Software
116 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
120 * This file contains functions for generating object code from an abstract
122 * The output of the assembler is not pure 6502 binary code. It is a file in
123 * a custom object format meant to be fed to the XORcyst linker. The object
124 * file contains information about the symbols it exports (that others may
125 * access), the symbols it imports (the linker will look for these in other
126 * units and resolve their values), and of course the 6502 instructions.
127 * Labels, data and instructions are encoded in a special bytecode language.
128 * All operands to instructions and directives which aren't constants are
129 * stored as expressions. (It is the linker's job to parse the expressions,
130 * compute their values and produce the actual 6502 binary.)
132 * The format of resulting file is:
133 * 1 word: magic number
135 * 1 word: number of exported constants
136 * ? bytes: exported constants descriptors
137 * 1 byte: number of units explicitly imported from
138 * ? bytes: names of units explicitly imported from
139 * 1 word: number of imported symbols (externals)
140 * ? bytes: imported symbols descriptors
141 * 24-bit word: size of data segment
142 * ? bytes: data segment bytecodes
143 * 24-bit word: size of code segment
144 * ? bytes: code segment bytecodes
145 * 1 word: number of expressions
146 * ? bytes: expression descriptors
159 /*---------------------------------------------------------------------------*/
161 /* Convenient macros to write integers in big-endian form. */
162 #define put_1(f, b) { fputc((unsigned char)(b), f); }
163 #define put_2(f, w) { put_1(f, (w) >> 8); put_1(f, w); }
164 #define put_3(f, t) { put_2(f, (t) >> 8); put_1(f, t); }
165 #define put_4(f, q) { put_2(f, (q) >> 16); put_2(f, q); }
167 /* Convenient macros to write length-prepended strings. */
168 #define put_str_8(f, s) { put_1(f, strlen(s)-1); fprintf(f, "%s", s); }
169 #define put_str_16(f, s) { put_2(f, strlen(s)-1); fprintf(f, "%s", s); }
170 #define put_str(f, s) { if (strlen(s) <= 0x100) { put_str_8(f, s); } else { put_str_16(f, s); } }
173 * Writes a sequence of bytes to file.
174 * @@param f File handle
175 * @@param bytes Array of bytes
176 * @@param count Number of bytes
178 static void put_bytes(FILE *f, const unsigned char *bytes, int count)
181 /* Write the bytes */
182 for (i=0; i<count; i++) {
187 /*---------------------------------------------------------------------------*/
189 #define BUF_MAX_SIZE 0x10000
190 /** Buffer used to collect binary data generated from processing consecutive code statements. */
191 static unsigned char buf[BUF_MAX_SIZE];
192 /** Current position in buffer */
193 static int buf_pos = 0;
195 static FILE *buf_file = NULL;
197 #define buf_reset() { buf_pos = 0; }
200 * Flushes contents of <code>buf</code> to file.
201 * @@param f File handle
203 static void buf_flush(FILE *f)
206 if (buf_pos <= 0x100) {
207 /* Use 8-bit form. */
209 put_1(f, buf_pos - 1);
210 put_bytes(f, buf, buf_pos);
212 else if (buf_pos <= 0x10000) {
213 /* Use 16-bit form. */
215 put_2(f, buf_pos - 1);
216 put_bytes(f, buf, buf_pos);
219 /* Error, buffer overflow. */
220 fprintf(stderr, "buf_flush: buffer overflow\n");
226 /** Appends single byte to buffer. */
227 #define buf_append(b) { if (buf_pos >= BUF_MAX_SIZE) buf_flush(buf_file); buf[buf_pos++] = (unsigned char)(b); }
229 /** Appends n bytes to buffer. */
230 static void buf_append_n(unsigned char *data, int size)
233 for (i=0; i<size; i++) {
238 /*---------------------------------------------------------------------------*/
241 * Converts an arithmetic operator (from ARITHMETIC_NODE) into a byte value.
242 * The bytecode language uses a different operator encoding which is why
243 * we need this function.
244 * @@param op Operator to convert
245 * @@return Bytecode-equivalent operator
247 static unsigned char operator_to_bytecode(arithmetic_operator op)
250 case PLUS_OPERATOR: return OP_PLUS;
251 case MINUS_OPERATOR: return OP_MINUS;
252 case MUL_OPERATOR: return OP_MUL;
253 case DIV_OPERATOR: return OP_DIV;
254 case MOD_OPERATOR: return OP_MOD;
255 case AND_OPERATOR: return OP_AND;
256 case OR_OPERATOR: return OP_OR;
257 case XOR_OPERATOR: return OP_XOR;
258 case SHL_OPERATOR: return OP_SHL;
259 case SHR_OPERATOR: return OP_SHR;
260 case LT_OPERATOR: return OP_LT;
261 case GT_OPERATOR: return OP_GT;
262 case EQ_OPERATOR: return OP_EQ;
263 case NE_OPERATOR: return OP_NE;
264 case LE_OPERATOR: return OP_LE;
265 case GE_OPERATOR: return OP_GE;
266 case NEG_OPERATOR: return OP_NEG;
267 case NOT_OPERATOR: return OP_NOT;
268 case LO_OPERATOR: return OP_LO;
269 case HI_OPERATOR: return OP_HI;
270 case UMINUS_OPERATOR: return OP_UMINUS;
271 case BANK_OPERATOR: return OP_BANK;
274 fprintf(stderr, "operator_to_bytecode(): bad operator\n");
279 /*---------------------------------------------------------------------------*/
281 /* Maximum number of expressions that the code generator can handle. */
282 #define MAX_EXPRS 16384
284 /* List of expressions involved in code statements. */
285 static astnode *expr_list[MAX_EXPRS];
286 /* Number of expressions generated so far. */
287 static int expr_count = 0;
290 * Registers an expression with the code generator.
291 * Unique 16-bit ID of the expression is returned, which may then be used to refer
292 * to the expression in bytecodes.
293 * @@param expr Expression to register
294 * @@return Unique ID of expression
296 static int register_expression(astnode *expr)
299 /* See if an equivalent expression already is registered */
300 for (i=0; i<expr_count; i++) {
301 if (astnode_equal(expr, expr_list[i])) {
302 /* Return ID of equivalent expression. */
306 /* This is a new expression, add it to end of list if possible. */
307 if (expr_count == MAX_EXPRS) {
308 fprintf(stderr, "register_expression(): buffer overflow\n");
312 expr_list[expr_count++] = expr;
318 * Serializes an expression recursively.
319 * The result of serializing a leaf node is always (type, value).
320 * The result of serializing an operator node is always (operator, lhs, rhs).
321 * @@param fp File handle
322 * @@param expr Expression to serialize
324 static void put_expr_recursive(FILE *fp, const astnode *expr)
329 if (expr == NULL) { return; }
330 // printf("put_expr_recursive(%s)\n", astnode_type_to_string(expr->type) );
331 switch (astnode_get_type(expr)) {
333 v = (unsigned long)expr->integer;
335 /* Write type */ put_1(fp, INT_8);
336 /* Write value */ put_1(fp, v);
338 else if (v < 0x10000) {
339 /* Write type */ put_1(fp, INT_16);
340 /* Write value */ put_2(fp, v);
342 else if (v < 0x1000000) {
343 /* Write type */ put_1(fp, INT_24);
344 /* Write value */ put_3(fp, v);
347 /* Write type */ put_1(fp, INT_32);
348 /* Write value */ put_4(fp, v);
354 if (strlen(s) <= 0x100) {
355 /* Write type */ put_1(fp, STR_8);
356 /* Write string */ put_str_8(fp, s);
359 /* Write type */ put_1(fp, STR_16);
360 /* Write string */ put_str_16(fp, s);
364 case IDENTIFIER_NODE:
366 e = symtab_lookup(expr->ident);
368 put_1(fp, (e->flags & EXTRN_FLAG) ? EXTRN : LOCAL);
373 case ARITHMETIC_NODE:
374 /* The operator goes first */
375 put_1(fp, operator_to_bytecode(expr->oper) );
376 /* Then left-hand side */
377 put_expr_recursive(fp, LHS(expr));
378 /* Then right-hand side */
379 put_expr_recursive(fp, RHS(expr));
382 case CURRENT_PC_NODE:
390 "put_expr_recursive(): unknown expression type (%s)\n",
391 astnode_type_to_string(astnode_get_type(expr))
398 * Serializes an expression.
399 * The expression is written in postfix form so that it can be easily evaluated
400 * even as pure binary.
401 * @@param fp File handle
402 * @@param expr Expression to serialize
404 static void put_expr(FILE *fp, const astnode *expr)
406 put_expr_recursive(fp, expr);
410 * Writes all expressions registered during code generation to file.
411 * @@param fp File handle
413 static void put_expressions(FILE *fp)
416 /* Write expression count */
417 put_2(fp, expr_count);
418 /* Write serialized expressions */
419 for (i=0; i<expr_count; i++) {
420 put_expr(fp, expr_list[i]);
424 /*---------------------------------------------------------------------------*/
427 * Tests if two file location descriptors are equal.
429 static int locations_are_equal(const location *l1, const location *l2)
431 return ((l1->first_line == l2->first_line) && (strcmp(l1->file, l2->file) == 0));
434 /*---------------------------------------------------------------------------*/
437 * Writes a statement to file.
438 * @@param fp File handle
439 * @@param n Statement
441 static void put_statement(FILE *fp, const astnode *n, location *loc)
450 static int tag = 0; /* Used to give labels unique IDs */
452 /* See if we should embed file+line information */
453 if (xasm_args.debug && !locations_are_equal(loc, &n->loc) ) {
455 if (strcmp(loc->file, n->loc.file) != 0) {
457 put_str_8(fp, n->loc.file);
459 if (loc->first_line != n->loc.first_line) {
460 line = n->loc.first_line;
461 if (line == loc->first_line + 1) {
462 put_1(fp, CMD_LINE_INC);
465 put_1(fp, CMD_LINE8);
468 else if (line < 65536) {
469 put_1(fp, CMD_LINE16);
473 put_1(fp, CMD_LINE24);
481 switch (astnode_get_type(n)) {
486 put_1(fp, CMD_LABEL);
487 /* Look it up in symbol table */
488 e = symtab_lookup(n->label);
489 /* IMPORTANT: Tag label uniquely so we can refer to it in expressions */
491 /* Write flag byte */
493 flags |= (e->flags & PUBLIC_FLAG) ? LABEL_FLAG_EXPORT : 0;
494 flags |= (e->flags & ZEROPAGE_FLAG) ? LABEL_FLAG_ZEROPAGE : 0;
495 flags |= (e->flags & ALIGN_FLAG) ? LABEL_FLAG_ALIGN : 0;
496 flags |= (e->flags & ADDR_FLAG) ? LABEL_FLAG_ADDR : 0;
498 /* If exported, write name also */
499 if (e->flags & PUBLIC_FLAG) {
500 put_str_8(fp, e->id);
502 /* if alignment, write that too */
503 if (e->flags & ALIGN_FLAG) {
506 /* if address, write that too */
507 if (e->flags & ADDR_FLAG) {
508 put_2(fp, e->address);
512 case INSTRUCTION_NODE:
513 /* Get # of bytes such a 6502 instruction occupies */
514 len = opcode_length(n->instr.opcode);
516 /* Instruction has no operand, so append it to binary buffer. */
517 buf_append(n->instr.opcode);
520 /* Instruction has an operand.
521 It may be a constant or something unresolved. */
522 expr = astnode_get_child(n, 0);
523 if (astnode_get_type(expr) == INTEGER_NODE) {
524 /* Instruction has constant operand, so append it to binary buffer. */
525 buf_append(n->instr.opcode);
527 buf_append(expr->integer);
530 buf_append(expr->integer >> 8);
534 /* Instruction has unresolved operand. */
535 /* Flush binary buffer to file */
537 /* Output 4-byte sequence: CMD_INSTR [opcode] [expr-id] */
538 put_1(fp, CMD_INSTR);
539 put_1(fp, n->instr.opcode);
540 put_2(fp, register_expression(expr));
546 /* Append the binary to the buffer */
547 buf_append_n(n->binary.data, n->binary.size);
553 /* Go through all the elements of the data array */
554 for (expr = RHS(n); expr != NULL; expr = astnode_get_next_sibling(expr) ) {
555 if (astnode_get_type(expr) == INTEGER_NODE) {
556 /* Constant, output as binary */
557 switch (type->datatype) {
559 buf_append(expr->integer);
563 /* Note: little-endian here (6502) */
564 buf_append(expr->integer);
565 buf_append(expr->integer >> 8);
569 /* Note: little-endian here (6502) */
570 buf_append(expr->integer);
571 buf_append(expr->integer >> 8);
572 buf_append(expr->integer >> 16);
573 buf_append(expr->integer >> 24);
582 /* Unresolved. Linker will handle it. */
583 /* Flush binary buffer to file */
585 /* Output 3-byte sequence: [type-cmd] [expr-id] */
586 switch (type->datatype) {
587 case BYTE_DATATYPE: put_1(fp, CMD_DB); break;
588 case WORD_DATATYPE: put_1(fp, CMD_DW); break;
589 case DWORD_DATATYPE: put_1(fp, CMD_DD); break;
594 put_2(fp, register_expression(expr));
602 assert(type->datatype == BYTE_DATATYPE);
603 /* Get expression which is the count */
606 if (astnode_get_type(expr) == INTEGER_NODE) {
607 /* Use the immediate form. */
608 /* Calculate the # of bytes. */
610 /* Select bytecode depending on whether count fits in 8 bits or not */
619 put_1(fp, CMD_DSI16);
625 /* Use the unresolved form. */
627 /* Write expression ID */
628 put_2(fp, register_expression(expr));
635 case STRUC_DECL_NODE:
636 case UNION_DECL_NODE:
638 case RECORD_DECL_NODE:
644 fprintf(stderr, "put_statement(%s): unsupported type\n", astnode_type_to_string(astnode_get_type(n)));
649 /*---------------------------------------------------------------------------*/
652 * Writes the public constants to file.
653 * @@param fp File handle
655 static void put_public_constants(FILE *fp)
657 symbol_ident_list list;
665 /* 16-bit count followed by (name, type, value) triplets */
667 symtab_list_type(CONSTANT_SYMBOL, &list);
668 /* Make one iteration to look them up and count them */
670 for (i=0; i<list.size; i++) {
671 e = symtab_lookup(list.idents[i]);
672 if (e->flags & PUBLIC_FLAG) {
679 for (i=0; i<list.size; i++) {
680 e = symtab_lookup(list.idents[i]);
681 if (e->flags & PUBLIC_FLAG) {
683 put_str_8(fp, e->id);
684 /* Get the expression which represents the value */
685 expr = (astnode *)e->def;
686 /* Write the type and value */
687 switch (astnode_get_type(expr)) {
689 v = (unsigned long)expr->integer;
691 /* Write type */ put_1(fp, INT_8);
692 /* Write value */ put_1(fp, v);
694 else if (v < 0x10000) {
695 /* Write type */ put_1(fp, INT_16);
696 /* Write value */ put_2(fp, v);
698 else if (v < 0x1000000) {
699 /* Write type */ put_1(fp, INT_24);
700 /* Write value */ put_3(fp, v);
703 /* Write type */ put_1(fp, INT_32);
704 /* Write value */ put_4(fp, v);
710 if (strlen(s) <= 0x100) {
711 /* Write type */ put_1(fp, STR_8);
712 /* Write value */ put_str_8(fp, s);
714 else if (strlen(s) <= 0x10000) {
715 /* Write type */ put_1(fp, STR_16);
716 /* Write value */ put_str_16(fp, s);
719 fprintf(stderr, "put_public_constants(): string constant too long\n");
724 fprintf(stderr, "put_public_constants(): expression isn't a constant after all\n");
729 symtab_list_finalize(&list);
733 * Writes the external symbol specifiers to file.
734 * @@param fp File handle
736 static void put_externals(FILE *fp)
738 symbol_ident_list list;
743 /* number of units explicitly imported from */
744 put_1(fp, 0x00); /* TODO */
745 /* List of unit names (TODO) */
747 /* 16-bit count followed by name list */
749 symtab_list_type(ANY_SYMBOL, &list);
750 /* One iteration to count them */
752 for (i=0; i<list.size; i++) {
753 e = symtab_lookup(list.idents[i]);
754 if (e->flags & EXTRN_FLAG) {
759 /* Another iteration to output them */
761 for (i=0; i<list.size; i++) {
763 e = symtab_lookup(list.idents[i]);
764 if (e->flags & EXTRN_FLAG) {
765 /* IMPORTANT: Set unique tag so we can refer to it in expressions */
766 /* (This probably shouldn't be done here though...???) */
768 /* Write unit (TODO) */
769 put_1(fp, 0x00); /* 0 = Any unit */
771 put_str_8(fp, list.idents[i]);
774 symtab_list_finalize(&list);
778 * Writes a segment to file.
779 * @@param fp File handle
780 * @@param root AST node which has the list of assembly statements as its children
781 * @@param targetseg Specifies the type of segment (data or code)
783 static void put_segment(FILE *fp, const astnode *root, int targetseg)
786 int seg; /* The type of segment we're in */
787 fpos_t size_pos, end_pos;
789 location loc = { -1, -1, -1, -1, "" };
791 /* Write the size of the segment (backpatched later) */
792 fgetpos(fp, &size_pos);
793 put_3(fp, 0xDECADE); /* 24-bit integer */
795 seg = 2; /* Codeseg is default */
798 /* Step through all the nodes in the list */
799 for (n = astnode_get_first_child(root); n != NULL; n = astnode_get_next_sibling(n) ) {
800 switch (astnode_get_type(n)) {
802 seg = 1; /* Now we're in a DATA segment */
806 seg = 2; /* Now we're in a CODE segment */
810 /* Only output the statement if we're in the proper segment. */
811 if (seg == targetseg) {
812 put_statement(fp, n, &loc);
821 fgetpos(fp, &end_pos); /* First save the current (end) position */
822 fsetpos(fp, &size_pos); /* Set position to where the size should be written */
823 put_3(fp, end - start); /* Size is difference between end and start offset */
824 fsetpos(fp, &end_pos); /* Restore end position */
828 * Writes a sequence of parsed assembly statements to file.
829 * @@param fp File handle
830 * @@param root AST node which has the assembly statements as its children
832 static void put_bytecodes(FILE *fp, const astnode *root)
834 /* Write data segment first */
835 put_segment(fp, root, 1);
836 /* Write code segment next */
837 put_segment(fp, root, 2);
840 /*---------------------------------------------------------------------------*/
843 * Writes an object file which captures all the information in a syntax tree.
844 * @@param root Root of the syntax tree
845 * @@param filename Name of the file to write to (object file)
847 void codegen_write(const astnode *root, const char *filename)
849 /* Attempt to open file for writing */
850 FILE *fp = fopen(filename, "wb");
852 fprintf(stderr, "codegen_write: could not open '%s' for writing\n", filename);
853 /* ### increase error count */
860 /* Write magic number */
862 /* Write version (upper nibble=major, lower nibble=minor) */
863 put_1(fp, A_VERSION);
865 /* Write exported constants. */
866 put_public_constants(fp);
868 /* Write imported symbols. */
871 /* Write bytecodes. */
872 put_bytecodes(fp, root);
874 /* Write expressions */
890 * $Id: codegen.c,v 1.8 2007/08/07 22:42:17 khansen Exp khansen $
895 type = LHS(n); /* NB! This is assumed to be BYTE_DATATYPE by now! */
902 @make sure a CMD_FILE command is output at the start of each segment
907 * $Id: codegen.c,v 1.7 2007/08/07 21:23:24 khansen Exp khansen $
920 * $Id: codegen.c,v 1.6 2007/07/22 13:33:26 khansen Exp khansen $
924 static void put_statement(FILE *fp, const astnode *n)
926 static location loc = { -1, -1, -1, -1, "" };
929 if (xasm_args.debug && !locations_are_equal(&loc, &n->loc) ) {
932 if (strcmp(loc.file, n->loc.file) != 0) {
935 if (loc.first_line != n->loc.first_line) {
938 if (line == loc.first_line + 1) {
951 put_statement(fp, n);
957 @convert tabs to whitespaces
962 * $Id: codegen.c,v 1.5 2004/12/19 19:58:37 kenth Exp $
966 static void put_bytes(FILE *f, unsigned char *bytes, int count)
969 static void put_expr_recursive(FILE *fp, astnode *expr)
972 static void put_expr(FILE *fp, astnode *expr)
975 static int locations_are_equal(location *l1, location *l2)
978 static void put_statement(FILE *fp, astnode *n)
987 static void put_segment(FILE *fp, astnode *root, int targetseg)
990 static void put_bytecodes(FILE *fp, astnode *root)
993 void codegen_write(astnode *root, char *filename)
1004 * $Id: codegen.c,v 1.4 2004/12/18 16:58:52 kenth Exp kenth $
1009 /* Write the bytes */
1010 for (i=0; i<count; i++) {
1016 if (buf_pos <= 0x100) {
1017 /* Use 8-bit form. */
1019 put_1(f, buf_pos - 1);
1020 put_bytes(f, buf, buf_pos);
1022 else if (buf_pos <= 0x10000) {
1023 /* Use 16-bit form. */
1024 put_1(f, CMD_BIN16);
1025 put_2(f, buf_pos - 1);
1026 put_bytes(f, buf, buf_pos);
1029 /* Error, buffer overflow. */
1030 fprintf(stderr, "buf_flush: buffer overflow\n");
1037 for (i=0; i<size; i++) {
1038 buf_append(data[i]);
1043 case PLUS_OPERATOR: return OP_PLUS;
1044 case MINUS_OPERATOR: return OP_MINUS;
1045 case MUL_OPERATOR: return OP_MUL;
1046 case DIV_OPERATOR: return OP_DIV;
1047 case MOD_OPERATOR: return OP_MOD;
1048 case AND_OPERATOR: return OP_AND;
1049 case OR_OPERATOR: return OP_OR;
1050 case XOR_OPERATOR: return OP_XOR;
1051 case SHL_OPERATOR: return OP_SHL;
1052 case SHR_OPERATOR: return OP_SHR;
1053 case LT_OPERATOR: return OP_LT;
1054 case GT_OPERATOR: return OP_GT;
1055 case EQ_OPERATOR: return OP_EQ;
1056 case NE_OPERATOR: return OP_NE;
1057 case LE_OPERATOR: return OP_LE;
1058 case GE_OPERATOR: return OP_GE;
1059 case NEG_OPERATOR: return OP_NEG;
1060 case NOT_OPERATOR: return OP_NOT;
1061 case LO_OPERATOR: return OP_LO;
1062 case HI_OPERATOR: return OP_HI;
1063 case UMINUS_OPERATOR: return OP_UMINUS;
1064 case BANK_OPERATOR: return OP_BANK;
1067 fprintf(stderr, "operator_to_bytecode(): bad operator\n");
1073 /* See if an equivalent expression already is registered */
1074 for (i=0; i<expr_count; i++) {
1075 if (astnode_equal(expr, expr_list[i])) {
1076 /* Return ID of equivalent expression. */
1080 /* This is a new expression, add it to end of list if possible. */
1081 if (expr_count == MAX_EXPRS) {
1082 fprintf(stderr, "register_expression(): buffer overflow\n");
1086 expr_list[expr_count++] = expr;
1087 return expr_count-1;
1094 if (expr == NULL) { return; }
1095 // printf("put_expr_recursive(%s)\n", astnode_type_to_string(expr->type) );
1096 switch (astnode_get_type(expr)) {
1098 v = (unsigned long)expr->integer;
1100 /* Write type */ put_1(fp, INT_8);
1101 /* Write value */ put_1(fp, v);
1103 else if (v < 0x10000) {
1104 /* Write type */ put_1(fp, INT_16);
1105 /* Write value */ put_2(fp, v);
1107 else if (v < 0x1000000) {
1108 /* Write type */ put_1(fp, INT_24);
1109 /* Write value */ put_3(fp, v);
1112 /* Write type */ put_1(fp, INT_32);
1113 /* Write value */ put_4(fp, v);
1119 if (strlen(s) <= 0x100) {
1120 /* Write type */ put_1(fp, STR_8);
1121 /* Write string */ put_str_8(fp, s);
1124 /* Write type */ put_1(fp, STR_16);
1125 /* Write string */ put_str_16(fp, s);
1129 case IDENTIFIER_NODE:
1131 e = symtab_lookup(expr->ident);
1133 put_1(fp, (e->flags & EXTRN_FLAG) ? EXTRN : LOCAL);
1138 case ARITHMETIC_NODE:
1139 /* The operator goes first */
1140 put_1(fp, operator_to_bytecode(expr->oper) );
1141 /* Then left-hand side */
1142 put_expr_recursive(fp, LHS(expr));
1143 /* Then right-hand side */
1144 put_expr_recursive(fp, RHS(expr));
1147 case CURRENT_PC_NODE:
1155 "put_expr_recursive(): unknown expression type (%s)\n",
1156 astnode_type_to_string(astnode_get_type(expr))
1162 put_expr_recursive(fp, expr);
1166 /* Write expression count */
1167 put_2(fp, expr_count);
1168 /* Write serialized expressions */
1169 for (i=0; i<expr_count; i++) {
1170 put_expr(fp, expr_list[i]);
1174 return ((l1->first_line == l2->first_line) && (strcmp(l1->file, l2->file) == 0));
1183 unsigned char flags;
1184 static int tag = 0; /* Used to give labels unique IDs */
1185 static location loc = { -1, -1, -1, -1, "" };
1187 /* See if we should embed file+line information */
1188 if (xasm_args.debug && !locations_are_equal(&loc, &n->loc) ) {
1190 if (strcmp(loc.file, n->loc.file) != 0) {
1191 put_1(fp, CMD_FILE);
1192 put_str_8(fp, n->loc.file);
1194 if (loc.first_line != n->loc.first_line) {
1195 line = n->loc.first_line;
1196 if (line == loc.first_line + 1) {
1197 put_1(fp, CMD_LINE_INC);
1201 put_1(fp, CMD_LINE8);
1204 else if (line < 65536) {
1205 put_1(fp, CMD_LINE16);
1209 put_1(fp, CMD_LINE24);
1217 switch (astnode_get_type(n)) {
1222 put_1(fp, CMD_LABEL);
1223 /* Look it up in symbol table */
1224 e = symtab_lookup(n->label);
1225 /* IMPORTANT: Tag label uniquely so we can refer to it in expressions */
1227 /* Write flag byte */
1229 flags |= (e->flags & PUBLIC_FLAG) ? LABEL_FLAG_EXPORT : 0;
1230 flags |= (e->flags & ZEROPAGE_FLAG) ? LABEL_FLAG_ZEROPAGE : 0;
1231 flags |= (e->flags & ALIGN_FLAG) ? LABEL_FLAG_ALIGN : 0;
1232 flags |= (e->flags & ADDR_FLAG) ? LABEL_FLAG_ADDR : 0;
1234 /* If exported, write name also */
1235 if (e->flags & PUBLIC_FLAG) {
1236 put_str_8(fp, e->id);
1238 /* if alignment, write that too */
1239 if (e->flags & ALIGN_FLAG) {
1240 put_1(fp, e->align);
1242 /* if address, write that too */
1243 if (e->flags & ADDR_FLAG) {
1244 put_2(fp, e->address);
1248 case INSTRUCTION_NODE:
1249 /* Get # of bytes such a 6502 instruction occupies */
1250 len = opcode_length(n->instr.opcode);
1252 /* Instruction has no operand, so append it to binary buffer. */
1253 buf_append(n->instr.opcode);
1256 /* Instruction has an operand.
1257 It may be a constant or something unresolved. */
1258 expr = astnode_get_child(n, 0);
1259 if (astnode_get_type(expr) == INTEGER_NODE) {
1260 /* Instruction has constant operand, so append it to binary buffer. */
1261 buf_append(n->instr.opcode);
1263 buf_append(expr->integer);
1266 buf_append(expr->integer >> 8);
1270 /* Instruction has unresolved operand. */
1271 /* Flush binary buffer to file */
1273 /* Output 4-byte sequence: CMD_INSTR [opcode] [expr-id] */
1274 put_1(fp, CMD_INSTR);
1275 put_1(fp, n->instr.opcode);
1276 put_2(fp, register_expression(expr));
1282 /* Append the binary to the buffer */
1283 buf_append_n(n->binary.data, n->binary.size);
1289 /* Go through all the elements of the data array */
1290 for (expr = RHS(n); expr != NULL; expr = astnode_get_next_sibling(expr) ) {
1291 if (astnode_get_type(expr) == INTEGER_NODE) {
1292 /* Constant, output as binary */
1293 switch (type->datatype) {
1295 buf_append(expr->integer);
1299 /* Note: little-endian here (6502) */
1300 buf_append(expr->integer);
1301 buf_append(expr->integer >> 8);
1304 case DWORD_DATATYPE:
1305 /* Note: little-endian here (6502) */
1306 buf_append(expr->integer);
1307 buf_append(expr->integer >> 8);
1308 buf_append(expr->integer >> 16);
1309 buf_append(expr->integer >> 24);
1318 /* Unresolved. Linker will handle it. */
1319 /* Flush binary buffer to file */
1321 /* Output 3-byte sequence: [type-cmd] [expr-id] */
1322 switch (type->datatype) {
1323 case BYTE_DATATYPE: put_1(fp, CMD_DB); break;
1324 case WORD_DATATYPE: put_1(fp, CMD_DW); break;
1325 case DWORD_DATATYPE: put_1(fp, CMD_DD); break;
1330 put_2(fp, register_expression(expr));
1337 type = LHS(n); /* NB! This is assumed to be BYTE_DATATYPE by now! */
1338 /* Get expression which is the count */
1341 if (astnode_get_type(expr) == INTEGER_NODE) {
1342 /* Use the immediate form. */
1343 /* Calculate the # of bytes. */
1344 len = expr->integer;
1345 /* Select bytecode depending on whether count fits in 8 bits or not */
1348 put_1(fp, CMD_DSI8);
1354 put_1(fp, CMD_DSI16);
1360 /* Use the unresolved form. */
1362 /* Write expression ID */
1363 put_2(fp, register_expression(expr));
1375 fprintf(stderr, "put_statement(%s): unsupported type\n", astnode_type_to_string(astnode_get_type(n)));
1381 symbol_ident_list list;
1389 /* 16-bit count followed by (name, type, value) triplets */
1391 symtab_list_type(CONSTANT_SYMBOL, &list);
1392 /* Make one iteration to look them up and count them */
1394 for (i=0; i<list.size; i++) {
1395 e = symtab_lookup(list.idents[i]);
1396 if (e->flags & PUBLIC_FLAG) {
1402 /* Write triplets */
1403 for (i=0; i<list.size; i++) {
1404 e = symtab_lookup(list.idents[i]);
1405 if (e->flags & PUBLIC_FLAG) {
1406 /* Write the name */
1407 put_str_8(fp, e->id);
1408 /* Get the expression which represents the value */
1409 expr = (astnode *)e->def;
1410 /* Write the type and value */
1411 switch (astnode_get_type(expr)) {
1413 v = (unsigned long)expr->integer;
1415 /* Write type */ put_1(fp, INT_8);
1416 /* Write value */ put_1(fp, v);
1418 else if (v < 0x10000) {
1419 /* Write type */ put_1(fp, INT_16);
1420 /* Write value */ put_2(fp, v);
1422 else if (v < 0x1000000) {
1423 /* Write type */ put_1(fp, INT_24);
1424 /* Write value */ put_3(fp, v);
1427 /* Write type */ put_1(fp, INT_32);
1428 /* Write value */ put_4(fp, v);
1434 if (strlen(s) <= 0x100) {
1435 /* Write type */ put_1(fp, STR_8);
1436 /* Write value */ put_str_8(fp, s);
1438 else if (strlen(s) <= 0x10000) {
1439 /* Write type */ put_1(fp, STR_16);
1440 /* Write value */ put_str_16(fp, s);
1443 fprintf(stderr, "put_public_constants(): string constant too long\n");
1448 fprintf(stderr, "put_public_constants(): expression isn't a constant after all\n");
1453 symtab_list_finalize(&list);
1456 symbol_ident_list list;
1461 /* number of units explicitly imported from */
1462 put_1(fp, 0x00); /* TODO */
1463 /* List of unit names (TODO) */
1465 /* 16-bit count followed by name list */
1467 symtab_list_type(ANY_SYMBOL, &list);
1468 /* One iteration to count them */
1470 for (i=0; i<list.size; i++) {
1471 e = symtab_lookup(list.idents[i]);
1472 if (e->flags & EXTRN_FLAG) {
1477 /* Another iteration to output them */
1479 for (i=0; i<list.size; i++) {
1481 e = symtab_lookup(list.idents[i]);
1482 if (e->flags & EXTRN_FLAG) {
1483 /* IMPORTANT: Set unique tag so we can refer to it in expressions */
1484 /* (This probably shouldn't be done here though...???) */
1486 /* Write unit (TODO) */
1487 put_1(fp, 0x00); /* 0 = Any unit */
1489 put_str_8(fp, list.idents[i]);
1492 symtab_list_finalize(&list);
1496 int seg; /* The type of segment we're in */
1497 fpos_t size_pos, end_pos;
1500 /* Write the size of the segment (backpatched later) */
1501 fgetpos(fp, &size_pos);
1502 put_3(fp, 0xDECADE); /* 24-bit integer */
1504 seg = 2; /* Codeseg is default */
1507 /* Step through all the nodes in the list */
1508 for (n = astnode_get_first_child(root); n != NULL; n = astnode_get_next_sibling(n) ) {
1509 switch (astnode_get_type(n)) {
1511 seg = 1; /* Now we're in a DATA segment */
1515 seg = 2; /* Now we're in a CODE segment */
1519 /* Only output the statement if we're in the proper segment. */
1520 if (seg == targetseg) {
1521 put_statement(fp, n);
1529 /* Backpatch size */
1530 fgetpos(fp, &end_pos); /* First save the current (end) position */
1531 fsetpos(fp, &size_pos); /* Set position to where the size should be written */
1532 put_3(fp, end - start); /* Size is difference between end and start offset */
1533 fsetpos(fp, &end_pos); /* Restore end position */
1536 /* Write data segment first */
1537 put_segment(fp, root, 1);
1538 /* Write code segment next */
1539 put_segment(fp, root, 2);
1542 /* Attempt to open file for writing */
1543 FILE *fp = fopen(filename, "wb");
1545 fprintf(stderr, "codegen_write: could not open '%s' for writing\n", filename);
1552 /* Write magic number */
1554 /* Write version (upper nibble=major, lower nibble=minor) */
1555 put_1(fp, A_VERSION);
1557 /* Write exported constants. */
1558 put_public_constants(fp);
1560 /* Write imported symbols. */
1564 /* Write bytecodes. */
1565 put_bytecodes(fp, root);
1568 /* Write expressions */
1569 put_expressions(fp);
1572 /* Close the file */
1579 @outputs file and line info if --debug
1580 CMD_DSW, CMD_DSD gone
1585 * $Id: codegen.c,v 1.3 2004/12/14 01:49:14 kenth Exp kenth $
1590 /* Write export flag byte */
1591 put_1(fp, (e->flags & PUBLIC_FLAG) ? 1 : 0);
1603 * $Id: codegen.c,v 1.2 2004/12/06 04:52:36 kenth Exp kenth $
1608 static location loc = { -1, -1, -1, -1, NULL };
1611 // if (!locations_are_equal(&loc, &n->loc)) {
1612 // TODO: output file/line info
1618 switch (type->datatype) {
1619 case BYTE_DATATYPE: len = len*1; break;
1620 case WORD_DATATYPE: len = len*2; break;
1621 case DWORD_DATATYPE: len = len*4; break;
1628 switch (type->datatype) {
1629 case BYTE_DATATYPE: put_1(fp, CMD_DSB); break;
1630 case WORD_DATATYPE: put_1(fp, CMD_DSW); break;
1631 case DWORD_DATATYPE: put_1(fp, CMD_DSD); break;
1638 /* Write length */ put_1(fp, strlen(s) - 1);
1641 /* Write type */ put_1(fp, STR_16);
1642 /* Write length */ put_2(fp, strlen(s) - 1);
1656 * $Id: codegen.c,v 1.1 2004/06/30 07:55:38 kenth Exp kenth $
1679 static char buf[0x10000];
1682 #define buf_append(b) { buf[buf_pos++] = b; }
1683 static void buf_append_n(unsigned char *data, int size)
1686 for (i=0; i<size; i++) {
1687 buf_append(data[i]);
1693 fprintf(stderr, "operator_to_bytecode: bad operator\n");
1698 fprintf(stderr, "register_expression: buffer overflow\n");
1700 #define LHS(e) astnode_get_child(e, 0)
1701 #define RHS(e) astnode_get_child(e, 1)
1706 put_1(fp, (e->type == EXTERNAL_SYMBOL) ? EXTRN : LOCAL);
1709 fprintf(stderr, "put_expr_recursive: unknown expression type\n");
1714 for (expr = astnode_get_first_child(n); expr != NULL; expr = astnode_get_next_sibling(expr) ) {
1717 switch (n->datatype) {
1726 switch (n->datatype) {
1731 expr = astnode_get_child(n, 0);
1734 switch (n->datatype) {
1738 switch (n->datatype) {
1744 fprintf(stderr, "put_public_constants: expression isn't a constant after all\n");
1750 symtab_list_type(EXTERNAL_SYMBOL, &list);
1751 put_2(fp, list.size);
1754 /* IMPORTANT: Set unique tag so we can refer to it in expressions */
1755 /* (This probably shouldn't be done here though...) */
1757 /* Write unit (TODO) */
1758 put_1(fp, 0x00); /* 0 = Any unit */
1760 put_str_8(fp, list.idents[i]);
1763 seg = 0; /* Invalid */