gbdk-releases/sdcc/src/ds390/gen.c
2015-01-10 16:25:09 +01:00

10653 lines
266 KiB
C

/*-------------------------------------------------------------------------
gen.c - source file for code generation for DS80C390
Written By - Sandeep Dutta . sandeep.dutta@usa.net (1998)
and - Jean-Louis VERN.jlvern@writeme.com (1999)
Bug Fixes - Wojciech Stryjewski wstryj1@tiger.lsu.edu (1999 v2.1.9a)
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
In other words, you are welcome to use, share and improve this program.
You are forbidden to forbid anyone else to use, share and improve
what you give them. Help stamp out software-hoarding!
-------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <common.h>
#include "ralloc.h"
#include "gen.h"
#include "SDCCglobl.h"
#include "newalloc.h"
#ifdef HAVE_SYS_ISA_DEFS_H
#include <sys/isa_defs.h>
#else
#ifdef HAVE_MACHINE_ENDIAN_H
#include <machine/endian.h>
#else
#ifdef HAVE_ENDIAN_H
#include <endian.h>
#else
#if !defined(__BORLANDC__) && !defined(_MSC_VER) && !defined(__MINGW32__) && !defined(__CYGWIN__)
#warning "Cannot determine ENDIANESS of this machine assuming LITTLE_ENDIAN"
#warning "If you running sdcc on an INTEL 80x86 Platform you are okay"
#endif
#endif
#endif
#endif
#define BETTER_LITERAL_SHIFT
char *aopLiteral (value * val, int offset);
/* this is the down and dirty file with all kinds of
kludgy & hacky stuff. This is what it is all about
CODE GENERATION for a specific MCU . some of the
routines may be reusable, will have to see */
static char *zero = "#0x00";
static char *one = "#0x01";
static char *spname;
#define D(x) x
#define TR_DPTR(s) if (options.model != MODEL_FLAT24) { emitcode(";", " Use_DPTR1 %s ", s); }
#define TR_AP(s) if (options.model != MODEL_FLAT24) { emitcode(";", " Use_AP %s ", s); }
unsigned fReturnSizeDS390 = 5; /* shared with ralloc.c */
static char *fReturn24[] =
{"dpl", "dph", "dpx", "b", "a"};
static char *fReturn16[] =
{"dpl", "dph", "b", "a"};
static char **fReturn = fReturn24;
static char *accUse[] =
{"a", "b"};
static short rbank = -1;
static struct
{
short r0Pushed;
short r1Pushed;
short accInUse;
short inLine;
short debugLine;
short nRegsSaved;
set *sendSet;
}
_G;
static void saveRBank (int, iCode *, bool);
#define RESULTONSTACK(x) \
(IC_RESULT(x) && IC_RESULT(x)->aop && \
IC_RESULT(x)->aop->type == AOP_STK )
/* #define MOVA(x) if (strcmp(x,"a") && strcmp(x,"acc")) emitcode("mov","a,%s",x); */
#define MOVA(x) { char *_mova_tmp = strdup(x); \
if (strcmp(_mova_tmp,"a") && strcmp(_mova_tmp,"acc")) \
{ \
emitcode("mov","a,%s",_mova_tmp); \
} \
free(_mova_tmp); \
}
#define CLRC emitcode("clr","c")
#define SETC emitcode("setb","c")
// A scratch register which will be used to hold
// result bytes from operands in far space via DPTR2.
#define DP2_RESULT_REG "ap"
static lineNode *lineHead = NULL;
static lineNode *lineCurr = NULL;
static unsigned char SLMask[] =
{0xFF, 0xFE, 0xFC, 0xF8, 0xF0,
0xE0, 0xC0, 0x80, 0x00};
static unsigned char SRMask[] =
{0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
0x07, 0x03, 0x01, 0x00};
#define LSB 0
#define MSB16 1
#define MSB24 2
#define MSB32 3
/*-----------------------------------------------------------------*/
/* emitcode - writes the code into a file : for now it is simple */
/*-----------------------------------------------------------------*/
static void
emitcode (char *inst, char *fmt,...)
{
va_list ap;
char lb[INITIAL_INLINEASM];
char *lbp = lb;
va_start (ap, fmt);
if (inst && *inst)
{
if (fmt && *fmt)
sprintf (lb, "%s\t", inst);
else
sprintf (lb, "%s", inst);
vsprintf (lb + (strlen (lb)), fmt, ap);
}
else
vsprintf (lb, fmt, ap);
while (isspace (*lbp))
lbp++;
if (lbp && *lbp)
lineCurr = (lineCurr ?
connectLine (lineCurr, newLineNode (lb)) :
(lineHead = newLineNode (lb)));
lineCurr->isInline = _G.inLine;
lineCurr->isDebug = _G.debugLine;
va_end (ap);
}
/*-----------------------------------------------------------------*/
/* getFreePtr - returns r0 or r1 whichever is free or can be pushed */
/*-----------------------------------------------------------------*/
static regs *
getFreePtr (iCode * ic, asmop ** aopp, bool result)
{
bool r0iu = FALSE, r1iu = FALSE;
bool r0ou = FALSE, r1ou = FALSE;
/* the logic: if r0 & r1 used in the instruction
then we are in trouble otherwise */
/* first check if r0 & r1 are used by this
instruction, in which case we are in trouble */
r0iu = bitVectBitValue (ic->rUsed, R0_IDX);
r1iu = bitVectBitValue (ic->rUsed, R1_IDX);
if (r0iu && r1iu) {
goto endOfWorld;
}
r0ou = bitVectBitValue (ic->rMask, R0_IDX);
r1ou = bitVectBitValue (ic->rMask, R1_IDX);
/* if no usage of r0 then return it */
if (!r0iu && !r0ou)
{
ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
(*aopp)->type = AOP_R0;
return (*aopp)->aopu.aop_ptr = ds390_regWithIdx (R0_IDX);
}
/* if no usage of r1 then return it */
if (!r1iu && !r1ou)
{
ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
(*aopp)->type = AOP_R1;
return (*aopp)->aopu.aop_ptr = ds390_regWithIdx (R1_IDX);
}
/* now we know they both have usage */
/* if r0 not used in this instruction */
if (!r0iu)
{
/* push it if not already pushed */
if (!_G.r0Pushed)
{
emitcode ("push", "%s",
ds390_regWithIdx (R0_IDX)->dname);
_G.r0Pushed++;
}
ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
(*aopp)->type = AOP_R0;
return (*aopp)->aopu.aop_ptr = ds390_regWithIdx (R0_IDX);
}
/* if r1 not used then */
if (!r1iu)
{
/* push it if not already pushed */
if (!_G.r1Pushed)
{
emitcode ("push", "%s",
ds390_regWithIdx (R1_IDX)->dname);
_G.r1Pushed++;
}
ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
(*aopp)->type = AOP_R1;
return ds390_regWithIdx (R1_IDX);
}
endOfWorld:
/* I said end of world but not quite end of world yet */
/* if this is a result then we can push it on the stack */
if (result)
{
(*aopp)->type = AOP_STK;
return NULL;
}
/* other wise this is true end of the world */
werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
"getFreePtr should never reach here");
exit (1);
}
/*-----------------------------------------------------------------*/
/* newAsmop - creates a new asmOp */
/*-----------------------------------------------------------------*/
static asmop *
newAsmop (short type)
{
asmop *aop;
aop = Safe_calloc (1, sizeof (asmop));
aop->type = type;
return aop;
}
static int _currentDPS; /* Current processor DPS. */
static int _desiredDPS; /* DPS value compiler thinks we should be using. */
static int _lazyDPS = 0; /* if non-zero, we are doing lazy evaluation of DPS changes. */
/*-----------------------------------------------------------------*/
/* genSetDPTR: generate code to select which DPTR is in use (zero */
/* selects standard DPTR (DPL/DPH/DPX), non-zero selects DS390 */
/* alternate DPTR (DPL1/DPH1/DPX1). */
/*-----------------------------------------------------------------*/
static void
genSetDPTR (int n)
{
/* If we are doing lazy evaluation, simply note the desired
* change, but don't emit any code yet.
*/
if (_lazyDPS)
{
_desiredDPS = n;
return;
}
if (!n)
{
emitcode ("mov", "dps, #0x00");
}
else
{
TR_DPTR("#1");
emitcode ("mov", "dps, #0x01");
}
}
/*-----------------------------------------------------------------*/
/* _startLazyDPSEvaluation: call to start doing lazy DPS evaluation */
/* */
/* Any code that operates on DPTR (NB: not on the individual */
/* components, like DPH) *must* call _flushLazyDPS() before using */
/* DPTR within a lazy DPS evaluation block. */
/* */
/* Note that aopPut and aopGet already contain the proper calls to */
/* _flushLazyDPS, so it is safe to use these calls within a lazy */
/* DPS evaluation block. */
/* */
/* Also, _flushLazyDPS must be called before any flow control */
/* operations that could potentially branch out of the block. */
/* */
/* Lazy DPS evaluation is simply an optimization (though an */
/* important one), so if in doubt, leave it out. */
/*-----------------------------------------------------------------*/
static void
_startLazyDPSEvaluation (void)
{
_currentDPS = 0;
_desiredDPS = 0;
#ifdef BETTER_LITERAL_SHIFT
_lazyDPS++;
#else
_lazyDPS = 1;
#endif
}
/*-----------------------------------------------------------------*/
/* _flushLazyDPS: emit code to force the actual DPS setting to the */
/* desired one. Call before using DPTR within a lazy DPS evaluation */
/* block. */
/*-----------------------------------------------------------------*/
static void
_flushLazyDPS (void)
{
if (!_lazyDPS)
{
/* nothing to do. */
return;
}
if (_desiredDPS != _currentDPS)
{
if (_desiredDPS)
{
emitcode ("inc", "dps");
}
else
{
emitcode ("dec", "dps");
}
_currentDPS = _desiredDPS;
}
}
/*-----------------------------------------------------------------*/
/* _endLazyDPSEvaluation: end lazy DPS evaluation block. */
/* */
/* Forces us back to the safe state (standard DPTR selected). */
/*-----------------------------------------------------------------*/
static void
_endLazyDPSEvaluation (void)
{
#ifdef BETTER_LITERAL_SHIFT
_lazyDPS--;
#else
_lazyDPS = 0;
#endif
if (!_lazyDPS)
{
if (_currentDPS)
{
genSetDPTR (0);
_flushLazyDPS ();
}
_currentDPS = 0;
_desiredDPS = 0;
}
}
/*-----------------------------------------------------------------*/
/* pointerCode - returns the code for a pointer type */
/*-----------------------------------------------------------------*/
static int
pointerCode (sym_link * etype)
{
return PTR_TYPE (SPEC_OCLS (etype));
}
/*-----------------------------------------------------------------*/
/* aopForSym - for a true symbol */
/*-----------------------------------------------------------------*/
static asmop *
aopForSym (iCode * ic, symbol * sym, bool result, bool useDP2)
{
asmop *aop;
memmap *space = SPEC_OCLS (sym->etype);
/* if already has one */
if (sym->aop)
return sym->aop;
/* assign depending on the storage class */
/* if it is on the stack or indirectly addressable */
/* space we need to assign either r0 or r1 to it */
if ((sym->onStack && !options.stack10bit) || sym->iaccess)
{
sym->aop = aop = newAsmop (0);
aop->aopu.aop_ptr = getFreePtr (ic, &aop, result);
aop->size = getSize (sym->type);
/* now assign the address of the variable to
the pointer register */
if (aop->type != AOP_STK)
{
if (sym->onStack)
{
if (_G.accInUse)
emitcode ("push", "acc");
emitcode ("mov", "a,_bp");
emitcode ("add", "a,#0x%02x",
((sym->stack < 0) ?
((char) (sym->stack - _G.nRegsSaved)) :
((char) sym->stack)) & 0xff);
emitcode ("mov", "%s,a",
aop->aopu.aop_ptr->name);
if (_G.accInUse)
emitcode ("pop", "acc");
}
else
emitcode ("mov", "%s,#%s",
aop->aopu.aop_ptr->name,
sym->rname);
aop->paged = space->paged;
}
else
aop->aopu.aop_stk = sym->stack;
return aop;
}
if (sym->onStack && options.stack10bit)
{
/* It's on the 10 bit stack, which is located in
* far data space.
*/
if (_G.accInUse)
emitcode ("push", "acc");
emitcode ("mov", "a,_bp");
emitcode ("add", "a,#0x%02x",
((sym->stack < 0) ?
((char) (sym->stack - _G.nRegsSaved)) :
((char) sym->stack)) & 0xff);
if (useDP2)
{
if (options.model == MODEL_FLAT24)
emitcode ("mov", "dpx1,#0x40");
TR_DPTR("#2");
emitcode ("mov", "dph1,#0x00");
emitcode ("mov", "dpl1, a");
}
else
{
if (options.model == MODEL_FLAT24)
emitcode ("mov", "dpx,#0x40");
emitcode ("mov", "dph,#0x00");
emitcode ("mov", "dpl, a");
}
if (_G.accInUse)
emitcode ("pop", "acc");
sym->aop = aop = newAsmop ((short) (useDP2 ? AOP_DPTR2 : AOP_DPTR));
aop->size = getSize (sym->type);
return aop;
}
/* if in bit space */
if (IN_BITSPACE (space))
{
sym->aop = aop = newAsmop (AOP_CRY);
aop->aopu.aop_dir = sym->rname;
aop->size = getSize (sym->type);
return aop;
}
/* if it is in direct space */
if (IN_DIRSPACE (space))
{
sym->aop = aop = newAsmop (AOP_DIR);
aop->aopu.aop_dir = sym->rname;
aop->size = getSize (sym->type);
return aop;
}
/* special case for a function */
if (IS_FUNC (sym->type))
{
sym->aop = aop = newAsmop (AOP_IMMD);
aop->aopu.aop_immd = Safe_calloc (1, strlen (sym->rname) + 1);
strcpy (aop->aopu.aop_immd, sym->rname);
aop->size = FPTRSIZE;
return aop;
}
/* only remaining is far space */
/* in which case DPTR gets the address */
sym->aop = aop = newAsmop ((short) (useDP2 ? AOP_DPTR2 : AOP_DPTR));
if (useDP2)
{
genSetDPTR (1);
_flushLazyDPS ();
emitcode ("mov", "dptr,#%s", sym->rname);
genSetDPTR (0);
}
else
{
emitcode ("mov", "dptr,#%s", sym->rname);
}
aop->size = getSize (sym->type);
/* if it is in code space */
if (IN_CODESPACE (space))
aop->code = 1;
return aop;
}
/*-----------------------------------------------------------------*/
/* aopForRemat - rematerialzes an object */
/*-----------------------------------------------------------------*/
static asmop *
aopForRemat (symbol * sym)
{
iCode *ic = sym->rematiCode;
asmop *aop = newAsmop (AOP_IMMD);
int val = 0;
for (;;)
{
if (ic->op == '+')
val += (int) operandLitValue (IC_RIGHT (ic));
else if (ic->op == '-')
val -= (int) operandLitValue (IC_RIGHT (ic));
else
break;
ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
}
if (val)
sprintf (buffer, "(%s %c 0x%04x)",
OP_SYMBOL (IC_LEFT (ic))->rname,
val >= 0 ? '+' : '-',
abs (val) & 0xffff);
else
strcpy (buffer, OP_SYMBOL (IC_LEFT (ic))->rname);
aop->aopu.aop_immd = Safe_calloc (1, strlen (buffer) + 1);
strcpy (aop->aopu.aop_immd, buffer);
return aop;
}
/*-----------------------------------------------------------------*/
/* regsInCommon - two operands have some registers in common */
/*-----------------------------------------------------------------*/
static bool
regsInCommon (operand * op1, operand * op2)
{
symbol *sym1, *sym2;
int i;
/* if they have registers in common */
if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
return FALSE;
sym1 = OP_SYMBOL (op1);
sym2 = OP_SYMBOL (op2);
if (sym1->nRegs == 0 || sym2->nRegs == 0)
return FALSE;
for (i = 0; i < sym1->nRegs; i++)
{
int j;
if (!sym1->regs[i])
continue;
for (j = 0; j < sym2->nRegs; j++)
{
if (!sym2->regs[j])
continue;
if (sym2->regs[j] == sym1->regs[i])
return TRUE;
}
}
return FALSE;
}
/*-----------------------------------------------------------------*/
/* operandsEqu - equivalent */
/*-----------------------------------------------------------------*/
static bool
operandsEqu (operand * op1, operand * op2)
{
symbol *sym1, *sym2;
/* if they not symbols */
if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
return FALSE;
sym1 = OP_SYMBOL (op1);
sym2 = OP_SYMBOL (op2);
/* if both are itemps & one is spilt
and the other is not then false */
if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
sym1->isspilt != sym2->isspilt)
return FALSE;
/* if they are the same */
if (sym1 == sym2)
return TRUE;
if (strcmp (sym1->rname, sym2->rname) == 0)
return TRUE;
/* if left is a tmp & right is not */
if (IS_ITEMP (op1) &&
!IS_ITEMP (op2) &&
sym1->isspilt &&
(sym1->usl.spillLoc == sym2))
return TRUE;
if (IS_ITEMP (op2) &&
!IS_ITEMP (op1) &&
sym2->isspilt &&
sym1->level > 0 &&
(sym2->usl.spillLoc == sym1))
return TRUE;
return FALSE;
}
/*-----------------------------------------------------------------*/
/* sameRegs - two asmops have the same registers */
/*-----------------------------------------------------------------*/
static bool
sameRegs (asmop * aop1, asmop * aop2)
{
int i;
if (aop1 == aop2)
{
if (aop1->type == AOP_DPTR || aop1->type == AOP_DPTR2)
{
return FALSE;
}
return TRUE;
}
if (aop1->type != AOP_REG ||
aop2->type != AOP_REG)
return FALSE;
if (aop1->size != aop2->size)
return FALSE;
for (i = 0; i < aop1->size; i++)
if (aop1->aopu.aop_reg[i] !=
aop2->aopu.aop_reg[i])
return FALSE;
return TRUE;
}
/*-----------------------------------------------------------------*/
/* aopOp - allocates an asmop for an operand : */
/*-----------------------------------------------------------------*/
static void
aopOp (operand * op, iCode * ic, bool result, bool useDP2)
{
asmop *aop;
symbol *sym;
int i;
if (!op)
return;
/* if this a literal */
if (IS_OP_LITERAL (op))
{
op->aop = aop = newAsmop (AOP_LIT);
aop->aopu.aop_lit = op->operand.valOperand;
aop->size = getSize (operandType (op));
return;
}
/* if already has a asmop then continue */
if (op->aop)
return;
/* if the underlying symbol has a aop */
if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
{
op->aop = OP_SYMBOL (op)->aop;
return;
}
/* if this is a true symbol */
if (IS_TRUE_SYMOP (op))
{
op->aop = aopForSym (ic, OP_SYMBOL (op), result, useDP2);
return;
}
/* this is a temporary : this has
only four choices :
a) register
b) spillocation
c) rematerialize
d) conditional
e) can be a return use only */
sym = OP_SYMBOL (op);
/* if the type is a conditional */
if (sym->regType == REG_CND)
{
aop = op->aop = sym->aop = newAsmop (AOP_CRY);
aop->size = 0;
return;
}
/* if it is spilt then two situations
a) is rematerialize
b) has a spill location */
if (sym->isspilt || sym->nRegs == 0)
{
/* rematerialize it NOW */
if (sym->remat)
{
sym->aop = op->aop = aop =
aopForRemat (sym);
aop->size = getSize (sym->type);
return;
}
if (sym->accuse)
{
int i;
aop = op->aop = sym->aop = newAsmop (AOP_ACC);
aop->size = getSize (sym->type);
for (i = 0; i < 2; i++)
aop->aopu.aop_str[i] = accUse[i];
return;
}
if (sym->ruonly)
{
int i;
if (useDP2)
{
/* a AOP_STR uses DPTR, but DPTR is already in use;
* we're just hosed.
*/
fprintf (stderr, "*** Internal error: AOP_STR with DPTR in use!\n");
}
aop = op->aop = sym->aop = newAsmop (AOP_STR);
aop->size = getSize (sym->type);
for (i = 0; i < (int) fReturnSizeDS390; i++)
aop->aopu.aop_str[i] = fReturn[i];
return;
}
/* else spill location */
sym->aop = op->aop = aop =
aopForSym (ic, sym->usl.spillLoc, result, useDP2);
aop->size = getSize (sym->type);
return;
}
/* must be in a register */
sym->aop = op->aop = aop = newAsmop (AOP_REG);
aop->size = sym->nRegs;
for (i = 0; i < sym->nRegs; i++)
aop->aopu.aop_reg[i] = sym->regs[i];
}
/*-----------------------------------------------------------------*/
/* freeAsmop - free up the asmop given to an operand */
/*----------------------------------------------------------------*/
static void
freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
{
asmop *aop;
if (!op)
aop = aaop;
else
aop = op->aop;
if (!aop)
return;
if (aop->freed)
goto dealloc;
aop->freed = 1;
/* depending on the asmop type only three cases need work AOP_RO
, AOP_R1 && AOP_STK */
switch (aop->type)
{
case AOP_R0:
if (_G.r0Pushed)
{
if (pop)
{
emitcode ("pop", "ar0");
_G.r0Pushed--;
}
}
bitVectUnSetBit (ic->rUsed, R0_IDX);
break;
case AOP_R1:
if (_G.r1Pushed)
{
if (pop)
{
emitcode ("pop", "ar1");
_G.r1Pushed--;
}
}
bitVectUnSetBit (ic->rUsed, R1_IDX);
break;
case AOP_STK:
{
int sz = aop->size;
int stk = aop->aopu.aop_stk + aop->size;
bitVectUnSetBit (ic->rUsed, R0_IDX);
bitVectUnSetBit (ic->rUsed, R1_IDX);
getFreePtr (ic, &aop, FALSE);
if (options.stack10bit)
{
/* I'm not sure what to do here yet... */
/* #STUB */
fprintf (stderr,
"*** Warning: probably generating bad code for "
"10 bit stack mode.\n");
}
if (stk)
{
emitcode ("mov", "a,_bp");
emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
}
else
{
emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
}
while (sz--)
{
emitcode ("pop", "acc");
emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
if (!sz)
break;
emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
}
op->aop = aop;
freeAsmop (op, NULL, ic, TRUE);
if (_G.r0Pushed)
{
emitcode ("pop", "ar0");
_G.r0Pushed--;
}
if (_G.r1Pushed)
{
emitcode ("pop", "ar1");
_G.r1Pushed--;
}
}
}
dealloc:
/* all other cases just dealloc */
if (op)
{
op->aop = NULL;
if (IS_SYMOP (op))
{
OP_SYMBOL (op)->aop = NULL;
/* if the symbol has a spill */
if (SPIL_LOC (op))
SPIL_LOC (op)->aop = NULL;
}
}
}
/*------------------------------------------------------------------*/
/* aopGet - for fetching value of the aop */
/* */
/* Set canClobberACC if you are sure it is OK to clobber the value */
/* in the accumulator. Set it FALSE otherwise; FALSE is always safe, */
/* just less efficient. */
/*------------------------------------------------------------------*/
static char *
aopGet (asmop * aop,
int offset,
bool bit16,
bool dname,
bool canClobberACC)
{
char *s = buffer;
char *rs;
/* offset is greater than
size then zero */
if (offset > (aop->size - 1) &&
aop->type != AOP_LIT)
return zero;
/* depending on type */
switch (aop->type)
{
case AOP_R0:
case AOP_R1:
/* if we need to increment it */
while (offset > aop->coff)
{
emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
aop->coff++;
}
while (offset < aop->coff)
{
emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
aop->coff--;
}
aop->coff = offset;
if (aop->paged)
{
emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
return (dname ? "acc" : "a");
}
sprintf (s, "@%s", aop->aopu.aop_ptr->name);
rs = Safe_calloc (1, strlen (s) + 1);
strcpy (rs, s);
return rs;
case AOP_DPTR:
case AOP_DPTR2:
if (aop->type == AOP_DPTR2)
{
genSetDPTR (1);
if (!canClobberACC)
{
TR_AP("#1");
emitcode ("xch", "a, %s", DP2_RESULT_REG);
}
}
_flushLazyDPS ();
while (offset > aop->coff)
{
emitcode ("inc", "dptr");
aop->coff++;
}
while (offset < aop->coff)
{
emitcode ("lcall", "__decdptr");
aop->coff--;
}
aop->coff = offset;
if (aop->code)
{
emitcode ("clr", "a");
emitcode ("movc", "a,@a+dptr");
}
else
{
emitcode ("movx", "a,@dptr");
}
if (aop->type == AOP_DPTR2)
{
genSetDPTR (0);
if (!canClobberACC)
{
TR_AP("#2");
emitcode ("xch", "a, %s", DP2_RESULT_REG);
return DP2_RESULT_REG;
}
}
return (dname ? "acc" : "a");
case AOP_IMMD:
if (bit16)
sprintf (s, "#%s", aop->aopu.aop_immd);
else if (offset)
sprintf (s, "#(%s >> %d)",
aop->aopu.aop_immd,
offset * 8);
else
sprintf (s, "#%s",
aop->aopu.aop_immd);
rs = Safe_calloc (1, strlen (s) + 1);
strcpy (rs, s);
return rs;
case AOP_DIR:
if (offset)
sprintf (s, "(%s + %d)",
aop->aopu.aop_dir,
offset);
else
sprintf (s, "%s", aop->aopu.aop_dir);
rs = Safe_calloc (1, strlen (s) + 1);
strcpy (rs, s);
return rs;
case AOP_REG:
if (dname)
return aop->aopu.aop_reg[offset]->dname;
else
return aop->aopu.aop_reg[offset]->name;
case AOP_CRY:
emitcode ("clr", "a");
emitcode ("mov", "c,%s", aop->aopu.aop_dir);
emitcode ("rlc", "a");
return (dname ? "acc" : "a");
case AOP_ACC:
if (!offset && dname)
return "acc";
return aop->aopu.aop_str[offset];
case AOP_LIT:
return aopLiteral (aop->aopu.aop_lit, offset);
case AOP_STR:
aop->coff = offset;
if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
dname)
return "acc";
return aop->aopu.aop_str[offset];
}
werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
"aopget got unsupported aop->type");
exit (1);
}
/*-----------------------------------------------------------------*/
/* aopPut - puts a string for a aop */
/*-----------------------------------------------------------------*/
static void
aopPut (asmop * aop, char *s, int offset)
{
char *d = buffer;
if (aop->size && offset > (aop->size - 1))
{
werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
"aopPut got offset > aop->size");
exit (1);
}
/* will assign value to value */
/* depending on where it is ofcourse */
switch (aop->type)
{
case AOP_DIR:
if (offset)
sprintf (d, "(%s + %d)",
aop->aopu.aop_dir, offset);
else
sprintf (d, "%s", aop->aopu.aop_dir);
if (strcmp (d, s))
emitcode ("mov", "%s,%s", d, s);
break;
case AOP_REG:
if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
{
if (*s == '@' ||
strcmp (s, "r0") == 0 ||
strcmp (s, "r1") == 0 ||
strcmp (s, "r2") == 0 ||
strcmp (s, "r3") == 0 ||
strcmp (s, "r4") == 0 ||
strcmp (s, "r5") == 0 ||
strcmp (s, "r6") == 0 ||
strcmp (s, "r7") == 0)
emitcode ("mov", "%s,%s",
aop->aopu.aop_reg[offset]->dname, s);
else
emitcode ("mov", "%s,%s",
aop->aopu.aop_reg[offset]->name, s);
}
break;
case AOP_DPTR:
case AOP_DPTR2:
if (aop->type == AOP_DPTR2)
{
genSetDPTR (1);
}
_flushLazyDPS ();
if (aop->code)
{
werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
"aopPut writting to code space");
exit (1);
}
while (offset > aop->coff)
{
aop->coff++;
emitcode ("inc", "dptr");
}
while (offset < aop->coff)
{
aop->coff--;
emitcode ("lcall", "__decdptr");
}
aop->coff = offset;
/* if not in accumulater */
MOVA (s);
emitcode ("movx", "@dptr,a");
if (aop->type == AOP_DPTR2)
{
genSetDPTR (0);
}
break;
case AOP_R0:
case AOP_R1:
while (offset > aop->coff)
{
aop->coff++;
emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
}
while (offset < aop->coff)
{
aop->coff--;
emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
}
aop->coff = offset;
if (aop->paged)
{
MOVA (s);
emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
}
else if (*s == '@')
{
MOVA (s);
emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
}
else if (strcmp (s, "r0") == 0 ||
strcmp (s, "r1") == 0 ||
strcmp (s, "r2") == 0 ||
strcmp (s, "r3") == 0 ||
strcmp (s, "r4") == 0 ||
strcmp (s, "r5") == 0 ||
strcmp (s, "r6") == 0 ||
strcmp (s, "r7") == 0)
{
char buffer[10];
sprintf (buffer, "a%s", s);
emitcode ("mov", "@%s,%s",
aop->aopu.aop_ptr->name, buffer);
}
else
emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
break;
case AOP_STK:
if (strcmp (s, "a") == 0)
emitcode ("push", "acc");
else
emitcode ("push", "%s", s);
break;
case AOP_CRY:
/* if bit variable */
if (!aop->aopu.aop_dir)
{
emitcode ("clr", "a");
emitcode ("rlc", "a");
}
else
{
if (s == zero)
emitcode ("clr", "%s", aop->aopu.aop_dir);
else if (s == one)
emitcode ("setb", "%s", aop->aopu.aop_dir);
else if (!strcmp (s, "c"))
emitcode ("mov", "%s,c", aop->aopu.aop_dir);
else
{
if (strcmp (s, "a"))
{
MOVA (s);
}
{
symbol *lbl = newiTempLabel (NULL);
emitcode ("clr", "c");
emitcode ("jz", "%05d$", lbl->key + 100);
emitcode ("cpl", "c");
emitcode ("", "%05d$:", lbl->key + 100);
emitcode ("mov", "%s,c", aop->aopu.aop_dir);
}
}
}
break;
case AOP_STR:
aop->coff = offset;
if (strcmp (aop->aopu.aop_str[offset], s))
emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
break;
case AOP_ACC:
aop->coff = offset;
if (!offset && (strcmp (s, "acc") == 0))
break;
if (strcmp (aop->aopu.aop_str[offset], s))
emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
break;
default:
werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
"aopPut got unsupported aop->type");
exit (1);
}
}
/*--------------------------------------------------------------------*/
/* reAdjustPreg - points a register back to where it should (coff==0) */
/*--------------------------------------------------------------------*/
static void
reAdjustPreg (asmop * aop)
{
if ((aop->coff==0) || (aop->size <= 1)) {
return;
}
switch (aop->type)
{
case AOP_R0:
case AOP_R1:
while (aop->coff--)
emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
break;
case AOP_DPTR:
case AOP_DPTR2:
if (aop->type == AOP_DPTR2)
{
genSetDPTR (1);
_flushLazyDPS ();
}
while (aop->coff--)
{
emitcode ("lcall", "__decdptr");
}
if (aop->type == AOP_DPTR2)
{
genSetDPTR (0);
}
break;
}
aop->coff=0;
}
#define AOP(op) op->aop
#define AOP_TYPE(op) AOP(op)->type
#define AOP_SIZE(op) AOP(op)->size
#define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_R1 || \
AOP_TYPE(x) == AOP_R0))
#define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY || \
AOP_TYPE(x) == AOP_DPTR || AOP_TYPE(x) == AOP_DPTR2 || \
AOP(x)->paged))
#define AOP_INPREG(x) (x && (x->type == AOP_REG && \
(x->aopu.aop_reg[0] == ds390_regWithIdx(R0_IDX) || \
x->aopu.aop_reg[0] == ds390_regWithIdx(R1_IDX) )))
/* Workaround for DS80C390 bug: div ab may return bogus results
* if A is accessed in instruction immediately before the div.
*
* Will be fixed in B4 rev of processor, Dallas claims.
*/
#define LOAD_AB_FOR_DIV(LEFT, RIGHT, L) \
if (!AOP_NEEDSACC(RIGHT)) \
{ \
/* We can load A first, then B, since \
* B (the RIGHT operand) won't clobber A, \
* thus avoiding touching A right before the div. \
*/ \
D(emitcode(";", "DS80C390 div bug: rearranged ops.");); \
L = aopGet(AOP(LEFT),0,FALSE,FALSE,TRUE); \
MOVA(L); \
emitcode("mov","b,%s",aopGet(AOP(RIGHT),0,FALSE,FALSE,FALSE));\
} \
else \
{ \
/* Just stuff in a nop after loading A. */ \
emitcode("mov","b,%s",aopGet(AOP(RIGHT),0,FALSE,FALSE,FALSE));\
L = aopGet(AOP(LEFT),0,FALSE,FALSE,TRUE); \
MOVA(L); \
emitcode("nop", "; workaround for DS80C390 div bug."); \
}
/*-----------------------------------------------------------------*/
/* genNotFloat - generates not for float operations */
/*-----------------------------------------------------------------*/
static void
genNotFloat (operand * op, operand * res)
{
int size, offset;
char *l;
symbol *tlbl;
D (emitcode (";", "genNotFloat ");
);
/* we will put 127 in the first byte of
the result */
aopPut (AOP (res), "#127", 0);
size = AOP_SIZE (op) - 1;
offset = 1;
_startLazyDPSEvaluation ();
l = aopGet (op->aop, offset++, FALSE, FALSE, TRUE);
MOVA (l);
while (size--)
{
emitcode ("orl", "a,%s",
aopGet (op->aop,
offset++, FALSE, FALSE, FALSE));
}
_endLazyDPSEvaluation ();
tlbl = newiTempLabel (NULL);
aopPut (res->aop, one, 1);
emitcode ("jz", "%05d$", (tlbl->key + 100));
aopPut (res->aop, zero, 1);
emitcode ("", "%05d$:", (tlbl->key + 100));
size = res->aop->size - 2;
offset = 2;
/* put zeros in the rest */
while (size--)
aopPut (res->aop, zero, offset++);
}
/*-----------------------------------------------------------------*/
/* opIsGptr: returns non-zero if the passed operand is */
/* a generic pointer type. */
/*-----------------------------------------------------------------*/
static int
opIsGptr (operand * op)
{
sym_link *type = operandType (op);
if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
{
return 1;
}
return 0;
}
/*-----------------------------------------------------------------*/
/* getDataSize - get the operand data size */
/*-----------------------------------------------------------------*/
static int
getDataSize (operand * op)
{
int size;
size = AOP_SIZE (op);
if (size == GPTRSIZE)
{
sym_link *type = operandType (op);
if (IS_GENPTR (type))
{
/* generic pointer; arithmetic operations
* should ignore the high byte (pointer type).
*/
size--;
}
}
return size;
}
/*-----------------------------------------------------------------*/
/* outAcc - output Acc */
/*-----------------------------------------------------------------*/
static void
outAcc (operand * result)
{
int size, offset;
size = getDataSize (result);
if (size)
{
aopPut (AOP (result), "a", 0);
size--;
offset = 1;
/* unsigned or positive */
while (size--)
{
aopPut (AOP (result), zero, offset++);
}
}
}
/*-----------------------------------------------------------------*/
/* outBitC - output a bit C */
/*-----------------------------------------------------------------*/
static void
outBitC (operand * result)
{
/* if the result is bit */
if (AOP_TYPE (result) == AOP_CRY)
{
aopPut (AOP (result), "c", 0);
}
else
{
emitcode ("clr", "a");
emitcode ("rlc", "a");
outAcc (result);
}
}
/*-----------------------------------------------------------------*/
/* toBoolean - emit code for orl a,operator(sizeop) */
/*-----------------------------------------------------------------*/
static void
toBoolean (operand * oper)
{
int size = AOP_SIZE (oper) - 1;
int offset = 1;
bool usedB = FALSE;
/* The generic part of a generic pointer should
* not participate in it's truth value.
*
* i.e. 0x10000000 is zero.
*/
if (opIsGptr (oper))
{
D (emitcode (";", "toBoolean: generic ptr special case.");
);
size--;
}
_startLazyDPSEvaluation ();
if (AOP_NEEDSACC (oper) && size)
{
usedB = TRUE;
emitcode ("push", "b");
emitcode ("mov", "b, %s", aopGet (AOP (oper), 0, FALSE, FALSE, FALSE));
}
else
{
MOVA (aopGet (AOP (oper), 0, FALSE, FALSE, TRUE));
}
while (size--)
{
if (usedB)
{
emitcode ("orl", "b,%s", aopGet (AOP (oper), offset++, FALSE, FALSE, FALSE));
}
else
{
emitcode ("orl", "a,%s", aopGet (AOP (oper), offset++, FALSE, FALSE, FALSE));
}
}
_endLazyDPSEvaluation ();
if (usedB)
{
emitcode ("mov", "a,b");
emitcode ("pop", "b");
}
}
/*-----------------------------------------------------------------*/
/* genNot - generate code for ! operation */
/*-----------------------------------------------------------------*/
static void
genNot (iCode * ic)
{
symbol *tlbl;
sym_link *optype = operandType (IC_LEFT (ic));
D (emitcode (";", "genNot ");
);
/* assign asmOps to operand & result */
aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
aopOp (IC_RESULT (ic), ic, TRUE, AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR);
/* if in bit space then a special case */
if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
{
emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
emitcode ("cpl", "c");
outBitC (IC_RESULT (ic));
goto release;
}
/* if type float then do float */
if (IS_FLOAT (optype))
{
genNotFloat (IC_LEFT (ic), IC_RESULT (ic));
goto release;
}
toBoolean (IC_LEFT (ic));
tlbl = newiTempLabel (NULL);
emitcode ("cjne", "a,#0x01,%05d$", tlbl->key + 100);
emitcode ("", "%05d$:", tlbl->key + 100);
outBitC (IC_RESULT (ic));
release:
/* release the aops */
freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
}
/*-----------------------------------------------------------------*/
/* genCpl - generate code for complement */
/*-----------------------------------------------------------------*/
static void
genCpl (iCode * ic)
{
int offset = 0;
int size;
D (emitcode (";", "genCpl ");
);
/* assign asmOps to operand & result */
aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
aopOp (IC_RESULT (ic), ic, TRUE, AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR);
/* if both are in bit space then
a special case */
if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
{
emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
emitcode ("cpl", "c");
emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
goto release;
}
size = AOP_SIZE (IC_RESULT (ic));
_startLazyDPSEvaluation ();
while (size--)
{
char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE, TRUE);
MOVA (l);
emitcode ("cpl", "a");
aopPut (AOP (IC_RESULT (ic)), "a", offset++);
}
_endLazyDPSEvaluation ();
release:
/* release the aops */
freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
}
/*-----------------------------------------------------------------*/
/* genUminusFloat - unary minus for floating points */
/*-----------------------------------------------------------------*/
static void
genUminusFloat (operand * op, operand * result)
{
int size, offset = 0;
char *l;
/* for this we just need to flip the
first it then copy the rest in place */
D (emitcode (";", "genUminusFloat");
);
_startLazyDPSEvaluation ();
size = AOP_SIZE (op) - 1;
l = aopGet (AOP (op), 3, FALSE, FALSE, TRUE);
MOVA (l);
emitcode ("cpl", "acc.7");
aopPut (AOP (result), "a", 3);
while (size--)
{
aopPut (AOP (result),
aopGet (AOP (op), offset, FALSE, FALSE, FALSE),
offset);
offset++;
}
_endLazyDPSEvaluation ();
}
/*-----------------------------------------------------------------*/
/* genUminus - unary minus code generation */
/*-----------------------------------------------------------------*/
static void
genUminus (iCode * ic)
{
int offset, size;
sym_link *optype, *rtype;
D (emitcode (";", "genUminus ");
);
/* assign asmops */
aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
aopOp (IC_RESULT (ic), ic, TRUE, AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR);
/* if both in bit space then special
case */
if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
{
emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
emitcode ("cpl", "c");
emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
goto release;
}
optype = operandType (IC_LEFT (ic));
rtype = operandType (IC_RESULT (ic));
/* if float then do float stuff */
if (IS_FLOAT (optype))
{
genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
goto release;
}
/* otherwise subtract from zero */
size = AOP_SIZE (IC_LEFT (ic));
offset = 0;
_startLazyDPSEvaluation ();
while (size--)
{
char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE, TRUE);
if (!strcmp (l, "a"))
{
if (offset == 0)
SETC;
emitcode ("cpl", "a");
emitcode ("addc", "a,#0");
}
else
{
if (offset == 0)
CLRC;
emitcode ("clr", "a");
emitcode ("subb", "a,%s", l);
}
aopPut (AOP (IC_RESULT (ic)), "a", offset++);
}
_endLazyDPSEvaluation ();
/* if any remaining bytes in the result */
/* we just need to propagate the sign */
if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
{
emitcode ("rlc", "a");
emitcode ("subb", "a,acc");
while (size--)
aopPut (AOP (IC_RESULT (ic)), "a", offset++);
}
release:
/* release the aops */
freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
}
/*-----------------------------------------------------------------*/
/* saveRegisters - will look for a call and save the registers */
/*-----------------------------------------------------------------*/
static void
saveRegisters (iCode * lic)
{
int i;
iCode *ic;
bitVect *rsave;
sym_link *detype;
/* look for call */
for (ic = lic; ic; ic = ic->next)
if (ic->op == CALL || ic->op == PCALL)
break;
if (!ic)
{
fprintf (stderr, "found parameter push with no function call\n");
return;
}
/* if the registers have been saved already then
do nothing */
if (ic->regsSaved || IFFUNC_CALLEESAVES(OP_SYMBOL (IC_LEFT (ic))->type) ||
IFFUNC_ISNAKED(OP_SYM_TYPE(IC_LEFT(ic))))
return;
/* find the registers in use at this time
and push them away to safety */
rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
ic->rUsed);
ic->regsSaved = 1;
if (options.useXstack)
{
if (bitVectBitValue (rsave, R0_IDX))
emitcode ("mov", "b,r0");
emitcode ("mov", "r0,%s", spname);
for (i = 0; i < ds390_nRegs; i++)
{
if (bitVectBitValue (rsave, i))
{
if (i == R0_IDX)
emitcode ("mov", "a,b");
else
emitcode ("mov", "a,%s", ds390_regWithIdx (i)->name);
emitcode ("movx", "@r0,a");
emitcode ("inc", "r0");
}
}
emitcode ("mov", "%s,r0", spname);
if (bitVectBitValue (rsave, R0_IDX))
emitcode ("mov", "r0,b");
}
else
for (i = 0; i < ds390_nRegs; i++)
{
if (bitVectBitValue (rsave, i))
emitcode ("push", "%s", ds390_regWithIdx (i)->dname);
}
detype = getSpec (operandType (IC_LEFT (ic)));
}
/*-----------------------------------------------------------------*/
/* unsaveRegisters - pop the pushed registers */
/*-----------------------------------------------------------------*/
static void
unsaveRegisters (iCode * ic)
{
int i;
bitVect *rsave;
/* find the registers in use at this time
and push them away to safety */
rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
ic->rUsed);
if (options.useXstack)
{
emitcode ("mov", "r0,%s", spname);
for (i = ds390_nRegs; i >= 0; i--)
{
if (bitVectBitValue (rsave, i))
{
emitcode ("dec", "r0");
emitcode ("movx", "a,@r0");
if (i == R0_IDX)
emitcode ("mov", "b,a");
else
emitcode ("mov", "%s,a", ds390_regWithIdx (i)->name);
}
}
emitcode ("mov", "%s,r0", spname);
if (bitVectBitValue (rsave, R0_IDX))
emitcode ("mov", "r0,b");
}
else
for (i = ds390_nRegs; i >= 0; i--)
{
if (bitVectBitValue (rsave, i))
emitcode ("pop", "%s", ds390_regWithIdx (i)->dname);
}
}
/*-----------------------------------------------------------------*/
/* pushSide - */
/*-----------------------------------------------------------------*/
static void
pushSide (operand * oper, int size)
{
int offset = 0;
_startLazyDPSEvaluation ();
while (size--)
{
char *l = aopGet (AOP (oper), offset++, FALSE, TRUE, FALSE);
if (AOP_TYPE (oper) != AOP_REG &&
AOP_TYPE (oper) != AOP_DIR &&
strcmp (l, "a"))
{
emitcode ("mov", "a,%s", l);
emitcode ("push", "acc");
}
else
emitcode ("push", "%s", l);
}
_endLazyDPSEvaluation ();
}
/*-----------------------------------------------------------------*/
/* assignResultValue - */
/*-----------------------------------------------------------------*/
static void
assignResultValue (operand * oper)
{
int offset = 0;
int size = AOP_SIZE (oper);
_startLazyDPSEvaluation ();
while (size--)
{
aopPut (AOP (oper), fReturn[offset], offset);
offset++;
}
_endLazyDPSEvaluation ();
}
/*-----------------------------------------------------------------*/
/* genXpush - pushes onto the external stack */
/*-----------------------------------------------------------------*/
static void
genXpush (iCode * ic)
{
asmop *aop = newAsmop (0);
regs *r;
int size, offset = 0;
D (emitcode (";", "genXpush ");
);
aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
r = getFreePtr (ic, &aop, FALSE);
emitcode ("mov", "%s,_spx", r->name);
size = AOP_SIZE (IC_LEFT (ic));
_startLazyDPSEvaluation ();
while (size--)
{
char *l = aopGet (AOP (IC_LEFT (ic)),
offset++, FALSE, FALSE, TRUE);
MOVA (l);
emitcode ("movx", "@%s,a", r->name);
emitcode ("inc", "%s", r->name);
}
_endLazyDPSEvaluation ();
emitcode ("mov", "_spx,%s", r->name);
freeAsmop (NULL, aop, ic, TRUE);
freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
}
/*-----------------------------------------------------------------*/
/* genIpush - genrate code for pushing this gets a little complex */
/*-----------------------------------------------------------------*/
static void
genIpush (iCode * ic)
{
int size, offset = 0;
char *l;
D (emitcode (";", "genIpush ");
);
/* if this is not a parm push : ie. it is spill push
and spill push is always done on the local stack */
if (!ic->parmPush)
{
/* and the item is spilt then do nothing */
if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
return;
aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
size = AOP_SIZE (IC_LEFT (ic));
/* push it on the stack */
_startLazyDPSEvaluation ();
while (size--)
{
l = aopGet (AOP (IC_LEFT (ic)), offset++, FALSE, TRUE, TRUE);
if (*l == '#')
{
MOVA (l);
l = "acc";
}
emitcode ("push", "%s", l);
}
_endLazyDPSEvaluation ();
return;
}
/* this is a paramter push: in this case we call
the routine to find the call and save those
registers that need to be saved */
saveRegisters (ic);
/* if use external stack then call the external
stack pushing routine */
if (options.useXstack)
{
genXpush (ic);
return;
}
/* then do the push */
aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
// pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
size = AOP_SIZE (IC_LEFT (ic));
_startLazyDPSEvaluation ();
while (size--)
{
l = aopGet (AOP (IC_LEFT (ic)), offset++, FALSE, TRUE, FALSE);
if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
AOP_TYPE (IC_LEFT (ic)) != AOP_DIR &&
strcmp (l, "a"))
{
emitcode ("mov", "a,%s", l);
emitcode ("push", "acc");
}
else
emitcode ("push", "%s", l);
}
_endLazyDPSEvaluation ();
freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
}
/*-----------------------------------------------------------------*/
/* genIpop - recover the registers: can happen only for spilling */
/*-----------------------------------------------------------------*/
static void
genIpop (iCode * ic)
{
int size, offset;
D (emitcode (";", "genIpop ");
);
/* if the temp was not pushed then */
if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
return;
aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
size = AOP_SIZE (IC_LEFT (ic));
offset = (size - 1);
_startLazyDPSEvaluation ();
while (size--)
{
emitcode ("pop", "%s", aopGet (AOP (IC_LEFT (ic)), offset--,
FALSE, TRUE, TRUE));
}
_endLazyDPSEvaluation ();
freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
}
/*-----------------------------------------------------------------*/
/* unsaveRBank - restores the resgister bank from stack */
/*-----------------------------------------------------------------*/
static void
unsaveRBank (int bank, iCode * ic, bool popPsw)
{
int i;
asmop *aop = NULL;
regs *r = NULL;
if (options.useXstack)
{
if (!ic)
{
/* Assume r0 is available for use. */
r = ds390_regWithIdx (R0_IDX);;
}
else
{
aop = newAsmop (0);
r = getFreePtr (ic, &aop, FALSE);
}
emitcode ("mov", "%s,_spx", r->name);
}
if (popPsw)
{
if (options.useXstack)
{
emitcode ("movx", "a,@%s", r->name);
emitcode ("mov", "psw,a");
emitcode ("dec", "%s", r->name);
}
else
{
emitcode ("pop", "psw");
}
}
for (i = (ds390_nRegs - 1); i >= 0; i--)
{
if (options.useXstack)
{
emitcode ("movx", "a,@%s", r->name);
emitcode ("mov", "(%s+%d),a",
regs390[i].base, 8 * bank + regs390[i].offset);
emitcode ("dec", "%s", r->name);
}
else
emitcode ("pop", "(%s+%d)",
regs390[i].base, 8 * bank + regs390[i].offset);
}
if (options.useXstack)
{
emitcode ("mov", "_spx,%s", r->name);
}
if (aop)
{
freeAsmop (NULL, aop, ic, TRUE);
}
}
/*-----------------------------------------------------------------*/
/* saveRBank - saves an entire register bank on the stack */
/*-----------------------------------------------------------------*/
static void
saveRBank (int bank, iCode * ic, bool pushPsw)
{
int i;
asmop *aop = NULL;
regs *r = NULL;
if (options.useXstack)
{
if (!ic)
{
/* Assume r0 is available for use. */
r = ds390_regWithIdx (R0_IDX);;
}
else
{
aop = newAsmop (0);
r = getFreePtr (ic, &aop, FALSE);
}
emitcode ("mov", "%s,_spx", r->name);
}
for (i = 0; i < ds390_nRegs; i++)
{
if (options.useXstack)
{
emitcode ("inc", "%s", r->name);
emitcode ("mov", "a,(%s+%d)",
regs390[i].base, 8 * bank + regs390[i].offset);
emitcode ("movx", "@%s,a", r->name);
}
else
emitcode ("push", "(%s+%d)",
regs390[i].base, 8 * bank + regs390[i].offset);
}
if (pushPsw)
{
if (options.useXstack)
{
emitcode ("mov", "a,psw");
emitcode ("movx", "@%s,a", r->name);
emitcode ("inc", "%s", r->name);
emitcode ("mov", "_spx,%s", r->name);
}
else
{
emitcode ("push", "psw");
}
emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0x00ff);
}
if (aop)
{
freeAsmop (NULL, aop, ic, TRUE);
}
if (ic)
{
ic->bankSaved = 1;
}
}
/*-----------------------------------------------------------------*/
/* genCall - generates a call statement */
/*-----------------------------------------------------------------*/
static void
genCall (iCode * ic)
{
sym_link *dtype;
bool restoreBank = FALSE;
bool swapBanks = FALSE;
D (emitcode (";", "genCall "););
/* if we are calling a not _naked function that is not using
the same register bank then we need to save the
destination registers on the stack */
dtype = operandType (IC_LEFT (ic));
if (dtype && !IFFUNC_ISNAKED(dtype) &&
(FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
IFFUNC_ISISR (currFunc->type))
{
if (!ic->bankSaved)
{
/* This is unexpected; the bank should have been saved in
* genFunction.
*/
saveRBank (FUNC_REGBANK (dtype), ic, FALSE);
restoreBank = TRUE;
}
swapBanks = TRUE;
}
/* if caller saves & we have not saved then */
if (!ic->regsSaved)
saveRegisters (ic);
/* if send set is not empty the assign */
/* We've saved all the registers we care about;
* therefore, we may clobber any register not used
* in the calling convention (i.e. anything not in
* fReturn.
*/
if (_G.sendSet)
{
iCode *sic;
for (sic = setFirstItem (_G.sendSet); sic;
sic = setNextItem (_G.sendSet))
{
int size, offset = 0;
aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
size = AOP_SIZE (IC_LEFT (sic));
_startLazyDPSEvaluation ();
while (size--)
{
char *l = aopGet (AOP(IC_LEFT(sic)), offset,
FALSE, FALSE, TRUE);
if ((AOP_TYPE(IC_LEFT(sic)) == AOP_DPTR) && size)
{
emitcode("mov", "%s,%s", regs390[offset].name, l);
}
else if (strcmp (l, fReturn[offset]))
{
emitcode ("mov", "%s,%s",
fReturn[offset],
l);
}
offset++;
}
_endLazyDPSEvaluation ();
if (AOP_TYPE(IC_LEFT(sic)) == AOP_DPTR)
{
size = AOP_SIZE (IC_LEFT (sic));
if (size)
{
size--;
}
while (size)
{
size--;
emitcode("mov", "%s,%s",
fReturn[size], regs390[size].name);
}
}
freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
}
_G.sendSet = NULL;
}
if (swapBanks)
{
emitcode ("mov", "psw,#0x%02x",
((FUNC_REGBANK(dtype)) << 3) & 0xff);
}
/* 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 (swapBanks)
{
emitcode ("mov", "psw,#0x%02x",
((FUNC_REGBANK(currFunc->type)) << 3) & 0xff);
}
/* if we need assign a result value */
if ((IS_ITEMP (IC_RESULT (ic)) &&
(OP_SYMBOL (IC_RESULT (ic))->nRegs ||
OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
IS_TRUE_SYMOP (IC_RESULT (ic)))
{
if (isOperandInFarSpace (IC_RESULT (ic))
&& getSize (operandType (IC_RESULT (ic))) <= 2)
{
int size = getSize (operandType (IC_RESULT (ic)));
/* Special case for 1 or 2 byte return in far space. */
MOVA (fReturn[0]);
if (size > 1)
{
emitcode ("mov", "b,%s", fReturn[1]);
}
aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
aopPut (AOP (IC_RESULT (ic)), "a", 0);
if (size > 1)
{
aopPut (AOP (IC_RESULT (ic)), "b", 1);
}
freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
}
else
{
_G.accInUse++;
aopOp (IC_RESULT (ic), ic, FALSE, TRUE);
_G.accInUse--;
assignResultValue (IC_RESULT (ic));
freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
}
}
/* adjust the stack for parameters if
required */
if (ic->parmBytes)
{
int i;
if (ic->parmBytes > 3)
{
emitcode ("mov", "a,%s", spname);
emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
emitcode ("mov", "%s,a", spname);
}
else
for (i = 0; i < ic->parmBytes; i++)
emitcode ("dec", "%s", spname);
}
/* if we hade saved some registers then unsave them */
if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
unsaveRegisters (ic);
/* if register bank was saved then pop them */
if (restoreBank)
unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
}
/*-----------------------------------------------------------------*/
/* genPcall - generates a call by pointer statement */
/*-----------------------------------------------------------------*/
static void
genPcall (iCode * ic)
{
sym_link *dtype;
symbol *rlbl = newiTempLabel (NULL);
D (emitcode (";", "genPcall ");
);
/* if caller saves & we have not saved then */
if (!ic->regsSaved)
saveRegisters (ic);
/* if we are calling a function that is not using
the same register bank then we need to save the
destination registers on the stack */
dtype = operandType (IC_LEFT (ic));
if (dtype &&
IFFUNC_ISISR (currFunc->type) &&
(FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)))
saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
/* 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");
if (options.model == MODEL_FLAT24)
{
emitcode ("mov", "a,#(%05d$ >> 16)", (rlbl->key + 100));
emitcode ("push", "acc");
}
/* now push the calling address */
aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
pushSide (IC_LEFT (ic), FPTRSIZE);
freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
/* if send set is not empty the assign */
if (_G.sendSet)
{
iCode *sic;
for (sic = setFirstItem (_G.sendSet); sic;
sic = setNextItem (_G.sendSet))
{
int size, offset = 0;
aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
size = AOP_SIZE (IC_LEFT (sic));
_startLazyDPSEvaluation ();
while (size--)
{
char *l = aopGet (AOP (IC_LEFT (sic)), offset,
FALSE, FALSE, TRUE);
if (strcmp (l, fReturn[offset]))
{
emitcode ("mov", "%s,%s",
fReturn[offset],
l);
}
offset++;
}
_endLazyDPSEvaluation ();
freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
}
_G.sendSet = NULL;
}
emitcode ("ret", "");
emitcode ("", "%05d$:", (rlbl->key + 100));
/* if we need assign a result value */
if ((IS_ITEMP (IC_RESULT (ic)) &&
(OP_SYMBOL (IC_RESULT (ic))->nRegs ||
OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
IS_TRUE_SYMOP (IC_RESULT (ic)))
{
_G.accInUse++;
aopOp (IC_RESULT (ic), ic, FALSE, TRUE);
_G.accInUse--;
assignResultValue (IC_RESULT (ic));
freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
}
/* adjust the stack for parameters if
required */
if (ic->parmBytes)
{
int i;
if (ic->parmBytes > 3)
{
emitcode ("mov", "a,%s", spname);
emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
emitcode ("mov", "%s,a", spname);
}
else
for (i = 0; i < ic->parmBytes; i++)
emitcode ("dec", "%s", spname);
}
/* if register bank was saved then unsave them */
if (dtype &&
(FUNC_REGBANK (currFunc->type) !=
FUNC_REGBANK (dtype)))
unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
/* if we hade saved some registers then
unsave them */
if (ic->regsSaved)
unsaveRegisters (ic);
}
/*-----------------------------------------------------------------*/
/* resultRemat - result is rematerializable */
/*-----------------------------------------------------------------*/
static int
resultRemat (iCode * ic)
{
if (SKIP_IC (ic) || ic->op == IFX)
return 0;
if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
{
symbol *sym = OP_SYMBOL (IC_RESULT (ic));
if (sym->remat && !POINTER_SET (ic))
return 1;
}
return 0;
}
#if defined(__BORLANDC__) || defined(_MSC_VER)
#define STRCASECMP stricmp
#else
#define STRCASECMP strcasecmp
#endif
/*-----------------------------------------------------------------*/
/* inExcludeList - return 1 if the string is in exclude Reg list */
/*-----------------------------------------------------------------*/
static bool
inExcludeList (char *s)
{
int i = 0;
if (options.excludeRegs[i] &&
STRCASECMP (options.excludeRegs[i], "none") == 0)
return FALSE;
for (i = 0; options.excludeRegs[i]; i++)
{
if (options.excludeRegs[i] &&
STRCASECMP (s, options.excludeRegs[i]) == 0)
return TRUE;
}
return FALSE;
}
/*-----------------------------------------------------------------*/
/* genFunction - generated code for function entry */
/*-----------------------------------------------------------------*/
static void
genFunction (iCode * ic)
{
symbol *sym;
sym_link *ftype;
bool switchedPSW = FALSE;
D (emitcode (";", "genFunction "););
_G.nRegsSaved = 0;
/* create the function header */
emitcode (";", "-----------------------------------------");
emitcode (";", " function %s", (sym = OP_SYMBOL (IC_LEFT (ic)))->name);
emitcode (";", "-----------------------------------------");
emitcode ("", "%s:", sym->rname);
ftype = operandType (IC_LEFT (ic));
if (IFFUNC_ISNAKED(ftype))
{
emitcode(";", "naked function: no prologue.");
return;
}
/* if critical function then turn interrupts off */
if (IFFUNC_ISCRITICAL (ftype))
emitcode ("clr", "ea");
/* here we need to generate the equates for the
register bank if required */
if (FUNC_REGBANK (ftype) != rbank)
{
int i;
rbank = FUNC_REGBANK (ftype);
for (i = 0; i < ds390_nRegs; i++)
{
if (strcmp (regs390[i].base, "0") == 0)
emitcode ("", "%s = 0x%02x",
regs390[i].dname,
8 * rbank + regs390[i].offset);
else
emitcode ("", "%s = %s + 0x%02x",
regs390[i].dname,
regs390[i].base,
8 * rbank + regs390[i].offset);
}
}
/* if this is an interrupt service routine then
save acc, b, dpl, dph */
if (IFFUNC_ISISR (sym->type))
{
if (!inExcludeList ("acc"))
emitcode ("push", "acc");
if (!inExcludeList ("b"))
emitcode ("push", "b");
if (!inExcludeList ("dpl"))
emitcode ("push", "dpl");
if (!inExcludeList ("dph"))
emitcode ("push", "dph");
if (options.model == MODEL_FLAT24 && !inExcludeList ("dpx"))
{
emitcode ("push", "dpx");
/* Make sure we're using standard DPTR */
emitcode ("push", "dps");
emitcode ("mov", "dps, #0x00");
if (options.stack10bit)
{
/* This ISR could conceivably use DPTR2. Better save it. */
emitcode ("push", "dpl1");
emitcode ("push", "dph1");
emitcode ("push", "dpx1");
emitcode ("push", DP2_RESULT_REG);
}
}
/* if this isr has no bank i.e. is going to
run with bank 0 , then we need to save more
registers :-) */
if (!FUNC_REGBANK (sym->type))
{
/* if this function does not call any other
function then we can be economical and
save only those registers that are used */
if (!IFFUNC_HASFCALL(sym->type))
{
int i;
/* if any registers used */
if (sym->regsUsed)
{
/* save the registers used */
for (i = 0; i < sym->regsUsed->size; i++)
{
if (bitVectBitValue (sym->regsUsed, i) ||
(ds390_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
emitcode ("push", "%s", ds390_regWithIdx (i)->dname);
}
}
}
else
{
/* this function has a function call cannot
determines register usage so we will have to push the
entire bank */
saveRBank (0, ic, FALSE);
}
}
else
{
/* This ISR uses a non-zero bank.
*
* We assume that the bank is available for our
* exclusive use.
*
* However, if this ISR calls a function which uses some
* other bank, we must save that bank entirely.
*/
unsigned long banksToSave = 0;
if (IFFUNC_HASFCALL(sym->type))
{
#define MAX_REGISTER_BANKS 4
iCode *i;
int ix;
for (i = ic; i; i = i->next)
{
if (i->op == ENDFUNCTION)
{
/* we got to the end OK. */
break;
}
if (i->op == CALL)
{
sym_link *dtype;
dtype = operandType (IC_LEFT(i));
if (dtype
&& FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
{
/* Mark this bank for saving. */
if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
{
werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
}
else
{
banksToSave |= (1 << FUNC_REGBANK(dtype));
}
/* And note that we don't need to do it in
* genCall.
*/
i->bankSaved = 1;
}
}
if (i->op == PCALL)
{
/* This is a mess; we have no idea what
* register bank the called function might
* use.
*
* The only thing I can think of to do is
* throw a warning and hope.
*/
werror(W_FUNCPTR_IN_USING_ISR);
}
}
if (banksToSave && options.useXstack)
{
/* Since we aren't passing it an ic,
* saveRBank will assume r0 is available to abuse.
*
* So switch to our (trashable) bank now, so
* the caller's R0 isn't trashed.
*/
emitcode ("push", "psw");
emitcode ("mov", "psw,#0x%02x",
(FUNC_REGBANK (sym->type) << 3) & 0x00ff);
switchedPSW = TRUE;
}
for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
{
if (banksToSave & (1 << ix))
{
saveRBank(ix, NULL, FALSE);
}
}
}
// jwk: this needs a closer look
SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
}
}
else
{
/* if callee-save to be used for this function
then save the registers being used in this function */
if (IFFUNC_CALLEESAVES(sym->type))
{
int i;
/* if any registers used */
if (sym->regsUsed)
{
/* save the registers used */
for (i = 0; i < sym->regsUsed->size; i++)
{
if (bitVectBitValue (sym->regsUsed, i) ||
(ds390_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
{
emitcode ("push", "%s", ds390_regWithIdx (i)->dname);
_G.nRegsSaved++;
}
}
}
}
}
/* set the register bank to the desired value */
if ((FUNC_REGBANK (sym->type) || FUNC_ISISR (sym->type))
&& !switchedPSW)
{
emitcode ("push", "psw");
emitcode ("mov", "psw,#0x%02x", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
}
if (IFFUNC_ISREENT (sym->type) || options.stackAuto)
{
if (options.useXstack)
{
emitcode ("mov", "r0,%s", spname);
emitcode ("mov", "a,_bp");
emitcode ("movx", "@r0,a");
emitcode ("inc", "%s", spname);
}
else
{
/* set up the stack */
emitcode ("push", "_bp"); /* save the callers stack */
}
emitcode ("mov", "_bp,%s", spname);
}
/* adjust the stack for the function */
if (sym->stack)
{
int i = sym->stack;
if (i > 256)
werror (W_STACK_OVERFLOW, sym->name);
if (i > 3 && sym->recvSize < 4)
{
emitcode ("mov", "a,sp");
emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
emitcode ("mov", "sp,a");
}
else
while (i--)
emitcode ("inc", "sp");
}
if (sym->xstack)
{
emitcode ("mov", "a,_spx");
emitcode ("add", "a,#0x%02x", ((char) sym->xstack & 0xff));
emitcode ("mov", "_spx,a");
}
}
/*-----------------------------------------------------------------*/
/* genEndFunction - generates epilogue for functions */
/*-----------------------------------------------------------------*/
static void
genEndFunction (iCode * ic)
{
symbol *sym = OP_SYMBOL (IC_LEFT (ic));
D (emitcode (";", "genEndFunction "););
if (IFFUNC_ISNAKED(sym->type))
{
emitcode(";", "naked function: no epilogue.");
return;
}
if (IFFUNC_ISREENT (sym->type) || options.stackAuto)
{
emitcode ("mov", "%s,_bp", spname);
}
/* if use external stack but some variables were
added to the local stack then decrement the
local stack */
if (options.useXstack && sym->stack)
{
emitcode ("mov", "a,sp");
emitcode ("add", "a,#0x%02x", ((char) -sym->stack) & 0xff);
emitcode ("mov", "sp,a");
}
if ((IFFUNC_ISREENT (sym->type) || options.stackAuto))
{
if (options.useXstack)
{
emitcode ("mov", "r0,%s", spname);
emitcode ("movx", "a,@r0");
emitcode ("mov", "_bp,a");
emitcode ("dec", "%s", spname);
}
else
{
emitcode ("pop", "_bp");
}
}
/* restore the register bank */
if (FUNC_REGBANK (sym->type) || IFFUNC_ISISR (sym->type))
{
if (!FUNC_REGBANK (sym->type) || !IFFUNC_ISISR (sym->type)
|| !options.useXstack)
{
/* Special case of ISR using non-zero bank with useXstack
* is handled below.
*/
emitcode ("pop", "psw");
}
}
if (IFFUNC_ISISR (sym->type))
{
/* now we need to restore the registers */
/* if this isr has no bank i.e. is going to
run with bank 0 , then we need to save more
registers :-) */
if (!FUNC_REGBANK (sym->type))
{
/* if this function does not call any other
function then we can be economical and
save only those registers that are used */
if (!IFFUNC_HASFCALL(sym->type))
{
int i;
/* if any registers used */
if (sym->regsUsed)
{
/* save the registers used */
for (i = sym->regsUsed->size; i >= 0; i--)
{
if (bitVectBitValue (sym->regsUsed, i) ||
(ds390_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
emitcode ("pop", "%s", ds390_regWithIdx (i)->dname);
}
}
}
else
{
/* this function has a function call cannot
determines register usage so we will have to pop the
entire bank */
unsaveRBank (0, ic, FALSE);
}
}
else
{
/* This ISR uses a non-zero bank.
*
* Restore any register banks saved by genFunction
* in reverse order.
*/
// jwk: this needs a closer look
unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
int ix;
for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
{
if (savedBanks & (1 << ix))
{
unsaveRBank(ix, NULL, FALSE);
}
}
if (options.useXstack)
{
/* Restore bank AFTER calling unsaveRBank,
* since it can trash r0.
*/
emitcode ("pop", "psw");
}
}
if (options.model == MODEL_FLAT24 && !inExcludeList ("dpx"))
{
if (options.stack10bit)
{
emitcode ("pop", DP2_RESULT_REG);
emitcode ("pop", "dpx1");
emitcode ("pop", "dph1");
emitcode ("pop", "dpl1");
}
emitcode ("pop", "dps");
emitcode ("pop", "dpx");
}
if (!inExcludeList ("dph"))
emitcode ("pop", "dph");
if (!inExcludeList ("dpl"))
emitcode ("pop", "dpl");
if (!inExcludeList ("b"))
emitcode ("pop", "b");
if (!inExcludeList ("acc"))
emitcode ("pop", "acc");
if (IFFUNC_ISCRITICAL (sym->type))
emitcode ("setb", "ea");
/* if debug then send end of function */
if (options.debug && currFunc) {
_G.debugLine = 1;
emitcode ("", "C$%s$%d$%d$%d ==.",
FileBaseName (ic->filename), currFunc->lastLine,
ic->level, ic->block);
if (IS_STATIC (currFunc->etype))
emitcode ("", "XF%s$%s$0$0 ==.", moduleName, currFunc->name);
else
emitcode ("", "XG$%s$0$0 ==.", currFunc->name);
_G.debugLine = 0;
}
emitcode ("reti", "");
}
else
{
if (IFFUNC_ISCRITICAL (sym->type))
emitcode ("setb", "ea");
if (IFFUNC_CALLEESAVES(sym->type))
{
int i;
/* if any registers used */
if (sym->regsUsed)
{
/* save the registers used */
for (i = sym->regsUsed->size; i >= 0; i--)
{
if (bitVectBitValue (sym->regsUsed, i) ||
(ds390_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
emitcode ("pop", "%s", ds390_regWithIdx (i)->dname);
}
}
}
/* if debug then send end of function */
if (options.debug && currFunc)
{
_G.debugLine = 1;
emitcode ("", "C$%s$%d$%d$%d ==.",
FileBaseName (ic->filename), currFunc->lastLine,
ic->level, ic->block);
if (IS_STATIC (currFunc->etype))
emitcode ("", "XF%s$%s$0$0 ==.", moduleName, currFunc->name);
else
emitcode ("", "XG$%s$0$0 ==.", currFunc->name);
_G.debugLine = 0;
}
emitcode ("ret", "");
}
}
/*-----------------------------------------------------------------*/
/* genRet - generate code for return statement */
/*-----------------------------------------------------------------*/
static void
genRet (iCode * ic)
{
int size, offset = 0, pushed = 0;
D (emitcode (";", "genRet ");
);
/* if we have no return value then
just generate the "ret" */
if (!IC_LEFT (ic))
goto jumpret;
/* we have something to return then
move the return value into place */
aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
size = AOP_SIZE (IC_LEFT (ic));
_startLazyDPSEvaluation ();
while (size--)
{
char *l;
if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
{
l = aopGet (AOP (IC_LEFT (ic)), offset++,
FALSE, TRUE, FALSE);
emitcode ("push", "%s", l);
pushed++;
}
else
{
/* Since A is the last element of fReturn,
* is is OK to clobber it in the aopGet.
*/
l = aopGet (AOP (IC_LEFT (ic)), offset,
FALSE, FALSE, TRUE);
if (strcmp (fReturn[offset], l))
emitcode ("mov", "%s,%s", fReturn[offset++], l);
}
}
_endLazyDPSEvaluation ();
if (pushed)
{
while (pushed)
{
pushed--;
if (strcmp (fReturn[pushed], "a"))
emitcode ("pop", fReturn[pushed]);
else
emitcode ("pop", "acc");
}
}
freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
jumpret:
/* generate a jump to the return label
if the next is not the return statement */
if (!(ic->next && ic->next->op == LABEL &&
IC_LABEL (ic->next) == returnLabel))
emitcode ("ljmp", "%05d$", (returnLabel->key + 100));
}
/*-----------------------------------------------------------------*/
/* genLabel - generates a label */
/*-----------------------------------------------------------------*/
static void
genLabel (iCode * ic)
{
/* special case never generate */
if (IC_LABEL (ic) == entryLabel)
return;
D (emitcode (";", "genLabel ");
);
emitcode ("", "%05d$:", (IC_LABEL (ic)->key + 100));
}
/*-----------------------------------------------------------------*/
/* genGoto - generates a ljmp */
/*-----------------------------------------------------------------*/
static void
genGoto (iCode * ic)
{
D (emitcode (";", "genGoto ");
);
emitcode ("ljmp", "%05d$", (IC_LABEL (ic)->key + 100));
}
/*-----------------------------------------------------------------*/
/* findLabelBackwards: walks back through the iCode chain looking */
/* for the given label. Returns number of iCode instructions */
/* between that label and given ic. */
/* Returns zero if label not found. */
/*-----------------------------------------------------------------*/
static int
findLabelBackwards (iCode * ic, int key)
{
int count = 0;
while (ic->prev)
{
ic = ic->prev;
count++;
if (ic->op == LABEL && IC_LABEL (ic)->key == key)
{
/* printf("findLabelBackwards = %d\n", count); */
return count;
}
}
return 0;
}
/*-----------------------------------------------------------------*/
/* genPlusIncr :- does addition with increment if possible */
/*-----------------------------------------------------------------*/
static bool
genPlusIncr (iCode * ic)
{
unsigned int icount;
unsigned int size = getDataSize (IC_RESULT (ic));
/* will try to generate an increment */
/* if the right side is not a literal
we cannot */
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;
/* if increment 16 bits in register */
if (
AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
(size > 1) &&
(icount == 1))
{
symbol *tlbl;
int emitTlbl;
int labelRange;
/* If the next instruction is a goto and the goto target
* is <= 5 instructions previous to this, we can generate
* jumps straight to that target.
*/
if (ic->next && ic->next->op == GOTO
&& (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
&& labelRange <= 5)
{
emitcode (";", "tail increment optimized (range %d)", labelRange);
tlbl = IC_LABEL (ic->next);
emitTlbl = 0;
}
else
{
tlbl = newiTempLabel (NULL);
emitTlbl = 1;
}
emitcode ("inc", "%s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE, FALSE));
if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
IS_AOP_PREG (IC_RESULT (ic)))
emitcode ("cjne", "%s,#0x00,%05d$"
,aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE, FALSE)
,tlbl->key + 100);
else
{
emitcode ("clr", "a");
emitcode ("cjne", "a,%s,%05d$"
,aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE, FALSE)
,tlbl->key + 100);
}
emitcode ("inc", "%s", aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE, FALSE));
if (size > 2)
{
if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
IS_AOP_PREG (IC_RESULT (ic)))
emitcode ("cjne", "%s,#0x00,%05d$"
,aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE, FALSE)
,tlbl->key + 100);
else
emitcode ("cjne", "a,%s,%05d$"
,aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE, FALSE)
,tlbl->key + 100);
emitcode ("inc", "%s", aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE, FALSE));
}
if (size > 3)
{
if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
IS_AOP_PREG (IC_RESULT (ic)))
emitcode ("cjne", "%s,#0x00,%05d$"
,aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE, FALSE)
,tlbl->key + 100);
else
{
emitcode ("cjne", "a,%s,%05d$"
,aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE, FALSE)
,tlbl->key + 100);
}
emitcode ("inc", "%s", aopGet (AOP (IC_RESULT (ic)), MSB32, FALSE, FALSE, FALSE));
}
if (emitTlbl)
{
emitcode ("", "%05d$:", tlbl->key + 100);
}
return TRUE;
}
/* if the sizes are greater than 1 then we cannot */
if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
AOP_SIZE (IC_LEFT (ic)) > 1)
return FALSE;
/* we can if the aops of the left & result match or
if they are in registers and the registers are the
same */
if (
AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
{
if (icount > 3)
{
MOVA (aopGet (AOP (IC_LEFT (ic)), 0, FALSE, FALSE, TRUE));
emitcode ("add", "a,#0x%02x", ((char) icount) & 0xff);
aopPut (AOP (IC_RESULT (ic)), "a", 0);
}
else
{
_startLazyDPSEvaluation ();
while (icount--)
{
emitcode ("inc", "%s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE, FALSE, FALSE));
}
_endLazyDPSEvaluation ();
}
return TRUE;
}
return FALSE;
}
/*-----------------------------------------------------------------*/
/* outBitAcc - output a bit in acc */
/*-----------------------------------------------------------------*/
static void
outBitAcc (operand * result)
{
symbol *tlbl = newiTempLabel (NULL);
/* if the result is a bit */
if (AOP_TYPE (result) == AOP_CRY)
{
aopPut (AOP (result), "a", 0);
}
else
{
emitcode ("jz", "%05d$", tlbl->key + 100);
emitcode ("mov", "a,%s", one);
emitcode ("", "%05d$:", tlbl->key + 100);
outAcc (result);
}
}
/*-----------------------------------------------------------------*/
/* genPlusBits - generates code for addition of two bits */
/*-----------------------------------------------------------------*/
static void
genPlusBits (iCode * ic)
{
D (emitcode (";", "genPlusBits ");
);
if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
{
symbol *lbl = newiTempLabel (NULL);
emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
emitcode ("cpl", "c");
emitcode ("", "%05d$:", (lbl->key + 100));
outBitC (IC_RESULT (ic));
}
else
{
emitcode ("clr", "a");
emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
emitcode ("rlc", "a");
emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
emitcode ("addc", "a,#0x00");
outAcc (IC_RESULT (ic));
}
}
static void
adjustArithmeticResult (iCode * ic)
{
if (opIsGptr (IC_RESULT (ic)) &&
opIsGptr (IC_LEFT (ic)) &&
!sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
{
aopPut (AOP (IC_RESULT (ic)),
aopGet (AOP (IC_LEFT (ic)), GPTRSIZE - 1, FALSE, FALSE, FALSE),
GPTRSIZE - 1);
}
if (opIsGptr (IC_RESULT (ic)) &&
opIsGptr (IC_RIGHT (ic)) &&
!sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
{
aopPut (AOP (IC_RESULT (ic)),
aopGet (AOP (IC_RIGHT (ic)), GPTRSIZE - 1, FALSE, FALSE, FALSE),
GPTRSIZE - 1);
}
if (opIsGptr (IC_RESULT (ic)) &&
AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
!sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
!sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
{
char buffer[5];
sprintf (buffer, "#%d", pointerCode (getSpec (operandType (IC_LEFT (ic)))));
aopPut (AOP (IC_RESULT (ic)), buffer, GPTRSIZE - 1);
}
}
#if 0 // AOP_OP_3 is deprecated; nobody likes Ack errors.
// Please don't bring it back without a really good reason.
// Macro to aopOp all three operands of an ic. Will fatal if this cannot be done
// (because all three operands are in far space).
#define AOP_OP_3(ic) \
aopOp (IC_RIGHT(ic),ic,FALSE, FALSE); \
aopOp (IC_LEFT(ic),ic,FALSE, (AOP_TYPE(IC_RIGHT(ic)) == AOP_DPTR)); \
aopOp (IC_RESULT(ic),ic,TRUE, (AOP_TYPE(IC_LEFT(ic)) == AOP_DPTR) || \
(AOP_TYPE(IC_RIGHT(ic)) == AOP_DPTR)); \
if (AOP_TYPE(IC_LEFT(ic)) == AOP_DPTR2 && \
AOP_TYPE(IC_RESULT(ic)) == AOP_DPTR2) \
{ \
/* werror(E_INTERNAL_ERROR,__FILE__,__LINE__, */ \
fprintf(stderr, \
"Ack: three operands in far space! (%s:%d %s:%d)\n", __FILE__, __LINE__, ic->filename, ic->lineno); \
}
#endif
// Macro to aopOp all three operands of an ic. If this cannot be done,
// the IC_LEFT and IC_RIGHT operands will be aopOp'd, and the rc parameter
// will be set TRUE. The caller must then handle the case specially, noting
// that the IC_RESULT operand is not aopOp'd.
#define AOP_OP_3_NOFATAL(ic, rc) \
aopOp (IC_RIGHT(ic),ic,FALSE, FALSE); \
aopOp (IC_LEFT(ic),ic,FALSE, (AOP_TYPE(IC_RIGHT(ic)) == AOP_DPTR)); \
if (AOP_TYPE(IC_LEFT(ic)) == AOP_DPTR2 && \
isOperandInFarSpace(IC_RESULT(ic))) \
{ \
/* No can do; DPTR & DPTR2 in use, and we need another. */ \
rc = TRUE; \
} \
else \
{ \
aopOp (IC_RESULT(ic),ic,TRUE, (AOP_TYPE(IC_LEFT(ic)) == AOP_DPTR) || \
(AOP_TYPE(IC_RIGHT(ic)) == AOP_DPTR)); \
rc = FALSE; \
if (AOP_TYPE(IC_LEFT(ic)) == AOP_DPTR2 && \
AOP_TYPE(IC_RESULT(ic)) == AOP_DPTR2) \
{ \
/* werror(E_INTERNAL_ERROR,__FILE__,__LINE__, */ \
fprintf(stderr, \
"Ack: got unexpected DP2! (%s:%d %s:%d)\n", __FILE__, __LINE__, ic->filename, ic->lineno); \
} \
}
// aopOp the left & right operands of an ic.
#define AOP_OP_2(ic) \
aopOp (IC_RIGHT(ic),ic,FALSE, FALSE); \
aopOp (IC_LEFT(ic),ic,FALSE, (AOP_TYPE(IC_RIGHT(ic)) == AOP_DPTR));
// convienience macro.
#define AOP_SET_LOCALS(ic) \
left = IC_LEFT(ic); \
right = IC_RIGHT(ic); \
result = IC_RESULT(ic);
// Given an integer value of pushedSize bytes on the stack,
// adjust it to be resultSize bytes, either by discarding
// the most significant bytes or by zero-padding.
//
// On exit from this macro, pushedSize will have been adjusted to
// equal resultSize, and ACC may be trashed.
#define ADJUST_PUSHED_RESULT(pushedSize, resultSize) \
/* If the pushed data is bigger than the result, \
* simply discard unused bytes. Icky, but works. \
*/ \
while (pushedSize > resultSize) \
{ \
D (emitcode (";", "discarding unused result byte."););\
emitcode ("pop", "acc"); \
pushedSize--; \
} \
if (pushedSize < resultSize) \
{ \
emitcode ("clr", "a"); \
/* Conversly, we haven't pushed enough here. \
* just zero-pad, and all is well. \
*/ \
while (pushedSize < resultSize) \
{ \
emitcode("push", "acc"); \
pushedSize++; \
} \
} \
assert(pushedSize == resultSize);
/*-----------------------------------------------------------------*/
/* genPlus - generates code for addition */
/*-----------------------------------------------------------------*/
static void
genPlus (iCode * ic)
{
int size, offset = 0;
bool pushResult = FALSE;
int rSize;
D (emitcode (";", "genPlus "););
/* special cases :- */
AOP_OP_3_NOFATAL (ic, pushResult);
if (pushResult)
{
D (emitcode (";", "genPlus: must push result: 3 ops in far space"););
}
if (!pushResult)
{
/* if literal, literal on the right or
if left requires ACC or right is already
in ACC */
if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
|| ((AOP_NEEDSACC (IC_LEFT (ic))) && !(AOP_NEEDSACC (IC_RIGHT (ic))))
|| AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
{
operand *t = IC_RIGHT (ic);
IC_RIGHT (ic) = IC_LEFT (ic);
IC_LEFT (ic) = t;
emitcode (";", "Swapped plus args.");
}
/* if both left & right are in bit
space */
if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
{
genPlusBits (ic);
goto release;
}
/* if left in bit space & right literal */
if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
{
emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
/* if result in bit space */
if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
{
if ((unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
emitcode ("cpl", "c");
outBitC (IC_RESULT (ic));
}
else
{
size = getDataSize (IC_RESULT (ic));
_startLazyDPSEvaluation ();
while (size--)
{
MOVA (aopGet (AOP (IC_RIGHT (ic)), offset, FALSE, FALSE, TRUE));
emitcode ("addc", "a,#00");
aopPut (AOP (IC_RESULT (ic)), "a", offset++);
}
_endLazyDPSEvaluation ();
}
goto release;
}
/* if I can do an increment instead
of add then GOOD for ME */
if (genPlusIncr (ic) == TRUE)
{
emitcode (";", "did genPlusIncr");
goto release;
}
}
size = getDataSize (pushResult ? IC_LEFT (ic) : IC_RESULT (ic));
_startLazyDPSEvaluation ();
while (size--)
{
if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC && !AOP_NEEDSACC(IC_RIGHT(ic)))
{
MOVA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE, TRUE));
if (offset == 0)
emitcode ("add", "a,%s",
aopGet (AOP (IC_RIGHT (ic)), offset, FALSE, FALSE, FALSE));
else
emitcode ("addc", "a,%s",
aopGet (AOP (IC_RIGHT (ic)), offset, FALSE, FALSE, FALSE));
}
else
{
if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC && (offset == 0))
{
/* right is going to use ACC or we would have taken the
* above branch.
*/
assert(AOP_NEEDSACC(IC_RIGHT(ic)));
TR_AP("#3");
D(emitcode(";", "+ AOP_ACC special case."););
emitcode("xch", "a, %s", DP2_RESULT_REG);
}
MOVA (aopGet (AOP (IC_RIGHT (ic)), offset, FALSE, FALSE, TRUE));
if (offset == 0)
{
if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC)
{
TR_AP("#4");
emitcode("add", "a, %s", DP2_RESULT_REG);
}
else
{
emitcode ("add", "a,%s",
aopGet (AOP(IC_LEFT(ic)), offset, FALSE, FALSE, FALSE));
}
}
else
{
emitcode ("addc", "a,%s",
aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE, FALSE));
}
}
if (!pushResult)
{
aopPut (AOP (IC_RESULT (ic)), "a", offset);
}
else
{
emitcode ("push", "acc");
}
offset++;
}
_endLazyDPSEvaluation ();
if (pushResult)
{
aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
size = getDataSize (IC_LEFT (ic));
rSize = getDataSize (IC_RESULT (ic));
ADJUST_PUSHED_RESULT(size, rSize);
_startLazyDPSEvaluation ();
while (size--)
{
emitcode ("pop", "acc");
aopPut (AOP (IC_RESULT (ic)), "a", size);
}
_endLazyDPSEvaluation ();
}
adjustArithmeticResult (ic);
release:
freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
}
/*-----------------------------------------------------------------*/
/* genMinusDec :- does subtraction with deccrement if possible */
/*-----------------------------------------------------------------*/
static bool
genMinusDec (iCode * ic)
{
unsigned int icount;
unsigned int size = getDataSize (IC_RESULT (ic));
/* will try to generate an increment */
/* if the right side is not a literal
we cannot */
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;
/* if decrement 16 bits in register */
if (AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
(size > 1) &&
(icount == 1))
{
symbol *tlbl;
int emitTlbl;
int labelRange;
/* If the next instruction is a goto and the goto target
* is <= 5 instructions previous to this, we can generate
* jumps straight to that target.
*/
if (ic->next && ic->next->op == GOTO
&& (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
&& labelRange <= 5)
{
emitcode (";", "tail decrement optimized (range %d)", labelRange);
tlbl = IC_LABEL (ic->next);
emitTlbl = 0;
}
else
{
tlbl = newiTempLabel (NULL);
emitTlbl = 1;
}
emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE, FALSE));
if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
IS_AOP_PREG (IC_RESULT (ic)))
emitcode ("cjne", "%s,#0xff,%05d$"
,aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE, FALSE)
,tlbl->key + 100);
else
{
emitcode ("mov", "a,#0xff");
emitcode ("cjne", "a,%s,%05d$"
,aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE, FALSE)
,tlbl->key + 100);
}
emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE, FALSE));
if (size > 2)
{
if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
IS_AOP_PREG (IC_RESULT (ic)))
emitcode ("cjne", "%s,#0xff,%05d$"
,aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE, FALSE)
,tlbl->key + 100);
else
{
emitcode ("cjne", "a,%s,%05d$"
,aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE, FALSE)
,tlbl->key + 100);
}
emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE, FALSE));
}
if (size > 3)
{
if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
IS_AOP_PREG (IC_RESULT (ic)))
emitcode ("cjne", "%s,#0xff,%05d$"
,aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE, FALSE)
,tlbl->key + 100);
else
{
emitcode ("cjne", "a,%s,%05d$"
,aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE, FALSE)
,tlbl->key + 100);
}
emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), MSB32, FALSE, FALSE, FALSE));
}
if (emitTlbl)
{
emitcode ("", "%05d$:", tlbl->key + 100);
}
return TRUE;
}
/* if the sizes are greater than 1 then we cannot */
if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
AOP_SIZE (IC_LEFT (ic)) > 1)
return FALSE;
/* we can if the aops of the left & result match or
if they are in registers and the registers are the
same */
if (
AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
{
_startLazyDPSEvaluation ();
while (icount--)
{
emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE, FALSE));
}
_endLazyDPSEvaluation ();
return TRUE;
}
return FALSE;
}
/*-----------------------------------------------------------------*/
/* addSign - complete with sign */
/*-----------------------------------------------------------------*/
static void
addSign (operand * result, int offset, int sign)
{
int size = (getDataSize (result) - offset);
if (size > 0)
{
_startLazyDPSEvaluation();
if (sign)
{
emitcode ("rlc", "a");
emitcode ("subb", "a,acc");
while (size--)
{
aopPut (AOP (result), "a", offset++);
}
}
else
{
while (size--)
{
aopPut (AOP (result), zero, offset++);
}
}
_endLazyDPSEvaluation();
}
}
/*-----------------------------------------------------------------*/
/* genMinusBits - generates code for subtraction of two bits */
/*-----------------------------------------------------------------*/
static void
genMinusBits (iCode * ic)
{
symbol *lbl = newiTempLabel (NULL);
D (emitcode (";", "genMinusBits "););
if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
{
emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
emitcode ("cpl", "c");
emitcode ("", "%05d$:", (lbl->key + 100));
outBitC (IC_RESULT (ic));
}
else
{
emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
emitcode ("subb", "a,acc");
emitcode ("jnb", "%s,%05d$", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
emitcode ("inc", "a");
emitcode ("", "%05d$:", (lbl->key + 100));
aopPut (AOP (IC_RESULT (ic)), "a", 0);
addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
}
}
/*-----------------------------------------------------------------*/
/* genMinus - generates code for subtraction */
/*-----------------------------------------------------------------*/
static void
genMinus (iCode * ic)
{
int size, offset = 0;
int rSize;
unsigned long lit = 0L;
bool pushResult = FALSE;
D (emitcode (";", "genMinus "););
aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
aopOp (IC_RIGHT (ic), ic, FALSE, TRUE);
if ((AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR) &&
(AOP_TYPE (IC_RIGHT (ic)) == AOP_DPTR2))
{
pushResult = TRUE;
}
else
{
aopOp (IC_RESULT (ic), ic, TRUE, AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR);
/* special cases :- */
/* if both left & right are in bit space */
if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
{
genMinusBits (ic);
goto release;
}
/* if I can do an decrement instead
of subtract then GOOD for ME */
if (genMinusDec (ic) == TRUE)
goto release;
}
size = getDataSize (pushResult ? IC_LEFT (ic) : IC_RESULT (ic));
if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
{
CLRC;
}
else
{
lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
lit = -(long) lit;
}
/* if literal, add a,#-lit, else normal subb */
_startLazyDPSEvaluation ();
while (size--)
{
MOVA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE, TRUE));
if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
emitcode ("subb", "a,%s",
aopGet (AOP (IC_RIGHT (ic)), offset, FALSE, FALSE, FALSE));
else
{
/* first add without previous c */
if (!offset) {
if (!size && lit==-1) {
emitcode ("dec", "a");
} else {
emitcode ("add", "a,#0x%02x",
(unsigned int) (lit & 0x0FFL));
}
} else {
emitcode ("addc", "a,#0x%02x",
(unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
}
}
if (pushResult)
{
emitcode ("push", "acc");
}
else
{
aopPut (AOP (IC_RESULT (ic)), "a", offset);
}
offset++;
}
_endLazyDPSEvaluation ();
if (pushResult)
{
aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
size = getDataSize (IC_LEFT (ic));
rSize = getDataSize (IC_RESULT (ic));
ADJUST_PUSHED_RESULT(size, rSize);
_startLazyDPSEvaluation ();
while (size--)
{
emitcode ("pop", "acc");
aopPut (AOP (IC_RESULT (ic)), "a", size);
}
_endLazyDPSEvaluation ();
}
adjustArithmeticResult (ic);
release:
freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
}
/*-----------------------------------------------------------------*/
/* genMultbits :- multiplication of bits */
/*-----------------------------------------------------------------*/
static void
genMultbits (operand * left,
operand * right,
operand * result,
iCode * ic)
{
emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
aopOp(result, ic, TRUE, FALSE);
outBitC (result);
}
/*-----------------------------------------------------------------*/
/* genMultOneByte : 8*8=8/16 bit multiplication */
/*-----------------------------------------------------------------*/
static void
genMultOneByte (operand * left,
operand * right,
operand * result,
iCode * ic)
{
sym_link *opetype = operandType (result);
symbol *lbl;
/* (if two literals: the value is computed before) */
/* if one literal, literal on the right */
if (AOP_TYPE (left) == AOP_LIT)
{
operand *t = right;
right = left;
left = t;
emitcode (";", "swapped left and right");
}
if (SPEC_USIGN(opetype)
// ignore the sign of left and right, what else can we do?
|| (SPEC_USIGN(operandType(left)) &&
SPEC_USIGN(operandType(right)))) {
// just an unsigned 8*8=8/16 multiply
//emitcode (";","unsigned");
emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE, TRUE));
MOVA (aopGet (AOP (left), 0, FALSE, FALSE, TRUE));
emitcode ("mul", "ab");
_G.accInUse++;
aopOp(result, ic, TRUE, FALSE);
if (AOP_SIZE(result)<1 || AOP_SIZE(result)>2)
{
// this should never happen
fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
AOP_SIZE(result), __FILE__, lineno);
exit (1);
}
aopPut (AOP (result), "a", 0);
_G.accInUse--;
if (AOP_SIZE(result)==2)
{
aopPut (AOP (result), "b", 1);
}
return;
}
// we have to do a signed multiply
emitcode (";", "signed");
emitcode ("clr", "F0"); // reset sign flag
MOVA (aopGet (AOP (left), 0, FALSE, FALSE, TRUE));
lbl=newiTempLabel(NULL);
emitcode ("jnb", "acc.7,%05d$", lbl->key+100);
// left side is negative, 8-bit two's complement, this fails for -128
emitcode ("setb", "F0"); // set sign flag
emitcode ("cpl", "a");
emitcode ("inc", "a");
emitcode ("", "%05d$:", lbl->key+100);
/* if literal */
if (AOP_TYPE(right)==AOP_LIT) {
signed char val=floatFromVal (AOP (right)->aopu.aop_lit);
/* AND literal negative */
if ((int) val < 0) {
emitcode ("cpl", "F0"); // complement sign flag
emitcode ("mov", "b,#0x%02x", -val);
} else {
emitcode ("mov", "b,#0x%02x", val);
}
} else {
lbl=newiTempLabel(NULL);
emitcode ("mov", "b,a");
emitcode ("mov", "a,%s", aopGet (AOP (right), 0, FALSE, FALSE, TRUE));
emitcode ("jnb", "acc.7,%05d$", lbl->key+100);
// right side is negative, 8-bit two's complement
emitcode ("cpl", "F0"); // complement sign flag
emitcode ("cpl", "a");
emitcode ("inc", "a");
emitcode ("", "%05d$:", lbl->key+100);
}
emitcode ("mul", "ab");
_G.accInUse++;
aopOp(result, ic, TRUE, FALSE);
if (AOP_SIZE(result)<1 || AOP_SIZE(result)>2)
{
// this should never happen
fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
AOP_SIZE(result), __FILE__, lineno);
exit (1);
}
lbl=newiTempLabel(NULL);
emitcode ("jnb", "F0,%05d$", lbl->key+100);
// only ONE op was negative, we have to do a 8/16-bit two's complement
emitcode ("cpl", "a"); // lsb
if (AOP_SIZE(result)==1) {
emitcode ("inc", "a");
} else {
emitcode ("add", "a,#1");
emitcode ("xch", "a,b");
emitcode ("cpl", "a"); // msb
emitcode ("addc", "a,#0");
emitcode ("xch", "a,b");
}
emitcode ("", "%05d$:", lbl->key+100);
aopPut (AOP (result), "a", 0);
_G.accInUse--;
if (AOP_SIZE(result)==2) {
aopPut (AOP (result), "b", 1);
}
}
/*-----------------------------------------------------------------*/
/* genMultTwoByte - use the DS390 MAC unit to do 16*16 multiply */
/*-----------------------------------------------------------------*/
static void genMultTwoByte (operand *left, operand *right,
operand *result, iCode *ic)
{
sym_link *retype = getSpec(operandType(right));
sym_link *letype = getSpec(operandType(left));
int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
symbol *lbl;
if (AOP_TYPE (left) == AOP_LIT) {
operand *t = right;
right = left;
left = t;
}
/* load up MB with right */
if (!umult) {
emitcode("clr","F0");
if (AOP_TYPE(right) == AOP_LIT) {
int val=floatFromVal (AOP (right)->aopu.aop_lit);
if (val < 0) {
emitcode("setb","F0");
val = -val;
}
emitcode ("mov","mb,#0x%02x",(val >> 8) & 0xff);
emitcode ("mov","mb,#0x%02x",val & 0xff);
} else {
lbl = newiTempLabel(NULL);
emitcode ("mov","b,%s",aopGet(AOP(right),0,FALSE,FALSE,TRUE));
emitcode ("mov","a,%s",aopGet(AOP(right),1,FALSE,FALSE,TRUE));
emitcode ("jnb","acc.7,%05d$",lbl->key+100);
emitcode ("xch", "a,b");
emitcode ("cpl","a");
emitcode ("add", "a,#1");
emitcode ("xch", "a,b");
emitcode ("cpl", "a"); // msb
emitcode ("addc", "a,#0");
emitcode ("setb","F0");
emitcode ("","%05d$:",lbl->key+100);
emitcode ("mov","mb,b");
emitcode ("mov","mb,a");
}
} else {
emitcode ("mov","mb,%s",aopGet(AOP(right),0,FALSE,FALSE,TRUE));
emitcode ("mov","mb,%s",aopGet(AOP(right),1,FALSE,FALSE,TRUE));
}
/* load up MA with left */
if (!umult) {
lbl = newiTempLabel(NULL);
emitcode ("mov","b,%s",aopGet(AOP(left),0,FALSE,FALSE,TRUE));
emitcode ("mov","a,%s",aopGet(AOP(left),1,FALSE,FALSE,TRUE));
emitcode ("jnb","acc.7,%05d$",lbl->key+100);
emitcode ("xch", "a,b");
emitcode ("cpl","a");
emitcode ("add", "a,#1");
emitcode ("xch", "a,b");
emitcode ("cpl", "a"); // msb
emitcode ("addc","a,#0");
emitcode ("jbc","F0,%05d$",lbl->key+100);
emitcode ("setb","F0");
emitcode ("","%05d$:",lbl->key+100);
emitcode ("mov","ma,b");
emitcode ("mov","ma,a");
} else {
emitcode ("mov","ma,%s",aopGet(AOP(left),0,FALSE,FALSE,TRUE));
emitcode ("mov","ma,%s",aopGet(AOP(left),1,FALSE,FALSE,TRUE));
}
/* wait for multiplication to finish */
lbl = newiTempLabel(NULL);
emitcode("","%05d$:", lbl->key+100);
emitcode("mov","a,mcnt1");
emitcode("anl","a,#0x80");
emitcode("jnz","%05d$",lbl->key+100);
freeAsmop (left, NULL, ic, TRUE);
freeAsmop (right, NULL, ic,TRUE);
aopOp(result, ic, TRUE, FALSE);
/* if unsigned then simple */
if (umult) {
emitcode ("mov","a,ma");
if (AOP_SIZE(result) >= 4) aopPut(AOP(result),"a",3);
emitcode ("mov","a,ma");
if (AOP_SIZE(result) >= 3) aopPut(AOP(result),"a",2);
aopPut(AOP(result),"ma",1);
aopPut(AOP(result),"ma",0);
} else {
emitcode("push","ma");
emitcode("push","ma");
emitcode("push","ma");
MOVA("ma");
/* negate result if needed */
lbl = newiTempLabel(NULL);
emitcode("jnb","F0,%05d$",lbl->key+100);
emitcode("cpl","a");
emitcode("add","a,#1");
emitcode("","%05d$:", lbl->key+100);
aopPut(AOP(result),"a",0);
emitcode("pop","acc");
lbl = newiTempLabel(NULL);
emitcode("jnb","F0,%05d$",lbl->key+100);
emitcode("cpl","a");
emitcode("addc","a,#0");
emitcode("","%05d$:", lbl->key+100);
aopPut(AOP(result),"a",1);
emitcode("pop","acc");
if (AOP_SIZE(result) >= 3) {
lbl = newiTempLabel(NULL);
emitcode("jnb","F0,%05d$",lbl->key+100);
emitcode("cpl","a");
emitcode("addc","a,#0");
emitcode("","%05d$:", lbl->key+100);
aopPut(AOP(result),"a",2);
}
emitcode("pop","acc");
if (AOP_SIZE(result) >= 4) {
lbl = newiTempLabel(NULL);
emitcode("jnb","F0,%05d$",lbl->key+100);
emitcode("cpl","a");
emitcode("addc","a,#0");
emitcode("","%05d$:", lbl->key+100);
aopPut(AOP(result),"a",3);
}
}
freeAsmop (result, NULL, ic, TRUE);
return ;
}
/*-----------------------------------------------------------------*/
/* genMult - generates code for multiplication */
/*-----------------------------------------------------------------*/
static void
genMult (iCode * ic)
{
operand *left = IC_LEFT (ic);
operand *right = IC_RIGHT (ic);
operand *result = IC_RESULT (ic);
D (emitcode (";", "genMult "););
/* assign the amsops */
AOP_OP_2 (ic);
/* special cases first */
/* both are bits */
if (AOP_TYPE (left) == AOP_CRY &&
AOP_TYPE (right) == AOP_CRY)
{
genMultbits (left, right, result, ic);
goto release;
}
/* if both are of size == 1 */
if (AOP_SIZE (left) == 1 &&
AOP_SIZE (right) == 1)
{
genMultOneByte (left, right, result, ic);
goto release;
}
if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
/* use the ds390 ARITHMETIC accel UNIT */
genMultTwoByte (left, right, result, ic);
return ;
}
/* should have been converted to function call */
assert (0);
release:
freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
freeAsmop (result, NULL, ic, TRUE);
}
/*-----------------------------------------------------------------*/
/* genDivbits :- division of bits */
/*-----------------------------------------------------------------*/
static void
genDivbits (operand * left,
operand * right,
operand * result,
iCode * ic)
{
char *l;
/* the result must be bit */
LOAD_AB_FOR_DIV (left, right, l);
emitcode ("div", "ab");
emitcode ("rrc", "a");
aopOp(result, ic, TRUE, FALSE);
aopPut (AOP (result), "c", 0);
}
/*-----------------------------------------------------------------*/
/* genDivOneByte : 8 bit division */
/*-----------------------------------------------------------------*/
static void
genDivOneByte (operand * left,
operand * right,
operand * result,
iCode * ic)
{
sym_link *opetype = operandType (result);
char *l;
symbol *lbl;
int size, offset;
offset = 1;
/* signed or unsigned */
if (SPEC_USIGN (opetype))
{
/* unsigned is easy */
LOAD_AB_FOR_DIV (left, right, l);
emitcode ("div", "ab");
_G.accInUse++;
aopOp(result, ic, TRUE, FALSE);
aopPut (AOP (result), "a", 0);
_G.accInUse--;
size = AOP_SIZE (result) - 1;
while (size--)
{
aopPut (AOP (result), zero, offset++);
}
return;
}
/* signed is a little bit more difficult */
/* save the signs of the operands */
l = aopGet (AOP (left), 0, FALSE, FALSE, TRUE);
MOVA (l);
emitcode ("xrl", "a,%s", aopGet (AOP (right), 0, FALSE, TRUE, FALSE));
emitcode ("push", "acc"); /* save it on the stack */
/* now sign adjust for both left & right */
l = aopGet (AOP (right), 0, FALSE, FALSE, TRUE);
MOVA (l);
lbl = newiTempLabel (NULL);
emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
emitcode ("cpl", "a");
emitcode ("inc", "a");
emitcode ("", "%05d$:", (lbl->key + 100));
emitcode ("mov", "b,a");
/* sign adjust left side */
l = aopGet (AOP (left), 0, FALSE, FALSE, TRUE);
MOVA (l);
lbl = newiTempLabel (NULL);
emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
emitcode ("cpl", "a");
emitcode ("inc", "a");
emitcode ("", "%05d$:", (lbl->key + 100));
/* now the division */
emitcode ("nop", "; workaround for DS80C390 div bug.");
emitcode ("div", "ab");
/* we are interested in the lower order
only */
emitcode ("mov", "b,a");
lbl = newiTempLabel (NULL);
emitcode ("pop", "acc");
/* if there was an over flow we don't
adjust the sign of the result */
emitcode ("jb", "ov,%05d$", (lbl->key + 100));
emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
CLRC;
emitcode ("clr", "a");
emitcode ("subb", "a,b");
emitcode ("mov", "b,a");
emitcode ("", "%05d$:", (lbl->key + 100));
/* now we are done */
_G.accInUse++;
aopOp(result, ic, TRUE, FALSE);
aopPut (AOP (result), "b", 0);
size = AOP_SIZE (result) - 1;
if (size > 0)
{
emitcode ("mov", "c,b.7");
emitcode ("subb", "a,acc");
}
while (size--)
{
aopPut (AOP (result), "a", offset++);
}
_G.accInUse--;
}
/*-----------------------------------------------------------------*/
/* genDivTwoByte - use the DS390 MAC unit to do 16/16 divide */
/*-----------------------------------------------------------------*/
static void genDivTwoByte (operand *left, operand *right,
operand *result, iCode *ic)
{
sym_link *retype = getSpec(operandType(right));
sym_link *letype = getSpec(operandType(left));
int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
symbol *lbl;
/* load up MA with left */
if (!umult) {
emitcode("clr","F0");
lbl = newiTempLabel(NULL);
emitcode ("mov","b,%s",aopGet(AOP(left),0,FALSE,FALSE,TRUE));
emitcode ("mov","a,%s",aopGet(AOP(left),1,FALSE,FALSE,TRUE));
emitcode ("jnb","acc.7,%05d$",lbl->key+100);
emitcode ("xch", "a,b");
emitcode ("cpl","a");
emitcode ("add", "a,#1");
emitcode ("xch", "a,b");
emitcode ("cpl", "a"); // msb
emitcode ("addc","a,#0");
emitcode ("setb","F0");
emitcode ("","%05d$:",lbl->key+100);
emitcode ("mov","ma,b");
emitcode ("mov","ma,a");
} else {
emitcode ("mov","ma,%s",aopGet(AOP(left),0,FALSE,FALSE,TRUE));
emitcode ("mov","ma,%s",aopGet(AOP(left),1,FALSE,FALSE,TRUE));
}
/* load up MB with right */
if (!umult) {
if (AOP_TYPE(right) == AOP_LIT) {
int val=floatFromVal (AOP (right)->aopu.aop_lit);
if (val < 0) {
lbl = newiTempLabel(NULL);
emitcode ("jbc","F0,%05d$",lbl->key+100);
emitcode("setb","F0");
emitcode ("","%05d$:",lbl->key+100);
val = -val;
}
emitcode ("mov","mb,#0x%02x",(val >> 8) & 0xff);
emitcode ("mov","mb,#0x%02x",val & 0xff);
} else {
lbl = newiTempLabel(NULL);
emitcode ("mov","b,%s",aopGet(AOP(right),0,FALSE,FALSE,TRUE));
emitcode ("mov","a,%s",aopGet(AOP(right),1,FALSE,FALSE,TRUE));
emitcode ("jnb","acc.7,%05d$",lbl->key+100);
emitcode ("xch", "a,b");
emitcode ("cpl","a");
emitcode ("add", "a,#1");
emitcode ("xch", "a,b");
emitcode ("cpl", "a"); // msb
emitcode ("addc", "a,#0");
emitcode ("jbc","F0,%05d$",lbl->key+100);
emitcode ("setb","F0");
emitcode ("","%05d$:",lbl->key+100);
emitcode ("mov","mb,b");
emitcode ("mov","mb,a");
}
} else {
emitcode ("mov","mb,%s",aopGet(AOP(right),0,FALSE,FALSE,TRUE));
emitcode ("mov","mb,%s",aopGet(AOP(right),1,FALSE,FALSE,TRUE));
}
/* wait for multiplication to finish */
lbl = newiTempLabel(NULL);
emitcode("","%05d$:", lbl->key+100);
emitcode("mov","a,mcnt1");
emitcode("anl","a,#0x80");
emitcode("jnz","%05d$",lbl->key+100);
freeAsmop (left, NULL, ic, TRUE);
freeAsmop (right, NULL, ic,TRUE);
aopOp(result, ic, TRUE, FALSE);
/* if unsigned then simple */
if (umult) {
aopPut(AOP(result),"ma",1);
aopPut(AOP(result),"ma",0);
} else {
emitcode("push","ma");
MOVA("ma");
/* negate result if needed */
lbl = newiTempLabel(NULL);
emitcode("jnb","F0,%05d$",lbl->key+100);
emitcode("cpl","a");
emitcode("add","a,#1");
emitcode("","%05d$:", lbl->key+100);
aopPut(AOP(result),"a",0);
emitcode("pop","acc");
lbl = newiTempLabel(NULL);
emitcode("jnb","F0,%05d$",lbl->key+100);
emitcode("cpl","a");
emitcode("addc","a,#0");
emitcode("","%05d$:", lbl->key+100);
aopPut(AOP(result),"a",1);
}
freeAsmop (result, NULL, ic, TRUE);
return ;
}
/*-----------------------------------------------------------------*/
/* genDiv - generates code for division */
/*-----------------------------------------------------------------*/
static void
genDiv (iCode * ic)
{
operand *left = IC_LEFT (ic);
operand *right = IC_RIGHT (ic);
operand *result = IC_RESULT (ic);
D (emitcode (";", "genDiv "););
/* assign the amsops */
AOP_OP_2 (ic);
/* special cases first */
/* both are bits */
if (AOP_TYPE (left) == AOP_CRY &&
AOP_TYPE (right) == AOP_CRY)
{
genDivbits (left, right, result, ic);
goto release;
}
/* if both are of size == 1 */
if (AOP_SIZE (left) == 1 &&
AOP_SIZE (right) == 1)
{
genDivOneByte (left, right, result, ic);
goto release;
}
if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
/* use the ds390 ARITHMETIC accel UNIT */
genDivTwoByte (left, right, result, ic);
return ;
}
/* should have been converted to function call */
assert (0);
release:
freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
freeAsmop (result, NULL, ic, TRUE);
}
/*-----------------------------------------------------------------*/
/* genModbits :- modulus of bits */
/*-----------------------------------------------------------------*/
static void
genModbits (operand * left,
operand * right,
operand * result,
iCode * ic)
{
char *l;
/* the result must be bit */
LOAD_AB_FOR_DIV (left, right, l);
emitcode ("div", "ab");
emitcode ("mov", "a,b");
emitcode ("rrc", "a");
aopOp(result, ic, TRUE, FALSE);
aopPut (AOP (result), "c", 0);
}
/*-----------------------------------------------------------------*/
/* genModOneByte : 8 bit modulus */
/*-----------------------------------------------------------------*/
static void
genModOneByte (operand * left,
operand * right,
operand * result,
iCode * ic)
{
sym_link *opetype = operandType (result);
char *l;
symbol *lbl;
/* signed or unsigned */
if (SPEC_USIGN (opetype))
{
/* unsigned is easy */
LOAD_AB_FOR_DIV (left, right, l);
emitcode ("div", "ab");
aopOp(result, ic, TRUE, FALSE);
aopPut (AOP (result), "b", 0);
return;
}
/* signed is a little bit more difficult */
/* save the signs of the operands */
l = aopGet (AOP (left), 0, FALSE, FALSE, TRUE);
MOVA (l);
emitcode ("xrl", "a,%s", aopGet (AOP (right), 0, FALSE, FALSE, FALSE));
emitcode ("push", "acc"); /* save it on the stack */
/* now sign adjust for both left & right */
l = aopGet (AOP (right), 0, FALSE, FALSE, TRUE);
MOVA (l);
lbl = newiTempLabel (NULL);
emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
emitcode ("cpl", "a");
emitcode ("inc", "a");
emitcode ("", "%05d$:", (lbl->key + 100));
emitcode ("mov", "b,a");
/* sign adjust left side */
l = aopGet (AOP (left), 0, FALSE, FALSE, TRUE);
MOVA (l);
lbl = newiTempLabel (NULL);
emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
emitcode ("cpl", "a");
emitcode ("inc", "a");
emitcode ("", "%05d$:", (lbl->key + 100));
/* now the multiplication */
emitcode ("nop", "; workaround for DS80C390 div bug.");
emitcode ("div", "ab");
/* we are interested in the lower order
only */
lbl = newiTempLabel (NULL);
emitcode ("pop", "acc");
/* if there was an over flow we don't
adjust the sign of the result */
emitcode ("jb", "ov,%05d$", (lbl->key + 100));
emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
CLRC;
emitcode ("clr", "a");
emitcode ("subb", "a,b");
emitcode ("mov", "b,a");
emitcode ("", "%05d$:", (lbl->key + 100));
/* now we are done */
aopOp(result, ic, TRUE, FALSE);
aopPut (AOP (result), "b", 0);
}
/*-----------------------------------------------------------------*/
/* genModTwoByte - use the DS390 MAC unit to do 16%16 modulus */
/*-----------------------------------------------------------------*/
static void genModTwoByte (operand *left, operand *right,
operand *result, iCode *ic)
{
sym_link *retype = getSpec(operandType(right));
sym_link *letype = getSpec(operandType(left));
int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
symbol *lbl;
/* load up MA with left */
if (!umult) {
lbl = newiTempLabel(NULL);
emitcode ("mov","b,%s",aopGet(AOP(left),0,FALSE,FALSE,TRUE));
emitcode ("mov","a,%s",aopGet(AOP(left),1,FALSE,FALSE,TRUE));
emitcode ("jnb","acc.7,%05d$",lbl->key+100);
emitcode ("xch", "a,b");
emitcode ("cpl","a");
emitcode ("add", "a,#1");
emitcode ("xch", "a,b");
emitcode ("cpl", "a"); // msb
emitcode ("addc","a,#0");
emitcode ("","%05d$:",lbl->key+100);
emitcode ("mov","ma,b");
emitcode ("mov","ma,a");
} else {
emitcode ("mov","ma,%s",aopGet(AOP(left),0,FALSE,FALSE,TRUE));
emitcode ("mov","ma,%s",aopGet(AOP(left),1,FALSE,FALSE,TRUE));
}
/* load up MB with right */
if (!umult) {
if (AOP_TYPE(right) == AOP_LIT) {
int val=floatFromVal (AOP (right)->aopu.aop_lit);
if (val < 0) {
val = -val;
}
emitcode ("mov","mb,#0x%02x",(val >> 8) & 0xff);
emitcode ("mov","mb,#0x%02x",val & 0xff);
} else {
lbl = newiTempLabel(NULL);
emitcode ("mov","b,%s",aopGet(AOP(right),0,FALSE,FALSE,TRUE));
emitcode ("mov","a,%s",aopGet(AOP(right),1,FALSE,FALSE,TRUE));
emitcode ("jnb","acc.7,%05d$",lbl->key+100);
emitcode ("xch", "a,b");
emitcode ("cpl","a");
emitcode ("add", "a,#1");
emitcode ("xch", "a,b");
emitcode ("cpl", "a"); // msb
emitcode ("addc", "a,#0");
emitcode ("","%05d$:",lbl->key+100);
emitcode ("mov","mb,b");
emitcode ("mov","mb,a");
}
} else {
emitcode ("mov","mb,%s",aopGet(AOP(right),0,FALSE,FALSE,TRUE));
emitcode ("mov","mb,%s",aopGet(AOP(right),1,FALSE,FALSE,TRUE));
}
/* wait for multiplication to finish */
lbl = newiTempLabel(NULL);
emitcode("","%05d$:", lbl->key+100);
emitcode("mov","a,mcnt1");
emitcode("anl","a,#0x80");
emitcode("jnz","%05d$",lbl->key+100);
freeAsmop (left, NULL, ic, TRUE);
freeAsmop (right, NULL, ic,TRUE);
aopOp(result, ic, TRUE, FALSE);
aopPut(AOP(result),"mb",1);
aopPut(AOP(result),"mb",0);
freeAsmop (result, NULL, ic, TRUE);
return ;
}
/*-----------------------------------------------------------------*/
/* genMod - generates code for division */
/*-----------------------------------------------------------------*/
static void
genMod (iCode * ic)
{
operand *left = IC_LEFT (ic);
operand *right = IC_RIGHT (ic);
operand *result = IC_RESULT (ic);
D (emitcode (";", "genMod "); );
/* assign the amsops */
AOP_OP_2 (ic);
/* special cases first */
/* both are bits */
if (AOP_TYPE (left) == AOP_CRY &&
AOP_TYPE (right) == AOP_CRY)
{
genModbits (left, right, result, ic);
goto release;
}
/* if both are of size == 1 */
if (AOP_SIZE (left) == 1 &&
AOP_SIZE (right) == 1)
{
genModOneByte (left, right, result, ic);
goto release;
}
if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
/* use the ds390 ARITHMETIC accel UNIT */
genModTwoByte (left, right, result, ic);
return ;
}
/* should have been converted to function call */
assert (0);
release:
freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
freeAsmop (result, NULL, ic, TRUE);
}
/*-----------------------------------------------------------------*/
/* genIfxJump :- will create a jump depending on the ifx */
/*-----------------------------------------------------------------*/
static void
genIfxJump (iCode * ic, char *jval)
{
symbol *jlbl;
symbol *tlbl = newiTempLabel (NULL);
char *inst;
D (emitcode (";", "genIfxJump ");
);
/* if true label then we jump if condition
supplied is true */
if (IC_TRUE (ic))
{
jlbl = IC_TRUE (ic);
inst = ((strcmp (jval, "a") == 0 ? "jz" :
(strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
}
else
{
/* false label is present */
jlbl = IC_FALSE (ic);
inst = ((strcmp (jval, "a") == 0 ? "jnz" :
(strcmp (jval, "c") == 0 ? "jc" : "jb")));
}
if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
emitcode (inst, "%s,%05d$", jval, (tlbl->key + 100));
else
emitcode (inst, "%05d$", tlbl->key + 100);
emitcode ("ljmp", "%05d$", jlbl->key + 100);
emitcode ("", "%05d$:", tlbl->key + 100);
/* mark the icode as generated */
ic->generated = 1;
}
/*-----------------------------------------------------------------*/
/* genCmp :- greater or less than comparison */
/*-----------------------------------------------------------------*/
static void
genCmp (operand * left, operand * right,
iCode * ic, iCode * ifx, int sign)
{
int size, offset = 0;
unsigned long lit = 0L;
operand *result;
D (emitcode (";", "genCmp");
);
result = IC_RESULT (ic);
/* if left & right are bit variables */
if (AOP_TYPE (left) == AOP_CRY &&
AOP_TYPE (right) == AOP_CRY)
{
emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
emitcode ("anl", "c,/%s", AOP (left)->aopu.aop_dir);
}
else
{
/* subtract right from left if at the
end the carry flag is set then we know that
left is greater than right */
size = max (AOP_SIZE (left), AOP_SIZE (right));
/* if unsigned char cmp with lit, do cjne left,#right,zz */
if ((size == 1) && !sign &&
(AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
{
symbol *lbl = newiTempLabel (NULL);
emitcode ("cjne", "%s,%s,%05d$",
aopGet (AOP (left), offset, FALSE, FALSE, FALSE),
aopGet (AOP (right), offset, FALSE, FALSE, FALSE),
lbl->key + 100);
emitcode ("", "%05d$:", lbl->key + 100);
}
else
{
if (AOP_TYPE (right) == AOP_LIT)
{
lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
/* optimize if(x < 0) or if(x >= 0) */
if (lit == 0L)
{
if (!sign)
{
CLRC;
}
else
{
MOVA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE, FALSE, TRUE));
freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
aopOp (result, ic, FALSE, FALSE);
if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
{
freeAsmop (result, NULL, ic, TRUE);
genIfxJump (ifx, "acc.7");
return;
}
else
{
emitcode ("rlc", "a");
}
goto release_freedLR;
}
goto release;
}
}
CLRC;
while (size--)
{
emitcode (";", "genCmp #1: %d/%d/%d", size, sign, offset);
MOVA (aopGet (AOP (left), offset, FALSE, FALSE, TRUE));
emitcode (";", "genCmp #2");
if (sign && (size == 0))
{
emitcode (";", "genCmp #3");
emitcode ("xrl", "a,#0x80");
if (AOP_TYPE (right) == AOP_LIT)
{
unsigned long lit = (unsigned long)
floatFromVal (AOP (right)->aopu.aop_lit);
emitcode (";", "genCmp #3.1");
emitcode ("subb", "a,#0x%02x",
0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
}
else
{
emitcode (";", "genCmp #3.2");
if (AOP_NEEDSACC (right))
{
emitcode ("push", "acc");
}
emitcode ("mov", "b,%s", aopGet (AOP (right), offset++,
FALSE, FALSE, FALSE));
emitcode ("xrl", "b,#0x80");
if (AOP_NEEDSACC (right))
{
emitcode ("pop", "acc");
}
emitcode ("subb", "a,b");
}
}
else
{
const char *s;
emitcode (";", "genCmp #4");
if (AOP_NEEDSACC (right))
{
/* Yuck!! */
emitcode (";", "genCmp #4.1");
emitcode ("xch", "a, b");
MOVA (aopGet (AOP (right), offset++, FALSE, FALSE, TRUE));
emitcode ("xch", "a, b");
s = "b";
}
else
{
emitcode (";", "genCmp #4.2");
s = aopGet (AOP (right), offset++, FALSE, FALSE, FALSE);
}
emitcode ("subb", "a,%s", s);
}
}
}
}
release:
/* Don't need the left & right operands any more; do need the result. */
freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
aopOp (result, ic, FALSE, FALSE);
release_freedLR:
if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
{
outBitC (result);
}
else
{
/* if the result is used in the next
ifx conditional branch then generate
code a little differently */
if (ifx)
{
genIfxJump (ifx, "c");
}
else
{
outBitC (result);
}
/* leave the result in acc */
}
freeAsmop (result, NULL, ic, TRUE);
}
/*-----------------------------------------------------------------*/
/* genCmpGt :- greater than comparison */
/*-----------------------------------------------------------------*/
static void
genCmpGt (iCode * ic, iCode * ifx)
{
operand *left, *right;
sym_link *letype, *retype;
int sign;
D (emitcode (";", "genCmpGt ");
);
left = IC_LEFT (ic);
right = IC_RIGHT (ic);
letype = getSpec (operandType (left));
retype = getSpec (operandType (right));
sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
/* assign the left & right amsops */
AOP_OP_2 (ic);
genCmp (right, left, ic, ifx, sign);
}
/*-----------------------------------------------------------------*/
/* genCmpLt - less than comparisons */
/*-----------------------------------------------------------------*/
static void
genCmpLt (iCode * ic, iCode * ifx)
{
operand *left, *right;
sym_link *letype, *retype;
int sign;
D (emitcode (";", "genCmpLt "););
left = IC_LEFT (ic);
right = IC_RIGHT (ic);
letype = getSpec (operandType (left));
retype = getSpec (operandType (right));
sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
/* assign the left & right amsops */
AOP_OP_2 (ic);
genCmp (left, right, ic, ifx, sign);
}
/*-----------------------------------------------------------------*/
/* gencjneshort - compare and jump if not equal */
/*-----------------------------------------------------------------*/
static void
gencjneshort (operand * left, operand * right, symbol * lbl)
{
int size = max (AOP_SIZE (left), AOP_SIZE (right));
int offset = 0;
unsigned long lit = 0L;
D (emitcode (";", "gencjneshort");
);
/* if the left side is a literal or
if the right is in a pointer register and left
is not */
if ((AOP_TYPE (left) == AOP_LIT) ||
(IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
{
operand *t = right;
right = left;
left = t;
}
if (AOP_TYPE (right) == AOP_LIT)
lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
if (opIsGptr (left) || opIsGptr (right))
{
/* We are comparing a generic pointer to something.
* Exclude the generic type byte from the comparison.
*/
size--;
D (emitcode (";", "cjneshort: generic ptr special case.");
)
}
/* if the right side is a literal then anything goes */
if (AOP_TYPE (right) == AOP_LIT &&
AOP_TYPE (left) != AOP_DIR)
{
while (size--)
{
char *l = aopGet (AOP (left), offset, FALSE, FALSE, TRUE);
MOVA (l);
emitcode ("cjne", "a,%s,%05d$",
aopGet (AOP (right), offset, FALSE, FALSE, FALSE),
lbl->key + 100);
offset++;
}
}
/* if the right side is in a register or in direct space or
if the left is a pointer register & right is not */
else if (AOP_TYPE (right) == AOP_REG ||
AOP_TYPE (right) == AOP_DIR ||
(AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
(IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
{
while (size--)
{
MOVA (aopGet (AOP (left), offset, FALSE, FALSE, TRUE));
if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
emitcode ("jnz", "%05d$", lbl->key + 100);
else
emitcode ("cjne", "a,%s,%05d$",
aopGet (AOP (right), offset, FALSE, TRUE, FALSE),
lbl->key + 100);
offset++;
}
}
else
{
/* right is a pointer reg need both a & b */
while (size--)
{
char *l = aopGet (AOP (left), offset, FALSE, FALSE, TRUE);
if (strcmp (l, "b"))
emitcode ("mov", "b,%s", l);
MOVA (aopGet (AOP (right), offset, FALSE, FALSE, TRUE));
emitcode ("cjne", "a,b,%05d$", lbl->key + 100);
offset++;
}
}
}
/*-----------------------------------------------------------------*/
/* gencjne - compare and jump if not equal */
/*-----------------------------------------------------------------*/
static void
gencjne (operand * left, operand * right, symbol * lbl)
{
symbol *tlbl = newiTempLabel (NULL);
D (emitcode (";", "gencjne");
);
gencjneshort (left, right, lbl);
emitcode ("mov", "a,%s", one);
emitcode ("sjmp", "%05d$", tlbl->key + 100);
emitcode ("", "%05d$:", lbl->key + 100);
emitcode ("clr", "a");
emitcode ("", "%05d$:", tlbl->key + 100);
}
/*-----------------------------------------------------------------*/
/* genCmpEq - generates code for equal to */
/*-----------------------------------------------------------------*/
static void
genCmpEq (iCode * ic, iCode * ifx)
{
operand *left, *right, *result;
D (emitcode (";", "genCmpEq ");
);
AOP_OP_2 (ic);
AOP_SET_LOCALS (ic);
/* if literal, literal on the right or
if the right is in a pointer register and left
is not */
if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
(IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
{
operand *t = IC_RIGHT (ic);
IC_RIGHT (ic) = IC_LEFT (ic);
IC_LEFT (ic) = t;
}
if (ifx && /* !AOP_SIZE(result) */
OP_SYMBOL (result) &&
OP_SYMBOL (result)->regType == REG_CND)
{
symbol *tlbl;
/* if they are both bit variables */
if (AOP_TYPE (left) == AOP_CRY &&
((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
{
if (AOP_TYPE (right) == AOP_LIT)
{
unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
if (lit == 0L)
{
emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
emitcode ("cpl", "c");
}
else if (lit == 1L)
{
emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
}
else
{
emitcode ("clr", "c");
}
/* AOP_TYPE(right) == AOP_CRY */
}
else
{
symbol *lbl = newiTempLabel (NULL);
emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
emitcode ("cpl", "c");
emitcode ("", "%05d$:", (lbl->key + 100));
}
/* if true label then we jump if condition
supplied is true */
tlbl = newiTempLabel (NULL);
if (IC_TRUE (ifx))
{
emitcode ("jnc", "%05d$", tlbl->key + 100);
emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
}
else
{
emitcode ("jc", "%05d$", tlbl->key + 100);
emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
}
emitcode ("", "%05d$:", tlbl->key + 100);
}
else
{
tlbl = newiTempLabel (NULL);
gencjneshort (left, right, tlbl);
if (IC_TRUE (ifx))
{
emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
emitcode ("", "%05d$:", tlbl->key + 100);
}
else
{
symbol *lbl = newiTempLabel (NULL);
emitcode ("sjmp", "%05d$", lbl->key + 100);
emitcode ("", "%05d$:", tlbl->key + 100);
emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
emitcode ("", "%05d$:", lbl->key + 100);
}
}
/* mark the icode as generated */
ifx->generated = 1;
freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
return;
}
/* if they are both bit variables */
if (AOP_TYPE (left) == AOP_CRY &&
((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
{
if (AOP_TYPE (right) == AOP_LIT)
{
unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
if (lit == 0L)
{
emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
emitcode ("cpl", "c");
}
else if (lit == 1L)
{
emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
}
else
{
emitcode ("clr", "c");
}
/* AOP_TYPE(right) == AOP_CRY */
}
else
{
symbol *lbl = newiTempLabel (NULL);
emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
emitcode ("cpl", "c");
emitcode ("", "%05d$:", (lbl->key + 100));
}
freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
aopOp (result, ic, TRUE, FALSE);
/* c = 1 if egal */
if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
{
outBitC (result);
goto release;
}
if (ifx)
{
genIfxJump (ifx, "c");
goto release;
}
/* if the result is used in an arithmetic operation
then put the result in place */
outBitC (result);
}
else
{
gencjne (left, right, newiTempLabel (NULL));
freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
aopOp (result, ic, TRUE, FALSE);
if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
{
aopPut (AOP (result), "a", 0);
goto release;
}
if (ifx)
{
genIfxJump (ifx, "a");
goto release;
}
/* if the result is used in an arithmetic operation
then put the result in place */
if (AOP_TYPE (result) != AOP_CRY)
outAcc (result);
/* leave the result in acc */
}
release:
freeAsmop (result, NULL, ic, TRUE);
}
/*-----------------------------------------------------------------*/
/* ifxForOp - returns the icode containing the ifx for operand */
/*-----------------------------------------------------------------*/
static iCode *
ifxForOp (operand * op, iCode * ic)
{
/* if true symbol then needs to be assigned */
if (IS_TRUE_SYMOP (op))
return NULL;
/* if this has register type condition and
the next instruction is ifx with the same operand
and live to of the operand is upto the ifx only then */
if (ic->next &&
ic->next->op == IFX &&
IC_COND (ic->next)->key == op->key &&
OP_SYMBOL (op)->liveTo <= ic->next->seq)
return ic->next;
return NULL;
}
/*-----------------------------------------------------------------*/
/* genAndOp - for && operation */
/*-----------------------------------------------------------------*/
static void
genAndOp (iCode * ic)
{
operand *left, *right, *result;
symbol *tlbl;
D (emitcode (";", "genAndOp "););
/* note here that && operations that are in an
if statement are taken away by backPatchLabels
only those used in arthmetic operations remain */
AOP_OP_2 (ic);
AOP_SET_LOCALS (ic);
/* if both are bit variables */
if (AOP_TYPE (left) == AOP_CRY &&
AOP_TYPE (right) == AOP_CRY)
{
emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
aopOp (result,ic,FALSE, FALSE);
outBitC (result);
}
else
{
tlbl = newiTempLabel (NULL);
toBoolean (left);
emitcode ("jz", "%05d$", tlbl->key + 100);
toBoolean (right);
emitcode ("", "%05d$:", tlbl->key + 100);
freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
aopOp (result,ic,FALSE, FALSE);
outBitAcc (result);
}
freeAsmop (result, NULL, ic, TRUE);
}
/*-----------------------------------------------------------------*/
/* genOrOp - for || operation */
/*-----------------------------------------------------------------*/
static void
genOrOp (iCode * ic)
{
operand *left, *right, *result;
symbol *tlbl;
D (emitcode (";", "genOrOp "););
/* note here that || operations that are in an
if statement are taken away by backPatchLabels
only those used in arthmetic operations remain */
AOP_OP_2 (ic);
AOP_SET_LOCALS (ic);
/* if both are bit variables */
if (AOP_TYPE (left) == AOP_CRY &&
AOP_TYPE (right) == AOP_CRY)
{
emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
aopOp (result,ic,FALSE, FALSE);
outBitC (result);
}
else
{
tlbl = newiTempLabel (NULL);
toBoolean (left);
emitcode ("jnz", "%05d$", tlbl->key + 100);
toBoolean (right);
emitcode ("", "%05d$:", tlbl->key + 100);
freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
aopOp (result,ic,FALSE, FALSE);
outBitAcc (result);
}
freeAsmop (result, NULL, ic, TRUE);
}
/*-----------------------------------------------------------------*/
/* isLiteralBit - test if lit == 2^n */
/*-----------------------------------------------------------------*/
static int
isLiteralBit (unsigned long lit)
{
unsigned long pw[32] =
{1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
0x100L, 0x200L, 0x400L, 0x800L,
0x1000L, 0x2000L, 0x4000L, 0x8000L,
0x10000L, 0x20000L, 0x40000L, 0x80000L,
0x100000L, 0x200000L, 0x400000L, 0x800000L,
0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
int idx;
for (idx = 0; idx < 32; idx++)
if (lit == pw[idx])
return idx + 1;
return 0;
}
/*-----------------------------------------------------------------*/
/* continueIfTrue - */
/*-----------------------------------------------------------------*/
static void
continueIfTrue (iCode * ic)
{
if (IC_TRUE (ic))
emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
ic->generated = 1;
}
/*-----------------------------------------------------------------*/
/* jmpIfTrue - */
/*-----------------------------------------------------------------*/
static void
jumpIfTrue (iCode * ic)
{
if (!IC_TRUE (ic))
emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
ic->generated = 1;
}
/*-----------------------------------------------------------------*/
/* jmpTrueOrFalse - */
/*-----------------------------------------------------------------*/
static void
jmpTrueOrFalse (iCode * ic, symbol * tlbl)
{
// ugly but optimized by peephole
if (IC_TRUE (ic))
{
symbol *nlbl = newiTempLabel (NULL);
emitcode ("sjmp", "%05d$", nlbl->key + 100);
emitcode ("", "%05d$:", tlbl->key + 100);
emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
emitcode ("", "%05d$:", nlbl->key + 100);
}
else
{
emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
emitcode ("", "%05d$:", tlbl->key + 100);
}
ic->generated = 1;
}
// Generate code to perform a bit-wise logic operation
// on two operands in far space (assumed to already have been
// aopOp'd by the AOP_OP_3_NOFATAL macro), storing the result
// in far space. This requires pushing the result on the stack
// then popping it into the result.
static void
genFarFarLogicOp(iCode *ic, char *logicOp)
{
int size, resultSize, compSize;
int offset = 0;
TR_AP("#5");
D(emitcode(";", "%s special case for 3 far operands.", logicOp););
compSize = AOP_SIZE(IC_LEFT(ic)) < AOP_SIZE(IC_RIGHT(ic)) ?
AOP_SIZE(IC_LEFT(ic)) : AOP_SIZE(IC_RIGHT(ic));
_startLazyDPSEvaluation();
for (size = compSize; (size--); offset++)
{
MOVA (aopGet (AOP (IC_LEFT(ic)), offset, FALSE, FALSE, TRUE));
emitcode ("mov", "%s, acc", DP2_RESULT_REG);
MOVA (aopGet (AOP (IC_RIGHT(ic)), offset, FALSE, FALSE, TRUE));
emitcode (logicOp, "a,%s", DP2_RESULT_REG);
emitcode ("push", "acc");
}
_endLazyDPSEvaluation();
freeAsmop (IC_LEFT(ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
freeAsmop (IC_RIGHT(ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
resultSize = AOP_SIZE(IC_RESULT(ic));
ADJUST_PUSHED_RESULT(compSize, resultSize);
_startLazyDPSEvaluation();
while (compSize--)
{
emitcode ("pop", "acc");
aopPut (AOP (IC_RESULT (ic)), "a", compSize);
}
_endLazyDPSEvaluation();
freeAsmop(IC_RESULT (ic), NULL, ic, TRUE);
}
/*-----------------------------------------------------------------*/
/* genAnd - code for and */
/*-----------------------------------------------------------------*/
static void
genAnd (iCode * ic, iCode * ifx)
{
operand *left, *right, *result;
int size, offset = 0;
unsigned long lit = 0L;
int bytelit = 0;
char buffer[10];
bool pushResult;
D (emitcode (";", "genAnd "););
AOP_OP_3_NOFATAL (ic, pushResult);
AOP_SET_LOCALS (ic);
if (pushResult)
{
genFarFarLogicOp(ic, "anl");
return;
}
#ifdef DEBUG_TYPE
emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
AOP_TYPE (result),
AOP_TYPE (left), AOP_TYPE (right));
emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
AOP_SIZE (result),
AOP_SIZE (left), AOP_SIZE (right));
#endif
/* if left is a literal & right is not then exchange them */
if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
#ifdef LOGIC_OPS_BROKEN
|| AOP_NEEDSACC (left)
#endif
)
{
operand *tmp = right;
right = left;
left = tmp;
}
/* if result = right then exchange them */
if (sameRegs (AOP (result), AOP (right)))
{
operand *tmp = right;
right = left;
left = tmp;
}
/* if right is bit then exchange them */
if (AOP_TYPE (right) == AOP_CRY &&
AOP_TYPE (left) != AOP_CRY)
{
operand *tmp = right;
right = left;
left = tmp;
}
if (AOP_TYPE (right) == AOP_LIT)
lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
size = AOP_SIZE (result);
// if(bit & yy)
// result = bit & yy;
if (AOP_TYPE (left) == AOP_CRY)
{
// c = bit & literal;
if (AOP_TYPE (right) == AOP_LIT)
{
if (lit & 1)
{
if (size && sameRegs (AOP (result), AOP (left)))
// no change
goto release;
emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
}
else
{
// bit(result) = 0;
if (size && (AOP_TYPE (result) == AOP_CRY))
{
emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
goto release;
}
if ((AOP_TYPE (result) == AOP_CRY) && ifx)
{
jumpIfTrue (ifx);
goto release;
}
emitcode ("clr", "c");
}
}
else
{
if (AOP_TYPE (right) == AOP_CRY)
{
// c = bit & bit;
emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
}
else
{
// c = bit & val;
MOVA (aopGet (AOP (right), 0, FALSE, FALSE, TRUE));
// c = lsb
emitcode ("rrc", "a");
emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
}
}
// bit = c
// val = c
if (size)
outBitC (result);
// if(bit & ...)
else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
genIfxJump (ifx, "c");
goto release;
}
// if(val & 0xZZ) - size = 0, ifx != FALSE -
// bit = val & 0xZZ - size = 1, ifx = FALSE -
if ((AOP_TYPE (right) == AOP_LIT) &&
(AOP_TYPE (result) == AOP_CRY) &&
(AOP_TYPE (left) != AOP_CRY))
{
int posbit = isLiteralBit (lit);
/* left & 2^n */
if (posbit)
{
posbit--;
MOVA (aopGet (AOP (left), posbit >> 3, FALSE, FALSE, TRUE));
// bit = left & 2^n
if (size)
emitcode ("mov", "c,acc.%d", posbit & 0x07);
// if(left & 2^n)
else
{
if (ifx)
{
sprintf (buffer, "acc.%d", posbit & 0x07);
genIfxJump (ifx, buffer);
}
goto release;
}
}
else
{
symbol *tlbl = newiTempLabel (NULL);
int sizel = AOP_SIZE (left);
if (size)
emitcode ("setb", "c");
while (sizel--)
{
if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
{
MOVA (aopGet (AOP (left), offset, FALSE, FALSE, TRUE));
// byte == 2^n ?
if ((posbit = isLiteralBit (bytelit)) != 0)
emitcode ("jb", "acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
else
{
if (bytelit != 0x0FFL)
emitcode ("anl", "a,%s",
aopGet (AOP (right), offset, FALSE, TRUE, FALSE));
emitcode ("jnz", "%05d$", tlbl->key + 100);
}
}
offset++;
}
// bit = left & literal
if (size)
{
emitcode ("clr", "c");
emitcode ("", "%05d$:", tlbl->key + 100);
}
// if(left & literal)
else
{
if (ifx)
jmpTrueOrFalse (ifx, tlbl);
goto release;
}
}
outBitC (result);
goto release;
}
/* if left is same as result */
if (sameRegs (AOP (result), AOP (left)))
{
for (; size--; offset++)
{
if (AOP_TYPE (right) == AOP_LIT)
{
if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
continue;
else if (bytelit == 0)
aopPut (AOP (result), zero, offset);
else if (IS_AOP_PREG (result))
{
MOVA (aopGet (AOP (right), offset, FALSE, FALSE, TRUE));
emitcode ("anl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE, FALSE));
aopPut (AOP (result), "a", offset);
}
else
emitcode ("anl", "%s,%s",
aopGet (AOP (left), offset, FALSE, TRUE, FALSE),
aopGet (AOP (right), offset, FALSE, FALSE, FALSE));
}
else
{
if (AOP_TYPE (left) == AOP_ACC)
emitcode ("anl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE, FALSE));
else
{
MOVA (aopGet (AOP (right), offset, FALSE, FALSE, TRUE));
if (IS_AOP_PREG (result))
{
emitcode ("anl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE, FALSE));
aopPut (AOP (result), "a", offset);
}
else
emitcode ("anl", "%s,a",
aopGet (AOP (left), offset, FALSE, TRUE, FALSE));
}
}
}
}
else
{
// left & result in different registers
if (AOP_TYPE (result) == AOP_CRY)
{
// result = bit
// if(size), result in bit
// if(!size && ifx), conditional oper: if(left & right)
symbol *tlbl = newiTempLabel (NULL);
int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
if (size)
emitcode ("setb", "c");
while (sizer--)
{
if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
emitcode ("anl", "a,%s",
aopGet (AOP (right), offset, FALSE, FALSE, FALSE));
} else {
if (AOP_TYPE(left)==AOP_ACC) {
emitcode("mov", "b,a");
MOVA (aopGet (AOP (right), offset, FALSE, FALSE, TRUE));
emitcode("anl", "a,b");
}else {
MOVA (aopGet (AOP (right), offset, FALSE, FALSE, TRUE));
emitcode ("anl", "a,%s",
aopGet (AOP (left), offset, FALSE, FALSE, FALSE));
}
}
emitcode ("jnz", "%05d$", tlbl->key + 100);
offset++;
}
if (size)
{
CLRC;
emitcode ("", "%05d$:", tlbl->key + 100);
outBitC (result);
}
else if (ifx)
jmpTrueOrFalse (ifx, tlbl);
}
else
{
for (; (size--); offset++)
{
// normal case
// result = left & right
if (AOP_TYPE (right) == AOP_LIT)
{
if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
{
aopPut (AOP (result),
aopGet (AOP (left), offset, FALSE, FALSE, FALSE),
offset);
continue;
}
else if (bytelit == 0)
{
aopPut (AOP (result), zero, offset);
continue;
}
D (emitcode (";", "better literal AND."););
MOVA (aopGet (AOP (left), offset, FALSE, FALSE, TRUE));
emitcode ("anl", "a, %s", aopGet (AOP (right), offset,
FALSE, FALSE, FALSE));
}
else
{
// faster than result <- left, anl result,right
// and better if result is SFR
if (AOP_TYPE (left) == AOP_ACC)
{
emitcode ("anl", "a,%s", aopGet (AOP (right), offset,
FALSE, FALSE, FALSE));
}
else
{
char *rOp = aopGet (AOP (right), offset, FALSE, FALSE, TRUE);
if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
{
emitcode("mov", "b,a");
rOp = "b";
}
MOVA (aopGet (AOP (left), offset, FALSE, FALSE, TRUE));
emitcode ("anl", "a,%s", rOp);
}
}
aopPut (AOP (result), "a", offset);
}
}
}
release:
freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
freeAsmop (result, NULL, ic, TRUE);
}
/*-----------------------------------------------------------------*/
/* genOr - code for or */
/*-----------------------------------------------------------------*/
static void
genOr (iCode * ic, iCode * ifx)
{
operand *left, *right, *result;
int size, offset = 0;
unsigned long lit = 0L;
bool pushResult;
D (emitcode (";", "genOr "););
AOP_OP_3_NOFATAL (ic, pushResult);
AOP_SET_LOCALS (ic);
if (pushResult)
{
genFarFarLogicOp(ic, "orl");
return;
}
#ifdef DEBUG_TYPE
emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
AOP_TYPE (result),
AOP_TYPE (left), AOP_TYPE (right));
emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
AOP_SIZE (result),
AOP_SIZE (left), AOP_SIZE (right));
#endif
/* if left is a literal & right is not then exchange them */
if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
#ifdef LOGIC_OPS_BROKEN
|| AOP_NEEDSACC (left) // I think this is a net loss now.
#endif
)
{
operand *tmp = right;
right = left;
left = tmp;
}
/* if result = right then exchange them */
if (sameRegs (AOP (result), AOP (right)))
{
operand *tmp = right;
right = left;
left = tmp;
}
/* if right is bit then exchange them */
if (AOP_TYPE (right) == AOP_CRY &&
AOP_TYPE (left) != AOP_CRY)
{
operand *tmp = right;
right = left;
left = tmp;
}
if (AOP_TYPE (right) == AOP_LIT)
lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
size = AOP_SIZE (result);
// if(bit | yy)
// xx = bit | yy;
if (AOP_TYPE (left) == AOP_CRY)
{
if (AOP_TYPE (right) == AOP_LIT)
{
// c = bit & literal;
if (lit)
{
// lit != 0 => result = 1
if (AOP_TYPE (result) == AOP_CRY)
{
if (size)
emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
else if (ifx)
continueIfTrue (ifx);
goto release;
}
emitcode ("setb", "c");
}
else
{
// lit == 0 => result = left
if (size && sameRegs (AOP (result), AOP (left)))
goto release;
emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
}
}
else
{
if (AOP_TYPE (right) == AOP_CRY)
{
// c = bit | bit;
emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
}
else
{
// c = bit | val;
symbol *tlbl = newiTempLabel (NULL);
if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
emitcode ("setb", "c");
emitcode ("jb", "%s,%05d$",
AOP (left)->aopu.aop_dir, tlbl->key + 100);
toBoolean (right);
emitcode ("jnz", "%05d$", tlbl->key + 100);
if ((AOP_TYPE (result) == AOP_CRY) && ifx)
{
jmpTrueOrFalse (ifx, tlbl);
goto release;
}
else
{
CLRC;
emitcode ("", "%05d$:", tlbl->key + 100);
}
}
}
// bit = c
// val = c
if (size)
outBitC (result);
// if(bit | ...)
else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
genIfxJump (ifx, "c");
goto release;
}
// if(val | 0xZZ) - size = 0, ifx != FALSE -
// bit = val | 0xZZ - size = 1, ifx = FALSE -
if ((AOP_TYPE (right) == AOP_LIT) &&
(AOP_TYPE (result) == AOP_CRY) &&
(AOP_TYPE (left) != AOP_CRY))
{
if (lit)
{
// result = 1
if (size)
emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
else
continueIfTrue (ifx);
goto release;
}
else
{
// lit = 0, result = boolean(left)
if (size)
emitcode ("setb", "c");
toBoolean (right);
if (size)
{
symbol *tlbl = newiTempLabel (NULL);
emitcode ("jnz", "%05d$", tlbl->key + 100);
CLRC;
emitcode ("", "%05d$:", tlbl->key + 100);
}
else
{
genIfxJump (ifx, "a");
goto release;
}
}
outBitC (result);
goto release;
}
/* if left is same as result */
if (sameRegs (AOP (result), AOP (left)))
{
for (; size--; offset++)
{
if (AOP_TYPE (right) == AOP_LIT)
{
if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
{
continue;
}
else
{
if (IS_AOP_PREG (left))
{
MOVA (aopGet (AOP (right), offset, FALSE, FALSE, TRUE));
emitcode ("orl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE, FALSE));
aopPut (AOP (result), "a", offset);
}
else
{
emitcode ("orl", "%s,%s",
aopGet (AOP (left), offset, FALSE, TRUE, FALSE),
aopGet (AOP (right), offset, FALSE, FALSE, FALSE));
}
}
}
else
{
if (AOP_TYPE (left) == AOP_ACC)
{
emitcode ("orl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE, FALSE));
}
else
{
MOVA (aopGet (AOP (right), offset, FALSE, FALSE, TRUE));
if (IS_AOP_PREG (left))
{
emitcode ("orl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE, FALSE));
aopPut (AOP (result), "a", offset);
}
else
{
emitcode ("orl", "%s,a",
aopGet (AOP (left), offset, FALSE, TRUE, FALSE));
}
}
}
}
}
else
{
// left & result in different registers
if (AOP_TYPE (result) == AOP_CRY)
{
// result = bit
// if(size), result in bit
// if(!size && ifx), conditional oper: if(left | right)
symbol *tlbl = newiTempLabel (NULL);
int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
if (size)
emitcode ("setb", "c");
while (sizer--)
{
if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
emitcode ("orl", "a,%s",
aopGet (AOP (right), offset, FALSE, FALSE, FALSE));
} else {
MOVA (aopGet (AOP (right), offset, FALSE, FALSE, TRUE));
emitcode ("orl", "a,%s",
aopGet (AOP (left), offset, FALSE, FALSE, FALSE));
}
emitcode ("jnz", "%05d$", tlbl->key + 100);
offset++;
}
if (size)
{
CLRC;
emitcode ("", "%05d$:", tlbl->key + 100);
outBitC (result);
}
else if (ifx)
jmpTrueOrFalse (ifx, tlbl);
}
else
{
_startLazyDPSEvaluation();
for (; (size--); offset++)
{
// normal case
// result = left & right
if (AOP_TYPE (right) == AOP_LIT)
{
if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
{
aopPut (AOP (result),
aopGet (AOP (left), offset, FALSE, FALSE, FALSE),
offset);
continue;
}
D (emitcode (";", "better literal OR."););
MOVA (aopGet (AOP (left), offset, FALSE, FALSE, TRUE));
emitcode ("orl", "a, %s", aopGet (AOP (right), offset,
FALSE, FALSE, FALSE));
}
else
{
// faster than result <- left, anl result,right
// and better if result is SFR
if (AOP_TYPE (left) == AOP_ACC)
{
emitcode ("orl", "a,%s", aopGet (AOP (right), offset,
FALSE, FALSE, FALSE));
}
else
{
char *rOp = aopGet (AOP (right), offset, FALSE, FALSE, TRUE);
if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
{
emitcode("mov", "b,a");
rOp = "b";
}
MOVA (aopGet (AOP (left), offset, FALSE, FALSE, TRUE));
emitcode ("orl", "a,%s", rOp);
}
}
aopPut (AOP (result), "a", offset);
}
_endLazyDPSEvaluation();
}
}
release:
freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
freeAsmop (result, NULL, ic, TRUE);
}
/*-----------------------------------------------------------------*/
/* genXor - code for xclusive or */
/*-----------------------------------------------------------------*/
static void
genXor (iCode * ic, iCode * ifx)
{
operand *left, *right, *result;
int size, offset = 0;
unsigned long lit = 0L;
bool pushResult;
D (emitcode (";", "genXor "););
AOP_OP_3_NOFATAL (ic, pushResult);
AOP_SET_LOCALS (ic);
if (pushResult)
{
genFarFarLogicOp(ic, "xrl");
return;
}
#ifdef DEBUG_TYPE
emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
AOP_TYPE (result),
AOP_TYPE (left), AOP_TYPE (right));
emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
AOP_SIZE (result),
AOP_SIZE (left), AOP_SIZE (right));
#endif
/* if left is a literal & right is not ||
if left needs acc & right does not */
if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
#ifdef LOGIC_OPS_BROKEN
|| (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right))
#endif
)
{
operand *tmp = right;
right = left;
left = tmp;
}
/* if result = right then exchange them */
if (sameRegs (AOP (result), AOP (right)))
{
operand *tmp = right;
right = left;
left = tmp;
}
/* if right is bit then exchange them */
if (AOP_TYPE (right) == AOP_CRY &&
AOP_TYPE (left) != AOP_CRY)
{
operand *tmp = right;
right = left;
left = tmp;
}
if (AOP_TYPE (right) == AOP_LIT)
lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
size = AOP_SIZE (result);
// if(bit ^ yy)
// xx = bit ^ yy;
if (AOP_TYPE (left) == AOP_CRY)
{
if (AOP_TYPE (right) == AOP_LIT)
{
// c = bit & literal;
if (lit >> 1)
{
// lit>>1 != 0 => result = 1
if (AOP_TYPE (result) == AOP_CRY)
{
if (size)
emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
else if (ifx)
continueIfTrue (ifx);
goto release;
}
emitcode ("setb", "c");
}
else
{
// lit == (0 or 1)
if (lit == 0)
{
// lit == 0, result = left
if (size && sameRegs (AOP (result), AOP (left)))
goto release;
emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
}
else
{
// lit == 1, result = not(left)
if (size && sameRegs (AOP (result), AOP (left)))
{
emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
goto release;
}
else
{
emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
emitcode ("cpl", "c");
}
}
}
}
else
{
// right != literal
symbol *tlbl = newiTempLabel (NULL);
if (AOP_TYPE (right) == AOP_CRY)
{
// c = bit ^ bit;
emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
}
else
{
int sizer = AOP_SIZE (right);
// c = bit ^ val
// if val>>1 != 0, result = 1
emitcode ("setb", "c");
while (sizer)
{
MOVA (aopGet (AOP (right), sizer - 1, FALSE, FALSE, TRUE));
if (sizer == 1)
// test the msb of the lsb
emitcode ("anl", "a,#0xfe");
emitcode ("jnz", "%05d$", tlbl->key + 100);
sizer--;
}
// val = (0,1)
emitcode ("rrc", "a");
}
emitcode ("jnb", "%s,%05d$", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
emitcode ("cpl", "c");
emitcode ("", "%05d$:", (tlbl->key + 100));
}
// bit = c
// val = c
if (size)
outBitC (result);
// if(bit | ...)
else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
genIfxJump (ifx, "c");
goto release;
}
if (sameRegs (AOP (result), AOP (left)))
{
/* if left is same as result */
for (; size--; offset++)
{
if (AOP_TYPE (right) == AOP_LIT)
{
if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
continue;
else if (IS_AOP_PREG (left))
{
MOVA (aopGet (AOP (right), offset, FALSE, FALSE, TRUE));
emitcode ("xrl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE, FALSE));
aopPut (AOP (result), "a", offset);
}
else
emitcode ("xrl", "%s,%s",
aopGet (AOP (left), offset, FALSE, TRUE, FALSE),
aopGet (AOP (right), offset, FALSE, FALSE, FALSE));
}
else
{
if (AOP_TYPE (left) == AOP_ACC)
emitcode ("xrl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE, FALSE));
else
{
MOVA (aopGet (AOP (right), offset, FALSE, FALSE, TRUE));
if (IS_AOP_PREG (left))
{
emitcode ("xrl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE, FALSE));
aopPut (AOP (result), "a", offset);
}
else
emitcode ("xrl", "%s,a",
aopGet (AOP (left), offset, FALSE, TRUE, FALSE));
}
}
}
}
else
{
// left & result in different registers
if (AOP_TYPE (result) == AOP_CRY)
{
// result = bit
// if(size), result in bit
// if(!size && ifx), conditional oper: if(left ^ right)
symbol *tlbl = newiTempLabel (NULL);
int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
if (size)
emitcode ("setb", "c");
while (sizer--)
{
if ((AOP_TYPE (right) == AOP_LIT) &&
(((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
{
MOVA (aopGet (AOP (left), offset, FALSE, FALSE, TRUE));
}
else
{
if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
emitcode ("xrl", "a,%s",
aopGet (AOP (right), offset, FALSE, FALSE, FALSE));
} else {
MOVA (aopGet (AOP (right), offset, FALSE, FALSE, TRUE));
emitcode ("xrl", "a,%s",
aopGet (AOP (left), offset, FALSE, FALSE, FALSE));
}
}
emitcode ("jnz", "%05d$", tlbl->key + 100);
offset++;
}
if (size)
{
CLRC;
emitcode ("", "%05d$:", tlbl->key + 100);
outBitC (result);
}
else if (ifx)
jmpTrueOrFalse (ifx, tlbl);
}
else
for (; (size--); offset++)
{
// normal case
// result = left & right
if (AOP_TYPE (right) == AOP_LIT)
{
if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
{
aopPut (AOP (result),
aopGet (AOP (left), offset, FALSE, FALSE, FALSE),
offset);
continue;
}
D (emitcode (";", "better literal XOR.");
);
MOVA (aopGet (AOP (left), offset, FALSE, FALSE, TRUE));
emitcode ("xrl", "a, %s", aopGet (AOP (right), offset,
FALSE, FALSE, FALSE));
}
else
{
// faster than result <- left, anl result,right
// and better if result is SFR
if (AOP_TYPE (left) == AOP_ACC)
{
emitcode ("xrl", "a,%s", aopGet (AOP (right), offset,
FALSE, FALSE, FALSE));
}
else
{
char *rOp = aopGet (AOP (right), offset, FALSE, FALSE, TRUE);
if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
{
emitcode("mov", "b,a");
rOp = "b";
}
MOVA (aopGet (AOP (left), offset, FALSE, FALSE, TRUE));
emitcode ("xrl", "a,%s", rOp);
}
}
aopPut (AOP (result), "a", offset);
}
}
release:
freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
freeAsmop (result, NULL, ic, TRUE);
}
/*-----------------------------------------------------------------*/
/* genInline - write the inline code out */
/*-----------------------------------------------------------------*/
static void
genInline (iCode * ic)
{
char *buffer, *bp, *bp1;
D (emitcode (";", "genInline ");
);
_G.inLine += (!options.asmpeep);
buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
strcpy (buffer, IC_INLINE (ic));
/* emit each line as a code */
while (*bp)
{
if (*bp == '\n')
{
*bp++ = '\0';
emitcode (bp1, "");
bp1 = bp;
}
else
{
if (*bp == ':')
{
bp++;
*bp = '\0';
bp++;
emitcode (bp1, "");
bp1 = bp;
}
else
bp++;
}
}
if (bp1 != bp)
emitcode (bp1, "");
/* emitcode("",buffer); */
_G.inLine -= (!options.asmpeep);
}
/*-----------------------------------------------------------------*/
/* genRRC - rotate right with carry */
/*-----------------------------------------------------------------*/
static void
genRRC (iCode * ic)
{
operand *left, *result;
int size, offset = 0;
char *l;
D (emitcode (";", "genRRC ");
);
/* rotate right with carry */
left = IC_LEFT (ic);
result = IC_RESULT (ic);
aopOp (left, ic, FALSE, FALSE);
aopOp (result, ic, FALSE, AOP_TYPE (left) == AOP_DPTR);
/* move it to the result */
size = AOP_SIZE (result);
offset = size - 1;
CLRC;
_startLazyDPSEvaluation ();
while (size--)
{
l = aopGet (AOP (left), offset, FALSE, FALSE, TRUE);
MOVA (l);
emitcode ("rrc", "a");
if (AOP_SIZE (result) > 1)
aopPut (AOP (result), "a", offset--);
}
_endLazyDPSEvaluation ();
/* now we need to put the carry into the
highest order byte of the result */
if (AOP_SIZE (result) > 1)
{
l = aopGet (AOP (result), AOP_SIZE (result) - 1, FALSE, FALSE, TRUE);
MOVA (l);
}
emitcode ("mov", "acc.7,c");
aopPut (AOP (result), "a", AOP_SIZE (result) - 1);
freeAsmop (left, NULL, ic, TRUE);
freeAsmop (result, NULL, ic, TRUE);
}
/*-----------------------------------------------------------------*/
/* genRLC - generate code for rotate left with carry */
/*-----------------------------------------------------------------*/
static void
genRLC (iCode * ic)
{
operand *left, *result;
int size, offset = 0;
char *l;
D (emitcode (";", "genRLC ");
);
/* rotate right with carry */
left = IC_LEFT (ic);
result = IC_RESULT (ic);
aopOp (left, ic, FALSE, FALSE);
aopOp (result, ic, FALSE, AOP_TYPE (left) == AOP_DPTR);
/* move it to the result */
size = AOP_SIZE (result);
offset = 0;
if (size--)
{
l = aopGet (AOP (left), offset, FALSE, FALSE, TRUE);
MOVA (l);
emitcode ("add", "a,acc");
if (AOP_SIZE (result) > 1)
{
aopPut (AOP (result), "a", offset++);
}
_startLazyDPSEvaluation ();
while (size--)
{
l = aopGet (AOP (left), offset, FALSE, FALSE, TRUE);
MOVA (l);
emitcode ("rlc", "a");
if (AOP_SIZE (result) > 1)
aopPut (AOP (result), "a", offset++);
}
_endLazyDPSEvaluation ();
}
/* now we need to put the carry into the
highest order byte of the result */
if (AOP_SIZE (result) > 1)
{
l = aopGet (AOP (result), 0, FALSE, FALSE, TRUE);
MOVA (l);
}
emitcode ("mov", "acc.0,c");
aopPut (AOP (result), "a", 0);
freeAsmop (left, NULL, ic, TRUE);
freeAsmop (result, NULL, ic, TRUE);
}
/*-----------------------------------------------------------------*/
/* genGetHbit - generates code get highest order bit */
/*-----------------------------------------------------------------*/
static void
genGetHbit (iCode * ic)
{
operand *left, *result;
left = IC_LEFT (ic);
result = IC_RESULT (ic);
aopOp (left, ic, FALSE, FALSE);
aopOp (result, ic, FALSE, AOP_TYPE (left) == AOP_DPTR);
D (emitcode (";", "genGetHbit ");
);
/* get the highest order byte into a */
MOVA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE, FALSE, TRUE));
if (AOP_TYPE (result) == AOP_CRY)
{
emitcode ("rlc", "a");
outBitC (result);
}
else
{
emitcode ("rl", "a");
emitcode ("anl", "a,#0x01");
outAcc (result);
}
freeAsmop (left, NULL, ic, TRUE);
freeAsmop (result, NULL, ic, TRUE);
}
/*-----------------------------------------------------------------*/
/* AccRol - rotate left accumulator by known count */
/*-----------------------------------------------------------------*/
static void
AccRol (int shCount)
{
shCount &= 0x0007; // shCount : 0..7
switch (shCount)
{
case 0:
break;
case 1:
emitcode ("rl", "a");
break;
case 2:
emitcode ("rl", "a");
emitcode ("rl", "a");
break;
case 3:
emitcode ("swap", "a");
emitcode ("rr", "a");
break;
case 4:
emitcode ("swap", "a");
break;
case 5:
emitcode ("swap", "a");
emitcode ("rl", "a");
break;
case 6:
emitcode ("rr", "a");
emitcode ("rr", "a");
break;
case 7:
emitcode ("rr", "a");
break;
}
}
/*-----------------------------------------------------------------*/
/* AccLsh - left shift accumulator by known count */
/*-----------------------------------------------------------------*/
static void
AccLsh (int shCount)
{
if (shCount != 0)
{
if (shCount == 1)
emitcode ("add", "a,acc");
else if (shCount == 2)
{
emitcode ("add", "a,acc");
emitcode ("add", "a,acc");
}
else
{
/* rotate left accumulator */
AccRol (shCount);
/* and kill the lower order bits */
emitcode ("anl", "a,#0x%02x", SLMask[shCount]);
}
}
}
/*-----------------------------------------------------------------*/
/* AccRsh - right shift accumulator by known count */
/*-----------------------------------------------------------------*/
static void
AccRsh (int shCount)
{
if (shCount != 0)
{
if (shCount == 1)
{
CLRC;
emitcode ("rrc", "a");
}
else
{
/* rotate right accumulator */
AccRol (8 - shCount);
/* and kill the higher order bits */
emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
}
}
}
#ifdef BETTER_LITERAL_SHIFT
/*-----------------------------------------------------------------*/
/* AccSRsh - signed right shift accumulator by known count */
/*-----------------------------------------------------------------*/
static void
AccSRsh (int shCount)
{
symbol *tlbl;
if (shCount != 0)
{
if (shCount == 1)
{
emitcode ("mov", "c,acc.7");
emitcode ("rrc", "a");
}
else if (shCount == 2)
{
emitcode ("mov", "c,acc.7");
emitcode ("rrc", "a");
emitcode ("mov", "c,acc.7");
emitcode ("rrc", "a");
}
else
{
tlbl = newiTempLabel (NULL);
/* rotate right accumulator */
AccRol (8 - shCount);
/* and kill the higher order bits */
emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
emitcode ("orl", "a,#0x%02x",
(unsigned char) ~SRMask[shCount]);
emitcode ("", "%05d$:", tlbl->key + 100);
}
}
}
#endif
#ifdef BETTER_LITERAL_SHIFT
/*-----------------------------------------------------------------*/
/* shiftR1Left2Result - shift right one byte from left to result */
/*-----------------------------------------------------------------*/
static void
shiftR1Left2Result (operand * left, int offl,
operand * result, int offr,
int shCount, int sign)
{
MOVA (aopGet (AOP (left), offl, FALSE, FALSE, TRUE));
/* shift right accumulator */
if (sign)
AccSRsh (shCount);
else
AccRsh (shCount);
aopPut (AOP (result), "a", offr);
}
#endif
#ifdef BETTER_LITERAL_SHIFT
/*-----------------------------------------------------------------*/
/* shiftL1Left2Result - shift left one byte from left to result */
/*-----------------------------------------------------------------*/
static void
shiftL1Left2Result (operand * left, int offl,
operand * result, int offr, int shCount)
{
MOVA(aopGet (AOP (left), offl, FALSE, FALSE, TRUE));
/* shift left accumulator */
AccLsh (shCount);
aopPut (AOP (result), "a", offr);
}
#endif
#ifdef BETTER_LITERAL_SHIFT
/*-----------------------------------------------------------------*/
/* movLeft2Result - move byte from left to result */
/*-----------------------------------------------------------------*/
static void
movLeft2Result (operand * left, int offl,
operand * result, int offr, int sign)
{
char *l;
if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
{
l = aopGet (AOP (left), offl, FALSE, FALSE, TRUE);
if (*l == '@' && (IS_AOP_PREG (result)))
{
emitcode ("mov", "a,%s", l);
aopPut (AOP (result), "a", offr);
}
else
{
if (!sign)
{
aopPut (AOP (result), l, offr);
}
else
{
/* MSB sign in acc.7 ! */
if (getDataSize (left) == offl + 1)
{
emitcode ("mov", "a,%s", l);
aopPut (AOP (result), "a", offr);
}
}
}
}
}
#endif
#ifdef BETTER_LITERAL_SHIFT
/*-----------------------------------------------------------------*/
/* AccAXRrl1 - right rotate c->a:x->c by 1 */
/*-----------------------------------------------------------------*/
static void
AccAXRrl1 (char *x)
{
emitcode ("rrc", "a");
emitcode ("xch", "a,%s", x);
emitcode ("rrc", "a");
emitcode ("xch", "a,%s", x);
}
#endif
#ifdef BETTER_LITERAL_SHIFT
//REMOVE ME!!!
/*-----------------------------------------------------------------*/
/* AccAXLrl1 - left rotate c<-a:x<-c by 1 */
/*-----------------------------------------------------------------*/
static void
AccAXLrl1 (char *x)
{
emitcode ("xch", "a,%s", x);
emitcode ("rlc", "a");
emitcode ("xch", "a,%s", x);
emitcode ("rlc", "a");
}
#endif
#ifdef BETTER_LITERAL_SHIFT
/*-----------------------------------------------------------------*/
/* AccAXLsh1 - left shift a:x<-0 by 1 */
/*-----------------------------------------------------------------*/
static void
AccAXLsh1 (char *x)
{
emitcode ("xch", "a,%s", x);
emitcode ("add", "a,acc");
emitcode ("xch", "a,%s", x);
emitcode ("rlc", "a");
}
#endif
#ifdef BETTER_LITERAL_SHIFT
/*-----------------------------------------------------------------*/
/* AccAXLsh - left shift a:x by known count (0..7) */
/*-----------------------------------------------------------------*/
static void
AccAXLsh (char *x, int shCount)
{
switch (shCount)
{
case 0:
break;
case 1:
AccAXLsh1 (x);
break;
case 2:
AccAXLsh1 (x);
AccAXLsh1 (x);
break;
case 3:
case 4:
case 5: // AAAAABBB:CCCCCDDD
AccRol (shCount); // BBBAAAAA:CCCCCDDD
emitcode ("anl", "a,#0x%02x",
SLMask[shCount]); // BBB00000:CCCCCDDD
emitcode ("xch", "a,%s", x); // CCCCCDDD:BBB00000
AccRol (shCount); // DDDCCCCC:BBB00000
emitcode ("xch", "a,%s", x); // BBB00000:DDDCCCCC
emitcode ("xrl", "a,%s", x); // (BBB^DDD)CCCCC:DDDCCCCC
emitcode ("xch", "a,%s", x); // DDDCCCCC:(BBB^DDD)CCCCC
emitcode ("anl", "a,#0x%02x",
SLMask[shCount]); // DDD00000:(BBB^DDD)CCCCC
emitcode ("xch", "a,%s", x); // (BBB^DDD)CCCCC:DDD00000
emitcode ("xrl", "a,%s", x); // BBBCCCCC:DDD00000
break;
case 6: // AAAAAABB:CCCCCCDD
emitcode ("anl", "a,#0x%02x",
SRMask[shCount]); // 000000BB:CCCCCCDD
emitcode ("mov", "c,acc.0"); // c = B
emitcode ("xch", "a,%s", x); // CCCCCCDD:000000BB
#if 0
AccAXRrl1 (x); // BCCCCCCD:D000000B
AccAXRrl1 (x); // BBCCCCCC:DD000000
#else
emitcode("rrc","a");
emitcode("xch","a,%s", x);
emitcode("rrc","a");
emitcode("mov","c,acc.0"); //<< get correct bit
emitcode("xch","a,%s", x);
emitcode("rrc","a");
emitcode("xch","a,%s", x);
emitcode("rrc","a");
emitcode("xch","a,%s", x);
#endif
break;
case 7: // a:x <<= 7
emitcode ("anl", "a,#0x%02x",
SRMask[shCount]); // 0000000B:CCCCCCCD
emitcode ("mov", "c,acc.0"); // c = B
emitcode ("xch", "a,%s", x); // CCCCCCCD:0000000B
AccAXRrl1 (x); // BCCCCCCC:D0000000
break;
default:
break;
}
}
#endif
#ifdef BETTER_LITERAL_SHIFT
//REMOVE ME!!!
/*-----------------------------------------------------------------*/
/* AccAXRsh - right shift a:x known count (0..7) */
/*-----------------------------------------------------------------*/
static void
AccAXRsh (char *x, int shCount)
{
switch (shCount)
{
case 0:
break;
case 1:
CLRC;
AccAXRrl1 (x); // 0->a:x
break;
case 2:
CLRC;
AccAXRrl1 (x); // 0->a:x
CLRC;
AccAXRrl1 (x); // 0->a:x
break;
case 3:
case 4:
case 5: // AAAAABBB:CCCCCDDD = a:x
AccRol (8 - shCount); // BBBAAAAA:DDDCCCCC
emitcode ("xch", "a,%s", x); // CCCCCDDD:BBBAAAAA
AccRol (8 - shCount); // DDDCCCCC:BBBAAAAA
emitcode ("anl", "a,#0x%02x",
SRMask[shCount]); // 000CCCCC:BBBAAAAA
emitcode ("xrl", "a,%s", x); // BBB(CCCCC^AAAAA):BBBAAAAA
emitcode ("xch", "a,%s", x); // BBBAAAAA:BBB(CCCCC^AAAAA)
emitcode ("anl", "a,#0x%02x",
SRMask[shCount]); // 000AAAAA:BBB(CCCCC^AAAAA)
emitcode ("xch", "a,%s", x); // BBB(CCCCC^AAAAA):000AAAAA
emitcode ("xrl", "a,%s", x); // BBBCCCCC:000AAAAA
emitcode ("xch", "a,%s", x); // 000AAAAA:BBBCCCCC
break;
case 6: // AABBBBBB:CCDDDDDD
emitcode ("mov", "c,acc.7");
AccAXLrl1 (x); // ABBBBBBC:CDDDDDDA
AccAXLrl1 (x); // BBBBBBCC:DDDDDDAA
emitcode ("xch", "a,%s", x); // DDDDDDAA:BBBBBBCC
emitcode ("anl", "a,#0x%02x",
SRMask[shCount]); // 000000AA:BBBBBBCC
break;
case 7: // ABBBBBBB:CDDDDDDD
emitcode ("mov", "c,acc.7"); // c = A
AccAXLrl1 (x); // BBBBBBBC:DDDDDDDA
emitcode ("xch", "a,%s", x); // DDDDDDDA:BBBBBBCC
emitcode ("anl", "a,#0x%02x",
SRMask[shCount]); // 0000000A:BBBBBBBC
break;
default:
break;
}
}
#endif
#ifdef BETTER_LITERAL_SHIFT
/*-----------------------------------------------------------------*/
/* AccAXRshS - right shift signed a:x known count (0..7) */
/*-----------------------------------------------------------------*/
static void
AccAXRshS (char *x, int shCount)
{
symbol *tlbl;
switch (shCount)
{
case 0:
break;
case 1:
emitcode ("mov", "c,acc.7");
AccAXRrl1 (x); // s->a:x
break;
case 2:
emitcode ("mov", "c,acc.7");
AccAXRrl1 (x); // s->a:x
emitcode ("mov", "c,acc.7");
AccAXRrl1 (x); // s->a:x
break;
case 3:
case 4:
case 5: // AAAAABBB:CCCCCDDD = a:x
tlbl = newiTempLabel (NULL);
AccRol (8 - shCount); // BBBAAAAA:CCCCCDDD
emitcode ("xch", "a,%s", x); // CCCCCDDD:BBBAAAAA
AccRol (8 - shCount); // DDDCCCCC:BBBAAAAA
emitcode ("anl", "a,#0x%02x",
SRMask[shCount]); // 000CCCCC:BBBAAAAA
emitcode ("xrl", "a,%s", x); // BBB(CCCCC^AAAAA):BBBAAAAA
emitcode ("xch", "a,%s", x); // BBBAAAAA:BBB(CCCCC^AAAAA)
emitcode ("anl", "a,#0x%02x",
SRMask[shCount]); // 000AAAAA:BBB(CCCCC^AAAAA)
emitcode ("xch", "a,%s", x); // BBB(CCCCC^AAAAA):000AAAAA
emitcode ("xrl", "a,%s", x); // BBBCCCCC:000AAAAA
emitcode ("xch", "a,%s", x); // 000SAAAA:BBBCCCCC
emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
emitcode ("orl", "a,#0x%02x",
(unsigned char) ~SRMask[shCount]); // 111AAAAA:BBBCCCCC
emitcode ("", "%05d$:", tlbl->key + 100);
break; // SSSSAAAA:BBBCCCCC
case 6: // AABBBBBB:CCDDDDDD
tlbl = newiTempLabel (NULL);
emitcode ("mov", "c,acc.7");
AccAXLrl1 (x); // ABBBBBBC:CDDDDDDA
AccAXLrl1 (x); // BBBBBBCC:DDDDDDAA
emitcode ("xch", "a,%s", x); // DDDDDDAA:BBBBBBCC
emitcode ("anl", "a,#0x%02x",
SRMask[shCount]); // 000000AA:BBBBBBCC
emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
emitcode ("orl", "a,#0x%02x",
(unsigned char) ~SRMask[shCount]); // 111111AA:BBBBBBCC
emitcode ("", "%05d$:", tlbl->key + 100);
break;
case 7: // ABBBBBBB:CDDDDDDD
tlbl = newiTempLabel (NULL);
emitcode ("mov", "c,acc.7"); // c = A
AccAXLrl1 (x); // BBBBBBBC:DDDDDDDA
emitcode ("xch", "a,%s", x); // DDDDDDDA:BBBBBBCC
emitcode ("anl", "a,#0x%02x",
SRMask[shCount]); // 0000000A:BBBBBBBC
emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
emitcode ("orl", "a,#0x%02x",
(unsigned char) ~SRMask[shCount]); // 1111111A:BBBBBBBC
emitcode ("", "%05d$:", tlbl->key + 100);
break;
default:
break;
}
}
#endif
#ifdef BETTER_LITERAL_SHIFT
static void
_loadLeftIntoAx(char **lsb,
operand *left,
operand *result,
int offl,
int offr)
{
// Get the initial value from left into a pair of registers.
// MSB must be in A, LSB can be any register.
//
// If the result is held in registers, it is an optimization
// if the LSB can be held in the register which will hold the,
// result LSB since this saves us from having to copy it into
// the result following AccAXLsh.
//
// If the result is addressed indirectly, this is not a gain.
if (AOP_NEEDSACC(result))
{
char *leftByte;
_startLazyDPSEvaluation();
if (AOP_TYPE(left) == AOP_DPTR2)
{
// Get MSB in A.
MOVA(aopGet(AOP(left), offl + MSB16, FALSE, FALSE, TRUE));
// get LSB in DP2_RESULT_REG.
leftByte = aopGet(AOP(left), offl, FALSE, FALSE, FALSE);
assert(!strcmp(leftByte, DP2_RESULT_REG));
}
else
{
// get LSB into DP2_RESULT_REG
leftByte = aopGet (AOP(left), offl, FALSE, FALSE, TRUE);
if (strcmp(leftByte, DP2_RESULT_REG))
{
TR_AP("#7");
emitcode("mov","%s,%s", DP2_RESULT_REG, leftByte);
}
// And MSB in A.
leftByte = aopGet(AOP(left), offl + MSB16, FALSE, FALSE, TRUE);
assert(strcmp(leftByte, DP2_RESULT_REG));
MOVA(leftByte);
}
_endLazyDPSEvaluation();
*lsb = DP2_RESULT_REG;
}
else
{
if (sameRegs (AOP (result), AOP (left)) &&
((offl + MSB16) == offr))
{
/* don't crash result[offr] */
MOVA(aopGet(AOP(left), offl, FALSE, FALSE, TRUE));
emitcode ("xch", "a,%s",
aopGet(AOP(left), offl + MSB16, FALSE, FALSE, FALSE));
}
else
{
movLeft2Result (left, offl, result, offr, 0);
MOVA (aopGet (AOP (left), offl + MSB16, FALSE, FALSE, TRUE));
}
*lsb = aopGet(AOP (result), offr, FALSE, FALSE, FALSE);
assert(strcmp(*lsb,"a"));
}
}
static void
_storeAxResults(char *lsb,
operand *result,
int offr)
{
_startLazyDPSEvaluation();
if (AOP_NEEDSACC(result))
{
/* We have to explicitly update the result LSB.
*/
emitcode("xch","a,%s", lsb);
aopPut(AOP(result), "a", offr);
emitcode("mov","a,%s", lsb);
}
if (getDataSize (result) > 1)
{
aopPut (AOP (result), "a", offr + MSB16);
}
_endLazyDPSEvaluation();
}
/*-----------------------------------------------------------------*/
/* shiftL2Left2Result - shift left two bytes from left to result */
/*-----------------------------------------------------------------*/
static void
shiftL2Left2Result (operand * left, int offl,
operand * result, int offr, int shCount)
{
char *lsb;
_loadLeftIntoAx(&lsb, left, result, offl, offr);
AccAXLsh (lsb, shCount);
_storeAxResults(lsb, result, offr);
}
#endif
#ifdef BETTER_LITERAL_SHIFT
/*-----------------------------------------------------------------*/
/* shiftR2Left2Result - shift right two bytes from left to result */
/*-----------------------------------------------------------------*/
static void
shiftR2Left2Result (operand * left, int offl,
operand * result, int offr,
int shCount, int sign)
{
char *lsb;
_loadLeftIntoAx(&lsb, left, result, offl, offr);
/* a:x >> shCount (x = lsb(result)) */
if (sign)
{
AccAXRshS(lsb, shCount);
}
else
{
AccAXRsh(lsb, shCount);
}
_storeAxResults(lsb, result, offr);
}
#endif
#if 0
//REMOVE ME!!!
/*-----------------------------------------------------------------*/
/* shiftLLeftOrResult - shift left one byte from left, or to result */
/*-----------------------------------------------------------------*/
static void
shiftLLeftOrResult (operand * left, int offl,
operand * result, int offr, int shCount)
{
MOVA (aopGet (AOP (left), offl, FALSE, FALSE, TRUE));
/* shift left accumulator */
AccLsh (shCount);
/* or with result */
emitcode ("orl", "a,%s", aopGet (AOP (result), offr, FALSE, FALSE, FALSE));
/* back to result */
aopPut (AOP (result), "a", offr);
}
#endif
#if 0
//REMOVE ME!!!
/*-----------------------------------------------------------------*/
/* shiftRLeftOrResult - shift right one byte from left,or to result */
/*-----------------------------------------------------------------*/
static void
shiftRLeftOrResult (operand * left, int offl,
operand * result, int offr, int shCount)
{
MOVA (aopGet (AOP (left), offl, FALSE, FALSE, TRUE));
/* shift right accumulator */
AccRsh (shCount);
/* or with result */
emitcode ("orl", "a,%s", aopGet (AOP (result), offr, FALSE, FALSE, FALSE));
/* back to result */
aopPut (AOP (result), "a", offr);
}
#endif
#ifdef BETTER_LITERAL_SHIFT
/*-----------------------------------------------------------------*/
/* genlshOne - left shift a one byte quantity by known count */
/*-----------------------------------------------------------------*/
static void
genlshOne (operand * result, operand * left, int shCount)
{
D (emitcode (";", "genlshOne "););
shiftL1Left2Result (left, LSB, result, LSB, shCount);
}
#endif
#ifdef BETTER_LITERAL_SHIFT
/*-----------------------------------------------------------------*/
/* genlshTwo - left shift two bytes by known amount != 0 */
/*-----------------------------------------------------------------*/
static void
genlshTwo (operand * result, operand * left, int shCount)
{
int size;
D (emitcode (";", "genlshTwo "););
size = getDataSize (result);
/* if shCount >= 8 */
if (shCount >= 8)
{
shCount -= 8;
_startLazyDPSEvaluation();
if (size > 1)
{
if (shCount)
{
_endLazyDPSEvaluation();
shiftL1Left2Result (left, LSB, result, MSB16, shCount);
aopPut (AOP (result), zero, LSB);
}
else
{
movLeft2Result (left, LSB, result, MSB16, 0);
aopPut (AOP (result), zero, LSB);
_endLazyDPSEvaluation();
}
}
else
{
aopPut (AOP (result), zero, LSB);
_endLazyDPSEvaluation();
}
}
/* 1 <= shCount <= 7 */
else
{
if (size == 1)
{
shiftL1Left2Result (left, LSB, result, LSB, shCount);
}
else
{
shiftL2Left2Result (left, LSB, result, LSB, shCount);
}
}
}
#endif
#if 0
//REMOVE ME!!!
/*-----------------------------------------------------------------*/
/* shiftLLong - shift left one long from left to result */
/* offl = LSB or MSB16 */
/*-----------------------------------------------------------------*/
static void
shiftLLong (operand * left, operand * result, int offr)
{
char *l;
int size = AOP_SIZE (result);
if (size >= LSB + offr)
{
l = aopGet (AOP (left), LSB, FALSE, FALSE, TRUE);
MOVA (l);
emitcode ("add", "a,acc");
if (sameRegs (AOP (left), AOP (result)) &&
size >= MSB16 + offr && offr != LSB)
emitcode ("xch", "a,%s",
aopGet (AOP (left), LSB + offr, FALSE, FALSE, FALSE));
else
aopPut (AOP (result), "a", LSB + offr);
}
if (size >= MSB16 + offr)
{
if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
{
l = aopGet (AOP (left), MSB16, FALSE, FALSE, TRUE);
MOVA (l);
}
emitcode ("rlc", "a");
if (sameRegs (AOP (left), AOP (result)) &&
size >= MSB24 + offr && offr != LSB)
emitcode ("xch", "a,%s",
aopGet (AOP (left), MSB16 + offr, FALSE, FALSE, FALSE));
else
aopPut (AOP (result), "a", MSB16 + offr);
}
if (size >= MSB24 + offr)
{
if (!(sameRegs (AOP (left), AOP (left)) && size >= MSB24 + offr && offr != LSB))
{
l = aopGet (AOP (left), MSB24, FALSE, FALSE, TRUE);
MOVA (l);
}
emitcode ("rlc", "a");
if (sameRegs (AOP (left), AOP (result)) &&
size >= MSB32 + offr && offr != LSB)
emitcode ("xch", "a,%s",
aopGet (AOP (left), MSB24 + offr, FALSE, FALSE, FALSE));
else
aopPut (AOP (result), "a", MSB24 + offr);
}
if (size > MSB32 + offr)
{
if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
{
l = aopGet (AOP (left), MSB32, FALSE, FALSE, TRUE);
MOVA (l);
}
emitcode ("rlc", "a");
aopPut (AOP (result), "a", MSB32 + offr);
}
if (offr != LSB)
aopPut (AOP (result), zero, LSB);
}
#endif
#if 0
//REMOVE ME!!!
/*-----------------------------------------------------------------*/
/* genlshFour - shift four byte by a known amount != 0 */
/*-----------------------------------------------------------------*/
static void
genlshFour (operand * result, operand * left, int shCount)
{
int size;
D (emitcode (";", "genlshFour ");
);
size = AOP_SIZE (result);
/* if shifting more that 3 bytes */
if (shCount >= 24)
{
shCount -= 24;
if (shCount)
/* lowest order of left goes to the highest
order of the destination */
shiftL1Left2Result (left, LSB, result, MSB32, shCount);
else
movLeft2Result (left, LSB, result, MSB32, 0);
aopPut (AOP (result), zero, LSB);
aopPut (AOP (result), zero, MSB16);
aopPut (AOP (result), zero, MSB24);
return;
}
/* more than two bytes */
else if (shCount >= 16)
{
/* lower order two bytes goes to higher order two bytes */
shCount -= 16;
/* if some more remaining */
if (shCount)
shiftL2Left2Result (left, LSB, result, MSB24, shCount);
else
{
movLeft2Result (left, MSB16, result, MSB32, 0);
movLeft2Result (left, LSB, result, MSB24, 0);
}
aopPut (AOP (result), zero, MSB16);
aopPut (AOP (result), zero, LSB);
return;
}
/* if more than 1 byte */
else if (shCount >= 8)
{
/* lower order three bytes goes to higher order three bytes */
shCount -= 8;
if (size == 2)
{
if (shCount)
shiftL1Left2Result (left, LSB, result, MSB16, shCount);
else
movLeft2Result (left, LSB, result, MSB16, 0);
}
else
{ /* size = 4 */
if (shCount == 0)
{
movLeft2Result (left, MSB24, result, MSB32, 0);
movLeft2Result (left, MSB16, result, MSB24, 0);
movLeft2Result (left, LSB, result, MSB16, 0);
aopPut (AOP (result), zero, LSB);
}
else if (shCount == 1)
shiftLLong (left, result, MSB16);
else
{
shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
shiftL1Left2Result (left, LSB, result, MSB16, shCount);
shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
aopPut (AOP (result), zero, LSB);
}
}
}
/* 1 <= shCount <= 7 */
else if (shCount <= 2)
{
shiftLLong (left, result, LSB);
if (shCount == 2)
shiftLLong (result, result, LSB);
}
/* 3 <= shCount <= 7, optimize */
else
{
shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
shiftL2Left2Result (left, LSB, result, LSB, shCount);
}
}
#endif
#ifdef BETTER_LITERAL_SHIFT
/*-----------------------------------------------------------------*/
/* genLeftShiftLiteral - left shifting by known count */
/*-----------------------------------------------------------------*/
static bool
genLeftShiftLiteral (operand * left,
operand * right,
operand * result,
iCode * ic)
{
int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
int size;
size = getSize (operandType (result));
D(emitcode (";", "genLeftShiftLiteral (%d), size %d", shCount, size););
/* We only handle certain easy cases so far. */
if ((shCount != 0)
&& (shCount < (size * 8))
&& (size != 1)
&& (size != 2))
{
D(emitcode (";", "genLeftShiftLiteral wimping out"););
return FALSE;
}
freeAsmop (right, NULL, ic, TRUE);
aopOp(left, ic, FALSE, FALSE);
aopOp(result, ic, FALSE, (AOP_TYPE(left) == AOP_DPTR));
#if 1 // debug spew
if (IS_SYMOP(left) && OP_SYMBOL(left)->aop)
{
emitcode(";", "left (%s) is %d", OP_SYMBOL(left)->rname, AOP_TYPE(left));
if (!IS_TRUE_SYMOP(left) && OP_SYMBOL(left)->usl.spillLoc)
{
emitcode(";", "\taka %s", OP_SYMBOL(left)->usl.spillLoc->rname);
}
}
if (IS_SYMOP(result) && OP_SYMBOL(result)->aop)
{
emitcode(";", "result (%s) is %d", OP_SYMBOL(result)->rname, AOP_TYPE(result));
if (!IS_TRUE_SYMOP(result) && OP_SYMBOL(result)->usl.spillLoc)
{
emitcode(";", "\taka %s", OP_SYMBOL(result)->usl.spillLoc->rname);
}
}
#endif
#if VIEW_SIZE
emitcode ("; shift left ", "result %d, left %d", size,
AOP_SIZE (left));
#endif
/* I suppose that the left size >= result size */
if (shCount == 0)
{
_startLazyDPSEvaluation();
while (size--)
{
movLeft2Result (left, size, result, size, 0);
}
_endLazyDPSEvaluation();
}
else if (shCount >= (size * 8))
{
_startLazyDPSEvaluation();
while (size--)
{
aopPut (AOP (result), zero, size);
}
_endLazyDPSEvaluation();
}
else
{
switch (size)
{
case 1:
genlshOne (result, left, shCount);
break;
case 2:
genlshTwo (result, left, shCount);
break;
#if 0
case 4:
genlshFour (result, left, shCount);
break;
#endif
default:
fprintf(stderr, "*** ack! mystery literal shift!\n");
break;
}
}
freeAsmop (left, NULL, ic, TRUE);
freeAsmop (result, NULL, ic, TRUE);
return TRUE;
}
#endif
/*-----------------------------------------------------------------*/
/* genLeftShift - generates code for left shifting */
/*-----------------------------------------------------------------*/
static void
genLeftShift (iCode * ic)
{
operand *left, *right, *result;
int size, offset;
char *l;
symbol *tlbl, *tlbl1;
D (emitcode (";", "genLeftShift "););
right = IC_RIGHT (ic);
left = IC_LEFT (ic);
result = IC_RESULT (ic);
aopOp (right, ic, FALSE, FALSE);
#ifdef BETTER_LITERAL_SHIFT
/* if the shift count is known then do it
as efficiently as possible */
if (AOP_TYPE (right) == AOP_LIT)
{
if (genLeftShiftLiteral (left, right, result, ic))
{
return;
}
}
#endif
/* shift count is unknown then we have to form
a loop get the loop count in B : Note: we take
only the lower order byte since shifting
more that 32 bits make no sense anyway, ( the
largest size of an object can be only 32 bits ) */
if (AOP_TYPE (right) == AOP_LIT)
{
/* Really should be handled by genLeftShiftLiteral,
* but since I'm too lazy to fix that today, at least we can make
* some small improvement.
*/
emitcode("mov", "b,#0x%02x",
((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
}
else
{
emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE, FALSE));
emitcode ("inc", "b");
}
freeAsmop (right, NULL, ic, TRUE);
aopOp (left, ic, FALSE, FALSE);
aopOp (result, ic, FALSE, AOP_TYPE (left) == AOP_DPTR);
/* now move the left to the result if they are not the
same */
if (!sameRegs (AOP (left), AOP (result)) &&
AOP_SIZE (result) > 1)
{
size = AOP_SIZE (result);
offset = 0;
_startLazyDPSEvaluation ();
while (size--)
{
l = aopGet (AOP (left), offset, FALSE, TRUE, FALSE);
if (*l == '@' && (IS_AOP_PREG (result)))
{
emitcode ("mov", "a,%s", l);
aopPut (AOP (result), "a", offset);
}
else
aopPut (AOP (result), l, offset);
offset++;
}
_endLazyDPSEvaluation ();
}
tlbl = newiTempLabel (NULL);
size = AOP_SIZE (result);
offset = 0;
tlbl1 = newiTempLabel (NULL);
/* if it is only one byte then */
if (size == 1)
{
symbol *tlbl1 = newiTempLabel (NULL);
l = aopGet (AOP (left), 0, FALSE, FALSE, TRUE);
MOVA (l);
emitcode ("sjmp", "%05d$", tlbl1->key + 100);
emitcode ("", "%05d$:", tlbl->key + 100);
emitcode ("add", "a,acc");
emitcode ("", "%05d$:", tlbl1->key + 100);
emitcode ("djnz", "b,%05d$", tlbl->key + 100);
aopPut (AOP (result), "a", 0);
goto release;
}
reAdjustPreg (AOP (result));
emitcode ("sjmp", "%05d$", tlbl1->key + 100);
emitcode ("", "%05d$:", tlbl->key + 100);
l = aopGet (AOP (result), offset, FALSE, FALSE, TRUE);
MOVA (l);
emitcode ("add", "a,acc");
aopPut (AOP (result), "a", offset++);
_startLazyDPSEvaluation ();
while (--size)
{
l = aopGet (AOP (result), offset, FALSE, FALSE, TRUE);
MOVA (l);
emitcode ("rlc", "a");
aopPut (AOP (result), "a", offset++);
}
_endLazyDPSEvaluation ();
reAdjustPreg (AOP (result));
emitcode ("", "%05d$:", tlbl1->key + 100);
emitcode ("djnz", "b,%05d$", tlbl->key + 100);
release:
freeAsmop (left, NULL, ic, TRUE);
freeAsmop (result, NULL, ic, TRUE);
}
#ifdef BETTER_LITERAL_SHIFT
/*-----------------------------------------------------------------*/
/* genrshOne - right shift a one byte quantity by known count */
/*-----------------------------------------------------------------*/
static void
genrshOne (operand * result, operand * left,
int shCount, int sign)
{
D (emitcode (";", "genrshOne"););
shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
}
#endif
#ifdef BETTER_LITERAL_SHIFT
/*-----------------------------------------------------------------*/
/* genrshTwo - right shift two bytes by known amount != 0 */
/*-----------------------------------------------------------------*/
static void
genrshTwo (operand * result, operand * left,
int shCount, int sign)
{
D (emitcode (";", "genrshTwo"););
/* if shCount >= 8 */
if (shCount >= 8)
{
shCount -= 8;
_startLazyDPSEvaluation();
if (shCount)
{
shiftR1Left2Result (left, MSB16, result, LSB,
shCount, sign);
}
else
{
movLeft2Result (left, MSB16, result, LSB, sign);
}
addSign (result, MSB16, sign);
_endLazyDPSEvaluation();
}
/* 1 <= shCount <= 7 */
else
{
shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
}
}
#endif
#if 0
//REMOVE ME!!!
/*-----------------------------------------------------------------*/
/* shiftRLong - shift right one long from left to result */
/* offl = LSB or MSB16 */
/*-----------------------------------------------------------------*/
static void
shiftRLong (operand * left, int offl,
operand * result, int sign)
{
int isSameRegs=sameRegs(AOP(left),AOP(result));
if (isSameRegs && offl>1) {
// we are in big trouble, but this shouldn't happen
werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
}
MOVA (aopGet (AOP (left), MSB32, FALSE, FALSE));
if (offl==MSB16) {
// shift is > 8
if (sign) {
emitcode ("rlc", "a");
emitcode ("subb", "a,acc");
emitcode ("xch", "a,%s", aopGet(AOP(left), MSB32, FALSE, FALSE));
} else {
aopPut (AOP(result), zero, MSB32);
}
}
if (!sign) {
emitcode ("clr", "c");
} else {
emitcode ("mov", "c,acc.7");
}
emitcode ("rrc", "a");
if (isSameRegs && offl==MSB16) {
emitcode ("xch", "a,%s",aopGet (AOP (left), MSB24, FALSE, FALSE));
} else {
aopPut (AOP (result), "a", MSB32);
MOVA (aopGet (AOP (left), MSB24, FALSE, FALSE));
}
emitcode ("rrc", "a");
if (isSameRegs && offl==1) {
emitcode ("xch", "a,%s",aopGet (AOP (left), MSB16, FALSE, FALSE));
} else {
aopPut (AOP (result), "a", MSB24);
MOVA (aopGet (AOP (left), MSB16, FALSE, FALSE));
}
emitcode ("rrc", "a");
aopPut (AOP (result), "a", MSB16 - offl);
if (offl == LSB)
{
MOVA (aopGet (AOP (left), LSB, FALSE, FALSE));
emitcode ("rrc", "a");
aopPut (AOP (result), "a", LSB);
}
}
#endif
#if 0
//REMOVE ME!!!
/*-----------------------------------------------------------------*/
/* genrshFour - shift four byte by a known amount != 0 */
/*-----------------------------------------------------------------*/
static void
genrshFour (operand * result, operand * left,
int shCount, int sign)
{
D (emitcode (";", "genrshFour");
);
/* if shifting more that 3 bytes */
if (shCount >= 24)
{
shCount -= 24;
if (shCount)
shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
else
movLeft2Result (left, MSB32, result, LSB, sign);
addSign (result, MSB16, sign);
}
else if (shCount >= 16)
{
shCount -= 16;
if (shCount)
shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
else
{
movLeft2Result (left, MSB24, result, LSB, 0);
movLeft2Result (left, MSB32, result, MSB16, sign);
}
addSign (result, MSB24, sign);
}
else if (shCount >= 8)
{
shCount -= 8;
if (shCount == 1)
shiftRLong (left, MSB16, result, sign);
else if (shCount == 0)
{
movLeft2Result (left, MSB16, result, LSB, 0);
movLeft2Result (left, MSB24, result, MSB16, 0);
movLeft2Result (left, MSB32, result, MSB24, sign);
addSign (result, MSB32, sign);
}
else
{
shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
/* the last shift is signed */
shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
addSign (result, MSB32, sign);
}
}
else
{ /* 1 <= shCount <= 7 */
if (shCount <= 2)
{
shiftRLong (left, LSB, result, sign);
if (shCount == 2)
shiftRLong (result, LSB, result, sign);
}
else
{
shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
}
}
}
#endif
#ifdef BETTER_LITERAL_SHIFT
/*-----------------------------------------------------------------*/
/* genRightShiftLiteral - right shifting by known count */
/*-----------------------------------------------------------------*/
static bool
genRightShiftLiteral (operand * left,
operand * right,
operand * result,
iCode * ic,
int sign)
{
int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
int size;
size = getSize (operandType (result));
D(emitcode (";", "genRightShiftLiteral (%d), size %d", shCount, size););
/* We only handle certain easy cases so far. */
if ((shCount != 0)
&& (shCount < (size * 8))
&& (size != 1)
&& (size != 2))
{
D(emitcode (";", "genRightShiftLiteral wimping out"););
return FALSE;
}
freeAsmop (right, NULL, ic, TRUE);
aopOp (left, ic, FALSE, FALSE);
aopOp (result, ic, FALSE, AOP_TYPE (left) == AOP_DPTR);
#if VIEW_SIZE
emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
AOP_SIZE (left));
#endif
/* test the LEFT size !!! */
/* I suppose that the left size >= result size */
if (shCount == 0)
{
size = getDataSize (result);
_startLazyDPSEvaluation();
while (size--)
{
movLeft2Result (left, size, result, size, 0);
}
_endLazyDPSEvaluation();
}
else if (shCount >= (size * 8))
{
if (sign)
{
/* get sign in acc.7 */
MOVA (aopGet (AOP (left), size - 1, FALSE, FALSE, TRUE));
}
addSign (result, LSB, sign);
}
else
{
switch (size)
{
case 1:
genrshOne (result, left, shCount, sign);
break;
case 2:
genrshTwo (result, left, shCount, sign);
break;
#if 0
case 4:
genrshFour (result, left, shCount, sign);
break;
#endif
default:
break;
}
freeAsmop (left, NULL, ic, TRUE);
freeAsmop (result, NULL, ic, TRUE);
}
return TRUE;
}
#endif
/*-----------------------------------------------------------------*/
/* genSignedRightShift - right shift of signed number */
/*-----------------------------------------------------------------*/
static void
genSignedRightShift (iCode * ic)
{
operand *right, *left, *result;
int size, offset;
char *l;
symbol *tlbl, *tlbl1;
D (emitcode (";", "genSignedRightShift "););
/* we do it the hard way put the shift count in b
and loop thru preserving the sign */
right = IC_RIGHT (ic);
left = IC_LEFT (ic);
result = IC_RESULT (ic);
aopOp (right, ic, FALSE, FALSE);
#ifdef BETTER_LITERAL_SHIFT
if (AOP_TYPE (right) == AOP_LIT)
{
if (genRightShiftLiteral (left, right, result, ic, 1))
{
return;
}
}
#endif
/* shift count is unknown then we have to form
a loop get the loop count in B : Note: we take
only the lower order byte since shifting
more that 32 bits make no sense anyway, ( the
largest size of an object can be only 32 bits ) */
if (AOP_TYPE (right) == AOP_LIT)
{
/* Really should be handled by genRightShiftLiteral,
* but since I'm too lazy to fix that today, at least we can make
* some small improvement.
*/
emitcode("mov", "b,#0x%02x",
((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
}
else
{
emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE, FALSE));
emitcode ("inc", "b");
}
freeAsmop (right, NULL, ic, TRUE);
aopOp (left, ic, FALSE, FALSE);
aopOp (result, ic, FALSE, AOP_TYPE (left) == AOP_DPTR);
/* now move the left to the result if they are not the
same */
if (!sameRegs (AOP (left), AOP (result)) &&
AOP_SIZE (result) > 1)
{
size = AOP_SIZE (result);
offset = 0;
_startLazyDPSEvaluation ();
while (size--)
{
l = aopGet (AOP (left), offset, FALSE, TRUE, FALSE);
if (*l == '@' && IS_AOP_PREG (result))
{
emitcode ("mov", "a,%s", l);
aopPut (AOP (result), "a", offset);
}
else
aopPut (AOP (result), l, offset);
offset++;
}
_endLazyDPSEvaluation ();
}
/* mov the highest order bit to OVR */
tlbl = newiTempLabel (NULL);
tlbl1 = newiTempLabel (NULL);
size = AOP_SIZE (result);
offset = size - 1;
emitcode ("mov", "a,%s", aopGet (AOP (left), offset, FALSE, FALSE, FALSE));
emitcode ("rlc", "a");
emitcode ("mov", "ov,c");
/* if it is only one byte then */
if (size == 1)
{
l = aopGet (AOP (left), 0, FALSE, FALSE, TRUE);
MOVA (l);
emitcode ("sjmp", "%05d$", tlbl1->key + 100);
emitcode ("", "%05d$:", tlbl->key + 100);
emitcode ("mov", "c,ov");
emitcode ("rrc", "a");
emitcode ("", "%05d$:", tlbl1->key + 100);
emitcode ("djnz", "b,%05d$", tlbl->key + 100);
aopPut (AOP (result), "a", 0);
goto release;
}
reAdjustPreg (AOP (result));
emitcode ("sjmp", "%05d$", tlbl1->key + 100);
emitcode ("", "%05d$:", tlbl->key + 100);
emitcode ("mov", "c,ov");
_startLazyDPSEvaluation ();
while (size--)
{
l = aopGet (AOP (result), offset, FALSE, FALSE, TRUE);
MOVA (l);
emitcode ("rrc", "a");
aopPut (AOP (result), "a", offset--);
}
_endLazyDPSEvaluation ();
reAdjustPreg (AOP (result));
emitcode ("", "%05d$:", tlbl1->key + 100);
emitcode ("djnz", "b,%05d$", tlbl->key + 100);
release:
freeAsmop (left, NULL, ic, TRUE);
freeAsmop (result, NULL, ic, TRUE);
}
/*-----------------------------------------------------------------*/
/* genRightShift - generate code for right shifting */
/*-----------------------------------------------------------------*/
static void
genRightShift (iCode * ic)
{
operand *right, *left, *result;
sym_link *retype;
int size, offset;
char *l;
symbol *tlbl, *tlbl1;
D (emitcode (";", "genRightShift "););
/* if signed then we do it the hard way preserve the
sign bit moving it inwards */
retype = getSpec (operandType (IC_RESULT (ic)));
if (!SPEC_USIGN (retype))
{
genSignedRightShift (ic);
return;
}
/* signed & unsigned types are treated the same : i.e. the
signed is NOT propagated inwards : quoting from the
ANSI - standard : "for E1 >> E2, is equivalent to division
by 2**E2 if unsigned or if it has a non-negative value,
otherwise the result is implementation defined ", MY definition
is that the sign does not get propagated */
right = IC_RIGHT (ic);
left = IC_LEFT (ic);
result = IC_RESULT (ic);
aopOp (right, ic, FALSE, FALSE);
#ifdef BETTER_LITERAL_SHIFT
/* if the shift count is known then do it
as efficiently as possible */
if (AOP_TYPE (right) == AOP_LIT)
{
if (genRightShiftLiteral (left, right, result, ic, 0))
{
return;
}
}
#endif
/* shift count is unknown then we have to form
a loop get the loop count in B : Note: we take
only the lower order byte since shifting
more that 32 bits make no sense anyway, ( the
largest size of an object can be only 32 bits ) */
if (AOP_TYPE (right) == AOP_LIT)
{
/* Really should be handled by genRightShiftLiteral,
* but since I'm too lazy to fix that today, at least we can make
* some small improvement.
*/
emitcode("mov", "b,#0x%02x",
((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
}
else
{
emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE, FALSE));
emitcode ("inc", "b");
}
freeAsmop (right, NULL, ic, TRUE);
aopOp (left, ic, FALSE, FALSE);
aopOp (result, ic, FALSE, AOP_TYPE (left) == AOP_DPTR);
/* now move the left to the result if they are not the
same */
if (!sameRegs (AOP (left), AOP (result)) &&
AOP_SIZE (result) > 1)
{
size = AOP_SIZE (result);
offset = 0;
_startLazyDPSEvaluation ();
while (size--)
{
l = aopGet (AOP (left), offset, FALSE, TRUE, FALSE);
if (*l == '@' && IS_AOP_PREG (result))
{
emitcode ("mov", "a,%s", l);
aopPut (AOP (result), "a", offset);
}
else
aopPut (AOP (result), l, offset);
offset++;
}
_endLazyDPSEvaluation ();
}
tlbl = newiTempLabel (NULL);
tlbl1 = newiTempLabel (NULL);
size = AOP_SIZE (result);
offset = size - 1;
/* if it is only one byte then */
if (size == 1)
{
l = aopGet (AOP (left), 0, FALSE, FALSE, TRUE);
MOVA (l);
emitcode ("sjmp", "%05d$", tlbl1->key + 100);
emitcode ("", "%05d$:", tlbl->key + 100);
CLRC;
emitcode ("rrc", "a");
emitcode ("", "%05d$:", tlbl1->key + 100);
emitcode ("djnz", "b,%05d$", tlbl->key + 100);
aopPut (AOP (result), "a", 0);
goto release;
}
reAdjustPreg (AOP (result));
emitcode ("sjmp", "%05d$", tlbl1->key + 100);
emitcode ("", "%05d$:", tlbl->key + 100);
CLRC;
_startLazyDPSEvaluation ();
while (size--)
{
l = aopGet (AOP (result), offset, FALSE, FALSE, TRUE);
MOVA (l);
emitcode ("rrc", "a");
aopPut (AOP (result), "a", offset--);
}
_endLazyDPSEvaluation ();
reAdjustPreg (AOP (result));
emitcode ("", "%05d$:", tlbl1->key + 100);
emitcode ("djnz", "b,%05d$", tlbl->key + 100);
release:
freeAsmop (left, NULL, ic, TRUE);
freeAsmop (result, NULL, ic, TRUE);
}
/*-----------------------------------------------------------------*/
/* genUnpackBits - generates code for unpacking bits */
/*-----------------------------------------------------------------*/
static void
genUnpackBits (operand * result, char *rname, int ptype)
{
int shCnt;
int rlen = 0;
sym_link *etype;
int offset = 0;
D (emitcode (";", "genUnpackBits ");
);
etype = getSpec (operandType (result));
/* read the first byte */
switch (ptype)
{
case POINTER:
case IPOINTER:
emitcode ("mov", "a,@%s", rname);
break;
case PPOINTER:
emitcode ("movx", "a,@%s", rname);
break;
case FPOINTER:
emitcode ("movx", "a,@dptr");
break;
case CPOINTER:
emitcode ("clr", "a");
emitcode ("movc", "a,@a+dptr");
break;
case GPOINTER:
emitcode ("lcall", "__gptrget");
break;
}
/* if we have bitdisplacement then it fits */
/* into this byte completely or if length is */
/* less than a byte */
if ((shCnt = SPEC_BSTR (etype)) ||
(SPEC_BLEN (etype) <= 8))
{
/* shift right acc */
AccRsh (shCnt);
emitcode ("anl", "a,#0x%02x",
((unsigned char) -1) >> (8 - SPEC_BLEN (etype)));
aopPut (AOP (result), "a", offset);
return;
}
/* bit field did not fit in a byte */
rlen = SPEC_BLEN (etype) - 8;
aopPut (AOP (result), "a", offset++);
while (1)
{
switch (ptype)
{
case POINTER:
case IPOINTER:
emitcode ("inc", "%s", rname);
emitcode ("mov", "a,@%s", rname);
break;
case PPOINTER:
emitcode ("inc", "%s", rname);
emitcode ("movx", "a,@%s", rname);
break;
case FPOINTER:
emitcode ("inc", "dptr");
emitcode ("movx", "a,@dptr");
break;
case CPOINTER:
emitcode ("clr", "a");
emitcode ("inc", "dptr");
emitcode ("movc", "a,@a+dptr");
break;
case GPOINTER:
emitcode ("inc", "dptr");
emitcode ("lcall", "__gptrget");
break;
}
rlen -= 8;
/* if we are done */
if (rlen < 8)
break;
aopPut (AOP (result), "a", offset++);
}
if (rlen)
{
emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (rlen));
aopPut (AOP (result), "a", offset);
}
return;
}
/*-----------------------------------------------------------------*/
/* genDataPointerGet - generates code when ptr offset is known */
/*-----------------------------------------------------------------*/
static void
genDataPointerGet (operand * left,
operand * result,
iCode * ic)
{
char *l;
char buffer[256];
int size, offset = 0;
aopOp (result, ic, TRUE, FALSE);
/* get the string representation of the name */
l = aopGet (AOP (left), 0, FALSE, TRUE, FALSE);
size = AOP_SIZE (result);
_startLazyDPSEvaluation ();
while (size--)
{
if (offset)
sprintf (buffer, "(%s + %d)", l + 1, offset);
else
sprintf (buffer, "%s", l + 1);
aopPut (AOP (result), buffer, offset++);
}
_endLazyDPSEvaluation ();
freeAsmop (left, NULL, ic, TRUE);
freeAsmop (result, NULL, ic, TRUE);
}
/*-----------------------------------------------------------------*/
/* genNearPointerGet - emitcode for near pointer fetch */
/*-----------------------------------------------------------------*/
static void
genNearPointerGet (operand * left,
operand * result,
iCode * ic)
{
asmop *aop = NULL;
regs *preg = NULL;
char *rname;
sym_link *rtype, *retype, *letype;
sym_link *ltype = operandType (left);
char buffer[80];
rtype = operandType (result);
retype = getSpec (rtype);
letype = getSpec (ltype);
aopOp (left, ic, FALSE, FALSE);
/* if left is rematerialisable and
result is not bit variable type and
the left is pointer to data space i.e
lower 128 bytes of space */
if (AOP_TYPE (left) == AOP_IMMD &&
!IS_BITVAR (retype) &&
!IS_BITVAR (letype) &&
DCL_TYPE (ltype) == POINTER)
{
genDataPointerGet (left, result, ic);
return;
}
/* if the value is already in a pointer register
then don't need anything more */
if (!AOP_INPREG (AOP (left)))
{
/* otherwise get a free pointer register */
aop = newAsmop (0);
preg = getFreePtr (ic, &aop, FALSE);
emitcode ("mov", "%s,%s",
preg->name,
aopGet (AOP (left), 0, FALSE, TRUE, FALSE));
rname = preg->name;
}
else
rname = aopGet (AOP (left), 0, FALSE, FALSE, FALSE);
freeAsmop (left, NULL, ic, TRUE);
aopOp (result, ic, FALSE, FALSE);
/* if bitfield then unpack the bits */
if (IS_BITVAR (retype) || IS_BITVAR (letype))
genUnpackBits (result, rname, POINTER);
else
{
/* we have can just get the values */
int size = AOP_SIZE (result);
int offset = 0;
while (size--)
{
if (IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
{
emitcode ("mov", "a,@%s", rname);
aopPut (AOP (result), "a", offset);
}
else
{
sprintf (buffer, "@%s", rname);
aopPut (AOP (result), buffer, offset);
}
offset++;
if (size)
emitcode ("inc", "%s", rname);
}
}
/* now some housekeeping stuff */
if (aop)
{
/* we had to allocate for this iCode */
freeAsmop (NULL, aop, ic, TRUE);
}
else
{
/* we did not allocate which means left
already in a pointer register, then
if size > 0 && this could be used again
we have to point it back to where it
belongs */
if (AOP_SIZE (result) > 1 &&
!OP_SYMBOL (left)->remat &&
(OP_SYMBOL (left)->liveTo > ic->seq ||
ic->depth))
{
int size = AOP_SIZE (result) - 1;
while (size--)
emitcode ("dec", "%s", rname);
}
}
/* done */
freeAsmop (result, NULL, ic, TRUE);
}
/*-----------------------------------------------------------------*/
/* genPagedPointerGet - emitcode for paged pointer fetch */
/*-----------------------------------------------------------------*/
static void
genPagedPointerGet (operand * left,
operand * result,
iCode * ic)
{
asmop *aop = NULL;
regs *preg = NULL;
char *rname;
sym_link *rtype, *retype, *letype;
rtype = operandType (result);
retype = getSpec (rtype);
letype = getSpec (operandType (left));
aopOp (left, ic, FALSE, FALSE);
/* if the value is already in a pointer register
then don't need anything more */
if (!AOP_INPREG (AOP (left)))
{
/* otherwise get a free pointer register */
aop = newAsmop (0);
preg = getFreePtr (ic, &aop, FALSE);
emitcode ("mov", "%s,%s",
preg->name,
aopGet (AOP (left), 0, FALSE, TRUE, FALSE));
rname = preg->name;
}
else
rname = aopGet (AOP (left), 0, FALSE, FALSE, FALSE);
freeAsmop (left, NULL, ic, TRUE);
aopOp (result, ic, FALSE, FALSE);
/* if bitfield then unpack the bits */
if (IS_BITVAR (retype) || IS_BITVAR (letype))
genUnpackBits (result, rname, PPOINTER);
else
{
/* we have can just get the values */
int size = AOP_SIZE (result);
int offset = 0;
while (size--)
{
emitcode ("movx", "a,@%s", rname);
aopPut (AOP (result), "a", offset);
offset++;
if (size)
emitcode ("inc", "%s", rname);
}
}
/* now some housekeeping stuff */
if (aop)
{
/* we had to allocate for this iCode */
freeAsmop (NULL, aop, ic, TRUE);
}
else
{
/* we did not allocate which means left
already in a pointer register, then
if size > 0 && this could be used again
we have to point it back to where it
belongs */
if (AOP_SIZE (result) > 1 &&
!OP_SYMBOL (left)->remat &&
(OP_SYMBOL (left)->liveTo > ic->seq ||
ic->depth))
{
int size = AOP_SIZE (result) - 1;
while (size--)
emitcode ("dec", "%s", rname);
}
}
/* done */
freeAsmop (result, NULL, ic, TRUE);
}
/*-----------------------------------------------------------------*/
/* genFarPointerGet - gget value from far space */
/*-----------------------------------------------------------------*/
static void
genFarPointerGet (operand * left,
operand * result, iCode * ic)
{
int size, offset;
sym_link *retype = getSpec (operandType (result));
sym_link *letype = getSpec (operandType (left));
D (emitcode (";", "genFarPointerGet");
);
aopOp (left, ic, FALSE, FALSE);
/* if the operand is already in dptr
then we do nothing else we move the value to dptr */
if (AOP_TYPE (left) != AOP_STR)
{
/* if this is remateriazable */
if (AOP_TYPE (left) == AOP_IMMD)
{
emitcode ("mov", "dptr,%s", aopGet (AOP (left), 0, TRUE, FALSE, FALSE));
}
else
{
/* we need to get it byte by byte */
_startLazyDPSEvaluation ();
if (AOP_TYPE (left) != AOP_DPTR)
{
emitcode ("mov", "dpl,%s", aopGet (AOP (left), 0, FALSE, FALSE, TRUE));
emitcode ("mov", "dph,%s", aopGet (AOP (left), 1, FALSE, FALSE, TRUE));
if (options.model == MODEL_FLAT24)
emitcode ("mov", "dpx,%s", aopGet (AOP (left), 2, FALSE, FALSE, TRUE));
}
else
{
/* We need to generate a load to DPTR indirect through DPTR. */
D (emitcode (";", "genFarPointerGet -- indirection special case.");
);
emitcode ("push", "%s", aopGet (AOP (left), 0, FALSE, TRUE, TRUE));
emitcode ("push", "%s", aopGet (AOP (left), 1, FALSE, TRUE, TRUE));
if (options.model == MODEL_FLAT24)
emitcode ("mov", "dpx,%s", aopGet (AOP (left), 2, FALSE, FALSE, TRUE));
emitcode ("pop", "dph");
emitcode ("pop", "dpl");
}
_endLazyDPSEvaluation ();
}
}
/* so dptr know contains the address */
freeAsmop (left, NULL, ic, TRUE);
aopOp (result, ic, FALSE, TRUE);
/* if bit then unpack */
if (IS_BITVAR (retype) || IS_BITVAR (letype))
genUnpackBits (result, "dptr", FPOINTER);
else
{
size = AOP_SIZE (result);
offset = 0;
_startLazyDPSEvaluation ();
while (size--)
{
genSetDPTR (0);
_flushLazyDPS ();
emitcode ("movx", "a,@dptr");
if (size)
emitcode ("inc", "dptr");
aopPut (AOP (result), "a", offset++);
}
_endLazyDPSEvaluation ();
}
freeAsmop (result, NULL, ic, TRUE);
}
/*-----------------------------------------------------------------*/
/* emitcodePointerGet - gget value from code space */
/*-----------------------------------------------------------------*/
static void
emitcodePointerGet (operand * left,
operand * result, iCode * ic)
{
int size, offset;
sym_link *retype = getSpec (operandType (result));
aopOp (left, ic, FALSE, FALSE);
/* if the operand is already in dptr
then we do nothing else we move the value to dptr */
if (AOP_TYPE (left) != AOP_STR)
{
/* if this is remateriazable */
if (AOP_TYPE (left) == AOP_IMMD)
{
emitcode ("mov", "dptr,%s", aopGet (AOP (left), 0, TRUE, FALSE, FALSE));
}
else
{ /* we need to get it byte by byte */
_startLazyDPSEvaluation ();
if (AOP_TYPE (left) != AOP_DPTR)
{
emitcode ("mov", "dpl,%s", aopGet (AOP (left), 0, FALSE, FALSE, TRUE));
emitcode ("mov", "dph,%s", aopGet (AOP (left), 1, FALSE, FALSE, TRUE));
if (options.model == MODEL_FLAT24)
emitcode ("mov", "dpx,%s", aopGet (AOP (left), 2, FALSE, FALSE, TRUE));
}
else
{
/* We need to generate a load to DPTR indirect through DPTR. */
D (emitcode (";", "gencodePointerGet -- indirection special case.");
);
emitcode ("push", "%s", aopGet (AOP (left), 0, FALSE, TRUE, TRUE));
emitcode ("push", "%s", aopGet (AOP (left), 1, FALSE, TRUE, TRUE));
if (options.model == MODEL_FLAT24)
emitcode ("mov", "dpx,%s", aopGet (AOP (left), 2, FALSE, FALSE, TRUE));
emitcode ("pop", "dph");
emitcode ("pop", "dpl");
}
_endLazyDPSEvaluation ();
}
}
/* so dptr know contains the address */
freeAsmop (left, NULL, ic, TRUE);
aopOp (result, ic, FALSE, TRUE);
/* if bit then unpack */
if (IS_BITVAR (retype))
genUnpackBits (result, "dptr", CPOINTER);
else
{
size = AOP_SIZE (result);
offset = 0;
_startLazyDPSEvaluation ();
while (size--)
{
genSetDPTR (0);
_flushLazyDPS ();
emitcode ("clr", "a");
emitcode ("movc", "a,@a+dptr");
if (size)
emitcode ("inc", "dptr");
aopPut (AOP (result), "a", offset++);
}
_endLazyDPSEvaluation ();
}
freeAsmop (result, NULL, ic, TRUE);
}
/*-----------------------------------------------------------------*/
/* genGenPointerGet - gget value from generic pointer space */
/*-----------------------------------------------------------------*/
static void
genGenPointerGet (operand * left,
operand * result, iCode * ic)
{
int size, offset;
sym_link *retype = getSpec (operandType (result));
sym_link *letype = getSpec (operandType (left));
D (emitcode (";", "genGenPointerGet "); );
aopOp (left, ic, FALSE, TRUE);
/* if the operand is already in dptr
then we do nothing else we move the value to dptr */
if (AOP_TYPE (left) != AOP_STR)
{
/* if this is remateriazable */
if (AOP_TYPE (left) == AOP_IMMD)
{
emitcode ("mov", "dptr,%s", aopGet (AOP (left), 0, TRUE, FALSE, FALSE));
emitcode ("mov", "b,#%d", pointerCode (retype));
}
else
{ /* we need to get it byte by byte */
_startLazyDPSEvaluation ();
if (AOP(left)->type==AOP_DPTR2) {
char *l;
l=aopGet(AOP(left),0,FALSE,FALSE,TRUE);
genSetDPTR(0);
_flushLazyDPS();
emitcode ("mov", "dpl,%s", l);
l=aopGet(AOP(left),1,FALSE,FALSE,TRUE);
genSetDPTR(0);
_flushLazyDPS();
emitcode ("mov", "dph,%s", l);
if (options.model == MODEL_FLAT24) {
l=aopGet(AOP(left),2,FALSE,FALSE,TRUE);
genSetDPTR(0);
_flushLazyDPS();
emitcode ("mov", "dpx,%s", l);
emitcode ("mov", "b,%s", aopGet (AOP(left),3,FALSE,FALSE,TRUE));
} else {
emitcode ("mov", "b,%s", aopGet (AOP(left),2,FALSE,FALSE,TRUE));
}
} else {
emitcode ("mov", "dpl,%s", aopGet (AOP(left),0,FALSE,FALSE,TRUE));
emitcode ("mov", "dph,%s", aopGet (AOP(left),1,FALSE,FALSE,TRUE));
if (options.model == MODEL_FLAT24) {
emitcode ("mov", "dpx,%s", aopGet (AOP(left),2,FALSE,FALSE,TRUE));
emitcode ("mov", "b,%s", aopGet (AOP(left),3,FALSE,FALSE,TRUE));
} else {
emitcode ("mov", "b,%s", aopGet (AOP(left),2,FALSE,FALSE,TRUE));
}
}
_endLazyDPSEvaluation ();
}
}
/* so dptr know contains the address */
freeAsmop (left, NULL, ic, TRUE);
aopOp (result, ic, FALSE, TRUE);
/* if bit then unpack */
if (IS_BITVAR (retype) || IS_BITVAR (letype))
genUnpackBits (result, "dptr", GPOINTER);
else
{
size = AOP_SIZE (result);
offset = 0;
while (size--)
{
emitcode ("lcall", "__gptrget");
aopPut (AOP (result), "a", offset++);
if (size)
emitcode ("inc", "dptr");
}
}
freeAsmop (result, NULL, ic, TRUE);
}
/*-----------------------------------------------------------------*/
/* genPointerGet - generate code for pointer get */
/*-----------------------------------------------------------------*/
static void
genPointerGet (iCode * ic)
{
operand *left, *result;
sym_link *type, *etype;
int p_type;
D (emitcode (";", "genPointerGet ");
);
left = IC_LEFT (ic);
result = IC_RESULT (ic);
/* depending on the type of pointer we need to
move it to the correct pointer register */
type = operandType (left);
etype = getSpec (type);
/* if left is of type of pointer then it is simple */
if (IS_PTR (type) && !IS_FUNC (type->next))
p_type = DCL_TYPE (type);
else
{
/* we have to go by the storage class */
p_type = PTR_TYPE (SPEC_OCLS (etype));
}
/* now that we have the pointer type we assign
the pointer values */
switch (p_type)
{
case POINTER:
case IPOINTER:
genNearPointerGet (left, result, ic);
break;
case PPOINTER:
genPagedPointerGet (left, result, ic);
break;
case FPOINTER:
genFarPointerGet (left, result, ic);
break;
case CPOINTER:
emitcodePointerGet (left, result, ic);
break;
case GPOINTER:
genGenPointerGet (left, result, ic);
break;
}
}
/*-----------------------------------------------------------------*/
/* genPackBits - generates code for packed bit storage */
/*-----------------------------------------------------------------*/
static void
genPackBits (sym_link * etype,
operand * right,
char *rname, int p_type)
{
int shCount = 0;
int offset = 0;
int rLen = 0;
int blen, bstr;
char *l;
blen = SPEC_BLEN (etype);
bstr = SPEC_BSTR (etype);
l = aopGet (AOP (right), offset++, FALSE, FALSE, TRUE);
MOVA (l);
/* if the bit lenth is less than or */
/* it exactly fits a byte then */
if (SPEC_BLEN (etype) <= 8)
{
shCount = SPEC_BSTR (etype);
/* shift left acc */
AccLsh (shCount);
if (SPEC_BLEN (etype) < 8)
{ /* if smaller than a byte */
switch (p_type)
{
case POINTER:
emitcode ("mov", "b,a");
emitcode ("mov", "a,@%s", rname);
break;
case FPOINTER:
emitcode ("mov", "b,a");
emitcode ("movx", "a,@dptr");
break;
case GPOINTER:
emitcode ("push", "b");
emitcode ("push", "acc");
emitcode ("lcall", "__gptrget");
emitcode ("pop", "b");
break;
}
emitcode ("anl", "a,#0x%02x", (unsigned char)
((unsigned char) (0xFF << (blen + bstr)) |
(unsigned char) (0xFF >> (8 - bstr))));
emitcode ("orl", "a,b");
if (p_type == GPOINTER)
emitcode ("pop", "b");
}
}
switch (p_type)
{
case POINTER:
emitcode ("mov", "@%s,a", rname);
break;
case FPOINTER:
emitcode ("movx", "@dptr,a");
break;
case GPOINTER:
emitcode ("lcall", "__gptrput");
break;
}
/* if we r done */
if (SPEC_BLEN (etype) <= 8)
return;
emitcode ("inc", "%s", rname);
rLen = SPEC_BLEN (etype);
/* now generate for lengths greater than one byte */
while (1)
{
l = aopGet (AOP (right), offset++, FALSE, TRUE, FALSE);
rLen -= 8;
if (rLen < 8)
break;
switch (p_type)
{
case POINTER:
if (*l == '@')
{
MOVA (l);
emitcode ("mov", "@%s,a", rname);
}
else
emitcode ("mov", "@%s,%s", rname, l);
break;
case FPOINTER:
MOVA (l);
emitcode ("movx", "@dptr,a");
break;
case GPOINTER:
MOVA (l);
emitcode ("lcall", "__gptrput");
break;
}
emitcode ("inc", "%s", rname);
}
MOVA (l);
/* last last was not complete */
if (rLen)
{
/* save the byte & read byte */
switch (p_type)
{
case POINTER:
emitcode ("mov", "b,a");
emitcode ("mov", "a,@%s", rname);
break;
case FPOINTER:
emitcode ("mov", "b,a");
emitcode ("movx", "a,@dptr");
break;
case GPOINTER:
emitcode ("push", "b");
emitcode ("push", "acc");
emitcode ("lcall", "__gptrget");
emitcode ("pop", "b");
break;
}
emitcode ("anl", "a,#0x%02x", ((unsigned char) -1 << rLen));
emitcode ("orl", "a,b");
}
if (p_type == GPOINTER)
emitcode ("pop", "b");
switch (p_type)
{
case POINTER:
emitcode ("mov", "@%s,a", rname);
break;
case FPOINTER:
emitcode ("movx", "@dptr,a");
break;
case GPOINTER:
emitcode ("lcall", "__gptrput");
break;
}
}
/*-----------------------------------------------------------------*/
/* genDataPointerSet - remat pointer to data space */
/*-----------------------------------------------------------------*/
static void
genDataPointerSet (operand * right,
operand * result,
iCode * ic)
{
int size, offset = 0;
char *l, buffer[256];
aopOp (right, ic, FALSE, FALSE);
l = aopGet (AOP (result), 0, FALSE, TRUE, FALSE);
size = AOP_SIZE (right);
while (size--)
{
if (offset)
sprintf (buffer, "(%s + %d)", l + 1, offset);
else
sprintf (buffer, "%s", l + 1);
emitcode ("mov", "%s,%s", buffer,
aopGet (AOP (right), offset++, FALSE, FALSE, FALSE));
}
freeAsmop (right, NULL, ic, TRUE);
freeAsmop (result, NULL, ic, TRUE);
}
/*-----------------------------------------------------------------*/
/* genNearPointerSet - emitcode for near pointer put */
/*-----------------------------------------------------------------*/
static void
genNearPointerSet (operand * right,
operand * result,
iCode * ic)
{
asmop *aop = NULL;
regs *preg = NULL;
char *rname, *l;
sym_link *retype, *letype;
sym_link *ptype = operandType (result);
retype = getSpec (operandType (right));
letype = getSpec (ptype);
aopOp (result, ic, FALSE, FALSE);
/* if the result is rematerializable &
in data space & not a bit variable */
if (AOP_TYPE (result) == AOP_IMMD &&
DCL_TYPE (ptype) == POINTER &&
!IS_BITVAR (retype) &&
!IS_BITVAR (letype))
{
genDataPointerSet (right, result, ic);
return;
}
/* if the value is already in a pointer register
then don't need anything more */
if (!AOP_INPREG (AOP (result)))
{
/* otherwise get a free pointer register */
aop = newAsmop (0);
preg = getFreePtr (ic, &aop, FALSE);
emitcode ("mov", "%s,%s",
preg->name,
aopGet (AOP (result), 0, FALSE, TRUE, FALSE));
rname = preg->name;
}
else
rname = aopGet (AOP (result), 0, FALSE, FALSE, FALSE);
freeAsmop (result, NULL, ic, TRUE);
aopOp (right, ic, FALSE, FALSE);
/* if bitfield then unpack the bits */
if (IS_BITVAR (retype) || IS_BITVAR (letype))
genPackBits ((IS_BITVAR (retype) ? retype : letype), right, rname, POINTER);
else
{
/* we have can just get the values */
int size = AOP_SIZE (right);
int offset = 0;
while (size--)
{
l = aopGet (AOP (right), offset, FALSE, TRUE, FALSE);
if (*l == '@')
{
MOVA (l);
emitcode ("mov", "@%s,a", rname);
}
else
emitcode ("mov", "@%s,%s", rname, l);
if (size)
emitcode ("inc", "%s", rname);
offset++;
}
}
/* now some housekeeping stuff */
if (aop)
{
/* we had to allocate for this iCode */
freeAsmop (NULL, aop, ic, TRUE);
}
else
{
/* we did not allocate which means left
already in a pointer register, then
if size > 0 && this could be used again
we have to point it back to where it
belongs */
if (AOP_SIZE (right) > 1 &&
!OP_SYMBOL (result)->remat &&
(OP_SYMBOL (result)->liveTo > ic->seq ||
ic->depth))
{
int size = AOP_SIZE (right) - 1;
while (size--)
emitcode ("dec", "%s", rname);
}
}
/* done */
freeAsmop (right, NULL, ic, TRUE);
}
/*-----------------------------------------------------------------*/
/* genPagedPointerSet - emitcode for Paged pointer put */
/*-----------------------------------------------------------------*/
static void
genPagedPointerSet (operand * right,
operand * result,
iCode * ic)
{
asmop *aop = NULL;
regs *preg = NULL;
char *rname, *l;
sym_link *retype, *letype;
retype = getSpec (operandType (right));
letype = getSpec (operandType (result));
aopOp (result, ic, FALSE, FALSE);
/* if the value is already in a pointer register
then don't need anything more */
if (!AOP_INPREG (AOP (result)))
{
/* otherwise get a free pointer register */
aop = newAsmop (0);
preg = getFreePtr (ic, &aop, FALSE);
emitcode ("mov", "%s,%s",
preg->name,
aopGet (AOP (result), 0, FALSE, TRUE, FALSE));
rname = preg->name;
}
else
rname = aopGet (AOP (result), 0, FALSE, FALSE, FALSE);
freeAsmop (result, NULL, ic, TRUE);
aopOp (right, ic, FALSE, FALSE);
/* if bitfield then unpack the bits */
if (IS_BITVAR (retype) || IS_BITVAR (letype))
genPackBits ((IS_BITVAR (retype) ? retype : letype), right, rname, PPOINTER);
else
{
/* we have can just get the values */
int size = AOP_SIZE (right);
int offset = 0;
while (size--)
{
l = aopGet (AOP (right), offset, FALSE, TRUE, TRUE);
MOVA (l);
emitcode ("movx", "@%s,a", rname);
if (size)
emitcode ("inc", "%s", rname);
offset++;
}
}
/* now some housekeeping stuff */
if (aop)
{
/* we had to allocate for this iCode */
freeAsmop (NULL, aop, ic, TRUE);
}
else
{
/* we did not allocate which means left
already in a pointer register, then
if size > 0 && this could be used again
we have to point it back to where it
belongs */
if (AOP_SIZE (right) > 1 &&
!OP_SYMBOL (result)->remat &&
(OP_SYMBOL (result)->liveTo > ic->seq ||
ic->depth))
{
int size = AOP_SIZE (right) - 1;
while (size--)
emitcode ("dec", "%s", rname);
}
}
/* done */
freeAsmop (right, NULL, ic, TRUE);
}
/*-----------------------------------------------------------------*/
/* genFarPointerSet - set value from far space */
/*-----------------------------------------------------------------*/
static void
genFarPointerSet (operand * right,
operand * result, iCode * ic)
{
int size, offset;
sym_link *retype = getSpec (operandType (right));
sym_link *letype = getSpec (operandType (result));
aopOp (result, ic, FALSE, FALSE);
/* if the operand is already in dptr
then we do nothing else we move the value to dptr */
if (AOP_TYPE (result) != AOP_STR)
{
/* if this is remateriazable */
if (AOP_TYPE (result) == AOP_IMMD)
emitcode ("mov", "dptr,%s", aopGet (AOP (result), 0, TRUE, FALSE, FALSE));
else
{
/* we need to get it byte by byte */
_startLazyDPSEvaluation ();
if (AOP_TYPE (result) != AOP_DPTR)
{
emitcode ("mov", "dpl,%s", aopGet (AOP (result), 0, FALSE, FALSE, TRUE));
emitcode ("mov", "dph,%s", aopGet (AOP (result), 1, FALSE, FALSE, TRUE));
if (options.model == MODEL_FLAT24)
emitcode ("mov", "dpx,%s", aopGet (AOP (result), 2, FALSE, FALSE, TRUE));
}
else
{
/* We need to generate a load to DPTR indirect through DPTR. */
D (emitcode (";", "genFarPointerSet -- indirection special case.");
);
emitcode ("push", "%s", aopGet (AOP (result), 0, FALSE, TRUE, TRUE));
emitcode ("push", "%s", aopGet (AOP (result), 1, FALSE, TRUE, TRUE));
if (options.model == MODEL_FLAT24)
emitcode ("mov", "dpx,%s", aopGet (AOP (result), 2, FALSE, FALSE, TRUE));
emitcode ("pop", "dph");
emitcode ("pop", "dpl");
}
_endLazyDPSEvaluation ();
}
}
/* so dptr know contains the address */
freeAsmop (result, NULL, ic, TRUE);
aopOp (right, ic, FALSE, TRUE);
/* if bit then unpack */
if (IS_BITVAR (retype) || IS_BITVAR (letype))
genPackBits ((IS_BITVAR (retype) ? retype : letype), right, "dptr", FPOINTER);
else
{
size = AOP_SIZE (right);
offset = 0;
_startLazyDPSEvaluation ();
while (size--)
{
char *l = aopGet (AOP (right), offset++, FALSE, FALSE, TRUE);
MOVA (l);
genSetDPTR (0);
_flushLazyDPS ();
emitcode ("movx", "@dptr,a");
if (size)
emitcode ("inc", "dptr");
}
_endLazyDPSEvaluation ();
}
freeAsmop (right, NULL, ic, TRUE);
}
/*-----------------------------------------------------------------*/
/* genGenPointerSet - set value from generic pointer space */
/*-----------------------------------------------------------------*/
static void
genGenPointerSet (operand * right,
operand * result, iCode * ic)
{
int size, offset;
sym_link *retype = getSpec (operandType (right));
sym_link *letype = getSpec (operandType (result));
aopOp (result, ic, FALSE, TRUE);
/* if the operand is already in dptr
then we do nothing else we move the value to dptr */
if (AOP_TYPE (result) != AOP_STR)
{
_startLazyDPSEvaluation ();
/* if this is remateriazable */
if (AOP_TYPE (result) == AOP_IMMD)
{
emitcode ("mov", "dptr,%s", aopGet (AOP (result), 0, TRUE, FALSE, FALSE));
emitcode ("mov", "b,%s + 1", aopGet (AOP (result), 0, TRUE, FALSE, FALSE));
}
else
{ /* we need to get it byte by byte */
emitcode ("mov", "dpl,%s", aopGet (AOP (result), 0, FALSE, FALSE, TRUE));
emitcode ("mov", "dph,%s", aopGet (AOP (result), 1, FALSE, FALSE, TRUE));
if (options.model == MODEL_FLAT24) {
emitcode ("mov", "dpx,%s", aopGet (AOP (result), 2, FALSE, FALSE, TRUE));
emitcode ("mov", "b,%s", aopGet (AOP (result), 3, FALSE, FALSE, TRUE));
} else {
emitcode ("mov", "b,%s", aopGet (AOP (result), 2, FALSE, FALSE, TRUE));
}
}
_endLazyDPSEvaluation ();
}
/* so dptr know contains the address */
freeAsmop (result, NULL, ic, TRUE);
aopOp (right, ic, FALSE, TRUE);
/* if bit then unpack */
if (IS_BITVAR (retype) || IS_BITVAR (letype))
genPackBits ((IS_BITVAR (retype) ? retype : letype), right, "dptr", GPOINTER);
else
{
size = AOP_SIZE (right);
offset = 0;
_startLazyDPSEvaluation ();
while (size--)
{
char *l = aopGet (AOP (right), offset++, FALSE, FALSE, TRUE);
MOVA (l);
genSetDPTR (0);
_flushLazyDPS ();
emitcode ("lcall", "__gptrput");
if (size)
emitcode ("inc", "dptr");
}
_endLazyDPSEvaluation ();
}
freeAsmop (right, NULL, ic, TRUE);
}
/*-----------------------------------------------------------------*/
/* genPointerSet - stores the value into a pointer location */
/*-----------------------------------------------------------------*/
static void
genPointerSet (iCode * ic)
{
operand *right, *result;
sym_link *type, *etype;
int p_type;
D (emitcode (";", "genPointerSet ");
);
right = IC_RIGHT (ic);
result = IC_RESULT (ic);
/* depending on the type of pointer we need to
move it to the correct pointer register */
type = operandType (result);
etype = getSpec (type);
/* if left is of type of pointer then it is simple */
if (IS_PTR (type) && !IS_FUNC (type->next))
{
p_type = DCL_TYPE (type);
}
else
{
/* we have to go by the storage class */
p_type = PTR_TYPE (SPEC_OCLS (etype));
}
/* now that we have the pointer type we assign
the pointer values */
switch (p_type)
{
case POINTER:
case IPOINTER:
genNearPointerSet (right, result, ic);
break;
case PPOINTER:
genPagedPointerSet (right, result, ic);
break;
case FPOINTER:
genFarPointerSet (right, result, ic);
break;
case GPOINTER:
genGenPointerSet (right, result, ic);
break;
}
}
/*-----------------------------------------------------------------*/
/* genIfx - generate code for Ifx statement */
/*-----------------------------------------------------------------*/
static void
genIfx (iCode * ic, iCode * popIc)
{
operand *cond = IC_COND (ic);
int isbit = 0;
D (emitcode (";", "genIfx "););
aopOp (cond, ic, FALSE, FALSE);
/* get the value into acc */
if (AOP_TYPE (cond) != AOP_CRY)
toBoolean (cond);
else
isbit = 1;
/* the result is now in the accumulator */
freeAsmop (cond, NULL, ic, TRUE);
/* if there was something to be popped then do it */
if (popIc)
genIpop (popIc);
/* if the condition is a bit variable */
if (isbit && IS_ITEMP (cond) &&
SPIL_LOC (cond))
genIfxJump (ic, SPIL_LOC (cond)->rname);
else if (isbit && !IS_ITEMP (cond))
genIfxJump (ic, OP_SYMBOL (cond)->rname);
else
genIfxJump (ic, "a");
ic->generated = 1;
}
/*-----------------------------------------------------------------*/
/* genAddrOf - generates code for address of */
/*-----------------------------------------------------------------*/
static void
genAddrOf (iCode * ic)
{
symbol *sym = OP_SYMBOL (IC_LEFT (ic));
int size, offset;
D (emitcode (";", "genAddrOf ");
);
aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
/* if the operand is on the stack then we
need to get the stack offset of this
variable */
if (sym->onStack)
{
/* if it has an offset then we need to compute
it */
if (sym->stack)
{
emitcode ("mov", "a,_bp");
emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
aopPut (AOP (IC_RESULT (ic)), "a", 0);
}
else
{
/* we can just move _bp */
aopPut (AOP (IC_RESULT (ic)), "_bp", 0);
}
/* fill the result with zero */
size = AOP_SIZE (IC_RESULT (ic)) - 1;
if (options.stack10bit && size < (FPTRSIZE - 1))
{
fprintf (stderr,
"*** warning: pointer to stack var truncated.\n");
}
offset = 1;
while (size--)
{
/* Yuck! */
if (options.stack10bit && offset == 2)
{
aopPut (AOP (IC_RESULT (ic)), "#0x40", offset++);
}
else
{
aopPut (AOP (IC_RESULT (ic)), zero, offset++);
}
}
goto release;
}
/* object not on stack then we need the name */
size = AOP_SIZE (IC_RESULT (ic));
offset = 0;
while (size--)
{
char s[SDCC_NAME_MAX];
if (offset)
sprintf (s, "#(%s >> %d)",
sym->rname,
offset * 8);
else
sprintf (s, "#%s", sym->rname);
aopPut (AOP (IC_RESULT (ic)), s, offset++);
}
release:
freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
}
/*-----------------------------------------------------------------*/
/* genArrayInit - generates code for address of */
/*-----------------------------------------------------------------*/
static void
genArrayInit (iCode * ic)
{
literalList *iLoop;
int ix, count;
int elementSize = 0, eIndex;
unsigned val, lastVal;
sym_link *type;
operand *left=IC_LEFT(ic);
D (emitcode (";", "genArrayInit "););
aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
{
// Load immediate value into DPTR.
emitcode("mov", "dptr, %s",
aopGet(AOP(IC_LEFT(ic)), 0, TRUE, FALSE, TRUE));
}
else if (AOP_TYPE(IC_LEFT(ic)) != AOP_DPTR)
{
#if 0
werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
"Unexpected operand to genArrayInit.\n");
exit(1);
#else
// a regression because of SDCCcse.c:1.52
emitcode ("mov", "dpl,%s", aopGet (AOP (left), 0, FALSE, FALSE, TRUE));
emitcode ("mov", "dph,%s", aopGet (AOP (left), 1, FALSE, FALSE, TRUE));
if (options.model == MODEL_FLAT24)
emitcode ("mov", "dpx,%s", aopGet (AOP (left), 2, FALSE, FALSE, TRUE));
#endif
}
type = operandType(IC_LEFT(ic));
if (type && type->next)
{
elementSize = getSize(type->next);
}
else
{
werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
"can't determine element size in genArrayInit.\n");
exit(1);
}
iLoop = IC_ARRAYILIST(ic);
lastVal = 0xffff;
while (iLoop)
{
bool firstpass = TRUE;
emitcode(";", "store %d x 0x%x to DPTR (element size %d)",
iLoop->count, (int)iLoop->literalValue, elementSize);
ix = iLoop->count;
while (ix)
{
symbol *tlbl = NULL;
count = ix > 256 ? 256 : ix;
if (count > 1)
{
tlbl = newiTempLabel (NULL);
if (firstpass || (count & 0xff))
{
emitcode("mov", "b, #0x%x", count & 0xff);
}
emitcode ("", "%05d$:", tlbl->key + 100);
}
firstpass = FALSE;
for (eIndex = 0; eIndex < elementSize; eIndex++)
{
val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
if (val != lastVal)
{
emitcode("mov", "a, #0x%x", val);
lastVal = val;
}
emitcode("movx", "@dptr, a");
emitcode("inc", "dptr");
}
if (count > 1)
{
emitcode("djnz", "b, %05d$", tlbl->key + 100);
}
ix -= count;
}
iLoop = iLoop->next;
}
freeAsmop (IC_LEFT(ic), NULL, ic, TRUE);
}
/*-----------------------------------------------------------------*/
/* genFarFarAssign - assignment when both are in far space */
/*-----------------------------------------------------------------*/
static void
genFarFarAssign (operand * result, operand * right, iCode * ic)
{
int size = AOP_SIZE (right);
int offset = 0;
symbol *rSym = NULL;
if (size == 1)
{
/* quick & easy case. */
D(emitcode(";","genFarFarAssign (1 byte case)"););
MOVA(aopGet(AOP(right), 0, FALSE, FALSE, TRUE));
freeAsmop (right, NULL, ic, FALSE);
/* now assign DPTR to result */
_G.accInUse++;
aopOp(result, ic, FALSE, FALSE);
_G.accInUse--;
aopPut(AOP(result), "a", 0);
freeAsmop(result, NULL, ic, FALSE);
return;
}
/* See if we've got an underlying symbol to abuse. */
if (IS_SYMOP(result) && OP_SYMBOL(result))
{
if (IS_TRUE_SYMOP(result))
{
rSym = OP_SYMBOL(result);
}
else if (IS_ITEMP(result) && OP_SYMBOL(result)->isspilt && OP_SYMBOL(result)->usl.spillLoc)
{
rSym = OP_SYMBOL(result)->usl.spillLoc;
}
}
if (size > 1 && rSym && rSym->rname && !rSym->onStack)
{
/* We can use the '390 auto-toggle feature to good effect here. */
D(emitcode(";","genFarFarAssign (390 auto-toggle fun)"););
emitcode("mov", "dps, #0x21"); /* Select DPTR2 & auto-toggle. */
emitcode ("mov", "dptr,#%s", rSym->rname);
/* DP2 = result, DP1 = right, DP1 is current. */
while (size)
{
emitcode("movx", "a,@dptr");
emitcode("movx", "@dptr,a");
if (--size)
{
emitcode("inc", "dptr");
emitcode("inc", "dptr");
}
}
emitcode("mov", "dps, #0");
freeAsmop (right, NULL, ic, FALSE);
#if 0
some alternative code for processors without auto-toggle
no time to test now, so later well put in...kpb
D(emitcode(";","genFarFarAssign (dual-dptr fun)"););
emitcode("mov", "dps, #0x01"); /* Select DPTR2. */
emitcode ("mov", "dptr,#%s", rSym->rname);
/* DP2 = result, DP1 = right, DP1 is current. */
while (size)
{
--size;
emitcode("movx", "a,@dptr");
if (size)
emitcode("inc", "dptr");
emitcode("inc", "dps");
emitcode("movx", "@dptr,a");
if (size)
emitcode("inc", "dptr");
emitcode("inc", "dps");
}
emitcode("mov", "dps, #0");
freeAsmop (right, NULL, ic, FALSE);
#endif
}
else
{
D (emitcode (";", "genFarFarAssign"););
aopOp (result, ic, TRUE, TRUE);
_startLazyDPSEvaluation ();
while (size--)
{
aopPut (AOP (result),
aopGet (AOP (right), offset, FALSE, FALSE, FALSE), offset);
offset++;
}
_endLazyDPSEvaluation ();
freeAsmop (result, NULL, ic, FALSE);
freeAsmop (right, NULL, ic, FALSE);
}
}
/*-----------------------------------------------------------------*/
/* genAssign - generate code for assignment */
/*-----------------------------------------------------------------*/
static void
genAssign (iCode * ic)
{
operand *result, *right;
int size, offset;
unsigned long lit = 0L;
D (emitcode (";", "genAssign ");
);
result = IC_RESULT (ic);
right = IC_RIGHT (ic);
/* if they are the same */
if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
return;
aopOp (right, ic, FALSE, FALSE);
emitcode (";", "genAssign: resultIsFar = %s",
isOperandInFarSpace (result) ?
"TRUE" : "FALSE");
/* special case both in far space */
if ((AOP_TYPE (right) == AOP_DPTR ||
AOP_TYPE (right) == AOP_DPTR2) &&
/* IS_TRUE_SYMOP(result) && */
isOperandInFarSpace (result))
{
genFarFarAssign (result, right, ic);
return;
}
aopOp (result, ic, TRUE, FALSE);
/* if they are the same registers */
if (sameRegs (AOP (right), AOP (result)))
goto release;
/* if the result is a bit */
if (AOP_TYPE (result) == AOP_CRY) /* works only for true symbols */
{
/* if the right size is a literal then
we know what the value is */
if (AOP_TYPE (right) == AOP_LIT)
{
if (((int) operandLitValue (right)))
aopPut (AOP (result), one, 0);
else
aopPut (AOP (result), zero, 0);
goto release;
}
/* the right is also a bit variable */
if (AOP_TYPE (right) == AOP_CRY)
{
emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
aopPut (AOP (result), "c", 0);
goto release;
}
/* we need to or */
toBoolean (right);
aopPut (AOP (result), "a", 0);
goto release;
}
/* bit variables done */
/* general case */
size = AOP_SIZE (result);
offset = 0;
if (AOP_TYPE (right) == AOP_LIT)
lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
if ((size > 1) &&
(AOP_TYPE (result) != AOP_REG) &&
(AOP_TYPE (right) == AOP_LIT) &&
!IS_FLOAT (operandType (right)))
{
_startLazyDPSEvaluation ();
while (size && ((unsigned int) (lit >> (offset * 8)) != 0))
{
aopPut (AOP (result),
aopGet (AOP (right), offset, FALSE, FALSE, TRUE),
offset);
offset++;
size--;
}
/* And now fill the rest with zeros. */
if (size)
{
emitcode ("clr", "a");
}
while (size--)
{
aopPut (AOP (result), "a", offset++);
}
_endLazyDPSEvaluation ();
}
else
{
_startLazyDPSEvaluation ();
while (size--)
{
aopPut (AOP (result),
aopGet (AOP (right), offset, FALSE, FALSE, FALSE),
offset);
offset++;
}
_endLazyDPSEvaluation ();
}
release:
freeAsmop (right, NULL, ic, FALSE);
freeAsmop (result, NULL, ic, TRUE);
}
/*-----------------------------------------------------------------*/
/* genJumpTab - generates code for jump table */
/*-----------------------------------------------------------------*/
static void
genJumpTab (iCode * ic)
{
symbol *jtab;
char *l;
D (emitcode (";", "genJumpTab ");
);
aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
/* get the condition into accumulator */
l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE, FALSE, TRUE);
MOVA (l);
/* multiply by four! */
emitcode ("add", "a,acc");
emitcode ("add", "a,acc");
freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
jtab = newiTempLabel (NULL);
emitcode ("mov", "dptr,#%05d$", jtab->key + 100);
emitcode ("jmp", "@a+dptr");
emitcode ("", "%05d$:", jtab->key + 100);
/* now generate the jump labels */
for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
jtab = setNextItem (IC_JTLABELS (ic)))
emitcode ("ljmp", "%05d$", jtab->key + 100);
}
/*-----------------------------------------------------------------*/
/* genCast - gen code for casting */
/*-----------------------------------------------------------------*/
static void
genCast (iCode * ic)
{
operand *result = IC_RESULT (ic);
sym_link *ctype = operandType (IC_LEFT (ic));
sym_link *rtype = operandType (IC_RIGHT (ic));
operand *right = IC_RIGHT (ic);
int size, offset;
D (emitcode (";", "genCast ");
);
/* if they are equivalent then do nothing */
if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
return;
aopOp (right, ic, FALSE, FALSE);
aopOp (result, ic, FALSE, AOP_TYPE (right) == AOP_DPTR);
/* if the result is a bit */
// if (AOP_TYPE (result) == AOP_CRY) /* works only for true symbols */
if (IS_BITVAR(OP_SYMBOL(result)->type))
{
/* if the right size is a literal then
we know what the value is */
if (AOP_TYPE (right) == AOP_LIT)
{
if (((int) operandLitValue (right)))
aopPut (AOP (result), one, 0);
else
aopPut (AOP (result), zero, 0);
goto release;
}
/* the right is also a bit variable */
if (AOP_TYPE (right) == AOP_CRY)
{
emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
aopPut (AOP (result), "c", 0);
goto release;
}
/* we need to or */
toBoolean (right);
aopPut (AOP (result), "a", 0);
goto release;
}
/* if they are the same size : or less */
if (AOP_SIZE (result) <= AOP_SIZE (right))
{
/* if they are in the same place */
if (sameRegs (AOP (right), AOP (result)))
goto release;
/* if they in different places then copy */
size = AOP_SIZE (result);
offset = 0;
_startLazyDPSEvaluation ();
while (size--)
{
aopPut (AOP (result),
aopGet (AOP (right), offset, FALSE, FALSE, FALSE),
offset);
offset++;
}
_endLazyDPSEvaluation ();
goto release;
}
/* if the result is of type pointer */
if (IS_PTR (ctype))
{
int p_type;
sym_link *type = operandType (right);
/* pointer to generic pointer */
if (IS_GENPTR (ctype))
{
char *l = zero;
if (IS_PTR (type))
{
p_type = DCL_TYPE (type);
}
else
{
#if OLD_CAST_BEHAVIOR
/* KV: we are converting a non-pointer type to
* a generic pointer. This (ifdef'd out) code
* says that the resulting generic pointer
* should have the same class as the storage
* location of the non-pointer variable.
*
* For example, converting an int (which happens
* to be stored in DATA space) to a pointer results
* in a DATA generic pointer; if the original int
* in XDATA space, so will be the resulting pointer.
*
* I don't like that behavior, and thus this change:
* all such conversions will be forced to XDATA and
* throw a warning. If you want some non-XDATA
* type, or you want to suppress the warning, you
* must go through an intermediate cast, like so:
*
* char _generic *gp = (char _xdata *)(intVar);
*/
sym_link *etype = getSpec (type);
/* we have to go by the storage class */
if (SPEC_OCLS (etype) != generic)
{
p_type = PTR_TYPE (SPEC_OCLS (etype));
}
else
#endif
{
/* Converting unknown class (i.e. register variable)
* to generic pointer. This is not good, but
* we'll make a guess (and throw a warning).
*/
p_type = FPOINTER;
werror (W_INT_TO_GEN_PTR_CAST);
}
}
/* the first two bytes are known */
size = GPTRSIZE - 1;
offset = 0;
_startLazyDPSEvaluation ();
while (size--)
{
aopPut (AOP (result),
aopGet (AOP (right), offset, FALSE, FALSE, FALSE),
offset);
offset++;
}
_endLazyDPSEvaluation ();
/* the last byte depending on type */
switch (p_type)
{
case IPOINTER:
case POINTER:
l = zero;
break;
case FPOINTER:
l = one;
break;
case CPOINTER:
l = "#0x02";
break;
case PPOINTER:
l = "#0x03";
break;
default:
/* this should never happen */
werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
"got unknown pointer type");
exit (1);
}
aopPut (AOP (result), l, GPTRSIZE - 1);
goto release;
}
/* just copy the pointers */
size = AOP_SIZE (result);
offset = 0;
_startLazyDPSEvaluation ();
while (size--)
{
aopPut (AOP (result),
aopGet (AOP (right), offset, FALSE, FALSE, FALSE),
offset);
offset++;
}
_endLazyDPSEvaluation ();
goto release;
}
/* so we now know that the size of destination is greater
than the size of the source */
/* we move to result for the size of source */
size = AOP_SIZE (right);
offset = 0;
_startLazyDPSEvaluation ();
while (size--)
{
aopPut (AOP (result),
aopGet (AOP (right), offset, FALSE, FALSE, FALSE),
offset);
offset++;
}
_endLazyDPSEvaluation ();
/* now depending on the sign of the source && destination */
size = AOP_SIZE (result) - AOP_SIZE (right);
/* if unsigned or not an integral type */
/* also, if the source is a bit, we don't need to sign extend, because
* it can't possibly have set the sign bit.
*/
if (SPEC_USIGN (rtype) || !IS_SPEC (rtype) || AOP_TYPE (right) == AOP_CRY)
{
while (size--)
{
aopPut (AOP (result), zero, offset++);
}
}
else
{
/* we need to extend the sign :{ */
char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
FALSE, FALSE, TRUE);
MOVA (l);
emitcode ("rlc", "a");
emitcode ("subb", "a,acc");
while (size--)
aopPut (AOP (result), "a", offset++);
}
/* we are done hurray !!!! */
release:
freeAsmop (right, NULL, ic, TRUE);
freeAsmop (result, NULL, ic, TRUE);
}
/*-----------------------------------------------------------------*/
/* genDjnz - generate decrement & jump if not zero instrucion */
/*-----------------------------------------------------------------*/
static int
genDjnz (iCode * ic, iCode * ifx)
{
symbol *lbl, *lbl1;
if (!ifx)
return 0;
/* if the if condition has a false label
then we cannot save */
if (IC_FALSE (ifx))
return 0;
/* if the minus is not of the form
a = a - 1 */
if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
!IS_OP_LITERAL (IC_RIGHT (ic)))
return 0;
if (operandLitValue (IC_RIGHT (ic)) != 1)
return 0;
/* if the size of this greater than one then no
saving */
if (getSize (operandType (IC_RESULT (ic))) > 1)
return 0;
/* otherwise we can save BIG */
D(emitcode(";", "genDjnz"););
lbl = newiTempLabel (NULL);
lbl1 = newiTempLabel (NULL);
aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
if (AOP_NEEDSACC(IC_RESULT(ic)))
{
/* If the result is accessed indirectly via
* the accumulator, we must explicitly write
* it back after the decrement.
*/
char *rByte = aopGet(AOP(IC_RESULT(ic)), 0, FALSE, FALSE, TRUE);
if (strcmp(rByte, "a"))
{
/* Something is hopelessly wrong */
fprintf(stderr, "*** warning: internal error at %s:%d\n",
__FILE__, __LINE__);
/* We can just give up; the generated code will be inefficient,
* but what the hey.
*/
freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
return 0;
}
emitcode ("dec", "%s", rByte);
aopPut(AOP(IC_RESULT(ic)), rByte, 0);
emitcode ("jnz", "%05d$", lbl->key + 100);
}
else if (IS_AOP_PREG (IC_RESULT (ic)))
{
emitcode ("dec", "%s",
aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE, FALSE));
emitcode ("mov", "a,%s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE, FALSE));
emitcode ("jnz", "%05d$", lbl->key + 100);
}
else
{
emitcode ("djnz", "%s,%05d$", aopGet (AOP (IC_RESULT (ic)), 0, FALSE, TRUE, FALSE),
lbl->key + 100);
}
emitcode ("sjmp", "%05d$", lbl1->key + 100);
emitcode ("", "%05d$:", lbl->key + 100);
emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
emitcode ("", "%05d$:", lbl1->key + 100);
freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
ifx->generated = 1;
return 1;
}
/*-----------------------------------------------------------------*/
/* genReceive - generate code for a receive iCode */
/*-----------------------------------------------------------------*/
static void
genReceive (iCode * ic)
{
D (emitcode (";", "genReceive ");
);
if (isOperandInFarSpace (IC_RESULT (ic)) &&
(OP_SYMBOL (IC_RESULT (ic))->isspilt ||
IS_TRUE_SYMOP (IC_RESULT (ic))))
{
int size = getSize (operandType (IC_RESULT (ic)));
int offset = fReturnSizeDS390 - size;
while (size--)
{
emitcode ("push", "%s", (strcmp (fReturn[fReturnSizeDS390 - offset - 1], "a") ?
fReturn[fReturnSizeDS390 - offset - 1] : "acc"));
offset++;
}
aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
size = AOP_SIZE (IC_RESULT (ic));
offset = 0;
while (size--)
{
emitcode ("pop", "acc");
aopPut (AOP (IC_RESULT (ic)), "a", offset++);
}
}
else
{
_G.accInUse++;
aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
_G.accInUse--;
assignResultValue (IC_RESULT (ic));
}
freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
}
/*-----------------------------------------------------------------*/
/* gen390Code - generate code for Dallas 390 based controllers */
/*-----------------------------------------------------------------*/
void
gen390Code (iCode * lic)
{
iCode *ic;
int cln = 0;
lineHead = lineCurr = NULL;
if (options.model == MODEL_FLAT24) {
fReturnSizeDS390 = 5;
fReturn = fReturn24;
} else {
fReturnSizeDS390 = 4;
fReturn = fReturn16;
options.stack10bit=0;
}
#if 0
//REMOVE ME!!!
/* print the allocation information */
if (allocInfo)
printAllocInfo (currFunc, codeOutFile);
#endif
/* if debug information required */
if (options.debug && currFunc)
{
cdbSymbol (currFunc, cdbFile, FALSE, TRUE);
_G.debugLine = 1;
if (IS_STATIC (currFunc->etype))
emitcode ("", "F%s$%s$0$0 ==.", moduleName, currFunc->name);
else
emitcode ("", "G$%s$0$0 ==.", currFunc->name);
_G.debugLine = 0;
}
/* stack pointer name */
if (options.useXstack)
spname = "_spx";
else
spname = "sp";
for (ic = lic; ic; ic = ic->next)
{
if (cln != ic->lineno)
{
if (options.debug)
{
_G.debugLine = 1;
emitcode ("", "C$%s$%d$%d$%d ==.",
FileBaseName (ic->filename), ic->lineno,
ic->level, ic->block);
_G.debugLine = 0;
}
emitcode (";", "%s %d", ic->filename, ic->lineno);
cln = ic->lineno;
}
/* if the result is marked as
spilt and rematerializable or code for
this has already been generated then
do nothing */
if (resultRemat (ic) || ic->generated)
continue;
/* depending on the operation */
switch (ic->op)
{
case '!':
genNot (ic);
break;
case '~':
genCpl (ic);
break;
case UNARYMINUS:
genUminus (ic);
break;
case IPUSH:
genIpush (ic);
break;
case IPOP:
/* IPOP happens only when trying to restore a
spilt live range, if there is an ifx statement
following this pop then the if statement might
be using some of the registers being popped which
would destory the contents of the register so
we need to check for this condition and handle it */
if (ic->next &&
ic->next->op == IFX &&
regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
genIfx (ic->next, ic);
else
genIpop (ic);
break;
case CALL:
genCall (ic);
break;
case PCALL:
genPcall (ic);
break;
case FUNCTION:
genFunction (ic);
break;
case ENDFUNCTION:
genEndFunction (ic);
break;
case RETURN:
genRet (ic);
break;
case LABEL:
genLabel (ic);
break;
case GOTO:
genGoto (ic);
break;
case '+':
genPlus (ic);
break;
case '-':
if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
genMinus (ic);
break;
case '*':
genMult (ic);
break;
case '/':
genDiv (ic);
break;
case '%':
genMod (ic);
break;
case '>':
genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
break;
case '<':
genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
break;
case LE_OP:
case GE_OP:
case NE_OP:
/* note these two are xlated by algebraic equivalence
during parsing SDCC.y */
werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
"got '>=' or '<=' shouldn't have come here");
break;
case EQ_OP:
genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
break;
case AND_OP:
genAndOp (ic);
break;
case OR_OP:
genOrOp (ic);
break;
case '^':
genXor (ic, ifxForOp (IC_RESULT (ic), ic));
break;
case '|':
genOr (ic, ifxForOp (IC_RESULT (ic), ic));
break;
case BITWISEAND:
genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
break;
case INLINEASM:
genInline (ic);
break;
case RRC:
genRRC (ic);
break;
case RLC:
genRLC (ic);
break;
case GETHBIT:
genGetHbit (ic);
break;
case LEFT_OP:
genLeftShift (ic);
break;
case RIGHT_OP:
genRightShift (ic);
break;
case GET_VALUE_AT_ADDRESS:
genPointerGet (ic);
break;
case '=':
if (POINTER_SET (ic))
genPointerSet (ic);
else
genAssign (ic);
break;
case IFX:
genIfx (ic, NULL);
break;
case ADDRESS_OF:
genAddrOf (ic);
break;
case JUMPTABLE:
genJumpTab (ic);
break;
case CAST:
genCast (ic);
break;
case RECEIVE:
genReceive (ic);
break;
case SEND:
addSet (&_G.sendSet, ic);
break;
case ARRAYINIT:
genArrayInit(ic);
break;
default:
ic = ic;
}
}
/* now we are ready to call the
peep hole optimizer */
if (!options.nopeep)
peepHole (&lineHead);
/* now do the actual printing */
printLine (lineHead, codeOutFile);
return;
}