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