diff options
| author | Xavier ASUS <xavi92psx@gmail.com> | 2019-10-18 00:31:54 +0200 |
|---|---|---|
| committer | Xavier ASUS <xavi92psx@gmail.com> | 2019-10-18 00:31:54 +0200 |
| commit | 268a53de823a6750d6256ee1fb1e7707b4b45740 (patch) | |
| tree | 42c1799a9a82b2f7d9790ee9fe181d72a7274751 /src/pic14/genarith.c | |
| download | sdcc-gas-268a53de823a6750d6256ee1fb1e7707b4b45740.tar.gz | |
sdcc-3.9.0 fork implementing GNU assembler syntax
This fork aims to provide better support for stm8-binutils
Diffstat (limited to 'src/pic14/genarith.c')
| -rw-r--r-- | src/pic14/genarith.c | 1289 |
1 files changed, 1289 insertions, 0 deletions
diff --git a/src/pic14/genarith.c b/src/pic14/genarith.c new file mode 100644 index 0000000..2c9936e --- /dev/null +++ b/src/pic14/genarith.c @@ -0,0 +1,1289 @@ +/*------------------------------------------------------------------------- + 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"; +} + +/*-----------------------------------------------------------------*/ +/* 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); + } + + /* + * Fix accessing libsdcc/<*>/idata.c:_cinit in __code space. + */ + if (AOP_PCODE == AOP_TYPE(IC_LEFT(ic))) + { + int u; + if (debug_verbose) + { + printf("%s:%u: CHECK: using address of '%s' instead of contents\n", + 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: + emitpcode(POC_MOVFW, popGet(AOP(left),0)); + emitMOVWF(result,0); + break; + case 1: + emitpcode(POC_INCFW, popGet(AOP(left),0)); + emitMOVWF(result,0); + break; + case 0xff: + emitpcode(POC_DECFW, popGet(AOP(left),0)); + emitMOVWF(result,0); + break; + default: + 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) + { + emitpcode(POC_MOVLW, popGetLit(lit & 0xff)); + emitpcode(POC_ADDFW, popGet(AOP(left),0)); + } + else + { + emitpcode(POC_MOVFW, popGet(AOP(left),0)); + /* We don't know the state of the carry bit at this point */ + clear_carry = 1; + } // if + emitMOVWF(result,0); + 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 */ + + emitpcode(POC_MOVLW, popGetLit(lit & 0xff)); + emitpcode(POC_ADDFW, popGet(AOP(left),offset)); + emitpcode(POC_MOVWF, popGet(AOP(result),offset)); + + clear_carry = 0; + } + 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 + { + 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; + + /* 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)); + + 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)); + } + } + + 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 (!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 (AOP_SIZE(IC_RESULT(ic)) > AOP_SIZE(IC_RIGHT(ic))) { + int 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++; + } + } + + + //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, 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((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 + + 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 + + /* + * Now for the remaining bytes with carry-in (and carry-out). + */ + offset = 0; + while(--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 + } // 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); +} + |
