Fixed up z80 port so that it works again
[fw/sdcc] / src / z80 / gen.c
index a257244c02d372782576cce1c1eff9edee30180e..2bdd7f38d866f20ce06015c7cacb9dfdeb19362d 100644 (file)
   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
-  Based on the mcs51 generator - Sandeep Dutta . sandeep.dutta@usa.net (1998)
-                           and -  Jean-Louis VERN.jlvern@writeme.com (1999)
+  Based on the mcs51 generator - 
+               Sandeep Dutta . sandeep.dutta@usa.net (1998)
+        and -  Jean-Louis VERN.jlvern@writeme.com (1999)
         
   This program is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the
@@ -141,9 +143,14 @@ static struct {
     struct {
        int last;
        int pushed;
+       int param_offset;
        int offset;
+       int pushed_bc;
+       int pushed_de;
     } stack;
     int frameId;
+    bool flush_statics;
+    bool in_home;
 } _G;
 
 static char *aopGet(asmop *aop, int offset, bool bit16);
@@ -337,7 +344,13 @@ static asmop *newAsmop (short type)
 static asmop *aopForSym (iCode *ic,symbol *sym,bool result, bool requires_a)
 {
     asmop *aop;
-    memmap *space= SPEC_OCLS(sym->etype);
+    memmap *space;
+
+    wassert(ic);
+    wassert(sym);
+    wassert(sym->etype);
+
+    space = SPEC_OCLS(sym->etype);
 
     /* if already has one */
     if (sym->aop)
@@ -561,7 +574,7 @@ static void aopOp (operand *op, iCode *ic, bool result, bool requires_a)
 
     /* if this is a true symbol */
     if (IS_TRUE_SYMOP(op)) {    
-        op->aop = aopForSym(ic,OP_SYMBOL(op),result, requires_a);
+        op->aop = aopForSym(ic, OP_SYMBOL(op), result, requires_a);
         return ;
     }
 
@@ -711,8 +724,10 @@ char *aopGetLitWordLong(asmop *aop, int offset, bool with_hash)
        /* otherwise it is fairly simple */
        if (!IS_FLOAT(val->type)) {
            unsigned long v = floatFromVal(val);
+
            if (offset == 2)
                v >>= 16;
+
            if (with_hash)
                tsprintf(buffer, "!immedword", v);
            else
@@ -790,11 +805,31 @@ static bool requiresHL(asmop *aop)
     }
 }
 
+static char *fetchLitSpecial(asmop *aop, bool negate, bool xor)
+{
+    unsigned long v;
+    value * val = aop->aopu.aop_lit;
+
+    wassert(aop->type == AOP_LIT);
+    wassert(!IS_FLOAT(val->type));
+    
+    v = floatFromVal(val);
+
+    if (xor)
+       v ^= 0x8000;
+    if (negate)
+       v = -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 *pair = _pairs[pairId].name;
-    l = aopGetLitWordLong(left, offset, FALSE);
+    l = aopGetLitWordLong(left, 0, FALSE);
     wassert(l && pair);
 
     if (isPtr(pair)) {
@@ -815,13 +850,21 @@ static void fetchLitPair(PAIR_ID pairId, asmop *left, int offset)
        _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].offset = offset;
+    }
     /* Both a lit on the right and a true symbol on the left */
-    /* PENDING: for re-target */
-#if 0
     if (offset)
-       emit2("ld %s,!hashedstr + %d", pair, l, offset);
-    else 
-#endif
+       emit2("ld %s,!hashedstr + %u", pair, l, offset);
+    else
        emit2("ld %s,!hashedstr", pair, l);
 }
 
@@ -834,9 +877,19 @@ static void fetchPairLong(PAIR_ID pairId, asmop *aop, int offset)
     else { /* we need to get it byte by byte */
        if (pairId == PAIR_HL && IS_GB && requiresHL(aop)) {
            aopGet(aop, offset, FALSE);
-           emit2("!ldahli");
-           emit2("ld h,!*hl");
-           emit2("ld l,a");
+           switch (aop->size) {
+           case 1:
+               emit2("ld l,!*hl");
+               emit2("ld h,!immedbyte", 0);
+               break;
+           case 2:
+               emit2("!ldahli");
+               emit2("ld h,!*hl");
+               emit2("ld l,a");
+               break;
+           default:
+               emit2("; WARNING: mlh woosed out.  This code is invalid.");
+           }
        }
        else if (IS_Z80 && aop->type == AOP_IY) {
            /* Instead of fetching relative to IY, just grab directly
@@ -880,13 +933,16 @@ static void setupPair(PAIR_ID pairId, asmop *aop, int offset)
     case AOP_STK: {
        /* Doesnt include _G.stack.pushed */
        int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
+       if (aop->aopu.aop_stk > 0) {
+           abso += _G.stack.param_offset;
+       }
        assert(pairId == PAIR_HL);
        /* In some cases we can still inc or dec hl */
        if (_G.pairs[pairId].last_type == AOP_STK && abs(_G.pairs[pairId].offset - abso) < 3) {
            adjustPair(_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
        }
        else {
-           emit2("!ldahlsp", aop->aopu.aop_stk+offset + _G.stack.pushed + _G.stack.offset);
+           emit2("!ldahlsp", abso +_G.stack.pushed);
        }
        _G.pairs[pairId].offset = abso;
        break;
@@ -924,12 +980,19 @@ static char *aopGet(asmop *aop, int offset, bool bit16)
        if (bit16) 
            tsprintf (s,"!immedwords", aop->aopu.aop_immd);
        else
-           if (offset) {
-               wassert(offset == 1);
+           switch (offset) {
+           case 2:
+               tsprintf(s, "!bankimmeds", aop->aopu.aop_immd);
+               break;
+           case 1:
+               tsprintf(s, "!msbimmeds", aop->aopu.aop_immd);
+               break;
+           case 0:
                tsprintf(s, "!lsbimmeds", aop->aopu.aop_immd);
+               break;
+           default:
+               wassert(0);
            }
-           else
-               tsprintf(s, "!msbimmeds", aop->aopu.aop_immd);
        ALLOC_ATOMIC(rs,strlen(s)+1);
        strcpy(rs,s);   
        return rs;
@@ -973,7 +1036,9 @@ static char *aopGet(asmop *aop, int offset, bool bit16)
            tsprintf(s, "!*hl");
        }
        else {
-           tsprintf(s,"!*ixx", aop->aopu.aop_stk+offset);
+           if (aop->aopu.aop_stk >= 0)
+               offset += _G.stack.param_offset;
+           tsprintf(s,"!*ixx ; x", aop->aopu.aop_stk+offset);
        }
        ALLOC_ATOMIC(rs,strlen(s)+1);
        strcpy(rs,s);   
@@ -1005,7 +1070,7 @@ static char *aopGet(asmop *aop, int offset, bool bit16)
     exit(0);
 }
 
-bool isRegString(char *s)
+bool isRegString(const char *s)
 {
     if (!strcmp(s, "b") ||
        !strcmp(s, "c") ||
@@ -1024,7 +1089,7 @@ bool isConstant(const char *s)
     return  (*s == '#' || *s == '$');
 }
 
-bool canAssignToPtr(char *s)
+bool canAssignToPtr(const char *s)
 {
     if (isRegString(s))
        return TRUE;
@@ -1036,7 +1101,7 @@ bool canAssignToPtr(char *s)
 /*-----------------------------------------------------------------*/
 /* aopPut - puts a string for a aop                                */
 /*-----------------------------------------------------------------*/
-static void aopPut (asmop *aop, char *s, int offset)
+static void aopPut (asmop *aop, const char *s, int offset)
 {
     if (aop->size && offset > ( aop->size - 1)) {
         werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
@@ -1106,9 +1171,11 @@ static void aopPut (asmop *aop, char *s, int offset)
                emit2("ld !*hl,a");
            }
            else
-               emit2("ld !*hl,%s ; 3", s);
+               emit2("ld !*hl,%s", s);
        }
        else {
+           if (aop->aopu.aop_stk >= 0)
+               offset += _G.stack.param_offset;
            if (!canAssignToPtr(s)) {
                emit2("ld a,%s", s);
                emit2("ld !*ixx,a", aop->aopu.aop_stk+offset);
@@ -1167,6 +1234,20 @@ static void aopPut (asmop *aop, char *s, int offset)
 #define AOP_SIZE(op) AOP(op)->size
 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
 
+static void commitPair(asmop *aop, PAIR_ID id)
+{
+    if (id == PAIR_HL && requiresHL(aop)) {
+       emit2("ld a,l");
+       emit2("ld d,h");
+       aopPut(aop, "a", 0);
+       aopPut(aop, "d", 1);
+    }
+    else {
+       aopPut(aop, _pairs[id].l, 0);
+       aopPut(aop, _pairs[id].h, 1);
+    }
+}
+
 /*-----------------------------------------------------------------*/
 /* getDataSize - get the operand data size                         */
 /*-----------------------------------------------------------------*/
@@ -1220,7 +1301,7 @@ void outAcc(operand *result)
 
 /** Take the value in carry and put it into a register
  */
-void outBitC(operand *result)
+void outBitCLong(operand *result, bool swap_sense)
 {
     /* if the result is bit */
     if (AOP_TYPE(result) == AOP_CRY) {
@@ -1230,10 +1311,17 @@ void outBitC(operand *result)
     else {
        emit2("ld a,!zero");
        emit2("rla");
+       if (swap_sense)
+           emit2("xor a,!immedbyte", 1);
         outAcc(result);
     }
 }
 
+void outBitC(operand *result)
+{
+    outBitCLong(result, FALSE);
+}
+
 /*-----------------------------------------------------------------*/
 /* toBoolean - emit code for orl a,operator(sizeop)                */
 /*-----------------------------------------------------------------*/
@@ -1378,6 +1466,19 @@ release:
     freeAsmop(IC_RESULT(ic),NULL,ic);
 }
 
+static void _push(PAIR_ID pairId)
+{
+    emit2("push %s", _pairs[pairId].name);
+    _G.stack.pushed += 2;
+}
+
+static void _pop(PAIR_ID pairId)
+{
+    emit2("pop %s", _pairs[pairId].name);
+    _G.stack.pushed -= 2;
+}
+
+
 /*-----------------------------------------------------------------*/
 /* assignResultValue -                                            */
 /*-----------------------------------------------------------------*/
@@ -1395,8 +1496,7 @@ void assignResultValue(operand * oper)
 #endif
     if (IS_GB && size == 4 && requiresHL(AOP(oper))) {
        /* We do it the hard way here. */
-       emitcode("push", "hl");
-       _G.stack.pushed += 2;
+       _push(PAIR_HL);
        aopPut(AOP(oper), _fReturn[0], 0);
        aopPut(AOP(oper), _fReturn[1], 1);
        emitcode("pop", "de");
@@ -1419,7 +1519,6 @@ static void genIpush (iCode *ic)
     int size, offset = 0 ;
     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) {
@@ -1536,38 +1635,158 @@ static void genIpop (iCode *ic)
     freeAsmop(IC_LEFT(ic),NULL,ic);
 }
 
+static int _isPairUsed(iCode *ic, PAIR_ID pairId)
+{
+    int ret = 0;
+    switch (pairId) {
+    case PAIR_DE:
+       if (bitVectBitValue(ic->rUsed, D_IDX))
+           ret++;
+       if (bitVectBitValue(ic->rUsed, E_IDX))
+           ret++;
+       break;
+    default:
+       wassert(0);
+    }
+    return ret;
+}
+
+static int _opUsesPair(operand *op, iCode *ic, PAIR_ID pairId)
+{
+    int ret = 0;
+    asmop *aop;
+    symbol *sym = OP_SYMBOL(op);
+
+    if (sym->isspilt || sym->nRegs == 0)
+       return 0;
+
+    aopOp(op, ic, FALSE, FALSE);
+    
+    aop = AOP(op);
+    if (aop->type == AOP_REG) {
+       int i;
+       for (i=0; i < aop->size; i++) {
+           if (pairId == PAIR_DE) {
+               emit2("; 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 {
+               wassert(0);
+           }
+       }
+    }
+
+    freeAsmop(IC_LEFT(ic),NULL,ic);
+    return ret;
+}
+
+/* This is quite unfortunate */
+static void setArea(int inHome)
+{
+    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;
+}
+
 /** Emit the code for a call statement 
  */
-static void emitCall (iCode *ic, bool ispcall)
+static void emitCall(iCode *ic, bool ispcall)
 {
+    int pushed_de = 0;
+    link *detype = getSpec(operandType(IC_LEFT(ic)));
+
     /* if caller saves & we have not saved then */
     if (!ic->regsSaved) {
        /* PENDING */
     }
-
+    
     /* if send set is not empty then assign */
     if (sendSet) {
-       iCode *sic ;
-       for (sic = setFirstItem(sendSet) ; sic ; 
-            sic = setNextItem(sendSet)) {
-           int size, offset = 0;
-           aopOp(IC_LEFT(sic),sic,FALSE, FALSE);
-           size = AOP_SIZE(IC_LEFT(sic));
-           while (size--) {
-               char *l = aopGet(AOP(IC_LEFT(sic)),offset,
-                               FALSE);
-               if (strcmp(l, _fReturn[offset]))
-                   emitcode("ld","%s,%s",
-                            _fReturn[offset],
-                            l);
-               offset++;
+       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) {
+       }
     }
 
     if (ispcall) {
+       if (IS_BANKEDCALL(detype)) {
+           werror(W_INDIR_BANKED);
+       }
        aopOp(IC_LEFT(ic),ic,FALSE, FALSE);
 
        if (isLitWord(AOP(IC_LEFT(ic)))) {
@@ -1577,7 +1796,7 @@ static void emitCall (iCode *ic, bool ispcall)
        else {
            symbol *rlbl = newiTempLabel(NULL);
            spillPair(PAIR_HL);
-           emit2("ld hl,#!tlabel", (rlbl->key+100));
+           emit2("ld hl,!immed!tlabel", (rlbl->key+100));
            emitcode("push", "hl");
            _G.stack.pushed += 2;
            
@@ -1589,11 +1808,18 @@ static void emitCall (iCode *ic, bool ispcall)
        freeAsmop(IC_LEFT(ic),NULL,ic); 
     }
     else {
-       /* make the call */
        char *name = OP_SYMBOL(IC_LEFT(ic))->rname[0] ?
            OP_SYMBOL(IC_LEFT(ic))->rname :
            OP_SYMBOL(IC_LEFT(ic))->name;
-       emitcode("call", "%s", name);
+       if (IS_BANKEDCALL(detype)) {
+           emit2("call banked_call");
+           emit2("!dws", name);
+           emit2("!dw !bankimmeds", name);
+       }
+       else {
+           /* make the call */
+           emit2("call %s", name);
+       }
     }
     spillCached();
 
@@ -1637,7 +1863,8 @@ static void emitCall (iCode *ic, bool ispcall)
            spillCached();
        }
     }
-
+    if (pushed_de)
+       _pop(PAIR_DE);
 }
 
 /*-----------------------------------------------------------------*/
@@ -1645,6 +1872,7 @@ static void emitCall (iCode *ic, bool ispcall)
 /*-----------------------------------------------------------------*/
 static void genCall (iCode *ic)
 {
+    link *detype = getSpec(operandType(IC_LEFT(ic)));
     emitCall(ic, FALSE);
 }
 
@@ -1673,6 +1901,8 @@ static int resultRemat (iCode *ic)
     return 0;
 }
 
+extern set *publics;
+
 /*-----------------------------------------------------------------*/
 /* genFunction - generated code for function entry                 */
 /*-----------------------------------------------------------------*/
@@ -1682,14 +1912,21 @@ static void genFunction (iCode *ic)
     link *fetype;
 
     nregssaved = 0;
+    setArea(IS_NONBANKED(sym->etype));
+
+    /* PENDING: hack */
+    if (!IS_STATIC(sym->etype)) {
+       addSetIfnotP(&publics, sym);
+    }
+
     /* 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 critical function then turn interrupts off */
     if (SPEC_CRTCL(fetype))
        emit2("!di");
@@ -1701,6 +1938,37 @@ static void genFunction (iCode *ic)
     }
     /* 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;
+    if (sym->regsUsed) {
+       int i;
+       for ( i = 0 ; i < sym->regsUsed->size ; i++) {
+           if (bitVectBitValue(sym->regsUsed, i)) {
+               switch (i) {
+               case C_IDX:
+               case B_IDX:
+                   _G.stack.pushed_bc = 1;
+                   break;
+               case D_IDX:
+               case E_IDX:
+                   if (IS_Z80)
+                       _G.stack.pushed_de = 1;
+                   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;
+       }
+    }
+
     /* adjust the stack for the function */
     _G.stack.last = sym->stack;
 
@@ -1743,9 +2011,18 @@ static void genEndFunction (iCode *ic)
            emit2("!leavex", _G.stack.offset);
        else
            emit2("!leave");
+
+       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.stack.pushed = 0;
     _G.stack.offset = 0;
 }
@@ -1973,6 +2250,8 @@ static void genPlus (iCode *ic)
     if (genPlusIncr (ic) == TRUE)
         goto release;   
 
+    emit2("; genPlusIncr failed");
+
     size = getDataSize(IC_RESULT(ic));
 
     /* Special case when left and right are constant */
@@ -1999,38 +2278,86 @@ static void genPlus (iCode *ic)
        goto release;
     }
 
+    /* Special case:
+       ld hl,sp+n trashes C so we cant afford to do it during an
+       add with stack based varibles.  Worst case is:
+               ld  hl,sp+left
+       ld  a,(hl)
+       ld  hl,sp+right
+       add (hl)
+       ld  hl,sp+result
+       ld  (hl),a
+       ld  hl,sp+left+1
+       ld  a,(hl)
+       ld  hl,sp+right+1
+       adc (hl)
+       ld  hl,sp+result+1
+       ld  (hl),a
+       So you cant afford to load up hl if either left, right, or result
+       is on the stack (*sigh*)  The alt is:
+       ld  hl,sp+left
+       ld  de,(hl)
+       ld  hl,sp+right
+       ld  hl,(hl)
+       add hl,de
+       ld  hl,sp+result
+       ld  (hl),hl
+       Combinations in here are:
+        * If left or right are in bc then the loss is small - trap later
+        * If the result is in bc then the loss is also small
+    */
+    if (IS_GB) {
+       if (AOP_TYPE(IC_LEFT(ic)) == AOP_STK ||
+           AOP_TYPE(IC_RIGHT(ic)) == AOP_STK ||
+           AOP_TYPE(IC_RESULT(ic)) == AOP_STK) {
+           if ((AOP_SIZE(IC_LEFT(ic)) == 2 ||
+               AOP_SIZE(IC_RIGHT(ic)) == 2) &&
+               (AOP_SIZE(IC_LEFT(ic)) <= 2 &&
+                AOP_SIZE(IC_RIGHT(ic)) <= 2)) {
+               if (getPairId(AOP(IC_RIGHT(ic))) == PAIR_BC) {
+                   /* Swap left and right */
+                   operand *t = IC_RIGHT(ic);
+                   IC_RIGHT(ic) = IC_LEFT(ic);
+                   IC_LEFT(ic) = t;
+               }
+               if (getPairId(AOP(IC_LEFT(ic))) == PAIR_BC) {
+                   fetchPair(PAIR_HL, AOP(IC_RIGHT(ic)));
+                   emit2("add hl,bc");
+               }
+               else {
+                   fetchPair(PAIR_DE, AOP(IC_LEFT(ic)));
+                   fetchPair(PAIR_HL, AOP(IC_RIGHT(ic)));
+                   emit2("add hl,de");
+               }
+               commitPair(AOP(IC_RESULT(ic)), PAIR_HL);
+               goto release;
+           }
+           else if (size == 4) {
+               emit2("; WARNING: This add is probably broken.\n");
+           }
+       }
+    }
+
     while(size--) {
        if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC) {
            MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
            if(offset == 0)
-               emitcode("add","a,%s",
-                        aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
+               emit2("add a,%s",
+                     aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
            else
-               emitcode("adc","a,%s",
-                        aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
+               emit2("adc a,%s",
+                     aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
        } else {
            MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
            if(offset == 0)
-               emitcode("add","a,%s",
-                        aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
+               emit2("add a,%s",
+                     aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
            else
-               emitcode("adc","a,%s",
-                        aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
+               emit2("adc a,%s",
+                     aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
        }
-        aopPut(AOP(IC_RESULT(ic)),"a",offset++);      
+       aopPut(AOP(IC_RESULT(ic)),"a",offset++);      
     }
-
-    /* Some kind of pointer arith. */
-    if (AOP_SIZE(IC_RESULT(ic)) == 3 && 
-       AOP_SIZE(IC_LEFT(ic)) == 3   &&
-       !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))))
-       wassert(0);
-
-     if (AOP_SIZE(IC_RESULT(ic)) == 3 && 
-       AOP_SIZE(IC_RIGHT(ic)) == 3   &&
-       !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_RIGHT(ic))))
-        wassert(0);
-
    
 release:
     freeAsmop(IC_LEFT(ic),NULL,ic);
@@ -2143,7 +2470,47 @@ static void genMinus (iCode *ic)
         lit = - (long)lit;
     }
 
-
+    /* Same logic as genPlus */
+    if (IS_GB) {
+       if (AOP_TYPE(IC_LEFT(ic)) == AOP_STK ||
+           AOP_TYPE(IC_RIGHT(ic)) == AOP_STK ||
+           AOP_TYPE(IC_RESULT(ic)) == AOP_STK) {
+           if ((AOP_SIZE(IC_LEFT(ic)) == 2 ||
+               AOP_SIZE(IC_RIGHT(ic)) == 2) &&
+               (AOP_SIZE(IC_LEFT(ic)) <= 2 &&
+                AOP_SIZE(IC_RIGHT(ic)) <= 2)) {
+               PAIR_ID left = getPairId(AOP(IC_LEFT(ic)));
+               PAIR_ID right = getPairId(AOP(IC_RIGHT(ic)));
+
+               if (left == PAIR_INVALID && right == PAIR_INVALID) {
+                   left = PAIR_DE;
+                   right = PAIR_HL;
+               }
+               else if (right == PAIR_INVALID)
+                   right = PAIR_DE;
+               else if (left == PAIR_INVALID)
+                   left = PAIR_DE;
+               
+               fetchPair(left, AOP(IC_LEFT(ic)));
+               /* Order is important.  Right may be HL */
+               fetchPair(right, AOP(IC_RIGHT(ic)));
+
+               emit2("ld a,%s", _pairs[left].l);
+               emit2("sub a,%s", _pairs[right].l);
+               emit2("ld e,a");
+               emit2("ld a,%s", _pairs[left].h);
+               emit2("sbc a,%s", _pairs[right].h);
+
+               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 literal, add a,#-lit, else normal subb */
     while (size--) {
        MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE));    
@@ -2213,7 +2580,7 @@ static void genIfxJump (iCode *ic, char *jval)
 
     /* if true label then we jump if condition
     supplied is true */
-    if ( IC_TRUE(ic) ) {
+    if (IC_TRUE(ic)) {
         jlbl = IC_TRUE(ic);
        if (!strcmp(jval, "a")) {
            inst = "nz";
@@ -2221,6 +2588,9 @@ static void genIfxJump (iCode *ic, char *jval)
        else if (!strcmp(jval, "c")) {
            inst = "c";
        }
+       else if (!strcmp(jval, "nc")) {
+           inst = "nc";
+       }
        else {
            /* The buffer contains the bit on A that we should test */
            inst = "nz";
@@ -2235,6 +2605,9 @@ static void genIfxJump (iCode *ic, char *jval)
        else if (!strcmp(jval, "c")) {
            inst = "nc";
        }
+       else if (!strcmp(jval, "nc")) {
+           inst = "c";
+       }
        else {
            /* The buffer contains the bit on A that we should test */
            inst = "z";
@@ -2246,6 +2619,8 @@ static void genIfxJump (iCode *ic, char *jval)
     }
     else if (!strcmp(jval, "c")) {
     }
+    else if (!strcmp(jval, "nc")) {
+    }
     else {
        emitcode("bit", "%s,a", jval);
     }
@@ -2255,6 +2630,11 @@ static void genIfxJump (iCode *ic, char *jval)
     ic->generated = 1;
 }
 
+static const char *_getPairIdName(PAIR_ID id)
+{
+    return _pairs[id].name;
+}
+
 /** Generic compare for > or <
  */
 static void genCmp (operand *left,operand *right,
@@ -2262,6 +2642,7 @@ static void genCmp (operand *left,operand *right,
 {
     int size, offset = 0 ;
     unsigned long lit = 0L;
+    bool swap_sense = FALSE;
 
     /* if left & right are bit variables */
     if (AOP_TYPE(left) == AOP_CRY &&
@@ -2286,6 +2667,40 @@ static void genCmp (operand *left,operand *right,
                emitcode("cp", "%s", aopGet(AOP(right), offset, FALSE));
         } 
        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);
                 /* optimize if(x < 0) or if(x >= 0) */
@@ -2359,15 +2774,15 @@ static void genCmp (operand *left,operand *right,
 
 release:
     if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) {
-        outBitC(result);
+        outBitCLong(result, swap_sense);
     } else {
         /* if the result is used in the next
         ifx conditional branch then generate
         code a little differently */
-        if (ifx )
-            genIfxJump (ifx,"c");
+        if (ifx)
+            genIfxJump(ifx, swap_sense ? "nc" : "c");
         else
-            outBitC(result);
+            outBitCLong(result, swap_sense);
         /* leave the result in acc */
     }
 }
@@ -3218,11 +3633,12 @@ static void shiftR2Left2Result (operand *left, int offl,
            symbol *tlbl , *tlbl1;
            char *l;
 
+           tlbl = newiTempLabel(NULL);
+           tlbl1 = newiTempLabel(NULL);
+               
            /* Left is already in result - so now do the shift */
            if (shCount>1) {
                emit2("ld a,!immedbyte+1", shCount);
-               tlbl = newiTempLabel(NULL);
-               tlbl1 = newiTempLabel(NULL);
                emit2("!shortjp !tlabel", tlbl1->key+100); 
                emitLabel(tlbl->key+100);    
            }
@@ -3263,11 +3679,12 @@ static void shiftL2Left2Result (operand *left, int offl,
        symbol *tlbl , *tlbl1;
        char *l;
 
+       tlbl = newiTempLabel(NULL);
+       tlbl1 = newiTempLabel(NULL);
+
        /* Left is already in result - so now do the shift */
        if (shCount>1) {
            emit2("ld a,!immedbyte+1", shCount);
-           tlbl = newiTempLabel(NULL);
-           tlbl1 = newiTempLabel(NULL);
            emit2("!shortjp !tlabel", tlbl1->key+100); 
            emitLabel(tlbl->key+100);    
        }
@@ -3332,19 +3749,19 @@ static void AccRol (int shCount)
 /*-----------------------------------------------------------------*/
 static void AccLsh (int shCount)
 {
-    if(shCount != 0){
-        if(shCount == 1)
-            emitcode("add","a,a");
-        else 
-           if(shCount == 2) {
+    if(shCount != 0) {
+        if(shCount == 1) {
             emitcode("add","a,a");
-            emitcode("add","a,a");
-        } else {
-            /* rotate left accumulator */
-            AccRol(shCount);
-            /* and kill the lower order bits */
-            emit2("and a,!immedbyte", SLMask[shCount]);
-        }
+       }
+        else if(shCount == 2) {
+           emitcode("add","a,a");
+           emitcode("add","a,a");
+       } else {
+           /* rotate left accumulator */
+           AccRol(shCount);
+           /* and kill the lower order bits */
+           emit2("and a,!immedbyte", SLMask[shCount]);
+       }
     }
 }
 
@@ -3375,19 +3792,20 @@ static void genlshTwo (operand *result,operand *left, int shCount)
     /* if shCount >= 8 */
     if (shCount >= 8) {
         shCount -= 8 ;
-
         if (size > 1){
             if (shCount) {
                 movLeft2Result(left, LSB, result, MSB16, 0);
                aopPut(AOP(result),zero, 0);   
-               shiftL1Left2Result(left, MSB16, result, MSB16, shCount-8);
+               shiftL1Left2Result(left, MSB16, result, MSB16, shCount);
            }
             else {
                 movLeft2Result(left, LSB, result, MSB16, 0);
                aopPut(AOP(result),zero, 0);   
            }
         }
-        aopPut(AOP(result),zero,LSB);   
+       else {
+           aopPut(AOP(result),zero,LSB);   
+       }
     }
     /*  1 <= shCount <= 7 */
     else {  
@@ -3537,7 +3955,7 @@ static void genLeftShift (iCode *ic)
 }
 
 /*-----------------------------------------------------------------*/
-/* genlshTwo - left shift two bytes by known amount != 0           */
+/* genrshOne - left shift two bytes by known amount != 0           */
 /*-----------------------------------------------------------------*/
 static void genrshOne (operand *result,operand *left, int shCount)
 {
@@ -3570,15 +3988,10 @@ static void genrshOne (operand *result,operand *left, int shCount)
 static void AccRsh (int shCount)
 {
     if(shCount != 0){
-        if(shCount == 1){
-            CLRC;
-            emitcode("rr","a");
-        } else {
-            /* rotate right accumulator */
-            AccRol(8 - shCount);
-            /* and kill the higher order bits */
-            emit2("and a,!immedbyte", SRMask[shCount]);
-        }
+       /* rotate right accumulator */
+       AccRol(8 - shCount);
+       /* and kill the higher order bits */
+       emit2("and a,!immedbyte", SRMask[shCount]);
     }
 }
 
@@ -3607,15 +4020,15 @@ static void genrshTwo (operand *result,operand *left,
 {
     /* if shCount >= 8 */
     if (shCount >= 8) {
-        shCount -= 8 ;
+        shCount -= 8;
         if (shCount) {
             shiftR1Left2Result(left, MSB16, result, LSB,
                                shCount, sign);
        }
         else {
             movLeft2Result(left, MSB16, result, LSB, sign);
-           aopPut(AOP(result),zero,1);
        }
+       aopPut(AOP(result),zero,1);
     }
     /*  1 <= shCount <= 7 */
     else {
@@ -3760,7 +4173,7 @@ static void genRightShift (iCode *ic)
 }
 
 /*-----------------------------------------------------------------*/
-/* genGenPointerGet - gget value from generic pointer space        */
+/* genGenPointerGet -  get value from generic pointer space        */
 /*-----------------------------------------------------------------*/
 static void genGenPointerGet (operand *left,
                               operand *result, iCode *ic)
@@ -3816,6 +4229,7 @@ static void genGenPointerGet (operand *left,
            }
            if (size) {
                emit2("inc %s", _pairs[pair].name);
+               _G.pairs[pair].offset++;
            }
         }
     }
@@ -3908,6 +4322,7 @@ static void genGenPointerSet (operand *right,
            }
            if (size) {
                emitcode("inc", _pairs[pairId].name);
+               _G.pairs[pairId].offset++;
            }
            offset++;
         }
@@ -3985,12 +4400,17 @@ static void genAddrOf (iCode *ic)
     if (IS_GB) {
        if (sym->onStack) {
            spillCached();
-           emit2("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset);
+           if (sym->stack <= 0) {
+               emit2("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset);
+           }
+           else {
+               emit2("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
+           }
            emitcode("ld", "d,h");
            emitcode("ld", "e,l");
        }
        else {
-           emitcode("ld", "de,#%s", sym->rname);
+           emit2("ld de,!hashedstr", sym->rname);
        }
        aopPut(AOP(IC_RESULT(ic)), "e", 0);
        aopPut(AOP(IC_RESULT(ic)), "d", 1);
@@ -3999,7 +4419,10 @@ static void genAddrOf (iCode *ic)
        spillCached();
        if (sym->onStack) {
            /* if it has an offset  then we need to compute it */
-           emitcode("ld", "hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
+           if (sym->stack > 0) 
+               emitcode("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");
        }
        else {
@@ -4540,7 +4963,17 @@ void genZ80Code (iCode *lic)
     if (!options.nopeep)
        peepHole (&lineHead);
 
+    /* This is unfortunate */
     /* now do the actual printing */
-    printLine (lineHead,codeOutFile);
-    return;
+    {
+       FILE *fp = codeOutFile;
+       if (isInHome() && codeOutFile == code->oFile)
+           codeOutFile = home->oFile;
+       printLine (lineHead, codeOutFile);
+       if (_G.flush_statics) {
+           flushStatics();
+           _G.flush_statics = 0;
+       }
+       codeOutFile = fp;
+    }
 }