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