extern FILE *codeOutFile;
+enum
+ {
+ INT8MIN = -128,
+ INT8MAX = 127
+ };
+
/** Enum covering all the possible register pairs.
*/
typedef enum
// PENDING
#define ACC_NAME _pairs[PAIR_AF].h
-#define RESULTONSTACK(x) \
- (IC_RESULT(x) && IC_RESULT(x)->aop && \
- IC_RESULT(x)->aop->type == AOP_STK )
-
enum
{
LSB,
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);
}
/*-----------------------------------------------------------------*/
/* Assign depending on the storage class */
if (sym->onStack || sym->iaccess)
{
- emitDebug ("; AOP_STK for %s", sym->rname);
- sym->aop = aop = newAsmop (AOP_STK);
+ /* The pointer that is used depends on how big the offset is.
+ 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 < INT8MIN || sym->stack > (int)(INT8MAX-getSize (sym->type))))
+ {
+ emitDebug ("; AOP_EXSTK for %s", sym->rname);
+ sym->aop = aop = newAsmop (AOP_EXSTK);
+ }
+ else
+ {
+ emitDebug ("; AOP_STK for %s", sym->rname);
+ sym->aop = aop = newAsmop (AOP_STK);
+ }
+
aop->size = getSize (sym->type);
aop->aopu.aop_stk = sym->stack;
return aop;
aop->freed = 1;
+ if (aop->type == AOP_PAIRPTR && IS_Z80 && aop->aopu.aop_pairId == PAIR_DE)
+ {
+ _pop (aop->aopu.aop_pairId);
+ }
+
dealloc:
/* all other cases just dealloc */
if (op)
SPIL_LOC (op)->aop = NULL;
}
}
+
}
bool
}
}
-static void
-spillPair (PAIR_ID pairId)
-{
- _G.pairs[pairId].last_type = AOP_INVALID;
- _G.pairs[pairId].base = NULL;
-}
-
static void
spillCached (void)
{
case AOP_IY:
case AOP_HL:
case AOP_STK:
+ case AOP_EXSTK:
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;
}
}
static void
-setupPair (PAIR_ID pairId, asmop * aop, int offset)
+setupPairFromSP (PAIR_ID id, int offset)
{
- assert (pairId == PAIR_HL || pairId == PAIR_IY);
+ 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)
+{
switch (aop->type)
{
case AOP_IY:
+ wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
fetchLitPair (pairId, aop, 0);
break;
+
case AOP_HL:
+ wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
+
fetchLitPair (pairId, aop, offset);
_G.pairs[pairId].offset = offset;
break;
+
+ case AOP_EXSTK:
+ wassertl (IS_Z80, "Only the Z80 has an extended stack");
+ wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
+
+ {
+ int offset = aop->aopu.aop_stk + _G.stack.offset;
+
+ if (_G.pairs[pairId].last_type == aop->type &&
+ _G.pairs[pairId].offset == offset)
+ {
+ /* Already setup */
+ }
+ else
+ {
+ /* PENDING: Do this better. */
+ sprintf (buffer, "%d", offset + _G.stack.pushed);
+ emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
+ emit2 ("add %s,sp", _pairs[pairId].name);
+ _G.pairs[pairId].last_type = aop->type;
+ _G.pairs[pairId].offset = offset;
+ }
+ }
+ break;
+
case AOP_STK:
{
/* Doesnt include _G.stack.pushed */
}
else
{
- emit2 ("!ldahlsp", abso + _G.stack.pushed);
+ setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
}
_G.pairs[pairId].offset = abso;
break;
}
+
+ case AOP_PAIRPTR:
+ adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
+ break;
+
default:
wassert (0);
}
return traceAlloc(&_G.trace.aops, Safe_strdup(s));
+ case AOP_EXSTK:
+ wassert (IS_Z80);
+ setupPair (PAIR_IY, aop, offset);
+ tsprintf (s, "!*iyx", offset, offset);
+
+ return traceAlloc(&_G.trace.aops, Safe_strdup(s));
+
case AOP_STK:
if (IS_GB)
{
aop->coff = offset;
return aop->aopu.aop_str[offset];
+ case AOP_PAIRPTR:
+ setupPair (aop->aopu.aop_pairId, aop, offset);
+ sprintf (s, "(%s)", _pairs[aop->aopu.aop_pairId].name);
+
+ return traceAlloc(&_G.trace.aops, Safe_strdup(s));
+
default:
break;
}
case AOP_IY:
wassert (!IS_GB);
- setupPair (PAIR_IY, aop, offset);
if (!canAssignToPtr (s))
{
emit2 ("ld a,%s", s);
+ setupPair (PAIR_IY, aop, offset);
emit2 ("ld !*iyx,a", offset);
}
else
- emit2 ("ld !*iyx,%s", offset, s);
+ {
+ setupPair (PAIR_IY, aop, offset);
+ emit2 ("ld !*iyx,%s", offset, s);
+ }
break;
case AOP_HL:
emit2 ("ld !*hl,%s", s);
break;
+ case AOP_EXSTK:
+ wassert (!IS_GB);
+ if (!canAssignToPtr (s))
+ {
+ emit2 ("ld a,%s", s);
+ setupPair (PAIR_IY, aop, offset);
+ emit2 ("ld !*iyx,a", offset);
+ }
+ else
+ {
+ setupPair (PAIR_IY, aop, offset);
+ emit2 ("ld !*iyx,%s", offset, s);
+ }
+ break;
+
case AOP_STK:
if (IS_GB)
{
emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
break;
+ case AOP_PAIRPTR:
+ setupPair (aop->aopu.aop_pairId, aop, offset);
+ emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
+ break;
+
default:
werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
"aopPut got unsupported aop->type");
if (i)
emit2 ("inc sp");
}
- spillCached ();
}
}
+ spillCached ();
+
if (_G.stack.pushedDE)
{
bool dInUse = bitVectBitValue(rInUse, D_IDX);
/* 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");
/* 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);
}
}
}
+bool
+couldDestroyCarry (asmop *aop)
+{
+ if (aop)
+ {
+ if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static void
+shiftIntoPair (int idx, asmop *aop)
+{
+ PAIR_ID id = PAIR_INVALID;
+
+ wassertl (IS_Z80, "Only implemented for the Z80");
+ // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
+
+ switch (idx)
+ {
+ case 0:
+ id = PAIR_HL;
+ break;
+ case 1:
+ id = PAIR_DE;
+ _push (PAIR_DE);
+ break;
+ default:
+ wassertl (0, "Internal error - hit default case");
+ }
+
+ emitDebug ("; Shift into pair idx %u", idx);
+
+ if (id == PAIR_HL)
+ {
+ setupPair (PAIR_HL, aop, 0);
+ }
+ else
+ {
+ setupPair (PAIR_IY, aop, 0);
+ emit2 ("push iy");
+ emit2 ("pop %s", _pairs[id].name);
+ }
+
+ aop->type = AOP_PAIRPTR;
+ aop->aopu.aop_pairId = id;
+ _G.pairs[id].offset = 0;
+ _G.pairs[id].last_type = aop->type;
+}
+
+static void
+setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
+{
+ wassert (left && right);
+
+ if (IS_Z80)
+ {
+ if (couldDestroyCarry (right) && couldDestroyCarry (result))
+ {
+ shiftIntoPair (0, right);
+ shiftIntoPair (1, result);
+ }
+ else if (couldDestroyCarry (right))
+ {
+ shiftIntoPair (0, right);
+ }
+ else if (couldDestroyCarry (result))
+ {
+ shiftIntoPair (0, result);
+ }
+ else
+ {
+ /* Fine */
+ }
+ }
+}
+
/*-----------------------------------------------------------------*/
/* genPlus - generates code for addition */
/*-----------------------------------------------------------------*/
goto release;
}
+ if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD)
+ {
+ fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
+ emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
+ spillCached();
+ commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
+ goto release;
+ }
+
/* Special case:
ld hl,sp+n trashes C so we cant afford to do it during an
add with stack based varibles. Worst case is:
}
}
+ setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
+
while (size--)
{
if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
}
}
+ setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
+
/* if literal, add a,#-lit, else normal subb */
while (size--)
{
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);
}
/*-----------------------------------------------------------------*/
}
spillPair (PAIR_HL);
}
+ else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
+ {
+ setupPair (PAIR_HL, AOP (left), 0);
+ aopGet (AOP(right), LSB, FALSE);
+
+ while (size--)
+ {
+ if (size == 0 && sign)
+ {
+ // Highest byte when signed needs the bits flipped
+ // Save the flags
+ emit2 ("push af");
+ emit2 ("ld a,(hl)");
+ emit2 ("xor #0x80");
+ emit2 ("ld l,a");
+ emit2 ("ld a,%d(iy)", offset);
+ emit2 ("xor #0x80");
+ emit2 ("ld h,a");
+ emit2 ("pop af");
+ emit2 ("ld a,l");
+ emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
+ }
+ else
+ {
+ emit2 ("ld a,(hl)");
+ emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
+ }
+
+ if (size != 0)
+ {
+ emit2 ("inc hl");
+ }
+ offset++;
+ }
+ spillPair (PAIR_HL);
+ spillPair (PAIR_IY);
+ }
else
{
if (AOP_TYPE (right) == AOP_LIT)
goto release;
}
}
+
if (sign)
{
/* First setup h and l contaning the top most bytes XORed */
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
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);
}