enum
{
/* Set to enable debugging trace statements in the output assembly code. */
- DISABLE_DEBUG = 0,
+ DISABLE_DEBUG = 0
};
static char *_z80_return[] =
extern FILE *codeOutFile;
+enum
+ {
+ INT8MIN = -128,
+ INT8MAX = 127
+ };
+
/** Enum covering all the possible register pairs.
*/
typedef enum
{ "bc", "c", "b" },
{ "de", "e", "d" },
{ "hl", "l", "h" },
- { "iy", "iy.l?", "iy.h?" },
- { "ix", "ix.l?", "ix.h?" }
+ { "iy", "iyl", "iyh" },
+ { "ix", "ixl", "ixh" }
};
// PENDING
return _pairs[_getTempPairId()].name;
}
+static PAIR_ID
+getFreePairId (iCode *ic)
+{
+ if (!(bitVectBitValue (ic->rMask, B_IDX) || bitVectBitValue(ic->rMask, C_IDX)))
+ {
+ return PAIR_BC;
+ }
+ else if (IS_Z80 && !(bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX)))
+ {
+ return PAIR_DE;
+ }
+ else
+ {
+ return PAIR_INVALID;
+ }
+}
+
static void
_tidyUp (char *buf)
{
break;
}
}
- else if (aop->type == AOP_STR)
+ else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
{
- switch (*aop->aopu.aop_str[0])
- {
- case 'c':
- return "bc";
- break;
- case 'e':
- return "de";
- break;
- case 'l':
- return "hl";
- break;
- }
+ int i;
+ for (i = 0; i < NUM_PAIRS; i++)
+ {
+ if (strcmp(aop->aopu.aop_str[0], _pairs[i].l) == 0)
+ {
+ return _pairs[i].name;
+ }
+ }
}
wassertl (0, "Tried to get the pair name of something that isn't a pair");
return NULL;
return PAIR_HL;
}
}
- if (aop->type == AOP_STR)
+ else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
{
- if (!strcmp (aop->aopu.aop_str[0], "c") && !strcmp (aop->aopu.aop_str[1], "b"))
- {
- return PAIR_BC;
- }
- if (!strcmp (aop->aopu.aop_str[0], "e") && !strcmp (aop->aopu.aop_str[1], "d"))
- {
- return PAIR_DE;
- }
- if (!strcmp (aop->aopu.aop_str[0], "l") && !strcmp (aop->aopu.aop_str[1], "h"))
- {
- return PAIR_HL;
- }
- }
+ int i;
+ for (i = 0; i < NUM_PAIRS; i++)
+ {
+ if (!strcmp (aop->aopu.aop_str[0], _pairs[i].l) && !strcmp (aop->aopu.aop_str[1], _pairs[i].h))
+ {
+ return i;
+ }
+ }
+ }
}
return PAIR_INVALID;
}
return FALSE;
}
}
+
+static void
+spillPair (PAIR_ID pairId)
+{
+ _G.pairs[pairId].last_type = AOP_INVALID;
+ _G.pairs[pairId].base = NULL;
+}
+
/** Push a register pair onto the stack */
void
genPairPush (asmop * aop)
{
emit2 ("pop %s", _pairs[pairId].name);
_G.stack.pushed -= 2;
+ spillPair (pairId);
}
/*-----------------------------------------------------------------*/
if (sym->onStack || sym->iaccess)
{
/* The pointer that is used depends on how big the offset is.
- Normally everything is AOP_STK, but for offsets of < -127 or
- > 128 on the Z80 an extended stack pointer is used.
+ Normally everything is AOP_STK, but for offsets of < -128 or
+ > 127 on the Z80 an extended stack pointer is used.
*/
- if (IS_Z80 && (options.ommitFramePtr || sym->stack < -127 || sym->stack > (int)(128-getSize (sym->type))))
+ if (IS_Z80 && (options.ommitFramePtr || sym->stack < INT8MIN || sym->stack > (int)(INT8MAX-getSize (sym->type))))
{
emitDebug ("; AOP_EXSTK for %s", sym->rname);
sym->aop = aop = newAsmop (AOP_EXSTK);
return;
}
+ if (sym->ruonly)
+ {
+ int i;
+ aop = op->aop = sym->aop = newAsmop (AOP_STR);
+ aop->size = getSize (sym->type);
+ for (i = 0; i < 4; i++)
+ aop->aopu.aop_str[i] = _fReturn[i];
+ return;
+ }
+
if (sym->accuse)
{
if (sym->accuse == ACCUSE_A)
aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
}
- else if (sym->accuse == ACCUSE_HL)
+ else if (sym->accuse == ACCUSE_SCRATCH)
{
- wassert (!IS_GB);
aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
aop->size = getSize (sym->type);
wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
}
+ else if (sym->accuse == ACCUSE_IY)
+ {
+ aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
+ aop->size = getSize (sym->type);
+ wassertl(aop->size <= 2, "Internal error: Caching in IY, but too big to fit in IY");
+ aop->aopu.aop_str[0] = _pairs[PAIR_IY].l;
+ aop->aopu.aop_str[1] = _pairs[PAIR_IY].h;
+ }
else
{
wassertl (0, "Marked as being allocated into A or HL but is actually in neither");
return;
}
- if (sym->ruonly)
- {
- int i;
- aop = op->aop = sym->aop = newAsmop (AOP_STR);
- aop->size = getSize (sym->type);
- for (i = 0; i < 4; i++)
- aop->aopu.aop_str[i] = _fReturn[i];
- return;
- }
-
/* else spill location */
sym->aop = op->aop = aop =
aopForSym (ic, sym->usl.spillLoc, result, requires_a);
aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
{
char *s = buffer;
- char *rs;
/* depending on type */
switch (aop->type)
}
else
{
- /* A float */
- Z80_FLOAT f;
- convertFloat (&f, floatFromVal (val));
+ union {
+ float f;
+ unsigned char c[4];
+ }
+ fl;
+ unsigned int i;
+
+ /* it is type float */
+ fl.f = (float) floatFromVal (val);
+
+#ifdef _BIG_ENDIAN
+ i = fl.c[3-offset] | (fl.c[3-offset-1]<<8);
+#else
+ i = fl.c[offset] | (fl.c[offset+1]<<8);
+#endif
if (with_hash)
- tsprintf (buffer, "!immedword", f.w[offset / 2]);
+ tsprintf (buffer, "!immedword", i);
else
- tsprintf (buffer, "!constword", f.w[offset / 2]);
- rs = Safe_calloc (1, strlen (buffer) + 1);
- return strcpy (rs, buffer);
+ tsprintf (buffer, "!constword", i);
+
+ return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
}
}
default:
}
}
-static void
-spillPair (PAIR_ID pairId)
-{
- _G.pairs[pairId].last_type = AOP_INVALID;
- _G.pairs[pairId].base = NULL;
-}
-
static void
spillCached (void)
{
case AOP_HL:
case AOP_STK:
case AOP_EXSTK:
+ case AOP_HLREG:
return TRUE;
default:
return FALSE;
adjustPair (pair, &_G.pairs[pairId].offset, offset);
return;
}
- if (pairId == PAIR_IY && abs (offset) < 127)
+ if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
{
return;
}
if (isLitWord (aop)) {
fetchLitPair (pairId, aop, offset);
}
- else {
+ else
+ {
+ if (getPairId (aop) == pairId)
+ {
+ /* Do nothing */
+ }
/* we need to get it byte by byte */
- if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
+ else if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
aopGet (aop, offset, FALSE);
switch (aop->size - offset) {
case 1:
emit2("ld %s,!zero", _pairs[pairId].h);
}
}
+ else if (pairId == PAIR_IY)
+ {
+ if (isPair (aop))
+ {
+ emit2 ("push %s", _pairs[getPairId(aop)].name);
+ emit2 ("pop iy");
+ }
+ else
+ {
+ _push (PAIR_HL);
+ /* Can't load into parts, so load into HL then exchange. */
+ emit2 ("ld %s,%s", _pairs[PAIR_HL].l, aopGet (aop, offset, FALSE));
+ emit2 ("ld %s,%s", _pairs[PAIR_HL].h, aopGet (aop, offset + 1, FALSE));
+ emit2 ("push hl");
+ emit2 ("pop iy");
+ _pop (PAIR_HL);
+ }
+ }
else {
emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
fetchPair (PAIR_HL, aop);
}
+static void
+setupPairFromSP (PAIR_ID id, int offset)
+{
+ wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
+
+ if (offset < INT8MIN || offset > INT8MAX)
+ {
+ emit2 ("ld hl,!immedword", offset);
+ emit2 ("add hl,sp");
+ }
+ else
+ {
+ emit2 ("!ldahlsp", offset);
+ }
+}
+
static void
setupPair (PAIR_ID pairId, asmop * aop, int offset)
{
}
else
{
- emit2 ("!ldahlsp", abso + _G.stack.pushed);
+ setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
}
_G.pairs[pairId].offset = abso;
break;
emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
}
else
- emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
+ {
+ emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
+ }
}
break;
static void
commitPair (asmop * aop, PAIR_ID id)
{
- if (id == PAIR_HL && requiresHL (aop))
+ /* PENDING: Verify this. */
+ if (id == PAIR_HL && requiresHL (aop) && IS_GB)
{
emit2 ("ld a,l");
emit2 ("ld d,h");
}
else
{
- aopPut (aop, _pairs[id].l, 0);
- aopPut (aop, _pairs[id].h, 1);
+ /* Special cases */
+ if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
+ {
+ char *l = aopGetLitWordLong (aop, 0, FALSE);
+ wassert (l);
+
+ emit2 ("ld (%s),%s", l, _pairs[id].name);
+ }
+ else
+ {
+ aopPut (aop, _pairs[id].l, 0);
+ aopPut (aop, _pairs[id].h, 1);
+ }
}
}
operand * result, int offr, int sign)
{
const char *l;
+
if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
{
l = aopGet (AOP (left), offl, FALSE);
}
}
+static void
+movLeft2ResultLong (operand * left, int offl,
+ operand * result, int offr, int sign,
+ int size)
+{
+ if (size == 1)
+ {
+ movLeft2Result (left, offl, result, offr, sign);
+ }
+ else
+ {
+ wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
+ wassertl (size == 2, "Only implemented for two bytes or one");
+
+ if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
+ {
+ emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
+ emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
+ emit2 ("ld l,a");
+ }
+ else if ( getPairId ( AOP (result)) == PAIR_IY)
+ {
+ PAIR_ID id = getPairId (AOP (left));
+ if (id != PAIR_INVALID)
+ {
+ emit2("push %s", _pairs[id].name);
+ emit2("pop iy");
+ }
+ else
+ {
+ /* PENDING */
+ emitDebug("Error");
+ }
+ }
+ else
+ {
+ movLeft2Result (left, offl, result, offr, sign);
+ movLeft2Result (left, offl+1, result, offr+1, sign);
+ }
+ }
+}
/** Put Acc into a register set
*/
}
}
+/*-----------------------------------------------------------------*/
+/* genNotFloat - generates not for float operations */
+/*-----------------------------------------------------------------*/
+static void
+genNotFloat (operand * op, operand * res)
+{
+ int size, offset;
+ symbol *tlbl;
+
+ emitDebug ("; genNotFloat");
+
+ /* we will put 127 in the first byte of
+ the result */
+ aopPut (AOP (res), "!immedbyte", 0x7F);
+ size = AOP_SIZE (op) - 1;
+ offset = 1;
+
+ _moveA (aopGet (op->aop, offset++, FALSE));
+
+ while (size--)
+ {
+ emit2 ("or a,%s", aopGet (op->aop, offset++, FALSE));
+ }
+
+ tlbl = newiTempLabel (NULL);
+ aopPut (res->aop, "!one", 1);
+ emit2 ("!shortjp z !tlabel", tlbl->key + 100);
+ aopPut (res->aop, "!zero", 1);
+
+ emitLabel(tlbl->key + 100);
+
+ size = res->aop->size - 2;
+ offset = 2;
+ /* put zeros in the rest */
+ while (size--)
+ aopPut (res->aop, "!zero", offset++);
+}
+
/*-----------------------------------------------------------------*/
/* genNot - generate code for ! operation */
/*-----------------------------------------------------------------*/
/* if type float then do float */
if (IS_FLOAT (optype))
{
- wassertl (0, "Tried to negate a float");
+ genNotFloat (IC_LEFT (ic), IC_RESULT (ic));
+ goto release;
}
_toBoolean (IC_LEFT (ic));
emit2 ("sub a,!one");
outBitC (IC_RESULT (ic));
+ release:
/* release the aops */
freeAsmop (IC_LEFT (ic), NULL, ic);
freeAsmop (IC_RESULT (ic), NULL, ic);
_gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
}
+/*-----------------------------------------------------------------*/
+/* genUminusFloat - unary minus for floating points */
+/*-----------------------------------------------------------------*/
+static void
+genUminusFloat (operand * op, operand * result)
+{
+ int size, offset = 0;
+
+ emitDebug("; genUminusFloat");
+
+ /* for this we just need to flip the
+ first it then copy the rest in place */
+ size = AOP_SIZE (op) - 1;
+
+ _moveA(aopGet (AOP (op), MSB32, FALSE));
+
+ emit2("xor a,!immedbyte", 0x80);
+ aopPut (AOP (result), "a", MSB32);
+
+ while (size--)
+ {
+ aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
+ offset++;
+ }
+}
+
/*-----------------------------------------------------------------*/
/* genUminus - unary minus code generation */
/*-----------------------------------------------------------------*/
/* if float then do float stuff */
if (IS_FLOAT (optype))
{
- wassertl (0, "Tried to do a unary minus on a float");
+ genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
goto release;
}
}
}
+/** Simple restore that doesn't take into account what is used in the
+ return.
+*/
+static void
+_restoreRegsAfterCall(void)
+{
+ if (_G.stack.pushedDE)
+ {
+ _pop ( PAIR_DE);
+ _G.stack.pushedDE = FALSE;
+ }
+ if (_G.stack.pushedBC)
+ {
+ _pop ( PAIR_BC);
+ _G.stack.pushedBC = FALSE;
+ }
+ _G.saves.saved = FALSE;
+}
+
static void
_saveRegsForCall(iCode *ic, int sendSetSize)
{
size = AOP_SIZE (IC_LEFT (ic));
- if (isPair (AOP (IC_LEFT (ic))))
+ if (isPair (AOP (IC_LEFT (ic))) && size == 2)
{
_G.stack.pushed += 2;
emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
static void
emitCall (iCode * ic, bool ispcall)
{
- sym_link *detype = getSpec (operandType (IC_LEFT (ic)));
+ sym_link *dtype = operandType (IC_LEFT (ic));
bitVect *rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
if (ispcall)
{
- if (IS_BANKEDCALL (detype))
+ if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
{
werror (W_INDIR_BANKED);
}
char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
OP_SYMBOL (IC_LEFT (ic))->rname :
OP_SYMBOL (IC_LEFT (ic))->name;
- if (IS_BANKEDCALL (detype))
+ if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
{
emit2 ("call banked_call");
emit2 ("!dws", name);
if (i)
emit2 ("inc sp");
}
- spillCached ();
}
}
+ spillCached ();
+
if (_G.stack.pushedDE)
{
bool dInUse = bitVectBitValue(rInUse, D_IDX);
genFunction (iCode * ic)
{
symbol *sym = OP_SYMBOL (IC_LEFT (ic));
- sym_link *fetype;
+ sym_link *ftype;
#if CALLEE_SAVES
bool bcInUse = FALSE;
bool deInUse = FALSE;
#endif
- setArea (IS_NONBANKED (sym->etype));
+ setArea (IFFUNC_NONBANKED (sym->type));
/* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
else.
emit2 ("!profileenter");
}
- fetype = getSpec (operandType (IC_LEFT (ic)));
+ ftype = operandType (IC_LEFT (ic));
/* if critical function then turn interrupts off */
- if (SPEC_CRTCL (fetype))
+ if (IFFUNC_ISCRITICAL (ftype))
emit2 ("!di");
/* if this is an interrupt service routine then save all potentially used registers. */
- if (IS_ISR (sym->etype))
+ if (IFFUNC_ISISR (sym->type))
{
emit2 ("!pusha");
}
/* adjust the stack for the function */
_G.stack.last = sym->stack;
- if (sym->stack)
+ if (sym->stack && IS_GB && sym->stack > -INT8MIN)
+ emit2 ("!enterxl", sym->stack);
+ else if (sym->stack)
emit2 ("!enterx", sym->stack);
else
emit2 ("!enter");
{
symbol *sym = OP_SYMBOL (IC_LEFT (ic));
- if (IS_ISR (sym->etype))
+ if (IFFUNC_ISISR (sym->type))
{
wassertl (0, "Tried to close an interrupt support function");
}
else
{
- if (SPEC_CRTCL (sym->etype))
+ if (IFFUNC_ISCRITICAL (sym->type))
emit2 ("!ei");
/* PENDING: calleeSave */
- if (_G.stack.offset)
+ if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
+ {
+ emit2 ("!leavexl", _G.stack.offset);
+ }
+ else if (_G.stack.offset)
{
emit2 ("!leavex", _G.stack.offset);
}
{
if (isLitWord (AOP (IC_LEFT (ic))))
{
- fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
+ fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
return TRUE;
}
if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
{
- fetchPair (resultId, AOP (IC_RIGHT (ic)));
- emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
- return TRUE;
+ if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
+ {
+ PAIR_ID freep = getFreePairId (ic);
+ if (freep != PAIR_INVALID)
+ {
+ fetchPair (freep, AOP (IC_RIGHT (ic)));
+ emit2 ("add hl,%s", _pairs[freep].name);
+ return TRUE;
+ }
+ }
+ else
+ {
+ fetchPair (resultId, AOP (IC_RIGHT (ic)));
+ emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
+ return TRUE;
+ }
}
if (icount > 5)
return FALSE;
{
if (icount > 2)
return FALSE;
- movLeft2Result (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0);
- movLeft2Result (IC_LEFT (ic), 1, IC_RESULT (ic), 1, 0);
+ movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
}
while (icount--)
{
return TRUE;
}
+ if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
+ {
+ fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
+ commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
+ return TRUE;
+ }
+
/* if the literal value of the right hand side
is greater than 4 then it is not worth it */
if (icount > 4)
AOP_SIZE (IC_LEFT (ic)) > 1)
return FALSE;
+ /* If the result is in a register then we can load then increment.
+ */
+ if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
+ {
+ aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
+ while (icount--)
+ {
+ emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
+ }
+ return TRUE;
+ }
+
/* we can if the aops of the left & result match or
if they are in registers and the registers are the
same */
}
}
- if (isPair (AOP (IC_RIGHT (ic))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
+ if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
{
/* Fetch into HL then do the add */
+ PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
+ PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
+
spillPair (PAIR_HL);
+
+ if (left == PAIR_HL && right != PAIR_INVALID)
+ {
+ emit2 ("add hl,%s", _pairs[right].name);
+ goto release;
+ }
+ else if (right == PAIR_HL && left != PAIR_INVALID)
+ {
+ emit2 ("add hl,%s", _pairs[left].name);
+ goto release;
+ }
+ else if (right != PAIR_INVALID && right != PAIR_HL)
+ {
+ fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
+ emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
+ goto release;
+ }
+ else if (left != PAIR_INVALID && left != PAIR_HL)
+ {
+ fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
+ emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
+ goto release;
+ }
+ else
+ {
+ /* Can't do it */
+ }
+ }
+
+ if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
+ {
fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
- emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
+ emit2 ("add hl,%s ; 2", getPairName (AOP (IC_RIGHT (ic))));
+ spillCached();
+ commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
goto release;
}
/* If result is a pair */
if (isPair (AOP (IC_RESULT (ic))))
{
- movLeft2Result (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0);
- movLeft2Result (IC_LEFT (ic), 1, IC_RESULT (ic), 1, 0);
+ movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
while (icount--)
emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
return TRUE;
emit2 ("ld a,%s", _pairs[left].h);
emit2 ("sbc a,%s", _pairs[right].h);
- aopPut (AOP (IC_RESULT (ic)), "a", 1);
+ if ( AOP_SIZE (IC_RESULT (ic)) > 1)
+ {
+ aopPut (AOP (IC_RESULT (ic)), "a", 1);
+ }
aopPut (AOP (IC_RESULT (ic)), "e", 0);
goto release;
}
static void
genMult (iCode * ic)
{
+ int val;
+ int count, i;
+ /* If true then the final operation should be a subtract */
+ bool active = FALSE;
+
/* Shouldn't occur - all done through function calls */
- wassertl (0, "Multiplication is handled through support function calls");
+ aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
+ aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
+ aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
+
+ if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
+ AOP_SIZE (IC_RIGHT (ic)) > 2 ||
+ AOP_SIZE (IC_RESULT (ic)) > 2)
+ {
+ wassertl (0, "Multiplication is handled through support function calls");
+ }
+
+ /* Swap left and right such that right is a literal */
+ if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
+ {
+ operand *t = IC_RIGHT (ic);
+ IC_RIGHT (ic) = IC_LEFT (ic);
+ IC_LEFT (ic) = t;
+ }
+
+ wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
+
+ val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
+ // wassertl (val > 0, "Multiply must be positive");
+ wassertl (val != 1, "Can't multiply by 1");
+
+ if (IS_Z80) {
+ _push (PAIR_DE);
+ }
+
+ if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
+ {
+ emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
+ emit2 ("ld a,e");
+ emit2 ("rlc a");
+ emit2 ("sbc a,a");
+ emit2 ("ld d,a");
+ }
+ else
+ {
+ fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
+ }
+
+ i = val;
+
+ /* Fully unroled version of mul.s. Not the most efficient.
+ */
+ for (count = 0; count < 16; count++)
+ {
+ if (count != 0 && active)
+ {
+ emit2 ("add hl,hl");
+ }
+ if (i & 0x8000U)
+ {
+ if (active == FALSE)
+ {
+ emit2 ("ld l,e");
+ emit2 ("ld h,d");
+ }
+ else
+ {
+ emit2 ("add hl,de");
+ }
+ active = TRUE;
+ }
+ i <<= 1;
+ }
+
+ spillCached();
+
+ if (IS_Z80)
+ {
+ _pop (PAIR_DE);
+ }
+
+ commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
+
+ freeAsmop (IC_LEFT (ic), NULL, ic);
+ freeAsmop (IC_RIGHT (ic), NULL, ic);
+ freeAsmop (IC_RESULT (ic), NULL, ic);
}
/*-----------------------------------------------------------------*/
{
inst = "nc";
}
+ else if (!strcmp (jval, "m"))
+ {
+ inst = "m";
+ }
+ else if (!strcmp (jval, "p"))
+ {
+ inst = "p";
+ }
else
{
/* The buffer contains the bit on A that we should test */
{
inst = "c";
}
+ else if (!strcmp (jval, "m"))
+ {
+ inst = "p";
+ }
+ else if (!strcmp (jval, "p"))
+ {
+ inst = "m";
+ }
else
{
/* The buffer contains the bit on A that we should test */
else if (!strcmp (jval, "nc"))
{
}
+ else if (!strcmp (jval, "m"))
+ {
+ }
+ else if (!strcmp (jval, "p"))
+ {
+ }
else
{
emit2 ("bit %s,a", jval);
}
#endif
-/** Generic compare for > or <
- */
-static void
-genCmp (operand * left, operand * right,
- operand * result, iCode * ifx, int sign)
-{
- int size, offset = 0;
- unsigned long lit = 0L;
- bool swap_sense = FALSE;
-
- /* if left & right are bit variables */
- if (AOP_TYPE (left) == AOP_CRY &&
- AOP_TYPE (right) == AOP_CRY)
- {
- /* Cant happen on the Z80 */
- wassertl (0, "Tried to compare two bits");
- }
- 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 OLD
/* if unsigned char cmp with lit, just compare */
if ((size == 1) &&
(AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
}
}
}
+#endif
+
+/** Generic compare for > or <
+ */
+static void
+genCmp (operand * left, operand * right,
+ operand * result, iCode * ifx, int sign)
+{
+ int size, offset = 0;
+ unsigned long lit = 0L;
+ bool swap_sense = FALSE;
+
+ /* if left & right are bit variables */
+ if (AOP_TYPE (left) == AOP_CRY &&
+ AOP_TYPE (right) == AOP_CRY)
+ {
+ /* Cant happen on the Z80 */
+ wassertl (0, "Tried to compare two bits");
+ }
+ else
+ {
+ /* Do a long subtract of right from left. */
+ size = max (AOP_SIZE (left), AOP_SIZE (right));
+
+ if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
+ {
+ // On the Gameboy we can't afford to adjust HL as it may trash the carry.
+ // Pull left into DE and right into HL
+ aopGet (AOP(left), LSB, FALSE);
+ emit2 ("ld d,h");
+ emit2 ("ld e,l");
+ aopGet (AOP(right), LSB, FALSE);
+
+ while (size--)
+ {
+ emit2 ("ld a,(de)");
+ emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
+
+ if (size != 0)
+ {
+ emit2 ("inc hl");
+ emit2 ("inc de");
+ }
+ offset++;
+ }
+ spillPair (PAIR_HL);
+ goto release;
+ }
+
+ 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 == 0)
+ {
+ if (!sign)
+ {
+ /* No sign so it's always false */
+ _clearCarry();
+ }
+ else
+ {
+ /* Just load in the top most bit */
+ _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
+ if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
+ {
+ genIfxJump (ifx, "7");
+ return;
+ }
+ else
+ {
+ if (!sign)
+ {
+ emit2 ("rlc a");
+ }
+ if (ifx)
+ {
+ genIfxJump (ifx, swap_sense ? "c" : "nc");
+ return;
+ }
+ }
+ }
+ goto release;
+ }
+ }
+
+ while (size--)
+ {
+ _moveA (aopGet (AOP (left), offset, FALSE));
+ /* Subtract through, propagating the carry */
+ emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
+ offset++;
+ }
+ }
release:
if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
{
+ if (sign)
+ {
+ /* Shift the sign bit up into carry */
+ emit2 ("rlca");
+ }
outBitCLong (result, swap_sense);
}
else
ifx conditional branch then generate
code a little differently */
if (ifx)
- genIfxJump (ifx, swap_sense ? "nc" : "c");
+ {
+ if (sign)
+ {
+ if (IS_GB)
+ {
+ emit2 ("rlca");
+ genIfxJump (ifx, swap_sense ? "nc" : "c");
+ }
+ else
+ {
+ genIfxJump (ifx, swap_sense ? "p" : "m");
+ }
+ }
+ else
+ {
+ genIfxJump (ifx, swap_sense ? "nc" : "c");
+ }
+ }
else
- outBitCLong (result, swap_sense);
+ {
+ if (sign)
+ {
+ /* Shift the sign bit up into carry */
+ emit2 ("rlca");
+ }
+ outBitCLong (result, swap_sense);
+ }
/* leave the result in acc */
}
}
emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
if (size > 1)
{
- size--;
- offset++;
- while (size--)
+ while (--size)
{
- emit2 ("or a,%s", aopGet (AOP (left), offset, FALSE));
+ emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
}
}
else
aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
- emitDebug ("; genCmpEq: left %u, right %u, result %u\n", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
+ emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
/* Swap operands if it makes the operation easier. ie if:
1. Left is a literal.
else
{
tlbl = newiTempLabel (NULL);
+ emitDebug(";1");
gencjneshort (left, right, tlbl);
if (IC_TRUE (ifx))
{
+ emitDebug(";2");
emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
emitLabel (tlbl->key + 100);
}
{
/* PENDING: do this better */
symbol *lbl = newiTempLabel (NULL);
+ emitDebug(";3");
emit2 ("!shortjp !tlabel", lbl->key + 100);
emitLabel (tlbl->key + 100);
emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
}
else
{
+ emitDebug(";4");
+
gencjne (left, right, newiTempLabel (NULL));
if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
{
}
if (ifx)
{
+ emitDebug(";5");
genIfxJump (ifx, "a");
goto release;
}
then put the result in place */
if (AOP_TYPE (result) != AOP_CRY)
{
+ emitDebug(";6");
outAcc (result);
}
/* leave the result in acc */
aopOp (left, ic, FALSE, FALSE);
aopOp (result, ic, FALSE, FALSE);
- if (isPair (AOP (left)) && AOP_SIZE (result) == 1)
+ size = AOP_SIZE (result);
+
+ if (isPair (AOP (left)) && size == 1)
{
/* Just do it */
if (isPtrPair (AOP (left)))
goto release;
}
+ if ( getPairId( AOP (left)) == PAIR_IY)
+ {
+ /* Just do it */
+ offset = 0;
+ while (size--)
+ {
+ char at[20];
+ tsprintf (at, "!*iyx", offset);
+ aopPut (AOP (result), at, offset);
+ offset++;
+ }
+ goto release;
+ }
+
/* For now we always load into IY */
/* if this is remateriazable */
fetchPair (pair, AOP (left));
- /* so iy now contains the address */
freeAsmop (left, NULL, ic);
/* if bit then unpack */
{
wassert (0);
}
+ else if ( getPairId( AOP (result)) == PAIR_HL)
+ {
+ wassertl (size == 2, "HL must be of size 2");
+ emit2 ("ld a,!*hl");
+ emit2 ("inc hl");
+ emit2 ("ld h,!*hl");
+ emit2 ("ld l,a");
+ }
else
{
size = AOP_SIZE (result);
bool
isRegOrLit (asmop * aop)
{
- if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
+ if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
return TRUE;
return FALSE;
}
int size, offset;
sym_link *retype = getSpec (operandType (right));
PAIR_ID pairId = PAIR_HL;
-
+
aopOp (result, ic, FALSE, FALSE);
aopOp (right, ic, FALSE, FALSE);
if (IS_GB)
pairId = PAIR_DE;
+ size = AOP_SIZE (right);
+
/* Handle the exceptions first */
- if (isPair (AOP (result)) && (AOP_SIZE (right) == 1))
+ if (isPair (AOP (result)) && size == 1)
{
/* Just do it */
const char *l = aopGet (AOP (right), 0, FALSE);
}
goto release;
}
+
+ if ( getPairId( AOP (result)) == PAIR_IY)
+ {
+ /* Just do it */
+ const char *l = aopGet (AOP (right), 0, FALSE);
+
+ offset = 0;
+ while (size--)
+ {
+ if (canAssignToPtr (l))
+ {
+ emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
+ }
+ else
+ {
+ _moveA (aopGet (AOP (right), offset, FALSE));
+ emit2 ("ld !*iyx,a", offset);
+ }
+ offset++;
+ }
+ goto release;
+ }
/* if the operand is already in dptr
then we do nothing else we move the value to dptr */
}
else
{
- size = AOP_SIZE (right);
offset = 0;
while (size--)
spillCached ();
if (sym->stack <= 0)
{
- emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset);
+ setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
}
else
{
- emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
+ setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
}
- emit2 ("ld d,h");
- emit2 ("ld e,l");
+ commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
}
else
{
emit2 ("ld de,!hashedstr", sym->rname);
+ commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
}
- aopPut (AOP (IC_RESULT (ic)), "e", 0);
- aopPut (AOP (IC_RESULT (ic)), "d", 1);
}
else
{
{
emit2 ("ld hl,#%s", sym->rname);
}
- aopPut (AOP (IC_RESULT (ic)), "l", 0);
- aopPut (AOP (IC_RESULT (ic)), "h", 1);
+ commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
}
freeAsmop (IC_RESULT (ic), NULL, ic);
}
offset = 0;
if (AOP_TYPE (right) == AOP_LIT)
+ {
lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
+ }
+
if (isPair (AOP (result)))
{
fetchPair (getPairId (AOP (result)), AOP (right));
offset++;
}
}
+ else if (size == 2 && AOP_TYPE (right) == AOP_IY)
+ {
+ emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
+ aopPut (AOP (result), "l", LSB);
+ aopPut (AOP (result), "h", MSB16);
+ }
else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
{
/* Special case. Load into a and d, then load out. */
while (size--)
{
/* PENDING: do this check better */
- if (requiresHL (AOP (right)) && requiresHL (AOP (result)))
+ if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
{
_moveA (aopGet (AOP (right), offset, FALSE));
aopPut (AOP (result), "a", offset);
aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
- if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
- {
- /* Emit the support function call and the destination address. */
- emit2("call __initrleblock");
- emit2(".dw %s", aopGetWord (AOP(IC_LEFT(ic)), 0));
- }
- else
- {
- wassertl (0, "Unexpected operand to genArrayInit.\n");
- }
+ _saveRegsForCall(ic, 0);
+
+ fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
+ emit2 ("call __initrleblock");
type = operandType(IC_LEFT(ic));
/* Mark the end of the run. */
emit2(".db 0");
+ _restoreRegsAfterCall();
+
+ spillCached ();
+
freeAsmop (IC_LEFT(ic), NULL, ic);
}
break;
case ARRAYINIT:
+ emitDebug ("; genArrayInit");
genArrayInit(ic);
break;