* use dynamic memory buffers instead temporary files
[fw/sdcc] / src / pic / main.c
1 /** @file main.c
2     pic14 specific general functions.
3
4     Note that mlh prepended _pic14_ on the static functions.  Makes
5     it easier to set a breakpoint using the debugger.
6 */
7 #include "common.h"
8 #include "main.h"
9 #include "ralloc.h"
10 #include "device.h"
11 #include "SDCCutil.h"
12 #include "SDCCmacro.h"
13 #include "MySystem.h"
14 #include "glue.h"
15 #include "dbuf_string.h"
16 #include <errno.h>
17 //#include "gen.h"
18
19
20 static char _defaultRules[] =
21 {
22 #include "peeph.rul"
23         ""
24 };
25
26 /* list of key words used by pic14 */
27 static char *_pic14_keywords[] =
28 {
29         "at",
30         //"bit",
31         "code",
32         "critical",
33         "data",
34         "far",
35         "idata",
36         "interrupt",
37         "near",
38         "pdata",
39         "reentrant",
40         "sfr",
41         //"sbit",
42         "using",
43         "xdata",
44         "_data",
45         "_code",
46         "_generic",
47         "_near",
48         "_xdata",
49         "_pdata",
50         "_idata",
51         NULL
52 };
53
54 pic14_options_t pic14_options;
55
56 #define ARG_STACKLOC    "--stack-loc"
57 #define ARG_STACKSIZ    "--stack-size"
58
59 extern int debug_verbose;       /* from pcode.c */
60 static OPTION _pic14_poptions[] = {
61         { 0 , "--debug-xtra", &debug_verbose, "show more debug info in assembly output" },
62         { 0 , "--no-pcode-opt", &pic14_options.disable_df, "disable (slightly faulty) optimization on pCode" },
63         { 0 , ARG_STACKLOC, NULL, "sets the lowest address of the argument passing stack" },
64         { 0 , ARG_STACKSIZ, NULL, "sets the size if the argument passing stack (default: 16, minimum: 4)" },
65         { 0 , NULL, NULL, NULL }
66 };
67
68 void  pCodeInitRegisters(void);
69
70 void pic14_assignRegisters (ebbIndex *);
71
72 /* Also defined in gen.h, but the #include is commented out */
73 /* for an unknowned reason. - EEP */
74 void pic14_emitDebuggerSymbol (char *);
75
76 static int regParmFlg = 0;      /* determine if we can register a parameter */
77
78 static void
79 _pic14_init (void)
80 {
81         asm_addTree (&asm_asxxxx_mapping);
82         memset (&pic14_options, 0, sizeof (pic14_options));
83 }
84
85 static void
86 _pic14_reset_regparm (void)
87 {
88         regParmFlg = 0;
89 }
90
91 static int
92 _pic14_regparm (sym_link * l, bool reentrant)
93 {
94 /* for this processor it is simple
95         can pass only the first parameter in a register */
96         //if (regParmFlg)
97         //  return 0;
98         
99         regParmFlg++;// = 1;
100         return 1;
101 }
102
103 extern char *udata_section_name;
104
105 static bool
106 _pic14_parseOptions (int *pargc, char **argv, int *i)
107 {
108         char buf[128];
109         
110         /* TODO: allow port-specific command line options to specify
111         * segment names here.
112         */
113         
114         /* This is a temporary hack, to solve problems with some processors
115         * that do not have udata section. It will be changed when a more
116         * robust solution is figured out -- VR 27-11-2003 FIXME
117         */
118         strcpy(buf, "--udata-section-name");
119         if(!strncmp(buf, argv[ *i ], strlen(buf))) {
120                 if(strlen(argv[ *i ]) <= strlen(buf)+1) {
121                         fprintf(stderr, "WARNING: no `%s' entered\n", buf+2);
122                         exit(EXIT_FAILURE);
123                 } else {
124                         udata_section_name = strdup( strchr(argv[*i], '=') + 1 );
125                 }
126                 return 1;
127         }
128
129         return FALSE;
130 }
131
132 extern set *dataDirsSet;
133 extern set *includeDirsSet;
134 /* pic14 port uses include/pic and lib/pic instead of
135  * include/pic14 and lib/pic14 as indicated by SDCCmain.c's
136  * setIncludePaths routine. */
137 static void
138 _pic14_initPaths (void)
139 {
140   char *p;
141   char *p2=NULL;
142   set *tempSet=NULL;
143
144   if (options.nostdinc)
145       return;
146
147   tempSet = appendStrSet(dataDirsSet, NULL, INCLUDE_DIR_SUFFIX DIR_SEPARATOR_STRING "pic");
148   mergeSets(&includeDirsSet, tempSet);
149
150   if ((p = getenv(SDCC_INCLUDE_NAME)) != NULL)
151   {
152     addSetHead(&includeDirsSet, p);
153     p2=Safe_alloc(strlen(p)+strlen(DIR_SEPARATOR_STRING)+strlen("pic")+1);
154     if(p2!=NULL)
155     {
156         strcpy(p2, p);
157         strcat(p2, DIR_SEPARATOR_STRING);
158         strcat(p2, "pic");
159         addSetHead(&includeDirsSet, p2);
160     }
161   }
162 }
163
164 static void
165 _pic14_finaliseOptions (void)
166 {
167         pCodeInitRegisters();
168         
169         port->mem.default_local_map = data;
170         port->mem.default_globl_map = data;
171 #if 0
172         /* Hack-o-matic: if we are using the flat24 model,
173         * adjust pointer sizes.
174         */
175         if (options.model == MODEL_FLAT24)
176         {
177                 
178                 fprintf (stderr, "*** WARNING: you should use the '-mds390' option "
179                         "for DS80C390 support. This code generator is "
180                         "badly out of date and probably broken.\n");
181                 
182                 port->s.fptr_size = 3;
183                 port->s.gptr_size = 4;
184                 port->stack.isr_overhead++;     /* Will save dpx on ISR entry. */
185 #if 1
186                 port->stack.call_overhead++;    /* This acounts for the extra byte 
187                                                  * of return addres on the stack.
188                                                  * but is ugly. There must be a 
189                                                  * better way.
190                                                  */
191 #endif
192                 fReturn = fReturn390;
193                 fReturnSize = 5;
194         }
195         
196         if (options.model == MODEL_LARGE)
197         {
198                 port->mem.default_local_map = xdata;
199                 port->mem.default_globl_map = xdata;
200         }
201         else
202         {
203                 port->mem.default_local_map = data;
204                 port->mem.default_globl_map = data;
205         }
206         
207         if (options.stack10bit)
208         {
209                 if (options.model != MODEL_FLAT24)
210                 {
211                         fprintf (stderr,
212                                 "*** warning: 10 bit stack mode is only supported in flat24 model.\n");
213                         fprintf (stderr, "\t10 bit stack mode disabled.\n");
214                         options.stack10bit = 0;
215                 }
216                 else
217                 {
218                 /* Fixup the memory map for the stack; it is now in
219                 * far space and requires a FPOINTER to access it.
220                 */
221                         istack->fmap = 1;
222                         istack->ptrType = FPOINTER;
223                 }
224         }
225 #endif
226 }
227
228 static void
229 _pic14_setDefaultOptions (void)
230 {
231 }
232
233 static const char *
234 _pic14_getRegName (struct regs *reg)
235 {
236         if (reg)
237                 return reg->name;
238         return "err";
239 }
240
241 extern char *processor_base_name(void);
242
243 static void
244 _pic14_genAssemblerPreamble (FILE * of)
245 {
246         char * name = processor_base_name();
247         
248         if(!name) {
249                 
250                 name = "16f877";
251                 fprintf(stderr,"WARNING: No Pic has been selected, defaulting to %s\n",name);
252         }
253         
254         fprintf (of, "\tlist\tp=%s\n",name);
255         fprintf (of, "\tradix dec\n");
256         fprintf (of, "\tinclude \"p%s.inc\"\n",name);
257 }
258
259 /* Generate interrupt vector table. */
260 static int
261 _pic14_genIVT (struct dbuf_s * oBuf, symbol ** interrupts, int maxInterrupts)
262 {
263         int i;
264         
265         if (options.model != MODEL_FLAT24)
266         {
267                 /* Let the default code handle it. */
268                 return FALSE;
269         }
270         
271         dbuf_printf (oBuf, "\t;ajmp\t__sdcc_gsinit_startup\n");
272         
273         /* now for the other interrupts */
274         for (i = 0; i < maxInterrupts; i++)
275         {
276                 if (interrupts[i])
277                 {
278                         dbuf_printf (oBuf, "\t;ljmp\t%s\n\t.ds\t4\n", interrupts[i]->rname);
279                 }
280                 else
281                 {
282                         dbuf_printf (oBuf, "\t;reti\n\t.ds\t7\n");
283                 }
284         }
285         
286         return TRUE;
287 }
288
289 static bool
290 _hasNativeMulFor (iCode *ic, sym_link *left, sym_link *right)
291 {
292 /*
293 sym_link *test = NULL;
294 value *val;
295         */
296         
297         //fprintf(stderr,"checking for native mult\n");
298         
299         if ( ic->op != '*')
300         {
301                 return FALSE;
302         }
303         
304         /* multiply chars in-place */
305         if (getSize(left) == 1 && getSize(right) == 1)
306                 return TRUE;
307         
308         /* use library functions for more complex maths */
309         return FALSE;
310
311         /*
312         if ( IS_LITERAL (left))
313         {
314         fprintf(stderr,"left is lit\n");
315         test = left;
316         val = OP_VALUE (IC_LEFT (ic));
317         }
318         else if ( IS_LITERAL (right))
319         {
320         fprintf(stderr,"right is lit\n");
321         test = left;
322         val = OP_VALUE (IC_RIGHT (ic));
323         }
324         else
325         {
326         fprintf(stderr,"oops, neither is lit so no\n");
327         return FALSE;
328         }
329         
330           if ( getSize (test) <= 2)
331           {
332           fprintf(stderr,"yep\n");
333           return TRUE;
334           }
335           fprintf(stderr,"nope\n");
336           
337                 return FALSE;
338         */
339 }
340
341 /* Indicate which extended bit operations this port supports */
342 static bool
343 hasExtBitOp (int op, int size)
344 {
345         if (op == RRC
346                 || op == RLC
347                 /* || op == GETHBIT */ /* GETHBIT doesn't look complete for PIC */
348                 )
349                 return TRUE;
350         else
351                 return FALSE;
352 }
353
354 /* Indicate the expense of an access to an output storage class */
355 static int
356 oclsExpense (struct memmap *oclass)
357 {
358         /* The IN_FARSPACE test is compatible with historical behaviour, */
359         /* but I don't think it is applicable to PIC. If so, please feel */
360         /* free to remove this test -- EEP */
361         if (IN_FARSPACE(oclass))
362                 return 1;
363
364         return 0;
365 }
366
367 /** $1 is always the basename.
368 $2 is always the output file.
369 $3 varies
370 $l is the list of extra options that should be there somewhere...
371 MUST be terminated with a NULL.
372 */
373 static const char *_linkCmd[] =
374 {
375         "gplink", "$l", "-w", "-r", "-o \"$2\"", "\"$1\"", "$3", NULL
376 };
377
378 static const char *_asmCmd[] =
379 {
380         "gpasm", "$l", "-c", "\"$1.asm\"", NULL
381                 
382 };
383
384 extern set *libFilesSet;
385 extern set *libDirsSet;
386 extern set *libPathsSet;
387 extern set *includeDirsSet;
388 extern set *userIncDirsSet;
389 extern set *dataDirsSetSet;
390 extern set *relFilesSet;
391 extern set *linkOptionsSet;
392
393 static void _pic14_do_link (void)
394 {
395   hTab *linkValues=NULL;
396   char lfrm[256];
397   char *lcmd;
398   char temp[128];
399   set *tSet=NULL;
400   int ret;
401   char * procName;
402   
403   /*
404    * link command format:
405    * {linker} {incdirs} {lflags} -o {outfile} {spec_ofiles} {ofiles} {libs}
406    *
407    */
408
409   sprintf(lfrm, "{linker} {incdirs} {sysincdirs} {lflags} -w -r -o {outfile} {user_ofile} {spec_ofiles} {ofiles} {libs}");
410
411   shash_add(&linkValues, "linker", "gplink");
412
413   /* LIBRARY SEARCH DIRS */
414   mergeSets(&tSet, libPathsSet);
415   mergeSets(&tSet, libDirsSet);
416   shash_add(&linkValues, "incdirs", joinStrSet(appendStrSet(tSet, "-I\"", "\"")));
417
418   SNPRINTF (&temp[0], 128, "%cpic\"", DIR_SEPARATOR_CHAR);
419   joinStrSet(appendStrSet(libDirsSet, "-I\"", &temp[0]));
420   shash_add(&linkValues, "sysincdirs", joinStrSet(appendStrSet(libDirsSet, "-I\"", &temp[0])));
421   
422   shash_add(&linkValues, "lflags", joinStrSet(linkOptionsSet));
423
424   shash_add(&linkValues, "outfile", fullDstFileName ? fullDstFileName : dstFileName);
425
426   if(fullSrcFileName) {
427     sprintf(temp, "%s.o", fullDstFileName ? fullDstFileName : dstFileName );
428     shash_add(&linkValues, "user_ofile", temp);
429   }
430
431   shash_add(&linkValues, "ofiles", joinStrSet(relFilesSet));
432
433   /* LIBRARIES */
434   procName = processor_base_name();
435   if (!procName) {
436      procName = "16f877";
437   }
438         
439   addSet(&libFilesSet, "libsdcc.lib");
440   SNPRINTF(&temp[0], 128, "pic%s.lib", procName);
441   addSet(&libFilesSet, temp);
442   shash_add(&linkValues, "libs", joinStrSet(libFilesSet));
443
444   lcmd = msprintf(linkValues, lfrm);
445
446   ret = my_system( lcmd );
447
448   Safe_free( lcmd );
449
450   if(ret)
451     exit(1);
452 }
453
454 /* Globals */
455 PORT pic_port =
456 {
457         TARGET_ID_PIC,
458         "pic14",
459         "MCU pic",                      /* Target name */
460         "",                    /* Processor */
461         {
462                 picglue,
463                 TRUE,                   /* Emit glue around main */
464                 MODEL_SMALL | MODEL_LARGE | MODEL_FLAT24,
465                 MODEL_SMALL
466         },
467         {
468                 _asmCmd,
469                 NULL,
470                 NULL,
471                 NULL,
472                 //"-plosgffc",          /* Options with debug */
473                 //"-plosgff",           /* Options without debug */
474                 0,
475                 ".asm",
476                 NULL                    /* no do_assemble function */
477         },
478         {
479                 _linkCmd,
480                 NULL,
481                 _pic14_do_link,         /* own do link function */
482                 ".o",
483                 0
484         },
485         {
486                 _defaultRules
487         },
488         {
489                 /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
490                 1, 2, 2, 4, 2, 2, 3, 1, 4, 4
491                 /* TSD - I changed the size of gptr from 3 to 1. However, it should be
492                    2 so that we can accomodate the PIC's with 4 register banks (like the
493                    16f877)
494                  */
495         },
496         /* tags for generic pointers */
497         { 0x00, 0x00, 0x00, 0x80 },             /* far, near, xstack, code */
498         {
499                 "XSEG    (XDATA)",
500                 "STACK   (DATA)",
501                 "code",
502                 "DSEG    (DATA)",
503                 "ISEG    (DATA)",
504                 NULL, /* pdata */
505                 "XSEG    (XDATA)",
506                 "BSEG    (BIT)",
507                 "RSEG    (DATA)",
508                 "GSINIT  (CODE)",
509                 "udata_ovr",
510                 "GSFINAL (CODE)",
511                 "HOME    (CODE)",
512                 NULL, // xidata
513                 NULL, // xinit
514                 "CONST   (CODE)",               // const_name - const data (code or not)
515                 "CABS    (ABS,CODE)",   // cabs_name - const absolute data (code or not)
516                 "XABS    (ABS,XDATA)",  // xabs_name - absolute xdata
517                 "IABS    (ABS,DATA)",   // iabs_name - absolute data
518                 NULL,
519                 NULL,
520                 1        // code is read only
521         },
522         { NULL, NULL },
523         {
524                 +1, 1, 4, 1, 1, 0
525         },
526                 /* pic14 has an 8 bit mul */
527         {
528                 1, -1
529         },
530         {
531                 pic14_emitDebuggerSymbol
532         },
533         {
534                 255/3,      /* maxCount */
535                 3,          /* sizeofElement */
536                 /* The rest of these costs are bogus. They approximate */
537                 /* the behavior of src/SDCCicode.c 1.207 and earlier.  */
538                 {4,4,4},    /* sizeofMatchJump[] */
539                 {0,0,0},    /* sizeofRangeCompare[] */
540                 0,          /* sizeofSubtract */
541                 3,          /* sizeofDispatch */
542         },
543         "_",
544         _pic14_init,
545         _pic14_parseOptions,
546         _pic14_poptions,
547         _pic14_initPaths,
548         _pic14_finaliseOptions,
549         _pic14_setDefaultOptions,
550         pic14_assignRegisters,
551         _pic14_getRegName,
552         _pic14_keywords,
553         _pic14_genAssemblerPreamble,
554         NULL,                           /* no genAssemblerEnd */
555         _pic14_genIVT,
556         NULL, // _pic14_genXINIT
557         NULL,                           /* genInitStartup */
558         _pic14_reset_regparm,
559         _pic14_regparm,
560         NULL,                           /* process a pragma */
561         NULL,
562         _hasNativeMulFor,
563         hasExtBitOp,                    /* hasExtBitOp */
564         oclsExpense,                    /* oclsExpense */
565         FALSE,
566 //      TRUE,                           /* little endian */
567         FALSE,                          /* little endian - PIC code enumlates big endian */
568         0,                              /* leave lt */
569         0,                              /* leave gt */
570         1,                              /* transform <= to ! > */
571         1,                              /* transform >= to ! < */
572         1,                              /* transform != to !(a == b) */
573         0,                              /* leave == */
574         FALSE,                        /* No array initializer support. */
575         0,                            /* no CSE cost estimation yet */
576         NULL,                   /* no builtin functions */
577         GPOINTER,                       /* treat unqualified pointers as "generic" pointers */
578         1,                              /* reset labelKey to 1 */
579         1,                              /* globals & local static allowed */
580         PORT_MAGIC
581 };