struct
{
AOP_TYPE last_type;
- const char *lit;
+ const char *base;
int offset;
} pairs[NUM_PAIRS];
struct
static const char *aopGet (asmop * aop, int offset, bool bit16);
+static PAIR_ID
+_getTempPairId(void)
+{
+ if (IS_GB)
+ {
+ return PAIR_DE;
+ }
+ else
+ {
+ return PAIR_HL;
+ }
+}
+
+static const char *
+_getTempPairName(void)
+{
+ return _pairs[_getTempPairId()].name;
+}
+
+#if 0
+static const char *
+_getTempPairPart(int idx)
+{
+ wassertl (idx == LSB || idx == MSB16, "Invalid pair offset");
+
+ if (idx == LSB)
+ {
+ return _pairs[_getTempPairId()].l;
+ }
+ else
+ {
+ return _pairs[_getTempPairId()].h;
+ }
+}
+#endif
+
static void
_tidyUp (char *buf)
{
emit2 ("push %s", getPairName (aop));
}
+static void
+_push (PAIR_ID pairId)
+{
+ emit2 ("push %s", _pairs[pairId].name);
+ _G.stack.pushed += 2;
+}
+
+static void
+_pop (PAIR_ID pairId)
+{
+ emit2 ("pop %s", _pairs[pairId].name);
+ _G.stack.pushed -= 2;
+}
/*-----------------------------------------------------------------*/
/* newAsmop - creates a new asmOp */
case AOP_IMMD:
/* PENDING: for re-target */
if (with_hash)
- tsprintf (s, "!hashedstr + %d", aop->aopu.aop_immd, offset);
+ {
+ tsprintf (s, "!hashedstr + %d", aop->aopu.aop_immd, offset);
+ }
+ else if (offset == 0)
+ {
+ tsprintf (s, "%s", aop->aopu.aop_immd);
+ }
else
- tsprintf (s, "%s + %d", aop->aopu.aop_immd, offset);
-
+ {
+ tsprintf (s, "%s + %d", aop->aopu.aop_immd, offset);
+ }
return gc_strdup(s);
case AOP_LIT:
spillPair (PAIR_ID pairId)
{
_G.pairs[pairId].last_type = AOP_INVALID;
- _G.pairs[pairId].lit = NULL;
+ _G.pairs[pairId].base = NULL;
}
static void
}
}
-static char *
-fetchLitSpecial (asmop * aop, bool negate, bool xor)
-{
- unsigned long v;
- value *val = aop->aopu.aop_lit;
-
- wassert (aop->type == AOP_LIT);
- wassert (!IS_FLOAT (val->type));
-
- v = (unsigned long) floatFromVal (val);
-
- if (xor)
- v ^= 0x8000;
- if (negate)
- v = 0-v;
- v &= 0xFFFF;
-
- tsprintf (buffer, "!immedword", v);
- return gc_strdup (buffer);
-}
-
static void
fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
{
- const char *l;
+ const char *l, *base;
const char *pair = _pairs[pairId].name;
l = aopGetLitWordLong (left, offset, FALSE);
- wassert (l && pair);
+ base = aopGetLitWordLong (left, 0, FALSE);
+ wassert (l && pair && base);
if (isPtr (pair))
{
{
if (_G.pairs[pairId].last_type == left->type)
{
- if (_G.pairs[pairId].lit && !strcmp (_G.pairs[pairId].lit, l))
+ if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
{
if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
{
}
}
_G.pairs[pairId].last_type = left->type;
- _G.pairs[pairId].lit = gc_strdup (l);
- _G.pairs[pairId].offset = offset;
- }
- if (IS_GB && pairId == PAIR_DE && 0)
- {
- if (_G.pairs[pairId].lit && !strcmp (_G.pairs[pairId].lit, l))
- {
- if (abs (_G.pairs[pairId].offset - offset) < 3)
- {
- adjustPair (pair, &_G.pairs[pairId].offset, offset);
- return;
- }
- }
- _G.pairs[pairId].last_type = left->type;
- _G.pairs[pairId].lit = gc_strdup (l);
+ _G.pairs[pairId].base = gc_strdup (base);
_G.pairs[pairId].offset = offset;
}
/* Both a lit on the right and a true symbol on the left */
/* we need to get it byte by byte */
if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
aopGet (aop, offset, FALSE);
- switch (aop->size) {
+ switch (aop->size - offset) {
case 1:
emit2 ("ld l,!*hl");
emit2 ("ld h,!immedbyte", 0);
break;
case 2:
+ // PENDING: Requires that you are only fetching two bytes.
+ case 4:
emit2 ("!ldahli");
emit2 ("ld h,!*hl");
emit2 ("ld l,a");
break;
default:
- emitDebug ("; WARNING: mlh woosed out. This code is invalid.");
+ wassertl (0, "Attempted to fetch too much data into HL");
+ break;
}
}
else if (IS_Z80 && aop->type == AOP_IY) {
case AOP_LIT:
return aopLiteral (aop->aopu.aop_lit, offset);
+ case AOP_SIMPLELIT:
+ {
+ unsigned long v = aop->aopu.aop_simplelit;
+
+ v >>= (offset * 8);
+ tsprintf (s, "!immedbyte", (unsigned int) v & 0xff);
+
+ return gc_strdup(s);
+ }
case AOP_STR:
aop->coff = offset;
return aop->aopu.aop_str[offset];
freeAsmop (IC_RESULT (ic), NULL, ic);
}
+static void
+_gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
+{
+ /* Logic:
+ ld de,right.lw
+ setup hl to left
+ de = hl - de
+ push flags
+ store de into result
+ pop flags
+ ld de,right.hw
+ setup hl
+ de = hl -de
+ store de into result
+ */
+ const char *first = isAdd ? "add" : "sub";
+ const char *later = isAdd ? "adc" : "sbc";
+
+ wassertl (IS_GB, "Code is only relevent to the gbz80");
+ wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
+
+ fetchPair (PAIR_DE, left);
+
+ emit2 ("ld a,e");
+ emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
+ emit2 ("ld e,a");
+ emit2 ("ld a,d");
+ emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
+
+ _push (PAIR_AF);
+ aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
+ aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
+
+ fetchPairLong (PAIR_DE, left, MSB24);
+ aopGet (right, MSB24, FALSE);
+
+ _pop (PAIR_AF);
+ emit2 ("ld a,e");
+ emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
+ emit2 ("ld e,a");
+ emit2 ("ld a,d");
+ emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
+
+ aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
+ aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
+}
+
+static void
+_gbz80_emitAddSubLong (iCode *ic, bool isAdd)
+{
+ _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
+}
+
/*-----------------------------------------------------------------*/
/* genUminus - unary minus code generation */
/*-----------------------------------------------------------------*/
goto release;
}
+ if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
+ {
+ /* Create a new asmop with value zero */
+ asmop *azero = newAsmop (AOP_SIMPLELIT);
+ azero->aopu.aop_simplelit = 0;
+ azero->size = size;
+ _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
+ goto release;
+ }
+
/* otherwise subtract from zero */
size = AOP_SIZE (IC_LEFT (ic));
offset = 0;
freeAsmop (IC_RESULT (ic), NULL, ic);
}
-static void
-_push (PAIR_ID pairId)
-{
- emit2 ("push %s", _pairs[pairId].name);
- _G.stack.pushed += 2;
-}
-
-static void
-_pop (PAIR_ID pairId)
-{
- emit2 ("pop %s", _pairs[pairId].name);
- _G.stack.pushed -= 2;
-}
-
-
/*-----------------------------------------------------------------*/
/* assignResultValue - */
/*-----------------------------------------------------------------*/
_push (PAIR_HL);
aopPut (AOP (oper), _fReturn[0], 0);
aopPut (AOP (oper), _fReturn[1], 1);
- emit2 ("pop de");
- _G.stack.pushed -= 2;
+ _pop (PAIR_DE);
aopPut (AOP (oper), _fReturn[0], 2);
aopPut (AOP (oper), _fReturn[1], 3);
}
commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
goto release;
}
- else if (size == 4)
- {
- // Fall through
- }
}
+ if (size == 4)
+ {
+ /* Be paranoid on the GB with 4 byte variables due to how C
+ can be trashed by lda hl,n(sp).
+ */
+ _gbz80_emitAddSubLong (ic, TRUE);
+ goto release;
+ }
}
while (size--)
/* if increment 16 bits in register */
if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
- (size == 2))
+ (size == 2)
+ )
{
- fetchPair (PAIR_HL, AOP (IC_RESULT (ic)));
+ fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
while (icount--) {
- emit2 ("dec hl");
+ emit2 ("dec %s", _getTempPairName());
}
- aopPut (AOP (IC_RESULT (ic)), "l", LSB);
- aopPut (AOP (IC_RESULT (ic)), "h", MSB16);
+
+ commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
return TRUE;
}
aopPut (AOP (IC_RESULT (ic)), "e", 0);
goto release;
}
- else if (size == 4)
- {
- emitDebug ("; WARNING: This sub is probably broken.\n");
- }
}
+ if (size == 4)
+ {
+ /* Be paranoid on the GB with 4 byte variables due to how C
+ can be trashed by lda hl,n(sp).
+ */
+ _gbz80_emitAddSubLong (ic, FALSE);
+ goto release;
+ }
}
/* if literal, add a,#-lit, else normal subb */
ic->generated = 1;
}
+#if DISABLED
static const char *
_getPairIdName (PAIR_ID id)
{
return _pairs[id].name;
}
+#endif
/** Generic compare for > or <
*/
else
emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
}
+ else if (size == 4 && 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--)
+ {
+ if (size == 0 && sign)
+ {
+ // Highest byte when signed needs the bits flipped
+ // Save the flags
+ emit2 ("push af");
+ emit2 ("ld a,(de)");
+ emit2 ("xor #0x80");
+ emit2 ("ld e,a");
+ emit2 ("ld a,(hl)");
+ emit2 ("xor #0x80");
+ emit2 ("ld d,a");
+ emit2 ("pop af");
+ emit2 ("ld a,e");
+ emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
+ }
+ else
+ {
+ 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);
+ }
else
{
+#if 0
+ // PENDING: Doesn't work around zero
+
/* Special cases:
On the GB:
If the left or the right is a lit:
emit2 ("add hl,%s", _getPairIdName (id));
goto release;
}
+#endif
if (AOP_TYPE (right) == AOP_LIT)
{
lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
emit2 ("ld %s,a", _fTmp[1]);
fDidXor = TRUE;
}
- if (!fDidXor)
- _clearCarry();
- }
- else
- {
- _clearCarry();
}
while (size--)
{
if (sign && size == 0)
{
emit2 ("ld a,%s", _fTmp[0]);
- emit2 ("sbc a,%s", _fTmp[1]);
+ emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
}
else
{
/* Subtract through, propagating the carry */
- emit2 ("sbc a,%s", aopGet (AOP (right), offset++, FALSE));
+ emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset++, FALSE));
}
}
}
emitLabel (tlbl->key + 100);
}
- emit2 ("or a,a");
while (size--)
{
l = aopGet (AOP (result), offset, FALSE);
- emit2 ("rl %s", l);
+ if (offset == 0)
+ {
+ emit2 ("sla %s", l);
+ }
+ else
+ {
+ emit2 ("rl %s", l);
+ }
offset++;
}
case 0:
break;
case 1:
- emit2 ("rl a");
+ emit2 ("sla a");
break;
case 2:
- emit2 ("rl a");
+ emit2 ("sla a");
emit2 ("rl a");
break;
case 3:
- emit2 ("rl a");
+ emit2 ("sla a");
emit2 ("rl a");
emit2 ("rl a");
break;
case 4:
- emit2 ("rl a");
+ emit2 ("sla a");
emit2 ("rl a");
emit2 ("rl a");
emit2 ("rl a");
break;
case 5:
- emit2 ("rr a");
+ emit2 ("srl a");
emit2 ("rr a");
emit2 ("rr a");
break;
case 6:
- emit2 ("rr a");
+ emit2 ("srl a");
emit2 ("rr a");
break;
case 7:
- emit2 ("rr a");
+ emit2 ("srl a");
break;
}
}
emitLabel (tlbl->key + 100);
l = aopGet (AOP (result), offset, FALSE);
- emit2 ("or a,a");
-
while (size--)
{
- l = aopGet (AOP (result), offset++, FALSE);
- emit2 ("rl %s", l);
+ l = aopGet (AOP (result), offset, FALSE);
+
+ if (offset == 0)
+ {
+ emit2 ("sla %s", l);
+ }
+ else
+ {
+ emit2 ("rl %s", l);
+ }
+ offset++;
}
emitLabel (tlbl1->key + 100);
emit2 ("dec a");
aopPut (AOP (result), "a", 0);
aopPut (AOP (result), "e", 1);
}
+ else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
+ {
+ /* Special case - simple memcpy */
+ aopGet (AOP (right), LSB, FALSE);
+ emit2 ("ld d,h");
+ emit2 ("ld e,l");
+ aopGet (AOP (result), LSB, FALSE);
+
+ while (size--)
+ {
+ emit2 ("ld a,(de)");
+ /* Peephole will optimise this. */
+ emit2 ("ld (hl),a");
+
+ if (size != 0)
+ {
+ emit2 ("inc hl");
+ emit2 ("inc de");
+ }
+ }
+ spillPair (PAIR_HL);
+ }
else
{
while (size--)
return ret;
}
+static char *
+fetchLitSpecial (asmop * aop, bool negate, bool xor)
+{
+ unsigned long v;
+ value *val = aop->aopu.aop_lit;
+
+ wassert (aop->type == AOP_LIT);
+ wassert (!IS_FLOAT (val->type));
+
+ v = (unsigned long) floatFromVal (val);
+
+ if (xor)
+ v ^= 0x8000;
+ if (negate)
+ v = 0-v;
+ v &= 0xFFFF;
+
+ tsprintf (buffer, "!immedword", v);
+ return gc_strdup (buffer);
+}
+
+
*/