Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
6400 | punk_joker | 1 | /*********************************************************************** |
2 | * |
||
3 | * avra - Assembler for the Atmel AVR microcontroller series |
||
4 | * |
||
5 | * Copyright (C) 1998-2004 Jon Anders Haugum, TObias Weber |
||
6 | * |
||
7 | * This program is free software; you can redistribute it and/or modify |
||
8 | * it under the terms of the GNU General Public License as published by |
||
9 | * the Free Software Foundation; either version 2 of the License, or |
||
10 | * (at your option) any later version. |
||
11 | * |
||
12 | * This program is distributed in the hope that it will be useful, |
||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
15 | * GNU General Public License for more details. |
||
16 | * |
||
17 | * You should have received a copy of the GNU General Public License |
||
18 | * along with this program; see the file COPYING. If not, write to |
||
19 | * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
||
20 | * Boston, MA 02111-1307, USA. |
||
21 | * |
||
22 | * |
||
23 | * Authors of avra can be reached at: |
||
24 | * email: jonah@omegav.ntnu.no, tobiw@suprafluid.com |
||
25 | * www: http://sourceforge.net/projects/avra |
||
26 | */ |
||
27 | |||
28 | /* |
||
29 | * In append_type: added generic register names support |
||
30 | * Alexey Pavluchenko, 16.Nov.2005 |
||
31 | */ |
||
32 | |||
33 | #include |
||
34 | #include |
||
35 | #include |
||
36 | #include |
||
37 | |||
38 | #include "misc.h" |
||
39 | #include "args.h" |
||
40 | #include "avra.h" |
||
41 | #include "device.h" |
||
42 | |||
43 | /* Only Windows LIBC does support itoa, so we add this |
||
44 | function for other systems here manually. Thank you |
||
45 | Peter Hettkamp for your work. */ |
||
46 | |||
47 | #ifndef WIN32 |
||
48 | char * itoa(int num, char *str, const int number_format) |
||
49 | { |
||
50 | int num1 = num; |
||
51 | int num_chars = 0; |
||
52 | int pos; |
||
53 | |||
54 | while (num1>0) |
||
55 | { |
||
56 | num_chars++; |
||
57 | num1 /= number_format; |
||
58 | } |
||
59 | |||
60 | if (num_chars == 0) num_chars = 1; |
||
61 | |||
62 | str[num_chars] = 0; |
||
63 | |||
64 | for (pos = num_chars-1; pos>=0; pos--) |
||
65 | { |
||
66 | int cur_char = num % number_format; |
||
67 | |||
68 | if (cur_char < 10) /* Insert number */ |
||
69 | { |
||
70 | str[pos] = cur_char + '0'; |
||
71 | } |
||
72 | else |
||
73 | { |
||
74 | str[pos] = cur_char-10 + 'A'; |
||
75 | } |
||
76 | |||
77 | num /= number_format; |
||
78 | } |
||
79 | return(str); |
||
80 | } |
||
81 | #endif |
||
82 | |||
83 | |||
84 | int read_macro(struct prog_info *pi, char *name) |
||
85 | { |
||
86 | int loopok; |
||
87 | int i; |
||
88 | int start; |
||
89 | struct macro *macro; |
||
90 | struct macro_line *macro_line; |
||
91 | struct macro_line **last_macro_line = NULL; |
||
92 | struct macro_label *macro_label; |
||
93 | |||
94 | if(pi->pass == PASS_1) { |
||
95 | if(!name) { |
||
96 | print_msg(pi, MSGTYPE_ERROR, "missing macro name"); |
||
97 | return(True); |
||
98 | } |
||
99 | get_next_token(name, TERM_END); |
||
100 | |||
101 | for(i = 0; !IS_END_OR_COMMENT(name[i]); i++) { |
||
102 | if(!IS_LABEL(name[i])) { |
||
103 | print_msg(pi, MSGTYPE_ERROR, "illegal characters used in macro name '%s'",name); |
||
104 | return(False); |
||
105 | } |
||
106 | } |
||
107 | |||
108 | macro = calloc(1, sizeof(struct macro)); |
||
109 | if(!macro) { |
||
110 | print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); |
||
111 | return(False); |
||
112 | } |
||
113 | |||
114 | if(pi->last_macro) |
||
115 | pi->last_macro->next = macro; |
||
116 | else |
||
117 | pi->first_macro = macro; |
||
118 | pi->last_macro = macro; |
||
119 | macro->name = malloc(strlen(name) + 1); |
||
120 | if(!macro->name) { |
||
121 | print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); |
||
122 | return(False); |
||
123 | } |
||
124 | strcpy(macro->name, name); |
||
125 | macro->include_file = pi->fi->include_file; |
||
126 | macro->first_line_number = pi->fi->line_number; |
||
127 | last_macro_line = ¯o->first_macro_line; |
||
128 | } |
||
129 | else { /* pi->pass == PASS_2 */ |
||
130 | if(pi->list_line && pi->list_on) { |
||
131 | fprintf(pi->list_file, " %s\n", pi->list_line); |
||
132 | pi->list_line = NULL; |
||
133 | } |
||
134 | // reset macro label running numbers |
||
135 | get_next_token(name, TERM_END); |
||
136 | macro = get_macro(pi, name); |
||
137 | if (!macro) { |
||
138 | print_msg(pi, MSGTYPE_ERROR, "macro inconsistency in '%s'", name); |
||
139 | return(True); |
||
140 | } |
||
141 | for(macro_label = macro->first_label; macro_label; macro_label = macro_label->next) { |
||
142 | macro_label->running_number = 0; |
||
143 | } |
||
144 | } |
||
145 | |||
146 | loopok = True; |
||
147 | while(loopok) { |
||
148 | if(fgets_new(pi,pi->fi->buff, LINEBUFFER_LENGTH, pi->fi->fp)) { |
||
149 | pi->fi->line_number++; |
||
150 | i = 0; |
||
151 | while(IS_HOR_SPACE(pi->fi->buff[i]) && !IS_END_OR_COMMENT(pi->fi->buff[i])) i++; |
||
152 | if(pi->fi->buff[i] == '.') { |
||
153 | i++; |
||
154 | if(!nocase_strncmp(&pi->fi->buff[i], "endm", 4)) |
||
155 | loopok = False; |
||
156 | if(!nocase_strncmp(&pi->fi->buff[i], "endmacro", 8)) |
||
157 | loopok = False; |
||
158 | } |
||
159 | if(pi->pass == PASS_1) { |
||
160 | if(loopok) { |
||
161 | i = 0; /* find start of line */ |
||
162 | while(IS_HOR_SPACE(pi->fi->buff[i]) && !IS_END_OR_COMMENT(pi->fi->buff[i])) { |
||
163 | i++; |
||
164 | } |
||
165 | start = i; |
||
166 | /* find end of line */ |
||
167 | while(!IS_END_OR_COMMENT(pi->fi->buff[i]) && (IS_LABEL(pi->fi->buff[i]) || pi->fi->buff[i] == ':')) { |
||
168 | i++; |
||
169 | } |
||
170 | if(pi->fi->buff[i-1] == ':' && (pi->fi->buff[i-2] == '%' |
||
171 | && (IS_HOR_SPACE(pi->fi->buff[i]) || IS_END_OR_COMMENT(pi->fi->buff[i])))) { |
||
172 | if(macro->first_label) { |
||
173 | for(macro_label = macro->first_label; macro_label->next; macro_label=macro_label->next){} |
||
174 | macro_label->next = calloc(1,sizeof(struct macro_label)); |
||
175 | macro_label = macro_label->next; |
||
176 | } |
||
177 | else { |
||
178 | macro_label = calloc(1,sizeof(struct macro_label)); |
||
179 | macro->first_label = macro_label; |
||
180 | } |
||
181 | macro_label->label = malloc(strlen(&pi->fi->buff[start])+1); |
||
182 | pi->fi->buff[i-1] = '\0'; |
||
183 | strcpy(macro_label->label, &pi->fi->buff[start]); |
||
184 | pi->fi->buff[i-1] = ':'; |
||
185 | macro_label->running_number = 0; |
||
186 | } |
||
187 | |||
188 | macro_line = calloc(1, sizeof(struct macro_line)); |
||
189 | if(!macro_line) { |
||
190 | print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); |
||
191 | return(False); |
||
192 | } |
||
193 | *last_macro_line = macro_line; |
||
194 | last_macro_line = ¯o_line->next; |
||
195 | macro_line->line = malloc(strlen(pi->fi->buff) + 1); |
||
196 | if(!macro_line->line) { |
||
197 | print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); |
||
198 | return(False); |
||
199 | } |
||
200 | strcpy(macro_line->line, &pi->fi->buff[start]); |
||
201 | } |
||
202 | } |
||
203 | else if(pi->fi->buff && pi->list_file && pi->list_on) { |
||
204 | if(pi->fi->buff[i] == ';') |
||
205 | fprintf(pi->list_file, " %s\n", pi->fi->buff); |
||
206 | else |
||
207 | fprintf(pi->list_file, " %s\n", pi->fi->buff); |
||
208 | } |
||
209 | } |
||
210 | else { |
||
211 | if(feof(pi->fi->fp)) { |
||
212 | print_msg(pi, MSGTYPE_ERROR, "Found no closing .ENDMACRO"); |
||
213 | return(True); |
||
214 | } |
||
215 | else { |
||
216 | perror(pi->fi->include_file->name); |
||
217 | return(False); |
||
218 | } |
||
219 | } |
||
220 | } |
||
221 | return(True); |
||
222 | } |
||
223 | |||
224 | |||
225 | struct macro *get_macro(struct prog_info *pi, char *name) |
||
226 | { |
||
227 | struct macro *macro; |
||
228 | |||
229 | for(macro = pi->first_macro; macro; macro = macro->next) |
||
230 | if(!nocase_strcmp(macro->name, name)) |
||
231 | return(macro); |
||
232 | return(NULL); |
||
233 | } |
||
234 | |||
235 | void append_type(struct prog_info *pi, char *name, int c, char *value) |
||
236 | { |
||
237 | int p, l; |
||
238 | struct def *def; |
||
239 | |||
240 | p = strlen(name); |
||
241 | name[p++] = '_'; |
||
242 | |||
243 | if(c == 0) |
||
244 | { |
||
245 | name[p++] = 'v'; |
||
246 | name[p] = '\0'; |
||
247 | return; |
||
248 | } |
||
249 | |||
250 | l = strlen(value); |
||
251 | if ((l==2 || l==3) && (tolower(value[0])=='r') && isdigit(value[1]) && (l==3?isdigit(value[2]):1) && (atoi(&value[1])<32)) |
||
252 | { |
||
253 | itoa((c*8),&name[p],10); |
||
254 | return; |
||
255 | } |
||
256 | |||
257 | |||
258 | for(def = pi->first_def; def; def = def->next) |
||
259 | if(!nocase_strcmp(def->name, value)) |
||
260 | { |
||
261 | itoa((c*8),&name[p],10); |
||
262 | return; |
||
263 | } |
||
264 | |||
265 | name[p++] = 'i'; |
||
266 | name[p] = '\0'; |
||
267 | } |
||
268 | |||
269 | |||
270 | /********************************************************* |
||
271 | * This routine replaces the macro call with mnemonics. * |
||
272 | *********************************************************/ |
||
273 | |||
274 | int expand_macro(struct prog_info *pi, struct macro *macro, char *rest_line) |
||
275 | { |
||
276 | int ok = True, macro_arg_count = 0, off, a, b = 0, c, i = 0, j = 0; |
||
277 | char *line = NULL; |
||
278 | char *temp; |
||
279 | char *macro_args[MAX_MACRO_ARGS]; |
||
280 | char tmp[7]; |
||
281 | char buff[LINEBUFFER_LENGTH]; |
||
282 | char arg = False; |
||
283 | char *nmn; //string buffer for 'n'ew 'm'acro 'n'ame |
||
284 | struct macro_line *old_macro_line; |
||
285 | struct macro_call *macro_call; |
||
286 | struct macro_label *macro_label; |
||
287 | |||
288 | if(rest_line) { |
||
289 | //we reserve some extra space for extended macro parameters |
||
290 | line = malloc(strlen(rest_line) + 20); |
||
291 | if(!line) { |
||
292 | print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); |
||
293 | return(False); |
||
294 | } |
||
295 | |||
296 | /* exchange amca word 'src' with YH:YL and 'dst' with ZH:ZL */ |
||
297 | for(c = 0, a = strlen(rest_line); c < a; c++) { |
||
298 | switch (tolower(rest_line[c])) { |
||
299 | case 's': |
||
300 | if(IS_SEPARATOR(rest_line[c-1]) && (rest_line[c+1] == 'r') && (rest_line[c+2] == 'c') && IS_SEPARATOR(rest_line[c+3])) { |
||
301 | strcpy(&line[b],"YH:YL"); |
||
302 | b += 5; |
||
303 | c += 2; |
||
304 | } |
||
305 | else { |
||
306 | line[b++] = rest_line[c]; |
||
307 | } |
||
308 | break; |
||
309 | case 'd': |
||
310 | if(IS_SEPARATOR(rest_line[c-1]) && (rest_line[c+1] == 's') && (rest_line[c+2] == 't') && IS_SEPARATOR(rest_line[c+3])) { |
||
311 | strcpy(&line[b],"ZH:ZL"); |
||
312 | b += 5; |
||
313 | c += 2; |
||
314 | } |
||
315 | else { |
||
316 | line[b++] = rest_line[c]; |
||
317 | } |
||
318 | break; |
||
319 | // case ';': |
||
320 | // break; |
||
321 | default: |
||
322 | line[b++] = rest_line[c]; |
||
323 | } |
||
324 | } |
||
325 | strcpy(&line[b],"\n"); /* set CR/LF at the end of the line */ |
||
326 | |||
327 | |||
328 | /* here we split up the macro arguments into "macro_args" |
||
329 | * Extended macro code interpreter added by TW 2002 |
||
330 | */ |
||
331 | |||
332 | temp = line; |
||
333 | /* test for advanced parameters */ |
||
334 | if( temp[0] == '[' ) { // there must be "[" " then "]", else it is garbage |
||
335 | if(!strchr(temp, ']')) { |
||
336 | print_msg(pi, MSGTYPE_ERROR, "found no closing ']'"); |
||
337 | return(False); |
||
338 | } |
||
339 | |||
340 | // Okay now we are within the advanced code interpreter |
||
341 | |||
342 | temp++; // = &temp[1]; // skip the first bracket |
||
343 | nmn = malloc(LINEBUFFER_LENGTH); |
||
344 | if(!nmn) { |
||
345 | print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); |
||
346 | return(False); |
||
347 | } |
||
348 | strcpy(nmn,macro->name); // create a new macro name buffer |
||
349 | c = 1; // byte counter |
||
350 | arg = True; // loop flag |
||
351 | |||
352 | while(arg) { |
||
353 | while(IS_HOR_SPACE(temp[0])) { //skip leading spaces |
||
354 | temp++; // = &temp[1]; |
||
355 | } |
||
356 | off = 0; // pointer offset |
||
357 | do { |
||
358 | switch(temp[off]) { //test current character code |
||
359 | case ':': |
||
360 | temp[off] = '\0'; |
||
361 | if(off > 0) { |
||
362 | c++; |
||
363 | macro_args[macro_arg_count++] = temp; |
||
364 | } |
||
365 | else { |
||
366 | print_msg(pi, MSGTYPE_ERROR, "missing register before ':'",nmn); |
||
367 | return(False); |
||
368 | } |
||
369 | break; |
||
370 | case ']': |
||
371 | arg = False; |
||
372 | case ',': |
||
373 | a = off; |
||
374 | do temp[a--] = '\0'; while( IS_HOR_SPACE(temp[a]) ); |
||
375 | if(off > 0) { |
||
376 | macro_args[macro_arg_count++] = temp; |
||
377 | append_type(pi, nmn, c, temp); |
||
378 | c = 1; |
||
379 | } |
||
380 | else { |
||
381 | append_type(pi, nmn, 0, temp); |
||
382 | c = 1; |
||
383 | } |
||
384 | break; |
||
385 | |||
386 | default: |
||
387 | off++; |
||
388 | } |
||
389 | } |
||
390 | while(temp[off] != '\0'); |
||
391 | |||
392 | if(arg) temp = &temp[off+1]; |
||
393 | else break; |
||
394 | } |
||
395 | |||
396 | macro = get_macro(pi,nmn); |
||
397 | if(macro == NULL) { |
||
398 | print_msg(pi, MSGTYPE_ERROR, "Macro %s is not defined !",nmn); |
||
399 | return(False); |
||
400 | } |
||
401 | free(nmn); |
||
402 | } |
||
403 | /* or else, we handle the macro as normal macro */ |
||
404 | else { |
||
405 | line = malloc(strlen(rest_line) + 1); |
||
406 | if(!line) { |
||
407 | print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); |
||
408 | return(False); |
||
409 | } |
||
410 | strcpy(line, rest_line); |
||
411 | temp = line; |
||
412 | while(temp) { |
||
413 | macro_args[macro_arg_count++] = temp; |
||
414 | temp = get_next_token(temp, TERM_COMMA); |
||
415 | } |
||
416 | } |
||
417 | } |
||
418 | |||
419 | if(pi->pass == PASS_1) { |
||
420 | macro_call = calloc(1, sizeof(struct macro_call)); |
||
421 | if(!macro_call) { |
||
422 | print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); |
||
423 | return(False); |
||
424 | } |
||
425 | if(pi->last_macro_call) |
||
426 | pi->last_macro_call->next = macro_call; |
||
427 | else |
||
428 | pi->first_macro_call = macro_call; |
||
429 | |||
430 | pi->last_macro_call = macro_call; |
||
431 | macro_call->line_number = pi->fi->line_number; |
||
432 | macro_call->include_file = pi->fi->include_file; |
||
433 | macro_call->macro = macro; |
||
434 | macro_call->prev_on_stack = pi->macro_call; |
||
435 | |||
436 | if(macro_call->prev_on_stack) { |
||
437 | macro_call->nest_level = macro_call->prev_on_stack->nest_level + 1; |
||
438 | macro_call->prev_line_index = macro_call->prev_on_stack->line_index; |
||
439 | } |
||
440 | } |
||
441 | else { |
||
442 | for(macro_call = pi->first_macro_call; macro_call; macro_call = macro_call->next) { |
||
443 | if((macro_call->include_file->num == pi->fi->include_file->num) && (macro_call->line_number == pi->fi->line_number)) { |
||
444 | if(pi->macro_call) { |
||
445 | /* Find correct macro_call when using recursion and nesting */ |
||
446 | if(macro_call->prev_on_stack == pi->macro_call) |
||
447 | if((macro_call->nest_level == (pi->macro_call->nest_level + 1)) && (macro_call->prev_line_index == pi->macro_call->line_index)) |
||
448 | break; |
||
449 | } |
||
450 | else break; |
||
451 | } |
||
452 | } |
||
453 | if(pi->list_line && pi->list_on) { |
||
454 | fprintf(pi->list_file, "C:%06x + %s\n", pi->cseg_addr, pi->list_line); |
||
455 | pi->list_line = NULL; |
||
456 | } |
||
457 | } |
||
458 | |||
459 | macro_call->line_index = 0; |
||
460 | pi->macro_call = macro_call; |
||
461 | old_macro_line = pi->macro_line; |
||
462 | |||
463 | //printf("\nconvert macro: '%s'\n",macro->name); |
||
464 | |||
465 | for(pi->macro_line = macro->first_macro_line; pi->macro_line && ok; pi->macro_line = pi->macro_line->next) { |
||
466 | macro_call->line_index++; |
||
467 | if(GET_ARG(pi->args, ARG_LISTMAC)) |
||
468 | pi->list_line = buff; |
||
469 | else |
||
470 | pi->list_line = NULL; |
||
471 | |||
472 | /* here we change jumps/calls within macro that corresponds to macro labels. |
||
473 | Only in case there is an entry in macro_label list */ |
||
474 | |||
475 | strcpy(buff,"\0"); |
||
476 | macro_label = get_macro_label(pi->macro_line->line,macro); |
||
477 | if(macro_label) { |
||
478 | /* test if the right macro label has been found */ |
||
479 | temp = strstr(pi->macro_line->line,macro_label->label); |
||
480 | c = strlen(macro_label->label); |
||
481 | if(temp[c] == ':') { /* it is a label definition */ |
||
482 | macro_label->running_number++; |
||
483 | strncpy(buff, macro_label->label, c - 1); |
||
484 | buff[c - 1] = 0; |
||
485 | i = strlen(buff) + 2; /* we set the process indeafter label */ |
||
486 | /* add running number to it */ |
||
487 | strcpy(&buff[c-1],itoa(macro_label->running_number, tmp, 10)); |
||
488 | strcat(buff, ":\0"); |
||
489 | } |
||
490 | else if(IS_HOR_SPACE(temp[c]) || IS_END_OR_COMMENT(temp[c])) { /* it is a jump to a macro defined label */ |
||
491 | strcpy(buff,pi->macro_line->line); |
||
492 | temp = strstr(buff, macro_label->label); |
||
493 | i = temp - buff + strlen(macro_label->label); |
||
494 | strncpy(temp, macro_label->label, c - 1); |
||
495 | strcpy(&temp[c-1], itoa(macro_label->running_number, tmp, 10)); |
||
496 | } |
||
497 | } |
||
498 | else { |
||
499 | i = 0; |
||
500 | } |
||
501 | |||
502 | /* here we check every character of current line */ |
||
503 | for(j = i; pi->macro_line->line[i] != '\0'; i++) { |
||
504 | /* check for register place holders */ |
||
505 | if(pi->macro_line->line[i] == '@') { |
||
506 | i++; |
||
507 | if(!isdigit(pi->macro_line->line[i])) |
||
508 | print_msg(pi, MSGTYPE_ERROR, "@ must be followed by a number"); |
||
509 | else if((pi->macro_line->line[i] - '0') >= macro_arg_count) |
||
510 | print_msg(pi, MSGTYPE_ERROR, "Missing macro argument (for @%c)", pi->macro_line->line[i]); |
||
511 | else { |
||
512 | /* and replace them with given registers */ |
||
513 | strcat(&buff[j], macro_args[pi->macro_line->line[i] - '0']); |
||
514 | j += strlen(macro_args[pi->macro_line->line[i] - '0']); |
||
515 | } |
||
516 | } |
||
517 | else if (pi->macro_line->line[i] == ';') { |
||
518 | strncat(buff, "\n", 1); |
||
519 | break; |
||
520 | } |
||
521 | else { |
||
522 | strncat(buff, &pi->macro_line->line[i], 1); |
||
523 | } |
||
524 | } |
||
525 | |||
526 | ok = parse_line(pi, buff); |
||
527 | if(ok) { |
||
528 | if((pi->pass == PASS_2) && pi->list_line && pi->list_on) |
||
529 | fprintf(pi->list_file, " %s\n", pi->list_line); |
||
530 | if(pi->error_count >= pi->max_errors) { |
||
531 | print_msg(pi, MSGTYPE_MESSAGE, "Maximum error count reached. Exiting..."); |
||
532 | ok = False; |
||
533 | break; |
||
534 | } |
||
535 | } |
||
536 | } |
||
537 | |||
538 | pi->macro_line = old_macro_line; |
||
539 | pi->macro_call = macro_call->prev_on_stack; |
||
540 | if(rest_line) |
||
541 | free(line); |
||
542 | return(ok); |
||
543 | } |
||
544 | |||
545 | struct macro_label *get_macro_label(char *line, struct macro *macro) |
||
546 | { |
||
547 | char *temp ; |
||
548 | struct macro_label *macro_label; |
||
549 | |||
550 | for(macro_label = macro->first_label; macro_label; macro_label = macro_label->next) { |
||
551 | temp = strstr(line,macro_label->label); |
||
552 | if(temp) { |
||
553 | return macro_label; |
||
554 | } |
||
555 | } |
||
556 | return NULL; |
||
557 | } |
||
558 | |||
559 | /* end of macro.c */>32)) |
||
560 |