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