1 /*-------------------------------------------------------------------------
3 glue.c - glues everything we have done together into one file.
4 Written By - Sandeep Dutta . sandeep.dutta@usa.net (1998)
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
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.
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.
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 -------------------------------------------------------------------------*/
26 #include "dbuf_string.h"
38 extern struct dbuf_s *codeOutBuf;
40 extern void initialComments (FILE *afile);
41 extern operand *operandFromAst (ast *tree, int lvl);
42 extern value *initPointer (initList *ilist, sym_link *toType);
45 set *pic14_localFunctions = NULL;
46 int pic14_hasInterrupt = 0; // Indicates whether to emit interrupt handler or not
48 int pic14_stringInSet(const char *str, set **world, int autoAdd);
51 #ifdef WORDS_BIGENDIAN
52 #define _ENDIAN(x) (3-x)
54 #define _ENDIAN(x) (x)
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))
61 /* dbufs for initialized data (idata and code sections),
62 * extern, and global declarations */
63 static struct dbuf_s *ivalBuf, *extBuf, *gloBuf, *gloDefBuf;
65 static set *emitted = NULL;
67 static void showAllMemmaps (FILE *of); // XXX: emits initialized symbols
70 emitPseudoStack(struct dbuf_s *oBuf, struct dbuf_s *oBufExt)
72 int shared, low, high, size, i;
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)
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);
92 dbuf_printf (oBuf, "\n");
94 // 16f84 has no SHAREBANK (in linkerscript) but memory aliased in two
97 // for single banked devices: use normal, "banked" RAM
98 dbuf_printf (oBuf, "sharebank udata_ovr 0x%04X\n", low);
100 // for devices with at least two banks, require a sharebank section
101 dbuf_printf (oBuf, "sharebank udata_shr\n");
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);
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--) {
119 SNPRINTF(&buffer[0], 127, "STK%02d", i);
120 dbuf_printf (oBufExt, "\textern %s\n", &buffer[0]);
121 pic14_stringInSet(&buffer[0], &emitted, 1);
124 dbuf_printf (oBuf, "\n");
128 emitIfNew(struct dbuf_s *oBuf, set **emitted, const char *fmt,
131 int wasPresent = pic14_stringInSet(name, emitted, 1);
134 dbuf_printf (oBuf, fmt, name);
136 return (!wasPresent);
140 pic14_constructAbsMap (struct dbuf_s *oBuf, struct dbuf_s *gloBuf)
142 memmap *maps[] = { data, sfr, NULL };
147 int addr, min=-1, max=-1;
150 for (i=0; maps[i] != NULL; i++)
152 for (sym = (symbol *)setFirstItem (maps[i]->syms);
153 sym; sym = setNextItem (maps[i]->syms))
155 if (IS_DEFINED_HERE(sym) && SPEC_ABSA(sym->etype))
157 addr = SPEC_ADDR(sym->etype);
159 /* handle CONFIG words here */
160 if (IS_CONFIG_ADDRESS( addr ))
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 ) );
165 pic14_assignConfigWordValue( addr, (int)list2int( sym->ival ) );
167 fprintf( stderr, "ERROR: Symbol %s, which is covering a __CONFIG word must be initialized!\n", sym->name );
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);
177 /* May not use addSetHead, as we cannot update the
178 * list's head in the hastable `ht'. */
179 addSet (&aliases, sym);
181 fprintf( stderr, "%s: now %d aliases for %s @ 0x%x\n",
182 __FUNCTION__, elementsInSet(aliases), sym->name, addr);
185 addSet (&aliases, sym);
186 hTabAddItem (&ht, addr, aliases);
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++)
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;
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))
212 if (getSize(sym->type) > size) {
213 size = getSize(sym->type);
216 /* initialized values are handled somewhere else */
217 if (sym->ival) continue;
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);
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);
228 dbuf_printf (oBuf, "\tres\t%d\n", size);
233 /*-----------------------------------------------------------------*/
234 /* createInterruptVect - creates the interrupt vector */
235 /*-----------------------------------------------------------------*/
237 pic14createInterruptVect (struct dbuf_s * vBuf)
239 mainf = newSymbol ("main", 0);
242 /* only if the main function exists */
243 if (!(mainf = findSymWithLevel (SymbolTab, mainf)))
245 struct options *op = &options;
246 if (!(op->cc_only || noAssemble))
247 // werror (E_NO_MAIN);
248 fprintf(stderr,"WARNING: function 'main' undefined\n");
252 /* if the main is only a prototype ie. no body then do nothing */
253 if (!IFFUNC_HASBODY(mainf->type))
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");
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);
274 /*-----------------------------------------------------------------*/
275 /* initialComments - puts in some initial comments */
276 /*-----------------------------------------------------------------*/
278 pic14initialComments (FILE * afile)
280 initialComments (afile);
281 fprintf (afile, "; PIC port for the 14-bit core\n");
282 fprintf (afile, "%s", iComments2);
287 pic14_stringInSet(const char *str, set **world, int autoAdd)
294 for (s = setFirstItem(*world); s; s = setNextItem(*world))
297 if (0 == strcmp(s, str)) return 1;
301 if (autoAdd) addSet(world, Safe_strdup(str));
306 pic14printLocals (struct dbuf_s *oBuf)
308 set *allregs[6] = { dynAllocRegs/*, dynStackRegs, dynProcessorRegs*/,
309 dynDirectRegs, dynDirectBitRegs/*, dynInternalRegs */ };
312 static unsigned sectionNr = 0;
314 /* emit all registers from all possible sets */
315 for (i = 0; i < 6; i++) {
316 if (allregs[i] == NULL) continue;
318 for (reg = setFirstItem(allregs[i]); reg; reg = setNextItem(allregs[i])) {
319 if (reg->isEmitted) continue;
321 if (reg->wasUsed && !reg->isExtern) {
322 if (!pic14_stringInSet(reg->name, &emitted, 1)) {
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);
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);
334 // group all local registers into a single section
335 // This should greatly improve BANKSEL generation...
337 dbuf_printf(oBuf, "UDL_%s_%u\tudata\n", moduleName, sectionNr++);
340 dbuf_printf(oBuf, "%s\tres\t%d\n", reg->name, reg->size);
350 /*-----------------------------------------------------------------*/
351 /* emitOverlay - will emit code for the overlay stuff */
352 /*-----------------------------------------------------------------*/
354 pic14emitOverlay (struct dbuf_s * aBuf)
358 /* if (!elementsInSet (ovrSetSets))*/
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);
366 /* for each of the sets in the overlay segment do */
367 for (ovrset = setFirstItem (ovrSetSets); ovrset;
368 ovrset = setNextItem (ovrSetSets))
373 if (elementsInSet (ovrset))
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
380 /* I don't think this applies to us. We are using gpasm. CRF */
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 */
387 for (sym = setFirstItem (ovrset); sym;
388 sym = setNextItem (ovrset))
391 /* if extern then do nothing */
392 if (IS_EXTERN (sym->etype))
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)
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);
409 /* if extern then do nothing or is a function
411 if (IS_FUNC (sym->type))
414 /* print extra debug info if required */
415 if (options.debug || sym->level == 0)
419 if (IS_STATIC (sym->etype))
420 dbuf_printf (aBuf, "F%s_", moduleName); /* scope is file */
422 dbuf_printf (aBuf, "G_"); /* scope is global */
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);
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))
436 if (options.debug || sym->level == 0)
437 dbuf_printf (aBuf, " == 0x%04x\n", SPEC_ADDR (sym->etype));
439 dbuf_printf (aBuf, "%s\t=\t0x%04x\n",
441 SPEC_ADDR (sym->etype));
445 if (options.debug || sym->level == 0)
446 dbuf_printf (aBuf, "==.\n");
449 dbuf_printf (aBuf, "%s:\n", sym->rname);
450 dbuf_printf (aBuf, "\t.ds\t0x%04x\n", (unsigned int) getSize (sym->type) & 0xffff);
459 pic14_emitInterruptHandler (FILE * asmFile)
461 if (pic14_hasInterrupt)
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);
472 /* interrupt service routine */
473 fprintf (asmFile, "__sdcc_interrupt\n");
474 copypCode(asmFile, 'I');
478 /*-----------------------------------------------------------------*/
479 /* glue - the final glue that hold the whole thing together */
480 /*-----------------------------------------------------------------*/
485 struct dbuf_s ovrBuf;
488 dbuf_init(&ovrBuf, 4096);
489 dbuf_init(&vBuf, 4096);
491 pCodeInitRegisters();
493 /* check for main() */
494 mainf = newSymbol ("main", 0);
496 mainf = findSymWithLevel (SymbolTab, mainf);
498 if (!mainf || !IFFUNC_HASBODY(mainf->type))
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;
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 */
509 movepBlock2Head('P'); // Last
510 movepBlock2Head(code->dbName);
511 movepBlock2Head('X');
512 movepBlock2Head(statsg->dbName); // First
515 /* print the global struct definitions */
519 /* do the overlay segments */
520 pic14emitOverlay(&ovrBuf);
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);
530 ReuseReg(); // ReuseReg where call tree permits
536 if (options.debug) pcode_test();
539 /* now put it all together into the assembler file */
540 /* create the assembler file name */
542 if ((noAssemble || options.c1mode) && fullDstFileName)
544 sprintf (buffer, "%s", fullDstFileName);
548 sprintf (buffer, "%s", dstFileName);
549 strcat (buffer, ".asm");
552 if (!(asmFile = fopen (buffer, "w"))) {
553 werror (E_FILE_OPEN_ERR, buffer);
557 /* prepare statistics */
558 resetpCodeStatistics ();
560 /* initial comments */
561 pic14initialComments (asmFile);
563 /* print module name */
564 fprintf (asmFile, "%s\t.file\t\"%s\"\n",
565 options.debug ? "" : ";", fullSrcFileName);
567 /* Let the port generate any global directives, etc. */
568 if (port->genAssemblerPreamble)
570 port->genAssemblerPreamble(asmFile);
573 /* Put all variables into a cblock */
576 /* emit initialized data */
577 showAllMemmaps(asmFile);
579 /* print the locally defined variables in this module */
580 writeUsedRegs(asmFile);
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);
588 /* copy the interrupt vector table */
589 if (mainf && IFFUNC_HASBODY(mainf->type))
590 dbuf_write_and_destroy (&vBuf, asmFile);
594 /* create interupt ventor handler */
595 pic14_emitInterruptHandler (asmFile);
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);
604 copypCode(asmFile, 'X');
607 copypCode(asmFile, 'M');
609 /* other functions */
610 copypCode(asmFile, code->dbName);
613 copypCode(asmFile, 'P');
615 dumppCodeStatistics (asmFile);
617 fprintf (asmFile,"\tend\n");
620 pic14_debugLogClose();
624 * Deal with initializers.
629 #define DEBUGprintf printf
632 #define DEBUGprintf 1 ? (void)0 : (void)printf
636 parseIvalAst (ast *node, int *inCodeSpace) {
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))))
649 if (inCodeSpace && sym
650 && (IS_FUNC(sym->type)
651 || IS_CODE(getSpec(sym->type))))
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) );
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);
668 buffer = Safe_strdup(AST_SYMBOL(node)->rname);
670 assert ( !"Invalid values type for initializers in AST." );
672 } else if (IS_AST_OP(node)) {
673 DEBUGprintf ("%s: AST_OP\n", __FUNCTION__);
674 switch (node->opval.op) {
676 assert (node->right);
677 buffer = parseIvalAst(node->right, inCodeSpace);
678 DEBUGprintf ("%s: %s\n", __FUNCTION__, buffer);
681 assert ( node->left && !node->right );
682 buffer = parseIvalAst(node->left, inCodeSpace);
683 DEBUGprintf ("%s: %s\n", __FUNCTION__, buffer);
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);
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);
703 DEBUGprintf ("%s: %s\n", __FUNCTION__, &buffer[0]);
706 assert ( !"Unhandled operation in initializer." );
710 assert ( !"Invalid construct in initializer." );
717 * Emit the section preamble, absolute location (if any) and
718 * symbol name(s) for intialized data.
721 emitIvalLabel(struct dbuf_s *oBuf, symbol *sym)
724 static int in_code = 0;
725 static int sectionNr = 0;
728 // code or data space?
729 if (IS_CODE(getSpec(sym->type))) {
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)));
741 dbuf_printf(oBuf, "\n%s\n", sym->rname);
743 addSet(&emitted, sym->rname);
749 * Actually emit the initial values in .asm format.
752 emitIvals(struct dbuf_s *oBuf, symbol *sym, initList *list, long lit, int size)
762 assert (size <= sizeof(long));
763 assert (!list || (list->type == INIT_NODE));
764 node = list ? list->init.node : NULL;
766 in_code = emitIvalLabel(oBuf, sym);
767 if (!in_code) dbuf_printf (oBuf, "\tdb\t");
770 // initialize as zero
771 for (i=0; i < size; i++) {
773 dbuf_printf (oBuf, "\tretlw 0x00");
775 dbuf_printf (oBuf, "%s0x00", (i == 0) ? "" : ", ");
778 dbuf_printf (oBuf, "\n");
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);
793 assert ( !"Unhandled construct in intializer." );
799 //printOperand(op, of);
802 for (i=0; i < size; i++) {
806 * FIXME: This is hacky and needs some more thought.
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;
814 text = op ? aopGet(AOP(op), i, 0, 0)
815 : get_op(newpCodeOpImmd(str, i, 0, inCodeSpace, 0), NULL, 0);
818 dbuf_printf (oBuf, "\tretlw %s\n", text);
820 dbuf_printf (oBuf, "%s%s", (i == 0) ? "" : ", ", text);
823 dbuf_printf (oBuf, "\n");
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.
833 matchIvalToUnion (initList *list, sym_link *type, int size)
839 if (IS_PTR(type) || IS_CHAR(type) || IS_INT(type) || IS_LONG(type)
842 if (!list || (list->type == INIT_NODE)) {
843 DEBUGprintf ("OK, simple type\n");
846 DEBUGprintf ("ERROR, simple type\n");
849 } else if (IS_BITFIELD(type)) {
850 if (!list || (list->type == INIT_NODE)) {
851 DEBUGprintf ("OK, bitfield\n");
854 DEBUGprintf ("ERROR, bitfield\n");
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;
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);
867 if (list) list = list->next;
871 // excess initializers?
873 DEBUGprintf ("ERROR, excess initializers\n");
877 DEBUGprintf ("OK, struct\n");
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;
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))
890 DEBUGprintf ("Matched UNION member %s.\n", sym->name);
897 DEBUGprintf ("ERROR, no match found.\n");
900 assert ( !"Unhandled type in UNION." );
903 assert ( !"No match found in UNION for the given initializer structure." );
908 * Parse the type and its initializer and emit it (recursively).
911 emitInitVal(struct dbuf_s *oBuf, symbol *topsym, sym_link *my_type, initList *list)
918 size = getSize(my_type);
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);
926 if (IS_ARRAY(my_type) && topsym && topsym->isstrlit) {
927 str = (unsigned char *)SPEC_CVAL(topsym->etype).v_char;
928 emitIvalLabel(oBuf, topsym);
930 dbuf_printf (oBuf, "\tretlw 0x%02x ; '%c'\n", str[0], (str[0] >= 0x20 && str[0] < 128) ? str[0] : '.');
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." );
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);
948 if (list) list = list->next;
953 if (IS_FLOAT(my_type)) {
955 DEBUGprintf ("(float, %d byte) %lf\n", size, list ? list2int(list) : 0.0);
956 emitIvals(oBuf, topsym, list, 0, size);
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);
966 } else if (IS_STRUCT(my_type) && SPEC_STRUCT(my_type)->type == STRUCT) {
968 DEBUGprintf ("(struct, %d byte) handled below\n", size);
969 assert (!list || (list->type == INIT_DEEP));
971 // iterate over struct members and initList
972 if (list) list = list->init.deep;
973 sym = SPEC_STRUCT(my_type)->fields;
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));
989 if (list) list = list->next;
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);
998 emitInitVal(oBuf, topsym, sym->type, list);
1001 if (list) list = list->next;
1005 assert ( !"Excess initializers." );
1009 } else if (IS_STRUCT(my_type) && SPEC_STRUCT(my_type)->type == UNION) {
1011 DEBUGprintf ("(union, %d byte) handled below\n", size);
1012 assert (list && list->type == INIT_DEEP);
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);
1017 emitInitVal(oBuf, topsym, my_type, list->init.deep);
1019 size -= getSize(my_type);
1021 // pad with (leading) zeros
1022 emitIvals(oBuf, NULL, NULL, 0, size);
1027 assert ( !"No UNION member matches the initializer structure.");
1028 } else if (IS_BITFIELD(my_type)) {
1029 assert ( !"bitfields should only occur in structs..." );
1032 printf ("SPEC_NOUN: %d\n", SPEC_NOUN(my_type));
1033 assert( !"Unhandled initialized type.");
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
1044 emitSymbolSet(set *s, int type)
1048 unsigned sectionNr = 0;
1050 for (sym = setFirstItem(s); sym; sym = setNextItem(s)) {
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);
1056 if (sym->etype && SPEC_ABSA(sym->etype)
1057 && IS_CONFIG_ADDRESS(SPEC_ADDR(sym->etype))
1060 // handle config words
1061 pic14_assignConfigWordValue(SPEC_ADDR(sym->etype),
1062 (int)list2int(sym->ival));
1063 pic14_stringInSet(sym->rname, &emitted, 1);
1067 if (sym->isstrlit) {
1068 // special case: string literals
1069 emitInitVal(ivalBuf, sym, sym->type, NULL);
1073 if (type != 0 || sym->cdef
1074 || (!IS_STATIC(sym->etype)
1077 // bail out for ___fsadd and friends
1078 if (sym->cdef && !sym->used) continue;
1080 /* export or import non-static globals */
1081 if (!pic14_stringInSet(sym->rname, &emitted, 0)) {
1083 if (type == 2 || IS_EXTERN(sym->etype) || sym->cdef)
1085 /* do not add to emitted set, it might occur again! */
1086 //if (!sym->used) continue;
1088 emitIfNew (extBuf, &emitted, "\textern\t%s\n", sym->rname);
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
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));
1104 pic14_stringInSet(sym->rname, &emitted, 1);
1108 //if (list) showInitList(list, 0);
1110 resolveIvalSym( list, sym->type );
1111 emitInitVal(ivalBuf, sym, sym->type, sym->ival);
1112 dbuf_printf (ivalBuf, "\n");
1118 * Iterate over all memmaps and emit their contents (attributes, symbols).
1121 showAllMemmaps(FILE *of)
1123 struct dbuf_s locBuf;
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 };
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);
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);
1144 for (i = 0; i < sizeof(maps) / sizeof (memmap *); i++) {
1146 //DEBUGprintf ("memmap %i: %p\n", i, map);
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);
1154 emitSymbolSet(map->syms, 0);
1157 DEBUGprintf ("---end of memmaps---\n");
1159 emitSymbolSet(publics, 1);
1160 emitSymbolSet(externs, 2);
1162 emitPseudoStack(gloBuf, extBuf);
1163 pic14_constructAbsMap(gloDefBuf, gloBuf);
1164 pic14printLocals (&locBuf);
1165 pic14_emitConfigWord(of); // must be done after all the rest
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);
1173 extBuf = gloBuf = gloDefBuf = ivalBuf = NULL;