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