/*-------------------------------------------------------------------------
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 <michaelh@earthling.net> 2000
+
+ 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)
-------------------------------------------------------------------------*/
+/*
+ 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SDCCglue.h"
#include "newalloc.h"
-/* this is the down and dirty file with all kinds of kludgy & hacky
+/* This is the down and dirty file with all kinds of kludgy & hacky
stuff. This is what it is all about CODE GENERATION for a specific MCU.
Some of the routines may be reusable, will have to see */
-static char *spname;
+/* Z80 calling convention description.
+ Parameters are passed right to left. As the stack grows downwards,
+ the parameters are arranged in left to right in memory.
+ Parameters may be passed in the HL and DE registers with one
+ parameter per pair.
+ PENDING: What if the parameter is a long?
+ Everything is caller saves. i.e. the caller must save any registers
+ that it wants to preserve over the call.
+ GB: The return value is returned in DEHL. DE is normally used as a
+ working register pair. Caller saves allows it to be used for a
+ return value.
+ va args functions do not use register parameters. All arguments
+ are passed on the stack.
+ IX is used as an index register to the top of the local variable
+ area. ix-0 is the top most local variable.
+*/
+
+enum
+{
+ /* Set to enable debugging trace statements in the output assembly code. */
+ DISABLE_DEBUG = 0
+};
+
static char *_z80_return[] =
{"l", "h", "e", "d"};
static char *_gbz80_return[] =
{"e", "d", "l", "h"};
+static char *_fReceive[] =
+ { "c", "b", "e", "d" };
+
static char **_fReturn;
static char **_fTmp;
-/* PENDING: messy */
-static char zero[20];
-
-static char *accUse[] =
-{"a"};
-static char *hlUse[] =
-{"l", "h"};
-short rbank = -1;
-short accInUse = 0;
-short inLine = 0;
-short debugLine = 0;
-short nregssaved = 0;
-extern int ptrRegReq;
-extern int nRegs;
extern FILE *codeOutFile;
-set *sendSet = NULL;
+enum
+ {
+ INT8MIN = -128,
+ INT8MAX = 127
+ };
+
+/** Enum covering all the possible register pairs.
+ */
typedef enum
{
PAIR_INVALID,
+ PAIR_AF,
PAIR_BC,
PAIR_DE,
PAIR_HL,
PAIR_IY,
PAIR_IX,
NUM_PAIRS
- }
-PAIR_ID;
+ } PAIR_ID;
static struct
- {
- const char *name;
- const char *l;
- const char *h;
- }
-_pairs[NUM_PAIRS] =
{
+ const char *name;
+ const char *l;
+ const char *h;
+} _pairs[NUM_PAIRS] = {
+ { "??1", "?2", "?3" },
+ { "af", "f", "a" },
+ { "bc", "c", "b" },
+ { "de", "e", "d" },
+ { "hl", "l", "h" },
+ { "iy", "iyl", "iyh" },
+ { "ix", "ixl", "ixh" }
+};
+
+// PENDING
+#define ACC_NAME _pairs[PAIR_AF].h
+
+enum
{
- "??", "?", "?"
- }
- ,
- {
- "bc", "c", "b"
- }
- ,
- {
- "de", "e", "d"
- }
- ,
+ LSB,
+ MSB16,
+ MSB24,
+ MSB32
+ };
+
+/** Code generator persistent data.
+ */
+static struct
+{
+ /** Used to optimised setting up of a pair by remebering what it
+ contains and adjusting instead of reloading where possible.
+ */
+ struct
{
- "hl", "l", "h"
- }
- ,
+ AOP_TYPE last_type;
+ const char *base;
+ int offset;
+ } pairs[NUM_PAIRS];
+ struct
{
- "iy", "iy.l?", "iy.h?"
- }
- ,
+ int last;
+ int pushed;
+ int param_offset;
+ int offset;
+ int pushedBC;
+ int pushedDE;
+ } stack;
+ int frameId;
+ int receiveOffset;
+ bool flushStatics;
+ bool in_home;
+ const char *lastFunctionName;
+
+ set *sendSet;
+
+ struct
{
- "ix", "ix.l?", "ix.h?"
- }
-};
-
-#define RESULTONSTACK(x) \
- (IC_RESULT(x) && IC_RESULT(x)->aop && \
- IC_RESULT(x)->aop->type == AOP_STK )
+ /** TRUE if the registers have already been saved. */
+ bool saved;
+ } saves;
-#define MOVA(x) if (strcmp(x,"a")) emitcode("ld","a,%s",x);
-#define CLRC emitcode("xor","a,a");
-
-lineNode *lineHead = NULL;
-lineNode *lineCurr = NULL;
+ struct
+ {
+ lineNode *head;
+ lineNode *current;
+ int isInline;
+ allocTrace trace;
+ } lines;
-static const unsigned char SLMask[] =
-{0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00};
-static const unsigned char SRMask[] =
-{0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00};
+ struct
+ {
+ allocTrace aops;
+ } trace;
+} _G;
-#define LSB 0
-#define MSB16 1
-#define MSB24 2
-#define MSB32 3
+static const char *aopGet (asmop * aop, int offset, bool bit16);
-/* Stack frame:
- IX+4 param0 LH
- IX+2 ret LH
- IX+0 ix LH
- IX-2 temp0 LH
- */
+static PAIR_ID
+_getTempPairId(void)
+{
+ if (IS_GB)
+ {
+ return PAIR_DE;
+ }
+ else
+ {
+ return PAIR_HL;
+ }
+}
-static struct {
- struct {
- AOP_TYPE last_type;
- const char *lit;
- int offset;
- }
- pairs[NUM_PAIRS];
- struct {
- int last;
- int pushed;
- int param_offset;
- int offset;
- int pushed_bc;
- int pushed_de;
- } stack;
- int frameId;
- int receiveOffset;
- bool flush_statics;
- bool in_home;
- }
-_G;
+static const char *
+_getTempPairName(void)
+{
+ return _pairs[_getTempPairId()].name;
+}
-static char *aopGet (asmop * aop, int offset, bool bit16);
+static PAIR_ID
+getFreePairId (iCode *ic)
+{
+ if (!(bitVectBitValue (ic->rMask, B_IDX) || bitVectBitValue(ic->rMask, C_IDX)))
+ {
+ return PAIR_BC;
+ }
+ else if (IS_Z80 && !(bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX)))
+ {
+ return PAIR_DE;
+ }
+ else
+ {
+ return PAIR_INVALID;
+ }
+}
static void
_tidyUp (char *buf)
}
/* Change the first (and probably only) ' ' to a tab so
everything lines up.
- */
+ */
while (*buf)
{
if (*buf == ' ')
- {
- *buf = '\t';
- return;
- }
+ {
+ *buf = '\t';
+ break;
+ }
buf++;
}
}
+static lineNode *
+_newLineNode (char *line)
+{
+ lineNode *pl;
+
+ pl = traceAlloc(&_G.lines.trace, Safe_alloc ( sizeof (lineNode)));
+ pl->line = traceAlloc(&_G.lines.trace, Safe_strdup (line));
+
+ return pl;
+}
+
static void
-emit2 (const char *szFormat,...)
+_vemit2 (const char *szFormat, va_list ap)
{
char buffer[256];
+
+ tvsprintf (buffer, szFormat, ap);
+
+ _tidyUp (buffer);
+ _G.lines.current = (_G.lines.current ?
+ connectLine (_G.lines.current, _newLineNode (buffer)) :
+ (_G.lines.head = _newLineNode (buffer)));
+
+ _G.lines.current->isInline = _G.lines.isInline;
+}
+
+static void
+emit2 (const char *szFormat,...)
+{
va_list ap;
va_start (ap, szFormat);
- tvsprintf (buffer, szFormat, ap);
+ _vemit2 (szFormat, ap);
- _tidyUp (buffer);
- lineCurr = (lineCurr ?
- connectLine (lineCurr, newLineNode (buffer)) :
- (lineHead = newLineNode (buffer)));
+ va_end (ap);
+}
- lineCurr->isInline = inLine;
- lineCurr->isDebug = debugLine;
+static void
+emitDebug (const char *szFormat,...)
+{
+ if (!DISABLE_DEBUG)
+ {
+ va_list ap;
+
+ va_start (ap, szFormat);
+
+ _vemit2 (szFormat, ap);
+
+ va_end (ap);
+ }
}
/*-----------------------------------------------------------------*/
-/* emitcode - writes the code into a file : for now it is simple */
+/* emit2 - writes the code into a file : for now it is simple */
/*-----------------------------------------------------------------*/
void
-emitcode (const char *inst, const char *fmt,...)
+_emit2 (const char *inst, const char *fmt,...)
{
va_list ap;
- char lb[MAX_INLINEASM];
+ char lb[INITIAL_INLINEASM];
char *lbp = lb;
va_start (ap, fmt);
lbp++;
if (lbp && *lbp)
- lineCurr = (lineCurr ?
- connectLine (lineCurr, newLineNode (lb)) :
- (lineHead = newLineNode (lb)));
- lineCurr->isInline = inLine;
- lineCurr->isDebug = debugLine;
+ {
+ _G.lines.current = (_G.lines.current ?
+ connectLine (_G.lines.current, _newLineNode (lb)) :
+ (_G.lines.head = _newLineNode (lb)));
+ }
+ _G.lines.current->isInline = _G.lines.isInline;
va_end (ap);
}
-/* Z80:
- { "adjustsp",
- "\tld hl,#-%d\n"
- "\tadd hl,sp\n"
- "\tld sp,hl"
- }
- { "prelude",
- "push bc"
- "push de"
- "push ix"
- "ld ix,#0"
- "add ix,sp"
- { "leave"
- emitcode("ld", "sp,ix");
- emitcode("pop", "ix");
- emitcode("pop", "de");
- }
- }
- */
+static void
+_emitMove(const char *to, const char *from)
+{
+ if (strcasecmp(to, from) != 0)
+ {
+ emit2("ld %s,%s", to, from);
+ }
+ else
+ {
+ // Optimise it out.
+ // Could leave this to the peephole, but sometimes the peephole is inhibited.
+ }
+}
+
+static void
+_moveA(const char *moveFrom)
+{
+ // Let the peephole optimiser take care of redundent loads
+ _emitMove(ACC_NAME, moveFrom);
+}
+
+static void
+_clearCarry(void)
+{
+ emit2("xor a,a");
+}
const char *
getPairName (asmop * aop)
break;
}
}
- else if (aop->type == AOP_STR)
+ else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
{
- switch (*aop->aopu.aop_str[0])
- {
- case 'c':
- return "bc";
- break;
- case 'e':
- return "de";
- break;
- case 'l':
- return "hl";
- break;
- }
+ int i;
+ for (i = 0; i < NUM_PAIRS; i++)
+ {
+ if (strcmp(aop->aopu.aop_str[0], _pairs[i].l) == 0)
+ {
+ return _pairs[i].name;
+ }
+ }
}
- wassert (0);
+ wassertl (0, "Tried to get the pair name of something that isn't a pair");
return NULL;
}
return PAIR_HL;
}
}
- if (aop->type == AOP_STR)
+ else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
{
- if (!strcmp (aop->aopu.aop_str[0], "c") && !strcmp (aop->aopu.aop_str[1], "b"))
- {
- return PAIR_BC;
- }
- if (!strcmp (aop->aopu.aop_str[0], "e") && !strcmp (aop->aopu.aop_str[1], "d"))
- {
- return PAIR_DE;
- }
- if (!strcmp (aop->aopu.aop_str[0], "l") && !strcmp (aop->aopu.aop_str[1], "h"))
- {
- return PAIR_HL;
- }
- }
+ int i;
+ for (i = 0; i < NUM_PAIRS; i++)
+ {
+ if (!strcmp (aop->aopu.aop_str[0], _pairs[i].l) && !strcmp (aop->aopu.aop_str[1], _pairs[i].h))
+ {
+ return i;
+ }
+ }
+ }
}
return PAIR_INVALID;
}
return FALSE;
}
}
+
+static void
+spillPair (PAIR_ID pairId)
+{
+ _G.pairs[pairId].last_type = AOP_INVALID;
+ _G.pairs[pairId].base = NULL;
+}
+
/** Push a register pair onto the stack */
void
genPairPush (asmop * aop)
{
- emitcode ("push", "%s", getPairName (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;
+ spillPair (pairId);
+}
/*-----------------------------------------------------------------*/
/* newAsmop - creates a new asmOp */
{
asmop *aop;
- aop = Safe_calloc (1, sizeof (asmop));
+ aop = traceAlloc(&_G.trace.aops, Safe_alloc (sizeof (asmop)));
aop->type = type;
return aop;
}
/* Assign depending on the storage class */
if (sym->onStack || sym->iaccess)
{
- emitcode ("", "; AOP_STK for %s", sym->rname);
- sym->aop = aop = newAsmop (AOP_STK);
+ /* The pointer that is used depends on how big the offset is.
+ Normally everything is AOP_STK, but for offsets of < -128 or
+ > 127 on the Z80 an extended stack pointer is used.
+ */
+ if (IS_Z80 && (options.ommitFramePtr || sym->stack < INT8MIN || sym->stack > (int)(INT8MAX-getSize (sym->type))))
+ {
+ emitDebug ("; AOP_EXSTK for %s", sym->rname);
+ sym->aop = aop = newAsmop (AOP_EXSTK);
+ }
+ else
+ {
+ emitDebug ("; AOP_STK for %s", sym->rname);
+ sym->aop = aop = newAsmop (AOP_STK);
+ }
+
aop->size = getSize (sym->type);
aop->aopu.aop_stk = sym->stack;
return aop;
if (IS_FUNC (sym->type))
{
sym->aop = aop = newAsmop (AOP_IMMD);
- aop->aopu.aop_immd = Safe_calloc (1, strlen (sym->rname) + 1);
- strcpy (aop->aopu.aop_immd, sym->rname);
+ aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup (sym->rname));
aop->size = 2;
return aop;
}
sym->aop = aop = newAsmop (AOP_SFR);
aop->aopu.aop_dir = sym->rname;
aop->size = getSize (sym->type);
- emitcode ("", "; AOP_SFR for %s", sym->rname);
+ emitDebug ("; AOP_SFR for %s", sym->rname);
return aop;
}
}
/* in which case DPTR gets the address */
if (IS_GB)
{
- emitcode ("", "; AOP_HL for %s", sym->rname);
+ emitDebug ("; AOP_HL for %s", sym->rname);
sym->aop = aop = newAsmop (AOP_HL);
}
else
break;
}
- aop->aopu.aop_immd = Safe_calloc (1, strlen (buffer) + 1);
- strcpy (aop->aopu.aop_immd, buffer);
+ aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
return aop;
}
return;
}
- if (sym->accuse)
+ if (sym->ruonly)
{
int i;
+ aop = op->aop = sym->aop = newAsmop (AOP_STR);
+ aop->size = getSize (sym->type);
+ for (i = 0; i < 4; i++)
+ aop->aopu.aop_str[i] = _fReturn[i];
+ return;
+ }
+
+ if (sym->accuse)
+ {
if (sym->accuse == ACCUSE_A)
{
aop = op->aop = sym->aop = newAsmop (AOP_ACC);
aop->size = getSize (sym->type);
- for (i = 0; i < 2; i++)
- aop->aopu.aop_str[i] = accUse[i];
+ wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
+
+ aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
}
- else if (sym->accuse == ACCUSE_HL)
+ else if (sym->accuse == ACCUSE_SCRATCH)
{
- wassert (!IS_GB);
aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
aop->size = getSize (sym->type);
- for (i = 0; i < 2; i++)
- aop->aopu.aop_str[i] = hlUse[i];
+ wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
+ aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
+ aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
}
- else
- wassert (0);
- return;
- }
-
- if (sym->ruonly)
- {
- int i;
- aop = op->aop = sym->aop = newAsmop (AOP_STR);
- aop->size = getSize (sym->type);
- for (i = 0; i < 4; i++)
- aop->aopu.aop_str[i] = _fReturn[i];
+ else if (sym->accuse == ACCUSE_IY)
+ {
+ aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
+ aop->size = getSize (sym->type);
+ wassertl(aop->size <= 2, "Internal error: Caching in IY, but too big to fit in IY");
+ aop->aopu.aop_str[0] = _pairs[PAIR_IY].l;
+ aop->aopu.aop_str[1] = _pairs[PAIR_IY].h;
+ }
+ else
+ {
+ wassertl (0, "Marked as being allocated into A or HL but is actually in neither");
+ }
return;
}
aop->freed = 1;
+ if (aop->type == AOP_PAIRPTR && IS_Z80 && aop->aopu.aop_pairId == PAIR_DE)
+ {
+ _pop (aop->aopu.aop_pairId);
+ }
+
dealloc:
/* all other cases just dealloc */
if (op)
SPIL_LOC (op)->aop = NULL;
}
}
+
}
bool
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)
{
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 traceAlloc(&_G.trace.aops, Safe_strdup(s));
+
case AOP_LIT:
{
value *val = aop->aopu.aop_lit;
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 traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
}
else
{
- /* A float */
- Z80_FLOAT f;
- convertFloat (&f, floatFromVal (val));
+ union {
+ float f;
+ unsigned char c[4];
+ }
+ fl;
+ unsigned int i;
+
+ /* it is type float */
+ fl.f = (float) floatFromVal (val);
+
+#ifdef _BIG_ENDIAN
+ i = fl.c[3-offset] | (fl.c[3-offset-1]<<8);
+#else
+ i = fl.c[offset] | (fl.c[offset+1]<<8);
+#endif
if (with_hash)
- tsprintf (buffer, "!immedword", f.w[offset / 2]);
+ tsprintf (buffer, "!immedword", i);
else
- tsprintf (buffer, "!constword", f.w[offset / 2]);
- rs = Safe_calloc (1, strlen (buffer) + 1);
- return strcpy (rs, buffer);
+ tsprintf (buffer, "!constword", i);
+
+ return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
}
}
default:
while (*pold < new)
{
- emitcode ("inc", "%s", pair);
+ emit2 ("inc %s", pair);
(*pold)++;
}
while (*pold > new)
{
- emitcode ("dec", "%s", pair);
+ emit2 ("dec %s", pair);
(*pold)--;
}
}
-static void
-spillPair (PAIR_ID pairId)
-{
- _G.pairs[pairId].last_type = AOP_INVALID;
- _G.pairs[pairId].lit = NULL;
-}
-
static void
spillCached (void)
{
case AOP_IY:
case AOP_HL:
case AOP_STK:
+ case AOP_EXSTK:
+ case AOP_HLREG:
return TRUE;
default:
return FALSE;
}
}
-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))
{
{
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)
{
adjustPair (pair, &_G.pairs[pairId].offset, offset);
return;
}
- if (pairId == PAIR_IY && abs (offset) < 127)
+ if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
{
return;
}
}
}
_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 = traceAlloc(&_G.trace.aops, Safe_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
if (isLitWord (aop)) {
fetchLitPair (pairId, aop, offset);
}
- else {
+ else
+ {
+ if (getPairId (aop) == pairId)
+ {
+ /* Do nothing */
+ }
/* we need to get it byte by byte */
- if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
+ else 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) {
emit2("ld %s,!zero", _pairs[pairId].h);
}
}
+ else if (pairId == PAIR_IY)
+ {
+ if (isPair (aop))
+ {
+ emit2 ("push %s", _pairs[getPairId(aop)].name);
+ emit2 ("pop iy");
+ }
+ else
+ {
+ _push (PAIR_HL);
+ /* Can't load into parts, so load into HL then exchange. */
+ emit2 ("ld %s,%s", _pairs[PAIR_HL].l, aopGet (aop, offset, FALSE));
+ emit2 ("ld %s,%s", _pairs[PAIR_HL].h, aopGet (aop, offset + 1, FALSE));
+ emit2 ("push hl");
+ emit2 ("pop iy");
+ _pop (PAIR_HL);
+ }
+ }
else {
- emitcode ("ld", "%s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
- emitcode ("ld", "%s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
+ emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
+ emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
}
/* PENDING: check? */
if (pairId == PAIR_HL)
}
static void
-setupPair (PAIR_ID pairId, asmop * aop, int offset)
+setupPairFromSP (PAIR_ID id, int offset)
{
- assert (pairId == PAIR_HL || pairId == PAIR_IY);
+ wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
+
+ if (offset < INT8MIN || offset > INT8MAX)
+ {
+ emit2 ("ld hl,!immedword", offset);
+ emit2 ("add hl,sp");
+ }
+ else
+ {
+ emit2 ("!ldahlsp", offset);
+ }
+}
+static void
+setupPair (PAIR_ID pairId, asmop * aop, int offset)
+{
switch (aop->type)
{
case AOP_IY:
+ wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
fetchLitPair (pairId, aop, 0);
break;
+
case AOP_HL:
+ wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
+
fetchLitPair (pairId, aop, offset);
_G.pairs[pairId].offset = offset;
break;
- case AOP_STK:
+
+ case AOP_EXSTK:
+ wassertl (IS_Z80, "Only the Z80 has an extended stack");
+ wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
+
+ {
+ int offset = aop->aopu.aop_stk + _G.stack.offset;
+
+ if (_G.pairs[pairId].last_type == aop->type &&
+ _G.pairs[pairId].offset == offset)
+ {
+ /* Already setup */
+ }
+ else
+ {
+ /* PENDING: Do this better. */
+ sprintf (buffer, "%d", offset + _G.stack.pushed);
+ emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
+ emit2 ("add %s,sp", _pairs[pairId].name);
+ _G.pairs[pairId].last_type = aop->type;
+ _G.pairs[pairId].offset = offset;
+ }
+ }
+ break;
+
+ case AOP_STK:
{
/* Doesnt include _G.stack.pushed */
int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
}
else
{
- emit2 ("!ldahlsp", abso + _G.stack.pushed);
+ setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
}
_G.pairs[pairId].offset = abso;
break;
}
+
+ case AOP_PAIRPTR:
+ adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
+ break;
+
default:
wassert (0);
}
/*-----------------------------------------------------------------*/
/* aopGet - for fetching value of the aop */
/*-----------------------------------------------------------------*/
-static char *
+static const char *
aopGet (asmop * aop, int offset, bool bit16)
{
char *s = buffer;
- char *rs;
/* offset is greater than size then zero */
/* PENDING: this seems a bit screwed in some pointer cases. */
if (offset > (aop->size - 1) &&
- aop->type != AOP_LIT)
- return zero;
+ aop->type != AOP_LIT)
+ {
+ tsprintf (s, "!zero");
+ return traceAlloc(&_G.trace.aops, Safe_strdup(s));
+ }
/* depending on type */
switch (aop->type)
tsprintf (s, "!lsbimmeds", aop->aopu.aop_immd);
break;
default:
- wassert (0);
+ wassertl (0, "Fetching from beyond the limits of an immediate value.");
}
- rs = Safe_calloc (1, strlen (s) + 1);
- strcpy (rs, s);
- return rs;
+
+ return traceAlloc(&_G.trace.aops, Safe_strdup(s));
case AOP_DIR:
wassert (IS_GB);
- emitcode ("ld", "a,(%s+%d) ; x", aop->aopu.aop_dir, offset);
+ emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
sprintf (s, "a");
- rs = Safe_calloc (1, strlen (s) + 1);
- strcpy (rs, s);
- return rs;
+
+ return traceAlloc(&_G.trace.aops, Safe_strdup(s));
case AOP_SFR:
wassert (IS_GB);
- emitcode ("ldh", "a,(%s+%d) ; x", aop->aopu.aop_dir, offset);
+ emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
sprintf (s, "a");
- rs = Safe_calloc (1, strlen (s) + 1);
- strcpy (rs, s);
- return rs;
+
+ return traceAlloc(&_G.trace.aops, Safe_strdup(s));
case AOP_REG:
return aop->aopu.aop_reg[offset]->name;
wassert (IS_GB);
setupPair (PAIR_HL, aop, offset);
tsprintf (s, "!*hl");
- return gc_strdup (s);
+
+ return traceAlloc(&_G.trace.aops, Safe_strdup (s));
case AOP_IY:
wassert (IS_Z80);
setupPair (PAIR_IY, aop, offset);
tsprintf (s, "!*iyx", offset);
- rs = Safe_calloc (1, strlen (s) + 1);
- strcpy (rs, s);
- return rs;
+
+ return traceAlloc(&_G.trace.aops, Safe_strdup(s));
+
+ case AOP_EXSTK:
+ wassert (IS_Z80);
+ setupPair (PAIR_IY, aop, offset);
+ tsprintf (s, "!*iyx", offset, offset);
+
+ return traceAlloc(&_G.trace.aops, Safe_strdup(s));
case AOP_STK:
if (IS_GB)
{
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);
}
- rs = Safe_calloc (1, strlen (s) + 1);
- strcpy (rs, s);
- return rs;
+
+ return traceAlloc(&_G.trace.aops, Safe_strdup(s));
case AOP_CRY:
- wassert (0);
+ wassertl (0, "Tried to fetch from a bit variable");
case AOP_ACC:
if (!offset)
{
return "a";
}
- return "!zero";
+ else
+ {
+ tsprintf(s, "!zero");
+ return traceAlloc(&_G.trace.aops, Safe_strdup(s));
+ }
case AOP_HLREG:
wassert (offset < 2);
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 traceAlloc(&_G.trace.aops, Safe_strdup(s));
+ }
case AOP_STR:
aop->coff = offset;
return aop->aopu.aop_str[offset];
+
+ case AOP_PAIRPTR:
+ setupPair (aop->aopu.aop_pairId, aop, offset);
+ sprintf (s, "(%s)", _pairs[aop->aopu.aop_pairId].name);
+
+ return traceAlloc(&_G.trace.aops, Safe_strdup(s));
+
default:
break;
}
static void
aopPut (asmop * aop, const char *s, int offset)
{
+ char buffer2[256];
+
if (aop->size && offset > (aop->size - 1))
{
werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
exit (0);
}
+ // PENDING
+ tsprintf(buffer2, s);
+ s = buffer2;
+
/* will assign value to value */
/* depending on where it is ofcourse */
switch (aop->type)
/* Direct. Hmmm. */
wassert (IS_GB);
if (strcmp (s, "a"))
- emitcode ("ld", "a,%s", s);
- emitcode ("ld", "(%s+%d),a", aop->aopu.aop_dir, offset);
+ emit2 ("ld a,%s", s);
+ emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
break;
case AOP_SFR:
wassert (IS_GB);
if (strcmp (s, "a"))
- emitcode ("ld", "a,%s", s);
- emitcode ("ldh", "(%s+%d),a", aop->aopu.aop_dir, offset);
+ emit2 ("ld a,%s", s);
+ emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
break;
case AOP_REG:
case AOP_IY:
wassert (!IS_GB);
- setupPair (PAIR_IY, aop, offset);
if (!canAssignToPtr (s))
{
emit2 ("ld a,%s", s);
+ setupPair (PAIR_IY, aop, offset);
emit2 ("ld !*iyx,a", offset);
}
else
- emit2 ("ld !*iyx,%s", offset, s);
+ {
+ setupPair (PAIR_IY, aop, offset);
+ emit2 ("ld !*iyx,%s", offset, s);
+ }
break;
case AOP_HL:
emit2 ("ld !*hl,%s", s);
break;
+ case AOP_EXSTK:
+ wassert (!IS_GB);
+ if (!canAssignToPtr (s))
+ {
+ emit2 ("ld a,%s", s);
+ setupPair (PAIR_IY, aop, offset);
+ emit2 ("ld !*iyx,a", offset);
+ }
+ else
+ {
+ setupPair (PAIR_IY, aop, offset);
+ emit2 ("ld !*iyx,%s", offset, s);
+ }
+ break;
+
case AOP_STK:
if (IS_GB)
{
emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
}
else
- emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
+ {
+ emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
+ }
}
break;
else
{
/* In bit space but not in C - cant happen */
- wassert (0);
+ wassertl (0, "Tried to write into a bit variable");
}
break;
aop->coff = offset;
if (strcmp (aop->aopu.aop_str[offset], s))
{
- emitcode ("ld", "%s,%s", aop->aopu.aop_str[offset], s);
+ emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
}
break;
break;
if (offset > 0)
{
-
- emitcode ("", "; Error aopPut AOP_ACC");
+ wassertl (0, "Tried to access past the end of A");
}
else
{
if (strcmp (aop->aopu.aop_str[offset], s))
- emitcode ("ld", "%s,%s", aop->aopu.aop_str[offset], s);
+ emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
}
break;
emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
break;
+ case AOP_PAIRPTR:
+ setupPair (aop->aopu.aop_pairId, aop, offset);
+ emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
+ break;
+
default:
werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
"aopPut got unsupported aop->type");
static void
commitPair (asmop * aop, PAIR_ID id)
{
- if (id == PAIR_HL && requiresHL (aop))
+ /* PENDING: Verify this. */
+ if (id == PAIR_HL && requiresHL (aop) && IS_GB)
{
emit2 ("ld a,l");
emit2 ("ld d,h");
}
else
{
- aopPut (aop, _pairs[id].l, 0);
- aopPut (aop, _pairs[id].h, 1);
+ /* Special cases */
+ if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
+ {
+ char *l = aopGetLitWordLong (aop, 0, FALSE);
+ wassert (l);
+
+ emit2 ("ld (%s),%s", l, _pairs[id].name);
+ }
+ else
+ {
+ aopPut (aop, _pairs[id].l, 0);
+ aopPut (aop, _pairs[id].h, 1);
+ }
}
}
if (size == 3)
{
/* pointer */
- wassert (0);
+ wassertl (0, "Somehow got a three byte data pointer");
}
return size;
}
movLeft2Result (operand * left, int offl,
operand * result, int offr, int sign)
{
- char *l;
+ const char *l;
+
if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
{
l = aopGet (AOP (left), offl, FALSE);
}
else
{
- wassert (0);
+ if (getDataSize (left) == offl + 1)
+ {
+ emit2 ("ld a,%s", l);
+ aopPut (AOP (result), "a", offr);
+ }
}
}
}
+static void
+movLeft2ResultLong (operand * left, int offl,
+ operand * result, int offr, int sign,
+ int size)
+{
+ if (size == 1)
+ {
+ movLeft2Result (left, offl, result, offr, sign);
+ }
+ else
+ {
+ wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
+ wassertl (size == 2, "Only implemented for two bytes or one");
+
+ if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
+ {
+ emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
+ emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
+ emit2 ("ld l,a");
+ }
+ else if ( getPairId ( AOP (result)) == PAIR_IY)
+ {
+ PAIR_ID id = getPairId (AOP (left));
+ if (id != PAIR_INVALID)
+ {
+ emit2("push %s", _pairs[id].name);
+ emit2("pop iy");
+ }
+ else
+ {
+ /* PENDING */
+ emitDebug("Error");
+ }
+ }
+ else
+ {
+ movLeft2Result (left, offl, result, offr, sign);
+ movLeft2Result (left, offl+1, result, offr+1, sign);
+ }
+ }
+}
/** Put Acc into a register set
*/
/* unsigned or positive */
while (size--)
{
- aopPut (AOP (result), zero, offset++);
+ aopPut (AOP (result), "!zero", offset++);
}
}
}
/* if the result is bit */
if (AOP_TYPE (result) == AOP_CRY)
{
- emitcode ("", "; Note: outBitC form 1");
- aopPut (AOP (result), "blah", 0);
+ wassertl (0, "Tried to write carry to a bit");
}
else
{
/* toBoolean - emit code for orl a,operator(sizeop) */
/*-----------------------------------------------------------------*/
void
-toBoolean (operand * oper)
+_toBoolean (operand * oper)
{
int size = AOP_SIZE (oper);
int offset = 0;
if (size > 1)
{
- emitcode ("ld", "a,%s", aopGet (AOP (oper), offset++, FALSE));
+ emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
size--;
while (size--)
- emitcode ("or", "a,%s", aopGet (AOP (oper), offset++, FALSE));
+ emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
}
else
{
if (AOP (oper)->type != AOP_ACC)
{
- CLRC;
- emitcode ("or", "a,%s", aopGet (AOP (oper), 0, FALSE));
+ _clearCarry();
+ emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
}
}
}
+/*-----------------------------------------------------------------*/
+/* genNotFloat - generates not for float operations */
+/*-----------------------------------------------------------------*/
+static void
+genNotFloat (operand * op, operand * res)
+{
+ int size, offset;
+ symbol *tlbl;
+
+ emitDebug ("; genNotFloat");
+
+ /* we will put 127 in the first byte of
+ the result */
+ aopPut (AOP (res), "!immedbyte", 0x7F);
+ size = AOP_SIZE (op) - 1;
+ offset = 1;
+
+ _moveA (aopGet (op->aop, offset++, FALSE));
+
+ while (size--)
+ {
+ emit2 ("or a,%s", aopGet (op->aop, offset++, FALSE));
+ }
+
+ tlbl = newiTempLabel (NULL);
+ aopPut (res->aop, "!one", 1);
+ emit2 ("!shortjp z !tlabel", tlbl->key + 100);
+ aopPut (res->aop, "!zero", 1);
+
+ emitLabel(tlbl->key + 100);
+
+ size = res->aop->size - 2;
+ offset = 2;
+ /* put zeros in the rest */
+ while (size--)
+ aopPut (res->aop, "!zero", offset++);
+}
+
/*-----------------------------------------------------------------*/
/* genNot - generate code for ! operation */
/*-----------------------------------------------------------------*/
/* if in bit space then a special case */
if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
{
- wassert (0);
+ wassertl (0, "Tried to negate a bit");
}
/* if type float then do float */
if (IS_FLOAT (optype))
{
- wassert (0);
+ genNotFloat (IC_LEFT (ic), IC_RESULT (ic));
+ goto release;
}
- toBoolean (IC_LEFT (ic));
+ _toBoolean (IC_LEFT (ic));
/* Not of A:
If A == 0, !A = 1
emit2 ("sub a,!one");
outBitC (IC_RESULT (ic));
+ release:
/* release the aops */
freeAsmop (IC_LEFT (ic), NULL, ic);
freeAsmop (IC_RESULT (ic), NULL, ic);
if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
{
- wassert (0);
+ wassertl (0, "Left and the result are in bit space");
}
size = AOP_SIZE (IC_RESULT (ic));
while (size--)
{
- char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
- MOVA (l);
- emitcode ("cpl", "");
+ const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
+ _moveA (l);
+ emit2("cpl");
aopPut (AOP (IC_RESULT (ic)), "a", 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);
+}
+
+/*-----------------------------------------------------------------*/
+/* genUminusFloat - unary minus for floating points */
+/*-----------------------------------------------------------------*/
+static void
+genUminusFloat (operand * op, operand * result)
+{
+ int size, offset = 0;
+
+ emitDebug("; genUminusFloat");
+
+ /* for this we just need to flip the
+ first it then copy the rest in place */
+ size = AOP_SIZE (op) - 1;
+
+ _moveA(aopGet (AOP (op), MSB32, FALSE));
+
+ emit2("xor a,!immedbyte", 0x80);
+ aopPut (AOP (result), "a", MSB32);
+
+ while (size--)
+ {
+ aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
+ offset++;
+ }
+}
+
/*-----------------------------------------------------------------*/
/* genUminus - unary minus code generation */
/*-----------------------------------------------------------------*/
if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
{
- wassert (0);
+ wassertl (0, "Left and right are in bit space");
goto release;
}
/* if float then do float stuff */
if (IS_FLOAT (optype))
{
- wassert (0);
+ genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
goto release;
}
/* otherwise subtract from zero */
size = AOP_SIZE (IC_LEFT (ic));
+
+ 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;
+ }
+
offset = 0;
- CLRC;
+ _clearCarry();
while (size--)
{
- char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
+ const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
emit2 ("ld a,!zero");
emit2 ("sbc a,%s", l);
aopPut (AOP (IC_RESULT (ic)), "a", offset++);
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 - */
/*-----------------------------------------------------------------*/
int size = AOP_SIZE (oper);
bool topInA = 0;
- wassert (size <= 4);
+ wassertl (size <= 4, "Got a result that is bigger than four bytes");
topInA = requiresHL (AOP (oper));
-#if 0
- if (!IS_GB)
- wassert (size <= 2);
-#endif
if (IS_GB && size == 4 && requiresHL (AOP (oper)))
{
/* We do it the hard way here. */
_push (PAIR_HL);
aopPut (AOP (oper), _fReturn[0], 0);
aopPut (AOP (oper), _fReturn[1], 1);
- emitcode ("pop", "de");
- _G.stack.pushed -= 2;
+ _pop (PAIR_DE);
aopPut (AOP (oper), _fReturn[0], 2);
aopPut (AOP (oper), _fReturn[1], 3);
}
}
}
+/** Simple restore that doesn't take into account what is used in the
+ return.
+*/
+static void
+_restoreRegsAfterCall(void)
+{
+ if (_G.stack.pushedDE)
+ {
+ _pop ( PAIR_DE);
+ _G.stack.pushedDE = FALSE;
+ }
+ if (_G.stack.pushedBC)
+ {
+ _pop ( PAIR_BC);
+ _G.stack.pushedBC = FALSE;
+ }
+ _G.saves.saved = FALSE;
+}
+
+static void
+_saveRegsForCall(iCode *ic, int sendSetSize)
+{
+ /* Rules:
+ o Stack parameters are pushed before this function enters
+ o DE and BC may be used in this function.
+ o HL and DE may be used to return the result.
+ o HL and DE may be used to send variables.
+ o DE and BC may be used to store the result value.
+ o HL may be used in computing the sent value of DE
+ o The iPushes for other parameters occur before any addSets
+
+ Logic: (to be run inside the first iPush or if none, before sending)
+ o Compute if DE and/or BC are in use over the call
+ o Compute if DE is used in the send set
+ o Compute if DE and/or BC are used to hold the result value
+ o If (DE is used, or in the send set) and is not used in the result, push.
+ o If BC is used and is not in the result, push
+ o
+ o If DE is used in the send set, fetch
+ o If HL is used in the send set, fetch
+ o Call
+ o ...
+ */
+ if (_G.saves.saved == FALSE) {
+ bool deInUse, bcInUse;
+ bool deSending;
+ bool bcInRet = FALSE, deInRet = FALSE;
+ bitVect *rInUse;
+
+ rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
+
+ deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
+ bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
+
+ deSending = (sendSetSize > 1);
+
+ emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
+
+ if (bcInUse && bcInRet == FALSE) {
+ _push(PAIR_BC);
+ _G.stack.pushedBC = TRUE;
+ }
+ if (deInUse && deInRet == FALSE) {
+ _push(PAIR_DE);
+ _G.stack.pushedDE = TRUE;
+ }
+
+ _G.saves.saved = TRUE;
+ }
+ else {
+ /* Already saved. */
+ }
+}
+
/*-----------------------------------------------------------------*/
/* genIpush - genrate code for pushing this gets a little complex */
/*-----------------------------------------------------------------*/
genIpush (iCode * ic)
{
int size, offset = 0;
- char *l;
+ const char *l;
/* if this is not a parm push : ie. it is spill push
and spill push is always done on the local stack */
if (!ic->parmPush)
{
- /* 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))))
- {
- emitcode ("push", 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++;
- }
- }
+ wassertl(0, "Encountered an unsupported spill push.");
return;
}
- /* Hmmm... what about saving the currently used registers
- at this point? */
+ if (_G.saves.saved == FALSE) {
+ /* Caller saves, and this is the first iPush. */
+ /* Scan ahead until we find the function that we are pushing parameters to.
+ Count the number of addSets on the way to figure out what registers
+ are used in the send set.
+ */
+ int nAddSets = 0;
+ iCode *walk = ic->next;
+
+ while (walk) {
+ if (walk->op == SEND) {
+ nAddSets++;
+ }
+ else if (walk->op == CALL || walk->op == PCALL) {
+ /* Found it. */
+ break;
+ }
+ else {
+ /* Keep looking. */
+ }
+ walk = walk->next;
+ }
+ _saveRegsForCall(walk, nAddSets);
+ }
+ else {
+ /* Already saved by another iPush. */
+ }
/* then do the push */
aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
size = AOP_SIZE (IC_LEFT (ic));
- if (isPair (AOP (IC_LEFT (ic))))
+ if (isPair (AOP (IC_LEFT (ic))) && size == 2)
{
_G.stack.pushed += 2;
- emitcode ("push", "%s", getPairName (AOP (IC_LEFT (ic))));
+ emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
}
else
{
if (size == 2)
{
fetchHL (AOP (IC_LEFT (ic)));
- emitcode ("push", "hl");
+ emit2 ("push hl");
spillPair (PAIR_HL);
_G.stack.pushed += 2;
goto release;
if (size == 4)
{
fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
- emitcode ("push", "hl");
+ emit2 ("push hl");
spillPair (PAIR_HL);
_G.stack.pushed += 2;
fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 0);
- emitcode ("push", "hl");
+ emit2 ("push hl");
spillPair (PAIR_HL);
_G.stack.pushed += 2;
goto release;
l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
emit2 ("ld a,%s", l);
}
- emitcode ("push", "af");
- emitcode ("inc", "sp");
+ emit2 ("push af");
+ emit2 ("inc sp");
_G.stack.pushed++;
}
}
offset = (size - 1);
if (isPair (AOP (IC_LEFT (ic))))
{
- emitcode ("pop", getPairName (AOP (IC_LEFT (ic))));
+ emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
}
else
{
while (size--)
{
- emitcode ("dec", "sp");
- emitcode ("pop", "hl");
+ emit2 ("dec sp");
+ emit2 ("pop hl");
spillPair (PAIR_HL);
aopPut (AOP (IC_LEFT (ic)), "l", offset--);
}
freeAsmop (IC_LEFT (ic), NULL, ic);
}
-static int
-_isPairUsed (iCode * ic, PAIR_ID pairId)
+/* This is quite unfortunate */
+static void
+setArea (int inHome)
{
- int ret = 0;
- switch (pairId)
- {
- case PAIR_DE:
- if (bitVectBitValue (ic->rMask, D_IDX))
- ret++;
- if (bitVectBitValue (ic->rMask, E_IDX))
- ret++;
- break;
- default:
- wassert (0);
- }
- return ret;
+ /*
+ static int lastArea = 0;
+
+ if (_G.in_home != inHome) {
+ if (inHome) {
+ const char *sz = port->mem.code_name;
+ port->mem.code_name = "HOME";
+ emit2("!area", CODE_NAME);
+ port->mem.code_name = sz;
+ }
+ else
+ emit2("!area", CODE_NAME); */
+ _G.in_home = inHome;
+ // }
+}
+
+static bool
+isInHome (void)
+{
+ return _G.in_home;
}
static int
{
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"))
ret++;
}
+ else if (pairId == PAIR_BC)
+ {
+ 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"))
+ ret++;
+ }
else
{
wassert (0);
return ret;
}
-/* This is quite unfortunate */
+/** Emit the code for a call statement
+ */
static void
-setArea (int inHome)
+emitCall (iCode * ic, bool ispcall)
{
- /*
- static int lastArea = 0;
+ sym_link *dtype = operandType (IC_LEFT (ic));
- if (_G.in_home != inHome) {
- if (inHome) {
- const char *sz = port->mem.code_name;
- port->mem.code_name = "HOME";
- emit2("!area", CODE_NAME);
- port->mem.code_name = sz;
- }
- else
- emit2("!area", CODE_NAME); */
- _G.in_home = inHome;
- // }
-}
-
-static bool
-isInHome (void)
-{
- return _G.in_home;
-}
-
-/** Emit the code for a call statement
- */
-static void
-emitCall (iCode * ic, bool ispcall)
-{
- int pushed_de = 0;
- sym_link *detype = getSpec (operandType (IC_LEFT (ic)));
+ bitVect *rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
/* if caller saves & we have not saved then */
if (!ic->regsSaved)
/* PENDING */
}
+ _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
+
/* if send set is not empty then assign */
- if (sendSet)
+ if (_G.sendSet)
{
iCode *sic;
int send = 0;
- int n = elementsInSet (sendSet);
- if (IS_Z80 && n == 2 && _isPairUsed (ic, PAIR_DE))
- {
- /* Only push de if it is used and if it's not used
- in the return value */
- /* Panic if partly used */
- if (_opUsesPair (IC_RESULT (ic), ic, PAIR_DE) == 1)
- {
- emit2 ("; Warning: de crossover");
- }
- else if (!_opUsesPair (IC_RESULT (ic), ic, PAIR_DE))
- {
- /* Store away de */
- _push (PAIR_DE);
- pushed_de = 1;
- }
- }
- /* PENDING: HACK */
- if (IS_Z80 && n == 2)
- {
- /* Want to load HL first, then DE as HL may = DE */
- sic = setFirstItem (sendSet);
- sic = setNextItem (sendSet);
- aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
- fetchPair (PAIR_HL, AOP (IC_LEFT (sic)));
- send++;
- freeAsmop (IC_LEFT (sic), NULL, sic);
- sic = setFirstItem (sendSet);
- aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
- fetchPair (PAIR_DE, AOP (IC_LEFT (sic)));
- send++;
- freeAsmop (IC_LEFT (sic), NULL, sic);
- }
- else
- {
- for (sic = setFirstItem (sendSet); sic;
- sic = setNextItem (sendSet))
- {
- int size;
- aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
- size = AOP_SIZE (IC_LEFT (sic));
- wassert (size <= 2);
- /* Always send in pairs */
- switch (send)
- {
- case 0:
- if (IS_Z80 && n == 1)
- fetchPair (PAIR_HL, AOP (IC_LEFT (sic)));
- else
- fetchPair (PAIR_DE, AOP (IC_LEFT (sic)));
- break;
- case 1:
- fetchPair (PAIR_HL, AOP (IC_LEFT (sic)));
- break;
- default:
- /* Send set too big */
- wassert (0);
- }
- send++;
- freeAsmop (IC_LEFT (sic), NULL, sic);
- }
- }
- sendSet = NULL;
- if (pushed_de)
- {
- }
+ int nSend = elementsInSet(_G.sendSet);
+ bool swapped = FALSE;
+
+ int _z80_sendOrder[] = {
+ PAIR_BC, PAIR_DE
+ };
+
+ if (nSend > 1) {
+ /* Check if the parameters are swapped. If so route through hl instead. */
+ wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
+
+ sic = setFirstItem(_G.sendSet);
+ sic = setNextItem(_G.sendSet);
+
+ if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
+ /* The second send value is loaded from one the one that holds the first
+ send, i.e. it is overwritten. */
+ /* Cache the first in HL, and load the second from HL instead. */
+ emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
+ emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
+
+ swapped = TRUE;
+ }
+ }
+
+ for (sic = setFirstItem (_G.sendSet); sic;
+ sic = setNextItem (_G.sendSet))
+ {
+ int size;
+ aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
+
+ size = AOP_SIZE (IC_LEFT (sic));
+ wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
+ wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
+
+ // PENDING: Mild hack
+ if (swapped == TRUE && send == 1) {
+ if (size > 1) {
+ emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
+ }
+ else {
+ emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
+ }
+ emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
+ }
+ else {
+ fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
+ }
+
+ send++;
+ freeAsmop (IC_LEFT (sic), NULL, sic);
+ }
+ _G.sendSet = NULL;
}
if (ispcall)
{
- if (IS_BANKEDCALL (detype))
+ if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
{
werror (W_INDIR_BANKED);
}
if (isLitWord (AOP (IC_LEFT (ic))))
{
- emitcode ("", "; Special case where the pCall is to a constant");
- emitcode ("call", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
+ emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
}
else
{
symbol *rlbl = newiTempLabel (NULL);
spillPair (PAIR_HL);
emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
- emitcode ("push", "hl");
+ emit2 ("push hl");
_G.stack.pushed += 2;
fetchHL (AOP (IC_LEFT (ic)));
char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
OP_SYMBOL (IC_LEFT (ic))->rname :
OP_SYMBOL (IC_LEFT (ic))->name;
- if (IS_BANKEDCALL (detype))
+ if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
{
emit2 ("call banked_call");
emit2 ("!dws", name);
}
spillCached ();
+ /* Mark the regsiters as restored. */
+ _G.saves.saved = FALSE;
+
/* if we need assign a result value */
if ((IS_ITEMP (IC_RESULT (ic)) &&
(OP_SYMBOL (IC_RESULT (ic))->nRegs ||
IS_TRUE_SYMOP (IC_RESULT (ic)))
{
- accInUse++;
aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
- accInUse--;
assignResultValue (IC_RESULT (ic));
if (ic->parmBytes)
{
int i = ic->parmBytes;
+
_G.stack.pushed -= i;
if (IS_GB)
{
spillCached ();
if (i > 6)
{
- emitcode ("ld", "hl,#%d", i);
- emitcode ("add", "hl,sp");
- emitcode ("ld", "sp,hl");
+ emit2 ("ld hl,#%d", i);
+ emit2 ("add hl,sp");
+ emit2 ("ld sp,hl");
}
else
{
while (i > 1)
{
- emitcode ("pop", "hl");
+ emit2 ("pop hl");
i -= 2;
}
if (i)
- emitcode ("inc", "sp");
+ emit2 ("inc sp");
}
- spillCached ();
}
}
- if (pushed_de)
- _pop (PAIR_DE);
+
+ spillCached ();
+
+ if (_G.stack.pushedDE)
+ {
+ bool dInUse = bitVectBitValue(rInUse, D_IDX);
+ bool eInUse = bitVectBitValue(rInUse, E_IDX);
+
+ if (dInUse && eInUse)
+ {
+ _pop (PAIR_DE);
+ }
+ else if (dInUse)
+ {
+ _pop(PAIR_HL);
+ emit2 ("ld d,h");
+ }
+ else if (eInUse)
+ {
+ _pop(PAIR_HL);
+ emit2 ("ld e,l");
+ }
+ else
+ {
+ wassertl (0, "Neither D or E were in use but it was pushed.");
+ }
+ _G.stack.pushedDE = FALSE;
+ }
+
+ if (_G.stack.pushedBC)
+ {
+ bool bInUse = bitVectBitValue(rInUse, B_IDX);
+ bool cInUse = bitVectBitValue(rInUse, C_IDX);
+
+ // If both B and C are used in the return value, then we won't get
+ // here.
+ if (bInUse && cInUse)
+ {
+ _pop (PAIR_BC);
+ }
+ else if (bInUse)
+ {
+ _pop(PAIR_HL);
+ emit2 ("ld b,h");
+ }
+ else if (cInUse)
+ {
+ _pop(PAIR_HL);
+ emit2 ("ld c,l");
+ }
+ else
+ {
+ wassertl (0, "Neither B or C were in use but it was pushed.");
+ }
+ _G.stack.pushedBC = FALSE;
+ }
}
/*-----------------------------------------------------------------*/
genFunction (iCode * ic)
{
symbol *sym = OP_SYMBOL (IC_LEFT (ic));
- sym_link *fetype;
+ sym_link *ftype;
- nregssaved = 0;
- // PENDING: HACK
- _G.receiveOffset = 0;
+#if CALLEE_SAVES
+ bool bcInUse = FALSE;
+ bool deInUse = FALSE;
+#endif
- setArea (IS_NONBANKED (sym->etype));
+ setArea (IFFUNC_NONBANKED (sym->type));
- /* PENDING: hack */
- if (!IS_STATIC (sym->etype))
- {
- addSetIfnotP (&publics, sym);
- }
+ /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
+ else.
+ */
+ _G.receiveOffset = 0;
- /* create the function header */
+ /* Record the last function name for debugging. */
+ _G.lastFunctionName = sym->rname;
+
+ /* Create the function header */
emit2 ("!functionheader", sym->name);
/* PENDING: portability. */
emit2 ("__%s_start:", sym->rname);
emit2 ("!functionlabeldef", sym->rname);
- fetype = getSpec (operandType (IC_LEFT (ic)));
+ if (options.profile)
+ {
+ emit2 ("!profileenter");
+ }
+
+ ftype = operandType (IC_LEFT (ic));
/* if critical function then turn interrupts off */
- if (SPEC_CRTCL (fetype))
+ if (IFFUNC_ISCRITICAL (ftype))
emit2 ("!di");
- /* if this is an interrupt service routine then
- save acc, b, dpl, dph */
- if (IS_ISR (sym->etype))
+ /* if this is an interrupt service routine then save all potentially used registers. */
+ if (IFFUNC_ISISR (sym->type))
{
emit2 ("!pusha");
}
+
/* PENDING: callee-save etc */
- /* If BC or DE are used, then push */
- _G.stack.pushed_bc = 0;
- _G.stack.pushed_de = 0;
_G.stack.param_offset = 0;
- /* PENDING: BUG: We don't detect if DE or BC are used in a send set.
- For now assume the worst and always save.
- */
- _G.stack.pushed_bc = 1;
- _G.stack.pushed_de = 1;
-
+#if CALLEE_SAVES
+ /* Detect which registers are used. */
if (sym->regsUsed)
{
int i;
{
case C_IDX:
case B_IDX:
- _G.stack.pushed_bc = 1;
+ bcInUse = TRUE;
break;
case D_IDX:
case E_IDX:
- if (IS_Z80)
- _G.stack.pushed_de = 1;
+ if (IS_Z80) {
+ deInUse = TRUE;
+ }
+ else {
+ /* Other systems use DE as a temporary. */
+ }
break;
}
}
}
}
- if (_G.stack.pushed_bc)
- {
- emit2 ("push bc");
- _G.stack.param_offset += 2;
- }
- if (_G.stack.pushed_de)
- {
- emit2 ("push de");
- _G.stack.param_offset += 2;
- }
+ if (bcInUse)
+ {
+ emit2 ("push bc");
+ _G.stack.param_offset += 2;
+ }
+
+ _G.stack.pushedBC = bcInUse;
+
+ if (deInUse)
+ {
+ emit2 ("push de");
+ _G.stack.param_offset += 2;
+ }
+
+ _G.stack.pushedDE = deInUse;
+#endif
/* adjust the stack for the function */
_G.stack.last = sym->stack;
- if (sym->stack)
+ if (sym->stack && IS_GB && sym->stack > -INT8MIN)
+ emit2 ("!enterxl", sym->stack);
+ else if (sym->stack)
emit2 ("!enterx", sym->stack);
else
emit2 ("!enter");
{
symbol *sym = OP_SYMBOL (IC_LEFT (ic));
- if (IS_ISR (sym->etype))
+ if (IFFUNC_ISISR (sym->type))
{
- wassert (0);
+ wassertl (0, "Tried to close an interrupt support function");
}
else
{
- if (SPEC_CRTCL (sym->etype))
+ if (IFFUNC_ISCRITICAL (sym->type))
emit2 ("!ei");
/* PENDING: calleeSave */
- /* if debug then send end of function */
- if (options.debug && currFunc)
- {
- debugLine = 1;
- emitcode ("", "C$%s$%d$%d$%d ==.",
- FileBaseName (ic->filename), currFunc->lastLine,
- ic->level, ic->block);
- if (IS_STATIC (currFunc->etype))
- emitcode ("", "XF%s$%s$0$0 ==.", moduleName, currFunc->name);
- else
- emitcode ("", "XG$%s$0$0 ==.", currFunc->name);
- debugLine = 0;
- }
- if (_G.stack.offset)
- emit2 ("!leavex", _G.stack.offset);
+ if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
+ {
+ emit2 ("!leavexl", _G.stack.offset);
+ }
+ else if (_G.stack.offset)
+ {
+ emit2 ("!leavex", _G.stack.offset);
+ }
else
- emit2 ("!leave");
+ {
+ emit2 ("!leave");
+ }
+
+#if CALLEE_SAVES
+ if (_G.stack.pushedDE)
+ {
+ emit2 ("pop de");
+ _G.stack.pushedDE = FALSE;
+ }
+
+ if (_G.stack.pushedDE)
+ {
+ emit2 ("pop bc");
+ _G.stack.pushedDE = FALSE;
+ }
+#endif
+
+ if (options.profile)
+ {
+ emit2 ("!profileexit");
+ }
+
- if (_G.stack.pushed_de)
- emit2 ("pop de");
- if (_G.stack.pushed_bc)
- emit2 ("pop bc");
/* Both baned and non-banked just ret */
emit2 ("ret");
/* PENDING: portability. */
emit2 ("__%s_end:", sym->rname);
}
- _G.flush_statics = 1;
+ _G.flushStatics = 1;
_G.stack.pushed = 0;
_G.stack.offset = 0;
}
static void
genRet (iCode * ic)
{
- char *l;
+ const char *l;
/* Errk. This is a hack until I can figure out how
to cause dehl to spill on a call */
int size, offset = 0;
{
if (IS_GB)
{
- emitcode ("ld", "de,%s", l);
+ emit2 ("ld de,%s", l);
}
else
{
- emitcode ("ld", "hl,%s", l);
+ emit2 ("ld hl,%s", l);
}
}
else
l = aopGet (AOP (IC_LEFT (ic)), offset,
FALSE);
if (strcmp (_fReturn[offset], l))
- emitcode ("ld", "%s,%s", _fReturn[offset++], l);
+ emit2 ("ld %s,%s", _fReturn[offset++], l);
}
}
}
if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
return FALSE;
- emitcode ("", "; genPlusIncr");
+ emitDebug ("; genPlusIncr");
icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
{
if (isLitWord (AOP (IC_LEFT (ic))))
{
- fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
+ fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
return TRUE;
}
if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
{
- fetchPair (resultId, AOP (IC_RIGHT (ic)));
- emitcode ("add", "hl,%s", getPairName (AOP (IC_LEFT (ic))));
- return TRUE;
+ if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
+ {
+ PAIR_ID freep = getFreePairId (ic);
+ if (freep != PAIR_INVALID)
+ {
+ fetchPair (freep, AOP (IC_RIGHT (ic)));
+ emit2 ("add hl,%s", _pairs[freep].name);
+ return TRUE;
+ }
+ }
+ else
+ {
+ fetchPair (resultId, AOP (IC_RIGHT (ic)));
+ emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
+ return TRUE;
+ }
}
if (icount > 5)
return FALSE;
{
if (icount > 2)
return FALSE;
- movLeft2Result (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0);
- movLeft2Result (IC_LEFT (ic), 1, IC_RESULT (ic), 1, 0);
+ movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
}
while (icount--)
{
- emitcode ("inc", "%s", getPairName (AOP (IC_RESULT (ic))));
+ emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
}
return TRUE;
}
+ if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
+ {
+ fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
+ commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
+ return TRUE;
+ }
+
/* if the literal value of the right hand side
is greater than 4 then it is not worth it */
if (icount > 4)
tlbl = newiTempLabel (NULL);
while (size--)
{
- emitcode ("inc", "%s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
+ emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
if (size)
{
emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
AOP_SIZE (IC_LEFT (ic)) > 1)
return FALSE;
+ /* If the result is in a register then we can load then increment.
+ */
+ if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
+ {
+ aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
+ while (icount--)
+ {
+ emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
+ }
+ return TRUE;
+ }
+
/* we can if the aops of the left & result match or
if they are in registers and the registers are the
same */
if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
{
while (icount--)
- emitcode ("inc", "%s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
+ {
+ emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
+ }
return TRUE;
}
/* if the result is a bit */
if (AOP_TYPE (result) == AOP_CRY)
{
- wassert (0);
+ wassertl (0, "Tried to write A into a bit");
}
else
{
}
}
+bool
+couldDestroyCarry (asmop *aop)
+{
+ if (aop)
+ {
+ if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static void
+shiftIntoPair (int idx, asmop *aop)
+{
+ PAIR_ID id = PAIR_INVALID;
+
+ wassertl (IS_Z80, "Only implemented for the Z80");
+ // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
+
+ switch (idx)
+ {
+ case 0:
+ id = PAIR_HL;
+ break;
+ case 1:
+ id = PAIR_DE;
+ _push (PAIR_DE);
+ break;
+ default:
+ wassertl (0, "Internal error - hit default case");
+ }
+
+ emitDebug ("; Shift into pair idx %u", idx);
+
+ if (id == PAIR_HL)
+ {
+ setupPair (PAIR_HL, aop, 0);
+ }
+ else
+ {
+ setupPair (PAIR_IY, aop, 0);
+ emit2 ("push iy");
+ emit2 ("pop %s", _pairs[id].name);
+ }
+
+ aop->type = AOP_PAIRPTR;
+ aop->aopu.aop_pairId = id;
+ _G.pairs[id].offset = 0;
+ _G.pairs[id].last_type = aop->type;
+}
+
+static void
+setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
+{
+ wassert (left && right);
+
+ if (IS_Z80)
+ {
+ if (couldDestroyCarry (right) && couldDestroyCarry (result))
+ {
+ shiftIntoPair (0, right);
+ shiftIntoPair (1, result);
+ }
+ else if (couldDestroyCarry (right))
+ {
+ shiftIntoPair (0, right);
+ }
+ else if (couldDestroyCarry (result))
+ {
+ shiftIntoPair (0, result);
+ }
+ else
+ {
+ /* Fine */
+ }
+ }
+}
+
/*-----------------------------------------------------------------*/
/* genPlus - generates code for addition */
/*-----------------------------------------------------------------*/
AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
{
/* Cant happen */
- wassert (0);
+ wassertl (0, "Tried to add two bits");
}
/* if left in bit space & right literal */
AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
{
/* Can happen I guess */
- wassert (0);
+ wassertl (0, "Tried to add a bit to a literal");
}
/* if I can do an increment instead
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));
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 */
char buffer[100];
sprintf (buffer, "#(%s + %s)", left, right);
- emitcode ("ld", "%s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
+ emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
goto release;
}
}
- if (isPair (AOP (IC_RIGHT (ic))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
+ if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
{
/* Fetch into HL then do the add */
+ PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
+ PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
+
spillPair (PAIR_HL);
+
+ if (left == PAIR_HL && right != PAIR_INVALID)
+ {
+ emit2 ("add hl,%s", _pairs[right].name);
+ goto release;
+ }
+ else if (right == PAIR_HL && left != PAIR_INVALID)
+ {
+ emit2 ("add hl,%s", _pairs[left].name);
+ goto release;
+ }
+ else if (right != PAIR_INVALID && right != PAIR_HL)
+ {
+ fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
+ emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
+ goto release;
+ }
+ else if (left != PAIR_INVALID && left != PAIR_HL)
+ {
+ fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
+ emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
+ goto release;
+ }
+ else
+ {
+ /* Can't do it */
+ }
+ }
+
+ if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
+ {
fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
- emitcode ("add", "hl,%s", getPairName (AOP (IC_RIGHT (ic))));
+ emit2 ("add hl,%s ; 2", getPairName (AOP (IC_RIGHT (ic))));
+ spillCached();
+ commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
goto release;
}
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;
+ }
}
+ setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
+
while (size--)
{
if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
{
- MOVA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
+ _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
if (offset == 0)
emit2 ("add a,%s",
aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
}
else
{
- MOVA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
+ _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
if (offset == 0)
emit2 ("add a,%s",
aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
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);
- emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
- emitcode ("jp", "np," LABEL_STR, tlbl->key + 100);
-
- emitcode ("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))))
{
while (icount--)
- emitcode ("dec", "%s", getPairName (AOP (IC_RESULT (ic))));
+ emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
return TRUE;
}
/* If result is a pair */
if (isPair (AOP (IC_RESULT (ic))))
{
- movLeft2Result (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0);
- movLeft2Result (IC_LEFT (ic), 1, IC_RESULT (ic), 1, 0);
+ movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
while (icount--)
- emitcode ("dec", "%s", getPairName (AOP (IC_RESULT (ic))));
+ emit2 ("dec %s", getPairName (AOP (IC_RESULT (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)
if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
{
while (icount--)
- emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
+ emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
return TRUE;
}
if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
{
- wassert (0);
+ wassertl (0, "Tried to subtract two bits");
goto release;
}
emit2 ("ld a,%s", _pairs[left].h);
emit2 ("sbc a,%s", _pairs[right].h);
- aopPut (AOP (IC_RESULT (ic)), "a", 1);
+ if ( AOP_SIZE (IC_RESULT (ic)) > 1)
+ {
+ aopPut (AOP (IC_RESULT (ic)), "a", 1);
+ }
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;
+ }
+ }
+
+ setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
+
+ /* if literal, add a,#-lit, else normal subb */
+ while (size--)
+ {
+ _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
+ if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
+ {
+ if (!offset)
+ emit2 ("sub a,%s",
+ aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
+ else
+ emit2 ("sbc a,%s",
+ aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
+ }
+ else
+ {
+ /* first add without previous c */
+ if (!offset)
+ emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
+ else
+ emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
+ }
+ aopPut (AOP (IC_RESULT (ic)), "a", offset++);
+ }
+
+ if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
+ AOP_SIZE (IC_LEFT (ic)) == 3 &&
+ !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
+ {
+ wassertl (0, "Tried to subtract on a long pointer");
+ }
+
+release:
+ freeAsmop (IC_LEFT (ic), NULL, ic);
+ freeAsmop (IC_RIGHT (ic), NULL, ic);
+ freeAsmop (IC_RESULT (ic), NULL, ic);
+}
+
+/*-----------------------------------------------------------------*/
+/* genMult - generates code for multiplication */
+/*-----------------------------------------------------------------*/
+static void
+genMult (iCode * ic)
+{
+ int val;
+ int count, i;
+ /* If true then the final operation should be a subtract */
+ bool active = FALSE;
+
+ /* Shouldn't occur - all done through function calls */
+ aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
+ aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
+ aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
+
+ if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
+ AOP_SIZE (IC_RIGHT (ic)) > 2 ||
+ AOP_SIZE (IC_RESULT (ic)) > 2)
+ {
+ wassertl (0, "Multiplication is handled through support function calls");
+ }
+
+ /* Swap left and right such that right is a literal */
+ if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
+ {
+ operand *t = IC_RIGHT (ic);
+ IC_RIGHT (ic) = IC_LEFT (ic);
+ IC_LEFT (ic) = t;
+ }
+
+ wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
+
+ val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
+ // wassertl (val > 0, "Multiply must be positive");
+ wassertl (val != 1, "Can't multiply by 1");
+
+ if (IS_Z80) {
+ _push (PAIR_DE);
+ }
+
+ if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
+ {
+ emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
+ emit2 ("ld a,e");
+ emit2 ("rlc a");
+ emit2 ("sbc a,a");
+ emit2 ("ld d,a");
+ }
+ else
+ {
+ fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
}
- /* if literal, add a,#-lit, else normal subb */
- while (size--)
+ i = val;
+
+ /* Fully unroled version of mul.s. Not the most efficient.
+ */
+ for (count = 0; count < 16; count++)
{
- MOVA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
- if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
- {
- if (!offset)
- emitcode ("sub", "a,%s",
- aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
- else
- emitcode ("sbc", "a,%s",
- aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
- }
- else
- {
- /* first add without previous c */
- if (!offset)
- emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
- else
- emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
- }
- aopPut (AOP (IC_RESULT (ic)), "a", offset++);
+ if (count != 0 && active)
+ {
+ emit2 ("add hl,hl");
+ }
+ if (i & 0x8000U)
+ {
+ if (active == FALSE)
+ {
+ emit2 ("ld l,e");
+ emit2 ("ld h,d");
+ }
+ else
+ {
+ emit2 ("add hl,de");
+ }
+ active = TRUE;
+ }
+ i <<= 1;
}
- if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
- AOP_SIZE (IC_LEFT (ic)) == 3 &&
- !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
- wassert (0);
+ spillCached();
+
+ if (IS_Z80)
+ {
+ _pop (PAIR_DE);
+ }
+
+ commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
-release:
freeAsmop (IC_LEFT (ic), NULL, ic);
freeAsmop (IC_RIGHT (ic), NULL, ic);
freeAsmop (IC_RESULT (ic), NULL, ic);
}
-/*-----------------------------------------------------------------*/
-/* genMult - generates code for multiplication */
-/*-----------------------------------------------------------------*/
-static void
-genMult (iCode * ic)
-{
- /* Shouldn't occur - all done through function calls */
- wassert (0);
-}
-
/*-----------------------------------------------------------------*/
/* genDiv - generates code for division */
/*-----------------------------------------------------------------*/
genDiv (iCode * ic)
{
/* Shouldn't occur - all done through function calls */
- wassert (0);
+ wassertl (0, "Division is handled through support function calls");
}
/*-----------------------------------------------------------------*/
{
inst = "nc";
}
+ else if (!strcmp (jval, "m"))
+ {
+ inst = "m";
+ }
+ else if (!strcmp (jval, "p"))
+ {
+ inst = "p";
+ }
else
{
/* The buffer contains the bit on A that we should test */
{
inst = "c";
}
+ else if (!strcmp (jval, "m"))
+ {
+ inst = "p";
+ }
+ else if (!strcmp (jval, "p"))
+ {
+ inst = "m";
+ }
else
{
/* The buffer contains the bit on A that we should test */
/* Z80 can do a conditional long jump */
if (!strcmp (jval, "a"))
{
- emitcode ("or", "a,a");
+ emit2 ("or a,a");
}
else if (!strcmp (jval, "c"))
{
else if (!strcmp (jval, "nc"))
{
}
+ else if (!strcmp (jval, "m"))
+ {
+ }
+ else if (!strcmp (jval, "p"))
+ {
+ }
else
{
- emitcode ("bit", "%s,a", jval);
+ emit2 ("bit %s,a", jval);
}
emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
ic->generated = 1;
}
+#if DISABLED
static const char *
_getPairIdName (PAIR_ID id)
{
return _pairs[id].name;
}
+#endif
-/** Generic compare for > or <
- */
-static void
-genCmp (operand * left, operand * right,
- operand * result, iCode * ifx, int sign)
-{
- int size, offset = 0;
- unsigned long lit = 0L;
- bool swap_sense = FALSE;
-
- /* if left & right are bit variables */
- if (AOP_TYPE (left) == AOP_CRY &&
- AOP_TYPE (right) == AOP_CRY)
- {
- /* Cant happen on the Z80 */
- wassert (0);
- }
- else
- {
- /* subtract right from left if at the
- end the carry flag is set then we know that
- left is greater than right */
- size = max (AOP_SIZE (left), AOP_SIZE (right));
-
+#if OLD
/* if unsigned char cmp with lit, just compare */
if ((size == 1) &&
(AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
{
- emitcode ("ld", "a,%s", aopGet (AOP (left), offset, FALSE));
+ emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
if (sign)
{
emit2 ("xor a,!immedbyte", 0x80);
emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
}
else
- emitcode ("cp", "%s", aopGet (AOP (right), offset, FALSE));
- }
+ 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 (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
+ {
+ setupPair (PAIR_HL, AOP (left), 0);
+ aopGet (AOP(right), LSB, FALSE);
+
+ while (size--)
+ {
+ if (size == 0 && sign)
+ {
+ // Highest byte when signed needs the bits flipped
+ // Save the flags
+ emit2 ("push af");
+ emit2 ("ld a,(hl)");
+ emit2 ("xor #0x80");
+ emit2 ("ld l,a");
+ emit2 ("ld a,%d(iy)", offset);
+ emit2 ("xor #0x80");
+ emit2 ("ld h,a");
+ emit2 ("pop af");
+ emit2 ("ld a,l");
+ emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
+ }
+ else
+ {
+ emit2 ("ld a,(hl)");
+ emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
+ }
+
+ if (size != 0)
+ {
+ emit2 ("inc hl");
+ }
+ offset++;
+ }
+ spillPair (PAIR_HL);
+ spillPair (PAIR_IY);
+ }
else
{
- /* Special cases:
- On the GB:
- If the left or the right is a lit:
- Load -lit into HL, add to right via, check sense.
- */
- if (size == 2 && (AOP_TYPE (right) == AOP_LIT || AOP_TYPE (left) == AOP_LIT))
- {
- PAIR_ID id = PAIR_DE;
- asmop *lit = AOP (right);
- asmop *op = AOP (left);
- swap_sense = TRUE;
-
- if (AOP_TYPE (left) == AOP_LIT)
- {
- swap_sense = FALSE;
- lit = AOP (left);
- op = AOP (right);
- }
- if (sign)
- {
- emit2 ("ld e,%s", aopGet (op, 0, 0));
- emit2 ("ld a,%s", aopGet (op, 1, 0));
- emit2 ("xor a,!immedbyte", 0x80);
- emit2 ("ld d,a");
- }
- else
- {
- id = getPairId (op);
- if (id == PAIR_INVALID)
- {
- fetchPair (PAIR_DE, op);
- id = PAIR_DE;
- }
- }
- spillPair (PAIR_HL);
- emit2 ("ld hl,%s", fetchLitSpecial (lit, TRUE, sign));
- emit2 ("add hl,%s", _getPairIdName (id));
- goto release;
- }
if (AOP_TYPE (right) == AOP_LIT)
{
lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
if (!sign)
{
/* No sign so it's always false */
- CLRC;
+ _clearCarry();
}
else
{
/* Just load in the top most bit */
- MOVA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
+ _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
{
genIfxJump (ifx, "7");
return;
}
else
- emitcode ("rlc", "a");
+ emit2 ("rlc a");
}
goto release;
}
}
+
if (sign)
{
/* First setup h and l contaning the top most bytes XORed */
}
else
{
- emitcode ("ld", "a,%s", aopGet (AOP (left), size - 1, FALSE));
+ emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
emit2 ("xor a,!immedbyte", 0x80);
- emitcode ("ld", "%s,a", _fTmp[0]);
+ emit2 ("ld %s,a", _fTmp[0]);
fDidXor = TRUE;
}
if (AOP_TYPE (right) == AOP_LIT)
}
else
{
- emitcode ("ld", "a,%s", aopGet (AOP (right), size - 1, FALSE));
+ emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
emit2 ("xor a,!immedbyte", 0x80);
- emitcode ("ld", "%s,a", _fTmp[1]);
+ emit2 ("ld %s,a", _fTmp[1]);
fDidXor = TRUE;
}
- if (!fDidXor)
- CLRC;
- }
- else
- {
- CLRC;
}
while (size--)
{
/* Do a long subtract */
if (!sign || size)
{
- MOVA (aopGet (AOP (left), offset, FALSE));
+ _moveA (aopGet (AOP (left), offset, FALSE));
}
if (sign && size == 0)
{
- emitcode ("ld", "a,%s", _fTmp[0]);
- emitcode ("sbc", "a,%s", _fTmp[1]);
+ emit2 ("ld a,%s", _fTmp[0]);
+ emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
}
else
{
/* Subtract through, propagating the carry */
- emitcode ("sbc", "a,%s ; 2", aopGet (AOP (right), offset++, FALSE));
+ emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
+ offset++;
}
}
}
}
+#endif
+
+/** Generic compare for > or <
+ */
+static void
+genCmp (operand * left, operand * right,
+ operand * result, iCode * ifx, int sign)
+{
+ int size, offset = 0;
+ unsigned long lit = 0L;
+ bool swap_sense = FALSE;
+
+ /* if left & right are bit variables */
+ if (AOP_TYPE (left) == AOP_CRY &&
+ AOP_TYPE (right) == AOP_CRY)
+ {
+ /* Cant happen on the Z80 */
+ wassertl (0, "Tried to compare two bits");
+ }
+ else
+ {
+ /* Do a long subtract of right from left. */
+ size = max (AOP_SIZE (left), AOP_SIZE (right));
+
+ if (size > 1 && 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--)
+ {
+ 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);
+ goto release;
+ }
+
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
+ /* optimize if(x < 0) or if(x >= 0) */
+ if (lit == 0)
+ {
+ if (!sign)
+ {
+ /* No sign so it's always false */
+ _clearCarry();
+ }
+ else
+ {
+ /* Just load in the top most bit */
+ _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
+ if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
+ {
+ genIfxJump (ifx, "7");
+ return;
+ }
+ else
+ {
+ if (!sign)
+ {
+ emit2 ("rlc a");
+ }
+ if (ifx)
+ {
+ genIfxJump (ifx, swap_sense ? "c" : "nc");
+ return;
+ }
+ }
+ }
+ goto release;
+ }
+ }
+
+ while (size--)
+ {
+ _moveA (aopGet (AOP (left), offset, FALSE));
+ /* Subtract through, propagating the carry */
+ emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
+ offset++;
+ }
+ }
release:
if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
{
+ if (sign)
+ {
+ /* Shift the sign bit up into carry */
+ emit2 ("rlca");
+ }
outBitCLong (result, swap_sense);
}
else
ifx conditional branch then generate
code a little differently */
if (ifx)
- genIfxJump (ifx, swap_sense ? "nc" : "c");
+ {
+ if (sign)
+ {
+ if (IS_GB)
+ {
+ emit2 ("rlca");
+ genIfxJump (ifx, swap_sense ? "nc" : "c");
+ }
+ else
+ {
+ genIfxJump (ifx, swap_sense ? "p" : "m");
+ }
+ }
+ else
+ {
+ genIfxJump (ifx, swap_sense ? "nc" : "c");
+ }
+ }
else
- outBitCLong (result, swap_sense);
+ {
+ if (sign)
+ {
+ /* Shift the sign bit up into carry */
+ emit2 ("rlca");
+ }
+ outBitCLong (result, swap_sense);
+ }
/* leave the result in acc */
}
}
{
if (lit == 0)
{
- emitcode ("ld", "a,%s", aopGet (AOP (left), offset, FALSE));
+ emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
if (size > 1)
{
- size--;
- offset++;
- while (size--)
+ while (--size)
{
- emitcode ("or", "a,%s", aopGet (AOP (left), offset, FALSE));
+ emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
}
}
else
{
- emitcode ("or", "a,a");
+ emit2 ("or a,a");
}
emit2 ("jp nz,!tlabel", lbl->key + 100);
}
{
while (size--)
{
- emitcode ("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)
- emitcode ("or", "a,a");
+ emit2 ("or a,a");
else
- emitcode ("cp", "a,%s", aopGet (AOP (right), offset, FALSE));
+ emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
emit2 ("jp nz,!tlabel", lbl->key + 100);
offset++;
}
{
while (size--)
{
- MOVA (aopGet (AOP (left), offset, FALSE));
+ _moveA (aopGet (AOP (left), offset, FALSE));
if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
/* PENDING */
emit2 ("jp nz,!tlabel", lbl->key + 100);
else
{
- emitcode ("cp", "%s ; 4", aopGet (AOP (right), offset, FALSE));
+ emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
emit2 ("jp nz,!tlabel", lbl->key + 100);
}
offset++;
/* PENDING: is this required? */
while (size--)
{
- MOVA (aopGet (AOP (right), offset, FALSE));
- emitcode ("cp", "%s ; 5", aopGet (AOP (left), offset, FALSE));
+ _moveA (aopGet (AOP (right), offset, FALSE));
+ emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
offset++;
}
emit2 ("ld a,!one");
emit2 ("!shortjp !tlabel", tlbl->key + 100);
emitLabel (lbl->key + 100);
- emitcode ("xor", "a,a");
+ emit2 ("xor a,a");
emitLabel (tlbl->key + 100);
}
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", 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.
if (AOP_TYPE (left) == AOP_CRY &&
((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
{
- wassert (0);
+ wassertl (0, "Tried to compare two bits");
}
else
{
tlbl = newiTempLabel (NULL);
+ emitDebug(";1");
gencjneshort (left, right, tlbl);
if (IC_TRUE (ifx))
{
+ emitDebug(";2");
emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
emitLabel (tlbl->key + 100);
}
{
/* PENDING: do this better */
symbol *lbl = newiTempLabel (NULL);
+ emitDebug(";3");
emit2 ("!shortjp !tlabel", lbl->key + 100);
emitLabel (tlbl->key + 100);
emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
if (AOP_TYPE (left) == AOP_CRY &&
((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
{
- wassert (0);
+ wassertl (0, "Tried to compare a bit to either a literal or another bit");
}
else
{
+ emitDebug(";4");
+
gencjne (left, right, newiTempLabel (NULL));
if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
{
}
if (ifx)
{
+ emitDebug(";5");
genIfxJump (ifx, "a");
goto release;
}
then put the result in place */
if (AOP_TYPE (result) != AOP_CRY)
{
+ emitDebug(";6");
outAcc (result);
}
/* leave the result in acc */
if (AOP_TYPE (left) == AOP_CRY &&
AOP_TYPE (right) == AOP_CRY)
{
- wassert (0);
+ wassertl (0, "Tried to and two bits");
}
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);
}
if (AOP_TYPE (left) == AOP_CRY &&
AOP_TYPE (right) == AOP_CRY)
{
- wassert (0);
+ wassertl (0, "Tried to OR two bits");
}
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);
}
aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
-#ifdef DEBUG_TYPE
- emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
- AOP_TYPE (result),
- AOP_TYPE (left), AOP_TYPE (right));
- emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
- AOP_SIZE (result),
- AOP_SIZE (left), AOP_SIZE (right));
-#endif
-
/* if left is a literal & right is not then exchange them */
if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
AOP_NEEDSACC (left))
if (AOP_TYPE (left) == AOP_CRY)
{
- wassert (0);
+ wassertl (0, "Tried to perform an AND with a bit as an operand");
goto release;
}
(AOP_TYPE (result) == AOP_CRY) &&
(AOP_TYPE (left) != AOP_CRY))
{
- int posbit = isLiteralBit (lit);
- /* left & 2^n */
- if (posbit)
- {
- posbit--;
- MOVA (aopGet (AOP (left), posbit >> 3, FALSE));
- // bit = left & 2^n
- if (size)
- {
- wassert (0);
- emitcode ("mov", "c,acc.%d", posbit & 0x07);
- }
- // if(left & 2^n)
- else
- {
- if (ifx)
- {
- sprintf (buffer, "%d", posbit & 0x07);
- genIfxJump (ifx, buffer);
- }
- else
- {
- wassert (0);
- }
- goto release;
- }
- }
- else
- {
- symbol *tlbl = newiTempLabel (NULL);
- int sizel = AOP_SIZE (left);
- if (size)
- {
- wassert (0);
- emitcode ("setb", "c");
- }
- while (sizel--)
- {
- if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
- {
- MOVA (aopGet (AOP (left), offset, FALSE));
- // byte == 2^n ?
- if ((posbit = isLiteralBit (bytelit)) != 0)
- {
- wassert (0);
- emitcode ("jb", "acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
- }
- else
- {
- if (bytelit != 0x0FFL)
- emitcode ("and", "a,%s",
- aopGet (AOP (right), offset, FALSE));
- else
- /* For the flags */
- emit2 ("or a,a");
- emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
- }
- }
+ symbol *tlbl = newiTempLabel (NULL);
+ int sizel = AOP_SIZE (left);
+ if (size)
+ {
+ /* PENDING: Test case for this. */
+ emit2 ("scf");
+ }
+ while (sizel--)
+ {
+ if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
+ {
+ _moveA (aopGet (AOP (left), offset, FALSE));
+ if (bytelit != 0x0FFL)
+ {
+ emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
+ }
+ else
+ {
+ /* For the flags */
+ emit2 ("or a,a");
+ }
+ emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
+ }
offset++;
- }
- // bit = left & literal
- if (size)
- {
- emitcode ("clr", "c");
- emit2 ("!tlabeldef", tlbl->key + 100);
- }
- // if(left & literal)
- else
- {
- if (ifx)
- jmpTrueOrFalse (ifx, tlbl);
- goto release;
- }
- }
+ }
+ // bit = left & literal
+ if (size)
+ {
+ emit2 ("clr c");
+ emit2 ("!tlabeldef", tlbl->key + 100);
+ }
+ // if(left & literal)
+ else
+ {
+ if (ifx)
+ {
+ jmpTrueOrFalse (ifx, tlbl);
+ }
+ goto release;
+ }
outBitC (result);
goto release;
}
else
{
if (bytelit == 0)
- aopPut (AOP (result), zero, offset);
+ aopPut (AOP (result), "!zero", offset);
else
{
- MOVA (aopGet (AOP (left), offset, FALSE));
- emitcode ("and", "a,%s",
+ _moveA (aopGet (AOP (left), offset, FALSE));
+ emit2 ("and a,%s",
aopGet (AOP (right), offset, FALSE));
aopPut (AOP (left), "a", offset);
}
{
if (AOP_TYPE (left) == AOP_ACC)
{
- wassert (0);
+ wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
}
else
{
- MOVA (aopGet (AOP (left), offset, FALSE));
- emitcode ("and", "a,%s",
+ _moveA (aopGet (AOP (left), offset, FALSE));
+ emit2 ("and a,%s",
aopGet (AOP (right), offset, FALSE));
aopPut (AOP (left), "a", offset);
}
// left & result in different registers
if (AOP_TYPE (result) == AOP_CRY)
{
- wassert (0);
+ wassertl (0, "Tried to AND where the result is in carry");
}
else
{
}
else if (bytelit == 0)
{
- aopPut (AOP (result), zero, offset);
+ aopPut (AOP (result), "!zero", offset);
continue;
}
}
// faster than result <- left, anl result,right
// and better if result is SFR
if (AOP_TYPE (left) == AOP_ACC)
- emitcode ("and", "a,%s", aopGet (AOP (right), offset, FALSE));
+ emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
else
{
- MOVA (aopGet (AOP (left), offset, FALSE));
- emitcode ("and", "a,%s",
+ _moveA (aopGet (AOP (left), offset, FALSE));
+ emit2 ("and a,%s",
aopGet (AOP (right), offset, FALSE));
}
aopPut (AOP (result), "a", offset);
operand *left, *right, *result;
int size, offset = 0;
unsigned long lit = 0L;
+ int bytelit = 0;
aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
-#if 1
- emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
- AOP_TYPE (result),
- AOP_TYPE (left), AOP_TYPE (right));
- emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
- AOP_SIZE (result),
- AOP_SIZE (left), AOP_SIZE (right));
-#endif
-
/* if left is a literal & right is not then exchange them */
if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
AOP_NEEDSACC (left))
if (AOP_TYPE (left) == AOP_CRY)
{
- wassert (0);
+ wassertl (0, "Tried to OR where left is a bit");
goto release;
}
+ // if(val | 0xZZ) - size = 0, ifx != FALSE -
+ // bit = val | 0xZZ - size = 1, ifx = FALSE -
if ((AOP_TYPE (right) == AOP_LIT) &&
(AOP_TYPE (result) == AOP_CRY) &&
(AOP_TYPE (left) != AOP_CRY))
{
- wassert (0);
+ symbol *tlbl = newiTempLabel (NULL);
+ int sizel = AOP_SIZE (left);
+
+ if (size)
+ {
+ wassertl (0, "Result is assigned to a bit");
+ }
+ /* PENDING: Modeled after the AND code which is inefficent. */
+ while (sizel--)
+ {
+ bytelit = (lit >> (offset * 8)) & 0x0FFL;
+
+ _moveA (aopGet (AOP (left), offset, FALSE));
+ /* OR with any literal is the same as OR with itself. */
+ emit2 ("or a,a");
+ emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
+
+ offset++;
+ }
+ if (ifx)
+ {
+ jmpTrueOrFalse (ifx, tlbl);
+ }
goto release;
}
continue;
else
{
- MOVA (aopGet (AOP (left), offset, FALSE));
- emitcode ("or", "a,%s",
+ _moveA (aopGet (AOP (left), offset, FALSE));
+ emit2 ("or a,%s",
aopGet (AOP (right), offset, FALSE));
aopPut (AOP (result), "a", offset);
}
else
{
if (AOP_TYPE (left) == AOP_ACC)
- emitcode ("or", "a,%s", aopGet (AOP (right), offset, FALSE));
+ emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
else
{
- MOVA (aopGet (AOP (left), offset, FALSE));
- emitcode ("or", "a,%s",
+ _moveA (aopGet (AOP (left), offset, FALSE));
+ emit2 ("or a,%s",
aopGet (AOP (right), offset, FALSE));
aopPut (AOP (result), "a", offset);
}
// left & result in different registers
if (AOP_TYPE (result) == AOP_CRY)
{
- wassert (0);
+ wassertl (0, "Result of OR is in a bit");
}
else
for (; (size--); offset++)
// faster than result <- left, anl result,right
// and better if result is SFR
if (AOP_TYPE (left) == AOP_ACC)
- emitcode ("or", "a,%s", aopGet (AOP (right), offset, FALSE));
+ emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
else
{
- MOVA (aopGet (AOP (left), offset, FALSE));
- emitcode ("or", "a,%s",
+ _moveA (aopGet (AOP (left), offset, FALSE));
+ emit2 ("or a,%s",
aopGet (AOP (right), offset, FALSE));
}
aopPut (AOP (result), "a", offset);
if (AOP_TYPE (left) == AOP_CRY)
{
- wassert (0);
+ wassertl (0, "Tried to XOR a bit");
goto release;
}
+ // if(val & 0xZZ) - size = 0, ifx != FALSE -
+ // bit = val & 0xZZ - size = 1, ifx = FALSE -
if ((AOP_TYPE (right) == AOP_LIT) &&
(AOP_TYPE (result) == AOP_CRY) &&
(AOP_TYPE (left) != AOP_CRY))
{
- wassert (0);
+ symbol *tlbl = newiTempLabel (NULL);
+ int sizel = AOP_SIZE (left);
+
+ if (size)
+ {
+ /* PENDING: Test case for this. */
+ wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
+ }
+ while (sizel--)
+ {
+ _moveA (aopGet (AOP (left), offset, FALSE));
+ emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
+ emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
+ offset++;
+ }
+ if (ifx)
+ {
+ jmpTrueOrFalse (ifx, tlbl);
+ }
+ else
+ {
+ wassertl (0, "Result of XOR was destined for a bit");
+ }
goto release;
}
continue;
else
{
- MOVA (aopGet (AOP (right), offset, FALSE));
- emitcode ("xor", "a,%s",
+ _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)
- emitcode ("xor", "a,%s", aopGet (AOP (right), offset, FALSE));
+ {
+ emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
+ }
else
{
- MOVA (aopGet (AOP (right), offset, FALSE));
- emitcode ("xor", "a,%s",
+ _moveA (aopGet (AOP (right), offset, FALSE));
+ emit2 ("xor a,%s",
aopGet (AOP (left), offset, FALSE));
aopPut (AOP (result), "a", 0);
}
// left & result in different registers
if (AOP_TYPE (result) == AOP_CRY)
{
- wassert (0);
+ wassertl (0, "Result of XOR is in a bit");
}
else
for (; (size--); offset++)
}
// faster than result <- left, anl result,right
// and better if result is SFR
- if (AOP_TYPE (left) == AOP_ACC)
- emitcode ("xor", "a,%s", aopGet (AOP (right), offset, FALSE));
+ if (AOP_TYPE (left) == AOP_ACC)
+ {
+ emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
+ }
else
{
- MOVA (aopGet (AOP (right), offset, FALSE));
- emitcode ("xor", "a,%s",
+ _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);
}
static void
genInline (iCode * ic)
{
- char buffer[MAX_INLINEASM];
- char *bp = buffer;
- char *bp1 = buffer;
+ char *buffer, *bp, *bp1;
- inLine += (!options.asmpeep);
+ _G.lines.isInline += (!options.asmpeep);
+
+ buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
strcpy (buffer, IC_INLINE (ic));
/* emit each line as a code */
if (*bp == '\n')
{
*bp++ = '\0';
- emitcode (bp1, "");
+ emit2 (bp1);
bp1 = bp;
}
else
bp++;
*bp = '\0';
bp++;
- emitcode (bp1, "");
+ emit2 (bp1);
bp1 = bp;
}
else
}
}
if (bp1 != bp)
- emitcode (bp1, "");
- /* emitcode("",buffer); */
- inLine -= (!options.asmpeep);
+ emit2 (bp1);
+ _G.lines.isInline -= (!options.asmpeep);
+
}
/*-----------------------------------------------------------------*/
/* genRLC - generate code for rotate left with carry */
/*-----------------------------------------------------------------*/
static void
-genRLC (iCode * ic)
+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)
{
- wassert (0);
+ 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++;
+ }
}
/*-----------------------------------------------------------------*/
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 <= 4)
{
- 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;
- 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);
- emitcode ("or", "a,a");
- offset = size;
- while (size--)
- {
- l = aopGet (AOP (result), --offset, FALSE);
- emitcode ("rr", "%s", l);
- }
- if (shCount > 1)
- {
- emitLabel (tlbl1->key + 100);
- emitcode ("dec", "a");
- emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
- }
+ emitLabel (tlbl1->key + 100);
+ emit2 ("dec a");
+ emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
}
}
int size = 2;
int offset = 0;
symbol *tlbl, *tlbl1;
- char *l;
+ const char *l;
tlbl = newiTempLabel (NULL);
tlbl1 = newiTempLabel (NULL);
emitLabel (tlbl->key + 100);
}
- emitcode ("or", "a,a");
while (size--)
{
- l = aopGet (AOP (result), offset++, FALSE);
- emitcode ("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)
{
emitLabel (tlbl1->key + 100);
- emitcode ("dec", "a");
+ emit2 ("dec a");
emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
}
}
case 0:
break;
case 1:
- emitcode ("rl", "a");
+ emit2 ("sla a");
break;
case 2:
- emitcode ("rl", "a");
- emitcode ("rl", "a");
+ emit2 ("sla a");
+ emit2 ("rl a");
break;
case 3:
- emitcode ("rl", "a");
- emitcode ("rl", "a");
- emitcode ("rl", "a");
+ emit2 ("sla a");
+ emit2 ("rl a");
+ emit2 ("rl a");
break;
case 4:
- emitcode ("rl", "a");
- emitcode ("rl", "a");
- emitcode ("rl", "a");
- emitcode ("rl", "a");
+ emit2 ("sla a");
+ emit2 ("rl a");
+ emit2 ("rl a");
+ emit2 ("rl a");
break;
case 5:
- emitcode ("rr", "a");
- emitcode ("rr", "a");
- emitcode ("rr", "a");
+ emit2 ("srl a");
+ emit2 ("rr a");
+ emit2 ("rr a");
break;
case 6:
- emitcode ("rr", "a");
- emitcode ("rr", "a");
+ emit2 ("srl a");
+ emit2 ("rr a");
break;
case 7:
- emitcode ("rr", "a");
+ emit2 ("srl a");
break;
}
}
static void
AccLsh (int shCount)
{
+ static const unsigned char SLMask[] =
+ {
+ 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
+ };
+
if (shCount != 0)
{
if (shCount == 1)
{
- emitcode ("add", "a,a");
+ emit2 ("add a,a");
}
else if (shCount == 2)
{
- emitcode ("add", "a,a");
- emitcode ("add", "a,a");
+ emit2 ("add a,a");
+ emit2 ("add a,a");
}
else
{
shiftL1Left2Result (operand * left, int offl,
operand * result, int offr, int shCount)
{
- char *l;
+ const char *l;
l = aopGet (AOP (left), offl, FALSE);
- MOVA (l);
+ _moveA (l);
/* shift left accumulator */
AccLsh (shCount);
aopPut (AOP (result), "a", offr);
if (shCount)
{
movLeft2Result (left, LSB, result, MSB16, 0);
- aopPut (AOP (result), zero, 0);
- shiftL1Left2Result (left, MSB16, result, MSB16, shCount);
+ aopPut (AOP (result), "!zero", 0);
+ shiftL1Left2Result (left, LSB, result, MSB16, shCount);
}
else
{
movLeft2Result (left, LSB, result, MSB16, 0);
- aopPut (AOP (result), zero, 0);
+ aopPut (AOP (result), "!zero", 0);
}
}
else
{
- aopPut (AOP (result), zero, LSB);
+ aopPut (AOP (result), "!zero", LSB);
}
}
/* 1 <= shCount <= 7 */
size = getSize (operandType (result));
-#if VIEW_SIZE
- emitcode ("; shift left ", "result %d, left %d", size,
- AOP_SIZE (left));
-#endif
-
/* I suppose that the left size >= result size */
if (shCount == 0)
{
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)
genlshTwo (result, left, shCount);
break;
case 4:
- wassert (0);
+ wassertl (0, "Shifting of longs is currently unsupported");
break;
default:
wassert (0);
genLeftShift (iCode * ic)
{
int size, offset;
- char *l;
+ const char *l;
symbol *tlbl, *tlbl1;
operand *left, *right, *result;
count in B : Note: we take only the lower order byte since
shifting more that 32 bits make no sense anyway, ( the largest
size of an object can be only 32 bits ) */
- emitcode ("ld", "a,%s", aopGet (AOP (right), 0, FALSE));
- emitcode ("inc", "a");
+ emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
+ emit2 ("inc a");
freeAsmop (right, NULL, ic);
aopOp (left, ic, FALSE, FALSE);
aopOp (result, ic, FALSE, FALSE);
/* now move the left to the result if they are not the
same */
-#if 1
+
if (!sameRegs (AOP (left), AOP (result)))
{
offset++;
}
}
-#else
- size = AOP_SIZE (result);
- offset = 0;
- while (size--)
- {
- l = aopGet (AOP (left), offset, FALSE);
- aopPut (AOP (result), l, offset);
- offset++;
- }
-#endif
-
tlbl = newiTempLabel (NULL);
size = AOP_SIZE (result);
emit2 ("!shortjp !tlabel", tlbl1->key + 100);
emitLabel (tlbl->key + 100);
l = aopGet (AOP (result), offset, FALSE);
- emitcode ("or", "a,a");
+
while (size--)
{
- l = aopGet (AOP (result), offset++, FALSE);
- emitcode ("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);
- emitcode ("dec", "a");
+ emit2 ("dec a");
emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
freeAsmop (left, NULL, 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);
- char *l;
+ const char *l;
wassert (size == 1);
wassert (shCount < 8);
l = aopGet (AOP (left), 0, FALSE);
+
if (AOP (result)->type == AOP_REG)
{
aopPut (AOP (result), l, 0);
l = aopGet (AOP (result), 0, FALSE);
while (shCount--)
- emitcode ("srl", "%s", l);
+ {
+ emit2 ("%s %s", is_signed ? "sra" : "srl", l);
+ }
}
else
{
- MOVA (l);
+ _moveA (l);
while (shCount--)
{
- emitcode ("srl", "a");
+ emit2 ("%s a", is_signed ? "sra" : "srl");
}
aopPut (AOP (result), "a", 0);
}
static void
AccRsh (int shCount)
{
+ static const unsigned char SRMask[] =
+ {
+ 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
+ };
+
if (shCount != 0)
{
/* rotate right accumulator */
operand * result, int offr,
int shCount, int sign)
{
- MOVA (aopGet (AOP (left), offl, FALSE));
+ _moveA (aopGet (AOP (left), offl, FALSE));
if (sign)
{
- wassert (0);
+ while (shCount--)
+ {
+ emit2 ("%s a", sign ? "sra" : "srl");
+ }
}
else
{
{
movLeft2Result (left, MSB16, result, LSB, sign);
}
- aopPut (AOP (result), zero, 1);
+ if (sign)
+ {
+ /* Sign extend the result */
+ _moveA(aopGet (AOP (result), 0, FALSE));
+ emit2 ("rlc a");
+ emit2 ("sbc a,a");
+
+ aopPut (AOP (result), ACC_NAME, MSB16);
+ }
+ else
+ {
+ aopPut (AOP (result), "!zero", 1);
+ }
}
/* 1 <= shCount <= 7 */
else
genRightShiftLiteral (operand * left,
operand * right,
operand * result,
- iCode * ic)
+ iCode * ic,
+ int sign)
{
int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
int size;
size = getSize (operandType (result));
- emitcode ("; shift right ", "result %d, left %d", size,
- AOP_SIZE (left));
-
/* I suppose that the left size >= result size */
if (shCount == 0)
{
else if (shCount >= (size * 8))
while (size--)
- aopPut (AOP (result), zero, size);
+ aopPut (AOP (result), "!zero", size);
else
{
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);
operand *right, *left, *result;
sym_link *retype;
int size, offset, first = 1;
- char *l;
+ const char *l;
bool is_signed;
symbol *tlbl, *tlbl1;
as efficiently as possible */
if (AOP_TYPE (right) == AOP_LIT)
{
- genRightShiftLiteral (left, right, result, ic);
+ genRightShiftLiteral (left, right, result, ic, is_signed);
return;
}
}
}
- emitcode ("ld", "a,%s", aopGet (AOP (right), 0, FALSE));
- emitcode ("inc", "a");
+ emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
+ emit2 ("inc a");
freeAsmop (right, NULL, ic);
tlbl = newiTempLabel (NULL);
l = aopGet (AOP (result), offset--, FALSE);
if (first)
{
- if (is_signed)
- emitcode ("sra", "%s", l);
- else
- emitcode ("srl", "%s", l);
+ emit2 ("%s %s", is_signed ? "sra" : "srl", l);
first = 0;
}
else
- emitcode ("rr", "%s", l);
+ {
+ emit2 ("rr %s", l);
+ }
}
emitLabel (tlbl1->key + 100);
- emitcode ("dec", "a");
+ emit2 ("dec a");
emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
freeAsmop (left, NULL, ic);
aopOp (left, ic, FALSE, FALSE);
aopOp (result, ic, FALSE, FALSE);
- if (isPair (AOP (left)) && AOP_SIZE (result) == 1)
+ size = AOP_SIZE (result);
+
+ if (isPair (AOP (left)) && size == 1)
{
/* Just do it */
if (isPtrPair (AOP (left)))
goto release;
}
+ if ( getPairId( AOP (left)) == PAIR_IY)
+ {
+ /* Just do it */
+ offset = 0;
+ while (size--)
+ {
+ char at[20];
+ tsprintf (at, "!*iyx", offset);
+ aopPut (AOP (result), at, offset);
+ offset++;
+ }
+ goto release;
+ }
+
/* For now we always load into IY */
/* if this is remateriazable */
fetchPair (pair, AOP (left));
- /* so iy now contains the address */
freeAsmop (left, NULL, ic);
/* if bit then unpack */
{
wassert (0);
}
+ else if ( getPairId( AOP (result)) == PAIR_HL)
+ {
+ wassertl (size == 2, "HL must be of size 2");
+ emit2 ("ld a,!*hl");
+ emit2 ("inc hl");
+ emit2 ("ld h,!*hl");
+ emit2 ("ld l,a");
+ }
else
{
size = AOP_SIZE (result);
bool
isRegOrLit (asmop * aop)
{
- if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
+ if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
return TRUE;
return FALSE;
}
int size, offset;
sym_link *retype = getSpec (operandType (right));
PAIR_ID pairId = PAIR_HL;
-
+
aopOp (result, ic, FALSE, FALSE);
aopOp (right, ic, FALSE, FALSE);
if (IS_GB)
pairId = PAIR_DE;
+ size = AOP_SIZE (right);
+
/* Handle the exceptions first */
- if (isPair (AOP (result)) && (AOP_SIZE (right) == 1))
+ if (isPair (AOP (result)) && size == 1)
{
/* Just do it */
- char *l = aopGet (AOP (right), 0, FALSE);
+ const char *l = aopGet (AOP (right), 0, FALSE);
const char *pair = getPairName (AOP (result));
if (canAssignToPtr (l) && isPtr (pair))
{
}
else
{
- MOVA (l);
+ _moveA (l);
emit2 ("ld !*pair,a", pair);
}
goto release;
}
+
+ if ( getPairId( AOP (result)) == PAIR_IY)
+ {
+ /* Just do it */
+ const char *l = aopGet (AOP (right), 0, FALSE);
+
+ offset = 0;
+ while (size--)
+ {
+ if (canAssignToPtr (l))
+ {
+ emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
+ }
+ else
+ {
+ _moveA (aopGet (AOP (right), offset, FALSE));
+ emit2 ("ld !*iyx,a", offset);
+ }
+ offset++;
+ }
+ goto release;
+ }
/* if the operand is already in dptr
then we do nothing else we move the value to dptr */
}
else
{
- size = AOP_SIZE (right);
offset = 0;
while (size--)
{
- char *l = aopGet (AOP (right), offset, FALSE);
+ const char *l = aopGet (AOP (right), offset, FALSE);
if (isRegOrLit (AOP (right)) && !IS_GB)
{
emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
}
else
{
- MOVA (l);
+ _moveA (l);
emit2 ("ld !*pair,a", _pairs[pairId].name);
}
if (size)
{
- emitcode ("inc", _pairs[pairId].name);
+ emit2 ("inc %s", _pairs[pairId].name);
_G.pairs[pairId].offset++;
}
offset++;
/* 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 */
spillCached ();
if (sym->stack <= 0)
{
- emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset);
+ setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
}
else
{
- emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
+ setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
}
- emitcode ("ld", "d,h");
- emitcode ("ld", "e,l");
+ commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
}
else
{
emit2 ("ld de,!hashedstr", sym->rname);
+ commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
}
- aopPut (AOP (IC_RESULT (ic)), "e", 0);
- aopPut (AOP (IC_RESULT (ic)), "d", 1);
}
else
{
{
/* if it has an offset then we need to compute it */
if (sym->stack > 0)
- emitcode ("ld", "hl,#%d+%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset, _G.stack.param_offset);
+ emit2 ("ld hl,#%d+%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset, _G.stack.param_offset);
else
- emitcode ("ld", "hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
- emitcode ("add", "hl,sp");
+ emit2 ("ld hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
+ emit2 ("add hl,sp");
}
else
{
- emitcode ("ld", "hl,#%s", sym->rname);
+ emit2 ("ld hl,#%s", sym->rname);
}
- aopPut (AOP (IC_RESULT (ic)), "l", 0);
- aopPut (AOP (IC_RESULT (ic)), "h", 1);
+ commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
}
freeAsmop (IC_RESULT (ic), NULL, ic);
}
result = IC_RESULT (ic);
right = IC_RIGHT (ic);
-#if 1
/* Dont bother assigning if they are the same */
if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
{
- emitcode ("", "; (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
aopOp (right, ic, FALSE, FALSE);
aopOp (result, ic, TRUE, FALSE);
/* if they are the same registers */
if (sameRegs (AOP (right), AOP (result)))
{
- emitcode ("", "; (registers are the same)");
+ emitDebug ("; (registers are the same)");
goto release;
}
/* if the result is a bit */
if (AOP_TYPE (result) == AOP_CRY)
{
- wassert (0);
+ wassertl (0, "Tried to assign to a bit");
}
/* general case */
offset = 0;
if (AOP_TYPE (right) == AOP_LIT)
+ {
lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
+ }
+
if (isPair (AOP (result)))
{
fetchPair (getPairId (AOP (result)), AOP (right));
{
if (!fXored && size > 1)
{
- emitcode ("xor", "a,a");
+ emit2 ("xor a,a");
fXored = TRUE;
}
if (fXored)
}
else
{
- aopPut (AOP (result), zero, offset);
+ aopPut (AOP (result), "!zero", offset);
}
}
else
offset++;
}
}
+ else if (size == 2 && AOP_TYPE (right) == AOP_IY)
+ {
+ emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
+ aopPut (AOP (result), "l", LSB);
+ aopPut (AOP (result), "h", MSB16);
+ }
else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
{
/* Special case. Load into a and d, then load out. */
- MOVA (aopGet (AOP (right), 0, FALSE));
- emitcode ("ld", "e,%s", aopGet (AOP (right), 1, FALSE));
+ _moveA (aopGet (AOP (right), 0, FALSE));
+ emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
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--)
{
/* PENDING: do this check better */
- if (requiresHL (AOP (right)) && requiresHL (AOP (result)))
+ if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
{
- MOVA (aopGet (AOP (right), offset, FALSE));
+ _moveA (aopGet (AOP (right), offset, FALSE));
aopPut (AOP (result), "a", offset);
}
else
genJumpTab (iCode * ic)
{
symbol *jtab;
- char *l;
+ const char *l;
aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
/* get the condition into accumulator */
l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
if (!IS_GB)
- emitcode ("push", "de");
- emitcode ("ld", "e,%s", l);
+ emit2 ("push de");
+ emit2 ("ld e,%s", l);
emit2 ("ld d,!zero");
jtab = newiTempLabel (NULL);
spillCached ();
emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
- emitcode ("add", "hl,de");
- emitcode ("add", "hl,de");
- emitcode ("add", "hl,de");
+ emit2 ("add hl,de");
+ emit2 ("add hl,de");
+ emit2 ("add hl,de");
freeAsmop (IC_JTCOND (ic), NULL, ic);
if (!IS_GB)
- emitcode ("pop", "de");
+ emit2 ("pop de");
emit2 ("jp !*hl");
emitLabel (jtab->key + 100);
/* now generate the jump labels */
/* if the result is a bit */
if (AOP_TYPE (result) == AOP_CRY)
{
- wassert (0);
+ wassertl (0, "Tried to cast to a bit");
}
/* if they are the same size : or less */
goto release;
}
- /* PENDING: should be OK. */
-#if 0
- /* if the result is of type pointer */
- if (IS_PTR (ctype))
- {
- wassert (0);
- }
-#endif
-
- /* so we now know that the size of destination is greater
+ /* So we now know that the size of destination is greater
than the size of the source */
/* we move to result for the size of source */
size = AOP_SIZE (right);
if (SPEC_USIGN (ctype) || !IS_SPEC (ctype))
{
while (size--)
- aopPut (AOP (result), zero, offset++);
+ aopPut (AOP (result), "!zero", offset++);
}
else
{
/* we need to extend the sign :{ */
- char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
+ const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
FALSE);
- MOVA (l);
- emitcode ("", "; genCast: sign extend untested.");
- emitcode ("rla", "");
- emitcode ("sbc", "a,a");
+ _moveA (l);
+ emit2 ("rla ");
+ emit2 ("sbc a,a");
while (size--)
aopPut (AOP (result), "a", offset++);
}
size = AOP_SIZE(IC_RESULT(ic));
for (i = 0; i < size; i++) {
- aopPut(AOP(IC_RESULT(ic)), _fReturn[_G.receiveOffset++], i);
+ aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
}
}
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);
+
+ _saveRegsForCall(ic, 0);
+
+ fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
+ emit2 ("call __initrleblock");
+
+ 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");
+
+ _restoreRegsAfterCall();
+
+ spillCached ();
+
+ freeAsmop (IC_LEFT(ic), NULL, ic);
+}
+
/*-----------------------------------------------------------------*/
/* genZ80Code - generate code for Z80 based controllers */
/*-----------------------------------------------------------------*/
iCode *ic;
int cln = 0;
- /* HACK */
+ /* Hack */
if (IS_GB)
{
_fReturn = _gbz80_return;
_fReturn = _z80_return;
_fTmp = _z80_return;
}
- tsprintf (zero, "!zero");
-
- lineHead = lineCurr = NULL;
-
- /* if debug information required */
- if (options.debug && currFunc)
- {
- cdbSymbol (currFunc, cdbFile, FALSE, TRUE);
- debugLine = 1;
- if (IS_STATIC (currFunc->etype))
- emitcode ("", "F%s$%s$0$0 ==.", moduleName, currFunc->name);
- else
- emitcode ("", "G$%s$0$0 ==.", currFunc->name);
- debugLine = 0;
- }
- /* stack pointer name */
- spname = "sp";
+ _G.lines.head = _G.lines.current = NULL;
for (ic = lic; ic; ic = ic->next)
{
if (cln != ic->lineno)
{
- if (options.debug)
- {
- debugLine = 1;
- emitcode ("", "C$%s$%d$%d$%d ==.",
- FileBaseName (ic->filename), ic->lineno,
- ic->level, ic->block);
- debugLine = 0;
- }
- emitcode (";", "%s %d", ic->filename, ic->lineno);
+ emit2 ("; %s %d", ic->filename, ic->lineno);
cln = ic->lineno;
}
/* if the result is marked as
switch (ic->op)
{
case '!':
- emitcode ("", "; genNot");
+ emitDebug ("; genNot");
genNot (ic);
break;
case '~':
- emitcode ("", "; genCpl");
+ emitDebug ("; genCpl");
genCpl (ic);
break;
case UNARYMINUS:
- emitcode ("", "; genUminus");
+ emitDebug ("; genUminus");
genUminus (ic);
break;
case IPUSH:
- emitcode ("", "; genIpush");
+ emitDebug ("; genIpush");
genIpush (ic);
break;
ic->next->op == IFX &&
regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
{
- emitcode ("", "; genIfx");
+ emitDebug ("; genIfx");
genIfx (ic->next, ic);
}
else
{
- emitcode ("", "; genIpop");
+ emitDebug ("; genIpop");
genIpop (ic);
}
break;
case CALL:
- emitcode ("", "; genCall");
+ emitDebug ("; genCall");
genCall (ic);
break;
case PCALL:
- emitcode ("", "; genPcall");
+ emitDebug ("; genPcall");
genPcall (ic);
break;
case FUNCTION:
- emitcode ("", "; genFunction");
+ emitDebug ("; genFunction");
genFunction (ic);
break;
case ENDFUNCTION:
- emitcode ("", "; genEndFunction");
+ emitDebug ("; genEndFunction");
genEndFunction (ic);
break;
case RETURN:
- emitcode ("", "; genRet");
+ emitDebug ("; genRet");
genRet (ic);
break;
case LABEL:
- emitcode ("", "; genLabel");
+ emitDebug ("; genLabel");
genLabel (ic);
break;
case GOTO:
- emitcode ("", "; genGoto");
+ emitDebug ("; genGoto");
genGoto (ic);
break;
case '+':
- emitcode ("", "; genPlus");
+ emitDebug ("; genPlus");
genPlus (ic);
break;
case '-':
- emitcode ("", "; genMinus");
+ emitDebug ("; genMinus");
genMinus (ic);
break;
case '*':
- emitcode ("", "; genMult");
+ emitDebug ("; genMult");
genMult (ic);
break;
case '/':
- emitcode ("", "; genDiv");
+ emitDebug ("; genDiv");
genDiv (ic);
break;
case '%':
- emitcode ("", "; genMod");
+ emitDebug ("; genMod");
genMod (ic);
break;
case '>':
- emitcode ("", "; genCmpGt");
+ emitDebug ("; genCmpGt");
genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
break;
case '<':
- emitcode ("", "; genCmpLt");
+ emitDebug ("; genCmpLt");
genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
break;
break;
case EQ_OP:
- emitcode ("", "; genCmpEq");
+ emitDebug ("; genCmpEq");
genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
break;
case AND_OP:
- emitcode ("", "; genAndOp");
+ emitDebug ("; genAndOp");
genAndOp (ic);
break;
case OR_OP:
- emitcode ("", "; genOrOp");
+ emitDebug ("; genOrOp");
genOrOp (ic);
break;
case '^':
- emitcode ("", "; genXor");
+ emitDebug ("; genXor");
genXor (ic, ifxForOp (IC_RESULT (ic), ic));
break;
case '|':
- emitcode ("", "; genOr");
+ emitDebug ("; genOr");
genOr (ic, ifxForOp (IC_RESULT (ic), ic));
break;
case BITWISEAND:
- emitcode ("", "; genAnd");
+ emitDebug ("; genAnd");
genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
break;
case INLINEASM:
- emitcode ("", "; genInline");
+ emitDebug ("; genInline");
genInline (ic);
break;
case RRC:
- emitcode ("", "; genRRC");
+ emitDebug ("; genRRC");
genRRC (ic);
break;
case RLC:
- emitcode ("", "; genRLC");
+ emitDebug ("; genRLC");
genRLC (ic);
break;
case GETHBIT:
- emitcode ("", "; genHBIT");
- wassert (0);
+ emitDebug ("; genGetHBIT");
+ genGetHbit (ic);
+ break;
case LEFT_OP:
- emitcode ("", "; genLeftShift");
+ emitDebug ("; genLeftShift");
genLeftShift (ic);
break;
case RIGHT_OP:
- emitcode ("", "; genRightShift");
+ emitDebug ("; genRightShift");
genRightShift (ic);
break;
case GET_VALUE_AT_ADDRESS:
- emitcode ("", "; genPointerGet");
+ emitDebug ("; genPointerGet");
genPointerGet (ic);
break;
if (POINTER_SET (ic))
{
- emitcode ("", "; genAssign (pointer)");
+ emitDebug ("; genAssign (pointer)");
genPointerSet (ic);
}
else
{
- emitcode ("", "; genAssign");
+ emitDebug ("; genAssign");
genAssign (ic);
}
break;
case IFX:
- emitcode ("", "; genIfx");
+ emitDebug ("; genIfx");
genIfx (ic, NULL);
break;
case ADDRESS_OF:
- emitcode ("", "; genAddrOf");
+ emitDebug ("; genAddrOf");
genAddrOf (ic);
break;
case JUMPTABLE:
- emitcode ("", "; genJumpTab");
+ emitDebug ("; genJumpTab");
genJumpTab (ic);
break;
case CAST:
- emitcode ("", "; genCast");
+ emitDebug ("; genCast");
genCast (ic);
break;
case RECEIVE:
- emitcode ("", "; genReceive");
+ emitDebug ("; genReceive");
genReceive (ic);
break;
case SEND:
- emitcode ("", "; addSet");
- addSet (&sendSet, ic);
+ emitDebug ("; addSet");
+ addSet (&_G.sendSet, ic);
break;
+ case ARRAYINIT:
+ emitDebug ("; genArrayInit");
+ genArrayInit(ic);
+ break;
+
default:
ic = ic;
- /* piCode(ic,stdout); */
-
}
}
/* now we are ready to call the
peep hole optimizer */
if (!options.nopeep)
- peepHole (&lineHead);
+ peepHole (&_G.lines.head);
/* This is unfortunate */
/* now do the actual printing */
FILE *fp = codeOutFile;
if (isInHome () && codeOutFile == code->oFile)
codeOutFile = home->oFile;
- printLine (lineHead, codeOutFile);
- if (_G.flush_statics)
+ printLine (_G.lines.head, codeOutFile);
+ if (_G.flushStatics)
{
flushStatics ();
- _G.flush_statics = 0;
+ _G.flushStatics = 0;
}
codeOutFile = fp;
}
+
+ freeTrace(&_G.lines.trace);
+ freeTrace(&_G.trace.aops);
+}
+
+/*
+ Attic
+static int
+_isPairUsed (iCode * ic, PAIR_ID pairId)
+{
+ int ret = 0;
+ switch (pairId)
+ {
+ case PAIR_DE:
+ if (bitVectBitValue (ic->rMask, D_IDX))
+ ret++;
+ if (bitVectBitValue (ic->rMask, E_IDX))
+ ret++;
+ break;
+ default:
+ wassert (0);
+ }
+ 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 traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
}
+
+
+*/