X-Git-Url: https://git.gag.com/?a=blobdiff_plain;ds=sidebyside;f=src%2Fz80%2Fgen.c;h=7c15dcaa646585bf0d34ca440730f039d98b0e81;hb=9527f72e6442a9d8919de3dcf42517ae0e2f80e9;hp=f697b995153b7d4e7197179d9a954871501b0dd6;hpb=b08365679f95e6cb1c7e8ef150ef304cc40cf305;p=fw%2Fsdcc diff --git a/src/z80/gen.c b/src/z80/gen.c index f697b995..7c15dcaa 100644 --- a/src/z80/gen.c +++ b/src/z80/gen.c @@ -180,7 +180,7 @@ static struct struct { AOP_TYPE last_type; - const char *lit; + const char *base; int offset; } pairs[NUM_PAIRS]; struct @@ -217,6 +217,42 @@ static 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) { @@ -446,6 +482,19 @@ genPairPush (asmop * aop) 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 */ @@ -866,10 +915,17 @@ aopGetLitWordLong (asmop * aop, int offset, bool with_hash) 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: @@ -958,7 +1014,7 @@ static void spillPair (PAIR_ID pairId) { _G.pairs[pairId].last_type = AOP_INVALID; - _G.pairs[pairId].lit = NULL; + _G.pairs[pairId].base = NULL; } static void @@ -982,34 +1038,14 @@ requiresHL (asmop * aop) } } -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)) { @@ -1017,7 +1053,7 @@ fetchLitPair (PAIR_ID pairId, asmop * left, int offset) { 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) { @@ -1032,21 +1068,7 @@ fetchLitPair (PAIR_ID pairId, asmop * left, int offset) } } _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 */ @@ -1064,18 +1086,21 @@ fetchPairLong (PAIR_ID pairId, asmop * aop, int offset) /* 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) { @@ -1268,6 +1293,15 @@ aopGet (asmop * aop, int offset, bool bit16) 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]; @@ -1671,6 +1705,59 @@ genCpl (iCode * ic) 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 */ /*-----------------------------------------------------------------*/ @@ -1703,6 +1790,16 @@ genUminus (iCode * ic) 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; @@ -1731,21 +1828,6 @@ release: 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 - */ /*-----------------------------------------------------------------*/ @@ -1768,8 +1850,7 @@ assignResultValue (operand * oper) _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); } @@ -2840,11 +2921,15 @@ genPlus (iCode * ic) 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--) @@ -2921,15 +3006,16 @@ genMinusDec (iCode * ic) /* 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; } @@ -3028,11 +3114,15 @@ genMinus (iCode * ic) 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 */ @@ -3175,11 +3265,13 @@ genIfxJump (iCode * ic, char *jval) ic->generated = 1; } +#if DISABLED static const char * _getPairIdName (PAIR_ID id) { return _pairs[id].name; } +#endif /** Generic compare for > or < */ @@ -3218,8 +3310,52 @@ genCmp (operand * left, operand * right, 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: @@ -3259,6 +3395,7 @@ genCmp (operand * left, operand * right, emit2 ("add hl,%s", _getPairIdName (id)); goto release; } +#endif if (AOP_TYPE (right) == AOP_LIT) { lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit); @@ -3317,12 +3454,6 @@ genCmp (operand * left, operand * right, emit2 ("ld %s,a", _fTmp[1]); fDidXor = TRUE; } - if (!fDidXor) - _clearCarry(); - } - else - { - _clearCarry(); } while (size--) { @@ -3334,12 +3465,12 @@ genCmp (operand * left, operand * right, 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)); } } } @@ -4465,12 +4596,18 @@ shiftL2Left2Result (operand * left, int offl, 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++; } @@ -4496,34 +4633,34 @@ AccRol (int shCount) 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; } } @@ -4761,12 +4898,19 @@ genLeftShift (iCode * ic) 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"); @@ -5414,6 +5558,28 @@ genAssign (iCode * ic) 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--) @@ -6156,4 +6322,26 @@ _isPairUsed (iCode * ic, PAIR_ID pairId) 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); +} + + */