586f7dc2c785c64b01669bc10645221c3001bfce
[fw/sdcc] / src / pic / glue.c
1 /*-------------------------------------------------------------------------
2
3   SDCCglue.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 "glue.h"
26 #include "dbuf_string.h"
27
28 #include "device.h"
29 #include "gen.h"
30 #include "main.h"
31
32 /*
33  * Imports
34  */
35 extern set *publics;
36 extern set *externs;
37 extern symbol *mainf;
38 extern struct dbuf_s *codeOutBuf;
39
40 extern DEFSETFUNC(closeTmpFiles);
41 extern DEFSETFUNC(rmTmpFiles);
42 extern void initialComments(FILE *afile);
43 extern operand *operandFromAst(ast *tree, int lvl);
44 extern value *initPointer(initList *ilist, sym_link *toType);
45
46
47 set *pic14_localFunctions = NULL;
48 int pic14_hasInterrupt = 0;             // Indicates whether to emit interrupt handler or not
49
50 int pic14_stringInSet(const char *str, set **world, int autoAdd);
51
52
53 #ifdef WORDS_BIGENDIAN
54 #define _ENDIAN(x)  (3-x)
55 #else
56 #define _ENDIAN(x)  (x)
57 #endif
58
59 #define BYTE_IN_LONG(x,b) ((x>>(8*_ENDIAN(b)))&0xff)
60 #define IS_GLOBAL(sym)  ((sym)->level == 0)
61 #define IS_DEFINED_HERE(sym)    (!IS_EXTERN(sym->etype))
62
63 /* dbufs for initialized data (idata and code sections),
64  * extern, and global declarations */
65 static struct dbuf_s *ivalBuf, *extBuf, *gloBuf, *gloDefBuf;
66
67 static set *emitted = NULL;
68
69 static void showAllMemmaps(FILE *of); // XXX: emits initialized symbols
70
71 static void
72 emitPseudoStack(struct dbuf_s *oBuf, struct dbuf_s *oBufExt)
73 {
74     int shared, low, high, size, i;
75     PIC_device *pic;
76
77     /* also emit STK symbols
78      * XXX: This is ugly and fails as soon as devices start to get
79      *      differently sized sharebanks, since STK12 will be
80      *      required by larger devices but only up to STK03 might
81      *      be defined using smaller devices. */
82     shared = pic14_getSharedStack(&low, &high, &size);
83     if (!pic14_options.isLibrarySource)
84     {
85         pic = pic14_getPIC();
86
87         dbuf_printf (oBuf, "\n");
88         dbuf_printf (oBuf, "\tglobal PSAVE\n");
89         dbuf_printf (oBuf, "\tglobal SSAVE\n");
90         dbuf_printf (oBuf, "\tglobal WSAVE\n");
91         for (i = size - 4; i >= 0; i--) {
92             dbuf_printf (oBuf, "\tglobal STK%02d\n", i);
93         } // for i
94         dbuf_printf (oBuf, "\n");
95
96         // 16f84 has no SHAREBANK (in linkerscript) but memory aliased in two
97         // banks, sigh...
98         if (1 || !shared) {
99             // for single banked devices: use normal, "banked" RAM
100             dbuf_printf (oBuf, "sharebank udata_ovr 0x%04X\n", low);
101         } else {
102             // for devices with at least two banks, require a sharebank section
103             dbuf_printf (oBuf, "sharebank udata_shr\n");
104         }
105         dbuf_printf (oBuf, "PSAVE\tres 1\n");
106         dbuf_printf (oBuf, "SSAVE\tres 1\n");
107         dbuf_printf (oBuf, "WSAVE\tres 1\n"); // WSAVE *must* be in sharebank (IRQ handlers)
108         /* fill rest of sharebank with stack STKxx .. STK00 */
109         for (i = size - 4; i >= 0; i--) {
110             dbuf_printf (oBuf, "STK%02d\tres 1\n", i);
111         } // for i
112     } else {
113         /* declare STKxx as extern for all files
114          * except the one containing main() */
115         dbuf_printf (oBufExt, "\n");
116         dbuf_printf (oBufExt, "\textern PSAVE\n");
117         dbuf_printf (oBufExt, "\textern SSAVE\n");
118         dbuf_printf (oBufExt, "\textern WSAVE\n");
119         for (i = size - 4; i >= 0; i--) {
120             char buffer[128];
121             SNPRINTF(&buffer[0], 127, "STK%02d", i);
122             dbuf_printf (oBufExt, "\textern %s\n", &buffer[0]);
123             pic14_stringInSet(&buffer[0], &emitted, 1);
124         } // for i
125     }
126     dbuf_printf (oBuf, "\n");
127 }
128
129 static int
130 emitIfNew(struct dbuf_s *oBuf, set **emitted, const char *fmt,
131         const char *name)
132 {
133     int wasPresent = pic14_stringInSet(name, emitted, 1);
134
135     if (!wasPresent) {
136         dbuf_printf (oBuf, fmt, name);
137     } // if
138     return (!wasPresent);
139 }
140
141 static void
142 pic14_constructAbsMap (struct dbuf_s *oBuf, struct dbuf_s *gloBuf)
143 {
144   memmap *maps[] = { data, sfr, NULL };
145   int i;
146   hTab *ht = NULL;
147   symbol *sym;
148   set *aliases;
149   int addr, min=-1, max=-1;
150   int size;
151
152   for (i=0; maps[i] != NULL; i++)
153   {
154     for (sym = (symbol *)setFirstItem (maps[i]->syms);
155         sym; sym = setNextItem (maps[i]->syms))
156     {
157       if (IS_DEFINED_HERE(sym) && SPEC_ABSA(sym->etype))
158       {
159         addr = SPEC_ADDR(sym->etype);
160
161         /* handle CONFIG words here */
162         if (IS_CONFIG_ADDRESS( addr ))
163         {
164           //fprintf( stderr, "%s: assignment to CONFIG@0x%x found\n", __FUNCTION__, addr );
165           //fprintf( stderr, "ival: %p (0x%x)\n", sym->ival, (int)list2int( sym->ival ) );
166           if (sym->ival) {
167             pic14_assignConfigWordValue( addr, (int)list2int( sym->ival ) );
168           } else {
169             fprintf( stderr, "ERROR: Symbol %s, which is covering a __CONFIG word must be initialized!\n", sym->name );
170           }
171           continue;
172         }
173
174         if (max == -1 || addr > max) max = addr;
175         if (min == -1 || addr < min) min = addr;
176         //fprintf (stderr, "%s: sym %s @ 0x%x\n", __FUNCTION__, sym->name, addr);
177         aliases = hTabItemWithKey (ht, addr);
178         if (aliases) {
179           /* May not use addSetHead, as we cannot update the
180            * list's head in the hastable `ht'. */
181           addSet (&aliases, sym);
182 #if 0
183           fprintf( stderr, "%s: now %d aliases for %s @ 0x%x\n",
184               __FUNCTION__, elementsInSet(aliases), sym->name, addr);
185 #endif
186         } else {
187           addSet (&aliases, sym);
188           hTabAddItem (&ht, addr, aliases);
189         } // if
190       } // if
191     } // for sym
192   } // for i
193
194   /* now emit definitions for all absolute symbols */
195   dbuf_printf (oBuf, "%s", iComments2);
196   dbuf_printf (oBuf, "; absolute symbol definitions\n");
197   dbuf_printf (oBuf, "%s", iComments2);
198   for (addr=min; addr <= max; addr++)
199   {
200     size = 1;
201     aliases = hTabItemWithKey (ht, addr);
202     if (aliases && elementsInSet(aliases)) {
203       /* Make sure there is no initialized value at this location! */
204       for (sym = setFirstItem(aliases); sym; sym = setNextItem(aliases)) {
205           if (sym->ival) break;
206       } // for
207       if (sym) continue;
208
209       dbuf_printf (oBuf, "UD_abs_%s_%x\tudata_ovr\t0x%04x\n",
210           moduleName, addr, addr);
211       for (sym = setFirstItem (aliases); sym;
212           sym = setNextItem (aliases))
213       {
214         if (getSize(sym->type) > size) {
215           size = getSize(sym->type);
216         }
217
218         /* initialized values are handled somewhere else */
219         if (sym->ival) continue;
220
221         /* emit STATUS as well as _STATUS, required for SFRs only */
222         //dbuf_printf (oBuf, "%s\tres\t0\n", sym->name);
223         dbuf_printf (oBuf, "%s\n", sym->rname);
224
225         if (IS_GLOBAL(sym) && !IS_STATIC(sym->etype)) {
226             //emitIfNew(gloBuf, &emitted, "\tglobal\t%s\n", sym->name);
227             emitIfNew(gloBuf, &emitted, "\tglobal\t%s\n", sym->rname);
228         } // if
229       } // for
230       dbuf_printf (oBuf, "\tres\t%d\n", size);
231     } // if
232   } // for i
233 }
234
235 /*-----------------------------------------------------------------*/
236 /* createInterruptVect - creates the interrupt vector              */
237 /*-----------------------------------------------------------------*/
238 static void
239 pic14createInterruptVect (struct dbuf_s * vBuf)
240 {
241         mainf = newSymbol ("main", 0);
242         mainf->block = 0;
243
244         /* only if the main function exists */
245         if (!(mainf = findSymWithLevel (SymbolTab, mainf)))
246         {
247                 struct options *op = &options;
248                 if (!(op->cc_only || noAssemble))
249                         //      werror (E_NO_MAIN);
250                         fprintf(stderr,"WARNING: function 'main' undefined\n");
251                 return;
252         }
253
254         /* if the main is only a prototype ie. no body then do nothing */
255         if (!IFFUNC_HASBODY(mainf->type))
256         {
257                 /* if ! compile only then main function should be present */
258                 if (!(options.cc_only || noAssemble))
259                         //      werror (E_NO_MAIN);
260                         fprintf(stderr,"WARNING: function 'main' undefined\n");
261                 return;
262         }
263
264         dbuf_printf (vBuf, "%s", iComments2);
265         dbuf_printf (vBuf, "; reset vector \n");
266         dbuf_printf (vBuf, "%s", iComments2);
267         dbuf_printf (vBuf, "STARTUP\t%s\n", CODE_NAME); // Lkr file should place section STARTUP at address 0x0
268         dbuf_printf (vBuf, "\tnop\n"); /* first location for used by incircuit debugger */
269         dbuf_printf (vBuf, "\tpagesel __sdcc_gsinit_startup\n");
270         dbuf_printf (vBuf, "\tgoto\t__sdcc_gsinit_startup\n");
271         popGetExternal("__sdcc_gsinit_startup", 0);
272 }
273
274
275 /*-----------------------------------------------------------------*/
276 /* initialComments - puts in some initial comments                 */
277 /*-----------------------------------------------------------------*/
278 static void
279 pic14initialComments (FILE * afile)
280 {
281         initialComments (afile);
282         fprintf (afile, "; PIC port for the 14-bit core\n");
283         fprintf (afile, "%s", iComments2);
284
285 }
286
287 int
288 pic14_stringInSet(const char *str, set **world, int autoAdd)
289 {
290   char *s;
291
292   if (!str) return 1;
293   assert(world);
294
295   for (s = setFirstItem(*world); s; s = setNextItem(*world))
296   {
297     /* found in set */
298     if (0 == strcmp(s, str)) return 1;
299   }
300
301   /* not found */
302   if (autoAdd) addSet(world, Safe_strdup(str));
303   return 0;
304 }
305
306 static void
307 pic14printLocals (struct dbuf_s *oBuf)
308 {
309     set *allregs[6] = { dynAllocRegs/*, dynStackRegs, dynProcessorRegs*/,
310         dynDirectRegs, dynDirectBitRegs/*, dynInternalRegs */ };
311     regs *reg;
312     int i, is_first = 1;
313     static unsigned sectionNr = 0;
314
315     /* emit all registers from all possible sets */
316     for (i = 0; i < 6; i++) {
317         if (allregs[i] == NULL) continue;
318
319         for (reg = setFirstItem(allregs[i]); reg; reg = setNextItem(allregs[i])) {
320             if (reg->isEmitted) continue;
321
322             if (reg->wasUsed && !reg->isExtern) {
323                 if (!pic14_stringInSet(reg->name, &emitted, 1)) {
324                     if (reg->isFixed) {
325                         // Should not happen, really...
326                         assert ( !"Compiler-assigned variables should not be pinned... This is a bug." );
327                         dbuf_printf(oBuf, "UDL_%s_%u\tudata\t0x%04X\n%s\tres\t%d\n",
328                                 moduleName, sectionNr++, reg->address, reg->name, reg->size);
329                     } else {
330                         if (getenv("SDCC_PIC14_SPLIT_LOCALS")) {
331                             // assign each local register into its own section
332                             dbuf_printf(oBuf, "UDL_%s_%u\tudata\n%s\tres\t%d\n",
333                                     moduleName, sectionNr++, reg->name, reg->size);
334                         } else {
335                             // group all local registers into a single section
336                             // This should greatly improve BANKSEL generation...
337                             if (is_first) {
338                                 dbuf_printf(oBuf, "UDL_%s_%u\tudata\n", moduleName, sectionNr++);
339                                 is_first = 0;
340                             }
341                             dbuf_printf(oBuf, "%s\tres\t%d\n", reg->name, reg->size);
342                         }
343                     }
344                 }
345             }
346             reg->isEmitted = 1;
347         } // for
348     } // for
349 }
350
351 /*-----------------------------------------------------------------*/
352 /* emitOverlay - will emit code for the overlay stuff              */
353 /*-----------------------------------------------------------------*/
354 static void
355 pic14emitOverlay (struct dbuf_s * aBuf)
356 {
357         set *ovrset;
358
359         /*  if (!elementsInSet (ovrSetSets))*/
360
361         /* the hack below, fixes translates for devices which
362         * only have udata_shr memory */
363         dbuf_printf (aBuf, "%s\t%s\n",
364                 (elementsInSet(ovrSetSets)?"":";"),
365                 port->mem.overlay_name);
366
367         /* for each of the sets in the overlay segment do */
368         for (ovrset = setFirstItem (ovrSetSets); ovrset;
369         ovrset = setNextItem (ovrSetSets))
370         {
371
372                 symbol *sym;
373
374                 if (elementsInSet (ovrset))
375                 {
376                 /* this dummy area is used to fool the assembler
377                 otherwise the assembler will append each of these
378                 declarations into one chunk and will not overlay
379                         sad but true */
380
381                         /* I don't think this applies to us. We are using gpasm.  CRF */
382
383                         dbuf_printf (aBuf, ";\t.area _DUMMY\n");
384                         /* output the area informtion */
385                         dbuf_printf (aBuf, ";\t.area\t%s\n", port->mem.overlay_name);   /* MOF */
386                 }
387
388                 for (sym = setFirstItem (ovrset); sym;
389                 sym = setNextItem (ovrset))
390                 {
391
392                         /* if extern then do nothing */
393                         if (IS_EXTERN (sym->etype))
394                                 continue;
395
396                                 /* if allocation required check is needed
397                                 then check if the symbol really requires
398                         allocation only for local variables */
399                         if (!IS_AGGREGATE (sym->type) &&
400                                 !(sym->_isparm && !IS_REGPARM (sym->etype))
401                                 && !sym->allocreq && sym->level)
402                                 continue;
403
404                                 /* if global variable & not static or extern
405                         and addPublics allowed then add it to the public set */
406                         if ((sym->_isparm && !IS_REGPARM (sym->etype))
407                                 && !IS_STATIC (sym->etype))
408                                 addSetHead (&publics, sym);
409
410                                 /* if extern then do nothing or is a function
411                         then do nothing */
412                         if (IS_FUNC (sym->type))
413                                 continue;
414
415                         /* print extra debug info if required */
416                         if (options.debug || sym->level == 0)
417                         {
418                                 if (!sym->level)
419                                 {               /* global */
420                                         if (IS_STATIC (sym->etype))
421                                                 dbuf_printf (aBuf, "F%s_", moduleName); /* scope is file */
422                                         else
423                                                 dbuf_printf (aBuf, "G_");       /* scope is global */
424                                 }
425                                 else
426                                         /* symbol is local */
427                                         dbuf_printf (aBuf, "L%s_",
428                                         (sym->localof ? sym->localof->name : "-null-"));
429                                 dbuf_printf (aBuf, "%s_%d_%d", sym->name, sym->level, sym->block);
430                         }
431
432                         /* if is has an absolute address then generate
433                         an equate for this no need to allocate space */
434                         if (SPEC_ABSA (sym->etype))
435                         {
436
437                                 if (options.debug || sym->level == 0)
438                                         dbuf_printf (aBuf, " == 0x%04x\n", SPEC_ADDR (sym->etype));
439
440                                 dbuf_printf (aBuf, "%s\t=\t0x%04x\n",
441                                         sym->rname,
442                                         SPEC_ADDR (sym->etype));
443                         }
444                         else
445                         {
446                                 if (options.debug || sym->level == 0)
447                                         dbuf_printf (aBuf, "==.\n");
448
449                                 /* allocate space */
450                                 dbuf_printf (aBuf, "%s:\n", sym->rname);
451                                 dbuf_printf (aBuf, "\t.ds\t0x%04x\n", (unsigned int) getSize (sym->type) & 0xffff);
452                         }
453
454                 }
455         }
456 }
457
458
459 static void
460 pic14_emitInterruptHandler (FILE * asmFile)
461 {
462         if (pic14_hasInterrupt)
463         {
464
465                 fprintf (asmFile, "%s", iComments2);
466                 fprintf (asmFile, "; interrupt and initialization code\n");
467                 fprintf (asmFile, "%s", iComments2);
468                 // Note - for mplink may have to enlarge section vectors in .lnk file
469                 // Note: Do NOT name this code_interrupt to avoid nameclashes with
470                 //       source files's code segment (interrupt.c -> code_interrupt)
471                 fprintf (asmFile, "c_interrupt\t%s\t0x4\n", CODE_NAME);
472
473                 /* interrupt service routine */
474                 fprintf (asmFile, "__sdcc_interrupt\n");
475                 copypCode(asmFile, 'I');
476         }
477 }
478
479 /*-----------------------------------------------------------------*/
480 /* glue - the final glue that hold the whole thing together        */
481 /*-----------------------------------------------------------------*/
482 void
483 picglue ()
484 {
485         FILE *asmFile;
486         struct dbuf_s ovrBuf;
487         struct dbuf_s vBuf;
488
489         dbuf_init(&ovrBuf, 4096);
490         dbuf_init(&vBuf, 4096);
491
492         pCodeInitRegisters();
493
494         /* check for main() */
495         mainf = newSymbol ("main", 0);
496         mainf->block = 0;
497         mainf = findSymWithLevel (SymbolTab, mainf);
498
499         if (!mainf || !IFFUNC_HASBODY(mainf->type))
500         {
501                 /* main missing -- import stack from main module */
502                 //fprintf (stderr, "main() missing -- assuming we are NOT the main module\n");
503                 pic14_options.isLibrarySource = 1;
504         }
505
506         /* At this point we've got all the code in the form of pCode structures */
507         /* Now it needs to be rearranged into the order it should be placed in the */
508         /* code space */
509
510         movepBlock2Head('P');              // Last
511         movepBlock2Head(code->dbName);
512         movepBlock2Head('X');
513         movepBlock2Head(statsg->dbName);   // First
514
515
516         /* print the global struct definitions */
517         if (options.debug)
518                 cdbStructBlock (0);
519
520         /* do the overlay segments */
521         pic14emitOverlay(&ovrBuf);
522
523         /* PENDING: this isnt the best place but it will do */
524         if (port->general.glue_up_main) {
525                 /* create the interrupt vector table */
526                 pic14createInterruptVect (&vBuf);
527         }
528
529         AnalyzepCode('*');
530
531         ReuseReg(); // ReuseReg where call tree permits
532
533         InlinepCode();
534
535         AnalyzepCode('*');
536
537         if (options.debug) pcode_test();
538
539
540         /* now put it all together into the assembler file */
541         /* create the assembler file name */
542
543         if ((noAssemble || options.c1mode) && fullDstFileName)
544         {
545                 sprintf (buffer, "%s", fullDstFileName);
546         }
547         else
548         {
549                 sprintf (buffer, "%s", dstFileName);
550                 strcat (buffer, ".asm");
551         }
552
553         if (!(asmFile = fopen (buffer, "w"))) {
554                 werror (E_FILE_OPEN_ERR, buffer);
555                 exit (1);
556         }
557
558         /* prepare statistics */
559         resetpCodeStatistics ();
560
561         /* initial comments */
562         pic14initialComments (asmFile);
563
564         /* print module name */
565         fprintf (asmFile, "%s\t.file\t\"%s\"\n",
566             options.debug ? "" : ";", fullSrcFileName);
567
568         /* Let the port generate any global directives, etc. */
569         if (port->genAssemblerPreamble)
570         {
571                 port->genAssemblerPreamble(asmFile);
572         }
573
574         /* Put all variables into a cblock */
575         AnalyzeBanking();
576
577         /* emit initialized data */
578         showAllMemmaps(asmFile);
579
580         /* print the locally defined variables in this module */
581         writeUsedRegs(asmFile);
582
583         /* create the overlay segments */
584         fprintf (asmFile, "%s", iComments2);
585         fprintf (asmFile, "; overlayable items in internal ram \n");
586         fprintf (asmFile, "%s", iComments2);
587         dbuf_write_and_destroy (&ovrBuf, asmFile);
588
589         /* copy the interrupt vector table */
590         if (mainf && IFFUNC_HASBODY(mainf->type))
591           dbuf_write_and_destroy (&vBuf, asmFile);
592         else
593           dbuf_destroy(&vBuf);
594
595         /* create interupt ventor handler */
596         pic14_emitInterruptHandler (asmFile);
597
598         /* copy over code */
599         fprintf (asmFile, "%s", iComments2);
600         fprintf (asmFile, "; code\n");
601         fprintf (asmFile, "%s", iComments2);
602         fprintf (asmFile, "code_%s\t%s\n", moduleName, port->mem.code_name);
603
604         /* unknown */
605         copypCode(asmFile, 'X');
606
607         /* _main function */
608         copypCode(asmFile, 'M');
609
610         /* other functions */
611         copypCode(asmFile, code->dbName);
612
613         /* unknown */
614         copypCode(asmFile, 'P');
615
616         dumppCodeStatistics (asmFile);
617
618         fprintf (asmFile,"\tend\n");
619
620         fclose (asmFile);
621         pic14_debugLogClose();
622 }
623
624 /*
625  * Deal with initializers.
626  */
627 #undef DEBUGprintf
628 #if 0
629 // debugging output
630 #define DEBUGprintf printf
631 #else
632 // be quiet
633 #define DEBUGprintf 1 ? (void)0 : (void)printf
634 #endif
635
636 static char *
637 parseIvalAst (ast *node, int *inCodeSpace) {
638 #define LEN 4096
639     char *buffer = NULL;
640     char *left, *right;
641
642     if (IS_AST_VALUE(node)) {
643         value *val = AST_VALUE(node);
644         symbol *sym = IS_AST_SYM_VALUE(node) ? AST_SYMBOL(node) : NULL;
645         if (inCodeSpace && val->type
646                 && (IS_FUNC(val->type) || IS_CODE(getSpec(val->type))))
647         {
648             *inCodeSpace = 1;
649         }
650         if (inCodeSpace && sym
651                 && (IS_FUNC(sym->type)
652                     || IS_CODE(getSpec(sym->type))))
653         {
654             *inCodeSpace = 1;
655         }
656
657         DEBUGprintf ("%s: AST_VALUE\n", __FUNCTION__);
658         if (IS_AST_LIT_VALUE(node)) {
659             buffer = Safe_alloc(LEN);
660             SNPRINTF(buffer, LEN, "0x%lx", AST_ULONG_VALUE (node));
661         } else if (IS_AST_SYM_VALUE(node)) {
662             assert ( AST_SYMBOL(node) );
663             /*
664             printf ("sym %s: ", AST_SYMBOL(node)->rname);
665             printTypeChain(AST_SYMBOL(node)->type, stdout);
666             printTypeChain(AST_SYMBOL(node)->etype, stdout);
667             printf ("\n---sym %s: done\n", AST_SYMBOL(node)->rname);
668             */
669             buffer = Safe_strdup(AST_SYMBOL(node)->rname);
670         } else {
671             assert ( !"Invalid values type for initializers in AST." );
672         }
673     } else if (IS_AST_OP(node)) {
674         DEBUGprintf ("%s: AST_OP\n", __FUNCTION__);
675         switch (node->opval.op) {
676         case CAST:
677             assert (node->right);
678             buffer = parseIvalAst(node->right, inCodeSpace);
679             DEBUGprintf ("%s: %s\n", __FUNCTION__, buffer);
680             break;
681         case '&':
682             assert ( node->left && !node->right );
683             buffer = parseIvalAst(node->left, inCodeSpace);
684             DEBUGprintf ("%s: %s\n", __FUNCTION__, buffer);
685             break;
686         case '+':
687             assert (node->left && node->right );
688             left = parseIvalAst(node->left, inCodeSpace);
689             right = parseIvalAst(node->right, inCodeSpace);
690             buffer = Safe_alloc(LEN);
691             SNPRINTF(buffer, LEN, "(%s + %s)", left, right);
692             DEBUGprintf ("%s: %s\n", __FUNCTION__, buffer);
693             Safe_free(left);
694             Safe_free(right);
695             break;
696         case '[':
697             assert ( node->left && node->right );
698             assert ( IS_AST_VALUE(node->left) && AST_VALUE(node->left)->sym );
699             right = parseIvalAst(node->right, inCodeSpace);
700             buffer = Safe_alloc(LEN);
701             SNPRINTF(buffer, LEN, "(%s + %u * %s)",
702                     AST_VALUE(node->left)->sym->rname, getSize(AST_VALUE(node->left)->type), right);
703             Safe_free(right);
704             DEBUGprintf ("%s: %s\n", __FUNCTION__, &buffer[0]);
705             break;
706         default:
707             assert ( !"Unhandled operation in initializer." );
708             break;
709         }
710     } else {
711         assert ( !"Invalid construct in initializer." );
712     }
713
714     return (buffer);
715 }
716
717 /*
718  * Emit the section preamble, absolute location (if any) and
719  * symbol name(s) for intialized data.
720  */
721 static int
722 emitIvalLabel(struct dbuf_s *oBuf, symbol *sym)
723 {
724     char *segname;
725     static int in_code = 0;
726     static int sectionNr = 0;
727
728     if (sym) {
729         // code or data space?
730         if (IS_CODE(getSpec(sym->type))) {
731             segname = "code";
732             in_code = 1;
733         } else {
734             segname = "idata";
735             in_code  = 0;
736         }
737         dbuf_printf(oBuf, "\nID_%s_%d\t%s", moduleName, sectionNr++, segname);
738         if (SPEC_ABSA(getSpec(sym->type))) {
739             // specify address for absolute symbols
740             dbuf_printf(oBuf, "\t0x%04X", SPEC_ADDR(getSpec(sym->type)));
741         } // if
742         dbuf_printf(oBuf, "\n%s\n", sym->rname);
743
744         addSet(&emitted, sym->rname);
745     }
746     return (in_code);
747 }
748
749 /*
750  * Actually emit the initial values in .asm format.
751  */
752 static void
753 emitIvals(struct dbuf_s *oBuf, symbol *sym, initList *list, long lit, int size)
754 {
755     int i;
756     ast *node;
757     operand *op;
758     value *val = NULL;
759     int inCodeSpace = 0;
760     char *str = NULL;
761     int in_code;
762
763     assert (size <= sizeof(long));
764     assert (!list || (list->type == INIT_NODE));
765     node = list ? list->init.node : NULL;
766
767     in_code = emitIvalLabel(oBuf, sym);
768     if (!in_code) dbuf_printf (oBuf, "\tdb\t");
769
770     if (!node) {
771         // initialize as zero
772         for (i=0; i < size; i++) {
773             if (in_code) {
774                 dbuf_printf (oBuf, "\tretlw 0x00");
775             } else {
776                 dbuf_printf (oBuf, "%s0x00", (i == 0) ? "" : ", ");
777             }
778         } // for
779         dbuf_printf (oBuf, "\n");
780         return;
781     } // if
782
783     op = NULL;
784     if (constExprTree(node) && (val = constExprValue(node, 0))) {
785         op = operandFromValue(val);
786         DEBUGprintf ("%s: constExpr ", __FUNCTION__);
787     } else if (IS_AST_VALUE(node)) {
788         op = operandFromAst(node, 0);
789     } else if (IS_AST_OP(node)) {
790         str = parseIvalAst(node, &inCodeSpace);
791         DEBUGprintf("%s: AST_OP: %s\n", __FUNCTION__, str);
792         op = NULL;
793     } else {
794         assert ( !"Unhandled construct in intializer." );
795     }
796
797     if (op) {
798         aopOp(op, NULL, 1);
799         assert(AOP(op));
800         //printOperand(op, of);
801     }
802
803     for (i=0; i < size; i++) {
804         char *text;
805
806         /*
807          * FIXME: This is hacky and needs some more thought.
808          */
809         if (op && IS_SYMOP(op) && IS_FUNC(OP_SYM_TYPE(op))) {
810             /* This branch is introduced to fix #1427663. */
811             PCOI(AOP(op)->aopu.pcop)->offset+=i;
812             text = get_op(AOP(op)->aopu.pcop, NULL, 0);
813             PCOI(AOP(op)->aopu.pcop)->offset-=i;
814         } else {
815             text = op ? aopGet(AOP(op), i, 0, 0)
816             : get_op(newpCodeOpImmd(str, i, 0, inCodeSpace, 0), NULL, 0);
817         } // if
818         if (in_code) {
819             dbuf_printf (oBuf, "\tretlw %s\n", text);
820         } else {
821             dbuf_printf (oBuf, "%s%s", (i == 0) ? "" : ", ", text);
822         }
823     } // for
824     dbuf_printf (oBuf, "\n");
825 }
826
827 /*
828  * For UNIONs, we first have to find the correct alternative to map the
829  * initializer to. This function maps the structure of the initializer to
830  * the UNION members recursively.
831  * Returns the type of the first `fitting' member.
832  */
833 static sym_link *
834 matchIvalToUnion (initList *list, sym_link *type, int size)
835 {
836     symbol *sym;
837
838     assert (type);
839
840     if (IS_PTR(type) || IS_CHAR(type) || IS_INT(type) || IS_LONG(type)
841             || IS_FLOAT(type))
842     {
843         if (!list || (list->type == INIT_NODE)) {
844             DEBUGprintf ("OK, simple type\n");
845             return (type);
846         } else {
847             DEBUGprintf ("ERROR, simple type\n");
848             return (NULL);
849         }
850     } else if (IS_BITFIELD(type)) {
851         if (!list || (list->type == INIT_NODE)) {
852             DEBUGprintf ("OK, bitfield\n");
853             return (type);
854         } else {
855             DEBUGprintf ("ERROR, bitfield\n");
856             return (NULL);
857         }
858     } else if (IS_STRUCT(type) && SPEC_STRUCT(getSpec(type))->type == STRUCT) {
859         if (!list || (list->type == INIT_DEEP)) {
860             if (list) list = list->init.deep;
861             sym = SPEC_STRUCT(type)->fields;
862             while (sym) {
863                 DEBUGprintf ("Checking STRUCT member %s\n", sym->name);
864                 if (!matchIvalToUnion(list, sym->type, 0)) {
865                     DEBUGprintf ("ERROR, STRUCT member %s\n", sym->name);
866                     return (NULL);
867                 }
868                 if (list) list = list->next;
869                 sym = sym->next;
870             } // while
871
872             // excess initializers?
873             if (list) {
874                 DEBUGprintf ("ERROR, excess initializers\n");
875                 return (NULL);
876             }
877
878             DEBUGprintf ("OK, struct\n");
879             return (type);
880         }
881         return (NULL);
882     } else if (IS_STRUCT(type) && SPEC_STRUCT(getSpec(type))->type == UNION) {
883         if (!list || (list->type == INIT_DEEP)) {
884             if (list) list = list->init.deep;
885             sym = SPEC_STRUCT(type)->fields;
886             while (sym) {
887                 DEBUGprintf ("Checking UNION member %s.\n", sym->name);
888                 if (((IS_STRUCT(sym->type) || getSize(sym->type) == size))
889                         && matchIvalToUnion(list, sym->type, size))
890                 {
891                     DEBUGprintf ("Matched UNION member %s.\n", sym->name);
892                     return (sym->type);
893                 }
894                 sym = sym->next;
895             } // while
896         } // if
897         // no match found
898         DEBUGprintf ("ERROR, no match found.\n");
899         return (NULL);
900     } else {
901         assert ( !"Unhandled type in UNION." );
902     }
903
904     assert ( !"No match found in UNION for the given initializer structure." );
905     return (NULL);
906 }
907
908 /*
909  * Parse the type and its initializer and emit it (recursively).
910  */
911 static void
912 emitInitVal(struct dbuf_s *oBuf, symbol *topsym, sym_link *my_type, initList *list)
913 {
914     symbol *sym;
915     int size, i;
916     long lit;
917     unsigned char *str;
918
919     size = getSize(my_type);
920
921     if (IS_PTR(my_type)) {
922         DEBUGprintf ("(pointer, %d byte) %p\n", size, list ? (void *)(long)list2int(list) : NULL);
923         emitIvals(oBuf, topsym, list, 0, size);
924         return;
925     }
926
927     if (IS_ARRAY(my_type) && topsym && topsym->isstrlit) {
928         str = (unsigned char *)SPEC_CVAL(topsym->etype).v_char;
929         emitIvalLabel(oBuf, topsym);
930         do {
931             dbuf_printf (oBuf, "\tretlw 0x%02x ; '%c'\n", str[0], (str[0] >= 0x20 && str[0] < 128) ? str[0] : '.');
932         } while (*(str++));
933         return;
934     }
935
936     if (IS_ARRAY(my_type) && list && list->type == INIT_NODE) {
937         fprintf (stderr, "Unhandled initialized symbol: %s\n", topsym->name);
938         assert ( !"Initialized char-arrays are not yet supported, assign at runtime instead." );
939         return;
940     }
941
942     if (IS_ARRAY(my_type)) {
943         DEBUGprintf ("(array, %d items, %d byte) below\n", DCL_ELEM(my_type), size);
944         assert (!list || list->type == INIT_DEEP);
945         if (list) list = list->init.deep;
946         for (i = 0; i < DCL_ELEM(my_type); i++) {
947             emitInitVal(oBuf, topsym, my_type->next, list);
948             topsym = NULL;
949             if (list) list = list->next;
950         } // for i
951         return;
952     }
953
954     if (IS_FLOAT(my_type)) {
955         // float, 32 bit
956         DEBUGprintf ("(float, %d byte) %lf\n", size, list ? list2int(list) : 0.0);
957         emitIvals(oBuf, topsym, list, 0, size);
958         return;
959     }
960
961     if (IS_CHAR(my_type) || IS_INT(my_type) || IS_LONG(my_type)) {
962         // integral type, 8, 16, or 32 bit
963         DEBUGprintf ("(integral, %d byte) 0x%lx/%ld\n", size, list ? (long)list2int(list) : 0, list ? (long)list2int(list) : 0);
964         emitIvals(oBuf, topsym, list, 0, size);
965         return;
966
967     } else if (IS_STRUCT(my_type) && SPEC_STRUCT(my_type)->type == STRUCT) {
968         // struct
969         DEBUGprintf ("(struct, %d byte) handled below\n", size);
970         assert (!list || (list->type == INIT_DEEP));
971
972         // iterate over struct members and initList
973         if (list) list = list->init.deep;
974         sym = SPEC_STRUCT(my_type)->fields;
975         while (sym) {
976             long bitfield = 0;
977             int len = 0;
978             if (IS_BITFIELD(sym->type)) {
979                 while (sym && IS_BITFIELD(sym->type)) {
980                     assert (!list || ((list->type == INIT_NODE)
981                                 && IS_AST_LIT_VALUE(list->init.node)));
982                     lit = (long) (list ? list2int(list) : 0);
983                     DEBUGprintf ( "(bitfield member) %02lx (%d bit, starting at %d, bitfield %02lx)\n",
984                             lit, SPEC_BLEN(getSpec(sym->type)),
985                             SPEC_BSTR(getSpec(sym->type)), bitfield);
986                     bitfield |= (lit & ((1ul << SPEC_BLEN(getSpec(sym->type))) - 1)) << SPEC_BSTR(getSpec(sym->type));
987                     len += SPEC_BLEN(getSpec(sym->type));
988
989                     sym = sym->next;
990                     if (list) list = list->next;
991                 } // while
992                 assert (len < sizeof (long) * 8); // did we overflow our initializer?!?
993                 len = (len + 7) & ~0x07; // round up to full bytes
994                 emitIvals(oBuf, topsym, NULL, bitfield, len / 8);
995                 topsym = NULL;
996             } // if
997
998             if (sym) {
999                 emitInitVal(oBuf, topsym, sym->type, list);
1000                 topsym = NULL;
1001                 sym = sym->next;
1002                 if (list) list = list->next;
1003             } // if
1004         } // while
1005         if (list) {
1006             assert ( !"Excess initializers." );
1007         } // if
1008         return;
1009
1010     } else if (IS_STRUCT(my_type) && SPEC_STRUCT(my_type)->type == UNION) {
1011         // union
1012         DEBUGprintf ("(union, %d byte) handled below\n", size);
1013         assert (list && list->type == INIT_DEEP);
1014
1015         // iterate over union members and initList, try to map number and type of fields and initializers
1016         my_type = matchIvalToUnion(list, my_type, size);
1017         if (my_type) {
1018             emitInitVal(oBuf, topsym, my_type, list->init.deep);
1019             topsym = NULL;
1020             size -= getSize(my_type);
1021             if (size > 0) {
1022                 // pad with (leading) zeros
1023                 emitIvals(oBuf, NULL, NULL, 0, size);
1024             }
1025             return;
1026         } // if
1027
1028         assert ( !"No UNION member matches the initializer structure.");
1029     } else if (IS_BITFIELD(my_type)) {
1030         assert ( !"bitfields should only occur in structs..." );
1031
1032     } else {
1033         printf ("SPEC_NOUN: %d\n", SPEC_NOUN(my_type));
1034         assert( !"Unhandled initialized type.");
1035     }
1036 }
1037
1038 /*
1039  * Emit a set of symbols.
1040  * type - 0: have symbol tell whether it is local, extern or global
1041  *        1: assume all symbols in set to be global
1042  *        2: assume all symbols in set to be extern
1043  */
1044 static void
1045 emitSymbolSet(set *s, int type)
1046 {
1047     symbol *sym;
1048     initList *list;
1049     unsigned sectionNr = 0;
1050
1051     for (sym = setFirstItem(s); sym; sym = setNextItem(s)) {
1052 #if 0
1053         fprintf (stdout, ";    name %s, rname %s, level %d, block %d, key %d, local %d, ival %p, static %d, cdef %d, used %d\n",
1054                 sym->name, sym->rname, sym->level, sym->block, sym->key, sym->islocal, sym->ival, IS_STATIC(sym->etype), sym->cdef, sym->used);
1055 #endif
1056
1057         if (sym->etype && SPEC_ABSA(sym->etype)
1058                 && IS_CONFIG_ADDRESS(SPEC_ADDR(sym->etype))
1059                 && sym->ival)
1060         {
1061             // handle config words
1062             pic14_assignConfigWordValue(SPEC_ADDR(sym->etype),
1063                     (int)list2int(sym->ival));
1064             pic14_stringInSet(sym->rname, &emitted, 1);
1065             continue;
1066         }
1067
1068         if (sym->isstrlit) {
1069             // special case: string literals
1070             emitInitVal(ivalBuf, sym, sym->type, NULL);
1071             continue;
1072         }
1073
1074         if (type != 0 || sym->cdef
1075                 || (!IS_STATIC(sym->etype)
1076                     && IS_GLOBAL(sym)))
1077         {
1078             // bail out for ___fsadd and friends
1079             if (sym->cdef && !sym->used) continue;
1080
1081             /* export or import non-static globals */
1082             if (!pic14_stringInSet(sym->rname, &emitted, 0)) {
1083
1084                 if (type == 2 || IS_EXTERN(sym->etype) || sym->cdef)
1085                 {
1086                     /* do not add to emitted set, it might occur again! */
1087                     //if (!sym->used) continue;
1088                     // declare symbol
1089                     emitIfNew (extBuf, &emitted, "\textern\t%s\n", sym->rname);
1090                 } else {
1091                     // declare symbol
1092                     emitIfNew (gloBuf, &emitted, "\tglobal\t%s\n", sym->rname);
1093                     if (!sym->ival && !IS_FUNC(sym->type)) {
1094                         // also define symbol
1095                         if (IS_ABSOLUTE(sym->etype)) {
1096                             // absolute location?
1097                             //dbuf_printf (gloDefBuf, "UD_%s_%u\tudata\t0x%04X\n", moduleName, sectionNr++, SPEC_ADDR(sym->etype));
1098                             // deferred to pic14_constructAbsMap
1099                         } else {
1100                             dbuf_printf (gloDefBuf, "UD_%s_%u\tudata\n", moduleName, sectionNr++);
1101                             dbuf_printf (gloDefBuf, "%s\tres\t%d\n\n", sym->rname, getSize(sym->type));
1102                         }
1103                     } // if
1104                 } // if
1105                 pic14_stringInSet(sym->rname, &emitted, 1);
1106             } // if
1107         } // if
1108         list = sym->ival;
1109         //if (list) showInitList(list, 0);
1110         if (list) {
1111             resolveIvalSym( list, sym->type );
1112             emitInitVal(ivalBuf, sym, sym->type, sym->ival);
1113             dbuf_printf (ivalBuf, "\n");
1114         }
1115     } // for sym
1116 }
1117
1118 /*
1119  * Iterate over all memmaps and emit their contents (attributes, symbols).
1120  */
1121 static void
1122 showAllMemmaps(FILE *of)
1123 {
1124     struct dbuf_s locBuf;
1125     memmap *maps[] = {
1126         xstack, istack, code, data, pdata, xdata, xidata, xinit,
1127         idata, bit, statsg, c_abs, x_abs, i_abs, d_abs,
1128         sfr, sfrbit, reg, generic, overlay, eeprom, home };
1129     memmap * map;
1130     int i;
1131
1132     DEBUGprintf ("---begin memmaps---\n");
1133     if (!extBuf) extBuf = dbuf_new(1024);
1134     if (!gloBuf) gloBuf = dbuf_new(1024);
1135     if (!gloDefBuf) gloDefBuf = dbuf_new(1024);
1136     if (!ivalBuf) ivalBuf = dbuf_new(1024);
1137     dbuf_init(&locBuf, 1024);
1138
1139     dbuf_printf (extBuf, "%s; external declarations\n%s", iComments2, iComments2);
1140     dbuf_printf (gloBuf, "%s; global declarations\n%s", iComments2, iComments2);
1141     dbuf_printf (gloDefBuf, "%s; global definitions\n%s", iComments2, iComments2);
1142     dbuf_printf (ivalBuf, "%s; initialized data\n%s", iComments2, iComments2);
1143     dbuf_printf (&locBuf, "%s; compiler-defined variables\n%s", iComments2, iComments2);
1144
1145     for (i = 0; i < sizeof(maps) / sizeof (memmap *); i++) {
1146         map = maps[i];
1147         //DEBUGprintf ("memmap %i: %p\n", i, map);
1148         if (map) {
1149 #if 0
1150             fprintf (stdout, ";  pageno %c, sname %s, dbName %c, ptrType %d, slbl %d, sloc %u, fmap %u, paged %u, direct %u, bitsp %u, codesp %u, regsp %u, syms %p\n",
1151                     map->pageno, map->sname, map->dbName, map->ptrType, map->slbl,
1152                     map->sloc, map->fmap, map->paged, map->direct, map->bitsp,
1153                     map->codesp, map->regsp, map->syms);
1154 #endif
1155             emitSymbolSet(map->syms, 0);
1156         } // if (map)
1157     } // for i
1158     DEBUGprintf ("---end of memmaps---\n");
1159
1160     emitSymbolSet(publics, 1);
1161     emitSymbolSet(externs, 2);
1162
1163     emitPseudoStack(gloBuf, extBuf);
1164     pic14_constructAbsMap(gloDefBuf, gloBuf);
1165     pic14printLocals (&locBuf);
1166     pic14_emitConfigWord(of); // must be done after all the rest
1167
1168     dbuf_write_and_destroy(extBuf, of);
1169     dbuf_write_and_destroy(gloBuf, of);
1170     dbuf_write_and_destroy(gloDefBuf, of);
1171     dbuf_write_and_destroy(&locBuf, of);
1172     dbuf_write_and_destroy(ivalBuf, of);
1173
1174     extBuf = gloBuf = gloDefBuf = ivalBuf = NULL;
1175 }
1176