*** 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 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 /** $1 is always the basename.
385     $2 is always the output file.
386     $3 varies
387     $l is the list of extra options that should be there somewhere...
388     MUST be terminated with a NULL.
389 */
390 static const char *_linkCmd[] =
391 {
392   "gplink", "\"$1.o\"", "-o $1", "$l", NULL
393 };
394
395 /* Sigh. This really is not good. For now, I recommend:
396  * sdcc -S -mpic16 file.c
397  * the -S option does not compile or link
398  */
399 static const char *_asmCmd[] =
400 {
401   "gpasm", "-c  -I/usr/local/share/gputils/header", "\"$1.asm\"", NULL
402
403 };
404
405 /* Globals */
406 PORT pic16_port =
407 {
408   TARGET_ID_PIC16,
409   "pic16",
410   "MCU PIC16",                  /* Target name */
411   "p18f442",                    /* Processor */
412   {
413     pic16glue,
414     TRUE,                       /* Emit glue around main */
415     MODEL_SMALL | MODEL_LARGE | MODEL_FLAT24,
416     MODEL_SMALL
417   },
418   {
419     _asmCmd,
420     NULL,
421     NULL,
422     NULL,
423         //"-plosgffc",          /* Options with debug */
424         //"-plosgff",           /* Options without debug */
425     0,
426     ".asm",
427     NULL                        /* no do_assemble function */
428   },
429   {
430     _linkCmd,
431     NULL,
432     NULL,
433     ".rel"
434   },
435   {
436     _defaultRules
437   },
438   {
439         /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */
440     1, 2, 2, 4, 2, 2, 2, 1, 4, 4
441         /* TSD - I changed the size of gptr from 3 to 1. However, it should be
442            2 so that we can accomodate the PIC's with 4 register banks (like the
443            16f877)
444          */
445   },
446   {
447     "XSEG    (XDATA)",          // xstack
448     "STACK   (DATA)",           // istack
449     "CSEG    (CODE)",           // code
450     "DSEG    (DATA)",           // data
451     "ISEG    (DATA)",           // idata
452     "XSEG    (XDATA)",          // xdata
453     "BSEG    (BIT)",            // bit
454     "RSEG    (DATA)",           // reg
455     "GSINIT  (CODE)",           // static
456     "OSEG    (OVR,DATA)",       // overlay
457     "GSFINAL (CODE)",           // post static
458     "HOME        (CODE)",       // home
459     NULL,                       // xidata
460     NULL,                       // xinit
461     NULL,                       // default location for auto vars
462     NULL,                       // default location for global vars
463     1                           // code is read only
464   },
465   { NULL, NULL },
466   {
467     +1, 1, 4, 1, 1, 0
468   },
469     /* pic16 has an 8 bit mul */
470   {
471     1, -1
472   },
473   "_",
474   _pic16_init,
475   _pic16_parseOptions,
476   NULL,
477   _pic16_finaliseOptions,
478   _pic16_setDefaultOptions,
479   pic16_assignRegisters,
480   _pic16_getRegName,
481   _pic16_keywords,
482   _pic16_genAssemblerPreamble,
483   NULL,                         /* no genAssemblerEnd */
484   _pic16_genIVT,
485   NULL, // _pic16_genXINIT
486   _pic16_reset_regparm,
487   _pic16_regparm,
488   _process_pragma,                              /* process a pragma */
489   NULL,
490   _hasNativeMulFor,
491   FALSE,
492   TRUE,                         /* little endian */
493   0,                            /* leave lt */
494   0,                            /* leave gt */
495   1,                            /* transform <= to ! > */
496   1,                            /* transform >= to ! < */
497   1,                            /* transform != to !(a == b) */
498   0,                            /* leave == */
499   FALSE,                        /* No array initializer support. */
500   0,                            /* no CSE cost estimation yet */
501   NULL,                         /* no builtin functions */
502   GPOINTER,                     /* treat unqualified pointers as "generic" pointers */
503   1,                            /* reset labelKey to 1 */
504   1,                            /* globals & local static allowed */
505   PORT_MAGIC
506 };