summaryrefslogtreecommitdiff
path: root/src/pic16/gen.c
diff options
context:
space:
mode:
authorXavier ASUS <xavi92psx@gmail.com>2019-10-18 00:31:54 +0200
committerXavier ASUS <xavi92psx@gmail.com>2019-10-18 00:31:54 +0200
commit268a53de823a6750d6256ee1fb1e7707b4b45740 (patch)
tree42c1799a9a82b2f7d9790ee9fe181d72a7274751 /src/pic16/gen.c
downloadsdcc-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.c11583
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 ();
+}