sdcc-gas/src/pic16/genarith.c

2037 lines
73 KiB
C

/*-------------------------------------------------------------------------
genarith.c - source file for code generation - arithmetic
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
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 "SDCCglobl.h"
#include "newalloc.h"
#include "common.h"
#include "SDCCpeeph.h"
#include "ralloc.h"
#include "pcode.h"
#include "gen.h"
#if 1
#define pic16_emitcode DEBUGpic16_emitcode
#endif
extern void pic16_emitpLabelFORCE(int key);
#define BYTEofLONG(l,b) ( (l>> (b<<3)) & 0xff)
void DEBUGpic16_pic16_AopType(int line_no, operand *left, operand *right, operand *result);
void pic16_emitpcomment(char *, ...);
pCodeOp *pic16_popGet2p(pCodeOp *src, pCodeOp *dst);
const char *pic16_AopType(short type)
{
switch(type) {
case AOP_LIT: return "AOP_LIT";
case AOP_REG: return "AOP_REG";
case AOP_DIR: return "AOP_DIR";
case AOP_STK: return "AOP_STK";
case AOP_STR: return "AOP_STR";
case AOP_CRY: return "AOP_CRY";
case AOP_ACC: return "AOP_ACC";
case AOP_PCODE: return "AOP_PCODE";
case AOP_STA: return "AOP_STA";
}
return "BAD TYPE";
}
const char *pic16_pCodeOpType(pCodeOp *pcop)
{
if(pcop) {
switch(pcop->type) {
case PO_NONE: return "PO_NONE";
case PO_W: return "PO_W";
case PO_WREG: return "PO_WREG";
case PO_STATUS: return "PO_STATUS";
case PO_BSR: return "PO_BSR";
case PO_FSR0: return "PO_FSR0";
case PO_INDF0: return "PO_INDF0";
case PO_INTCON: return "PO_INTCON";
case PO_GPR_REGISTER: return "PO_GPR_REGISTER";
case PO_GPR_BIT: return "PO_GPR_BIT";
case PO_GPR_TEMP: return "PO_GPR_TEMP";
case PO_SFR_REGISTER: return "PO_SFR_REGISTER";
case PO_PCL: return "PO_PCL";
case PO_PCLATH: return "PO_PCLATH";
case PO_PCLATU: return "PO_PCLATU";
case PO_PRODL: return "PO_PRODL";
case PO_PRODH: return "PO_PRODH";
case PO_LITERAL: return "PO_LITERAL";
case PO_REL_ADDR: return "PO_REL_ADDR";
case PO_IMMEDIATE: return "PO_IMMEDIATE";
case PO_DIR: return "PO_DIR";
case PO_CRY: return "PO_CRY";
case PO_BIT: return "PO_BIT";
case PO_STR: return "PO_STR";
case PO_LABEL: return "PO_LABEL";
case PO_WILD: return "PO_WILD";
case PO_TWO_OPS: return "PO_TWO_OPS";
}
}
return "BAD PO_TYPE";
}
const char *pic16_pCodeOpSubType(pCodeOp *pcop)
{
if(pcop && (pcop->type == PO_GPR_BIT)) {
switch(PCORB(pcop)->subtype) {
case PO_NONE: return "PO_NONE";
case PO_W: return "PO_W";
case PO_WREG: return "PO_WREG";
case PO_STATUS: return "PO_STATUS";
case PO_BSR: return "PO_BSR";
case PO_FSR0: return "PO_FSR0";
case PO_INDF0: return "PO_INDF0";
case PO_INTCON: return "PO_INTCON";
case PO_GPR_REGISTER: return "PO_GPR_REGISTER";
case PO_GPR_BIT: return "PO_GPR_BIT";
case PO_GPR_TEMP: return "PO_GPR_TEMP";
case PO_SFR_REGISTER: return "PO_SFR_REGISTER";
case PO_PCL: return "PO_PCL";
case PO_PCLATH: return "PO_PCLATH";
case PO_PCLATU: return "PO_PCLATU";
case PO_PRODL: return "PO_PRODL";
case PO_PRODH: return "PO_PRODH";
case PO_LITERAL: return "PO_LITERAL";
case PO_REL_ADDR: return "PO_REL_ADDR";
case PO_IMMEDIATE: return "PO_IMMEDIATE";
case PO_DIR: return "PO_DIR";
case PO_CRY: return "PO_CRY";
case PO_BIT: return "PO_BIT";
case PO_STR: return "PO_STR";
case PO_LABEL: return "PO_LABEL";
case PO_WILD: return "PO_WILD";
case PO_TWO_OPS: return "PO_TWO_OPS";
}
}
return "BAD PO_TYPE";
}
/*-----------------------------------------------------------------*/
/* pic16_genPlusIncr :- does addition with increment if possible */
/*-----------------------------------------------------------------*/
bool pic16_genPlusIncr (iCode *ic)
{
unsigned int icount;
unsigned int size = pic16_getDataSize(IC_RESULT(ic));
FENTRY;
DEBUGpic16_emitcode ("; ","result %s, left %s, right %s",
pic16_AopType(AOP_TYPE(IC_RESULT(ic))),
pic16_AopType(AOP_TYPE(IC_LEFT(ic))),
pic16_AopType(AOP_TYPE(IC_RIGHT(ic))));
/* will try to generate an increment */
/* if the right side is not a literal
we cannot */
if (AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
{
return FALSE;
}
DEBUGpic16_emitcode ("; ","%s %d",__FUNCTION__,__LINE__);
/* if the literal value of the right hand side
is greater than 2 then it is faster to add */
if ((icount = (unsigned int)ulFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit)) > 2)
{
return FALSE;
}
/* if increment 16 bits in register */
if (pic16_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) && icount == 1)
{
int offset = LSB;
switch (size)
{
case 2:
pic16_emitpcode(POC_INFSNZ, pic16_popGet(AOP(IC_RESULT(ic)), offset++));
case 1:
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(IC_RESULT(ic)), offset));
break;
default:
{
symbol *inclbl = newiTempLabel(NULL);
pCodeOp *pcop_lbl = pic16_popGetLabel(inclbl->key);
int label_use = 0;
size -= 2;
if (size)
{
label_use = 1;
}
while (size--)
{
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(IC_RESULT(ic)), offset++));
pic16_emitpcode(POC_BNC, pcop_lbl);
}
pic16_emitpcode(POC_INFSNZ, pic16_popGet(AOP(IC_RESULT(ic)), offset++));
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(IC_RESULT(ic)), offset));
if (label_use)
{
pic16_emitpLabelFORCE(inclbl->key);
}
}
} // switch (size)
return TRUE;
}
// DEBUGpic16_emitcode ("; ","%s %d",__FUNCTION__,__LINE__);
/* if left is in accumulator - probably a bit operation*/ // VR - why this is a bit operation?!
if( (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC) &&
(AOP_TYPE(IC_RESULT(ic)) == AOP_CRY) ) {
pic16_emitpcode(POC_BCF, pic16_popGet(AOP(IC_RESULT(ic)),0));
if(icount)
pic16_emitpcode(POC_XORLW,pic16_popGetLit(1));
//pic16_emitcode("xorlw","1");
else
pic16_emitpcode(POC_ANDLW,pic16_popGetLit(1));
//pic16_emitcode("andlw","1");
emitSKPZ;
pic16_emitpcode(POC_BSF, pic16_popGet(AOP(IC_RESULT(ic)),0));
return TRUE;
}
/* if the sizes are greater than 1 then we cannot */
if (AOP_SIZE(IC_RESULT(ic)) > 1 ||
AOP_SIZE(IC_LEFT(ic)) > 1 )
return FALSE ;
/* If we are incrementing the same register by two: */
if (pic16_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) {
while (icount--)
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(IC_RESULT(ic)),0));
//pic16_emitcode("incf","%s,f",pic16_aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE));
return TRUE ;
}
DEBUGpic16_emitcode ("; ","couldn't increment ");
return FALSE ;
}
/*-----------------------------------------------------------------*/
/* pic16_outBitAcc - output a bit in acc */
/*-----------------------------------------------------------------*/
void pic16_outBitAcc(operand *result)
{
symbol *tlbl = newiTempLabel(NULL);
/* if the result is a bit */
DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
assert(0); // not implemented for PIC16?
if (AOP_TYPE(result) == AOP_CRY){
pic16_aopPut(AOP(result),"a",0);
}
else {
pic16_emitcode("jz","%05d_DS_",tlbl->key+100);
pic16_emitcode("mov","a,#01");
pic16_emitcode("","%05d_DS_:",tlbl->key+100);
pic16_outAcc(result);
}
}
/*-----------------------------------------------------------------*/
/* pic16_genPlusBits - generates code for addition of two bits */
/*-----------------------------------------------------------------*/
void pic16_genPlusBits (iCode *ic)
{
FENTRY;
DEBUGpic16_emitcode ("; ","result %s, left %s, right %s",
pic16_AopType(AOP_TYPE(IC_RESULT(ic))),
pic16_AopType(AOP_TYPE(IC_LEFT(ic))),
pic16_AopType(AOP_TYPE(IC_RIGHT(ic))));
/*
The following block of code will add two bits.
Note that it'll even work if the destination is
the carry (C in the status register).
It won't work if the 'Z' bit is a source or destination.
*/
/* If the result is stored in the accumulator (w) */
//if(strcmp(pic16_aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE),"a") == 0 ) {
switch(AOP_TYPE(IC_RESULT(ic))) {
case AOP_ACC:
pic16_emitpcode(POC_CLRF, pic16_popCopyReg(&pic16_pc_wreg));
pic16_emitpcode(POC_BTFSC, pic16_popGet(AOP(IC_RIGHT(ic)),0));
pic16_emitpcode(POC_XORLW, pic16_popGetLit(1));
pic16_emitpcode(POC_BTFSC, pic16_popGet(AOP(IC_LEFT(ic)),0));
pic16_emitpcode(POC_XORLW, pic16_popGetLit(1));
break;
case AOP_REG:
pic16_emitpcode(POC_MOVLW, pic16_popGetLit(0));
pic16_emitpcode(POC_BTFSC, pic16_popGet(AOP(IC_RIGHT(ic)),0));
pic16_emitpcode(POC_XORLW, pic16_popGetLit(1));
pic16_emitpcode(POC_BTFSC, pic16_popGet(AOP(IC_LEFT(ic)),0));
pic16_emitpcode(POC_XORLW, pic16_popGetLit(1));
pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(IC_RESULT(ic)),0));
break;
default:
pic16_emitpcode(POC_MOVLW, pic16_popGet(AOP(IC_RESULT(ic)),0));
pic16_emitpcode(POC_BCF, pic16_popGet(AOP(IC_RESULT(ic)),0));
pic16_emitpcode(POC_BTFSC, pic16_popGet(AOP(IC_RIGHT(ic)),0));
pic16_emitpcode(POC_XORWF, pic16_popGet(AOP(IC_RESULT(ic)),0));
pic16_emitpcode(POC_BTFSC, pic16_popGet(AOP(IC_LEFT(ic)),0));
pic16_emitpcode(POC_XORWF, pic16_popGet(AOP(IC_RESULT(ic)),0));
break;
}
}
#if 0
/* This is the original version of this code.
*
* This is being kept around for reference,
* because I am not entirely sure I got it right...
*/
static void adjustArithmeticResult(iCode *ic)
{
if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
AOP_SIZE(IC_LEFT(ic)) == 3 &&
!pic16_sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))))
pic16_aopPut(AOP(IC_RESULT(ic)),
pic16_aopGet(AOP(IC_LEFT(ic)),2,FALSE,FALSE),
2);
if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
AOP_SIZE(IC_RIGHT(ic)) == 3 &&
!pic16_sameRegs(AOP(IC_RESULT(ic)),AOP(IC_RIGHT(ic))))
pic16_aopPut(AOP(IC_RESULT(ic)),
pic16_aopGet(AOP(IC_RIGHT(ic)),2,FALSE,FALSE),
2);
if (AOP_SIZE(IC_RESULT(ic)) == 3 &&
AOP_SIZE(IC_LEFT(ic)) < 3 &&
AOP_SIZE(IC_RIGHT(ic)) < 3 &&
!pic16_sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))) &&
!pic16_sameRegs(AOP(IC_RESULT(ic)),AOP(IC_RIGHT(ic)))) {
char buffer[5];
SNPRINTF(buffer, sizeof(buffer), "#%d", pointerCode(getSpec(operandType(IC_LEFT(ic)))));
pic16_aopPut(AOP(IC_RESULT(ic)),buffer,2);
}
}
//#else
/* This is the pure and virtuous version of this code.
* I'm pretty certain it's right, but not enough to toss the old
* code just yet...
*/
static void adjustArithmeticResult(iCode *ic)
{
if (opIsGptr(IC_RESULT(ic)) &&
opIsGptr(IC_LEFT(ic)) &&
!pic16_sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))))
{
pic16_aopPut(AOP(IC_RESULT(ic)),
pic16_aopGet(AOP(IC_LEFT(ic)), GPTRSIZE - 1,FALSE,FALSE),
GPTRSIZE - 1);
}
if (opIsGptr(IC_RESULT(ic)) &&
opIsGptr(IC_RIGHT(ic)) &&
!pic16_sameRegs(AOP(IC_RESULT(ic)),AOP(IC_RIGHT(ic))))
{
pic16_aopPut(AOP(IC_RESULT(ic)),
pic16_aopGet(AOP(IC_RIGHT(ic)),GPTRSIZE - 1,FALSE,FALSE),
GPTRSIZE - 1);
}
if (opIsGptr(IC_RESULT(ic)) &&
AOP_SIZE(IC_LEFT(ic)) < GPTRSIZE &&
AOP_SIZE(IC_RIGHT(ic)) < GPTRSIZE &&
!pic16_sameRegs(AOP(IC_RESULT(ic)),AOP(IC_LEFT(ic))) &&
!pic16_sameRegs(AOP(IC_RESULT(ic)),AOP(IC_RIGHT(ic)))) {
char buffer[5];
SNPRINTF(buffer, sizeof(buffer), "#%d", pointerCode(getSpec(operandType(IC_LEFT(ic)))));
pic16_aopPut(AOP(IC_RESULT(ic)),buffer,GPTRSIZE - 1);
}
}
#endif
#if 1
/*-----------------------------------------------------------------*/
/* genAddlit - generates code for addition */
/*-----------------------------------------------------------------*/
static void genAddLit2byte (operand *result, int offr, int lit)
{
FENTRY;
switch(lit & 0xff)
{
case 0:
break;
case 1:
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),offr));
break;
case 0xff:
pic16_emitpcode(POC_DECF, pic16_popGet(AOP(result),offr));
break;
default:
{
int resultIsWREG = (AOP_TYPE(result) != AOP_STA && ! strcmp(pic16_aopGet(AOP(result), 0, TRUE, FALSE), "WREG"));
if (resultIsWREG)
{
pic16_emitpcode(POC_ADDLW, pic16_popGetLit(lit & 0xff));
}
else
{
pic16_emitpcode(POC_MOVLW,pic16_popGetLit(lit & 0xff));
pic16_emitpcode(POC_ADDWF,pic16_popGet(AOP(result),offr));
}
}
}
}
#endif
static void emitMOVWF(operand *reg, int offset)
{
if(!reg)
return;
if (AOP_TYPE(reg) == AOP_ACC) {
DEBUGpic16_emitcode ("; ***","%s %d ignoring mov into W",__FUNCTION__,__LINE__);
return;
}
pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(reg),offset));
}
#if 1
static void genAddLit (iCode *ic, int lit)
{
int size,same;
int lo, offset;
operand *result;
operand *left;
FENTRY;
left = IC_LEFT(ic);
result = IC_RESULT(ic);
same = pic16_sameRegs(AOP(left), AOP(result));
size = pic16_getDataSize(result);
if ((AOP_PCODE == AOP_TYPE(left))
&& (PO_IMMEDIATE == AOP(left)->aopu.pcop->type))
{
/* see #1888004 for an example case for this */
for (offset = 0; offset < size; offset++) {
pic16_emitpcode(POC_MOVLW, pic16_newpCodeOpImmd(AOP(left)->aopu.pcop->name,
offset, PCOI(AOP(left)->aopu.pcop)->index + lit, 0));
pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result), offset));
} // for
return;
} // if
if(same) {
/* Handle special cases first */
if(size == 1)
genAddLit2byte (result, 0, lit);
else if(size == 2) {
int hi = 0xff & (lit >> 8);
lo = lit & 0xff;
switch(hi) {
case 0:
/* lit = 0x00LL */
DEBUGpic16_emitcode ("; hi = 0","%s %d",__FUNCTION__,__LINE__);
switch(lo) {
case 0:
break;
case 1:
pic16_emitpcode(POC_INFSNZ, pic16_popGet(AOP(result),0));
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),MSB16));
break;
case 0xff:
pic16_emitpcode(POC_DECF, pic16_popGet(AOP(result),0));
pic16_emitpcode(POC_INCFSZW, pic16_popGet(AOP(result),0));
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),MSB16));
break;
default:
pic16_emitpcode(POC_MOVLW,pic16_popGetLit(lit&0xff));
pic16_emitpcode(POC_ADDWF,pic16_popGet(AOP(result),0));
emitSKPNC;
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),MSB16));
}
break;
case 1:
/* lit = 0x01LL */
DEBUGpic16_emitcode ("; hi = 1","%s %d",__FUNCTION__,__LINE__);
switch(lo) {
case 0: /* 0x0100 */
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),MSB16));
break;
case 1: /* 0x0101 */
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),MSB16));
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),0));
emitSKPNZ;
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),MSB16));
break;
case 0xff: /* 0x01ff */
pic16_emitpcode(POC_DECF, pic16_popGet(AOP(result),0));
pic16_emitpcode(POC_INCFSZW, pic16_popGet(AOP(result),0));
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),MSB16));
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),MSB16));
break;
default: /* 0x01LL */
pic16_emitpcode(POC_MOVLW,pic16_popGetLit(lo));
pic16_emitpcode(POC_ADDWF,pic16_popGet(AOP(result),0));
emitSKPNC;
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),MSB16));
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),MSB16));
}
break;
case 0xff:
DEBUGpic16_emitcode ("; hi = ff","%s %d",__FUNCTION__,__LINE__);
/* lit = 0xffLL */
switch(lo) {
case 0: /* 0xff00 */
pic16_emitpcode(POC_DECF, pic16_popGet(AOP(result),MSB16));
break;
case 1: /*0xff01 */
pic16_emitpcode(POC_INCFSZ, pic16_popGet(AOP(result),0));
pic16_emitpcode(POC_DECF, pic16_popGet(AOP(result),MSB16));
break;
case 0xff: /* 0xffff */
pic16_emitpcode(POC_MOVLW, pic16_popGetLit(lo));
pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(result),0));
pic16_emitpcode(POC_ADDWFC, pic16_popGet(AOP(result),MSB16));
break;
default:
pic16_emitpcode(POC_MOVLW,pic16_popGetLit(lo));
pic16_emitpcode(POC_ADDWF,pic16_popGet(AOP(result),0));
emitSKPC;
pic16_emitpcode(POC_DECF, pic16_popGet(AOP(result),MSB16));
}
break;
default:
DEBUGpic16_emitcode ("; hi is generic","%d %s %d",hi,__FUNCTION__,__LINE__);
/* lit = 0xHHLL */
switch(lo) {
case 0: /* 0xHH00 */
genAddLit2byte (result, MSB16, hi);
break;
case 1: /* 0xHH01 */
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),0));
pic16_emitpcode(POC_MOVLW,pic16_popGetLit(hi));
pic16_emitpcode(POC_ADDWFC,pic16_popGet(AOP(result),MSB16));
break;
/* case 0xff: * 0xHHff *
pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(result),0,FALSE,FALSE));
pic16_emitpcode(POC_DECF, pic16_popGet(AOP(result),MSB16,FALSE,FALSE));
pic16_emitpcode(POC_MOVLW,pic16_popGetLit(hi));
pic16_emitpcode(POC_ADDWF,pic16_popGet(AOP(result),MSB16,FALSE,FALSE));
break;
*/ default: /* 0xHHLL */
pic16_emitpcode(POC_MOVLW,pic16_popGetLit(lo));
pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(result),0));
pic16_emitpcode(POC_MOVLW,pic16_popGetLit(hi));
pic16_emitpcode(POC_ADDWFC,pic16_popGet(AOP(result),MSB16));
break;
}
}
} else {
int carry_info = 0;
int prev_W = -1;
/* size > 2 */
DEBUGpic16_emitcode ("; add lit to long","%s %d",__FUNCTION__,__LINE__);
offset = 0;
while (size--)
{
lo = BYTEofLONG(lit,0);
if (carry_info)
{
if (prev_W != (lo & 0xFF))
{
pic16_emitpcode(POC_MOVLW, pic16_popGetLit(lo));
prev_W = lo & 0xFF;
}
pic16_emitpcode(POC_ADDWFC, pic16_popGet(AOP(result),offset));
}
else {
/* no carry info from previous step */
/* this means this is the first time to add */
switch (lo)
{
case 0:
break;
case 1:
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),offset));
carry_info = 1;
break;
default:
{
if (prev_W != (lo & 0xFF))
{
pic16_emitpcode(POC_MOVLW, pic16_popGetLit(lo));
prev_W = lo & 0xFF;
}
pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(result),offset));
if (lit < 0x100)
carry_info = 3; /* Were adding only one byte and propogating the carry. */
else
carry_info = 2;
break;
}
}
}
offset++;
lit >>= 8;
}
/*
lo = BYTEofLONG(lit,0);
if(lit < 0x100) {
if(lo) {
if(lo == 1) {
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),0,FALSE,FALSE));
emitSKPNZ;
} else {
pic16_emitpcode(POC_MOVLW,pic16_popGetLit(lo));
pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(result),0,FALSE,FALSE));
emitSKPNC;
}
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),1,FALSE,FALSE));
emitSKPNZ;
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),2,FALSE,FALSE));
emitSKPNZ;
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),3,FALSE,FALSE));
}
}
*/
}
} else {
int offset = 1;
DEBUGpic16_emitcode ("; left and result aren't same","%s %d",__FUNCTION__,__LINE__);
if(size == 1) {
if(AOP_TYPE(left) == AOP_ACC) {
/* left addend is already in accumulator */
switch(lit & 0xff) {
case 0:
//pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),0,FALSE,FALSE));
emitMOVWF(result,0);
break;
default:
pic16_emitpcode(POC_ADDLW, pic16_popGetLit(lit & 0xff));
//pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),0,FALSE,FALSE));
emitMOVWF(result,0);
}
} else {
/* left addend is in a register */
switch(lit & 0xff) {
case 0:
pic16_mov2w(AOP(left),0);
emitMOVWF(result, 0);
break;
case 1:
pic16_emitpcode(POC_INCFW, pic16_popGet(AOP(left),0));
//pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),0,FALSE,FALSE));
emitMOVWF(result,0);
break;
case 0xff:
pic16_emitpcode(POC_DECFW, pic16_popGet(AOP(left),0));
//pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),0,FALSE,FALSE));
emitMOVWF(result,0);
break;
default:
pic16_emitpcode(POC_MOVLW, pic16_popGetLit(lit & 0xff));
pic16_emitpcode(POC_ADDFW, pic16_popGet(AOP(left),0));
//pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),0,FALSE,FALSE));
emitMOVWF(result,0);
}
}
// } else if (pic16_isLitAop(AOP(left))) {
// // adding two literals
// assert ( !"adding two literals is not yet supported" );
} else {
int clear_carry=0;
/* left is not the accumulator */
if(lit & 0xff) {
pic16_mov2w(AOP(left),0);
pic16_emitpcode(POC_ADDLW, pic16_popGetLit(lit & 0xff));
} else {
pic16_mov2w(AOP(left),0);
/* We don't know the state of the carry bit at this point */
clear_carry = 1;
}
//pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),0,FALSE,FALSE));
emitMOVWF(result,0);
while(--size) {
lit >>= 8;
pic16_emitpcode(POC_MOVLW, pic16_popGetLit(lit & 0xff));
if (offset < AOP_SIZE(left)) {
pic16_emitpcode(clear_carry ? POC_ADDFW : POC_ADDFWC, pic16_popGet(AOP(left),offset));
pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),offset));
} else {
pic16_emitpcode(POC_CLRF, pic16_popGet(AOP(result),offset));
if (!SPEC_USIGN(operandType(IC_LEFT(ic)))) {
/* sign-extend left (in result) */
pic16_emitpcode (POC_BTFSC, pic16_newpCodeOpBit_simple(AOP(left),AOP_SIZE(left)-1,7));
pic16_emitpcode(POC_SETF, pic16_popGet(AOP(result),offset));
}
pic16_emitpcode(clear_carry ? POC_ADDWF : POC_ADDWFC, pic16_popGet(AOP(result),offset));
}
clear_carry = 0;
offset++;
}
}
}
}
#else
/* this fails when result is an SFR because value is written there
* during addition and not at the end */
static void genAddLit (iCode *ic, int lit)
{
int size,sizeL,same;
int i, llit, prev_W;
operand *result;
operand *left;
FENTRY;
left = IC_LEFT(ic);
result = IC_RESULT(ic);
same = pic16_sameRegs(AOP(left), AOP(result));
size = pic16_getDataSize(result);
sizeL = pic16_getDataSize(left);
llit = lit;
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
/* move left to result -- possibly sign extend */
for (i=0; i < MIN(size, sizeL); i++) {
pic16_mov2f (AOP(result), AOP(left), i);
} // for i
#undef MIN
/* extend to result size */
pic16_addSign(result, sizeL, !IS_UNSIGNED(operandType(left)));
/* special cases */
if (lit == 0) {
/* nothing to do */
} else if (lit == 1) {
switch (size) {
case 1:
/* handled below */
break;
case 2:
pic16_emitpcode (POC_INFSNZ, pic16_popGet (AOP(result), 0));
break;
default:
assert (size > 2);
pic16_emitpcode (POC_INCF, pic16_popGet(AOP(result), 0));
for (i=1; i < size-1; i++) {
emitSKPNC; /* a jump here saves up to 2(size-2)cycles */
pic16_emitpcode (POC_INCF, pic16_popGet(AOP(result), i));
} // for i
emitSKPNC;
break;
} // switch
pic16_emitpcode (POC_INCF, pic16_popGet (AOP(result), size-1));
} else {
/* general case */
/* add literal to result */
prev_W = -1;
for (i = 0; i < size; i++)
{
if (prev_W != (llit & 0xFF))
{
pic16_emitpcode(POC_MOVLW, pic16_popGetLit(llit));
prev_W = llit & 0xFF;
}
llit >>= 8; /* FIXME: arithmetic right shift for signed literals? */
pic16_emitpcode(i == 0 ? POC_ADDWF : POC_ADDWFC, pic16_popGet(AOP(result), i));
}
}
#if 0
if(same) {
/* Handle special cases first */
if(size == 1)
genAddLit2byte (result, 0, lit);
else if(size == 2) {
int hi = 0xff & (lit >> 8);
lo = lit & 0xff;
switch(hi) {
case 0:
/* lit = 0x00LL */
DEBUGpic16_emitcode ("; hi = 0","%s %d",__FUNCTION__,__LINE__);
switch(lo) {
case 0:
break;
case 1:
pic16_emitpcode(POC_INFSNZ, pic16_popGet(AOP(result),0));
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),MSB16));
break;
case 0xff:
pic16_emitpcode(POC_DECF, pic16_popGet(AOP(result),0));
pic16_emitpcode(POC_INCFSZW, pic16_popGet(AOP(result),0));
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),MSB16));
break;
default:
pic16_emitpcode(POC_MOVLW,pic16_popGetLit(lit&0xff));
pic16_emitpcode(POC_ADDWF,pic16_popGet(AOP(result),0));
emitSKPNC;
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),MSB16));
}
break;
case 1:
/* lit = 0x01LL */
DEBUGpic16_emitcode ("; hi = 1","%s %d",__FUNCTION__,__LINE__);
switch(lo) {
case 0: /* 0x0100 */
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),MSB16));
break;
case 1: /* 0x0101 */
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),MSB16));
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),0));
emitSKPNZ;
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),MSB16));
break;
case 0xff: /* 0x01ff */
pic16_emitpcode(POC_DECF, pic16_popGet(AOP(result),0));
pic16_emitpcode(POC_INCFSZW, pic16_popGet(AOP(result),0));
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),MSB16));
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),MSB16));
break;
default: /* 0x01LL */
pic16_emitpcode(POC_MOVLW,pic16_popGetLit(lo));
pic16_emitpcode(POC_ADDWF,pic16_popGet(AOP(result),0));
emitSKPNC;
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),MSB16));
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),MSB16));
}
break;
case 0xff:
DEBUGpic16_emitcode ("; hi = ff","%s %d",__FUNCTION__,__LINE__);
/* lit = 0xffLL */
switch(lo) {
case 0: /* 0xff00 */
pic16_emitpcode(POC_DECF, pic16_popGet(AOP(result),MSB16));
break;
case 1: /*0xff01 */
pic16_emitpcode(POC_INCFSZ, pic16_popGet(AOP(result),0));
pic16_emitpcode(POC_DECF, pic16_popGet(AOP(result),MSB16));
break;
/* case 0xff: * 0xffff *
pic16_emitpcode(POC_INCFSZW, pic16_popGet(AOP(result),0,FALSE,FALSE));
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),MSB16,FALSE,FALSE));
pic16_emitpcode(POC_DECF, pic16_popGet(AOP(result),0,FALSE,FALSE));
break;
*/
default:
pic16_emitpcode(POC_MOVLW,pic16_popGetLit(lo));
pic16_emitpcode(POC_ADDWF,pic16_popGet(AOP(result),0));
emitSKPC;
pic16_emitpcode(POC_DECF, pic16_popGet(AOP(result),MSB16));
}
break;
default:
DEBUGpic16_emitcode ("; hi is generic","%d %s %d",hi,__FUNCTION__,__LINE__);
/* lit = 0xHHLL */
switch(lo) {
case 0: /* 0xHH00 */
genAddLit2byte (result, MSB16, hi);
break;
case 1: /* 0xHH01 */
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),0));
pic16_emitpcode(POC_MOVLW,pic16_popGetLit(hi));
pic16_emitpcode(POC_ADDWFC,pic16_popGet(AOP(result),MSB16));
break;
/* case 0xff: * 0xHHff *
pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(result),0,FALSE,FALSE));
pic16_emitpcode(POC_DECF, pic16_popGet(AOP(result),MSB16,FALSE,FALSE));
pic16_emitpcode(POC_MOVLW,pic16_popGetLit(hi));
pic16_emitpcode(POC_ADDWF,pic16_popGet(AOP(result),MSB16,FALSE,FALSE));
break;
*/ default: /* 0xHHLL */
pic16_emitpcode(POC_MOVLW,pic16_popGetLit(lo));
pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(result),0));
pic16_emitpcode(POC_MOVLW,pic16_popGetLit(hi));
pic16_emitpcode(POC_ADDWFC,pic16_popGet(AOP(result),MSB16));
break;
}
}
} else {
int carry_info = 0;
int offset = 0;
/* size > 2 */
DEBUGpic16_emitcode ("; add lit to long","%s %d",__FUNCTION__,__LINE__);
while(size--) {
lo = BYTEofLONG(lit,0);
if(carry_info) {
pic16_emitpcode(POC_MOVLW,pic16_popGetLit(lo));
pic16_emitpcode(POC_ADDWFC, pic16_popGet(AOP(result),offset));
}else {
/* no carry info from previous step */
/* this means this is the first time to add */
switch(lo) {
case 0:
break;
case 1:
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),offset));
carry_info=1;
break;
default:
pic16_emitpcode(POC_MOVLW,pic16_popGetLit(lo));
pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(result),offset));
if(lit <0x100)
carry_info = 3; /* Were adding only one byte and propogating the carry */
else
carry_info = 2;
break;
}
}
offset++;
lit >>= 8;
}
/*
lo = BYTEofLONG(lit,0);
if(lit < 0x100) {
if(lo) {
if(lo == 1) {
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),0,FALSE,FALSE));
emitSKPNZ;
} else {
pic16_emitpcode(POC_MOVLW,pic16_popGetLit(lo));
pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(result),0,FALSE,FALSE));
emitSKPNC;
}
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),1,FALSE,FALSE));
emitSKPNZ;
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),2,FALSE,FALSE));
emitSKPNZ;
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),3,FALSE,FALSE));
}
}
*/
}
} else {
int offset = 1;
DEBUGpic16_emitcode ("; left and result aren't same","%s %d",__FUNCTION__,__LINE__);
if(size == 1) {
if(AOP_TYPE(left) == AOP_ACC) {
/* left addend is already in accumulator */
switch(lit & 0xff) {
case 0:
//pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),0,FALSE,FALSE));
emitMOVWF(result,0);
break;
default:
pic16_emitpcode(POC_ADDLW, pic16_popGetLit(lit & 0xff));
//pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),0,FALSE,FALSE));
emitMOVWF(result,0);
}
} else {
/* left addend is in a register */
switch(lit & 0xff) {
case 0:
pic16_mov2w(AOP(left),0);
emitMOVWF(result, 0);
break;
case 1:
pic16_emitpcode(POC_INCFW, pic16_popGet(AOP(left),0));
//pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),0,FALSE,FALSE));
emitMOVWF(result,0);
break;
case 0xff:
pic16_emitpcode(POC_DECFW, pic16_popGet(AOP(left),0));
//pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),0,FALSE,FALSE));
emitMOVWF(result,0);
break;
default:
pic16_emitpcode(POC_MOVLW, pic16_popGetLit(lit & 0xff));
pic16_emitpcode(POC_ADDFW, pic16_popGet(AOP(left),0));
//pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),0,FALSE,FALSE));
emitMOVWF(result,0);
}
}
} else {
int clear_carry=0;
/* left is not the accumulator */
if(lit & 0xff) {
pic16_emitpcode(POC_MOVLW, pic16_popGetLit(lit & 0xff));
pic16_emitpcode(POC_ADDFW, pic16_popGet(AOP(left),0));
} else {
pic16_mov2w(AOP(left),0);
/* We don't know the state of the carry bit at this point */
clear_carry = 1;
}
//pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),0,FALSE,FALSE));
emitMOVWF(result,0);
while(--size) {
lit >>= 8;
if(lit & 0xff) {
if(clear_carry) {
/* The ls byte of the lit must've been zero - that
means we don't have to deal with carry */
pic16_emitpcode(POC_MOVLW, pic16_popGetLit(lit & 0xff));
pic16_emitpcode(POC_ADDFW, pic16_popGet(AOP(left),offset));
pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),offset));
clear_carry = 0;
} else {
pic16_emitpcode(POC_MOVLW, pic16_popGetLit(lit & 0xff));
pic16_emitpcode(POC_ADDFWC, pic16_popGet(AOP(left),offset));
pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),offset));
}
} else {
pic16_emitpcode(POC_CLRF, pic16_popGet(AOP(result),offset));
pic16_mov2w(AOP(left),offset);
pic16_emitpcode(POC_ADDWFC, pic16_popGet(AOP(result),offset));
}
offset++;
}
}
}
#endif
}
#endif
/*-----------------------------------------------------------------*/
/* pic16_genPlus - generates code for addition */
/*-----------------------------------------------------------------*/
void pic16_genPlus (iCode *ic)
{
int i, size, offset = 0;
operand *result, *left, *right;
FENTRY;
/* special cases :- */
result = IC_RESULT(ic);
left = IC_LEFT(ic);
right = IC_RIGHT(ic);
pic16_aopOp (left,ic,FALSE);
pic16_aopOp (right,ic,FALSE);
pic16_aopOp (result,ic,TRUE);
DEBUGpic16_pic16_AopType(__LINE__,left, right, result);
// pic16_DumpOp("(left)",left);
/* if literal, literal on the right or
if left requires ACC or right is already
in ACC */
if ( (AOP_TYPE(left) == AOP_LIT) || (pic16_sameRegs(AOP(right), AOP(result))) ) {
operand *t = right;
right = IC_RIGHT(ic) = left;
left = IC_LEFT(ic) = t;
}
/* if both left & right are in bit space */
if (AOP_TYPE(left) == AOP_CRY &&
AOP_TYPE(right) == AOP_CRY) {
pic16_genPlusBits (ic);
goto release ;
}
/* if left in bit space & right literal */
if (AOP_TYPE(left) == AOP_CRY &&
AOP_TYPE(right) == AOP_LIT) {
/* if result in bit space */
if(AOP_TYPE(result) == AOP_CRY){
if(ulFromVal (AOP(right)->aopu.aop_lit) != 0L) {
pic16_emitpcode(POC_MOVLW, pic16_popGet(AOP(result),0));
if (!pic16_sameRegs(AOP(left), AOP(result)) )
pic16_emitpcode(POC_BTFSC, pic16_popGet(AOP(left),0));
pic16_emitpcode(POC_XORWF, pic16_popGet(AOP(result),0));
}
} else {
unsigned long lit = ulFromVal (AOP(right)->aopu.aop_lit);
size = pic16_getDataSize(result);
while (size--) {
pic16_emitpcode (POC_CLRF, pic16_popGet (AOP(result), offset));
pic16_emitpcode (POC_MOVLW, pic16_popGetLit ((lit >> (8*offset)) & 0xFF));
pic16_emitpcode (POC_ADDWFC, pic16_popGet(AOP(result), offset++));
//MOVA(pic16_aopGet(AOP(right),offset,FALSE,FALSE));
//pic16_emitcode("addc","a,#00 ;%d",__LINE__);
//pic16_aopPut(AOP(result),"a",offset++);
}
}
goto release ;
} // left == CRY
/* if I can do an increment instead
of add then GOOD for ME */
if (pic16_genPlusIncr (ic) == TRUE)
goto release;
size = pic16_getDataSize(result);
if(AOP(right)->type == AOP_LIT) {
/* Add a literal to something else */
//bool know_W=0;
unsigned lit = (unsigned) ulFromVal (AOP(right)->aopu.aop_lit);
//unsigned l1=0;
//offset = 0;
DEBUGpic16_emitcode(";","adding lit to something. size %d",size);
genAddLit (ic, lit);
goto release;
} else if(AOP_TYPE(right) == AOP_CRY) {
pic16_emitcode(";bitadd","right is bit: %s",pic16_aopGet(AOP(right),0,FALSE,FALSE));
pic16_emitcode(";bitadd","left is bit: %s",pic16_aopGet(AOP(left),0,FALSE,FALSE));
pic16_emitcode(";bitadd","result is bit: %s",pic16_aopGet(AOP(result),0,FALSE,FALSE));
/* here we are adding a bit to a char or int */
if(size == 1) {
if (pic16_sameRegs(AOP(left), AOP(result)) ) {
pic16_emitpcode(POC_BTFSC , pic16_popGet(AOP(right),0));
pic16_emitpcode(POC_INCF , pic16_popGet(AOP(result),0));
} else { // not same
if(AOP_TYPE(left) == AOP_ACC) {
pic16_emitpcode(POC_BTFSC , pic16_popGet(AOP(right),0));
pic16_emitpcode(POC_XORLW , pic16_popGetLit(1));
} else {
pic16_mov2w(AOP(left),0);
pic16_emitpcode(POC_BTFSC , pic16_popGet(AOP(right),0));
pic16_emitpcode(POC_INCFW , pic16_popGet(AOP(left),0));
}
if(AOP_TYPE(result) != AOP_ACC) {
if(AOP_TYPE(result) == AOP_CRY) {
pic16_emitpcode(POC_ANDLW , pic16_popGetLit(1));
pic16_emitpcode(POC_BCF , pic16_popGet(AOP(result),0));
emitSKPZ;
pic16_emitpcode(POC_BSF , pic16_popGet(AOP(result),0));
} else {
pic16_emitpcode(POC_MOVWF , pic16_popGet(AOP(result),0));
}
}
}
} else {
int offset = 1;
DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
if (pic16_sameRegs(AOP(left), AOP(result)) ) {
emitCLRZ;
pic16_emitpcode(POC_BTFSC, pic16_popGet(AOP(right),0));
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),0));
} else {
emitCLRZ; // needed here as well: INCFW is not always executed, Z is undefined then
pic16_mov2w(AOP(left),0);
pic16_emitpcode(POC_BTFSC, pic16_popGet(AOP(right),0));
pic16_emitpcode(POC_INCFW, pic16_popGet(AOP(left),0));
emitMOVWF(right,0);
}
while(--size){
emitSKPZ;
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),offset++));
}
}
} else {
// add bytes
// Note: the following is an example of WISC code, eg.
// it's supposed to run on a Weird Instruction Set Computer :o)
DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
if ( AOP_TYPE(left) == AOP_ACC) {
DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
pic16_emitpcode(POC_ADDFW, pic16_popGet(AOP(right),0));
if ( AOP_TYPE(result) != AOP_ACC)
pic16_emitpcode(POC_MOVWF,pic16_popGet(AOP(result),0));
goto release; // we're done, since WREG is 1 byte
}
DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
size = min( AOP_SIZE(result), AOP_SIZE(right) );
size = min( size, AOP_SIZE(left) );
offset = 0;
if(pic16_debug_verbose) {
// fprintf(stderr, "%s:%d result: %d\tleft: %d\tright: %d\n", __FILE__, __LINE__,
// AOP_SIZE(result), AOP_SIZE(left), AOP_SIZE(right));
// fprintf(stderr, "%s:%d size of operands: %d\n", __FILE__, __LINE__, size);
}
if ((AOP_TYPE(left) == AOP_PCODE) && (
(AOP(left)->aopu.pcop->type == PO_LITERAL) ||
// (AOP(left)->aopu.pcop->type == PO_DIR) || // patch 9
(AOP(left)->aopu.pcop->type == PO_IMMEDIATE)))
{
// add to literal operand
// add first bytes
for(i=0; i<size; i++) {
if (AOP_TYPE(right) == AOP_ACC) {
pic16_emitpcode(POC_ADDLW, pic16_popGet(AOP(left),i));
} else {
pic16_emitpcode(POC_MOVLW, pic16_popGet(AOP(left),i));
if(i) { // add with carry
pic16_emitpcode(POC_ADDFWC, pic16_popGet(AOP(right),i));
} else { // add without
pic16_emitpcode(POC_ADDFW, pic16_popGet(AOP(right),i));
}
}
pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),i));
}
DEBUGpic16_pic16_AopTypeSign(__LINE__, NULL, right, NULL);
// add leftover bytes
if (SPEC_USIGN(getSpec(operandType(right)))) {
// right is unsigned
for(i=size; i< AOP_SIZE(result); i++) {
pic16_emitpcode(POC_CLRF, pic16_popGet(AOP(result),i));
pic16_emitpcode(POC_MOVLW, pic16_popGet(AOP(left),i));
pic16_emitpcode(POC_ADDWFC, pic16_popGet(AOP(result),i));
}
} else {
// right is signed, oh dear ...
for(i=size; i< AOP_SIZE(result); i++) {
pic16_emitpcode(POC_CLRF, pic16_popGet(AOP(result),i));
pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit(pic16_aopGet(AOP(right),size-1,FALSE,FALSE),7,0, PO_GPR_REGISTER));
pic16_emitpcode(POC_SETF, pic16_popGet(AOP(result),i));
pic16_emitpcode(POC_MOVLW, pic16_popGet(AOP(left),i));
pic16_emitpcode(POC_ADDWFC, pic16_popGet(AOP(result),i));
}
}
goto release;
} else {
// add regs
if (pic16_sameRegs(AOP(left), AOP(result))
&& (AOP_SIZE(left) < AOP_SIZE(result)))
{
// extend left operand, sign-bit still intact
pic16_addSign (result, AOP_SIZE(left), !SPEC_USIGN(getSpec(operandType(left))));
}
// add first bytes
for(i=0; i<size; i++) {
if (AOP_TYPE(right) != AOP_ACC)
pic16_mov2w(AOP(right),i);
if (pic16_sameRegs(AOP(left), AOP(result)))
{
if(i) { // add with carry
pic16_emitpcode(POC_ADDWFC, pic16_popGet(AOP(left),i));
} else { // add without
pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(left),i));
}
} else { // not same
if(i) { // add with carry
pic16_emitpcode(POC_ADDFWC, pic16_popGet(AOP(left),i));
} else { // add without
pic16_emitpcode(POC_ADDFW, pic16_popGet(AOP(left),i));
}
pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),i));
}
}
// add leftover bytes
// either left or right is too short
for (i=size; i < AOP_SIZE(result); i++) {
// get right operand into WREG
if (i < AOP_SIZE(right)) {
pic16_mov2w (AOP(right), i);
} else {
// right is too short, not overwritten with result
pic16_emitpcode (POC_CLRF, pic16_popCopyReg (&pic16_pc_wreg));
if (!SPEC_USIGN(getSpec(operandType(right)))) {
// right operand is signed
// Make sure that right's sign is not yet overwritten
assert (!pic16_sameRegs (AOP(right), AOP(result)));
pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit(pic16_aopGet(AOP(right),AOP_SIZE(right)-1,FALSE,FALSE),7,0, PO_GPR_REGISTER));
pic16_emitpcode(POC_SETF, pic16_popCopyReg (&pic16_pc_wreg));
}
}
// get left+WREG+CARRY into result
if (pic16_sameRegs (AOP(left), AOP(result))) {
// left might have been extended in result above
pic16_emitpcode (POC_ADDWFC, pic16_popGet (AOP(result), i));
} else if (i < AOP_SIZE(left)) {
pic16_emitpcode (POC_ADDFWC, pic16_popGet (AOP(left), i));
pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),i));
} else {
// left is too short, not overwritten with result
pic16_emitpcode (POC_CLRF, pic16_popGet (AOP(result), i));
if (!SPEC_USIGN(getSpec(operandType(left)))) {
// left operand is signed
pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit(pic16_aopGet(AOP(left),AOP_SIZE(left)-1,FALSE,FALSE),7,0, PO_GPR_REGISTER));
pic16_emitpcode(POC_SETF, pic16_popGet (AOP(result), i));
}
pic16_emitpcode (POC_ADDWFC, pic16_popGet (AOP(result), i));
}
} // for i
goto release;
}
}
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);
}
/*-----------------------------------------------------------------*/
/* pic16_genMinusDec :- does subtraction with decrement if possible */
/*-----------------------------------------------------------------*/
bool pic16_genMinusDec (iCode *ic)
{
unsigned int icount ;
unsigned int size = pic16_getDataSize(IC_RESULT(ic));
FENTRY;
/* will try to generate an increment */
/* if the right side is not a literal
we cannot */
if ((AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT) ||
(AOP_TYPE(IC_LEFT(ic)) == AOP_CRY) ||
(AOP_TYPE(IC_RESULT(ic)) == AOP_CRY) )
return FALSE ;
DEBUGpic16_emitcode ("; lit val","%d",(unsigned int) ulFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit));
/* if the literal value of the right hand side
is greater than 4 then it is not worth it */
if ((icount = (unsigned int) ulFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit)) > 2)
return FALSE ;
/* if decrement 16 bits in register */
if (pic16_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
(size > 1) &&
(icount == 1)) {
if(size == 2) {
pic16_emitpcode(POC_DECF, pic16_popGet(AOP(IC_RESULT(ic)),LSB));
emitSKPC;
pic16_emitpcode(POC_DECF, pic16_popGet(AOP(IC_RESULT(ic)),MSB16));
pic16_emitcode("decf","%s,f",pic16_aopGet(AOP(IC_RESULT(ic)),LSB,FALSE,FALSE));
pic16_emitcode("incfsz","%s,w",pic16_aopGet(AOP(IC_RESULT(ic)),LSB,FALSE,FALSE));
pic16_emitcode(" decf","%s,f",pic16_aopGet(AOP(IC_RESULT(ic)),MSB16,FALSE,FALSE));
} else {
/* size is 3 or 4 */
pic16_emitpcode(POC_DECF, pic16_popGet(AOP(IC_RESULT(ic)),LSB));
pic16_emitpcode(POC_CLRF, pic16_popCopyReg(&pic16_pc_wreg));
pic16_emitpcode(POC_SUBWFB_D1, pic16_popGet(AOP(IC_RESULT(ic)),MSB16));
pic16_emitpcode(POC_SUBWFB_D1, pic16_popGet(AOP(IC_RESULT(ic)),MSB24));
pic16_emitcode("movlw","0xff");
pic16_emitcode("addwf","%s,f",pic16_aopGet(AOP(IC_RESULT(ic)),LSB,FALSE,FALSE));
//emitSKPNC;
pic16_emitcode("addwf","%s,f",pic16_aopGet(AOP(IC_RESULT(ic)),MSB16,FALSE,FALSE));
//emitSKPNC;
pic16_emitcode("addwf","%s,f",pic16_aopGet(AOP(IC_RESULT(ic)),MSB24,FALSE,FALSE));
if(size > 3) {
pic16_emitpcode(POC_SUBWFB_D1, pic16_popGet(AOP(IC_RESULT(ic)),MSB32));
pic16_emitcode("skpnc","");
//emitSKPNC;
pic16_emitcode("addwf","%s,f",pic16_aopGet(AOP(IC_RESULT(ic)),MSB32,FALSE,FALSE));
}
}
return TRUE;
}
/* if the sizes are greater than 1 then we cannot */
if (AOP_SIZE(IC_RESULT(ic)) > 1 ||
AOP_SIZE(IC_LEFT(ic)) > 1 )
return FALSE ;
/* we can if the aops of the left & result match or
if they are in registers and the registers are the
same */
if (pic16_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic)))) {
while (icount--)
pic16_emitpcode(POC_DECF, pic16_popGet(AOP(IC_RESULT(ic)),0));
//pic16_emitcode ("decf","%s,f",pic16_aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE));
return TRUE ;
}
DEBUGpic16_emitcode ("; returning"," result=%s, left=%s",
pic16_aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE),
pic16_aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE));
if(size==1) {
pic16_emitcode("decf","%s,w",pic16_aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE));
pic16_emitcode("movwf","%s",pic16_aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE));
pic16_emitpcode(POC_DECFW, pic16_popGet(AOP(IC_LEFT(ic)),0));
pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(IC_RESULT(ic)),0));
return TRUE;
}
return FALSE ;
}
/*-----------------------------------------------------------------*/
/* pic16_addSign - propogate sign bit to higher bytes */
/*-----------------------------------------------------------------*/
void pic16_addSign(operand *result, int offset, int sign)
{
int size = (pic16_getDataSize(result) - offset);
DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
if(size > 0){
if(sign && offset) {
if(size == 1) {
pic16_emitpcode(POC_CLRF,pic16_popGet(AOP(result),offset));
pic16_emitpcode(POC_BTFSC,pic16_newpCodeOpBit(pic16_aopGet(AOP(result),offset-1,FALSE,FALSE),7,0, PO_GPR_REGISTER));
pic16_emitpcode(POC_SETF, pic16_popGet(AOP(result),offset));
} else {
pic16_emitpcode(POC_MOVLW, pic16_popGetLit(0));
pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit(pic16_aopGet(AOP(result),offset-1,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+size));
}
} else
while(size--)
pic16_emitpcode(POC_CLRF,pic16_popGet(AOP(result),offset++));
}
}
/*-----------------------------------------------------------------*/
/* pic16_genMinus - generates code for subtraction */
/*-----------------------------------------------------------------*/
void pic16_genMinus (iCode *ic)
{
int size, offset = 0, same=0;
unsigned long lit = 0L;
FENTRY;
pic16_aopOp (IC_LEFT(ic),ic,FALSE);
pic16_aopOp (IC_RIGHT(ic),ic,FALSE);
pic16_aopOp (IC_RESULT(ic),ic,TRUE);
if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY &&
AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT) {
operand *t = IC_RIGHT(ic);
IC_RIGHT(ic) = IC_LEFT(ic);
IC_LEFT(ic) = t;
}
DEBUGpic16_emitcode ("; ","result %s, left %s, right %s",
pic16_AopType(AOP_TYPE(IC_RESULT(ic))),
pic16_AopType(AOP_TYPE(IC_LEFT(ic))),
pic16_AopType(AOP_TYPE(IC_RIGHT(ic))));
/* special cases :- */
/* if both left & right are in bit space */
if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY &&
AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
pic16_genPlusBits (ic);
goto release ;
}
/* if I can do an decrement instead
of subtract then GOOD for ME */
// if (pic16_genMinusDec (ic) == TRUE)
// goto release;
size = pic16_getDataSize(IC_RESULT(ic));
same = pic16_sameRegs(AOP(IC_RIGHT(ic)), AOP(IC_RESULT(ic)));
if(AOP(IC_RIGHT(ic))->type == AOP_LIT) {
/* Add a literal to something else */
lit = ulFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit);
lit = - (long)lit;
genAddLit ( ic, lit);
} else if(AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
// bit subtraction
pic16_emitcode(";bitsub","right is bit: %s",pic16_aopGet(AOP(IC_RIGHT(ic)),0,FALSE,FALSE));
pic16_emitcode(";bitsub","left is bit: %s",pic16_aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE));
pic16_emitcode(";bitsub","result is bit: %s",pic16_aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE));
/* here we are subtracting a bit from a char or int */
if(size == 1) {
if (pic16_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) {
pic16_emitpcode(POC_BTFSC , pic16_popGet(AOP(IC_RIGHT(ic)),0));
pic16_emitpcode(POC_DECF , pic16_popGet(AOP(IC_RESULT(ic)),0));
} else {
if(AOP_TYPE(IC_LEFT(ic)) == AOP_ACC) {
pic16_emitpcode(POC_BTFSC , pic16_popGet(AOP(IC_RIGHT(ic)),0));
pic16_emitpcode(POC_XORLW , pic16_popGetLit(1));
}else if( (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) ) {
lit = ulFromVal (AOP(IC_LEFT(ic))->aopu.aop_lit);
if(AOP_TYPE(IC_RESULT(ic)) == AOP_CRY) {
if (pic16_sameRegs(AOP(IC_RIGHT(ic)), AOP(IC_RESULT(ic))) ) {
if(lit & 1) {
pic16_emitpcode(POC_MOVLW , pic16_popGetLit(1));
pic16_emitpcode(POC_XORWF , pic16_popGet(AOP(IC_RIGHT(ic)),0));
}
}else{
pic16_emitpcode(POC_BCF , pic16_popGet(AOP(IC_RESULT(ic)),0));
if(lit & 1)
pic16_emitpcode(POC_BTFSS , pic16_popGet(AOP(IC_RIGHT(ic)),0));
else
pic16_emitpcode(POC_BTFSC , pic16_popGet(AOP(IC_RIGHT(ic)),0));
pic16_emitpcode(POC_BSF , pic16_popGet(AOP(IC_RESULT(ic)),0));
}
goto release;
} else {
pic16_emitpcode(POC_MOVLW , pic16_popGetLit(lit & 0xff));
pic16_emitpcode(POC_BTFSC , pic16_popGet(AOP(IC_RIGHT(ic)),0));
pic16_emitpcode(POC_MOVLW , pic16_popGetLit((lit-1) & 0xff));
//pic16_emitpcode(POC_MOVWF , pic16_popGet(AOP(IC_RESULT(ic)),0));
}
} else {
pic16_mov2w(AOP(IC_LEFT(ic)),0);
pic16_emitpcode(POC_BTFSC , pic16_popGet(AOP(IC_RIGHT(ic)),0));
pic16_emitpcode(POC_DECFW , pic16_popGet(AOP(IC_LEFT(ic)),0));
}
if(AOP_TYPE(IC_RESULT(ic)) != AOP_ACC) {
pic16_emitpcode(POC_MOVWF , pic16_popGet(AOP(IC_RESULT(ic)),0));
} else {
pic16_emitpcode(POC_ANDLW , pic16_popGetLit(1));
/*
pic16_emitpcode(POC_BCF , pic16_popGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE));
emitSKPZ;
pic16_emitpcode(POC_BSF , pic16_popGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE));
*/
}
}
}
} else if((AOP(IC_LEFT(ic))->type == AOP_LIT) &&
(AOP_TYPE(IC_RIGHT(ic)) != AOP_ACC)) {
lit = ulFromVal (AOP(IC_LEFT(ic))->aopu.aop_lit);
DEBUGpic16_emitcode ("; left is lit","line %d result %s, left %s, right %s",__LINE__,
pic16_AopType(AOP_TYPE(IC_RESULT(ic))),
pic16_AopType(AOP_TYPE(IC_LEFT(ic))),
pic16_AopType(AOP_TYPE(IC_RIGHT(ic))));
if( (size == 1) && ((lit & 0xff) == 0) ) {
/* res = 0 - right */
if (pic16_sameRegs(AOP(IC_RIGHT(ic)), AOP(IC_RESULT(ic))) ) {
pic16_emitpcode(POC_NEGF, pic16_popGet(AOP(IC_RIGHT(ic)),0));
} else {
pic16_emitpcode(POC_COMFW, pic16_popGet(AOP(IC_RIGHT(ic)),0));
pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(IC_RESULT(ic)),0));
pic16_emitpcode(POC_INCF, pic16_popGet(AOP(IC_RESULT(ic)),0));
}
goto release;
}
pic16_mov2w(AOP(IC_RIGHT(ic)),0);
pic16_emitpcode(POC_SUBLW, pic16_popGetLit(lit & 0xff));
pic16_emitpcode(POC_MOVWF,pic16_popGet(AOP(IC_RESULT(ic)),0));
offset = 0;
while(--size) {
lit >>= 8;
offset++;
if(same) {
// here we have x = lit - x for sizeof(x)>1
pic16_emitpcode(POC_MOVLW, pic16_popGetLit(lit & 0xff));
pic16_emitpcode(POC_SUBFWB_D1, pic16_popGet(AOP(IC_RESULT(ic)),offset));
} else {
pic16_emitpcode(POC_MOVLW, pic16_popGetLit(lit & 0xff));
pic16_emitpcode(POC_SUBFWB_D0, pic16_popGet(AOP(IC_RIGHT(ic)),offset));
pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(IC_RESULT(ic)),offset));
}
}
} else {
DEBUGpic16_emitcode ("; ","line %d result %s, left %s, right %s",__LINE__,
pic16_AopType(AOP_TYPE(IC_RESULT(ic))),
pic16_AopType(AOP_TYPE(IC_LEFT(ic))),
pic16_AopType(AOP_TYPE(IC_RIGHT(ic))));
if ((AOP_SIZE(IC_LEFT(ic)) < AOP_SIZE(IC_RESULT(ic)))
&& pic16_sameRegs (AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic)))) {
// extend left in result
pic16_addSign (IC_RESULT(ic), AOP_SIZE(IC_LEFT(ic)), !SPEC_USIGN(getSpec(operandType(IC_LEFT(ic)))));
}
if ((AOP_SIZE(IC_RIGHT(ic)) < AOP_SIZE(IC_RESULT(ic)))
&& pic16_sameRegs (AOP(IC_RIGHT(ic)), AOP(IC_RESULT(ic)))) {
// extend right in result---fails if left resides in result as well...
assert ((IC_LEFT(ic) == IC_RIGHT(ic)) || !pic16_sameRegs (AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))));
pic16_addSign (IC_RESULT(ic), AOP_SIZE(IC_RIGHT(ic)), !SPEC_USIGN(getSpec(operandType(IC_RIGHT(ic)))));
}
if(AOP_TYPE(IC_LEFT(ic)) == AOP_ACC) {
DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
pic16_emitpcode(POC_SUBFW, pic16_popGet(AOP(IC_RIGHT(ic)),0));
pic16_emitpcode(POC_SUBLW, pic16_popGetLit(0));
if ( AOP_TYPE(IC_RESULT(ic)) != AOP_ACC)
pic16_emitpcode(POC_MOVWF,pic16_popGet(AOP(IC_RESULT(ic)),0));
} else {
DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
if(AOP_TYPE(IC_RIGHT(ic)) != AOP_ACC)
pic16_mov2w(AOP(IC_RIGHT(ic)),0);
if (pic16_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) )
pic16_emitpcode(POC_SUBWF, pic16_popGet(AOP(IC_LEFT(ic)),0));
else {
if( (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) ) {
pic16_emitpcode(POC_SUBLW, pic16_popGet(AOP(IC_LEFT(ic)),0));
} else {
pic16_emitpcode(POC_SUBFW, pic16_popGet(AOP(IC_LEFT(ic)),0));
}
if ( AOP_TYPE(IC_RESULT(ic)) != AOP_ACC) {
if ( AOP_TYPE(IC_RESULT(ic)) == AOP_CRY) {
pic16_emitpcode(POC_BCF , pic16_popGet(AOP(IC_RESULT(ic)),0));
emitSKPZ;
pic16_emitpcode(POC_BSF , pic16_popGet(AOP(IC_RESULT(ic)),0));
}else
pic16_emitpcode(POC_MOVWF,pic16_popGet(AOP(IC_RESULT(ic)),0));
}
}
}
/*
pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(IC_RIGHT(ic)),0,FALSE,FALSE));
if (pic16_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) {
pic16_emitpcode(POC_SUBFW, pic16_popGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE));
} else {
pic16_emitpcode(POC_SUBFW, pic16_popGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE));
pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE));
}
*/
offset = 1;
size--;
while (size--) {
if (pic16_sameRegs (AOP(IC_RIGHT(ic)), AOP(IC_RESULT(ic)))) {
pic16_mov2w (AOP(IC_RESULT(ic)), offset);
} else if (offset < AOP_SIZE(IC_RIGHT(ic)))
pic16_mov2w(AOP(IC_RIGHT(ic)),offset);
else {
// right operand is too short, not overwritten with result
pic16_emitpcode (POC_CLRF, pic16_popCopyReg (&pic16_pc_wreg));
if (!SPEC_USIGN(operandType(IC_RIGHT(ic)))) {
// signed -- sign extend the right operand
pic16_emitpcode (POC_BTFSC, pic16_newpCodeOpBit(pic16_aopGet(AOP(IC_RIGHT(ic)),AOP_SIZE(IC_RIGHT(ic))-1,FALSE,FALSE),7,0, PO_GPR_REGISTER));
pic16_emitpcode (POC_SETF, pic16_popCopyReg (&pic16_pc_wreg));
}
}
if (pic16_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic)))) {
pic16_emitpcode(POC_SUBWFB_D1, pic16_popGet(AOP(IC_RESULT(ic)),offset));
} else if (offset < AOP_SIZE(IC_LEFT(ic))) {
pic16_emitpcode(POC_SUBWFB_D0, pic16_popGet(AOP(IC_LEFT(ic)),offset));
pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(IC_RESULT(ic)),offset));
} else {
// left operand is too short, not overwritten with result
pic16_emitpcode (POC_CLRF, pic16_popGet(AOP(IC_RESULT(ic)), offset));
if (!SPEC_USIGN(operandType(IC_LEFT(ic)))) {
// signed -- sign extend the left operand
pic16_emitpcode (POC_BTFSC, pic16_newpCodeOpBit(pic16_aopGet(AOP(IC_LEFT(ic)),AOP_SIZE(IC_LEFT(ic))-1,FALSE,FALSE),7,0, PO_GPR_REGISTER));
pic16_emitpcode (POC_SETF, pic16_popGet(AOP(IC_RESULT(ic)), offset)); // keep CARRY/#BORROW bit intact!
}
pic16_emitpcode(POC_SUBWFB_D1, pic16_popGet(AOP(IC_RESULT(ic)),offset));
}
offset++;
}
}
// adjustArithmeticResult(ic);
release:
pic16_freeAsmop(IC_LEFT(ic),NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
pic16_freeAsmop(IC_RIGHT(ic),NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
pic16_freeAsmop(IC_RESULT(ic),NULL,ic,TRUE);
}
/*-----------------------------------------------------------------*
* pic_genMult8XLit_n - multiplication of two 8-bit numbers.
*
*
*-----------------------------------------------------------------*/
static void
pic16_genMult8XLit_n (operand *left, operand *right, operand *result)
{
int lit;
int size = AOP_SIZE (result);
FENTRY;
DEBUGpic16_pic16_AopType (__LINE__, left, right, result);
if (AOP_TYPE (right) != AOP_LIT)
{
fprintf (stderr, "%s %d - right operand is not a literal\n", __FILE__, __LINE__);
exit (1);
}
lit = (int) ulFromVal (AOP (right)->aopu.aop_lit);
assert ((lit >= -128) && (lit < 256) );
/* We need to adjust the high byte of the result (in PRODH) if
* (a) literals < 0 or
* (b) signed register operands < 0.
*
* If lit >= 0 and val is unsigned, MULLW will do the trick.
*
* If val is signed and 8 bit:
* val = -2^7 * v_7 + SUM(2^i * v_i, i=0..6)
* = -2^7 * v_7 + -2^7 * v_7 + SUM(2^i * v_i, i=0..7)
* = -2^8 * v_7 + SUM(2^i * v_i, i=0..7)
* = -2^8 * v_7 + UNSIGNED(val)
*
* For lit >= 0:
* lit * val = lit * UNSIGNED(val) - 2^8 * v_7 * lit
*
* For lit < 0, lit = l_7 .. l_0:
*
* lit * val = (-2^8 * l_7 + UNSIGNED(lit)) * (-2^8 * v_7 + UNSIGNED(val))
* = 2^8 * l_7 * 2^8 * v_7
* - 2^8 * l_7 * UNSIGNED(val)
* - 2^8 * v_7 * UNSIGNED(lit)
* + UNSIGNED(lit) * UNSIGNED(val)
* = 2^16 * l_7 * v_7
* - 2^8 * (l_7 * UNSIGNED(val) + v_7 * UNSIGNED(lit))
* + UNSIGNED(lit) * UNSIGNED(val)
*
* '2^16 * X' is only of interest if the result is larger than 16 * bit
* ==> ignored.
* '-2^8 * X' requires subtracting the original values of 'val'
* respectively 'lit' from the high byte of the result.
* UNSIGNED(lit) * UNSIGNED(val) can be computed via a MUL instruction.
*
* So, we do:
* MOVF val, W
* MULLW lit
* # Now, PRODH:PRODL hold UNSIGNED(val) * UNSIGNED(lit)
* if result > 8 bit:
* if lit < 0:
* SUBWF PRODH, F # -2^8 * l_7 * UNSIGNED(val)
* MOVF PRODH, W
* BTFSC val, 7
* SUBLW lit # -2^8 * v_7 * UNSIGNED(lit)
* MOVWF result[1] # this might overwrite val!
* MOVFF PRODL, result[0] # this might overwrite val!
*/
pic16_mov2w (AOP (left), 0);
pic16_emitpcode (POC_MULLW, pic16_popGetLit (lit & 0x00ff));
if (size > 1)
{
/* Adjust PRODH for signed operands. */
if (lit < 0)
{
/* left is still in WREG */
pic16_emitpcode (POC_SUBWF, pic16_popCopyReg (&pic16_pc_prodh));
} // if
pic16_emitpcode (POC_MOVFW, pic16_popCopyReg (&pic16_pc_prodh));
if (!SPEC_USIGN (operandType (left)))
{
pic16_emitpcode (POC_BTFSC,
pic16_newpCodeOpBit (pic16_aopGet (AOP (left), 0, FALSE, FALSE),
7, 0, PO_GPR_REGISTER));
pic16_emitpcode (POC_SUBLW, pic16_popGetLit (lit & 0x00ff));
} // if
/* Assign result (high byte) -- this may overwrite val. */
pic16_emitpcode (POC_MOVWF, pic16_popGet (AOP (result), 1));
} // if
/* Assign result (low byte) -- this may overwrite val. */
pic16_emitpcode (POC_MOVFF,
pic16_popGet2p (pic16_popCopyReg (&pic16_pc_prodl),
pic16_popGet (AOP (result), 0)));
/* Must sign/zero-extend here if size > 2. */
if (size > 2)
{
pic16_addSign (result, 2, !IS_UNSIGNED (operandType (left)));
} // if
}
/*-----------------------------------------------------------------*
* genMult8X8_n - multiplication of two 8-bit numbers.
*
*
*-----------------------------------------------------------------*/
void
pic16_genMult8X8_n (operand *left, operand *right, operand *result)
{
FENTRY;
/* Special case: multiply by literal. */
if (AOP_TYPE (right) == AOP_LIT)
{
pic16_genMult8XLit_n (left, right, result);
return;
}
else if (AOP_TYPE (left) == AOP_LIT)
{
pic16_genMult8XLit_n (right, left, result);
return;
} // if
/* cases:
A = A x B B = A x B
A = B x C
W = A x B
W = W x B W = B x W
*/
/* if result == right then exchange left and right */
if (pic16_sameRegs (AOP (result), AOP (right)))
{
operand *tmp;
tmp = left;
left = right;
right = tmp;
} // if
if (AOP_TYPE (left) != AOP_ACC)
{
// left is not WREG
if (AOP_TYPE (right) != AOP_ACC)
{
pic16_mov2w (AOP (left), 0);
pic16_emitpcode (POC_MULWF, pic16_popGet (AOP (right), 0));
}
else
{
pic16_emitpcode (POC_MULWF, pic16_popGet (AOP (left), 0));
} // if
}
else
{
pic16_emitpcode (POC_MULWF, pic16_popGet (AOP (right), 0));
} // if
/* result is in PRODL:PRODH */
if (AOP_TYPE (result) != AOP_ACC)
{
int isPRODL = (AOP (result)->type != AOP_STA && ! strcmp (pic16_aopGet (AOP (result), 0, TRUE, FALSE), "_PRODL"));
if (AOP_SIZE (result) > 1)
{
/* If s8 x s8 --> s16 multiplication was called for, fixup high byte.
* (left=a1a0, right=b1b0, X1: high byte, X0: low byte)
*
* a1a0 * b1b0
* --------------
* a1b0 a0b0
* a1b1 a0b1
* ---------------
* a0b0 a1= 0, b1= 0 (both unsigned)
* -b0 a0b0 a1=-1, b1= 0 (a signed and < 0, b unsigned or >= 0)
* -a0 a0b0 a1= 0, b1=-1 (b signed and < 0, a unsigned or >= 0)
* -(a0+b0) a0b0 a1=-1, b1=-1 (a and b signed and < 0)
*
* Currently, PRODH:PRODL holds a0b0 as 16 bit value; we need to
* subtract a0 and/or b0 from PRODH. */
if (!IS_UNSIGNED (operandType (right)))
{
/* right operand (b1) signed and < 0, then subtract left op (a0) */
pic16_mov2w (AOP (left), 0);
pic16_emitpcode (POC_BTFSC, pic16_newpCodeOpBit_simple (AOP (right), 0, 7));
pic16_emitpcode (POC_SUBWF, pic16_popCopyReg (&pic16_pc_prodh));
} // if
if (!IS_UNSIGNED (getSpec (operandType (left))))
{
/* left operand (a1) signed and < 0, then subtract right op (b0) */
pic16_mov2w (AOP (right), 0 );
pic16_emitpcode (POC_BTFSC, pic16_newpCodeOpBit_simple (AOP (left), 0, 7));
pic16_emitpcode (POC_SUBWF, pic16_popCopyReg (&pic16_pc_prodh));
} // if
/* Assing high byte of result -- this may overwrite one of the operands. */
pic16_emitpcode (POC_MOVFF, pic16_popGet2p (pic16_popCopyReg(&pic16_pc_prodh), pic16_popGet (AOP (result), 1)));
} // if
/* Assign low byte of result -- this may overwrite one of the operands. */
if (!isPRODL)
{
pic16_emitpcode (POC_MOVFF, pic16_popGet2p (pic16_popCopyReg (&pic16_pc_prodl), pic16_popGet (AOP (result), 0)));
} // if
/* Must sign/zero-extend here if size > 2. */
if (AOP_SIZE (result) > 2)
{
pic16_addSign (result, 2, !IS_UNSIGNED (operandType (left)));
} // if
}
else
{
pic16_emitpcode (POC_MOVFW, pic16_popCopyReg (&pic16_pc_prodl));
}
}