*** empty log message ***
[fw/sdcc] / src / pic16 / main.c
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 "main.h"
29 #include "ralloc.h"
30 #include "device.h"
31 #include "SDCCutil.h"
32 #include "glue.h"
33 //#include "gen.h"
34
35
36 static char _defaultRules[] =
37 {
38 #include "peeph.rul"
39 };
40
41 /* list of key words used by pic16 */
42 static char *_pic16_keywords[] =
43 {
44   "at",
45   "bit",
46   "code",
47   "critical",
48   "data",
49   "far",
50   "idata",
51   "interrupt",
52   "near",
53   "pdata",
54   "reentrant",
55   "sfr",
56   "sbit",
57   "using",
58   "xdata",
59   "_data",
60   "_code",
61   "_generic",
62   "_near",
63   "_xdata",
64   "_pdata",
65   "_idata",
66   NULL
67 };
68
69
70 extern char *pic16_processor_base_name(void);
71
72 void  pic16_pCodeInitRegisters(void);
73
74 void pic16_assignRegisters (eBBlock ** ebbs, int count);
75
76 static int regParmFlg = 0;      /* determine if we can register a parameter */
77
78 static void
79 _pic16_init (void)
80 {
81   asm_addTree (&asm_asxxxx_mapping);
82   pic16_pCodeInitRegisters();
83   maxInterrupts = 2;
84 }
85
86 static void
87 _pic16_reset_regparm ()
88 {
89   regParmFlg = 0;
90 }
91
92 static int
93 _pic16_regparm (sym_link * l)
94 {
95   /* for this processor it is simple
96      can pass only the first parameter in a register */
97   //if (regParmFlg)
98   //  return 0;
99
100   regParmFlg++;// = 1;
101   return 1;
102 }
103
104 static int
105 _process_pragma(const char *sz)
106 {
107   static const char *WHITE = " \t";
108   char  *ptr = strtok((char *)sz, WHITE);
109
110   if (startsWith (ptr, "memmap"))
111     {
112       char      *start;
113       char      *end;
114       char      *type;
115       char      *alias;
116
117       start = strtok((char *)NULL, WHITE);
118       end = strtok((char *)NULL, WHITE);
119       type = strtok((char *)NULL, WHITE);
120       alias = strtok((char *)NULL, WHITE);
121
122       if (start != (char *)NULL
123           && end != (char *)NULL
124           && type != (char *)NULL) {
125         value           *startVal = constVal(start);
126         value           *endVal = constVal(end);
127         value           *aliasVal;
128         memRange        r;
129
130         if (alias == (char *)NULL) {
131           aliasVal = constVal(0);
132         } else {
133           aliasVal = constVal(alias);
134         }
135
136         r.start_address = (int)floatFromVal(startVal);
137         r.end_address = (int)floatFromVal(endVal);
138         r.alias = (int)floatFromVal(aliasVal);
139         r.bank = (r.start_address >> 7) & 0xf;
140
141         if (strcmp(type, "RAM") == 0) {
142           pic16_addMemRange(&r, 0);
143         } else if (strcmp(type, "SFR") == 0) {
144           pic16_addMemRange(&r, 1);
145         } else {
146           return 1;
147         }
148       }
149
150       return 0;
151     } else if (startsWith (ptr, "maxram")) {
152       char *maxRAM = strtok((char *)NULL, WHITE);
153
154       if (maxRAM != (char *)NULL) {
155         int     maxRAMaddress;
156         value   *maxRAMVal;
157
158         maxRAMVal = constVal(maxRAM);
159         maxRAMaddress = (int)floatFromVal(maxRAMVal);
160         pic16_setMaxRAM(maxRAMaddress);
161       }
162         
163       return 0;
164     }
165   return 1;
166 }
167
168 static bool
169 _pic16_parseOptions (int *pargc, char **argv, int *i)
170 {
171   /* TODO: allow port-specific command line options to specify
172    * segment names here.
173    */
174   return FALSE;
175 }
176
177 static void
178 _pic16_finaliseOptions (void)
179 {
180         port->mem.default_local_map = data;
181         port->mem.default_globl_map = data;
182
183         setMainValue("mcu", pic16_processor_base_name() );
184         addSet(&preArgvSet, Safe_strdup("-DMCU={mcu}"));
185 }
186
187
188 /* all the rest is commented ifdef'd out */
189 #if 0
190   /* Hack-o-matic: if we are using the flat24 model,
191    * adjust pointer sizes.
192    */
193   if (options.model == MODEL_FLAT24)
194     {
195
196       fprintf (stderr, "*** WARNING: you should use the '-mds390' option "
197                "for DS80C390 support. This code generator is "
198                "badly out of date and probably broken.\n");
199
200       port->s.fptr_size = 3;
201       port->s.gptr_size = 4;
202       port->stack.isr_overhead++;       /* Will save dpx on ISR entry. */
203 #if 1
204       port->stack.call_overhead++;      /* This acounts for the extra byte 
205                                          * of return addres on the stack.
206                                          * but is ugly. There must be a 
207                                          * better way.
208                                          */
209 #endif
210       fReturn = fReturn390;
211       fReturnSize = 5;
212     }
213
214   if (options.model == MODEL_LARGE)
215     {
216       port->mem.default_local_map = xdata;
217       port->mem.default_globl_map = xdata;
218     }
219   else
220     {
221       port->mem.default_local_map = data;
222       port->mem.default_globl_map = data;
223     }
224
225   if (options.stack10bit)
226     {
227       if (options.model != MODEL_FLAT24)
228         {
229           fprintf (stderr,
230                    "*** warning: 10 bit stack mode is only supported in flat24 model.\n");
231           fprintf (stderr, "\t10 bit stack mode disabled.\n");
232           options.stack10bit = 0;
233         }
234       else
235         {
236           /* Fixup the memory map for the stack; it is now in
237            * far space and requires a FPOINTER to access it.
238            */
239           istack->fmap = 1;
240           istack->ptrType = FPOINTER;
241         }
242     }
243 #endif
244
245
246 static void
247 _pic16_setDefaultOptions (void)
248 {
249 }
250
251 static const char *
252 _pic16_getRegName (struct regs *reg)
253 {
254   if (reg)
255     return reg->name;
256   return "err";
257 }
258
259
260 static void
261 _pic16_genAssemblerPreamble (FILE * of)
262 {
263   char * name = pic16_processor_base_name();
264
265   if(!name) {
266
267     name = "p18f452";
268     fprintf(stderr,"WARNING: No Pic has been selected, defaulting to %s\n",name);
269   }
270
271   fprintf (of, "\tlist\tp=%s\n",&name[1]);
272   fprintf (of, "\tinclude \"%s.inc\"\n",name);
273
274   fprintf (of, "\t__config _CONFIG1H,0x%x\n",pic16_getConfigWord(0x300001));
275   fprintf (of, "\t__config _CONFIG2L,0x%x\n",pic16_getConfigWord(0x300002));
276   fprintf (of, "\t__config _CONFIG2H,0x%x\n",pic16_getConfigWord(0x300003));
277   fprintf (of, "\t__config _CONFIG3H,0x%x\n",pic16_getConfigWord(0x300005));
278   fprintf (of, "\t__config _CONFIG4L,0x%x\n",pic16_getConfigWord(0x300006));
279   fprintf (of, "\t__config _CONFIG5L,0x%x\n",pic16_getConfigWord(0x300008));
280   fprintf (of, "\t__config _CONFIG5H,0x%x\n",pic16_getConfigWord(0x300009));
281   fprintf (of, "\t__config _CONFIG6L,0x%x\n",pic16_getConfigWord(0x30000a));
282   fprintf (of, "\t__config _CONFIG6H,0x%x\n",pic16_getConfigWord(0x30000b));
283   fprintf (of, "\t__config _CONFIG7L,0x%x\n",pic16_getConfigWord(0x30000c));
284   fprintf (of, "\t__config _CONFIG7H,0x%x\n",pic16_getConfigWord(0x30000d));
285
286   fprintf (of, "\tradix dec\n");
287 }
288
289 /* Generate interrupt vector table. */
290 static int
291 _pic16_genIVT (FILE * of, symbol ** interrupts, int maxInterrupts)
292 {
293 #if 0
294   int i;
295 #endif
296
297 #if 0
298         if (options.model != MODEL_FLAT24) {
299         /* Let the default code handle it. */
300           return FALSE;
301         }
302 #endif
303
304         /* PIC18F family has only two interrupts, the high and the low
305          * priority interrupts, which reside at 0x0008 and 0x0018 respectively - VR */
306
307         fprintf(of, "; RESET vector\n");
308         fprintf(of, "\tgoto\t__sdcc_gsinit_startup\n");
309         fprintf(of, "\tres 4\n");
310
311
312         fprintf(of, "; High priority interrupt vector 0x0008\n");
313         if(interrupts[1]) {
314                 fprintf(of, "\tgoto\t%s\n", interrupts[1]->rname);
315                 fprintf(of, "\tres\t12\n"); 
316         } else {
317                 fprintf(of, "\tretfie\n");
318                 fprintf(of, "\tres\t14\n");
319         }
320
321         fprintf(of, "; Low priority interrupt vector 0x0018\n");
322         if(interrupts[2]) {
323                 fprintf(of, "\tgoto\t%s\n", interrupts[2]->rname);
324         } else {
325                 fprintf(of, "\tretfie\n");
326         }
327 #if 0
328   /* now for the other interrupts */
329   for (i = 0; i < maxInterrupts; i++)
330     {
331         fprintf(of, "; %s priority interrupt vector 0x%s\n", (i==0)?"high":"low", (i==0)?"0008":"0018");
332       if (interrupts[i])
333         {
334           fprintf (of, "\tgoto\t%s\n\tres\t4\n", interrupts[i]->rname);
335         }
336       else
337         {
338           fprintf (of, "\tretfie\n\tres\t7\n");
339         }
340     }
341 #endif
342
343   return TRUE;
344 }
345
346 static bool
347 _hasNativeMulFor (iCode *ic, sym_link *left, sym_link *right)
348 {
349   //  sym_link *test = NULL;
350   //  value *val;
351
352   fprintf(stderr,"checking for native mult\n");
353
354   if ( ic->op != '*')
355     {
356       return FALSE;
357     }
358
359   return TRUE;
360 /*
361   if ( IS_LITERAL (left))
362     {
363       fprintf(stderr,"left is lit\n");
364       test = left;
365       val = OP_VALUE (IC_LEFT (ic));
366     }
367   else if ( IS_LITERAL (right))
368     {
369       fprintf(stderr,"right is lit\n");
370       test = left;
371       val = OP_VALUE (IC_RIGHT (ic));
372     }
373   else
374     {
375       fprintf(stderr,"oops, neither is lit so no\n");
376       return FALSE;
377     }
378
379   if ( getSize (test) <= 2)
380     {
381       fprintf(stderr,"yep\n");
382       return TRUE;
383     }
384   fprintf(stderr,"nope\n");
385
386   return FALSE;
387 */
388 }
389
390 /* Indicate which extended bit operations this port supports */
391 static bool
392 hasExtBitOp (int op, int size)
393 {
394   if (op == RRC
395       || op == RLC
396       /* || op == GETHBIT */ /* GETHBIT doesn't look complete for PIC */
397      )
398     return TRUE;
399   else
400     return FALSE;
401 }
402
403 /* Indicate the expense of an access to an output storage class */
404 static int
405 oclsExpense (struct memmap *oclass)
406 {
407   /* The IN_FARSPACE test is compatible with historical behaviour, */
408   /* but I don't think it is applicable to PIC. If so, please feel */
409   /* free to remove this test -- EEP */
410   if (IN_FARSPACE(oclass))
411     return 1;
412     
413   return 0;
414 }
415
416 /** $1 is always the basename.
417     $2 is always the output file.
418     $3 varies
419     $l is the list of extra options that should be there somewhere...
420     MUST be terminated with a NULL.
421 */
422 static const char *_linkCmd[] =
423 {
424   "gplink", "\"$1.o\"", "-o $1", "$l", NULL
425 };
426
427 /* Sigh. This really is not good. For now, I recommend:
428  * sdcc -S -mpic16 file.c
429  * the -S option does not compile or link
430  */
431 static const char *_asmCmd[] =
432 {
433   "gpasm", "-c  -I/usr/local/share/gputils/header", "\"$1.asm\"", NULL
434
435 };
436
437 /* Globals */
438 PORT pic16_port =
439 {
440   TARGET_ID_PIC16,
441   "pic16",
442   "MCU PIC16",                  /* Target name */
443   "p18f442",                    /* Processor */
444   {
445     pic16glue,
446     TRUE,                       /* Emit glue around main */
447     MODEL_SMALL | MODEL_LARGE | MODEL_FLAT24,
448     MODEL_SMALL
449   },
450   {
451     _asmCmd,
452     NULL,
453     NULL,
454     NULL,
455         //"-plosgffc",          /* Options with debug */
456         //"-plosgff",           /* Options without debug */
457     0,
458     ".asm",
459     NULL                        /* no do_assemble function */
460   },
461   {
462     _linkCmd,
463     NULL,
464     NULL,
465     ".rel"
466   },
467   {
468     _defaultRules
469   },
470   {
471         /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
472     1, 2, 2, 4, 2, 2, 2, 1, 4, 4
473         /* TSD - I changed the size of gptr from 3 to 1. However, it should be
474            2 so that we can accomodate the PIC's with 4 register banks (like the
475            16f877)
476          */
477   },
478   {
479     "XSEG    (XDATA)",          // xstack
480     "STACK   (DATA)",           // istack
481     "CSEG    (CODE)",           // code
482     "DSEG    (DATA)",           // data
483     "ISEG    (DATA)",           // idata
484     "XSEG    (XDATA)",          // xdata
485     "BSEG    (BIT)",            // bit
486     "RSEG    (DATA)",           // reg
487     "GSINIT  (CODE)",           // static
488     "OSEG    (OVR,DATA)",       // overlay
489     "GSFINAL (CODE)",           // post static
490     "HOME        (CODE)",       // home
491     NULL,                       // xidata
492     NULL,                       // xinit
493     NULL,                       // default location for auto vars
494     NULL,                       // default location for global vars
495     1                           // code is read only
496   },
497   { NULL, NULL },
498   {
499     +1, 1, 4, 1, 1, 0
500   },
501     /* pic16 has an 8 bit mul */
502   {
503     1, -1
504   },
505   "_",
506   _pic16_init,
507   _pic16_parseOptions,
508   NULL,
509   _pic16_finaliseOptions,
510   _pic16_setDefaultOptions,
511   pic16_assignRegisters,
512   _pic16_getRegName,
513   _pic16_keywords,
514   _pic16_genAssemblerPreamble,
515   NULL,                         /* no genAssemblerEnd */
516   _pic16_genIVT,
517   NULL, // _pic16_genXINIT
518   _pic16_reset_regparm,
519   _pic16_regparm,
520   _process_pragma,                              /* process a pragma */
521   NULL,
522   _hasNativeMulFor,
523   hasExtBitOp,                  /* hasExtBitOp */
524   oclsExpense,                  /* oclsExpense */
525   FALSE,
526   TRUE,                         /* little endian */
527   0,                            /* leave lt */
528   0,                            /* leave gt */
529   1,                            /* transform <= to ! > */
530   1,                            /* transform >= to ! < */
531   1,                            /* transform != to !(a == b) */
532   0,                            /* leave == */
533   FALSE,                        /* No array initializer support. */
534   0,                            /* no CSE cost estimation yet */
535   NULL,                         /* no builtin functions */
536   GPOINTER,                     /* treat unqualified pointers as "generic" pointers */
537   1,                            /* reset labelKey to 1 */
538   1,                            /* globals & local static allowed */
539   PORT_MAGIC
540 };