* src/pic/main.c (_pic14_parseOptions): added --stack-loc=NUM and
[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-siz"
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, &pic14_options.stackLocation, "sets the lowest address of the argument passing stack" },
63         { 0 , ARG_STACKSIZ, &pic14_options.stackSize, "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         static const char *WHITE = " \t";
106         char    *ptr = strtok((char *)sz, WHITE);
107         
108         if (startsWith (ptr, "memmap"))
109         {
110                 char    *start;
111                 char    *end;
112                 char    *type;
113                 char    *alias;
114                 
115                 start = strtok((char *)NULL, WHITE);
116                 end = strtok((char *)NULL, WHITE);
117                 type = strtok((char *)NULL, WHITE);
118                 alias = strtok((char *)NULL, WHITE);
119                 
120                 if (start != (char *)NULL
121                         && end != (char *)NULL
122                         && type != (char *)NULL) {
123                         value           *startVal = constVal(start);
124                         value           *endVal = constVal(end);
125                         value           *aliasVal;
126                         memRange        r;
127                         
128                         if (alias == (char *)NULL) {
129                                 aliasVal = constVal(0);
130                         } else {
131                                 aliasVal = constVal(alias);
132                         }
133                         
134                         r.start_address = (int)floatFromVal(startVal);
135                         r.end_address = (int)floatFromVal(endVal);
136                         r.alias = (int)floatFromVal(aliasVal);
137                         r.bank = (r.start_address >> 7) & 3;
138                         
139                         if (strcmp(type, "RAM") == 0) {
140                                 addMemRange(&r, 0);
141                         } else if (strcmp(type, "SFR") == 0) {
142                                 addMemRange(&r, 1);
143                         } else {
144                                 return 1;
145                         }
146                 }
147                 
148                 return 0;
149         } else if (startsWith (ptr, "maxram")) {
150                 // not used any more - comes from device config file pic14devices.txt instead
151                 return 0;
152         }
153         return 1;
154 }
155
156 extern char *udata_section_name;
157
158 static bool
159 _pic14_parseOptions (int *pargc, char **argv, int *i)
160 {
161         char buf[128];
162         int len;
163         
164         /* TODO: allow port-specific command line options to specify
165         * segment names here.
166         */
167         
168         /* This is a temporary hack, to solve problems with some processors
169         * that do not have udata section. It will be changed when a more
170         * robust solution is figured out -- VR 27-11-2003 FIXME
171         */
172         strcpy(buf, "--udata-section-name");
173         if(!strncmp(buf, argv[ *i ], strlen(buf))) {
174                 if(strlen(argv[ *i ]) <= strlen(buf)+1) {
175                         fprintf(stderr, "WARNING: no `%s' entered\n", buf+2);
176                         exit(EXIT_FAILURE);
177                 } else {
178                         udata_section_name = strdup( strchr(argv[*i], '=') + 1 );
179                 }
180                 return 1;
181         }
182
183         len = strlen(ARG_STACKLOC);
184         if (!strncmp(ARG_STACKLOC, argv[ *i ], len)) {
185                 if (argv[*i][len] != '=' || argv[*i][len+1] == 0) {
186                     printf("ERROR: no number entered for %s=num\n", ARG_STACKLOC);
187                     exit(EXIT_FAILURE);
188                 }
189                 // extract number from "--stack-loc=0x70"
190                 pic14_options.stackLocation = strtol(argv[ *i ] + len + 1, NULL, 0);
191
192                 if (errno) {
193                     printf("ERROR: Could not parse number after %s=num\n", ARG_STACKLOC);
194                     exit(EXIT_FAILURE);
195                 }
196                 return 1;
197         }
198
199         len = strlen(ARG_STACKLOC);
200         if (!strncmp(ARG_STACKSIZ, argv[*i], len)) {
201                 if (argv[*i][len] != '=' || argv[*i][len+1] == 0) {
202                     printf("ERROR: no number entered for %s=num\n", ARG_STACKSIZ);
203                     exit(EXIT_FAILURE);
204                 }
205                 // extract number from "--stack-size=16"
206                 pic14_options.stackSize = strtol(argv[ *i ] + len + 1, NULL, 0);
207                 if (errno) {
208                     printf("ERROR: Could not parse number after %s=num\n", ARG_STACKLOC);
209                     exit(EXIT_FAILURE);
210                 }
211                 return 1;
212         }
213
214         return FALSE;
215 }
216
217 extern set *dataDirsSet;
218 extern set *includeDirsSet;
219 /* pic14 port uses include/pic and lib/pic instead of
220  * include/pic14 and lib/pic14 as indicated by SDCCmain.c's
221  * setIncludePaths routine. */
222 static void
223 _pic14_initPaths (void)
224 {
225   char *p;
226   char *p2=NULL;
227   set *tempSet=NULL;
228
229   if (options.nostdinc)
230       return;
231
232   tempSet = appendStrSet(dataDirsSet, NULL, INCLUDE_DIR_SUFFIX DIR_SEPARATOR_STRING "pic");
233   mergeSets(&includeDirsSet, tempSet);
234
235   if ((p = getenv(SDCC_INCLUDE_NAME)) != NULL)
236   {
237     addSetHead(&includeDirsSet, p);
238     p2=Safe_alloc(strlen(p)+strlen(DIR_SEPARATOR_STRING)+strlen("pic")+1);
239     if(p2!=NULL)
240     {
241         strcpy(p2, p);
242         strcat(p2, DIR_SEPARATOR_STRING);
243         strcat(p2, "pic");
244         addSetHead(&includeDirsSet, p2);
245     }
246   }
247 }
248
249 static void
250 _pic14_finaliseOptions (void)
251 {
252         pCodeInitRegisters();
253         
254         port->mem.default_local_map = data;
255         port->mem.default_globl_map = data;
256 #if 0
257         /* Hack-o-matic: if we are using the flat24 model,
258         * adjust pointer sizes.
259         */
260         if (options.model == MODEL_FLAT24)
261         {
262                 
263                 fprintf (stderr, "*** WARNING: you should use the '-mds390' option "
264                         "for DS80C390 support. This code generator is "
265                         "badly out of date and probably broken.\n");
266                 
267                 port->s.fptr_size = 3;
268                 port->s.gptr_size = 4;
269                 port->stack.isr_overhead++;     /* Will save dpx on ISR entry. */
270 #if 1
271                 port->stack.call_overhead++;    /* This acounts for the extra byte 
272                                                  * of return addres on the stack.
273                                                  * but is ugly. There must be a 
274                                                  * better way.
275                                                  */
276 #endif
277                 fReturn = fReturn390;
278                 fReturnSize = 5;
279         }
280         
281         if (options.model == MODEL_LARGE)
282         {
283                 port->mem.default_local_map = xdata;
284                 port->mem.default_globl_map = xdata;
285         }
286         else
287         {
288                 port->mem.default_local_map = data;
289                 port->mem.default_globl_map = data;
290         }
291         
292         if (options.stack10bit)
293         {
294                 if (options.model != MODEL_FLAT24)
295                 {
296                         fprintf (stderr,
297                                 "*** warning: 10 bit stack mode is only supported in flat24 model.\n");
298                         fprintf (stderr, "\t10 bit stack mode disabled.\n");
299                         options.stack10bit = 0;
300                 }
301                 else
302                 {
303                 /* Fixup the memory map for the stack; it is now in
304                 * far space and requires a FPOINTER to access it.
305                 */
306                         istack->fmap = 1;
307                         istack->ptrType = FPOINTER;
308                 }
309         }
310 #endif
311 }
312
313 static void
314 _pic14_setDefaultOptions (void)
315 {
316 }
317
318 static const char *
319 _pic14_getRegName (struct regs *reg)
320 {
321         if (reg)
322                 return reg->name;
323         return "err";
324 }
325
326 extern char *processor_base_name(void);
327
328 static void
329 _pic14_genAssemblerPreamble (FILE * of)
330 {
331         char * name = processor_base_name();
332         
333         if(!name) {
334                 
335                 name = "16f877";
336                 fprintf(stderr,"WARNING: No Pic has been selected, defaulting to %s\n",name);
337         }
338         
339         fprintf (of, "\tlist\tp=%s\n",name);
340         fprintf (of, "\tradix dec\n");
341         fprintf (of, "\tinclude \"p%s.inc\"\n",name);
342 }
343
344 /* Generate interrupt vector table. */
345 static int
346 _pic14_genIVT (FILE * of, symbol ** interrupts, int maxInterrupts)
347 {
348         int i;
349         
350         if (options.model != MODEL_FLAT24)
351         {
352                 /* Let the default code handle it. */
353                 return FALSE;
354         }
355         
356         fprintf (of, "\t;ajmp\t__sdcc_gsinit_startup\n");
357         
358         /* now for the other interrupts */
359         for (i = 0; i < maxInterrupts; i++)
360         {
361                 if (interrupts[i])
362                 {
363                         fprintf (of, "\t;ljmp\t%s\n\t.ds\t4\n", interrupts[i]->rname);
364                 }
365                 else
366                 {
367                         fprintf (of, "\t;reti\n\t.ds\t7\n");
368                 }
369         }
370         
371         return TRUE;
372 }
373
374 static bool
375 _hasNativeMulFor (iCode *ic, sym_link *left, sym_link *right)
376 {
377 /*
378 sym_link *test = NULL;
379 value *val;
380         */
381         
382         //fprintf(stderr,"checking for native mult\n");
383         
384         if ( ic->op != '*')
385         {
386                 return FALSE;
387         }
388         
389         /* multiply chars in-place */
390         if (getSize(left) == 1 && getSize(right) == 1)
391                 return TRUE;
392         
393         /* use library functions for more complex maths */
394         return FALSE;
395
396         /*
397         if ( IS_LITERAL (left))
398         {
399         fprintf(stderr,"left is lit\n");
400         test = left;
401         val = OP_VALUE (IC_LEFT (ic));
402         }
403         else if ( IS_LITERAL (right))
404         {
405         fprintf(stderr,"right is lit\n");
406         test = left;
407         val = OP_VALUE (IC_RIGHT (ic));
408         }
409         else
410         {
411         fprintf(stderr,"oops, neither is lit so no\n");
412         return FALSE;
413         }
414         
415           if ( getSize (test) <= 2)
416           {
417           fprintf(stderr,"yep\n");
418           return TRUE;
419           }
420           fprintf(stderr,"nope\n");
421           
422                 return FALSE;
423         */
424 }
425
426 /* Indicate which extended bit operations this port supports */
427 static bool
428 hasExtBitOp (int op, int size)
429 {
430         if (op == RRC
431                 || op == RLC
432                 /* || op == GETHBIT */ /* GETHBIT doesn't look complete for PIC */
433                 )
434                 return TRUE;
435         else
436                 return FALSE;
437 }
438
439 /* Indicate the expense of an access to an output storage class */
440 static int
441 oclsExpense (struct memmap *oclass)
442 {
443         /* The IN_FARSPACE test is compatible with historical behaviour, */
444         /* but I don't think it is applicable to PIC. If so, please feel */
445         /* free to remove this test -- EEP */
446         if (IN_FARSPACE(oclass))
447                 return 1;
448
449         return 0;
450 }
451
452 /** $1 is always the basename.
453 $2 is always the output file.
454 $3 varies
455 $l is the list of extra options that should be there somewhere...
456 MUST be terminated with a NULL.
457 */
458 static const char *_linkCmd[] =
459 {
460         "gplink", "$l", "-w", "-r", "-o \"$2\"", "\"$1\"", "$3", NULL
461 };
462
463 static const char *_asmCmd[] =
464 {
465         "gpasm", "$l", "-c", "\"$1.asm\"", NULL
466                 
467 };
468
469 extern set *libFilesSet;
470 extern set *libDirsSet;
471 extern set *libPathsSet;
472 extern set *includeDirsSet;
473 extern set *userIncDirsSet;
474 extern set *dataDirsSetSet;
475 extern set *relFilesSet;
476 extern set *linkOptionsSet;
477
478 static void _pic14_do_link (void)
479 {
480   hTab *linkValues=NULL;
481   char lfrm[256];
482   char *lcmd;
483   char temp[128];
484   set *tSet=NULL;
485   int ret;
486   char * procName;
487   
488   /*
489    * link command format:
490    * {linker} {incdirs} {lflags} -o {outfile} {spec_ofiles} {ofiles} {libs}
491    *
492    */
493
494   sprintf(lfrm, "{linker} {incdirs} {sysincdirs} {lflags} -w -r -o {outfile} {user_ofile} {spec_ofiles} {ofiles} {libs}");
495
496   shash_add(&linkValues, "linker", "gplink");
497
498   /* LIBRARY SEARCH DIRS */
499   mergeSets(&tSet, libPathsSet);
500   mergeSets(&tSet, libDirsSet);
501   shash_add(&linkValues, "incdirs", joinStrSet(appendStrSet(tSet, "-I\"", "\"")));
502
503   SNPRINTF (&temp[0], 128, "%cpic\"", DIR_SEPARATOR_CHAR);
504   joinStrSet(appendStrSet(libDirsSet, "-I\"", &temp[0]));
505   shash_add(&linkValues, "sysincdirs", joinStrSet(appendStrSet(libDirsSet, "-I\"", &temp[0])));
506   
507   shash_add(&linkValues, "lflags", joinStrSet(linkOptionsSet));
508
509   shash_add(&linkValues, "outfile", fullDstFileName ? fullDstFileName : dstFileName);
510
511   if(fullSrcFileName) {
512     sprintf(temp, "%s.o", fullDstFileName ? fullDstFileName : dstFileName );
513     shash_add(&linkValues, "user_ofile", temp);
514   }
515
516   shash_add(&linkValues, "ofiles", joinStrSet(relFilesSet));
517
518   /* LIBRARIES */
519   procName = processor_base_name();
520   if (!procName) {
521      procName = "16f877";
522   }
523         
524   addSet(&libFilesSet, "libsdcc.lib");
525   SNPRINTF(&temp[0], 128, "pic%s.lib", procName);
526   addSet(&libFilesSet, temp);
527   shash_add(&linkValues, "libs", joinStrSet(libFilesSet));
528
529   lcmd = msprintf(linkValues, lfrm);
530
531   ret = my_system( lcmd );
532
533   Safe_free( lcmd );
534
535   if(ret)
536     exit(1);
537 }
538
539 /* Globals */
540 PORT pic_port =
541 {
542         TARGET_ID_PIC,
543         "pic14",
544         "MCU pic",                      /* Target name */
545         "",                    /* Processor */
546         {
547                 picglue,
548                 TRUE,                   /* Emit glue around main */
549                 MODEL_SMALL | MODEL_LARGE | MODEL_FLAT24,
550                 MODEL_SMALL
551         },
552         {
553                 _asmCmd,
554                 NULL,
555                 NULL,
556                 NULL,
557                 //"-plosgffc",          /* Options with debug */
558                 //"-plosgff",           /* Options without debug */
559                 0,
560                 ".asm",
561                 NULL                    /* no do_assemble function */
562         },
563         {
564                 _linkCmd,
565                 NULL,
566                 _pic14_do_link,         /* own do link function */
567                 ".o",
568                 0
569         },
570         {
571                 _defaultRules
572         },
573         {
574                 /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
575                 1, 2, 2, 4, 2, 2, 3, 1, 4, 4
576                 /* TSD - I changed the size of gptr from 3 to 1. However, it should be
577                    2 so that we can accomodate the PIC's with 4 register banks (like the
578                    16f877)
579                  */
580         },
581         /* tags for generic pointers */
582         { 0x00, 0x00, 0x00, 0x80 },             /* far, near, xstack, code */
583         {
584                 "XSEG    (XDATA)",
585                 "STACK   (DATA)",
586                 "code",
587                 "DSEG    (DATA)",
588                 "ISEG    (DATA)",
589                 NULL, /* pdata */
590                 "XSEG    (XDATA)",
591                 "BSEG    (BIT)",
592                 "RSEG    (DATA)",
593                 "GSINIT  (CODE)",
594                 "udata_ovr",
595                 "GSFINAL (CODE)",
596                 "HOME    (CODE)",
597                 NULL, // xidata
598                 NULL, // xinit
599                 "CONST   (CODE)",               // const_name - const data (code or not)
600                 "CABS    (ABS,CODE)",   // cabs_name - const absolute data (code or not)
601                 NULL,
602                 NULL,
603                 1        // code is read only
604         },
605         { NULL, NULL },
606         {
607                 +1, 1, 4, 1, 1, 0
608         },
609                 /* pic14 has an 8 bit mul */
610         {
611                 1, -1
612         },
613         {
614                 pic14_emitDebuggerSymbol
615         },
616         {
617                 255/3,      /* maxCount */
618                 3,          /* sizeofElement */
619                 /* The rest of these costs are bogus. They approximate */
620                 /* the behavior of src/SDCCicode.c 1.207 and earlier.  */
621                 {4,4,4},    /* sizeofMatchJump[] */
622                 {0,0,0},    /* sizeofRangeCompare[] */
623                 0,          /* sizeofSubtract */
624                 3,          /* sizeofDispatch */
625         },
626         "_",
627         _pic14_init,
628         _pic14_parseOptions,
629         _pic14_poptions,
630         _pic14_initPaths,
631         _pic14_finaliseOptions,
632         _pic14_setDefaultOptions,
633         pic14_assignRegisters,
634         _pic14_getRegName,
635         _pic14_keywords,
636         _pic14_genAssemblerPreamble,
637         NULL,                           /* no genAssemblerEnd */
638         _pic14_genIVT,
639         NULL, // _pic14_genXINIT
640         NULL,                           /* genInitStartup */
641         _pic14_reset_regparm,
642         _pic14_regparm,
643         _process_pragma,                                /* process a pragma */
644         NULL,
645         _hasNativeMulFor,
646         hasExtBitOp,                    /* hasExtBitOp */
647         oclsExpense,                    /* oclsExpense */
648         FALSE,
649 //      TRUE,                           /* little endian */
650         FALSE,                          /* little endian - PIC code enumlates big endian */
651         0,                              /* leave lt */
652         0,                              /* leave gt */
653         1,                              /* transform <= to ! > */
654         1,                              /* transform >= to ! < */
655         1,                              /* transform != to !(a == b) */
656         0,                              /* leave == */
657         FALSE,                        /* No array initializer support. */
658         0,                            /* no CSE cost estimation yet */
659         NULL,                   /* no builtin functions */
660         GPOINTER,                       /* treat unqualified pointers as "generic" pointers */
661         1,                              /* reset labelKey to 1 */
662         1,                              /* globals & local static allowed */
663         PORT_MAGIC
664 };