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 -------------------------------------------------------------------------*/
36 #include "SDCCglobl.h"
39 #if defined(_MSC_VER) && (_MSC_VER < 1300)
40 #define __FUNCTION__ __FILE__
44 #include "SDCCpeeph.h"
50 #define BYTEofLONG(l,b) ( (l>> (b<<3)) & 0xff)
51 extern void DEBUGpic14_AopType(int line_no, operand *left, operand *right, operand *result);
53 const char *AopType(short type)
85 void DebugAop(asmop *aop)
89 printf("%s\n",AopType(aop->type));
90 printf(" current offset: %d\n",aop->coff);
91 printf(" size: %d\n",aop->size);
95 printf(" name: %s\n",aop->aopu.aop_lit->name);
98 printf(" name: %s\n",aop->aopu.aop_reg[0]->name);
102 printf(" name: %s\n",aop->aopu.aop_dir);
105 printf(" Stack offset: %d\n",aop->aopu.aop_stk);
108 printf(" immediate: %s\n",aop->aopu.aop_immd);
111 printf(" aop_str[0]: %s\n",aop->aopu.aop_str[0]);
114 //printpCode(stdout,aop->aopu.pcop);
119 const char *pCodeOpType( pCodeOp *pcop)
138 case PO_GPR_REGISTER:
139 return "PO_GPR_REGISTER";
141 return "PO_GPR_POINTER";
145 return "PO_GPR_TEMP";
146 case PO_SFR_REGISTER:
147 return "PO_SFR_REGISTER";
155 return "PO_IMMEDIATE";
171 return "BAD PO_TYPE";
174 /*-----------------------------------------------------------------*/
175 /* genPlusIncr :- does addition with increment if possible */
176 /*-----------------------------------------------------------------*/
177 bool genPlusIncr (iCode *ic)
179 unsigned int icount ;
180 unsigned int size = pic14_getDataSize(IC_RESULT(ic));
183 DEBUGpic14_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
184 DEBUGpic14_emitcode ("; ","result %s, left %s, right %s",
185 AopType(AOP_TYPE(IC_RESULT(ic))),
186 AopType(AOP_TYPE(IC_LEFT(ic))),
187 AopType(AOP_TYPE(IC_RIGHT(ic))));
189 /* will try to generate an increment */
190 /* if the right side is not a literal
192 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
195 DEBUGpic14_emitcode ("; ","%s %d",__FUNCTION__,__LINE__);
196 /* if the literal value of the right hand side
197 is greater than 1 then it is faster to add */
198 if ((icount = (unsigned int) ulFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit)) > 2)
201 /* if increment 16 bits in register */
202 if (pic14_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
207 emitpcode(POC_INCF, popGet(AOP(IC_RESULT(ic)),LSB));
208 //pic14_emitcode("incf","%s,f",aopGet(AOP(IC_RESULT(ic)),LSB,FALSE,FALSE));
212 emitpcode(POC_INCF, popGet(AOP(IC_RESULT(ic)),offset++));
213 //pic14_emitcode(" incf","%s,f",aopGet(AOP(IC_RESULT(ic)),offset++,FALSE,FALSE));
219 DEBUGpic14_emitcode ("; ","%s %d",__FUNCTION__,__LINE__);
220 /* if left is in accumulator - probably a bit operation*/
221 if( strcmp(aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE),"a") &&
222 (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY) ) {
224 emitpcode(POC_BCF, popGet(AOP(IC_RESULT(ic)),0));
225 pic14_emitcode("bcf","(%s >> 3), (%s & 7)",
226 AOP(IC_RESULT(ic))->aopu.aop_dir,
227 AOP(IC_RESULT(ic))->aopu.aop_dir);
229 emitpcode(POC_XORLW,popGetLit(1));
230 //pic14_emitcode("xorlw","1");
232 emitpcode(POC_ANDLW,popGetLit(1));
233 //pic14_emitcode("andlw","1");
236 emitpcode(POC_BSF, popGet(AOP(IC_RESULT(ic)),0));
237 pic14_emitcode("bsf","(%s >> 3), (%s & 7)",
238 AOP(IC_RESULT(ic))->aopu.aop_dir,
239 AOP(IC_RESULT(ic))->aopu.aop_dir);
246 /* if the sizes are greater than 1 then we cannot */
247 if (AOP_SIZE(IC_RESULT(ic)) > 1 ||
248 AOP_SIZE(IC_LEFT(ic)) > 1 )
251 /* If we are incrementing the same register by two: */
253 if (pic14_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) {
256 emitpcode(POC_INCF, popGet(AOP(IC_RESULT(ic)),0));
257 //pic14_emitcode("incf","%s,f",aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE));
262 DEBUGpic14_emitcode ("; ","couldn't increment ");
267 /*-----------------------------------------------------------------*/
268 /* pic14_outBitAcc - output a bit in acc */
269 /*-----------------------------------------------------------------*/
270 void pic14_outBitAcc(operand *result)
272 symbol *tlbl = newiTempLabel(NULL);
273 /* if the result is a bit */
275 DEBUGpic14_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
277 if (AOP_TYPE(result) == AOP_CRY){
278 aopPut(AOP(result),"a",0);
281 pic14_emitcode("jz","%05d_DS_",tlbl->key+100);
282 pic14_emitcode("mov","a,#01");
283 pic14_emitcode("","%05d_DS_:",tlbl->key+100);
284 pic14_outAcc(result);
289 /* This is the original version of this code.
291 * This is being kept around for reference,
292 * because I am not entirely sure I got it right...
294 static void adjustArithmeticResult(iCode *ic)
296 if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
297 AOP_SIZE(IC_LEFT(ic)) == 3 &&
298 !pic14_sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))))
299 aopPut(AOP(IC_RESULT(ic)),
300 aopGet(AOP(IC_LEFT(ic)),2,FALSE,FALSE),
303 if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
304 AOP_SIZE(IC_RIGHT(ic)) == 3 &&
305 !pic14_sameRegs(AOP(IC_RESULT(ic)),AOP(IC_RIGHT(ic))))
306 aopPut(AOP(IC_RESULT(ic)),
307 aopGet(AOP(IC_RIGHT(ic)),2,FALSE,FALSE),
310 if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
311 AOP_SIZE(IC_LEFT(ic)) < 3 &&
312 AOP_SIZE(IC_RIGHT(ic)) < 3 &&
313 !pic14_sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))) &&
314 !pic14_sameRegs(AOP(IC_RESULT(ic)),AOP(IC_RIGHT(ic)))) {
316 sprintf(buffer,"#%d",pointerCode(getSpec(operandType(IC_LEFT(ic)))));
317 aopPut(AOP(IC_RESULT(ic)),buffer,2);
321 /* This is the pure and virtuous version of this code.
322 * I'm pretty certain it's right, but not enough to toss the old
325 static void adjustArithmeticResult(iCode *ic)
327 if (opIsGptr(IC_RESULT(ic)) &&
328 opIsGptr(IC_LEFT(ic)) &&
329 !pic14_sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))))
331 aopPut(AOP(IC_RESULT(ic)),
332 aopGet(AOP(IC_LEFT(ic)), GPTRSIZE - 1,FALSE,FALSE),
336 if (opIsGptr(IC_RESULT(ic)) &&
337 opIsGptr(IC_RIGHT(ic)) &&
338 !pic14_sameRegs(AOP(IC_RESULT(ic)),AOP(IC_RIGHT(ic))))
340 aopPut(AOP(IC_RESULT(ic)),
341 aopGet(AOP(IC_RIGHT(ic)),GPTRSIZE - 1,FALSE,FALSE),
345 if (opIsGptr(IC_RESULT(ic)) &&
346 AOP_SIZE(IC_LEFT(ic)) < GPTRSIZE &&
347 AOP_SIZE(IC_RIGHT(ic)) < GPTRSIZE &&
348 !pic14_sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))) &&
349 !pic14_sameRegs(AOP(IC_RESULT(ic)),AOP(IC_RIGHT(ic)))) {
351 sprintf(buffer,"#%d",pointerCode(getSpec(operandType(IC_LEFT(ic)))));
352 aopPut(AOP(IC_RESULT(ic)),buffer,GPTRSIZE - 1);
357 /*-----------------------------------------------------------------*/
358 /* genAddlit - generates code for addition */
359 /*-----------------------------------------------------------------*/
360 static void genAddLit2byte (operand *result, int offr, int lit)
368 emitpcode(POC_INCF, popGet(AOP(result),offr));
371 emitpcode(POC_DECF, popGet(AOP(result),offr));
374 emitpcode(POC_MOVLW,popGetLit(lit&0xff));
375 emitpcode(POC_ADDWF,popGet(AOP(result),offr));
380 static void emitMOVWF(operand *reg, int offset)
386 emitpcode(POC_MOVWF, popGet(AOP(reg),offset));
390 static void genAddLit (iCode *ic, int lit)
400 DEBUGpic14_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
404 result = IC_RESULT(ic);
405 same = pic14_sameRegs(AOP(left), AOP(result));
406 size = pic14_getDataSize(result);
407 if (size > pic14_getDataSize(left))
408 size = pic14_getDataSize(left);
412 /* Handle special cases first */
414 genAddLit2byte (result, 0, lit);
417 int hi = 0xff & (lit >> 8);
424 DEBUGpic14_emitcode ("; hi = 0","%s %d",__FUNCTION__,__LINE__);
429 emitpcode(POC_INCF, popGet(AOP(result),0));
431 emitpcode(POC_INCF, popGet(AOP(result),MSB16));
434 emitpcode(POC_DECF, popGet(AOP(result),0));
435 emitpcode(POC_INCFSZW, popGet(AOP(result),0));
436 emitpcode(POC_INCF, popGet(AOP(result),MSB16));
440 emitpcode(POC_MOVLW,popGetLit(lit&0xff));
441 emitpcode(POC_ADDWF,popGet(AOP(result),0));
443 emitpcode(POC_INCF, popGet(AOP(result),MSB16));
451 DEBUGpic14_emitcode ("; hi = 1","%s %d",__FUNCTION__,__LINE__);
454 emitpcode(POC_INCF, popGet(AOP(result),MSB16));
457 emitpcode(POC_INCF, popGet(AOP(result),MSB16));
458 emitpcode(POC_INCF, popGet(AOP(result),0));
460 emitpcode(POC_INCF, popGet(AOP(result),MSB16));
462 case 0xff: /* 0x01ff */
463 emitpcode(POC_DECF, popGet(AOP(result),0));
464 emitpcode(POC_INCFSZW, popGet(AOP(result),0));
465 emitpcode(POC_INCF, popGet(AOP(result),MSB16));
466 emitpcode(POC_INCF, popGet(AOP(result),MSB16));
471 DEBUGpic14_emitcode ("; hi = ff","%s %d",__FUNCTION__,__LINE__);
475 emitpcode(POC_DECF, popGet(AOP(result),MSB16));
478 emitpcode(POC_INCFSZ, popGet(AOP(result),0));
479 emitpcode(POC_DECF, popGet(AOP(result),MSB16));
481 /* case 0xff: * 0xffff *
482 emitpcode(POC_INCFSZW, popGet(AOP(result),0,FALSE,FALSE));
483 emitpcode(POC_INCF, popGet(AOP(result),MSB16,FALSE,FALSE));
484 emitpcode(POC_DECF, popGet(AOP(result),0,FALSE,FALSE));
488 emitpcode(POC_MOVLW,popGetLit(lo));
489 emitpcode(POC_ADDWF,popGet(AOP(result),0));
491 emitpcode(POC_DECF, popGet(AOP(result),MSB16));
498 DEBUGpic14_emitcode ("; hi is generic","%d %s %d",hi,__FUNCTION__,__LINE__);
503 genAddLit2byte (result, MSB16, hi);
506 emitpcode(POC_MOVLW,popGetLit((hi+1)&0xff));
507 emitpcode(POC_INCFSZ, popGet(AOP(result),0));
508 emitpcode(POC_MOVLW,popGetLit(hi));
509 emitpcode(POC_ADDWF,popGet(AOP(result),MSB16));
511 /* case 0xff: * 0xHHff *
512 emitpcode(POC_MOVFW, popGet(AOP(result),0,FALSE,FALSE));
513 emitpcode(POC_DECF, popGet(AOP(result),MSB16,FALSE,FALSE));
514 emitpcode(POC_MOVLW,popGetLit(hi));
515 emitpcode(POC_ADDWF,popGet(AOP(result),MSB16,FALSE,FALSE));
517 */ default: /* 0xHHLL */
518 emitpcode(POC_MOVLW,popGetLit(lo));
519 emitpcode(POC_ADDWF, popGet(AOP(result),0));
520 emitpcode(POC_MOVLW,popGetLit(hi));
522 emitpcode(POC_MOVLW,popGetLit((hi+1) & 0xff));
523 emitpcode(POC_ADDWF,popGet(AOP(result),MSB16));
532 DEBUGpic14_emitcode ("; add lit to long","%s %d",__FUNCTION__,__LINE__);
535 lo = BYTEofLONG(lit,0);
543 emitpcode(POC_INCF, popGet(AOP(result),offset));
546 emitpcode(POC_RLFW, popGet(AOP(result),offset));
547 emitpcode(POC_ANDLW,popGetLit(1));
548 emitpcode(POC_ADDWF, popGet(AOP(result),offset));
550 default: /* carry_info = 3 */
552 emitpcode(POC_INCF, popGet(AOP(result),offset));
558 emitpcode(POC_MOVLW,popGetLit(lo));
563 emitpcode(POC_ADDWF, popGet(AOP(result),offset));
566 emitpcode(POC_MOVLW,popGetLit(lo));
571 emitpcode(POC_MOVLW,popGetLit(lo+1));
572 emitpcode(POC_ADDWF, popGet(AOP(result),offset));
577 /* no carry info from previous step */
578 /* this means this is the first time to add */
583 emitpcode(POC_INCF, popGet(AOP(result),offset));
587 emitpcode(POC_MOVLW,popGetLit(lo));
588 emitpcode(POC_ADDWF, popGet(AOP(result),offset));
590 carry_info = 3; /* Were adding only one byte and propogating the carry */
601 lo = BYTEofLONG(lit,0);
606 emitpcode(POC_INCF, popGet(AOP(result),0,FALSE,FALSE));
609 emitpcode(POC_MOVLW,popGetLit(lo));
610 emitpcode(POC_ADDWF, popGet(AOP(result),0,FALSE,FALSE));
613 emitpcode(POC_INCF, popGet(AOP(result),1,FALSE,FALSE));
615 emitpcode(POC_INCF, popGet(AOP(result),2,FALSE,FALSE));
617 emitpcode(POC_INCF, popGet(AOP(result),3,FALSE,FALSE));
626 DEBUGpic14_emitcode ("; left and result aren't same","%s %d",__FUNCTION__,__LINE__);
630 /* left addend is in a register */
633 emitpcode(POC_MOVFW, popGet(AOP(left),0));
634 emitMOVWF(result, 0);
635 //emitpcode(POC_MOVWF, popGet(AOP(result),0,FALSE,FALSE));
639 emitpcode(POC_INCFW, popGet(AOP(left),0));
640 //emitpcode(POC_MOVWF, popGet(AOP(result),0,FALSE,FALSE));
644 emitpcode(POC_DECFW, popGet(AOP(left),0));
645 //emitpcode(POC_MOVWF, popGet(AOP(result),0,FALSE,FALSE));
649 emitpcode(POC_MOVLW, popGetLit(lit & 0xff));
650 emitpcode(POC_ADDFW, popGet(AOP(left),0));
651 //emitpcode(POC_MOVWF, popGet(AOP(result),0,FALSE,FALSE));
658 /* left is not the accumulator */
660 emitpcode(POC_MOVLW, popGetLit(lit & 0xff));
661 emitpcode(POC_ADDFW, popGet(AOP(left),0));
663 emitpcode(POC_MOVFW, popGet(AOP(left),0));
664 /* We don't know the state of the carry bit at this point */
667 //emitpcode(POC_MOVWF, popGet(AOP(result),0,FALSE,FALSE));
674 /* The ls byte of the lit must've been zero - that
675 means we don't have to deal with carry */
677 emitpcode(POC_MOVLW, popGetLit(lit & 0xff));
678 emitpcode(POC_ADDFW, popGet(AOP(left),offset));
679 emitpcode(POC_MOVWF, popGet(AOP(left),offset));
684 emitpcode(POC_MOVLW, popGetLit(lit & 0xff));
685 //emitpcode(POC_MOVWF, popGet(AOP(result),offset,FALSE,FALSE));
686 emitMOVWF(result,offset);
687 emitpcode(POC_MOVFW, popGet(AOP(left),offset));
689 emitpcode(POC_INCFSZW,popGet(AOP(left),offset));
690 emitpcode(POC_ADDWF, popGet(AOP(result),offset));
694 emitpcode(POC_CLRF, popGet(AOP(result),offset));
695 emitpcode(POC_RLF, popGet(AOP(result),offset));
696 emitpcode(POC_MOVFW, popGet(AOP(left),offset));
697 emitpcode(POC_ADDWF, popGet(AOP(result),offset));
704 size = pic14_getDataSize(result);
705 if (size > pic14_getDataSize(left))
706 size = pic14_getDataSize(left);
707 addSign(result, size, 0);
710 /*-----------------------------------------------------------------*/
711 /* genPlus - generates code for addition */
712 /*-----------------------------------------------------------------*/
713 void genPlus (iCode *ic)
715 int size, offset = 0;
717 /* special cases :- */
718 DEBUGpic14_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
721 aopOp (IC_LEFT(ic),ic,FALSE);
722 aopOp (IC_RIGHT(ic),ic,FALSE);
723 aopOp (IC_RESULT(ic),ic,TRUE);
725 DEBUGpic14_AopType(__LINE__,IC_LEFT(ic),IC_RIGHT(ic),IC_RESULT(ic));
727 /* if literal, literal on the right or
728 if left requires ACC or right is already
731 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) {
732 operand *t = IC_RIGHT(ic);
733 IC_RIGHT(ic) = IC_LEFT(ic);
737 /* if left in bit space & right literal */
738 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
739 AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT) {
740 /* if result in bit space */
741 if(AOP_TYPE(IC_RESULT(ic)) == AOP_CRY){
742 if(ulFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit) != 0L) {
743 emitpcode(POC_MOVLW, popGet(AOP(IC_RESULT(ic)),0));
744 if (!pic14_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) )
745 emitpcode(POC_BTFSC, popGet(AOP(IC_LEFT(ic)),0));
746 emitpcode(POC_XORWF, popGet(AOP(IC_RESULT(ic)),0));
749 size = pic14_getDataSize(IC_RESULT(ic));
751 MOVA(aopGet(AOP(IC_RIGHT(ic)),offset,FALSE,FALSE));
752 pic14_emitcode("addc","a,#00 ;%d",__LINE__);
753 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
759 /* if I can do an increment instead
760 of add then GOOD for ME */
761 if (genPlusIncr (ic) == TRUE)
764 size = pic14_getDataSize(IC_RESULT(ic));
766 if(AOP(IC_RIGHT(ic))->type == AOP_LIT) {
767 /* Add a literal to something else */
769 unsigned lit = (unsigned) ulFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit);
773 DEBUGpic14_emitcode(";","adding lit to something. size %d",size);
778 } else if(AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
780 pic14_emitcode(";bitadd","right is bit: %s",aopGet(AOP(IC_RIGHT(ic)),0,FALSE,FALSE));
781 pic14_emitcode(";bitadd","left is bit: %s",aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE));
782 pic14_emitcode(";bitadd","result is bit: %s",aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE));
784 /* here we are adding a bit to a char or int */
786 if (pic14_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) {
787 emitpcode(POC_BTFSC , popGet(AOP(IC_RIGHT(ic)),0));
788 emitpcode(POC_INCF , popGet(AOP(IC_RESULT(ic)),0));
791 emitpcode(POC_MOVFW , popGet(AOP(IC_LEFT(ic)),0));
792 emitpcode(POC_BTFSC , popGet(AOP(IC_RIGHT(ic)),0));
793 emitpcode(POC_INCFW , popGet(AOP(IC_LEFT(ic)),0));
795 if(AOP_TYPE(IC_RESULT(ic)) == AOP_CRY) {
796 emitpcode(POC_ANDLW , popGetLit(1));
797 emitpcode(POC_BCF , popGet(AOP(IC_RESULT(ic)),0));
799 emitpcode(POC_BSF , popGet(AOP(IC_RESULT(ic)),0));
801 emitpcode(POC_MOVWF , popGet(AOP(IC_RESULT(ic)),0));
807 DEBUGpic14_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
808 if (pic14_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) {
810 emitpcode(POC_BTFSC, popGet(AOP(IC_RIGHT(ic)),0));
811 emitpcode(POC_INCF, popGet(AOP(IC_RESULT(ic)),0));
814 emitpcode(POC_MOVFW, popGet(AOP(IC_LEFT(ic)),0));
815 emitpcode(POC_BTFSC, popGet(AOP(IC_RIGHT(ic)),0));
816 emitpcode(POC_INCFW, popGet(AOP(IC_LEFT(ic)),0));
817 //emitpcode(POC_MOVWF, popGet(AOP(IC_RIGHT(ic)),0,FALSE,FALSE));
818 emitMOVWF(IC_RIGHT(ic),0);
823 emitpcode(POC_INCF, popGet(AOP(IC_RESULT(ic)),offset++));
829 DEBUGpic14_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
831 /* Add the first bytes */
833 if(strcmp(aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE),"a") == 0 ) {
834 emitpcode(POC_ADDFW, popGet(AOP(IC_RIGHT(ic)),0));
835 emitpcode(POC_MOVWF,popGet(AOP(IC_RESULT(ic)),0));
838 emitpcode(POC_MOVFW,popGet(AOP(IC_RIGHT(ic)),0));
840 if (pic14_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) )
841 emitpcode(POC_ADDWF, popGet(AOP(IC_LEFT(ic)),0));
843 PIC_OPCODE poc = POC_ADDFW;
845 if (op_isLitLike (IC_LEFT (ic)))
847 emitpcode(poc, popGetAddr(AOP(IC_LEFT(ic)),0,0));
848 emitpcode(POC_MOVWF,popGet(AOP(IC_RESULT(ic)),0));
852 size = min( AOP_SIZE(IC_RESULT(ic)), AOP_SIZE(IC_RIGHT(ic))) - 1;
857 if (pic14_sameRegs(AOP(IC_RIGHT(ic)), AOP(IC_RESULT(ic)))) {
858 if (op_isLitLike (IC_LEFT(ic)))
861 emitpcode(POC_MOVFW, popGet(AOP(IC_RIGHT(ic)),offset));
863 emitpcode(POC_INCFSZW, popGet(AOP(IC_RIGHT(ic)),offset));
864 emitpcode(POC_ADDLW, popGetAddr(AOP(IC_LEFT(ic)),offset,0));
865 emitpcode(POC_MOVWF, popGet(AOP(IC_RESULT(ic)),offset));
870 emitpcode(POC_MOVFW, popGet(AOP(IC_LEFT(ic)),offset));
872 emitpcode(POC_INCFSZW, popGet(AOP(IC_LEFT(ic)),offset));
873 emitpcode(POC_ADDWF, popGet(AOP(IC_RESULT(ic)),offset));
878 PIC_OPCODE poc = POC_MOVFW;
879 if (op_isLitLike (IC_LEFT(ic)))
882 if (!pic14_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) {
883 emitpcode(poc, popGetAddr(AOP(IC_LEFT(ic)),offset,0));
884 emitpcode(POC_MOVWF, popGet(AOP(IC_RESULT(ic)),offset));
886 emitpcode(POC_MOVFW, popGet(AOP(IC_RIGHT(ic)),offset));
888 emitpcode(POC_INCFSZW, popGet(AOP(IC_RIGHT(ic)),offset));
889 emitpcode(POC_ADDWF, popGet(AOP(IC_RESULT(ic)),offset));
896 if (AOP_SIZE(IC_RESULT(ic)) > AOP_SIZE(IC_RIGHT(ic))) {
897 int sign = !(SPEC_USIGN(getSpec(operandType(IC_LEFT(ic)))) |
898 SPEC_USIGN(getSpec(operandType(IC_RIGHT(ic)))) );
901 /* Need to extend result to higher bytes */
902 size = AOP_SIZE(IC_RESULT(ic)) - AOP_SIZE(IC_RIGHT(ic)) - 1;
904 /* First grab the carry from the lower bytes */
905 if (AOP_SIZE(IC_LEFT(ic)) > AOP_SIZE(IC_RIGHT(ic))) {
906 int leftsize = AOP_SIZE(IC_LEFT(ic)) - AOP_SIZE(IC_RIGHT(ic));
907 PIC_OPCODE poc = POC_MOVFW;
908 if (op_isLitLike (IC_LEFT(ic)))
910 while(leftsize-- > 0) {
911 emitpcode(poc, popGetAddr(AOP(IC_LEFT(ic)),offset,0));
913 emitpcode(POC_ADDLW, popGetLit(0x01));
914 emitpcode(POC_MOVWF, popGet(AOP(IC_RESULT(ic)),offset));
916 //emitpcode(POC_INCF, popGet(AOP(IC_RESULT(ic)),offset)); /* INCF does not update Carry! */
924 emitpcode(POC_CLRF, popGet(AOP(IC_RESULT(ic)),offset));
925 emitpcode(POC_RLF, popGet(AOP(IC_RESULT(ic)),offset));
929 if(sign && offset > 0 && offset < AOP_SIZE(IC_RESULT(ic))) {
930 /* Now this is really horrid. Gotta check the sign of the addends and propogate
933 emitpcode(POC_BTFSC, newpCodeOpBit(aopGet(AOP(IC_LEFT(ic)),offset-1,FALSE,FALSE),7,0));
934 emitpcode(POC_DECF, popGet(AOP(IC_RESULT(ic)),offset));
935 emitpcode(POC_BTFSC, newpCodeOpBit(aopGet(AOP(IC_RIGHT(ic)),offset-1,FALSE,FALSE),7,0));
936 emitpcode(POC_DECF, popGet(AOP(IC_RESULT(ic)),offset));
938 /* if chars or ints or being signed extended to longs: */
940 emitpcode(POC_MOVLW, popGetLit(0));
941 emitpcode(POC_BTFSC, newpCodeOpBit(aopGet(AOP(IC_RESULT(ic)),offset,FALSE,FALSE),7,0));
942 emitpcode(POC_MOVLW, popGetLit(0xff));
950 emitpcode(POC_MOVWF, popGet(AOP(IC_RESULT(ic)),offset));
952 emitpcode(POC_CLRF, popGet(AOP(IC_RESULT(ic)),offset));
959 //adjustArithmeticResult(ic);
962 freeAsmop(IC_LEFT(ic),NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
963 freeAsmop(IC_RIGHT(ic),NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
964 freeAsmop(IC_RESULT(ic),NULL,ic,TRUE);
967 /*-----------------------------------------------------------------*/
968 /* addSign - propogate sign bit to higher bytes */
969 /*-----------------------------------------------------------------*/
970 void addSign(operand *result, int offset, int sign)
972 int size = (pic14_getDataSize(result) - offset);
973 DEBUGpic14_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
980 emitpcode(POC_CLRF,popGet(AOP(result),offset));
981 emitpcode(POC_BTFSC,newpCodeOpBit(aopGet(AOP(result),offset-1,FALSE,FALSE),7,0));
982 emitpcode(POC_DECF, popGet(AOP(result),offset));
985 emitpcode(POC_MOVLW, popGetLit(0));
986 emitpcode(POC_BTFSC, newpCodeOpBit(aopGet(AOP(result),offset-1,FALSE,FALSE),7,0));
987 emitpcode(POC_MOVLW, popGetLit(0xff));
989 emitpcode(POC_MOVWF, popGet(AOP(result),offset+size));
993 emitpcode(POC_CLRF,popGet(AOP(result),offset++));
997 /*-----------------------------------------------------------------*/
998 /* genMinus - generates code for subtraction */
999 /*-----------------------------------------------------------------*/
1000 void genMinus (iCode *ic)
1002 int size, offset = 0, same=0;
1003 unsigned long lit = 0L;
1005 symbol *lbl_comm, *lbl_next;
1006 asmop *left, *right, *result;
1009 DEBUGpic14_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
1010 aopOp (IC_LEFT(ic),ic,FALSE);
1011 aopOp (IC_RIGHT(ic),ic,FALSE);
1012 aopOp (IC_RESULT(ic),ic,TRUE);
1014 if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY &&
1015 AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT) {
1016 operand *t = IC_RIGHT(ic);
1017 IC_RIGHT(ic) = IC_LEFT(ic);
1021 DEBUGpic14_emitcode ("; ","result %s, left %s, right %s",
1022 AopType(AOP_TYPE(IC_RESULT(ic))),
1023 AopType(AOP_TYPE(IC_LEFT(ic))),
1024 AopType(AOP_TYPE(IC_RIGHT(ic))));
1026 left = AOP(IC_LEFT(ic));
1027 right = AOP(IC_RIGHT(ic));
1028 result = AOP(IC_RESULT(ic));
1030 size = pic14_getDataSize(IC_RESULT(ic));
1031 same = pic14_sameRegs(right, result);
1033 if((AOP_TYPE(IC_LEFT(ic)) != AOP_LIT)
1034 && (pic14_getDataSize(IC_LEFT(ic)) < size))
1036 fprintf(stderr, "%s:%d(%s):WARNING: left operand too short for result\n",
1037 ic->filename, ic->lineno, __FUNCTION__);
1039 if((AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
1040 && (pic14_getDataSize(IC_RIGHT(ic)) < size))
1042 fprintf(stderr, "%s:%d(%s):WARNING: right operand too short for result\n",
1043 ic->filename, ic->lineno, __FUNCTION__ );
1046 if(AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT) {
1047 /* Add a literal to something else */
1049 lit = ulFromVal(right->aopu.aop_lit);
1054 } else if(AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
1057 pic14_emitcode(";bitsub","right is bit: %s",aopGet(right,0,FALSE,FALSE));
1058 pic14_emitcode(";bitsub","left is bit: %s",aopGet(left,0,FALSE,FALSE));
1059 pic14_emitcode(";bitsub","result is bit: %s",aopGet(result,0,FALSE,FALSE));
1061 /* here we are subtracting a bit from a char or int */
1063 if(pic14_sameRegs(left, result)) {
1065 emitpcode(POC_BTFSC, popGet(right, 0));
1066 emitpcode(POC_DECF , popGet(result, 0));
1070 if( (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD) ||
1071 (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) ) {
1073 * result = literal - bit
1075 * XXX: probably fails for AOP_IMMDs!
1078 lit = ulFromVal (left->aopu.aop_lit);
1080 if(AOP_TYPE(IC_RESULT(ic)) == AOP_CRY) {
1081 if(pic14_sameRegs(right, result)) {
1083 emitpcode(POC_MOVLW, popGet(right, 0));
1084 emitpcode(POC_XORWF, popGet(result, 0));
1087 emitpcode(POC_BCF, popGet(result, 0));
1089 emitpcode(POC_BTFSS, popGet(right, 0));
1091 emitpcode(POC_BTFSC, popGet(right, 0));
1092 emitpcode(POC_BSF, popGet(result, 0));
1096 emitpcode(POC_MOVLW, popGetLit(lit & 0xff));
1097 emitpcode(POC_BTFSC, popGet(right, 0));
1098 emitpcode(POC_MOVLW, popGetLit((lit-1) & 0xff));
1099 emitpcode(POC_MOVWF, popGet(result, 0));
1103 // result = register - bit
1104 // XXX: Fails for lit-like left operands
1105 emitpcode(POC_MOVFW, popGet(left, 0));
1106 emitpcode(POC_BTFSC, popGet(right, 0));
1107 emitpcode(POC_DECFW, popGet(left, 0));
1108 emitpcode(POC_MOVWF, popGet(result, 0));
1112 fprintf(stderr, "WARNING: subtracting bit from multi-byte operands is incomplete.\n");
1113 //exit(EXIT_FAILURE);
1117 * RIGHT is not a literal and not a bit operand,
1118 * LEFT is unknown (register, literal, bit, ...)
1123 if(AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) {
1124 lit = ulFromVal (left->aopu.aop_lit);
1126 DEBUGpic14_emitcode ("; left is lit","line %d result %s, left %s, right %s",__LINE__,
1127 AopType(AOP_TYPE(IC_RESULT(ic))),
1128 AopType(AOP_TYPE(IC_LEFT(ic))),
1129 AopType(AOP_TYPE(IC_RIGHT(ic))));
1134 * First byte, no carry-in.
1135 * Any optimizations that are longer than 2 instructions are
1138 if(same && isLit && ((lit & 0xff) == 0xff)) {
1139 // right === res = 0xFF - right = ~right
1140 emitpcode(POC_COMF, popGet(right, 0));
1142 // setup CARRY/#BORROW
1145 } else if((size == 1) && isLit && ((lit & 0xff) == 0xff)) {
1146 // res = 0xFF - right = ~right
1147 emitpcode(POC_COMFW, popGet(right, 0));
1148 emitpcode(POC_MOVWF, popGet(result, 0));
1149 // CARRY/#BORROW is not setup correctly
1150 } else if((size == 1) && same && isLit && ((lit & 0xff) == 0)) {
1151 // right === res = 0 - right = ~right + 1
1152 emitpcode(POC_COMF, popGet(right, 0));
1153 emitpcode(POC_INCF, popGet(right, 0));
1154 // CARRY/#BORROW is not setup correctly
1156 // general case, should always work
1158 if (pic14_sameRegs(left, result)) {
1159 // result === left = left - right (in place)
1160 emitpcode(POC_SUBWF, popGet(result, 0));
1162 // works always: result = left - right
1163 emitpcode(op_isLitLike(IC_LEFT(ic))
1164 ? POC_SUBLW : POC_SUBFW,
1165 popGetAddr(left, 0, 0));
1166 emitpcode(POC_MOVWF, popGet(result, 0));
1171 * Now for the remaining bytes with carry-in (and carry-out).
1179 * The following code generation templates are ordered
1180 * according to increasing length; the first template
1181 * that matches will thus be the shortest and produce
1182 * the best code possible with thees templates.
1185 if(pic14_sameRegs(left, right)) {
1187 * This case should not occur; however, the
1188 * template works if LEFT, RIGHT, and RESULT are
1189 * register operands and LEFT and RIGHT are the
1190 * same register(s) and at least as long as the
1197 emitpcode(POC_CLRF, popGet(result, offset));
1198 } else if(pic14_sameRegs(left, result)) {
1200 * This template works if LEFT, RIGHT, and
1201 * RESULT are register operands and LEFT and
1202 * RESULT are the same register(s).
1204 * MOVF right, W ; W := right
1206 * INCFSZ right, W ; W := right + BORROW
1207 * SUBWF result, F ; res === left := left - (right + BORROW)
1209 * The SUBWF *must* be skipped if we have a
1210 * BORROW bit and right == 0xFF in order to
1211 * keep the BORROW bit intact!
1215 mov2w(right, offset);
1217 emitpcode(POC_INCFSZW, popGet(right, offset));
1218 emitpcode(POC_SUBWF, popGet(result, offset));
1219 } else if((size == 1) && isLit && ((lit & 0xff) == 0xff)) {
1221 * This template works for the last byte (MSB) of
1222 * the subtraction and ignores correct propagation
1223 * of the outgoing BORROW bit. RIGHT and RESULT
1224 * must be register operands, LEFT must be the
1227 * (The case LEFT === RESULT is optimized above.)
1229 * 0xFF - right - BORROW = ~right - BORROW
1231 * COMF right, W ; W := 0xff - right
1233 * ADDLW 0xFF ; W := 0xff - right - BORROW
1238 emitpcode(POC_COMFW, popGet(right, offset));
1240 emitpcode(POC_ADDLW, popGetLit(0xff));
1241 emitpcode(POC_MOVWF, popGet(result, offset));
1242 } else if(size == 1) {
1244 * This template works for the last byte (MSB) of
1245 * the subtraction and ignores correct propagation
1246 * of the outgoing BORROW bit. RIGHT and RESULT
1247 * must be register operands, LEFT can be a
1248 * register or a literal operand.
1250 * (The case LEFT === RESULT is optimized above.)
1252 * MOVF right, W ; W := right
1254 * INCF right, W ; W := right + BORROW
1255 * SUBxW left, W ; W := left - right - BORROW
1260 mov2w(right, offset);
1262 emitpcode(POC_INCFW, popGet(right, offset));
1263 emitpcode(op_isLitLike(IC_LEFT(ic))
1264 ? POC_SUBLW : POC_SUBFW,
1265 popGetAddr(left, offset, 0));
1266 emitpcode(POC_MOVWF, popGet(result, offset));
1267 } else if(IS_ITEMP(IC_RESULT(ic))
1268 && !pic14_sameRegs(right, result)) {
1270 * This code template works if RIGHT and RESULT
1271 * are different register operands and RESULT
1272 * is not volatile/an SFR (written twice).
1274 * #########################################
1275 * Since we cannot determine that for sure,
1276 * we approximate via IS_ITEMP() for now.
1277 * #########################################
1279 * MOVxW left, W ; copy left to result
1281 * MOVF right, W ; W := right
1283 * INCFSZ right, W ; W := right + BORROW
1284 * SUBWF result, F ; res === left := left - (right + BORROW)
1286 * 6 cycles, but fails for SFR RESULT operands
1288 mov2w(left, offset);
1289 emitpcode(POC_MOVWF, popGet(result, offset));
1290 mov2w(right, offset);
1292 emitpcode(POC_INCFSZW, popGet(right, offset));
1293 emitpcode(POC_SUBWF, popGet(result, offset));
1294 } else if(!optimize.codeSize && isLit && ((lit & 0xff) != 0)) {
1296 * This template works if RIGHT and RESULT are
1297 * register operands and LEFT is a literal
1310 * 6 cycles, 7 iff BORROW
1313 lbl_comm = newiTempLabel(NULL);
1314 lbl_next = newiTempLabel(NULL);
1316 mov2w(right, offset);
1318 emitpcode(POC_GOTO, popGetLabel(lbl_next->key));
1319 emitpcode(POC_SUBLW, popGetLit((lit - 1) & 0xff));
1320 emitpcode(POC_GOTO, popGetLabel(lbl_comm->key));
1321 emitpLabel(lbl_next->key);
1322 emitpcode(POC_SUBLW, popGetLit(lit & 0xff));
1323 emitpLabel(lbl_comm->key);
1324 emitpcode(POC_MOVWF, popGet(result, offset));
1327 * This code template works if RIGHT and RESULT
1328 * are register operands.
1330 * MOVF right, W ; W := right
1332 * INCFSZ right, W ; W := right + BORROW
1334 * MOVxW left ; if we subtract 0x100 = 0xFF + 1, ...
1335 * GOTO next ; res := left, but keep BORROW intact
1337 * SUBxW left, W ; W := left - (right + BORROW)
1339 * MOVW result ; res := left - (right + BORROW)
1341 * 7 cycles, 8 iff BORROW and (right == 0xFF)
1346 * Alternative approach using -x = ~x + 1 ==> ~x = -x - 1 = -(x + 1)
1348 * COMFW right, W ; W := -right - (assumed BORROW)
1349 * BTFSC STATUS, C ; SKIP if we have a BORROW
1350 * ADDLW 1 ; W := -right (no BORROW)
1351 * BTFSC STATUS, C ; (***)
1352 * MOVLW left ; (***)
1353 * BTFSS STATUS, C ; (***)
1354 * ADDFW left, W ; W := left - right - BORROW (if any)
1355 * MOVWF result ; result := left - right - BORROW (if any)
1359 * Case A: C=0 (BORROW)
1360 * r=0x00, W=0xFF, W=left+0xFF, C iff left>0x00
1361 * r=0x01, W=0xFE, W=left+0xFE, C iff left>0x01
1362 * r=0xFE, W=0x01, W=left+0x01, C iff left>0xFE
1363 * r=0xFF, W=0x00, W=left+0x00, C iff left>0xFF
1365 * Case B: C=1 (no BORROW)
1366 * r=0x00, W=0xFF, W=0x00/C=1, W=left+0x00, C iff left>=0x100 (***)
1367 * r=0x01, W=0xFE, W=0xFF/C=0, W=left+0xFF, C iff left>=0x01
1368 * r=0xFE, W=0x01, W=0x02/C=0, W=left+0x02, C iff left>=0xFE
1369 * r=0xFF, W=0x00, W=0x01/C=0, W=left+0x01, C iff left>=0xFF
1371 lbl_comm = newiTempLabel(NULL);
1372 lbl_next = newiTempLabel(NULL);
1374 mov2w(right, offset);
1376 emitpcode(POC_INCFSZW, popGet(right, offset));
1377 emitpcode(POC_GOTO, popGetLabel(lbl_comm->key));
1378 mov2w(left, offset);
1379 emitpcode(POC_GOTO, popGetLabel(lbl_next->key));
1380 emitpLabel(lbl_comm->key);
1381 emitpcode(op_isLitLike(IC_LEFT(ic))
1382 ? POC_SUBLW : POC_SUBFW,
1383 popGetAddr(left, offset, 0));
1384 emitpLabel(lbl_next->key);
1385 emitpcode(POC_MOVWF, popGet(result, offset));
1390 if(AOP_TYPE(IC_RESULT(ic)) == AOP_CRY) {
1391 fprintf(stderr, "WARNING: AOP_CRY (bit-) results are probably broken. Please report this with source code as a bug.\n");
1392 mov2w(result, 0); // load Z flag
1393 emitpcode(POC_BCF, popGet(result, 0));
1395 emitpcode(POC_BSF, popGet(result, 0));
1398 // adjustArithmeticResult(ic);
1401 freeAsmop(IC_LEFT(ic),NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
1402 freeAsmop(IC_RIGHT(ic),NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
1403 freeAsmop(IC_RESULT(ic),NULL,ic,TRUE);