Applied patch from Vangelis Rokas <vrokas@otenet.gr> for pic16 multi-operand
[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 pic16 */
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
244 #if 0
245   fprintf (of, "\t__config _CONFIG1H,0x%x\n",pic16_getConfigWord(0x300001));
246   fprintf (of, "\t__config _CONFIG2L,0x%x\n",pic16_getConfigWord(0x300002));
247   fprintf (of, "\t__config _CONFIG2H,0x%x\n",pic16_getConfigWord(0x300003));
248   fprintf (of, "\t__config _CONFIG3H,0x%x\n",pic16_getConfigWord(0x300005));
249   fprintf (of, "\t__config _CONFIG4L,0x%x\n",pic16_getConfigWord(0x300006));
250   fprintf (of, "\t__config _CONFIG5L,0x%x\n",pic16_getConfigWord(0x300008));
251   fprintf (of, "\t__config _CONFIG5H,0x%x\n",pic16_getConfigWord(0x300009));
252   fprintf (of, "\t__config _CONFIG6L,0x%x\n",pic16_getConfigWord(0x30000a));
253   fprintf (of, "\t__config _CONFIG6H,0x%x\n",pic16_getConfigWord(0x30000b));
254   fprintf (of, "\t__config _CONFIG7L,0x%x\n",pic16_getConfigWord(0x30000c));
255   fprintf (of, "\t__config _CONFIG7H,0x%x\n",pic16_getConfigWord(0x30000d));
256 #endif
257
258   fprintf (of, "\tradix dec\n");
259 }
260
261 /* Generate interrupt vector table. */
262 static int
263 _pic16_genIVT (FILE * of, symbol ** interrupts, int maxInterrupts)
264 {
265   int i;
266
267   if (options.model != MODEL_FLAT24)
268     {
269       /* Let the default code handle it. */
270       return FALSE;
271     }
272
273   fprintf (of, "\t;ajmp\t__sdcc_gsinit_startup\n");
274
275   /* now for the other interrupts */
276   for (i = 0; i < maxInterrupts; i++)
277     {
278       if (interrupts[i])
279         {
280           fprintf (of, "\t;ljmp\t%s\n\t.ds\t4\n", interrupts[i]->rname);
281         }
282       else
283         {
284           fprintf (of, "\t;reti\n\t.ds\t7\n");
285         }
286     }
287
288   return TRUE;
289 }
290
291 static bool
292 _hasNativeMulFor (iCode *ic, sym_link *left, sym_link *right)
293 {
294   //  sym_link *test = NULL;
295   //  value *val;
296
297   fprintf(stderr,"checking for native mult\n");
298
299   if ( ic->op != '*')
300     {
301       return FALSE;
302     }
303
304   return TRUE;
305 /*
306   if ( IS_LITERAL (left))
307     {
308       fprintf(stderr,"left is lit\n");
309       test = left;
310       val = OP_VALUE (IC_LEFT (ic));
311     }
312   else if ( IS_LITERAL (right))
313     {
314       fprintf(stderr,"right is lit\n");
315       test = left;
316       val = OP_VALUE (IC_RIGHT (ic));
317     }
318   else
319     {
320       fprintf(stderr,"oops, neither is lit so no\n");
321       return FALSE;
322     }
323
324   if ( getSize (test) <= 2)
325     {
326       fprintf(stderr,"yep\n");
327       return TRUE;
328     }
329   fprintf(stderr,"nope\n");
330
331   return FALSE;
332 */
333 }
334
335 /** $1 is always the basename.
336     $2 is always the output file.
337     $3 varies
338     $l is the list of extra options that should be there somewhere...
339     MUST be terminated with a NULL.
340 */
341 static const char *_linkCmd[] =
342 {
343   "gplink", "\"$1.o\"", "-o $1", "$l", NULL
344 };
345
346 /* Sigh. This really is not good. For now, I recommend:
347  * sdcc -S -mpic16 file.c
348  * the -S option does not compile or link
349  */
350 static const char *_asmCmd[] =
351 {
352   "gpasm", "-c  -I/usr/local/share/gputils/header", "\"$1.asm\"", NULL
353
354 };
355
356 /* Globals */
357 PORT pic16_port =
358 {
359   TARGET_ID_PIC16,
360   "pic16",
361   "MCU PIC16",                  /* Target name */
362   "p18f452",                    /* Processor */
363   {
364     TRUE,                       /* Emit glue around main */
365     MODEL_SMALL | MODEL_LARGE | MODEL_FLAT24,
366     MODEL_SMALL
367   },
368   {
369     _asmCmd,
370     NULL,
371     NULL,
372     NULL,
373         //"-plosgffc",          /* Options with debug */
374         //"-plosgff",           /* Options without debug */
375     0,
376     ".asm",
377     NULL                        /* no do_assemble function */
378   },
379   {
380     _linkCmd,
381     NULL,
382     NULL,
383     ".rel"
384   },
385   {
386     _defaultRules
387   },
388   {
389         /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
390     1, 2, 2, 4, 2, 2, 2, 1, 4, 4
391         /* TSD - I changed the size of gptr from 3 to 1. However, it should be
392            2 so that we can accomodate the PIC's with 4 register banks (like the
393            16f877)
394          */
395   },
396   {
397     "XSEG    (XDATA)",
398     "STACK   (DATA)",
399     "CSEG    (CODE)",
400     "DSEG    (DATA)",
401     "ISEG    (DATA)",
402     "XSEG    (XDATA)",
403     "BSEG    (BIT)",
404     "RSEG    (DATA)",
405     "GSINIT  (CODE)",
406     "OSEG    (OVR,DATA)",
407     "GSFINAL (CODE)",
408     "HOME        (CODE)",
409     NULL, // xidata
410     NULL, // xinit
411     NULL,
412     NULL,
413     1        // code is read only
414   },
415   {
416     +1, 1, 4, 1, 1, 0
417   },
418     /* pic16 has an 8 bit mul */
419   {
420     1, -1
421   },
422   "_",
423   _pic16_init,
424   _pic16_parseOptions,
425   NULL,
426   _pic16_finaliseOptions,
427   _pic16_setDefaultOptions,
428   pic16_assignRegisters,
429   _pic16_getRegName,
430   _pic16_keywords,
431   _pic16_genAssemblerPreamble,
432   NULL,                         /* no genAssemblerEnd */
433   _pic16_genIVT,
434   NULL, // _pic16_genXINIT
435   _pic16_reset_regparm,
436   _pic16_regparm,
437   _process_pragma,                              /* process a pragma */
438   NULL,
439   _hasNativeMulFor,
440   FALSE,
441   0,                            /* leave lt */
442   0,                            /* leave gt */
443   1,                            /* transform <= to ! > */
444   1,                            /* transform >= to ! < */
445   1,                            /* transform != to !(a == b) */
446   0,                            /* leave == */
447   FALSE,                        /* No array initializer support. */
448   0,                            /* no CSE cost estimation yet */
449   NULL,                         /* no builtin functions */
450   GPOINTER,                     /* treat unqualified pointers as "generic" pointers */
451   1,                            /* reset labelKey to 1 */
452   1,                            /* globals & local static allowed */
453   PORT_MAGIC
454 };