diff options
| author | Xavier ASUS <xavi92psx@gmail.com> | 2019-10-18 00:31:54 +0200 |
|---|---|---|
| committer | Xavier ASUS <xavi92psx@gmail.com> | 2019-10-18 00:31:54 +0200 |
| commit | 268a53de823a6750d6256ee1fb1e7707b4b45740 (patch) | |
| tree | 42c1799a9a82b2f7d9790ee9fe181d72a7274751 /src/pic14/gen.c | |
| download | sdcc-gas-268a53de823a6750d6256ee1fb1e7707b4b45740.tar.gz | |
sdcc-3.9.0 fork implementing GNU assembler syntax
This fork aims to provide better support for stm8-binutils
Diffstat (limited to 'src/pic14/gen.c')
| -rw-r--r-- | src/pic14/gen.c | 7842 |
1 files changed, 7842 insertions, 0 deletions
diff --git a/src/pic14/gen.c b/src/pic14/gen.c new file mode 100644 index 0000000..7dd7548 --- /dev/null +++ b/src/pic14/gen.c @@ -0,0 +1,7842 @@ +/*------------------------------------------------------------------------- + gen.c - source file for code generation for pic + + Copyright (C) 1998, Sandeep Dutta . sandeep.dutta@usa.net + Copyright (C) 1999, Jean-Louis VERN.jlvern@writeme.com + Bug Fixes - Wojciech Stryjewski wstryj1@tiger.lsu.edu (1999 v2.1.9a) + PIC port: + Copyright (C) 2000, Scott Dattalo scott@dattalo.com + Copyright (C) 2005, Raphael Neider <rneider AT web.de> + + 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. +-------------------------------------------------------------------------*/ +/* + Notes: + 000123 mlh Moved aopLiteral to SDCCglue.c to help the split + Made everything static +*/ + +/* + * 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. + */ + +#include "device.h" +#include "gen.h" +#include "glue.h" +#include "dbuf_string.h" + +/* + * Imports + */ +extern struct dbuf_s *codeOutBuf; +extern set *externs; + +static PIC_device *pic = NULL; + +static pCodeOp *popGetImmd (const char *name, unsigned int offset, int index, int is_func); +static pCodeOp *popRegFromString (const char *str, int size, int offset); +static int aop_isLitLike (asmop * aop); +static void genCritical (iCode * ic); +static void genEndCritical (iCode * ic); + +/* The PIC port(s) need not differentiate between POINTER and FPOINTER. */ +#define PIC_IS_DATA_PTR(x) (IS_DATA_PTR(x) || IS_FARPTR(x)) + +/* + * max_key keeps track of the largest label number used in + * a function. This is then used to adjust the label offset + * for the next function. + */ +static int max_key = 0; +static int labelOffset = 0; +static int GpseudoStkPtr = 0; +static int pic14_inISR = 0; + +static char *zero = "0x00"; +static char *one = "0x01"; +static char *spname = "sp"; + +unsigned fReturnSizePic = 4; /* shared with ralloc.c */ +static char *fReturnpic14[] = { "temp1", "temp2", "temp3", "temp4" }; + +static char **fReturn = fReturnpic14; + +static struct +{ + short accInUse; + short nRegsSaved; + set *sendSet; +} _G; + +/* + * Resolved ifx structure. This structure stores information + * about an iCode ifx that makes it easier to generate code. + */ +typedef struct resolvedIfx +{ + symbol *lbl; /* pointer to a label */ + int condition; /* true or false ifx */ + int generated; /* set true when the code associated with the ifx + * is generated */ +} resolvedIfx; + +static pBlock *pb; + +/*-----------------------------------------------------------------*/ +/* my_powof2(n) - If `n' is an integer 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; +} + +void +DEBUGpic14_AopType (int line_no, operand * left, operand * right, operand * result) +{ + + DEBUGpic14_emitcode ("; ", "line = %d result %s=%s, size=%d, left %s=%s, size=%d, right %s=%s, size=%d", + line_no, + ((result) ? AopType (AOP_TYPE (result)) : "-"), + ((result) ? aopGet (AOP (result), 0, TRUE, FALSE) : "-"), + ((result) ? AOP_SIZE (result) : 0), + ((left) ? AopType (AOP_TYPE (left)) : "-"), + ((left) ? aopGet (AOP (left), 0, TRUE, FALSE) : "-"), + ((left) ? AOP_SIZE (left) : 0), + ((right) ? AopType (AOP_TYPE (right)) : "-"), + ((right) ? aopGet (AOP (right), 0, FALSE, FALSE) : "-"), ((right) ? AOP_SIZE (right) : 0)); + +} + +static void +DEBUGpic14_AopTypeSign (int line_no, operand * left, operand * right, operand * result) +{ + + DEBUGpic14_emitcode ("; ", "line = %d, signs: result %s=%c, left %s=%c, right %s=%c", + line_no, + ((result) ? AopType (AOP_TYPE (result)) : "-"), + ((result) ? (SPEC_USIGN (operandType (result)) ? 'u' : 's') : '-'), + ((left) ? AopType (AOP_TYPE (left)) : "-"), + ((left) ? (SPEC_USIGN (operandType (left)) ? 'u' : 's') : '-'), + ((right) ? AopType (AOP_TYPE (right)) : "-"), + ((right) ? (SPEC_USIGN (operandType (right)) ? 'u' : 's') : '-')); + +} + +void +DEBUGpic14_emitcode (const char *inst, const char *fmt, ...) +{ + va_list ap; + + if (!debug_verbose && !options.debug) + return; + + va_start (ap, fmt); + va_emitcode (inst, fmt, ap); + va_end (ap); + + addpCode2pBlock (pb, newpCodeCharP (genLine.lineCurr->line)); +} + +void +emitpComment (const char *fmt, ...) +{ + va_list ap; + struct dbuf_s dbuf; + const char *line; + + dbuf_init (&dbuf, INITIAL_INLINEASM); + + dbuf_append_char (&dbuf, ';'); + va_start (ap, fmt); + dbuf_vprintf (&dbuf, fmt, ap); + va_end (ap); + + line = dbuf_detach_c_str (&dbuf); + emit_raw (line); + dbuf_free (line); + + addpCode2pBlock (pb, newpCodeCharP (genLine.lineCurr->line)); +} + +void +emitpLabel (int key) +{ + addpCode2pBlock (pb, newpCodeLabel (NULL, labelKey2num (key + labelOffset))); +} + +/* gen.h defines a macro emitpcode that should be used to call emitpcode + * as this allows for easy debugging (ever asked the question: where was + * this instruction geenrated? Here is the answer... */ +void +emitpcode_real (PIC_OPCODE poc, pCodeOp * pcop) +{ + if (pcop) + addpCode2pBlock (pb, newpCode (poc, pcop)); + else + { + static int has_warned = FALSE; + + DEBUGpic14_emitcode (";", "%s ignoring NULL pcop", __FUNCTION__); + if (!has_warned) + { + has_warned = TRUE; + fprintf (stderr, "WARNING: encountered NULL pcop--this is probably a compiler bug...\n"); + } + } +} + +static void +emitpcodeNULLop (PIC_OPCODE poc) +{ + addpCode2pBlock (pb, newpCode (poc, NULL)); +} + +/*-----------------------------------------------------------------*/ +/* pic14_emitcode - writes the code into a file : for now it is simple */ +/*-----------------------------------------------------------------*/ +void +pic14_emitcode (const char *inst, const char *fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + va_emitcode (inst, fmt, ap); + va_end (ap); + + if (debug_verbose) + addpCode2pBlock (pb, newpCodeCharP (genLine.lineCurr->line)); +} + +/*-----------------------------------------------------------------*/ +/* pic14_emitDebuggerSymbol - associate the current code location */ +/* with a debugger symbol */ +/*-----------------------------------------------------------------*/ +void +pic14_emitDebuggerSymbol (const char *debugSym) +{ + genLine.lineElement.isDebug = TRUE; + pic14_emitcode ("", ";%s ==.", debugSym); + genLine.lineElement.isDebug = FALSE; +} + +/*-----------------------------------------------------------------*/ +/* newAsmop - creates a new asmOp */ +/*-----------------------------------------------------------------*/ +static asmop * +newAsmop (short type) +{ + asmop *aop; + + aop = Safe_alloc(sizeof(asmop)); + aop->type = type; + return aop; +} + +/*-----------------------------------------------------------------*/ +/* resolveIfx - converts an iCode ifx into a form more useful for */ +/* generating code */ +/*-----------------------------------------------------------------*/ +static void +resolveIfx (resolvedIfx * resIfx, iCode * ifx) +{ + if (!resIfx) + return; + + // DEBUGpic14_emitcode("; ***","%s %d",__FUNCTION__,__LINE__); + + resIfx->condition = TRUE; /* assume that the ifx is true */ + resIfx->generated = FALSE; /* indicate that the ifx has not been used */ + + if (!ifx) + { + resIfx->lbl = NULL; /* this is wrong: newiTempLabel(NULL); / * oops, there is no ifx. so create a label */ + } + else + { + if (IC_TRUE (ifx)) + { + resIfx->lbl = IC_TRUE (ifx); + } + else + { + resIfx->lbl = IC_FALSE (ifx); + resIfx->condition = FALSE; + } + } + + // DEBUGpic14_emitcode("; ***","%s lbl->key=%d, (lab offset=%d)",__FUNCTION__,resIfx->lbl->key,labelOffset); + +} + +/*-----------------------------------------------------------------*/ +/* aopForSym - for a true symbol */ +/*-----------------------------------------------------------------*/ +static asmop * +aopForSym (iCode * ic, symbol * sym, bool result) +{ + asmop *aop; + memmap *space = SPEC_OCLS (sym->etype); + + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + /* if already has one */ + if (sym->aop) + return sym->aop; + + //DEBUGpic14_emitcode(";","%d",__LINE__); + /* 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); + DEBUGpic14_emitcode (";", "%d sym->rname = %s, size = %d", __LINE__, sym->rname, aop->size); + return aop; + } + + /* special case for a function */ + if (IS_FUNC (sym->type)) + { + + sym->aop = aop = newAsmop (AOP_PCODE); + aop->aopu.pcop = popGetImmd (sym->rname, 0, 0, 1); + PCOI (aop->aopu.pcop)->_const = IN_CODESPACE (space); + PCOI (aop->aopu.pcop)->_function = TRUE; + PCOI (aop->aopu.pcop)->index = 0; + aop->size = FARPTRSIZE; + DEBUGpic14_emitcode (";", "%d size = %d, name =%s", __LINE__, aop->size, sym->rname); + return aop; + } + + if (IS_ARRAY (sym->type)) + { + sym->aop = aop = newAsmop (AOP_PCODE); + aop->aopu.pcop = popGetImmd (sym->rname, 0, 0, 1); + PCOI (aop->aopu.pcop)->_const = IN_CODESPACE (space); + PCOI (aop->aopu.pcop)->_function = FALSE; + PCOI (aop->aopu.pcop)->index = 0; + aop->size = getSize (sym->etype) * DCL_ELEM (sym->type); + + DEBUGpic14_emitcode (";", "%d size = %d, name =%s", __LINE__, aop->size, sym->rname); + return aop; + } + + /* only remaining is far space */ + /* in which case DPTR gets the address */ + sym->aop = aop = newAsmop (AOP_PCODE); + + aop->aopu.pcop = popGetImmd (sym->rname, 0, 0, 0); + PCOI (aop->aopu.pcop)->_const = IN_CODESPACE (space); + PCOI (aop->aopu.pcop)->index = 0; + + DEBUGpic14_emitcode (";", "%d: rname %s, val %d, const = %d", __LINE__, sym->rname, 0, PCOI (aop->aopu.pcop)->_const); + + allocDirReg (IC_LEFT (ic)); + + aop->size = FARPTRSIZE; + + /* if it is in code space */ + if (IN_CODESPACE (space)) + aop->code = TRUE; + + return aop; +} + +/*-----------------------------------------------------------------*/ +/* aopForRemat - rematerialzes an object */ +/*-----------------------------------------------------------------*/ +static asmop * +aopForRemat (operand * op) // x symbol *sym) +{ + symbol *sym = OP_SYMBOL (op); + iCode *ic = NULL; + asmop *aop = newAsmop (AOP_PCODE); + int val = 0; + + ic = sym->rematiCode; + + DEBUGpic14_emitcode (";", "%s %d", __FUNCTION__, __LINE__); + if (IS_OP_POINTER (op)) + { + DEBUGpic14_emitcode (";", "%s %d IS_OP_POINTER", __FUNCTION__, __LINE__); + } + for (;;) + { + if (ic->op == '+') + { + val += (int) operandLitValue (IC_RIGHT (ic)); + } + else if (ic->op == '-') + { + val -= (int) operandLitValue (IC_RIGHT (ic)); + } + else + break; + + ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode; + } + + aop->aopu.pcop = popGetImmd (OP_SYMBOL (IC_LEFT (ic))->rname, 0, val, 0); + PCOI (aop->aopu.pcop)->_const = IS_PTR_CONST (operandType (op)); + PCOI (aop->aopu.pcop)->index = val; + + DEBUGpic14_emitcode (";", "%d: rname %s, val %d, const = %d", + __LINE__, OP_SYMBOL (IC_LEFT (ic))->rname, val, IS_PTR_CONST (operandType (op))); + + // DEBUGpic14_emitcode(";","aop type %s",AopType(AOP_TYPE(IC_LEFT(ic)))); + + allocDirReg (IC_LEFT (ic)); + + return aop; +} + +static int +aopIdx (asmop * aop, int offset) +{ + if (!aop) + return -1; + + if (aop->type != AOP_REG) + return -2; + + return aop->aopu.aop_reg[offset]->rIdx; + +} + +/*-----------------------------------------------------------------*/ +/* 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 (sym1->rname[0] && sym2->rname[0] && 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; +} + +/*-----------------------------------------------------------------*/ +/* pic14_sameRegs - two asmops have the same registers */ +/*-----------------------------------------------------------------*/ +bool +pic14_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 : */ +/*-----------------------------------------------------------------*/ +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_VALUE (op); + aop->size = getSize (operandType (op)); + return; + } + + { + sym_link *type = operandType (op); + if (IS_PTR_CONST (type)) + DEBUGpic14_emitcode (";", "%d aop type is const pointer", __LINE__); + } + + /* 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) + { + DEBUGpic14_emitcode (";", "%d", __LINE__); + op->aop = OP_SYMBOL (op)->aop; + return; + } + + /* if this is a true symbol */ + if (IS_TRUE_SYMOP (op)) + { + //DEBUGpic14_emitcode(";","%d - true symop",__LINE__); + 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) + { + + DEBUGpic14_emitcode (";", "%d", __LINE__); + /* rematerialize it NOW */ + if (sym->remat) + { + + sym->aop = op->aop = aop = aopForRemat (op); + aop->size = getSize (sym->type); + //DEBUGpic14_emitcode(";"," %d: size %d, %s\n",__LINE__,aop->size,aop->aopu.aop_immd); + return; + } + + if (sym->ruonly) + { + if (sym->isptr) // && sym->uptr + { + aop = op->aop = sym->aop = newAsmop (AOP_PCODE); + aop->aopu.pcop = newpCodeOp (NULL, PO_GPR_POINTER); //popCopyReg(&pc_fsr); + + //PCOI(aop->aopu.pcop)->_const = 0; + //PCOI(aop->aopu.pcop)->index = 0; + /* + DEBUGpic14_emitcode(";","%d: rname %s, val %d, const = %d", + __LINE__,sym->rname, 0, PCOI(aop->aopu.pcop)->_const); + */ + //allocDirReg (IC_LEFT(ic)); + + aop->size = getSize (sym->type); + DEBUGpic14_emitcode (";", "%d", __LINE__); + return; + + } + else + { + + unsigned i; + + aop = op->aop = sym->aop = newAsmop (AOP_STR); + aop->size = getSize (sym->type); + for (i = 0; i < fReturnSizePic; i++) + aop->aopu.aop_str[i] = fReturn[i]; + + DEBUGpic14_emitcode (";", "%d", __LINE__); + return; + } + } + + /* else spill location */ + if (sym->isspilt && sym->usl.spillLoc) + { + asmop *oldAsmOp = NULL; + + if (getSize (sym->type) != getSize (sym->usl.spillLoc->type)) + { + /* force a new aop if sizes differ */ + oldAsmOp = sym->usl.spillLoc->aop; + sym->usl.spillLoc->aop = NULL; + } + DEBUGpic14_emitcode (";", "%s %d %s sym->rname = %s, offset %d", + __FUNCTION__, __LINE__, sym->usl.spillLoc->rname, sym->rname, sym->usl.spillLoc->offset); + + sym->aop = op->aop = aop = newAsmop (AOP_PCODE); + if (getSize (sym->type) != getSize (sym->usl.spillLoc->type)) + { + /* Don't reuse the new aop, go with the last one */ + sym->usl.spillLoc->aop = oldAsmOp; + } + //aop->aopu.pcop = popGetImmd(sym->usl.spillLoc->rname,0,sym->usl.spillLoc->offset); + aop->aopu.pcop = popRegFromString (sym->usl.spillLoc->rname, getSize (sym->type), sym->usl.spillLoc->offset); + aop->size = getSize (sym->type); + + return; + } + } + + { + sym_link *type = operandType (op); + if (IS_PTR_CONST (type)) + DEBUGpic14_emitcode (";", "%d aop type is const pointer", __LINE__); + } + + /* must be in a register */ + DEBUGpic14_emitcode (";", "%d register type nRegs=%d", __LINE__, sym->nRegs); + 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 */ +/*----------------------------------------------------------------*/ +void +freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop) +{ + asmop *aop; + + if (!op) + aop = aaop; + else + aop = op->aop; + + if (!aop) + return; + + aop->freed = TRUE; + + /* 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; + } + } +} + +/*-----------------------------------------------------------------*/ +/* pic14aopLiteral - string from a literal value */ +/*-----------------------------------------------------------------*/ +static unsigned int +pic14aopLiteral (value * val, int offset) +{ + 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 = ulFromVal (val); + + return ((v >> (offset * 8)) & 0xff); + } + + /* it is type float */ + fl.f = (float) floatFromVal (val); +#ifdef WORDS_BIGENDIAN + return fl.c[3 - offset]; +#else + return fl.c[offset]; +#endif +} + +/*-----------------------------------------------------------------*/ +/* aopGet - for fetching value of the aop */ +/*-----------------------------------------------------------------*/ +char * +aopGet (asmop * aop, int offset, bool bit16, bool dname) +{ + //DEBUGpic14_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* offset is greater than + size then zero */ + assert (aop); + if (offset > (aop->size - 1) && aop->type != AOP_LIT) + return zero; + + /* depending on type */ + switch (aop->type) + { + case AOP_IMMD: + if (bit16) + SNPRINTF(buffer, sizeof(buffer), "%s", aop->aopu.aop_immd); + else if (offset) + SNPRINTF(buffer, sizeof(buffer), "(%s >> %d)", aop->aopu.aop_immd, offset * 8); + else + SNPRINTF(buffer, sizeof(buffer), "%s", aop->aopu.aop_immd); + DEBUGpic14_emitcode (";", "%d immd %s", __LINE__, buffer); + return Safe_strdup(buffer); + + case AOP_DIR: + if (offset) + { + SNPRINTF(buffer, sizeof(buffer), "(%s + %d)", aop->aopu.aop_dir, offset); + DEBUGpic14_emitcode (";", "oops AOP_DIR did this %s\n", buffer); + } + else + SNPRINTF(buffer, sizeof(buffer), "%s", aop->aopu.aop_dir); + return Safe_strdup(buffer); + + case AOP_REG: + //if (dname) + // return aop->aopu.aop_reg[offset]->dname; + //else + return aop->aopu.aop_reg[offset]->name; + + case AOP_CRY: + //pic14_emitcode(";","%d",__LINE__); + return aop->aopu.aop_dir; + + case AOP_LIT: + SNPRINTF(buffer, sizeof(buffer), "0x%02x", pic14aopLiteral (aop->aopu.aop_lit, offset)); + return Safe_strdup(buffer); + + case AOP_STR: + aop->coff = offset; + if (strcmp (aop->aopu.aop_str[offset], "a") == 0 && dname) + return "acc"; + DEBUGpic14_emitcode (";", "%d - %s", __LINE__, aop->aopu.aop_str[offset]); + return aop->aopu.aop_str[offset]; + + case AOP_PCODE: + { + pCodeOp *pcop = aop->aopu.pcop; + DEBUGpic14_emitcode (";", "%d: aopGet AOP_PCODE type %s", __LINE__, pCodeOpType (pcop)); + if (pcop->name) + { + if (pcop->type == PO_IMMEDIATE) + { + offset += PCOI (pcop)->index; + } + + if (offset) + { + DEBUGpic14_emitcode (";", "%s offset %d", pcop->name, offset); + SNPRINTF(buffer, sizeof(buffer), "(%s+%d)", pcop->name, offset); + } + else + { + DEBUGpic14_emitcode (";", "%s", pcop->name); + SNPRINTF(buffer, sizeof(buffer), "%s", pcop->name); + } + } + else + SNPRINTF(buffer, sizeof(buffer), "0x%02x", PCOI (aop->aopu.pcop)->offset); + } + + return Safe_strdup(buffer); + } + + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "aopget got unsupported aop->type"); + exit (0); +} + +/*-----------------------------------------------------------------*/ +/* popGetTempReg - create a new temporary pCodeOp */ +/*-----------------------------------------------------------------*/ +static pCodeOp * +popGetTempReg (void) +{ + + pCodeOp *pcop; + + pcop = newpCodeOp (NULL, PO_GPR_TEMP); + if (pcop && pcop->type == PO_GPR_TEMP && PCOR (pcop)->r) + { + PCOR (pcop)->r->wasUsed = TRUE; + PCOR (pcop)->r->isFree = FALSE; + } + + return pcop; +} + +/*-----------------------------------------------------------------*/ +/* popReleaseTempReg - create a new temporary pCodeOp */ +/*-----------------------------------------------------------------*/ +static void +popReleaseTempReg (pCodeOp * pcop) +{ + + if (pcop && pcop->type == PO_GPR_TEMP && PCOR (pcop)->r) + PCOR (pcop)->r->isFree = TRUE; + +} + +/*-----------------------------------------------------------------*/ +/* popGetLabel - create a new pCodeOp of type PO_LABEL */ +/*-----------------------------------------------------------------*/ +pCodeOp * +popGetLabel (unsigned int key) +{ + + DEBUGpic14_emitcode ("; ***", "%s key=%d, label offset %d", __FUNCTION__, key, labelOffset); + + if (key > (unsigned int) max_key) + max_key = key; + + return newpCodeOpLabel (NULL, labelKey2num (key + labelOffset)); +} + +/*-------------------------------------------------------------------*/ +/* popGetHighLabel - create a new pCodeOp of type PO_LABEL with offset=1 */ +/*-------------------------------------------------------------------*/ +static pCodeOp * +popGetHighLabel (unsigned int key) +{ + pCodeOp *pcop; + pcop = popGetLabel (key); + PCOLAB (pcop)->offset = 1; + return pcop; +} + +/*-----------------------------------------------------------------*/ +/* popGetLit - asm operator to pcode operator conversion */ +/*-----------------------------------------------------------------*/ +pCodeOp * +popGetLit (unsigned int lit) +{ + + return newpCodeOpLit ((unsigned char) lit); +} + +/*-----------------------------------------------------------------*/ +/* popGetImmd - asm operator to pcode immediate conversion */ +/*-----------------------------------------------------------------*/ +static pCodeOp * +popGetImmd (const char *name, unsigned int offset, int index, int is_func) +{ + + return newpCodeOpImmd (name, offset, index, 0, is_func); +} + +/*-----------------------------------------------------------------*/ +/* popGetWithString - asm operator to pcode operator conversion */ +/*-----------------------------------------------------------------*/ +static pCodeOp * +popGetWithString (const char *str, int isExtern) +{ + pCodeOp *pcop; + + + if (!str) + { + fprintf (stderr, "NULL string %s %d\n", __FILE__, __LINE__); + exit (1); + } + + pcop = newpCodeOp (str, PO_STR); + PCOS (pcop)->isPublic = isExtern ? 1 : 0; + + return pcop; +} + +pCodeOp * +popGetExternal (const char *str, int isReg) +{ + pCodeOp *pcop; + + if (isReg) + { + pcop = newpCodeOpRegFromStr (str); + } + else + { + pcop = popGetWithString (str, 1); + } + + if (str) + { + symbol *sym; + + for (sym = setFirstItem (externs); sym; sym = setNextItem (externs)) + { + if (!strcmp (str, sym->rname)) + break; + } + + if (!sym) + { + sym = newSymbol (str, 0); + strncpy (sym->rname, str, SDCC_NAME_MAX); + addSet (&externs, sym); + } // if + sym->used++; + } + return pcop; +} + +/*-----------------------------------------------------------------*/ +/* popRegFromString - */ +/*-----------------------------------------------------------------*/ +static pCodeOp * +popRegFromString (const char *str, int size, int offset) +{ + + pCodeOp *pcop = Safe_alloc(sizeof(pCodeOpReg)); + pcop->type = PO_DIR; + + DEBUGpic14_emitcode (";", "%d", __LINE__); + + if (!str) + str = "BAD_STRING"; + + pcop->name = Safe_strdup(str); + + //pcop->name = Safe_strdup( ( (str) ? str : "BAD STRING")); + + PCOR (pcop)->r = dirregWithName (pcop->name); + if (PCOR (pcop)->r == NULL) + { + //fprintf(stderr,"%d - couldn't find %s in allocated registers, size =%d\n",__LINE__,aop->aopu.aop_dir,aop->size); + PCOR (pcop)->r = allocRegByName (pcop->name, size); + DEBUGpic14_emitcode (";", "%d %s offset=%d - had to alloc by reg name", __LINE__, pcop->name, offset); + } + else + { + DEBUGpic14_emitcode (";", "%d %s offset=%d", __LINE__, pcop->name, offset); + } + PCOR (pcop)->instance = offset; + + return pcop; +} + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +static pCodeOp * +popRegFromIdx (int rIdx) +{ + pCodeOp *pcop; + + DEBUGpic14_emitcode ("; ***", "%s,%d , rIdx=0x%x", __FUNCTION__, __LINE__, rIdx); + + pcop = Safe_alloc(sizeof(pCodeOpReg)); + + PCOR (pcop)->rIdx = rIdx; + PCOR (pcop)->r = typeRegWithIdx (rIdx, REG_STK, 1); + PCOR (pcop)->r->isFree = FALSE; + PCOR (pcop)->r->wasUsed = TRUE; + + pcop->type = PCOR (pcop)->r->pc_type; + + + return pcop; +} + +/*-----------------------------------------------------------------*/ +/* popGet - asm operator to pcode operator conversion */ +/*-----------------------------------------------------------------*/ +pCodeOp * +popGet (asmop * aop, int offset) //, bool bit16, bool dname) +{ + //char *s = buffer ; + //char *rs; + + pCodeOp *pcop; + + //DEBUGpic14_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* offset is greater than + size then zero */ + + assert (aop); + + + /* XXX: still needed for BIT operands (AOP_CRY) */ + if ((offset >= aop->size) && (aop->type != AOP_LIT) && (aop->type != AOP_PCODE)) + { + printf ("%s: (offset[%d] >= AOP_SIZE(op)[%d]) && (AOP_TYPE(op)[%d] != { AOP_LIT, AOP_PCODE })\n", + __FUNCTION__, offset, aop->size, aop->type); + return NULL; //zero; + } + + /* depending on type */ + switch (aop->type) + { + + case AOP_IMMD: + DEBUGpic14_emitcode (";", "%d", __LINE__); + return popGetImmd (aop->aopu.aop_immd, offset, 0, 0); + + case AOP_DIR: + return popRegFromString (aop->aopu.aop_dir, aop->size, offset); + + case AOP_REG: + { + int rIdx; + assert (offset < aop->size); + rIdx = aop->aopu.aop_reg[offset]->rIdx; + + pcop = Safe_alloc(sizeof(pCodeOpReg)); + PCOR (pcop)->rIdx = rIdx; + PCOR (pcop)->r = pic14_regWithIdx (rIdx); + PCOR (pcop)->r->wasUsed = TRUE; + PCOR (pcop)->r->isFree = FALSE; + + PCOR (pcop)->instance = offset; + pcop->type = PCOR (pcop)->r->pc_type; + //rs = aop->aopu.aop_reg[offset]->name; + DEBUGpic14_emitcode (";", "%d rIdx = r0x%X ", __LINE__, rIdx); + return pcop; + } + + case AOP_CRY: + pcop = newpCodeOpBit (aop->aopu.aop_dir, -1, 1); + PCOR (pcop)->r = dirregWithName (aop->aopu.aop_dir); + //if(PCOR(pcop)->r == NULL) + //fprintf(stderr,"%d - couldn't find %s in allocated registers\n",__LINE__,aop->aopu.aop_dir); + return pcop; + + case AOP_LIT: + return newpCodeOpLit (pic14aopLiteral (aop->aopu.aop_lit, offset)); + + case AOP_STR: + DEBUGpic14_emitcode (";", "%d %s", __LINE__, aop->aopu.aop_str[offset]); + return newpCodeOpRegFromStr (aop->aopu.aop_str[offset]); + + case AOP_PCODE: + pcop = NULL; + DEBUGpic14_emitcode (";", "popGet AOP_PCODE (%s + %i) %d %s", pCodeOpType (aop->aopu.pcop), offset, + __LINE__, ((aop->aopu.pcop->name) ? (aop->aopu.pcop->name) : "no name")); + //emitpComment ("popGet; name %s, offset: %i, pcop-type: %s\n", aop->aopu.pcop->name, offset, pCodeOpType (aop->aopu.pcop)); + switch (aop->aopu.pcop->type) + { + case PO_IMMEDIATE: + pcop = pCodeOpCopy (aop->aopu.pcop); + /* usually we want to access the memory at "<symbol> + offset" (using ->index), + * but sometimes we want to access the high byte of the symbol's address (using ->offset) */ + PCOI (pcop)->index += offset; + //PCOI(pcop)->offset = 0; + break; + case PO_DIR: + pcop = pCodeOpCopy (aop->aopu.pcop); + PCOR (pcop)->instance = offset; + break; + default: + assert (!"unhandled pCode type"); + break; + } // switch + return pcop; + } + + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "popGet got unsupported aop->type"); + exit (0); +} + +/*-----------------------------------------------------------------*/ +/* popGetAddr - access the low/high word of a symbol (immediate) */ +/* (for non-PO_IMMEDIATEs this is the same as popGet) */ +/*-----------------------------------------------------------------*/ +pCodeOp * +popGetAddr (asmop * aop, int offset, int index) +{ + if (aop->type == AOP_PCODE && aop->aopu.pcop->type == PO_IMMEDIATE) + { + pCodeOp *pcop = aop->aopu.pcop; + assert (offset <= GPTRSIZE); + + /* special case: index >= 2 should return GPOINTER-style values */ + if (offset == 2) + { + pcop = popGetLit (aop->code ? GPTRTAG_CODE : GPTRTAG_DATA); + return pcop; + } + + pcop = pCodeOpCopy (pcop); + /* usually we want to access the memory at "<symbol> + offset" (using ->index), + * but sometimes we want to access the high byte of the symbol's address (using ->offset) */ + PCOI (pcop)->offset += offset; + PCOI (pcop)->index += index; + //fprintf (stderr, "is PO_IMMEDIATE: %s+o%d+i%d (new o%d,i%d)\n", pcop->name,PCOI(pcop)->offset,PCOI(pcop)->index, offset, index); + return pcop; + } + else + { + return popGet (aop, offset + index); + } +} + +/*-----------------------------------------------------------------*/ +/* aopPut - puts a string for a aop */ +/*-----------------------------------------------------------------*/ +void +aopPut (asmop * aop, const char *s, int offset) +{ + symbol *lbl; + + DEBUGpic14_emitcode ("; ***", "%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) + { + SNPRINTF(buffer, sizeof(buffer), "(%s + %d)", aop->aopu.aop_dir, offset); + fprintf (stderr, "oops aopPut:AOP_DIR did this %s\n", s); + } + else + SNPRINTF(buffer, sizeof(buffer), "%s", aop->aopu.aop_dir); + + if (strcmp (buffer, s)) + { + DEBUGpic14_emitcode (";", "%d", __LINE__); + if (strcmp (s, "W")) + pic14_emitcode ("movf", "%s,w", s); + + pic14_emitcode ("movwf", "%s", buffer); + + if (strcmp (s, "W")) + { + pic14_emitcode (";BUG!? should have this:movf", "%s,w %d", s, __LINE__); + if (offset >= aop->size) + { + emitpcode (POC_CLRF, popGet (aop, offset)); + break; + } + else + { + emitpcode (POC_MOVFW, popGetImmd (s, 0, offset, 0)); + } + } + emitpcode (POC_MOVWF, popGet (aop, offset)); + } + break; + + case AOP_REG: + if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0) + { + if (strcmp (s, "W") == 0) + pic14_emitcode ("movf", "%s,w ; %d", s, __LINE__); + + pic14_emitcode ("movwf", "%s", aop->aopu.aop_reg[offset]->name); + + if (strcmp (s, zero) == 0) + { + emitpcode (POC_CLRF, popGet (aop, offset)); + + } + else if (strcmp (s, "W") == 0) + { + pCodeOp *pcop = Safe_alloc(sizeof(pCodeOpReg)); + pcop->type = PO_GPR_REGISTER; + + PCOR (pcop)->rIdx = -1; + PCOR (pcop)->r = NULL; + + DEBUGpic14_emitcode (";", "%d", __LINE__); + pcop->name = Safe_strdup (s); + emitpcode (POC_MOVFW, pcop); + emitpcode (POC_MOVWF, popGet (aop, offset)); + } + else if (strcmp (s, one) == 0) + { + emitpcode (POC_CLRF, popGet (aop, offset)); + emitpcode (POC_INCF, popGet (aop, offset)); + } + else + { + emitpcode (POC_MOVWF, popGet (aop, offset)); + } + } + break; + + case AOP_STK: + if (strcmp (s, "a") == 0) + pic14_emitcode ("push", "acc"); + else + pic14_emitcode ("push", "%s", s); + break; + + case AOP_CRY: + /* if bit variable */ + if (!aop->aopu.aop_dir) + { + pic14_emitcode ("clr", "a"); + pic14_emitcode ("rlc", "a"); + } + else + { + if (s == zero) + pic14_emitcode ("clr", "%s", aop->aopu.aop_dir); + else if (s == one) + pic14_emitcode ("setb", "%s", aop->aopu.aop_dir); + else if (!strcmp (s, "c")) + pic14_emitcode ("mov", "%s,c", aop->aopu.aop_dir); + else + { + lbl = newiTempLabel (NULL); + + if (strcmp (s, "a")) + { + MOVA (s); + } + + pic14_emitcode ("clr", "c"); + pic14_emitcode ("jz", "%05d_DS_", labelKey2num (lbl->key)); + pic14_emitcode ("cpl", "c"); + pic14_emitcode ("", "%05d_DS_:", labelKey2num (lbl->key)); + pic14_emitcode ("mov", "%s,c", aop->aopu.aop_dir); + } + } + break; + + case AOP_STR: + aop->coff = offset; + if (strcmp (aop->aopu.aop_str[offset], s)) + pic14_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); + } +} + +/*-----------------------------------------------------------------*/ +/* mov2w_op - generate either a MOVLW or MOVFW based operand type */ +/*-----------------------------------------------------------------*/ +static void +mov2w_op (operand * op, int offset) +{ + assert (op); + FENTRY; + + /* for PO_IMMEDIATEs: use address or value? */ + if (op_isLitLike (op)) + { + /* access address of op */ + if (AOP_TYPE (op) != AOP_LIT) + { + assert (offset < 3); + } + if (IS_SYMOP (op) && IS_GENPTR (OP_SYM_TYPE (op)) && AOP_SIZE (op) < offset) + { + if (offset == GPTRSIZE - 1) + emitpcode (POC_MOVLW, popGetLit (GPTRTAG_DATA)); + else + emitpcode (POC_MOVLW, popGetLit (0)); + } + else + emitpcode (POC_MOVLW, popGetAddr (AOP (op), offset, 0)); + } + else + { + /* access value stored in op */ + mov2w (AOP (op), offset); + } +} + + +/*-----------------------------------------------------------------*/ +/* mov2w - generate either a MOVLW or MOVFW based operand type */ +/*-----------------------------------------------------------------*/ +void +mov2w (asmop * aop, int offset) +{ + + if (!aop) + return; + + DEBUGpic14_emitcode ("; ***", "%s %d offset=%d", __FUNCTION__, __LINE__, offset); + + if (aop_isLitLike (aop)) + emitpcode (POC_MOVLW, popGetAddr (aop, offset, 0)); + else + emitpcode (POC_MOVFW, popGet (aop, offset)); + +} + +static void +movwf (asmop * op, int offset) +{ + emitpcode (POC_MOVWF, popGet (op, offset)); +} + +static pCodeOp * +get_argument_pcop (int idx) +{ + assert (idx > 0 && "the 0th (first) argument is passed via WREG"); + return popRegFromIdx (Gstack_base_addr - (idx - 1)); +} + +static pCodeOp * +get_return_val_pcop (int offset) +{ + assert (offset > 0 && "the most significant byte is returned via WREG"); + return popRegFromIdx (Gstack_base_addr - (offset - 1)); +} + +static void +pass_argument (operand * op, int offset, int idx) +{ + if (op) + mov2w_op (op, offset); + if (idx != 0) + emitpcode (POC_MOVWF, get_argument_pcop (idx)); +} + +static void +get_returnvalue (operand * op, int offset, int idx) +{ + if (idx != 0) + emitpcode (POC_MOVFW, get_return_val_pcop (idx)); + movwf (AOP (op), offset); +} + +static void +call_libraryfunc (char *name) +{ + symbol *sym; + + /* library code might reside in different page... */ + emitpcode (POC_PAGESEL, popGetWithString (name, 1)); + /* call the library function */ + emitpcode (POC_CALL, popGetExternal (name, 0)); + /* might return from different page... */ + emitpcode (POC_PAGESEL, popGetWithString ("$", 0)); + + /* create symbol, mark it as `extern' */ + sym = findSym (SymbolTab, NULL, name); + if (!sym) + { + sym = newSymbol (name, 0); + strncpy (sym->rname, name, SDCC_NAME_MAX); + addSym (SymbolTab, sym, sym->rname, 0, 0, 0); + addSet (&externs, sym); + } // if + sym->used++; +} + +/*-----------------------------------------------------------------*/ +/* pic14_getDataSize - get the operand data size */ +/*-----------------------------------------------------------------*/ +int +pic14_getDataSize (operand * op) +{ + int size; + + size = AOP_SIZE (op); + return size; +} + +/*-----------------------------------------------------------------*/ +/* pic14_outAcc - output Acc */ +/*-----------------------------------------------------------------*/ +void +pic14_outAcc (operand * result) +{ + int size, offset; + DEBUGpic14_emitcode ("; ***", "%s %d - ", __FUNCTION__, __LINE__); + DEBUGpic14_AopType (__LINE__, NULL, NULL, result); + + + size = pic14_getDataSize (result); + if (size) + { + emitpcode (POC_MOVWF, popGet (AOP (result), 0)); + size--; + offset = 1; + /* unsigned or positive */ + while (size--) + emitpcode (POC_CLRF, popGet (AOP (result), offset++)); + } + +} + +/*-----------------------------------------------------------------*/ +/* pic14_outBitC - output a bit C */ +/*-----------------------------------------------------------------*/ +static void +pic14_outBitC (operand * result) +{ + + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + /* if the result is bit */ + if (AOP_TYPE (result) == AOP_CRY) + aopPut (AOP (result), "c", 0); + else + { + pic14_emitcode ("clr", "a ; %d", __LINE__); + pic14_emitcode ("rlc", "a"); + pic14_outAcc (result); + } +} + +/*-----------------------------------------------------------------*/ +/* pic14_toBoolean - emit code for orl a,operator(sizeop) */ +/*-----------------------------------------------------------------*/ +static void +pic14_toBoolean (operand * oper) +{ + int size = AOP_SIZE (oper); + int offset = 0; + + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + + assert (size > 0); + + if (size == 1) + { + /* MOVFW does not load the flags... */ + emitpcode (POC_MOVLW, popGetLit (0)); + offset = 0; + } + else + { + emitpcode (POC_MOVFW, popGet (AOP (oper), 0)); + offset = 1; + } + + while (offset < size) + { + emitpcode (POC_IORFW, popGet (AOP (oper), offset++)); + } + /* Z is set iff (oper == 0) */ +} + + +/*-----------------------------------------------------------------*/ +/* genNot - generate code for ! operation */ +/*-----------------------------------------------------------------*/ +static void +genNot (iCode * ic) +{ + //symbol *tlbl; + int size; + + FENTRY; + + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + /* assign asmOps to operand & result */ + aopOp (IC_LEFT (ic), ic, FALSE); + aopOp (IC_RESULT (ic), ic, TRUE); + + DEBUGpic14_AopType (__LINE__, IC_LEFT (ic), NULL, IC_RESULT (ic)); + /* if in bit space then a special case */ + if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY) + { + if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY) + { + emitpcode (POC_MOVLW, popGet (AOP (IC_LEFT (ic)), 0)); + emitpcode (POC_XORWF, popGet (AOP (IC_RESULT (ic)), 0)); + } + else + { + emitpcode (POC_CLRF, popGet (AOP (IC_RESULT (ic)), 0)); + emitpcode (POC_BTFSS, popGet (AOP (IC_LEFT (ic)), 0)); + emitpcode (POC_INCF, popGet (AOP (IC_RESULT (ic)), 0)); + } + goto release; + } + + size = AOP_SIZE (IC_LEFT (ic)); + mov2w (AOP (IC_LEFT (ic)), 0); + while (--size > 0) + { + if (op_isLitLike (IC_LEFT (ic))) + emitpcode (POC_IORLW, popGetAddr (AOP (IC_LEFT (ic)), size, 0)); + else + emitpcode (POC_IORFW, popGet (AOP (IC_LEFT (ic)), size)); + } + emitpcode (POC_MOVLW, popGetLit (0)); + emitSKPNZ; + emitpcode (POC_MOVLW, popGetLit (1)); + movwf (AOP (IC_RESULT (ic)), 0); + + for (size = 1; size < AOP_SIZE (IC_RESULT (ic)); size++) + { + emitpcode (POC_CLRF, popGet (AOP (IC_RESULT (ic)), size)); + } + goto release; + +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) +{ + operand *left, *result; + int size, offset = 0; + + FENTRY; + + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + aopOp ((left = IC_LEFT (ic)), ic, FALSE); + aopOp ((result = IC_RESULT (ic)), ic, TRUE); + + /* if both are in bit space then + a special case */ + if (AOP_TYPE (result) == AOP_CRY && AOP_TYPE (left) == AOP_CRY) + { + + pic14_emitcode ("mov", "c,%s", left->aop->aopu.aop_dir); + pic14_emitcode ("cpl", "c"); + pic14_emitcode ("mov", "%s,c", result->aop->aopu.aop_dir); + goto release; + } + + size = AOP_SIZE (result); + if (AOP_SIZE (left) < size) + size = AOP_SIZE (left); + while (size--) + { + emitpcode (POC_COMFW, popGet (AOP (left), offset)); + emitpcode (POC_MOVWF, popGet (AOP (result), offset)); + offset++; + } + addSign (result, AOP_SIZE (left), !SPEC_USIGN (operandType (result))); + + +release: + /* release the aops */ + freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? 0 : 1)); + freeAsmop (result, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genUminusFloat - unary minus for floating points */ +/*-----------------------------------------------------------------*/ +static void +genUminusFloat (operand * op, operand * result) +{ + int size; + + FENTRY; + + DEBUGpic14_emitcode ("; ***", "%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; + + mov2w_op (op, size); + emitpcode (POC_XORLW, popGetLit (0x80)); + movwf (AOP (result), size); + + while (size--) + { + mov2w_op (op, size); + movwf (AOP (result), size); + } // while +} + +/*-----------------------------------------------------------------*/ +/* genUminus - unary minus code generation */ +/*-----------------------------------------------------------------*/ +static void +genUminus (iCode * ic) +{ + int size, i; + sym_link *optype; + + FENTRY; + + DEBUGpic14_emitcode ("; ***", "%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) + { + + emitpcode (POC_BCF, popGet (AOP (IC_RESULT (ic)), 0)); + emitpcode (POC_BTFSS, popGet (AOP (IC_LEFT (ic)), 0)); + emitpcode (POC_BSF, popGet (AOP (IC_RESULT (ic)), 0)); + + goto release; + } + + optype = operandType (IC_LEFT (ic)); + + /* if float then do float stuff */ + if (IS_FLOAT (optype)) + { + genUminusFloat (IC_LEFT (ic), IC_RESULT (ic)); + goto release; + } + + /* otherwise subtract from zero by taking the 2's complement */ + size = AOP_SIZE (IC_LEFT (ic)); + + for (i = 0; i < size; i++) + { + if (pic14_sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic)))) + emitpcode (POC_COMF, popGet (AOP (IC_LEFT (ic)), i)); + else + { + emitpcode (POC_COMFW, popGet (AOP (IC_LEFT (ic)), i)); + emitpcode (POC_MOVWF, popGet (AOP (IC_RESULT (ic)), i)); + } + } + + emitpcode (POC_INCF, popGet (AOP (IC_RESULT (ic)), 0)); + for (i = 1; i < size; i++) + { + emitSKPNZ; + emitpcode (POC_INCF, popGet (AOP (IC_RESULT (ic)), i)); + } + +release: + /* release the aops */ + freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1)); + freeAsmop (IC_RESULT (ic), NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* saverbank - saves an entire register bank on the stack */ +/*-----------------------------------------------------------------*/ +static void +saverbank (int bank, iCode * ic, bool pushPsw) +{ + FENTRY; + + DEBUGpic14_emitcode ("; ***", "%s %d - WARNING no code generated", __FUNCTION__, __LINE__); +#if 0 + int i; + asmop *aop; + regs *r = NULL; + + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + if (options.useXstack) + { + + aop = newAsmop (0); + r = getFreePtr (ic, &aop, FALSE); + pic14_emitcode ("mov", "%s,_spx", r->name); + + } + + for (i = 0; i < pic14_nRegs; i++) + { + if (options.useXstack) + { + pic14_emitcode ("inc", "%s", r->name); + //pic14_emitcode("mov","a,(%s+%d)", + // regspic14[i].base,8*bank+regspic14[i].offset); + pic14_emitcode ("movx", "@%s,a", r->name); + } + else + pic14_emitcode ("push", ""); // "(%s+%d)", + //regspic14[i].base,8*bank+regspic14[i].offset); + } + + if (pushPsw) + { + if (options.useXstack) + { + pic14_emitcode ("mov", "a,psw"); + pic14_emitcode ("movx", "@%s,a", r->name); + pic14_emitcode ("inc", "%s", r->name); + pic14_emitcode ("mov", "_spx,%s", r->name); + freeAsmop (NULL, aop, ic, TRUE); + + } + else + pic14_emitcode ("push", "psw"); + + pic14_emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0x00ff); + } + ic->bankSaved = 1; +#endif +} + +/*-----------------------------------------------------------------*/ +/* saveRegisters - will look for a call and save the registers */ +/*-----------------------------------------------------------------*/ +static void +saveRegisters (iCode * lic) +{ + iCode *ic; + sym_link *dtype; + + FENTRY; + + DEBUGpic14_emitcode ("; ***", "%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 || IFFUNC_CALLEESAVES (OP_SYMBOL (IC_LEFT (ic))->type)) + return; + + /* find the registers in use at this time + and push them away to safety */ + bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed); + + ic->regsSaved = 1; + + //fprintf(stderr, "ERROR: saveRegisters did not do anything to save registers, please report this as a bug.\n"); + + dtype = operandType (IC_LEFT (ic)); + if (currFunc && dtype && + (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) && IFFUNC_ISISR (currFunc->type) && !ic->bankSaved) + { + saverbank (FUNC_REGBANK (dtype), ic, TRUE); + } +} + +/*-----------------------------------------------------------------*/ +/* unsaveRegisters - pop the pushed registers */ +/*-----------------------------------------------------------------*/ +static void +unsaveRegisters (iCode * ic) +{ + int i; + bitVect *rsave; + + FENTRY; + + DEBUGpic14_emitcode ("; ***", "%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) + { + pic14_emitcode ("mov", "r0,%s", spname); + for (i = pic14_nRegs; i >= 0; i--) + { + if (bitVectBitValue (rsave, i)) + { + pic14_emitcode ("dec", "r0"); + pic14_emitcode ("movx", "a,@r0"); + pic14_emitcode ("mov", "%s,a", pic14_regWithIdx (i)->name); + } + + } + pic14_emitcode ("mov", "%s,r0", spname); + } //else + //for (i = pic14_nRegs ; i >= 0 ; i--) { + // if (bitVectBitValue(rsave,i)) + // pic14_emitcode("pop","%s",pic14_regWithIdx(i)->dname); + //} + +} + + +/*-----------------------------------------------------------------*/ +/* pushSide - */ +/*-----------------------------------------------------------------*/ +static void +pushSide (operand * oper, int size) +{ +#if 0 + int offset = 0; + DEBUGpic14_emitcode ("; ***", "%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")) + { + pic14_emitcode ("mov", "a,%s", l); + pic14_emitcode ("push", "acc"); + } + else + pic14_emitcode ("push", "%s", l); + } +#endif +} + +/*-----------------------------------------------------------------*/ +/* assignResultValue - */ +/*-----------------------------------------------------------------*/ +static void +assignResultValue (operand * oper) +{ + int size = AOP_SIZE (oper); + int offset = 0; + + FENTRY; + + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + + DEBUGpic14_AopType (__LINE__, oper, NULL, NULL); + + /* assign MSB first (passed via WREG) */ + while (size--) + { + get_returnvalue (oper, size, offset + GpseudoStkPtr); + GpseudoStkPtr++; + } +} + + +/*-----------------------------------------------------------------*/ +/* genIpush - genrate code for pushing this gets a little complex */ +/*-----------------------------------------------------------------*/ +static void +genIpush (iCode * ic) +{ + FENTRY; + + DEBUGpic14_emitcode ("; ***", "%s %d - WARNING no code generated", __FUNCTION__, __LINE__); +#if 0 + int size, offset = 0; + char *l; + + + /* 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"; + } + pic14_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); + + /* 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")) + { + pic14_emitcode ("mov", "a,%s", l); + pic14_emitcode ("push", "acc"); + } + else + pic14_emitcode ("push", "%s", l); + } + + freeAsmop (IC_LEFT (ic), NULL, ic, TRUE); +#endif +} + +/*-----------------------------------------------------------------*/ +/* genIpop - recover the registers: can happen only for spilling */ +/*-----------------------------------------------------------------*/ +static void +genIpop (iCode * ic) +{ + FENTRY; + + DEBUGpic14_emitcode ("; ***", "%s %d - WARNING no code generated", __FUNCTION__, __LINE__); + assert (!"genIpop -- unimplemented"); +#if 0 + int size, offset; + + + /* if the temp was not pushed then */ + if (OP_SYMBOL (IC_LEFT (ic))->isspilt) + return; + + aopOp (IC_LEFT (ic), ic, FALSE); + size = AOP_SIZE (IC_LEFT (ic)); + offset = (size - 1); + while (size--) + pic14_emitcode ("pop", "%s", aopGet (AOP (IC_LEFT (ic)), offset--, FALSE, TRUE)); + + freeAsmop (IC_LEFT (ic), NULL, ic, TRUE); +#endif +} + +/*-----------------------------------------------------------------*/ +/* unsaverbank - restores the resgister bank from stack */ +/*-----------------------------------------------------------------*/ +static void +unsaverbank (int bank, iCode * ic, bool popPsw) +{ + FENTRY; + + DEBUGpic14_emitcode ("; ***", "%s %d - WARNING no code generated", __FUNCTION__, __LINE__); +#if 0 + int i; + asmop *aop; + regs *r = NULL; + + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + if (popPsw) + { + if (options.useXstack) + { + aop = newAsmop (0); + r = getFreePtr (ic, &aop, FALSE); + + + pic14_emitcode ("mov", "%s,_spx", r->name); + pic14_emitcode ("movx", "a,@%s", r->name); + pic14_emitcode ("mov", "psw,a"); + pic14_emitcode ("dec", "%s", r->name); + + } + else + pic14_emitcode ("pop", "psw"); + } + + for (i = (pic14_nRegs - 1); i >= 0; i--) + { + if (options.useXstack) + { + pic14_emitcode ("movx", "a,@%s", r->name); + //pic14_emitcode("mov","(%s+%d),a", + // regspic14[i].base,8*bank+regspic14[i].offset); + pic14_emitcode ("dec", "%s", r->name); + + } + else + pic14_emitcode ("pop", ""); //"(%s+%d)", + //regspic14[i].base,8*bank); //+regspic14[i].offset); + } + + if (options.useXstack) + { + + pic14_emitcode ("mov", "_spx,%s", r->name); + freeAsmop (NULL, aop, ic, TRUE); + + } +#endif +} + +/*-----------------------------------------------------------------*/ +/* genCall - generates a call statement */ +/*-----------------------------------------------------------------*/ +static void +genCall (iCode * ic) +{ + sym_link *dtype; + symbol *sym; + char *name; + int isExtern; + + FENTRY; + + DEBUGpic14_emitcode ("; ***", "%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 */ + dtype = operandType (IC_LEFT (ic)); + if (currFunc && dtype && + (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) && IFFUNC_ISISR (currFunc->type) && !ic->bankSaved) + + saverbank (FUNC_REGBANK (dtype), ic, TRUE); + + /* if send set is not empty the assign */ + if (_G.sendSet) + { + iCode *sic; + /* For the Pic port, there is no data stack. + * So parameters passed to functions are stored + * in registers. (The pCode optimizer will get + * rid of most of these :). + */ + int pseudoStkPtr = -1; + int firstTimeThruLoop = 1; + + _G.sendSet = reverseSet (_G.sendSet); + + /* First figure how many parameters are getting passed */ + for (sic = setFirstItem (_G.sendSet); sic; sic = setNextItem (_G.sendSet)) + { + + aopOp (IC_LEFT (sic), sic, FALSE); + pseudoStkPtr += AOP_SIZE (IC_LEFT (sic)); + freeAsmop (IC_LEFT (sic), NULL, sic, FALSE); + } + + 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--) + { + DEBUGpic14_emitcode ("; ", "%d left %s", __LINE__, AopType (AOP_TYPE (IC_LEFT (sic)))); + + if (!firstTimeThruLoop) + { + /* If this is not the first time we've been through the loop + * then we need to save the parameter in a temporary + * register. The last byte of the last parameter is + * passed in W. */ + emitpcode (POC_MOVWF, popRegFromIdx (Gstack_base_addr - --pseudoStkPtr)); + + } + firstTimeThruLoop = 0; + + mov2w_op (IC_LEFT (sic), offset); + offset++; + } + freeAsmop (IC_LEFT (sic), NULL, sic, TRUE); + } + _G.sendSet = NULL; + } + /* make the call */ + sym = OP_SYMBOL (IC_LEFT (ic)); + name = sym->rname[0] ? sym->rname : sym->name; + /* + * As SDCC emits code as soon as it reaches the end of each + * function's definition, prototyped functions that are implemented + * after the current one are always considered EXTERN, which + * introduces many unneccessary PAGESEL instructions. + * XXX: Use a post pass to iterate over all `CALL _name' statements + * and insert `PAGESEL _name' and `PAGESEL $' around the CALL + * only iff there is no definition of the function in the whole + * file (might include this in the PAGESEL pass). + */ + isExtern = IS_EXTERN (sym->etype) || pic14_inISR; +#if 0 + if (isExtern) + { + /* Extern functions and ISRs maybe on a different page; + * must call pagesel */ +#endif + emitpcode (POC_PAGESEL, popGetWithString (name, 1)); +#if 0 + } +#endif + + emitpcode (POC_CALL, popGetWithString (name, isExtern)); +#if 0 + if (isExtern) + { + /* May have returned from a different page; + * must use pagesel to restore PCLATH before next + * goto or call instruction */ +#endif + emitpcode (POC_PAGESEL, popGetWithString ("$", 0)); +#if 0 + } +#endif + GpseudoStkPtr = 0; + /* 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)); + + DEBUGpic14_emitcode ("; ", "%d left %s", __LINE__, AopType (AOP_TYPE (IC_RESULT (ic)))); + + freeAsmop (IC_RESULT (ic), NULL, ic, TRUE); + } + + /* if register bank was saved then pop them */ + if (ic->bankSaved) + unsaverbank (FUNC_REGBANK (dtype), ic, TRUE); + + /* if we hade saved some registers then unsave them */ + if (ic->regsSaved && !IFFUNC_CALLEESAVES (dtype)) + unsaveRegisters (ic); +} + +/*-----------------------------------------------------------------*/ +/* genPcall - generates a call by pointer statement */ +/*-----------------------------------------------------------------*/ +static void +genPcall (iCode * ic) +{ + sym_link *dtype; + symbol *albl = newiTempLabel (NULL); + symbol *blbl = newiTempLabel (NULL); + PIC_OPCODE poc; + pCodeOp *pcop; + operand *left; + + FENTRY; + + DEBUGpic14_emitcode ("; ***", "%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 */ + dtype = operandType (IC_LEFT (ic)); + if (currFunc && dtype && IFFUNC_ISISR (currFunc->type) && (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype))) + saverbank (FUNC_REGBANK (dtype), ic, TRUE); + + left = IC_LEFT (ic); + aopOp (left, ic, FALSE); + DEBUGpic14_AopType (__LINE__, left, NULL, NULL); + + poc = (op_isLitLike (IC_LEFT (ic)) ? POC_MOVLW : POC_MOVFW); + + pushSide (IC_LEFT (ic), FARPTRSIZE); + + /* if send set is not empty, assign parameters */ + if (_G.sendSet) + { + DEBUGpic14_emitcode ("; ***", "%s %d - WARNING arg-passing to indirect call not supported", __FUNCTION__, __LINE__); + /* no way to pass args - W always gets used to make the call */ + } + /* first idea - factor out a common helper function and call it. + But don't know how to get it generated only once in its own block + + if(AOP_TYPE(IC_LEFT(ic)) == AOP_DIR) { + char *rname; + char *buffer; + size_t len; + + rname = IC_LEFT(ic)->aop->aopu.aop_dir; + DEBUGpic14_emitcode ("; ***","%s %d AOP_DIR %s",__FUNCTION__,__LINE__,rname); + len = strlen(rname) + 16; + buffer = Safe_alloc(len); + SNPRINTF(buffer, len, "%s_goto_helper", rname); + addpCode2pBlock(pb,newpCode(POC_CALL,newpCodeOp(buffer,PO_STR))); + free(buffer); + } + */ + emitpcode (POC_CALL, popGetLabel (albl->key)); + pcop = popGetLabel (blbl->key); + emitpcode (POC_PAGESEL, pcop); /* Must restore PCLATH before goto, without destroying W */ + emitpcode (POC_GOTO, pcop); + emitpLabel (albl->key); + + emitpcode (poc, popGetAddr (AOP (left), 1, 0)); + emitpcode (POC_MOVWF, popCopyReg (&pc_pclath)); + emitpcode (poc, popGetAddr (AOP (left), 0, 0)); + emitpcode (POC_MOVWF, popCopyReg (&pc_pcl)); + + emitpLabel (blbl->key); + + freeAsmop (IC_LEFT (ic), NULL, ic, TRUE); + + /* if we need to 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--; + + GpseudoStkPtr = 0; + + assignResultValue (IC_RESULT (ic)); + + freeAsmop (IC_RESULT (ic), NULL, ic, TRUE); + } + + /* if register bank was saved then unsave them */ + if (currFunc && dtype && (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype))) + unsaverbank (FUNC_REGBANK (dtype), 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) +{ + // DEBUGpic14_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + FENTRY; + + 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; +} + +/*-----------------------------------------------------------------*/ +/* genFunction - generated code for function entry */ +/*-----------------------------------------------------------------*/ +static void +genFunction (iCode * ic) +{ + symbol *sym; + sym_link *ftype; + + FENTRY; + + DEBUGpic14_emitcode ("; ***", "%s %d curr label offset=%dprevious max_key=%d ", __FUNCTION__, __LINE__, labelOffset, + max_key); + + labelOffset += (max_key + 4); + max_key = 0; + GpseudoStkPtr = 0; + _G.nRegsSaved = 0; + /* create the function header */ + pic14_emitcode (";", "-----------------------------------------"); + pic14_emitcode (";", " function %s", (sym = OP_SYMBOL (IC_LEFT (ic)))->name); + pic14_emitcode (";", "-----------------------------------------"); + + /* prevent this symbol from being emitted as 'extern' */ + pic14_stringInSet (sym->rname, &pic14_localFunctions, 1); + + pic14_emitcode ("", "%s:", sym->rname); + addpCode2pBlock (pb, newpCodeFunction (moduleName, sym->rname, !IS_STATIC (sym->etype), IFFUNC_ISISR (sym->type))); + + /* mark symbol as NOT extern (even if it was declared so previously) */ + assert (IS_SPEC (sym->etype)); + SPEC_EXTR (sym->etype) = 0; + sym->cdef = 0; + if (!SPEC_OCLS (sym->etype)) + SPEC_OCLS (sym->etype) = code; + addSetIfnotP (&SPEC_OCLS (sym->etype)->syms, sym); + + ftype = operandType (IC_LEFT (ic)); + + /* here we need to generate the equates for the + register bank if required */ +#if 0 + if (FUNC_REGBANK (ftype) != rbank) + { + int i; + + rbank = FUNC_REGBANK (ftype); + for (i = 0; i < pic14_nRegs; i++) + { + if (strcmp (regspic14[i].base, "0") == 0) + pic14_emitcode ("", "%s = 0x%02x", regspic14[i].dname, 8 * rbank + regspic14[i].offset); + else + pic14_emitcode ("", "%s = %s + 0x%02x", regspic14[i].dname, regspic14[i].base, 8 * rbank + regspic14[i].offset); + } + } +#endif + + /* if this is an interrupt service routine */ + pic14_inISR = 0; + if (IFFUNC_ISISR (sym->type)) + { + pic14_inISR = 1; + + /* generate ISR prolog if and not naked */ + if (!IFFUNC_ISNAKED (sym->type)) + { + if (pic->isEnhancedCore) + { + /* + * Enhanced CPUs have automatic context saving for W, + * STATUS, BSR, FSRx, and PCLATH in shadow registers. + */ + emitpcode (POC_CLRF, popCopyReg (&pc_pclath)); + } + else + { + emitpcode (POC_MOVWF, popCopyReg (&pc_wsave)); + emitpcode (POC_SWAPFW, popCopyReg (&pc_status)); + /* XXX: Why? Does this assume that ssave and psave reside + * in a shared bank or bank0? We cannot guarantee the + * latter... + */ + emitpcode (POC_CLRF, popCopyReg (&pc_status)); + emitpcode (POC_MOVWF, popCopyReg (&pc_ssave)); + //emitpcode(POC_MOVWF, popGetExternal("___sdcc_saved_status",1 )); + emitpcode (POC_MOVFW, popCopyReg (&pc_pclath)); + /* during an interrupt PCLATH must be cleared before a goto or call statement */ + emitpcode (POC_CLRF, popCopyReg (&pc_pclath)); + emitpcode (POC_MOVWF, popCopyReg (&pc_psave)); + //emitpcode(POC_MOVWF, popGetExternal("___sdcc_saved_pclath", 1)); + emitpcode (POC_MOVFW, popCopyReg (&pc_fsr)); + emitpcode (POC_MOVWF, popGetExternal ("___sdcc_saved_fsr", 1)); + } + } + + pBlockConvert2ISR (pb); + pic14_hasInterrupt = 1; + } + else + { + /* if callee-save to be used for this function + then save the registers being used in this function */ + if (IFFUNC_CALLEESAVES (sym->type)) + { + 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_emitcode("push","%s",pic14_regWithIdx(i)->dname); + _G.nRegsSaved++; + } + } + } + } + } + + /* if critical function then turn interrupts off */ + if (IFFUNC_ISCRITICAL (ftype)) + { + genCritical (NULL); + if (IFFUNC_ARGS (sym->type)) + { + fprintf (stderr, "PIC14: Functions with __critical (%s) must not have arguments for now.\n", sym->name); + exit (1); + } // if + } // if + + /* set the register bank to the desired value */ + if (FUNC_REGBANK (sym->type) || FUNC_ISISR (sym->type)) + { + pic14_emitcode ("push", "psw"); + pic14_emitcode ("mov", "psw,#0x%02x", (FUNC_REGBANK (sym->type) << 3) & 0x00ff); + } + + if (IFFUNC_ISREENT (sym->type) || options.stackAuto) + { + + if (options.useXstack) + { + pic14_emitcode ("mov", "r0,%s", spname); + pic14_emitcode ("mov", "a,_bp"); + pic14_emitcode ("movx", "@r0,a"); + pic14_emitcode ("inc", "%s", spname); + } + else + { + /* set up the stack */ + pic14_emitcode ("push", "_bp"); /* save the callers stack */ + } + pic14_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) + { + + pic14_emitcode ("mov", "a,sp"); + pic14_emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff)); + pic14_emitcode ("mov", "sp,a"); + + } + else + while (i--) + pic14_emitcode ("inc", "sp"); + } + + if (sym->xstack) + { + + pic14_emitcode ("mov", "a,_spx"); + pic14_emitcode ("add", "a,#0x%02x", ((char) sym->xstack & 0xff)); + pic14_emitcode ("mov", "_spx,a"); + } + +} + +/*-----------------------------------------------------------------*/ +/* genEndFunction - generates epilogue for functions */ +/*-----------------------------------------------------------------*/ +static void +genEndFunction (iCode * ic) +{ + symbol *sym = OP_SYMBOL (IC_LEFT (ic)); + + FENTRY; + + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + + if (IFFUNC_ISREENT (sym->type) || options.stackAuto) + { + pic14_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) + { + pic14_emitcode ("mov", "a,sp"); + pic14_emitcode ("add", "a,#0x%02x", ((char) - sym->stack) & 0xff); + pic14_emitcode ("mov", "sp,a"); + } + + + if ((IFFUNC_ISREENT (sym->type) || options.stackAuto)) + { + if (options.useXstack) + { + pic14_emitcode ("mov", "r0,%s", spname); + pic14_emitcode ("movx", "a,@r0"); + pic14_emitcode ("mov", "_bp,a"); + pic14_emitcode ("dec", "%s", spname); + } + else + { + pic14_emitcode ("pop", "_bp"); + } + } + + /* restore the register bank */ + if (FUNC_REGBANK (sym->type) || FUNC_ISISR (sym->type)) + pic14_emitcode ("pop", "psw"); + + /* if critical function then turn interrupts off */ + if (IFFUNC_ISCRITICAL (sym->type)) + { + genEndCritical (NULL); + } // if + + if (IFFUNC_ISISR (sym->type)) + { + + /* 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 (!FUNC_REGBANK (sym->type)) + { + + /* if this function does not call any other + function then we can be economical and + save only those registers that are used */ + if (!IFFUNC_HASFCALL (sym->type)) + { + 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_emitcode ("pop", "junk"); //"%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 debug then send end of function */ + if (options.debug && debugFile && currFunc) + { + debugFile->writeEndFunction (currFunc, ic, 1); + } + + /* generate ISR epilog if not enhanced core and not naked */ + if (!pic->isEnhancedCore && !IFFUNC_ISNAKED (sym->type)) + { + emitpcode (POC_MOVFW, popGetExternal ("___sdcc_saved_fsr", 1)); + emitpcode (POC_MOVWF, popCopyReg (&pc_fsr)); + //emitpcode(POC_MOVFW, popGetExternal("___sdcc_saved_pclath", 1)); + emitpcode (POC_MOVFW, popCopyReg (&pc_psave)); + emitpcode (POC_MOVWF, popCopyReg (&pc_pclath)); + emitpcode (POC_CLRF, popCopyReg (&pc_status)); // see genFunction + //emitpcode(POC_SWAPFW, popGetExternal("___sdcc_saved_status", 1)); + emitpcode (POC_SWAPFW, popCopyReg (&pc_ssave)); + emitpcode (POC_MOVWF, popCopyReg (&pc_status)); + emitpcode (POC_SWAPF, popCopyReg (&pc_wsave)); + emitpcode (POC_SWAPFW, popCopyReg (&pc_wsave)); + } + addpCode2pBlock (pb, newpCodeLabel ("END_OF_INTERRUPT", -1)); + emitpcodeNULLop (POC_RETFIE); + } + else + { + if (IFFUNC_ISCRITICAL (sym->type)) + pic14_emitcode ("setb", "ea"); + + if (IFFUNC_CALLEESAVES (sym->type)) + { + 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_emitcode ("pop", "junk"); //"%s",pic14_regWithIdx(i)->dname); + } + } + } + } + + /* if debug then send end of function */ + if (options.debug && debugFile && currFunc) + { + debugFile->writeEndFunction (currFunc, ic, 1); + } + + pic14_emitcode ("return", ""); + emitpcodeNULLop (POC_RETURN); + + /* Mark the end of a function */ + addpCode2pBlock (pb, newpCodeFunction (moduleName, NULL, 0, 0)); + } + +} + +/*-----------------------------------------------------------------*/ +/* genRet - generate code for return statement */ +/*-----------------------------------------------------------------*/ +static void +genRet (iCode * ic) +{ + int size, offset = 0; + + FENTRY; + + DEBUGpic14_emitcode ("; ***", "%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)); + + for (offset = 0; offset < size; offset++) + { + pass_argument (IC_LEFT (ic), offset, size - 1 - offset); + } + + 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)) + { + + emitpcode (POC_GOTO, popGetLabel (returnLabel->key)); + } + +} + +static set *critical_temps = NULL; + +static void +genCritical (iCode * ic) +{ + pCodeOp *saved_intcon; + + (void) ic; + + if (!critical_temps) + critical_temps = newSet (); + + saved_intcon = popGetTempReg (); + addSetHead (&critical_temps, saved_intcon); + + /* This order saves one BANKSEL back to INTCON. */ + emitpcode (POC_MOVFW, popCopyReg (&pc_intcon)); + emitpcode (POC_BCF, popCopyGPR2Bit (popCopyReg (&pc_intcon), 7)); + emitpcode (POC_MOVWF, pCodeOpCopy (saved_intcon)); +} + +static void +genEndCritical (iCode * ic) +{ + pCodeOp *saved_intcon = NULL; + + (void) ic; + + saved_intcon = getSet (&critical_temps); + if (!saved_intcon) + { + fprintf (stderr, "Critical section left, but none entered -- ignoring for now.\n"); + return; + } // if + + emitpcode (POC_BTFSC, popCopyGPR2Bit (pCodeOpCopy (saved_intcon), 7)); + emitpcode (POC_BSF, popCopyGPR2Bit (popCopyReg (&pc_intcon), 7)); + popReleaseTempReg (saved_intcon); +} + +/*-----------------------------------------------------------------*/ +/* genLabel - generates a label */ +/*-----------------------------------------------------------------*/ +static void +genLabel (iCode * ic) +{ + FENTRY; + + /* special case never generate */ + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + if (IC_LABEL (ic) == entryLabel) + return; + + emitpLabel (IC_LABEL (ic)->key); + pic14_emitcode ("", "_%05d_DS_:", labelKey2num (IC_LABEL (ic)->key + labelOffset)); +} + +/*-----------------------------------------------------------------*/ +/* genGoto - generates a goto */ +/*-----------------------------------------------------------------*/ +//tsd +static void +genGoto (iCode * ic) +{ + FENTRY; + + emitpcode (POC_GOTO, popGetLabel (IC_LABEL (ic)->key)); + pic14_emitcode ("goto", "_%05d_DS_", labelKey2num (IC_LABEL (ic)->key + labelOffset)); +} + + +/*-----------------------------------------------------------------*/ +/* genMultbits :- multiplication of bits */ +/*-----------------------------------------------------------------*/ +static void +genMultbits (operand * left, operand * right, operand * result) +{ + FENTRY; + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + + if (!pic14_sameRegs (AOP (result), AOP (right))) + emitpcode (POC_BSF, popGet (AOP (result), 0)); + + emitpcode (POC_BTFSC, popGet (AOP (right), 0)); + emitpcode (POC_BTFSS, popGet (AOP (left), 0)); + emitpcode (POC_BCF, popGet (AOP (result), 0)); + +} + + +/*-----------------------------------------------------------------*/ +/* genMultOneByte : 8 bit multiplication & division */ +/*-----------------------------------------------------------------*/ +static void +genMultOneByte (operand * left, operand * right, operand * result) +{ + char *func[] = { NULL, "__mulchar", "__mulint", NULL, "__mullong" }; + + // symbol *lbl ; + int size, offset, i; + + + FENTRY; + + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + DEBUGpic14_AopType (__LINE__, left, right, result); + DEBUGpic14_AopTypeSign (__LINE__, left, right, result); + + /* (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; + } + + assert (AOP_SIZE (left) == AOP_SIZE (right)); + + size = min (AOP_SIZE (result), AOP_SIZE (left)); + offset = Gstack_base_addr - (2 * size - 1); + + /* pass right operand as argument */ + for (i = 0; i < size; i++) + { + mov2w (AOP (right), i); + emitpcode (POC_MOVWF, popRegFromIdx (++offset)); + } // for + + /* pass left operand as argument */ + for (i = 0; i < size; i++) + { + mov2w (AOP (left), i); + if (i != size - 1) + emitpcode (POC_MOVWF, popRegFromIdx (++offset)); + } // for + assert (offset == Gstack_base_addr); + + /* call library routine */ + assert (size > 0 && size <= 4); + call_libraryfunc (func[size]); + + /* assign result */ + movwf (AOP (result), size - 1); + for (i = 0; i < size - 1; i++) + { + emitpcode (POC_MOVFW, popRegFromIdx (Gstack_base_addr - i)); + movwf (AOP (result), size - 2 - i); + } // for + + /* now (zero-/sign) extend the result to its size */ + addSign (result, AOP_SIZE (left), !SPEC_USIGN (operandType (result))); +} + +/*-----------------------------------------------------------------*/ +/* 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); + + FENTRY; + + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + /* assign the amsops */ + aopOp (left, ic, FALSE); + aopOp (right, ic, FALSE); + aopOp (result, ic, TRUE); + + DEBUGpic14_AopType (__LINE__, left, right, result); + + /* 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 (0); + +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; + + FENTRY; + + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + /* the result must be bit */ + pic14_emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE)); + l = aopGet (AOP (left), 0, FALSE, FALSE); + + MOVA (l); + + pic14_emitcode ("div", "ab"); + pic14_emitcode ("rrc", "a"); + aopPut (AOP (result), "c", 0); +} + +/*-----------------------------------------------------------------*/ +/* genDivOneByte : 8 bit division */ +/*-----------------------------------------------------------------*/ +static void +genDivOneByte (operand * left, operand * right, operand * result) +{ + int sign; + + FENTRY; + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + + assert (AOP_SIZE (right) == 1); + assert (AOP_SIZE (left) == 1); + + sign = !(SPEC_USIGN (operandType (left)) && SPEC_USIGN (operandType (right))); + + if (AOP_TYPE (right) == AOP_LIT) + { + /* XXX: might add specialized code */ + } + + if (!sign) + { + /* unsigned division */ +#if 1 + mov2w (AOP (right), 0); + emitpcode (POC_MOVWF, popRegFromIdx (Gstack_base_addr)); + mov2w (AOP (left), 0); + call_libraryfunc ("__divuchar"); + movwf (AOP (result), 0); +#else + pCodeOp *temp; + symbol *lbl; + + temp = popGetTempReg (); + lbl = newiTempLabel (NULL); + + /* XXX: improve this naive approach: + [result] = [a] / [b] + ::= [result] = 0; while ([a] > [b]) do [a] -= [b]; [result]++ done + + In PIC assembler: + movf left,W + movwf temp // temp <-- left + movf right,W // W <-- right + clrf result + label1: + incf result + subwf temp,F // temp <-- temp - W + skipNC // subwf clears CARRY (i.e. sets BORROW) if temp < W + goto label1 + decf result // we just subtract once too often + */ + + /* XXX: This loops endlessly on DIVIDE BY ZERO */ + /* We need 1..128 iterations of the loop body (`4 / 5' .. `255 / 2'). */ + + mov2w (AOP (left), 0); + emitpcode (POC_MOVWF, temp); + mov2w (AOP (right), 0); + emitpcode (POC_CLRF, popGet (AOP (result), 0)); + + emitpLabel (lbl->key); + emitpcode (POC_INCF, popGet (AOP (result), 0)); + emitpcode (POC_SUBWF, temp); + emitSKPNC; + + if (pic->isEnhancedCore) + { + emitpcode (POC_BRA, popGetLabel (lbl->key)); + } + else + { + emitpcode (POC_GOTO, popGetLabel (lbl->key)); + } + + emitpcode (POC_DECF, popGet (AOP (result), 0)); + popReleaseTempReg (temp); +#endif + } + else + { + /* signed division */ + mov2w (AOP (right), 0); + emitpcode (POC_MOVWF, popRegFromIdx (Gstack_base_addr)); + mov2w (AOP (left), 0); + call_libraryfunc ("__divschar"); + movwf (AOP (result), 0); + } + + /* now performed the signed/unsigned division -- extend result */ + addSign (result, 1, sign); +} + +/*-----------------------------------------------------------------*/ +/* 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); + + FENTRY; + DEBUGpic14_emitcode ("; ***", "%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 (0); +release: + freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + freeAsmop (result, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genModOneByte : 8 bit modulus */ +/*-----------------------------------------------------------------*/ +static void +genModOneByte (operand * left, operand * right, operand * result) +{ + int sign; + + FENTRY; + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + + assert (AOP_SIZE (right) == 1); + assert (AOP_SIZE (left) == 1); + + sign = !(SPEC_USIGN (operandType (left)) && SPEC_USIGN (operandType (right))); + + if (AOP_TYPE (right) == AOP_LIT) + { + /* XXX: might add specialized code */ + } + + if (!sign) + { + /* unsigned division */ +#if 1 + mov2w (AOP (right), 0); + emitpcode (POC_MOVWF, popRegFromIdx (Gstack_base_addr)); + mov2w (AOP (left), 0); + call_libraryfunc ("__moduchar"); + movwf (AOP (result), 0); +#else + pCodeOp *temp; + symbol *lbl; + + lbl = newiTempLabel (NULL); + + assert (!pic14_sameRegs (AOP (right), AOP (result))); + + /* XXX: improve this naive approach: + [result] = [a] % [b] + ::= [result] = [a]; while ([result] > [b]) do [result] -= [b]; done + + In PIC assembler: + movf left,W + movwf result // result <-- left + movf right,W // W <-- right + label1: + subwf result,F // result <-- result - W + skipNC // subwf clears CARRY (i.e. sets BORROW) if result < W + goto label1 + addwf result, F // we just subtract once too often + */ + + /* XXX: This loops endlessly on DIVIDE BY ZERO */ + /* We need 1..128 iterations of the loop body (`4 % 5' .. `255 % 2'). */ + + if (!pic14_sameRegs (AOP (left), AOP (result))) + { + mov2w (AOP (left), 0); + emitpcode (POC_MOVWF, popGet (AOP (result), 0)); + } + mov2w (AOP (right), 0); + + emitpLabel (lbl->key); + emitpcode (POC_SUBWF, popGet (AOP (result), 0)); + emitSKPNC; + + if (pic->isEnhancedCore) + { + emitpcode (POC_BRA, popGetLabel (lbl->key)); + } + else + { + emitpcode (POC_GOTO, popGetLabel (lbl->key)); + } + + emitpcode (POC_ADDWF, popGet (AOP (result), 0)); +#endif + } + else + { + /* signed division */ + mov2w (AOP (right), 0); + emitpcode (POC_MOVWF, popRegFromIdx (Gstack_base_addr)); + mov2w (AOP (left), 0); + call_libraryfunc ("__modschar"); + movwf (AOP (result), 0); + } + + /* now we performed the signed/unsigned modulus -- extend result */ + addSign (result, 1, sign); +} + +/*-----------------------------------------------------------------*/ +/* 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); + + FENTRY; + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + /* assign the amsops */ + aopOp (left, ic, FALSE); + aopOp (right, ic, FALSE); + aopOp (result, ic, TRUE); + + /* 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 (0); + +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 */ +/*-----------------------------------------------------------------*/ +/* +note: May need to add parameter to indicate when a variable is in bit space. +*/ +static void +genIfxJump (iCode * ic, char *jval) +{ + + FENTRY; + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + /* if true label then we jump if condition + supplied is true */ + if (IC_TRUE (ic)) + { + + if (strcmp (jval, "a") == 0) + emitSKPZ; + else if (strcmp (jval, "c") == 0) + emitSKPC; + else + { + DEBUGpic14_emitcode ("; ***", "%d - assuming %s is in bit space", __LINE__, jval); + emitpcode (POC_BTFSC, newpCodeOpBit (jval, -1, 1)); + } + + emitpcode (POC_GOTO, popGetLabel (IC_TRUE (ic)->key)); + pic14_emitcode (" goto", "_%05d_DS_", labelKey2num (IC_TRUE (ic)->key + labelOffset)); + + } + else + { + /* false label is present */ + if (strcmp (jval, "a") == 0) + emitSKPNZ; + else if (strcmp (jval, "c") == 0) + emitSKPNC; + else + { + DEBUGpic14_emitcode ("; ***", "%d - assuming %s is in bit space", __LINE__, jval); + emitpcode (POC_BTFSS, newpCodeOpBit (jval, -1, 1)); + } + + emitpcode (POC_GOTO, popGetLabel (IC_FALSE (ic)->key)); + pic14_emitcode (" goto", "_%05d_DS_", labelKey2num (IC_FALSE (ic)->key + labelOffset)); + + } + + + /* mark the icode as generated */ + ic->generated = TRUE; +} + +/*-----------------------------------------------------------------*/ +/* genSkipc */ +/*-----------------------------------------------------------------*/ +static void +genSkipc (resolvedIfx * rifx) +{ + FENTRY; + if (!rifx) + return; + + if (rifx->condition) + emitSKPNC; + else + emitSKPC; + + emitpcode (POC_GOTO, popGetLabel (rifx->lbl->key)); + emitpComment ("%s:%u: created from rifx:%p", __FUNCTION__, __LINE__, rifx); + rifx->generated = TRUE; +} + +#define isAOP_REGlike(x) (AOP_TYPE(x) == AOP_REG || AOP_TYPE(x) == AOP_DIR || AOP_TYPE(x) == AOP_PCODE) +#define isAOP_LIT(x) (AOP_TYPE(x) == AOP_LIT) +#define DEBUGpc emitpComment + +/*-----------------------------------------------------------------*/ +/* mov2w_regOrLit :- move to WREG either the offset's byte from */ +/* aop (if it's NOT a literal) or from lit (if */ +/* aop is a literal) */ +/*-----------------------------------------------------------------*/ +static void +pic14_mov2w_regOrLit (asmop * aop, unsigned long lit, int offset) +{ + if (aop->type == AOP_LIT) + { + emitpcode (POC_MOVLW, popGetLit ((lit >> (offset * 8)) & 0x00FF)); + } + else + { + emitpcode (POC_MOVFW, popGet (aop, offset)); + } +} + +/* genCmp performs a left < right comparison, stores + * the outcome in result (if != NULL) and generates + * control flow code for the ifx (if != NULL). + * + * This version leaves in sequences like + * "B[CS]F STATUS,0; BTFS[CS] STATUS,0" + * which should be optmized by the peephole + * optimizer - RN 2005-01-01 */ +static void +genCmp (operand * left, operand * right, operand * result, iCode * ifx, int sign) +{ + resolvedIfx rIfx; + int size; + int offs; + symbol *templbl; + operand *dummy; + unsigned long lit; + unsigned long mask; + int performedLt; + int invert_result = 0; + + FENTRY; + + assert (AOP_SIZE (left) == AOP_SIZE (right)); + assert (left && right); + + size = AOP_SIZE (right) - 1; + mask = (0x100UL << (size * 8)) - 1; + // in the end CARRY holds "left < right" (performedLt == 1) or "left >= right" (performedLt == 0) + performedLt = 1; + templbl = NULL; + lit = 0; + + resolveIfx (&rIfx, ifx); + + /********************************************************************** + * handle bits - bit compares are promoted to int compares seemingly! * + **********************************************************************/ +#if 0 + // THIS IS COMPLETELY UNTESTED! + if (AOP_TYPE (left) == AOP_CRY && AOP_TYPE (right) == AOP_CRY) + { + pCodeOp *pcleft = pic16_popGet (AOP (left), 0); + pCodeOp *pcright = pic16_popGet (AOP (right), 0); + assert (pcleft->type == PO_GPR_BIT && pcright->type == PO_GPR_BIT); + + emitSETC; + // 1 < {0,1} is false --> clear C by skipping the next instruction + //pic16_emitpcode (POC_BTFSS, pic16_popCopyGPR2Bit (AOP (left),0), PCORB (pcleft)->bit); + pic16_emitpcode (POC_BTFSS, pic16_popGet (AOP (left), 0)); + // {0,1} < 0 is false --> clear C by NOT skipping the next instruction + pic16_emitpcode (POC_BTFSS, pic16_popCopyGPR2Bit (pic16_popGet (AOP (right), 0), PCORB (pcright)->bit)); + emitCLRC; // only skipped for left=0 && right=1 + + goto correct_result_in_carry; + } // if +#endif + + /************************************************* + * make sure that left is register (or the like) * + *************************************************/ + if (!isAOP_REGlike (left)) + { + DEBUGpc ("swapping arguments (AOP_TYPEs %d/%d)", AOP_TYPE (left), AOP_TYPE (right)); + assert (isAOP_LIT (left)); + assert (isAOP_REGlike (right)); + // swap left and right + // left < right <==> right > left <==> (right >= left + 1) + lit = ulFromVal (AOP (left)->aopu.aop_lit); + + if ((!sign && (lit & mask) == mask) || (sign && (lit & mask) == (mask >> 1))) + { + // MAXVALUE < right? always false + if (performedLt) + emitCLRC; + else + emitSETC; + goto correct_result_in_carry; + } // if + + // This fails for lit = 0xFF (unsigned) AND lit = 0x7F (signed), + // that's why we handled it above. + lit++; + + dummy = left; + left = right; + right = dummy; + + performedLt ^= 1; // instead of "left < right" we check for "right >= left+1, i.e. "right < left+1" + } + else if (isAOP_LIT (right)) + { + lit = ulFromVal (AOP (right)->aopu.aop_lit); + } // if + + assert (isAOP_REGlike (left)); // left must be register or the like + assert (isAOP_REGlike (right) || isAOP_LIT (right)); // right may be register-like or a literal + + /************************************************* + * special cases go here * + *************************************************/ + + if (isAOP_LIT (right)) + { + if (!sign) + { + // unsigned comparison to a literal + DEBUGpc ("unsigned compare: left %s lit(0x%X=%lu), size=%d", performedLt ? "<" : ">=", lit, lit, size + 1); + if (lit == 0) + { + // unsigned left < 0? always false + if (performedLt) + emitCLRC; + else + emitSETC; + goto correct_result_in_carry; + } + } + else + { + // signed comparison to a literal + DEBUGpc ("signed compare: left %s lit(0x%X=%ld), size=%d, mask=%x", performedLt ? "<" : ">=", lit, lit, size + 1, + mask); + if ((lit & mask) == ((0x80 << (size * 8)) & mask)) + { + // signed left < 0x80000000? always false + if (performedLt) + emitCLRC; + else + emitSETC; + goto correct_result_in_carry; + } + else if (lit == 0) + { + // compare left < 0; set CARRY if SIGNBIT(left) is set + if (performedLt) + emitSETC; + else + emitCLRC; + emitpcode (POC_BTFSS, newpCodeOpBit (aopGet (AOP (left), size, FALSE, FALSE), 7, 0)); + if (performedLt) + emitCLRC; + else + emitSETC; + goto correct_result_in_carry; + } + } // if (!sign) + } // right is literal + + /************************************************* + * perform a general case comparison * + * make sure we get CARRY==1 <==> left >= right * + *************************************************/ + // compare most significant bytes + //DEBUGpc ("comparing bytes at offset %d", size); + if (!sign) + { + // unsigned comparison + pic14_mov2w_regOrLit (AOP (right), lit, size); + emitpcode (POC_SUBFW, popGet (AOP (left), size)); + } + else + { + // signed comparison + // (add 2^n to both operands then perform an unsigned comparison) + if (isAOP_LIT (right)) + { + // left >= LIT <-> LIT-left <= 0 <-> LIT-left == 0 OR !(LIT-left >= 0) + unsigned char litbyte = (lit >> (8 * size)) & 0xFF; + + if (litbyte == 0x80) + { + // left >= 0x80 -- always true, but more bytes to come + mov2w (AOP (left), size); + emitpcode (POC_XORLW, popGetLit (0x80)); // set ZERO flag + emitSETC; + } + else + { + // left >= LIT <-> left + (-LIT) >= 0 <-> left + (0x100-LIT) >= 0x100 + mov2w (AOP (left), size); + emitpcode (POC_ADDLW, popGetLit (0x80)); + emitpcode (POC_ADDLW, popGetLit ((0x100 - (litbyte + 0x80)) & 0x00FF)); + } // if + } + else + { + pCodeOp *pctemp = popGetTempReg (); + mov2w (AOP (left), size); + emitpcode (POC_ADDLW, popGetLit (0x80)); + emitpcode (POC_MOVWF, pctemp); + mov2w (AOP (right), size); + emitpcode (POC_ADDLW, popGetLit (0x80)); + emitpcode (POC_SUBFW, pctemp); + popReleaseTempReg (pctemp); + } + } // if (!sign) + + // compare remaining bytes (treat as unsigned case from above) + templbl = newiTempLabel (NULL); + offs = size; + while (offs--) + { + //DEBUGpc ("comparing bytes at offset %d", offs); + emitSKPZ; + + if (pic->isEnhancedCore) + { + emitpcode (POC_BRA, popGetLabel (templbl->key)); + } + else + { + emitpcode (POC_GOTO, popGetLabel (templbl->key)); + } + + pic14_mov2w_regOrLit (AOP (right), lit, offs); + emitpcode (POC_SUBFW, popGet (AOP (left), offs)); + } // while (offs) + emitpLabel (templbl->key); + goto result_in_carry; + +result_in_carry: + + /**************************************************** + * now CARRY contains the result of the comparison: * + * SUBWF sets CARRY iff * + * F-W >= 0 <==> F >= W <==> !(F < W) * + * (F=left, W=right) * + ****************************************************/ + + if (performedLt) + { + invert_result = 1; + // value will be used in the following genSkipc () + rIfx.condition ^= TRUE; + } // if + +correct_result_in_carry: + + // assign result to variable (if neccessary), but keep CARRY intact to be used below + if (result && AOP_TYPE (result) != AOP_CRY) + { + //DEBUGpc ("assign result"); + size = AOP_SIZE (result); + while (size--) + { + emitpcode (POC_CLRF, popGet (AOP (result), size)); + } // while + if (invert_result) + { + emitSKPC; + emitpcode (POC_BSF, newpCodeOpBit (aopGet (AOP (result), 0, FALSE, FALSE), 0, 0)); + } + else + { + emitpcode (POC_RLF, popGet (AOP (result), 0)); + if (ifx) + { + /* Result is expected to be in CARRY by genSkipc () below. */ + emitpcode (POC_RRFW, popGet (AOP (result), 0)); + } // if + } // if + } // if (result) + + // perform conditional jump + if (ifx) + { + //DEBUGpc ("generate control flow"); + genSkipc (&rIfx); + ifx->generated = TRUE; + } // if +} + +/*-----------------------------------------------------------------*/ +/* genCmpGt :- greater than comparison */ +/*-----------------------------------------------------------------*/ +static void +genCmpGt (iCode * ic, iCode * ifx) +{ + operand *left, *right, *result; + sym_link *letype, *retype; + int sign; + + FENTRY; + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + left = IC_LEFT (ic); + right = IC_RIGHT (ic); + result = IC_RESULT (ic); + + sign = 0; + if (IS_SPEC (operandType (left)) && IS_SPEC (operandType (right))) + { + 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; + sym_link *letype, *retype; + int sign; + + FENTRY; + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + left = IC_LEFT (ic); + right = IC_RIGHT (ic); + result = IC_RESULT (ic); + + sign = 0; + if (IS_SPEC (operandType (left)) && IS_SPEC (operandType (right))) + { + 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); +} + +/*-----------------------------------------------------------------*/ +/* genCmpEq - generates code for equal to */ +/*-----------------------------------------------------------------*/ +static void +genCmpEq (iCode * ic, iCode * ifx) +{ + operand *left, *right, *result; + int size; + symbol *false_label; + + FENTRY; + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + + if (ifx) + DEBUGpic14_emitcode ("; ifx is non-null", ""); + else + DEBUGpic14_emitcode ("; ifx is null", ""); + + aopOp ((left = IC_LEFT (ic)), ic, FALSE); + aopOp ((right = IC_RIGHT (ic)), ic, FALSE); + aopOp ((result = IC_RESULT (ic)), ic, TRUE); + + DEBUGpic14_AopType (__LINE__, left, right, result); + + /* if literal, move literal to right */ + if (op_isLitLike (IC_LEFT (ic))) + { + operand *tmp = right; + right = left; + left = tmp; + } + + false_label = NULL; + if (ifx && !IC_TRUE (ifx)) + { + assert (IC_FALSE (ifx)); + false_label = IC_FALSE (ifx); + } + + size = min (AOP_SIZE (left), AOP_SIZE (right)); + assert (!pic14_sameRegs (AOP (result), AOP (left))); + assert (!pic14_sameRegs (AOP (result), AOP (right))); + + /* assume left != right */ + { + int i; + for (i = 0; i < AOP_SIZE (result); i++) + { + emitpcode (POC_CLRF, popGet (AOP (result), i)); + } + } + + if (AOP_TYPE (right) == AOP_LIT) + { + unsigned long lit = ulFromVal (AOP (right)->aopu.aop_lit); + int i; + size = AOP_SIZE (left); + assert (!op_isLitLike (left)); + + switch (lit) + { + case 0: + mov2w (AOP (left), 0); + for (i = 1; i < size; i++) + emitpcode (POC_IORFW, popGet (AOP (left), i)); + /* now Z is set iff `left == right' */ + emitSKPZ; + if (!false_label) + false_label = newiTempLabel (NULL); + emitpcode (POC_GOTO, popGetLabel (false_label->key)); + break; + + default: + for (i = 0; i < size; i++) + { + mov2w (AOP (left), i); + emitpcode (POC_XORLW, popGetLit (lit >> (8 * i))); + /* now Z is cleared if `left != right' */ + emitSKPZ; + if (!false_label) + false_label = newiTempLabel (NULL); + emitpcode (POC_GOTO, popGetLabel (false_label->key)); + } // for i + break; + } // switch (lit) + } + else + { + /* right is no literal */ + int i; + + for (i = 0; i < size; i++) + { + mov2w (AOP (right), i); + emitpcode (POC_XORFW, popGet (AOP (left), i)); + /* now Z is cleared if `left != right' */ + emitSKPZ; + if (!false_label) + false_label = newiTempLabel (NULL); + emitpcode (POC_GOTO, popGetLabel (false_label->key)); + } // for i + } + + /* if we reach here, left == right */ + + if (AOP_SIZE (result) > 0) + { + emitpcode (POC_INCF, popGet (AOP (result), 0)); + } + + if (ifx && IC_TRUE (ifx)) + { + emitpcode (POC_GOTO, popGetLabel (IC_TRUE (ifx)->key)); + } + + if (false_label && (!ifx || IC_TRUE (ifx))) + emitpLabel (false_label->key); + + if (ifx) + ifx->generated = TRUE; + + freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + freeAsmop (result, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genAndOp - for && operation */ +/*-----------------------------------------------------------------*/ +static void +genAndOp (iCode * ic) +{ + operand *left, *right, *result; + /* symbol *tlbl; */ + + FENTRY; + DEBUGpic14_emitcode ("; ***", "%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); + + DEBUGpic14_AopType (__LINE__, left, right, result); + + emitpcode (POC_MOVFW, popGet (AOP (left), 0)); + emitpcode (POC_ANDFW, popGet (AOP (right), 0)); + emitpcode (POC_MOVWF, popGet (AOP (result), 0)); + + /* if both are bit variables */ + /* if (AOP_TYPE(left) == AOP_CRY && */ + /* AOP_TYPE(right) == AOP_CRY ) { */ + /* pic14_emitcode("mov","c,%s",AOP(left)->aopu.aop_dir); */ + /* pic14_emitcode("anl","c,%s",AOP(right)->aopu.aop_dir); */ + /* pic14_outBitC(result); */ + /* } else { */ + /* tlbl = newiTempLabel(NULL); */ + /* pic14_toBoolean(left); */ + /* pic14_emitcode("jz","%05d_DS_",labelKey2num (tlbl->key)); */ + /* pic14_toBoolean(right); */ + /* pic14_emitcode("","%05d_DS_:",labelKey2num (tlbl->key)); */ + /* pic14_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 */ +/*-----------------------------------------------------------------*/ +/* +tsd pic port - +modified this code, but it doesn't appear to ever get called +*/ + +static void +genOrOp (iCode * ic) +{ + operand *left, *right, *result; + symbol *tlbl; + int i; + + /* note here that || operations that are in an + if statement are taken away by backPatchLabels + only those used in arthmetic operations remain */ + FENTRY; + DEBUGpic14_emitcode ("; ***", "%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); + + DEBUGpic14_AopType (__LINE__, left, right, result); + + for (i = 0; i < AOP_SIZE (result); i++) + { + emitpcode (POC_CLRF, popGet (AOP (result), i)); + } // for i + + tlbl = newiTempLabel (NULL); + pic14_toBoolean (left); + emitSKPZ; + emitpcode (POC_GOTO, popGetLabel (tlbl->key)); + pic14_toBoolean (right); + emitpLabel (tlbl->key); + /* here Z is clear IFF `left || right' */ + emitSKPZ; + emitpcode (POC_INCF, popGet (AOP (result), 0)); + + 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; + + FENTRY; + DEBUGpic14_emitcode ("; ***", "%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) +{ + FENTRY; + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + if (IC_TRUE (ic)) + { + emitpcode (POC_GOTO, popGetLabel (labelKey2num (IC_TRUE (ic)->key))); + pic14_emitcode ("ljmp", "%05d_DS_", labelKey2num (IC_FALSE (ic)->key)); + } + ic->generated = TRUE; +} + +/*-----------------------------------------------------------------*/ +/* jmpIfTrue - */ +/*-----------------------------------------------------------------*/ +static void +jumpIfTrue (iCode * ic) +{ + FENTRY; + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + if (!IC_TRUE (ic)) + { + emitpcode (POC_GOTO, labelKey2num (popGetLabel (IC_TRUE (ic)->key))); + pic14_emitcode ("ljmp", "%05d_DS_", labelKey2num (IC_FALSE (ic)->key)); + } + ic->generated = TRUE; +} + +/*-----------------------------------------------------------------*/ +/* jmpTrueOrFalse - */ +/*-----------------------------------------------------------------*/ +static void +jmpTrueOrFalse (iCode * ic, symbol * tlbl) +{ + FENTRY; + // ugly but optimized by peephole + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + if (IC_TRUE (ic)) + { + symbol *nlbl = newiTempLabel (NULL); + pic14_emitcode ("sjmp", "%05d_DS_", labelKey2num (nlbl->key)); + pic14_emitcode ("", "%05d_DS_:", labelKey2num (tlbl->key)); + pic14_emitcode ("ljmp", "%05d_DS_", labelKey2num (IC_TRUE (ic)->key)); + pic14_emitcode ("", "%05d_DS_:", labelKey2num (nlbl->key)); + } + else + { + pic14_emitcode ("ljmp", "%05d_DS_", labelKey2num (IC_FALSE (ic)->key)); + pic14_emitcode ("", "%05d_DS_:", labelKey2num (tlbl->key)); + } + ic->generated = TRUE; +} + +/*-----------------------------------------------------------------*/ +/* 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; + resolvedIfx rIfx; + + FENTRY; + DEBUGpic14_emitcode ("; ***", "%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); + + resolveIfx (&rIfx, ifx); + + /* 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 (pic14_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 = ulFromVal (AOP (right)->aopu.aop_lit); + + size = AOP_SIZE (result); + + DEBUGpic14_AopType (__LINE__, left, right, 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 && pic14_sameRegs (AOP (result), AOP (left))) + // no change + goto release; + pic14_emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir); + } + else + { + // bit(result) = 0; + if (size && (AOP_TYPE (result) == AOP_CRY)) + { + pic14_emitcode ("clr", "%s", AOP (result)->aopu.aop_dir); + goto release; + } + if ((AOP_TYPE (result) == AOP_CRY) && ifx) + { + jumpIfTrue (ifx); + goto release; + } + pic14_emitcode ("clr", "c"); + } + } + else + { + if (AOP_TYPE (right) == AOP_CRY) + { + // c = bit & bit; + pic14_emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir); + pic14_emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir); + } + else + { + // c = bit & val; + MOVA (aopGet (AOP (right), 0, FALSE, FALSE)); + // c = lsb + pic14_emitcode ("rrc", "a"); + pic14_emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir); + } + } + // bit = c + // val = c + if (size) + pic14_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) + pic14_emitcode ("mov", "c,acc.%d", posbit & 0x07); + // if(left & 2^n) + else + { + if (ifx) + { + int offset = 0; + while (posbit > 7) + { + posbit -= 8; + offset++; + } + emitpcode (((rIfx.condition) ? POC_BTFSC : POC_BTFSS), + newpCodeOpBit (aopGet (AOP (left), offset, FALSE, FALSE), posbit, 0)); + emitpcode (POC_GOTO, popGetLabel (rIfx.lbl->key)); + + ifx->generated = TRUE; + } + goto release; + } + } + else + { + symbol *tlbl = newiTempLabel (NULL); + int sizel = AOP_SIZE (left); + if (size) + pic14_emitcode ("setb", "c"); + while (sizel--) + { + if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L) + { + // byte == 2^n ? + if ((posbit = isLiteralBit (bytelit)) != 0) + { + emitpcode (POC_BTFSC, + newpCodeOpBit (aopGet (AOP (left), offset, FALSE, FALSE), posbit - 1, 0)); + } + else + { + mov2w (AOP (left), offset); + emitpcode (POC_ANDLW, newpCodeOpLit (bytelit & 0x0ff)); + emitSKPZ; + } + emitpcode (POC_GOTO, popGetLabel (rIfx.condition ? + rIfx.lbl->key : tlbl->key)); + } + offset++; + } + if (!rIfx.condition) + { + emitpcode (POC_GOTO, popGetLabel (rIfx.lbl->key)); + } + emitpLabel(tlbl->key); + ifx->generated = TRUE; + // bit = left & literal + if (size) + { + pic14_emitcode ("clr", "c"); + pic14_emitcode ("", "%05d_DS_:", labelKey2num (tlbl->key)); + } + // if(left & literal) + else + { + if (ifx) + jmpTrueOrFalse (ifx, tlbl); + goto release; + } + } + pic14_outBitC (result); + goto release; + } + + /* if left is same as result */ + if (pic14_sameRegs (AOP (result), AOP (left))) + { + int know_W = -1; + for (; size--; offset++, lit >>= 8) + { + if (AOP_TYPE (right) == AOP_LIT) + { + switch (lit & 0xff) + { + case 0x00: + /* and'ing with 0 has clears the result */ + emitpcode (POC_CLRF, popGet (AOP (result), offset)); + break; + case 0xff: + /* and'ing with 0xff is a nop when the result and left are the same */ + break; + + default: + { + int p = my_powof2 ((~lit) & 0xff); + if (p >= 0) + { + /* only one bit is set in the literal, so use a bcf instruction */ + emitpcode (POC_BCF, newpCodeOpBit (aopGet (AOP (left), offset, FALSE, FALSE), p, 0)); + + } + else + { + if (know_W != (int) (lit & 0xff)) + emitpcode (POC_MOVLW, popGetLit (lit & 0xff)); + know_W = lit & 0xff; + emitpcode (POC_ANDWF, popGet (AOP (left), offset)); + } + } + } + } + else + { + emitpcode (POC_MOVFW, popGet (AOP (right), offset)); + emitpcode (POC_ANDWF, popGet (AOP (left), offset)); + } + } + + } + 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) + pic14_emitcode ("setb", "c"); + while (sizer--) + { + MOVA (aopGet (AOP (right), offset, FALSE, FALSE)); + pic14_emitcode ("anl", "a,%s", aopGet (AOP (left), offset, FALSE, FALSE)); + pic14_emitcode ("jnz", "%05d_DS_", labelKey2num (tlbl->key)); + offset++; + } + if (size) + { + CLRC; + pic14_emitcode ("", "%05d_DS_:", labelKey2num (tlbl->key)); + pic14_outBitC (result); + } + else if (ifx) + jmpTrueOrFalse (ifx, tlbl); + } + else + { + for (; (size--); offset++) + { + // normal case + // result = left & right + if (AOP_TYPE (right) == AOP_LIT) + { + int t = (lit >> (offset * 8)) & 0x0FFL; + switch (t) + { + case 0x00: + emitpcode (POC_CLRF, popGet (AOP (result), offset)); + break; + case 0xff: + emitpcode (POC_MOVFW, popGet (AOP (left), offset)); + emitpcode (POC_MOVWF, popGet (AOP (result), offset)); + break; + default: + emitpcode (POC_MOVLW, popGetLit (t)); + emitpcode (POC_ANDFW, popGet (AOP (left), offset)); + emitpcode (POC_MOVWF, popGet (AOP (result), offset)); + } + continue; + } + + emitpcode (POC_MOVFW, popGet (AOP (right), offset)); + emitpcode (POC_ANDFW, popGet (AOP (left), offset)); + emitpcode (POC_MOVWF, popGet (AOP (result), 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; + + FENTRY; + DEBUGpic14_emitcode ("; ***", "%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); + + DEBUGpic14_AopType (__LINE__, left, right, result); + + /* 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 (pic14_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; + } + + DEBUGpic14_AopType (__LINE__, left, right, result); + + if (AOP_TYPE (right) == AOP_LIT) + lit = ulFromVal (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) + emitpcode (POC_BSF, popGet (AOP (result), 0)); + //pic14_emitcode("bsf","(%s >> 3), (%s & 7)", + // AOP(result)->aopu.aop_dir, + // AOP(result)->aopu.aop_dir); + else if (ifx) + continueIfTrue (ifx); + goto release; + } + } + else + { + // lit == 0 => result = left + if (size && pic14_sameRegs (AOP (result), AOP (left))) + goto release; + pic14_emitcode (";XXX mov", "c,%s %s,%d", AOP (left)->aopu.aop_dir, __FILE__, __LINE__); + } + } + else + { + if (AOP_TYPE (right) == AOP_CRY) + { + if (pic14_sameRegs (AOP (result), AOP (left))) + { + // c = bit | bit; + emitpcode (POC_BCF, popGet (AOP (result), 0)); + emitpcode (POC_BTFSC, popGet (AOP (right), 0)); + emitpcode (POC_BSF, popGet (AOP (result), 0)); + + pic14_emitcode ("bcf", "(%s >> 3), (%s & 7)", AOP (result)->aopu.aop_dir, AOP (result)->aopu.aop_dir); + pic14_emitcode ("btfsc", "(%s >> 3), (%s & 7)", AOP (right)->aopu.aop_dir, AOP (right)->aopu.aop_dir); + pic14_emitcode ("bsf", "(%s >> 3), (%s & 7)", AOP (result)->aopu.aop_dir, AOP (result)->aopu.aop_dir); + } + else + { + emitpcode (POC_BCF, popGet (AOP (result), 0)); + emitpcode (POC_BTFSS, popGet (AOP (right), 0)); + emitpcode (POC_BTFSC, popGet (AOP (left), 0)); + emitpcode (POC_BSF, popGet (AOP (result), 0)); + } + } + else + { + // c = bit | val; + symbol *tlbl = newiTempLabel (NULL); + pic14_emitcode (";XXX ", " %s,%d", __FILE__, __LINE__); + + + emitpcode (POC_BCF, popGet (AOP (result), 0)); + + if (!((AOP_TYPE (result) == AOP_CRY) && ifx)) + pic14_emitcode (";XXX setb", "c"); + pic14_emitcode (";XXX jb", "%s,%05d_DS_", AOP (left)->aopu.aop_dir, labelKey2num (tlbl->key)); + pic14_toBoolean (right); + pic14_emitcode (";XXX jnz", "%05d_DS_", labelKey2num (tlbl->key)); + if ((AOP_TYPE (result) == AOP_CRY) && ifx) + { + jmpTrueOrFalse (ifx, tlbl); + goto release; + } + else + { + CLRC; + pic14_emitcode ("", "%05d_DS_:", labelKey2num (tlbl->key)); + } + } + } + // bit = c + // val = c + if (size) + pic14_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) + { + pic14_emitcode (";XXX ", " %s,%d", __FILE__, __LINE__); + // result = 1 + if (size) + pic14_emitcode (";XXX setb", "%s", AOP (result)->aopu.aop_dir); + else + continueIfTrue (ifx); + goto release; + } + else + { + pic14_emitcode (";XXX ", " %s,%d", __FILE__, __LINE__); + // lit = 0, result = boolean(left) + if (size) + pic14_emitcode (";XXX setb", "c"); + pic14_toBoolean (right); + if (size) + { + symbol *tlbl = newiTempLabel (NULL); + pic14_emitcode (";XXX jnz", "%05d_DS_", labelKey2num (tlbl->key)); + CLRC; + pic14_emitcode ("", "%05d_DS_:", labelKey2num (tlbl->key)); + } + else + { + genIfxJump (ifx, "a"); + goto release; + } + } + pic14_outBitC (result); + goto release; + } + + /* if left is same as result */ + if (pic14_sameRegs (AOP (result), AOP (left))) + { + int know_W = -1; + 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 */ + emitpcode (POC_BSF, newpCodeOpBit (aopGet (AOP (left), offset, FALSE, FALSE), p, 0)); + } + else + { + if (know_W != (int) (lit & 0xff)) + emitpcode (POC_MOVLW, popGetLit (lit & 0xff)); + know_W = lit & 0xff; + emitpcode (POC_IORWF, popGet (AOP (left), offset)); + } + + } + } + else + { + emitpcode (POC_MOVFW, popGet (AOP (right), offset)); + emitpcode (POC_IORWF, popGet (AOP (left), offset)); + } + } + } + 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)); + pic14_emitcode (";XXX ", " %s,%d", __FILE__, __LINE__); + + + if (size) + pic14_emitcode (";XXX setb", "c"); + while (sizer--) + { + MOVA (aopGet (AOP (right), offset, FALSE, FALSE)); + pic14_emitcode (";XXX orl", "a,%s", aopGet (AOP (left), offset, FALSE, FALSE)); + pic14_emitcode (";XXX jnz", "%05d_DS_", labelKey2num (tlbl->key)); + offset++; + } + if (size) + { + CLRC; + pic14_emitcode ("", "%05d_DS_:", labelKey2num (tlbl->key)); + pic14_outBitC (result); + } + else if (ifx) + jmpTrueOrFalse (ifx, tlbl); + } + else + for (; (size--); offset++) + { + // normal case + // result = left | right + if (AOP_TYPE (right) == AOP_LIT) + { + int t = (lit >> (offset * 8)) & 0x0FFL; + switch (t) + { + case 0x00: + emitpcode (POC_MOVFW, popGet (AOP (left), offset)); + emitpcode (POC_MOVWF, popGet (AOP (result), offset)); + + break; + default: + emitpcode (POC_MOVLW, popGetLit (t)); + emitpcode (POC_IORFW, popGet (AOP (left), offset)); + emitpcode (POC_MOVWF, popGet (AOP (result), offset)); + } + continue; + } + + // faster than result <- left, anl result,right + // and better if result is SFR + emitpcode (POC_MOVFW, popGet (AOP (right), offset)); + emitpcode (POC_IORFW, popGet (AOP (left), offset)); + emitpcode (POC_MOVWF, popGet (AOP (result), offset)); + } + } + +release: + freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + freeAsmop (result, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genXor - code for xclusive or */ +/*-----------------------------------------------------------------*/ +static void +genXor (iCode * ic, iCode * ifx) +{ + operand *left, *right, *result; + int size, offset = 0; + unsigned long lit = 0L; + + FENTRY; + DEBUGpic14_emitcode ("; ***", "%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); + + /* 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 (pic14_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 = ulFromVal (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) + { + emitpcode (POC_BSF, popGet (AOP (result), offset)); + pic14_emitcode ("setb", "%s", AOP (result)->aopu.aop_dir); + } + else if (ifx) + continueIfTrue (ifx); + goto release; + } + pic14_emitcode ("setb", "c"); + } + else + { + // lit == (0 or 1) + if (lit == 0) + { + // lit == 0, result = left + if (size && pic14_sameRegs (AOP (result), AOP (left))) + goto release; + pic14_emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir); + } + else + { + // lit == 1, result = not(left) + if (size && pic14_sameRegs (AOP (result), AOP (left))) + { + emitpcode (POC_MOVLW, popGet (AOP (result), offset)); + emitpcode (POC_XORWF, popGet (AOP (result), offset)); + pic14_emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir); + goto release; + } + else + { + assert (!"incomplete genXor"); + pic14_emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir); + pic14_emitcode ("cpl", "c"); + } + } + } + + } + else + { + // right != literal + symbol *tlbl = newiTempLabel (NULL); + if (AOP_TYPE (right) == AOP_CRY) + { + // c = bit ^ bit; + pic14_emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir); + } + else + { + int sizer = AOP_SIZE (right); + // c = bit ^ val + // if val>>1 != 0, result = 1 + pic14_emitcode ("setb", "c"); + while (sizer) + { + MOVA (aopGet (AOP (right), sizer - 1, FALSE, FALSE)); + if (sizer == 1) + // test the msb of the lsb + pic14_emitcode ("anl", "a,#0xfe"); + pic14_emitcode ("jnz", "%05d_DS_", labelKey2num (tlbl->key)); + sizer--; + } + // val = (0,1) + pic14_emitcode ("rrc", "a"); + } + pic14_emitcode ("jnb", "%s,%05d_DS_", AOP (left)->aopu.aop_dir, (labelKey2num (tlbl->key))); + pic14_emitcode ("cpl", "c"); + pic14_emitcode ("", "%05d_DS_:", (labelKey2num (tlbl->key))); + } + // bit = c + // val = c + if (size) + pic14_outBitC (result); + // if(bit | ...) + else if ((AOP_TYPE (result) == AOP_CRY) && ifx) + genIfxJump (ifx, "c"); + goto release; + } + + if (pic14_sameRegs (AOP (result), AOP (left))) + { + /* if left is same as result */ + for (; size--; offset++) + { + if (AOP_TYPE (right) == AOP_LIT) + { + int t = (lit >> (offset * 8)) & 0x0FFL; + if (t == 0x00L) + continue; + else + { + emitpcode (POC_MOVLW, popGetLit (t)); + emitpcode (POC_XORWF, popGet (AOP (left), offset)); + } + } + else + { + emitpcode (POC_MOVFW, popGet (AOP (right), offset)); + emitpcode (POC_XORWF, popGet (AOP (left), offset)); + } + } + } + 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) + pic14_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)); + pic14_emitcode ("xrl", "a,%s", aopGet (AOP (left), offset, FALSE, FALSE)); + } + pic14_emitcode ("jnz", "%05d_DS_", labelKey2num (tlbl->key)); + offset++; + } + if (size) + { + CLRC; + pic14_emitcode ("", "%05d_DS_:", labelKey2num (tlbl->key)); + pic14_outBitC (result); + } + else if (ifx) + jmpTrueOrFalse (ifx, tlbl); + } + else + for (; (size--); offset++) + { + // normal case + // result = left & right + if (AOP_TYPE (right) == AOP_LIT) + { + int t = (lit >> (offset * 8)) & 0x0FFL; + switch (t) + { + case 0x00: + emitpcode (POC_MOVFW, popGet (AOP (left), offset)); + emitpcode (POC_MOVWF, popGet (AOP (result), offset)); + break; + case 0xff: + emitpcode (POC_COMFW, popGet (AOP (left), offset)); + emitpcode (POC_MOVWF, popGet (AOP (result), offset)); + break; + default: + emitpcode (POC_MOVLW, popGetLit (t)); + emitpcode (POC_XORFW, popGet (AOP (left), offset)); + emitpcode (POC_MOVWF, popGet (AOP (result), offset)); + } + continue; + } + + // faster than result <- left, anl result,right + // and better if result is SFR + emitpcode (POC_MOVFW, popGet (AOP (right), offset)); + emitpcode (POC_XORFW, popGet (AOP (left), offset)); + emitpcode (POC_MOVWF, popGet (AOP (result), 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 +pic14_genInline (iCode * ic) +{ + char *buffer, *bp, *bp1; + bool inComment = FALSE; + + FENTRY; + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + + genLine.lineElement.isInline += (!options.asmpeep); + + buffer = bp = bp1 = Safe_strdup (IC_INLINE (ic)); + + while (*bp) + { + switch (*bp) + { + case ';': + inComment = TRUE; + ++bp; + break; + + case '\x87': + case '\n': + inComment = FALSE; + *bp++ = '\0'; + if (*bp1) + addpCode2pBlock (pb, newpCodeAsmDir (bp1, NULL)); // inline directly, no process + bp1 = bp; + break; + + default: + /* Add \n for labels, not dirs such as c:\mydir */ + if (!inComment && (*bp == ':') && (isspace ((unsigned char) bp[1]))) + { + ++bp; + *bp = '\0'; + ++bp; + /* print label, use this special format with NULL directive + * to denote that the argument should not be indented with tab */ + addpCode2pBlock (pb, newpCodeAsmDir (NULL, bp1)); // inline directly, no process + bp1 = bp; + } + else + ++bp; + break; + } + } + if ((bp1 != bp) && *bp1) + addpCode2pBlock (pb, newpCodeAsmDir (bp1, NULL)); // inline directly, no process + + Safe_free (buffer); + + /* consumed; we can free it here */ + dbuf_free (IC_INLINE (ic)); + + genLine.lineElement.isInline -= (!options.asmpeep); +} + +/*-----------------------------------------------------------------*/ +/* genRRC - rotate right with carry */ +/*-----------------------------------------------------------------*/ +static void +genRRC (iCode * ic) +{ + operand *left, *result; + int size, offset = 0, same; + + FENTRY; + /* rotate right with carry */ + left = IC_LEFT (ic); + result = IC_RESULT (ic); + aopOp (left, ic, FALSE); + aopOp (result, ic, FALSE); + + DEBUGpic14_AopType (__LINE__, left, NULL, result); + + same = pic14_sameRegs (AOP (result), AOP (left)); + + size = AOP_SIZE (result); + + /* get the lsb and put it into the carry */ + emitpcode (POC_RRFW, popGet (AOP (left), size - 1)); + + offset = 0; + + while (size--) + { + if (same) + { + emitpcode (POC_RRF, popGet (AOP (left), offset)); + } + else + { + emitpcode (POC_RRFW, popGet (AOP (left), offset)); + emitpcode (POC_MOVWF, popGet (AOP (result), offset)); + } + + offset++; + } + + 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; + int same; + + FENTRY; + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + /* rotate right with carry */ + left = IC_LEFT (ic); + result = IC_RESULT (ic); + aopOp (left, ic, FALSE); + aopOp (result, ic, FALSE); + + DEBUGpic14_AopType (__LINE__, left, NULL, result); + + same = pic14_sameRegs (AOP (result), AOP (left)); + + /* move it to the result */ + size = AOP_SIZE (result); + + /* get the msb and put it into the carry */ + emitpcode (POC_RLFW, popGet (AOP (left), size - 1)); + + offset = 0; + + while (size--) + { + if (same) + { + emitpcode (POC_RLF, popGet (AOP (left), offset)); + } + else + { + emitpcode (POC_RLFW, popGet (AOP (left), offset)); + emitpcode (POC_MOVWF, popGet (AOP (result), offset)); + } + + offset++; + } + + + freeAsmop (left, NULL, ic, TRUE); + freeAsmop (result, NULL, ic, TRUE); +} + +static void +genGetABit (iCode * ic) +{ + operand *left, *right, *result; + int shCount; + int offset; + int i; + + left = IC_LEFT (ic); + right = IC_RIGHT (ic); + result = IC_RESULT (ic); + + aopOp (left, ic, FALSE); + aopOp (right, ic, FALSE); + aopOp (result, ic, TRUE); + + shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit); + offset = shCount / 8; + shCount %= 8; + + /* load and mask the source byte */ + mov2w (AOP (left), offset); + emitpcode (POC_ANDLW, popGetLit (1 << shCount)); + + /* move selected bit to bit 0 */ + switch (shCount) + { + case 0: + /* nothing more to do */ + break; + default: + /* keep W==0, force W=0x01 otherwise */ + emitSKPZ; + emitpcode (POC_MOVLW, popGetLit (1)); + break; + } // switch + + /* write result */ + emitpcode (POC_MOVWF, popGet (AOP (result), 0)); + + for (i = 1; i < AOP_SIZE (result); ++i) + { + emitpcode (POC_CLRF, popGet (AOP (result), i)); + } // for + + freeAsmop (left, NULL, ic, TRUE); + freeAsmop (right, 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); + + FENTRY; + DEBUGpic14_emitcode ("; ***", "%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) + { + pic14_emitcode ("rlc", "a"); + pic14_outBitC (result); + } + else + { + pic14_emitcode ("rl", "a"); + pic14_emitcode ("anl", "a,#0x01"); + pic14_outAcc (result); + } + + + freeAsmop (left, NULL, ic, TRUE); + freeAsmop (result, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* AccLsh - shift left accumulator by known count */ +/* MARK: pic14 always rotates through CARRY! */ +/*-----------------------------------------------------------------*/ +static void +AccLsh (pCodeOp * pcop, int shCount) +{ + FENTRY; + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + shCount &= 0x0007; // shCount : 0..7 + switch (shCount) + { + case 0: + return; + break; + case 1: + emitCLRC; + emitpcode (POC_RLF, pcop); + return; + break; + case 2: + emitpcode (POC_RLF, pcop); + emitpcode (POC_RLF, pcop); + break; + case 3: + emitpcode (POC_RLF, pcop); + emitpcode (POC_RLF, pcop); + emitpcode (POC_RLF, pcop); + break; + case 4: + emitpcode (POC_SWAPF, pcop); + break; + case 5: + emitpcode (POC_SWAPF, pcop); + emitpcode (POC_RLF, pcop); + break; + case 6: + emitpcode (POC_SWAPF, pcop); + emitpcode (POC_RLF, pcop); + emitpcode (POC_RLF, pcop); + break; + case 7: + emitpcode (POC_RRFW, pcop); + emitpcode (POC_RRF, pcop); + break; + } + /* clear invalid bits */ + emitpcode (POC_MOVLW, popGetLit ((unsigned char) (~((1UL << shCount) - 1)))); + emitpcode (POC_ANDWF, pcop); +} + +/*-----------------------------------------------------------------*/ +/* AccRsh - shift right accumulator by known count */ +/* MARK: pic14 always rotates through CARRY! */ +/* maskmode - 0: leave invalid bits undefined (caller should mask) */ +/* 1: mask out invalid bits (zero-extend) */ +/* 2: sign-extend result (pretty slow) */ +/*-----------------------------------------------------------------*/ +static void +AccRsh (pCodeOp * pcop, int shCount, int mask_mode) +{ + FENTRY; + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + shCount &= 0x0007; // shCount : 0..7 + switch (shCount) + { + case 0: + return; + break; + case 1: + /* load sign if needed */ + if (mask_mode == 2) + emitpcode (POC_RLFW, pcop); + else if (mask_mode == 1) + emitCLRC; + emitpcode (POC_RRF, pcop); + return; + break; + case 2: + /* load sign if needed */ + if (mask_mode == 2) + emitpcode (POC_RLFW, pcop); + emitpcode (POC_RRF, pcop); + /* load sign if needed */ + if (mask_mode == 2) + emitpcode (POC_RLFW, pcop); + emitpcode (POC_RRF, pcop); + if (mask_mode == 2) + return; + break; + case 3: + /* load sign if needed */ + if (mask_mode == 2) + emitpcode (POC_RLFW, pcop); + emitpcode (POC_RRF, pcop); + /* load sign if needed */ + if (mask_mode == 2) + emitpcode (POC_RLFW, pcop); + emitpcode (POC_RRF, pcop); + /* load sign if needed */ + if (mask_mode == 2) + emitpcode (POC_RLFW, pcop); + emitpcode (POC_RRF, pcop); + if (mask_mode == 2) + return; + break; + case 4: + emitpcode (POC_SWAPF, pcop); + break; + case 5: + emitpcode (POC_SWAPF, pcop); + emitpcode (POC_RRF, pcop); + break; + case 6: + emitpcode (POC_SWAPF, pcop); + emitpcode (POC_RRF, pcop); + emitpcode (POC_RRF, pcop); + break; + case 7: + if (mask_mode == 2) + { + /* load sign */ + emitpcode (POC_RLFW, pcop); + emitpcode (POC_CLRF, pcop); + emitSKPNC; + emitpcode (POC_COMF, pcop); + return; + } + else + { + emitpcode (POC_RLFW, pcop); + emitpcode (POC_RLF, pcop); + } + break; + } + + if (mask_mode == 0) + { + /* leave invalid bits undefined */ + return; + } + + /* clear invalid bits -- zero-extend */ + emitpcode (POC_MOVLW, popGetLit (0x00ff >> shCount)); + emitpcode (POC_ANDWF, pcop); + + if (mask_mode == 2) + { + /* sign-extend */ + emitpcode (POC_MOVLW, popGetLit (0x00ff << (8 - shCount))); + emitpcode (POC_BTFSC, newpCodeOpBit (get_op (pcop, NULL, 0), 7 - shCount, 0)); + emitpcode (POC_IORWF, pcop); + } +} + +/*-----------------------------------------------------------------*/ +/* movLeft2Result - move byte from left to result */ +/*-----------------------------------------------------------------*/ +static void +movLeft2Result (operand * left, int offl, operand * result, int offr) +{ + FENTRY; + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + if (!pic14_sameRegs (AOP (left), AOP (result)) || (offl != offr)) + { + aopGet (AOP (left), offl, FALSE, FALSE); + + emitpcode (POC_MOVFW, popGet (AOP (left), offl)); + emitpcode (POC_MOVWF, popGet (AOP (result), offr)); + } +} + +/*-----------------------------------------------------------------*/ +/* shiftLeft_Left2ResultLit - shift left by known count */ +/*-----------------------------------------------------------------*/ + +static void +shiftLeft_Left2ResultLit (operand * left, operand * result, int shCount) +{ + int size, same, offr, i; + + size = AOP_SIZE (left); + if (AOP_SIZE (result) < size) + size = AOP_SIZE (result); + + same = pic14_sameRegs (AOP (left), AOP (result)); + + offr = shCount / 8; + shCount = shCount & 0x07; + + size -= offr; + + switch (shCount) + { + case 0: /* takes 0 or 2N cycles (for offr==0) */ + if (!same || offr) + { + for (i = size - 1; i >= 0; i--) + movLeft2Result (left, i, result, offr + i); + } // if + break; + + case 1: /* takes 1N+1 or 2N+1 cycles (or offr==0) */ + if (same && offr) + { + shiftLeft_Left2ResultLit (left, result, 8 * offr); + shiftLeft_Left2ResultLit (result, result, shCount); + return; /* prevent clearing result again */ + } + else + { + if (pic->isEnhancedCore) + { + for (i = 0; i < size; i++) + { + if (same && !offr) + { + if (i == 0) + { + emitpcode (POC_LSLF, popGet (AOP (left), i)); + } + else + { + emitpcode (POC_RLF, popGet (AOP (left), i)); + } + } + else + { + if (i == 0) + { + emitpcode (POC_LSLFW, popGet (AOP (left), i)); + } + else + { + emitpcode (POC_RLFW, popGet (AOP (left), i)); + } + + emitpcode (POC_MOVWF, popGet (AOP (result), i + offr)); + } + } + } + else + { + emitCLRC; + for (i = 0; i < size; i++) + { + if (same && !offr) + { + emitpcode (POC_RLF, popGet (AOP (left), i)); + } + else + { + emitpcode (POC_RLFW, popGet (AOP (left), i)); + emitpcode (POC_MOVWF, popGet (AOP (result), i + offr)); + } // if + } // for + } // if (pic->isEnhancedCore) + } // if (same && offr) + break; + + case 4: /* takes 3+5(N-1) = 5N-2 cycles (for offr==0) */ + /* works in-place/with offr as well */ + emitpcode (POC_SWAPFW, popGet (AOP (left), size - 1)); + emitpcode (POC_ANDLW, popGetLit (0xF0)); + emitpcode (POC_MOVWF, popGet (AOP (result), size - 1 + offr)); + + for (i = size - 2; i >= 0; i--) + { + emitpcode (POC_SWAPFW, popGet (AOP (left), i)); + emitpcode (POC_MOVWF, popGet (AOP (result), i + offr)); + emitpcode (POC_ANDLW, popGetLit (0x0F)); + emitpcode (POC_IORWF, popGet (AOP (result), i + offr + 1)); + emitpcode (POC_XORWF, popGet (AOP (result), i + offr)); + } // for i + break; + + case 7: /* takes 2(N-1)+3 = 2N+1 cycles */ + /* works in-place/with offr as well */ + emitpcode (POC_RRFW, popGet (AOP (left), size - 1)); + for (i = size - 2; i >= 0; i--) + { + emitpcode (POC_RRFW, popGet (AOP (left), i)); + emitpcode (POC_MOVWF, popGet (AOP (result), offr + i + 1)); + } // for i + emitpcode (POC_CLRF, popGet (AOP (result), offr)); + emitpcode (POC_RRF, popGet (AOP (result), offr)); + break; + + default: + shiftLeft_Left2ResultLit (left, result, offr * 8 + shCount - 1); + shiftLeft_Left2ResultLit (result, result, 1); + return; /* prevent clearing result again */ + break; + } // switch + + while (0 < offr--) + { + emitpcode (POC_CLRF, popGet (AOP (result), offr)); + } // while +} + +/*-----------------------------------------------------------------*/ +/* shiftRight_Left2ResultLit - shift right by known count */ +/*-----------------------------------------------------------------*/ + +static void +shiftRight_Left2ResultLit (operand * left, operand * result, int shCount, int sign) +{ + int size, same, offr, i; + + size = AOP_SIZE (left); + if (AOP_SIZE (result) < size) + size = AOP_SIZE (result); + + same = pic14_sameRegs (AOP (left), AOP (result)); + + offr = shCount / 8; + shCount = shCount & 0x07; + + size -= offr; + + if (size) + { + switch (shCount) + { + case 0: /* takes 0 or 2N cycles (for offr==0) */ + if (!same || offr) + { + for (i = 0; i < size; i++) + movLeft2Result (left, i + offr, result, i); + } // if + break; + + case 1: /* takes 1N+1(3) or 2N+1(3) cycles (or offr==0) */ + emitpComment ("%s:%d: shCount=%d, size=%d, sign=%d, same=%d, offr=%d", __FUNCTION__, __LINE__, shCount, size, sign, + same, offr); + if (same && offr) + { + shiftRight_Left2ResultLit (left, result, 8 * offr, sign); + shiftRight_Left2ResultLit (result, result, shCount, sign); + return; /* prevent sign-extending result again */ + } + else + { + if (pic->isEnhancedCore) + { + for (i = size - 1; i >= 0; i--) + { + if (same && !offr) + { + if (i == (size - 1)) + { + if (sign) + { + emitpcode (POC_ASRF, popGet (AOP (left), i)); + } + else + { + emitpcode (POC_LSRF, popGet (AOP (left), i)); + } + } + else + { + emitpcode (POC_RRF, popGet (AOP (left), i)); + } + } + else + { + if (i == (size - 1)) + { + if (sign) + { + emitpcode (POC_ASRFW, popGet (AOP (left), i)); + } + else + { + emitpcode (POC_LSRFW, popGet (AOP (left), i)); + } + } + else + { + emitpcode (POC_RRFW, popGet (AOP (left), i + offr)); + } + + emitpcode (POC_MOVWF, popGet (AOP (result), i)); + } // if (same && !offr) + } // for i + } + else + { + emitCLRC; + if (sign) + { + emitpcode (POC_BTFSC, newpCodeOpBit (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE, FALSE), 7, 0)); + emitSETC; + } + + for (i = size - 1; i >= 0; i--) + { + if (same && !offr) + { + emitpcode (POC_RRF, popGet (AOP (left), i)); + } + else + { + emitpcode (POC_RRFW, popGet (AOP (left), i + offr)); + emitpcode (POC_MOVWF, popGet (AOP (result), i)); + } + } // for i + } // if (pic->isEnhancedCore) + } // if (same && offr) + break; + + case 4: /* takes 3(6)+5(N-1) = 5N-2(+1) cycles (for offr==0) */ + /* works in-place/with offr as well */ + emitpcode (POC_SWAPFW, popGet (AOP (left), offr)); + emitpcode (POC_ANDLW, popGetLit (0x0F)); + emitpcode (POC_MOVWF, popGet (AOP (result), 0)); + + for (i = 1; i < size; i++) + { + emitpcode (POC_SWAPFW, popGet (AOP (left), i + offr)); + emitpcode (POC_MOVWF, popGet (AOP (result), i)); + emitpcode (POC_ANDLW, popGetLit (0xF0)); + emitpcode (POC_IORWF, popGet (AOP (result), i - 1)); + emitpcode (POC_XORWF, popGet (AOP (result), i)); + } // for i + + if (sign) + { + emitpcode (POC_MOVLW, popGetLit (0xF0)); + emitpcode (POC_BTFSC, newpCodeOpBit (aopGet (AOP (result), size - 1, FALSE, FALSE), 3, 0)); + emitpcode (POC_IORWF, popGet (AOP (result), size - 1)); + } // if + break; + + case 7: /* takes 2(N-1)+3(4) = 2N+1(2) cycles */ + /* works in-place/with offr as well */ + emitpcode (POC_RLFW, popGet (AOP (left), offr)); + for (i = 0; i < size - 1; i++) + { + emitpcode (POC_RLFW, popGet (AOP (left), offr + i + 1)); + emitpcode (POC_MOVWF, popGet (AOP (result), i)); + } // for i + emitpcode (POC_CLRF, popGet (AOP (result), size - 1)); + if (!sign) + { + emitpcode (POC_RLF, popGet (AOP (result), size - 1)); + } + else + { + emitSKPNC; + emitpcode (POC_DECF, popGet (AOP (result), size - 1)); + } + break; + + default: + shiftRight_Left2ResultLit (left, result, offr * 8 + shCount - 1, sign); + shiftRight_Left2ResultLit (result, result, 1, sign); + return; /* prevent sign extending result again */ + break; + } // switch + } // if + + addSign (result, size, sign); +} + +/*-----------------------------------------------------------------* +* genMultiAsm - repeat assembly instruction for size of register. +* if endian == 1, then the high byte (i.e base address + size of +* register) is used first else the low byte is used first; +*-----------------------------------------------------------------*/ +static void +genMultiAsm (PIC_OPCODE poc, operand * reg, int size, int endian) +{ + + int offset = 0; + + FENTRY; + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + + if (!reg) + return; + + if (!endian) + { + endian = 1; + } + else + { + endian = -1; + offset = size - 1; + } + + while (size--) + { + emitpcode (poc, popGet (AOP (reg), offset)); + offset += endian; + } + +} + +/*-----------------------------------------------------------------*/ +/* loadSignToC - load the operand's sign bit into CARRY */ +/*-----------------------------------------------------------------*/ + +static void +loadSignToC (operand * op) +{ + FENTRY; + assert (op && AOP (op) && AOP_SIZE (op)); + + emitCLRC; + emitpcode (POC_BTFSC, newpCodeOpBit (aopGet (AOP (op), AOP_SIZE (op) - 1, FALSE, FALSE), 7, 0)); + emitSETC; +} + +/*-----------------------------------------------------------------*/ +/* genRightShift - generate code for right shifting */ +/*-----------------------------------------------------------------*/ +static void +genGenericShift (iCode * ic, int shiftRight) +{ + operand *right, *left, *result; + int size; + symbol *tlbl, *tlbl1, *inverselbl; + + FENTRY; + /* if signed then we do it the hard way preserve the + sign bit moving it inwards */ + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + + /* 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); + aopOp (left, ic, FALSE); + aopOp (result, ic, FALSE); + + /* if the shift count is known then do it + as efficiently as possible */ + if (AOP_TYPE (right) == AOP_LIT) + { + int lit = (int) ulFromVal (AOP (right)->aopu.aop_lit); + if (lit < 0) + { + lit = -lit; + shiftRight = !shiftRight; + } + + if (shiftRight) + shiftRight_Left2ResultLit (left, result, lit, !SPEC_USIGN (operandType (left))); + else + shiftLeft_Left2ResultLit (left, result, 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 ) */ + + /* we must not overwrite the shift counter */ + assert (!pic14_sameRegs (AOP (right), AOP (result))); + + /* now move the left to the result if they are not the + same */ + if (!pic14_sameRegs (AOP (left), AOP (result))) + { + size = min (AOP_SIZE (result), AOP_SIZE (left)); + while (size--) + { + mov2w (AOP (left), size); + movwf (AOP (result), size); + } + addSign (result, AOP_SIZE (left), !SPEC_USIGN (operandType (left))); + } + + tlbl = newiTempLabel (NULL); + tlbl1 = newiTempLabel (NULL); + inverselbl = NULL; + size = AOP_SIZE (result); + + mov2w (AOP (right), 0); + if (!SPEC_USIGN (operandType (right))) + { + inverselbl = newiTempLabel (NULL); + /* signed shift count -- invert shift direction for c<0 */ + emitpcode (POC_BTFSC, newpCodeOpBit (aopGet (AOP (right), 0, FALSE, FALSE), 7, 0)); + emitpcode (POC_GOTO, popGetLabel (inverselbl->key)); + } // if + emitpcode (POC_SUBLW, popGetLit (0)); /* -count in WREG, 0-x > 0 --> BORROW = !CARRY --> CARRY is clear! */ + /* check for `a = b >> c' with `-c == 0' */ + emitSKPNZ; + emitpcode (POC_GOTO, popGetLabel (tlbl1->key)); + emitpLabel (tlbl->key); + /* propagate the sign bit inwards for SIGNED result */ + if (shiftRight && !SPEC_USIGN (operandType (result))) + loadSignToC (result); + genMultiAsm (shiftRight ? POC_RRF : POC_RLF, result, size, shiftRight); + emitpcode (POC_ADDLW, popGetLit (1)); /* clears CARRY (unless W==0 afterwards) */ + emitSKPC; + emitpcode (POC_GOTO, popGetLabel (tlbl->key)); + + if (!SPEC_USIGN (operandType (right))) + { + symbol *inv_loop = newiTempLabel (NULL); + + shiftRight = !shiftRight; /* invert shift direction */ + + /* we came here from the code above -- we are done */ + emitpcode (POC_GOTO, popGetLabel (tlbl1->key)); + + /* emit code for shifting N<0 steps, count is already in W */ + emitpLabel (inverselbl->key); + if (!shiftRight || SPEC_USIGN (operandType (result))) + emitCLRC; + emitpLabel (inv_loop->key); + /* propagate the sign bit inwards for SIGNED result */ + if (shiftRight && !SPEC_USIGN (operandType (result))) + loadSignToC (result); + genMultiAsm (shiftRight ? POC_RRF : POC_RLF, result, size, shiftRight); + emitpcode (POC_ADDLW, popGetLit (1)); + emitSKPC; + emitpcode (POC_GOTO, popGetLabel (inv_loop->key)); + } // if + + emitpLabel (tlbl1->key); + + freeAsmop (left, NULL, ic, TRUE); + freeAsmop (right, NULL, ic, TRUE); + freeAsmop (result, NULL, ic, TRUE); +} + +static void +genRightShift (iCode * ic) +{ + genGenericShift (ic, 1); +} + +static void +genLeftShift (iCode * ic) +{ + genGenericShift (ic, 0); +} + +/*-----------------------------------------------------------------*/ +/* SetIrp - Set IRP bit */ +/*-----------------------------------------------------------------*/ +static void +SetIrp (operand * result) +{ + FENTRY; + if (AOP_TYPE (result) == AOP_LIT) + { + unsigned lit = (unsigned) double2ul (operandLitValue (result)); + if (lit & 0x100) + emitSETIRP; + else + emitCLRIRP; + } + else if ((AOP_TYPE (result) == AOP_PCODE) && (AOP (result)->aopu.pcop->type == PO_LITERAL)) + { + int addrs = PCOL (AOP (result)->aopu.pcop)->lit; + if (addrs & 0x100) + emitSETIRP; + else + emitCLRIRP; + } + else if ((AOP_TYPE (result) == AOP_PCODE) && (AOP (result)->aopu.pcop->type == PO_IMMEDIATE)) + { + emitCLRIRP; /* always ensure this is clear as it may have previously been set */ + emitpcode (POC_MOVLW, popGetAddr (AOP (result), 1, 0)); + emitpcode (POC_ANDLW, popGetLit (0x01)); + emitSKPZ; + emitSETIRP; + } + else + { + emitCLRIRP; /* always ensure this is clear as it may have previouly been set */ + if (AOP_SIZE (result) > 1) + { + emitpcode (POC_BTFSC, newpCodeOpBit (aopGet (AOP (result), 1, FALSE, FALSE), 0, 0)); + emitSETIRP; + } + } +} + +static void +setup_fsr (operand * ptr) +{ + if (pic->isEnhancedCore) + { + mov2w_op (ptr, 0); + emitpcode (POC_MOVWF, popCopyReg (&pc_fsr0l)); + mov2w_op (ptr, 1); + emitpcode (POC_MOVWF, popCopyReg (&pc_fsr0h)); + } + else + { + mov2w_op (ptr, 0); + emitpcode (POC_MOVWF, popCopyReg (&pc_fsr)); + + /* also setup-up IRP */ + SetIrp (ptr); + } +} + +static void +inc_fsr (int delta) +{ + if (0 == delta) + { + /* Nothing to do. */ + return; + } // if + + if (pic->isEnhancedCore) + { + if (pic14_options.no_ext_instr) + { + /* + * Not sure if we may modify W here, so implement this without + * touching W. + * + * Efficiency is not too important here, as enhanced cores + * will most likely use extended instructions here. This is + * only a workaround for gputils 0.13.7, which supports the + * 16f1934 enhanced core, but fails to assemble ADDFSR. + */ + while (delta > 0) + { + emitpcode (POC_INCFSZ, popCopyReg (&pc_fsr0l)); + emitpcode (POC_DECF, popCopyReg (&pc_fsr0h)); + emitpcode (POC_INCF, popCopyReg (&pc_fsr0h)); + --delta; + } // while + while (delta < 0) + { + addpCode2pBlock (pb, newpCodeAsmDir("MOVF", "FSR0L, 1")); + emitSKPNZ; + emitpcode (POC_DECF, popCopyReg (&pc_fsr0h)); + emitpcode (POC_DECF, popCopyReg (&pc_fsr0l)); + ++delta; + } // while + } + else + { + assert (delta >= -32); + assert (delta < 32); + /* Hack: Turn this into a PCI (not that easy due to the argument structure). */ + addpCode2pBlock (pb, newpCodeAsmDir ("ADDFSR", "FSR0, %d", delta)); + } // if + } + else + { + while (delta > 0) + { + emitpcode (POC_INCF, popCopyReg (&pc_fsr)); + --delta; + } // while + while (delta < 0) + { + emitpcode (POC_DECF, popCopyReg (&pc_fsr)); + ++delta; + } // while + } // if +} + +/*-----------------------------------------------------------------*/ +/* emitPtrByteGet - emits code to get a byte into WREG from an */ +/* arbitrary pointer (__code, __data, generic) */ +/*-----------------------------------------------------------------*/ +static void +emitPtrByteGet (operand * src, int p_type, bool alreadyAddressed) +{ + FENTRY; + switch (p_type) + { + case POINTER: + case FPOINTER: + if (!alreadyAddressed) + setup_fsr (src); + emitpcode (POC_MOVFW, popCopyReg (pc_indf)); + break; + + case CPOINTER: + assert (AOP_SIZE (src) == 2); + mov2w_op (src, 0); + emitpcode (POC_MOVWF, popRegFromIdx (Gstack_base_addr - 1)); + mov2w_op (src, 1); + emitpcode (POC_MOVWF, popRegFromIdx (Gstack_base_addr)); + emitpcode (POC_MOVLW, popGetLit (GPTRTAG_CODE)); /* GPOINTER tag for __code space */ + call_libraryfunc ("__gptrget1"); + break; + + case GPOINTER: + assert (AOP_SIZE (src) == 3); + mov2w_op (src, 0); + emitpcode (POC_MOVWF, popRegFromIdx (Gstack_base_addr - 1)); + mov2w_op (src, 1); + emitpcode (POC_MOVWF, popRegFromIdx (Gstack_base_addr)); + mov2w_op (src, 2); + call_libraryfunc ("__gptrget1"); + break; + + default: + assert (!"unhandled pointer type"); + break; + } +} + +/*-----------------------------------------------------------------*/ +/* emitPtrByteSet - emits code to set a byte from src through a */ +/* pointer register INDF (legacy 8051 uses R0, R1, or DPTR). */ +/*-----------------------------------------------------------------*/ +static void +emitPtrByteSet (operand * dst, int p_type, bool alreadyAddressed) +{ + FENTRY; + switch (p_type) + { + case POINTER: + case FPOINTER: + if (!alreadyAddressed) + setup_fsr (dst); + emitpcode (POC_MOVWF, popCopyReg (pc_indf)); + break; + + case CPOINTER: + assert (!"trying to assign to __code pointer"); + break; + + case GPOINTER: + emitpcode (POC_MOVWF, popRegFromIdx (Gstack_base_addr - 2)); + mov2w_op (dst, 0); + emitpcode (POC_MOVWF, popRegFromIdx (Gstack_base_addr - 1)); + mov2w_op (dst, 1); + emitpcode (POC_MOVWF, popRegFromIdx (Gstack_base_addr)); + mov2w_op (dst, 2); + call_libraryfunc ("__gptrput1"); + break; + + default: + assert (!"unhandled pointer type"); + break; + } +} + +/*-----------------------------------------------------------------*/ +/* genUnpackBits - generates code for unpacking bits */ +/*-----------------------------------------------------------------*/ +static void +genUnpackBits (operand * result, operand * left, int ptype, iCode * ifx) +{ + sym_link *etype; /* bitfield type information */ + unsigned blen; /* bitfield length */ + unsigned bstr; /* bitfield starting bit within byte */ + + FENTRY; + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + etype = getSpec (operandType (result)); + blen = SPEC_BLEN (etype); + bstr = SPEC_BSTR (etype); + + /* single bit field case */ + if (blen == 1) + { + if (ifx) + { + /* that is for an if statement */ + pCodeOp *pcop; + resolvedIfx rIfx; + + resolveIfx (&rIfx, ifx); + if (ptype == -1) /* direct */ + pcop = newpCodeOpBit (aopGet (AOP (left), 0, FALSE, FALSE), bstr, 0); + else + { + setup_fsr (left); + pcop = newpCodeOpBit (pc_indf->pcop.name, bstr, 0); + } + emitpcode ((rIfx.condition) ? POC_BTFSC : POC_BTFSS, pcop); + emitpcode (POC_GOTO, popGetLabel (rIfx.lbl->key)); + ifx->generated = TRUE; + } + else + { + /* + * In case of a volatile bitfield read such as + * (void)PORTCbits.RC3; + * we end up having no result ... + */ + int haveResult = !!AOP_SIZE(result); + + if (haveResult) + { + assert (!pic14_sameRegs (AOP (result), AOP (left))); + emitpcode (POC_CLRF, popGet (AOP (result), 0)); + } // if + + switch (ptype) + { + case -1: + emitpcode (POC_BTFSC, newpCodeOpBit (aopGet (AOP (left), 0, FALSE, FALSE), bstr, 0)); + /* If haveResult, adjust result below, otherwise: */ + if (!haveResult) + { + /* Dummy instruction to allow bit-test above (volatile dummy bitfield read). */ + emitpcode (POC_MOVLW, popGetLit (0)); + } // if + break; + + case POINTER: + case FPOINTER: + case GPOINTER: + case CPOINTER: + emitPtrByteGet (left, ptype, FALSE); + if (haveResult) + { + emitpcode (POC_ANDLW, popGetLit (1UL << bstr)); + emitSKPZ; + /* adjust result below */ + } // if + break; + + default: + assert (!"unhandled pointer type"); + } // switch + + /* move sign-/zero extended bit to result */ + if (haveResult) + { + if (SPEC_USIGN (OP_SYM_ETYPE (left))) + emitpcode (POC_INCF, popGet (AOP (result), 0)); + else + emitpcode (POC_DECF, popGet (AOP (result), 0)); + addSign (result, 1, !SPEC_USIGN (OP_SYM_ETYPE (left))); + } // if + } + return; + } + else if (blen <= 8 && ((blen + bstr) <= 8)) + { + /* blen > 1 */ + int i; + + for (i = 0; i < AOP_SIZE (result); i++) + emitpcode (POC_CLRF, popGet (AOP (result), i)); + + switch (ptype) + { + case -1: + mov2w (AOP (left), 0); + break; + + case POINTER: + case FPOINTER: + case GPOINTER: + case CPOINTER: + emitPtrByteGet (left, ptype, FALSE); + break; + + default: + assert (!"unhandled pointer type"); + } // switch + + if (blen < 8) + emitpcode (POC_ANDLW, popGetLit ((((1UL << blen) - 1) << bstr) & 0x00ff)); + movwf (AOP (result), 0); + AccRsh (popGet (AOP (result), 0), bstr, 1); /* zero extend the bitfield */ + + if (!SPEC_USIGN (OP_SYM_ETYPE (left)) && (bstr + blen != 8)) + { + /* signed bitfield */ + assert (bstr + blen > 0); + emitpcode (POC_MOVLW, popGetLit (0x00ff << (bstr + blen))); + emitpcode (POC_BTFSC, newpCodeOpBit (aopGet (AOP (result), 0, FALSE, FALSE), bstr + blen - 1, 0)); + emitpcode (POC_IORWF, popGet (AOP (result), 0)); + } + addSign (result, 1, !SPEC_USIGN (OP_SYM_ETYPE (left))); + return; + } + + assert (!"bitfields larger than 8 bits or crossing byte boundaries are not yet supported"); +} + +#if 1 +/*-----------------------------------------------------------------*/ +/* genDataPointerGet - generates code when ptr offset is known */ +/*-----------------------------------------------------------------*/ +static void +genDataPointerGet (operand * left, operand * result, iCode * ic) +{ + unsigned int size; + int offset = 0; + + FENTRY; + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + + + /* optimization - most of the time, left and result are the same + * address, but different types. for the pic code, we could omit + * the following + */ + aopOp (result, ic, TRUE); + + if (pic14_sameRegs (AOP (left), AOP (result))) + return; + + DEBUGpic14_AopType (__LINE__, left, NULL, result); + + //emitpcode(POC_MOVFW, popGet(AOP(left),0)); + + size = AOP_SIZE (result); + if (size > getSize (OP_SYM_ETYPE (left))) + size = getSize (OP_SYM_ETYPE (left)); + + offset = 0; + while (size--) + { + emitpcode (POC_MOVFW, popGet (AOP (left), offset)); + emitpcode (POC_MOVWF, popGet (AOP (result), offset)); + offset++; + } + + freeAsmop (left, NULL, ic, TRUE); + freeAsmop (result, NULL, ic, TRUE); +} +#endif + +/*-----------------------------------------------------------------*/ +/* genNearPointerGet - pic14_emitcode for near pointer fetch */ +/*-----------------------------------------------------------------*/ +static void +genNearPointerGet (operand * left, operand * result, iCode * ic) +{ + asmop *aop = NULL; + sym_link *ltype = operandType (left); + sym_link *rtype = operandType (result); + sym_link *retype = getSpec (rtype); /* bitfield type information */ + int direct = 0; + + FENTRY; + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + + + 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_PCODE && //AOP_TYPE(left) == AOP_IMMD && + !IS_BITVAR (retype) && PIC_IS_DATA_PTR (ltype)) + { + genDataPointerGet (left, result, ic); + return; + } + + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + aopOp (result, ic, FALSE); + + /* Check if can access directly instead of via a pointer */ + if ((AOP_TYPE (left) == AOP_PCODE) && (AOP (left)->aopu.pcop->type == PO_IMMEDIATE) && (AOP_SIZE (result) <= 1)) + { + direct = 1; + } + + if (IS_BITFIELD (getSpec (operandType (result)))) + { + genUnpackBits (result, left, direct ? -1 : POINTER, ifxForOp (IC_RESULT (ic), ic)); + goto release; + } + + /* If the pointer value is not in a the FSR then need to put it in */ + /* Must set/reset IRP bit for use with FSR. */ + if (!direct) + setup_fsr (left); + +// sym_link *etype; + /* if bitfield then unpack the bits */ + { + /* we have can just get the values */ + int size = AOP_SIZE (result); + int offset = 0; + + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + + while (size--) + { + if (direct) + emitpcode (POC_MOVWF, popGet (AOP (left), 0)); + else + emitpcode (POC_MOVFW, popCopyReg (pc_indf)); + if (AOP_TYPE (result) == AOP_LIT) + { + emitpcode (POC_MOVLW, popGet (AOP (result), offset)); + } + else + { + emitpcode (POC_MOVWF, popGet (AOP (result), offset)); + } + if (size && !direct) + { + inc_fsr (1); + } + offset++; + } + } + + /* now some housekeeping stuff */ + if (aop) + { + /* we had to allocate for this iCode */ + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + freeAsmop (NULL, aop, ic, TRUE); + } + else if (!direct) + { + /* nothing to do */ + } + 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 */ + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + if (AOP_SIZE (result) > 1 && !OP_SYMBOL (left)->remat && (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) + { + int size = AOP_SIZE (result) - 1; + inc_fsr (-size); + } + } + +release: + /* done */ + freeAsmop (left, NULL, ic, TRUE); + freeAsmop (result, NULL, ic, TRUE); + +} + +/*-----------------------------------------------------------------*/ +/* genGenPointerGet - gget value from generic pointer space */ +/*-----------------------------------------------------------------*/ +static void +genGenPointerGet (operand * left, operand * result, iCode * ic) +{ + FENTRY; + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + aopOp (left, ic, FALSE); + aopOp (result, ic, FALSE); + + + DEBUGpic14_AopType (__LINE__, left, NULL, result); + + if (IS_BITFIELD (getSpec (operandType (result)))) + { + genUnpackBits (result, left, GPOINTER, ifxForOp (IC_RESULT (ic), ic)); + return; + } + + { + /* emit call to __gptrget */ + char *func[] = { NULL, "__gptrget1", "__gptrget2", "__gptrget3", "__gptrget4" }; + int size = AOP_SIZE (result); + int idx = 0; + + assert (size > 0 && size <= 4); + + /* pass arguments */ + assert (AOP_SIZE (left) == 3); + mov2w (AOP (left), 0); + emitpcode (POC_MOVWF, popRegFromIdx (Gstack_base_addr - 1)); + mov2w (AOP (left), 1); + emitpcode (POC_MOVWF, popRegFromIdx (Gstack_base_addr)); + mov2w (AOP (left), 2); + call_libraryfunc (func[size]); + + /* save result */ + movwf (AOP (result), --size); + while (size--) + { + emitpcode (POC_MOVFW, popRegFromIdx (Gstack_base_addr - idx++)); + movwf (AOP (result), size); + } // while + } + + freeAsmop (left, NULL, ic, TRUE); + freeAsmop (result, NULL, ic, TRUE); + +} + +/*-----------------------------------------------------------------*/ +/* genConstPointerGet - get value from const generic pointer space */ +/*-----------------------------------------------------------------*/ +static void +genConstPointerGet (operand * left, operand * result, iCode * ic) +{ + //sym_link *retype = getSpec(operandType(result)); +#if 0 + symbol *albl, *blbl; //, *clbl; + pCodeOp *pcop; +#endif + int i, lit; + + FENTRY; + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + aopOp (left, ic, FALSE); + aopOp (result, ic, FALSE); + + DEBUGpic14_AopType (__LINE__, left, NULL, result); + + DEBUGpic14_emitcode ("; ", " %d getting const pointer", __LINE__); + + lit = op_isLitLike (left); + + if (IS_BITFIELD (getSpec (operandType (result)))) + { + genUnpackBits (result, left, lit ? -1 : CPOINTER, ifxForOp (IC_RESULT (ic), ic)); + goto release; + } + + { + char *func[] = { NULL, "__gptrget1", "__gptrget2", "__gptrget3", "__gptrget4" }; + int size = AOP_SIZE (result); + assert (size > 0 && size <= 4); + + mov2w_op (left, 0); + emitpcode (POC_MOVWF, popRegFromIdx (Gstack_base_addr - 1)); + mov2w_op (left, 1); + emitpcode (POC_MOVWF, popRegFromIdx (Gstack_base_addr)); + emitpcode (POC_MOVLW, popGetLit (GPTRTAG_CODE)); /* GPOINTER tag for __code space */ + call_libraryfunc (func[size]); + + movwf (AOP (result), size - 1); + for (i = 1; i < size; i++) + { + emitpcode (POC_MOVFW, popRegFromIdx (Gstack_base_addr + 1 - i)); + movwf (AOP (result), size - 1 - i); + } // for + } + +release: + freeAsmop (left, NULL, ic, TRUE); + freeAsmop (result, NULL, ic, TRUE); + +} + +/*-----------------------------------------------------------------*/ +/* genPointerGet - generate code for pointer get */ +/*-----------------------------------------------------------------*/ +static void +genPointerGet (iCode * ic) +{ + operand *left, *result; + sym_link *type, *etype; + int p_type = -1; + + FENTRY; + DEBUGpic14_emitcode ("; ***", "%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 (IS_PTR_CONST (type)) + DEBUGpic14_emitcode ("; ***", "%d - const pointer", __LINE__); + + /* 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)); + + DEBUGpic14_emitcode ("; ***", "%d - resolve pointer by storage class", __LINE__); + + if (SPEC_OCLS (etype)->codesp) + { + DEBUGpic14_emitcode ("; ***", "%d - cpointer", __LINE__); + //p_type = CPOINTER ; + } + else if (SPEC_OCLS (etype)->fmap && !SPEC_OCLS (etype)->paged) + DEBUGpic14_emitcode ("; ***", "%d - fpointer", __LINE__); + /*p_type = FPOINTER ; */ + else if (SPEC_OCLS (etype)->fmap && SPEC_OCLS (etype)->paged) + DEBUGpic14_emitcode ("; ***", "%d - ppointer", __LINE__); + /* p_type = PPOINTER; */ + else if (SPEC_OCLS (etype) == idata) + DEBUGpic14_emitcode ("; ***", "%d - ipointer", __LINE__); + /* p_type = IPOINTER; */ + else + DEBUGpic14_emitcode ("; ***", "%d - pointer", __LINE__); + /* p_type = POINTER ; */ + } + + /* now that we have the pointer type we assign + the pointer values */ + switch (p_type) + { + + case POINTER: + case FPOINTER: + //case IPOINTER: + genNearPointerGet (left, result, ic); + break; + /* + case PPOINTER: + genPagedPointerGet(left,result,ic); + break; + + case FPOINTER: + genFarPointerGet (left,result,ic); + break; + */ + case CPOINTER: + genConstPointerGet (left, result, ic); + break; + + case GPOINTER: + genGenPointerGet (left, result, ic); + break; + default: + assert (!"unhandled pointer type"); + break; + } + +} + +/*-----------------------------------------------------------------*/ +/* genPackBits - generates code for packed bit storage */ +/*-----------------------------------------------------------------*/ +static void +genPackBits (sym_link * etype, operand * result, operand * right, int p_type) +{ + unsigned blen; /* bitfield length */ + unsigned bstr; /* bitfield starting bit within byte */ + int litval; /* source literal value (if AOP_LIT) */ + unsigned char mask; /* bitmask within current byte */ + + FENTRY; + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + + blen = SPEC_BLEN (etype); + bstr = SPEC_BSTR (etype); + + /* If the bitfield length is less than a byte and does not cross byte boundaries */ + if ((blen <= 8) && ((bstr + blen) <= 8)) + { + mask = ((unsigned char) (0xFF << (blen + bstr)) | (unsigned char) (0xFF >> (8 - bstr))); + + if (AOP_TYPE (right) == AOP_LIT) + { + /* Case with a bitfield length <8 and literal source */ + int lit = (int) ulFromVal (AOP (right)->aopu.aop_lit); + if (blen == 1) + { + pCodeOp *pcop; + + switch (p_type) + { + case -1: + if (AOP (result)->type == AOP_PCODE) + pcop = newpCodeOpBit (aopGet (AOP (result), 0, FALSE, FALSE), bstr, 0); + else + pcop = popGet (AOP (result), 0); + emitpcode (lit ? POC_BSF : POC_BCF, pcop); + break; + + case POINTER: + case FPOINTER: + setup_fsr (result); + emitpcode (lit ? POC_BSF : POC_BCF, newpCodeOpBit (PCOP (pc_indf)->name, bstr, 0)); + break; + + case CPOINTER: + assert (!"trying to assign to bitfield via pointer to __code space"); + break; + + case GPOINTER: + emitPtrByteGet (result, p_type, FALSE); + if (lit) + { + emitpcode (POC_IORLW, newpCodeOpLit (1UL << bstr)); + } + else + { + emitpcode (POC_ANDLW, newpCodeOpLit ((~(1UL << bstr)) & 0x0ff)); + } + emitPtrByteSet (result, p_type, TRUE); + break; + + default: + assert (!"unhandled pointer type"); + break; + } // switch (p_type) + } + else + { + /* blen > 1 */ + litval = lit << bstr; + litval &= (~mask) & 0x00ff; + + switch (p_type) + { + case -1: + mov2w (AOP (result), 0); + if ((litval | mask) != 0x00ff) + emitpcode (POC_ANDLW, popGetLit (mask)); + if (litval != 0x00) + emitpcode (POC_IORLW, popGetLit (litval)); + movwf (AOP (result), 0); + break; + + case POINTER: + case FPOINTER: + case GPOINTER: + emitPtrByteGet (result, p_type, FALSE); + if ((litval | mask) != 0x00ff) + emitpcode (POC_ANDLW, popGetLit (mask)); + if (litval != 0x00) + emitpcode (POC_IORLW, popGetLit (litval)); + emitPtrByteSet (result, p_type, TRUE); + break; + + case CPOINTER: + assert (!"trying to assign to bitfield via pointer to __code space"); + break; + + default: + assert (!"unhandled pointer type"); + break; + } // switch + } // if (blen > 1) + } + else + { + /* right is no literal */ + if (blen == 1) + { + switch (p_type) + { + case -1: + /* Note more efficient code, of pre clearing bit then only setting it if required, + * can only be done if it is known that the result is not a SFR */ + emitpcode (POC_RRFW, popGet (AOP (right), 0)); + emitSKPC; + emitpcode (POC_BCF, newpCodeOpBit (aopGet (AOP (result), 0, FALSE, FALSE), bstr, 0)); + emitSKPNC; + emitpcode (POC_BSF, newpCodeOpBit (aopGet (AOP (result), 0, FALSE, FALSE), bstr, 0)); + break; + + case POINTER: + case FPOINTER: + case GPOINTER: + emitPtrByteGet (result, p_type, FALSE); + emitpcode (POC_BTFSS, newpCodeOpBit (aopGet (AOP (right), 0, FALSE, FALSE), bstr, 0)); + emitpcode (POC_ANDLW, newpCodeOpLit (~(1UL << bstr) & 0x0ff)); + emitpcode (POC_BTFSC, newpCodeOpBit (aopGet (AOP (right), 0, FALSE, FALSE), bstr, 0)); + emitpcode (POC_IORLW, newpCodeOpLit ((1UL << bstr) & 0x0ff)); + emitPtrByteSet (result, p_type, TRUE); + break; + + case CPOINTER: + assert (!"trying to assign to bitfield via pointer to __code space"); + break; + + default: + assert (!"unhandled pointer type"); + break; + } // switch + return; + } + else + { + /* Case with a bitfield 1 < length <= 8 and arbitrary source */ + pCodeOp *temp = popGetTempReg (); + + mov2w (AOP (right), 0); + if (blen < 8) + { + emitpcode (POC_ANDLW, popGetLit ((1UL << blen) - 1)); + } + emitpcode (POC_MOVWF, temp); + if (bstr) + { + AccLsh (temp, bstr); + } + + switch (p_type) + { + case -1: + mov2w (AOP (result), 0); + emitpcode (POC_ANDLW, popGetLit (mask)); + emitpcode (POC_IORFW, temp); + movwf (AOP (result), 0); + break; + + case POINTER: + case FPOINTER: + case GPOINTER: + emitPtrByteGet (result, p_type, FALSE); + emitpcode (POC_ANDLW, popGetLit (mask)); + emitpcode (POC_IORFW, temp); + emitPtrByteSet (result, p_type, TRUE); + break; + + case CPOINTER: + assert (!"trying to assign to bitfield via pointer to __code space"); + break; + + default: + assert (!"unhandled pointer type"); + break; + } // switch + + popReleaseTempReg (temp); + } // if (blen > 1) + } // if (AOP(right)->type != AOP_LIT) + return; + } // if (blen <= 8 && ((blen + bstr) <= 8)) + + assert (!"bitfields larger than 8 bits or crossing byte boundaries are not yet supported"); +} + +/*-----------------------------------------------------------------*/ +/* genDataPointerSet - remat pointer to data space */ +/*-----------------------------------------------------------------*/ +static void +genDataPointerSet (operand * right, operand * result, iCode * ic) +{ + int size = 0; + int offset = 0; + sym_link *rtype = operandType(right); + + FENTRY; + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + aopOp (right, ic, FALSE); + aopOp (result, ic, FALSE); + + assert (IS_SYMOP (result)); + assert (IS_PTR (OP_SYM_TYPE (result))); + + /* + * Determine size from right operand (not result): + * The result might be a rematerialized pointer to (the first field in) a struct, + * which then assumes the type (and size) of the struct rather than the first field. + */ + size = AOP_SIZE(right); + + /*test the right operand has a pointer value*/ + if ((AOP_TYPE(right) == AOP_PCODE) && PIC_IS_DATA_PTR(rtype)) + { + while (size--) + { + emitpcode(POC_MOVLW, popGetAddr(AOP(right), size, 0)); + emitpcode(POC_MOVWF, popGet(AOP(result), size)); + } + } + else + { + // tsd, was l+1 - the underline `_' prefix was being stripped + while (size--) + { + emitpComment ("%s:%u: size=%d, offset=%d, AOP_TYPE(res)=%d", __FILE__, __LINE__, size, offset, + AOP_TYPE (result)); + + if (AOP_TYPE (right) == AOP_LIT) + { + unsigned int lit = pic14aopLiteral (AOP (IC_RIGHT (ic))->aopu.aop_lit, offset); + //fprintf (stderr, "%s:%u: lit %d 0x%x\n", __FUNCTION__,__LINE__, lit, lit); + if (lit & 0xff) + { + emitpcode (POC_MOVLW, popGetLit (lit & 0xff)); + emitpcode (POC_MOVWF, popGet (AOP (result), offset)); + } + else + { + emitpcode (POC_CLRF, popGet (AOP (result), offset)); + } + } + else + { + //fprintf (stderr, "%s:%u: no lit\n", __FUNCTION__,__LINE__); + emitpcode (POC_MOVFW, popGet (AOP (right), offset)); + emitpcode (POC_MOVWF, popGet (AOP (result), offset)); + } + offset++; + } + } + + freeAsmop (right, NULL, ic, TRUE); + freeAsmop (result, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genNearPointerSet - pic14_emitcode for near pointer put */ +/*-----------------------------------------------------------------*/ +static void +genNearPointerSet (operand * right, operand * result, iCode * ic) +{ + asmop *aop = NULL; + sym_link *ptype = operandType (result); + sym_link *retype = getSpec (operandType (right)); + sym_link *letype = getSpec (ptype); + int direct = 0; + + + FENTRY; + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + aopOp (result, ic, FALSE); + +#if 1 + /* if the result is rematerializable & + in data space & not a bit variable */ + //if (AOP_TYPE(result) == AOP_IMMD && + if (AOP_TYPE (result) == AOP_PCODE && PIC_IS_DATA_PTR (ptype) && !IS_BITVAR (retype) && !IS_BITVAR (letype)) + { + genDataPointerSet (right, result, ic); + freeAsmop (result, NULL, ic, TRUE); + return; + } +#endif + + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + aopOp (right, ic, FALSE); + DEBUGpic14_AopType (__LINE__, NULL, right, result); + + /* Check if can access directly instead of via a pointer */ + if ((AOP_TYPE (result) == AOP_PCODE) && (AOP (result)->aopu.pcop->type == PO_IMMEDIATE) && (AOP_SIZE (right) == 1)) + { + direct = 1; + } + + if (IS_BITFIELD (letype)) + { + genPackBits (letype, result, right, direct ? -1 : POINTER); + return; + } + + /* If the pointer value is not in a the FSR then need to put it in */ + /* Must set/reset IRP bit for use with FSR. */ + /* Note only do this once - assuming that never need to cross a bank boundary at address 0x100. */ + if (!direct) + setup_fsr (result); + + { + /* we have can just get the values */ + int size = AOP_SIZE (right); + int offset = 0; + + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + while (size--) + { + char *l = aopGet (AOP (right), offset, FALSE, TRUE); + if (*l == '@') + { + emitpcode (POC_MOVFW, popCopyReg (pc_indf)); + } + else + { + if (AOP_TYPE (right) == AOP_LIT) + { + emitpcode (POC_MOVLW, popGet (AOP (right), offset)); + } + else + { + emitpcode (POC_MOVFW, popGet (AOP (right), offset)); + } + if (direct) + emitpcode (POC_MOVWF, popGet (AOP (result), 0)); + else + emitpcode (POC_MOVWF, popCopyReg (pc_indf)); + } + if (size && !direct) + inc_fsr (1); + offset++; + } + } + + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + /* now some housekeeping stuff */ + if (aop) + { + /* we had to allocate for this iCode */ + freeAsmop (NULL, aop, ic, TRUE); + } + else if (!direct) + { + /* nothing to do */ + } + 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 */ + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + if (AOP_SIZE (right) > 1 && !OP_SYMBOL (result)->remat && (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) + { + int size = AOP_SIZE (right) - 1; + inc_fsr (-size); + } + } + + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + /* done */ + + freeAsmop (right, NULL, ic, TRUE); + freeAsmop (result, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genGenPointerSet - set value from generic pointer space */ +/*-----------------------------------------------------------------*/ +static void +genGenPointerSet (operand * right, operand * result, iCode * ic) +{ + sym_link *retype = getSpec (operandType (result)); + + FENTRY; + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + aopOp (right, ic, FALSE); + aopOp (result, ic, FALSE); + + + DEBUGpic14_AopType (__LINE__, right, NULL, result); + + if (IS_BITFIELD (retype)) + { + genPackBits (retype, result, right, GPOINTER); + return; + } + + { + /* emit call to __gptrput */ + char *func[] = { NULL, "__gptrput1", "__gptrput2", "__gptrput3", "__gptrput4" }; + int size = AOP_SIZE (right); + int idx = 0; + + /* The following assertion fails for + * struct foo { char a; char b; } bar; + * void demo(struct foo *dst, char c) { dst->b = c; } + * as size will be 1 (sizeof(c)), whereas dst->b will be accessed + * using (((char *)dst)+1), whose OP_SYM_ETYPE still is struct foo + * of size 2. + * The frontend seems to guarantee that IC_LEFT has the correct size, + * it works fine both for larger and smaller types of `char c'. + * */ + //assert (size == getSize(OP_SYM_ETYPE(result))); + assert (size > 0 && size <= 4); + + /* pass arguments */ + /* - value (MSB in Gstack_base_addr-2, growing downwards) */ + { + int off = size; + idx = 2; + while (off--) + { + mov2w_op (right, off); + emitpcode (POC_MOVWF, popRegFromIdx (Gstack_base_addr - idx++)); + } + idx = 0; + } + /* - address */ + assert (AOP_SIZE (result) == 3); + mov2w (AOP (result), 0); + emitpcode (POC_MOVWF, popRegFromIdx (Gstack_base_addr - 1)); + mov2w (AOP (result), 1); + emitpcode (POC_MOVWF, popRegFromIdx (Gstack_base_addr)); + mov2w (AOP (result), 2); + call_libraryfunc (func[size]); + } + + freeAsmop (right, NULL, ic, TRUE); + freeAsmop (result, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genPointerSet - stores the value into a pointer location */ +/*-----------------------------------------------------------------*/ +static void +genPointerSet (iCode * ic) +{ + operand *right, *result; + sym_link *type, *etype; + int p_type; + + FENTRY; + DEBUGpic14_emitcode ("; ***", "%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 FPOINTER: + //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; + + default: + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "genPointerSet: illegal pointer type"); + } +} + +/*-----------------------------------------------------------------*/ +/* genIfx - generate code for Ifx statement */ +/*-----------------------------------------------------------------*/ +static void +genIfx (iCode * ic, iCode * popIc) +{ + operand *cond = IC_COND (ic); + int isbit = 0; + + FENTRY; + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + + aopOp (cond, ic, FALSE); + + /* get the value into acc */ + if (AOP_TYPE (cond) != AOP_CRY) + pic14_toBoolean (cond); + else + isbit = 1; + + /* if there was something to be popped then do it */ + if (popIc) + genIpop (popIc); + + if (isbit) + { + /* This assumes that CARRY is set iff cond is true */ + if (IC_TRUE (ic)) + { + assert (!IC_FALSE (ic)); + emitpcode (POC_BTFSC, popGet (AOP (cond), 0)); + //emitSKPNC; + emitpcode (POC_GOTO, popGetLabel (IC_TRUE (ic)->key)); + } + else + { + assert (IC_FALSE (ic)); + emitpcode (POC_BTFSS, popGet (AOP (cond), 0)); + //emitSKPC; + emitpcode (POC_GOTO, popGetLabel (IC_FALSE (ic)->key)); + } + if (0) + { + static int hasWarned = 0; + if (!hasWarned) + { + fprintf (stderr, "WARNING: using untested code for %s:%u -- please check the .asm output and report bugs.\n", + ic->filename, ic->lineno); + hasWarned = 1; + } + } + } + else + { + /* now Z is set iff !cond */ + if (IC_TRUE (ic)) + { + assert (!IC_FALSE (ic)); + emitSKPZ; + emitpcode (POC_GOTO, popGetLabel (IC_TRUE (ic)->key)); + } + else + { + emitSKPNZ; + emitpcode (POC_GOTO, popGetLabel (IC_FALSE (ic)->key)); + } + } + + ic->generated = TRUE; + + /* the result is now in the accumulator */ + freeAsmop (cond, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genAddrOf - generates code for address of */ +/*-----------------------------------------------------------------*/ +static void +genAddrOf (iCode * ic) +{ + operand *right, *result, *left; + int size, offset; + + FENTRY; + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + + + //aopOp(IC_RESULT(ic),ic,FALSE); + + aopOp ((left = IC_LEFT (ic)), ic, FALSE); + aopOp ((right = IC_RIGHT (ic)), ic, FALSE); + aopOp ((result = IC_RESULT (ic)), ic, TRUE); + + DEBUGpic14_AopType (__LINE__, left, right, result); + assert (IS_SYMOP (left)); + + /* sanity check: generic pointers to code space are not yet supported, + * pionters to codespace must not be assigned addresses of __data values. */ +#if 0 + fprintf (stderr, "result: %s, left: %s\n", OP_SYMBOL (result)->name, OP_SYMBOL (left)->name); + fprintf (stderr, "result->type : "); + printTypeChain (OP_SYM_TYPE (result), stderr); + fprintf (stderr, ", codesp:%d, codeptr:%d, constptr:%d\n", IN_CODESPACE (SPEC_OCLS (getSpec (OP_SYM_TYPE (result)))), + IS_CODEPTR (OP_SYM_TYPE (result)), IS_PTR_CONST (OP_SYM_TYPE (result))); + fprintf (stderr, "result->etype: "); + printTypeChain (OP_SYM_ETYPE (result), stderr); + fprintf (stderr, ", codesp:%d, codeptr:%d, constptr:%d\n", IN_CODESPACE (SPEC_OCLS (getSpec (OP_SYM_ETYPE (result)))), + IS_CODEPTR (OP_SYM_ETYPE (result)), IS_PTR_CONST (OP_SYM_ETYPE (result))); + fprintf (stderr, "left->type : "); + printTypeChain (OP_SYM_TYPE (left), stderr); + fprintf (stderr, ", codesp:%d, codeptr:%d, constptr:%d\n", IN_CODESPACE (SPEC_OCLS (getSpec (OP_SYM_TYPE (left)))), + IS_CODEPTR (OP_SYM_TYPE (left)), IS_PTR_CONST (OP_SYM_TYPE (left))); + fprintf (stderr, "left->etype : "); + printTypeChain (OP_SYM_ETYPE (left), stderr); + fprintf (stderr, ", codesp:%d, codeptr:%d, constptr:%d\n", IN_CODESPACE (SPEC_OCLS (getSpec (OP_SYM_ETYPE (left)))), + IS_CODEPTR (OP_SYM_ETYPE (left)), IS_PTR_CONST (OP_SYM_ETYPE (left))); +#endif + + if (IS_SYMOP (result) && IS_CODEPTR (OP_SYM_TYPE (result)) && !IN_CODESPACE (SPEC_OCLS (getSpec (OP_SYM_TYPE (left))))) + { + fprintf (stderr, "trying to assign __code pointer (%s) an address in __data space (&%s) -- expect trouble\n", + IS_SYMOP (result) ? OP_SYMBOL (result)->name : "unknown", OP_SYMBOL (left)->name); + } + else if (IS_SYMOP (result) && !IS_CODEPTR (OP_SYM_TYPE (result)) && IN_CODESPACE (SPEC_OCLS (getSpec (OP_SYM_TYPE (left))))) + { + fprintf (stderr, "trying to assign __data pointer (%s) an address in __code space (&%s) -- expect trouble\n", + IS_SYMOP (result) ? OP_SYMBOL (result)->name : "unknown", OP_SYMBOL (left)->name); + } + + size = AOP_SIZE (IC_RESULT (ic)); + if (IS_SYMOP (result) && IS_GENPTR (OP_SYM_TYPE (result))) + { + /* strip tag */ + if (size > GPTRSIZE - 1) + size = GPTRSIZE - 1; + } + offset = 0; + + while (size--) + { + /* fixing bug #863624, reported from (errolv) */ + emitpcode (POC_MOVLW, popGetImmd (OP_SYMBOL (left)->rname, offset, 0, IS_FUNC (OP_SYM_TYPE (left)))); + emitpcode (POC_MOVWF, popGet (AOP (result), offset)); + +#if 0 + emitpcode (POC_MOVLW, popGet (AOP (left), offset)); + emitpcode (POC_MOVWF, popGet (AOP (result), offset)); +#endif + offset++; + } + + if (IS_SYMOP (result) && IS_GENPTR (OP_SYM_TYPE (result))) + { + /* provide correct tag */ + int isCode = IN_CODESPACE (SPEC_OCLS (getSpec (OP_SYM_TYPE (left)))); + emitpcode (POC_MOVLW, popGetLit (isCode ? GPTRTAG_CODE : GPTRTAG_DATA)); + movwf (AOP (result), 2); + } + + freeAsmop (left, NULL, ic, FALSE); + freeAsmop (result, NULL, ic, TRUE); + +} + +/*-----------------------------------------------------------------*/ +/* genAssign - generate code for assignment */ +/*-----------------------------------------------------------------*/ +static void +genAssign (iCode * ic) +{ + operand *result, *right; + int size, offset, know_W; + unsigned long lit = 0L; + + result = IC_RESULT (ic); + right = IC_RIGHT (ic); + + FENTRY; + DEBUGpic14_emitcode ("; ***", "%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); + + DEBUGpic14_AopType (__LINE__, NULL, right, result); + + /* if they are the same registers */ + if (pic14_sameRegs (AOP (right), AOP (result))) + goto release; + + /* special case: assign from __code */ + if (!IS_ITEMP (right) /* --> iTemps never reside in __code */ + && IS_SYMOP (right) /* --> must be an immediate (otherwise we would be in genConstPointerGet) */ + && !IS_FUNC (OP_SYM_TYPE (right)) /* --> we would want its address instead of the first instruction */ + && !IS_CODEPTR (OP_SYM_TYPE (right)) /* --> get symbols address instread */ + && IN_CODESPACE (SPEC_OCLS (getSpec (OP_SYM_TYPE (right))))) + { + emitpComment ("genAssign from CODESPACE"); + genConstPointerGet (right, result, ic); + goto release; + } + + /* just for symmetry reasons... */ + if (!IS_ITEMP (result) && IS_SYMOP (result) && IN_CODESPACE (SPEC_OCLS (getSpec (OP_SYM_TYPE (result))))) + { + assert (!"cannot write to CODESPACE"); + } + + /* 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) + { + + emitpcode ((((int) operandLitValue (right)) ? POC_BSF : POC_BCF), popGet (AOP (result), 0)); + + if (((int) operandLitValue (right))) + pic14_emitcode ("bsf", "(%s >> 3),(%s & 7)", AOP (result)->aopu.aop_dir, AOP (result)->aopu.aop_dir); + else + pic14_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) + { + emitpcode (POC_BCF, popGet (AOP (result), 0)); + emitpcode (POC_BTFSC, popGet (AOP (right), 0)); + emitpcode (POC_BSF, popGet (AOP (result), 0)); + + pic14_emitcode ("bcf", "(%s >> 3),(%s & 7)", AOP (result)->aopu.aop_dir, AOP (result)->aopu.aop_dir); + pic14_emitcode ("btfsc", "(%s >> 3),(%s & 7)", AOP (right)->aopu.aop_dir, AOP (right)->aopu.aop_dir); + pic14_emitcode ("bsf", "(%s >> 3),(%s & 7)", AOP (result)->aopu.aop_dir, AOP (result)->aopu.aop_dir); + goto release; + } + + /* we need to or */ + emitpcode (POC_BCF, popGet (AOP (result), 0)); + pic14_toBoolean (right); + emitSKPZ; + emitpcode (POC_BSF, popGet (AOP (result), 0)); + //aopPut(AOP(result),"a",0); + goto release; + } + + /* bit variables done */ + /* general case */ + size = AOP_SIZE (result); + offset = 0; + if (AOP_TYPE (right) == AOP_DIR && (AOP_TYPE (result) == AOP_REG) && size == 1) + { + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + if (aopIdx (AOP (result), 0) == 4) + { + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + emitpcode (POC_MOVFW, popGet (AOP (right), offset)); + emitpcode (POC_MOVWF, popGet (AOP (result), offset)); + goto release; + } + else + DEBUGpic14_emitcode ("; WARNING", "%s %d ignoring register storage", __FUNCTION__, __LINE__); + } + + know_W = -1; + while (size--) + { + + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + if (AOP_TYPE (right) == AOP_LIT) + { + lit = (unsigned long) pic14aopLiteral (AOP (right)->aopu.aop_lit, offset) & 0x0ff; + if (lit & 0xff) + { + if (know_W != (int) (lit & 0xff)) + emitpcode (POC_MOVLW, popGetLit (lit & 0xff)); + know_W = lit & 0xff; + emitpcode (POC_MOVWF, popGet (AOP (result), offset)); + } + else + emitpcode (POC_CLRF, popGet (AOP (result), offset)); + + } + else if (AOP_TYPE (right) == AOP_CRY) + { + emitpcode (POC_CLRF, popGet (AOP (result), offset)); + if (offset == 0) + { + emitpcode (POC_BTFSS, popGet (AOP (right), 0)); + emitpcode (POC_INCF, popGet (AOP (result), 0)); + } + } + else + { + mov2w_op (right, offset); + emitpcode (POC_MOVWF, popGet (AOP (result), offset)); + } + + offset++; + } + + +release: + freeAsmop (right, NULL, ic, FALSE); + freeAsmop (result, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genJumpTab - generates code for jump table */ +/*-----------------------------------------------------------------*/ +static void +genJumpTab (iCode * ic) +{ + symbol *jtab; + char *l; + + FENTRY; + DEBUGpic14_emitcode ("; ***", "%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 */ + pic14_emitcode ("add", "a,acc"); + pic14_emitcode ("add", "a,%s", aopGet (AOP (IC_JTCOND (ic)), 0, FALSE, FALSE)); + + jtab = newiTempLabel (NULL); + pic14_emitcode ("mov", "dptr,#%05d_DS_", labelKey2num (jtab->key)); + pic14_emitcode ("jmp", "@a+dptr"); + pic14_emitcode ("", "%05d_DS_:", labelKey2num (jtab->key)); + + emitpcode (POC_MOVLW, popGetHighLabel (jtab->key)); + emitpcode (POC_MOVWF, popCopyReg (&pc_pclath)); + emitpcode (POC_MOVLW, popGetLabel (jtab->key)); + emitpcode (POC_ADDFW, popGet (AOP (IC_JTCOND (ic)), 0)); + emitSKPNC; + emitpcode (POC_INCF, popCopyReg (&pc_pclath)); + emitpcode (POC_MOVWF, popCopyReg (&pc_pcl)); + emitpLabel (jtab->key); + + freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE); + + /* now generate the jump labels */ + for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab; jtab = setNextItem (IC_JTLABELS (ic))) + { + pic14_emitcode ("ljmp", "%05d_DS_", labelKey2num (jtab->key)); + emitpcode (POC_GOTO, popGetLabel (jtab->key)); + + } + +} + +/*-----------------------------------------------------------------*/ +/* genCast - gen code for casting */ +/*-----------------------------------------------------------------*/ +static void +genCast (iCode * ic) +{ + operand *result = IC_RESULT (ic); + sym_link *restype = operandType (result); + sym_link *rtype = operandType (IC_RIGHT (ic)); + operand *right = IC_RIGHT (ic); + int size, offset; + + FENTRY; + DEBUGpic14_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); + + DEBUGpic14_AopType (__LINE__, NULL, right, result); + + /* if the result is a bit */ + if (AOP_TYPE (result) == AOP_CRY) + { + assert (!"assigning to bit variables is not supported"); + } + + if ((AOP_TYPE (right) == AOP_CRY) && (AOP_TYPE (result) == AOP_REG)) + { + int offset = 1; + size = AOP_SIZE (result); + + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + + emitpcode (POC_CLRF, popGet (AOP (result), 0)); + emitpcode (POC_BTFSC, popGet (AOP (right), 0)); + emitpcode (POC_INCF, popGet (AOP (result), 0)); + + while (size--) + emitpcode (POC_CLRF, popGet (AOP (result), offset++)); + + goto release; + } + + if (IS_BOOL (operandType (result))) + { + pic14_toBoolean (right); + emitSKPNZ; + emitpcode (POC_MOVLW, popGetLit (1)); + emitpcode (POC_MOVWF, popGet (AOP (result), 0)); + goto release; + } + + if (IS_PTR (restype)) + { + operand *result = IC_RESULT (ic); + //operand *left = IC_LEFT(ic); + operand *right = IC_RIGHT (ic); + int tag = 0xff; + + /* copy common part */ + int max, size = AOP_SIZE (result); + if (size > AOP_SIZE (right)) + size = AOP_SIZE (right); + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + + /* warn if we discard generic opinter tag */ + if (!IS_GENPTR (restype) && IS_GENPTR (rtype) && (AOP_SIZE (result) < AOP_SIZE (right))) + { + //fprintf (stderr, "%s:%u: discarding generic pointer type tag\n", __FUNCTION__, __LINE__); + } // if + + max = size; + while (size--) + { + mov2w_op (right, size); + movwf (AOP (result), size); + } // while + + /* upcast into generic pointer type? */ + if (IS_GENPTR (restype) && (size < AOP_SIZE (result)) && (!IS_GENPTR (rtype) || AOP_SIZE (right) < GPTRSIZE)) + { + //fprintf (stderr, "%s:%u: must determine pointer type\n", __FUNCTION__, __LINE__); + if (IS_PTR (rtype)) + { + switch (DCL_TYPE (rtype)) + { + case POINTER: /* __data */ + case FPOINTER: /* __data */ + assert (AOP_SIZE (right) == 2); + tag = GPTRTAG_DATA; + break; + + case CPOINTER: /* __code */ + assert (AOP_SIZE (right) == 2); + tag = GPTRTAG_CODE; + break; + + case GPOINTER: /* unknown destination, __data or __code */ + /* assume __data space (address of immediate) */ + assert (AOP_TYPE (right) == AOP_PCODE && AOP (right)->aopu.pcop->type == PO_IMMEDIATE); + if (AOP (right)->code) + tag = GPTRTAG_CODE; + else + tag = GPTRTAG_DATA; + break; + + default: + assert (!"unhandled pointer type"); + } // switch + } + else + { + /* convert other values into pointers to __data space */ + tag = GPTRTAG_DATA; + } + + assert (AOP_SIZE (result) == 3); + if (tag == 0) + { + emitpcode (POC_CLRF, popGet (AOP (result), 2)); + } + else + { + emitpcode (POC_MOVLW, popGetLit (tag)); + movwf (AOP (result), 2); + } + } + else + { + addSign (result, max, 0); + } // if + 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 (pic14_sameRegs (AOP (right), AOP (result))) + goto release; + + DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + if (IS_PTR_CONST (rtype)) + DEBUGpic14_emitcode ("; ***", "%d - right is const pointer", __LINE__); + if (IS_PTR_CONST (operandType (IC_RESULT (ic)))) + DEBUGpic14_emitcode ("; ***", "%d - result is const pointer", __LINE__); + + if ((AOP_TYPE (right) == AOP_PCODE) && AOP (right)->aopu.pcop->type == PO_IMMEDIATE) + { + emitpcode (POC_MOVLW, popGetAddr (AOP (right), 0, 0)); + emitpcode (POC_MOVWF, popGet (AOP (result), 0)); + emitpcode (POC_MOVLW, popGetAddr (AOP (right), 1, 0)); + emitpcode (POC_MOVWF, popGet (AOP (result), 1)); + if (AOP_SIZE (result) < 2) + fprintf (stderr, "%d -- result is not big enough to hold a ptr\n", __LINE__); + + } + else + { + + /* if they in different places then copy */ + size = AOP_SIZE (result); + offset = 0; + while (size--) + { + emitpcode (POC_MOVFW, popGet (AOP (right), offset)); + emitpcode (POC_MOVWF, popGet (AOP (result), offset)); + + //aopPut(AOP(result), + // aopGet(AOP(right),offset,FALSE,FALSE), + // offset); + + offset++; + } + } + goto release; + } + + /* so we now know that the size of destination is greater + than the size of the source. */ + + /* we move to result for the size of source */ + size = AOP_SIZE (right); + offset = 0; + while (size--) + { + emitpcode (POC_MOVFW, popGet (AOP (right), offset)); + emitpcode (POC_MOVWF, popGet (AOP (result), offset)); + offset++; + } + + addSign (result, AOP_SIZE (right), !SPEC_USIGN (rtype)); + +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) +{ + FENTRY; + DEBUGpic14_emitcode ("; ***", "%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 */ + aopOp (IC_RESULT (ic), ic, FALSE); + + emitpcode (POC_DECFSZ, popGet (AOP (IC_RESULT (ic)), 0)); + emitpcode (POC_GOTO, popGetLabel (IC_TRUE (ifx)->key)); + + freeAsmop (IC_RESULT (ic), NULL, ic, TRUE); + ifx->generated = TRUE; + return 1; +} + +/*-----------------------------------------------------------------*/ +/* genReceive - generate code for a receive iCode */ +/*-----------------------------------------------------------------*/ +static void +genReceive (iCode * ic) +{ + FENTRY; + DEBUGpic14_emitcode ("; ***", "%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 = fReturnSizePic - size; + while (size--) + { + pic14_emitcode ("push", "%s", (strcmp (fReturn[fReturnSizePic - offset - 1], "a") ? + fReturn[fReturnSizePic - offset - 1] : "acc")); + offset++; + } + aopOp (IC_RESULT (ic), ic, FALSE); + size = AOP_SIZE (IC_RESULT (ic)); + offset = 0; + while (size--) + { + pic14_emitcode ("pop", "acc"); + aopPut (AOP (IC_RESULT (ic)), "a", offset++); + } + + } + else + { + _G.accInUse++; + aopOp (IC_RESULT (ic), ic, FALSE); + _G.accInUse--; + GpseudoStkPtr = ic->parmBytes; // address used arg on stack + assignResultValue (IC_RESULT (ic)); + } + + freeAsmop (IC_RESULT (ic), NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genDummyRead - generate code for dummy read of volatiles */ +/*-----------------------------------------------------------------*/ +static void +genDummyRead (iCode * ic) +{ + FENTRY; + pic14_emitcode ("; genDummyRead", ""); + pic14_emitcode ("; not implemented", ""); + + ic = ic; +} + +/*-----------------------------------------------------------------*/ +/* genpic14Code - generate code for pic14 based controllers */ +/*-----------------------------------------------------------------*/ +/* +* At this point, ralloc.c has gone through the iCode and attempted +* to optimize in a way suitable for a PIC. Now we've got to generate +* PIC instructions that correspond to the iCode. +* +* Once the instructions are generated, we'll pass through both the +* peep hole optimizer and the pCode optimizer. +*-----------------------------------------------------------------*/ + +void +genpic14Code (iCode * lic) +{ + iCode *ic; + int cln = 0; + const char *cline; + + FENTRY; + + pic = pic14_getPIC(); + + pb = newpCodeChain (GcurMemmap, 0, newpCodeCharP ("; Starting pCode block")); + addpBlock (pb); + + /* if debug information required */ + if (options.debug && debugFile && currFunc) + { + debugFile->writeFunction (currFunc, lic); + } + + + for (ic = lic; ic; ic = ic->next) + { + initGenLineElement (); + + //DEBUGpic14_emitcode(";ic",""); + //fprintf (stderr, "in ic loop\n"); + //pic14_emitcode ("", ";\t%s:%d: %s", ic->filename, + //ic->lineno, printCLine(ic->filename, ic->lineno)); + + if (!options.noCcodeInAsm && (cln != ic->lineno)) + { + cln = ic->lineno; + //fprintf (stderr, "%s\n", printCLine (ic->filename, ic->lineno)); + cline = printCLine (ic->filename, ic->lineno); + if (!cline || strlen (cline) == 0) + cline = printCLine (ic->filename, ic->lineno); + addpCode2pBlock (pb, newpCodeCSource (ic->lineno, ic->filename, cline)); + //emitpComment ("[C-SRC] %s:%d: %s", ic->filename, cln, cline); + } + + if (options.iCodeInAsm) + { + const char *iLine = printILine (ic); + emitpComment ("[ICODE] %s:%d: %s", ic->filename, ic->lineno, printILine (ic)); + dbuf_free (iLine); + } + /* 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: + pic14_genInline (ic); + break; + + case RRC: + genRRC (ic); + break; + + case RLC: + genRLC (ic); + break; + + case GETABIT: + genGetABit (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; + + case DUMMY_READ_VOLATILE: + genDummyRead (ic); + break; + + case CRITICAL: + genCritical (ic); + break; + + case ENDCRITICAL: + genEndCritical (ic); + break; + + default: + fprintf (stderr, "UNHANDLED iCode: "); + piCode (ic, stderr); + ic = ic; + break; + } + } + + + /* now we are ready to call the + peep hole optimizer */ + if (!options.nopeep) + { + peepHole (&genLine.lineHead); + } + /* now do the actual printing */ + printLine (genLine.lineHead, codeOutBuf); + +#ifdef PCODE_DEBUG + DFPRINTF ((stderr, "printing pBlock\n\n")); + printpBlock (stdout, pb); +#endif + + /* destroy the line list */ + destroy_line_list (); +} + +/* This is not safe, as a AOP_PCODE/PO_IMMEDIATE might be used both as literal + * (meaning: representing its own address) or not (referencing its contents). + * This can only be decided based on the operand's type. */ +static int +aop_isLitLike (asmop * aop) +{ + assert (aop); + if (aop->type == AOP_LIT) + return TRUE; + if (aop->type == AOP_IMMD) + return TRUE; + if ((aop->type == AOP_PCODE) && + ((aop->aopu.pcop->type == PO_LITERAL) || + (aop->aopu.pcop->type == PO_IMMEDIATE))) + { + /* this should be treated like a literal/immediate (use MOVLW/ADDLW/SUBLW + * instead of MOVFW/ADDFW/SUBFW, use popGetAddr instead of popGet) */ + return TRUE; + } + return FALSE; +} + +int +op_isLitLike (operand * op) +{ + assert (op); + if (aop_isLitLike (AOP (op))) + return TRUE; + if (IS_SYMOP (op) && IS_FUNC (OP_SYM_TYPE (op))) + return TRUE; + if (IS_SYMOP (op) && IS_PTR (OP_SYM_TYPE (op)) && (AOP_TYPE (op) == AOP_PCODE) && (AOP (op)->aopu.pcop->type == PO_IMMEDIATE)) + { + return TRUE; + } + + return FALSE; +} |
