sdcc-gas/src/SDCCglue.c

2773 lines
87 KiB
C

/*-------------------------------------------------------------------------
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];
static void emit_ds_comm( struct dbuf_s *oBuf,
const char *name,
unsigned int size);
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 && !options.gasOutput)
{
/* 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);
}
else if (options.gasOutput)
if (map == code)
dbuf_tprintf (&map->oBuf, "\t!area\n", ".text");
else if (map == data)
if (!options.data_sections)
dbuf_tprintf (&map->oBuf, "\t!area\n", DATA_NAME);
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), options.gasOutput ? "%s" : "__xinit_%s", sym->name);
SNPRINTF (newSym->rname, sizeof (newSym->rname), options.gasOutput ? "%s" : "__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);
if (options.gasOutput)
dbuf_printf (&map->oBuf, ":\n");
else
dbuf_printf (&map->oBuf, "==.\n");
}
if ((map != initialized && options.gasOutput) || !options.gasOutput)
{
if (IS_STATIC (sym->etype) || sym->level)
if (options.gasOutput)
{
if (options.data_sections)
dbuf_tprintf (&map->oBuf, "\t!area.%s\n", options.data_seg, sym->rname);
dbuf_tprintf (&map->oBuf, "\t!local\n", sym->rname);
}
else
dbuf_tprintf (&map->oBuf, "!slabeldef\n", sym->rname);
else
if (options.gasOutput)
dbuf_tprintf (&map->oBuf, "!global\n", sym->rname);
else if (IS_STATIC (sym->etype))
dbuf_tprintf (&map->oBuf, "!slabeldef\n", sym->rname);
else
dbuf_tprintf (&map->oBuf, "!labeldef\n", sym->rname);
emit_ds_comm(&map->oBuf, sym->rname, 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_tprintf (oBuf, "\tret !lsbimmeds\n", name);
dbuf_tprintf (oBuf, "\tret !msbimmeds\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_tprintf (oBuf, "\tret !lsbimmeds\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 && !options.gasOutput)
{
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 && !options.gasOutput)
{
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 && !options.gasOutput)
{
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)
if (options.data_sections)
dbuf_tprintf(&code->oBuf, "\t!area.%s\n", options.const_seg, sym->rname);
else
dbuf_tprintf(&code->oBuf, "\t!area\n", options.const_seg);
if (IS_STATIC (sym->etype) && !options.gasOutput)
dbuf_tprintf (oBuf, "!slabeldef\n", sym->rname);
else
dbuf_tprintf (oBuf, "!labeldef\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
{
if (options.gasOutput)
dbuf_tprintf(oBuf, "\t!local\n", sym->rname);
else
dbuf_printf (oBuf, "%s:\n", sym->rname);
emit_ds_comm(oBuf, sym->rname, 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", options.gasOutput ? INITIALIZER_NAME : 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", HOME_NAME);
if (options.gasOutput)
/* Read-executable flags must be defined so ld can
* place the interrupt vectors into a separate section.*/
dbuf_tprintf (vBuf, ",\t\"ax\"");
dbuf_printf(vBuf, "\n");
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);
}
}
const char *iComments1 = {
";--------------------------------------------------------\n"
"; File Created by SDCC : free open source ANSI-C Compiler\n"
};
const 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_tprintf (aBuf, "\t!area\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 && !options.gasOutput)
{
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);
if (options.gasOutput)
dbuf_printf (aBuf, ":\n");
else
dbuf_printf (aBuf, "==.\n");
}
/* allocate space */
if (options.gasOutput)
/* .bss variables do not need a label definition on GNU as. */
dbuf_tprintf(aBuf, "\t!local\n", sym->rname);
else
dbuf_tprintf (aBuf, "!slabeldef\n", sym->rname);
emit_ds_comm(aBuf, sym->rname, 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 && !options.gasOutput)
fprintf (asmFile, "\t.optsdcc -m%s", port->target);
else if (options.gasOutput && options.noOptsdccInAsm)
werror(W_IGNORED_OPT_IN_ASM);
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)
{
if(!options.gasOutput)
fprintf (asmFile, "\t.optsdcc -m%s", port->target);
}
else if (options.noOptsdccInAsm && options.gasOutput)
werror(W_IGNORED_OPT_IN_ASM);
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);
if (!options.gasOutput)
{
const unsigned int size = 1;
tfprintf(asmFile, "\t!area\n", "SSEG");
tfprintf(asmFile, "\t__start__stack:\n");
tfprintf(asmFile, "\t!ds\n\n", size);
}
}
/* 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.
* This is not needed for GNU as, though. */
if (port->extraAreas.genExtraAreaDeclaration && !options.gasOutput)
{
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);
if (!options.gasOutput)
{
/* 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 (options.gasOutput)
{
tfprintf (asmFile, "\t!areacode\n", CODE_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) && !options.gasOutput)
{
/* 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');
}
if (!options.gasOutput)
{
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, its address is specified in the
interrupts table and always equals to 0x8080.
*/
/* entry point @ start of HOME */
tfprintf (asmFile, "!labeldef\n", "__sdcc_program_startup");
/* 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;
}
static void emit_ds_comm( struct dbuf_s *const oBuf,
const char *const name,
const unsigned int size)
{
if (options.gasOutput)
dbuf_tprintf(oBuf, "\t!comm\n", name, size);
else
dbuf_tprintf(oBuf, "\t!ds\n", size);
}