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