X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=src%2Fz80%2Fgen.c;h=72d5726683ebcc6742b85efb135b77742e0331a3;hb=195ee3f3ee25ce2c5f2a59fbd2779c4cb80527c3;hp=4a9f8b25e766a8e14bc183e86e513ff28ce616ac;hpb=55ea92f1a4a24c9626e8c8b504874b22a10a83e3;p=fw%2Fsdcc diff --git a/src/z80/gen.c b/src/z80/gen.c index 4a9f8b25..72d57266 100644 --- a/src/z80/gen.c +++ b/src/z80/gen.c @@ -93,10 +93,6 @@ #define STRCASECMP strcasecmp #endif -#ifdef HAVE_SYS_ISA_DEFS_H -#include -#endif - #include "z80.h" #include "SDCCglobl.h" #include "SDCCpeeph.h" @@ -218,12 +214,15 @@ static struct int pushedDE; } calleeSaves; + bool omitFramePtr; int frameId; int receiveOffset; bool flushStatics; bool in_home; const char *lastFunctionName; - + iCode *current_iCode; + bool preserveCarry; + set *sendSet; struct @@ -237,6 +236,7 @@ static struct lineNode *head; lineNode *current; int isInline; + int isDebug; allocTrace trace; } lines; @@ -264,7 +264,8 @@ static const char *aopNames[] = { "AOP_HLREG", "AOP_SIMPLELIT", "AOP_EXSTK", - "AOP_PAIRPT" + "AOP_PAIRPT", + "AOP_DUMMY" }; static bool @@ -400,9 +401,9 @@ _newLineNode (char *line) static void _vemit2 (const char *szFormat, va_list ap) { - char buffer[256]; + char buffer[INITIAL_INLINEASM]; - tvsprintf (buffer, szFormat, ap); + tvsprintf (buffer, sizeof(buffer), szFormat, ap); _tidyUp (buffer); _G.lines.current = (_G.lines.current ? @@ -410,6 +411,8 @@ _vemit2 (const char *szFormat, va_list ap) (_G.lines.head = _newLineNode (buffer))); _G.lines.current->isInline = _G.lines.isInline; + _G.lines.current->isDebug = _G.lines.isDebug; + _G.lines.current->ic = _G.current_iCode; } static void @@ -430,15 +433,28 @@ emitDebug (const char *szFormat,...) if (!DISABLE_DEBUG) { va_list ap; - + va_start (ap, szFormat); - + _vemit2 (szFormat, ap); - + va_end (ap); } } +/*-----------------------------------------------------------------*/ +/* z80_emitDebuggerSymbol - associate the current code location */ +/* with a debugger symbol */ +/*-----------------------------------------------------------------*/ +void +z80_emitDebuggerSymbol (char * debugSym) +{ + _G.lines.isDebug = 1; + emit2 ("%s !equ .", debugSym); + emit2 ("!global", debugSym); + _G.lines.isDebug = 0; +} + /*-----------------------------------------------------------------*/ /* emit2 - writes the code into a file : for now it is simple */ /*-----------------------------------------------------------------*/ @@ -447,7 +463,7 @@ _emit2 (const char *inst, const char *fmt,...) { va_list ap; char lb[INITIAL_INLINEASM]; - char *lbp = lb; + unsigned char *lbp = lb; va_start (ap, fmt); @@ -469,6 +485,7 @@ _emit2 (const char *inst, const char *fmt,...) (_G.lines.head = _newLineNode (lb))); } _G.lines.current->isInline = _G.lines.isInline; + _G.lines.current->ic = _G.current_iCode; va_end (ap); } @@ -489,12 +506,26 @@ _emitMove(const char *to, const char *from) void aopDump(const char *plabel, asmop *aop) { + int i; + char regbuf[9]; + char *rbp = regbuf; + emitDebug("; Dump of %s: type %s size %u", plabel, aopNames[aop->type], aop->size); switch (aop->type) { + case AOP_EXSTK: case AOP_STK: emitDebug("; aop_stk %d", aop->aopu.aop_stk); break; + case AOP_REG: + for (i=aop->size-1;i>=0;i--) + *rbp++ = *(aop->aopu.aop_reg[i]->name); + *rbp = '\0'; + emitDebug("; reg = %s", regbuf); + break; + case AOP_PAIRPTR: + emitDebug("; pairptr = (%s)", _pairs[aop->aopu.aop_pairId].name); + default: /* No information. */ break; @@ -589,6 +620,22 @@ isPair (asmop * aop) return (getPairId (aop) != PAIR_INVALID); } +/** Returns TRUE if the registers used in aop cannot be split into high + and low halves */ +bool +isUnsplitable (asmop * aop) +{ + switch (getPairId (aop)) + { + case PAIR_IX: + case PAIR_IY: + return TRUE; + default: + return FALSE; + } + return FALSE; +} + bool isPtrPair (asmop * aop) { @@ -611,6 +658,30 @@ spillPair (PAIR_ID pairId) _G.pairs[pairId].base = NULL; } +/* Given a register name, spill the pair (if any) the register is part of */ +static void +spillPairReg (const char *regname) +{ + if (strlen(regname)==1) + { + switch (*regname) + { + case 'h': + case 'l': + spillPair(PAIR_HL); + break; + case 'd': + case 'e': + spillPair(PAIR_DE); + break; + case 'b': + case 'c': + spillPair(PAIR_BC); + break; + } + } +} + /** Push a register pair onto the stack */ void genPairPush (asmop * aop) @@ -633,6 +704,39 @@ _pop (PAIR_ID pairId) spillPair (pairId); } +void +genMovePairPair (PAIR_ID srcPair, PAIR_ID dstPair) +{ + switch (dstPair) + { + case PAIR_IX: + case PAIR_IY: + case PAIR_AF: + _push(srcPair); + _pop(dstPair); + break; + case PAIR_BC: + case PAIR_DE: + case PAIR_HL: + if (srcPair == PAIR_IX || srcPair == PAIR_IY) + { + _push(srcPair); + _pop(dstPair); + } + else + { + emit2("ld %s,%s",_pairs[dstPair].l,_pairs[srcPair].l); + emit2("ld %s,%s",_pairs[dstPair].h,_pairs[srcPair].h); + } + default: + wassertl (0, "Tried to move a nonphysical pair"); + } + _G.pairs[dstPair].last_type = _G.pairs[srcPair].last_type; + _G.pairs[dstPair].base = _G.pairs[srcPair].base; + _G.pairs[dstPair].offset = _G.pairs[srcPair].offset; +} + + /*-----------------------------------------------------------------*/ /* newAsmop - creates a new asmOp */ /*-----------------------------------------------------------------*/ @@ -674,7 +778,7 @@ aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a) 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)))) + if (IS_Z80 && (_G.omitFramePtr || sym->stack < INT8MIN || sym->stack > (int)(INT8MAX-getSize (sym->type)))) { emitDebug ("; AOP_EXSTK for %s", sym->rname); sym->aop = aop = newAsmop (AOP_EXSTK); @@ -699,18 +803,34 @@ aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a) return aop; } - if (IS_GB) + if( IN_REGSP( space )) + { /*.p.t.20030716 minor restructure to add SFR support to the Z80 */ + if (IS_GB) { /* if it is in direct space */ - if (IN_REGSP (space) && !requires_a) - { - sym->aop = aop = newAsmop (AOP_SFR); - aop->aopu.aop_dir = sym->rname; - aop->size = getSize (sym->type); + if( !requires_a ) + { + sym->aop = aop = newAsmop (AOP_SFR); + aop->aopu.aop_dir = sym->rname; + aop->size = getSize (sym->type); emitDebug ("; AOP_SFR for %s", sym->rname); - return aop; - } + return aop; + } + } + else + { /*.p.t.20030716 adding SFR support to the Z80 port */ + aop = newAsmop (AOP_SFR); + sym->aop = aop; + aop->aopu.aop_dir = sym->rname; + aop->size = getSize( sym->type ); + aop->paged = FUNC_REGBANK(sym->type); + aop->bcInUse = isPairInUse( PAIR_BC, ic ); + aop->deInUse = isPairInUse( PAIR_DE, ic ); + emitDebug( ";Z80 AOP_SFR for %s banked:%d bc:%d de:%d", sym->rname, FUNC_REGBANK(sym->type), aop->bcInUse, aop->deInUse ); + + return( aop ); } + } /* only remaining is far space */ /* in which case DPTR gets the address */ @@ -827,10 +947,10 @@ operandsEqu (operand * op1, operand * op2) if (sym1 == sym2) return 1; - if (strcmp (sym1->rname, sym2->rname) == 0) + if (sym1->rname[0] && sym2->rname[0] + && strcmp (sym1->rname, sym2->rname) == 0) return 2; - /* if left is a tmp & right is not */ if (IS_ITEMP (op1) && !IS_ITEMP (op2) && @@ -903,6 +1023,11 @@ aopOp (operand * op, iCode * ic, bool result, bool requires_a) /* if already has a asmop then continue */ if (op->aop) { + if (op->aop->type == AOP_SFR) + { + op->aop->bcInUse = isPairInUse( PAIR_BC, ic ); + op->aop->deInUse = isPairInUse( PAIR_DE, ic ); + } return; } @@ -910,6 +1035,11 @@ aopOp (operand * op, iCode * ic, bool result, bool requires_a) if (IS_SYMOP (op) && OP_SYMBOL (op)->aop) { op->aop = OP_SYMBOL (op)->aop; + if (op->aop->type == AOP_SFR) + { + op->aop->bcInUse = isPairInUse( PAIR_BC, ic ); + op->aop->deInUse = isPairInUse( PAIR_DE, ic ); + } return; } @@ -995,14 +1125,21 @@ aopOp (operand * op, iCode * ic, bool result, bool requires_a) return; } - /* else spill location */ - if (sym->usl.spillLoc && getSize(sym->type) != getSize(sym->usl.spillLoc->type)) { - /* force a new aop if sizes differ */ - sym->usl.spillLoc->aop = NULL; - } - sym->aop = op->aop = aop = - aopForSym (ic, sym->usl.spillLoc, result, requires_a); - wassertl (aop->size >= getSize (sym->type), "Operand doesn't fit in the spill location"); + if (sym->usl.spillLoc) + { + if (getSize(sym->type) != getSize(sym->usl.spillLoc->type)) + { + /* force a new aop if sizes differ */ + sym->usl.spillLoc->aop = NULL; + } + sym->aop = op->aop = aop = + aopForSym (ic, sym->usl.spillLoc, result, requires_a); + aop->size = getSize (sym->type); + return; + } + + /* else must be a dummy iTemp */ + sym->aop = op->aop = aop = newAsmop (AOP_DUMMY); aop->size = getSize (sym->type); return; } @@ -1079,8 +1216,6 @@ isLitWord (asmop * aop) char * aopGetLitWordLong (asmop * aop, int offset, bool with_hash) { - char *s = buffer; - /* depending on type */ switch (aop->type) { @@ -1090,17 +1225,20 @@ aopGetLitWordLong (asmop * aop, int offset, bool with_hash) /* PENDING: for re-target */ if (with_hash) { - tsprintf (s, "!hashedstr + %d", aop->aopu.aop_immd, offset); + tsprintf (buffer, sizeof(buffer), + "!hashedstr + %d", aop->aopu.aop_immd, offset); } else if (offset == 0) { - tsprintf (s, "%s", aop->aopu.aop_immd); + tsprintf (buffer, sizeof(buffer), + "%s", aop->aopu.aop_immd); } else { - tsprintf (s, "%s + %d", aop->aopu.aop_immd, offset); + tsprintf (buffer, sizeof(buffer), + "%s + %d", aop->aopu.aop_immd, offset); } - return traceAlloc(&_G.trace.aops, Safe_strdup(s)); + return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); case AOP_LIT: { @@ -1125,9 +1263,9 @@ aopGetLitWordLong (asmop * aop, int offset, bool with_hash) } if (with_hash) - tsprintf (buffer, "!immedword", v); + tsprintf (buffer, sizeof(buffer), "!immedword", v); else - tsprintf (buffer, "!constword", v); + tsprintf (buffer, sizeof(buffer), "!constword", v); return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); } @@ -1143,15 +1281,15 @@ aopGetLitWordLong (asmop * aop, int offset, bool with_hash) /* it is type float */ fl.f = (float) floatFromVal (val); -#ifdef _BIG_ENDIAN +#ifdef WORDS_BIGENDIAN 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", i); + tsprintf (buffer, sizeof(buffer), "!immedword", i); else - tsprintf (buffer, "!constword", i); + tsprintf (buffer, sizeof(buffer), "!constword", i); return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); } @@ -1350,6 +1488,11 @@ fetchPairLong (PAIR_ID pairId, asmop * aop, iCode *ic, int offset) _pop (id); } } + else if (isUnsplitable(aop)) + { + emit2("push %s", _pairs[getPairId(aop)].name); + emit2("pop %s", _pairs[pairId].name); + } else { emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE)); @@ -1378,6 +1521,12 @@ setupPairFromSP (PAIR_ID id, int offset) { wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL"); + if (_G.preserveCarry) + { + _push (PAIR_AF); + offset += 2; + } + if (offset < INT8MIN || offset > INT8MAX) { emit2 ("ld hl,!immedword", offset); @@ -1385,7 +1534,13 @@ setupPairFromSP (PAIR_ID id, int offset) } else { - emit2 ("!ldahlsp", offset); + emit2 ("!ldahlsp", offset); + } + + if (_G.preserveCarry) + { + _pop (PAIR_AF); + offset -= 2; } } @@ -1421,11 +1576,15 @@ setupPair (PAIR_ID pairId, asmop * aop, int offset) else { /* PENDING: Do this better. */ + if (_G.preserveCarry) + _push (PAIR_AF); 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; + if (_G.preserveCarry) + _pop (PAIR_AF); } } break; @@ -1454,6 +1613,8 @@ setupPair (PAIR_ID pairId, asmop * aop, int offset) } case AOP_PAIRPTR: + if (pairId != aop->aopu.aop_pairId) + genMovePairPair(aop->aopu.aop_pairId, pairId); adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset); break; @@ -1476,55 +1637,83 @@ emitLabel (int key) static const char * aopGet (asmop * aop, int offset, bool bit16) { - char *s = buffer; + // char *s = buffer; /* 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) { - tsprintf (s, "!zero"); - return traceAlloc(&_G.trace.aops, Safe_strdup(s)); + tsprintf (buffer, sizeof(buffer), "!zero"); + return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); } /* depending on type */ switch (aop->type) { + case AOP_DUMMY: + tsprintf (buffer, sizeof(buffer), "!zero"); + return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); + case AOP_IMMD: /* PENDING: re-target */ if (bit16) - tsprintf (s, "!immedwords", aop->aopu.aop_immd); + tsprintf (buffer, sizeof(buffer), "!immedwords", aop->aopu.aop_immd); else switch (offset) { case 2: - tsprintf (s, "!bankimmeds", aop->aopu.aop_immd); + tsprintf (buffer, sizeof(buffer), "!bankimmeds", aop->aopu.aop_immd); break; case 1: - tsprintf (s, "!msbimmeds", aop->aopu.aop_immd); + tsprintf (buffer, sizeof(buffer), "!msbimmeds", aop->aopu.aop_immd); break; case 0: - tsprintf (s, "!lsbimmeds", aop->aopu.aop_immd); + tsprintf (buffer, sizeof(buffer), "!lsbimmeds", aop->aopu.aop_immd); break; default: wassertl (0, "Fetching from beyond the limits of an immediate value."); } - return traceAlloc(&_G.trace.aops, Safe_strdup(s)); + return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); case AOP_DIR: wassert (IS_GB); emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset); - sprintf (s, "a"); + SNPRINTF (buffer, sizeof(buffer), "a"); - return traceAlloc(&_G.trace.aops, Safe_strdup(s)); + return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); case AOP_SFR: - wassert (IS_GB); - emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset); - sprintf (s, "a"); + if( IS_GB ) + { + // wassert (IS_GB); + emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset); + SNPRINTF (buffer, sizeof(buffer), "a"); - return traceAlloc(&_G.trace.aops, Safe_strdup(s)); + return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); + } + else + { /*.p.t.20030716 handling for i/o port read access for Z80 */ + if( aop->paged ) + { /* banked mode */ + /* reg A goes to address bits 15-8 during "in a,(x)" instruction */ + emit2( "ld a,!msbimmeds", aop->aopu.aop_dir); + emit2( "in a,(!lsbimmeds)", aop->aopu.aop_dir); + } + else if( z80_opts.port_mode == 180 ) + { /* z180 in0/out0 mode */ + emit2( "in0 a,(%s)", aop->aopu.aop_dir ); + } + else + { /* 8 bit mode */ + emit2( "in a,(%s)", aop->aopu.aop_dir ); + } + + SNPRINTF (buffer, sizeof(buffer), "a"); + + return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); + } case AOP_REG: return aop->aopu.aop_reg[offset]->name; @@ -1532,38 +1721,39 @@ aopGet (asmop * aop, int offset, bool bit16) case AOP_HL: wassert (IS_GB); setupPair (PAIR_HL, aop, offset); - tsprintf (s, "!*hl"); + tsprintf (buffer, sizeof(buffer), "!*hl"); - return traceAlloc(&_G.trace.aops, Safe_strdup (s)); + return traceAlloc(&_G.trace.aops, Safe_strdup (buffer)); case AOP_IY: wassert (IS_Z80); setupPair (PAIR_IY, aop, offset); - tsprintf (s, "!*iyx", offset); + tsprintf (buffer, sizeof(buffer), "!*iyx", offset); - return traceAlloc(&_G.trace.aops, Safe_strdup(s)); + return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); case AOP_EXSTK: wassert (IS_Z80); setupPair (PAIR_IY, aop, offset); - tsprintf (s, "!*iyx", offset, offset); + tsprintf (buffer, sizeof(buffer), "!*iyx", offset, offset); - return traceAlloc(&_G.trace.aops, Safe_strdup(s)); + return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); case AOP_STK: if (IS_GB) { setupPair (PAIR_HL, aop, offset); - tsprintf (s, "!*hl"); + tsprintf (buffer, sizeof(buffer), "!*hl"); } else { if (aop->aopu.aop_stk >= 0) offset += _G.stack.param_offset; - tsprintf (s, "!*ixx", aop->aopu.aop_stk + offset); + tsprintf (buffer, sizeof(buffer), + "!*ixx", aop->aopu.aop_stk + offset); } - return traceAlloc(&_G.trace.aops, Safe_strdup(s)); + return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); case AOP_CRY: wassertl (0, "Tried to fetch from a bit variable"); @@ -1575,8 +1765,8 @@ aopGet (asmop * aop, int offset, bool bit16) } else { - tsprintf(s, "!zero"); - return traceAlloc(&_G.trace.aops, Safe_strdup(s)); + tsprintf(buffer, sizeof(buffer), "!zero"); + return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); } case AOP_HLREG: @@ -1591,9 +1781,10 @@ aopGet (asmop * aop, int offset, bool bit16) unsigned long v = aop->aopu.aop_simplelit; v >>= (offset * 8); - tsprintf (s, "!immedbyte", (unsigned int) v & 0xff); + tsprintf (buffer, sizeof(buffer), + "!immedbyte", (unsigned int) v & 0xff); - return traceAlloc(&_G.trace.aops, Safe_strdup(s)); + return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); } case AOP_STR: aop->coff = offset; @@ -1601,9 +1792,17 @@ aopGet (asmop * aop, int offset, bool bit16) case AOP_PAIRPTR: setupPair (aop->aopu.aop_pairId, aop, offset); - sprintf (s, "(%s)", _pairs[aop->aopu.aop_pairId].name); + if (aop->aopu.aop_pairId==PAIR_IX) + SNPRINTF (buffer, sizeof(buffer), + "!*ixx", 0); + else if (aop->aopu.aop_pairId==PAIR_IY) + SNPRINTF (buffer, sizeof(buffer), + "!*iyx", 0); + else + SNPRINTF (buffer, sizeof(buffer), + "(%s)", _pairs[aop->aopu.aop_pairId].name); - return traceAlloc(&_G.trace.aops, Safe_strdup(s)); + return traceAlloc(&_G.trace.aops, Safe_strdup(buffer)); default: break; @@ -1659,13 +1858,17 @@ aopPut (asmop * aop, const char *s, int offset) } // PENDING - tsprintf(buffer2, s); + tsprintf(buffer2, sizeof(buffer2), s); s = buffer2; /* will assign value to value */ /* depending on where it is ofcourse */ switch (aop->type) { + case AOP_DUMMY: + _moveA (s); /* in case s is volatile */ + break; + case AOP_DIR: /* Direct. Hmmm. */ wassert (IS_GB); @@ -1675,10 +1878,47 @@ aopPut (asmop * aop, const char *s, int offset) break; case AOP_SFR: - wassert (IS_GB); - if (strcmp (s, "a")) - emit2 ("ld a,%s", s); - emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset); + if( IS_GB ) + { + // wassert (IS_GB); + if (strcmp (s, "a")) + emit2 ("ld a,%s", s); + emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset); + } + else + { /*.p.t.20030716 handling for i/o port read access for Z80 */ + if (aop->paged) + { /* banked mode */ + if (aop->bcInUse) + emit2( "push bc" ); + + if (strlen(s) != 1 + || (s[0] != 'a' && s[0] != 'd' && s[0] != 'e' + && s[0] != 'h' && s[0] != 'l')) + { + emit2( "ld a,%s", s ); + s = "a"; + } + + emit2( "ld bc,#%s", aop->aopu.aop_dir ); + emit2( "out (c),%s", s ); + + if( aop->bcInUse ) + emit2( "pop bc" ); + else + spillPair (PAIR_BC); + } + else if( z80_opts.port_mode == 180 ) + { /* z180 in0/out0 mode */ + emit2( "ld a,%s", s ); + emit2( "out0 (%s),a", aop->aopu.aop_dir ); + } + else + { /* 8 bit mode */ + emit2( "ld a,%s", s ); + emit2( "out (%s),a", aop->aopu.aop_dir ); + } + } break; case AOP_REG: @@ -1687,6 +1927,7 @@ aopPut (asmop * aop, const char *s, int offset) else emit2 ("ld %s,%s", aop->aopu.aop_reg[offset]->name, s); + spillPairReg(aop->aopu.aop_reg[offset]->name); break; case AOP_IY: @@ -1786,6 +2027,7 @@ aopPut (asmop * aop, const char *s, int offset) { emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s); } + spillPairReg(aop->aopu.aop_str[offset]); break; case AOP_ACC: @@ -1799,18 +2041,27 @@ aopPut (asmop * aop, const char *s, int offset) else { if (strcmp (aop->aopu.aop_str[offset], s)) - emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s); + { + emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s); + spillPairReg(aop->aopu.aop_str[offset]); + } } break; case AOP_HLREG: wassert (offset < 2); emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s); + spillPairReg(aop->aopu.aop_str[offset]); break; case AOP_PAIRPTR: setupPair (aop->aopu.aop_pairId, aop, offset); - emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s); + if (aop->aopu.aop_pairId==PAIR_IX) + emit2 ("ld !*ixx,%s", 0, s); + else if (aop->aopu.aop_pairId==PAIR_IY) + emit2 ("ld !*ixy,%s", 0, s); + else + emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s); break; default: @@ -1823,7 +2074,7 @@ aopPut (asmop * aop, const char *s, int offset) #define AOP(op) op->aop #define AOP_TYPE(op) AOP(op)->type #define AOP_SIZE(op) AOP(op)->size -#define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY)) +#define AOP_NEEDSACC(x) (AOP(x) && ((AOP_TYPE(x) == AOP_CRY) || (AOP_TYPE(x) == AOP_SFR))) static void commitPair (asmop * aop, PAIR_ID id) @@ -2012,43 +2263,6 @@ _toBoolean (operand * oper) } } -/*-----------------------------------------------------------------*/ -/* 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 */ @@ -2056,7 +2270,6 @@ genNotFloat (operand * op, operand * res) static void genNot (iCode * ic) { - sym_link *optype = operandType (IC_LEFT (ic)); /* assign asmOps to operand & result */ aopOp (IC_LEFT (ic), ic, FALSE, TRUE); @@ -2068,13 +2281,6 @@ genNot (iCode * ic) wassertl (0, "Tried to negate a bit"); } - /* if type float then do float */ - if (IS_FLOAT (optype)) - { - genNotFloat (IC_LEFT (ic), IC_RESULT (ic)); - goto release; - } - _toBoolean (IC_LEFT (ic)); /* Not of A: @@ -2084,7 +2290,6 @@ genNot (iCode * ic) emit2 ("sub a,!one"); outBitC (IC_RESULT (ic)); - release: /* release the aops */ freeAsmop (IC_LEFT (ic), NULL, ic); freeAsmop (IC_RESULT (ic), NULL, ic); @@ -2190,7 +2395,7 @@ genUminusFloat (operand * op, operand * result) emitDebug("; genUminusFloat"); /* for this we just need to flip the - first it then copy the rest in place */ + first bit then copy the rest in place */ size = AOP_SIZE (op) - 1; _moveA(aopGet (AOP (op), MSB32, FALSE)); @@ -2356,7 +2561,8 @@ _saveRegsForCall(iCode *ic, int sendSetSize) bool bcInRet = FALSE, deInRet = FALSE; bitVect *rInUse; - rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed); + rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), + z80_rUmaskForOp (IC_RESULT(ic))); deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX); bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX); @@ -2591,6 +2797,7 @@ _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId) static void emitCall (iCode * ic, bool ispcall) { + bool bInRet, cInRet, dInRet, eInRet; sym_link *dtype = operandType (IC_LEFT (ic)); /* if caller saves & we have not saved then */ @@ -2707,7 +2914,7 @@ emitCall (iCode * ic, bool ispcall) } spillCached (); - /* Mark the regsiters as restored. */ + /* Mark the registers as restored. */ _G.saves.saved = FALSE; /* if we need assign a result value */ @@ -2759,12 +2966,24 @@ emitCall (iCode * ic, bool ispcall) } spillCached (); + if (IC_RESULT (ic)) + { + bitVect *result = z80_rUmaskForOp (IC_RESULT (ic)); + bInRet = bitVectBitValue(result, B_IDX); + cInRet = bitVectBitValue(result, C_IDX); + dInRet = bitVectBitValue(result, D_IDX); + eInRet = bitVectBitValue(result, E_IDX); + } + else + { + bInRet = FALSE; + cInRet = FALSE; + dInRet = FALSE; + eInRet = FALSE; + } if (_G.stack.pushedDE) { - bool dInRet = bitVectBitValue(ic->rUsed, D_IDX); - bool eInRet = bitVectBitValue(ic->rUsed, E_IDX); - if (dInRet && eInRet) { wassertl (0, "Shouldn't push DE if it's wiped out by the return"); @@ -2791,9 +3010,6 @@ emitCall (iCode * ic, bool ispcall) if (_G.stack.pushedBC) { - bool bInRet = bitVectBitValue(ic->rUsed, B_IDX); - bool cInRet = bitVectBitValue(ic->rUsed, C_IDX); - if (bInRet && cInRet) { wassertl (0, "Shouldn't push BC if it's wiped out by the return"); @@ -2864,6 +3080,8 @@ extern set *publics; static void genFunction (iCode * ic) { + bool stackParm; + symbol *sym = OP_SYMBOL (IC_LEFT (ic)); sym_link *ftype; @@ -2882,8 +3100,11 @@ genFunction (iCode * ic) /* Create the function header */ emit2 ("!functionheader", sym->name); - sprintf (buffer, "%s_start", sym->rname); - emit2 ("!labeldef", buffer); + if (!IS_STATIC(sym->etype)) + { + sprintf (buffer, "%s_start", sym->rname); + emit2 ("!labeldef", buffer); + } emit2 ("!functionlabeldef", sym->rname); if (options.profile) @@ -2893,14 +3114,21 @@ genFunction (iCode * ic) ftype = operandType (IC_LEFT (ic)); - /* if critical function then turn interrupts off */ - if (IFFUNC_ISCRITICAL (ftype)) - emit2 ("!di"); - /* if this is an interrupt service routine then save all potentially used registers. */ if (IFFUNC_ISISR (sym->type)) { - emit2 ("!pusha"); + if (!FUNC_ISNAKED( sym->type )) + { + emit2 ("!pusha"); + } + } + else + { + /* if critical function then turn interrupts off */ + if (IFFUNC_ISCRITICAL (sym->type)) + { + emit2 ("!di"); + } } /* PENDING: callee-save etc */ @@ -2958,13 +3186,35 @@ genFunction (iCode * ic) /* adjust the stack for the function */ _G.stack.last = sym->stack; - - if (sym->stack && IS_GB && sym->stack > -INT8MIN) + + stackParm = FALSE; + for (sym = setFirstItem (istack->syms); sym; + sym = setNextItem (istack->syms)) + { + if (sym->_isparm && !IS_REGPARM (sym->etype)) + { + stackParm = TRUE; + break; + } + } + sym = OP_SYMBOL (IC_LEFT (ic)); + + _G.omitFramePtr = options.ommitFramePtr; + if (IS_Z80 && !stackParm && !sym->stack) + { + /* When the conflicts between AOP_EXSTK && AOP_HLREG are fixed, */ + /* the above !sym->stack condition can be removed. -- EEP */ + if (sym->stack) + emit2 ("!ldaspsp", -sym->stack); + _G.omitFramePtr = TRUE; + } + else if (sym->stack && IS_GB && sym->stack > -INT8MIN) emit2 ("!enterxl", sym->stack); else if (sym->stack) emit2 ("!enterx", sym->stack); - else + else if( !FUNC_ISNAKED( sym->type )) /*.p.t.20030716 - now supporting Naked funcitons */ emit2 ("!enter"); + _G.stack.offset = sym->stack; } @@ -2976,54 +3226,83 @@ genEndFunction (iCode * ic) { symbol *sym = OP_SYMBOL (IC_LEFT (ic)); - if (IFFUNC_ISISR (sym->type)) + + /* PENDING: calleeSave */ + if (IS_Z80 && _G.omitFramePtr) { - wassertl (0, "Tried to close an interrupt support function"); + if (_G.stack.offset) + emit2 ("!ldaspsp", _G.stack.offset); } - else + else if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX) { - if (IFFUNC_ISCRITICAL (sym->type)) - emit2 ("!ei"); - - /* PENDING: calleeSave */ - - 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 ("!leavexl", _G.stack.offset); + } + else if (_G.stack.offset) + { + emit2 ("!leavex", _G.stack.offset); + } + else if( !FUNC_ISNAKED( sym->type )) /*.p.t.20030716 - now supporting Naked funcitons */ + { + emit2 ("!leave"); + } + + if (_G.calleeSaves.pushedDE) + { + emit2 ("pop de"); + _G.calleeSaves.pushedDE = FALSE; + } - if (_G.calleeSaves.pushedDE) - { - emit2 ("pop de"); - _G.calleeSaves.pushedDE = FALSE; - } + if (_G.calleeSaves.pushedBC) + { + emit2 ("pop bc"); + _G.calleeSaves.pushedBC = FALSE; + } - if (_G.calleeSaves.pushedBC) - { - emit2 ("pop bc"); - _G.calleeSaves.pushedBC = FALSE; - } + if (options.profile) + { + emit2 ("!profileexit"); + } - if (options.profile) + /* if this is an interrupt service routine then restore all potentially used registers. */ + if (IFFUNC_ISISR (sym->type)) + { + if (!FUNC_ISNAKED( sym->type )) { - emit2 ("!profileexit"); + emit2 ("!popa"); } + } + else + { + /* if critical function then turn interrupts back on */ + if (IFFUNC_ISCRITICAL (sym->type)) + emit2 ("!ei"); + } - - /* Both baned and non-banked just ret */ + if (options.debug && currFunc) + { + debugFile->writeEndFunction (currFunc, ic, 1); + } + + if (IFFUNC_ISISR (sym->type)) + { + /* "critical interrupt" is used to imply NMI handler */ + if (IS_Z80 && IFFUNC_ISCRITICAL (sym->type)) + emit2 ("retn"); + else + emit2 ("reti"); + } + else + { + /* Both banked and non-banked just ret */ emit2 ("ret"); - + } + + if (!IS_STATIC(sym->etype)) + { sprintf (buffer, "%s_end", sym->rname); emit2 ("!labeldef", buffer); } + _G.flushStatics = 1; _G.stack.pushed = 0; _G.stack.offset = 0; @@ -3050,6 +3329,9 @@ genRet (iCode * ic) aopOp (IC_LEFT (ic), ic, FALSE, FALSE); size = AOP_SIZE (IC_LEFT (ic)); + aopDump("IC_LEFT", AOP(IC_LEFT(ic))); + + #if 0 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0)))) { if (IS_GB) @@ -3061,6 +3343,11 @@ genRet (iCode * ic) emit2 ("ld hl,%s", l); } } + #endif + if (size==2) + { + fetchPair(IS_GB ? PAIR_DE : PAIR_HL, AOP (IC_LEFT (ic))); + } else { if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic)))) @@ -3075,7 +3362,8 @@ genRet (iCode * ic) l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE); if (strcmp (_fReturn[offset], l)) - emit2 ("ld %s,%s", _fReturn[offset++], l); + emit2 ("ld %s,%s", _fReturn[offset], l); + offset++; } } } @@ -3324,11 +3612,16 @@ setupToPreserveCarry (asmop *result, asmop *left, asmop *right) if (couldDestroyCarry (right) && couldDestroyCarry (result)) { shiftIntoPair (0, right); - shiftIntoPair (1, result); + /* check result again, in case right == result */ + if (couldDestroyCarry (result)) + shiftIntoPair (1, result); } else if (couldDestroyCarry (right)) { - shiftIntoPair (0, right); + if (getPairId (result) == PAIR_HL) + _G.preserveCarry = TRUE; + else + shiftIntoPair (0, right); } else if (couldDestroyCarry (result)) { @@ -3362,7 +3655,7 @@ genPlus (iCode * ic) in ACC */ if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) || - (AOP_NEEDSACC (IC_LEFT (ic))) || + (AOP_NEEDSACC (IC_RIGHT (ic))) || AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC) { operand *t = IC_RIGHT (ic); @@ -3530,7 +3823,7 @@ genPlus (iCode * ic) goto release; } } - + setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic))); while (size--) @@ -3559,6 +3852,7 @@ genPlus (iCode * ic) } release: + _G.preserveCarry = FALSE; freeAsmop (IC_LEFT (ic), NULL, ic); freeAsmop (IC_RIGHT (ic), NULL, ic); freeAsmop (IC_RESULT (ic), NULL, ic); @@ -3762,6 +4056,7 @@ genMinus (iCode * ic) } release: + _G.preserveCarry = FALSE; freeAsmop (IC_LEFT (ic), NULL, ic); freeAsmop (IC_RIGHT (ic), NULL, ic); freeAsmop (IC_RESULT (ic), NULL, ic); @@ -3777,11 +4072,14 @@ genMult (iCode * ic) int count, i; /* If true then the final operation should be a subtract */ bool active = FALSE; + bool byteResult; /* 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); + + byteResult = (AOP_SIZE (IC_RESULT (ic)) == 1); if (AOP_SIZE (IC_LEFT (ic)) > 2 || AOP_SIZE (IC_RIGHT (ic)) > 2 || @@ -3812,10 +4110,13 @@ genMult (iCode * ic) 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"); + if (!byteResult) + { + emit2 ("ld a,e"); + emit2 ("rlc a"); + emit2 ("sbc a,a"); + emit2 ("ld d,a"); + } } else { @@ -3837,7 +4138,8 @@ genMult (iCode * ic) if (active == FALSE) { emit2 ("ld l,e"); - emit2 ("ld h,d"); + if (!byteResult) + emit2 ("ld h,d"); } else { @@ -3856,7 +4158,10 @@ genMult (iCode * ic) _G.stack.pushedDE = FALSE; } - commitPair ( AOP (IC_RESULT (ic)), PAIR_HL); + if (byteResult) + aopPut (AOP (IC_RESULT (ic)), _pairs[PAIR_HL].l, 0); + else + commitPair ( AOP (IC_RESULT (ic)), PAIR_HL); freeAsmop (IC_LEFT (ic), NULL, ic); freeAsmop (IC_RIGHT (ic), NULL, ic); @@ -4726,7 +5031,7 @@ genAnd (iCode * ic, iCode * ifx) /* 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)) + (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left))) { operand *tmp = right; right = left; @@ -4916,7 +5221,7 @@ genOr (iCode * ic, iCode * ifx) /* 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)) + (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left))) { operand *tmp = right; right = left; @@ -5074,7 +5379,7 @@ genXor (iCode * ic, iCode * ifx) /* 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)) + (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left))) { operand *tmp = right; right = left; @@ -5151,9 +5456,9 @@ genXor (iCode * ic, iCode * ifx) continue; else { - _moveA (aopGet (AOP (right), offset, FALSE)); + _moveA (aopGet (AOP (left), offset, FALSE)); emit2 ("xor a,%s", - aopGet (AOP (left), offset, FALSE)); + aopGet (AOP (right), offset, FALSE)); aopPut (AOP (result), "a", offset); } } @@ -5165,10 +5470,10 @@ genXor (iCode * ic, iCode * ifx) } else { - _moveA (aopGet (AOP (right), offset, FALSE)); + _moveA (aopGet (AOP (left), offset, FALSE)); emit2 ("xor a,%s", - aopGet (AOP (left), offset, FALSE)); - aopPut (AOP (result), "a", 0); + aopGet (AOP (right), offset, FALSE)); + aopPut (AOP (result), "a", offset); } } } @@ -5203,9 +5508,9 @@ genXor (iCode * ic, iCode * ifx) } else { - _moveA (aopGet (AOP (right), offset, FALSE)); + _moveA (aopGet (AOP (left), offset, FALSE)); emit2 ("xor a,%s", - aopGet (AOP (left), offset, FALSE)); + aopGet (AOP (right), offset, FALSE)); } aopPut (AOP (result), "a", offset); } @@ -5469,6 +5774,7 @@ AccRol (int shCount) { shCount &= 0x0007; // shCount : 0..7 +#if 0 switch (shCount) { case 0: @@ -5504,6 +5810,43 @@ AccRol (int shCount) emit2 ("srl a"); break; } +#else + switch (shCount) + { + case 0: + break; + case 1: + emit2 ("rlca"); + break; + case 2: + emit2 ("rlca"); + emit2 ("rlca"); + break; + case 3: + emit2 ("rlca"); + emit2 ("rlca"); + emit2 ("rlca"); + break; + case 4: + emit2 ("rlca"); + emit2 ("rlca"); + emit2 ("rlca"); + emit2 ("rlca"); + break; + case 5: + emit2 ("rrca"); + emit2 ("rrca"); + emit2 ("rrca"); + break; + case 6: + emit2 ("rrca"); + emit2 ("rrca"); + break; + case 7: + emit2 ("rrca"); + break; + } +#endif } /*-----------------------------------------------------------------*/ @@ -5698,6 +6041,9 @@ genLeftShift (iCode * ic) aopOp (left, ic, FALSE, FALSE); aopOp (result, ic, FALSE, FALSE); + if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG) + _push (PAIR_AF); + /* now move the left to the result if they are not the same */ @@ -5719,6 +6065,9 @@ genLeftShift (iCode * ic) offset = 0; tlbl1 = newiTempLabel (NULL); + if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG) + _pop (PAIR_AF); + emit2 ("!shortjp !tlabel", tlbl1->key + 100); emitLabel (tlbl->key + 100); l = aopGet (AOP (result), offset, FALSE); @@ -5965,13 +6314,19 @@ genRightShift (iCode * ic) return; } + 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); + if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG) + _push (PAIR_AF); + /* now move the left to the result if they are not the same */ - if (!sameRegs (AOP (left), AOP (result)) && - AOP_SIZE (result) > 1) + if (!sameRegs (AOP (left), AOP (result))) { size = AOP_SIZE (result); @@ -5984,14 +6339,13 @@ genRightShift (iCode * ic) } } - emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE)); - emit2 ("inc a"); - freeAsmop (right, NULL, ic); - tlbl = newiTempLabel (NULL); tlbl1 = newiTempLabel (NULL); size = AOP_SIZE (result); offset = size - 1; + + if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG) + _pop (PAIR_AF); emit2 ("!shortjp !tlabel", tlbl1->key + 100); emitLabel (tlbl->key + 100); @@ -6016,6 +6370,82 @@ genRightShift (iCode * ic) freeAsmop (result, NULL, ic); } + +/*-----------------------------------------------------------------*/ +/* genUnpackBits - generates code for unpacking bits */ +/*-----------------------------------------------------------------*/ +static void +genUnpackBits (operand * result, int pair) +{ + int offset = 0; /* result byte offset */ + int rsize; /* result size */ + int rlen = 0; /* remaining bitfield length */ + sym_link *etype; /* bitfield type information */ + int blen; /* bitfield length */ + int bstr; /* bitfield starting bit within byte */ + + emitDebug ("; genUnpackBits"); + + etype = getSpec (operandType (result)); + rsize = getSize (operandType (result)); + blen = SPEC_BLEN (etype); + bstr = SPEC_BSTR (etype); + + /* If the bitfield length is less than a byte */ + if (blen < 8) + { + emit2 ("ld a,!*pair", _pairs[pair].name); + AccRsh (bstr); + emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen)); + aopPut (AOP (result), "a", offset++); + goto finish; + } + + /* TODO: what if pair == PAIR_DE ? */ + if (getPairId (AOP (result)) == PAIR_HL) + { + wassertl (rsize == 2, "HL must be of size 2"); + emit2 ("ld a,!*hl"); + emit2 ("inc hl"); + emit2 ("ld h,!*hl"); + emit2 ("ld l,a"); + emit2 ("ld a,h"); + emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen)); + emit2 ("ld h,a"); + spillPair (PAIR_HL); + return; + } + + /* Bit field did not fit in a byte. Copy all + but the partial byte at the end. */ + for (rlen=blen;rlen>=8;rlen-=8) + { + emit2 ("ld a,!*pair", _pairs[pair].name); + aopPut (AOP (result), "a", offset++); + if (rlen>8) + { + emit2 ("inc %s", _pairs[pair].name); + _G.pairs[pair].offset++; + } + } + + /* Handle the partial byte at the end */ + if (rlen) + { + emit2 ("ld a,!*pair", _pairs[pair].name); + emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen)); + aopPut (AOP (result), "a", offset++); + } + +finish: + if (offset < rsize) + { + rsize -= offset; + while (rsize--) + aopPut (AOP (result), "!zero", offset++); + } +} + /*-----------------------------------------------------------------*/ /* genGenPointerGet - get value from generic pointer space */ /*-----------------------------------------------------------------*/ @@ -6035,12 +6465,13 @@ genGenPointerGet (operand * left, size = AOP_SIZE (result); - if (isPair (AOP (left)) && size == 1) + if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype)) { /* Just do it */ if (isPtrPair (AOP (left))) { - tsprintf (buffer, "!*pair", getPairName (AOP (left))); + tsprintf (buffer, sizeof(buffer), + "!*pair", getPairName (AOP (left))); aopPut (AOP (result), buffer, 0); } else @@ -6052,14 +6483,14 @@ genGenPointerGet (operand * left, goto release; } - if (getPairId (AOP (left)) == PAIR_IY) + if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype)) { /* Just do it */ offset = 0; while (size--) { char at[20]; - tsprintf (at, "!*iyx", offset); + tsprintf (at, sizeof(at), "!*iyx", offset); aopPut (AOP (result), at, offset); offset++; } @@ -6075,7 +6506,10 @@ genGenPointerGet (operand * left, /* if bit then unpack */ if (IS_BITVAR (retype)) { - wassert (0); + genUnpackBits (result, pair); + freeAsmop (left, NULL, ic); + goto release; + //wassert (0); } else if (getPairId (AOP (result)) == PAIR_HL) { @@ -6175,6 +6609,149 @@ isRegOrLit (asmop * aop) return FALSE; } + +/*-----------------------------------------------------------------*/ +/* genPackBits - generates code for packed bit storage */ +/*-----------------------------------------------------------------*/ +static void +genPackBits (sym_link * etype, + operand * right, + int pair, + iCode *ic) +{ + int offset = 0; /* source byte offset */ + int rlen = 0; /* remaining bitfield length */ + int blen; /* bitfield length */ + int bstr; /* bitfield starting bit within byte */ + int litval; /* source literal value (if AOP_LIT) */ + unsigned char mask; /* bitmask within current byte */ + int extraPair; /* a tempory register */ + bool needPopExtra=0; /* need to restore original value of temp reg */ + + emitDebug ("; genPackBits",""); + + blen = SPEC_BLEN (etype); + bstr = SPEC_BSTR (etype); + + /* If the bitfield length is less than a byte */ + if (blen < 8) + { + mask = ((unsigned char) (0xFF << (blen + bstr)) | + (unsigned char) (0xFF >> (8 - bstr))); + + if (AOP_TYPE (right) == AOP_LIT) + { + /* Case with a bitfield length <8 and literal source + */ + litval = (int) floatFromVal (AOP (right)->aopu.aop_lit); + litval <<= bstr; + litval &= (~mask) & 0xff; + emit2 ("ld a,!*pair", _pairs[pair].name); + if ((mask|litval)!=0xff) + emit2 ("and a,!immedbyte", mask); + if (litval) + emit2 ("or a,!immedbyte", litval); + emit2 ("ld !*pair,a", _pairs[pair].name); + return; + } + else + { + /* Case with a bitfield length <8 and arbitrary source + */ + _moveA (aopGet (AOP (right), 0, FALSE)); + /* shift and mask source value */ + AccLsh (bstr); + emit2 ("and a,!immedbyte", (~mask) & 0xff); + + extraPair = getFreePairId(ic); + if (extraPair == PAIR_INVALID) + { + extraPair = PAIR_BC; + if (getPairId (AOP (right)) != PAIR_BC + || !isLastUse (ic, right)) + { + _push (extraPair); + needPopExtra = 1; + } + } + emit2 ("ld %s,a", _pairs[extraPair].l); + emit2 ("ld a,!*pair", _pairs[pair].name); + + emit2 ("and a,!immedbyte", mask); + emit2 ("or a,%s", _pairs[extraPair].l); + emit2 ("ld !*pair,a", _pairs[pair].name); + if (needPopExtra) + _pop (extraPair); + return; + } + } + + /* Bit length is greater than 7 bits. In this case, copy */ + /* all except the partial byte at the end */ + for (rlen=blen;rlen>=8;rlen-=8) + { + emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) ); + emit2 ("ld !*pair,a", _pairs[pair].name); + if (rlen>8) + { + emit2 ("inc %s", _pairs[pair].name); + _G.pairs[pair].offset++; + } + } + + /* If there was a partial byte at the end */ + if (rlen) + { + mask = (((unsigned char) -1 << rlen) & 0xff); + + if (AOP_TYPE (right) == AOP_LIT) + { + /* Case with partial byte and literal source + */ + litval = (int) floatFromVal (AOP (right)->aopu.aop_lit); + litval >>= (blen-rlen); + litval &= (~mask) & 0xff; + emit2 ("ld a,!*pair", _pairs[pair].name); + if ((mask|litval)!=0xff) + emit2 ("and a,!immedbyte", mask); + if (litval) + emit2 ("or a,!immedbyte", litval); + } + else + { + /* Case with partial byte and arbitrary source + */ + _moveA (aopGet (AOP (right), offset++, FALSE)); + emit2 ("and a,!immedbyte", (~mask) & 0xff); + + extraPair = getFreePairId(ic); + if (extraPair == PAIR_INVALID) + { + extraPair = getPairId (AOP (right)); + if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID)) + extraPair = PAIR_BC; + + if (getPairId (AOP (right)) != PAIR_BC + || !isLastUse (ic, right)) + { + _push (extraPair); + needPopExtra = 1; + } + } + emit2 ("ld %s,a", _pairs[extraPair].l); + emit2 ("ld a,!*pair", _pairs[pair].name); + + emit2 ("and a,!immedbyte", mask); + emit2 ("or a,%s", _pairs[extraPair].l); + if (needPopExtra) + _pop (extraPair); + + } + emit2 ("ld !*pair,a", _pairs[pair].name); + } +} + + /*-----------------------------------------------------------------*/ /* genGenPointerSet - stores the value into a pointer location */ /*-----------------------------------------------------------------*/ @@ -6184,7 +6761,9 @@ genGenPointerSet (operand * right, { int size, offset; sym_link *retype = getSpec (operandType (right)); + sym_link *letype = getSpec (operandType (result)); PAIR_ID pairId = PAIR_HL; + bool isBitvar; aopOp (result, ic, FALSE, FALSE); aopOp (right, ic, FALSE, FALSE); @@ -6194,8 +6773,11 @@ genGenPointerSet (operand * right, size = AOP_SIZE (right); + isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype); + emitDebug("; isBitvar = %d", isBitvar); + /* Handle the exceptions first */ - if (isPair (AOP (result)) && size == 1) + if (isPair (AOP (result)) && size == 1 && !isBitvar) { /* Just do it */ const char *l = aopGet (AOP (right), 0, FALSE); @@ -6212,7 +6794,7 @@ genGenPointerSet (operand * right, goto release; } - if ( getPairId( AOP (result)) == PAIR_IY) + if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar) { /* Just do it */ const char *l = aopGet (AOP (right), 0, FALSE); @@ -6233,7 +6815,8 @@ genGenPointerSet (operand * right, } goto release; } - else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)) + else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result) + && !isBitvar) { offset = 0; @@ -6271,13 +6854,15 @@ genGenPointerSet (operand * right, { fetchPair (pairId, AOP (result)); } - /* so hl know contains the address */ + /* so hl now contains the address */ freeAsmop (result, NULL, ic); /* if bit then unpack */ - if (IS_BITVAR (retype)) + if (isBitvar) { - wassert (0); + genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic); + goto release; + //wassert (0); } else { @@ -6655,7 +7240,7 @@ genCast (iCode * ic) /* now depending on the sign of the destination */ size = AOP_SIZE (result) - AOP_SIZE (right); /* Unsigned or not an integral type - right fill with zeros */ - if (SPEC_USIGN (rtype) || !IS_SPEC (rtype) || AOP_TYPE(right)==AOP_CRY) + if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY) { while (size--) aopPut (AOP (result), "!zero", offset++); @@ -6706,6 +7291,52 @@ genReceive (iCode * ic) freeAsmop (IC_RESULT (ic), NULL, ic); } +/*-----------------------------------------------------------------*/ +/* genDummyRead - generate code for dummy read of volatiles */ +/*-----------------------------------------------------------------*/ +static void +genDummyRead (iCode * ic) +{ + operand *op; + int size, offset; + + op = IC_RIGHT (ic); + if (op && IS_SYMOP (op)) + { + aopOp (op, ic, FALSE, FALSE); + + /* general case */ + size = AOP_SIZE (op); + offset = 0; + + while (size--) + { + _moveA (aopGet (AOP (op), offset, FALSE)); + offset++; + } + + freeAsmop (op, NULL, ic); + } + + op = IC_LEFT (ic); + if (op && IS_SYMOP (op)) + { + aopOp (op, ic, FALSE, FALSE); + + /* general case */ + size = AOP_SIZE (op); + offset = 0; + + while (size--) + { + _moveA (aopGet (AOP (op), offset, FALSE)); + offset++; + } + + freeAsmop (op, NULL, ic); + } +} + enum { /** Maximum number of bytes to emit per line. */ @@ -6816,7 +7447,7 @@ _rleCommit(RLECTX *self) chunks. */ static void -_rleAppend(RLECTX *self, int c) +_rleAppend(RLECTX *self, unsigned c) { int i; @@ -6899,13 +7530,27 @@ genArrayInit (iCode * ic) if (type && type->next) { - elementSize = getSize(type->next); + if (IS_SPEC(type->next) || IS_PTR(type->next)) + { + elementSize = getSize(type->next); + } + else if (IS_ARRAY(type->next) && type->next->next) + { + elementSize = getSize(type->next->next); + } + else + { + printTypeChainRaw (type, NULL); + wassertl (0, "Can't determine element size in genArrayInit."); + } } else { wassertl (0, "Can't determine element size in genArrayInit."); } + wassertl ((elementSize > 0) && (elementSize <= 4), "Illegal element size in genArrayInit."); + iLoop = IC_ARRAYILIST(ic); lastVal = (unsigned)-1; @@ -6918,17 +7563,14 @@ genArrayInit (iCode * ic) { ix = iLoop->count; - if (ix != 0) + for (i = 0; i < ix; i++) { - for (i = 0; i < ix; i++) + for (eIndex = 0; eIndex < elementSize; eIndex++) { - for (eIndex = 0; eIndex < elementSize; eIndex++) - { - val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff; - _rleAppend(&rle, val); - } + val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff; + _rleAppend(&rle, val); } - } + } iLoop = iLoop->next; } @@ -7242,12 +7884,23 @@ genZ80Code (iCode * lic) } _G.lines.head = _G.lines.current = NULL; + + /* if debug information required */ + if (options.debug && currFunc) + { + debugFile->writeFunction (currFunc, lic); + } for (ic = lic; ic; ic = ic->next) { + _G.current_iCode = ic; - if (cln != ic->lineno) + if (ic->lineno && cln != ic->lineno) { + if (options.debug) + { + debugFile->writeCLine (ic); + } if (!options.noCcodeInAsm) { emit2 (";%s:%d: %s", ic->filename, ic->lineno, printCLine(ic->filename, ic->lineno)); @@ -7509,7 +8162,12 @@ genZ80Code (iCode * lic) emitDebug ("; genArrayInit"); genArrayInit(ic); break; - + + case DUMMY_READ_VOLATILE: + emitDebug ("; genDummyRead"); + genDummyRead (ic); + break; + default: ic = ic; } @@ -7577,7 +8235,7 @@ fetchLitSpecial (asmop * aop, bool negate, bool xor) v = 0-v; v &= 0xFFFF; - tsprintf (buffer, "!immedword", v); + tsprintf (buffer, sizeof(buffer), "!immedword", v); return traceAlloc(&_G.trace.aops, Safe_strdup (buffer)); }