/*-------------------------------------------------------------------------
  genarith.c - source file for code generation - arithmetic 
  
  Written By -  Sandeep Dutta . sandeep.dutta@usa.net (1998)
         and -  Jean-Louis VERN.jlvern@writeme.com (1999)
  Bug Fixes  -  Wojciech Stryjewski  wstryj1@tiger.lsu.edu (1999 v2.1.9a)
  PIC port   -  Scott Dattalo scott@dattalo.com (2000)
  
  This program is free software; you can redistribute it and/or modify it
  under the terms of the GNU General Public License as published by the
  Free Software Foundation; either version 2, or (at your option) any
  later version.
  
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
  
  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  
  In other words, you are welcome to use, share and improve this program.
  You are forbidden to forbid anyone else to use, share and improve
  what you give them.   Help stamp out software-hoarding!
  
  Notes:
  000123 mlh  Moved aopLiteral to SDCCglue.c to help the split
      Made everything static
-------------------------------------------------------------------------*/

#include "common.h"
#include "newalloc.h"
//#include "SDCCglobl.h"
//#include "SDCCpeeph.h"

#include "gen.h"
#include "pcode.h"
#include "ralloc.h"


#define BYTEofLONG(l,b) ( (l>> (b<<3)) & 0xff)

const char *AopType(short type)
{
        switch(type) {
        case AOP_LIT:
                return "AOP_LIT";
                break;
        case AOP_REG:
                return "AOP_REG";
                break;
        case AOP_DIR:
                return "AOP_DIR";
                break;
        case AOP_STK:
                return "AOP_STK";
                break;
        case AOP_IMMD:
                return "AOP_IMMD";
                break;
        case AOP_STR:
                return "AOP_STR";
                break;
        case AOP_CRY:
                return "AOP_CRY";
                break;
        case AOP_PCODE:
                return "AOP_PCODE";
                break;
        }
        
        return "BAD TYPE";
}

const char *pCodeOpType(pCodeOp *pcop)
{
        
        if(pcop) {
                
                switch(pcop->type) {
                        
                case  PO_NONE:
                        return "PO_NONE";
                case  PO_W:
                        return  "PO_W";
                case  PO_STATUS:
                        return  "PO_STATUS";
                case  PO_FSR:
                        return  "PO_FSR";
                case  PO_INDF:
                        return  "PO_INDF";
                case  PO_INTCON:
                        return  "PO_INTCON";
                case  PO_GPR_REGISTER:
                        return  "PO_GPR_REGISTER";
                case  PO_GPR_POINTER:
                        return  "PO_GPR_POINTER";
                case  PO_GPR_BIT:
                        return  "PO_GPR_BIT";
                case  PO_GPR_TEMP:
                        return  "PO_GPR_TEMP";
                case  PO_SFR_REGISTER:
                        return  "PO_SFR_REGISTER";
                case  PO_PCL:
                        return  "PO_PCL";
                case  PO_PCLATH:
                        return  "PO_PCLATH";
                case  PO_LITERAL:
                        return  "PO_LITERAL";
                case  PO_IMMEDIATE:
                        return  "PO_IMMEDIATE";
                case  PO_DIR:
                        return  "PO_DIR";
                case  PO_CRY:
                        return  "PO_CRY";
                case  PO_BIT:
                        return  "PO_BIT";
                case  PO_STR:
                        return  "PO_STR";
                case  PO_LABEL:
                        return  "PO_LABEL";
                case  PO_WILD:
                        return  "PO_WILD";
                }
        }
        
        return "BAD PO_TYPE";
}

/*-----------------------------------------------------------------*/
/* pic14_sameRegs - two asmops have the same registers             */
/*-----------------------------------------------------------------*/
static bool
_isSameReg (asmop * aop1, asmop * aop2, int offset)
{
  if (aop1 == aop2)
    return TRUE;

  if (aop1->type != AOP_REG || aop2->type != AOP_REG)
    return FALSE;

  if (aop1->size <= offset || aop2->size <= offset)
    return FALSE;

    if (aop1->aopu.aop_reg[offset] != aop2->aopu.aop_reg[offset])
      return FALSE;

  return TRUE;
}

/*-----------------------------------------------------------------*/
/* genPlusIncr :- does addition with increment if possible         */
/*-----------------------------------------------------------------*/
static bool genPlusIncr (iCode *ic)
{
        unsigned int icount ;
        unsigned int size = pic14_getDataSize(IC_RESULT(ic));
        FENTRY;
        
        DEBUGpic14_emitcode ("; ***","%s  %d",__FUNCTION__,__LINE__);
        DEBUGpic14_emitcode ("; ","result %s, left %s, right %s",
                AopType(AOP_TYPE(IC_RESULT(ic))),
                AopType(AOP_TYPE(IC_LEFT(ic))),
                AopType(AOP_TYPE(IC_RIGHT(ic))));
        
        /* will try to generate an increment */
        /* if the right side is not a literal 
        we cannot */
        if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
                return FALSE ;
        
        DEBUGpic14_emitcode ("; ","%s  %d",__FUNCTION__,__LINE__);
        /* if the literal value of the right hand side
        is greater than 1 then it is faster to add */
        if ((icount = (unsigned int) ulFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit)) > 2)
                return FALSE ;
        
        /* if increment 16 bits in register */
        if (pic14_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
                (icount == 1)) {
                
                int offset = MSB16;
                
                emitpcode(POC_INCF, popGet(AOP(IC_RESULT(ic)),LSB));
                //pic14_emitcode("incf","%s,f",aopGet(AOP(IC_RESULT(ic)),LSB,FALSE,FALSE));
                
                while(--size) {
                        emitSKPNZ;
                        emitpcode(POC_INCF, popGet(AOP(IC_RESULT(ic)),offset++));
                        //pic14_emitcode(" incf","%s,f",aopGet(AOP(IC_RESULT(ic)),offset++,FALSE,FALSE));
                }
                
                return TRUE;
        }
        
        DEBUGpic14_emitcode ("; ","%s  %d",__FUNCTION__,__LINE__);
        /* if left is in accumulator  - probably a bit operation*/
        if( strcmp(aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE),"a")  &&
                (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY) ) {
                
                emitpcode(POC_BCF, popGet(AOP(IC_RESULT(ic)),0));
                pic14_emitcode("bcf","(%s >> 3), (%s & 7)",
                        AOP(IC_RESULT(ic))->aopu.aop_dir,
                        AOP(IC_RESULT(ic))->aopu.aop_dir);
                if(icount)
                        emitpcode(POC_XORLW,popGetLit(1));
                //pic14_emitcode("xorlw","1");
                else
                        emitpcode(POC_ANDLW,popGetLit(1));
                //pic14_emitcode("andlw","1");
                
                emitSKPZ;
                emitpcode(POC_BSF, popGet(AOP(IC_RESULT(ic)),0));
                pic14_emitcode("bsf","(%s >> 3), (%s & 7)",
                        AOP(IC_RESULT(ic))->aopu.aop_dir,
                        AOP(IC_RESULT(ic))->aopu.aop_dir);
                
                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   )
                return FALSE ;
        
        /* If we are incrementing the same register by two: */
        
        if (pic14_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) {
                
                while (icount--) 
                        emitpcode(POC_INCF, popGet(AOP(IC_RESULT(ic)),0));
                //pic14_emitcode("incf","%s,f",aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE));
                
                return TRUE ;
        }
        
        DEBUGpic14_emitcode ("; ","couldn't increment ");
        
        return FALSE ;
}

/*-----------------------------------------------------------------*/
/* genAddlit - generates code for addition                         */
/*-----------------------------------------------------------------*/
static void genAddLit2byte (operand *result, int offr, int lit)
{
        FENTRY;
        
        switch(lit & 0xff) {
        case 0:
                break;
        case 1:
                emitpcode(POC_INCF, popGet(AOP(result),offr));
                break;
        case 0xff:
                emitpcode(POC_DECF, popGet(AOP(result),offr));
                break;
        default:
                emitpcode(POC_MOVLW,popGetLit(lit&0xff));
                emitpcode(POC_ADDWF,popGet(AOP(result),offr));
        }
        
}

static void emitMOVWF(operand *reg, int offset)
{
        FENTRY;
        if(!reg)
                return;
        
        emitpcode(POC_MOVWF, popGet(AOP(reg),offset));
        
}

static void genAddLit (iCode *ic, int lit)
{
  int size, same;
  int lo;

  operand *result;
  operand *left;

  FENTRY;
  DEBUGpic14_emitcode ("; ***","%s  %d",__FUNCTION__,__LINE__);

  left = IC_LEFT(ic);
  result = IC_RESULT(ic);
  same = pic14_sameRegs(AOP(left), AOP(result));
  size = pic14_getDataSize(result);
  if (size > pic14_getDataSize(left))
    {
      size = pic14_getDataSize(left);
    }

  if (size < 1)
    {
      printf("FIXME: size %d in genAddLit ic key %d lit %d (%s:%d)\n", size, ic->key, lit, ic->filename, ic->lineno);
      return;
    }

  /*
   * Fix accessing libsdcc/<*>/idata.c:_cinit in __code space.
   */
  if ((AOP_TYPE (left) == AOP_PCODE) && (AOP (left)->aopu.pcop->type == PO_IMMEDIATE))
    {
      int u;
      if (debug_verbose)
        {
          emitpComment("%s:%u: using address of '%s' instead of contents",
                 ic->filename, ic->lineno,
                 popGetAddr(AOP(IC_LEFT(ic)), 0, lit & 0xff)->name);
        } // if
      for (u = 0; u < size; ++u)
        {
          emitpcode(POC_MOVLW, popGetAddr(AOP(IC_LEFT(ic)), u, lit));
          emitpcode(POC_MOVWF, popGet(AOP(IC_RESULT(ic)), u));
        } // for

      if (size < pic14_getDataSize(result))
        {
          for (u = size; u < pic14_getDataSize(result); ++u)
            {
              /* XXX: Might fail for u >= size?!? */
              emitpcode(POC_MOVLW, popGetAddr(AOP(IC_LEFT(ic)), u, lit));
              emitpcode(POC_MOVWF, popGet(AOP(IC_RESULT(ic)), u));
            } // for
        } // if

      goto out;
    } // if

  if (same)
    {
      /* Handle special cases first */
      if (size == 1) 
        {
          genAddLit2byte (result, 0, lit);
        }
      else if (size == 2)
        {
          int hi = (lit >> 8) & 0xff;
          lo = lit & 0xff;

          switch (hi)
            {
              case 0: 
                  /* lit = 0x00LL */
                  DEBUGpic14_emitcode ("; hi = 0","%s  %d",__FUNCTION__,__LINE__);
                  switch (lo)
                    {
                      case 0:
                          break;
                      case 1:
                          emitpcode(POC_INCF, popGet(AOP(result),0));
                          emitSKPNZ;
                          emitpcode(POC_INCF, popGet(AOP(result),MSB16));
                          break;
                      case 0xff:
                          emitpcode(POC_DECF, popGet(AOP(result),0));
                          emitpcode(POC_INCFSZW, popGet(AOP(result),0));
                          emitpcode(POC_INCF, popGet(AOP(result),MSB16));
                          break;
                      default:
                          emitpcode(POC_MOVLW,popGetLit(lit&0xff));
                          emitpcode(POC_ADDWF,popGet(AOP(result),0));
                          emitSKPNC;
                          emitpcode(POC_INCF, popGet(AOP(result),MSB16));
                          break;
                    } // switch
                  break;

              case 1:
                  /* lit = 0x01LL */
                  DEBUGpic14_emitcode ("; hi = 1","%s  %d",__FUNCTION__,__LINE__);
                  switch (lo)
                    {
                      case 0:  /* 0x0100 */
                          emitpcode(POC_INCF, popGet(AOP(result),MSB16));
                          break;
                      case 1:  /* 0x0101  */
                          emitpcode(POC_INCF, popGet(AOP(result),MSB16));
                          emitpcode(POC_INCF, popGet(AOP(result),0));
                          emitSKPNZ;
                          emitpcode(POC_INCF, popGet(AOP(result),MSB16));
                          break;
                      case 0xff: /* 0x01ff */
                          emitpcode(POC_DECF, popGet(AOP(result),0));
                          emitpcode(POC_INCFSZW, popGet(AOP(result),0));
                          emitpcode(POC_INCF, popGet(AOP(result),MSB16));
                          emitpcode(POC_INCF, popGet(AOP(result),MSB16));
                          break;
                      default:
                          emitpcode(POC_MOVLW, popGetLit(lo));
                          emitpcode(POC_ADDWF, popGet(AOP(result),0));
                          emitSKPNC;
                          emitpcode(POC_INCF, popGet(AOP(result),MSB16));
                          emitpcode(POC_INCF, popGet(AOP(result),MSB16));
                          break;
                    }    // switch
                  break;

              case 0xff:
                  DEBUGpic14_emitcode ("; hi = ff","%s  %d",__FUNCTION__,__LINE__);
                  /* lit = 0xffLL */
                  switch (lo)
                    {
                      case 0:  /* 0xff00 */
                          emitpcode(POC_DECF, popGet(AOP(result),MSB16));
                          break;
                      case 1:  /*0xff01 */
                          emitpcode(POC_INCFSZ, popGet(AOP(result),0));
                          emitpcode(POC_DECF, popGet(AOP(result),MSB16));
                          break;
                      default:
                          emitpcode(POC_MOVLW,popGetLit(lo));
                          emitpcode(POC_ADDWF,popGet(AOP(result),0));
                          emitSKPC;
                          emitpcode(POC_DECF, popGet(AOP(result),MSB16));
                          break;
                    } // switch
                  break;

              default:
                  DEBUGpic14_emitcode ("; hi is generic","%d   %s  %d",hi,__FUNCTION__,__LINE__);

                  /* lit = 0xHHLL */
                  switch (lo)
                    {
                      case 0:  /* 0xHH00 */
                          genAddLit2byte (result, MSB16, hi);
                          break;
                      case 1:  /* 0xHH01 */
                          emitpcode(POC_MOVLW,popGetLit((hi+1)&0xff));
                          emitpcode(POC_INCFSZ, popGet(AOP(result),0));
                          emitpcode(POC_MOVLW,popGetLit(hi));
                          emitpcode(POC_ADDWF,popGet(AOP(result),MSB16));
                          break;
                      default:  /* 0xHHLL */
                          emitpcode(POC_MOVLW,popGetLit(lo));
                          emitpcode(POC_ADDWF, popGet(AOP(result),0));
                          emitpcode(POC_MOVLW,popGetLit(hi));
                          emitSKPNC;
                          emitpcode(POC_MOVLW,popGetLit((hi+1) & 0xff));
                          emitpcode(POC_ADDWF,popGet(AOP(result),MSB16));
                          break;
                    } // switch
                  break;
            } // switch
        }
      else
        {
          int carry_info = 0;
          int offset = 0;
          /* size > 2 */
          DEBUGpic14_emitcode (";  add lit to long","%s  %d",__FUNCTION__,__LINE__);

          while (size--)
            {
              lo = BYTEofLONG(lit,0);

              if (carry_info)
                {
                  switch (lo)
                    {
                      case 0:
                          switch (carry_info)
                            {
                              case 1:
                                  emitSKPNZ;
                                  emitpcode(POC_INCF, popGet(AOP(result),offset));
                                  break;
                              case 2:
                                  emitpcode(POC_RLFW, popGet(AOP(result),offset));
                                  emitpcode(POC_ANDLW,popGetLit(1));
                                  emitpcode(POC_ADDWF, popGet(AOP(result),offset));
                                  break;
                              default: /* carry_info = 3  */
                                  emitSKPNC;
                                  emitpcode(POC_INCF, popGet(AOP(result),offset));
                                  carry_info = 1;
                                  break;
                            } // switch
                          break;
                      case 0xff:
                          emitpcode(POC_MOVLW,popGetLit(lo));
                          if (carry_info==1) 
                            emitSKPZ;
                          else
                            emitSKPC;
                          emitpcode(POC_ADDWF, popGet(AOP(result),offset));
                          break;
                      default:
                          emitpcode(POC_MOVLW,popGetLit(lo));
                          if (carry_info==1) 
                            emitSKPNZ;
                          else
                            emitSKPNC;
                          emitpcode(POC_MOVLW,popGetLit(lo+1));
                          emitpcode(POC_ADDWF, popGet(AOP(result),offset));
                          carry_info=2;
                          break;
                    } // switch
                }
              else
                {
                  /* no carry info from previous step */
                  /* this means this is the first time to add */
                  switch (lo)
                    {
                      case 0:
                          break;
                      case 1:
                          emitpcode(POC_INCF, popGet(AOP(result),offset));
                          carry_info=1;
                          break;
                      default:
                          emitpcode(POC_MOVLW,popGetLit(lo));
                          emitpcode(POC_ADDWF, popGet(AOP(result),offset));
                          if (lit <0x100) 
                            carry_info = 3;  /* Were adding only one byte and propogating the carry */
                          else
                            carry_info = 2;
                          break;
                    } // switch
                } // if
              offset++;
              lit >>= 8;
            } // while
        } // if
    }
  else
    {
      int offset = 1;
      DEBUGpic14_emitcode (";  left and result aren't same","%s  %d",__FUNCTION__,__LINE__);

      if (size == 1)
        {
          /* left addend is in a register */
          switch (lit & 0xff)
            {
              case 0:
                  if (!_isSameReg(AOP(left), AOP(result), 0))
                    {
                  emitpcode(POC_MOVFW, popGet(AOP(left),0));
                  emitMOVWF(result,0);
                    }
                  break;
              case 1:
                  if (_isSameReg(AOP(left), AOP(result), 0))
                    {
                  emitpcode(POC_INCF, popGet(AOP(left),0));
                    }
                  else
                    {
                  emitpcode(POC_INCFW, popGet(AOP(left),0));
                  emitMOVWF(result,0);
                    }
                  break;
              case 0xff:
                  if (_isSameReg(AOP(left), AOP(result), 0))
                    {
                  emitpcode(POC_DECF, popGet(AOP(left),0));
                    }
                  else
                    {
                  emitpcode(POC_DECFW, popGet(AOP(left),0));
                  emitMOVWF(result,0);
                    }
                  break;
              default:
                  if (_isSameReg(AOP(left), AOP(result), 0))
                    {
                  emitpcode(POC_MOVLW, popGetLit(lit & 0xff));
                  emitpcode(POC_ADDWF, popGet(AOP(left),0));
                    }
                  else
                  {
                  emitpcode(POC_MOVLW, popGetLit(lit & 0xff));
                  emitpcode(POC_ADDFW, popGet(AOP(left),0));
                  emitMOVWF(result,0);
                  }
            } // switch
        }
      else
        {
          int clear_carry=0;

          /* left is not the accumulator */
          if (lit & 0xff)
            {
                  if (_isSameReg(AOP(left), AOP(result), 0))
                    {
                  emitpcode(POC_MOVLW, popGetLit(lit & 0xff));
                  emitpcode(POC_ADDWF, popGet(AOP(left),0));
                    }
                  else
                  {
              emitpcode(POC_MOVLW, popGetLit(lit & 0xff));
              emitpcode(POC_ADDFW, popGet(AOP(left),0));
          emitMOVWF(result,0);
                  }
            }
          else
            {
              if (!_isSameReg(AOP(left), AOP(result), 0))
              {
              emitpcode(POC_MOVFW, popGet(AOP(left),0));
          emitMOVWF(result,0);
              }
              /* We don't know the state of the carry bit at this point */
              clear_carry = 1;
            } // if
          while (--size)
            {
              lit >>= 8;
              if (lit & 0xff)
                {
                  if (clear_carry)
                    {
                      /* The ls byte of the lit must've been zero - that 
                         means we don't have to deal with carry */

                      if (_isSameReg(AOP(left), AOP(result), offset))
                        {
                      emitpcode(POC_MOVLW, popGetLit(lit & 0xff));
                      emitpcode(POC_ADDWF, popGet(AOP(left),offset));
                        }
                      else
                      {
                      emitpcode(POC_MOVLW, popGetLit(lit & 0xff));
                      emitpcode(POC_ADDFW,  popGet(AOP(left),offset));
                      emitpcode(POC_MOVWF, popGet(AOP(result),offset));
                      }

                      clear_carry = 0;
                    }
                  else
                    {
                      if (_isSameReg(AOP(left), AOP(result), offset))
                        {
                          emitpcode(POC_MOVLW, popGetLit(lit & 0xff));
                          if (((lit + 1) & 0xff) == 0)
                            {
                              emitSKPC;
                            }
                          else
                            {
                              emitSKPNC;
                              emitpcode(POC_MOVLW, popGetLit((lit + 1) & 0xff));
                            }
                          emitpcode(POC_ADDWF,  popGet(AOP(result),offset));
                        }
                      else
                      {
                      emitpcode(POC_MOVLW, popGetLit(lit & 0xff));
                      emitMOVWF(result,offset);
                      emitpcode(POC_MOVFW, popGet(AOP(left),offset));
                      emitSKPNC;
                      emitpcode(POC_INCFSZW,popGet(AOP(left),offset));
                      emitpcode(POC_ADDWF,  popGet(AOP(result),offset));
                      }
                    } // if
                }
              else
                {
                  if (_isSameReg(AOP(left), AOP(result), offset))
                    {
                      emitpcode(POC_MOVLW, popGetLit(1));
                      emitSKPNC;
                      emitpcode(POC_ADDWF,  popGet(AOP(result),offset));
                    }
                  else
                  {
                  emitpcode(POC_CLRF,  popGet(AOP(result),offset));
                  emitpcode(POC_RLF,   popGet(AOP(result),offset));
                  emitpcode(POC_MOVFW, popGet(AOP(left),offset));
                  emitpcode(POC_ADDWF, popGet(AOP(result),offset));
                  }
                } // if
              offset++;
            } // while
        } // if
    } // if

out:
  size = pic14_getDataSize(result);
  if (size > pic14_getDataSize(left))
    {
      size = pic14_getDataSize(left);
    } // if
  addSign(result, size, 0);
}

/*-----------------------------------------------------------------*/
/* genPlus - generates code for addition                           */
/*-----------------------------------------------------------------*/
void genPlus (iCode *ic)
{
        int size, offset = 0;
        int sign;
        int isGptr;
        
        /* special cases :- */
        DEBUGpic14_emitcode ("; ***","%s  %d",__FUNCTION__,__LINE__);
        FENTRY;
        
        aopOp (IC_LEFT(ic),ic,FALSE);
        aopOp (IC_RIGHT(ic),ic,FALSE);
        aopOp (IC_RESULT(ic),ic,TRUE);
        
        DEBUGpic14_AopType(__LINE__,IC_LEFT(ic),IC_RIGHT(ic),IC_RESULT(ic));
        
        /* if literal, literal on the right or
        if left requires ACC or right is already
        in ACC */
        
        if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) {
                operand *t = IC_RIGHT(ic);
                IC_RIGHT(ic) = IC_LEFT(ic);
                IC_LEFT(ic) = t;
        }
        
        /* if left in bit space & right literal */
        if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
                AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT) {
                /* if result in bit space */
                if(AOP_TYPE(IC_RESULT(ic)) == AOP_CRY){
                        if(ulFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit) != 0L) {
                                emitpcode(POC_MOVLW, popGet(AOP(IC_RESULT(ic)),0));
                                if (!pic14_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) )
                                        emitpcode(POC_BTFSC, popGet(AOP(IC_LEFT(ic)),0));
                                emitpcode(POC_XORWF, popGet(AOP(IC_RESULT(ic)),0));
                        }
                } else {
                        size = pic14_getDataSize(IC_RESULT(ic));
                        while (size--) {
                                MOVA(aopGet(AOP(IC_RIGHT(ic)),offset,FALSE,FALSE));  
                                pic14_emitcode("addc","a,#00  ;%d",__LINE__);
                                aopPut(AOP(IC_RESULT(ic)),"a",offset++);
                        }
                }
                goto release ;
        }
        
        /* if I can do an increment instead
        of add then GOOD for ME */
        if (genPlusIncr (ic) == TRUE)
                goto release;   
        
        size = pic14_getDataSize(IC_RESULT(ic));
        isGptr = IS_GENPTR(operandType(IC_RESULT(ic))) || IS_GENPTR(operandType(IC_LEFT(ic)));
        
        if(AOP(IC_RIGHT(ic))->type == AOP_LIT) {
                /* Add a literal to something else */
                unsigned lit = (unsigned) ulFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit);
                DEBUGpic14_emitcode(";","adding lit to something. size %d",size);
                
                genAddLit (ic,  lit);
                goto release;
                
        } else if(AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
                
                pic14_emitcode(";bitadd","right is bit: %s",aopGet(AOP(IC_RIGHT(ic)),0,FALSE,FALSE));
                pic14_emitcode(";bitadd","left is bit: %s",aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE));
                pic14_emitcode(";bitadd","result is bit: %s",aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE));
                
                /* here we are adding a bit to a char or int */
                if(size == 1) {
                        if (pic14_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) {
                                emitpcode(POC_BTFSC , popGet(AOP(IC_RIGHT(ic)),0));
                                emitpcode(POC_INCF ,  popGet(AOP(IC_RESULT(ic)),0));
                        } else {
                                
                                emitpcode(POC_MOVFW , popGet(AOP(IC_LEFT(ic)),0));
                                emitpcode(POC_BTFSC , popGet(AOP(IC_RIGHT(ic)),0));
                                emitpcode(POC_INCFW , popGet(AOP(IC_LEFT(ic)),0));
                                
                                if(AOP_TYPE(IC_RESULT(ic)) == AOP_CRY) {
                                        emitpcode(POC_ANDLW , popGetLit(1));
                                        emitpcode(POC_BCF ,   popGet(AOP(IC_RESULT(ic)),0));
                                        emitSKPZ;
                                        emitpcode(POC_BSF ,   popGet(AOP(IC_RESULT(ic)),0));
                                } else {
                                        emitpcode(POC_MOVWF ,   popGet(AOP(IC_RESULT(ic)),0));
                                }
                        }
                        
                } else {
                        int offset = 1;
                        DEBUGpic14_emitcode ("; ***","%s  %d",__FUNCTION__,__LINE__);
                        if (pic14_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) {
                                emitCLRZ;
                                emitpcode(POC_BTFSC, popGet(AOP(IC_RIGHT(ic)),0));
                                emitpcode(POC_INCF,  popGet(AOP(IC_RESULT(ic)),0));
                        } else {
                                
                                emitpcode(POC_MOVFW, popGet(AOP(IC_LEFT(ic)),0));
                                emitpcode(POC_BTFSC, popGet(AOP(IC_RIGHT(ic)),0));
                                emitpcode(POC_INCFW, popGet(AOP(IC_LEFT(ic)),0));
                                emitMOVWF(IC_RIGHT(ic),0);
                        }
                        
                        while(--size){
                                emitSKPZ;
                                emitpcode(POC_INCF,  popGet(AOP(IC_RESULT(ic)),offset++));
                        }
                        
                }
                
        } else {
                DEBUGpic14_emitcode ("; ***","%s  %d",__FUNCTION__,__LINE__);    
                
                /* Add the first bytes */
                
                if(strcmp(aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE),"a") == 0 ) {
                        emitpcode(POC_ADDFW, popGet(AOP(IC_RIGHT(ic)),0));
                        emitpcode(POC_MOVWF,popGet(AOP(IC_RESULT(ic)),0));
                } else {
                        
                        emitpcode(POC_MOVFW,popGet(AOP(IC_RIGHT(ic)),0));

                        if (pic14_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) )
                                emitpcode(POC_ADDWF, popGet(AOP(IC_LEFT(ic)),0));
                        else {
                                PIC_OPCODE poc = POC_ADDFW;
                                
                                if (op_isLitLike (IC_LEFT (ic)))
                                        poc = POC_ADDLW;
                                emitpcode(poc, popGetAddr(AOP(IC_LEFT(ic)),0,0));
                                emitpcode(POC_MOVWF,popGet(AOP(IC_RESULT(ic)),0));
                        }
                }
                
                if (isGptr)
                  size = min( (GPTRSIZE - 1), AOP_SIZE(IC_RIGHT(ic))) - 1;
                else
                  size = min( AOP_SIZE(IC_RESULT(ic)), AOP_SIZE(IC_RIGHT(ic))) - 1;
                offset = 1;
                
                
                if(size){
                        if (pic14_sameRegs(AOP(IC_RIGHT(ic)), AOP(IC_RESULT(ic)))) {
                                if (op_isLitLike (IC_LEFT(ic)))
                                {
                                        while(size--){
                                                emitpcode(POC_MOVFW,   popGet(AOP(IC_RIGHT(ic)),offset));
                                                emitSKPNC;
                                                emitpcode(POC_INCFSZW, popGet(AOP(IC_RIGHT(ic)),offset));
                                                emitpcode(POC_ADDLW,   popGetAddr(AOP(IC_LEFT(ic)),offset,0));
                                                emitpcode(POC_MOVWF,   popGet(AOP(IC_RESULT(ic)),offset));
                                                offset++;
                                        }
                                } else {
                                        while(size--){
                                                emitpcode(POC_MOVFW,   popGet(AOP(IC_LEFT(ic)),offset));
                                                emitSKPNC;
                                                emitpcode(POC_INCFSZW, popGet(AOP(IC_LEFT(ic)),offset));
                                                emitpcode(POC_ADDWF,   popGet(AOP(IC_RESULT(ic)),offset));
                                                offset++;
                                        }
                                }
                        } else {
                                PIC_OPCODE poc = POC_MOVFW;
                                if (op_isLitLike (IC_LEFT(ic)))
                                        poc = POC_MOVLW;
                                while(size--){
                                        if (_isSameReg(AOP(IC_RIGHT(ic)), AOP(IC_RESULT(ic)), offset))
                                        {
                                                emitpcode(POC_MOVFW,   popGet(AOP(IC_LEFT(ic)),offset));
                                                emitSKPNC;
                                                emitpcode(POC_INCFSZW, popGet(AOP(IC_LEFT(ic)),offset));
                                                emitpcode(POC_ADDWF,   popGet(AOP(IC_RESULT(ic)),offset));
                                        }
                                        else
                                        {
                                        if (!pic14_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) {
                                                emitpcode(poc, popGetAddr(AOP(IC_LEFT(ic)),offset,0));
                                                emitpcode(POC_MOVWF, popGet(AOP(IC_RESULT(ic)),offset));
                                        }
                                        emitpcode(POC_MOVFW,   popGet(AOP(IC_RIGHT(ic)),offset));
                                        emitSKPNC;
                                        emitpcode(POC_INCFSZW, popGet(AOP(IC_RIGHT(ic)),offset));
                                        emitpcode(POC_ADDWF,   popGet(AOP(IC_RESULT(ic)),offset));
                                        }
                                        offset++;
                                }
                        }
                }
        }

#if 0

        if (AOP_SIZE(IC_RESULT(ic)) > AOP_SIZE(IC_RIGHT(ic))) {
                sign =  !(SPEC_USIGN(getSpec(operandType(IC_LEFT(ic)))) |
                        SPEC_USIGN(getSpec(operandType(IC_RIGHT(ic)))) );
                
                
                /* Need to extend result to higher bytes */
                size = AOP_SIZE(IC_RESULT(ic)) - AOP_SIZE(IC_RIGHT(ic)) - 1;
                
                /* First grab the carry from the lower bytes */
                if (AOP_SIZE(IC_LEFT(ic)) > AOP_SIZE(IC_RIGHT(ic))) { 
                        int leftsize = AOP_SIZE(IC_LEFT(ic)) - AOP_SIZE(IC_RIGHT(ic));
                        PIC_OPCODE poc = POC_MOVFW;
                        if (op_isLitLike (IC_LEFT(ic)))
                                poc = POC_MOVLW;
                        while(leftsize-- > 0) {
                                emitpcode(poc, popGetAddr(AOP(IC_LEFT(ic)),offset,0));
                                emitSKPNC;
                                emitpcode(POC_ADDLW, popGetLit(0x01));
                                emitpcode(POC_MOVWF, popGet(AOP(IC_RESULT(ic)),offset));
                                //emitSKPNC;
                                //emitpcode(POC_INCF, popGet(AOP(IC_RESULT(ic)),offset)); /* INCF does not update Carry! */
                                offset++;
                                if (size)
                                        size--;
                                else
                                        break;
                        }
                } else {
                        emitpcode(POC_CLRF, popGet(AOP(IC_RESULT(ic)),offset));
                        emitpcode(POC_RLF,  popGet(AOP(IC_RESULT(ic)),offset));
                }
                
                
                if(sign && offset > 0 && offset < AOP_SIZE(IC_RESULT(ic))) {
                /* Now this is really horrid. Gotta check the sign of the addends and propogate
                        * to the result */
                        
                        emitpcode(POC_BTFSC, newpCodeOpBit(aopGet(AOP(IC_LEFT(ic)),offset-1,FALSE,FALSE),7,0));
                        emitpcode(POC_DECF,  popGet(AOP(IC_RESULT(ic)),offset));
                        emitpcode(POC_BTFSC, newpCodeOpBit(aopGet(AOP(IC_RIGHT(ic)),offset-1,FALSE,FALSE),7,0));
                        emitpcode(POC_DECF,  popGet(AOP(IC_RESULT(ic)),offset));
                        
                        /* if chars or ints or being signed extended to longs: */
                        if(size) {
                                emitpcode(POC_MOVLW, popGetLit(0));
                                emitpcode(POC_BTFSC, newpCodeOpBit(aopGet(AOP(IC_RESULT(ic)),offset,FALSE,FALSE),7,0));
                                emitpcode(POC_MOVLW, popGetLit(0xff));
                        }
                }
                
                offset++;
                while(size--) {
                        
                        if(sign)
                                emitpcode(POC_MOVWF, popGet(AOP(IC_RESULT(ic)),offset));
                        else
                                emitpcode(POC_CLRF,  popGet(AOP(IC_RESULT(ic)),offset));
                        
                        offset++;
                }
        }

#else

        if (isGptr)
          size = (GPTRSIZE - 1) - AOP_SIZE(IC_RIGHT(ic));
        else
          size = AOP_SIZE(IC_LEFT(ic)) - AOP_SIZE(IC_RIGHT(ic));
        if (size > 0)
          {
            symbol *lbl_nosign, *lbl_done;
            sign = !(SPEC_USIGN(getSpec(operandType(IC_RIGHT(ic)))));
            if (sign)
              {
                int tmp;
                /* We must do
                 *   result = left + carry + sign-extension(right)
                 * so
                 *   right <  0 && C == 0 => result := left + 0xff && update C
                 *   right <  0 && C == 1 => result := left && C = 1
                 *   right >= 0 && C == 0 => result := left && C = 0
                 *   right >= 0 && C == 1 => result := left + 1 && update C
                 */
                lbl_nosign = newiTempLabel(NULL);
                lbl_done = newiTempLabel(NULL);
                emitpcode(POC_BTFSS, newpCodeOpBit(aopGet(AOP(IC_RIGHT(ic)),offset-1,FALSE,FALSE),7,0));
                emitpcode(POC_GOTO, popGetLabel(lbl_nosign->key));
                tmp = size;
                while (size--)
                  {
                    mov2w_op (IC_LEFT(ic),offset);
                    emitSKPC;
                    emitpcode(POC_ADDLW, popGetLit(0xff));
                    emitpcode(POC_MOVWF, popGet(AOP(IC_RESULT(ic)),offset));
                    offset++;
                  }
                size = tmp;
                offset -= tmp;
                emitpcode(POC_GOTO, popGetLabel(lbl_done->key));
                emitpLabel(lbl_nosign->key);
              }
            /* We must do
             *   result = left + carry
             * so
             *   C == 0 => result := left && C = 0
             *   C == 1 => result := left + 1 && update C
             */
           while (size--)
             {
               mov2w_op (IC_LEFT(ic),offset);
               emitSKPNC;
               emitpcode(POC_ADDLW, popGetLit(1));
               emitpcode(POC_MOVWF, popGet(AOP(IC_RESULT(ic)),offset));
               offset++;
             }
           if (sign)
             {
               emitpLabel(lbl_done->key);
             }
          }

        if (isGptr)
          {
            size = AOP_SIZE(IC_RESULT(ic)) - (GPTRSIZE - 1);
            sign = 0;
            if (size > 0)
              {
                mov2w_op (IC_LEFT(ic),offset);
                emitpcode(POC_MOVWF, popGet(AOP(IC_RESULT(ic)),offset++));
                size--;
              }
          }
        else
          {
            size = AOP_SIZE(IC_RESULT(ic)) - AOP_SIZE(IC_LEFT(ic));
            sign =  !(SPEC_USIGN(getSpec(operandType(IC_LEFT(ic)))) |
                    SPEC_USIGN(getSpec(operandType(IC_RIGHT(ic)))) );
            if (size > 0)
              {
                if (sign)
                  {
                    /* We must do
                     *   result = carry + sign-extension(result)
                     * so
                     *   result <  0 && C == 0 => result := 0xff (all remaining bytes)
                     *   result <  0 && C == 1 => result := 0 (all remaining bytes)
                     *   result >= 0 && C == 0 => result := 0 (all remaining bytes)
                     *   result >= 0 && C == 1 => result := 1 (first byte, remaining bytes 0)
                     */
                    emitpcode(POC_MOVLW, popGetLit(0xff));
                    emitpcode(POC_BTFSS, newpCodeOpBit(aopGet(AOP(IC_RESULT(ic)),offset-1,FALSE,FALSE),7,0));
                  }
                /* We must do
                 *   result = carry
                 * so
                 *   C == 0 => result := 0 (all remaining bytes)
                 *   C == 1 => result := 1 (first byte, remaining bytes 0)
                 */
               emitpcode(POC_MOVLW, popGetLit(0));
//               emitSKPNC;
//               emitpcode(POC_ADDLW, popGetLit(1));
               emitpcode(POC_MOVWF, popGet(AOP(IC_RESULT(ic)),offset));
               offset++;
               size--;
              }
          }
        while (size--)
          {
            if(sign)
              emitpcode(POC_MOVWF, popGet(AOP(IC_RESULT(ic)),offset));
            else
              emitpcode(POC_CLRF,  popGet(AOP(IC_RESULT(ic)),offset));
            offset++;
          }

#endif
        
        //adjustArithmeticResult(ic);
        
release:
        freeAsmop(IC_LEFT(ic),NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
        freeAsmop(IC_RIGHT(ic),NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
        freeAsmop(IC_RESULT(ic),NULL,ic,TRUE);
}

/*-----------------------------------------------------------------*/
/* addSign - propogate sign bit to higher bytes                    */
/*-----------------------------------------------------------------*/
void addSign(operand *result, int offset, int sign)
{
        int size = (pic14_getDataSize(result) - offset);
        DEBUGpic14_emitcode ("; ***","%s  %d",__FUNCTION__,__LINE__);
        FENTRY;
        
        if(size > 0){
                if(sign && offset) {
                        
                        if(size == 1) {
                                emitpcode(POC_CLRF,popGet(AOP(result),offset));
                                emitpcode(POC_BTFSC,newpCodeOpBit(aopGet(AOP(result),offset-1,FALSE,FALSE),7,0));
                                emitpcode(POC_DECF, popGet(AOP(result),offset));
                        } else {
                                
                                emitpcode(POC_MOVLW, popGetLit(0));
                                emitpcode(POC_BTFSC, newpCodeOpBit(aopGet(AOP(result),offset-1,FALSE,FALSE),7,0));
                                emitpcode(POC_MOVLW, popGetLit(0xff));
                                while(size--)
                                        emitpcode(POC_MOVWF, popGet(AOP(result),offset+size));
                        }
                } else
                        while(size--)
                                emitpcode(POC_CLRF,popGet(AOP(result),offset++));
        }
}

/*-----------------------------------------------------------------*/
/* genMinus - generates code for subtraction                       */
/*-----------------------------------------------------------------*/
void genMinus (iCode *ic)
{
        int size, opsize, offset = 0, same=0;
        unsigned long lit = 0L;
        int isLit;
        symbol *lbl_comm, *lbl_next;
        asmop *left, *right, *result;

        FENTRY;
        DEBUGpic14_emitcode ("; ***","%s  %d",__FUNCTION__,__LINE__);
        aopOp (IC_LEFT(ic),ic,FALSE);
        aopOp (IC_RIGHT(ic),ic,FALSE);
        aopOp (IC_RESULT(ic),ic,TRUE);
        
        if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY  &&
                AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT) {
                operand *t = IC_RIGHT(ic);
                IC_RIGHT(ic) = IC_LEFT(ic);
                IC_LEFT(ic) = t;
        }
        
        DEBUGpic14_emitcode ("; ","result %s, left %s, right %s",
                AopType(AOP_TYPE(IC_RESULT(ic))),
                AopType(AOP_TYPE(IC_LEFT(ic))),
                AopType(AOP_TYPE(IC_RIGHT(ic))));
        
        left = AOP(IC_LEFT(ic));
        right = AOP(IC_RIGHT(ic));
        result = AOP(IC_RESULT(ic));
        
        size = pic14_getDataSize(IC_RESULT(ic));
        same = pic14_sameRegs(right, result);

#if 0
        if((AOP_TYPE(IC_LEFT(ic)) != AOP_LIT)
            && (pic14_getDataSize(IC_LEFT(ic)) < size))
        {
                fprintf(stderr, "%s:%d(%s):WARNING: left operand too short for result\n",
                        ic->filename, ic->lineno, __FUNCTION__);
        } // if
        if((AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
            && (pic14_getDataSize(IC_RIGHT(ic)) < size))
        {
                fprintf(stderr, "%s:%d(%s):WARNING: right operand too short for result\n",
                        ic->filename, ic->lineno, __FUNCTION__ );
        } // if
#endif

        if(AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT) {
                /* Add a literal to something else */
                
                lit = ulFromVal(right->aopu.aop_lit);
                lit = -(long)lit;
                
                genAddLit(ic, lit);
                
        } else if(AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
                // bit subtraction
                
                pic14_emitcode(";bitsub","right is bit: %s",aopGet(right,0,FALSE,FALSE));
                pic14_emitcode(";bitsub","left is bit: %s",aopGet(left,0,FALSE,FALSE));
                pic14_emitcode(";bitsub","result is bit: %s",aopGet(result,0,FALSE,FALSE));
                
                /* here we are subtracting a bit from a char or int */
                if(size == 1) {
                        if(pic14_sameRegs(left, result)) {
                                
                                emitpcode(POC_BTFSC, popGet(right, 0));
                                emitpcode(POC_DECF , popGet(result, 0));
                                
                        } else {
                                
                                if( (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD) ||
                                        (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) ) {
                                        /*
                                         * result = literal - bit
                                         *
                                         * XXX: probably fails for AOP_IMMDs!
                                         */
                                        
                                        lit = ulFromVal (left->aopu.aop_lit);
                                        
                                        if(AOP_TYPE(IC_RESULT(ic)) == AOP_CRY) {
                                                if(pic14_sameRegs(right, result)) {
                                                        if(lit & 1) {
                                                                emitpcode(POC_MOVLW, popGet(right, 0));
                                                                emitpcode(POC_XORWF, popGet(result, 0));
                                                        }
                                                } else {
                                                        emitpcode(POC_BCF, popGet(result, 0));
                                                        if(lit & 1) 
                                                                emitpcode(POC_BTFSS, popGet(right, 0));
                                                        else
                                                                emitpcode(POC_BTFSC, popGet(right, 0));
                                                        emitpcode(POC_BSF, popGet(result, 0));
                                                }
                                                goto release;
                                        } else {
                                                emitpcode(POC_MOVLW, popGetLit(lit & 0xff));
                                                emitpcode(POC_BTFSC, popGet(right, 0));
                                                emitpcode(POC_MOVLW, popGetLit((lit-1) & 0xff));
                                                emitpcode(POC_MOVWF, popGet(result, 0));
                                        }
                                        
                                } else {
                                        // result = register - bit
                                        // XXX: Fails for lit-like left operands
                                        emitpcode(POC_MOVFW, popGet(left, 0));
                                        emitpcode(POC_BTFSC, popGet(right, 0));
                                        emitpcode(POC_DECFW, popGet(left, 0));
                                        emitpcode(POC_MOVWF, popGet(result, 0));
                                }
                        }
                } else {
                    fprintf(stderr, "WARNING: subtracting bit from multi-byte operands is incomplete.\n");
                    //exit(EXIT_FAILURE);
                } // if
        } else {
                /*
                 * RIGHT is not a literal and not a bit operand,
                 * LEFT is unknown (register, literal, bit, ...)
                 */
                lit = 0;
                isLit = 0;

                if(AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) {
                        lit = ulFromVal (left->aopu.aop_lit);
                        isLit = 1;
                        DEBUGpic14_emitcode ("; left is lit","line %d result %s, left %s, right %s",__LINE__,
                                AopType(AOP_TYPE(IC_RESULT(ic))),
                                AopType(AOP_TYPE(IC_LEFT(ic))),
                                AopType(AOP_TYPE(IC_RIGHT(ic))));
                } // if


                /*
                 * First byte, no carry-in.
                 * Any optimizations that are longer than 2 instructions are
                 * useless.
                 */
                if(same && isLit && ((lit & 0xff) == 0xff)) {
                        // right === res = 0xFF - right = ~right
                        emitpcode(POC_COMF, popGet(right, 0));
                        if(size > 1) {
                                // setup CARRY/#BORROW
                                emitSETC;
                        } // if
                } else if((size == 1) && isLit && ((lit & 0xff) == 0xff)) {
                        // res = 0xFF - right = ~right
                        emitpcode(POC_COMFW, popGet(right, 0));
                        emitpcode(POC_MOVWF, popGet(result, 0));
                        // CARRY/#BORROW is not setup correctly
                } else if((size == 1) && same && isLit && ((lit & 0xff) == 0)) {
                        // right === res = 0 - right = ~right + 1
                        emitpcode(POC_COMF, popGet(right, 0));
                        emitpcode(POC_INCF, popGet(right, 0));
                        // CARRY/#BORROW is not setup correctly
                } else {
                        // general case, should always work
                        mov2w(right, 0);
                        if (pic14_sameRegs(left, result)) {
                                // result === left = left - right (in place)
                                emitpcode(POC_SUBWF, popGet(result, 0));
                        } else {
                                // works always: result = left - right
                                emitpcode(op_isLitLike(IC_LEFT(ic))
                                        ? POC_SUBLW : POC_SUBFW,
                                        popGetAddr(left, 0, 0));
                                emitpcode(POC_MOVWF, popGet(result, 0));
                        } // if
                } // if

                /* the minimal size of both operands */
                opsize = pic14_getDataSize(IC_RIGHT(ic));
                if (!isLit && pic14_getDataSize(IC_LEFT(ic)) < opsize)
                        opsize = pic14_getDataSize(IC_LEFT(ic));
                if (size < opsize)
                        opsize = size;

                /*
                 * Next bytes, while both operands are valid registers (or literal)
                 */
                offset = 0;
                while((offset+1) < opsize && --size) {
                        lit >>= 8;
                        offset++;

                        /*
                         * The following code generation templates are ordered
                         * according to increasing length; the first template
                         * that matches will thus be the shortest and produce
                         * the best code possible with thees templates.
                         */

                        if(pic14_sameRegs(left, right)) {
                            /*
                             * This case should not occur; however, the
                             * template works if LEFT, RIGHT, and RESULT are
                             * register operands and LEFT and RIGHT are the
                             * same register(s) and at least as long as the
                             * result.
                             *
                             *   CLRF   result
                             *
                             * 1 cycle
                             */
                            emitpcode(POC_CLRF, popGet(result, offset));
                        } else if(pic14_sameRegs(left, result)) {
                            /*
                             * This template works if LEFT, RIGHT, and
                             * RESULT are register operands and LEFT and
                             * RESULT are the same register(s).
                             *
                             *   MOVF   right, W    ; W := right
                             *   BTFSS  STATUS, C
                             *   INCFSZ right, W    ; W := right + BORROW
                             *   SUBWF  result, F   ; res === left := left - (right + BORROW)
                             *
                             * The SUBWF *must* be skipped if we have a
                             * BORROW bit and right == 0xFF in order to
                             * keep the BORROW bit intact!
                             *
                             * 4 cycles
                             */
                            mov2w(right, offset);
                            emitSKPC;
                            emitpcode(POC_INCFSZW, popGet(right, offset));
                            emitpcode(POC_SUBWF, popGet(result, offset));
                        } else if((size == 1) && isLit && ((lit & 0xff) == 0xff)) {
                            /*
                             * This template works for the last byte (MSB) of
                             * the subtraction and ignores correct propagation
                             * of the outgoing BORROW bit. RIGHT and RESULT
                             * must be register operands, LEFT must be the
                             * literal 0xFF.
                             *
                             * (The case LEFT === RESULT is optimized above.)
                             *
                             * 0xFF - right - BORROW = ~right - BORROW
                             *
                             *   COMF   right, W    ; W := 0xff - right
                             *   BTFSS  STATUS, C
                             *   ADDLW  0xFF        ; W := 0xff - right - BORROW
                             *   MOVWF  result
                             *
                             * 4 cycles
                             */
                            emitpcode(POC_COMFW, popGet(right, offset));
                            emitSKPC;
                            emitpcode(POC_ADDLW, popGetLit(0xff));
                            emitpcode(POC_MOVWF, popGet(result, offset));
                        } else if(size == 1) {
                            /*
                             * This template works for the last byte (MSB) of
                             * the subtraction and ignores correct propagation
                             * of the outgoing BORROW bit. RIGHT and RESULT
                             * must be register operands, LEFT can be a
                             * register or a literal operand.
                             *
                             * (The case LEFT === RESULT is optimized above.)
                             *
                             *   MOVF   right, W    ; W := right
                             *   BTFSS  STATUS, C
                             *   INCF   right, W    ; W := right + BORROW
                             *   SUBxW  left, W     ; W := left - right - BORROW
                             *   MOVWF  result
                             *
                             * 5 cycles
                             */
                            mov2w(right, offset);
                            emitSKPC;
                            emitpcode(POC_INCFW, popGet(right, offset));
                            emitpcode(op_isLitLike(IC_LEFT(ic))
                                    ? POC_SUBLW : POC_SUBFW,
                                    popGetAddr(left, offset, 0));
                            emitpcode(POC_MOVWF, popGet(result, offset));
                        } else if(IS_ITEMP(IC_RESULT(ic))
                                && !pic14_sameRegs(right, result)) {
                            /*
                             * This code template works if RIGHT and RESULT
                             * are different register operands and RESULT
                             * is not volatile/an SFR (written twice).
                             *
                             * #########################################
                             * Since we cannot determine that for sure,
                             * we approximate via IS_ITEMP() for now.
                             * #########################################
                             *
                             *   MOVxW  left, W     ; copy left to result
                             *   MOVWF  result
                             *   MOVF   right, W    ; W := right
                             *   BTFSS  STATUS, C
                             *   INCFSZ right, W    ; W := right + BORROW
                             *   SUBWF  result, F   ; res === left := left - (right + BORROW)
                             *
                             * 6 cycles, but fails for SFR RESULT operands
                             */
                            mov2w(left, offset);
                            emitpcode(POC_MOVWF, popGet(result, offset));
                            mov2w(right, offset);
                            emitSKPC;
                            emitpcode(POC_INCFSZW, popGet(right, offset));
                            emitpcode(POC_SUBWF, popGet(result, offset));
                        } else if(!optimize.codeSize && isLit && ((lit & 0xff) != 0)) {
                            /*
                             * This template works if RIGHT and RESULT are
                             * register operands and LEFT is a literal
                             * operand != 0.
                             *
                             *   MOVxW  right, W
                             *   BTFSC  STATUS, C
                             *   GOTO   next
                             *   SUBLW  left-1
                             *   GOTO   common
                             * next:
                             *   SUBLW  left
                             * common:
                             *   MOVWF  result
                             *
                             * 6 cycles, 7 iff BORROW
                             * (9 instructions)
                             */
                            lbl_comm = newiTempLabel(NULL);
                            lbl_next = newiTempLabel(NULL);

                            mov2w(right, offset);
                            emitSKPNC;
                            emitpcode(POC_GOTO, popGetLabel(lbl_next->key));
                            emitpcode(POC_SUBLW, popGetLit((lit - 1) & 0xff));
                            emitpcode(POC_GOTO, popGetLabel(lbl_comm->key));
                            emitpLabel(lbl_next->key);
                            emitpcode(POC_SUBLW, popGetLit(lit & 0xff));
                            emitpLabel(lbl_comm->key);
                            emitpcode(POC_MOVWF, popGet(result, offset));
                        } else {
                            /*
                             * This code template works if RIGHT and RESULT
                             * are register operands.
                             *
                             *   MOVF   right, W    ; W := right
                             *   BTFSS  STATUS, C
                             *   INCFSZ right, W    ; W := right + BORROW
                             *   GOTO   common
                             *   MOVxW  left        ; if we subtract 0x100 = 0xFF + 1, ...
                             *   GOTO   next        ; res := left, but keep BORROW intact
                             * common:
                             *   SUBxW  left, W     ; W := left - (right + BORROW)
                             * next:
                             *   MOVW   result      ; res := left - (right + BORROW)
                             *
                             * 7 cycles, 8 iff BORROW and (right == 0xFF)
                             * (8 instructions)
                             *
                             *
                             *
                             * Alternative approach using -x = ~x + 1 ==> ~x = -x - 1 = -(x + 1)
                             *
                             *   COMFW  right, W    ; W := -right - (assumed BORROW)
                             *   BTFSC  STATUS, C   ; SKIP if we have a BORROW
                             *   ADDLW  1           ; W := -right (no BORROW)
                             *   BTFSC  STATUS, C   ; (***)
                             *   MOVLW  left        ; (***)
                             *   BTFSS  STATUS, C   ; (***)
                             *   ADDFW  left, W     ; W := left - right - BORROW (if any)
                             *   MOVWF  result      ; result := left - right - BORROW (if any)
                             *
                             * 8 cycles
                             *
                             * Case A: C=0 (BORROW)
                             * r=0x00, W=0xFF, W=left+0xFF, C iff left>0x00
                             * r=0x01, W=0xFE, W=left+0xFE, C iff left>0x01
                             * r=0xFE, W=0x01, W=left+0x01, C iff left>0xFE
                             * r=0xFF, W=0x00, W=left+0x00, C iff left>0xFF
                             *
                             * Case B: C=1 (no BORROW)
                             * r=0x00, W=0xFF, W=0x00/C=1, W=left+0x00, C iff left>=0x100 (***)
                             * r=0x01, W=0xFE, W=0xFF/C=0, W=left+0xFF, C iff left>=0x01
                             * r=0xFE, W=0x01, W=0x02/C=0, W=left+0x02, C iff left>=0xFE
                             * r=0xFF, W=0x00, W=0x01/C=0, W=left+0x01, C iff left>=0xFF
                             */
                            lbl_comm = newiTempLabel(NULL);
                            lbl_next = newiTempLabel(NULL);

                            mov2w(right, offset);
                            emitSKPC;
                            emitpcode(POC_INCFSZW, popGet(right, offset));
                            emitpcode(POC_GOTO, popGetLabel(lbl_comm->key));
                            mov2w(left, offset);
                            emitpcode(POC_GOTO, popGetLabel(lbl_next->key));
                            emitpLabel(lbl_comm->key);
                            emitpcode(op_isLitLike(IC_LEFT(ic))
                                    ? POC_SUBLW : POC_SUBFW,
                                    popGetAddr(left, offset, 0));
                            emitpLabel(lbl_next->key);
                            emitpcode(POC_MOVWF, popGet(result, offset));
                        } // if
                } // while

                /*
                 * Next bytes, only LEFT remains
                 */
                if (!isLit && pic14_getDataSize(IC_RIGHT(ic)) < pic14_getDataSize(IC_LEFT(ic)))
                {
                        opsize = pic14_getDataSize(IC_LEFT(ic));
                        if (size < opsize)
                                opsize = size;

                        if((offset+1) < opsize && size > 1)
                        {
                            /* the pCode needed to get the sign of RIGHT */
                            pCodeOp *pcop = NULL;
                            if (! SPEC_USIGN(getSpec(operandType(IC_RIGHT(ic)))))
                                pcop = newpCodeOpBit(aopGet(AOP(IC_RIGHT(ic)),pic14_getDataSize(IC_RIGHT(ic))-1,FALSE,FALSE),7,0);

                            /*
                             * If RIGHT is unsigned or positive, this is equivalent of RESULT := LEFT - BORROW,
                             * otherwise this is equivalent of RESULT := LEFT - (BORROW - 1)
                             */

                            if (pcop) {
                                lbl_comm = newiTempLabel(NULL);
                                lbl_next = newiTempLabel(NULL);

                                emitpcode(POC_BTFSS, pcop);
                                emitpcode(POC_GOTO, popGetLabel(lbl_comm->key));

                                /*
                                 * RESULT := LEFT - (BORROW - 1)
                                 *
                                 * if CARRY set
                                 *      RESULT := LEFT - 0xff = LEFT + 1
                                 * else
                                 *      RESULT := LEFT
                                 */


                                if(pic14_sameRegs(left, result))
                                        emitpcode(POC_MOVLW, popGetLit(1));

                                while((offset+1) < opsize && --size)
                                {
                                    offset++;
                                    if(pic14_sameRegs(left, result)) {
                                        emitSKPNC;
                                        emitpcode(POC_ADDWF, popGet(result, offset));
                                    } else {
                                       mov2w(left, offset);
                                        emitSKPNC;
                                        emitpcode(POC_ADDLW, popGetLit(1));
                                       emitpcode(POC_MOVWF, popGet(result, offset));
                                    }
                                }

                                emitpcode(POC_GOTO, popGetLabel(lbl_next->key));
                                emitpLabel(lbl_comm->key);
                            }

                            /* RESULT := LEFT - BORROW
                             *
                             * if CARRY set
                             *      RESULT := LEFT
                             * else
                             *      RESULT := LEFT - 1 = LEFT + 0xff
                             */

                            if(pic14_sameRegs(left, result))
                                emitpcode(POC_MOVLW, popGetLit(0xff));

                            while((offset+1) < opsize && --size)
                            {
                                offset++;
                                if(pic14_sameRegs(left, result)) {
                                    emitSKPC;
                                    emitpcode(POC_ADDWF, popGet(result, offset));
                                } else {
                                   mov2w(left, offset);
                                    emitSKPC;
                                    emitpcode(POC_ADDLW, popGetLit(0xff));
                                   emitpcode(POC_MOVWF, popGet(result, offset));
                                }
                            }

                            if (pcop)
                                emitpLabel(lbl_next->key);
                        }
                }

                /* Next bytes, only RIGHT remains */
                if (!isLit && pic14_getDataSize(IC_RIGHT(ic)) > pic14_getDataSize(IC_LEFT(ic)))
                {
                        opsize = pic14_getDataSize(IC_RIGHT(ic));
                        if (size < opsize)
                                opsize = size;

                        if((offset+1) < opsize && size > 1)
                        {
                            /* the pCode needed to get the sign of LEFT */
                            pCodeOp *pcop = NULL;
                            if (! SPEC_USIGN(getSpec(operandType(IC_LEFT(ic)))))
                                pcop = newpCodeOpBit(aopGet(AOP(IC_LEFT(ic)),pic14_getDataSize(IC_LEFT(ic))-1,FALSE,FALSE),7,0);

                            /*
                             * If LEFT is unsigned or positive, this is equivalent of RESULT := - (RIGHT + BORROW),
                             * otherwise this is equivalent of RESULT := -1 - (RIGHT + BORROW)
                             */

                            if (pcop) {
                                lbl_comm = newiTempLabel(NULL);
                                lbl_next = newiTempLabel(NULL);

                                emitpcode(POC_BTFSS, pcop);
                                emitpcode(POC_GOTO, popGetLabel(lbl_comm->key));

                                /*
                                 * RESULT := -1 - (RIGHT + BORROW)
                                 *
                                 * if CARRY set
                                 *      RESULT := 0xff - RIGHT = ~ RIGHT
                                 * else
                                 *      RESULT := 0xff - (RIGHT + 1) = ~ RIGHT - 1
                                 */

                                while((offset+1) < opsize && --size)
                                {
                                    offset++;
                                    emitpcode(POC_MOVLW, popGetLit(0xff));
                                   emitpcode(POC_MOVWF, popGet(result, offset));
                                    mov2w(right, offset);
                                    emitSKPC;
                                    emitpcode(POC_INCFSZW, popGet(right, offset));
                                    emitpcode(POC_SUBWF, popGet(result, offset));
                                }

                                emitpcode(POC_GOTO, popGetLabel(lbl_next->key));
                                emitpLabel(lbl_comm->key);
                            }

                            /*
                             * RESULT := - (RIGHT + BORROW)
                             *
                             * if CARRY set
                             *      RESULT := - RIGHT = ~ RIGHT + 1
                             * else
                             *      RESULT := - (RIGHT + 1) = ~ RIGHT
                             */

                            while((offset+1) < opsize && --size)
                            {
                                offset++;
                               emitpcode(POC_CLRF, popGet(result, offset));
                                mov2w(right, offset);
                                emitSKPC;
                                emitpcode(POC_INCFSZW, popGet(right, offset));
                                emitpcode(POC_SUBWF, popGet(result, offset));
                            }

                            if (pcop)
                                emitpLabel(lbl_next->key);
                        }
                }

                /* Sign extend the result if needed */
                if (size > opsize)
                        addSign(IC_RESULT(ic), opsize, !(SPEC_USIGN (operandType (IC_LEFT(ic))) && SPEC_USIGN (operandType (IC_RIGHT(ic)))));
        } // if

        if(AOP_TYPE(IC_RESULT(ic)) == AOP_CRY) {
            fprintf(stderr, "WARNING: AOP_CRY (bit-) results are probably broken. Please report this with source code as a bug.\n");
            mov2w(result, 0); // load Z flag
            emitpcode(POC_BCF, popGet(result, 0));
            emitSKPZ;
            emitpcode(POC_BSF, popGet(result, 0));
        } // if
        
        //    adjustArithmeticResult(ic);
        
release:
        freeAsmop(IC_LEFT(ic),NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
        freeAsmop(IC_RIGHT(ic),NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
        freeAsmop(IC_RESULT(ic),NULL,ic,TRUE);
}

