diff options
| author | Xavier ASUS <xavi92psx@gmail.com> | 2019-10-18 00:31:54 +0200 |
|---|---|---|
| committer | Xavier ASUS <xavi92psx@gmail.com> | 2019-10-18 00:31:54 +0200 |
| commit | 268a53de823a6750d6256ee1fb1e7707b4b45740 (patch) | |
| tree | 42c1799a9a82b2f7d9790ee9fe181d72a7274751 /src/SDCCglue.c | |
| download | sdcc-gas-268a53de823a6750d6256ee1fb1e7707b4b45740.tar.gz | |
sdcc-3.9.0 fork implementing GNU assembler syntax
This fork aims to provide better support for stm8-binutils
Diffstat (limited to 'src/SDCCglue.c')
| -rw-r--r-- | src/SDCCglue.c | 2674 |
1 files changed, 2674 insertions, 0 deletions
diff --git a/src/SDCCglue.c b/src/SDCCglue.c new file mode 100644 index 0000000..8251c43 --- /dev/null +++ b/src/SDCCglue.c @@ -0,0 +1,2674 @@ +/*------------------------------------------------------------------------- + SDCCglue.c - glues everything we have done together into one file. + + Copyright (C) 1998 Sandeep Dutta . sandeep.dutta@usa.net + + 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. +-------------------------------------------------------------------------*/ + +#include "common.h" +#include <time.h> +#include "newalloc.h" +#include <fcntl.h> +#include <sys/stat.h> +#include "dbuf_string.h" + +#ifdef _WIN32 +#include <io.h> +#else +#include <unistd.h> +#endif + +symbol *interrupts[INTNO_MAX + 1]; + +void printIval (symbol *, sym_link *, initList *, struct dbuf_s *, bool check); +set *publics = NULL; /* public variables */ +set *externs = NULL; /* Variables that are declared as extern */ +set *strSym = NULL; /* string initializers */ +set *ccpStr = NULL; /* char * const pointers with a string literal initializer */ + +unsigned maxInterrupts = 0; +int allocInfo = 1; +symbol *mainf; +int noInit = 0; /* no initialization */ + + +char * +aopLiteralGptr (const char * name, value * val) +{ + unsigned long v = ulFromVal (val); + struct dbuf_s dbuf; + + dbuf_init (&dbuf, 128); + + v >>= ((GPTRSIZE - 1) * 8); + + if (IS_FUNCPTR (val->type)) + dbuf_tprintf (&dbuf, "!immedbyte", v | pointerTypeToGPByte (DCL_TYPE (val->type->next), val->name, name)); + else if (IS_PTR (val->type) && !IS_GENPTR (val->type)) + dbuf_tprintf (&dbuf, "!immedbyte", pointerTypeToGPByte (DCL_TYPE (val->type), val->name, name)); + else + dbuf_tprintf (&dbuf, "!immedbyte", (unsigned int) v & 0xff); + + return dbuf_detach_c_str (&dbuf); +} + +const char * +aopLiteralLong (value *val, int offset, int size) +{ + unsigned long v; + struct dbuf_s dbuf; + + if (!val) + { + // assuming we have been warned before + val = constCharVal (0); + } + + dbuf_init (&dbuf, 128); + + switch (size) + { + case 1: + v = byteOfVal (val, offset); + dbuf_tprintf (&dbuf, "!immedbyte", (unsigned int) v & 0xff); + break; + case 2: + v = byteOfVal (val, offset+1); + v = (v << 8) | byteOfVal (val, offset); + dbuf_tprintf (&dbuf, "!immedword", (unsigned int) v & 0xffff); + break; + case 3: + v = byteOfVal (val, offset+2); + v = (v << 8) | byteOfVal (val, offset+1); + v = (v << 8) | byteOfVal (val, offset); + // we don't have a !immedword24 yet for ds390 + dbuf_printf (&dbuf, "#0x%06X", (unsigned int) v & 0xffffff); + break; + default: + /* Hmm. Too big for now. */ + assert (0); + } + return dbuf_detach_c_str (&dbuf); +} + +/*-----------------------------------------------------------------*/ +/* aopLiteral - string from a literal value */ +/*-----------------------------------------------------------------*/ +const char * +aopLiteral (value *val, int offset) +{ + return aopLiteralLong (val, offset, 1); +} + +/*-----------------------------------------------------------------*/ +/* emitDebugSym - emit label for debug symbol */ +/*-----------------------------------------------------------------*/ +static void +emitDebugSym (struct dbuf_s *oBuf, symbol * sym) +{ + if (sym->level && sym->localof) /* symbol scope is local */ + { + dbuf_printf (oBuf, "L%s.%s$", moduleName, sym->localof->name); + } + else if (IS_STATIC (sym->etype)) /* symbol scope is file */ + { + dbuf_printf (oBuf, "F%s$", moduleName); + } + else /* symbol scope is global */ + { + dbuf_printf (oBuf, "G$"); + } + dbuf_printf (oBuf, "%s$%ld_%ld$%d", sym->name, sym->level / LEVEL_UNIT, sym->level % LEVEL_UNIT, sym->block); +} + +/*-----------------------------------------------------------------*/ +/* emitRegularMap - emit code for maps with no special cases */ +/*-----------------------------------------------------------------*/ +static void +emitRegularMap (memmap *map, bool addPublics, bool arFlag) +{ + symbol *sym; + ast *ival = NULL; + + if (!map) + return; + + if (addPublics) + { + /* PENDING: special case here - should remove */ + if (!strcmp (map->sname, CODE_NAME)) + dbuf_tprintf (&map->oBuf, "\t!areacode\n", map->sname); + else if (!strcmp (map->sname, DATA_NAME)) + { + dbuf_tprintf (&map->oBuf, "\t!areadata\n", map->sname); + if (options.data_seg && strcmp (DATA_NAME, options.data_seg)) + dbuf_tprintf (&map->oBuf, "\t!area\n", options.data_seg); + } + else if (!strcmp (map->sname, HOME_NAME)) + dbuf_tprintf (&map->oBuf, "\t!areahome\n", map->sname); + else + dbuf_tprintf (&map->oBuf, "\t!area\n", map->sname); + + if (map->regsp) + dbuf_tprintf (&map->oBuf, "\t!org\n", 0); + } + + for (sym = setFirstItem (map->syms); sym; sym = setNextItem (map->syms)) + { + symbol *newSym = NULL; + + /* if allocation required check is needed + then check if the symbol really requires + allocation only for local variables */ + + if (arFlag && !IS_AGGREGATE (sym->type) && !(sym->_isparm && !IS_REGPARM (sym->etype)) && !sym->allocreq && sym->level) + continue; + + /* for bitvar locals and parameters */ + if (!arFlag && !sym->allocreq && sym->level && !SPEC_ABSA (sym->etype)) + { + continue; + } + + /* if global variable & not static or extern + and addPublics allowed then add it to the public set */ + if ((sym->level == 0 || + (sym->_isparm && !IS_REGPARM (sym->etype) && !IS_STATIC (sym->localof->etype))) && + addPublics && + !IS_STATIC (sym->etype) && + (IS_FUNC (sym->type) ? (sym->used || IFFUNC_HASBODY (sym->type)) : (!IS_EXTERN (sym->etype) || sym->ival)) && + !(IFFUNC_ISINLINE (sym->type) && !IS_STATIC (sym->etype) && !IS_EXTERN (sym->etype))) + { + addSetHead (&publics, sym); + } + + /* if extern then add it into the extern list */ + if (IS_EXTERN (sym->etype) && !sym->ival) + { + addSetHead (&externs, sym); + continue; + } + + /* if extern then do nothing or is a function + then do nothing */ + if (IS_FUNC (sym->type) && !(sym->isitmp)) + continue; + + /* if it has an initial value then do it only if + it is a global variable */ + if (sym->ival && sym->level == 0) + { + if ((SPEC_OCLS (sym->etype) == xidata || SPEC_OCLS (sym->etype) == initialized) && !SPEC_ABSA (sym->etype) && !SPEC_ADDRSPACE (sym->etype)) + { + sym_link *t; + ast *ival = NULL; + symbol *tsym = copySymbol (sym); + + // check for constant + if (IS_AGGREGATE (tsym->type)) + { + ival = initAggregates (tsym, tsym->ival, NULL); + } + else + { + if (getNelements (tsym->type, tsym->ival) > 1) + { + werrorfl (tsym->fileDef, tsym->lineDef, W_EXCESS_INITIALIZERS, "scalar", tsym->name); + } + ival = newNode ('=', newAst_VALUE (symbolVal (tsym)), + decorateType (resolveSymbols (list2expr (tsym->ival)), RESULT_TYPE_NONE)); + } + if (ival) + { + // set ival's lineno to where the symbol was defined + setAstFileLine (ival, filename = tsym->fileDef, lineno = tsym->lineDef); + // check if this is not a constant expression + if (!constExprTree (ival)) + { + werrorfl (ival->filename, ival->lineno, E_CONST_EXPECTED, "found expression"); + // but try to do it anyway + } + } + + /* create a new "XINIT (CODE)" symbol, that will be emitted later + in the static seg */ + newSym = copySymbol (sym); + SPEC_OCLS (newSym->etype) = (SPEC_OCLS (sym->etype) == xidata) ? xinit : initializer; + SNPRINTF (newSym->name, sizeof (newSym->name), "__xinit_%s", sym->name); + SNPRINTF (newSym->rname, sizeof (newSym->rname), "__xinit_%s", sym->rname); + + /* find the first non-array link */ + t = newSym->type; + while (IS_ARRAY (t)) + t = t->next; + if (IS_SPEC (t)) + SPEC_CONST (t) = 1; + else + DCL_PTR_CONST (t) = 1; + SPEC_STAT (newSym->etype) = 1; + + strSym = NULL; + ++noAlloc; + resolveIvalSym (newSym->ival, newSym->type); + --noAlloc; + + // add it to the "XINIT (CODE)" segment + addSet ((SPEC_OCLS (sym->etype) == xidata) ? &xinit->syms : &initializer->syms, newSym); + + if (!SPEC_ABSA (sym->etype)) + { + struct dbuf_s tmpBuf; + symbol *ps = NULL; + set *tmpSym = NULL; + + wassert(dbuf_init (&tmpBuf, 4096)); + // before allocation we must parse the sym->ival tree + // but without actually generating initialization code + ++noAlloc; + resolveIvalSym (sym->ival, sym->type); + ++noInit; + printIval (sym, sym->type, sym->ival, &tmpBuf, TRUE); + --noInit; + --noAlloc; + + // delete redundant __str_%d symbols (initializer for char arrays) + for (ps = setFirstItem (statsg->syms); ps; ps = setNextItem (statsg->syms)) + if (!strstr (tmpBuf.buf, ps->name) && isinSet (strSym, ps)) + addSet (&tmpSym, ps); + for (ps = setFirstItem (tmpSym); ps; ps = setNextItem (tmpSym)) + deleteSetItem (&statsg->syms, ps); + + deleteSet (&tmpSym); + dbuf_destroy (&tmpBuf); + } + + if (strSym) + deleteSet (&strSym); + } + else + { + if (IS_AGGREGATE (sym->type)) + { + ival = initAggregates (sym, sym->ival, NULL); + } + else + { + if (getNelements (sym->type, sym->ival) > 1) + { + werrorfl (sym->fileDef, sym->lineDef, W_EXCESS_INITIALIZERS, "scalar", sym->name); + } + ival = newNode ('=', newAst_VALUE (symbolVal (sym)), + decorateType (resolveSymbols (list2expr (sym->ival)), RESULT_TYPE_NONE)); + } + codeOutBuf = &statsg->oBuf; + + if (ival) + { + // set ival's lineno to where the symbol was defined + setAstFileLine (ival, filename = sym->fileDef, lineno = sym->lineDef); + // check if this is not a constant expression + if (!constExprTree (ival)) + { + werrorfl (ival->filename, ival->lineno, E_CONST_EXPECTED, "found expression"); + // but try to do it anyway + } + allocInfo = 0; + if (!astErrors (ival)) + eBBlockFromiCode (iCodeFromAst (ival)); + allocInfo = 1; + } + } + } + + /* if it has an absolute address then generate + an equate for this no need to allocate space */ + if (SPEC_ABSA (sym->etype) && !sym->ival) + { + char *equ = "="; + + /* print extra debug info if required */ + if (options.debug) + { + emitDebugSym (&map->oBuf, sym); + dbuf_printf (&map->oBuf, " == 0x%04x\n", SPEC_ADDR (sym->etype)); + } + dbuf_printf (&map->oBuf, "%s\t%s\t0x%04x\n", sym->rname, equ, SPEC_ADDR (sym->etype)); + } + else + { + int size = getSize (sym->type) + sym->flexArrayLength; + if (size == 0) + { + werrorfl (sym->fileDef, sym->lineDef, E_UNKNOWN_SIZE, sym->name); + } + /* allocate space */ + if (SPEC_ABSA (sym->etype)) + { + dbuf_tprintf (&map->oBuf, "\t!org\n", SPEC_ADDR (sym->etype)); + } + /* print extra debug info if required */ + if (options.debug) + { + emitDebugSym (&map->oBuf, sym); + dbuf_printf (&map->oBuf, "==.\n"); + } + if (IS_STATIC (sym->etype) || sym->level) + dbuf_tprintf (&map->oBuf, "!slabeldef\n", sym->rname); + else + dbuf_tprintf (&map->oBuf, "!labeldef\n", sym->rname); + dbuf_tprintf (&map->oBuf, "\t!ds\n", (unsigned int) size & 0xffff); + } + + sym->ival = NULL; + } +} + +/*-----------------------------------------------------------------*/ +/* initValPointer - pointer initialization code massaging */ +/*-----------------------------------------------------------------*/ +value * +initValPointer (ast *expr) +{ + value *val; + + /* no then we have to do these kludgy checks */ + /* pointers can be initialized with address of + a variable or address of an array element */ + if (IS_ADDRESS_OF_OP (expr)) + { + /* address of symbol */ + if (IS_AST_SYM_VALUE (expr->left)) + { + STORAGE_CLASS sclass = SPEC_SCLS (expr->left->etype); + memmap *oclass = SPEC_OCLS (expr->left->etype); + + val = AST_VALUE (expr->left); + val->type = newLink (DECLARATOR); + if (sclass == S_CODE) + { + DCL_TYPE (val->type) = CPOINTER; + CodePtrPointsToConst (val->type); + } + else if (oclass) + DCL_TYPE (val->type) = oclass->ptrType; + else if (sclass == S_XDATA) + DCL_TYPE (val->type) = FPOINTER; + else if (sclass == S_DATA) + DCL_TYPE (val->type) = POINTER; + else if (sclass == S_IDATA) + DCL_TYPE (val->type) = IPOINTER; + else if (sclass == S_PDATA) + DCL_TYPE (val->type) = PPOINTER; + else if (sclass == S_XSTACK) + DCL_TYPE (val->type) = PPOINTER; + else if (sclass == S_EEPROM) + DCL_TYPE (val->type) = EEPPOINTER; + else + DCL_TYPE (val->type) = POINTER; + val->type->next = expr->left->ftype; + val->etype = getSpec (val->type); + return val; + } + + /* if address of indexed array */ + if (IS_ARRAY_OP (expr->left)) + return valForArray (expr->left); + + /* if address of structure element then + case 1. a.b ; */ + if (IS_AST_OP (expr->left) && expr->left->opval.op == '.') + { + return valForStructElem (expr->left->left, expr->left->right); + } + + /* case 2. (&a)->b ; + (&some_struct)->element */ + if (IS_AST_OP (expr->left) && expr->left->opval.op == PTR_OP && IS_ADDRESS_OF_OP (expr->left->left)) + { + return valForStructElem (expr->left->left->left, expr->left->right); + } + + /* case 2.1. a->b */ + if (IS_AST_OP (expr->left) && expr->left->opval.op == PTR_OP) + { + return valForStructElem (expr->left->left, expr->left->right); + } + } + + /* case 3. (((char *) &a) +/- constant) */ + if (IS_AST_OP (expr) && + (expr->opval.op == '+' || expr->opval.op == '-') && + IS_CAST_OP (expr->left) && IS_ADDRESS_OF_OP (expr->left->right) && IS_AST_LIT_VALUE (expr->right)) + { + return valForCastAggr (expr->left->right->left, expr->left->left->opval.lnk, expr->right, expr->opval.op); + } + + /* case 4. (array type) */ + if (IS_AST_SYM_VALUE (expr) && IS_ARRAY (expr->ftype)) + { + STORAGE_CLASS sclass = SPEC_SCLS (expr->etype); + memmap *oclass = SPEC_OCLS (expr->etype); + + val = copyValue (AST_VALUE (expr)); + val->type = newLink (DECLARATOR); + if (SPEC_SCLS (expr->etype) == S_CODE) + { + DCL_TYPE (val->type) = CPOINTER; + CodePtrPointsToConst (val->type); + } + else if (oclass) + DCL_TYPE (val->type) = oclass->ptrType; + else if (sclass == S_XDATA) + DCL_TYPE (val->type) = FPOINTER; + else if (sclass == S_DATA) + DCL_TYPE (val->type) = POINTER; + else if (sclass == S_IDATA) + DCL_TYPE (val->type) = IPOINTER; + else if (sclass == S_PDATA) + DCL_TYPE (val->type) = PPOINTER; + else if (sclass == S_XSTACK) + DCL_TYPE (val->type) = PPOINTER; + else if (sclass == S_EEPROM) + DCL_TYPE (val->type) = EEPPOINTER; + else + DCL_TYPE (val->type) = POINTER; + val->type->next = expr->ftype->next; + val->etype = getSpec (val->type); + return val; + } + + /* if structure element then + case 5. a.b ; */ + if (IS_AST_OP (expr) && expr->opval.op == '.') + { + return valForStructElem (expr->left, expr->right); + } + + /* case 6. a->b ; + some_struct->element */ + if (IS_AST_OP (expr) && expr->opval.op == PTR_OP) + { + ast *t = expr->left; + + /*if (expr->left->left) + if (expr->left->left->left) + if (expr->left->left->opval.op == '[') + t = expr->left->left; + else + t = expr->left->left->left; + else + t = expr->left->left; + else + t = expr->left;*/ + + /* a more generic way of above code */ + while (t->left != NULL && t->opval.op != '[') + t = t->left; + + return valForStructElem (t, expr->right); + } + + return NULL; +} + +/*-----------------------------------------------------------------*/ +/* initPointer - pointer initialization code massaging */ +/*-----------------------------------------------------------------*/ +value * +initPointer (initList *ilist, sym_link *toType, int showError) +{ + value *val; + ast *expr; + + if (!ilist) + { + return valCastLiteral (toType, 0.0, 0); + } + + expr = list2expr (ilist); + + if (!expr) + { + if (showError) + werror (E_CONST_EXPECTED); + return 0; + } + + /* try it the old way first */ + if ((val = constExprValue (expr, FALSE))) + return val; + + /* ( ptr + constant ) */ + if (IS_AST_OP (expr) && + (expr->opval.op == '+' || expr->opval.op == '-') && + IS_AST_SYM_VALUE (expr->left) && + (IS_ARRAY (expr->left->ftype) || IS_PTR (expr->left->ftype)) && + compareType (toType, expr->left->ftype) && IS_AST_LIT_VALUE (expr->right)) + { + return valForCastAggr (expr->left, expr->left->ftype, expr->right, expr->opval.op); + } + + /* (char *)(expr1) */ + if (IS_CAST_OP (expr)) + { + if (compareType (toType, expr->left->ftype) == 0 && showError) + { + werror (W_INIT_WRONG); + printFromToType (expr->left->ftype, toType); + } + val = initValPointer (expr->right); + if (val) + { + DECLARATOR_TYPE dcl_type = DCL_TYPE (val->type); + val->type = expr->left->ftype; + val->etype = getSpec (val->type); + if (IS_GENPTR (val->type)) + DCL_TYPE (val->type) = dcl_type; + } + } + else + { + val = initValPointer (expr); + } + + if (val) + return val; + + if (showError) + { + if (expr) + werrorfl (expr->filename, expr->lineno, E_CONST_EXPECTED); + else + werror (E_CONST_EXPECTED); + } + return 0; +} + +/*-----------------------------------------------------------------*/ +/* printChar - formats and prints a UTF-8 character string with DB */ +/*-----------------------------------------------------------------*/ +void +printChar (struct dbuf_s *oBuf, const char *s, int plen) +{ + int i; + int pplen = 0; + char buf[100]; + char *p = buf; + + if (TARGET_PDK_LIKE && !TARGET_IS_PDK16) // Assembler does not support .ascii + { + while (pplen < plen) + { + if (isprint((unsigned char) *s)) + dbuf_tprintf (oBuf, "\t!db !constbyte\t; %c\n", (unsigned char) *s, (unsigned char) *s); + else + dbuf_tprintf (oBuf, "\t!db !constbyte\n", (unsigned char) *s); + + s++; + pplen++; + } + return; + } + + while (pplen < plen) + { + i = 60; + while (i && pplen < plen) + { + if (!isprint((unsigned char) *s) || *s == '\"' || *s == '\\') + { + *p = '\0'; + if (p != buf) + dbuf_tprintf (oBuf, "\t!ascii\n", buf); + dbuf_tprintf (oBuf, "\t!db !constbyte\n", (unsigned char) *s); + p = buf; + i = 60; + } + else + { + *p = *s; + p++; + i--; + } + s++; + pplen++; + } + if (p != buf) + { + *p = '\0'; + dbuf_tprintf (oBuf, "\t!ascii\n", buf); + p = buf; + i = 60; + } + } +} + +/*-----------------------------------------------------------------*/ +/* printChar16 - formats and prints a UTF-16 character string with DB*/ +/*-----------------------------------------------------------------*/ +void +printChar16 (struct dbuf_s *oBuf, const TYPE_TARGET_UINT *s, int plen) +{ + int pplen = 0; + + while (pplen < plen) + { + if (TARGET_PDK_LIKE && !TARGET_IS_PDK16) + { + dbuf_tprintf (oBuf, "\t!db !constbyte\n", (*s >> 0) & 0xff); + dbuf_tprintf (oBuf, "\t!db !constbyte\n", (*s >> 8) & 0xff); + } + else if (port->little_endian) + dbuf_printf (oBuf, "\t.byte %d,%d\n", (*s >> 0) & 0xff, (*s >> 8) & 0xff); + else + dbuf_printf (oBuf, "\t.byte %d,%d\n", (*s >> 8) & 0xff, (*s >> 0) & 0xff); + + s++; + pplen++; + } + while (pplen < plen) + { + dbuf_tprintf (oBuf, "\t!db !constbyte\n", 0); + pplen++; + } +} + +/*-----------------------------------------------------------------*/ +/* printChar32 - formats and prints a UTF-32 character string with DB*/ +/*-----------------------------------------------------------------*/ +void +printChar32 (struct dbuf_s *oBuf, const TYPE_TARGET_ULONG *s, int plen) +{ + int pplen = 0; + + while (pplen < plen) + { + if (TARGET_PDK_LIKE && !TARGET_IS_PDK16) + { + dbuf_tprintf (oBuf, "\t!db !constbyte\n", (*s >> 0) & 0xff); + dbuf_tprintf (oBuf, "\t!db !constbyte\n", (*s >> 8) & 0xff); + dbuf_tprintf (oBuf, "\t!db !constbyte\n", (*s >> 16) & 0xff); + dbuf_tprintf (oBuf, "\t!db !constbyte\n", (*s >> 24) & 0xff); + } + else if (port->little_endian) + dbuf_printf (oBuf, "\t.byte %d,%d,%d,%d\n", (*s >> 0) & 0xff, (*s >> 8) & 0xff, (*s >> 16) & 0xff, (*s >> 24) & 0xff); + else + dbuf_printf (oBuf, "\t.byte %d,%d,%d,%d\n", (*s >> 24) & 0xff, (*s >> 16) & 0xff, (*s >> 8) & 0xff,(*s >> 0) & 0xff); + + s++; + pplen++; + } + while (pplen < plen) + { + dbuf_tprintf (oBuf, "\t!db !constbyte\n", 0); + pplen++; + } +} + +/*-----------------------------------------------------------------*/ +/* return the generic pointer high byte for a given pointer type. */ +/*-----------------------------------------------------------------*/ +int +pointerTypeToGPByte (const int p_type, const char *iname, const char *oname) +{ + switch (p_type) + { + case IPOINTER: + case POINTER: + return GPTYPE_NEAR; + case GPOINTER: + werror (W_USING_GENERIC_POINTER, iname ? iname : "<null>", oname ? oname : "<null>"); + return -1; + case FPOINTER: + return GPTYPE_FAR; + case CPOINTER: + case FUNCTION: + return GPTYPE_CODE; + case PPOINTER: + return GPTYPE_XSTACK; + default: + fprintf (stderr, "*** internal error: unknown pointer type %d in GPByte.\n", p_type); + exit (EXIT_FAILURE); + } + return -1; +} + +/*-----------------------------------------------------------------*/ +/* printIvalVal - generate ival according from value */ +/*-----------------------------------------------------------------*/ +static void printIvalVal(struct dbuf_s *oBuf, value *val, int size, bool newline) +{ + if (size == 2 && port->use_dw_for_init) + { + dbuf_tprintf (oBuf, "\t!dws\n", aopLiteralLong (val, 0, 2)); + return; + } + + const bool use_ret = TARGET_PDK_LIKE && !TARGET_IS_PDK16; + + if (!use_ret) + dbuf_printf (oBuf, "\t.byte "); + + for (int i = 0; i < size; i++) + { + const char *inst; + const char *byte = aopLiteral (val, port->little_endian ? i : size - 1 - i); + if (use_ret) + inst = i != size - 1 ? "\tret %s\n" : "\tret %s"; + else + inst = i != size - 1 ? "%s, " : "%s"; + dbuf_printf (oBuf, inst, byte); + } + if (newline) + dbuf_printf (oBuf, "\n"); +} + +/*-----------------------------------------------------------------*/ +/* _printPointerType - generates ival for pointer type */ +/*-----------------------------------------------------------------*/ +static void +_printPointerType (struct dbuf_s *oBuf, const char *name, int size) +{ + wassert (!TARGET_PDK_LIKE); + + if (size == 4) + { + if (port->little_endian) + dbuf_printf (oBuf, "\t.byte %s, (%s >> 8), (%s >> 16), (%s >> 24)", name, name, name, name); + else + dbuf_printf (oBuf, "\t.byte (%s >> 24), (%s >> 16), (%s >> 8), %s", name, name, name, name); + } + else if (size == 3) + { + if (port->little_endian) + dbuf_printf (oBuf, "\t.byte %s, (%s >> 8), (%s >> 16)", name, name, name); + else + dbuf_printf (oBuf, "\t.byte (%s >> 16), (%s >> 8), %s", name, name, name); + } + else + { + if (port->little_endian) + dbuf_printf (oBuf, "\t.byte %s, (%s >> 8)", name, name); + else + dbuf_printf (oBuf, "\t.byte (%s >> 8), %s", name, name); + } +} + +/*-----------------------------------------------------------------*/ +/* printPointerType - generates ival for pointer type */ +/*-----------------------------------------------------------------*/ +static void +printPointerType (struct dbuf_s *oBuf, const char *name) +{ + _printPointerType (oBuf, name, (options.model == MODEL_FLAT24) ? 3 : 2); + dbuf_printf (oBuf, "\n"); +} + +/*-----------------------------------------------------------------*/ +/* printGPointerType - generates ival for generic pointer type */ +/*-----------------------------------------------------------------*/ +static void +printGPointerType (struct dbuf_s *oBuf, const char *iname, const char *oname, int type) +{ + int byte = pointerTypeToGPByte (type, iname, oname); + int size = (options.model == MODEL_FLAT24) ? 3 : 2; + if (byte == -1) + { + _printPointerType (oBuf, iname, size + 1); + dbuf_printf (oBuf, "\n"); + } + else + { + _printPointerType (oBuf, iname, size); + dbuf_printf (oBuf, ",#0x%02x\n", byte); + } +} + +/*-----------------------------------------------------------------*/ +/* printIvalType - generates ival for int/char */ +/*-----------------------------------------------------------------*/ +void +printIvalType (symbol * sym, sym_link * type, initList * ilist, struct dbuf_s *oBuf) +{ + value *val; + unsigned long ulVal = 0; + + /* if initList is deep */ + if (ilist && (ilist->type == INIT_DEEP)) + ilist = ilist->init.deep; + + if (!(val = list2val (ilist, FALSE))) + { + if (!!(val = initPointer (ilist, type, 0))) + { + int i, size = getSize (type), le = port->little_endian, top = (options.model == MODEL_FLAT24) ? 3 : 2;; + dbuf_printf (oBuf, "\t.byte "); + for (i = (le ? 0 : size - 1); le ? (i < size) : (i > -1); i += (le ? 1 : -1)) + { + if (i == 0) + if (val->name && strlen (val->name) > 0) + dbuf_printf (oBuf, "%s", val->name); + else + dbuf_printf (oBuf, "#0x00"); + else if (0 < i && i < top) + if (val->name && strlen (val->name) > 0) + dbuf_printf (oBuf, "(%s >> %d)", val->name, i * 8); + else + dbuf_printf (oBuf, "#0x00"); + else + dbuf_printf (oBuf, "#0x00"); + if (i == (le ? (size - 1) : 0)) + dbuf_printf (oBuf, "\n"); + else + dbuf_printf (oBuf, ", "); + } + return; + } + else + { + werrorfl (ilist->filename, ilist->lineno, E_CONST_EXPECTED); + val = constCharVal (0); + } + } + + if (val->etype && SPEC_SCLS (val->etype) != S_LITERAL) + { + werrorfl (ilist->filename, ilist->lineno, E_CONST_EXPECTED); + val = constCharVal (0); + } + + /* check if the literal value is within bounds */ + if (checkConstantRange (type, val->etype, '=', FALSE) == CCR_OVL) + { + werror (W_LIT_OVERFLOW); + } + + if (val->type != type) + { + val = valCastLiteral (type, floatFromVal (val), (TYPE_TARGET_ULONGLONG) ullFromVal (val)); + } + + if (IS_INTEGRAL (val->type)) + ulVal = ulFromVal (val); + + switch (getSize (type)) + { + case 1: + if (!val) + dbuf_tprintf (oBuf, "\t!db !constbyte\n", 0); + else + { + if (IS_UNSIGNED (val->type)) + { + dbuf_tprintf (oBuf, "\t!dbs\t; %u", aopLiteral (val, 0), (unsigned int) ulVal); + } + else + { + dbuf_tprintf (oBuf, "\t!dbs\t; % d", aopLiteral (val, 0), (int) ulVal); + } + if (isalnum ((int) ulVal)) + dbuf_tprintf (oBuf, "\t'%c'\n", (int) ulVal); + else + dbuf_tprintf (oBuf, "\n"); + } + break; + + case 2: + if (port->use_dw_for_init) + { + printIvalVal (oBuf, val, 2, true); + break; + } + printIvalVal (oBuf, val, 2, false); + if (IS_UNSIGNED (val->type)) + dbuf_printf (oBuf, "\t; %u\n", (unsigned int) ulVal); + else + dbuf_printf (oBuf, "\t; % d\n", (int) ulVal); + break; + + case 4: + if (!val) + { + dbuf_tprintf (oBuf, "\t!dw !constword\n", 0); + dbuf_tprintf (oBuf, "\t!dw !constword\n", 0); + } + else + { + printIvalVal (oBuf, val, 4, false); + + if (IS_FLOAT (val->type)) + { + dbuf_printf (oBuf, "\t; % e\n", floatFromVal (val)); + } + else + { + if (IS_UNSIGNED (val->type)) + dbuf_printf (oBuf, "\t; %u\n", (unsigned int) ulVal); + else + dbuf_printf (oBuf, "\t; % d\n", (int) ulVal); + } + } + break; + case 8: + printIvalVal (oBuf, val, 8, true); // TODO: Print value as comment. Does dbuf_printf support long long even on MSVC? + break; + default: + wassertl (0, "Attempting to initialize integer of non-handled size."); + } +} + +/*-----------------------------------------------------------------*/ +/* printIvalBitFields - generate initializer for bitfields */ +/* return the number of bytes written */ +/*-----------------------------------------------------------------*/ +static unsigned int +printIvalBitFields (symbol ** sym, initList ** ilist, struct dbuf_s *oBuf) +{ + symbol *lsym = *sym; + initList *lilist = *ilist; + unsigned long ival = 0; + unsigned size = 0; + unsigned bit_start = 0; + unsigned long int bytes_written = 0; + + while (lsym && IS_BITFIELD (lsym->type)) + { + unsigned bit_length = SPEC_BLEN (lsym->etype); + if (0 == bit_length) + { + /* bit-field structure member with a width of 0 */ + lsym = lsym->next; + break; + } + else if (!SPEC_BUNNAMED (lsym->etype)) + { + /* not an unnamed bit-field structure member */ + value *val = list2val (lilist, TRUE); + + if (val && val->etype && SPEC_SCLS (val->etype) != S_LITERAL) + { + werrorfl (lilist->filename, lilist->lineno, E_CONST_EXPECTED); + val = constCharVal (0); + } + if (size) + { + if (bit_length > 8) + size += (bit_length + 7) / 8; + } + else + size = (bit_length + 7) / 8; + + /* check if the literal value is within bounds */ + if (val && checkConstantRange (lsym->etype, val->etype, '=', FALSE) == CCR_OVL) + { + werror (W_LIT_OVERFLOW); + } + + ival |= (ulFromVal (val) & ((1ul << bit_length) - 1ul)) << bit_start; + lilist = lilist ? lilist->next : NULL; + } + bit_start += bit_length; + lsym = lsym->next; + if (lsym && IS_BITFIELD (lsym->type) && (0 == SPEC_BSTR (lsym->etype))) + { + /* a new integer */ + break; + } + } + + switch (size) + { + case 0: + dbuf_tprintf (oBuf, "\n"); + break; + + case 1: + dbuf_tprintf (oBuf, "\t!db !constbyte\n", ival); + bytes_written++; + break; + + case 2: + if (TARGET_PDK_LIKE && !TARGET_IS_PDK16) + { + dbuf_tprintf (oBuf, "\t!db !constbyte\n", (ival & 0xff)); + dbuf_tprintf (oBuf, "\t!db !constbyte\n", ((ival >> 8) & 0xff)); + } + else + dbuf_tprintf (oBuf, "\t!db !constbyte, !constbyte\n", (ival & 0xff), (ival >> 8) & 0xff); + bytes_written += 2; + break; + + case 4: + dbuf_tprintf (oBuf, "\t!db !constbyte, !constbyte, !constbyte, !constbyte\n", + (ival & 0xff), (ival >> 8) & 0xff, (ival >> 16) & 0xff, (ival >> 24) & 0xff); + bytes_written += 4; + break; + default: + wassert (0); + } + *sym = lsym; + *ilist = lilist; + + return (bytes_written); +} + +/*-----------------------------------------------------------------*/ +/* printIvalStruct - generates initial value for structures */ +/*-----------------------------------------------------------------*/ +static void +printIvalStruct (symbol *sym, sym_link *type, initList *ilist, struct dbuf_s *oBuf) +{ + symbol *sflds; + initList *iloop = NULL; + unsigned int skip_holes = 0; + + sflds = SPEC_STRUCT (type)->fields; + + if (ilist) + { + if (ilist->type != INIT_DEEP) + { + werrorfl (sym->fileDef, sym->lineDef, E_INIT_STRUCT, sym->name); + return; + } + + iloop = ilist->init.deep; + } + + if (SPEC_STRUCT (type)->type == UNION) + { + int size; + /* skip past holes, print value */ + while (iloop && iloop->type == INIT_HOLE) + { + iloop = iloop->next; + sflds = sflds->next; + } + printIval (sym, sflds->type, iloop, oBuf, 1); + /* pad out with zeros if necessary */ + size = getSize(type) - getSize(sflds->type); + for ( ; size > 0 ; size-- ) + { + dbuf_tprintf (oBuf, "\t!db !constbyte\n", 0); + } + /* advance past holes to find out if there were excess initializers */ + do + { + iloop = iloop ? iloop->next : NULL; + sflds = sflds->next; + } + while (iloop && iloop->type == INIT_HOLE); + } + else + { + while (sflds) + { + unsigned int oldoffset = sflds->offset; + + if (IS_BITFIELD (sflds->type)) + printIvalBitFields (&sflds, &iloop, oBuf); + else + { + printIval (sym, sflds->type, iloop, oBuf, 1); + sflds = sflds->next; + iloop = iloop ? iloop->next : NULL; + } + + // Handle members from anonymous unions. Just a hack to fix bug #2643. + while (sflds && sflds->offset == oldoffset) + { + sflds = sflds->next; + skip_holes++; + } + } + + while (skip_holes && iloop && iloop->type == INIT_HOLE) + { + skip_holes--; + iloop = iloop ? iloop->next : NULL; + } + } + + if (iloop) + werrorfl (sym->fileDef, sym->lineDef, W_EXCESS_INITIALIZERS, "struct", sym->name); +} + +/*-----------------------------------------------------------------*/ +/* printIvalChar - generates initital value for character array */ +/*-----------------------------------------------------------------*/ +int +printIvalChar (symbol * sym, sym_link * type, initList * ilist, struct dbuf_s *oBuf, const char *s, bool check) +{ + value *val; + size_t size = DCL_ELEM(type); + char *p; + size_t asz; + + if (!s) + { + val = list2val (ilist, TRUE); + /* if the value is a character string */ + if (IS_ARRAY (val->type) && IS_CHAR (val->etype)) + { + if (!size) + { + /* we have not been given a size, but now we know it */ + size = strlen (SPEC_CVAL (val->etype).v_char) + 1; + /* but first check, if it's a flexible array */ + if (sym && IS_STRUCT (sym->type)) + sym->flexArrayLength = size; + else + DCL_ELEM (type) = size; + } + + if (check && DCL_ELEM (val->type) > size) + werror (W_EXCESS_INITIALIZERS, "array of chars", sym->name, sym->lineDef); + + if (size > (asz = DCL_ELEM (val->type)) && !!(p = malloc (size))) + { + memcpy (p, SPEC_CVAL (val->etype).v_char, asz); + memset (p + asz, 0x00, size - asz); + printChar (oBuf, p, size); + free (p); + } + else + printChar (oBuf, SPEC_CVAL (val->etype).v_char, size); + + return 1; + } + else + return 0; + } + else + printChar (oBuf, s, strlen (s) + 1); + return 1; +} + +static size_t strLen16(const TYPE_TARGET_UINT *s) +{ + size_t l = 0; + while(*s++) + l++; + + return l; +} + +/*-----------------------------------------------------------------*/ +/* printIvalChar16 - generates initital value for character array */ +/*-----------------------------------------------------------------*/ +int +printIvalChar16 (symbol * sym, sym_link * type, initList * ilist, struct dbuf_s *oBuf, const TYPE_TARGET_UINT *s, bool check) +{ + value *val; + size_t size = DCL_ELEM(type); + TYPE_TARGET_UINT *p; + size_t asz; + + if (!s) + { + val = list2val (ilist, TRUE); + /* if the value is a character string */ + if (IS_ARRAY (val->type) && IS_INT (val->etype) && IS_UNSIGNED (val->etype) && !IS_LONG (val->etype)) + { + if (!size) + { + /* we have not been given a size, but now we know it */ + size = strLen16 (SPEC_CVAL (val->etype).v_char16) + 1; + /* but first check, if it's a flexible array */ + if (sym && IS_STRUCT (sym->type)) + sym->flexArrayLength = size; + else + DCL_ELEM (type) = size; + } + + if (check && DCL_ELEM (val->type) > size) + werror (W_EXCESS_INITIALIZERS, "array of chars", sym->name, sym->lineDef); + + if (size > (asz = DCL_ELEM (val->type)) && !!(p = malloc (size * 2))) + { + memcpy (p, SPEC_CVAL (val->etype).v_char16, asz * 2); + memset (p + asz, 0x00, size * 2 - asz * 2); + printChar16 (oBuf, p, size); + free (p); + } + else + printChar16 (oBuf, SPEC_CVAL (val->etype).v_char16, size); + + return 1; + } + else + return 0; + } + else + printChar16 (oBuf, s, strLen16 (s) + 1); + return 1; +} + +static size_t strLen32(const TYPE_TARGET_ULONG *s) +{ + size_t l = 0; + while(*s++) + l++; + return l; +} + +/*-----------------------------------------------------------------*/ +/* printIvalChar32 - generates initital value for character array */ +/*-----------------------------------------------------------------*/ +int +printIvalChar32 (symbol * sym, sym_link * type, initList * ilist, struct dbuf_s *oBuf, const TYPE_TARGET_ULONG *s, bool check) +{ + value *val; + size_t size = DCL_ELEM(type); + TYPE_TARGET_ULONG *p; + size_t asz; + + if (!s) + { + val = list2val (ilist, TRUE); + /* if the value is a character string */ + if (IS_ARRAY (val->type) && IS_INT (val->etype) && IS_UNSIGNED (val->etype) && IS_LONG (val->etype)) + { + if (!size) + { + /* we have not been given a size, but now we know it */ + size = strLen32 (SPEC_CVAL (val->etype).v_char32) + 1; + /* but first check, if it's a flexible array */ + if (sym && IS_STRUCT (sym->type)) + sym->flexArrayLength = size; + else + DCL_ELEM (type) = size; + } + + if (check && DCL_ELEM (val->type) > size) + werror (W_EXCESS_INITIALIZERS, "array of chars", sym->name, sym->lineDef); + + if (size > (asz = DCL_ELEM (val->type)) && !!(p = malloc (size * 4))) + { + memcpy (p, SPEC_CVAL (val->etype).v_char32, asz * 4); + memset (p + asz, 0x00, size * 4 - asz * 4); + printChar32 (oBuf, p, size); + free (p); + } + else + printChar32 (oBuf, SPEC_CVAL (val->etype).v_char32, size); + + return 1; + } + else + return 0; + } + else + printChar32 (oBuf, s, strLen32 (s) + 1); + return 1; +} + +/*-----------------------------------------------------------------*/ +/* printIvalArray - generates code for array initialization */ +/*-----------------------------------------------------------------*/ +void +printIvalArray (symbol * sym, sym_link * type, initList * ilist, struct dbuf_s *oBuf, bool check) +{ + value *val; + initList *iloop; + unsigned int size = 0; + + if (ilist) + { + /* take care of the special case */ + /* array of characters can be init */ + /* by a string */ + /* char *p = "abc"; */ + if ((IS_CHAR (type->next) || IS_INT (type->next)) && ilist->type == INIT_NODE) + { + val = list2val (ilist, TRUE); + if (!val) + { + werrorfl (ilist->filename, ilist->lineno, E_INIT_STRUCT, sym->name); + return; + } + if (!IS_LITERAL (val->etype)) + { + werrorfl (ilist->filename, ilist->lineno, E_CONST_EXPECTED); + return; + } + if (IS_CHAR (type->next) && printIvalChar (sym, type, ilist, oBuf, SPEC_CVAL (sym->etype).v_char, check)) + return; + if (IS_INT (type->next) && IS_UNSIGNED (type->next)) + { + if (!IS_LONG (type->next) && printIvalChar16 (sym, type, ilist, oBuf, SPEC_CVAL (sym->etype).v_char16, check)) + return; + if (IS_LONG (type->next) && printIvalChar32 (sym, type, ilist, oBuf, SPEC_CVAL (sym->etype).v_char32, check)) + return; + } + } + /* char *p = {"abc"}; */ + if ((IS_CHAR (type->next) || IS_INT (type->next)) && ilist->type == INIT_DEEP && ilist->init.deep && ilist->init.deep->type == INIT_NODE) + { + val = list2val (ilist->init.deep, TRUE); + if (!val) + { + werrorfl (ilist->init.deep->filename, ilist->init.deep->lineno, E_INIT_STRUCT, sym->name); + return; + } + if (!IS_LITERAL (val->etype)) + { + werrorfl (ilist->init.deep->filename, ilist->init.deep->lineno, E_CONST_EXPECTED); + return; + } + if (IS_CHAR (type->next) && printIvalChar (sym, type, ilist->init.deep, oBuf, SPEC_CVAL (sym->etype).v_char, check)) + return; + if (IS_INT (type->next) && IS_UNSIGNED (type->next)) + { + if (!IS_LONG (type->next) && printIvalChar16 (sym, type, ilist->init.deep, oBuf, SPEC_CVAL (sym->etype).v_char16, check)) + return; + if (IS_LONG (type->next) && printIvalChar32 (sym, type, ilist->init.deep, oBuf, SPEC_CVAL (sym->etype).v_char32, check)) + return; + } + } + + /* not the special case */ + if (ilist->type != INIT_DEEP) + { + werrorfl (ilist->filename, ilist->lineno, E_INIT_STRUCT, sym->name); + return; + } + + for (iloop = ilist->init.deep; iloop; iloop = iloop->next) + { + if ((++size > DCL_ELEM (type)) && DCL_ELEM (type)) + { + werrorfl (sym->fileDef, sym->lineDef, W_EXCESS_INITIALIZERS, "array", sym->name); + break; + } + printIval (sym, type->next, iloop, oBuf, TRUE); + } + } + + if (DCL_ELEM (type)) + { + // pad with zeros if needed + if (size < DCL_ELEM (type)) + { + size = (DCL_ELEM (type) - size) * getSize (type->next); + while (size--) + { + dbuf_tprintf (oBuf, "\t!db !constbyte\n", 0); + } + } + } + else + { + /* we have not been given a size, but now we know it */ + /* but first check, if it's a flexible array */ + if (IS_STRUCT (sym->type)) + sym->flexArrayLength = size * getSize (type->next); + else + DCL_ELEM (type) = size; + } + + return; +} + +/*-----------------------------------------------------------------*/ +/* printIvalFuncPtr - generate initial value for function pointers */ +/*-----------------------------------------------------------------*/ +void +printIvalFuncPtr (sym_link * type, initList * ilist, struct dbuf_s *oBuf) +{ + value *val; + char *name; + int size; + + if (ilist) + val = list2val (ilist, TRUE); + else + val = valCastLiteral (type, 0.0, 0); + + if (!val) + { + // an error has been thrown already + val = constCharVal (0); + } + + if (IS_LITERAL (val->etype)) + { + if (compareType (type, val->type) == 0) + { + if (ilist) + werrorfl (ilist->filename, ilist->lineno, E_INCOMPAT_TYPES); + else + werror (E_INCOMPAT_TYPES); + printFromToType (val->type, type); + } + printIvalCharPtr (NULL, type, val, oBuf); + return; + } + + /* now generate the name */ + if (!val->sym) + name = val->name; + else + name = val->sym->rname; + + size = getSize (type); + + if (size == FUNCPTRSIZE) + { + if (TARGET_PDK_LIKE) + { + dbuf_printf (oBuf, "\tret #<%s\n", name); + dbuf_printf (oBuf, "\tret #>%s\n", name); + } + else if (TARGET_IS_STM8 && FUNCPTRSIZE == 3) + { + _printPointerType (oBuf, name, size); + dbuf_printf (oBuf, "\n"); + } + else if (port->use_dw_for_init) + { + dbuf_tprintf (oBuf, "\t!dws\n", name); + } + else + { + printPointerType (oBuf, name); + } + } + else if (size == BFUNCPTRSIZE) + { + _printPointerType (oBuf, name, size); + dbuf_printf (oBuf, "\n"); + } + else + { + wassertl (0, "Invalid function pointer size."); + } + + return; +} + +/*--------------------------------------------------------------------*/ +/* printIvalCharPtr - generates initial values for character pointers */ +/*--------------------------------------------------------------------*/ +int +printIvalCharPtr (symbol * sym, sym_link * type, value * val, struct dbuf_s *oBuf) +{ + int size = 0; + char *p; + + if (val && !!(p = (char *) malloc (strlen (val->name) + 1))) + { + strcpy (p, val->name); + addSet (&ccpStr, p); + } + + /* PENDING: this is _very_ mcs51 specific, including a magic + number... + It's also endian specific. + */ + size = getSize (type); + + if (val->name && strlen (val->name)) + { + if (size == 1) /* This appears to be Z80 specific?? */ + { + dbuf_tprintf (oBuf, "\t!dbs\n", val->name); + } + else if (size == FARPTRSIZE) + { + if (TARGET_PDK_LIKE && !TARGET_IS_PDK16) + { + dbuf_printf (oBuf, "\tret #<%s\n", val->name); + dbuf_printf (oBuf, IN_CODESPACE (SPEC_OCLS (val->etype)) ? "\tret #>(%s + 0x8000)\n" : "\tret #0\n", val->name); + } + else if (port->use_dw_for_init) + dbuf_tprintf (oBuf, "\t!dws\n", val->name); + else + printPointerType (oBuf, val->name); + } + else if (size == GPTRSIZE) + { + int type; + if (IS_PTR (val->type)) + { + type = DCL_TYPE (val->type); + } + else + { + type = PTR_TYPE (SPEC_OCLS (val->etype)); + } + if (val->sym && val->sym->isstrlit) + { + // this is a literal string + type = CPOINTER; + } + printGPointerType (oBuf, val->name, sym->name, type); + } + else + { + fprintf (stderr, "*** internal error: unknown size in " "printIvalCharPtr.\n"); + } + } + else + { + // these are literals assigned to pointers + switch (size) + { + case 1: + dbuf_tprintf (oBuf, "\t!dbs\n", aopLiteral (val, 0)); + break; + case 2: + if (TARGET_PDK_LIKE && !TARGET_IS_PDK16) + { + dbuf_tprintf (oBuf, "\tret %s\n", aopLiteral (val, 0)); + dbuf_tprintf (oBuf, "\tret %s\n", aopLiteral (val, 1)); + } + else if (port->use_dw_for_init) + dbuf_tprintf (oBuf, "\t!dws\n", aopLiteralLong (val, 0, size)); + else if (port->little_endian) + dbuf_tprintf (oBuf, "\t.byte %s,%s\n", aopLiteral (val, 0), aopLiteral (val, 1)); + else + dbuf_tprintf (oBuf, "\t.byte %s,%s\n", aopLiteral (val, 1), aopLiteral (val, 0)); + break; + case 3: + if (IS_GENPTR (type) && GPTRSIZE > FARPTRSIZE && floatFromVal (val) != 0) + { + if (!IS_PTR (val->type) && !IS_FUNC (val->type)) + { + // non-zero mcs51 generic pointer + werrorfl (sym->fileDef, sym->lineDef, W_LITERAL_GENERIC); + } + if (port->little_endian) + dbuf_printf (oBuf, "\t.byte %s,%s,%s\n", aopLiteral (val, 0), aopLiteral (val, 1), aopLiteralGptr (sym->name, val)); + else + dbuf_printf (oBuf, "\t.byte %s,%s,%s\n", aopLiteralGptr (sym->name, val), aopLiteral (val, 1), aopLiteral (val, 0)); + } + else + { + if (port->little_endian) + dbuf_printf (oBuf, "\t.byte %s,%s,%s\n", aopLiteral (val, 0), aopLiteral (val, 1), aopLiteral (val, 2)); + else + dbuf_printf (oBuf, "\t.byte %s,%s,%s\n", aopLiteral (val, 2), aopLiteral (val, 1), aopLiteral (val, 0)); + } + break; + case 4: + if (IS_GENPTR (type) && GPTRSIZE > FARPTRSIZE && floatFromVal (val) != 0) + { + if (!IS_PTR (val->type) && !IS_FUNC (val->type)) + { + // non-zero ds390 generic pointer + werrorfl (sym->fileDef, sym->lineDef, W_LITERAL_GENERIC); + } + if (port->little_endian) + { + dbuf_printf (oBuf, "\t.byte %s,%s,%s", aopLiteral (val, 0), aopLiteral (val, 1), aopLiteral (val, 2)); + if (IS_PTR (val->type) && !IS_GENPTR (val->type)) + dbuf_tprintf (oBuf, ",!immedbyte\n", pointerTypeToGPByte (DCL_TYPE (val->type), val->name, sym->name)); + else + dbuf_printf (oBuf, ",%s\n", aopLiteral (val, 3)); + } + else + { + if (IS_PTR (val->type) && !IS_GENPTR (val->type)) + dbuf_tprintf (oBuf, "\t.byte !immedbyte\n", pointerTypeToGPByte (DCL_TYPE (val->type), val->name, sym->name)); + else + dbuf_printf (oBuf, "\t.byte %s\n", aopLiteral (val, 3)); + dbuf_printf (oBuf, ",%s,%s,%s", aopLiteral (val, 2), aopLiteral (val, 1), aopLiteral (val, 0)); + } + } + else + { + if (port->little_endian) + { + dbuf_printf (oBuf, "\t.byte %s,%s,%s,%s\n", + aopLiteral (val, 0), aopLiteral (val, 1), aopLiteral (val, 2), aopLiteral (val, 3)); + } + else + { + dbuf_printf (oBuf, "\t.byte %s,%s,%s,%s\n", + aopLiteral (val, 3), aopLiteral (val, 2), aopLiteral (val, 1), aopLiteral (val, 0)); + } + } + break; + default: + assert (0); + } + } + + if (!noInit && val->sym && val->sym->isstrlit && !isinSet (statsg->syms, val->sym)) + { + addSet (&statsg->syms, val->sym); + } + + return 1; +} + +/*-----------------------------------------------------------------*/ +/* printIvalPtr - generates initial value for pointers */ +/*-----------------------------------------------------------------*/ +void +printIvalPtr (symbol *sym, sym_link *type, initList *ilist, struct dbuf_s *oBuf) +{ + value *val; + int size; + + /* if deep then */ + if (ilist && (ilist->type == INIT_DEEP)) + ilist = ilist->init.deep; + + /* function pointer */ + if (IS_FUNC (type->next)) + { + printIvalFuncPtr (type, ilist, oBuf); + return; + } + + if (!(val = initPointer (ilist, type, 1))) + return; + + /* if character pointer */ + if (IS_CHAR (type->next) || IS_INT (type->next) && IS_UNSIGNED (type->next)) + if (printIvalCharPtr (sym, type, val, oBuf)) + return; + + /* check the type */ + if (compareType (type, val->type) == 0) + { + assert (ilist != NULL); + werrorfl (ilist->filename, ilist->lineno, W_INIT_WRONG); + printFromToType (val->type, type); + } + + /* if val is literal */ + if (IS_LITERAL (val->etype)) + { + switch (getSize (type)) + { + case 1: + dbuf_tprintf (oBuf, "\t!db !constbyte\n", (unsigned int) ulFromVal (val) & 0xff); + break; + case 2: + if (port->use_dw_for_init) + dbuf_tprintf (oBuf, "\t!dws\n", aopLiteralLong (val, 0, 2)); + else if (port->little_endian) + dbuf_tprintf (oBuf, "\t.byte %s,%s\n", aopLiteral (val, 0), aopLiteral (val, 1)); + else + dbuf_tprintf (oBuf, "\t.byte %s,%s\n", aopLiteral (val, 1), aopLiteral (val, 0)); + break; + case 3: + dbuf_printf (oBuf, "; generic printIvalPtr\n"); + if (port->little_endian) + dbuf_printf (oBuf, "\t.byte %s,%s", aopLiteral (val, 0), aopLiteral (val, 1)); + else + dbuf_printf (oBuf, "\t.byte %s,%s", aopLiteral (val, 1), aopLiteral (val, 0)); + if (IS_GENPTR (val->type)) + dbuf_printf (oBuf, ",%s\n", aopLiteral (val, 2)); + else if (IS_PTR (val->type)) + dbuf_tprintf (oBuf, ",!immedbyte\n", pointerTypeToGPByte (DCL_TYPE (val->type), val->name, sym->name)); + else + dbuf_printf (oBuf, ",%s\n", aopLiteral (val, 2)); + break; + case 4: + if (TARGET_IS_DS390 || TARGET_IS_DS400) + dbuf_printf (oBuf, "\t.byte %s,%s,%s,%s\n", aopLiteral (val, 0), aopLiteral (val, 1), aopLiteral (val, 2), aopLiteral (val, 3)); + else + wassertl(0, "Printing pointer of invalid size"); + break; + default: + wassertl(0, "Printing pointer of invalid size"); + break; + } + return; + } + + size = getSize (type); + + if (TARGET_PDK_LIKE && size == 2) + { + if (IN_CODESPACE (SPEC_OCLS (val->etype))) + { + dbuf_printf (oBuf, "\tret #<%s\n", val->name); + dbuf_printf (oBuf, "\tret #>(%s + 0x8000)\n", val->name); + } + else + { + dbuf_printf (oBuf, "\tret #%s\n", val->name); + dbuf_printf (oBuf, "\tret #0\n"); + } + } + else if (size == 1) /* Z80 specific?? */ + { + dbuf_tprintf (oBuf, "\t!dbs\n", val->name); + } + else if (size == FARPTRSIZE) + { + if (port->use_dw_for_init) + dbuf_tprintf (oBuf, "\t!dws\n", val->name); + else + printPointerType (oBuf, val->name); + } + else if (size == GPTRSIZE) + { + printGPointerType (oBuf, val->name, sym->name, + (IS_PTR (val->type) ? DCL_TYPE (val->type) : PTR_TYPE (SPEC_OCLS (val->etype)))); + } + + return; +} + +/*-----------------------------------------------------------------*/ +/* printIval - generates code for initial value */ +/*-----------------------------------------------------------------*/ +void +printIval (symbol * sym, sym_link * type, initList * ilist, struct dbuf_s *oBuf, bool check) +{ + sym_link *itype; + + /* Handle designated initializers */ + if (ilist && ilist->type==INIT_DEEP) + ilist = reorderIlist (type, ilist); + + /* If this is a hole, substitute an appropriate initializer. */ + if (ilist && ilist->type == INIT_HOLE) + { + if (IS_AGGREGATE (type)) + { + ilist = newiList(INIT_DEEP, NULL); /* init w/ {} */ + } + else + { + ast *ast = newAst_VALUE (constVal("0")); + ast = decorateType (ast, RESULT_TYPE_NONE); + ilist = newiList(INIT_NODE, ast); + } + } + + /* if structure then */ + if (IS_STRUCT (type)) + { + printIvalStruct (sym, type, ilist, oBuf); + return; + } + + /* if this is an array */ + if (IS_ARRAY (type)) + { + printIvalArray (sym, type, ilist, oBuf, check); + return; + } + + if (ilist) + { + // not an aggregate, ilist must be a node + if (ilist->type != INIT_NODE) + { + // or a 1-element list + if (ilist->init.deep->next) + { + werrorfl (sym->fileDef, sym->lineDef, W_EXCESS_INITIALIZERS, "scalar", sym->name); + } + else + { + ilist = ilist->init.deep; + } + } + + // and the type must match + itype = ilist->init.node->ftype; + + if (compareType (type, itype) == 0) + { + // special case for literal strings + if (IS_ARRAY (itype) && IS_CHAR (getSpec (itype)) && + // which are really code pointers + IS_CODEPTR (type)) + { + // no sweat + } + else if (IS_CODEPTR (type) && IS_FUNC (type->next)) /* function pointer */ + { + if (ilist) + werrorfl (ilist->filename, ilist->lineno, E_INCOMPAT_TYPES); + else + werror (E_INCOMPAT_TYPES); + printFromToType (itype, type->next); + } + else + { + werrorfl (ilist->filename, ilist->lineno, E_TYPE_MISMATCH, "assignment", " "); + printFromToType (itype, type); + } + } + } + + /* if this is a pointer */ + if (IS_PTR (type)) + { + printIvalPtr (sym, type, ilist, oBuf); + return; + } + + /* if type is SPECIFIER */ + if (IS_SPEC (type)) + { + printIvalType (sym, type, ilist, oBuf); + return; + } +} + +/*-----------------------------------------------------------------*/ +/* emitStaticSeg - emitcode for the static segment */ +/*-----------------------------------------------------------------*/ +void +emitStaticSeg (memmap *map, struct dbuf_s *oBuf) +{ + symbol *sym; + set *tmpSet = NULL; + + /* fprintf(out, "\t.area\t%s\n", map->sname); */ + + /* eliminate redundant __str_%d (generated in stringToSymbol(), SDCCast.c) */ + for (sym = setFirstItem (map->syms); sym; sym = setNextItem (map->syms)) + addSet (&tmpSet, sym); + + /* for all variables in this segment do */ + for (sym = setFirstItem (map->syms); sym; sym = setNextItem (map->syms)) + { + /* if it is "extern" then do nothing */ + if (IS_EXTERN (sym->etype) && !sym->ival) + continue; + + /* eliminate redundant __str_%d (generated in stringToSymbol(), SDCCast.c) */ + if (!isinSet (tmpSet, sym)) + { + const char *p; + if (!ccpStr) + continue; + for (p = setFirstItem (ccpStr); p; p = setNextItem (ccpStr)) + if (strcmp (p, sym->name) == 0) + break; + if (!p) + continue; + } + + /* if it is not static add it to the public table */ + if (!IS_STATIC (sym->etype)) + { + addSetHead (&publics, sym); + } + + /* if it has an absolute address and no initializer */ + if (SPEC_ABSA (sym->etype) && !sym->ival) + { + if (options.debug) + { + emitDebugSym (oBuf, sym); + dbuf_printf (oBuf, " == 0x%04x\n", SPEC_ADDR (sym->etype)); + } + dbuf_printf (oBuf, "%s\t=\t0x%04x\n", sym->rname, SPEC_ADDR (sym->etype)); + } + else + { + int size = getSize (sym->type); + + if (size == 0) + { + werrorfl (sym->fileDef, sym->lineDef, E_UNKNOWN_SIZE, sym->name); + } + /* if it has an initial value */ + if (sym->ival) + { + if (SPEC_ABSA (sym->etype)) + { + dbuf_tprintf (oBuf, "\t!org\n", SPEC_ADDR (sym->etype)); + } + if (options.debug) + { + emitDebugSym (oBuf, sym); + dbuf_printf (oBuf, " == .\n"); + } + dbuf_printf (oBuf, "%s:\n", sym->rname); + ++noAlloc; + resolveIvalSym (sym->ival, sym->type); + printIval (sym, sym->type, sym->ival, oBuf, (map != xinit && map != initializer)); + --noAlloc; + /* if sym is a simple string and sym->ival is a string, + WE don't need it anymore */ + if (IS_ARRAY (sym->type) && IS_CHAR (sym->type->next) && + IS_AST_SYM_VALUE (list2expr (sym->ival)) && list2val (sym->ival, TRUE)->sym->isstrlit) + { + freeStringSymbol (list2val (sym->ival, TRUE)->sym); + } + } + else + { + /* allocate space */ + if (options.debug) + { + emitDebugSym (oBuf, sym); + dbuf_printf (oBuf, " == .\n"); + } + /* special case for character strings */ + if (IS_ARRAY (sym->type) && + (IS_CHAR (sym->type->next) && SPEC_CVAL (sym->etype).v_char || + IS_INT (sym->type->next) && !IS_LONG (sym->type->next) && SPEC_CVAL (sym->etype).v_char16 || + IS_INT (sym->type->next) && IS_LONG (sym->type->next) && SPEC_CVAL (sym->etype).v_char32)) + { + if (options.const_seg) + dbuf_tprintf(&code->oBuf, "\t!area\n", options.const_seg); + dbuf_printf (oBuf, "%s:\n", sym->rname); + if (IS_CHAR (sym->type->next)) + printChar (oBuf, SPEC_CVAL (sym->etype).v_char, size); + else if (IS_INT (sym->type->next) && !IS_LONG (sym->type->next)) + printChar16 (oBuf, SPEC_CVAL (sym->etype).v_char16, size / 2); + else if (IS_INT (sym->type->next) && IS_LONG (sym->type->next)) + printChar32 (oBuf, SPEC_CVAL (sym->etype).v_char32, size / 4); + else + wassert (0); + if (options.const_seg) + dbuf_tprintf(oBuf, "\t!areacode\n", options.code_seg); + } + else + { + dbuf_printf (oBuf, "%s:\n", sym->rname); + dbuf_tprintf (oBuf, "\t!ds\n", (unsigned int) size & 0xffff); + } + } + } + } + + if (tmpSet) + deleteSet (&tmpSet); + if (ccpStr) + { + char *p; + for (p = setFirstItem (ccpStr); p; p = setNextItem (ccpStr)) + if (p) + free (p); + deleteSet (&ccpStr); + } +} + +/*-----------------------------------------------------------------*/ +/* emitMaps - emits the code for the data portion the code */ +/*-----------------------------------------------------------------*/ +void +emitMaps (void) +{ + namedspacemap *nm; + int publicsfr = TARGET_IS_MCS51 || TARGET_PDK_LIKE; /* Ideally, this should be true for all */ + /* ports but let's be conservative - EEP */ + + inInitMode++; + /* no special considerations for the following + data, idata & bit & xdata */ + emitRegularMap (data, TRUE, TRUE); + emitRegularMap (initialized, TRUE, TRUE); + for (nm = namedspacemaps; nm; nm = nm->next) + if (nm->is_const) + { + dbuf_tprintf (&nm->map->oBuf, "\t!areacode\n", nm->map->sname); + emitStaticSeg (nm->map, &nm->map->oBuf); + } + else + emitRegularMap (nm->map, TRUE, TRUE); + emitRegularMap (idata, TRUE, TRUE); + emitRegularMap (d_abs, TRUE, TRUE); + emitRegularMap (i_abs, TRUE, TRUE); + emitRegularMap (bit, TRUE, TRUE); + emitRegularMap (pdata, TRUE, TRUE); + emitRegularMap (xdata, TRUE, TRUE); + emitRegularMap (x_abs, TRUE, TRUE); + if (port->genXINIT) + { + emitRegularMap (xidata, TRUE, TRUE); + } + emitRegularMap (sfr, publicsfr, FALSE); + emitRegularMap (sfrbit, publicsfr, FALSE); + emitRegularMap (home, TRUE, FALSE); + emitRegularMap (code, TRUE, FALSE); + + if (options.const_seg) + dbuf_tprintf (&code->oBuf, "\t!area\n", options.const_seg); + emitStaticSeg (statsg, &code->oBuf); + + if (port->genXINIT) + { + dbuf_tprintf (&code->oBuf, "\t!area\n", xinit->sname); + emitStaticSeg (xinit, &code->oBuf); + } + if (initializer) + { + dbuf_tprintf (&code->oBuf, "\t!area\n", initializer->sname); + emitStaticSeg (initializer, &code->oBuf); + } + dbuf_tprintf (&code->oBuf, "\t!area\n", c_abs->sname); + emitStaticSeg (c_abs, &code->oBuf); + inInitMode--; +} + +/*-----------------------------------------------------------------*/ +/* flushStatics - flush all currently defined statics out to file */ +/* and delete. Temporary function */ +/*-----------------------------------------------------------------*/ +void +flushStatics (void) +{ + emitStaticSeg (statsg, codeOutBuf); + statsg->syms = NULL; +} + +/*-----------------------------------------------------------------*/ +/* createInterruptVect - creates the interrupt vector */ +/*-----------------------------------------------------------------*/ +void +createInterruptVect (struct dbuf_s *vBuf) +{ + mainf = newSymbol ("main", 0); + mainf->block = 0; + + /* only if the main function exists */ + if (!(mainf = findSymWithLevel (SymbolTab, mainf))) + { + if (!options.cc_only && !noAssemble && !options.c1mode) + werror (E_NO_MAIN); + 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); + return; + } + + dbuf_tprintf (vBuf, "\t!areacode\n", HOME_NAME); + dbuf_printf (vBuf, "__interrupt_vect:\n"); + + + if (!port->genIVT || !(port->genIVT (vBuf, interrupts, maxInterrupts))) + { + /* There's no such thing as a "generic" interrupt table header. */ + wassert (0); + } +} + +char *iComments1 = { + ";--------------------------------------------------------\n" + "; File Created by SDCC : free open source ANSI-C Compiler\n" +}; + +char *iComments2 = { + ";--------------------------------------------------------\n" +}; + + +/*-----------------------------------------------------------------*/ +/* initialComments - puts in some initial comments */ +/*-----------------------------------------------------------------*/ +void +initialComments (FILE * afile) +{ + fprintf (afile, "%s", iComments1); + fprintf (afile, "; Version " SDCC_VERSION_STR " #%s (%s)\n", getBuildNumber (), getBuildEnvironment ()); + fprintf (afile, "%s", iComments2); +} + +/*-----------------------------------------------------------------*/ +/* printPublics - generates .global for publics */ +/*-----------------------------------------------------------------*/ +void +printPublics (FILE * afile) +{ + symbol *sym; + + fprintf (afile, "%s", iComments2); + fprintf (afile, "; Public variables in this module\n"); + fprintf (afile, "%s", iComments2); + + for (sym = setFirstItem (publics); sym; sym = setNextItem (publics)) + tfprintf (afile, "\t!global\n", sym->rname); +} + +/*-----------------------------------------------------------------*/ +/* printExterns - generates .global for externs */ +/*-----------------------------------------------------------------*/ +void +printExterns (FILE * afile) +{ + symbol *sym; + + fprintf (afile, "%s", iComments2); + fprintf (afile, "; Externals used\n"); + fprintf (afile, "%s", iComments2); + + for (sym = setFirstItem (externs); sym; sym = setNextItem (externs)) + tfprintf (afile, "\t!extern\n", sym->rname); +} + +/*-----------------------------------------------------------------*/ +/* emitOverlay - will emit code for the overlay stuff */ +/*-----------------------------------------------------------------*/ +static void +emitOverlay (struct dbuf_s *aBuf) +{ + set *ovrset; + + /* for each of the sets in the overlay segment do */ + for (ovrset = setFirstItem (ovrSetSets); ovrset; ovrset = setNextItem (ovrSetSets)) + { + symbol *sym; + + if (elementsInSet (ovrset)) + { + /* output the area information */ + dbuf_printf (aBuf, "\t.area\t%s\n", port->mem.overlay_name); /* MOF */ + } + + for (sym = setFirstItem (ovrset); sym; sym = setNextItem (ovrset)) + { + /* if extern then it is in the publics table: 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) && !IS_STATIC (sym->localof->etype)) + { + addSetHead (&publics, sym); + } + + /* if extern then do nothing or is a function + then do nothing */ + if (IS_FUNC (sym->type)) + continue; + + /* if is has an absolute address then generate + an equate for this no need to allocate space */ + if (SPEC_ABSA (sym->etype)) + { + /* print extra debug info if required */ + if (options.debug) + { + emitDebugSym (aBuf, sym); + 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 + { + int size = getSize (sym->type); + + if (size == 0) + { + werrorfl (sym->fileDef, sym->lineDef, E_UNKNOWN_SIZE, sym->name); + } + /* print extra debug info if required */ + if (options.debug) + { + emitDebugSym (aBuf, sym); + dbuf_printf (aBuf, "==.\n"); + } + + /* allocate space */ + dbuf_tprintf (aBuf, "!slabeldef\n", sym->rname); + dbuf_tprintf (aBuf, "\t!ds\n", (unsigned int) getSize (sym->type) & 0xffff); + } + } + } +} + +/*-----------------------------------------------------------------*/ +/* glue - the final glue that hold the whole thing together */ +/*-----------------------------------------------------------------*/ +void +glue (void) +{ + struct dbuf_s vBuf; + struct dbuf_s ovrBuf; + struct dbuf_s asmFileName; + FILE *asmFile; + int mcs51_like; + namedspacemap *nm; + + dbuf_init (&vBuf, 4096); + dbuf_init (&ovrBuf, 4096); + + mcs51_like = (port->general.glue_up_main && + (TARGET_IS_MCS51 || TARGET_IS_DS390 || TARGET_IS_DS400)); + + /* print the global struct definitions */ + if (options.debug) + cdbStructBlock (0); + + /* PENDING: this isn't the best place but it will do */ + if (port->general.glue_up_main) + { + /* create the interrupt vector table */ + createInterruptVect (&vBuf); + } + + /* emit code for the all the variables declared */ + emitMaps (); + /* do the overlay segments */ + emitOverlay (&ovrBuf); + + outputDebugSymbols (); + + /* now put it all together into the assembler file */ + /* create the assembler file name */ + + /* -o option overrides default name? */ + dbuf_init (&asmFileName, PATH_MAX); + if ((noAssemble || options.c1mode) && fullDstFileName) + { + dbuf_append_str (&asmFileName, fullDstFileName); + } + else + { + dbuf_append_str (&asmFileName, dstFileName); + dbuf_append_str (&asmFileName, port->assembler.file_ext); + } + + if (!(asmFile = fopen (dbuf_c_str (&asmFileName), "w"))) + { + werror (E_FILE_OPEN_ERR, dbuf_c_str (&asmFileName)); + dbuf_destroy (&asmFileName); + exit (EXIT_FAILURE); + } + dbuf_destroy (&asmFileName); + + /* initial comments */ + initialComments (asmFile); + + if (TARGET_IS_S08) + fprintf (asmFile, "\t.cs08\n"); + else if (TARGET_IS_Z180) + fprintf (asmFile, "\t.hd64\n"); + else if (TARGET_IS_R3KA) + fprintf (asmFile, "\t.r3k\n"); + else if (TARGET_IS_EZ80_Z80) + fprintf (asmFile, "\t.ez80\n"); + + /* print module name */ + tfprintf (asmFile, "\t!module\n", moduleName); + if (mcs51_like) + { + if(!options.noOptsdccInAsm) + fprintf (asmFile, "\t.optsdcc -m%s", port->target); + + switch (options.model) + { + case MODEL_SMALL: + fprintf (asmFile, " --model-small"); + break; + case MODEL_COMPACT: + fprintf (asmFile, " --model-compact"); + break; + case MODEL_MEDIUM: + fprintf (asmFile, " --model-medium"); + break; + case MODEL_LARGE: + fprintf (asmFile, " --model-large"); + break; + case MODEL_FLAT24: + fprintf (asmFile, " --model-flat24"); + break; + case MODEL_HUGE: + fprintf (asmFile, " --model-huge"); + break; + default: + break; + } + /*if(options.stackAuto) fprintf (asmFile, " --stack-auto"); */ + if (options.useXstack) + fprintf (asmFile, " --xstack"); + /*if(options.intlong_rent) fprintf (asmFile, " --int-long-rent"); */ + /*if(options.float_rent) fprintf (asmFile, " --float-rent"); */ + if (options.noRegParams) + fprintf (asmFile, " --no-reg-params"); + if (options.parms_in_bank1) + fprintf (asmFile, " --parms-in-bank1"); + if (options.all_callee_saves) + fprintf (asmFile, " --all-callee-saves"); + fprintf (asmFile, "\n"); + } + else if (!TARGET_PIC_LIKE && !options.noOptsdccInAsm) + { + fprintf (asmFile, "\t.optsdcc -m%s\n", port->target); + } + + tfprintf (asmFile, "\t!fileprelude\n"); + + /* Let the port generate any global directives, etc. */ + if (port->genAssemblerPreamble) + { + port->genAssemblerPreamble (asmFile); + } + + /* print the global variables in this module */ + printPublics (asmFile); + if (port->assembler.externGlobal) + printExterns (asmFile); + + if ((mcs51_like) || (TARGET_IS_Z80 || TARGET_IS_GBZ80 || TARGET_IS_Z180 || TARGET_IS_RABBIT || TARGET_IS_EZ80_Z80) || TARGET_PDK_LIKE) /*.p.t.20030924 need to output SFR table for Z80 as well */ + { + /* copy the sfr segment */ + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "; special function registers\n"); + fprintf (asmFile, "%s", iComments2); + dbuf_write_and_destroy (&sfr->oBuf, asmFile); + } + + if (mcs51_like) + { + /* copy the sbit segment */ + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "; special function bits\n"); + fprintf (asmFile, "%s", iComments2); + dbuf_write_and_destroy (&sfrbit->oBuf, asmFile); + + /*JCF: Create the areas for the register banks */ + if (RegBankUsed[0] || RegBankUsed[1] || RegBankUsed[2] || RegBankUsed[3]) + { + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "; overlayable register banks\n"); + fprintf (asmFile, "%s", iComments2); + if (RegBankUsed[0]) + fprintf (asmFile, "\t.area REG_BANK_0\t(REL,OVR,DATA)\n\t.ds 8\n"); + if (RegBankUsed[1] || options.parms_in_bank1) + fprintf (asmFile, "\t.area REG_BANK_1\t(REL,OVR,DATA)\n\t.ds 8\n"); + if (RegBankUsed[2]) + fprintf (asmFile, "\t.area REG_BANK_2\t(REL,OVR,DATA)\n\t.ds 8\n"); + if (RegBankUsed[3]) + fprintf (asmFile, "\t.area REG_BANK_3\t(REL,OVR,DATA)\n\t.ds 8\n"); + } + if (BitBankUsed) + { + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "; overlayable bit register bank\n"); + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "\t.area BIT_BANK\t(REL,OVR,DATA)\n"); + fprintf (asmFile, "bits:\n\t.ds 1\n"); + fprintf (asmFile, "\tb0 = bits[0]\n"); + fprintf (asmFile, "\tb1 = bits[1]\n"); + fprintf (asmFile, "\tb2 = bits[2]\n"); + fprintf (asmFile, "\tb3 = bits[3]\n"); + fprintf (asmFile, "\tb4 = bits[4]\n"); + fprintf (asmFile, "\tb5 = bits[5]\n"); + fprintf (asmFile, "\tb6 = bits[6]\n"); + fprintf (asmFile, "\tb7 = bits[7]\n"); + } + } + + /* copy the data segment */ + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, ";%s ram data\n", mcs51_like ? " internal" : ""); + fprintf (asmFile, "%s", iComments2); + dbuf_write_and_destroy (&data->oBuf, asmFile); + + /* copy the initialized segment */ + if (initialized) + { + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, ";%s ram data\n", mcs51_like ? " internal" : ""); + fprintf (asmFile, "%s", iComments2); + dbuf_write_and_destroy (&initialized->oBuf, asmFile); + } + + /* copy segments for named address spaces */ + for (nm = namedspacemaps; nm; nm = nm->next) + { + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "; %s %s data\n", nm->name, nm->is_const ? "rom" : "ram"); + fprintf (asmFile, "%s", iComments2); + dbuf_write_and_destroy (&nm->map->oBuf, asmFile); + } + + /* create the overlay segments */ + if (overlay) + { + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "; overlayable items in%s ram \n", mcs51_like ? " internal" : ""); + fprintf (asmFile, "%s", iComments2); + dbuf_write_and_destroy (&ovrBuf, asmFile); + } + + /* create the stack segment MOF */ + if (mainf && IFFUNC_HASBODY (mainf->type)) + { + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "; Stack segment in internal ram \n"); + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "\t.area\tSSEG\n" "__start__stack:\n\t.ds\t1\n\n"); + } + + /* create the idata segment */ + if (idata) + { + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "; indirectly addressable internal ram data\n"); + fprintf (asmFile, "%s", iComments2); + dbuf_write_and_destroy (&idata->oBuf, asmFile); + } + + /* create the absolute idata/data segment */ + if (d_abs || i_abs) + { + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "; absolute%s ram data\n", mcs51_like ? " internal" : ""); + fprintf (asmFile, "%s", iComments2); + if (d_abs) + dbuf_write_and_destroy (&d_abs->oBuf, asmFile); + if (i_abs) + dbuf_write_and_destroy (&i_abs->oBuf, asmFile); + } + + /* copy the bit segment */ + if (bit) + { + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "; bit data\n"); + fprintf (asmFile, "%s", iComments2); + dbuf_write_and_destroy (&bit->oBuf, asmFile); + } + + /* copy paged external ram data */ + if (pdata) + { + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "; paged external ram data\n"); + fprintf (asmFile, "%s", iComments2); + dbuf_write_and_destroy (&pdata->oBuf, asmFile); + } + + /* if external stack then reserve space for it */ + if (mainf && IFFUNC_HASBODY (mainf->type) && options.useXstack) + { + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "; external stack \n"); + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "\t.area XSTK (PAG,XDATA)\n" "__start__xstack:\n\t.ds\t1\n\n"); + } + + /* copy external ram data */ + if (xdata && mcs51_like) + { + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "; external ram data\n"); + fprintf (asmFile, "%s", iComments2); + dbuf_write_and_destroy (&xdata->oBuf, asmFile); + } + + /* create the absolute xdata segment */ + if (x_abs) + { + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "; absolute external ram data\n"); + fprintf (asmFile, "%s", iComments2); + dbuf_write_and_destroy (&x_abs->oBuf, asmFile); + } + + /* copy external initialized ram data */ + if (xidata) + { + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "; external initialized ram data\n"); + fprintf (asmFile, "%s", iComments2); + dbuf_write_and_destroy (&xidata->oBuf, asmFile); + } + + /* If the port wants to generate any extra areas, let it do so. */ + if (port->extraAreas.genExtraAreaDeclaration) + { + port->extraAreas.genExtraAreaDeclaration (asmFile, mainf && IFFUNC_HASBODY (mainf->type)); + } + + /* copy the interrupt vector table */ + if (mainf && IFFUNC_HASBODY (mainf->type)) + { + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "; interrupt vector \n"); + fprintf (asmFile, "%s", iComments2); + dbuf_write_and_destroy (&vBuf, asmFile); + } + + /* copy global & static initialisations */ + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "; global & static initialisations\n"); + fprintf (asmFile, "%s", iComments2); + + /* Everywhere we generate a reference to the static_name area, + * (which is currently only here), we immediately follow it with a + * definition of the post_static_name area. This guarantees that + * the post_static_name area will immediately follow the static_name + * area. + */ + tfprintf (asmFile, "\t!area\n", port->mem.home_name); + tfprintf (asmFile, "\t!area\n", port->mem.static_name); /* MOF */ + tfprintf (asmFile, "\t!area\n", port->mem.post_static_name); + tfprintf (asmFile, "\t!area\n", port->mem.static_name); + + if (mainf && IFFUNC_HASBODY (mainf->type)) + { + if (port->genInitStartup) + { + port->genInitStartup (asmFile); + } + else + { + assert (0); + } + } + dbuf_write_and_destroy (&statsg->oBuf, asmFile); + + /* STM8 / PDK14 note: there are no such instructions supported. + Also, we don't need this logic as well. */ + if (port->general.glue_up_main && mainf && IFFUNC_HASBODY (mainf->type)) + { + /* This code is generated in the post-static area. + * This area is guaranteed to follow the static area + * by the ugly shucking and jiving about 20 lines ago. + */ + tfprintf (asmFile, "\t!area\n", port->mem.post_static_name); + if(TARGET_IS_STM8) + fprintf (asmFile, "\tjp\t__sdcc_program_startup\n"); + else if(TARGET_PDK_LIKE) + fprintf (asmFile, "\tgoto\t__sdcc_program_startup\n"); + else + fprintf (asmFile, "\t%cjmp\t__sdcc_program_startup\n", options.acall_ajmp ? 'a' : 'l'); + } + + fprintf (asmFile, "%s" "; Home\n" "%s", iComments2, iComments2); + tfprintf (asmFile, "\t!areahome\n", HOME_NAME); + dbuf_write_and_destroy (&home->oBuf, asmFile); + + if (mainf && IFFUNC_HASBODY (mainf->type)) + { + /* STM8 note: there is no need to call main(). + Instead of that, it's address is specified in the + interrupts table and always equals to 0x8080. + */ + + /* entry point @ start of HOME */ + fprintf (asmFile, "__sdcc_program_startup:\n"); + + /* put in jump or call to main */ + if(TARGET_IS_STM8) + fprintf (asmFile, options.model == MODEL_LARGE ? "\tjpf\t_main\n" : "\tjp\t_main\n"); + else if(TARGET_PDK_LIKE) + fprintf (asmFile, "\tgoto\t_main\n"); + else + fprintf (asmFile, "\t%cjmp\t_main\n", options.acall_ajmp ? 'a' : 'l'); /* needed? */ + fprintf (asmFile, ";\treturn from main will return to caller\n"); + } + /* copy over code */ + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "; code\n"); + fprintf (asmFile, "%s", iComments2); + tfprintf (asmFile, "\t!areacode\n", options.code_seg); + dbuf_write_and_destroy (&code->oBuf, asmFile); + + if (port->genAssemblerEnd) + { + port->genAssemblerEnd (asmFile); + } + fclose (asmFile); +} + +/* will return 1 if the string is a part + of a target specific keyword */ +int +isTargetKeyword (const char *s) +{ + int i; + + if (port->keywords == NULL) + return 0; + + if (s[0] == '_' && s[1] == '_') + { + /* Keywords in the port's array have either 0 or 1 underscore, */ + /* so skip over the appropriate number of chars when comparing */ + for (i = 0 ; port->keywords[i] ; i++ ) + { + if (port->keywords[i][0] == '_' && + strcmp(port->keywords[i],s+1) == 0) + return 1; + else if (strcmp(port->keywords[i],s+2) == 0) + return 1; + } + } + else + { + for (i = 0 ; port->keywords[i] ; i++ ) + { + if (strcmp(port->keywords[i],s) == 0) + return 1; + } + } + + return 0; +} + |
