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