/*-------------------------------------------------------------------------
gen.c - Z80 specific code generator.
+
+ Michael Hope <michaelh@juju.net.nz> 2000
+ Based on the mcs51 generator -
+ Sandeep Dutta . sandeep.dutta@usa.net (1998)
+ and - Jean-Louis VERN.jlvern@writeme.com (1999)
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ In other words, you are welcome to use, share and improve this program.
+ You are forbidden to forbid anyone else to use, share and improve
+ what you give them. Help stamp out software-hoarding!
+-------------------------------------------------------------------------*/
+
+/*
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
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
- Michael Hope <michaelh@juju.net.nz> 2000
- Based on the mcs51 generator -
- Sandeep Dutta . sandeep.dutta@usa.net (1998)
- and - Jean-Louis VERN.jlvern@writeme.com (1999)
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2, or (at your option) any
- later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
- In other words, you are welcome to use, share and improve this program.
- You are forbidden to forbid anyone else to use, share and improve
- what you give them. Help stamp out software-hoarding!
-
--------------------------------------------------------------------------*/
+ 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 <stdio.h>
#include <stdlib.h>
*/
enum {
- DISABLE_DEBUG = 1
+ DISABLE_DEBUG = 0
};
static char *_z80_return[] =
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);
}
if (genPlusIncr (ic) == TRUE)
goto release;
- emitDebug ("; genPlusIncr failed");
+ emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
size = getDataSize (IC_RESULT (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 */
commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
goto release;
}
- else if (size == 4)
- {
- emitDebug ("; 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--)
/* 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--)
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 */
/*-----------------------------------------------------------------*/
addSet (&_G.sendSet, ic);
break;
+ case ARRAYINIT:
+ genArrayInit(ic);
+ break;
+
default:
ic = ic;
/* piCode(ic,stdout); */
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);
+}
+
+
*/