From: sandeep Date: Sat, 30 Sep 2000 16:57:19 +0000 (+0000) Subject: AVR Intermediate commit X-Git-Url: https://git.gag.com/?a=commitdiff_plain;h=92b0649396f87589345e71797951ba3472b81257;p=fw%2Fsdcc AVR Intermediate commit git-svn-id: https://sdcc.svn.sourceforge.net/svnroot/sdcc/trunk/sdcc@426 4a8a32a2-be11-0410-ad9d-d568d2c75423 --- diff --git a/src/avr/Makefile b/src/avr/Makefile index d2783a64..111eb50d 100644 --- a/src/avr/Makefile +++ b/src/avr/Makefile @@ -2,7 +2,7 @@ PRJDIR = ../.. include $(PRJDIR)/Makefile.common -OBJ = gen.o ralloc.o main.o +OBJ = ralloc.o main.o LIB = port.a CFLAGS += -I.. -I. -I../.. diff --git a/src/avr/gen.c b/src/avr/gen.c index ae091594..ec7277d3 100644 --- a/src/avr/gen.c +++ b/src/avr/gen.c @@ -1,9 +1,7 @@ -/*------------------------------------------------------------------------- - gen.c - source file for code generation for AVR +s/*------------------------------------------------------------------------- + avrgen.c - source file for code generation for ATMEL AVR - Written By - Sandeep Dutta . sandeep.dutta@usa.net (1998) - and - Jean-Louis VERN.jlvern@writeme.com (1999) - Bug Fixes - Wojciech Stryjewski wstryj1@tiger.lsu.edu (1999 v2.1.9a) + Written By - Sandeep Dutta . sandeep.dutta@usa.net (2000) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the @@ -23,9 +21,7 @@ You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! - Notes: - 000123 mlh Moved aopLiteral to SDCCglue.c to help the split - Made everything static + -------------------------------------------------------------------------*/ #include @@ -53,18 +49,26 @@ #include "gen.h" char *aopLiteral (value *val, int offset); +extern int allocInfo; /* this is the down and dirty file with all kinds of kludgy & hacky stuff. This is what it is all about CODE GENERATION for a specific MCU . some of the routines may be reusable, will have to see */ -static char *zero = "#0x00"; -static char *one = "#0x01"; +static char *zero = "0x00"; +static char *one = "0x01"; +static char *spname ; + +char *fReturnAVR[] = {"r16","r17","r18","r19" }; +unsigned fReturnSize = 4; /* shared with ralloc.c */ +char **fReturn = fReturnAVR; + +static short rbank = -1; static struct { - short r0Pushed; - short r1Pushed; + short xPushed; + short zPushed; short accInUse; short inLine; short debugLine; @@ -72,11 +76,31 @@ static struct { set *sendSet; } _G; +extern int avr_ptrRegReq ; +extern int avr_nRegs; extern FILE *codeOutFile; +static void saverbank (int, iCode *,bool); +#define RESULTONSTACK(x) \ + (IC_RESULT(x) && IC_RESULT(x)->aop && \ + IC_RESULT(x)->aop->type == AOP_STK ) + +#define MOVR0(x) if (strcmp(x,"r0")) emitcode("mov","r0,%s",x); +#define CLRC emitcode("clc") +#define SETC emitcode("stc") static lineNode *lineHead = NULL; static lineNode *lineCurr = NULL; +static unsigned char SLMask[] = {0xFF ,0xFE, 0xFC, 0xF8, 0xF0, +0xE0, 0xC0, 0x80, 0x00}; +static unsigned char SRMask[] = {0xFF, 0x7F, 0x3F, 0x1F, 0x0F, +0x07, 0x03, 0x01, 0x00}; + +#define LSB 0 +#define MSB16 1 +#define MSB24 2 +#define MSB32 3 + /*-----------------------------------------------------------------*/ /* emitcode - writes the code into a file : for now it is simple */ /*-----------------------------------------------------------------*/ @@ -109,30 +133,6693 @@ static void emitcode (char *inst,char *fmt, ...) } /*-----------------------------------------------------------------*/ -/* genAVRCode - generate code forAVR based controllers */ +/* getFreePtr - returns X or Z whichever is free or can be pushed */ /*-----------------------------------------------------------------*/ -void genAVRCode (iCode *lic) +static regs *getFreePtr (iCode *ic, asmop **aopp, bool result, bool zonly) { - iCode *ic; - int cln = 0; + bool xiu = FALSE , ziu = FALSE; + bool xou = FALSE , zou = FALSE; - lineHead = lineCurr = NULL; + /* the logic: if x & z used in the instruction + then we are in trouble otherwise */ - /* if debug information required */ -/* if (options.debug && currFunc) { */ - if (currFunc) { - cdbSymbol(currFunc,cdbFile,FALSE,TRUE); - _G.debugLine = 1; - if (IS_STATIC(currFunc->etype)) - emitcode("","F%s$%s$0$0 ==.",moduleName,currFunc->name); + /* first check if x & z are used by this + instruction, in which case we are in trouble */ + if ((xiu = bitVectBitValue(ic->rUsed,X_IDX)) && + (ziu = bitVectBitValue(ic->rUsed,Z_IDX))) + { + goto endOfWorld; + } + + xou = bitVectBitValue(ic->rMask,X_IDX); + zou = bitVectBitValue(ic->rMask,Z_IDX); + + /* if no usage of Z then return it */ + if (!ziu && !zou) { + ic->rUsed = bitVectSetBit(ic->rUsed,Z_IDX); + (*aopp)->type = AOP_Z; + + (*aopp)->aop_ptr2 = avr_regWithIdx(R31_IDX); + return (*aopp)->aopu.aop_ptr = avr_regWithIdx(R30_IDX); + } + + /* if no usage of X then return it */ + if (!xiu && !xou && !zonly) { + ic->rUsed = bitVectSetBit(ic->rUsed,X_IDX); + (*aopp)->type = AOP_X; + + (*aopp)->aop_ptr2 = avr_regWithIdx(R27_IDX); + return (*aopp)->aopu.aop_ptr = avr_regWithIdx(R26_IDX); + } + + /* if z not used then */ + + if (!ziu) { + /* push it if not already pushed */ + if (!_G.zPushed) { + emitcode ("push","%s", + avr_regWithIdx(R30_IDX)->dname); + emitcode ("push","%s", + avr_regWithIdx(R31_IDX)->dname); + _G.zPushed++ ; + } + + ic->rUsed = bitVectSetBit(ic->rUsed,Z_IDX); + (*aopp)->type = AOP_Z; + (*aopp)->aop_ptr2 = avr_regWithIdx(R31_IDX); + return (*aopp)->aopu.aop_ptr = avr_regWithIdx(R30_IDX); + } + + /* now we know they both have usage */ + /* if x not used in this instruction */ + if (!xiu && !zonly) { + /* push it if not already pushed */ + if (!_G.xPushed) { + emitcode ("push","%s", + avr_regWithIdx(R26_IDX)->dname); + emitcode ("push","%s", + avr_regWithIdx(R27_IDX)->dname); + _G.xPushed++ ; + } + + ic->rUsed = bitVectSetBit(ic->rUsed,X_IDX); + (*aopp)->type = AOP_X; + + (*aopp)->aop_ptr2 = avr_regWithIdx(R27_IDX); + return (*aopp)->aopu.aop_ptr = avr_regWithIdx(R26_IDX); + } + + +endOfWorld : + /* I said end of world but not quite end of world yet */ + /* if this is a result then we can push it on the stack*/ + if (result) { + (*aopp)->type = AOP_STK; + return NULL; + } + + piCode(ic,stdout); + /* other wise this is true end of the world */ + werror(E_INTERNAL_ERROR,__FILE__,__LINE__, + "getFreePtr should never reach here"); + exit(0); +} + +/*-----------------------------------------------------------------*/ +/* newAsmop - creates a new asmOp */ +/*-----------------------------------------------------------------*/ +static asmop *newAsmop (short type) +{ + asmop *aop; + + ALLOC(aop,sizeof(asmop)); + aop->type = type; + return aop; +} + +/*-----------------------------------------------------------------*/ +/* pointerCode - returns the code for a pointer type */ +/*-----------------------------------------------------------------*/ +static int pointerCode (link *etype) +{ + + return PTR_TYPE(SPEC_OCLS(etype)); + +} + +/*-----------------------------------------------------------------*/ +/* aopForSym - for a true symbol */ +/*-----------------------------------------------------------------*/ +static asmop *aopForSym (iCode *ic,symbol *sym,bool result) +{ + asmop *aop; + memmap *space= SPEC_OCLS(sym->etype); + + /* if already has one */ + if (sym->aop) + return sym->aop; + + /* assign depending on the storage class */ + /* if it is on the stack */ + if (sym->onStack) { + sym->aop = aop = newAsmop(0); + aop->size = getSize(sym->type); + + /* we can use std / ldd instruction */ + if (sym->stack > 0 && (sym->stack + getSize(sym->type) - 1) <= 63) { + aop->type = AOP_STK_D; + aop->aopu.aop_stk = sym->stack; + return aop; + } + + /* otherwise get a free pointer register X/Z */ + aop->aopu.aop_ptr = getFreePtr(ic,&aop,result,FALSE); + + /* now assign the address of the variable to + the pointer register */ + if (aop->type != AOP_STK) { + emitcode("movw","%s,r28",aop->aopu.aop_ptr->name); + if (sym->stack < 0) { + if ((sym->stack - _G.nRegsSaved) > -63) { + emitcode("sbiw","%s,0x%02x", + aop->aopu.aop_ptr->name, + (sym->stack - _G.nRegsSaved)); + } else { + emitcode("subi","%s,lo8(%d)", aop->aopu.aop_ptr->name, + sym->stack - _G.nRegsSaved); + emitcode("sbci","%s,hi8(%d)",aop->aop_ptr2->name, + sym->stack - _G.nRegsSaved); + } + } else { + if (sym->stack <= 63) { + emitcode("adiw","%s,0x%02x",aop->aopu.aop_ptr->name,sym->stack); + } else { + emitcode("subi","%s,lo8(-%d)",aop->aopu.aop_ptr->name,sym->stack); + emitcode("sbci","%s,hi8(-%d)",aop->aop_ptr2->name,sym->stack); + } + } + } + return aop; + } + + /* if in bit space */ + if (IN_BITSPACE(space)) { + sym->aop = aop = newAsmop (AOP_CRY); + aop->aopu.aop_dir = sym->rname ; + aop->size = getSize(sym->type); + return aop; + } + /* if it is in direct space */ + if (IN_DIRSPACE(space)) { + sym->aop = aop = newAsmop (AOP_DIR); + aop->aopu.aop_dir = sym->rname ; + aop->size = getSize(sym->type); + return aop; + } + + /* special case for a function */ + if (IS_FUNC(sym->type)) { + sym->aop = aop = newAsmop(AOP_IMMD); + ALLOC_ATOMIC(aop->aopu.aop_immd,strlen(sym->rname)+1); + strcpy(aop->aopu.aop_immd,sym->rname); + aop->size = FPTRSIZE; + return aop; + } + + /* only remaining is code / eeprom which will need pointer reg */ + /* if it is in code space */ + if (IN_CODESPACE(space)) + aop->code = 1; + + sym->aop = aop = newAsmop(0); + aop->aopu.aop_ptr = getFreePtr(ic,&aop,result,aop->code); + aop->size = getSize(sym->type); + emitcode ("ldi","%s,lo8(%s)",aop->aopu.aop_ptr->name,sym->rname); + emircode ("ldi","%s,hi8(%s)",aop->aop_ptr2); + + return aop; +} + +/*-----------------------------------------------------------------*/ +/* aopForRemat - rematerialzes an object */ +/*-----------------------------------------------------------------*/ +static asmop *aopForRemat (symbol *sym) +{ + iCode *ic = sym->rematiCode; + asmop *aop = newAsmop(AOP_IMMD); + int val = 0; + + for (;;) { + if (ic->op == '+') + val += operandLitValue(IC_RIGHT(ic)); + else if (ic->op == '-') + val -= operandLitValue(IC_RIGHT(ic)); else - emitcode("","G$%s$0$0 ==.",currFunc->name); - _G.debugLine = 0; + break; + + ic = OP_SYMBOL(IC_LEFT(ic))->rematiCode; } - - for (ic = lic ; ic ; ic = ic->next ) { - piCode(ic,stdout); + + if (val) + sprintf(buffer,"(%s %c 0x%04x)", + OP_SYMBOL(IC_LEFT(ic))->rname, + val >= 0 ? '+' : '-', + abs(val) & 0xffff); + else + strcpy(buffer,OP_SYMBOL(IC_LEFT(ic))->rname); + + ALLOC_ATOMIC(aop->aopu.aop_immd,strlen(buffer)+1); + strcpy(aop->aopu.aop_immd,buffer); + return aop; +} + +/*-----------------------------------------------------------------*/ +/* regsInCommon - two operands have some registers in common */ +/*-----------------------------------------------------------------*/ +static bool regsInCommon (operand *op1, operand *op2) +{ + symbol *sym1, *sym2; + int i; + + /* if they have registers in common */ + if (!IS_SYMOP(op1) || !IS_SYMOP(op2)) + return FALSE ; + + sym1 = OP_SYMBOL(op1); + sym2 = OP_SYMBOL(op2); + + if (sym1->nRegs == 0 || sym2->nRegs == 0) + return FALSE ; + + for (i = 0 ; i < sym1->nRegs ; i++) { + int j; + if (!sym1->regs[i]) + continue ; + + for (j = 0 ; j < sym2->nRegs ;j++ ) { + if (!sym2->regs[j]) + continue ; + + if (sym2->regs[j] == sym1->regs[i]) + return TRUE ; + } + } + + return FALSE ; +} + +/*-----------------------------------------------------------------*/ +/* operandsEqu - equivalent */ +/*-----------------------------------------------------------------*/ +static bool operandsEqu ( operand *op1, operand *op2) +{ + symbol *sym1, *sym2; + + /* if they not symbols */ + if (!IS_SYMOP(op1) || !IS_SYMOP(op2)) + return FALSE; + + sym1 = OP_SYMBOL(op1); + sym2 = OP_SYMBOL(op2); + + /* if both are itemps & one is spilt + and the other is not then false */ + if (IS_ITEMP(op1) && IS_ITEMP(op2) && + sym1->isspilt != sym2->isspilt ) + return FALSE ; + + /* if they are the same */ + if (sym1 == sym2) + return TRUE ; + + if (strcmp(sym1->rname,sym2->rname) == 0) + return TRUE; + + + /* if left is a tmp & right is not */ + if (IS_ITEMP(op1) && + !IS_ITEMP(op2) && + sym1->isspilt && + (sym1->usl.spillLoc == sym2)) + return TRUE; + + if (IS_ITEMP(op2) && + !IS_ITEMP(op1) && + sym2->isspilt && + sym1->level > 0 && + (sym2->usl.spillLoc == sym1)) + return TRUE ; + + return FALSE ; +} + +/*-----------------------------------------------------------------*/ +/* sameRegs - two asmops have the same registers */ +/*-----------------------------------------------------------------*/ +static bool sameRegs (asmop *aop1, asmop *aop2 ) +{ + int i; + + if (aop1 == aop2) + return TRUE ; + + if (aop1->type != AOP_REG || + aop2->type != AOP_REG ) + return FALSE ; + + if (aop1->size != aop2->size ) + return FALSE ; + + for (i = 0 ; i < aop1->size ; i++ ) + if (aop1->aopu.aop_reg[i] != + aop2->aopu.aop_reg[i] ) + return FALSE ; + + return TRUE ; +} + +/*-----------------------------------------------------------------*/ +/* isRegPair - for size 2 if this operand has a register pair */ +/*-----------------------------------------------------------------*/ +static int isRegPair (aop *aopp) +{ + if (!aop || aop->size != 2) return 0; + if (aop->type == AOP_X || aop->type == AOP_Y) return 1; + if (aop->type != AOP_REG) return 0; + if ((aop->aopu.aop_reg[1]->rIdx - + aop->aopu.aop_reg[0]->rIdx) == 1) return 1; + return 0; +} + +/*-----------------------------------------------------------------*/ +/* aopOp - allocates an asmop for an operand : */ +/*-----------------------------------------------------------------*/ +static void aopOp (operand *op, iCode *ic, bool result) +{ + asmop *aop; + symbol *sym; + int i; + + if (!op) + return ; + + /* if this a literal */ + if (IS_OP_LITERAL(op)) { + op->aop = aop = newAsmop(AOP_LIT); + aop->aopu.aop_lit = op->operand.valOperand; + aop->size = getSize(operandType(op)); + return; + } + + /* if already has a asmop then continue */ + if (op->aop) + return ; + + /* if the underlying symbol has a aop */ + if (IS_SYMOP(op) && OP_SYMBOL(op)->aop) { + op->aop = OP_SYMBOL(op)->aop; + return; + } + + /* if this is a true symbol */ + if (IS_TRUE_SYMOP(op)) { + op->aop = aopForSym(ic,OP_SYMBOL(op),result); + return ; + } + + /* this is a temporary : this has + only four choices : + a) register + b) spillocation + c) rematerialize + d) conditional + e) can be a return use only */ + + sym = OP_SYMBOL(op); + + + /* if the type is a conditional */ + if (sym->regType == REG_CND) { + aop = op->aop = sym->aop = newAsmop(AOP_CRY); + aop->size = 0; + return; + } + + /* if it is spilt then two situations + a) is rematerialize + b) has a spill location */ + if (sym->isspilt || sym->nRegs == 0) { + + /* rematerialize it NOW */ + if (sym->remat) { + sym->aop = op->aop = aop = + aopForRemat (sym); + aop->size = getSize(sym->type); + return; + } + + if (sym->accuse) { + assert("ACC_USE cannot happen in AVR\n"); + } + + if (sym->ruonly ) { + int i; + aop = op->aop = sym->aop = newAsmop(AOP_STR); + aop->size = getSize(sym->type); + for ( i = 0 ; i < fReturnSize ; i++ ) + aop->aopu.aop_str[i] = fReturn[i]; + return; + } + + /* else spill location */ + sym->aop = op->aop = aop = + aopForSym(ic,sym->usl.spillLoc,result); + aop->size = getSize(sym->type); + return; + } + + /* must be in a register */ + sym->aop = op->aop = aop = newAsmop(AOP_REG); + aop->size = sym->nRegs; + for ( i = 0 ; i < sym->nRegs ;i++) + aop->aopu.aop_reg[i] = sym->regs[i]; +} + +/*-----------------------------------------------------------------*/ +/* freeAsmop - free up the asmop given to an operand */ +/*----------------------------------------------------------------*/ +static void freeAsmop (operand *op, asmop *aaop, iCode *ic, bool pop) +{ + asmop *aop ; + + if (!op) + aop = aaop; + else + aop = op->aop; + + if (!aop) + return ; + + if (aop->freed) + goto dealloc; + + aop->freed = 1; + + /* depending on the asmop type only three cases need work AOP_RO + , AOP_R1 && AOP_STK */ + switch (aop->type) { + case AOP_X : + if (_G.xPushed ) { + if (pop) { + emitcode ("pop","r26"); + emitcode ("pop","r27"); + _G.xPushed--; + } + } + bitVectUnSetBit(ic->rUsed,X_IDX); + break; + + case AOP_Z : + if (_G.zPushed ) { + if (pop) { + emitcode ("pop","r30"); + emitcode ("pop","r31"); + _G.zPushed--; + } + } + bitVectUnSetBit(ic->rUsed,Z_IDX); + break; + + case AOP_STK : + { + int sz = aop->size; + int stk = aop->aopu.aop_stk + aop->size; + bitVectUnSetBit(ic->rUsed,X_IDX); + bitVectUnSetBit(ic->rUsed,Z_IDX); + + getFreePtr(ic,&aop,FALSE,0); + + emitcode ("movw","%s,r28"); + if (stk) { + if (stk <= 63 && stk > 0) { + emitcode ("adiw","%s,0x%02x",aop->aopu.aop_ptr->name,stk+1); + } else { + emitcode ("subi","%s,lo8(%d)",aop->aopu.aop_ptr->name,-(stk+1)); + emitcode ("sbci","%s,hi8(%d)",aop->aop_ptr2->name,-(stk+1)); + } + } + + while (sz--) { + emitcode("pop","r24"); + emitcode("st","-%s,r24",aop->type == AOP_X ? "X" : "Z"); + if (!sz) break; + } + op->aop = aop; + freeAsmop(op,NULL,ic,TRUE); + if (_G.xPushed) { + emitcode("pop","r26"); + emitcode("pop","r27"); + _G.xPushed--; + } + + if (_G.zPushed) { + emitcode("pop","r30"); + emitcode("pop","r31"); + _G.zPushed--; + } + } + } + +dealloc: + /* all other cases just dealloc */ + if (op ) { + op->aop = NULL; + if (IS_SYMOP(op)) { + OP_SYMBOL(op)->aop = NULL; + /* if the symbol has a spill */ + if (SPIL_LOC(op)) + SPIL_LOC(op)->aop = NULL; + } + } +} + +/*-----------------------------------------------------------------*/ +/* aopGet - for fetching value of the aop */ +/*-----------------------------------------------------------------*/ +static char *aopGet (asmop *aop, int offset) +{ + char *s = buffer ; + char *rs; + + /* offset is greater than + size then zero */ + if (offset > (aop->size - 1) && + aop->type != AOP_LIT) + return zero; + + /* depending on type */ + switch (aop->type) { + + case AOP_X: + if (offset > aop->coff) { + emitcode ("adiw","%s,%d",aop->aopu.aop_ptr->name,offset - aop->coff); + } + + if (offset < aop->coff) { + emitcode("sbiw","%s,%d",aop->aopu.aop_ptr->name,aop->coff - offset); + } + + aop->coff = offset ; + emitcode("ld","%s,x", + (rs = ((offset & 1) ? "r25" : "r24"))); + return rs; + + case AOP_Z: + if (aop->code) { + if (offset > aop->coff) { + emitcode("adiw","r30,%d",offset - aop->coff); + } else { + emitcode("sbiw","r30,%d",aop->coff - offset); + } + emitcode("lpm","%s,z",(rs = ((offset & 1) ? "r25" : "r24"))); + } else { + /* we can use lds */ + if (offset > aop->coff) { + emitcode ("ldd","%s,z+%d",(rs = ((offset & 1) ? "r25" : "r24")), + offset - aop->coff); + } else { + emitcode("sbiw","%s,%d",aop->aopu.aop_ptr->name,aop->coff - offset); + aop->coff = offset; + emitcode ("ld","%s,z",(rs = ((offset & 1) ? "r25" : "r24"))); + } + } + return rs; + + case AOP_IMMD: + + emitcode ("lds","%s,(%s)+%d", + (rs = ((offset & 1) ? "r25" : "r24")), + aop->aopu.aop_immd, offset); + return rs; + + case AOP_DIR: + emitcode ("lds","%s,(%s)+%d", + (rs = ((offset & 1) ? "r25" : "r24")), + aop->aopu.aop_dir, offset); + return rs; + + case AOP_REG: + return aop->aopu.aop_reg[offset]->name; + + case AOP_CRY: + assert("cannot be in bit space AOP_CRY\n"); + break; + + case AOP_LIT: + s = aopLiteral(aop->aopu.aop_lit,offset); + emitcode("ldi","%s,lo8(%s)",(rs = ((offset & 1)?"r24" : "r25")),s); + return rs; + + case AOP_STR: + aop->coff = offset ; + return aop->aopu.aop_str[offset]; + + case AOP_STK_D: + emitcode ("ldd","%s,Y+%d", + (rs = ((offset & 1) ? "r25" : "r24")), + aop->aopu.aop_stk+offset); + return rs; + } + + werror(E_INTERNAL_ERROR,__FILE__,__LINE__, + "aopget got unsupported aop->type"); + exit(0); +} +/*-----------------------------------------------------------------*/ +/* aopPut - puts a string for a aop */ +/*-----------------------------------------------------------------*/ +static void aopPut (asmop *aop, char *s, int offset) +{ + char *d = buffer ; + symbol *lbl ; + + if (aop->size && offset > ( aop->size - 1)) { + werror(E_INTERNAL_ERROR,__FILE__,__LINE__, + "aopPut got offset > aop->size"); + exit(0); + } + + /* will assign value to value */ + /* depending on where it is ofcourse */ + switch (aop->type) { + case AOP_DIR: + if (offset) { + sprintf(d,"(%s)+%d", aop->aopu.aop_dir,offset); + } + else { + sprintf(d,"%s",aop->aopu.aop_dir); + } + + emitcode("sts","%s,%s",d,s); + break; + + case AOP_REG: + if (toupper(*s) != 'R') { + if (s == zero) { + emitcode("clr","%s",aop->aopu.aop_reg[offset]->name); + } else { + emitcode("ldi","r25,%s",s); + emitcode("mov","%s,r35",aop->aopu.aop_reg[offset]->name); + } + } else { + if (strcmp( aop->aopu.aop_reg[offset]->name,s)) { + emitcode("mov","%s,%s", aop->aopu.aop_reg[offset]->name,s); + } + } + break; + + case AOP_X: + if (offset > aop->coff) { + emitcode ("adiw","%s,%d",aop->aopu.aop_ptr->name,offset - aop->coff); + } + + if (offset < aop->coff) { + emitcode("sbiw","%s,%d",aop->aopu.aop_ptr->name,aop->coff - offset); + } + + aop->coff = offset ; + emitcode("st","x,%s", s); + break; + + case AOP_Z: + if (aop->code) { + if (offset > aop->coff) { + emitcode("adiw","r30,%d",offset - aop->coff); + } else { + emitcode("sbiw","r30,%d",aop->coff - offset); + } + emitcode("lpm","%s,z",s); + } else { + /* we can use lds */ + if (offset > aop->coff) { + emitcode ("sdd","z+%d,%s",offset - aop->coff,s); + } else { + emitcode("sbiw","%s,%d",aop->aopu.aop_ptr->name,aop->coff - offset); + aop->coff = offset; + emitcode ("ld","%s,z",s); + } + } + break; + + case AOP_STK: + emitcode("push","%s",s); + break; + + case AOP_CRY: + /* if bit variable */ + assert("bit variable cannot be AOP_CRY\n"); + break; + + case AOP_STR: + aop->coff = offset; + if (strcmp(aop->aopu.aop_str[offset],s)) + emitcode ("mov","%s,%s",aop->aopu.aop_str[offset],s); + break; + + case AOP_STK_D: + emitcode ("std","y+%d,%s",offset,s); + break; + + default : + werror(E_INTERNAL_ERROR,__FILE__,__LINE__, + "aopPut got unsupported aop->type"); + exit(0); + } + +} + + +#if 0 +/*-----------------------------------------------------------------*/ +/* pointToEnd :- points to the last byte of the operand */ +/*-----------------------------------------------------------------*/ +static void pointToEnd (asmop *aop) +{ + int count ; + if (!aop) + return ; + + aop->coff = count = (aop->size - 1); + switch (aop->type) { + case AOP_X : + case AOP_Z : + emitcode("adiw","%s,%d",aop->aopu.aop_ptr->name,count); + break; + } + +} +#endif + +/*-----------------------------------------------------------------*/ +/* reAdjustPreg - points a register back to where it should */ +/*-----------------------------------------------------------------*/ +static void reAdjustPreg (asmop *aop) +{ + int size ; + + aop->coff = 0; + if ((size = aop->size) <= 1) + return ; + size-- ; + switch (aop->type) { + case AOP_X : + case AOP_Z : + emitcode("sbiw","%s,%d",aop->aopu.aop_ptr->name,size); + break; + } + +} + +#define AOP(op) op->aop +#define AOP_TYPE(op) AOP(op)->type +#define AOP_SIZE(op) AOP(op)->size +#define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_X || \ + AOP_TYPE(x) == AOP_Z)) +#define AOP_INPREG(x) (x && (x->type == AOP_REG && \ + (x->aopu.aop_reg[0] == avr_regWithIdx(R26_IDX) || \ + x->aopu.aop_reg[0] == avr_regWithIdx(R30_IDX) ))) + +/*-----------------------------------------------------------------*/ +/* genNotFloat - generates not for float operations */ +/*-----------------------------------------------------------------*/ +static void genNotFloat (operand *op, operand *res) +{ + int size, offset; + char *l; + symbol *tlbl ; + + /* we will put 127 in the first byte of + the result */ + aopPut(AOP(res),"127",0); + size = AOP_SIZE(op) - 1; + offset = 1; + + l = aopGet(op->aop,offset++); + MOVR0(l); + + while(size--) { + emitcode("or","R0,%s", aopGet(op->aop, offset++); + } + tlbl = newiTempLabel(NULL); + + tlbl = newiTempLabel(NULL); + aopPut(res->aop,zero,1); + emitcode("cpi","r0,0"); + emitcode("breq","L%05d",tlbl->key); + aopPut(res->aop,one,1); + emitcode("","L%05d:",tlbl->key); + + size = res->aop->size - 2; + offset = 2; + /* put zeros in the rest */ + while (size--) + aopPut(res->aop,zero,offset++); +} + +/*-----------------------------------------------------------------*/ +/* opIsGptr: returns non-zero if the passed operand is */ +/* a generic pointer type. */ +/*-----------------------------------------------------------------*/ +static int opIsGptr(operand *op) +{ + link *type = operandType(op); + + if ((AOP_SIZE(op) == GPTRSIZE) && IS_GENPTR(type)) + { + return 1; + } + return 0; +} + +/*-----------------------------------------------------------------*/ +/* getDataSize - get the operand data size */ +/*-----------------------------------------------------------------*/ +static int getDataSize(operand *op) +{ + int size; + size = AOP_SIZE(op); + if (size == GPTRSIZE) + { + link *type = operandType(op); + if (IS_GENPTR(type)) + { + /* generic pointer; arithmetic operations + * should ignore the high byte (pointer type). + */ + size--; + } + } + return size; +} + +/*-----------------------------------------------------------------*/ +/* outAcc - output Acc */ +/*-----------------------------------------------------------------*/ +static void outAcc(operand *result) +{ + int size, offset; + size = getDataSize(result); + if(size){ + aopPut(AOP(result),"r0",0); + size--; + offset = 1; + /* unsigned or positive */ + while(size--){ + aopPut(AOP(result),zero,offset++); + } + } +} + +/*-----------------------------------------------------------------*/ +/* outBitC - output a bit C */ +/*-----------------------------------------------------------------*/ +static void outBitC(operand *result) +{ + emitcode("clr","r0"); + emitcode("rol","r0"); + outAcc(result); +} + +/*-----------------------------------------------------------------*/ +/* toBoolean - emit code for orl a,operator(sizeop) */ +/*-----------------------------------------------------------------*/ +static void toBoolean(operand *oper) +{ + int size = AOP_SIZE(oper) ; + int offset = 0; + emitcode ("clr","r0"); + while (size--) + emitcode("or","r0,%s",aopGet(AOP(oper),offset++,FALSE,FALSE)); +} + + +/*-----------------------------------------------------------------*/ +/* genNot - generate code for ! operation */ +/*-----------------------------------------------------------------*/ +static void genNot (iCode *ic) +{ + symbol *tlbl; + link *optype = operandType(IC_LEFT(ic)); + int size, offset = 1; + + /* assign asmOps to operand & result */ + aopOp (IC_LEFT(ic),ic,FALSE); + aopOp (IC_RESULT(ic),ic,TRUE); + + /* if type float then do float */ + if (IS_FLOAT(optype)) { + genNotFloat(IC_LEFT(ic),IC_RESULT(ic)); + goto release; + } + emitcode("clr","r24"); + tlbl = newiTempLabel(NULL); + toBoolean(IC_LEFT(ic)); + emitcode("bne","L%05d",tlbl->key); + emitcode("ldi","r24,1"); + emitcode("","L%05d:",tlbl->key); + aopPut(AOP(IC_RESULT(ic)),"r24",0); + size = AOP_SIZE(IC_RESULT(ic)) -1; + while (size--) aopPut(AOP(IC_RESULT(ic)),zero,offset++); + + +release: + /* release the aops */ + freeAsmop(IC_LEFT(ic),NULL,ic,(RESULTONSTACK(ic) ? 0 : 1)); + freeAsmop(IC_RESULT(ic),NULL,ic,TRUE); +} + + +/*-----------------------------------------------------------------*/ +/* genCpl - generate code for complement */ +/*-----------------------------------------------------------------*/ +static void genCpl (iCode *ic) +{ + int offset = 0; + int size ; + int samer; + + /* assign asmOps to operand & result */ + aopOp (IC_LEFT(ic),ic,FALSE); + aopOp (IC_RESULT(ic),ic,TRUE); + samer = sameRegs(AOP(IC_LEFT(ic),AOP(IC_RESULT(ic)))); + size = AOP_SIZE(IC_RESULT(ic)); + while (size--) { + char *l = aopGet(AOP(IC_LEFT(ic)),offset); + if (samer) { + emitcode ("com","%s",l); + } else { + aopPut(AOP(IC_RESULT(ic)),l,offset); + emitcode ("com","%s",aopGet(AOP(IC_RESULT(ic)),offset++)); + } + } + + +release: + /* release the aops */ + freeAsmop(IC_LEFT(ic),NULL,ic,(RESULTONSTACK(ic) ? 0 : 1)); + freeAsmop(IC_RESULT(ic),NULL,ic,TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genUminusFloat - unary minus for floating points */ +/*-----------------------------------------------------------------*/ +static void genUminusFloat(operand *op,operand *result) +{ + int size ,offset =0 ; + char *l; + /* for this we just need to flip the + first it then copy the rest in place */ + size = AOP_SIZE(op) - 1; + l = aopGet(AOP(op),3,FALSE,FALSE); + + emitcode("ldi","r24,0x80"); + if (sameRegs(AOP(op),AOP(result))) { + emitcode("eor","%s,r24",l); + } else { + aopPut(AOP(result),l,3); + emitcode("eor","%s,r24",aopGet(AOP(result),3)); + } + while(size--) { + aopPut(AOP(result), + aopGet(AOP(op),offset,FALSE,FALSE), + offset); + offset++; + } +} + +/*-----------------------------------------------------------------*/ +/* genUminus - unary minus code generation */ +/*-----------------------------------------------------------------*/ +static void genUminus (iCode *ic) +{ + int offset ,size ; + link *optype, *rtype; + int samer ; + + /* assign asmops */ + aopOp(IC_LEFT(ic),ic,FALSE); + aopOp(IC_RESULT(ic),ic,TRUE); + + optype = operandType(IC_LEFT(ic)); + rtype = operandType(IC_RESULT(ic)); + + /* if float then do float stuff */ + if (IS_FLOAT(optype)) { + genUminusFloat(IC_LEFT(ic),IC_RESULT(ic)); + goto release; + } + + /* otherwise subtract from zero */ + size = AOP_SIZE(IC_LEFT(ic)); + offset = 0 ; + samer = sameRegs(AOP(IC_LEFT(ic)),AOP(IC_RESULT(ic))); + CLRC; + while(size--) { + char *l = aopGet(AOP(IC_LEFT(ic)),offset); + if (samer) { + emitcode("clr","r0"); + emitcode("sbc","r0,%s",l); + aopPut(AOP(IC_RESULT(ic)),"r0",offset++); + } else { + char *s; + emitcode("clr","%s",s=aopGet(IC_RESULT(ic),offset++)); + emitcode("sbc","%s,%s",s,l); + } + } + + /* if any remaining bytes in the result */ + /* we just need to propagate the sign */ + if ((size = (AOP_SIZE(IC_RESULT(ic)) - AOP_SIZE(IC_LEFT(ic))))) { + symbol *tlbl = newiTempLabel(NULL); + emitcode("clr","r0"); + emitcode("brcc","L%05d",tlbl->key); + emitcode("com","r0"); + emitcode("","L%05d:",tlbl->key); + while (size--) + aopPut(AOP(IC_RESULT(ic)),"r0",offset++); + } + +release: + /* release the aops */ + freeAsmop(IC_LEFT(ic),NULL,ic,(RESULTONSTACK(ic) ? 0 : 1)); + freeAsmop(IC_RESULT(ic),NULL,ic,TRUE); +} + +/*-----------------------------------------------------------------*/ +/* assignResultValue - */ +/*-----------------------------------------------------------------*/ +static void assignResultValue(operand * oper) +{ + int offset = 0; + int size = AOP_SIZE(oper); + while (size--) { + aopPut(AOP(oper),fReturn[offset],offset); + offset++; + } +} + +/*-----------------------------------------------------------------*/ +/* saveZreg - if indirect call then save z-pointer register */ +/*-----------------------------------------------------------------*/ +static void saveZreg (iCode *ic) +{ + /* only if live accross this call */ + if (ic->regSaved == 0 && + (bitVectBitValue(ic->rMask,R30_IDX) || + bitVectBitValue(ic->rMask,R31_IDX))) { + ic->regsSaved = 1; + emitcode("push","r30"); + emitcode("push","r31"); + } +} + +/*-----------------------------------------------------------------*/ +/* popZreg - restore values of zreg */ +/*-----------------------------------------------------------------*/ +static void popZreg (iCode *ic) +{ + if (ic->regsSaved) { + emitcode ("pop","r31"); + emitcode ("pop","r30"); + } +} + +/*-----------------------------------------------------------------*/ +/* genIpush - genrate code for pushing this gets a little complex */ +/*-----------------------------------------------------------------*/ +static void genIpush (iCode *ic) +{ + int size, offset = 0 ; + char *l; + + + if (!ic->parmPush) { + /* and the item is spilt then do nothing */ + if (OP_SYMBOL(IC_LEFT(ic))->isspilt) + return ; + } else { + iCode *lic ; + for (lic = ic->next ; lic ; lic = lic->next) + if (lic->op == PCALL) break; + if (lic) saveZreg(lic); + } + + /* this is a paramter push */ + aopOp(IC_LEFT(ic),ic,FALSE); + size = AOP_SIZE(IC_LEFT(ic)); + while (size--) { + l = aopGet(AOP(IC_LEFT(ic)),offset++,FALSE,TRUE); + emitcode("push","%s",l); + } + + freeAsmop(IC_LEFT(ic),NULL,ic,TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genIpop - recover the registers: can happen only for spilling */ +/*-----------------------------------------------------------------*/ +static void genIpop (iCode *ic) +{ + int size,offset ; + + + /* if the temp was not pushed then */ + if (OP_SYMBOL(IC_LEFT(ic))->isspilt) + return ; + + aopOp(IC_LEFT(ic),ic,FALSE); + size = AOP_SIZE(IC_LEFT(ic)); + offset = (size-1); + while (size--) + emitcode("pop","%s",aopGet(AOP(IC_LEFT(ic)),offset--, + FALSE,TRUE)); + + freeAsmop(IC_LEFT(ic),NULL,ic,TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genCall - generates a call statement */ +/*-----------------------------------------------------------------*/ +static void genCall (iCode *ic) +{ + link *detype; + + /* if send set is not empty the assign */ + if (_G.sendSet) { + iCode *sic ; + + for (sic = setFirstItem(_G.sendSet) ; sic ; + sic = setNextItem(_G.sendSet)) { + int size, offset = 0; + aopOp(IC_LEFT(sic),sic,FALSE); + size = AOP_SIZE(IC_LEFT(sic)); + while (size--) { + char *l = aopGet(AOP(IC_LEFT(sic)),offset, + FALSE,FALSE); + if (strcmp(l,fReturn[offset])) + emitcode("mov","%s,%s", + fReturn[offset], + l); + offset++; + } + freeAsmop (IC_LEFT(sic),NULL,sic,TRUE); + } + _G.sendSet = NULL; + } + /* make the call */ + emitcode("call","%s",(OP_SYMBOL(IC_LEFT(ic))->rname[0] ? + OP_SYMBOL(IC_LEFT(ic))->rname : + OP_SYMBOL(IC_LEFT(ic))->name)); + + /* if we need assign a result value */ + if ((IS_ITEMP(IC_RESULT(ic)) && + (OP_SYMBOL(IC_RESULT(ic))->nRegs || + OP_SYMBOL(IC_RESULT(ic))->spildir )) || + IS_TRUE_SYMOP(IC_RESULT(ic)) ) { + + aopOp(IC_RESULT(ic),ic,FALSE); + assignResultValue(IC_RESULT(ic)); + freeAsmop(IC_RESULT(ic),NULL, ic,TRUE); + } + + /* adjust the stack for parameters if required */ + if (IC_LEFT(ic)->parmBytes) { + if (IC_LEFT(ic)->parmBytes > 63) { + emitcode("sbiw","r28,%d",IC_LEFT(ic)->parmBytes); + } else { + emitcode("subi","r28,lo8(%d)",IC_LEFT(ic)->parmBytes); + emitcode("sbci","r29,hi8(%d)",IC_LEFT(ic)->parmBytes); + } + } + +} + +/*-----------------------------------------------------------------*/ +/* genPcall - generates a call by pointer statement */ +/*-----------------------------------------------------------------*/ +static void genPcall (iCode *ic) +{ + link *detype; + + if (!ic->regsSaved) saveZreg(ic); + + aopOp(IC_LEFT(ic),ic,FALSE); + emitcode("mov","r30",aopGet(AOP(IC_LEFT(ic)),0)); + emitcode("mov","r31",aopGet(AOP(IC_RIGHT(ic)),0)); + freeAsmop(IC_LEFT(ic),NULL,ic,TRUE); + + /* if send set is not empty the assign */ + if (_G.sendSet) { + iCode *sic ; + + for (sic = setFirstItem(_G.sendSet) ; sic ; + sic = setNextItem(_G.sendSet)) { + int size, offset = 0; + aopOp(IC_LEFT(sic),sic,FALSE); + size = AOP_SIZE(IC_LEFT(sic)); + while (size--) { + char *l = aopGet(AOP(IC_LEFT(sic)),offset, + FALSE,FALSE); + if (strcmp(l,fReturn[offset])) + emitcode("mov","%s,%s", + fReturn[offset], + l); + offset++; + } + freeAsmop (IC_LEFT(sic),NULL,sic,TRUE); + } + _G.sendSet = NULL; + } + + emitcode("icall",""); + + /* if we need assign a result value */ + if ((IS_ITEMP(IC_RESULT(ic)) && + (OP_SYMBOL(IC_RESULT(ic))->nRegs || + OP_SYMBOL(IC_RESULT(ic))->spildir)) || + IS_TRUE_SYMOP(IC_RESULT(ic)) ) { + + aopOp(IC_RESULT(ic),ic,FALSE); + + assignResultValue(IC_RESULT(ic)); + freeAsmop(IC_RESULT(ic),NULL,ic,TRUE); + } + + /* adjust the stack for parameters if + required */ + if (IC_LEFT(ic)->parmBytes) { + int i; + if (IC_LEFT(ic)->parmBytes > 3) { + emitcode("mov","a,%s",spname); + emitcode("add","a,#0x%02x", (- IC_LEFT(ic)->parmBytes) & 0xff); + emitcode("mov","%s,a",spname); + } else + for ( i = 0 ; i < IC_LEFT(ic)->parmBytes ;i++) + emitcode("dec","%s",spname); + + } + + /* adjust the stack for parameters if required */ + if (IC_LEFT(ic)->parmBytes) { + if (IC_LEFT(ic)->parmBytes > 63) { + emitcode("sbiw","r28,%d",IC_LEFT(ic)->parmBytes); + } else { + emitcode("subi","r28,lo8(%d)",IC_LEFT(ic)->parmBytes); + emitcode("sbci","r29,hi8(%d)",IC_LEFT(ic)->parmBytes); + } + } + if (ic->regsSaved) popZregs(ic); +} + +/*-----------------------------------------------------------------*/ +/* resultRemat - result is rematerializable */ +/*-----------------------------------------------------------------*/ +static int resultRemat (iCode *ic) +{ + if (SKIP_IC(ic) || ic->op == IFX) + return 0; + + if (IC_RESULT(ic) && IS_ITEMP(IC_RESULT(ic))) { + symbol *sym = OP_SYMBOL(IC_RESULT(ic)); + if (sym->remat && !POINTER_SET(ic)) + return 1; + } + + return 0; +} + +#ifdef __BORLANDC__ +#define STRCASECMP stricmp +#else +#define STRCASECMP strcasecmp +#endif + +/*-----------------------------------------------------------------*/ +/* inExcludeList - return 1 if the string is in exclude Reg list */ +/*-----------------------------------------------------------------*/ +static bool inExcludeList(char *s) +{ + int i =0; + + if (options.excludeRegs[i] && + STRCASECMP(options.excludeRegs[i],"none") == 0) + return FALSE ; + + for ( i = 0 ; options.excludeRegs[i]; i++) { + if (options.excludeRegs[i] && + STRCASECMP(s,options.excludeRegs[i]) == 0) + return TRUE; + } + return FALSE ; +} + +/*-----------------------------------------------------------------*/ +/* genFunction - generated code for function entry */ +/*-----------------------------------------------------------------*/ +static void genFunction (iCode *ic) +{ + symbol *sym; + link *fetype; + int i = 0; + + _G.nRegsSaved = 0; + /* create the function header */ + emitcode(";","-----------------------------------------"); + emitcode(";"," function %s",(sym = OP_SYMBOL(IC_LEFT(ic)))->name); + emitcode(";","-----------------------------------------"); + + emitcode("","%s:",sym->rname); + fetype = getSpec(operandType(IC_LEFT(ic))); + + /* if critical function then turn interrupts off */ + if (SPEC_CRTCL(fetype)) + emitcode("cli"); + + if (IS_ISR(sym->etype)) { + } + + /* save the preserved registers that are used in this function */ + for (i = R2_IDX ; i <= R15_IDX ; i++ ) { + if (bitVectBitValue(sym->regsUsed,i)) { + _G.nRegsSaved++; + emitcode("push","%s",avr_regWithIdx(i)->name); + } + } + /* now for the pointer registers */ + if (bitVectBitValue(sym->regsUsed,R26_IDX)) { + _G.nRegsSaved++; + emitcode("push","r26"); + } + if (bitVectBitValue(sym->regsUsed,R27_IDX)) { + _G.nRegsSaved++; + emitcode("push","r27"); + } + if (bitVectBitValue(sym->regsUsed,R30_IDX)) { + _G.nRegsSaved++; + emitcode("push","r30"); + } + if (bitVectBitValue(sym->regsUsed,R31_IDX)) { + _G.nRegsSaved++; + emitcode("push","r31"); + } + /* adjust the stack for the function */ + if (sym->stack) { + emitcode ("push","r28"); + emitcode ("push","r29"); + emitcode ("in","r28,__SP_L__"); + emitcode ("in","r29,__SP_H__"); + emitcode ("movw","r24,r28"); + if (sym->stack <= 63) { + emitcode("sbiw","r24,%d",sym->stack); + } else { + emitcode ("subi","r24,lo8(%d)",sym->stack); + emitcode ("sbci","r25,hi8(%d)",sym->stack); + } + emitcode("out","__SP_L__,r24"); + emitcode("out","__SP_H__,r25"); + } +} + +/*-----------------------------------------------------------------*/ +/* genEndFunction - generates epilogue for functions */ +/*-----------------------------------------------------------------*/ +static void genEndFunction (iCode *ic) +{ + symbol *sym = OP_SYMBOL(IC_LEFT(ic)); + + /* restore stack pointer */ + emitcode("out","__SP_L__,r28"); + emitcode("out","__SP_H__,r29"); + + /* pop frame pointer */ + emitcode ("pop","r29"); + emitcode ("pop","r28"); + + /* restore preserved registers */ + if (bitVectBitValue(sym->regsUsed,R31_IDX)) { + _G.nRegsSaved--; + emitcode("pop","r31"); + } + if (bitVectBitValue(sym->regsUsed,R30_IDX)) { + _G.nRegsSaved--; + emitcode("pop","r30"); + } + if (bitVectBitValue(sym->regsUsed,R27_IDX)) { + _G.nRegsSaved--; + emitcode("push","r27"); + } + if (bitVectBitValue(sym->regsUsed,R26_IDX)) { + _G.nRegsSaved--; + emitcode("push","r26"); + } + for (i = R15_IDX ; i >= R2_IDX ; i-- ) { + if (bitVectBitValue(sym->regsUsed,i)) { + _G.nRegsSaved--; + emitcode("pop","%s",avr_regWithIdx(i)->name); + } + } + + if (IS_ISR(sym->etype)) { + } + + if (SPEC_CRTCL(fetype)) + emitcode("sti"); +} + +/*-----------------------------------------------------------------*/ +/* genRet - generate code for return statement */ +/*-----------------------------------------------------------------*/ +static void genRet (iCode *ic) +{ + int size,offset = 0 , pushed = 0; + + /* if we have no return value then + just generate the "ret" */ + if (!IC_LEFT(ic)) + goto jumpret; + + /* we have something to return then + move the return value into place */ + aopOp(IC_LEFT(ic),ic,FALSE); + size = AOP_SIZE(IC_LEFT(ic)); + + while (size--) { + char *l ; + l = aopGet(AOP(IC_LEFT(ic)),offset, + FALSE,FALSE); + if (strcmp(fReturn[offset],l)) + emitcode("mov","%s,%s",fReturn[offset++],l); + } + + freeAsmop (IC_LEFT(ic),NULL,ic,TRUE); + + jumpret: + /* generate a jump to the return label + if the next is not the return statement */ + if (!(ic->next && ic->next->op == LABEL && + IC_LABEL(ic->next) == returnLabel)) + + emitcode("rjmp","L%05d",returnLabel->key); + +} + +/*-----------------------------------------------------------------*/ +/* genLabel - generates a label */ +/*-----------------------------------------------------------------*/ +static void genLabel (iCode *ic) +{ + /* special case never generate */ + if (IC_LABEL(ic) == entryLabel) + return ; + + emitcode("","L%05d:",IC_LABEL(ic)->key); +} + +/*-----------------------------------------------------------------*/ +/* genGoto - generates a ljmp */ +/*-----------------------------------------------------------------*/ +static void genGoto (iCode *ic) +{ + emitcode ("rjmp","L%05d:",(IC_LABEL(ic)->key+100)); +} + +/*-----------------------------------------------------------------*/ +/* findLabelBackwards: walks back through the iCode chain looking */ +/* for the given label. Returns number of iCode instructions */ +/* between that label and given ic. */ +/* Returns zero if label not found. */ +/*-----------------------------------------------------------------*/ +static int findLabelBackwards(iCode *ic, int key) +{ + int count = 0; + + while (ic->prev) + { + ic = ic->prev; + count++; + + if (ic->op == LABEL && IC_LABEL(ic)->key == key) + { + /* printf("findLabelBackwards = %d\n", count); */ + return count; + } + } + + return 0; +} + +/*-----------------------------------------------------------------*/ +/* genPlusIncr :- does addition with increment if possible */ +/*-----------------------------------------------------------------*/ +static bool genPlusIncr (iCode *ic) +{ + unsigned int icount ; + unsigned int size = getDataSize(IC_RESULT(ic)); + + /* will try to generate an increment */ + /* if the right side is not a literal + we cannot */ + if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT) + return FALSE ; + + /* if the literal value of the right hand side + is greater than 63 then it is not worth it */ + if ((icount = floatFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit)) > 63) + return FALSE ; + + /* if the sizes are greater than 2 or they are not the same regs + then we cannot */ + if (AOP_SIZE(IC_RESULT(ic)) > 2 || + AOP_SIZE(IC_LEFT(ic)) > 2 || + !sameRegs(AOP(IC_LEFT(ic)),AOP(IC_RIGHT(ic)))) + return FALSE ; + + + return FALSE ; +} + +/*-----------------------------------------------------------------*/ +/* outBitAcc - output a bit in acc */ +/*-----------------------------------------------------------------*/ +static void outBitAcc(operand *result) +{ + symbol *tlbl = newiTempLabel(NULL); + /* if the result is a bit */ + if (AOP_TYPE(result) == AOP_CRY){ + aopPut(AOP(result),"a",0); + } + else { + emitcode("jz","%05d$",tlbl->key+100); + emitcode("mov","a,%s",one); + emitcode("","%05d$:",tlbl->key+100); + outAcc(result); + } +} + +/*-----------------------------------------------------------------*/ +/* genPlusBits - generates code for addition of two bits */ +/*-----------------------------------------------------------------*/ +static void genPlusBits (iCode *ic) +{ + if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY){ + symbol *lbl = newiTempLabel(NULL); + emitcode("mov","c,%s",AOP(IC_LEFT(ic))->aopu.aop_dir); + emitcode("jnb","%s,%05d$",AOP(IC_RIGHT(ic))->aopu.aop_dir,(lbl->key+100)); + emitcode("cpl","c"); + emitcode("","%05d$:",(lbl->key+100)); + outBitC(IC_RESULT(ic)); + } + else{ + emitcode("clr","a"); + emitcode("mov","c,%s",AOP(IC_LEFT(ic))->aopu.aop_dir); + emitcode("rlc","a"); + emitcode("mov","c,%s",AOP(IC_RIGHT(ic))->aopu.aop_dir); + emitcode("addc","a,#0x00"); + outAcc(IC_RESULT(ic)); + } +} + +#if 0 +/* This is the original version of this code. + * + * This is being kept around for reference, + * because I am not entirely sure I got it right... + */ +static void adjustArithmeticResult(iCode *ic) +{ + if (AOP_SIZE(IC_RESULT(ic)) == 3 && + AOP_SIZE(IC_LEFT(ic)) == 3 && + !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic)))) + aopPut(AOP(IC_RESULT(ic)), + aopGet(AOP(IC_LEFT(ic)),2,FALSE,FALSE), + 2); + + if (AOP_SIZE(IC_RESULT(ic)) == 3 && + AOP_SIZE(IC_RIGHT(ic)) == 3 && + !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_RIGHT(ic)))) + aopPut(AOP(IC_RESULT(ic)), + aopGet(AOP(IC_RIGHT(ic)),2,FALSE,FALSE), + 2); + + if (AOP_SIZE(IC_RESULT(ic)) == 3 && + AOP_SIZE(IC_LEFT(ic)) < 3 && + AOP_SIZE(IC_RIGHT(ic)) < 3 && + !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))) && + !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_RIGHT(ic)))) { + char buffer[5]; + sprintf(buffer,"#%d",pointerCode(getSpec(operandType(IC_LEFT(ic))))); + aopPut(AOP(IC_RESULT(ic)),buffer,2); + } +} +#else +/* This is the pure and virtuous version of this code. + * I'm pretty certain it's right, but not enough to toss the old + * code just yet... + */ +static void adjustArithmeticResult(iCode *ic) +{ + if (opIsGptr(IC_RESULT(ic)) && + opIsGptr(IC_LEFT(ic)) && + !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic)))) + { + aopPut(AOP(IC_RESULT(ic)), + aopGet(AOP(IC_LEFT(ic)), GPTRSIZE - 1,FALSE,FALSE), + GPTRSIZE - 1); + } + + if (opIsGptr(IC_RESULT(ic)) && + opIsGptr(IC_RIGHT(ic)) && + !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_RIGHT(ic)))) + { + aopPut(AOP(IC_RESULT(ic)), + aopGet(AOP(IC_RIGHT(ic)),GPTRSIZE - 1,FALSE,FALSE), + GPTRSIZE - 1); + } + + if (opIsGptr(IC_RESULT(ic)) && + AOP_SIZE(IC_LEFT(ic)) < GPTRSIZE && + AOP_SIZE(IC_RIGHT(ic)) < GPTRSIZE && + !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))) && + !sameRegs(AOP(IC_RESULT(ic)),AOP(IC_RIGHT(ic)))) { + char buffer[5]; + sprintf(buffer,"#%d",pointerCode(getSpec(operandType(IC_LEFT(ic))))); + aopPut(AOP(IC_RESULT(ic)),buffer,GPTRSIZE - 1); + } +} +#endif + +/*-----------------------------------------------------------------*/ +/* genPlus - generates code for addition */ +/*-----------------------------------------------------------------*/ +static void genPlus (iCode *ic) +{ + int size, offset = 0; + + /* special cases :- */ + + aopOp (IC_LEFT(ic),ic,FALSE); + aopOp (IC_RIGHT(ic),ic,FALSE); + aopOp (IC_RESULT(ic),ic,TRUE); + + /* if literal, literal on the right or + if left requires ACC or right is already + in ACC */ + if ((AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) || + (AOP_NEEDSACC(IC_LEFT(ic))) || + AOP_TYPE(IC_RIGHT(ic)) == AOP_ACC ){ + operand *t = IC_RIGHT(ic); + IC_RIGHT(ic) = IC_LEFT(ic); + IC_LEFT(ic) = t; + } + + /* if both left & right are in bit + space */ + if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY && + AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) { + genPlusBits (ic); + goto release ; + } + + /* if left in bit space & right literal */ + if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY && + AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT) { + emitcode("mov","c,%s",AOP(IC_LEFT(ic))->aopu.aop_dir); + /* if result in bit space */ + if(AOP_TYPE(IC_RESULT(ic)) == AOP_CRY){ + if((unsigned long)floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit) != 0L) + emitcode("cpl","c"); + outBitC(IC_RESULT(ic)); + } else { + size = getDataSize(IC_RESULT(ic)); + while (size--) { + MOVA(aopGet(AOP(IC_RIGHT(ic)),offset,FALSE,FALSE)); + emitcode("addc","a,#00"); + aopPut(AOP(IC_RESULT(ic)),"a",offset++); + } + } + goto release ; + } + + /* if I can do an increment instead + of add then GOOD for ME */ + if (genPlusIncr (ic) == TRUE) + goto release; + + size = getDataSize(IC_RESULT(ic)); + + while(size--){ + if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC) { + MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE,FALSE)); + if(offset == 0) + emitcode("add","a,%s", + aopGet(AOP(IC_RIGHT(ic)),offset,FALSE,FALSE)); + else + emitcode("addc","a,%s", + aopGet(AOP(IC_RIGHT(ic)),offset,FALSE,FALSE)); + } else { + MOVA(aopGet(AOP(IC_RIGHT(ic)),offset,FALSE,FALSE)); + if(offset == 0) + emitcode("add","a,%s", + aopGet(AOP(IC_LEFT(ic)),offset,FALSE,FALSE)); + else + emitcode("addc","a,%s", + aopGet(AOP(IC_LEFT(ic)),offset,FALSE,FALSE)); + } + aopPut(AOP(IC_RESULT(ic)),"a",offset++); + } + + adjustArithmeticResult(ic); + +release: + freeAsmop(IC_LEFT(ic),NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE)); + freeAsmop(IC_RIGHT(ic),NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE)); + freeAsmop(IC_RESULT(ic),NULL,ic,TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genMinusDec :- does subtraction with deccrement if possible */ +/*-----------------------------------------------------------------*/ +static bool genMinusDec (iCode *ic) +{ + unsigned int icount ; + unsigned int size = getDataSize(IC_RESULT(ic)); + + /* will try to generate an increment */ + /* if the right side is not a literal + we cannot */ + if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT) + return FALSE ; + + /* if the literal value of the right hand side + is greater than 4 then it is not worth it */ + if ((icount = (unsigned int) floatFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit)) > 4) + return FALSE ; + + /* if decrement 16 bits in register */ + if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) && + (size > 1) && + (icount == 1)) { + symbol *tlbl; + int emitTlbl; + int labelRange; + + /* If the next instruction is a goto and the goto target + * is <= 10 instructions previous to this, we can generate + * jumps straight to that target. + */ + if (ic->next && ic->next->op == GOTO + && (labelRange = findLabelBackwards(ic, IC_LABEL(ic->next)->key)) != 0 + && labelRange <= 10 ) + { + emitcode(";", "tail decrement optimized"); + tlbl = IC_LABEL(ic->next); + emitTlbl = 0; + } + else + { + tlbl = newiTempLabel(NULL); + emitTlbl = 1; + } + + emitcode("dec","%s",aopGet(AOP(IC_RESULT(ic)),LSB,FALSE,FALSE)); + if(AOP_TYPE(IC_RESULT(ic)) == AOP_REG || + IS_AOP_PREG(IC_RESULT(ic))) + emitcode("cjne","%s,#0xff,%05d$" + ,aopGet(AOP(IC_RESULT(ic)),LSB,FALSE,FALSE) + ,tlbl->key+100); + else{ + emitcode("mov","a,#0xff"); + emitcode("cjne","a,%s,%05d$" + ,aopGet(AOP(IC_RESULT(ic)),LSB,FALSE,FALSE) + ,tlbl->key+100); + } + emitcode("dec","%s",aopGet(AOP(IC_RESULT(ic)),MSB16,FALSE,FALSE)); + if (size > 2) + { + if(AOP_TYPE(IC_RESULT(ic)) == AOP_REG || + IS_AOP_PREG(IC_RESULT(ic))) + emitcode("cjne","%s,#0xff,%05d$" + ,aopGet(AOP(IC_RESULT(ic)),MSB16,FALSE,FALSE) + ,tlbl->key+100); + else{ + emitcode("cjne","a,%s,%05d$" + ,aopGet(AOP(IC_RESULT(ic)),MSB16,FALSE,FALSE) + ,tlbl->key+100); + } + emitcode("dec","%s",aopGet(AOP(IC_RESULT(ic)),MSB24,FALSE,FALSE)); + } + if (size > 3) + { + if(AOP_TYPE(IC_RESULT(ic)) == AOP_REG || + IS_AOP_PREG(IC_RESULT(ic))) + emitcode("cjne","%s,#0xff,%05d$" + ,aopGet(AOP(IC_RESULT(ic)),MSB24,FALSE,FALSE) + ,tlbl->key+100); + else{ + emitcode("cjne","a,%s,%05d$" + ,aopGet(AOP(IC_RESULT(ic)),MSB24,FALSE,FALSE) + ,tlbl->key+100); + } + emitcode("dec","%s",aopGet(AOP(IC_RESULT(ic)),MSB32,FALSE,FALSE)); + } + if (emitTlbl) + { + emitcode("","%05d$:",tlbl->key+100); + } + return TRUE; + } + + /* if the sizes are greater than 1 then we cannot */ + if (AOP_SIZE(IC_RESULT(ic)) > 1 || + AOP_SIZE(IC_LEFT(ic)) > 1 ) + return FALSE ; + + /* we can if the aops of the left & result match or + if they are in registers and the registers are the + same */ + if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic)))) { + + while (icount--) + emitcode ("dec","%s",aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE)); + + return TRUE ; + } + + return FALSE ; +} + +/*-----------------------------------------------------------------*/ +/* addSign - complete with sign */ +/*-----------------------------------------------------------------*/ +static void addSign(operand *result, int offset, int sign) +{ + int size = (getDataSize(result) - offset); + if(size > 0){ + if(sign){ + emitcode("rlc","a"); + emitcode("subb","a,acc"); + while(size--) + aopPut(AOP(result),"a",offset++); + } else + while(size--) + aopPut(AOP(result),zero,offset++); + } +} + +/*-----------------------------------------------------------------*/ +/* genMinusBits - generates code for subtraction of two bits */ +/*-----------------------------------------------------------------*/ +static void genMinusBits (iCode *ic) +{ + symbol *lbl = newiTempLabel(NULL); + if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY){ + emitcode("mov","c,%s",AOP(IC_LEFT(ic))->aopu.aop_dir); + emitcode("jnb","%s,%05d$",AOP(IC_RIGHT(ic))->aopu.aop_dir,(lbl->key+100)); + emitcode("cpl","c"); + emitcode("","%05d$:",(lbl->key+100)); + outBitC(IC_RESULT(ic)); + } + else{ + emitcode("mov","c,%s",AOP(IC_RIGHT(ic))->aopu.aop_dir); + emitcode("subb","a,acc"); + emitcode("jnb","%s,%05d$",AOP(IC_LEFT(ic))->aopu.aop_dir,(lbl->key+100)); + emitcode("inc","a"); + emitcode("","%05d$:",(lbl->key+100)); + aopPut(AOP(IC_RESULT(ic)),"a",0); + addSign(IC_RESULT(ic), MSB16, SPEC_USIGN(getSpec(operandType(IC_RESULT(ic))))); + } +} + +/*-----------------------------------------------------------------*/ +/* genMinus - generates code for subtraction */ +/*-----------------------------------------------------------------*/ +static void genMinus (iCode *ic) +{ + int size, offset = 0; + unsigned long lit = 0L; + + aopOp (IC_LEFT(ic),ic,FALSE); + aopOp (IC_RIGHT(ic),ic,FALSE); + aopOp (IC_RESULT(ic),ic,TRUE); + + /* special cases :- */ + /* if both left & right are in bit space */ + if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY && + AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) { + genMinusBits (ic); + goto release ; + } + + /* if I can do an decrement instead + of subtract then GOOD for ME */ + if (genMinusDec (ic) == TRUE) + goto release; + + size = getDataSize(IC_RESULT(ic)); + + if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT){ + CLRC; + } + else{ + lit = (unsigned long)floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit); + lit = - (long)lit; + } + + /* if literal, add a,#-lit, else normal subb */ + while (size--) { + MOVA(aopGet(AOP(IC_LEFT(ic)),offset,FALSE,FALSE)); + if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT) + emitcode("subb","a,%s", + aopGet(AOP(IC_RIGHT(ic)),offset,FALSE,FALSE)); + else{ + /* first add without previous c */ + if(!offset) + emitcode("add","a,#0x%02x", + (unsigned int)(lit & 0x0FFL)); + else + emitcode("addc","a,#0x%02x", + (unsigned int)((lit >> (offset*8)) & 0x0FFL)); + } + aopPut(AOP(IC_RESULT(ic)),"a",offset++); + } + + adjustArithmeticResult(ic); + +release: + freeAsmop(IC_LEFT(ic),NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE)); + freeAsmop(IC_RIGHT(ic),NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE)); + freeAsmop(IC_RESULT(ic),NULL,ic,TRUE); +} + + +/*-----------------------------------------------------------------*/ +/* genMultbits :- multiplication of bits */ +/*-----------------------------------------------------------------*/ +static void genMultbits (operand *left, + operand *right, + operand *result) +{ + emitcode("mov","c,%s",AOP(left)->aopu.aop_dir); + emitcode("anl","c,%s",AOP(right)->aopu.aop_dir); + outBitC(result); +} + + +/*-----------------------------------------------------------------*/ +/* genMultOneByte : 8 bit multiplication & division */ +/*-----------------------------------------------------------------*/ +static void genMultOneByte (operand *left, + operand *right, + operand *result) +{ + link *opetype = operandType(result); + char *l ; + symbol *lbl ; + int size,offset; + + /* (if two literals, the value is computed before) */ + /* if one literal, literal on the right */ + if (AOP_TYPE(left) == AOP_LIT){ + operand *t = right; + right = left; + left = t; + } + + size = AOP_SIZE(result); + /* signed or unsigned */ + emitcode("mov","b,%s", aopGet(AOP(right),0,FALSE,FALSE)); + l = aopGet(AOP(left),0,FALSE,FALSE); + MOVA(l); + emitcode("mul","ab"); + /* if result size = 1, mul signed = mul unsigned */ + aopPut(AOP(result),"a",0); + if (size > 1){ + if (SPEC_USIGN(opetype)){ + aopPut(AOP(result),"b",1); + if (size > 2) + /* for filling the MSBs */ + emitcode("clr","a"); + } + else{ + emitcode("mov","a,b"); + + /* adjust the MSB if left or right neg */ + + /* if one literal */ + if (AOP_TYPE(right) == AOP_LIT){ + /* AND literal negative */ + if((int) floatFromVal (AOP(right)->aopu.aop_lit) < 0){ + /* adjust MSB (c==0 after mul) */ + emitcode("subb","a,%s", aopGet(AOP(left),0,FALSE,FALSE)); + } + } + else{ + lbl = newiTempLabel(NULL); + emitcode("xch","a,%s",aopGet(AOP(right),0,FALSE,FALSE)); + emitcode("cjne","a,#0x80,%05d$", (lbl->key+100)); + emitcode("","%05d$:",(lbl->key+100)); + emitcode("xch","a,%s",aopGet(AOP(right),0,FALSE,FALSE)); + lbl = newiTempLabel(NULL); + emitcode("jc","%05d$",(lbl->key+100)); + emitcode("subb","a,%s", aopGet(AOP(left),0,FALSE,FALSE)); + emitcode("","%05d$:",(lbl->key+100)); + } + + lbl = newiTempLabel(NULL); + emitcode("xch","a,%s",aopGet(AOP(left),0,FALSE,FALSE)); + emitcode("cjne","a,#0x80,%05d$", (lbl->key+100)); + emitcode("","%05d$:",(lbl->key+100)); + emitcode("xch","a,%s",aopGet(AOP(left),0,FALSE,FALSE)); + lbl = newiTempLabel(NULL); + emitcode("jc","%05d$",(lbl->key+100)); + emitcode("subb","a,%s", aopGet(AOP(right),0,FALSE,FALSE)); + emitcode("","%05d$:",(lbl->key+100)); + + aopPut(AOP(result),"a",1); + if(size > 2){ + /* get the sign */ + emitcode("rlc","a"); + emitcode("subb","a,acc"); + } + } + size -= 2; + offset = 2; + if (size > 0) + while (size--) + aopPut(AOP(result),"a",offset++); + } +} + +/*-----------------------------------------------------------------*/ +/* genMult - generates code for multiplication */ +/*-----------------------------------------------------------------*/ +static void genMult (iCode *ic) +{ + operand *left = IC_LEFT(ic); + operand *right = IC_RIGHT(ic); + operand *result= IC_RESULT(ic); + + /* assign the amsops */ + aopOp (left,ic,FALSE); + aopOp (right,ic,FALSE); + aopOp (result,ic,TRUE); + + /* special cases first */ + /* both are bits */ + if (AOP_TYPE(left) == AOP_CRY && + AOP_TYPE(right)== AOP_CRY) { + genMultbits(left,right,result); + goto release ; + } + + /* if both are of size == 1 */ + if (AOP_SIZE(left) == 1 && + AOP_SIZE(right) == 1 ) { + genMultOneByte(left,right,result); + goto release ; + } + + /* should have been converted to function call */ + assert(1) ; + +release : + freeAsmop(left,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE)); + freeAsmop(right,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE)); + freeAsmop(result,NULL,ic,TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genDivbits :- division of bits */ +/*-----------------------------------------------------------------*/ +static void genDivbits (operand *left, + operand *right, + operand *result) +{ + + char *l; + + /* the result must be bit */ + emitcode("mov","b,%s",aopGet(AOP(right),0,FALSE,FALSE)); + l = aopGet(AOP(left),0,FALSE,FALSE); + + MOVA(l); + + emitcode("div","ab"); + emitcode("rrc","a"); + aopPut(AOP(result),"c",0); +} + +/*-----------------------------------------------------------------*/ +/* genDivOneByte : 8 bit division */ +/*-----------------------------------------------------------------*/ +static void genDivOneByte (operand *left, + operand *right, + operand *result) +{ + link *opetype = operandType(result); + char *l ; + symbol *lbl ; + int size,offset; + + size = AOP_SIZE(result) - 1; + offset = 1; + /* signed or unsigned */ + if (SPEC_USIGN(opetype)) { + /* unsigned is easy */ + emitcode("mov","b,%s", aopGet(AOP(right),0,FALSE,FALSE)); + l = aopGet(AOP(left),0,FALSE,FALSE); + MOVA(l); + emitcode("div","ab"); + aopPut(AOP(result),"a",0); + while (size--) + aopPut(AOP(result),zero,offset++); + return ; + } + + /* signed is a little bit more difficult */ + + /* save the signs of the operands */ + l = aopGet(AOP(left),0,FALSE,FALSE); + MOVA(l); + emitcode("xrl","a,%s",aopGet(AOP(right),0,FALSE,TRUE)); + emitcode("push","acc"); /* save it on the stack */ + + /* now sign adjust for both left & right */ + l = aopGet(AOP(right),0,FALSE,FALSE); + MOVA(l); + lbl = newiTempLabel(NULL); + emitcode("jnb","acc.7,%05d$",(lbl->key+100)); + emitcode("cpl","a"); + emitcode("inc","a"); + emitcode("","%05d$:",(lbl->key+100)); + emitcode("mov","b,a"); + + /* sign adjust left side */ + l = aopGet(AOP(left),0,FALSE,FALSE); + MOVA(l); + + lbl = newiTempLabel(NULL); + emitcode("jnb","acc.7,%05d$",(lbl->key+100)); + emitcode("cpl","a"); + emitcode("inc","a"); + emitcode("","%05d$:",(lbl->key+100)); + + /* now the division */ + emitcode("div","ab"); + /* we are interested in the lower order + only */ + emitcode("mov","b,a"); + lbl = newiTempLabel(NULL); + emitcode("pop","acc"); + /* if there was an over flow we don't + adjust the sign of the result */ + emitcode("jb","ov,%05d$",(lbl->key+100)); + emitcode("jnb","acc.7,%05d$",(lbl->key+100)); + CLRC; + emitcode("clr","a"); + emitcode("subb","a,b"); + emitcode("mov","b,a"); + emitcode("","%05d$:",(lbl->key+100)); + + /* now we are done */ + aopPut(AOP(result),"b",0); + if(size > 0){ + emitcode("mov","c,b.7"); + emitcode("subb","a,acc"); + } + while (size--) + aopPut(AOP(result),"a",offset++); + +} + +/*-----------------------------------------------------------------*/ +/* genDiv - generates code for division */ +/*-----------------------------------------------------------------*/ +static void genDiv (iCode *ic) +{ + operand *left = IC_LEFT(ic); + operand *right = IC_RIGHT(ic); + operand *result= IC_RESULT(ic); + + /* assign the amsops */ + aopOp (left,ic,FALSE); + aopOp (right,ic,FALSE); + aopOp (result,ic,TRUE); + + /* special cases first */ + /* both are bits */ + if (AOP_TYPE(left) == AOP_CRY && + AOP_TYPE(right)== AOP_CRY) { + genDivbits(left,right,result); + goto release ; + } + + /* if both are of size == 1 */ + if (AOP_SIZE(left) == 1 && + AOP_SIZE(right) == 1 ) { + genDivOneByte(left,right,result); + goto release ; + } + + /* should have been converted to function call */ + assert(1); +release : + freeAsmop(left,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE)); + freeAsmop(right,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE)); + freeAsmop(result,NULL,ic,TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genModbits :- modulus of bits */ +/*-----------------------------------------------------------------*/ +static void genModbits (operand *left, + operand *right, + operand *result) +{ + + char *l; + + /* the result must be bit */ + emitcode("mov","b,%s",aopGet(AOP(right),0,FALSE,FALSE)); + l = aopGet(AOP(left),0,FALSE,FALSE); + + MOVA(l); + + emitcode("div","ab"); + emitcode("mov","a,b"); + emitcode("rrc","a"); + aopPut(AOP(result),"c",0); +} + +/*-----------------------------------------------------------------*/ +/* genModOneByte : 8 bit modulus */ +/*-----------------------------------------------------------------*/ +static void genModOneByte (operand *left, + operand *right, + operand *result) +{ + link *opetype = operandType(result); + char *l ; + symbol *lbl ; + + /* signed or unsigned */ + if (SPEC_USIGN(opetype)) { + /* unsigned is easy */ + emitcode("mov","b,%s", aopGet(AOP(right),0,FALSE,FALSE)); + l = aopGet(AOP(left),0,FALSE,FALSE); + MOVA(l); + emitcode("div","ab"); + aopPut(AOP(result),"b",0); + return ; + } + + /* signed is a little bit more difficult */ + + /* save the signs of the operands */ + l = aopGet(AOP(left),0,FALSE,FALSE); + MOVA(l); + + emitcode("xrl","a,%s",aopGet(AOP(right),0,FALSE,FALSE)); + emitcode("push","acc"); /* save it on the stack */ + + /* now sign adjust for both left & right */ + l = aopGet(AOP(right),0,FALSE,FALSE); + MOVA(l); + + lbl = newiTempLabel(NULL); + emitcode("jnb","acc.7,%05d$",(lbl->key+100)); + emitcode("cpl","a"); + emitcode("inc","a"); + emitcode("","%05d$:",(lbl->key+100)); + emitcode("mov","b,a"); + + /* sign adjust left side */ + l = aopGet(AOP(left),0,FALSE,FALSE); + MOVA(l); + + lbl = newiTempLabel(NULL); + emitcode("jnb","acc.7,%05d$",(lbl->key+100)); + emitcode("cpl","a"); + emitcode("inc","a"); + emitcode("","%05d$:",(lbl->key+100)); + + /* now the multiplication */ + emitcode("div","ab"); + /* we are interested in the lower order + only */ + lbl = newiTempLabel(NULL); + emitcode("pop","acc"); + /* if there was an over flow we don't + adjust the sign of the result */ + emitcode("jb","ov,%05d$",(lbl->key+100)); + emitcode("jnb","acc.7,%05d$",(lbl->key+100)); + CLRC ; + emitcode("clr","a"); + emitcode("subb","a,b"); + emitcode("mov","b,a"); + emitcode("","%05d$:",(lbl->key+100)); + + /* now we are done */ + aopPut(AOP(result),"b",0); + +} + +/*-----------------------------------------------------------------*/ +/* genMod - generates code for division */ +/*-----------------------------------------------------------------*/ +static void genMod (iCode *ic) +{ + operand *left = IC_LEFT(ic); + operand *right = IC_RIGHT(ic); + operand *result= IC_RESULT(ic); + + /* assign the amsops */ + aopOp (left,ic,FALSE); + aopOp (right,ic,FALSE); + aopOp (result,ic,TRUE); + + /* special cases first */ + /* both are bits */ + if (AOP_TYPE(left) == AOP_CRY && + AOP_TYPE(right)== AOP_CRY) { + genModbits(left,right,result); + goto release ; + } + + /* if both are of size == 1 */ + if (AOP_SIZE(left) == 1 && + AOP_SIZE(right) == 1 ) { + genModOneByte(left,right,result); + goto release ; + } + + /* should have been converted to function call */ + assert(1); + +release : + freeAsmop(left,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE)); + freeAsmop(right,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE)); + freeAsmop(result,NULL,ic,TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genIfxJump :- will create a jump depending on the ifx */ +/*-----------------------------------------------------------------*/ +static void genIfxJump (iCode *ic, char *jval) +{ + symbol *jlbl ; + symbol *tlbl = newiTempLabel(NULL); + char *inst; + + /* if true label then we jump if condition + supplied is true */ + if ( IC_TRUE(ic) ) { + jlbl = IC_TRUE(ic); + inst = ((strcmp(jval,"a") == 0 ? "jz" : + (strcmp(jval,"c") == 0 ? "jnc" : "jnb" ))); + } + else { + /* false label is present */ + jlbl = IC_FALSE(ic) ; + inst = ((strcmp(jval,"a") == 0 ? "jnz" : + (strcmp(jval,"c") == 0 ? "jc" : "jb" ))); + } + if (strcmp(inst,"jb") == 0 || strcmp(inst,"jnb") == 0) + emitcode(inst,"%s,%05d$",jval,(tlbl->key+100)); + else + emitcode(inst,"%05d$",tlbl->key+100); + emitcode("ljmp","%05d$",jlbl->key+100); + emitcode("","%05d$:",tlbl->key+100); + + /* mark the icode as generated */ + ic->generated = 1; +} + +/*-----------------------------------------------------------------*/ +/* genCmp :- greater or less than comparison */ +/*-----------------------------------------------------------------*/ +static void genCmp (operand *left,operand *right, + operand *result, iCode *ifx, int sign) +{ + int size, offset = 0 ; + unsigned long lit = 0L; + + /* if left & right are bit variables */ + if (AOP_TYPE(left) == AOP_CRY && + AOP_TYPE(right) == AOP_CRY ) { + emitcode("mov","c,%s",AOP(right)->aopu.aop_dir); + emitcode("anl","c,/%s",AOP(left)->aopu.aop_dir); + } else { + /* subtract right from left if at the + end the carry flag is set then we know that + left is greater than right */ + size = max(AOP_SIZE(left),AOP_SIZE(right)); + + /* if unsigned char cmp with lit, do cjne left,#right,zz */ + if((size == 1) && !sign && + (AOP_TYPE(right) == AOP_LIT && AOP_TYPE(left) != AOP_DIR )){ + symbol *lbl = newiTempLabel(NULL); + emitcode("cjne","%s,%s,%05d$", + aopGet(AOP(left),offset,FALSE,FALSE), + aopGet(AOP(right),offset,FALSE,FALSE), + lbl->key+100); + emitcode("","%05d$:",lbl->key+100); + } else { + if(AOP_TYPE(right) == AOP_LIT){ + lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit); + /* optimize if(x < 0) or if(x >= 0) */ + if(lit == 0L){ + if(!sign){ + CLRC; + } + else{ + MOVA(aopGet(AOP(left),AOP_SIZE(left)-1,FALSE,FALSE)); + if(!(AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) && ifx){ + genIfxJump (ifx,"acc.7"); + return; + } + else + emitcode("rlc","a"); + } + goto release; + } + } + CLRC; + while (size--) { + MOVA(aopGet(AOP(left),offset,FALSE,FALSE)); + if (sign && size == 0) { + emitcode("xrl","a,#0x80"); + if (AOP_TYPE(right) == AOP_LIT){ + unsigned long lit = (unsigned long) + floatFromVal(AOP(right)->aopu.aop_lit); + emitcode("subb","a,#0x%02x", + 0x80 ^ (unsigned int)((lit >> (offset*8)) & 0x0FFL)); + } else { + emitcode("mov","b,%s",aopGet(AOP(right),offset++,FALSE,FALSE)); + emitcode("xrl","b,#0x80"); + emitcode("subb","a,b"); + } + } else + emitcode("subb","a,%s",aopGet(AOP(right),offset++,FALSE,FALSE)); + } + } + } + +release: + if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) { + outBitC(result); + } else { + /* if the result is used in the next + ifx conditional branch then generate + code a little differently */ + if (ifx ) + genIfxJump (ifx,"c"); + else + outBitC(result); + /* leave the result in acc */ + } +} + +/*-----------------------------------------------------------------*/ +/* genCmpGt :- greater than comparison */ +/*-----------------------------------------------------------------*/ +static void genCmpGt (iCode *ic, iCode *ifx) +{ + operand *left, *right, *result; + link *letype , *retype; + int sign ; + + left = IC_LEFT(ic); + right= IC_RIGHT(ic); + result = IC_RESULT(ic); + + letype = getSpec(operandType(left)); + retype =getSpec(operandType(right)); + sign = !(SPEC_USIGN(letype) | SPEC_USIGN(retype)); + /* assign the amsops */ + aopOp (left,ic,FALSE); + aopOp (right,ic,FALSE); + aopOp (result,ic,TRUE); + + genCmp(right, left, result, ifx, sign); + + freeAsmop(left,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE)); + freeAsmop(right,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE)); + freeAsmop(result,NULL,ic,TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genCmpLt - less than comparisons */ +/*-----------------------------------------------------------------*/ +static void genCmpLt (iCode *ic, iCode *ifx) +{ + operand *left, *right, *result; + link *letype , *retype; + int sign ; + + left = IC_LEFT(ic); + right= IC_RIGHT(ic); + result = IC_RESULT(ic); + + letype = getSpec(operandType(left)); + retype =getSpec(operandType(right)); + sign = !(SPEC_USIGN(letype) | SPEC_USIGN(retype)); + + /* assign the amsops */ + aopOp (left,ic,FALSE); + aopOp (right,ic,FALSE); + aopOp (result,ic,TRUE); + + genCmp(left, right, result, ifx, sign); + + freeAsmop(left,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE)); + freeAsmop(right,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE)); + freeAsmop(result,NULL,ic,TRUE); +} + +/*-----------------------------------------------------------------*/ +/* gencjneshort - compare and jump if not equal */ +/*-----------------------------------------------------------------*/ +static void gencjneshort(operand *left, operand *right, symbol *lbl) +{ + int size = max(AOP_SIZE(left),AOP_SIZE(right)); + int offset = 0; + unsigned long lit = 0L; + + /* if the left side is a literal or + if the right is in a pointer register and left + is not */ + if ((AOP_TYPE(left) == AOP_LIT) || + (IS_AOP_PREG(right) && !IS_AOP_PREG(left))) { + operand *t = right; + right = left; + left = t; + } + if(AOP_TYPE(right) == AOP_LIT) + lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit); + + /* if the right side is a literal then anything goes */ + if (AOP_TYPE(right) == AOP_LIT && + AOP_TYPE(left) != AOP_DIR ) { + while (size--) { + emitcode("cjne","%s,%s,%05d$", + aopGet(AOP(left),offset,FALSE,FALSE), + aopGet(AOP(right),offset,FALSE,FALSE), + lbl->key+100); + offset++; + } + } + + /* if the right side is in a register or in direct space or + if the left is a pointer register & right is not */ + else if (AOP_TYPE(right) == AOP_REG || + AOP_TYPE(right) == AOP_DIR || + (AOP_TYPE(left) == AOP_DIR && AOP_TYPE(right) == AOP_LIT) || + (IS_AOP_PREG(left) && !IS_AOP_PREG(right))) { + while (size--) { + MOVA(aopGet(AOP(left),offset,FALSE,FALSE)); + if((AOP_TYPE(left) == AOP_DIR && AOP_TYPE(right) == AOP_LIT) && + ((unsigned int)((lit >> (offset*8)) & 0x0FFL) == 0)) + emitcode("jnz","%05d$",lbl->key+100); + else + emitcode("cjne","a,%s,%05d$", + aopGet(AOP(right),offset,FALSE,TRUE), + lbl->key+100); + offset++; + } + } else { + /* right is a pointer reg need both a & b */ + while(size--) { + char *l = aopGet(AOP(left),offset,FALSE,FALSE); + if(strcmp(l,"b")) + emitcode("mov","b,%s",l); + MOVA(aopGet(AOP(right),offset,FALSE,FALSE)); + emitcode("cjne","a,b,%05d$",lbl->key+100); + offset++; + } + } +} + +/*-----------------------------------------------------------------*/ +/* gencjne - compare and jump if not equal */ +/*-----------------------------------------------------------------*/ +static void gencjne(operand *left, operand *right, symbol *lbl) +{ + symbol *tlbl = newiTempLabel(NULL); + + gencjneshort(left, right, lbl); + + emitcode("mov","a,%s",one); + emitcode("sjmp","%05d$",tlbl->key+100); + emitcode("","%05d$:",lbl->key+100); + emitcode("clr","a"); + emitcode("","%05d$:",tlbl->key+100); +} + +/*-----------------------------------------------------------------*/ +/* genCmpEq - generates code for equal to */ +/*-----------------------------------------------------------------*/ +static void genCmpEq (iCode *ic, iCode *ifx) +{ + operand *left, *right, *result; + + aopOp((left=IC_LEFT(ic)),ic,FALSE); + aopOp((right=IC_RIGHT(ic)),ic,FALSE); + aopOp((result=IC_RESULT(ic)),ic,TRUE); + + /* if literal, literal on the right or + if the right is in a pointer register and left + is not */ + if ((AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) || + (IS_AOP_PREG(right) && !IS_AOP_PREG(left))) { + operand *t = IC_RIGHT(ic); + IC_RIGHT(ic) = IC_LEFT(ic); + IC_LEFT(ic) = t; + } + + if(ifx && !AOP_SIZE(result)){ + symbol *tlbl; + /* if they are both bit variables */ + if (AOP_TYPE(left) == AOP_CRY && + ((AOP_TYPE(right) == AOP_CRY) || (AOP_TYPE(right) == AOP_LIT))) { + if(AOP_TYPE(right) == AOP_LIT){ + unsigned long lit = (unsigned long)floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit); + if(lit == 0L){ + emitcode("mov","c,%s",AOP(left)->aopu.aop_dir); + emitcode("cpl","c"); + } else if(lit == 1L) { + emitcode("mov","c,%s",AOP(left)->aopu.aop_dir); + } else { + emitcode("clr","c"); + } + /* AOP_TYPE(right) == AOP_CRY */ + } else { + symbol *lbl = newiTempLabel(NULL); + emitcode("mov","c,%s",AOP(left)->aopu.aop_dir); + emitcode("jb","%s,%05d$",AOP(right)->aopu.aop_dir,(lbl->key+100)); + emitcode("cpl","c"); + emitcode("","%05d$:",(lbl->key+100)); + } + /* if true label then we jump if condition + supplied is true */ + tlbl = newiTempLabel(NULL); + if ( IC_TRUE(ifx) ) { + emitcode("jnc","%05d$",tlbl->key+100); + emitcode("ljmp","%05d$",IC_TRUE(ifx)->key+100); + } else { + emitcode("jc","%05d$",tlbl->key+100); + emitcode("ljmp","%05d$",IC_FALSE(ifx)->key+100); + } + emitcode("","%05d$:",tlbl->key+100); + } else { + tlbl = newiTempLabel(NULL); + gencjneshort(left, right, tlbl); + if ( IC_TRUE(ifx) ) { + emitcode("ljmp","%05d$",IC_TRUE(ifx)->key+100); + emitcode("","%05d$:",tlbl->key+100); + } else { + symbol *lbl = newiTempLabel(NULL); + emitcode("sjmp","%05d$",lbl->key+100); + emitcode("","%05d$:",tlbl->key+100); + emitcode("ljmp","%05d$",IC_FALSE(ifx)->key+100); + emitcode("","%05d$:",lbl->key+100); + } + } + /* mark the icode as generated */ + ifx->generated = 1; + goto release ; + } + + /* if they are both bit variables */ + if (AOP_TYPE(left) == AOP_CRY && + ((AOP_TYPE(right) == AOP_CRY) || (AOP_TYPE(right) == AOP_LIT))) { + if(AOP_TYPE(right) == AOP_LIT){ + unsigned long lit = (unsigned long)floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit); + if(lit == 0L){ + emitcode("mov","c,%s",AOP(left)->aopu.aop_dir); + emitcode("cpl","c"); + } else if(lit == 1L) { + emitcode("mov","c,%s",AOP(left)->aopu.aop_dir); + } else { + emitcode("clr","c"); + } + /* AOP_TYPE(right) == AOP_CRY */ + } else { + symbol *lbl = newiTempLabel(NULL); + emitcode("mov","c,%s",AOP(left)->aopu.aop_dir); + emitcode("jb","%s,%05d$",AOP(right)->aopu.aop_dir,(lbl->key+100)); + emitcode("cpl","c"); + emitcode("","%05d$:",(lbl->key+100)); + } + /* c = 1 if egal */ + if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)){ + outBitC(result); + goto release ; + } + if (ifx) { + genIfxJump (ifx,"c"); + goto release ; + } + /* if the result is used in an arithmetic operation + then put the result in place */ + outBitC(result); + } else { + gencjne(left,right,newiTempLabel(NULL)); + if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) { + aopPut(AOP(result),"a",0); + goto release ; + } + if (ifx) { + genIfxJump (ifx,"a"); + goto release ; + } + /* if the result is used in an arithmetic operation + then put the result in place */ + if (AOP_TYPE(result) != AOP_CRY) + outAcc(result); + /* leave the result in acc */ + } + +release: + freeAsmop(left,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE)); + freeAsmop(right,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE)); + freeAsmop(result,NULL,ic,TRUE); +} + +/*-----------------------------------------------------------------*/ +/* ifxForOp - returns the icode containing the ifx for operand */ +/*-----------------------------------------------------------------*/ +static iCode *ifxForOp ( operand *op, iCode *ic ) +{ + /* if true symbol then needs to be assigned */ + if (IS_TRUE_SYMOP(op)) + return NULL ; + + /* if this has register type condition and + the next instruction is ifx with the same operand + and live to of the operand is upto the ifx only then */ + if (ic->next && + ic->next->op == IFX && + IC_COND(ic->next)->key == op->key && + OP_SYMBOL(op)->liveTo <= ic->next->seq ) + return ic->next; + + return NULL; +} +/*-----------------------------------------------------------------*/ +/* genAndOp - for && operation */ +/*-----------------------------------------------------------------*/ +static void genAndOp (iCode *ic) +{ + operand *left,*right, *result; + symbol *tlbl; + + /* note here that && operations that are in an + if statement are taken away by backPatchLabels + only those used in arthmetic operations remain */ + aopOp((left=IC_LEFT(ic)),ic,FALSE); + aopOp((right=IC_RIGHT(ic)),ic,FALSE); + aopOp((result=IC_RESULT(ic)),ic,FALSE); + + /* if both are bit variables */ + if (AOP_TYPE(left) == AOP_CRY && + AOP_TYPE(right) == AOP_CRY ) { + emitcode("mov","c,%s",AOP(left)->aopu.aop_dir); + emitcode("anl","c,%s",AOP(right)->aopu.aop_dir); + outBitC(result); + } else { + tlbl = newiTempLabel(NULL); + toBoolean(left); + emitcode("jz","%05d$",tlbl->key+100); + toBoolean(right); + emitcode("","%05d$:",tlbl->key+100); + outBitAcc(result); + } + + freeAsmop(left,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE)); + freeAsmop(right,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE)); + freeAsmop(result,NULL,ic,TRUE); +} + + +/*-----------------------------------------------------------------*/ +/* genOrOp - for || operation */ +/*-----------------------------------------------------------------*/ +static void genOrOp (iCode *ic) +{ + operand *left,*right, *result; + symbol *tlbl; + + /* note here that || operations that are in an + if statement are taken away by backPatchLabels + only those used in arthmetic operations remain */ + aopOp((left=IC_LEFT(ic)),ic,FALSE); + aopOp((right=IC_RIGHT(ic)),ic,FALSE); + aopOp((result=IC_RESULT(ic)),ic,FALSE); + + /* if both are bit variables */ + if (AOP_TYPE(left) == AOP_CRY && + AOP_TYPE(right) == AOP_CRY ) { + emitcode("mov","c,%s",AOP(left)->aopu.aop_dir); + emitcode("orl","c,%s",AOP(right)->aopu.aop_dir); + outBitC(result); + } else { + tlbl = newiTempLabel(NULL); + toBoolean(left); + emitcode("jnz","%05d$",tlbl->key+100); + toBoolean(right); + emitcode("","%05d$:",tlbl->key+100); + outBitAcc(result); + } + + freeAsmop(left,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE)); + freeAsmop(right,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE)); + freeAsmop(result,NULL,ic,TRUE); +} + +/*-----------------------------------------------------------------*/ +/* isLiteralBit - test if lit == 2^n */ +/*-----------------------------------------------------------------*/ +static int isLiteralBit(unsigned long lit) +{ + unsigned long pw[32] = {1L,2L,4L,8L,16L,32L,64L,128L, + 0x100L,0x200L,0x400L,0x800L, + 0x1000L,0x2000L,0x4000L,0x8000L, + 0x10000L,0x20000L,0x40000L,0x80000L, + 0x100000L,0x200000L,0x400000L,0x800000L, + 0x1000000L,0x2000000L,0x4000000L,0x8000000L, + 0x10000000L,0x20000000L,0x40000000L,0x80000000L}; + int idx; + + for(idx = 0; idx < 32; idx++) + if(lit == pw[idx]) + return idx+1; + return 0; +} + +/*-----------------------------------------------------------------*/ +/* continueIfTrue - */ +/*-----------------------------------------------------------------*/ +static void continueIfTrue (iCode *ic) +{ + if(IC_TRUE(ic)) + emitcode("ljmp","%05d$",IC_TRUE(ic)->key+100); + ic->generated = 1; +} + +/*-----------------------------------------------------------------*/ +/* jmpIfTrue - */ +/*-----------------------------------------------------------------*/ +static void jumpIfTrue (iCode *ic) +{ + if(!IC_TRUE(ic)) + emitcode("ljmp","%05d$",IC_FALSE(ic)->key+100); + ic->generated = 1; +} + +/*-----------------------------------------------------------------*/ +/* jmpTrueOrFalse - */ +/*-----------------------------------------------------------------*/ +static void jmpTrueOrFalse (iCode *ic, symbol *tlbl) +{ + // ugly but optimized by peephole + if(IC_TRUE(ic)){ + symbol *nlbl = newiTempLabel(NULL); + emitcode("sjmp","%05d$",nlbl->key+100); + emitcode("","%05d$:",tlbl->key+100); + emitcode("ljmp","%05d$",IC_TRUE(ic)->key+100); + emitcode("","%05d$:",nlbl->key+100); + } + else{ + emitcode("ljmp","%05d$",IC_FALSE(ic)->key+100); + emitcode("","%05d$:",tlbl->key+100); + } + ic->generated = 1; +} + +/*-----------------------------------------------------------------*/ +/* genAnd - code for and */ +/*-----------------------------------------------------------------*/ +static void genAnd (iCode *ic, iCode *ifx) +{ + operand *left, *right, *result; + int size, offset=0; + unsigned long lit = 0L; + int bytelit = 0; + char buffer[10]; + + aopOp((left = IC_LEFT(ic)),ic,FALSE); + aopOp((right= IC_RIGHT(ic)),ic,FALSE); + aopOp((result=IC_RESULT(ic)),ic,TRUE); + +#ifdef DEBUG_TYPE + emitcode("","; Type res[%d] = l[%d]&r[%d]", + AOP_TYPE(result), + AOP_TYPE(left), AOP_TYPE(right)); + emitcode("","; Size res[%d] = l[%d]&r[%d]", + AOP_SIZE(result), + AOP_SIZE(left), AOP_SIZE(right)); +#endif + + /* if left is a literal & right is not then exchange them */ + if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) || + AOP_NEEDSACC(left)) { + operand *tmp = right ; + right = left; + left = tmp; + } + + /* if result = right then exchange them */ + if(sameRegs(AOP(result),AOP(right))){ + operand *tmp = right ; + right = left; + left = tmp; + } + + /* if right is bit then exchange them */ + if (AOP_TYPE(right) == AOP_CRY && + AOP_TYPE(left) != AOP_CRY){ + operand *tmp = right ; + right = left; + left = tmp; + } + if(AOP_TYPE(right) == AOP_LIT) + lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit); + + size = AOP_SIZE(result); + + // if(bit & yy) + // result = bit & yy; + if (AOP_TYPE(left) == AOP_CRY){ + // c = bit & literal; + if(AOP_TYPE(right) == AOP_LIT){ + if(lit & 1) { + if(size && sameRegs(AOP(result),AOP(left))) + // no change + goto release; + emitcode("mov","c,%s",AOP(left)->aopu.aop_dir); + } else { + // bit(result) = 0; + if(size && (AOP_TYPE(result) == AOP_CRY)){ + emitcode("clr","%s",AOP(result)->aopu.aop_dir); + goto release; + } + if((AOP_TYPE(result) == AOP_CRY) && ifx){ + jumpIfTrue(ifx); + goto release; + } + emitcode("clr","c"); + } + } else { + if (AOP_TYPE(right) == AOP_CRY){ + // c = bit & bit; + emitcode("mov","c,%s",AOP(right)->aopu.aop_dir); + emitcode("anl","c,%s",AOP(left)->aopu.aop_dir); + } else { + // c = bit & val; + MOVA(aopGet(AOP(right),0,FALSE,FALSE)); + // c = lsb + emitcode("rrc","a"); + emitcode("anl","c,%s",AOP(left)->aopu.aop_dir); + } + } + // bit = c + // val = c + if(size) + outBitC(result); + // if(bit & ...) + else if((AOP_TYPE(result) == AOP_CRY) && ifx) + genIfxJump(ifx, "c"); + goto release ; + } + + // if(val & 0xZZ) - size = 0, ifx != FALSE - + // bit = val & 0xZZ - size = 1, ifx = FALSE - + if((AOP_TYPE(right) == AOP_LIT) && + (AOP_TYPE(result) == AOP_CRY) && + (AOP_TYPE(left) != AOP_CRY)){ + int posbit = isLiteralBit(lit); + /* left & 2^n */ + if(posbit){ + posbit--; + MOVA(aopGet(AOP(left),posbit>>3,FALSE,FALSE)); + // bit = left & 2^n + if(size) + emitcode("mov","c,acc.%d",posbit&0x07); + // if(left & 2^n) + else{ + if(ifx){ + sprintf(buffer,"acc.%d",posbit&0x07); + genIfxJump(ifx, buffer); + } + goto release; + } + } else { + symbol *tlbl = newiTempLabel(NULL); + int sizel = AOP_SIZE(left); + if(size) + emitcode("setb","c"); + while(sizel--){ + if((bytelit = ((lit >> (offset*8)) & 0x0FFL)) != 0x0L){ + MOVA( aopGet(AOP(left),offset,FALSE,FALSE)); + // byte == 2^n ? + if((posbit = isLiteralBit(bytelit)) != 0) + emitcode("jb","acc.%d,%05d$",(posbit-1)&0x07,tlbl->key+100); + else{ + if(bytelit != 0x0FFL) + emitcode("anl","a,%s", + aopGet(AOP(right),offset,FALSE,TRUE)); + emitcode("jnz","%05d$",tlbl->key+100); + } + } + offset++; + } + // bit = left & literal + if(size){ + emitcode("clr","c"); + emitcode("","%05d$:",tlbl->key+100); + } + // if(left & literal) + else{ + if(ifx) + jmpTrueOrFalse(ifx, tlbl); + goto release ; + } + } + outBitC(result); + goto release ; + } + + /* if left is same as result */ + if(sameRegs(AOP(result),AOP(left))){ + for(;size--; offset++) { + if(AOP_TYPE(right) == AOP_LIT){ + if((bytelit = (int)((lit >> (offset*8)) & 0x0FFL)) == 0x0FF) + continue; + else + if (bytelit == 0) + aopPut(AOP(result),zero,offset); + else + if (IS_AOP_PREG(result)) { + MOVA(aopGet(AOP(right),offset,FALSE,FALSE)); + emitcode("anl","a,%s",aopGet(AOP(left),offset,FALSE,TRUE)); + aopPut(AOP(result),"a",offset); + } else + emitcode("anl","%s,%s", + aopGet(AOP(left),offset,FALSE,TRUE), + aopGet(AOP(right),offset,FALSE,FALSE)); + } else { + if (AOP_TYPE(left) == AOP_ACC) + emitcode("anl","a,%s",aopGet(AOP(right),offset,FALSE,FALSE)); + else { + MOVA(aopGet(AOP(right),offset,FALSE,FALSE)); + if (IS_AOP_PREG(result)) { + emitcode("anl","a,%s",aopGet(AOP(left),offset,FALSE,TRUE)); + aopPut(AOP(result),"a",offset); + + } else + emitcode("anl","%s,a", + aopGet(AOP(left),offset,FALSE,TRUE)); + } + } + } + } else { + // left & result in different registers + if(AOP_TYPE(result) == AOP_CRY){ + // result = bit + // if(size), result in bit + // if(!size && ifx), conditional oper: if(left & right) + symbol *tlbl = newiTempLabel(NULL); + int sizer = min(AOP_SIZE(left),AOP_SIZE(right)); + if(size) + emitcode("setb","c"); + while(sizer--){ + MOVA(aopGet(AOP(right),offset,FALSE,FALSE)); + emitcode("anl","a,%s", + aopGet(AOP(left),offset,FALSE,FALSE)); + emitcode("jnz","%05d$",tlbl->key+100); + offset++; + } + if(size){ + CLRC; + emitcode("","%05d$:",tlbl->key+100); + outBitC(result); + } else if(ifx) + jmpTrueOrFalse(ifx, tlbl); + } else { + for(;(size--);offset++) { + // normal case + // result = left & right + if(AOP_TYPE(right) == AOP_LIT){ + if((bytelit = (int)((lit >> (offset*8)) & 0x0FFL)) == 0x0FF){ + aopPut(AOP(result), + aopGet(AOP(left),offset,FALSE,FALSE), + offset); + continue; + } else if(bytelit == 0){ + aopPut(AOP(result),zero,offset); + continue; + } + } + // faster than result <- left, anl result,right + // and better if result is SFR + if (AOP_TYPE(left) == AOP_ACC) + emitcode("anl","a,%s",aopGet(AOP(right),offset,FALSE,FALSE)); + else { + MOVA(aopGet(AOP(right),offset,FALSE,FALSE)); + emitcode("anl","a,%s", + aopGet(AOP(left),offset,FALSE,FALSE)); + } + aopPut(AOP(result),"a",offset); + } + } + } + +release : + freeAsmop(left,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE)); + freeAsmop(right,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE)); + freeAsmop(result,NULL,ic,TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genOr - code for or */ +/*-----------------------------------------------------------------*/ +static void genOr (iCode *ic, iCode *ifx) +{ + operand *left, *right, *result; + int size, offset=0; + unsigned long lit = 0L; + + aopOp((left = IC_LEFT(ic)),ic,FALSE); + aopOp((right= IC_RIGHT(ic)),ic,FALSE); + aopOp((result=IC_RESULT(ic)),ic,TRUE); + +#ifdef DEBUG_TYPE + emitcode("","; Type res[%d] = l[%d]&r[%d]", + AOP_TYPE(result), + AOP_TYPE(left), AOP_TYPE(right)); + emitcode("","; Size res[%d] = l[%d]&r[%d]", + AOP_SIZE(result), + AOP_SIZE(left), AOP_SIZE(right)); +#endif + + /* if left is a literal & right is not then exchange them */ + if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) || + AOP_NEEDSACC(left)) { + operand *tmp = right ; + right = left; + left = tmp; + } + + /* if result = right then exchange them */ + if(sameRegs(AOP(result),AOP(right))){ + operand *tmp = right ; + right = left; + left = tmp; + } + + /* if right is bit then exchange them */ + if (AOP_TYPE(right) == AOP_CRY && + AOP_TYPE(left) != AOP_CRY){ + operand *tmp = right ; + right = left; + left = tmp; + } + if(AOP_TYPE(right) == AOP_LIT) + lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit); + + size = AOP_SIZE(result); + + // if(bit | yy) + // xx = bit | yy; + if (AOP_TYPE(left) == AOP_CRY){ + if(AOP_TYPE(right) == AOP_LIT){ + // c = bit & literal; + if(lit){ + // lit != 0 => result = 1 + if(AOP_TYPE(result) == AOP_CRY){ + if(size) + emitcode("setb","%s",AOP(result)->aopu.aop_dir); + else if(ifx) + continueIfTrue(ifx); + goto release; + } + emitcode("setb","c"); + } else { + // lit == 0 => result = left + if(size && sameRegs(AOP(result),AOP(left))) + goto release; + emitcode("mov","c,%s",AOP(left)->aopu.aop_dir); + } + } else { + if (AOP_TYPE(right) == AOP_CRY){ + // c = bit | bit; + emitcode("mov","c,%s",AOP(right)->aopu.aop_dir); + emitcode("orl","c,%s",AOP(left)->aopu.aop_dir); + } + else{ + // c = bit | val; + symbol *tlbl = newiTempLabel(NULL); + if(!((AOP_TYPE(result) == AOP_CRY) && ifx)) + emitcode("setb","c"); + emitcode("jb","%s,%05d$", + AOP(left)->aopu.aop_dir,tlbl->key+100); + toBoolean(right); + emitcode("jnz","%05d$",tlbl->key+100); + if((AOP_TYPE(result) == AOP_CRY) && ifx){ + jmpTrueOrFalse(ifx, tlbl); + goto release; + } else { + CLRC; + emitcode("","%05d$:",tlbl->key+100); + } + } + } + // bit = c + // val = c + if(size) + outBitC(result); + // if(bit | ...) + else if((AOP_TYPE(result) == AOP_CRY) && ifx) + genIfxJump(ifx, "c"); + goto release ; + } + + // if(val | 0xZZ) - size = 0, ifx != FALSE - + // bit = val | 0xZZ - size = 1, ifx = FALSE - + if((AOP_TYPE(right) == AOP_LIT) && + (AOP_TYPE(result) == AOP_CRY) && + (AOP_TYPE(left) != AOP_CRY)){ + if(lit){ + // result = 1 + if(size) + emitcode("setb","%s",AOP(result)->aopu.aop_dir); + else + continueIfTrue(ifx); + goto release; + } else { + // lit = 0, result = boolean(left) + if(size) + emitcode("setb","c"); + toBoolean(right); + if(size){ + symbol *tlbl = newiTempLabel(NULL); + emitcode("jnz","%05d$",tlbl->key+100); + CLRC; + emitcode("","%05d$:",tlbl->key+100); + } else { + genIfxJump (ifx,"a"); + goto release; + } + } + outBitC(result); + goto release ; + } + + /* if left is same as result */ + if(sameRegs(AOP(result),AOP(left))){ + for(;size--; offset++) { + if(AOP_TYPE(right) == AOP_LIT){ + if(((lit >> (offset*8)) & 0x0FFL) == 0x00L) + continue; + else + if (IS_AOP_PREG(left)) { + MOVA(aopGet(AOP(right),offset,FALSE,FALSE)); + emitcode("orl","a,%s",aopGet(AOP(left),offset,FALSE,TRUE)); + aopPut(AOP(result),"a",offset); + } else + emitcode("orl","%s,%s", + aopGet(AOP(left),offset,FALSE,TRUE), + aopGet(AOP(right),offset,FALSE,FALSE)); + } else { + if (AOP_TYPE(left) == AOP_ACC) + emitcode("orl","a,%s",aopGet(AOP(right),offset,FALSE,FALSE)); + else { + MOVA(aopGet(AOP(right),offset,FALSE,FALSE)); + if (IS_AOP_PREG(left)) { + emitcode("orl","a,%s",aopGet(AOP(left),offset,FALSE,TRUE)); + aopPut(AOP(result),"a",offset); + } else + emitcode("orl","%s,a", + aopGet(AOP(left),offset,FALSE,TRUE)); + } + } + } + } else { + // left & result in different registers + if(AOP_TYPE(result) == AOP_CRY){ + // result = bit + // if(size), result in bit + // if(!size && ifx), conditional oper: if(left | right) + symbol *tlbl = newiTempLabel(NULL); + int sizer = max(AOP_SIZE(left),AOP_SIZE(right)); + if(size) + emitcode("setb","c"); + while(sizer--){ + MOVA(aopGet(AOP(right),offset,FALSE,FALSE)); + emitcode("orl","a,%s", + aopGet(AOP(left),offset,FALSE,FALSE)); + emitcode("jnz","%05d$",tlbl->key+100); + offset++; + } + if(size){ + CLRC; + emitcode("","%05d$:",tlbl->key+100); + outBitC(result); + } else if(ifx) + jmpTrueOrFalse(ifx, tlbl); + } else for(;(size--);offset++){ + // normal case + // result = left & right + if(AOP_TYPE(right) == AOP_LIT){ + if(((lit >> (offset*8)) & 0x0FFL) == 0x00L){ + aopPut(AOP(result), + aopGet(AOP(left),offset,FALSE,FALSE), + offset); + continue; + } + } + // faster than result <- left, anl result,right + // and better if result is SFR + if (AOP_TYPE(left) == AOP_ACC) + emitcode("orl","a,%s",aopGet(AOP(right),offset,FALSE,FALSE)); + else { + MOVA(aopGet(AOP(right),offset,FALSE,FALSE)); + emitcode("orl","a,%s", + aopGet(AOP(left),offset,FALSE,FALSE)); + } + aopPut(AOP(result),"a",offset); + } + } + +release : + freeAsmop(left,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE)); + freeAsmop(right,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE)); + freeAsmop(result,NULL,ic,TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genXor - code for xclusive or */ +/*-----------------------------------------------------------------*/ +static void genXor (iCode *ic, iCode *ifx) +{ + operand *left, *right, *result; + int size, offset=0; + unsigned long lit = 0L; + + aopOp((left = IC_LEFT(ic)),ic,FALSE); + aopOp((right= IC_RIGHT(ic)),ic,FALSE); + aopOp((result=IC_RESULT(ic)),ic,TRUE); + +#ifdef DEBUG_TYPE + emitcode("","; Type res[%d] = l[%d]&r[%d]", + AOP_TYPE(result), + AOP_TYPE(left), AOP_TYPE(right)); + emitcode("","; Size res[%d] = l[%d]&r[%d]", + AOP_SIZE(result), + AOP_SIZE(left), AOP_SIZE(right)); +#endif + + /* if left is a literal & right is not || + if left needs acc & right does not */ + if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) || + (AOP_NEEDSACC(left) && !AOP_NEEDSACC(right))) { + operand *tmp = right ; + right = left; + left = tmp; + } + + /* if result = right then exchange them */ + if(sameRegs(AOP(result),AOP(right))){ + operand *tmp = right ; + right = left; + left = tmp; + } + + /* if right is bit then exchange them */ + if (AOP_TYPE(right) == AOP_CRY && + AOP_TYPE(left) != AOP_CRY){ + operand *tmp = right ; + right = left; + left = tmp; + } + if(AOP_TYPE(right) == AOP_LIT) + lit = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit); + + size = AOP_SIZE(result); + + // if(bit ^ yy) + // xx = bit ^ yy; + if (AOP_TYPE(left) == AOP_CRY){ + if(AOP_TYPE(right) == AOP_LIT){ + // c = bit & literal; + if(lit>>1){ + // lit>>1 != 0 => result = 1 + if(AOP_TYPE(result) == AOP_CRY){ + if(size) + emitcode("setb","%s",AOP(result)->aopu.aop_dir); + else if(ifx) + continueIfTrue(ifx); + goto release; + } + emitcode("setb","c"); + } else{ + // lit == (0 or 1) + if(lit == 0){ + // lit == 0, result = left + if(size && sameRegs(AOP(result),AOP(left))) + goto release; + emitcode("mov","c,%s",AOP(left)->aopu.aop_dir); + } else{ + // lit == 1, result = not(left) + if(size && sameRegs(AOP(result),AOP(left))){ + emitcode("cpl","%s",AOP(result)->aopu.aop_dir); + goto release; + } else { + emitcode("mov","c,%s",AOP(left)->aopu.aop_dir); + emitcode("cpl","c"); + } + } + } + + } else { + // right != literal + symbol *tlbl = newiTempLabel(NULL); + if (AOP_TYPE(right) == AOP_CRY){ + // c = bit ^ bit; + emitcode("mov","c,%s",AOP(right)->aopu.aop_dir); + } + else{ + int sizer = AOP_SIZE(right); + // c = bit ^ val + // if val>>1 != 0, result = 1 + emitcode("setb","c"); + while(sizer){ + MOVA(aopGet(AOP(right),sizer-1,FALSE,FALSE)); + if(sizer == 1) + // test the msb of the lsb + emitcode("anl","a,#0xfe"); + emitcode("jnz","%05d$",tlbl->key+100); + sizer--; + } + // val = (0,1) + emitcode("rrc","a"); + } + emitcode("jnb","%s,%05d$",AOP(left)->aopu.aop_dir,(tlbl->key+100)); + emitcode("cpl","c"); + emitcode("","%05d$:",(tlbl->key+100)); + } + // bit = c + // val = c + if(size) + outBitC(result); + // if(bit | ...) + else if((AOP_TYPE(result) == AOP_CRY) && ifx) + genIfxJump(ifx, "c"); + goto release ; + } + + if(sameRegs(AOP(result),AOP(left))){ + /* if left is same as result */ + for(;size--; offset++) { + if(AOP_TYPE(right) == AOP_LIT){ + if(((lit >> (offset*8)) & 0x0FFL) == 0x00L) + continue; + else + if (IS_AOP_PREG(left)) { + MOVA(aopGet(AOP(right),offset,FALSE,FALSE)); + emitcode("xrl","a,%s",aopGet(AOP(left),offset,FALSE,TRUE)); + aopPut(AOP(result),"a",offset); + } else + emitcode("xrl","%s,%s", + aopGet(AOP(left),offset,FALSE,TRUE), + aopGet(AOP(right),offset,FALSE,FALSE)); + } else { + if (AOP_TYPE(left) == AOP_ACC) + emitcode("xrl","a,%s",aopGet(AOP(right),offset,FALSE,FALSE)); + else { + MOVA(aopGet(AOP(right),offset,FALSE,FALSE)); + if (IS_AOP_PREG(left)) { + emitcode("xrl","a,%s",aopGet(AOP(left),offset,FALSE,TRUE)); + aopPut(AOP(result),"a",offset); + } else + emitcode("xrl","%s,a", + aopGet(AOP(left),offset,FALSE,TRUE)); + } + } + } + } else { + // left & result in different registers + if(AOP_TYPE(result) == AOP_CRY){ + // result = bit + // if(size), result in bit + // if(!size && ifx), conditional oper: if(left ^ right) + symbol *tlbl = newiTempLabel(NULL); + int sizer = max(AOP_SIZE(left),AOP_SIZE(right)); + if(size) + emitcode("setb","c"); + while(sizer--){ + if((AOP_TYPE(right) == AOP_LIT) && + (((lit >> (offset*8)) & 0x0FFL) == 0x00L)){ + MOVA(aopGet(AOP(left),offset,FALSE,FALSE)); + } else { + MOVA(aopGet(AOP(right),offset,FALSE,FALSE)); + emitcode("xrl","a,%s", + aopGet(AOP(left),offset,FALSE,FALSE)); + } + emitcode("jnz","%05d$",tlbl->key+100); + offset++; + } + if(size){ + CLRC; + emitcode("","%05d$:",tlbl->key+100); + outBitC(result); + } else if(ifx) + jmpTrueOrFalse(ifx, tlbl); + } else for(;(size--);offset++){ + // normal case + // result = left & right + if(AOP_TYPE(right) == AOP_LIT){ + if(((lit >> (offset*8)) & 0x0FFL) == 0x00L){ + aopPut(AOP(result), + aopGet(AOP(left),offset,FALSE,FALSE), + offset); + continue; + } + } + // faster than result <- left, anl result,right + // and better if result is SFR + if (AOP_TYPE(left) == AOP_ACC) + emitcode("xrl","a,%s",aopGet(AOP(right),offset,FALSE,FALSE)); + else { + MOVA(aopGet(AOP(right),offset,FALSE,FALSE)); + emitcode("xrl","a,%s", + aopGet(AOP(left),offset,FALSE,TRUE)); + } + aopPut(AOP(result),"a",offset); + } + } + +release : + freeAsmop(left,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE)); + freeAsmop(right,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE)); + freeAsmop(result,NULL,ic,TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genInline - write the inline code out */ +/*-----------------------------------------------------------------*/ +static void genInline (iCode *ic) +{ + char buffer[MAX_INLINEASM]; + char *bp = buffer; + char *bp1= buffer; + + _G.inLine += (!options.asmpeep); + strcpy(buffer,IC_INLINE(ic)); + + /* emit each line as a code */ + while (*bp) { + if (*bp == '\n') { + *bp++ = '\0'; + emitcode(bp1,""); + bp1 = bp; + } else { + if (*bp == ':') { + bp++; + *bp = '\0'; + bp++; + emitcode(bp1,""); + bp1 = bp; + } else + bp++; + } + } + if (bp1 != bp) + emitcode(bp1,""); + /* emitcode("",buffer); */ + _G.inLine -= (!options.asmpeep); +} + +/*-----------------------------------------------------------------*/ +/* genRRC - rotate right with carry */ +/*-----------------------------------------------------------------*/ +static void genRRC (iCode *ic) +{ + operand *left , *result ; + int size, offset = 0; + char *l; + + /* rotate right with carry */ + left = IC_LEFT(ic); + result=IC_RESULT(ic); + aopOp (left,ic,FALSE); + aopOp (result,ic,FALSE); + + /* move it to the result */ + size = AOP_SIZE(result); + offset = size - 1 ; + CLRC; + while (size--) { + l = aopGet(AOP(left),offset,FALSE,FALSE); + MOVA(l); + emitcode("rrc","a"); + if (AOP_SIZE(result) > 1) + aopPut(AOP(result),"a",offset--); + } + /* now we need to put the carry into the + highest order byte of the result */ + if (AOP_SIZE(result) > 1) { + l = aopGet(AOP(result),AOP_SIZE(result)-1,FALSE,FALSE); + MOVA(l); + } + emitcode("mov","acc.7,c"); + aopPut(AOP(result),"a",AOP_SIZE(result)-1); + freeAsmop(left,NULL,ic,TRUE); + freeAsmop(result,NULL,ic,TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genRLC - generate code for rotate left with carry */ +/*-----------------------------------------------------------------*/ +static void genRLC (iCode *ic) +{ + operand *left , *result ; + int size, offset = 0; + char *l; + + /* rotate right with carry */ + left = IC_LEFT(ic); + result=IC_RESULT(ic); + aopOp (left,ic,FALSE); + aopOp (result,ic,FALSE); + + /* move it to the result */ + size = AOP_SIZE(result); + offset = 0 ; + if (size--) { + l = aopGet(AOP(left),offset,FALSE,FALSE); + MOVA(l); + emitcode("add","a,acc"); + if (AOP_SIZE(result) > 1) + aopPut(AOP(result),"a",offset++); + while (size--) { + l = aopGet(AOP(left),offset,FALSE,FALSE); + MOVA(l); + emitcode("rlc","a"); + if (AOP_SIZE(result) > 1) + aopPut(AOP(result),"a",offset++); + } + } + /* now we need to put the carry into the + highest order byte of the result */ + if (AOP_SIZE(result) > 1) { + l = aopGet(AOP(result),0,FALSE,FALSE); + MOVA(l); + } + emitcode("mov","acc.0,c"); + aopPut(AOP(result),"a",0); + freeAsmop(left,NULL,ic,TRUE); + freeAsmop(result,NULL,ic,TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genGetHbit - generates code get highest order bit */ +/*-----------------------------------------------------------------*/ +static void genGetHbit (iCode *ic) +{ + operand *left, *result; + left = IC_LEFT(ic); + result=IC_RESULT(ic); + aopOp (left,ic,FALSE); + aopOp (result,ic,FALSE); + + /* get the highest order byte into a */ + MOVA(aopGet(AOP(left),AOP_SIZE(left) - 1,FALSE,FALSE)); + if(AOP_TYPE(result) == AOP_CRY){ + emitcode("rlc","a"); + outBitC(result); + } + else{ + emitcode("rl","a"); + emitcode("anl","a,#0x01"); + outAcc(result); + } + + + freeAsmop(left,NULL,ic,TRUE); + freeAsmop(result,NULL,ic,TRUE); +} + +/*-----------------------------------------------------------------*/ +/* AccRol - rotate left accumulator by known count */ +/*-----------------------------------------------------------------*/ +static void AccRol (int shCount) +{ + shCount &= 0x0007; // shCount : 0..7 + switch(shCount){ + case 0 : + break; + case 1 : + emitcode("rl","a"); + break; + case 2 : + emitcode("rl","a"); + emitcode("rl","a"); + break; + case 3 : + emitcode("swap","a"); + emitcode("rr","a"); + break; + case 4 : + emitcode("swap","a"); + break; + case 5 : + emitcode("swap","a"); + emitcode("rl","a"); + break; + case 6 : + emitcode("rr","a"); + emitcode("rr","a"); + break; + case 7 : + emitcode("rr","a"); + break; + } +} + +/*-----------------------------------------------------------------*/ +/* AccLsh - left shift accumulator by known count */ +/*-----------------------------------------------------------------*/ +static void AccLsh (int shCount) +{ + if(shCount != 0){ + if(shCount == 1) + emitcode("add","a,acc"); + else + if(shCount == 2) { + emitcode("add","a,acc"); + emitcode("add","a,acc"); + } else { + /* rotate left accumulator */ + AccRol(shCount); + /* and kill the lower order bits */ + emitcode("anl","a,#0x%02x", SLMask[shCount]); + } + } +} + +/*-----------------------------------------------------------------*/ +/* AccRsh - right shift accumulator by known count */ +/*-----------------------------------------------------------------*/ +static void AccRsh (int shCount) +{ + if(shCount != 0){ + if(shCount == 1){ + CLRC; + emitcode("rrc","a"); + } else { + /* rotate right accumulator */ + AccRol(8 - shCount); + /* and kill the higher order bits */ + emitcode("anl","a,#0x%02x", SRMask[shCount]); + } + } +} + +/*-----------------------------------------------------------------*/ +/* AccSRsh - signed right shift accumulator by known count */ +/*-----------------------------------------------------------------*/ +static void AccSRsh (int shCount) +{ + symbol *tlbl ; + if(shCount != 0){ + if(shCount == 1){ + emitcode("mov","c,acc.7"); + emitcode("rrc","a"); + } else if(shCount == 2){ + emitcode("mov","c,acc.7"); + emitcode("rrc","a"); + emitcode("mov","c,acc.7"); + emitcode("rrc","a"); + } else { + tlbl = newiTempLabel(NULL); + /* rotate right accumulator */ + AccRol(8 - shCount); + /* and kill the higher order bits */ + emitcode("anl","a,#0x%02x", SRMask[shCount]); + emitcode("jnb","acc.%d,%05d$",7-shCount,tlbl->key+100); + emitcode("orl","a,#0x%02x", + (unsigned char)~SRMask[shCount]); + emitcode("","%05d$:",tlbl->key+100); + } + } +} + +/*-----------------------------------------------------------------*/ +/* shiftR1Left2Result - shift right one byte from left to result */ +/*-----------------------------------------------------------------*/ +static void shiftR1Left2Result (operand *left, int offl, + operand *result, int offr, + int shCount, int sign) +{ + MOVA(aopGet(AOP(left),offl,FALSE,FALSE)); + /* shift right accumulator */ + if(sign) + AccSRsh(shCount); + else + AccRsh(shCount); + aopPut(AOP(result),"a",offr); +} + +/*-----------------------------------------------------------------*/ +/* shiftL1Left2Result - shift left one byte from left to result */ +/*-----------------------------------------------------------------*/ +static void shiftL1Left2Result (operand *left, int offl, + operand *result, int offr, int shCount) +{ + char *l; + l = aopGet(AOP(left),offl,FALSE,FALSE); + MOVA(l); + /* shift left accumulator */ + AccLsh(shCount); + aopPut(AOP(result),"a",offr); +} + +/*-----------------------------------------------------------------*/ +/* movLeft2Result - move byte from left to result */ +/*-----------------------------------------------------------------*/ +static void movLeft2Result (operand *left, int offl, + operand *result, int offr, int sign) +{ + char *l; + if(!sameRegs(AOP(left),AOP(result)) || (offl != offr)){ + l = aopGet(AOP(left),offl,FALSE,FALSE); + + if (*l == '@' && (IS_AOP_PREG(result))) { + emitcode("mov","a,%s",l); + aopPut(AOP(result),"a",offr); + } else { + if(!sign) + aopPut(AOP(result),l,offr); + else{ + /* MSB sign in acc.7 ! */ + if(getDataSize(left) == offl+1){ + emitcode("mov","a,%s",l); + aopPut(AOP(result),"a",offr); + } + } + } + } +} + +/*-----------------------------------------------------------------*/ +/* AccAXRrl1 - right rotate c->a:x->c by 1 */ +/*-----------------------------------------------------------------*/ +static void AccAXRrl1 (char *x) +{ + emitcode("rrc","a"); + emitcode("xch","a,%s", x); + emitcode("rrc","a"); + emitcode("xch","a,%s", x); +} + +/*-----------------------------------------------------------------*/ +/* AccAXLrl1 - left rotate c<-a:x<-c by 1 */ +/*-----------------------------------------------------------------*/ +static void AccAXLrl1 (char *x) +{ + emitcode("xch","a,%s",x); + emitcode("rlc","a"); + emitcode("xch","a,%s",x); + emitcode("rlc","a"); +} + +/*-----------------------------------------------------------------*/ +/* AccAXLsh1 - left shift a:x<-0 by 1 */ +/*-----------------------------------------------------------------*/ +static void AccAXLsh1 (char *x) +{ + emitcode("xch","a,%s",x); + emitcode("add","a,acc"); + emitcode("xch","a,%s",x); + emitcode("rlc","a"); +} + +/*-----------------------------------------------------------------*/ +/* AccAXLsh - left shift a:x by known count (0..7) */ +/*-----------------------------------------------------------------*/ +static void AccAXLsh (char *x, int shCount) +{ + switch(shCount){ + case 0 : + break; + case 1 : + AccAXLsh1(x); + break; + case 2 : + AccAXLsh1(x); + AccAXLsh1(x); + break; + case 3 : + case 4 : + case 5 : // AAAAABBB:CCCCCDDD + AccRol(shCount); // BBBAAAAA:CCCCCDDD + emitcode("anl","a,#0x%02x", + SLMask[shCount]); // BBB00000:CCCCCDDD + emitcode("xch","a,%s",x); // CCCCCDDD:BBB00000 + AccRol(shCount); // DDDCCCCC:BBB00000 + emitcode("xch","a,%s",x); // BBB00000:DDDCCCCC + emitcode("xrl","a,%s",x); // (BBB^DDD)CCCCC:DDDCCCCC + emitcode("xch","a,%s",x); // DDDCCCCC:(BBB^DDD)CCCCC + emitcode("anl","a,#0x%02x", + SLMask[shCount]); // DDD00000:(BBB^DDD)CCCCC + emitcode("xch","a,%s",x); // (BBB^DDD)CCCCC:DDD00000 + emitcode("xrl","a,%s",x); // BBBCCCCC:DDD00000 + break; + case 6 : // AAAAAABB:CCCCCCDD + emitcode("anl","a,#0x%02x", + SRMask[shCount]); // 000000BB:CCCCCCDD + emitcode("mov","c,acc.0"); // c = B + emitcode("xch","a,%s",x); // CCCCCCDD:000000BB + AccAXRrl1(x); // BCCCCCCD:D000000B + AccAXRrl1(x); // BBCCCCCC:DD000000 + break; + case 7 : // a:x <<= 7 + emitcode("anl","a,#0x%02x", + SRMask[shCount]); // 0000000B:CCCCCCCD + emitcode("mov","c,acc.0"); // c = B + emitcode("xch","a,%s",x); // CCCCCCCD:0000000B + AccAXRrl1(x); // BCCCCCCC:D0000000 + break; + default : + break; + } +} + +/*-----------------------------------------------------------------*/ +/* AccAXRsh - right shift a:x known count (0..7) */ +/*-----------------------------------------------------------------*/ +static void AccAXRsh (char *x, int shCount) +{ + switch(shCount){ + case 0 : + break; + case 1 : + CLRC; + AccAXRrl1(x); // 0->a:x + break; + case 2 : + CLRC; + AccAXRrl1(x); // 0->a:x + CLRC; + AccAXRrl1(x); // 0->a:x + break; + case 3 : + case 4 : + case 5 : // AAAAABBB:CCCCCDDD = a:x + AccRol(8 - shCount); // BBBAAAAA:DDDCCCCC + emitcode("xch","a,%s",x); // CCCCCDDD:BBBAAAAA + AccRol(8 - shCount); // DDDCCCCC:BBBAAAAA + emitcode("anl","a,#0x%02x", + SRMask[shCount]); // 000CCCCC:BBBAAAAA + emitcode("xrl","a,%s",x); // BBB(CCCCC^AAAAA):BBBAAAAA + emitcode("xch","a,%s",x); // BBBAAAAA:BBB(CCCCC^AAAAA) + emitcode("anl","a,#0x%02x", + SRMask[shCount]); // 000AAAAA:BBB(CCCCC^AAAAA) + emitcode("xch","a,%s",x); // BBB(CCCCC^AAAAA):000AAAAA + emitcode("xrl","a,%s",x); // BBBCCCCC:000AAAAA + emitcode("xch","a,%s",x); // 000AAAAA:BBBCCCCC + break; + case 6 : // AABBBBBB:CCDDDDDD + emitcode("mov","c,acc.7"); + AccAXLrl1(x); // ABBBBBBC:CDDDDDDA + AccAXLrl1(x); // BBBBBBCC:DDDDDDAA + emitcode("xch","a,%s",x); // DDDDDDAA:BBBBBBCC + emitcode("anl","a,#0x%02x", + SRMask[shCount]); // 000000AA:BBBBBBCC + break; + case 7 : // ABBBBBBB:CDDDDDDD + emitcode("mov","c,acc.7"); // c = A + AccAXLrl1(x); // BBBBBBBC:DDDDDDDA + emitcode("xch","a,%s",x); // DDDDDDDA:BBBBBBCC + emitcode("anl","a,#0x%02x", + SRMask[shCount]); // 0000000A:BBBBBBBC + break; + default : + break; + } +} + +/*-----------------------------------------------------------------*/ +/* AccAXRshS - right shift signed a:x known count (0..7) */ +/*-----------------------------------------------------------------*/ +static void AccAXRshS (char *x, int shCount) +{ + symbol *tlbl ; + switch(shCount){ + case 0 : + break; + case 1 : + emitcode("mov","c,acc.7"); + AccAXRrl1(x); // s->a:x + break; + case 2 : + emitcode("mov","c,acc.7"); + AccAXRrl1(x); // s->a:x + emitcode("mov","c,acc.7"); + AccAXRrl1(x); // s->a:x + break; + case 3 : + case 4 : + case 5 : // AAAAABBB:CCCCCDDD = a:x + tlbl = newiTempLabel(NULL); + AccRol(8 - shCount); // BBBAAAAA:CCCCCDDD + emitcode("xch","a,%s",x); // CCCCCDDD:BBBAAAAA + AccRol(8 - shCount); // DDDCCCCC:BBBAAAAA + emitcode("anl","a,#0x%02x", + SRMask[shCount]); // 000CCCCC:BBBAAAAA + emitcode("xrl","a,%s",x); // BBB(CCCCC^AAAAA):BBBAAAAA + emitcode("xch","a,%s",x); // BBBAAAAA:BBB(CCCCC^AAAAA) + emitcode("anl","a,#0x%02x", + SRMask[shCount]); // 000AAAAA:BBB(CCCCC^AAAAA) + emitcode("xch","a,%s",x); // BBB(CCCCC^AAAAA):000AAAAA + emitcode("xrl","a,%s",x); // BBBCCCCC:000AAAAA + emitcode("xch","a,%s",x); // 000SAAAA:BBBCCCCC + emitcode("jnb","acc.%d,%05d$",7-shCount,tlbl->key+100); + emitcode("orl","a,#0x%02x", + (unsigned char)~SRMask[shCount]); // 111AAAAA:BBBCCCCC + emitcode("","%05d$:",tlbl->key+100); + break; // SSSSAAAA:BBBCCCCC + case 6 : // AABBBBBB:CCDDDDDD + tlbl = newiTempLabel(NULL); + emitcode("mov","c,acc.7"); + AccAXLrl1(x); // ABBBBBBC:CDDDDDDA + AccAXLrl1(x); // BBBBBBCC:DDDDDDAA + emitcode("xch","a,%s",x); // DDDDDDAA:BBBBBBCC + emitcode("anl","a,#0x%02x", + SRMask[shCount]); // 000000AA:BBBBBBCC + emitcode("jnb","acc.%d,%05d$",7-shCount,tlbl->key+100); + emitcode("orl","a,#0x%02x", + (unsigned char)~SRMask[shCount]); // 111111AA:BBBBBBCC + emitcode("","%05d$:",tlbl->key+100); + break; + case 7 : // ABBBBBBB:CDDDDDDD + tlbl = newiTempLabel(NULL); + emitcode("mov","c,acc.7"); // c = A + AccAXLrl1(x); // BBBBBBBC:DDDDDDDA + emitcode("xch","a,%s",x); // DDDDDDDA:BBBBBBCC + emitcode("anl","a,#0x%02x", + SRMask[shCount]); // 0000000A:BBBBBBBC + emitcode("jnb","acc.%d,%05d$",7-shCount,tlbl->key+100); + emitcode("orl","a,#0x%02x", + (unsigned char)~SRMask[shCount]); // 1111111A:BBBBBBBC + emitcode("","%05d$:",tlbl->key+100); + break; + default : + break; + } +} + +/*-----------------------------------------------------------------*/ +/* shiftL2Left2Result - shift left two bytes from left to result */ +/*-----------------------------------------------------------------*/ +static void shiftL2Left2Result (operand *left, int offl, + operand *result, int offr, int shCount) +{ + if(sameRegs(AOP(result), AOP(left)) && + ((offl + MSB16) == offr)){ + /* don't crash result[offr] */ + MOVA(aopGet(AOP(left),offl,FALSE,FALSE)); + emitcode("xch","a,%s", aopGet(AOP(left),offl+MSB16,FALSE,FALSE)); + } else { + movLeft2Result(left,offl, result, offr, 0); + MOVA(aopGet(AOP(left),offl+MSB16,FALSE,FALSE)); + } + /* ax << shCount (x = lsb(result))*/ + AccAXLsh( aopGet(AOP(result),offr,FALSE,FALSE) , shCount); + aopPut(AOP(result),"a",offr+MSB16); +} + + +/*-----------------------------------------------------------------*/ +/* shiftR2Left2Result - shift right two bytes from left to result */ +/*-----------------------------------------------------------------*/ +static void shiftR2Left2Result (operand *left, int offl, + operand *result, int offr, + int shCount, int sign) +{ + if(sameRegs(AOP(result), AOP(left)) && + ((offl + MSB16) == offr)){ + /* don't crash result[offr] */ + MOVA(aopGet(AOP(left),offl,FALSE,FALSE)); + emitcode("xch","a,%s", aopGet(AOP(left),offl+MSB16,FALSE,FALSE)); + } else { + movLeft2Result(left,offl, result, offr, 0); + MOVA(aopGet(AOP(left),offl+MSB16,FALSE,FALSE)); + } + /* a:x >> shCount (x = lsb(result))*/ + if(sign) + AccAXRshS( aopGet(AOP(result),offr,FALSE,FALSE) , shCount); + else + AccAXRsh( aopGet(AOP(result),offr,FALSE,FALSE) , shCount); + if(getDataSize(result) > 1) + aopPut(AOP(result),"a",offr+MSB16); +} + +/*-----------------------------------------------------------------*/ +/* shiftLLeftOrResult - shift left one byte from left, or to result*/ +/*-----------------------------------------------------------------*/ +static void shiftLLeftOrResult (operand *left, int offl, + operand *result, int offr, int shCount) +{ + MOVA(aopGet(AOP(left),offl,FALSE,FALSE)); + /* shift left accumulator */ + AccLsh(shCount); + /* or with result */ + emitcode("orl","a,%s", aopGet(AOP(result),offr,FALSE,FALSE)); + /* back to result */ + aopPut(AOP(result),"a",offr); +} + +/*-----------------------------------------------------------------*/ +/* shiftRLeftOrResult - shift right one byte from left,or to result*/ +/*-----------------------------------------------------------------*/ +static void shiftRLeftOrResult (operand *left, int offl, + operand *result, int offr, int shCount) +{ + MOVA(aopGet(AOP(left),offl,FALSE,FALSE)); + /* shift right accumulator */ + AccRsh(shCount); + /* or with result */ + emitcode("orl","a,%s", aopGet(AOP(result),offr,FALSE,FALSE)); + /* back to result */ + aopPut(AOP(result),"a",offr); +} + +/*-----------------------------------------------------------------*/ +/* genlshOne - left shift a one byte quantity by known count */ +/*-----------------------------------------------------------------*/ +static void genlshOne (operand *result, operand *left, int shCount) +{ + shiftL1Left2Result(left, LSB, result, LSB, shCount); +} + +/*-----------------------------------------------------------------*/ +/* genlshTwo - left shift two bytes by known amount != 0 */ +/*-----------------------------------------------------------------*/ +static void genlshTwo (operand *result,operand *left, int shCount) +{ + int size; + + size = getDataSize(result); + + /* if shCount >= 8 */ + if (shCount >= 8) { + shCount -= 8 ; + + if (size > 1){ + if (shCount) + shiftL1Left2Result(left, LSB, result, MSB16, shCount); + else + movLeft2Result(left, LSB, result, MSB16, 0); + } + aopPut(AOP(result),zero,LSB); + } + + /* 1 <= shCount <= 7 */ + else { + if(size == 1) + shiftL1Left2Result(left, LSB, result, LSB, shCount); + else + shiftL2Left2Result(left, LSB, result, LSB, shCount); + } +} + +/*-----------------------------------------------------------------*/ +/* shiftLLong - shift left one long from left to result */ +/* offl = LSB or MSB16 */ +/*-----------------------------------------------------------------*/ +static void shiftLLong (operand *left, operand *result, int offr ) +{ + char *l; + int size = AOP_SIZE(result); + + if(size >= LSB+offr){ + l = aopGet(AOP(left),LSB,FALSE,FALSE); + MOVA(l); + emitcode("add","a,acc"); + if (sameRegs(AOP(left),AOP(result)) && + size >= MSB16+offr && offr != LSB ) + emitcode("xch","a,%s", + aopGet(AOP(left),LSB+offr,FALSE,FALSE)); + else + aopPut(AOP(result),"a",LSB+offr); + } + + if(size >= MSB16+offr){ + if (!(sameRegs(AOP(result),AOP(left)) && size >= MSB16+offr && offr != LSB) ) { + l = aopGet(AOP(left),MSB16,FALSE,FALSE); + MOVA(l); + } + emitcode("rlc","a"); + if (sameRegs(AOP(left),AOP(result)) && + size >= MSB24+offr && offr != LSB) + emitcode("xch","a,%s", + aopGet(AOP(left),MSB16+offr,FALSE,FALSE)); + else + aopPut(AOP(result),"a",MSB16+offr); + } + + if(size >= MSB24+offr){ + if (!(sameRegs(AOP(left),AOP(left)) && size >= MSB24+offr && offr != LSB)) { + l = aopGet(AOP(left),MSB24,FALSE,FALSE); + MOVA(l); + } + emitcode("rlc","a"); + if (sameRegs(AOP(left),AOP(result)) && + size >= MSB32+offr && offr != LSB ) + emitcode("xch","a,%s", + aopGet(AOP(left),MSB24+offr,FALSE,FALSE)); + else + aopPut(AOP(result),"a",MSB24+offr); + } + + if(size > MSB32+offr){ + if (!(sameRegs(AOP(result),AOP(left)) && size >= MSB32+offr && offr != LSB)) { + l = aopGet(AOP(left),MSB32,FALSE,FALSE); + MOVA(l); + } + emitcode("rlc","a"); + aopPut(AOP(result),"a",MSB32+offr); + } + if(offr != LSB) + aopPut(AOP(result),zero,LSB); +} + +/*-----------------------------------------------------------------*/ +/* genlshFour - shift four byte by a known amount != 0 */ +/*-----------------------------------------------------------------*/ +static void genlshFour (operand *result, operand *left, int shCount) +{ + int size; + + size = AOP_SIZE(result); + + /* if shifting more that 3 bytes */ + if (shCount >= 24 ) { + shCount -= 24; + if (shCount) + /* lowest order of left goes to the highest + order of the destination */ + shiftL1Left2Result(left, LSB, result, MSB32, shCount); + else + movLeft2Result(left, LSB, result, MSB32, 0); + aopPut(AOP(result),zero,LSB); + aopPut(AOP(result),zero,MSB16); + aopPut(AOP(result),zero,MSB32); + return; + } + + /* more than two bytes */ + else if ( shCount >= 16 ) { + /* lower order two bytes goes to higher order two bytes */ + shCount -= 16; + /* if some more remaining */ + if (shCount) + shiftL2Left2Result(left, LSB, result, MSB24, shCount); + else { + movLeft2Result(left, MSB16, result, MSB32, 0); + movLeft2Result(left, LSB, result, MSB24, 0); + } + aopPut(AOP(result),zero,MSB16); + aopPut(AOP(result),zero,LSB); + return; + } + + /* if more than 1 byte */ + else if ( shCount >= 8 ) { + /* lower order three bytes goes to higher order three bytes */ + shCount -= 8; + if(size == 2){ + if(shCount) + shiftL1Left2Result(left, LSB, result, MSB16, shCount); + else + movLeft2Result(left, LSB, result, MSB16, 0); + } + else{ /* size = 4 */ + if(shCount == 0){ + movLeft2Result(left, MSB24, result, MSB32, 0); + movLeft2Result(left, MSB16, result, MSB24, 0); + movLeft2Result(left, LSB, result, MSB16, 0); + aopPut(AOP(result),zero,LSB); + } + else if(shCount == 1) + shiftLLong(left, result, MSB16); + else{ + shiftL2Left2Result(left, MSB16, result, MSB24, shCount); + shiftL1Left2Result(left, LSB, result, MSB16, shCount); + shiftRLeftOrResult(left, LSB, result, MSB24, 8 - shCount); + aopPut(AOP(result),zero,LSB); + } + } + } + + /* 1 <= shCount <= 7 */ + else if(shCount <= 2){ + shiftLLong(left, result, LSB); + if(shCount == 2) + shiftLLong(result, result, LSB); + } + /* 3 <= shCount <= 7, optimize */ + else{ + shiftL2Left2Result(left, MSB24, result, MSB24, shCount); + shiftRLeftOrResult(left, MSB16, result, MSB24, 8 - shCount); + shiftL2Left2Result(left, LSB, result, LSB, shCount); + } +} + +/*-----------------------------------------------------------------*/ +/* genLeftShiftLiteral - left shifting by known count */ +/*-----------------------------------------------------------------*/ +static void genLeftShiftLiteral (operand *left, + operand *right, + operand *result, + iCode *ic) +{ + int shCount = (int) floatFromVal (AOP(right)->aopu.aop_lit); + int size; + + freeAsmop(right,NULL,ic,TRUE); + + aopOp(left,ic,FALSE); + aopOp(result,ic,FALSE); + + size = getSize(operandType(result)); + +#if VIEW_SIZE + emitcode("; shift left ","result %d, left %d",size, + AOP_SIZE(left)); +#endif + + /* I suppose that the left size >= result size */ + if(shCount == 0){ + while(size--){ + movLeft2Result(left, size, result, size, 0); + } + } + + else if(shCount >= (size * 8)) + while(size--) + aopPut(AOP(result),zero,size); + else{ + switch (size) { + case 1: + genlshOne (result,left,shCount); + break; + + case 2: + case 3: + genlshTwo (result,left,shCount); + break; + + case 4: + genlshFour (result,left,shCount); + break; + } + } + freeAsmop(left,NULL,ic,TRUE); + freeAsmop(result,NULL,ic,TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genLeftShift - generates code for left shifting */ +/*-----------------------------------------------------------------*/ +static void genLeftShift (iCode *ic) +{ + operand *left,*right, *result; + int size, offset; + char *l; + symbol *tlbl , *tlbl1; + + right = IC_RIGHT(ic); + left = IC_LEFT(ic); + result = IC_RESULT(ic); + + aopOp(right,ic,FALSE); + + /* if the shift count is known then do it + as efficiently as possible */ + if (AOP_TYPE(right) == AOP_LIT) { + genLeftShiftLiteral (left,right,result,ic); + return ; + } + + /* shift count is unknown then we have to form + a loop get the loop count in B : Note: we take + only the lower order byte since shifting + more that 32 bits make no sense anyway, ( the + largest size of an object can be only 32 bits ) */ + + emitcode("mov","b,%s",aopGet(AOP(right),0,FALSE,FALSE)); + emitcode("inc","b"); + freeAsmop (right,NULL,ic,TRUE); + aopOp(left,ic,FALSE); + aopOp(result,ic,FALSE); + + /* now move the left to the result if they are not the + same */ + if (!sameRegs(AOP(left),AOP(result)) && + AOP_SIZE(result) > 1) { + + size = AOP_SIZE(result); + offset=0; + while (size--) { + l = aopGet(AOP(left),offset,FALSE,TRUE); + if (*l == '@' && (IS_AOP_PREG(result))) { + + emitcode("mov","a,%s",l); + aopPut(AOP(result),"a",offset); + } else + aopPut(AOP(result),l,offset); + offset++; + } + } + + tlbl = newiTempLabel(NULL); + size = AOP_SIZE(result); + offset = 0 ; + tlbl1 = newiTempLabel(NULL); + + /* if it is only one byte then */ + if (size == 1) { + symbol *tlbl1 = newiTempLabel(NULL); + + l = aopGet(AOP(left),0,FALSE,FALSE); + MOVA(l); + emitcode("sjmp","%05d$",tlbl1->key+100); + emitcode("","%05d$:",tlbl->key+100); + emitcode("add","a,acc"); + emitcode("","%05d$:",tlbl1->key+100); + emitcode("djnz","b,%05d$",tlbl->key+100); + aopPut(AOP(result),"a",0); + goto release ; + } + + reAdjustPreg(AOP(result)); + + emitcode("sjmp","%05d$",tlbl1->key+100); + emitcode("","%05d$:",tlbl->key+100); + l = aopGet(AOP(result),offset,FALSE,FALSE); + MOVA(l); + emitcode("add","a,acc"); + aopPut(AOP(result),"a",offset++); + while (--size) { + l = aopGet(AOP(result),offset,FALSE,FALSE); + MOVA(l); + emitcode("rlc","a"); + aopPut(AOP(result),"a",offset++); + } + reAdjustPreg(AOP(result)); + + emitcode("","%05d$:",tlbl1->key+100); + emitcode("djnz","b,%05d$",tlbl->key+100); +release: + freeAsmop(left,NULL,ic,TRUE); + freeAsmop(result,NULL,ic,TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genrshOne - right shift a one byte quantity by known count */ +/*-----------------------------------------------------------------*/ +static void genrshOne (operand *result, operand *left, + int shCount, int sign) +{ + shiftR1Left2Result(left, LSB, result, LSB, shCount, sign); +} + +/*-----------------------------------------------------------------*/ +/* genrshTwo - right shift two bytes by known amount != 0 */ +/*-----------------------------------------------------------------*/ +static void genrshTwo (operand *result,operand *left, + int shCount, int sign) +{ + /* if shCount >= 8 */ + if (shCount >= 8) { + shCount -= 8 ; + if (shCount) + shiftR1Left2Result(left, MSB16, result, LSB, + shCount, sign); + else + movLeft2Result(left, MSB16, result, LSB, sign); + addSign(result, MSB16, sign); + } + + /* 1 <= shCount <= 7 */ + else + shiftR2Left2Result(left, LSB, result, LSB, shCount, sign); +} + +/*-----------------------------------------------------------------*/ +/* shiftRLong - shift right one long from left to result */ +/* offl = LSB or MSB16 */ +/*-----------------------------------------------------------------*/ +static void shiftRLong (operand *left, int offl, + operand *result, int sign) +{ + if(!sign) + emitcode("clr","c"); + MOVA(aopGet(AOP(left),MSB32,FALSE,FALSE)); + if(sign) + emitcode("mov","c,acc.7"); + emitcode("rrc","a"); + aopPut(AOP(result),"a",MSB32-offl); + if(offl == MSB16) + /* add sign of "a" */ + addSign(result, MSB32, sign); + + MOVA(aopGet(AOP(left),MSB24,FALSE,FALSE)); + emitcode("rrc","a"); + aopPut(AOP(result),"a",MSB24-offl); + + MOVA(aopGet(AOP(left),MSB16,FALSE,FALSE)); + emitcode("rrc","a"); + aopPut(AOP(result),"a",MSB16-offl); + + if(offl == LSB){ + MOVA(aopGet(AOP(left),LSB,FALSE,FALSE)); + emitcode("rrc","a"); + aopPut(AOP(result),"a",LSB); + } +} + +/*-----------------------------------------------------------------*/ +/* genrshFour - shift four byte by a known amount != 0 */ +/*-----------------------------------------------------------------*/ +static void genrshFour (operand *result, operand *left, + int shCount, int sign) +{ + /* if shifting more that 3 bytes */ + if(shCount >= 24 ) { + shCount -= 24; + if(shCount) + shiftR1Left2Result(left, MSB32, result, LSB, shCount, sign); + else + movLeft2Result(left, MSB32, result, LSB, sign); + addSign(result, MSB16, sign); + } + else if(shCount >= 16){ + shCount -= 16; + if(shCount) + shiftR2Left2Result(left, MSB24, result, LSB, shCount, sign); + else{ + movLeft2Result(left, MSB24, result, LSB, 0); + movLeft2Result(left, MSB32, result, MSB16, sign); + } + addSign(result, MSB24, sign); + } + else if(shCount >= 8){ + shCount -= 8; + if(shCount == 1) + shiftRLong(left, MSB16, result, sign); + else if(shCount == 0){ + movLeft2Result(left, MSB16, result, LSB, 0); + movLeft2Result(left, MSB24, result, MSB16, 0); + movLeft2Result(left, MSB32, result, MSB24, sign); + addSign(result, MSB32, sign); + } + else{ + shiftR2Left2Result(left, MSB16, result, LSB, shCount, 0); + shiftLLeftOrResult(left, MSB32, result, MSB16, 8 - shCount); + /* the last shift is signed */ + shiftR1Left2Result(left, MSB32, result, MSB24, shCount, sign); + addSign(result, MSB32, sign); + } + } + else{ /* 1 <= shCount <= 7 */ + if(shCount <= 2){ + shiftRLong(left, LSB, result, sign); + if(shCount == 2) + shiftRLong(result, LSB, result, sign); + } + else{ + shiftR2Left2Result(left, LSB, result, LSB, shCount, 0); + shiftLLeftOrResult(left, MSB24, result, MSB16, 8 - shCount); + shiftR2Left2Result(left, MSB24, result, MSB24, shCount, sign); + } + } +} + +/*-----------------------------------------------------------------*/ +/* genRightShiftLiteral - right shifting by known count */ +/*-----------------------------------------------------------------*/ +static void genRightShiftLiteral (operand *left, + operand *right, + operand *result, + iCode *ic, + int sign) +{ + int shCount = (int) floatFromVal (AOP(right)->aopu.aop_lit); + int size; + + freeAsmop(right,NULL,ic,TRUE); + + aopOp(left,ic,FALSE); + aopOp(result,ic,FALSE); + +#if VIEW_SIZE + emitcode("; shift right ","result %d, left %d",AOP_SIZE(result), + AOP_SIZE(left)); +#endif + + size = getDataSize(left); + /* test the LEFT size !!! */ + + /* I suppose that the left size >= result size */ + if(shCount == 0){ + size = getDataSize(result); + while(size--) + movLeft2Result(left, size, result, size, 0); + } + + else if(shCount >= (size * 8)){ + if(sign) + /* get sign in acc.7 */ + MOVA(aopGet(AOP(left),size-1,FALSE,FALSE)); + addSign(result, LSB, sign); + } else{ + switch (size) { + case 1: + genrshOne (result,left,shCount,sign); + break; + + case 2: + genrshTwo (result,left,shCount,sign); + break; + + case 4: + genrshFour (result,left,shCount,sign); + break; + default : + break; + } + + freeAsmop(left,NULL,ic,TRUE); + freeAsmop(result,NULL,ic,TRUE); + } +} + +/*-----------------------------------------------------------------*/ +/* genSignedRightShift - right shift of signed number */ +/*-----------------------------------------------------------------*/ +static void genSignedRightShift (iCode *ic) +{ + operand *right, *left, *result; + int size, offset; + char *l; + symbol *tlbl, *tlbl1 ; + + /* we do it the hard way put the shift count in b + and loop thru preserving the sign */ + + right = IC_RIGHT(ic); + left = IC_LEFT(ic); + result = IC_RESULT(ic); + + aopOp(right,ic,FALSE); + + + if ( AOP_TYPE(right) == AOP_LIT) { + genRightShiftLiteral (left,right,result,ic,1); + return ; + } + /* shift count is unknown then we have to form + a loop get the loop count in B : Note: we take + only the lower order byte since shifting + more that 32 bits make no sense anyway, ( the + largest size of an object can be only 32 bits ) */ + + emitcode("mov","b,%s",aopGet(AOP(right),0,FALSE,FALSE)); + emitcode("inc","b"); + freeAsmop (right,NULL,ic,TRUE); + aopOp(left,ic,FALSE); + aopOp(result,ic,FALSE); + + /* now move the left to the result if they are not the + same */ + if (!sameRegs(AOP(left),AOP(result)) && + AOP_SIZE(result) > 1) { + + size = AOP_SIZE(result); + offset=0; + while (size--) { + l = aopGet(AOP(left),offset,FALSE,TRUE); + if (*l == '@' && IS_AOP_PREG(result)) { + + emitcode("mov","a,%s",l); + aopPut(AOP(result),"a",offset); + } else + aopPut(AOP(result),l,offset); + offset++; + } + } + + /* mov the highest order bit to OVR */ + tlbl = newiTempLabel(NULL); + tlbl1= newiTempLabel(NULL); + + size = AOP_SIZE(result); + offset = size - 1; + emitcode("mov","a,%s",aopGet(AOP(left),offset,FALSE,FALSE)); + emitcode("rlc","a"); + emitcode("mov","ov,c"); + /* if it is only one byte then */ + if (size == 1) { + l = aopGet(AOP(left),0,FALSE,FALSE); + MOVA(l); + emitcode("sjmp","%05d$",tlbl1->key+100); + emitcode("","%05d$:",tlbl->key+100); + emitcode("mov","c,ov"); + emitcode("rrc","a"); + emitcode("","%05d$:",tlbl1->key+100); + emitcode("djnz","b,%05d$",tlbl->key+100); + aopPut(AOP(result),"a",0); + goto release ; + } + + reAdjustPreg(AOP(result)); + emitcode("sjmp","%05d$",tlbl1->key+100); + emitcode("","%05d$:",tlbl->key+100); + emitcode("mov","c,ov"); + while (size--) { + l = aopGet(AOP(result),offset,FALSE,FALSE); + MOVA(l); + emitcode("rrc","a"); + aopPut(AOP(result),"a",offset--); + } + reAdjustPreg(AOP(result)); + emitcode("","%05d$:",tlbl1->key+100); + emitcode("djnz","b,%05d$",tlbl->key+100); + +release: + freeAsmop(left,NULL,ic,TRUE); + freeAsmop(result,NULL,ic,TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genRightShift - generate code for right shifting */ +/*-----------------------------------------------------------------*/ +static void genRightShift (iCode *ic) +{ + operand *right, *left, *result; + link *retype ; + int size, offset; + char *l; + symbol *tlbl, *tlbl1 ; + + /* if signed then we do it the hard way preserve the + sign bit moving it inwards */ + retype = getSpec(operandType(IC_RESULT(ic))); + + if (!SPEC_USIGN(retype)) { + genSignedRightShift (ic); + return ; + } + + /* signed & unsigned types are treated the same : i.e. the + signed is NOT propagated inwards : quoting from the + ANSI - standard : "for E1 >> E2, is equivalent to division + by 2**E2 if unsigned or if it has a non-negative value, + otherwise the result is implementation defined ", MY definition + is that the sign does not get propagated */ + + right = IC_RIGHT(ic); + left = IC_LEFT(ic); + result = IC_RESULT(ic); + + aopOp(right,ic,FALSE); + + /* if the shift count is known then do it + as efficiently as possible */ + if (AOP_TYPE(right) == AOP_LIT) { + genRightShiftLiteral (left,right,result,ic, 0); + return ; + } + + /* shift count is unknown then we have to form + a loop get the loop count in B : Note: we take + only the lower order byte since shifting + more that 32 bits make no sense anyway, ( the + largest size of an object can be only 32 bits ) */ + + emitcode("mov","b,%s",aopGet(AOP(right),0,FALSE,FALSE)); + emitcode("inc","b"); + freeAsmop (right,NULL,ic,TRUE); + aopOp(left,ic,FALSE); + aopOp(result,ic,FALSE); + + /* now move the left to the result if they are not the + same */ + if (!sameRegs(AOP(left),AOP(result)) && + AOP_SIZE(result) > 1) { + + size = AOP_SIZE(result); + offset=0; + while (size--) { + l = aopGet(AOP(left),offset,FALSE,TRUE); + if (*l == '@' && IS_AOP_PREG(result)) { + + emitcode("mov","a,%s",l); + aopPut(AOP(result),"a",offset); + } else + aopPut(AOP(result),l,offset); + offset++; + } + } + + tlbl = newiTempLabel(NULL); + tlbl1= newiTempLabel(NULL); + size = AOP_SIZE(result); + offset = size - 1; + + /* if it is only one byte then */ + if (size == 1) { + l = aopGet(AOP(left),0,FALSE,FALSE); + MOVA(l); + emitcode("sjmp","%05d$",tlbl1->key+100); + emitcode("","%05d$:",tlbl->key+100); + CLRC; + emitcode("rrc","a"); + emitcode("","%05d$:",tlbl1->key+100); + emitcode("djnz","b,%05d$",tlbl->key+100); + aopPut(AOP(result),"a",0); + goto release ; + } + + reAdjustPreg(AOP(result)); + emitcode("sjmp","%05d$",tlbl1->key+100); + emitcode("","%05d$:",tlbl->key+100); + CLRC; + while (size--) { + l = aopGet(AOP(result),offset,FALSE,FALSE); + MOVA(l); + emitcode("rrc","a"); + aopPut(AOP(result),"a",offset--); + } + reAdjustPreg(AOP(result)); + + emitcode("","%05d$:",tlbl1->key+100); + emitcode("djnz","b,%05d$",tlbl->key+100); + +release: + freeAsmop(left,NULL,ic,TRUE); + freeAsmop(result,NULL,ic,TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genUnpackBits - generates code for unpacking bits */ +/*-----------------------------------------------------------------*/ +static void genUnpackBits (operand *result, char *rname, int ptype) +{ + int shCnt ; + int rlen = 0 ; + link *etype; + int offset = 0 ; + + etype = getSpec(operandType(result)); + + /* read the first byte */ + switch (ptype) { + + case POINTER: + case IPOINTER: + emitcode("mov","a,@%s",rname); + break; + + case PPOINTER: + emitcode("movx","a,@%s",rname); + break; + + case FPOINTER: + emitcode("movx","a,@dptr"); + break; + + case CPOINTER: + emitcode("clr","a"); + emitcode("movc","a","@a+dptr"); + break; + + case GPOINTER: + emitcode("lcall","__gptrget"); + break; + } + + /* if we have bitdisplacement then it fits */ + /* into this byte completely or if length is */ + /* less than a byte */ + if ((shCnt = SPEC_BSTR(etype)) || + (SPEC_BLEN(etype) <= 8)) { + + /* shift right acc */ + AccRsh(shCnt); + + emitcode("anl","a,#0x%02x", + ((unsigned char) -1)>>(8 - SPEC_BLEN(etype))); + aopPut(AOP(result),"a",offset); + return ; + } + + /* bit field did not fit in a byte */ + rlen = SPEC_BLEN(etype) - 8; + aopPut(AOP(result),"a",offset++); + + while (1) { + + switch (ptype) { + case POINTER: + case IPOINTER: + emitcode("inc","%s",rname); + emitcode("mov","a,@%s",rname); + break; + + case PPOINTER: + emitcode("inc","%s",rname); + emitcode("movx","a,@%s",rname); + break; + + case FPOINTER: + emitcode("inc","dptr"); + emitcode("movx","a,@dptr"); + break; + + case CPOINTER: + emitcode("clr","a"); + emitcode("inc","dptr"); + emitcode("movc","a","@a+dptr"); + break; + + case GPOINTER: + emitcode("inc","dptr"); + emitcode("lcall","__gptrget"); + break; + } + + rlen -= 8; + /* if we are done */ + if ( rlen <= 0 ) + break ; + + aopPut(AOP(result),"a",offset++); + + } + + if (rlen) { + emitcode("anl","a,#0x%02x",((unsigned char)-1)>>(-rlen)); + aopPut(AOP(result),"a",offset); + } + + return ; +} + + +/*-----------------------------------------------------------------*/ +/* genDataPointerGet - generates code when ptr offset is known */ +/*-----------------------------------------------------------------*/ +static void genDataPointerGet (operand *left, + operand *result, + iCode *ic) +{ + char *l; + char buffer[256]; + int size , offset = 0; + aopOp(result,ic,TRUE); + + /* get the string representation of the name */ + l = aopGet(AOP(left),0,FALSE,TRUE); + size = AOP_SIZE(result); + while (size--) { + if (offset) + sprintf(buffer,"(%s + %d)",l+1,offset); + else + sprintf(buffer,"%s",l+1); + aopPut(AOP(result),buffer,offset++); + } + + freeAsmop(left,NULL,ic,TRUE); + freeAsmop(result,NULL,ic,TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genNearPointerGet - emitcode for near pointer fetch */ +/*-----------------------------------------------------------------*/ +static void genNearPointerGet (operand *left, + operand *result, + iCode *ic) +{ + asmop *aop = NULL; + regs *preg = NULL ; + char *rname ; + link *rtype, *retype; + link *ltype = operandType(left); + char buffer[80]; + + rtype = operandType(result); + retype= getSpec(rtype); + + aopOp(left,ic,FALSE); + + /* if left is rematerialisable and + result is not bit variable type and + the left is pointer to data space i.e + lower 128 bytes of space */ + if (AOP_TYPE(left) == AOP_IMMD && + !IS_BITVAR(retype) && + DCL_TYPE(ltype) == POINTER) { + genDataPointerGet (left,result,ic); + return ; + } + + /* if the value is already in a pointer register + then don't need anything more */ + if (!AOP_INPREG(AOP(left))) { + /* otherwise get a free pointer register */ + aop = newAsmop(0); + preg = getFreePtr(ic,&aop,FALSE); + emitcode("mov","%s,%s", + preg->name, + aopGet(AOP(left),0,FALSE,TRUE)); + rname = preg->name ; + } else + rname = aopGet(AOP(left),0,FALSE,FALSE); + + freeAsmop(left,NULL,ic,TRUE); + aopOp (result,ic,FALSE); + + /* if bitfield then unpack the bits */ + if (IS_BITVAR(retype)) + genUnpackBits (result,rname,POINTER); + else { + /* we have can just get the values */ + int size = AOP_SIZE(result); + int offset = 0 ; + + while (size--) { + if (IS_AOP_PREG(result) || AOP_TYPE(result) == AOP_STK ) { + + emitcode("mov","a,@%s",rname); + aopPut(AOP(result),"a",offset); + } else { + sprintf(buffer,"@%s",rname); + aopPut(AOP(result),buffer,offset); + } + offset++ ; + if (size) + emitcode("inc","%s",rname); + } + } + + /* now some housekeeping stuff */ + if (aop) { + /* we had to allocate for this iCode */ + freeAsmop(NULL,aop,ic,TRUE); + } else { + /* we did not allocate which means left + already in a pointer register, then + if size > 0 && this could be used again + we have to point it back to where it + belongs */ + if (AOP_SIZE(result) > 1 && + !OP_SYMBOL(left)->remat && + ( OP_SYMBOL(left)->liveTo > ic->seq || + ic->depth )) { + int size = AOP_SIZE(result) - 1; + while (size--) + emitcode("dec","%s",rname); + } + } + + /* done */ + freeAsmop(result,NULL,ic,TRUE); + +} + +/*-----------------------------------------------------------------*/ +/* genPagedPointerGet - emitcode for paged pointer fetch */ +/*-----------------------------------------------------------------*/ +static void genPagedPointerGet (operand *left, + operand *result, + iCode *ic) +{ + asmop *aop = NULL; + regs *preg = NULL ; + char *rname ; + link *rtype, *retype; + + rtype = operandType(result); + retype= getSpec(rtype); + + aopOp(left,ic,FALSE); + + /* if the value is already in a pointer register + then don't need anything more */ + if (!AOP_INPREG(AOP(left))) { + /* otherwise get a free pointer register */ + aop = newAsmop(0); + preg = getFreePtr(ic,&aop,FALSE); + emitcode("mov","%s,%s", + preg->name, + aopGet(AOP(left),0,FALSE,TRUE)); + rname = preg->name ; + } else + rname = aopGet(AOP(left),0,FALSE,FALSE); + + freeAsmop(left,NULL,ic,TRUE); + aopOp (result,ic,FALSE); + + /* if bitfield then unpack the bits */ + if (IS_BITVAR(retype)) + genUnpackBits (result,rname,PPOINTER); + else { + /* we have can just get the values */ + int size = AOP_SIZE(result); + int offset = 0 ; + + while (size--) { + + emitcode("movx","a,@%s",rname); + aopPut(AOP(result),"a",offset); + + offset++ ; + + if (size) + emitcode("inc","%s",rname); + } + } + + /* now some housekeeping stuff */ + if (aop) { + /* we had to allocate for this iCode */ + freeAsmop(NULL,aop,ic,TRUE); + } else { + /* we did not allocate which means left + already in a pointer register, then + if size > 0 && this could be used again + we have to point it back to where it + belongs */ + if (AOP_SIZE(result) > 1 && + !OP_SYMBOL(left)->remat && + ( OP_SYMBOL(left)->liveTo > ic->seq || + ic->depth )) { + int size = AOP_SIZE(result) - 1; + while (size--) + emitcode("dec","%s",rname); + } + } + + /* done */ + freeAsmop(result,NULL,ic,TRUE); + + +} + +/*-----------------------------------------------------------------*/ +/* genFarPointerGet - gget value from far space */ +/*-----------------------------------------------------------------*/ +static void genFarPointerGet (operand *left, + operand *result, iCode *ic) +{ + int size, offset ; + link *retype = getSpec(operandType(result)); + + aopOp(left,ic,FALSE); + + /* if the operand is already in dptr + then we do nothing else we move the value to dptr */ + if (AOP_TYPE(left) != AOP_STR) { + /* if this is remateriazable */ + if (AOP_TYPE(left) == AOP_IMMD) + emitcode("mov","dptr,%s",aopGet(AOP(left),0,TRUE,FALSE)); + else { /* we need to get it byte by byte */ + emitcode("mov","dpl,%s",aopGet(AOP(left),0,FALSE,FALSE)); + emitcode("mov","dph,%s",aopGet(AOP(left),1,FALSE,FALSE)); + if (options.model == MODEL_FLAT24) + { + emitcode("mov", "dpx,%s",aopGet(AOP(left),2,FALSE,FALSE)); + } + } + } + /* so dptr know contains the address */ + freeAsmop(left,NULL,ic,TRUE); + aopOp(result,ic,FALSE); + + /* if bit then unpack */ + if (IS_BITVAR(retype)) + genUnpackBits(result,"dptr",FPOINTER); + else { + size = AOP_SIZE(result); + offset = 0 ; + + while (size--) { + emitcode("movx","a,@dptr"); + aopPut(AOP(result),"a",offset++); + if (size) + emitcode("inc","dptr"); + } + } + + freeAsmop(result,NULL,ic,TRUE); +} + +/*-----------------------------------------------------------------*/ +/* emitcodePointerGet - gget value from code space */ +/*-----------------------------------------------------------------*/ +static void emitcodePointerGet (operand *left, + operand *result, iCode *ic) +{ + int size, offset ; + link *retype = getSpec(operandType(result)); + + aopOp(left,ic,FALSE); + + /* if the operand is already in dptr + then we do nothing else we move the value to dptr */ + if (AOP_TYPE(left) != AOP_STR) { + /* if this is remateriazable */ + if (AOP_TYPE(left) == AOP_IMMD) + emitcode("mov","dptr,%s",aopGet(AOP(left),0,TRUE,FALSE)); + else { /* we need to get it byte by byte */ + emitcode("mov","dpl,%s",aopGet(AOP(left),0,FALSE,FALSE)); + emitcode("mov","dph,%s",aopGet(AOP(left),1,FALSE,FALSE)); + if (options.model == MODEL_FLAT24) + { + emitcode("mov", "dpx,%s",aopGet(AOP(left),2,FALSE,FALSE)); + } + } + } + /* so dptr know contains the address */ + freeAsmop(left,NULL,ic,TRUE); + aopOp(result,ic,FALSE); + + /* if bit then unpack */ + if (IS_BITVAR(retype)) + genUnpackBits(result,"dptr",CPOINTER); + else { + size = AOP_SIZE(result); + offset = 0 ; + + while (size--) { + emitcode("clr","a"); + emitcode("movc","a,@a+dptr"); + aopPut(AOP(result),"a",offset++); + if (size) + emitcode("inc","dptr"); + } + } + + freeAsmop(result,NULL,ic,TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genGenPointerGet - gget value from generic pointer space */ +/*-----------------------------------------------------------------*/ +static void genGenPointerGet (operand *left, + operand *result, iCode *ic) +{ + int size, offset ; + link *retype = getSpec(operandType(result)); + + aopOp(left,ic,FALSE); + + /* if the operand is already in dptr + then we do nothing else we move the value to dptr */ + if (AOP_TYPE(left) != AOP_STR) { + /* if this is remateriazable */ + if (AOP_TYPE(left) == AOP_IMMD) { + emitcode("mov","dptr,%s",aopGet(AOP(left),0,TRUE,FALSE)); + emitcode("mov","b,#%d",pointerCode(retype)); + } + else { /* we need to get it byte by byte */ + emitcode("mov","dpl,%s",aopGet(AOP(left),0,FALSE,FALSE)); + emitcode("mov","dph,%s",aopGet(AOP(left),1,FALSE,FALSE)); + if (options.model == MODEL_FLAT24) + { + emitcode("mov", "dpx,%s",aopGet(AOP(left),2,FALSE,FALSE)); + emitcode("mov","b,%s",aopGet(AOP(left),3,FALSE,FALSE)); + } + else + { + emitcode("mov","b,%s",aopGet(AOP(left),2,FALSE,FALSE)); + } + } + } + /* so dptr know contains the address */ + freeAsmop(left,NULL,ic,TRUE); + aopOp(result,ic,FALSE); + + /* if bit then unpack */ + if (IS_BITVAR(retype)) + genUnpackBits(result,"dptr",GPOINTER); + else { + size = AOP_SIZE(result); + offset = 0 ; + + while (size--) { + emitcode("lcall","__gptrget"); + aopPut(AOP(result),"a",offset++); + if (size) + emitcode("inc","dptr"); + } + } + + freeAsmop(result,NULL,ic,TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genPointerGet - generate code for pointer get */ +/*-----------------------------------------------------------------*/ +static void genPointerGet (iCode *ic) +{ + operand *left, *result ; + link *type, *etype; + int p_type; + + left = IC_LEFT(ic); + result = IC_RESULT(ic) ; + + /* depending on the type of pointer we need to + move it to the correct pointer register */ + type = operandType(left); + etype = getSpec(type); + /* if left is of type of pointer then it is simple */ + if (IS_PTR(type) && !IS_FUNC(type->next)) + p_type = DCL_TYPE(type); + else { + /* we have to go by the storage class */ + p_type = PTR_TYPE(SPEC_OCLS(etype)); + +/* if (SPEC_OCLS(etype)->codesp ) { */ +/* p_type = CPOINTER ; */ +/* } */ +/* else */ +/* if (SPEC_OCLS(etype)->fmap && !SPEC_OCLS(etype)->paged) */ +/* p_type = FPOINTER ; */ +/* else */ +/* if (SPEC_OCLS(etype)->fmap && SPEC_OCLS(etype)->paged) */ +/* p_type = PPOINTER; */ +/* else */ +/* if (SPEC_OCLS(etype) == idata ) */ +/* p_type = IPOINTER; */ +/* else */ +/* p_type = POINTER ; */ + } + + /* now that we have the pointer type we assign + the pointer values */ + switch (p_type) { + + case POINTER: + case IPOINTER: + genNearPointerGet (left,result,ic); + break; + + case PPOINTER: + genPagedPointerGet(left,result,ic); + break; + + case FPOINTER: + genFarPointerGet (left,result,ic); + break; + + case CPOINTER: + emitcodePointerGet (left,result,ic); + break; + + case GPOINTER: + genGenPointerGet (left,result,ic); + break; + } + +} + +/*-----------------------------------------------------------------*/ +/* genPackBits - generates code for packed bit storage */ +/*-----------------------------------------------------------------*/ +static void genPackBits (link *etype , + operand *right , + char *rname, int p_type) +{ + int shCount = 0 ; + int offset = 0 ; + int rLen = 0 ; + int blen, bstr ; + char *l ; + + blen = SPEC_BLEN(etype); + bstr = SPEC_BSTR(etype); + + l = aopGet(AOP(right),offset++,FALSE,FALSE); + MOVA(l); + + /* if the bit lenth is less than or */ + /* it exactly fits a byte then */ + if (SPEC_BLEN(etype) <= 8 ) { + shCount = SPEC_BSTR(etype) ; + + /* shift left acc */ + AccLsh(shCount); + + if (SPEC_BLEN(etype) < 8 ) { /* if smaller than a byte */ + + + switch (p_type) { + case POINTER: + emitcode ("mov","b,a"); + emitcode("mov","a,@%s",rname); + break; + + case FPOINTER: + emitcode ("mov","b,a"); + emitcode("movx","a,@dptr"); + break; + + case GPOINTER: + emitcode ("push","b"); + emitcode ("push","acc"); + emitcode ("lcall","__gptrget"); + emitcode ("pop","b"); + break; + } + + emitcode ("anl","a,#0x%02x",(unsigned char) + ((unsigned char)(0xFF << (blen+bstr)) | + (unsigned char)(0xFF >> (8-bstr)) ) ); + emitcode ("orl","a,b"); + if (p_type == GPOINTER) + emitcode("pop","b"); + } + } + + switch (p_type) { + case POINTER: + emitcode("mov","@%s,a",rname); + break; + + case FPOINTER: + emitcode("movx","@dptr,a"); + break; + + case GPOINTER: + emitcode("lcall","__gptrput"); + break; + } + + /* if we r done */ + if ( SPEC_BLEN(etype) <= 8 ) + return ; + + emitcode("inc","%s",rname); + rLen = SPEC_BLEN(etype) ; + + /* now generate for lengths greater than one byte */ + while (1) { + + l = aopGet(AOP(right),offset++,FALSE,TRUE); + + rLen -= 8 ; + if (rLen <= 0 ) + break ; + + switch (p_type) { + case POINTER: + if (*l == '@') { + MOVA(l); + emitcode("mov","@%s,a",rname); + } else + emitcode("mov","@%s,%s",rname,l); + break; + + case FPOINTER: + MOVA(l); + emitcode("movx","@dptr,a"); + break; + + case GPOINTER: + MOVA(l); + emitcode("lcall","__gptrput"); + break; + } + emitcode ("inc","%s",rname); + } + + MOVA(l); + + /* last last was not complete */ + if (rLen) { + /* save the byte & read byte */ + switch (p_type) { + case POINTER: + emitcode ("mov","b,a"); + emitcode("mov","a,@%s",rname); + break; + + case FPOINTER: + emitcode ("mov","b,a"); + emitcode("movx","a,@dptr"); + break; + + case GPOINTER: + emitcode ("push","b"); + emitcode ("push","acc"); + emitcode ("lcall","__gptrget"); + emitcode ("pop","b"); + break; + } + + emitcode ("anl","a,#0x%02x",((unsigned char)-1 << -rLen) ); + emitcode ("orl","a,b"); + } + + if (p_type == GPOINTER) + emitcode("pop","b"); + + switch (p_type) { + + case POINTER: + emitcode("mov","@%s,a",rname); + break; + + case FPOINTER: + emitcode("movx","@dptr,a"); + break; + + case GPOINTER: + emitcode("lcall","__gptrput"); + break; + } +} +/*-----------------------------------------------------------------*/ +/* genDataPointerSet - remat pointer to data space */ +/*-----------------------------------------------------------------*/ +static void genDataPointerSet(operand *right, + operand *result, + iCode *ic) +{ + int size, offset = 0 ; + char *l, buffer[256]; + + aopOp(right,ic,FALSE); + + l = aopGet(AOP(result),0,FALSE,TRUE); + size = AOP_SIZE(right); + while (size--) { + if (offset) + sprintf(buffer,"(%s + %d)",l+1,offset); + else + sprintf(buffer,"%s",l+1); + emitcode("mov","%s,%s",buffer, + aopGet(AOP(right),offset++,FALSE,FALSE)); + } + + freeAsmop(right,NULL,ic,TRUE); + freeAsmop(result,NULL,ic,TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genNearPointerSet - emitcode for near pointer put */ +/*-----------------------------------------------------------------*/ +static void genNearPointerSet (operand *right, + operand *result, + iCode *ic) +{ + asmop *aop = NULL; + regs *preg = NULL ; + char *rname , *l; + link *retype; + link *ptype = operandType(result); + + retype= getSpec(operandType(right)); + + aopOp(result,ic,FALSE); + + /* if the result is rematerializable & + in data space & not a bit variable */ + if (AOP_TYPE(result) == AOP_IMMD && + DCL_TYPE(ptype) == POINTER && + !IS_BITVAR(retype)) { + genDataPointerSet (right,result,ic); + return; + } + + /* if the value is already in a pointer register + then don't need anything more */ + if (!AOP_INPREG(AOP(result))) { + /* otherwise get a free pointer register */ + aop = newAsmop(0); + preg = getFreePtr(ic,&aop,FALSE); + emitcode("mov","%s,%s", + preg->name, + aopGet(AOP(result),0,FALSE,TRUE)); + rname = preg->name ; + } else + rname = aopGet(AOP(result),0,FALSE,FALSE); + + freeAsmop(result,NULL,ic,TRUE); + aopOp (right,ic,FALSE); + + /* if bitfield then unpack the bits */ + if (IS_BITVAR(retype)) + genPackBits (retype,right,rname,POINTER); + else { + /* we have can just get the values */ + int size = AOP_SIZE(right); + int offset = 0 ; + + while (size--) { + l = aopGet(AOP(right),offset,FALSE,TRUE); + if (*l == '@' ) { + MOVA(l); + emitcode("mov","@%s,a",rname); + } else + emitcode("mov","@%s,%s",rname,l); + if (size) + emitcode("inc","%s",rname); + offset++; + } + } + + /* now some housekeeping stuff */ + if (aop) { + /* we had to allocate for this iCode */ + freeAsmop(NULL,aop,ic,TRUE); + } else { + /* we did not allocate which means left + already in a pointer register, then + if size > 0 && this could be used again + we have to point it back to where it + belongs */ + if (AOP_SIZE(right) > 1 && + !OP_SYMBOL(result)->remat && + ( OP_SYMBOL(result)->liveTo > ic->seq || + ic->depth )) { + int size = AOP_SIZE(right) - 1; + while (size--) + emitcode("dec","%s",rname); + } + } + + /* done */ + freeAsmop(right,NULL,ic,TRUE); + + +} + +/*-----------------------------------------------------------------*/ +/* genPagedPointerSet - emitcode for Paged pointer put */ +/*-----------------------------------------------------------------*/ +static void genPagedPointerSet (operand *right, + operand *result, + iCode *ic) +{ + asmop *aop = NULL; + regs *preg = NULL ; + char *rname , *l; + link *retype; + + retype= getSpec(operandType(right)); + + aopOp(result,ic,FALSE); + + /* if the value is already in a pointer register + then don't need anything more */ + if (!AOP_INPREG(AOP(result))) { + /* otherwise get a free pointer register */ + aop = newAsmop(0); + preg = getFreePtr(ic,&aop,FALSE); + emitcode("mov","%s,%s", + preg->name, + aopGet(AOP(result),0,FALSE,TRUE)); + rname = preg->name ; + } else + rname = aopGet(AOP(result),0,FALSE,FALSE); + + freeAsmop(result,NULL,ic,TRUE); + aopOp (right,ic,FALSE); + + /* if bitfield then unpack the bits */ + if (IS_BITVAR(retype)) + genPackBits (retype,right,rname,PPOINTER); + else { + /* we have can just get the values */ + int size = AOP_SIZE(right); + int offset = 0 ; + + while (size--) { + l = aopGet(AOP(right),offset,FALSE,TRUE); + + MOVA(l); + emitcode("movx","@%s,a",rname); + + if (size) + emitcode("inc","%s",rname); + + offset++; + } + } + + /* now some housekeeping stuff */ + if (aop) { + /* we had to allocate for this iCode */ + freeAsmop(NULL,aop,ic,TRUE); + } else { + /* we did not allocate which means left + already in a pointer register, then + if size > 0 && this could be used again + we have to point it back to where it + belongs */ + if (AOP_SIZE(right) > 1 && + !OP_SYMBOL(result)->remat && + ( OP_SYMBOL(result)->liveTo > ic->seq || + ic->depth )) { + int size = AOP_SIZE(right) - 1; + while (size--) + emitcode("dec","%s",rname); + } + } + + /* done */ + freeAsmop(right,NULL,ic,TRUE); + + +} + +/*-----------------------------------------------------------------*/ +/* genFarPointerSet - set value from far space */ +/*-----------------------------------------------------------------*/ +static void genFarPointerSet (operand *right, + operand *result, iCode *ic) +{ + int size, offset ; + link *retype = getSpec(operandType(right)); + + aopOp(result,ic,FALSE); + + /* if the operand is already in dptr + then we do nothing else we move the value to dptr */ + if (AOP_TYPE(result) != AOP_STR) { + /* if this is remateriazable */ + if (AOP_TYPE(result) == AOP_IMMD) + emitcode("mov","dptr,%s",aopGet(AOP(result),0,TRUE,FALSE)); + else { /* we need to get it byte by byte */ + emitcode("mov","dpl,%s",aopGet(AOP(result),0,FALSE,FALSE)); + emitcode("mov","dph,%s",aopGet(AOP(result),1,FALSE,FALSE)); + if (options.model == MODEL_FLAT24) + { + emitcode("mov", "dpx,%s",aopGet(AOP(result),2,FALSE,FALSE)); + } + } + } + /* so dptr know contains the address */ + freeAsmop(result,NULL,ic,TRUE); + aopOp(right,ic,FALSE); + + /* if bit then unpack */ + if (IS_BITVAR(retype)) + genPackBits(retype,right,"dptr",FPOINTER); + else { + size = AOP_SIZE(right); + offset = 0 ; + + while (size--) { + char *l = aopGet(AOP(right),offset++,FALSE,FALSE); + MOVA(l); + emitcode("movx","@dptr,a"); + if (size) + emitcode("inc","dptr"); + } + } + + freeAsmop(right,NULL,ic,TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genGenPointerSet - set value from generic pointer space */ +/*-----------------------------------------------------------------*/ +static void genGenPointerSet (operand *right, + operand *result, iCode *ic) +{ + int size, offset ; + link *retype = getSpec(operandType(right)); + + aopOp(result,ic,FALSE); + + /* if the operand is already in dptr + then we do nothing else we move the value to dptr */ + if (AOP_TYPE(result) != AOP_STR) { + /* if this is remateriazable */ + if (AOP_TYPE(result) == AOP_IMMD) { + emitcode("mov","dptr,%s",aopGet(AOP(result),0,TRUE,FALSE)); + emitcode("mov","b,%s + 1",aopGet(AOP(result),0,TRUE,FALSE)); + } + else { /* we need to get it byte by byte */ + emitcode("mov","dpl,%s",aopGet(AOP(result),0,FALSE,FALSE)); + emitcode("mov","dph,%s",aopGet(AOP(result),1,FALSE,FALSE)); + if (options.model == MODEL_FLAT24) + { + emitcode("mov", "dpx,%s",aopGet(AOP(result),2,FALSE,FALSE)); + emitcode("mov","b,%s",aopGet(AOP(result),3,FALSE,FALSE)); + } + else + { + emitcode("mov","b,%s",aopGet(AOP(result),2,FALSE,FALSE)); + } + } + } + /* so dptr know contains the address */ + freeAsmop(result,NULL,ic,TRUE); + aopOp(right,ic,FALSE); + + /* if bit then unpack */ + if (IS_BITVAR(retype)) + genPackBits(retype,right,"dptr",GPOINTER); + else { + size = AOP_SIZE(right); + offset = 0 ; + + while (size--) { + char *l = aopGet(AOP(right),offset++,FALSE,FALSE); + MOVA(l); + emitcode("lcall","__gptrput"); + if (size) + emitcode("inc","dptr"); + } + } + + freeAsmop(right,NULL,ic,TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genPointerSet - stores the value into a pointer location */ +/*-----------------------------------------------------------------*/ +static void genPointerSet (iCode *ic) +{ + operand *right, *result ; + link *type, *etype; + int p_type; + + right = IC_RIGHT(ic); + result = IC_RESULT(ic) ; + + /* depending on the type of pointer we need to + move it to the correct pointer register */ + type = operandType(result); + etype = getSpec(type); + /* if left is of type of pointer then it is simple */ + if (IS_PTR(type) && !IS_FUNC(type->next)) { + p_type = DCL_TYPE(type); + } + else { + /* we have to go by the storage class */ + p_type = PTR_TYPE(SPEC_OCLS(etype)); + +/* if (SPEC_OCLS(etype)->codesp ) { */ +/* p_type = CPOINTER ; */ +/* } */ +/* else */ +/* if (SPEC_OCLS(etype)->fmap && !SPEC_OCLS(etype)->paged) */ +/* p_type = FPOINTER ; */ +/* else */ +/* if (SPEC_OCLS(etype)->fmap && SPEC_OCLS(etype)->paged) */ +/* p_type = PPOINTER ; */ +/* else */ +/* if (SPEC_OCLS(etype) == idata ) */ +/* p_type = IPOINTER ; */ +/* else */ +/* p_type = POINTER ; */ + } + + /* now that we have the pointer type we assign + the pointer values */ + switch (p_type) { + + case POINTER: + case IPOINTER: + genNearPointerSet (right,result,ic); + break; + + case PPOINTER: + genPagedPointerSet (right,result,ic); + break; + + case FPOINTER: + genFarPointerSet (right,result,ic); + break; + + case GPOINTER: + genGenPointerSet (right,result,ic); + break; + } + +} + +/*-----------------------------------------------------------------*/ +/* genIfx - generate code for Ifx statement */ +/*-----------------------------------------------------------------*/ +static void genIfx (iCode *ic, iCode *popIc) +{ + operand *cond = IC_COND(ic); + int isbit =0; + + aopOp(cond,ic,FALSE); + + /* get the value into acc */ + if (AOP_TYPE(cond) != AOP_CRY) + toBoolean(cond); + else + isbit = 1; + /* the result is now in the accumulator */ + freeAsmop(cond,NULL,ic,TRUE); + + /* if there was something to be popped then do it */ + if (popIc) + genIpop(popIc); + + /* if the condition is a bit variable */ + if (isbit && IS_ITEMP(cond) && + SPIL_LOC(cond)) + genIfxJump(ic,SPIL_LOC(cond)->rname); + else + if (isbit && !IS_ITEMP(cond)) + genIfxJump(ic,OP_SYMBOL(cond)->rname); + else + genIfxJump(ic,"a"); + + ic->generated = 1; +} + +/*-----------------------------------------------------------------*/ +/* genAddrOf - generates code for address of */ +/*-----------------------------------------------------------------*/ +static void genAddrOf (iCode *ic) +{ + symbol *sym = OP_SYMBOL(IC_LEFT(ic)); + int size, offset ; + + aopOp(IC_RESULT(ic),ic,FALSE); + + /* if the operand is on the stack then we + need to get the stack offset of this + variable */ + if (sym->onStack) { + /* if it has an offset then we need to compute + it */ + if (sym->stack) { + emitcode("mov","a,_bp"); + emitcode("add","a,#0x%02x",((char) sym->stack & 0xff)); + aopPut(AOP(IC_RESULT(ic)),"a",0); + } else { + /* we can just move _bp */ + aopPut(AOP(IC_RESULT(ic)),"_bp",0); + } + /* fill the result with zero */ + size = AOP_SIZE(IC_RESULT(ic)) - 1; + + + if (options.stack10bit && size < (FPTRSIZE - 1)) + { + fprintf(stderr, + "*** warning: pointer to stack var truncated.\n"); + } + + offset = 1; + while (size--) + { + /* Yuck! */ + if (options.stack10bit && offset == 2) + { + aopPut(AOP(IC_RESULT(ic)),"#0x40", offset++); + } + else + { + aopPut(AOP(IC_RESULT(ic)),zero,offset++); + } + } + + goto release; + } + + /* object not on stack then we need the name */ + size = AOP_SIZE(IC_RESULT(ic)); + offset = 0; + + while (size--) { + char s[SDCC_NAME_MAX]; + if (offset) + sprintf(s,"#(%s >> %d)", + sym->rname, + offset*8); + else + sprintf(s,"#%s",sym->rname); + aopPut(AOP(IC_RESULT(ic)),s,offset++); + } + +release: + freeAsmop(IC_RESULT(ic),NULL,ic,TRUE); + +} + +/*-----------------------------------------------------------------*/ +/* genFarFarAssign - assignment when both are in far space */ +/*-----------------------------------------------------------------*/ +static void genFarFarAssign (operand *result, operand *right, iCode *ic) +{ + int size = AOP_SIZE(right); + int offset = 0; + char *l ; + /* first push the right side on to the stack */ + while (size--) { + l = aopGet(AOP(right),offset++,FALSE,FALSE); + MOVA(l); + emitcode ("push","acc"); + } + + freeAsmop(right,NULL,ic,FALSE); + /* now assign DPTR to result */ + aopOp(result,ic,FALSE); + size = AOP_SIZE(result); + while (size--) { + emitcode ("pop","acc"); + aopPut(AOP(result),"a",--offset); + } + freeAsmop(result,NULL,ic,FALSE); + +} + +/*-----------------------------------------------------------------*/ +/* genAssign - generate code for assignment */ +/*-----------------------------------------------------------------*/ +static void genAssign (iCode *ic) +{ + operand *result, *right; + int size, offset ; + unsigned long lit = 0L; + + result = IC_RESULT(ic); + right = IC_RIGHT(ic) ; + + /* if they are the same */ + if (operandsEqu (IC_RESULT(ic),IC_RIGHT(ic))) + return ; + + aopOp(right,ic,FALSE); + + /* special case both in far space */ + if ((AOP_TYPE(right) == AOP_DPTR || + AOP_TYPE(right) == AOP_DPTR2) && + IS_TRUE_SYMOP(result) && + isOperandInFarSpace(result)) { + + genFarFarAssign (result,right,ic); + return ; + } + + aopOp(result,ic,TRUE); + + /* if they are the same registers */ + if (sameRegs(AOP(right),AOP(result))) + goto release; + + /* if the result is a bit */ + if (AOP_TYPE(result) == AOP_CRY) { + + /* if the right size is a literal then + we know what the value is */ + if (AOP_TYPE(right) == AOP_LIT) { + if (((int) operandLitValue(right))) + aopPut(AOP(result),one,0); + else + aopPut(AOP(result),zero,0); + goto release; + } + + /* the right is also a bit variable */ + if (AOP_TYPE(right) == AOP_CRY) { + emitcode("mov","c,%s",AOP(right)->aopu.aop_dir); + aopPut(AOP(result),"c",0); + goto release ; + } + + /* we need to or */ + toBoolean(right); + aopPut(AOP(result),"a",0); + goto release ; + } + + /* bit variables done */ + /* general case */ + size = AOP_SIZE(result); + offset = 0 ; + if(AOP_TYPE(right) == AOP_LIT) + lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit); + if((size > 1) && + (AOP_TYPE(result) != AOP_REG) && + (AOP_TYPE(right) == AOP_LIT) && + !IS_FLOAT(operandType(right)) && + (lit < 256L)){ + emitcode("clr","a"); + while (size--) { + if((unsigned int)((lit >> (size*8)) & 0x0FFL)== 0) + aopPut(AOP(result),"a",size); + else + aopPut(AOP(result), + aopGet(AOP(right),size,FALSE,FALSE), + size); + } + } else { + while (size--) { + aopPut(AOP(result), + aopGet(AOP(right),offset,FALSE,FALSE), + offset); + offset++; + } + } + +release: + freeAsmop (right,NULL,ic,FALSE); + freeAsmop (result,NULL,ic,TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genJumpTab - genrates code for jump table */ +/*-----------------------------------------------------------------*/ +static void genJumpTab (iCode *ic) +{ + symbol *jtab; + char *l; + + aopOp(IC_JTCOND(ic),ic,FALSE); + /* get the condition into accumulator */ + l = aopGet(AOP(IC_JTCOND(ic)),0,FALSE,FALSE); + MOVA(l); + /* multiply by three */ + emitcode("add","a,acc"); + emitcode("add","a,%s",aopGet(AOP(IC_JTCOND(ic)),0,FALSE,FALSE)); + freeAsmop(IC_JTCOND(ic),NULL,ic,TRUE); + + jtab = newiTempLabel(NULL); + emitcode("mov","dptr,#%05d$",jtab->key+100); + emitcode("jmp","@a+dptr"); + emitcode("","%05d$:",jtab->key+100); + /* now generate the jump labels */ + for (jtab = setFirstItem(IC_JTLABELS(ic)) ; jtab; + jtab = setNextItem(IC_JTLABELS(ic))) + emitcode("ljmp","%05d$",jtab->key+100); + +} + +/*-----------------------------------------------------------------*/ +/* genCast - gen code for casting */ +/*-----------------------------------------------------------------*/ +static void genCast (iCode *ic) +{ + operand *result = IC_RESULT(ic); + link *ctype = operandType(IC_LEFT(ic)); + link *rtype = operandType(IC_RIGHT(ic)); + operand *right = IC_RIGHT(ic); + int size, offset ; + + /* if they are equivalent then do nothing */ + if (operandsEqu(IC_RESULT(ic),IC_RIGHT(ic))) + return ; + + aopOp(right,ic,FALSE) ; + aopOp(result,ic,FALSE); + + /* if the result is a bit */ + if (AOP_TYPE(result) == AOP_CRY) { + /* if the right size is a literal then + we know what the value is */ + if (AOP_TYPE(right) == AOP_LIT) { + if (((int) operandLitValue(right))) + aopPut(AOP(result),one,0); + else + aopPut(AOP(result),zero,0); + + goto release; + } + + /* the right is also a bit variable */ + if (AOP_TYPE(right) == AOP_CRY) { + emitcode("mov","c,%s",AOP(right)->aopu.aop_dir); + aopPut(AOP(result),"c",0); + goto release ; + } + + /* we need to or */ + toBoolean(right); + aopPut(AOP(result),"a",0); + goto release ; + } + + /* if they are the same size : or less */ + if (AOP_SIZE(result) <= AOP_SIZE(right)) { + + /* if they are in the same place */ + if (sameRegs(AOP(right),AOP(result))) + goto release; + + /* if they in different places then copy */ + size = AOP_SIZE(result); + offset = 0 ; + while (size--) { + aopPut(AOP(result), + aopGet(AOP(right),offset,FALSE,FALSE), + offset); + offset++; + } + goto release; + } + + + /* if the result is of type pointer */ + if (IS_PTR(ctype)) { + + int p_type; + link *type = operandType(right); + link *etype = getSpec(type); + + /* pointer to generic pointer */ + if (IS_GENPTR(ctype)) { + char *l = zero; + + if (IS_PTR(type)) + p_type = DCL_TYPE(type); + else { + /* we have to go by the storage class */ + p_type = PTR_TYPE(SPEC_OCLS(etype)); + } + + /* the first two bytes are known */ + size = GPTRSIZE - 1; + offset = 0 ; + while (size--) { + aopPut(AOP(result), + aopGet(AOP(right),offset,FALSE,FALSE), + offset); + offset++; + } + /* the last byte depending on type */ + switch (p_type) { + case IPOINTER: + case POINTER: + l = zero; + break; + case FPOINTER: + l = one; + break; + case CPOINTER: + l = "#0x02"; + break; + case PPOINTER: + l = "#0x03"; + break; + + default: + /* this should never happen */ + werror(E_INTERNAL_ERROR,__FILE__,__LINE__, + "got unknown pointer type"); + exit(1); + } + aopPut(AOP(result),l, GPTRSIZE - 1); + goto release ; + } + + /* just copy the pointers */ + size = AOP_SIZE(result); + offset = 0 ; + while (size--) { + aopPut(AOP(result), + aopGet(AOP(right),offset,FALSE,FALSE), + offset); + offset++; + } + goto release ; + } + + /* so we now know that the size of destination is greater + than the size of the source */ + /* we move to result for the size of source */ + size = AOP_SIZE(right); + offset = 0 ; + while (size--) { + aopPut(AOP(result), + aopGet(AOP(right),offset,FALSE,FALSE), + offset); + offset++; + } + + /* now depending on the sign of the source && destination */ + size = AOP_SIZE(result) - AOP_SIZE(right); + /* if unsigned or not an integral type */ + if (SPEC_USIGN(rtype) || !IS_SPEC(rtype)) { + while (size--) + aopPut(AOP(result),zero,offset++); + } else { + /* we need to extend the sign :{ */ + char *l = aopGet(AOP(right),AOP_SIZE(right) - 1, + FALSE,FALSE); + MOVA(l); + emitcode("rlc","a"); + emitcode("subb","a,acc"); + while (size--) + aopPut(AOP(result),"a",offset++); + } + + /* we are done hurray !!!! */ + +release: + freeAsmop(right,NULL,ic,TRUE); + freeAsmop(result,NULL,ic,TRUE); + +} + +/*-----------------------------------------------------------------*/ +/* genDjnz - generate decrement & jump if not zero instrucion */ +/*-----------------------------------------------------------------*/ +static int genDjnz (iCode *ic, iCode *ifx) +{ + symbol *lbl, *lbl1; + if (!ifx) + return 0; + + /* if the if condition has a false label + then we cannot save */ + if (IC_FALSE(ifx)) + return 0; + + /* if the minus is not of the form + a = a - 1 */ + if (!isOperandEqual(IC_RESULT(ic),IC_LEFT(ic)) || + !IS_OP_LITERAL(IC_RIGHT(ic))) + return 0; + + if (operandLitValue(IC_RIGHT(ic)) != 1) + return 0; + + /* if the size of this greater than one then no + saving */ + if (getSize(operandType(IC_RESULT(ic))) > 1) + return 0; + + /* otherwise we can save BIG */ + lbl = newiTempLabel(NULL); + lbl1= newiTempLabel(NULL); + + aopOp(IC_RESULT(ic),ic,FALSE); + + if (IS_AOP_PREG(IC_RESULT(ic))) { + emitcode("dec","%s", + aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE)); + emitcode("mov","a,%s",aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE)); + emitcode("jnz","%05d$",lbl->key+100); + } else { + emitcode ("djnz","%s,%05d$",aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE), + lbl->key+100); + } + emitcode ("sjmp","%05d$",lbl1->key+100); + emitcode ("","%05d$:",lbl->key+100); + emitcode ("ljmp","%05d$",IC_TRUE(ifx)->key+100); + emitcode ("","%05d$:",lbl1->key+100); + + freeAsmop(IC_RESULT(ic),NULL,ic,TRUE); + ifx->generated = 1; + return 1; +} + +/*-----------------------------------------------------------------*/ +/* genReceive - generate code for a receive iCode */ +/*-----------------------------------------------------------------*/ +static void genReceive (iCode *ic) +{ + if (isOperandInFarSpace(IC_RESULT(ic)) && + ( OP_SYMBOL(IC_RESULT(ic))->isspilt || + IS_TRUE_SYMOP(IC_RESULT(ic))) ) { + + int size = getSize(operandType(IC_RESULT(ic))); + int offset = fReturnSize - size; + while (size--) { + emitcode ("push","%s", (strcmp(fReturn[fReturnSize - offset - 1],"a") ? + fReturn[fReturnSize - offset - 1] : "acc")); + offset++; + } + aopOp(IC_RESULT(ic),ic,FALSE); + size = AOP_SIZE(IC_RESULT(ic)); + offset = 0; + while (size--) { + emitcode ("pop","acc"); + aopPut (AOP(IC_RESULT(ic)),"a",offset++); + } + + } else { + _G.accInUse++; + aopOp(IC_RESULT(ic),ic,FALSE); + _G.accInUse--; + assignResultValue(IC_RESULT(ic)); + } + + freeAsmop(IC_RESULT(ic),NULL,ic,TRUE); +} + +/*-----------------------------------------------------------------*/ +/* gen51Code - generate code for 8051 based controllers */ +/*-----------------------------------------------------------------*/ +void gen51Code (iCode *lic) +{ + iCode *ic; + int cln = 0; + + lineHead = lineCurr = NULL; + + /* print the allocation information */ + if (allocInfo) + printAllocInfo( currFunc, codeOutFile); + /* if debug information required */ +/* if (options.debug && currFunc) { */ + if (currFunc) { + cdbSymbol(currFunc,cdbFile,FALSE,TRUE); + _G.debugLine = 1; + if (IS_STATIC(currFunc->etype)) + emitcode("","F%s$%s$0$0 ==.",moduleName,currFunc->name); + else + emitcode("","G$%s$0$0 ==.",currFunc->name); + _G.debugLine = 0; + } + /* stack pointer name */ + if (options.useXstack) + spname = "_spx"; + else + spname = "sp"; + + + for (ic = lic ; ic ; ic = ic->next ) { + + if ( cln != ic->lineno ) { + if ( options.debug ) { + _G.debugLine = 1; + emitcode("","C$%s$%d$%d$%d ==.", + ic->filename,ic->lineno, + ic->level,ic->block); + _G.debugLine = 0; + } + emitcode(";","%s %d",ic->filename,ic->lineno); + cln = ic->lineno ; + } + /* if the result is marked as + spilt and rematerializable or code for + this has already been generated then + do nothing */ + if (resultRemat(ic) || ic->generated ) + continue ; + + /* depending on the operation */ + switch (ic->op) { + case '!' : + genNot(ic); + break; + + case '~' : + genCpl(ic); + break; + + case UNARYMINUS: + genUminus (ic); + break; + + case IPUSH: + genIpush (ic); + break; + + case IPOP: + /* IPOP happens only when trying to restore a + spilt live range, if there is an ifx statement + following this pop then the if statement might + be using some of the registers being popped which + would destory the contents of the register so + we need to check for this condition and handle it */ + if (ic->next && + ic->next->op == IFX && + regsInCommon(IC_LEFT(ic),IC_COND(ic->next))) + genIfx (ic->next,ic); + else + genIpop (ic); + break; + + case CALL: + genCall (ic); + break; + + case PCALL: + genPcall (ic); + break; + + case FUNCTION: + genFunction (ic); + break; + + case ENDFUNCTION: + genEndFunction (ic); + break; + + case RETURN: + genRet (ic); + break; + + case LABEL: + genLabel (ic); + break; + + case GOTO: + genGoto (ic); + break; + + case '+' : + genPlus (ic) ; + break; + + case '-' : + if ( ! genDjnz (ic,ifxForOp(IC_RESULT(ic),ic))) + genMinus (ic); + break; + + case '*' : + genMult (ic); + break; + + case '/' : + genDiv (ic) ; + break; + + case '%' : + genMod (ic); + break; + + case '>' : + genCmpGt (ic,ifxForOp(IC_RESULT(ic),ic)); + break; + + case '<' : + genCmpLt (ic,ifxForOp(IC_RESULT(ic),ic)); + break; + + case LE_OP: + case GE_OP: + case NE_OP: + + /* note these two are xlated by algebraic equivalence + during parsing SDCC.y */ + werror(E_INTERNAL_ERROR,__FILE__,__LINE__, + "got '>=' or '<=' shouldn't have come here"); + break; + + case EQ_OP: + genCmpEq (ic,ifxForOp(IC_RESULT(ic),ic)); + break; + + case AND_OP: + genAndOp (ic); + break; + + case OR_OP: + genOrOp (ic); + break; + + case '^' : + genXor (ic,ifxForOp(IC_RESULT(ic),ic)); + break; + + case '|' : + genOr (ic,ifxForOp(IC_RESULT(ic),ic)); + break; + + case BITWISEAND: + genAnd (ic,ifxForOp(IC_RESULT(ic),ic)); + break; + + case INLINEASM: + genInline (ic); + break; + + case RRC: + genRRC (ic); + break; + + case RLC: + genRLC (ic); + break; + + case GETHBIT: + genGetHbit (ic); + break; + + case LEFT_OP: + genLeftShift (ic); + break; + + case RIGHT_OP: + genRightShift (ic); + break; + + case GET_VALUE_AT_ADDRESS: + genPointerGet(ic); + break; + + case '=' : + if (POINTER_SET(ic)) + genPointerSet(ic); + else + genAssign(ic); + break; + + case IFX: + genIfx (ic,NULL); + break; + + case ADDRESS_OF: + genAddrOf (ic); + break; + + case JUMPTABLE: + genJumpTab (ic); + break; + + case CAST: + genCast (ic); + break; + + case RECEIVE: + genReceive(ic); + break; + + case SEND: + addSet(&_G.sendSet,ic); + break; + + default : + ic = ic; + /* piCode(ic,stdout); */ + + } } + /* now we are ready to call the peep hole optimizer */ @@ -140,6 +6827,6 @@ void genAVRCode (iCode *lic) peepHole (&lineHead); /* now do the actual printing */ - printLine (lineHead,codeOutFile); + printLine (lineHead,codeOutFile); return; } diff --git a/src/avr/gen.h b/src/avr/gen.h index 643dfcc3..42ddbbe8 100644 --- a/src/avr/gen.h +++ b/src/avr/gen.h @@ -28,9 +28,9 @@ enum { AOP_LIT = 1, AOP_REG, AOP_DIR, - AOP_DPTR,AOP_R0,AOP_R1, + AOP_DPTR,AOP_X,AOP_Z, AOP_STK ,AOP_IMMD, AOP_STR, - AOP_CRY, AOP_ACC }; + AOP_CRY, AOP_ACC , AOP_STK_D}; /* type asmop : a homogenised type for all the different spaces an operand can be @@ -59,11 +59,12 @@ typedef struct asmop { value *aop_lit ; /* if literal */ regs *aop_reg[4]; /* array of registers */ char *aop_dir ; /* if direct */ - regs *aop_ptr ; /* either -> to r0 or r1 */ + regs *aop_ptr ; /* either -> R26 or R30 */ char *aop_immd; /* if immediate others are implied */ int aop_stk ; /* stack offset when AOP_STK */ char *aop_str[4]; /* just a string array containing the location */ } aopu; + regs *aop_ptr2; /* either -> R27 or R31 */ } asmop; void gen51Code (iCode *); diff --git a/src/avr/main.c b/src/avr/main.c index ebd04b14..b2c69005 100644 --- a/src/avr/main.c +++ b/src/avr/main.c @@ -91,10 +91,13 @@ static void _avr_finaliseOptions(void) BIT-ACCESS - NO CODE-ACESS - NO DEBUG-NAME - 'B' - POINTER-TYPE - POINTER + POINTER-TYPE - FPOINTER */ istack = allocMap (0, 1, 0, 0, 0, 0,options.stack_loc, ISTACK_NAME,'B',FPOINTER); + /* also change xdata to be direct space since we can use lds/sts */ + xdata->direct = 1; + } static void _avr_setDefaultOptions(void) diff --git a/src/avr/ralloc.c b/src/avr/ralloc.c index 20259605..186b968b 100644 --- a/src/avr/ralloc.c +++ b/src/avr/ralloc.c @@ -111,8 +111,7 @@ static regs *allocReg (short type) regsAVR[i].isFree ) { regsAVR[i].isFree = 0; if (currFunc) - currFunc->regsUsed = - bitVectSetBit(currFunc->regsUsed,i); + currFunc->regsUsed = bitVectSetBit(currFunc->regsUsed,i); return ®sAVR[i]; } /* other wise look for specific type @@ -745,6 +744,31 @@ static regs *getRegPtr (iCode *ic, eBBlock *ebp, symbol *sym) goto tryAgain ; } +/*-----------------------------------------------------------------*/ +/* getRegScr - will try for SCR if not a GPR type if not spil */ +/*-----------------------------------------------------------------*/ +static regs *getRegScr (iCode *ic, eBBlock *ebp, symbol *sym) +{ + regs *reg; + + tryAgain: + /* try for a ptr type */ + if ((reg = allocReg(REG_SCR))) + return reg; + + /* try for gpr type */ + if ((reg = allocReg(REG_GPR))) + return reg; + + /* we have to spil */ + if (!spilSomething (ic,ebp,sym)) + return NULL ; + + /* this looks like an infinite loop but + in really selectSpil will abort */ + goto tryAgain ; +} + /*-----------------------------------------------------------------*/ /* getRegGpr - will try for GPR if not spil */ /*-----------------------------------------------------------------*/ @@ -1064,6 +1088,8 @@ static void serialRegAssign (eBBlock **ebbs, int count) for (j = 0 ; j < sym->nRegs ;j++ ) { if (sym->regType == REG_PTR) sym->regs[j] = getRegPtr(ic,ebbs[i],sym); + else if (sym->regType == REG_SCR) + sym->regs[j] = getRegScr(ic,ebbs[i],sym); else sym->regs[j] = getRegGpr(ic,ebbs[i],sym); @@ -1214,10 +1240,17 @@ static void createRegMask (eBBlock **ebbs, int count) continue ; /* for all the registers allocated to it */ - for (k = 0 ; k < sym->nRegs ;k++) - if (sym->regs[k]) + for (k = 0 ; k < sym->nRegs ;k++) { + if (sym->regs[k]) { ic->rMask = bitVectSetBit(ic->rMask,sym->regs[k]->rIdx); + /* special case for X & Z registers */ + if (k == R26_IDX || k == R27_IDX) + ic->rMask = bitVectSetBit(ic->rMask,X_IDX); + if (k == R30_IDX || k == R31_IDX) + ic->rMask = bitVectSetBit(ic->rMask,Z_IDX); + } + } } } } @@ -2221,20 +2254,17 @@ static void setDefaultRegs(eBBlock **ebbs,int count) /* if no pointer registers required in this function then mark r26-27 & r30-r31 as GPR & free */ + regsAVR[R26_IDX].isFree = + regsAVR[R27_IDX].isFree = + regsAVR[R30_IDX].isFree = + regsAVR[R31_IDX].isFree = 1; + if (!avr_ptrRegReq) { - regsAVR[R26_IDX].isFree = - regsAVR[R27_IDX].isFree = - regsAVR[R30_IDX].isFree = - regsAVR[R31_IDX].isFree = 1; regsAVR[R26_IDX].type = regsAVR[R27_IDX].type = regsAVR[R30_IDX].type = regsAVR[R31_IDX].type = REG_GPR ; } else { - regsAVR[R26_IDX].isFree = - regsAVR[R27_IDX].isFree = - regsAVR[R30_IDX].isFree = - regsAVR[R31_IDX].isFree = 1; regsAVR[R26_IDX].type = regsAVR[R27_IDX].type = regsAVR[R30_IDX].type = @@ -2254,7 +2284,7 @@ static void setDefaultRegs(eBBlock **ebbs,int count) if (!currFunc->hasFcall) { /* mark the parameter regs as GPR */ for (i= R16_IDX ; i <= R23_IDX ;i++) { - regsAVR[i].type = REG_GPR; + regsAVR[i].type = REG_SCR; regsAVR[i].isFree = 1; } preAssignParms(ebbs[0]->sch); @@ -2328,8 +2358,9 @@ void avr_assignRegisters (eBBlock **ebbs, int count) ic = iCodeLabelOptimize(iCodeFromeBBlock (ebbs,count)); - genAVRCode(ic); - + /* genAVRCode(ic); */ + for (; ic ; ic = ic->next) + piCode(ic,stdout); /* free up any _G.stackSpil locations allocated */ applyToSet(_G.stackSpil,deallocStackSpil); _G.slocNum = 0;