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/pic16/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/pic16/gen.c')
| -rw-r--r-- | src/pic16/gen.c | 11583 |
1 files changed, 11583 insertions, 0 deletions
diff --git a/src/pic16/gen.c b/src/pic16/gen.c new file mode 100644 index 0000000..3150a07 --- /dev/null +++ b/src/pic16/gen.c @@ -0,0 +1,11583 @@ +/*------------------------------------------------------------------------- + gen.c - source file for code generation for pic16 + + 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 + PIC16 port: + Copyright (C) 2002, Martin Dubuc m.dubuc@rogers.com + Copyright (C) 2003-2006,Vangelis Rokas <vrokas AT users.sourceforge.net> + Bug Fixes - Raphael Neider <rneider AT web.de> (2004,2005) + Bug Fixes - Borut Razem <borut.razem AT siol.net> (2007) + Bug Fixes - Mauro Giachero <maurogiachero AT users.sourceforge.net> (2008) + + 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 +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#include "common.h" +#include "ralloc.h" +#include "pcode.h" +#include "gen.h" +#include "genutils.h" +#include "device.h" +#include "main.h" +#include "glue.h" +#include "dbuf_string.h" + +/* The PIC port(s) do not need to distinguish between POINTER and FPOINTER. */ +#define PIC_IS_DATA_PTR(x) (IS_DATA_PTR(x) || IS_FARPTR(x)) +#define PIC_IS_FARPTR(x) (IS_DATA_PTR(x) || IS_FARPTR(x)) +#define PIC_IS_TAGGED(x) (IS_GENPTR(x) || IS_CODEPTR(x)) +#define IS_DIRECT(op) ((AOP_TYPE(op) == AOP_PCODE) && (AOP(op)->aopu.pcop->type == PO_DIR)) + +/* Wrapper to execute `code' at most once. */ +#define PERFORM_ONCE(id,code) do { static char id = 0; if (!id) { id = 1; code } } while (0) + +void pic16_genMult8X8_n (operand *, operand *, operand *); +extern void pic16_printpBlock (FILE * of, pBlock * pb); +static asmop *newAsmop (short type); +static pCodeOp *pic16_popRegFromString (char *str, int size, int offset, operand * op); +extern pCode *pic16_newpCodeAsmDir (const char *asdir, const char *argfmt, ...); +static void mov2fp (pCodeOp * dst, asmop * src, int offset); +static pCodeOp *pic16_popRegFromIdx (int rIdx); +static void genCritical (iCode * ic); +static void genEndCritical (iCode * ic); + +int pic16_labelOffset = 0; +extern int pic16_debug_verbose; + +extern set *externs; + +/* 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 GpseudoStkPtr = 0; + +pCodeOp *pic16_popGetImmd (char *name, unsigned int offset, int index); + +const char *pic16_AopType (short type); + +void pic16_pushpCodeOp (pCodeOp * pcop); +void pic16_poppCodeOp (pCodeOp * pcop); + + +#define BYTEofLONG(l,b) ( (l>> (b<<3)) & 0xff) + +/* set the following macro to 1 to enable passing the + * first byte of functions parameters via WREG */ +#define USE_WREG_IN_FUNC_PARAMS 0 + + +/* this is the down and dirty file with all kinds of + kludgy & hacky stuff. This is what it is all about + CODE GENERATION for a specific MCU . some of the + routines may be reusable, will have to see */ +static char *zero = "#0x00"; +static char *one = "#0x01"; + + +/* + * Function return value policy (MSB-->LSB): + * 8 bits -> WREG + * 16 bits -> PRODL:WREG + * 24 bits -> PRODH:PRODL:WREG + * 32 bits -> FSR0L:PRODH:PRODL:WREG + * >32 bits -> on stack, and FSR0 points to the beginning + */ +char *fReturnpic16[] = { "WREG", "PRODL", "PRODH", "FSR0L" }; +int fReturnIdx[] = { IDX_WREG, IDX_PRODL, IDX_PRODH, IDX_FSR0L }; + +unsigned pic16_fReturnSizePic = 4; /* shared with ralloc.c */ +static char **fReturn = fReturnpic16; + +static char *accUse[] = { "WREG" }; + +static struct +{ + short accInUse; + short inLine; + short debugLine; + short nRegsSaved; + set *sendSet; + set *stackRegSet; + int usefastretfie; + bitVect *fregsUsed; /* registers used in function */ + bitVect *sregsAlloc; + set *sregsAllocSet; /* registers used to store stack variables */ + int stack_lat; /* stack offset latency */ + int resDirect; + int useWreg; /* flag when WREG is used to pass function parameter */ +} _G; + +extern struct dbuf_s *codeOutBuf; + +static unsigned char SLMask[] = { 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, + 0xE0, 0xC0, 0x80, 0x00 + }; + +static unsigned char SRMask[] = { 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, + 0x07, 0x03, 0x01, 0x00 + }; + +static pBlock *pb; + +/*-----------------------------------------------------------------*/ +/* my_powof2(n) - If `n' is an integaer power of 2, then the */ +/* exponent of 2 is returned, otherwise -1 is */ +/* returned. */ +/* note that this is similar to the function `powof2' in SDCCsymt */ +/* if(n == 2^y) */ +/* return y; */ +/* return -1; */ +/*-----------------------------------------------------------------*/ +int +pic16_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 +DEBUGpic16_pic16_AopType (int line_no, operand * left, operand * right, operand * result) +{ + DEBUGpic16_emitcode ("; ", "line = %d result %s=%s, left %s=%s, right %s=%s, size = %d", + line_no, + ((result) ? pic16_AopType (AOP_TYPE (result)) : "-"), + ((result) ? pic16_aopGet (AOP (result), 0, TRUE, FALSE) : "-"), + ((left) ? pic16_AopType (AOP_TYPE (left)) : "-"), + ((left) ? pic16_aopGet (AOP (left), 0, TRUE, FALSE) : "-"), + ((right) ? pic16_AopType (AOP_TYPE (right)) : "-"), + ((right) ? pic16_aopGet (AOP (right), 0, FALSE, FALSE) : "-"), ((result) ? AOP_SIZE (result) : 0)); +} + +void +DEBUGpic16_pic16_AopTypeSign (int line_no, operand * left, operand * right, operand * result) +{ + + DEBUGpic16_emitcode ("; ", "line = %d, signs: result %s=%c, left %s=%c, right %s=%c", + line_no, + ((result) ? pic16_AopType (AOP_TYPE (result)) : "-"), + ((result) ? (SPEC_USIGN (operandType (result)) ? 'u' : 's') : '-'), + ((left) ? pic16_AopType (AOP_TYPE (left)) : "-"), + ((left) ? (SPEC_USIGN (operandType (left)) ? 'u' : 's') : '-'), + ((right) ? pic16_AopType (AOP_TYPE (right)) : "-"), + ((right) ? (SPEC_USIGN (operandType (right)) ? 'u' : 's') : '-')); + +} + +void +pic16_emitpcomment (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); + + pic16_addpCode2pBlock (pb, pic16_newpCodeCharP (genLine.lineCurr->line)); +} + +void +DEBUGpic16_emitcode (char *inst, char *fmt, ...) +{ + va_list ap; + + if (!pic16_debug_verbose) + return; + + va_start (ap, fmt); + va_emitcode (inst, fmt, ap); + va_end (ap); + + pic16_addpCode2pBlock (pb, pic16_newpCodeCharP (genLine.lineCurr->line)); +} + +void +pic16_emitpLabel (int key) +{ + if (key > max_key) + max_key = key; + + pic16_addpCode2pBlock (pb, pic16_newpCodeLabel (NULL, labelKey2num (key + pic16_labelOffset))); +} + +void +pic16_emitpLabelFORCE (int key) +{ + if (key > max_key) + max_key = key; + + pic16_addpCode2pBlock (pb, pic16_newpCodeLabelFORCE (NULL, labelKey2num (key + pic16_labelOffset))); +} + +/* gen.h defines a macro pic16_emitpcode that allows for debug information to be inserted on demand + * NEVER call pic16_emitpcode_real directly, please... */ +void +pic16_emitpcode_real (PIC_OPCODE poc, pCodeOp * pcop) +{ + + if (pcop) + pic16_addpCode2pBlock (pb, pic16_newpCode (poc, pcop)); + else + DEBUGpic16_emitcode (";", "%s ignoring NULL pcop", __FUNCTION__); +} + +void +pic16_emitpinfo (INFO_TYPE itype, pCodeOp * pcop) +{ + if (pcop) + pic16_addpCode2pBlock (pb, pic16_newpCodeInfo (itype, pcop)); + else + DEBUGpic16_emitcode (";", "%s ignoring NULL pcop", __FUNCTION__); +} + +void +pic16_emitpcodeNULLop (PIC_OPCODE poc) +{ + + pic16_addpCode2pBlock (pb, pic16_newpCode (poc, NULL)); + +} + + +#if 1 +#define pic16_emitcode DEBUGpic16_emitcode +#else +/*-----------------------------------------------------------------*/ +/* pic16_emitcode - writes the code into a file : for now it is simple */ +/*-----------------------------------------------------------------*/ +void +pic16_emitcode (char *inst, char *fmt, ...) +{ + va_list ap; + char lb[INITIAL_INLINEASM]; + unsigned char *lbp = lb; + + va_start (ap, fmt); + + if (inst && *inst) + { + if (fmt && *fmt) + SNPRINTF(lb, sizeof(lb), "%s\t", inst); + else + SNPRINTF(lb, sizeof(lb), "%s", inst); + + vsprintf (lb + (strlen (lb)), fmt, ap); + } + else + vsprintf (lb, fmt, ap); + + while (isspace (*lbp)) + lbp++; + + if (lbp && *lbp) + genLine.lineCurr = (genLine.lineCurr ? + connectLine (genLine.lineCurr, newLineNode (lb)) : (genLine.lineHead = newLineNode (lb))); + genLine.lineCurr->isInline = genLine.lineElement.isInline; + genLine.lineCurr->isDebug = genLine.lineElement.isDebug; + genLine.lineCurr->isLabel = (lbp[strlen (lbp) - 1] == ':'); + genLine.lineCurr->isComment = (*lbp == ';'); + +// VR fprintf(stderr, "lb = <%s>\n", lbp); + +// if(pic16_debug_verbose) +// pic16_addpCode2pBlock(pb,pic16_newpCodeCharP(lb)); + + va_end (ap); +} +#endif + + +/*-----------------------------------------------------------------*/ +/* pic16_emitDebuggerSymbol - associate the current code location */ +/* with a debugger symbol */ +/*-----------------------------------------------------------------*/ +void +pic16_emitDebuggerSymbol (const char *debugSym) +{ + genLine.lineElement.isDebug = 1; + pic16_emitcode (";", "%s ==.", debugSym); + genLine.lineElement.isDebug = 0; +} + +/*-----------------------------------------------------------------*/ +/* 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) +{ + FENTRY2; + +// DEBUGpic16_emitcode("; ***","%s %d",__FUNCTION__,__LINE__); + + if (!resIfx) + return; + + + resIfx->condition = 1; /* assume that the ifx is true */ + resIfx->generated = 0; /* indicate that the ifx has not been used */ + + if (!ifx) + { + resIfx->lbl = newiTempLabel (NULL); /* oops, there is no ifx. so create a label */ + +#if 1 + DEBUGpic16_emitcode ("; ***", "%s %d null ifx creating new label key =%d", __FUNCTION__, __LINE__, resIfx->lbl->key); +#endif + + } + else + { + if (IC_TRUE (ifx)) + { + resIfx->lbl = IC_TRUE (ifx); + } + else + { + resIfx->lbl = IC_FALSE (ifx); + resIfx->condition = 0; + } + +#if 1 + if (IC_TRUE (ifx)) + DEBUGpic16_emitcode ("; +++", "ifx true is non-null"); + else + DEBUGpic16_emitcode ("; +++", "ifx true is null"); + if (IC_FALSE (ifx)) + DEBUGpic16_emitcode ("; +++", "ifx false is non-null"); + else + DEBUGpic16_emitcode ("; +++", "ifx false is null"); +#endif + } + + DEBUGpic16_emitcode ("; ***", "%s lbl->key=%d, (lab offset=%d)", __FUNCTION__, resIfx->lbl->key, pic16_labelOffset); + +} + +#if 0 +/*-----------------------------------------------------------------*/ +/* pointerCode - returns the code for a pointer type */ +/*-----------------------------------------------------------------*/ +static int +pointerCode (sym_link * etype) +{ + + return PTR_TYPE (SPEC_OCLS (etype)); + +} +#endif + +/*-----------------------------------------------------------------*/ +/* aopForSym - for a true symbol */ +/*-----------------------------------------------------------------*/ +static asmop * +aopForSym (iCode * ic, operand * op, bool result) +{ + symbol *sym = OP_SYMBOL (op); + asmop *aop; + memmap *space = SPEC_OCLS (sym->etype); + + FENTRY2; + + _G.resDirect = 0; /* clear flag that instructs the result is loaded directly from aopForSym */ + +// sym = OP_SYMBOL(op); + + /* if already has one */ + if (sym->aop) + { + DEBUGpic16_emitcode ("; ***", "already has sym %s %d", __FUNCTION__, __LINE__); + return sym->aop; + } + +#if 0 + /* if symbol was initially placed onStack then we must re-place it + * to direct memory, since pic16 does not have a specific stack */ + if (sym->onStack) + { + fprintf (stderr, "%s:%d symbol %s on stack\n", __FILE__, __LINE__, OP_SYMBOL (op)->name); + } +#endif + + +#if 0 + if (sym->iaccess) + { + if (space->paged) + { + fprintf (stderr, "%s:%d symbol %s points to paged data\n", __FILE__, __LINE__, sym->name); + + sym->aop = aop = newAsmop (AOP_PAGED); + aop->aopu.aop_dir = sym->rname; + aop->size = getSize (sym->type); + DEBUGpic16_emitcode (";", "%d sym->rname = %s, size = %d", __LINE__, sym->rname, aop->size); + pic16_allocDirReg (IC_LEFT (ic)); + return aop; + } + assert (0); + } +#endif + +#if 1 + /* assign depending on the storage class */ + /* if it is on the stack or indirectly addressable */ + /* space we need to assign either r0 or r1 to it */ + if (sym->onStack) // || sym->iaccess) + { + pCodeOp *pcop[4]; + int i; + + DEBUGpic16_emitcode ("; ***", "%s:%d sym->onStack:%d || sym->iaccess:%d", + __FUNCTION__, __LINE__, sym->onStack, sym->iaccess); + + /* acquire a temporary register -- it is saved in function */ + + sym->aop = aop = newAsmop (AOP_STA); + aop->aopu.stk.stk = sym->stack; + aop->size = getSize (sym->type); + + + DEBUGpic16_emitcode ("; +++ ", "%s:%d\top = %s", __FILE__, __LINE__, pic16_decodeOp (ic->op)); + if ((ic->op == '=' /*|| ic->op == CAST */ ) && IC_RESULT (ic) && AOP (IC_RESULT (ic)) + && (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)) + { +// pic16_DumpAop("aopForSym", AOP( IC_RESULT(ic) )); + + for (i = 0; i < aop->size; i++) + aop->aopu.stk.pop[i] = pcop[i] = pic16_popRegFromIdx (AOP (IC_RESULT (ic))->aopu.aop_reg[i]->rIdx); + _G.resDirect = 1; /* notify that result will be loaded directly from aopForSym */ + } + else if (1 && ic->op == SEND) + { + + /* if SEND do the send here */ + _G.resDirect = 1; + } + else + { +// debugf3("symbol `%s' level = %d / %d\n", sym->name, ic->level, ic->seq); + for (i = 0; i < aop->size; i++) + { + aop->aopu.stk.pop[i] = pcop[i] = pic16_popGetTempRegCond (_G.fregsUsed, _G.sregsAlloc, 0); + _G.sregsAlloc = bitVectSetBit (_G.sregsAlloc, PCOR (pcop[i])->r->rIdx); + } + } + + +// fprintf(stderr, "%s:%d\t%s\tsym size %d\n", __FILE__, __LINE__, __FUNCTION__, aop->size); + +#if 1 + DEBUGpic16_emitcode (";", "%d sym->rname = %s, size = %d stack = %d", __LINE__, sym->rname, aop->size, sym->stack); + + // we do not need to load the value if it is to be defined... + if (result) + return aop; + + if (_G.accInUse) + { + pic16_pushpCodeOp (pic16_popCopyReg (&pic16_pc_wreg)); + } + + for (i = 0; i < aop->size; i++) + { + + /* initialise for stack access via frame pointer */ + // operands on stack are accessible via "{FRAME POINTER} + index" with index + // starting at 2 for arguments and growing from 0 downwards for + // local variables (index == 0 is not assigned so we add one here) + { + int soffs = sym->stack; + if (soffs <= 0) + { + assert (soffs < 0); + soffs++; + } // if + + if (1 && ic->op == SEND) + { + pic16_emitpcode (POC_MOVLW, pic16_popGetLit (soffs + aop->size - i - 1 /*+ _G.stack_lat */ )); + pic16_emitpcode (POC_MOVFF, pic16_popGet2p (pic16_popCopyReg (pic16_frame_plusw), + pic16_popCopyReg (pic16_stack_postdec))); + } + else + { + pic16_emitpcode (POC_MOVLW, pic16_popGetLit (soffs + i /*+ _G.stack_lat */ )); + pic16_emitpcode (POC_MOVFF, pic16_popGet2p (pic16_popCopyReg (pic16_frame_plusw), pcop[i])); + } + } + } + + if (_G.accInUse) + { + pic16_poppCodeOp (pic16_popCopyReg (&pic16_pc_wreg)); + } + + return (aop); +#endif + +#if 0 + /* now assign the address of the variable to + the pointer register */ + if (aop->type != AOP_STK) + { + + if (sym->onStack) + { + if (_G.accInUse) + pic16_emitcode ("push", "acc"); + + pic16_emitcode ("mov", "a,_bp"); + pic16_emitcode ("add", "a,#0x%02x", + ((sym->stack < 0) ? ((char) (sym->stack - _G.nRegsSaved)) : ((char) sym->stack)) & 0xff); + pic16_emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name); + + if (_G.accInUse) + pic16_emitcode ("pop", "acc"); + } + else + pic16_emitcode ("mov", "%s,#%s", aop->aopu.aop_ptr->name, sym->rname); + aop->paged = space->paged; + } + else + aop->aopu.aop_stk = sym->stack; + return aop; +#endif + + } +#endif + +#if 1 + /* special case for a function */ + if (IS_FUNC (sym->type)) + { + sym->aop = aop = newAsmop (AOP_PCODE); + aop->aopu.pcop = pic16_popGetImmd (sym->rname, 0, 0); + PCOI (aop->aopu.pcop)->_const = IN_CODESPACE (space); + PCOI (aop->aopu.pcop)->index = 0; + aop->size = FARPTRSIZE; + DEBUGpic16_emitcode (";", "%d size = %d, name =%s", __LINE__, aop->size, sym->rname); + return aop; + } +#endif + + + + //DEBUGpic16_emitcode(";","%d",__LINE__); + /* if in bit space */ + if (IN_BITSPACE (space)) + { + sym->aop = aop = newAsmop (AOP_CRY); + aop->aopu.aop_dir = sym->rname; + aop->size = getSize (sym->type); + DEBUGpic16_emitcode (";", "%d sym->rname = %s, size = %d", __LINE__, sym->rname, aop->size); + return aop; + } + /* if it is in direct space */ + if (IN_DIRSPACE (space)) + { + if (!strcmp (sym->rname, "_WREG")) + { + sym->aop = aop = newAsmop (AOP_ACC); + aop->size = getSize (sym->type); /* should always be 1 */ + assert (aop->size == 1); + DEBUGpic16_emitcode (";", "%d sym->rname (AOP_ACC) = %s, size = %d", __LINE__, sym->rname, aop->size); + return (aop); + } + else + { + sym->aop = aop = newAsmop (AOP_DIR); + aop->aopu.aop_dir = sym->rname; + aop->size = getSize (sym->type); + DEBUGpic16_emitcode (";", "%d sym->rname (AOP_DIR) = %s, size = %d", __LINE__, sym->rname, aop->size); + pic16_allocDirReg (IC_LEFT (ic)); + return (aop); + } + } + + if (IN_FARSPACE (space) && !IN_CODESPACE (space)) + { + sym->aop = aop = newAsmop (AOP_DIR); + aop->aopu.aop_dir = sym->rname; + aop->size = getSize (sym->type); + DEBUGpic16_emitcode (";", "%d sym->rname = %s, size = %d", __LINE__, sym->rname, aop->size); + pic16_allocDirReg (IC_LEFT (ic)); + return aop; + } + + + /* only remaining is far space */ + sym->aop = aop = newAsmop (AOP_PCODE); + + /* change the next if to 1 to revert to good old immediate code */ + if (IN_CODESPACE (space)) + { + aop->aopu.pcop = pic16_popGetImmd (sym->rname, 0, 0); + PCOI (aop->aopu.pcop)->_const = IN_CODESPACE (space); + PCOI (aop->aopu.pcop)->index = 0; + } + else + { + /* try to allocate via direct register */ + aop->aopu.pcop = pic16_popRegFromString (sym->rname, getSize (sym->type), sym->offset, op); // Patch 8 +// aop->size = getSize( sym->type ); + } + + DEBUGpic16_emitcode (";", "%d: rname %s, val %d, const = %d", __LINE__, sym->rname, 0, PCOI (aop->aopu.pcop)->_const); + +#if 0 + if (!pic16_allocDirReg (IC_LEFT (ic))) + return NULL; +#endif + + if (IN_DIRSPACE (space)) + aop->size = NEARPTRSIZE; + else if (IN_CODESPACE (space) || IN_FARSPACE (space)) + aop->size = FARPTRSIZE; + else if (IC_LEFT (ic) && AOP (IC_LEFT (ic))) + aop->size = AOP_SIZE (IC_LEFT (ic)); + else if (IC_RIGHT (ic) && AOP (IC_RIGHT (ic))) + aop->size = AOP_SIZE (IC_RIGHT (ic)); + else if (sym->onStack) + { + aop->size = NEARPTRSIZE; + } + else + { + if (SPEC_SCLS (sym->etype) == S_PDATA) + { + fprintf (stderr, "%s: %d symbol in PDATA space\n", __FILE__, __LINE__); + aop->size = FARPTRSIZE; + } + else + assert (0); + } + + DEBUGpic16_emitcode (";", "%d size = %d", __LINE__, aop->size); + + /* if it is in code space */ + if (IN_CODESPACE (space)) + aop->code = 1; + + return aop; +} + +/*-----------------------------------------------------------------*/ +/* aopForRemat - rematerialzes an object */ +/*-----------------------------------------------------------------*/ +static asmop * +aopForRemat (operand * op, bool result) // x symbol *sym) +{ + symbol *sym = OP_SYMBOL (op); + operand *refop; + iCode *ic = NULL; + asmop *aop = newAsmop (AOP_PCODE); + int val = 0; + int viaimmd = 0; + + FENTRY2; + + ic = sym->rematiCode; + + if (IS_OP_POINTER (op)) + { + DEBUGpic16_emitcode (";", "%s %d IS_OP_POINTER", __FUNCTION__, __LINE__); + } + +// if(!result) /* fixme-vr */ + for (;;) + { +// chat *iLine = printILine(ic); +// pic16_emitpcomment("ic: %s\n", iLine); +// dbuf_free(iLine); + + 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; + } + + refop = IC_LEFT (ic); + + if (!op->isaddr) + viaimmd++; + else + viaimmd = 0; + + /* set the following if to 1 to revert to good old immediate code */ + if (IN_CODESPACE (SPEC_OCLS (OP_SYM_ETYPE (refop))) || viaimmd) + { + + DEBUGpic16_emitcode (";", "%s:%d immediate, size: %d", __FILE__, __LINE__, getSize (sym->type)); + + aop->aopu.pcop = pic16_popGetImmd (OP_SYMBOL (IC_LEFT (ic))->rname, 0, val); + +#if 0 + PCOI (aop->aopu.pcop)->_const = IS_PTR_CONST (operandType (op)); +#else + PCOI (aop->aopu.pcop)->_const = IS_CODEPTR (operandType (op)); +#endif + + PCOI (aop->aopu.pcop)->index = val; + + aop->size = getSize (sym->type); + } + else + { + DEBUGpic16_emitcode (";", "%s:%d dir size: %d", __FILE__, __LINE__, getSize (OP_SYMBOL (IC_LEFT (ic))->type)); + + aop->aopu.pcop = pic16_popRegFromString (OP_SYMBOL (IC_LEFT (ic))->rname, + getSize (OP_SYMBOL (IC_LEFT (ic))->type), val, op); + + aop->size = getSize (OP_SYMBOL (IC_LEFT (ic))->type); + } + + + DEBUGpic16_emitcode (";", "%d: rname %s, val %d, const = %d", __LINE__, OP_SYMBOL (IC_LEFT (ic))->rname, +#if 0 + val, IS_PTR_CONST (operandType (op))); +#else + val, IS_CODEPTR (operandType (op))); +#endif + +// DEBUGpic16_emitcode(";","aop type %s",pic16_AopType(AOP_TYPE(IC_LEFT(ic)))); + + pic16_allocDirReg (IC_LEFT (ic)); + + if (IN_CODESPACE (SPEC_OCLS (OP_SYM_ETYPE (op)))) + aop->code = 1; + + return aop; +} + +#if 0 +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; + +} +#endif + +/*-----------------------------------------------------------------*/ +/* 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 && (SYM_SPIL_LOC (sym1) == sym2)) + return TRUE; + + if (IS_ITEMP (op2) && !IS_ITEMP (op1) && sym2->isspilt && sym1->level > 0 && (SYM_SPIL_LOC (sym2) == sym1)) + return TRUE; + + return FALSE; +} + +/*-----------------------------------------------------------------*/ +/* pic16_sameRegs - two asmops have the same registers */ +/*-----------------------------------------------------------------*/ +bool +pic16_sameRegs (asmop * aop1, asmop * aop2) +{ + int i; + + if (aop1 == aop2) + return TRUE; + + DEBUGpic16_emitcode (";***", "%s aop1->type = %s\taop2->type = %s\n", __FUNCTION__, + pic16_AopType (aop1->type), pic16_AopType (aop2->type)); + + if (aop1->type == AOP_ACC && aop2->type == AOP_ACC) + return TRUE; + + if (aop1->type != AOP_REG || aop2->type != AOP_REG) + return FALSE; + + /* This is a bit too restrictive if one is a subset of the other... + if (aop1->size != aop2->size ) + return FALSE ; + */ + + for (i = 0; i < min (aop1->size, aop2->size); i++) + { +// if(aop1->aopu.aop_reg[i]->type != aop2->aopu.aop_reg[i]->type)return FALSE; + +// if(aop1->aopu.aop_reg[i]->type == AOP_REG) + if (strcmp (aop1->aopu.aop_reg[i]->name, aop2->aopu.aop_reg[i]->name)) + return FALSE; + } + + return TRUE; +} + +bool +pic16_sameRegsOfs (asmop * aop1, asmop * aop2, int offset) +{ + DEBUGpic16_emitcode (";***", "%s aop1->type = %s\taop2->type = %s (offset = %d)\n", __FUNCTION__, + pic16_AopType (aop1->type), pic16_AopType (aop2->type), offset); + + if (aop1 == aop2) + return TRUE; + if (aop1->type != AOP_REG || aop2->type != AOP_REG) + return FALSE; + + if (strcmp (aop1->aopu.aop_reg[offset]->name, aop2->aopu.aop_reg[offset]->name)) + return FALSE; + + return TRUE; +} + + +/*-----------------------------------------------------------------*/ +/* pic16_aopOp - allocates an asmop for an operand : */ +/*-----------------------------------------------------------------*/ +void +pic16_aopOp (operand * op, iCode * ic, bool result) +{ + asmop *aop; + symbol *sym; + int i; + + if (!op) + return; + + DEBUGpic16_emitcode (";", "%s %d", __FUNCTION__, __LINE__); + + /* 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 0 + if (IS_PTR_CONST (type)) +#else + if (IS_CODEPTR (type)) +#endif + DEBUGpic16_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) + { + DEBUGpic16_emitcode (";", "%d has symbol", __LINE__); + op->aop = OP_SYMBOL (op)->aop; + return; + } + + /* if this is a true symbol */ + if (IS_TRUE_SYMOP (op)) + { + DEBUGpic16_emitcode (";", "%d - true symop", __LINE__); + op->aop = aopForSym (ic, 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); + + DEBUGpic16_emitcode ("; ***", "%d: symbol name = %s, regType = %d", __LINE__, sym->name, sym->regType); + /* 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) + { + +// debugf3("symbol %s\tisspilt: %d\tnRegs: %d\n", sym->rname, sym->isspilt, sym->nRegs); + DEBUGpic16_emitcode (";", "%d", __LINE__); + /* rematerialize it NOW */ + if (sym->remat) + { + + sym->aop = op->aop = aop = aopForRemat (op, result); + return; + } + +#if 1 + if (sym->accuse) + { + int i; + aop = op->aop = sym->aop = newAsmop (AOP_ACC); + aop->size = getSize (sym->type); + for (i = 0; i < 1; i++) + { + aop->aopu.aop_str[i] = accUse[i]; +// aop->aopu.pcop = pic16_popRegFromString("WREG", aop->size, SYM_SPIL_LOC(sym)->offset); + } + fprintf (stderr, "%s:%d allocating AOP_ACC for sym= %s\n", __FILE__, __LINE__, sym->name); + DEBUGpic16_emitcode (";", "%d size=%d", __LINE__, aop->size); + return; + } +#endif + +#if 1 + if (sym->ruonly) + { + /* + sym->aop = op->aop = aop = newAsmop(AOP_PCODE); + aop->aopu.pcop = pic16_popGetImmd(SYM_SPIL_LOC(sym)->rname,0,SYM_SPIL_LOC(sym)->offset); + //pic16_allocDirReg (IC_LEFT(ic)); + aop->size = getSize(sym->type); + */ + + unsigned i; + + aop = op->aop = sym->aop = newAsmop (AOP_REG); + aop->size = getSize (sym->type); + for (i = 0; i < pic16_fReturnSizePic; i++) + aop->aopu.aop_reg[i] = PCOR (pic16_popRegFromIdx (fReturnIdx[i]))->r; + + DEBUGpic16_emitcode (";", "%d", __LINE__); + return; + } +#endif + /* else spill location */ + if (sym->isspilt && SYM_SPIL_LOC (sym) && getSize (sym->type) != getSize (SYM_SPIL_LOC (sym)->type)) + { + /* force a new aop if sizes differ */ + SYM_SPIL_LOC (sym)->aop = NULL; + } + +#if 0 + DEBUGpic16_emitcode (";", "%s %d %s sym->rname = %s, offset %d", + __FUNCTION__, __LINE__, SYM_SPIL_LOC (sym)->rname, sym->rname, SYM_SPIL_LOC (sym)->offset); +#endif + + //aop->aopu.pcop = pic16_popGetImmd(SYM_SPIL_LOC(sym)->rname,0,SYM_SPIL_LOC(sym)->offset); + if (sym->isspilt && SYM_SPIL_LOC (sym) && SYM_SPIL_LOC (sym)->rname) + { + sym->aop = op->aop = aop = newAsmop (AOP_PCODE); + aop->aopu.pcop = pic16_popRegFromString (SYM_SPIL_LOC (sym)->rname, + getSize (sym->type), SYM_SPIL_LOC (sym)->offset, op); + } + else if (getSize (sym->type) <= 1) + { + //fprintf (stderr, "%s:%d called for a spillLocation -- assigning WREG instead --- CHECK (size:%u)!\n", __FUNCTION__, __LINE__, getSize(sym->type)); + pic16_emitpcomment (";!!! %s:%d called for a spillLocation -- assigning WREG instead --- CHECK", __FUNCTION__, + __LINE__); + assert (getSize (sym->type) <= 1); + sym->aop = op->aop = aop = newAsmop (AOP_PCODE); + aop->aopu.pcop = pic16_popCopyReg (&pic16_pc_wreg); + } + else + { + /* We need some kind of dummy area for getSize(sym->type) byte, + * use WREG for all storage locations. + * XXX: This only works if we are implementing a `dummy read', + * the stored value will not be retrievable... + * See #1503234 for a case requiring this. */ + sym->aop = op->aop = aop = newAsmop (AOP_REG); + aop->size = getSize (sym->type); + for (i = 0; i < aop->size; i++) + aop->aopu.aop_reg[i] = pic16_pc_wreg.r; + } + aop->size = getSize (sym->type); + + return; + } + + { + sym_link *type = operandType (op); +#if 0 + if (IS_PTR_CONST (type)) +#else + if (IS_CODEPTR (type)) +#endif + DEBUGpic16_emitcode (";", "%d aop type is const pointer", __LINE__); + } + + /* must be in a register */ + DEBUGpic16_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]; +} + +/*-----------------------------------------------------------------*/ +/* pic16_freeAsmop - free up the asmop given to an operand */ +/*----------------------------------------------------------------*/ +void +pic16_freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop) +{ + asmop *aop; + + if (!op) + aop = aaop; + else + aop = op->aop; + + if (!aop) + return; + + if (aop->freed) + goto dealloc; + + aop->freed = 1; + +#if 1 + switch (aop->type) + { + case AOP_STA: + { + int i; + + /* we must store the result on stack */ + if ((op == IC_RESULT (ic)) && RESULTONSTA (ic)) + { + // operands on stack are accessible via "FSR2 + index" with index + // starting at 2 for arguments and growing from 0 downwards for + // local variables (index == 0 is not assigned so we add one here) + int soffs = OP_SYMBOL (IC_RESULT (ic))->stack; + if (soffs <= 0) + { + assert (soffs < 0); + soffs++; + } // if + if (_G.accInUse) + pic16_pushpCodeOp (pic16_popCopyReg (&pic16_pc_wreg)); + for (i = 0; i < aop->size; i++) + { + /* initialise for stack access via frame pointer */ + pic16_emitpcode (POC_MOVLW, pic16_popGetLit (soffs + i /*+ _G.stack_lat */ )); + pic16_emitpcode (POC_MOVFF, pic16_popGet2p (aop->aopu.stk.pop[i], pic16_popCopyReg (pic16_frame_plusw))); + } + + if (_G.accInUse) + pic16_poppCodeOp (pic16_popCopyReg (&pic16_pc_wreg)); + } + + if (!_G.resDirect) + { + for (i = 0; i < aop->size; i++) + { + PCOR (aop->aopu.stk.pop[i])->r->isFree = 1; + + if (bitVectBitValue (_G.sregsAlloc, PCOR (aop->aopu.stk.pop[i])->r->rIdx)) + { + bitVectUnSetBit (_G.sregsAlloc, PCOR (aop->aopu.stk.pop[i])->r->rIdx); +// pic16_popReleaseTempReg(aop->aopu.stk.pop[i], 0); + } + } + + if (_G.sregsAllocSet) + { + reg_info *sr; + + _G.sregsAllocSet = reverseSet (_G.sregsAllocSet); + for (sr = setFirstItem (_G.sregsAllocSet); sr; sr = setFirstItem (_G.sregsAllocSet)) + { + pic16_poppCodeOp (pic16_popRegFromIdx (sr->rIdx)); + deleteSetItem (&_G.sregsAllocSet, sr); + } + } + } + _G.resDirect = 0; + } + break; +#if 0 + case AOP_STK: + { + int sz = aop->size; + int stk = aop->aopu.aop_stk + aop->size; + bitVectUnSetBit (ic->rUsed, R0_IDX); + bitVectUnSetBit (ic->rUsed, R1_IDX); + + getFreePtr (ic, &aop, FALSE); + + if (options.stack10bit) + { + /* I'm not sure what to do here yet... */ + /* #STUB */ + fprintf (stderr, "*** Warning: probably generating bad code for " "10 bit stack mode.\n"); + } + + if (stk) + { + pic16_emitcode ("mov", "a,_bp"); + pic16_emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff); + pic16_emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name); + } + else + { + pic16_emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name); + } + + while (sz--) + { + pic16_emitcode ("pop", "acc"); + pic16_emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name); + if (!sz) + break; + pic16_emitcode ("dec", "%s", aop->aopu.aop_ptr->name); + } + op->aop = aop; + pic16_freeAsmop (op, NULL, ic, TRUE); + if (_G.r0Pushed) + { + pic16_emitcode ("pop", "ar0"); + _G.r0Pushed--; + } + + if (_G.r1Pushed) + { + pic16_emitcode ("pop", "ar1"); + _G.r1Pushed--; + } + } +#endif + + } +#endif + +dealloc: + /* all other cases just dealloc */ + if (op) + { + op->aop = NULL; + if (IS_SYMOP (op)) + { + OP_SYMBOL (op)->aop = NULL; + /* if the symbol has a spill */ + if (SPIL_LOC (op)) + SPIL_LOC (op)->aop = NULL; + } + } +} + +/*-----------------------------------------------------------------*/ +/* pic16_aopGet - for fetching value of the aop */ +/*-----------------------------------------------------------------*/ +char * +pic16_aopGet (asmop * aop, int offset, bool bit16, bool dname) +{ + //DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + /* offset is greater than size then zero */ + if (offset > (aop->size - 1) && aop->type != AOP_LIT) + return zero; + + /* depending on type */ + switch (aop->type) + { + case AOP_DIR: + if (offset > 0) + { + SNPRINTF(buffer, sizeof(buffer), "(%s + %d)", aop->aopu.aop_dir, offset); + DEBUGpic16_emitcode (";", "oops AOP_DIR did this %s\n", buffer); + return Safe_strdup(buffer); + } + else + return Safe_strdup(aop->aopu.aop_dir); + + case AOP_REG: + return aop->aopu.aop_reg[offset]->name; + + case AOP_CRY: + return aop->aopu.aop_dir; + + case AOP_ACC: + DEBUGpic16_emitcode (";Warning -pic port ignoring get(AOP_ACC)", "%d\toffset: %d", __LINE__, offset); +// fprintf(stderr, "%s:%d Warning -pic port ignoring get(AOP_ACC)\n",__FILE__, __LINE__); +// assert( 0 ); +// return aop->aopu.aop_str[offset]; //->"AOP_accumulator_bug"; + return Safe_strdup("WREG"); + + case AOP_LIT: + SNPRINTF(buffer, sizeof(buffer), "0x%02x", pic16aopLiteral (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"; + if (!strcmp (aop->aopu.aop_str[offset], "WREG")) + { + aop->type = AOP_ACC; + return Safe_strdup ("_WREG"); + } + DEBUGpic16_emitcode (";", "%d - %s", __LINE__, aop->aopu.aop_str[offset]); + return aop->aopu.aop_str[offset]; + + case AOP_PCODE: + { + pCodeOp *pcop = aop->aopu.pcop; + DEBUGpic16_emitcode (";", "%d: pic16_aopGet AOP_PCODE type %s", __LINE__, pic16_pCodeOpType (pcop)); + if (pcop->name) + { + DEBUGpic16_emitcode (";", "%s offset %d", pcop->name, PCOI (pcop)->offset); + //SNPRINTF(buffer, sizeof(buffer), "(%s+0x%02x)", pcop->name, PCOI(aop->aopu.pcop)->offset); + if (offset > 0) + { + SNPRINTF(buffer, sizeof(buffer), "(%s + %d)", pic16_get_op (pcop, NULL, 0), offset); + } + else + { + SNPRINTF(buffer, sizeof(buffer), "%s", pic16_get_op (pcop, NULL, 0)); + } + } + else + SNPRINTF(buffer, sizeof(buffer), "0x%02x", PCOI (aop->aopu.pcop)->offset); + + } + return Safe_strdup(buffer); + +#if 0 + case AOP_PAGED: + DEBUGpic16_emitcode (";", "oops AOP_PAGED did this %s\n", s); + if (offset) + { + SNPRINTF(buffer, sizeof(buffer), "(%s + %d)", aop->aopu.aop_dir, offset); + } + else + SNPRINTF(buffer, sizeof(buffer), "%s", aop->aopu.aop_dir); + DEBUGpic16_emitcode (";", "oops AOP_PAGED did this %s\n", s); + return Safe_strdup(buffer); +#endif + + case AOP_STA: + return Safe_strdup(PCOR(aop->aopu.stk.pop[offset])->r->name); + + case AOP_STK: +// pCodeOp *pcop = aop->aop + break; + + } + + fprintf (stderr, "%s:%d unsupported aop->type: %s\n", __FILE__, __LINE__, pic16_AopType (aop->type)); + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "aopget got unsupported aop->type"); + exit (0); +} + + + +/* lock has the following meaning: When allocating temporary registers + * for stack variables storage, the value of the temporary register is + * saved on stack. Its value is restored at the end. This procedure is + * done via calls to pic16_aopOp and pic16_freeAsmop functions. There is + * a possibility that before a call to pic16_aopOp, a temporary register + * is allocated for a while and it is freed after some time, this will + * mess the stack and values will not be restored properly. So use lock=1 + * to allocate temporary registers used internally by the programmer, and + * lock=0 to allocate registers for stack use. lock=1 will emit a warning + * to inform the compiler developer about a possible bug. This is an internal + * feature for developing the compiler -- VR */ + +int _TempReg_lock = 0; +/*-----------------------------------------------------------------*/ +/* pic16_popGetTempReg - create a new temporary pCodeOp */ +/*-----------------------------------------------------------------*/ +pCodeOp * +pic16_popGetTempReg (int lock) +{ + pCodeOp *pcop = NULL; + symbol *cfunc; + +// DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + if (_TempReg_lock) + { +// werror(W_POSSBUG2, __FILE__, __LINE__); + } + + _TempReg_lock += lock; + + cfunc = currFunc; + currFunc = NULL; + + pcop = pic16_newpCodeOp (NULL, PO_GPR_TEMP); + if (pcop && pcop->type == PO_GPR_TEMP && PCOR (pcop)->r) + { + PCOR (pcop)->r->wasUsed = 1; + PCOR (pcop)->r->isFree = 0; + + /* push value on stack */ + pic16_pushpCodeOp (pic16_pCodeOpCopy (pcop)); + } + + currFunc = cfunc; + + return pcop; +} + +/*-----------------------------------------------------------------*/ +/* pic16_popGetTempRegCond - create a new temporary pCodeOp which */ +/* is not part of f, but don't save if */ +/* inside v */ +/*-----------------------------------------------------------------*/ +pCodeOp * +pic16_popGetTempRegCond (bitVect * f, bitVect * v, int lock) +{ + pCodeOp *pcop = NULL; + symbol *cfunc; + int i; + +// DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + if (_TempReg_lock) + { +// werror(W_POSSBUG2, __FILE__, __LINE__); + } + + _TempReg_lock += lock; + + cfunc = currFunc; + currFunc = NULL; + + i = bitVectFirstBit (f); + while (i < 128) + { + + /* bypass registers that are used by function */ + if (!bitVectBitValue (f, i)) + { + + /* bypass registers that are already allocated for stack access */ + if (!bitVectBitValue (v, i)) + { + +// debugf("getting register rIdx = %d\n", i); + /* ok, get the operand */ + pcop = pic16_newpCodeOpReg (i); + + /* should never by NULL */ + assert (pcop != NULL); + + + /* sanity check */ + if (pcop && pcop->type == PO_GPR_TEMP && PCOR (pcop)->r) + { + int found = 0; + + PCOR (pcop)->r->wasUsed = 1; + PCOR (pcop)->r->isFree = 0; + + + { + reg_info *sr; + + for (sr = setFirstItem (_G.sregsAllocSet); sr; sr = setNextItem (_G.sregsAllocSet)) + { + + if (sr->rIdx == PCOR (pcop)->r->rIdx) + { + /* already used in previous steps, break */ + found = 1; + break; + } + } + } + + /* caller takes care of the following */ +// bitVectSetBit(v, i); + + if (!found) + { + /* push value on stack */ + pic16_pushpCodeOp (pic16_pCodeOpCopy (pcop)); + addSet (&_G.sregsAllocSet, PCOR (pcop)->r); + } + + break; + } + } + } + i++; + } + + currFunc = cfunc; + + return pcop; +} + + +/*-----------------------------------------------------------------*/ +/* pic16_popReleaseTempReg - create a new temporary pCodeOp */ +/*-----------------------------------------------------------------*/ +void +pic16_popReleaseTempReg (pCodeOp * pcop, int lock) +{ + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + + _TempReg_lock -= lock; + + if (pcop && pcop->type == PO_GPR_TEMP && PCOR (pcop)->r) + { + PCOR (pcop)->r->isFree = 1; + + pic16_poppCodeOp (pic16_pCodeOpCopy (pcop)); + } +} + +/*-----------------------------------------------------------------*/ +/* pic16_popGetLabel - create a new pCodeOp of type PO_LABEL */ +/*-----------------------------------------------------------------*/ +pCodeOp * +pic16_popGetLabel (int key) +{ + + DEBUGpic16_emitcode ("; ***", "%s key=%d, label offset %d", __FUNCTION__, key, pic16_labelOffset); + + if (key > max_key) + max_key = key; + + return pic16_newpCodeOpLabel (NULL, labelKey2num (key + pic16_labelOffset)); +} + +/*-----------------------------------------------------------------*/ +/* pic16_popCopyReg - copy a pcode operator */ +/*-----------------------------------------------------------------*/ +pCodeOp * +pic16_popCopyReg (pCodeOpReg * pc) +{ + pCodeOpReg *pcor; + + pcor = Safe_malloc(sizeof(pCodeOpReg)); + memcpy(pcor, pc, sizeof(pCodeOpReg)); + pcor->r->wasUsed = TRUE; + + //pcor->pcop.type = pc->pcop.type; + if (pc->pcop.name) + { + if (!(pcor->pcop.name = Safe_strdup (pc->pcop.name))) + fprintf (stderr, "oops %s %d", __FILE__, __LINE__); + } + else + pcor->pcop.name = NULL; + + //pcor->r = pc->r; + //pcor->rIdx = pc->rIdx; + //pcor->r->wasUsed=1; + //pcor->instance = pc->instance; + +// DEBUGpic16_emitcode ("; ***","%s , copying %s, rIdx=%d",__FUNCTION__,pc->pcop.name,pc->rIdx); + + return PCOP (pcor); +} + +/*-----------------------------------------------------------------*/ +/* pic16_popGetLit - asm operator to pcode operator conversion */ +/*-----------------------------------------------------------------*/ +pCodeOp * +pic16_popGetLit (int lit) +{ + return pic16_newpCodeOpLit (lit); +} + +/* Allow for 12 bit literals (LFSR x, <here!>). */ +pCodeOp * +pic16_popGetLit12 (int lit) +{ + return pic16_newpCodeOpLit12 (lit); +} + +/*-----------------------------------------------------------------*/ +/* pic16_popGetLit2 - asm operator to pcode operator conversion */ +/*-----------------------------------------------------------------*/ +pCodeOp * +pic16_popGetLit2 (int lit, pCodeOp * arg2) +{ + return pic16_newpCodeOpLit2 (lit, arg2); +} + + +/*-----------------------------------------------------------------*/ +/* pic16_popGetImmd - asm operator to pcode immediate conversion */ +/*-----------------------------------------------------------------*/ +pCodeOp * +pic16_popGetImmd (char *name, unsigned int offset, int index) +{ + return pic16_newpCodeOpImmd (name, offset, index, 0); +} + + +/*-----------------------------------------------------------------*/ +/* pic16_popGet - asm operator to pcode operator conversion */ +/*-----------------------------------------------------------------*/ +pCodeOp * +pic16_popGetWithString (char *str) +{ + pCodeOp *pcop; + + + if (!str) + { + fprintf (stderr, "NULL string %s %d\n", __FILE__, __LINE__); + exit (1); + } + + pcop = pic16_newpCodeOp (str, PO_STR); + + return pcop; +} + +/*-----------------------------------------------------------------*/ +/* pic16_popRegFromString - */ +/*-----------------------------------------------------------------*/ +static pCodeOp * +pic16_popRegFromString (char *str, int size, int offset, operand * op) +{ + + pCodeOp *pcop = Safe_alloc(sizeof(pCodeOpReg)); + pcop->type = PO_DIR; + + DEBUGpic16_emitcode (";", "%d %s %s %d/%d", __LINE__, __FUNCTION__, str, size, offset); // patch 14 + // fprintf(stderr, "%s:%d: register name = %s pos = %d/%d\n", __FUNCTION__, __LINE__, str, offset, size); + + if (!str) + str = "BAD_STRING"; + + pcop->name = Safe_strdup(str); + + //pcop->name = Safe_strdup( ( (str) ? str : "BAD STRING")); + + PCOR (pcop)->r = pic16_dirregWithName (pcop->name); +// PCOR(pcop)->r->wasUsed = 1; + + /* make sure that register doesn't exist, + * and operand isn't NULL + * and symbol isn't in codespace (codespace symbols are handled elsewhere) */ + if ((PCOR (pcop)->r == NULL) && (op) && !IN_CODESPACE (SPEC_OCLS (OP_SYM_ETYPE (op)))) + { +// fprintf(stderr, "%s:%d - couldn't find %s in allocated regsters, size= %d ofs= %d\n", +// __FUNCTION__, __LINE__, str, size, offset); + + PCOR (pcop)->r = pic16_allocRegByName (pcop->name, size, op); + //fprintf(stderr, "%s:%d: WARNING: need to allocate new register by name -> %s\n", __FILE__, __LINE__, str); + + } + PCOR (pcop)->instance = offset; + + return pcop; +} + +static pCodeOp * +pic16_popRegFromIdx (int rIdx) +{ + pCodeOp *pcop; + +// DEBUGpic16_emitcode ("; ***","%s,%d\trIdx=0x%x", __FUNCTION__,__LINE__,rIdx); +// fprintf(stderr, "%s:%d rIdx = 0x%0x\n", __FUNCTION__, __LINE__, rIdx); + + pcop = Safe_alloc(sizeof(pCodeOpReg)); + PCOR (pcop)->rIdx = rIdx; + PCOR (pcop)->r = pic16_regWithIdx (rIdx); + if (!PCOR (pcop)->r) + PCOR (pcop)->r = pic16_allocWithIdx (rIdx); + + PCOR (pcop)->r->isFree = 0; + PCOR (pcop)->r->wasUsed = 1; + + pcop->type = PCOR (pcop)->r->pc_type; + + return pcop; +} + +/*---------------------------------------------------------------------------------*/ +/* pic16_popGet2 - a variant of pic16_popGet to handle two memory operand commands */ +/* VR 030601 */ +/*---------------------------------------------------------------------------------*/ +pCodeOp * +pic16_popGet2 (asmop * aop_src, asmop * aop_dst, int offset) +{ + pCodeOp2 *pcop2 = (pCodeOp2 *) pic16_newpCodeOp2 (pic16_popGet (aop_src, offset), pic16_popGet (aop_dst, offset)); + return PCOP (pcop2); +} + +/*--------------------------------------------------------------------------------.-*/ +/* pic16_popGet2p - a variant of pic16_popGet to handle two memory operand commands */ +/* VR 030601 , adapted by Hans Dorn */ +/*--------------------------------------------------------------------------------.-*/ +pCodeOp * +pic16_popGet2p (pCodeOp * src, pCodeOp * dst) +{ + pCodeOp2 *pcop2; + pcop2 = (pCodeOp2 *) pic16_newpCodeOp2 (src, dst); + return PCOP (pcop2); +} + +/*---------------------------------------------------------------------------------*/ +/* pic16_popCombine2 - combine two pCodeOpReg variables into one for use with */ +/* movff instruction */ +/*---------------------------------------------------------------------------------*/ +pCodeOp * +pic16_popCombine2 (pCodeOpReg * src, pCodeOpReg * dst, int noalloc) +{ + pCodeOp2 *pcop2 = (pCodeOp2 *) pic16_newpCodeOp2 (pic16_popCopyReg (src), pic16_popCopyReg (dst)); + + return PCOP (pcop2); +} + +/*-----------------------------------------------------------------*/ +/* pic16_popGet - asm operator to pcode operator conversion */ +/*-----------------------------------------------------------------*/ +pCodeOp * +pic16_popGet (asmop * aop, int offset) //, bool bit16, bool dname) +{ +// char *s = buffer ; +// char *rs; + pCodeOp *pcop; + + FENTRY2; + + /* offset is greater than size then zero */ + +// if (offset > (aop->size - 1) && +// aop->type != AOP_LIT) +// return NULL; //zero; + + /* depending on type */ + switch (aop->type) + { + case AOP_STA: + /* pCodeOp is already allocated from aopForSym */ + DEBUGpic16_emitcode (";---", "%d getting stack + offset %d\n", __LINE__, offset); + pcop = pic16_pCodeOpCopy (aop->aopu.stk.pop[offset]); + return (pcop); + + case AOP_ACC: + { + int rIdx = IDX_WREG; //aop->aopu.aop_reg[offset]->rIdx; + +// fprintf (stderr, "%s:%d returning register AOP_ACC %s\n", __FILE__, __LINE__, aop->aopu.aop_str[offset]); + + DEBUGpic16_emitcode (";", "%d\tAOP_ACC", __LINE__); + + pcop = Safe_alloc(sizeof(pCodeOpReg)); + PCOR (pcop)->rIdx = rIdx; + PCOR (pcop)->r = pic16_typeRegWithIdx (rIdx, REG_SFR, 1); // pic16_regWithIdx(rIdx); + PCOR (pcop)->r->wasUsed = 1; + PCOR (pcop)->r->isFree = 0; + + PCOR (pcop)->instance = offset; + pcop->type = PCOR (pcop)->r->pc_type; +// DEBUGpic16_emitcode(";","%d register idx = %d name =%s",__LINE__,rIdx,rs); + return pcop; + + +// return pic16_popRegFromString(aop->aopu.aop_str[offset], aop->size, offset); +// return pic16_newpCodeOpRegFromStr(aop->aopu.aop_str[offset]); + +// assert( 0 ); + } + + case AOP_DIR: + DEBUGpic16_emitcode (";", "%d\tAOP_DIR (name = %s)", __LINE__, aop->aopu.aop_dir); + return pic16_popRegFromString (aop->aopu.aop_dir, aop->size, offset, NULL); + +#if 0 + case AOP_PAGED: + DEBUGpic16_emitcode (";", "%d\tAOP_DIR", __LINE__); + return pic16_popRegFromString (aop->aopu.aop_dir, aop->size, offset, NULL); +#endif + + case AOP_REG: + { + int rIdx; + +// debugf2("aop = %p\toffset = %d\n", aop, offset); +// assert (aop && aop->aopu.aop_reg[offset] != NULL); + rIdx = aop->aopu.aop_reg[offset]->rIdx; + + DEBUGpic16_emitcode (";", "%d\tAOP_REG", __LINE__); + + pcop = Safe_alloc(sizeof(pCodeOpReg)); +// pcop->type = PO_GPR_REGISTER; + PCOR (pcop)->rIdx = rIdx; + PCOR (pcop)->r = pic16_allocWithIdx (rIdx); //pic16_regWithIdx(rIdx); + PCOR (pcop)->r->wasUsed = 1; + PCOR (pcop)->r->isFree = 0; + + PCOR (pcop)->instance = offset; + pcop->type = PCOR (pcop)->r->pc_type; + + DEBUGpic16_emitcode (";*+*", "%d\tAOP_REG type = %s", __LINE__, dumpPicOptype (pcop->type)); +// rs = aop->aopu.aop_reg[offset]->name; +// DEBUGpic16_emitcode(";","%d register idx = %d name = %s",__LINE__,rIdx,rs); + return pcop; + } + + case AOP_CRY: + DEBUGpic16_emitcode (";", "%d\tAOP_CRY", __LINE__); + + pcop = pic16_newpCodeOpBit (aop->aopu.aop_dir, -1, 1, PO_GPR_REGISTER); + PCOR (pcop)->instance = offset; + PCOR (pcop)->r = pic16_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: + DEBUGpic16_emitcode (";", "%d\tAOP_LIT", __LINE__); + return pic16_newpCodeOpLit (pic16aopLiteral (aop->aopu.aop_lit, offset)); + + case AOP_STR: + DEBUGpic16_emitcode (";", "%d AOP_STR %s", __LINE__, aop->aopu.aop_str[offset]); + return pic16_newpCodeOpRegFromStr (aop->aopu.aop_str[offset]); + + /* + pcop = Safe_alloc(sizeof(pCodeOpReg)); + PCOR(pcop)->r = pic16_allocRegByName(aop->aopu.aop_str[offset]); + PCOR(pcop)->rIdx = PCOR(pcop)->r->rIdx; + pcop->type = PCOR(pcop)->r->pc_type; + pcop->name = PCOR(pcop)->r->name; + + return pcop; + */ + + case AOP_PCODE: + DEBUGpic16_emitcode (";", "pic16_popGet AOP_PCODE (%s) %d %s offset %d", pic16_pCodeOpType (aop->aopu.pcop), + __LINE__, ((aop->aopu.pcop->name) ? (aop->aopu.pcop->name) : "no name"), offset); + pcop = pic16_pCodeOpCopy (aop->aopu.pcop); + switch (aop->aopu.pcop->type) + { + case PO_DIR: + PCOR (pcop)->instance += offset; + break; + case PO_IMMEDIATE: + PCOI (pcop)->offset = offset; + break; + case PO_WREG: + assert (offset == 0); + break; + default: + fprintf (stderr, "%s: unhandled aop->aopu.pcop->type %d\n", __FUNCTION__, aop->aopu.pcop->type); + assert (0); /* should never reach here */ ; + } + return pcop; + } + + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "pic16_popGet got unsupported aop->type"); + exit (0); +} + +/*-------------------------------------------------------------------------*/ +/* pic16_popGetImmed - immediate asm operator to pcode operator conversion */ +/*-------------------------------------------------------------------------*/ +static pCodeOp * +pic16_popGetImmed(asmop *aop, int offset, int overload) +{ + pCodeOp *pcop; + + FENTRY2; + + if (aop->type == AOP_PCODE) + { + if (aop->aopu.pcop->type == PO_IMMEDIATE) + { + pcop = pic16_pCodeOpCopy(aop->aopu.pcop); + PCOI(pcop)->offset = offset; // offset: "LOW", "HIGH", "UPPER" + PCOI(pcop)->index += overload; // LOW(ptr + index + overload) + return pcop; + } + + fprintf(stderr, "%s: Only handled PO_IMMEDIATE.\n", __FUNCTION__); + assert(0); + } + + werror(E_INTERNAL_ERROR, __FILE__, __LINE__, "pic16_popGetImmed supported only AOP_PCODE."); + exit(0); +} + +/*-----------------------------------------------------------------*/ +/* pic16_aopPut - puts a string for a aop */ +/*-----------------------------------------------------------------*/ +void +pic16_aopPut (asmop * aop, char *s, int offset) +{ + symbol *lbl; + + return; + + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + + if (aop->size && offset > (aop->size - 1)) + { + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "pic16_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 > 0) + { + SNPRINTF(buffer, sizeof(buffer), "(%s + %d)", aop->aopu.aop_dir, offset); + fprintf (stderr, "oops pic16_aopPut:AOP_DIR did this %s\n", s); + } + else + SNPRINTF(buffer, sizeof(buffer), "%s", aop->aopu.aop_dir); + + if (strcmp(buffer, s)) + { + DEBUGpic16_emitcode (";", "%d", __LINE__); + if (strcmp (s, "W")) + pic16_emitcode ("movf", "%s,w", s); + + pic16_emitcode ("movwf", "%s", buffer); + + if (strcmp (s, "W")) + { + pic16_emitcode (";BUG!? should have this:movf", "%s,w %d", s, __LINE__); + if (offset >= aop->size) + { + pic16_emitpcode (POC_CLRF, pic16_popGet (aop, offset)); + break; + } + else + pic16_emitpcode (POC_MOVLW, pic16_popGetImmd (s, offset, 0)); + } + + pic16_emitpcode (POC_MOVWF, pic16_popGet (aop, offset)); + + + } + break; + + case AOP_REG: + if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0) // && + { + //strcmp(aop->aopu.aop_reg[offset]->dname,s)!= 0){ + /* + if (*s == '@' || + strcmp(s,"r0") == 0 || + strcmp(s,"r1") == 0 || + strcmp(s,"r2") == 0 || + strcmp(s,"r3") == 0 || + strcmp(s,"r4") == 0 || + strcmp(s,"r5") == 0 || + strcmp(s,"r6") == 0 || + strcmp(s,"r7") == 0 ) + pic16_emitcode("mov","%s,%s ; %d", + aop->aopu.aop_reg[offset]->dname,s,__LINE__); + else + */ + + if (strcmp (s, "W") == 0) + pic16_emitcode ("movf", "%s,w ; %d", s, __LINE__); + + pic16_emitcode ("movwf", "%s", aop->aopu.aop_reg[offset]->name); + + if (strcmp (s, zero) == 0) + { + pic16_emitpcode (POC_CLRF, pic16_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; + + DEBUGpic16_emitcode (";", "%d", __LINE__); + pcop->name = Safe_strdup (s); + pic16_emitpcode (POC_MOVFW, pcop); + pic16_emitpcode (POC_MOVWF, pic16_popGet (aop, offset)); + } + else if (strcmp (s, one) == 0) + { + pic16_emitpcode (POC_CLRF, pic16_popGet (aop, offset)); + pic16_emitpcode (POC_INCF, pic16_popGet (aop, offset)); + } + else + { + pic16_emitpcode (POC_MOVWF, pic16_popGet (aop, offset)); + } + } + break; + + case AOP_STK: + if (strcmp (s, "a") == 0) + pic16_emitcode ("push", "acc"); + else + pic16_emitcode ("push", "%s", s); + break; + + case AOP_CRY: + /* if bit variable */ + if (!aop->aopu.aop_dir) + { + pic16_emitcode ("clr", "a"); + pic16_emitcode ("rlc", "a"); + } + else + { + if (s == zero) + pic16_emitcode ("clr", "%s", aop->aopu.aop_dir); + else if (s == one) + pic16_emitcode ("setb", "%s", aop->aopu.aop_dir); + else if (!strcmp (s, "c")) + pic16_emitcode ("mov", "%s,c", aop->aopu.aop_dir); + else + { + lbl = newiTempLabel (NULL); + + if (strcmp (s, "a")) + { + MOVA (s); + } + pic16_emitcode ("clr", "c"); + pic16_emitcode ("jz", "%05d_DS_", labelKey2num (lbl->key)); + pic16_emitcode ("cpl", "c"); + pic16_emitcode ("", "%05d_DS_:", labelKey2num (lbl->key)); + pic16_emitcode ("mov", "%s,c", aop->aopu.aop_dir); + } + } + break; + + case AOP_STR: + aop->coff = offset; + if (strcmp (aop->aopu.aop_str[offset], s)) + pic16_emitcode ("mov", "%s,%s ; %d", aop->aopu.aop_str[offset], s, __LINE__); + break; + + case AOP_ACC: + aop->coff = offset; + if (!offset && (strcmp (s, "acc") == 0)) + break; + + if (strcmp (aop->aopu.aop_str[offset], s)) + pic16_emitcode ("mov", "%s,%s ; %d", aop->aopu.aop_str[offset], s, __LINE__); + break; + + default: + fprintf (stderr, "%s:%d: unknown aop->type = 0x%x\n", __FILE__, __LINE__, aop->type); +// werror(E_INTERNAL_ERROR,__FILE__,__LINE__, +// "pic16_aopPut got unsupported aop->type"); +// exit(0); + } + +} + +/*-----------------------------------------------------------------*/ +/* pic16_mov2w - generate either a MOVLW or MOVFW based operand type */ +/*-----------------------------------------------------------------*/ +void +pic16_mov2w (asmop * aop, int offset) +{ + int isWREG = (aop->type != AOP_STA && ! strcmp (pic16_aopGet(aop, 0, TRUE, FALSE), "WREG")); + + DEBUGpic16_emitcode ("; ***", "%s %d offset=%d", __FUNCTION__, __LINE__, offset); + + if (pic16_isLitAop (aop)) + pic16_emitpcode (POC_MOVLW, pic16_popGet (aop, offset)); + else if (isWREG) + DEBUGpic16_emitcode ("; ***", "ignore MOVF\tWREG, W", __FUNCTION__, __LINE__); + else + pic16_emitpcode (POC_MOVFW, pic16_popGet (aop, offset)); +} + +void +pic16_mov2w_volatile (asmop * aop) +{ + int i; + + if (!pic16_isLitAop (aop)) + { + // may need to protect this from the peepholer -- this is not nice but works... + pic16_addpCode2pBlock (pb, pic16_newpCodeAsmDir (";", "VOLATILE READ - BEGIN")); + for (i = 0; i < aop->size; i++) + { + if (i > 0) + { + pic16_addpCode2pBlock (pb, pic16_newpCodeAsmDir (";", "VOLATILE READ - MORE")); + } // if + pic16_emitpcode (POC_MOVFW, pic16_popGet (aop, i)); + } // for + pic16_addpCode2pBlock (pb, pic16_newpCodeAsmDir (";", "VOLATILE READ - END")); + } +} + +void +pic16_mov2f (asmop * dst, asmop * src, int offset) +{ + if (pic16_isLitAop (src)) + { + int dstIsWREG = (dst->type != AOP_STA && ! strcmp(pic16_aopGet(dst, 0, TRUE, FALSE), "WREG")); + + pic16_emitpcode (POC_MOVLW, pic16_popGet (src, offset)); + + if (! dstIsWREG) + { + pic16_emitpcode (POC_MOVWF, pic16_popGet(dst, offset)); + } + } + else + { + int srcIsWREG; + + if (pic16_sameRegsOfs (src, dst, offset)) + return; + + srcIsWREG = (src->type != AOP_STA && ! strcmp (pic16_aopGet (src, 0, TRUE, FALSE), "WREG")); + + if (srcIsWREG) + { + pic16_emitpcode (POC_MOVWF, pic16_popGet (dst, offset)); + } + else + { + int dstIsINTCON = (src->type != AOP_STA && ! strcmp (pic16_aopGet(src, 0, TRUE, FALSE), "INTCON")); + int dstIsPCL = (src->type != AOP_STA && ! strcmp (pic16_aopGet(src, 0, TRUE, FALSE), "PCL")); + + if (dstIsINTCON || dstIsPCL) + { + pic16_emitpcode (POC_MOVFW, pic16_popGet (src, offset)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (dst, offset)); + } + else + { + pic16_emitpcode(POC_MOVFF, pic16_popGet2p (pic16_popGet (src, offset), + pic16_popGet (dst, offset))); + } + } + } +} + +static void +pic16_movLit2f (pCodeOp * pc, int lit) +{ + if (0 == (lit & 0x00ff)) + { + pic16_emitpcode (POC_CLRF, pc); + } + else if (0xff == (lit & 0x00ff)) + { + pic16_emitpcode (POC_SETF, pc); + } + else + { + pic16_emitpcode (POC_MOVLW, pic16_popGetLit (lit & 0x00ff)); + if (pc->type != PO_WREG) + pic16_emitpcode (POC_MOVWF, pc); + } +} + +static void +mov2fp (pCodeOp * dst, asmop * src, int offset) +{ + if (pic16_isLitAop (src)) + { + pic16_emitpcode (POC_MOVLW, pic16_popGet (src, offset)); + + if (dst->type != PO_WREG) + { + pic16_emitpcode (POC_MOVWF, dst); + } + } + else + { + if (dst->type == PO_INTCON || dst->type == PO_PCL) + { + pic16_emitpcode (POC_MOVFW, pic16_popGet (src, offset)); + pic16_emitpcode (POC_MOVWF, dst); + } + else + { + pic16_emitpcode (POC_MOVFF, pic16_popGet2p (pic16_popGet (src, offset), dst)); + } + } +} + +void +pic16_testStackOverflow (void) +{ +#define GSTACK_TEST_NAME "_gstack_test" + + pic16_emitpcode (POC_CALL, pic16_popGetWithString (GSTACK_TEST_NAME)); + + { + symbol *sym; + + sym = newSymbol (GSTACK_TEST_NAME, 0); + SNPRINTF(sym->rname, sizeof(sym->rname), "%s", /*port->fun_prefix, */ GSTACK_TEST_NAME); +// strcpy(sym->rname, GSTACK_TEST_NAME); + checkAddSym (&externs, sym); + } +} + +/* push pcop into stack */ +void +pic16_pushpCodeOp (pCodeOp * pcop) +{ +// DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + if (pcop->type == PO_LITERAL) + { + pic16_emitpcode (POC_MOVLW, pcop); + pic16_emitpcode (POC_MOVWF, pic16_popCopyReg (pic16_stack_postdec)); + } + else + { + pic16_emitpcode (POC_MOVFF, pic16_popGet2p (pcop, pic16_popCopyReg (pic16_stack_postdec))); + } + + if (pic16_options.gstack) + pic16_testStackOverflow (); +} + +/* pop pcop from stack */ +void +pic16_poppCodeOp (pCodeOp * pcop) +{ + pic16_emitpcode (POC_MOVFF, pic16_popGet2p (pic16_popCopyReg (pic16_stack_preinc), pcop)); + if (pic16_options.gstack) + pic16_testStackOverflow (); +} + + +/*-----------------------------------------------------------------*/ +/* pushw - pushes wreg to stack */ +/*-----------------------------------------------------------------*/ +void +pushw (void) +{ + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + pic16_emitpcode (POC_MOVWF, pic16_popCopyReg (pic16_stack_postdec)); + if (pic16_options.gstack) + pic16_testStackOverflow (); +} + + +/*-----------------------------------------------------------------*/ +/* pushaop - pushes aop to stack */ +/*-----------------------------------------------------------------*/ +void +pushaop (asmop * aop, int offset) +{ + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + + if (_G.resDirect) + return; + + if (pic16_isLitAop (aop)) + { + pic16_emitpcode (POC_MOVLW, pic16_popGet (aop, offset)); + pic16_emitpcode (POC_MOVWF, pic16_popCopyReg (pic16_stack_postdec)); + } + else + { + pic16_emitpcode (POC_MOVFF, pic16_popGet2p (pic16_popGet (aop, offset), pic16_popCopyReg (pic16_stack_postdec))); + } + + if (pic16_options.gstack) + pic16_testStackOverflow (); +} + +/*-----------------------------------------------------------------*/ +/* popaop - pops aop from stack */ +/*-----------------------------------------------------------------*/ +void +popaop (asmop * aop, int offset) +{ + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + pic16_emitpcode (POC_MOVFF, pic16_popCombine2 (pic16_stack_preinc, PCOR (pic16_popGet (aop, offset)), 0)); + if (pic16_options.gstack) + pic16_testStackOverflow (); +} + +void +popaopidx (asmop * aop, int offset, int index) +{ + int ofs = 1; + + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + + if (STACK_MODEL_LARGE) + ofs++; + + pic16_emitpcode (POC_MOVLW, pic16_popGetLit (index + ofs)); + pic16_emitpcode (POC_MOVFF, pic16_popCombine2 (pic16_frame_plusw, PCOR (pic16_popGet (aop, offset)), 0)); + if (pic16_options.gstack) + pic16_testStackOverflow (); +} + +/*-----------------------------------------------------------------*/ +/* pic16_getDataSize - get the operand data size */ +/*-----------------------------------------------------------------*/ +int +pic16_getDataSize (operand * op) +{ + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + + + return AOP_SIZE (op); + + // tsd- in the pic port, the genptr size is 1, so this code here + // fails. ( in the 8051 port, the size was 4). +#if 0 + int size; + size = AOP_SIZE (op); + if (size == GPTRSIZE) + { + sym_link *type = operandType (op); + if (IS_GENPTR (type)) + { + /* generic pointer; arithmetic operations + * should ignore the high byte (pointer type). + */ + size--; + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + } + } + return size; +#endif +} + +/*-----------------------------------------------------------------*/ +/* pic16_outAcc - output Acc */ +/*-----------------------------------------------------------------*/ +void +pic16_outAcc (operand * result) +{ + int size, offset; + DEBUGpic16_emitcode ("; ***", "%s %d - ", __FUNCTION__, __LINE__); + DEBUGpic16_pic16_AopType (__LINE__, NULL, NULL, result); + + + size = pic16_getDataSize (result); + if (size) + { + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), 0)); + size--; + offset = 1; + /* unsigned or positive */ + while (size--) + pic16_emitpcode (POC_CLRF, pic16_popGet (AOP (result), offset++)); + } + +} + +/*-----------------------------------------------------------------*/ +/* pic16_outBitC - output a bit C */ +/* Move to result the value of Carry flag -- VR */ +/*-----------------------------------------------------------------*/ +void +pic16_outBitC (operand * result) +{ + int i; + + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + + /* if the result is bit */ + if (AOP_TYPE (result) == AOP_CRY) + { + fprintf (stderr, "%s:%d: pic16 port warning: unsupported case\n", __FILE__, __LINE__); + pic16_aopPut (AOP (result), "c", 0); + } + else + { + + i = AOP_SIZE (result); + while (i--) + { + pic16_emitpcode (POC_CLRF, pic16_popGet (AOP (result), i)); + } + pic16_emitpcode (POC_RLCF, pic16_popGet (AOP (result), 0)); + } +} + +/*-----------------------------------------------------------------*/ +/* pic16_outBitOp - output a bit from Op */ +/* Move to result the value of set/clr op -- VR */ +/*-----------------------------------------------------------------*/ +void +pic16_outBitOp (operand * result, pCodeOp * pcop) +{ + int i; + + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + + /* if the result is bit */ + if (AOP_TYPE (result) == AOP_CRY) + { + fprintf (stderr, "%s:%d: pic16 port warning: unsupported case\n", __FILE__, __LINE__); + pic16_aopPut (AOP (result), "c", 0); + } + else + { + + i = AOP_SIZE (result); + while (i--) + { + pic16_emitpcode (POC_CLRF, pic16_popGet (AOP (result), i)); + } + pic16_emitpcode (POC_RRCF, pcop); + pic16_emitpcode (POC_RLCF, pic16_popGet (AOP (result), 0)); + } +} + +/*-----------------------------------------------------------------*/ +/* pic16_toBoolean - emit code for orl a,operator(sizeop) */ +/*-----------------------------------------------------------------*/ +void +pic16_toBoolean (operand * oper) +{ + int size = AOP_SIZE (oper) - 1; + int offset = 1; + + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + + if (AOP_TYPE (oper) != AOP_ACC) + { + pic16_emitpcode (POC_MOVFW, pic16_popGet (AOP (oper), 0)); + } + while (size--) + { + pic16_emitpcode (POC_IORFW, pic16_popGet (AOP (oper), offset++)); + } +} + +/*-----------------------------------------------------------------*/ +/* genUminusFloat - unary minus for floating points */ +/*-----------------------------------------------------------------*/ +static void +genUminusFloat (operand * op, operand * result) +{ + int size, offset = 0; + + FENTRY; + /* for this we just need to flip the + first it then copy the rest in place */ + size = AOP_SIZE (op); + assert (size == AOP_SIZE (result)); + + while (size--) + { + pic16_mov2f (AOP (result), AOP (op), offset); + offset++; + } + + /* toggle the MSB's highest bit */ + pic16_emitpcode (POC_BTG, pic16_popCopyGPR2Bit (pic16_popGet (AOP (result), offset - 1), 7)); +} + +/*-----------------------------------------------------------------*/ +/* genUminus - unary minus code generation */ +/*-----------------------------------------------------------------*/ +static void +genUminus (iCode * ic) +{ + int lsize, rsize, i; + sym_link *optype; + symbol *label; + int needLabel = 0; + + FENTRY; + + /* assign asmops */ + pic16_aopOp (IC_LEFT (ic), ic, FALSE); + pic16_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) + { + + pic16_emitpcode (POC_BCF, pic16_popGet (AOP (IC_RESULT (ic)), 0)); + pic16_emitpcode (POC_BTFSS, pic16_popGet (AOP (IC_LEFT (ic)), 0)); + pic16_emitpcode (POC_BSF, pic16_popGet (AOP (IC_RESULT (ic)), 0)); + goto release; + } + + optype = operandType (IC_LEFT (ic)); + + /* if float then do float stuff */ + if (IS_FLOAT (optype) || IS_FIXED (optype)) + { + if (IS_FIXED (optype)) + debugf ("implement fixed16x16 type\n", 0); + + genUminusFloat (IC_LEFT (ic), IC_RESULT (ic)); + goto release; + } + + /* otherwise subtract from zero by taking the 2's complement */ + lsize = AOP_SIZE (IC_LEFT (ic)); + rsize = AOP_SIZE (IC_RESULT (ic)); + label = newiTempLabel (NULL); + + if (pic16_sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic)))) + { + /* If the result is longer than the operand, + store sign extension (0x00 or 0xff) in W */ + if (rsize > lsize) + { + pic16_emitpcode (POC_MOVLW, pic16_popGetLit (0x00)); + pic16_emitpcode (POC_BTFSS, pic16_popCopyGPR2Bit (pic16_popGet (AOP (IC_LEFT (ic)), lsize - 1), 7)); + pic16_emitpcode (POC_MOVLW, pic16_popGetLit (0xFF)); + } + for (i = rsize - 1; i > 0; --i) + { + if (i > lsize - 1) + { + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (IC_RESULT (ic)), i)); + } + else + { + pic16_emitpcode (POC_COMF, pic16_popGet (AOP (IC_RESULT (ic)), i)); + } // if + } // for + pic16_emitpcode (POC_NEGF, pic16_popGet (AOP (IC_RESULT (ic)), 0)); + for (i = 1; i < rsize; ++i) + { + if (i == rsize - 1) + { + emitSKPNZ; + } + else + { + pic16_emitpcode (POC_BNZ, pic16_popGetLabel (label->key)); + needLabel++; + } + pic16_emitpcode (POC_INCF, pic16_popGet (AOP (IC_RESULT (ic)), i)); + } // for + } + else + { + for (i = min (rsize, lsize) - 1; i >= 0; i--) + { + pic16_emitpcode (POC_COMFW, pic16_popGet (AOP (IC_LEFT (ic)), i)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (IC_RESULT (ic)), i)); + } // for + /* Sign extend if the result is longer than the operand */ + if (rsize > lsize) + { + pic16_emitpcode (POC_MOVLW, pic16_popGetLit (0x00)); + pic16_emitpcode (POC_BTFSC, pic16_popCopyGPR2Bit (pic16_popGet (AOP (IC_RESULT (ic)), lsize - 1), 7)); + pic16_emitpcode (POC_MOVLW, pic16_popGetLit (0xFF)); + for (i = rsize - 1; i > lsize - 1; --i) + { + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (IC_RESULT (ic)), i)); + } // for + } // if + if (rsize > 1) + { + for (i = 0; i < rsize - 2; i++) + { + pic16_emitpcode (POC_INCF, pic16_popGet (AOP (IC_RESULT (ic)), i)); + pic16_emitpcode (POC_BNZ, pic16_popGetLabel (label->key)); + needLabel++; + } // for + pic16_emitpcode (POC_INFSNZ, pic16_popGet (AOP (IC_RESULT (ic)), rsize - 2)); + } // if + pic16_emitpcode (POC_INCF, pic16_popGet (AOP (IC_RESULT (ic)), rsize - 1)); + } + if (needLabel) + pic16_emitpLabel (label->key); + +release: + /* release the aops */ + pic16_freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1)); + pic16_freeAsmop (IC_RESULT (ic), NULL, ic, TRUE); +} + +void +pic16_loadFromReturn (operand * op, int offset, pCodeOp * src) +{ + if ((AOP (op)->type == AOP_PCODE) && (AOP (op)->aopu.pcop->type == PO_IMMEDIATE)) + { + pic16_emitpcode (POC_MOVFW, src); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (op), offset)); + } + else + { + pic16_emitpcode (POC_MOVFF, pic16_popGet2p (src, pic16_popGet (AOP (op), offset))); + } +} + +/*-----------------------------------------------------------------*/ + +static void +free_stack_parameters (int Parameter_count) +{ + if (Parameter_count < 1) + { + return; + } + + if (Parameter_count == 1) + { + pic16_emitpcode (POC_MOVF, pic16_popCopyReg (pic16_stack_postinc)); + } + else if (Parameter_count == 2) + { + pic16_emitpcode (POC_MOVF, pic16_popCopyReg (pic16_stack_postinc)); + pic16_emitpcode (POC_MOVF, pic16_popCopyReg (pic16_stack_postinc)); + } + else + { + pic16_emitpcode (POC_MOVLW, pic16_popGetLit (Parameter_count)); + pic16_emitpcode (POC_ADDWF, pic16_popCopyReg (pic16_stackpnt_lo)); // &pic16_pc_fsr1l)); + + if (STACK_MODEL_LARGE) + { + emitSKPNC; + pic16_emitpcode (POC_INCF, pic16_popCopyReg (pic16_stackpnt_hi)); // &pic16_pc_fsr1h)); + } + } +} + +/*-----------------------------------------------------------------*/ +/* assignResultValue - assign results to oper, rescall==1 is */ +/* called from genCall() or genPcall() */ +/*-----------------------------------------------------------------*/ +static void +assignResultValue (operand * oper, int res_size, int rescall) +{ + int size = AOP_SIZE (oper); + int offset = 0; + + FENTRY2; +// DEBUGpic16_emitcode ("; ***","%s %d rescall:%d size:%d",__FUNCTION__,__LINE__,rescall,size); // patch 14 + DEBUGpic16_pic16_AopType (__LINE__, oper, NULL, NULL); + + if (rescall) + { + /* assign result from a call/pcall function() */ + + /* function results are stored in a special order, + * see top of file with Function return policy, or manual */ + + if (size <= 4) + { + /* 8-bits, result in WREG */ + if (AOP_TYPE(oper) != AOP_ACC) + { + /* If destination NOT WREG. */ + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (oper), 0)); + } + else + { + DEBUGpic16_emitcode ("; ***", "ignore MOVWF\tWREG", __FUNCTION__, __LINE__); + } + + if (size > 1 && res_size > 1) + { + /* 16-bits, result in PRODL:WREG */ + pic16_loadFromReturn (oper, 1, pic16_popCopyReg (&pic16_pc_prodl)); + } + + if (size > 2 && res_size > 2) + { + /* 24-bits, result in PRODH:PRODL:WREG */ + pic16_loadFromReturn (oper, 2, pic16_popCopyReg (&pic16_pc_prodh)); // patch 14 + } + + if (size > 3 && res_size > 3) + { + /* 32-bits, result in FSR0L:PRODH:PRODL:WREG */ + pic16_loadFromReturn (oper, 3, pic16_popCopyReg (&pic16_pc_fsr0l)); // patch14 + } + + pic16_addSign (oper, res_size, IS_UNSIGNED (operandType (oper))); + + } + else + { + /* >32-bits, result on stack, and FSR0 points to beginning. + * Fix stack when done */ + /* FIXME FIXME */ +// debugf("WARNING: Possible bug when returning more than 4-bytes\n"); + while (size--) + { +// DEBUGpic16_emitcode("; ", "POC_MOVLW %d", GpseudoStkPtr); +// DEBUGpic16_emitcode("; ", "POC_MOVFW PLUSW2"); + + popaopidx (AOP (oper), size, GpseudoStkPtr); + GpseudoStkPtr++; + } + + /* fix stack */ + free_stack_parameters (AOP_SIZE (oper)); + } + } + else + { + int areg = 0; /* matching argument register */ + +// debugf("_G.useWreg = %d\tGpseudoStkPtr = %d\n", _G.useWreg, GpseudoStkPtr); + areg = SPEC_ARGREG (OP_SYM_ETYPE (oper)) - 1; + + + /* its called from genReceive (probably) -- VR */ + /* I hope this code will not be called from somewhere else in the future! + * We manually set the pseudo stack pointer in genReceive. - dw + */ + if (!GpseudoStkPtr && _G.useWreg) + { +// DEBUGpic16_emitcode("; ", "pop %d", GpseudoStkPtr); + + /* The last byte in the assignment is in W */ + if (areg <= GpseudoStkPtr) + { + size--; + + if (AOP_TYPE(oper) != AOP_ACC) + { + /* If destination NOT WREG. */ + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (oper), offset /*size*/)); + } + else + { + DEBUGpic16_emitcode ("; ***", "ignore MOVWF\tWREG", __FUNCTION__, __LINE__); + } + + offset++; +// debugf("receive from WREG\n", 0); + } + GpseudoStkPtr++; /* otherwise the calculation below fails (-_G.useWreg) */ + } +// GpseudoStkPtr++; + _G.stack_lat = AOP_SIZE (oper) - 1; + + while (size) + { + size--; + GpseudoStkPtr++; + popaopidx (AOP (oper), offset, GpseudoStkPtr - _G.useWreg); +// debugf("receive from STACK\n", 0); + offset++; + } + } +} + + +/*-----------------------------------------------------------------*/ +/* genIpush - generate code for pushing this gets a little complex */ +/*-----------------------------------------------------------------*/ +static void +genIpush (iCode * ic) +{ +// int size, offset=0; + + FENTRY; + DEBUGpic16_emitcode ("; ***", "%s %d - WARNING no code generated", __FUNCTION__, __LINE__); + + if (ic->parmPush) + { + pic16_aopOp (IC_LEFT (ic), ic, FALSE); + + /* send to stack as normal */ + addSet (&_G.sendSet, ic); +// addSetHead(&_G.sendSet,ic); + pic16_freeAsmop (IC_LEFT (ic), NULL, ic, TRUE); + } + + +#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; + + pic16_aopOp (IC_LEFT (ic), ic, FALSE); + size = AOP_SIZE (IC_LEFT (ic)); + /* push it on the stack */ + while (size--) + { + l = pic16_aopGet (AOP (IC_LEFT (ic)), offset++, FALSE, TRUE); + if (*l == '#') + { + MOVA (l); + l = "acc"; + } + pic16_emitcode ("push", "%s", l); + } + return; + } + + pic16_freeAsmop (IC_LEFT (ic), NULL, ic, TRUE); +#endif +} + +/*-----------------------------------------------------------------*/ +/* genIpop - recover the registers: can happen only for spilling */ +/*-----------------------------------------------------------------*/ +static void +genIpop (iCode * ic) +{ + FENTRY; + DEBUGpic16_emitcode ("; ***", "%s %d - WARNING no code generated", __FUNCTION__, __LINE__); +#if 0 + int size, offset; + + + /* if the temp was not pushed then */ + if (OP_SYMBOL (IC_LEFT (ic))->isspilt) + return; + + pic16_aopOp (IC_LEFT (ic), ic, FALSE); + size = AOP_SIZE (IC_LEFT (ic)); + offset = (size - 1); + while (size--) + pic16_emitcode ("pop", "%s", pic16_aopGet (AOP (IC_LEFT (ic)), offset--, FALSE, TRUE)); + + pic16_freeAsmop (IC_LEFT (ic), NULL, ic, TRUE); +#endif +} + +static int +wparamCmp (void *p1, void *p2) +{ + return (!strcmp ((char *) p1, (char *) p2)); +} + +int +inWparamList (char *s) +{ + return isinSetWith (wparamList, s, wparamCmp); +} + + +/*-----------------------------------------------------------------*/ +/* genCall - generates a call statement */ +/*-----------------------------------------------------------------*/ +static void +genCall (iCode * ic) +{ + sym_link *ftype; + int stackParms = 0; + int use_wreg = 0; + int inwparam = 0; + char *fname; + + FENTRY; + + ftype = OP_SYM_TYPE (IC_LEFT (ic)); + /* if caller saves & we have not saved then */ +// if (!ic->regsSaved) +// saveRegisters(ic); + + /* initialise stackParms for IPUSH pushes */ +// stackParms = pseudoStkPtr; +// fprintf(stderr, "%s:%d ic parmBytes = %d\n", __FILE__, __LINE__, ic->parmBytes); + fname = OP_SYMBOL (IC_LEFT (ic))->rname[0] ? OP_SYMBOL (IC_LEFT (ic))->rname : OP_SYMBOL (IC_LEFT (ic))->name; + inwparam = (inWparamList (OP_SYMBOL (IC_LEFT (ic))->name)) || (FUNC_ISWPARAM (OP_SYM_TYPE (IC_LEFT (ic)))); + +#if 0 + gpsimDebug_StackDump (__FILE__, __LINE__, fname); +#endif + + /* if send set is not empty the assign */ + if (_G.sendSet) + { + iCode *sic; + int pseudoStkPtr = -1; + int firstTimeThruLoop = 1; + + + /* reverse sendSet if function is not reentrant */ + if (!IFFUNC_ISREENT (ftype)) + _G.sendSet = reverseSet (_G.sendSet); + + /* First figure how many parameters are getting passed */ + stackParms = 0; + use_wreg = 0; + + for (sic = setFirstItem (_G.sendSet); sic; sic = setNextItem (_G.sendSet)) + { + int size; +// int offset = 0; + + pic16_aopOp (IC_LEFT (sic), sic, FALSE); + size = AOP_SIZE (IC_LEFT (sic)); + + stackParms += size; + + /* pass the last byte through WREG */ + if (inwparam) + { + + while (size--) + { + DEBUGpic16_emitcode ("; ", "%d left %s", __LINE__, pic16_AopType (AOP_TYPE (IC_LEFT (sic)))); + DEBUGpic16_emitcode ("; ", "push %d", pseudoStkPtr - 1); + + 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. */ + + pushw (); +// --pseudoStkPtr; // sanity check + use_wreg = 1; + } + + firstTimeThruLoop = 0; + + pic16_mov2w (AOP (IC_LEFT (sic)), size); + +// offset++; + } + } + else + { + /* all arguments are passed via stack */ + use_wreg = 0; + + while (size--) + { + DEBUGpic16_emitcode ("; ", "%d left %s", __LINE__, pic16_AopType (AOP_TYPE (IC_LEFT (sic)))); + DEBUGpic16_emitcode ("; ", "push %d", pseudoStkPtr - 1); + +// pushaop(AOP(IC_LEFT(sic)), size); + pic16_mov2w (AOP (IC_LEFT (sic)), size); + + if (!_G.resDirect) + pushw (); + } + } + + pic16_freeAsmop (IC_LEFT (sic), NULL, sic, TRUE); + } + + if (inwparam) + { + if (IFFUNC_HASVARARGS (ftype) || IFFUNC_ISREENT (ftype)) + { + pushw (); /* save last parameter to stack if functions has varargs */ + use_wreg = 0; + } + else + use_wreg = 1; + } + else + use_wreg = 0; + + _G.stackRegSet = _G.sendSet; + _G.sendSet = NULL; + } + + /* make the call */ + pic16_emitpcode (POC_CALL, pic16_popGetWithString (fname)); + + GpseudoStkPtr = 0; + + /* 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++; + pic16_aopOp (IC_RESULT (ic), ic, FALSE); + _G.accInUse--; + + /* Must not assign an 8-bit result to a 16-bit variable; + * this would use (used...) the uninitialized PRODL! */ + /* FIXME: Need a proper way to obtain size of function result type, + * OP_SYM_ETYPE does not work: it dereferences pointer types! */ + assignResultValue (IC_RESULT (ic), getSize (OP_SYM_TYPE (IC_LEFT (ic))->next), 1); + + DEBUGpic16_emitcode ("; ", "%d left %s", __LINE__, pic16_AopType (AOP_TYPE (IC_RESULT (ic)))); + + pic16_freeAsmop (IC_RESULT (ic), NULL, ic, TRUE); + } + + if (!stackParms && ic->parmBytes) + { + stackParms = ic->parmBytes; + } + + stackParms -= use_wreg; + free_stack_parameters (stackParms); + +#if 0 + gpsimDebug_StackDump (__FILE__, __LINE__, fname); +#endif + + /* adjust the stack for parameters if required */ +// fprintf(stderr, "%s:%d: %s ic->parmBytes= %d\n", __FILE__, __LINE__, OP_SYMBOL(IC_LEFT(ic))->name, ic->parmBytes); + +#if 0 + /* 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); +#endif +} + + + +/*-----------------------------------------------------------------*/ +/* genPcall - generates a call by pointer statement */ +/* new version, created from genCall - HJD */ +/*-----------------------------------------------------------------*/ +static void +genPcall (iCode * ic) +{ + sym_link *fntype; + int stackParms = 0; + symbol *retlbl = newiTempLabel (NULL); + pCodeOp *pcop_lbl = pic16_popGetLabel (retlbl->key); + + FENTRY; + + fntype = operandType (IC_LEFT (ic))->next; + + /* if send set is not empty the assign */ + if (_G.sendSet) + { + iCode *sic; + int pseudoStkPtr = -1; + + /* reverse sendSet if function is not reentrant */ + if (!IFFUNC_ISREENT (fntype)) + _G.sendSet = reverseSet (_G.sendSet); + + stackParms = 0; + + for (sic = setFirstItem (_G.sendSet); sic; sic = setNextItem (_G.sendSet)) + { + int size; + + pic16_aopOp (IC_LEFT (sic), sic, FALSE); + size = AOP_SIZE (IC_LEFT (sic)); + stackParms += size; + + /* all parameters are passed via stack, since WREG is clobbered + * by the calling sequence */ + while (size--) + { + DEBUGpic16_emitcode ("; ", "%d left %s", __LINE__, pic16_AopType (AOP_TYPE (IC_LEFT (sic)))); + DEBUGpic16_emitcode ("; ", "push %d", pseudoStkPtr - 1); + + pic16_mov2w (AOP (IC_LEFT (sic)), size); + pushw (); + } + + pic16_freeAsmop (IC_LEFT (sic), NULL, sic, TRUE); + } + + _G.stackRegSet = _G.sendSet; + _G.sendSet = NULL; + } + + pic16_aopOp (IC_LEFT (ic), ic, FALSE); + + // push return address + // push $ on return stack, then replace with retlbl + + /* Thanks to Thorsten Klose for pointing out that the following + * snippet should be interrupt safe */ + pic16_emitpcode (POC_MOVFF, pic16_popGet2p (pic16_popCopyReg (&pic16_pc_intcon), pic16_popCopyReg (&pic16_pc_postdec1))); + pic16_emitpcode (POC_BCF, pic16_popCopyGPR2Bit (pic16_popCopyReg (&pic16_pc_intcon), 7)); + + pic16_emitpcodeNULLop (POC_PUSH); + + pic16_emitpcode (POC_MOVLW, pic16_popGetImmd (pcop_lbl->name, 0, 0)); + pic16_emitpcode (POC_MOVWF, pic16_popCopyReg (&pic16_pc_tosl)); + pic16_emitpcode (POC_MOVLW, pic16_popGetImmd (pcop_lbl->name, 1, 0)); + pic16_emitpcode (POC_MOVWF, pic16_popCopyReg (&pic16_pc_tosh)); + pic16_emitpcode (POC_MOVLW, pic16_popGetImmd (pcop_lbl->name, 2, 0)); + pic16_emitpcode (POC_MOVWF, pic16_popCopyReg (&pic16_pc_tosu)); + + /* Conditionally re-enable interrupts, but keep interrupt flags in + * INTCON intact (thanks to J. van der Boon, #3420588). */ + pic16_emitpcode (POC_BTFSC, pic16_popCopyGPR2Bit (pic16_popCopyReg (&pic16_pc_preinc1), 7)); + pic16_emitpcode (POC_BSF, pic16_popCopyGPR2Bit (pic16_popCopyReg (&pic16_pc_intcon), 7)); + + /* make the call by writing the pointer into pc */ + mov2fp (pic16_popCopyReg (&pic16_pc_pclatu), AOP (IC_LEFT (ic)), 2); + mov2fp (pic16_popCopyReg (&pic16_pc_pclath), AOP (IC_LEFT (ic)), 1); + + // note: MOVFF to PCL not allowed + pic16_mov2w (AOP (IC_LEFT (ic)), 0); + pic16_emitpcode (POC_MOVWF, pic16_popCopyReg (&pic16_pc_pcl)); + + + /* return address is here: (X) */ + pic16_emitpLabelFORCE (retlbl->key); + + pic16_freeAsmop (IC_LEFT (ic), NULL, ic, TRUE); + + 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++; + pic16_aopOp (IC_RESULT (ic), ic, FALSE); + _G.accInUse--; + + /* FIXME: Need proper way to obtain the function result's type. + * OP_SYM_TYPE(IC_LEFT(ic))->next does not work --> points to function pointer */ + assignResultValue (IC_RESULT (ic), getSize (OP_SYM_TYPE (IC_LEFT (ic))->next->next), 1); + + DEBUGpic16_emitcode ("; ", "%d left %s", __LINE__, pic16_AopType (AOP_TYPE (IC_RESULT (ic)))); + + pic16_freeAsmop (IC_RESULT (ic), NULL, ic, TRUE); + } + +// stackParms -= use_wreg; + + free_stack_parameters (stackParms); +} + +/*-----------------------------------------------------------------*/ +/* resultRemat - result is rematerializable */ +/*-----------------------------------------------------------------*/ +static int +resultRemat (iCode * ic) +{ + // DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + if (SKIP_IC (ic) || ic->op == IFX) + return 0; + + if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic))) + { + symbol *sym = OP_SYMBOL (IC_RESULT (ic)); + if (sym->remat && !POINTER_SET (ic)) + return 1; + } + + return 0; +} + +#if 0 +/*-----------------------------------------------------------------*/ +/* inExcludeList - return 1 if the string is in exclude Reg list */ +/*-----------------------------------------------------------------*/ +static bool +inExcludeList (char *s) +{ + DEBUGpic16_emitcode ("; ***", "%s %d - WARNING no code generated", __FUNCTION__, __LINE__); + int i = 0; + + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + if (options.excludeRegs[i] && STRCASECMP (options.excludeRegs[i], "none") == 0) + return FALSE; + + for (i = 0; options.excludeRegs[i]; i++) + { + if (options.excludeRegs[i] && STRCASECMP (s, options.excludeRegs[i]) == 0) + return TRUE; + } + return FALSE; +} +#endif + +/*-----------------------------------------------------------------*/ +/* genFunction - generated code for function entry */ +/*-----------------------------------------------------------------*/ +static void +genFunction (iCode * ic) +{ + symbol *sym; + sym_link *ftype; + + FENTRY; + DEBUGpic16_emitcode ("; ***", "%s %d curr label offset=%dprevious max_key=%d ", __FUNCTION__, __LINE__, pic16_labelOffset, + max_key); + + pic16_labelOffset += (max_key + 4); + max_key = 0; + GpseudoStkPtr = 0; + _G.nRegsSaved = 0; + + ftype = operandType (IC_LEFT (ic)); + sym = OP_SYMBOL (IC_LEFT (ic)); + + if (IFFUNC_ISISR (sym->type)) + { + /* create an absolute section at the interrupt vector: + * that is 0x0008 for interrupt 1 (high), 0x0018 interrupt 2 (low) */ + symbol *asym; + char asymname[128]; + pBlock *apb; + + //debugf ("interrupt number: %hhi\n", FUNC_INTNO (sym->type)); + + if (FUNC_INTNO (sym->type) == INTNO_UNSPEC) + SNPRINTF(asymname, sizeof(asymname), "ivec_%s", sym->name); + else + SNPRINTF(asymname, sizeof(asymname), "ivec_0x%x_%s", FUNC_INTNO (sym->type), sym->name); + + /* when an interrupt is declared as naked, do not emit the special + * wrapper segment at vector address. The user should take care for + * this instead. -- VR */ + + if (!IFFUNC_ISNAKED (ftype) && (FUNC_INTNO (sym->type) != INTNO_UNSPEC)) + { + asym = newSymbol (asymname, 0); + apb = pic16_newpCodeChain (NULL, 'A', pic16_newpCodeCharP ("; Starting pCode block for absolute section")); + pic16_addpBlock (apb); + + pic16_addpCode2pBlock (apb, pic16_newpCodeCharP (";-----------------------------------------")); + pic16_addpCode2pBlock (apb, pic16_newpCodeFunction (moduleName, asym->name)); + //pic16_addpCode2pBlock (apb, pic16_newpCode (POC_GOTO, pic16_popGetWithString (sym->rname))); + //pic16_addpCode2pBlock (apb, pic16_newpCode (POC_GOTO, pic16_newpCodeOpLabel (sym->rname, 0))); + pic16_addpCode2pBlock (apb, pic16_newpCodeAsmDir ("GOTO", "%s", sym->rname)); /* this suppresses a warning in LinkFlow */ + + /* mark the end of this tiny function */ + pic16_addpCode2pBlock (apb, pic16_newpCodeFunction (NULL, NULL)); + } + else + { + SNPRINTF(asymname, sizeof(asymname), "%s", sym->rname); + } + + { + absSym *abSym; + + abSym = Safe_alloc(sizeof(absSym)); + strncpy(abSym->name, asymname, sizeof(abSym->name) - 1); + abSym->name[sizeof(abSym->name) - 1] = '\0'; + + switch (FUNC_INTNO (sym->type)) + { + case 0: + abSym->address = 0x000000; + break; + case 1: + abSym->address = 0x000008; + break; + case 2: + abSym->address = 0x000018; + break; + default: + //fprintf (stderr, "no interrupt number is given\n"); + abSym->address = -1; + break; + } + + /* relocate interrupt vectors if needed */ + if (abSym->address != -1) + abSym->address += pic16_options.ivt_loc; + + addSet (&absSymSet, abSym); + } + } + + /* create the function header */ + pic16_emitcode (";", "-----------------------------------------"); + pic16_emitcode (";", " function %s", sym->name); + pic16_emitcode (";", "-----------------------------------------"); + + /* prevent this symbol from being emitted as 'extern' */ + pic16_stringInSet (sym->rname, &pic16_localFunctions, 1); + + pic16_emitcode ("", "%s:", sym->rname); + pic16_addpCode2pBlock (pb, pic16_newpCodeFunction (moduleName, sym->rname)); + + { + absSym *ab; + + for (ab = setFirstItem (absSymSet); ab; ab = setNextItem (absSymSet)) + { + if (!strcmp (ab->name, sym->rname)) + { + pic16_pBlockConvert2Absolute (pb); + break; + } + } + } + + currFunc = sym; /* update the currFunc symbol */ + _G.fregsUsed = sym->regsUsed; + _G.sregsAlloc = newBitVect (128); + + if (IFFUNC_ISNAKED (ftype)) + { + DEBUGpic16_emitcode ("; ***", "__naked function, no prologue"); + return; + } + + /* if this is an interrupt service routine then + * save wreg, status, bsr, prodl, prodh, fsr0l, fsr0h */ + if (IFFUNC_ISISR (sym->type)) + { + _G.usefastretfie = 1; /* use shadow registers by default */ + + /* an ISR should save: WREG, STATUS, BSR, PRODL, PRODH, FSR0L, FSR0H */ + if (!FUNC_ISSHADOWREGS (sym->type)) + { + /* do not save WREG, STATUS, BSR for high priority interrupts + * because they are stored in the hardware shadow registers already */ + _G.usefastretfie = 0; + pic16_pushpCodeOp (pic16_popCopyReg (&pic16_pc_status)); + pic16_pushpCodeOp (pic16_popCopyReg (&pic16_pc_bsr)); + pushw (); + } + + /* these should really be optimized somehow, because not all + * interrupt handlers modify them */ + pic16_pushpCodeOp (pic16_popCopyReg (&pic16_pc_prodl)); + pic16_pushpCodeOp (pic16_popCopyReg (&pic16_pc_prodh)); + pic16_pushpCodeOp (pic16_popCopyReg (&pic16_pc_fsr0l)); + pic16_pushpCodeOp (pic16_popCopyReg (&pic16_pc_fsr0h)); + pic16_pushpCodeOp (pic16_popCopyReg (&pic16_pc_pclath)); + pic16_pushpCodeOp (pic16_popCopyReg (&pic16_pc_pclatu)); + + //pic16_pBlockConvert2ISR (pb); + } + + /* emit code to setup stack frame if user enabled, + * and function is not main () */ + + //debugf (stderr, "function name: %s ARGS=%p\n", sym->name, FUNC_ARGS (sym->type)); + if (strcmp (sym->name, "main")) + { + if (0 || !options.omitFramePtr + //|| sym->regsUsed + || IFFUNC_ARGS (sym->type) || FUNC_HASSTACKPARM (sym->etype)) + { + /* setup the stack frame */ + if (STACK_MODEL_LARGE) + pic16_pushpCodeOp (pic16_popCopyReg (pic16_framepnt_hi)); + pic16_pushpCodeOp (pic16_popCopyReg (pic16_framepnt_lo)); + + if (STACK_MODEL_LARGE) + pic16_emitpcode (POC_MOVFF, pic16_popCombine2 (pic16_stackpnt_hi, pic16_framepnt_hi, 0)); + pic16_emitpcode (POC_MOVFF, pic16_popCombine2 (pic16_stackpnt_lo, pic16_framepnt_lo, 0)); + } + } + + if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) && sym->stack) + { + if (sym->stack > 127) + werror (W_STACK_OVERFLOW, sym->name); + + pic16_emitpcode (POC_MOVLW, pic16_popGetLit (sym->stack)); + pic16_emitpcode (POC_SUBWF, pic16_popCopyReg (pic16_stackpnt_lo)); //&pic16_pc_fsr1l)); + emitSKPC; + pic16_emitpcode (POC_DECF, pic16_popCopyReg (pic16_stackpnt_hi)); //&pic16_pc_fsr1h)); + } + + if (inWparamList (sym->name) || FUNC_ISWPARAM (sym->type)) + { + if (IFFUNC_HASVARARGS (sym->type) || IFFUNC_ISREENT (sym->type)) + _G.useWreg = 0; + else + _G.useWreg = 1; + } + else + _G.useWreg = 0; + + /* if callee-save to be used for this function + * then save the registers being used in this function */ + //if (IFFUNC_CALLEESAVES (sym->type)) + if (strcmp (sym->name, "main")) + { + int i; + + /* if any registers used */ + if (sym->regsUsed) + { + pic16_emitpinfo (INF_LOCALREGS, pic16_newpCodeOpLocalRegs (LR_ENTRY_BEGIN)); + + if (!pic16_options.xinst) + { + /* save the registers used */ + DEBUGpic16_emitcode ("; **", "Saving used registers in stack"); + for (i = 0; i < sym->regsUsed->size; i++) + { + if (bitVectBitValue (sym->regsUsed, i)) + { +#if 0 + fprintf (stderr, "%s:%d local register w/rIdx = %d is used in function\n", __FUNCTION__, __LINE__, i); +#endif + pic16_pushpCodeOp (pic16_popRegFromIdx (i)); + _G.nRegsSaved++; + + if (!pic16_regWithIdx (i)->wasUsed) + { + fprintf (stderr, "%s:%d register %s is used in function but was wasUsed = 0\n", + __FILE__, __LINE__, pic16_regWithIdx (i)->name); + pic16_regWithIdx (i)->wasUsed = 1; + } + } + } + } + else + { + /* xinst */ + DEBUGpic16_emitcode ("; **", "Allocate a space in stack to be used as temporary registers"); + for (i = 0; i < sym->regsUsed->size; i++) + { + if (bitVectBitValue (sym->regsUsed, i)) + _G.nRegsSaved++; + } + + //pic16_emitpcode (POC_ADDFSR, pic16_popGetLit2 (2, pic16_popGetLit (_G.nRegsSaved))); + } + + pic16_emitpinfo (INF_LOCALREGS, pic16_newpCodeOpLocalRegs (LR_ENTRY_END)); + } + } + + /* if critical function then turn interrupts off */ + if (IFFUNC_ISCRITICAL (ftype)) + { + genCritical (NULL); + } // if + + DEBUGpic16_emitcode ("; ", "need to adjust stack = %d", sym->stack); + //fprintf (stderr, "Function '%s' uses %d bytes of stack\n", sym->name, sym->stack); +} + +/*-----------------------------------------------------------------*/ +/* genEndFunction - generates epilogue for functions */ +/*-----------------------------------------------------------------*/ +static void +genEndFunction (iCode * ic) +{ + symbol *sym = OP_SYMBOL (IC_LEFT (ic)); + + FENTRY; + + if (IFFUNC_ISNAKED (sym->type)) + { + DEBUGpic16_emitcode ("; ***", "__naked function, no epilogue"); + return; + } + + if (IFFUNC_ISCRITICAL (sym->type)) + { + genEndCritical (NULL); + } // if + + _G.stack_lat = 0; + + //sym->regsUsed = _G.fregsUsed; + + /* now we need to restore the registers */ + /* if any registers used */ + + /* first restore registers that might be used for stack access */ + if (_G.sregsAllocSet) + { + reg_info *sr; + + _G.sregsAllocSet = reverseSet (_G.sregsAllocSet); + for (sr = setFirstItem (_G.sregsAllocSet); sr; sr = setNextItem (_G.sregsAllocSet)) + { + pic16_poppCodeOp (pic16_popRegFromIdx (sr->rIdx)); + } + } + + if (strcmp (sym->name, "main") && sym->regsUsed) + { + int i; + + pic16_emitpinfo (INF_LOCALREGS, pic16_newpCodeOpLocalRegs (LR_EXIT_BEGIN)); + /* restore registers used */ + DEBUGpic16_emitcode ("; **", "Restoring used registers from stack"); + for (i = sym->regsUsed->size; i >= 0; i--) + { + if (bitVectBitValue (sym->regsUsed, i)) + { + pic16_poppCodeOp (pic16_popRegFromIdx (i)); + _G.nRegsSaved--; + } + } + pic16_emitpinfo (INF_LOCALREGS, pic16_newpCodeOpLocalRegs (LR_EXIT_END)); + } + + if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) && sym->stack) + { + if (sym->stack == 1) + { + pic16_emitpcode (POC_INFSNZ, pic16_popCopyReg (pic16_stackpnt_lo)); + pic16_emitpcode (POC_INCF, pic16_popCopyReg (pic16_stackpnt_hi)); + } + else + { + // we have to add more than one... + pic16_emitpcode (POC_MOVWF, pic16_popCopyReg (pic16_stack_postinc)); // this holds a return value! + pic16_emitpcode (POC_MOVLW, pic16_popGetLit (sym->stack - 1)); + pic16_emitpcode (POC_ADDWF, pic16_popCopyReg (pic16_stackpnt_lo)); + emitSKPNC; + pic16_emitpcode (POC_INCF, pic16_popCopyReg (pic16_stackpnt_hi)); + pic16_emitpcode (POC_COMF, pic16_popCopyReg (&pic16_pc_wreg)); // WREG = - (WREG+1)! + pic16_emitpcode (POC_MOVFW, pic16_popCopyReg (pic16_stack_plusw)); // this holds a retrun value! + } + } + + if (strcmp (sym->name, "main")) + { + if (0 || !options.omitFramePtr + //|| sym->regsUsed + || IFFUNC_ARGS (sym->type) || FUNC_HASSTACKPARM (sym->etype)) + { + /* restore stack frame */ + pic16_poppCodeOp (pic16_popCopyReg (pic16_framepnt_lo)); + if (STACK_MODEL_LARGE) + pic16_poppCodeOp (pic16_popCopyReg (pic16_framepnt_hi)); + } + } + + _G.useWreg = 0; + + if (IFFUNC_ISISR (sym->type)) + { + pic16_poppCodeOp (pic16_popCopyReg (&pic16_pc_pclatu)); + pic16_poppCodeOp (pic16_popCopyReg (&pic16_pc_pclath)); + pic16_poppCodeOp (pic16_popCopyReg (&pic16_pc_fsr0h)); + pic16_poppCodeOp (pic16_popCopyReg (&pic16_pc_fsr0l)); + pic16_poppCodeOp (pic16_popCopyReg (&pic16_pc_prodh)); + pic16_poppCodeOp (pic16_popCopyReg (&pic16_pc_prodl)); + + if (!FUNC_ISSHADOWREGS (sym->type)) + { + /* do not restore interrupt vector for WREG, STATUS, BSR + * for high priority interrupt, see genFunction */ + pic16_emitpcode (POC_MOVFW, pic16_popCopyReg (pic16_stack_preinc)); + pic16_poppCodeOp (pic16_popCopyReg (&pic16_pc_bsr)); + pic16_poppCodeOp (pic16_popCopyReg (&pic16_pc_status)); + } + //_G.interruptvector = 0; /* sanity check */ + + /* if debug then send end of function */ + /* if (options.debug && currFunc) */ + if (currFunc) + { + debugFile->writeEndFunction (currFunc, ic, 1); + } + + if (_G.usefastretfie) + pic16_emitpcode (POC_RETFIE, pic16_newpCodeOpLit (1)); + else + pic16_emitpcodeNULLop (POC_RETFIE); + + pic16_addpCode2pBlock (pb, pic16_newpCodeFunction (NULL, NULL)); + + _G.usefastretfie = 0; + return; + } + + /* if debug then send end of function */ + if (currFunc) + { + debugFile->writeEndFunction (currFunc, ic, 1); + } + + /* insert code to restore stack frame, if user enabled it + * and function is not main () */ + + pic16_emitpcodeNULLop (POC_RETURN); + + /* Mark the end of a function */ + pic16_addpCode2pBlock (pb, pic16_newpCodeFunction (NULL, NULL)); +} + + +void +pic16_storeForReturn (iCode * ic, /*operand *op, */ int offset, pCodeOp * dest) +{ + unsigned long lit = 1; + operand *op; + + op = IC_LEFT (ic); + + // this fails for pic16_isLitOp(op) (if op is an AOP_PCODE) + if (AOP_TYPE (op) == AOP_LIT) + { + if (!IS_FLOAT (operandType (op))) + { + lit = ulFromVal (AOP (op)->aopu.aop_lit); + } + else + { + union + { + unsigned long lit_int; + float lit_float; + } info; + + /* take care if literal is a float */ + info.lit_float = (float)floatFromVal (AOP (op)->aopu.aop_lit); + lit = info.lit_int; + } + } + + if (AOP_TYPE (op) == AOP_LIT) + { + /* FIXME: broken for + * char __at(0x456) foo; + * return &foo; + * (upper byte is 0x00 (__code space) instead of 0x80 (__data) */ + pic16_movLit2f (dest, (lit >> (8ul * offset))); + } + else if (AOP_TYPE (op) == AOP_PCODE && AOP (op)->aopu.pcop->type == PO_IMMEDIATE) + { + /* char *s= "aaa"; return s; */ + /* XXX: Using UPPER(__str_0) will yield 0b00XXXXXX, so + * that the generic pointer is interpreted correctly + * as referring to __code space, but this is fragile! */ + pic16_emitpcode (POC_MOVLW, pic16_popGet (AOP (op), offset)); + /* XXX: should check that dest != WREG */ + pic16_emitpcode (POC_MOVWF, dest); + } + else + { + if (dest->type == PO_WREG && (offset == 0)) + { + pic16_emitpcode (POC_MOVFW, pic16_popGet (AOP (op), offset)); + return; + } + pic16_emitpcode (POC_MOVFF, pic16_popGet2p (pic16_popGet (AOP (op), offset), dest)); + } +} + +/*-----------------------------------------------------------------*/ +/* genRet - generate code for return statement */ +/*-----------------------------------------------------------------*/ +static void +genRet (iCode * ic) +{ + int size; + operand *left; + + FENTRY; + /* 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 */ + pic16_aopOp ((left = IC_LEFT (ic)), ic, FALSE); + size = AOP_SIZE (IC_LEFT (ic)); + + if (size <= 4) + { + if (size > 3) + pic16_storeForReturn (ic, /*IC_LEFT(ic), */ 3, pic16_popCopyReg (&pic16_pc_fsr0l)); + + if (size > 2) + pic16_storeForReturn (ic, /*IC_LEFT(ic), */ 2, pic16_popCopyReg (&pic16_pc_prodh)); + + if (size > 1) + pic16_storeForReturn (ic, /*IC_LEFT(ic), */ 1, pic16_popCopyReg (&pic16_pc_prodl)); + + pic16_storeForReturn (ic, /*IC_LEFT(ic), */ 0, pic16_popCopyReg (&pic16_pc_wreg)); + + } + else + { + /* >32-bits, setup stack and FSR0 */ + while (size--) + { +// DEBUGpic16_emitcode("; ", "POC_MOVLW %d", GpseudoStkPtr); +// DEBUGpic16_emitcode("; ", "POC_MOVFW PLUSW2"); + + pic16_pushpCodeOp (pic16_popGet (AOP (IC_LEFT (ic)), size)); + +// popaopidx(AOP(oper), size, GpseudoStkPtr); + GpseudoStkPtr++; + } + + /* setup FSR0 */ + pic16_emitpcode (POC_MOVFF, pic16_popGet2p (pic16_popCopyReg (pic16_stackpnt_lo), pic16_popCopyReg (&pic16_pc_fsr0l))); + + if (STACK_MODEL_LARGE) + { + pic16_emitpcode (POC_MOVFF, + pic16_popGet2p (pic16_popCopyReg (pic16_stackpnt_hi), pic16_popCopyReg (&pic16_pc_fsr0h))); + } + else + { + pic16_emitpcode (POC_CLRF, pic16_popCopyReg (pic16_stackpnt_hi)); + } + } + + pic16_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)) + { + + pic16_emitpcode (POC_GOTO, pic16_popGetLabel (returnLabel->key)); + pic16_emitcode ("goto", "_%05d_DS_", labelKey2num (returnLabel->key + pic16_labelOffset)); + } +} + +static set *critical_temps = NULL; + +static void +genCritical (iCode * ic) +{ + pCodeOp *saved_intcon; + + if (!critical_temps) + critical_temps = newSet (); + + saved_intcon = pic16_popGetTempReg (0); + pic16_emitpcode (POC_MOVFF, pic16_popGet2p (pic16_popCopyReg (&pic16_pc_intcon), saved_intcon)); + pic16_emitpcode (POC_BCF, pic16_popCopyGPR2Bit (pic16_popCopyReg (&pic16_pc_intcon), 7)); + addSetHead (&critical_temps, saved_intcon); +} + +static void +genEndCritical (iCode * ic) +{ + pCodeOp *saved_intcon = NULL; + + saved_intcon = getSet (&critical_temps); + if (!saved_intcon) + { + fprintf (stderr, "Critical section left, but none entered -- ignoring for now.\n"); + return; + } // if + + pic16_emitpcode (POC_BTFSC, pic16_popCopyGPR2Bit (saved_intcon, 7)); + pic16_emitpcode (POC_BSF, pic16_popCopyGPR2Bit (pic16_popCopyReg (&pic16_pc_intcon), 7)); + pic16_popReleaseTempReg (saved_intcon, 0); +} + +/*-----------------------------------------------------------------*/ +/* genLabel - generates a label */ +/*-----------------------------------------------------------------*/ +static void +genLabel (iCode * ic) +{ + FENTRY; + + /* special case never generate */ + if (IC_LABEL (ic) == entryLabel) + return; + + pic16_emitpLabel (IC_LABEL (ic)->key); +// pic16_emitcode("","_%05d_DS_:",labelKey2num (IC_LABEL(ic)->key + pic16_labelOffset)); +} + +/*-----------------------------------------------------------------*/ +/* genGoto - generates a goto */ +/*-----------------------------------------------------------------*/ +//tsd +static void +genGoto (iCode * ic) +{ + FENTRY; + pic16_emitpcode (POC_GOTO, pic16_popGetLabel (IC_LABEL (ic)->key)); +// pic16_emitcode ("goto","_%05d_DS_",labelKey2num (IC_LABEL(ic)->key + pic16_labelOffset)); +} + + +/*-----------------------------------------------------------------*/ +/* genMultbits :- multiplication of bits */ +/*-----------------------------------------------------------------*/ +static void +genMultbits (operand * left, operand * right, operand * result) +{ + FENTRY; + + if (!pic16_sameRegs (AOP (result), AOP (right))) + pic16_emitpcode (POC_BSF, pic16_popGet (AOP (result), 0)); + + pic16_emitpcode (POC_BTFSC, pic16_popGet (AOP (right), 0)); + pic16_emitpcode (POC_BTFSS, pic16_popGet (AOP (left), 0)); + pic16_emitpcode (POC_BCF, pic16_popGet (AOP (result), 0)); + +} + + +/*-----------------------------------------------------------------*/ +/* genMultOneByte : 8 bit multiplication & division */ +/*-----------------------------------------------------------------*/ +static void +genMultOneByte (operand * left, operand * right, operand * result) +{ + + FENTRY; + DEBUGpic16_pic16_AopType (__LINE__, left, right, result); + DEBUGpic16_pic16_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; + } + + /* size is already checked in genMult == 1 */ +// size = AOP_SIZE(result); + + if (AOP_TYPE (right) == AOP_LIT) + { + pic16_emitpcomment ("multiply lit val:%s by variable %s and store in %s", + pic16_aopGet (AOP (right), 0, FALSE, FALSE), + pic16_aopGet (AOP (left), 0, FALSE, FALSE), pic16_aopGet (AOP (result), 0, FALSE, FALSE)); + } + else + { + pic16_emitpcomment ("multiply variable :%s by variable %s and store in %s", + pic16_aopGet (AOP (right), 0, FALSE, FALSE), + pic16_aopGet (AOP (left), 0, FALSE, FALSE), pic16_aopGet (AOP (result), 0, FALSE, FALSE)); + } + + pic16_genMult8X8_n (left, right, result); +} + +#if 0 +/*-----------------------------------------------------------------*/ +/* genMultOneWord : 16 bit multiplication */ +/*-----------------------------------------------------------------*/ +static void +genMultOneWord (operand * left, operand * right, operand * result) +{ + FENTRY; + DEBUGpic16_pic16_AopType (__LINE__, left, right, result); + DEBUGpic16_pic16_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; + } + + /* size is checked already == 2 */ +// size = AOP_SIZE(result); + + if (AOP_TYPE (right) == AOP_LIT) + { + pic16_emitpcomment ("multiply lit val:%s by variable %s and store in %s", + pic16_aopGet (AOP (right), 0, FALSE, FALSE), + pic16_aopGet (AOP (left), 0, FALSE, FALSE), pic16_aopGet (AOP (result), 0, FALSE, FALSE)); + } + else + { + pic16_emitpcomment ("multiply variable :%s by variable %s and store in %s", + pic16_aopGet (AOP (right), 0, FALSE, FALSE), + pic16_aopGet (AOP (left), 0, FALSE, FALSE), pic16_aopGet (AOP (result), 0, FALSE, FALSE)); + } + + pic16_genMult16X16_16 (left, right, result); +} +#endif + +#if 0 +/*-----------------------------------------------------------------*/ +/* genMultOneLong : 32 bit multiplication */ +/*-----------------------------------------------------------------*/ +static void +genMultOneLong (operand * left, operand * right, operand * result) +{ + FENTRY; + DEBUGpic16_pic16_AopType (__LINE__, left, right, result); + DEBUGpic16_pic16_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; + } + + /* size is checked already == 4 */ +// size = AOP_SIZE(result); + + if (AOP_TYPE (right) == AOP_LIT) + { + pic16_emitpcomment ("multiply lit val:%s by variable %s and store in %s", + pic16_aopGet (AOP (right), 0, FALSE, FALSE), + pic16_aopGet (AOP (left), 0, FALSE, FALSE), pic16_aopGet (AOP (result), 0, FALSE, FALSE)); + } + else + { + pic16_emitpcomment ("multiply variable :%s by variable %s and store in %s", + pic16_aopGet (AOP (right), 0, FALSE, FALSE), + pic16_aopGet (AOP (left), 0, FALSE, FALSE), pic16_aopGet (AOP (result), 0, FALSE, FALSE)); + } + + pic16_genMult32X32_32 (left, right, result); +} +#endif + + + +/*-----------------------------------------------------------------*/ +/* 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; + /* assign the amsops */ + pic16_aopOp (left, ic, FALSE); + pic16_aopOp (right, ic, FALSE); + pic16_aopOp (result, ic, TRUE); + + DEBUGpic16_pic16_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; + } + +#if 0 + /* if both are of size == 2 */ + if (AOP_SIZE (left) == 2 && AOP_SIZE (right) == 2) + { + genMultOneWord (left, right, result); + goto release; + } + + /* if both are of size == 4 */ + if (AOP_SIZE (left) == 4 && AOP_SIZE (right) == 4) + { + genMultOneLong (left, right, result); + goto release; + } +#endif + + fprintf (stderr, "%s: should have been transformed into function call\n", __FUNCTION__); + assert (!"Multiplication should have been transformed into function call!"); + + pic16_emitcode ("multiply ", "sizes are greater than 4 ... need to insert proper algor."); + + + fprintf (stderr, "operand sizes result: %d left: %d right: %d\n", AOP_SIZE (result), AOP_SIZE (left), AOP_SIZE (right)); + /* should have been converted to function call */ + assert (0); + +release: + pic16_freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + pic16_freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + pic16_freeAsmop (result, NULL, ic, TRUE); +} + +#if 0 +/*-----------------------------------------------------------------*/ +/* genDivbits :- division of bits */ +/*-----------------------------------------------------------------*/ +static void +genDivbits (operand * left, operand * right, operand * result) +{ + char *l; + + FENTRY; + /* the result must be bit */ + pic16_emitcode ("mov", "b,%s", pic16_aopGet (AOP (right), 0, FALSE, FALSE)); + l = pic16_aopGet (AOP (left), 0, FALSE, FALSE); + + MOVA (l); + + pic16_emitcode ("div", "ab"); + pic16_emitcode ("rrc", "a"); + pic16_aopPut (AOP (result), "c", 0); +} + +/*-----------------------------------------------------------------*/ +/* genDivOneByte : 8 bit division */ +/*-----------------------------------------------------------------*/ +static void +genDivOneByte (operand * left, operand * right, operand * result) +{ + sym_link *opetype = operandType (result); + char *l; + symbol *lbl; + int size, offset; + + /* result = divident / divisor + * - divident may be a register or a literal, + * - divisor may be a register or a literal, + * so there are 3 cases (literal / literal is optimized + * by the front-end) to handle. + * In addition we must handle signed and unsigned, which + * result in 6 final different cases -- VR */ + + FENTRY; + + size = AOP_SIZE (result) - 1; + offset = 1; + /* signed or unsigned */ + if (SPEC_USIGN (opetype)) + { + pCodeOp *pct1, /* count */ + *pct2, /* reste */ + *pct3; /* temp */ + symbol *label1, *label2, *label3;; + + + /* unsigned is easy */ + + pct1 = pic16_popGetTempReg (1); + pct2 = pic16_popGetTempReg (1); + pct3 = pic16_popGetTempReg (1); + + label1 = newiTempLabel (NULL); + label2 = newiTempLabel (NULL); + label3 = newiTempLabel (NULL); + + /* the following algorithm is extracted from divuint.c */ + + pic16_emitpcode (POC_MOVLW, pic16_popGetLit (8)); + pic16_emitpcode (POC_MOVWF, pic16_pCodeOpCopy (pct1)); + + pic16_emitpcode (POC_CLRF, pic16_pCodeOpCopy (pct2)); + + pic16_emitpcode (POC_MOVFW, pic16_popGet (AOP (left), 0)); + + pic16_emitpLabel (label1->key); + + emitCLRC; + pic16_emitpcode (POC_RLCF, pic16_pCodeOpCopy (pct2)); + + + emitCLRC; + pic16_emitpcode (POC_RLCF, pic16_popCopyReg (&pic16_pc_wreg)); + + + emitSKPNC; + pic16_emitpcode (POC_INCF, pic16_pCodeOpCopy (pct2)); + + pic16_emitpcode (POC_MOVWF, pic16_pCodeOpCopy (pct3)); + pic16_emitpcode (POC_MOVFW, pic16_popGet (AOP (right), 0)); + + pic16_emitpcode (POC_CPFSLT, pic16_pCodeOpCopy (pct2)); + pic16_emitpcode (POC_BRA, pic16_popGetLabel (label3->key)); + pic16_emitpcode (POC_BRA, pic16_popGetLabel (label2->key)); + + pic16_emitpLabel (label3->key); + pic16_emitpcode (POC_SUBWF, pic16_pCodeOpCopy (pct2)); + pic16_emitpcode (POC_INCF, pic16_pCodeOpCopy (pct3)); + + + + pic16_emitpLabel (label2->key); + pic16_emitpcode (POC_MOVFW, pic16_pCodeOpCopy (pct3)); + pic16_emitpcode (POC_DECFSZ, pic16_pCodeOpCopy (pct1)); + pic16_emitpcode (POC_BRA, pic16_popGetLabel (label1->key)); + + /* result is in wreg */ + if (AOP_TYPE (result) != AOP_ACC) + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), 0)); + + pic16_popReleaseTempReg (pct3, 1); + pic16_popReleaseTempReg (pct2, 1); + pic16_popReleaseTempReg (pct1, 1); + + return; + } + + /* signed is a little bit more difficult */ + + /* save the signs of the operands */ + l = pic16_aopGet (AOP (left), 0, FALSE, FALSE); + MOVA (l); + pic16_emitcode ("xrl", "a,%s", pic16_aopGet (AOP (right), 0, FALSE, TRUE)); + pic16_emitcode ("push", "acc"); /* save it on the stack */ + + /* now sign adjust for both left & right */ + l = pic16_aopGet (AOP (right), 0, FALSE, FALSE); + MOVA (l); + lbl = newiTempLabel (NULL); + pic16_emitcode ("jnb", "acc.7,%05d_DS_", labelKey2num (lbl->key)); + pic16_emitcode ("cpl", "a"); + pic16_emitcode ("inc", "a"); + pic16_emitcode ("", "%05d_DS_:", labelKey2num (lbl->key)); + pic16_emitcode ("mov", "b,a"); + + /* sign adjust left side */ + l = pic16_aopGet (AOP (left), 0, FALSE, FALSE); + MOVA (l); + + lbl = newiTempLabel (NULL); + pic16_emitcode ("jnb", "acc.7,%05d_DS_", labelKey2num (lbl->key)); + pic16_emitcode ("cpl", "a"); + pic16_emitcode ("inc", "a"); + pic16_emitcode ("", "%05d_DS_:", labelKey2num (lbl->key)); + + /* now the division */ + pic16_emitcode ("div", "ab"); + /* we are interested in the lower order + only */ + pic16_emitcode ("mov", "b,a"); + lbl = newiTempLabel (NULL); + pic16_emitcode ("pop", "acc"); + /* if there was an over flow we don't + adjust the sign of the result */ + pic16_emitcode ("jb", "ov,%05d_DS_", labelKey2num (lbl->key)); + pic16_emitcode ("jnb", "acc.7,%05d_DS_", labelKey2num (lbl->key)); + CLRC; + pic16_emitcode ("clr", "a"); + pic16_emitcode ("subb", "a,b"); + pic16_emitcode ("mov", "b,a"); + pic16_emitcode ("", "%05d_DS_:", labelKey2num (lbl->key)); + + /* now we are done */ + pic16_aopPut (AOP (result), "b", 0); + if (size > 0) + { + pic16_emitcode ("mov", "c,b.7"); + pic16_emitcode ("subb", "a,acc"); + } + while (size--) + pic16_aopPut (AOP (result), "a", offset++); + +} +#endif + +/*-----------------------------------------------------------------*/ +/* 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); + int negated = 0; + int leftVal = 0, rightVal = 0; + int signedLits = 0; + char *functions[2][2] = { {"__divschar", "__divuchar"}, {"__modschar", "__moduchar"} }; + int op = 0; + + /* Division is a very lengthy algorithm, so it is better + * to call support routines than inlining algorithm. + * Division functions written here just in case someone + * wants to inline and not use the support libraries -- VR */ + + FENTRY; + + /* assign the amsops */ + pic16_aopOp (left, ic, FALSE); + pic16_aopOp (right, ic, FALSE); + pic16_aopOp (result, ic, TRUE); + + if (ic->op == '/') + op = 0; + else if (ic->op == '%') + op = 1; + else + assert (!"invalid operation requested in genDivMod"); + + /* get literal values */ + if (IS_VALOP (left)) + { + leftVal = (int) ulFromVal (OP_VALUE (left)); + assert (leftVal >= -128 && leftVal < 256); + if (leftVal < 0) + { + signedLits++; + } + } + if (IS_VALOP (right)) + { + rightVal = (int) ulFromVal (OP_VALUE (right)); + assert (rightVal >= -128 && rightVal < 256); + if (rightVal < 0) + { + signedLits++; + } + } + + /* We should only come here to convert all + * / : {u8_t, s8_t} x {u8_t, s8_t} -> {u8_t, s8_t} + * with exactly one operand being s8_t into + * u8_t x u8_t -> u8_t. All other cases should have been + * turned into calls to support routines beforehand... */ + if ((AOP_SIZE (left) == 1 || IS_VALOP (left)) && (AOP_SIZE (right) == 1 || IS_VALOP (right))) + { + if ((!IS_UNSIGNED (operandType (right)) || rightVal < 0) && (!IS_UNSIGNED (operandType (left)) || leftVal < 0)) + { + /* Both operands are signed or negative, use _divschar + * instead of _divuchar */ + pushaop (AOP (right), 0); + pushaop (AOP (left), 0); + + /* call _divschar */ + pic16_emitpcode (POC_CALL, pic16_popGetWithString (functions[op][0])); + + { + symbol *sym; + sym = newSymbol (functions[op][0], 0); + sym->used++; + strcpy (sym->rname, functions[op][0]); + checkAddSym (&externs, sym); + } + + /* assign result */ + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), 0)); + if (AOP_SIZE (result) > 1) + { + pic16_emitpcode (POC_MOVFF, pic16_popGet2p (pic16_popCopyReg (&pic16_pc_prodl), pic16_popGet (AOP (result), 1))); + /* sign extend */ + pic16_addSign (result, 2, 1); + } + + /* clean up stack */ + pic16_emitpcode (POC_MOVFW, pic16_popCopyReg (pic16_stack_preinc)); + pic16_emitpcode (POC_MOVFW, pic16_popCopyReg (pic16_stack_preinc)); + + goto release; + } + + /* push right operand */ + if (IS_VALOP (right)) + { + if (rightVal < 0) + { + pic16_pushpCodeOp (pic16_popGetLit (-rightVal)); + negated++; + } + else + { + pushaop (AOP (right), 0); + } + } + else if (!IS_UNSIGNED (operandType (right))) + { + pic16_mov2w (AOP (right), 0); + pic16_emitpcode (POC_BTFSC, pic16_newpCodeOpBit_simple (AOP (right), 0, 7)); + pic16_emitpcode (POC_NEGF, pic16_popCopyReg (&pic16_pc_wreg)); + pic16_emitpcode (POC_MOVWF, pic16_popCopyReg (pic16_stack_postdec)); + negated++; + } + else + { + pushaop (AOP (right), 0); + } + + /* push left operand */ + if (IS_VALOP (left)) + { + if (leftVal < 0) + { + pic16_pushpCodeOp (pic16_popGetLit (-leftVal)); + negated++; + } + else + { + pushaop (AOP (left), 0); + } + } + else if (!IS_UNSIGNED (operandType (left))) + { + pic16_mov2w (AOP (left), 0); + pic16_emitpcode (POC_BTFSC, pic16_newpCodeOpBit_simple (AOP (left), 0, 7)); + pic16_emitpcode (POC_NEGF, pic16_popCopyReg (&pic16_pc_wreg)); + pic16_emitpcode (POC_MOVWF, pic16_popCopyReg (pic16_stack_postdec)); + negated++; + } + else + { + pushaop (AOP (left), 0); + } + + /* call _divuchar */ + pic16_emitpcode (POC_CALL, pic16_popGetWithString (functions[op][1])); + + { + symbol *sym; + sym = newSymbol (functions[op][1], 0); + sym->used++; + strcpy (sym->rname, functions[op][1]); + checkAddSym (&externs, sym); + } + + /* Revert negation(s) from above. + * This is inefficient: if both operands are negative, this + * should not touch WREG. However, determining that exactly + * one operand was negated costs at least 3 instructions, + * so there is nothing to be gained here, is there? + * + * I negate WREG because either operand might share registers with + * result, so assigning first might destroy an operand. */ + + /* For the modulus operator, (a/b)*b == a shall hold. + * Thus: a>0, b>0 --> a/b >= 0 and a%b >= 0 + * a>0, b<0 --> a/b <= 0 and a%b >= 0 (e.g. 128 / -5 = -25, -25*(-5) = 125 and +3 remaining) + * a<0, b>0 --> a/b <= 0 and a%b < 0 (e.g. -128 / 5 = -25, -25* 5 = -125 and -3 remaining) + * a<0, b<0 --> a/b >= 0 and a%b < 0 (e.g. -128 / -5 = 25, 25*(-5) = -125 and -3 remaining) + * Only invert the result if the left operand is negative (sigh). + */ + if (AOP_SIZE (result) <= 1 || !negated) + { + if (ic->op == '/') + { + if (IS_VALOP (right)) + { + if (rightVal < 0) + { + /* we negated this operand above */ + pic16_emitpcode (POC_NEGF, pic16_popCopyReg (&pic16_pc_wreg)); + } + } + else if (!IS_UNSIGNED (operandType (right))) + { + pic16_emitpcode (POC_BTFSC, pic16_newpCodeOpBit_simple (AOP (right), 0, 7)); + pic16_emitpcode (POC_NEGF, pic16_popCopyReg (&pic16_pc_wreg)); + } + } + + if (IS_VALOP (left)) + { + if (leftVal < 0) + { + /* we negated this operand above */ + pic16_emitpcode (POC_NEGF, pic16_popCopyReg (&pic16_pc_wreg)); + } + } + else if (!IS_UNSIGNED (operandType (left))) + { + pic16_emitpcode (POC_BTFSC, pic16_newpCodeOpBit_simple (AOP (left), 0, 7)); + pic16_emitpcode (POC_NEGF, pic16_popCopyReg (&pic16_pc_wreg)); + } + + /* Move result to destination. */ + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), 0)); + + /* Zero-extend: no operand was signed (or result is just a byte). */ + pic16_addSign (result, 1, 0); + } + else + { + assert (AOP_SIZE (result) > 1); + pic16_emitpcode (POC_CLRF, pic16_popGet (AOP (result), 1)); + if (ic->op == '/') + { + if (IS_VALOP (right)) + { + if (rightVal < 0) + { + /* we negated this operand above */ + pic16_emitpcode (POC_COMF, pic16_popGet (AOP (result), 1)); + } + } + else if (!IS_UNSIGNED (operandType (right))) + { + pic16_emitpcode (POC_BTFSC, pic16_newpCodeOpBit_simple (AOP (right), 0, 7)); + pic16_emitpcode (POC_COMF, pic16_popGet (AOP (result), 1)); + } + } + + if (IS_VALOP (left)) + { + if (leftVal < 0) + { + /* we negated this operand above */ + pic16_emitpcode (POC_COMF, pic16_popGet (AOP (result), 1)); + } + } + else if (!IS_UNSIGNED (operandType (left))) + { + pic16_emitpcode (POC_BTFSC, pic16_newpCodeOpBit_simple (AOP (left), 0, 7)); + pic16_emitpcode (POC_COMF, pic16_popGet (AOP (result), 1)); + } + + /* Move result to destination. */ + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), 0)); + + /* Negate result if required. */ + pic16_emitpcode (POC_BTFSC, pic16_newpCodeOpBit_simple (AOP (result), 1, 7)); + pic16_emitpcode (POC_NEGF, pic16_popGet (AOP (result), 0)); + + /* Sign-extend. */ + pic16_addSign (result, 2, 1); + } + + /* clean up stack */ + pic16_emitpcode (POC_MOVFW, pic16_popCopyReg (pic16_stack_preinc)); + pic16_emitpcode (POC_MOVFW, pic16_popCopyReg (pic16_stack_preinc)); + goto release; + } + +#if 0 + /* 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; + } +#endif + + /* should have been converted to function call */ + assert (0); +release: + pic16_freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + pic16_freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + pic16_freeAsmop (result, NULL, ic, TRUE); +} + +#if 0 +/*-----------------------------------------------------------------*/ +/* genModbits :- modulus of bits */ +/*-----------------------------------------------------------------*/ +static void +genModbits (operand * left, operand * right, operand * result) +{ + char *l; + + FENTRY; + + werror (W_POSSBUG2, __FILE__, __LINE__); + /* the result must be bit */ + pic16_emitcode ("mov", "b,%s", pic16_aopGet (AOP (right), 0, FALSE, FALSE)); + l = pic16_aopGet (AOP (left), 0, FALSE, FALSE); + + MOVA (l); + + pic16_emitcode ("div", "ab"); + pic16_emitcode ("mov", "a,b"); + pic16_emitcode ("rrc", "a"); + pic16_aopPut (AOP (result), "c", 0); +} + +/*-----------------------------------------------------------------*/ +/* genModOneByte : 8 bit modulus */ +/*-----------------------------------------------------------------*/ +static void +genModOneByte (operand * left, operand * right, operand * result) +{ + sym_link *opetype = operandType (result); + char *l; + symbol *lbl; + + FENTRY; + werror (W_POSSBUG2, __FILE__, __LINE__); + + /* signed or unsigned */ + if (SPEC_USIGN (opetype)) + { + /* unsigned is easy */ + pic16_emitcode ("mov", "b,%s", pic16_aopGet (AOP (right), 0, FALSE, FALSE)); + l = pic16_aopGet (AOP (left), 0, FALSE, FALSE); + MOVA (l); + pic16_emitcode ("div", "ab"); + pic16_aopPut (AOP (result), "b", 0); + return; + } + + /* signed is a little bit more difficult */ + + /* save the signs of the operands */ + l = pic16_aopGet (AOP (left), 0, FALSE, FALSE); + MOVA (l); + + pic16_emitcode ("xrl", "a,%s", pic16_aopGet (AOP (right), 0, FALSE, FALSE)); + pic16_emitcode ("push", "acc"); /* save it on the stack */ + + /* now sign adjust for both left & right */ + l = pic16_aopGet (AOP (right), 0, FALSE, FALSE); + MOVA (l); + + lbl = newiTempLabel (NULL); + pic16_emitcode ("jnb", "acc.7,%05d_DS_", labelKey2num (lbl->key)); + pic16_emitcode ("cpl", "a"); + pic16_emitcode ("inc", "a"); + pic16_emitcode ("", "%05d_DS_:", labelKey2num (lbl->key)); + pic16_emitcode ("mov", "b,a"); + + /* sign adjust left side */ + l = pic16_aopGet (AOP (left), 0, FALSE, FALSE); + MOVA (l); + + lbl = newiTempLabel (NULL); + pic16_emitcode ("jnb", "acc.7,%05d_DS_", labelKey2num (lbl->key)); + pic16_emitcode ("cpl", "a"); + pic16_emitcode ("inc", "a"); + pic16_emitcode ("", "%05d_DS_:", labelKey2num (lbl->key)); + + /* now the multiplication */ + pic16_emitcode ("div", "ab"); + /* we are interested in the lower order + only */ + lbl = newiTempLabel (NULL); + pic16_emitcode ("pop", "acc"); + /* if there was an over flow we don't + adjust the sign of the result */ + pic16_emitcode ("jb", "ov,%05d_DS_", labelKey2num (lbl->key)); + pic16_emitcode ("jnb", "acc.7,%05d_DS_", labelKey2num (lbl->key)); + CLRC; + pic16_emitcode ("clr", "a"); + pic16_emitcode ("subb", "a,b"); + pic16_emitcode ("mov", "b,a"); + pic16_emitcode ("", "%05d_DS_:", labelKey2num (lbl->key)); + + /* now we are done */ + pic16_aopPut (AOP (result), "b", 0); + +} +#endif + +/*-----------------------------------------------------------------*/ +/* genMod - generates code for division */ +/*-----------------------------------------------------------------*/ +static void +genMod (iCode * ic) +{ + /* Task deferred to genDiv */ + genDiv (ic); +#if 0 + operand *left = IC_LEFT (ic); + operand *right = IC_RIGHT (ic); + operand *result = IC_RESULT (ic); + + FENTRY; + + /* assign the amsops */ + pic16_aopOp (left, ic, FALSE); + pic16_aopOp (right, ic, FALSE); + pic16_aopOp (result, ic, TRUE); + + /* special cases first */ + /* both are bits */ + if (AOP_TYPE (left) == AOP_CRY && AOP_TYPE (right) == AOP_CRY) + { + genModbits (left, right, result); + goto release; + } + + /* if both are of size == 1 */ + if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1) + { + genModOneByte (left, right, result); + goto release; + } + + /* should have been converted to function call */ + assert (0); + +release: + pic16_freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + pic16_freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + pic16_freeAsmop (result, NULL, ic, TRUE); +#endif +} + +/*-----------------------------------------------------------------*/ +/* 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; + + /* 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) + emitSKPNC; + else + { + DEBUGpic16_emitcode ("; ***", "%d - assuming %s is in bit space", __LINE__, jval); + pic16_emitpcode (POC_BTFSC, pic16_newpCodeOpBit (jval, -1, 1, PO_GPR_REGISTER)); + } + + pic16_emitpcode (POC_GOTO, pic16_popGetLabel (IC_TRUE (ic)->key)); + pic16_emitcode (" goto", "_%05d_DS_", labelKey2num (IC_TRUE (ic)->key + pic16_labelOffset)); + + } + else + { + /* false label is present */ + if (strcmp (jval, "a") == 0) + emitSKPNZ; + else if (strcmp (jval, "c") == 0) + emitSKPC; + else + { + DEBUGpic16_emitcode ("; ***", "%d - assuming %s is in bit space", __LINE__, jval); + pic16_emitpcode (POC_BTFSS, pic16_newpCodeOpBit (jval, -1, 1, PO_GPR_REGISTER)); + } + + pic16_emitpcode (POC_GOTO, pic16_popGetLabel (IC_FALSE (ic)->key)); + pic16_emitcode (" goto", "_%05d_DS_", labelKey2num (IC_FALSE (ic)->key + pic16_labelOffset)); + + } + + + /* mark the icode as generated */ + ic->generated = 1; +} + +static void +genIfxpCOpJump (iCode * ic, pCodeOp * jop) +{ + FENTRY; + + /* if true label then we jump if condition + supplied is true */ + if (IC_TRUE (ic)) + { + DEBUGpic16_emitcode ("; ***", "%d - assuming is in bit space", __LINE__); + pic16_emitpcode (POC_BTFSC, jop); + + pic16_emitpcode (POC_GOTO, pic16_popGetLabel (IC_TRUE (ic)->key)); + pic16_emitcode (" goto", "_%05d_DS_", labelKey2num (IC_TRUE (ic)->key + pic16_labelOffset)); + + } + else + { + /* false label is present */ + DEBUGpic16_emitcode ("; ***", "%d - assuming is in bit space", __LINE__); + pic16_emitpcode (POC_BTFSS, jop); + + pic16_emitpcode (POC_GOTO, pic16_popGetLabel (IC_FALSE (ic)->key)); + pic16_emitcode (" goto", "_%05d_DS_", labelKey2num (IC_FALSE (ic)->key + pic16_labelOffset)); + } + + + /* mark the icode as generated */ + ic->generated = 1; +} + +#if 0 +// not needed ATM + +/*-----------------------------------------------------------------*/ +/* genSkip */ +/*-----------------------------------------------------------------*/ +static void +genSkip (iCode * ifx, int status_bit) +{ + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + if (!ifx) + return; + + if (IC_TRUE (ifx)) + { + switch (status_bit) + { + case 'z': + emitSKPNZ; + break; + + case 'c': + emitSKPNC; + break; + + case 'd': + emitSKPDC; + break; + + } + + pic16_emitpcode (POC_GOTO, pic16_popGetLabel (IC_TRUE (ifx)->key)); + // pic16_emitcode("goto","_%05d_DS_",labelKey2num (IC_TRUE(ifx)->key + pic16_labelOffset)); + + } + else + { + + switch (status_bit) + { + + case 'z': + emitSKPZ; + break; + + case 'c': + emitSKPC; + break; + + case 'd': + emitSKPDC; + break; + } + pic16_emitpcode (POC_GOTO, pic16_popGetLabel (IC_FALSE (ifx)->key)); + // pic16_emitcode("goto","_%05d_DS_",labelKey2num (IC_FALSE(ifx)->key + pic16_labelOffset)); + + } + +} +#endif + +/*-----------------------------------------------------------------*/ +/* genSkipc */ +/*-----------------------------------------------------------------*/ +static void +genSkipc (resolvedIfx * rifx) +{ + DEBUGpic16_emitcode ("; ***", "%s %d rifx= %p", __FUNCTION__, __LINE__, rifx); + + if (!rifx) + return; + + if (rifx->condition) + emitSKPNC; + else + emitSKPC; + + pic16_emitpcode (POC_GOTO, pic16_popGetLabel (rifx->lbl->key)); + rifx->generated = 1; +} + +/*-----------------------------------------------------------------*/ +/* 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) */ +/*-----------------------------------------------------------------*/ +void +mov2w_regOrLit (asmop * aop, unsigned long lit, int offset) +{ + if (aop->type == AOP_LIT) + { + pic16_emitpcode (POC_MOVLW, pic16_popGetLit (lit >> (offset * 8))); + } + else + { + pic16_emitpcode (POC_MOVFW, pic16_popGet (aop, offset)); + } +} + +/*-----------------------------------------------------------------*/ +/* genCmp :- greater or less than comparison */ +/*-----------------------------------------------------------------*/ + +/* 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; + + FENTRY; + + assert (left && right); + assert (AOP_SIZE (left) == AOP_SIZE (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 for special cases */ + if (pic16_genCmp_special (left, right, result, ifx, &rIfx, sign)) + return; + + /********************************************************************** + * 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; + pic16_emitpcode (POC_BTFSS, pic16_popCopyGPR2Bit (pic16_popGet (AOP (left), size), 7)); + 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 + if (AOP_TYPE (left) == AOP_PCODE && AOP (left)->aopu.pcop->type == PO_IMMEDIATE) + { + // right >= left(PO_IMMEDIATE) + pic16_emitpcode (POC_MOVLW, pic16_popGetImmed (AOP (left), size, 1)); // left+1 + pic16_emitpcode (POC_SUBFW, pic16_popGet(AOP (right), size)); + performedLt = 0; + } + else if (AOP_TYPE (right) == AOP_PCODE && AOP (right)->aopu.pcop->type == PO_IMMEDIATE) + { + // left < right(PO_IMMEDIATE) + pic16_emitpcode (POC_MOVLW, pic16_popGetImmed (AOP (right), size, 0)); // right+0 + pic16_emitpcode (POC_SUBFW, pic16_popGet (AOP (left), size)); + } + else + { + mov2w_regOrLit (AOP(right), lit, size); + pic16_emitpcode (POC_SUBFW, pic16_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 + pic16_mov2w (AOP (left), size); + pic16_emitpcode (POC_XORLW, pic16_popGetLit (0x80)); // set ZERO flag + emitSETC; + } + else + { + // left >= LIT <-> left + (-LIT) >= 0 <-> left + (0x100-LIT) >= 0x100 + pic16_mov2w (AOP (left), size); + pic16_emitpcode (POC_ADDLW, pic16_popGetLit (0x80)); + pic16_emitpcode (POC_ADDLW, pic16_popGetLit ((0x100 - (litbyte + 0x80)) & 0x00FF)); + } // if + } + else + { + /* using PRODL as a temporary register here */ + pCodeOp *pctemp = pic16_popCopyReg (&pic16_pc_prodl); + //pCodeOp *pctemp = pic16_popGetTempReg(1); + pic16_mov2w (AOP (left), size); + pic16_emitpcode (POC_ADDLW, pic16_popGetLit (0x80)); + pic16_emitpcode (POC_MOVWF, pctemp); + pic16_mov2w (AOP (right), size); + pic16_emitpcode (POC_ADDLW, pic16_popGetLit (0x80)); + pic16_emitpcode (POC_SUBFW, pctemp); + //pic16_popReleaseTempReg(pctemp, 1); + } + } // 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); + pic16_emitpcode (POC_BNZ, pic16_popGetLabel (templbl->key)); + + if (AOP_TYPE (left) == AOP_PCODE && AOP (left)->aopu.pcop->type == PO_IMMEDIATE) + { + // right >= left(PO_IMMEDIATE) + pic16_emitpcode (POC_MOVLW, pic16_popGetImmed( AOP (left), offs, 1)); // left+1 + pic16_emitpcode (POC_SUBFW, pic16_popGet (AOP (right), offs)); + performedLt = 0; + } + else if (AOP_TYPE (right) == AOP_PCODE && AOP (right)->aopu.pcop->type == PO_IMMEDIATE) + { + // left < right(PO_IMMEDIATE) + pic16_emitpcode (POC_MOVLW, pic16_popGetImmed (AOP (right), offs, 0)); // right+0 + pic16_emitpcode (POC_SUBFW, pic16_popGet (AOP (left), offs)); + } + else + { + mov2w_regOrLit (AOP (right), lit, offs); + pic16_emitpcode (POC_SUBFW, pic16_popGet (AOP (left), offs)); + } + } // while (offs) + pic16_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) + { + if (result && AOP_TYPE (result) != AOP_CRY) + { + // value will be stored + emitTOGC; + } + else + { + // value wil only be used in the following genSkipc() + rIfx.condition ^= 1; + } + } // if + +correct_result_in_carry: + + // assign result to variable (if neccessary) + if (result && AOP_TYPE (result) != AOP_CRY) + { + //DEBUGpc ("assign result"); + size = AOP_SIZE (result); + while (size--) + { + pic16_emitpcode (POC_CLRF, pic16_popGet (AOP (result), size)); + } // while + pic16_emitpcode (POC_RLCF, pic16_popGet (AOP (result), 0)); + } // if (result) + + // perform conditional jump + if (ifx) + { + //DEBUGpc ("generate control flow"); + genSkipc (&rIfx); + ifx->generated = 1; + } // if +} + +/*-----------------------------------------------------------------*/ +/* genCmpGt :- greater than comparison */ +/*-----------------------------------------------------------------*/ +static void +genCmpGt (iCode * ic, iCode * ifx) +{ + operand *left, *right, *result; + sym_link *letype, *retype; + int sign; + + FENTRY; + + 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 */ + pic16_aopOp (left, ic, FALSE); + pic16_aopOp (right, ic, FALSE); + pic16_aopOp (result, ic, TRUE); + + genCmp (right, left, result, ifx, sign); + + pic16_freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + pic16_freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + pic16_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; + + 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 */ + pic16_aopOp (left, ic, FALSE); + pic16_aopOp (right, ic, FALSE); + pic16_aopOp (result, ic, TRUE); + + genCmp (left, right, result, ifx, sign); + + pic16_freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + pic16_freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + pic16_freeAsmop (result, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* pic16_isLitOp - check if operand has to be treated as literal */ +/*-----------------------------------------------------------------*/ +bool +pic16_isLitOp (operand * op) +{ + return ((AOP_TYPE (op) == AOP_LIT) + || ((AOP_TYPE (op) == AOP_PCODE) + && ((AOP (op)->aopu.pcop->type == PO_LITERAL) || (AOP (op)->aopu.pcop->type == PO_IMMEDIATE)))); +} + +/*-----------------------------------------------------------------*/ +/* pic16_isLitAop - check if operand has to be treated as literal */ +/*-----------------------------------------------------------------*/ +bool +pic16_isLitAop (asmop * aop) +{ + return ((aop->type == AOP_LIT) + || ((aop->type == AOP_PCODE) && ((aop->aopu.pcop->type == PO_LITERAL) || (aop->aopu.pcop->type == PO_IMMEDIATE)))); +} + + + +/*-----------------------------------------------------------------*/ +/* genCmpEq - generates code for equal to */ +/*-----------------------------------------------------------------*/ +static void +genCmpEq (iCode * ic, iCode * ifx) +{ + operand *left, *right, *result; + symbol *falselbl = newiTempLabel (NULL); + symbol *donelbl = newiTempLabel (NULL); + + int preserve_result = 0; + int generate_result = 0; + int i = 0; + unsigned long lit = -1; + + FENTRY; + + pic16_aopOp ((left = IC_LEFT (ic)), ic, FALSE); + pic16_aopOp ((right = IC_RIGHT (ic)), ic, FALSE); + pic16_aopOp ((result = IC_RESULT (ic)), ic, TRUE); + + DEBUGpic16_pic16_AopType (__LINE__, left, right, result); + + if ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (left) == AOP_CRY)) + { + werror (W_POSSBUG2, __FILE__, __LINE__); + DEBUGpic16_emitcode ("; ***", "%s %d -- ERROR", __FUNCTION__, __LINE__); + fprintf (stderr, "%s %d error - left/right CRY operands not supported\n", __FUNCTION__, __LINE__); + goto release; + } + + if (pic16_isLitOp (left) || (AOP_TYPE (right) == AOP_ACC)) + { + operand *tmp = right; + right = left; + left = tmp; + } + + if (AOP_TYPE (right) == AOP_LIT) + { + lit = ulFromVal (AOP (right)->aopu.aop_lit); + } + + if (regsInCommon (left, result) || regsInCommon (right, result)) + preserve_result = 1; + + if (result && AOP_SIZE (result)) + generate_result = 1; + + if (generate_result && !preserve_result) + { + for (i = 0; i < AOP_SIZE (result); i++) + pic16_emitpcode (POC_CLRF, pic16_popGet (AOP (result), i)); + } + + assert (AOP_SIZE (left) == AOP_SIZE (right)); + for (i = 0; i < AOP_SIZE (left); i++) + { + if (AOP_TYPE (left) != AOP_ACC) + { + if (pic16_isLitOp (left)) + pic16_emitpcode (POC_MOVLW, pic16_popGet (AOP (left), i)); + else + pic16_emitpcode (POC_MOVFW, pic16_popGet (AOP (left), i)); + } + if (pic16_isLitOp (right)) + { + if (pic16_isLitOp (left) || (0 != ((lit >> (8 * i)) & 0x00FF))) + { + pic16_emitpcode (POC_XORLW, pic16_popGet (AOP (right), i)); + } + } + else + pic16_emitpcode (POC_XORFW, pic16_popGet (AOP (right), i)); + + pic16_emitpcode (POC_BNZ, pic16_popGetLabel (falselbl->key)); + } + + // result == true + + if (generate_result && preserve_result) + { + for (i = 0; i < AOP_SIZE (result); i++) + pic16_emitpcode (POC_CLRF, pic16_popGet (AOP (result), i)); + } + + if (generate_result) + pic16_emitpcode (POC_INCF, pic16_popGet (AOP (result), 0)); // result = true + + if (generate_result && preserve_result) + pic16_emitpcode (POC_GOTO, pic16_popGetLabel (donelbl->key)); + + if (ifx && IC_TRUE (ifx)) + pic16_emitpcode (POC_GOTO, pic16_popGetLabel (IC_TRUE (ifx)->key)); + + if (ifx && IC_FALSE (ifx)) + pic16_emitpcode (POC_GOTO, pic16_popGetLabel (donelbl->key)); + + pic16_emitpLabel (falselbl->key); + + // result == false + + if (ifx && IC_FALSE (ifx)) + pic16_emitpcode (POC_GOTO, pic16_popGetLabel (IC_FALSE (ifx)->key)); + + if (generate_result && preserve_result) + { + for (i = 0; i < AOP_SIZE (result); i++) + pic16_emitpcode (POC_CLRF, pic16_popGet (AOP (result), i)); + } + + pic16_emitpLabel (donelbl->key); + + if (ifx) + ifx->generated = 1; + +release: + pic16_freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + pic16_freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + pic16_freeAsmop (result, NULL, ic, TRUE); + +} + + +#if 0 +// old version kept for reference + +/*-----------------------------------------------------------------*/ +/* genCmpEq - generates code for equal to */ +/*-----------------------------------------------------------------*/ +static void +genCmpEq (iCode * ic, iCode * ifx) +{ + operand *left, *right, *result; + unsigned long lit = 0L; + int size, offset = 0; + symbol *falselbl = newiTempLabel (NULL); + + + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + + if (ifx) + DEBUGpic16_emitcode ("; ifx is non-null", ""); + else + DEBUGpic16_emitcode ("; ifx is null", ""); + + pic16_aopOp ((left = IC_LEFT (ic)), ic, FALSE); + pic16_aopOp ((right = IC_RIGHT (ic)), ic, FALSE); + pic16_aopOp ((result = IC_RESULT (ic)), ic, TRUE); + + size = max (AOP_SIZE (left), AOP_SIZE (right)); + + DEBUGpic16_pic16_AopType (__LINE__, left, right, result); + + /* if literal, literal on the right or + if the right is in a pointer register and left + is not */ + if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)) + { + operand *tmp = right; + right = left; + left = tmp; + } + + + if (ifx && !AOP_SIZE (result)) + { + symbol *tlbl; + DEBUGpic16_emitcode ("; ***", "%s %d CASE 1", __FUNCTION__, __LINE__); + /* if they are both bit variables */ + if (AOP_TYPE (left) == AOP_CRY && ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT))) + { + DEBUGpic16_emitcode ("; ***", "%s %d CASE 11", __FUNCTION__, __LINE__); + if (AOP_TYPE (right) == AOP_LIT) + { + unsigned long lit = ulFromVal (AOP (right)->aopu.aop_lit); + if (lit == 0L) + { + pic16_emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir); + pic16_emitcode ("cpl", "c"); + } + else if (lit == 1L) + { + pic16_emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir); + } + else + { + pic16_emitcode ("clr", "c"); + } + /* AOP_TYPE(right) == AOP_CRY */ + } + else + { + symbol *lbl = newiTempLabel (NULL); + pic16_emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir); + pic16_emitcode ("jb", "%s,%05d_DS_", AOP (right)->aopu.aop_dir, labelKey2num (lbl->key)); + pic16_emitcode ("cpl", "c"); + pic16_emitcode ("", "%05d_DS_:", labelKey2num (lbl->key)); + } + /* if true label then we jump if condition + supplied is true */ + tlbl = newiTempLabel (NULL); + if (IC_TRUE (ifx)) + { + pic16_emitcode ("jnc", "%05d_DS_", labelKey2num (tlbl->key)); + pic16_emitcode ("ljmp", "%05d_DS_", labelKey2num (IC_TRUE (ifx)->key)); + } + else + { + pic16_emitcode ("jc", "%05d_DS_", labelKey2num (tlbl->key)); + pic16_emitcode ("ljmp", "%05d_DS_", labelKey2num (IC_FALSE (ifx)->key)); + } + pic16_emitcode ("", "%05d_DS_:", labelKey2num (tlbl->key + pic16_labelOffset)); + + { + /* left and right are both bit variables, result is carry */ + resolvedIfx rIfx; + + resolveIfx (&rIfx, ifx); + + pic16_emitpcode (POC_MOVLW, pic16_popGet (AOP (left), 0)); + pic16_emitpcode (POC_ANDFW, pic16_popGet (AOP (left), 0)); + pic16_emitpcode (POC_BTFSC, pic16_popGet (AOP (right), 0)); + pic16_emitpcode (POC_ANDLW, pic16_popGet (AOP (left), 0)); + genSkipz2 (&rIfx, 0); + } + } + else + { + + DEBUGpic16_emitcode ("; ***", "%s %d CASE 12", __FUNCTION__, __LINE__); + + /* They're not both bit variables. Is the right a literal? */ + if (AOP_TYPE (right) == AOP_LIT) + { + lit = ulFromVal (AOP (right)->aopu.aop_lit); + + switch (size) + { + + case 1: + switch (lit & 0xff) + { + case 1: + if (IC_TRUE (ifx)) + { + pic16_emitpcode (POC_DECFW, pic16_popGet (AOP (left), offset)); + emitSKPNZ; + pic16_emitpcode (POC_GOTO, pic16_popGetLabel (IC_TRUE (ifx)->key)); + } + else + { + pic16_emitpcode (POC_DECFSZW, pic16_popGet (AOP (left), offset)); + pic16_emitpcode (POC_GOTO, pic16_popGetLabel (IC_FALSE (ifx)->key)); + } + break; + case 0xff: + if (IC_TRUE (ifx)) + { + pic16_emitpcode (POC_INCFW, pic16_popGet (AOP (left), offset)); + emitSKPNZ; + pic16_emitpcode (POC_GOTO, pic16_popGetLabel (IC_TRUE (ifx)->key)); + } + else + { + pic16_emitpcode (POC_INCFSZW, pic16_popGet (AOP (left), offset)); + pic16_emitpcode (POC_GOTO, pic16_popGetLabel (IC_FALSE (ifx)->key)); + } + break; + default: + pic16_emitpcode (POC_MOVFW, pic16_popGet (AOP (left), offset)); + if (lit) + pic16_emitpcode (POC_XORLW, pic16_popGetLit (lit & 0xff)); + genSkip (ifx, 'z'); + } // switch lit + + + /* end of size == 1 */ + break; + + case 2: + genc16bit2lit (left, lit, offset); + genSkip (ifx, 'z'); + break; + /* end of size == 2 */ + + default: + /* size is 4 */ + if (lit == 0) + { + pic16_emitpcode (POC_MOVFW, pic16_popGet (AOP (left), 0)); + pic16_emitpcode (POC_IORFW, pic16_popGet (AOP (left), 1)); + pic16_emitpcode (POC_IORFW, pic16_popGet (AOP (left), 2)); + pic16_emitpcode (POC_IORFW, pic16_popGet (AOP (left), 3)); + genSkip (ifx, 'z'); + } + else + { + /* search for patterns that can be optimized */ + + genc16bit2lit (left, lit, 0); + lit >>= 16; + if (lit) + { + if (IC_TRUE (ifx)) + emitSKPZ; // if hi word unequal + else + emitSKPNZ; // if hi word equal + // fail early + pic16_emitpcode (POC_GOTO, pic16_popGetLabel (falselbl->key)); + genc16bit2lit (left, lit, 2); + genSkip (ifx, 'z'); + } + else + { + pic16_emitpcode (POC_IORFW, pic16_popGet (AOP (left), 2)); + pic16_emitpcode (POC_IORFW, pic16_popGet (AOP (left), 3)); + genSkip (ifx, 'z'); + } + } + pic16_emitpLabel (falselbl->key); + break; + + } // switch size + + ifx->generated = 1; + goto release; + + + } + else if (AOP_TYPE (right) == AOP_CRY) + { + /* we know the left is not a bit, but that the right is */ + pic16_emitpcode (POC_MOVFW, pic16_popGet (AOP (left), offset)); + pic16_emitpcode (((IC_TRUE (ifx)) ? POC_BTFSC : POC_BTFSS), pic16_popGet (AOP (right), offset)); + pic16_emitpcode (POC_XORLW, pic16_popGetLit (1)); + + /* if the two are equal, then W will be 0 and the Z bit is set + * we could test Z now, or go ahead and check the high order bytes if + * the variable we're comparing is larger than a byte. */ + + while (--size) + pic16_emitpcode (POC_IORFW, pic16_popGet (AOP (left), offset)); + + if (IC_TRUE (ifx)) + { + emitSKPNZ; + pic16_emitpcode (POC_GOTO, pic16_popGetLabel (IC_TRUE (ifx)->key)); + // pic16_emitcode(" goto","_%05d_DS_",labelKey2num (IC_TRUE(ifx)->key + pic16_labelOffset)); + } + else + { + emitSKPZ; + pic16_emitpcode (POC_GOTO, pic16_popGetLabel (IC_FALSE (ifx)->key)); + // pic16_emitcode(" goto","_%05d_DS_",labelKey2num (IC_FALSE(ifx)->key + pic16_labelOffset)); + } + + } + else + { + /* They're both variables that are larger than bits */ + int s = size; + + tlbl = newiTempLabel (NULL); + + while (size--) + { + pic16_emitpcode (POC_MOVFW, pic16_popGet (AOP (left), offset)); + pic16_emitpcode (POC_XORFW, pic16_popGet (AOP (right), offset)); + + if (IC_TRUE (ifx)) + { + if (size) + { + emitSKPZ; + + DEBUGpic16_emitcode (";", "\tIC_TRUE emitSKPZ"); + + pic16_emitpcode (POC_GOTO, pic16_popGetLabel (tlbl->key)); + pic16_emitcode (" goto", "_%05d_DS_", labelKey2num (tlbl->key + pic16_labelOffset)); + } + else + { + emitSKPNZ; + + DEBUGpic16_emitcode (";", "\tIC_TRUE emitSKPNZ"); + + + pic16_emitpcode (POC_GOTO, pic16_popGetLabel (IC_TRUE (ifx)->key)); + pic16_emitcode (" goto", "_%05d_DS_", labelKey2num (IC_TRUE (ifx)->key + pic16_labelOffset)); + } + } + else + { + emitSKPZ; + + DEBUGpic16_emitcode (";", "\tnot IC_TRUE emitSKPZ"); + + pic16_emitpcode (POC_GOTO, pic16_popGetLabel (IC_FALSE (ifx)->key)); + pic16_emitcode (" goto", "_%05d_DS_", labelKey2num (IC_FALSE (ifx)->key + pic16_labelOffset)); + } + offset++; + } + if (s > 1 && IC_TRUE (ifx)) + { + pic16_emitpLabel (tlbl->key); + pic16_emitcode ("", "_%05d_DS_:", labelKey2num (tlbl->key + pic16_labelOffset)); + } + } + } + /* mark the icode as generated */ + ifx->generated = 1; + goto release; + } + + /* if they are both bit variables */ + if (AOP_TYPE (left) == AOP_CRY && ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT))) + { + DEBUGpic16_emitcode ("; ***", "%s %d CASE 2", __FUNCTION__, __LINE__); + if (AOP_TYPE (right) == AOP_LIT) + { + unsigned long lit = ulFromVal (AOP (right)->aopu.aop_lit); + if (lit == 0L) + { + pic16_emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir); + pic16_emitcode ("cpl", "c"); + } + else if (lit == 1L) + { + pic16_emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir); + } + else + { + pic16_emitcode ("clr", "c"); + } + /* AOP_TYPE(right) == AOP_CRY */ + } + else + { + symbol *lbl = newiTempLabel (NULL); + pic16_emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir); + pic16_emitcode ("jb", "%s,%05d_DS_", AOP (right)->aopu.aop_dir, labelKey2num (lbl->key)); + pic16_emitcode ("cpl", "c"); + pic16_emitcode ("", "%05d_DS_:", labelKey2num (lbl->key)); + } + /* c = 1 if egal */ + if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) + { + pic16_outBitC (result); + goto release; + } + if (ifx) + { + genIfxJump (ifx, "c"); + goto release; + } + /* if the result is used in an arithmetic operation + then put the result in place */ + pic16_outBitC (result); + } + else + { + + DEBUGpic16_emitcode ("; ***", "%s %d CASE 3", __FUNCTION__, __LINE__); + gencjne (left, right, result, ifx); + /* + if(ifx) + gencjne(left,right,newiTempLabel(NULL)); + else { + if(IC_TRUE(ifx)->key) + gencjne(left,right,IC_TRUE(ifx)->key); + else + gencjne(left,right,IC_FALSE(ifx)->key); + ifx->generated = 1; + goto release ; + } + if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) { + pic16_aopPut(AOP(result),"a",0); + goto release ; + } + + if (ifx) { + genIfxJump (ifx,"a"); + goto release ; + } + */ + /* if the result is used in an arithmetic operation + then put the result in place */ + /* + if (AOP_TYPE(result) != AOP_CRY) + pic16_outAcc(result); + */ + /* leave the result in acc */ + } + +release: + pic16_freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + pic16_freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + pic16_freeAsmop (result, NULL, ic, TRUE); +} +#endif + +/*-----------------------------------------------------------------*/ +/* genAndOp - for && operation */ +/*-----------------------------------------------------------------*/ +static void +genAndOp (iCode * ic) +{ + operand *left, *right, *result; + /* symbol *tlbl; */ + + FENTRY; + + /* note here that && operations that are in an + if statement are taken away by backPatchLabels + only those used in arthmetic operations remain */ + pic16_aopOp ((left = IC_LEFT (ic)), ic, FALSE); + pic16_aopOp ((right = IC_RIGHT (ic)), ic, FALSE); + pic16_aopOp ((result = IC_RESULT (ic)), ic, TRUE); + + DEBUGpic16_pic16_AopType (__LINE__, left, right, result); + + pic16_emitpcode (POC_MOVFW, pic16_popGet (AOP (left), 0)); + pic16_emitpcode (POC_ANDFW, pic16_popGet (AOP (right), 0)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), 0)); + + /* if both are bit variables */ + /* if (AOP_TYPE(left) == AOP_CRY && */ + /* AOP_TYPE(right) == AOP_CRY ) { */ + /* pic16_emitcode("mov","c,%s",AOP(left)->aopu.aop_dir); */ + /* pic16_emitcode("anl","c,%s",AOP(right)->aopu.aop_dir); */ + /* pic16_outBitC(result); */ + /* } else { */ + /* tlbl = newiTempLabel(NULL); */ + /* pic16_toBoolean(left); */ + /* pic16_emitcode("jz","%05d_DS_",labelKey2num (tlbl->key)); */ + /* pic16_toBoolean(right); */ + /* pic16_emitcode("","%05d_DS_:",labelKey2num (tlbl->key)); */ + /* pic16_outBitAcc(result); */ + /* } */ + + pic16_freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + pic16_freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + pic16_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; + + FENTRY; + + /* note here that || operations that are in an + if statement are taken away by backPatchLabels + only those used in arthmetic operations remain */ + pic16_aopOp ((left = IC_LEFT (ic)), ic, FALSE); + pic16_aopOp ((right = IC_RIGHT (ic)), ic, FALSE); + pic16_aopOp ((result = IC_RESULT (ic)), ic, TRUE); + + DEBUGpic16_pic16_AopType (__LINE__, left, right, result); + + /* if both are bit variables */ + if (AOP_TYPE (left) == AOP_CRY && AOP_TYPE (right) == AOP_CRY) + { + pic16_emitcode ("clrc", ""); + pic16_emitcode ("btfss", "(%s >> 3), (%s & 7)", AOP (left)->aopu.aop_dir, AOP (left)->aopu.aop_dir); + pic16_emitcode ("btfsc", "(%s >> 3), (%s & 7)", AOP (right)->aopu.aop_dir, AOP (right)->aopu.aop_dir); + pic16_emitcode ("setc", ""); + + } + else + { + tlbl = newiTempLabel (NULL); + pic16_toBoolean (left); + emitSKPZ; + pic16_emitcode ("goto", "%05d_DS_", labelKey2num (tlbl->key + pic16_labelOffset)); + pic16_toBoolean (right); + pic16_emitcode ("", "%05d_DS_:", labelKey2num (tlbl->key + pic16_labelOffset)); + + pic16_outBitAcc (result); + } + + pic16_freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + pic16_freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + pic16_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; + + DEBUGpic16_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; + if (IC_TRUE (ic)) + pic16_emitcode ("ljmp", "%05d_DS_", labelKey2num (IC_TRUE (ic)->key)); + ic->generated = 1; +} + +/*-----------------------------------------------------------------*/ +/* jmpIfTrue - */ +/*-----------------------------------------------------------------*/ +static void +jumpIfTrue (iCode * ic) +{ + FENTRY; + if (!IC_TRUE (ic)) + pic16_emitcode ("ljmp", "%05d_DS_", labelKey2num (IC_FALSE (ic)->key)); + ic->generated = 1; +} + +/*-----------------------------------------------------------------*/ +/* jmpTrueOrFalse - */ +/*-----------------------------------------------------------------*/ +static void +jmpTrueOrFalse (iCode * ic, symbol * tlbl) +{ + // ugly but optimized by peephole + FENTRY; + if (IC_TRUE (ic)) + { + symbol *nlbl = newiTempLabel (NULL); + pic16_emitcode ("sjmp", "%05d_DS_", labelKey2num (nlbl->key)); + pic16_emitcode ("", "%05d_DS_:", labelKey2num (tlbl->key)); + pic16_emitcode ("ljmp", "%05d_DS_", labelKey2num (IC_TRUE (ic)->key)); + pic16_emitcode ("", "%05d_DS_:", labelKey2num (nlbl->key)); + } + else + { + pic16_emitcode ("ljmp", "%05d_DS_", labelKey2num (IC_FALSE (ic)->key)); + pic16_emitcode ("", "%05d_DS_:", labelKey2num (tlbl->key)); + } + ic->generated = 1; +} + +/*-----------------------------------------------------------------*/ +/* genAnd - code for and */ +/*-----------------------------------------------------------------*/ +static void +genAnd (iCode * ic, iCode * ifx) +{ + operand *left, *right, *result; + int size, offset = 0; + unsigned long lit = 0L; + resolvedIfx rIfx; + + FENTRY; + + pic16_aopOp ((left = IC_LEFT (ic)), ic, FALSE); + pic16_aopOp ((right = IC_RIGHT (ic)), ic, FALSE); + pic16_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 (pic16_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); + + DEBUGpic16_pic16_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 && pic16_sameRegs (AOP (result), AOP (left))) + // no change + goto release; + pic16_emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir); + } + else + { + // bit(result) = 0; + if (size && (AOP_TYPE (result) == AOP_CRY)) + { + pic16_emitcode ("clr", "%s", AOP (result)->aopu.aop_dir); + goto release; + } + if ((AOP_TYPE (result) == AOP_CRY) && ifx) + { + jumpIfTrue (ifx); + goto release; + } + pic16_emitcode ("clr", "c"); + } + } + else + { + if (AOP_TYPE (right) == AOP_CRY) + { + // c = bit & bit; + pic16_emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir); + pic16_emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir); + } + else + { + // c = bit & val; + MOVA (pic16_aopGet (AOP (right), 0, FALSE, FALSE)); + // c = lsb + pic16_emitcode ("rrc", "a"); + pic16_emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir); + } + } + // bit = c + // val = c + if (size) + pic16_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)) + { + symbol *tlbl = newiTempLabel (NULL); + int sizel = AOP_SIZE (left); + int nonnull = 0; + char emitBra; + + if (size) + emitSETC; + + /* get number of non null bytes in literal */ + while (sizel--) + { + if (lit & (0xff << (sizel * 8))) + ++nonnull; + } + + emitBra = nonnull || rIfx.condition; + + for (sizel = AOP_SIZE (left); sizel--; ++offset, lit >>= 8) + { + unsigned char bytelit = lit & 0xFF; + + if (bytelit != 0) + { + int posbit; + + --nonnull; + + /* patch provided by Aaron Colwell */ + if ((posbit = isLiteralBit (bytelit)) != 0) + { + if (nonnull) + { + pic16_emitpcode (POC_BTFSC, + pic16_newpCodeOpBit (pic16_aopGet (AOP (left), offset, FALSE, FALSE), posbit - 1, 0, + PO_GPR_REGISTER)); + pic16_emitpcode (POC_GOTO, pic16_popGetLabel (rIfx.condition ? rIfx.lbl->key : tlbl->key)); + } + else + { + pic16_emitpcode (rIfx.condition ? POC_BTFSC : POC_BTFSS, + pic16_newpCodeOpBit (pic16_aopGet (AOP (left), offset, FALSE, FALSE), posbit - 1, 0, + PO_GPR_REGISTER)); + } + } + else + { + if (bytelit == 0xff) + { + /* Aaron had a MOVF instruction here, changed to MOVFW cause + * a peephole could optimize it out -- VR */ + pic16_emitpcode (POC_MOVFW, pic16_popGet (AOP (left), offset)); + } + else + { + pic16_emitpcode (POC_MOVFW, pic16_popGet (AOP (left), offset)); + pic16_emitpcode (POC_ANDLW, pic16_popGetLit (bytelit)); + } + if (nonnull) + { + if (rIfx.condition) + { + emitSKPZ; + pic16_emitpcode (POC_GOTO, pic16_popGetLabel (rIfx.lbl->key)); /* to false */ + } + else + { + pic16_emitpcode (POC_BNZ, pic16_popGetLabel (tlbl->key)); /* to true */ + } + } + else + { + /* last non null byte */ + if (rIfx.condition) + emitSKPZ; + else + emitSKPNZ; + } + } + } + } + + // bit = left & literal + if (size) + { + emitCLRC; + pic16_emitpLabel (tlbl->key); + } + + // if(left & literal) + else + { + if (ifx) + { + if (emitBra) + pic16_emitpcode (POC_GOTO, pic16_popGetLabel (rIfx.lbl->key)); + ifx->generated = 1; + } + pic16_emitpLabel (tlbl->key); + goto release; + } + pic16_outBitC (result); + goto release; + } + + /* if left is same as result */ + if (pic16_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 */ +// pic16_emitcode("clrf","%s",pic16_aopGet(AOP(result),offset,FALSE,FALSE)); + pic16_emitpcode (POC_CLRF, pic16_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 = pic16_my_powof2 ((~lit) & 0xff); + if (p >= 0) + { + /* only one bit is clear in the literal, so use a bcf instruction */ +// pic16_emitcode("bcf","%s,%d",pic16_aopGet(AOP(left),offset,FALSE,TRUE),p); + pic16_emitpcode (POC_BCF, + pic16_newpCodeOpBit (pic16_aopGet (AOP (left), offset, FALSE, FALSE), p, 0, + PO_GPR_REGISTER)); + + } + else + { + if (AOP_TYPE (left) == AOP_ACC) + { + pic16_emitcode ("andlw", "0x%x", lit & 0xff); + pic16_emitpcode (POC_ANDLW, pic16_popGetLit (lit & 0xff)); + know_W = -1; + } + else + { + if (know_W != (lit & 0xff)) + { + pic16_emitcode ("movlw", "0x%x", lit & 0xff); + pic16_emitpcode (POC_MOVLW, pic16_popGetLit (lit & 0xff)); + } + + know_W = lit & 0xff; + pic16_emitcode ("andwf", "%s,f", pic16_aopGet (AOP (left), offset, FALSE, TRUE)); + pic16_emitpcode (POC_ANDWF, pic16_popGet (AOP (left), offset)); + } + } + } + } + } + else + { + if (AOP_TYPE (left) == AOP_ACC) + { + pic16_emitpcode (POC_ANDFW, pic16_popGet (AOP (right), offset)); + } + else + { + pic16_emitpcode (POC_MOVFW, pic16_popGet (AOP (right), offset)); + pic16_emitpcode (POC_ANDWF, pic16_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) + pic16_emitcode ("setb", "c"); + while (sizer--) + { + MOVA (pic16_aopGet (AOP (right), offset, FALSE, FALSE)); + pic16_emitcode ("anl", "a,%s", pic16_aopGet (AOP (left), offset, FALSE, FALSE)); + pic16_emitcode ("jnz", "%05d_DS_", labelKey2num (tlbl->key)); + offset++; + } + if (size) + { + CLRC; + pic16_emitcode ("", "%05d_DS_:", labelKey2num (tlbl->key)); + pic16_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: + pic16_emitcode ("clrf", "%s", pic16_aopGet (AOP (result), offset, FALSE, FALSE)); + pic16_emitpcode (POC_CLRF, pic16_popGet (AOP (result), offset)); + break; + case 0xff: + pic16_emitcode ("movf", "%s,w", pic16_aopGet (AOP (left), offset, FALSE, FALSE)); + pic16_emitcode ("movwf", "%s", pic16_aopGet (AOP (result), offset, FALSE, FALSE)); + pic16_emitpcode (POC_MOVFW, pic16_popGet (AOP (left), offset)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offset)); + break; + default: + { + if (AOP_TYPE (left) == AOP_ACC) + { + pic16_emitcode ("andlw", "0x%02x", t); + pic16_emitcode ("movwf", "%s", pic16_aopGet (AOP (result), offset, FALSE, FALSE)); + pic16_emitpcode (POC_ANDLW, pic16_popGetLit (t)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offset)); + } + else + { + pic16_emitcode ("movlw", "0x%02x", t); + pic16_emitcode ("andwf", "%s,w", pic16_aopGet (AOP (left), offset, FALSE, FALSE)); + pic16_emitpcode (POC_MOVLW, pic16_popGetLit (t)); + pic16_emitpcode (POC_ANDFW, pic16_popGet (AOP (left), offset)); + + if (AOP_TYPE (result) != AOP_ACC) + { + pic16_emitcode ("movwf", "%s", pic16_aopGet (AOP (result), offset, FALSE, FALSE)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offset)); + } + else + { + DEBUGpic16_emitcode ("; ***", "ignore MOVWF\tWREG", __FUNCTION__, __LINE__); + } + } + } + } + continue; + } + + if (AOP_TYPE (left) == AOP_ACC) + { + pic16_emitcode ("andwf", "%s,w", pic16_aopGet (AOP (right), offset, FALSE, FALSE)); + pic16_emitpcode (POC_ANDFW, pic16_popGet (AOP (right), offset)); + } + else + { + pic16_emitcode ("movf", "%s,w", pic16_aopGet (AOP (right), offset, FALSE, FALSE)); + pic16_emitcode ("andwf", "%s,w", pic16_aopGet (AOP (left), offset, FALSE, FALSE)); + pic16_emitpcode (POC_MOVFW, pic16_popGet (AOP (right), offset)); + pic16_emitpcode (POC_ANDFW, pic16_popGet (AOP (left), offset)); + } + pic16_emitcode ("movwf", "%s", pic16_aopGet (AOP (result), offset, FALSE, FALSE)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offset)); + } + } + } + +release: + pic16_freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + pic16_freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + pic16_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; + resolvedIfx rIfx; + + FENTRY; + + pic16_aopOp ((left = IC_LEFT (ic)), ic, FALSE); + pic16_aopOp ((right = IC_RIGHT (ic)), ic, FALSE); + pic16_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 (pic16_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; + } + + DEBUGpic16_pic16_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) + pic16_emitpcode (POC_BSF, pic16_popGet (AOP (result), 0)); + //pic16_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 && pic16_sameRegs (AOP (result), AOP (left))) + goto release; + pic16_emitcode (";XXX mov", "c,%s %s,%d", AOP (left)->aopu.aop_dir, __FILE__, __LINE__); + } + } + else + { + if (AOP_TYPE (right) == AOP_CRY) + { + if (pic16_sameRegs (AOP (result), AOP (left))) + { + // c = bit | bit; + pic16_emitpcode (POC_BCF, pic16_popGet (AOP (result), 0)); + pic16_emitpcode (POC_BTFSC, pic16_popGet (AOP (right), 0)); + pic16_emitpcode (POC_BSF, pic16_popGet (AOP (result), 0)); + + } + else + { + if (AOP_TYPE (result) == AOP_ACC) + { + pic16_emitpcode (POC_MOVLW, pic16_popGetLit (0)); + pic16_emitpcode (POC_BTFSS, pic16_popGet (AOP (right), 0)); + pic16_emitpcode (POC_BTFSC, pic16_popGet (AOP (left), 0)); + pic16_emitpcode (POC_MOVLW, pic16_popGetLit (1)); + + } + else + { + + pic16_emitpcode (POC_BCF, pic16_popGet (AOP (result), 0)); + pic16_emitpcode (POC_BTFSS, pic16_popGet (AOP (right), 0)); + pic16_emitpcode (POC_BTFSC, pic16_popGet (AOP (left), 0)); + pic16_emitpcode (POC_BSF, pic16_popGet (AOP (result), 0)); + + } + } + } + else + { + // c = bit | val; + symbol *tlbl = newiTempLabel (NULL); + pic16_emitcode (";XXX ", " %s,%d", __FILE__, __LINE__); + + + pic16_emitpcode (POC_BCF, pic16_popGet (AOP (result), 0)); + if (AOP_TYPE (right) == AOP_ACC) + { + pic16_emitpcode (POC_IORLW, pic16_popGetLit (0)); + emitSKPNZ; + pic16_emitpcode (POC_BTFSC, pic16_popGet (AOP (left), 0)); + pic16_emitpcode (POC_BSF, pic16_popGet (AOP (result), 0)); + } + + + + if (!((AOP_TYPE (result) == AOP_CRY) && ifx)) + pic16_emitcode (";XXX setb", "c"); + pic16_emitcode (";XXX jb", "%s,%05d_DS_", AOP (left)->aopu.aop_dir, labelKey2num (tlbl->key)); + pic16_toBoolean (right); + pic16_emitcode (";XXX jnz", "%05d_DS_", labelKey2num (tlbl->key)); + if ((AOP_TYPE (result) == AOP_CRY) && ifx) + { + jmpTrueOrFalse (ifx, tlbl); + goto release; + } + else + { + CLRC; + pic16_emitcode ("", "%05d_DS_:", labelKey2num (tlbl->key)); + } + } + } + // bit = c + // val = c + if (size) + pic16_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 (IS_OP_VOLATILE (left)) + { + pic16_mov2w_volatile (AOP (left)); + } // if + if (lit) + { + if (rIfx.condition) + pic16_emitpcode (POC_GOTO, pic16_popGetLabel (rIfx.lbl->key)); /* to false */ + ifx->generated = 1; + } + else + wassert (0); + + goto release; + } + + /* if left is same as result */ + if (pic16_sameRegs (AOP (result), AOP (left))) + { + int know_W = -1; + for (; size--; offset++, lit >>= 8) + { + if (AOP_TYPE (right) == AOP_LIT) + { + if (((lit & 0xff) == 0) && !IS_OP_VOLATILE (left)) + { + /* or'ing with 0 has no effect */ + continue; + } + else + { + int p = pic16_my_powof2 (lit & 0xff); + if (p >= 0) + { + /* only one bit is set in the literal, so use a bsf instruction */ + pic16_emitpcode (POC_BSF, + pic16_newpCodeOpBit (pic16_aopGet (AOP (left), offset, FALSE, FALSE), p, 0, + PO_GPR_REGISTER)); + } + else + { + if (AOP_TYPE (left) == AOP_ACC) + { + pic16_emitpcode (POC_IORLW, pic16_popGetLit (lit & 0xff)); + know_W = -1; + } + else + { + if (know_W != (lit & 0xff)) + { + pic16_emitpcode (POC_MOVLW, pic16_popGetLit (lit & 0xff)); + } + + know_W = lit & 0xff; + pic16_emitpcode (POC_IORWF, pic16_popGet (AOP(left), offset)); + } + } + + } + } + else + { + if (AOP_TYPE (left) == AOP_ACC) + { + pic16_emitpcode (POC_IORFW, pic16_popGet (AOP (right), offset)); + } + else + { + pic16_emitpcode (POC_MOVFW, pic16_popGet (AOP (right), offset)); + pic16_emitpcode (POC_IORWF, pic16_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)); + pic16_emitcode (";XXX ", " %s,%d", __FILE__, __LINE__); + + + if (size) + pic16_emitcode (";XXX setb", "c"); + while (sizer--) + { + MOVA (pic16_aopGet (AOP (right), offset, FALSE, FALSE)); + pic16_emitcode (";XXX orl", "a,%s", pic16_aopGet (AOP (left), offset, FALSE, FALSE)); + pic16_emitcode (";XXX jnz", "%05d_DS_", labelKey2num (tlbl->key)); + offset++; + } + if (size) + { + CLRC; + pic16_emitcode ("", "%05d_DS_:", labelKey2num (tlbl->key)); + pic16_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: + pic16_emitpcode (POC_MOVFW, pic16_popGet (AOP (left), offset)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offset)); + break; + default: + { + if (AOP_TYPE (left) == AOP_ACC) + { + pic16_emitcode ("iorlw", "0x%02x", t); + pic16_emitcode ("movwf", "%s", pic16_aopGet (AOP (result), offset, FALSE, FALSE)); + pic16_emitpcode (POC_IORLW, pic16_popGetLit (t)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offset)); + } + else + { + pic16_emitcode("movlw", "0x%02x", t); + pic16_emitcode("iorwf", "%s", pic16_aopGet (AOP (left), offset, FALSE, FALSE)); + pic16_emitpcode(POC_MOVLW, pic16_popGetLit (t)); + pic16_emitpcode(POC_IORFW, pic16_popGet (AOP (left), offset)); + + if (AOP_TYPE (result) != AOP_ACC) + { + pic16_emitcode ("movwf", "%s", pic16_aopGet (AOP (result), offset, FALSE, FALSE)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offset)); + } + else + { + DEBUGpic16_emitcode ("; ***", "ignore MOVWF\tWREG", __FUNCTION__, __LINE__); + } + } + } + } + continue; + } + + // faster than result <- left, anl result,right + // and better if result is SFR + if (AOP_TYPE (left) == AOP_ACC) + { + pic16_emitpcode (POC_IORWF, pic16_popGet (AOP (right), offset)); + } + else + { + pic16_emitpcode (POC_MOVFW, pic16_popGet (AOP (right), offset)); + pic16_emitpcode (POC_IORFW, pic16_popGet (AOP (left), offset)); + } + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offset)); + } + } + +release: + pic16_freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + pic16_freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + pic16_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; + resolvedIfx rIfx; + + FENTRY; + + pic16_aopOp ((left = IC_LEFT (ic)), ic, FALSE); + pic16_aopOp ((right = IC_RIGHT (ic)), ic, FALSE); + pic16_aopOp ((result = IC_RESULT (ic)), ic, TRUE); + + resolveIfx (&rIfx, ifx); + + /* 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 (pic16_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) + { + pic16_emitpcode (POC_BSF, pic16_popGet (AOP (result), offset)); + } + else if (ifx) + continueIfTrue (ifx); + goto release; + } + pic16_emitcode ("setb", "c"); + } + else + { + // lit == (0 or 1) + if (lit == 0) + { + // lit == 0, result = left + if (size && pic16_sameRegs (AOP (result), AOP (left))) + goto release; + pic16_emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir); + } + else + { + // lit == 1, result = not(left) + if (size && pic16_sameRegs (AOP (result), AOP (left))) + { + pic16_emitpcode (POC_MOVLW, pic16_popGet (AOP (result), offset)); + pic16_emitpcode (POC_XORWF, pic16_popGet (AOP (result), offset)); + pic16_emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir); + goto release; + } + else + { + pic16_emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir); + pic16_emitcode ("cpl", "c"); + } + } + } + } + else + { + // right != literal + symbol *tlbl = newiTempLabel (NULL); + if (AOP_TYPE (right) == AOP_CRY) + { + // c = bit ^ bit; + pic16_emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir); + } + else + { + int sizer = AOP_SIZE (right); + // c = bit ^ val + // if val>>1 != 0, result = 1 + pic16_emitcode ("setb", "c"); + while (sizer) + { + MOVA (pic16_aopGet (AOP (right), sizer - 1, FALSE, FALSE)); + if (sizer == 1) + // test the msb of the lsb + pic16_emitcode ("anl", "a,#0xfe"); + pic16_emitcode ("jnz", "%05d_DS_", labelKey2num (tlbl->key)); + sizer--; + } + // val = (0,1) + pic16_emitcode ("rrc", "a"); + } + pic16_emitcode ("jnb", "%s,%05d_DS_", AOP (left)->aopu.aop_dir, labelKey2num (tlbl->key)); + pic16_emitcode ("cpl", "c"); + pic16_emitcode ("", "%05d_DS_:", labelKey2num (tlbl->key)); + } + // bit = c + // val = c + if (size) + pic16_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)) + { + symbol *tlbl = newiTempLabel (NULL); + int sizel; + + if (size) + emitSETC; + + for (sizel = AOP_SIZE (left); sizel--; ++offset, lit >>= 8) + { + unsigned char bytelit = lit & 0xFF; + + switch (bytelit) + { + case 0xff: + pic16_emitpcode (POC_COMFW, pic16_popGet (AOP (left), offset)); + break; + + case 0x00: + pic16_emitpcode (POC_MOVFW, pic16_popGet (AOP (left), offset)); + break; + + default: + pic16_emitpcode (POC_MOVLW, pic16_popGetLit (bytelit)); + pic16_emitpcode (POC_XORFW, pic16_popGet (AOP (left), offset)); + break; + } + if (sizel) + { + if (rIfx.condition) + { + /* rIfx.lbl might be far away... */ + emitSKPZ; + pic16_emitpcode (POC_GOTO, pic16_popGetLabel (rIfx.lbl->key)); /* to false */ + } + else + { + pic16_emitpcode (POC_BNZ, pic16_popGetLabel (tlbl->key)); /* to true */ + } + } + else + { + /* last non null byte */ + if (rIfx.condition) + emitSKPZ; + else + emitSKPNZ; + } + } + + // bit = left ^ literal + if (size) + { + emitCLRC; + pic16_emitpLabel (tlbl->key); + } + // if (left ^ literal) + else + { + if (ifx) + { + pic16_emitpcode (POC_GOTO, pic16_popGetLabel (rIfx.lbl->key)); + ifx->generated = 1; + } + pic16_emitpLabel (tlbl->key); + goto release; + } + + pic16_outBitC (result); + goto release; + } + + if (pic16_sameRegs (AOP (result), AOP (left))) + { + /* if left is same as result */ + int know_W = -1; + + for (; size--; offset++) + { + if (AOP_TYPE (right) == AOP_LIT) + { + int t = (lit >> (offset * 8)) & 0x0FFL; + if (t == 0x00L) + continue; + else + { + int p = pic16_my_powof2 (t); + + if (p >= 0) + { + /* Only one bit is toggle in the literal, so use a btg instruction. */ + pic16_emitpcode (POC_BTG, + pic16_newpCodeOpBit (pic16_aopGet (AOP (left), offset, FALSE, FALSE), p, 0, PO_GPR_REGISTER)); + } + else + { + if (AOP_TYPE (left) == AOP_ACC) + { + pic16_emitcode ("xorlw", "0x%02x", t); + pic16_emitpcode (POC_XORLW, pic16_popGetLit (t)); + know_W = -1; + } + else + { + if (know_W != t) + { + pic16_emitcode ("movlw", "0x%02x", t); + pic16_emitpcode (POC_MOVLW, pic16_popGetLit (t)); + } + + know_W = t; + } + + pic16_emitcode ("xorwf", "%s", pic16_aopGet (AOP (left), offset, FALSE, FALSE)); + pic16_emitpcode (POC_XORWF, pic16_popGet (AOP (left), offset)); + } + } + } + else + { + if (AOP_TYPE (left) == AOP_ACC) + pic16_emitcode ("xrl", "a,%s", pic16_aopGet (AOP (right), offset, FALSE, FALSE)); + else + { + pic16_emitpcode (POC_MOVFW, pic16_popGet (AOP (right), offset)); + pic16_emitpcode (POC_XORWF, pic16_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) + pic16_emitcode ("setb", "c"); + while (sizer--) + { + if ((AOP_TYPE (right) == AOP_LIT) && (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)) + { + MOVA (pic16_aopGet (AOP (left), offset, FALSE, FALSE)); + } + else + { + MOVA (pic16_aopGet (AOP (right), offset, FALSE, FALSE)); + pic16_emitcode ("xrl", "a,%s", pic16_aopGet (AOP (left), offset, FALSE, FALSE)); + } + pic16_emitcode ("jnz", "%05d_DS_", labelKey2num (tlbl->key)); + offset++; + } + if (size) + { + CLRC; + pic16_emitcode ("", "%05d_DS_:", labelKey2num (tlbl->key)); + pic16_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: + pic16_emitpcode (POC_MOVFW, pic16_popGet (AOP (left), offset)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offset)); + break; + + case 0xff: + pic16_emitpcode (POC_COMFW, pic16_popGet (AOP (left), offset)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offset)); + break; + + default: + { + if (AOP_TYPE (left) == AOP_ACC) + { + pic16_emitcode ("xorlw", "0x%02x", t); + pic16_emitpcode (POC_XORLW, pic16_popGetLit (t)); + } + else + { + pic16_emitcode ("movlw", "0x%02x", t); + pic16_emitcode ("xorwf", "%s", pic16_aopGet (AOP (left), offset, FALSE, FALSE)); + pic16_emitpcode (POC_MOVLW, pic16_popGetLit (t)); + pic16_emitpcode (POC_XORFW, pic16_popGet (AOP (left), offset)); + } + + pic16_emitcode ("movwf", "%s", pic16_aopGet (AOP (result), offset, FALSE, FALSE)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offset)); + } + } + continue; + } + + // faster than result <- left, anl result,right + // and better if result is SFR + if (AOP_TYPE (left) == AOP_ACC) + { + pic16_emitpcode (POC_XORFW, pic16_popGet (AOP (right), offset)); + } + else + { + pic16_emitpcode (POC_MOVFW, pic16_popGet (AOP (right), offset)); + pic16_emitpcode (POC_XORFW, pic16_popGet (AOP (left), offset)); + } + if (AOP_TYPE (result) != AOP_ACC) + { + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offset)); + } + else + { + DEBUGpic16_emitcode ("; ***", "ignore MOVWF\tWREG", __FUNCTION__, __LINE__); + } + } + } + } + +release: + pic16_freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + pic16_freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + pic16_freeAsmop (result, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genInline - write the inline code out */ +/*-----------------------------------------------------------------*/ +static void +pic16_genInline (iCode * ic) +{ + char *buffer, *bp, *bp1; + bool inComment = FALSE; + + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + + genLine.lineElement.isInline += (!options.asmpeep); + + buffer = bp = bp1 = Safe_strdup (IC_INLINE (ic)); + + while ((bp1 = strstr (bp, "\\n"))) + { + *bp1++ = '\n'; + *bp1++ = ' '; + bp = bp1; + } + bp = bp1 = buffer; + +#if 0 + /* This is an experimental code for #pragma inline + and is temporarily disabled for 2.5.0 release */ + if (asmInlineMap) + { + symbol *sym; + char *s; + char *cbuf; + int cblen; + + cbuf = Safe_strdup (buffer); + cblen = strlen (buffer) + 1; + memset (cbuf, 0, cblen); + + bp = buffer; + bp1 = cbuf; + while (*bp) + { + if (*bp != '%') + *bp1++ = *bp++; + else + { + int i; + + bp++; + i = *bp - '0'; + if (i > elementsInSet (asmInlineMap)) + break; + + bp++; + s = indexSet (asmInlineMap, i); + DEBUGpc ("searching symbol s = `%s'", s); + sym = findSym (SymbolTab, NULL, s); + + if (sym->reqv) + { + strcat (bp1, sym->reqv->operand.symOperand->regs[0]->name); + } + else + { + strcat (bp1, sym->rname); + } + + while (*bp1) + bp1++; + } + + if (strlen (bp1) > cblen - 16) + { + int i = strlen (cbuf); + cblen += 50; + cbuf = realloc (cbuf, cblen); + memset (cbuf + i, 0, 50); + bp1 = cbuf + i; + } + } + + free (buffer); + buffer = Safe_strdup (cbuf); + free (cbuf); + + bp = bp1 = buffer; + } +#endif /* 0 */ + + /* emit each line as a code */ + while (*bp) + { + switch (*bp) + { + case ';': + inComment = TRUE; + ++bp; + break; + + case '\x87': + case '\n': + inComment = FALSE; + *bp++ = '\0'; + if (*bp1) + pic16_addpCode2pBlock (pb, pic16_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 */ + pic16_addpCode2pBlock (pb, pic16_newpCodeAsmDir (NULL, bp1)); // inline directly, no process + bp1 = bp; + } + else + ++bp; + break; + } + } + + if ((bp1 != bp) && *bp1) + pic16_addpCode2pBlock (pb, pic16_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, same; + + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + + /* rotate right with carry */ + left = IC_LEFT (ic); + result = IC_RESULT (ic); + pic16_aopOp (left, ic, FALSE); + pic16_aopOp (result, ic, TRUE); + + DEBUGpic16_pic16_AopType (__LINE__, left, NULL, result); + + same = pic16_sameRegs (AOP (result), AOP (left)); + + size = AOP_SIZE (result); + + DEBUGpic16_emitcode ("; ***", "%s %d size:%d same:%d", __FUNCTION__, __LINE__, size, same); + + /* get the lsb and put it into the carry */ + pic16_emitpcode (POC_RRCFW, pic16_popGet (AOP (left), 0)); + + while (size--) + { + + if (same) + { + pic16_emitpcode (POC_RRCF, pic16_popGet (AOP (left), size)); + } + else + { + pic16_emitpcode (POC_RRCFW, pic16_popGet (AOP (left), size)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), size)); + } + } + + pic16_freeAsmop (left, NULL, ic, TRUE); + pic16_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; + + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + /* rotate right with carry */ + left = IC_LEFT (ic); + result = IC_RESULT (ic); + pic16_aopOp (left, ic, FALSE); + pic16_aopOp (result, ic, TRUE); + + DEBUGpic16_pic16_AopType (__LINE__, left, NULL, result); + + same = pic16_sameRegs (AOP (result), AOP (left)); + + /* move it to the result */ + size = AOP_SIZE (result); + + /* get the msb and put it into the carry */ + pic16_emitpcode (POC_RLCFW, pic16_popGet (AOP (left), size - 1)); + + offset = 0; + + while (size--) + { + + if (same) + { + pic16_emitpcode (POC_RLCF, pic16_popGet (AOP (left), offset)); + } + else + { + pic16_emitpcode (POC_RLCFW, pic16_popGet (AOP (left), offset)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offset)); + } + + offset++; + } + + + pic16_freeAsmop (left, NULL, ic, TRUE); + pic16_freeAsmop (result, NULL, ic, TRUE); +} + + +/* gpasm can get the highest order bit with HIGH/UPPER + * so the following probably is not needed -- VR */ + +/*-----------------------------------------------------------------*/ +/* genGetHbit - generates code get highest order bit */ +/*-----------------------------------------------------------------*/ +static void +genGetHbit (iCode * ic) +{ + operand *left, *result; + left = IC_LEFT (ic); + result = IC_RESULT (ic); + pic16_aopOp (left, ic, FALSE); + pic16_aopOp (result, ic, FALSE); + + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + /* get the highest order byte into a */ + MOVA (pic16_aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE, FALSE)); + if (AOP_TYPE (result) == AOP_CRY) + { + pic16_emitcode ("rlc", "a"); + pic16_outBitC (result); + } + else + { + pic16_emitcode ("rl", "a"); + pic16_emitcode ("anl", "a,#0x01"); + pic16_outAcc (result); + } + + + pic16_freeAsmop (left, NULL, ic, TRUE); + pic16_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); + + pic16_aopOp (left, ic, FALSE); + pic16_aopOp (right, ic, FALSE); + pic16_aopOp (result, ic, TRUE); + + shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit); + offset = shCount / 8; + shCount %= 8; + + /* load and mask the source byte */ + pic16_mov2w (AOP (left), offset); + pic16_emitpcode (POC_ANDLW, pic16_popGetLit (1 << shCount)); + + /* move selected bit to bit 0 */ + switch (shCount) + { + case 0: + /* nothing more to do */ + break; + case 1: + /* shift bit 1 into bit 0 */ + pic16_emitpcode (POC_RRNCFW, pic16_popCopyReg (&pic16_pc_wreg)); + break; + case 4: + /* shift bit 4 into bit 0 */ + pic16_emitpcode (POC_SWAPFW, pic16_popCopyReg (&pic16_pc_wreg)); + break; + case 7: + /* shift bit 7 into bit 0 */ + pic16_emitpcode (POC_RLNCFW, pic16_popCopyReg (&pic16_pc_wreg)); + break; + default: + /* keep W==0, force W=0x01 otherwise */ + emitSKPZ; + pic16_emitpcode (POC_MOVLW, pic16_popGetLit (1)); + break; + } // switch + + /* write result */ + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), 0)); + + for (i = 1; i < AOP_SIZE (result); ++i) + { + pic16_emitpcode (POC_CLRF, pic16_popGet (AOP (result), i)); + } // for + + pic16_freeAsmop (left, NULL, ic, TRUE); + pic16_freeAsmop (right, NULL, ic, TRUE); + pic16_freeAsmop (result, NULL, ic, TRUE); +} + +#if 0 +/*-----------------------------------------------------------------*/ +/* AccRol - rotate left accumulator by known count */ +/*-----------------------------------------------------------------*/ +static void +AccRol (int shCount) +{ + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + shCount &= 0x0007; // shCount : 0..7 + switch (shCount) + { + case 0: + break; + case 1: + pic16_emitcode ("rl", "a"); + break; + case 2: + pic16_emitcode ("rl", "a"); + pic16_emitcode ("rl", "a"); + break; + case 3: + pic16_emitcode ("swap", "a"); + pic16_emitcode ("rr", "a"); + break; + case 4: + pic16_emitcode ("swap", "a"); + break; + case 5: + pic16_emitcode ("swap", "a"); + pic16_emitcode ("rl", "a"); + break; + case 6: + pic16_emitcode ("rr", "a"); + pic16_emitcode ("rr", "a"); + break; + case 7: + pic16_emitcode ("rr", "a"); + break; + } +} +#endif + +/*-----------------------------------------------------------------*/ +/* AccLsh - left shift accumulator by known count */ +/*-----------------------------------------------------------------*/ +static void +AccLsh (int shCount, int doMask) +{ + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + switch (shCount) + { + case 0: + return; + break; + case 1: + pic16_emitpcode (POC_RLNCFW, pic16_popCopyReg (&pic16_pc_wreg)); + break; + case 2: + pic16_emitpcode (POC_RLNCFW, pic16_popCopyReg (&pic16_pc_wreg)); + pic16_emitpcode (POC_RLNCFW, pic16_popCopyReg (&pic16_pc_wreg)); + break; + case 3: + pic16_emitpcode (POC_SWAPFW, pic16_popCopyReg (&pic16_pc_wreg)); + pic16_emitpcode (POC_RRNCFW, pic16_popCopyReg (&pic16_pc_wreg)); + break; + case 4: + pic16_emitpcode (POC_SWAPFW, pic16_popCopyReg (&pic16_pc_wreg)); + break; + case 5: + pic16_emitpcode (POC_SWAPFW, pic16_popCopyReg (&pic16_pc_wreg)); + pic16_emitpcode (POC_RLNCFW, pic16_popCopyReg (&pic16_pc_wreg)); + break; + case 6: + pic16_emitpcode (POC_RRNCFW, pic16_popCopyReg (&pic16_pc_wreg)); + pic16_emitpcode (POC_RRNCFW, pic16_popCopyReg (&pic16_pc_wreg)); + break; + case 7: + pic16_emitpcode (POC_RRNCFW, pic16_popCopyReg (&pic16_pc_wreg)); + break; + } + if (doMask) + { + /* no masking is required in genPackBits */ + pic16_emitpcode (POC_ANDLW, pic16_popGetLit (SLMask[shCount])); + } +} + +/*-----------------------------------------------------------------*/ +/* AccRsh - right shift accumulator by known count */ +/*-----------------------------------------------------------------*/ +static void +AccRsh (int shCount, int andmask) +{ + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + assert ((shCount >= 0) && (shCount <= 8)); + switch (shCount) + { + case 0: + return; + break; + case 1: + pic16_emitpcode (POC_RRNCFW, pic16_popCopyReg (&pic16_pc_wreg)); + break; + case 2: + pic16_emitpcode (POC_RRNCFW, pic16_popCopyReg (&pic16_pc_wreg)); + pic16_emitpcode (POC_RRNCFW, pic16_popCopyReg (&pic16_pc_wreg)); + break; + case 3: + pic16_emitpcode (POC_SWAPFW, pic16_popCopyReg (&pic16_pc_wreg)); + pic16_emitpcode (POC_RLNCFW, pic16_popCopyReg (&pic16_pc_wreg)); + break; + case 4: + pic16_emitpcode (POC_SWAPFW, pic16_popCopyReg (&pic16_pc_wreg)); + break; + case 5: + pic16_emitpcode (POC_SWAPFW, pic16_popCopyReg (&pic16_pc_wreg)); + pic16_emitpcode (POC_RRNCFW, pic16_popCopyReg (&pic16_pc_wreg)); + break; + case 6: + pic16_emitpcode (POC_RLNCFW, pic16_popCopyReg (&pic16_pc_wreg)); + pic16_emitpcode (POC_RLNCFW, pic16_popCopyReg (&pic16_pc_wreg)); + break; + case 7: + pic16_emitpcode (POC_RLNCFW, pic16_popCopyReg (&pic16_pc_wreg)); + break; + default: + // Rotating by 8 is a NOP. + break; + } + + if (andmask) + pic16_emitpcode (POC_ANDLW, pic16_popGetLit (SRMask[shCount])); + else + DEBUGpic16_emitcode ("; ***", "%s omitting masking the result", __FUNCTION__); +} + +/*-----------------------------------------------------------------*/ +/* shiftR1Left2Result - shift right one byte from left to result */ +/*-----------------------------------------------------------------*/ +static void +shiftR1Left2ResultSigned (operand * left, int offl, operand * result, int offr, int shCount) +{ + int same; + + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + assert ((shCount >= 0) && (shCount <= 8)); + + same = ((left == result) || (AOP (left) == AOP (result))) && (offl == offr); + + /* Do NOT use result for intermediate results, it might be an SFR!. */ + switch (shCount) + { + case 0: + if (!same) + { + pic16_emitpcode (POC_MOVFW, pic16_popGet (AOP (left), offl)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr)); + } + break; + + case 1: + pic16_emitpcode (POC_RLCFW, pic16_popGet (AOP (left), offl)); + if (same) + pic16_emitpcode (POC_RRCF, pic16_popGet (AOP (result), offr)); + else + { + pic16_emitpcode (POC_RRCFW, pic16_popGet (AOP (left), offl)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr)); + } + break; + + case 2: + pic16_emitpcode (POC_RRNCFW, pic16_popGet (AOP (left), offl)); + pic16_emitpcode (POC_RRNCFW, pic16_popCopyReg (&pic16_pc_wreg)); + pic16_emitpcode (POC_ANDLW, pic16_popGetLit (0x3f)); // keep sign bit in W<5> + pic16_emitpcode (POC_BTFSC, pic16_popCopyGPR2Bit (PCOP (&pic16_pc_wreg), 5)); + pic16_emitpcode (POC_IORLW, pic16_popGetLit (0xc0)); // sign-extend + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr)); + break; + + case 3: + pic16_emitpcode (POC_SWAPFW, pic16_popGet (AOP (left), offl)); + pic16_emitpcode (POC_RLNCFW, pic16_popCopyReg (&pic16_pc_wreg)); + pic16_emitpcode (POC_ANDLW, pic16_popGetLit (0x1f)); // keep sign in W<4> + pic16_emitpcode (POC_BTFSC, pic16_popCopyGPR2Bit (PCOP (&pic16_pc_wreg), 4)); + pic16_emitpcode (POC_IORLW, pic16_popGetLit (0xe0)); // sign-extend + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr)); + break; + + case 4: + pic16_emitpcode (POC_SWAPFW, pic16_popGet (AOP (left), offl)); + pic16_emitpcode (POC_ANDLW, pic16_popGetLit (0x0f)); // keep sign in W<3> + pic16_emitpcode (POC_BTFSC, pic16_popCopyGPR2Bit (PCOP (&pic16_pc_wreg), 3)); + pic16_emitpcode (POC_IORLW, pic16_popGetLit (0xf0)); // sign-extend + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr)); + break; + + case 5: + pic16_emitpcode (POC_SWAPFW, pic16_popGet (AOP (left), offl)); + pic16_emitpcode (POC_RRNCFW, pic16_popCopyReg (&pic16_pc_wreg)); + pic16_emitpcode (POC_ANDLW, pic16_popGetLit (0x07)); // keep sign in W<2> + pic16_emitpcode (POC_BTFSC, pic16_popCopyGPR2Bit (PCOP (&pic16_pc_wreg), 2)); + pic16_emitpcode (POC_IORLW, pic16_popGetLit (0xf8)); // sign-extend + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr)); + break; + + case 6: + pic16_emitpcode (POC_RLNCFW, pic16_popGet (AOP (left), offl)); + pic16_emitpcode (POC_RLNCFW, pic16_popCopyReg (&pic16_pc_wreg)); + pic16_emitpcode (POC_ANDLW, pic16_popGetLit (0x03)); // keep sign bit in W<1> + pic16_emitpcode (POC_BTFSC, pic16_popCopyGPR2Bit (PCOP (&pic16_pc_wreg), 1)); + pic16_emitpcode (POC_IORLW, pic16_popGetLit (0xfc)); // sign-extend + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr)); + break; + + case 7: + pic16_emitpcode (POC_MOVLW, pic16_popGetLit (0x00)); + pic16_emitpcode (POC_BTFSC, pic16_popCopyGPR2Bit (pic16_popGet (AOP (left), offl), 7)); + pic16_emitpcode (POC_MOVLW, pic16_popGetLit (0xff)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr)); + break; + + default: + pic16_emitpcode (POC_CLRF, pic16_popGet (AOP (result), offr)); + break; + } +} + +/*-----------------------------------------------------------------*/ +/* shiftR1Left2Result - shift right one byte from left to result */ +/*-----------------------------------------------------------------*/ +static void +shiftR1Left2Result (operand * left, int offl, operand * result, int offr, int shCount, int sign) +{ + int same; + + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + assert ((shCount >= 0) && (shCount <= 8)); + + same = ((left == result) || (AOP (left) == AOP (result))) && (offl == offr); + + /* Copy the msb into the carry if signed. */ + if (sign) + { + shiftR1Left2ResultSigned (left, offl, result, offr, shCount); + return; + } + + /* Do NOT use result for intermediate results, it might be an SFR!. */ + switch (shCount) + { + case 0: + if (!same) + { + pic16_emitpcode (POC_MOVFW, pic16_popGet (AOP (left), offl)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr)); + } + break; + + case 1: + if (same) + { + emitCLRC; + pic16_emitpcode (POC_RRCF, pic16_popGet (AOP (result), offr)); + } + else + { + pic16_emitpcode (POC_RRNCFW, pic16_popGet (AOP (left), offl)); + pic16_emitpcode (POC_ANDLW, pic16_popGetLit (0x7f)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr)); + } + break; + + case 2: + pic16_emitpcode (POC_RRNCFW, pic16_popGet (AOP (left), offl)); + pic16_emitpcode (POC_RRNCFW, pic16_popCopyReg (&pic16_pc_wreg)); + pic16_emitpcode (POC_ANDLW, pic16_popGetLit (0x3f)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr)); + break; + + case 3: + pic16_emitpcode (POC_SWAPFW, pic16_popGet (AOP (left), offl)); + pic16_emitpcode (POC_RLNCFW, pic16_popCopyReg (&pic16_pc_wreg)); + pic16_emitpcode (POC_ANDLW, pic16_popGetLit (0x1f)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr)); + break; + + case 4: + pic16_emitpcode (POC_SWAPFW, pic16_popGet (AOP (left), offl)); + pic16_emitpcode (POC_ANDLW, pic16_popGetLit (0x0f)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr)); + break; + + case 5: + pic16_emitpcode (POC_SWAPFW, pic16_popGet (AOP (left), offl)); + pic16_emitpcode (POC_RRNCFW, pic16_popCopyReg (&pic16_pc_wreg)); + pic16_emitpcode (POC_ANDLW, pic16_popGetLit (0x07)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr)); + break; + + case 6: + pic16_emitpcode (POC_RLNCFW, pic16_popGet (AOP (left), offl)); + pic16_emitpcode (POC_RLNCFW, pic16_popCopyReg (&pic16_pc_wreg)); + pic16_emitpcode (POC_ANDLW, pic16_popGetLit (0x03)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr)); + break; + + case 7: + pic16_emitpcode (POC_RLNCFW, pic16_popGet (AOP (left), offl)); + pic16_emitpcode (POC_ANDLW, pic16_popGetLit (0x01)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr)); + break; + + default: + pic16_emitpcode (POC_CLRF, pic16_popGet (AOP (result), offr)); + break; + } +} + +/*-----------------------------------------------------------------*/ +/* shiftL1Left2Result - shift left one byte from left to result */ +/*-----------------------------------------------------------------*/ +static void +shiftL1Left2Result (operand * left, int offl, operand * result, int offr, int shCount) +{ + int same; + + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + assert ((shCount >= 0) && (shCount <= 8)); + + same = ((left == result) || (AOP (left) == AOP (result))) && (offl == offr); + + /* Do NOT use result for intermediate results, it might be an SFR!. */ + switch (shCount) + { + case 0: + if (!same) + { + pic16_emitpcode (POC_MOVFW, pic16_popGet (AOP (left), offl)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr)); + } + break; + + case 1: + if (same) + { + emitCLRC; + pic16_emitpcode (POC_RLCF, pic16_popGet (AOP (left), offl)); + } + else + { + pic16_emitpcode (POC_RLNCFW, pic16_popGet (AOP (left), offl)); + pic16_emitpcode (POC_ANDLW, pic16_popGetLit (0xfe)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr)); + } + break; + + case 2: + { + if (same) + { + if (AOP_TYPE (left) == AOP_ACC) + { + /* Reduces the number of instructions. */ + pic16_emitpcode(POC_ADDFW, pic16_popGet (AOP (left), offl)); + pic16_emitpcode(POC_ADDFW, pic16_popGet (AOP (left), offl)); + } + else + { + emitCLRC; + pic16_emitpcode (POC_RLCF, pic16_popGet (AOP (left), offl)); + emitCLRC; + pic16_emitpcode (POC_RLCF, pic16_popGet (AOP (left), offl)); + } + } + else + { + pic16_emitpcode (POC_RLNCFW, pic16_popGet (AOP (left), offl)); + pic16_emitpcode (POC_RLNCFW, pic16_popCopyReg (&pic16_pc_wreg)); + pic16_emitpcode (POC_ANDLW, pic16_popGetLit (0xfc)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr)); + } + + break; + } + + case 3: + if (same && AOP_TYPE(left) == AOP_ACC) + { + /* Reduces the number of instructions. */ + pic16_emitpcode (POC_ADDFW, pic16_popGet (AOP (left), offl)); + pic16_emitpcode (POC_ADDFW, pic16_popGet (AOP (left), offl)); + pic16_emitpcode (POC_ADDFW, pic16_popGet (AOP (left), offl)); + } + else + { + pic16_emitpcode (POC_SWAPFW, pic16_popGet (AOP (left), offl)); + pic16_emitpcode (POC_RRNCFW, pic16_popCopyReg (&pic16_pc_wreg)); + pic16_emitpcode (POC_ANDLW, pic16_popGetLit (0xf8)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr)); + } + break; + + case 4: + pic16_emitpcode (POC_SWAPFW, pic16_popGet (AOP (left), offl)); + pic16_emitpcode (POC_ANDLW, pic16_popGetLit (0xf0)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr)); + break; + + case 5: + pic16_emitpcode (POC_SWAPFW, pic16_popGet (AOP (left), offl)); + pic16_emitpcode (POC_RLNCFW, pic16_popCopyReg (&pic16_pc_wreg)); + pic16_emitpcode (POC_ANDLW, pic16_popGetLit (0xe0)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr)); + break; + + case 6: + pic16_emitpcode (POC_RRNCFW, pic16_popGet (AOP (left), offl)); + pic16_emitpcode (POC_RRNCFW, pic16_popCopyReg (&pic16_pc_wreg)); + pic16_emitpcode (POC_ANDLW, pic16_popGetLit (0xc0)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr)); + break; + + case 7: + pic16_emitpcode (POC_RRNCFW, pic16_popGet (AOP (left), offl)); + pic16_emitpcode (POC_ANDLW, pic16_popGetLit (0x80)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr)); + break; + + default: + pic16_emitpcode (POC_CLRF, pic16_popGet (AOP (result), offr)); + break; + } +} + +/*-----------------------------------------------------------------*/ +/* movLeft2Result - move byte from left to result */ +/*-----------------------------------------------------------------*/ +static void +movLeft2Result (operand * left, int offl, operand * result, int offr) +{ + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + if (!pic16_sameRegs (AOP (left), AOP (result)) || (offl != offr)) + { + pic16_emitpcode (POC_MOVFW, pic16_popGet (AOP (left), offl)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr)); + } +} + +/*-----------------------------------------------------------------*/ +/* shiftL2Left2Result - shift left two bytes from left to result */ +/*-----------------------------------------------------------------*/ +static void +shiftL2Left2Result (operand * left, int offl, operand * result, int offr, int shCount) +{ + int same = pic16_sameRegs (AOP (result), AOP (left)); + int i; + + DEBUGpic16_emitcode ("; ***", "%s %d shCount:%d same:%d offl:%d offr:%d", __FUNCTION__, __LINE__, shCount, same, offl, offr); + + if (same && (offl != offr)) // shift bytes + { + if (offr > offl) + { + for (i = 1; i > -1; i--) + { + pic16_emitpcode (POC_MOVFW, pic16_popGet (AOP (result), offl + i)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr + i)); + } + } + else // just treat as different later on + { + same = 0; + } + } + + if (same) + { + switch (shCount) + { + case 0: + break; + case 1: + case 2: + case 3: + + pic16_emitpcode (POC_MOVFW, pic16_popGet (AOP (result), offr)); + pic16_emitpcode (POC_ADDWF, pic16_popGet (AOP (result), offr)); + pic16_emitpcode (POC_RLCF, pic16_popGet (AOP (result), offr + MSB16)); + + while (--shCount) + { + emitCLRC; + pic16_emitpcode (POC_RLCF, pic16_popGet (AOP (result), offr)); + pic16_emitpcode (POC_RLCF, pic16_popGet (AOP (result), offr + MSB16)); + } + + break; + case 4: + case 5: + pic16_emitpcode (POC_MOVLW, pic16_popGetLit (0x0f)); + pic16_emitpcode (POC_ANDWF, pic16_popGet (AOP (result), offr + MSB16)); + pic16_emitpcode (POC_SWAPF, pic16_popGet (AOP (result), offr + MSB16)); + pic16_emitpcode (POC_SWAPF, pic16_popGet (AOP (result), offr)); + pic16_emitpcode (POC_ANDFW, pic16_popGet (AOP (result), offr)); + pic16_emitpcode (POC_XORWF, pic16_popGet (AOP (result), offr)); + pic16_emitpcode (POC_ADDWF, pic16_popGet (AOP (result), offr + MSB16)); + if (shCount >= 5) + { + pic16_emitpcode (POC_RLCF, pic16_popGet (AOP (result), offr)); + pic16_emitpcode (POC_RLCF, pic16_popGet (AOP (result), offr + MSB16)); + } + break; + case 6: + pic16_emitpcode (POC_RRCF, pic16_popGet (AOP (result), offr + MSB16)); + pic16_emitpcode (POC_RRCF, pic16_popGet (AOP (result), offr)); + pic16_emitpcode (POC_RRCF, pic16_popGet (AOP (result), offr + MSB16)); + pic16_emitpcode (POC_RRCF, pic16_popGet (AOP (result), offr)); + pic16_emitpcode (POC_RRCFW, pic16_popGet (AOP (result), offr + MSB16)); + pic16_emitpcode (POC_ANDLW, pic16_popGetLit (0xc0)); + pic16_emitpcode (POC_XORFW, pic16_popGet (AOP (result), offr)); + pic16_emitpcode (POC_XORWF, pic16_popGet (AOP (result), offr)); + pic16_emitpcode (POC_XORFW, pic16_popGet (AOP (result), offr)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr + MSB16)); + break; + case 7: + pic16_emitpcode (POC_RRCFW, pic16_popGet (AOP (result), offr + MSB16)); + pic16_emitpcode (POC_RRCFW, pic16_popGet (AOP (result), offr)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr + MSB16)); + pic16_emitpcode (POC_CLRF, pic16_popGet (AOP (result), offr)); + pic16_emitpcode (POC_RRCF, pic16_popGet (AOP (result), offr)); + } + + } + else + { + switch (shCount) + { + case 0: + break; + case 1: + case 2: + case 3: + /* note, use a mov/add for the shift since the mov has a + chance of getting optimized out */ + pic16_emitpcode (POC_MOVFW, pic16_popGet (AOP (left), offl)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr)); + pic16_emitpcode (POC_ADDWF, pic16_popGet (AOP (result), offr)); + pic16_emitpcode (POC_RLCFW, pic16_popGet (AOP (left), offl + MSB16)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr + MSB16)); + + while (--shCount) + { + emitCLRC; + pic16_emitpcode (POC_RLCF, pic16_popGet (AOP (result), offr)); + pic16_emitpcode (POC_RLCF, pic16_popGet (AOP (result), offr + MSB16)); + } + break; + + case 4: + case 5: + pic16_emitpcode (POC_SWAPFW, pic16_popGet (AOP (left), offl + MSB16)); + pic16_emitpcode (POC_ANDLW, pic16_popGetLit (0xF0)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr + MSB16)); + pic16_emitpcode (POC_SWAPFW, pic16_popGet (AOP (left), offl)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr)); + pic16_emitpcode (POC_ANDLW, pic16_popGetLit (0x0F)); + pic16_emitpcode (POC_XORWF, pic16_popGet (AOP (result), offr)); + pic16_emitpcode (POC_ADDWF, pic16_popGet (AOP (result), offr + MSB16)); + + + if (shCount == 5) + { + pic16_emitpcode (POC_RLCF, pic16_popGet (AOP (result), offr)); + pic16_emitpcode (POC_RLCF, pic16_popGet (AOP (result), offr + MSB16)); + } + break; + case 6: + pic16_emitpcode (POC_RRNCFW, pic16_popGet (AOP (left), offl)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr)); + pic16_emitpcode (POC_RRNCF, pic16_popGet (AOP (result), offr)); + pic16_emitpcode (POC_RRNCFW, pic16_popGet (AOP (left), offl + MSB16)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr + MSB16)); + pic16_emitpcode (POC_RRNCF, pic16_popGet (AOP (result), offr + MSB16)); + pic16_emitpcode (POC_MOVLW, pic16_popGetLit (0xc0)); + pic16_emitpcode (POC_ANDWF, pic16_popGet (AOP (result), offr + MSB16)); + pic16_emitpcode (POC_ANDFW, pic16_popGet (AOP (result), offr)); + pic16_emitpcode (POC_XORFW, pic16_popGet (AOP (result), offr)); + pic16_emitpcode (POC_IORWF, pic16_popGet (AOP (result), offr + MSB16)); + pic16_emitpcode (POC_XORWF, pic16_popGet (AOP (result), offr)); + break; + case 7: + pic16_emitpcode (POC_RRCFW, pic16_popGet (AOP (left), offl + MSB16)); + pic16_emitpcode (POC_RRCFW, pic16_popGet (AOP (left), offl)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr + MSB16)); + pic16_emitpcode (POC_CLRF, pic16_popGet (AOP (result), offr)); + pic16_emitpcode (POC_RRCF, pic16_popGet (AOP (result), offr)); + } + } + +} + +/*-----------------------------------------------------------------*/ +/* shiftR2Left2Result - shift right two bytes from left to result */ +/*-----------------------------------------------------------------*/ +static void +shiftR2Left2Result (operand * left, int offl, operand * result, int offr, int shCount, int sign) +{ + int same = pic16_sameRegs (AOP (result), AOP (left)); + int i; + DEBUGpic16_emitcode ("; ***", "%s %d shCount:%d same:%d sign:%d", __FUNCTION__, __LINE__, shCount, same, sign); + + if (same && (offl != offr)) // shift right bytes + { + if (offr < offl) + { + for (i = 0; i < 2; i++) + { + pic16_emitpcode (POC_MOVFW, pic16_popGet (AOP (result), offl + i)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr + i)); + } + } + else // just treat as different later on + { + same = 0; + } + } + + switch (shCount) + { + case 0: + break; + case 1: + case 2: + case 3: + /* obtain sign from left operand */ + if (sign) + pic16_emitpcode (POC_RLCFW, pic16_popGet (AOP (left), offr + MSB16)); + else + emitCLRC; + + if (same) + { + pic16_emitpcode (POC_RRCF, pic16_popGet (AOP (result), offr + MSB16)); + pic16_emitpcode (POC_RRCF, pic16_popGet (AOP (result), offr)); + } + else + { + pic16_emitpcode (POC_RRCFW, pic16_popGet (AOP (left), offl + MSB16)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr + MSB16)); + pic16_emitpcode (POC_RRCFW, pic16_popGet (AOP (left), offl)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr)); + } + + while (--shCount) + { + if (sign) + /* now get sign from already assigned result (avoid BANKSEL) */ + pic16_emitpcode (POC_RLCFW, pic16_popGet (AOP (result), offr + MSB16)); + else + emitCLRC; + pic16_emitpcode (POC_RRCF, pic16_popGet (AOP (result), offr + MSB16)); + pic16_emitpcode (POC_RRCF, pic16_popGet (AOP (result), offr)); + } + break; + case 4: + case 5: + if (same) + { + + pic16_emitpcode (POC_MOVLW, pic16_popGetLit (0xf0)); + pic16_emitpcode (POC_ANDWF, pic16_popGet (AOP (result), offr)); + pic16_emitpcode (POC_SWAPF, pic16_popGet (AOP (result), offr)); + + pic16_emitpcode (POC_SWAPF, pic16_popGet (AOP (result), offr + MSB16)); + pic16_emitpcode (POC_ANDFW, pic16_popGet (AOP (result), offr + MSB16)); + pic16_emitpcode (POC_XORWF, pic16_popGet (AOP (result), offr + MSB16)); + pic16_emitpcode (POC_ADDWF, pic16_popGet (AOP (result), offr)); + } + else + { + pic16_emitpcode (POC_SWAPFW, pic16_popGet (AOP (left), offl)); + pic16_emitpcode (POC_ANDLW, pic16_popGetLit (0x0f)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr)); + + pic16_emitpcode (POC_SWAPFW, pic16_popGet (AOP (left), offl + MSB16)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr + MSB16)); + pic16_emitpcode (POC_ANDLW, pic16_popGetLit (0xf0)); + pic16_emitpcode (POC_XORWF, pic16_popGet (AOP (result), offr + MSB16)); + pic16_emitpcode (POC_ADDWF, pic16_popGet (AOP (result), offr)); + } + + if (shCount >= 5) + { + pic16_emitpcode (POC_RRCF, pic16_popGet (AOP (result), offr + MSB16)); + pic16_emitpcode (POC_RRCF, pic16_popGet (AOP (result), offr)); + } + + if (sign) + { + pic16_emitpcode (POC_MOVLW, pic16_popGetLit (0xf0 + (shCount - 4) * 8)); + pic16_emitpcode (POC_BTFSC, + pic16_newpCodeOpBit (pic16_aopGet (AOP (result), offr + MSB16, FALSE, FALSE), 7 - shCount, 0, + PO_GPR_REGISTER)); + pic16_emitpcode (POC_ADDWF, pic16_popGet (AOP (result), offr + MSB16)); + } + + break; + + case 6: + if (same) + { + + pic16_emitpcode (POC_RLCF, pic16_popGet (AOP (result), offr)); + pic16_emitpcode (POC_RLCF, pic16_popGet (AOP (result), offr + MSB16)); + + pic16_emitpcode (POC_RLCF, pic16_popGet (AOP (result), offr)); + pic16_emitpcode (POC_RLCF, pic16_popGet (AOP (result), offr + MSB16)); + pic16_emitpcode (POC_RLCFW, pic16_popGet (AOP (result), offr)); + pic16_emitpcode (POC_ANDLW, pic16_popGetLit (0x03)); + if (sign) + { + pic16_emitpcode (POC_BTFSC, + pic16_newpCodeOpBit (pic16_aopGet (AOP (result), offr, FALSE, FALSE), 0, 0, PO_GPR_REGISTER)); + pic16_emitpcode (POC_IORLW, pic16_popGetLit (0xfc)); + } + pic16_emitpcode (POC_XORFW, pic16_popGet (AOP (result), offr + MSB16)); + pic16_emitpcode (POC_XORWF, pic16_popGet (AOP (result), offr + MSB16)); + pic16_emitpcode (POC_XORFW, pic16_popGet (AOP (result), offr + MSB16)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr)); + } + else + { + pic16_emitpcode (POC_RLCFW, pic16_popGet (AOP (left), offl)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr + MSB16)); + pic16_emitpcode (POC_RLCFW, pic16_popGet (AOP (left), offl + MSB16)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr)); + pic16_emitpcode (POC_RLCF, pic16_popGet (AOP (result), offr + MSB16)); + pic16_emitpcode (POC_RLCF, pic16_popGet (AOP (result), offr)); + pic16_emitpcode (POC_RLCFW, pic16_popGet (AOP (result), offr + MSB16)); + pic16_emitpcode (POC_ANDLW, pic16_popGetLit (0x03)); + if (sign) + { + pic16_emitpcode (POC_BTFSC, + pic16_newpCodeOpBit (pic16_aopGet (AOP (result), offr + MSB16, FALSE, FALSE), 0, 0, + PO_GPR_REGISTER)); + pic16_emitpcode (POC_IORLW, pic16_popGetLit (0xfc)); + } + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr + MSB16)); + //pic16_emitpcode(POC_RLCF, pic16_popGet(AOP(result),offr)); + + + } + + break; + case 7: + pic16_emitpcode (POC_RLCFW, pic16_popGet (AOP (left), offl)); + pic16_emitpcode (POC_RLCFW, pic16_popGet (AOP (left), offl + MSB16)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offr)); + pic16_emitpcode (POC_CLRF, pic16_popGet (AOP (result), offr + MSB16)); + if (sign) + { + emitSKPNC; + pic16_emitpcode (POC_DECF, pic16_popGet (AOP (result), offr + MSB16)); + } + else + pic16_emitpcode (POC_RLCF, pic16_popGet (AOP (result), offr + MSB16)); + } +} + + +/*-----------------------------------------------------------------*/ +/* shiftLLeftOrResult - shift left one byte from left, or to result*/ +/*-----------------------------------------------------------------*/ +static void +shiftLLeftOrResult (operand * left, int offl, operand * result, int offr, int shCount) +{ + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + + pic16_emitpcode (POC_MOVFW, pic16_popGet (AOP (left), offl)); + /* shift left accumulator */ + AccLsh (shCount, 1); + /* or with result */ + /* back to result */ + pic16_emitpcode (POC_IORWF, pic16_popGet (AOP (result), offr)); +} + +/*-----------------------------------------------------------------*/ +/* shiftRLeftOrResult - shift right one byte from left,or to result*/ +/*-----------------------------------------------------------------*/ +static void +shiftRLeftOrResult (operand * left, int offl, operand * result, int offr, int shCount) +{ + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + + pic16_emitpcode (POC_MOVFW, pic16_popGet (AOP (left), offl)); + /* shift right accumulator */ + AccRsh (shCount, 1); + /* or with result */ + /* back to result */ + pic16_emitpcode (POC_IORWF, pic16_popGet (AOP (result), offr)); +} + +/*-----------------------------------------------------------------*/ +/* genlshOne - left shift a one byte quantity by known count */ +/*-----------------------------------------------------------------*/ +static void +genlshOne (operand * result, operand * left, int shCount) +{ + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + shiftL1Left2Result (left, LSB, result, LSB, shCount); +} + +/*-----------------------------------------------------------------*/ +/* genlshTwo - left shift two bytes by known amount != 0 */ +/*-----------------------------------------------------------------*/ +static void +genlshTwo (operand * result, operand * left, int shCount) +{ + int size; + + DEBUGpic16_emitcode ("; ***", "%s %d shCount:%d", __FUNCTION__, __LINE__, shCount); + size = pic16_getDataSize (result); + + /* if shCount >= 8 */ + if (shCount >= 8) + { + shCount -= 8; + + if (size > 1) + { + if (shCount) + shiftL1Left2Result (left, LSB, result, MSB16, shCount); + else + movLeft2Result (left, LSB, result, MSB16); + } + pic16_emitpcode (POC_CLRF, pic16_popGet (AOP (result), LSB)); + } + + /* 1 <= shCount <= 7 */ + else + { + if (size == 1) + shiftL1Left2Result (left, LSB, result, LSB, shCount); + else + shiftL2Left2Result (left, LSB, result, LSB, shCount); + } +} + +/*-----------------------------------------------------------------*/ +/* shiftLLong - shift left one long from left to result */ +/* offr = LSB or MSB16 */ +/*-----------------------------------------------------------------*/ +static void +shiftLLong (operand * left, operand * result, int offr) +{ + int size = AOP_SIZE (result); + int same = pic16_sameRegs (AOP (left), AOP (result)); + int i; + + DEBUGpic16_emitcode ("; ***", "%s %d offr:%d size:%d", __FUNCTION__, __LINE__, offr, size); + + if (same && (offr == MSB16)) //shift one byte + { + for (i = size - 1; i >= MSB16; i--) + { + pic16_emitpcode (POC_MOVFW, pic16_popGet (AOP (left), i - 1)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (left), i)); + } + } + else + { + pic16_emitpcode (POC_MOVFW, pic16_popGet (AOP (left), LSB)); + } + + if (size > LSB + offr) + { + if (same) + { + pic16_emitpcode (POC_ADDWF, pic16_popGet (AOP (left), LSB + offr)); + } + else + { + pic16_emitpcode (POC_ADDFW, pic16_popGet (AOP (left), LSB)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), LSB + offr)); + } + } + + if (size > MSB16 + offr) + { + if (same) + { + pic16_emitpcode (POC_RLCF, pic16_popGet (AOP (left), MSB16 + offr)); + } + else + { + pic16_emitpcode (POC_RLCFW, pic16_popGet (AOP (left), MSB16)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), MSB16 + offr)); + } + } + + if (size > MSB24 + offr) + { + if (same) + { + pic16_emitpcode (POC_RLCF, pic16_popGet (AOP (left), MSB24 + offr)); + } + else + { + pic16_emitpcode (POC_RLCFW, pic16_popGet (AOP (left), MSB24)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), MSB24 + offr)); + } + } + + if (size > MSB32 + offr) + { + if (same) + { + pic16_emitpcode (POC_RLCF, pic16_popGet (AOP (left), MSB32 + offr)); + } + else + { + pic16_emitpcode (POC_RLCFW, pic16_popGet (AOP (left), MSB32)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), MSB32 + offr)); + } + } + if (offr != LSB) + pic16_emitpcode (POC_CLRF, pic16_popGet (AOP (result), LSB)); + +} + +/*-----------------------------------------------------------------*/ +/* genlshFour - shift four byte by a known amount != 0 */ +/*-----------------------------------------------------------------*/ +static void +genlshFour (operand * result, operand * left, int shCount) +{ + int size; + + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + size = AOP_SIZE (result); + + /* if shifting more that 3 bytes */ + if (shCount >= 24) + { + shCount -= 24; + if (shCount) + /* lowest order of left goes to the highest + order of the destination */ + shiftL1Left2Result (left, LSB, result, MSB32, shCount); + else + movLeft2Result (left, LSB, result, MSB32); + + pic16_emitpcode (POC_CLRF, pic16_popGet (AOP (result), LSB)); + pic16_emitpcode (POC_CLRF, pic16_popGet (AOP (result), MSB16)); + pic16_emitpcode (POC_CLRF, pic16_popGet (AOP (result), MSB24)); + + return; + } + + /* more than two bytes */ + else if (shCount >= 16) + { + /* lower order two bytes goes to higher order two bytes */ + shCount -= 16; + /* if some more remaining */ + if (shCount) + shiftL2Left2Result (left, LSB, result, MSB24, shCount); + else + { + movLeft2Result (left, MSB16, result, MSB32); + movLeft2Result (left, LSB, result, MSB24); + } + pic16_emitpcode (POC_CLRF, pic16_popGet (AOP (result), LSB)); + pic16_emitpcode (POC_CLRF, pic16_popGet (AOP (result), MSB16)); + return; + } + + /* if more than 1 byte */ + else if (shCount >= 8) + { + /* lower order three bytes goes to higher order three bytes */ + shCount -= 8; + if (size == 2) + { + if (shCount) + shiftL1Left2Result (left, LSB, result, MSB16, shCount); + else + movLeft2Result (left, LSB, result, MSB16); + } + else /* size = 4 */ + { + if (shCount == 0) + { + movLeft2Result (left, MSB24, result, MSB32); + movLeft2Result (left, MSB16, result, MSB24); + movLeft2Result (left, LSB, result, MSB16); + pic16_emitpcode (POC_CLRF, pic16_popGet (AOP (result), LSB)); + } + else if (shCount == 1) + shiftLLong (left, result, MSB16); + else + { + shiftL2Left2Result (left, MSB16, result, MSB24, shCount); + shiftL1Left2Result (left, LSB, result, MSB16, shCount); + shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount); + pic16_emitpcode (POC_CLRF, pic16_popGet (AOP (result), LSB)); + } + } + } + + /* 1 <= shCount <= 7 */ + else if (shCount <= 3) + { + shiftLLong (left, result, LSB); + while (--shCount >= 1) + shiftLLong (result, result, LSB); + } + /* 3 <= shCount <= 7, optimize */ + else + { + shiftL2Left2Result (left, MSB24, result, MSB24, shCount); + shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount); + shiftL2Left2Result (left, LSB, result, LSB, shCount); + } +} + +/*-----------------------------------------------------------------*/ +/* genLeftShiftLiteral - left shifting by known count */ +/*-----------------------------------------------------------------*/ +void +pic16_genLeftShiftLiteral (operand * left, operand * right, operand * result, iCode * ic) +{ + int shCount = abs ((int) ulFromVal (AOP (right)->aopu.aop_lit)); + int size; + + FENTRY; + DEBUGpic16_emitcode ("; ***", "shCount:%d", shCount); + pic16_freeAsmop (right, NULL, ic, TRUE); + + pic16_aopOp (left, ic, FALSE); + pic16_aopOp (result, ic, TRUE); + + size = getSize (operandType (result)); + +#if VIEW_SIZE + pic16_emitcode ("; shift left ", "result %d, left %d", size, AOP_SIZE (left)); +#endif + + /* I suppose that the left size >= result size */ + if (shCount == 0) + { + while (size--) + { + movLeft2Result (left, size, result, size); + } + } + + else if (shCount >= (size * 8)) + while (size--) + pic16_aopPut (AOP (result), zero, size); + else + { + switch (size) + { + case 1: + genlshOne (result, left, shCount); + break; + + case 2: + case 3: + genlshTwo (result, left, shCount); + break; + + case 4: + genlshFour (result, left, shCount); + break; + } + } + pic16_freeAsmop (left, NULL, ic, TRUE); + pic16_freeAsmop (result, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------* + * 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; + + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + + if (!reg) + return; + + if (!endian) + { + endian = 1; + } + else + { + endian = -1; + offset = size - 1; + } + + while (size--) + { + pic16_emitpcode (poc, pic16_popGet (AOP (reg), offset)); + offset += endian; + } + +} + +/*-----------------------------------------------------------------*/ +/* genrshOne - right shift a one byte quantity by known count */ +/*-----------------------------------------------------------------*/ +static void +genrshOne (operand * result, operand * left, int shCount, int sign) +{ + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + shiftR1Left2Result (left, LSB, result, LSB, shCount, sign); +} + +/*-----------------------------------------------------------------*/ +/* genrshTwo - right shift two bytes by known amount != 0 */ +/*-----------------------------------------------------------------*/ +static void +genrshTwo (operand * result, operand * left, int shCount, int sign) +{ + DEBUGpic16_emitcode ("; ***", "%s %d shCount:%d", __FUNCTION__, __LINE__, shCount); + /* if shCount >= 8 */ + if (shCount >= 8) + { + shCount -= 8; + if (shCount) + shiftR1Left2Result (left, MSB16, result, LSB, shCount, sign); + else + movLeft2Result (left, MSB16, result, LSB); + + pic16_addSign (result, 1, sign); + } + + /* 1 <= shCount <= 7 */ + else + shiftR2Left2Result (left, LSB, result, LSB, shCount, sign); +} + +/*-----------------------------------------------------------------*/ +/* shiftRLong - shift right one long from left to result */ +/* offl = LSB or MSB16 */ +/*-----------------------------------------------------------------*/ +static void +shiftRLong (operand * left, int offl, operand * result, int sign) +{ + int size = AOP_SIZE (result); + int same = pic16_sameRegs (AOP (left), AOP (result)); + int i; + DEBUGpic16_emitcode ("; ***", "%s %d offl:%d size:%d", __FUNCTION__, __LINE__, offl, size); + + if (same && (offl == MSB16)) //shift one byte right + { + for (i = MSB16; i < size; i++) + { + pic16_emitpcode (POC_MOVFW, pic16_popGet (AOP (left), i)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (left), i - 1)); + } + } + + if (sign) + pic16_emitpcode (POC_RLCFW, pic16_popGet (AOP (left), MSB32)); + else + emitCLRC; + + if (same) + { + if (offl == LSB) + pic16_emitpcode (POC_RRCF, pic16_popGet (AOP (left), MSB32)); + } + else + { + pic16_emitpcode (POC_RRCFW, pic16_popGet (AOP (left), MSB32)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), MSB32 - offl)); + } + + if (offl == MSB16) + { + /* add sign of "a" */ + pic16_addSign (result, MSB32, sign); + } + + if (same) + { + pic16_emitpcode (POC_RRCF, pic16_popGet (AOP (left), MSB24)); + } + else + { + pic16_emitpcode (POC_RRCFW, pic16_popGet (AOP (left), MSB24)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), MSB24 - offl)); + } + + if (same) + { + pic16_emitpcode (POC_RRCF, pic16_popGet (AOP (left), MSB16)); + } + else + { + pic16_emitpcode (POC_RRCFW, pic16_popGet (AOP (left), MSB16)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), MSB16 - offl)); + } + + if (same) + { + pic16_emitpcode (POC_RRCF, pic16_popGet (AOP (left), LSB)); + } + else + { + if (offl == LSB) + { + pic16_emitpcode (POC_RRCFW, pic16_popGet (AOP (left), LSB)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), LSB)); + } + } +} + +/*-----------------------------------------------------------------*/ +/* genrshFour - shift four byte by a known amount != 0 */ +/*-----------------------------------------------------------------*/ +static void +genrshFour (operand * result, operand * left, int shCount, int sign) +{ + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + /* if shifting more that 3 bytes */ + if (shCount >= 24) + { + shCount -= 24; + if (shCount) + shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign); + else + movLeft2Result (left, MSB32, result, LSB); + + pic16_addSign (result, MSB16, sign); + } + else if (shCount >= 16) + { + shCount -= 16; + if (shCount) + shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign); + else + { + movLeft2Result (left, MSB24, result, LSB); + movLeft2Result (left, MSB32, result, MSB16); + } + pic16_addSign (result, MSB24, sign); + } + else if (shCount >= 8) + { + shCount -= 8; + if (shCount == 1) + shiftRLong (left, MSB16, result, sign); + else if (shCount == 0) + { + movLeft2Result (left, MSB16, result, LSB); + movLeft2Result (left, MSB24, result, MSB16); + movLeft2Result (left, MSB32, result, MSB24); + pic16_addSign (result, MSB32, sign); + } + else //shcount >= 2 + { + shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0); + shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount); + /* the last shift is signed */ + shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign); + pic16_addSign (result, MSB32, sign); + } + } + else /* 1 <= shCount <= 7 */ + { + if (shCount <= 2) + { + shiftRLong (left, LSB, result, sign); + if (shCount == 2) + shiftRLong (result, LSB, result, sign); + } + else + { + shiftR2Left2Result (left, LSB, result, LSB, shCount, 0); + shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount); + shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign); + } + } +} + +/*-----------------------------------------------------------------*/ +/* genRightShiftLiteral - right shifting by known count */ +/*-----------------------------------------------------------------*/ +static void +genRightShiftLiteral (operand * left, operand * right, operand * result, iCode * ic, int sign) +{ + int shCount = abs ((int) ulFromVal (AOP (right)->aopu.aop_lit)); + int lsize, res_size; + + pic16_freeAsmop (right, NULL, ic, TRUE); + + pic16_aopOp (left, ic, FALSE); + pic16_aopOp (result, ic, TRUE); + + DEBUGpic16_emitcode ("; ***", "%s %d shCount:%d result:%d left:%d", __FUNCTION__, __LINE__, shCount, AOP_SIZE (result), + AOP_SIZE (left)); + +#if VIEW_SIZE + pic16_emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result), AOP_SIZE (left)); +#endif + + lsize = pic16_getDataSize (left); + res_size = pic16_getDataSize (result); + /* test the LEFT size !!! */ + + /* I suppose that the left size >= result size */ + if (shCount == 0) + { + assert (res_size <= lsize); + while (res_size--) + { + pic16_mov2f (AOP (result), AOP (left), res_size); + } // for + } + else if (shCount >= (lsize * 8)) + { + if (sign) + { + /* + * Do NOT use + * CLRF result + * BTFSC left, 7 + * SETF result + * even for 8-bit operands; result might be an SFR. + */ + pic16_emitpcode (POC_MOVLW, pic16_popGetLit (0x00)); + pic16_emitpcode (POC_BTFSC, pic16_popCopyGPR2Bit (pic16_popGet (AOP (left), lsize - 1), 7)); + pic16_emitpcode (POC_MOVLW, pic16_popGetLit (0xff)); + while (res_size--) + { + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), res_size)); + } + } + else // unsigned + { + while (res_size--) + { + pic16_emitpcode (POC_CLRF, pic16_popGet (AOP (result), res_size)); + } + } + } + else // 0 < shCount < 8*lsize + { + switch (res_size) + { + case 1: + genrshOne (result, left, shCount, sign); + break; + + case 2: + genrshTwo (result, left, shCount, sign); + break; + + case 4: + genrshFour (result, left, shCount, sign); + break; + default: + break; + } + } + + pic16_freeAsmop (left, NULL, ic, TRUE); + pic16_freeAsmop (result, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genGenericShift - generates code for left or right shifting */ +/*-----------------------------------------------------------------*/ +static void +genGenericShift (iCode * ic, int isShiftLeft) +{ + operand *left, *right, *result; + int offset; + int sign, signedCount; + symbol *label_complete, *label_loop_pos, *label_loop_neg, *label_negative; + PIC_OPCODE pos_shift, neg_shift; + + FENTRY; + + right = IC_RIGHT (ic); + left = IC_LEFT (ic); + result = IC_RESULT (ic); + + pic16_aopOp (right, ic, FALSE); + pic16_aopOp (left, ic, FALSE); + pic16_aopOp (result, ic, TRUE); + + sign = !SPEC_USIGN (operandType (left)); + signedCount = !SPEC_USIGN (operandType (right)); + + /* if the shift count is known then do it + as efficiently as possible */ + if (AOP_TYPE (right) == AOP_LIT) + { + long lit = (long) ulFromVal (AOP (right)->aopu.aop_lit); + if (signedCount && lit < 0) + { + lit = -lit; + isShiftLeft = !isShiftLeft; + } + // we should modify right->aopu.aop_lit here! + // Instead we use abs(shCount) in genXXXShiftLiteral()... + // lit > 8*size is handled in pic16_genXXXShiftLiteral() + if (isShiftLeft) + pic16_genLeftShiftLiteral (left, right, result, ic); + else + genRightShiftLiteral (left, right, result, ic, sign); + + goto release; + } // if (right is literal) + + /* shift count is unknown then we have to form a loop. + * Note: we take only the lower order byte since shifting + * more than 32 bits make no sense anyway, ( the + * largest size of an object can be only 32 bits ) + * Note: we perform arithmetic shifts if the left operand is + * signed and we do an (effective) right shift, i. e. we + * shift in the sign bit from the left. */ + + label_complete = newiTempLabel (NULL); + label_loop_pos = newiTempLabel (NULL); + label_loop_neg = NULL; + label_negative = NULL; + pos_shift = isShiftLeft ? POC_RLCF : POC_RRCF; + neg_shift = isShiftLeft ? POC_RRCF : POC_RLCF; + + if (signedCount) + { + // additional labels needed + label_loop_neg = newiTempLabel (NULL); + label_negative = newiTempLabel (NULL); + } // if + + /* + * The code below overwrites the shift count for `val = (1 << val)' + * when it assigns LEFT to RESULT (== RIGHT == shift count). + * XXX: This problem should have been/is also addressed in ralloc.c, + * but the code there seems not to catch this case ... + */ + if (pic16_sameRegs (AOP (right), AOP (result))) + { + // We abuse FSR0L as a temporary, pic16_popGetTempReg() is too costly. + pic16_mov2w (AOP (right), 0); + pic16_emitpcode (POC_MOVWF, pic16_popCopyReg (&pic16_pc_fsr0l)); + } // if + + // copy source to result -- this will effectively truncate the left operand to the size of result! + // (e.g. char c = 0x100 << -3 will become c = 0x00 >> 3 == 0x00 instad of 0x20) + // This is fine, as it only occurs for left shifting with negative count which is not standardized! + for (offset = 0; offset < min (AOP_SIZE (left), AOP_SIZE (result)); offset++) + { + pic16_mov2f (AOP (result), AOP (left), offset); + } // for + + // if result is longer than left, fill with zeros (or sign) + if (AOP_SIZE (left) < AOP_SIZE (result)) + { + if (sign && AOP_SIZE (left) > 0) + { + // shift signed operand -- fill with sign + pic16_emitpcode (POC_CLRF, pic16_popCopyReg (&pic16_pc_wreg)); + pic16_emitpcode (POC_BTFSC, pic16_popCopyGPR2Bit (pic16_popGet (AOP (result), AOP_SIZE (left) - 1), 7)); + pic16_emitpcode (POC_MOVLW, pic16_popGetLit (0xFF)); + for (offset = AOP_SIZE (left); offset < AOP_SIZE (result); offset++) + { + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offset)); + } // for + } + else + { + // shift unsigned operand -- fill result with zeros + for (offset = AOP_SIZE (left); offset < AOP_SIZE (result); offset++) + { + pic16_emitpcode (POC_CLRF, pic16_popGet (AOP (result), offset)); + } // for + } + } // if (size mismatch) + + /* load/restore shift count */ + if (pic16_sameRegs (AOP (right), AOP (result))) + { + pic16_emitpcode (POC_MOVFW, pic16_popCopyReg (&pic16_pc_fsr0l)); + } + else + { + pic16_mov2w (AOP (right), 0); + } // if + + pic16_emitpcode (POC_BZ, pic16_popGetLabel (label_complete->key)); + if (signedCount) + pic16_emitpcode (POC_BN, pic16_popGetLabel (label_negative->key)); + +#if 0 + // perform a shift by one (shift count is positive) + // cycles used for shifting {unsigned,signed} values on n bytes by [unsigned,signed] shift count c>0: + // 2n+[2,3]+({1,3}+n+3)c-2+[0,2]=({4,6}+n)c+2n+[0,3] ({5,7}c+[2,5] / {6,8}c+[4, 7] / {8,10}c+[ 8,11]) + pic16_emitpLabel (label_loop_pos->key); + emitCLRC; + if (sign && (pos_shift == POC_RRCF)) + { + pic16_emitpcode (POC_BTFSC, pic16_popCopyGPR2Bit (pic16_popGet (AOP (result), AOP_SIZE (result) - 1), 7)); + emitSETC; + } // if + genMultiAsm (pos_shift, result, AOP_SIZE (result), pos_shift == POC_RRCF); + pic16_emitpcode (POC_DECFSZ, pic16_popCopyReg (&pic16_pc_wreg)); + pic16_emitpcode (POC_BRA, pic16_popGetLabel (label_loop_pos->key)); +#else + // perform a shift by one (shift count is positive) + // cycles used for shifting {unsigned,signed} values on n bytes by [unsigned,signed] shift count c>0: + // 2n+[2,3]+2+({0,2}+n+3)c-1+[0,2]=({3,5}+n)c+2n+[3,6] ({4,6}c+[5,8] / {5,7}c+[7,10] / {7, 9}c+[11,14]) + // This variant is slower for 0<c<3, equally fast for c==3, and faster for 3<c. + pic16_emitpcode (POC_NEGF, pic16_popCopyReg (&pic16_pc_wreg)); + emitCLRC; + pic16_emitpLabel (label_loop_pos->key); + if (sign && (pos_shift == POC_RRCF)) + { + pic16_emitpcode (POC_BTFSC, pic16_popCopyGPR2Bit (pic16_popGet (AOP (result), AOP_SIZE (result) - 1), 7)); + emitSETC; + } // if + genMultiAsm (pos_shift, result, AOP_SIZE (result), pos_shift == POC_RRCF); + //pic16_emitpcode (POC_INCF, pic16_popCopyReg (&pic16_pc_wreg)); // gpsim does not like this... + pic16_emitpcode (POC_ADDLW, pic16_popGetLit (0x01)); + pic16_emitpcode (POC_BNC, pic16_popGetLabel (label_loop_pos->key)); +#endif + + if (signedCount) + { + pic16_emitpcode (POC_BRA, pic16_popGetLabel (label_complete->key)); + + pic16_emitpLabel (label_negative->key); + // perform a shift by -1 (shift count is negative) + // 2n+4+1+({0,2}+n+3)*c-1=({3,5}+n)c+2n+4 ({4,6}c+6 / {5,7}c+8 / {7,9}c+12) + emitCLRC; + pic16_emitpLabel (label_loop_neg->key); + if (sign && (neg_shift == POC_RRCF)) + { + pic16_emitpcode (POC_BTFSC, pic16_popCopyGPR2Bit (pic16_popGet (AOP (result), AOP_SIZE (result) - 1), 7)); + emitSETC; + } // if + genMultiAsm (neg_shift, result, AOP_SIZE (result), neg_shift == POC_RRCF); + //pic16_emitpcode (POC_INCF, pic16_popCopyReg (&pic16_pc_wreg)); // gpsim does not like this... + pic16_emitpcode (POC_ADDLW, pic16_popGetLit (0x01)); + pic16_emitpcode (POC_BNC, pic16_popGetLabel (label_loop_neg->key)); + } // if (signedCount) + + pic16_emitpLabel (label_complete->key); + +release: + pic16_freeAsmop (right, NULL, ic, TRUE); + pic16_freeAsmop (left, NULL, ic, TRUE); + pic16_freeAsmop (result, NULL, ic, TRUE); +} + +static void +genLeftShift (iCode * ic) +{ + genGenericShift (ic, 1); +} + +static void +genRightShift (iCode * ic) +{ + genGenericShift (ic, 0); +} + + +/* load FSR0 with address of/from op according to pic16_isLitOp() or if lit is 1 */ +void +pic16_loadFSR0 (operand * op, int lit) +{ + if ((IS_SYMOP (op) && OP_SYMBOL (op)->remat) || pic16_isLitOp (op)) + { + if (AOP_TYPE (op) == AOP_LIT) + { + /* handle 12 bit integers correctly */ + unsigned int val = (unsigned int) ulFromVal (AOP (op)->aopu.aop_lit); + if ((val & 0x0fff) != val) + { + fprintf (stderr, "WARNING: Accessing memory at 0x%x truncated to 0x%x.\n", val, (val & 0x0fff)); + val &= 0x0fff; + } + pic16_emitpcode (POC_LFSR, pic16_popGetLit2 (0, pic16_popGetLit12 (val))); + } + else + { + pic16_emitpcode (POC_LFSR, pic16_popGetLit2 (0, pic16_popGet (AOP (op), 0))); + } + } + else + { + assert (!IS_SYMOP (op) || !OP_SYMBOL (op)->remat); + // set up FSR0 with address of result + pic16_emitpcode (POC_MOVFF, pic16_popGet2p (pic16_popGet (AOP (op), 0), pic16_popCopyReg (&pic16_pc_fsr0l))); + pic16_emitpcode (POC_MOVFF, pic16_popGet2p (pic16_popGet (AOP (op), 1), pic16_popCopyReg (&pic16_pc_fsr0h))); + } +} + +/*----------------------------------------------------------------*/ +/* pic16_derefPtr - move one byte from the location ptr points to */ +/* to WREG (doWrite == 0) or one byte from WREG */ +/* to the location ptr points to (doWrite != 0) */ +/*----------------------------------------------------------------*/ +static void +pic16_derefPtr (operand * ptr, int p_type, int doWrite, int *fsr0_setup) +{ + if (!IS_PTR (operandType (ptr))) + { + if (doWrite) + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (ptr), 0)); + else + pic16_mov2w (AOP (ptr), 0); + return; + } + + //assert (IS_DECL(operandType(ptr)) && (p_type == DCL_TYPE(operandType(ptr)))); + /* We might determine pointer type right here: */ + p_type = DCL_TYPE (operandType (ptr)); + + switch (p_type) + { + case POINTER: + case FPOINTER: + case IPOINTER: + case PPOINTER: + if (!fsr0_setup || !*fsr0_setup) + { + pic16_loadFSR0 (ptr, 0); + if (fsr0_setup) + *fsr0_setup = 1; + } + if (doWrite) + pic16_emitpcode (POC_MOVWF, pic16_popCopyReg (&pic16_pc_indf0)); + else + pic16_emitpcode (POC_MOVFW, pic16_popCopyReg (&pic16_pc_indf0)); + break; + + case GPOINTER: + if (AOP (ptr)->aopu.aop_reg[2]) + { + if (doWrite) + pic16_emitpcode (POC_MOVWF, pic16_popCopyReg (pic16_stack_postdec)); + // prepare call to __gptrget1, this is actually genGenPointerGet(result, WREG, ?ic?) + mov2fp (pic16_popCopyReg (&pic16_pc_fsr0l), AOP (ptr), 0); + mov2fp (pic16_popCopyReg (&pic16_pc_prodl), AOP (ptr), 1); + pic16_mov2w (AOP (ptr), 2); + pic16_callGenericPointerRW (doWrite, 1); + } + else + { + // data pointer (just 2 byte given) + if (!fsr0_setup || !*fsr0_setup) + { + pic16_loadFSR0 (ptr, 0); + if (fsr0_setup) + *fsr0_setup = 1; + } + if (doWrite) + pic16_emitpcode (POC_MOVWF, pic16_popCopyReg (&pic16_pc_indf0)); + else + pic16_emitpcode (POC_MOVFW, pic16_popCopyReg (&pic16_pc_indf0)); + } + break; + + case CPOINTER: + /* XXX: Writing to CPOINTERs not (yet) implemented. */ + assert (!doWrite && "Cannot write into __code space!"); + if ((AOP_TYPE (ptr) == AOP_PCODE) + && ((AOP (ptr)->aopu.pcop->type == PO_IMMEDIATE) || (AOP (ptr)->aopu.pcop->type == PO_DIR))) + { + pic16_emitpcode (POC_MOVLW, pic16_popGet (AOP (ptr), 0)); + pic16_emitpcode (POC_MOVWF, pic16_popCopyReg (&pic16_pc_tblptrl)); + pic16_emitpcode (POC_MOVLW, pic16_popGet (AOP (ptr), 1)); + pic16_emitpcode (POC_MOVWF, pic16_popCopyReg (&pic16_pc_tblptrh)); + pic16_emitpcode (POC_MOVLW, pic16_popGet (AOP (ptr), 2)); + pic16_emitpcode (POC_MOVWF, pic16_popCopyReg (&pic16_pc_tblptru)); + } + else + { + mov2fp (pic16_popCopyReg (&pic16_pc_tblptrl), AOP (ptr), 0); + mov2fp (pic16_popCopyReg (&pic16_pc_tblptrh), AOP (ptr), 1); + mov2fp (pic16_popCopyReg (&pic16_pc_tblptru), AOP (ptr), 2); + } // if + + pic16_emitpcodeNULLop (POC_TBLRD_POSTINC); + pic16_emitpcode (POC_MOVFW, pic16_popCopyReg (&pic16_pc_tablat)); + break; + + default: + assert (0 && "invalid pointer type specified"); + break; + } +} + +/*-----------------------------------------------------------------*/ +/* genUnpackBits - generates code for unpacking bits */ +/*-----------------------------------------------------------------*/ +static void +genUnpackBits (operand * result, operand * left, char *rname, int ptype) +{ + int shCnt; + sym_link *etype; + unsigned blen = 0, bstr = 0; + int same; + pCodeOp *op; + + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + etype = getSpec (operandType (result)); + + // if(IS_BITFIELD(etype)) { + blen = SPEC_BLEN (etype); + bstr = SPEC_BSTR (etype); + // } + + DEBUGpic16_emitcode ("; ***", "%s %d - reading %s bitfield int %s destination", __FUNCTION__, __LINE__, + SPEC_USIGN (OP_SYM_ETYPE (left)) ? "an unsigned" : "a signed", + SPEC_USIGN (OP_SYM_TYPE (result)) ? "an unsigned" : "a signed"); + +#if 1 + if ((blen == 1) && (bstr < 8) && (!IS_PTR (operandType (left)) || IS_DIRECT (left) || PIC_IS_DATA_PTR (operandType (left)))) + { + /* it is a single bit, so use the appropriate bit instructions */ + DEBUGpic16_emitcode (";", "%s %d optimize bit read", __FUNCTION__, __LINE__); + + same = pic16_sameRegs (AOP (left), AOP (result)); + op = (same ? pic16_popCopyReg (&pic16_pc_wreg) : pic16_popGet (AOP (result), 0)); + pic16_emitpcode (POC_CLRF, op); + + if (!IS_PTR (operandType (left)) || IS_DIRECT (left)) + { + /* workaround to reduce the extra lfsr instruction */ + pic16_emitpcode (POC_BTFSC, pic16_popCopyGPR2Bit (pic16_popGet (AOP (left), 0), bstr)); + } + else + { + assert (PIC_IS_DATA_PTR (operandType (left))); + pic16_loadFSR0 (left, 0); + pic16_emitpcode (POC_BTFSC, pic16_popCopyGPR2Bit (pic16_popCopyReg (&pic16_pc_indf0), bstr)); + } + + if (SPEC_USIGN (OP_SYM_ETYPE (left))) + { + /* unsigned bitfields result in either 0 or 1 */ + pic16_emitpcode (POC_INCF, op); + } + else + { + /* signed bitfields result in either 0 or -1 */ + pic16_emitpcode (POC_DECF, op); + } + if (same) + { + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), 0)); + } + + pic16_addSign (result, 1, !SPEC_USIGN (OP_SYM_TYPE (result))); + return; + } + +#endif + + if (!IS_PTR (operandType (left)) || IS_DIRECT (left)) + { + // access symbol directly + pic16_mov2w (AOP (left), 0); + } + else + { + pic16_derefPtr (left, ptype, 0, NULL); + } + + /* if we have bitdisplacement then it fits */ + /* into this byte completely or if length is */ + /* less than a byte */ + if ((shCnt = SPEC_BSTR (etype)) || (SPEC_BLEN (etype) <= 8)) + { + + /* shift right acc */ + AccRsh (shCnt, 0); + + pic16_emitpcode (POC_ANDLW, pic16_popGetLit ((((unsigned char) - 1) >> (8 - SPEC_BLEN (etype))) & SRMask[shCnt])); + + /* VR -- normally I would use the following, but since we use the hack, + * to avoid the masking from AccRsh, why not mask it right now? */ + + /* + pic16_emitpcode(POC_ANDLW, pic16_popGetLit(((unsigned char) -1)>>(8 - SPEC_BLEN(etype)))); + */ + + /* extend signed bitfields to 8 bits */ + if (!SPEC_USIGN (OP_SYM_ETYPE (left)) && (bstr + blen < 8)) + { + assert (blen + bstr > 0); + pic16_emitpcode (POC_BTFSC, pic16_popCopyGPR2Bit (pic16_popCopyReg (&pic16_pc_wreg), bstr + blen - 1)); + pic16_emitpcode (POC_IORLW, pic16_popGetLit (0xFF << (bstr + blen))); + } + + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), 0)); + + pic16_addSign (result, 1, !SPEC_USIGN (OP_SYM_TYPE (result))); + return; + } + + fprintf (stderr, "SDCC pic16 port error: the port currently does not support *reading*\n"); + fprintf (stderr, "bitfields of size >=8. Instead of generating wrong code, bailing out...\n"); + exit (EXIT_FAILURE); +} + + +static void +genDataPointerGet (operand * left, operand * result, iCode * ic) +{ + int size, offset = 0, leoffset = 0; + + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + pic16_aopOp (result, ic, TRUE); + + FENTRY; + + size = AOP_SIZE (result); +// fprintf(stderr, "%s:%d size= %d\n", __FILE__, __LINE__, size); + + +#if 1 + if (!strcmp (pic16_aopGet (AOP (result), 0, TRUE, FALSE), pic16_aopGet (AOP (left), 0, TRUE, FALSE))) + { + DEBUGpic16_emitcode ("; ***", "left and result names are same, skipping moving"); + goto release; + } +#endif + + if (AOP (left)->aopu.pcop->type == PO_DIR) + leoffset = PCOR (AOP (left)->aopu.pcop)->instance; + + DEBUGpic16_pic16_AopType (__LINE__, left, NULL, result); + + while (size--) + { + DEBUGpic16_emitcode ("; ***", "%s loop offset=%d leoffset=%d", __FUNCTION__, offset, leoffset); + +// pic16_DumpOp("(result)",result); + if (pic16_isLitAop (AOP (result))) + { + pic16_mov2w (AOP (left), offset); // patch 8 + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offset)); + } + else + { + pic16_emitpcode (POC_MOVFF, pic16_popGet2p (pic16_popGet (AOP (left), offset), //patch 8 + pic16_popGet (AOP (result), offset))); + } + + offset++; + leoffset++; + } + +release: + pic16_freeAsmop (result, NULL, ic, TRUE); +} + + + +/*-----------------------------------------------------------------*/ +/* genNearPointerGet - pic16_emitcode for near pointer fetch */ +/*-----------------------------------------------------------------*/ +static void +genNearPointerGet (operand * left, operand * result, iCode * ic) +{ +// asmop *aop = NULL; + //regs *preg = NULL ; + sym_link *rtype, *retype; + sym_link *ltype, *letype; + + FENTRY; + + rtype = operandType (result); + retype = getSpec (rtype); + ltype = operandType (left); + letype = getSpec (ltype); + + pic16_aopOp (left, ic, FALSE); + +// pic16_DumpOp("(left)",left); +// pic16_DumpOp("(result)",result); + + /* 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 && !IS_BITFIELD (retype) && DCL_TYPE (ltype) == POINTER) + { + + genDataPointerGet (left, result, ic); + pic16_freeAsmop (left, NULL, ic, TRUE); + return; + } + + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + pic16_aopOp (result, ic, TRUE); + + DEBUGpic16_pic16_AopType (__LINE__, left, NULL, result); + +#if 1 + if (IS_BITFIELD (retype) && (SPEC_BLEN (retype) == 1)) + { + iCode *nextic; + pCodeOp *jop; + int bitstrt; + + /* if this is bitfield of size 1, see if we are checking the value + * of a single bit in an if-statement, + * if yes, then don't generate usual code, but execute the + * genIfx directly -- VR */ + + nextic = ic->next; + + /* CHECK: if next iCode is IFX + * and current result operand is nextic's conditional operand + * and current result operand live ranges ends at nextic's key number + */ + if ((nextic->op == IFX) && (result == IC_COND (nextic)) && (OP_LIVETO (result) == nextic->seq) && (OP_SYMBOL (left)->remat) // below fails for "if (p->bitfield)" + ) + { + /* everything is ok then */ + /* find a way to optimize the genIfx iCode */ + + bitstrt = SPEC_BSTR (retype) % 8; + + jop = pic16_popCopyGPR2Bit (pic16_popGet (AOP (left), 0), bitstrt); + + genIfxpCOpJump (nextic, jop); + + pic16_freeAsmop (left, NULL, ic, TRUE); + pic16_freeAsmop (result, NULL, ic, TRUE); + return; + } + } +#endif + + /* if bitfield then unpack the bits */ + if (IS_BITFIELD (letype)) + genUnpackBits (result, left, NULL, POINTER); + else + { + /* we have can just get the values */ + int size = AOP_SIZE (result); + int offset = 0; + + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + + pic16_loadFSR0 (left, 0); + + while (size--) + { + if (size) + { + pic16_emitpcode (POC_MOVFF, pic16_popGet2p (pic16_popCopyReg (&pic16_pc_postinc0), + pic16_popGet (AOP (result), offset++))); + } + else + { + pic16_emitpcode (POC_MOVFF, pic16_popGet2p (pic16_popCopyReg (&pic16_pc_indf0), + pic16_popGet (AOP (result), offset++))); + } + } + } + +#if 0 + /* now some housekeeping stuff */ + if (aop) + { + /* we had to allocate for this iCode */ + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + pic16_freeAsmop (NULL, aop, ic, TRUE); + } + else + { + /* we did not allocate which means left + * already in a pointer register, then + * if size > 0 && this could be used again + * we have to point it back to where it + * belongs */ + DEBUGpic16_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; +// while (size--) +// pic16_emitcode("dec","%s",rname); + } + } +#endif + + /* done */ + pic16_freeAsmop (left, NULL, ic, TRUE); + pic16_freeAsmop (result, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genGenPointerGet - gget value from generic pointer space */ +/*-----------------------------------------------------------------*/ +static void +genGenPointerGet (operand * left, operand * result, iCode * ic) +{ + int size; + sym_link *letype = getSpec (operandType (left)); + + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + pic16_aopOp (left, ic, FALSE); + pic16_aopOp (result, ic, TRUE); + size = AOP_SIZE (result); + + DEBUGpic16_pic16_AopType (__LINE__, left, NULL, result); + + /* if bit then unpack */ + if (IS_BITFIELD (letype)) + { + genUnpackBits (result, left, "BAD", GPOINTER); + goto release; + } + + /* set up WREG:PRODL:FSR0L with address from left */ + mov2fp (pic16_popCopyReg (&pic16_pc_fsr0l), AOP (left), 0); + mov2fp (pic16_popCopyReg (&pic16_pc_prodl), AOP (left), 1); + pic16_mov2w (AOP (left), 2); + pic16_callGenericPointerRW (0, size); + + assignResultValue (result, size, 1); + +release: + pic16_freeAsmop (left, NULL, ic, TRUE); + pic16_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)); + // symbol *albl = newiTempLabel(NULL); // patch 15 + // symbol *blbl = newiTempLabel(NULL); // + // PIC_OPCODE poc; // patch 15 + int size; + int offset = 0; + + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + pic16_aopOp (left, ic, FALSE); + pic16_aopOp (result, ic, TRUE); + size = AOP_SIZE (result); + + /* if bit then unpack */ + if (IS_BITFIELD (getSpec (operandType (left)))) + { + genUnpackBits (result, left, "BAD", GPOINTER); + goto release; + } // if + + DEBUGpic16_pic16_AopType (__LINE__, left, NULL, result); + + DEBUGpic16_emitcode ("; ", " %d getting const pointer", __LINE__); + + // set up table pointer + if ((AOP_TYPE (left) == AOP_PCODE) + && ((AOP (left)->aopu.pcop->type == PO_IMMEDIATE) || (AOP (left)->aopu.pcop->type == PO_DIR))) + { + pic16_emitpcode (POC_MOVLW, pic16_popGet (AOP (left), 0)); + pic16_emitpcode (POC_MOVWF, pic16_popCopyReg (&pic16_pc_tblptrl)); + pic16_emitpcode (POC_MOVLW, pic16_popGet (AOP (left), 1)); + pic16_emitpcode (POC_MOVWF, pic16_popCopyReg (&pic16_pc_tblptrh)); + pic16_emitpcode (POC_MOVLW, pic16_popGet (AOP (left), 2)); + pic16_emitpcode (POC_MOVWF, pic16_popCopyReg (&pic16_pc_tblptru)); + } + else + { + mov2fp (pic16_popCopyReg (&pic16_pc_tblptrl), AOP (left), 0); + mov2fp (pic16_popCopyReg (&pic16_pc_tblptrh), AOP (left), 1); + mov2fp (pic16_popCopyReg (&pic16_pc_tblptru), AOP (left), 2); + } + + while (size--) + { + pic16_emitpcodeNULLop (POC_TBLRD_POSTINC); + pic16_emitpcode (POC_MOVFF, pic16_popGet2p (pic16_popCopyReg (&pic16_pc_tablat), pic16_popGet (AOP (result), offset))); + offset++; + } + +release: + pic16_freeAsmop (left, NULL, ic, TRUE); + pic16_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; + + FENTRY; + + 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 0 + if (IS_PTR_CONST (type)) +#else + if (IS_CODEPTR (type)) +#endif + DEBUGpic16_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)); + + DEBUGpic16_emitcode ("; ***", "%d - resolve pointer by storage class", __LINE__); + + if (SPEC_OCLS (etype)->codesp) + { + DEBUGpic16_emitcode ("; ***", "%d - cpointer", __LINE__); + //p_type = CPOINTER ; + } + else if (SPEC_OCLS (etype)->fmap && !SPEC_OCLS (etype)->paged) + { + DEBUGpic16_emitcode ("; ***", "%d - fpointer", __LINE__); + /*p_type = FPOINTER ; */ + } + else if (SPEC_OCLS (etype)->fmap && SPEC_OCLS (etype)->paged) + { + DEBUGpic16_emitcode ("; ***", "%d - ppointer", __LINE__); + /* p_type = PPOINTER; */ + } + else if (SPEC_OCLS (etype) == idata) + { + DEBUGpic16_emitcode ("; ***", "%d - ipointer", __LINE__); + /* p_type = IPOINTER; */ + } + else + { + DEBUGpic16_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: + case PPOINTER: + genNearPointerGet (left, result, ic); + break; + + case CPOINTER: + genConstPointerGet (left, result, ic); + //pic16_emitcodePointerGet (left,result,ic); + break; + + case GPOINTER: +#if 0 + if (IS_PTR_CONST (type)) + genConstPointerGet (left, result, ic); + else +#endif + genGenPointerGet (left, result, ic); + break; + + default: + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "genPointerGet: illegal pointer type"); + + } +} + +/*-----------------------------------------------------------------*/ +/* genPackBits - generates code for packed bit storage */ +/*-----------------------------------------------------------------*/ +static void +genPackBits (sym_link * etype, operand * result, operand * right, char *rname, int p_type) +{ + unsigned shCnt = 0; + int offset = 0; + int rLen = 0; + unsigned blen, bstr; + int shifted_and_masked = 0; + unsigned long lit = (unsigned long) - 1; + sym_link *retype; + + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + blen = SPEC_BLEN (etype); + bstr = SPEC_BSTR (etype); + + retype = getSpec (operandType (right)); + + if (AOP_TYPE (right) == AOP_LIT) + { + lit = ulFromVal (AOP (right)->aopu.aop_lit); + + if ((blen == 1) && (bstr < 8)) + { + /* it is a single bit, so use the appropriate bit instructions */ + + DEBUGpic16_emitcode (";", "%s %d optimize bit assignment", __FUNCTION__, __LINE__); + + if (!IS_PTR (operandType (result)) || IS_DIRECT (result)) + { + /* workaround to reduce the extra lfsr instruction */ + if (lit) + { + pic16_emitpcode (POC_BSF, pic16_popCopyGPR2Bit (pic16_popGet (AOP (result), 0), bstr)); + } + else + { + pic16_emitpcode (POC_BCF, pic16_popCopyGPR2Bit (pic16_popGet (AOP (result), 0), bstr)); + } + } + else + { + if (PIC_IS_DATA_PTR (operandType (result))) + { + pic16_loadFSR0 (result, 0); + pic16_emitpcode (lit ? POC_BSF : POC_BCF, pic16_popCopyGPR2Bit (pic16_popCopyReg (&pic16_pc_indf0), bstr)); + } + else + { + /* get old value */ + pic16_derefPtr (result, p_type, 0, NULL); + pic16_emitpcode (lit ? POC_BSF : POC_BCF, pic16_popCopyGPR2Bit (pic16_popCopyReg (&pic16_pc_wreg), bstr)); + /* write back new value */ + pic16_derefPtr (result, p_type, 1, NULL); + } + } + + return; + } + /* IORLW below is more efficient */ + //pic16_emitpcode(POC_MOVLW, pic16_popGetLit((lit & ((1UL << blen) - 1)) << bstr)); + lit = (lit & ((1UL << blen) - 1)) << bstr; + shifted_and_masked = 1; + offset++; + } + else if (IS_DIRECT (result) && !IS_PTR (operandType (result)) + && IS_BITFIELD (retype) && (AOP_TYPE (right) == AOP_REG || AOP_TYPE (right) == AOP_DIR) && (blen == 1)) + { + int rbstr; + + rbstr = SPEC_BSTR (retype); + + if (IS_BITFIELD (etype)) + { + pic16_emitpcode (POC_MOVFW, pic16_popGet (AOP (result), 0)); + pic16_emitpcode (POC_BCF, pic16_popCopyGPR2Bit (pic16_popCopyReg (&pic16_pc_wreg), bstr)); + } + else + { + pic16_emitpcode (POC_CLRF, pic16_popCopyReg (&pic16_pc_wreg)); + } + + pic16_emitpcode (POC_BTFSC, pic16_popCopyGPR2Bit (pic16_popGet (AOP (right), 0), rbstr)); + + if (IS_BITFIELD (etype)) + { + pic16_emitpcode (POC_BSF, pic16_popCopyGPR2Bit (pic16_popCopyReg (&pic16_pc_wreg), bstr)); + } + else + { + pic16_emitpcode (POC_INCF, pic16_popCopyReg (&pic16_pc_wreg)); + } + + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), 0)); + + return; + } + else + { + /* move right to W */ + pic16_emitpcode (POC_MOVFW, pic16_popGet (AOP (right), offset++)); + } + + /* if the bit length is less than or */ + /* it exactly fits a byte then */ + if ((shCnt = SPEC_BSTR (etype)) || SPEC_BLEN (etype) <= 8) + { + int fsr0_setup = 0; + + if (blen != 8 || (bstr % 8) != 0) + { + // we need to combine the value with the old value + if (!shifted_and_masked) + { + pic16_emitpcode (POC_ANDLW, pic16_popGetLit ((1U << blen) - 1)); + + DEBUGpic16_emitcode (";", "shCnt = %d SPEC_BSTR(etype) = %d:%d", shCnt, SPEC_BSTR (etype), SPEC_BLEN (etype)); + + /* shift left acc, do NOT mask the result again */ + AccLsh (shCnt, 0); + + /* using PRODH as a temporary register here */ + pic16_emitpcode (POC_MOVWF, pic16_popCopyReg (&pic16_pc_prodh)); + } + + if ((IS_SYMOP (result) && !IS_PTR (operandType (result))) || IS_DIRECT (result)) + { + /* access symbol directly */ + pic16_mov2w (AOP (result), 0); + } + else + { + /* get old value */ + pic16_derefPtr (result, p_type, 0, &fsr0_setup); + } +#if 1 + pic16_emitpcode (POC_ANDLW, pic16_popGetLit ((unsigned char) ((unsigned char) (0xff << (blen + bstr)) | + (unsigned char) (0xff >> (8 - bstr))))); + if (!shifted_and_masked) + { + pic16_emitpcode (POC_IORFW, pic16_popCopyReg (&pic16_pc_prodh)); + } + else + { + /* We have the shifted and masked (literal) right value in `lit' */ + if (lit != 0) + pic16_emitpcode (POC_IORLW, pic16_popGetLit (lit)); + } + } + else // if (blen == 8 && (bstr % 8) == 0) + { + if (shifted_and_masked) + { + // move right (literal) to WREG (only case where right is not yet in WREG) + pic16_mov2w (AOP (right), (bstr / 8)); + } + } + + /* write new value back */ + if ((IS_SYMOP (result) && !IS_PTR (operandType (result))) || IS_DIRECT (result)) + { + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), 0)); + } + else + { + pic16_derefPtr (result, p_type, 1, &fsr0_setup); + } +#endif + + return; + } + + +#if 0 + fprintf (stderr, "SDCC pic16 port error: the port currently does not support\n"); + fprintf (stderr, "bitfields of size >=8. Instead of generating wrong code, bailing out...\n"); + exit (EXIT_FAILURE); +#endif + + + pic16_loadFSR0 (result, 0); // load FSR0 with address of result + rLen = SPEC_BLEN (etype) - 8; + + /* now generate for lengths greater than one byte */ + while (1) + { + rLen -= 8; + if (rLen <= 0) + { + mov2fp (pic16_popCopyReg (&pic16_pc_prodh), AOP (right), offset); + break; + } + + switch (p_type) + { + case POINTER: + pic16_emitpcode (POC_MOVWF, pic16_popCopyReg (&pic16_pc_postinc0)); + break; + + /* + case FPOINTER: + MOVA(l); + pic16_emitcode("movx","@dptr,a"); + break; + + case GPOINTER: + MOVA(l); + DEBUGpic16_emitcode(";lcall","__gptrput"); + break; + */ + default: + assert (0); + } + + + pic16_mov2w (AOP (right), offset++); + } + + /* last last was not complete */ + if (rLen) + { + /* save the byte & read byte */ + switch (p_type) + { + case POINTER: + // pic16_emitpcode(POC_MOVWF, pic16_popCopyReg(&pic16_pc_prodl)); + pic16_emitpcode (POC_MOVFW, pic16_popCopyReg (&pic16_pc_indf0)); + break; + + /* + case FPOINTER: + pic16_emitcode ("mov","b,a"); + pic16_emitcode("movx","a,@dptr"); + break; + + case GPOINTER: + pic16_emitcode ("push","b"); + pic16_emitcode ("push","acc"); + pic16_emitcode ("lcall","__gptrget"); + pic16_emitcode ("pop","b"); + break; + */ + default: + assert (0); + } + DEBUGpic16_emitcode (";", "rLen = %i", rLen); + pic16_emitpcode (POC_ANDLW, pic16_popGetLit ((unsigned char) - 1 << -rLen)); + pic16_emitpcode (POC_IORFW, pic16_popCopyReg (&pic16_pc_prodh)); + // pic16_emitcode ("anl","a,#0x%02x",((unsigned char)-1 << -rLen) ); + // pic16_emitcode ("orl","a,b"); + } + + // if (p_type == GPOINTER) + // pic16_emitcode("pop","b"); + + switch (p_type) + { + + case POINTER: + pic16_emitpcode (POC_MOVWF, pic16_popCopyReg (&pic16_pc_indf0)); + // pic16_emitcode("mov","@%s,a",rname); + break; + /* + case FPOINTER: + pic16_emitcode("movx","@dptr,a"); + break; + + case GPOINTER: + DEBUGpic16_emitcode(";lcall","__gptrput"); + break; + */ + default: + assert (0); + } + + // pic16_freeAsmop(right, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genDataPointerSet - remat pointer to data space */ +/*-----------------------------------------------------------------*/ +static void +genDataPointerSet (operand * right, operand * result, iCode * ic) +{ + int size, offset = 0, resoffset = 0; + + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + pic16_aopOp (right, ic, FALSE); + + size = AOP_SIZE (right); + +// fprintf(stderr, "%s:%d size= %d\n", __FILE__, __LINE__, size); + +#if 0 + if (AOP_TYPE (result) == AOP_PCODE) + { + fprintf (stderr, "genDataPointerSet %s, %d\n", + AOP (result)->aopu.pcop->name, + (AOP (result)->aopu.pcop->type == PO_DIR) ? + PCOR (AOP (result)->aopu.pcop)->instance : PCOI (AOP (result)->aopu.pcop)->offset); + } +#endif + + if (AOP (result)->aopu.pcop->type == PO_DIR) + resoffset = PCOR (AOP (result)->aopu.pcop)->instance; + + while (size--) + { + if (AOP_TYPE (right) == AOP_LIT) + { + unsigned int lit = pic16aopLiteral (AOP (IC_RIGHT (ic))->aopu.aop_lit, offset); + pic16_movLit2f (pic16_popGet (AOP (result), offset), lit); + } + else + { + pic16_mov2w (AOP (right), offset); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offset)); // patch 8 + } + offset++; + resoffset++; + } + + pic16_freeAsmop (right, NULL, ic, TRUE); +} + + + +/*-----------------------------------------------------------------*/ +/* genNearPointerSet - pic16_emitcode for near pointer put */ +/*-----------------------------------------------------------------*/ +static void +genNearPointerSet (operand * right, operand * result, iCode * ic) +{ + asmop *aop = NULL; + sym_link *retype; + sym_link *ptype = operandType (result); + sym_link *resetype; + + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + retype = getSpec (operandType (right)); + resetype = getSpec (operandType (result)); + + pic16_aopOp (result, ic, FALSE); + + /* if the result is rematerializable & + * in data space & not a bit variable */ + + /* and result is not a bit variable */ + if (AOP_TYPE (result) == AOP_PCODE && DCL_TYPE (ptype) == POINTER && !IS_BITFIELD (retype) && !IS_BITFIELD (resetype)) + { + + genDataPointerSet (right, result, ic); + pic16_freeAsmop (result, NULL, ic, TRUE); + return; + } + + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + pic16_aopOp (right, ic, FALSE); + DEBUGpic16_pic16_AopType (__LINE__, NULL, right, result); + + /* if bitfield then unpack the bits */ + if (IS_BITFIELD (resetype)) + { + genPackBits (resetype, result, right, NULL, POINTER); + } + else + { + /* we have can just get the values */ + int size = AOP_SIZE (right); + int offset = 0; + + pic16_loadFSR0 (result, 0); + + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + while (size--) + { + if (pic16_isLitOp (right)) + { + pic16_emitpcode (POC_MOVLW, pic16_popGet (AOP (right), offset)); + if (size) + { + pic16_emitpcode (POC_MOVWF, pic16_popCopyReg (&pic16_pc_postinc0)); + } + else + { + pic16_emitpcode (POC_MOVWF, pic16_popCopyReg (&pic16_pc_indf0)); + } + } + else // no literal + { + if (size) + { + pic16_emitpcode (POC_MOVFF, + pic16_popGet2p (pic16_popGet (AOP (right), offset), pic16_popCopyReg (&pic16_pc_postinc0))); + } + else + { + pic16_emitpcode (POC_MOVFF, + pic16_popGet2p (pic16_popGet (AOP (right), offset), pic16_popCopyReg (&pic16_pc_indf0))); + } + } + + offset++; + } + } + + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + /* now some housekeeping stuff */ + if (aop) + { + /* we had to allocate for this iCode */ + pic16_freeAsmop (NULL, aop, ic, TRUE); + } + else + { + /* we did not allocate which means left + * already in a pointer register, then + * if size > 0 && this could be used again + * we have to point it back to where it + * belongs */ + DEBUGpic16_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; + + while (size--) + pic16_emitcode ("decf", "fsr0,f"); + //pic16_emitcode("dec","%s",rname); + } + } + + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + /* done */ +//release: + pic16_freeAsmop (right, NULL, ic, TRUE); + pic16_freeAsmop (result, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genGenPointerSet - set value from generic pointer space */ +/*-----------------------------------------------------------------*/ +static void +genGenPointerSet (operand * right, operand * result, iCode * ic) +{ + int size; + sym_link *retype = getSpec (operandType (result)); + + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + + pic16_aopOp (result, ic, FALSE); + pic16_aopOp (right, ic, FALSE); + size = AOP_SIZE (right); + + DEBUGpic16_pic16_AopType (__LINE__, NULL, right, result); + + + /* if bit then unpack */ + if (IS_BITFIELD (retype)) + { +// pic16_emitpcode(POC_LFSR,pic16_popGetLit2(0,pic16_popGetLit(lit))); + genPackBits (retype, result, right, "dptr", GPOINTER); + goto release; + } + + size = AOP_SIZE (right); + + DEBUGpic16_emitcode ("; ***", "%s %d size=%d", __FUNCTION__, __LINE__, size); + + + /* load value to write in TBLPTRH:TBLPTRL:PRODH:[stack] */ + + /* value of right+0 is placed on stack, which will be retrieved + * by the support function thus restoring the stack. The important + * thing is that there is no need to manually restore stack pointer + * here */ + pushaop (AOP (right), 0); +// mov2fp(pic16_popCopyReg(&pic16_pc_postdec1), AOP(right), 0); + if (size > 1) + mov2fp (pic16_popCopyReg (&pic16_pc_prodh), AOP (right), 1); + if (size > 2) + mov2fp (pic16_popCopyReg (&pic16_pc_tblptrl), AOP (right), 2); + if (size > 3) + mov2fp (pic16_popCopyReg (&pic16_pc_tblptrh), AOP (right), 3); + + /* load address to write to in WREG:FSR0H:FSR0L */ + pic16_emitpcode (POC_MOVFF, pic16_popGet2p (pic16_popGet (AOP (result), 0), pic16_popCopyReg (&pic16_pc_fsr0l))); + pic16_emitpcode (POC_MOVFF, pic16_popGet2p (pic16_popGet (AOP (result), 1), pic16_popCopyReg (&pic16_pc_prodl))); + pic16_emitpcode (POC_MOVFW, pic16_popGet (AOP (result), 2)); + + pic16_callGenericPointerRW (1, size); + +release: + pic16_freeAsmop (right, NULL, ic, TRUE); + pic16_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; + + 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: + case PPOINTER: + genNearPointerSet (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; + + pic16_aopOp (cond, ic, FALSE); + + /* get the value into acc */ + if (AOP_TYPE (cond) != AOP_CRY) + pic16_toBoolean (cond); + else + isbit = 1; + /* the result is now in the accumulator */ + pic16_freeAsmop (cond, NULL, ic, TRUE); + + /* if there was something to be popped then do it */ + if (popIc) + genIpop (popIc); + + /* if the condition is a bit variable */ + if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond)) + { + genIfxJump (ic, "c"); + DEBUGpic16_emitcode ("; isbit SPIL_LOC", "%s", SPIL_LOC (cond)->rname); + } + else + { + if (isbit && !IS_ITEMP (cond)) + genIfxJump (ic, OP_SYMBOL (cond)->rname); + else + genIfxJump (ic, "a"); + } + ic->generated = 1; +} + +/*-----------------------------------------------------------------*/ +/* genAddrOf - generates code for address of */ +/*-----------------------------------------------------------------*/ +static void +genAddrOf (iCode * ic) +{ + operand *result, *left; + int size; + symbol *sym; // = OP_SYMBOL(IC_LEFT(ic)); + pCodeOp *pcop0, *pcop1, *pcop2; + + FENTRY; + + pic16_aopOp ((result = IC_RESULT (ic)), ic, TRUE); + + sym = OP_SYMBOL (IC_LEFT (ic)); + + if (sym->onStack) + { + /* get address of symbol on stack */ + DEBUGpic16_emitcode ("; ", "%s symbol %s on stack", __FUNCTION__, sym->name); +#if 0 + fprintf (stderr, "%s:%d symbol %s on stack offset %i\n", __FILE__, __LINE__, + OP_SYMBOL (IC_LEFT (ic))->name, OP_SYMBOL (IC_LEFT (ic))->stack); +#endif + + // operands on stack are accessible via "FSR2 + index" with index + // starting at 2 for arguments and growing from 0 downwards for + // local variables (index == 0 is not assigned so we add one here) + { + int soffs = OP_SYMBOL (IC_LEFT (ic))->stack; + + if (soffs <= 0) + { + assert (soffs < 0); + soffs++; + } // if + + DEBUGpic16_emitcode ("*!*", "accessing stack symbol at offset=%d", soffs); + pic16_emitpcode (POC_MOVLW, pic16_popGetLit (soffs & 0x00FF)); + pic16_emitpcode (POC_ADDFW, pic16_popCopyReg (pic16_framepnt_lo)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), 0)); + pic16_emitpcode (POC_MOVLW, pic16_popGetLit ((soffs >> 8) & 0x00FF)); + pic16_emitpcode (POC_ADDFWC, pic16_popCopyReg (pic16_framepnt_hi)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), 1)); + } + + goto release; + } + +// if(pic16_debug_verbose) { +// fprintf(stderr, "%s:%d %s symbol %s , codespace=%d\n", +// __FILE__, __LINE__, __FUNCTION__, sym->name, IN_CODESPACE( SPEC_OCLS(sym->etype))); +// } + + pic16_aopOp ((left = IC_LEFT (ic)), ic, FALSE); + size = AOP_SIZE (IC_RESULT (ic)); + + pcop0 = PCOP (pic16_newpCodeOpImmd (sym->rname, 0, 0, IN_CODESPACE (SPEC_OCLS (sym->etype)))); + pcop1 = PCOP (pic16_newpCodeOpImmd (sym->rname, 1, 0, IN_CODESPACE (SPEC_OCLS (sym->etype)))); + pcop2 = PCOP (pic16_newpCodeOpImmd (sym->rname, 2, 0, IN_CODESPACE (SPEC_OCLS (sym->etype)))); + + if (size == 3) + { + pic16_emitpcode (POC_MOVLW, pcop0); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), 0)); + pic16_emitpcode (POC_MOVLW, pcop1); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), 1)); + pic16_emitpcode (POC_MOVLW, pcop2); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), 2)); + } + else if (size == 2) + { + pic16_emitpcode (POC_MOVLW, pcop0); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), 0)); + pic16_emitpcode (POC_MOVLW, pcop1); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), 1)); + } + else + { + pic16_emitpcode (POC_MOVLW, pcop0); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), 0)); + } + + pic16_freeAsmop (left, NULL, ic, FALSE); +release: + pic16_freeAsmop (result, NULL, ic, TRUE); +} + + +/*-----------------------------------------------------------------*/ +/* genAssign - generate code for assignment */ +/*-----------------------------------------------------------------*/ +static void +genAssign (iCode * ic) +{ + operand *result, *right; + sym_link *restype, *rtype; + int size, offset, know_W; + unsigned long lit = 0L; + + result = IC_RESULT (ic); + right = IC_RIGHT (ic); + + FENTRY; + + /* if they are the same */ + if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic))) + return; + + /* reversed order operands are aopOp'ed so that result operand + * is effective in case right is a stack symbol. This maneauver + * allows to use the _G.resDirect flag later */ + pic16_aopOp (result, ic, TRUE); + pic16_aopOp (right, ic, FALSE); + + DEBUGpic16_pic16_AopType (__LINE__, NULL, right, result); + + /* if they are the same registers */ + if (pic16_sameRegs (AOP (right), AOP (result))) + goto release; + + /* if the result is a bit */ + if (AOP_TYPE (result) == AOP_CRY) + { + /* if the right size is a literal then + we know what the value is */ + if (AOP_TYPE (right) == AOP_LIT) + { + + pic16_emitpcode ((((int) operandLitValue (right)) ? POC_BSF : POC_BCF), pic16_popGet (AOP (result), 0)); + + if (((int) operandLitValue (right))) + pic16_emitcode ("bsf", "(%s >> 3),(%s & 7)", AOP (result)->aopu.aop_dir, AOP (result)->aopu.aop_dir); + else + pic16_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) + { + pic16_emitpcode (POC_BCF, pic16_popGet (AOP (result), 0)); + pic16_emitpcode (POC_BTFSC, pic16_popGet (AOP (right), 0)); + pic16_emitpcode (POC_BSF, pic16_popGet (AOP (result), 0)); + + goto release; + } + + /* we need to or */ + pic16_emitpcode (POC_BCF, pic16_popGet (AOP (result), 0)); + pic16_toBoolean (right); + emitSKPZ; + pic16_emitpcode (POC_BSF, pic16_popGet (AOP (result), 0)); + //pic16_aopPut(AOP(result),"a",0); + goto release; + } + + /* bit variables done */ + /* general case */ + size = AOP_SIZE (result); + offset = 0; + + /* bit variables done */ + /* general case */ + size = AOP_SIZE (result); + restype = operandType (result); + rtype = operandType (right); + offset = 0; + + if (AOP_TYPE (right) == AOP_LIT) + { + if (!(IS_FLOAT (operandType (right)) || IS_FIXED (operandType (right)))) + { + lit = ulFromVal (AOP (right)->aopu.aop_lit); + + /* patch tag for literals that are cast to pointers */ + if (IS_CODEPTR (restype)) + { + //fprintf (stderr, "%s:%u: INFO: `(__code*)literal'\n", ic->filename, ic->lineno); + lit = (lit & 0x00ffff) | (GPTR_TAG_CODE << 16); + } + else + { + if (IS_GENPTR (restype)) + { + if (IS_CODEPTR (rtype)) + { + //fprintf (stderr, "%s:%u: INFO: `(generic*)(literal __code*)'\n", ic->filename, ic->lineno); + lit = (lit & 0x00ffff) | (GPTR_TAG_CODE << 16); + } + else if (PIC_IS_DATA_PTR (rtype)) + { + //fprintf (stderr, "%s:%u: INFO: `(generic*)(literal __data*)'\n", ic->filename, ic->lineno); + lit = (lit & 0x00ffff) | (GPTR_TAG_DATA << 16); + } + else if (!IS_PTR (rtype) || IS_GENPTR (rtype)) + { + //fprintf (stderr, "%s:%u: INFO: `(generic*)literal' -- accepting specified tag %02x\n", ic->filename, ic->lineno, (unsigned char)(lit >> 16)); + } + else if (IS_PTR (rtype)) + { + fprintf (stderr, "%s:%u: WARNING: `(generic*)literal' -- assuming __data space\n", ic->filename, + ic->lineno); + lit = (lit & 0x00ffff) | (GPTR_TAG_DATA << 16); + } + } + } + } + else + { + union + { + unsigned long lit_int; + float lit_float; + } info; + + + if (IS_FIXED16X16 (operandType (right))) + { + lit = (unsigned long) fixed16x16FromDouble (floatFromVal (AOP (right)->aopu.aop_lit)); + } + else + { + /* take care if literal is a float */ + info.lit_float = (float)floatFromVal (AOP (right)->aopu.aop_lit); + lit = info.lit_int; + } + } + } + +// fprintf(stderr, "%s:%d: assigning value 0x%04lx (%d:%d)\n", __FUNCTION__, __LINE__, lit, +// sizeof(unsigned long int), sizeof(float)); + + + if (AOP_TYPE (right) == AOP_REG) + { + DEBUGpic16_emitcode ("; ", "%s:%d assign from register\n", __FUNCTION__, __LINE__); + while (size--) + { + pic16_emitpcode (POC_MOVFF, pic16_popGet2 (AOP (right), AOP (result), offset++)); + } // while + goto release; + } + + /* when do we have to read the program memory? + * - if right itself is a symbol in code space + * (we don't care what it points to if it's a pointer) + * - AND right is not a function (we would want its address) + */ + if (AOP_TYPE (right) != AOP_LIT + && IN_CODESPACE (SPEC_OCLS (OP_SYM_ETYPE (right))) && !IS_FUNC (OP_SYM_TYPE (right)) && !IS_ITEMP (right)) + { + + DEBUGpic16_emitcode ("; ", "%s:%d symbol in code space, take special care\n", __FUNCTION__, __LINE__); + //fprintf(stderr, "%s:%d symbol %s = [ %s ] is in code space\n", __FILE__, __LINE__, OP_SYMBOL(result)->name, OP_SYMBOL(right)->name); + + // set up table pointer + if (pic16_isLitOp (right)) + { +// fprintf(stderr, "%s:%d inside block 1\n", __FILE__, __LINE__); + pic16_emitpcode (POC_MOVLW, pic16_popGet (AOP (right), 0)); + pic16_emitpcode (POC_MOVWF, pic16_popCopyReg (&pic16_pc_tblptrl)); + pic16_emitpcode (POC_MOVLW, pic16_popGet (AOP (right), 1)); + pic16_emitpcode (POC_MOVWF, pic16_popCopyReg (&pic16_pc_tblptrh)); + pic16_emitpcode (POC_MOVLW, pic16_popGet (AOP (right), 2)); + pic16_emitpcode (POC_MOVWF, pic16_popCopyReg (&pic16_pc_tblptru)); + } + else + { +// fprintf(stderr, "%s:%d inside block 2\n", __FILE__, __LINE__); + pic16_emitpcode (POC_MOVFF, pic16_popGet2p (pic16_popGet (AOP (right), 0), pic16_popCopyReg (&pic16_pc_tblptrl))); + pic16_emitpcode (POC_MOVFF, pic16_popGet2p (pic16_popGet (AOP (right), 1), pic16_popCopyReg (&pic16_pc_tblptrh))); + pic16_emitpcode (POC_MOVFF, pic16_popGet2p (pic16_popGet (AOP (right), 2), pic16_popCopyReg (&pic16_pc_tblptru))); + } + + /* must fetch 3 bytes for pointers (was OP_SYM_ETYPE before) */ + size = min ((int)getSize (OP_SYM_TYPE (right)), AOP_SIZE (result)); + while (size--) + { + pic16_emitpcodeNULLop (POC_TBLRD_POSTINC); + pic16_emitpcode (POC_MOVFF, pic16_popGet2p (pic16_popCopyReg (&pic16_pc_tablat), + pic16_popGet (AOP (result), offset))); + offset++; + } + + /* FIXME: for pointers we need to extend differently (according + * to pointer type DATA/CODE/EEPROM/... :*/ + size = getSize (OP_SYM_TYPE (right)); + if (AOP_SIZE (result) > size) + { + size = AOP_SIZE (result) - size; + while (size--) + { + pic16_emitpcode (POC_CLRF, pic16_popGet (AOP (result), offset)); + offset++; + } + } + goto release; + } + +#if 0 + /* VR - What is this?! */ + if (AOP_TYPE (right) == AOP_DIR && (AOP_TYPE (result) == AOP_REG) && size == 1) + { + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + + if (aopIdx (AOP (result), 0) == 4) + { + /* this is a workaround to save value of right into wreg too, + * value of wreg is going to be used later */ + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + pic16_emitpcode (POC_MOVFW, pic16_popGet (AOP (right), offset)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offset)); + goto release; + } + else +// assert(0); + DEBUGpic16_emitcode ("; WARNING", "%s %d ignoring register storage", __FUNCTION__, __LINE__); + } +#endif + + size = AOP_SIZE (right); + if (size > AOP_SIZE (result)) + size = AOP_SIZE (result); + know_W = -1; + while (size--) + { + DEBUGpic16_emitcode ("; ***", "%s %d size %d", __FUNCTION__, __LINE__, size); + if (AOP_TYPE (right) == AOP_LIT) + { + if (lit & 0xff) + { + if (know_W != (lit & 0xff)) + pic16_emitpcode (POC_MOVLW, pic16_popGetLit (lit & 0xff)); + know_W = lit & 0xff; + + if (AOP_TYPE (result) != AOP_ACC) + { + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offset)); + } + } + else + pic16_emitpcode (POC_CLRF, pic16_popGet (AOP (result), offset)); + + lit >>= 8; + + } + else if (AOP_TYPE (right) == AOP_CRY) + { + pic16_emitpcode (POC_CLRF, pic16_popGet (AOP (result), offset)); + if (offset == 0) + { + //debugf("%s: BTFSS offset == 0\n", __FUNCTION__); + pic16_emitpcode (POC_BTFSC, pic16_popGet (AOP (right), 0)); + pic16_emitpcode (POC_INCF, pic16_popGet (AOP (result), 0)); + } + } + else if ((AOP_TYPE (right) == AOP_PCODE) && (AOP (right)->aopu.pcop->type == PO_IMMEDIATE)) + { + pic16_emitpcode (POC_MOVLW, pic16_popGet (AOP (right), offset)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offset)); + } + else + { + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + + if (!_G.resDirect) /* use this aopForSym feature */ + { + if (AOP_TYPE (result) == AOP_ACC) + { + pic16_emitpcode (POC_MOVFW, pic16_popGet (AOP (right), offset)); + } + else if (AOP_TYPE (right) == AOP_ACC) + { + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offset)); + } + else + { + pic16_emitpcode (POC_MOVFF, pic16_popGet2 (AOP (right), AOP (result), offset)); + } + } + } + + offset++; + } + pic16_addSign (result, AOP_SIZE (right), !IS_UNSIGNED (operandType (right))); + +release: + pic16_freeAsmop (result, NULL, ic, TRUE); + pic16_freeAsmop (right, NULL, ic, FALSE); +} + +/*-----------------------------------------------------------------*/ +/* genJumpTab - generates code for jump table */ +/*-----------------------------------------------------------------*/ +static void +genJumpTab (iCode * ic) +{ + symbol *jtab; + char *l; + pCodeOp *jt_label; + + FENTRY; + + pic16_aopOp (IC_JTCOND (ic), ic, FALSE); + /* get the condition into accumulator */ + l = pic16_aopGet (AOP (IC_JTCOND (ic)), 0, FALSE, FALSE); + MOVA (l); + /* multiply by three */ + pic16_emitcode ("add", "a,acc"); + pic16_emitcode ("add", "a,%s", pic16_aopGet (AOP (IC_JTCOND (ic)), 0, FALSE, FALSE)); + + jtab = newiTempLabel (NULL); + pic16_emitcode ("mov", "dptr,#%05d_DS_", labelKey2num (jtab->key)); + pic16_emitcode ("jmp", "@a+dptr"); + pic16_emitcode ("", "%05d_DS_:", labelKey2num (jtab->key)); + +#if 0 + pic16_emitpcode (POC_MOVLW, pic16_popGetLabel (jtab->key)); + pic16_emitpcode (POC_ADDFW, pic16_popGet (AOP (IC_JTCOND (ic)), 0)); + emitSKPNC; + pic16_emitpcode (POC_INCF, pic16_popCopyReg (&pic16_pc_pclath)); + pic16_emitpcode (POC_MOVWF, pic16_popCopyReg (&pic16_pc_pcl)); + pic16_emitpLabel (jtab->key); + +#else + + jt_label = pic16_popGetLabel (jtab->key); + //fprintf (stderr, "Creating jump table...\n"); + + // calculate offset into jump table (idx * sizeof(GOTO)) + // This solution does not use temporary registers and the code is shorter. + pic16_emitpcode (POC_CLRF , pic16_popCopyReg (&pic16_pc_pclath)); + pic16_emitpcode (POC_CLRF , pic16_popCopyReg (&pic16_pc_pclatu)); + pic16_emitpcode (POC_RLCFW , pic16_popGet (AOP (IC_JTCOND (ic)), 0)); + pic16_emitpcode (POC_RLCF , pic16_popCopyReg (&pic16_pc_pclath)); + pic16_emitpcode (POC_RLCFW , pic16_popCopyReg (&pic16_pc_wreg)); + pic16_emitpcode (POC_RLCF , pic16_popCopyReg (&pic16_pc_pclath)); + pic16_emitpcode (POC_ANDLW , pic16_popGetLit (0xFC)); + pic16_emitpcode (POC_ADDLW , pic16_popGetImmd (jt_label->name, 0, 0)); + pic16_emitpcode (POC_MOVWF , pic16_popCopyReg (pic16_stack_postdec)); + pic16_emitpcode (POC_MOVLW , pic16_popGetImmd (jt_label->name, 1, 0)); + pic16_emitpcode (POC_ADDWFC, pic16_popCopyReg (&pic16_pc_pclath)); + pic16_emitpcode (POC_MOVLW , pic16_popGetImmd (jt_label->name, 2, 0)); + pic16_emitpcode (POC_ADDWFC, pic16_popCopyReg (&pic16_pc_pclatu)); + + // jump into the table + pic16_emitpcode (POC_MOVFW, pic16_popCopyReg (pic16_stack_preinc)); + pic16_emitpcode (POC_MOVWF, pic16_popCopyReg (&pic16_pc_pcl)); + + pic16_emitpLabelFORCE (jtab->key); +#endif + + pic16_freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE); +// pic16_emitpinfo(INF_LOCALREGS, pic16_newpCodeOpLocalRegs(LR_ENTRY_BEGIN)); + + pic16_emitpinfo (INF_OPTIMIZATION, pic16_newpCodeOpOpt (OPT_JUMPTABLE_BEGIN, "")); + /* now generate the jump labels */ + for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab; jtab = setNextItem (IC_JTLABELS (ic))) + { +// pic16_emitcode("ljmp","%05d_DS_",labelKey2num (jtab->key)); + pic16_emitpcode (POC_GOTO, pic16_popGetLabel (jtab->key)); + + } + pic16_emitpinfo (INF_OPTIMIZATION, pic16_newpCodeOpOpt (OPT_JUMPTABLE_END, "")); + +} + +/*-----------------------------------------------------------------*/ +/* genMixedOperation - gen code for operators between mixed types */ +/*-----------------------------------------------------------------*/ +/* + TSD - Written for the PIC port - but this unfortunately is buggy. + This routine is good in that it is able to efficiently promote + types to different (larger) sizes. Unfortunately, the temporary + variables that are optimized out by this routine are sometimes + used in other places. So until I know how to really parse the + iCode tree, I'm going to not be using this routine :(. +*/ +static int +genMixedOperation (iCode * ic) +{ +#if 0 + operand *result = IC_RESULT (ic); + sym_link *ctype = operandType (IC_LEFT (ic)); + operand *right = IC_RIGHT (ic); + int ret = 0; + int big, small; + int offset; + + iCode *nextic; + operand *nextright = NULL, *nextleft = NULL, *nextresult = NULL; + + pic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + + nextic = ic->next; + if (!nextic) + return 0; + + nextright = IC_RIGHT (nextic); + nextleft = IC_LEFT (nextic); + nextresult = IC_RESULT (nextic); + + pic16_aopOp (right, ic, FALSE); + pic16_aopOp (result, ic, FALSE); + pic16_aopOp (nextright, nextic, FALSE); + pic16_aopOp (nextleft, nextic, FALSE); + pic16_aopOp (nextresult, nextic, FALSE); + + if (pic16_sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (nextic)))) + { + + operand *t = right; + right = nextright; + nextright = t; + + pic16_emitcode (";remove right +", ""); + + } + else if (pic16_sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (nextic)))) + { + /* + operand *t = right; + right = nextleft; + nextleft = t; + */ + pic16_emitcode (";remove left +", ""); + } + else + return 0; + + big = AOP_SIZE (nextleft); + small = AOP_SIZE (nextright); + + switch (nextic->op) + { + + case '+': + pic16_emitcode (";optimize a +", ""); + /* if unsigned or not an integral type */ + if (AOP_TYPE (IC_LEFT (nextic)) == AOP_CRY) + { + pic16_emitcode (";add a bit to something", ""); + } + else + { + + pic16_emitcode ("movf", "%s,w", AOP (nextright)->aopu.aop_dir); + + if (!pic16_sameRegs (AOP (IC_LEFT (nextic)), AOP (IC_RESULT (nextic)))) + { + pic16_emitcode ("addwf", "%s,w", AOP (nextleft)->aopu.aop_dir); + pic16_emitcode ("movwf", "%s", pic16_aopGet (AOP (IC_RESULT (nextic)), 0, FALSE, FALSE)); + } + else + pic16_emitcode ("addwf", "%s,f", AOP (nextleft)->aopu.aop_dir); + + offset = 0; + while (--big) + { + + offset++; + + if (--small) + { + if (!pic16_sameRegs (AOP (IC_LEFT (nextic)), AOP (IC_RESULT (nextic)))) + { + pic16_emitcode ("movf", "%s,w", pic16_aopGet (AOP (IC_LEFT (nextic)), offset, FALSE, FALSE)); + pic16_emitcode ("movwf", "%s,f", pic16_aopGet (AOP (IC_RESULT (nextic)), offset, FALSE, FALSE)); + } + + pic16_emitcode ("movf", "%s,w", pic16_aopGet (AOP (IC_LEFT (nextic)), offset, FALSE, FALSE)); + emitSKPNC; + pic16_emitcode ("btfsc", "(%s >> 3), (%s & 7)", + AOP (IC_RIGHT (nextic))->aopu.aop_dir, AOP (IC_RIGHT (nextic))->aopu.aop_dir); + pic16_emitcode (" incf", "%s,w", pic16_aopGet (AOP (IC_LEFT (nextic)), offset, FALSE, FALSE)); + pic16_emitcode ("movwf", "%s", pic16_aopGet (AOP (IC_RESULT (nextic)), offset, FALSE, FALSE)); + + } + else + { + pic16_emitcode ("rlf", "known_zero,w"); + + /* + if right is signed + btfsc right,7 + addlw ff + */ + if (!pic16_sameRegs (AOP (IC_LEFT (nextic)), AOP (IC_RESULT (nextic)))) + { + pic16_emitcode ("addwf", "%s,w", pic16_aopGet (AOP (IC_LEFT (nextic)), offset, FALSE, FALSE)); + pic16_emitcode ("movwf", "%s,f", pic16_aopGet (AOP (IC_RESULT (nextic)), offset, FALSE, FALSE)); + } + else + { + pic16_emitcode ("addwf", "%s,f", pic16_aopGet (AOP (IC_RESULT (nextic)), offset, FALSE, FALSE)); + } + } + } + ret = 1; + } + } + ret = 1; + +release: + pic16_freeAsmop (right, NULL, ic, TRUE); + pic16_freeAsmop (result, NULL, ic, TRUE); + pic16_freeAsmop (nextright, NULL, ic, TRUE); + pic16_freeAsmop (nextleft, NULL, ic, TRUE); + if (ret) + nextic->generated = 1; + + return ret; +#else + return 0; +#endif +} + +/*-----------------------------------------------------------------*/ +/* genCast - gen code for casting */ +/*-----------------------------------------------------------------*/ +static void +genCast (iCode * ic) +{ + operand *result = IC_RESULT (ic); + sym_link *ctype = operandType (IC_LEFT (ic)); + sym_link *rtype = operandType (IC_RIGHT (ic)); + sym_link *restype = operandType (IC_RESULT (ic)); + operand *right = IC_RIGHT (ic); + int size, offset; + + + FENTRY; + + /* if they are equivalent then do nothing */ +// if (operandsEqu(IC_RESULT(ic),IC_RIGHT(ic))) +// return ; + + pic16_aopOp (result, ic, FALSE); + pic16_aopOp (right, ic, FALSE); + + DEBUGpic16_pic16_AopType (__LINE__, NULL, right, result); + + + /* 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 */ + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + + if (AOP_TYPE (right) == AOP_LIT) + { + pic16_emitpcode ((((int) operandLitValue (right)) ? POC_BSF : POC_BCF), pic16_popGet (AOP (result), 0)); + + if (((int) operandLitValue (right))) + pic16_emitcode ("bsf", "(%s >> 3), (%s & 7)", AOP (result)->aopu.aop_dir, AOP (result)->aopu.aop_dir); + else + pic16_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) + { + emitCLRC; + pic16_emitpcode (POC_BTFSC, pic16_popGet (AOP (right), 0)); + + pic16_emitcode ("clrc", ""); + pic16_emitcode ("btfsc", "(%s >> 3), (%s & 7)", AOP (right)->aopu.aop_dir, AOP (right)->aopu.aop_dir); + pic16_aopPut (AOP (result), "c", 0); + goto release; + } + + /* we need to or */ + if (AOP_TYPE (right) == AOP_REG) + { + pic16_emitpcode (POC_BCF, pic16_popGet (AOP (result), 0)); + pic16_emitpcode (POC_BTFSC, pic16_newpCodeOpBit (pic16_aopGet (AOP (right), 0, FALSE, FALSE), 0, 0, PO_GPR_REGISTER)); + pic16_emitpcode (POC_BSF, pic16_popGet (AOP (result), 0)); + } + pic16_toBoolean (right); + pic16_aopPut (AOP (result), "a", 0); + goto release; + } + + if ((AOP_TYPE (right) == AOP_CRY) && (AOP_TYPE (result) == AOP_REG)) + { + int offset = 1; + + size = AOP_SIZE (result); + + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + + pic16_emitpcode (POC_CLRF, pic16_popGet (AOP (result), 0)); + pic16_emitpcode (POC_BTFSC, pic16_popGet (AOP (right), 0)); + pic16_emitpcode (POC_INCF, pic16_popGet (AOP (result), 0)); + + while (size--) + pic16_emitpcode (POC_CLRF, pic16_popGet (AOP (result), offset++)); + + goto release; + } + + if (IS_BOOL (operandType (result))) + { + pic16_toBoolean (right); + emitSKPNZ; + pic16_emitpcode (POC_MOVLW, pic16_popGetLit (1)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), 0)); + goto release; + } + + if (IS_BITFIELD (getSpec (restype)) && IS_BITFIELD (getSpec (rtype))) + { + DEBUGpic16_emitcode ("***", "%d casting a bit to another bit", __LINE__); + } + + /* port from pic14 to cope with generic pointers */ + if (PIC_IS_TAGGED (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); + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + + max = size; + while (size--) + { + pic16_mov2w (AOP (right), size); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), size)); + } // while + + /* upcast into generic pointer type? */ + if (IS_GENPTR (restype) && !PIC_IS_TAGGED (rtype) && (AOP_SIZE (result) > max)) + { + /* determine appropriate tag for right */ + if (PIC_IS_DATA_PTR (rtype)) + tag = GPTR_TAG_DATA; + else if (IS_CODEPTR (rtype)) + tag = GPTR_TAG_CODE; + else if (PIC_IS_DATA_PTR (ctype)) + { + //fprintf (stderr, "%s:%u: WARNING: casting `(generic*)(__data*)(non-pointer)'\n", ic->filename, ic->lineno); + tag = GPTR_TAG_DATA; + } + else if (IS_CODEPTR (ctype)) + { + //fprintf (stderr, "%s:%u: WARNING: casting `(generic*)(__code*)(non-pointer)'\n", ic->filename, ic->lineno); + tag = GPTR_TAG_CODE; + } + else if (IS_PTR (rtype)) + { + PERFORM_ONCE (weirdcast, + fprintf (stderr, "%s:%u: WARNING: casting `(generic*)(unknown*)' -- assuming __data space\n", + ic->filename, ic->lineno);); + tag = GPTR_TAG_DATA; + } + else + { + PERFORM_ONCE (weirdcast, + fprintf (stderr, "%s:%u: WARNING: casting `(generic*)(non-pointer)' -- assuming __data space\n", + ic->filename, ic->lineno);); + tag = GPTR_TAG_DATA; + } + + assert (AOP_SIZE (result) == 3); + /* zero-extend address... */ + for (size = max; size < AOP_SIZE (result) - 1; size++) + pic16_emitpcode (POC_CLRF, pic16_popGet (AOP (result), size)); + /* ...and add tag */ + pic16_movLit2f (pic16_popGet (AOP (result), AOP_SIZE (result) - 1), tag); + } + else if (IS_CODEPTR (restype) && AOP_SIZE (result) > max) + { + //fprintf (stderr, "%s:%u: INFO: code pointer\n", ic->filename, ic->lineno); + for (size = max; size < AOP_SIZE (result) - 1; size++) + pic16_emitpcode (POC_CLRF, pic16_popGet (AOP (result), size)); + /* add __code tag */ + pic16_movLit2f (pic16_popGet (AOP (result), AOP_SIZE (result) - 1), GPTR_TAG_CODE); + } + else if (AOP_SIZE (result) > max) + { + /* extend non-pointers */ + //fprintf (stderr, "%s:%u: zero-extending value cast to pointer\n", ic->filename, ic->lineno); + pic16_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 (pic16_sameRegs (AOP (right), AOP (result))) + goto release; + + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); +#if 0 + if (IS_PTR_CONST (rtype)) +#else + if (IS_CODEPTR (rtype)) +#endif + DEBUGpic16_emitcode ("; ***", "%d - right is const pointer", __LINE__); + +#if 0 + if (IS_PTR_CONST (operandType (IC_RESULT (ic)))) +#else + if (IS_CODEPTR (operandType (IC_RESULT (ic)))) +#endif + DEBUGpic16_emitcode ("; ***", "%d - result is const pointer", __LINE__); + + if ((AOP_TYPE (right) == AOP_PCODE) && AOP (right)->aopu.pcop->type == PO_IMMEDIATE) + { + pic16_emitpcode (POC_MOVLW, pic16_popGet (AOP (right), 0)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), 0)); + + if (AOP_SIZE (result) < 2) + { + fprintf (stderr, "%d -- casting a ptr to a char\n", __LINE__); + } + else + { + pic16_emitpcode (POC_MOVLW, pic16_popGet (AOP (right), 1)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), 1)); + } + } + else + { + /* if they in different places then copy */ + size = AOP_SIZE (result); + offset = 0; + while (size--) + { + pic16_emitpcode (POC_MOVFW, pic16_popGet (AOP (right), offset)); + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offset)); + offset++; + } + } + goto release; + } + + /* if the result is of type pointer */ + if (IS_PTR (ctype)) + { + int p_type; + sym_link *type = operandType (right); + sym_link *etype = getSpec (type); + + DEBUGpic16_emitcode ("; ***", "%s %d - pointer cast", __FUNCTION__, __LINE__); + + /* pointer to generic pointer */ + if (IS_GENPTR (ctype)) + { + + if (IS_PTR (type)) + p_type = DCL_TYPE (type); + else + { + /* we have to go by the storage class */ + p_type = PTR_TYPE (SPEC_OCLS (etype)); + + /* if (SPEC_OCLS(etype)->codesp ) */ + /* p_type = CPOINTER ; */ + /* else */ + /* if (SPEC_OCLS(etype)->fmap && !SPEC_OCLS(etype)->paged) */ + /* p_type = FPOINTER ; */ + /* else */ + /* if (SPEC_OCLS(etype)->fmap && SPEC_OCLS(etype)->paged) */ + /* p_type = PPOINTER; */ + /* else */ + /* if (SPEC_OCLS(etype) == idata ) */ + /* p_type = IPOINTER ; */ + /* else */ + /* p_type = POINTER ; */ + } + + /* the first two bytes are known */ + DEBUGpic16_emitcode ("; ***", "%s %d - pointer cast2", __FUNCTION__, __LINE__); + size = GPTRSIZE - 1; + offset = 0; + while (size--) + { + if (offset < AOP_SIZE (right)) + { + DEBUGpic16_emitcode ("; ***", "%s %d - pointer cast3 ptype = 0x%x", __FUNCTION__, __LINE__, p_type); + pic16_mov2f (AOP (result), AOP (right), offset); + /* + if ((AOP_TYPE(right) == AOP_PCODE) && + AOP(right)->aopu.pcop->type == PO_IMMEDIATE) { + pic16_emitpcode(POC_MOVLW, pic16_popGet(AOP(right),offset)); + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),offset)); + } else { + + pic16_aopPut(AOP(result), + pic16_aopGet(AOP(right),offset,FALSE,FALSE), + offset); + } + */ + } + else + pic16_emitpcode (POC_CLRF, pic16_popGet (AOP (result), offset)); + offset++; + } + /* the last byte depending on type */ + switch (p_type) + { + case POINTER: + case FPOINTER: + case IPOINTER: + case PPOINTER: + pic16_movLit2f (pic16_popGet (AOP (result), GPTRSIZE - 1), GPTR_TAG_DATA); + break; + + case CPOINTER: + pic16_emitpcode (POC_MOVFF, pic16_popGet2 (AOP (right), AOP (result), GPTRSIZE - 1)); + break; + + case GPOINTER: + if (GPTRSIZE > AOP_SIZE (right)) + { + // assume __data pointer... THIS MIGHT BE WRONG! + pic16_movLit2f (pic16_popGet (AOP (result), GPTRSIZE - 1), GPTR_TAG_DATA); + } + else + { + pic16_emitpcode (POC_MOVFF, pic16_popGet2 (AOP (right), AOP (result), GPTRSIZE - 1)); + } + break; + + default: + /* this should never happen */ + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "got unknown pointer type"); + exit (1); + } + //pic16_aopPut(AOP(result),l, GPTRSIZE - 1); + goto release; + } + + + assert (0); + /* just copy the pointers */ + size = AOP_SIZE (result); + offset = 0; + while (size--) + { + pic16_aopPut (AOP (result), pic16_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. + Now, if the next iCode is an operator then we might be + able to optimize the operation without performing a cast. + */ + if (genMixedOperation (ic)) + goto release; + + DEBUGpic16_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__); + + /* we move to result for the size of source */ + size = AOP_SIZE (right); + offset = 0; + + while (size--) + { + if (!_G.resDirect) + pic16_mov2f (AOP (result), AOP (right), offset); + offset++; + } + + /* now depending on the sign of the destination */ + size = AOP_SIZE (result) - AOP_SIZE (right); + /* if unsigned or not an integral type */ + if (SPEC_USIGN (getSpec (rtype)) || !IS_SPEC (rtype)) + { + while (size--) + pic16_emitpcode (POC_CLRF, pic16_popGet (AOP (result), offset++)); + } + else + { + /* we need to extend the sign :( */ + + if (size == 1) + { + /* Save one instruction of casting char to int */ + pic16_emitpcode (POC_CLRF, pic16_popGet (AOP (result), offset)); + pic16_emitpcode (POC_BTFSC, + pic16_newpCodeOpBit (pic16_aopGet (AOP (right), offset - 1, FALSE, FALSE), 7, 0, PO_GPR_REGISTER)); + pic16_emitpcode (POC_SETF, pic16_popGet (AOP (result), offset)); + } + else + { + pic16_emitpcode (POC_CLRF, pic16_popCopyReg (&pic16_pc_wreg)); + + if (offset) + pic16_emitpcode (POC_BTFSC, + pic16_newpCodeOpBit (pic16_aopGet (AOP (right), offset - 1, FALSE, FALSE), 7, 0, PO_GPR_REGISTER)); + else + pic16_emitpcode (POC_BTFSC, + pic16_newpCodeOpBit (pic16_aopGet (AOP (right), offset, FALSE, FALSE), 7, 0, PO_GPR_REGISTER)); + + pic16_emitpcode (POC_MOVLW, pic16_popGetLit (0xff)); + + while (size--) + pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), offset++)); + } + } + +release: + pic16_freeAsmop (right, NULL, ic, TRUE); + pic16_freeAsmop (result, NULL, ic, TRUE); + +} + +/*-----------------------------------------------------------------*/ +/* genDjnz - generate decrement & jump if not zero instrucion */ +/*-----------------------------------------------------------------*/ +static int +genDjnz (iCode * ic, iCode * ifx) +{ + DEBUGpic16_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 */ + pic16_aopOp (IC_RESULT (ic), ic, FALSE); + + pic16_emitpcode (POC_DECFSZ, pic16_popGet (AOP (IC_RESULT (ic)), 0)); + pic16_emitpcode (POC_GOTO, pic16_popGetLabel (IC_TRUE (ifx)->key)); + + pic16_freeAsmop (IC_RESULT (ic), NULL, ic, TRUE); + ifx->generated = 1; + return 1; +} + +/*-----------------------------------------------------------------*/ +/* genReceive - generate code for a receive iCode */ +/*-----------------------------------------------------------------*/ +static void +genReceive (iCode * ic) +{ + + FENTRY; + +#if 0 + fprintf (stderr, "%s:%d %s for symbol %s\tonStack: %d\n", __FILE__, __LINE__, __FUNCTION__, + OP_SYMBOL (IC_RESULT (ic))->rname, OP_SYMBOL (IC_RESULT (ic))->onStack); +#endif +// pic16_DumpOp(__FUNCTION__, IC_RESULT(ic)); + + if (isOperandInFarSpace (IC_RESULT (ic)) && (OP_SYMBOL (IC_RESULT (ic))->isspilt || IS_TRUE_SYMOP (IC_RESULT (ic)))) + { + + int size = getSize (operandType (IC_RESULT (ic))); + int offset = pic16_fReturnSizePic - size; + + assert (0); + while (size--) + { + pic16_emitcode ("push", "%s", (strcmp (fReturn[pic16_fReturnSizePic - offset - 1], "a") ? + fReturn[pic16_fReturnSizePic - offset - 1] : "acc")); + offset++; + } + + DEBUGpic16_emitcode ("; ***", "1 %s %d", __FUNCTION__, __LINE__); + + pic16_aopOp (IC_RESULT (ic), ic, FALSE); + size = AOP_SIZE (IC_RESULT (ic)); + offset = 0; + while (size--) + { + pic16_emitcode ("pop", "acc"); + pic16_aopPut (AOP (IC_RESULT (ic)), "a", offset++); + } + } + else + { + DEBUGpic16_emitcode ("; ***", "2 %s %d argreg = %d", __FUNCTION__, __LINE__, + SPEC_ARGREG (OP_SYM_ETYPE (IC_RESULT (ic)))); + _G.accInUse++; + pic16_aopOp (IC_RESULT (ic), ic, FALSE); + _G.accInUse--; + + /* set pseudo stack pointer to where it should be - dw */ + GpseudoStkPtr = ic->parmBytes; + + /* setting GpseudoStkPtr has side effects here: */ + /* FIXME: What's the correct size of the return(ed) value? + * For now, assuming '4' as before... */ + assignResultValue (IC_RESULT (ic), 4, 0); + } + + pic16_freeAsmop (IC_RESULT (ic), NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genDummyRead - generate code for dummy read of volatiles */ +/*-----------------------------------------------------------------*/ +static void +genDummyRead (iCode * ic) +{ + operand *op; + + op = IC_RIGHT (ic); + if (op && IS_SYMOP (op)) + { + if (IN_CODESPACE (SPEC_OCLS (OP_SYM_ETYPE (op)))) + { + fprintf (stderr, "%s: volatile symbols in codespace?!? -- might go wrong...\n", __FUNCTION__); + return; + } + pic16_aopOp (op, ic, FALSE); + pic16_mov2w_volatile (AOP (op)); + pic16_freeAsmop (op, NULL, ic, TRUE); + } + else if (op) + { + fprintf (stderr, "%s: not implemented for non-symbols (volatile operand might not be read)\n", __FUNCTION__); + } // if +} + +/*-----------------------------------------------------------------*/ +/* genpic16Code - generate code for pic16 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 +genpic16Code (iCode * lic) +{ + iCode *ic; + int cln = 0; + + pb = pic16_newpCodeChain (GcurMemmap, 0, pic16_newpCodeCharP ("; Starting pCode block")); + pic16_addpBlock (pb); + +#if 0 + /* if debug information required */ + if (options.debug && currFunc) + { + if (currFunc) + { + cdbSymbol (currFunc, cdbFile, FALSE, TRUE); + } + } +#endif + + for (ic = lic; ic; ic = ic->next) + { + initGenLineElement (); + + DEBUGpic16_emitcode (";ic ", "\t%c 0x%x\t(%s)", ic->op, ic->op, pic16_decodeOp (ic->op)); + if (cln != ic->lineno) + { + if (options.debug) + { + debugFile->writeCLine (ic); + } + + if (!options.noCcodeInAsm) + { + pic16_addpCode2pBlock (pb, pic16_newpCodeCSource (ic->lineno, ic->filename, + printCLine (ic->filename, ic->lineno))); + } + + cln = ic->lineno; + } + + if (options.iCodeInAsm) + { + const char *iLine; + + /* insert here code to print iCode as comment */ + iLine = printILine (ic); + pic16_emitpcomment ("ic:%d: %s", ic->seq, iLine); + 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 '!': + pic16_genNot (ic); + break; + + case '~': + pic16_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 destroy 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 '+': + pic16_genPlus (ic); + break; + + case '-': + if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic))) + pic16_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: + pic16_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; + } + } + + + /* 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")); + pic16_printpBlock (stdout, pb); +#endif + + /* destroy the line list */ + destroy_line_list (); +} |
