1 /*-------------------------------------------------------------------------
2 SDCCgen51.c - source file for code generation for 8051
4 Written By - Sandeep Dutta . sandeep.dutta@usa.net (1998)
5 and - Jean-Louis VERN.jlvern@writeme.com (1999)
7 This program is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 2, or (at your option) any
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 In other words, you are welcome to use, share and improve this program.
22 You are forbidden to forbid anyone else to use, share and improve
23 what you give them. Help stamp out software-hoarding!
25 -------------------------------------------------------------------------*/
31 #include "SDCCglobl.h"
33 #ifdef HAVE_SYS_ISA_DEFS_H
34 #include <sys/isa_defs.h>
40 #include "SDCChasht.h"
43 #include "SDCCicode.h"
44 #include "SDCClabel.h"
45 #include "SDCCBBlock.h"
48 #include "SDCCcflow.h"
49 #include "SDCCdflow.h"
50 #include "SDCClrange.h"
53 #include "SDCCpeeph.h"
54 #include "SDCCglue.h" /* drdani Jan 30 2000 */
56 /* this is the down and dirty file with all kinds of kludgy & hacky
57 stuff. This is what it is all about CODE GENERATION for a specific MCU.
58 Some of the routines may be reusable, will have to see */
60 static char *zero = "#0x00";
61 static char *one = "#0x01";
63 static char *fReturn[] = {"l", "h", "e", "d" };
64 static char *accUse[] = {"a" };
70 extern int ptrRegReq ;
72 extern FILE *codeOutFile;
74 #define RESULTONSTACK(x) \
75 (IC_RESULT(x) && IC_RESULT(x)->aop && \
76 IC_RESULT(x)->aop->type == AOP_STK )
78 #define MOVA(x) if (strcmp(x,"a")) emitcode("ld","a,%s",x);
79 #define CLRC emitcode("xor","a,a");
81 #define LABEL_STR "%05d$"
83 lineNode *lineHead = NULL;
84 lineNode *lineCurr = NULL;
86 unsigned char SLMask[] = {0xFF ,0xFE, 0xFC, 0xF8, 0xF0,
87 0xE0, 0xC0, 0x80, 0x00};
88 unsigned char SRMask[] = {0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
89 0x07, 0x03, 0x01, 0x00};
91 static int _lastStack = 0;
106 /*-----------------------------------------------------------------*/
107 /* emitcode - writes the code into a file : for now it is simple */
108 /*-----------------------------------------------------------------*/
109 void emitcode (const char *inst, const char *fmt, ...)
112 char lb[MAX_INLINEASM];
118 sprintf(lb,"%s\t",inst);
119 vsprintf(lb+(strlen(lb)),fmt,ap);
123 while (isspace(*lbp)) lbp++;
126 lineCurr = (lineCurr ?
127 connectLine(lineCurr,newLineNode(lb)) :
128 (lineHead = newLineNode(lb)));
129 lineCurr->isInline = inLine;
130 lineCurr->isDebug = debugLine;
134 const char *getPairName(asmop *aop)
136 if (aop->type == AOP_REG) {
137 switch (aop->aopu.aop_reg[0]->rIdx) {
149 else if (aop->type == AOP_STR) {
150 switch (*aop->aopu.aop_str[0]) {
166 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
167 bool isPair(asmop *aop)
169 if (aop->size == 2) {
170 if (aop->type == AOP_REG) {
171 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX)&&(aop->aopu.aop_reg[1]->rIdx == B_IDX)) {
174 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX)&&(aop->aopu.aop_reg[1]->rIdx == D_IDX)) {
177 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX)&&(aop->aopu.aop_reg[1]->rIdx == H_IDX)) {
181 if (aop->type == AOP_STR) {
182 if (!strcmp(aop->aopu.aop_str[0], "c")&&!strcmp(aop->aopu.aop_str[1], "b")) {
185 if (!strcmp(aop->aopu.aop_str[0], "e")&&!strcmp(aop->aopu.aop_str[1], "d")) {
188 if (!strcmp(aop->aopu.aop_str[0], "l")&&!strcmp(aop->aopu.aop_str[1], "h")) {
196 /** Push a register pair onto the stack */
197 void genPairPush(asmop *aop)
199 emitcode("push", "%s", getPairName(aop));
202 /*-----------------------------------------------------------------*/
203 /* newAsmop - creates a new asmOp */
204 /*-----------------------------------------------------------------*/
205 static asmop *newAsmop (short type)
209 ALLOC(aop,sizeof(asmop));
214 /*-----------------------------------------------------------------*/
215 /* aopForSym - for a true symbol */
216 /*-----------------------------------------------------------------*/
217 static asmop *aopForSym (iCode *ic,symbol *sym,bool result)
220 memmap *space= SPEC_OCLS(sym->etype);
222 /* if already has one */
226 /* Assign depending on the storage class */
227 if (sym->onStack || sym->iaccess) {
228 sym->aop = aop = newAsmop(AOP_STK);
229 aop->size = getSize(sym->type);
231 aop->aopu.aop_stk = sym->stack;
235 /* special case for a function */
236 if (IS_FUNC(sym->type)) {
237 sym->aop = aop = newAsmop(AOP_IMMD);
238 ALLOC_ATOMIC(aop->aopu.aop_immd,strlen(sym->rname)+1);
239 strcpy(aop->aopu.aop_immd,sym->rname);
244 /* only remaining is far space */
245 /* in which case DPTR gets the address */
246 sym->aop = aop = newAsmop(AOP_IY);
247 emitcode ("ld","iy,#%s", sym->rname);
248 aop->size = getSize(sym->type);
249 aop->aopu.aop_dir = sym->rname;
251 /* if it is in code space */
252 if (IN_CODESPACE(space))
258 /*-----------------------------------------------------------------*/
259 /* aopForRemat - rematerialzes an object */
260 /*-----------------------------------------------------------------*/
261 static asmop *aopForRemat (symbol *sym)
264 iCode *ic = sym->rematiCode;
265 asmop *aop = newAsmop(AOP_IMMD);
268 /* if plus or minus print the right hand side */
269 if (ic->op == '+' || ic->op == '-') {
270 sprintf(s,"0x%04x %c ",(int) operandLitValue(IC_RIGHT(ic)),
273 ic = OP_SYMBOL(IC_LEFT(ic))->rematiCode;
276 /* we reached the end */
277 sprintf(s,"%s",OP_SYMBOL(IC_LEFT(ic))->rname);
281 ALLOC_ATOMIC(aop->aopu.aop_immd,strlen(buffer)+1);
282 strcpy(aop->aopu.aop_immd,buffer);
286 /*-----------------------------------------------------------------*/
287 /* regsInCommon - two operands have some registers in common */
288 /*-----------------------------------------------------------------*/
289 bool regsInCommon (operand *op1, operand *op2)
294 /* if they have registers in common */
295 if (!IS_SYMOP(op1) || !IS_SYMOP(op2))
298 sym1 = OP_SYMBOL(op1);
299 sym2 = OP_SYMBOL(op2);
301 if (sym1->nRegs == 0 || sym2->nRegs == 0)
304 for (i = 0 ; i < sym1->nRegs ; i++) {
309 for (j = 0 ; j < sym2->nRegs ;j++ ) {
313 if (sym2->regs[j] == sym1->regs[i])
321 /*-----------------------------------------------------------------*/
322 /* operandsEqu - equivalent */
323 /*-----------------------------------------------------------------*/
324 bool operandsEqu ( operand *op1, operand *op2)
328 /* if they not symbols */
329 if (!IS_SYMOP(op1) || !IS_SYMOP(op2))
332 sym1 = OP_SYMBOL(op1);
333 sym2 = OP_SYMBOL(op2);
335 /* if both are itemps & one is spilt
336 and the other is not then false */
337 if (IS_ITEMP(op1) && IS_ITEMP(op2) &&
338 sym1->isspilt != sym2->isspilt )
341 /* if they are the same */
345 if (strcmp(sym1->rname,sym2->rname) == 0)
349 /* if left is a tmp & right is not */
353 (sym1->usl.spillLoc == sym2))
360 (sym2->usl.spillLoc == sym1))
366 /*-----------------------------------------------------------------*/
367 /* sameRegs - two asmops have the same registers */
368 /*-----------------------------------------------------------------*/
369 bool sameRegs (asmop *aop1, asmop *aop2 )
376 if (aop1->type != AOP_REG ||
377 aop2->type != AOP_REG )
380 if (aop1->size != aop2->size)
383 for (i = 0 ; i < aop1->size ; i++ )
384 if (aop1->aopu.aop_reg[i] !=
385 aop2->aopu.aop_reg[i] )
391 /*-----------------------------------------------------------------*/
392 /* aopOp - allocates an asmop for an operand : */
393 /*-----------------------------------------------------------------*/
394 static void aopOp (operand *op, iCode *ic, bool result)
403 /* if this a literal */
404 if (IS_OP_LITERAL(op)) {
405 op->aop = aop = newAsmop(AOP_LIT);
406 aop->aopu.aop_lit = op->operand.valOperand;
407 aop->size = getSize(operandType(op));
411 /* if already has a asmop then continue */
415 /* if the underlying symbol has a aop */
416 if (IS_SYMOP(op) && OP_SYMBOL(op)->aop) {
417 op->aop = OP_SYMBOL(op)->aop;
421 /* if this is a true symbol */
422 if (IS_TRUE_SYMOP(op)) {
423 op->aop = aopForSym(ic,OP_SYMBOL(op),result);
427 /* this is a temporary : this has
433 e) can be a return use only */
437 /* if the type is a conditional */
438 if (sym->regType == REG_CND) {
439 aop = op->aop = sym->aop = newAsmop(AOP_CRY);
444 /* if it is spilt then two situations
446 b) has a spill location */
447 if (sym->isspilt || sym->nRegs == 0) {
448 /* rematerialize it NOW */
450 sym->aop = op->aop = aop =
452 aop->size = getSize(sym->type);
458 aop = op->aop = sym->aop = newAsmop(AOP_ACC);
459 aop->size = getSize(sym->type);
460 for ( i = 0 ; i < 2 ; i++ )
461 aop->aopu.aop_str[i] = accUse[i];
467 aop = op->aop = sym->aop = newAsmop(AOP_STR);
468 aop->size = getSize(sym->type);
469 for ( i = 0 ; i < 4 ; i++ )
470 aop->aopu.aop_str[i] = fReturn[i];
474 /* else spill location */
475 sym->aop = op->aop = aop =
476 aopForSym(ic,sym->usl.spillLoc,result);
477 aop->size = getSize(sym->type);
481 /* must be in a register */
482 sym->aop = op->aop = aop = newAsmop(AOP_REG);
483 aop->size = sym->nRegs;
484 for ( i = 0 ; i < sym->nRegs ;i++)
485 aop->aopu.aop_reg[i] = sym->regs[i];
488 /*-----------------------------------------------------------------*/
489 /* freeAsmop - free up the asmop given to an operand */
490 /*----------------------------------------------------------------*/
491 static void freeAsmop (operand *op, asmop *aaop, iCode *ic)
514 /* all other cases just dealloc */
518 OP_SYMBOL(op)->aop = NULL;
519 /* if the symbol has a spill */
521 SPIL_LOC(op)->aop = NULL;
526 char *aopGetWord(asmop *aop, int offset)
531 assert(aop->size == 2);
534 /* depending on type */
537 sprintf (s,"#%s",aop->aopu.aop_immd);
538 ALLOC_ATOMIC(rs,strlen(s)+1);
543 value * val = aop->aopu.aop_lit;
544 /* if it is a float then it gets tricky */
545 /* otherwise it is fairly simple */
546 if (!IS_FLOAT(val->type)) {
547 unsigned long v = floatFromVal(val);
549 sprintf(buffer,"#0x%04lx", v);
550 ALLOC_ATOMIC(rs,strlen(buffer)+1);
551 return strcpy (rs,buffer);
560 /*-----------------------------------------------------------------*/
561 /* aopGet - for fetching value of the aop */
562 /*-----------------------------------------------------------------*/
563 static char *aopGet (asmop *aop, int offset, bool bit16)
568 /* offset is greater than size then zero */
569 if (offset > (aop->size - 1) &&
570 aop->type != AOP_LIT)
573 /* depending on type */
577 sprintf (s,"#%s",aop->aopu.aop_immd);
587 ALLOC_ATOMIC(rs,strlen(s)+1);
593 emitcode("ld", "a,(%s+%d)", aop->aopu.aop_dir, offset);
595 ALLOC_ATOMIC(rs,strlen(s)+1);
600 return aop->aopu.aop_reg[offset]->name;
603 sprintf(s,"%d(iy)", offset);
604 ALLOC_ATOMIC(rs,strlen(s)+1);
609 sprintf(s,"%d(ix) ; %u", aop->aopu.aop_stk+offset, offset);
610 ALLOC_ATOMIC(rs,strlen(s)+1);
624 return aopLiteral (aop->aopu.aop_lit,offset);
628 return aop->aopu.aop_str[offset];
631 fprintf(stderr, "Type %u\n", aop->type);
633 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
634 "aopget got unsupported aop->type");
638 bool isRegString(char *s)
640 if (!strcmp(s, "b") ||
651 bool isConstant(char *s)
656 bool canAssignToPtr(char *s)
665 /*-----------------------------------------------------------------*/
666 /* aopPut - puts a string for a aop */
667 /*-----------------------------------------------------------------*/
668 static void aopPut (asmop *aop, char *s, int offset)
672 if (aop->size && offset > ( aop->size - 1)) {
673 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
674 "aopPut got offset > aop->size");
678 /* will assign value to value */
679 /* depending on where it is ofcourse */
684 emitcode("ld", "a,%s", s);
685 emitcode("ld", "(%s+%d),a", d, offset);
689 /* Dont bother if it's a ld x,x */
690 if (strcmp(aop->aopu.aop_reg[offset]->name,s) != 0) {
691 emitcode("ld","%s,%s",
692 aop->aopu.aop_reg[offset]->name,s);
697 if (!canAssignToPtr(s)) {
698 emitcode("ld", "a,%s", s);
699 emitcode("ld", "%d(iy),a", offset);
702 emitcode("ld", "%d(iy),%s", offset, s);
706 if (!canAssignToPtr(s)) {
707 emitcode("ld", "a,%s", s);
708 emitcode("ld", "%d(ix),a", aop->aopu.aop_stk+offset);
711 emitcode("ld", "%d(ix),%s", aop->aopu.aop_stk+offset, s);
715 /* if bit variable */
716 if (!aop->aopu.aop_dir) {
717 emitcode("ld", "a,#0");
720 /* In bit space but not in C - cant happen */
727 if (strcmp(aop->aopu.aop_str[offset],s)) {
728 emitcode ("ld","%s,%s",aop->aopu.aop_str[offset],s);
734 if (!offset && (strcmp(s,"acc") == 0))
738 emitcode("", "; Error aopPut AOP_ACC");
741 if (strcmp(aop->aopu.aop_str[offset],s))
742 emitcode ("ld","%s,%s",aop->aopu.aop_str[offset],s);
747 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
748 "aopPut got unsupported aop->type");
753 #define AOP(op) op->aop
754 #define AOP_TYPE(op) AOP(op)->type
755 #define AOP_SIZE(op) AOP(op)->size
756 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
758 /*-----------------------------------------------------------------*/
759 /* getDataSize - get the operand data size */
760 /*-----------------------------------------------------------------*/
761 int getDataSize(operand *op)
772 /*-----------------------------------------------------------------*/
773 /* movLeft2Result - move byte from left to result */
774 /*-----------------------------------------------------------------*/
775 static void movLeft2Result (operand *left, int offl,
776 operand *result, int offr, int sign)
779 if(!sameRegs(AOP(left),AOP(result)) || (offl != offr)){
780 l = aopGet(AOP(left),offl,FALSE);
783 aopPut(AOP(result),l,offr);
792 /** Put Acc into a register set
794 void outAcc(operand *result)
797 size = getDataSize(result);
799 aopPut(AOP(result),"a",0);
802 /* unsigned or positive */
804 aopPut(AOP(result),zero,offset++);
809 /** Take the value in carry and put it into a register
811 void outBitC(operand *result)
813 /* if the result is bit */
814 if (AOP_TYPE(result) == AOP_CRY) {
815 emitcode("", "; Note: outBitC form 1");
816 aopPut(AOP(result),"blah",0);
819 emitcode("ld", "a,#0");
825 /*-----------------------------------------------------------------*/
826 /* toBoolean - emit code for orl a,operator(sizeop) */
827 /*-----------------------------------------------------------------*/
828 void toBoolean(operand *oper)
830 int size = AOP_SIZE(oper);
833 emitcode("ld", "a,%s", aopGet(AOP(oper), offset++, FALSE));
836 emitcode("or","a,%s",aopGet(AOP(oper),offset++,FALSE));
840 emitcode("or","a,%s",aopGet(AOP(oper),0,FALSE));
844 /*-----------------------------------------------------------------*/
845 /* genNot - generate code for ! operation */
846 /*-----------------------------------------------------------------*/
847 static void genNot (iCode *ic)
849 link *optype = operandType(IC_LEFT(ic));
851 /* assign asmOps to operand & result */
852 aopOp (IC_LEFT(ic),ic,FALSE);
853 aopOp (IC_RESULT(ic),ic,TRUE);
855 /* if in bit space then a special case */
856 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY) {
860 /* if type float then do float */
861 if (IS_FLOAT(optype)) {
865 toBoolean(IC_LEFT(ic));
870 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
871 emitcode("sub", "a,#0x01");
872 outBitC(IC_RESULT(ic));
874 /* release the aops */
875 freeAsmop(IC_LEFT(ic),NULL,ic);
876 freeAsmop(IC_RESULT(ic),NULL,ic);
879 /*-----------------------------------------------------------------*/
880 /* genCpl - generate code for complement */
881 /*-----------------------------------------------------------------*/
882 static void genCpl (iCode *ic)
888 /* assign asmOps to operand & result */
889 aopOp (IC_LEFT(ic),ic,FALSE);
890 aopOp (IC_RESULT(ic),ic,TRUE);
892 /* if both are in bit space then
894 if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY &&
895 AOP_TYPE(IC_LEFT(ic)) == AOP_CRY ) {
899 size = AOP_SIZE(IC_RESULT(ic));
901 char *l = aopGet(AOP(IC_LEFT(ic)),offset,FALSE);
904 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
907 /* release the aops */
908 freeAsmop(IC_LEFT(ic),NULL,ic);
909 freeAsmop(IC_RESULT(ic),NULL,ic);
912 /*-----------------------------------------------------------------*/
913 /* genUminus - unary minus code generation */
914 /*-----------------------------------------------------------------*/
915 static void genUminus (iCode *ic)
921 /*-----------------------------------------------------------------*/
922 /* assignResultValue - */
923 /*-----------------------------------------------------------------*/
924 void assignResultValue(operand * oper)
927 int size = AOP_SIZE(oper);
929 aopPut(AOP(oper),fReturn[offset],offset);
934 /*-----------------------------------------------------------------*/
935 /* genIpush - genrate code for pushing this gets a little complex */
936 /*-----------------------------------------------------------------*/
937 static void genIpush (iCode *ic)
939 int size, offset = 0 ;
943 /* if this is not a parm push : ie. it is spill push
944 and spill push is always done on the local stack */
946 /* and the item is spilt then do nothing */
947 if (OP_SYMBOL(IC_LEFT(ic))->isspilt)
950 aopOp(IC_LEFT(ic),ic,FALSE);
951 size = AOP_SIZE(IC_LEFT(ic));
952 /* push it on the stack */
953 if (isPair(AOP(IC_LEFT(ic)))) {
954 emitcode("push", getPairName(AOP(IC_LEFT(ic))));
959 l = aopGet(AOP(IC_LEFT(ic)), --offset, FALSE);
960 /* Simple for now - load into A and PUSH AF */
961 emitcode("ld", "a,%s", l);
962 emitcode("push", "af");
963 emitcode("inc", "sp");
969 /* Hmmm... what about saving the currently used registers
972 /* then do the push */
973 aopOp(IC_LEFT(ic),ic,FALSE);
975 size = AOP_SIZE(IC_LEFT(ic));
977 if (isPair(AOP(IC_LEFT(ic)))) {
978 emitcode("push", "%s", getPairName(AOP(IC_LEFT(ic))));
982 char *s = aopGetWord(AOP(IC_LEFT(ic)), 0);
984 emitcode("ld", "hl,%s", s);
985 emitcode("push", "hl");
991 l = aopGet(AOP(IC_LEFT(ic)), --offset, FALSE);
992 emitcode("ld", "a,%s", l);
993 emitcode("push", "af");
994 emitcode("inc", "sp");
998 freeAsmop(IC_LEFT(ic),NULL,ic);
1001 /*-----------------------------------------------------------------*/
1002 /* genIpop - recover the registers: can happen only for spilling */
1003 /*-----------------------------------------------------------------*/
1004 static void genIpop (iCode *ic)
1009 /* if the temp was not pushed then */
1010 if (OP_SYMBOL(IC_LEFT(ic))->isspilt)
1013 aopOp(IC_LEFT(ic),ic,FALSE);
1014 size = AOP_SIZE(IC_LEFT(ic));
1016 if (isPair(AOP(IC_LEFT(ic)))) {
1017 emitcode("pop", getPairName(AOP(IC_LEFT(ic))));
1021 emitcode("dec", "sp");
1022 emitcode("pop", "hl");
1023 aopPut(AOP(IC_LEFT(ic)), "l", offset--);
1027 freeAsmop(IC_LEFT(ic),NULL,ic);
1030 /** Emit the code for a call statement
1032 static void emitCall (iCode *ic, bool ispcall)
1034 /* if caller saves & we have not saved then */
1035 if (!ic->regsSaved) {
1039 /* if send set is not empty then assign */
1043 for (sic = setFirstItem(sendSet) ; sic ;
1044 sic = setNextItem(sendSet)) {
1045 int size, offset = 0;
1046 aopOp(IC_LEFT(sic),sic,FALSE);
1047 size = AOP_SIZE(IC_LEFT(sic));
1049 char *l = aopGet(AOP(IC_LEFT(sic)),offset,
1051 if (strcmp(l,fReturn[offset]))
1052 emitcode("ld","%s,%s",
1057 freeAsmop (IC_LEFT(sic),NULL,sic);
1063 symbol *rlbl = newiTempLabel(NULL);
1065 emitcode("ld", "hl,#" LABEL_STR, (rlbl->key+100));
1066 emitcode("push", "hl");
1068 aopOp(IC_LEFT(ic),ic,FALSE);
1069 emitcode("ld", "l,%s", aopGet(AOP(IC_LEFT(ic)), 0,FALSE));
1070 emitcode("ld", "h,%s", aopGet(AOP(IC_LEFT(ic)), 1,FALSE));
1071 freeAsmop(IC_LEFT(ic),NULL,ic);
1073 emitcode("jp", "(hl)");
1074 emitcode("","%05d$:",(rlbl->key+100));
1078 emitcode("call", "%s", (OP_SYMBOL(IC_LEFT(ic))->rname[0] ?
1079 OP_SYMBOL(IC_LEFT(ic))->rname :
1080 OP_SYMBOL(IC_LEFT(ic))->name));
1083 /* if we need assign a result value */
1084 if ((IS_ITEMP(IC_RESULT(ic)) &&
1085 (OP_SYMBOL(IC_RESULT(ic))->nRegs ||
1086 OP_SYMBOL(IC_RESULT(ic))->spildir )) ||
1087 IS_TRUE_SYMOP(IC_RESULT(ic)) ) {
1090 aopOp(IC_RESULT(ic),ic,FALSE);
1093 assignResultValue(IC_RESULT(ic));
1095 freeAsmop(IC_RESULT(ic),NULL, ic);
1098 /* adjust the stack for parameters if required */
1099 if (IC_LEFT(ic)->parmBytes) {
1100 int i = IC_LEFT(ic)->parmBytes;
1102 emitcode("ld", "hl,#%d", i);
1103 emitcode("add", "hl,sp");
1104 emitcode("ld", "sp,hl");
1108 emitcode("pop", "hl");
1112 emitcode("inc", "sp");
1118 /*-----------------------------------------------------------------*/
1119 /* genCall - generates a call statement */
1120 /*-----------------------------------------------------------------*/
1121 static void genCall (iCode *ic)
1123 emitCall(ic, FALSE);
1126 /*-----------------------------------------------------------------*/
1127 /* genPcall - generates a call by pointer statement */
1128 /*-----------------------------------------------------------------*/
1129 static void genPcall (iCode *ic)
1134 /*-----------------------------------------------------------------*/
1135 /* resultRemat - result is rematerializable */
1136 /*-----------------------------------------------------------------*/
1137 static int resultRemat (iCode *ic)
1139 if (SKIP_IC(ic) || ic->op == IFX)
1142 if (IC_RESULT(ic) && IS_ITEMP(IC_RESULT(ic))) {
1143 symbol *sym = OP_SYMBOL(IC_RESULT(ic));
1144 if (sym->remat && !POINTER_SET(ic))
1151 /*-----------------------------------------------------------------*/
1152 /* genFunction - generated code for function entry */
1153 /*-----------------------------------------------------------------*/
1154 static void genFunction (iCode *ic)
1160 /* create the function header */
1161 emitcode(";","-----------------------------------------");
1162 emitcode(";"," function %s",(sym = OP_SYMBOL(IC_LEFT(ic)))->name);
1163 emitcode(";","-----------------------------------------");
1165 emitcode("","%s:",sym->rname);
1166 fetype = getSpec(operandType(IC_LEFT(ic)));
1168 /* if critical function then turn interrupts off */
1169 if (SPEC_CRTCL(fetype))
1172 /* if this is an interrupt service routine then
1173 save acc, b, dpl, dph */
1174 if (IS_ISR(sym->etype)) {
1175 emitcode("push", "af");
1176 emitcode("push", "bc");
1177 emitcode("push", "de");
1178 emitcode("push", "hl");
1180 /* PENDING: callee-save etc */
1182 /* adjust the stack for the function */
1183 emitcode("push", "de");
1184 emitcode("push", "bc");
1185 emitcode("push", "ix");
1186 emitcode("ld", "ix,#0");
1187 emitcode("add", "ix,sp");
1189 _lastStack = sym->stack;
1192 emitcode("ld", "hl,#-%d", sym->stack);
1193 emitcode("add", "hl,sp");
1194 emitcode("ld", "sp,hl");
1198 /*-----------------------------------------------------------------*/
1199 /* genEndFunction - generates epilogue for functions */
1200 /*-----------------------------------------------------------------*/
1201 static void genEndFunction (iCode *ic)
1203 symbol *sym = OP_SYMBOL(IC_LEFT(ic));
1205 if (IS_ISR(sym->etype)) {
1209 if (SPEC_CRTCL(sym->etype))
1212 /* PENDING: calleeSave */
1214 /* if debug then send end of function */
1215 if (options.debug && currFunc) {
1217 emitcode("","C$%s$%d$%d$%d ==.",
1218 ic->filename,currFunc->lastLine,
1219 ic->level,ic->block);
1220 if (IS_STATIC(currFunc->etype))
1221 emitcode("","XF%s$%s$0$0 ==.",moduleName,currFunc->name);
1223 emitcode("","XG$%s$0$0 ==.",currFunc->name);
1226 emitcode("ld", "sp,ix");
1227 emitcode("pop", "ix");
1228 emitcode("pop", "bc");
1229 emitcode("pop", "de");
1230 emitcode("ret", "");
1235 /*-----------------------------------------------------------------*/
1236 /* genRet - generate code for return statement */
1237 /*-----------------------------------------------------------------*/
1238 static void genRet (iCode *ic)
1241 /* Errk. This is a hack until I can figure out how
1242 to cause dehl to spill on a call */
1243 int size,offset = 0;
1245 /* if we have no return value then
1246 just generate the "ret" */
1250 /* we have something to return then
1251 move the return value into place */
1252 aopOp(IC_LEFT(ic),ic,FALSE);
1253 size = AOP_SIZE(IC_LEFT(ic));
1255 if ((size == 2) && ((l = aopGetWord(AOP(IC_LEFT(ic)), 0)))) {
1256 emitcode("ld", "hl,%s", l);
1260 l = aopGet(AOP(IC_LEFT(ic)),offset,
1262 if (strcmp(fReturn[offset],l))
1263 emitcode("ld","%s,%s",fReturn[offset++],l);
1266 freeAsmop (IC_LEFT(ic),NULL,ic);
1269 /* generate a jump to the return label
1270 if the next is not the return statement */
1271 if (!(ic->next && ic->next->op == LABEL &&
1272 IC_LABEL(ic->next) == returnLabel))
1274 emitcode("jp", LABEL_STR ,(returnLabel->key+100));
1277 /*-----------------------------------------------------------------*/
1278 /* genLabel - generates a label */
1279 /*-----------------------------------------------------------------*/
1280 static void genLabel (iCode *ic)
1282 /* special case never generate */
1283 if (IC_LABEL(ic) == entryLabel)
1286 emitcode("", LABEL_STR ":",(IC_LABEL(ic)->key+100));
1289 /*-----------------------------------------------------------------*/
1290 /* genGoto - generates a ljmp */
1291 /*-----------------------------------------------------------------*/
1292 static void genGoto (iCode *ic)
1294 emitcode ("jp", LABEL_STR ,(IC_LABEL(ic)->key+100));
1297 /*-----------------------------------------------------------------*/
1298 /* genPlusIncr :- does addition with increment if possible */
1299 /*-----------------------------------------------------------------*/
1300 static bool genPlusIncr (iCode *ic)
1302 unsigned int icount ;
1303 unsigned int size = getDataSize(IC_RESULT(ic));
1305 /* will try to generate an increment */
1306 /* if the right side is not a literal
1308 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
1311 /* if the literal value of the right hand side
1312 is greater than 4 then it is not worth it */
1313 if ((icount = floatFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit)) > 4)
1317 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
1318 isPair(AOP(IC_RESULT(ic)))) {
1320 emitcode("inc", "%s", getPairName(AOP(IC_RESULT(ic))));
1324 /* if increment 16 bits in register */
1325 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
1328 symbol *tlbl = newiTempLabel(NULL);
1329 emitcode("inc","%s",aopGet(AOP(IC_RESULT(ic)),LSB,FALSE));
1330 emitcode("jp", "nz," LABEL_STR ,tlbl->key+100);
1332 emitcode("inc","%s",aopGet(AOP(IC_RESULT(ic)),MSB16,FALSE));
1336 emitcode("", LABEL_STR ":",tlbl->key+100);
1340 /* If result is a pair */
1341 if (isPair(AOP(IC_RESULT(ic)))) {
1342 movLeft2Result(IC_LEFT(ic), 0, IC_RESULT(ic), 0, 0);
1343 movLeft2Result(IC_LEFT(ic), 1, IC_RESULT(ic), 1, 0);
1345 emitcode("inc", "%s", getPairName(AOP(IC_RESULT(ic))));
1349 /* if the sizes are greater than 1 then we cannot */
1350 if (AOP_SIZE(IC_RESULT(ic)) > 1 ||
1351 AOP_SIZE(IC_LEFT(ic)) > 1 )
1354 /* we can if the aops of the left & result match or
1355 if they are in registers and the registers are the
1357 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) {
1359 emitcode ("inc","%s",aopGet(AOP(IC_LEFT(ic)),0, FALSE));
1367 /*-----------------------------------------------------------------*/
1368 /* outBitAcc - output a bit in acc */
1369 /*-----------------------------------------------------------------*/
1370 void outBitAcc(operand *result)
1372 symbol *tlbl = newiTempLabel(NULL);
1373 /* if the result is a bit */
1374 if (AOP_TYPE(result) == AOP_CRY){
1378 emitcode("jp","z," LABEL_STR ,tlbl->key+100);
1379 emitcode("ld","a,%s",one);
1380 emitcode("", LABEL_STR ":",tlbl->key+100);
1385 /*-----------------------------------------------------------------*/
1386 /* genPlus - generates code for addition */
1387 /*-----------------------------------------------------------------*/
1388 static void genPlus (iCode *ic)
1390 int size, offset = 0;
1392 /* special cases :- */
1394 aopOp (IC_LEFT(ic),ic,FALSE);
1395 aopOp (IC_RIGHT(ic),ic,FALSE);
1396 aopOp (IC_RESULT(ic),ic,TRUE);
1398 /* Swap the left and right operands if:
1400 if literal, literal on the right or
1401 if left requires ACC or right is already
1404 if ((AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) ||
1405 (AOP_NEEDSACC(IC_LEFT(ic))) ||
1406 AOP_TYPE(IC_RIGHT(ic)) == AOP_ACC ){
1407 operand *t = IC_RIGHT(ic);
1408 IC_RIGHT(ic) = IC_LEFT(ic);
1412 /* if both left & right are in bit
1414 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
1415 AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
1420 /* if left in bit space & right literal */
1421 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
1422 AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT) {
1423 /* Can happen I guess */
1427 /* if I can do an increment instead
1428 of add then GOOD for ME */
1429 if (genPlusIncr (ic) == TRUE)
1432 size = getDataSize(IC_RESULT(ic));
1435 if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC) {
1436 MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
1438 emitcode("add","a,%s",
1439 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
1441 emitcode("adc","a,%s",
1442 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
1444 MOVA(aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
1446 emitcode("add","a,%s",
1447 aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
1449 emitcode("adc","a,%s",
1450 aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
1452 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1455 /* Some kind of pointer arith. */
1456 if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
1457 AOP_SIZE(IC_LEFT(ic)) == 3 &&
1458 !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))))
1461 if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
1462 AOP_SIZE(IC_RIGHT(ic)) == 3 &&
1463 !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_RIGHT(ic))))
1468 freeAsmop(IC_LEFT(ic),NULL,ic);
1469 freeAsmop(IC_RIGHT(ic),NULL,ic);
1470 freeAsmop(IC_RESULT(ic),NULL,ic);
1474 /*-----------------------------------------------------------------*/
1475 /* genMinusDec :- does subtraction with deccrement if possible */
1476 /*-----------------------------------------------------------------*/
1477 static bool genMinusDec (iCode *ic)
1479 unsigned int icount ;
1480 unsigned int size = getDataSize(IC_RESULT(ic));
1482 /* will try to generate an increment */
1483 /* if the right side is not a literal we cannot */
1484 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
1487 /* if the literal value of the right hand side
1488 is greater than 4 then it is not worth it */
1489 if ((icount = (unsigned int) floatFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit)) > 2)
1492 size = getDataSize(IC_RESULT(ic));
1493 /* if decrement 16 bits in register */
1494 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
1495 (size > 1) && isPair(AOP(IC_RESULT(ic)))) {
1497 emitcode("dec", "%s", getPairName(AOP(IC_RESULT(ic))));
1501 /* If result is a pair */
1502 if (isPair(AOP(IC_RESULT(ic)))) {
1503 movLeft2Result(IC_LEFT(ic), 0, IC_RESULT(ic), 0, 0);
1504 movLeft2Result(IC_LEFT(ic), 1, IC_RESULT(ic), 1, 0);
1506 emitcode("dec", "%s", getPairName(AOP(IC_RESULT(ic))));
1510 /* if the sizes are greater than 1 then we cannot */
1511 if (AOP_SIZE(IC_RESULT(ic)) > 1 ||
1512 AOP_SIZE(IC_LEFT(ic)) > 1 )
1515 /* we can if the aops of the left & result match or if they are in
1516 registers and the registers are the same */
1517 if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic)))) {
1519 emitcode ("dec","%s",aopGet(AOP(IC_RESULT(ic)),0,FALSE));
1526 /*-----------------------------------------------------------------*/
1527 /* genMinus - generates code for subtraction */
1528 /*-----------------------------------------------------------------*/
1529 static void genMinus (iCode *ic)
1531 int size, offset = 0;
1532 unsigned long lit = 0L;
1534 aopOp (IC_LEFT(ic),ic,FALSE);
1535 aopOp (IC_RIGHT(ic),ic,FALSE);
1536 aopOp (IC_RESULT(ic),ic,TRUE);
1538 /* special cases :- */
1539 /* if both left & right are in bit space */
1540 if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
1541 AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
1546 /* if I can do an decrement instead of subtract then GOOD for ME */
1547 if (genMinusDec (ic) == TRUE)
1550 size = getDataSize(IC_RESULT(ic));
1552 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT){
1556 lit = (unsigned long)floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit);
1561 /* if literal, add a,#-lit, else normal subb */
1563 MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE));
1564 if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
1565 emitcode("sbc","a,%s",
1566 aopGet(AOP(IC_RIGHT(ic)),offset,FALSE));
1568 /* first add without previous c */
1570 emitcode("add","a,#0x%02x",
1571 (unsigned int)(lit & 0x0FFL));
1573 emitcode("adc","a,#0x%02x",
1574 (unsigned int)((lit >> (offset*8)) & 0x0FFL));
1576 aopPut(AOP(IC_RESULT(ic)),"a",offset++);
1579 if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
1580 AOP_SIZE(IC_LEFT(ic)) == 3 &&
1581 !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))))
1585 freeAsmop(IC_LEFT(ic),NULL,ic);
1586 freeAsmop(IC_RIGHT(ic),NULL,ic);
1587 freeAsmop(IC_RESULT(ic),NULL,ic);
1590 /*-----------------------------------------------------------------*/
1591 /* genMult - generates code for multiplication */
1592 /*-----------------------------------------------------------------*/
1593 static void genMult (iCode *ic)
1595 /* Shouldn't occur - all done through function calls */
1599 /*-----------------------------------------------------------------*/
1600 /* genDiv - generates code for division */
1601 /*-----------------------------------------------------------------*/
1602 static void genDiv (iCode *ic)
1604 /* Shouldn't occur - all done through function calls */
1608 /*-----------------------------------------------------------------*/
1609 /* genMod - generates code for division */
1610 /*-----------------------------------------------------------------*/
1611 static void genMod (iCode *ic)
1613 /* Shouldn't occur - all done through function calls */
1617 /*-----------------------------------------------------------------*/
1618 /* genIfxJump :- will create a jump depending on the ifx */
1619 /*-----------------------------------------------------------------*/
1620 static void genIfxJump (iCode *ic, char *jval)
1625 /* if true label then we jump if condition
1627 if ( IC_TRUE(ic) ) {
1629 if (!strcmp(jval, "a")) {
1632 else if (!strcmp(jval, "c")) {
1636 /* The buffer contains the bit on A that we should test */
1641 /* false label is present */
1642 jlbl = IC_FALSE(ic) ;
1643 if (!strcmp(jval, "a")) {
1646 else if (!strcmp(jval, "c")) {
1650 /* The buffer contains the bit on A that we should test */
1654 /* Z80 can do a conditional long jump */
1655 if (!strcmp(jval, "a")) {
1656 emitcode("or", "a,a");
1658 else if (!strcmp(jval, "c")) {
1661 emitcode("bit", "%s,a", jval);
1663 emitcode("jp", "%s," LABEL_STR , inst, jlbl->key+100);
1665 /* mark the icode as generated */
1669 /** Generic compare for > or <
1671 static void genCmp (operand *left,operand *right,
1672 operand *result, iCode *ifx, int sign)
1674 int size, offset = 0 ;
1675 unsigned long lit = 0L;
1677 /* if left & right are bit variables */
1678 if (AOP_TYPE(left) == AOP_CRY &&
1679 AOP_TYPE(right) == AOP_CRY ) {
1680 /* Cant happen on the Z80 */
1683 /* subtract right from left if at the
1684 end the carry flag is set then we know that
1685 left is greater than right */
1686 size = max(AOP_SIZE(left),AOP_SIZE(right));
1688 /* if unsigned char cmp with lit, just compare */
1689 if((size == 1) && !sign &&
1690 (AOP_TYPE(right) == AOP_LIT && AOP_TYPE(left) != AOP_DIR )){
1691 emitcode("ld", "a,%s", aopGet(AOP(left), offset, FALSE));
1692 emitcode("cp", "%s", aopGet(AOP(right), offset, FALSE));
1695 if(AOP_TYPE(right) == AOP_LIT) {
1696 lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
1697 /* optimize if(x < 0) or if(x >= 0) */
1700 /* No sign so it's always false */
1704 /* Just load in the top most bit */
1705 MOVA(aopGet(AOP(left),AOP_SIZE(left)-1,FALSE));
1706 if(!(AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) && ifx) {
1707 genIfxJump (ifx,"7");
1711 emitcode("rlc","a");
1717 /* Do a long subtract */
1718 MOVA(aopGet(AOP(left),offset,FALSE));
1719 /* PENDING: CRITICAL: support signed cmp's */
1720 /* Subtract through, propagating the carry */
1722 emitcode("sub","a,%s",aopGet(AOP(right),offset++,FALSE));
1725 emitcode("sbc","a,%s",aopGet(AOP(right),offset++,FALSE));
1731 if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) {
1734 /* if the result is used in the next
1735 ifx conditional branch then generate
1736 code a little differently */
1738 genIfxJump (ifx,"c");
1741 /* leave the result in acc */
1745 /*-----------------------------------------------------------------*/
1746 /* genCmpGt :- greater than comparison */
1747 /*-----------------------------------------------------------------*/
1748 static void genCmpGt (iCode *ic, iCode *ifx)
1750 operand *left, *right, *result;
1751 link *letype , *retype;
1755 right= IC_RIGHT(ic);
1756 result = IC_RESULT(ic);
1758 letype = getSpec(operandType(left));
1759 retype =getSpec(operandType(right));
1760 sign = !(SPEC_USIGN(letype) | SPEC_USIGN(retype));
1761 /* assign the amsops */
1762 aopOp (left,ic,FALSE);
1763 aopOp (right,ic,FALSE);
1764 aopOp (result,ic,TRUE);
1766 genCmp(right, left, result, ifx, sign);
1768 freeAsmop(left,NULL,ic);
1769 freeAsmop(right,NULL,ic);
1770 freeAsmop(result,NULL,ic);
1773 /*-----------------------------------------------------------------*/
1774 /* genCmpLt - less than comparisons */
1775 /*-----------------------------------------------------------------*/
1776 static void genCmpLt (iCode *ic, iCode *ifx)
1778 operand *left, *right, *result;
1779 link *letype , *retype;
1783 right= IC_RIGHT(ic);
1784 result = IC_RESULT(ic);
1786 letype = getSpec(operandType(left));
1787 retype =getSpec(operandType(right));
1788 sign = !(SPEC_USIGN(letype) | SPEC_USIGN(retype));
1790 /* assign the amsops */
1791 aopOp (left,ic,FALSE);
1792 aopOp (right,ic,FALSE);
1793 aopOp (result,ic,TRUE);
1795 genCmp(left, right, result, ifx, sign);
1797 freeAsmop(left,NULL,ic);
1798 freeAsmop(right,NULL,ic);
1799 freeAsmop(result,NULL,ic);
1802 /*-----------------------------------------------------------------*/
1803 /* gencjneshort - compare and jump if not equal */
1804 /*-----------------------------------------------------------------*/
1805 static void gencjneshort(operand *left, operand *right, symbol *lbl)
1807 int size = max(AOP_SIZE(left),AOP_SIZE(right));
1809 unsigned long lit = 0L;
1811 /* Swap the left and right if it makes the computation easier */
1812 if (AOP_TYPE(left) == AOP_LIT) {
1818 if(AOP_TYPE(right) == AOP_LIT)
1819 lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
1821 /* if the right side is a literal then anything goes */
1822 if (AOP_TYPE(right) == AOP_LIT &&
1823 AOP_TYPE(left) != AOP_DIR ) {
1825 emitcode("ld", "a,%s", aopGet(AOP(left),offset,FALSE));
1826 emitcode("cp", "a,%s", aopGet(AOP(right),offset,FALSE));
1827 emitcode("jp", "nz," LABEL_STR , lbl->key+100);
1831 /* if the right side is in a register or in direct space or
1832 if the left is a pointer register & right is not */
1833 else if (AOP_TYPE(right) == AOP_REG ||
1834 AOP_TYPE(right) == AOP_DIR ||
1835 (AOP_TYPE(left) == AOP_DIR && AOP_TYPE(right) == AOP_LIT)) {
1837 MOVA(aopGet(AOP(left),offset,FALSE));
1838 if((AOP_TYPE(left) == AOP_DIR && AOP_TYPE(right) == AOP_LIT) &&
1839 ((unsigned int)((lit >> (offset*8)) & 0x0FFL) == 0))
1841 emitcode("jp","nz," LABEL_STR ,lbl->key+100);
1843 emitcode("cp", "%s", aopGet(AOP(right),offset,FALSE));
1844 emitcode("jp", "nz," LABEL_STR , lbl->key+100);
1849 /* right is a pointer reg need both a & b */
1850 /* PENDING: is this required? */
1852 char *l = aopGet(AOP(left),offset,FALSE);
1853 MOVA(aopGet(AOP(right),offset,FALSE));
1854 emitcode("cp", "%s", l);
1855 emitcode("jr", "nz," LABEL_STR, lbl->key+100);
1861 /*-----------------------------------------------------------------*/
1862 /* gencjne - compare and jump if not equal */
1863 /*-----------------------------------------------------------------*/
1864 static void gencjne(operand *left, operand *right, symbol *lbl)
1866 symbol *tlbl = newiTempLabel(NULL);
1868 gencjneshort(left, right, lbl);
1871 emitcode("ld","a,%s",one);
1872 emitcode("jp", LABEL_STR ,tlbl->key+100);
1873 emitcode("", LABEL_STR ":",lbl->key+100);
1874 emitcode("xor","a,a");
1875 emitcode("", LABEL_STR ":",tlbl->key+100);
1878 /*-----------------------------------------------------------------*/
1879 /* genCmpEq - generates code for equal to */
1880 /*-----------------------------------------------------------------*/
1881 static void genCmpEq (iCode *ic, iCode *ifx)
1883 operand *left, *right, *result;
1885 aopOp((left=IC_LEFT(ic)),ic,FALSE);
1886 aopOp((right=IC_RIGHT(ic)),ic,FALSE);
1887 aopOp((result=IC_RESULT(ic)),ic,TRUE);
1889 /* Swap operands if it makes the operation easier. ie if:
1890 1. Left is a literal.
1892 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) {
1893 operand *t = IC_RIGHT(ic);
1894 IC_RIGHT(ic) = IC_LEFT(ic);
1898 if (ifx && !AOP_SIZE(result)){
1900 /* if they are both bit variables */
1901 if (AOP_TYPE(left) == AOP_CRY &&
1902 ((AOP_TYPE(right) == AOP_CRY) || (AOP_TYPE(right) == AOP_LIT))) {
1905 tlbl = newiTempLabel(NULL);
1906 gencjneshort(left, right, tlbl);
1907 if ( IC_TRUE(ifx) ) {
1908 emitcode("jp", LABEL_STR ,IC_TRUE(ifx)->key+100);
1909 emitcode("", LABEL_STR ":",tlbl->key+100);
1911 /* PENDING: do this better */
1912 symbol *lbl = newiTempLabel(NULL);
1913 emitcode("jp", LABEL_STR ,lbl->key+100);
1914 emitcode("", LABEL_STR ":",tlbl->key+100);
1915 emitcode("jp", LABEL_STR ,IC_FALSE(ifx)->key+100);
1916 emitcode("", LABEL_STR ":",lbl->key+100);
1919 /* mark the icode as generated */
1924 /* if they are both bit variables */
1925 if (AOP_TYPE(left) == AOP_CRY &&
1926 ((AOP_TYPE(right) == AOP_CRY) || (AOP_TYPE(right) == AOP_LIT))) {
1929 gencjne(left,right,newiTempLabel(NULL));
1930 if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) {
1934 genIfxJump(ifx,"a");
1937 /* if the result is used in an arithmetic operation
1938 then put the result in place */
1939 if (AOP_TYPE(result) != AOP_CRY) {
1942 /* leave the result in acc */
1946 freeAsmop(left,NULL,ic);
1947 freeAsmop(right,NULL,ic);
1948 freeAsmop(result,NULL,ic);
1951 /*-----------------------------------------------------------------*/
1952 /* ifxForOp - returns the icode containing the ifx for operand */
1953 /*-----------------------------------------------------------------*/
1954 static iCode *ifxForOp ( operand *op, iCode *ic )
1956 /* if true symbol then needs to be assigned */
1957 if (IS_TRUE_SYMOP(op))
1960 /* if this has register type condition and
1961 the next instruction is ifx with the same operand
1962 and live to of the operand is upto the ifx only then */
1964 ic->next->op == IFX &&
1965 IC_COND(ic->next)->key == op->key &&
1966 OP_SYMBOL(op)->liveTo <= ic->next->seq )
1972 /*-----------------------------------------------------------------*/
1973 /* genAndOp - for && operation */
1974 /*-----------------------------------------------------------------*/
1975 static void genAndOp (iCode *ic)
1977 operand *left,*right, *result;
1980 /* note here that && operations that are in an if statement are
1981 taken away by backPatchLabels only those used in arthmetic
1982 operations remain */
1983 aopOp((left=IC_LEFT(ic)),ic,FALSE);
1984 aopOp((right=IC_RIGHT(ic)),ic,FALSE);
1985 aopOp((result=IC_RESULT(ic)),ic,FALSE);
1987 /* if both are bit variables */
1988 if (AOP_TYPE(left) == AOP_CRY &&
1989 AOP_TYPE(right) == AOP_CRY ) {
1992 tlbl = newiTempLabel(NULL);
1994 emitcode("jp","z," LABEL_STR ,tlbl->key+100);
1996 emitcode("", LABEL_STR ":",tlbl->key+100);
2000 freeAsmop(left,NULL,ic);
2001 freeAsmop(right,NULL,ic);
2002 freeAsmop(result,NULL,ic);
2005 /*-----------------------------------------------------------------*/
2006 /* genOrOp - for || operation */
2007 /*-----------------------------------------------------------------*/
2008 static void genOrOp (iCode *ic)
2010 operand *left,*right, *result;
2013 /* note here that || operations that are in an
2014 if statement are taken away by backPatchLabels
2015 only those used in arthmetic operations remain */
2016 aopOp((left=IC_LEFT(ic)),ic,FALSE);
2017 aopOp((right=IC_RIGHT(ic)),ic,FALSE);
2018 aopOp((result=IC_RESULT(ic)),ic,FALSE);
2020 /* if both are bit variables */
2021 if (AOP_TYPE(left) == AOP_CRY &&
2022 AOP_TYPE(right) == AOP_CRY ) {
2025 tlbl = newiTempLabel(NULL);
2027 emitcode("jp","nz," LABEL_STR,tlbl->key+100);
2029 emitcode("", LABEL_STR,tlbl->key+100);
2033 freeAsmop(left,NULL,ic);
2034 freeAsmop(right,NULL,ic);
2035 freeAsmop(result,NULL,ic);
2038 /*-----------------------------------------------------------------*/
2039 /* isLiteralBit - test if lit == 2^n */
2040 /*-----------------------------------------------------------------*/
2041 int isLiteralBit(unsigned long lit)
2043 unsigned long pw[32] = {1L,2L,4L,8L,16L,32L,64L,128L,
2044 0x100L,0x200L,0x400L,0x800L,
2045 0x1000L,0x2000L,0x4000L,0x8000L,
2046 0x10000L,0x20000L,0x40000L,0x80000L,
2047 0x100000L,0x200000L,0x400000L,0x800000L,
2048 0x1000000L,0x2000000L,0x4000000L,0x8000000L,
2049 0x10000000L,0x20000000L,0x40000000L,0x80000000L};
2052 for(idx = 0; idx < 32; idx++)
2058 /*-----------------------------------------------------------------*/
2059 /* genAnd - code for and */
2060 /*-----------------------------------------------------------------*/
2061 static void genAnd (iCode *ic, iCode *ifx)
2063 operand *left, *right, *result;
2065 unsigned long lit = 0L;
2068 aopOp((left = IC_LEFT(ic)),ic,FALSE);
2069 aopOp((right= IC_RIGHT(ic)),ic,FALSE);
2070 aopOp((result=IC_RESULT(ic)),ic,TRUE);
2073 emitcode("","; Type res[%d] = l[%d]&r[%d]",
2075 AOP_TYPE(left), AOP_TYPE(right));
2076 emitcode("","; Size res[%d] = l[%d]&r[%d]",
2078 AOP_SIZE(left), AOP_SIZE(right));
2081 /* if left is a literal & right is not then exchange them */
2082 if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
2083 AOP_NEEDSACC(left)) {
2084 operand *tmp = right ;
2089 /* if result = right then exchange them */
2090 if(sameRegs(AOP(result),AOP(right))){
2091 operand *tmp = right ;
2096 /* if right is bit then exchange them */
2097 if (AOP_TYPE(right) == AOP_CRY &&
2098 AOP_TYPE(left) != AOP_CRY){
2099 operand *tmp = right ;
2103 if(AOP_TYPE(right) == AOP_LIT)
2104 lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
2106 size = AOP_SIZE(result);
2108 if (AOP_TYPE(left) == AOP_CRY){
2113 // if(val & 0xZZ) - size = 0, ifx != FALSE -
2114 // bit = val & 0xZZ - size = 1, ifx = FALSE -
2115 if((AOP_TYPE(right) == AOP_LIT) &&
2116 (AOP_TYPE(result) == AOP_CRY) &&
2117 (AOP_TYPE(left) != AOP_CRY)) {
2118 int posbit = isLiteralBit(lit);
2122 MOVA(aopGet(AOP(left),posbit>>3,FALSE));
2126 emitcode("mov","c,acc.%d",posbit&0x07);
2131 sprintf(buffer, "%d", posbit&0x07);
2132 genIfxJump(ifx, buffer);
2140 symbol *tlbl = newiTempLabel(NULL);
2141 int sizel = AOP_SIZE(left);
2144 emitcode("setb","c");
2147 if((bytelit = ((lit >> (offset*8)) & 0x0FFL)) != 0x0L){
2148 MOVA( aopGet(AOP(left),offset,FALSE));
2150 if((posbit = isLiteralBit(bytelit)) != 0) {
2152 emitcode("jb","acc.%d,%05d$",(posbit-1)&0x07,tlbl->key+100);
2155 if(bytelit != 0x0FFL)
2156 emitcode("and","a,%s",
2157 aopGet(AOP(right),offset,FALSE));
2158 emitcode("jr","nz, %05d$",tlbl->key+100);
2163 // bit = left & literal
2165 emitcode("clr","c");
2166 emitcode("","%05d$:",tlbl->key+100);
2168 // if(left & literal)
2172 jmpTrueOrFalse(ifx, tlbl);
2183 /* if left is same as result */
2184 if(sameRegs(AOP(result),AOP(left))){
2185 for(;size--; offset++) {
2186 if(AOP_TYPE(right) == AOP_LIT){
2187 if((bytelit = (int)((lit >> (offset*8)) & 0x0FFL)) == 0x0FF)
2191 aopPut(AOP(result),zero,offset);
2193 MOVA(aopGet(AOP(left),offset,FALSE));
2194 emitcode("and","a,%s",
2195 aopGet(AOP(right),offset,FALSE));
2196 emitcode("ld", "%s,a", aopGet(AOP(left),offset,FALSE));
2201 if (AOP_TYPE(left) == AOP_ACC) {
2205 MOVA(aopGet(AOP(right),offset,FALSE));
2206 emitcode("and","%s,a",
2207 aopGet(AOP(left),offset,FALSE));
2212 // left & result in different registers
2213 if(AOP_TYPE(result) == AOP_CRY){
2216 for(;(size--);offset++) {
2218 // result = left & right
2219 if(AOP_TYPE(right) == AOP_LIT){
2220 if((bytelit = (int)((lit >> (offset*8)) & 0x0FFL)) == 0x0FF){
2222 aopGet(AOP(left),offset,FALSE),
2225 } else if(bytelit == 0){
2226 aopPut(AOP(result),zero,offset);
2230 // faster than result <- left, anl result,right
2231 // and better if result is SFR
2232 if (AOP_TYPE(left) == AOP_ACC)
2233 emitcode("and","a,%s",aopGet(AOP(right),offset,FALSE));
2235 MOVA(aopGet(AOP(right),offset,FALSE));
2236 emitcode("and","a,%s",
2237 aopGet(AOP(left),offset,FALSE));
2239 aopPut(AOP(result),"a",offset);
2246 freeAsmop(left,NULL,ic);
2247 freeAsmop(right,NULL,ic);
2248 freeAsmop(result,NULL,ic);
2251 /*-----------------------------------------------------------------*/
2252 /* genOr - code for or */
2253 /*-----------------------------------------------------------------*/
2254 static void genOr (iCode *ic, iCode *ifx)
2256 operand *left, *right, *result;
2258 unsigned long lit = 0L;
2260 aopOp((left = IC_LEFT(ic)),ic,FALSE);
2261 aopOp((right= IC_RIGHT(ic)),ic,FALSE);
2262 aopOp((result=IC_RESULT(ic)),ic,TRUE);
2265 emitcode("","; Type res[%d] = l[%d]&r[%d]",
2267 AOP_TYPE(left), AOP_TYPE(right));
2268 emitcode("","; Size res[%d] = l[%d]&r[%d]",
2270 AOP_SIZE(left), AOP_SIZE(right));
2273 /* if left is a literal & right is not then exchange them */
2274 if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
2275 AOP_NEEDSACC(left)) {
2276 operand *tmp = right ;
2281 /* if result = right then exchange them */
2282 if(sameRegs(AOP(result),AOP(right))){
2283 operand *tmp = right ;
2288 /* if right is bit then exchange them */
2289 if (AOP_TYPE(right) == AOP_CRY &&
2290 AOP_TYPE(left) != AOP_CRY){
2291 operand *tmp = right ;
2295 if(AOP_TYPE(right) == AOP_LIT)
2296 lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
2298 size = AOP_SIZE(result);
2300 if (AOP_TYPE(left) == AOP_CRY){
2305 if((AOP_TYPE(right) == AOP_LIT) &&
2306 (AOP_TYPE(result) == AOP_CRY) &&
2307 (AOP_TYPE(left) != AOP_CRY)){
2312 /* if left is same as result */
2313 if(sameRegs(AOP(result),AOP(left))){
2314 for(;size--; offset++) {
2315 if(AOP_TYPE(right) == AOP_LIT){
2316 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L)
2319 emitcode("or","%s,%s; 5",
2320 aopGet(AOP(left),offset,FALSE),
2321 aopGet(AOP(right),offset,FALSE));
2323 if (AOP_TYPE(left) == AOP_ACC)
2324 emitcode("or","a,%s ; 6",aopGet(AOP(right),offset,FALSE));
2326 MOVA(aopGet(AOP(right),offset,FALSE));
2327 emitcode("or","a,%s ; 7",
2328 aopGet(AOP(left),offset,FALSE));
2329 aopPut(AOP(result),"a ; 8",0);
2334 // left & result in different registers
2335 if(AOP_TYPE(result) == AOP_CRY){
2337 } else for(;(size--);offset++){
2339 // result = left & right
2340 if(AOP_TYPE(right) == AOP_LIT){
2341 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L){
2343 aopGet(AOP(left),offset,FALSE),
2348 // faster than result <- left, anl result,right
2349 // and better if result is SFR
2350 if (AOP_TYPE(left) == AOP_ACC)
2351 emitcode("or","a,%s",aopGet(AOP(right),offset,FALSE));
2353 MOVA(aopGet(AOP(right),offset,FALSE));
2354 emitcode("or","a,%s",
2355 aopGet(AOP(left),offset,FALSE));
2357 aopPut(AOP(result),"a",offset);
2358 /* PENDING: something weird is going on here. Add exception. */
2359 if (AOP_TYPE(result) == AOP_ACC)
2365 freeAsmop(left,NULL,ic);
2366 freeAsmop(right,NULL,ic);
2367 freeAsmop(result,NULL,ic);
2370 /*-----------------------------------------------------------------*/
2371 /* genXor - code for xclusive or */
2372 /*-----------------------------------------------------------------*/
2373 static void genXor (iCode *ic, iCode *ifx)
2375 operand *left, *right, *result;
2377 unsigned long lit = 0L;
2379 aopOp((left = IC_LEFT(ic)),ic,FALSE);
2380 aopOp((right= IC_RIGHT(ic)),ic,FALSE);
2381 aopOp((result=IC_RESULT(ic)),ic,TRUE);
2383 /* if left is a literal & right is not then exchange them */
2384 if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) ||
2385 AOP_NEEDSACC(left)) {
2386 operand *tmp = right ;
2391 /* if result = right then exchange them */
2392 if(sameRegs(AOP(result),AOP(right))){
2393 operand *tmp = right ;
2398 /* if right is bit then exchange them */
2399 if (AOP_TYPE(right) == AOP_CRY &&
2400 AOP_TYPE(left) != AOP_CRY){
2401 operand *tmp = right ;
2405 if(AOP_TYPE(right) == AOP_LIT)
2406 lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit);
2408 size = AOP_SIZE(result);
2410 if (AOP_TYPE(left) == AOP_CRY){
2415 if((AOP_TYPE(right) == AOP_LIT) &&
2416 (AOP_TYPE(result) == AOP_CRY) &&
2417 (AOP_TYPE(left) != AOP_CRY)){
2422 /* if left is same as result */
2423 if(sameRegs(AOP(result),AOP(left))){
2424 for(;size--; offset++) {
2425 if(AOP_TYPE(right) == AOP_LIT){
2426 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L)
2429 MOVA(aopGet(AOP(right),offset,FALSE));
2430 emitcode("xor","a,%s",
2431 aopGet(AOP(left),offset,FALSE));
2432 aopPut(AOP(result),"a",0);
2435 if (AOP_TYPE(left) == AOP_ACC)
2436 emitcode("xor","a,%s",aopGet(AOP(right),offset,FALSE));
2438 MOVA(aopGet(AOP(right),offset,FALSE));
2439 emitcode("xor","a,%s",
2440 aopGet(AOP(left),offset,FALSE));
2441 aopPut(AOP(result),"a",0);
2446 // left & result in different registers
2447 if(AOP_TYPE(result) == AOP_CRY){
2449 } else for(;(size--);offset++){
2451 // result = left & right
2452 if(AOP_TYPE(right) == AOP_LIT){
2453 if(((lit >> (offset*8)) & 0x0FFL) == 0x00L){
2455 aopGet(AOP(left),offset,FALSE),
2460 // faster than result <- left, anl result,right
2461 // and better if result is SFR
2462 if (AOP_TYPE(left) == AOP_ACC)
2463 emitcode("xor","a,%s",aopGet(AOP(right),offset,FALSE));
2465 MOVA(aopGet(AOP(right),offset,FALSE));
2466 emitcode("xor","a,%s",
2467 aopGet(AOP(left),offset,FALSE));
2468 aopPut(AOP(result),"a",0);
2470 aopPut(AOP(result),"a",offset);
2475 freeAsmop(left,NULL,ic);
2476 freeAsmop(right,NULL,ic);
2477 freeAsmop(result,NULL,ic);
2480 /*-----------------------------------------------------------------*/
2481 /* genInline - write the inline code out */
2482 /*-----------------------------------------------------------------*/
2483 static void genInline (iCode *ic)
2485 char buffer[MAX_INLINEASM];
2489 inLine += (!options.asmpeep);
2490 strcpy(buffer,IC_INLINE(ic));
2492 /* emit each line as a code */
2511 /* emitcode("",buffer); */
2512 inLine -= (!options.asmpeep);
2515 /*-----------------------------------------------------------------*/
2516 /* genRRC - rotate right with carry */
2517 /*-----------------------------------------------------------------*/
2518 static void genRRC (iCode *ic)
2523 /*-----------------------------------------------------------------*/
2524 /* genRLC - generate code for rotate left with carry */
2525 /*-----------------------------------------------------------------*/
2526 static void genRLC (iCode *ic)
2531 /*-----------------------------------------------------------------*/
2532 /* shiftR2Left2Result - shift right two bytes from left to result */
2533 /*-----------------------------------------------------------------*/
2534 static void shiftR2Left2Result (operand *left, int offl,
2535 operand *result, int offr,
2536 int shCount, int sign)
2538 if(sameRegs(AOP(result), AOP(left)) &&
2539 ((offl + MSB16) == offr)){
2542 movLeft2Result(left, offl, result, offr, 0);
2543 movLeft2Result(left, offl+1, result, offr+1, 0);
2550 /* if (AOP(result)->type == AOP_REG) {*/
2553 symbol *tlbl , *tlbl1;
2556 /* Left is already in result - so now do the shift */
2558 emitcode("ld","a,#%u+1", shCount);
2559 tlbl = newiTempLabel(NULL);
2560 tlbl1 = newiTempLabel(NULL);
2561 emitcode("jp", LABEL_STR ,tlbl1->key+100);
2562 emitcode("", LABEL_STR ":",tlbl->key+100);
2565 emitcode("or", "a,a");
2568 l = aopGet(AOP(result), --offset, FALSE);
2569 emitcode("rr","%s", l);
2572 emitcode("", LABEL_STR ":",tlbl1->key+100);
2573 emitcode("dec", "a");
2574 emitcode("jp","nz," LABEL_STR ,tlbl->key+100);
2579 /*-----------------------------------------------------------------*/
2580 /* shiftL2Left2Result - shift left two bytes from left to result */
2581 /*-----------------------------------------------------------------*/
2582 static void shiftL2Left2Result (operand *left, int offl,
2583 operand *result, int offr, int shCount)
2585 if(sameRegs(AOP(result), AOP(left)) &&
2586 ((offl + MSB16) == offr)){
2589 /* Copy left into result */
2590 movLeft2Result(left,offl, result, offr, 0);
2592 /* PENDING: for now just see if it'll work. */
2593 /*if (AOP(result)->type == AOP_REG) { */
2597 symbol *tlbl , *tlbl1;
2600 /* Left is already in result - so now do the shift */
2602 emitcode("ld","a,#%u+1", shCount);
2603 tlbl = newiTempLabel(NULL);
2604 tlbl1 = newiTempLabel(NULL);
2605 emitcode("jp", LABEL_STR ,tlbl1->key+100);
2606 emitcode("", LABEL_STR ":",tlbl->key+100);
2609 emitcode("or", "a,a");
2611 l = aopGet(AOP(result),offset++,FALSE);
2612 emitcode("rl","%s", l);
2615 emitcode("", LABEL_STR ":",tlbl1->key+100);
2616 emitcode("dec", "a");
2617 emitcode("jp","nz," LABEL_STR ,tlbl->key+100);
2622 /*-----------------------------------------------------------------*/
2623 /* AccRol - rotate left accumulator by known count */
2624 /*-----------------------------------------------------------------*/
2625 static void AccRol (int shCount)
2627 shCount &= 0x0007; // shCount : 0..7
2664 /*-----------------------------------------------------------------*/
2665 /* AccLsh - left shift accumulator by known count */
2666 /*-----------------------------------------------------------------*/
2667 static void AccLsh (int shCount)
2671 emitcode("add","a,a");
2674 emitcode("add","a,a");
2675 emitcode("add","a,a");
2677 /* rotate left accumulator */
2679 /* and kill the lower order bits */
2680 emitcode("and","a,#0x%02x", SLMask[shCount]);
2685 /*-----------------------------------------------------------------*/
2686 /* shiftL1Left2Result - shift left one byte from left to result */
2687 /*-----------------------------------------------------------------*/
2688 static void shiftL1Left2Result (operand *left, int offl,
2689 operand *result, int offr, int shCount)
2692 l = aopGet(AOP(left),offl,FALSE);
2694 /* shift left accumulator */
2696 aopPut(AOP(result),"a",offr);
2700 /*-----------------------------------------------------------------*/
2701 /* genlshTwo - left shift two bytes by known amount != 0 */
2702 /*-----------------------------------------------------------------*/
2703 static void genlshTwo (operand *result,operand *left, int shCount)
2705 int size = AOP_SIZE(result);
2709 /* if shCount >= 8 */
2715 movLeft2Result(left, LSB, result, MSB16, 0);
2716 aopPut(AOP(result),zero, 0);
2717 shiftL1Left2Result(left, MSB16, result, MSB16, shCount-8);
2720 movLeft2Result(left, LSB, result, MSB16, 0);
2721 aopPut(AOP(result),zero, 0);
2724 aopPut(AOP(result),zero,LSB);
2726 /* 1 <= shCount <= 7 */
2732 shiftL2Left2Result(left, LSB, result, LSB, shCount);
2737 /*-----------------------------------------------------------------*/
2738 /* genlshOne - left shift a one byte quantity by known count */
2739 /*-----------------------------------------------------------------*/
2740 static void genlshOne (operand *result, operand *left, int shCount)
2742 shiftL1Left2Result(left, LSB, result, LSB, shCount);
2745 /*-----------------------------------------------------------------*/
2746 /* genLeftShiftLiteral - left shifting by known count */
2747 /*-----------------------------------------------------------------*/
2748 static void genLeftShiftLiteral (operand *left,
2753 int shCount = (int) floatFromVal (AOP(right)->aopu.aop_lit);
2756 freeAsmop(right,NULL,ic);
2758 aopOp(left,ic,FALSE);
2759 aopOp(result,ic,FALSE);
2761 size = getSize(operandType(result));
2764 emitcode("; shift left ","result %d, left %d",size,
2768 /* I suppose that the left size >= result size */
2773 else if(shCount >= (size * 8))
2775 aopPut(AOP(result),zero,size);
2779 genlshOne (result,left,shCount);
2782 genlshTwo (result,left,shCount);
2791 freeAsmop(left,NULL,ic);
2792 freeAsmop(result,NULL,ic);
2795 /*-----------------------------------------------------------------*/
2796 /* genLeftShift - generates code for left shifting */
2797 /*-----------------------------------------------------------------*/
2798 static void genLeftShift (iCode *ic)
2802 symbol *tlbl , *tlbl1;
2803 operand *left,*right, *result;
2805 right = IC_RIGHT(ic);
2807 result = IC_RESULT(ic);
2809 aopOp(right,ic,FALSE);
2811 /* if the shift count is known then do it
2812 as efficiently as possible */
2813 if (AOP_TYPE(right) == AOP_LIT) {
2814 genLeftShiftLiteral (left,right,result,ic);
2818 /* shift count is unknown then we have to form a loop get the loop
2819 count in B : Note: we take only the lower order byte since
2820 shifting more that 32 bits make no sense anyway, ( the largest
2821 size of an object can be only 32 bits ) */
2822 emitcode("ld","a,%s",aopGet(AOP(right),0,FALSE));
2823 emitcode("inc","a");
2824 freeAsmop (right,NULL,ic);
2825 aopOp(left,ic,FALSE);
2826 aopOp(result,ic,FALSE);
2828 /* now move the left to the result if they are not the
2831 if (!sameRegs(AOP(left),AOP(result))) {
2833 size = AOP_SIZE(result);
2836 l = aopGet(AOP(left),offset,FALSE);
2837 aopPut(AOP(result),l,offset);
2842 size = AOP_SIZE(result);
2845 l = aopGet(AOP(left),offset,FALSE);
2846 aopPut(AOP(result),l,offset);
2852 tlbl = newiTempLabel(NULL);
2853 size = AOP_SIZE(result);
2855 tlbl1 = newiTempLabel(NULL);
2857 emitcode("jp", LABEL_STR ,tlbl1->key+100);
2858 emitcode("", LABEL_STR ":",tlbl->key+100);
2859 l = aopGet(AOP(result),offset,FALSE);
2860 emitcode("or", "a,a");
2862 l = aopGet(AOP(result),offset++,FALSE);
2863 emitcode("rl","%s", l);
2865 emitcode("", LABEL_STR ":",tlbl1->key+100);
2866 emitcode("dec", "a");
2867 emitcode("jp","nz," LABEL_STR ,tlbl->key+100);
2869 freeAsmop(left,NULL,ic);
2870 freeAsmop(result,NULL,ic);
2873 /* genlshTwo - left shift two bytes by known amount != 0 */
2874 /*-----------------------------------------------------------------*/
2875 static void genrshOne (operand *result,operand *left, int shCount)
2878 int size = AOP_SIZE(result);
2884 l = aopGet(AOP(left),0,FALSE);
2885 if (AOP(result)->type == AOP_REG) {
2886 aopPut(AOP(result), l, 0);
2887 l = aopGet(AOP(result), 0, FALSE);
2889 emitcode("srl", "%s", l);
2894 emitcode("srl", "a");
2896 aopPut(AOP(result),"a",0);
2900 /*-----------------------------------------------------------------*/
2901 /* AccRsh - right shift accumulator by known count */
2902 /*-----------------------------------------------------------------*/
2903 static void AccRsh (int shCount)
2910 /* rotate right accumulator */
2911 AccRol(8 - shCount);
2912 /* and kill the higher order bits */
2913 emitcode("and","a,#0x%02x", SRMask[shCount]);
2918 /*-----------------------------------------------------------------*/
2919 /* shiftR1Left2Result - shift right one byte from left to result */
2920 /*-----------------------------------------------------------------*/
2921 static void shiftR1Left2Result (operand *left, int offl,
2922 operand *result, int offr,
2923 int shCount, int sign)
2925 MOVA(aopGet(AOP(left),offl,FALSE));
2932 aopPut(AOP(result),"a",offr);
2935 /*-----------------------------------------------------------------*/
2936 /* genrshTwo - right shift two bytes by known amount != 0 */
2937 /*-----------------------------------------------------------------*/
2938 static void genrshTwo (operand *result,operand *left,
2939 int shCount, int sign)
2941 /* if shCount >= 8 */
2946 shiftR1Left2Result(left, MSB16, result, LSB,
2950 movLeft2Result(left, MSB16, result, LSB, sign);
2951 aopPut(AOP(result),zero,1);
2954 /* 1 <= shCount <= 7 */
2956 shiftR2Left2Result(left, LSB, result, LSB, shCount, sign);
2960 /*-----------------------------------------------------------------*/
2961 /* genRightShiftLiteral - left shifting by known count */
2962 /*-----------------------------------------------------------------*/
2963 static void genRightShiftLiteral (operand *left,
2968 int shCount = (int) floatFromVal (AOP(right)->aopu.aop_lit);
2971 freeAsmop(right,NULL,ic);
2973 aopOp(left,ic,FALSE);
2974 aopOp(result,ic,FALSE);
2976 size = getSize(operandType(result));
2978 emitcode("; shift right ","result %d, left %d",size,
2981 /* I suppose that the left size >= result size */
2986 else if(shCount >= (size * 8))
2988 aopPut(AOP(result),zero,size);
2992 genrshOne(result, left, shCount);
2995 /* PENDING: sign support */
2996 genrshTwo(result, left, shCount, FALSE);
3005 freeAsmop(left,NULL,ic);
3006 freeAsmop(result,NULL,ic);
3009 /*-----------------------------------------------------------------*/
3010 /* genRightShift - generate code for right shifting */
3011 /*-----------------------------------------------------------------*/
3012 static void genRightShift (iCode *ic)
3014 operand *left,*right, *result;
3016 right = IC_RIGHT(ic);
3018 result = IC_RESULT(ic);
3020 aopOp(right,ic,FALSE);
3022 /* if the shift count is known then do it
3023 as efficiently as possible */
3024 if (AOP_TYPE(right) == AOP_LIT) {
3025 genRightShiftLiteral (left,right,result,ic);
3033 /*-----------------------------------------------------------------*/
3034 /* genGenPointerGet - gget value from generic pointer space */
3035 /*-----------------------------------------------------------------*/
3036 static void genGenPointerGet (operand *left,
3037 operand *result, iCode *ic)
3040 link *retype = getSpec(operandType(result));
3042 aopOp(left,ic,FALSE);
3043 aopOp(result,ic,FALSE);
3045 if (isPair(AOP(left)) && (AOP_SIZE(result)==1)) {
3047 emitcode("ld", "a,(%s)", getPairName(AOP(left)));
3048 aopPut(AOP(result),"a", 0);
3049 freeAsmop(left,NULL,ic);
3053 /* For now we always load into IY */
3054 /* if this is remateriazable */
3055 if (AOP_TYPE(left) == AOP_IMMD)
3056 emitcode("ld","hl,%s",aopGet(AOP(left),0,TRUE));
3057 else { /* we need to get it byte by byte */
3058 emitcode("ld", "l,%s", aopGet(AOP(left), 0, FALSE));
3059 emitcode("ld", "h,%s", aopGet(AOP(left), 1, FALSE));
3061 /* so iy now contains the address */
3062 freeAsmop(left,NULL,ic);
3064 /* if bit then unpack */
3065 if (IS_BITVAR(retype)) {
3069 size = AOP_SIZE(result);
3073 /* PENDING: make this better */
3074 if (AOP(result)->type == AOP_REG) {
3075 aopPut(AOP(result),"(hl)",offset++);
3078 emitcode("ld", "a,(hl)", offset);
3079 aopPut(AOP(result),"a",offset++);
3082 emitcode("inc", "hl");
3088 freeAsmop(result,NULL,ic);
3091 /*-----------------------------------------------------------------*/
3092 /* genPointerGet - generate code for pointer get */
3093 /*-----------------------------------------------------------------*/
3094 static void genPointerGet (iCode *ic)
3096 operand *left, *result ;
3100 result = IC_RESULT(ic) ;
3102 /* depending on the type of pointer we need to
3103 move it to the correct pointer register */
3104 type = operandType(left);
3105 etype = getSpec(type);
3107 genGenPointerGet (left,result,ic);
3110 bool isRegOrLit(asmop *aop)
3112 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
3117 /*-----------------------------------------------------------------*/
3118 /* genGenPointerSet - stores the value into a pointer location */
3119 /*-----------------------------------------------------------------*/
3120 static void genGenPointerSet (operand *right,
3121 operand *result, iCode *ic)
3124 link *retype = getSpec(operandType(right));
3126 aopOp(result,ic,FALSE);
3127 aopOp(right,ic,FALSE);
3129 /* Handle the exceptions first */
3130 if (isPair(AOP(result)) && (AOP_SIZE(right)==1)) {
3132 char *l = aopGet(AOP(right), 0, FALSE);
3134 emitcode("ld", "(%s),a", getPairName(AOP(result)));
3135 freeAsmop(result,NULL,ic);
3139 /* if the operand is already in dptr
3140 then we do nothing else we move the value to dptr */
3141 if (AOP_TYPE(result) != AOP_STR) {
3142 /* if this is remateriazable */
3143 if (AOP_TYPE(result) == AOP_IMMD) {
3144 emitcode("", "; Error 2");
3145 emitcode("ld", "hl,%s", aopGet(AOP(result), 0, TRUE));
3147 else { /* we need to get it byte by byte */
3148 /* PENDING: do this better */
3149 emitcode("ld", "l,%s", aopGet(AOP(result), 0, FALSE));
3150 emitcode("ld", "h,%s", aopGet(AOP(result), 1, FALSE));
3153 /* so hl know contains the address */
3154 freeAsmop(result,NULL,ic);
3156 /* if bit then unpack */
3157 if (IS_BITVAR(retype)) {
3161 size = AOP_SIZE(right);
3165 char *l = aopGet(AOP(right),offset,FALSE);
3167 if (isRegOrLit(AOP(right))) {
3168 emitcode("ld", "(hl),%s", l);
3172 emitcode("ld", "(hl),a", offset);
3175 emitcode("inc", "hl");
3181 freeAsmop(right,NULL,ic);
3184 /*-----------------------------------------------------------------*/
3185 /* genPointerSet - stores the value into a pointer location */
3186 /*-----------------------------------------------------------------*/
3187 static void genPointerSet (iCode *ic)
3189 operand *right, *result ;
3192 right = IC_RIGHT(ic);
3193 result = IC_RESULT(ic) ;
3195 /* depending on the type of pointer we need to
3196 move it to the correct pointer register */
3197 type = operandType(result);
3198 etype = getSpec(type);
3200 genGenPointerSet (right,result,ic);
3203 /*-----------------------------------------------------------------*/
3204 /* genIfx - generate code for Ifx statement */
3205 /*-----------------------------------------------------------------*/
3206 static void genIfx (iCode *ic, iCode *popIc)
3208 operand *cond = IC_COND(ic);
3211 aopOp(cond,ic,FALSE);
3213 /* get the value into acc */
3214 if (AOP_TYPE(cond) != AOP_CRY)
3218 /* the result is now in the accumulator */
3219 freeAsmop(cond,NULL,ic);
3221 /* if there was something to be popped then do it */
3225 /* if the condition is a bit variable */
3226 if (isbit && IS_ITEMP(cond) &&
3228 genIfxJump(ic,SPIL_LOC(cond)->rname);
3230 if (isbit && !IS_ITEMP(cond))
3231 genIfxJump(ic,OP_SYMBOL(cond)->rname);
3238 /*-----------------------------------------------------------------*/
3239 /* genAddrOf - generates code for address of */
3240 /*-----------------------------------------------------------------*/
3241 static void genAddrOf (iCode *ic)
3243 symbol *sym = OP_SYMBOL(IC_LEFT(ic));
3245 aopOp(IC_RESULT(ic),ic,FALSE);
3247 /* if the operand is on the stack then we
3248 need to get the stack offset of this
3251 /* if it has an offset then we need to compute it */
3252 emitcode("push", "de");
3253 emitcode("push", "ix");
3254 emitcode("pop", "hl");
3255 emitcode("ld", "de,#%d", sym->stack);
3256 emitcode("add", "hl,de");
3257 emitcode("pop", "de");
3260 emitcode("ld", "hl,#%s", sym->rname);
3262 aopPut(AOP(IC_RESULT(ic)), "l", 0);
3263 aopPut(AOP(IC_RESULT(ic)), "h", 1);
3265 freeAsmop(IC_RESULT(ic),NULL,ic);
3268 /*-----------------------------------------------------------------*/
3269 /* genAssign - generate code for assignment */
3270 /*-----------------------------------------------------------------*/
3271 static void genAssign (iCode *ic)
3273 operand *result, *right;
3275 unsigned long lit = 0L;
3277 result = IC_RESULT(ic);
3278 right = IC_RIGHT(ic) ;
3281 /* Dont bother assigning if they are the same */
3282 if (operandsEqu (IC_RESULT(ic),IC_RIGHT(ic))) {
3283 emitcode("", "; (operands are equal %u)", operandsEqu(IC_RESULT(ic),IC_RIGHT(ic)));
3288 aopOp(right,ic,FALSE);
3289 aopOp(result,ic,TRUE);
3291 /* if they are the same registers */
3292 if (sameRegs(AOP(right),AOP(result))) {
3293 emitcode("", "; (registers are the same)");
3297 /* if the result is a bit */
3298 if (AOP_TYPE(result) == AOP_CRY) {
3303 size = AOP_SIZE(result);
3306 if(AOP_TYPE(right) == AOP_LIT)
3307 lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit);
3309 (AOP_TYPE(result) != AOP_REG) &&
3310 (AOP_TYPE(right) == AOP_LIT) &&
3311 !IS_FLOAT(operandType(right)) &&
3313 emitcode("xor","a,a");
3314 /* Work from the top down.
3315 Done this way so that we can use the cached copy of 0
3316 in A for a fast clear */
3318 if((unsigned int)((lit >> (size*8)) & 0x0FFL)== 0)
3319 aopPut(AOP(result),"a",size);
3322 aopGet(AOP(right),size,FALSE),
3328 aopGet(AOP(right),offset,FALSE),
3335 freeAsmop(right,NULL,ic);
3336 freeAsmop(result,NULL,ic);
3339 /*-----------------------------------------------------------------*/
3340 /* genJumpTab - genrates code for jump table */
3341 /*-----------------------------------------------------------------*/
3342 static void genJumpTab (iCode *ic)
3347 aopOp(IC_JTCOND(ic),ic,FALSE);
3348 /* get the condition into accumulator */
3349 l = aopGet(AOP(IC_JTCOND(ic)),0,FALSE);
3351 emitcode("push", "de");
3352 emitcode("ld", "e,%s", l);
3353 emitcode("ld", "d,#0");
3354 jtab = newiTempLabel(NULL);
3355 emitcode("ld", "hl,#" LABEL_STR, jtab->key+100);
3356 emitcode("add", "hl,de");
3357 emitcode("add", "hl,de");
3358 freeAsmop(IC_JTCOND(ic),NULL,ic);
3359 emitcode("pop", "de");
3360 emitcode("jp", "(hl)");
3361 emitcode("","%05d$:",jtab->key+100);
3362 /* now generate the jump labels */
3363 for (jtab = setFirstItem(IC_JTLABELS(ic)) ; jtab;
3364 jtab = setNextItem(IC_JTLABELS(ic)))
3365 emitcode("jp", LABEL_STR, jtab->key+100);
3368 /*-----------------------------------------------------------------*/
3369 /* genCast - gen code for casting */
3370 /*-----------------------------------------------------------------*/
3371 static void genCast (iCode *ic)
3373 operand *result = IC_RESULT(ic);
3374 link *ctype = operandType(IC_LEFT(ic));
3375 operand *right = IC_RIGHT(ic);
3378 /* if they are equivalent then do nothing */
3379 if (operandsEqu(IC_RESULT(ic),IC_RIGHT(ic)))
3382 aopOp(right,ic,FALSE) ;
3383 aopOp(result,ic,FALSE);
3385 /* if the result is a bit */
3386 if (AOP_TYPE(result) == AOP_CRY) {
3390 /* if they are the same size : or less */
3391 if (AOP_SIZE(result) <= AOP_SIZE(right)) {
3393 /* if they are in the same place */
3394 if (sameRegs(AOP(right),AOP(result)))
3397 /* if they in different places then copy */
3398 size = AOP_SIZE(result);
3402 aopGet(AOP(right),offset,FALSE),
3409 /* if the result is of type pointer */
3410 if (IS_PTR(ctype)) {
3414 /* so we now know that the size of destination is greater
3415 than the size of the source */
3416 /* we move to result for the size of source */
3417 size = AOP_SIZE(right);
3421 aopGet(AOP(right),offset,FALSE),
3426 /* now depending on the sign of the destination */
3427 size = AOP_SIZE(result) - AOP_SIZE(right);
3428 /* Unsigned or not an integral type - right fill with zeros */
3429 if (SPEC_USIGN(ctype) || !IS_SPEC(ctype)) {
3431 aopPut(AOP(result),zero,offset++);
3433 /* we need to extend the sign :{ */
3434 char *l = aopGet(AOP(right),AOP_SIZE(right) - 1,
3437 emitcode("", "; genCast: sign extend untested.");
3438 emitcode("rla", "");
3439 emitcode("sbc", "a,a");
3441 aopPut(AOP(result),"a",offset++);
3445 freeAsmop(right, NULL, ic);
3446 freeAsmop(result, NULL, ic);
3449 /*-----------------------------------------------------------------*/
3450 /* genReceive - generate code for a receive iCode */
3451 /*-----------------------------------------------------------------*/
3452 static void genReceive (iCode *ic)
3454 if (isOperandInFarSpace(IC_RESULT(ic)) &&
3455 ( OP_SYMBOL(IC_RESULT(ic))->isspilt ||
3456 IS_TRUE_SYMOP(IC_RESULT(ic))) ) {
3460 aopOp(IC_RESULT(ic),ic,FALSE);
3462 assignResultValue(IC_RESULT(ic));
3465 freeAsmop(IC_RESULT(ic),NULL,ic);
3468 /*-----------------------------------------------------------------*/
3469 /* genZ80Code - generate code for Z80 based controllers */
3470 /*-----------------------------------------------------------------*/
3471 void genZ80Code (iCode *lic)
3476 lineHead = lineCurr = NULL;
3478 /* if debug information required */
3479 if (options.debug && currFunc) {
3480 cdbSymbol(currFunc,cdbFile,FALSE,TRUE);
3482 if (IS_STATIC(currFunc->etype))
3483 emitcode("","F%s$%s$0$0 ==.",moduleName,currFunc->name);
3485 emitcode("","G$%s$0$0 ==.",currFunc->name);
3488 /* stack pointer name */
3492 for (ic = lic ; ic ; ic = ic->next ) {
3494 if ( cln != ic->lineno ) {
3495 if ( options.debug ) {
3497 emitcode("","C$%s$%d$%d$%d ==.",
3498 ic->filename,ic->lineno,
3499 ic->level,ic->block);
3502 emitcode(";","%s %d",ic->filename,ic->lineno);
3505 /* if the result is marked as
3506 spilt and rematerializable or code for
3507 this has already been generated then
3509 if (resultRemat(ic) || ic->generated )
3512 /* depending on the operation */
3515 emitcode("", "; genNot");
3520 emitcode("", "; genCpl");
3525 emitcode("", "; genUminus");
3530 emitcode("", "; genIpush");
3535 /* IPOP happens only when trying to restore a
3536 spilt live range, if there is an ifx statement
3537 following this pop then the if statement might
3538 be using some of the registers being popped which
3539 would destory the contents of the register so
3540 we need to check for this condition and handle it */
3542 ic->next->op == IFX &&
3543 regsInCommon(IC_LEFT(ic),IC_COND(ic->next))) {
3544 emitcode("", "; genIfx");
3545 genIfx (ic->next,ic);
3548 emitcode("", "; genIpop");
3554 emitcode("", "; genCall");
3559 emitcode("", "; genPcall");
3564 emitcode("", "; genFunction");
3569 emitcode("", "; genEndFunction");
3570 genEndFunction (ic);
3574 emitcode("", "; genRet");
3579 emitcode("", "; genLabel");
3584 emitcode("", "; genGoto");
3589 emitcode("", "; genPlus");
3594 emitcode("", "; genMinus");
3599 emitcode("", "; genMult");
3604 emitcode("", "; genDiv");
3609 emitcode("", "; genMod");
3614 emitcode("", "; genCmpGt");
3615 genCmpGt (ic,ifxForOp(IC_RESULT(ic),ic));
3619 emitcode("", "; genCmpLt");
3620 genCmpLt (ic,ifxForOp(IC_RESULT(ic),ic));
3627 /* note these two are xlated by algebraic equivalence
3628 during parsing SDCC.y */
3629 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,
3630 "got '>=' or '<=' shouldn't have come here");
3634 emitcode("", "; genCmpEq");
3635 genCmpEq (ic,ifxForOp(IC_RESULT(ic),ic));
3639 emitcode("", "; genAndOp");
3644 emitcode("", "; genOrOp");
3649 emitcode("", "; genXor");
3650 genXor (ic,ifxForOp(IC_RESULT(ic),ic));
3654 emitcode("", "; genOr");
3655 genOr (ic,ifxForOp(IC_RESULT(ic),ic));
3659 emitcode("", "; genAnd");
3660 genAnd (ic,ifxForOp(IC_RESULT(ic),ic));
3664 emitcode("", "; genInline");
3669 emitcode("", "; genRRC");
3674 emitcode("", "; genRLC");
3679 emitcode("", "; genHBIT");
3683 emitcode("", "; genLeftShift");
3688 emitcode("", "; genRightShift");
3692 case GET_VALUE_AT_ADDRESS:
3693 emitcode("", "; genPointerGet");
3699 if (POINTER_SET(ic)) {
3700 emitcode("", "; genAssign (pointer)");
3704 emitcode("", "; genAssign");
3710 emitcode("", "; genIfx");
3715 emitcode("", "; genAddrOf");
3720 emitcode("", "; genJumpTab");
3725 emitcode("", "; genCast");
3730 emitcode("", "; genReceive");
3735 emitcode("", "; addSet");
3736 addSet(&sendSet,ic);
3741 /* piCode(ic,stdout); */
3747 /* now we are ready to call the
3748 peep hole optimizer */
3749 /* if (!options.nopeep)
3750 peepHole (&lineHead); */
3752 /* now do the actual printing */
3753 printLine (lineHead,codeOutFile);