Use 'ao-dbg' instead of 's51' to communicate with TeleMetrum
[fw/sdcc] / src / SDCCasm.c
1 /*-------------------------------------------------------------------------
2   SDCCasm.c - header file for all types of stuff to support different assemblers.
3
4
5   Written By - Michael Hope <michaelh@juju.net.nz> 2000
6
7   This program is free software; you can redistribute it and/or modify it
8   under the terms of the GNU General Public License as published by the
9   Free Software Foundation; either version 2, or (at your option) any
10   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; if not, write to the Free Software
19   Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20
21   In other words, you are welcome to use, share and improve this program.
22   You are forbidden to forbid anyone else to use, share and improve
23   what you give them.   Help stamp out software-hoarding!
24 -------------------------------------------------------------------------*/
25
26 /*  Provides output functions that modify the output string
27     based on the input tokens and the assembler token mapping
28     specification loaded.
29
30     Note that the functions below only handle digit format modifiers.
31     eg %02X is ok, but %lu and %.4u will fail.
32 */
33
34 #include <errno.h>
35
36 #include "common.h"
37 #include "dbuf_string.h"
38
39 /* A 'token' is like !blah or %24f and is under the programmers
40    control. */
41
42 static hTab *_h;
43
44 char *
45 FileBaseName (char *fileFullName)
46 {
47   char *p = fileFullName;
48
49   if (!fileFullName) {
50     return "unknown";
51   }
52
53   while (*fileFullName)
54     {
55       if ((*fileFullName == '/') || (*fileFullName == '\\') || (*fileFullName == ':'))
56         {
57           p = fileFullName;
58           p++;
59         }
60       fileFullName++;
61     }
62   return p;
63 }
64
65 void
66 dbuf_tvprintf (struct dbuf_s *dbuf, const char *format, va_list ap)
67 {
68   // Under Linux PPC va_list is a structure instead of a primitive type,
69   // and doesnt like being passed around.  This version turns everything
70   // into one function.
71
72   // Supports:
73   //  !tokens
74   //  %[CIFN] - special formats with no argument (ie list isnt touched)
75   //  All of the system formats
76
77   // This is acheived by expanding the tokens and zero arg formats into
78   // one big format string, which is passed to the native printf.
79   static int count;
80   struct dbuf_s tmpDBuf;
81   const char *noTokens;
82   const char *sz = format;
83
84   dbuf_init(&tmpDBuf, INITIAL_INLINEASM);
85
86   /* First pass: expand all of the macros */
87   while (*sz)
88     {
89       if (*sz == '!')
90         {
91           /* Start of a token.  Search until the first
92              [non alpha, *] and call it a token. */
93           const char *t;
94           struct dbuf_s token;
95
96           dbuf_init (&token, 64);
97           sz++;
98           while (isalpha ((unsigned char)*sz) || *sz == '*')
99             {
100               dbuf_append (&token, sz++, 1);
101             }
102           /* Now find the token in the token list */
103           if ((t = shash_find (_h, dbuf_c_str(&token))))
104             {
105               dbuf_append_str (&tmpDBuf, t);
106             }
107           else
108             {
109               fprintf (stderr, "Cant find token \"%s\"\n", dbuf_c_str(&token));
110               wassert (0);
111             }
112           dbuf_destroy (&token);
113         }
114       else
115         {
116           dbuf_append_char (&tmpDBuf, *sz++);
117         }
118     }
119
120   /* Second pass: Expand any macros that we own */
121   dbuf_c_str (&tmpDBuf);
122   sz = noTokens = dbuf_detach (&tmpDBuf);
123
124   /* recycle tmpDBuf */
125   dbuf_init (&tmpDBuf, INITIAL_INLINEASM);
126
127   while (*sz)
128     {
129       if (*sz == '%')
130         {
131           // See if its one that we handle.
132           sz++;
133           switch (*sz)
134             {
135             case 'C':
136               // Code segment name.
137               dbuf_append_str (&tmpDBuf, CODE_NAME);
138               sz++;
139               break;
140
141             case 'F':
142               // Source file name.
143               dbuf_append_str (&tmpDBuf, fullSrcFileName);
144               sz++;
145               break;
146
147             case 'N':
148               // Current function name.
149               dbuf_append_str (&tmpDBuf, currFunc->rname);
150               sz++;
151               break;
152
153             case 'I':
154               // Unique ID.
155               dbuf_printf (&tmpDBuf, "%u", ++count);
156               sz++;
157               break;
158
159             default:
160               // Not one of ours.  Copy until the end.
161               dbuf_append_char (&tmpDBuf, '%');
162               while (!isalpha ((unsigned char)*sz))
163                 dbuf_append_char (&tmpDBuf, *sz++);
164
165               dbuf_append_char (&tmpDBuf, *sz++);
166             }
167         }
168       else
169         {
170           dbuf_append_char (&tmpDBuf, *sz++);
171         }
172     }
173
174   dbuf_free (noTokens);
175
176   dbuf_vprintf (dbuf, dbuf_c_str (&tmpDBuf), ap);
177
178   dbuf_destroy (&tmpDBuf);
179 }
180
181 void
182 dbuf_tprintf (struct dbuf_s *dbuf, const char *szFormat, ...)
183 {
184   va_list ap;
185   va_start (ap, szFormat);
186   dbuf_tvprintf (dbuf, szFormat, ap);
187   va_end (ap);
188 }
189
190 void
191 tsprintf (char *buffer, size_t len, const char *szFormat, ...)
192 {
193   va_list ap;
194   struct dbuf_s dbuf;
195   size_t copyLen;
196
197   dbuf_init (&dbuf, INITIAL_INLINEASM);
198
199   va_start (ap, szFormat);
200   dbuf_tvprintf (&dbuf, szFormat, ap);
201   va_end (ap);
202
203   copyLen = min (len - 1, dbuf_get_length (&dbuf));
204   memcpy (buffer, dbuf_get_buf (&dbuf), copyLen);
205   buffer[copyLen] = '\0';
206   dbuf_destroy (&dbuf);
207 }
208
209 void
210 tfprintf (FILE *fp, const char *szFormat, ...)
211 {
212   va_list ap;
213   struct dbuf_s dbuf;
214   size_t len;
215
216   dbuf_init (&dbuf, INITIAL_INLINEASM);
217
218   va_start (ap, szFormat);
219   dbuf_tvprintf (&dbuf, szFormat, ap);
220   va_end (ap);
221
222   len = dbuf_get_length (&dbuf);
223   fwrite(dbuf_get_buf (&dbuf), 1, len, fp);
224   dbuf_destroy (&dbuf);
225 }
226
227 void
228 asm_addTree (const ASM_MAPPINGS *pMappings)
229 {
230   const ASM_MAPPING *pMap;
231
232   /* Traverse down first */
233   if (pMappings->pParent)
234     asm_addTree (pMappings->pParent);
235   pMap = pMappings->pMappings;
236   while (pMap->szKey && pMap->szValue) {
237       shash_add (&_h, pMap->szKey, pMap->szValue);
238       pMap++;
239   }
240 }
241
242 /*-----------------------------------------------------------------*/
243 /* printILine - return the readable i-code for this ic             */
244 /*-----------------------------------------------------------------*/
245 const char *
246 printILine (iCode *ic)
247 {
248   char *verbalICode;
249   struct dbuf_s tmpBuf;
250   size_t len;
251   iCodeTable *icTab = getTableEntry (ic->op);
252
253   dbuf_init (&tmpBuf, 1024);
254
255   if (INLINEASM == ic->op)
256     dbuf_append (&tmpBuf, "inline", (sizeof "inline") - 1);
257   else
258     {
259       /* stuff the temporary file with the readable icode */
260       icTab->iCodePrint (&tmpBuf, ic, icTab->printName);
261     }
262
263   len = dbuf_get_length (&tmpBuf);
264
265   /* null terminate the buffer */
266   dbuf_c_str (&tmpBuf);
267   verbalICode = dbuf_detach (&tmpBuf);
268
269   /* kill the trailing NL */
270   if (len > 0 && '\n' == verbalICode[len - 1])
271     verbalICode[--len] = '\0';
272
273   /* and throw it up */
274   return verbalICode;
275 }
276
277
278 /*-----------------------------------------------------------------*/
279 /* skipLine - skip the line from file infp                         */
280 /*-----------------------------------------------------------------*/
281 static int
282 skipLine (FILE *infp)
283 {
284   int c;
285   static char is_eof = 0;
286   size_t len = 0;
287
288   if (is_eof)
289     return 0;
290
291   while ((c = getc(infp)) != '\n' && EOF != c)
292     ++len;
293
294   if (EOF == c)
295     {
296       if (len)
297         {
298           /* EOF in the middle of the line */
299           is_eof = 1;
300           return 1;
301         }
302       else
303         return 0;
304     }
305   else
306     return 1;
307 }
308
309 /*-----------------------------------------------------------------*/
310 /* printCLine - return the c-code for this lineno                  */
311 /*-----------------------------------------------------------------*/
312 /* int rewinds=0; */
313 const char *
314 printCLine (const char *srcFile, int lineno)
315 {
316   static FILE *inFile = NULL;
317   static struct dbuf_s line;
318   static struct dbuf_s lastSrcFile;
319   static char dbufInitialized = 0;
320   static int inLineNo = 0;
321   size_t len;
322
323   if (!dbufInitialized)
324     {
325       dbuf_init (&line, 1024);
326       dbuf_init (&lastSrcFile, PATH_MAX);
327       dbufInitialized = 1;
328     }
329   else
330     {
331       /* empty the dynamic buffer */
332       dbuf_set_length (&line, 0);
333     }
334
335   if (inFile)
336     {
337       if (strcmp (dbuf_c_str (&lastSrcFile), srcFile) != 0)
338         {
339           fclose (inFile);
340           inFile = NULL;
341           inLineNo = 0;
342           dbuf_set_length (&lastSrcFile, 0);
343           dbuf_append_str (&lastSrcFile, srcFile);
344         }
345     }
346
347   if (!inFile)
348     {
349       if (!(inFile = fopen(srcFile, "r")))
350         {
351           /* can't open the file:
352              don't panic, just return the error message */
353           dbuf_printf(&line, "ERROR: %s", strerror(errno));
354
355           return dbuf_c_str (&line);
356         }
357       else
358         {
359           dbuf_set_length (&lastSrcFile, 0);
360           dbuf_append_str (&lastSrcFile, srcFile);
361         }
362     }
363
364   if (inLineNo > lineno)
365     {
366       /* past the lineno: rewind the file pointer */
367       rewind (inFile);
368       inLineNo = 0;
369       /* rewinds++; */
370     }
371
372    /* skip lines until lineno */
373   while (inLineNo + 1 < lineno)
374     {
375       if (!skipLine (inFile))
376         goto err_no_line;
377       ++inLineNo;
378     }
379
380    /* get the line */
381   if (0 != (len = dbuf_getline (&line, inFile)))
382     {
383       const char *inLineString = dbuf_c_str (&line);
384
385       ++inLineNo;
386
387       /* remove the trailing NL */
388       if (len > 0 &&'\n' == inLineString[len - 1])
389         {
390           dbuf_set_length (&line, --len);
391           inLineString = dbuf_c_str (&line);
392         }
393
394       /* skip leading spaces */
395       while (isspace (*inLineString))
396         inLineString++;
397
398       return inLineString;
399     }
400
401 err_no_line:
402   dbuf_printf(&line, "ERROR: no line number %d in file %s", lineno, srcFile);
403
404   return dbuf_c_str (&line);
405 }
406
407 static const ASM_MAPPING _asxxxx_mapping[] =
408 {
409   {"labeldef", "%s::"},
410   {"slabeldef", "%s:"},
411   {"tlabeldef", "%05d$:"},
412   {"tlabel", "%05d$"},
413   {"immed", "#"},
414   {"zero", "#0x00"},
415   {"one", "#0x01"},
416   {"area", ".area %s"},
417   {"areacode", ".area %s"},
418   {"areadata", ".area %s"},
419   {"areahome", ".area %s"},
420   {"ascii", ".ascii \"%s\""},
421   {"ds", ".ds %d"},
422   {"db", ".db"},
423   {"dbs", ".db %s"},
424   {"dw", ".dw"},
425   {"dws", ".dw %s"},
426   {"constbyte", "0x%02X"},
427   {"constword", "0x%04X"},
428   {"immedword", "#0x%04X"},
429   {"immedbyte", "#0x%02X"},
430   {"hashedstr", "#%s"},
431   {"lsbimmeds", "#<%s"},
432   {"msbimmeds", "#>%s"},
433   {"module", ".module %s"},
434   {"global", ".globl %s"},
435   {"fileprelude", ""},
436   {"functionheader",
437    "; ---------------------------------\n"
438    "; Function %s\n"
439    "; ---------------------------------"
440   },
441   {"functionlabeldef", "%s:"},
442   {"bankimmeds", "0     ; PENDING: bank support"},
443   {"los", "(%s & 0xFF)"},
444   {"his", "(%s >> 8)"},
445   {"hihis", "(%s >> 16)"},
446   {"hihihis", "(%s >> 24)"},
447   {"lod", "(%d & 0xFF)"},
448   {"hid", "(%d >> 8)"},
449   {"hihid", "(%d >> 16)"},
450   {"hihihid", "(%d >> 24)"},
451   {"lol", "(%05d$ & 0xFF)"},
452   {"hil", "(%05d$ >> 8)"},
453   {"hihil", "(%05d$ >> 16)"},
454   {"hihihil", "(%05d$ >> 24)"},
455   {"equ", "="},
456   {"org", ".org 0x%04X"},
457   {NULL, NULL}
458 };
459
460 static const ASM_MAPPING _gas_mapping[] =
461 {
462   {"labeldef", "%s::"},
463   {"slabeldef", "%s:"},
464   {"tlabeldef", "%05d$:"},
465   {"tlabel", "%05d$"},
466   {"immed", "#"},
467   {"zero", "#0x00"},
468   {"one", "#0x01"},
469   {"area", ".section %s"},
470   {"areacode", ".section %s"},
471   {"areadata", ".section %s"},
472   {"areahome", ".section %s"},
473   {"ascii", ".ascii \"%s\""},
474   {"ds", ".ds %d"},
475   {"db", ".db"},
476   {"dbs", ".db %s"},
477   {"dw", ".dw"},
478   {"dws", ".dw %s"},
479   {"constbyte", "0x%02X"},
480   {"constword", "0x%04X"},
481   {"immedword", "#0x%04X"},
482   {"immedbyte", "#0x%02X"},
483   {"hashedstr", "#%s"},
484   {"lsbimmeds", "#<%s"},
485   {"msbimmeds", "#>%s"},
486   {"module", ".file \"%s.c\""},
487   {"global", ".globl %s"},
488   {"extern", ".globl %s"},
489   {"fileprelude", ""},
490   {"functionheader",
491    "; ---------------------------------\n"
492    "; Function %s\n"
493    "; ---------------------------------"
494   },
495   {"functionlabeldef", "%s:"},
496   {"bankimmeds", "0     ; PENDING: bank support"},
497   {NULL, NULL}
498 };
499
500 static const ASM_MAPPING _a390_mapping[] =
501 {
502   {"labeldef", "%s:"},
503   {"slabeldef", "%s:"},
504   {"tlabeldef", "L%05d:"},
505   {"tlabel", "L%05d"},
506   {"immed", "#"},
507   {"zero", "#0"},
508   {"one", "#1"},
509   {"area", "; SECTION NOT SUPPORTED"},
510   {"areacode", "; SECTION NOT SUPPORTED"},
511   {"areadata", "; SECTION NOT SUPPORTED"},
512   {"areahome", "; SECTION NOT SUPPORTED"},
513   {"ascii", "db \"%s\""},
514   {"ds", "; STORAGE NOT SUPPORTED"},
515   {"db", "db"},
516   {"dbs", "db \"%s\""},
517   {"dw", "dw"},
518   {"dws", "dw %s"},
519   {"constbyte", "0%02xh"},
520   {"constword", "0%04xh"},
521   {"immedword", "#0%04Xh"},
522   {"immedbyte", "#0%02Xh"},
523   {"hashedstr", "#%s"},
524   {"lsbimmeds", "#<%s"},
525   {"msbimmeds", "#>%s"},
526   {"module", "; .file \"%s.c\""},
527   {"global", "; .globl %s"},
528   {"fileprelude", ""},
529   {"functionheader",
530    "; ---------------------------------\n"
531    "; Function %s\n"
532    "; ---------------------------------"
533   },
534   {"functionlabeldef", "%s:"},
535   {"bankimmeds", "0     ; PENDING: bank support"},
536   {"los", "(%s & 0FFh)"},
537   {"his", "((%s / 256) & 0FFh)"},
538   {"hihis", "((%s / 65536) & 0FFh)"},
539   {"hihihis", "((%s / 16777216) & 0FFh)"},
540   {"lod", "(%d & 0FFh)"},
541   {"hid", "((%d / 256) & 0FFh)"},
542   {"hihid", "((%d / 65536) & 0FFh)"},
543   {"hihihid", "((%d / 16777216) & 0FFh)"},
544   {"lol", "(L%05d & 0FFh)"},
545   {"hil", "((L%05d / 256) & 0FFh)"},
546   {"hihil", "((L%05d / 65536) & 0FFh)"},
547   {"hihihil", "((L%09d / 16777216) & 0FFh)"},
548   {"equ", " equ"},
549   {"org", ".org 0x%04X"},
550   {NULL, NULL}
551 };
552
553 static const ASM_MAPPING _xa_asm_mapping[] =
554 {
555   {"labeldef", "%s:"},
556   {"slabeldef", "%s:"},
557   {"tlabeldef", "L%05d:"},
558   {"tlabel", "L%05d"},
559   {"immed", "#"},
560   {"zero", "#0"},
561   {"one", "#1"},
562   {"area", ".area %s"},
563   {"areacode", ".area %s"},
564   {"areadata", ".area %s"},
565   {"areahome", ".area %s"},
566   {"ascii", ".db \"%s\""},
567   {"ds", ".ds %d"},
568   {"db", ".db"},
569   {"dbs", ".db \"%s\""},
570   {"dw", ".dw"},
571   {"dws", ".dw %s"},
572   {"constbyte", "0x%02x"},
573   {"constword", "0x%04x"},
574   {"immedword", "0x%04x"},
575   {"immedbyte", "0x%02x"},
576   {"hashedstr", "#%s"},
577   {"lsbimmeds", "#<%s"},
578   {"msbimmeds", "#>%s"},
579   {"module", "; .module %s"},
580   {"global", ".globl %s"},
581   {"fileprelude", ""},
582   {"functionheader",
583    "; ---------------------------------\n"
584    "; Function %s\n"
585    "; ---------------------------------"
586   },
587   {"functionlabeldef", "%s:"},
588   {"bankimmeds", "0     ; PENDING: bank support"},
589   {"los", "(%s & 0FFh)"},
590   {"his", "((%s / 256) & 0FFh)"},
591   {"hihis", "((%s / 65536) & 0FFh)"},
592   {"hihihis", "((%s / 16777216) & 0FFh)"},
593   {"lod", "(%d & 0FFh)"},
594   {"hid", "((%d / 256) & 0FFh)"},
595   {"hihid", "((%d / 65536) & 0FFh)"},
596   {"hihihid", "((%d / 16777216) & 0FFh)"},
597   {"lol", "(L%05d & 0FFh)"},
598   {"hil", "((L%05d / 256) & 0FFh)"},
599   {"hihil", "((L%05d / 65536) & 0FFh)"},
600   {"hihihil", "((L%09d / 16777216) & 0FFh)"},
601   {"equ", " equ"},
602   {NULL, NULL}
603 };
604
605 const ASM_MAPPINGS asm_asxxxx_mapping =
606 {
607   NULL,
608   _asxxxx_mapping
609 };
610
611 const ASM_MAPPINGS asm_gas_mapping =
612 {
613   NULL,
614   _gas_mapping
615 };
616
617 const ASM_MAPPINGS asm_a390_mapping =
618 {
619   NULL,
620   _a390_mapping
621 };
622
623 const ASM_MAPPINGS asm_xa_asm_mapping =
624 {
625   NULL,
626   _xa_asm_mapping
627 };