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)
80 const char *pCodeOpType(pCodeOp *pcop)
100 return "PO_GPR_REGISTER";
102 return "PO_GPR_POINTER";
106 return "PO_GPR_TEMP";
107 case PO_SFR_REGISTER:
108 return "PO_SFR_REGISTER";
116 return "PO_IMMEDIATE";
132 return "BAD PO_TYPE";
135 /*-----------------------------------------------------------------*/
136 /* genPlusIncr :- does addition with increment if possible */
137 /*-----------------------------------------------------------------*/
138 static bool genPlusIncr (iCode *ic)
140 unsigned int icount ;
141 unsigned int size = pic14_getDataSize(IC_RESULT(ic));
144 DEBUGpic14_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
145 DEBUGpic14_emitcode ("; ","result %s, left %s, right %s",
146 AopType(AOP_TYPE(IC_RESULT(ic))),
147 AopType(AOP_TYPE(IC_LEFT(ic))),
148 AopType(AOP_TYPE(IC_RIGHT(ic))));
150 /* will try to generate an increment */
151 /* if the right side is not a literal
153 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
156 DEBUGpic14_emitcode ("; ","%s %d",__FUNCTION__,__LINE__);
157 /* if the literal value of the right hand side
158 is greater than 1 then it is faster to add */
159 if ((icount = (unsigned int) ulFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit)) > 2)
162 /* if increment 16 bits in register */
163 if (pic14_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
168 emitpcode(POC_INCF, popGet(AOP(IC_RESULT(ic)),LSB));
169 //pic14_emitcode("incf","%s,f",aopGet(AOP(IC_RESULT(ic)),LSB,FALSE,FALSE));
173 emitpcode(POC_INCF, popGet(AOP(IC_RESULT(ic)),offset++));
174 //pic14_emitcode(" incf","%s,f",aopGet(AOP(IC_RESULT(ic)),offset++,FALSE,FALSE));
180 DEBUGpic14_emitcode ("; ","%s %d",__FUNCTION__,__LINE__);
181 /* if left is in accumulator - probably a bit operation*/
182 if( strcmp(aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE),"a") &&
183 (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY) ) {
185 emitpcode(POC_BCF, popGet(AOP(IC_RESULT(ic)),0));
186 pic14_emitcode("bcf","(%s >> 3), (%s & 7)",
187 AOP(IC_RESULT(ic))->aopu.aop_dir,
188 AOP(IC_RESULT(ic))->aopu.aop_dir);
190 emitpcode(POC_XORLW,popGetLit(1));
191 //pic14_emitcode("xorlw","1");
193 emitpcode(POC_ANDLW,popGetLit(1));
194 //pic14_emitcode("andlw","1");
197 emitpcode(POC_BSF, popGet(AOP(IC_RESULT(ic)),0));
198 pic14_emitcode("bsf","(%s >> 3), (%s & 7)",
199 AOP(IC_RESULT(ic))->aopu.aop_dir,
200 AOP(IC_RESULT(ic))->aopu.aop_dir);
207 /* if the sizes are greater than 1 then we cannot */
208 if (AOP_SIZE(IC_RESULT(ic)) > 1 ||
209 AOP_SIZE(IC_LEFT(ic)) > 1 )
212 /* If we are incrementing the same register by two: */
214 if (pic14_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) {
217 emitpcode(POC_INCF, popGet(AOP(IC_RESULT(ic)),0));
218 //pic14_emitcode("incf","%s,f",aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE));
223 DEBUGpic14_emitcode ("; ","couldn't increment ");
228 /*-----------------------------------------------------------------*/
229 /* genAddlit - generates code for addition */
230 /*-----------------------------------------------------------------*/
231 static void genAddLit2byte (operand *result, int offr, int lit)
239 emitpcode(POC_INCF, popGet(AOP(result),offr));
242 emitpcode(POC_DECF, popGet(AOP(result),offr));
245 emitpcode(POC_MOVLW,popGetLit(lit&0xff));
246 emitpcode(POC_ADDWF,popGet(AOP(result),offr));
251 static void emitMOVWF(operand *reg, int offset)
257 emitpcode(POC_MOVWF, popGet(AOP(reg),offset));
261 static void genAddLit (iCode *ic, int lit)
271 DEBUGpic14_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
275 result = IC_RESULT(ic);
276 same = pic14_sameRegs(AOP(left), AOP(result));
277 size = pic14_getDataSize(result);
278 if (size > pic14_getDataSize(left))
279 size = pic14_getDataSize(left);
283 /* Handle special cases first */
285 genAddLit2byte (result, 0, lit);
288 int hi = 0xff & (lit >> 8);
295 DEBUGpic14_emitcode ("; hi = 0","%s %d",__FUNCTION__,__LINE__);
300 emitpcode(POC_INCF, popGet(AOP(result),0));
302 emitpcode(POC_INCF, popGet(AOP(result),MSB16));
305 emitpcode(POC_DECF, popGet(AOP(result),0));
306 emitpcode(POC_INCFSZW, popGet(AOP(result),0));
307 emitpcode(POC_INCF, popGet(AOP(result),MSB16));
311 emitpcode(POC_MOVLW,popGetLit(lit&0xff));
312 emitpcode(POC_ADDWF,popGet(AOP(result),0));
314 emitpcode(POC_INCF, popGet(AOP(result),MSB16));
322 DEBUGpic14_emitcode ("; hi = 1","%s %d",__FUNCTION__,__LINE__);
325 emitpcode(POC_INCF, popGet(AOP(result),MSB16));
328 emitpcode(POC_INCF, popGet(AOP(result),MSB16));
329 emitpcode(POC_INCF, popGet(AOP(result),0));
331 emitpcode(POC_INCF, popGet(AOP(result),MSB16));
333 case 0xff: /* 0x01ff */
334 emitpcode(POC_DECF, popGet(AOP(result),0));
335 emitpcode(POC_INCFSZW, popGet(AOP(result),0));
336 emitpcode(POC_INCF, popGet(AOP(result),MSB16));
337 emitpcode(POC_INCF, popGet(AOP(result),MSB16));
342 DEBUGpic14_emitcode ("; hi = ff","%s %d",__FUNCTION__,__LINE__);
346 emitpcode(POC_DECF, popGet(AOP(result),MSB16));
349 emitpcode(POC_INCFSZ, popGet(AOP(result),0));
350 emitpcode(POC_DECF, popGet(AOP(result),MSB16));
353 emitpcode(POC_MOVLW,popGetLit(lo));
354 emitpcode(POC_ADDWF,popGet(AOP(result),0));
356 emitpcode(POC_DECF, popGet(AOP(result),MSB16));
363 DEBUGpic14_emitcode ("; hi is generic","%d %s %d",hi,__FUNCTION__,__LINE__);
368 genAddLit2byte (result, MSB16, hi);
371 emitpcode(POC_MOVLW,popGetLit((hi+1)&0xff));
372 emitpcode(POC_INCFSZ, popGet(AOP(result),0));
373 emitpcode(POC_MOVLW,popGetLit(hi));
374 emitpcode(POC_ADDWF,popGet(AOP(result),MSB16));
376 default: /* 0xHHLL */
377 emitpcode(POC_MOVLW,popGetLit(lo));
378 emitpcode(POC_ADDWF, popGet(AOP(result),0));
379 emitpcode(POC_MOVLW,popGetLit(hi));
381 emitpcode(POC_MOVLW,popGetLit((hi+1) & 0xff));
382 emitpcode(POC_ADDWF,popGet(AOP(result),MSB16));
391 DEBUGpic14_emitcode ("; add lit to long","%s %d",__FUNCTION__,__LINE__);
394 lo = BYTEofLONG(lit,0);
402 emitpcode(POC_INCF, popGet(AOP(result),offset));
405 emitpcode(POC_RLFW, popGet(AOP(result),offset));
406 emitpcode(POC_ANDLW,popGetLit(1));
407 emitpcode(POC_ADDWF, popGet(AOP(result),offset));
409 default: /* carry_info = 3 */
411 emitpcode(POC_INCF, popGet(AOP(result),offset));
417 emitpcode(POC_MOVLW,popGetLit(lo));
422 emitpcode(POC_ADDWF, popGet(AOP(result),offset));
425 emitpcode(POC_MOVLW,popGetLit(lo));
430 emitpcode(POC_MOVLW,popGetLit(lo+1));
431 emitpcode(POC_ADDWF, popGet(AOP(result),offset));
436 /* no carry info from previous step */
437 /* this means this is the first time to add */
442 emitpcode(POC_INCF, popGet(AOP(result),offset));
446 emitpcode(POC_MOVLW,popGetLit(lo));
447 emitpcode(POC_ADDWF, popGet(AOP(result),offset));
449 carry_info = 3; /* Were adding only one byte and propogating the carry */
461 DEBUGpic14_emitcode ("; left and result aren't same","%s %d",__FUNCTION__,__LINE__);
465 /* left addend is in a register */
468 emitpcode(POC_MOVFW, popGet(AOP(left),0));
469 emitMOVWF(result, 0);
473 emitpcode(POC_INCFW, popGet(AOP(left),0));
477 emitpcode(POC_DECFW, popGet(AOP(left),0));
481 emitpcode(POC_MOVLW, popGetLit(lit & 0xff));
482 emitpcode(POC_ADDFW, popGet(AOP(left),0));
489 /* left is not the accumulator */
491 emitpcode(POC_MOVLW, popGetLit(lit & 0xff));
492 emitpcode(POC_ADDFW, popGet(AOP(left),0));
494 emitpcode(POC_MOVFW, popGet(AOP(left),0));
495 /* We don't know the state of the carry bit at this point */
504 /* The ls byte of the lit must've been zero - that
505 means we don't have to deal with carry */
507 emitpcode(POC_MOVLW, popGetLit(lit & 0xff));
508 emitpcode(POC_ADDFW, popGet(AOP(left),offset));
509 emitpcode(POC_MOVWF, popGet(AOP(left),offset));
514 emitpcode(POC_MOVLW, popGetLit(lit & 0xff));
515 emitMOVWF(result,offset);
516 emitpcode(POC_MOVFW, popGet(AOP(left),offset));
518 emitpcode(POC_INCFSZW,popGet(AOP(left),offset));
519 emitpcode(POC_ADDWF, popGet(AOP(result),offset));
523 emitpcode(POC_CLRF, popGet(AOP(result),offset));
524 emitpcode(POC_RLF, popGet(AOP(result),offset));
525 emitpcode(POC_MOVFW, popGet(AOP(left),offset));
526 emitpcode(POC_ADDWF, popGet(AOP(result),offset));
533 size = pic14_getDataSize(result);
534 if (size > pic14_getDataSize(left))
535 size = pic14_getDataSize(left);
536 addSign(result, size, 0);
539 /*-----------------------------------------------------------------*/
540 /* genPlus - generates code for addition */
541 /*-----------------------------------------------------------------*/
542 void genPlus (iCode *ic)
544 int size, offset = 0;
546 /* special cases :- */
547 DEBUGpic14_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
550 aopOp (IC_LEFT(ic),ic,FALSE);
551 aopOp (IC_RIGHT(ic),ic,FALSE);
552 aopOp (IC_RESULT(ic),ic,TRUE);
554 DEBUGpic14_AopType(__LINE__,IC_LEFT(ic),IC_RIGHT(ic),IC_RESULT(ic));
556 /* if literal, literal on the right or
557 if left requires ACC or right is already
560 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) {
561 operand *t = IC_RIGHT(ic);
562 IC_RIGHT(ic) = IC_LEFT(ic);
566 /* if left in bit space & right literal */
567 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
568 AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT) {
569 /* if result in bit space */
570 if(AOP_TYPE(IC_RESULT(ic)) == AOP_CRY){
571 if(ulFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit) != 0L) {
572 emitpcode(POC_MOVLW, popGet(AOP(IC_RESULT(ic)),0));
573 if (!pic14_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) )
574 emitpcode(POC_BTFSC, popGet(AOP(IC_LEFT(ic)),0));
575 emitpcode(POC_XORWF, popGet(AOP(IC_RESULT(ic)),0));
578 size = pic14_getDataSize(IC_RESULT(ic));
580 MOVA(aopGet(AOP(IC_RIGHT(ic)),offset,FALSE,FALSE));
581 pic14_emitcode("addc","a,#00 ;%d",__LINE__);
582 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
588 /* if I can do an increment instead
589 of add then GOOD for ME */
590 if (genPlusIncr (ic) == TRUE)
593 size = pic14_getDataSize(IC_RESULT(ic));
595 if(AOP(IC_RIGHT(ic))->type == AOP_LIT) {
596 /* Add a literal to something else */
597 unsigned lit = (unsigned) ulFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit);
598 DEBUGpic14_emitcode(";","adding lit to something. size %d",size);
603 } else if(AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
605 pic14_emitcode(";bitadd","right is bit: %s",aopGet(AOP(IC_RIGHT(ic)),0,FALSE,FALSE));
606 pic14_emitcode(";bitadd","left is bit: %s",aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE));
607 pic14_emitcode(";bitadd","result is bit: %s",aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE));
609 /* here we are adding a bit to a char or int */
611 if (pic14_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) {
612 emitpcode(POC_BTFSC , popGet(AOP(IC_RIGHT(ic)),0));
613 emitpcode(POC_INCF , popGet(AOP(IC_RESULT(ic)),0));
616 emitpcode(POC_MOVFW , popGet(AOP(IC_LEFT(ic)),0));
617 emitpcode(POC_BTFSC , popGet(AOP(IC_RIGHT(ic)),0));
618 emitpcode(POC_INCFW , popGet(AOP(IC_LEFT(ic)),0));
620 if(AOP_TYPE(IC_RESULT(ic)) == AOP_CRY) {
621 emitpcode(POC_ANDLW , popGetLit(1));
622 emitpcode(POC_BCF , popGet(AOP(IC_RESULT(ic)),0));
624 emitpcode(POC_BSF , popGet(AOP(IC_RESULT(ic)),0));
626 emitpcode(POC_MOVWF , popGet(AOP(IC_RESULT(ic)),0));
632 DEBUGpic14_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
633 if (pic14_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) {
635 emitpcode(POC_BTFSC, popGet(AOP(IC_RIGHT(ic)),0));
636 emitpcode(POC_INCF, popGet(AOP(IC_RESULT(ic)),0));
639 emitpcode(POC_MOVFW, popGet(AOP(IC_LEFT(ic)),0));
640 emitpcode(POC_BTFSC, popGet(AOP(IC_RIGHT(ic)),0));
641 emitpcode(POC_INCFW, popGet(AOP(IC_LEFT(ic)),0));
642 emitMOVWF(IC_RIGHT(ic),0);
647 emitpcode(POC_INCF, popGet(AOP(IC_RESULT(ic)),offset++));
653 DEBUGpic14_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
655 /* Add the first bytes */
657 if(strcmp(aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE),"a") == 0 ) {
658 emitpcode(POC_ADDFW, popGet(AOP(IC_RIGHT(ic)),0));
659 emitpcode(POC_MOVWF,popGet(AOP(IC_RESULT(ic)),0));
662 emitpcode(POC_MOVFW,popGet(AOP(IC_RIGHT(ic)),0));
664 if (pic14_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) )
665 emitpcode(POC_ADDWF, popGet(AOP(IC_LEFT(ic)),0));
667 PIC_OPCODE poc = POC_ADDFW;
669 if (op_isLitLike (IC_LEFT (ic)))
671 emitpcode(poc, popGetAddr(AOP(IC_LEFT(ic)),0,0));
672 emitpcode(POC_MOVWF,popGet(AOP(IC_RESULT(ic)),0));
676 size = min( AOP_SIZE(IC_RESULT(ic)), AOP_SIZE(IC_RIGHT(ic))) - 1;
681 if (pic14_sameRegs(AOP(IC_RIGHT(ic)), AOP(IC_RESULT(ic)))) {
682 if (op_isLitLike (IC_LEFT(ic)))
685 emitpcode(POC_MOVFW, popGet(AOP(IC_RIGHT(ic)),offset));
687 emitpcode(POC_INCFSZW, popGet(AOP(IC_RIGHT(ic)),offset));
688 emitpcode(POC_ADDLW, popGetAddr(AOP(IC_LEFT(ic)),offset,0));
689 emitpcode(POC_MOVWF, popGet(AOP(IC_RESULT(ic)),offset));
694 emitpcode(POC_MOVFW, popGet(AOP(IC_LEFT(ic)),offset));
696 emitpcode(POC_INCFSZW, popGet(AOP(IC_LEFT(ic)),offset));
697 emitpcode(POC_ADDWF, popGet(AOP(IC_RESULT(ic)),offset));
702 PIC_OPCODE poc = POC_MOVFW;
703 if (op_isLitLike (IC_LEFT(ic)))
706 if (!pic14_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) {
707 emitpcode(poc, popGetAddr(AOP(IC_LEFT(ic)),offset,0));
708 emitpcode(POC_MOVWF, popGet(AOP(IC_RESULT(ic)),offset));
710 emitpcode(POC_MOVFW, popGet(AOP(IC_RIGHT(ic)),offset));
712 emitpcode(POC_INCFSZW, popGet(AOP(IC_RIGHT(ic)),offset));
713 emitpcode(POC_ADDWF, popGet(AOP(IC_RESULT(ic)),offset));
720 if (AOP_SIZE(IC_RESULT(ic)) > AOP_SIZE(IC_RIGHT(ic))) {
721 int sign = !(SPEC_USIGN(getSpec(operandType(IC_LEFT(ic)))) |
722 SPEC_USIGN(getSpec(operandType(IC_RIGHT(ic)))) );
725 /* Need to extend result to higher bytes */
726 size = AOP_SIZE(IC_RESULT(ic)) - AOP_SIZE(IC_RIGHT(ic)) - 1;
728 /* First grab the carry from the lower bytes */
729 if (AOP_SIZE(IC_LEFT(ic)) > AOP_SIZE(IC_RIGHT(ic))) {
730 int leftsize = AOP_SIZE(IC_LEFT(ic)) - AOP_SIZE(IC_RIGHT(ic));
731 PIC_OPCODE poc = POC_MOVFW;
732 if (op_isLitLike (IC_LEFT(ic)))
734 while(leftsize-- > 0) {
735 emitpcode(poc, popGetAddr(AOP(IC_LEFT(ic)),offset,0));
737 emitpcode(POC_ADDLW, popGetLit(0x01));
738 emitpcode(POC_MOVWF, popGet(AOP(IC_RESULT(ic)),offset));
740 //emitpcode(POC_INCF, popGet(AOP(IC_RESULT(ic)),offset)); /* INCF does not update Carry! */
748 emitpcode(POC_CLRF, popGet(AOP(IC_RESULT(ic)),offset));
749 emitpcode(POC_RLF, popGet(AOP(IC_RESULT(ic)),offset));
753 if(sign && offset > 0 && offset < AOP_SIZE(IC_RESULT(ic))) {
754 /* Now this is really horrid. Gotta check the sign of the addends and propogate
757 emitpcode(POC_BTFSC, newpCodeOpBit(aopGet(AOP(IC_LEFT(ic)),offset-1,FALSE,FALSE),7,0));
758 emitpcode(POC_DECF, popGet(AOP(IC_RESULT(ic)),offset));
759 emitpcode(POC_BTFSC, newpCodeOpBit(aopGet(AOP(IC_RIGHT(ic)),offset-1,FALSE,FALSE),7,0));
760 emitpcode(POC_DECF, popGet(AOP(IC_RESULT(ic)),offset));
762 /* if chars or ints or being signed extended to longs: */
764 emitpcode(POC_MOVLW, popGetLit(0));
765 emitpcode(POC_BTFSC, newpCodeOpBit(aopGet(AOP(IC_RESULT(ic)),offset,FALSE,FALSE),7,0));
766 emitpcode(POC_MOVLW, popGetLit(0xff));
774 emitpcode(POC_MOVWF, popGet(AOP(IC_RESULT(ic)),offset));
776 emitpcode(POC_CLRF, popGet(AOP(IC_RESULT(ic)),offset));
783 //adjustArithmeticResult(ic);
786 freeAsmop(IC_LEFT(ic),NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
787 freeAsmop(IC_RIGHT(ic),NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
788 freeAsmop(IC_RESULT(ic),NULL,ic,TRUE);
791 /*-----------------------------------------------------------------*/
792 /* addSign - propogate sign bit to higher bytes */
793 /*-----------------------------------------------------------------*/
794 void addSign(operand *result, int offset, int sign)
796 int size = (pic14_getDataSize(result) - offset);
797 DEBUGpic14_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
804 emitpcode(POC_CLRF,popGet(AOP(result),offset));
805 emitpcode(POC_BTFSC,newpCodeOpBit(aopGet(AOP(result),offset-1,FALSE,FALSE),7,0));
806 emitpcode(POC_DECF, popGet(AOP(result),offset));
809 emitpcode(POC_MOVLW, popGetLit(0));
810 emitpcode(POC_BTFSC, newpCodeOpBit(aopGet(AOP(result),offset-1,FALSE,FALSE),7,0));
811 emitpcode(POC_MOVLW, popGetLit(0xff));
813 emitpcode(POC_MOVWF, popGet(AOP(result),offset+size));
817 emitpcode(POC_CLRF,popGet(AOP(result),offset++));
821 /*-----------------------------------------------------------------*/
822 /* genMinus - generates code for subtraction */
823 /*-----------------------------------------------------------------*/
824 void genMinus (iCode *ic)
826 int size, offset = 0, same=0;
827 unsigned long lit = 0L;
829 symbol *lbl_comm, *lbl_next;
830 asmop *left, *right, *result;
833 DEBUGpic14_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
834 aopOp (IC_LEFT(ic),ic,FALSE);
835 aopOp (IC_RIGHT(ic),ic,FALSE);
836 aopOp (IC_RESULT(ic),ic,TRUE);
838 if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY &&
839 AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT) {
840 operand *t = IC_RIGHT(ic);
841 IC_RIGHT(ic) = IC_LEFT(ic);
845 DEBUGpic14_emitcode ("; ","result %s, left %s, right %s",
846 AopType(AOP_TYPE(IC_RESULT(ic))),
847 AopType(AOP_TYPE(IC_LEFT(ic))),
848 AopType(AOP_TYPE(IC_RIGHT(ic))));
850 left = AOP(IC_LEFT(ic));
851 right = AOP(IC_RIGHT(ic));
852 result = AOP(IC_RESULT(ic));
854 size = pic14_getDataSize(IC_RESULT(ic));
855 same = pic14_sameRegs(right, result);
857 if((AOP_TYPE(IC_LEFT(ic)) != AOP_LIT)
858 && (pic14_getDataSize(IC_LEFT(ic)) < size))
860 fprintf(stderr, "%s:%d(%s):WARNING: left operand too short for result\n",
861 ic->filename, ic->lineno, __FUNCTION__);
863 if((AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
864 && (pic14_getDataSize(IC_RIGHT(ic)) < size))
866 fprintf(stderr, "%s:%d(%s):WARNING: right operand too short for result\n",
867 ic->filename, ic->lineno, __FUNCTION__ );
870 if(AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT) {
871 /* Add a literal to something else */
873 lit = ulFromVal(right->aopu.aop_lit);
878 } else if(AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
881 pic14_emitcode(";bitsub","right is bit: %s",aopGet(right,0,FALSE,FALSE));
882 pic14_emitcode(";bitsub","left is bit: %s",aopGet(left,0,FALSE,FALSE));
883 pic14_emitcode(";bitsub","result is bit: %s",aopGet(result,0,FALSE,FALSE));
885 /* here we are subtracting a bit from a char or int */
887 if(pic14_sameRegs(left, result)) {
889 emitpcode(POC_BTFSC, popGet(right, 0));
890 emitpcode(POC_DECF , popGet(result, 0));
894 if( (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD) ||
895 (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) ) {
897 * result = literal - bit
899 * XXX: probably fails for AOP_IMMDs!
902 lit = ulFromVal (left->aopu.aop_lit);
904 if(AOP_TYPE(IC_RESULT(ic)) == AOP_CRY) {
905 if(pic14_sameRegs(right, result)) {
907 emitpcode(POC_MOVLW, popGet(right, 0));
908 emitpcode(POC_XORWF, popGet(result, 0));
911 emitpcode(POC_BCF, popGet(result, 0));
913 emitpcode(POC_BTFSS, popGet(right, 0));
915 emitpcode(POC_BTFSC, popGet(right, 0));
916 emitpcode(POC_BSF, popGet(result, 0));
920 emitpcode(POC_MOVLW, popGetLit(lit & 0xff));
921 emitpcode(POC_BTFSC, popGet(right, 0));
922 emitpcode(POC_MOVLW, popGetLit((lit-1) & 0xff));
923 emitpcode(POC_MOVWF, popGet(result, 0));
927 // result = register - bit
928 // XXX: Fails for lit-like left operands
929 emitpcode(POC_MOVFW, popGet(left, 0));
930 emitpcode(POC_BTFSC, popGet(right, 0));
931 emitpcode(POC_DECFW, popGet(left, 0));
932 emitpcode(POC_MOVWF, popGet(result, 0));
936 fprintf(stderr, "WARNING: subtracting bit from multi-byte operands is incomplete.\n");
937 //exit(EXIT_FAILURE);
941 * RIGHT is not a literal and not a bit operand,
942 * LEFT is unknown (register, literal, bit, ...)
947 if(AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) {
948 lit = ulFromVal (left->aopu.aop_lit);
950 DEBUGpic14_emitcode ("; left is lit","line %d result %s, left %s, right %s",__LINE__,
951 AopType(AOP_TYPE(IC_RESULT(ic))),
952 AopType(AOP_TYPE(IC_LEFT(ic))),
953 AopType(AOP_TYPE(IC_RIGHT(ic))));
958 * First byte, no carry-in.
959 * Any optimizations that are longer than 2 instructions are
962 if(same && isLit && ((lit & 0xff) == 0xff)) {
963 // right === res = 0xFF - right = ~right
964 emitpcode(POC_COMF, popGet(right, 0));
966 // setup CARRY/#BORROW
969 } else if((size == 1) && isLit && ((lit & 0xff) == 0xff)) {
970 // res = 0xFF - right = ~right
971 emitpcode(POC_COMFW, popGet(right, 0));
972 emitpcode(POC_MOVWF, popGet(result, 0));
973 // CARRY/#BORROW is not setup correctly
974 } else if((size == 1) && same && isLit && ((lit & 0xff) == 0)) {
975 // right === res = 0 - right = ~right + 1
976 emitpcode(POC_COMF, popGet(right, 0));
977 emitpcode(POC_INCF, popGet(right, 0));
978 // CARRY/#BORROW is not setup correctly
980 // general case, should always work
982 if (pic14_sameRegs(left, result)) {
983 // result === left = left - right (in place)
984 emitpcode(POC_SUBWF, popGet(result, 0));
986 // works always: result = left - right
987 emitpcode(op_isLitLike(IC_LEFT(ic))
988 ? POC_SUBLW : POC_SUBFW,
989 popGetAddr(left, 0, 0));
990 emitpcode(POC_MOVWF, popGet(result, 0));
995 * Now for the remaining bytes with carry-in (and carry-out).
1003 * The following code generation templates are ordered
1004 * according to increasing length; the first template
1005 * that matches will thus be the shortest and produce
1006 * the best code possible with thees templates.
1009 if(pic14_sameRegs(left, right)) {
1011 * This case should not occur; however, the
1012 * template works if LEFT, RIGHT, and RESULT are
1013 * register operands and LEFT and RIGHT are the
1014 * same register(s) and at least as long as the
1021 emitpcode(POC_CLRF, popGet(result, offset));
1022 } else if(pic14_sameRegs(left, result)) {
1024 * This template works if LEFT, RIGHT, and
1025 * RESULT are register operands and LEFT and
1026 * RESULT are the same register(s).
1028 * MOVF right, W ; W := right
1030 * INCFSZ right, W ; W := right + BORROW
1031 * SUBWF result, F ; res === left := left - (right + BORROW)
1033 * The SUBWF *must* be skipped if we have a
1034 * BORROW bit and right == 0xFF in order to
1035 * keep the BORROW bit intact!
1039 mov2w(right, offset);
1041 emitpcode(POC_INCFSZW, popGet(right, offset));
1042 emitpcode(POC_SUBWF, popGet(result, offset));
1043 } else if((size == 1) && isLit && ((lit & 0xff) == 0xff)) {
1045 * This template works for the last byte (MSB) of
1046 * the subtraction and ignores correct propagation
1047 * of the outgoing BORROW bit. RIGHT and RESULT
1048 * must be register operands, LEFT must be the
1051 * (The case LEFT === RESULT is optimized above.)
1053 * 0xFF - right - BORROW = ~right - BORROW
1055 * COMF right, W ; W := 0xff - right
1057 * ADDLW 0xFF ; W := 0xff - right - BORROW
1062 emitpcode(POC_COMFW, popGet(right, offset));
1064 emitpcode(POC_ADDLW, popGetLit(0xff));
1065 emitpcode(POC_MOVWF, popGet(result, offset));
1066 } else if(size == 1) {
1068 * This template works for the last byte (MSB) of
1069 * the subtraction and ignores correct propagation
1070 * of the outgoing BORROW bit. RIGHT and RESULT
1071 * must be register operands, LEFT can be a
1072 * register or a literal operand.
1074 * (The case LEFT === RESULT is optimized above.)
1076 * MOVF right, W ; W := right
1078 * INCF right, W ; W := right + BORROW
1079 * SUBxW left, W ; W := left - right - BORROW
1084 mov2w(right, offset);
1086 emitpcode(POC_INCFW, popGet(right, offset));
1087 emitpcode(op_isLitLike(IC_LEFT(ic))
1088 ? POC_SUBLW : POC_SUBFW,
1089 popGetAddr(left, offset, 0));
1090 emitpcode(POC_MOVWF, popGet(result, offset));
1091 } else if(IS_ITEMP(IC_RESULT(ic))
1092 && !pic14_sameRegs(right, result)) {
1094 * This code template works if RIGHT and RESULT
1095 * are different register operands and RESULT
1096 * is not volatile/an SFR (written twice).
1098 * #########################################
1099 * Since we cannot determine that for sure,
1100 * we approximate via IS_ITEMP() for now.
1101 * #########################################
1103 * MOVxW left, W ; copy left to result
1105 * MOVF right, W ; W := right
1107 * INCFSZ right, W ; W := right + BORROW
1108 * SUBWF result, F ; res === left := left - (right + BORROW)
1110 * 6 cycles, but fails for SFR RESULT operands
1112 mov2w(left, offset);
1113 emitpcode(POC_MOVWF, popGet(result, offset));
1114 mov2w(right, offset);
1116 emitpcode(POC_INCFSZW, popGet(right, offset));
1117 emitpcode(POC_SUBWF, popGet(result, offset));
1118 } else if(!optimize.codeSize && isLit && ((lit & 0xff) != 0)) {
1120 * This template works if RIGHT and RESULT are
1121 * register operands and LEFT is a literal
1134 * 6 cycles, 7 iff BORROW
1137 lbl_comm = newiTempLabel(NULL);
1138 lbl_next = newiTempLabel(NULL);
1140 mov2w(right, offset);
1142 emitpcode(POC_GOTO, popGetLabel(lbl_next->key));
1143 emitpcode(POC_SUBLW, popGetLit((lit - 1) & 0xff));
1144 emitpcode(POC_GOTO, popGetLabel(lbl_comm->key));
1145 emitpLabel(lbl_next->key);
1146 emitpcode(POC_SUBLW, popGetLit(lit & 0xff));
1147 emitpLabel(lbl_comm->key);
1148 emitpcode(POC_MOVWF, popGet(result, offset));
1151 * This code template works if RIGHT and RESULT
1152 * are register operands.
1154 * MOVF right, W ; W := right
1156 * INCFSZ right, W ; W := right + BORROW
1158 * MOVxW left ; if we subtract 0x100 = 0xFF + 1, ...
1159 * GOTO next ; res := left, but keep BORROW intact
1161 * SUBxW left, W ; W := left - (right + BORROW)
1163 * MOVW result ; res := left - (right + BORROW)
1165 * 7 cycles, 8 iff BORROW and (right == 0xFF)
1170 * Alternative approach using -x = ~x + 1 ==> ~x = -x - 1 = -(x + 1)
1172 * COMFW right, W ; W := -right - (assumed BORROW)
1173 * BTFSC STATUS, C ; SKIP if we have a BORROW
1174 * ADDLW 1 ; W := -right (no BORROW)
1175 * BTFSC STATUS, C ; (***)
1176 * MOVLW left ; (***)
1177 * BTFSS STATUS, C ; (***)
1178 * ADDFW left, W ; W := left - right - BORROW (if any)
1179 * MOVWF result ; result := left - right - BORROW (if any)
1183 * Case A: C=0 (BORROW)
1184 * r=0x00, W=0xFF, W=left+0xFF, C iff left>0x00
1185 * r=0x01, W=0xFE, W=left+0xFE, C iff left>0x01
1186 * r=0xFE, W=0x01, W=left+0x01, C iff left>0xFE
1187 * r=0xFF, W=0x00, W=left+0x00, C iff left>0xFF
1189 * Case B: C=1 (no BORROW)
1190 * r=0x00, W=0xFF, W=0x00/C=1, W=left+0x00, C iff left>=0x100 (***)
1191 * r=0x01, W=0xFE, W=0xFF/C=0, W=left+0xFF, C iff left>=0x01
1192 * r=0xFE, W=0x01, W=0x02/C=0, W=left+0x02, C iff left>=0xFE
1193 * r=0xFF, W=0x00, W=0x01/C=0, W=left+0x01, C iff left>=0xFF
1195 lbl_comm = newiTempLabel(NULL);
1196 lbl_next = newiTempLabel(NULL);
1198 mov2w(right, offset);
1200 emitpcode(POC_INCFSZW, popGet(right, offset));
1201 emitpcode(POC_GOTO, popGetLabel(lbl_comm->key));
1202 mov2w(left, offset);
1203 emitpcode(POC_GOTO, popGetLabel(lbl_next->key));
1204 emitpLabel(lbl_comm->key);
1205 emitpcode(op_isLitLike(IC_LEFT(ic))
1206 ? POC_SUBLW : POC_SUBFW,
1207 popGetAddr(left, offset, 0));
1208 emitpLabel(lbl_next->key);
1209 emitpcode(POC_MOVWF, popGet(result, offset));
1214 if(AOP_TYPE(IC_RESULT(ic)) == AOP_CRY) {
1215 fprintf(stderr, "WARNING: AOP_CRY (bit-) results are probably broken. Please report this with source code as a bug.\n");
1216 mov2w(result, 0); // load Z flag
1217 emitpcode(POC_BCF, popGet(result, 0));
1219 emitpcode(POC_BSF, popGet(result, 0));
1222 // adjustArithmeticResult(ic);
1225 freeAsmop(IC_LEFT(ic),NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
1226 freeAsmop(IC_RIGHT(ic),NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
1227 freeAsmop(IC_RESULT(ic),NULL,ic,TRUE);