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