X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=src%2Fz80%2Fgen.c;h=7c15dcaa646585bf0d34ca440730f039d98b0e81;hb=9527f72e6442a9d8919de3dcf42517ae0e2f80e9;hp=39c048e88f1a8baa65061493efd49c52b5a5bc85;hpb=5348b1694fe65587bad6296d9ecf146b2aa962d1;p=fw%2Fsdcc diff --git a/src/z80/gen.c b/src/z80/gen.c index 39c048e8..7c15dcaa 100644 --- a/src/z80/gen.c +++ b/src/z80/gen.c @@ -1,25 +1,7 @@ /*------------------------------------------------------------------------- gen.c - Z80 specific code generator. - - Benchmarks on dhry.c 2.1 with 32766 loops and a 10ms clock: - ticks dhry size - Base with asm strcpy / strcmp / memcpy: 23198 141 1A14 - Improved WORD push 22784 144 19AE - With label1 on 22694 144 197E - With label2 on 22743 144 198A - With label3 on 22776 144 1999 - With label4 on 22776 144 1999 - With all 'label' on 22661 144 196F - With loopInvariant on 20919 156 19AB - With loopInduction on Breaks 198B - With all working on 20796 158 196C - Slightly better genCmp(signed) 20597 159 195B - Better reg packing, first peephole 20038 163 1873 - With assign packing 19281 165 1849 - 5/3/00 17741 185 17B6 - With reg params for mul and div 16234 202 162D - - Michael Hope 2000 + + Michael Hope 2000 Based on the mcs51 generator - Sandeep Dutta . sandeep.dutta@usa.net (1998) and - Jean-Louis VERN.jlvern@writeme.com (1999) @@ -45,6 +27,59 @@ -------------------------------------------------------------------------*/ +/* + Benchmarks on dhry.c 2.1 with 32766 loops and a 10ms clock: + ticks dhry size + Base with asm strcpy / strcmp / memcpy: 23198 141 1A14 + Improved WORD push 22784 144 19AE + With label1 on 22694 144 197E + With label2 on 22743 144 198A + With label3 on 22776 144 1999 + With label4 on 22776 144 1999 + With all 'label' on 22661 144 196F + With loopInvariant on 20919 156 19AB + With loopInduction on Breaks 198B + With all working on 20796 158 196C + Slightly better genCmp(signed) 20597 159 195B + Better reg packing, first peephole 20038 163 1873 + With assign packing 19281 165 1849 + 5/3/00 17741 185 17B6 + With reg params for mul and div 16234 202 162D + + 1. Starting again at 3 Aug 01 34965 93 219C + No asm strings + Includes long mul/div in code + 2. Optimised memcpy for acc use 32102 102 226B + 3. Optimised strcpy for acc use 27819 117 2237 + 3a Optimised memcpy fun + 4. Optimised strcmp fun 21999 149 2294 + 5. Optimised strcmp further 21660 151 228C + 6. Optimised memcpy by unroling 20885 157 2201 + 7. After turning loop induction on 19862 165 236D + 8. Same as 7 but with more info + 9. With asm optimised strings 17030 192 2223 + + 10 and below are with asm strings off. + + Apparent advantage of turning on regparams: + 1. Cost of push + Decent case is push of a constant + - ld hl,#n; push hl: (10+11)*nargs + 2. Cost of pull from stack + Using asm with ld hl, etc + - ld hl,#2; add hl,sp; (ld bc,(hl); hl+=2)*nargs + 10+11+(7+6+7+6)*nargs + 3. Cost of fixing stack + - pop hl*nargs + 10*nargs + + So cost is (10+11+7+6+7+10)*nargs+10+11 + = 51*nargs+21 + = 123 for mul, div, strcmp, strcpy + Saving of (98298+32766+32766+32766)*123 = 24181308 + At 192 d/s for 682411768t, speed up to 199. Hmm. +*/ + #include #include #include @@ -81,6 +116,11 @@ IX is used as an index register to the top of the local variable area. ix-0 is the top most local variable. */ + +enum { + DISABLE_DEBUG = 0 +}; + static char *_z80_return[] = {"l", "h", "e", "d"}; static char *_gbz80_return[] = @@ -140,7 +180,7 @@ static struct struct { AOP_TYPE last_type; - const char *lit; + const char *base; int offset; } pairs[NUM_PAIRS]; struct @@ -177,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) { @@ -201,12 +277,9 @@ _tidyUp (char *buf) } static void -emit2 (const char *szFormat,...) +_vemit2 (const char *szFormat, va_list ap) { char buffer[256]; - va_list ap; - - va_start (ap, szFormat); tvsprintf (buffer, szFormat, ap); @@ -218,6 +291,33 @@ emit2 (const char *szFormat,...) _G.lines.current->isInline = _G.lines.isInline; } +static void +emit2 (const char *szFormat,...) +{ + va_list ap; + + va_start (ap, szFormat); + + _vemit2 (szFormat, ap); + + va_end (ap); +} + +static void +emitDebug (const char *szFormat,...) +{ + if (!DISABLE_DEBUG) + { + va_list ap; + + va_start (ap, szFormat); + + _vemit2 (szFormat, ap); + + va_end (ap); + } +} + /*-----------------------------------------------------------------*/ /* emit2 - writes the code into a file : for now it is simple */ /*-----------------------------------------------------------------*/ @@ -382,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 */ @@ -418,7 +531,7 @@ aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a) /* Assign depending on the storage class */ if (sym->onStack || sym->iaccess) { - emit2 ("; AOP_STK for %s", sym->rname); + emitDebug ("; AOP_STK for %s", sym->rname); sym->aop = aop = newAsmop (AOP_STK); aop->size = getSize (sym->type); aop->aopu.aop_stk = sym->stack; @@ -443,7 +556,7 @@ aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a) sym->aop = aop = newAsmop (AOP_SFR); aop->aopu.aop_dir = sym->rname; aop->size = getSize (sym->type); - emit2 ("; AOP_SFR for %s", sym->rname); + emitDebug ("; AOP_SFR for %s", sym->rname); return aop; } } @@ -452,7 +565,7 @@ aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a) /* in which case DPTR gets the address */ if (IS_GB) { - emit2 ("; AOP_HL for %s", sym->rname); + emitDebug ("; AOP_HL for %s", sym->rname); sym->aop = aop = newAsmop (AOP_HL); } else @@ -794,10 +907,6 @@ aopGetLitWordLong (asmop * aop, int offset, bool with_hash) char *s = buffer; char *rs; -#if 0 - if (aop->size != 2 && aop->type != AOP_HL) - return NULL; -#endif /* depending on type */ switch (aop->type) { @@ -806,12 +915,19 @@ 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); - rs = Safe_calloc (1, strlen (s) + 1); - strcpy (rs, s); - return rs; + { + tsprintf (s, "%s + %d", aop->aopu.aop_immd, offset); + } + return gc_strdup(s); + case AOP_LIT: { value *val = aop->aopu.aop_lit; @@ -822,14 +938,24 @@ aopGetLitWordLong (asmop * aop, int offset, bool with_hash) unsigned long v = (unsigned long) floatFromVal (val); if (offset == 2) - v >>= 16; + { + v >>= 16; + } + else if (offset == 0) + { + // OK + } + else + { + wassertl(0, "Encountered an invalid offset while fetching a literal"); + } if (with_hash) tsprintf (buffer, "!immedword", v); else tsprintf (buffer, "!constword", v); - rs = Safe_calloc (1, strlen (buffer) + 1); - return strcpy (rs, buffer); + + return gc_strdup(buffer); } else { @@ -888,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 @@ -912,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, 0, FALSE); - wassert (l && pair); + l = aopGetLitWordLong (left, offset, FALSE); + base = aopGetLitWordLong (left, 0, FALSE); + wassert (l && pair && base); if (isPtr (pair)) { @@ -947,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) { @@ -962,28 +1068,11 @@ 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 */ - if (offset) - emit2 ("ld %s,!hashedstr + %u", pair, l, offset); - else - emit2 ("ld %s,!hashedstr", pair, l); + emit2 ("ld %s,!hashedstr", pair, l); } static void @@ -997,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: - emit2 ("; 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) { @@ -1136,14 +1228,14 @@ aopGet (asmop * aop, int offset, bool bit16) case AOP_DIR: wassert (IS_GB); - emit2 ("ld a,(%s+%d) ; x", aop->aopu.aop_dir, offset); + emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset); sprintf (s, "a"); return gc_strdup(s); case AOP_SFR: wassert (IS_GB); - emit2 ("ldh a,(%s+%d) ; x", aop->aopu.aop_dir, offset); + emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset); sprintf (s, "a"); return gc_strdup(s); @@ -1175,7 +1267,7 @@ aopGet (asmop * aop, int offset, bool bit16) { if (aop->aopu.aop_stk >= 0) offset += _G.stack.param_offset; - tsprintf (s, "!*ixx ; x", aop->aopu.aop_stk + offset); + tsprintf (s, "!*ixx", aop->aopu.aop_stk + offset); } return gc_strdup(s); @@ -1201,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]; @@ -1375,7 +1476,7 @@ aopPut (asmop * aop, const char *s, int offset) if (offset > 0) { - emit2 ("; Error aopPut AOP_ACC"); + emitDebug ("; Error aopPut AOP_ACC"); } else { @@ -1486,7 +1587,7 @@ outBitCLong (operand * result, bool swap_sense) /* if the result is bit */ if (AOP_TYPE (result) == AOP_CRY) { - emit2 ("; Note: outBitC form 1"); + emitDebug ("; Note: outBitC form 1"); aopPut (AOP (result), "blah", 0); } else @@ -1509,7 +1610,7 @@ outBitC (operand * result) /* toBoolean - emit code for orl a,operator(sizeop) */ /*-----------------------------------------------------------------*/ void -toBoolean (operand * oper) +_toBoolean (operand * oper) { int size = AOP_SIZE (oper); int offset = 0; @@ -1554,7 +1655,7 @@ genNot (iCode * ic) wassert (0); } - toBoolean (IC_LEFT (ic)); + _toBoolean (IC_LEFT (ic)); /* Not of A: If A == 0, !A = 1 @@ -1604,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 */ /*-----------------------------------------------------------------*/ @@ -1636,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; @@ -1664,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 - */ /*-----------------------------------------------------------------*/ @@ -1701,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); } @@ -1764,7 +1912,7 @@ _saveRegsForCall(iCode *ic, int sendSetSize) deSending = (sendSetSize > 1); - emit2 ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending); + emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending); if (bcInUse && bcInRet == FALSE) { _push(PAIR_BC); @@ -1796,42 +1944,6 @@ genIpush (iCode * ic) if (!ic->parmPush) { wassertl(0, "Encountered an unsupported spill push."); -#if 0 - /* 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 */ - if (isPair (AOP (IC_LEFT (ic)))) - { - emit2 ("push %s", getPairName (AOP (IC_LEFT (ic)))); - _G.stack.pushed += 2; - } - else - { - offset = size; - while (size--) - { - /* Simple for now - load into A and PUSH AF */ - if (AOP (IC_LEFT (ic))->type == AOP_IY) - { - char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE); - wassert (l); - emit2 ("ld a,(%s)", l); - } - else - { - l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE); - emit2 ("ld a,%s", l); - } - emit2 ("push af"); - emit2 ("inc sp"); - _G.stack.pushed++; - } - } -#endif return; } @@ -1998,7 +2110,7 @@ _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId) { if (pairId == PAIR_DE) { - emit2 ("; name %s", aop->aopu.aop_reg[i]->name); + emitDebug ("; name %s", aop->aopu.aop_reg[i]->name); if (!strcmp (aop->aopu.aop_reg[i]->name, "e")) ret++; if (!strcmp (aop->aopu.aop_reg[i]->name, "d")) @@ -2006,7 +2118,7 @@ _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId) } else if (pairId == PAIR_BC) { - emit2 ("; name %s", aop->aopu.aop_reg[i]->name); + emitDebug ("; name %s", aop->aopu.aop_reg[i]->name); if (!strcmp (aop->aopu.aop_reg[i]->name, "c")) ret++; if (!strcmp (aop->aopu.aop_reg[i]->name, "b")) @@ -2110,7 +2222,7 @@ emitCall (iCode * ic, bool ispcall) if (isLitWord (AOP (IC_LEFT (ic)))) { - emit2 ("; Special case where the pCall is to a constant"); + emitDebug ("; Special case where the pCall is to a constant"); emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE)); } else @@ -2291,15 +2403,6 @@ resultRemat (iCode * ic) extern set *publics; -/* Steps: - o Check genFunction - o Check emitCall and clean up - o Check genReturn - o Check return puller - - PENDING: Remove this. -*/ - /*-----------------------------------------------------------------*/ /* genFunction - generated code for function entry */ /*-----------------------------------------------------------------*/ @@ -2338,6 +2441,11 @@ genFunction (iCode * ic) emit2 ("__%s_start:", sym->rname); emit2 ("!functionlabeldef", sym->rname); + if (options.profile) + { + emit2 ("!profileenter"); + } + fetype = getSpec (operandType (IC_LEFT (ic))); /* if critical function then turn interrupts off */ @@ -2452,6 +2560,12 @@ genEndFunction (iCode * ic) } #endif + if (options.profile) + { + emit2 ("!profileexit"); + } + + /* Both baned and non-banked just ret */ emit2 ("ret"); @@ -2562,7 +2676,7 @@ genPlusIncr (iCode * ic) if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT) return FALSE; - emit2 ("; genPlusIncr"); + emitDebug ("; genPlusIncr"); icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit); @@ -2634,7 +2748,9 @@ genPlusIncr (iCode * ic) if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic)))) { while (icount--) - emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE)); + { + emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE)); + } return TRUE; } @@ -2713,7 +2829,7 @@ genPlus (iCode * ic) if (genPlusIncr (ic) == TRUE) goto release; - emit2 ("; genPlusIncr failed"); + emitDebug ("; Can't optimise plus by inc, falling back to the normal way"); size = getDataSize (IC_RESULT (ic)); @@ -2721,10 +2837,11 @@ genPlus (iCode * ic) if (isPair (AOP (IC_RESULT (ic)))) { char *left, *right; - left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE); right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE); - if (left && right) + + if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT && + left && right) { /* It's a pair */ /* PENDING: fix */ @@ -2804,11 +2921,15 @@ genPlus (iCode * ic) commitPair (AOP (IC_RESULT (ic)), PAIR_HL); goto release; } - else if (size == 4) - { - emit2 ("; WARNING: This add 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, TRUE); + goto release; + } } while (size--) @@ -2864,26 +2985,6 @@ genMinusDec (iCode * ic) size = getDataSize (IC_RESULT (ic)); -#if 0 - /* if increment 16 bits in register */ - if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) && - (size > 1) && - (icount == 1)) - { - symbol *tlbl = newiTempLabel (NULL); - emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE)); - emit2 ("jp np," LABEL_STR, tlbl->key + 100); - - emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE)); - if (size == 4) - { - wassert (0); - } - emitLabel (tlbl->key + 100); - return TRUE; - } -#endif - /* if decrement 16 bits in register */ if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) && (size > 1) && isPair (AOP (IC_RESULT (ic)))) @@ -2903,6 +3004,23 @@ genMinusDec (iCode * ic) return TRUE; } + /* if increment 16 bits in register */ + if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) && + (size == 2) + ) + { + fetchPair (_getTempPairId(), AOP (IC_RESULT (ic))); + + while (icount--) { + emit2 ("dec %s", _getTempPairName()); + } + + commitPair (AOP (IC_RESULT (ic)), _getTempPairId()); + + 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) @@ -2996,12 +3114,16 @@ genMinus (iCode * ic) aopPut (AOP (IC_RESULT (ic)), "e", 0); goto release; } - else if (size == 4) - { - emit2 ("; 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 */ while (size--) @@ -3143,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 < */ @@ -3186,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: @@ -3227,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); @@ -3285,12 +3454,6 @@ genCmp (operand * left, operand * right, emit2 ("ld %s,a", _fTmp[1]); fDidXor = TRUE; } - if (!fDidXor) - _clearCarry(); - } - else - { - _clearCarry(); } while (size--) { @@ -3302,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 ; 2", aopGet (AOP (right), offset++, FALSE)); + emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset++, FALSE)); } } } @@ -3437,7 +3600,7 @@ gencjneshort (operand * left, operand * right, symbol * lbl) { while (size--) { - emit2 ("ld a,%s ; 2", aopGet (AOP (left), offset, FALSE)); + emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE)); if ((AOP_TYPE (right) == AOP_LIT) && lit == 0) emit2 ("or a,a"); else @@ -3462,7 +3625,7 @@ gencjneshort (operand * left, operand * right, symbol * lbl) emit2 ("jp nz,!tlabel", lbl->key + 100); else { - emit2 ("cp %s ; 4", aopGet (AOP (right), offset, FALSE)); + emit2 ("cp %s", aopGet (AOP (right), offset, FALSE)); emit2 ("jp nz,!tlabel", lbl->key + 100); } offset++; @@ -3475,7 +3638,7 @@ gencjneshort (operand * left, operand * right, symbol * lbl) while (size--) { _moveA (aopGet (AOP (right), offset, FALSE)); - emit2 ("cp %s ; 5", aopGet (AOP (left), offset, FALSE)); + emit2 ("cp %s", aopGet (AOP (left), offset, FALSE)); emit2 ("!shortjp nz,!tlabel", lbl->key + 100); offset++; } @@ -3512,7 +3675,7 @@ genCmpEq (iCode * ic, iCode * ifx) aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE); aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE); - emit2("; 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\n", 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. @@ -3637,9 +3800,9 @@ genAndOp (iCode * ic) else { tlbl = newiTempLabel (NULL); - toBoolean (left); + _toBoolean (left); emit2 ("!shortjp z,!tlabel", tlbl->key + 100); - toBoolean (right); + _toBoolean (right); emitLabel (tlbl->key + 100); outBitAcc (result); } @@ -3674,9 +3837,9 @@ genOrOp (iCode * ic) else { tlbl = newiTempLabel (NULL); - toBoolean (left); + _toBoolean (left); emit2 ("!shortjp nz,!tlabel", tlbl->key + 100); - toBoolean (right); + _toBoolean (right); emitLabel (tlbl->key + 100); outBitAcc (result); } @@ -3747,10 +3910,10 @@ genAnd (iCode * ic, iCode * ifx) aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE); #ifdef DEBUG_TYPE - emit2 ("; Type res[%d] = l[%d]&r[%d]", + emitDebug ("; Type res[%d] = l[%d]&r[%d]", AOP_TYPE (result), AOP_TYPE (left), AOP_TYPE (right)); - emit2 ("; Size res[%d] = l[%d]&r[%d]", + emitDebug ("; Size res[%d] = l[%d]&r[%d]", AOP_SIZE (result), AOP_SIZE (left), AOP_SIZE (right)); #endif @@ -3979,10 +4142,10 @@ genOr (iCode * ic, iCode * ifx) aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE); #if 1 - emit2 ("; Type res[%d] = l[%d]&r[%d]", + emitDebug ("; Type res[%d] = l[%d]&r[%d]", AOP_TYPE (result), AOP_TYPE (left), AOP_TYPE (right)); - emit2 ("; Size res[%d] = l[%d]&r[%d]", + emitDebug ("; Size res[%d] = l[%d]&r[%d]", AOP_SIZE (result), AOP_SIZE (left), AOP_SIZE (right)); #endif @@ -4179,13 +4342,15 @@ genXor (iCode * ic, iCode * ifx) _moveA (aopGet (AOP (right), offset, FALSE)); emit2 ("xor a,%s", aopGet (AOP (left), offset, FALSE)); - aopPut (AOP (result), "a", 0); + aopPut (AOP (result), "a", offset); } } else { if (AOP_TYPE (left) == AOP_ACC) - emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE)); + { + emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE)); + } else { _moveA (aopGet (AOP (right), offset, FALSE)); @@ -4220,14 +4385,15 @@ genXor (iCode * ic, iCode * ifx) } // faster than result <- left, anl result,right // and better if result is SFR - if (AOP_TYPE (left) == AOP_ACC) - emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE)); + if (AOP_TYPE (left) == AOP_ACC) + { + emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE)); + } else { _moveA (aopGet (AOP (right), offset, FALSE)); emit2 ("xor a,%s", aopGet (AOP (left), offset, FALSE)); - aopPut (AOP (result), "a", 0); } aopPut (AOP (result), "a", offset); } @@ -4299,53 +4465,97 @@ genRLC (iCode * ic) wassert (0); } +/*-----------------------------------------------------------------*/ +/* 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, FALSE); + + /* get the highest order byte into a */ + emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE)); + + if (AOP_TYPE (result) == AOP_CRY) + { + emit2 ("rl a"); + outBitC (result); + } + else + { + emit2 ("rlc a"); + /* PENDING: For re-target. */ + emit2 ("and a,#1"); + outAcc (result); + } + + + freeAsmop (left, NULL, ic); + freeAsmop (result, NULL, ic); +} + +static void +emitRsh2 (asmop *aop, int size, int is_signed) +{ + int offset = 0; + + while (size--) + { + const char *l = aopGet (aop, size, FALSE); + if (offset == 0) + { + emit2 ("%s %s", is_signed ? "sra" : "srl", l); + } + else + { + emit2 ("rr %s", l); + } + offset++; + } +} + /*-----------------------------------------------------------------*/ /* shiftR2Left2Result - shift right two bytes from left to result */ /*-----------------------------------------------------------------*/ static void shiftR2Left2Result (operand * left, int offl, operand * result, int offr, - int shCount, int sign) + int shCount, int is_signed) { + int size = 2; + symbol *tlbl, *tlbl1; + movLeft2Result (left, offl, result, offr, 0); movLeft2Result (left, offl + 1, result, offr + 1, 0); - if (sign) + /* if (AOP(result)->type == AOP_REG) { */ + + tlbl = newiTempLabel (NULL); + tlbl1 = newiTempLabel (NULL); + + /* Left is already in result - so now do the shift */ + if (shCount <= 2) { - wassert (0); + while (shCount--) + { + emitRsh2 (AOP (result), size, is_signed); + } } else { - /* if (AOP(result)->type == AOP_REG) { */ - int size = 2; - int offset = 0; - symbol *tlbl, *tlbl1; - const char *l; - - tlbl = newiTempLabel (NULL); - tlbl1 = newiTempLabel (NULL); + emit2 ("ld a,!immedbyte+1", shCount); + emit2 ("!shortjp !tlabel", tlbl1->key + 100); + emitLabel (tlbl->key + 100); - /* Left is already in result - so now do the shift */ - if (shCount > 1) - { - emit2 ("ld a,!immedbyte+1", shCount); - emit2 ("!shortjp !tlabel", tlbl1->key + 100); - emitLabel (tlbl->key + 100); - } + emitRsh2 (AOP (result), size, is_signed); - emit2 ("or a,a"); - offset = size; - while (size--) - { - l = aopGet (AOP (result), --offset, FALSE); - emit2 ("rr %s", l); - } - if (shCount > 1) - { - emitLabel (tlbl1->key + 100); - emit2 ("dec a"); - emit2 ("!shortjp nz,!tlabel", tlbl->key + 100); - } + emitLabel (tlbl1->key + 100); + emit2 ("dec a"); + emit2 ("!shortjp nz,!tlabel", tlbl->key + 100); } } @@ -4386,11 +4596,20 @@ 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); + l = aopGet (AOP (result), offset, FALSE); + + if (offset == 0) + { + emit2 ("sla %s", l); + } + else + { + emit2 ("rl %s", l); + } + + offset++; } if (shCount > 1) { @@ -4414,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; } } @@ -4570,7 +4789,7 @@ genLeftShiftLiteral (operand * left, size = getSize (operandType (result)); #if VIEW_SIZE - emit2 ("; shift left result %d, left %d", size, + emitDebug ("; shift left result %d, left %d", size, AOP_SIZE (left)); #endif @@ -4580,9 +4799,13 @@ genLeftShiftLiteral (operand * left, wassert (0); } - else if (shCount >= (size * 8)) - while (size--) - aopPut (AOP (result), "!zero", size); + else if (shCount >= (size * 8)) + { + while (size--) + { + aopPut (AOP (result), "!zero", size); + } + } else { switch (size) @@ -4594,7 +4817,7 @@ genLeftShiftLiteral (operand * left, genlshTwo (result, left, shCount); break; case 4: - wassert (0); + wassertl (0, "Shifting of longs is currently unsupported"); break; default: wassert (0); @@ -4674,11 +4897,20 @@ genLeftShift (iCode * ic) emit2 ("!shortjp !tlabel", tlbl1->key + 100); 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"); @@ -4692,7 +4924,7 @@ genLeftShift (iCode * ic) /* genrshOne - left shift two bytes by known amount != 0 */ /*-----------------------------------------------------------------*/ static void -genrshOne (operand * result, operand * left, int shCount) +genrshOne (operand * result, operand * left, int shCount, int is_signed) { /* Errk */ int size = AOP_SIZE (result); @@ -4702,19 +4934,24 @@ genrshOne (operand * result, operand * left, int shCount) wassert (shCount < 8); l = aopGet (AOP (left), 0, FALSE); + + emit2 ("or a,a"); + if (AOP (result)->type == AOP_REG) { aopPut (AOP (result), l, 0); l = aopGet (AOP (result), 0, FALSE); while (shCount--) - emit2 ("srl %s", l); + { + emit2 ("%s %s", is_signed ? "sra" : "srl", l); + } } else { _moveA (l); while (shCount--) { - emit2 ("srl a"); + emit2 ("%s a", is_signed ? "sra" : "srl"); } aopPut (AOP (result), "a", 0); } @@ -4796,7 +5033,8 @@ static void genRightShiftLiteral (operand * left, operand * right, operand * result, - iCode * ic) + iCode * ic, + int sign) { int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit); int size; @@ -4808,7 +5046,7 @@ genRightShiftLiteral (operand * left, size = getSize (operandType (result)); - emit2 ("; shift right result %d, left %d", size, + emitDebug ("; shift right result %d, left %d", size, AOP_SIZE (left)); /* I suppose that the left size >= result size */ @@ -4825,17 +5063,17 @@ genRightShiftLiteral (operand * left, switch (size) { case 1: - genrshOne (result, left, shCount); + genrshOne (result, left, shCount, sign); break; case 2: /* PENDING: sign support */ - genrshTwo (result, left, shCount, FALSE); + genrshTwo (result, left, shCount, sign); break; case 4: - wassert (0); + wassertl (0, "Asked to shift right a long which should be a function call"); break; default: - wassert (0); + wassertl (0, "Entered default case in right shift delegate"); } } freeAsmop (left, NULL, ic); @@ -4879,7 +5117,7 @@ genRightShift (iCode * ic) as efficiently as possible */ if (AOP_TYPE (right) == AOP_LIT) { - genRightShiftLiteral (left, right, result, ic); + genRightShiftLiteral (left, right, result, ic, is_signed); return; } @@ -4918,14 +5156,13 @@ genRightShift (iCode * ic) l = aopGet (AOP (result), offset--, FALSE); if (first) { - if (is_signed) - emit2 ("sra %s", l); - else - emit2 ("srl %s", l); + emit2 ("%s %s", is_signed ? "sra" : "srl", l); first = 0; } else - emit2 ("rr %s", l); + { + emit2 ("rr %s", l); + } } emitLabel (tlbl1->key + 100); emit2 ("dec a"); @@ -5149,7 +5386,7 @@ genIfx (iCode * ic, iCode * popIc) /* get the value into acc */ if (AOP_TYPE (cond) != AOP_CRY) - toBoolean (cond); + _toBoolean (cond); else isbit = 1; /* the result is now in the accumulator */ @@ -5246,7 +5483,7 @@ genAssign (iCode * ic) /* Dont bother assigning if they are the same */ if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic))) { - emit2 ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic))); + emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic))); return; } #endif @@ -5257,7 +5494,7 @@ genAssign (iCode * ic) /* if they are the same registers */ if (sameRegs (AOP (right), AOP (result))) { - emit2 ("; (registers are the same)"); + emitDebug ("; (registers are the same)"); goto release; } @@ -5321,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--) @@ -5458,7 +5717,7 @@ genCast (iCode * ic) const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1, FALSE); _moveA (l); - emit2 ("; genCast: sign extend untested."); + emitDebug ("; genCast: sign extend untested."); emit2 ("rla "); emit2 ("sbc a,a"); while (size--) @@ -5499,6 +5758,246 @@ genReceive (iCode * ic) freeAsmop (IC_RESULT (ic), NULL, ic); } +enum + { + /** Maximum number of bytes to emit per line. */ + DBEMIT_MAX_RUN = 8 + }; + +/** Context for the byte output chunker. */ +typedef struct +{ + unsigned char buffer[DBEMIT_MAX_RUN]; + int pos; +} DBEMITCTX; + + +/** Flushes a byte chunker by writing out all in the buffer and + reseting. +*/ +static void +_dbFlush(DBEMITCTX *self) +{ + char line[256]; + + if (self->pos > 0) + { + int i; + sprintf(line, ".db 0x%02X", self->buffer[0]); + + for (i = 1; i < self->pos; i++) + { + sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]); + } + emit2(line); + } + self->pos = 0; +} + +/** Write out another byte, buffering until a decent line is + generated. +*/ +static void +_dbEmit(DBEMITCTX *self, int c) +{ + if (self->pos == DBEMIT_MAX_RUN) + { + _dbFlush(self); + } + self->buffer[self->pos++] = c; +} + +/** Context for a simple run length encoder. */ +typedef struct +{ + unsigned last; + unsigned char buffer[128]; + int pos; + /** runLen may be equivalent to pos. */ + int runLen; +} RLECTX; + +enum + { + RLE_CHANGE_COST = 4, + RLE_MAX_BLOCK = 127 + }; + +/** Flush the buffer of a run length encoder by writing out the run or + data that it currently contains. +*/ +static void +_rleCommit(RLECTX *self) +{ + int i; + if (self->pos != 0) + { + DBEMITCTX db; + memset(&db, 0, sizeof(db)); + + emit2(".db %u", self->pos); + + for (i = 0; i < self->pos; i++) + { + _dbEmit(&db, self->buffer[i]); + } + _dbFlush(&db); + } + /* Reset */ + self->pos = 0; +} + +/* Encoder design: + Can get either a run or a block of random stuff. + Only want to change state if a good run comes in or a run ends. + Detecting run end is easy. + Initial state? + + Say initial state is in run, len zero, last zero. Then if you get a + few zeros then something else then a short run will be output. + Seems OK. While in run mode, keep counting. While in random mode, + keep a count of the run. If run hits margin, output all up to run, + restart, enter run mode. +*/ + +/** Add another byte into the run length encoder, flushing as + required. The run length encoder uses the Amiga IFF style, where + a block is prefixed by its run length. A positive length means + the next n bytes pass straight through. A negative length means + that the next byte is repeated -n times. A zero terminates the + chunks. +*/ +static void +_rleAppend(RLECTX *self, int c) +{ + int i; + + if (c != self->last) + { + /* The run has stopped. See if it is worthwhile writing it out + as a run. Note that the random data comes in as runs of + length one. + */ + if (self->runLen > RLE_CHANGE_COST) + { + /* Yes, worthwhile. */ + /* Commit whatever was in the buffer. */ + _rleCommit(self); + emit2(".db -%u,0x%02X", self->runLen, self->last); + } + else + { + /* Not worthwhile. Append to the end of the random list. */ + for (i = 0; i < self->runLen; i++) + { + if (self->pos >= RLE_MAX_BLOCK) + { + /* Commit. */ + _rleCommit(self); + } + self->buffer[self->pos++] = self->last; + } + } + self->runLen = 1; + self->last = c; + } + else + { + if (self->runLen >= RLE_MAX_BLOCK) + { + /* Commit whatever was in the buffer. */ + _rleCommit(self); + + emit2 (".db -%u,0x%02X", self->runLen, self->last); + self->runLen = 0; + } + self->runLen++; + } +} + +static void +_rleFlush(RLECTX *self) +{ + _rleAppend(self, -1); + _rleCommit(self); + self->pos = 0; + self->last = 0; + self->runLen = 0; +} + +/** genArrayInit - Special code for initialising an array with constant + data. +*/ +static void +genArrayInit (iCode * ic) +{ + literalList *iLoop; + int ix; + int elementSize = 0, eIndex, i; + unsigned val, lastVal; + sym_link *type; + RLECTX rle; + + memset(&rle, 0, sizeof(rle)); + + 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"); + } + + type = operandType(IC_LEFT(ic)); + + if (type && type->next) + { + elementSize = getSize(type->next); + } + else + { + wassertl (0, "Can't determine element size in genArrayInit."); + } + + iLoop = IC_ARRAYILIST(ic); + lastVal = (unsigned)-1; + + /* Feed all the bytes into the run length encoder which will handle + the actual output. + This works well for mixed char data, and for random int and long + data. + */ + while (iLoop) + { + ix = iLoop->count; + + if (ix != 0) + { + for (i = 0; i < ix; i++) + { + for (eIndex = 0; eIndex < elementSize; eIndex++) + { + val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff; + _rleAppend(&rle, val); + } + } + } + + iLoop = iLoop->next; + } + + _rleFlush(&rle); + /* Mark the end of the run. */ + emit2(".db 0"); + + freeAsmop (IC_LEFT(ic), NULL, ic); +} + /*-----------------------------------------------------------------*/ /* genZ80Code - generate code for Z80 based controllers */ /*-----------------------------------------------------------------*/ @@ -5541,22 +6040,22 @@ genZ80Code (iCode * lic) switch (ic->op) { case '!': - emit2 ("; genNot"); + emitDebug ("; genNot"); genNot (ic); break; case '~': - emit2 ("; genCpl"); + emitDebug ("; genCpl"); genCpl (ic); break; case UNARYMINUS: - emit2 ("; genUminus"); + emitDebug ("; genUminus"); genUminus (ic); break; case IPUSH: - emit2 ("; genIpush"); + emitDebug ("; genIpush"); genIpush (ic); break; @@ -5571,83 +6070,83 @@ genZ80Code (iCode * lic) ic->next->op == IFX && regsInCommon (IC_LEFT (ic), IC_COND (ic->next))) { - emit2 ("; genIfx"); + emitDebug ("; genIfx"); genIfx (ic->next, ic); } else { - emit2 ("; genIpop"); + emitDebug ("; genIpop"); genIpop (ic); } break; case CALL: - emit2 ("; genCall"); + emitDebug ("; genCall"); genCall (ic); break; case PCALL: - emit2 ("; genPcall"); + emitDebug ("; genPcall"); genPcall (ic); break; case FUNCTION: - emit2 ("; genFunction"); + emitDebug ("; genFunction"); genFunction (ic); break; case ENDFUNCTION: - emit2 ("; genEndFunction"); + emitDebug ("; genEndFunction"); genEndFunction (ic); break; case RETURN: - emit2 ("; genRet"); + emitDebug ("; genRet"); genRet (ic); break; case LABEL: - emit2 ("; genLabel"); + emitDebug ("; genLabel"); genLabel (ic); break; case GOTO: - emit2 ("; genGoto"); + emitDebug ("; genGoto"); genGoto (ic); break; case '+': - emit2 ("; genPlus"); + emitDebug ("; genPlus"); genPlus (ic); break; case '-': - emit2 ("; genMinus"); + emitDebug ("; genMinus"); genMinus (ic); break; case '*': - emit2 ("; genMult"); + emitDebug ("; genMult"); genMult (ic); break; case '/': - emit2 ("; genDiv"); + emitDebug ("; genDiv"); genDiv (ic); break; case '%': - emit2 ("; genMod"); + emitDebug ("; genMod"); genMod (ic); break; case '>': - emit2 ("; genCmpGt"); + emitDebug ("; genCmpGt"); genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic)); break; case '<': - emit2 ("; genCmpLt"); + emitDebug ("; genCmpLt"); genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic)); break; @@ -5662,66 +6161,67 @@ genZ80Code (iCode * lic) break; case EQ_OP: - emit2 ("; genCmpEq"); + emitDebug ("; genCmpEq"); genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic)); break; case AND_OP: - emit2 ("; genAndOp"); + emitDebug ("; genAndOp"); genAndOp (ic); break; case OR_OP: - emit2 ("; genOrOp"); + emitDebug ("; genOrOp"); genOrOp (ic); break; case '^': - emit2 ("; genXor"); + emitDebug ("; genXor"); genXor (ic, ifxForOp (IC_RESULT (ic), ic)); break; case '|': - emit2 ("; genOr"); + emitDebug ("; genOr"); genOr (ic, ifxForOp (IC_RESULT (ic), ic)); break; case BITWISEAND: - emit2 ("; genAnd"); + emitDebug ("; genAnd"); genAnd (ic, ifxForOp (IC_RESULT (ic), ic)); break; case INLINEASM: - emit2 ("; genInline"); + emitDebug ("; genInline"); genInline (ic); break; case RRC: - emit2 ("; genRRC"); + emitDebug ("; genRRC"); genRRC (ic); break; case RLC: - emit2 ("; genRLC"); + emitDebug ("; genRLC"); genRLC (ic); break; case GETHBIT: - emit2 ("; genHBIT"); - wassert (0); + emitDebug ("; genGetHBIT"); + genGetHbit (ic); + break; case LEFT_OP: - emit2 ("; genLeftShift"); + emitDebug ("; genLeftShift"); genLeftShift (ic); break; case RIGHT_OP: - emit2 ("; genRightShift"); + emitDebug ("; genRightShift"); genRightShift (ic); break; case GET_VALUE_AT_ADDRESS: - emit2 ("; genPointerGet"); + emitDebug ("; genPointerGet"); genPointerGet (ic); break; @@ -5729,46 +6229,50 @@ genZ80Code (iCode * lic) if (POINTER_SET (ic)) { - emit2 ("; genAssign (pointer)"); + emitDebug ("; genAssign (pointer)"); genPointerSet (ic); } else { - emit2 ("; genAssign"); + emitDebug ("; genAssign"); genAssign (ic); } break; case IFX: - emit2 ("; genIfx"); + emitDebug ("; genIfx"); genIfx (ic, NULL); break; case ADDRESS_OF: - emit2 ("; genAddrOf"); + emitDebug ("; genAddrOf"); genAddrOf (ic); break; case JUMPTABLE: - emit2 ("; genJumpTab"); + emitDebug ("; genJumpTab"); genJumpTab (ic); break; case CAST: - emit2 ("; genCast"); + emitDebug ("; genCast"); genCast (ic); break; case RECEIVE: - emit2 ("; genReceive"); + emitDebug ("; genReceive"); genReceive (ic); break; case SEND: - emit2 ("; addSet"); + emitDebug ("; addSet"); addSet (&_G.sendSet, ic); break; + case ARRAYINIT: + genArrayInit(ic); + break; + default: ic = ic; /* piCode(ic,stdout); */ @@ -5818,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); +} + + */