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