/*------------------------------------------------------------------------- glue.c - glues everything we have done together into one file. Written By - Sandeep Dutta . sandeep.dutta@usa.net (1998) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! -------------------------------------------------------------------------*/ #include "glue.h" #include "dbuf_string.h" #include "device.h" #include "gen.h" #include "main.h" /* * Imports */ extern set *publics; extern set *externs; extern symbol *mainf; extern struct dbuf_s *codeOutBuf; extern void initialComments (FILE *afile); extern operand *operandFromAst (ast *tree, int lvl); extern value *initPointer (initList *ilist, sym_link *toType); set *pic14_localFunctions = NULL; int pic14_hasInterrupt = 0; // Indicates whether to emit interrupt handler or not int pic14_stringInSet(const char *str, set **world, int autoAdd); #ifdef WORDS_BIGENDIAN #define _ENDIAN(x) (3-x) #else #define _ENDIAN(x) (x) #endif #define BYTE_IN_LONG(x,b) ((x>>(8*_ENDIAN(b)))&0xff) #define IS_GLOBAL(sym) ((sym)->level == 0) #define IS_DEFINED_HERE(sym) (!IS_EXTERN(sym->etype)) /* dbufs for initialized data (idata and code sections), * extern, and global declarations */ static struct dbuf_s *ivalBuf, *extBuf, *gloBuf, *gloDefBuf; static set *emitted = NULL; static void showAllMemmaps (FILE *of); // XXX: emits initialized symbols static void emitPseudoStack(struct dbuf_s *oBuf, struct dbuf_s *oBufExt) { int shared, low, high, size, i; PIC_device *pic = pic14_getPIC(); /* also emit STK symbols * XXX: This is ugly and fails as soon as devices start to get * differently sized sharebanks, since STK12 will be * required by larger devices but only up to STK03 might * be defined using smaller devices. */ shared = pic14_getSharedStack(&low, &high, &size); if (!pic14_options.isLibrarySource) { dbuf_printf (oBuf, "\n"); if (!pic->isEnhancedCore) { size -= 3; dbuf_printf (oBuf, "\tglobal PSAVE\n"); dbuf_printf (oBuf, "\tglobal SSAVE\n"); dbuf_printf (oBuf, "\tglobal WSAVE\n"); } for (i = size - 1; i >= 0; i--) { dbuf_printf (oBuf, "\tglobal STK%02d\n", i); } // for i dbuf_printf (oBuf, "\n"); // 16f84 has no SHAREBANK (in linkerscript) but memory aliased in two // banks, sigh... if (1 || !shared) { // for single banked devices: use normal, "banked" RAM dbuf_printf (oBuf, "sharebank udata_ovr 0x%04X\n", low); } else { // for devices with at least two banks, require a sharebank section dbuf_printf (oBuf, "sharebank udata_shr\n"); } if (!pic->isEnhancedCore) { dbuf_printf (oBuf, "PSAVE\tres 1\n"); dbuf_printf (oBuf, "SSAVE\tres 1\n"); dbuf_printf (oBuf, "WSAVE\tres 1\n"); // WSAVE *must* be in sharebank (IRQ handlers) } /* fill rest of sharebank with stack STKxx .. STK00 */ for (i = size - 1; i >= 0; i--) { dbuf_printf (oBuf, "STK%02d\tres 1\n", i); } // for i } else { /* declare STKxx as extern for all files * except the one containing main() */ dbuf_printf (oBufExt, "\n"); if (!pic->isEnhancedCore) { size -= 3; dbuf_printf (oBufExt, "\textern PSAVE\n"); dbuf_printf (oBufExt, "\textern SSAVE\n"); dbuf_printf (oBufExt, "\textern WSAVE\n"); } for (i = size - 1; i >= 0; i--) { char buffer[128]; SNPRINTF(&buffer[0], 127, "STK%02d", i); dbuf_printf (oBufExt, "\textern %s\n", &buffer[0]); pic14_stringInSet(&buffer[0], &emitted, 1); } // for i } dbuf_printf (oBuf, "\n"); } static int emitIfNew(struct dbuf_s *oBuf, set **emitted, const char *fmt, const char *name) { int wasPresent = pic14_stringInSet(name, emitted, 1); if (!wasPresent) { dbuf_printf (oBuf, fmt, name); } // if return (!wasPresent); } static void pic14_constructAbsMap (struct dbuf_s *oBuf, struct dbuf_s *gloBuf) { memmap *maps[] = { data, sfr, NULL }; int i; hTab *ht = NULL; symbol *sym; set *aliases; int addr, min=-1, max=-1; unsigned int size; for (i=0; maps[i] != NULL; i++) { for (sym = (symbol *)setFirstItem (maps[i]->syms); sym; sym = setNextItem (maps[i]->syms)) { if (IS_DEFINED_HERE(sym) && SPEC_ABSA(sym->etype)) { addr = SPEC_ADDR(sym->etype); /* handle CONFIG words here */ if (IS_CONFIG_ADDRESS( addr )) { //fprintf( stderr, "%s: assignment to CONFIG@0x%x found\n", __FUNCTION__, addr ); //fprintf( stderr, "ival: %p (0x%x)\n", sym->ival, (int)list2int( sym->ival ) ); if (sym->ival) { pic14_assignConfigWordValue( addr, (int)list2int( sym->ival ) ); } else { fprintf( stderr, "ERROR: Symbol %s, which is covering a __CONFIG word must be initialized!\n", sym->name ); } continue; } if (max == -1 || addr > max) max = addr; if (min == -1 || addr < min) min = addr; //fprintf (stderr, "%s: sym %s @ 0x%x\n", __FUNCTION__, sym->name, addr); aliases = hTabItemWithKey (ht, addr); if (aliases) { /* May not use addSetHead, as we cannot update the * list's head in the hastable `ht'. */ addSet (&aliases, sym); #if 0 fprintf( stderr, "%s: now %d aliases for %s @ 0x%x\n", __FUNCTION__, elementsInSet(aliases), sym->name, addr); #endif } else { addSet (&aliases, sym); hTabAddItem (&ht, addr, aliases); } // if } // if } // for sym } // for i /* now emit definitions for all absolute symbols */ dbuf_printf (oBuf, "%s", iComments2); dbuf_printf (oBuf, "; absolute symbol definitions\n"); dbuf_printf (oBuf, "%s", iComments2); for (addr=min; addr <= max; addr++) { size = 1; aliases = hTabItemWithKey (ht, addr); if (aliases && elementsInSet(aliases)) { /* Make sure there is no initialized value at this location! */ for (sym = setFirstItem(aliases); sym; sym = setNextItem(aliases)) { if (sym->ival) break; } // for if (sym) continue; dbuf_printf (oBuf, "UD_abs_%s_%x\tudata_ovr\t0x%04x\n", moduleName, addr, addr); for (sym = setFirstItem (aliases); sym; sym = setNextItem (aliases)) { if (getSize(sym->type) > size) { size = getSize(sym->type); } /* initialized values are handled somewhere else */ if (sym->ival) continue; /* emit STATUS as well as _STATUS, required for SFRs only */ //dbuf_printf (oBuf, "%s\tres\t0\n", sym->name); dbuf_printf (oBuf, "%s\n", sym->rname); if (IS_GLOBAL(sym) && !IS_STATIC(sym->etype)) { //emitIfNew(gloBuf, &emitted, "\tglobal\t%s\n", sym->name); emitIfNew(gloBuf, &emitted, "\tglobal\t%s\n", sym->rname); } // if } // for dbuf_printf (oBuf, "\tres\t%d\n", size); } // if } // for i } /*-----------------------------------------------------------------*/ /* createInterruptVect - creates the interrupt vector */ /*-----------------------------------------------------------------*/ static void pic14createInterruptVect (struct dbuf_s * vBuf) { mainf = newSymbol ("main", 0); mainf->block = 0; /* only if the main function exists */ if (!(mainf = findSymWithLevel (SymbolTab, mainf))) { struct options *op = &options; if (!(op->cc_only || noAssemble)) // werror (E_NO_MAIN); fprintf(stderr,"WARNING: function 'main' undefined\n"); return; } /* if the main is only a prototype ie. no body then do nothing */ if (!IFFUNC_HASBODY(mainf->type)) { /* if ! compile only then main function should be present */ if (!(options.cc_only || noAssemble)) // werror (E_NO_MAIN); fprintf(stderr,"WARNING: function 'main' undefined\n"); return; } dbuf_printf (vBuf, "%s", iComments2); dbuf_printf (vBuf, "; reset vector \n"); dbuf_printf (vBuf, "%s", iComments2); // Lkr file should place section STARTUP at address 0x0, but does not ... dbuf_printf (vBuf, "STARTUP\t%s 0x0000\n", CODE_NAME); dbuf_printf (vBuf, "\tnop\n"); /* first location for used by incircuit debugger */ dbuf_printf (vBuf, "\tpagesel __sdcc_gsinit_startup\n"); dbuf_printf (vBuf, "\tgoto\t__sdcc_gsinit_startup\n"); popGetExternal("__sdcc_gsinit_startup", 0); } /*-----------------------------------------------------------------*/ /* initialComments - puts in some initial comments */ /*-----------------------------------------------------------------*/ static void pic14initialComments (FILE * afile) { initialComments (afile); fprintf (afile, "; PIC port for the 14-bit core\n"); fprintf (afile, "%s", iComments2); } int pic14_stringInSet(const char *str, set **world, int autoAdd) { char *s; if (!str) return TRUE; assert(world); for (s = setFirstItem(*world); s; s = setNextItem(*world)) { /* found in set */ if (0 == strcmp(s, str)) return TRUE; } /* not found */ if (autoAdd) addSet(world, Safe_strdup(str)); return FALSE; } static void pic14printLocals (struct dbuf_s *oBuf) { set *allregs[6] = { dynAllocRegs/*, dynStackRegs, dynProcessorRegs*/, dynDirectRegs, dynDirectBitRegs/*, dynInternalRegs */ }; reg_info *reg; int i, is_first = TRUE; static unsigned sectionNr = 0; const char *split_locals; split_locals = getenv("SDCC_PIC14_SPLIT_LOCALS"); /* emit all registers from all possible sets */ for (i = 0; i < 6; i++) { if (allregs[i] == NULL) continue; for (reg = setFirstItem(allregs[i]); reg; reg = setNextItem(allregs[i])) { if (reg->isEmitted) continue; if (reg->wasUsed && !reg->isExtern) { if (!pic14_stringInSet(reg->name, &emitted, TRUE)) { if (reg->isFixed) { // Should not happen, really... assert ( !"Compiler-assigned variables should not be pinned... This is a bug." ); dbuf_printf(oBuf, "UDL_%s_%u\tudata\t0x%04X\n%s\tres\t%d\n", moduleName, sectionNr++, reg->address, reg->name, reg->size); } else { if (split_locals != NULL) { // assign each local register into its own section dbuf_printf(oBuf, "UDL_%s_%u\tudata\n%s\tres\t%d\n", moduleName, sectionNr++, reg->name, reg->size); } else { // group all local registers into a single section // This should greatly improve BANKSEL generation... if (is_first) { dbuf_printf(oBuf, "UDL_%s_%u\tudata\n", moduleName, sectionNr++); is_first = FALSE; } dbuf_printf(oBuf, "%s\tres\t%d\n", reg->name, reg->size); } } } } reg->isEmitted = TRUE; } // for } // for } /*-----------------------------------------------------------------*/ /* emitOverlay - will emit code for the overlay stuff */ /*-----------------------------------------------------------------*/ static void pic14emitOverlay (struct dbuf_s * aBuf) { set *ovrset; /* if (!elementsInSet (ovrSetSets))*/ /* the hack below, fixes translates for devices which * only have udata_shr memory */ dbuf_printf (aBuf, "%s\t%s\n", (elementsInSet(ovrSetSets)?"":";"), port->mem.overlay_name); /* for each of the sets in the overlay segment do */ for (ovrset = setFirstItem (ovrSetSets); ovrset; ovrset = setNextItem (ovrSetSets)) { symbol *sym; if (elementsInSet (ovrset)) { /* this dummy area is used to fool the assembler otherwise the assembler will append each of these declarations into one chunk and will not overlay sad but true */ /* I don't think this applies to us. We are using gpasm. CRF */ dbuf_tprintf (aBuf, ";\t!area\n", "_DUMMY"); /* output the area informtion */ dbuf_tprintf (aBuf, ";\t!area\t\n", port->mem.overlay_name); /* MOF */ } for (sym = setFirstItem (ovrset); sym; sym = setNextItem (ovrset)) { /* if extern then do nothing */ if (IS_EXTERN (sym->etype)) continue; /* if allocation required check is needed then check if the symbol really requires allocation only for local variables */ if (!IS_AGGREGATE (sym->type) && !(sym->_isparm && !IS_REGPARM (sym->etype)) && !sym->allocreq && sym->level) continue; /* if global variable & not static or extern and addPublics allowed then add it to the public set */ if ((sym->_isparm && !IS_REGPARM (sym->etype)) && !IS_STATIC (sym->etype)) addSetHead (&publics, sym); /* if extern then do nothing or is a function then do nothing */ if (IS_FUNC (sym->type)) continue; /* print extra debug info if required */ if (options.debug || sym->level == 0) { if (!sym->level) { /* global */ if (IS_STATIC (sym->etype)) dbuf_printf (aBuf, "F%s_", moduleName); /* scope is file */ else dbuf_printf (aBuf, "G_"); /* scope is global */ } else /* symbol is local */ dbuf_printf (aBuf, "L%s_", (sym->localof ? sym->localof->name : "-null-")); dbuf_printf (aBuf, "%s_%ld_%d", sym->name, sym->level, sym->block); } /* if is has an absolute address then generate an equate for this no need to allocate space */ if (SPEC_ABSA (sym->etype)) { if (options.debug || sym->level == 0) dbuf_printf (aBuf, " == 0x%04x\n", SPEC_ADDR (sym->etype)); dbuf_printf (aBuf, "%s\t=\t0x%04x\n", sym->rname, SPEC_ADDR (sym->etype)); } else { if (options.debug || sym->level == 0) dbuf_printf (aBuf, "==.\n"); /* allocate space */ dbuf_printf (aBuf, "%s:\n", sym->rname); dbuf_printf (aBuf, "\t.ds\t0x%04x\n", (unsigned int) getSize (sym->type) & 0xffff); } } } } static void pic14_emitInterruptHandler (FILE * asmFile) { if (pic14_hasInterrupt) { fprintf (asmFile, "%s", iComments2); fprintf (asmFile, "; interrupt and initialization code\n"); fprintf (asmFile, "%s", iComments2); // Note - for mplink may have to enlarge section vectors in .lnk file // Note: Do NOT name this code_interrupt to avoid nameclashes with // source files's code segment (interrupt.c -> code_interrupt) fprintf (asmFile, "c_interrupt\t%s\t0x0004\n", CODE_NAME); /* interrupt service routine */ fprintf (asmFile, "__sdcc_interrupt:\n"); copypCode(asmFile, 'I'); } } /*-----------------------------------------------------------------*/ /* glue - the final glue that hold the whole thing together */ /*-----------------------------------------------------------------*/ void picglue (void) { FILE *asmFile; struct dbuf_s ovrBuf; struct dbuf_s vBuf; dbuf_init(&ovrBuf, 4096); dbuf_init(&vBuf, 4096); pCodeInitRegisters(); /* check for main() */ mainf = newSymbol ("main", 0); mainf->block = 0; mainf = findSymWithLevel (SymbolTab, mainf); if (!mainf || !IFFUNC_HASBODY(mainf->type)) { /* main missing -- import stack from main module */ //fprintf (stderr, "main() missing -- assuming we are NOT the main module\n"); pic14_options.isLibrarySource = TRUE; } /* At this point we've got all the code in the form of pCode structures */ /* Now it needs to be rearranged into the order it should be placed in the */ /* code space */ movepBlock2Head('P'); // Last movepBlock2Head(code->dbName); movepBlock2Head('X'); movepBlock2Head(statsg->dbName); // First /* print the global struct definitions */ if (options.debug) cdbStructBlock (0); /* do the overlay segments */ pic14emitOverlay(&ovrBuf); /* PENDING: this isnt the best place but it will do */ if (port->general.glue_up_main) { /* create the interrupt vector table */ pic14createInterruptVect (&vBuf); } AnalyzepCode('*'); ReuseReg(); // ReuseReg where call tree permits InlinepCode(); AnalyzepCode('*'); if (options.debug) pcode_test(); /* now put it all together into the assembler file */ /* create the assembler file name */ if ((noAssemble || options.c1mode) && fullDstFileName) { SNPRINTF(buffer, sizeof(buffer), "%s", fullDstFileName); } else { SNPRINTF(buffer, sizeof(buffer), "%s.asm", dstFileName); } if (!(asmFile = fopen (buffer, "w"))) { werror (E_FILE_OPEN_ERR, buffer); exit (1); } /* prepare statistics */ resetpCodeStatistics (); /* initial comments */ pic14initialComments (asmFile); /* print module name */ fprintf (asmFile, "%s\t.file\t\"%s\"\n", options.debug ? "" : ";", fullSrcFileName); /* Let the port generate any global directives, etc. */ if (port->genAssemblerPreamble) { port->genAssemblerPreamble(asmFile); } /* Put all variables into a cblock */ AnalyzeBanking(); /* emit initialized data */ showAllMemmaps(asmFile); /* print the locally defined variables in this module */ writeUsedRegs(asmFile); /* create the overlay segments */ fprintf (asmFile, "%s", iComments2); fprintf (asmFile, "; overlayable items in internal ram \n"); fprintf (asmFile, "%s", iComments2); dbuf_write_and_destroy (&ovrBuf, asmFile); /* copy the interrupt vector table */ if (mainf && IFFUNC_HASBODY(mainf->type)) dbuf_write_and_destroy (&vBuf, asmFile); else dbuf_destroy(&vBuf); /* create interupt vector handler */ pic14_emitInterruptHandler (asmFile); /* copy over code */ fprintf (asmFile, "%s", iComments2); fprintf (asmFile, "; code\n"); fprintf (asmFile, "%s", iComments2); fprintf (asmFile, "code_%s\t%s\n", moduleName, port->mem.code_name); /* unknown */ copypCode(asmFile, 'X'); /* _main function */ copypCode(asmFile, 'M'); /* other functions */ copypCode(asmFile, code->dbName); /* unknown */ copypCode(asmFile, 'P'); dumppCodeStatistics (asmFile); fprintf (asmFile,"\tend\n"); fclose (asmFile); pic14_debugLogClose(); } /* * Deal with initializers. */ #undef DEBUGprintf #if 0 // debugging output #define DEBUGprintf printf #else // be quiet #define DEBUGprintf 1 ? (void)0 : (void)printf #endif static char * parseIvalAst (ast *node, int *inCodeSpace) { #define LEN 4096 char *buffer = NULL; char *left, *right; if (IS_AST_VALUE(node)) { value *val = AST_VALUE(node); symbol *sym = IS_AST_SYM_VALUE(node) ? AST_SYMBOL(node) : NULL; if (inCodeSpace && val->type && (IS_FUNC(val->type) || IS_CODE(getSpec(val->type)))) { *inCodeSpace = TRUE; } if (inCodeSpace && sym && (IS_FUNC(sym->type) || IS_CODE(getSpec(sym->type)))) { *inCodeSpace = TRUE; } DEBUGprintf ("%s: AST_VALUE\n", __FUNCTION__); if (IS_AST_LIT_VALUE(node)) { buffer = Safe_alloc(LEN); SNPRINTF(buffer, LEN, "0x%lx", AST_ULONG_VALUE (node)); } else if (IS_AST_SYM_VALUE(node)) { assert ( AST_SYMBOL(node) ); /* printf ("sym %s: ", AST_SYMBOL(node)->rname); printTypeChain(AST_SYMBOL(node)->type, stdout); printTypeChain(AST_SYMBOL(node)->etype, stdout); printf ("\n---sym %s: done\n", AST_SYMBOL(node)->rname); */ buffer = Safe_strdup(AST_SYMBOL(node)->rname); } else { assert ( !"Invalid values type for initializers in AST." ); } } else if (IS_AST_OP(node)) { DEBUGprintf ("%s: AST_OP\n", __FUNCTION__); switch (node->opval.op) { case CAST: assert (node->right); buffer = parseIvalAst(node->right, inCodeSpace); DEBUGprintf ("%s: %s\n", __FUNCTION__, buffer); break; case '&': assert ( node->left && !node->right ); buffer = parseIvalAst(node->left, inCodeSpace); DEBUGprintf ("%s: %s\n", __FUNCTION__, buffer); break; case '+': assert (node->left && node->right ); left = parseIvalAst(node->left, inCodeSpace); right = parseIvalAst(node->right, inCodeSpace); buffer = Safe_alloc(LEN); SNPRINTF(buffer, LEN, "(%s + %s)", left, right); DEBUGprintf ("%s: %s\n", __FUNCTION__, buffer); Safe_free(left); Safe_free(right); break; case '[': assert ( node->left && node->right ); assert ( IS_AST_VALUE(node->left) && AST_VALUE(node->left)->sym ); right = parseIvalAst(node->right, inCodeSpace); buffer = Safe_alloc(LEN); SNPRINTF(buffer, LEN, "(%s + %u * %s)", AST_VALUE(node->left)->sym->rname, getSize(AST_VALUE(node->left)->type), right); Safe_free(right); DEBUGprintf ("%s: %s\n", __FUNCTION__, &buffer[0]); break; default: assert ( !"Unhandled operation in initializer." ); break; } } else { assert ( !"Invalid construct in initializer." ); } return (buffer); } /* * Emit the section preamble, absolute location (if any) and * symbol name(s) for intialized data. */ static int emitIvalLabel(struct dbuf_s *oBuf, symbol *sym) { char *segname; static int in_code = FALSE; static int sectionNr = 0; if (sym) { // code or data space? if (IS_CODE(getSpec(sym->type))) { segname = "code"; in_code = TRUE; } else { segname = "idata"; in_code = FALSE; } dbuf_printf(oBuf, "\nID_%s_%d\t%s", moduleName, sectionNr++, segname); if (SPEC_ABSA(getSpec(sym->type))) { // specify address for absolute symbols dbuf_printf(oBuf, "\t0x%04X", SPEC_ADDR(getSpec(sym->type))); } // if dbuf_printf(oBuf, "\n%s\n", sym->rname); addSet(&emitted, sym->rname); } return (in_code); } /* * Actually emit the initial values in .asm format. */ static void emitIvals(struct dbuf_s *oBuf, symbol *sym, initList *list, long lit, int size) { int i; ast *node; operand *op; value *val = NULL; int inCodeSpace = FALSE; char *str = NULL; int in_code; assert (size <= sizeof(long)); assert (!list || (list->type == INIT_NODE)); node = list ? list->init.node : NULL; in_code = emitIvalLabel(oBuf, sym); if (!in_code) dbuf_printf (oBuf, "\tdb\t"); if (!node) { for (i = 0; i < size; i++) { if (in_code) { dbuf_printf (oBuf, "\tretlw 0x%02x\n", (int)(lit & 0xff)); // dbuf_printf (oBuf, "\tretlw 0x00\n"); // conflict from merge of sf-patch-2991122 ? } else { dbuf_printf (oBuf, "%s0x%02x", (i == 0) ? "" : ", ", (int)(lit & 0xff)); } lit >>= 8; } // for if (!in_code) dbuf_printf (oBuf, "\n"); return; } // if op = NULL; if (constExprTree(node) && (val = constExprValue(node, 0))) { op = operandFromValue(val); DEBUGprintf ("%s: constExpr ", __FUNCTION__); } else if (IS_AST_VALUE(node)) { op = operandFromAst(node, 0); } else if (IS_AST_OP(node)) { str = parseIvalAst(node, &inCodeSpace); DEBUGprintf("%s: AST_OP: %s\n", __FUNCTION__, str); op = NULL; } else { assert ( !"Unhandled construct in intializer." ); } if (op) { aopOp(op, NULL, 1); assert(AOP(op)); //printOperand(op, of); } for (i = 0; i < size; i++) { char *text; /* * FIXME: This is hacky and needs some more thought. */ if (op && IS_SYMOP(op) && IS_FUNC(OP_SYM_TYPE(op))) { /* This branch is introduced to fix #1427663. */ PCOI(AOP(op)->aopu.pcop)->offset+=i; text = get_op(AOP(op)->aopu.pcop, NULL, 0); PCOI(AOP(op)->aopu.pcop)->offset-=i; } else { text = op ? aopGet(AOP(op), i, 0, 0) : get_op(newpCodeOpImmd(str, i, 0, inCodeSpace, 0), NULL, 0); } // if if (in_code) { dbuf_printf (oBuf, "\tretlw %s\n", text); } else { dbuf_printf (oBuf, "%s%s", (i == 0) ? "" : ", ", text); } } // for if (!in_code) dbuf_printf (oBuf, "\n"); } /* * For UNIONs, we first have to find the correct alternative to map the * initializer to. This function maps the structure of the initializer to * the UNION members recursively. * Returns the type of the first `fitting' member. */ static sym_link * matchIvalToUnion (initList *list, sym_link *type, int size) { symbol *sym; assert (type); if (IS_PTR(type) || IS_CHAR(type) || IS_INT(type) || IS_LONG(type) || IS_FLOAT(type)) { if (!list || (list->type == INIT_NODE)) { DEBUGprintf ("OK, simple type\n"); return (type); } else { DEBUGprintf ("ERROR, simple type\n"); return (NULL); } } else if (IS_BITFIELD(type)) { if (!list || (list->type == INIT_NODE)) { DEBUGprintf ("OK, bitfield\n"); return (type); } else { DEBUGprintf ("ERROR, bitfield\n"); return (NULL); } } else if (IS_STRUCT(type) && SPEC_STRUCT(getSpec(type))->type == STRUCT) { if (!list || (list->type == INIT_DEEP)) { if (list) list = list->init.deep; sym = SPEC_STRUCT(type)->fields; while (sym) { DEBUGprintf ("Checking STRUCT member %s\n", sym->name); if (!matchIvalToUnion(list, sym->type, 0)) { DEBUGprintf ("ERROR, STRUCT member %s\n", sym->name); return (NULL); } if (list) list = list->next; sym = sym->next; } // while // excess initializers? if (list) { DEBUGprintf ("ERROR, excess initializers\n"); return (NULL); } DEBUGprintf ("OK, struct\n"); return (type); } return (NULL); } else if (IS_STRUCT(type) && SPEC_STRUCT(getSpec(type))->type == UNION) { if (!list || (list->type == INIT_DEEP)) { if (list) list = list->init.deep; sym = SPEC_STRUCT(type)->fields; while (sym) { while (list && list->type == INIT_HOLE) { list = list->next; sym = sym->next; } DEBUGprintf ("Checking UNION member %s.\n", sym->name); if (((IS_STRUCT(sym->type) || getSize(sym->type) == size)) && matchIvalToUnion(list, sym->type, size)) { DEBUGprintf ("Matched UNION member %s.\n", sym->name); return (sym->type); } sym = sym->next; } // while } // if // no match found DEBUGprintf ("ERROR, no match found.\n"); return (NULL); } else { assert ( !"Unhandled type in UNION." ); } assert ( !"No match found in UNION for the given initializer structure." ); return (NULL); } /* * Parse the type and its initializer and emit it (recursively). */ static void emitInitVal(struct dbuf_s *oBuf, symbol *topsym, sym_link *my_type, initList *list) { symbol *sym; int size; long lit; unsigned char *str; /* Handle designated initializers */ if (list) list = reorderIlist (my_type, list); /* If this is a hole, substitute an appropriate initializer. */ if (list && list->type == INIT_HOLE) { if (IS_AGGREGATE (my_type)) { list = newiList(INIT_DEEP, NULL); /* init w/ {} */ } else { ast *ast = newAst_VALUE (constVal("0")); ast = decorateType (ast, RESULT_TYPE_NONE); list = newiList(INIT_NODE, ast); } } size = getSize(my_type); if (IS_PTR(my_type)) { DEBUGprintf ("(pointer, %d byte) 0x%x\n", size, list ? (unsigned int)list2int(list) : 0); emitIvals(oBuf, topsym, list, 0, size); return; } if (IS_ARRAY(my_type) && topsym && topsym->isstrlit) { str = (unsigned char *)SPEC_CVAL(topsym->etype).v_char; emitIvalLabel(oBuf, topsym); do { dbuf_printf (oBuf, "\tretlw 0x%02x ; '%c'\n", str[0], (str[0] >= 0x20 && str[0] < 128) ? str[0] : '.'); } while (*(str++)); return; } if (IS_ARRAY(my_type) && list && list->type == INIT_NODE) { fprintf (stderr, "Unhandled initialized symbol: %s\n", topsym->name); assert ( !"Initialized char-arrays are not yet supported, assign at runtime instead." ); return; } if (IS_ARRAY(my_type)) { size_t i; DEBUGprintf ("(array, %d items, %ud byte) below\n", (unsigned int) DCL_ELEM(my_type), size); assert (!list || list->type == INIT_DEEP); if (list) list = list->init.deep; for (i = 0; i < DCL_ELEM(my_type); i++) { emitInitVal(oBuf, topsym, my_type->next, list); topsym = NULL; if (list) list = list->next; } // for i return; } if (IS_FLOAT(my_type)) { // float, 32 bit DEBUGprintf ("(float, %d byte) %lf\n", size, list ? list2int(list) : 0.0); emitIvals(oBuf, topsym, list, 0, size); return; } if (IS_CHAR(my_type) || IS_INT(my_type) || IS_LONG(my_type) || IS_BOOL(my_type)) { // integral type, 8, 16, or 32 bit DEBUGprintf ("(integral, %d byte) 0x%lx/%ld\n", size, list ? (long)list2int(list) : 0, list ? (long)list2int(list) : 0); emitIvals(oBuf, topsym, list, 0, size); return; } else if (IS_STRUCT(my_type) && SPEC_STRUCT(my_type)->type == STRUCT) { // struct DEBUGprintf ("(struct, %d byte) handled below\n", size); assert (!list || (list->type == INIT_DEEP)); // iterate over struct members and initList if (list) list = list->init.deep; sym = SPEC_STRUCT(my_type)->fields; while (sym) { long bitfield = 0; int len = 0; if (IS_BITFIELD(sym->type)) { while (sym && IS_BITFIELD(sym->type)) { int bitoff = SPEC_BSTR(getSpec(sym->type)) + 8 * sym->offset; assert (!list || ((list->type == INIT_NODE) && IS_AST_LIT_VALUE(list->init.node))); lit = (long) (list ? list2int(list) : 0); DEBUGprintf ( "(bitfield member) %02lx (%d bit, starting at %d, bitfield %02lx)\n", lit, SPEC_BLEN(getSpec(sym->type)), bitoff, bitfield); bitfield |= (lit & ((1ul << SPEC_BLEN(getSpec(sym->type))) - 1)) << bitoff; len += SPEC_BLEN(getSpec(sym->type)); sym = sym->next; if (list) list = list->next; } // while assert (len < sizeof (long) * 8); // did we overflow our initializer?!? len = (len + 7) & ~0x07; // round up to full bytes emitIvals(oBuf, topsym, NULL, bitfield, len / 8); topsym = NULL; } // if if (sym) { emitInitVal(oBuf, topsym, sym->type, list); topsym = NULL; sym = sym->next; if (list) list = list->next; } // if } // while if (list) { assert ( !"Excess initializers." ); } // if return; } else if (IS_STRUCT(my_type) && SPEC_STRUCT(my_type)->type == UNION) { // union DEBUGprintf ("(union, %d byte) handled below\n", size); assert (list && list->type == INIT_DEEP); // iterate over union members and initList, try to map number and type of fields and initializers my_type = matchIvalToUnion(list, my_type, size); if (my_type) { emitInitVal(oBuf, topsym, my_type, list->init.deep); topsym = NULL; size -= getSize(my_type); if (size > 0) { // pad with (leading) zeros emitIvals(oBuf, NULL, NULL, 0, size); } return; } // if assert ( !"No UNION member matches the initializer structure."); } else if (IS_BITFIELD(my_type)) { assert ( !"bitfields should only occur in structs..." ); } else { printf ("SPEC_NOUN: %d\n", SPEC_NOUN(my_type)); assert( !"Unhandled initialized type."); } } /* * Emit a set of symbols. * type - 0: have symbol tell whether it is local, extern or global * 1: assume all symbols in set to be global * 2: assume all symbols in set to be extern */ static void emitSymbolSet(set *s, int type) { symbol *sym; initList *list; unsigned int sectionNr = 0; for (sym = setFirstItem(s); sym; sym = setNextItem(s)) { #if 0 fprintf (stdout, "; name %s, rname %s, level %d, block %d, key %d, local %d, ival %p, static %d, cdef %d, used %d\n", sym->name, sym->rname, sym->level, sym->block, sym->key, sym->islocal, sym->ival, IS_STATIC(sym->etype), sym->cdef, sym->used); #endif if (sym->etype && SPEC_ABSA(sym->etype) && IS_CONFIG_ADDRESS(SPEC_ADDR(sym->etype)) && sym->ival) { // handle config words pic14_assignConfigWordValue(SPEC_ADDR(sym->etype), (int)list2int(sym->ival)); pic14_stringInSet(sym->rname, &emitted, 1); continue; } if (sym->isstrlit) { // special case: string literals emitInitVal(ivalBuf, sym, sym->type, NULL); continue; } if (type != 0 || sym->cdef || (!IS_STATIC(sym->etype) && IS_GLOBAL(sym))) { // bail out for ___fsadd and friends if (sym->cdef && !sym->used) continue; /* export or import non-static globals */ if (!pic14_stringInSet(sym->rname, &emitted, 0)) { if (type == 2 || IS_EXTERN(sym->etype) || sym->cdef) { /* do not add to emitted set, it might occur again! */ //if (!sym->used) continue; // declare symbol emitIfNew (extBuf, &emitted, "\textern\t%s\n", sym->rname); } else { // declare symbol emitIfNew (gloBuf, &emitted, "\tglobal\t%s\n", sym->rname); if (!sym->ival && !IS_FUNC(sym->type)) { // also define symbol if (IS_ABSOLUTE(sym->etype)) { // absolute location? //dbuf_printf (gloDefBuf, "UD_%s_%u\tudata\t0x%04X\n", moduleName, sectionNr++, SPEC_ADDR(sym->etype)); // deferred to pic14_constructAbsMap } else { dbuf_printf (gloDefBuf, "UD_%s_%u\tudata\n", moduleName, sectionNr++); dbuf_printf (gloDefBuf, "%s\tres\t%d\n\n", sym->rname, getSize(sym->type)); } } // if } // if pic14_stringInSet(sym->rname, &emitted, 1); } // if } // if list = sym->ival; //if (list) showInitList(list, 0); if (list) { resolveIvalSym( list, sym->type ); emitInitVal(ivalBuf, sym, sym->type, sym->ival); dbuf_printf (ivalBuf, "\n"); } } // for sym } /* * Iterate over all memmaps and emit their contents (attributes, symbols). */ static void showAllMemmaps(FILE *of) { struct dbuf_s locBuf; memmap *maps[] = { xstack, istack, code, data, pdata, xdata, xidata, xinit, idata, bit, statsg, c_abs, x_abs, i_abs, d_abs, sfr, sfrbit, reg, generic, overlay, eeprom, home }; memmap * map; int i; DEBUGprintf ("---begin memmaps---\n"); if (!extBuf) extBuf = dbuf_new(1024); if (!gloBuf) gloBuf = dbuf_new(1024); if (!gloDefBuf) gloDefBuf = dbuf_new(1024); if (!ivalBuf) ivalBuf = dbuf_new(1024); dbuf_init(&locBuf, 1024); dbuf_printf (extBuf, "%s; external declarations\n%s", iComments2, iComments2); dbuf_printf (gloBuf, "%s; global declarations\n%s", iComments2, iComments2); dbuf_printf (gloDefBuf, "%s; global definitions\n%s", iComments2, iComments2); dbuf_printf (ivalBuf, "%s; initialized data\n%s", iComments2, iComments2); dbuf_printf (&locBuf, "%s; compiler-defined variables\n%s", iComments2, iComments2); for (i = 0; i < sizeof(maps) / sizeof (memmap *); i++) { map = maps[i]; //DEBUGprintf ("memmap %i: %p\n", i, map); if (map) { #if 0 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", map->pageno, map->sname, map->dbName, map->ptrType, map->slbl, map->sloc, map->fmap, map->paged, map->direct, map->bitsp, map->codesp, map->regsp, map->syms); #endif emitSymbolSet(map->syms, 0); } // if (map) } // for i DEBUGprintf ("---end of memmaps---\n"); emitSymbolSet(publics, 1); emitSymbolSet(externs, 2); emitPseudoStack(gloBuf, extBuf); pic14_constructAbsMap(gloDefBuf, gloBuf); pic14printLocals (&locBuf); pic14_emitConfigWord(of); // must be done after all the rest dbuf_write_and_destroy(extBuf, of); dbuf_write_and_destroy(gloBuf, of); dbuf_write_and_destroy(gloDefBuf, of); dbuf_write_and_destroy(&locBuf, of); dbuf_write_and_destroy(ivalBuf, of); extBuf = gloBuf = gloDefBuf = ivalBuf = NULL; }