From: sdattalo Date: Mon, 4 Dec 2000 06:21:46 +0000 (+0000) Subject: Started PIC port (based on mcs51 port) X-Git-Url: https://git.gag.com/?a=commitdiff_plain;h=778f1b919b8f1bc96249966828c4b7b209d1b212;p=fw%2Fsdcc Started PIC port (based on mcs51 port) git-svn-id: https://sdcc.svn.sourceforge.net/svnroot/sdcc/trunk/sdcc@512 4a8a32a2-be11-0410-ad9d-d568d2c75423 --- diff --git a/src/Makefile.bcc b/src/Makefile.bcc index a305b00d..d64e7729 100644 --- a/src/Makefile.bcc +++ b/src/Makefile.bcc @@ -7,8 +7,8 @@ PRJDIR = .. # !include $(PRJDIR)/Makefile.common -PORTS = mcs51 z80 avr ds390 -PORT_LIBS = mcs51/port.lib z80/port.lib avr/port.lib ds390/port.lib +PORTS = mcs51 z80 avr ds390 pic +PORT_LIBS = mcs51/port.lib z80/port.lib avr/port.lib ds390/port.lib pic/port.lib LIBS = -lgc LIBDIRS = -L$(PRJDIR)/support/gc diff --git a/src/Makefile.in b/src/Makefile.in index 279f7576..96c6f497 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -8,7 +8,7 @@ include $(PRJDIR)/Makefile.common USE_ALT_LEX = 0 -PORTS = mcs51 z80 avr ds390 +PORTS = mcs51 z80 avr ds390 pic PORT_LIBS = $(PORTS:%=%/port.a) ifeq ($(DISABLE_GC),1) diff --git a/src/pic/Makefile b/src/pic/Makefile new file mode 100644 index 00000000..c9556e90 --- /dev/null +++ b/src/pic/Makefile @@ -0,0 +1,23 @@ +PRJDIR = ../.. + +include $(PRJDIR)/Makefile.common + +OBJ = gen.o ralloc.o main.o glue.o +LIB = port.a + +CFLAGS = -ggdb -Wall -O2 +CFLAGS += -I.. -I. -I../.. + +all: $(LIB) + +main.o: main.c peeph.rul + +$(LIB): peeph.rul $(OBJ) + rm -f $(LIB) + ar r $(LIB) $(OBJ) + ranlib $(LIB) + +peeph.rul: peeph.def + $(AWK) -f ../SDCCpeeph.awk peeph.def > peeph.rul + +include clean.mk diff --git a/src/pic/Makefile.bcc b/src/pic/Makefile.bcc new file mode 100644 index 00000000..4b17a92d --- /dev/null +++ b/src/pic/Makefile.bcc @@ -0,0 +1,22 @@ +PRJDIR = ../.. + +# !include $(PRJDIR)/Makefile.common + +OBJ = gen.obj ralloc.obj main.obj +LIB = port.lib + +!include ..\..\Bcc.inc +CFLAGS = -I.. -I. -I..\.. -I..\..\support + +all: $(LIB) + +main.obj: main.c peeph.rul + +$(LIB): peeph.rul $(OBJ) + del $(LIB) + tlib /a $(LIB) +gen.obj +ralloc.obj +main.obj + +peeph.rul: peeph.def + gawk -f ../SDCCpeeph.awk peeph.def > peeph.rul + +# include clean.mk diff --git a/src/pic/clean.mk b/src/pic/clean.mk new file mode 100644 index 00000000..07f3ca43 --- /dev/null +++ b/src/pic/clean.mk @@ -0,0 +1,6 @@ +# + +clean: + rm -f $(LIB) *.o *~ port.a + +# End of src/mcs51/clean.mk diff --git a/src/pic/gen.c b/src/pic/gen.c new file mode 100644 index 00000000..6ce86d55 --- /dev/null +++ b/src/pic/gen.c @@ -0,0 +1,8324 @@ +/*------------------------------------------------------------------------- + SDCCgen51.c - source file for code generation for 8051 + + 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) + PIC port - Scott Dattalo scott@dattalo.com (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 + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + 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 +#include +#include +#include +#include "SDCCglobl.h" + +#ifdef HAVE_SYS_ISA_DEFS_H +#include +#else +#ifdef HAVE_ENDIAN_H +#include +#else +#ifndef __BORLANDC__ +#warning "Cannot determine ENDIANESS of this machine assuming LITTLE_ENDIAN" +#warning "If you running sdcc on an INTEL 80x86 Platform you are okay" +#endif +#endif +#endif + +#include "common.h" +#include "SDCCpeeph.h" +#include "ralloc.h" +#include "gen.h" + +//char *aopLiteral (value *val, int offset); +char *pic14aopLiteral (value *val, int offset); + +/* 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 *spname = "sp"; + +char *fReturnpic14[] = {"dpl","dph","b","a" }; +//char *fReturn390[] = {"dpl","dph","dpx", "b","a" }; +static unsigned fReturnSize = 4; /* shared with ralloc.c */ +static char **fReturn = fReturnpic14; + +static char *accUse[] = {"a","b"}; + +static short rbank = -1; + +static struct { + short r0Pushed; + short r1Pushed; + short accInUse; + short inLine; + short debugLine; + short nRegsSaved; + set *sendSet; +} _G; + +extern int pic14_ptrRegReq ; +extern int pic14_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 MOVA(x) if (strcmp(x,"a") && strcmp(x,"acc")) emitcode(";XXX mov","a,%s %s,%d",x,__FILE__,__LINE__); +#define CLRC emitcode(";XXX clr","c %s,%d",__FILE__,__LINE__); + +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 + + +#define FUNCTION_LABEL_INC 20 +static int labelOffset=0; +static int debug_verbose=1; + +/*-----------------------------------------------------------------*/ +/* my_powof2(n) - If `n' is an integaer power of 2, then the */ +/* exponent of 2 is returned, otherwise -1 is */ +/* returned. */ +/* note that this is similar to the function `powof2' in SDCCsymt */ +/* if(n == 2^y) */ +/* return y; */ +/* return -1; */ +/*-----------------------------------------------------------------*/ +static int my_powof2 (unsigned long num) +{ + if(num) { + if( (num & (num-1)) == 0) { + int nshifts = -1; + while(num) { + num>>=1; + nshifts++; + } + return nshifts; + } + } + + return -1; +} + + +/*-----------------------------------------------------------------*/ +/* emitcode - writes the code into a file : for now it is simple */ +/*-----------------------------------------------------------------*/ +static void emitcode (char *inst,char *fmt, ...) +{ + va_list ap; + char lb[MAX_INLINEASM]; + char *lbp = lb; + + va_start(ap,fmt); + + if (inst && *inst) { + if (fmt && *fmt) + sprintf(lb,"%s\t",inst); + else + sprintf(lb,"%s",inst); + vsprintf(lb+(strlen(lb)),fmt,ap); + } else + vsprintf(lb,fmt,ap); + + while (isspace(*lbp)) lbp++; + + if (lbp && *lbp) + lineCurr = (lineCurr ? + connectLine(lineCurr,newLineNode(lb)) : + (lineHead = newLineNode(lb))); + lineCurr->isInline = _G.inLine; + lineCurr->isDebug = _G.debugLine; + va_end(ap); +} + +static void DEBUGemitcode (char *inst,char *fmt, ...) +{ + va_list ap; + char lb[MAX_INLINEASM]; + char *lbp = lb; + + if(!debug_verbose) + return; + + va_start(ap,fmt); + + if (inst && *inst) { + if (fmt && *fmt) + sprintf(lb,"%s\t",inst); + else + sprintf(lb,"%s",inst); + vsprintf(lb+(strlen(lb)),fmt,ap); + } else + vsprintf(lb,fmt,ap); + + while (isspace(*lbp)) lbp++; + + if (lbp && *lbp) + lineCurr = (lineCurr ? + connectLine(lineCurr,newLineNode(lb)) : + (lineHead = newLineNode(lb))); + lineCurr->isInline = _G.inLine; + lineCurr->isDebug = _G.debugLine; + va_end(ap); +} + + +/*-----------------------------------------------------------------*/ +/* getFreePtr - returns r0 or r1 whichever is free or can be pushed*/ +/*-----------------------------------------------------------------*/ +static regs *getFreePtr (iCode *ic, asmop **aopp, bool result) +{ + bool r0iu = FALSE , r1iu = FALSE; + bool r0ou = FALSE , r1ou = FALSE; + + /* the logic: if r0 & r1 used in the instruction + then we are in trouble otherwise */ + + /* first check if r0 & r1 are used by this + instruction, in which case we are in trouble */ + if ((r0iu = bitVectBitValue(ic->rUsed,R0_IDX)) && + (r1iu = bitVectBitValue(ic->rUsed,R1_IDX))) + { + goto endOfWorld; + } + + r0ou = bitVectBitValue(ic->rMask,R0_IDX); + r1ou = bitVectBitValue(ic->rMask,R1_IDX); + + /* if no usage of r0 then return it */ + if (!r0iu && !r0ou) { + ic->rUsed = bitVectSetBit(ic->rUsed,R0_IDX); + (*aopp)->type = AOP_R0; + + return (*aopp)->aopu.aop_ptr = pic14_regWithIdx(R0_IDX); + } + + /* if no usage of r1 then return it */ + if (!r1iu && !r1ou) { + ic->rUsed = bitVectSetBit(ic->rUsed,R1_IDX); + (*aopp)->type = AOP_R1; + + return (*aopp)->aopu.aop_ptr = pic14_regWithIdx(R1_IDX); + } + + /* now we know they both have usage */ + /* if r0 not used in this instruction */ + if (!r0iu) { + /* push it if not already pushed */ + if (!_G.r0Pushed) { + emitcode ("push","%s", + pic14_regWithIdx(R0_IDX)->dname); + _G.r0Pushed++ ; + } + + ic->rUsed = bitVectSetBit(ic->rUsed,R0_IDX); + (*aopp)->type = AOP_R0; + + return (*aopp)->aopu.aop_ptr = pic14_regWithIdx(R0_IDX); + } + + /* if r1 not used then */ + + if (!r1iu) { + /* push it if not already pushed */ + if (!_G.r1Pushed) { + emitcode ("push","%s", + pic14_regWithIdx(R1_IDX)->dname); + _G.r1Pushed++ ; + } + + ic->rUsed = bitVectSetBit(ic->rUsed,R1_IDX); + (*aopp)->type = AOP_R1; + return pic14_regWithIdx(R1_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; +} + +static void genSetDPTR(int n) +{ + if (!n) + { + emitcode(";", "Select standard DPTR"); + emitcode("mov", "dps, #0x00"); + } + else + { + emitcode(";", "Select alternate DPTR"); + emitcode("mov", "dps, #0x01"); + } +} + +/*-----------------------------------------------------------------*/ +/* 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 or indirectly addressable */ + /* space we need to assign either r0 or r1 to it */ + if ((sym->onStack && !options.stack10bit) || sym->iaccess) { + sym->aop = aop = newAsmop(0); + aop->aopu.aop_ptr = getFreePtr(ic,&aop,result); + aop->size = getSize(sym->type); + + /* now assign the address of the variable to + the pointer register */ + if (aop->type != AOP_STK) { + + if (sym->onStack) { + if ( _G.accInUse ) + emitcode("push","acc"); + + emitcode("mov","a,_bp"); + emitcode("add","a,#0x%02x", + ((sym->stack < 0) ? + ((char)(sym->stack - _G.nRegsSaved )) : + ((char)sym->stack)) & 0xff); + emitcode("mov","%s,a", + aop->aopu.aop_ptr->name); + + if ( _G.accInUse ) + emitcode("pop","acc"); + } else + emitcode("mov","%s,#%s", + aop->aopu.aop_ptr->name, + sym->rname); + aop->paged = space->paged; + } else + aop->aopu.aop_stk = sym->stack; + return aop; + } + + if (sym->onStack && options.stack10bit) + { + /* It's on the 10 bit stack, which is located in + * far data space. + */ + + if ( _G.accInUse ) + emitcode("push","acc"); + + emitcode("mov","a,_bp"); + emitcode("add","a,#0x%02x", + ((sym->stack < 0) ? + ((char)(sym->stack - _G.nRegsSaved )) : + ((char)sym->stack)) & 0xff); + + genSetDPTR(1); + emitcode ("mov","dpx1,#0x40"); + emitcode ("mov","dph1,#0x00"); + emitcode ("mov","dpl1, a"); + genSetDPTR(0); + + if ( _G.accInUse ) + emitcode("pop","acc"); + + sym->aop = aop = newAsmop(AOP_DPTR2); + aop->size = getSize(sym->type); + 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 far space */ + /* in which case DPTR gets the address */ + sym->aop = aop = newAsmop(AOP_DPTR); + emitcode ("mov","dptr,#%s", sym->rname); + aop->size = getSize(sym->type); + + /* if it is in code space */ + if (IN_CODESPACE(space)) + aop->code = 1; + + return aop; +} + +/*-----------------------------------------------------------------*/ +/* aopForRemat - rematerialzes an object */ +/*-----------------------------------------------------------------*/ +static asmop *aopForRemat (symbol *sym) +{ + iCode *ic = sym->rematiCode; + asmop *aop = newAsmop(AOP_IMMD); + int val = 0; + emitcode(";","%s",__FUNCTION__); + for (;;) { + if (ic->op == '+') + val += operandLitValue(IC_RIGHT(ic)); + else if (ic->op == '-') + val -= operandLitValue(IC_RIGHT(ic)); + else + break; + + ic = OP_SYMBOL(IC_LEFT(ic))->rematiCode; + } + + 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 ; +} + +/*-----------------------------------------------------------------*/ +/* 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) { + int i; + aop = op->aop = sym->aop = newAsmop(AOP_ACC); + aop->size = getSize(sym->type); + for ( i = 0 ; i < 2 ; i++ ) + aop->aopu.aop_str[i] = accUse[i]; + return; + } + + 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_R0 : + if (_G.r0Pushed ) { + if (pop) { + emitcode ("pop","ar0"); + _G.r0Pushed--; + } + } + bitVectUnSetBit(ic->rUsed,R0_IDX); + break; + + case AOP_R1 : + if (_G.r1Pushed ) { + if (pop) { + emitcode ("pop","ar1"); + _G.r1Pushed--; + } + } + bitVectUnSetBit(ic->rUsed,R1_IDX); + break; + + case AOP_STK : + { + int sz = aop->size; + int stk = aop->aopu.aop_stk + aop->size; + bitVectUnSetBit(ic->rUsed,R0_IDX); + bitVectUnSetBit(ic->rUsed,R1_IDX); + + getFreePtr(ic,&aop,FALSE); + + if (options.stack10bit) + { + /* I'm not sure what to do here yet... */ + /* #STUB */ + fprintf(stderr, + "*** Warning: probably generating bad code for " + "10 bit stack mode.\n"); + } + + if (stk) { + emitcode ("mov","a,_bp"); + emitcode ("add","a,#0x%02x",((char)stk) & 0xff); + emitcode ("mov","%s,a",aop->aopu.aop_ptr->name); + } else { + emitcode ("mov","%s,_bp",aop->aopu.aop_ptr->name); + } + + while (sz--) { + emitcode("pop","acc"); + emitcode("mov","@%s,a",aop->aopu.aop_ptr->name); + if (!sz) break; + emitcode("dec","%s",aop->aopu.aop_ptr->name); + } + op->aop = aop; + freeAsmop(op,NULL,ic,TRUE); + if (_G.r0Pushed) { + emitcode("pop","ar0"); + _G.r0Pushed--; + } + + if (_G.r1Pushed) { + emitcode("pop","ar1"); + _G.r1Pushed--; + } + } + } + +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, bool bit16, bool dname) +{ + char *s = buffer ; + char *rs; + + //DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* 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_R0: + case AOP_R1: + DEBUGemitcode(";","%d",__LINE__); + /* if we need to increment it */ + while (offset > aop->coff) { + emitcode ("inc","%s",aop->aopu.aop_ptr->name); + aop->coff++; + } + + while (offset < aop->coff) { + emitcode("dec","%s",aop->aopu.aop_ptr->name); + aop->coff--; + } + + aop->coff = offset ; + if (aop->paged) { + emitcode("movx","a,@%s",aop->aopu.aop_ptr->name); + return (dname ? "acc" : "a"); + } + sprintf(s,"@%s",aop->aopu.aop_ptr->name); + ALLOC_ATOMIC(rs,strlen(s)+1); + strcpy(rs,s); + return rs; + + case AOP_DPTR: + case AOP_DPTR2: + DEBUGemitcode(";","%d",__LINE__); + if (aop->type == AOP_DPTR2) + { + genSetDPTR(1); + } + + while (offset > aop->coff) { + emitcode ("inc","dptr"); + aop->coff++; + } + + while (offset < aop->coff) { + emitcode("lcall","__decdptr"); + aop->coff--; + } + + aop->coff = offset; + if (aop->code) { + emitcode("clr","a"); + emitcode("movc","a,@a+dptr"); + } + else { + emitcode("movx","a,@dptr"); + } + + if (aop->type == AOP_DPTR2) + { + genSetDPTR(0); + } + + return (dname ? "acc" : "a"); + + + case AOP_IMMD: + DEBUGemitcode(";","%d",__LINE__); + if (bit16) + sprintf (s,"#%s",aop->aopu.aop_immd); + else + if (offset) + sprintf(s,"#(%s >> %d)", + aop->aopu.aop_immd, + offset*8); + else + sprintf(s,"#%s", + aop->aopu.aop_immd); + ALLOC_ATOMIC(rs,strlen(s)+1); + strcpy(rs,s); + return rs; + + case AOP_DIR: + if (offset) + sprintf(s,"(%s + %d)", + aop->aopu.aop_dir, + offset); + else + sprintf(s,"%s",aop->aopu.aop_dir); + ALLOC_ATOMIC(rs,strlen(s)+1); + strcpy(rs,s); + return rs; + + case AOP_REG: + DEBUGemitcode(";","%d",__LINE__); + if (dname) + return aop->aopu.aop_reg[offset]->dname; + else + return aop->aopu.aop_reg[offset]->name; + + case AOP_CRY: + emitcode(";","%d",__LINE__); + //emitcode("clr","a"); + //emitcode("mov","c,%s",aop->aopu.aop_dir); + //emitcode("rlc","a") ; + //return (dname ? "acc" : "a"); + return "bit"; + + case AOP_ACC: + DEBUGemitcode(";","%d",__LINE__); + if (!offset && dname) + return "acc"; + return aop->aopu.aop_str[offset]; + + case AOP_LIT: + DEBUGemitcode(";","%d",__LINE__); + return pic14aopLiteral (aop->aopu.aop_lit,offset); + + case AOP_STR: + DEBUGemitcode(";","%d",__LINE__); + aop->coff = offset ; + if (strcmp(aop->aopu.aop_str[offset],"a") == 0 && + dname) + return "acc"; + + return aop->aopu.aop_str[offset]; + + } + + 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 ; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + 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); + + if (strcmp(d,s)) { + emitcode("movf","%s,w ; %d",s,__LINE__); + emitcode("movwf","%s",d); + } + break; + + case AOP_REG: + if (strcmp(aop->aopu.aop_reg[offset]->name,s) != 0 && + strcmp(aop->aopu.aop_reg[offset]->dname,s)!= 0){ + if (*s == '@' || + strcmp(s,"r0") == 0 || + strcmp(s,"r1") == 0 || + strcmp(s,"r2") == 0 || + strcmp(s,"r3") == 0 || + strcmp(s,"r4") == 0 || + strcmp(s,"r5") == 0 || + strcmp(s,"r6") == 0 || + strcmp(s,"r7") == 0 ) + emitcode("mov","%s,%s ; %d", + aop->aopu.aop_reg[offset]->dname,s,__LINE__); + else + emitcode("mov","%s,%s ; %d", + aop->aopu.aop_reg[offset]->name,s,__LINE__); + } + break; + + case AOP_DPTR: + case AOP_DPTR2: + + if (aop->type == AOP_DPTR2) + { + genSetDPTR(1); + } + + if (aop->code) { + werror(E_INTERNAL_ERROR,__FILE__,__LINE__, + "aopPut writting to code space"); + exit(0); + } + + while (offset > aop->coff) { + aop->coff++; + emitcode ("inc","dptr"); + } + + while (offset < aop->coff) { + aop->coff-- ; + emitcode("lcall","__decdptr"); + } + + aop->coff = offset; + + /* if not in accumulater */ + MOVA(s); + + emitcode ("movx","@dptr,a"); + + if (aop->type == AOP_DPTR2) + { + genSetDPTR(0); + } + break; + + case AOP_R0: + case AOP_R1: + while (offset > aop->coff) { + aop->coff++; + emitcode("inc","%s",aop->aopu.aop_ptr->name); + } + while (offset < aop->coff) { + aop->coff-- ; + emitcode ("dec","%s",aop->aopu.aop_ptr->name); + } + aop->coff = offset; + + if (aop->paged) { + MOVA(s); + emitcode("movx","@%s,a",aop->aopu.aop_ptr->name); + + } else + if (*s == '@') { + MOVA(s); + emitcode("mov","@%s,a ; %d",aop->aopu.aop_ptr->name,__LINE__); + } else + if (strcmp(s,"r0") == 0 || + strcmp(s,"r1") == 0 || + strcmp(s,"r2") == 0 || + strcmp(s,"r3") == 0 || + strcmp(s,"r4") == 0 || + strcmp(s,"r5") == 0 || + strcmp(s,"r6") == 0 || + strcmp(s,"r7") == 0 ) { + char buffer[10]; + sprintf(buffer,"a%s",s); + emitcode("mov","@%s,%s", + aop->aopu.aop_ptr->name,buffer); + } else + emitcode("mov","@%s,%s",aop->aopu.aop_ptr->name,s); + + break; + + case AOP_STK: + if (strcmp(s,"a") == 0) + emitcode("push","acc"); + else + emitcode("push","%s",s); + + break; + + case AOP_CRY: + /* if bit variable */ + if (!aop->aopu.aop_dir) { + emitcode("clr","a"); + emitcode("rlc","a"); + } else { + if (s == zero) + emitcode("clr","%s",aop->aopu.aop_dir); + else + if (s == one) + emitcode("setb","%s",aop->aopu.aop_dir); + else + if (!strcmp(s,"c")) + emitcode("mov","%s,c",aop->aopu.aop_dir); + else { + lbl = newiTempLabel(NULL); + + if (strcmp(s,"a")) { + MOVA(s); + } + emitcode("clr","c"); + emitcode("jz","%05d_DS_",lbl->key+100); + emitcode("cpl","c"); + emitcode("","%05d_DS_:",lbl->key+100); + emitcode("mov","%s,c",aop->aopu.aop_dir); + } + } + break; + + case AOP_STR: + aop->coff = offset; + if (strcmp(aop->aopu.aop_str[offset],s)) + emitcode ("mov","%s,%s ; %d",aop->aopu.aop_str[offset],s,__LINE__); + break; + + case AOP_ACC: + aop->coff = offset; + if (!offset && (strcmp(s,"acc") == 0)) + break; + + if (strcmp(aop->aopu.aop_str[offset],s)) + emitcode ("mov","%s,%s ; %d",aop->aopu.aop_str[offset],s, __LINE__); + break; + + default : + werror(E_INTERNAL_ERROR,__FILE__,__LINE__, + "aopPut got unsupported aop->type"); + exit(0); + } + +} + +/*-----------------------------------------------------------------*/ +/* reAdjustPreg - points a register back to where it should */ +/*-----------------------------------------------------------------*/ +static void reAdjustPreg (asmop *aop) +{ + int size ; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + aop->coff = 0; + if ((size = aop->size) <= 1) + return ; + size-- ; + switch (aop->type) { + case AOP_R0 : + case AOP_R1 : + while (size--) + emitcode("dec","%s",aop->aopu.aop_ptr->name); + break; + case AOP_DPTR : + case AOP_DPTR2: + if (aop->type == AOP_DPTR2) + { + genSetDPTR(1); + } + while (size--) + { + emitcode("lcall","__decdptr"); + } + + if (aop->type == AOP_DPTR2) + { + genSetDPTR(0); + } + 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_R1 || \ + AOP_TYPE(x) == AOP_R0)) + +#define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY || \ + AOP_TYPE(x) == AOP_DPTR || AOP_TYPE(x) == AOP_DPTR2 || \ + AOP(x)->paged)) + +#define AOP_INPREG(x) (x && (x->type == AOP_REG && \ + (x->aopu.aop_reg[0] == pic14_regWithIdx(R0_IDX) || \ + x->aopu.aop_reg[0] == pic14_regWithIdx(R1_IDX) ))) + +/*-----------------------------------------------------------------*/ +/* genNotFloat - generates not for float operations */ +/*-----------------------------------------------------------------*/ +static void genNotFloat (operand *op, operand *res) +{ + int size, offset; + char *l; + symbol *tlbl ; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* 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++,FALSE,FALSE); + MOVA(l); + + while(size--) { + emitcode("orl","a,%s", + aopGet(op->aop, + offset++,FALSE,FALSE)); + } + tlbl = newiTempLabel(NULL); + + tlbl = newiTempLabel(NULL); + aopPut(res->aop,one,1); + emitcode("jz","%05d_DS_",(tlbl->key+100)); + aopPut(res->aop,zero,1); + emitcode("","%05d_DS_:",(tlbl->key+100)); + + 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); + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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; + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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; + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + size = getDataSize(result); + if(size){ + aopPut(AOP(result),"a",0); + size--; + offset = 1; + /* unsigned or positive */ + while(size--){ + aopPut(AOP(result),zero,offset++); + } + } +} + +/*-----------------------------------------------------------------*/ +/* outBitC - output a bit C */ +/*-----------------------------------------------------------------*/ +static void outBitC(operand *result) +{ + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* if the result is bit */ + if (AOP_TYPE(result) == AOP_CRY) + aopPut(AOP(result),"c",0); + else { + emitcode("clr","a ; %d", __LINE__); + emitcode("rlc","a"); + outAcc(result); + } +} + +/*-----------------------------------------------------------------*/ +/* toBoolean - emit code for orl a,operator(sizeop) */ +/*-----------------------------------------------------------------*/ +static void toBoolean(operand *oper) +{ + int size = AOP_SIZE(oper) - 1; + int offset = 1; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + emitcode("movf","%s,w",aopGet(AOP(oper),0,FALSE,FALSE)); + while (size--) + emitcode("iorwf","%s,w",aopGet(AOP(oper),offset++,FALSE,FALSE)); +} + + +/*-----------------------------------------------------------------*/ +/* genNot - generate code for ! operation */ +/*-----------------------------------------------------------------*/ +static void genNot (iCode *ic) +{ + symbol *tlbl; + link *optype = operandType(IC_LEFT(ic)); + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* assign asmOps to operand & result */ + aopOp (IC_LEFT(ic),ic,FALSE); + aopOp (IC_RESULT(ic),ic,TRUE); + + /* if in bit space then a special case */ + if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY) { + emitcode("movlw","1<<%s"); + //emitcode("mov","c,%s",IC_LEFT(ic)->aop->aopu.aop_dir); + //emitcode("cpl","c"); + //outBitC(IC_RESULT(ic)); + goto release; + } + + /* if type float then do float */ + if (IS_FLOAT(optype)) { + genNotFloat(IC_LEFT(ic),IC_RESULT(ic)); + goto release; + } + + toBoolean(IC_LEFT(ic)); + + tlbl = newiTempLabel(NULL); + emitcode("cjne","a,#0x01,%05d_DS_",tlbl->key+100); + emitcode("","%05d_DS_:",tlbl->key+100); + outBitC(IC_RESULT(ic)); + +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 ; + + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* assign asmOps to operand & result */ + aopOp (IC_LEFT(ic),ic,FALSE); + aopOp (IC_RESULT(ic),ic,TRUE); + + /* if both are in bit space then + a special case */ + if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY && + AOP_TYPE(IC_LEFT(ic)) == AOP_CRY ) { + + emitcode("mov","c,%s",IC_LEFT(ic)->aop->aopu.aop_dir); + emitcode("cpl","c"); + emitcode("mov","%s,c",IC_RESULT(ic)->aop->aopu.aop_dir); + goto release; + } + + size = AOP_SIZE(IC_RESULT(ic)); + while (size--) { + char *l = aopGet(AOP(IC_LEFT(ic)),offset,FALSE,FALSE); + MOVA(l); + emitcode("cpl","a"); + aopPut(AOP(IC_RESULT(ic)),"a",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; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* 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); + + MOVA(l); + + emitcode("cpl","acc.7"); + aopPut(AOP(result),"a",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; + + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* assign asmops */ + aopOp(IC_LEFT(ic),ic,FALSE); + aopOp(IC_RESULT(ic),ic,TRUE); + + /* if both in bit space then special + case */ + if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY && + AOP_TYPE(IC_LEFT(ic)) == AOP_CRY ) { + + emitcode("mov","c,%s",IC_LEFT(ic)->aop->aopu.aop_dir); + emitcode("cpl","c"); + emitcode("mov","%s,c",IC_RESULT(ic)->aop->aopu.aop_dir); + goto release; + } + + 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 ; + CLRC ; + while(size--) { + char *l = aopGet(AOP(IC_LEFT(ic)),offset,FALSE,FALSE); + if (!strcmp(l,"a")) { + emitcode("cpl","a"); + emitcode("inc","a"); + } else { + emitcode("clr","a"); + emitcode("subb","a,%s",l); + } + aopPut(AOP(IC_RESULT(ic)),"a",offset++); + } + + /* 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))))) { + emitcode("rlc","a"); + emitcode("subb","a,acc"); + while (size--) + aopPut(AOP(IC_RESULT(ic)),"a",offset++); + } + +release: + /* release the aops */ + freeAsmop(IC_LEFT(ic),NULL,ic,(RESULTONSTACK(ic) ? 0 : 1)); + freeAsmop(IC_RESULT(ic),NULL,ic,TRUE); +} + +/*-----------------------------------------------------------------*/ +/* saveRegisters - will look for a call and save the registers */ +/*-----------------------------------------------------------------*/ +static void saveRegisters(iCode *lic) +{ + int i; + iCode *ic; + bitVect *rsave; + link *detype; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* look for call */ + for (ic = lic ; ic ; ic = ic->next) + if (ic->op == CALL || ic->op == PCALL) + break; + + if (!ic) { + fprintf(stderr,"found parameter push with no function call\n"); + return ; + } + + /* if the registers have been saved already then + do nothing */ + if (ic->regsSaved || (OP_SYMBOL(IC_LEFT(ic))->calleeSave)) + return ; + + /* find the registers in use at this time + and push them away to safety */ + rsave = bitVectCplAnd(bitVectCopy(ic->rMask), + ic->rUsed); + + ic->regsSaved = 1; + if (options.useXstack) { + if (bitVectBitValue(rsave,R0_IDX)) + emitcode("mov","b,r0"); + emitcode("mov","r0,%s",spname); + for (i = 0 ; i < pic14_nRegs ; i++) { + if (bitVectBitValue(rsave,i)) { + if (i == R0_IDX) + emitcode("mov","a,b"); + else + emitcode("mov","a,%s",pic14_regWithIdx(i)->name); + emitcode("movx","@r0,a"); + emitcode("inc","r0"); + } + } + emitcode("mov","%s,r0",spname); + if (bitVectBitValue(rsave,R0_IDX)) + emitcode("mov","r0,b"); + } else + for (i = 0 ; i < pic14_nRegs ; i++) { + if (bitVectBitValue(rsave,i)) + emitcode("push","%s",pic14_regWithIdx(i)->dname); + } + + detype = getSpec(operandType(IC_LEFT(ic))); + if (detype && + (SPEC_BANK(currFunc->etype) != SPEC_BANK(detype)) && + IS_ISR(currFunc->etype) && + !ic->bankSaved) + + saverbank(SPEC_BANK(detype),ic,TRUE); + +} +/*-----------------------------------------------------------------*/ +/* unsaveRegisters - pop the pushed registers */ +/*-----------------------------------------------------------------*/ +static void unsaveRegisters (iCode *ic) +{ + int i; + bitVect *rsave; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* find the registers in use at this time + and push them away to safety */ + rsave = bitVectCplAnd(bitVectCopy(ic->rMask), + ic->rUsed); + + if (options.useXstack) { + emitcode("mov","r0,%s",spname); + for (i = pic14_nRegs ; i >= 0 ; i--) { + if (bitVectBitValue(rsave,i)) { + emitcode("dec","r0"); + emitcode("movx","a,@r0"); + if (i == R0_IDX) + emitcode("mov","b,a"); + else + emitcode("mov","%s,a",pic14_regWithIdx(i)->name); + } + + } + emitcode("mov","%s,r0",spname); + if (bitVectBitValue(rsave,R0_IDX)) + emitcode("mov","r0,b"); + } else + for (i = pic14_nRegs ; i >= 0 ; i--) { + if (bitVectBitValue(rsave,i)) + emitcode("pop","%s",pic14_regWithIdx(i)->dname); + } + +} + + +/*-----------------------------------------------------------------*/ +/* pushSide - */ +/*-----------------------------------------------------------------*/ +static void pushSide(operand * oper, int size) +{ + int offset = 0; + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + while (size--) { + char *l = aopGet(AOP(oper),offset++,FALSE,TRUE); + if (AOP_TYPE(oper) != AOP_REG && + AOP_TYPE(oper) != AOP_DIR && + strcmp(l,"a") ) { + emitcode("mov","a,%s",l); + emitcode("push","acc"); + } else + emitcode("push","%s",l); + } +} + +/*-----------------------------------------------------------------*/ +/* assignResultValue - */ +/*-----------------------------------------------------------------*/ +static void assignResultValue(operand * oper) +{ + int offset = 0; + int size = AOP_SIZE(oper); + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + while (size--) { + aopPut(AOP(oper),fReturn[offset],offset); + offset++; + } +} + + +/*-----------------------------------------------------------------*/ +/* genXpush - pushes onto the external stack */ +/*-----------------------------------------------------------------*/ +static void genXpush (iCode *ic) +{ + asmop *aop = newAsmop(0); + regs *r ; + int size,offset = 0; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + aopOp(IC_LEFT(ic),ic,FALSE); + r = getFreePtr(ic,&aop,FALSE); + + + emitcode("mov","%s,_spx",r->name); + + size = AOP_SIZE(IC_LEFT(ic)); + while(size--) { + + char *l = aopGet(AOP(IC_LEFT(ic)), + offset++,FALSE,FALSE); + MOVA(l); + emitcode("movx","@%s,a",r->name); + emitcode("inc","%s",r->name); + + } + + + emitcode("mov","_spx,%s",r->name); + + freeAsmop(NULL,aop,ic,TRUE); + freeAsmop(IC_LEFT(ic),NULL,ic,TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genIpush - genrate code for pushing this gets a little complex */ +/*-----------------------------------------------------------------*/ +static void genIpush (iCode *ic) +{ + int size, offset = 0 ; + char *l; + + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* if this is not a parm push : ie. it is spill push + and spill push is always done on the local stack */ + if (!ic->parmPush) { + + /* and the item is spilt then do nothing */ + if (OP_SYMBOL(IC_LEFT(ic))->isspilt) + return ; + + aopOp(IC_LEFT(ic),ic,FALSE); + size = AOP_SIZE(IC_LEFT(ic)); + /* push it on the stack */ + while(size--) { + l = aopGet(AOP(IC_LEFT(ic)),offset++,FALSE,TRUE); + if (*l == '#') { + MOVA(l); + l = "acc"; + } + emitcode("push","%s",l); + } + return ; + } + + /* this is a paramter push: in this case we call + the routine to find the call and save those + registers that need to be saved */ + saveRegisters(ic); + + /* if use external stack then call the external + stack pushing routine */ + if (options.useXstack) { + genXpush(ic); + return ; + } + + /* then do the push */ + aopOp(IC_LEFT(ic),ic,FALSE); + + + // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic))); + size = AOP_SIZE(IC_LEFT(ic)); + + while (size--) { + l = aopGet(AOP(IC_LEFT(ic)),offset++,FALSE,TRUE); + if (AOP_TYPE(IC_LEFT(ic)) != AOP_REG && + AOP_TYPE(IC_LEFT(ic)) != AOP_DIR && + strcmp(l,"a") ) { + emitcode("mov","a,%s",l); + emitcode("push","acc"); + } else + 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 ; + + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* 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); +} + +/*-----------------------------------------------------------------*/ +/* unsaverbank - restores the resgister bank from stack */ +/*-----------------------------------------------------------------*/ +static void unsaverbank (int bank,iCode *ic,bool popPsw) +{ + int i; + asmop *aop ; + regs *r = NULL; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + if (popPsw) { + if (options.useXstack) { + aop = newAsmop(0); + r = getFreePtr(ic,&aop,FALSE); + + + emitcode("mov","%s,_spx",r->name); + emitcode("movx","a,@%s",r->name); + emitcode("mov","psw,a"); + emitcode("dec","%s",r->name); + + }else + emitcode ("pop","psw"); + } + + for (i = (pic14_nRegs - 1) ; i >= 0 ;i--) { + if (options.useXstack) { + emitcode("movx","a,@%s",r->name); + emitcode("mov","(%s+%d),a", + regspic14[i].base,8*bank+regspic14[i].offset); + emitcode("dec","%s",r->name); + + } else + emitcode("pop","(%s+%d)", + regspic14[i].base,8*bank+regspic14[i].offset); + } + + if (options.useXstack) { + + emitcode("mov","_spx,%s",r->name); + freeAsmop(NULL,aop,ic,TRUE); + + } +} + +/*-----------------------------------------------------------------*/ +/* saverbank - saves an entire register bank on the stack */ +/*-----------------------------------------------------------------*/ +static void saverbank (int bank, iCode *ic, bool pushPsw) +{ + int i; + asmop *aop ; + regs *r = NULL; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + if (options.useXstack) { + + aop = newAsmop(0); + r = getFreePtr(ic,&aop,FALSE); + emitcode("mov","%s,_spx",r->name); + + } + + for (i = 0 ; i < pic14_nRegs ;i++) { + if (options.useXstack) { + emitcode("inc","%s",r->name); + emitcode("mov","a,(%s+%d)", + regspic14[i].base,8*bank+regspic14[i].offset); + emitcode("movx","@%s,a",r->name); + } else + emitcode("push","(%s+%d)", + regspic14[i].base,8*bank+regspic14[i].offset); + } + + if (pushPsw) { + if (options.useXstack) { + emitcode("mov","a,psw"); + emitcode("movx","@%s,a",r->name); + emitcode("inc","%s",r->name); + emitcode("mov","_spx,%s",r->name); + freeAsmop (NULL,aop,ic,TRUE); + + } else + emitcode("push","psw"); + + emitcode("mov","psw,#0x%02x",(bank << 3)&0x00ff); + } + ic->bankSaved = 1; + +} + +/*-----------------------------------------------------------------*/ +/* genCall - generates a call statement */ +/*-----------------------------------------------------------------*/ +static void genCall (iCode *ic) +{ + link *detype; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + /* if caller saves & we have not saved then */ + if (!ic->regsSaved) + saveRegisters(ic); + + /* if we are calling a function that is not using + the same register bank then we need to save the + destination registers on the stack */ + detype = getSpec(operandType(IC_LEFT(ic))); + if (detype && + (SPEC_BANK(currFunc->etype) != SPEC_BANK(detype)) && + IS_ISR(currFunc->etype) && + !ic->bankSaved) + + saverbank(SPEC_BANK(detype),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; + } + /* 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)) ) { + + _G.accInUse++; + aopOp(IC_RESULT(ic),ic,FALSE); + _G.accInUse--; + + 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); + + } + + /* if register bank was saved then pop them */ + if (ic->bankSaved) + unsaverbank(SPEC_BANK(detype),ic,TRUE); + + /* if we hade saved some registers then unsave them */ + if (ic->regsSaved && !(OP_SYMBOL(IC_LEFT(ic))->calleeSave)) + unsaveRegisters (ic); + + +} + +/*-----------------------------------------------------------------*/ +/* genPcall - generates a call by pointer statement */ +/*-----------------------------------------------------------------*/ +static void genPcall (iCode *ic) +{ + link *detype; + symbol *rlbl = newiTempLabel(NULL); + + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* if caller saves & we have not saved then */ + if (!ic->regsSaved) + saveRegisters(ic); + + /* if we are calling a function that is not using + the same register bank then we need to save the + destination registers on the stack */ + detype = getSpec(operandType(IC_LEFT(ic))); + if (detype && + IS_ISR(currFunc->etype) && + (SPEC_BANK(currFunc->etype) != SPEC_BANK(detype))) + saverbank(SPEC_BANK(detype),ic,TRUE); + + + /* push the return address on to the stack */ + emitcode("mov","a,#%05d_DS_",(rlbl->key+100)); + emitcode("push","acc"); + emitcode("mov","a,#(%05d_DS_ >> 8)",(rlbl->key+100)); + emitcode("push","acc"); + + if (options.model == MODEL_FLAT24) + { + emitcode("mov","a,#(%05d_DS_ >> 16)",(rlbl->key+100)); + emitcode("push","acc"); + } + + /* now push the calling address */ + aopOp(IC_LEFT(ic),ic,FALSE); + + pushSide(IC_LEFT(ic), FPTRSIZE); + + 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("ret",""); + emitcode("","%05d_DS_:",(rlbl->key+100)); + + + /* 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)) ) { + + _G.accInUse++; + aopOp(IC_RESULT(ic),ic,FALSE); + _G.accInUse--; + + 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); + + } + + /* if register bank was saved then unsave them */ + if (detype && + (SPEC_BANK(currFunc->etype) != + SPEC_BANK(detype))) + unsaverbank(SPEC_BANK(detype),ic,TRUE); + + /* if we hade saved some registers then + unsave them */ + if (ic->regsSaved) + unsaveRegisters (ic); + +} + +/*-----------------------------------------------------------------*/ +/* resultRemat - result is rematerializable */ +/*-----------------------------------------------------------------*/ +static int resultRemat (iCode *ic) +{ + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + labelOffset += FUNCTION_LABEL_INC; + + _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("clr","ea"); + + /* here we need to generate the equates for the + register bank if required */ +#if 0 + if (SPEC_BANK(fetype) != rbank) { + int i ; + + rbank = SPEC_BANK(fetype); + for ( i = 0 ; i < pic14_nRegs ; i++ ) { + if (strcmp(regspic14[i].base,"0") == 0) + emitcode("","%s = 0x%02x", + regspic14[i].dname, + 8*rbank+regspic14[i].offset); + else + emitcode ("","%s = %s + 0x%02x", + regspic14[i].dname, + regspic14[i].base, + 8*rbank+regspic14[i].offset); + } + } +#endif + + /* if this is an interrupt service routine then + save acc, b, dpl, dph */ + if (IS_ISR(sym->etype)) { + + if (!inExcludeList("acc")) + emitcode ("push","acc"); + if (!inExcludeList("b")) + emitcode ("push","b"); + if (!inExcludeList("dpl")) + emitcode ("push","dpl"); + if (!inExcludeList("dph")) + emitcode ("push","dph"); + if (options.model == MODEL_FLAT24 && !inExcludeList("dpx")) + { + emitcode ("push", "dpx"); + /* Make sure we're using standard DPTR */ + emitcode ("push", "dps"); + emitcode ("mov", "dps, #0x00"); + if (options.stack10bit) + { + /* This ISR could conceivably use DPTR2. Better save it. */ + emitcode ("push", "dpl1"); + emitcode ("push", "dph1"); + emitcode ("push", "dpx1"); + } + } + /* if this isr has no bank i.e. is going to + run with bank 0 , then we need to save more + registers :-) */ + if (!SPEC_BANK(sym->etype)) { + + /* if this function does not call any other + function then we can be economical and + save only those registers that are used */ + if (! sym->hasFcall) { + int i; + + /* if any registers used */ + if (sym->regsUsed) { + /* save the registers used */ + for ( i = 0 ; i < sym->regsUsed->size ; i++) { + if (bitVectBitValue(sym->regsUsed,i) || + (pic14_ptrRegReq && (i == R0_IDX || i == R1_IDX)) ) + emitcode("push","%s",pic14_regWithIdx(i)->dname); + } + } + + } else { + /* this function has a function call cannot + determines register usage so we will have the + entire bank */ + saverbank(0,ic,FALSE); + } + } + } else { + /* if callee-save to be used for this function + then save the registers being used in this function */ + if (sym->calleeSave) { + int i; + + /* if any registers used */ + if (sym->regsUsed) { + /* save the registers used */ + for ( i = 0 ; i < sym->regsUsed->size ; i++) { + if (bitVectBitValue(sym->regsUsed,i) || + (pic14_ptrRegReq && (i == R0_IDX || i == R1_IDX)) ) { + emitcode("push","%s",pic14_regWithIdx(i)->dname); + _G.nRegsSaved++; + } + } + } + } + } + + /* set the register bank to the desired value */ + if (SPEC_BANK(sym->etype) || IS_ISR(sym->etype)) { + emitcode("push","psw"); + emitcode("mov","psw,#0x%02x",(SPEC_BANK(sym->etype) << 3)&0x00ff); + } + + if (IS_RENT(sym->etype) || options.stackAuto) { + + if (options.useXstack) { + emitcode("mov","r0,%s",spname); + emitcode("mov","a,_bp"); + emitcode("movx","@r0,a"); + emitcode("inc","%s",spname); + } + else + { + /* set up the stack */ + emitcode ("push","_bp"); /* save the callers stack */ + } + emitcode ("mov","_bp,%s",spname); + } + + /* adjust the stack for the function */ + if (sym->stack) { + + int i = sym->stack; + if (i > 256 ) + werror(W_STACK_OVERFLOW,sym->name); + + if (i > 3 && sym->recvSize < 4) { + + emitcode ("mov","a,sp"); + emitcode ("add","a,#0x%02x",((char)sym->stack & 0xff)); + emitcode ("mov","sp,a"); + + } + else + while(i--) + emitcode("inc","sp"); + } + + if (sym->xstack) { + + emitcode ("mov","a,_spx"); + emitcode ("add","a,#0x%02x",((char)sym->xstack & 0xff)); + emitcode ("mov","_spx,a"); + } + +} + +/*-----------------------------------------------------------------*/ +/* genEndFunction - generates epilogue for functions */ +/*-----------------------------------------------------------------*/ +static void genEndFunction (iCode *ic) +{ + symbol *sym = OP_SYMBOL(IC_LEFT(ic)); + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + if (IS_RENT(sym->etype) || options.stackAuto) + { + emitcode ("mov","%s,_bp",spname); + } + + /* if use external stack but some variables were + added to the local stack then decrement the + local stack */ + if (options.useXstack && sym->stack) { + emitcode("mov","a,sp"); + emitcode("add","a,#0x%02x",((char)-sym->stack) & 0xff); + emitcode("mov","sp,a"); + } + + + if ((IS_RENT(sym->etype) || options.stackAuto)) { + if (options.useXstack) { + emitcode("mov","r0,%s",spname); + emitcode("movx","a,@r0"); + emitcode("mov","_bp,a"); + emitcode("dec","%s",spname); + } + else + { + emitcode ("pop","_bp"); + } + } + + /* restore the register bank */ + if (SPEC_BANK(sym->etype) || IS_ISR(sym->etype)) + emitcode ("pop","psw"); + + if (IS_ISR(sym->etype)) { + + /* now we need to restore the registers */ + /* if this isr has no bank i.e. is going to + run with bank 0 , then we need to save more + registers :-) */ + if (!SPEC_BANK(sym->etype)) { + + /* if this function does not call any other + function then we can be economical and + save only those registers that are used */ + if (! sym->hasFcall) { + int i; + + /* if any registers used */ + if (sym->regsUsed) { + /* save the registers used */ + for ( i = sym->regsUsed->size ; i >= 0 ; i--) { + if (bitVectBitValue(sym->regsUsed,i) || + (pic14_ptrRegReq && (i == R0_IDX || i == R1_IDX)) ) + emitcode("pop","%s",pic14_regWithIdx(i)->dname); + } + } + + } else { + /* this function has a function call cannot + determines register usage so we will have the + entire bank */ + unsaverbank(0,ic,FALSE); + } + } + + if (options.model == MODEL_FLAT24 && !inExcludeList("dpx")) + { + if (options.stack10bit) + { + emitcode ("pop", "dpx1"); + emitcode ("pop", "dph1"); + emitcode ("pop", "dpl1"); + } + emitcode ("pop", "dps"); + emitcode ("pop", "dpx"); + } + if (!inExcludeList("dph")) + emitcode ("pop","dph"); + if (!inExcludeList("dpl")) + emitcode ("pop","dpl"); + if (!inExcludeList("b")) + emitcode ("pop","b"); + if (!inExcludeList("acc")) + emitcode ("pop","acc"); + + if (SPEC_CRTCL(sym->etype)) + emitcode("setb","ea"); + + /* if debug then send end of function */ +/* if (options.debug && currFunc) { */ + if (currFunc) { + _G.debugLine = 1; + emitcode(";","C_DS_%s_DS_%d_DS_%d_DS_%d ==.", + ic->filename,currFunc->lastLine, + ic->level,ic->block); + if (IS_STATIC(currFunc->etype)) + emitcode(";","XF%s_DS_%s_DS_0_DS_0 ==.",moduleName,currFunc->name); + else + emitcode(";","XG_DS_%s_DS_0_DS_0 ==.",currFunc->name); + _G.debugLine = 0; + } + + emitcode ("reti",""); + } + else { + if (SPEC_CRTCL(sym->etype)) + emitcode("setb","ea"); + + if (sym->calleeSave) { + int i; + + /* if any registers used */ + if (sym->regsUsed) { + /* save the registers used */ + for ( i = sym->regsUsed->size ; i >= 0 ; i--) { + if (bitVectBitValue(sym->regsUsed,i) || + (pic14_ptrRegReq && (i == R0_IDX || i == R1_IDX)) ) + emitcode("pop","%s",pic14_regWithIdx(i)->dname); + } + } + + } + + /* if debug then send end of function */ + if (currFunc) { + _G.debugLine = 1; + emitcode(";","C_DS_%s_DS_%d_DS_%d_DS_%d ==.", + ic->filename,currFunc->lastLine, + ic->level,ic->block); + if (IS_STATIC(currFunc->etype)) + emitcode(";","XF%s_DS_%s_DS_0_DS_0 ==.",moduleName,currFunc->name); + else + emitcode(";","XG_DS_%s_DS_0_DS_0 ==.",currFunc->name); + _G.debugLine = 0; + } + + emitcode ("return",""); + } + +} + +/*-----------------------------------------------------------------*/ +/* genRet - generate code for return statement */ +/*-----------------------------------------------------------------*/ +static void genRet (iCode *ic) +{ + int size,offset = 0 , pushed = 0; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* 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 ; + if (AOP_TYPE(IC_LEFT(ic)) == AOP_DPTR) { + /* #NOCHANGE */ + l = aopGet(AOP(IC_LEFT(ic)),offset++, + FALSE,TRUE); + emitcode("push","%s",l); + pushed++; + } else { + l = aopGet(AOP(IC_LEFT(ic)),offset, + FALSE,FALSE); + if (strcmp(fReturn[offset],l)) + emitcode("mov","%s,%s",fReturn[offset++],l); + } + } + + if (pushed) { + while(pushed) { + pushed--; + if (strcmp(fReturn[pushed],"a")) + emitcode("pop",fReturn[pushed]); + else + emitcode("pop","acc"); + } + } + 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("goto","_%05d_DS_",(returnLabel->key+100)); + +} + +/*-----------------------------------------------------------------*/ +/* genLabel - generates a label */ +/*-----------------------------------------------------------------*/ +static void genLabel (iCode *ic) +{ + /* special case never generate */ + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + if (IC_LABEL(ic) == entryLabel) + return ; + + emitcode("","_%05d_DS_:",(IC_LABEL(ic)->key+100 + labelOffset)); +} + +/*-----------------------------------------------------------------*/ +/* genGoto - generates a goto */ +/*-----------------------------------------------------------------*/ +//tsd +static void genGoto (iCode *ic) +{ + emitcode ("goto","_%05d_DS_",(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; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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)); + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* 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 1 then it is faster to add */ + if ((icount = floatFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit)) > 2) + return FALSE ; + + /* if increment 16 bits in register */ + if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) && + (icount == 1)) { + + int offset = MSB16; + + emitcode("incf","%s,f",aopGet(AOP(IC_RESULT(ic)),LSB,FALSE,FALSE)); + + while(--size) { + emitcode("skpnz",""); + emitcode(" incf","%s,f",aopGet(AOP(IC_RESULT(ic)),offset++,FALSE,FALSE)); + } + + 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 ; + + /* If we are incrementing the same register by two: */ + + if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) { + + while (icount--) + emitcode("incf","%s,f",aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE)); + + return TRUE ; + } + + return FALSE ; +} + +/*-----------------------------------------------------------------*/ +/* outBitAcc - output a bit in acc */ +/*-----------------------------------------------------------------*/ +static void outBitAcc(operand *result) +{ + symbol *tlbl = newiTempLabel(NULL); + /* if the result is a bit */ + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + if (AOP_TYPE(result) == AOP_CRY){ + aopPut(AOP(result),"a",0); + } + else { + emitcode("jz","%05d_DS_",tlbl->key+100); + emitcode("mov","a,%s",one); + emitcode("","%05d_DS_:",tlbl->key+100); + outAcc(result); + } +} + +/*-----------------------------------------------------------------*/ +/* genPlusBits - generates code for addition of two bits */ +/*-----------------------------------------------------------------*/ +static void genPlusBits (iCode *ic) +{ + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* + The following block of code will add two bits. + Note that it'll even work if the destination is + the carry (C in the status register). + It won't work if the 'Z' bit is a source or destination. + */ + emitcode("movlw","(1 << (%s & 7))", + AOP(IC_RESULT(ic))->aopu.aop_dir, + AOP(IC_RESULT(ic))->aopu.aop_dir); + emitcode("bcf","(%s >> 3), (%s & 7)", + AOP(IC_RESULT(ic))->aopu.aop_dir, + AOP(IC_RESULT(ic))->aopu.aop_dir); + emitcode("btfsc","(%s >> 3), (%s & 7)", + AOP(IC_RIGHT(ic))->aopu.aop_dir, + AOP(IC_RIGHT(ic))->aopu.aop_dir); + emitcode("xorwf","%s,f", + AOP(IC_RESULT(ic))->aopu.aop_dir); + emitcode("btfsc","(%s >> 3), (%s & 7)", + AOP(IC_LEFT(ic))->aopu.aop_dir, + AOP(IC_LEFT(ic))->aopu.aop_dir); + emitcode("xorwf","%s,f", + AOP(IC_RESULT(ic))->aopu.aop_dir); +} + +#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 :- */ + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + 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 ;%d",AOP(IC_LEFT(ic))->aopu.aop_dir,__LINE__); + /* 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 ;%d",__LINE__); + 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 ;%d",__LINE__); + 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)); + + if(AOP(IC_RIGHT(ic))->type == AOP_LIT) { + /* Add a literal to something else */ + + unsigned lit = floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit); + + /* add the first byte: */ + emitcode("movlw","0x%x", lit & 0xff); + emitcode("addwf","%s,f", aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE)); + + offset = 1; + size--; + + while(size--){ + + emitcode("rlf","_known_zero,w"); + emitcode(" addwf","%s,f", aopGet(AOP(IC_LEFT(ic)),offset,FALSE,FALSE)); + + lit >>= 8; + if(lit & 0xff) { + emitcode("movlw","0x%x", lit & 0xff); + emitcode("addwf","%s,f", aopGet(AOP(IC_LEFT(ic)),offset,FALSE,FALSE)); + + } + offset++; + } + + } else if(AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) { + + /* here we are adding a bit to a char or int */ + if(size == 1) { + if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) { + + emitcode("btfsc","(%s >> 3), (%s & 7)", + AOP(IC_RIGHT(ic))->aopu.aop_dir, + AOP(IC_RIGHT(ic))->aopu.aop_dir); + emitcode(" incf","%s,f", aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE)); + } else { + + emitcode("movf","%s,w", aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE)); + emitcode("btfsc","(%s >> 3), (%s & 7)", + AOP(IC_RIGHT(ic))->aopu.aop_dir, + AOP(IC_RIGHT(ic))->aopu.aop_dir); + emitcode(" incf","%s,w", aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE)); + emitcode("movwf","%s", aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE)); + } + + } else { + int offset = 1; + + if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) { + emitcode("clrz",""); + + emitcode("btfsc","(%s >> 3), (%s & 7)", + AOP(IC_RIGHT(ic))->aopu.aop_dir, + AOP(IC_RIGHT(ic))->aopu.aop_dir); + emitcode(" incf","%s,f", aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE)); + + } else { + + emitcode("movf","%s,w", aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE)); + emitcode("btfsc","(%s >> 3), (%s & 7)", + AOP(IC_RIGHT(ic))->aopu.aop_dir, + AOP(IC_RIGHT(ic))->aopu.aop_dir); + emitcode(" incf","%s,w", aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE)); + emitcode("movwf","%s", aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE)); + + } + + while(--size){ + emitcode("skpz",""); + emitcode(" incf","%s,f", aopGet(AOP(IC_RIGHT(ic)),offset++,FALSE,FALSE)); + } + + } + + } else { + + if(strcmp(aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE),"a") == 0 ) { + emitcode("addwf","%s,w", aopGet(AOP(IC_RIGHT(ic)),0,FALSE,FALSE)); + emitcode("movwf","%s", aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE)); + } else { + emitcode("movf","%s,w", aopGet(AOP(IC_RIGHT(ic)),0,FALSE,FALSE)); + + if ( (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC) || (AOP_TYPE(IC_RESULT(ic)) == AOP_ACC) ) + emitcode("addwf","%s,w", aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE)); + else { + + if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) + emitcode("addwf","%s,f", aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE)); + else { + emitcode("addwf","%s,w", aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE)); + emitcode("movwf","%s", aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE)); + } + } + } + + offset = 1; + size--; + + while(size--){ + if (!sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) { + emitcode("movf","%s,w", aopGet(AOP(IC_LEFT(ic)),offset,FALSE,FALSE)); + emitcode("movwf","%s", aopGet(AOP(IC_RESULT(ic)),offset,FALSE,FALSE)); + } + emitcode("movf","%s,w", aopGet(AOP(IC_RIGHT(ic)),offset,FALSE,FALSE)); + emitcode("skpnc",""); + emitcode("incfsz","%s,w",aopGet(AOP(IC_RIGHT(ic)),offset,FALSE,FALSE)); + emitcode("addwf","%s,f", aopGet(AOP(IC_RESULT(ic)),offset,FALSE,FALSE)); + + } + + } + + //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)); + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* 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)) > 2) + return FALSE ; + + /* if decrement 16 bits in register */ + if (sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) && + (size > 1) && + (icount == 1)) { + + if(size == 2) { + emitcode("decf","%s,f",aopGet(AOP(IC_RESULT(ic)),LSB,FALSE,FALSE)); + emitcode("incfsz","%s,w",aopGet(AOP(IC_RESULT(ic)),LSB,FALSE,FALSE)); + emitcode(" decf","%s,f",aopGet(AOP(IC_RESULT(ic)),MSB16,FALSE,FALSE)); + } else { + /* size is 3 or 4 */ + emitcode("movlw","0xff"); + emitcode("addwf","%s,f",aopGet(AOP(IC_RESULT(ic)),LSB,FALSE,FALSE)); + + emitcode("skpnc",""); + emitcode("addwf","%s,f",aopGet(AOP(IC_RESULT(ic)),MSB16,FALSE,FALSE)); + emitcode("skpnc",""); + emitcode("addwf","%s,f",aopGet(AOP(IC_RESULT(ic)),MSB24,FALSE,FALSE)); + + if(size > 3) { + emitcode("skpnc",""); + emitcode("addwf","%s,f",aopGet(AOP(IC_RESULT(ic)),MSB32,FALSE,FALSE)); + } + + } + + 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 ("decf","%s,f",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); + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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); + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY){ + emitcode("mov","c,%s",AOP(IC_LEFT(ic))->aopu.aop_dir); + emitcode("jnb","%s,%05d_DS_",AOP(IC_RIGHT(ic))->aopu.aop_dir,(lbl->key+100)); + emitcode("cpl","c"); + emitcode("","%05d_DS_:",(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_DS_",AOP(IC_LEFT(ic))->aopu.aop_dir,(lbl->key+100)); + emitcode("inc","a"); + emitcode("","%05d_DS_:",(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; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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(IC_RIGHT(ic))->type == AOP_LIT) { + /* Add a literal to something else */ + + lit = (unsigned long)floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit); + lit = - (long)lit; + + /* add the first byte: */ + emitcode("movlw","0x%x", lit & 0xff); + emitcode("addwf","%s,f", aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE)); + + offset = 1; + size--; + + while(size--){ + + emitcode("rlf","_known_zero,w"); + emitcode("addwf","%s,f", aopGet(AOP(IC_LEFT(ic)),offset,FALSE,FALSE)); + + lit >>= 8; + if(lit & 0xff) { + emitcode("movlw","0x%x", lit & 0xff); + emitcode("addwf","%s,f", aopGet(AOP(IC_LEFT(ic)),offset,FALSE,FALSE)); + + } + offset++; + } + + } else { + + emitcode("movf","%s", aopGet(AOP(IC_RIGHT(ic)),0,FALSE,FALSE)); + emitcode("subwf","%s,f", aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE)); + + offset = 1; + size--; + + while(size--){ + emitcode("movf","%s,w", aopGet(AOP(IC_RIGHT(ic)),offset,FALSE,FALSE)); + emitcode("skpnc",""); + emitcode("incfsz","%s,w",aopGet(AOP(IC_RIGHT(ic)),offset,FALSE,FALSE)); + emitcode("subwf","%s,f", aopGet(AOP(IC_LEFT(ic)),offset,FALSE,FALSE)); + + } + + } + + + // 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) +{ + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + 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; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* (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_DS_", (lbl->key+100)); + emitcode("","%05d_DS_:",(lbl->key+100)); + emitcode("xch","a,%s",aopGet(AOP(right),0,FALSE,FALSE)); + lbl = newiTempLabel(NULL); + emitcode("jc","%05d_DS_",(lbl->key+100)); + emitcode("subb","a,%s", aopGet(AOP(left),0,FALSE,FALSE)); + emitcode("","%05d_DS_:",(lbl->key+100)); + } + + lbl = newiTempLabel(NULL); + emitcode("xch","a,%s",aopGet(AOP(left),0,FALSE,FALSE)); + emitcode("cjne","a,#0x80,%05d_DS_", (lbl->key+100)); + emitcode("","%05d_DS_:",(lbl->key+100)); + emitcode("xch","a,%s",aopGet(AOP(left),0,FALSE,FALSE)); + lbl = newiTempLabel(NULL); + emitcode("jc","%05d_DS_",(lbl->key+100)); + emitcode("subb","a,%s", aopGet(AOP(right),0,FALSE,FALSE)); + emitcode("","%05d_DS_:",(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); + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* 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; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* 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; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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_DS_",(lbl->key+100)); + emitcode("cpl","a"); + emitcode("inc","a"); + emitcode("","%05d_DS_:",(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_DS_",(lbl->key+100)); + emitcode("cpl","a"); + emitcode("inc","a"); + emitcode("","%05d_DS_:",(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_DS_",(lbl->key+100)); + emitcode("jnb","acc.7,%05d_DS_",(lbl->key+100)); + CLRC; + emitcode("clr","a"); + emitcode("subb","a,b"); + emitcode("mov","b,a"); + emitcode("","%05d_DS_:",(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); + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* 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 ; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* 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_DS_",(lbl->key+100)); + emitcode("cpl","a"); + emitcode("inc","a"); + emitcode("","%05d_DS_:",(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_DS_",(lbl->key+100)); + emitcode("cpl","a"); + emitcode("inc","a"); + emitcode("","%05d_DS_:",(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_DS_",(lbl->key+100)); + emitcode("jnb","acc.7,%05d_DS_",(lbl->key+100)); + CLRC ; + emitcode("clr","a"); + emitcode("subb","a,b"); + emitcode("mov","b,a"); + emitcode("","%05d_DS_:",(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); + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* 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; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* if true label then we jump if condition + supplied is true */ + if ( IC_TRUE(ic) ) { + + if(strcmp(jval,"a") == 0) + emitcode("skpz",""); + else if (strcmp(jval,"c") == 0) + emitcode("skpc",""); + else + emitcode("skpnc",""); + + emitcode(" goto","_%05d_DS_",IC_TRUE(ic)->key+100 + labelOffset); + + } + else { + /* false label is present */ + if(strcmp(jval,"a") == 0) + emitcode("skpnz",""); + else if (strcmp(jval,"c") == 0) + emitcode("skpnc",""); + else + emitcode("skpc",""); + + emitcode(" goto","_%05d_DS_",IC_FALSE(ic)->key+100 + labelOffset); + + + } + + + /* mark the icode as generated */ + ic->generated = 1; +} + +/*-----------------------------------------------------------------*/ +/* genSkip */ +/*-----------------------------------------------------------------*/ +static void genSkip(iCode *ifx,int status_bit) +{ + if(!ifx) + return; + + if ( IC_TRUE(ifx) ) { + switch(status_bit) { + case 'z': + emitcode("skpnz",""); + break; + + case 'c': + emitcode("skpnc",""); + break; + + case 'd': + emitcode("skpndc",""); + break; + + } + + emitcode("goto","_%05d_DS_",IC_TRUE(ifx)->key+100+labelOffset); + + } else { + + switch(status_bit) { + + case 'z': + emitcode("skpz",""); + break; + + case 'c': + emitcode("skpc",""); + break; + + case 'd': + emitcode("skpdc",""); + break; + } + emitcode("goto","_%05d_DS_",IC_FALSE(ifx)->key+100+labelOffset); + + } + +} + +/*-----------------------------------------------------------------*/ +/* genSkip */ +/*-----------------------------------------------------------------*/ +static void genSkipc(iCode *ifx, int condition) +{ + if(!ifx) + return; + + if(condition) + emitcode("skpnc",""); + else + emitcode("skpc",""); + + if ( IC_TRUE(ifx) ) + emitcode("goto","_%05d_DS_",IC_TRUE(ifx)->key+100+labelOffset); + else + emitcode("goto","_%05d_DS_",IC_FALSE(ifx)->key+100+labelOffset); + +} + +/*-----------------------------------------------------------------*/ +/* 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; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* 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_DS_", + aopGet(AOP(left),offset,FALSE,FALSE), + aopGet(AOP(right),offset,FALSE,FALSE), + lbl->key+100); + emitcode("","%05d_DS_:",lbl->key+100); + } else { + + if(AOP_TYPE(right) == AOP_LIT) { + + DEBUGemitcode(";right lit","%d",sign); + + lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit); + //default: + while(size--) { + emitcode("movlw","0x%x",(lit >> (size*8)) & 0xff); + emitcode("subwf","%s,w",aopGet(AOP(left),size,FALSE,FALSE)); + genSkipc(ifx,IC_TRUE(ifx) == NULL); + } + ifx->generated = 1; + return; + } + if(AOP_TYPE(left) == AOP_LIT) { + + DEBUGemitcode(";left lit","%d",sign); + + lit = (unsigned long)(floatFromVal(AOP(left)->aopu.aop_lit))+1; + + //default: + while(size--) { + emitcode("movlw","0x%x",(lit >> (size*8)) & 0xff); + emitcode("subwf","%s,w",aopGet(AOP(right),size,FALSE,FALSE)); + genSkipc(ifx,IC_TRUE(ifx) != NULL); + } + ifx->generated = 1; + return; + } + + + // CLRC; + DEBUGemitcode(";sign","%d",sign); + emitcode("movf","%s,w",aopGet(AOP(right),offset,FALSE,FALSE)); + emitcode("subwf","%s,w",aopGet(AOP(left),offset++,FALSE,FALSE)); + size--; + while (size--) { + + /*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)); + */ + emitcode("movf","%s,w",aopGet(AOP(right),offset,FALSE,FALSE)); + emitcode("skpc",""); + emitcode("incfsz","%s,w",aopGet(AOP(right),offset,FALSE,FALSE)); + emitcode("subwf","%s,w",aopGet(AOP(left),offset,FALSE,FALSE)); + offset++; + } + } + } + + //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 ; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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 ; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* 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--) { + if(lit & 0xff) { + emitcode("movf","%s,w",aopGet(AOP(left),offset,FALSE,FALSE)); + emitcode("xorlw","0x%x",lit & 0xff); + } else + emitcode("movf","%s,f",aopGet(AOP(left),offset,FALSE,FALSE)); + + emitcode("skpnz",""); + emitcode("goto","_%05d_DS_",lbl->key+100+labelOffset); + offset++; + lit >>= 8; + } + } + + /* 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--) { + if((AOP_TYPE(left) == AOP_DIR && AOP_TYPE(right) == AOP_LIT) && + ( (lit & 0xff) != 0)) { + emitcode("movf","%s,w",aopGet(AOP(left),offset,FALSE,FALSE)); + emitcode("xorlw","0x%x",lit & 0xff); + lit >>= 8; + } else + emitcode("movf","%s,f",aopGet(AOP(left),offset,FALSE,FALSE)); + + emitcode("skpz",""); + emitcode("goto","_%05d_DS_",lbl->key+100+labelOffset); + offset++; +/* + 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_DS_",lbl->key+100); + else + emitcode("cjne","a,%s,%05d_DS_", + 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_DS_",lbl->key+100); + offset++; + } + } +} + +/*-----------------------------------------------------------------*/ +/* gencjne - compare and jump if not equal */ +/*-----------------------------------------------------------------*/ +static void gencjne(operand *left, operand *right, symbol *lbl) +{ + symbol *tlbl = newiTempLabel(NULL); + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + gencjneshort(left, right, lbl); + + emitcode("mov","a,%s",one); + emitcode("sjmp","%05d_DS_",tlbl->key+100); + emitcode("","%05d_DS_:",lbl->key+100); + emitcode("clr","a"); + emitcode("","%05d_DS_:",tlbl->key+100); +} + + +/*-----------------------------------------------------------------*/ +/* genCmpEq - generates code for equal to */ +/*-----------------------------------------------------------------*/ +static void genCmpEq (iCode *ic, iCode *ifx) +{ + operand *left, *right, *result; + unsigned long lit = 0L; + int size,offset=0; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + if(ifx) + DEBUGemitcode ("; ifx is non-null",""); + else + DEBUGemitcode ("; ifx is null",""); + + aopOp((left=IC_LEFT(ic)),ic,FALSE); + aopOp((right=IC_RIGHT(ic)),ic,FALSE); + aopOp((result=IC_RESULT(ic)),ic,TRUE); + + size = max(AOP_SIZE(left),AOP_SIZE(right)); + + /* 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_DS_",AOP(right)->aopu.aop_dir,(lbl->key+100)); + emitcode("cpl","c"); + emitcode("","%05d_DS_:",(lbl->key+100)); + } + /* if true label then we jump if condition + supplied is true */ + tlbl = newiTempLabel(NULL); + if ( IC_TRUE(ifx) ) { + emitcode("jnc","%05d_DS_",tlbl->key+100); + emitcode("ljmp","%05d_DS_",IC_TRUE(ifx)->key+100); + } else { + emitcode("jc","%05d_DS_",tlbl->key+100); + emitcode("ljmp","%05d_DS_",IC_FALSE(ifx)->key+100); + } + emitcode("","%05d_DS_:",tlbl->key+100); + } else { + + /* They're not both bit variables. Is the right a literal? */ + if(AOP_TYPE(right) == AOP_LIT) { + + lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit); + while (size--) { + + if(size >= 1) { + int l = lit & 0xff; + int h = (lit>>8) & 0xff; + int optimized=0; + + /* Check special cases for integers */ + switch(lit & 0xffff) { + case 0x0000: + emitcode("movf","%s,w",aopGet(AOP(left),offset,FALSE,FALSE)); + emitcode("iorwf","%s,w",aopGet(AOP(left),offset+1,FALSE,FALSE)); + genSkip(ifx,'z'); + optimized++; + break; + case 0x0001: + emitcode("decf","%s,w",aopGet(AOP(left),offset,FALSE,FALSE)); + emitcode("iorwf","%s,w",aopGet(AOP(left),offset+1,FALSE,FALSE)); + genSkip(ifx,'z'); + optimized++; + break; + case 0x0100: + emitcode("decf","%s,w",aopGet(AOP(left),offset+1,FALSE,FALSE)); + emitcode("iorwf","%s,w",aopGet(AOP(left),offset,FALSE,FALSE)); + genSkip(ifx,'z'); + optimized++; + break; + case 0x00ff: + emitcode("incf","%s,w",aopGet(AOP(left),offset,FALSE,FALSE)); + emitcode("iorwf","%s,w",aopGet(AOP(left),offset+1,FALSE,FALSE)); + genSkip(ifx,'z'); + optimized++; + break; + case 0xff00: + emitcode("incf","%s,w",aopGet(AOP(left),offset+1,FALSE,FALSE)); + emitcode("iorwf","%s,w",aopGet(AOP(left),offset,FALSE,FALSE)); + genSkip(ifx,'z'); + optimized++; + break; + default: + if(h == 0) { + emitcode("movf","%s,w",aopGet(AOP(left),offset,FALSE,FALSE)); + emitcode("xorlw","0x%x",l); + emitcode("iorwf","%s,w",aopGet(AOP(left),offset+1,FALSE,FALSE)); + optimized++; + genSkip(ifx,'z'); + } else if (l == 0) { + emitcode("movf","%s,w",aopGet(AOP(left),offset+1,FALSE,FALSE)); + emitcode("xorlw","0x%x",h); + emitcode("iorwf","%s,w",aopGet(AOP(left),offset,FALSE,FALSE)); + optimized++; + genSkip(ifx,'z'); + } else { + emitcode("movf","%s,w",aopGet(AOP(left),offset,FALSE,FALSE)); + emitcode("xorlw","0x%x",l); + emitcode("movlw","0x%x",h); + emitcode("skpz",""); + emitcode("xorwf","%s,w",aopGet(AOP(left),offset+1,FALSE,FALSE)); + optimized++; + genSkip(ifx,'z'); + } + + } + if(optimized) { + size--; + offset+=2; + lit>>=16; + + continue; + } + + } + + switch(lit & 0xff) { + case 1: + if ( IC_TRUE(ifx) ) { + emitcode("decf","%s,w",aopGet(AOP(left),offset,FALSE,FALSE)); + emitcode("skpnz",""); + emitcode("goto","_%05d_DS_",IC_TRUE(ifx)->key+100+labelOffset); + } else { + emitcode("decfsz","%s,w",aopGet(AOP(left),offset,FALSE,FALSE)); + emitcode("goto","_%05d_DS_",IC_FALSE(ifx)->key+100+labelOffset); + } + break; + case 0xff: + if ( IC_TRUE(ifx) ) { + emitcode("incf","%s,w",aopGet(AOP(left),offset,FALSE,FALSE)); + emitcode("skpnz",""); + emitcode("goto","_%05d_DS_",IC_TRUE(ifx)->key+100+labelOffset); + } else { + emitcode("incfsz","%s,w",aopGet(AOP(left),offset,FALSE,FALSE)); + emitcode("goto","_%05d_DS_",IC_FALSE(ifx)->key+100+labelOffset); + } + break; + default: + emitcode("movf","%s,w",aopGet(AOP(left),offset,FALSE,FALSE)); + if(lit) + emitcode("xorlw","0x%x",lit & 0xff); + genSkip(ifx,'z'); + } + + + // emitcode("goto","_%05d_DS_",tlbl->key+100+labelOffset); + //emitcode("","_%05d_DS_:",tlbl->key+100+labelOffset); + offset++; + lit >>= 8; + } + + } else { + /* They're both variables that are larger than bits */ + int s = size; + + tlbl = newiTempLabel(NULL); + + while(size--) { + + emitcode("movf","%s,w",aopGet(AOP(left),offset,FALSE,FALSE)); + emitcode("xorwf","%s,w",aopGet(AOP(right),offset,FALSE,FALSE)); + + if ( IC_TRUE(ifx) ) { + if(size) { + emitcode("skpz",""); + emitcode(" goto","_%05d_DS_",tlbl->key+100); + } else { + emitcode("skpnz",""); + emitcode(" goto","_%05d_DS_",IC_TRUE(ifx)->key+100+labelOffset); + } + } else { + emitcode("skpz",""); + emitcode(" goto","_%05d_DS_",IC_FALSE(ifx)->key+100+labelOffset); + } + offset++; + } + if(s>1 && IC_TRUE(ifx)) + emitcode("","_%05d_DS_:",tlbl->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_DS_",AOP(right)->aopu.aop_dir,(lbl->key+100)); + emitcode("cpl","c"); + emitcode("","%05d_DS_:",(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 */ + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* 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_DS_",tlbl->key+100); + toBoolean(right); + emitcode("","%05d_DS_:",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 */ + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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_DS_",tlbl->key+100); + toBoolean(right); + emitcode("","%05d_DS_:",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; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + for(idx = 0; idx < 32; idx++) + if(lit == pw[idx]) + return idx+1; + return 0; +} + +/*-----------------------------------------------------------------*/ +/* continueIfTrue - */ +/*-----------------------------------------------------------------*/ +static void continueIfTrue (iCode *ic) +{ + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + if(IC_TRUE(ic)) + emitcode("ljmp","%05d_DS_",IC_TRUE(ic)->key+100); + ic->generated = 1; +} + +/*-----------------------------------------------------------------*/ +/* jmpIfTrue - */ +/*-----------------------------------------------------------------*/ +static void jumpIfTrue (iCode *ic) +{ + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + if(!IC_TRUE(ic)) + emitcode("ljmp","%05d_DS_",IC_FALSE(ic)->key+100); + ic->generated = 1; +} + +/*-----------------------------------------------------------------*/ +/* jmpTrueOrFalse - */ +/*-----------------------------------------------------------------*/ +static void jmpTrueOrFalse (iCode *ic, symbol *tlbl) +{ + // ugly but optimized by peephole + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + if(IC_TRUE(ic)){ + symbol *nlbl = newiTempLabel(NULL); + emitcode("sjmp","%05d_DS_",nlbl->key+100); + emitcode("","%05d_DS_:",tlbl->key+100); + emitcode("ljmp","%05d_DS_",IC_TRUE(ic)->key+100); + emitcode("","%05d_DS_:",nlbl->key+100); + } + else{ + emitcode("ljmp","%05d_DS_",IC_FALSE(ic)->key+100); + emitcode("","%05d_DS_:",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]; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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_DS_",(posbit-1)&0x07,tlbl->key+100); + else{ + if(bytelit != 0x0FFL) + emitcode("anl","a,%s", + aopGet(AOP(right),offset,FALSE,TRUE)); + emitcode("jnz","%05d_DS_",tlbl->key+100); + } + } + offset++; + } + // bit = left & literal + if(size){ + emitcode("clr","c"); + emitcode("","%05d_DS_:",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_DS_",tlbl->key+100); + offset++; + } + if(size){ + CLRC; + emitcode("","%05d_DS_:",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; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + 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("bsf","(%s >> 3), (%s & 7)", + AOP(result)->aopu.aop_dir, + AOP(result)->aopu.aop_dir); + else if(ifx) + continueIfTrue(ifx); + goto release; + } + emitcode(";XXXsetb","c %s,%d",__FILE__,__LINE__); + } else { + // lit == 0 => result = left + if(size && sameRegs(AOP(result),AOP(left))) + goto release; + emitcode(";XXX mov","c,%s %s,%d",AOP(left)->aopu.aop_dir,__FILE__,__LINE__); + } + } else { + if (AOP_TYPE(right) == AOP_CRY){ + if(sameRegs(AOP(result),AOP(left))){ + // c = bit | bit; + emitcode("bcf","(%s >> 3), (%s & 7)", + AOP(result)->aopu.aop_dir, + AOP(result)->aopu.aop_dir); + emitcode("btfsc","(%s >> 3), (%s & 7)", + AOP(right)->aopu.aop_dir, + AOP(right)->aopu.aop_dir); + emitcode("bsf","(%s >> 3), (%s & 7)", + AOP(result)->aopu.aop_dir, + AOP(result)->aopu.aop_dir); + } else { + + emitcode("bcf","(%s >> 3), (%s & 7)", + AOP(result)->aopu.aop_dir, + AOP(result)->aopu.aop_dir); + emitcode("btfss","(%s >> 3), (%s & 7)", + AOP(right)->aopu.aop_dir, + AOP(right)->aopu.aop_dir); + emitcode("btfsc","(%s >> 3), (%s & 7)", + AOP(left)->aopu.aop_dir, + AOP(left)->aopu.aop_dir); + emitcode("bsf","(%s >> 3), (%s & 7)", + AOP(result)->aopu.aop_dir, + AOP(result)->aopu.aop_dir); + } + } + else{ + // c = bit | val; + symbol *tlbl = newiTempLabel(NULL); + emitcode(";XXX "," %s,%d",__FILE__,__LINE__); + if(!((AOP_TYPE(result) == AOP_CRY) && ifx)) + emitcode(";XXX setb","c"); + emitcode(";XXX jb","%s,%05d_DS_", + AOP(left)->aopu.aop_dir,tlbl->key+100); + toBoolean(right); + emitcode(";XXX jnz","%05d_DS_",tlbl->key+100); + if((AOP_TYPE(result) == AOP_CRY) && ifx){ + jmpTrueOrFalse(ifx, tlbl); + goto release; + } else { + CLRC; + emitcode("","%05d_DS_:",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){ + emitcode(";XXX "," %s,%d",__FILE__,__LINE__); + // result = 1 + if(size) + emitcode(";XXX setb","%s",AOP(result)->aopu.aop_dir); + else + continueIfTrue(ifx); + goto release; + } else { + emitcode(";XXX "," %s,%d",__FILE__,__LINE__); + // lit = 0, result = boolean(left) + if(size) + emitcode(";XXX setb","c"); + toBoolean(right); + if(size){ + symbol *tlbl = newiTempLabel(NULL); + emitcode(";XXX jnz","%05d_DS_",tlbl->key+100); + CLRC; + emitcode("","%05d_DS_:",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++,lit>>=8) { + if(AOP_TYPE(right) == AOP_LIT){ + if((lit & 0xff) == 0) + /* or'ing with 0 has no effect */ + continue; + else { + int p = my_powof2(lit & 0xff); + if(p>=0) { + /* only one bit is set in the literal, so use a bsf instruction */ + emitcode("bsf","%s,%d",aopGet(AOP(left),offset,FALSE,TRUE),p); + } else { + emitcode("movlw","0x%x", (lit & 0xff)); + emitcode("iorwf","%s,f",aopGet(AOP(left),offset,FALSE,TRUE),p); + } + + } + } else { + if (AOP_TYPE(left) == AOP_ACC) + emitcode("iorwf","%s,w",aopGet(AOP(right),offset,FALSE,FALSE)); + else { + emitcode("movf","%s,w",aopGet(AOP(right),offset,FALSE,FALSE)); + emitcode("iorwf","%s,f",aopGet(AOP(left),offset,FALSE,FALSE)); + + } + } + } + } 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)); + emitcode(";XXX "," %s,%d",__FILE__,__LINE__); + + if(size) + emitcode(";XXX setb","c"); + while(sizer--){ + MOVA(aopGet(AOP(right),offset,FALSE,FALSE)); + emitcode(";XXX orl","a,%s", + aopGet(AOP(left),offset,FALSE,FALSE)); + emitcode(";XXX jnz","%05d_DS_",tlbl->key+100); + offset++; + } + if(size){ + CLRC; + emitcode("","%05d_DS_:",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("iorwf","%s,w",aopGet(AOP(right),offset,FALSE,FALSE)); + else { + emitcode("movf","%s,w",aopGet(AOP(right),offset,FALSE,FALSE)); + emitcode("iorwf","%s,w", + aopGet(AOP(left),offset,FALSE,FALSE)); + } + emitcode("movwf","%s",aopGet(AOP(result),offset,FALSE,FALSE)); + } + } + +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; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + 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_DS_",tlbl->key+100); + sizer--; + } + // val = (0,1) + emitcode("rrc","a"); + } + emitcode("jnb","%s,%05d_DS_",AOP(left)->aopu.aop_dir,(tlbl->key+100)); + emitcode("cpl","c"); + emitcode("","%05d_DS_:",(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_DS_",tlbl->key+100); + offset++; + } + if(size){ + CLRC; + emitcode("","%05d_DS_:",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; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + _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; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* 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); + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* 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) +{ + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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) +{ + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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) +{ + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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 ; + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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_DS_",7-shCount,tlbl->key+100); + emitcode("orl","a,#0x%02x", + (unsigned char)~SRMask[shCount]); + emitcode("","%05d_DS_:",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) +{ + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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; + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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; + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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) +{ + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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) +{ + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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) +{ + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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) +{ + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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) +{ + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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 ; + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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_DS_",7-shCount,tlbl->key+100); + emitcode("orl","a,#0x%02x", + (unsigned char)~SRMask[shCount]); // 111AAAAA:BBBCCCCC + emitcode("","%05d_DS_:",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_DS_",7-shCount,tlbl->key+100); + emitcode("orl","a,#0x%02x", + (unsigned char)~SRMask[shCount]); // 111111AA:BBBBBBCC + emitcode("","%05d_DS_:",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_DS_",7-shCount,tlbl->key+100); + emitcode("orl","a,#0x%02x", + (unsigned char)~SRMask[shCount]); // 1111111A:BBBBBBBC + emitcode("","%05d_DS_:",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) +{ + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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) +{ + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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) +{ + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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) +{ + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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) +{ + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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); + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + 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_DS_",tlbl1->key+100); + emitcode("","%05d_DS_:",tlbl->key+100); + emitcode("add","a,acc"); + emitcode("","%05d_DS_:",tlbl1->key+100); + emitcode("djnz","b,%05d_DS_",tlbl->key+100); + aopPut(AOP(result),"a",0); + goto release ; + } + + reAdjustPreg(AOP(result)); + + emitcode("sjmp","%05d_DS_",tlbl1->key+100); + emitcode("","%05d_DS_:",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_DS_:",tlbl1->key+100); + emitcode("djnz","b,%05d_DS_",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) +{ + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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) +{ + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* 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) +{ + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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) +{ + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* 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; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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 */ + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + 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_DS_",tlbl1->key+100); + emitcode("","%05d_DS_:",tlbl->key+100); + emitcode("mov","c,ov"); + emitcode("rrc","a"); + emitcode("","%05d_DS_:",tlbl1->key+100); + emitcode("djnz","b,%05d_DS_",tlbl->key+100); + aopPut(AOP(result),"a",0); + goto release ; + } + + reAdjustPreg(AOP(result)); + emitcode("sjmp","%05d_DS_",tlbl1->key+100); + emitcode("","%05d_DS_:",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_DS_:",tlbl1->key+100); + emitcode("djnz","b,%05d_DS_",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))); + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + 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_DS_",tlbl1->key+100); + emitcode("","%05d_DS_:",tlbl->key+100); + CLRC; + emitcode("rrc","a"); + emitcode("","%05d_DS_:",tlbl1->key+100); + emitcode("djnz","b,%05d_DS_",tlbl->key+100); + aopPut(AOP(result),"a",0); + goto release ; + } + + reAdjustPreg(AOP(result)); + emitcode("sjmp","%05d_DS_",tlbl1->key+100); + emitcode("","%05d_DS_:",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_DS_:",tlbl1->key+100); + emitcode("djnz","b,%05d_DS_",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 ; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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); + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* 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]; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + 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; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + 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)); + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + 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)); + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + 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)); + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + 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 ; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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]; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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); + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + 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)); + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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)); + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + 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; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + 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; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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 ; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + 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) ; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + /* if they are the same */ + if (operandsEqu (IC_RESULT(ic),IC_RIGHT(ic))) + return ; + + aopOp(right,ic,FALSE); + 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))) + emitcode("bsf","(%s >> 3),(%s & 7)", + AOP(result)->aopu.aop_dir, + AOP(result)->aopu.aop_dir); + else + emitcode("bcf","(%s >> 3),(%s & 7)", + AOP(result)->aopu.aop_dir, + AOP(result)->aopu.aop_dir); + goto release; + } + + /* the right is also a bit variable */ + if (AOP_TYPE(right) == AOP_CRY) { + emitcode("bcf","(%s >> 3),(%s & 7)", + AOP(result)->aopu.aop_dir, + AOP(result)->aopu.aop_dir); + emitcode("btfsc","(%s >> 3),(%s & 7)", + AOP(right)->aopu.aop_dir, + AOP(right)->aopu.aop_dir); + emitcode("bsf","(%s >> 3),(%s & 7)", + AOP(result)->aopu.aop_dir, + AOP(result)->aopu.aop_dir); + 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((AOP_TYPE(result) != AOP_REG) && + (AOP_TYPE(right) == AOP_LIT) && + !IS_FLOAT(operandType(right)) && + (lit < 256L)){ + + while (size--) { + if((unsigned int)((lit >> (size*8)) & 0x0FFL)== 0) + emitcode("clrf","%s", aopGet(AOP(result),size,FALSE,FALSE)); + else { + emitcode("movlw","%s", aopGet(AOP(right),size,FALSE,FALSE)); + emitcode("movwf","%s", aopGet(AOP(result),size,FALSE,FALSE)); + } + } + } else { + while (size--) { + if(AOP_TYPE(right) == AOP_LIT) + emitcode("movlw","%s", aopGet(AOP(right),offset,FALSE,FALSE)); + else + emitcode("movf","%s,w", aopGet(AOP(right),offset,FALSE,FALSE)); + + emitcode("movwf","%s", aopGet(AOP(result),offset,FALSE,FALSE)); + 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; + + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + 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_DS_",jtab->key+100); + emitcode("jmp","@a+dptr"); + emitcode("","%05d_DS_:",jtab->key+100); + /* now generate the jump labels */ + for (jtab = setFirstItem(IC_JTLABELS(ic)) ; jtab; + jtab = setNextItem(IC_JTLABELS(ic))) + emitcode("ljmp","%05d_DS_",jtab->key+100); + +} + +/*-----------------------------------------------------------------*/ +/* genMixedOperation - gen code for operators between mixed types */ +/*-----------------------------------------------------------------*/ +/* + TSD - Written for the PIC port - but this unfortunately is buggy. + This routine is good in that it is able to efficiently promote + types to different (larger) sizes. Unfortunately, the temporary + variables that are optimized out by this routine are sometimes + used in other places. So until I know how to really parse the + iCode tree, I'm going to not be using this routine :(. +*/ +static int genMixedOperation (iCode *ic) +{ +#if 0 + operand *result = IC_RESULT(ic); + link *ctype = operandType(IC_LEFT(ic)); + operand *right = IC_RIGHT(ic); + int ret = 0; + int big,small; + int offset; + + iCode *nextic; + operand *nextright=NULL,*nextleft=NULL,*nextresult=NULL; + + emitcode("; ***","%s %d",__FUNCTION__,__LINE__); + + nextic = ic->next; + if(!nextic) + return 0; + + nextright = IC_RIGHT(nextic); + nextleft = IC_LEFT(nextic); + nextresult = IC_RESULT(nextic); + + aopOp(right,ic,FALSE); + aopOp(result,ic,FALSE); + aopOp(nextright, nextic, FALSE); + aopOp(nextleft, nextic, FALSE); + aopOp(nextresult, nextic, FALSE); + + if (sameRegs(AOP(IC_RESULT(ic)), AOP(IC_RIGHT(nextic)))) { + + operand *t = right; + right = nextright; + nextright = t; + + emitcode(";remove right +",""); + + } else if (sameRegs(AOP(IC_RESULT(ic)), AOP(IC_LEFT(nextic)))) { +/* + operand *t = right; + right = nextleft; + nextleft = t; +*/ + emitcode(";remove left +",""); + } else + return 0; + + big = AOP_SIZE(nextleft); + small = AOP_SIZE(nextright); + + switch(nextic->op) { + + case '+': + emitcode(";optimize a +",""); + /* if unsigned or not an integral type */ + if (AOP_TYPE(IC_LEFT(nextic)) == AOP_CRY) { + emitcode(";add a bit to something",""); + } else { + + emitcode("movf","%s,w",AOP(nextright)->aopu.aop_dir); + + if (!sameRegs(AOP(IC_LEFT(nextic)), AOP(IC_RESULT(nextic))) ) { + emitcode("addwf","%s,w",AOP(nextleft)->aopu.aop_dir); + emitcode("movwf","%s",aopGet(AOP(IC_RESULT(nextic)),0,FALSE,FALSE)); + } else + emitcode("addwf","%s,f",AOP(nextleft)->aopu.aop_dir); + + offset = 0; + while(--big) { + + offset++; + + if(--small) { + if (!sameRegs(AOP(IC_LEFT(nextic)), AOP(IC_RESULT(nextic))) ){ + emitcode("movf","%s,w",aopGet(AOP(IC_LEFT(nextic)),offset,FALSE,FALSE)); + emitcode("movwf","%s,f",aopGet(AOP(IC_RESULT(nextic)),offset,FALSE,FALSE) ); + } + + emitcode("movf","%s,w", aopGet(AOP(IC_LEFT(nextic)),offset,FALSE,FALSE)); + emitcode("skpnc",""); + emitcode("btfsc","(%s >> 3), (%s & 7)", + AOP(IC_RIGHT(nextic))->aopu.aop_dir, + AOP(IC_RIGHT(nextic))->aopu.aop_dir); + emitcode(" incf","%s,w", aopGet(AOP(IC_LEFT(nextic)),offset,FALSE,FALSE)); + emitcode("movwf","%s", aopGet(AOP(IC_RESULT(nextic)),offset,FALSE,FALSE)); + + } else { + emitcode("rlf","known_zero,w"); + + /* + if right is signed + btfsc right,7 + addlw ff + */ + if (!sameRegs(AOP(IC_LEFT(nextic)), AOP(IC_RESULT(nextic))) ){ + emitcode("addwf","%s,w",aopGet(AOP(IC_LEFT(nextic)),offset,FALSE,FALSE)); + emitcode("movwf","%s,f",aopGet(AOP(IC_RESULT(nextic)),offset,FALSE,FALSE) ); + } else { + emitcode("addwf","%s,f",aopGet(AOP(IC_RESULT(nextic)),offset,FALSE,FALSE) ); + } + } + } + ret = 1; + } + } + ret = 1; + +release: + freeAsmop(right,NULL,ic,TRUE); + freeAsmop(result,NULL,ic,TRUE); + freeAsmop(nextright,NULL,ic,TRUE); + freeAsmop(nextleft,NULL,ic,TRUE); + if(ret) + nextic->generated = 1; + + return ret; +#else + return 0; +#endif +} +/*-----------------------------------------------------------------*/ +/* genCast - gen code for casting */ +/*-----------------------------------------------------------------*/ +static void genCast (iCode *ic) +{ + operand *result = IC_RESULT(ic); + link *ctype = operandType(IC_LEFT(ic)); + operand *right = IC_RIGHT(ic); + int size, offset ; + + emitcode("; ***","%s %d",__FUNCTION__,__LINE__); + /* 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) { + emitcode("; *** right is a lit","%s %d",__FUNCTION__,__LINE__); + if (((int) operandLitValue(right))) + emitcode("bsf","(%s >> 3), (%s & 7)", + AOP(result)->aopu.aop_dir, + AOP(result)->aopu.aop_dir); + else + emitcode("bcf","(%s >> 3), (%s & 7)", + AOP(result)->aopu.aop_dir, + AOP(result)->aopu.aop_dir); + + goto release; + } + + /* the right is also a bit variable */ + if (AOP_TYPE(right) == AOP_CRY) { + emitcode("clrc",""); + emitcode("btfsc","(%s >> 3), (%s & 7)", + AOP(right)->aopu.aop_dir, + 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)); + +/* 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 ; */ + } + + /* 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 ; + } + + + if (AOP_TYPE(right) == AOP_CRY) { + int offset = 1; + size = AOP_SIZE(right); + + emitcode("clrf","%s ; %d", aopGet(AOP(result),0,FALSE,FALSE),__LINE__); + emitcode("btfsc","(%s >> 3), (%s & 7)", + AOP(right)->aopu.aop_dir, + AOP(right)->aopu.aop_dir); + emitcode("incf","%s,f", aopGet(AOP(result),0,FALSE,FALSE),__LINE__); + while (size--) { + emitcode("clrf","%s", aopGet(AOP(result),offset++,FALSE,FALSE),__LINE__); + } + goto release; + } + + /* so we now know that the size of destination is greater + than the size of the source. + Now, if the next iCode is an operator then we might be + able to optimize the operation without performing a cast. + */ + if(genMixedOperation(ic)) + goto release; + + + /* we move to result for the size of source */ + size = AOP_SIZE(right); + offset = 0 ; + while (size--) { + emitcode(";","%d",__LINE__); + aopPut(AOP(result), + aopGet(AOP(right),offset,FALSE,FALSE), + offset); + offset++; + } + + /* now depending on the sign of the destination */ + size = AOP_SIZE(result) - AOP_SIZE(right); + /* if unsigned or not an integral type */ + if (SPEC_USIGN(ctype) || !IS_SPEC(ctype)) { + while (size--) + emitcode("clrf","%s",aopGet(AOP(result),offset++,FALSE,FALSE)); + } else { + /* we need to extend the sign :{ */ + char *l = aopGet(AOP(right),AOP_SIZE(right) - 1, + FALSE,FALSE); + //MOVA(l); + emitcode("clrw",""); + emitcode("btfsc","(%s >> 3), (%s & 7)", + AOP(right)->aopu.aop_dir, + AOP(right)->aopu.aop_dir); + emitcode("movlw","0xff"); + while (size--) { + emitcode("movwf","%s",aopGet(AOP(result),offset++,FALSE,FALSE)); + // 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; + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + 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_DS_",lbl->key+100); + } else { + emitcode ("djnz","%s,%05d_DS_",aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE), + lbl->key+100); + } + emitcode ("sjmp","%05d_DS_",lbl1->key+100); + emitcode ("","%05d_DS_:",lbl->key+100); + emitcode ("ljmp","%05d_DS_",IC_TRUE(ifx)->key+100); + emitcode ("","%05d_DS_:",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) +{ + DEBUGemitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + 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); +} + +/*-----------------------------------------------------------------*/ +/* genpic14Code - generate code for pic14 based controllers */ +/*-----------------------------------------------------------------*/ +void genpic14Code (iCode *lic) +{ + iCode *ic; + int cln = 0; + + lineHead = lineCurr = NULL; + + /* 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_DS_%s_DS_0_DS_0 %d",moduleName,currFunc->name,__LINE__); + else + emitcode("",";G_DS_%s_DS_0_DS_0 %d",currFunc->name,__LINE__); + _G.debugLine = 0; + } + + + for (ic = lic ; ic ; ic = ic->next ) { + + DEBUGemitcode(";ic",""); + if ( cln != ic->lineno ) { + if ( options.debug ) { + _G.debugLine = 1; + emitcode("",";C_DS_%s_DS_%d_DS_%d_DS_%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 */ + if (!options.nopeep) { + printf("peep hole optimizing\n"); + peepHole (&lineHead); + } + /* now do the actual printing */ + printLine (lineHead,codeOutFile); + return; +} diff --git a/src/pic/gen.h b/src/pic/gen.h new file mode 100644 index 00000000..d75961ab --- /dev/null +++ b/src/pic/gen.h @@ -0,0 +1,78 @@ +/*------------------------------------------------------------------------- + SDCCgen51.h - header file for code generation for 8051 + + Written By - Sandeep Dutta . sandeep.dutta@usa.net (1998) + PIC port - T. Scott Dattalo scott@dattalo.com (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 + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! +-------------------------------------------------------------------------*/ + +#ifndef SDCCGENPIC14_H +#define SDCCGENPIC14_H + +enum { + AOP_LIT = 1, + AOP_REG, AOP_DIR, + AOP_DPTR, AOP_DPTR2, AOP_R0,AOP_R1, + AOP_STK ,AOP_IMMD, AOP_STR, + AOP_CRY, AOP_ACC }; + +/* type asmop : a homogenised type for + all the different spaces an operand can be + in */ +typedef struct asmop { + + short type ; /* can have values + AOP_LIT - operand is a literal value + AOP_REG - is in registers + AOP_DIR - direct just a name + AOP_DPTR - dptr contains address of operand + AOP_DPTR2 - dptr2 contains address of operand (DS80C390 only). + AOP_R0/R1 - r0/r1 contains address of operand + AOP_STK - should be pushed on stack this + can happen only for the result + AOP_IMMD - immediate value for eg. remateriazable + AOP_CRY - carry contains the value of this + AOP_STR - array of strings + AOP_ACC - result is in the acc:b pair + */ + short coff ; /* current offset */ + short size ; /* total size */ + unsigned code :1 ; /* is in Code space */ + unsigned paged:1 ; /* in paged memory */ + unsigned freed:1 ; /* already freed */ + union { + 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 */ + 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; +} asmop; + +void genpic14Code (iCode *); + +extern char *fReturnpic14[]; +extern char *fReturn390[]; +extern unsigned fReturnSize; +extern char **fReturn; + +#endif diff --git a/src/pic/glue.c b/src/pic/glue.c new file mode 100644 index 00000000..f06e3467 --- /dev/null +++ b/src/pic/glue.c @@ -0,0 +1,1117 @@ +/*------------------------------------------------------------------------- + + SDCCglue.c - glues everything we have done together into one file. + Written By - Sandeep Dutta . sandeep.dutta@usa.net (1998) + + 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 + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! +-------------------------------------------------------------------------*/ + +#include "../common.h" +#include + + +extern symbol *interrupts[256]; +void printIval (symbol *, link *, initList *, FILE *); +extern int noAlloc; +extern set *publics; +extern int maxInterrupts; +extern int maxRegBank ; +extern symbol *mainf; +extern char *VersionString; +extern FILE *codeOutFile; +extern set *tmpfileSet; +extern set *tmpfileNameSet; +extern char *iComments1; +extern char *iComments2; +//extern void emitStaticSeg (memmap * map); + +extern DEFSETFUNC(closeTmpFiles); +extern DEFSETFUNC(rmTmpFiles); + +extern void copyFile (FILE * dest, FILE * src); + + +//extern void emitMaps (); +//extern void createInterruptVect (FILE * vFile); +extern void initialComments (FILE * afile); +extern void printPublics (FILE * afile); + +extern void printChar (FILE * ofile, char *s, int plen); + +#if 0 +char *aopLiteral (value *val, int offset) +static void emitRegularMap (memmap * map, bool addPublics, bool arFlag) +value *initPointer (initList *ilist) +void printIvalType (link * type, initList * ilist, FILE * oFile) +void printIvalStruct (symbol * sym,link * type, + initList * ilist, FILE * oFile) +int printIvalChar (link * type, initList * ilist, FILE * oFile, char *s) +void printIvalArray (symbol * sym, link * type, initList * ilist, + FILE * oFile) +void printIvalFuncPtr (link * type, initList * ilist, FILE * oFile) +int printIvalCharPtr (symbol * sym, link * type, value * val, FILE * oFile) +void printIvalPtr (symbol * sym, link * type, initList * ilist, FILE * oFile) +#endif + + +/*-----------------------------------------------------------------*/ +/* aopLiteral - string from a literal value */ +/*-----------------------------------------------------------------*/ +char *pic14aopLiteral (value *val, int offset) +{ + char *rs; + union { + float f; + unsigned char c[4]; + } fl; + + /* if it is a float then it gets tricky */ + /* otherwise it is fairly simple */ + if (!IS_FLOAT(val->type)) { + unsigned long v = floatFromVal(val); + + v >>= (offset * 8); + sprintf(buffer,"0x%02x",((char) v) & 0xff); + ALLOC_ATOMIC(rs,strlen(buffer)+1); + return strcpy (rs,buffer); + } + + /* it is type float */ + fl.f = (float) floatFromVal(val); +#ifdef _BIG_ENDIAN + sprintf(buffer,"0x%02x",fl.c[3-offset]); +#else + sprintf(buffer,"0x%02x",fl.c[offset]); +#endif + ALLOC_ATOMIC(rs,strlen(buffer)+1); + return strcpy (rs,buffer); +} + + +/*-----------------------------------------------------------------*/ +/* emitRegularMap - emit code for maps with no special cases */ +/*-----------------------------------------------------------------*/ +static void pic14emitRegularMap (memmap * map, bool addPublics, bool arFlag) +{ + symbol *sym; + int i,size; + + if (addPublics) + fprintf (map->oFile, ";\t.area\t%s\n", map->sname); + + /* print the area name */ + for (sym = setFirstItem (map->syms); sym; + sym = setNextItem (map->syms)) { + + /* if extern then do nothing */ + if (IS_EXTERN (sym->etype)) + continue; + + /* if allocation required check is needed + then check if the symbol really requires + allocation only for local variables */ + if (arFlag && !IS_AGGREGATE(sym->type) && + !(sym->_isparm && !IS_REGPARM(sym->etype)) && + !sym->allocreq && sym->level) + continue ; + + /* if global variable & not static or extern + and addPublics allowed then add it to the public set */ + if ((sym->level == 0 || + (sym->_isparm && !IS_REGPARM(sym->etype))) && + addPublics && + !IS_STATIC (sym->etype)) + addSetHead (&publics, sym); + + /* if extern then do nothing or is a function + then do nothing */ + if (IS_FUNC (sym->type)) + continue; +#if 0 + /* print extra debug info if required */ + if (options.debug || sym->level == 0) { + + cdbSymbol(sym,cdbFile,FALSE,FALSE); + + if (!sym->level) /* global */ + if (IS_STATIC(sym->etype)) + fprintf(map->oFile,"F%s_",moduleName); /* scope is file */ + else + fprintf(map->oFile,"G_"); /* scope is global */ + else + /* symbol is local */ + fprintf(map->oFile,"L%s_",(sym->localof ? sym->localof->name : "-null-")); + fprintf(map->oFile,"%s_%d_%d",sym->name,sym->level,sym->block); + } +#endif + + /* if is has an absolute address then generate + an equate for this no need to allocate space */ + if (SPEC_ABSA (sym->etype)) { + //if (options.debug || sym->level == 0) + //fprintf (map->oFile,"; == 0x%04x\n",SPEC_ADDR (sym->etype)); + + fprintf (map->oFile, "%s\tEQU\t0x%04x\n", + sym->rname, + SPEC_ADDR (sym->etype)); + } + else { + /* allocate space */ + //if (options.debug || sym->level == 0) + //fprintf(map->oFile,"==.\n"); + fprintf (map->oFile, "\t%s\n", sym->rname); + if( (size = (unsigned int)getSize (sym->type) & 0xffff)>1) { + for(i=1; ioFile, "\t%s_%d\n", sym->rname,size); + } + //fprintf (map->oFile, "\t.ds\t0x%04x\n", (unsigned int)getSize (sym->type) & 0xffff); + } + + /* if it has a initial value then do it only if + it is a global variable */ + if (sym->ival && sym->level == 0) { + ast *ival = NULL; + + if (IS_AGGREGATE (sym->type)) + ival = initAggregates (sym, sym->ival, NULL); + else + ival = newNode ('=', newAst (EX_VALUE, symbolVal (sym)), + decorateType (resolveSymbols (list2expr (sym->ival)))); + codeOutFile = statsg->oFile; + eBBlockFromiCode (iCodeFromAst (ival)); + sym->ival = NULL; + } + } +} + + +#if 0 +/*-----------------------------------------------------------------*/ +/* initPointer - pointer initialization code massaging */ +/*-----------------------------------------------------------------*/ +value *initPointer (initList *ilist) +{ + value *val; + ast *expr = list2expr(ilist); + + if (!expr) + goto wrong; + + /* try it the oldway first */ + if ((val = constExprValue(expr,FALSE))) + return val; + + /* no then we have to do these cludgy checks */ + /* pointers can be initialized with address of + a variable or address of an array element */ + if (IS_AST_OP(expr) && expr->opval.op == '&') { + /* address of symbol */ + if (IS_AST_SYM_VALUE(expr->left)) { + val = copyValue(AST_VALUE(expr->left)); + val->type = newLink(); + if (SPEC_SCLS(expr->left->etype) == S_CODE) { + DCL_TYPE(val->type) = CPOINTER ; + DCL_PTR_CONST(val->type) = port->mem.code_ro; + } + else + if (SPEC_SCLS(expr->left->etype) == S_XDATA) + DCL_TYPE(val->type) = FPOINTER; + else + if (SPEC_SCLS(expr->left->etype) == S_XSTACK ) + DCL_TYPE(val->type) = PPOINTER ; + else + if (SPEC_SCLS(expr->left->etype) == S_IDATA) + DCL_TYPE(val->type) = IPOINTER ; + else + if (SPEC_SCLS(expr->left->etype) == S_EEPROM) + DCL_TYPE(val->type) = EEPPOINTER ; + else + DCL_TYPE(val->type) = POINTER ; + val->type->next = expr->left->ftype; + val->etype = getSpec(val->type); + return val; + } + + /* if address of indexed array */ + if (IS_AST_OP(expr->left) && expr->left->opval.op == '[') + return valForArray(expr->left); + + /* if address of structure element then + case 1. a.b ; */ + if (IS_AST_OP(expr->left) && + expr->left->opval.op == '.' ) { + return valForStructElem(expr->left->left, + expr->left->right); + } + + /* case 2. (&a)->b ; + (&some_struct)->element */ + if (IS_AST_OP(expr->left) && + expr->left->opval.op == PTR_OP && + IS_ADDRESS_OF_OP(expr->left->left)) + return valForStructElem(expr->left->left->left, + expr->left->right); + } + + wrong: + werror(E_INIT_WRONG); + return NULL; + +} + +/*-----------------------------------------------------------------*/ +/* printChar - formats and prints a characater string with DB */ +/*-----------------------------------------------------------------*/ +void printChar (FILE * ofile, char *s, int plen) +{ + int i; + int len = strlen (s); + int pplen = 0; + + while (len && pplen < plen) { + + fprintf (ofile, "\t.ascii /"); + i = 60; + while (i && *s && pplen < plen) { + if (*s < ' ' || *s == '/') { + fprintf (ofile, "/\n\t.byte 0x%02x\n\t.ascii /", *s++); + } + else + fprintf (ofile, "%c", *s++); + pplen++; + i--; + } + fprintf (ofile, "/\n"); + + if (len > 60) + len -= 60; + else + len = 0; + } + if (pplen < plen) + fprintf(ofile,"\t.byte\t0\n"); +} + +/*-----------------------------------------------------------------*/ +/* printIvalType - generates ival for int/char */ +/*-----------------------------------------------------------------*/ +void printIvalType (link * type, initList * ilist, FILE * oFile) +{ + value *val; + + /* if initList is deep */ + if (ilist->type == INIT_DEEP) + ilist = ilist->init.deep; + + val = list2val (ilist); + switch (getSize (type)) { + case 1: + if (!val) + fprintf (oFile, "\t.byte 0\n"); + else + fprintf (oFile, "\t.byte %s\n", + aopLiteral (val, 0)); + break; + + case 2: + if (!val) + fprintf (oFile, "\t.word 0\n"); + else + fprintf (oFile, "\t.byte %s,%s\n", + aopLiteral (val, 0), aopLiteral (val, 1)); + break; + + case 4: + if (!val) + fprintf (oFile, "\t.word 0,0\n"); + else + fprintf (oFile, "\t.byte %s,%s,%s,%s\n", + aopLiteral (val, 0), aopLiteral (val, 1), + aopLiteral (val, 2), aopLiteral (val, 3)); + break; + } + + return; +} + +/*-----------------------------------------------------------------*/ +/* printIvalStruct - generates initial value for structures */ +/*-----------------------------------------------------------------*/ +void printIvalStruct (symbol * sym,link * type, + initList * ilist, FILE * oFile) +{ + symbol *sflds; + initList *iloop; + + sflds = SPEC_STRUCT (type)->fields; + if (ilist->type != INIT_DEEP) { + werror (E_INIT_STRUCT, sym->name); + return; + } + + iloop = ilist->init.deep; + + for (; sflds; sflds = sflds->next, iloop = (iloop ? iloop->next : NULL)) + printIval (sflds, sflds->type, iloop, oFile); + + return; +} + +/*-----------------------------------------------------------------*/ +/* printIvalChar - generates initital value for character array */ +/*-----------------------------------------------------------------*/ +int printIvalChar (link * type, initList * ilist, FILE * oFile, char *s) +{ + value *val; + int remain; + + if (!s) { + + val = list2val (ilist); + /* if the value is a character string */ + if (IS_ARRAY (val->type) && IS_CHAR (val->etype)) { + if (!DCL_ELEM (type)) + DCL_ELEM (type) = strlen (SPEC_CVAL (val->etype).v_char) + 1; + + /* if size mismatch */ +/* if (DCL_ELEM (type) < ((int) strlen (SPEC_CVAL (val->etype).v_char) + 1)) */ +/* werror (E_ARRAY_BOUND); */ + + printChar (oFile, SPEC_CVAL (val->etype).v_char,DCL_ELEM(type)); + + if ((remain = (DCL_ELEM (type) - strlen (SPEC_CVAL (val->etype).v_char) -1))>0) + while (remain--) + fprintf (oFile, "\t.byte 0\n"); + + return 1; + } + else + return 0; + } + else + printChar (oFile, s,strlen(s)+1); + return 1; +} + +/*-----------------------------------------------------------------*/ +/* printIvalArray - generates code for array initialization */ +/*-----------------------------------------------------------------*/ +void printIvalArray (symbol * sym, link * type, initList * ilist, + FILE * oFile) +{ + initList *iloop; + int lcnt = 0, size = 0; + + /* take care of the special case */ + /* array of characters can be init */ + /* by a string */ + if (IS_CHAR (type->next)) + if (printIvalChar (type, + (ilist->type == INIT_DEEP ? ilist->init.deep : ilist), + oFile, SPEC_CVAL (sym->etype).v_char)) + return; + + /* not the special case */ + if (ilist->type != INIT_DEEP) { + werror (E_INIT_STRUCT, sym->name); + return; + } + + iloop = ilist->init.deep; + lcnt = DCL_ELEM (type); + + for (;;) { + size++; + printIval (sym, type->next, iloop, oFile); + iloop = (iloop ? iloop->next : NULL); + + + /* if not array limits given & we */ + /* are out of initialisers then */ + if (!DCL_ELEM (type) && !iloop) + break; + + /* no of elements given and we */ + /* have generated for all of them */ + if (!--lcnt) + break; + } + + /* if we have not been given a size */ + if (!DCL_ELEM (type)) + DCL_ELEM (type) = size; + + return; +} + +/*-----------------------------------------------------------------*/ +/* printIvalFuncPtr - generate initial value for function pointers */ +/*-----------------------------------------------------------------*/ +void printIvalFuncPtr (link * type, initList * ilist, FILE * oFile) +{ + value *val; + int dLvl = 0; + + val = list2val (ilist); + /* check the types */ + if ((dLvl = checkType (val->type, type->next)) <= 0) { + + fprintf (oFile, "\t.word 0\n"); + return; + } + + /* now generate the name */ + if (!val->sym) { + if (IS_LITERAL (val->etype)) + fprintf (oFile, "\t.byte %s,%s\n", + aopLiteral (val, 0), aopLiteral (val, 1)); + else + fprintf (oFile, "\t.byte %s,(%s >> 8)\n", + val->name, val->name); + } + else + fprintf (oFile, "\t.byte %s,(%s >> 8)\n", + val->sym->rname, val->sym->rname); + + return; +} + +/*-----------------------------------------------------------------*/ +/* printIvalCharPtr - generates initial values for character pointers */ +/*-----------------------------------------------------------------*/ +int printIvalCharPtr (symbol * sym, link * type, value * val, FILE * oFile) +{ + int size = 0; + + size = getSize (type); + + if (size == 1) + fprintf(oFile, + "\t.byte %s", val->name) ; + else + fprintf (oFile, + "\t.byte %s,(%s >> 8)", + val->name, val->name); + + if (size > 2) + fprintf (oFile, ",#0x02\n"); + else + fprintf (oFile, "\n"); + + if (val->sym && val->sym->isstrlit) + addSet (&statsg->syms, val->sym); + + return 1; +} + +/*-----------------------------------------------------------------*/ +/* printIvalPtr - generates initial value for pointers */ +/*-----------------------------------------------------------------*/ +void printIvalPtr (symbol * sym, link * type, initList * ilist, FILE * oFile) +{ + value *val; + + /* if deep then */ + if (ilist->type == INIT_DEEP) + ilist = ilist->init.deep; + + /* function pointer */ + if (IS_FUNC (type->next)) { + printIvalFuncPtr (type, ilist, oFile); + return; + } + + if (!(val = initPointer (ilist))) + return ; + + /* if character pointer */ + if (IS_CHAR (type->next)) + if (printIvalCharPtr (sym, type, val, oFile)) + return; + + /* check the type */ + if (checkType (type, val->type) != 1) + werror (E_INIT_WRONG); + + /* if val is literal */ + if (IS_LITERAL (val->etype)) { + switch (getSize (type)) { + case 1: + fprintf (oFile, "\t.byte 0x%02x\n", ((char) floatFromVal (val)) & 0xff); + break; + case 2: + fprintf (oFile, "\t.byte %s,%s\n", + aopLiteral (val, 0), aopLiteral (val, 1)); + + break; + case 3: + fprintf (oFile, "\t.byte %s,%s,0x%02x\n", + aopLiteral (val, 0), aopLiteral (val, 1), CPOINTER); + } + return; + } + + + switch (getSize (type)) { + case 1: + fprintf (oFile, "\t.byte %s\n", val->name); + break; + case 2: + fprintf (oFile, "\t.byte %s,(%s >> 8)\n", val->name, val->name); + break; + + case 3: + fprintf (oFile, "\t.byte %s,(%s >> 8),0x%02x\n", + val->name, val->name, DCL_TYPE(val->type)); + } + return; +} + +/*-----------------------------------------------------------------*/ +/* printIval - generates code for initial value */ +/*-----------------------------------------------------------------*/ +void printIval (symbol * sym, link * type, initList * ilist, FILE * oFile) +{ + if (!ilist) + return; + + /* if structure then */ + if (IS_STRUCT (type)) { + printIvalStruct (sym, type, ilist, oFile); + return; + } + + /* if this is a pointer */ + if (IS_PTR (type)) { + printIvalPtr (sym, type, ilist, oFile); + return; + } + + /* if this is an array */ + if (IS_ARRAY (type)) { + printIvalArray (sym, type, ilist, oFile); + return; + } + + /* if type is SPECIFIER */ + if (IS_SPEC (type)) { + printIvalType (type, ilist, oFile); + return; + } +} + +#endif +/*-----------------------------------------------------------------*/ +/* emitStaticSeg - emitcode for the static segment */ +/*-----------------------------------------------------------------*/ +static void pic14emitStaticSeg (memmap * map) +{ + symbol *sym; + + fprintf(map->oFile,";\t.area\t%s\n",map->sname); + + + /* for all variables in this segment do */ + for (sym = setFirstItem (map->syms); sym; + sym = setNextItem (map->syms)) { + + /* if it is "extern" then do nothing */ + if (IS_EXTERN (sym->etype)) + continue; + + /* if it is not static add it to the public + table */ + if (!IS_STATIC (sym->etype)) + addSetHead (&publics, sym); + + /* print extra debug info if required */ + if (options.debug || sym->level == 0) { + + cdbSymbol(sym,cdbFile,FALSE,FALSE); + + if (!sym->level) { /* global */ + if (IS_STATIC(sym->etype)) + fprintf(code->oFile,"F%s_",moduleName); /* scope is file */ + else + fprintf(code->oFile,"G_"); /* scope is global */ + } + else + /* symbol is local */ + fprintf(code->oFile,"L%s_", + (sym->localof ? sym->localof->name : "-null-")); + fprintf(code->oFile,"%s_%d_%d",sym->name,sym->level,sym->block); + } + + /* if it has an absolute address */ + if (SPEC_ABSA (sym->etype)) { + if (options.debug || sym->level == 0) + fprintf(code->oFile," == 0x%04x\n", SPEC_ADDR (sym->etype)); + + fprintf (code->oFile, "%s\t=\t0x%04x\n", + sym->rname, + SPEC_ADDR (sym->etype)); + } + else { + if (options.debug || sym->level == 0) + fprintf(code->oFile," == .\n"); + + /* if it has an initial value */ + if (sym->ival) { + fprintf (code->oFile, "%s:\n", sym->rname); + noAlloc++; + resolveIvalSym (sym->ival); + printIval (sym, sym->type, sym->ival, code->oFile); + noAlloc--; + } + else { + /* allocate space */ + fprintf (code->oFile, "%s:\n", sym->rname); + /* special case for character strings */ + if (IS_ARRAY (sym->type) && IS_CHAR (sym->type->next) && + SPEC_CVAL (sym->etype).v_char) + printChar (code->oFile, + SPEC_CVAL (sym->etype).v_char, + strlen(SPEC_CVAL (sym->etype).v_char)+1); + else + fprintf (code->oFile, "\t.ds\t0x%04x\n", (unsigned int)getSize (sym->type)& 0xffff); + } + } + } +} + + +/*-----------------------------------------------------------------*/ +/* emitMaps - emits the code for the data portion the code */ +/*-----------------------------------------------------------------*/ +static void pic14emitMaps () +{ + /* no special considerations for the following + data, idata & bit & xdata */ + pic14emitRegularMap (data, TRUE, TRUE); + pic14emitRegularMap (idata, TRUE,TRUE); + pic14emitRegularMap (bit, TRUE,FALSE); + pic14emitRegularMap (xdata, TRUE,TRUE); + pic14emitRegularMap (sfr, FALSE,FALSE); + pic14emitRegularMap (sfrbit, FALSE,FALSE); + pic14emitRegularMap (code, TRUE,FALSE); + pic14emitStaticSeg (statsg); +} + +/*-----------------------------------------------------------------*/ +/* createInterruptVect - creates the interrupt vector */ +/*-----------------------------------------------------------------*/ +static void pic14createInterruptVect (FILE * vFile) +{ + int i = 0; + mainf = newSymbol ("main", 0); + mainf->block = 0; + + /* only if the main function exists */ + if (!(mainf = findSymWithLevel (SymbolTab, mainf))) { + if (!options.cc_only) + werror(E_NO_MAIN); + return; + } + + /* if the main is only a prototype ie. no body then do nothing */ + if (!mainf->fbody) { + /* if ! compile only then main function should be present */ + if (!options.cc_only) + werror(E_NO_MAIN); + return; + } + + fprintf (vFile, ";\t.area\t%s\n", CODE_NAME); + fprintf (vFile, ";__interrupt_vect:\n"); + + + if (!port->genIVT || ! (port->genIVT(vFile, interrupts, maxInterrupts))) + { + /* "generic" interrupt table header (if port doesn't specify one). + * + * Look suspiciously like 8051 code to me... + */ + + fprintf (vFile, ";\tljmp\t__sdcc_gsinit_startup\n"); + + + /* now for the other interrupts */ + for (; i < maxInterrupts; i++) { + if (interrupts[i]) + fprintf (vFile, ";\tljmp\t%s\n\t.ds\t5\n", interrupts[i]->rname); + else + fprintf (vFile, ";\treti\n;\t.ds\t7\n"); + } + } +} + + +/*-----------------------------------------------------------------*/ +/* initialComments - puts in some initial comments */ +/*-----------------------------------------------------------------*/ +static void pic14initialComments (FILE * afile) +{ + initialComments(afile); + fprintf (afile, "; PIC port for the 14-bit core\n" ); + fprintf (afile, iComments2); + +} + +/*-----------------------------------------------------------------*/ +/* printPublics - generates .global for publics */ +/*-----------------------------------------------------------------*/ +static void pic14printPublics (FILE * afile) +{ + symbol *sym; + + fprintf (afile, "%s", iComments2); + fprintf (afile, "; publics variables in this module\n"); + fprintf (afile, "%s", iComments2); + + for (sym = setFirstItem (publics); sym; + sym = setNextItem (publics)) + fprintf (afile, ";\t.globl %s\n", sym->rname); +} + + + +/*-----------------------------------------------------------------*/ +/* emitOverlay - will emit code for the overlay stuff */ +/*-----------------------------------------------------------------*/ +static void pic14emitOverlay(FILE *afile) +{ + set *ovrset; + + if (!elementsInSet(ovrSetSets)) + fprintf(afile,";\t.area\t%s\n", port->mem.overlay_name); + + /* for each of the sets in the overlay segment do */ + for (ovrset = setFirstItem(ovrSetSets); ovrset; + ovrset = setNextItem(ovrSetSets)) { + + symbol *sym ; + + if (elementsInSet(ovrset)) { + /* this dummy area is used to fool the assembler + otherwise the assembler will append each of these + declarations into one chunk and will not overlay + sad but true */ + fprintf(afile,";\t.area _DUMMY\n"); + /* output the area informtion */ + fprintf(afile,";\t.area\t%s\n", port->mem.overlay_name); /* MOF */ + } + + for (sym = setFirstItem(ovrset); sym; + sym = setNextItem(ovrset)) { + + /* if extern then do nothing */ + if (IS_EXTERN (sym->etype)) + continue; + + /* if allocation required check is needed + then check if the symbol really requires + allocation only for local variables */ + if (!IS_AGGREGATE(sym->type) && + !(sym->_isparm && !IS_REGPARM(sym->etype)) + && !sym->allocreq && sym->level) + continue ; + + /* if global variable & not static or extern + and addPublics allowed then add it to the public set */ + if ((sym->_isparm && !IS_REGPARM(sym->etype)) + && !IS_STATIC (sym->etype)) + addSetHead (&publics, sym); + + /* if extern then do nothing or is a function + then do nothing */ + if (IS_FUNC (sym->type)) + continue; + + /* print extra debug info if required */ + if (options.debug || sym->level == 0) { + + cdbSymbol(sym,cdbFile,FALSE,FALSE); + + if (!sym->level) { /* global */ + if (IS_STATIC(sym->etype)) + fprintf(afile,"F%s_",moduleName); /* scope is file */ + else + fprintf(afile,"G_"); /* scope is global */ + } + else + /* symbol is local */ + fprintf(afile,"L%s_", + (sym->localof ? sym->localof->name : "-null-")); + fprintf(afile,"%s_%d_%d",sym->name,sym->level,sym->block); + } + + /* if is has an absolute address then generate + an equate for this no need to allocate space */ + if (SPEC_ABSA (sym->etype)) { + + if (options.debug || sym->level == 0) + fprintf (afile," == 0x%04x\n",SPEC_ADDR (sym->etype)); + + fprintf (afile, "%s\t=\t0x%04x\n", + sym->rname, + SPEC_ADDR (sym->etype)); + } + else { + if (options.debug || sym->level == 0) + fprintf(afile,"==.\n"); + + /* allocate space */ + fprintf (afile, "%s:\n", sym->rname); + fprintf (afile, "\t.ds\t0x%04x\n", (unsigned int)getSize (sym->type) & 0xffff); + } + + } + } +} + + + +/*-----------------------------------------------------------------*/ +/* glue - the final glue that hold the whole thing together */ +/*-----------------------------------------------------------------*/ +void pic14glue () +{ + FILE *vFile; + FILE *asmFile; + FILE *ovrFile = tempfile(); + + addSetHead(&tmpfileSet,ovrFile); + /* print the global struct definitions */ + if (options.debug) + cdbStructBlock (0,cdbFile); + + vFile = tempfile(); + /* PENDING: this isnt the best place but it will do */ + if (port->general.glue_up_main) { + /* create the interrupt vector table */ + pic14createInterruptVect (vFile); + } + + addSetHead(&tmpfileSet,vFile); + + /* emit code for the all the variables declared */ + pic14emitMaps (); + /* do the overlay segments */ + pic14emitOverlay(ovrFile); + + /* now put it all together into the assembler file */ + /* create the assembler file name */ + + if (!options.c1mode) { + sprintf (buffer, srcFileName); + strcat (buffer, ".asm"); + } + else { + strcpy(buffer, options.out_name); + } + + if (!(asmFile = fopen (buffer, "w"))) { + werror (E_FILE_OPEN_ERR, buffer); + exit (1); + } + + /* initial comments */ + pic14initialComments (asmFile); + + /* print module name */ + fprintf (asmFile, ";\t.module %s\n", moduleName); + + /* Let the port generate any global directives, etc. */ + if (port->genAssemblerPreamble) + { + port->genAssemblerPreamble(asmFile); + } + + /* print the global variables in this module */ + pic14printPublics (asmFile); + + + /* copy the sfr segment */ + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "; special function registers\n"); + fprintf (asmFile, "%s", iComments2); + copyFile (asmFile, sfr->oFile); + + + /* Put all variables into a cblock */ + fprintf (asmFile, "\n\n\tcblock 0x13\n\n"); + + + /* copy the sbit segment */ + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "; special function bits \n"); + fprintf (asmFile, "%s", iComments2); + copyFile (asmFile, sfrbit->oFile); + + /* copy the data segment */ + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "; internal ram data\n"); + fprintf (asmFile, "%s", iComments2); + copyFile (asmFile, data->oFile); + + + /* create the overlay segments */ + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "; overlayable items in internal ram \n"); + fprintf (asmFile, "%s", iComments2); + copyFile (asmFile, ovrFile); + + /* copy the bit segment */ + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "; bit data\n"); + fprintf (asmFile, "%s", iComments2); + copyFile (asmFile, bit->oFile); + + /* create the stack segment MOF */ + if (mainf && mainf->fbody) { + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "; Stack segment in internal ram \n"); + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, ";\t.area\tSSEG\t(DATA)\n" + ";__start__stack:\n;\t.ds\t1\n\n"); + } + + /* create the idata segment */ + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "; indirectly addressable internal ram data\n"); + fprintf (asmFile, "%s", iComments2); + copyFile (asmFile, idata->oFile); + + /* if external stack then reserve space of it */ + if (mainf && mainf->fbody && options.useXstack ) { + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "; external stack \n"); + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile,";\t.area XSEG (XDATA)\n"); /* MOF */ + fprintf (asmFile,";\t.ds 256\n"); + } + + + /* copy xtern ram data */ + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "; external ram data\n"); + fprintf (asmFile, "%s", iComments2); + copyFile (asmFile, xdata->oFile); + + + fprintf (asmFile, "\tendc\n"); + fprintf (asmFile, "\tORG 0\n"); + + /* copy the interrupt vector table */ + if (mainf && mainf->fbody) { + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "; interrupt vector \n"); + fprintf (asmFile, "%s", iComments2); + copyFile (asmFile, vFile); + } + + /* copy global & static initialisations */ + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "; global & static initialisations\n"); + fprintf (asmFile, "%s", iComments2); + + /* Everywhere we generate a reference to the static_name area, + * (which is currently only here), we immediately follow it with a + * definition of the post_static_name area. This guarantees that + * the post_static_name area will immediately follow the static_name + * area. + */ + fprintf (asmFile, ";\t.area %s\n", port->mem.static_name); /* MOF */ + fprintf (asmFile, ";\t.area %s\n", port->mem.post_static_name); + fprintf (asmFile, ";\t.area %s\n", port->mem.static_name); + + if (mainf && mainf->fbody) { + fprintf (asmFile,"__sdcc_gsinit_startup:\n"); + /* if external stack is specified then the + higher order byte of the xdatalocation is + going into P2 and the lower order going into + spx */ + if (options.useXstack) { + fprintf(asmFile,";\tmov\tP2,#0x%02x\n", + (((unsigned int)options.xdata_loc) >> 8) & 0xff); + fprintf(asmFile,";\tmov\t_spx,#0x%02x\n", + (unsigned int)options.xdata_loc & 0xff); + } + + /* initialise the stack pointer */ + /* if the user specified a value then use it */ + if (options.stack_loc) + fprintf(asmFile,";\tmov\tsp,#%d\n",options.stack_loc); + else + /* no: we have to compute it */ + if (!options.stackOnData && maxRegBank <= 3) + fprintf(asmFile,";\tmov\tsp,#%d\n",((maxRegBank + 1) * 8) -1); + else + fprintf(asmFile,";\tmov\tsp,#__start__stack\n"); /* MOF */ + + fprintf (asmFile,";\tlcall\t__sdcc_external_startup\n"); + fprintf (asmFile,";\tmov\ta,dpl\n"); + fprintf (asmFile,";\tjz\t__sdcc_init_data\n"); + fprintf (asmFile,";\tljmp\t__sdcc_program_startup\n"); + fprintf (asmFile,";__sdcc_init_data:\n"); + + } + copyFile (asmFile, statsg->oFile); + + if (port->general.glue_up_main && mainf && mainf->fbody) + { + /* This code is generated in the post-static area. + * This area is guaranteed to follow the static area + * by the ugly shucking and jiving about 20 lines ago. + */ + fprintf(asmFile, ";\t.area %s\n", port->mem.post_static_name); + fprintf (asmFile,";\tljmp\t__sdcc_program_startup\n"); + } + + /* copy over code */ + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "; code\n"); + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, ";\t.area %s\n", port->mem.code_name); + if (mainf && mainf->fbody) { + + /* entry point @ start of CSEG */ + fprintf (asmFile,"__sdcc_program_startup:\n"); + + /* put in the call to main */ + fprintf(asmFile,"\tcall\t_main\n"); + if (options.mainreturn) { + + fprintf(asmFile,";\treturn from main ; will return to caller\n"); + fprintf(asmFile,"\treturn\n"); + + } else { + + fprintf(asmFile,";\treturn from main will lock up\n"); + fprintf(asmFile,"\tgoto\t$\n"); + } + } + copyFile (asmFile, code->oFile); + + fprintf (asmFile,"\tend\n"); + + fclose (asmFile); + applyToSet(tmpfileSet,closeTmpFiles); + applyToSet(tmpfileNameSet, rmTmpFiles); +} diff --git a/src/pic/glue.h b/src/pic/glue.h new file mode 100644 index 00000000..5150428f --- /dev/null +++ b/src/pic/glue.h @@ -0,0 +1,35 @@ +/*------------------------------------------------------------------------- + + SDCCglue.h - glues everything we have done together into one file. + Written By - Sandeep Dutta . sandeep.dutta@usa.net (1998) + + 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 + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! +-------------------------------------------------------------------------*/ +#include "SDCCglobl.h" +#include "SDCCmem.h" + +#ifndef SDCCGLUE_H +#define SDCCGLUE_H 1 + +void glue(); +/* drdani Jan 30 2000 + This is needed in gen.c of z80 port */ +char *aopLiteral (value *, int); + +#endif diff --git a/src/pic/main.c b/src/pic/main.c new file mode 100644 index 00000000..7d37f321 --- /dev/null +++ b/src/pic/main.c @@ -0,0 +1,247 @@ +/** @file main.c + pic14 specific general functions. + + Note that mlh prepended _pic14_ on the static functions. Makes + it easier to set a breakpoint using the debugger. +*/ +#include "common.h" +#include "main.h" +#include "ralloc.h" +#include "gen.h" + +static char _defaultRules[] = +{ +#include "peeph.rul" +}; + +/* list of key words used by pic14 */ +static char *_pic14_keywords[] = { + "at", + "bit", + "code", + "critical", + "data", + "far", + "idata", + "interrupt", + "near", + "pdata", + "reentrant", + "sfr", + "sbit", + "using", + "xdata", + "_data", + "_code", + "_generic", + "_near", + "_xdata", + "_pdata", + "_idata", + NULL +}; + + +void pic14_assignRegisters (eBBlock **ebbs, int count); + +static int regParmFlg = 0; /* determine if we can register a parameter */ + +static void _pic14_reset_regparm() +{ + regParmFlg = 0; +} + +static int _pic14_regparm( link *l) +{ + /* for this processor it is simple + can pass only the first parameter in a register */ + if (regParmFlg) + return 0; + + regParmFlg = 1; + return 1; +} + +static bool _pic14_parseOptions(int *pargc, char **argv, int *i) +{ + /* TODO: allow port-specific command line options to specify + * segment names here. + */ + return FALSE; +} + +static void _pic14_finaliseOptions(void) +{ + /* Hack-o-matic: if we are using the flat24 model, + * adjust pointer sizes. + */ + if (options.model == MODEL_FLAT24) + { + port->s.fptr_size = 3; + port->s.gptr_size = 4; + port->stack.isr_overhead++; /* Will save dpx on ISR entry. */ + #if 1 + port->stack.call_overhead++; /* This acounts for the extra byte + * of return addres on the stack. + * but is ugly. There must be a + * better way. + */ + #endif + fReturn = fReturn390; + fReturnSize = 5; + } + + if (options.model) { + port->mem.default_local_map = xdata; + port->mem.default_globl_map = xdata; + } else { + port->mem.default_local_map = data; + port->mem.default_globl_map = data; + } + + if (options.stack10bit) + { + if (options.model != MODEL_FLAT24) + { + fprintf(stderr, + "*** warning: 10 bit stack mode is only supported in flat24 model.\n"); + fprintf(stderr, "\t10 bit stack mode disabled.\n"); + options.stack10bit = 0; + } + else + { + /* Fixup the memory map for the stack; it is now in + * far space and requires a FPOINTER to access it. + */ + istack->fmap = 1; + istack->ptrType = FPOINTER; + } + } +} + +static void _pic14_setDefaultOptions(void) +{ +} + +static void _pic14_init(void) +{ + printf("cool init was called for pic14\n"); + +} +static const char *_pic14_getRegName(struct regs *reg) +{ + if (reg) + return reg->name; + return "err"; +} + +static void _pic14_genAssemblerPreamble(FILE *of) +{ + fprintf(of,"\tlist\tp=16c84\n"); + fprintf(of,"\t__config _wdt_off\n"); + fprintf(of,"\ninclude \"p16c84.inc\"\n"); + +} + +/* Generate interrupt vector table. */ +static int _pic14_genIVT(FILE *of, symbol **interrupts, int maxInterrupts) +{ + int i; + + if (options.model != MODEL_FLAT24) + { + /* Let the default code handle it. */ + return FALSE; + } + + fprintf (of, ";\tajmp\t__sdcc_gsinit_startup\n"); + + /* now for the other interrupts */ + for (i = 0; i < maxInterrupts; i++) + { + if (interrupts[i]) + { + fprintf(of, ";\tljmp\t%s\n;\t.ds\t4\n", interrupts[i]->rname); + } + else + { + fprintf(of, ";\treti\n;\t.ds\t7\n"); + } + } + + return TRUE; +} + +/** $1 is always the basename. + $2 is always the output file. + $3 varies + $l is the list of extra options that should be there somewhere... + MUST be terminated with a NULL. +*/ +static const char *_linkCmd[] = { + "aslink", "-nf", "$1", NULL +}; + +static const char *_asmCmd[] = { + "asxpic14", "-plosgffc", "$1.asm", NULL +}; + +/* Globals */ +PORT pic14_port = { + "pic14", + "MCU pic14", /* Target name */ + { + TRUE, /* Emit glue around main */ + }, + { + _asmCmd, + "-plosgffc", /* Options with debug */ + "-plosgff", /* Options without debug */ + }, + { + _linkCmd + }, + { + _defaultRules + }, + { + /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */ + 1, 1, 2, 4, 1, 2, 3, 1, 4, 4 + }, + { + "XSEG (XDATA)", + "STACK (DATA)", + "CSEG (CODE)", + "DSEG (DATA)", + "ISEG (DATA)", + "XSEG (XDATA)", + "BSEG (BIT)", + "RSEG (DATA)", + "GSINIT (CODE)", + "OSEG (OVR,DATA)", + "GSFINAL (CODE)", + NULL, + NULL, + 1 + }, + { + +1, 1, 4, 1, 1 + }, + /* pic14 does not have an 8 bit mul */ + { + 0 + }, + _pic14_init, + _pic14_parseOptions, + _pic14_finaliseOptions, + _pic14_setDefaultOptions, + pic14_assignRegisters, + _pic14_getRegName , + _pic14_keywords, + _pic14_genAssemblerPreamble, + _pic14_genIVT , + _pic14_reset_regparm, + _pic14_regparm, + NULL +}; + diff --git a/src/pic/main.h b/src/pic/main.h new file mode 100644 index 00000000..c4d16020 --- /dev/null +++ b/src/pic/main.h @@ -0,0 +1,8 @@ +#ifndef MAIN_INCLUDE +#define MAIN_INCLUDE + +bool x_parseOptions(char **argv, int *pargc); +void x_setDefaultOptions(void); +void x_finaliseOptions(void); + +#endif diff --git a/src/pic/peeph.def b/src/pic/peeph.def new file mode 100644 index 00000000..79f17633 --- /dev/null +++ b/src/pic/peeph.def @@ -0,0 +1,83 @@ +// ; Peephole 2 removed pop %1 push %1 (not push pop) +// mov %2,%3 +//} + +// peep 1 +replace restart { + skpz + goto %1 + incf %2,f +%1: +} by { + ;peep 1 + skpnz + incf %2,f +%1: +} + +// like peep1 +replace restart { + skpz + goto %1 +%2: + incf %3,f +%1: +} by { + ;peep 2 + skpnz +%2: + incf %3,f +%1: +} + +replace restart { + skpnz + goto %1 + incf %2,f +%1: +} by { + ;peep 3 + skpz + incf %2,f +%1: +} + +replace restart { + skpnz + goto %1 +%2: + incf %3,f +%1: +} by { + ;peep 4 + skpz +%2: + incf %3,f +%1: +} + +// peep 5 +replace restart { + skpc + goto %1 + incf %2,f +%1: +} by { + ;peep 5 + skpnc + incf %2,f +%1: +} + +// peep 6 +replace restart { + skpnc + goto %1 + incf %2,f +%1: +} by { + ;peep 6 + skpc + incf %2,f +%1: +} diff --git a/src/pic/ralloc.c b/src/pic/ralloc.c new file mode 100644 index 00000000..11eab9dc --- /dev/null +++ b/src/pic/ralloc.c @@ -0,0 +1,2333 @@ +/*------------------------------------------------------------------------ + + SDCCralloc.c - source file for register allocation. (8051) specific + + Written By - Sandeep Dutta . sandeep.dutta@usa.net (1998) + Added Pic Port T.scott Dattalo scott@dattalo.com (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 + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! +-------------------------------------------------------------------------*/ + +#include "common.h" +#include "ralloc.h" +#include "gen.h" + +/*-----------------------------------------------------------------*/ +/* At this point we start getting processor specific although */ +/* some routines are non-processor specific & can be reused when */ +/* targetting other processors. The decision for this will have */ +/* to be made on a routine by routine basis */ +/* routines used to pack registers are most definitely not reusable*/ +/* since the pack the registers depending strictly on the MCU */ +/*-----------------------------------------------------------------*/ + +extern void genpic14Code(iCode *); + +/* Global data */ +static struct { + bitVect *spiltSet; + set *stackSpil; + bitVect *regAssigned; + short blockSpil; + int slocNum; + bitVect *funcrUsed; /* registers used in a function */ + int stackExtend; + int dataExtend; +} _G; + +/* Shared with gen.c */ +int pic14_ptrRegReq; /* one byte pointer register required */ + +/* pic14 registers */ +regs regspic14[] = +{ + + {PIC_INDF, 0, "INDF", "INDR", "0", 0, 1}, + {PIC_GPR, 0, "r0x0C", "r0x0C", "0x0C", 0x0C, 1}, + {PIC_GPR, 0, "r0x0D", "r0x0C", "0x0D", 0x0D, 1}, + {PIC_GPR, 0, "r0x0E", "r0x0C", "0x0E", 0x0E, 1}, + {PIC_GPR, 0, "r0x0F", "r0x0C", "0x0F", 0x0F, 1}, + {PIC_GPR, 0, "r0x10", "r0x10", "0x10", 0x10, 1}, + {PIC_GPR, 0, "r0x11", "r0x11", "0x11", 0x11, 1}, + {PIC_GPR, 0, "r0x12", "r0x12", "0x12", 0x12, 1}, + {PIC_GPR, 0, "r0x13", "r0x13", "0x13", 0x13, 1}, + {PIC_GPR, 0, "r0x14", "r0x14", "0x14", 0x14, 1}, + {PIC_GPR, 0, "r0x15", "r0x15", "0x15", 0x15, 1}, + {PIC_GPR, 0, "r0x16", "r0x16", "0x16", 0x16, 1}, + {PIC_GPR, 0, "r0x17", "r0x17", "0x17", 0x17, 1}, + {PIC_GPR, 0, "r0x18", "r0x18", "0x18", 0x18, 1}, + {PIC_GPR, 0, "r0x19", "r0x19", "0x19", 0x19, 1}, + {PIC_GPR, 0, "r0x1A", "r0x1A", "0x1A", 0x1A, 1}, + {PIC_GPR, 0, "r0x1B", "r0x1B", "0x1B", 0x1B, 1}, + {PIC_GPR, 0, "r0x1C", "r0x1C", "0x1C", 0x1C, 1}, + {PIC_GPR, 0, "r0x1D", "r0x1D", "0x1D", 0x1D, 1}, + {PIC_GPR, 0, "r0x1E", "r0x1E", "0x1E", 0x1E, 1}, + {PIC_GPR, 0, "r0x1F", "r0x1F", "0x1F", 0x1F, 1}, + +}; + +int pic14_nRegs = sizeof(regspic14) / sizeof(regs); +static void spillThis (symbol *); + +/*-----------------------------------------------------------------*/ +/* allocReg - allocates register of given type */ +/*-----------------------------------------------------------------*/ +static regs *allocReg (short type) +{ + int i; + + for ( i = 0 ; i < pic14_nRegs ; i++ ) { + + /* if type is given as 0 then any + free register will do */ + if (!type && + regspic14[i].isFree ) { + regspic14[i].isFree = 0; + if (currFunc) + currFunc->regsUsed = + bitVectSetBit(currFunc->regsUsed,i); + return ®spic14[i]; + } + /* other wise look for specific type + of register */ + if (regspic14[i].isFree && + regspic14[i].type == type) { + regspic14[i].isFree = 0; + if (currFunc) + currFunc->regsUsed = + bitVectSetBit(currFunc->regsUsed,i); + return ®spic14[i]; + } + } + return NULL; +} + +/*-----------------------------------------------------------------*/ +/* pic14_regWithIdx - returns pointer to register wit index number */ +/*-----------------------------------------------------------------*/ +regs *pic14_regWithIdx (int idx) +{ + int i ; + + for (i=0;i < pic14_nRegs;i++) + if (regspic14[i].rIdx == idx) + return ®spic14[i]; + + werror(E_INTERNAL_ERROR,__FILE__,__LINE__, + "regWithIdx not found"); + exit(1); +} + +/*-----------------------------------------------------------------*/ +/* freeReg - frees a register */ +/*-----------------------------------------------------------------*/ +static void freeReg (regs *reg) +{ + reg->isFree = 1; +} + + +/*-----------------------------------------------------------------*/ +/* nFreeRegs - returns number of free registers */ +/*-----------------------------------------------------------------*/ +static int nFreeRegs (int type) +{ + int i; + int nfr=0; + + for (i = 0 ; i < pic14_nRegs; i++ ) + if (regspic14[i].isFree && regspic14[i].type == type) + nfr++; + return nfr; +} + +/*-----------------------------------------------------------------*/ +/* nfreeRegsType - free registers with type */ +/*-----------------------------------------------------------------*/ +static int nfreeRegsType (int type) +{ + int nfr ; + if (type == REG_PTR) { + if ((nfr = nFreeRegs(type)) == 0) + return nFreeRegs(REG_GPR); + } + + return nFreeRegs(type); +} + + +/*-----------------------------------------------------------------*/ +/* allDefsOutOfRange - all definitions are out of a range */ +/*-----------------------------------------------------------------*/ +static bool allDefsOutOfRange (bitVect *defs,int fseq, int toseq) +{ + int i ; + + if (!defs) + return TRUE ; + + for ( i = 0 ;i < defs->size ; i++ ) { + iCode *ic; + + if (bitVectBitValue(defs,i) && + (ic = hTabItemWithKey(iCodehTab,i)) && + ( ic->seq >= fseq && ic->seq <= toseq)) + + return FALSE; + + } + + return TRUE; +} + +/*-----------------------------------------------------------------*/ +/* computeSpillable - given a point find the spillable live ranges */ +/*-----------------------------------------------------------------*/ +static bitVect *computeSpillable (iCode *ic) +{ + bitVect *spillable ; + + /* spillable live ranges are those that are live at this + point . the following categories need to be subtracted + from this set. + a) - those that are already spilt + b) - if being used by this one + c) - defined by this one */ + + spillable = bitVectCopy(ic->rlive); + spillable = + bitVectCplAnd(spillable,_G.spiltSet); /* those already spilt */ + spillable = + bitVectCplAnd(spillable,ic->uses); /* used in this one */ + bitVectUnSetBit(spillable,ic->defKey); + spillable = bitVectIntersect(spillable,_G.regAssigned); + return spillable; + +} + +/*-----------------------------------------------------------------*/ +/* noSpilLoc - return true if a variable has no spil location */ +/*-----------------------------------------------------------------*/ +static int noSpilLoc (symbol *sym, eBBlock *ebp,iCode *ic) +{ + return (sym->usl.spillLoc ? 0 : 1); +} + +/*-----------------------------------------------------------------*/ +/* hasSpilLoc - will return 1 if the symbol has spil location */ +/*-----------------------------------------------------------------*/ +static int hasSpilLoc (symbol *sym, eBBlock *ebp, iCode *ic) +{ + return (sym->usl.spillLoc ? 1 : 0); +} + +/*-----------------------------------------------------------------*/ +/* directSpilLoc - will return 1 if the splilocation is in direct */ +/*-----------------------------------------------------------------*/ +static int directSpilLoc (symbol *sym, eBBlock *ebp, iCode *ic) +{ + if ( sym->usl.spillLoc && + (IN_DIRSPACE(SPEC_OCLS(sym->usl.spillLoc->etype)))) + return 1; + else + return 0; +} + +/*-----------------------------------------------------------------*/ +/* hasSpilLocnoUptr - will return 1 if the symbol has spil location*/ +/* but is not used as a pointer */ +/*-----------------------------------------------------------------*/ +static int hasSpilLocnoUptr (symbol *sym, eBBlock *ebp, iCode *ic) +{ + return ((sym->usl.spillLoc && !sym->uptr) ? 1 : 0); +} + +/*-----------------------------------------------------------------*/ +/* rematable - will return 1 if the remat flag is set */ +/*-----------------------------------------------------------------*/ +static int rematable (symbol *sym, eBBlock *ebp, iCode *ic) +{ + return sym->remat; +} + +/*-----------------------------------------------------------------*/ +/* notUsedInBlock - not used in this block */ +/*-----------------------------------------------------------------*/ +static int notUsedInBlock (symbol *sym, eBBlock *ebp, iCode *ic) +{ + return (!bitVectBitsInCommon(sym->defs,ebp->usesDefs) && + allDefsOutOfRange (sym->defs,ebp->fSeq,ebp->lSeq)); +/* return (!bitVectBitsInCommon(sym->defs,ebp->usesDefs)); */ +} + +/*-----------------------------------------------------------------*/ +/* notUsedInRemaining - not used or defined in remain of the block */ +/*-----------------------------------------------------------------*/ +static int notUsedInRemaining (symbol *sym, eBBlock *ebp, iCode *ic) +{ + return ((usedInRemaining (operandFromSymbol(sym),ic) ? 0 : 1) && + allDefsOutOfRange (sym->defs,ebp->fSeq,ebp->lSeq)); +} + +/*-----------------------------------------------------------------*/ +/* allLRs - return true for all */ +/*-----------------------------------------------------------------*/ +static int allLRs (symbol *sym, eBBlock *ebp, iCode *ic) +{ + return 1; +} + +/*-----------------------------------------------------------------*/ +/* liveRangesWith - applies function to a given set of live range */ +/*-----------------------------------------------------------------*/ +static set *liveRangesWith (bitVect *lrs, int (func)(symbol *,eBBlock *, iCode *), + eBBlock *ebp, iCode *ic) +{ + set *rset = NULL; + int i; + + if (!lrs || !lrs->size) + return NULL; + + for ( i = 1 ; i < lrs->size ; i++ ) { + symbol *sym; + if (!bitVectBitValue(lrs,i)) + continue ; + + /* if we don't find it in the live range + hash table we are in serious trouble */ + if (!(sym = hTabItemWithKey(liveRanges,i))) { + werror(E_INTERNAL_ERROR,__FILE__,__LINE__, + "liveRangesWith could not find liveRange"); + exit(1); + } + + if (func(sym,ebp,ic) && bitVectBitValue(_G.regAssigned,sym->key)) + addSetHead(&rset,sym); + } + + return rset; +} + + +/*-----------------------------------------------------------------*/ +/* leastUsedLR - given a set determines which is the least used */ +/*-----------------------------------------------------------------*/ +static symbol *leastUsedLR (set *sset) +{ + symbol *sym = NULL, *lsym = NULL ; + + sym = lsym = setFirstItem(sset); + + if (!lsym) + return NULL; + + for (; lsym; lsym = setNextItem(sset)) { + + /* if usage is the same then prefer + the spill the smaller of the two */ + if ( lsym->used == sym->used ) + if (getSize(lsym->type) < getSize(sym->type)) + sym = lsym; + + /* if less usage */ + if (lsym->used < sym->used ) + sym = lsym; + + } + + setToNull((void **)&sset); + sym->blockSpil = 0; + return sym; +} + +/*-----------------------------------------------------------------*/ +/* noOverLap - will iterate through the list looking for over lap */ +/*-----------------------------------------------------------------*/ +static int noOverLap (set *itmpStack, symbol *fsym) +{ + symbol *sym; + + + for (sym = setFirstItem(itmpStack); sym; + sym = setNextItem(itmpStack)) { + if (sym->liveTo > fsym->liveFrom ) + return 0; + + } + + return 1; +} + +/*-----------------------------------------------------------------*/ +/* isFree - will return 1 if the a free spil location is found */ +/*-----------------------------------------------------------------*/ +static DEFSETFUNC(isFree) +{ + symbol *sym = item; + V_ARG(symbol **,sloc); + V_ARG(symbol *,fsym); + + /* if already found */ + if (*sloc) + return 0; + + /* if it is free && and the itmp assigned to + this does not have any overlapping live ranges + with the one currently being assigned and + the size can be accomodated */ + if (sym->isFree && + noOverLap(sym->usl.itmpStack,fsym) && + getSize(sym->type) >= getSize(fsym->type)) { + *sloc = sym; + return 1; + } + + return 0; +} + +/*-----------------------------------------------------------------*/ +/* spillLRWithPtrReg :- will spil those live ranges which use PTR */ +/*-----------------------------------------------------------------*/ +static void spillLRWithPtrReg (symbol *forSym) +{ + symbol *lrsym; + regs *r0,*r1; + int k; + + if (!_G.regAssigned || + bitVectIsZero(_G.regAssigned)) + return; + + r0 = pic14_regWithIdx(R0_IDX); + r1 = pic14_regWithIdx(R1_IDX); + + /* for all live ranges */ + for (lrsym = hTabFirstItem(liveRanges,&k) ; lrsym ; + lrsym = hTabNextItem(liveRanges,&k) ) { + int j; + + /* if no registers assigned to it or + spilt */ + /* if it does not overlap with this then + not need to spill it */ + + if (lrsym->isspilt || !lrsym->nRegs || + (lrsym->liveTo < forSym->liveFrom)) + continue ; + + /* go thru the registers : if it is either + r0 or r1 then spil it */ + for (j = 0 ; j < lrsym->nRegs ; j++ ) + if (lrsym->regs[j] == r0 || + lrsym->regs[j] == r1 ) { + spillThis (lrsym); + break; + } + } + +} + +/*-----------------------------------------------------------------*/ +/* createStackSpil - create a location on the stack to spil */ +/*-----------------------------------------------------------------*/ +static symbol *createStackSpil (symbol *sym) +{ + symbol *sloc= NULL; + int useXstack, model, noOverlay; + + char slocBuffer[30]; + + /* first go try and find a free one that is already + existing on the stack */ + if (applyToSet(_G.stackSpil,isFree,&sloc, sym)) { + /* found a free one : just update & return */ + sym->usl.spillLoc = sloc; + sym->stackSpil= 1; + sloc->isFree = 0; + addSetHead(&sloc->usl.itmpStack,sym); + return sym; + } + + /* could not then have to create one , this is the hard part + we need to allocate this on the stack : this is really a + hack!! but cannot think of anything better at this time */ + + if (sprintf(slocBuffer,"sloc%d",_G.slocNum++) >= sizeof(slocBuffer)) + { + fprintf(stderr, "***Internal error: slocBuffer overflowed: %s:%d\n", + __FILE__, __LINE__); + exit(1); + } + + sloc = newiTemp(slocBuffer); + + /* set the type to the spilling symbol */ + sloc->type = copyLinkChain(sym->type); + sloc->etype = getSpec(sloc->type); + SPEC_SCLS(sloc->etype) = S_DATA ; + SPEC_EXTR(sloc->etype) = 0; + + /* we don't allow it to be allocated` + onto the external stack since : so we + temporarily turn it off ; we also + turn off memory model to prevent + the spil from going to the external storage + and turn off overlaying + */ + + useXstack = options.useXstack; + model = options.model; + noOverlay = options.noOverlay; + options.noOverlay = 1; + options.model = options.useXstack = 0; + + allocLocal(sloc); + + options.useXstack = useXstack; + options.model = model; + options.noOverlay = noOverlay; + sloc->isref = 1; /* to prevent compiler warning */ + + /* if it is on the stack then update the stack */ + if (IN_STACK(sloc->etype)) { + currFunc->stack += getSize(sloc->type); + _G.stackExtend += getSize(sloc->type); + } else + _G.dataExtend += getSize(sloc->type); + + /* add it to the _G.stackSpil set */ + addSetHead(&_G.stackSpil,sloc); + sym->usl.spillLoc = sloc; + sym->stackSpil = 1; + + /* add it to the set of itempStack set + of the spill location */ + addSetHead(&sloc->usl.itmpStack,sym); + return sym; +} + +/*-----------------------------------------------------------------*/ +/* isSpiltOnStack - returns true if the spil location is on stack */ +/*-----------------------------------------------------------------*/ +static bool isSpiltOnStack (symbol *sym) +{ + link *etype; + + if (!sym) + return FALSE ; + + if (!sym->isspilt) + return FALSE ; + +/* if (sym->_G.stackSpil) */ +/* return TRUE; */ + + if (!sym->usl.spillLoc) + return FALSE; + + etype = getSpec(sym->usl.spillLoc->type); + if (IN_STACK(etype)) + return TRUE; + + return FALSE ; +} + +/*-----------------------------------------------------------------*/ +/* spillThis - spils a specific operand */ +/*-----------------------------------------------------------------*/ +static void spillThis (symbol *sym) +{ + int i; + /* if this is rematerializable or has a spillLocation + we are okay, else we need to create a spillLocation + for it */ + if (!(sym->remat || sym->usl.spillLoc)) + createStackSpil (sym); + + + /* mark it has spilt & put it in the spilt set */ + sym->isspilt = 1; + _G.spiltSet = bitVectSetBit(_G.spiltSet,sym->key); + + bitVectUnSetBit(_G.regAssigned,sym->key); + + for (i = 0 ; i < sym->nRegs ; i++) + + if (sym->regs[i]) { + freeReg(sym->regs[i]); + sym->regs[i] = NULL; + } + + /* if spilt on stack then free up r0 & r1 + if they could have been assigned to some + LIVE ranges */ + if (!pic14_ptrRegReq && isSpiltOnStack(sym)) { + pic14_ptrRegReq++ ; + spillLRWithPtrReg(sym); + } + + if (sym->usl.spillLoc && !sym->remat) + sym->usl.spillLoc->allocreq = 1; + return; +} + +/*-----------------------------------------------------------------*/ +/* selectSpil - select a iTemp to spil : rather a simple procedure */ +/*-----------------------------------------------------------------*/ +static symbol *selectSpil (iCode *ic, eBBlock *ebp, symbol *forSym) +{ + bitVect *lrcs= NULL ; + set *selectS ; + symbol *sym; + + /* get the spillable live ranges */ + lrcs = computeSpillable (ic); + + /* get all live ranges that are rematerizable */ + if ((selectS = liveRangesWith(lrcs,rematable,ebp,ic))) { + + /* return the least used of these */ + return leastUsedLR(selectS); + } + + /* get live ranges with spillLocations in direct space */ + if ((selectS = liveRangesWith(lrcs,directSpilLoc,ebp,ic))) { + sym = leastUsedLR(selectS); + strcpy(sym->rname,(sym->usl.spillLoc->rname[0] ? + sym->usl.spillLoc->rname : + sym->usl.spillLoc->name)); + sym->spildir = 1; + /* mark it as allocation required */ + sym->usl.spillLoc->allocreq = 1; + return sym; + } + + /* if the symbol is local to the block then */ + if (forSym->liveTo < ebp->lSeq) { + + /* check if there are any live ranges allocated + to registers that are not used in this block */ + if (!_G.blockSpil && (selectS = liveRangesWith(lrcs,notUsedInBlock,ebp,ic))) { + sym = leastUsedLR(selectS); + /* if this is not rematerializable */ + if (!sym->remat) { + _G.blockSpil++; + sym->blockSpil = 1; + } + return sym; + } + + /* check if there are any live ranges that not + used in the remainder of the block */ + if (!_G.blockSpil && (selectS = liveRangesWith(lrcs,notUsedInRemaining,ebp,ic))) { + sym = leastUsedLR (selectS); + if (!sym->remat) { + sym->remainSpil = 1; + _G.blockSpil++; + } + return sym; + } + } + + /* find live ranges with spillocation && not used as pointers */ + if ((selectS = liveRangesWith(lrcs,hasSpilLocnoUptr,ebp,ic))) { + + sym = leastUsedLR(selectS); + /* mark this as allocation required */ + sym->usl.spillLoc->allocreq = 1; + return sym; + } + + /* find live ranges with spillocation */ + if ((selectS = liveRangesWith(lrcs,hasSpilLoc,ebp,ic))) { + + sym = leastUsedLR(selectS); + sym->usl.spillLoc->allocreq = 1; + return sym; + } + + /* couldn't find then we need to create a spil + location on the stack , for which one? the least + used ofcourse */ + if ((selectS = liveRangesWith(lrcs,noSpilLoc,ebp,ic))) { + + /* return a created spil location */ + sym = createStackSpil(leastUsedLR(selectS)); + sym->usl.spillLoc->allocreq = 1; + return sym; + } + + /* this is an extreme situation we will spill + this one : happens very rarely but it does happen */ + spillThis ( forSym ); + return forSym ; + +} + +/*-----------------------------------------------------------------*/ +/* spilSomething - spil some variable & mark registers as free */ +/*-----------------------------------------------------------------*/ +static bool spilSomething (iCode *ic, eBBlock *ebp, symbol *forSym) +{ + symbol *ssym; + int i ; + + /* get something we can spil */ + ssym = selectSpil(ic,ebp,forSym); + + /* mark it as spilt */ + ssym->isspilt = 1; + _G.spiltSet = bitVectSetBit(_G.spiltSet,ssym->key); + + /* mark it as not register assigned & + take it away from the set */ + bitVectUnSetBit(_G.regAssigned,ssym->key); + + /* mark the registers as free */ + for (i = 0 ; i < ssym->nRegs ;i++ ) + if (ssym->regs[i]) + freeReg(ssym->regs[i]); + + /* if spilt on stack then free up r0 & r1 + if they could have been assigned to as gprs */ + if (!pic14_ptrRegReq && isSpiltOnStack(ssym) ) { + pic14_ptrRegReq++ ; + spillLRWithPtrReg(ssym); + } + + /* if this was a block level spil then insert push & pop + at the start & end of block respectively */ + if (ssym->blockSpil) { + iCode *nic = newiCode(IPUSH,operandFromSymbol(ssym),NULL); + /* add push to the start of the block */ + addiCodeToeBBlock(ebp,nic,( ebp->sch->op == LABEL ? + ebp->sch->next : ebp->sch)); + nic = newiCode(IPOP,operandFromSymbol(ssym),NULL); + /* add pop to the end of the block */ + addiCodeToeBBlock(ebp,nic,NULL); + } + + /* if spilt because not used in the remainder of the + block then add a push before this instruction and + a pop at the end of the block */ + if (ssym->remainSpil) { + + iCode *nic = newiCode(IPUSH,operandFromSymbol(ssym),NULL); + /* add push just before this instruction */ + addiCodeToeBBlock(ebp,nic,ic); + + nic = newiCode(IPOP,operandFromSymbol(ssym),NULL); + /* add pop to the end of the block */ + addiCodeToeBBlock(ebp,nic,NULL); + } + + if (ssym == forSym ) + return FALSE ; + else + return TRUE ; +} + +/*-----------------------------------------------------------------*/ +/* getRegPtr - will try for PTR if not a GPR type if not spil */ +/*-----------------------------------------------------------------*/ +static regs *getRegPtr (iCode *ic, eBBlock *ebp, symbol *sym) +{ + regs *reg; + + tryAgain: + /* try for a ptr type */ + if ((reg = allocReg(REG_PTR))) + 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 */ +/*-----------------------------------------------------------------*/ +static regs *getRegGpr (iCode *ic, eBBlock *ebp,symbol *sym) +{ + regs *reg; + + tryAgain: + /* try for gpr type */ + if ((reg = allocReg(REG_GPR))) + return reg; + + if (!pic14_ptrRegReq) + if ((reg = allocReg(REG_PTR))) + 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 ; +} + +/*-----------------------------------------------------------------*/ +/* symHasReg - symbol has a given register */ +/*-----------------------------------------------------------------*/ +static bool symHasReg(symbol *sym,regs *reg) +{ + int i; + + for ( i = 0 ; i < sym->nRegs ; i++) + if (sym->regs[i] == reg) + return TRUE; + + return FALSE; +} + +/*-----------------------------------------------------------------*/ +/* deassignLRs - check the live to and if they have registers & are*/ +/* not spilt then free up the registers */ +/*-----------------------------------------------------------------*/ +static void deassignLRs (iCode *ic, eBBlock *ebp) +{ + symbol *sym; + int k; + symbol *result; + + for (sym = hTabFirstItem(liveRanges,&k); sym; + sym = hTabNextItem(liveRanges,&k)) { + + symbol *psym= NULL; + /* if it does not end here */ + if (sym->liveTo > ic->seq ) + continue ; + + /* if it was spilt on stack then we can + mark the stack spil location as free */ + if (sym->isspilt ) { + if (sym->stackSpil) { + sym->usl.spillLoc->isFree = 1; + sym->stackSpil = 0; + } + continue ; + } + + if (!bitVectBitValue(_G.regAssigned,sym->key)) + continue; + + /* special case check if this is an IFX & + the privious one was a pop and the + previous one was not spilt then keep track + of the symbol */ + if (ic->op == IFX && ic->prev && + ic->prev->op == IPOP && + !ic->prev->parmPush && + !OP_SYMBOL(IC_LEFT(ic->prev))->isspilt) + psym = OP_SYMBOL(IC_LEFT(ic->prev)); + + if (sym->nRegs) { + int i = 0; + + bitVectUnSetBit(_G.regAssigned,sym->key); + + /* if the result of this one needs registers + and does not have it then assign it right + away */ + if (IC_RESULT(ic) && + ! (SKIP_IC2(ic) || /* not a special icode */ + ic->op == JUMPTABLE || + ic->op == IFX || + ic->op == IPUSH || + ic->op == IPOP || + ic->op == RETURN || + POINTER_SET(ic)) && + (result = OP_SYMBOL(IC_RESULT(ic))) && /* has a result */ + result->liveTo > ic->seq && /* and will live beyond this */ + result->liveTo <= ebp->lSeq && /* does not go beyond this block */ + result->regType == sym->regType && /* same register types */ + result->nRegs && /* which needs registers */ + ! result->isspilt && /* and does not already have them */ + ! result->remat && + ! bitVectBitValue(_G.regAssigned,result->key) && + /* the number of free regs + number of regs in this LR + can accomodate the what result Needs */ + ((nfreeRegsType(result->regType) + + sym->nRegs) >= result->nRegs) + ) { + + for (i = 0 ; i < max(sym->nRegs,result->nRegs) ; i++) + if (i < sym->nRegs ) + result->regs[i] = sym->regs[i] ; + else + result->regs[i] = getRegGpr (ic,ebp,result); + + _G.regAssigned = bitVectSetBit(_G.regAssigned,result->key); + + } + + /* free the remaining */ + for (; i < sym->nRegs ; i++) { + if (psym) { + if (!symHasReg(psym,sym->regs[i])) + freeReg(sym->regs[i]); + } else + freeReg(sym->regs[i]); + } + } + } +} + + +/*-----------------------------------------------------------------*/ +/* reassignLR - reassign this to registers */ +/*-----------------------------------------------------------------*/ +static void reassignLR (operand *op) +{ + symbol *sym = OP_SYMBOL(op); + int i; + + /* not spilt any more */ + sym->isspilt = sym->blockSpil = sym->remainSpil = 0; + bitVectUnSetBit(_G.spiltSet,sym->key); + + _G.regAssigned = bitVectSetBit(_G.regAssigned,sym->key); + + _G.blockSpil--; + + for (i=0;inRegs;i++) + sym->regs[i]->isFree = 0; +} + +/*-----------------------------------------------------------------*/ +/* willCauseSpill - determines if allocating will cause a spill */ +/*-----------------------------------------------------------------*/ +static int willCauseSpill ( int nr, int rt) +{ + /* first check if there are any avlb registers + of te type required */ + if (rt == REG_PTR) { + /* special case for pointer type + if pointer type not avlb then + check for type gpr */ + if (nFreeRegs(rt) >= nr) + return 0; + if (nFreeRegs(REG_GPR) >= nr) + return 0; + } else { + if (pic14_ptrRegReq) { + if (nFreeRegs(rt) >= nr) + return 0; + } else { + if (nFreeRegs(REG_PTR) + + nFreeRegs(REG_GPR) >= nr) + return 0; + } + } + + /* it will cause a spil */ + return 1; +} + +/*-----------------------------------------------------------------*/ +/* positionRegs - the allocator can allocate same registers to res-*/ +/* ult and operand, if this happens make sure they are in the same */ +/* position as the operand otherwise chaos results */ +/*-----------------------------------------------------------------*/ +static void positionRegs (symbol *result, symbol *opsym, int lineno) +{ + int count = min(result->nRegs,opsym->nRegs); + int i , j = 0, shared = 0; + + /* if the result has been spilt then cannot share */ + if (opsym->isspilt) + return ; + again: + shared = 0; + /* first make sure that they actually share */ + for ( i = 0 ; i < count; i++ ) { + for (j = 0 ; j < count ; j++ ) { + if (result->regs[i] == opsym->regs[j] && i !=j) { + shared = 1; + goto xchgPositions; + } + } + } + xchgPositions: + if (shared) { + regs *tmp = result->regs[i]; + result->regs[i] = result->regs[j]; + result->regs[j] = tmp; + goto again; + } +} + +/*-----------------------------------------------------------------*/ +/* serialRegAssign - serially allocate registers to the variables */ +/*-----------------------------------------------------------------*/ +static void serialRegAssign (eBBlock **ebbs, int count) +{ + int i; + + /* for all blocks */ + for (i = 0; i < count ; i++ ) { + + iCode *ic; + + if (ebbs[i]->noPath && + (ebbs[i]->entryLabel != entryLabel && + ebbs[i]->entryLabel != returnLabel )) + continue ; + + /* of all instructions do */ + for (ic = ebbs[i]->sch ; ic ; ic = ic->next) { + + /* if this is an ipop that means some live + range will have to be assigned again */ + if (ic->op == IPOP) + reassignLR (IC_LEFT(ic)); + + /* if result is present && is a true symbol */ + if (IC_RESULT(ic) && ic->op != IFX && + IS_TRUE_SYMOP(IC_RESULT(ic))) + OP_SYMBOL(IC_RESULT(ic))->allocreq = 1; + + /* take away registers from live + ranges that end at this instruction */ + deassignLRs (ic, ebbs[i]) ; + + /* some don't need registers */ + if (SKIP_IC2(ic) || + ic->op == JUMPTABLE || + ic->op == IFX || + ic->op == IPUSH || + ic->op == IPOP || + (IC_RESULT(ic) &&POINTER_SET(ic)) ) + continue; + + /* now we need to allocate registers + only for the result */ + if (IC_RESULT(ic)) { + symbol *sym = OP_SYMBOL(IC_RESULT(ic)); + bitVect *spillable; + int willCS ; + int j; + int ptrRegSet = 0; + + /* if it does not need or is spilt + or is already assigned to registers + or will not live beyond this instructions */ + if (!sym->nRegs || + sym->isspilt || + bitVectBitValue(_G.regAssigned,sym->key) || + sym->liveTo <= ic->seq) + continue ; + + /* if some liverange has been spilt at the block level + and this one live beyond this block then spil this + to be safe */ + if (_G.blockSpil && sym->liveTo > ebbs[i]->lSeq) { + spillThis (sym); + continue ; + } + /* if trying to allocate this will cause + a spill and there is nothing to spill + or this one is rematerializable then + spill this one */ + willCS = willCauseSpill(sym->nRegs,sym->regType); + spillable = computeSpillable(ic); + if ( sym->remat || + (willCS && bitVectIsZero(spillable) ) ) { + + spillThis (sym) ; + continue ; + + } + + /* if it has a spillocation & is used less than + all other live ranges then spill this */ + if ( willCS && sym->usl.spillLoc ) { + + symbol *leastUsed = + leastUsedLR(liveRangesWith (spillable , + allLRs, + ebbs[i], + ic)); + if (leastUsed && + leastUsed->used > sym->used) { + spillThis (sym); + continue; + } + } + + /* if we need ptr regs for the right side + then mark it */ + if (POINTER_GET(ic) && getSize(OP_SYMBOL(IC_LEFT(ic))->type) + <= PTRSIZE) + { + pic14_ptrRegReq++; + ptrRegSet = 1; + } + /* else we assign registers to it */ + _G.regAssigned = bitVectSetBit(_G.regAssigned,sym->key); + + for (j = 0 ; j < sym->nRegs ;j++ ) { + if (sym->regType == REG_PTR) + sym->regs[j] = getRegPtr(ic,ebbs[i],sym); + else + sym->regs[j] = getRegGpr(ic,ebbs[i],sym); + + /* if the allocation falied which means + this was spilt then break */ + if (!sym->regs[j]) + break; + } + /* if it shares registers with operands make sure + that they are in the same position */ + if (IC_LEFT(ic) && IS_SYMOP(IC_LEFT(ic)) && + OP_SYMBOL(IC_LEFT(ic))->nRegs && ic->op != '=') + positionRegs(OP_SYMBOL(IC_RESULT(ic)), + OP_SYMBOL(IC_LEFT(ic)),ic->lineno); + /* do the same for the right operand */ + if (IC_RIGHT(ic) && IS_SYMOP(IC_RIGHT(ic)) && + OP_SYMBOL(IC_RIGHT(ic))->nRegs && ic->op != '=') + positionRegs(OP_SYMBOL(IC_RESULT(ic)), + OP_SYMBOL(IC_RIGHT(ic)),ic->lineno); + + if (ptrRegSet) { + pic14_ptrRegReq--; + ptrRegSet = 0; + } + + } + } + } +} + +/*-----------------------------------------------------------------*/ +/* rUmaskForOp :- returns register mask for an operand */ +/*-----------------------------------------------------------------*/ +static bitVect *rUmaskForOp (operand *op) +{ + bitVect *rumask; + symbol *sym; + int j; + + /* only temporaries are assigned registers */ + if (!IS_ITEMP(op)) + return NULL; + + sym = OP_SYMBOL(op); + + /* if spilt or no registers assigned to it + then nothing */ + if (sym->isspilt || !sym->nRegs) + return NULL; + + rumask = newBitVect(pic14_nRegs); + + for (j = 0; j < sym->nRegs; j++) { + rumask = bitVectSetBit(rumask, + sym->regs[j]->rIdx); + } + + return rumask; +} + +/*-----------------------------------------------------------------*/ +/* regsUsedIniCode :- returns bit vector of registers used in iCode*/ +/*-----------------------------------------------------------------*/ +static bitVect *regsUsedIniCode (iCode *ic) +{ + bitVect *rmask = newBitVect(pic14_nRegs); + + /* do the special cases first */ + if (ic->op == IFX ) { + rmask = bitVectUnion(rmask, + rUmaskForOp(IC_COND(ic))); + goto ret; + } + + /* for the jumptable */ + if (ic->op == JUMPTABLE) { + rmask = bitVectUnion(rmask, + rUmaskForOp(IC_JTCOND(ic))); + + goto ret; + } + + /* of all other cases */ + if (IC_LEFT(ic)) + rmask = bitVectUnion(rmask, + rUmaskForOp(IC_LEFT(ic))); + + + if (IC_RIGHT(ic)) + rmask = bitVectUnion(rmask, + rUmaskForOp(IC_RIGHT(ic))); + + if (IC_RESULT(ic)) + rmask = bitVectUnion(rmask, + rUmaskForOp(IC_RESULT(ic))); + + ret: + return rmask; +} + +/*-----------------------------------------------------------------*/ +/* createRegMask - for each instruction will determine the regsUsed*/ +/*-----------------------------------------------------------------*/ +static void createRegMask (eBBlock **ebbs, int count) +{ + int i; + + /* for all blocks */ + for (i = 0; i < count ; i++ ) { + iCode *ic ; + + if ( ebbs[i]->noPath && + ( ebbs[i]->entryLabel != entryLabel && + ebbs[i]->entryLabel != returnLabel )) + continue ; + + /* for all instructions */ + for ( ic = ebbs[i]->sch ; ic ; ic = ic->next ) { + + int j; + + if (SKIP_IC2(ic) || !ic->rlive) + continue ; + + /* first mark the registers used in this + instruction */ + ic->rUsed = regsUsedIniCode(ic); + _G.funcrUsed = bitVectUnion(_G.funcrUsed,ic->rUsed); + + /* now create the register mask for those + registers that are in use : this is a + super set of ic->rUsed */ + ic->rMask = newBitVect(pic14_nRegs+1); + + /* for all live Ranges alive at this point */ + for (j = 1; j < ic->rlive->size; j++ ) { + symbol *sym; + int k; + + /* if not alive then continue */ + if (!bitVectBitValue(ic->rlive,j)) + continue ; + + /* find the live range we are interested in */ + if (!(sym = hTabItemWithKey(liveRanges,j))) { + werror (E_INTERNAL_ERROR,__FILE__,__LINE__, + "createRegMask cannot find live range"); + exit(0); + } + + /* if no register assigned to it */ + if (!sym->nRegs || sym->isspilt) + continue ; + + /* for all the registers allocated to it */ + for (k = 0 ; k < sym->nRegs ;k++) + if (sym->regs[k]) + ic->rMask = + bitVectSetBit(ic->rMask,sym->regs[k]->rIdx); + } + } + } +} + +/*-----------------------------------------------------------------*/ +/* rematStr - returns the rematerialized string for a remat var */ +/*-----------------------------------------------------------------*/ +static char *rematStr (symbol *sym) +{ + char *s = buffer; + iCode *ic = sym->rematiCode; + + while (1) { + + /* if plus or minus print the right hand side */ + if (ic->op == '+' || ic->op == '-') { + sprintf(s,"0x%04x %c ",(int) operandLitValue(IC_RIGHT(ic)), + ic->op ); + s += strlen(s); + ic = OP_SYMBOL(IC_LEFT(ic))->rematiCode; + continue ; + } + + /* we reached the end */ + sprintf(s,"%s",OP_SYMBOL(IC_LEFT(ic))->rname); + break; + } + + return buffer ; +} + +/*-----------------------------------------------------------------*/ +/* regTypeNum - computes the type & number of registers required */ +/*-----------------------------------------------------------------*/ +static void regTypeNum () +{ + symbol *sym; + int k; + iCode *ic; + + /* for each live range do */ + for ( sym = hTabFirstItem(liveRanges,&k); sym ; + sym = hTabNextItem(liveRanges,&k)) { + + /* if used zero times then no registers needed */ + if ((sym->liveTo - sym->liveFrom) == 0) + continue ; + + + /* if the live range is a temporary */ + if (sym->isitmp) { + + /* if the type is marked as a conditional */ + if (sym->regType == REG_CND) + continue ; + + /* if used in return only then we don't + need registers */ + if (sym->ruonly || sym->accuse) { + if (IS_AGGREGATE(sym->type) || sym->isptr) + sym->type = aggrToPtr(sym->type,FALSE); + continue ; + } + + /* if the symbol has only one definition & + that definition is a get_pointer and the + pointer we are getting is rematerializable and + in "data" space */ + + if (bitVectnBitsOn(sym->defs) == 1 && + (ic = hTabItemWithKey(iCodehTab, + bitVectFirstBit(sym->defs))) && + POINTER_GET(ic) && + !IS_BITVAR(sym->etype)) { + + + /* if remat in data space */ + if (OP_SYMBOL(IC_LEFT(ic))->remat && + DCL_TYPE(aggrToPtr(sym->type,FALSE)) == POINTER) { + + /* create a psuedo symbol & force a spil */ + symbol *psym = newSymbol(rematStr(OP_SYMBOL(IC_LEFT(ic))),1); + psym->type = sym->type; + psym->etype = sym->etype; + strcpy(psym->rname,psym->name); + sym->isspilt = 1; + sym->usl.spillLoc = psym; + continue ; + } + + /* if in data space or idata space then try to + allocate pointer register */ + + } + + /* if not then we require registers */ + sym->nRegs = ((IS_AGGREGATE(sym->type) || sym->isptr ) ? + getSize(sym->type = aggrToPtr(sym->type,FALSE)) : + getSize(sym->type)); + + if (sym->nRegs > 4) { + fprintf(stderr,"allocated more than 4 or 0 registers for type "); + printTypeChain(sym->type,stderr);fprintf(stderr,"\n"); + } + + /* determine the type of register required */ + if (sym->nRegs == 1 && + IS_PTR(sym->type) && + sym->uptr) + sym->regType = REG_PTR ; + else + sym->regType = REG_GPR ; + + } else + /* for the first run we don't provide */ + /* registers for true symbols we will */ + /* see how things go */ + sym->nRegs = 0 ; + } + +} + +/*-----------------------------------------------------------------*/ +/* freeAllRegs - mark all registers as free */ +/*-----------------------------------------------------------------*/ +static void freeAllRegs() +{ + int i; + + for (i=0;i< pic14_nRegs;i++ ) + regspic14[i].isFree = 1; +} + +/*-----------------------------------------------------------------*/ +/* deallocStackSpil - this will set the stack pointer back */ +/*-----------------------------------------------------------------*/ +static DEFSETFUNC(deallocStackSpil) +{ + symbol *sym = item; + + deallocLocal(sym); + return 0; +} + +/*-----------------------------------------------------------------*/ +/* farSpacePackable - returns the packable icode for far variables */ +/*-----------------------------------------------------------------*/ +static iCode *farSpacePackable (iCode *ic) +{ + iCode *dic ; + + /* go thru till we find a definition for the + symbol on the right */ + for ( dic = ic->prev ; dic ; dic = dic->prev) { + + /* if the definition is a call then no */ + if ((dic->op == CALL || dic->op == PCALL) && + IC_RESULT(dic)->key == IC_RIGHT(ic)->key) { + return NULL; + } + + /* if shift by unknown amount then not */ + if ((dic->op == LEFT_OP || dic->op == RIGHT_OP) && + IC_RESULT(dic)->key == IC_RIGHT(ic)->key) + return NULL; + + /* if pointer get and size > 1 */ + if (POINTER_GET(dic) && + getSize(aggrToPtr(operandType(IC_LEFT(dic)),FALSE)) > 1) + return NULL ; + + if (POINTER_SET(dic) && + getSize(aggrToPtr(operandType(IC_RESULT(dic)),FALSE)) > 1) + return NULL ; + + /* if any three is a true symbol in far space */ + if (IC_RESULT(dic) && + IS_TRUE_SYMOP(IC_RESULT(dic)) && + isOperandInFarSpace(IC_RESULT(dic))) + return NULL; + + if (IC_RIGHT(dic) && + IS_TRUE_SYMOP(IC_RIGHT(dic)) && + isOperandInFarSpace(IC_RIGHT(dic)) && + !isOperandEqual(IC_RIGHT(dic),IC_RESULT(ic))) + return NULL; + + if (IC_LEFT(dic) && + IS_TRUE_SYMOP(IC_LEFT(dic)) && + isOperandInFarSpace(IC_LEFT(dic)) && + !isOperandEqual(IC_LEFT(dic),IC_RESULT(ic))) + return NULL; + + if (isOperandEqual(IC_RIGHT(ic),IC_RESULT(dic))) { + if ( (dic->op == LEFT_OP || + dic->op == RIGHT_OP || + dic->op == '-') && + IS_OP_LITERAL(IC_RIGHT(dic))) + return NULL; + else + return dic; + } + } + + return NULL; +} + +/*-----------------------------------------------------------------*/ +/* packRegsForAssign - register reduction for assignment */ +/*-----------------------------------------------------------------*/ +static int packRegsForAssign (iCode *ic,eBBlock *ebp) +{ + + iCode *dic, *sic; + + if (!IS_ITEMP(IC_RIGHT(ic)) || + OP_SYMBOL(IC_RIGHT(ic))->isind || + OP_LIVETO(IC_RIGHT(ic)) > ic->seq) { + return 0; + } + + /* if the true symbol is defined in far space or on stack + then we should not since this will increase register pressure */ + if (isOperandInFarSpace(IC_RESULT(ic))) { + if ((dic = farSpacePackable(ic))) + goto pack; + else + return 0; + + } + /* find the definition of iTempNN scanning backwards if we find a + a use of the true symbol in before we find the definition then + we cannot */ + for ( dic = ic->prev ; dic ; dic = dic->prev) { + + /* if there is a function call and this is + a parameter & not my parameter then don't pack it */ + if ( (dic->op == CALL || dic->op == PCALL) && + (OP_SYMBOL(IC_RESULT(ic))->_isparm && + !OP_SYMBOL(IC_RESULT(ic))->ismyparm)) { + dic = NULL; + break; + } + + if (SKIP_IC2(dic)) + continue; + + if (IS_TRUE_SYMOP(IC_RESULT(dic)) && + IS_OP_VOLATILE(IC_RESULT(dic))) { + dic = NULL; + break; + } + + if (IS_SYMOP(IC_RESULT(dic)) && + IC_RESULT(dic)->key == IC_RIGHT(ic)->key) { + if (POINTER_SET(dic)) + dic = NULL; + + break; + } + + if (IS_SYMOP(IC_RIGHT(dic)) && + (IC_RIGHT(dic)->key == IC_RESULT(ic)->key || + IC_RIGHT(dic)->key == IC_RIGHT(ic)->key)) { + dic = NULL; + break; + } + + if (IS_SYMOP(IC_LEFT(dic)) && + (IC_LEFT(dic)->key == IC_RESULT(ic)->key || + IC_LEFT(dic)->key == IC_RIGHT(ic)->key)) { + dic = NULL; + break; + } + + if (POINTER_SET(dic) && + IC_RESULT(dic)->key == IC_RESULT(ic)->key ) { + dic = NULL ; + break; + } + } + + if (!dic) + return 0 ; /* did not find */ + + /* if the result is on stack or iaccess then it must be + the same atleast one of the operands */ + if (OP_SYMBOL(IC_RESULT(ic))->onStack || + OP_SYMBOL(IC_RESULT(ic))->iaccess ) { + + /* the operation has only one symbol + operator then we can pack */ + if ((IC_LEFT(dic) && !IS_SYMOP(IC_LEFT(dic))) || + (IC_RIGHT(dic) && !IS_SYMOP(IC_RIGHT(dic)))) + goto pack; + + if (!((IC_LEFT(dic) && + IC_RESULT(ic)->key == IC_LEFT(dic)->key) || + (IC_RIGHT(dic) && + IC_RESULT(ic)->key == IC_RIGHT(dic)->key))) + return 0; + } +pack: + /* found the definition */ + /* replace the result with the result of */ + /* this assignment and remove this assignment */ + IC_RESULT(dic) = IC_RESULT(ic) ; + + if (IS_ITEMP(IC_RESULT(dic)) && OP_SYMBOL(IC_RESULT(dic))->liveFrom > dic->seq) { + OP_SYMBOL(IC_RESULT(dic))->liveFrom = dic->seq; + } + /* delete from liverange table also + delete from all the points inbetween and the new + one */ + for ( sic = dic; sic != ic ; sic = sic->next ) { + bitVectUnSetBit(sic->rlive,IC_RESULT(ic)->key); + if (IS_ITEMP(IC_RESULT(dic))) + bitVectSetBit(sic->rlive,IC_RESULT(dic)->key); + } + + remiCodeFromeBBlock(ebp,ic); + hTabDeleteItem (&iCodehTab,ic->key,ic,DELETE_ITEM,NULL); + OP_DEFS(IC_RESULT(dic)) = bitVectSetBit(OP_DEFS(IC_RESULT(dic)),dic->key); + return 1; + + +} + +/*-----------------------------------------------------------------*/ +/* findAssignToSym : scanning backwards looks for first assig found*/ +/*-----------------------------------------------------------------*/ +static iCode *findAssignToSym (operand *op,iCode *ic) +{ + iCode *dic; + + for (dic = ic->prev ; dic ; dic = dic->prev) { + + /* if definition by assignment */ + if (dic->op == '=' && + !POINTER_SET(dic) && + IC_RESULT(dic)->key == op->key +/* && IS_TRUE_SYMOP(IC_RIGHT(dic)) */ + ) { + + /* we are interested only if defined in far space */ + /* or in stack space in case of + & - */ + + /* if assigned to a non-symbol then return + true */ + if (!IS_SYMOP(IC_RIGHT(dic))) + break ; + + /* if the symbol is in far space then + we should not */ + if (isOperandInFarSpace(IC_RIGHT(dic))) + return NULL ; + + /* for + & - operations make sure that + if it is on the stack it is the same + as one of the three operands */ + if ((ic->op == '+' || ic->op == '-') && + OP_SYMBOL(IC_RIGHT(dic))->onStack) { + + if ( IC_RESULT(ic)->key != IC_RIGHT(dic)->key && + IC_LEFT(ic)->key != IC_RIGHT(dic)->key && + IC_RIGHT(ic)->key != IC_RIGHT(dic)->key) + return NULL; + } + + break ; + + } + + /* if we find an usage then we cannot delete it */ + if (IC_LEFT(dic) && IC_LEFT(dic)->key == op->key) + return NULL; + + if (IC_RIGHT(dic) && IC_RIGHT(dic)->key == op->key) + return NULL; + + if (POINTER_SET(dic) && IC_RESULT(dic)->key == op->key) + return NULL; + } + + /* now make sure that the right side of dic + is not defined between ic & dic */ + if (dic) { + iCode *sic = dic->next ; + + for (; sic != ic ; sic = sic->next) + if (IC_RESULT(sic) && + IC_RESULT(sic)->key == IC_RIGHT(dic)->key) + return NULL; + } + + return dic; + + +} + +/*-----------------------------------------------------------------*/ +/* packRegsForSupport :- reduce some registers for support calls */ +/*-----------------------------------------------------------------*/ +static int packRegsForSupport (iCode *ic, eBBlock *ebp) +{ + int change = 0 ; + /* for the left & right operand :- look to see if the + left was assigned a true symbol in far space in that + case replace them */ + if (IS_ITEMP(IC_LEFT(ic)) && + OP_SYMBOL(IC_LEFT(ic))->liveTo <= ic->seq) { + iCode *dic = findAssignToSym(IC_LEFT(ic),ic); + iCode *sic; + + if (!dic) + goto right ; + + /* found it we need to remove it from the + block */ + for ( sic = dic; sic != ic ; sic = sic->next ) + bitVectUnSetBit(sic->rlive,IC_LEFT(ic)->key); + + IC_LEFT(ic)->operand.symOperand = + IC_RIGHT(dic)->operand.symOperand; + IC_LEFT(ic)->key = IC_RIGHT(dic)->operand.symOperand->key; + remiCodeFromeBBlock(ebp,dic); + hTabDeleteItem (&iCodehTab,dic->key,dic,DELETE_ITEM,NULL); + change++; + } + + /* do the same for the right operand */ + right: + if (!change && + IS_ITEMP(IC_RIGHT(ic)) && + OP_SYMBOL(IC_RIGHT(ic))->liveTo <= ic->seq) { + iCode *dic = findAssignToSym(IC_RIGHT(ic),ic); + iCode *sic; + + if (!dic) + return change ; + + /* if this is a subtraction & the result + is a true symbol in far space then don't pack */ + if (ic->op == '-' && IS_TRUE_SYMOP(IC_RESULT(dic))) { + link *etype =getSpec(operandType(IC_RESULT(dic))); + if (IN_FARSPACE(SPEC_OCLS(etype))) + return change ; + } + /* found it we need to remove it from the + block */ + for ( sic = dic; sic != ic ; sic = sic->next ) + bitVectUnSetBit(sic->rlive,IC_RIGHT(ic)->key); + + IC_RIGHT(ic)->operand.symOperand = + IC_RIGHT(dic)->operand.symOperand; + IC_RIGHT(ic)->key = IC_RIGHT(dic)->operand.symOperand->key; + + remiCodeFromeBBlock(ebp,dic); + hTabDeleteItem (&iCodehTab,dic->key,dic,DELETE_ITEM,NULL); + change ++; + } + + return change ; +} + +#define IS_OP_RUONLY(x) (x && IS_SYMOP(x) && OP_SYMBOL(x)->ruonly) + + +/*-----------------------------------------------------------------*/ +/* packRegsForOneuse : - will reduce some registers for single Use */ +/*-----------------------------------------------------------------*/ +static iCode *packRegsForOneuse (iCode *ic, operand *op , eBBlock *ebp) +{ + bitVect *uses ; + iCode *dic, *sic; + + /* if returning a literal then do nothing */ + if (!IS_SYMOP(op)) + return NULL; + + /* only upto 2 bytes since we cannot predict + the usage of b, & acc */ + if (getSize(operandType(op)) > (fReturnSize - 2) && + ic->op != RETURN && + ic->op != SEND) + return NULL; + + /* this routine will mark the a symbol as used in one + instruction use only && if the defintion is local + (ie. within the basic block) && has only one definition && + that definiion is either a return value from a + function or does not contain any variables in + far space */ + uses = bitVectCopy(OP_USES(op)); + bitVectUnSetBit(uses,ic->key); /* take away this iCode */ + if (!bitVectIsZero(uses)) /* has other uses */ + return NULL ; + + /* if it has only one defintion */ + if (bitVectnBitsOn(OP_DEFS(op)) > 1) + return NULL ; /* has more than one definition */ + + /* get the that definition */ + if (!(dic = + hTabItemWithKey(iCodehTab, + bitVectFirstBit(OP_DEFS(op))))) + return NULL ; + + /* found the definition now check if it is local */ + if (dic->seq < ebp->fSeq || + dic->seq > ebp->lSeq) + return NULL ; /* non-local */ + + /* now check if it is the return from + a function call */ + if (dic->op == CALL || dic->op == PCALL ) { + if (ic->op != SEND && ic->op != RETURN) { + OP_SYMBOL(op)->ruonly = 1; + return dic; + } + dic = dic->next ; + } + + + /* otherwise check that the definition does + not contain any symbols in far space */ + if (isOperandInFarSpace(IC_LEFT(dic)) || + isOperandInFarSpace(IC_RIGHT(dic)) || + IS_OP_RUONLY(IC_LEFT(ic)) || + IS_OP_RUONLY(IC_RIGHT(ic)) ) { + return NULL; + } + + /* if pointer set then make sure the pointer + is one byte */ + if (POINTER_SET(dic) && + !IS_DATA_PTR(aggrToPtr(operandType(IC_RESULT(dic)),FALSE))) + return NULL ; + + if (POINTER_GET(dic) && + !IS_DATA_PTR(aggrToPtr(operandType(IC_LEFT(dic)),FALSE))) + return NULL ; + + sic = dic; + + /* also make sure the intervenening instructions + don't have any thing in far space */ + for (dic = dic->next ; dic && dic != ic ; dic = dic->next) { + + /* if there is an intervening function call then no */ + if (dic->op == CALL || dic->op == PCALL) + return NULL; + /* if pointer set then make sure the pointer + is one byte */ + if (POINTER_SET(dic) && + !IS_DATA_PTR(aggrToPtr(operandType(IC_RESULT(dic)),FALSE))) + return NULL ; + + if (POINTER_GET(dic) && + !IS_DATA_PTR(aggrToPtr(operandType(IC_LEFT(dic)),FALSE))) + return NULL ; + + /* if address of & the result is remat the okay */ + if (dic->op == ADDRESS_OF && + OP_SYMBOL(IC_RESULT(dic))->remat) + continue ; + + /* if operand has size of three or more & this + operation is a '*','/' or '%' then 'b' may + cause a problem */ + if (( dic->op == '%' || dic->op == '/' || dic->op == '*') && + getSize(operandType(op)) >= 3) + return NULL; + + /* if left or right or result is in far space */ + if (isOperandInFarSpace(IC_LEFT(dic)) || + isOperandInFarSpace(IC_RIGHT(dic)) || + isOperandInFarSpace(IC_RESULT(dic)) || + IS_OP_RUONLY(IC_LEFT(dic)) || + IS_OP_RUONLY(IC_RIGHT(dic)) || + IS_OP_RUONLY(IC_RESULT(dic)) ) { + return NULL; + } + } + + OP_SYMBOL(op)->ruonly = 1; + return sic; + +} + +/*-----------------------------------------------------------------*/ +/* isBitwiseOptimizable - requirements of JEAN LOUIS VERN */ +/*-----------------------------------------------------------------*/ +static bool isBitwiseOptimizable (iCode *ic) +{ + link *ltype = getSpec(operandType(IC_LEFT(ic))); + link *rtype = getSpec(operandType(IC_RIGHT(ic))); + + /* bitwise operations are considered optimizable + under the following conditions (Jean-Louis VERN) + + x & lit + bit & bit + bit & x + bit ^ bit + bit ^ x + x ^ lit + x | lit + bit | bit + bit | x + */ + if ( IS_LITERAL(rtype) || + (IS_BITVAR(ltype) && IN_BITSPACE(SPEC_OCLS(ltype)))) + return TRUE ; + else + return FALSE ; +} + +/*-----------------------------------------------------------------*/ +/* packRegsForAccUse - pack registers for acc use */ +/*-----------------------------------------------------------------*/ +static void packRegsForAccUse (iCode *ic) +{ + iCode *uic; + + /* if + or - then it has to be one byte result */ + if ((ic->op == '+' || ic->op == '-') + && getSize(operandType(IC_RESULT(ic))) > 1) + return ; + + /* if shift operation make sure right side is not a literal */ + if (ic->op == RIGHT_OP && + ( isOperandLiteral(IC_RIGHT(ic)) || + getSize(operandType(IC_RESULT(ic))) > 1)) + return ; + + if (ic->op == LEFT_OP && + ( isOperandLiteral(IC_RIGHT(ic)) || + getSize(operandType(IC_RESULT(ic))) > 1)) + return ; + + if (IS_BITWISE_OP(ic) && + getSize(operandType(IC_RESULT(ic))) > 1) + return ; + + + /* has only one definition */ + if (bitVectnBitsOn(OP_DEFS(IC_RESULT(ic))) > 1) + return ; + + /* has only one use */ + if (bitVectnBitsOn(OP_USES(IC_RESULT(ic))) > 1) + return ; + + /* and the usage immediately follows this iCode */ + if (!(uic = hTabItemWithKey(iCodehTab, + bitVectFirstBit(OP_USES(IC_RESULT(ic)))))) + return ; + + if (ic->next != uic) + return ; + + /* if it is a conditional branch then we definitely can */ + if (uic->op == IFX ) + goto accuse; + + if ( uic->op == JUMPTABLE ) + return ; + + /* if the usage is not is an assignment + or an arithmetic / bitwise / shift operation then not */ + if (POINTER_SET(uic) && + getSize(aggrToPtr(operandType(IC_RESULT(uic)),FALSE)) > 1) + return; + + if (uic->op != '=' && + !IS_ARITHMETIC_OP(uic) && + !IS_BITWISE_OP(uic) && + uic->op != LEFT_OP && + uic->op != RIGHT_OP ) + return; + + /* if used in ^ operation then make sure right is not a + literl */ + if (uic->op == '^' && isOperandLiteral(IC_RIGHT(uic))) + return ; + + /* if shift operation make sure right side is not a literal */ + if (uic->op == RIGHT_OP && + ( isOperandLiteral(IC_RIGHT(uic)) || + getSize(operandType(IC_RESULT(uic))) > 1)) + return ; + + if (uic->op == LEFT_OP && + ( isOperandLiteral(IC_RIGHT(uic)) || + getSize(operandType(IC_RESULT(uic))) > 1)) + return ; + + /* make sure that the result of this icode is not on the + stack, since acc is used to compute stack offset */ + if (IS_TRUE_SYMOP(IC_RESULT(uic)) && + OP_SYMBOL(IC_RESULT(uic))->onStack) + return ; + + /* if either one of them in far space then we cannot */ + if ((IS_TRUE_SYMOP(IC_LEFT(uic)) && + isOperandInFarSpace(IC_LEFT(uic))) || + (IS_TRUE_SYMOP(IC_RIGHT(uic)) && + isOperandInFarSpace(IC_RIGHT(uic)))) + return ; + + /* if the usage has only one operand then we can */ + if (IC_LEFT(uic) == NULL || + IC_RIGHT(uic) == NULL) + goto accuse; + + /* make sure this is on the left side if not + a '+' since '+' is commutative */ + if (ic->op != '+' && + IC_LEFT(uic)->key != IC_RESULT(ic)->key) + return; + + /* if one of them is a literal then we can */ + if ((IC_LEFT(uic) && IS_OP_LITERAL(IC_LEFT(uic))) || + (IC_RIGHT(uic) && IS_OP_LITERAL(IC_RIGHT(uic)))) { + OP_SYMBOL(IC_RESULT(ic))->accuse = 1; + return ; + } + + /* if the other one is not on stack then we can */ + if (IC_LEFT(uic)->key == IC_RESULT(ic)->key && + (IS_ITEMP(IC_RIGHT(uic)) || + (IS_TRUE_SYMOP(IC_RIGHT(uic)) && + !OP_SYMBOL(IC_RIGHT(uic))->onStack))) + goto accuse; + + if (IC_RIGHT(uic)->key == IC_RESULT(ic)->key && + (IS_ITEMP(IC_LEFT(uic)) || + (IS_TRUE_SYMOP(IC_LEFT(uic)) && + !OP_SYMBOL(IC_LEFT(uic))->onStack))) + goto accuse ; + + return ; + + accuse: + OP_SYMBOL(IC_RESULT(ic))->accuse = 1; + + +} + +/*-----------------------------------------------------------------*/ +/* packForPush - hueristics to reduce iCode for pushing */ +/*-----------------------------------------------------------------*/ +static void packForPush(iCode *ic, eBBlock *ebp) +{ + iCode *dic; + + if (ic->op != IPUSH || !IS_ITEMP(IC_LEFT(ic))) + return ; + + /* must have only definition & one usage */ + if (bitVectnBitsOn(OP_DEFS(IC_LEFT(ic))) != 1 || + bitVectnBitsOn(OP_USES(IC_LEFT(ic))) != 1 ) + return ; + + /* find the definition */ + if (!(dic = hTabItemWithKey(iCodehTab, + bitVectFirstBit(OP_DEFS(IC_LEFT(ic)))))) + return ; + + if (dic->op != '=' || POINTER_SET(dic)) + return; + + /* we now we know that it has one & only one def & use + and the that the definition is an assignment */ + IC_LEFT(ic) = IC_RIGHT(dic); + + remiCodeFromeBBlock(ebp,dic); + hTabDeleteItem (&iCodehTab,dic->key,dic,DELETE_ITEM,NULL); +} + +/*-----------------------------------------------------------------*/ +/* packRegisters - does some transformations to reduce register */ +/* pressure */ +/*-----------------------------------------------------------------*/ +static void packRegisters (eBBlock *ebp) +{ + iCode *ic ; + int change = 0 ; + + while (1) { + + change = 0; + + /* look for assignments of the form */ + /* iTempNN = TRueSym (someoperation) SomeOperand */ + /* .... */ + /* TrueSym := iTempNN:1 */ + for ( ic = ebp->sch ; ic ; ic = ic->next ) { + + + /* find assignment of the form TrueSym := iTempNN:1 */ + if (ic->op == '=' && !POINTER_SET(ic)) + change += packRegsForAssign(ic,ebp); + } + + if (!change) + break; + } + + for ( ic = ebp->sch ; ic ; ic = ic->next ) { + + /* if this is an itemp & result of a address of a true sym + then mark this as rematerialisable */ + if (ic->op == ADDRESS_OF && + IS_ITEMP(IC_RESULT(ic)) && + IS_TRUE_SYMOP(IC_LEFT(ic)) && + bitVectnBitsOn(OP_DEFS(IC_RESULT(ic))) == 1 && + !OP_SYMBOL(IC_LEFT(ic))->onStack ) { + + OP_SYMBOL(IC_RESULT(ic))->remat = 1; + OP_SYMBOL(IC_RESULT(ic))->rematiCode = ic; + OP_SYMBOL(IC_RESULT(ic))->usl.spillLoc = NULL; + + } + + /* if straight assignment then carry remat flag if + this is the only definition */ + if (ic->op == '=' && + !POINTER_SET(ic) && + IS_SYMOP(IC_RIGHT(ic)) && + OP_SYMBOL(IC_RIGHT(ic))->remat && + bitVectnBitsOn(OP_SYMBOL(IC_RESULT(ic))->defs) <= 1) { + + OP_SYMBOL(IC_RESULT(ic))->remat = + OP_SYMBOL(IC_RIGHT(ic))->remat; + OP_SYMBOL(IC_RESULT(ic))->rematiCode = + OP_SYMBOL(IC_RIGHT(ic))->rematiCode ; + } + + /* if this is a +/- operation with a rematerizable + then mark this as rematerializable as well */ + if ((ic->op == '+' || ic->op == '-') && + (IS_SYMOP(IC_LEFT(ic)) && + IS_ITEMP(IC_RESULT(ic)) && + OP_SYMBOL(IC_LEFT(ic))->remat && + bitVectnBitsOn(OP_DEFS(IC_RESULT(ic))) == 1 && + IS_OP_LITERAL(IC_RIGHT(ic))) ) { + + //int i = + operandLitValue(IC_RIGHT(ic)); + OP_SYMBOL(IC_RESULT(ic))->remat = 1; + OP_SYMBOL(IC_RESULT(ic))->rematiCode = ic; + OP_SYMBOL(IC_RESULT(ic))->usl.spillLoc = NULL; + } + + /* mark the pointer usages */ + if (POINTER_SET(ic)) + OP_SYMBOL(IC_RESULT(ic))->uptr = 1; + + if (POINTER_GET(ic)) + OP_SYMBOL(IC_LEFT(ic))->uptr = 1; + + if (!SKIP_IC2(ic)) { + /* if we are using a symbol on the stack + then we should say pic14_ptrRegReq */ + if (ic->op == IFX && IS_SYMOP(IC_COND(ic))) + pic14_ptrRegReq += ((OP_SYMBOL(IC_COND(ic))->onStack || + OP_SYMBOL(IC_COND(ic))->iaccess) ? 1 : 0); + else + if (ic->op == JUMPTABLE && IS_SYMOP(IC_JTCOND(ic))) + pic14_ptrRegReq += ((OP_SYMBOL(IC_JTCOND(ic))->onStack || + OP_SYMBOL(IC_JTCOND(ic))->iaccess) ? 1 : 0); + else { + if (IS_SYMOP(IC_LEFT(ic))) + pic14_ptrRegReq += ((OP_SYMBOL(IC_LEFT(ic))->onStack || + OP_SYMBOL(IC_LEFT(ic))->iaccess) ? 1 : 0); + if (IS_SYMOP(IC_RIGHT(ic))) + pic14_ptrRegReq += ((OP_SYMBOL(IC_RIGHT(ic))->onStack || + OP_SYMBOL(IC_RIGHT(ic))->iaccess) ? 1 : 0); + if (IS_SYMOP(IC_RESULT(ic))) + pic14_ptrRegReq += ((OP_SYMBOL(IC_RESULT(ic))->onStack || + OP_SYMBOL(IC_RESULT(ic))->iaccess) ? 1 : 0); + } + } + + /* if the condition of an if instruction + is defined in the previous instruction then + mark the itemp as a conditional */ + if ((IS_CONDITIONAL(ic) || + ( ( ic->op == BITWISEAND || + ic->op == '|' || + ic->op == '^' ) && + isBitwiseOptimizable(ic))) && + ic->next && ic->next->op == IFX && + isOperandEqual(IC_RESULT(ic),IC_COND(ic->next)) && + OP_SYMBOL(IC_RESULT(ic))->liveTo <= ic->next->seq) { + + OP_SYMBOL(IC_RESULT(ic))->regType = REG_CND; + continue ; + } + + /* reduce for support function calls */ + if (ic->supportRtn || ic->op == '+' || ic->op == '-' ) + packRegsForSupport (ic,ebp); + + /* some cases the redundant moves can + can be eliminated for return statements */ + if ((ic->op == RETURN || ic->op == SEND) && + !isOperandInFarSpace(IC_LEFT(ic)) && + !options.model) + packRegsForOneuse (ic,IC_LEFT(ic),ebp); + + /* if pointer set & left has a size more than + one and right is not in far space */ + if (POINTER_SET(ic) && + !isOperandInFarSpace(IC_RIGHT(ic)) && + !OP_SYMBOL(IC_RESULT(ic))->remat && + !IS_OP_RUONLY(IC_RIGHT(ic)) && + getSize(aggrToPtr(operandType(IC_RESULT(ic)),FALSE)) > 1 ) + + packRegsForOneuse (ic,IC_RESULT(ic),ebp); + + /* if pointer get */ + if (POINTER_GET(ic) && + !isOperandInFarSpace(IC_RESULT(ic))&& + !OP_SYMBOL(IC_LEFT(ic))->remat && + !IS_OP_RUONLY(IC_RESULT(ic)) && + getSize(aggrToPtr(operandType(IC_LEFT(ic)),FALSE)) > 1 ) + + packRegsForOneuse (ic,IC_LEFT(ic),ebp); + + + /* if this is cast for intergral promotion then + check if only use of the definition of the + operand being casted/ if yes then replace + the result of that arithmetic operation with + this result and get rid of the cast */ + if (ic->op == CAST) { + link *fromType = operandType(IC_RIGHT(ic)); + link *toType = operandType(IC_LEFT(ic)); + + if (IS_INTEGRAL(fromType) && IS_INTEGRAL(toType) && + getSize(fromType) != getSize(toType) ) { + + iCode *dic = packRegsForOneuse(ic,IC_RIGHT(ic),ebp); + if (dic) { + if (IS_ARITHMETIC_OP(dic)) { + IC_RESULT(dic) = IC_RESULT(ic); + remiCodeFromeBBlock(ebp,ic); + hTabDeleteItem (&iCodehTab,ic->key,ic,DELETE_ITEM,NULL); + OP_DEFS(IC_RESULT(dic)) = bitVectSetBit(OP_DEFS(IC_RESULT(dic)),dic->key); + ic = ic->prev; + } else + OP_SYMBOL(IC_RIGHT(ic))->ruonly = 0; + } + } else { + + /* if the type from and type to are the same + then if this is the only use then packit */ + if (checkType(operandType(IC_RIGHT(ic)), + operandType(IC_LEFT(ic))) == 1) { + iCode *dic = packRegsForOneuse (ic,IC_RIGHT(ic),ebp); + if (dic) { + IC_RESULT(dic) = IC_RESULT(ic); + remiCodeFromeBBlock(ebp,ic); + hTabDeleteItem (&iCodehTab,ic->key,ic,DELETE_ITEM,NULL); + OP_DEFS(IC_RESULT(dic)) = bitVectSetBit(OP_DEFS(IC_RESULT(dic)),dic->key); + ic = ic->prev; + } + } + } + } + + /* pack for PUSH + iTempNN := (some variable in farspace) V1 + push iTempNN ; + ------------- + push V1 + */ + if (ic->op == IPUSH ) { + packForPush(ic,ebp); + } + + + /* pack registers for accumulator use, when the + result of an arithmetic or bit wise operation + has only one use, that use is immediately following + the defintion and the using iCode has only one + operand or has two operands but one is literal & + the result of that operation is not on stack then + we can leave the result of this operation in acc:b + combination */ + if ((IS_ARITHMETIC_OP(ic) + + || IS_BITWISE_OP(ic) + + || ic->op == LEFT_OP || ic->op == RIGHT_OP + + ) && + IS_ITEMP(IC_RESULT(ic)) && + getSize(operandType(IC_RESULT(ic))) <= 2) + + packRegsForAccUse (ic); + + } +} + +/*-----------------------------------------------------------------*/ +/* assignRegisters - assigns registers to each live range as need */ +/*-----------------------------------------------------------------*/ +void pic14_assignRegisters (eBBlock **ebbs, int count) +{ + iCode *ic; + int i ; + + setToNull((void *)&_G.funcrUsed); + pic14_ptrRegReq = _G.stackExtend = _G.dataExtend = 0; + + + /* change assignments this will remove some + live ranges reducing some register pressure */ + for (i = 0 ; i < count ;i++ ) + packRegisters (ebbs[i]); + + if (options.dump_pack) + dumpEbbsToFileExt(".dumppack",ebbs,count); + + /* first determine for each live range the number of + registers & the type of registers required for each */ + regTypeNum (); + + /* and serially allocate registers */ + serialRegAssign(ebbs,count); + + /* if stack was extended then tell the user */ + if (_G.stackExtend) { +/* werror(W_TOOMANY_SPILS,"stack", */ +/* _G.stackExtend,currFunc->name,""); */ + _G.stackExtend = 0 ; + } + + if (_G.dataExtend) { +/* werror(W_TOOMANY_SPILS,"data space", */ +/* _G.dataExtend,currFunc->name,""); */ + _G.dataExtend = 0 ; + } + + /* after that create the register mask + for each of the instruction */ + createRegMask (ebbs,count); + + /* redo that offsets for stacked automatic variables */ + redoStackOffsets (); + + if (options.dump_rassgn) + dumpEbbsToFileExt(".dumprassgn",ebbs,count); + + /* now get back the chain */ + ic = iCodeLabelOptimize(iCodeFromeBBlock (ebbs,count)); + + + genpic14Code(ic); + + /* free up any _G.stackSpil locations allocated */ + applyToSet(_G.stackSpil,deallocStackSpil); + _G.slocNum = 0; + setToNull((void **)&_G.stackSpil); + setToNull((void **)&_G.spiltSet); + /* mark all registers as free */ + freeAllRegs(); + + return ; +} diff --git a/src/pic/ralloc.h b/src/pic/ralloc.h new file mode 100644 index 00000000..6b3bf841 --- /dev/null +++ b/src/pic/ralloc.h @@ -0,0 +1,71 @@ +/*------------------------------------------------------------------------- + + SDCCralloc.h - header file register allocation + + Written By - Sandeep Dutta . sandeep.dutta@usa.net (1998) + PIC port - T. Scott Dattalo scott@dattalo.com (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 + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! +-------------------------------------------------------------------------*/ +#include "SDCCicode.h" +#include "SDCCBBlock.h" +#ifndef SDCCRALLOC_H +#define SDCCRALLOC_H 1 + +enum { R2_IDX = 0, R3_IDX , R4_IDX , + R5_IDX ,R6_IDX , R7_IDX , + R0_IDX ,R1_IDX , X8_IDX , + X9_IDX ,X10_IDX , X11_IDX , + X12_IDX ,CND_IDX }; + + +#define REG_PTR 0x01 +#define REG_GPR 0x02 +#define REG_CND 0x04 +/* definition for the registers */ +typedef struct regs +{ + short type; /* can have value + REG_GPR, REG_PTR or REG_CND */ + short rIdx ; /* index into register table */ + // short otype; + char *name ; /* name */ + char *dname; /* name when direct access needed */ + char *base ; /* base address */ + short offset; /* offset from the base */ + unsigned isFree :1; /* is currently unassigned */ +} regs; +extern regs regspic14[]; + +regs *pic14_regWithIdx (int); + + +enum PIC_register_types { + PIC_INDF, + PIC_TMR0, + PIC_FSR, + PIC_STATUS, + PIC_IOPORT, + PIC_IOTRIS, + PIC_GPR, /* A general purpose file register */ + PIC_SFR /* A special function register */ +}; + + +#endif diff --git a/src/regression/Makefile b/src/regression/Makefile new file mode 100644 index 00000000..834cff10 --- /dev/null +++ b/src/regression/Makefile @@ -0,0 +1,121 @@ +# Regression testing Makefile for Pic Port of SDCC +# +# GPL'd +# +# T. Scott Dattalo scott@dattalo.com +# +# This makefile provides a means by which the output +# of the SDCC Compiler can be tested. This version +# is unique to the PIC (as in Microchip PIC) port. +# As such it requires the following software: +# +# gpasm version 0.8.10 (or greater) +# gpsim version 0.20.7 (or greater) +# +# Usage: +# +# make +# - without any options the whole regression test is +# performed. The results are placed into a log file +# (defined by $LOGFILE). +# +# make asm +# - Creates .asm files by compiling the .c files +# +# make cod +# - Creates .cod files by assembling the .asm files +# (.cod files are symbolic files compatible with +# MPASM, Microchip's assembler) +# +# make stc +# - Creates .stc files which are script files for +# gpsim. +# +# make clean +# - removes all of the intermediate files created +# +# make cleancod +# make cleanasm +# make cleanstc +# - removes either the .stc, .asm, or .cod files + + +CC = ../../bin/sdcc + +.SUFFIXES: .asm .c .cod .stc + +# Results of the test are placed here: +LOGFILE = test.log + +# Script file for creating gpsim scripts +CREATESTC = create_stc + +# Script file for invoking gpsim +SIMULATE = simulate + +# List the C files to be test here: +SRC = b.c \ + compare.c + +COD := $(patsubst %.c, %.cod, $(SRC)) +ASM := $(patsubst %.c, %.asm, $(SRC)) +STC := $(patsubst %.c, %.stc, $(SRC)) + +all: test + + +# The asm files are generated by sdcc +.c.asm: + $(CC) -mpic -c $*.c + +# The .cod files are generated by gpasm +# these get loaded by gpsim. +.asm.cod: + gpasm $*.asm + +# The .stc files are script files for gpsim +.cod.stc: + ./$(CREATESTC) $*.cod $*.stc + +# this will also make .stc files +#%.stc : %.cod +# ./create_stc $^ $@ + +# now for the dependencies + +cod : $(COD) + + +asm : $(ASM) + +stc : $(STC) + +test: $(STC) + if [ -n "$(STC)" ]; then \ + stcfiles="$(STC)" ; \ + for f in $$stcfiles ; do \ + ./$(SIMULATE) $$f $(LOGFILE); \ + done ; \ + fi + echo "Done - Results are in $(LOGFILE)" + +cleancod: + files="$(COD)" ; \ + for f in $$files ; do \ + if [ -f $$f ]; then rm $$f; fi \ + done ; \ + +cleanasm: + files="$(ASM)" ; \ + for f in $$files ; do \ + if [ -f $$f ]; then rm $$f; fi \ + done ; \ + +cleanstc: + files="$(STC)" ; \ + for f in $$files ; do \ + if [ -f $$f ]; then rm $$f; fi \ + done ; \ + +clean: cleancod cleanasm cleanstc + if [ -f "$(LOGFILE)" ]; then rm $(LOGFILE); fi diff --git a/src/regression/b.c b/src/regression/b.c new file mode 100644 index 00000000..d082a4e1 --- /dev/null +++ b/src/regression/b.c @@ -0,0 +1,162 @@ +//#include "p16c84.h" + +unsigned char success=0; +unsigned char failures=0; +unsigned char dummy=0; + +bit bit0 = 0; +unsigned int aint0 = 0; +unsigned int aint1 = 0; +unsigned char achar0 = 0; +unsigned char achar1 = 0; + +void done() +{ + + dummy++; + +} + + + +void char_lt_char(void) +{ + if(achar0 < achar1) + failures++; +} + +void char_gt_char(void) +{ + if(achar1 > achar0) + failures++; +} + +void char_lte_char(void) +{ + if(achar0 <= achar1) + failures++; +} + +void char_gte_char(void) +{ + if(achar1 >= achar0) + failures++; +} + +void char_lt_lit(void) +{ + if(achar1 < 0x10) + failures++; +} + +void char_gt_lit(void) +{ + if(achar1 > 0x10) + failures++; +} + +void char_lte_lit(void) +{ + if(achar1 <= 0x0f) + failures++; +} + +void char_gte_lit(void) +{ + if(achar1 >= 0x11) + failures++; +} + + +/* ints */ + +void int_lt_int(void) +{ + if(aint0 < aint1) + failures++; +} + +void int_gt_int(void) +{ + if(aint1 > aint0) + failures++; +} + +void int_lte_int(void) +{ + if(aint0 <= aint1) + failures++; +} + +void int_gte_int(void) +{ + if(aint1 >= aint0) + failures++; +} + +void int_lt_lit(void) +{ + if(aint1 < 0x10) + failures++; +} + +void int_gt_lit(void) +{ + if(aint1 > 0x10) + failures++; +} + +void int_lte_lit(void) +{ + if(aint1 <= 0x0f) + failures++; +} + +void int_gte_lit(void) +{ + if(aint1 >= 0x11) + failures++; +} + + + + + + + +void main(void) +{ + + char_lt_char(); + char_gt_char(); + + achar0++; + char_lt_char(); + char_gt_char(); + char_gte_char(); + char_lte_char(); + + achar1 = 0x10; + char_lt_lit(); + char_gt_lit(); + char_lte_lit(); + char_gte_lit(); + + + + int_lt_int(); + int_gt_int(); + + aint0++; + int_lt_int(); + int_gt_int(); + int_gte_int(); + int_lte_int(); + + aint1 = 0x10; + int_lt_lit(); + int_gt_lit(); + + success = failures; + done(); +} diff --git a/src/regression/compare.c b/src/regression/compare.c new file mode 100644 index 00000000..b3cb8560 --- /dev/null +++ b/src/regression/compare.c @@ -0,0 +1,181 @@ +/* + + PIC PORT Test code + +*/ + +/* + compare.c test compare + +*/ + +bit bit0=0; +bit bit1=0; + +unsigned char success=0; +unsigned char failures=0; +unsigned char dummy=0; + +unsigned char achar0 = 0; +unsigned char achar1 = 0; +unsigned int aint0 = 0; +unsigned int aint1 = 0; + +char schar0=0; +char schar1=0; + +void done() +{ + + dummy++; + +} + +/* achar0 should be zero */ + +void compare_char_to_lits1(void) +{ + + if(achar0) + failures++; + + if(achar0 == 1) + failures++; + + if(achar0 == 7) + failures++; + + if(achar0 != 0) + failures++; +} + +/* achar0 should be `5' */ +void compare_char_to_lits2(void) +{ + + if(!achar0) + failures++; + + if(achar0 == 1) + failures++; + + if(achar0 == 7) + failures++; + + if(achar0 != 5) + failures++; +} + + +/* achar0 should equal achar1 */ +void compare_char_to_char1(void) +{ + + if(achar0 != achar1) + failures++; + + if(schar0 != schar1) + failures++; +} + +/* achar0 should be different than achar1 */ +void compare_char_to_char2(void) +{ + + if(achar0 == achar1) + failures++; + +} + +/* aint0 should be zero */ + +void compare_int_to_lits1(void) +{ + + if(aint0) + failures++; + + if(aint0 == 1) + failures++; + + if(aint0 == 7) + failures++; + + if(aint0 != 0) + failures++; +} + +/* aint0 should be `5' */ +void compare_int_to_lits2(void) +{ + + if(!aint0) + failures++; + + if(aint0 == 1) + failures++; + + if(aint0 == 7) + failures++; + + if(aint0 != 5) + failures++; +} + +/* aint0 should be `0x1234' */ +void compare_int_to_lits3(void) +{ + + if(!aint0) + failures++; + + if(aint0 == 1) + failures++; + + if(aint0 == 7) + failures++; + + if(aint0 != 0x1234) + failures++; +} + +/* aint0 should equal aint1 */ +void compare_int_to_int1(void) +{ + + if(aint0 != aint1) + failures++; + +} + +/* aint0 should be different than aint1 */ +void compare_int_to_int2(void) +{ + + if(aint0 == aint1) + failures++; + +} + +void main(void) +{ + + compare_char_to_lits1(); + compare_char_to_char1(); + achar0 = 5; + compare_char_to_lits2(); + compare_char_to_char2(); + + + compare_int_to_lits1(); + aint0 = 5; + compare_int_to_lits2(); + aint0 = 0x1234; + compare_int_to_lits3(); + compare_int_to_int2(); + aint0 = 0; + compare_int_to_int1(); + + success = failures; + done(); +} diff --git a/src/regression/create_stc b/src/regression/create_stc new file mode 100755 index 00000000..95eca641 --- /dev/null +++ b/src/regression/create_stc @@ -0,0 +1,16 @@ +# Create gpsim script file +# + +USAGE="Usage: `basename $0` COD_FILE GPSIM_SCRIPT" + +if [ $# -lt 2 ] ; then + echo "$USAGE" + exit 1 +fi + + +echo "load s $1" > $2 +echo "break e _done" >> $2 +echo "run" >> $2 +echo "x _success" >> $2 +echo "abort_gpsim_now" >> $2 diff --git a/src/regression/simulate b/src/regression/simulate new file mode 100755 index 00000000..548d3dbd --- /dev/null +++ b/src/regression/simulate @@ -0,0 +1,21 @@ +# SDCC test script for the PIC Port +# +USAGE="Usage: `basename $0` GPSIM_SCRIPT OUTPUT" + +if [ $# -lt 2 ] ; then + echo "$USAGE" + exit 1 +fi + + +GPSIM_SCRIPT=$1 +LOGFILE=$2 +touch $2 +echo "Test $GPSIM_SCRIPT" >> $LOGFILE +gpsim --cli -c $GPSIM_SCRIPT $2> test +grep "success " test | grep "= 0x0" +if [ $? -eq 0 ] ; then + echo "PASSED" >> $LOGFILE +else + echo "FAILED" >> $LOGFILE +fi \ No newline at end of file