+2005-07-19 Maarten Brock <sourceforge.brock AT dse.nl>
+
+ * as/mcs51/lkarea.c (lnkarea, lnkarea2): improved BSEG size calculation,
+ (lnksect2): generate warnings for memory overlap
+ * src/SDCC.lex (doPragma, process_pragma): added pragma's codeseg and
+ constseg to set the name of these segments so you can instruct the linker
+ to place them in banks
+ * src/SDCCast.c (decorateType): use new macro IS_FUNCPTR()
+ * src/SDCCglobl.h: added MODEL_HUGE to enum,
+ added code_seg and const_seg to options
+ * src/SDCCglue.c (emitMaps): use options.const_seg,
+ (createInterruptVect): put interrupt vectors in segment HOME,
+ (glue): put HOME before static segment and put the main glue in HOME,
+ (glue): use options.code_seg
+ * src/SDCCicode.c (geniCodeCall): use new macro IS_FUNCPTR()
+ * src/SDCCmain.c: added option --codeseg and --constseg to set the name of
+ these segments so you can instruct the linker to place them in banks
+ (linkEdit): use code_loc for HOME segment which should be the first
+ segment in code memory now
+ * src/SDCCmem.c: fixed more stuff like bug 1238386
+ * src/SDCCsymt.c (getSize): use generic pointer size for banked functions,
+ (changePointer): don't change function pointers to code pointers for
+ banked functions,
+ (compareType): added exceptional check for banked function pointers
+ * src/SDCCsymt.h: changed IFFUNC_ISBANKEDCALL, added IS_FUNCPTR
+ * src/hc08/main.c (_hc08_genAssemblerPreamble): put HOME first, put CSEG
+ after static in code memory
+ * src/mcs51/gen.c: added aopLiteralLong prototype,
+ (aopForSym): use getSize for functions,
+ (genCall): generate banked calls over one trampoline __sdcc_banked_call
+ in HOME with lsb of address in r0, msb in r1 and bank in r2, use
+ -Wl-bBANKSEG=0xbbaaaa option to set the address (aaaa) and bank (bb) of
+ the segment,
+ (genPcall): use call for literal function pointers and generate banked
+ calls over the one trampoline so there's only one place for the user to
+ modify according to his/hers hardware,
+ (genEndFunction): jump to __sdcc_banked_ret in HOME for banked functions,
+ (genPlusIncr): moved check icount>4 beyond inc dptr optimization
+ * src/mcs51/main.c: added keyword banked,
+ (_mcs51_genExtraAreas): put HOME first followed by GSINIT, STATIC and CSEG
+ * support/Util/SDCCerr.c,
+ * support/Util/SDCCerr.h: added E_BANKED_WITH_CALLEESAVES, registers are
+ needed for passing the bank and address to the trampoline
+ * device/lib/mcs51/crtbank.asm: added for bankswitching
+ * device/lib/mcs51/Makefile: added crtbank
+
2005-07-16 Erik Petrich <epetrich AT ivorytower.norman.ok.us>
* src/SDCCcse.c (algebraicOpts): fixed loss of volatility
ap = areap;
axp = (struct areax *) new (sizeof(struct areax));
+ axp->a_addr = -1; /* default: no address yet */
while (ap) {
if (symeq(id, ap->a_id)) {
taxp = ap->a_axp;
/*JCF: Since area BSEG is defined just before BSEG_BYTES, use the bit size of BSEG
to compute the byte size of BSEG_BYTES: */
if (!strcmp(ap->a_id, "BSEG")) {
- ap->a_ap->a_axp->a_size=(ap->a_addr/8)+((ap->a_size+7)/8); /*Bits to bytes*/
+ ap->a_ap->a_axp->a_size += ((ap->a_addr + ap->a_size + 7)/8); /*Bits to bytes*/
}
else if (!strcmp(ap->a_id, "REG_BANK_0")) ta[0]=ap;
else if (!strcmp(ap->a_id, "REG_BANK_1")) ta[1]=ap;
void lnksect2 (struct area *tap, int rloc);
char idatamap[256];
+long codemap[2048];
/*Modified version of the functions for packing variables in internal data memory*/
VOID lnkarea2 (void)
struct sym *sp_dseg_s=NULL, *sp_dseg_l=NULL;
for(j=0; j<256; j++) idatamap[j]=' ';
+ memset(codemap, 0, sizeof(codemap));
ap = areap;
while (ap)
to compute the byte size of BSEG_BYTES: */
if (!strcmp(ap->a_id, "BSEG"))
{
- ap->a_ap->a_axp->a_size=(ap->a_addr/8)+((ap->a_size+7)/8); /*Bits to bytes*/
+ ap->a_ap->a_axp->a_size = ((ap->a_addr + ap->a_size + 7)/8); /*Bits to bytes*/
}
else if (!strcmp(ap->a_id, "DSEG"))
{
{
if(taxp->a_size!=0)
{
- for(j=0x20+taxp->a_addr; j<((int)(0x20+taxp->a_addr+taxp->a_size)); j++)
+ for(j=addr; j<((int)(addr+taxp->a_size)); j++)
idatamap[j]=fchar;
}
{
taxp->a_size = 256-(addr & 0xFF);
}
+ //should find next unused address now!!!
+ //but let's first just warn for overlaps
+ if (rloc == 1)
+ {
+ int a = addr;
+ int i = addr >> 5;
+ int j = (addr + taxp->a_size) >> 5;
+ long mask = -(1 << (addr & 0x1F));
+
+ while (i < j)
+ {
+ if (codemap[i] & mask)
+ {
+ fprintf(stderr, "memory overlap near 0x%X for %s\n", a, tap->a_id);
+ }
+ codemap[i++] |= mask;
+ mask = 0xFFFFFFFF;
+ a += 32;
+ }
+ mask &= (1 << ((addr + taxp->a_size) & 0x1F)) - 1;
+ if (codemap[i] & mask)
+ {
+ fprintf(stderr, "memory overlap near 0x%X for %s\n", a, tap->a_id);
+ }
+ codemap[i] |= mask;
+ }
taxp->a_addr = addr;
addr += taxp->a_size;
size += taxp->a_size;
SCC = $(TOPDIR)/bin/sdcc
OBJ = crtstart.rel crtxinit.rel crtxclear.rel crtclear.rel crtxstack.rel \
- crtpagesfr.rel
-
+ crtpagesfr.rel crtbank.rel
+
LIB = mcs51.lib
CC = $(SCC)
--- /dev/null
+; /*-------------------------------------------------------------------------
+;
+; crtbank.asm :- C run-time: bank switching
+;
+; This library is free software; you can redistribute it and/or modify it
+; under the terms of the GNU Library General Public License as published by the
+; Free Software Foundation; either version 2, or (at your option) any
+; later version.
+;
+; This library 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 Library General Public License for more details.
+;
+; You should have received a copy of the GNU Library General Public License
+; along with this program; if not, write to the Free Software
+; Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+;
+; In other words, you are welcome to use, share and improve this program.
+; You are forbidden to forbid anyone else to use, share and improve
+; what you give them. Help stamp out software-hoarding!
+; -------------------------------------------------------------------------*/
+
+ .area HOME (CODE)
+ .area GSINIT0 (CODE)
+ .area GSINIT1 (CODE)
+ .area GSINIT2 (CODE)
+ .area GSINIT3 (CODE)
+ .area GSINIT4 (CODE)
+ .area GSINIT5 (CODE)
+ .area GSINIT (CODE)
+ .area GSFINAL (CODE)
+ .area CSEG (CODE)
+
+; /*-------------------------------------------------------------------------
+; Example for SiLabs C8051F12x / C8051F13x with 128kB code memory
+; divided into 4 banks of 32kB
+; These devices have an sfr called PSBANK containing two parts:
+; COBANK (bit 5:4): Constant Operations Bank
+; IFBANK (bit 1:0): Instruction Fetch Bank
+; From 0x0000 to 0x7FFF bank 0 is always accessed
+; From 0x8000 to 0xFFFF bank COBANK is accessed for reading with movc
+; From 0x8000 to 0xFFFF bank IFBANK is accessed for executing instructions
+;
+; Make your own copy of this file,
+; adapt it to your situation,
+; and compile/link it in your project
+; -------------------------------------------------------------------------*/
+
+ .globl _PSBANK
+
+ .area HOME (CODE)
+
+__sdcc_banked_call::
+ push _PSBANK ;save return bank
+ xch a,r0 ;save Acc in r0, do not assume any register bank
+ push acc ;push LSB address
+ mov a,r1
+ push acc ;push MSB address
+ mov a,r2 ;get new bank
+ anl a,0x0F ;remove storage class indicator
+ anl _PSBANK,#0xF0
+ orl _PSBANK,a ;select bank
+ xch a,r0 ;restore Acc
+ ret ;make the call
+
+__sdcc_banked_ret::
+ pop _PSBANK ;restore bank
+ ret ;return to caller
P_STD_C89,
P_STD_C99,
P_STD_SDCC89,
- P_STD_SDCC99
+ P_STD_SDCC99,
+ P_CODESEG,
+ P_CONSTSEG
};
options.std_c99 = 1;
options.std_sdcc = 1;
break;
+
+ case P_CODESEG:
+ {
+ char str[9];
+ char *segname = Safe_malloc(15);
+ sscanf(cp, " %8s", str);
+ str[8] = '\0';
+ sprintf(segname, "%-8.8s(CODE)", str);
+ options.code_seg = segname;
+ }
+ break;
+
+ case P_CONSTSEG:
+ {
+ char str[9];
+ char *segname = Safe_malloc(15);
+ sscanf(cp, " %8s", str);
+ str[8] = '\0';
+ sprintf(segname, "%-8.8s(CODE)", str);
+ options.const_seg = segname;
+ }
+ break;
}
}
{ "opt_code_speed", P_OPTCODESPEED, 0 },
{ "opt_code_size", P_OPTCODESIZE, 0 },
{ "opt_code_balanced", P_OPTCODEBALANCED, 0 },
- { "std_c89", P_STD_C89, 0 },
- { "std_c99", P_STD_C99, 0 },
- { "std_sdcc89", P_STD_SDCC89, 0 },
- { "std_sdcc99", P_STD_SDCC99, 0 },
+ { "std_c89", P_STD_C89, 0 },
+ { "std_c99", P_STD_C99, 0 },
+ { "std_sdcc89", P_STD_SDCC89, 0 },
+ { "std_sdcc99", P_STD_SDCC99, 0 },
+ { "codeseg", P_CODESEG, 0 },
+ { "constseg", P_CONSTSEG, 0 },
/*
* The following lines are deprecated pragmas,
}
/* require a function or pointer to function */
- if (!IS_FUNC (LTYPE (tree))
- && !(IS_CODEPTR (LTYPE (tree)) && IS_FUNC (LTYPE (tree)->next)))
+ if (!IS_FUNC (LTYPE (tree)) && !IS_FUNCPTR (LTYPE (tree)))
{
werrorfl (tree->filename, tree->lineno, E_FUNCTION_EXPECTED);
goto errorTreeReturn;
sym_link *functype;
parmNumber = 1;
- if (IS_CODEPTR(LTYPE(tree)))
+ if (IS_FUNCPTR (LTYPE (tree)))
functype = LTYPE (tree)->next;
else
functype = LTYPE (tree);
MODEL_MEDIUM = 4,
MODEL_LARGE = 8,
MODEL_FLAT24 = 16,
- MODEL_PAGE0 = 32 /* for the xa51 port */
+ MODEL_PAGE0 = 32, /* for the xa51 port */
+ MODEL_HUGE = 64 /* for banked support */
};
/* overlay segment name and the functions
int printSearchDirs; /* display the directories in the compiler's search path */
int vc_err_style; /* errors and warnings are compatible with Micro$oft visual studio */
int use_stdout; /* send errors to stdout instead of stderr */
- int no_std_crt0; /*For the z80/gbz80 do not link default crt0.o*/
- int std_c99; /* enable C99 keywords/constructs */
- int std_sdcc; /* enable SDCC extensions to C */
+ int no_std_crt0; /* for the z80/gbz80 do not link default crt0.o*/
+ int std_c99; /* enable C99 keywords/constructs */
+ int std_sdcc; /* enable SDCC extensions to C */
+ const char *code_seg; /* segment name to use instead of CSEG */
+ const char *const_seg; /* segment name to use instead of CONST */
/* sets */
set *calleeSavesSet; /* list of functions using callee save */
set *excludeRegsSet; /* registers excluded from saving */
};
/* forward definition for variables accessed globally */
-extern int noAssemble; /* no assembly, stop after code generation */
+extern int noAssemble; /* no assembly, stop after code generation */
extern char *yytext;
extern char *currFname;
extern char *fullSrcFileName; /* full name for the source file; */
emitRegularMap (home, TRUE, FALSE);
emitRegularMap (code, TRUE, FALSE);
- if (CONST_NAME) {
- tfprintf (code->oFile, "\t!area\n", CONST_NAME);
+ if (options.const_seg) {
+ tfprintf (code->oFile, "\t!area\n", options.const_seg);
}
emitStaticSeg (statsg, code->oFile);
if (port->genXINIT) {
return;
}
- tfprintf (vFile, "\t!areacode\n", CODE_NAME);
+ tfprintf (vFile, "\t!areacode\n", HOME_NAME);
fprintf (vFile, "__interrupt_vect:\n");
* the post_static_name area will immediately follow the static_name
* area.
*/
- tfprintf (asmFile, "\t!area\n", port->mem.code_name);
+ 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);
tfprintf (asmFile, "\t!areahome\n", HOME_NAME);
copyFile (asmFile, home->oFile);
- /* copy over code */
- fprintf (asmFile, "%s", iComments2);
- fprintf (asmFile, "; code\n");
- fprintf (asmFile, "%s", iComments2);
- tfprintf (asmFile, "\t!areacode\n", CODE_NAME);
if (mainf && IFFUNC_HASBODY(mainf->type))
{
- /* entry point @ start of CSEG */
+ /* entry point @ start of HOME */
fprintf (asmFile, "__sdcc_program_startup:\n");
/* put in jump or call to main */
fprintf (asmFile, "\tsjmp .\n");
}
}
+ /* copy over code */
+ fprintf (asmFile, "%s", iComments2);
+ fprintf (asmFile, "; code\n");
+ fprintf (asmFile, "%s", iComments2);
+ tfprintf (asmFile, "\t!areacode\n", options.code_seg);
copyFile (asmFile, code->oFile);
if (port->genAssemblerEnd) {
int stack = 0;
if (!IS_FUNC(OP_SYMBOL(left)->type) &&
- !IS_CODEPTR(OP_SYMBOL(left)->type)) {
+ !IS_FUNCPTR(OP_SYMBOL(left)->type)) {
werror (E_FUNCTION_EXPECTED);
return operandFromValue(valueFromLit(0));
}
geniCodeSEParms (parms,lvl);
ftype = operandType (left);
- if (IS_CODEPTR (ftype))
+ if (IS_FUNCPTR (ftype))
ftype = ftype->next;
/* first the parameters */
#define OPTION_STD_C99 "--std-c99"
#define OPTION_STD_SDCC89 "--std-sdcc89"
#define OPTION_STD_SDCC99 "--std-sdcc99"
+#define OPTION_CODE_SEG "--codeseg"
+#define OPTION_CONST_SEG "--constseg"
static const OPTION
optionsTable[] = {
{ 0, "--no-std-crt0", &options.no_std_crt0, "For the z80/gbz80 do not link default crt0.o"},
#endif
{ 0, OPTION_SHORT_IS_8BITS, NULL, "Make short 8 bits (for old times sake)" },
+ { 0, OPTION_CODE_SEG, NULL, "<name> use this name for the code segment" },
+ { 0, OPTION_CONST_SEG, NULL, "<name> use this name for the const segment" },
{ 0, NULL, NULL, "Optimization options"},
{ 0, "--nooverlay", &options.noOverlay, "Disable overlaying leaf function auto variables" },
options.shortis8bits = 0;
options.std_sdcc = 1; /* enable SDCC language extensions */
options.std_c99 = 0; /* default to C89 until more C99 support */
+ options.code_seg = CODE_NAME; /* default to CSEG for generated code */
+ options.const_seg = CONST_NAME; /* default to CONST for generated code */
options.stack10bit=0;
continue;
}
+ if (strcmp (argv[i], OPTION_CODE_SEG) == 0)
+ {
+ options.code_seg = getStringArg(OPTION_CODE_SEG, argv, &i, argc);
+ continue;
+ }
+
+ if (strcmp (argv[i], OPTION_CONST_SEG) == 0)
+ {
+ options.const_seg = getStringArg(OPTION_CONST_SEG, argv, &i, argc);
+ continue;
+ }
+
if (!port->parseOption (&argc, argv, &i))
{
werror (W_UNKNOWN_OPTION, argv[i]);
{
/* code segment start */
- WRITE_SEG_LOC (CODE_NAME, options.code_loc);
+ WRITE_SEG_LOC (HOME_NAME, options.code_loc);
/* data segment start. If zero, the linker chooses
the best place for data */
}
}
+/*-----------------------------------------------------------------*/
+/* allocDefault - assigns the output segment based on SCLASS */
+/*-----------------------------------------------------------------*/
+bool
+allocDefault (symbol * sym)
+{
+ switch (SPEC_SCLS (sym->etype))
+ {
+ case S_SFR:
+ SPEC_OCLS (sym->etype) = sfr;
+ break;
+ case S_SBIT:
+ SPEC_OCLS (sym->etype) = sfrbit;
+ break;
+ case S_CODE:
+ if (sym->_isparm)
+ return FALSE;
+ /* if code change to constant */
+ SPEC_OCLS (sym->etype) = statsg;
+ break;
+ case S_XDATA:
+ // should we move this to the initialized data segment?
+ if (port->genXINIT &&
+ sym->ival && (sym->level==0) && !SPEC_ABSA(sym->etype)) {
+ SPEC_OCLS(sym->etype) = xidata;
+ } else {
+ SPEC_OCLS (sym->etype) = xdata;
+ }
+ break;
+ case S_DATA:
+ SPEC_OCLS (sym->etype) = data;
+ break;
+ case S_IDATA:
+ SPEC_OCLS (sym->etype) = idata;
+ sym->iaccess = 1;
+ break;
+ case S_PDATA:
+ SPEC_OCLS (sym->etype) = pdata;
+ sym->iaccess = 1;
+ break;
+ case S_BIT:
+ SPEC_OCLS (sym->etype) = bit;
+ break;
+ case S_EEPROM:
+ SPEC_OCLS (sym->etype) = eeprom;
+ break;
+ default:
+ return FALSE;
+ }
+ allocIntoSeg (sym);
+ return TRUE;
+}
/*-----------------------------------------------------------------*/
/* allocGlobal - assigns the output segment to a global var */
return;
}
- /* if this is a SFR or SBIT */
- if (SPEC_SCLS (sym->etype) == S_SFR ||
- SPEC_SCLS (sym->etype) == S_SBIT)
- {
-
- SPEC_OCLS (sym->etype) =
- (SPEC_SCLS (sym->etype) == S_SFR ? sfr : sfrbit);
-
- allocIntoSeg (sym);
- return;
- }
-
/* if this is a bit variable and no storage class */
if (SPEC_NOUN (sym->etype) == V_BIT
- && SPEC_SCLS (sym->etype) == S_BIT)
- {
- SPEC_OCLS (sym->etype) = bit;
- allocIntoSeg (sym);
- return;
- }
-
- /* if bit storage class */
- if (SPEC_SCLS (sym->etype) == S_SBIT)
+ /*&& SPEC_SCLS (sym->etype) == S_BIT*/)
{
SPEC_OCLS (sym->etype) = bit;
allocIntoSeg (sym);
if (SPEC_SCLS (sym->etype) == S_REGISTER)
SPEC_SCLS (sym->etype) = S_FIXED;
- /* if data specified then */
- if (SPEC_SCLS (sym->etype) == S_DATA)
- {
- /* set the output class */
- SPEC_OCLS (sym->etype) = data;
- /* generate the symbol */
- allocIntoSeg (sym);
- return;
- }
-
/* if it is fixed, then allocate depending on the */
/* current memory model, same for automatics */
if (SPEC_SCLS (sym->etype) == S_FIXED ||
}
}
- /* if code change to constant */
- if (SPEC_SCLS (sym->etype) == S_CODE) {
- SPEC_OCLS (sym->etype) = statsg;
- allocIntoSeg (sym);
- return;
- }
-
- if (SPEC_SCLS (sym->etype) == S_XDATA)
- {
- // should we move this to the initialized data segment?
- if (port->genXINIT &&
- sym->ival && (sym->level==0) && !SPEC_ABSA(sym->etype)) {
- SPEC_OCLS(sym->etype)=xidata;
- } else {
- SPEC_OCLS (sym->etype) = xdata;
- }
- allocIntoSeg (sym);
- return;
- }
-
- if (SPEC_SCLS (sym->etype) == S_IDATA)
- {
- SPEC_OCLS (sym->etype) = idata;
- sym->iaccess = 1;
- allocIntoSeg (sym);
- return;
- }
-
- if (SPEC_SCLS (sym->etype) == S_PDATA)
- {
- SPEC_OCLS (sym->etype) = pdata;
- sym->iaccess = 1;
- allocIntoSeg (sym);
- return;
- }
-
- if (SPEC_SCLS (sym->etype) == S_EEPROM)
- {
- SPEC_OCLS (sym->etype) = eeprom;
- allocIntoSeg (sym);
- return;
- }
-
+ allocDefault (sym);
return;
}
"%s%s_PARM_%d", port->fun_prefix, currFunc->name, pNum);
strncpyz (lval->name, lval->sym->rname, sizeof(lval->name));
- /* if declared in external storage */
- if (SPEC_SCLS (lval->etype) == S_XDATA)
- SPEC_OCLS (lval->etype) = SPEC_OCLS (lval->sym->etype) = xdata;
- else if (SPEC_SCLS (lval->etype) == S_BIT)
- SPEC_OCLS (lval->etype) = SPEC_OCLS (lval->sym->etype) = bit;
- else
+ /* if declared in specific storage */
+ if (allocDefault (lval->sym))
+ {
+ SPEC_OCLS (lval->etype) = SPEC_OCLS (lval->sym->etype);
+ continue;
+ }
+
/* otherwise depending on the memory model
note here that we put it into the overlay segment
first, we will remove it from the overlay segment
}
/* else depending on the storage class specified */
- if (SPEC_SCLS (sym->etype) == S_XDATA)
- {
- SPEC_OCLS (sym->etype) = xdata;
- allocIntoSeg (sym);
- return;
- }
-
- if (SPEC_SCLS (sym->etype) == S_CODE && !sym->_isparm) {
- SPEC_OCLS (sym->etype) = statsg;
- allocIntoSeg (sym);
- return;
- }
-
- if (SPEC_SCLS (sym->etype) == S_IDATA)
- {
- SPEC_OCLS (sym->etype) = idata;
- sym->iaccess = 1;
- allocIntoSeg (sym);
- return;
- }
-
- if (SPEC_SCLS (sym->etype) == S_PDATA)
- {
- SPEC_OCLS (sym->etype) = pdata;
- sym->iaccess = 1;
- allocIntoSeg (sym);
- return;
- }
/* if this is a function then assign code space */
if (IS_FUNC (sym->type))
return;
}
- /* if this is a SFR or SBIT */
- if (SPEC_SCLS (sym->etype) == S_SFR ||
- SPEC_SCLS (sym->etype) == S_SBIT)
- {
- SPEC_OCLS (sym->etype) =
- (SPEC_SCLS (sym->etype) == S_SFR ? sfr : sfrbit);
-
- allocIntoSeg (sym);
- return;
- }
-
/* if this is a bit variable and no storage class */
if (SPEC_NOUN (sym->etype) == V_BIT
&& (SPEC_SCLS (sym->etype) == S_BIT))
return;
}
- if (SPEC_SCLS (sym->etype) == S_EEPROM)
+ if (allocDefault (sym))
{
- SPEC_OCLS (sym->etype) = eeprom;
- allocIntoSeg (sym);
return;
}
case FPOINTER:
case CPOINTER:
case FUNCTION:
- return (FPTRSIZE);
+ return (IFFUNC_BANKED (p) ? GPTRSIZE : FPTRSIZE);
case GPOINTER:
return (GPTRSIZE);
/* go thru the chain of declarations */
/* if we find a pointer to a function */
- /* unconditionally change it to a ptr */
- /* to code area */
+ /* change it to a ptr to code area */
+ /* unless the function is banked. */
for (; p; p = p->next)
{
if (!IS_SPEC (p) && DCL_TYPE (p) == UPOINTER)
DCL_TYPE (p) = port->unqualified_pointer;
if (IS_PTR (p) && IS_FUNC (p->next))
+ if (!IFFUNC_BANKED(p->next))
DCL_TYPE (p) = CPOINTER;
}
}
{
if (IS_DECL (src))
{
+ /* banked function pointer */
+ if (IS_GENPTR (dest) && IS_GENPTR (src))
+ {
+ if (IS_FUNC (src->next) && IS_VOID(dest->next))
+ return -1;
+ if (IS_FUNC (dest->next) && IS_VOID(src->next))
+ return -1;
+ return compareType (dest->next, src->next);
+ }
+
if (DCL_TYPE (src) == DCL_TYPE (dest)) {
if (IS_FUNC(src)) {
//checkFunction(src,dest);
#define IFFUNC_ISOVERLAY(x) (IS_FUNC(x) && FUNC_ISOVERLAY(x))
#define IFFUNC_ISBANKEDCALL(x) (!IFFUNC_NONBANKED(x) && \
- (options.model == MODEL_LARGE || \
- options.model == MODEL_MEDIUM || \
+ (options.model == MODEL_HUGE || \
+ ((options.model == MODEL_LARGE || options.model == MODEL_MEDIUM) && \
+ (TARGET_IS_Z80 || TARGET_IS_GBZ80)) || \
IFFUNC_BANKED(x)))
#define SPEC_NOUN(x) validateLink(x, "SPEC_NOUN", #x, SPECIFIER, __FILE__, __LINE__)->select.s.noun
#define IS_FARPTR(x) (IS_DECL(x) && DCL_TYPE(x) == FPOINTER)
#define IS_CODEPTR(x) (IS_DECL(x) && DCL_TYPE(x) == CPOINTER)
#define IS_GENPTR(x) (IS_DECL(x) && DCL_TYPE(x) == GPOINTER)
+#define IS_FUNCPTR(x) (IS_DECL(x) && (DCL_TYPE(x) == CPOINTER || DCL_TYPE(x) == GPOINTER) && IS_FUNC(x->next))
#define IS_FUNC(x) (IS_DECL(x) && DCL_TYPE(x) == FUNCTION)
#define IS_LONG(x) (IS_SPEC(x) && x->select.s._long)
#define IS_UNSIGNED(x) (IS_SPEC(x) && x->select.s._unsigned)
symbol *mainExists=newSymbol("main", 0);
mainExists->block=0;
- fprintf (of, "\t.area %s\n",port->mem.code_name);
+ fprintf (of, "\t.area %s\n",HOME_NAME);
fprintf (of, "\t.area GSINIT0 (CODE)\n");
fprintf (of, "\t.area %s\n",port->mem.static_name);
fprintf (of, "\t.area %s\n",port->mem.post_static_name);
+ fprintf (of, "\t.area %s\n",CODE_NAME);
fprintf (of, "\t.area %s\n",port->mem.xinit_name);
fprintf (of, "\t.area %s\n",port->mem.const_name);
fprintf (of, "\t.area %s\n",port->mem.data_name);
#include "gen.h"
char *aopLiteral (value * val, int offset);
+char *aopLiteralLong (value * val, int offset, int size);
extern int allocInfo;
/* this is the down and dirty file with all kinds of
sym->aop = aop = newAsmop (AOP_IMMD);
aop->aopu.aop_immd.aop_immd1 = Safe_calloc (1, strlen (sym->rname) + 1);
strcpy (aop->aopu.aop_immd.aop_immd1, sym->rname);
- aop->size = FPTRSIZE;
+ aop->size = getSize (sym->type);
return aop;
}
emitcode ("push", "acc");
}
else
+ {
emitcode ("push", "%s", l);
}
}
+}
/*-----------------------------------------------------------------*/
/* assignResultValue - also indicates if acc is in use afterwards */
}
/* make the call */
- emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
- OP_SYMBOL (IC_LEFT (ic))->rname :
- OP_SYMBOL (IC_LEFT (ic))->name));
+ if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
+ {
+ if (IFFUNC_CALLEESAVES(dtype))
+ {
+ werror (E_BANKED_WITH_CALLEESAVES);
+ }
+ else
+ {
+ char *l = (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
+ OP_SYMBOL (IC_LEFT (ic))->rname :
+ OP_SYMBOL (IC_LEFT (ic))->name);
+
+ emitcode ("mov", "r0,#%s", l);
+ emitcode ("mov", "r1,#(%s >> 8)", l);
+ emitcode ("mov", "r2,#(%s >> 16)", l);
+ emitcode ("lcall", "__sdcc_banked_call");
+ }
+ }
+ else
+ {
+ emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
+ OP_SYMBOL (IC_LEFT (ic))->rname :
+ OP_SYMBOL (IC_LEFT (ic))->name));
+ }
if (swapBanks)
{
genPcall (iCode * ic)
{
sym_link *dtype;
+ sym_link *etype;
symbol *rlbl = newiTempLabel (NULL);
// bool restoreBank=FALSE;
bool swapBanks = FALSE;
// need caution message to user here
}
- /* push the return address on to the stack */
- emitcode ("mov", "a,#%05d$", (rlbl->key + 100));
- emitcode ("push", "acc");
- emitcode ("mov", "a,#(%05d$ >> 8)", (rlbl->key + 100));
- emitcode ("push", "acc");
-
- /* now push the calling address */
- aopOp (IC_LEFT (ic), ic, FALSE);
+ etype = getSpec(dtype);
+ if (IS_LITERAL(etype))
+ {
+ /* if send set is not empty then assign */
+ if (_G.sendSet)
+ {
+ genSend(reverseSet(_G.sendSet));
+ _G.sendSet = NULL;
+ }
- pushSide (IC_LEFT (ic), FPTRSIZE);
+ if (swapBanks)
+ {
+ emitcode ("mov", "psw,#0x%02x",
+ ((FUNC_REGBANK(dtype)) << 3) & 0xff);
+ }
- freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
+ if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
+ {
+ if (IFFUNC_CALLEESAVES(dtype))
+ {
+ werror (E_BANKED_WITH_CALLEESAVES);
+ }
+ else
+ {
+ char *l = aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2);
- /* if send set is not empty the assign */
- if (_G.sendSet)
- {
- genSend(reverseSet(_G.sendSet));
- _G.sendSet = NULL;
+ emitcode ("mov", "r0,#%s", l);
+ emitcode ("mov", "r1,#(%s >> 8)", l);
+ emitcode ("mov", "r2,#(%s >> 16)", l);
+ emitcode ("lcall", "__sdcc_banked_call");
+ }
+ }
+ else
+ {
+ emitcode ("lcall", "%s", aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2));
+ }
}
+ else
+ {
+ if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
+ {
+ if (IFFUNC_CALLEESAVES(dtype))
+ {
+ werror (E_BANKED_WITH_CALLEESAVES);
+ }
+ else
+ {
+ aopOp (IC_LEFT (ic), ic, FALSE);
- if (swapBanks)
- {
- emitcode ("mov", "psw,#0x%02x",
- ((FUNC_REGBANK(dtype)) << 3) & 0xff);
- }
+ if (!swapBanks)
+ {
+ emitcode ("mov", "ar0,%s", aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
+ emitcode ("mov", "ar1,%s", aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
+ emitcode ("mov", "ar2,%s", aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
+ }
+ else
+ {
+ int reg = ((FUNC_REGBANK(dtype)) << 3) & 0xff;
+ emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
+ emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
+ emitcode ("mov", "0x%02x,%s", reg, aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
+ }
- /* make the call */
- emitcode ("ret", "");
- emitcode ("", "%05d$:", (rlbl->key + 100));
+ freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
+
+ /* if send set is not empty then assign */
+ if (_G.sendSet)
+ {
+ genSend(reverseSet(_G.sendSet));
+ _G.sendSet = NULL;
+ }
+
+ if (swapBanks)
+ {
+ emitcode ("mov", "psw,#0x%02x",
+ ((FUNC_REGBANK(dtype)) << 3) & 0xff);
+ }
+
+ /* make the call */
+ emitcode ("lcall", "__sdcc_banked_call");
+ }
+ }
+ else
+ {
+ /* push the return address on to the stack */
+ emitcode ("mov", "a,#%05d$", (rlbl->key + 100));
+ emitcode ("push", "acc");
+ emitcode ("mov", "a,#(%05d$ >> 8)", (rlbl->key + 100));
+ emitcode ("push", "acc");
+
+ /* now push the calling address */
+ aopOp (IC_LEFT (ic), ic, FALSE);
+
+ pushSide (IC_LEFT (ic), FPTRSIZE);
+ freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
+ /* if send set is not empty the assign */
+ if (_G.sendSet)
+ {
+ genSend(reverseSet(_G.sendSet));
+ _G.sendSet = NULL;
+ }
+
+ if (swapBanks)
+ {
+ emitcode ("mov", "psw,#0x%02x",
+ ((FUNC_REGBANK(dtype)) << 3) & 0xff);
+ }
+
+ /* make the call */
+ emitcode ("ret", "");
+ emitcode ("", "%05d$:", (rlbl->key + 100));
+ }
+ }
if (swapBanks)
{
emitcode ("mov", "psw,#0x%02x",
debugFile->writeEndFunction (currFunc, ic, 1);
}
- emitcode ("ret", "");
+ if (IFFUNC_ISBANKEDCALL (sym->type) && !SPEC_STAT(getSpec(sym->type)))
+ {
+ emitcode ("ljmp", "__sdcc_banked_ret");
+ }
+ else
+ {
+ emitcode ("ret", "");
+ }
}
if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
return FALSE;
- /* if the literal value of the right hand side
- is greater than 4 then it is not worth it */
- if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
- return FALSE;
+ icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
D(emitcode ("; genPlusIncr",""));
return TRUE;
}
+ /* if the literal value of the right hand side
+ is greater than 4 then it is not worth it */
+ if (icount > 4)
+ return FALSE;
+
/* if the sizes are greater than 1 then we cannot */
if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
AOP_SIZE (IC_LEFT (ic)) > 1)
static char *_mcs51_keywords[] =
{
"at",
+ "banked",
"bit",
"code",
"critical",
static void
_mcs51_genExtraAreas(FILE *of, bool hasMain)
{
- tfprintf (of, "\t!area\n", port->mem.code_name);
+ tfprintf (of, "\t!area\n", HOME_NAME);
tfprintf (of, "\t!area\n", "GSINIT0 (CODE)");
tfprintf (of, "\t!area\n", "GSINIT1 (CODE)");
tfprintf (of, "\t!area\n", "GSINIT2 (CODE)");
tfprintf (of, "\t!area\n", "GSINIT3 (CODE)");
tfprintf (of, "\t!area\n", "GSINIT4 (CODE)");
tfprintf (of, "\t!area\n", "GSINIT5 (CODE)");
+ tfprintf (of, "\t!area\n", STATIC_NAME);
+ tfprintf (of, "\t!area\n", port->mem.post_static_name);
+ tfprintf (of, "\t!area\n", CODE_NAME);
}
static void
"ISR function attribute 'shadowregs' following non-ISR function '%s'" },
{ W_SFR_ABSRANGE, ERROR_LEVEL_WARNING,
"absolute address for sfr '%s' probably out of range." },
+{ E_BANKED_WITH_CALLEESAVES, ERROR_LEVEL_ERROR,
+ "Both banked and callee-saves cannot be used together." },
};
/*
#define W_COMPLEMENT 180 /* ~bit can give unexpected results */
#define E_SHADOWREGS_NO_ISR 181 /* shadowregs keyword following non-ISR function */
#define W_SFR_ABSRANGE 182 /* sfr at address out of range */
+#define E_BANKED_WITH_CALLEESAVES 183 /* banked and callee-saves mixed */
#define MAX_ERROR_WARNING 256 /* size of disable warnings array */