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