/*********************************************************************** * * avra - Assembler for the Atmel AVR microcontroller series * * Copyright (C) 1998-2004 Jon Anders Haugum, Tobias Weber * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * * * Authors of avra can be reached at: * email: jonah@omegav.ntnu.no, tobiw@suprafluid.com * www: http://sourceforge.net/projects/avra */ #include #include #include #include #include "misc.h" #include "args.h" #include "avra.h" #include "device.h" #define debug 0 const char *title = "AVRA: advanced AVR macro assembler Version %i.%i.%i Build %i (%s)\n" "Copyright (C) 1998-2004 Jon Anders Haugum, Tobias Weber\n" "\n" " AVRA is an open source assembler for Atmel AVR microcontroller family\n" " It can be used as a replacement of 'AVRASM32.EXE' the original assembler\n" " shipped with AVR Studio. We do not guarantee full compatibility for avra.\n" "\n" " AVRA comes with NO WARRANTY, to the extent permitted by law.\n" " You may redistribute copies of avra under the terms\n" " of the GNU General Public License.\n" " For more information about these matters, see the files named COPYING.\n" "\n"; const char *usage = "usage: AVRA [-f][O|M|I|G] output file type\n" " [-o ] output file name\n" " [-l ] generate list file\n" " [-m ] generate map file\n" "[--define [=]] [--includedir ] [--listmac]\n" " [--max_errors ] [--devices] [--version]\n" " [-h] [--help] general help\n" " " " \n" "\n" " --listfile -l : Create list file\n" " --mapfile -m : Create map file\n" " --define -D : Define symbol.\n" " --includedir -I : Additional include dirs.\n" " --listmac : List macro expansion in listfile.\n" " --max_errors : Maximum number of errors before exit\n" " (default: 10)\n" " --devices : List out supported devices.\n" " --version : Version information.\n" " --help, -h : This help text.\n" "\n" "Just replace the AVRASM32.EXE with AVRA.EXE in your\n" "AVRStudio directories to avra's binary.\n" "\n" "Report bugs to tobiw@suprafluid.com\n" " or jonah@omegav.ntnu.no\n"; int main(int argc, char *argv[]) { int show_usage = False; struct prog_info *pi; struct args *args; unsigned char c; #if debug == 1 for(i = 0; i < argc; i++) { printf(argv[i]); printf("\n"); } #endif printf(title, VER_MAJOR, VER_MINOR, VER_RELEASE, VER_BUILD, VER_DATE); args = alloc_args(ARG_COUNT); if(args) { define_arg(args, ARG_DEFINE, ARGTYPE_STRING_MULTISINGLE, 'D', "define", NULL); define_arg(args, ARG_INCLUDEDIR, ARGTYPE_STRING_MULTISINGLE, 'I', "includedir", NULL); define_arg(args, ARG_LISTMAC, ARGTYPE_BOOLEAN, 0, "listmac", "1"); define_arg(args, ARG_MAX_ERRORS, ARGTYPE_STRING, 0, "max_errors", "10"); define_arg(args, ARG_DEVICES, ARGTYPE_BOOLEAN, 0, "devices", NULL); define_arg(args, ARG_VER, ARGTYPE_BOOLEAN, 0, "version", NULL); define_arg(args, ARG_HELP, ARGTYPE_BOOLEAN, 'h', "help", NULL); define_arg(args, ARG_WRAP, ARGTYPE_BOOLEAN, 'w', "wrap", NULL); define_arg(args, ARG_FILEFORMAT, ARGTYPE_CHAR_ATTACHED, 'f', "filetype", "0"); define_arg(args, ARG_LISTFILE, ARGTYPE_STRING, 'l', "listfile", NULL); define_arg(args, ARG_OUTFILE, ARGTYPE_STRING, 'o', "outfile", NULL); define_arg(args, ARG_MAPFILE, ARGTYPE_STRING, 'm', "mapfile", NULL); define_arg(args, ARG_DEBUGFILE, ARGTYPE_STRING, 'd', "debugfile", NULL); define_arg(args, ARG_EEPFILE, ARGTYPE_STRING, 'e', "eepfile", NULL); c = read_args(args, argc, argv); if(c != 0) { if(!GET_ARG(args, ARG_HELP) && (argc != 1)) { if(!GET_ARG(args, ARG_VER)) { if(!GET_ARG(args, ARG_DEVICES)) { pi = get_pi(args); if(pi) { get_rootpath(pi, args); /* get assembly root path */ assemble(pi); /* the main assembly routine */ free_pi(pi); /* free all allocated memory */ } } else { list_devices(); /* list all supported devices */ } } } else show_usage = True; } free_args(args); } else { show_usage = True; printf("\n"); } if(show_usage) { printf("%s", usage); } exit(EXIT_SUCCESS); return (0); /* compiler warning, JEG 4-23-03 */ } void get_rootpath(struct prog_info *pi, struct args *args) { int i; int j; char c; struct data_list *data; data = args->first_data; while(data->next) data = ((data)->next); if (data != NULL) { i = strlen((char *)data->data); if (i > 0) { pi->root_path = malloc(i + 1); strcpy(pi->root_path,(char *)data->data); j = 0; do { c = pi->root_path[i]; if(c == '\\' || c == '/') { j = i + 1; break; } } while(i-- > 0); pi->root_path[j] = '\0'; return; } } pi->root_path = ""; } void assemble(struct prog_info *pi) { unsigned char c; if(pi->args->first_data) { printf("Pass 1...\n"); c = load_arg_defines(pi); if(c == 0) return; predef_dev(pi); c = parse_file(pi, (char *)pi->args->first_data->data, PASS_1); if(c != 0) { if(pi->error_count == 0) { prepare_second_pass(pi); c = load_arg_defines(pi); if(c == 0) return; predef_dev(pi); c = open_out_files(pi, pi->args->first_data->data); if(c != 0) { printf("Pass 2...\n"); parse_file(pi, (char *)pi->args->first_data->data, PASS_2); printf("done\n\n"); if(GET_ARG(pi->args, ARG_COFF) && (pi->error_count == 0)) { write_coff_file(pi); } write_map_file(pi); close_out_files(pi); if(pi->error_count) printf("\nAssembly aborted with %d errors and %d warnings.\n", pi->error_count, pi->warning_count); else if(pi->warning_count) printf("\nAssembly complete with no errors (%d warnings).\n", pi->warning_count); else printf("\nAssembly complete with no errors.\n"); } } } } else { printf("Error: You need to specify a file to assemble\n"); } } int load_arg_defines(struct prog_info *pi) { int i; char *expr; char buff[256]; struct data_list *define; struct label *label; for(define = GET_ARG(pi->args, ARG_DEFINE); define; define = define->next) { strcpy(buff, define->data); expr = get_next_token(buff, TERM_EQUAL); if(expr) { if(!get_expr(pi, expr, &i)) { return(False); } else i = 1; for(label = pi->first_constant; label; label = label->next) if(!nocase_strcmp(label->name, buff)) { printf("Error: Can't define symbol %s twice\n", buff); return(False); } label = malloc(sizeof(struct label)); if(!label) { print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); return(False); } label->next = NULL; if(pi->last_constant) pi->last_constant->next = label; else pi->first_constant = label; pi->last_constant = label; label->name = malloc(strlen(buff) + 1); if(!label->name) { print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); return(False); } strcpy(label->name, buff); label->value = i; } } return(True); } struct prog_info *get_pi(struct args *args) { struct prog_info *pi; pi = (struct prog_info *)calloc(1, sizeof(struct prog_info)); if(pi) { pi->args = args; pi->device = get_device(pi,NULL); if (GET_ARG(args, ARG_LISTFILE) == NULL) { pi->list_on = False; } else { pi->list_on = True; } if (GET_ARG(args, ARG_MAPFILE) == NULL) { pi->map_on = False; } else { pi->map_on = True; } pi->segment = SEGMENT_CODE; pi->dseg_addr = DSEG_START; pi->max_errors = atoi(GET_ARG(args, ARG_MAX_ERRORS)); return(pi); } else return(NULL); } void free_pi(struct prog_info *pi) { free(pi); } void prepare_second_pass(struct prog_info *pi) { struct def *def, *temp_def; struct label *label, *temp_label; pi->segment = SEGMENT_CODE; pi->cseg_addr = 0; pi->dseg_addr = DSEG_START; pi->eseg_addr = 0; //pi->macro_nstlblnr = 0; for(def = pi->first_def; def;) { temp_def = def; def = def->next; free(temp_def->name); free(temp_def); } pi->first_def = NULL; pi->last_def = NULL; for(label = pi->first_constant; label;) { temp_label = label; label = label->next; free(temp_label->name); free(temp_label); } pi->first_constant = NULL; pi->last_constant = NULL; for(label = pi->first_variable; label;) { temp_label = label; label = label->next; free(temp_label->name); free(temp_label); } pi->first_variable = NULL; pi->last_variable = NULL; } void print_msg(struct prog_info *pi, int type, char *fmt, ... ) { va_list args; char *pc; if(type == MSGTYPE_OUT_OF_MEM) { fprintf(stderr, "Error: Unable to allocate memory!\n"); } else { va_start(args, fmt); /* check if adding path name is needed*/ pc = strstr(pi->fi->include_file->name, pi->root_path); if(pc == NULL) { fprintf(stderr, "%s%s(%d) : ", pi->root_path ,pi->fi->include_file->name, pi->fi->line_number); } else { fprintf(stderr, "%s(%d) : ", pi->fi->include_file->name, pi->fi->line_number); } switch(type) { case MSGTYPE_ERROR: pi->error_count++; fprintf(stderr, "error : "); break; case MSGTYPE_WARNING: pi->warning_count++; fprintf(stderr, "warning : "); break; case MSGTYPE_MESSAGE: break; } if(pi->macro_call) { fprintf(stderr, "[Macro: %s: %d:] ", pi->macro_call->macro->include_file->name, pi->macro_call->line_index + pi->macro_call->macro->first_line_number); } vfprintf(stderr, fmt, args); fprintf(stderr, "\n"); va_end(args); } } /* avra.c */