1 /*-------------------------------------------------------------------------
2 genarith.c - source file for code generation - arithmetic
4 Written By - Sandeep Dutta . sandeep.dutta@usa.net (1998)
5 and - Jean-Louis VERN.jlvern@writeme.com (1999)
6 Bug Fixes - Wojciech Stryjewski wstryj1@tiger.lsu.edu (1999 v2.1.9a)
7 PIC port - Scott Dattalo scott@dattalo.com (2000)
9 This program is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 2, or (at your option) any
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 In other words, you are welcome to use, share and improve this program.
24 You are forbidden to forbid anyone else to use, share and improve
25 what you give them. Help stamp out software-hoarding!
28 000123 mlh Moved aopLiteral to SDCCglue.c to help the split
29 Made everything static
30 -------------------------------------------------------------------------*/
32 #if defined(_MSC_VER) && (_MSC_VER < 1300)
33 #define __FUNCTION__ __FILE__
38 //#include "SDCCglobl.h"
39 //#include "SDCCpeeph.h"
46 #define BYTEofLONG(l,b) ( (l>> (b<<3)) & 0xff)
48 const char *AopType(short type)
81 static void DebugAop(asmop *aop)
85 printf("%s\n",AopType(aop->type));
86 printf(" current offset: %d\n",aop->coff);
87 printf(" size: %d\n",aop->size);
91 printf(" name: %s\n",aop->aopu.aop_lit->name);
94 printf(" name: %s\n",aop->aopu.aop_reg[0]->name);
98 printf(" name: %s\n",aop->aopu.aop_dir);
101 printf(" Stack offset: %d\n",aop->aopu.aop_stk);
104 printf(" immediate: %s\n",aop->aopu.aop_immd);
107 printf(" aop_str[0]: %s\n",aop->aopu.aop_str[0]);
110 //printpCode(stdout,aop->aopu.pcop);
116 const char *pCodeOpType( pCodeOp *pcop)
135 case PO_GPR_REGISTER:
136 return "PO_GPR_REGISTER";
138 return "PO_GPR_POINTER";
142 return "PO_GPR_TEMP";
143 case PO_SFR_REGISTER:
144 return "PO_SFR_REGISTER";
152 return "PO_IMMEDIATE";
168 return "BAD PO_TYPE";
171 /*-----------------------------------------------------------------*/
172 /* genPlusIncr :- does addition with increment if possible */
173 /*-----------------------------------------------------------------*/
174 static bool genPlusIncr (iCode *ic)
176 unsigned int icount ;
177 unsigned int size = pic14_getDataSize(IC_RESULT(ic));
180 DEBUGpic14_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
181 DEBUGpic14_emitcode ("; ","result %s, left %s, right %s",
182 AopType(AOP_TYPE(IC_RESULT(ic))),
183 AopType(AOP_TYPE(IC_LEFT(ic))),
184 AopType(AOP_TYPE(IC_RIGHT(ic))));
186 /* will try to generate an increment */
187 /* if the right side is not a literal
189 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
192 DEBUGpic14_emitcode ("; ","%s %d",__FUNCTION__,__LINE__);
193 /* if the literal value of the right hand side
194 is greater than 1 then it is faster to add */
195 if ((icount = (unsigned int) ulFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit)) > 2)
198 /* if increment 16 bits in register */
199 if (pic14_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
204 emitpcode(POC_INCF, popGet(AOP(IC_RESULT(ic)),LSB));
205 //pic14_emitcode("incf","%s,f",aopGet(AOP(IC_RESULT(ic)),LSB,FALSE,FALSE));
209 emitpcode(POC_INCF, popGet(AOP(IC_RESULT(ic)),offset++));
210 //pic14_emitcode(" incf","%s,f",aopGet(AOP(IC_RESULT(ic)),offset++,FALSE,FALSE));
216 DEBUGpic14_emitcode ("; ","%s %d",__FUNCTION__,__LINE__);
217 /* if left is in accumulator - probably a bit operation*/
218 if( strcmp(aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE),"a") &&
219 (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY) ) {
221 emitpcode(POC_BCF, popGet(AOP(IC_RESULT(ic)),0));
222 pic14_emitcode("bcf","(%s >> 3), (%s & 7)",
223 AOP(IC_RESULT(ic))->aopu.aop_dir,
224 AOP(IC_RESULT(ic))->aopu.aop_dir);
226 emitpcode(POC_XORLW,popGetLit(1));
227 //pic14_emitcode("xorlw","1");
229 emitpcode(POC_ANDLW,popGetLit(1));
230 //pic14_emitcode("andlw","1");
233 emitpcode(POC_BSF, popGet(AOP(IC_RESULT(ic)),0));
234 pic14_emitcode("bsf","(%s >> 3), (%s & 7)",
235 AOP(IC_RESULT(ic))->aopu.aop_dir,
236 AOP(IC_RESULT(ic))->aopu.aop_dir);
243 /* if the sizes are greater than 1 then we cannot */
244 if (AOP_SIZE(IC_RESULT(ic)) > 1 ||
245 AOP_SIZE(IC_LEFT(ic)) > 1 )
248 /* If we are incrementing the same register by two: */
250 if (pic14_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) {
253 emitpcode(POC_INCF, popGet(AOP(IC_RESULT(ic)),0));
254 //pic14_emitcode("incf","%s,f",aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE));
259 DEBUGpic14_emitcode ("; ","couldn't increment ");
265 /*-----------------------------------------------------------------*/
266 /* pic14_outBitAcc - output a bit in acc */
267 /*-----------------------------------------------------------------*/
268 static void pic14_outBitAcc(operand *result)
270 symbol *tlbl = newiTempLabel(NULL);
271 /* if the result is a bit */
273 DEBUGpic14_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
275 if (AOP_TYPE(result) == AOP_CRY){
276 aopPut(AOP(result),"a",0);
279 pic14_emitcode("jz","%05d_DS_",tlbl->key+100);
280 pic14_emitcode("mov","a,#01");
281 pic14_emitcode("","%05d_DS_:",tlbl->key+100);
282 pic14_outAcc(result);
288 /* This is the original version of this code.
290 * This is being kept around for reference,
291 * because I am not entirely sure I got it right...
293 static void adjustArithmeticResult(iCode *ic)
295 if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
296 AOP_SIZE(IC_LEFT(ic)) == 3 &&
297 !pic14_sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))))
298 aopPut(AOP(IC_RESULT(ic)),
299 aopGet(AOP(IC_LEFT(ic)),2,FALSE,FALSE),
302 if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
303 AOP_SIZE(IC_RIGHT(ic)) == 3 &&
304 !pic14_sameRegs(AOP(IC_RESULT(ic)),AOP(IC_RIGHT(ic))))
305 aopPut(AOP(IC_RESULT(ic)),
306 aopGet(AOP(IC_RIGHT(ic)),2,FALSE,FALSE),
309 if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
310 AOP_SIZE(IC_LEFT(ic)) < 3 &&
311 AOP_SIZE(IC_RIGHT(ic)) < 3 &&
312 !pic14_sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))) &&
313 !pic14_sameRegs(AOP(IC_RESULT(ic)),AOP(IC_RIGHT(ic)))) {
315 sprintf(buffer,"#%d",pointerCode(getSpec(operandType(IC_LEFT(ic)))));
316 aopPut(AOP(IC_RESULT(ic)),buffer,2);
320 /* This is the pure and virtuous version of this code.
321 * I'm pretty certain it's right, but not enough to toss the old
324 static void adjustArithmeticResult(iCode *ic)
326 if (opIsGptr(IC_RESULT(ic)) &&
327 opIsGptr(IC_LEFT(ic)) &&
328 !pic14_sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))))
330 aopPut(AOP(IC_RESULT(ic)),
331 aopGet(AOP(IC_LEFT(ic)), GPTRSIZE - 1,FALSE,FALSE),
335 if (opIsGptr(IC_RESULT(ic)) &&
336 opIsGptr(IC_RIGHT(ic)) &&
337 !pic14_sameRegs(AOP(IC_RESULT(ic)),AOP(IC_RIGHT(ic))))
339 aopPut(AOP(IC_RESULT(ic)),
340 aopGet(AOP(IC_RIGHT(ic)),GPTRSIZE - 1,FALSE,FALSE),
344 if (opIsGptr(IC_RESULT(ic)) &&
345 AOP_SIZE(IC_LEFT(ic)) < GPTRSIZE &&
346 AOP_SIZE(IC_RIGHT(ic)) < GPTRSIZE &&
347 !pic14_sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))) &&
348 !pic14_sameRegs(AOP(IC_RESULT(ic)),AOP(IC_RIGHT(ic)))) {
350 sprintf(buffer,"#%d",pointerCode(getSpec(operandType(IC_LEFT(ic)))));
351 aopPut(AOP(IC_RESULT(ic)),buffer,GPTRSIZE - 1);
356 /*-----------------------------------------------------------------*/
357 /* genAddlit - generates code for addition */
358 /*-----------------------------------------------------------------*/
359 static void genAddLit2byte (operand *result, int offr, int lit)
367 emitpcode(POC_INCF, popGet(AOP(result),offr));
370 emitpcode(POC_DECF, popGet(AOP(result),offr));
373 emitpcode(POC_MOVLW,popGetLit(lit&0xff));
374 emitpcode(POC_ADDWF,popGet(AOP(result),offr));
379 static void emitMOVWF(operand *reg, int offset)
385 emitpcode(POC_MOVWF, popGet(AOP(reg),offset));
389 static void genAddLit (iCode *ic, int lit)
399 DEBUGpic14_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
403 result = IC_RESULT(ic);
404 same = pic14_sameRegs(AOP(left), AOP(result));
405 size = pic14_getDataSize(result);
406 if (size > pic14_getDataSize(left))
407 size = pic14_getDataSize(left);
411 /* Handle special cases first */
413 genAddLit2byte (result, 0, lit);
416 int hi = 0xff & (lit >> 8);
423 DEBUGpic14_emitcode ("; hi = 0","%s %d",__FUNCTION__,__LINE__);
428 emitpcode(POC_INCF, popGet(AOP(result),0));
430 emitpcode(POC_INCF, popGet(AOP(result),MSB16));
433 emitpcode(POC_DECF, popGet(AOP(result),0));
434 emitpcode(POC_INCFSZW, popGet(AOP(result),0));
435 emitpcode(POC_INCF, popGet(AOP(result),MSB16));
439 emitpcode(POC_MOVLW,popGetLit(lit&0xff));
440 emitpcode(POC_ADDWF,popGet(AOP(result),0));
442 emitpcode(POC_INCF, popGet(AOP(result),MSB16));
450 DEBUGpic14_emitcode ("; hi = 1","%s %d",__FUNCTION__,__LINE__);
453 emitpcode(POC_INCF, popGet(AOP(result),MSB16));
456 emitpcode(POC_INCF, popGet(AOP(result),MSB16));
457 emitpcode(POC_INCF, popGet(AOP(result),0));
459 emitpcode(POC_INCF, popGet(AOP(result),MSB16));
461 case 0xff: /* 0x01ff */
462 emitpcode(POC_DECF, popGet(AOP(result),0));
463 emitpcode(POC_INCFSZW, popGet(AOP(result),0));
464 emitpcode(POC_INCF, popGet(AOP(result),MSB16));
465 emitpcode(POC_INCF, popGet(AOP(result),MSB16));
470 DEBUGpic14_emitcode ("; hi = ff","%s %d",__FUNCTION__,__LINE__);
474 emitpcode(POC_DECF, popGet(AOP(result),MSB16));
477 emitpcode(POC_INCFSZ, popGet(AOP(result),0));
478 emitpcode(POC_DECF, popGet(AOP(result),MSB16));
480 /* case 0xff: * 0xffff *
481 emitpcode(POC_INCFSZW, popGet(AOP(result),0,FALSE,FALSE));
482 emitpcode(POC_INCF, popGet(AOP(result),MSB16,FALSE,FALSE));
483 emitpcode(POC_DECF, popGet(AOP(result),0,FALSE,FALSE));
487 emitpcode(POC_MOVLW,popGetLit(lo));
488 emitpcode(POC_ADDWF,popGet(AOP(result),0));
490 emitpcode(POC_DECF, popGet(AOP(result),MSB16));
497 DEBUGpic14_emitcode ("; hi is generic","%d %s %d",hi,__FUNCTION__,__LINE__);
502 genAddLit2byte (result, MSB16, hi);
505 emitpcode(POC_MOVLW,popGetLit((hi+1)&0xff));
506 emitpcode(POC_INCFSZ, popGet(AOP(result),0));
507 emitpcode(POC_MOVLW,popGetLit(hi));
508 emitpcode(POC_ADDWF,popGet(AOP(result),MSB16));
510 /* case 0xff: * 0xHHff *
511 emitpcode(POC_MOVFW, popGet(AOP(result),0,FALSE,FALSE));
512 emitpcode(POC_DECF, popGet(AOP(result),MSB16,FALSE,FALSE));
513 emitpcode(POC_MOVLW,popGetLit(hi));
514 emitpcode(POC_ADDWF,popGet(AOP(result),MSB16,FALSE,FALSE));
516 */ default: /* 0xHHLL */
517 emitpcode(POC_MOVLW,popGetLit(lo));
518 emitpcode(POC_ADDWF, popGet(AOP(result),0));
519 emitpcode(POC_MOVLW,popGetLit(hi));
521 emitpcode(POC_MOVLW,popGetLit((hi+1) & 0xff));
522 emitpcode(POC_ADDWF,popGet(AOP(result),MSB16));
531 DEBUGpic14_emitcode ("; add lit to long","%s %d",__FUNCTION__,__LINE__);
534 lo = BYTEofLONG(lit,0);
542 emitpcode(POC_INCF, popGet(AOP(result),offset));
545 emitpcode(POC_RLFW, popGet(AOP(result),offset));
546 emitpcode(POC_ANDLW,popGetLit(1));
547 emitpcode(POC_ADDWF, popGet(AOP(result),offset));
549 default: /* carry_info = 3 */
551 emitpcode(POC_INCF, popGet(AOP(result),offset));
557 emitpcode(POC_MOVLW,popGetLit(lo));
562 emitpcode(POC_ADDWF, popGet(AOP(result),offset));
565 emitpcode(POC_MOVLW,popGetLit(lo));
570 emitpcode(POC_MOVLW,popGetLit(lo+1));
571 emitpcode(POC_ADDWF, popGet(AOP(result),offset));
576 /* no carry info from previous step */
577 /* this means this is the first time to add */
582 emitpcode(POC_INCF, popGet(AOP(result),offset));
586 emitpcode(POC_MOVLW,popGetLit(lo));
587 emitpcode(POC_ADDWF, popGet(AOP(result),offset));
589 carry_info = 3; /* Were adding only one byte and propogating the carry */
600 lo = BYTEofLONG(lit,0);
605 emitpcode(POC_INCF, popGet(AOP(result),0,FALSE,FALSE));
608 emitpcode(POC_MOVLW,popGetLit(lo));
609 emitpcode(POC_ADDWF, popGet(AOP(result),0,FALSE,FALSE));
612 emitpcode(POC_INCF, popGet(AOP(result),1,FALSE,FALSE));
614 emitpcode(POC_INCF, popGet(AOP(result),2,FALSE,FALSE));
616 emitpcode(POC_INCF, popGet(AOP(result),3,FALSE,FALSE));
625 DEBUGpic14_emitcode ("; left and result aren't same","%s %d",__FUNCTION__,__LINE__);
629 /* left addend is in a register */
632 emitpcode(POC_MOVFW, popGet(AOP(left),0));
633 emitMOVWF(result, 0);
634 //emitpcode(POC_MOVWF, popGet(AOP(result),0,FALSE,FALSE));
638 emitpcode(POC_INCFW, popGet(AOP(left),0));
639 //emitpcode(POC_MOVWF, popGet(AOP(result),0,FALSE,FALSE));
643 emitpcode(POC_DECFW, popGet(AOP(left),0));
644 //emitpcode(POC_MOVWF, popGet(AOP(result),0,FALSE,FALSE));
648 emitpcode(POC_MOVLW, popGetLit(lit & 0xff));
649 emitpcode(POC_ADDFW, popGet(AOP(left),0));
650 //emitpcode(POC_MOVWF, popGet(AOP(result),0,FALSE,FALSE));
657 /* left is not the accumulator */
659 emitpcode(POC_MOVLW, popGetLit(lit & 0xff));
660 emitpcode(POC_ADDFW, popGet(AOP(left),0));
662 emitpcode(POC_MOVFW, popGet(AOP(left),0));
663 /* We don't know the state of the carry bit at this point */
666 //emitpcode(POC_MOVWF, popGet(AOP(result),0,FALSE,FALSE));
673 /* The ls byte of the lit must've been zero - that
674 means we don't have to deal with carry */
676 emitpcode(POC_MOVLW, popGetLit(lit & 0xff));
677 emitpcode(POC_ADDFW, popGet(AOP(left),offset));
678 emitpcode(POC_MOVWF, popGet(AOP(left),offset));
683 emitpcode(POC_MOVLW, popGetLit(lit & 0xff));
684 //emitpcode(POC_MOVWF, popGet(AOP(result),offset,FALSE,FALSE));
685 emitMOVWF(result,offset);
686 emitpcode(POC_MOVFW, popGet(AOP(left),offset));
688 emitpcode(POC_INCFSZW,popGet(AOP(left),offset));
689 emitpcode(POC_ADDWF, popGet(AOP(result),offset));
693 emitpcode(POC_CLRF, popGet(AOP(result),offset));
694 emitpcode(POC_RLF, popGet(AOP(result),offset));
695 emitpcode(POC_MOVFW, popGet(AOP(left),offset));
696 emitpcode(POC_ADDWF, popGet(AOP(result),offset));
703 size = pic14_getDataSize(result);
704 if (size > pic14_getDataSize(left))
705 size = pic14_getDataSize(left);
706 addSign(result, size, 0);
709 /*-----------------------------------------------------------------*/
710 /* genPlus - generates code for addition */
711 /*-----------------------------------------------------------------*/
712 void genPlus (iCode *ic)
714 int size, offset = 0;
716 /* special cases :- */
717 DEBUGpic14_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
720 aopOp (IC_LEFT(ic),ic,FALSE);
721 aopOp (IC_RIGHT(ic),ic,FALSE);
722 aopOp (IC_RESULT(ic),ic,TRUE);
724 DEBUGpic14_AopType(__LINE__,IC_LEFT(ic),IC_RIGHT(ic),IC_RESULT(ic));
726 /* if literal, literal on the right or
727 if left requires ACC or right is already
730 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) {
731 operand *t = IC_RIGHT(ic);
732 IC_RIGHT(ic) = IC_LEFT(ic);
736 /* if left in bit space & right literal */
737 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
738 AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT) {
739 /* if result in bit space */
740 if(AOP_TYPE(IC_RESULT(ic)) == AOP_CRY){
741 if(ulFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit) != 0L) {
742 emitpcode(POC_MOVLW, popGet(AOP(IC_RESULT(ic)),0));
743 if (!pic14_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) )
744 emitpcode(POC_BTFSC, popGet(AOP(IC_LEFT(ic)),0));
745 emitpcode(POC_XORWF, popGet(AOP(IC_RESULT(ic)),0));
748 size = pic14_getDataSize(IC_RESULT(ic));
750 MOVA(aopGet(AOP(IC_RIGHT(ic)),offset,FALSE,FALSE));
751 pic14_emitcode("addc","a,#00 ;%d",__LINE__);
752 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
758 /* if I can do an increment instead
759 of add then GOOD for ME */
760 if (genPlusIncr (ic) == TRUE)
763 size = pic14_getDataSize(IC_RESULT(ic));
765 if(AOP(IC_RIGHT(ic))->type == AOP_LIT) {
766 /* Add a literal to something else */
768 unsigned lit = (unsigned) ulFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit);
772 DEBUGpic14_emitcode(";","adding lit to something. size %d",size);
777 } else if(AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
779 pic14_emitcode(";bitadd","right is bit: %s",aopGet(AOP(IC_RIGHT(ic)),0,FALSE,FALSE));
780 pic14_emitcode(";bitadd","left is bit: %s",aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE));
781 pic14_emitcode(";bitadd","result is bit: %s",aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE));
783 /* here we are adding a bit to a char or int */
785 if (pic14_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) {
786 emitpcode(POC_BTFSC , popGet(AOP(IC_RIGHT(ic)),0));
787 emitpcode(POC_INCF , popGet(AOP(IC_RESULT(ic)),0));
790 emitpcode(POC_MOVFW , popGet(AOP(IC_LEFT(ic)),0));
791 emitpcode(POC_BTFSC , popGet(AOP(IC_RIGHT(ic)),0));
792 emitpcode(POC_INCFW , popGet(AOP(IC_LEFT(ic)),0));
794 if(AOP_TYPE(IC_RESULT(ic)) == AOP_CRY) {
795 emitpcode(POC_ANDLW , popGetLit(1));
796 emitpcode(POC_BCF , popGet(AOP(IC_RESULT(ic)),0));
798 emitpcode(POC_BSF , popGet(AOP(IC_RESULT(ic)),0));
800 emitpcode(POC_MOVWF , popGet(AOP(IC_RESULT(ic)),0));
806 DEBUGpic14_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
807 if (pic14_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) {
809 emitpcode(POC_BTFSC, popGet(AOP(IC_RIGHT(ic)),0));
810 emitpcode(POC_INCF, popGet(AOP(IC_RESULT(ic)),0));
813 emitpcode(POC_MOVFW, popGet(AOP(IC_LEFT(ic)),0));
814 emitpcode(POC_BTFSC, popGet(AOP(IC_RIGHT(ic)),0));
815 emitpcode(POC_INCFW, popGet(AOP(IC_LEFT(ic)),0));
816 //emitpcode(POC_MOVWF, popGet(AOP(IC_RIGHT(ic)),0,FALSE,FALSE));
817 emitMOVWF(IC_RIGHT(ic),0);
822 emitpcode(POC_INCF, popGet(AOP(IC_RESULT(ic)),offset++));
828 DEBUGpic14_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
830 /* Add the first bytes */
832 if(strcmp(aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE),"a") == 0 ) {
833 emitpcode(POC_ADDFW, popGet(AOP(IC_RIGHT(ic)),0));
834 emitpcode(POC_MOVWF,popGet(AOP(IC_RESULT(ic)),0));
837 emitpcode(POC_MOVFW,popGet(AOP(IC_RIGHT(ic)),0));
839 if (pic14_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) )
840 emitpcode(POC_ADDWF, popGet(AOP(IC_LEFT(ic)),0));
842 PIC_OPCODE poc = POC_ADDFW;
844 if (op_isLitLike (IC_LEFT (ic)))
846 emitpcode(poc, popGetAddr(AOP(IC_LEFT(ic)),0,0));
847 emitpcode(POC_MOVWF,popGet(AOP(IC_RESULT(ic)),0));
851 size = min( AOP_SIZE(IC_RESULT(ic)), AOP_SIZE(IC_RIGHT(ic))) - 1;
856 if (pic14_sameRegs(AOP(IC_RIGHT(ic)), AOP(IC_RESULT(ic)))) {
857 if (op_isLitLike (IC_LEFT(ic)))
860 emitpcode(POC_MOVFW, popGet(AOP(IC_RIGHT(ic)),offset));
862 emitpcode(POC_INCFSZW, popGet(AOP(IC_RIGHT(ic)),offset));
863 emitpcode(POC_ADDLW, popGetAddr(AOP(IC_LEFT(ic)),offset,0));
864 emitpcode(POC_MOVWF, popGet(AOP(IC_RESULT(ic)),offset));
869 emitpcode(POC_MOVFW, popGet(AOP(IC_LEFT(ic)),offset));
871 emitpcode(POC_INCFSZW, popGet(AOP(IC_LEFT(ic)),offset));
872 emitpcode(POC_ADDWF, popGet(AOP(IC_RESULT(ic)),offset));
877 PIC_OPCODE poc = POC_MOVFW;
878 if (op_isLitLike (IC_LEFT(ic)))
881 if (!pic14_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) {
882 emitpcode(poc, popGetAddr(AOP(IC_LEFT(ic)),offset,0));
883 emitpcode(POC_MOVWF, popGet(AOP(IC_RESULT(ic)),offset));
885 emitpcode(POC_MOVFW, popGet(AOP(IC_RIGHT(ic)),offset));
887 emitpcode(POC_INCFSZW, popGet(AOP(IC_RIGHT(ic)),offset));
888 emitpcode(POC_ADDWF, popGet(AOP(IC_RESULT(ic)),offset));
895 if (AOP_SIZE(IC_RESULT(ic)) > AOP_SIZE(IC_RIGHT(ic))) {
896 int sign = !(SPEC_USIGN(getSpec(operandType(IC_LEFT(ic)))) |
897 SPEC_USIGN(getSpec(operandType(IC_RIGHT(ic)))) );
900 /* Need to extend result to higher bytes */
901 size = AOP_SIZE(IC_RESULT(ic)) - AOP_SIZE(IC_RIGHT(ic)) - 1;
903 /* First grab the carry from the lower bytes */
904 if (AOP_SIZE(IC_LEFT(ic)) > AOP_SIZE(IC_RIGHT(ic))) {
905 int leftsize = AOP_SIZE(IC_LEFT(ic)) - AOP_SIZE(IC_RIGHT(ic));
906 PIC_OPCODE poc = POC_MOVFW;
907 if (op_isLitLike (IC_LEFT(ic)))
909 while(leftsize-- > 0) {
910 emitpcode(poc, popGetAddr(AOP(IC_LEFT(ic)),offset,0));
912 emitpcode(POC_ADDLW, popGetLit(0x01));
913 emitpcode(POC_MOVWF, popGet(AOP(IC_RESULT(ic)),offset));
915 //emitpcode(POC_INCF, popGet(AOP(IC_RESULT(ic)),offset)); /* INCF does not update Carry! */
923 emitpcode(POC_CLRF, popGet(AOP(IC_RESULT(ic)),offset));
924 emitpcode(POC_RLF, popGet(AOP(IC_RESULT(ic)),offset));
928 if(sign && offset > 0 && offset < AOP_SIZE(IC_RESULT(ic))) {
929 /* Now this is really horrid. Gotta check the sign of the addends and propogate
932 emitpcode(POC_BTFSC, newpCodeOpBit(aopGet(AOP(IC_LEFT(ic)),offset-1,FALSE,FALSE),7,0));
933 emitpcode(POC_DECF, popGet(AOP(IC_RESULT(ic)),offset));
934 emitpcode(POC_BTFSC, newpCodeOpBit(aopGet(AOP(IC_RIGHT(ic)),offset-1,FALSE,FALSE),7,0));
935 emitpcode(POC_DECF, popGet(AOP(IC_RESULT(ic)),offset));
937 /* if chars or ints or being signed extended to longs: */
939 emitpcode(POC_MOVLW, popGetLit(0));
940 emitpcode(POC_BTFSC, newpCodeOpBit(aopGet(AOP(IC_RESULT(ic)),offset,FALSE,FALSE),7,0));
941 emitpcode(POC_MOVLW, popGetLit(0xff));
949 emitpcode(POC_MOVWF, popGet(AOP(IC_RESULT(ic)),offset));
951 emitpcode(POC_CLRF, popGet(AOP(IC_RESULT(ic)),offset));
958 //adjustArithmeticResult(ic);
961 freeAsmop(IC_LEFT(ic),NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
962 freeAsmop(IC_RIGHT(ic),NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
963 freeAsmop(IC_RESULT(ic),NULL,ic,TRUE);
966 /*-----------------------------------------------------------------*/
967 /* addSign - propogate sign bit to higher bytes */
968 /*-----------------------------------------------------------------*/
969 void addSign(operand *result, int offset, int sign)
971 int size = (pic14_getDataSize(result) - offset);
972 DEBUGpic14_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
979 emitpcode(POC_CLRF,popGet(AOP(result),offset));
980 emitpcode(POC_BTFSC,newpCodeOpBit(aopGet(AOP(result),offset-1,FALSE,FALSE),7,0));
981 emitpcode(POC_DECF, popGet(AOP(result),offset));
984 emitpcode(POC_MOVLW, popGetLit(0));
985 emitpcode(POC_BTFSC, newpCodeOpBit(aopGet(AOP(result),offset-1,FALSE,FALSE),7,0));
986 emitpcode(POC_MOVLW, popGetLit(0xff));
988 emitpcode(POC_MOVWF, popGet(AOP(result),offset+size));
992 emitpcode(POC_CLRF,popGet(AOP(result),offset++));
996 /*-----------------------------------------------------------------*/
997 /* genMinus - generates code for subtraction */
998 /*-----------------------------------------------------------------*/
999 void genMinus (iCode *ic)
1001 int size, offset = 0, same=0;
1002 unsigned long lit = 0L;
1004 symbol *lbl_comm, *lbl_next;
1005 asmop *left, *right, *result;
1008 DEBUGpic14_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
1009 aopOp (IC_LEFT(ic),ic,FALSE);
1010 aopOp (IC_RIGHT(ic),ic,FALSE);
1011 aopOp (IC_RESULT(ic),ic,TRUE);
1013 if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY &&
1014 AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT) {
1015 operand *t = IC_RIGHT(ic);
1016 IC_RIGHT(ic) = IC_LEFT(ic);
1020 DEBUGpic14_emitcode ("; ","result %s, left %s, right %s",
1021 AopType(AOP_TYPE(IC_RESULT(ic))),
1022 AopType(AOP_TYPE(IC_LEFT(ic))),
1023 AopType(AOP_TYPE(IC_RIGHT(ic))));
1025 left = AOP(IC_LEFT(ic));
1026 right = AOP(IC_RIGHT(ic));
1027 result = AOP(IC_RESULT(ic));
1029 size = pic14_getDataSize(IC_RESULT(ic));
1030 same = pic14_sameRegs(right, result);
1032 if((AOP_TYPE(IC_LEFT(ic)) != AOP_LIT)
1033 && (pic14_getDataSize(IC_LEFT(ic)) < size))
1035 fprintf(stderr, "%s:%d(%s):WARNING: left operand too short for result\n",
1036 ic->filename, ic->lineno, __FUNCTION__);
1038 if((AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
1039 && (pic14_getDataSize(IC_RIGHT(ic)) < size))
1041 fprintf(stderr, "%s:%d(%s):WARNING: right operand too short for result\n",
1042 ic->filename, ic->lineno, __FUNCTION__ );
1045 if(AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT) {
1046 /* Add a literal to something else */
1048 lit = ulFromVal(right->aopu.aop_lit);
1053 } else if(AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
1056 pic14_emitcode(";bitsub","right is bit: %s",aopGet(right,0,FALSE,FALSE));
1057 pic14_emitcode(";bitsub","left is bit: %s",aopGet(left,0,FALSE,FALSE));
1058 pic14_emitcode(";bitsub","result is bit: %s",aopGet(result,0,FALSE,FALSE));
1060 /* here we are subtracting a bit from a char or int */
1062 if(pic14_sameRegs(left, result)) {
1064 emitpcode(POC_BTFSC, popGet(right, 0));
1065 emitpcode(POC_DECF , popGet(result, 0));
1069 if( (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD) ||
1070 (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) ) {
1072 * result = literal - bit
1074 * XXX: probably fails for AOP_IMMDs!
1077 lit = ulFromVal (left->aopu.aop_lit);
1079 if(AOP_TYPE(IC_RESULT(ic)) == AOP_CRY) {
1080 if(pic14_sameRegs(right, result)) {
1082 emitpcode(POC_MOVLW, popGet(right, 0));
1083 emitpcode(POC_XORWF, popGet(result, 0));
1086 emitpcode(POC_BCF, popGet(result, 0));
1088 emitpcode(POC_BTFSS, popGet(right, 0));
1090 emitpcode(POC_BTFSC, popGet(right, 0));
1091 emitpcode(POC_BSF, popGet(result, 0));
1095 emitpcode(POC_MOVLW, popGetLit(lit & 0xff));
1096 emitpcode(POC_BTFSC, popGet(right, 0));
1097 emitpcode(POC_MOVLW, popGetLit((lit-1) & 0xff));
1098 emitpcode(POC_MOVWF, popGet(result, 0));
1102 // result = register - bit
1103 // XXX: Fails for lit-like left operands
1104 emitpcode(POC_MOVFW, popGet(left, 0));
1105 emitpcode(POC_BTFSC, popGet(right, 0));
1106 emitpcode(POC_DECFW, popGet(left, 0));
1107 emitpcode(POC_MOVWF, popGet(result, 0));
1111 fprintf(stderr, "WARNING: subtracting bit from multi-byte operands is incomplete.\n");
1112 //exit(EXIT_FAILURE);
1116 * RIGHT is not a literal and not a bit operand,
1117 * LEFT is unknown (register, literal, bit, ...)
1122 if(AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) {
1123 lit = ulFromVal (left->aopu.aop_lit);
1125 DEBUGpic14_emitcode ("; left is lit","line %d result %s, left %s, right %s",__LINE__,
1126 AopType(AOP_TYPE(IC_RESULT(ic))),
1127 AopType(AOP_TYPE(IC_LEFT(ic))),
1128 AopType(AOP_TYPE(IC_RIGHT(ic))));
1133 * First byte, no carry-in.
1134 * Any optimizations that are longer than 2 instructions are
1137 if(same && isLit && ((lit & 0xff) == 0xff)) {
1138 // right === res = 0xFF - right = ~right
1139 emitpcode(POC_COMF, popGet(right, 0));
1141 // setup CARRY/#BORROW
1144 } else if((size == 1) && isLit && ((lit & 0xff) == 0xff)) {
1145 // res = 0xFF - right = ~right
1146 emitpcode(POC_COMFW, popGet(right, 0));
1147 emitpcode(POC_MOVWF, popGet(result, 0));
1148 // CARRY/#BORROW is not setup correctly
1149 } else if((size == 1) && same && isLit && ((lit & 0xff) == 0)) {
1150 // right === res = 0 - right = ~right + 1
1151 emitpcode(POC_COMF, popGet(right, 0));
1152 emitpcode(POC_INCF, popGet(right, 0));
1153 // CARRY/#BORROW is not setup correctly
1155 // general case, should always work
1157 if (pic14_sameRegs(left, result)) {
1158 // result === left = left - right (in place)
1159 emitpcode(POC_SUBWF, popGet(result, 0));
1161 // works always: result = left - right
1162 emitpcode(op_isLitLike(IC_LEFT(ic))
1163 ? POC_SUBLW : POC_SUBFW,
1164 popGetAddr(left, 0, 0));
1165 emitpcode(POC_MOVWF, popGet(result, 0));
1170 * Now for the remaining bytes with carry-in (and carry-out).
1178 * The following code generation templates are ordered
1179 * according to increasing length; the first template
1180 * that matches will thus be the shortest and produce
1181 * the best code possible with thees templates.
1184 if(pic14_sameRegs(left, right)) {
1186 * This case should not occur; however, the
1187 * template works if LEFT, RIGHT, and RESULT are
1188 * register operands and LEFT and RIGHT are the
1189 * same register(s) and at least as long as the
1196 emitpcode(POC_CLRF, popGet(result, offset));
1197 } else if(pic14_sameRegs(left, result)) {
1199 * This template works if LEFT, RIGHT, and
1200 * RESULT are register operands and LEFT and
1201 * RESULT are the same register(s).
1203 * MOVF right, W ; W := right
1205 * INCFSZ right, W ; W := right + BORROW
1206 * SUBWF result, F ; res === left := left - (right + BORROW)
1208 * The SUBWF *must* be skipped if we have a
1209 * BORROW bit and right == 0xFF in order to
1210 * keep the BORROW bit intact!
1214 mov2w(right, offset);
1216 emitpcode(POC_INCFSZW, popGet(right, offset));
1217 emitpcode(POC_SUBWF, popGet(result, offset));
1218 } else if((size == 1) && isLit && ((lit & 0xff) == 0xff)) {
1220 * This template works for the last byte (MSB) of
1221 * the subtraction and ignores correct propagation
1222 * of the outgoing BORROW bit. RIGHT and RESULT
1223 * must be register operands, LEFT must be the
1226 * (The case LEFT === RESULT is optimized above.)
1228 * 0xFF - right - BORROW = ~right - BORROW
1230 * COMF right, W ; W := 0xff - right
1232 * ADDLW 0xFF ; W := 0xff - right - BORROW
1237 emitpcode(POC_COMFW, popGet(right, offset));
1239 emitpcode(POC_ADDLW, popGetLit(0xff));
1240 emitpcode(POC_MOVWF, popGet(result, offset));
1241 } else if(size == 1) {
1243 * This template works for the last byte (MSB) of
1244 * the subtraction and ignores correct propagation
1245 * of the outgoing BORROW bit. RIGHT and RESULT
1246 * must be register operands, LEFT can be a
1247 * register or a literal operand.
1249 * (The case LEFT === RESULT is optimized above.)
1251 * MOVF right, W ; W := right
1253 * INCF right, W ; W := right + BORROW
1254 * SUBxW left, W ; W := left - right - BORROW
1259 mov2w(right, offset);
1261 emitpcode(POC_INCFW, popGet(right, offset));
1262 emitpcode(op_isLitLike(IC_LEFT(ic))
1263 ? POC_SUBLW : POC_SUBFW,
1264 popGetAddr(left, offset, 0));
1265 emitpcode(POC_MOVWF, popGet(result, offset));
1266 } else if(IS_ITEMP(IC_RESULT(ic))
1267 && !pic14_sameRegs(right, result)) {
1269 * This code template works if RIGHT and RESULT
1270 * are different register operands and RESULT
1271 * is not volatile/an SFR (written twice).
1273 * #########################################
1274 * Since we cannot determine that for sure,
1275 * we approximate via IS_ITEMP() for now.
1276 * #########################################
1278 * MOVxW left, W ; copy left to result
1280 * MOVF right, W ; W := right
1282 * INCFSZ right, W ; W := right + BORROW
1283 * SUBWF result, F ; res === left := left - (right + BORROW)
1285 * 6 cycles, but fails for SFR RESULT operands
1287 mov2w(left, offset);
1288 emitpcode(POC_MOVWF, popGet(result, offset));
1289 mov2w(right, offset);
1291 emitpcode(POC_INCFSZW, popGet(right, offset));
1292 emitpcode(POC_SUBWF, popGet(result, offset));
1293 } else if(!optimize.codeSize && isLit && ((lit & 0xff) != 0)) {
1295 * This template works if RIGHT and RESULT are
1296 * register operands and LEFT is a literal
1309 * 6 cycles, 7 iff BORROW
1312 lbl_comm = newiTempLabel(NULL);
1313 lbl_next = newiTempLabel(NULL);
1315 mov2w(right, offset);
1317 emitpcode(POC_GOTO, popGetLabel(lbl_next->key));
1318 emitpcode(POC_SUBLW, popGetLit((lit - 1) & 0xff));
1319 emitpcode(POC_GOTO, popGetLabel(lbl_comm->key));
1320 emitpLabel(lbl_next->key);
1321 emitpcode(POC_SUBLW, popGetLit(lit & 0xff));
1322 emitpLabel(lbl_comm->key);
1323 emitpcode(POC_MOVWF, popGet(result, offset));
1326 * This code template works if RIGHT and RESULT
1327 * are register operands.
1329 * MOVF right, W ; W := right
1331 * INCFSZ right, W ; W := right + BORROW
1333 * MOVxW left ; if we subtract 0x100 = 0xFF + 1, ...
1334 * GOTO next ; res := left, but keep BORROW intact
1336 * SUBxW left, W ; W := left - (right + BORROW)
1338 * MOVW result ; res := left - (right + BORROW)
1340 * 7 cycles, 8 iff BORROW and (right == 0xFF)
1345 * Alternative approach using -x = ~x + 1 ==> ~x = -x - 1 = -(x + 1)
1347 * COMFW right, W ; W := -right - (assumed BORROW)
1348 * BTFSC STATUS, C ; SKIP if we have a BORROW
1349 * ADDLW 1 ; W := -right (no BORROW)
1350 * BTFSC STATUS, C ; (***)
1351 * MOVLW left ; (***)
1352 * BTFSS STATUS, C ; (***)
1353 * ADDFW left, W ; W := left - right - BORROW (if any)
1354 * MOVWF result ; result := left - right - BORROW (if any)
1358 * Case A: C=0 (BORROW)
1359 * r=0x00, W=0xFF, W=left+0xFF, C iff left>0x00
1360 * r=0x01, W=0xFE, W=left+0xFE, C iff left>0x01
1361 * r=0xFE, W=0x01, W=left+0x01, C iff left>0xFE
1362 * r=0xFF, W=0x00, W=left+0x00, C iff left>0xFF
1364 * Case B: C=1 (no BORROW)
1365 * r=0x00, W=0xFF, W=0x00/C=1, W=left+0x00, C iff left>=0x100 (***)
1366 * r=0x01, W=0xFE, W=0xFF/C=0, W=left+0xFF, C iff left>=0x01
1367 * r=0xFE, W=0x01, W=0x02/C=0, W=left+0x02, C iff left>=0xFE
1368 * r=0xFF, W=0x00, W=0x01/C=0, W=left+0x01, C iff left>=0xFF
1370 lbl_comm = newiTempLabel(NULL);
1371 lbl_next = newiTempLabel(NULL);
1373 mov2w(right, offset);
1375 emitpcode(POC_INCFSZW, popGet(right, offset));
1376 emitpcode(POC_GOTO, popGetLabel(lbl_comm->key));
1377 mov2w(left, offset);
1378 emitpcode(POC_GOTO, popGetLabel(lbl_next->key));
1379 emitpLabel(lbl_comm->key);
1380 emitpcode(op_isLitLike(IC_LEFT(ic))
1381 ? POC_SUBLW : POC_SUBFW,
1382 popGetAddr(left, offset, 0));
1383 emitpLabel(lbl_next->key);
1384 emitpcode(POC_MOVWF, popGet(result, offset));
1389 if(AOP_TYPE(IC_RESULT(ic)) == AOP_CRY) {
1390 fprintf(stderr, "WARNING: AOP_CRY (bit-) results are probably broken. Please report this with source code as a bug.\n");
1391 mov2w(result, 0); // load Z flag
1392 emitpcode(POC_BCF, popGet(result, 0));
1394 emitpcode(POC_BSF, popGet(result, 0));
1397 // adjustArithmeticResult(ic);
1400 freeAsmop(IC_LEFT(ic),NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
1401 freeAsmop(IC_RIGHT(ic),NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
1402 freeAsmop(IC_RESULT(ic),NULL,ic,TRUE);