0c3c7f3d919c304803fecc3d64481736f5aadb82
[fw/sdcc] / src / pic16 / glue.c
1 /*-------------------------------------------------------------------------
2
3   glue.c - glues everything we have done together into one file.
4                 Written By -  Sandeep Dutta . sandeep.dutta@usa.net (1998)
5
6    This program is free software; you can redistribute it and/or modify it
7    under the terms of the GNU General Public License as published by the
8    Free Software Foundation; either version 2, or (at your option) any
9    later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
20    In other words, you are welcome to use, share and improve this program.
21    You are forbidden to forbid anyone else to use, share and improve
22    what you give them.   Help stamp out software-hoarding!
23 -------------------------------------------------------------------------*/
24
25 #include "../common.h"
26 #include <time.h>
27 #include "ralloc.h"
28 #include "pcode.h"
29 #include "newalloc.h"
30
31
32 #ifdef WORDS_BIGENDIAN
33   #define _ENDIAN(x)  (3-x)
34 #else
35   #define _ENDIAN(x)  (x)
36 #endif
37
38 #define BYTE_IN_LONG(x,b) ((x>>(8*_ENDIAN(b)))&0xff)
39
40 extern symbol *interrupts[256];
41 static void printIval (symbol * sym, sym_link * type, initList * ilist, pBlock *pb);
42 extern int noAlloc;
43 extern set *publics;
44 extern unsigned maxInterrupts;
45 extern int maxRegBank;
46 extern symbol *mainf;
47 extern char *VersionString;
48 extern FILE *codeOutFile;
49 extern set *tmpfileSet;
50 extern set *tmpfileNameSet;
51 extern char *iComments1;
52 extern char *iComments2;
53 //extern void emitStaticSeg (memmap * map);
54
55 extern DEFSETFUNC (closeTmpFiles);
56 extern DEFSETFUNC (rmTmpFiles);
57
58 extern void pic16_AnalyzeBanking (void);
59 extern void copyFile (FILE * dest, FILE * src);
60 extern void pic16_InlinepCode(void);
61 extern void pic16_writeUsedRegs(FILE *);
62
63 extern void initialComments (FILE * afile);
64 extern void printPublics (FILE * afile);
65
66 extern void printChar (FILE * ofile, char *s, int plen);
67 void  pic16_pCodeInitRegisters(void);
68
69 /*-----------------------------------------------------------------*/
70 /* aopLiteral - string from a literal value                        */
71 /*-----------------------------------------------------------------*/
72 int pic16aopLiteral (value *val, int offset)
73 {
74   union {
75     float f;
76     unsigned char c[4];
77   } fl;
78
79   /* if it is a float then it gets tricky */
80   /* otherwise it is fairly simple */
81   if (!IS_FLOAT(val->type)) {
82     unsigned long v = (unsigned long) floatFromVal(val);
83
84     return ( (v >> (offset * 8)) & 0xff);
85   }
86
87   /* it is type float */
88   fl.f = (float) floatFromVal(val);
89 #ifdef WORDS_BIGENDIAN
90   return fl.c[3-offset];
91 #else
92   return fl.c[offset];
93 #endif
94
95 }
96
97
98 /*-----------------------------------------------------------------*/
99 /* emitRegularMap - emit code for maps with no special cases       */
100 /*-----------------------------------------------------------------*/
101 static void
102 pic16emitRegularMap (memmap * map, bool addPublics, bool arFlag)
103 {
104   symbol *sym;
105   int i, size, bitvars = 0;;
106
107   if (addPublics)
108     fprintf (map->oFile, ";\t.area\t%s\n", map->sname);
109
110   /* print the area name */
111   for (sym = setFirstItem (map->syms); sym;
112        sym = setNextItem (map->syms))
113     {
114
115       /* if extern then do nothing */
116       if (IS_EXTERN (sym->etype))
117         continue;
118
119       /* if allocation required check is needed
120          then check if the symbol really requires
121          allocation only for local variables */
122       if (arFlag && !IS_AGGREGATE (sym->type) &&
123           !(sym->_isparm && !IS_REGPARM (sym->etype)) &&
124           !sym->allocreq && sym->level)
125         continue;
126
127       /* if global variable & not static or extern
128          and addPublics allowed then add it to the public set */
129       if ((sym->level == 0 ||
130            (sym->_isparm && !IS_REGPARM (sym->etype))) &&
131           addPublics &&
132           !IS_STATIC (sym->etype))
133         addSetHead (&publics, sym);
134
135       /* if extern then do nothing or is a function
136          then do nothing */
137       if (IS_FUNC (sym->type))
138         continue;
139 #if 0
140       /* print extra debug info if required */
141       if (options.debug || sym->level == 0)
142         {
143
144           cdbSymbol (sym, cdbFile, FALSE, FALSE);
145
146           if (!sym->level)      /* global */
147             if (IS_STATIC (sym->etype))
148               fprintf (map->oFile, "F%s_", moduleName);         /* scope is file */
149             else
150               fprintf (map->oFile, "G_");       /* scope is global */
151           else
152             /* symbol is local */
153             fprintf (map->oFile, "L%s_", (sym->localof ? sym->localof->name : "-null-"));
154           fprintf (map->oFile, "%s_%d_%d", sym->name, sym->level, sym->block);
155         }
156 #endif
157
158       /* if is has an absolute address then generate
159          an equate for this no need to allocate space */
160       if (SPEC_ABSA (sym->etype))
161         {
162           //if (options.debug || sym->level == 0)
163           //fprintf (map->oFile,"; == 0x%04x\n",SPEC_ADDR (sym->etype));
164
165           fprintf (map->oFile, "%s\tEQU\t0x%04x\n",
166                    sym->rname,
167                    SPEC_ADDR (sym->etype));
168         }
169       else
170         {
171           /* allocate space */
172
173           /* If this is a bit variable, then allocate storage after 8 bits have been declared */
174           /* unlike the 8051, the pic does not have a separate bit area. So we emulate bit ram */
175           /* by grouping the bits together into groups of 8 and storing them in the normal ram. */
176           if (IS_BITVAR (sym->etype))
177             {
178               bitvars++;
179             }
180           else
181             {
182               fprintf (map->oFile, "\t%s\n", sym->rname);
183               if ((size = (unsigned int) getSize (sym->type) & 0xffff) > 1)
184                 {
185                   for (i = 1; i < size; i++)
186                     fprintf (map->oFile, "\t%s_%d\n", sym->rname, i);
187                 }
188             }
189           //fprintf (map->oFile, "\t.ds\t0x%04x\n", (unsigned int)getSize (sym->type) & 0xffff);
190         }
191         
192         /* if it has a initial value then do it only if
193            it is a global variable */
194         if (sym->ival && sym->level == 0) {
195             ast *ival = NULL;
196             
197             if (IS_AGGREGATE (sym->type))
198                 ival = initAggregates (sym, sym->ival, NULL);
199             else
200                 ival = newNode ('=', newAst_VALUE(symbolVal (sym)),
201                                 decorateType (resolveSymbols (list2expr (sym->ival))));
202             codeOutFile = statsg->oFile;
203             GcurMemmap = statsg;
204             eBBlockFromiCode (iCodeFromAst (ival));
205             sym->ival = NULL;
206         }
207     }
208 }
209
210
211 /*-----------------------------------------------------------------*/
212 /* printIvalType - generates ival for int/char                     */
213 /*-----------------------------------------------------------------*/
214 static void 
215 printIvalType (symbol *sym, sym_link * type, initList * ilist, pBlock *pb)
216 {
217   value *val;
218   unsigned long ulval;
219
220   //fprintf(stderr, "%s\n",__FUNCTION__);
221
222   /* if initList is deep */
223   if (ilist->type == INIT_DEEP)
224     ilist = ilist->init.deep;
225
226   if (!IS_AGGREGATE(sym->type) && getNelements(type, ilist)>1) {
227     werror (W_EXCESS_INITIALIZERS, "scalar", sym->name, sym->lineDef);
228   }
229
230   if (!(val = list2val (ilist))) {
231     // assuming a warning has been thrown
232     val=constVal("0");
233   }
234
235   if (val->type != type) {
236     val = valCastLiteral(type, floatFromVal(val));
237   }
238
239   if(val) 
240     ulval = (unsigned long) floatFromVal (val);
241   else
242     ulval =0;
243
244   switch (getSize (type)) {
245   case 1:
246     pic16_addpCode2pBlock(pb,pic16_newpCode(POC_RETLW,pic16_newpCodeOpLit(BYTE_IN_LONG(ulval,0))));
247     break;
248
249   case 2:
250     pic16_addpCode2pBlock(pb,pic16_newpCode(POC_RETLW,pic16_newpCodeOpLit(BYTE_IN_LONG(ulval,0))));
251     pic16_addpCode2pBlock(pb,pic16_newpCode(POC_RETLW,pic16_newpCodeOpLit(BYTE_IN_LONG(ulval,1))));
252     break;
253
254   case 4:
255     pic16_addpCode2pBlock(pb,pic16_newpCode(POC_RETLW,pic16_newpCodeOpLit(BYTE_IN_LONG(ulval,0))));
256     pic16_addpCode2pBlock(pb,pic16_newpCode(POC_RETLW,pic16_newpCodeOpLit(BYTE_IN_LONG(ulval,1))));
257     pic16_addpCode2pBlock(pb,pic16_newpCode(POC_RETLW,pic16_newpCodeOpLit(BYTE_IN_LONG(ulval,2))));
258     pic16_addpCode2pBlock(pb,pic16_newpCode(POC_RETLW,pic16_newpCodeOpLit(BYTE_IN_LONG(ulval,3))));
259     break;
260   }
261 }
262
263 /*-----------------------------------------------------------------*/
264 /* printIvalChar - generates initital value for character array    */
265 /*-----------------------------------------------------------------*/
266 static int 
267 printIvalChar (sym_link * type, initList * ilist, pBlock *pb, char *s)
268 {
269   value *val;
270   int remain;
271
272   if(!pb)
273     return 0;
274
275   fprintf(stderr, "%s\n",__FUNCTION__);
276   if (!s)
277     {
278
279       val = list2val (ilist);
280       /* if the value is a character string  */
281       if (IS_ARRAY (val->type) && IS_CHAR (val->etype))
282         {
283           if (!DCL_ELEM (type))
284             DCL_ELEM (type) = strlen (SPEC_CVAL (val->etype).v_char) + 1;
285
286           //printChar (oFile, SPEC_CVAL (val->etype).v_char, DCL_ELEM (type));
287           //fprintf(stderr, "%s omitting call to printChar\n",__FUNCTION__);
288           pic16_addpCode2pBlock(pb,pic16_newpCodeCharP(";omitting call to printChar"));
289
290           if ((remain = (DCL_ELEM (type) - strlen (SPEC_CVAL (val->etype).v_char) - 1)) > 0)
291             while (remain--)
292               //tfprintf (oFile, "\t!db !constbyte\n", 0);
293               pic16_addpCode2pBlock(pb,pic16_newpCode(POC_RETLW,pic16_newpCodeOpLit(0)));
294           return 1;
295         }
296       else
297         return 0;
298     }
299   else {
300     //printChar (oFile, s, strlen (s) + 1);
301
302     for(remain=0; remain<strlen(s); remain++) {
303       pic16_addpCode2pBlock(pb,pic16_newpCode(POC_RETLW,pic16_newpCodeOpLit(s[remain])));
304       //fprintf(stderr,"0x%02x ",s[remain]);
305     }
306     //fprintf(stderr,"\n");
307   }
308   return 1;
309 }
310
311 /*-----------------------------------------------------------------*/
312 /* printIvalArray - generates code for array initialization        */
313 /*-----------------------------------------------------------------*/
314 static void 
315 printIvalArray (symbol * sym, sym_link * type, initList * ilist,
316                 pBlock *pb)
317 {
318   initList *iloop;
319   int lcnt = 0, size = 0;
320
321   if(!pb)
322     return;
323
324   /* take care of the special   case  */
325   /* array of characters can be init  */
326   /* by a string                      */
327   if (IS_CHAR (type->next)) {
328     //fprintf(stderr,"%s:%d - is_char\n",__FUNCTION__,__LINE__);
329     if (!IS_LITERAL(list2val(ilist)->etype)) {
330       werror (W_INIT_WRONG);
331       return;
332     }
333     if (printIvalChar (type,
334                        (ilist->type == INIT_DEEP ? ilist->init.deep : ilist),
335                        pb, SPEC_CVAL (sym->etype).v_char))
336       return;
337   }
338   /* not the special case             */
339   if (ilist->type != INIT_DEEP)
340     {
341       werror (E_INIT_STRUCT, sym->name);
342       return;
343     }
344
345   iloop = ilist->init.deep;
346   lcnt = DCL_ELEM (type);
347
348   for (;;)
349     {
350       //fprintf(stderr,"%s:%d - is_char\n",__FUNCTION__,__LINE__);
351       size++;
352       printIval (sym, type->next, iloop, pb);
353       iloop = (iloop ? iloop->next : NULL);
354
355
356       /* if not array limits given & we */
357       /* are out of initialisers then   */
358       if (!DCL_ELEM (type) && !iloop)
359         break;
360
361       /* no of elements given and we    */
362       /* have generated for all of them */
363       if (!--lcnt) {
364         /* if initializers left */
365         if (iloop) {
366           werror (W_EXCESS_INITIALIZERS, "array", sym->name, sym->lineDef);
367         }
368         break;
369       }
370     }
371
372   /* if we have not been given a size  */
373   if (!DCL_ELEM (type))
374     DCL_ELEM (type) = size;
375
376   return;
377 }
378
379 /*-----------------------------------------------------------------*/
380 /* printIval - generates code for initial value                    */
381 /*-----------------------------------------------------------------*/
382 static void 
383 printIval (symbol * sym, sym_link * type, initList * ilist, pBlock *pb)
384 {
385   if (!ilist || !pb)
386     return;
387
388   /* if structure then    */
389   if (IS_STRUCT (type))
390     {
391       //fprintf(stderr,"%s struct\n",__FUNCTION__);
392       //printIvalStruct (sym, type, ilist, oFile);
393       return;
394     }
395
396   /* if this is a pointer */
397   if (IS_PTR (type))
398     {
399       //fprintf(stderr,"%s pointer\n",__FUNCTION__);
400       //printIvalPtr (sym, type, ilist, oFile);
401       return;
402     }
403
404   /* if this is an array   */
405   if (IS_ARRAY (type))
406     {
407       //fprintf(stderr,"%s array\n",__FUNCTION__);
408       printIvalArray (sym, type, ilist, pb);
409       return;
410     }
411
412   /* if type is SPECIFIER */
413   if (IS_SPEC (type))
414     {
415       //fprintf(stderr,"%s spec\n",__FUNCTION__);
416       printIvalType (sym, type, ilist, pb);
417       return;
418     }
419 }
420
421 extern void pic16_pCodeConstString(char *name, char *value);
422 /*-----------------------------------------------------------------*/
423 /* emitStaticSeg - emitcode for the static segment                 */
424 /*-----------------------------------------------------------------*/
425 static void
426 pic16emitStaticSeg (memmap * map)
427 {
428   symbol *sym;
429
430   fprintf (map->oFile, ";\t.area\t%s\n", map->sname);
431
432   //fprintf(stderr, "%s\n",__FUNCTION__);
433
434   /* for all variables in this segment do */
435   for (sym = setFirstItem (map->syms); sym;
436        sym = setNextItem (map->syms))
437     {
438       /* if it is "extern" then do nothing */
439       if (IS_EXTERN (sym->etype))
440         continue;
441
442       /* if it is not static add it to the public
443          table */
444       if (!IS_STATIC (sym->etype))
445         addSetHead (&publics, sym);
446
447 #if 0
448       /* print extra debug info if required */
449       if (options.debug || sym->level == 0)
450         {
451           /* NOTE to me - cdbFile may be null in which case,
452            * the sym name will be printed to stdout. oh well */
453           if(cdbFile)
454             cdbSymbol (sym, cdbFile, FALSE, FALSE);
455
456           if (!sym->level)
457             {                   /* global */
458               if (IS_STATIC (sym->etype))
459                 fprintf (code->oFile, "F%s_", moduleName);      /* scope is file */
460               else
461                 fprintf (code->oFile, "G_");    /* scope is global */
462             }
463           else
464             /* symbol is local */
465             fprintf (code->oFile, "L%s_",
466                      (sym->localof ? sym->localof->name : "-null-"));
467           fprintf (code->oFile, "%s_%d_%d", sym->name, sym->level, sym->block);
468
469         }
470 #endif
471
472       /* if it has an absolute address */
473       if (SPEC_ABSA (sym->etype))
474         {
475           if (options.debug || sym->level == 0)
476             fprintf (code->oFile, " == 0x%04x\n", SPEC_ADDR (sym->etype));
477
478           fprintf (code->oFile, "%s\t=\t0x%04x\n",
479                    sym->rname,
480                    SPEC_ADDR (sym->etype));
481         }
482       else
483         {
484           if (options.debug || sym->level == 0)
485             fprintf (code->oFile, " == .\n");
486
487           /* if it has an initial value */
488           if (sym->ival)
489             {
490               pBlock *pb;
491
492               fprintf (code->oFile, "%s:\n", sym->rname);
493               noAlloc++;
494               resolveIvalSym (sym->ival);
495               //printIval (sym, sym->type, sym->ival, code->oFile);
496               pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block for Ival"));
497               pic16_addpBlock(pb);
498               pic16_addpCode2pBlock(pb,pic16_newpCodeLabel(sym->rname,-1));
499
500               printIval (sym, sym->type, sym->ival, pb);
501               noAlloc--;
502             }
503           else
504             {
505
506               /* allocate space */
507               fprintf (code->oFile, "%s:\n", sym->rname);
508               /* special case for character strings */
509               if (IS_ARRAY (sym->type) && IS_CHAR (sym->type->next) &&
510                   SPEC_CVAL (sym->etype).v_char)
511                 pic16_pCodeConstString(sym->rname , SPEC_CVAL (sym->etype).v_char);
512                 /*printChar (code->oFile,
513                            SPEC_CVAL (sym->etype).v_char,
514                            strlen (SPEC_CVAL (sym->etype).v_char) + 1);*/
515               else
516                 fprintf (code->oFile, "\t.ds\t0x%04x\n", (unsigned int) getSize (sym->type) & 0xffff);
517             }
518         }
519     }
520
521 }
522
523
524 /*-----------------------------------------------------------------*/
525 /* emitMaps - emits the code for the data portion the code         */
526 /*-----------------------------------------------------------------*/
527 static void
528 pic16emitMaps ()
529 {
530   /* no special considerations for the following
531      data, idata & bit & xdata */
532   pic16emitRegularMap (data, TRUE, TRUE);
533   pic16emitRegularMap (idata, TRUE, TRUE);
534   pic16emitRegularMap (bit, TRUE, FALSE);
535   pic16emitRegularMap (xdata, TRUE, TRUE);
536   pic16emitRegularMap (sfr, FALSE, FALSE);
537   pic16emitRegularMap (sfrbit, FALSE, FALSE);
538   pic16emitRegularMap (code, TRUE, FALSE);
539   pic16emitStaticSeg (statsg);
540 }
541
542 /*-----------------------------------------------------------------*/
543 /* createInterruptVect - creates the interrupt vector              */
544 /*-----------------------------------------------------------------*/
545 static void
546 pic16createInterruptVect (FILE * vFile)
547 {
548   unsigned i = 0;
549   mainf = newSymbol ("main", 0);
550   mainf->block = 0;
551
552   /* only if the main function exists */
553   if (!(mainf = findSymWithLevel (SymbolTab, mainf)))
554     {
555       if (!options.cc_only)
556         werror (E_NO_MAIN);
557       return;
558     }
559
560   /* if the main is only a prototype ie. no body then do nothing */
561   if (!IFFUNC_HASBODY(mainf->type))
562     {
563       /* if ! compile only then main function should be present */
564       if (!options.cc_only)
565         werror (E_NO_MAIN);
566       return;
567     }
568
569 /*
570  * update started by Vangelis Rokas on 19-Jun-2003
571  * all fprintf() calls are prefixed with ';' so they seem
572  * as comments to the assembler. I (VR) removed them */
573
574 //  fprintf (vFile, "\t.area\t%s\n", CODE_NAME);
575         fprintf(vFile, "\tcode\t0x0000\n");
576   fprintf (vFile, "__interrupt_vect:\n");
577
578
579   if (!port->genIVT || !(port->genIVT (vFile, interrupts, maxInterrupts)))
580     {
581       /* "generic" interrupt table header (if port doesn't specify one).
582
583        * Look suspiciously like 8051 code to me...
584        */
585
586       fprintf (vFile, ";\tljmp\t__sdcc_gsinit_startup\n");
587
588
589       /* now for the other interrupts */
590       for (; i < maxInterrupts; i++)
591         {
592           if (interrupts[i])
593             fprintf (vFile, ";\tljmp\t%s\n;\t.ds\t5\n", interrupts[i]->rname);
594           else
595             fprintf (vFile, ";\treti\n;\t.ds\t7\n");
596         }
597     }
598 }
599
600
601 /*-----------------------------------------------------------------*/
602 /* initialComments - puts in some initial comments                 */
603 /*-----------------------------------------------------------------*/
604 static void
605 pic16initialComments (FILE * afile)
606 {
607   initialComments (afile);
608   fprintf (afile, "; PIC port for the 16-bit core\n");
609   fprintf (afile, iComments2);
610
611 }
612
613 /*-----------------------------------------------------------------*/
614 /* printPublics - generates .global for publics                    */
615 /*-----------------------------------------------------------------*/
616 static void
617 pic16printPublics (FILE * afile)
618 {
619   symbol *sym;
620
621   fprintf (afile, "%s", iComments2);
622   fprintf (afile, "; publics variables in this module\n");
623   fprintf (afile, "%s", iComments2);
624
625   for (sym = setFirstItem (publics); sym;
626        sym = setNextItem (publics))
627     fprintf (afile, ";\t.globl %s\n", sym->rname);
628 }
629
630
631
632 /*-----------------------------------------------------------------*/
633 /* emitOverlay - will emit code for the overlay stuff              */
634 /*-----------------------------------------------------------------*/
635 static void
636 pic16emitOverlay (FILE * afile)
637 {
638   set *ovrset;
639
640   if (!elementsInSet (ovrSetSets))
641     fprintf (afile, ";\t.area\t%s\n", port->mem.overlay_name);
642
643   /* for each of the sets in the overlay segment do */
644   for (ovrset = setFirstItem (ovrSetSets); ovrset;
645        ovrset = setNextItem (ovrSetSets))
646     {
647
648       symbol *sym;
649
650       if (elementsInSet (ovrset))
651         {
652           /* this dummy area is used to fool the assembler
653              otherwise the assembler will append each of these
654              declarations into one chunk and will not overlay
655              sad but true */
656           fprintf (afile, ";\t.area _DUMMY\n");
657           /* output the area informtion */
658           fprintf (afile, ";\t.area\t%s\n", port->mem.overlay_name);    /* MOF */
659         }
660
661       for (sym = setFirstItem (ovrset); sym;
662            sym = setNextItem (ovrset))
663         {
664
665           /* if extern then do nothing */
666           if (IS_EXTERN (sym->etype))
667             continue;
668
669           /* if allocation required check is needed
670              then check if the symbol really requires
671              allocation only for local variables */
672           if (!IS_AGGREGATE (sym->type) &&
673               !(sym->_isparm && !IS_REGPARM (sym->etype))
674               && !sym->allocreq && sym->level)
675             continue;
676
677           /* if global variable & not static or extern
678              and addPublics allowed then add it to the public set */
679           if ((sym->_isparm && !IS_REGPARM (sym->etype))
680               && !IS_STATIC (sym->etype))
681             addSetHead (&publics, sym);
682
683           /* if extern then do nothing or is a function
684              then do nothing */
685           if (IS_FUNC (sym->type))
686             continue;
687
688 #if 0
689           /* print extra debug info if required */
690           if (options.debug || sym->level == 0)
691             {
692
693               cdbSymbol (sym, cdbFile, FALSE, FALSE);
694
695               if (!sym->level)
696                 {               /* global */
697                   if (IS_STATIC (sym->etype))
698                     fprintf (afile, "F%s_", moduleName);        /* scope is file */
699                   else
700                     fprintf (afile, "G_");      /* scope is global */
701                 }
702               else
703                 /* symbol is local */
704                 fprintf (afile, "L%s_",
705                          (sym->localof ? sym->localof->name : "-null-"));
706               fprintf (afile, "%s_%d_%d", sym->name, sym->level, sym->block);
707             }
708 #endif
709
710           /* if is has an absolute address then generate
711              an equate for this no need to allocate space */
712           if (SPEC_ABSA (sym->etype))
713             {
714
715               if (options.debug || sym->level == 0)
716                 fprintf (afile, " == 0x%04x\n", SPEC_ADDR (sym->etype));
717
718               fprintf (afile, "%s\t=\t0x%04x\n",
719                        sym->rname,
720                        SPEC_ADDR (sym->etype));
721             }
722           else
723             {
724               if (options.debug || sym->level == 0)
725                 fprintf (afile, "==.\n");
726
727               /* allocate space */
728               fprintf (afile, "%s:\n", sym->rname);
729               fprintf (afile, "\t.ds\t0x%04x\n", (unsigned int) getSize (sym->type) & 0xffff);
730             }
731
732         }
733     }
734 }
735
736
737 /*-----------------------------------------------------------------*/
738 /* glue - the final glue that hold the whole thing together        */
739 /*-----------------------------------------------------------------*/
740 void
741 pic16glue ()
742 {
743
744   FILE *vFile;
745   FILE *asmFile;
746   FILE *ovrFile = tempfile();
747
748   addSetHead(&tmpfileSet,ovrFile);
749   pic16_pCodeInitRegisters();
750
751   if (mainf && IFFUNC_HASBODY(mainf->type)) {
752
753     pBlock *pb = pic16_newpCodeChain(NULL,'X',pic16_newpCodeCharP("; Starting pCode block"));
754     pic16_addpBlock(pb);
755
756     /* entry point @ start of CSEG */
757     pic16_addpCode2pBlock(pb,pic16_newpCodeLabel("__sdcc_program_startup",-1));
758     /* put in the call to main */
759     pic16_addpCode2pBlock(pb,pic16_newpCode(POC_CALL,pic16_newpCodeOp("_main",PO_STR)));
760
761     if (options.mainreturn) {
762
763       pic16_addpCode2pBlock(pb,pic16_newpCodeCharP(";\treturn from main will return to caller\n"));
764       pic16_addpCode2pBlock(pb,pic16_newpCode(POC_RETURN,NULL));
765
766     } else {
767
768       pic16_addpCode2pBlock(pb,pic16_newpCodeCharP(";\treturn from main will lock up\n"));
769       pic16_addpCode2pBlock(pb,pic16_newpCode(POC_GOTO,pic16_newpCodeOp("$",PO_STR)));
770
771     }
772   }
773
774
775   /* At this point we've got all the code in the form of pCode structures */
776   /* Now it needs to be rearranged into the order it should be placed in the */
777   /* code space */
778
779   pic16_movepBlock2Head('P');              // Last
780   pic16_movepBlock2Head(code->dbName);
781   pic16_movepBlock2Head('X');
782   pic16_movepBlock2Head(statsg->dbName);   // First
783
784
785   /* print the global struct definitions */
786   if (options.debug)
787     cdbStructBlock (0); //,cdbFile);
788
789   vFile = tempfile();
790   /* PENDING: this isnt the best place but it will do */
791   if (port->general.glue_up_main) {
792     /* create the interrupt vector table */
793     pic16createInterruptVect (vFile);
794   }
795
796   addSetHead(&tmpfileSet,vFile);
797     
798   /* emit code for the all the variables declared */
799   pic16emitMaps ();
800   /* do the overlay segments */
801   pic16emitOverlay(ovrFile);
802
803
804         pic16_AnalyzepCode('*');
805
806   //#ifdef PCODE_DEBUG
807   //pic16_printCallTree(stderr);
808   //#endif
809
810   pic16_InlinepCode();
811
812   pic16_AnalyzepCode('*');
813
814   pic16_pcode_test();
815
816
817   /* now put it all together into the assembler file */
818   /* create the assembler file name */
819     
820   if ((noAssemble || options.c1mode)  && fullDstFileName)
821     {
822       sprintf (buffer, fullDstFileName);
823     }
824   else
825     {
826       sprintf (buffer, dstFileName);
827       strcat (buffer, ".asm");
828     }
829
830   if (!(asmFile = fopen (buffer, "w"))) {
831     werror (E_FILE_OPEN_ERR, buffer);
832     exit (1);
833   }
834     
835   /* initial comments */
836   pic16initialComments (asmFile);
837     
838   /* print module name */
839   fprintf (asmFile, ";\t.module %s\n", moduleName);
840     
841   /* Let the port generate any global directives, etc. */
842   if (port->genAssemblerPreamble)
843     {
844       port->genAssemblerPreamble(asmFile);
845     }
846     
847   /* print the global variables in this module */
848   pic16printPublics (asmFile);
849     
850
851   /* copy the sfr segment */
852   fprintf (asmFile, "%s", iComments2);
853   fprintf (asmFile, "; special function registers\n");
854   fprintf (asmFile, "%s", iComments2);
855   copyFile (asmFile, sfr->oFile);
856     
857
858   /* Put all variables into a cblock */
859   pic16_AnalyzeBanking();
860   pic16_writeUsedRegs(asmFile);
861
862   /* create the overlay segments */
863   fprintf (asmFile, "%s", iComments2);
864   fprintf (asmFile, "; overlayable items in internal ram \n");
865   fprintf (asmFile, "%s", iComments2);    
866   copyFile (asmFile, ovrFile);
867
868   /* create the stack segment MOF */
869   if (mainf && IFFUNC_HASBODY(mainf->type)) {
870     fprintf (asmFile, "%s", iComments2);
871     fprintf (asmFile, "; Stack segment in internal ram \n");
872     fprintf (asmFile, "%s", iComments2);    
873     fprintf (asmFile, ";\t.area\tSSEG\t(DATA)\n"
874              ";__start__stack:\n;\t.ds\t1\n\n");
875   }
876
877   /* create the idata segment */
878   fprintf (asmFile, "%s", iComments2);
879   fprintf (asmFile, "; indirectly addressable internal ram data\n");
880   fprintf (asmFile, "%s", iComments2);
881   copyFile (asmFile, idata->oFile);
882     
883   /* if external stack then reserve space of it */
884   if (mainf && IFFUNC_HASBODY(mainf->type) && options.useXstack ) {
885     fprintf (asmFile, "%s", iComments2);
886     fprintf (asmFile, "; external stack \n");
887     fprintf (asmFile, "%s", iComments2);
888     fprintf (asmFile,";\t.area XSEG (XDATA)\n"); /* MOF */
889     fprintf (asmFile,";\t.ds 256\n");
890   }
891         
892         
893   /* copy xtern ram data */
894   fprintf (asmFile, "%s", iComments2);
895   fprintf (asmFile, "; external ram data\n");
896   fprintf (asmFile, "%s", iComments2);
897   copyFile (asmFile, xdata->oFile);
898     
899
900   /* copy the bit segment */
901   fprintf (asmFile, "%s", iComments2);
902   fprintf (asmFile, "; bit data\n");
903   fprintf (asmFile, "%s", iComments2);
904   copyFile (asmFile, bit->oFile);
905
906
907 /* the following is commented out. the CODE directive will be
908    used instead before code */
909    
910 //  fprintf (asmFile, "\tORG 0\n");
911
912   /* copy the interrupt vector table */
913   if (mainf && IFFUNC_HASBODY(mainf->type)) {
914     fprintf (asmFile, "%s", iComments2);
915     fprintf (asmFile, "; interrupt vector \n");
916     fprintf (asmFile, "%s", iComments2);
917     copyFile (asmFile, vFile);
918   }
919     
920   /* copy global & static initialisations */
921   fprintf (asmFile, "%s", iComments2);
922   fprintf (asmFile, "; global & static initialisations\n");
923   fprintf (asmFile, "%s", iComments2);
924     
925   /* Everywhere we generate a reference to the static_name area, 
926    * (which is currently only here), we immediately follow it with a 
927    * definition of the post_static_name area. This guarantees that
928    * the post_static_name area will immediately follow the static_name
929    * area.
930    */
931   fprintf (asmFile, ";\t.area %s\n", port->mem.static_name); /* MOF */
932   fprintf (asmFile, ";\t.area %s\n", port->mem.post_static_name);
933   fprintf (asmFile, ";\t.area %s\n", port->mem.static_name);
934
935   if (mainf && IFFUNC_HASBODY(mainf->type)) {
936     fprintf (asmFile,"__sdcc_gsinit_startup:\n");
937
938 #if 0
939         /* 8051 legacy (?!) - VR 20-Jun-2003 */
940     /* if external stack is specified then the
941        higher order byte of the xdatalocation is
942        going into P2 and the lower order going into
943        spx */
944     if (options.useXstack) {
945       fprintf(asmFile,";\tmov\tP2,#0x%02x\n",
946               (((unsigned int)options.xdata_loc) >> 8) & 0xff);
947       fprintf(asmFile,";\tmov\t_spx,#0x%02x\n",
948               (unsigned int)options.xdata_loc & 0xff);
949     }
950 #endif
951
952   }
953
954   if (port->general.glue_up_main && mainf && IFFUNC_HASBODY(mainf->type))
955     {
956       /* This code is generated in the post-static area.
957        * This area is guaranteed to follow the static area
958        * by the ugly shucking and jiving about 20 lines ago.
959        */
960       fprintf(asmFile, ";\t.area %s\n", port->mem.post_static_name);
961       fprintf (asmFile,"\tgoto\t__sdcc_program_startup\n");
962     }
963         
964   /* copy over code */
965   fprintf (asmFile, "%s", iComments2);
966   fprintf (asmFile, "; code\n");
967   fprintf (asmFile, "%s", iComments2);
968   fprintf (asmFile, ";\t.area %s\n", port->mem.code_name);
969
970   //copyFile (stderr, code->oFile);
971
972 //              fprintf(asmFile, "; I code from now on!\n");
973         pic16_copypCode(asmFile, 'I');
974
975         
976 //              fprintf(asmFile, "; dbName from now on!\n");
977         fprintf(asmFile, "__sdcc_program_startup:\n");
978         pic16_copypCode(asmFile, statsg->dbName);
979
980                 fprintf(asmFile, "; X code from now on!\n");
981         pic16_copypCode(asmFile, 'X');
982                 fprintf(asmFile, "; M code from now on!\n");
983         pic16_copypCode(asmFile, 'M');
984         pic16_copypCode(asmFile, code->dbName);
985         pic16_copypCode(asmFile, 'P');
986
987         fprintf (asmFile,"\tend\n");
988
989         fclose (asmFile);
990
991         rm_tmpfiles();
992 }