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