1 /*-------------------------------------------------------------------------
2 
3   main.c - pic16 specific general functions.
4 
5    Written by - Scott Dattalo scott@dattalo.com
6    Ported to PIC16 by - Martin Dubuc m.debuc@rogers.com
7 
8    Note that mlh prepended _pic16_ on the static functions.  Makes
9    it easier to set a breakpoint using the debugger.
10 
11 
12    This program is free software; you can redistribute it and/or modify it
13    under the terms of the GNU General Public License as published by the
14    Free Software Foundation; either version 2, or (at your option) any
15    later version.
16 
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20    GNU General Public License for more details.
21 
22    You should have received a copy of the GNU General Public License
23    along with this program; if not, write to the Free Software
24    Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 -------------------------------------------------------------------------*/
26 
27 #include "common.h"
28 #include "dbuf_string.h"
29 
30 #include "main.h"
31 #include "ralloc.h"
32 #include "device.h"
33 #include "glue.h"
34 #include "pcode.h"
35 #include "SDCCargs.h"
36 #include "dbuf_string.h"
37 
38 
39 static char _defaultRules[] =
40 {
41 #include "peeph.rul"
42 };
43 
44 /* list of key words used by pic16 */
45 static char *_pic16_keywords[] =
46 {
47   "at",
48   "code",
49   "critical",
50   "register",
51   "data",
52   "far",
53   "interrupt",
54   "near",
55   //"pdata",
56   "reentrant",
57   "sfr",
58   "sfr16",
59   "using",
60   "_data",
61   "_code",
62   "_generic",
63   "_near",
64   //"_pdata",
65   "_naked",
66   "shadowregs",
67   "wparam",
68   "prodlp",
69   "prodhp",
70   "fsr0lp",
71   "fixed16x16",
72 
73 //  "bit",
74 //  "idata",
75 //  "sbit",
76 //  "xdata",
77 //  "_xdata",
78 //  "_idata",
79   NULL
80 };
81 
82 
83 pic16_sectioninfo_t pic16_sectioninfo;
84 int has_xinst_config = 0;
85 
86 static int regParmFlg = 0;  /* determine if we can register a parameter */
87 
88 pic16_options_t pic16_options;
89 pic16_config_options_t *pic16_config_options;
90 
91 extern set *includeDirsSet;
92 extern set *dataDirsSet;
93 extern set *libFilesSet;
94 
95 /* Also defined in gen.h, but the #include is commented out */
96 /* for an unknowned reason. - EEP */
97 void pic16_emitDebuggerSymbol (const char *);
98 
99 extern void pic16_emitConfigRegs (FILE *of);
100 extern void pic16_emitIDRegs (FILE *of);
101 
102 
103 static void
_pic16_init(void)104 _pic16_init (void)
105 {
106   asm_addTree (&asm_asxxxx_mapping);
107   pic16_pCodeInitRegisters();
108   maxInterrupts = 2;
109   memset(&pic16_options, 0, sizeof(pic16_options));
110 }
111 
112 static void
_pic16_reset_regparm(struct sym_link * funcType)113 _pic16_reset_regparm (struct sym_link *funcType)
114 {
115   regParmFlg = 0;
116 }
117 
118 static int
_pic16_regparm(sym_link * l,bool reentrant)119 _pic16_regparm (sym_link * l, bool reentrant)
120 {
121   /* force all parameters via SEND/RECEIVE */
122   if(0 /*pic16_options.ip_stack*/) {
123     /* for this processor it is simple
124      * can pass only the first parameter in a register */
125     if(regParmFlg)return 0;
126       regParmFlg++;
127       return 1; //regParmFlg;
128   } else {
129     /* otherwise pass all arguments in registers via SEND/RECEIVE */
130     regParmFlg++;// = 1;
131     return regParmFlg;
132   }
133 }
134 
135 
136 int initsfpnt=0;        /* set to 1 if source provides a pragma for stack
137                          * so glue() later emits code to initialize stack/frame pointers */
138 set *absSymSet;
139 
140 set *sectNames=NULL;    /* list of section listed in pragma directives */
141 set *sectSyms=NULL;     /* list of symbols set in a specific section */
142 set *wparamList=NULL;
143 
144 #if 0
145 /* This is an experimental code for #pragma inline
146    and is temporarily disabled for 2.5.0 release */
147 set *asmInlineMap=NULL;
148 #endif  /* 0 */
149 
150 struct {
151   unsigned ignore: 1;
152   unsigned want_libc: 1;
153   unsigned want_libm: 1;
154   unsigned want_libio: 1;
155   unsigned want_libdebug: 1;
156 } libflags = { 0, 0, 0, 0, 0 };
157 
158 
159 enum {
160   P_STACK = 1,
161   P_CODE,
162   P_UDATA,
163   P_LIBRARY,
164   P_CONFIG
165 };
166 
167 static int
do_pragma(int id,const char * name,const char * cp)168 do_pragma (int id, const char *name, const char *cp)
169 {
170   struct pragma_token_s token;
171   int err = 0;
172   int processed = 1;
173 
174   init_pragma_token(&token);
175 
176   switch (id)
177     {
178     /* #pragma stack [stack-position] [stack-len] */
179     case  P_STACK:
180       {
181         unsigned int stackPos, stackLen;
182         reg_info *reg;
183         symbol *sym;
184 
185         cp = get_pragma_token (cp, &token);
186         if (TOKEN_INT != token.type)
187           {
188             err = 1;
189             break;
190           }
191         stackPos = token.val.int_val;
192 
193         cp = get_pragma_token (cp, &token);
194         if (TOKEN_INT != token.type)
195           {
196             err = 1;
197             break;
198           }
199         stackLen = token.val.int_val;
200 
201         cp = get_pragma_token (cp, &token);
202         if (TOKEN_EOL != token.type)
203           {
204             err = 1;
205             break;
206           }
207 
208         if (stackLen < 1) {
209           stackLen = 64;
210           fprintf (stderr, "%s:%d: warning: setting stack to default size %d (0x%04x)\n",
211                   filename, lineno, stackLen, stackLen);
212         }
213 
214         /* check sanity of stack */
215         if ((stackPos >> 8) != ((stackPos + stackLen - 1) >> 8)) {
216           fprintf (stderr, "%s:%u: warning: stack [0x%03X,0x%03X] crosses memory bank boundaries (not fully tested)\n",
217                   filename, lineno, stackPos, stackPos + stackLen - 1);
218         }
219 
220         if (pic16) {
221           if (stackPos < pic16->acsSplitOfs) {
222             fprintf (stderr, "%s:%u: warning: stack [0x%03X, 0x%03X] intersects with the access bank [0x000,0x%03x] -- this is highly discouraged!\n",
223                   filename, lineno, stackPos, stackPos + stackLen - 1, pic16->acsSplitOfs);
224           }
225 
226           if (stackPos+stackLen > 0xF00 + pic16->acsSplitOfs) {
227             fprintf (stderr, "%s:%u: warning: stack [0x%03X,0x%03X] intersects with special function registers [0x%03X,0xFFF]-- this is highly discouraged!\n",
228                    filename, lineno, stackPos, stackPos + stackLen - 1, 0xF00 + pic16->acsSplitOfs);
229           }
230 
231           if (stackPos+stackLen > pic16->RAMsize) {
232             fprintf (stderr, "%s:%u: error: stack [0x%03X,0x%03X] is placed outside available memory [0x000,0x%03X]!\n",
233                   filename, lineno, stackPos, stackPos + stackLen - 1, pic16->RAMsize-1);
234             err = 1;
235             break;
236           }
237         }
238 
239         reg = newReg (REG_SFR, PO_SFR_REGISTER, stackPos, "_stack", stackLen-1, 0, NULL);
240         addSet (&pic16_fix_udata, reg);
241 
242         reg = newReg (REG_SFR, PO_SFR_REGISTER, stackPos + stackLen-1, "_stack_end", 1, 0, NULL);
243         addSet (&pic16_fix_udata, reg);
244 
245         sym = newSymbol ("stack", 0);
246         SNPRINTF(sym->rname, sizeof(sym->rname), "_%s", sym->name);
247         addSet (&publics, sym);
248 
249         sym = newSymbol ("stack_end", 0);
250         SNPRINTF(sym->rname, sizeof(sym->rname), "_%s", sym->name);
251         addSet (&publics, sym);
252 
253         initsfpnt = 1;    // force glue() to initialize stack/frame pointers */
254       }
255       break;
256 
257     /* #pragma code [symbol] [location] */
258     case P_CODE:
259       {
260         absSym *absS;
261 
262         cp = get_pragma_token (cp, &token);
263         if (TOKEN_STR != token.type)
264           goto code_err;
265 
266         absS = Safe_alloc(sizeof(absSym));
267         SNPRINTF(absS->name, sizeof(absS->name), "_%s", get_pragma_string(&token));
268 
269         cp = get_pragma_token (cp, &token);
270         if (TOKEN_INT != token.type)
271           {
272           code_err:
273             //fprintf (stderr, "%s:%d: #pragma code [symbol] [location] -- symbol or location missing\n", filename, lineno);
274             err = 1;
275             break;
276           }
277         absS->address = token.val.int_val;
278 
279         cp = get_pragma_token (cp, &token);
280         if (TOKEN_EOL != token.type)
281           {
282             err = 1;
283             break;
284           }
285 
286         if ((absS->address % 2) != 0) {
287           absS->address--;
288           fprintf (stderr, "%s:%d: warning: code memory locations should be word aligned, will locate to 0x%06x instead\n",
289                    filename, lineno, absS->address);
290         }
291 
292         addSet (&absSymSet, absS);
293 //      fprintf(stderr, "%s:%d symbol %s will be placed in location 0x%06x in code memory\n",
294 //        __FILE__, __LINE__, symname, absS->address);
295       }
296       break;
297 
298     /* #pragma udata [section-name] [symbol] */
299     case P_UDATA:
300       {
301         char *sectname;
302         const char *symname;
303         symbol *nsym;
304         sectSym *ssym;
305         sectName *snam;
306         int found = 0;
307 
308         cp = get_pragma_token (cp, &token);
309         if (TOKEN_STR == token.type)
310           sectname = Safe_strdup (get_pragma_string (&token));
311         else
312           {
313             err = 1;
314             break;
315           }
316 
317         cp = get_pragma_token (cp, &token);
318         if (TOKEN_STR == token.type)
319           symname = get_pragma_string (&token);
320         else
321           {
322             //fprintf (stderr, "%s:%d: #pragma udata [section-name] [symbol] -- section-name or symbol missing!\n", filename, lineno);
323             err = 1;
324             symname = NULL;
325           }
326 
327         while (symname)
328           {
329             size_t len = strlen(symname) + 2;
330 
331             ssym = Safe_alloc(sizeof(sectSym));
332             ssym->name = Safe_alloc(len);
333             SNPRINTF(ssym->name, len, "%s%s", port->fun_prefix, symname);
334             ssym->reg = NULL;
335 
336             addSet (&sectSyms, ssym);
337 
338             nsym = newSymbol ((char *)symname, 0);
339             strcpy(nsym->rname, ssym->name);
340 
341 #if 0
342             checkAddSym (&publics, nsym);
343 #endif
344 
345             found = 0;
346             for (snam = setFirstItem (sectNames); snam; snam = setNextItem (sectNames))
347               {
348                 if (!strcmp (sectname, snam->name))
349                   {
350                     found=1;
351                     break;
352                   }
353               }
354 
355             if(!found)
356               {
357                 snam = Safe_alloc(sizeof(sectName));
358                 snam->name = Safe_strdup (sectname);
359                 snam->regsSet = NULL;
360 
361                 addSet (&sectNames, snam);
362               }
363 
364             ssym->section = snam;
365 
366 #if 0
367             fprintf (stderr, "%s:%d placing symbol %s at section %s (%p)\n", __FILE__, __LINE__,
368                      ssym->name, snam->name, snam);
369 #endif
370 
371             cp = get_pragma_token (cp, &token);
372             if (TOKEN_STR == token.type)
373               symname = get_pragma_string (&token);
374             else if (TOKEN_EOL == token.type)
375               symname = NULL;
376             else
377               {
378                 err = 1;
379                 symname = NULL;
380               }
381           }
382 
383           Safe_free (sectname);
384       }
385       break;
386 
387     /* #pragma library library_module */
388     case P_LIBRARY:
389       {
390         const char *lmodule;
391 
392         cp = get_pragma_token (cp, &token);
393         if (TOKEN_EOL != token.type)
394           {
395             lmodule = get_pragma_string (&token);
396 
397             /* lmodule can be:
398              * c    link the C library
399              * math link the math library
400              * io   link the IO library
401              * debug    link the debug libary
402              * anything else, will link as-is */
403 
404             if(!strcmp (lmodule, "c"))
405               libflags.want_libc = 1;
406             else if(!strcmp (lmodule, "math"))
407               libflags.want_libm = 1;
408             else if(!strcmp (lmodule, "io"))
409               libflags.want_libio = 1;
410             else if(!strcmp (lmodule, "debug"))
411               libflags.want_libdebug = 1;
412             else if(!strcmp (lmodule, "ignore"))
413               libflags.ignore = 1;
414             else
415               {
416                 if(!libflags.ignore)
417                   {
418                     fprintf (stderr, "link library %s\n", lmodule);
419                     addSetHead (&libFilesSet, (char *)lmodule);
420                   }
421               }
422           }
423         else
424           {
425             err = 1;
426             break;
427           }
428 
429         cp = get_pragma_token (cp, &token);
430         if (TOKEN_EOL != token.type)
431           {
432             err = 1;
433             break;
434           }
435       }
436       break;
437 
438     case P_CONFIG:
439       {
440         const char *begin;
441         struct dbuf_s dbuf;
442         bool first = TRUE;
443 
444         token.type = TOKEN_EOL; /* just to make the final error test happy */
445 
446         dbuf_init (&dbuf, 128);
447         dbuf_append_str (&dbuf, "CONFIG\t");
448 
449         do
450           {
451             int isXINST = 0;
452 
453             if (first)
454               first = FALSE;
455             else
456               {
457                 if (',' == *cp)
458                   ++cp;
459                 else
460                   goto error;
461 
462                 dbuf_append_char (&dbuf, ',');
463               }
464 
465 
466             while (isspace (*cp))
467               ++cp;
468 
469             if (*cp == '_' || isalpha (*cp))
470               {
471                 begin = cp++;
472                 while (*cp == '_' || isalnum (*cp))
473                   ++cp;
474                 if ((5 == (cp - begin)) && (0 == strncmp("XINST", begin, 5)))
475                   {
476                     /* Keep warning if we have XINST=ON ... */
477                     isXINST = 1;
478                   } // if
479                 dbuf_append (&dbuf, begin, cp - begin);
480               }
481             else
482               goto error;
483 
484             while (isspace (*cp))
485               ++cp;
486 
487             if ('=' == *cp)
488               dbuf_append_char (&dbuf, *cp++);
489             else
490               goto error;
491 
492             while (isspace (*cp))
493               ++cp;
494 
495             if (*cp == '_' || isalnum (*cp))
496               {
497                 begin = cp++;
498                 while (*cp == '_' || isalnum (*cp))
499                   ++cp;
500                 if (isXINST && (3 == cp - begin) && (0 == strncmp("OFF", begin, 3)))
501                   {
502                     /* Suppress warning in glue.c if #pragma config XINST=OFF is present. */
503                     has_xinst_config = 1;
504                   } // if
505                 dbuf_append (&dbuf, begin, cp - begin);
506               }
507             else
508               goto error;
509 
510             while (isspace (*cp))
511               ++cp;
512           }
513         while ('\0' != *cp);
514 
515         /* append to the config options list */
516         if (!pic16_config_options)
517           {
518             pic16_config_options = malloc (sizeof (pic16_config_options_t));
519             memset (pic16_config_options, 0, sizeof (pic16_config_options_t));
520             pic16_config_options->config_str = dbuf_detach_c_str (&dbuf);
521           }
522         else
523           {
524             pic16_config_options_t *p;
525 
526             for (p = pic16_config_options; p->next; p = p->next)
527               ;
528             p->next = malloc (sizeof (pic16_config_options_t));
529             memset (p->next, 0, sizeof (pic16_config_options_t));
530             p->next->config_str = dbuf_detach_c_str (&dbuf);
531           }
532         break;
533 
534       error:
535         dbuf_destroy(&dbuf);
536         err = 1;
537       }
538       break;
539 
540 #if 0
541   /* This is an experimental code for #pragma inline
542      and is temporarily disabled for 2.5.0 release */
543     case P_INLINE:
544       {
545         char *tmp = strtok ((char *)NULL, WHITECOMMA);
546 
547         while (tmp)
548           {
549             addSet (&asmInlineMap, Safe_strdup ( tmp ));
550             tmp = strtok ((char *)NULL, WHITECOMMA);
551           }
552 
553           {
554             char *s;
555 
556             for (s = setFirstItem (asmInlineMap); s ; s = setNextItem (asmInlineMap))
557               {
558                 debugf ("inline asm: `%s'\n", s);
559               }
560           }
561       }
562       break;
563 #endif  /* 0 */
564 
565     default:
566       processed = 0;
567       break;
568   }
569 
570   get_pragma_token (cp, &token);
571 
572   if (1 == err || token.type != TOKEN_EOL)
573     werror (W_BAD_PRAGMA_ARGUMENTS, name);
574 
575   free_pragma_token (&token);
576   return processed;
577 }
578 
579 static struct pragma_s pragma_tbl[] = {
580   { "stack",   P_STACK,   0, do_pragma },
581   { "code",    P_CODE,    0, do_pragma },
582   { "udata",   P_UDATA,   0, do_pragma },
583   { "library", P_LIBRARY, 0, do_pragma },
584   { "config",  P_CONFIG,  0, do_pragma },
585 /*{ "inline",  P_INLINE,  0, do_pragma }, */
586   { NULL,      0,         0, NULL },
587   };
588 
589 static int
_process_pragma(const char * s)590 _process_pragma (const char *s)
591 {
592   return process_pragma_tbl(pragma_tbl, s);
593 }
594 
595 #define REP_UDATA         "--preplace-udata-with="
596 
597 #define STACK_MODEL       "--pstack-model="
598 #define OPT_BANKSEL       "--obanksel="
599 
600 #define ALT_ASM           "--asm="
601 #define ALT_LINK          "--link="
602 
603 #define IVT_LOC           "--ivt-loc="
604 #define NO_DEFLIBS        "--nodefaultlibs"
605 #define MPLAB_COMPAT      "--mplab-comp"
606 
607 #define USE_CRT           "--use-crt="
608 
609 #define OFMSG_LRSUPPORT   "--flr-support"
610 
611 #define NO_OPTIMIZE_GOTO  "--no-optimize-goto"
612 #define OPTIMIZE_CMP      "--optimize-cmp"
613 #define OPTIMIZE_DF       "--optimize-df"
614 
615 char *alt_asm = NULL;
616 char *alt_link = NULL;
617 
618 int pic16_mplab_comp = 0;
619 extern int pic16_debug_verbose;
620 extern int pic16_ralloc_debug;
621 extern int pic16_pcode_verbose;
622 
623 int pic16_enable_peeps = 0;
624 
625 OPTION pic16_optionsTable[]= {
626     /* code generation options */
627     { 0, STACK_MODEL,           NULL, "use stack model 'small' (default) or 'large'"},
628 #if XINST
629     { 'y', "--extended",        &pic16_options.xinst, "enable Extended Instruction Set/Literal Offset Addressing mode"},
630 #endif
631     { 0, "--pno-banksel",       &pic16_options.no_banksel, "do not generate BANKSEL assembler directives"},
632 
633     /* optimization options */
634     { 0, OPT_BANKSEL,           &pic16_options.opt_banksel, "set banksel optimization level (default=0 no)", CLAT_INTEGER },
635     { 0, "--denable-peeps",     &pic16_enable_peeps, "explicit enable of peepholes"},
636     { 0, NO_OPTIMIZE_GOTO,      NULL, "do NOT use (conditional) BRA instead of GOTO"},
637     { 0, OPTIMIZE_CMP,          NULL, "try to optimize some compares"},
638     { 0, OPTIMIZE_DF,           NULL, "thoroughly analyze data flow (memory and time intensive!)"},
639 
640     /* assembling options */
641     { 0, ALT_ASM,               &alt_asm, "Use alternative assembler", CLAT_STRING},
642     { 0, MPLAB_COMPAT,          &pic16_mplab_comp, "enable compatibility mode for MPLAB utilities (MPASM/MPLINK)"},
643 
644     /* linking options */
645     { 0, ALT_LINK,              &alt_link, "Use alternative linker", CLAT_STRING },
646     { 0, REP_UDATA,             &pic16_sectioninfo.at_udata, "Place udata variables at another section: udata_acs, udata_ovr, udata_shr", CLAT_STRING },
647     { 0, IVT_LOC,               NULL, "Set address of interrupt vector table."},
648     { 0, NO_DEFLIBS,            &pic16_options.nodefaultlibs,   "do not link default libraries when linking"},
649     { 0, USE_CRT,               NULL, "use <crt-o> run-time initialization module"},
650     { 0, "--no-crt",            &pic16_options.no_crt, "do not link any default run-time initialization module"},
651 
652     /* debugging options */
653     { 0, "--debug-xtra",        &pic16_debug_verbose, "show more debug info in assembly output"},
654     { 0, "--debug-ralloc",      &pic16_ralloc_debug, "dump register allocator debug file *.d"},
655     { 0, "--pcode-verbose",     &pic16_pcode_verbose, "dump pcode related info"},
656     { 0, "--calltree",          &pic16_options.dumpcalltree, "dump call tree in .calltree file"},
657     { 0, "--gstack",            &pic16_options.gstack, "trace stack pointer push/pop to overflow"},
658     { 0, "--no-warn-non-free",  &pic16_options.no_warn_non_free, "suppress warning on absent --use-non-free option" },
659     { 0, NULL,                  NULL, NULL}
660 };
661 
662 
663 #define ISOPT(str)  !strncmp(argv[ *i ], str, strlen(str) )
664 
665 static bool
_pic16_parseOptions(int * pargc,char ** argv,int * i)666 _pic16_parseOptions (int *pargc, char **argv, int *i)
667 {
668   int j=0;
669   char *stkmodel;
670 
671   /* TODO: allow port-specific command line options to specify
672    * segment names here.
673    */
674 
675     /* check for arguments that have associated an integer variable */
676     while(pic16_optionsTable[j].pparameter) {
677       if(ISOPT( pic16_optionsTable[j].longOpt )) {
678         (*(int *)pic16_optionsTable[j].pparameter)++;
679         return TRUE;
680       }
681       j++;
682     }
683 
684     if(ISOPT(STACK_MODEL)) {
685       stkmodel = getStringArg(STACK_MODEL, argv, i, *pargc);
686       if(!STRCASECMP(stkmodel, "small"))pic16_options.stack_model = 0;
687       else if(!STRCASECMP(stkmodel, "large"))pic16_options.stack_model = 1;
688       else {
689         fprintf(stderr, "Unknown stack model: %s", stkmodel);
690         exit(EXIT_FAILURE);
691       }
692       return TRUE;
693     }
694 
695     if(ISOPT(IVT_LOC)) {
696       pic16_options.ivt_loc = getIntArg(IVT_LOC, argv, i, *pargc);
697       fprintf(stderr, "%s:%d setting interrupt vector addresses 0x%x\n", __FILE__, __LINE__, pic16_options.ivt_loc);
698       return TRUE;
699     }
700 
701     if(ISOPT(USE_CRT)) {
702       pic16_options.no_crt = 0;
703       pic16_options.crt_name = Safe_strdup( getStringArg(USE_CRT, argv, i, *pargc) );
704 
705       return TRUE;
706     }
707 
708 #if 0
709     if(ISOPT(OFMSG_LRSUPPORT)) {
710       pic16_options.opt_flags |= OF_LR_SUPPORT;
711       return TRUE;
712     }
713 #endif
714 
715     if (ISOPT(NO_OPTIMIZE_GOTO)) {
716       pic16_options.opt_flags |= OF_NO_OPTIMIZE_GOTO;
717       return TRUE;
718     }
719 
720     if(ISOPT(OPTIMIZE_CMP)) {
721       pic16_options.opt_flags |= OF_OPTIMIZE_CMP;
722       return TRUE;
723     }
724 
725     if (ISOPT(OPTIMIZE_DF)) {
726       pic16_options.opt_flags |= OF_OPTIMIZE_DF;
727       return TRUE;
728     }
729 
730 
731   return FALSE;
732 }
733 
734 extern void pic16_init_pic(const char *name);
735 
736 static void
_pic16_initPaths(void)737 _pic16_initPaths (void)
738 {
739   pic16_init_pic(port->processor);
740 }
741 
742 extern set *linkOptionsSet;
743 char *msprintf(hTab *pvals, const char *pformat, ...);
744 
745 /* forward declarations */
746 extern const char *pic16_linkCmd[];
747 extern const char *pic16_asmCmd[];
748 extern set *asmOptionsSet;
749 
750 /* custom function to link objects */
751 static void
_pic16_linkEdit(void)752 _pic16_linkEdit (void)
753 {
754   /*
755    * link command format:
756    * {linker} {incdirs} {lflags} -o {outfile} {spec_ofiles} {ofiles} {libs}
757    *
758    */
759 #define LFRM  "{linker} {incdirs} {lflags} -w -r -o {outfile} {user_ofile} {ofiles} {spec_ofiles} {libs}"
760   hTab *linkValues = NULL;
761   char *lcmd;
762   set *tSet = NULL;
763   int ret;
764 
765   shash_add (&linkValues, "linker", pic16_linkCmd[0]);
766 
767   mergeSets (&tSet, libPathsSet);
768   mergeSets (&tSet, libDirsSet);
769 
770   shash_add (&linkValues, "incdirs", joinStrSet (processStrSet(tSet, "-I", NULL, shell_escape)));
771   shash_add (&linkValues, "lflags", joinStrSet (linkOptionsSet));
772 
773   {
774     char *s = shell_escape (fullDstFileName ? fullDstFileName : dstFileName);
775 
776     shash_add (&linkValues, "outfile", s);
777     Safe_free (s);
778   }
779 
780   if (fullSrcFileName)
781     {
782       struct dbuf_s dbuf;
783       char *s;
784 
785       dbuf_init (&dbuf, 128);
786 
787       dbuf_append_str (&dbuf, fullDstFileName ? fullDstFileName : dstFileName);
788       dbuf_append (&dbuf, ".o", 2);
789       s = shell_escape (dbuf_c_str (&dbuf));
790       dbuf_destroy (&dbuf);
791       shash_add (&linkValues, "user_ofile", s);
792       Safe_free (s);
793     }
794 
795   if (!pic16_options.no_crt)
796     {
797       char *s = shell_escape (pic16_options.crt_name);
798 
799       shash_add (&linkValues, "spec_ofiles", s);
800       Safe_free (s);
801     }
802 
803   shash_add (&linkValues, "ofiles", joinStrSet (processStrSet (relFilesSet, NULL, NULL, shell_escape)));
804 
805   if (!libflags.ignore)
806     {
807       if (libflags.want_libc)
808         addSet (&libFilesSet, Safe_strdup ("libc18f.lib"));
809 
810       if (libflags.want_libm)
811         addSet (&libFilesSet, Safe_strdup ("libm18f.lib"));
812 
813       if (libflags.want_libio)
814         {
815           /* build libio18f452.lib name */
816           struct dbuf_s dbuf;
817 
818           dbuf_init (&dbuf, 128);
819 
820           dbuf_append (&dbuf, "libio", sizeof ("libio") - 1);
821           dbuf_append_str (&dbuf, pic16->name[1]);
822           dbuf_append (&dbuf, ".lib", sizeof (".lib") - 1);
823           addSet (&libFilesSet, dbuf_detach_c_str (&dbuf));
824         }
825 
826       if (libflags.want_libdebug)
827         addSet(&libFilesSet, Safe_strdup ("libdebug.lib"));
828     }
829 
830   shash_add (&linkValues, "libs", joinStrSet (processStrSet (libFilesSet, NULL, NULL, shell_escape)));
831 
832   lcmd = msprintf(linkValues, LFRM);
833   ret = sdcc_system (lcmd);
834   Safe_free (lcmd);
835 
836   if (ret)
837       exit (1);
838 }
839 
840 
841 static void
_pic16_finaliseOptions(void)842 _pic16_finaliseOptions (void)
843 {
844   struct dbuf_s dbuf;
845 
846   port->mem.default_local_map = data;
847   port->mem.default_globl_map = data;
848 
849   /* peepholes are disabled for the time being */
850   options.nopeep = 1;
851 
852   /* explicit enable peepholes for testing */
853   if (pic16_enable_peeps)
854     options.nopeep = 0;
855 
856   options.all_callee_saves = 1;       // always callee saves
857 
858 #if 0
859   options.float_rent = 1;
860   options.intlong_rent = 1;
861 #endif
862 
863   dbuf_init (&dbuf, 128);
864 
865   dbuf_set_length (&dbuf, 0);
866   dbuf_append (&dbuf, "-D__", sizeof ("-D__") - 1);
867   dbuf_append_str (&dbuf, pic16->name[1]);
868   addSet (&preArgvSet, Safe_strdup (dbuf_c_str (&dbuf)));
869 
870     {
871       char *upperProc, *p1, *p2;
872       int len;
873 
874       dbuf_set_length (&dbuf, 0);
875       len = strlen (port->processor);
876       upperProc = Safe_malloc (len);
877       for (p1 = port->processor, p2 = upperProc; *p1; ++p1, ++p2)
878         {
879           *p2 = toupper (*p1);
880         }
881       dbuf_append (&dbuf, "-D__SDCC_PIC", sizeof ("-D__SDCC_PIC") - 1);
882       dbuf_append (&dbuf, upperProc, len);
883       addSet (&preArgvSet, dbuf_detach_c_str (&dbuf));
884     }
885   if (!pic16_options.nodefaultlibs)
886     {
887       /* now add the library for the device */
888       dbuf_set_length (&dbuf, 0);
889       dbuf_printf (&dbuf, "libdev%s.lib", pic16->name[1]);   /* e.g., libdev18f452.lib */
890       addSet (&libFilesSet, Safe_strdup (dbuf_c_str (&dbuf)));
891 
892       /* add the internal SDCC library */
893       addSet (&libFilesSet, Safe_strdup ("libsdcc.lib" ));
894     }
895 
896   if (alt_asm && alt_asm[0] != '\0')
897     {
898       pic16_asmCmd[0] = alt_asm;
899     }
900 
901   if (alt_link && alt_link[0] != '\0')
902     {
903       pic16_linkCmd[0] = alt_link;
904     }
905 
906   if (!pic16_options.no_crt)
907     {
908       pic16_options.omit_ivt = 1;
909       pic16_options.leave_reset = 0;
910     }
911 
912   if (options.model == MODEL_SMALL)
913     {
914       addSet (&asmOptionsSet, Safe_strdup ("-DSDCC_MODEL_SMALL"));
915     }
916   else if (options.model == MODEL_LARGE)
917     {
918       char *s, *p;
919 
920       addSet (&asmOptionsSet, Safe_strdup ("-DSDCC_MODEL_LARGE"));
921 
922       dbuf_printf (&dbuf, "-D%s -D__%s", pic16->name[2], pic16->name[1]);
923       s = Safe_strdup (dbuf_c_str (&dbuf));
924       /* TODO: borut - why only the first 'f' is converted to upper case?
925        * What if there is an other letter instead 'f'?
926        */
927       if (NULL != (p = strrchr (s, 'f')))
928         *p = 'F';
929       addSet (&asmOptionsSet, s);
930     }
931 
932   if (STACK_MODEL_LARGE)
933     {
934       addSet (&preArgvSet, Safe_strdup ("-D__STACK_MODEL_LARGE"));
935       addSet (&asmOptionsSet, Safe_strdup ("-D__STACK_MODEL_LARGE"));
936     }
937   else
938     {
939       addSet (&preArgvSet, Safe_strdup ("-D__STACK_MODEL_SMALL"));
940       addSet (&asmOptionsSet, Safe_strdup ("-D__STACK_MODEL_SMALL"));
941     }
942 
943   if (!pic16_options.no_warn_non_free && !options.use_non_free)
944     {
945       fprintf(stderr,
946               "WARNING: Command line option --use-non-free not present.\n"
947               "         When compiling for PIC14/PIC16, please provide --use-non-free\n"
948               "         to get access to device headers and libraries.\n"
949               "         If you do not use these, you may provide --no-warn-non-free\n"
950               "         to suppress this warning (not recommended).\n");
951     } // if
952 
953   dbuf_destroy (&dbuf);
954 }
955 
956 
957 static void
_pic16_setDefaultOptions(void)958 _pic16_setDefaultOptions (void)
959 {
960   options.stackAuto = 0;        /* implicit declaration */
961   /* port is not capable yet to allocate separate registers
962    * dedicated for passing certain parameters */
963 
964   /* initialize to defaults section locations, names and addresses */
965   pic16_sectioninfo.at_udata    = "udata";
966 
967   /* set pic16 port options to defaults */
968   pic16_options.no_banksel = 0;
969   pic16_options.opt_banksel = 0;
970   pic16_options.omit_configw = 0;
971   pic16_options.omit_ivt = 0;
972   pic16_options.leave_reset = 0;
973   pic16_options.stack_model = 0;            /* 0 for 'small', 1 for 'large' */
974   pic16_options.ivt_loc = 0x000000;
975   pic16_options.nodefaultlibs = 0;
976   pic16_options.dumpcalltree = 0;
977   pic16_options.crt_name = "crt0iz.o";       /* the default crt to link */
978   pic16_options.no_crt = 0;         /* use crt by default */
979   pic16_options.ip_stack = 1;       /* set to 1 to enable ipop/ipush for stack */
980   pic16_options.gstack = 0;
981   pic16_options.debgen = 0;
982   pic16_options.no_warn_non_free = 0;
983 }
984 
985 static const char *
_pic16_getRegName(const struct reg_info * reg)986 _pic16_getRegName (const struct reg_info *reg)
987 {
988   if (reg)
989     return reg->name;
990   return "err";
991 }
992 
993 
994 #if 1
995 static const char *
_pic16_mangleFunctionName(const char * sz)996 _pic16_mangleFunctionName (const char *sz)
997 {
998 //  fprintf(stderr, "mangled function name: %s\n", sz);
999 
1000   return sz;
1001 }
1002 #endif
1003 
1004 
1005 static void
_pic16_genAssemblerPreamble(FILE * of)1006 _pic16_genAssemblerPreamble (FILE * of)
1007 {
1008   const char *name = pic16_processor_base_name();
1009 
1010   if (!name)
1011     {
1012       name = "p18f452";
1013       fprintf(stderr,"WARNING: No Pic has been selected, defaulting to %s\n",name);
1014     }
1015 
1016   fprintf (of, "\tlist\tp=%s\n", &name[1]);
1017   fprintf (of, "\tradix\tdec\n");
1018 
1019   if (pic16_mplab_comp)
1020     {
1021       // provide ACCESS macro used during SFR accesses
1022       fprintf (of, "\tinclude <p%s.inc>\n", &name[1]);
1023     }
1024 
1025   if(!pic16_options.omit_configw) {
1026     pic16_emitConfigRegs(of);
1027     fprintf(of, "\n");
1028     pic16_emitIDRegs(of);
1029   }
1030 }
1031 
1032 /* Generate interrupt vector table. */
1033 static int
_pic16_genIVT(struct dbuf_s * oBuf,symbol ** interrupts,int maxInterrupts)1034 _pic16_genIVT (struct dbuf_s * oBuf, symbol ** interrupts, int maxInterrupts)
1035 {
1036 #if 1
1037     /* PIC18F family has only two interrupts, the high and the low
1038      * priority interrupts, which reside at 0x0008 and 0x0018 respectively - VR */
1039 
1040     if((!pic16_options.omit_ivt) || (pic16_options.omit_ivt && pic16_options.leave_reset)) {
1041         dbuf_printf(oBuf, "; RESET vector\n");
1042         dbuf_printf(oBuf, "\tgoto\t__sdcc_gsinit_startup\n");
1043     }
1044 
1045     if(!pic16_options.omit_ivt) {
1046         dbuf_printf(oBuf, "\tres 4\n");
1047 
1048 
1049         dbuf_printf(oBuf, "; High priority interrupt vector 0x0008\n");
1050         if(interrupts[1]) {
1051             dbuf_printf(oBuf, "\tgoto\t%s\n", interrupts[1]->rname);
1052             dbuf_printf(oBuf, "\tres\t12\n");
1053         } else {
1054             dbuf_printf(oBuf, "\tretfie\n");
1055             dbuf_printf(oBuf, "\tres\t14\n");
1056         }
1057 
1058         dbuf_printf(oBuf, "; Low priority interrupt vector 0x0018\n");
1059         if(interrupts[2]) {
1060             dbuf_printf(oBuf, "\tgoto\t%s\n", interrupts[2]->rname);
1061         } else {
1062             dbuf_printf(oBuf, "\tretfie\n");
1063         }
1064     }
1065 #endif
1066   return TRUE;
1067 }
1068 
1069 /* return True if the port can handle the type,
1070  * False to convert it to function call */
1071 static bool
_hasNativeMulFor(iCode * ic,sym_link * left,sym_link * right)1072 _hasNativeMulFor (iCode *ic, sym_link *left, sym_link *right)
1073 {
1074   //fprintf(stderr,"checking for native mult for %c (size: %d)\n", ic->op, getSize(OP_SYMBOL(IC_RESULT(ic))->type));
1075   int symL, symR, symRes, sizeL = 0, sizeR = 0, sizeRes = 0;
1076 
1077   /* left/right are symbols? */
1078   symL = IS_SYMOP(IC_LEFT(ic));
1079   symR = IS_SYMOP(IC_RIGHT(ic));
1080   symRes = IS_SYMOP(IC_RESULT(ic));
1081 
1082   /* --> then determine their sizes */
1083   sizeL = symL ? getSize(OP_SYM_TYPE(IC_LEFT(ic))) : 4;
1084   sizeR = symR ? getSize(OP_SYM_TYPE(IC_RIGHT(ic))) : 4;
1085   sizeRes = symRes ? getSize(OP_SYM_TYPE(IC_RESULT(ic))) : 4;
1086 
1087   /* Checks to enable native multiplication.
1088    * PICs do not offer native division at all...
1089    *
1090    * Ideas:
1091    * (  i) if result is just one byte, use native MUL
1092    *       (regardless of the operands)
1093    * ( ii) if left and right are unsigned 8-bit operands,
1094    *       use native MUL
1095    * (iii) if left or right is a literal in the range of [-128..256)
1096    *       and the other is an unsigned byte, use native MUL
1097    */
1098   if (ic->op == '*')
1099   {
1100     /* use native mult for `*: <?> x <?> --> {u8_t, s8_t}' */
1101     if (sizeRes == 1) { return TRUE; }
1102 
1103     /* use native mult for `u8_t x u8_t --> { u16_t, s16_t }' */
1104     if (sizeL == 1 && symL /*&& SPEC_USIGN(OP_SYM_TYPE(IC_LEFT(ic)))*/) {
1105       sizeL = 1;
1106     } else {
1107       //printf( "%s: left too large (%u) / signed (%u)\n", __FUNCTION__, sizeL, symL && !SPEC_USIGN(OP_SYM_TYPE(IC_LEFT(ic))));
1108       sizeL = 4;
1109     }
1110     if (sizeR == 1 && symR /*&& SPEC_USIGN(OP_SYM_TYPE(IC_RIGHT(ic)))*/) {
1111       sizeR = 1;
1112     } else {
1113       //printf( "%s: right too large (%u) / signed (%u)\n", __FUNCTION__, sizeR, symR && !SPEC_USIGN(OP_SYM_TYPE(IC_RIGHT(ic))));
1114       sizeR = 4;
1115     }
1116 
1117     /* also allow literals [-128..256) for left/right operands */
1118     if (IS_VALOP(IC_LEFT(ic)))
1119     {
1120       long l = (long) ulFromVal ( OP_VALUE( IC_LEFT(ic) ) );
1121       sizeL = 4;
1122       //printf( "%s: val(left) = %ld\n", __FUNCTION__, l );
1123       if (l >= -128 && l < 256)
1124       {
1125     sizeL = 1;
1126       } else {
1127     //printf( "%s: left value %ld outside [-128..256)\n", __FUNCTION__, l );
1128       }
1129     }
1130     if (IS_VALOP( IC_RIGHT(ic) ))
1131     {
1132       long l = (long) ulFromVal ( OP_VALUE( IC_RIGHT(ic) ) );
1133       sizeR = 4;
1134       //printf( "%s: val(right) = %ld\n", __FUNCTION__, l );
1135       if (l >= -128 && l < 256)
1136       {
1137     sizeR = 1;
1138       } else {
1139     //printf( "%s: right value %ld outside [-128..256)\n", __FUNCTION__, l );
1140       }
1141     }
1142 
1143     /* use native mult iff left and right are (unsigned) 8-bit operands */
1144     if (sizeL == 1 && sizeR == 1) { return TRUE; }
1145   }
1146 
1147   if (ic->op == '/' || ic->op == '%')
1148   {
1149     /* We must catch /: {u8_t,s8_t} x {u8_t,s8_t} --> {u8_t,s8_t},
1150      * because SDCC will call 'divuchar' even for u8_t / s8_t.
1151      * Example: 128 / -2 becomes 128 / 254 = 0 != -64... */
1152     if (sizeL == 1 && sizeR == 1) return TRUE;
1153 
1154     /* What about literals? */
1155     if (IS_VALOP( IC_LEFT(ic) ))
1156     {
1157       long l = (long) ulFromVal ( OP_VALUE( IC_LEFT(ic) ) );
1158       sizeL = 4;
1159       //printf( "%s: val(left) = %ld\n", __FUNCTION__, l );
1160       if (l >= -128 && l < 256)
1161       {
1162     sizeL = 1;
1163       } else {
1164     //printf( "%s: left value %ld outside [-128..256)\n", __FUNCTION__, l );
1165       }
1166     }
1167     if (IS_VALOP( IC_RIGHT(ic) ))
1168     {
1169       long l = (long) ulFromVal ( OP_VALUE( IC_RIGHT(ic) ) );
1170       sizeR = 4;
1171       //printf( "%s: val(right) = %ld\n", __FUNCTION__, l );
1172       if (l >= -128 && l < 256)
1173       {
1174     sizeR = 1;
1175       } else {
1176     //printf( "%s: right value %ld outside [-128..256)\n", __FUNCTION__, l );
1177       }
1178     }
1179     if (sizeL == 1 && sizeR == 1) { return TRUE; }
1180   }
1181 
1182   return FALSE;
1183 }
1184 
1185 
1186 #if 0
1187 /* Do CSE estimation */
1188 static bool cseCostEstimation (iCode *ic, iCode *pdic)
1189 {
1190 //    operand *result = IC_RESULT(ic);
1191 //    sym_link *result_type = operandType(result);
1192 
1193 
1194     /* VR -- this is an adhoc. Put here after conversation
1195      * with Erik Epetrich */
1196 
1197     if(ic->op == '<'
1198         || ic->op == '>'
1199         || ic->op == EQ_OP) {
1200 
1201         fprintf(stderr, "%d %s\n", __LINE__, __FUNCTION__);
1202       return 0;
1203     }
1204 
1205 #if 0
1206     /* if it is a pointer then return ok for now */
1207     if (IC_RESULT(ic) && IS_PTR(result_type)) return 1;
1208 
1209     /* if bitwise | add & subtract then no since mcs51 is pretty good at it
1210        so we will cse only if they are local (i.e. both ic & pdic belong to
1211        the same basic block */
1212     if (IS_BITWISE_OP(ic) || ic->op == '+' || ic->op == '-') {
1213         /* then if they are the same Basic block then ok */
1214         if (ic->eBBlockNum == pdic->eBBlockNum) return 1;
1215         else return 0;
1216     }
1217 #endif
1218 
1219     /* for others it is cheaper to do the cse */
1220     return 1;
1221 }
1222 #endif
1223 
1224 
1225 /* Indicate which extended bit operations this port supports */
1226 static bool
hasExtBitOp(int op,int size)1227 hasExtBitOp (int op, int size)
1228 {
1229   if (op == RRC
1230       || op == RLC
1231       || op == GETABIT
1232       /* || op == GETHBIT */ /* GETHBIT doesn't look complete for PIC */
1233      )
1234     return TRUE;
1235   else
1236     return FALSE;
1237 }
1238 
1239 /* Indicate the expense of an access to an output storage class */
1240 static int
oclsExpense(struct memmap * oclass)1241 oclsExpense (struct memmap *oclass)
1242 {
1243   /* The IN_FARSPACE test is compatible with historical behaviour, */
1244   /* but I don't think it is applicable to PIC. If so, please feel */
1245   /* free to remove this test -- EEP */
1246   if (IN_FARSPACE(oclass))
1247     return 1;
1248 
1249   return 0;
1250 }
1251 
1252 /** $1 is the input object file (PIC16 specific)    // >>always the basename<<.
1253     $2 is always the output file.
1254     $3 -L path and -l libraries
1255     $l is the list of extra options that should be there somewhere...
1256     MUST be terminated with a NULL.
1257 */
1258 const char *pic16_linkCmd[] =
1259 {
1260   "gplink", "$l", "-w", "-r", "-o", "$2", "$1","$3", NULL
1261 };
1262 
1263 /** $1 is always the basename.
1264     $2 is always the output file.
1265     $3 varies (nothing currently)
1266     $l is the list of extra options that should be there somewhere...
1267     MUST be terminated with a NULL.
1268 */
1269 const char *pic16_asmCmd[] =
1270 {
1271   "gpasm", "$l", "$3", "-o", "$2", "-c", "$1.asm", NULL
1272 };
1273 
1274 /* Globals */
1275 PORT pic16_port =
1276 {
1277   TARGET_ID_PIC16,
1278   "pic16",
1279   "MCU PIC16",      /* Target name */
1280   "18f452",        /* Processor */
1281   {
1282     pic16glue,
1283     TRUE,           /* Emit glue around main */
1284     NO_MODEL,
1285     NO_MODEL,
1286     NULL,           /* model == target */
1287   },
1288   {
1289     pic16_asmCmd,   /* assembler command and arguments */
1290     NULL,           /* alternate macro based form */
1291     "-g",           /* arguments for debug mode */
1292     NULL,           /* arguments for normal mode */
1293     0,              /* print externs as global */
1294     ".asm",         /* assembler file extension */
1295     NULL            /* no do_assemble function */
1296   },
1297   {
1298     NULL,           //    pic16_linkCmd,        /* linker command and arguments */
1299     NULL,           /* alternate macro based form */
1300     _pic16_linkEdit,        //NULL,         /* no do_link function */
1301     ".o",           /* extension for object files */
1302     0               /* no need for linker file */
1303   },
1304   {                 /* Peephole optimizer */
1305     _defaultRules
1306   },
1307   {
1308     /* Sizes */
1309     1,      /* char */
1310     2,      /* short */
1311     2,      /* int */
1312     4,      /* long */
1313     8,      /* long long */
1314     2,      /* near ptr */
1315     3,      /* far ptr, far pointers (see Microchip) */
1316     3,      /* gptr */
1317     2,      /* func ptr */
1318     3,      /* banked func ptr */
1319     1,      /* bit */
1320     4,      /* float */
1321   },
1322 
1323     /* generic pointer tags */
1324   {
1325     0x00,   /* far */
1326     0x80,   /* near */
1327     0x00,   /* xstack */
1328     0x00    /* code */
1329   },
1330 
1331   {
1332     "XSEG    (XDATA)",      // xstack
1333     "STACK   (DATA)",       // istack
1334     "CSEG    (CODE)",       // code
1335     "DSEG    (DATA)",       // data
1336     "ISEG    (DATA)",       // idata
1337     "PSEG    (DATA)",       // pdata
1338     "XSEG    (XDATA)",      // xdata
1339     "BSEG    (BIT)",        // bit
1340     "RSEG    (DATA)",       // reg
1341     "GSINIT  (CODE)",       // static
1342     "OSEG    (OVR,DATA)",   // overlay
1343     "GSFINAL (CODE)",       // post static
1344     "HOME    (CODE)",       // home
1345     NULL,                   // xidata
1346     NULL,                   // xinit
1347     "CONST   (CODE)",       // const_name - const data (code or not)
1348     "CABS    (ABS,CODE)",   // cabs_name - const absolute data (code or not)
1349     "XABS    (ABS,XDATA)",  // xabs_name - absolute xdata
1350     "IABS    (ABS,DATA)",   // iabs_name - absolute data
1351     NULL,                   // name of segment for initialized variables
1352     NULL,                   // name of segment for copies of initialized variables in code space
1353     NULL,                   // default location for auto vars
1354     NULL,                   // default location for global vars
1355     1,                      // code is read only 1=yes
1356     1                       // No fancy alignments supported.
1357   },
1358   {
1359     NULL,       /* genExtraAreaDeclaration */
1360     NULL        /* genExatrAreaLinkOptions */
1361   },
1362   {
1363     /* stack related information */
1364     -1,         /* -1 stack grows downwards, +1 upwards */
1365     1,          /* extra overhead when calling between banks */
1366     4,          /* extra overhead when the function is an ISR */
1367     1,          /* extra overhead for a function call */
1368     1,          /* re-entrant space */
1369     0,          /* 'banked' call overhead, mild overlap with bank_overhead */
1370     1           /* sp is offset by 1 from last item pushed */
1371   },
1372   {
1373      -1, FALSE
1374   },
1375   {
1376     pic16_emitDebuggerSymbol
1377   },
1378   {
1379     255/3,      /* maxCount */
1380     3,          /* sizeofElement */
1381     /* The rest of these costs are bogus. They approximate */
1382     /* the behavior of src/SDCCicode.c 1.207 and earlier.  */
1383     {4,4,4},    /* sizeofMatchJump[] */
1384     {0,0,0},    /* sizeofRangeCompare[] */
1385     0,          /* sizeofSubtract */
1386     3,          /* sizeofDispatch */
1387   },
1388   "_",
1389   _pic16_init,
1390   _pic16_parseOptions,
1391   pic16_optionsTable,
1392   _pic16_initPaths,
1393   _pic16_finaliseOptions,
1394   _pic16_setDefaultOptions,
1395   pic16_assignRegisters,
1396   _pic16_getRegName,
1397   0,
1398   NULL,
1399   _pic16_keywords,
1400   _pic16_genAssemblerPreamble,
1401   NULL,             /* no genAssemblerEnd */
1402   _pic16_genIVT,
1403   NULL, // _pic16_genXINIT
1404   NULL,             /* genInitStartup */
1405   _pic16_reset_regparm,
1406   _pic16_regparm,
1407   _process_pragma,  /* process a pragma */
1408   _pic16_mangleFunctionName, /* mangles function name */
1409   _hasNativeMulFor,
1410   hasExtBitOp,      /* hasExtBitOp */
1411   oclsExpense,      /* oclsExpense */
1412   FALSE,
1413   TRUE,             /* little endian */
1414   0,                /* leave lt */
1415   0,                /* leave gt */
1416   1,                /* transform <= to ! > */
1417   1,                /* transform >= to ! < */
1418   1,                /* transform != to !(a == b) */
1419   0,                /* leave == */
1420   FALSE,            /* No array initializer support. */
1421   0,    //cseCostEstimation,            /* !!!no CSE cost estimation yet */
1422   NULL,             /* no builtin functions */
1423   GPOINTER,         /* treat unqualified pointers as "generic" pointers */
1424   1,                /* reset labelKey to 1 */
1425   1,                /* globals & local static allowed */
1426   0,                /* Number of registers handled in the tree-decomposition-based register allocator in SDCCralloc.hpp */
1427   PORT_MAGIC
1428 };
1429