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