From 437d64783e5a2f4a6cb2f096627d57f5a9fa734f Mon Sep 17 00:00:00 2001 From: sdattalo Date: Sun, 1 Dec 2002 03:24:42 +0000 Subject: [PATCH] Added the pic16 port for Martin Dubuc. git-svn-id: https://sdcc.svn.sourceforge.net/svnroot/sdcc/trunk/sdcc@2111 4a8a32a2-be11-0410-ad9d-d568d2c75423 --- src/pic16/Makefile.bcc | 23 + src/pic16/device.c | 686 +++ src/pic16/device.h | 103 + src/pic16/gen.c | 10179 +++++++++++++++++++++++++++++++++++++++ src/pic16/gen.h | 181 + src/pic16/genarith.c | 1971 ++++++++ src/pic16/glue.c | 966 ++++ src/pic16/glue.h | 35 + src/pic16/main.c | 450 ++ src/pic16/main.h | 8 + src/pic16/pcode.c | 6547 +++++++++++++++++++++++++ src/pic16/pcode.h | 885 ++++ src/pic16/pcodeflow.c | 350 ++ src/pic16/pcodeflow.h | 66 + src/pic16/pcodepeep.c | 2226 +++++++++ src/pic16/pcoderegs.c | 844 ++++ src/pic16/pcoderegs.h | 42 + src/pic16/peeph.def | 285 ++ src/pic16/pic.dsp | 164 + src/pic16/pica.dsp | 90 + src/pic16/ralloc.c | 3882 +++++++++++++++ src/pic16/ralloc.h | 127 + 22 files changed, 30110 insertions(+) create mode 100644 src/pic16/Makefile.bcc create mode 100644 src/pic16/device.c create mode 100644 src/pic16/device.h create mode 100644 src/pic16/gen.c create mode 100644 src/pic16/gen.h create mode 100644 src/pic16/genarith.c create mode 100644 src/pic16/glue.c create mode 100644 src/pic16/glue.h create mode 100644 src/pic16/main.c create mode 100644 src/pic16/main.h create mode 100644 src/pic16/pcode.c create mode 100644 src/pic16/pcode.h create mode 100644 src/pic16/pcodeflow.c create mode 100644 src/pic16/pcodeflow.h create mode 100644 src/pic16/pcodepeep.c create mode 100644 src/pic16/pcoderegs.c create mode 100644 src/pic16/pcoderegs.h create mode 100644 src/pic16/peeph.def create mode 100644 src/pic16/pic.dsp create mode 100644 src/pic16/pica.dsp create mode 100644 src/pic16/ralloc.c create mode 100644 src/pic16/ralloc.h diff --git a/src/pic16/Makefile.bcc b/src/pic16/Makefile.bcc new file mode 100644 index 00000000..445fa5ff --- /dev/null +++ b/src/pic16/Makefile.bcc @@ -0,0 +1,23 @@ +PRJDIR = ../.. + +# !include $(PRJDIR)/Makefile.common + +OBJ = gen.obj genarith.obj ralloc.obj main.obj glue.obj pcode.obj pcodepeep.obj +LIB = port.lib + +!include ..\..\Bcc.inc +CFLAGS = -I.. -I. -I..\.. -I..\..\support -D__FUNCTION__=__FILE__ + +all: $(LIB) + +main.obj: main.c peeph.rul + +$(LIB): peeph.rul $(OBJ) + del $(LIB) + tlib /a $(LIB) +gen.obj +genarith.obj +ralloc.obj +main.obj +glue.obj + tlib /a $(LIB) +pcode.obj +pcodepeep.obj + +peeph.rul: peeph.def + gawk -f ../SDCCpeeph.awk peeph.def > peeph.rul + +# include clean.mk diff --git a/src/pic16/device.c b/src/pic16/device.c new file mode 100644 index 00000000..3b33b564 --- /dev/null +++ b/src/pic16/device.c @@ -0,0 +1,686 @@ +/*------------------------------------------------------------------------- + + device.c - Accomodates subtle variations in PIC16 devices + Written By - Scott Dattalo scott@dattalo.com + Ported to PIC16 By - 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. +-------------------------------------------------------------------------*/ + +#include + +#include "common.h" // Include everything in the SDCC src directory +#include "newalloc.h" + + +#include "pcode.h" +#include "ralloc.h" +#include "device.h" + +#if defined(__BORLANDC__) || defined(_MSC_VER) +#define STRCASECMP stricmp +#else +#define STRCASECMP strcasecmp +#endif + +static PIC_device Pics[] = { + { + {"p18f242", "18f242", "pic18f242", "f242"}, + (memRange *)NULL, + (memRange *)NULL, + 0, + 0x300, + }, + + { + {"p18f252", "18f252", "pic18f252", "f252"}, + (memRange *)NULL, + (memRange *)NULL, + 0, + 0x600, + }, + + { + {"p18f442", "18f442", "pic18f442", "f442"}, + (memRange *)NULL, + (memRange *)NULL, + 0, + 0x300, + }, + + { + {"p18f452", "18f452", "pic18f452", "f452"}, + (memRange *)NULL, + (memRange *)NULL, + 0, + 0x600, + }, + +}; + +static int num_of_supported_PICS = sizeof(Pics)/sizeof(PIC_device); + +#define DEFAULT_PIC "f452" + +static PIC_device *pic=NULL; + +AssignedMemory *pic16_finalMapping=NULL; + +#define DEFAULT_CONFIG_BYTE 0xff + +#define CONFIG1H_WORD_ADDRESS 0x300001 +#define DEFAULT_CONFIG1H_WORD DEFAULT_CONFIG_BYTE + +#define CONFIG2L_WORD_ADDRESS 0x300002 +#define DEFAULT_CONFIG2L_WORD DEFAULT_CONFIG_BYTE + +#define CONFIG2H_WORD_ADDRESS 0x300003 +#define DEFAULT_CONFIG2H_WORD DEFAULT_CONFIG_BYTE + +#define CONFIG3H_WORD_ADDRESS 0x300005 +#define DEFAULT_CONFIG3H_WORD DEFAULT_CONFIG_BYTE + +#define CONFIG4L_WORD_ADDRESS 0x300006 +#define DEFAULT_CONFIG4L_WORD DEFAULT_CONFIG_BYTE + +#define CONFIG5L_WORD_ADDRESS 0x300008 +#define DEFAULT_CONFIG5L_WORD DEFAULT_CONFIG_BYTE + +#define CONFIG5H_WORD_ADDRESS 0x300009 +#define DEFAULT_CONFIG5H_WORD DEFAULT_CONFIG_BYTE + +#define CONFIG6L_WORD_ADDRESS 0x30000a +#define DEFAULT_CONFIG6L_WORD DEFAULT_CONFIG_BYTE + +#define CONFIG6H_WORD_ADDRESS 0x30000b +#define DEFAULT_CONFIG6H_WORD DEFAULT_CONFIG_BYTE + +#define CONFIG7L_WORD_ADDRESS 0x30000c +#define DEFAULT_CONFIG7L_WORD DEFAULT_CONFIG_BYTE + +#define CONFIG7H_WORD_ADDRESS 0x30000d +#define DEFAULT_CONFIG7H_WORD DEFAULT_CONFIG_BYTE + +static unsigned int config1h_word = DEFAULT_CONFIG1H_WORD; +static unsigned int config2l_word = DEFAULT_CONFIG2L_WORD; +static unsigned int config2h_word = DEFAULT_CONFIG2H_WORD; +static unsigned int config3h_word = DEFAULT_CONFIG3H_WORD; +static unsigned int config4l_word = DEFAULT_CONFIG4L_WORD; +static unsigned int config5l_word = DEFAULT_CONFIG5L_WORD; +static unsigned int config5h_word = DEFAULT_CONFIG5H_WORD; +static unsigned int config6l_word = DEFAULT_CONFIG6L_WORD; +static unsigned int config6h_word = DEFAULT_CONFIG6H_WORD; +static unsigned int config7l_word = DEFAULT_CONFIG7L_WORD; +static unsigned int config7h_word = DEFAULT_CONFIG7H_WORD; + +void pic16_addMemRange(memRange *r, int type) +{ + int i; + int alias = r->alias; + + if (pic->maxRAMaddress < 0) { + fprintf(stderr, "missing \"#pragma maxram\" setting\n"); + return; + } + + do { + for (i=r->start_address; i<= r->end_address; i++) { + if ((i|alias) <= pic->maxRAMaddress) { + pic16_finalMapping[i | alias].isValid = 1; + pic16_finalMapping[i | alias].alias = r->alias; + pic16_finalMapping[i | alias].bank = r->bank; + if(type) { + /* hack for now */ + pic16_finalMapping[i | alias].isSFR = 1; + } else { + pic16_finalMapping[i | alias].isSFR = 0; + } + } else { + fprintf(stderr, "WARNING: %s:%s memory at 0x%x is beyond max ram = 0x%x\n", + __FILE__,__FUNCTION__,(i|alias), pic->maxRAMaddress); + } + } + + /* Decrement alias */ + if (alias) { + alias -= ((alias & (alias - 1)) ^ alias); + } else { + alias--; + } + + } while (alias >= 0); +} + +void pic16_setMaxRAM(int size) +{ + int i; + pic->maxRAMaddress = size; + + if (pic->maxRAMaddress < 0) { + fprintf(stderr, "invalid \"#pragma maxram 0x%x\" setting\n", + pic->maxRAMaddress); + return; + } + + pic16_finalMapping = Safe_calloc(1+pic->maxRAMaddress, + sizeof(AssignedMemory)); + + /* Now initialize the pic16_finalMapping array */ + + for(i=0; i<=pic->maxRAMaddress; i++) { + pic16_finalMapping[i].reg = NULL; + pic16_finalMapping[i].isValid = 0; + } +} + +/*-----------------------------------------------------------------* + *-----------------------------------------------------------------*/ + +int pic16_isREGinBank(regs *reg, int bank) +{ + + if(!reg || !pic) + return 0; + + if(pic16_finalMapping[reg->address].bank == bank) + return 1; + + return 0; +} + +/*-----------------------------------------------------------------* + *-----------------------------------------------------------------*/ +int pic16_REGallBanks(regs *reg) +{ + + if(!reg || !pic) + return 0; + + if (reg->address > pic->maxRAMaddress) + return 0; + + return 1; + +} + +/*-----------------------------------------------------------------* + *-----------------------------------------------------------------*/ + +/* + * pic16_dump_map -- debug stuff + */ + +void pic16_dump_map(void) +{ + int i; + + for(i=0; i<=pic->maxRAMaddress; i++) { + //fprintf(stdout , "addr 0x%02x is %s\n", i, ((pic16_finalMapping[i].isValid) ? "valid":"invalid")); + + if(pic16_finalMapping[i].isValid) { + fprintf(stderr,"addr: 0x%02x",i); + if(pic16_finalMapping[i].isSFR) + fprintf(stderr," isSFR"); + if(pic16_finalMapping[i].reg) + fprintf( stderr, " reg %s", pic16_finalMapping[i].reg->name); + fprintf(stderr, "\n"); + } + } + +} + +void pic16_dump_cblock(FILE *of) +{ + int start=-1; + int addr=0; + int bank_base; + + //pic16_dump_map(); /* display the register map */ + + if (pic->maxRAMaddress < 0) { + fprintf(stderr, "missing \"#pragma maxram\" setting\n"); + return; + } + + do { + + if(pic16_finalMapping[addr].reg && !pic16_finalMapping[addr].reg->isEmitted) { + + if(start<0) + start = addr; + } else { + if(start>=0) { + + /* clear the lower 7-bits of the start address of the first + * variable declared in this bank. The upper bits for the mid + * range pics are the bank select bits. + */ + + bank_base = start & 0xfff8; + + /* The bank number printed in the cblock comment tacitly + * assumes that the first register in the contiguous group + * of registers represents the bank for the whole group */ + + if ((pic16_finalMapping[start].bank == 0 && start <= 0x7f) || + pic16_finalMapping[start].isSFR) + fprintf(of," cblock 0X%04X\t; Access Bank\n",start); + else + fprintf(of," cblock 0X%04X\t; Bank %d\n",start,pic16_finalMapping[start].bank); + + for( ; start < addr; start++) { + if((pic16_finalMapping[start].reg) && !pic16_finalMapping[start].reg->isEmitted ) { + fprintf(of,"\t%s",pic16_finalMapping[start].reg->name); + + /* If this register is aliased in multiple banks, then + * mangle the variable name with the alias address: */ + if(pic16_finalMapping[start].alias & start) + fprintf(of,"_%x",bank_base); + + if(pic16_finalMapping[start].instance) + fprintf(of,"_%d",pic16_finalMapping[start].instance); + + + fputc('\n',of); + + //pic16_finalMapping[start].reg->isEmitted = 1; + } + } + + fprintf(of," endc\n"); + + start = -1; + } + + } + + addr++; + + } while(addr <= pic->maxRAMaddress); + + +} + +/*-----------------------------------------------------------------* + * void pic16_list_valid_pics(int ncols, int list_alias) + * + * Print out a formatted list of valid PIC devices + * + * ncols - number of columns in the list. + * + * list_alias - if non-zero, print all of the supported aliases + * for a device (e.g. F84, 16F84, etc...) + *-----------------------------------------------------------------*/ +void pic16_list_valid_pics(int ncols, int list_alias) +{ + int col,longest; + int i,j,k,l; + + if(list_alias) + list_alias = sizeof(Pics[0].name) / sizeof(Pics[0].name[0]); + + /* decrement the column number if it's greater than zero */ + ncols = (ncols > 1) ? ncols-1 : 4; + + /* Find the device with the longest name */ + for(i=0,longest=0; ilongest) + longest = k; + } + } + + col = 0; + + for(i=0; i < num_of_supported_PICS; i++) { + j = 0; + do { + + fprintf(stderr,"%s", Pics[i].name[j]); + if(colmaxRAMaddress = -1; +} + +/*-----------------------------------------------------------------* + * + *-----------------------------------------------------------------*/ +int pic16_picIsInitialized(void) +{ + if(pic && pic->maxRAMaddress > 0) + return 1; + + return 0; + +} + +/*-----------------------------------------------------------------* + * char *pic16_processor_base_name(void) - Include file is derived from this. + *-----------------------------------------------------------------*/ +char *pic16_processor_base_name(void) +{ + + if(!pic) + return NULL; + + return pic->name[0]; +} + +static int isSFR(int address) +{ + + if( (address > pic->maxRAMaddress) || !pic16_finalMapping[address].isSFR) + return 0; + + return 1; + +} + +/*-----------------------------------------------------------------* + *-----------------------------------------------------------------*/ +static int validAddress(int address, int reg_size) +{ + int i; + + if (pic->maxRAMaddress < 0) { + fprintf(stderr, "missing \"#pragma maxram\" setting\n"); + return 0; + } + // fprintf(stderr, "validAddress: Checking 0x%04x\n",address); + if(address > pic->maxRAMaddress) + return 0; + + for (i=0; isize) { + fprintf(stderr,"WARNING: %s:%s:%d Bad register\n",__FILE__,__FUNCTION__,__LINE__); + return; + } + + if (pic->maxRAMaddress < 0) { + fprintf(stderr, "missing \"#pragma maxram\" setting\n"); + return; + } + + for(i=0; isize; i++) { + + alias = pic16_finalMapping[reg->address].alias; + reg->alias = alias; + + do { + + //fprintf(stdout,"mapping %s to address 0x%02x, reg size = %d\n",reg->name, (reg->address+alias+i),reg->size); + + pic16_finalMapping[reg->address + alias + i].reg = reg; + pic16_finalMapping[reg->address + alias + i].instance = i; + + /* Decrement alias */ + if(alias) + alias -= ((alias & (alias - 1)) ^ alias); + else + alias--; + + } while (alias>=0); + } + + // fprintf(stderr,"%s - %s addr = 0x%03x, size %d\n",__FUNCTION__,reg->name, reg->address,reg->size); + + reg->isMapped = 1; + +} + +/*-----------------------------------------------------------------* + *-----------------------------------------------------------------*/ +static int assignRegister(regs *reg, int start_address) +{ + int i; + + //fprintf(stderr,"%s - %s start_address = 0x%03x\n",__FUNCTION__,reg->name, start_address); + if(reg->isFixed) { + + if (validAddress(reg->address,reg->size)) { + //fprintf(stderr,"%s - %s address = 0x%03x\n",__FUNCTION__,reg->name, reg->address); + mapRegister(reg); + return reg->address; + } + + if( isSFR(reg->address)) { + mapRegister(reg); + return reg->address; + } + + //fprintf(stderr, "WARNING: Ignoring Out of Range register assignment at fixed address %d, %s\n", + // reg->address, reg->name); + + } else { + + /* This register does not have a fixed address requirement + * so we'll search through all availble ram address and + * assign the first one */ + + for (i=start_address; i<=pic->maxRAMaddress; i++) { + + if (validAddress(i,reg->size)) { + reg->address = i; + mapRegister(reg); + return i; + } + } + + fprintf(stderr, "WARNING: No more RAM available for %s\n",reg->name); + + } + + return -1; +} + +/*-----------------------------------------------------------------* + *-----------------------------------------------------------------*/ +void pic16_assignFixedRegisters(set *regset) +{ + regs *reg; + + for (reg = setFirstItem(regset) ; reg ; + reg = setNextItem(regset)) { + + if(reg->isFixed) + assignRegister(reg,0); + } + +} + +/*-----------------------------------------------------------------* + *-----------------------------------------------------------------*/ +void pic16_assignRelocatableRegisters(set *regset, int used) +{ + + regs *reg; + int address = 0; + + for (reg = setFirstItem(regset) ; reg ; + reg = setNextItem(regset)) { + + //fprintf(stdout,"assigning %s isFixed=%d, wasUsed=%d\n",reg->name,reg->isFixed,reg->wasUsed); + + if((!reg->isFixed) && ( used || reg->wasUsed)) + address = assignRegister(reg,address); + + } + +} + + +/*-----------------------------------------------------------------* + * void pic16_assignConfigWordValue(int address, int value) + * + * All high performance RISC CPU PICs have seven config word starting + * at address 0x300000. + * This routine will assign a value to that address. + * + *-----------------------------------------------------------------*/ + +void pic16_assignConfigWordValue(int address, int value) +{ + switch(address) { + case CONFIG1H_WORD_ADDRESS: + config1h_word = value; + break; + case CONFIG2L_WORD_ADDRESS: + config2l_word = value; + break; + case CONFIG2H_WORD_ADDRESS: + config2h_word = value; + break; + case CONFIG3H_WORD_ADDRESS: + config3h_word = value; + break; + case CONFIG4L_WORD_ADDRESS: + config4l_word = value; + break; + case CONFIG5L_WORD_ADDRESS: + config5l_word = value; + break; + case CONFIG5H_WORD_ADDRESS: + config5h_word = value; + break; + case CONFIG6L_WORD_ADDRESS: + config6l_word = value; + break; + case CONFIG6H_WORD_ADDRESS: + config6h_word = value; + break; + case CONFIG7L_WORD_ADDRESS: + config7l_word = value; + break; + case CONFIG7H_WORD_ADDRESS: + config7h_word = value; + break; + } + + //fprintf(stderr,"setting config word to 0x%x\n",value); + +} +/*-----------------------------------------------------------------* + * int pic16_getConfigWord(int address) + * + * Get the current value of the config word. + * + *-----------------------------------------------------------------*/ + +int pic16_getConfigWord(int address) +{ + switch(address) { + case CONFIG1H_WORD_ADDRESS: + return config1h_word; + case CONFIG2L_WORD_ADDRESS: + return config2l_word; + case CONFIG2H_WORD_ADDRESS: + return config2h_word; + case CONFIG3H_WORD_ADDRESS: + return config3h_word; + case CONFIG4L_WORD_ADDRESS: + return config4l_word; + case CONFIG5L_WORD_ADDRESS: + return config5l_word; + case CONFIG5H_WORD_ADDRESS: + return config5h_word; + case CONFIG6L_WORD_ADDRESS: + return config6l_word; + case CONFIG6H_WORD_ADDRESS: + return config6h_word; + case CONFIG7L_WORD_ADDRESS: + return config7l_word; + case CONFIG7H_WORD_ADDRESS: + return config7h_word; + default: + return 0; + } +} + diff --git a/src/pic16/device.h b/src/pic16/device.h new file mode 100644 index 00000000..f24cb7a8 --- /dev/null +++ b/src/pic16/device.h @@ -0,0 +1,103 @@ +/*------------------------------------------------------------------------- + + device.c - Accomodates subtle variations in PIC16 devices + Written By - Scott Dattalo scott@dattalo.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. +-------------------------------------------------------------------------*/ + +/* + PIC device abstraction + + There are dozens of variations of PIC microcontrollers. This include + file attempts to abstract those differences so that SDCC can easily + deal with them. +*/ + +#ifndef __DEVICE_H__ +#define __DEVICE_H__ + +/* memRange - a structure to define a range of valid memory addresses + * + * The Memory of most PICs (and other micros) is a collection of + * disjoint chunks. The memRange structure will define the start + * and end address of one of these chunks. The memory map of a + * particular device is a collection of memRange struct's. + */ + +typedef struct memRange { + int start_address; /* first address in range */ + int end_address; /* last */ + int alias; /* bit mask defining how/if memory range is aliased + * e.g. alias = 0x80 means start_address is identical + * to the memory location at (0x80 | start_address) */ + int bank; /* PIC memory bank this range occupies */ + +} memRange; + +/* AssignedMemory - A structure to keep track of the memory that has been used. + * + * When a register gets assigned an address this struct is used to + * keep track of a few details about the register. There is one of + * these structures for each memory location in the device. + */ + +typedef struct AssignedMemory { + regs *reg; /* Pointer to the register (NULL if this is an invalid address) */ + int instance; /* the i'th byte of a multibyte register */ + int alias; /* Bit mapping of aliased addresses (see memRange) */ + int bank; /* Memory bank of this register */ + int isValid:1; /* True if the address is legal */ + int isSFR:1; /* True if the address is that of a Special Function reg */ + int isEmitted:1; /* True if the register has been written to a cBlock */ + +} AssignedMemory; + + +/* + * pic16_finalMapping - Dynamically allocated array that records the register assignments + */ + +extern AssignedMemory *pic16_finalMapping; +#define PROCESSOR_NAMES 4 +/* Processor unique attributes */ +typedef struct PIC_device { + char *name[PROCESSOR_NAMES];/* aliases for the processor name */ + + memRange *ram; /* RAM memory map */ + memRange *sfr; /* SFR memory map */ + + int maxRAMaddress; /* maximum value for a data address */ + int bankMask; /* Bitmask that is ANDed with address to extract banking bits */ + // int hasAliasedRAM:1; /* True if there are bank independent registers */ + +} PIC_device; + +/* Given a pointer to a register, this macro returns the bank that it is in */ +#define REG_ADDR(r) ((r)->isBitField ? (((r)->address)>>3) : (r)->address) +#define REG_BANK(r) (pic16_finalMapping[REG_ADDR(r)].bank) +#define REG_isALIASED(r) (pic16_finalMapping[REG_ADDR(r)].alias != 0) +#define REG_isVALID(r) (pic16_finalMapping[REG_ADDR(r)].isValid) + + +/****************************************/ +void pic16_assignConfigWordValue(int address, int value); +int pic16_getConfigWord(int address); +int pic16_isREGinBank(regs *reg, int bank); +int pic16_REGallBanks(regs *reg); +void pic16_addMemRange(memRange *r, int type); +void pic16_setMaxRAM(int size); + +#endif /* __DEVICE_H__ */ diff --git a/src/pic16/gen.c b/src/pic16/gen.c new file mode 100644 index 00000000..d9265bce --- /dev/null +++ b/src/pic16/gen.c @@ -0,0 +1,10179 @@ +/*------------------------------------------------------------------------- + SDCCgen51.c - source file for code generation for 8051 + + Written By - Sandeep Dutta . sandeep.dutta@usa.net (1998) + and - Jean-Louis VERN.jlvern@writeme.com (1999) + Bug Fixes - Wojciech Stryjewski wstryj1@tiger.lsu.edu (1999 v2.1.9a) + PIC port - Scott Dattalo scott@dattalo.com (2000) + PIC16 port - Martin Dubuc m.dubuc@rogers.com (2002) + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! + + Notes: + 000123 mlh Moved aopLiteral to SDCCglue.c to help the split + Made everything static +-------------------------------------------------------------------------*/ + +#include +#include +#include +#include +#include "SDCCglobl.h" +#include "newalloc.h" + +#ifdef HAVE_SYS_ISA_DEFS_H +#include +#else +#ifdef HAVE_MACHINE_ENDIAN_H +#include +#else +#ifdef HAVE_ENDIAN_H +#include +#else +#if !defined(__BORLANDC__) && !defined(_MSC_VER) && !defined(__MINGW32__) && !defined(__CYGWIN__) +#warning "Cannot determine ENDIANESS of this machine assuming LITTLE_ENDIAN" +#warning "If you running sdcc on an INTEL 80x86 Platform you are okay" +#endif +#endif +#endif +#endif + +#include "common.h" +#include "SDCCpeeph.h" +#include "ralloc.h" +#include "pcode.h" +#include "gen.h" + + +extern void pic16_genUMult8X8_16 (operand *, operand *,operand *,pCodeOpReg *); +extern void pic16_genSMult8X8_16 (operand *, operand *,operand *,pCodeOpReg *); +void pic16_genMult8X8_8 (operand *, operand *,operand *); +pCode *pic16_AssembleLine(char *line); +extern void pic16_printpBlock(FILE *of, pBlock *pb); +static asmop *newAsmop (short type); +static pCodeOp *popRegFromString(char *str, int size, int offset); +static void mov2w (asmop *aop, int offset); +static int aopIdx (asmop *aop, int offset); + +static int labelOffset=0; +extern int pic16_debug_verbose; +static int optimized_for_speed = 0; + +/* 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 GpsuedoStkPtr=0; + +pCodeOp *pic16_popGetImmd(char *name, unsigned int offset, int index); +unsigned int pic16aopLiteral (value *val, int offset); +const char *pic16_AopType(short type); +static iCode *ifxForOp ( operand *op, iCode *ic ); + +#define BYTEofLONG(l,b) ( (l>> (b<<3)) & 0xff) + +/* this is the down and dirty file with all kinds of + kludgy & hacky stuff. This is what it is all about + CODE GENERATION for a specific MCU . some of the + routines may be reusable, will have to see */ + +static char *zero = "#0x00"; +static char *one = "#0x01"; +static char *spname = "sp"; + +char *fReturnpic16[] = {"temp1","temp2","temp3","temp4" }; +//char *fReturn390[] = {"dpl","dph","dpx", "b","a" }; +unsigned pic16_fReturnSizePic = 4; /* shared with ralloc.c */ +static char **fReturn = fReturnpic16; + +static char *accUse[] = {"a","b"}; + +//static short rbank = -1; + +static struct { + short r0Pushed; + short r1Pushed; + short accInUse; + short inLine; + short debugLine; + short nRegsSaved; + set *sendSet; +} _G; + +/* Resolved ifx structure. This structure stores information + about an iCode ifx that makes it easier to generate code. +*/ +typedef struct resolvedIfx { + symbol *lbl; /* pointer to a label */ + int condition; /* true or false ifx */ + int generated; /* set true when the code associated with the ifx + * is generated */ +} resolvedIfx; + +extern int pic16_ptrRegReq ; +extern int pic16_nRegs; +extern FILE *codeOutFile; +static void saverbank (int, iCode *,bool); + +static lineNode *lineHead = NULL; +static lineNode *lineCurr = NULL; + +static unsigned char SLMask[] = {0xFF ,0xFE, 0xFC, 0xF8, 0xF0, +0xE0, 0xC0, 0x80, 0x00}; +static unsigned char SRMask[] = {0xFF, 0x7F, 0x3F, 0x1F, 0x0F, +0x07, 0x03, 0x01, 0x00}; + +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; */ +/*-----------------------------------------------------------------*/ +static int my_powof2 (unsigned long num) +{ + if(num) { + if( (num & (num-1)) == 0) { + int nshifts = -1; + while(num) { + num>>=1; + nshifts++; + } + return nshifts; + } + } + + return -1; +} + +void 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 DEBUGpic16_emitcode (char *inst,char *fmt, ...) +{ + va_list ap; + char lb[INITIAL_INLINEASM]; + char *lbp = lb; + + if(!pic16_debug_verbose) + return; + + va_start(ap,fmt); + + if (inst && *inst) { + if (fmt && *fmt) + sprintf(lb,"%s\t",inst); + else + sprintf(lb,"%s",inst); + vsprintf(lb+(strlen(lb)),fmt,ap); + } else + vsprintf(lb,fmt,ap); + + while (isspace(*lbp)) lbp++; + + if (lbp && *lbp) + lineCurr = (lineCurr ? + connectLine(lineCurr,newLineNode(lb)) : + (lineHead = newLineNode(lb))); + lineCurr->isInline = _G.inLine; + lineCurr->isDebug = _G.debugLine; + + pic16_addpCode2pBlock(pb,pic16_newpCodeCharP(lb)); + + va_end(ap); +} + + +void pic16_emitpLabel(int key) +{ + pic16_addpCode2pBlock(pb,pic16_newpCodeLabel(NULL,key+100+labelOffset)); +} + +void pic16_emitpcode(PIC_OPCODE poc, pCodeOp *pcop) +{ + + if(pcop) + pic16_addpCode2pBlock(pb,pic16_newpCode(poc,pcop)); + else + DEBUGpic16_emitcode(";","%s ignoring NULL pcop",__FUNCTION__); +} + +void pic16_emitpcodeNULLop(PIC_OPCODE poc) +{ + + pic16_addpCode2pBlock(pb,pic16_newpCode(poc,NULL)); + +} + +/*-----------------------------------------------------------------*/ +/* 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]; + char *lbp = lb; + + va_start(ap,fmt); + + if (inst && *inst) { + if (fmt && *fmt) + sprintf(lb,"%s\t",inst); + else + sprintf(lb,"%s",inst); + vsprintf(lb+(strlen(lb)),fmt,ap); + } else + vsprintf(lb,fmt,ap); + + while (isspace(*lbp)) lbp++; + + if (lbp && *lbp) + lineCurr = (lineCurr ? + connectLine(lineCurr,newLineNode(lb)) : + (lineHead = newLineNode(lb))); + lineCurr->isInline = _G.inLine; + lineCurr->isDebug = _G.debugLine; + + if(pic16_debug_verbose) + pic16_addpCode2pBlock(pb,pic16_newpCodeCharP(lb)); + + va_end(ap); +} + + +/*-----------------------------------------------------------------*/ +/* getFreePtr - returns r0 or r1 whichever is free or can be pushed*/ +/*-----------------------------------------------------------------*/ +static regs *getFreePtr (iCode *ic, asmop **aopp, bool result) +{ + bool r0iu = FALSE , r1iu = FALSE; + bool r0ou = FALSE , r1ou = FALSE; + + /* the logic: if r0 & r1 used in the instruction + then we are in trouble otherwise */ + + /* first check if r0 & r1 are used by this + instruction, in which case we are in trouble */ + if ((r0iu = bitVectBitValue(ic->rUsed,R0_IDX)) && + (r1iu = bitVectBitValue(ic->rUsed,R1_IDX))) + { + goto endOfWorld; + } + + r0ou = bitVectBitValue(ic->rMask,R0_IDX); + r1ou = bitVectBitValue(ic->rMask,R1_IDX); + + /* if no usage of r0 then return it */ + if (!r0iu && !r0ou) { + ic->rUsed = bitVectSetBit(ic->rUsed,R0_IDX); + (*aopp)->type = AOP_R0; + + return (*aopp)->aopu.aop_ptr = pic16_regWithIdx(R0_IDX); + } + + /* if no usage of r1 then return it */ + if (!r1iu && !r1ou) { + ic->rUsed = bitVectSetBit(ic->rUsed,R1_IDX); + (*aopp)->type = AOP_R1; + + return (*aopp)->aopu.aop_ptr = pic16_regWithIdx(R1_IDX); + } + + /* now we know they both have usage */ + /* if r0 not used in this instruction */ + if (!r0iu) { + /* push it if not already pushed */ + if (!_G.r0Pushed) { + //pic16_emitcode ("push","%s", + // pic16_regWithIdx(R0_IDX)->dname); + _G.r0Pushed++ ; + } + + ic->rUsed = bitVectSetBit(ic->rUsed,R0_IDX); + (*aopp)->type = AOP_R0; + + return (*aopp)->aopu.aop_ptr = pic16_regWithIdx(R0_IDX); + } + + /* if r1 not used then */ + + if (!r1iu) { + /* push it if not already pushed */ + if (!_G.r1Pushed) { + //pic16_emitcode ("push","%s", + // pic16_regWithIdx(R1_IDX)->dname); + _G.r1Pushed++ ; + } + + ic->rUsed = bitVectSetBit(ic->rUsed,R1_IDX); + (*aopp)->type = AOP_R1; + return pic16_regWithIdx(R1_IDX); + } + +endOfWorld : + /* I said end of world but not quite end of world yet */ + /* if this is a result then we can push it on the stack*/ + if (result) { + (*aopp)->type = AOP_STK; + return NULL; + } + + /* other wise this is true end of the world */ + werror(E_INTERNAL_ERROR,__FILE__,__LINE__, + "getFreePtr should never reach here"); + exit(0); +} + +/*-----------------------------------------------------------------*/ +/* newAsmop - creates a new asmOp */ +/*-----------------------------------------------------------------*/ +static asmop *newAsmop (short type) +{ + asmop *aop; + + aop = Safe_calloc(1,sizeof(asmop)); + aop->type = type; + return aop; +} + +static void genSetDPTR(int n) +{ + if (!n) + { + pic16_emitcode(";", "Select standard DPTR"); + pic16_emitcode("mov", "dps, #0x00"); + } + else + { + pic16_emitcode(";", "Select alternate DPTR"); + pic16_emitcode("mov", "dps, #0x01"); + } +} + +/*-----------------------------------------------------------------*/ +/* resolveIfx - converts an iCode ifx into a form more useful for */ +/* generating code */ +/*-----------------------------------------------------------------*/ +static void resolveIfx(resolvedIfx *resIfx, iCode *ifx) +{ + if(!resIfx) + return; + + // DEBUGpic16_emitcode("; ***","%s %d",__FUNCTION__,__LINE__); + + 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 */ +/* + DEBUGpic16_emitcode("; ***","%s %d null ifx creating new label key =%d", + __FUNCTION__,__LINE__,resIfx->lbl->key); +*/ + } else { + if(IC_TRUE(ifx)) { + resIfx->lbl = IC_TRUE(ifx); + } else { + resIfx->lbl = IC_FALSE(ifx); + resIfx->condition = 0; + } +/* + if(IC_TRUE(ifx)) + DEBUGpic16_emitcode("; ***","ifx true is non-null"); + if(IC_FALSE(ifx)) + DEBUGpic16_emitcode("; ***","ifx false is non-null"); +*/ + } + + // DEBUGpic16_emitcode("; ***","%s lbl->key=%d, (lab offset=%d)",__FUNCTION__,resIfx->lbl->key,labelOffset); + +} +/*-----------------------------------------------------------------*/ +/* pointerCode - returns the code for a pointer type */ +/*-----------------------------------------------------------------*/ +static int pointerCode (sym_link *etype) +{ + + return PTR_TYPE(SPEC_OCLS(etype)); + +} + +/*-----------------------------------------------------------------*/ +/* aopForSym - for a true symbol */ +/*-----------------------------------------------------------------*/ +static asmop *aopForSym (iCode *ic,symbol *sym,bool result) +{ + asmop *aop; + memmap *space= SPEC_OCLS(sym->etype); + + DEBUGpic16_emitcode("; ***","%s %d",__FUNCTION__,__LINE__); + /* if already has one */ + if (sym->aop) + return sym->aop; + + /* assign depending on the storage class */ + /* if it is on the stack or indirectly addressable */ + /* space we need to assign either r0 or r1 to it */ + if ((sym->onStack && !options.stack10bit) || sym->iaccess) { + sym->aop = aop = newAsmop(0); + aop->aopu.aop_ptr = getFreePtr(ic,&aop,result); + aop->size = getSize(sym->type); + + /* now assign the address of the variable to + the pointer register */ + if (aop->type != AOP_STK) { + + if (sym->onStack) { + if ( _G.accInUse ) + 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; + } + + if (sym->onStack && options.stack10bit) + { + /* It's on the 10 bit stack, which is located in + * far data space. + */ + + //DEBUGpic16_emitcode(";","%d",__LINE__); + + 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); + + genSetDPTR(1); + pic16_emitcode ("mov","dpx1,#0x40"); + pic16_emitcode ("mov","dph1,#0x00"); + pic16_emitcode ("mov","dpl1, a"); + genSetDPTR(0); + + if ( _G.accInUse ) + pic16_emitcode("pop","acc"); + + sym->aop = aop = newAsmop(AOP_DPTR2); + aop->size = getSize(sym->type); + return aop; + } + + //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)) { + 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); + return aop; + } + + /* special case for a function */ + if (IS_FUNC(sym->type)) { + sym->aop = aop = newAsmop(AOP_IMMD); + //_ALLOC_ATOMIC(aop->aopu.aop_immd,strlen(sym->rname)+1); + aop->aopu.aop_immd = Safe_calloc(1,strlen(sym->rname)+1); + strcpy(aop->aopu.aop_immd,sym->rname); + aop->size = FPTRSIZE; + DEBUGpic16_emitcode(";","%d size = %d, name =%s",__LINE__,aop->size,sym->rname); + return aop; + } + + + /* only remaining is far space */ + /* in which case DPTR gets the address */ + sym->aop = aop = newAsmop(AOP_PCODE); + + aop->aopu.pcop = pic16_popGetImmd(sym->rname,0,0); + PCOI(aop->aopu.pcop)->_const = IN_CODESPACE(space); + PCOI(aop->aopu.pcop)->index = 0; + + DEBUGpic16_emitcode(";","%d: rname %s, val %d, const = %d", + __LINE__,sym->rname, 0, PCOI(aop->aopu.pcop)->_const); + + pic16_allocDirReg (IC_LEFT(ic)); + + aop->size = FPTRSIZE; +/* + DEBUGpic16_emitcode(";","%d size = %d, name =%s",__LINE__,aop->size,sym->rname); + sym->aop = aop = newAsmop(AOP_DPTR); + pic16_emitcode ("mov","dptr,#%s", sym->rname); + aop->size = getSize(sym->type); + + 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) // x symbol *sym) +{ + symbol *sym = OP_SYMBOL(op); + iCode *ic = NULL; + asmop *aop = newAsmop(AOP_PCODE); + int val = 0; + int offset = 0; + + ic = sym->rematiCode; + + DEBUGpic16_emitcode(";","%s %d",__FUNCTION__,__LINE__); + if(IS_OP_POINTER(op)) { + DEBUGpic16_emitcode(";","%s %d IS_OP_POINTER",__FUNCTION__,__LINE__); + } + for (;;) { + if (ic->op == '+') { + val += (int) operandLitValue(IC_RIGHT(ic)); + } else if (ic->op == '-') { + val -= (int) operandLitValue(IC_RIGHT(ic)); + } else + break; + + ic = OP_SYMBOL(IC_LEFT(ic))->rematiCode; + } + + offset = OP_SYMBOL(IC_LEFT(ic))->offset; + aop->aopu.pcop = pic16_popGetImmd(OP_SYMBOL(IC_LEFT(ic))->rname,0,val); + PCOI(aop->aopu.pcop)->_const = IS_PTR_CONST(operandType(op)); + PCOI(aop->aopu.pcop)->index = val; + + DEBUGpic16_emitcode(";","%d: rname %s, val %d, const = %d", + __LINE__,OP_SYMBOL(IC_LEFT(ic))->rname, + val, IS_PTR_CONST(operandType(op))); + + // DEBUGpic16_emitcode(";","aop type %s",pic16_AopType(AOP_TYPE(IC_LEFT(ic)))); + + pic16_allocDirReg (IC_LEFT(ic)); + + return aop; +} + +static int aopIdx (asmop *aop, int offset) +{ + if(!aop) + return -1; + + if(aop->type != AOP_REG) + return -2; + + return aop->aopu.aop_reg[offset]->rIdx; + +} +/*-----------------------------------------------------------------*/ +/* regsInCommon - two operands have some registers in common */ +/*-----------------------------------------------------------------*/ +static bool regsInCommon (operand *op1, operand *op2) +{ + symbol *sym1, *sym2; + int i; + + /* if they have registers in common */ + if (!IS_SYMOP(op1) || !IS_SYMOP(op2)) + return FALSE ; + + sym1 = OP_SYMBOL(op1); + sym2 = OP_SYMBOL(op2); + + if (sym1->nRegs == 0 || sym2->nRegs == 0) + return FALSE ; + + for (i = 0 ; i < sym1->nRegs ; i++) { + int j; + if (!sym1->regs[i]) + continue ; + + for (j = 0 ; j < sym2->nRegs ;j++ ) { + if (!sym2->regs[j]) + continue ; + + if (sym2->regs[j] == sym1->regs[i]) + return TRUE ; + } + } + + return FALSE ; +} + +/*-----------------------------------------------------------------*/ +/* operandsEqu - equivalent */ +/*-----------------------------------------------------------------*/ +static bool operandsEqu ( operand *op1, operand *op2) +{ + symbol *sym1, *sym2; + + /* if they not symbols */ + if (!IS_SYMOP(op1) || !IS_SYMOP(op2)) + return FALSE; + + sym1 = OP_SYMBOL(op1); + sym2 = OP_SYMBOL(op2); + + /* if both are itemps & one is spilt + and the other is not then false */ + if (IS_ITEMP(op1) && IS_ITEMP(op2) && + sym1->isspilt != sym2->isspilt ) + return FALSE ; + + /* if they are the same */ + if (sym1 == sym2) + return TRUE ; + + if (strcmp(sym1->rname,sym2->rname) == 0) + return TRUE; + + + /* if left is a tmp & right is not */ + if (IS_ITEMP(op1) && + !IS_ITEMP(op2) && + sym1->isspilt && + (sym1->usl.spillLoc == sym2)) + return TRUE; + + if (IS_ITEMP(op2) && + !IS_ITEMP(op1) && + sym2->isspilt && + sym1->level > 0 && + (sym2->usl.spillLoc == sym1)) + return TRUE ; + + return FALSE ; +} + +/*-----------------------------------------------------------------*/ +/* pic16_sameRegs - two asmops have the same registers */ +/*-----------------------------------------------------------------*/ +bool pic16_sameRegs (asmop *aop1, asmop *aop2 ) +{ + int i; + + if (aop1 == aop2) + return TRUE ; + + if (aop1->type != AOP_REG || + aop2->type != AOP_REG ) + return FALSE ; + + if (aop1->size != aop2->size ) + return FALSE ; + + for (i = 0 ; i < aop1->size ; i++ ) + if (aop1->aopu.aop_reg[i] != + aop2->aopu.aop_reg[i] ) + return FALSE ; + + return TRUE ; +} + +/*-----------------------------------------------------------------*/ +/* 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(";","%d",__LINE__); + /* if this a literal */ + if (IS_OP_LITERAL(op)) { + op->aop = aop = newAsmop(AOP_LIT); + aop->aopu.aop_lit = op->operand.valOperand; + aop->size = getSize(operandType(op)); + return; + } + + { + sym_link *type = operandType(op); + if(IS_PTR_CONST(type)) + 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",__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_SYMBOL(op),result); + return ; + } + + /* this is a temporary : this has + only four choices : + a) register + b) spillocation + c) rematerialize + d) conditional + e) can be a return use only */ + + sym = OP_SYMBOL(op); + + + /* if the type is a conditional */ + if (sym->regType == REG_CND) { + aop = op->aop = sym->aop = newAsmop(AOP_CRY); + aop->size = 0; + return; + } + + /* if it is spilt then two situations + a) is rematerialize + b) has a spill location */ + if (sym->isspilt || sym->nRegs == 0) { + + DEBUGpic16_emitcode(";","%d",__LINE__); + /* rematerialize it NOW */ + if (sym->remat) { + + sym->aop = op->aop = aop = + aopForRemat (op); + aop->size = getSize(sym->type); + //DEBUGpic16_emitcode(";"," %d: size %d, %s\n",__LINE__,aop->size,aop->aopu.aop_immd); + return; + } + + if (sym->accuse) { + int i; + aop = op->aop = sym->aop = newAsmop(AOP_ACC); + aop->size = getSize(sym->type); + for ( i = 0 ; i < 2 ; i++ ) + aop->aopu.aop_str[i] = accUse[i]; + DEBUGpic16_emitcode(";","%d size=%d",__LINE__,aop->size); + return; + } + + if (sym->ruonly ) { + /* + sym->aop = op->aop = aop = newAsmop(AOP_PCODE); + aop->aopu.pcop = pic16_popGetImmd(sym->usl.spillLoc->rname,0,sym->usl.spillLoc->offset); + //pic16_allocDirReg (IC_LEFT(ic)); + aop->size = getSize(sym->type); + */ + + unsigned i; + + aop = op->aop = sym->aop = newAsmop(AOP_STR); + aop->size = getSize(sym->type); + for ( i = 0 ; i < pic16_fReturnSizePic ; i++ ) + aop->aopu.aop_str[i] = fReturn[i]; + + DEBUGpic16_emitcode(";","%d",__LINE__); + return; + } + + /* else spill location */ + if (sym->usl.spillLoc && getSize(sym->type) != getSize(sym->usl.spillLoc->type)) { + /* force a new aop if sizes differ */ + sym->usl.spillLoc->aop = NULL; + } + DEBUGpic16_emitcode(";","%s %d %s sym->rname = %s, offset %d", + __FUNCTION__,__LINE__, + sym->usl.spillLoc->rname, + sym->rname, sym->usl.spillLoc->offset); + + sym->aop = op->aop = aop = newAsmop(AOP_PCODE); + //aop->aopu.pcop = pic16_popGetImmd(sym->usl.spillLoc->rname,0,sym->usl.spillLoc->offset); + aop->aopu.pcop = popRegFromString(sym->usl.spillLoc->rname, + getSize(sym->type), + sym->usl.spillLoc->offset); + aop->size = getSize(sym->type); + + return; + } + + { + sym_link *type = operandType(op); + if(IS_PTR_CONST(type)) + 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; + + /* depending on the asmop type only three cases need work AOP_RO + , AOP_R1 && AOP_STK */ +#if 0 + switch (aop->type) { + case AOP_R0 : + if (_G.r0Pushed ) { + if (pop) { + pic16_emitcode ("pop","ar0"); + _G.r0Pushed--; + } + } + bitVectUnSetBit(ic->rUsed,R0_IDX); + break; + + case AOP_R1 : + if (_G.r1Pushed ) { + if (pop) { + pic16_emitcode ("pop","ar1"); + _G.r1Pushed--; + } + } + bitVectUnSetBit(ic->rUsed,R1_IDX); + break; + + case AOP_STK : + { + int sz = aop->size; + int stk = aop->aopu.aop_stk + aop->size; + bitVectUnSetBit(ic->rUsed,R0_IDX); + bitVectUnSetBit(ic->rUsed,R1_IDX); + + getFreePtr(ic,&aop,FALSE); + + if (options.stack10bit) + { + /* I'm not sure what to do here yet... */ + /* #STUB */ + fprintf(stderr, + "*** Warning: probably generating bad code for " + "10 bit stack mode.\n"); + } + + if (stk) { + 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 + +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) +{ + char *s = buffer ; + char *rs; + + //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_R0: + case AOP_R1: + DEBUGpic16_emitcode(";","%d",__LINE__); + /* if we need to increment it */ + while (offset > aop->coff) { + pic16_emitcode ("inc","%s",aop->aopu.aop_ptr->name); + aop->coff++; + } + + while (offset < aop->coff) { + pic16_emitcode("dec","%s",aop->aopu.aop_ptr->name); + aop->coff--; + } + + aop->coff = offset ; + if (aop->paged) { + pic16_emitcode("movx","a,@%s",aop->aopu.aop_ptr->name); + return (dname ? "acc" : "a"); + } + sprintf(s,"@%s",aop->aopu.aop_ptr->name); + rs = Safe_calloc(1,strlen(s)+1); + strcpy(rs,s); + return rs; + + case AOP_DPTR: + case AOP_DPTR2: + DEBUGpic16_emitcode(";","%d",__LINE__); + if (aop->type == AOP_DPTR2) + { + genSetDPTR(1); + } + + while (offset > aop->coff) { + pic16_emitcode ("inc","dptr"); + aop->coff++; + } + + while (offset < aop->coff) { + pic16_emitcode("lcall","__decdptr"); + aop->coff--; + } + + aop->coff = offset; + if (aop->code) { + pic16_emitcode("clr","a"); + pic16_emitcode("movc","a,@a+dptr"); + } + else { + pic16_emitcode("movx","a,@dptr"); + } + + if (aop->type == AOP_DPTR2) + { + genSetDPTR(0); + } + + return (dname ? "acc" : "a"); + + + case AOP_IMMD: + if (bit16) + sprintf (s,"%s",aop->aopu.aop_immd); + else + if (offset) + sprintf(s,"(%s >> %d)", + aop->aopu.aop_immd, + offset*8); + else + sprintf(s,"%s", + aop->aopu.aop_immd); + DEBUGpic16_emitcode(";","%d immd %s",__LINE__,s); + rs = Safe_calloc(1,strlen(s)+1); + strcpy(rs,s); + return rs; + + case AOP_DIR: + if (offset) { + sprintf(s,"(%s + %d)", + aop->aopu.aop_dir, + offset); + DEBUGpic16_emitcode(";","oops AOP_DIR did this %s\n",s); + } else + sprintf(s,"%s",aop->aopu.aop_dir); + rs = Safe_calloc(1,strlen(s)+1); + strcpy(rs,s); + return rs; + + case AOP_REG: + //if (dname) + // return aop->aopu.aop_reg[offset]->dname; + //else + return aop->aopu.aop_reg[offset]->name; + + case AOP_CRY: + //pic16_emitcode(";","%d",__LINE__); + return aop->aopu.aop_dir; + + case AOP_ACC: + DEBUGpic16_emitcode(";Warning -pic port ignoring get(AOP_ACC)","%d",__LINE__); + return "AOP_accumulator_bug"; + + case AOP_LIT: + sprintf(s,"0x%02x", pic16aopLiteral (aop->aopu.aop_lit,offset)); + rs = Safe_calloc(1,strlen(s)+1); + strcpy(rs,s); + return rs; + + case AOP_STR: + aop->coff = offset ; + if (strcmp(aop->aopu.aop_str[offset],"a") == 0 && + dname) + return "acc"; + 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); + //sprintf(s,"(%s+0x%02x)", pcop->name,PCOI(aop->aopu.pcop)->offset); + sprintf(s,"%s", pcop->name); + } else + sprintf(s,"0x%02x", PCOI(aop->aopu.pcop)->offset); + + } + rs = Safe_calloc(1,strlen(s)+1); + strcpy(rs,s); + return rs; + + } + + werror(E_INTERNAL_ERROR,__FILE__,__LINE__, + "aopget got unsupported aop->type"); + exit(0); +} + + +/*-----------------------------------------------------------------*/ +/* pic16_popGetTempReg - create a new temporary pCodeOp */ +/*-----------------------------------------------------------------*/ +pCodeOp *pic16_popGetTempReg(void) +{ + + pCodeOp *pcop; + + 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; + } + + return pcop; +} + +/*-----------------------------------------------------------------*/ +/* pic16_popGetTempReg - create a new temporary pCodeOp */ +/*-----------------------------------------------------------------*/ +void pic16_popReleaseTempReg(pCodeOp *pcop) +{ + + if(pcop && pcop->type == PO_GPR_TEMP && PCOR(pcop)->r) + PCOR(pcop)->r->isFree = 1; + +} +/*-----------------------------------------------------------------*/ +/* pic16_popGetLabel - create a new pCodeOp of type PO_LABEL */ +/*-----------------------------------------------------------------*/ +pCodeOp *pic16_popGetLabel(unsigned int key) +{ + + DEBUGpic16_emitcode ("; ***","%s key=%d, label offset %d",__FUNCTION__,key, labelOffset); + + if(key>max_key) + max_key = key; + + return pic16_newpCodeOpLabel(NULL,key+100+labelOffset); +} + +/*-----------------------------------------------------------------*/ +/* pic16_popCopyReg - copy a pcode operator */ +/*-----------------------------------------------------------------*/ +pCodeOp *pic16_popCopyReg(pCodeOpReg *pc) +{ + pCodeOpReg *pcor; + + pcor = Safe_calloc(1,sizeof(pCodeOpReg) ); + 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; + + //DEBUGpic16_emitcode ("; ***","%s , copying %s, rIdx=%d",__FUNCTION__,pc->pcop.name,pc->rIdx); + + return PCOP(pcor); +} +/*-----------------------------------------------------------------*/ +/* pic16_popGet - asm operator to pcode operator conversion */ +/*-----------------------------------------------------------------*/ +pCodeOp *pic16_popGetLit(unsigned int lit) +{ + + return pic16_newpCodeOpLit(lit); +} + + +/*-----------------------------------------------------------------*/ +/* 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; +} + +/*-----------------------------------------------------------------*/ +/* popRegFromString - */ +/*-----------------------------------------------------------------*/ +static pCodeOp *popRegFromString(char *str, int size, int offset) +{ + + pCodeOp *pcop = Safe_calloc(1,sizeof(pCodeOpReg) ); + pcop->type = PO_DIR; + + DEBUGpic16_emitcode(";","%d",__LINE__); + + if(!str) + str = "BAD_STRING"; + + pcop->name = Safe_calloc(1,strlen(str)+1); + strcpy(pcop->name,str); + + //pcop->name = Safe_strdup( ( (str) ? str : "BAD STRING")); + + PCOR(pcop)->r = pic16_dirregWithName(pcop->name); + if(PCOR(pcop)->r == NULL) { + //fprintf(stderr,"%d - couldn't find %s in allocated registers, size =%d\n",__LINE__,aop->aopu.aop_dir,aop->size); + PCOR(pcop)->r = pic16_allocRegByName (pcop->name,size); + DEBUGpic16_emitcode(";","%d %s offset=%d - had to alloc by reg name",__LINE__,pcop->name,offset); + } else { + DEBUGpic16_emitcode(";","%d %s offset=%d",__LINE__,pcop->name,offset); + } + PCOR(pcop)->instance = offset; + + return pcop; +} + +static pCodeOp *popRegFromIdx(int rIdx) +{ + pCodeOp *pcop; + + DEBUGpic16_emitcode ("; ***","%s,%d , rIdx=0x%x", + __FUNCTION__,__LINE__,rIdx); + + pcop = Safe_calloc(1,sizeof(pCodeOpReg) ); + + PCOR(pcop)->rIdx = rIdx; + PCOR(pcop)->r = pic16_regWithIdx(rIdx); + PCOR(pcop)->r->isFree = 0; + PCOR(pcop)->r->wasUsed = 1; + + pcop->type = PCOR(pcop)->r->pc_type; + + + return pcop; +} +/*-----------------------------------------------------------------*/ +/* 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; + + //DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* 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_R0: + case AOP_R1: + case AOP_DPTR: + case AOP_DPTR2: + case AOP_ACC: + DEBUGpic16_emitcode(";8051 legacy","%d type = %s",__LINE__,pic16_AopType(aop->type)); + return NULL; + + case AOP_IMMD: + DEBUGpic16_emitcode(";","%d",__LINE__); + return pic16_popGetImmd(aop->aopu.aop_immd,offset,0); + + case AOP_DIR: + return popRegFromString(aop->aopu.aop_dir, aop->size, offset); +#if 0 + pcop = Safe_calloc(1,sizeof(pCodeOpReg) ); + pcop->type = PO_DIR; + + /* + if (offset) + sprintf(s,"(%s + %d)", + aop->aopu.aop_dir, + offset); + else + sprintf(s,"%s",aop->aopu.aop_dir); + pcop->name = Safe_calloc(1,strlen(s)+1); + strcpy(pcop->name,s); + */ + pcop->name = Safe_calloc(1,strlen(aop->aopu.aop_dir)+1); + strcpy(pcop->name,aop->aopu.aop_dir); + PCOR(pcop)->r = pic16_dirregWithName(aop->aopu.aop_dir); + if(PCOR(pcop)->r == NULL) { + //fprintf(stderr,"%d - couldn't find %s in allocated registers, size =%d\n",__LINE__,aop->aopu.aop_dir,aop->size); + PCOR(pcop)->r = pic16_allocRegByName (aop->aopu.aop_dir,aop->size); + DEBUGpic16_emitcode(";","%d %s offset=%d - had to alloc by reg name",__LINE__,pcop->name,offset); + } else { + DEBUGpic16_emitcode(";","%d %s offset=%d",__LINE__,pcop->name,offset); + } + PCOR(pcop)->instance = offset; + + return pcop; +#endif + + case AOP_REG: + { + int rIdx = aop->aopu.aop_reg[offset]->rIdx; + + pcop = Safe_calloc(1,sizeof(pCodeOpReg) ); + PCOR(pcop)->rIdx = rIdx; + PCOR(pcop)->r = pic16_regWithIdx(rIdx); + PCOR(pcop)->r->wasUsed=1; + PCOR(pcop)->r->isFree=0; + + PCOR(pcop)->instance = offset; + pcop->type = PCOR(pcop)->r->pc_type; + //rs = aop->aopu.aop_reg[offset]->name; + //DEBUGpic16_emitcode(";","%d regiser idx = %d name =%s",__LINE__,rIdx,rs); + return pcop; + } + + case AOP_CRY: + pcop = pic16_newpCodeOpBit(aop->aopu.aop_dir,-1,1); + 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: + return pic16_newpCodeOpLit(pic16aopLiteral (aop->aopu.aop_lit,offset)); + + case AOP_STR: + DEBUGpic16_emitcode(";","%d %s",__LINE__,aop->aopu.aop_str[offset]); + return pic16_newpCodeOpRegFromStr(aop->aopu.aop_str[offset]); + /* + pcop = Safe_calloc(1,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",pic16_pCodeOpType(aop->aopu.pcop), + __LINE__, + ((aop->aopu.pcop->name)? (aop->aopu.pcop->name) : "no name")); + pcop = pic16_pCodeOpCopy(aop->aopu.pcop); + PCOI(pcop)->offset = offset; + return pcop; + } + + werror(E_INTERNAL_ERROR,__FILE__,__LINE__, + "pic16_popGet got unsupported aop->type"); + exit(0); +} +/*-----------------------------------------------------------------*/ +/* pic16_aopPut - puts a string for a aop */ +/*-----------------------------------------------------------------*/ +void pic16_aopPut (asmop *aop, char *s, int offset) +{ + char *d = buffer ; + symbol *lbl ; + + 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) { + sprintf(d,"(%s + %d)", + aop->aopu.aop_dir,offset); + fprintf(stderr,"oops pic16_aopPut:AOP_DIR did this %s\n",s); + + } else + sprintf(d,"%s",aop->aopu.aop_dir); + + if (strcmp(d,s)) { + DEBUGpic16_emitcode(";","%d",__LINE__); + if(strcmp(s,"W")) + pic16_emitcode("movf","%s,w",s); + pic16_emitcode("movwf","%s",d); + + 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_calloc(1,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_DPTR: + case AOP_DPTR2: + + if (aop->type == AOP_DPTR2) + { + genSetDPTR(1); + } + + if (aop->code) { + werror(E_INTERNAL_ERROR,__FILE__,__LINE__, + "pic16_aopPut writting to code space"); + exit(0); + } + + while (offset > aop->coff) { + aop->coff++; + pic16_emitcode ("inc","dptr"); + } + + while (offset < aop->coff) { + aop->coff-- ; + pic16_emitcode("lcall","__decdptr"); + } + + aop->coff = offset; + + /* if not in accumulater */ + MOVA(s); + + pic16_emitcode ("movx","@dptr,a"); + + if (aop->type == AOP_DPTR2) + { + genSetDPTR(0); + } + break; + + case AOP_R0: + case AOP_R1: + while (offset > aop->coff) { + aop->coff++; + pic16_emitcode("inc","%s",aop->aopu.aop_ptr->name); + } + while (offset < aop->coff) { + aop->coff-- ; + pic16_emitcode ("dec","%s",aop->aopu.aop_ptr->name); + } + aop->coff = offset; + + if (aop->paged) { + MOVA(s); + pic16_emitcode("movx","@%s,a",aop->aopu.aop_ptr->name); + + } else + if (*s == '@') { + MOVA(s); + pic16_emitcode("mov","@%s,a ; %d",aop->aopu.aop_ptr->name,__LINE__); + } else + if (strcmp(s,"r0") == 0 || + strcmp(s,"r1") == 0 || + strcmp(s,"r2") == 0 || + strcmp(s,"r3") == 0 || + strcmp(s,"r4") == 0 || + strcmp(s,"r5") == 0 || + strcmp(s,"r6") == 0 || + strcmp(s,"r7") == 0 ) { + char buffer[10]; + sprintf(buffer,"a%s",s); + pic16_emitcode("mov","@%s,%s", + aop->aopu.aop_ptr->name,buffer); + } else + pic16_emitcode("mov","@%s,%s",aop->aopu.aop_ptr->name,s); + + 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_",lbl->key+100); + pic16_emitcode("cpl","c"); + pic16_emitcode("","%05d_DS_:",lbl->key+100); + 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 : + werror(E_INTERNAL_ERROR,__FILE__,__LINE__, + "pic16_aopPut got unsupported aop->type"); + exit(0); + } + +} + +/*-----------------------------------------------------------------*/ +/* mov2w - generate either a MOVLW or MOVFW based operand type */ +/*-----------------------------------------------------------------*/ +static void mov2w (asmop *aop, int offset) +{ + + if(!aop) + return; + + DEBUGpic16_emitcode ("; ***","%s %d offset=%d",__FUNCTION__,__LINE__,offset); + + if ( aop->type == AOP_PCODE || + aop->type == AOP_LIT ) + pic16_emitpcode(POC_MOVLW,pic16_popGet(aop,offset)); + else + pic16_emitpcode(POC_MOVFW,pic16_popGet(aop,offset)); + +} + +/*-----------------------------------------------------------------*/ +/* reAdjustPreg - points a register back to where it should */ +/*-----------------------------------------------------------------*/ +static void reAdjustPreg (asmop *aop) +{ + int size ; + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + aop->coff = 0; + if ((size = aop->size) <= 1) + return ; + size-- ; + switch (aop->type) { + case AOP_R0 : + case AOP_R1 : + while (size--) + pic16_emitcode("dec","%s",aop->aopu.aop_ptr->name); + break; + case AOP_DPTR : + case AOP_DPTR2: + if (aop->type == AOP_DPTR2) + { + genSetDPTR(1); + } + while (size--) + { + pic16_emitcode("lcall","__decdptr"); + } + + if (aop->type == AOP_DPTR2) + { + genSetDPTR(0); + } + break; + + } + +} + +/*-----------------------------------------------------------------*/ +/* genNotFloat - generates not for float operations */ +/*-----------------------------------------------------------------*/ +static void genNotFloat (operand *op, operand *res) +{ + int size, offset; + char *l; + symbol *tlbl ; + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* we will put 127 in the first byte of + the result */ + pic16_aopPut(AOP(res),"#127",0); + size = AOP_SIZE(op) - 1; + offset = 1; + + l = pic16_aopGet(op->aop,offset++,FALSE,FALSE); + MOVA(l); + + while(size--) { + pic16_emitcode("orl","a,%s", + pic16_aopGet(op->aop, + offset++,FALSE,FALSE)); + } + tlbl = newiTempLabel(NULL); + + tlbl = newiTempLabel(NULL); + pic16_aopPut(res->aop,one,1); + pic16_emitcode("jz","%05d_DS_",(tlbl->key+100)); + pic16_aopPut(res->aop,zero,1); + pic16_emitcode("","%05d_DS_:",(tlbl->key+100)); + + size = res->aop->size - 2; + offset = 2; + /* put zeros in the rest */ + while (size--) + pic16_aopPut(res->aop,zero,offset++); +} + +#if 0 +/*-----------------------------------------------------------------*/ +/* opIsGptr: returns non-zero if the passed operand is */ +/* a generic pointer type. */ +/*-----------------------------------------------------------------*/ +static int opIsGptr(operand *op) +{ + sym_link *type = operandType(op); + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + if ((AOP_SIZE(op) == GPTRSIZE) && IS_GENPTR(type)) + { + return 1; + } + return 0; +} +#endif + +/*-----------------------------------------------------------------*/ +/* 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 */ +/*-----------------------------------------------------------------*/ +void pic16_outBitC(operand *result) +{ + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* if the result is bit */ + if (AOP_TYPE(result) == AOP_CRY) + pic16_aopPut(AOP(result),"c",0); + else { + pic16_emitcode("clr","a ; %d", __LINE__); + pic16_emitcode("rlc","a"); + pic16_outAcc(result); + } +} + +/*-----------------------------------------------------------------*/ +/* 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++)); + } +} + + +/*-----------------------------------------------------------------*/ +/* genNot - generate code for ! operation */ +/*-----------------------------------------------------------------*/ +static void genNot (iCode *ic) +{ + symbol *tlbl; + sym_link *optype = operandType(IC_LEFT(ic)); + int size; + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* assign asmOps to operand & result */ + pic16_aopOp (IC_LEFT(ic),ic,FALSE); + pic16_aopOp (IC_RESULT(ic),ic,TRUE); + + DEBUGpic16_pic16_AopType(__LINE__,IC_LEFT(ic),NULL,IC_RESULT(ic)); + /* if in bit space then a special case */ + if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY) { + if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY) { + pic16_emitpcode(POC_MOVLW,pic16_popGet(AOP(IC_LEFT(ic)),0)); + pic16_emitpcode(POC_XORWF,pic16_popGet(AOP(IC_RESULT(ic)),0)); + } else { + pic16_emitpcode(POC_CLRF,pic16_popGet(AOP(IC_RESULT(ic)),0)); + pic16_emitpcode(POC_BTFSS,pic16_popGet(AOP(IC_LEFT(ic)),0)); + pic16_emitpcode(POC_INCF,pic16_popGet(AOP(IC_RESULT(ic)),0)); + } + goto release; + } + + /* if type float then do float */ + if (IS_FLOAT(optype)) { + genNotFloat(IC_LEFT(ic),IC_RESULT(ic)); + goto release; + } + + size = AOP_SIZE(IC_RESULT(ic)); + if(size == 1) { + pic16_emitpcode(POC_COMFW,pic16_popGet(AOP(IC_LEFT(ic)),0)); + pic16_emitpcode(POC_ANDLW,pic16_popGetLit(1)); + pic16_emitpcode(POC_MOVWF,pic16_popGet(AOP(IC_RESULT(ic)),0)); + goto release; + } + pic16_toBoolean(IC_LEFT(ic)); + + tlbl = newiTempLabel(NULL); + pic16_emitcode("cjne","a,#0x01,%05d_DS_",tlbl->key+100); + pic16_emitcode("","%05d_DS_:",tlbl->key+100); + pic16_outBitC(IC_RESULT(ic)); + + release: + /* release the aops */ + pic16_freeAsmop(IC_LEFT(ic),NULL,ic,(RESULTONSTACK(ic) ? 0 : 1)); + pic16_freeAsmop(IC_RESULT(ic),NULL,ic,TRUE); +} + + +/*-----------------------------------------------------------------*/ +/* genCpl - generate code for complement */ +/*-----------------------------------------------------------------*/ +static void genCpl (iCode *ic) +{ + int offset = 0; + int size ; + + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* assign asmOps to operand & result */ + pic16_aopOp (IC_LEFT(ic),ic,FALSE); + pic16_aopOp (IC_RESULT(ic),ic,TRUE); + + /* if both are in bit space then + a special case */ + if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY && + AOP_TYPE(IC_LEFT(ic)) == AOP_CRY ) { + + pic16_emitcode("mov","c,%s",IC_LEFT(ic)->aop->aopu.aop_dir); + pic16_emitcode("cpl","c"); + pic16_emitcode("mov","%s,c",IC_RESULT(ic)->aop->aopu.aop_dir); + goto release; + } + + size = AOP_SIZE(IC_RESULT(ic)); + while (size--) { + char *l = pic16_aopGet(AOP(IC_LEFT(ic)),offset,FALSE,FALSE); + MOVA(l); + pic16_emitcode("cpl","a"); + pic16_aopPut(AOP(IC_RESULT(ic)),"a",offset++); + } + + +release: + /* release the aops */ + pic16_freeAsmop(IC_LEFT(ic),NULL,ic,(RESULTONSTACK(ic) ? 0 : 1)); + pic16_freeAsmop(IC_RESULT(ic),NULL,ic,TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genUminusFloat - unary minus for floating points */ +/*-----------------------------------------------------------------*/ +static void genUminusFloat(operand *op,operand *result) +{ + int size ,offset =0 ; + char *l; + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* for this we just need to flip the + first it then copy the rest in place */ + size = AOP_SIZE(op) - 1; + l = pic16_aopGet(AOP(op),3,FALSE,FALSE); + + MOVA(l); + + pic16_emitcode("cpl","acc.7"); + pic16_aopPut(AOP(result),"a",3); + + while(size--) { + pic16_aopPut(AOP(result), + pic16_aopGet(AOP(op),offset,FALSE,FALSE), + offset); + offset++; + } +} + +/*-----------------------------------------------------------------*/ +/* genUminus - unary minus code generation */ +/*-----------------------------------------------------------------*/ +static void genUminus (iCode *ic) +{ + int size, i; + sym_link *optype, *rtype; + + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* 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)); + rtype = operandType(IC_RESULT(ic)); + + /* if float then do float stuff */ + if (IS_FLOAT(optype)) { + genUminusFloat(IC_LEFT(ic),IC_RESULT(ic)); + goto release; + } + + /* otherwise subtract from zero by taking the 2's complement */ + size = AOP_SIZE(IC_LEFT(ic)); + + for(i=0; inext) + if (ic->op == CALL || ic->op == PCALL) + break; + + if (!ic) { + fprintf(stderr,"found parameter push with no function call\n"); + return ; + } + + /* if the registers have been saved already then + do nothing */ + if (ic->regsSaved || IFFUNC_CALLEESAVES(OP_SYMBOL(IC_LEFT(ic))->type)) + return ; + + /* find the registers in use at this time + and push them away to safety */ + rsave = bitVectCplAnd(bitVectCopy(ic->rMask), + ic->rUsed); + + ic->regsSaved = 1; + if (options.useXstack) { + if (bitVectBitValue(rsave,R0_IDX)) + pic16_emitcode("mov","b,r0"); + pic16_emitcode("mov","r0,%s",spname); + for (i = 0 ; i < pic16_nRegs ; i++) { + if (bitVectBitValue(rsave,i)) { + if (i == R0_IDX) + pic16_emitcode("mov","a,b"); + else + pic16_emitcode("mov","a,%s",pic16_regWithIdx(i)->name); + pic16_emitcode("movx","@r0,a"); + pic16_emitcode("inc","r0"); + } + } + pic16_emitcode("mov","%s,r0",spname); + if (bitVectBitValue(rsave,R0_IDX)) + pic16_emitcode("mov","r0,b"); + }// else + //for (i = 0 ; i < pic16_nRegs ; i++) { + // if (bitVectBitValue(rsave,i)) + // pic16_emitcode("push","%s",pic16_regWithIdx(i)->dname); + //} + + dtype = operandType(IC_LEFT(ic)); + if (currFunc && dtype && + (FUNC_REGBANK(currFunc->type) != FUNC_REGBANK(dtype)) && + IFFUNC_ISISR(currFunc->type) && + !ic->bankSaved) + + saverbank(FUNC_REGBANK(dtype),ic,TRUE); + +} +/*-----------------------------------------------------------------*/ +/* unsaveRegisters - pop the pushed registers */ +/*-----------------------------------------------------------------*/ +static void unsaveRegisters (iCode *ic) +{ + int i; + bitVect *rsave; + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* find the registers in use at this time + and push them away to safety */ + rsave = bitVectCplAnd(bitVectCopy(ic->rMask), + ic->rUsed); + + if (options.useXstack) { + pic16_emitcode("mov","r0,%s",spname); + for (i = pic16_nRegs ; i >= 0 ; i--) { + if (bitVectBitValue(rsave,i)) { + pic16_emitcode("dec","r0"); + pic16_emitcode("movx","a,@r0"); + if (i == R0_IDX) + pic16_emitcode("mov","b,a"); + else + pic16_emitcode("mov","%s,a",pic16_regWithIdx(i)->name); + } + + } + pic16_emitcode("mov","%s,r0",spname); + if (bitVectBitValue(rsave,R0_IDX)) + pic16_emitcode("mov","r0,b"); + } //else + //for (i = pic16_nRegs ; i >= 0 ; i--) { + // if (bitVectBitValue(rsave,i)) + // pic16_emitcode("pop","%s",pic16_regWithIdx(i)->dname); + //} + +} + + +/*-----------------------------------------------------------------*/ +/* pushSide - */ +/*-----------------------------------------------------------------*/ +static void pushSide(operand * oper, int size) +{ +#if 0 + int offset = 0; + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + while (size--) { + char *l = pic16_aopGet(AOP(oper),offset++,FALSE,TRUE); + if (AOP_TYPE(oper) != AOP_REG && + AOP_TYPE(oper) != AOP_DIR && + strcmp(l,"a") ) { + pic16_emitcode("mov","a,%s",l); + pic16_emitcode("push","acc"); + } else + pic16_emitcode("push","%s",l); + } +#endif +} + +/*-----------------------------------------------------------------*/ +/* assignResultValue - */ +/*-----------------------------------------------------------------*/ +static void assignResultValue(operand * oper) +{ + int size = AOP_SIZE(oper); + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + DEBUGpic16_pic16_AopType(__LINE__,oper,NULL,NULL); + + if(!GpsuedoStkPtr) { + /* The last byte in the assignment is in W */ + size--; + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(oper),size)); + GpsuedoStkPtr++; + } + + while (size--) { + pic16_emitpcode(POC_MOVFW,popRegFromIdx(GpsuedoStkPtr-1 + pic16_Gstack_base_addr)); + GpsuedoStkPtr++; + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(oper),size)); + } +} + + +/*-----------------------------------------------------------------*/ +/* genIpush - genrate code for pushing this gets a little complex */ +/*-----------------------------------------------------------------*/ +static void genIpush (iCode *ic) +{ + + DEBUGpic16_emitcode ("; ***","%s %d - WARNING no code generated",__FUNCTION__,__LINE__); +#if 0 + int size, offset = 0 ; + char *l; + + + /* if this is not a parm push : ie. it is spill push + and spill push is always done on the local stack */ + if (!ic->parmPush) { + + /* and the item is spilt then do nothing */ + if (OP_SYMBOL(IC_LEFT(ic))->isspilt) + return ; + + 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 ; + } + + /* this is a paramter push: in this case we call + the routine to find the call and save those + registers that need to be saved */ + saveRegisters(ic); + + /* then do the push */ + pic16_aopOp(IC_LEFT(ic),ic,FALSE); + + + // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic))); + size = AOP_SIZE(IC_LEFT(ic)); + + while (size--) { + l = pic16_aopGet(AOP(IC_LEFT(ic)),offset++,FALSE,TRUE); + if (AOP_TYPE(IC_LEFT(ic)) != AOP_REG && + AOP_TYPE(IC_LEFT(ic)) != AOP_DIR && + strcmp(l,"a") ) { + pic16_emitcode("mov","a,%s",l); + pic16_emitcode("push","acc"); + } else + pic16_emitcode("push","%s",l); + } + + pic16_freeAsmop(IC_LEFT(ic),NULL,ic,TRUE); +#endif +} + +/*-----------------------------------------------------------------*/ +/* genIpop - recover the registers: can happen only for spilling */ +/*-----------------------------------------------------------------*/ +static void genIpop (iCode *ic) +{ + 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 +} + +/*-----------------------------------------------------------------*/ +/* unsaverbank - restores the resgister bank from stack */ +/*-----------------------------------------------------------------*/ +static void unsaverbank (int bank,iCode *ic,bool popPsw) +{ + DEBUGpic16_emitcode ("; ***","%s %d - WARNING no code generated",__FUNCTION__,__LINE__); +#if 0 + int i; + asmop *aop ; + regs *r = NULL; + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + if (popPsw) { + if (options.useXstack) { + aop = newAsmop(0); + r = getFreePtr(ic,&aop,FALSE); + + + pic16_emitcode("mov","%s,_spx",r->name); + pic16_emitcode("movx","a,@%s",r->name); + pic16_emitcode("mov","psw,a"); + pic16_emitcode("dec","%s",r->name); + + }else + pic16_emitcode ("pop","psw"); + } + + for (i = (pic16_nRegs - 1) ; i >= 0 ;i--) { + if (options.useXstack) { + pic16_emitcode("movx","a,@%s",r->name); + //pic16_emitcode("mov","(%s+%d),a", + // regspic16[i].base,8*bank+regspic16[i].offset); + pic16_emitcode("dec","%s",r->name); + + } else + pic16_emitcode("pop",""); //"(%s+%d)", + //regspic16[i].base,8*bank); //+regspic16[i].offset); + } + + if (options.useXstack) { + + pic16_emitcode("mov","_spx,%s",r->name); + pic16_freeAsmop(NULL,aop,ic,TRUE); + + } +#endif +} + +/*-----------------------------------------------------------------*/ +/* saverbank - saves an entire register bank on the stack */ +/*-----------------------------------------------------------------*/ +static void saverbank (int bank, iCode *ic, bool pushPsw) +{ + DEBUGpic16_emitcode ("; ***","%s %d - WARNING no code generated",__FUNCTION__,__LINE__); +#if 0 + int i; + asmop *aop ; + regs *r = NULL; + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + if (options.useXstack) { + + aop = newAsmop(0); + r = getFreePtr(ic,&aop,FALSE); + pic16_emitcode("mov","%s,_spx",r->name); + + } + + for (i = 0 ; i < pic16_nRegs ;i++) { + if (options.useXstack) { + pic16_emitcode("inc","%s",r->name); + //pic16_emitcode("mov","a,(%s+%d)", + // regspic16[i].base,8*bank+regspic16[i].offset); + pic16_emitcode("movx","@%s,a",r->name); + } else + pic16_emitcode("push","");// "(%s+%d)", + //regspic16[i].base,8*bank+regspic16[i].offset); + } + + if (pushPsw) { + if (options.useXstack) { + pic16_emitcode("mov","a,psw"); + pic16_emitcode("movx","@%s,a",r->name); + pic16_emitcode("inc","%s",r->name); + pic16_emitcode("mov","_spx,%s",r->name); + pic16_freeAsmop (NULL,aop,ic,TRUE); + + } else + pic16_emitcode("push","psw"); + + pic16_emitcode("mov","psw,#0x%02x",(bank << 3)&0x00ff); + } + ic->bankSaved = 1; +#endif +} + +/*-----------------------------------------------------------------*/ +/* genCall - generates a call statement */ +/*-----------------------------------------------------------------*/ +static void genCall (iCode *ic) +{ + sym_link *dtype; + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + /* if caller saves & we have not saved then */ + if (!ic->regsSaved) + saveRegisters(ic); + + /* if we are calling a function that is not using + the same register bank then we need to save the + destination registers on the stack */ + dtype = operandType(IC_LEFT(ic)); + if (currFunc && dtype && + (FUNC_REGBANK(currFunc->type) != FUNC_REGBANK(dtype)) && + IFFUNC_ISISR(currFunc->type) && + !ic->bankSaved) + + saverbank(FUNC_REGBANK(dtype),ic,TRUE); + + /* if send set is not empty the assign */ + if (_G.sendSet) { + iCode *sic; + /* For the Pic port, there is no data stack. + * So parameters passed to functions are stored + * in registers. (The pCode optimizer will get + * rid of most of these :). + */ + int psuedoStkPtr=-1; + int firstTimeThruLoop = 1; + + _G.sendSet = reverseSet(_G.sendSet); + + /* First figure how many parameters are getting passed */ + for (sic = setFirstItem(_G.sendSet) ; sic ; + sic = setNextItem(_G.sendSet)) { + + pic16_aopOp(IC_LEFT(sic),sic,FALSE); + psuedoStkPtr += AOP_SIZE(IC_LEFT(sic)); + pic16_freeAsmop (IC_LEFT(sic),NULL,sic,FALSE); + } + + for (sic = setFirstItem(_G.sendSet) ; sic ; + sic = setNextItem(_G.sendSet)) { + int size, offset = 0; + + pic16_aopOp(IC_LEFT(sic),sic,FALSE); + size = AOP_SIZE(IC_LEFT(sic)); + + while (size--) { + DEBUGpic16_emitcode ("; ","%d left %s",__LINE__, + pic16_AopType(AOP_TYPE(IC_LEFT(sic)))); + + if(!firstTimeThruLoop) { + /* If this is not the first time we've been through the loop + * then we need to save the parameter in a temporary + * register. The last byte of the last parameter is + * passed in W. */ + pic16_emitpcode(POC_MOVWF,popRegFromIdx(--psuedoStkPtr + pic16_Gstack_base_addr)); + + } + firstTimeThruLoop=0; + + //if (strcmp(l,fReturn[offset])) { + mov2w (AOP(IC_LEFT(sic)), offset); +/* + if ( ((AOP(IC_LEFT(sic))->type) == AOP_PCODE) || + ((AOP(IC_LEFT(sic))->type) == AOP_LIT) ) + pic16_emitpcode(POC_MOVLW,pic16_popGet(AOP(IC_LEFT(sic)),offset)); + else + pic16_emitpcode(POC_MOVFW,pic16_popGet(AOP(IC_LEFT(sic)),offset)); +*/ + //} + offset++; + } + pic16_freeAsmop (IC_LEFT(sic),NULL,sic,TRUE); + } + _G.sendSet = NULL; + } + /* make the call */ + pic16_emitpcode(POC_CALL,pic16_popGetWithString(OP_SYMBOL(IC_LEFT(ic))->rname[0] ? + OP_SYMBOL(IC_LEFT(ic))->rname : + OP_SYMBOL(IC_LEFT(ic))->name)); + + GpsuedoStkPtr=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--; + + assignResultValue(IC_RESULT(ic)); + + DEBUGpic16_emitcode ("; ","%d left %s",__LINE__, + pic16_AopType(AOP_TYPE(IC_RESULT(ic)))); + + pic16_freeAsmop(IC_RESULT(ic),NULL, ic,TRUE); + } + + /* adjust the stack for parameters if + required */ + if (ic->parmBytes) { + int i; + if (ic->parmBytes > 3) { + pic16_emitcode("mov","a,%s",spname); + pic16_emitcode("add","a,#0x%02x", (- ic->parmBytes) & 0xff); + pic16_emitcode("mov","%s,a",spname); + } else + for ( i = 0 ; i < ic->parmBytes ;i++) + pic16_emitcode("dec","%s",spname); + + } + + /* if register bank was saved then pop them */ + if (ic->bankSaved) + unsaverbank(FUNC_REGBANK(dtype),ic,TRUE); + + /* if we hade saved some registers then unsave them */ + if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype)) + unsaveRegisters (ic); + + +} + +/*-----------------------------------------------------------------*/ +/* genPcall - generates a call by pointer statement */ +/*-----------------------------------------------------------------*/ +static void genPcall (iCode *ic) +{ + sym_link *dtype; + symbol *rlbl = newiTempLabel(NULL); + + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* if caller saves & we have not saved then */ + if (!ic->regsSaved) + saveRegisters(ic); + + /* if we are calling a function that is not using + the same register bank then we need to save the + destination registers on the stack */ + dtype = operandType(IC_LEFT(ic)); + if (currFunc && dtype && + IFFUNC_ISISR(currFunc->type) && + (FUNC_REGBANK(currFunc->type) != FUNC_REGBANK(dtype))) + saverbank(FUNC_REGBANK(dtype),ic,TRUE); + + + /* push the return address on to the stack */ + pic16_emitcode("mov","a,#%05d_DS_",(rlbl->key+100)); + pic16_emitcode("push","acc"); + pic16_emitcode("mov","a,#(%05d_DS_ >> 8)",(rlbl->key+100)); + pic16_emitcode("push","acc"); + + if (options.model == MODEL_FLAT24) + { + pic16_emitcode("mov","a,#(%05d_DS_ >> 16)",(rlbl->key+100)); + pic16_emitcode("push","acc"); + } + + /* now push the calling address */ + pic16_aopOp(IC_LEFT(ic),ic,FALSE); + + pushSide(IC_LEFT(ic), FPTRSIZE); + + pic16_freeAsmop(IC_LEFT(ic),NULL,ic,TRUE); + + /* if send set is not empty the assign */ + if (_G.sendSet) { + iCode *sic ; + + for (sic = setFirstItem(_G.sendSet) ; sic ; + sic = setNextItem(_G.sendSet)) { + int size, offset = 0; + pic16_aopOp(IC_LEFT(sic),sic,FALSE); + size = AOP_SIZE(IC_LEFT(sic)); + while (size--) { + char *l = pic16_aopGet(AOP(IC_LEFT(sic)),offset, + FALSE,FALSE); + if (strcmp(l,fReturn[offset])) + pic16_emitcode("mov","%s,%s", + fReturn[offset], + l); + offset++; + } + pic16_freeAsmop (IC_LEFT(sic),NULL,sic,TRUE); + } + _G.sendSet = NULL; + } + + pic16_emitcode("ret",""); + pic16_emitcode("","%05d_DS_:",(rlbl->key+100)); + + + /* if we need assign a result value */ + if ((IS_ITEMP(IC_RESULT(ic)) && + (OP_SYMBOL(IC_RESULT(ic))->nRegs || + OP_SYMBOL(IC_RESULT(ic))->spildir)) || + IS_TRUE_SYMOP(IC_RESULT(ic)) ) { + + _G.accInUse++; + pic16_aopOp(IC_RESULT(ic),ic,FALSE); + _G.accInUse--; + + assignResultValue(IC_RESULT(ic)); + + pic16_freeAsmop(IC_RESULT(ic),NULL,ic,TRUE); + } + + /* adjust the stack for parameters if + required */ + if (ic->parmBytes) { + int i; + if (ic->parmBytes > 3) { + pic16_emitcode("mov","a,%s",spname); + pic16_emitcode("add","a,#0x%02x", (- ic->parmBytes) & 0xff); + pic16_emitcode("mov","%s,a",spname); + } else + for ( i = 0 ; i < ic->parmBytes ;i++) + pic16_emitcode("dec","%s",spname); + + } + + /* if register bank was saved then unsave them */ + if (currFunc && dtype && + (FUNC_REGBANK(currFunc->type) != FUNC_REGBANK(dtype))) + unsaverbank(FUNC_REGBANK(dtype),ic,TRUE); + + /* if we hade saved some registers then + unsave them */ + if (ic->regsSaved) + unsaveRegisters (ic); + +} + +/*-----------------------------------------------------------------*/ +/* resultRemat - result is rematerializable */ +/*-----------------------------------------------------------------*/ +static int resultRemat (iCode *ic) +{ + // 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 defined(__BORLANDC__) || defined(_MSC_VER) +#define STRCASECMP stricmp +#else +#define STRCASECMP strcasecmp +#endif + +#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; + + DEBUGpic16_emitcode ("; ***","%s %d curr label offset=%dprevious max_key=%d ",__FUNCTION__,__LINE__,labelOffset,max_key); + + labelOffset += (max_key+4); + max_key=0; + GpsuedoStkPtr=0; + _G.nRegsSaved = 0; + /* create the function header */ + pic16_emitcode(";","-----------------------------------------"); + pic16_emitcode(";"," function %s",(sym = OP_SYMBOL(IC_LEFT(ic)))->name); + pic16_emitcode(";","-----------------------------------------"); + + pic16_emitcode("","%s:",sym->rname); + pic16_addpCode2pBlock(pb,pic16_newpCodeFunction(NULL,sym->rname)); + + ftype = operandType(IC_LEFT(ic)); + + /* if critical function then turn interrupts off */ + if (IFFUNC_ISCRITICAL(ftype)) + pic16_emitcode("clr","ea"); + + /* here we need to generate the equates for the + register bank if required */ +#if 0 + if (FUNC_REGBANK(ftype) != rbank) { + int i ; + + rbank = FUNC_REGBANK(ftype); + for ( i = 0 ; i < pic16_nRegs ; i++ ) { + if (strcmp(regspic16[i].base,"0") == 0) + pic16_emitcode("","%s = 0x%02x", + regspic16[i].dname, + 8*rbank+regspic16[i].offset); + else + pic16_emitcode ("","%s = %s + 0x%02x", + regspic16[i].dname, + regspic16[i].base, + 8*rbank+regspic16[i].offset); + } + } +#endif + + /* if this is an interrupt service routine then + save acc, b, dpl, dph */ + if (IFFUNC_ISISR(sym->type)) { + pic16_addpCode2pBlock(pb,pic16_newpCode(POC_BRA,pic16_newpCodeOp("END_OF_INTERRUPT+2",PO_STR))); + pic16_emitpcodeNULLop(POC_NOP); + pic16_emitpcodeNULLop(POC_NOP); + pic16_emitpcodeNULLop(POC_NOP); + pic16_emitpcode(POC_MOVWF, pic16_popCopyReg(&pic16_pc_wsave)); + pic16_emitpcode(POC_SWAPFW, pic16_popCopyReg(&pic16_pc_status)); + pic16_emitpcode(POC_CLRF, pic16_popCopyReg(&pic16_pc_status)); + pic16_emitpcode(POC_MOVWF, pic16_popCopyReg(&pic16_pc_ssave)); + + pic16_pBlockConvert2ISR(pb); +#if 0 + if (!inExcludeList("acc")) + pic16_emitcode ("push","acc"); + if (!inExcludeList("b")) + pic16_emitcode ("push","b"); + if (!inExcludeList("dpl")) + pic16_emitcode ("push","dpl"); + if (!inExcludeList("dph")) + pic16_emitcode ("push","dph"); + if (options.model == MODEL_FLAT24 && !inExcludeList("dpx")) + { + pic16_emitcode ("push", "dpx"); + /* Make sure we're using standard DPTR */ + pic16_emitcode ("push", "dps"); + pic16_emitcode ("mov", "dps, #0x00"); + if (options.stack10bit) + { + /* This ISR could conceivably use DPTR2. Better save it. */ + pic16_emitcode ("push", "dpl1"); + pic16_emitcode ("push", "dph1"); + pic16_emitcode ("push", "dpx1"); + } + } + /* if this isr has no bank i.e. is going to + run with bank 0 , then we need to save more + registers :-) */ + if (!FUNC_REGBANK(sym->type)) { + + /* if this function does not call any other + function then we can be economical and + save only those registers that are used */ + if (! IFFUNC_HASFCALL(sym->type)) { + int i; + + /* if any registers used */ + if (sym->regsUsed) { + /* save the registers used */ + for ( i = 0 ; i < sym->regsUsed->size ; i++) { + if (bitVectBitValue(sym->regsUsed,i) || + (pic16_ptrRegReq && (i == R0_IDX || i == R1_IDX)) ) + pic16_emitcode("push","junk");//"%s",pic16_regWithIdx(i)->dname); + } + } + + } else { + /* this function has a function call cannot + determines register usage so we will have the + entire bank */ + saverbank(0,ic,FALSE); + } + } +#endif + } else { + /* if callee-save to be used for this function + then save the registers being used in this function */ + if (IFFUNC_CALLEESAVES(sym->type)) { + int i; + + /* if any registers used */ + if (sym->regsUsed) { + /* save the registers used */ + for ( i = 0 ; i < sym->regsUsed->size ; i++) { + if (bitVectBitValue(sym->regsUsed,i) || + (pic16_ptrRegReq && (i == R0_IDX || i == R1_IDX)) ) { + //pic16_emitcode("push","%s",pic16_regWithIdx(i)->dname); + _G.nRegsSaved++; + } + } + } + } + } + + /* set the register bank to the desired value */ + if (FUNC_REGBANK(sym->type) || FUNC_ISISR(sym->type)) { + pic16_emitcode("push","psw"); + pic16_emitcode("mov","psw,#0x%02x",(FUNC_REGBANK(sym->type) << 3)&0x00ff); + } + + if (IFFUNC_ISREENT(sym->type) || options.stackAuto) { + + if (options.useXstack) { + pic16_emitcode("mov","r0,%s",spname); + pic16_emitcode("mov","a,_bp"); + pic16_emitcode("movx","@r0,a"); + pic16_emitcode("inc","%s",spname); + } + else + { + /* set up the stack */ + pic16_emitcode ("push","_bp"); /* save the callers stack */ + } + pic16_emitcode ("mov","_bp,%s",spname); + } + + /* adjust the stack for the function */ + if (sym->stack) { + + int i = sym->stack; + if (i > 256 ) + werror(W_STACK_OVERFLOW,sym->name); + + if (i > 3 && sym->recvSize < 4) { + + pic16_emitcode ("mov","a,sp"); + pic16_emitcode ("add","a,#0x%02x",((char)sym->stack & 0xff)); + pic16_emitcode ("mov","sp,a"); + + } + else + while(i--) + pic16_emitcode("inc","sp"); + } + + if (sym->xstack) { + + pic16_emitcode ("mov","a,_spx"); + pic16_emitcode ("add","a,#0x%02x",((char)sym->xstack & 0xff)); + pic16_emitcode ("mov","_spx,a"); + } + +} + +/*-----------------------------------------------------------------*/ +/* genEndFunction - generates epilogue for functions */ +/*-----------------------------------------------------------------*/ +static void genEndFunction (iCode *ic) +{ + symbol *sym = OP_SYMBOL(IC_LEFT(ic)); + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + if (IFFUNC_ISREENT(sym->type) || options.stackAuto) + { + pic16_emitcode ("mov","%s,_bp",spname); + } + + /* if use external stack but some variables were + added to the local stack then decrement the + local stack */ + if (options.useXstack && sym->stack) { + pic16_emitcode("mov","a,sp"); + pic16_emitcode("add","a,#0x%02x",((char)-sym->stack) & 0xff); + pic16_emitcode("mov","sp,a"); + } + + + if ((IFFUNC_ISREENT(sym->type) || options.stackAuto)) { + if (options.useXstack) { + pic16_emitcode("mov","r0,%s",spname); + pic16_emitcode("movx","a,@r0"); + pic16_emitcode("mov","_bp,a"); + pic16_emitcode("dec","%s",spname); + } + else + { + pic16_emitcode ("pop","_bp"); + } + } + + /* restore the register bank */ + if (FUNC_REGBANK(sym->type) || FUNC_ISISR(sym->type)) + pic16_emitcode ("pop","psw"); + + if (IFFUNC_ISISR(sym->type)) { + + /* now we need to restore the registers */ + /* if this isr has no bank i.e. is going to + run with bank 0 , then we need to save more + registers :-) */ + if (!FUNC_REGBANK(sym->type)) { + + /* if this function does not call any other + function then we can be economical and + save only those registers that are used */ + if (! IFFUNC_HASFCALL(sym->type)) { + int i; + + /* if any registers used */ + if (sym->regsUsed) { + /* save the registers used */ + for ( i = sym->regsUsed->size ; i >= 0 ; i--) { + if (bitVectBitValue(sym->regsUsed,i) || + (pic16_ptrRegReq && (i == R0_IDX || i == R1_IDX)) ) + pic16_emitcode("pop","junk");//"%s",pic16_regWithIdx(i)->dname); + } + } + + } else { + /* this function has a function call cannot + determines register usage so we will have the + entire bank */ + unsaverbank(0,ic,FALSE); + } + } +#if 0 + if (options.model == MODEL_FLAT24 && !inExcludeList("dpx")) + { + if (options.stack10bit) + { + pic16_emitcode ("pop", "dpx1"); + pic16_emitcode ("pop", "dph1"); + pic16_emitcode ("pop", "dpl1"); + } + pic16_emitcode ("pop", "dps"); + pic16_emitcode ("pop", "dpx"); + } + if (!inExcludeList("dph")) + pic16_emitcode ("pop","dph"); + if (!inExcludeList("dpl")) + pic16_emitcode ("pop","dpl"); + if (!inExcludeList("b")) + pic16_emitcode ("pop","b"); + if (!inExcludeList("acc")) + pic16_emitcode ("pop","acc"); + + if (IFFUNC_ISCRITICAL(sym->type)) + pic16_emitcode("setb","ea"); +#endif + + /* if debug then send end of function */ +/* if (options.debug && currFunc) { */ + if (currFunc) { + _G.debugLine = 1; + pic16_emitcode(";","C$%s$%d$%d$%d ==.", + FileBaseName(ic->filename),currFunc->lastLine, + ic->level,ic->block); + if (IS_STATIC(currFunc->etype)) + pic16_emitcode(";","XF%s$%s$0$0 ==.",moduleName,currFunc->name); + else + pic16_emitcode(";","XG$%s$0$0 ==.",currFunc->name); + _G.debugLine = 0; + } + + pic16_emitcode ("reti",""); + + pic16_emitpcode(POC_CLRF, pic16_popCopyReg(&pic16_pc_status)); + pic16_emitpcode(POC_SWAPFW, pic16_popCopyReg(&pic16_pc_ssave)); + pic16_emitpcode(POC_MOVWF, pic16_popCopyReg(&pic16_pc_status)); + pic16_emitpcode(POC_SWAPF, pic16_popCopyReg(&pic16_pc_wsave)); + pic16_emitpcode(POC_SWAPFW, pic16_popCopyReg(&pic16_pc_wsave)); + pic16_addpCode2pBlock(pb,pic16_newpCodeLabel("END_OF_INTERRUPT",-1)); + + pic16_emitpcodeNULLop(POC_RETFIE); + + } + else { + if (IFFUNC_ISCRITICAL(sym->type)) + pic16_emitcode("setb","ea"); + + if (IFFUNC_CALLEESAVES(sym->type)) { + int i; + + /* if any registers used */ + if (sym->regsUsed) { + /* save the registers used */ + for ( i = sym->regsUsed->size ; i >= 0 ; i--) { + if (bitVectBitValue(sym->regsUsed,i) || + (pic16_ptrRegReq && (i == R0_IDX || i == R1_IDX)) ) + pic16_emitcode("pop","junk");//"%s",pic16_regWithIdx(i)->dname); + } + } + + } + + /* if debug then send end of function */ + if (currFunc) { + _G.debugLine = 1; + pic16_emitcode(";","C$%s$%d$%d$%d ==.", + FileBaseName(ic->filename),currFunc->lastLine, + ic->level,ic->block); + if (IS_STATIC(currFunc->etype)) + pic16_emitcode(";","XF%s$%s$0$0 ==.",moduleName,currFunc->name); + else + pic16_emitcode(";","XG$%s$0$0 ==.",currFunc->name); + _G.debugLine = 0; + } + + pic16_emitcode ("return",""); + pic16_emitpcodeNULLop(POC_RETURN); + + /* Mark the end of a function */ + pic16_addpCode2pBlock(pb,pic16_newpCodeFunction(NULL,NULL)); + } + +} + +/*-----------------------------------------------------------------*/ +/* genRet - generate code for return statement */ +/*-----------------------------------------------------------------*/ +static void genRet (iCode *ic) +{ + int size,offset = 0 , pushed = 0; + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* if we have no return value then + just generate the "ret" */ + if (!IC_LEFT(ic)) + goto jumpret; + + /* we have something to return then + move the return value into place */ + pic16_aopOp(IC_LEFT(ic),ic,FALSE); + size = AOP_SIZE(IC_LEFT(ic)); + + while (size--) { + char *l ; + if (AOP_TYPE(IC_LEFT(ic)) == AOP_DPTR) { + /* #NOCHANGE */ + l = pic16_aopGet(AOP(IC_LEFT(ic)),offset++, + FALSE,TRUE); + pic16_emitcode("push","%s",l); + pushed++; + } else { + l = pic16_aopGet(AOP(IC_LEFT(ic)),offset, + FALSE,FALSE); + if (strcmp(fReturn[offset],l)) { + if( ( (AOP(IC_LEFT(ic))->type) == AOP_IMMD) || + ((AOP(IC_LEFT(ic))->type) == AOP_LIT) ) { + pic16_emitpcode(POC_MOVLW, pic16_popGet(AOP(IC_LEFT(ic)),offset)); + }else { + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(IC_LEFT(ic)),offset)); + } + if(size) { + pic16_emitpcode(POC_MOVWF,popRegFromIdx(offset + pic16_Gstack_base_addr)); + } + offset++; + } + } + } + + if (pushed) { + while(pushed) { + pushed--; + if (strcmp(fReturn[pushed],"a")) + pic16_emitcode("pop",fReturn[pushed]); + else + pic16_emitcode("pop","acc"); + } + } + 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_",returnLabel->key+100 + labelOffset); + } + +} + +/*-----------------------------------------------------------------*/ +/* genLabel - generates a label */ +/*-----------------------------------------------------------------*/ +static void genLabel (iCode *ic) +{ + /* special case never generate */ + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + if (IC_LABEL(ic) == entryLabel) + return ; + + pic16_emitpLabel(IC_LABEL(ic)->key); + pic16_emitcode("","_%05d_DS_:",(IC_LABEL(ic)->key+100 + labelOffset)); +} + +/*-----------------------------------------------------------------*/ +/* genGoto - generates a goto */ +/*-----------------------------------------------------------------*/ +//tsd +static void genGoto (iCode *ic) +{ + pic16_emitpcode(POC_GOTO,pic16_popGetLabel(IC_LABEL(ic)->key)); + pic16_emitcode ("goto","_%05d_DS_",(IC_LABEL(ic)->key+100)+labelOffset); +} + + +/*-----------------------------------------------------------------*/ +/* genMultbits :- multiplication of bits */ +/*-----------------------------------------------------------------*/ +static void genMultbits (operand *left, + operand *right, + operand *result) +{ + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + 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) +{ + sym_link *opetype = operandType(result); + + // symbol *lbl ; + int size,offset; + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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 = AOP_SIZE(result); + if(size == 1) { + + if (AOP_TYPE(right) == AOP_LIT){ + pic16_emitcode("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)); + pic16_emitcode("call","genMultLit"); + } else { + pic16_emitcode("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_emitcode("call","pic16_genMult8X8_8"); + + } + pic16_genMult8X8_8 (left, right,result); + + + /* signed or unsigned */ + //pic16_emitcode("mov","b,%s", pic16_aopGet(AOP(right),0,FALSE,FALSE)); + //l = pic16_aopGet(AOP(left),0,FALSE,FALSE); + //MOVA(l); + //pic16_emitcode("mul","ab"); + /* if result size = 1, mul signed = mul unsigned */ + //pic16_aopPut(AOP(result),"a",0); + + } else { // (size > 1) + + pic16_emitcode("multiply (size>1) ","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)); + + if (SPEC_USIGN(opetype)){ + pic16_emitcode("multiply ","unsigned result. size = %d",AOP_SIZE(result)); + pic16_genUMult8X8_16 (left, right, result, NULL); + + if (size > 2) { + /* for filling the MSBs */ + pic16_emitpcode(POC_CLRF, pic16_popGet(AOP(result),2)); + pic16_emitpcode(POC_CLRF, pic16_popGet(AOP(result),3)); + } + } + else{ + pic16_emitcode("multiply ","signed result. size = %d",AOP_SIZE(result)); + + pic16_emitcode("mov","a,b"); + + /* adjust the MSB if left or right neg */ + + /* if one literal */ + if (AOP_TYPE(right) == AOP_LIT){ + pic16_emitcode("multiply ","right is a lit"); + /* AND literal negative */ + if((int) floatFromVal (AOP(right)->aopu.aop_lit) < 0){ + /* adjust MSB (c==0 after mul) */ + pic16_emitcode("subb","a,%s", pic16_aopGet(AOP(left),0,FALSE,FALSE)); + } + } + else{ + pic16_genSMult8X8_16 (left, right, result, NULL); + } + + if(size > 2){ + pic16_emitcode("multiply ","size is greater than 2, so propogate sign"); + /* get the sign */ + pic16_emitcode("rlc","a"); + pic16_emitcode("subb","a,acc"); + } + } + + size -= 2; + offset = 2; + if (size > 0) + while (size--) + pic16_emitcode("multiply ","size is way greater than 2, so propogate sign"); + //pic16_aopPut(AOP(result),"a",offset++); + } +} + +/*-----------------------------------------------------------------*/ +/* genMult - generates code for multiplication */ +/*-----------------------------------------------------------------*/ +static void genMult (iCode *ic) +{ + operand *left = IC_LEFT(ic); + operand *right = IC_RIGHT(ic); + operand *result= IC_RESULT(ic); + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* 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 ; + } + + pic16_emitcode("multiply ","sizes are greater than 2... need to insert proper algor."); + + /* 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); +} + +/*-----------------------------------------------------------------*/ +/* genDivbits :- division of bits */ +/*-----------------------------------------------------------------*/ +static void genDivbits (operand *left, + operand *right, + operand *result) +{ + + char *l; + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__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("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; + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + size = AOP_SIZE(result) - 1; + offset = 1; + /* 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),"a",0); + while (size--) + pic16_aopPut(AOP(result),zero,offset++); + 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_",(lbl->key+100)); + pic16_emitcode("cpl","a"); + pic16_emitcode("inc","a"); + pic16_emitcode("","%05d_DS_:",(lbl->key+100)); + 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_",(lbl->key+100)); + pic16_emitcode("cpl","a"); + pic16_emitcode("inc","a"); + pic16_emitcode("","%05d_DS_:",(lbl->key+100)); + + /* 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_",(lbl->key+100)); + pic16_emitcode("jnb","acc.7,%05d_DS_",(lbl->key+100)); + CLRC; + pic16_emitcode("clr","a"); + pic16_emitcode("subb","a,b"); + pic16_emitcode("mov","b,a"); + pic16_emitcode("","%05d_DS_:",(lbl->key+100)); + + /* 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++); + +} + +/*-----------------------------------------------------------------*/ +/* 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); + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* 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) { + genDivbits(left,right,result); + goto release ; + } + + /* if both are of size == 1 */ + if (AOP_SIZE(left) == 1 && + AOP_SIZE(right) == 1 ) { + genDivOneByte(left,right,result); + goto release ; + } + + /* should have been converted to function call */ + assert(0); +release : + pic16_freeAsmop(left,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE)); + pic16_freeAsmop(right,NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE)); + pic16_freeAsmop(result,NULL,ic,TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genModbits :- modulus of bits */ +/*-----------------------------------------------------------------*/ +static void genModbits (operand *left, + operand *right, + operand *result) +{ + + char *l; + + /* the result must be bit */ + 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 ; + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__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_",(lbl->key+100)); + pic16_emitcode("cpl","a"); + pic16_emitcode("inc","a"); + pic16_emitcode("","%05d_DS_:",(lbl->key+100)); + 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_",(lbl->key+100)); + pic16_emitcode("cpl","a"); + pic16_emitcode("inc","a"); + pic16_emitcode("","%05d_DS_:",(lbl->key+100)); + + /* 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_",(lbl->key+100)); + pic16_emitcode("jnb","acc.7,%05d_DS_",(lbl->key+100)); + CLRC ; + pic16_emitcode("clr","a"); + pic16_emitcode("subb","a,b"); + pic16_emitcode("mov","b,a"); + pic16_emitcode("","%05d_DS_:",(lbl->key+100)); + + /* now we are done */ + pic16_aopPut(AOP(result),"b",0); + +} + +/*-----------------------------------------------------------------*/ +/* genMod - generates code for division */ +/*-----------------------------------------------------------------*/ +static void genMod (iCode *ic) +{ + operand *left = IC_LEFT(ic); + operand *right = IC_RIGHT(ic); + operand *result= IC_RESULT(ic); + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* 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); +} + +/*-----------------------------------------------------------------*/ +/* 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) +{ + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* if true label then we jump if condition + supplied is true */ + if ( IC_TRUE(ic) ) { + + if(strcmp(jval,"a") == 0) + emitSKPZ; + else if (strcmp(jval,"c") == 0) + emitSKPC; + else { + DEBUGpic16_emitcode ("; ***","%d - assuming %s is in bit space",__LINE__,jval); + pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit(jval,-1,1)); + } + + pic16_emitpcode(POC_GOTO,pic16_popGetLabel(IC_TRUE(ic)->key)); + pic16_emitcode(" goto","_%05d_DS_",IC_TRUE(ic)->key+100 + labelOffset); + + } + else { + /* false label is present */ + if(strcmp(jval,"a") == 0) + emitSKPNZ; + else if (strcmp(jval,"c") == 0) + emitSKPNC; + else { + DEBUGpic16_emitcode ("; ***","%d - assuming %s is in bit space",__LINE__,jval); + pic16_emitpcode(POC_BTFSS, pic16_newpCodeOpBit(jval,-1,1)); + } + + pic16_emitpcode(POC_GOTO,pic16_popGetLabel(IC_FALSE(ic)->key)); + pic16_emitcode(" goto","_%05d_DS_",IC_FALSE(ic)->key+100 + labelOffset); + + } + + + /* mark the icode as generated */ + ic->generated = 1; +} + +/*-----------------------------------------------------------------*/ +/* genSkip */ +/*-----------------------------------------------------------------*/ +static void genSkip(iCode *ifx,int status_bit) +{ + if(!ifx) + return; + + if ( IC_TRUE(ifx) ) { + switch(status_bit) { + case 'z': + 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_",IC_TRUE(ifx)->key+100+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_",IC_FALSE(ifx)->key+100+labelOffset); + + } + +} + +/*-----------------------------------------------------------------*/ +/* genSkipc */ +/*-----------------------------------------------------------------*/ +static void genSkipc(resolvedIfx *rifx) +{ + if(!rifx) + return; + + if(rifx->condition) + emitSKPC; + else + emitSKPNC; + + pic16_emitpcode(POC_GOTO,pic16_popGetLabel(rifx->lbl->key)); + rifx->generated = 1; +} + +/*-----------------------------------------------------------------*/ +/* genSkipz2 */ +/*-----------------------------------------------------------------*/ +static void genSkipz2(resolvedIfx *rifx, int invert_condition) +{ + if(!rifx) + return; + + if( (rifx->condition ^ invert_condition) & 1) + emitSKPZ; + else + emitSKPNZ; + + pic16_emitpcode(POC_GOTO,pic16_popGetLabel(rifx->lbl->key)); + rifx->generated = 1; +} + +/*-----------------------------------------------------------------*/ +/* genSkipz */ +/*-----------------------------------------------------------------*/ +static void genSkipz(iCode *ifx, int condition) +{ + if(!ifx) + return; + + if(condition) + emitSKPNZ; + else + emitSKPZ; + + if ( IC_TRUE(ifx) ) + pic16_emitpcode(POC_GOTO,pic16_popGetLabel(IC_TRUE(ifx)->key)); + else + pic16_emitpcode(POC_GOTO,pic16_popGetLabel(IC_FALSE(ifx)->key)); + + if ( IC_TRUE(ifx) ) + pic16_emitcode("goto","_%05d_DS_",IC_TRUE(ifx)->key+100+labelOffset); + else + pic16_emitcode("goto","_%05d_DS_",IC_FALSE(ifx)->key+100+labelOffset); + +} +/*-----------------------------------------------------------------*/ +/* genSkipCond */ +/*-----------------------------------------------------------------*/ +static void genSkipCond(resolvedIfx *rifx,operand *op, int offset, int bit) +{ + if(!rifx) + return; + + if(rifx->condition) + pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit(pic16_aopGet(AOP(op),offset,FALSE,FALSE),bit,0)); + else + pic16_emitpcode(POC_BTFSS, pic16_newpCodeOpBit(pic16_aopGet(AOP(op),offset,FALSE,FALSE),bit,0)); + + + pic16_emitpcode(POC_GOTO,pic16_popGetLabel(rifx->lbl->key)); + rifx->generated = 1; +} + +#if 0 +/*-----------------------------------------------------------------*/ +/* genChkZeroes :- greater or less than comparison */ +/* For each byte in a literal that is zero, inclusive or the */ +/* the corresponding byte in the operand with W */ +/* returns true if any of the bytes are zero */ +/*-----------------------------------------------------------------*/ +static int genChkZeroes(operand *op, int lit, int size) +{ + + int i; + int flag =1; + + while(size--) { + i = (lit >> (size*8)) & 0xff; + + if(i==0) { + if(flag) + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(op),size)); + else + pic16_emitpcode(POC_IORFW, pic16_popGet(AOP(op),size)); + flag = 0; + } + } + + return (flag==0); +} +#endif + +/*-----------------------------------------------------------------*/ +/* genCmp :- greater or less than comparison */ +/*-----------------------------------------------------------------*/ +static void genCmp (operand *left,operand *right, + operand *result, iCode *ifx, int sign) +{ + int size; //, offset = 0 ; + unsigned long lit = 0L,i = 0; + resolvedIfx rFalseIfx; + // resolvedIfx rTrueIfx; + symbol *truelbl; + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); +/* + if(ifx) { + DEBUGpic16_emitcode ("; ***","true ifx is %s",((IC_TRUE(ifx) == NULL) ? "false" : "true")); + DEBUGpic16_emitcode ("; ***","false ifx is %s",((IC_FALSE(ifx) == NULL) ? "false" : "true")); + } +*/ + + resolveIfx(&rFalseIfx,ifx); + truelbl = newiTempLabel(NULL); + size = max(AOP_SIZE(left),AOP_SIZE(right)); + + DEBUGpic16_pic16_AopType(__LINE__,left,right,result); + +#define _swapp + + /* if literal is on the right then swap with left */ + if ((AOP_TYPE(right) == AOP_LIT)) { + operand *tmp = right ; + unsigned long mask = (0x100 << (8*(size-1))) - 1; + lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit); +#ifdef _swapp + + lit = (lit - 1) & mask; + right = left; + left = tmp; + rFalseIfx.condition ^= 1; +#endif + + } else if ((AOP_TYPE(left) == AOP_LIT)) { + lit = (unsigned long)floatFromVal(AOP(left)->aopu.aop_lit); + } + + + //if(IC_TRUE(ifx) == NULL) + /* if left & right are bit variables */ + if (AOP_TYPE(left) == AOP_CRY && + AOP_TYPE(right) == AOP_CRY ) { + pic16_emitcode("mov","c,%s",AOP(right)->aopu.aop_dir); + pic16_emitcode("anl","c,/%s",AOP(left)->aopu.aop_dir); + } else { + /* subtract right from left if at the + end the carry flag is set then we know that + left is greater than right */ + + // { + + symbol *lbl = newiTempLabel(NULL); + +#ifndef _swapp + if(AOP_TYPE(right) == AOP_LIT) { + + //lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit); + + DEBUGpic16_emitcode(";right lit","lit = 0x%x,sign=%d",lit,sign); + + /* special cases */ + + if(lit == 0) { + + if(sign != 0) + genSkipCond(&rFalseIfx,left,size-1,7); + else + /* no need to compare to 0...*/ + /* NOTE: this is a de-generate compare that most certainly + * creates some dead code. */ + pic16_emitpcode(POC_GOTO,pic16_popGetLabel(rFalseIfx.lbl->key)); + + if(ifx) ifx->generated = 1; + return; + + } + size--; + + if(size == 0) { + //i = (lit >> (size*8)) & 0xff; + DEBUGpic16_emitcode(";right lit","line = %d",__LINE__); + + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(left),size)); + + i = ((0-lit) & 0xff); + if(sign) { + if( i == 0x81) { + /* lit is 0x7f, all signed chars are less than + * this except for 0x7f itself */ + pic16_emitpcode(POC_XORLW, pic16_popGetLit(0x7f)); + genSkipz2(&rFalseIfx,0); + } else { + pic16_emitpcode(POC_ADDLW, pic16_popGetLit(0x80)); + pic16_emitpcode(POC_ADDLW, pic16_popGetLit(i^0x80)); + genSkipc(&rFalseIfx); + } + + } else { + if(lit == 1) { + genSkipz2(&rFalseIfx,1); + } else { + pic16_emitpcode(POC_ADDLW, pic16_popGetLit(i)); + genSkipc(&rFalseIfx); + } + } + + if(ifx) ifx->generated = 1; + return; + } + + /* chars are out of the way. now do ints and longs */ + + + DEBUGpic16_emitcode(";right lit","line = %d",__LINE__); + + /* special cases */ + + if(sign) { + + if(lit == 0) { + genSkipCond(&rFalseIfx,left,size,7); + if(ifx) ifx->generated = 1; + return; + } + + if(lit <0x100) { + DEBUGpic16_emitcode(";right lit","line = %d signed compare to 0x%x",__LINE__,lit); + + //rFalseIfx.condition ^= 1; + //genSkipCond(&rFalseIfx,left,size,7); + //rFalseIfx.condition ^= 1; + + pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit(pic16_aopGet(AOP(left),size,FALSE,FALSE),7,0)); + if(rFalseIfx.condition) + pic16_emitpcode(POC_GOTO, pic16_popGetLabel(rFalseIfx.lbl->key)); + else + pic16_emitpcode(POC_GOTO, pic16_popGetLabel(truelbl->key)); + + pic16_emitpcode(POC_MOVLW, pic16_popGetLit(0x100-lit)); + pic16_emitpcode(POC_ADDFW, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(left),1)); + + while(size > 1) + pic16_emitpcode(POC_IORFW, pic16_popGet(AOP(left),size--)); + + if(rFalseIfx.condition) { + emitSKPZ; + pic16_emitpcode(POC_GOTO, pic16_popGetLabel(truelbl->key)); + + } else { + emitSKPNZ; + } + + genSkipc(&rFalseIfx); + pic16_emitpLabel(truelbl->key); + if(ifx) ifx->generated = 1; + return; + + } + + if(size == 1) { + + if( (lit & 0xff) == 0) { + /* lower byte is zero */ + DEBUGpic16_emitcode(";right lit","line = %d signed compare to 0x%x",__LINE__,lit); + i = ((lit >> 8) & 0xff) ^0x80; + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(left),size)); + pic16_emitpcode(POC_ADDLW, pic16_popGetLit( 0x80)); + pic16_emitpcode(POC_ADDLW, pic16_popGetLit(0x100-i)); + genSkipc(&rFalseIfx); + + + if(ifx) ifx->generated = 1; + return; + + } + } else { + /* Special cases for signed longs */ + if( (lit & 0xffffff) == 0) { + /* lower byte is zero */ + DEBUGpic16_emitcode(";right lit","line = %d signed compare to 0x%x",__LINE__,lit); + i = ((lit >> 8*3) & 0xff) ^0x80; + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(left),size)); + pic16_emitpcode(POC_ADDLW, pic16_popGetLit( 0x80)); + pic16_emitpcode(POC_ADDLW, pic16_popGetLit(0x100-i)); + genSkipc(&rFalseIfx); + + + if(ifx) ifx->generated = 1; + return; + + } + + } + + + if(lit & (0x80 << (size*8))) { + /* lit is negative */ + DEBUGpic16_emitcode(";right lit","line = %d signed compare to 0x%x",__LINE__,lit); + + //genSkipCond(&rFalseIfx,left,size,7); + + pic16_emitpcode(POC_BTFSS, pic16_newpCodeOpBit(pic16_aopGet(AOP(left),size,FALSE,FALSE),7,0)); + + if(rFalseIfx.condition) + pic16_emitpcode(POC_GOTO, pic16_popGetLabel(truelbl->key)); + else + pic16_emitpcode(POC_GOTO, pic16_popGetLabel(rFalseIfx.lbl->key)); + + + } else { + /* lit is positive */ + DEBUGpic16_emitcode(";right lit","line = %d signed compare to 0x%x",__LINE__,lit); + pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit(pic16_aopGet(AOP(left),size,FALSE,FALSE),7,0)); + if(rFalseIfx.condition) + pic16_emitpcode(POC_GOTO, pic16_popGetLabel(rFalseIfx.lbl->key)); + else + pic16_emitpcode(POC_GOTO, pic16_popGetLabel(truelbl->key)); + + } + + /* + This works, but is only good for ints. + It also requires a "known zero" register. + pic16_emitpcode(POC_MOVLW, pic16_popGetLit(mlit & 0xff)); + pic16_emitpcode(POC_ADDFW, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_RLCFW, pic16_popCopyReg(&pic16_pc_kzero)); + pic16_emitpcode(POC_ADDLW, pic16_popGetLit( ((mlit>>8) & 0xff))); + pic16_emitpcode(POC_ADDFW, pic16_popGet(AOP(left),1)); + genSkipc(&rFalseIfx); + + pic16_emitpLabel(truelbl->key); + if(ifx) ifx->generated = 1; + return; + **/ + + /* There are no more special cases, so perform a general compare */ + + pic16_emitpcode(POC_MOVLW, pic16_popGetLit((lit >> (size*8)) & 0xff)); + pic16_emitpcode(POC_SUBFW, pic16_popGet(AOP(left),size)); + + while(size--) { + + pic16_emitpcode(POC_MOVLW, pic16_popGetLit((lit >> (size*8)) & 0xff)); + emitSKPNZ; + pic16_emitpcode(POC_SUBFW, pic16_popGet(AOP(left),size)); + } + //rFalseIfx.condition ^= 1; + genSkipc(&rFalseIfx); + + pic16_emitpLabel(truelbl->key); + + if(ifx) ifx->generated = 1; + return; + + + } + + + /* sign is out of the way. So now do an unsigned compare */ + DEBUGpic16_emitcode(";right lit","line = %d unsigned compare to 0x%x",__LINE__,lit); + + + /* General case - compare to an unsigned literal on the right.*/ + + i = (lit >> (size*8)) & 0xff; + pic16_emitpcode(POC_MOVLW, pic16_popGetLit(i)); + pic16_emitpcode(POC_SUBFW, pic16_popGet(AOP(left),size)); + while(size--) { + i = (lit >> (size*8)) & 0xff; + + if(i) { + pic16_emitpcode(POC_MOVLW, pic16_popGetLit(i)); + emitSKPNZ; + pic16_emitpcode(POC_SUBFW, pic16_popGet(AOP(left),size)); + } else { + /* this byte of the lit is zero, + *if it's not the last then OR in the variable */ + if(size) + pic16_emitpcode(POC_IORFW, pic16_popGet(AOP(left),size)); + } + } + + + pic16_emitpLabel(lbl->key); + //if(emitFinalCheck) + genSkipc(&rFalseIfx); + if(sign) + pic16_emitpLabel(truelbl->key); + + if(ifx) ifx->generated = 1; + return; + + + } +#endif // _swapp + + if(AOP_TYPE(left) == AOP_LIT) { + //symbol *lbl = newiTempLabel(NULL); + + //EXPERIMENTAL lit = (unsigned long)(floatFromVal(AOP(left)->aopu.aop_lit)); + + + DEBUGpic16_emitcode(";left lit","lit = 0x%x,sign=%d",lit,sign); + + /* Special cases */ + if((lit == 0) && (sign == 0)){ + + size--; + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(right),size)); + while(size) + pic16_emitpcode(POC_IORFW, pic16_popGet(AOP(right),--size)); + + genSkipz2(&rFalseIfx,0); + if(ifx) ifx->generated = 1; + return; + } + + if(size==1) { + /* Special cases */ + lit &= 0xff; + if(((lit == 0xff) && !sign) || ((lit==0x7f) && sign)) { + /* degenerate compare can never be true */ + if(rFalseIfx.condition == 0) + pic16_emitpcode(POC_GOTO,pic16_popGetLabel(rFalseIfx.lbl->key)); + + if(ifx) ifx->generated = 1; + return; + } + + if(sign) { + /* signed comparisons to a literal byte */ + + int lp1 = (lit+1) & 0xff; + + DEBUGpic16_emitcode(";left lit","line = %d lit = 0x%x",__LINE__,lit); + switch (lp1) { + case 0: + rFalseIfx.condition ^= 1; + genSkipCond(&rFalseIfx,right,0,7); + break; + case 0x7f: + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(right),0)); + pic16_emitpcode(POC_XORLW, pic16_popGetLit(0x7f)); + genSkipz2(&rFalseIfx,1); + break; + default: + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(right),0)); + pic16_emitpcode(POC_ADDLW, pic16_popGetLit(0x80)); + pic16_emitpcode(POC_ADDLW, pic16_popGetLit(((-(lit+1)) & 0xff) ^ 0x80)); + rFalseIfx.condition ^= 1; + genSkipc(&rFalseIfx); + break; + } + } else { + /* unsigned comparisons to a literal byte */ + + switch(lit & 0xff ) { + case 0: + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(right),0)); + genSkipz2(&rFalseIfx,0); + break; + case 0x7f: + rFalseIfx.condition ^= 1; + genSkipCond(&rFalseIfx,right,0,7); + break; + + default: + pic16_emitpcode(POC_MOVLW, pic16_popGetLit((lit+1) & 0xff)); + pic16_emitpcode(POC_SUBFW, pic16_popGet(AOP(right),0)); + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + rFalseIfx.condition ^= 1; + if (AOP_TYPE(result) == AOP_CRY) + genSkipc(&rFalseIfx); + else { + pic16_emitpcode(POC_CLRF, pic16_popGet(AOP(result),0)); + pic16_emitpcode(POC_RLCF, pic16_popGet(AOP(result),0)); + } + break; + } + } + + if(ifx) ifx->generated = 1; + //goto check_carry; + return; + + } else { + + /* Size is greater than 1 */ + + if(sign) { + int lp1 = lit+1; + + size--; + + if(lp1 == 0) { + /* this means lit = 0xffffffff, or -1 */ + + + DEBUGpic16_emitcode(";left lit = -1","line = %d ",__LINE__); + rFalseIfx.condition ^= 1; + genSkipCond(&rFalseIfx,right,size,7); + if(ifx) ifx->generated = 1; + return; + } + + if(lit == 0) { + int s = size; + + if(rFalseIfx.condition) { + pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit(pic16_aopGet(AOP(right),size,FALSE,FALSE),7,0)); + pic16_emitpcode(POC_GOTO, pic16_popGetLabel(truelbl->key)); + } + + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(right),size)); + while(size--) + pic16_emitpcode(POC_IORFW, pic16_popGet(AOP(right),size)); + + + emitSKPZ; + if(rFalseIfx.condition) { + pic16_emitpcode(POC_GOTO, pic16_popGetLabel(rFalseIfx.lbl->key)); + pic16_emitpLabel(truelbl->key); + }else { + rFalseIfx.condition ^= 1; + genSkipCond(&rFalseIfx,right,s,7); + } + + if(ifx) ifx->generated = 1; + return; + } + + if((size == 1) && (0 == (lp1&0xff))) { + /* lower byte of signed word is zero */ + DEBUGpic16_emitcode(";left lit","line = %d 0x%x+1 low byte is zero",__LINE__,lit); + i = ((lp1 >> 8) & 0xff) ^0x80; + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(right),size)); + pic16_emitpcode(POC_ADDLW, pic16_popGetLit( 0x80)); + pic16_emitpcode(POC_ADDLW, pic16_popGetLit(0x100-i)); + rFalseIfx.condition ^= 1; + genSkipc(&rFalseIfx); + + + if(ifx) ifx->generated = 1; + return; + } + + if(lit & (0x80 << (size*8))) { + /* Lit is less than zero */ + DEBUGpic16_emitcode(";left lit","line = %d 0x%x is less than 0",__LINE__,lit); + //rFalseIfx.condition ^= 1; + //genSkipCond(&rFalseIfx,left,size,7); + //rFalseIfx.condition ^= 1; + pic16_emitpcode(POC_BTFSS, pic16_newpCodeOpBit(pic16_aopGet(AOP(right),size,FALSE,FALSE),7,0)); + //pic16_emitpcode(POC_GOTO, pic16_popGetLabel(truelbl->key)); + + if(rFalseIfx.condition) + pic16_emitpcode(POC_GOTO, pic16_popGetLabel(rFalseIfx.lbl->key)); + else + pic16_emitpcode(POC_GOTO, pic16_popGetLabel(truelbl->key)); + + + } else { + /* Lit is greater than or equal to zero */ + DEBUGpic16_emitcode(";left lit","line = %d 0x%x is greater than 0",__LINE__,lit); + //rFalseIfx.condition ^= 1; + //genSkipCond(&rFalseIfx,right,size,7); + //rFalseIfx.condition ^= 1; + + //pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit(pic16_aopGet(AOP(right),size,FALSE,FALSE),7,0)); + //pic16_emitpcode(POC_GOTO, pic16_popGetLabel(rFalseIfx.lbl->key)); + + pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit(pic16_aopGet(AOP(right),size,FALSE,FALSE),7,0)); + if(rFalseIfx.condition) + pic16_emitpcode(POC_GOTO, pic16_popGetLabel(truelbl->key)); + else + pic16_emitpcode(POC_GOTO, pic16_popGetLabel(rFalseIfx.lbl->key)); + + } + + + pic16_emitpcode(POC_MOVLW, pic16_popGetLit((lp1 >> (size*8)) & 0xff)); + pic16_emitpcode(POC_SUBFW, pic16_popGet(AOP(right),size)); + + while(size--) { + + pic16_emitpcode(POC_MOVLW, pic16_popGetLit((lp1 >> (size*8)) & 0xff)); + emitSKPNZ; + pic16_emitpcode(POC_SUBFW, pic16_popGet(AOP(right),size)); + } + rFalseIfx.condition ^= 1; + //rFalseIfx.condition = 1; + genSkipc(&rFalseIfx); + + pic16_emitpLabel(truelbl->key); + + if(ifx) ifx->generated = 1; + return; + // end of if (sign) + } else { + + /* compare word or long to an unsigned literal on the right.*/ + + + size--; + if(lit < 0xff) { + DEBUGpic16_emitcode ("; ***","%s %d lit =0x%x < 0xff",__FUNCTION__,__LINE__,lit); + switch (lit) { + case 0: + break; /* handled above */ +/* + case 0xff: + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(right),size)); + while(size--) + pic16_emitpcode(POC_IORFW, pic16_popGet(AOP(right),size)); + genSkipz2(&rFalseIfx,0); + break; +*/ + default: + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(right),size)); + while(--size) + pic16_emitpcode(POC_IORFW, pic16_popGet(AOP(right),size)); + + emitSKPZ; + if(rFalseIfx.condition) + pic16_emitpcode(POC_GOTO, pic16_popGetLabel(rFalseIfx.lbl->key)); + else + pic16_emitpcode(POC_GOTO, pic16_popGetLabel(truelbl->key)); + + + pic16_emitpcode(POC_MOVLW, pic16_popGetLit(lit+1)); + pic16_emitpcode(POC_SUBFW, pic16_popGet(AOP(right),0)); + + rFalseIfx.condition ^= 1; + genSkipc(&rFalseIfx); + } + + pic16_emitpLabel(truelbl->key); + + if(ifx) ifx->generated = 1; + return; + } + + + lit++; + DEBUGpic16_emitcode ("; ***","%s %d lit =0x%x",__FUNCTION__,__LINE__,lit); + i = (lit >> (size*8)) & 0xff; + + pic16_emitpcode(POC_MOVLW, pic16_popGetLit(i)); + pic16_emitpcode(POC_SUBFW, pic16_popGet(AOP(right),size)); + + while(size--) { + i = (lit >> (size*8)) & 0xff; + + if(i) { + pic16_emitpcode(POC_MOVLW, pic16_popGetLit(i)); + emitSKPNZ; + pic16_emitpcode(POC_SUBFW, pic16_popGet(AOP(right),size)); + } else { + /* this byte of the lit is zero, + *if it's not the last then OR in the variable */ + if(size) + pic16_emitpcode(POC_IORFW, pic16_popGet(AOP(right),size)); + } + } + + + pic16_emitpLabel(lbl->key); + + rFalseIfx.condition ^= 1; + genSkipc(&rFalseIfx); + } + + if(sign) + pic16_emitpLabel(truelbl->key); + if(ifx) ifx->generated = 1; + return; + } + } + /* Compare two variables */ + + DEBUGpic16_emitcode(";sign","%d",sign); + + size--; + if(sign) { + /* Sigh. thus sucks... */ + if(size) { + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(left),size)); + pic16_emitpcode(POC_MOVWF, popRegFromIdx(pic16_Gstack_base_addr)); + pic16_emitpcode(POC_MOVLW, pic16_popGetLit(0x80)); + pic16_emitpcode(POC_XORWF, popRegFromIdx(pic16_Gstack_base_addr)); + pic16_emitpcode(POC_XORFW, pic16_popGet(AOP(right),size)); + pic16_emitpcode(POC_SUBFW, popRegFromIdx(pic16_Gstack_base_addr)); + } else { + /* Signed char comparison */ + /* Special thanks to Nikolai Golovchenko for this snippet */ + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(right),0)); + pic16_emitpcode(POC_SUBFW, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_RRCFW, pic16_popGet(AOP(left),0)); /* could be any register */ + pic16_emitpcode(POC_XORFW, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_XORFW, pic16_popGet(AOP(right),0)); + pic16_emitpcode(POC_ADDLW, pic16_popGetLit(0x80)); + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + genSkipc(&rFalseIfx); + + if(ifx) ifx->generated = 1; + return; + } + + } else { + + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(right),size)); + pic16_emitpcode(POC_SUBFW, pic16_popGet(AOP(left),size)); + } + + + /* The rest of the bytes of a multi-byte compare */ + while (size) { + + emitSKPZ; + pic16_emitpcode(POC_GOTO, pic16_popGetLabel(lbl->key)); + size--; + + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(right),size)); + pic16_emitpcode(POC_SUBFW, pic16_popGet(AOP(left),size)); + + + } + + pic16_emitpLabel(lbl->key); + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + if ((AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) || + (AOP_TYPE(result) == AOP_REG)) { + pic16_emitpcode(POC_CLRF, pic16_popGet(AOP(result),0)); + pic16_emitpcode(POC_RLCF, pic16_popGet(AOP(result),0)); + } else { + genSkipc(&rFalseIfx); + } + //genSkipc(&rFalseIfx); + if(ifx) ifx->generated = 1; + + return; + + } + + // check_carry: + if (AOP_TYPE(result) == AOP_CRY && AOP_SIZE(result)) { + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + pic16_outBitC(result); + } else { + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* if the result is used in the next + ifx conditional branch then generate + code a little differently */ + if (ifx ) + genIfxJump (ifx,"c"); + else + pic16_outBitC(result); + /* leave the result in acc */ + } + +} + +/*-----------------------------------------------------------------*/ +/* genCmpGt :- greater than comparison */ +/*-----------------------------------------------------------------*/ +static void genCmpGt (iCode *ic, iCode *ifx) +{ + operand *left, *right, *result; + sym_link *letype , *retype; + int sign ; + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + left = IC_LEFT(ic); + right= IC_RIGHT(ic); + result = IC_RESULT(ic); + + letype = getSpec(operandType(left)); + retype =getSpec(operandType(right)); + sign = !(SPEC_USIGN(letype) | SPEC_USIGN(retype)); + /* assign the amsops */ + 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 ; + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + left = IC_LEFT(ic); + right= IC_RIGHT(ic); + result = IC_RESULT(ic); + + letype = getSpec(operandType(left)); + retype =getSpec(operandType(right)); + sign = !(SPEC_USIGN(letype) | SPEC_USIGN(retype)); + + /* assign the amsops */ + 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); +} + +/*-----------------------------------------------------------------*/ +/* genc16bit2lit - compare a 16 bit value to a literal */ +/*-----------------------------------------------------------------*/ +static void genc16bit2lit(operand *op, int lit, int offset) +{ + int i; + + DEBUGpic16_emitcode ("; ***","%s %d, lit = %d",__FUNCTION__,__LINE__,lit); + if( (lit&0xff) == 0) + i=1; + else + i=0; + + switch( BYTEofLONG(lit,i)) { + case 0: + pic16_emitpcode(POC_MOVFW,pic16_popGet(AOP(op),offset+i)); + break; + case 1: + pic16_emitpcode(POC_DECFW,pic16_popGet(AOP(op),offset+i)); + break; + case 0xff: + pic16_emitpcode(POC_INCFW,pic16_popGet(AOP(op),offset+i)); + break; + default: + pic16_emitpcode(POC_MOVFW,pic16_popGet(AOP(op),offset+i)); + pic16_emitpcode(POC_XORLW,pic16_popGetLit(BYTEofLONG(lit,i))); + } + + i ^= 1; + + switch( BYTEofLONG(lit,i)) { + case 0: + pic16_emitpcode(POC_IORFW,pic16_popGet(AOP(op),offset+i)); + break; + case 1: + emitSKPNZ; + pic16_emitpcode(POC_DECFW,pic16_popGet(AOP(op),offset+i)); + break; + case 0xff: + emitSKPNZ; + pic16_emitpcode(POC_INCFW,pic16_popGet(AOP(op),offset+i)); + break; + default: + pic16_emitpcode(POC_MOVLW,pic16_popGetLit(BYTEofLONG(lit,i))); + emitSKPNZ; + pic16_emitpcode(POC_XORFW,pic16_popGet(AOP(op),offset+i)); + + } + +} + +/*-----------------------------------------------------------------*/ +/* gencjneshort - compare and jump if not equal */ +/*-----------------------------------------------------------------*/ +static void gencjne(operand *left, operand *right, operand *result, iCode *ifx) +{ + int size = max(AOP_SIZE(left),AOP_SIZE(right)); + int offset = 0; + int res_offset = 0; /* the result may be a different size then left or right */ + int res_size = AOP_SIZE(result); + resolvedIfx rIfx; + symbol *lbl; + + unsigned long lit = 0L; + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + DEBUGpic16_pic16_AopType(__LINE__,left,right,result); + if(result) + DEBUGpic16_emitcode ("; ***","%s %d result is not null",__FUNCTION__,__LINE__); + resolveIfx(&rIfx,ifx); + lbl = newiTempLabel(NULL); + + + /* if the left side is a literal or + if the right is in a pointer register and left + is not */ + if ((AOP_TYPE(left) == AOP_LIT) || + (IS_AOP_PREG(right) && !IS_AOP_PREG(left))) { + operand *t = right; + right = left; + left = t; + } + if(AOP_TYPE(right) == AOP_LIT) + lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit); + + /* if the right side is a literal then anything goes */ + if (AOP_TYPE(right) == AOP_LIT && + AOP_TYPE(left) != AOP_DIR ) { + switch(size) { + case 2: + genc16bit2lit(left, lit, 0); + emitSKPNZ; + pic16_emitpcode(POC_GOTO,pic16_popGetLabel(lbl->key)); + break; + default: + while (size--) { + if(lit & 0xff) { + pic16_emitpcode(POC_MOVFW,pic16_popGet(AOP(left),offset)); + pic16_emitpcode(POC_XORLW,pic16_popGetLit(lit & 0xff)); + } else { + pic16_emitpcode(POC_MOVF,pic16_popGet(AOP(left),offset)); + } + + emitSKPNZ; + pic16_emitpcode(POC_GOTO,pic16_popGetLabel(lbl->key)); + offset++; + if(res_offset < res_size-1) + res_offset++; + lit >>= 8; + } + break; + } + } + + /* if the right side is in a register or in direct space or + if the left is a pointer register & right is not */ + else if (AOP_TYPE(right) == AOP_REG || + AOP_TYPE(right) == AOP_DIR || + (AOP_TYPE(left) == AOP_DIR && AOP_TYPE(right) == AOP_LIT) || + (IS_AOP_PREG(left) && !IS_AOP_PREG(right))) { + //int lbl_key = (rIfx.condition) ? rIfx.lbl->key : lbl->key; + int lbl_key = lbl->key; + + if(result) { + pic16_emitpcode(POC_CLRF,pic16_popGet(AOP(result),res_offset)); + //pic16_emitpcode(POC_INCF,pic16_popGet(AOP(result),res_offset)); + }else { + DEBUGpic16_emitcode ("; ***","%s %d -- ERROR",__FUNCTION__,__LINE__); + fprintf(stderr, "%s %d error - expecting result to be non_null\n", + __FUNCTION__,__LINE__); + return; + } + +/* switch(size) { */ +/* case 2: */ +/* genc16bit2lit(left, lit, 0); */ +/* emitSKPNZ; */ +/* pic16_emitpcode(POC_GOTO,pic16_popGetLabel(lbl->key)); */ +/* break; */ +/* default: */ + while (size--) { + int emit_skip=1; + if((AOP_TYPE(left) == AOP_DIR) && + ((AOP_TYPE(right) == AOP_REG) || (AOP_TYPE(right) == AOP_DIR))) { + + pic16_emitpcode(POC_MOVFW,pic16_popGet(AOP(left),offset)); + pic16_emitpcode(POC_XORFW,pic16_popGet(AOP(right),offset)); + + } else if((AOP_TYPE(left) == AOP_DIR) && (AOP_TYPE(right) == AOP_LIT)){ + + switch (lit & 0xff) { + case 0: + pic16_emitpcode(POC_MOVFW,pic16_popGet(AOP(left),offset)); + break; + case 1: + pic16_emitpcode(POC_DECFSZW,pic16_popGet(AOP(left),offset)); + pic16_emitpcode(POC_INCF,pic16_popGet(AOP(result),res_offset)); + //pic16_emitpcode(POC_GOTO,pic16_popGetLabel(lbl->key)); + emit_skip=0; + break; + case 0xff: + pic16_emitpcode(POC_INCFSZW,pic16_popGet(AOP(left),offset)); + //pic16_emitpcode(POC_INCF,pic16_popGet(AOP(result),res_offset)); + //pic16_emitpcode(POC_INCFSZW,pic16_popGet(AOP(left),offset)); + pic16_emitpcode(POC_GOTO,pic16_popGetLabel(lbl_key)); + emit_skip=0; + break; + default: + pic16_emitpcode(POC_MOVFW,pic16_popGet(AOP(left),offset)); + pic16_emitpcode(POC_XORLW,pic16_popGetLit(lit & 0xff)); + } + lit >>= 8; + + } else { + pic16_emitpcode(POC_MOVF,pic16_popGet(AOP(left),offset)); + } + if(emit_skip) { + if(AOP_TYPE(result) == AOP_CRY) { + pic16_emitcode(";***","%s %d",__FUNCTION__,__LINE__); + if(rIfx.condition) + emitSKPNZ; + else + emitSKPZ; + pic16_emitpcode(POC_GOTO,pic16_popGetLabel(rIfx.lbl->key)); + } else { + /* fix me. probably need to check result size too */ + //pic16_emitpcode(POC_CLRF,pic16_popGet(AOP(result),0)); + if(rIfx.condition) + emitSKPZ; + else + emitSKPNZ; + pic16_emitpcode(POC_GOTO,pic16_popGetLabel(lbl_key)); + //pic16_emitpcode(POC_INCF,pic16_popGet(AOP(result),res_offset)); + } + if(ifx) + ifx->generated=1; + } + emit_skip++; + offset++; + if(res_offset < res_size-1) + res_offset++; + } +/* break; */ +/* } */ + } else if(AOP_TYPE(right) == AOP_REG && + AOP_TYPE(left) != AOP_DIR){ + + while(size--) { + pic16_emitpcode(POC_MOVFW,pic16_popGet(AOP(left),offset)); + pic16_emitpcode(POC_XORFW,pic16_popGet(AOP(right),offset)); + pic16_emitcode(";***","%s %d",__FUNCTION__,__LINE__); + if(rIfx.condition) + emitSKPNZ; + else + emitSKPZ; + pic16_emitpcode(POC_GOTO,pic16_popGetLabel(rIfx.lbl->key)); + offset++; + if(res_offset < res_size-1) + res_offset++; + } + + }else{ + /* right is a pointer reg need both a & b */ + while(size--) { + char *l = pic16_aopGet(AOP(left),offset,FALSE,FALSE); + if(strcmp(l,"b")) + pic16_emitcode("mov","b,%s",l); + MOVA(pic16_aopGet(AOP(right),offset,FALSE,FALSE)); + pic16_emitcode("cjne","a,b,%05d_DS_",lbl->key+100); + offset++; + } + } + + pic16_emitpcode(POC_INCF,pic16_popGet(AOP(result),res_offset)); + if(!rIfx.condition) + pic16_emitpcode(POC_GOTO,pic16_popGetLabel(rIfx.lbl->key)); + + pic16_emitpLabel(lbl->key); + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + if(ifx) + ifx->generated = 1; +} + +#if 0 +/*-----------------------------------------------------------------*/ +/* gencjne - compare and jump if not equal */ +/*-----------------------------------------------------------------*/ +static void gencjne(operand *left, operand *right, iCode *ifx) +{ + symbol *tlbl = newiTempLabel(NULL); + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + gencjneshort(left, right, lbl); + + pic16_emitcode("mov","a,%s",one); + pic16_emitcode("sjmp","%05d_DS_",tlbl->key+100); + pic16_emitcode("","%05d_DS_:",lbl->key+100); + pic16_emitcode("clr","a"); + pic16_emitcode("","%05d_DS_:",tlbl->key+100); + + pic16_emitpLabel(lbl->key); + pic16_emitpLabel(tlbl->key); + +} +#endif + +/*-----------------------------------------------------------------*/ +/* 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; + + 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) || + (IS_AOP_PREG(right) && !IS_AOP_PREG(left))) { + operand *tmp = right ; + right = left; + left = tmp; + } + + + if(ifx && !AOP_SIZE(result)){ + symbol *tlbl; + /* if they are both bit variables */ + if (AOP_TYPE(left) == AOP_CRY && + ((AOP_TYPE(right) == AOP_CRY) || (AOP_TYPE(right) == AOP_LIT))) { + if(AOP_TYPE(right) == AOP_LIT){ + unsigned long lit = (unsigned long)floatFromVal(AOP(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,(lbl->key+100)); + pic16_emitcode("cpl","c"); + pic16_emitcode("","%05d_DS_:",(lbl->key+100)); + } + /* if true label then we jump if condition + supplied is true */ + tlbl = newiTempLabel(NULL); + if ( IC_TRUE(ifx) ) { + pic16_emitcode("jnc","%05d_DS_",tlbl->key+100); + pic16_emitcode("ljmp","%05d_DS_",IC_TRUE(ifx)->key+100); + } else { + pic16_emitcode("jc","%05d_DS_",tlbl->key+100); + pic16_emitcode("ljmp","%05d_DS_",IC_FALSE(ifx)->key+100); + } + pic16_emitcode("","%05d_DS_:",tlbl->key+100+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 { + + /* They're not both bit variables. Is the right a literal? */ + if(AOP_TYPE(right) == AOP_LIT) { + lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit); + + 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'); + } + + + /* 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)); + + } else { + + /* search for patterns that can be optimized */ + + genc16bit2lit(left,lit,0); + lit >>= 16; + if(lit) { + genSkipz(ifx,IC_TRUE(ifx) == NULL); + //genSkip(ifx,'z'); + genc16bit2lit(left,lit,2); + } else { + pic16_emitpcode(POC_IORFW,pic16_popGet(AOP(left),2)); + pic16_emitpcode(POC_IORFW,pic16_popGet(AOP(left),3)); + + } + + } + + genSkip(ifx,'z'); + } + + 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_",IC_TRUE(ifx)->key+100+labelOffset); + } else { + emitSKPZ; + pic16_emitpcode(POC_GOTO,pic16_popGetLabel(IC_FALSE(ifx)->key)); + pic16_emitcode(" goto","_%05d_DS_",IC_FALSE(ifx)->key+100+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; + pic16_emitpcode(POC_GOTO,pic16_popGetLabel(tlbl->key)); + pic16_emitcode(" goto","_%05d_DS_",tlbl->key+100+labelOffset); + } else { + emitSKPNZ; + pic16_emitpcode(POC_GOTO,pic16_popGetLabel(IC_TRUE(ifx)->key)); + pic16_emitcode(" goto","_%05d_DS_",IC_TRUE(ifx)->key+100+labelOffset); + } + } else { + emitSKPZ; + pic16_emitpcode(POC_GOTO,pic16_popGetLabel(IC_FALSE(ifx)->key)); + pic16_emitcode(" goto","_%05d_DS_",IC_FALSE(ifx)->key+100+labelOffset); + } + offset++; + } + if(s>1 && IC_TRUE(ifx)) { + pic16_emitpLabel(tlbl->key); + pic16_emitcode("","_%05d_DS_:",tlbl->key+100+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))) { + if(AOP_TYPE(right) == AOP_LIT){ + unsigned long lit = (unsigned long)floatFromVal(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,(lbl->key+100)); + pic16_emitcode("cpl","c"); + pic16_emitcode("","%05d_DS_:",(lbl->key+100)); + } + /* 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",__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); +} + +/*-----------------------------------------------------------------*/ +/* ifxForOp - returns the icode containing the ifx for operand */ +/*-----------------------------------------------------------------*/ +static iCode *ifxForOp ( operand *op, iCode *ic ) +{ + /* if true symbol then needs to be assigned */ + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + if (IS_TRUE_SYMOP(op)) + return NULL ; + + /* if this has register type condition and + the next instruction is ifx with the same operand + and live to of the operand is upto the ifx only then */ + if (ic->next && + ic->next->op == IFX && + IC_COND(ic->next)->key == op->key && + OP_SYMBOL(op)->liveTo <= ic->next->seq ) + return ic->next; + + if (ic->next && + ic->next->op == IFX && + IC_COND(ic->next)->key == op->key) { + DEBUGpic16_emitcode ("; WARNING ","%d IGNORING liveTo range in %s",__LINE__,__FUNCTION__); + return ic->next; + } + + DEBUGpic16_emitcode ("; NULL :(","%d",__LINE__); + if (ic->next && + ic->next->op == IFX) + DEBUGpic16_emitcode ("; ic-next"," is an IFX"); + + if (ic->next && + ic->next->op == IFX && + IC_COND(ic->next)->key == op->key) { + DEBUGpic16_emitcode ("; "," key is okay"); + DEBUGpic16_emitcode ("; "," key liveTo %d, next->seq = %d", + OP_SYMBOL(op)->liveTo, + ic->next->seq); + } + + + return NULL; +} +/*-----------------------------------------------------------------*/ +/* genAndOp - for && operation */ +/*-----------------------------------------------------------------*/ +static void genAndOp (iCode *ic) +{ + operand *left,*right, *result; +/* symbol *tlbl; */ + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* note here that && operations that are in an + if statement are taken away by backPatchLabels + only those used in arthmetic operations remain */ + pic16_aopOp((left=IC_LEFT(ic)),ic,FALSE); + pic16_aopOp((right=IC_RIGHT(ic)),ic,FALSE); + pic16_aopOp((result=IC_RESULT(ic)),ic,FALSE); + + 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_",tlbl->key+100); */ +/* pic16_toBoolean(right); */ +/* pic16_emitcode("","%05d_DS_:",tlbl->key+100); */ +/* 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; + + /* note here that || operations that are in an + if statement are taken away by backPatchLabels + only those used in arthmetic operations remain */ + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + pic16_aopOp((left=IC_LEFT(ic)),ic,FALSE); + pic16_aopOp((right=IC_RIGHT(ic)),ic,FALSE); + pic16_aopOp((result=IC_RESULT(ic)),ic,FALSE); + + 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_",tlbl->key+100+labelOffset); + pic16_toBoolean(right); + pic16_emitcode("","%05d_DS_:",tlbl->key+100+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) +{ + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + if(IC_TRUE(ic)) + pic16_emitcode("ljmp","%05d_DS_",IC_TRUE(ic)->key+100); + ic->generated = 1; +} + +/*-----------------------------------------------------------------*/ +/* jmpIfTrue - */ +/*-----------------------------------------------------------------*/ +static void jumpIfTrue (iCode *ic) +{ + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + if(!IC_TRUE(ic)) + pic16_emitcode("ljmp","%05d_DS_",IC_FALSE(ic)->key+100); + ic->generated = 1; +} + +/*-----------------------------------------------------------------*/ +/* jmpTrueOrFalse - */ +/*-----------------------------------------------------------------*/ +static void jmpTrueOrFalse (iCode *ic, symbol *tlbl) +{ + // ugly but optimized by peephole + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + if(IC_TRUE(ic)){ + symbol *nlbl = newiTempLabel(NULL); + pic16_emitcode("sjmp","%05d_DS_",nlbl->key+100); + pic16_emitcode("","%05d_DS_:",tlbl->key+100); + pic16_emitcode("ljmp","%05d_DS_",IC_TRUE(ic)->key+100); + pic16_emitcode("","%05d_DS_:",nlbl->key+100); + } + else{ + pic16_emitcode("ljmp","%05d_DS_",IC_FALSE(ic)->key+100); + pic16_emitcode("","%05d_DS_:",tlbl->key+100); + } + ic->generated = 1; +} + +/*-----------------------------------------------------------------*/ +/* genAnd - code for and */ +/*-----------------------------------------------------------------*/ +static void genAnd (iCode *ic, iCode *ifx) +{ + operand *left, *right, *result; + int size, offset=0; + unsigned long lit = 0L; + int bytelit = 0; + resolvedIfx rIfx; + + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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 = (unsigned long)floatFromVal (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)){ + int posbit = isLiteralBit(lit); + /* left & 2^n */ + if(posbit){ + posbit--; + //MOVA(pic16_aopGet(AOP(left),posbit>>3,FALSE,FALSE)); + // bit = left & 2^n + if(size) + pic16_emitcode("mov","c,acc.%d",posbit&0x07); + // if(left & 2^n) + else{ + if(ifx){ +/* + if(IC_TRUE(ifx)) { + pic16_emitpcode(POC_BTFSC,pic16_newpCodeOpBit(pic16_aopGet(AOP(left),0,FALSE,FALSE),posbit,0)); + pic16_emitpcode(POC_GOTO,pic16_popGetLabel(IC_TRUE(ic)->key)); + } else { + pic16_emitpcode(POC_BTFSS,pic16_newpCodeOpBit(pic16_aopGet(AOP(left),0,FALSE,FALSE),posbit,0)); + pic16_emitpcode(POC_GOTO,pic16_popGetLabel(IC_FALSE(ic)->key)); + } +*/ + pic16_emitpcode(((rIfx.condition) ? POC_BTFSC : POC_BTFSS), + pic16_newpCodeOpBit(pic16_aopGet(AOP(left),0,FALSE,FALSE),posbit,0)); + pic16_emitpcode(POC_GOTO,pic16_popGetLabel(rIfx.lbl->key)); + + ifx->generated = 1; + } + goto release; + } + } else { + symbol *tlbl = newiTempLabel(NULL); + int sizel = AOP_SIZE(left); + if(size) + pic16_emitcode("setb","c"); + while(sizel--){ + if((bytelit = ((lit >> (offset*8)) & 0x0FFL)) != 0x0L){ + MOVA( pic16_aopGet(AOP(left),offset,FALSE,FALSE)); + // byte == 2^n ? + if((posbit = isLiteralBit(bytelit)) != 0) + pic16_emitcode("jb","acc.%d,%05d_DS_",(posbit-1)&0x07,tlbl->key+100); + else{ + if(bytelit != 0x0FFL) + pic16_emitcode("anl","a,%s", + pic16_aopGet(AOP(right),offset,FALSE,TRUE)); + pic16_emitcode("jnz","%05d_DS_",tlbl->key+100); + } + } + offset++; + } + // bit = left & literal + if(size){ + pic16_emitcode("clr","c"); + pic16_emitcode("","%05d_DS_:",tlbl->key+100); + } + // if(left & literal) + else{ + if(ifx) + jmpTrueOrFalse(ifx, tlbl); + 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 = my_powof2( (~lit) & 0xff ); + if(p>=0) { + /* only one bit is set 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)); + + } else { + pic16_emitcode("movlw","0x%x", (lit & 0xff)); + pic16_emitcode("andwf","%s,f",pic16_aopGet(AOP(left),offset,FALSE,TRUE)); + if(know_W != (lit&0xff)) + pic16_emitpcode(POC_MOVLW, pic16_popGetLit(lit & 0xff)); + know_W = lit &0xff; + 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_",tlbl->key+100); + offset++; + } + if(size){ + CLRC; + pic16_emitcode("","%05d_DS_:",tlbl->key+100); + 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: + pic16_emitcode("movlw","0x%x",t); + pic16_emitcode("andwf","%s,w", + pic16_aopGet(AOP(left),offset,FALSE,FALSE)); + pic16_emitcode("movwf","%s", + pic16_aopGet(AOP(result),offset,FALSE,FALSE)); + + pic16_emitpcode(POC_MOVLW, pic16_popGetLit(t)); + pic16_emitpcode(POC_ANDFW,pic16_popGet(AOP(left),offset)); + pic16_emitpcode(POC_MOVWF,pic16_popGet(AOP(result),offset)); + } + 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; + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + 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 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 = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit); + + size = AOP_SIZE(result); + + // if(bit | yy) + // xx = bit | yy; + if (AOP_TYPE(left) == AOP_CRY){ + if(AOP_TYPE(right) == AOP_LIT){ + // c = bit & literal; + if(lit){ + // lit != 0 => result = 1 + if(AOP_TYPE(result) == AOP_CRY){ + if(size) + 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)); + + pic16_emitcode("bcf","(%s >> 3), (%s & 7)", + AOP(result)->aopu.aop_dir, + AOP(result)->aopu.aop_dir); + pic16_emitcode("btfsc","(%s >> 3), (%s & 7)", + AOP(right)->aopu.aop_dir, + AOP(right)->aopu.aop_dir); + pic16_emitcode("bsf","(%s >> 3), (%s & 7)", + AOP(result)->aopu.aop_dir, + AOP(result)->aopu.aop_dir); + } 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)); + + pic16_emitcode("bcf","(%s >> 3), (%s & 7)", + AOP(result)->aopu.aop_dir, + AOP(result)->aopu.aop_dir); + pic16_emitcode("btfss","(%s >> 3), (%s & 7)", + AOP(right)->aopu.aop_dir, + AOP(right)->aopu.aop_dir); + pic16_emitcode("btfsc","(%s >> 3), (%s & 7)", + AOP(left)->aopu.aop_dir, + AOP(left)->aopu.aop_dir); + pic16_emitcode("bsf","(%s >> 3), (%s & 7)", + AOP(result)->aopu.aop_dir, + AOP(result)->aopu.aop_dir); + } + } + } 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,tlbl->key+100); + pic16_toBoolean(right); + pic16_emitcode(";XXX jnz","%05d_DS_",tlbl->key+100); + if((AOP_TYPE(result) == AOP_CRY) && ifx){ + jmpTrueOrFalse(ifx, tlbl); + goto release; + } else { + CLRC; + pic16_emitcode("","%05d_DS_:",tlbl->key+100); + } + } + } + // 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(lit){ + pic16_emitcode(";XXX "," %s,%d",__FILE__,__LINE__); + // result = 1 + if(size) + pic16_emitcode(";XXX setb","%s",AOP(result)->aopu.aop_dir); + else + continueIfTrue(ifx); + goto release; + } else { + pic16_emitcode(";XXX "," %s,%d",__FILE__,__LINE__); + // lit = 0, result = boolean(left) + if(size) + pic16_emitcode(";XXX setb","c"); + pic16_toBoolean(right); + if(size){ + symbol *tlbl = newiTempLabel(NULL); + pic16_emitcode(";XXX jnz","%05d_DS_",tlbl->key+100); + CLRC; + pic16_emitcode("","%05d_DS_:",tlbl->key+100); + } else { + genIfxJump (ifx,"a"); + 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){ + if((lit & 0xff) == 0) + /* or'ing with 0 has no effect */ + continue; + else { + int p = my_powof2(lit & 0xff); + if(p>=0) { + /* only one bit is set in the literal, so use a bsf instruction */ + pic16_emitpcode(POC_BSF, + pic16_newpCodeOpBit(pic16_aopGet(AOP(left),offset,FALSE,FALSE),p,0)); + } 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)); + pic16_emitcode("iorwf","%s,w",pic16_aopGet(AOP(right),offset,FALSE,FALSE)); + } else { + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(right),offset)); + pic16_emitpcode(POC_IORWF, pic16_popGet(AOP(left),offset)); + + pic16_emitcode("movf","%s,w",pic16_aopGet(AOP(right),offset,FALSE,FALSE)); + pic16_emitcode("iorwf","%s,f",pic16_aopGet(AOP(left),offset,FALSE,FALSE)); + + } + } + } + } else { + // left & result in different registers + if(AOP_TYPE(result) == AOP_CRY){ + // result = bit + // if(size), result in bit + // if(!size && ifx), conditional oper: if(left | right) + symbol *tlbl = newiTempLabel(NULL); + int sizer = max(AOP_SIZE(left),AOP_SIZE(right)); + 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_",tlbl->key+100); + offset++; + } + if(size){ + CLRC; + pic16_emitcode("","%05d_DS_:",tlbl->key+100); + 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)); + + pic16_emitcode("movf","%s,w", + pic16_aopGet(AOP(left),offset,FALSE,FALSE)); + pic16_emitcode("movwf","%s", + pic16_aopGet(AOP(result),offset,FALSE,FALSE)); + break; + default: + pic16_emitpcode(POC_MOVLW, pic16_popGetLit(t)); + pic16_emitpcode(POC_IORFW, pic16_popGet(AOP(left),offset)); + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),offset)); + + pic16_emitcode("movlw","0x%x",t); + pic16_emitcode("iorwf","%s,w", + pic16_aopGet(AOP(left),offset,FALSE,FALSE)); + pic16_emitcode("movwf","%s", + pic16_aopGet(AOP(result),offset,FALSE,FALSE)); + + } + 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)); + pic16_emitcode("iorwf","%s,w",pic16_aopGet(AOP(right),offset,FALSE,FALSE)); + } else { + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(right),offset)); + pic16_emitpcode(POC_IORFW, pic16_popGet(AOP(left),offset)); + + pic16_emitcode("movf","%s,w",pic16_aopGet(AOP(right),offset,FALSE,FALSE)); + pic16_emitcode("iorwf","%s,w", + pic16_aopGet(AOP(left),offset,FALSE,FALSE)); + } + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),offset)); + pic16_emitcode("movwf","%s",pic16_aopGet(AOP(result),offset,FALSE,FALSE)); + } + } + +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; + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + pic16_aopOp((left = IC_LEFT(ic)),ic,FALSE); + pic16_aopOp((right= IC_RIGHT(ic)),ic,FALSE); + pic16_aopOp((result=IC_RESULT(ic)),ic,TRUE); + + /* if left is a literal & right is not || + if left needs acc & right does not */ + if ((AOP_TYPE(left) == AOP_LIT && AOP_TYPE(right) != AOP_LIT) || + (AOP_NEEDSACC(left) && !AOP_NEEDSACC(right))) { + operand *tmp = right ; + right = left; + left = tmp; + } + + /* if result = right then exchange them */ + if(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 = (unsigned long)floatFromVal (AOP(right)->aopu.aop_lit); + + size = AOP_SIZE(result); + + // if(bit ^ yy) + // xx = bit ^ yy; + if (AOP_TYPE(left) == AOP_CRY){ + if(AOP_TYPE(right) == AOP_LIT){ + // c = bit & literal; + if(lit>>1){ + // lit>>1 != 0 => result = 1 + if(AOP_TYPE(result) == AOP_CRY){ + if(size) + {pic16_emitpcode(POC_BSF, pic16_popGet(AOP(result),offset)); + pic16_emitcode("setb","%s",AOP(result)->aopu.aop_dir);} + 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_",tlbl->key+100); + sizer--; + } + // val = (0,1) + pic16_emitcode("rrc","a"); + } + pic16_emitcode("jnb","%s,%05d_DS_",AOP(left)->aopu.aop_dir,(tlbl->key+100)); + pic16_emitcode("cpl","c"); + pic16_emitcode("","%05d_DS_:",(tlbl->key+100)); + } + // 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(pic16_sameRegs(AOP(result),AOP(left))){ + /* if left is same as result */ + for(;size--; offset++) { + if(AOP_TYPE(right) == AOP_LIT){ + int t = (lit >> (offset*8)) & 0x0FFL; + if(t == 0x00L) + continue; + else + if (IS_AOP_PREG(left)) { + MOVA(pic16_aopGet(AOP(right),offset,FALSE,FALSE)); + pic16_emitcode("xrl","a,%s",pic16_aopGet(AOP(left),offset,FALSE,TRUE)); + pic16_aopPut(AOP(result),"a",offset); + } else { + pic16_emitpcode(POC_MOVLW, pic16_popGetLit(t)); + pic16_emitpcode(POC_XORWF,pic16_popGet(AOP(left),offset)); + pic16_emitcode("xrl","%s,%s", + pic16_aopGet(AOP(left),offset,FALSE,TRUE), + pic16_aopGet(AOP(right),offset,FALSE,FALSE)); + } + } 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)); +/* + if (IS_AOP_PREG(left)) { + pic16_emitcode("xrl","a,%s",pic16_aopGet(AOP(left),offset,FALSE,TRUE)); + pic16_aopPut(AOP(result),"a",offset); + } else + pic16_emitcode("xrl","%s,a", + pic16_aopGet(AOP(left),offset,FALSE,TRUE)); +*/ + } + } + } + } else { + // left & result in different registers + if(AOP_TYPE(result) == AOP_CRY){ + // result = bit + // if(size), result in bit + // if(!size && ifx), conditional oper: if(left ^ right) + symbol *tlbl = newiTempLabel(NULL); + int sizer = max(AOP_SIZE(left),AOP_SIZE(right)); + if(size) + 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_",tlbl->key+100); + offset++; + } + if(size){ + CLRC; + pic16_emitcode("","%05d_DS_:",tlbl->key+100); + 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)); + pic16_emitcode("movf","%s,w", + pic16_aopGet(AOP(left),offset,FALSE,FALSE)); + pic16_emitcode("movwf","%s", + pic16_aopGet(AOP(result),offset,FALSE,FALSE)); + break; + case 0xff: + pic16_emitpcode(POC_COMFW,pic16_popGet(AOP(left),offset)); + pic16_emitpcode(POC_MOVWF,pic16_popGet(AOP(result),offset)); + pic16_emitcode("comf","%s,w", + pic16_aopGet(AOP(left),offset,FALSE,FALSE)); + pic16_emitcode("movwf","%s", + pic16_aopGet(AOP(result),offset,FALSE,FALSE)); + break; + default: + pic16_emitpcode(POC_MOVLW, pic16_popGetLit(t)); + pic16_emitpcode(POC_XORFW,pic16_popGet(AOP(left),offset)); + pic16_emitpcode(POC_MOVWF,pic16_popGet(AOP(result),offset)); + pic16_emitcode("movlw","0x%x",t); + pic16_emitcode("xorwf","%s,w", + pic16_aopGet(AOP(left),offset,FALSE,FALSE)); + pic16_emitcode("movwf","%s", + pic16_aopGet(AOP(result),offset,FALSE,FALSE)); + + } + 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)); + pic16_emitcode("xorwf","%s,w",pic16_aopGet(AOP(right),offset,FALSE,FALSE)); + } else { + pic16_emitpcode(POC_MOVFW,pic16_popGet(AOP(right),offset)); + pic16_emitpcode(POC_XORFW,pic16_popGet(AOP(left),offset)); + pic16_emitcode("movf","%s,w",pic16_aopGet(AOP(right),offset,FALSE,FALSE)); + pic16_emitcode("xorwf","%s,w",pic16_aopGet(AOP(left),offset,FALSE,FALSE)); + } + if ( AOP_TYPE(result) != AOP_ACC){ + pic16_emitpcode(POC_MOVWF,pic16_popGet(AOP(result),offset)); + pic16_emitcode("movwf","%s",pic16_aopGet(AOP(result),offset,FALSE,FALSE)); + } + } + } + + 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 genInline (iCode *ic) +{ + char *buffer, *bp, *bp1; + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + _G.inLine += (!options.asmpeep); + + buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1); + strcpy(buffer,IC_INLINE(ic)); + + /* emit each line as a code */ + while (*bp) { + if (*bp == '\n') { + *bp++ = '\0'; + + if(*bp1) + pic16_addpCode2pBlock(pb,pic16_AssembleLine(bp1)); + bp1 = bp; + } else { + if (*bp == ':') { + bp++; + *bp = '\0'; + bp++; + pic16_emitcode(bp1,""); + bp1 = bp; + } else + bp++; + } + } + if ((bp1 != bp) && *bp1) + pic16_addpCode2pBlock(pb,pic16_AssembleLine(bp1)); + + Safe_free(buffer); + + _G.inLine -= (!options.asmpeep); +} + +/*-----------------------------------------------------------------*/ +/* genRRC - rotate right with carry */ +/*-----------------------------------------------------------------*/ +static void genRRC (iCode *ic) +{ + operand *left , *result ; + int size, offset = 0, same; + + /* rotate right with carry */ + left = IC_LEFT(ic); + result=IC_RESULT(ic); + pic16_aopOp (left,ic,FALSE); + pic16_aopOp (result,ic,FALSE); + + DEBUGpic16_pic16_AopType(__LINE__,left,NULL,result); + + same = pic16_sameRegs(AOP(result),AOP(left)); + + size = AOP_SIZE(result); + + /* get the lsb and put it into the carry */ + pic16_emitpcode(POC_RRCFW, pic16_popGet(AOP(left),size-1)); + + offset = 0 ; + + while(size--) { + + if(same) { + pic16_emitpcode(POC_RRCF, pic16_popGet(AOP(left),offset)); + } else { + pic16_emitpcode(POC_RRCFW, 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); +} + +/*-----------------------------------------------------------------*/ +/* 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,FALSE); + + 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); +} + +/*-----------------------------------------------------------------*/ +/* 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); +} + +/*-----------------------------------------------------------------*/ +/* 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; + } +} + +/*-----------------------------------------------------------------*/ +/* AccLsh - left shift accumulator by known count */ +/*-----------------------------------------------------------------*/ +static void AccLsh (int shCount) +{ + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + if(shCount != 0){ + if(shCount == 1) + pic16_emitcode("add","a,acc"); + else + if(shCount == 2) { + pic16_emitcode("add","a,acc"); + pic16_emitcode("add","a,acc"); + } else { + /* rotate left accumulator */ + AccRol(shCount); + /* and kill the lower order bits */ + pic16_emitcode("anl","a,#0x%02x", SLMask[shCount]); + } + } +} + +/*-----------------------------------------------------------------*/ +/* AccRsh - right shift accumulator by known count */ +/*-----------------------------------------------------------------*/ +static void AccRsh (int shCount) +{ + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + if(shCount != 0){ + if(shCount == 1){ + CLRC; + pic16_emitcode("rrc","a"); + } else { + /* rotate right accumulator */ + AccRol(8 - shCount); + /* and kill the higher order bits */ + pic16_emitcode("anl","a,#0x%02x", SRMask[shCount]); + } + } +} + +#if 0 +/*-----------------------------------------------------------------*/ +/* AccSRsh - signed right shift accumulator by known count */ +/*-----------------------------------------------------------------*/ +static void AccSRsh (int shCount) +{ + symbol *tlbl ; + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + if(shCount != 0){ + if(shCount == 1){ + pic16_emitcode("mov","c,acc.7"); + pic16_emitcode("rrc","a"); + } else if(shCount == 2){ + pic16_emitcode("mov","c,acc.7"); + pic16_emitcode("rrc","a"); + pic16_emitcode("mov","c,acc.7"); + pic16_emitcode("rrc","a"); + } else { + tlbl = newiTempLabel(NULL); + /* rotate right accumulator */ + AccRol(8 - shCount); + /* and kill the higher order bits */ + pic16_emitcode("anl","a,#0x%02x", SRMask[shCount]); + pic16_emitcode("jnb","acc.%d,%05d_DS_",7-shCount,tlbl->key+100); + pic16_emitcode("orl","a,#0x%02x", + (unsigned char)~SRMask[shCount]); + pic16_emitcode("","%05d_DS_:",tlbl->key+100); + } + } +} +#endif +/*-----------------------------------------------------------------*/ +/* 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__); + + same = ((left == result) || (AOP(left) == AOP(result))) && (offl == offr); + + switch(shCount) { + 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_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)); + } + pic16_emitpcode(POC_RLCFW, pic16_popGet(AOP(result),offr)); + pic16_emitpcode(POC_RRCF, pic16_popGet(AOP(result),offr)); + + break; + + case 3: + if(same) + pic16_emitpcode(POC_SWAPF, pic16_popGet(AOP(result),offr)); + else { + pic16_emitpcode(POC_SWAPFW, pic16_popGet(AOP(left),offl)); + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),offr)); + } + + pic16_emitpcode(POC_RLCFW, pic16_popGet(AOP(result),offr)); + pic16_emitpcode(POC_RLCFW, pic16_popGet(AOP(result),offr)); + pic16_emitpcode(POC_ANDLW, pic16_popGetLit(0x1f)); + + pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit(pic16_aopGet(AOP(result),offr,FALSE,FALSE),3,0)); + pic16_emitpcode(POC_IORLW, pic16_popGetLit(0xe0)); + + 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_BTFSC, pic16_newpCodeOpBit(pic16_aopGet(AOP(left),offl,FALSE,FALSE),7,0)); + pic16_emitpcode(POC_IORLW, pic16_popGetLit(0xf0)); + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),offr)); + break; + case 5: + if(same) { + pic16_emitpcode(POC_SWAPF, pic16_popGet(AOP(result),offr)); + } else { + pic16_emitpcode(POC_SWAPFW, pic16_popGet(AOP(left),offl)); + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),offr)); + } + pic16_emitpcode(POC_RRCFW, pic16_popGet(AOP(result),offr)); + pic16_emitpcode(POC_ANDLW, pic16_popGetLit(0x07)); + pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit(pic16_aopGet(AOP(result),offr,FALSE,FALSE),3,0)); + pic16_emitpcode(POC_IORLW, pic16_popGetLit(0xf8)); + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),offr)); + break; + + case 6: + if(same) { + pic16_emitpcode(POC_MOVLW, pic16_popGetLit(0x00)); + pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit(pic16_aopGet(AOP(left),offl,FALSE,FALSE),7,0)); + pic16_emitpcode(POC_MOVLW, pic16_popGetLit(0xfe)); + pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit(pic16_aopGet(AOP(left),offl,FALSE,FALSE),6,0)); + pic16_emitpcode(POC_IORLW, pic16_popGetLit(0x01)); + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),offr)); + } else { + pic16_emitpcode(POC_CLRF, pic16_popGet(AOP(result),offr)); + pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit(pic16_aopGet(AOP(left),offl,FALSE,FALSE),7,0)); + pic16_emitpcode(POC_DECF, pic16_popGet(AOP(result),offr)); + pic16_emitpcode(POC_BTFSS, pic16_newpCodeOpBit(pic16_aopGet(AOP(left),offl,FALSE,FALSE),6,0)); + pic16_emitpcode(POC_BCF, pic16_newpCodeOpBit(pic16_aopGet(AOP(result),offr,FALSE,FALSE),0,0)); + } + break; + + case 7: + if(same) { + pic16_emitpcode(POC_MOVLW, pic16_popGetLit(0x00)); + pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit(pic16_aopGet(AOP(left),LSB,FALSE,FALSE),7,0)); + pic16_emitpcode(POC_MOVLW, pic16_popGetLit(0xff)); + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),offr)); + } else { + pic16_emitpcode(POC_CLRF, pic16_popGet(AOP(result),offr)); + pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit(pic16_aopGet(AOP(left),offl,FALSE,FALSE),7,0)); + pic16_emitpcode(POC_DECF, pic16_popGet(AOP(result),offr)); + } + + default: + 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__); + + 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; + } + + + + switch(shCount) { + case 1: + emitCLRC; + 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: + emitCLRC; + 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)); + } + emitCLRC; + pic16_emitpcode(POC_RRCF, pic16_popGet(AOP(result),offr)); + + break; + case 3: + if(same) + pic16_emitpcode(POC_SWAPF, pic16_popGet(AOP(result),offr)); + else { + pic16_emitpcode(POC_SWAPFW, pic16_popGet(AOP(left),offl)); + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),offr)); + } + + pic16_emitpcode(POC_RLCFW, pic16_popGet(AOP(result),offr)); + pic16_emitpcode(POC_RLCFW, pic16_popGet(AOP(result),offr)); + 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_ANDLW, pic16_popGetLit(0x0f)); + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),offr)); + emitCLRC; + pic16_emitpcode(POC_RRCF, pic16_popGet(AOP(result),offr)); + + break; + case 6: + + pic16_emitpcode(POC_RLCFW, pic16_popGet(AOP(left),offl)); + pic16_emitpcode(POC_ANDLW, pic16_popGetLit(0x80)); + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),offr)); + pic16_emitpcode(POC_RLCF, pic16_popGet(AOP(result),offr)); + pic16_emitpcode(POC_RLCF, pic16_popGet(AOP(result),offr)); + break; + + case 7: + + pic16_emitpcode(POC_RLCFW, pic16_popGet(AOP(left),offl)); + pic16_emitpcode(POC_CLRF, pic16_popGet(AOP(result),offr)); + pic16_emitpcode(POC_RLCF, pic16_popGet(AOP(result),offr)); + + break; + + default: + 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; + + // char *l; + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + same = ((left == result) || (AOP(left) == AOP(result))) && (offl==offr); + DEBUGpic16_emitcode ("; ***","same = %d",same); + // l = pic16_aopGet(AOP(left),offl,FALSE,FALSE); + // MOVA(l); + /* shift left accumulator */ + //AccLsh(shCount); // don't comment out just yet... + // pic16_aopPut(AOP(result),"a",offr); + + switch(shCount) { + case 1: + /* Shift left 1 bit position */ + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(left),offl)); + if(same) { + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(left),offl)); + } else { + pic16_emitpcode(POC_ADDFW, pic16_popGet(AOP(left),offl)); + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),offr)); + } + break; + case 2: + pic16_emitpcode(POC_RLCFW, pic16_popGet(AOP(left),offl)); + pic16_emitpcode(POC_ANDLW,pic16_popGetLit(0x7e)); + pic16_emitpcode(POC_MOVWF,pic16_popGet(AOP(result),offr)); + pic16_emitpcode(POC_ADDWF,pic16_popGet(AOP(result),offr)); + break; + case 3: + pic16_emitpcode(POC_RLCFW, pic16_popGet(AOP(left),offl)); + pic16_emitpcode(POC_ANDLW,pic16_popGetLit(0x3e)); + pic16_emitpcode(POC_MOVWF,pic16_popGet(AOP(result),offr)); + pic16_emitpcode(POC_ADDWF,pic16_popGet(AOP(result),offr)); + pic16_emitpcode(POC_RLCF, 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_ANDLW, pic16_popGetLit(0xf0)); + pic16_emitpcode(POC_MOVWF,pic16_popGet(AOP(result),offr)); + pic16_emitpcode(POC_ADDWF,pic16_popGet(AOP(result),offr)); + break; + case 6: + pic16_emitpcode(POC_SWAPFW,pic16_popGet(AOP(left),offl)); + pic16_emitpcode(POC_ANDLW, pic16_popGetLit(0x30)); + pic16_emitpcode(POC_MOVWF,pic16_popGet(AOP(result),offr)); + pic16_emitpcode(POC_ADDWF,pic16_popGet(AOP(result),offr)); + pic16_emitpcode(POC_RLCF, pic16_popGet(AOP(result),offr)); + break; + case 7: + pic16_emitpcode(POC_RRCFW, pic16_popGet(AOP(left),offl)); + pic16_emitpcode(POC_CLRF, pic16_popGet(AOP(result),offr)); + pic16_emitpcode(POC_RRCF, pic16_popGet(AOP(result),offr)); + break; + + default: + DEBUGpic16_emitcode ("; ***","%s %d, shift count is %d",__FUNCTION__,__LINE__,shCount); + } + +} + +/*-----------------------------------------------------------------*/ +/* movLeft2Result - move byte from left to result */ +/*-----------------------------------------------------------------*/ +static void movLeft2Result (operand *left, int offl, + operand *result, int offr) +{ + char *l; + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + if(!pic16_sameRegs(AOP(left),AOP(result)) || (offl != offr)){ + l = pic16_aopGet(AOP(left),offl,FALSE,FALSE); + + if (*l == '@' && (IS_AOP_PREG(result))) { + pic16_emitcode("mov","a,%s",l); + pic16_aopPut(AOP(result),"a",offr); + } else { + 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) +{ + + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + if(pic16_sameRegs(AOP(result), AOP(left))) { + 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(0xF0)); + 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_RRCFW, pic16_popGet(AOP(left),offl+MSB16)); + pic16_emitpcode(POC_MOVWF,pic16_popGet(AOP(result),offr+MSB16)); + pic16_emitpcode(POC_RRCFW, pic16_popGet(AOP(result),offl)); + pic16_emitpcode(POC_MOVWF, 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(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=0; + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + same = pic16_sameRegs(AOP(result), AOP(left)); + + if(same && ((offl + MSB16) == offr)){ + same=1; + /* don't crash result[offr] */ + MOVA(pic16_aopGet(AOP(left),offl,FALSE,FALSE)); + pic16_emitcode("xch","a,%s", pic16_aopGet(AOP(left),offl+MSB16,FALSE,FALSE)); + } +/* else { + movLeft2Result(left,offl, result, offr); + MOVA(pic16_aopGet(AOP(left),offl+MSB16,FALSE,FALSE)); + } +*/ + /* a:x >> shCount (x = lsb(result))*/ +/* + if(sign) + AccAXRshS( pic16_aopGet(AOP(result),offr,FALSE,FALSE) , shCount); + else { + AccAXRsh( pic16_aopGet(AOP(result),offr,FALSE,FALSE) , shCount); +*/ + switch(shCount) { + case 0: + break; + case 1: + case 2: + case 3: + if(sign) + pic16_emitpcode(POC_RLCFW,pic16_popGet(AOP(result),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) + 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)); + 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+MSB16,FALSE,FALSE),1,0)); + 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)); + 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__); + MOVA(pic16_aopGet(AOP(left),offl,FALSE,FALSE)); + /* shift left accumulator */ + AccLsh(shCount); + /* or with result */ + pic16_emitcode("orl","a,%s", pic16_aopGet(AOP(result),offr,FALSE,FALSE)); + /* back to result */ + pic16_aopPut(AOP(result),"a",offr); +} + +/*-----------------------------------------------------------------*/ +/* shiftRLeftOrResult - shift right one byte from left,or to result*/ +/*-----------------------------------------------------------------*/ +static void shiftRLeftOrResult (operand *left, int offl, + operand *result, int offr, int shCount) +{ + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + MOVA(pic16_aopGet(AOP(left),offl,FALSE,FALSE)); + /* shift right accumulator */ + AccRsh(shCount); + /* or with result */ + pic16_emitcode("orl","a,%s", pic16_aopGet(AOP(result),offr,FALSE,FALSE)); + /* back to result */ + pic16_aopPut(AOP(result),"a",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",__FUNCTION__,__LINE__); + 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 */ +/* offl = LSB or MSB16 */ +/*-----------------------------------------------------------------*/ +static void shiftLLong (operand *left, operand *result, int offr ) +{ + char *l; + int size = AOP_SIZE(result); + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + if(size >= LSB+offr){ + l = pic16_aopGet(AOP(left),LSB,FALSE,FALSE); + MOVA(l); + pic16_emitcode("add","a,acc"); + if (pic16_sameRegs(AOP(left),AOP(result)) && + size >= MSB16+offr && offr != LSB ) + pic16_emitcode("xch","a,%s", + pic16_aopGet(AOP(left),LSB+offr,FALSE,FALSE)); + else + pic16_aopPut(AOP(result),"a",LSB+offr); + } + + if(size >= MSB16+offr){ + if (!(pic16_sameRegs(AOP(result),AOP(left)) && size >= MSB16+offr && offr != LSB) ) { + l = pic16_aopGet(AOP(left),MSB16,FALSE,FALSE); + MOVA(l); + } + pic16_emitcode("rlc","a"); + if (pic16_sameRegs(AOP(left),AOP(result)) && + size >= MSB24+offr && offr != LSB) + pic16_emitcode("xch","a,%s", + pic16_aopGet(AOP(left),MSB16+offr,FALSE,FALSE)); + else + pic16_aopPut(AOP(result),"a",MSB16+offr); + } + + if(size >= MSB24+offr){ + if (!(pic16_sameRegs(AOP(left),AOP(left)) && size >= MSB24+offr && offr != LSB)) { + l = pic16_aopGet(AOP(left),MSB24,FALSE,FALSE); + MOVA(l); + } + pic16_emitcode("rlc","a"); + if (pic16_sameRegs(AOP(left),AOP(result)) && + size >= MSB32+offr && offr != LSB ) + pic16_emitcode("xch","a,%s", + pic16_aopGet(AOP(left),MSB24+offr,FALSE,FALSE)); + else + pic16_aopPut(AOP(result),"a",MSB24+offr); + } + + if(size > MSB32+offr){ + if (!(pic16_sameRegs(AOP(result),AOP(left)) && size >= MSB32+offr && offr != LSB)) { + l = pic16_aopGet(AOP(left),MSB32,FALSE,FALSE); + MOVA(l); + } + pic16_emitcode("rlc","a"); + pic16_aopPut(AOP(result),"a",MSB32+offr); + } + if(offr != LSB) + pic16_aopPut(AOP(result),zero,LSB); +} + +/*-----------------------------------------------------------------*/ +/* genlshFour - shift four byte by a known amount != 0 */ +/*-----------------------------------------------------------------*/ +static void genlshFour (operand *result, operand *left, int shCount) +{ + int size; + + 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_aopPut(AOP(result),zero,LSB); + pic16_aopPut(AOP(result),zero,MSB16); + pic16_aopPut(AOP(result),zero,MSB32); + return; + } + + /* more than two bytes */ + else if ( shCount >= 16 ) { + /* lower order two bytes goes to higher order two bytes */ + shCount -= 16; + /* if some more remaining */ + if (shCount) + shiftL2Left2Result(left, LSB, result, MSB24, shCount); + else { + movLeft2Result(left, MSB16, result, MSB32); + movLeft2Result(left, LSB, result, MSB24); + } + pic16_aopPut(AOP(result),zero,MSB16); + pic16_aopPut(AOP(result),zero,LSB); + return; + } + + /* if more than 1 byte */ + else if ( shCount >= 8 ) { + /* lower order three bytes goes to higher order three bytes */ + shCount -= 8; + if(size == 2){ + if(shCount) + shiftL1Left2Result(left, LSB, result, MSB16, shCount); + else + movLeft2Result(left, LSB, result, MSB16); + } + else{ /* size = 4 */ + if(shCount == 0){ + movLeft2Result(left, MSB24, result, MSB32); + movLeft2Result(left, MSB16, result, MSB24); + movLeft2Result(left, LSB, result, MSB16); + pic16_aopPut(AOP(result),zero,LSB); + } + else if(shCount == 1) + shiftLLong(left, result, MSB16); + else{ + shiftL2Left2Result(left, MSB16, result, MSB24, shCount); + shiftL1Left2Result(left, LSB, result, MSB16, shCount); + shiftRLeftOrResult(left, LSB, result, MSB24, 8 - shCount); + pic16_aopPut(AOP(result),zero,LSB); + } + } + } + + /* 1 <= shCount <= 7 */ + else if(shCount <= 2){ + shiftLLong(left, result, LSB); + if(shCount == 2) + shiftLLong(result, result, LSB); + } + /* 3 <= shCount <= 7, optimize */ + else{ + shiftL2Left2Result(left, MSB24, result, MSB24, shCount); + shiftRLeftOrResult(left, MSB16, result, MSB24, 8 - shCount); + shiftL2Left2Result(left, LSB, result, LSB, shCount); + } +} + +/*-----------------------------------------------------------------*/ +/* genLeftShiftLiteral - left shifting by known count */ +/*-----------------------------------------------------------------*/ +static void genLeftShiftLiteral (operand *left, + operand *right, + operand *result, + iCode *ic) +{ + int shCount = (int) floatFromVal (AOP(right)->aopu.aop_lit); + int size; + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + pic16_freeAsmop(right,NULL,ic,TRUE); + + pic16_aopOp(left,ic,FALSE); + pic16_aopOp(result,ic,FALSE); + + 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; + } + +} +/*-----------------------------------------------------------------*/ +/* genLeftShift - generates code for left shifting */ +/*-----------------------------------------------------------------*/ +static void genLeftShift (iCode *ic) +{ + operand *left,*right, *result; + int size, offset; + char *l; + symbol *tlbl , *tlbl1; + pCodeOp *pctemp; + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + right = IC_RIGHT(ic); + left = IC_LEFT(ic); + result = IC_RESULT(ic); + + pic16_aopOp(right,ic,FALSE); + + /* if the shift count is known then do it + as efficiently as possible */ + if (AOP_TYPE(right) == AOP_LIT) { + genLeftShiftLiteral (left,right,result,ic); + return ; + } + + /* shift count is unknown then we have to form + a loop get the loop count in B : Note: we take + only the lower order byte since shifting + more that 32 bits make no sense anyway, ( the + largest size of an object can be only 32 bits ) */ + + + pic16_aopOp(left,ic,FALSE); + pic16_aopOp(result,ic,FALSE); + + /* now move the left to the result if they are not the + same */ + if (!pic16_sameRegs(AOP(left),AOP(result)) && + AOP_SIZE(result) > 1) { + + size = AOP_SIZE(result); + offset=0; + while (size--) { + l = pic16_aopGet(AOP(left),offset,FALSE,TRUE); + if (*l == '@' && (IS_AOP_PREG(result))) { + + pic16_emitcode("mov","a,%s",l); + pic16_aopPut(AOP(result),"a",offset); + } else { + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(left),offset)); + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),offset)); + //pic16_aopPut(AOP(result),l,offset); + } + offset++; + } + } + + size = AOP_SIZE(result); + + /* if it is only one byte then */ + if (size == 1) { + if(optimized_for_speed) { + pic16_emitpcode(POC_SWAPFW, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_ANDLW, pic16_popGetLit(0xf0)); + pic16_emitpcode(POC_BTFSS, pic16_newpCodeOpBit(pic16_aopGet(AOP(right),0,FALSE,FALSE),2,0)); + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),0)); + pic16_emitpcode(POC_BTFSS, pic16_newpCodeOpBit(pic16_aopGet(AOP(right),0,FALSE,FALSE),0,0)); + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(result),0)); + pic16_emitpcode(POC_RLCFW, pic16_popGet(AOP(result),0)); + pic16_emitpcode(POC_ANDLW, pic16_popGetLit(0xfe)); + pic16_emitpcode(POC_ADDFW, pic16_popGet(AOP(result),0)); + pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit(pic16_aopGet(AOP(right),0,FALSE,FALSE),1,0)); + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(result),0)); + } else { + + tlbl = newiTempLabel(NULL); + if (!pic16_sameRegs(AOP(left),AOP(result))) { + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),0)); + } + + pic16_emitpcode(POC_COMFW, pic16_popGet(AOP(right),0)); + pic16_emitpcode(POC_RRCF, pic16_popGet(AOP(result),0)); + pic16_emitpLabel(tlbl->key); + pic16_emitpcode(POC_RLCF, pic16_popGet(AOP(result),0)); + pic16_emitpcode(POC_ADDLW, pic16_popGetLit(1)); + emitSKPC; + pic16_emitpcode(POC_GOTO,pic16_popGetLabel(tlbl->key)); + } + goto release ; + } + + if (pic16_sameRegs(AOP(left),AOP(result))) { + + tlbl = newiTempLabel(NULL); + pic16_emitpcode(POC_COMFW, pic16_popGet(AOP(right),0)); + genMultiAsm(POC_RRCF, result, size,1); + pic16_emitpLabel(tlbl->key); + genMultiAsm(POC_RLCF, result, size,0); + pic16_emitpcode(POC_ADDLW, pic16_popGetLit(1)); + emitSKPC; + pic16_emitpcode(POC_GOTO,pic16_popGetLabel(tlbl->key)); + goto release; + } + + //tlbl = newiTempLabel(NULL); + //offset = 0 ; + //tlbl1 = newiTempLabel(NULL); + + //reAdjustPreg(AOP(result)); + + //pic16_emitcode("sjmp","%05d_DS_",tlbl1->key+100); + //pic16_emitcode("","%05d_DS_:",tlbl->key+100); + //l = pic16_aopGet(AOP(result),offset,FALSE,FALSE); + //MOVA(l); + //pic16_emitcode("add","a,acc"); + //pic16_aopPut(AOP(result),"a",offset++); + //while (--size) { + // l = pic16_aopGet(AOP(result),offset,FALSE,FALSE); + // MOVA(l); + // pic16_emitcode("rlc","a"); + // pic16_aopPut(AOP(result),"a",offset++); + //} + //reAdjustPreg(AOP(result)); + + //pic16_emitcode("","%05d_DS_:",tlbl1->key+100); + //pic16_emitcode("djnz","b,%05d_DS_",tlbl->key+100); + + + tlbl = newiTempLabel(NULL); + tlbl1= newiTempLabel(NULL); + + size = AOP_SIZE(result); + offset = 1; + + pctemp = pic16_popGetTempReg(); /* grab a temporary working register. */ + + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(right),0)); + + /* offset should be 0, 1 or 3 */ + pic16_emitpcode(POC_ANDLW, pic16_popGetLit(0x07 + ((offset&3) << 3))); + emitSKPNZ; + pic16_emitpcode(POC_GOTO, pic16_popGetLabel(tlbl1->key)); + + pic16_emitpcode(POC_MOVWF, pctemp); + + + pic16_emitpLabel(tlbl->key); + + emitCLRC; + pic16_emitpcode(POC_RLCF, pic16_popGet(AOP(result),0)); + while(--size) + pic16_emitpcode(POC_RLCF, pic16_popGet(AOP(result),offset++)); + + pic16_emitpcode(POC_DECFSZ, pctemp); + pic16_emitpcode(POC_GOTO,pic16_popGetLabel(tlbl->key)); + pic16_emitpLabel(tlbl1->key); + + pic16_popReleaseTempReg(pctemp); + + + release: + pic16_freeAsmop (right,NULL,ic,TRUE); + pic16_freeAsmop(left,NULL,ic,TRUE); + pic16_freeAsmop(result,NULL,ic,TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genrshOne - right shift a one byte quantity by known count */ +/*-----------------------------------------------------------------*/ +static void genrshOne (operand *result, operand *left, + int shCount, int sign) +{ + 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",__FUNCTION__,__LINE__); + /* if shCount >= 8 */ + if (shCount >= 8) { + shCount -= 8 ; + if (shCount) + shiftR1Left2Result(left, MSB16, result, LSB, + shCount, sign); + else + movLeft2Result(left, MSB16, result, LSB); + + pic16_emitpcode(POC_CLRF,pic16_popGet(AOP(result),MSB16)); + + if(sign) { + pic16_emitpcode(POC_BTFSC,pic16_newpCodeOpBit(pic16_aopGet(AOP(left),LSB,FALSE,FALSE),7,0)); + pic16_emitpcode(POC_DECF, pic16_popGet(AOP(result),MSB16)); + } + } + + /* 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) +{ + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + if(!sign) + pic16_emitcode("clr","c"); + MOVA(pic16_aopGet(AOP(left),MSB32,FALSE,FALSE)); + if(sign) + pic16_emitcode("mov","c,acc.7"); + pic16_emitcode("rrc","a"); + pic16_aopPut(AOP(result),"a",MSB32-offl); + if(offl == MSB16) + /* add sign of "a" */ + pic16_addSign(result, MSB32, sign); + + MOVA(pic16_aopGet(AOP(left),MSB24,FALSE,FALSE)); + pic16_emitcode("rrc","a"); + pic16_aopPut(AOP(result),"a",MSB24-offl); + + MOVA(pic16_aopGet(AOP(left),MSB16,FALSE,FALSE)); + pic16_emitcode("rrc","a"); + pic16_aopPut(AOP(result),"a",MSB16-offl); + + if(offl == LSB){ + MOVA(pic16_aopGet(AOP(left),LSB,FALSE,FALSE)); + pic16_emitcode("rrc","a"); + pic16_aopPut(AOP(result),"a",LSB); + } +} + +/*-----------------------------------------------------------------*/ +/* genrshFour - shift four byte by a known amount != 0 */ +/*-----------------------------------------------------------------*/ +static void genrshFour (operand *result, operand *left, + int shCount, int sign) +{ + 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{ + 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 = (int) floatFromVal (AOP(right)->aopu.aop_lit); + int lsize,res_size; + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + pic16_freeAsmop(right,NULL,ic,TRUE); + + pic16_aopOp(left,ic,FALSE); + pic16_aopOp(result,ic,FALSE); + +#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){ + while(res_size--) + movLeft2Result(left, lsize, result, res_size); + } + + else if(shCount >= (lsize * 8)){ + + if(res_size == 1) { + pic16_emitpcode(POC_CLRF, pic16_popGet(AOP(result),LSB)); + if(sign) { + pic16_emitpcode(POC_BTFSC,pic16_newpCodeOpBit(pic16_aopGet(AOP(left),lsize-1,FALSE,FALSE),7,0)); + pic16_emitpcode(POC_DECF, pic16_popGet(AOP(result),LSB)); + } + } else { + + if(sign) { + pic16_emitpcode(POC_MOVLW, pic16_popGetLit(0)); + pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit(pic16_aopGet(AOP(left),lsize-1,FALSE,FALSE),7,0)); + pic16_emitpcode(POC_MOVLW, pic16_popGetLit(0xff)); + while(res_size--) + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),res_size)); + + } else { + + while(res_size--) + pic16_emitpcode(POC_CLRF, pic16_popGet(AOP(result),res_size)); + } + } + } else { + + 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); +} + +/*-----------------------------------------------------------------*/ +/* genSignedRightShift - right shift of signed number */ +/*-----------------------------------------------------------------*/ +static void genSignedRightShift (iCode *ic) +{ + operand *right, *left, *result; + int size, offset; + // char *l; + symbol *tlbl, *tlbl1 ; + pCodeOp *pctemp; + + //same = ((left == result) || (AOP(left) == AOP(result))) && (offl == offr); + + /* we do it the hard way put the shift count in b + and loop thru preserving the sign */ + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + 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,FALSE); + + + if ( AOP_TYPE(right) == AOP_LIT) { + genRightShiftLiteral (left,right,result,ic,1); + return ; + } + /* shift count is unknown then we have to form + a loop get the loop count in B : Note: we take + only the lower order byte since shifting + more that 32 bits make no sense anyway, ( the + largest size of an object can be only 32 bits ) */ + + //pic16_emitcode("mov","b,%s",pic16_aopGet(AOP(right),0,FALSE,FALSE)); + //pic16_emitcode("inc","b"); + //pic16_freeAsmop (right,NULL,ic,TRUE); + //pic16_aopOp(left,ic,FALSE); + //pic16_aopOp(result,ic,FALSE); + + /* now move the left to the result if they are not the + same */ + if (!pic16_sameRegs(AOP(left),AOP(result)) && + AOP_SIZE(result) > 1) { + + size = AOP_SIZE(result); + offset=0; + while (size--) { + /* + l = pic16_aopGet(AOP(left),offset,FALSE,TRUE); + if (*l == '@' && IS_AOP_PREG(result)) { + + pic16_emitcode("mov","a,%s",l); + pic16_aopPut(AOP(result),"a",offset); + } else + pic16_aopPut(AOP(result),l,offset); + */ + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(left),offset)); + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),offset)); + + offset++; + } + } + + /* mov the highest order bit to OVR */ + tlbl = newiTempLabel(NULL); + tlbl1= newiTempLabel(NULL); + + size = AOP_SIZE(result); + offset = size - 1; + + pctemp = pic16_popGetTempReg(); /* grab a temporary working register. */ + + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(right),0)); + + /* offset should be 0, 1 or 3 */ + pic16_emitpcode(POC_ANDLW, pic16_popGetLit(0x07 + ((offset&3) << 3))); + emitSKPNZ; + pic16_emitpcode(POC_GOTO, pic16_popGetLabel(tlbl1->key)); + + pic16_emitpcode(POC_MOVWF, pctemp); + + + pic16_emitpLabel(tlbl->key); + + pic16_emitpcode(POC_RLCFW, pic16_popGet(AOP(result),offset)); + pic16_emitpcode(POC_RRCF, pic16_popGet(AOP(result),offset)); + + while(--size) { + pic16_emitpcode(POC_RRCF, pic16_popGet(AOP(result),--offset)); + } + + pic16_emitpcode(POC_DECFSZ, pctemp); + pic16_emitpcode(POC_GOTO,pic16_popGetLabel(tlbl->key)); + pic16_emitpLabel(tlbl1->key); + + pic16_popReleaseTempReg(pctemp); +#if 0 + size = AOP_SIZE(result); + offset = size - 1; + pic16_emitcode("mov","a,%s",pic16_aopGet(AOP(left),offset,FALSE,FALSE)); + pic16_emitcode("rlc","a"); + pic16_emitcode("mov","ov,c"); + /* if it is only one byte then */ + if (size == 1) { + l = pic16_aopGet(AOP(left),0,FALSE,FALSE); + MOVA(l); + pic16_emitcode("sjmp","%05d_DS_",tlbl1->key+100); + pic16_emitcode("","%05d_DS_:",tlbl->key+100); + pic16_emitcode("mov","c,ov"); + pic16_emitcode("rrc","a"); + pic16_emitcode("","%05d_DS_:",tlbl1->key+100); + pic16_emitcode("djnz","b,%05d_DS_",tlbl->key+100); + pic16_aopPut(AOP(result),"a",0); + goto release ; + } + + reAdjustPreg(AOP(result)); + pic16_emitcode("sjmp","%05d_DS_",tlbl1->key+100); + pic16_emitcode("","%05d_DS_:",tlbl->key+100); + pic16_emitcode("mov","c,ov"); + while (size--) { + l = pic16_aopGet(AOP(result),offset,FALSE,FALSE); + MOVA(l); + pic16_emitcode("rrc","a"); + pic16_aopPut(AOP(result),"a",offset--); + } + reAdjustPreg(AOP(result)); + pic16_emitcode("","%05d_DS_:",tlbl1->key+100); + pic16_emitcode("djnz","b,%05d_DS_",tlbl->key+100); + + release: +#endif + + pic16_freeAsmop(left,NULL,ic,TRUE); + pic16_freeAsmop(result,NULL,ic,TRUE); + pic16_freeAsmop(right,NULL,ic,TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genRightShift - generate code for right shifting */ +/*-----------------------------------------------------------------*/ +static void genRightShift (iCode *ic) +{ + operand *right, *left, *result; + sym_link *retype ; + int size, offset; + char *l; + symbol *tlbl, *tlbl1 ; + + /* if signed then we do it the hard way preserve the + sign bit moving it inwards */ + retype = getSpec(operandType(IC_RESULT(ic))); + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + if (!SPEC_USIGN(retype)) { + genSignedRightShift (ic); + return ; + } + + /* signed & unsigned types are treated the same : i.e. the + signed is NOT propagated inwards : quoting from the + ANSI - standard : "for E1 >> E2, is equivalent to division + by 2**E2 if unsigned or if it has a non-negative value, + otherwise the result is implementation defined ", MY definition + is that the sign does not get propagated */ + + right = IC_RIGHT(ic); + left = IC_LEFT(ic); + result = IC_RESULT(ic); + + pic16_aopOp(right,ic,FALSE); + + /* if the shift count is known then do it + as efficiently as possible */ + if (AOP_TYPE(right) == AOP_LIT) { + genRightShiftLiteral (left,right,result,ic, 0); + return ; + } + + /* shift count is unknown then we have to form + a loop get the loop count in B : Note: we take + only the lower order byte since shifting + more that 32 bits make no sense anyway, ( the + largest size of an object can be only 32 bits ) */ + + pic16_emitcode("mov","b,%s",pic16_aopGet(AOP(right),0,FALSE,FALSE)); + pic16_emitcode("inc","b"); + pic16_aopOp(left,ic,FALSE); + pic16_aopOp(result,ic,FALSE); + + /* now move the left to the result if they are not the + same */ + if (!pic16_sameRegs(AOP(left),AOP(result)) && + AOP_SIZE(result) > 1) { + + size = AOP_SIZE(result); + offset=0; + while (size--) { + l = pic16_aopGet(AOP(left),offset,FALSE,TRUE); + if (*l == '@' && IS_AOP_PREG(result)) { + + pic16_emitcode("mov","a,%s",l); + pic16_aopPut(AOP(result),"a",offset); + } else + pic16_aopPut(AOP(result),l,offset); + offset++; + } + } + + tlbl = newiTempLabel(NULL); + tlbl1= newiTempLabel(NULL); + size = AOP_SIZE(result); + offset = size - 1; + + /* if it is only one byte then */ + if (size == 1) { + + tlbl = newiTempLabel(NULL); + if (!pic16_sameRegs(AOP(left),AOP(result))) { + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),0)); + } + + pic16_emitpcode(POC_COMFW, pic16_popGet(AOP(right),0)); + pic16_emitpcode(POC_RLCF, pic16_popGet(AOP(result),0)); + pic16_emitpLabel(tlbl->key); + pic16_emitpcode(POC_RRCF, pic16_popGet(AOP(result),0)); + pic16_emitpcode(POC_ADDLW, pic16_popGetLit(1)); + emitSKPC; + pic16_emitpcode(POC_GOTO,pic16_popGetLabel(tlbl->key)); + + goto release ; + } + + reAdjustPreg(AOP(result)); + pic16_emitcode("sjmp","%05d_DS_",tlbl1->key+100); + pic16_emitcode("","%05d_DS_:",tlbl->key+100); + CLRC; + while (size--) { + l = pic16_aopGet(AOP(result),offset,FALSE,FALSE); + MOVA(l); + pic16_emitcode("rrc","a"); + pic16_aopPut(AOP(result),"a",offset--); + } + reAdjustPreg(AOP(result)); + + pic16_emitcode("","%05d_DS_:",tlbl1->key+100); + pic16_emitcode("djnz","b,%05d_DS_",tlbl->key+100); + +release: + pic16_freeAsmop(left,NULL,ic,TRUE); + pic16_freeAsmop (right,NULL,ic,TRUE); + pic16_freeAsmop(result,NULL,ic,TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genUnpackBits - generates code for unpacking bits */ +/*-----------------------------------------------------------------*/ +static void genUnpackBits (operand *result, char *rname, int ptype) +{ + int shCnt ; + int rlen = 0 ; + sym_link *etype; + int offset = 0 ; + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + etype = getSpec(operandType(result)); + + /* read the first byte */ + switch (ptype) { + + case POINTER: + case IPOINTER: + pic16_emitcode("mov","a,@%s",rname); + break; + + case PPOINTER: + pic16_emitcode("movx","a,@%s",rname); + break; + + case FPOINTER: + pic16_emitcode("movx","a,@dptr"); + break; + + case CPOINTER: + pic16_emitcode("clr","a"); + pic16_emitcode("movc","a","@a+dptr"); + break; + + case GPOINTER: + pic16_emitcode("lcall","__gptrget"); + break; + } + + /* if we have bitdisplacement then it fits */ + /* into this byte completely or if length is */ + /* less than a byte */ + if ((shCnt = SPEC_BSTR(etype)) || + (SPEC_BLEN(etype) <= 8)) { + + /* shift right acc */ + AccRsh(shCnt); + + pic16_emitcode("anl","a,#0x%02x", + ((unsigned char) -1)>>(8 - SPEC_BLEN(etype))); + pic16_aopPut(AOP(result),"a",offset); + return ; + } + + /* bit field did not fit in a byte */ + rlen = SPEC_BLEN(etype) - 8; + pic16_aopPut(AOP(result),"a",offset++); + + while (1) { + + switch (ptype) { + case POINTER: + case IPOINTER: + pic16_emitcode("inc","%s",rname); + pic16_emitcode("mov","a,@%s",rname); + break; + + case PPOINTER: + pic16_emitcode("inc","%s",rname); + pic16_emitcode("movx","a,@%s",rname); + break; + + case FPOINTER: + pic16_emitcode("inc","dptr"); + pic16_emitcode("movx","a,@dptr"); + break; + + case CPOINTER: + pic16_emitcode("clr","a"); + pic16_emitcode("inc","dptr"); + pic16_emitcode("movc","a","@a+dptr"); + break; + + case GPOINTER: + pic16_emitcode("inc","dptr"); + pic16_emitcode("lcall","__gptrget"); + break; + } + + rlen -= 8; + /* if we are done */ + if ( rlen <= 0 ) + break ; + + pic16_aopPut(AOP(result),"a",offset++); + + } + + if (rlen) { + pic16_emitcode("anl","a,#0x%02x",((unsigned char)-1)>>(-rlen)); + pic16_aopPut(AOP(result),"a",offset); + } + + return ; +} + +#if 0 +/*-----------------------------------------------------------------*/ +/* genDataPointerGet - generates code when ptr offset is known */ +/*-----------------------------------------------------------------*/ +static void genDataPointerGet (operand *left, + operand *result, + iCode *ic) +{ + int size , offset = 0; + + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + + /* optimization - most of the time, left and result are the same + * address, but different types. for the pic code, we could omit + * the following + */ + + pic16_aopOp(result,ic,TRUE); + + DEBUGpic16_pic16_AopType(__LINE__,left,NULL,result); + + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(left),0)); + + size = AOP_SIZE(result); + + while (size--) { + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),offset)); + offset++; + } + + pic16_freeAsmop(left,NULL,ic,TRUE); + pic16_freeAsmop(result,NULL,ic,TRUE); +} +#endif +/*-----------------------------------------------------------------*/ +/* genNearPointerGet - pic16_emitcode for near pointer fetch */ +/*-----------------------------------------------------------------*/ +static void genNearPointerGet (operand *left, + operand *result, + iCode *ic) +{ + asmop *aop = NULL; + //regs *preg = NULL ; + char *rname ; + sym_link *rtype, *retype; + sym_link *ltype = operandType(left); + //char buffer[80]; + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + rtype = operandType(result); + retype= getSpec(rtype); + + pic16_aopOp(left,ic,FALSE); + + /* if left is rematerialisable and + result is not bit variable type and + the left is pointer to data space i.e + lower 128 bytes of space */ + if (AOP_TYPE(left) == AOP_PCODE && //AOP_TYPE(left) == AOP_IMMD && + !IS_BITVAR(retype) && + DCL_TYPE(ltype) == POINTER) { + //genDataPointerGet (left,result,ic); + return ; + } + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + /* if the value is already in a pointer register + then don't need anything more */ + if (!AOP_INPREG(AOP(left))) { + /* otherwise get a free pointer register */ + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); +/* + aop = newAsmop(0); + preg = getFreePtr(ic,&aop,FALSE); + pic16_emitcode("mov","%s,%s", + preg->name, + pic16_aopGet(AOP(left),0,FALSE,TRUE)); + rname = preg->name ; +*/ + rname ="BAD"; + } else + rname = pic16_aopGet(AOP(left),0,FALSE,FALSE); + + pic16_aopOp (result,ic,FALSE); + + /* if bitfield then unpack the bits */ + if (IS_BITVAR(retype)) + genUnpackBits (result,rname,POINTER); + else { + /* we have can just get the values */ + int size = AOP_SIZE(result); + int offset = 0 ; + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + pic16_emitpcode(POC_MOVFW,pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_MOVWF,pic16_popCopyReg(&pic16_pc_fsr0)); + while(size--) { + pic16_emitpcode(POC_MOVFW,pic16_popCopyReg(&pic16_pc_indf0)); + pic16_emitpcode(POC_MOVWF,pic16_popGet(AOP(result),offset++)); + if(size) + pic16_emitpcode(POC_INCF,pic16_popCopyReg(&pic16_pc_fsr0)); + } +/* + while (size--) { + if (IS_AOP_PREG(result) || AOP_TYPE(result) == AOP_STK ) { + + pic16_emitcode("mov","a,@%s",rname); + pic16_aopPut(AOP(result),"a",offset); + } else { + sprintf(buffer,"@%s",rname); + pic16_aopPut(AOP(result),buffer,offset); + } + offset++ ; + if (size) + pic16_emitcode("inc","%s",rname); + } +*/ + } + + /* 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); + } + } + + /* done */ + pic16_freeAsmop(left,NULL,ic,TRUE); + pic16_freeAsmop(result,NULL,ic,TRUE); + +} + +/*-----------------------------------------------------------------*/ +/* genPagedPointerGet - pic16_emitcode for paged pointer fetch */ +/*-----------------------------------------------------------------*/ +static void genPagedPointerGet (operand *left, + operand *result, + iCode *ic) +{ + asmop *aop = NULL; + regs *preg = NULL ; + char *rname ; + sym_link *rtype, *retype; + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + rtype = operandType(result); + retype= getSpec(rtype); + + pic16_aopOp(left,ic,FALSE); + + /* if the value is already in a pointer register + then don't need anything more */ + if (!AOP_INPREG(AOP(left))) { + /* otherwise get a free pointer register */ + aop = newAsmop(0); + preg = getFreePtr(ic,&aop,FALSE); + pic16_emitcode("mov","%s,%s", + preg->name, + pic16_aopGet(AOP(left),0,FALSE,TRUE)); + rname = preg->name ; + } else + rname = pic16_aopGet(AOP(left),0,FALSE,FALSE); + + pic16_freeAsmop(left,NULL,ic,TRUE); + pic16_aopOp (result,ic,FALSE); + + /* if bitfield then unpack the bits */ + if (IS_BITVAR(retype)) + genUnpackBits (result,rname,PPOINTER); + else { + /* we have can just get the values */ + int size = AOP_SIZE(result); + int offset = 0 ; + + while (size--) { + + pic16_emitcode("movx","a,@%s",rname); + pic16_aopPut(AOP(result),"a",offset); + + offset++ ; + + if (size) + pic16_emitcode("inc","%s",rname); + } + } + + /* 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 */ + 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); + } + } + + /* done */ + pic16_freeAsmop(result,NULL,ic,TRUE); + + +} + +/*-----------------------------------------------------------------*/ +/* genFarPointerGet - gget value from far space */ +/*-----------------------------------------------------------------*/ +static void genFarPointerGet (operand *left, + operand *result, iCode *ic) +{ + int size, offset ; + sym_link *retype = getSpec(operandType(result)); + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + pic16_aopOp(left,ic,FALSE); + + /* if the operand is already in dptr + then we do nothing else we move the value to dptr */ + if (AOP_TYPE(left) != AOP_STR) { + /* if this is remateriazable */ + if (AOP_TYPE(left) == AOP_IMMD) + pic16_emitcode("mov","dptr,%s",pic16_aopGet(AOP(left),0,TRUE,FALSE)); + else { /* we need to get it byte by byte */ + pic16_emitcode("mov","dpl,%s",pic16_aopGet(AOP(left),0,FALSE,FALSE)); + pic16_emitcode("mov","dph,%s",pic16_aopGet(AOP(left),1,FALSE,FALSE)); + if (options.model == MODEL_FLAT24) + { + pic16_emitcode("mov", "dpx,%s",pic16_aopGet(AOP(left),2,FALSE,FALSE)); + } + } + } + /* so dptr know contains the address */ + pic16_freeAsmop(left,NULL,ic,TRUE); + pic16_aopOp(result,ic,FALSE); + + /* if bit then unpack */ + if (IS_BITVAR(retype)) + genUnpackBits(result,"dptr",FPOINTER); + else { + size = AOP_SIZE(result); + offset = 0 ; + + while (size--) { + pic16_emitcode("movx","a,@dptr"); + pic16_aopPut(AOP(result),"a",offset++); + if (size) + pic16_emitcode("inc","dptr"); + } + } + + pic16_freeAsmop(result,NULL,ic,TRUE); +} +#if 0 +/*-----------------------------------------------------------------*/ +/* genCodePointerGet - get value from code space */ +/*-----------------------------------------------------------------*/ +static void genCodePointerGet (operand *left, + operand *result, iCode *ic) +{ + int size, offset ; + sym_link *retype = getSpec(operandType(result)); + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + pic16_aopOp(left,ic,FALSE); + + /* if the operand is already in dptr + then we do nothing else we move the value to dptr */ + if (AOP_TYPE(left) != AOP_STR) { + /* if this is remateriazable */ + if (AOP_TYPE(left) == AOP_IMMD) + pic16_emitcode("mov","dptr,%s",pic16_aopGet(AOP(left),0,TRUE,FALSE)); + else { /* we need to get it byte by byte */ + pic16_emitcode("mov","dpl,%s",pic16_aopGet(AOP(left),0,FALSE,FALSE)); + pic16_emitcode("mov","dph,%s",pic16_aopGet(AOP(left),1,FALSE,FALSE)); + if (options.model == MODEL_FLAT24) + { + pic16_emitcode("mov", "dpx,%s",pic16_aopGet(AOP(left),2,FALSE,FALSE)); + } + } + } + /* so dptr know contains the address */ + pic16_freeAsmop(left,NULL,ic,TRUE); + pic16_aopOp(result,ic,FALSE); + + /* if bit then unpack */ + if (IS_BITVAR(retype)) + genUnpackBits(result,"dptr",CPOINTER); + else { + size = AOP_SIZE(result); + offset = 0 ; + + while (size--) { + pic16_emitcode("clr","a"); + pic16_emitcode("movc","a,@a+dptr"); + pic16_aopPut(AOP(result),"a",offset++); + if (size) + pic16_emitcode("inc","dptr"); + } + } + + pic16_freeAsmop(result,NULL,ic,TRUE); +} +#endif +/*-----------------------------------------------------------------*/ +/* genGenPointerGet - gget value from generic pointer space */ +/*-----------------------------------------------------------------*/ +static void genGenPointerGet (operand *left, + operand *result, iCode *ic) +{ + int size, offset ; + sym_link *retype = getSpec(operandType(result)); + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + pic16_aopOp(left,ic,FALSE); + pic16_aopOp(result,ic,FALSE); + + + DEBUGpic16_pic16_AopType(__LINE__,left,NULL,result); + + /* if the operand is already in dptr + then we do nothing else we move the value to dptr */ + // if (AOP_TYPE(left) != AOP_STR) { + /* if this is remateriazable */ + if (AOP_TYPE(left) == AOP_IMMD) { + pic16_emitcode("mov","dptr,%s",pic16_aopGet(AOP(left),0,TRUE,FALSE)); + pic16_emitcode("mov","b,#%d",pointerCode(retype)); + } + else { /* we need to get it byte by byte */ + + pic16_emitpcode(POC_MOVFW,pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_MOVWF,pic16_popCopyReg(&pic16_pc_fsr0)); + + size = AOP_SIZE(result); + offset = 0 ; + + while(size--) { + pic16_emitpcode(POC_MOVFW,pic16_popCopyReg(&pic16_pc_indf0)); + pic16_emitpcode(POC_MOVWF,pic16_popGet(AOP(result),offset++)); + if(size) + pic16_emitpcode(POC_INCF,pic16_popCopyReg(&pic16_pc_fsr0)); + } + goto release; + } + //} + /* so dptr know contains the address */ + + /* if bit then unpack */ + //if (IS_BITVAR(retype)) + // genUnpackBits(result,"dptr",GPOINTER); + + 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); + symbol *blbl = newiTempLabel(NULL); + PIC_OPCODE poc; + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + pic16_aopOp(left,ic,FALSE); + pic16_aopOp(result,ic,FALSE); + + + DEBUGpic16_pic16_AopType(__LINE__,left,NULL,result); + + DEBUGpic16_emitcode ("; "," %d getting const pointer",__LINE__); + + pic16_emitpcode(POC_CALL,pic16_popGetLabel(albl->key)); + pic16_emitpcode(POC_GOTO,pic16_popGetLabel(blbl->key)); + pic16_emitpLabel(albl->key); + + poc = ( (AOP_TYPE(left) == AOP_PCODE) ? POC_MOVLW : POC_MOVFW); + + pic16_emitpcode(poc,pic16_popGet(AOP(left),1)); + pic16_emitpcode(POC_MOVWF,pic16_popCopyReg(&pic16_pc_pclath)); + pic16_emitpcode(poc,pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_MOVWF,pic16_popCopyReg(&pic16_pc_pcl)); + + pic16_emitpLabel(blbl->key); + + pic16_emitpcode(POC_MOVWF,pic16_popGet(AOP(result),0)); + + + 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; + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + left = IC_LEFT(ic); + result = IC_RESULT(ic) ; + + /* depending on the type of pointer we need to + move it to the correct pointer register */ + type = operandType(left); + etype = getSpec(type); + + if (IS_PTR_CONST(type)) + 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 IPOINTER: + genNearPointerGet (left,result,ic); + break; + + case PPOINTER: + genPagedPointerGet(left,result,ic); + break; + + case FPOINTER: + genFarPointerGet (left,result,ic); + break; + + case CPOINTER: + genConstPointerGet (left,result,ic); + //pic16_emitcodePointerGet (left,result,ic); + break; + + case GPOINTER: + if (IS_PTR_CONST(type)) + genConstPointerGet (left,result,ic); + else + genGenPointerGet (left,result,ic); + break; + } + +} + +/*-----------------------------------------------------------------*/ +/* genPackBits - generates code for packed bit storage */ +/*-----------------------------------------------------------------*/ +static void genPackBits (sym_link *etype , + operand *right , + char *rname, int p_type) +{ + int shCount = 0 ; + int offset = 0 ; + int rLen = 0 ; + int blen, bstr ; + char *l ; + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + blen = SPEC_BLEN(etype); + bstr = SPEC_BSTR(etype); + + l = pic16_aopGet(AOP(right),offset++,FALSE,FALSE); + MOVA(l); + + /* if the bit lenth is less than or */ + /* it exactly fits a byte then */ + if (SPEC_BLEN(etype) <= 8 ) { + shCount = SPEC_BSTR(etype) ; + + /* shift left acc */ + AccLsh(shCount); + + if (SPEC_BLEN(etype) < 8 ) { /* if smaller than a byte */ + + + switch (p_type) { + case POINTER: + pic16_emitcode ("mov","b,a"); + pic16_emitcode("mov","a,@%s",rname); + 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; + } + + pic16_emitcode ("anl","a,#0x%02x",(unsigned char) + ((unsigned char)(0xFF << (blen+bstr)) | + (unsigned char)(0xFF >> (8-bstr)) ) ); + pic16_emitcode ("orl","a,b"); + if (p_type == GPOINTER) + pic16_emitcode("pop","b"); + } + } + + switch (p_type) { + case POINTER: + pic16_emitcode("mov","@%s,a",rname); + break; + + case FPOINTER: + pic16_emitcode("movx","@dptr,a"); + break; + + case GPOINTER: + DEBUGpic16_emitcode(";lcall","__gptrput"); + break; + } + + /* if we r done */ + if ( SPEC_BLEN(etype) <= 8 ) + return ; + + pic16_emitcode("inc","%s",rname); + rLen = SPEC_BLEN(etype) ; + + /* now generate for lengths greater than one byte */ + while (1) { + + l = pic16_aopGet(AOP(right),offset++,FALSE,TRUE); + + rLen -= 8 ; + if (rLen <= 0 ) + break ; + + switch (p_type) { + case POINTER: + if (*l == '@') { + MOVA(l); + pic16_emitcode("mov","@%s,a",rname); + } else + pic16_emitcode("mov","@%s,%s",rname,l); + break; + + case FPOINTER: + MOVA(l); + pic16_emitcode("movx","@dptr,a"); + break; + + case GPOINTER: + MOVA(l); + DEBUGpic16_emitcode(";lcall","__gptrput"); + break; + } + pic16_emitcode ("inc","%s",rname); + } + + MOVA(l); + + /* last last was not complete */ + if (rLen) { + /* save the byte & read byte */ + switch (p_type) { + case POINTER: + pic16_emitcode ("mov","b,a"); + pic16_emitcode("mov","a,@%s",rname); + 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; + } + + 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_emitcode("mov","@%s,a",rname); + break; + + case FPOINTER: + pic16_emitcode("movx","@dptr,a"); + break; + + case GPOINTER: + DEBUGpic16_emitcode(";lcall","__gptrput"); + break; + } +} +/*-----------------------------------------------------------------*/ +/* genDataPointerSet - remat pointer to data space */ +/*-----------------------------------------------------------------*/ +static void genDataPointerSet(operand *right, + operand *result, + iCode *ic) +{ + int size, offset = 0 ; + char *l, buffer[256]; + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + pic16_aopOp(right,ic,FALSE); + + l = pic16_aopGet(AOP(result),0,FALSE,TRUE); + size = AOP_SIZE(right); +/* + if ( AOP_TYPE(result) == AOP_PCODE) { + fprintf(stderr,"genDataPointerSet %s, %d\n", + AOP(result)->aopu.pcop->name, + PCOI(AOP(result)->aopu.pcop)->offset); + } +*/ + + // tsd, was l+1 - the underline `_' prefix was being stripped + while (size--) { + if (offset) { + sprintf(buffer,"(%s + %d)",l,offset); + fprintf(stderr,"oops %s\n",buffer); + } else + sprintf(buffer,"%s",l); + + if (AOP_TYPE(right) == AOP_LIT) { + unsigned int lit = (unsigned int) floatFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit); + lit = lit >> (8*offset); + if(lit&0xff) { + pic16_emitcode("movlw","%d",lit); + pic16_emitcode("movwf","%s",buffer); + + pic16_emitpcode(POC_MOVLW, pic16_popGetLit(lit&0xff)); + //pic16_emitpcode(POC_MOVWF, popRegFromString(buffer)); + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),0)); + + } else { + pic16_emitcode("clrf","%s",buffer); + //pic16_emitpcode(POC_CLRF, popRegFromString(buffer)); + pic16_emitpcode(POC_CLRF, pic16_popGet(AOP(result),0)); + } + }else { + pic16_emitcode("movf","%s,w",pic16_aopGet(AOP(right),offset,FALSE,FALSE)); + pic16_emitcode("movwf","%s",buffer); + + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(right),offset)); + //pic16_emitpcode(POC_MOVWF, popRegFromString(buffer)); + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),0)); + + } + + offset++; + } + + pic16_freeAsmop(right,NULL,ic,TRUE); + pic16_freeAsmop(result,NULL,ic,TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genNearPointerSet - pic16_emitcode for near pointer put */ +/*-----------------------------------------------------------------*/ +static void genNearPointerSet (operand *right, + operand *result, + iCode *ic) +{ + asmop *aop = NULL; + char *l; + sym_link *retype; + sym_link *ptype = operandType(result); + + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + retype= getSpec(operandType(right)); + + pic16_aopOp(result,ic,FALSE); + + + /* if the result is rematerializable & + in data space & not a bit variable */ + //if (AOP_TYPE(result) == AOP_IMMD && + if (AOP_TYPE(result) == AOP_PCODE && //AOP_TYPE(result) == AOP_IMMD && + DCL_TYPE(ptype) == POINTER && + !IS_BITVAR(retype)) { + 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 the value is already in a pointer register + then don't need anything more */ + if (!AOP_INPREG(AOP(result))) { + /* otherwise get a free pointer register */ + //aop = newAsmop(0); + //preg = getFreePtr(ic,&aop,FALSE); + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + //pic16_emitcode("mov","%s,%s", + // preg->name, + // pic16_aopGet(AOP(result),0,FALSE,TRUE)); + //rname = preg->name ; + //pic16_emitcode("movwf","fsr0"); + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(result),0)); + pic16_emitpcode(POC_MOVWF, pic16_popCopyReg(&pic16_pc_fsr0)); + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(right),0)); + pic16_emitpcode(POC_MOVWF, pic16_popCopyReg(&pic16_pc_indf0)); + goto release; + + }// else + // rname = pic16_aopGet(AOP(result),0,FALSE,FALSE); + + + /* if bitfield then unpack the bits */ + if (IS_BITVAR(retype)) { + werror(E_INTERNAL_ERROR,__FILE__,__LINE__, + "The programmer is obviously confused"); + //genPackBits (retype,right,rname,POINTER); + exit(1); + } + else { + /* we have can just get the values */ + int size = AOP_SIZE(right); + int offset = 0 ; + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + while (size--) { + l = pic16_aopGet(AOP(right),offset,FALSE,TRUE); + if (*l == '@' ) { + //MOVA(l); + //pic16_emitcode("mov","@%s,a",rname); + pic16_emitcode("movf","indf0,w ;1"); + } else { + + if (AOP_TYPE(right) == AOP_LIT) { + unsigned int lit = (unsigned int) floatFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit); + if(lit) { + pic16_emitcode("movlw","%s",l); + pic16_emitcode("movwf","indf0 ;2"); + } else + pic16_emitcode("clrf","indf0"); + }else { + pic16_emitcode("movf","%s,w",l); + pic16_emitcode("movwf","indf0 ;2"); + } + //pic16_emitcode("mov","@%s,%s",rname,l); + } + if (size) + pic16_emitcode("incf","fsr0,f ;3"); + //pic16_emitcode("inc","%s",rname); + 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); +} + +/*-----------------------------------------------------------------*/ +/* genPagedPointerSet - pic16_emitcode for Paged pointer put */ +/*-----------------------------------------------------------------*/ +static void genPagedPointerSet (operand *right, + operand *result, + iCode *ic) +{ + asmop *aop = NULL; + regs *preg = NULL ; + char *rname , *l; + sym_link *retype; + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + retype= getSpec(operandType(right)); + + pic16_aopOp(result,ic,FALSE); + + /* if the value is already in a pointer register + then don't need anything more */ + if (!AOP_INPREG(AOP(result))) { + /* otherwise get a free pointer register */ + aop = newAsmop(0); + preg = getFreePtr(ic,&aop,FALSE); + pic16_emitcode("mov","%s,%s", + preg->name, + pic16_aopGet(AOP(result),0,FALSE,TRUE)); + rname = preg->name ; + } else + rname = pic16_aopGet(AOP(result),0,FALSE,FALSE); + + pic16_freeAsmop(result,NULL,ic,TRUE); + pic16_aopOp (right,ic,FALSE); + + /* if bitfield then unpack the bits */ + if (IS_BITVAR(retype)) + genPackBits (retype,right,rname,PPOINTER); + else { + /* we have can just get the values */ + int size = AOP_SIZE(right); + int offset = 0 ; + + while (size--) { + l = pic16_aopGet(AOP(right),offset,FALSE,TRUE); + + MOVA(l); + pic16_emitcode("movx","@%s,a",rname); + + if (size) + pic16_emitcode("inc","%s",rname); + + offset++; + } + } + + /* 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 */ + 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("dec","%s",rname); + } + } + + /* done */ + pic16_freeAsmop(right,NULL,ic,TRUE); + + +} + +/*-----------------------------------------------------------------*/ +/* genFarPointerSet - set value from far space */ +/*-----------------------------------------------------------------*/ +static void genFarPointerSet (operand *right, + operand *result, iCode *ic) +{ + int size, offset ; + sym_link *retype = getSpec(operandType(right)); + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + pic16_aopOp(result,ic,FALSE); + + /* if the operand is already in dptr + then we do nothing else we move the value to dptr */ + if (AOP_TYPE(result) != AOP_STR) { + /* if this is remateriazable */ + if (AOP_TYPE(result) == AOP_IMMD) + pic16_emitcode("mov","dptr,%s",pic16_aopGet(AOP(result),0,TRUE,FALSE)); + else { /* we need to get it byte by byte */ + pic16_emitcode("mov","dpl,%s",pic16_aopGet(AOP(result),0,FALSE,FALSE)); + pic16_emitcode("mov","dph,%s",pic16_aopGet(AOP(result),1,FALSE,FALSE)); + if (options.model == MODEL_FLAT24) + { + pic16_emitcode("mov", "dpx,%s",pic16_aopGet(AOP(result),2,FALSE,FALSE)); + } + } + } + /* so dptr know contains the address */ + pic16_freeAsmop(result,NULL,ic,TRUE); + pic16_aopOp(right,ic,FALSE); + + /* if bit then unpack */ + if (IS_BITVAR(retype)) + genPackBits(retype,right,"dptr",FPOINTER); + else { + size = AOP_SIZE(right); + offset = 0 ; + + while (size--) { + char *l = pic16_aopGet(AOP(right),offset++,FALSE,FALSE); + MOVA(l); + pic16_emitcode("movx","@dptr,a"); + if (size) + pic16_emitcode("inc","dptr"); + } + } + + pic16_freeAsmop(right,NULL,ic,TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genGenPointerSet - set value from generic pointer space */ +/*-----------------------------------------------------------------*/ +static void genGenPointerSet (operand *right, + operand *result, iCode *ic) +{ + int size, offset ; + sym_link *retype = getSpec(operandType(right)); + + 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 the operand is already in dptr + then we do nothing else we move the value to dptr */ + if (AOP_TYPE(result) != AOP_STR) { + /* if this is remateriazable */ + if (AOP_TYPE(result) == AOP_IMMD) { + pic16_emitcode("mov","dptr,%s",pic16_aopGet(AOP(result),0,TRUE,FALSE)); + pic16_emitcode("mov","b,%s + 1",pic16_aopGet(AOP(result),0,TRUE,FALSE)); + } + else { /* we need to get it byte by byte */ + //char *l = pic16_aopGet(AOP(result),0,FALSE,FALSE); + size = AOP_SIZE(right); + offset = 0 ; + + /* hack hack! see if this the FSR. If so don't load W */ + if(AOP_TYPE(right) != AOP_ACC) { + + + pic16_emitpcode(POC_MOVFW,pic16_popGet(AOP(result),0)); + pic16_emitpcode(POC_MOVWF,pic16_popCopyReg(&pic16_pc_fsr0)); + + if(AOP_SIZE(result) > 1) { + pic16_emitpcode(POC_BCF, pic16_popCopyGPR2Bit(PCOP(&pic16_pc_status),PIC_IRP_BIT)); + pic16_emitpcode(POC_BTFSC,pic16_newpCodeOpBit(pic16_aopGet(AOP(result),1,FALSE,FALSE),0,0)); + pic16_emitpcode(POC_BSF, pic16_popCopyGPR2Bit(PCOP(&pic16_pc_status),PIC_IRP_BIT)); + + } + + //if(size==2) + //pic16_emitpcode(POC_DECF,pic16_popCopyReg(&pic16_pc_fsr0)); + //if(size==4) { + // pic16_emitpcode(POC_MOVLW,pic16_popGetLit(0xfd)); + // pic16_emitpcode(POC_ADDWF,pic16_popCopyReg(&pic16_pc_fsr0)); + //} + + while(size--) { + pic16_emitpcode(POC_MOVFW,pic16_popGet(AOP(right),offset++)); + pic16_emitpcode(POC_MOVWF,pic16_popCopyReg(&pic16_pc_indf0)); + + if(size) + pic16_emitpcode(POC_INCF,pic16_popCopyReg(&pic16_pc_fsr0)); + } + + + goto release; + } + + if(aopIdx(AOP(result),0) != 4) { + + pic16_emitpcode(POC_MOVWF,pic16_popCopyReg(&pic16_pc_indf0)); + goto release; + } + + pic16_emitpcode(POC_MOVWF,pic16_popCopyReg(&pic16_pc_indf0)); + goto release; + + } + } + /* so dptr know contains the address */ + + + /* if bit then unpack */ + if (IS_BITVAR(retype)) + genPackBits(retype,right,"dptr",GPOINTER); + else { + size = AOP_SIZE(right); + offset = 0 ; + + DEBUGpic16_emitcode ("; ***","%s %d size=%d",__FUNCTION__,__LINE__,size); + + while (size--) { + + pic16_emitpcode(POC_MOVFW,pic16_popGet(AOP(result),offset)); + pic16_emitpcode(POC_MOVWF,pic16_popCopyReg(&pic16_pc_fsr0)); + + if (AOP_TYPE(right) == AOP_LIT) + pic16_emitpcode(POC_MOVLW, pic16_popGet(AOP(right),offset)); + else + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(right),offset)); + + pic16_emitpcode(POC_MOVWF,pic16_popCopyReg(&pic16_pc_indf0)); + + offset++; + } + } + + 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; + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + right = IC_RIGHT(ic); + result = IC_RESULT(ic) ; + + /* depending on the type of pointer we need to + move it to the correct pointer register */ + type = operandType(result); + etype = getSpec(type); + /* if left is of type of pointer then it is simple */ + if (IS_PTR(type) && !IS_FUNC(type->next)) { + p_type = DCL_TYPE(type); + } + else { + /* we have to go by the storage class */ + p_type = PTR_TYPE(SPEC_OCLS(etype)); + +/* if (SPEC_OCLS(etype)->codesp ) { */ +/* p_type = CPOINTER ; */ +/* } */ +/* else */ +/* if (SPEC_OCLS(etype)->fmap && !SPEC_OCLS(etype)->paged) */ +/* p_type = FPOINTER ; */ +/* else */ +/* if (SPEC_OCLS(etype)->fmap && SPEC_OCLS(etype)->paged) */ +/* p_type = PPOINTER ; */ +/* else */ +/* if (SPEC_OCLS(etype) == idata ) */ +/* p_type = IPOINTER ; */ +/* else */ +/* p_type = POINTER ; */ + } + + /* now that we have the pointer type we assign + the pointer values */ + switch (p_type) { + + case POINTER: + case IPOINTER: + genNearPointerSet (right,result,ic); + break; + + case PPOINTER: + genPagedPointerSet (right,result,ic); + break; + + case FPOINTER: + genFarPointerSet (right,result,ic); + break; + + case GPOINTER: + genGenPointerSet (right,result,ic); + break; + + default: + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, + "genPointerSet: illegal pointer type"); + } +} + +/*-----------------------------------------------------------------*/ +/* genIfx - generate code for Ifx statement */ +/*-----------------------------------------------------------------*/ +static void genIfx (iCode *ic, iCode *popIc) +{ + operand *cond = IC_COND(ic); + int isbit =0; + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + 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,SPIL_LOC(cond)->rname); + 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 *right, *result, *left; + int size, offset ; + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + + //pic16_aopOp(IC_RESULT(ic),ic,FALSE); + + 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); + + size = AOP_SIZE(IC_RESULT(ic)); + offset = 0; + + while (size--) { + pic16_emitpcode(POC_MOVLW, pic16_popGet(AOP(left),offset)); + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),offset)); + offset++; + } + + pic16_freeAsmop(left,NULL,ic,FALSE); + pic16_freeAsmop(result,NULL,ic,TRUE); + +} + +#if 0 +/*-----------------------------------------------------------------*/ +/* genFarFarAssign - assignment when both are in far space */ +/*-----------------------------------------------------------------*/ +static void genFarFarAssign (operand *result, operand *right, iCode *ic) +{ + int size = AOP_SIZE(right); + int offset = 0; + char *l ; + /* first push the right side on to the stack */ + while (size--) { + l = pic16_aopGet(AOP(right),offset++,FALSE,FALSE); + MOVA(l); + pic16_emitcode ("push","acc"); + } + + pic16_freeAsmop(right,NULL,ic,FALSE); + /* now assign DPTR to result */ + pic16_aopOp(result,ic,FALSE); + size = AOP_SIZE(result); + while (size--) { + pic16_emitcode ("pop","acc"); + pic16_aopPut(AOP(result),"a",--offset); + } + pic16_freeAsmop(result,NULL,ic,FALSE); + +} +#endif + +/*-----------------------------------------------------------------*/ +/* genAssign - generate code for assignment */ +/*-----------------------------------------------------------------*/ +static void genAssign (iCode *ic) +{ + operand *result, *right; + int size, offset,know_W; + unsigned long lit = 0L; + + result = IC_RESULT(ic); + right = IC_RIGHT(ic) ; + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + /* if they are the same */ + if (operandsEqu (IC_RESULT(ic),IC_RIGHT(ic))) + return ; + + pic16_aopOp(right,ic,FALSE); + pic16_aopOp(result,ic,TRUE); + + 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)); + + pic16_emitcode("bcf","(%s >> 3),(%s & 7)", + AOP(result)->aopu.aop_dir, + AOP(result)->aopu.aop_dir); + pic16_emitcode("btfsc","(%s >> 3),(%s & 7)", + AOP(right)->aopu.aop_dir, + AOP(right)->aopu.aop_dir); + pic16_emitcode("bsf","(%s >> 3),(%s & 7)", + AOP(result)->aopu.aop_dir, + AOP(result)->aopu.aop_dir); + 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 ; + if(AOP_TYPE(right) == AOP_LIT) + lit = (unsigned long)floatFromVal(AOP(right)->aopu.aop_lit); + + 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) { + 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 + DEBUGpic16_emitcode ("; WARNING","%s %d ignoring register storage",__FUNCTION__,__LINE__); + } + + know_W=-1; + while (size--) { + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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; + 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) { + pic16_emitpcode(POC_BTFSS, pic16_popGet(AOP(right),0)); + pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),0)); + } + } else { + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(right),offset)); + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),offset)); + } + + offset++; + } + + + release: + pic16_freeAsmop (right,NULL,ic,FALSE); + pic16_freeAsmop (result,NULL,ic,TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genJumpTab - genrates code for jump table */ +/*-----------------------------------------------------------------*/ +static void genJumpTab (iCode *ic) +{ + symbol *jtab; + char *l; + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + 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_",jtab->key+100); + pic16_emitcode("jmp","@a+dptr"); + pic16_emitcode("","%05d_DS_:",jtab->key+100); + + 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); + + pic16_freeAsmop(IC_JTCOND(ic),NULL,ic,TRUE); + + /* now generate the jump labels */ + for (jtab = setFirstItem(IC_JTLABELS(ic)) ; jtab; + jtab = setNextItem(IC_JTLABELS(ic))) { + pic16_emitcode("ljmp","%05d_DS_",jtab->key+100); + pic16_emitpcode(POC_GOTO,pic16_popGetLabel(jtab->key)); + + } + +} + +/*-----------------------------------------------------------------*/ +/* 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)); + operand *right = IC_RIGHT(ic); + int size, offset ; + + DEBUGpic16_emitcode("; ***","%s %d",__FUNCTION__,__LINE__); + /* if they are equivalent then do nothing */ + if (operandsEqu(IC_RESULT(ic),IC_RIGHT(ic))) + return ; + + pic16_aopOp(right,ic,FALSE) ; + pic16_aopOp(result,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)); + 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 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 (IS_PTR_CONST(rtype)) + DEBUGpic16_emitcode ("; ***","%d - right is const pointer",__LINE__); + if (IS_PTR_CONST(operandType(IC_RESULT(ic)))) + 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)); + pic16_emitpcode(POC_MOVLW, pic16_popGet(AOP(right),1)); + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),1)); + if(AOP_SIZE(result) <2) + fprintf(stderr,"%d -- result is not big enough to hold a ptr\n",__LINE__); + + } else { + + /* if they in different places then copy */ + size = AOP_SIZE(result); + offset = 0 ; + while (size--) { + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(right),offset)); + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),offset)); + + //pic16_aopPut(AOP(result), + // pic16_aopGet(AOP(right),offset,FALSE,FALSE), + // 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)) { + char *l = zero; + + if (IS_PTR(type)) + p_type = DCL_TYPE(type); + else { + /* we have to go by the storage class */ + p_type = PTR_TYPE(SPEC_OCLS(etype)); + +/* if (SPEC_OCLS(etype)->codesp ) */ +/* p_type = CPOINTER ; */ +/* else */ +/* if (SPEC_OCLS(etype)->fmap && !SPEC_OCLS(etype)->paged) */ +/* p_type = FPOINTER ; */ +/* else */ +/* if (SPEC_OCLS(etype)->fmap && SPEC_OCLS(etype)->paged) */ +/* p_type = PPOINTER; */ +/* else */ +/* if (SPEC_OCLS(etype) == idata ) */ +/* p_type = IPOINTER ; */ +/* else */ +/* p_type = POINTER ; */ + } + + /* the first two bytes are known */ + 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",__FUNCTION__,__LINE__); + 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 IPOINTER: + case POINTER: + pic16_emitpcode(POC_CLRF,pic16_popGet(AOP(result),GPTRSIZE - 1)); + break; + case FPOINTER: + pic16_emitcode(";BUG!? ","%d",__LINE__); + l = one; + break; + case CPOINTER: + pic16_emitcode(";BUG!? ","%d",__LINE__); + l = "#0x02"; + break; + case PPOINTER: + pic16_emitcode(";BUG!? ","%d",__LINE__); + l = "#0x03"; + 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 ; + } + + /* 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--) { + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(right),offset)); + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),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(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)); + pic16_emitpcode(POC_DECF, 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)); + else + pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit(pic16_aopGet(AOP(right),offset,FALSE,FALSE),7,0)); + + 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) +{ + symbol *lbl, *lbl1; + 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 */ + lbl = newiTempLabel(NULL); + lbl1= newiTempLabel(NULL); + + pic16_aopOp(IC_RESULT(ic),ic,FALSE); + + if (IS_AOP_PREG(IC_RESULT(ic))) { + pic16_emitcode("dec","%s", + pic16_aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE)); + pic16_emitcode("mov","a,%s",pic16_aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE)); + pic16_emitcode("jnz","%05d_DS_",lbl->key+100); + } else { + + + pic16_emitpcode(POC_DECFSZ,pic16_popGet(AOP(IC_RESULT(ic)),0)); + pic16_emitpcode(POC_GOTO,pic16_popGetLabel(IC_TRUE(ifx)->key)); + + pic16_emitcode("decfsz","%s,f",pic16_aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE)); + pic16_emitcode ("goto","_%05d_DS_",IC_TRUE(ifx)->key+100 + labelOffset); + + } +/* pic16_emitcode ("sjmp","%05d_DS_",lbl1->key+100); */ +/* pic16_emitcode ("","%05d_DS_:",lbl->key+100); */ +/* pic16_emitcode ("ljmp","%05d_DS_",IC_TRUE(ifx)->key+100); */ +/* pic16_emitcode ("","%05d_DS_:",lbl1->key+100); */ + + + 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) +{ + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + if (isOperandInFarSpace(IC_RESULT(ic)) && + ( OP_SYMBOL(IC_RESULT(ic))->isspilt || + IS_TRUE_SYMOP(IC_RESULT(ic))) ) { + + int size = getSize(operandType(IC_RESULT(ic))); + int offset = pic16_fReturnSizePic - size; + while (size--) { + pic16_emitcode ("push","%s", (strcmp(fReturn[pic16_fReturnSizePic - offset - 1],"a") ? + fReturn[pic16_fReturnSizePic - offset - 1] : "acc")); + offset++; + } + 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 { + _G.accInUse++; + pic16_aopOp(IC_RESULT(ic),ic,FALSE); + _G.accInUse--; + assignResultValue(IC_RESULT(ic)); + } + + pic16_freeAsmop(IC_RESULT(ic),NULL,ic,TRUE); +} + +/*-----------------------------------------------------------------*/ +/* 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; + + lineHead = lineCurr = NULL; + + pb = pic16_newpCodeChain(GcurMemmap,0,pic16_newpCodeCharP("; Starting pCode block")); + pic16_addpBlock(pb); + + /* if debug information required */ + if (options.debug && currFunc) { + if (currFunc) { + cdbSymbol(currFunc,cdbFile,FALSE,TRUE); + _G.debugLine = 1; + if (IS_STATIC(currFunc->etype)) { + pic16_emitcode("",";F%s$%s$0$0 %d",moduleName,currFunc->name,__LINE__); + //pic16_addpCode2pBlock(pb,pic16_newpCodeLabel(moduleName,currFunc->name)); + } else { + pic16_emitcode("",";G$%s$0$0 %d",currFunc->name,__LINE__); + //pic16_addpCode2pBlock(pb,pic16_newpCodeLabel(NULL,currFunc->name)); + } + _G.debugLine = 0; + } + } + + + for (ic = lic ; ic ; ic = ic->next ) { + + DEBUGpic16_emitcode(";ic",""); + if ( cln != ic->lineno ) { + if ( options.debug ) { + _G.debugLine = 1; + pic16_emitcode("",";C$%s$%d$%d$%d ==.", + FileBaseName(ic->filename),ic->lineno, + ic->level,ic->block); + _G.debugLine = 0; + } + /* + pic16_emitcode("#CSRC","%s %d",FileBaseName(ic->filename),ic->lineno); + pic16_emitcode ("", ";\t%s:%d: %s", ic->filename, ic->lineno, + printCLine(ic->filename, ic->lineno)); + */ + pic16_addpCode2pBlock(pb, + pic16_newpCodeCSource(ic->lineno, + ic->filename, + printCLine(ic->filename, ic->lineno))); + + cln = ic->lineno ; + } + /* if the result is marked as + spilt and rematerializable or code for + this has already been generated then + do nothing */ + if (resultRemat(ic) || ic->generated ) + continue ; + + /* depending on the operation */ + switch (ic->op) { + case '!' : + genNot(ic); + break; + + case '~' : + genCpl(ic); + break; + + case UNARYMINUS: + genUminus (ic); + break; + + case IPUSH: + genIpush (ic); + break; + + case IPOP: + /* IPOP happens only when trying to restore a + spilt live range, if there is an ifx statement + following this pop then the if statement might + be using some of the registers being popped which + would 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: + genInline (ic); + break; + + case RRC: + genRRC (ic); + break; + + case RLC: + genRLC (ic); + break; + + case GETHBIT: + genGetHbit (ic); + break; + + case LEFT_OP: + genLeftShift (ic); + break; + + case RIGHT_OP: + genRightShift (ic); + break; + + case GET_VALUE_AT_ADDRESS: + genPointerGet(ic); + break; + + case '=' : + if (POINTER_SET(ic)) + genPointerSet(ic); + else + genAssign(ic); + break; + + case IFX: + genIfx (ic,NULL); + break; + + case ADDRESS_OF: + genAddrOf (ic); + break; + + case JUMPTABLE: + genJumpTab (ic); + break; + + case CAST: + genCast (ic); + break; + + case RECEIVE: + genReceive(ic); + break; + + case SEND: + addSet(&_G.sendSet,ic); + break; + + default : + ic = ic; + } + } + + + /* now we are ready to call the + peep hole optimizer */ + if (!options.nopeep) { + peepHole (&lineHead); + } + /* now do the actual printing */ + printLine (lineHead,codeOutFile); + +#ifdef PCODE_DEBUG + DFPRINTF((stderr,"printing pBlock\n\n")); + pic16_printpBlock(stdout,pb); +#endif + + return; +} diff --git a/src/pic16/gen.h b/src/pic16/gen.h new file mode 100644 index 00000000..8b72f5da --- /dev/null +++ b/src/pic16/gen.h @@ -0,0 +1,181 @@ +/*------------------------------------------------------------------------- + SDCCgen51.h - header file for code generation for 8051 + + Written By - Sandeep Dutta . sandeep.dutta@usa.net (1998) + PIC port - T. Scott Dattalo scott@dattalo.com (2000) + PIC16 port - Martin Dubuc m.dubuc@rogers.com (2000) + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! +-------------------------------------------------------------------------*/ + +#ifndef SDCCGENPIC14_H +#define SDCCGENPIC14_H + +struct pCodeOp; + +enum + { + AOP_LIT = 1, + AOP_REG, AOP_DIR, + AOP_DPTR, AOP_DPTR2, AOP_R0, AOP_R1, + AOP_STK, AOP_IMMD, AOP_STR, + AOP_CRY, AOP_ACC, + AOP_PCODE + + }; + +/* type asmop : a homogenised type for + all the different spaces an operand can be + in */ +typedef struct asmop + { + + short type; /* can have values + AOP_LIT - operand is a literal value + AOP_REG - is in registers + AOP_DIR - direct just a name + AOP_DPTR - dptr contains address of operand + AOP_DPTR2 - dptr2 contains address of operand (DS80C390 only). + AOP_R0/R1 - r0/r1 contains address of operand + AOP_STK - should be pushed on stack this + can happen only for the result + AOP_IMMD - immediate value for eg. remateriazable + AOP_CRY - carry contains the value of this + AOP_STR - array of strings + AOP_ACC - result is in the acc:b pair + */ + short coff; /* current offset */ + short size; /* total size */ + unsigned code:1; /* is in Code space */ + unsigned paged:1; /* in paged memory */ + unsigned freed:1; /* already freed */ + union + { + value *aop_lit; /* if literal */ + regs *aop_reg[4]; /* array of registers */ + char *aop_dir; /* if direct */ + regs *aop_ptr; /* either -> to r0 or r1 */ + char *aop_immd; /* if immediate others are implied */ + int aop_stk; /* stack offset when AOP_STK */ + char *aop_str[4]; /* just a string array containing the location */ +/* regs *aop_alloc_reg; * points to a dynamically allocated register */ + pCodeOp *pcop; + } + aopu; + } +asmop; + +void genpic16Code (iCode *); + +//extern char *fReturnpic16[]; +//extern char *fReturn390[]; +extern unsigned pic16_fReturnSizePic; +//extern char **fReturn; + + +#define AOP(op) op->aop +#define AOP_TYPE(op) AOP(op)->type +#define AOP_SIZE(op) AOP(op)->size +#define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_R1 || \ + AOP_TYPE(x) == AOP_R0)) + +#define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY || \ + AOP_TYPE(x) == AOP_DPTR || AOP_TYPE(x) == AOP_DPTR2 || \ + AOP(x)->paged)) + +#define AOP_INPREG(x) (x && (x->type == AOP_REG && \ + (x->aopu.aop_reg[0] == pic16_regWithIdx(R0_IDX) || \ + x->aopu.aop_reg[0] == pic16_regWithIdx(R1_IDX) ))) + +#define RESULTONSTACK(x) \ + (IC_RESULT(x) && IC_RESULT(x)->aop && \ + IC_RESULT(x)->aop->type == AOP_STK ) + +#define MOVA(x) if (strcmp(x,"a") && strcmp(x,"acc")) pic16_emitcode(";XXX mov","a,%s %s,%d",x,__FILE__,__LINE__); +#define CLRC pic16_emitcode(";XXX clr","c %s,%d",__FILE__,__LINE__); + +#define BIT_NUMBER(x) (x & 7) +#define BIT_REGISTER(x) (x>>3) + + +#define LSB 0 +#define MSB16 1 +#define MSB24 2 +#define MSB32 3 + + +#define FUNCTION_LABEL_INC 40 + +/*-----------------------------------------------------------------*/ +/* Macros for emitting skip instructions */ +/*-----------------------------------------------------------------*/ + +#define emitSKPC pic16_emitpcode(POC_BTFSS,pic16_popCopyGPR2Bit(PCOP(&pic16_pc_status),PIC_C_BIT)) +#define emitSKPNC pic16_emitpcode(POC_BTFSC,pic16_popCopyGPR2Bit(PCOP(&pic16_pc_status),PIC_C_BIT)) +#define emitSKPZ pic16_emitpcode(POC_BTFSS,pic16_popCopyGPR2Bit(PCOP(&pic16_pc_status),PIC_Z_BIT)) +#define emitSKPNZ pic16_emitpcode(POC_BTFSC,pic16_popCopyGPR2Bit(PCOP(&pic16_pc_status),PIC_Z_BIT)) +#define emitSKPDC pic16_emitpcode(POC_BTFSS,pic16_popCopyGPR2Bit(PCOP(&pic16_pc_status),PIC_DC_BIT)) +#define emitSKPNDC pic16_emitpcode(POC_BTFSC,pic16_popCopyGPR2Bit(PCOP(&pic16_pc_status),PIC_DC_BIT)) +#define emitCLRZ pic16_emitpcode(POC_BCF, pic16_popCopyGPR2Bit(PCOP(&pic16_pc_status),PIC_Z_BIT)) +#define emitCLRC pic16_emitpcode(POC_BCF, pic16_popCopyGPR2Bit(PCOP(&pic16_pc_status),PIC_C_BIT)) +#define emitCLRDC pic16_emitpcode(POC_BCF, pic16_popCopyGPR2Bit(PCOP(&pic16_pc_status),PIC_DC_BIT)) +#define emitSETZ pic16_emitpcode(POC_BSF, pic16_popCopyGPR2Bit(PCOP(&pic16_pc_status),PIC_Z_BIT)) +#define emitSETC pic16_emitpcode(POC_BSF, pic16_popCopyGPR2Bit(PCOP(&pic16_pc_status),PIC_C_BIT)) +#define emitSETDC pic16_emitpcode(POC_BSF, pic16_popCopyGPR2Bit(PCOP(&pic16_pc_status),PIC_DC_BIT)) + +int pic16_getDataSize(operand *op); +void pic16_emitpcode(PIC_OPCODE poc, pCodeOp *pcop); +void pic16_emitpLabel(int key); +void pic16_emitcode (char *inst,char *fmt, ...); +void DEBUGpic16_emitcode (char *inst,char *fmt, ...); +bool pic16_sameRegs (asmop *aop1, asmop *aop2 ); +char *pic16_aopGet (asmop *aop, int offset, bool bit16, bool dname); + + +bool pic16_genPlusIncr (iCode *ic); +void pic16_outBitAcc(operand *result); +void pic16_genPlusBits (iCode *ic); +void pic16_genPlus (iCode *ic); +bool pic16_genMinusDec (iCode *ic); +void pic16_addSign(operand *result, int offset, int sign); +void pic16_genMinusBits (iCode *ic); +void pic16_genMinus (iCode *ic); + + +pCodeOp *pic16_popGetLabel(unsigned int key); +pCodeOp *pic16_popCopyReg(pCodeOpReg *pc); +pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval); +pCodeOp *pic16_popGetLit(unsigned int lit); +pCodeOp *popGetWithString(char *str); +pCodeOp *pic16_popGet (asmop *aop, int offset);//, bool bit16, bool dname); +pCodeOp *pic16_popGetTempReg(void); +void pic16_popReleaseTempReg(pCodeOp *pcop); + + +void pic16_aopPut (asmop *aop, char *s, int offset); +void pic16_outAcc(operand *result); +void pic16_aopOp (operand *op, iCode *ic, bool result); +void pic16_outBitC(operand *result); +void pic16_toBoolean(operand *oper); +void pic16_freeAsmop (operand *op, asmop *aaop, iCode *ic, bool pop); +const char *pic16_pCodeOpType( pCodeOp *pcop); + + + +#endif diff --git a/src/pic16/genarith.c b/src/pic16/genarith.c new file mode 100644 index 00000000..0c8f6ff3 --- /dev/null +++ b/src/pic16/genarith.c @@ -0,0 +1,1971 @@ +/*------------------------------------------------------------------------- + genarith.c - source file for code generation - arithmetic + + Written By - Sandeep Dutta . sandeep.dutta@usa.net (1998) + and - Jean-Louis VERN.jlvern@writeme.com (1999) + Bug Fixes - Wojciech Stryjewski wstryj1@tiger.lsu.edu (1999 v2.1.9a) + PIC port - Scott Dattalo scott@dattalo.com (2000) + PIC16 port - Martin Dubuc m.dubuc@rogers.com (2002) + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! + + Notes: + 000123 mlh Moved aopLiteral to SDCCglue.c to help the split + Made everything static +-------------------------------------------------------------------------*/ + +#include +#include +#include +#include +#include "SDCCglobl.h" +#include "newalloc.h" + +#if defined(_MSC_VER) && (_MSC_VER < 1300) +#define __FUNCTION__ __FILE__ +#endif + +#ifdef HAVE_SYS_ISA_DEFS_H +#include +#else +#ifdef HAVE_MACHINE_ENDIAN_H +#include +#else +#ifdef HAVE_ENDIAN_H +#include +#else +#if !defined(__BORLANDC__) && !defined(_MSC_VER) && !defined(__MINGW32__) && !defined(__CYGWIN__) +#warning "Cannot determine ENDIANESS of this machine assuming LITTLE_ENDIAN" +#warning "If you running sdcc on an INTEL 80x86 Platform you are okay" +#endif +#endif +#endif +#endif + +#include "common.h" +#include "SDCCpeeph.h" +#include "ralloc.h" +#include "pcode.h" +#include "gen.h" + + +#define BYTEofLONG(l,b) ( (l>> (b<<3)) & 0xff) +void DEBUGpic16_pic16_AopType(int line_no, operand *left, operand *right, operand *result); + +const char *pic16_AopType(short type) +{ + switch(type) { + case AOP_LIT: + return "AOP_LIT"; + break; + case AOP_REG: + return "AOP_REG"; + break; + case AOP_DIR: + return "AOP_DIR"; + break; + case AOP_DPTR: + return "AOP_DPTR"; + break; + case AOP_DPTR2: + return "AOP_DPTR2"; + break; + case AOP_R0: + return "AOP_R0"; + break; + case AOP_R1: + return "AOP_R1"; + break; + case AOP_STK: + return "AOP_STK"; + break; + case AOP_IMMD: + return "AOP_IMMD"; + break; + case AOP_STR: + return "AOP_STR"; + break; + case AOP_CRY: + return "AOP_CRY"; + break; + case AOP_ACC: + return "AOP_ACC"; + break; + case AOP_PCODE: + return "AOP_PCODE"; + break; + } + + 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_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"; + } + } + + 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)); + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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 1 then it is faster to add */ + if ((icount = (unsigned int) floatFromVal (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 = MSB16; + + pic16_emitpcode(POC_INCF, pic16_popGet(AOP(IC_RESULT(ic)),LSB)); + //pic16_emitcode("incf","%s,f",pic16_aopGet(AOP(IC_RESULT(ic)),LSB,FALSE,FALSE)); + + while(--size) { + emitSKPNZ; + pic16_emitpcode(POC_INCF, pic16_popGet(AOP(IC_RESULT(ic)),offset++)); + //pic16_emitcode(" incf","%s,f",pic16_aopGet(AOP(IC_RESULT(ic)),offset++,FALSE,FALSE)); + } + + return TRUE; + } + + DEBUGpic16_emitcode ("; ","%s %d",__FUNCTION__,__LINE__); + /* if left is in accumulator - probably a bit operation*/ + if( strcmp(pic16_aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE),"a") && + (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY) ) { + + pic16_emitpcode(POC_BCF, pic16_popGet(AOP(IC_RESULT(ic)),0)); + pic16_emitcode("bcf","(%s >> 3), (%s & 7)", + AOP(IC_RESULT(ic))->aopu.aop_dir, + AOP(IC_RESULT(ic))->aopu.aop_dir); + 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)); + pic16_emitcode("bsf","(%s >> 3), (%s & 7)", + AOP(IC_RESULT(ic))->aopu.aop_dir, + AOP(IC_RESULT(ic))->aopu.aop_dir); + + 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__); + + 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) +{ + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + 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)); + + pic16_emitcode("clrw",""); + pic16_emitcode("btfsc","(%s >> 3), (%s & 7)", + AOP(IC_RIGHT(ic))->aopu.aop_dir, + AOP(IC_RIGHT(ic))->aopu.aop_dir); + pic16_emitcode("xorlw","1"); + pic16_emitcode("btfsc","(%s >> 3), (%s & 7)", + AOP(IC_LEFT(ic))->aopu.aop_dir, + AOP(IC_LEFT(ic))->aopu.aop_dir); + pic16_emitcode("xorlw","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)); + + pic16_emitcode("movlw","(1 << (%s & 7))", + AOP(IC_RESULT(ic))->aopu.aop_dir, + AOP(IC_RESULT(ic))->aopu.aop_dir); + pic16_emitcode("bcf","(%s >> 3), (%s & 7)", + AOP(IC_RESULT(ic))->aopu.aop_dir, + AOP(IC_RESULT(ic))->aopu.aop_dir); + pic16_emitcode("btfsc","(%s >> 3), (%s & 7)", + AOP(IC_RIGHT(ic))->aopu.aop_dir, + AOP(IC_RIGHT(ic))->aopu.aop_dir); + pic16_emitcode("xorwf","(%s >>3),f", + AOP(IC_RESULT(ic))->aopu.aop_dir); + pic16_emitcode("btfsc","(%s >> 3), (%s & 7)", + AOP(IC_LEFT(ic))->aopu.aop_dir, + AOP(IC_LEFT(ic))->aopu.aop_dir); + pic16_emitcode("xorwf","(%s>>3),f", + AOP(IC_RESULT(ic))->aopu.aop_dir); + 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]; + sprintf(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]; + sprintf(buffer,"#%d",pointerCode(getSpec(operandType(IC_LEFT(ic))))); + pic16_aopPut(AOP(IC_RESULT(ic)),buffer,GPTRSIZE - 1); + } +} +#endif + +/*-----------------------------------------------------------------*/ +/* genAddlit - generates code for addition */ +/*-----------------------------------------------------------------*/ +static void genAddLit2byte (operand *result, int offr, int lit) +{ + + 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: + pic16_emitpcode(POC_MOVLW,pic16_popGetLit(lit&0xff)); + pic16_emitpcode(POC_ADDWF,pic16_popGet(AOP(result),offr)); + } + +} + +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)); + +} + +static void genAddLit (iCode *ic, int lit) +{ + + int size,same; + int lo; + + operand *result; + operand *left; + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + + left = IC_LEFT(ic); + result = IC_RESULT(ic); + same = pic16_sameRegs(AOP(left), AOP(result)); + size = pic16_getDataSize(result); + + 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_INCF, pic16_popGet(AOP(result),0)); + emitSKPNZ; + 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; + + 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_MOVLW,pic16_popGetLit((hi+1)&0xff)); + pic16_emitpcode(POC_INCFSZ, pic16_popGet(AOP(result),0)); + pic16_emitpcode(POC_MOVLW,pic16_popGetLit(hi)); + pic16_emitpcode(POC_ADDWF,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)); + emitSKPNC; + pic16_emitpcode(POC_MOVLW,pic16_popGetLit((hi+1) & 0xff)); + pic16_emitpcode(POC_ADDWF,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) { + switch(lo) { + case 0: + switch(carry_info) { + case 1: + emitSKPNZ; + pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),offset)); + break; + case 2: + pic16_emitpcode(POC_RLCFW, pic16_popGet(AOP(result),offset)); + pic16_emitpcode(POC_ANDLW, pic16_popGetLit(1)); + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(result),offset)); + break; + default: /* carry_info = 3 */ + emitSKPNC; + pic16_emitpcode(POC_INCF, pic16_popGet(AOP(result),offset)); + carry_info = 1; + break; + } + break; + case 0xff: + pic16_emitpcode(POC_MOVLW,pic16_popGetLit(lo)); + if(carry_info==1) + emitSKPZ; + else + emitSKPC; + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(result),offset)); + break; + default: + pic16_emitpcode(POC_MOVLW,pic16_popGetLit(lo)); + if(carry_info==1) + emitSKPNZ; + else + emitSKPNC; + pic16_emitpcode(POC_MOVLW,pic16_popGetLit(lo+1)); + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(result),offset)); + carry_info=2; + break; + } + }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_emitpcode(POC_MOVFW, pic16_popGet(AOP(left),0)); + emitMOVWF(result, 0); + //pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),0,FALSE,FALSE)); + 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_emitpcode(POC_MOVFW, pic16_popGet(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(left),offset)); + + clear_carry = 0; + + } else { + pic16_emitpcode(POC_MOVLW, pic16_popGetLit(lit & 0xff)); + //pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),offset,FALSE,FALSE)); + emitMOVWF(result,offset); + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(left),offset)); + emitSKPNC; + pic16_emitpcode(POC_INCFSZW,pic16_popGet(AOP(left),offset)); + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(result),offset)); + } + + } else { + pic16_emitpcode(POC_CLRF, pic16_popGet(AOP(result),offset)); + pic16_emitpcode(POC_RLCF, pic16_popGet(AOP(result),offset)); + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(left),offset)); + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(result),offset)); + } + offset++; + } + } + } +} + +/*-----------------------------------------------------------------*/ +/* pic16_genPlus - generates code for addition */ +/*-----------------------------------------------------------------*/ +void pic16_genPlus (iCode *ic) +{ + int size, offset = 0; + + /* special cases :- */ + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + pic16_aopOp (IC_LEFT(ic),ic,FALSE); + pic16_aopOp (IC_RIGHT(ic),ic,FALSE); + pic16_aopOp (IC_RESULT(ic),ic,TRUE); + + DEBUGpic16_pic16_AopType(__LINE__,IC_LEFT(ic),IC_RIGHT(ic),IC_RESULT(ic)); + + /* if literal, literal on the right or + if left requires ACC or right is already + in ACC */ + + if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) { + operand *t = IC_RIGHT(ic); + IC_RIGHT(ic) = IC_LEFT(ic); + IC_LEFT(ic) = t; + } + + /* if both left & right are in bit space */ + if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY && + AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) { + pic16_genPlusBits (ic); + goto release ; + } + + /* if left in bit space & right literal */ + if (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY && + AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT) { + /* if result in bit space */ + if(AOP_TYPE(IC_RESULT(ic)) == AOP_CRY){ + if((unsigned long)floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit) != 0L) { + pic16_emitpcode(POC_MOVLW, pic16_popGet(AOP(IC_RESULT(ic)),0)); + if (!pic16_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) + pic16_emitpcode(POC_BTFSC, pic16_popGet(AOP(IC_LEFT(ic)),0)); + pic16_emitpcode(POC_XORWF, pic16_popGet(AOP(IC_RESULT(ic)),0)); + } + } else { + size = pic16_getDataSize(IC_RESULT(ic)); + while (size--) { + MOVA(pic16_aopGet(AOP(IC_RIGHT(ic)),offset,FALSE,FALSE)); + pic16_emitcode("addc","a,#00 ;%d",__LINE__); + pic16_aopPut(AOP(IC_RESULT(ic)),"a",offset++); + } + } + goto release ; + } + + /* if I can do an increment instead + of add then GOOD for ME */ + if (pic16_genPlusIncr (ic) == TRUE) + goto release; + + size = pic16_getDataSize(IC_RESULT(ic)); + + if(AOP(IC_RIGHT(ic))->type == AOP_LIT) { + /* Add a literal to something else */ + //bool know_W=0; + unsigned lit = (unsigned) floatFromVal(AOP(IC_RIGHT(ic))->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(IC_RIGHT(ic)) == AOP_CRY) { + + pic16_emitcode(";bitadd","right is bit: %s",pic16_aopGet(AOP(IC_RIGHT(ic)),0,FALSE,FALSE)); + pic16_emitcode(";bitadd","left is bit: %s",pic16_aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE)); + pic16_emitcode(";bitadd","result is bit: %s",pic16_aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE)); + + /* here we are adding a bit to 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_INCF , pic16_popGet(AOP(IC_RESULT(ic)),0)); + + pic16_emitcode("btfsc","(%s >> 3), (%s & 7)", + AOP(IC_RIGHT(ic))->aopu.aop_dir, + AOP(IC_RIGHT(ic))->aopu.aop_dir); + pic16_emitcode(" incf","%s,f", pic16_aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE)); + } 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)); + + pic16_emitcode("btfsc","(%s >> 3), (%s & 7)", + AOP(IC_RIGHT(ic))->aopu.aop_dir, + AOP(IC_RIGHT(ic))->aopu.aop_dir); + pic16_emitcode(" xorlw","1"); + } else { + pic16_emitpcode(POC_MOVFW , pic16_popGet(AOP(IC_LEFT(ic)),0)); + pic16_emitpcode(POC_BTFSC , pic16_popGet(AOP(IC_RIGHT(ic)),0)); + pic16_emitpcode(POC_INCFW , pic16_popGet(AOP(IC_LEFT(ic)),0)); + + pic16_emitcode("movf","%s,w", pic16_aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE)); + pic16_emitcode("btfsc","(%s >> 3), (%s & 7)", + AOP(IC_RIGHT(ic))->aopu.aop_dir, + AOP(IC_RIGHT(ic))->aopu.aop_dir); + pic16_emitcode(" incf","%s,w", pic16_aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE)); + } + + if(AOP_TYPE(IC_RESULT(ic)) != AOP_ACC) { + + if(AOP_TYPE(IC_RESULT(ic)) == AOP_CRY) { + pic16_emitpcode(POC_ANDLW , pic16_popGetLit(1)); + 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_emitcode("movwf","%s", pic16_aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE)); + } + } + } + + } else { + int offset = 1; + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + if (pic16_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) { + emitCLRZ; + pic16_emitpcode(POC_BTFSC, pic16_popGet(AOP(IC_RIGHT(ic)),0)); + pic16_emitpcode(POC_INCF, pic16_popGet(AOP(IC_RESULT(ic)),0)); + + pic16_emitcode("clrz",""); + + pic16_emitcode("btfsc","(%s >> 3), (%s & 7)", + AOP(IC_RIGHT(ic))->aopu.aop_dir, + AOP(IC_RIGHT(ic))->aopu.aop_dir); + pic16_emitcode(" incf","%s,f", pic16_aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE)); + + } else { + + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(IC_LEFT(ic)),0)); + pic16_emitpcode(POC_BTFSC, pic16_popGet(AOP(IC_RIGHT(ic)),0)); + pic16_emitpcode(POC_INCFW, pic16_popGet(AOP(IC_LEFT(ic)),0)); + //pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(IC_RIGHT(ic)),0,FALSE,FALSE)); + emitMOVWF(IC_RIGHT(ic),0); + + pic16_emitcode("movf","%s,w", pic16_aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE)); + pic16_emitcode("btfsc","(%s >> 3), (%s & 7)", + AOP(IC_RIGHT(ic))->aopu.aop_dir, + AOP(IC_RIGHT(ic))->aopu.aop_dir); + pic16_emitcode(" incf","%s,w", pic16_aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE)); + pic16_emitcode("movwf","%s", pic16_aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE)); + + } + + while(--size){ + emitSKPZ; + pic16_emitpcode(POC_INCF, pic16_popGet(AOP(IC_RESULT(ic)),offset++)); + //pic16_emitcode(" incf","%s,f", pic16_aopGet(AOP(IC_RIGHT(ic)),offset++,FALSE,FALSE)); + } + + } + + } else { + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + + /* Add the first bytes */ + + if(strcmp(pic16_aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE),"a") == 0 ) { + pic16_emitpcode(POC_ADDFW, pic16_popGet(AOP(IC_RIGHT(ic)),0)); + pic16_emitpcode(POC_MOVWF,pic16_popGet(AOP(IC_RESULT(ic)),0)); + } else { + + if ( AOP_TYPE(IC_LEFT(ic)) == AOP_ACC) { + pic16_emitpcode(POC_ADDFW, pic16_popGet(AOP(IC_RIGHT(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_MOVFW,pic16_popGet(AOP(IC_RIGHT(ic)),0)); + + if (pic16_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(IC_LEFT(ic)),0)); + else { + PIC_OPCODE poc = POC_ADDFW; + + if ((AOP_TYPE(IC_LEFT(ic)) == AOP_PCODE) && ( + (AOP(IC_LEFT(ic))->aopu.pcop->type == PO_LITERAL) || + (AOP(IC_LEFT(ic))->aopu.pcop->type == PO_IMMEDIATE))) + poc = POC_ADDLW; + pic16_emitpcode(poc, 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)); + } + } + } + + size = min( AOP_SIZE(IC_RESULT(ic)), AOP_SIZE(IC_RIGHT(ic))) - 1; + offset = 1; + + + while(size--){ + if (!pic16_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) { + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(IC_LEFT(ic)),offset)); + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(IC_RESULT(ic)),offset)); + + pic16_emitcode("movf","%s,w", pic16_aopGet(AOP(IC_LEFT(ic)),offset,FALSE,FALSE)); + pic16_emitcode("movwf","%s", pic16_aopGet(AOP(IC_RESULT(ic)),offset,FALSE,FALSE)); + } + + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(IC_RIGHT(ic)),offset)); + emitSKPNC; + pic16_emitpcode(POC_INCFSZW, pic16_popGet(AOP(IC_RIGHT(ic)),offset)); + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(IC_RESULT(ic)),offset)); + + /* + pic16_emitcode("movf","%s,w", pic16_aopGet(AOP(IC_RIGHT(ic)),offset,FALSE,FALSE)); + emitSKPNC; + pic16_emitcode("incfsz","%s,w",pic16_aopGet(AOP(IC_RIGHT(ic)),offset,FALSE,FALSE)); + pic16_emitcode("addwf","%s,f", pic16_aopGet(AOP(IC_RESULT(ic)),offset,FALSE,FALSE)); + */ + + offset++; + } + + } + + if (AOP_SIZE(IC_RESULT(ic)) > AOP_SIZE(IC_RIGHT(ic))) { + int sign = !(SPEC_USIGN(getSpec(operandType(IC_LEFT(ic)))) | + SPEC_USIGN(getSpec(operandType(IC_RIGHT(ic)))) ); + + + /* Need to extend result to higher bytes */ + size = AOP_SIZE(IC_RESULT(ic)) - AOP_SIZE(IC_RIGHT(ic)) - 1; + + /* First grab the carry from the lower bytes */ + pic16_emitpcode(POC_CLRF, pic16_popGet(AOP(IC_RESULT(ic)),offset)); + pic16_emitpcode(POC_RLCF, pic16_popGet(AOP(IC_RESULT(ic)),offset)); + + + if(sign) { + /* Now this is really horrid. Gotta check the sign of the addends and propogate + * to the result */ + + pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit(pic16_aopGet(AOP(IC_LEFT(ic)),offset-1,FALSE,FALSE),7,0)); + pic16_emitpcode(POC_DECF, pic16_popGet(AOP(IC_RESULT(ic)),offset)); + pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit(pic16_aopGet(AOP(IC_RIGHT(ic)),offset-1,FALSE,FALSE),7,0)); + pic16_emitpcode(POC_DECF, pic16_popGet(AOP(IC_RESULT(ic)),offset)); + + /* if chars or ints or being signed extended to longs: */ + if(size) { + pic16_emitpcode(POC_MOVLW, pic16_popGetLit(0)); + pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit(pic16_aopGet(AOP(IC_RESULT(ic)),offset,FALSE,FALSE),7,0)); + pic16_emitpcode(POC_MOVLW, pic16_popGetLit(0xff)); + } + } + + offset++; + while(size--) { + + if(sign) + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(IC_RESULT(ic)),offset)); + else + pic16_emitpcode(POC_CLRF, 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); +} + +/*-----------------------------------------------------------------*/ +/* pic16_genMinusDec :- does subtraction with decrement if possible */ +/*-----------------------------------------------------------------*/ +bool pic16_genMinusDec (iCode *ic) +{ + unsigned int icount ; + unsigned int size = pic16_getDataSize(IC_RESULT(ic)); + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + /* will try to generate an increment */ + /* if the right side is not a literal + we cannot */ + if ((AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT) || + (AOP_TYPE(IC_LEFT(ic)) == AOP_CRY) || + (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY) ) + return FALSE ; + + DEBUGpic16_emitcode ("; lit val","%d",(unsigned int) floatFromVal (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) floatFromVal (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)); + pic16_emitpcode(POC_INCFSZW, pic16_popGet(AOP(IC_RESULT(ic)),LSB)); + pic16_emitpcode(POC_INCF, pic16_popGet(AOP(IC_RESULT(ic)),MSB16)); + 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_MOVLW, pic16_popGetLit(0xff)); + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(IC_RESULT(ic)),LSB)); + emitSKPNC; + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(IC_RESULT(ic)),MSB16)); + emitSKPNC; + pic16_emitpcode(POC_ADDWF, 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) { + emitSKPNC; + pic16_emitpcode(POC_ADDWF, 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)); + pic16_emitpcode(POC_DECF, 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)); + pic16_emitpcode(POC_MOVLW, pic16_popGetLit(0xff)); + while(size--) + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),size)); + + } + } else + while(size--) + pic16_emitpcode(POC_CLRF,pic16_popGet(AOP(result),offset++)); + } +} + +/*-----------------------------------------------------------------*/ +/* pic16_genMinusBits - generates code for subtraction of two bits */ +/*-----------------------------------------------------------------*/ +void pic16_genMinusBits (iCode *ic) +{ + symbol *lbl = newiTempLabel(NULL); + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + if (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY){ + pic16_emitcode("mov","c,%s",AOP(IC_LEFT(ic))->aopu.aop_dir); + pic16_emitcode("jnb","%s,%05d_DS_",AOP(IC_RIGHT(ic))->aopu.aop_dir,(lbl->key+100)); + pic16_emitcode("cpl","c"); + pic16_emitcode("","%05d_DS_:",(lbl->key+100)); + pic16_outBitC(IC_RESULT(ic)); + } + else{ + pic16_emitcode("mov","c,%s",AOP(IC_RIGHT(ic))->aopu.aop_dir); + pic16_emitcode("subb","a,acc"); + pic16_emitcode("jnb","%s,%05d_DS_",AOP(IC_LEFT(ic))->aopu.aop_dir,(lbl->key+100)); + pic16_emitcode("inc","a"); + pic16_emitcode("","%05d_DS_:",(lbl->key+100)); + pic16_aopPut(AOP(IC_RESULT(ic)),"a",0); + pic16_addSign(IC_RESULT(ic), MSB16, SPEC_USIGN(getSpec(operandType(IC_RESULT(ic))))); + } +} + +/*-----------------------------------------------------------------*/ +/* pic16_genMinus - generates code for subtraction */ +/*-----------------------------------------------------------------*/ +void pic16_genMinus (iCode *ic) +{ + int size, offset = 0, same=0; + unsigned long lit = 0L; + + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + 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 = (unsigned long)floatFromVal(AOP(IC_RIGHT(ic))->aopu.aop_lit); + lit = - (long)lit; + + genAddLit ( ic, lit); + +#if 0 + /* add the first byte: */ + pic16_emitcode("movlw","0x%x", lit & 0xff); + pic16_emitcode("addwf","%s,f", pic16_aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE)); + pic16_emitpcode(POC_MOVLW, pic16_popGetLit(lit & 0xff)); + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(IC_LEFT(ic)),0)); + + + offset = 1; + size--; + + while(size-- > 0) { + + lit >>= 8; + + if(lit & 0xff) { + + if((lit & 0xff) == 0xff) { + pic16_emitpcode(POC_MOVLW, pic16_popGetLit(0xff)); + emitSKPC; + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(IC_LEFT(ic)),offset)); + } else { + pic16_emitpcode(POC_MOVLW, pic16_popGetLit(lit & 0xff)); + emitSKPNC; + pic16_emitpcode(POC_MOVLW, pic16_popGetLit((lit+1) & 0xff)); + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(IC_LEFT(ic)),offset)); + } + + } else { + /* do the rlf known zero trick here */ + pic16_emitpcode(POC_MOVLW, pic16_popGetLit(1)); + emitSKPNC; + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(IC_LEFT(ic)),offset)); + } + offset++; + } +#endif + } 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)); + + pic16_emitcode("btfsc","(%s >> 3), (%s & 7)", + AOP(IC_RIGHT(ic))->aopu.aop_dir, + AOP(IC_RIGHT(ic))->aopu.aop_dir); + pic16_emitcode(" incf","%s,f", pic16_aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE)); + } 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_IMMD) || + (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) ) { + + lit = (unsigned long)floatFromVal(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_popGet(AOP(IC_RIGHT(ic)),0)); + 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_emitpcode(POC_MOVFW , pic16_popGet(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_TYPE(IC_LEFT(ic)) == AOP_IMMD) || + (AOP(IC_LEFT(ic))->type == AOP_LIT) && + (AOP_TYPE(IC_RIGHT(ic)) != AOP_ACC)) { + + lit = (unsigned long)floatFromVal(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_COMF, pic16_popGet(AOP(IC_RIGHT(ic)),0)); + pic16_emitpcode(POC_INCF, 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_emitpcode(POC_MOVFW, pic16_popGet(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 = 1; + while(--size) { + lit >>= 8; + + if(size == 1) { + /* This is the last byte in a multibyte subtraction + * There are a couple of tricks we can do by not worrying about + * propogating the carry */ + if(lit == 0xff) { + /* 0xff - x == ~x */ + if(same) { + pic16_emitpcode(POC_COMF, pic16_popGet(AOP(IC_RESULT(ic)),offset)); + emitSKPC; + pic16_emitpcode(POC_DECF, pic16_popGet(AOP(IC_RESULT(ic)),offset)); + } else { + pic16_emitpcode(POC_COMFW, pic16_popGet(AOP(IC_RIGHT(ic)),offset)); + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(IC_RESULT(ic)),offset)); + emitSKPC; + pic16_emitpcode(POC_DECF, pic16_popGet(AOP(IC_RESULT(ic)),offset)); + } + } else { + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(IC_RIGHT(ic)),offset)); + emitSKPC; + pic16_emitpcode(POC_INCFW, pic16_popGet(AOP(IC_RIGHT(ic)),offset)); + pic16_emitpcode(POC_SUBLW, pic16_popGetLit(lit & 0xff)); + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(IC_RESULT(ic)),offset)); + } + + goto release; + } + + if(same) { + + if(lit & 0xff) { + pic16_emitpcode(POC_MOVLW, pic16_popGetLit(lit & 0xff)); + emitSKPC; + pic16_emitpcode(POC_MOVLW, pic16_popGetLit((lit & 0xff)-1)); + pic16_emitpcode(POC_SUBWF, pic16_popGet(AOP(IC_RESULT(ic)),offset)); + } else { + emitSKPNC; + pic16_emitpcode(POC_SUBWF, pic16_popGet(AOP(IC_RESULT(ic)),offset)); + + } + } else { + + if(lit & 0xff) { + pic16_emitpcode(POC_MOVLW, pic16_popGetLit(lit & 0xff)); + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(IC_RESULT(ic)),offset)); + } else + pic16_emitpcode(POC_CLRF, pic16_popGet(AOP(IC_RESULT(ic)),offset)); + + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(IC_RIGHT(ic)),offset)); + emitSKPC; + pic16_emitpcode(POC_INCFSZW,pic16_popGet(AOP(IC_RIGHT(ic)),offset)); + pic16_emitpcode(POC_SUBWF, 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(strcmp(pic16_aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE),"a") == 0 ) { + DEBUGpic16_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__); + pic16_emitpcode(POC_SUBFW, pic16_popGet(AOP(IC_RIGHT(ic)),0)); + pic16_emitpcode(POC_SUBLW, pic16_popGetLit(0)); + pic16_emitpcode(POC_MOVWF,pic16_popGet(AOP(IC_RESULT(ic)),0)); + } else { + + if ( AOP_TYPE(IC_LEFT(ic)) == AOP_ACC) { + 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_emitpcode(POC_MOVFW,pic16_popGet(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_IMMD) || + (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_LEFT(ic)), AOP(IC_RESULT(ic))) ) { + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(IC_LEFT(ic)),offset)); + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(IC_RESULT(ic)),offset)); + } + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(IC_RIGHT(ic)),offset)); + emitSKPC; + pic16_emitpcode(POC_INCFSZW,pic16_popGet(AOP(IC_RIGHT(ic)),offset)); + pic16_emitpcode(POC_SUBWF, 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_genUMult8XLit_16 - unsigned multiplication of two 8-bit numbers. + * + * + *-----------------------------------------------------------------*/ +void pic16_genUMult8XLit_16 (operand *left, + operand *right, + operand *result, + pCodeOpReg *result_hi) + +{ + + unsigned int lit; + unsigned int i,have_first_bit; + int same; + pCodeOp *temp; + + if (AOP_TYPE(right) != AOP_LIT){ + fprintf(stderr,"%s %d - right operand is not a literal\n",__FILE__,__LINE__); + exit(1); + } + + + if(!result_hi) { + result_hi = PCOR(pic16_popGet(AOP(result),1)); + } + + lit = (unsigned int)floatFromVal(AOP(right)->aopu.aop_lit); + lit &= 0xff; + pic16_emitcode(";","Unrolled 8 X 8 multiplication"); + + same = pic16_sameRegs(AOP(left), AOP(result)); + + if(same) { + switch(lit) { + case 0: + pic16_emitpcode(POC_CLRF, pic16_popGet(AOP(left),0)); + return; + case 2: + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(left),0)); + return; + case 3: + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(left),0)); + return; + case 4: + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(left),0)); + return; + case 5: + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_ADDFW, pic16_popGet(AOP(left),0)); // W = 2*F + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(left),0)); // F = 3*F + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(left),0)); // F = 5*F + return; + case 6: + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(left),0)); + return; + case 7: + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_ADDFW, pic16_popGet(AOP(left),0)); // W = 2*F + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(left),0)); // F = 3*F + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(left),0)); // F = 5*F + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(left),0)); // F = 7*F + return; + case 8: + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_ADDFW, pic16_popGet(AOP(left),0)); // W = 2*F + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(left),0)); // F = 3*F + pic16_emitpcode(POC_ADDFW, pic16_popGet(AOP(left),0)); // W = 5*F + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(left),0)); // F = 8*F + return; + case 9: + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(left),0)); + return; + case 10: + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_ADDFW, pic16_popGet(AOP(left),0)); // W = 2*F + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(left),0)); // F = 3*F + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(left),0)); // F = 5*F + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(left),0)); + return; + case 11: + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_ADDFW, pic16_popGet(AOP(left),0)); // W = 2*F + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(left),0)); // F = 3*F + pic16_emitpcode(POC_ADDFW, pic16_popGet(AOP(left),0)); // W = 5*F + pic16_emitpcode(POC_ADDFW, pic16_popGet(AOP(left),0)); // W = 8*F + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(left),0)); // F = 11*F + return; + case 12: + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(left),0)); + return; + case 13: + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_ADDFW, pic16_popGet(AOP(left),0)); // W = 2*F + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(left),0)); // F = 3*F + pic16_emitpcode(POC_ADDFW, pic16_popGet(AOP(left),0)); // W = 5*F + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(left),0)); // F = 8*F + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(left),0)); // F = 13*F + return; + case 14: + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_ADDFW, pic16_popGet(AOP(left),0)); // W = 2*F + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(left),0)); // F = 3*F + pic16_emitpcode(POC_ADDFW, pic16_popGet(AOP(left),0)); // W = 5*F + pic16_emitpcode(POC_ADDFW, pic16_popGet(AOP(left),0)); // W = 8*F + pic16_emitpcode(POC_ADDFW, pic16_popGet(AOP(left),0)); // W = 11*F + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(left),0)); // F = 14*F + return; + case 15: + temp = pic16_popGetTempReg(); + if(!temp) { + fprintf(stderr,"ERROR: unable to allocate register. %s:%d\n",__FUNCTION__,__LINE__); + exit(1); + } + pic16_emitpcode(POC_SWAPFW, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_MOVWF, temp); + pic16_emitpcode(POC_ANDLW, pic16_popGetLit(0xf0)); + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_SWAPFW, temp); + pic16_emitpcode(POC_SUBWF, pic16_popGet(AOP(left),0)); + pic16_popReleaseTempReg(temp); + return; + case 16: + pic16_emitpcode(POC_SWAPFW, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_ANDLW, pic16_popGetLit(0xf0)); + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(left),0)); + return; + case 17: + pic16_emitpcode(POC_SWAPFW, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_ANDLW, pic16_popGetLit(0xf0)); + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(left),0)); + return; + case 32: + pic16_emitpcode(POC_SWAPF, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_RLCFW, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_ANDLW, pic16_popGetLit(0xe0)); + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(left),0)); + return; + case 64: + pic16_emitpcode(POC_SWAPF, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_RLCF, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_RLCFW, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_ANDLW, pic16_popGetLit(0xc0)); + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(left),0)); + return; + case 128: + pic16_emitpcode(POC_RRCFW, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_CLRF, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_RRCF, pic16_popGet(AOP(left),0)); + return; + + } + } else { + + switch(lit) { + case 0: + pic16_emitpcode(POC_CLRF, pic16_popGet(AOP(result),0)); + pic16_emitpcode(POC_CLRF, pic16_popCopyReg(result_hi)); + return; + case 2: + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),0)); + pic16_emitpcode(POC_ADDWF, pic16_popGet(AOP(result),0)); + pic16_emitpcode(POC_CLRF, pic16_popCopyReg(result_hi)); + pic16_emitpcode(POC_RLCF, pic16_popCopyReg(result_hi)); + return; + } + + } + + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_CLRF, pic16_popGet(AOP(result),0)); + pic16_emitpcode(POC_CLRF, pic16_popCopyReg(result_hi)); + + have_first_bit = 0; + for(i=0; i<8; i++) { + + if(lit & 1) { + pic16_emitpcode(POC_ADDWF, pic16_popCopyReg(result_hi)); + have_first_bit = 1; + } + + if(have_first_bit) { + pic16_emitpcode(POC_RRCF, pic16_popCopyReg(result_hi)); + pic16_emitpcode(POC_RRCF, pic16_popGet(AOP(result),0)); + } + + lit >>= 1; + } + +} + +/*-----------------------------------------------------------------* + * genUMult8X8_16 - unsigned multiplication of two 8-bit numbers. + * + * + *-----------------------------------------------------------------*/ +void pic16_genUMult8X8_16 (operand *left, + operand *right, + operand *result, + pCodeOpReg *result_hi) + +{ + + int i; + int looped = 1; + + if(!result_hi) { + result_hi = PCOR(pic16_popGet(AOP(result),1)); + } + + if (AOP_TYPE(right) == AOP_LIT) { + pic16_genUMult8XLit_16(left,right,result,result_hi); + return; + } + + if(!looped) { + pic16_emitcode(";","Unrolled 8 X 8 multiplication"); + + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(right),0)); + pic16_emitpcode(POC_CLRF, pic16_popGet(AOP(result),0)); + pic16_emitpcode(POC_CLRF, pic16_popCopyReg(result_hi)); + emitCLRC; + + for(i=0; i<8; i++) { + pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit(pic16_aopGet(AOP(left),0,FALSE,FALSE),i,0)); + pic16_emitpcode(POC_ADDWF, pic16_popCopyReg(result_hi)); + pic16_emitpcode(POC_RRCF, pic16_popCopyReg(result_hi)); + pic16_emitpcode(POC_RRCF, pic16_popGet(AOP(result),0)); + } + + + /* + Here's another version that does the same thing and takes the + same number of instructions. The one above is slightly better + because the entry instructions have a higher probability of + being optimized out. + */ + /* + pic16_emitpcode(POC_CLRF, pic16_popCopyReg(result_hi)); + pic16_emitpcode(POC_RRCFW, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_MOVWF, pic16_popGet(AOP(result),0)); + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(right),0)); + + for(i=0; i<8; i++) { + emitSKPNC; + pic16_emitpcode(POC_ADDWF, pic16_popCopyReg(result_hi)); + pic16_emitpcode(POC_RRCF, pic16_popCopyReg(result_hi)); + pic16_emitpcode(POC_RRCF, pic16_popGet(AOP(result),0)); + } + */ + + } else { + symbol *tlbl = newiTempLabel(NULL); + pCodeOp *temp; + + + pic16_emitcode(";","Looped 8 X 8 multiplication"); + + pic16_emitpcode(POC_CLRF, pic16_popGet(AOP(result),0)); + pic16_emitpcode(POC_CLRF, pic16_popCopyReg(result_hi)); + + pic16_emitpcode(POC_BSF, pic16_newpCodeOpBit(pic16_aopGet(AOP(result),0,FALSE,FALSE),7,0)); + + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(right),0)); + + temp = pic16_popGetTempReg(); + pic16_emitpcode(POC_MOVWF, pic16_popCopyReg(PCOR(temp))); + + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(left),0)); + + pic16_emitpLabel(tlbl->key); + + pic16_emitpcode(POC_RRCF, pic16_popCopyReg(PCOR(temp))); + emitSKPNC; + pic16_emitpcode(POC_ADDWF, pic16_popCopyReg(result_hi)); + + pic16_emitpcode(POC_RRCF, pic16_popCopyReg(result_hi)); + pic16_emitpcode(POC_RRCF, pic16_popGet(AOP(result),0)); + + emitSKPC; + pic16_emitpcode(POC_GOTO, pic16_popGetLabel(tlbl->key)); + + pic16_popReleaseTempReg(temp); + + } +} + +/*-----------------------------------------------------------------* + * pic16_genSMult8X8_16 - signed multiplication of two 8-bit numbers + * + * this routine will call the unsigned multiply routine and then + * post-fix the sign bit. + *-----------------------------------------------------------------*/ +void pic16_genSMult8X8_16 (operand *left, + operand *right, + operand *result, + pCodeOpReg *result_hi) +{ + + if(!result_hi) { + result_hi = PCOR(pic16_popGet(AOP(result),1)); + } + + pic16_genUMult8X8_16(left,right,result,result_hi); + + pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit(pic16_aopGet(AOP(left),0,FALSE,FALSE),7,0)); + pic16_emitpcode(POC_SUBWF, pic16_popCopyReg(result_hi)); + pic16_emitpcode(POC_MOVFW, pic16_popGet(AOP(left),0)); + pic16_emitpcode(POC_BTFSC, pic16_newpCodeOpBit(pic16_aopGet(AOP(right),0,FALSE,FALSE),7,0)); + pic16_emitpcode(POC_SUBWF, pic16_popGet(AOP(result),1)); + +} + +/*-----------------------------------------------------------------* + * pic16_genMult8X8_8 - multiplication of two 8-bit numbers + * + * this routine will call the unsigned multiply 8X8=>16 routine and + * then throw away the high byte of the result. + * + *-----------------------------------------------------------------*/ +void pic16_genMult8X8_8 (operand *left, + operand *right, + operand *result) +{ + pCodeOp *result_hi = pic16_popGetTempReg(); + + if (AOP_TYPE(right) == AOP_LIT) + pic16_genUMult8XLit_16(left,right,result,PCOR(result_hi)); + else + pic16_genUMult8X8_16(left,right,result,PCOR(result_hi)); + + pic16_popReleaseTempReg(result_hi); +} +#if 0 +/*-----------------------------------------------------------------*/ +/* constMult - generates code for multiplication by a constant */ +/*-----------------------------------------------------------------*/ +void genMultConst(unsigned C) +{ + + unsigned lit; + unsigned sr3; // Shift right 3 + unsigned mask; + + int size = 1; + + /* + Convert a string of 3 binary 1's in the lit into + 0111 = 1000 - 1; + */ + + mask = 7 << ( (size*8) - 3); + lit = C; + sr3 = 0; + + while(mask < (1<>= 1; + + } + +} + +#endif diff --git a/src/pic16/glue.c b/src/pic16/glue.c new file mode 100644 index 00000000..9c79d34a --- /dev/null +++ b/src/pic16/glue.c @@ -0,0 +1,966 @@ +/*------------------------------------------------------------------------- + + SDCCglue.c - glues everything we have done together into one file. + Written By - Sandeep Dutta . sandeep.dutta@usa.net (1998) + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! +-------------------------------------------------------------------------*/ + +#include "../common.h" +#include +#include "ralloc.h" +#include "pcode.h" +#include "newalloc.h" + + +#ifdef _BIG_ENDIAN + #define _ENDIAN(x) (3-x) +#else + #define _ENDIAN(x) (x) +#endif + +#define BYTE_IN_LONG(x,b) ((x>>(8*_ENDIAN(b)))&0xff) + +extern symbol *interrupts[256]; +static void printIval (symbol * sym, sym_link * type, initList * ilist, pBlock *pb); +extern int noAlloc; +extern set *publics; +extern unsigned maxInterrupts; +extern int maxRegBank; +extern symbol *mainf; +extern char *VersionString; +extern FILE *codeOutFile; +extern set *tmpfileSet; +extern set *tmpfileNameSet; +extern char *iComments1; +extern char *iComments2; +//extern void emitStaticSeg (memmap * map); + +extern DEFSETFUNC (closeTmpFiles); +extern DEFSETFUNC (rmTmpFiles); + +extern void pic16_AnalyzeBanking (void); +extern void copyFile (FILE * dest, FILE * src); +extern void pic16_InlinepCode(void); +extern void pic16_writeUsedRegs(FILE *); + +extern void initialComments (FILE * afile); +extern void printPublics (FILE * afile); + +extern void printChar (FILE * ofile, char *s, int plen); +void pic16_pCodeInitRegisters(void); + +/*-----------------------------------------------------------------*/ +/* aopLiteral - string from a literal value */ +/*-----------------------------------------------------------------*/ +int pic16aopLiteral (value *val, int offset) +{ + union { + float f; + unsigned char c[4]; + } fl; + + /* if it is a float then it gets tricky */ + /* otherwise it is fairly simple */ + if (!IS_FLOAT(val->type)) { + unsigned long v = (unsigned long) floatFromVal(val); + + return ( (v >> (offset * 8)) & 0xff); + } + + /* it is type float */ + fl.f = (float) floatFromVal(val); +#ifdef _BIG_ENDIAN + return fl.c[3-offset]; +#else + return fl.c[offset]; +#endif + +} + + +/*-----------------------------------------------------------------*/ +/* emitRegularMap - emit code for maps with no special cases */ +/*-----------------------------------------------------------------*/ +static void +pic16emitRegularMap (memmap * map, bool addPublics, bool arFlag) +{ + symbol *sym; + int i, size, bitvars = 0;; + + if (addPublics) + fprintf (map->oFile, ";\t.area\t%s\n", map->sname); + + /* print the area name */ + for (sym = setFirstItem (map->syms); sym; + sym = setNextItem (map->syms)) + { + + /* if extern then do nothing */ + if (IS_EXTERN (sym->etype)) + continue; + + /* if allocation required check is needed + then check if the symbol really requires + allocation only for local variables */ + if (arFlag && !IS_AGGREGATE (sym->type) && + !(sym->_isparm && !IS_REGPARM (sym->etype)) && + !sym->allocreq && sym->level) + continue; + + /* if global variable & not static or extern + and addPublics allowed then add it to the public set */ + if ((sym->level == 0 || + (sym->_isparm && !IS_REGPARM (sym->etype))) && + addPublics && + !IS_STATIC (sym->etype)) + addSetHead (&publics, sym); + + /* if extern then do nothing or is a function + then do nothing */ + if (IS_FUNC (sym->type)) + continue; +#if 0 + /* print extra debug info if required */ + if (options.debug || sym->level == 0) + { + + cdbSymbol (sym, cdbFile, FALSE, FALSE); + + if (!sym->level) /* global */ + if (IS_STATIC (sym->etype)) + fprintf (map->oFile, "F%s_", moduleName); /* scope is file */ + else + fprintf (map->oFile, "G_"); /* scope is global */ + else + /* symbol is local */ + fprintf (map->oFile, "L%s_", (sym->localof ? sym->localof->name : "-null-")); + fprintf (map->oFile, "%s_%d_%d", sym->name, sym->level, sym->block); + } +#endif + + /* if is has an absolute address then generate + an equate for this no need to allocate space */ + if (SPEC_ABSA (sym->etype)) + { + //if (options.debug || sym->level == 0) + //fprintf (map->oFile,"; == 0x%04x\n",SPEC_ADDR (sym->etype)); + + fprintf (map->oFile, "%s\tEQU\t0x%04x\n", + sym->rname, + SPEC_ADDR (sym->etype)); + } + else + { + /* allocate space */ + + /* If this is a bit variable, then allocate storage after 8 bits have been declared */ + /* unlike the 8051, the pic does not have a separate bit area. So we emulate bit ram */ + /* by grouping the bits together into groups of 8 and storing them in the normal ram. */ + if (IS_BITVAR (sym->etype)) + { + bitvars++; + } + else + { + fprintf (map->oFile, "\t%s\n", sym->rname); + if ((size = (unsigned int) getSize (sym->type) & 0xffff) > 1) + { + for (i = 1; i < size; i++) + fprintf (map->oFile, "\t%s_%d\n", sym->rname, i); + } + } + //fprintf (map->oFile, "\t.ds\t0x%04x\n", (unsigned int)getSize (sym->type) & 0xffff); + } + + /* if it has a initial value then do it only if + it is a global variable */ + if (sym->ival && sym->level == 0) { + ast *ival = NULL; + + if (IS_AGGREGATE (sym->type)) + ival = initAggregates (sym, sym->ival, NULL); + else + ival = newNode ('=', newAst_VALUE(symbolVal (sym)), + decorateType (resolveSymbols (list2expr (sym->ival)))); + codeOutFile = statsg->oFile; + GcurMemmap = statsg; + eBBlockFromiCode (iCodeFromAst (ival)); + sym->ival = NULL; + } + } +} + + +/*-----------------------------------------------------------------*/ +/* printIvalType - generates ival for int/char */ +/*-----------------------------------------------------------------*/ +static void +printIvalType (symbol *sym, sym_link * type, initList * ilist, pBlock *pb) +{ + value *val; + unsigned long ulval; + + //fprintf(stderr, "%s\n",__FUNCTION__); + + /* if initList is deep */ + if (ilist->type == INIT_DEEP) + ilist = ilist->init.deep; + + if (!IS_AGGREGATE(sym->type) && getNelements(type, ilist)>1) { + werror (W_EXCESS_INITIALIZERS, "scalar", sym->name, sym->lineDef); + } + + if (!(val = list2val (ilist))) { + // assuming a warning has been thrown + val=constVal("0"); + } + + if (val->type != type) { + val = valCastLiteral(type, floatFromVal(val)); + } + + if(val) + ulval = (unsigned long) floatFromVal (val); + else + ulval =0; + + switch (getSize (type)) { + case 1: + pic16_addpCode2pBlock(pb,pic16_newpCode(POC_RETLW,pic16_newpCodeOpLit(BYTE_IN_LONG(ulval,0)))); + break; + + case 2: + pic16_addpCode2pBlock(pb,pic16_newpCode(POC_RETLW,pic16_newpCodeOpLit(BYTE_IN_LONG(ulval,0)))); + pic16_addpCode2pBlock(pb,pic16_newpCode(POC_RETLW,pic16_newpCodeOpLit(BYTE_IN_LONG(ulval,1)))); + break; + + case 4: + pic16_addpCode2pBlock(pb,pic16_newpCode(POC_RETLW,pic16_newpCodeOpLit(BYTE_IN_LONG(ulval,0)))); + pic16_addpCode2pBlock(pb,pic16_newpCode(POC_RETLW,pic16_newpCodeOpLit(BYTE_IN_LONG(ulval,1)))); + pic16_addpCode2pBlock(pb,pic16_newpCode(POC_RETLW,pic16_newpCodeOpLit(BYTE_IN_LONG(ulval,2)))); + pic16_addpCode2pBlock(pb,pic16_newpCode(POC_RETLW,pic16_newpCodeOpLit(BYTE_IN_LONG(ulval,3)))); + break; + } +} + +/*-----------------------------------------------------------------*/ +/* printIvalChar - generates initital value for character array */ +/*-----------------------------------------------------------------*/ +static int +printIvalChar (sym_link * type, initList * ilist, pBlock *pb, char *s) +{ + value *val; + int remain; + + if(!pb) + return 0; + + fprintf(stderr, "%s\n",__FUNCTION__); + if (!s) + { + + val = list2val (ilist); + /* if the value is a character string */ + if (IS_ARRAY (val->type) && IS_CHAR (val->etype)) + { + if (!DCL_ELEM (type)) + DCL_ELEM (type) = strlen (SPEC_CVAL (val->etype).v_char) + 1; + + //printChar (oFile, SPEC_CVAL (val->etype).v_char, DCL_ELEM (type)); + //fprintf(stderr, "%s omitting call to printChar\n",__FUNCTION__); + pic16_addpCode2pBlock(pb,pic16_newpCodeCharP(";omitting call to printChar")); + + if ((remain = (DCL_ELEM (type) - strlen (SPEC_CVAL (val->etype).v_char) - 1)) > 0) + while (remain--) + //tfprintf (oFile, "\t!db !constbyte\n", 0); + pic16_addpCode2pBlock(pb,pic16_newpCode(POC_RETLW,pic16_newpCodeOpLit(0))); + return 1; + } + else + return 0; + } + else { + //printChar (oFile, s, strlen (s) + 1); + + for(remain=0; remainnext)) { + //fprintf(stderr,"%s:%d - is_char\n",__FUNCTION__,__LINE__); + if (!IS_LITERAL(list2val(ilist)->etype)) { + werror (W_INIT_WRONG); + return; + } + if (printIvalChar (type, + (ilist->type == INIT_DEEP ? ilist->init.deep : ilist), + pb, SPEC_CVAL (sym->etype).v_char)) + return; + } + /* not the special case */ + if (ilist->type != INIT_DEEP) + { + werror (E_INIT_STRUCT, sym->name); + return; + } + + iloop = ilist->init.deep; + lcnt = DCL_ELEM (type); + + for (;;) + { + //fprintf(stderr,"%s:%d - is_char\n",__FUNCTION__,__LINE__); + size++; + printIval (sym, type->next, iloop, pb); + iloop = (iloop ? iloop->next : NULL); + + + /* if not array limits given & we */ + /* are out of initialisers then */ + if (!DCL_ELEM (type) && !iloop) + break; + + /* no of elements given and we */ + /* have generated for all of them */ + if (!--lcnt) { + /* if initializers left */ + if (iloop) { + werror (W_EXCESS_INITIALIZERS, "array", sym->name, sym->lineDef); + } + break; + } + } + + /* if we have not been given a size */ + if (!DCL_ELEM (type)) + DCL_ELEM (type) = size; + + return; +} + +/*-----------------------------------------------------------------*/ +/* printIval - generates code for initial value */ +/*-----------------------------------------------------------------*/ +static void +printIval (symbol * sym, sym_link * type, initList * ilist, pBlock *pb) +{ + if (!ilist || !pb) + return; + + /* if structure then */ + if (IS_STRUCT (type)) + { + //fprintf(stderr,"%s struct\n",__FUNCTION__); + //printIvalStruct (sym, type, ilist, oFile); + return; + } + + /* if this is a pointer */ + if (IS_PTR (type)) + { + //fprintf(stderr,"%s pointer\n",__FUNCTION__); + //printIvalPtr (sym, type, ilist, oFile); + return; + } + + /* if this is an array */ + if (IS_ARRAY (type)) + { + //fprintf(stderr,"%s array\n",__FUNCTION__); + printIvalArray (sym, type, ilist, pb); + return; + } + + /* if type is SPECIFIER */ + if (IS_SPEC (type)) + { + //fprintf(stderr,"%s spec\n",__FUNCTION__); + printIvalType (sym, type, ilist, pb); + return; + } +} + +extern void pic16_pCodeConstString(char *name, char *value); +/*-----------------------------------------------------------------*/ +/* emitStaticSeg - emitcode for the static segment */ +/*-----------------------------------------------------------------*/ +static void +pic16emitStaticSeg (memmap * map) +{ + symbol *sym; + + fprintf (map->oFile, ";\t.area\t%s\n", map->sname); + + //fprintf(stderr, "%s\n",__FUNCTION__); + + /* for all variables in this segment do */ + for (sym = setFirstItem (map->syms); sym; + sym = setNextItem (map->syms)) + { + /* if it is "extern" then do nothing */ + if (IS_EXTERN (sym->etype)) + continue; + + /* if it is not static add it to the public + table */ + if (!IS_STATIC (sym->etype)) + addSetHead (&publics, sym); + + /* print extra debug info if required */ + if (options.debug || sym->level == 0) + { + /* NOTE to me - cdbFile may be null in which case, + * the sym name will be printed to stdout. oh well */ + if(cdbFile) + cdbSymbol (sym, cdbFile, FALSE, FALSE); + + if (!sym->level) + { /* global */ + if (IS_STATIC (sym->etype)) + fprintf (code->oFile, "F%s_", moduleName); /* scope is file */ + else + fprintf (code->oFile, "G_"); /* scope is global */ + } + else + /* symbol is local */ + fprintf (code->oFile, "L%s_", + (sym->localof ? sym->localof->name : "-null-")); + fprintf (code->oFile, "%s_%d_%d", sym->name, sym->level, sym->block); + + } + + /* if it has an absolute address */ + if (SPEC_ABSA (sym->etype)) + { + if (options.debug || sym->level == 0) + fprintf (code->oFile, " == 0x%04x\n", SPEC_ADDR (sym->etype)); + + fprintf (code->oFile, "%s\t=\t0x%04x\n", + sym->rname, + SPEC_ADDR (sym->etype)); + } + else + { + if (options.debug || sym->level == 0) + fprintf (code->oFile, " == .\n"); + + /* if it has an initial value */ + if (sym->ival) + { + pBlock *pb; + + fprintf (code->oFile, "%s:\n", sym->rname); + noAlloc++; + resolveIvalSym (sym->ival); + //printIval (sym, sym->type, sym->ival, code->oFile); + pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block for Ival")); + pic16_addpBlock(pb); + pic16_addpCode2pBlock(pb,pic16_newpCodeLabel(sym->rname,-1)); + + printIval (sym, sym->type, sym->ival, pb); + noAlloc--; + } + else + { + + /* allocate space */ + fprintf (code->oFile, "%s:\n", sym->rname); + /* special case for character strings */ + if (IS_ARRAY (sym->type) && IS_CHAR (sym->type->next) && + SPEC_CVAL (sym->etype).v_char) + pic16_pCodeConstString(sym->rname , SPEC_CVAL (sym->etype).v_char); + /*printChar (code->oFile, + SPEC_CVAL (sym->etype).v_char, + strlen (SPEC_CVAL (sym->etype).v_char) + 1);*/ + else + fprintf (code->oFile, "\t.ds\t0x%04x\n", (unsigned int) getSize (sym->type) & 0xffff); + } + } + } + +} + + +/*-----------------------------------------------------------------*/ +/* emitMaps - emits the code for the data portion the code */ +/*-----------------------------------------------------------------*/ +static void +pic16emitMaps () +{ + /* no special considerations for the following + data, idata & bit & xdata */ + pic16emitRegularMap (data, TRUE, TRUE); + pic16emitRegularMap (idata, TRUE, TRUE); + pic16emitRegularMap (bit, TRUE, FALSE); + pic16emitRegularMap (xdata, TRUE, TRUE); + pic16emitRegularMap (sfr, FALSE, FALSE); + pic16emitRegularMap (sfrbit, FALSE, FALSE); + pic16emitRegularMap (code, TRUE, FALSE); + pic16emitStaticSeg (statsg); +} + +/*-----------------------------------------------------------------*/ +/* createInterruptVect - creates the interrupt vector */ +/*-----------------------------------------------------------------*/ +static void +pic16createInterruptVect (FILE * vFile) +{ + unsigned i = 0; + mainf = newSymbol ("main", 0); + mainf->block = 0; + + /* only if the main function exists */ + if (!(mainf = findSymWithLevel (SymbolTab, mainf))) + { + if (!options.cc_only) + werror (E_NO_MAIN); + return; + } + + /* if the main is only a prototype ie. no body then do nothing */ + if (!IFFUNC_HASBODY(mainf->type)) + { + /* if ! compile only then main function should be present */ + if (!options.cc_only) + werror (E_NO_MAIN); + return; + } + + fprintf (vFile, ";\t.area\t%s\n", CODE_NAME); + fprintf (vFile, ";__interrupt_vect:\n"); + + + if (!port->genIVT || !(port->genIVT (vFile, interrupts, maxInterrupts))) + { + /* "generic" interrupt table header (if port doesn't specify one). + + * Look suspiciously like 8051 code to me... + */ + + fprintf (vFile, ";\tljmp\t__sdcc_gsinit_startup\n"); + + + /* now for the other interrupts */ + for (; i < maxInterrupts; i++) + { + if (interrupts[i]) + fprintf (vFile, ";\tljmp\t%s\n;\t.ds\t5\n", interrupts[i]->rname); + else + fprintf (vFile, ";\treti\n;\t.ds\t7\n"); + } + } +} + + +/*-----------------------------------------------------------------*/ +/* initialComments - puts in some initial comments */ +/*-----------------------------------------------------------------*/ +static void +pic16initialComments (FILE * afile) +{ + initialComments (afile); + fprintf (afile, "; PIC port for the 16-bit core\n"); + fprintf (afile, iComments2); + +} + +/*-----------------------------------------------------------------*/ +/* printPublics - generates .global for publics */ +/*-----------------------------------------------------------------*/ +static void +pic16printPublics (FILE * afile) +{ + symbol *sym; + + fprintf (afile, "%s", iComments2); + fprintf (afile, "; publics variables in this module\n"); + fprintf (afile, "%s", iComments2); + + for (sym = setFirstItem (publics); sym; + sym = setNextItem (publics)) + fprintf (afile, ";\t.globl %s\n", sym->rname); +} + + + +/*-----------------------------------------------------------------*/ +/* emitOverlay - will emit code for the overlay stuff */ +/*-----------------------------------------------------------------*/ +static void +pic16emitOverlay (FILE * afile) +{ + set *ovrset; + + if (!elementsInSet (ovrSetSets)) + fprintf (afile, ";\t.area\t%s\n", port->mem.overlay_name); + + /* for each of the sets in the overlay segment do */ + for (ovrset = setFirstItem (ovrSetSets); ovrset; + ovrset = setNextItem (ovrSetSets)) + { + + symbol *sym; + + if (elementsInSet (ovrset)) + { + /* this dummy area is used to fool the assembler + otherwise the assembler will append each of these + declarations into one chunk and will not overlay + sad but true */ + fprintf (afile, ";\t.area _DUMMY\n"); + /* output the area informtion */ + fprintf (afile, ";\t.area\t%s\n", port->mem.overlay_name); /* MOF */ + } + + for (sym = setFirstItem (ovrset); sym; + sym = setNextItem (ovrset)) + { + + /* if extern then do nothing */ + if (IS_EXTERN (sym->etype)) + continue; + + /* if allocation required check is needed + then check if the symbol really requires + allocation only for local variables */ + if (!IS_AGGREGATE (sym->type) && + !(sym->_isparm && !IS_REGPARM (sym->etype)) + && !sym->allocreq && sym->level) + continue; + + /* if global variable & not static or extern + and addPublics allowed then add it to the public set */ + if ((sym->_isparm && !IS_REGPARM (sym->etype)) + && !IS_STATIC (sym->etype)) + addSetHead (&publics, sym); + + /* if extern then do nothing or is a function + then do nothing */ + if (IS_FUNC (sym->type)) + continue; + + /* print extra debug info if required */ + if (options.debug || sym->level == 0) + { + + cdbSymbol (sym, cdbFile, FALSE, FALSE); + + if (!sym->level) + { /* global */ + if (IS_STATIC (sym->etype)) + fprintf (afile, "F%s_", moduleName); /* scope is file */ + else + fprintf (afile, "G_"); /* scope is global */ + } + else + /* symbol is local */ + fprintf (afile, "L%s_", + (sym->localof ? sym->localof->name : "-null-")); + fprintf (afile, "%s_%d_%d", sym->name, sym->level, sym->block); + } + + /* if is has an absolute address then generate + an equate for this no need to allocate space */ + if (SPEC_ABSA (sym->etype)) + { + + if (options.debug || sym->level == 0) + fprintf (afile, " == 0x%04x\n", SPEC_ADDR (sym->etype)); + + fprintf (afile, "%s\t=\t0x%04x\n", + sym->rname, + SPEC_ADDR (sym->etype)); + } + else + { + if (options.debug || sym->level == 0) + fprintf (afile, "==.\n"); + + /* allocate space */ + fprintf (afile, "%s:\n", sym->rname); + fprintf (afile, "\t.ds\t0x%04x\n", (unsigned int) getSize (sym->type) & 0xffff); + } + + } + } +} + + +/*-----------------------------------------------------------------*/ +/* glue - the final glue that hold the whole thing together */ +/*-----------------------------------------------------------------*/ +void +pic16glue () +{ + + FILE *vFile; + FILE *asmFile; + FILE *ovrFile = tempfile(); + + addSetHead(&tmpfileSet,ovrFile); + pic16_pCodeInitRegisters(); + + if (mainf && IFFUNC_HASBODY(mainf->type)) { + + pBlock *pb = pic16_newpCodeChain(NULL,'X',pic16_newpCodeCharP("; Starting pCode block")); + pic16_addpBlock(pb); + + /* entry point @ start of CSEG */ + pic16_addpCode2pBlock(pb,pic16_newpCodeLabel("__sdcc_program_startup",-1)); + /* put in the call to main */ + pic16_addpCode2pBlock(pb,pic16_newpCode(POC_CALL,pic16_newpCodeOp("_main",PO_STR))); + + if (options.mainreturn) { + + pic16_addpCode2pBlock(pb,pic16_newpCodeCharP(";\treturn from main will return to caller\n")); + pic16_addpCode2pBlock(pb,pic16_newpCode(POC_RETURN,NULL)); + + } else { + + pic16_addpCode2pBlock(pb,pic16_newpCodeCharP(";\treturn from main will lock up\n")); + pic16_addpCode2pBlock(pb,pic16_newpCode(POC_GOTO,pic16_newpCodeOp("$",PO_STR))); + + } + } + + + /* At this point we've got all the code in the form of pCode structures */ + /* Now it needs to be rearranged into the order it should be placed in the */ + /* code space */ + + pic16_movepBlock2Head('P'); // Last + pic16_movepBlock2Head(code->dbName); + pic16_movepBlock2Head('X'); + pic16_movepBlock2Head(statsg->dbName); // First + + + /* print the global struct definitions */ + if (options.debug) + cdbStructBlock (0,cdbFile); + + vFile = tempfile(); + /* PENDING: this isnt the best place but it will do */ + if (port->general.glue_up_main) { + /* create the interrupt vector table */ + pic16createInterruptVect (vFile); + } + + addSetHead(&tmpfileSet,vFile); + + /* emit code for the all the variables declared */ + pic16emitMaps (); + /* do the overlay segments */ + pic16emitOverlay(ovrFile); + + + pic16_AnalyzepCode('*'); + + //#ifdef PCODE_DEBUG + //pic16_printCallTree(stderr); + //#endif + + pic16_InlinepCode(); + + pic16_AnalyzepCode('*'); + + pic16_pcode_test(); + + + /* now put it all together into the assembler file */ + /* create the assembler file name */ + + if (!options.c1mode) { + sprintf (buffer, srcFileName); + strcat (buffer, ".asm"); + } + else { + strcpy(buffer, options.out_name); + } + + if (!(asmFile = fopen (buffer, "w"))) { + werror (E_FILE_OPEN_ERR, buffer); + exit (1); + } + + /* initial comments */ + pic16initialComments (asmFile); + + /* print module name */ + fprintf (asmFile, ";\t.module %s\n", moduleName); + + /* Let the port generate any global directives, etc. */ + if (port->genAssemblerPreamble) + { + port->genAssemblerPreamble(asmFile); + } + + /* print the global variables in this module */ + pic16printPublics (asmFile); + + + /* copy the sfr segment */ + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "; special function registers\n"); + fprintf (asmFile, "%s", iComments2); + copyFile (asmFile, sfr->oFile); + + + /* Put all variables into a cblock */ + pic16_AnalyzeBanking(); + pic16_writeUsedRegs(asmFile); + + /* create the overlay segments */ + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "; overlayable items in internal ram \n"); + fprintf (asmFile, "%s", iComments2); + copyFile (asmFile, ovrFile); + + /* create the stack segment MOF */ + if (mainf && IFFUNC_HASBODY(mainf->type)) { + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "; Stack segment in internal ram \n"); + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, ";\t.area\tSSEG\t(DATA)\n" + ";__start__stack:\n;\t.ds\t1\n\n"); + } + + /* create the idata segment */ + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "; indirectly addressable internal ram data\n"); + fprintf (asmFile, "%s", iComments2); + copyFile (asmFile, idata->oFile); + + /* if external stack then reserve space of it */ + if (mainf && IFFUNC_HASBODY(mainf->type) && options.useXstack ) { + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "; external stack \n"); + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile,";\t.area XSEG (XDATA)\n"); /* MOF */ + fprintf (asmFile,";\t.ds 256\n"); + } + + + /* copy xtern ram data */ + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "; external ram data\n"); + fprintf (asmFile, "%s", iComments2); + copyFile (asmFile, xdata->oFile); + + + /* copy the bit segment */ + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "; bit data\n"); + fprintf (asmFile, "%s", iComments2); + copyFile (asmFile, bit->oFile); + + + fprintf (asmFile, "\tORG 0\n"); + + /* copy the interrupt vector table */ + if (mainf && IFFUNC_HASBODY(mainf->type)) { + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "; interrupt vector \n"); + fprintf (asmFile, "%s", iComments2); + copyFile (asmFile, vFile); + } + + /* copy global & static initialisations */ + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "; global & static initialisations\n"); + fprintf (asmFile, "%s", iComments2); + + /* Everywhere we generate a reference to the static_name area, + * (which is currently only here), we immediately follow it with a + * definition of the post_static_name area. This guarantees that + * the post_static_name area will immediately follow the static_name + * area. + */ + fprintf (asmFile, ";\t.area %s\n", port->mem.static_name); /* MOF */ + fprintf (asmFile, ";\t.area %s\n", port->mem.post_static_name); + fprintf (asmFile, ";\t.area %s\n", port->mem.static_name); + + if (mainf && IFFUNC_HASBODY(mainf->type)) { + fprintf (asmFile,"__sdcc_gsinit_startup:\n"); + /* if external stack is specified then the + higher order byte of the xdatalocation is + going into P2 and the lower order going into + spx */ + if (options.useXstack) { + fprintf(asmFile,";\tmov\tP2,#0x%02x\n", + (((unsigned int)options.xdata_loc) >> 8) & 0xff); + fprintf(asmFile,";\tmov\t_spx,#0x%02x\n", + (unsigned int)options.xdata_loc & 0xff); + } + + } + + if (port->general.glue_up_main && mainf && IFFUNC_HASBODY(mainf->type)) + { + /* This code is generated in the post-static area. + * This area is guaranteed to follow the static area + * by the ugly shucking and jiving about 20 lines ago. + */ + fprintf(asmFile, ";\t.area %s\n", port->mem.post_static_name); + fprintf (asmFile,";\tljmp\t__sdcc_program_startup\n"); + } + + /* copy over code */ + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, "; code\n"); + fprintf (asmFile, "%s", iComments2); + fprintf (asmFile, ";\t.area %s\n", port->mem.code_name); + + //copyFile (stderr, code->oFile); + + pic16_copypCode(asmFile, 'I'); + pic16_copypCode(asmFile, statsg->dbName); + pic16_copypCode(asmFile, 'X'); + pic16_copypCode(asmFile, 'M'); + pic16_copypCode(asmFile, code->dbName); + pic16_copypCode(asmFile, 'P'); + + + fprintf (asmFile,"\tend\n"); + + fclose (asmFile); + + rm_tmpfiles(); +} diff --git a/src/pic16/glue.h b/src/pic16/glue.h new file mode 100644 index 00000000..30e54dde --- /dev/null +++ b/src/pic16/glue.h @@ -0,0 +1,35 @@ +/*------------------------------------------------------------------------- + + SDCCglue.h - glues everything we have done together into one file. + Written By - Sandeep Dutta . sandeep.dutta@usa.net (1998) + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! +-------------------------------------------------------------------------*/ +#include "SDCCglobl.h" +#include "SDCCmem.h" + +#ifndef SDCCGLUE_H +#define SDCCGLUE_H 1 + +void glue (); +/* drdani Jan 30 2000 + This is needed in gen.c of z80 port */ +char *aopLiteral (value *, int); + +#endif diff --git a/src/pic16/main.c b/src/pic16/main.c new file mode 100644 index 00000000..8b3f3ae9 --- /dev/null +++ b/src/pic16/main.c @@ -0,0 +1,450 @@ +/** @file main.c + pic16 specific general functions. + + Note that mlh prepended _pic16_ on the static functions. Makes + it easier to set a breakpoint using the debugger. +*/ +#include "common.h" +#include "main.h" +#include "ralloc.h" +#include "device.h" +#include "SDCCutil.h" +//#include "gen.h" + + +static char _defaultRules[] = +{ +#include "peeph.rul" +}; + +/* list of key words used by msc51 */ +static char *_pic16_keywords[] = +{ + "at", + "bit", + "code", + "critical", + "data", + "far", + "idata", + "interrupt", + "near", + "pdata", + "reentrant", + "sfr", + "sbit", + "using", + "xdata", + "_data", + "_code", + "_generic", + "_near", + "_xdata", + "_pdata", + "_idata", + NULL +}; + +void pic16_pCodeInitRegisters(void); + +void pic16_assignRegisters (eBBlock ** ebbs, int count); + +static int regParmFlg = 0; /* determine if we can register a parameter */ + +static void +_pic16_init (void) +{ + asm_addTree (&asm_asxxxx_mapping); + pic16_pCodeInitRegisters(); +} + +static void +_pic16_reset_regparm () +{ + regParmFlg = 0; +} + +static int +_pic16_regparm (sym_link * l) +{ + /* for this processor it is simple + can pass only the first parameter in a register */ + //if (regParmFlg) + // return 0; + + regParmFlg++;// = 1; + return 1; +} + +static int +_process_pragma(const char *sz) +{ + static const char *WHITE = " \t"; + char *ptr = strtok((char *)sz, WHITE); + + if (startsWith (ptr, "memmap")) + { + char *start; + char *end; + char *type; + char *alias; + + start = strtok((char *)NULL, WHITE); + end = strtok((char *)NULL, WHITE); + type = strtok((char *)NULL, WHITE); + alias = strtok((char *)NULL, WHITE); + + if (start != (char *)NULL + && end != (char *)NULL + && type != (char *)NULL) { + value *startVal = constVal(start); + value *endVal = constVal(end); + value *aliasVal; + memRange r; + + if (alias == (char *)NULL) { + aliasVal = constVal(0); + } else { + aliasVal = constVal(alias); + } + + r.start_address = (int)floatFromVal(startVal); + r.end_address = (int)floatFromVal(endVal); + r.alias = (int)floatFromVal(aliasVal); + r.bank = (r.start_address >> 7) & 0xf; + + if (strcmp(type, "RAM") == 0) { + pic16_addMemRange(&r, 0); + } else if (strcmp(type, "SFR") == 0) { + pic16_addMemRange(&r, 1); + } else { + return 1; + } + } + + return 0; + } else if (startsWith (ptr, "maxram")) { + char *maxRAM = strtok((char *)NULL, WHITE); + + if (maxRAM != (char *)NULL) { + int maxRAMaddress; + value *maxRAMVal; + + maxRAMVal = constVal(maxRAM); + maxRAMaddress = (int)floatFromVal(maxRAMVal); + pic16_setMaxRAM(maxRAMaddress); + } + + return 0; + } + return 1; +} + +static bool +_pic16_parseOptions (int *pargc, char **argv, int *i) +{ + /* TODO: allow port-specific command line options to specify + * segment names here. + */ + return FALSE; +} + +static void +_pic16_finaliseOptions (void) +{ + + port->mem.default_local_map = data; + port->mem.default_globl_map = data; +#if 0 + /* Hack-o-matic: if we are using the flat24 model, + * adjust pointer sizes. + */ + if (options.model == MODEL_FLAT24) + { + + fprintf (stderr, "*** WARNING: you should use the '-mds390' option " + "for DS80C390 support. This code generator is " + "badly out of date and probably broken.\n"); + + port->s.fptr_size = 3; + port->s.gptr_size = 4; + port->stack.isr_overhead++; /* Will save dpx on ISR entry. */ +#if 1 + port->stack.call_overhead++; /* This acounts for the extra byte + * of return addres on the stack. + * but is ugly. There must be a + * better way. + */ +#endif + fReturn = fReturn390; + fReturnSize = 5; + } + + if (options.model == MODEL_LARGE) + { + port->mem.default_local_map = xdata; + port->mem.default_globl_map = xdata; + } + else + { + port->mem.default_local_map = data; + port->mem.default_globl_map = data; + } + + if (options.stack10bit) + { + if (options.model != MODEL_FLAT24) + { + fprintf (stderr, + "*** warning: 10 bit stack mode is only supported in flat24 model.\n"); + fprintf (stderr, "\t10 bit stack mode disabled.\n"); + options.stack10bit = 0; + } + else + { + /* Fixup the memory map for the stack; it is now in + * far space and requires a FPOINTER to access it. + */ + istack->fmap = 1; + istack->ptrType = FPOINTER; + } + } +#endif +} + +static void +_pic16_setDefaultOptions (void) +{ +} + +static const char * +_pic16_getRegName (struct regs *reg) +{ + if (reg) + return reg->name; + return "err"; +} + +extern char *pic16_processor_base_name(void); + +static void +_pic16_genAssemblerPreamble (FILE * of) +{ + char * name = pic16_processor_base_name(); + + if(!name) { + + name = "p18f452"; + fprintf(stderr,"WARNING: No Pic has been selected, defaulting to %s\n",name); + } + + fprintf (of, "\tlist\tp=%s\n",&name[1]); + fprintf (of, "\tinclude \"%s.inc\"\n",name); + fprintf (of, "\t__config _CONFIG1H,0x%x\n",pic16_getConfigWord(0x300001)); + fprintf (of, "\t__config _CONFIG2L,0x%x\n",pic16_getConfigWord(0x300002)); + fprintf (of, "\t__config _CONFIG2H,0x%x\n",pic16_getConfigWord(0x300003)); + fprintf (of, "\t__config _CONFIG3H,0x%x\n",pic16_getConfigWord(0x300005)); + fprintf (of, "\t__config _CONFIG4L,0x%x\n",pic16_getConfigWord(0x300006)); + fprintf (of, "\t__config _CONFIG5L,0x%x\n",pic16_getConfigWord(0x300008)); + fprintf (of, "\t__config _CONFIG5H,0x%x\n",pic16_getConfigWord(0x300009)); + fprintf (of, "\t__config _CONFIG6L,0x%x\n",pic16_getConfigWord(0x30000a)); + fprintf (of, "\t__config _CONFIG6H,0x%x\n",pic16_getConfigWord(0x30000b)); + fprintf (of, "\t__config _CONFIG7L,0x%x\n",pic16_getConfigWord(0x30000c)); + fprintf (of, "\t__config _CONFIG7H,0x%x\n",pic16_getConfigWord(0x30000d)); + fprintf (of, "\tradix dec\n"); +} + +/* Generate interrupt vector table. */ +static int +_pic16_genIVT (FILE * of, symbol ** interrupts, int maxInterrupts) +{ + int i; + + if (options.model != MODEL_FLAT24) + { + /* Let the default code handle it. */ + return FALSE; + } + + fprintf (of, "\t;ajmp\t__sdcc_gsinit_startup\n"); + + /* now for the other interrupts */ + for (i = 0; i < maxInterrupts; i++) + { + if (interrupts[i]) + { + fprintf (of, "\t;ljmp\t%s\n\t.ds\t4\n", interrupts[i]->rname); + } + else + { + fprintf (of, "\t;reti\n\t.ds\t7\n"); + } + } + + return TRUE; +} + +static bool +_hasNativeMulFor (iCode *ic, sym_link *left, sym_link *right) +{ + sym_link *test = NULL; + value *val; + + fprintf(stderr,"checking for native mult\n"); + + if ( ic->op != '*') + { + return FALSE; + } + + return TRUE; +/* + if ( IS_LITERAL (left)) + { + fprintf(stderr,"left is lit\n"); + test = left; + val = OP_VALUE (IC_LEFT (ic)); + } + else if ( IS_LITERAL (right)) + { + fprintf(stderr,"right is lit\n"); + test = left; + val = OP_VALUE (IC_RIGHT (ic)); + } + else + { + fprintf(stderr,"oops, neither is lit so no\n"); + return FALSE; + } + + if ( getSize (test) <= 2) + { + fprintf(stderr,"yep\n"); + return TRUE; + } + fprintf(stderr,"nope\n"); + + return FALSE; +*/ +} + +/** $1 is always the basename. + $2 is always the output file. + $3 varies + $l is the list of extra options that should be there somewhere... + MUST be terminated with a NULL. +*/ +static const char *_linkCmd[] = +{ + "aslink", "-nf", "$1", NULL +}; + +/* Sigh. This really is not good. For now, I recommend: + * sdcc -S -mpic16 file.c + * the -S option does not compile or link + */ +static const char *_asmCmd[] = +{ + "gpasm", "-c -I /usr/local/share/gpasm/header", "$1.asm", NULL + +}; + +/* Globals */ +PORT pic16_port = +{ + TARGET_ID_PIC16, + "pic16", + "MCU PIC16", /* Target name */ + "p18f452", /* Processor */ + { + TRUE, /* Emit glue around main */ + MODEL_SMALL | MODEL_LARGE | MODEL_FLAT24, + MODEL_SMALL + }, + { + _asmCmd, + NULL, + NULL, + NULL, + //"-plosgffc", /* Options with debug */ + //"-plosgff", /* Options without debug */ + 0, + ".asm", + NULL /* no do_assemble function */ + }, + { + _linkCmd, + NULL, + NULL, + ".rel" + }, + { + _defaultRules + }, + { + /* Sizes: char, short, int, long, ptr, fptr, gptr, bit, float, max */ + 1, 2, 2, 4, 2, 2, 2, 1, 4, 4 + /* TSD - I changed the size of gptr from 3 to 1. However, it should be + 2 so that we can accomodate the PIC's with 4 register banks (like the + 16f877) + */ + }, + { + "XSEG (XDATA)", + "STACK (DATA)", + "CSEG (CODE)", + "DSEG (DATA)", + "ISEG (DATA)", + "XSEG (XDATA)", + "BSEG (BIT)", + "RSEG (DATA)", + "GSINIT (CODE)", + "OSEG (OVR,DATA)", + "GSFINAL (CODE)", + "HOME (CODE)", + NULL, // xidata + NULL, // xinit + NULL, + NULL, + 1 // code is read only + }, + { + +1, 1, 4, 1, 1, 0 + }, + /* pic16 has an 8 bit mul */ + { + 1, -1 + }, + "_", + _pic16_init, + _pic16_parseOptions, + NULL, + _pic16_finaliseOptions, + _pic16_setDefaultOptions, + pic16_assignRegisters, + _pic16_getRegName, + _pic16_keywords, + _pic16_genAssemblerPreamble, + NULL, /* no genAssemblerEnd */ + _pic16_genIVT, + NULL, // _pic16_genXINIT + _pic16_reset_regparm, + _pic16_regparm, + _process_pragma, /* process a pragma */ + NULL, + _hasNativeMulFor, + FALSE, + 0, /* leave lt */ + 0, /* leave gt */ + 1, /* transform <= to ! > */ + 1, /* transform >= to ! < */ + 1, /* transform != to !(a == b) */ + 0, /* leave == */ + FALSE, /* No array initializer support. */ + 0, /* no CSE cost estimation yet */ + NULL, /* no builtin functions */ + GPOINTER, /* treat unqualified pointers as "generic" pointers */ + 1, /* reset labelKey to 1 */ + 1, /* globals & local static allowed */ + PORT_MAGIC +}; diff --git a/src/pic16/main.h b/src/pic16/main.h new file mode 100644 index 00000000..65552254 --- /dev/null +++ b/src/pic16/main.h @@ -0,0 +1,8 @@ +#ifndef MAIN_INCLUDE +#define MAIN_INCLUDE + +bool x_parseOptions (char **argv, int *pargc); +void x_setDefaultOptions (void); +void x_finaliseOptions (void); + +#endif diff --git a/src/pic16/pcode.c b/src/pic16/pcode.c new file mode 100644 index 00000000..12fed716 --- /dev/null +++ b/src/pic16/pcode.c @@ -0,0 +1,6547 @@ +/*------------------------------------------------------------------------- + + pcode.c - post code generation + Written By - Scott Dattalo scott@dattalo.com + Ported to PIC16 By - 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. +-------------------------------------------------------------------------*/ + + +#include + +#include "common.h" // Include everything in the SDCC src directory +#include "newalloc.h" + + +#include "pcode.h" +#include "pcodeflow.h" +#include "ralloc.h" +#include "device.h" + +#if defined(__BORLANDC__) || defined(_MSC_VER) +#define STRCASECMP stricmp +#else +#define STRCASECMP strcasecmp +#endif + +/****************************************************************/ +/****************************************************************/ + +static peepCommand peepCommands[] = { + + {NOTBITSKIP, "_NOTBITSKIP_"}, + {BITSKIP, "_BITSKIP_"}, + {INVERTBITSKIP, "_INVERTBITSKIP_"}, + + {-1, NULL} +}; + + + +// Eventually this will go into device dependent files: +pCodeOpReg pic16_pc_status = {{PO_STATUS, "_STATUS"}, -1, NULL,0,NULL}; +pCodeOpReg pic16_pc_indf0 = {{PO_INDF0, "INDF0"}, -1, NULL,0,NULL}; +pCodeOpReg pic16_pc_fsr0 = {{PO_FSR0, "FSR0"}, -1, NULL,0,NULL}; +pCodeOpReg pic16_pc_intcon = {{PO_INTCON, ""}, -1, NULL,0,NULL}; +pCodeOpReg pic16_pc_pcl = {{PO_PCL, "PCL"}, -1, NULL,0,NULL}; +pCodeOpReg pic16_pc_pclath = {{PO_PCLATH, "_PCLATH"}, -1, NULL,0,NULL}; +pCodeOpReg pic16_pc_wreg = {{PO_WREG, "WREG"}, -1, NULL,0,NULL}; +pCodeOpReg pic16_pc_bsr = {{PO_BSR, "BSR"}, -1, NULL,0,NULL}; + +pCodeOpReg pic16_pc_kzero = {{PO_GPR_REGISTER, "KZ"}, -1, NULL,0,NULL}; +pCodeOpReg pic16_pc_wsave = {{PO_GPR_REGISTER, "WSAVE"}, -1, NULL,0,NULL}; +pCodeOpReg pic16_pc_ssave = {{PO_GPR_REGISTER, "SSAVE"}, -1, NULL,0,NULL}; + +static int mnemonics_initialized = 0; + + +static hTab *pic16MnemonicsHash = NULL; +static hTab *pic16pCodePeepCommandsHash = NULL; + + + +static pFile *the_pFile = NULL; +static pBlock *pb_dead_pcodes = NULL; + +/* Hardcoded flags to change the behavior of the PIC port */ +static int peepOptimizing = 1; /* run the peephole optimizer if nonzero */ +static int functionInlining = 1; /* inline functions if nonzero */ +int pic16_debug_verbose = 0; /* Set true to inundate .asm file */ + +static int GpCodeSequenceNumber = 1; +static int GpcFlowSeq = 1; + +extern void pic16_RemoveUnusedRegisters(void); +extern void pic16_RegsUnMapLiveRanges(void); +extern void pic16_BuildFlowTree(pBlock *pb); +extern void pic16_pCodeRegOptimizeRegUsage(int level); +extern int pic16_picIsInitialized(void); +#if !OPT_DISABLE_PIC +// From pic/pcode.c: +extern void SAFE_snprintf(char **str, size_t *size, const char *format, ...); +extern int mnem2key(char const *mnem); +#endif // OPT_DISABLE_PIC + +/****************************************************************/ +/* Forward declarations */ +/****************************************************************/ + +void pic16_unlinkpCode(pCode *pc); +#if 0 +static void genericAnalyze(pCode *pc); +static void AnalyzeGOTO(pCode *pc); +static void AnalyzeSKIP(pCode *pc); +static void AnalyzeRETURN(pCode *pc); +#endif + +static void genericDestruct(pCode *pc); +static void genericPrint(FILE *of,pCode *pc); + +static void pCodePrintLabel(FILE *of, pCode *pc); +static void pCodePrintFunction(FILE *of, pCode *pc); +static void pCodeOpPrint(FILE *of, pCodeOp *pcop); +static char *pic16_get_op_from_instruction( pCodeInstruction *pcc); +char *pic16_get_op( pCodeOp *pcop,char *buff,int buf_size); +int pCodePeepMatchLine(pCodePeep *peepBlock, pCode *pcs, pCode *pcd); +int pic16_pCodePeepMatchRule(pCode *pc); +static void pBlockStats(FILE *of, pBlock *pb); +static pBlock *newpBlock(void); +extern void pic16_pCodeInsertAfter(pCode *pc1, pCode *pc2); +extern pCodeOp *pic16_popCopyReg(pCodeOpReg *pc); +pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval); +void pic16_pCodeRegMapLiveRanges(pBlock *pb); + + +/****************************************************************/ +/* PIC Instructions */ +/****************************************************************/ + +pCodeInstruction pic16_pciADDWF = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_ADDWF, + "ADDWF", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 1,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_W | PCC_REGISTER), // inCond + (PCC_REGISTER | PCC_Z) // outCond +}; + +pCodeInstruction pic16_pciADDFW = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_ADDFW, + "ADDWF", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 0,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_W | PCC_REGISTER), // inCond + (PCC_W | PCC_Z) // outCond +}; + +pCodeInstruction pic16_pciADDWFC = { // mdubuc - New + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_ADDWFC, + "ADDWFC", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 1,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_W | PCC_REGISTER | PCC_C), // inCond + (PCC_REGISTER | PCC_Z) // outCond +}; + +pCodeInstruction pic16_pciADDFWC = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_ADDFWC, + "ADDWFC", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 0,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_W | PCC_REGISTER | PCC_C), // inCond + (PCC_W | PCC_Z) // outCond +}; + +pCodeInstruction pic16_pciADDLW = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_ADDLW, + "ADDLW", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 1, // num ops + 0,0, // dest, bit instruction + 0,0, // branch, skip + 1, // literal operand + 0, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_W | PCC_LITERAL), // inCond + (PCC_W | PCC_Z | PCC_C | PCC_DC | PCC_OV | PCC_N) // outCond +}; + +pCodeInstruction pic16_pciANDLW = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_ANDLW, + "ANDLW", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 1, // num ops + 0,0, // dest, bit instruction + 0,0, // branch, skip + 1, // literal operand + 0, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_W | PCC_LITERAL), // inCond + (PCC_W | PCC_Z | PCC_N) // outCond +}; + +pCodeInstruction pic16_pciANDWF = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_ANDWF, + "ANDWF", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 1,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_W | PCC_REGISTER), // inCond + (PCC_REGISTER | PCC_Z | PCC_N) // outCond +}; + +pCodeInstruction pic16_pciANDFW = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_ANDFW, + "ANDWF", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 0,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_W | PCC_REGISTER), // inCond + (PCC_W | PCC_Z) // outCond +}; + +pCodeInstruction pic16_pciBC = { // mdubuc - New + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_BC, + "BC", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 1, // num ops + 0,0, // dest, bit instruction + 1,0, // branch, skip + 0, // literal operand + 0, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_REL_ADDR | PCC_C), // inCond + PCC_NONE // outCond +}; + +pCodeInstruction pic16_pciBCF = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_BCF, + "BCF", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 1,1, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_BSF, + (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond + PCC_REGISTER // outCond +}; + +pCodeInstruction pic16_pciBN = { // mdubuc - New + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_BN, + "BN", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 1, // num ops + 0,0, // dest, bit instruction + 1,0, // branch, skip + 0, // literal operand + 0, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_REL_ADDR | PCC_N), // inCond + PCC_NONE // outCond +}; + +pCodeInstruction pic16_pciBNC = { // mdubuc - New + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_BNC, + "BNC", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 1, // num ops + 0,0, // dest, bit instruction + 1,0, // branch, skip + 0, // literal operand + 0, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_REL_ADDR | PCC_C), // inCond + PCC_NONE // outCond +}; + +pCodeInstruction pic16_pciBNN = { // mdubuc - New + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_BNN, + "BNN", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 1, // num ops + 0,0, // dest, bit instruction + 1,0, // branch, skip + 0, // literal operand + 0, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_REL_ADDR | PCC_N), // inCond + PCC_NONE // outCond +}; + +pCodeInstruction pic16_pciBNOV = { // mdubuc - New + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_BNOV, + "BNOV", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 1, // num ops + 0,0, // dest, bit instruction + 1,0, // branch, skip + 0, // literal operand + 0, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_REL_ADDR | PCC_OV), // inCond + PCC_NONE // outCond +}; + +pCodeInstruction pic16_pciBNZ = { // mdubuc - New + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_BNZ, + "BNZ", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 1, // num ops + 0,0, // dest, bit instruction + 1,0, // branch, skip + 0, // literal operand + 0, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_REL_ADDR | PCC_Z), // inCond + PCC_NONE // outCond +}; + +pCodeInstruction pic16_pciBOV = { // mdubuc - New + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_BOV, + "BOV", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 1, // num ops + 0,0, // dest, bit instruction + 1,0, // branch, skip + 0, // literal operand + 0, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_REL_ADDR | PCC_OV), // inCond + PCC_NONE // outCond +}; + +pCodeInstruction pic16_pciBRA = { // mdubuc - New + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_BRA, + "BRA", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 1, // num ops + 0,0, // dest, bit instruction + 1,0, // branch, skip + 0, // literal operand + 0, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + PCC_REL_ADDR, // inCond + PCC_NONE // outCond +}; + +pCodeInstruction pic16_pciBSF = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_BSF, + "BSF", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 1,1, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_BCF, + (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond + (PCC_REGISTER | PCC_EXAMINE_PCOP) // outCond +}; + +pCodeInstruction pic16_pciBTFSC = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // AnalyzeSKIP, + genericDestruct, + genericPrint}, + POC_BTFSC, + "BTFSC", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 0,1, // dest, bit instruction + 1,1, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_BTFSS, + (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond + PCC_EXAMINE_PCOP // outCond +}; + +pCodeInstruction pic16_pciBTFSS = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // AnalyzeSKIP, + genericDestruct, + genericPrint}, + POC_BTFSS, + "BTFSS", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 0,1, // dest, bit instruction + 1,1, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_BTFSC, + (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond + PCC_EXAMINE_PCOP // outCond +}; + +pCodeInstruction pic16_pciBTG = { // mdubuc - New + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_BTG, + "BTG", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 0,1, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond + (PCC_REGISTER | PCC_EXAMINE_PCOP) // outCond +}; + +pCodeInstruction pic16_pciBZ = { // mdubuc - New + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_BZ, + "BZ", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 1, // num ops + 0,0, // dest, bit instruction + 1,0, // branch, skip + 0, // literal operand + 0, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + PCC_Z, // inCond + PCC_NONE // outCond +}; + +pCodeInstruction pic16_pciCALL = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_CALL, + "CALL", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 2, // num ops + 0,0, // dest, bit instruction + 1,0, // branch, skip + 0, // literal operand + 0, // RAM access bit + 1, // fast call/return mode select bit + POC_NOP, + PCC_NONE, // inCond + PCC_NONE // outCond +}; + +pCodeInstruction pic16_pciCOMF = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_COMF, + "COMF", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 1,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + PCC_REGISTER, // inCond + PCC_REGISTER // outCond +}; + +pCodeInstruction pic16_pciCOMFW = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_COMFW, + "COMF", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 0,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + PCC_REGISTER, // inCond + PCC_W // outCond +}; + +pCodeInstruction pic16_pciCLRF = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_CLRF, + "CLRF", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 2, // num ops + 0,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + PCC_REGISTER, // inCond + PCC_REGISTER // outCond +}; + +pCodeInstruction pic16_pciCLRWDT = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_CLRWDT, + "CLRWDT", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 0, // num ops + 0,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 0, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + PCC_NONE, // inCond + PCC_NONE // outCond +}; + +pCodeInstruction pic16_pciCPFSEQ = { // mdubuc - New + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_CPFSEQ, + "CPFSEQ", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 2, // num ops + 0,0, // dest, bit instruction + 1,1, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_W | PCC_REGISTER), // inCond + PCC_NONE // outCond +}; + +pCodeInstruction pic16_pciCPFSGT = { // mdubuc - New + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_CPFSGT, + "CPFSGT", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 2, // num ops + 0,0, // dest, bit instruction + 1,1, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_W | PCC_REGISTER), // inCond + PCC_NONE // outCond +}; + +pCodeInstruction pic16_pciCPFSLT = { // mdubuc - New + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_CPFSLT, + "CPFSLT", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 2, // num ops + 1,0, // dest, bit instruction + 1,1, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_W | PCC_REGISTER), // inCond + PCC_NONE // outCond +}; + +pCodeInstruction pic16_pciDAW = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_DAW, + "DAW", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 0, // num ops + 0,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 0, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + PCC_W, // inCond + (PCC_W | PCC_C) // outCond +}; + +pCodeInstruction pic16_pciDCFSNZ = { // mdubuc - New + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_DCFSNZ, + "DCFSNZ", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 1,0, // dest, bit instruction + 1,1, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + PCC_REGISTER, // inCond + PCC_REGISTER // outCond +}; + +pCodeInstruction pic16_pciDCFSNZW = { // mdubuc - New + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_DCFSNZW, + "DCFSNZ", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 0,0, // dest, bit instruction + 1,1, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + PCC_REGISTER, // inCond + PCC_W // outCond +}; + +pCodeInstruction pic16_pciDECF = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_DECF, + "DECF", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 1,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + PCC_REGISTER, // inCond + PCC_REGISTER // outCond +}; + +pCodeInstruction pic16_pciDECFW = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_DECFW, + "DECF", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 0,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + PCC_REGISTER, // inCond + PCC_W // outCond +}; + +pCodeInstruction pic16_pciDECFSZ = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // AnalyzeSKIP, + genericDestruct, + genericPrint}, + POC_DECFSZ, + "DECFSZ", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 1,0, // dest, bit instruction + 1,1, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + PCC_REGISTER, // inCond + PCC_REGISTER // outCond +}; + +pCodeInstruction pic16_pciDECFSZW = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // AnalyzeSKIP, + genericDestruct, + genericPrint}, + POC_DECFSZW, + "DECFSZ", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 0,0, // dest, bit instruction + 1,1, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + PCC_REGISTER, // inCond + PCC_W // outCond +}; + +pCodeInstruction pic16_pciGOTO = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // AnalyzeGOTO, + genericDestruct, + genericPrint}, + POC_GOTO, + "GOTO", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 1, // num ops + 0,0, // dest, bit instruction + 1,0, // branch, skip + 0, // literal operand + 0, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + PCC_REL_ADDR, // inCond + PCC_NONE // outCond +}; + +pCodeInstruction pic16_pciINCF = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_INCF, + "INCF", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 1,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + PCC_REGISTER, // inCond + (PCC_REGISTER | PCC_C | PCC_DC | PCC_Z | PCC_OV | PCC_N) // outCond +}; + +pCodeInstruction pic16_pciINCFW = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_INCFW, + "INCF", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 0,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + PCC_REGISTER, // inCond + PCC_W // outCond +}; + +pCodeInstruction pic16_pciINCFSZ = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // AnalyzeSKIP, + genericDestruct, + genericPrint}, + POC_INCFSZ, + "INCFSZ", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 1,0, // dest, bit instruction + 1,1, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + PCC_REGISTER, // inCond + PCC_REGISTER // outCond +}; + +pCodeInstruction pic16_pciINCFSZW = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // AnalyzeSKIP, + genericDestruct, + genericPrint}, + POC_INCFSZW, + "INCFSZ", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 0,0, // dest, bit instruction + 1,1, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + PCC_REGISTER, // inCond + PCC_W // outCond +}; + +pCodeInstruction pic16_pciINFSNZ = { // mdubuc - New + {PC_OPCODE, NULL, NULL, 0, NULL, + // AnalyzeSKIP, + genericDestruct, + genericPrint}, + POC_INFSNZ, + "INCFSNZ", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 1,0, // dest, bit instruction + 1,1, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + PCC_REGISTER, // inCond + PCC_REGISTER // outCond +}; + +pCodeInstruction pic16_pciIORWF = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_IORWF, + "IORWF", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 1,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_W | PCC_REGISTER), // inCond + (PCC_REGISTER | PCC_Z | PCC_N) // outCond +}; + +pCodeInstruction pic16_pciIORFW = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_IORFW, + "IORWF", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 0,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_W | PCC_REGISTER), // inCond + (PCC_W | PCC_Z | PCC_N) // outCond +}; + +pCodeInstruction pic16_pciIORLW = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_IORLW, + "IORLW", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 1, // num ops + 0,0, // dest, bit instruction + 0,0, // branch, skip + 1, // literal operand + 0, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_W | PCC_LITERAL), // inCond + (PCC_W | PCC_Z | PCC_N) // outCond +}; + +pCodeInstruction pic16_pciLFSR = { // mdubuc - New + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_LFSR, + "LFSR", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 2, // num ops + 0,0, // dest, bit instruction + 0,0, // branch, skip + 1, // literal operand + 0, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_REGISTER | PCC_LITERAL), // mdubuc - Should we use a special syntax for + // f (identifies FSRx)? + PCC_REGISTER // outCond +}; + +pCodeInstruction pic16_pciMOVF = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_MOVF, + "MOVF", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 1,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + PCC_REGISTER, // inCond + (PCC_Z | PCC_N) // outCond +}; + +pCodeInstruction pic16_pciMOVFW = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_MOVFW, + "MOVF", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 0,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + PCC_REGISTER, // inCond + (PCC_W | PCC_Z) // outCond +}; + +pCodeInstruction pic16_pciMOVFF = { // mdubuc - New + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_MOVFF, + "MOVFF", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 2, // num ops + 0,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 0, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + PCC_REGISTER, // inCond + PCC_REGISTER2 // outCond +}; + +pCodeInstruction pic16_pciMOVLB = { // mdubuc - New + {PC_OPCODE, NULL, NULL, 0, NULL, + genericDestruct, + genericPrint}, + POC_MOVLB, + "MOVLB", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 1, // num ops + 0,0, // dest, bit instruction + 0,0, // branch, skip + 1, // literal operand + 0, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_NONE | PCC_LITERAL), // inCond + PCC_REGISTER // outCond - BSR +}; + +pCodeInstruction pic16_pciMOVLW = { + {PC_OPCODE, NULL, NULL, 0, NULL, + genericDestruct, + genericPrint}, + POC_MOVLW, + "MOVLW", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 1, // num ops + 0,0, // dest, bit instruction + 0,0, // branch, skip + 1, // literal operand + 0, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_NONE | PCC_LITERAL), // inCond + PCC_W // outCond +}; + +pCodeInstruction pic16_pciMOVWF = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_MOVWF, + "MOVWF", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 2, // num ops + 0,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + PCC_REGISTER, // inCond + PCC_W // outCond +}; + +pCodeInstruction pic16_pciMULLW = { // mdubuc - New + {PC_OPCODE, NULL, NULL, 0, NULL, + genericDestruct, + genericPrint}, + POC_MULLW, + "MULLW", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 1, // num ops + 0,0, // dest, bit instruction + 0,0, // branch, skip + 1, // literal operand + 0, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_W | PCC_LITERAL), // inCond + PCC_REGISTER // outCond - PROD +}; + +pCodeInstruction pic16_pciMULWF = { // mdubuc - New + {PC_OPCODE, NULL, NULL, 0, NULL, + genericDestruct, + genericPrint}, + POC_MULWF, + "MULWF", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 2, // num ops + 0,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_W | PCC_REGISTER), // inCond + PCC_REGISTER // outCond - PROD +}; + +pCodeInstruction pic16_pciNEGF = { // mdubuc - New + {PC_OPCODE, NULL, NULL, 0, NULL, + genericDestruct, + genericPrint}, + POC_NEGF, + "NEGF", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 2, // num ops + 0,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + PCC_REGISTER, // inCond + (PCC_REGISTER | PCC_C | PCC_DC | PCC_OV | PCC_N) // outCond +}; + +pCodeInstruction pic16_pciNOP = { + {PC_OPCODE, NULL, NULL, 0, NULL, + genericDestruct, + genericPrint}, + POC_NOP, + "NOP", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 0, // num ops + 0,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 0, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + PCC_NONE, // inCond + PCC_NONE // outCond +}; + +pCodeInstruction pic16_pciPOP = { // mdubuc - New + {PC_OPCODE, NULL, NULL, 0, NULL, + genericDestruct, + genericPrint}, + POC_POP, + "POP", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 0, // num ops + 0,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 0, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + PCC_NONE, // inCond + PCC_NONE // outCond +}; + +pCodeInstruction pic16_pciPUSH = { + {PC_OPCODE, NULL, NULL, 0, NULL, + genericDestruct, + genericPrint}, + POC_PUSH, + "PUSH", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 0, // num ops + 0,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 0, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + PCC_NONE, // inCond + PCC_NONE // outCond +}; + +pCodeInstruction pic16_pciRCALL = { // mdubuc - New + {PC_OPCODE, NULL, NULL, 0, NULL, + genericDestruct, + genericPrint}, + POC_RCALL, + "RCALL", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 1, // num ops + 0,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 0, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + PCC_REL_ADDR, // inCond + PCC_NONE // outCond +}; + +pCodeInstruction pic16_pciRETFIE = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // AnalyzeRETURN, + genericDestruct, + genericPrint}, + POC_RETFIE, + "RETFIE", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 1, // num ops + 0,0, // dest, bit instruction + 1,0, // branch, skip + 0, // literal operand + 0, // RAM access bit + 1, // fast call/return mode select bit + POC_NOP, + PCC_NONE, // inCond + PCC_NONE // outCond (not true... affects the GIE bit too) +}; + +pCodeInstruction pic16_pciRETLW = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // AnalyzeRETURN, + genericDestruct, + genericPrint}, + POC_RETLW, + "RETLW", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 1, // num ops + 0,0, // dest, bit instruction + 1,0, // branch, skip + 1, // literal operand + 0, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + PCC_LITERAL, // inCond + PCC_W // outCond +}; + +pCodeInstruction pic16_pciRETURN = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // AnalyzeRETURN, + genericDestruct, + genericPrint}, + POC_RETURN, + "RETURN", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 1, // num ops + 0,0, // dest, bit instruction + 1,0, // branch, skip + 0, // literal operand + 0, // RAM access bit + 1, // fast call/return mode select bit + POC_NOP, + PCC_NONE, // inCond + PCC_NONE // outCond +}; +pCodeInstruction pic16_pciRLCF = { // mdubuc - New + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_RLCF, + "RLCF", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 1,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_C | PCC_REGISTER), // inCond + (PCC_REGISTER | PCC_C | PCC_Z | PCC_N) // outCond +}; + +pCodeInstruction pic16_pciRLCFW = { // mdubuc - New + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_RLCFW, + "RLCF", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 0,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_C | PCC_REGISTER), // inCond + (PCC_W | PCC_C | PCC_Z | PCC_N) // outCond +}; + +pCodeInstruction pic16_pciRLNCF = { // mdubuc - New + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_RLNCF, + "RLNCF", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 1,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + PCC_REGISTER, // inCond + (PCC_REGISTER | PCC_Z | PCC_N) // outCond +}; +pCodeInstruction pic16_pciRLNCFW = { // mdubuc - New + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_RLNCFW, + "RLNCF", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 0,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + PCC_REGISTER, // inCond + (PCC_W | PCC_Z | PCC_N) // outCond +}; +pCodeInstruction pic16_pciRRCF = { // mdubuc - New + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_RRCF, + "RRCF", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 1,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_C | PCC_REGISTER), // inCond + (PCC_REGISTER | PCC_C | PCC_Z | PCC_N) // outCond +}; +pCodeInstruction pic16_pciRRCFW = { // mdubuc - New + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_RRCFW, + "RRCF", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 0,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_C | PCC_REGISTER), // inCond + (PCC_W | PCC_C | PCC_Z | PCC_N) // outCond +}; +pCodeInstruction pic16_pciRRNCF = { // mdubuc - New + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_RRNCF, + "RRNCF", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 1,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + PCC_REGISTER, // inCond + (PCC_REGISTER | PCC_Z | PCC_N) // outCond +}; + +pCodeInstruction pic16_pciRRNCFW = { // mdubuc - New + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_RRNCFW, + "RRNCF", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 0,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + PCC_REGISTER, // inCond + (PCC_W | PCC_Z | PCC_N) // outCond +}; + +pCodeInstruction pic16_pciSETF = { // mdubuc - New + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_SETF, + "SETF", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 2, // num ops + 0,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + PCC_REGISTER, // inCond + PCC_REGISTER // outCond +}; + +pCodeInstruction pic16_pciSUBLW = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_SUBLW, + "SUBLW", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 1, // num ops + 0,0, // dest, bit instruction + 0,0, // branch, skip + 1, // literal operand + 0, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_W | PCC_LITERAL), // inCond + (PCC_W | PCC_C | PCC_DC | PCC_Z | PCC_OV | PCC_N) // outCond +}; + +pCodeInstruction pic16_pciSUBFWB = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_SUBFWB, + "SUBFWB", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 1,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_W | PCC_REGISTER | PCC_C), // inCond + (PCC_W | PCC_C | PCC_DC | PCC_Z | PCC_OV | PCC_N) // outCond +}; + +pCodeInstruction pic16_pciSUBWF = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_SUBWF, + "SUBWF", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 1,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_W | PCC_REGISTER), // inCond + (PCC_REGISTER | PCC_Z) // outCond +}; + +pCodeInstruction pic16_pciSUBFW = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_SUBFW, + "SUBWF", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 0,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_W | PCC_REGISTER), // inCond + (PCC_W | PCC_Z | PCC_OV | PCC_N) // outCond +}; + +pCodeInstruction pic16_pciSUBFWB_D1 = { // mdubuc - New + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_SUBFWB_D1, + "SUBFWB", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 1,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_W | PCC_REGISTER | PCC_C), // inCond + (PCC_REGISTER | PCC_Z | PCC_C | PCC_DC | PCC_OV | PCC_N) // outCond +}; + +pCodeInstruction pic16_pciSUBFWB_D0 = { // mdubuc - New + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_SUBFWB_D0, + "SUBFWB", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 0,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_W | PCC_REGISTER | PCC_C), // inCond + (PCC_W | PCC_Z | PCC_C | PCC_DC | PCC_OV | PCC_N) // outCond +}; + +pCodeInstruction pic16_pciSUBWFB_D1 = { // mdubuc - New + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_SUBWFB_D1, + "SUBWFB", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 1,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_W | PCC_REGISTER | PCC_C), // inCond + (PCC_REGISTER | PCC_Z | PCC_C | PCC_DC | PCC_OV | PCC_N) // outCond +}; + +pCodeInstruction pic16_pciSUBWFB_D0 = { // mdubuc - New + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_SUBWFB_D0, + "SUBWFB", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 0,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_W | PCC_REGISTER | PCC_C), // inCond + (PCC_W | PCC_Z | PCC_C | PCC_DC | PCC_OV | PCC_N) // outCond +}; + +pCodeInstruction pic16_pciSWAPF = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_SWAPF, + "SWAPF", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 1,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_REGISTER), // inCond + (PCC_REGISTER) // outCond +}; + +pCodeInstruction pic16_pciSWAPFW = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_SWAPFW, + "SWAPF", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 0,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_REGISTER), // inCond + (PCC_W) // outCond +}; + +// mdubuc - Remove TRIS + +pCodeInstruction pic16_pciTRIS = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_TRIS, + "TRIS", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 1, // num ops + 0,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + POC_NOP, + PCC_NONE, // inCond + PCC_REGISTER // outCond +}; + +pCodeInstruction pic16_pciTSTFSZ = { // mdubuc - New + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_TSTFSZ, + "TSTFSZ", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 2, // num ops + 0,0, // dest, bit instruction + 1,1, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + PCC_REGISTER, // inCond + PCC_NONE // outCond +}; + +pCodeInstruction pic16_pciXORWF = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_XORWF, + "XORWF", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 1,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_W | PCC_REGISTER), // inCond + (PCC_REGISTER | PCC_Z | PCC_N) // outCond +}; + +pCodeInstruction pic16_pciXORFW = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_XORFW, + "XORWF", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 3, // num ops + 0,0, // dest, bit instruction + 0,0, // branch, skip + 0, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_W | PCC_REGISTER), // inCond + (PCC_W | PCC_Z | PCC_N) // outCond +}; + +pCodeInstruction pic16_pciXORLW = { + {PC_OPCODE, NULL, NULL, 0, NULL, + // genericAnalyze, + genericDestruct, + genericPrint}, + POC_XORLW, + "XORLW", + NULL, // from branch + NULL, // to branch + NULL, // label + NULL, // operand + NULL, // flow block + NULL, // C source + 1, // num ops + 0,0, // dest, bit instruction + 0,0, // branch, skip + 1, // literal operand + 1, // RAM access bit + 0, // fast call/return mode select bit + POC_NOP, + (PCC_W | PCC_LITERAL), // inCond + (PCC_W | PCC_Z | PCC_C | PCC_DC | PCC_N) // outCond +}; + + +#define MAX_PIC16MNEMONICS 100 +pCodeInstruction *pic16Mnemonics[MAX_PIC16MNEMONICS]; + +#if OPT_DISABLE_PIC +/* This definition needs to be part of configure.in */ +// #define USE_VSNPRINTF + +#ifdef USE_VSNPRINTF + // Alas, vsnprintf is not ANSI standard, and does not exist + // on Solaris (and probably other non-Gnu flavored Unixes). + +/*-----------------------------------------------------------------*/ +/* SAFE_snprintf - like snprintf except the string pointer is */ +/* after the string has been printed to. This is */ +/* useful for printing to string as though if it */ +/* were a stream. */ +/*-----------------------------------------------------------------*/ +void SAFE_snprintf(char **str, size_t *size, const char *format, ...) +{ + va_list val; + int len; + + if(!str || !*str) + return; + + va_start(val, format); + + vsnprintf(*str, *size, format, val); + + va_end (val); + + len = strlen(*str); + if(len > *size) { + fprintf(stderr,"WARNING, it looks like %s has overflowed\n",__FUNCTION__); + fprintf(stderr,"len = %d is > str size %d\n",len,*size); + } + + *str += len; + *size -= len; + +} + +#else // USE_VSNPRINTF + +// This version is *not* safe, despite the name. + +void SAFE_snprintf(char **str, size_t *size, const char *format, ...) +{ + va_list val; + int len; + static char buffer[1024]; /* grossly conservative, but still not inherently safe */ + + if(!str || !*str) + return; + + va_start(val, format); + + vsprintf(buffer, format, val); + va_end (val); + + len = strlen(buffer); + if(len > *size) { + fprintf(stderr,"WARNING, it looks like %s has overflowed\n",__FUNCTION__); + fprintf(stderr,"len = %d is > str size %d\n",len,*size); + } + + strcpy(*str, buffer); + *str += len; + *size -= len; + +} + +#endif // USE_VSNPRINTF + +#endif // OPT_DISABLE_PIC + + +extern void pic16_initStack(int base_address, int size); +extern regs *pic16_allocProcessorRegister(int rIdx, char * name, short po_type, int alias); +extern regs *pic16_allocInternalRegister(int rIdx, char * name, short po_type, int alias); +extern void pic16_init_pic(char *); + +void pic16_pCodeInitRegisters(void) +{ + static int initialized=0; + + if(initialized) + return; + initialized = 1; + + pic16_initStack(0xfff, 8); + pic16_init_pic(port->processor); + + pic16_pc_status.r = pic16_allocProcessorRegister(IDX_STATUS,"_STATUS", PO_STATUS, 0x80); + pic16_pc_pcl.r = pic16_allocProcessorRegister(IDX_PCL,"PCL", PO_PCL, 0x80); + pic16_pc_pclath.r = pic16_allocProcessorRegister(IDX_PCLATH,"_PCLATH", PO_PCLATH, 0x80); + pic16_pc_fsr0.r = pic16_allocProcessorRegister(IDX_FSR0,"FSR0", PO_FSR0, 0x80); + pic16_pc_indf0.r = pic16_allocProcessorRegister(IDX_INDF0,"INDF0", PO_INDF0, 0x80); + pic16_pc_intcon.r = pic16_allocProcessorRegister(IDX_INTCON,"INTCON", PO_INTCON, 0x80); + pic16_pc_wreg.r = pic16_allocProcessorRegister(IDX_WREG,"WREG", PO_WREG, 0x80); + + pic16_pc_status.rIdx = IDX_STATUS; + pic16_pc_fsr0.rIdx = IDX_FSR0; + pic16_pc_indf0.rIdx = IDX_INDF0; + pic16_pc_intcon.rIdx = IDX_INTCON; + pic16_pc_pcl.rIdx = IDX_PCL; + pic16_pc_pclath.rIdx = IDX_PCLATH; + pic16_pc_wreg.rIdx = IDX_WREG; + + pic16_pc_kzero.r = pic16_allocInternalRegister(IDX_KZ,"KZ",PO_GPR_REGISTER,0); + pic16_pc_ssave.r = pic16_allocInternalRegister(IDX_SSAVE,"SSAVE", PO_GPR_REGISTER, 0x80); + pic16_pc_wsave.r = pic16_allocInternalRegister(IDX_WSAVE,"WSAVE", PO_GPR_REGISTER, 0); + + pic16_pc_kzero.rIdx = IDX_KZ; + pic16_pc_wsave.rIdx = IDX_WSAVE; + pic16_pc_ssave.rIdx = IDX_SSAVE; + + /* probably should put this in a separate initialization routine */ + pb_dead_pcodes = newpBlock(); + +} + +#if OPT_DISABLE_PIC +/*-----------------------------------------------------------------*/ +/* mnem2key - convert a pic mnemonic into a hash key */ +/* (BTW - this spreads the mnemonics quite well) */ +/* */ +/*-----------------------------------------------------------------*/ + +int mnem2key(char const *mnem) +{ + int key = 0; + + if(!mnem) + return 0; + + while(*mnem) { + + key += toupper(*mnem++) +1; + + } + + return (key & 0x1f); + +} +#endif // OPT_DISABLE_PIC + +void pic16initMnemonics(void) +{ + int i = 0; + int key; + // char *str; + pCodeInstruction *pci; + + if(mnemonics_initialized) + return; + + // NULL out the array before making the assignments + // since we check the array contents below this initialization. + + for (i = 0; i < MAX_PIC16MNEMONICS; i++) { + pic16Mnemonics[i] = NULL; + } + + pic16Mnemonics[POC_ADDLW] = &pic16_pciADDLW; + pic16Mnemonics[POC_ADDWF] = &pic16_pciADDWF; + pic16Mnemonics[POC_ADDFW] = &pic16_pciADDFW; + pic16Mnemonics[POC_ADDWFC] = &pic16_pciADDWFC; + pic16Mnemonics[POC_ADDFWC] = &pic16_pciADDFWC; + pic16Mnemonics[POC_ANDLW] = &pic16_pciANDLW; + pic16Mnemonics[POC_ANDWF] = &pic16_pciANDWF; + pic16Mnemonics[POC_ANDFW] = &pic16_pciANDFW; + pic16Mnemonics[POC_BC] = &pic16_pciBC; + pic16Mnemonics[POC_BCF] = &pic16_pciBCF; + pic16Mnemonics[POC_BN] = &pic16_pciBN; + pic16Mnemonics[POC_BNC] = &pic16_pciBNC; + pic16Mnemonics[POC_BNN] = &pic16_pciBNN; + pic16Mnemonics[POC_BNOV] = &pic16_pciBNOV; + pic16Mnemonics[POC_BNZ] = &pic16_pciBNZ; + pic16Mnemonics[POC_BOV] = &pic16_pciBOV; + pic16Mnemonics[POC_BRA] = &pic16_pciBRA; + pic16Mnemonics[POC_BSF] = &pic16_pciBSF; + pic16Mnemonics[POC_BTFSC] = &pic16_pciBTFSC; + pic16Mnemonics[POC_BTFSS] = &pic16_pciBTFSS; + pic16Mnemonics[POC_BTG] = &pic16_pciBTG; + pic16Mnemonics[POC_BZ] = &pic16_pciBZ; + pic16Mnemonics[POC_CALL] = &pic16_pciCALL; + pic16Mnemonics[POC_CLRF] = &pic16_pciCLRF; + pic16Mnemonics[POC_CLRWDT] = &pic16_pciCLRWDT; + pic16Mnemonics[POC_COMF] = &pic16_pciCOMF; + pic16Mnemonics[POC_COMFW] = &pic16_pciCOMFW; + pic16Mnemonics[POC_CPFSEQ] = &pic16_pciCPFSEQ; + pic16Mnemonics[POC_CPFSGT] = &pic16_pciCPFSGT; + pic16Mnemonics[POC_CPFSLT] = &pic16_pciCPFSLT; + pic16Mnemonics[POC_DAW] = &pic16_pciDAW; + pic16Mnemonics[POC_DCFSNZ] = &pic16_pciDCFSNZ; + pic16Mnemonics[POC_DECF] = &pic16_pciDECF; + pic16Mnemonics[POC_DECFW] = &pic16_pciDECFW; + pic16Mnemonics[POC_DECFSZ] = &pic16_pciDECFSZ; + pic16Mnemonics[POC_DECFSZW] = &pic16_pciDECFSZW; + pic16Mnemonics[POC_GOTO] = &pic16_pciGOTO; + pic16Mnemonics[POC_INCF] = &pic16_pciINCF; + pic16Mnemonics[POC_INCFW] = &pic16_pciINCFW; + pic16Mnemonics[POC_INCFSZ] = &pic16_pciINCFSZ; + pic16Mnemonics[POC_INCFSZW] = &pic16_pciINCFSZW; + pic16Mnemonics[POC_INFSNZ] = &pic16_pciINFSNZ; + pic16Mnemonics[POC_IORWF] = &pic16_pciIORWF; + pic16Mnemonics[POC_IORFW] = &pic16_pciIORFW; + pic16Mnemonics[POC_IORLW] = &pic16_pciIORLW; + pic16Mnemonics[POC_LFSR] = &pic16_pciLFSR; + pic16Mnemonics[POC_MOVF] = &pic16_pciMOVF; + pic16Mnemonics[POC_MOVFW] = &pic16_pciMOVFW; + pic16Mnemonics[POC_MOVFF] = &pic16_pciMOVFF; + pic16Mnemonics[POC_MOVLB] = &pic16_pciMOVLB; + pic16Mnemonics[POC_MOVLW] = &pic16_pciMOVLW; + pic16Mnemonics[POC_MOVWF] = &pic16_pciMOVWF; + pic16Mnemonics[POC_MULLW] = &pic16_pciMULLW; + pic16Mnemonics[POC_MULWF] = &pic16_pciMULWF; + pic16Mnemonics[POC_NEGF] = &pic16_pciNEGF; + pic16Mnemonics[POC_NOP] = &pic16_pciNOP; + pic16Mnemonics[POC_POP] = &pic16_pciPOP; + pic16Mnemonics[POC_PUSH] = &pic16_pciPUSH; + pic16Mnemonics[POC_RCALL] = &pic16_pciRCALL; + pic16Mnemonics[POC_RETFIE] = &pic16_pciRETFIE; + pic16Mnemonics[POC_RETLW] = &pic16_pciRETLW; + pic16Mnemonics[POC_RETURN] = &pic16_pciRETURN; + pic16Mnemonics[POC_RLCF] = &pic16_pciRLCF; + pic16Mnemonics[POC_RLCFW] = &pic16_pciRLCFW; + pic16Mnemonics[POC_RLCF] = &pic16_pciRLNCF; + pic16Mnemonics[POC_RLNCFW] = &pic16_pciRLNCFW; + pic16Mnemonics[POC_RRCF] = &pic16_pciRRCF; + pic16Mnemonics[POC_RRCFW] = &pic16_pciRRCFW; + pic16Mnemonics[POC_RRNCF] = &pic16_pciRRNCF; + pic16Mnemonics[POC_RRNCFW] = &pic16_pciRRNCFW; + pic16Mnemonics[POC_SETF] = &pic16_pciSETF; + pic16Mnemonics[POC_SUBLW] = &pic16_pciSUBLW; + pic16Mnemonics[POC_SUBWF] = &pic16_pciSUBWF; + pic16Mnemonics[POC_SUBFW] = &pic16_pciSUBFW; + pic16Mnemonics[POC_SUBWFB_D0] = &pic16_pciSUBWFB_D0; + pic16Mnemonics[POC_SUBWFB_D1] = &pic16_pciSUBWFB_D1; + pic16Mnemonics[POC_SUBFWB_D0] = &pic16_pciSUBFWB_D0; + pic16Mnemonics[POC_SUBFWB_D1] = &pic16_pciSUBFWB_D1; + pic16Mnemonics[POC_SWAPF] = &pic16_pciSWAPF; + pic16Mnemonics[POC_SWAPFW] = &pic16_pciSWAPFW; + pic16Mnemonics[POC_TRIS] = &pic16_pciTRIS; + pic16Mnemonics[POC_TSTFSZ] = &pic16_pciTSTFSZ; + pic16Mnemonics[POC_XORLW] = &pic16_pciXORLW; + pic16Mnemonics[POC_XORWF] = &pic16_pciXORWF; + pic16Mnemonics[POC_XORFW] = &pic16_pciXORFW; + + for(i=0; imnemonic), pic16Mnemonics[i]); + pci = hTabFirstItem(pic16MnemonicsHash, &key); + + while(pci) { + DFPRINTF((stderr, "element %d key %d, mnem %s\n",i++,key,pci->mnemonic)); + pci = hTabNextItem(pic16MnemonicsHash, &key); + } + + mnemonics_initialized = 1; +} + +int pic16_getpCodePeepCommand(char *cmd); + +int pic16_getpCode(char *mnem,unsigned dest) +{ + + pCodeInstruction *pci; + int key = mnem2key(mnem); + + if(!mnemonics_initialized) + pic16initMnemonics(); + + pci = hTabFirstItemWK(pic16MnemonicsHash, key); + + while(pci) { + + if(STRCASECMP(pci->mnemonic, mnem) == 0) { + if((pci->num_ops <= 1) || (pci->isModReg == dest) || (pci->isBitInst) || + (pci->num_ops <= 2 && pci->isAccess) || + (pci->num_ops <= 2 && pci->isFastCall)) + return(pci->op); + } + + pci = hTabNextItemWK (pic16MnemonicsHash); + + } + + return -1; +} + +/*-----------------------------------------------------------------* + * pic16initpCodePeepCommands + * + *-----------------------------------------------------------------*/ +void pic16initpCodePeepCommands(void) +{ + + int key, i; + peepCommand *pcmd; + + i = 0; + do { + hTabAddItem(&pic16pCodePeepCommandsHash, + mnem2key(peepCommands[i].cmd), &peepCommands[i]); + i++; + } while (peepCommands[i].cmd); + + pcmd = hTabFirstItem(pic16pCodePeepCommandsHash, &key); + + while(pcmd) { + //fprintf(stderr, "peep command %s key %d\n",pcmd->cmd,pcmd->id); + pcmd = hTabNextItem(pic16pCodePeepCommandsHash, &key); + } + +} + +/*----------------------------------------------------------------- + * + * + *-----------------------------------------------------------------*/ + +int pic16_getpCodePeepCommand(char *cmd) +{ + + peepCommand *pcmd; + int key = mnem2key(cmd); + + + pcmd = hTabFirstItemWK(pic16pCodePeepCommandsHash, key); + + while(pcmd) { + // fprintf(stderr," comparing %s to %s\n",pcmd->cmd,cmd); + if(STRCASECMP(pcmd->cmd, cmd) == 0) { + return pcmd->id; + } + + pcmd = hTabNextItemWK (pic16pCodePeepCommandsHash); + + } + + return -1; +} + +static char getpBlock_dbName(pBlock *pb) +{ + if(!pb) + return 0; + + if(pb->cmemmap) + return pb->cmemmap->dbName; + + return pb->dbName; +} +void pic16_pBlockConvert2ISR(pBlock *pb) +{ + if(!pb) + return; + + if(pb->cmemmap) + pb->cmemmap = NULL; + + pb->dbName = 'I'; +} + +/*-----------------------------------------------------------------*/ +/* pic16_movepBlock2Head - given the dbname of a pBlock, move all */ +/* instances to the front of the doubly linked */ +/* list of pBlocks */ +/*-----------------------------------------------------------------*/ + +void pic16_movepBlock2Head(char dbName) +{ + pBlock *pb; + + pb = the_pFile->pbHead; + + while(pb) { + + if(getpBlock_dbName(pb) == dbName) { + pBlock *pbn = pb->next; + pb->next = the_pFile->pbHead; + the_pFile->pbHead->prev = pb; + the_pFile->pbHead = pb; + + if(pb->prev) + pb->prev->next = pbn; + + // If the pBlock that we just moved was the last + // one in the link of all of the pBlocks, then we + // need to point the tail to the block just before + // the one we moved. + // Note: if pb->next is NULL, then pb must have + // been the last pBlock in the chain. + + if(pbn) + pbn->prev = pb->prev; + else + the_pFile->pbTail = pb->prev; + + pb = pbn; + + } else + pb = pb->next; + + } + +} + +void pic16_copypCode(FILE *of, char dbName) +{ + pBlock *pb; + + if(!of || !the_pFile) + return; + + for(pb = the_pFile->pbHead; pb; pb = pb->next) { + if(getpBlock_dbName(pb) == dbName) { + pBlockStats(of,pb); + pic16_printpBlock(of,pb); + } + } + +} +void pic16_pcode_test(void) +{ + + DFPRINTF((stderr,"pcode is alive!\n")); + + //initMnemonics(); + + if(the_pFile) { + + pBlock *pb; + FILE *pFile; + char buffer[100]; + + /* create the file name */ + strcpy(buffer,srcFileName); + strcat(buffer,".p"); + + if( !(pFile = fopen(buffer, "w" ))) { + werror(E_FILE_OPEN_ERR,buffer); + exit(1); + } + + fprintf(pFile,"pcode dump\n\n"); + + for(pb = the_pFile->pbHead; pb; pb = pb->next) { + fprintf(pFile,"\n\tNew pBlock\n\n"); + if(pb->cmemmap) + fprintf(pFile,"%s",pb->cmemmap->sname); + else + fprintf(pFile,"internal pblock"); + + fprintf(pFile,", dbName =%c\n",getpBlock_dbName(pb)); + pic16_printpBlock(pFile,pb); + } + } +} +/*-----------------------------------------------------------------*/ +/* int RegCond(pCodeOp *pcop) - if pcop points to the STATUS reg- */ +/* ister, RegCond will return the bit being referenced. */ +/* */ +/* fixme - why not just OR in the pcop bit field */ +/*-----------------------------------------------------------------*/ + +static int RegCond(pCodeOp *pcop) +{ + + if(!pcop) + return 0; + + if(pcop->type == PO_GPR_BIT && !strcmp(pcop->name, pic16_pc_status.pcop.name)) { + switch(PCORB(pcop)->bit) { + case PIC_C_BIT: + return PCC_C; + case PIC_DC_BIT: + return PCC_DC; + case PIC_Z_BIT: + return PCC_Z; + } + + } + + return 0; +} + +/*-----------------------------------------------------------------*/ +/* pic16_newpCode - create and return a newly initialized pCode */ +/* */ +/* fixme - rename this */ +/* */ +/* The purpose of this routine is to create a new Instruction */ +/* pCode. This is called by gen.c while the assembly code is being */ +/* generated. */ +/* */ +/* Inouts: */ +/* PIC_OPCODE op - the assembly instruction we wish to create. */ +/* (note that the op is analogous to but not the */ +/* same thing as the opcode of the instruction.) */ +/* pCdoeOp *pcop - pointer to the operand of the instruction. */ +/* */ +/* Outputs: */ +/* a pointer to the new malloc'd pCode is returned. */ +/* */ +/* */ +/* */ +/*-----------------------------------------------------------------*/ +pCode *pic16_newpCode (PIC_OPCODE op, pCodeOp *pcop) +{ + pCodeInstruction *pci ; + + if(!mnemonics_initialized) + pic16initMnemonics(); + + pci = Safe_calloc(1, sizeof(pCodeInstruction)); + + if((op>=0) && (op < MAX_PIC16MNEMONICS) && pic16Mnemonics[op]) { + memcpy(pci, pic16Mnemonics[op], sizeof(pCodeInstruction)); + pci->pcop = pcop; + + if(pci->inCond & PCC_EXAMINE_PCOP) + pci->inCond |= RegCond(pcop); + + if(pci->outCond & PCC_EXAMINE_PCOP) + pci->outCond |= RegCond(pcop); + + pci->pc.prev = pci->pc.next = NULL; + return (pCode *)pci; + } + + fprintf(stderr, "pCode mnemonic error %s,%d\n",__FUNCTION__,__LINE__); + exit(1); + + return NULL; +} + +/*-----------------------------------------------------------------*/ +/* pic16_newpCodeWild - create a "wild" as in wild card pCode */ +/* */ +/* Wild pcodes are used during the peep hole optimizer to serve */ +/* as place holders for any instruction. When a snippet of code is */ +/* compared to a peep hole rule, the wild card opcode will match */ +/* any instruction. However, the optional operand and label are */ +/* additional qualifiers that must also be matched before the */ +/* line (of assembly code) is declared matched. Note that the */ +/* operand may be wild too. */ +/* */ +/* Note, a wild instruction is specified just like a wild var: */ +/* %4 ; A wild instruction, */ +/* See the peeph.def file for additional examples */ +/* */ +/*-----------------------------------------------------------------*/ + +pCode *pic16_newpCodeWild(int pCodeID, pCodeOp *optional_operand, pCodeOp *optional_label) +{ + + pCodeWild *pcw; + + pcw = Safe_calloc(1,sizeof(pCodeWild)); + + pcw->pci.pc.type = PC_WILD; + pcw->pci.pc.prev = pcw->pci.pc.next = NULL; + pcw->pci.from = pcw->pci.to = pcw->pci.label = NULL; + pcw->pci.pc.pb = NULL; + + // pcw->pci.pc.analyze = genericAnalyze; + pcw->pci.pc.destruct = genericDestruct; + pcw->pci.pc.print = genericPrint; + + pcw->id = pCodeID; // this is the 'n' in %n + pcw->operand = optional_operand; + pcw->label = optional_label; + + pcw->mustBeBitSkipInst = 0; + pcw->mustNotBeBitSkipInst = 0; + pcw->invertBitSkipInst = 0; + + return ( (pCode *)pcw); + +} + + /*-----------------------------------------------------------------*/ +/* newPcodeInlineP - create a new pCode from a char string */ +/*-----------------------------------------------------------------*/ + + +pCode *pic16_newpCodeInlineP(char *cP) +{ + + pCodeComment *pcc ; + + pcc = Safe_calloc(1,sizeof(pCodeComment)); + + pcc->pc.type = PC_INLINE; + pcc->pc.prev = pcc->pc.next = NULL; + //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL; + pcc->pc.pb = NULL; + + // pcc->pc.analyze = genericAnalyze; + pcc->pc.destruct = genericDestruct; + pcc->pc.print = genericPrint; + + if(cP) + pcc->comment = Safe_strdup(cP); + else + pcc->comment = NULL; + + return ( (pCode *)pcc); + +} + +/*-----------------------------------------------------------------*/ +/* newPcodeCharP - create a new pCode from a char string */ +/*-----------------------------------------------------------------*/ + +pCode *pic16_newpCodeCharP(char *cP) +{ + + pCodeComment *pcc ; + + pcc = Safe_calloc(1,sizeof(pCodeComment)); + + pcc->pc.type = PC_COMMENT; + pcc->pc.prev = pcc->pc.next = NULL; + //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL; + pcc->pc.pb = NULL; + + // pcc->pc.analyze = genericAnalyze; + pcc->pc.destruct = genericDestruct; + pcc->pc.print = genericPrint; + + if(cP) + pcc->comment = Safe_strdup(cP); + else + pcc->comment = NULL; + + return ( (pCode *)pcc); + +} + +/*-----------------------------------------------------------------*/ +/* pic16_newpCodeFunction - */ +/*-----------------------------------------------------------------*/ + + +pCode *pic16_newpCodeFunction(char *mod,char *f) +{ + pCodeFunction *pcf; + + pcf = Safe_calloc(1,sizeof(pCodeFunction)); + //_ALLOC(pcf,sizeof(pCodeFunction)); + + pcf->pc.type = PC_FUNCTION; + pcf->pc.prev = pcf->pc.next = NULL; + //pcf->pc.from = pcf->pc.to = pcf->pc.label = NULL; + pcf->pc.pb = NULL; + + // pcf->pc.analyze = genericAnalyze; + pcf->pc.destruct = genericDestruct; + pcf->pc.print = pCodePrintFunction; + + pcf->ncalled = 0; + + if(mod) { + //_ALLOC_ATOMIC(pcf->modname,strlen(mod)+1); + pcf->modname = Safe_calloc(1,strlen(mod)+1); + strcpy(pcf->modname,mod); + } else + pcf->modname = NULL; + + if(f) { + //_ALLOC_ATOMIC(pcf->fname,strlen(f)+1); + pcf->fname = Safe_calloc(1,strlen(f)+1); + strcpy(pcf->fname,f); + } else + pcf->fname = NULL; + + return ( (pCode *)pcf); + +} + +/*-----------------------------------------------------------------*/ +/* pic16_newpCodeFlow */ +/*-----------------------------------------------------------------*/ +static void destructpCodeFlow(pCode *pc) +{ + if(!pc || !isPCFL(pc)) + return; + +/* + if(PCFL(pc)->from) + if(PCFL(pc)->to) +*/ + pic16_unlinkpCode(pc); + + deleteSet(&PCFL(pc)->registers); + deleteSet(&PCFL(pc)->from); + deleteSet(&PCFL(pc)->to); + free(pc); + +} + +pCode *pic16_newpCodeFlow(void ) +{ + pCodeFlow *pcflow; + + //_ALLOC(pcflow,sizeof(pCodeFlow)); + pcflow = Safe_calloc(1,sizeof(pCodeFlow)); + + pcflow->pc.type = PC_FLOW; + pcflow->pc.prev = pcflow->pc.next = NULL; + pcflow->pc.pb = NULL; + + // pcflow->pc.analyze = genericAnalyze; + pcflow->pc.destruct = destructpCodeFlow; + pcflow->pc.print = genericPrint; + + pcflow->pc.seq = GpcFlowSeq++; + + pcflow->from = pcflow->to = NULL; + + pcflow->inCond = PCC_NONE; + pcflow->outCond = PCC_NONE; + + pcflow->firstBank = -1; + pcflow->lastBank = -1; + + pcflow->FromConflicts = 0; + pcflow->ToConflicts = 0; + + pcflow->end = NULL; + + pcflow->registers = newSet(); + + return ( (pCode *)pcflow); + +} + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +pCodeFlowLink *pic16_newpCodeFlowLink(pCodeFlow *pcflow) +{ + pCodeFlowLink *pcflowLink; + + pcflowLink = Safe_calloc(1,sizeof(pCodeFlowLink)); + + pcflowLink->pcflow = pcflow; + pcflowLink->bank_conflict = 0; + + return pcflowLink; +} + +/*-----------------------------------------------------------------*/ +/* pic16_newpCodeCSource - create a new pCode Source Symbol */ +/*-----------------------------------------------------------------*/ + +pCode *pic16_newpCodeCSource(int ln, char *f, char *l) +{ + + pCodeCSource *pccs; + + pccs = Safe_calloc(1,sizeof(pCodeCSource)); + + pccs->pc.type = PC_CSOURCE; + pccs->pc.prev = pccs->pc.next = NULL; + pccs->pc.pb = NULL; + + pccs->pc.destruct = genericDestruct; + pccs->pc.print = genericPrint; + + pccs->line_number = ln; + if(l) + pccs->line = Safe_strdup(l); + else + pccs->line = NULL; + + if(f) + pccs->file_name = Safe_strdup(f); + else + pccs->file_name = NULL; + + return ( (pCode *)pccs); + +} +/*-----------------------------------------------------------------*/ +/* pCodeLabelDestruct - free memory used by a label. */ +/*-----------------------------------------------------------------*/ +static void pCodeLabelDestruct(pCode *pc) +{ + + if(!pc) + return; + + if((pc->type == PC_LABEL) && PCL(pc)->label) + free(PCL(pc)->label); + + free(pc); + +} + +pCode *pic16_newpCodeLabel(char *name, int key) +{ + + char *s = buffer; + pCodeLabel *pcl; + + pcl = Safe_calloc(1,sizeof(pCodeLabel) ); + + pcl->pc.type = PC_LABEL; + pcl->pc.prev = pcl->pc.next = NULL; + //pcl->pc.from = pcl->pc.to = pcl->pc.label = NULL; + pcl->pc.pb = NULL; + + // pcl->pc.analyze = genericAnalyze; + pcl->pc.destruct = pCodeLabelDestruct; + pcl->pc.print = pCodePrintLabel; + + pcl->key = key; + + pcl->label = NULL; + if(key>0) { + sprintf(s,"_%05d_DS_",key); + } else + s = name; + + if(s) + pcl->label = Safe_strdup(s); + + //fprintf(stderr,"pic16_newpCodeLabel: key=%d, name=%s\n",key, ((s)?s:"")); + return ( (pCode *)pcl); + +} + + +/*-----------------------------------------------------------------*/ +/* newpBlock - create and return a pointer to a new pBlock */ +/*-----------------------------------------------------------------*/ +static pBlock *newpBlock(void) +{ + + pBlock *PpB; + + PpB = Safe_calloc(1,sizeof(pBlock) ); + PpB->next = PpB->prev = NULL; + + PpB->function_entries = PpB->function_exits = PpB->function_calls = NULL; + PpB->tregisters = NULL; + PpB->visited = 0; + PpB->FlowTree = NULL; + + return PpB; + +} + +/*-----------------------------------------------------------------*/ +/* pic16_newpCodeChain - create a new chain of pCodes */ +/*-----------------------------------------------------------------* + * + * This function will create a new pBlock and the pointer to the + * pCode that is passed in will be the first pCode in the block. + *-----------------------------------------------------------------*/ + + +pBlock *pic16_newpCodeChain(memmap *cm,char c, pCode *pc) +{ + + pBlock *pB = newpBlock(); + + pB->pcHead = pB->pcTail = pc; + pB->cmemmap = cm; + pB->dbName = c; + + return pB; +} + +/*-----------------------------------------------------------------*/ +/* pic16_newpCodeOpLabel - Create a new label given the key */ +/* Note, a negative key means that the label is part of wild card */ +/* (and hence a wild card label) used in the pCodePeep */ +/* optimizations). */ +/*-----------------------------------------------------------------*/ + +pCodeOp *pic16_newpCodeOpLabel(char *name, int key) +{ + char *s=NULL; + static int label_key=-1; + + pCodeOp *pcop; + + pcop = Safe_calloc(1,sizeof(pCodeOpLabel) ); + pcop->type = PO_LABEL; + + pcop->name = NULL; + + if(key>0) + sprintf(s=buffer,"_%05d_DS_",key); + else + s = name, key = label_key--; + + if(s) + pcop->name = Safe_strdup(s); + + ((pCodeOpLabel *)pcop)->key = key; + + //fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",key,((s)?s:"")); + return pcop; +} + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +pCodeOp *pic16_newpCodeOpLit(int lit) +{ + char *s = buffer; + pCodeOp *pcop; + + + pcop = Safe_calloc(1,sizeof(pCodeOpLit) ); + pcop->type = PO_LITERAL; + + pcop->name = NULL; + if(lit>=0) { + sprintf(s,"0x%02x",lit); + if(s) + pcop->name = Safe_strdup(s); + } + + ((pCodeOpLit *)pcop)->lit = lit; + + return pcop; +} + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +pCodeOp *pic16_newpCodeOpImmd(char *name, int offset, int index, int code_space) +{ + pCodeOp *pcop; + + pcop = Safe_calloc(1,sizeof(pCodeOpImmd) ); + pcop->type = PO_IMMEDIATE; + if(name) { + regs *r = pic16_dirregWithName(name); + pcop->name = Safe_strdup(name); + PCOI(pcop)->r = r; + if(r) { + //fprintf(stderr, " pic16_newpCodeOpImmd reg %s exists\n",name); + PCOI(pcop)->rIdx = r->rIdx; + } else { + //fprintf(stderr, " pic16_newpCodeOpImmd reg %s doesn't exist\n",name); + PCOI(pcop)->rIdx = -1; + } + //fprintf(stderr,"%s %s %d\n",__FUNCTION__,name,offset); + } else { + pcop->name = NULL; + } + + PCOI(pcop)->index = index; + PCOI(pcop)->offset = offset; + PCOI(pcop)->_const = code_space; + + return pcop; +} + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +pCodeOp *pic16_newpCodeOpWild(int id, pCodeWildBlock *pcwb, pCodeOp *subtype) +{ + char *s = buffer; + pCodeOp *pcop; + + + if(!pcwb || !subtype) { + fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__); + exit(1); + } + + pcop = Safe_calloc(1,sizeof(pCodeOpWild)); + pcop->type = PO_WILD; + sprintf(s,"%%%d",id); + pcop->name = Safe_strdup(s); + + PCOW(pcop)->id = id; + PCOW(pcop)->pcwb = pcwb; + PCOW(pcop)->subtype = subtype; + PCOW(pcop)->matched = NULL; + + return pcop; +} + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +pCodeOp *pic16_newpCodeOpBit(char *s, int bit, int inBitSpace) +{ + pCodeOp *pcop; + + pcop = Safe_calloc(1,sizeof(pCodeOpRegBit) ); + pcop->type = PO_GPR_BIT; + if(s) + pcop->name = Safe_strdup(s); + else + pcop->name = NULL; + + PCORB(pcop)->bit = bit; + PCORB(pcop)->inBitSpace = inBitSpace; + + /* pCodeOpBit is derived from pCodeOpReg. We need to init this too */ + PCOR(pcop)->r = NULL; + PCOR(pcop)->rIdx = 0; + return pcop; +} + +/*-----------------------------------------------------------------* + * pCodeOp *pic16_newpCodeOpReg(int rIdx) - allocate a new register + * + * If rIdx >=0 then a specific register from the set of registers + * will be selected. If rIdx <0, then a new register will be searched + * for. + *-----------------------------------------------------------------*/ + +pCodeOp *pic16_newpCodeOpReg(int rIdx) +{ + pCodeOp *pcop; + + pcop = Safe_calloc(1,sizeof(pCodeOpReg) ); + + pcop->name = NULL; + + if(rIdx >= 0) { + PCOR(pcop)->rIdx = rIdx; + PCOR(pcop)->r = pic16_regWithIdx(rIdx); + } else { + PCOR(pcop)->r = pic16_findFreeReg(REG_GPR); + + if(PCOR(pcop)->r) + PCOR(pcop)->rIdx = PCOR(pcop)->r->rIdx; + } + + pcop->type = PCOR(pcop)->r->pc_type; + + return pcop; +} + +pCodeOp *pic16_newpCodeOpRegFromStr(char *name) +{ + pCodeOp *pcop; + + pcop = Safe_calloc(1,sizeof(pCodeOpReg) ); + PCOR(pcop)->r = pic16_allocRegByName(name, 1); + PCOR(pcop)->rIdx = PCOR(pcop)->r->rIdx; + pcop->type = PCOR(pcop)->r->pc_type; + pcop->name = PCOR(pcop)->r->name; + + return pcop; +} + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ + +pCodeOp *pic16_newpCodeOp(char *name, PIC_OPTYPE type) +{ + pCodeOp *pcop; + + switch(type) { + case PO_BIT: + case PO_GPR_BIT: + pcop = pic16_newpCodeOpBit(name, -1,0); + break; + + case PO_LITERAL: + pcop = pic16_newpCodeOpLit(-1); + break; + + case PO_LABEL: + pcop = pic16_newpCodeOpLabel(NULL,-1); + break; + case PO_GPR_TEMP: + pcop = pic16_newpCodeOpReg(-1); + break; + + case PO_GPR_REGISTER: + if(name) + pcop = pic16_newpCodeOpRegFromStr(name); + else + pcop = pic16_newpCodeOpReg(-1); + break; + + default: + pcop = Safe_calloc(1,sizeof(pCodeOp) ); + pcop->type = type; + if(name) + pcop->name = Safe_strdup(name); + else + pcop->name = NULL; + } + + return pcop; +} + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +void pic16_pCodeConstString(char *name, char *value) +{ + pBlock *pb; + + // fprintf(stderr, " %s %s %s\n",__FUNCTION__,name,value); + + if(!name || !value) + return; + + pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block")); + + pic16_addpBlock(pb); + + sprintf(buffer,"; %s = %s",name,value); + + pic16_addpCode2pBlock(pb,pic16_newpCodeCharP(buffer)); + pic16_addpCode2pBlock(pb,pic16_newpCodeLabel(name,-1)); + + do { + pic16_addpCode2pBlock(pb,pic16_newpCode(POC_RETLW,pic16_newpCodeOpLit(*value))); + }while (*value++); + + +} + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +static void pCodeReadCodeTable(void) +{ + pBlock *pb; + + fprintf(stderr, " %s\n",__FUNCTION__); + + pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block")); + + pic16_addpBlock(pb); + + pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; ReadCodeTable - built in function")); + pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Inputs: temp1,temp2 = code pointer")); + pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Outpus: W (from RETLW at temp2:temp1)")); + pic16_addpCode2pBlock(pb,pic16_newpCodeLabel("ReadCodeTable:",-1)); + + pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp2"))); + pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCLATH"))); + pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp1"))); + pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCL"))); + + +} + +/*-----------------------------------------------------------------*/ +/* pic16_addpCode2pBlock - place the pCode into the pBlock linked list */ +/*-----------------------------------------------------------------*/ +void pic16_addpCode2pBlock(pBlock *pb, pCode *pc) +{ + + if(!pc) + return; + + if(!pb->pcHead) { + /* If this is the first pcode to be added to a block that + * was initialized with a NULL pcode, then go ahead and + * make this pcode the head and tail */ + pb->pcHead = pb->pcTail = pc; + } else { + // if(pb->pcTail) + pb->pcTail->next = pc; + + pc->prev = pb->pcTail; + pc->pb = pb; + + pb->pcTail = pc; + } +} + +/*-----------------------------------------------------------------*/ +/* pic16_addpBlock - place a pBlock into the pFile */ +/*-----------------------------------------------------------------*/ +void pic16_addpBlock(pBlock *pb) +{ + // fprintf(stderr," Adding pBlock: dbName =%c\n",getpBlock_dbName(pb)); + + if(!the_pFile) { + /* First time called, we'll pass through here. */ + //_ALLOC(the_pFile,sizeof(pFile)); + the_pFile = Safe_calloc(1,sizeof(pFile)); + the_pFile->pbHead = the_pFile->pbTail = pb; + the_pFile->functions = NULL; + return; + } + + the_pFile->pbTail->next = pb; + pb->prev = the_pFile->pbTail; + pb->next = NULL; + the_pFile->pbTail = pb; +} + +/*-----------------------------------------------------------------*/ +/* removepBlock - remove a pBlock from the pFile */ +/*-----------------------------------------------------------------*/ +static void removepBlock(pBlock *pb) +{ + pBlock *pbs; + + if(!the_pFile) + return; + + + //fprintf(stderr," Removing pBlock: dbName =%c\n",getpBlock_dbName(pb)); + + for(pbs = the_pFile->pbHead; pbs; pbs = pbs->next) { + if(pbs == pb) { + + if(pbs == the_pFile->pbHead) + the_pFile->pbHead = pbs->next; + + if (pbs == the_pFile->pbTail) + the_pFile->pbTail = pbs->prev; + + if(pbs->next) + pbs->next->prev = pbs->prev; + + if(pbs->prev) + pbs->prev->next = pbs->next; + + return; + + } + } + + fprintf(stderr, "Warning: call to %s:%s didn't find pBlock\n",__FILE__,__FUNCTION__); + +} + +/*-----------------------------------------------------------------*/ +/* printpCode - write the contents of a pCode to a file */ +/*-----------------------------------------------------------------*/ +static void printpCode(FILE *of, pCode *pc) +{ + + if(!pc || !of) + return; + + if(pc->print) { + pc->print(of,pc); + return; + } + + fprintf(of,"warning - unable to print pCode\n"); +} + +/*-----------------------------------------------------------------*/ +/* pic16_printpBlock - write the contents of a pBlock to a file */ +/*-----------------------------------------------------------------*/ +void pic16_printpBlock(FILE *of, pBlock *pb) +{ + pCode *pc; + + if(!pb) + return; + + if(!of) + of = stderr; + + for(pc = pb->pcHead; pc; pc = pc->next) + printpCode(of,pc); + +} + +/*-----------------------------------------------------------------*/ +/* */ +/* pCode processing */ +/* */ +/* */ +/* */ +/*-----------------------------------------------------------------*/ + +void pic16_unlinkpCode(pCode *pc) +{ + + + if(pc) { +#ifdef PCODE_DEBUG + fprintf(stderr,"Unlinking: "); + printpCode(stderr, pc); +#endif + if(pc->prev) + pc->prev->next = pc->next; + if(pc->next) + pc->next->prev = pc->prev; + + pc->prev = pc->next = NULL; + } +} + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ + +static void genericDestruct(pCode *pc) +{ + + pic16_unlinkpCode(pc); + + if(isPCI(pc)) { + /* For instructions, tell the register (if there's one used) + * that it's no longer needed */ + regs *reg = pic16_getRegFromInstruction(pc); + if(reg) + deleteSetItem (&(reg->reglives.usedpCodes),pc); + } + + /* Instead of deleting the memory used by this pCode, mark + * the object as bad so that if there's a pointer to this pCode + * dangling around somewhere then (hopefully) when the type is + * checked we'll catch it. + */ + + pc->type = PC_BAD; + + pic16_addpCode2pBlock(pb_dead_pcodes, pc); + + //free(pc); + +} + + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +static void pBlockRegs(FILE *of, pBlock *pb) +{ + + regs *r; + + r = setFirstItem(pb->tregisters); + while (r) { + r = setNextItem(pb->tregisters); + } +} + + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +char *pic16_get_op(pCodeOp *pcop,char *buffer, int size) +{ + regs *r; + static char b[50]; + char *s; + int use_buffer = 1; // copy the string to the passed buffer pointer + + if(!buffer) { + buffer = b; + size = sizeof(b); + use_buffer = 0; // Don't bother copying the string to the buffer. + } + + if(pcop) { + switch(pcop->type) { + case PO_INDF0: + case PO_FSR0: + if(use_buffer) { + SAFE_snprintf(&buffer,&size,"%s",PCOR(pcop)->r->name); + return buffer; + } + return PCOR(pcop)->r->name; + break; + case PO_GPR_TEMP: + r = pic16_regWithIdx(PCOR(pcop)->r->rIdx); + + if(use_buffer) { + SAFE_snprintf(&buffer,&size,"%s",r->name); + return buffer; + } + + return r->name; + + + case PO_IMMEDIATE: + s = buffer; + + if(PCOI(pcop)->_const) { + + if( PCOI(pcop)->offset && PCOI(pcop)->offset<4) { + SAFE_snprintf(&s,&size,"(((%s+%d) >> %d)&0xff)", + pcop->name, + PCOI(pcop)->index, + 8 * PCOI(pcop)->offset ); + } else + SAFE_snprintf(&s,&size,"LOW(%s+%d)",pcop->name,PCOI(pcop)->index); + } else { + + if( PCOI(pcop)->index) { // && PCOI(pcc->pcop)->offset<4) { + SAFE_snprintf(&s,&size,"(%s + %d)", + pcop->name, + PCOI(pcop)->index ); + } else { + if(PCOI(pcop)->offset) + SAFE_snprintf(&s,&size,"(%s >> %d)&0xff",pcop->name, 8*PCOI(pcop)->offset); + else + SAFE_snprintf(&s,&size,"%s",pcop->name); + } + } + + return buffer; + + case PO_DIR: + s = buffer; + //size = sizeof(buffer); + if( PCOR(pcop)->instance) { + SAFE_snprintf(&s,&size,"(%s + %d)", + pcop->name, + PCOR(pcop)->instance ); + //fprintf(stderr,"PO_DIR %s\n",buffer); + } else + SAFE_snprintf(&s,&size,"%s",pcop->name); + return buffer; + + default: + if (pcop->name) { + if(use_buffer) { + SAFE_snprintf(&buffer,&size,"%s",pcop->name); + return buffer; + } + return pcop->name; + } + + } + } + + return "NO operand"; + +} + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +static char *pic16_get_op_from_instruction( pCodeInstruction *pcc) +{ + + if(pcc ) + return pic16_get_op(pcc->pcop,NULL,0); + + return ("ERROR Null: "__FUNCTION__); + +} + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +static void pCodeOpPrint(FILE *of, pCodeOp *pcop) +{ + + fprintf(of,"pcodeopprint- not implemented\n"); +} + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +static char *pCode2str(char *str, int size, pCode *pc) +{ + char *s = str; + + switch(pc->type) { + + case PC_OPCODE: + + SAFE_snprintf(&s,&size, "\t%s\t", PCI(pc)->mnemonic); + + if( (PCI(pc)->num_ops >= 1) && (PCI(pc)->pcop)) { + + if(PCI(pc)->isBitInst) { + if(PCI(pc)->pcop->type == PO_GPR_BIT) { + if( (((pCodeOpRegBit *)(PCI(pc)->pcop))->inBitSpace) ) + SAFE_snprintf(&s,&size,"(%s >> 3), (%s & 7)", + PCI(pc)->pcop->name , + PCI(pc)->pcop->name ); + else + SAFE_snprintf(&s,&size,"%s,%d", pic16_get_op_from_instruction(PCI(pc)), + (((pCodeOpRegBit *)(PCI(pc)->pcop))->bit )); + } else if(PCI(pc)->pcop->type == PO_GPR_BIT) { + SAFE_snprintf(&s,&size,"%s,%d", pic16_get_op_from_instruction(PCI(pc)),PCORB(PCI(pc)->pcop)->bit); + }else + SAFE_snprintf(&s,&size,"%s,0 ; ?bug", pic16_get_op_from_instruction(PCI(pc))); + //PCI(pc)->pcop->t.bit ); + } else { + + if(PCI(pc)->pcop->type == PO_GPR_BIT) { + if( PCI(pc)->num_ops == 3) + SAFE_snprintf(&s,&size,"(%s >> 3),%c",pic16_get_op_from_instruction(PCI(pc)),((PCI(pc)->isModReg) ? 'F':'W')); + else + SAFE_snprintf(&s,&size,"(1 << (%s & 7))",pic16_get_op_from_instruction(PCI(pc))); + + }else { + SAFE_snprintf(&s,&size,"%s",pic16_get_op_from_instruction(PCI(pc))); + + if( PCI(pc)->num_ops == 3) + SAFE_snprintf(&s,&size,",%c", ( (PCI(pc)->isModReg) ? 'F':'W')); + } + } + + } + break; + + case PC_COMMENT: + /* assuming that comment ends with a \n */ + SAFE_snprintf(&s,&size,";%s", ((pCodeComment *)pc)->comment); + break; + + case PC_INLINE: + /* assuming that inline code ends with a \n */ + SAFE_snprintf(&s,&size,"%s", ((pCodeComment *)pc)->comment); + break; + + case PC_LABEL: + SAFE_snprintf(&s,&size,";label=%s, key=%d\n",PCL(pc)->label,PCL(pc)->key); + break; + case PC_FUNCTION: + SAFE_snprintf(&s,&size,";modname=%s,function=%s: id=%d\n",PCF(pc)->modname,PCF(pc)->fname); + break; + case PC_WILD: + SAFE_snprintf(&s,&size,";\tWild opcode: id=%d\n",PCW(pc)->id); + break; + case PC_FLOW: + SAFE_snprintf(&s,&size,";\t--FLOW change\n"); + break; + case PC_CSOURCE: + SAFE_snprintf(&s,&size,";#CSRC\t%s %d\n; %s\n", PCCS(pc)->file_name, PCCS(pc)->line_number, PCCS(pc)->line); + break; + + case PC_BAD: + SAFE_snprintf(&s,&size,";A bad pCode is being used\n"); + } + + return str; + +} + +/*-----------------------------------------------------------------*/ +/* genericPrint - the contents of a pCode to a file */ +/*-----------------------------------------------------------------*/ +static void genericPrint(FILE *of, pCode *pc) +{ + + if(!pc || !of) + return; + + switch(pc->type) { + case PC_COMMENT: + fprintf(of,";%s\n", ((pCodeComment *)pc)->comment); + break; + + case PC_INLINE: + fprintf(of,"%s\n", ((pCodeComment *)pc)->comment); + break; + + case PC_OPCODE: + // If the opcode has a label, print that first + { + pBranch *pbl = PCI(pc)->label; + while(pbl && pbl->pc) { + if(pbl->pc->type == PC_LABEL) + pCodePrintLabel(of, pbl->pc); + pbl = pbl->next; + } + } + + if(PCI(pc)->cline) + genericPrint(of,PCODE(PCI(pc)->cline)); + + { + char str[256]; + + pCode2str(str, 256, pc); + + fprintf(of,"%s",str); + + /* Debug */ + if(pic16_debug_verbose) { + fprintf(of, "\t;key=%03x",pc->seq); + if(PCI(pc)->pcflow) + fprintf(of,",flow seq=%03x",PCI(pc)->pcflow->pc.seq); + } + } +#if 0 + { + pBranch *dpb = pc->to; // debug + while(dpb) { + switch ( dpb->pc->type) { + case PC_OPCODE: + fprintf(of, "\t;%s", PCI(dpb->pc)->mnemonic); + break; + case PC_LABEL: + fprintf(of, "\t;label %d", PCL(dpb->pc)->key); + break; + case PC_FUNCTION: + fprintf(of, "\t;function %s", ( (PCF(dpb->pc)->fname) ? (PCF(dpb->pc)->fname) : "[END]")); + break; + case PC_FLOW: + fprintf(of, "\t;flow"); + break; + case PC_COMMENT: + case PC_WILD: + break; + } + dpb = dpb->next; + } + } +#endif + fprintf(of,"\n"); + break; + + case PC_WILD: + fprintf(of,";\tWild opcode: id=%d\n",PCW(pc)->id); + if(PCW(pc)->pci.label) + pCodePrintLabel(of, PCW(pc)->pci.label->pc); + + if(PCW(pc)->operand) { + fprintf(of,";\toperand "); + pCodeOpPrint(of,PCW(pc)->operand ); + } + break; + + case PC_FLOW: + if(pic16_debug_verbose) { + fprintf(of,";<>Start of new flow, seq=0x%x",pc->seq); + if(PCFL(pc)->ancestor) + fprintf(of," ancestor = 0x%x", PCODE(PCFL(pc)->ancestor)->seq); + fprintf(of,"\n"); + + } + break; + + case PC_CSOURCE: + fprintf(of,";#CSRC\t%s %d\n; %s\n", PCCS(pc)->file_name, PCCS(pc)->line_number, PCCS(pc)->line); + break; + case PC_LABEL: + default: + fprintf(of,"unknown pCode type %d\n",pc->type); + } + +} + +/*-----------------------------------------------------------------*/ +/* pCodePrintFunction - prints function begin/end */ +/*-----------------------------------------------------------------*/ + +static void pCodePrintFunction(FILE *of, pCode *pc) +{ + + if(!pc || !of) + return; + + if( ((pCodeFunction *)pc)->modname) + fprintf(of,"F_%s",((pCodeFunction *)pc)->modname); + + if(PCF(pc)->fname) { + pBranch *exits = PCF(pc)->to; + int i=0; + fprintf(of,"%s\t;Function start\n",PCF(pc)->fname); + while(exits) { + i++; + exits = exits->next; + } + //if(i) i--; + fprintf(of,"; %d exit point%c\n",i, ((i==1) ? ' ':'s')); + + }else { + if((PCF(pc)->from && + PCF(pc)->from->pc->type == PC_FUNCTION && + PCF(PCF(pc)->from->pc)->fname) ) + fprintf(of,"; exit point of %s\n",PCF(PCF(pc)->from->pc)->fname); + else + fprintf(of,"; exit point [can't find entry point]\n"); + } +} +/*-----------------------------------------------------------------*/ +/* pCodePrintLabel - prints label */ +/*-----------------------------------------------------------------*/ + +static void pCodePrintLabel(FILE *of, pCode *pc) +{ + + if(!pc || !of) + return; + + if(PCL(pc)->label) + fprintf(of,"%s\n",PCL(pc)->label); + else if (PCL(pc)->key >=0) + fprintf(of,"_%05d_DS_:\n",PCL(pc)->key); + else + fprintf(of,";wild card label: id=%d\n",-PCL(pc)->key); + +} +/*-----------------------------------------------------------------*/ +/* unlinkpCodeFromBranch - Search for a label in a pBranch and */ +/* remove it if it is found. */ +/*-----------------------------------------------------------------*/ +static void unlinkpCodeFromBranch(pCode *pcl , pCode *pc) +{ + pBranch *b, *bprev; + + + bprev = NULL; + + if(pcl->type == PC_OPCODE) + b = PCI(pcl)->label; + else { + fprintf(stderr, "LINE %d. can't unlink from non opcode\n",__LINE__); + exit(1); + + } + + //fprintf (stderr, "%s \n",__FUNCTION__); + //pcl->print(stderr,pcl); + //pc->print(stderr,pc); + while(b) { + if(b->pc == pc) { + //fprintf (stderr, "found label\n"); + + /* Found a label */ + if(bprev) { + bprev->next = b->next; /* Not first pCode in chain */ + free(b); + } else { + pc->destruct(pc); + PCI(pcl)->label = b->next; /* First pCode in chain */ + free(b); + } + return; /* A label can't occur more than once */ + } + bprev = b; + b = b->next; + } + +} + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +pBranch * pic16_pBranchAppend(pBranch *h, pBranch *n) +{ + pBranch *b; + + if(!h) + return n; + + if(h == n) + return n; + + b = h; + while(b->next) + b = b->next; + + b->next = n; + + return h; + +} +/*-----------------------------------------------------------------*/ +/* pBranchLink - given two pcodes, this function will link them */ +/* together through their pBranches */ +/*-----------------------------------------------------------------*/ +static void pBranchLink(pCodeFunction *f, pCodeFunction *t) +{ + pBranch *b; + + // Declare a new branch object for the 'from' pCode. + + //_ALLOC(b,sizeof(pBranch)); + b = Safe_calloc(1,sizeof(pBranch)); + b->pc = PCODE(t); // The link to the 'to' pCode. + b->next = NULL; + + f->to = pic16_pBranchAppend(f->to,b); + + // Now do the same for the 'to' pCode. + + //_ALLOC(b,sizeof(pBranch)); + b = Safe_calloc(1,sizeof(pBranch)); + b->pc = PCODE(f); + b->next = NULL; + + t->from = pic16_pBranchAppend(t->from,b); + +} + +#if 0 +/*-----------------------------------------------------------------*/ +/* pBranchFind - find the pBranch in a pBranch chain that contains */ +/* a pCode */ +/*-----------------------------------------------------------------*/ +static pBranch *pBranchFind(pBranch *pb,pCode *pc) +{ + while(pb) { + + if(pb->pc == pc) + return pb; + + pb = pb->next; + } + + return NULL; +} + +/*-----------------------------------------------------------------*/ +/* pCodeUnlink - Unlink the given pCode from its pCode chain. */ +/*-----------------------------------------------------------------*/ +static void pCodeUnlink(pCode *pc) +{ + pBranch *pb1,*pb2; + pCode *pc1; + + if(!pc->prev || !pc->next) { + fprintf(stderr,"unlinking bad pCode in %s:%d\n",__FILE__,__LINE__); + exit(1); + } + + /* first remove the pCode from the chain */ + pc->prev->next = pc->next; + pc->next->prev = pc->prev; + + /* Now for the hard part... */ + + /* Remove the branches */ + + pb1 = pc->from; + while(pb1) { + pc1 = pb1->pc; /* Get the pCode that branches to the + * one we're unlinking */ + + /* search for the link back to this pCode (the one we're + * unlinking) */ + if(pb2 = pBranchFind(pc1->to,pc)) { + pb2->pc = pc->to->pc; // make the replacement + + /* if the pCode we're unlinking contains multiple 'to' + * branches (e.g. this a skip instruction) then we need + * to copy these extra branches to the chain. */ + if(pc->to->next) + pic16_pBranchAppend(pb2, pc->to->next); + } + + pb1 = pb1->next; + } + + +} +#endif +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +#if 0 +static void genericAnalyze(pCode *pc) +{ + switch(pc->type) { + case PC_WILD: + case PC_COMMENT: + return; + case PC_LABEL: + case PC_FUNCTION: + case PC_OPCODE: + { + // Go through the pCodes that are in pCode chain and link + // them together through the pBranches. Note, the pCodes + // are linked together as a contiguous stream like the + // assembly source code lines. The linking here mimics this + // except that comments are not linked in. + // + pCode *npc = pc->next; + while(npc) { + if(npc->type == PC_OPCODE || npc->type == PC_LABEL) { + pBranchLink(pc,npc); + return; + } else + npc = npc->next; + } + /* reached the end of the pcode chain without finding + * an instruction we could link to. */ + } + break; + case PC_FLOW: + fprintf(stderr,"analyze PC_FLOW\n"); + + return; + case PC_BAD: + fprintf(stderr,,";A bad pCode is being used\n"); + + } +} +#endif + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +static int compareLabel(pCode *pc, pCodeOpLabel *pcop_label) +{ + pBranch *pbr; + + if(pc->type == PC_LABEL) { + if( ((pCodeLabel *)pc)->key == pcop_label->key) + return TRUE; + } + if(pc->type == PC_OPCODE) { + pbr = PCI(pc)->label; + while(pbr) { + if(pbr->pc->type == PC_LABEL) { + if( ((pCodeLabel *)(pbr->pc))->key == pcop_label->key) + return TRUE; + } + pbr = pbr->next; + } + } + + return FALSE; +} + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +static int checkLabel(pCode *pc) +{ + pBranch *pbr; + + if(pc && isPCI(pc)) { + pbr = PCI(pc)->label; + while(pbr) { + if(isPCL(pbr->pc) && (PCL(pbr->pc)->key >= 0)) + return TRUE; + + pbr = pbr->next; + } + } + + return FALSE; +} + +/*-----------------------------------------------------------------*/ +/* findLabelinpBlock - Search the pCode for a particular label */ +/*-----------------------------------------------------------------*/ +static pCode * findLabelinpBlock(pBlock *pb,pCodeOpLabel *pcop_label) +{ + pCode *pc; + + if(!pb) + return NULL; + + for(pc = pb->pcHead; pc; pc = pc->next) + if(compareLabel(pc,pcop_label)) + return pc; + + return NULL; +} + +/*-----------------------------------------------------------------*/ +/* findLabel - Search the pCode for a particular label */ +/*-----------------------------------------------------------------*/ +static pCode * findLabel(pCodeOpLabel *pcop_label) +{ + pBlock *pb; + pCode *pc; + + if(!the_pFile) + return NULL; + + for(pb = the_pFile->pbHead; pb; pb = pb->next) { + if( (pc = findLabelinpBlock(pb,pcop_label)) != NULL) + return pc; + } + + fprintf(stderr,"Couldn't find label %s", pcop_label->pcop.name); + return NULL; +} + +/*-----------------------------------------------------------------*/ +/* pic16_findNextpCode - given a pCode, find the next of type 'pct' */ +/* in the linked list */ +/*-----------------------------------------------------------------*/ +pCode * pic16_findNextpCode(pCode *pc, PC_TYPE pct) +{ + + while(pc) { + if(pc->type == pct) + return pc; + + pc = pc->next; + } + + return NULL; +} + +/*-----------------------------------------------------------------*/ +/* findPrevpCode - given a pCode, find the previous of type 'pct' */ +/* in the linked list */ +/*-----------------------------------------------------------------*/ +static pCode * findPrevpCode(pCode *pc, PC_TYPE pct) +{ + + while(pc) { + if(pc->type == pct) + return pc; + + pc = pc->prev; + } + + return NULL; +} +/*-----------------------------------------------------------------*/ +/* pic16_findNextInstruction - given a pCode, find the next instruction */ +/* in the linked list */ +/*-----------------------------------------------------------------*/ +pCode * pic16_findNextInstruction(pCode *pci) +{ + pCode *pc = pci; + + while(pc) { + if((pc->type == PC_OPCODE) || (pc->type == PC_WILD)) + return pc; + +#ifdef PCODE_DEBUG + fprintf(stderr,"pic16_findNextInstruction: "); + printpCode(stderr, pc); +#endif + pc = pc->next; + } + + //fprintf(stderr,"Couldn't find instruction\n"); + return NULL; +} + +/*-----------------------------------------------------------------*/ +/* pic16_findNextInstruction - given a pCode, find the next instruction */ +/* in the linked list */ +/*-----------------------------------------------------------------*/ +pCode * pic16_findPrevInstruction(pCode *pci) +{ + return findPrevpCode(pci, PC_OPCODE); +} + +/*-----------------------------------------------------------------*/ +/* findFunctionEnd - given a pCode find the end of the function */ +/* that contains it */ +/*-----------------------------------------------------------------*/ +static pCode * findFunctionEnd(pCode *pc) +{ + + while(pc) { + if(pc->type == PC_FUNCTION && !(PCF(pc)->fname)) + return pc; + + pc = pc->next; + } + + fprintf(stderr,"Couldn't find function end\n"); + return NULL; +} + +#if 0 +/*-----------------------------------------------------------------*/ +/* AnalyzeLabel - if the pCode is a label, then merge it with the */ +/* instruction with which it is associated. */ +/*-----------------------------------------------------------------*/ +static void AnalyzeLabel(pCode *pc) +{ + + pCodeUnlink(pc); + +} +#endif + +#if 0 +static void AnalyzeGOTO(pCode *pc) +{ + + pBranchLink(pc,findLabel( (pCodeOpLabel *) (PCI(pc)->pcop) )); + +} + +static void AnalyzeSKIP(pCode *pc) +{ + + pBranchLink(pc,pic16_findNextInstruction(pc->next)); + pBranchLink(pc,pic16_findNextInstruction(pc->next->next)); + +} + +static void AnalyzeRETURN(pCode *pc) +{ + + // branch_link(pc,findFunctionEnd(pc->next)); + +} + +#endif + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +regs * pic16_getRegFromInstruction(pCode *pc) +{ + + if(!pc || + !isPCI(pc) || + !PCI(pc)->pcop || + PCI(pc)->num_ops == 0 || + (PCI(pc)->num_ops == 1 && PCI(pc)->isFastCall)) + return NULL; + + switch(PCI(pc)->pcop->type) { + case PO_INDF0: + case PO_FSR0: + return PCOR(PCI(pc)->pcop)->r; + + // return typeRegWithIdx (PCOR(PCI(pc)->pcop)->rIdx, REG_SFR, 0); + + case PO_BIT: + case PO_GPR_TEMP: + //fprintf(stderr, "pic16_getRegFromInstruction - bit or temp\n"); + return PCOR(PCI(pc)->pcop)->r; + + case PO_IMMEDIATE: + if(PCOI(PCI(pc)->pcop)->r) + return (PCOI(PCI(pc)->pcop)->r); + + //fprintf(stderr, "pic16_getRegFromInstruction - immediate\n"); + return pic16_dirregWithName(PCI(pc)->pcop->name); + //return NULL; // PCOR(PCI(pc)->pcop)->r; + + case PO_GPR_BIT: + return PCOR(PCI(pc)->pcop)->r; + + case PO_DIR: + //fprintf(stderr, "pic16_getRegFromInstruction - dir\n"); + return PCOR(PCI(pc)->pcop)->r; + case PO_LITERAL: + //fprintf(stderr, "pic16_getRegFromInstruction - literal\n"); + break; + + default: + //fprintf(stderr, "pic16_getRegFromInstruction - unknown reg type %d\n",PCI(pc)->pcop->type); + //genericPrint(stderr, pc); + break; + } + + return NULL; + +} + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ + +static void AnalyzepBlock(pBlock *pb) +{ + pCode *pc; + + if(!pb) + return; + + /* Find all of the registers used in this pBlock + * by looking at each instruction and examining it's + * operands + */ + for(pc = pb->pcHead; pc; pc = pc->next) { + + /* Is this an instruction with operands? */ + if(pc->type == PC_OPCODE && PCI(pc)->pcop) { + + if(PCI(pc)->pcop->type == PO_GPR_TEMP) { + + /* Loop through all of the registers declared so far in + this block and see if we find this one there */ + + regs *r = setFirstItem(pb->tregisters); + + while(r) { + if(r->rIdx == PCOR(PCI(pc)->pcop)->r->rIdx) { + PCOR(PCI(pc)->pcop)->r = r; + break; + } + r = setNextItem(pb->tregisters); + } + + if(!r) { + /* register wasn't found */ + //r = Safe_calloc(1, sizeof(regs)); + //memcpy(r,PCOR(PCI(pc)->pcop)->r, sizeof(regs)); + //addSet(&pb->tregisters, r); + addSet(&pb->tregisters, PCOR(PCI(pc)->pcop)->r); + //PCOR(PCI(pc)->pcop)->r = r; + //fprintf(stderr,"added register to pblock: reg %d\n",r->rIdx); + }/* else + fprintf(stderr,"found register in pblock: reg %d\n",r->rIdx); + */ + } + if(PCI(pc)->pcop->type == PO_GPR_REGISTER) { + if(PCOR(PCI(pc)->pcop)->r) { + pic16_allocWithIdx (PCOR(PCI(pc)->pcop)->r->rIdx); + DFPRINTF((stderr,"found register in pblock: reg 0x%x\n",PCOR(PCI(pc)->pcop)->r->rIdx)); + } else { + if(PCI(pc)->pcop->name) + fprintf(stderr,"ERROR: %s is a NULL register\n",PCI(pc)->pcop->name ); + else + fprintf(stderr,"ERROR: NULL register\n"); + } + } + } + + + } +} + +/*-----------------------------------------------------------------*/ +/* */ +/*-----------------------------------------------------------------*/ +#define PCI_HAS_LABEL(x) ((x) && (PCI(x)->label != NULL)) + +static void InsertpFlow(pCode *pc, pCode **pflow) +{ + if(*pflow) + PCFL(*pflow)->end = pc; + + if(!pc || !pc->next) + return; + + *pflow = pic16_newpCodeFlow(); + pic16_pCodeInsertAfter(pc, *pflow); +} + +/*-----------------------------------------------------------------*/ +/* pic16_BuildFlow(pBlock *pb) - examine the code in a pBlock and build */ +/* the flow blocks. */ +/* + * pic16_BuildFlow inserts pCodeFlow objects into the pCode chain at each + * point the instruction flow changes. + */ +/*-----------------------------------------------------------------*/ +void pic16_BuildFlow(pBlock *pb) +{ + pCode *pc; + pCode *last_pci=NULL; + pCode *pflow=NULL; + int seq = 0; + + if(!pb) + return; + + //fprintf (stderr,"build flow start seq %d ",GpcFlowSeq); + /* Insert a pCodeFlow object at the beginning of a pBlock */ + + InsertpFlow(pb->pcHead, &pflow); + + //pflow = pic16_newpCodeFlow(); /* Create a new Flow object */ + //pflow->next = pb->pcHead; /* Make the current head the next object */ + //pb->pcHead->prev = pflow; /* let the current head point back to the flow object */ + //pb->pcHead = pflow; /* Make the Flow object the head */ + //pflow->pb = pb; + + for( pc = pic16_findNextInstruction(pb->pcHead); + pc != NULL; + pc=pic16_findNextInstruction(pc)) { + + pc->seq = seq++; + PCI(pc)->pcflow = PCFL(pflow); + + //fprintf(stderr," build: "); + //pflow->print(stderr,pflow); + + if( PCI(pc)->isSkip) { + + /* The two instructions immediately following this one + * mark the beginning of a new flow segment */ + + while(pc && PCI(pc)->isSkip) { + + PCI(pc)->pcflow = PCFL(pflow); + pc->seq = seq-1; + seq = 1; + + InsertpFlow(pc, &pflow); + pc=pic16_findNextInstruction(pc->next); + } + + seq = 0; + + if(!pc) + break; + + PCI(pc)->pcflow = PCFL(pflow); + pc->seq = 0; + InsertpFlow(pc, &pflow); + + } else if ( PCI(pc)->isBranch && !checkLabel(pic16_findNextInstruction(pc->next))) { + + InsertpFlow(pc, &pflow); + seq = 0; + + } else if (checkLabel(pc)) { + + /* This instruction marks the beginning of a + * new flow segment */ + + pc->seq = 0; + seq = 1; + + /* If the previous pCode is not a flow object, then + * insert a new flow object. (This check prevents + * two consecutive flow objects from being insert in + * the case where a skip instruction preceeds an + * instruction containing a label.) */ + + if(last_pci && (PCI(last_pci)->pcflow == PCFL(pflow))) + InsertpFlow(pic16_findPrevInstruction(pc->prev), &pflow); + + PCI(pc)->pcflow = PCFL(pflow); + + } + last_pci = pc; + pc = pc->next; + } + + //fprintf (stderr,",end seq %d",GpcFlowSeq); + if(pflow) + PCFL(pflow)->end = pb->pcTail; +} + +/*-------------------------------------------------------------------*/ +/* unBuildFlow(pBlock *pb) - examine the code in a pBlock and build */ +/* the flow blocks. */ +/* + * unBuildFlow removes pCodeFlow objects from a pCode chain + */ +/*-----------------------------------------------------------------*/ +static void unBuildFlow(pBlock *pb) +{ + pCode *pc,*pcnext; + + if(!pb) + return; + + pc = pb->pcHead; + + while(pc) { + pcnext = pc->next; + + if(isPCI(pc)) { + + pc->seq = 0; + if(PCI(pc)->pcflow) { + //free(PCI(pc)->pcflow); + PCI(pc)->pcflow = NULL; + } + + } else if(isPCFL(pc) ) + pc->destruct(pc); + + pc = pcnext; + } + + +} + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +static void dumpCond(int cond) +{ + + static char *pcc_str[] = { + //"PCC_NONE", + "PCC_REGISTER", + "PCC_REGISTER2", + "PCC_C", + "PCC_Z", + "PCC_DC", + "PCC_OV", + "PCC_N", + "PCC_W", + "PCC_EXAMINE_PCOP", + "PCC_LITERAL", + "PCC_REL_ADDR" + }; + + int ncond = sizeof(pcc_str) / sizeof(char *); + int i,j; + + fprintf(stderr, "0x%04X\n",cond); + + for(i=0,j=1; ipc.seq); + + pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE); + + if(!pc) { + fprintf(stderr, " FlowStats - empty flow (seq=%d)\n", pcflow->pc.seq); + return; + } + + + fprintf(stderr, " FlowStats inCond: "); + dumpCond(pcflow->inCond); + fprintf(stderr, " FlowStats outCond: "); + dumpCond(pcflow->outCond); + +} + +/*-----------------------------------------------------------------* + * int isBankInstruction(pCode *pc) - examine the pCode *pc to determine + * if it affects the banking bits. + * + * return: -1 == Banking bits are unaffected by this pCode. + * + * return: > 0 == Banking bits are affected. + * + * If the banking bits are affected, then the returned value describes + * which bits are affected and how they're affected. The lower half + * of the integer maps to the bits that are affected, the upper half + * to whether they're set or cleared. + * + *-----------------------------------------------------------------*/ + +static int isBankInstruction(pCode *pc) +{ + regs *reg; + int bank = -1; + + if(!isPCI(pc)) + return -1; + + if( PCI(pc)->op == POC_MOVLB || + (( (reg = pic16_getRegFromInstruction(pc)) != NULL) && isBSR_REG(reg))) { + bank = PCOL(pc)->lit; + } + + return bank; +} + + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +static void FillFlow(pCodeFlow *pcflow) +{ + + pCode *pc; + int cur_bank; + + if(!isPCFL(pcflow)) + return; + + // fprintf(stderr, " FillFlow - flow block (seq=%d)\n", pcflow->pc.seq); + + pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE); + + if(!pc) { + //fprintf(stderr, " FillFlow - empty flow (seq=%d)\n", pcflow->pc.seq); + return; + } + + cur_bank = -1; + + do { + isBankInstruction(pc); + pc = pc->next; + } while (pc && (pc != pcflow->end) && !isPCFL(pc)); + +/* + if(!pc ) { + fprintf(stderr, " FillFlow - Bad end of flow\n"); + } else { + fprintf(stderr, " FillFlow - Ending flow with\n "); + pc->print(stderr,pc); + } + + fprintf(stderr, " FillFlow inCond: "); + dumpCond(pcflow->inCond); + fprintf(stderr, " FillFlow outCond: "); + dumpCond(pcflow->outCond); +*/ +} + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +static void LinkFlow_pCode(pCodeInstruction *from, pCodeInstruction *to) +{ + pCodeFlowLink *fromLink, *toLink; + + if(!from || !to || !to->pcflow || !from->pcflow) + return; + + fromLink = pic16_newpCodeFlowLink(from->pcflow); + toLink = pic16_newpCodeFlowLink(to->pcflow); + + addSetIfnotP(&(from->pcflow->to), toLink); //to->pcflow); + addSetIfnotP(&(to->pcflow->from), fromLink); //from->pcflow); + +} + +/*-----------------------------------------------------------------* + * void LinkFlow(pBlock *pb) + * + * In pic16_BuildFlow, the PIC code has been partitioned into contiguous + * non-branching segments. In LinkFlow, we determine the execution + * order of these segments. For example, if one of the segments ends + * with a skip, then we know that there are two possible flow segments + * to which control may be passed. + *-----------------------------------------------------------------*/ +static void LinkFlow(pBlock *pb) +{ + pCode *pc=NULL; + pCode *pcflow; + pCode *pct; + + //fprintf(stderr,"linkflow \n"); + + for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); + pcflow != NULL; + pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) { + + if(!isPCFL(pcflow)) + fprintf(stderr, "LinkFlow - pcflow is not a flow object "); + + //fprintf(stderr," link: "); + //pcflow->print(stderr,pcflow); + + //FillFlow(PCFL(pcflow)); + + pc = PCFL(pcflow)->end; + + //fprintf(stderr, "LinkFlow - flow block (seq=%d) ", pcflow->seq); + if(isPCI_SKIP(pc)) { + //fprintf(stderr, "ends with skip\n"); + //pc->print(stderr,pc); + pct=pic16_findNextInstruction(pc->next); + LinkFlow_pCode(PCI(pc),PCI(pct)); + pct=pic16_findNextInstruction(pct->next); + LinkFlow_pCode(PCI(pc),PCI(pct)); + continue; + } + + if(isPCI_BRANCH(pc)) { + pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop); + + //fprintf(stderr, "ends with branch\n "); + //pc->print(stderr,pc); + + if(!(pcol && isPCOLAB(pcol))) { + if((PCI(pc)->op != POC_RETLW) && (PCI(pc)->op != POC_RETURN) && (PCI(pc)->op != POC_CALL) && (PCI(pc)->op != POC_RETFIE) ) { + pc->print(stderr,pc); + fprintf(stderr, "ERROR: %s, branch instruction doesn't have label\n",__FUNCTION__); + } + continue; + } + + if( (pct = findLabelinpBlock(pb,pcol)) != NULL) + LinkFlow_pCode(PCI(pc),PCI(pct)); + else + fprintf(stderr, "ERROR: %s, couldn't find label. key=%d,lab=%s\n", + __FUNCTION__,pcol->key,((PCOP(pcol)->name)?PCOP(pcol)->name:"-")); + //fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",key,((s)?s:"")); + + continue; + } + + if(isPCI(pc)) { + //fprintf(stderr, "ends with non-branching instruction:\n"); + //pc->print(stderr,pc); + + LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next))); + + continue; + } + + if(pc) { + //fprintf(stderr, "ends with unknown\n"); + //pc->print(stderr,pc); + continue; + } + + //fprintf(stderr, "ends with nothing: ERROR\n"); + + } +} +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +int pic16_isPCinFlow(pCode *pc, pCode *pcflow) +{ + + if(!pc || !pcflow) + return 0; + + if(!isPCI(pc) || !PCI(pc)->pcflow || !isPCFL(pcflow) ) + return 0; + + if( PCI(pc)->pcflow->pc.seq == pcflow->seq) + return 1; + + return 0; +} + +/*-----------------------------------------------------------------*/ +/* BanksUsedFlow - Identify which banks are used in flow 2. */ +/*-----------------------------------------------------------------*/ +static void BanksUsedFlow2(pCode *pcflow) +{ + pCode *pc=NULL; + + int bank = -1; + bool RegUsed = 0; + + regs *reg; + + if(!isPCFL(pcflow)) { + fprintf(stderr, "BanksUsed - pcflow is not a flow object "); + return; + } + + pc = pic16_findNextInstruction(pcflow->next); + + PCFL(pcflow)->lastBank = -1; + + while(pic16_isPCinFlow(pc,pcflow)) { + + int bank_selected = isBankInstruction(pc); + + //if(PCI(pc)->pcflow) + //fprintf(stderr,"BanksUsedFlow2, looking at seq %d\n",PCI(pc)->pcflow->pc.seq); + + if(bank_selected >= 0) { + //fprintf(stderr,"BanksUsed - mucking with bank %d\n",bank_selected); + + /* This instruction is modifying banking bits before accessing registers */ + if(!RegUsed) + PCFL(pcflow)->firstBank = -1; + + if(PCFL(pcflow)->lastBank == -1) + PCFL(pcflow)->lastBank = 0; + + bank = 1 << bank_selected; + PCFL(pcflow)->lastBank |= bank; + + + } else { + reg = pic16_getRegFromInstruction(pc); + + if(reg && !pic16_isREGinBank(reg, bank)) { + int allbanks = pic16_REGallBanks(reg); + if(bank == -1) + PCFL(pcflow)->firstBank = allbanks; + + PCFL(pcflow)->lastBank = allbanks; + + bank = allbanks; + } + RegUsed = 1; + } + + pc = pic16_findNextInstruction(pc->next); + } + +// fprintf(stderr,"BanksUsedFlow2 flow seq=%3d, first bank = 0x%03x, Last bank 0x%03x\n", +// pcflow->seq,PCFL(pcflow)->firstBank,PCFL(pcflow)->lastBank); + + + +} +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +static void BanksUsedFlow(pBlock *pb) +{ + pCode *pcflow; + + + //pb->pcHead->print(stderr, pb->pcHead); + + pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); + //pcflow->print(stderr,pcflow); + + for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); + pcflow != NULL; + pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) { + + BanksUsedFlow2(pcflow); + } + +} + + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +static void insertBankSwitch(int position, pCode *pc, int bsr) +{ + pCode *new_pc; + + if(!pc) + return; + + new_pc = pic16_newpCode(POC_MOVLB, pic16_newpCodeOpLit(bsr)); + + if(position) { + /* insert the bank switch after this pc instruction */ + pCode *pcnext = pic16_findNextInstruction(pc); + pic16_pCodeInsertAfter(pc, new_pc); + if(pcnext) + pc = pcnext; + + } else + pic16_pCodeInsertAfter(pc->prev, new_pc); + + /* Move the label, if there is one */ + + if(PCI(pc)->label) { + PCI(new_pc)->label = PCI(pc)->label; + PCI(pc)->label = NULL; + } + + /* The new instruction has the same pcflow block */ + PCI(new_pc)->pcflow = PCI(pc)->pcflow; + +} +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +static void FixRegisterBankingInFlow(pCodeFlow *pcfl, int cur_bank) +{ + pCode *pc=NULL; + pCode *pcprev=NULL; + pCode *new_pc; + + regs *reg; + + if(!pcfl) + return; + + pc = pic16_findNextInstruction(pcfl->pc.next); + + while(pic16_isPCinFlow(pc,PCODE(pcfl))) { + + reg = pic16_getRegFromInstruction(pc); +#if 0 + if(reg) { + fprintf(stderr, " %s ",reg->name); + fprintf(stderr, "addr = 0x%03x, bank = %d\n",reg->address,REG_BANK(reg)); + + } +#endif + + if( ( (reg && !isACCESS_BANK(reg) && REG_BANK(reg)!=cur_bank) || + ((PCI(pc)->op == POC_CALL) && (cur_bank != 0) ) ) && + (!isPCI_LIT(pc)) ){ + + /* Examine the instruction before this one to make sure it is + * not a skip type instruction */ + pcprev = findPrevpCode(pc->prev, PC_OPCODE); + + if(!pcprev || (pcprev && !isPCI_SKIP(pcprev))) { + int reg_bank; + + reg_bank = (reg) ? REG_BANK(reg) : 0; + + + if (cur_bank != reg_bank) { + //fprintf(stderr, "Cool! can switch banks\n"); + cur_bank = reg_bank; + insertBankSwitch(0, pc, cur_bank); + } + + } else { + //fprintf(stderr, "Bummer can't switch banks\n"); + ; + } + } + + pcprev = pc; + pc = pic16_findNextInstruction(pc->next); + + } + + if(pcprev && cur_bank) { + /* Brute force - make sure that we point to bank 0 at the + * end of each flow block */ + new_pc = pic16_newpCode(POC_MOVLB, pic16_newpCodeOpLit(0)); + pic16_pCodeInsertAfter(pcprev, new_pc); + cur_bank = 0; + //fprintf(stderr, "Brute force switch\n"); + } + +} + +/*-----------------------------------------------------------------*/ +/*int compareBankFlow - compare the banking requirements between */ +/* flow objects. */ +/*-----------------------------------------------------------------*/ +static int compareBankFlow(pCodeFlow *pcflow, pCodeFlowLink *pcflowLink, int toORfrom) +{ + + if(!pcflow || !pcflowLink || !pcflowLink->pcflow) + return 0; + + if(!isPCFL(pcflow) || !isPCFL(pcflowLink->pcflow)) + return 0; + + if(pcflow->firstBank == -1) + return 0; + + + if(pcflowLink->pcflow->firstBank == -1) { + pCodeFlowLink *pctl = setFirstItem( toORfrom ? + pcflowLink->pcflow->to : + pcflowLink->pcflow->from); + return compareBankFlow(pcflow, pctl, toORfrom); + } + + if(toORfrom) { + if(pcflow->lastBank == pcflowLink->pcflow->firstBank) + return 0; + + pcflowLink->bank_conflict++; + pcflowLink->pcflow->FromConflicts++; + pcflow->ToConflicts++; + } else { + + if(pcflow->firstBank == pcflowLink->pcflow->lastBank) + return 0; + + pcflowLink->bank_conflict++; + pcflowLink->pcflow->ToConflicts++; + pcflow->FromConflicts++; + + } + /* + fprintf(stderr,"compare flow found conflict: seq %d from conflicts %d, to conflicts %d\n", + pcflowLink->pcflow->pc.seq, + pcflowLink->pcflow->FromConflicts, + pcflowLink->pcflow->ToConflicts); + */ + return 1; + +} +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +static void FixBankFlow(pBlock *pb) +{ + pCode *pc=NULL; + pCode *pcflow; + pCodeFlowLink *pcfl; + + pCode *pcflow_max_To=NULL; + pCode *pcflow_max_From=NULL; + int max_ToConflicts=0; + int max_FromConflicts=0; + + //fprintf(stderr,"Fix Bank flow \n"); + pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); + + + /* + First loop through all of the flow objects in this pcode block + and fix the ones that have banking conflicts between the + entry and exit. + */ + + //fprintf(stderr, "FixBankFlow - Phase 1\n"); + + for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); + pcflow != NULL; + pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) { + + if(!isPCFL(pcflow)) { + fprintf(stderr, "FixBankFlow - pcflow is not a flow object "); + continue; + } + + if(PCFL(pcflow)->firstBank != PCFL(pcflow)->lastBank && + PCFL(pcflow)->firstBank >= 0 && + PCFL(pcflow)->lastBank >= 0 ) { + + int cur_bank = (PCFL(pcflow)->firstBank < PCFL(pcflow)->lastBank) ? + PCFL(pcflow)->firstBank : PCFL(pcflow)->lastBank; + + FixRegisterBankingInFlow(PCFL(pcflow),cur_bank); + BanksUsedFlow2(pcflow); + + } + } + + //fprintf(stderr, "FixBankFlow - Phase 2\n"); + + for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); + pcflow != NULL; + pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) { + + int nFlows; + int nConflicts; + + if(!isPCFL(pcflow)) { + fprintf(stderr, "FixBankFlow - pcflow is not a flow object "); + continue; + } + + PCFL(pcflow)->FromConflicts = 0; + PCFL(pcflow)->ToConflicts = 0; + + nFlows = 0; + nConflicts = 0; + + //fprintf(stderr, " FixBankFlow flow seq %d\n",pcflow->seq); + pcfl = setFirstItem(PCFL(pcflow)->from); + while (pcfl) { + + pc = PCODE(pcfl->pcflow); + + if(!isPCFL(pc)) { + fprintf(stderr,"oops dumpflow - to is not a pcflow\n"); + pc->print(stderr,pc); + } + + nConflicts += compareBankFlow(PCFL(pcflow), pcfl, 0); + nFlows++; + + pcfl=setNextItem(PCFL(pcflow)->from); + } + + if((nFlows >= 2) && nConflicts && (PCFL(pcflow)->firstBank>0)) { + //fprintf(stderr, " From conflicts flow seq %d, nflows %d ,nconflicts %d\n",pcflow->seq,nFlows, nConflicts); + + FixRegisterBankingInFlow(PCFL(pcflow),0); + BanksUsedFlow2(pcflow); + + continue; /* Don't need to check the flow from here - it's already been fixed */ + + } + + nFlows = 0; + nConflicts = 0; + + pcfl = setFirstItem(PCFL(pcflow)->to); + while (pcfl) { + + pc = PCODE(pcfl->pcflow); + if(!isPCFL(pc)) { + fprintf(stderr,"oops dumpflow - to is not a pcflow\n"); + pc->print(stderr,pc); + } + + nConflicts += compareBankFlow(PCFL(pcflow), pcfl, 1); + nFlows++; + + pcfl=setNextItem(PCFL(pcflow)->to); + } + + if((nFlows >= 2) && nConflicts &&(nConflicts != nFlows) && (PCFL(pcflow)->lastBank>0)) { + //fprintf(stderr, " To conflicts flow seq %d, nflows %d ,nconflicts %d\n",pcflow->seq,nFlows, nConflicts); + + FixRegisterBankingInFlow(PCFL(pcflow),0); + BanksUsedFlow2(pcflow); + } + } + + /* + Loop through the flow objects again and find the ones with the + maximum conflicts + */ + + for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); + pcflow != NULL; + pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) { + + if(PCFL(pcflow)->ToConflicts > max_ToConflicts) + pcflow_max_To = pcflow; + + if(PCFL(pcflow)->FromConflicts > max_FromConflicts) + pcflow_max_From = pcflow; + } +/* + if(pcflow_max_To) + fprintf(stderr,"compare flow Max To conflicts: seq %d conflicts %d\n", + PCFL(pcflow_max_To)->pc.seq, + PCFL(pcflow_max_To)->ToConflicts); + + if(pcflow_max_From) + fprintf(stderr,"compare flow Max From conflicts: seq %d conflicts %d\n", + PCFL(pcflow_max_From)->pc.seq, + PCFL(pcflow_max_From)->FromConflicts); +*/ +} + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +static void DumpFlow(pBlock *pb) +{ + pCode *pc=NULL; + pCode *pcflow; + pCodeFlowLink *pcfl; + + + fprintf(stderr,"Dump flow \n"); + pb->pcHead->print(stderr, pb->pcHead); + + pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); + pcflow->print(stderr,pcflow); + + for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); + pcflow != NULL; + pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) { + + if(!isPCFL(pcflow)) { + fprintf(stderr, "DumpFlow - pcflow is not a flow object "); + continue; + } + fprintf(stderr,"dumping: "); + pcflow->print(stderr,pcflow); + FlowStats(PCFL(pcflow)); + + for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) { + + pc = PCODE(pcfl->pcflow); + + fprintf(stderr, " from seq %d:\n",pc->seq); + if(!isPCFL(pc)) { + fprintf(stderr,"oops dumpflow - from is not a pcflow\n"); + pc->print(stderr,pc); + } + + } + + for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) { + + pc = PCODE(pcfl->pcflow); + + fprintf(stderr, " to seq %d:\n",pc->seq); + if(!isPCFL(pc)) { + fprintf(stderr,"oops dumpflow - to is not a pcflow\n"); + pc->print(stderr,pc); + } + + } + + } + +} + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +static int OptimizepBlock(pBlock *pb) +{ + pCode *pc, *pcprev; + int matches =0; + + if(!pb || !peepOptimizing) + return 0; + + DFPRINTF((stderr," Optimizing pBlock: %c\n",getpBlock_dbName(pb))); +/* + for(pc = pb->pcHead; pc; pc = pc->next) + matches += pic16_pCodePeepMatchRule(pc); +*/ + + pc = pic16_findNextInstruction(pb->pcHead); + if(!pc) + return 0; + + pcprev = pc->prev; + do { + + + if(pic16_pCodePeepMatchRule(pc)) { + + matches++; + + if(pcprev) + pc = pic16_findNextInstruction(pcprev->next); + else + pc = pic16_findNextInstruction(pb->pcHead); + } else + pc = pic16_findNextInstruction(pc->next); + } while(pc); + + if(matches) + DFPRINTF((stderr," Optimizing pBlock: %c - matches=%d\n",getpBlock_dbName(pb),matches)); + return matches; + +} + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +static pCode * findInstructionUsingLabel(pCodeLabel *pcl, pCode *pcs) +{ + pCode *pc; + + for(pc = pcs; pc; pc = pc->next) { + + if((pc->type == PC_OPCODE) && + (PCI(pc)->pcop) && + (PCI(pc)->pcop->type == PO_LABEL) && + (PCOLAB(PCI(pc)->pcop)->key == pcl->key)) + return pc; + } + + + return NULL; +} + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +static void exchangeLabels(pCodeLabel *pcl, pCode *pc) +{ + + char *s=NULL; + + if(isPCI(pc) && + (PCI(pc)->pcop) && + (PCI(pc)->pcop->type == PO_LABEL)) { + + pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop); + + //fprintf(stderr,"changing label key from %d to %d\n",pcol->key, pcl->key); + if(pcol->pcop.name) + free(pcol->pcop.name); + + /* If the key is negative, then we (probably) have a label to + * a function and the name is already defined */ + + if(pcl->key>0) + sprintf(s=buffer,"_%05d_DS_",pcl->key); + else + s = pcl->label; + + //sprintf(buffer,"_%05d_DS_",pcl->key); + if(!s) { + fprintf(stderr, "ERROR %s:%d function label is null\n",__FUNCTION__,__LINE__); + } + pcol->pcop.name = Safe_strdup(s); + pcol->key = pcl->key; + //pc->print(stderr,pc); + + } + + +} + +/*-----------------------------------------------------------------*/ +/* pBlockRemoveUnusedLabels - remove the pCode labels from the */ +/* pCode chain if they're not used. */ +/*-----------------------------------------------------------------*/ +static void pBlockRemoveUnusedLabels(pBlock *pb) +{ + pCode *pc; pCodeLabel *pcl; + + if(!pb) + return; + + for(pc = pb->pcHead; (pc=pic16_findNextInstruction(pc->next)) != NULL; ) { + + pBranch *pbr = PCI(pc)->label; + if(pbr && pbr->next) { + pCode *pcd = pb->pcHead; + + //fprintf(stderr, "multiple labels\n"); + //pc->print(stderr,pc); + + pbr = pbr->next; + while(pbr) { + + while ( (pcd = findInstructionUsingLabel(PCL(PCI(pc)->label->pc), pcd)) != NULL) { + //fprintf(stderr,"Used by:\n"); + //pcd->print(stderr,pcd); + + exchangeLabels(PCL(pbr->pc),pcd); + + pcd = pcd->next; + } + pbr = pbr->next; + } + } + } + + for(pc = pb->pcHead; pc; pc = pc->next) { + + if(isPCL(pc)) // pc->type == PC_LABEL) + pcl = PCL(pc); + else if (isPCI(pc) && PCI(pc)->label) //((pc->type == PC_OPCODE) && PCI(pc)->label) + pcl = PCL(PCI(pc)->label->pc); + else continue; + + //fprintf(stderr," found A LABEL !!! key = %d, %s\n", pcl->key,pcl->label); + + /* This pCode is a label, so search the pBlock to see if anyone + * refers to it */ + + if( (pcl->key>0) && (!findInstructionUsingLabel(pcl, pb->pcHead))) { + //if( !findInstructionUsingLabel(pcl, pb->pcHead)) { + /* Couldn't find an instruction that refers to this label + * So, unlink the pCode label from it's pCode chain + * and destroy the label */ + //fprintf(stderr," removed A LABEL !!! key = %d, %s\n", pcl->key,pcl->label); + + DFPRINTF((stderr," !!! REMOVED A LABEL !!! key = %d, %s\n", pcl->key,pcl->label)); + if(pc->type == PC_LABEL) { + pic16_unlinkpCode(pc); + pCodeLabelDestruct(pc); + } else { + unlinkpCodeFromBranch(pc, PCODE(pcl)); + /*if(pc->label->next == NULL && pc->label->pc == NULL) { + free(pc->label); + }*/ + } + + } + } + +} + + +/*-----------------------------------------------------------------*/ +/* pic16_pBlockMergeLabels - remove the pCode labels from the pCode */ +/* chain and put them into pBranches that are */ +/* associated with the appropriate pCode */ +/* instructions. */ +/*-----------------------------------------------------------------*/ +void pic16_pBlockMergeLabels(pBlock *pb) +{ + pBranch *pbr; + pCode *pc, *pcnext=NULL; + + if(!pb) + return; + + /* First, Try to remove any unused labels */ + //pBlockRemoveUnusedLabels(pb); + + /* Now loop through the pBlock and merge the labels with the opcodes */ + + pc = pb->pcHead; + // for(pc = pb->pcHead; pc; pc = pc->next) { + + while(pc) { + pCode *pcn = pc->next; + + if(pc->type == PC_LABEL) { + + //fprintf(stderr," checking merging label %s\n",PCL(pc)->label); + //fprintf(stderr,"Checking label key = %d\n",PCL(pc)->key); + if((pcnext = pic16_findNextInstruction(pc) )) { + + // Unlink the pCode label from it's pCode chain + pic16_unlinkpCode(pc); + + //fprintf(stderr,"Merged label key = %d\n",PCL(pc)->key); + // And link it into the instruction's pBranch labels. (Note, since + // it's possible to have multiple labels associated with one instruction + // we must provide a means to accomodate the additional labels. Thus + // the labels are placed into the singly-linked list "label" as + // opposed to being a single member of the pCodeInstruction.) + + //_ALLOC(pbr,sizeof(pBranch)); + pbr = Safe_calloc(1,sizeof(pBranch)); + pbr->pc = pc; + pbr->next = NULL; + + PCI(pcnext)->label = pic16_pBranchAppend(PCI(pcnext)->label,pbr); + + } else { + fprintf(stderr, "WARNING: couldn't associate label %s with an instruction\n",PCL(pc)->label); + } + } else if(pc->type == PC_CSOURCE) { + + /* merge the source line symbolic info into the next instruction */ + if((pcnext = pic16_findNextInstruction(pc) )) { + + // Unlink the pCode label from it's pCode chain + pic16_unlinkpCode(pc); + PCI(pcnext)->cline = PCCS(pc); + //fprintf(stderr, "merging CSRC\n"); + //genericPrint(stderr,pcnext); + } + + } + pc = pcn; + } + pBlockRemoveUnusedLabels(pb); + +} + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +static int OptimizepCode(char dbName) +{ +#define MAX_PASSES 4 + + int matches = 0; + int passes = 0; + pBlock *pb; + + if(!the_pFile) + return 0; + + DFPRINTF((stderr," Optimizing pCode\n")); + + do { + matches = 0; + for(pb = the_pFile->pbHead; pb; pb = pb->next) { + if('*' == dbName || getpBlock_dbName(pb) == dbName) + matches += OptimizepBlock(pb); + } + } + while(matches && ++passes < MAX_PASSES); + + return matches; +} + +/*-----------------------------------------------------------------*/ +/* pic16_popCopyGPR2Bit - copy a pcode operator */ +/*-----------------------------------------------------------------*/ + +pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval) +{ + pCodeOp *pcop; + + pcop = pic16_newpCodeOpBit(pc->name, bitval, 0); + + if( !( (pcop->type == PO_LABEL) || + (pcop->type == PO_LITERAL) || + (pcop->type == PO_STR) )) + PCOR(pcop)->r = PCOR(pc)->r; /* This is dangerous... */ + + return pcop; +} + + + +#if 0 +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +int InstructionRegBank(pCode *pc) +{ + regs *reg; + + if( (reg = pic16_getRegFromInstruction(pc)) == NULL) + return -1; + + return REG_BANK(reg); + +} +#endif + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +static void FixRegisterBanking(pBlock *pb) +{ + pCode *pc=NULL; + pCode *pcprev=NULL; + + int cur_bank; + regs *reg; + + if(!pb) + return; + + //pc = pic16_findNextpCode(pb->pcHead, PC_FLOW); + pc = pic16_findNextpCode(pb->pcHead, PC_OPCODE); + if(!pc) + return; + /* loop through all of the flow blocks with in one pblock */ + + //fprintf(stderr,"Register banking\n"); + cur_bank = 0; + do { + /* at this point, pc should point to a PC_FLOW object */ + + + /* for each flow block, determine the register banking + requirements */ + + // do { + if(isPCI(pc)) { + //genericPrint(stderr, pc); + + reg = pic16_getRegFromInstruction(pc); +#if 0 + if(reg) { + fprintf(stderr, " %s ",reg->name); + fprintf(stderr, "addr = 0x%03x, bank = %d, bit=%d\n", + reg->address,REG_BANK(reg),reg->isBitField); + + } +#endif + + if( ( (reg && !isACCESS_BANK(reg) && REG_BANK(reg)!=cur_bank) || + ((PCI(pc)->op == POC_CALL) && (cur_bank != 0) ) ) && + (!isPCI_LIT(pc)) ){ + + + /* Examine the instruction before this one to make sure it is + * not a skip type instruction */ + pcprev = findPrevpCode(pc->prev, PC_OPCODE); + + if(!pcprev || (pcprev && !isPCI_SKIP(pcprev))) { + int reg_bank; + + reg_bank = (reg) ? REG_BANK(reg) : 0; + + if (cur_bank != reg_bank) { + cur_bank = reg_bank; + insertBankSwitch(0, pc, cur_bank); + } + + }else { + //fprintf(stderr, "Bummer can't switch banks\n"); + ; + } + } + + pcprev = pc; + + } + + pc = pc->next; + // } while(pc && !(isPCFL(pc))); + + + }while (pc); + + if(pcprev && cur_bank) { + + int pos = 1; /* Assume that the bank switch instruction(s) + * are inserted after this instruction */ + + if((PCI(pcprev)->op == POC_RETLW) || + (PCI(pcprev)->op == POC_RETURN) || + (PCI(pcprev)->op == POC_RETFIE)) { + + /* oops, a RETURN - we need to switch banks *before* the RETURN */ + + pos = 0; + + } + + /* Brute force - make sure that we point to bank 0 at the + * end of each flow block */ + + insertBankSwitch(pos, pcprev, 0); +/* + new_pc = pic16_newpCode(POC_MOVLB, pic16_newpCodeOpLit(0)); + pic16_pCodeInsertAfter(pcprev, new_pc); +*/ + cur_bank = 0; + //fprintf(stderr, "Brute force switch\n"); + } + +} + + + + +#if 0 + if(reg && REG_BANK(reg)!=cur_bank) { + //fprintf(stderr,"need to switch banks\n"); + /* Examine the instruction before this one to make sure it is + * not a skip type instruction */ + pcprev = findPrevpCode(pc->prev, PC_OPCODE); + if(!pcprev || (pcprev && !isPCI_SKIP(pcprev))) { + int b = cur_bank ^ REG_BANK(reg); + + cur_bank = REG_BANK(reg); + + switch(b & 3) { + case 0: + break; + case 1: + insertBankSwitch(0, pc, cur_bank&1, PIC_RP0_BIT); + break; + case 2: + insertBankSwitch(0, pc, cur_bank&2, PIC_RP1_BIT); + insertBankSwitch(0, pc, cur_bank&2, PIC_RP1_BIT); + break; + case 3: + if(cur_bank & 3) { + insertBankSwitch(0, pc, cur_bank&1, PIC_RP0_BIT); + insertBankSwitch(0, pc, cur_bank&2, PIC_RP1_BIT); + } else + insertBankSwitch(0, pc, -1, -1); + break; + + } +#endif + + + + +static void pBlockDestruct(pBlock *pb) +{ + + if(!pb) + return; + + + free(pb); + +} + +/*-----------------------------------------------------------------*/ +/* void mergepBlocks(char dbName) - Search for all pBlocks with the*/ +/* name dbName and combine them */ +/* into one block */ +/*-----------------------------------------------------------------*/ +static void mergepBlocks(char dbName) +{ + + pBlock *pb, *pbmerged = NULL,*pbn; + + pb = the_pFile->pbHead; + + //fprintf(stderr," merging blocks named %c\n",dbName); + while(pb) { + + pbn = pb->next; + //fprintf(stderr,"looking at %c\n",getpBlock_dbName(pb)); + if( getpBlock_dbName(pb) == dbName) { + + //fprintf(stderr," merged block %c\n",dbName); + + if(!pbmerged) { + pbmerged = pb; + } else { + pic16_addpCode2pBlock(pbmerged, pb->pcHead); + /* pic16_addpCode2pBlock doesn't handle the tail: */ + pbmerged->pcTail = pb->pcTail; + + pb->prev->next = pbn; + if(pbn) + pbn->prev = pb->prev; + + + pBlockDestruct(pb); + } + //pic16_printpBlock(stderr, pbmerged); + } + pb = pbn; + } + +} + +/*-----------------------------------------------------------------*/ +/* AnalyzeFlow - Examine the flow of the code and optimize */ +/* */ +/* level 0 == minimal optimization */ +/* optimize registers that are used only by two instructions */ +/* level 1 == maximal optimization */ +/* optimize by looking at pairs of instructions that use the */ +/* register. */ +/*-----------------------------------------------------------------*/ + +static void AnalyzeFlow(int level) +{ + static int times_called=0; + + pBlock *pb; + + if(!the_pFile) + return; + + + /* if this is not the first time this function has been called, + then clean up old flow information */ + if(times_called++) { + for(pb = the_pFile->pbHead; pb; pb = pb->next) + unBuildFlow(pb); + + pic16_RegsUnMapLiveRanges(); + + } + + GpcFlowSeq = 1; + + /* Phase 2 - Flow Analysis - Register Banking + * + * In this phase, the individual flow blocks are examined + * and register banking is fixed. + */ + + //for(pb = the_pFile->pbHead; pb; pb = pb->next) + //FixRegisterBanking(pb); + + /* Phase 2 - Flow Analysis + * + * In this phase, the pCode is partition into pCodeFlow + * blocks. The flow blocks mark the points where a continuous + * stream of instructions changes flow (e.g. because of + * a call or goto or whatever). + */ + + for(pb = the_pFile->pbHead; pb; pb = pb->next) + pic16_BuildFlow(pb); + + + /* Phase 2 - Flow Analysis - linking flow blocks + * + * In this phase, the individual flow blocks are examined + * to determine their order of excution. + */ + + for(pb = the_pFile->pbHead; pb; pb = pb->next) + LinkFlow(pb); + + /* Phase 3 - Flow Analysis - Flow Tree + * + * In this phase, the individual flow blocks are examined + * to determine their order of excution. + */ + + for(pb = the_pFile->pbHead; pb; pb = pb->next) + pic16_BuildFlowTree(pb); + + + /* Phase x - Flow Analysis - Used Banks + * + * In this phase, the individual flow blocks are examined + * to determine the Register Banks they use + */ + + for(pb = the_pFile->pbHead; pb; pb = pb->next) + FixBankFlow(pb); + + + for(pb = the_pFile->pbHead; pb; pb = pb->next) + pic16_pCodeRegMapLiveRanges(pb); + + pic16_RemoveUnusedRegisters(); + + // for(pb = the_pFile->pbHead; pb; pb = pb->next) + pic16_pCodeRegOptimizeRegUsage(level); + + OptimizepCode('*'); + + +/* + for(pb = the_pFile->pbHead; pb; pb = pb->next) + DumpFlow(pb); +*/ + /* debug stuff */ + for(pb = the_pFile->pbHead; pb; pb = pb->next) { + pCode *pcflow; + for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); + (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL; + pcflow = pcflow->next) { + + FillFlow(PCFL(pcflow)); + } + } + +/* + for(pb = the_pFile->pbHead; pb; pb = pb->next) { + pCode *pcflow; + for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); + (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL; + pcflow = pcflow->next) { + + FlowStats(PCFL(pcflow)); + } + } +*/ +} + +/*-----------------------------------------------------------------*/ +/* pic16_AnalyzeBanking - Called after the memory addresses have been */ +/* assigned to the registers. */ +/* */ +/*-----------------------------------------------------------------*/ + +void pic16_AnalyzeBanking(void) +{ + pBlock *pb; + + if(!pic16_picIsInitialized()) { + fprintf(stderr,"Temporary ERROR: at the moment you have to use\n"); + fprintf(stderr,"an include file create by inc2h.pl. See SDCC source:\n"); + fprintf(stderr,"support/scripts/inc2h.pl\n"); + fprintf(stderr,"this is a nuisance bug that will be fixed shortly\n"); + + exit(1); + } + + /* Phase x - Flow Analysis - Used Banks + * + * In this phase, the individual flow blocks are examined + * to determine the Register Banks they use + */ + + AnalyzeFlow(0); + AnalyzeFlow(1); + + for(pb = the_pFile->pbHead; pb; pb = pb->next) + BanksUsedFlow(pb); + for(pb = the_pFile->pbHead; pb; pb = pb->next) + FixRegisterBanking(pb); + +} + +/*-----------------------------------------------------------------*/ +/* buildCallTree - Look at the flow and extract all of the calls. */ +/*-----------------------------------------------------------------*/ +static set *register_usage(pBlock *pb); + +static void buildCallTree(void ) +{ + pBranch *pbr; + pBlock *pb; + pCode *pc; + + if(!the_pFile) + return; + + + + /* Now build the call tree. + First we examine all of the pCodes for functions. + Keep in mind that the function boundaries coincide + with pBlock boundaries. + + The algorithm goes something like this: + We have two nested loops. The outer loop iterates + through all of the pBlocks/functions. The inner + loop iterates through all of the pCodes for + a given pBlock. When we begin iterating through + a pBlock, the variable pc_fstart, pCode of the start + of a function, is cleared. We then search for pCodes + of type PC_FUNCTION. When one is encountered, we + initialize pc_fstart to this and at the same time + associate a new pBranch object that signifies a + branch entry. If a return is found, then this signifies + a function exit point. We'll link the pCodes of these + returns to the matching pc_fstart. + + When we're done, a doubly linked list of pBranches + will exist. The head of this list is stored in + `the_pFile', which is the meta structure for all + of the pCode. Look at the pic16_printCallTree function + on how the pBranches are linked together. + + */ + for(pb = the_pFile->pbHead; pb; pb = pb->next) { + pCode *pc_fstart=NULL; + for(pc = pb->pcHead; pc; pc = pc->next) { + if(isPCF(pc)) { + if (PCF(pc)->fname) { + + if(STRCASECMP(PCF(pc)->fname, "_main") == 0) { + //fprintf(stderr," found main \n"); + pb->cmemmap = NULL; /* FIXME do we need to free ? */ + pb->dbName = 'M'; + } + + pbr = Safe_calloc(1,sizeof(pBranch)); + pbr->pc = pc_fstart = pc; + pbr->next = NULL; + + the_pFile->functions = pic16_pBranchAppend(the_pFile->functions,pbr); + + // Here's a better way of doing the same: + addSet(&pb->function_entries, pc); + + } else { + // Found an exit point in a function, e.g. return + // (Note, there may be more than one return per function) + if(pc_fstart) + pBranchLink(PCF(pc_fstart), PCF(pc)); + + addSet(&pb->function_exits, pc); + } + } else if(isCALL(pc)) { + addSet(&pb->function_calls,pc); + } + } + } + + /* Re-allocate the registers so that there are no collisions + * between local variables when one function call another */ + + // this is weird... + // pic16_deallocateAllRegs(); + + for(pb = the_pFile->pbHead; pb; pb = pb->next) { + if(!pb->visited) + register_usage(pb); + } + +} + +/*-----------------------------------------------------------------*/ +/* pic16_AnalyzepCode - parse the pCode that has been generated and form */ +/* all of the logical connections. */ +/* */ +/* Essentially what's done here is that the pCode flow is */ +/* determined. */ +/*-----------------------------------------------------------------*/ + +void pic16_AnalyzepCode(char dbName) +{ + pBlock *pb; + int i,changes; + + if(!the_pFile) + return; + + mergepBlocks('D'); + + + /* Phase 1 - Register allocation and peep hole optimization + * + * The first part of the analysis is to determine the registers + * that are used in the pCode. Once that is done, the peep rules + * are applied to the code. We continue to loop until no more + * peep rule optimizations are found (or until we exceed the + * MAX_PASSES threshold). + * + * When done, the required registers will be determined. + * + */ + i = 0; + do { + + DFPRINTF((stderr," Analyzing pCode: PASS #%d\n",i+1)); + //fprintf(stderr," Analyzing pCode: PASS #%d\n",i+1); + + /* First, merge the labels with the instructions */ + for(pb = the_pFile->pbHead; pb; pb = pb->next) { + if('*' == dbName || getpBlock_dbName(pb) == dbName) { + + DFPRINTF((stderr," analyze and merging block %c\n",dbName)); + //fprintf(stderr," analyze and merging block %c\n",dbName); + pic16_pBlockMergeLabels(pb); + AnalyzepBlock(pb); + } else { + DFPRINTF((stderr," skipping block analysis dbName=%c blockname=%c\n",dbName,getpBlock_dbName)); + } + } + + changes = OptimizepCode(dbName); + + } while(changes && (i++ < MAX_PASSES)); + + buildCallTree(); +} + +/*-----------------------------------------------------------------*/ +/* ispCodeFunction - returns true if *pc is the pCode of a */ +/* function */ +/*-----------------------------------------------------------------*/ +static bool ispCodeFunction(pCode *pc) +{ + + if(pc && pc->type == PC_FUNCTION && PCF(pc)->fname) + return 1; + + return 0; +} + +/*-----------------------------------------------------------------*/ +/* findFunction - Search for a function by name (given the name) */ +/* in the set of all functions that are in a pBlock */ +/* (note - I expect this to change because I'm planning to limit */ +/* pBlock's to just one function declaration */ +/*-----------------------------------------------------------------*/ +static pCode *findFunction(char *fname) +{ + pBlock *pb; + pCode *pc; + if(!fname) + return NULL; + + for(pb = the_pFile->pbHead; pb; pb = pb->next) { + + pc = setFirstItem(pb->function_entries); + while(pc) { + + if((pc->type == PC_FUNCTION) && + (PCF(pc)->fname) && + (strcmp(fname, PCF(pc)->fname)==0)) + return pc; + + pc = setNextItem(pb->function_entries); + + } + + } + return NULL; +} + +static void MarkUsedRegisters(set *regset) +{ + + regs *r1,*r2; + + for(r1=setFirstItem(regset); r1; r1=setNextItem(regset)) { + r2 = pic16_regWithIdx(r1->rIdx); + r2->isFree = 0; + r2->wasUsed = 1; + } +} + +static void pBlockStats(FILE *of, pBlock *pb) +{ + + pCode *pc; + regs *r; + + fprintf(of,";***\n; pBlock Stats: dbName = %c\n;***\n",getpBlock_dbName(pb)); + + // for now just print the first element of each set + pc = setFirstItem(pb->function_entries); + if(pc) { + fprintf(of,";entry: "); + pc->print(of,pc); + } + pc = setFirstItem(pb->function_exits); + if(pc) { + fprintf(of,";has an exit\n"); + //pc->print(of,pc); + } + + pc = setFirstItem(pb->function_calls); + if(pc) { + fprintf(of,";functions called:\n"); + + while(pc) { + if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) { + fprintf(of,"; %s\n",pic16_get_op_from_instruction(PCI(pc))); + } + pc = setNextItem(pb->function_calls); + } + } + + r = setFirstItem(pb->tregisters); + if(r) { + int n = elementsInSet(pb->tregisters); + + fprintf(of,";%d compiler assigned register%c:\n",n, ( (n!=1) ? 's' : ' ')); + + while (r) { + fprintf(of,"; %s\n",r->name); + r = setNextItem(pb->tregisters); + } + } +} + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +#if 0 +static void sequencepCode(void) +{ + pBlock *pb; + pCode *pc; + + + for(pb = the_pFile->pbHead; pb; pb = pb->next) { + + pb->seq = GpCodeSequenceNumber+1; + + for( pc = pb->pcHead; pc; pc = pc->next) + pc->seq = ++GpCodeSequenceNumber; + } + +} +#endif + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +static set *register_usage(pBlock *pb) +{ + pCode *pc,*pcn; + set *registers=NULL; + set *registersInCallPath = NULL; + + /* check recursion */ + + pc = setFirstItem(pb->function_entries); + + if(!pc) + return registers; + + pb->visited = 1; + + if(pc->type != PC_FUNCTION) + fprintf(stderr,"%s, first pc is not a function???\n",__FUNCTION__); + + pc = setFirstItem(pb->function_calls); + for( ; pc; pc = setNextItem(pb->function_calls)) { + + if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) { + char *dest = pic16_get_op_from_instruction(PCI(pc)); + + pcn = findFunction(dest); + if(pcn) + registersInCallPath = register_usage(pcn->pb); + } else + fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__); + + } + +#ifdef PCODE_DEBUG + pBlockStats(stderr,pb); // debug +#endif + + // Mark the registers in this block as used. + + MarkUsedRegisters(pb->tregisters); + if(registersInCallPath) { + /* registers were used in the functions this pBlock has called */ + /* so now, we need to see if these collide with the ones we are */ + /* using here */ + + regs *r1,*r2, *newreg; + + DFPRINTF((stderr,"comparing registers\n")); + + r1 = setFirstItem(registersInCallPath); + while(r1) { + + r2 = setFirstItem(pb->tregisters); + + while(r2 && (r1->type != REG_STK)) { + + if(r2->rIdx == r1->rIdx) { + newreg = pic16_findFreeReg(REG_GPR); + + + if(!newreg) { + DFPRINTF((stderr,"Bummer, no more registers.\n")); + exit(1); + } + + DFPRINTF((stderr,"Cool found register collision nIdx=%d moving to %d\n", + r1->rIdx, newreg->rIdx)); + r2->rIdx = newreg->rIdx; + //if(r2->name) free(r2->name); + if(newreg->name) + r2->name = Safe_strdup(newreg->name); + else + r2->name = NULL; + newreg->isFree = 0; + newreg->wasUsed = 1; + } + r2 = setNextItem(pb->tregisters); + } + + r1 = setNextItem(registersInCallPath); + } + + /* Collisions have been resolved. Now free the registers in the call path */ + r1 = setFirstItem(registersInCallPath); + while(r1) { + if(r1->type != REG_STK) { + newreg = pic16_regWithIdx(r1->rIdx); + newreg->isFree = 1; + } + r1 = setNextItem(registersInCallPath); + } + + }// else + // MarkUsedRegisters(pb->registers); + + registers = unionSets(pb->tregisters, registersInCallPath, THROW_NONE); +#ifdef PCODE_DEBUG + if(registers) + DFPRINTF((stderr,"returning regs\n")); + else + DFPRINTF((stderr,"not returning regs\n")); + + DFPRINTF((stderr,"pBlock after register optim.\n")); + pBlockStats(stderr,pb); // debug +#endif + + return registers; +} + +/*-----------------------------------------------------------------*/ +/* pct2 - writes the call tree to a file */ +/* */ +/*-----------------------------------------------------------------*/ +static void pct2(FILE *of,pBlock *pb,int indent) +{ + pCode *pc,*pcn; + int i; + // set *registersInCallPath = NULL; + + if(!of) + return; + + if(indent > 10) + return; //recursion ? + + pc = setFirstItem(pb->function_entries); + + if(!pc) + return; + + pb->visited = 0; + + for(i=0;itype == PC_FUNCTION) + fprintf(of,"%s\n",PCF(pc)->fname); + else + return; // ??? + + + pc = setFirstItem(pb->function_calls); + for( ; pc; pc = setNextItem(pb->function_calls)) { + + if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) { + char *dest = pic16_get_op_from_instruction(PCI(pc)); + + pcn = findFunction(dest); + if(pcn) + pct2(of,pcn->pb,indent+1); + } else + fprintf(of,"BUG? pCode isn't a POC_CALL %d\n",__LINE__); + + } + + +} + + +/*-----------------------------------------------------------------*/ +/* pic16_printCallTree - writes the call tree to a file */ +/* */ +/*-----------------------------------------------------------------*/ + +void pic16_printCallTree(FILE *of) +{ + pBranch *pbr; + pBlock *pb; + pCode *pc; + + if(!the_pFile) + return; + + if(!of) + of = stderr; + + fprintf(of, "\npBlock statistics\n"); + for(pb = the_pFile->pbHead; pb; pb = pb->next ) + pBlockStats(of,pb); + + + + fprintf(of,"Call Tree\n"); + pbr = the_pFile->functions; + while(pbr) { + if(pbr->pc) { + pc = pbr->pc; + if(!ispCodeFunction(pc)) + fprintf(of,"bug in call tree"); + + + fprintf(of,"Function: %s\n", PCF(pc)->fname); + + while(pc->next && !ispCodeFunction(pc->next)) { + pc = pc->next; + if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) + fprintf(of,"\t%s\n",pic16_get_op_from_instruction(PCI(pc))); + } + } + + pbr = pbr->next; + } + + + fprintf(of,"\n**************\n\na better call tree\n"); + for(pb = the_pFile->pbHead; pb; pb = pb->next) { + if(pb->visited) + pct2(of,pb,0); + } + + for(pb = the_pFile->pbHead; pb; pb = pb->next) { + fprintf(of,"block dbname: %c\n", getpBlock_dbName(pb)); + } +} + + + +/*-----------------------------------------------------------------*/ +/* */ +/*-----------------------------------------------------------------*/ + +static void InlineFunction(pBlock *pb) +{ + pCode *pc; + pCode *pc_call; + + if(!pb) + return; + + pc = setFirstItem(pb->function_calls); + + for( ; pc; pc = setNextItem(pb->function_calls)) { + + if(isCALL(pc)) { + pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc))); + pCode *pct; + pCode *pce; + + pBranch *pbr; + + if(pcn && isPCF(pcn) && (PCF(pcn)->ncalled == 1)) { + + //fprintf(stderr,"Cool can inline:\n"); + //pcn->print(stderr,pcn); + + //fprintf(stderr,"recursive call Inline\n"); + InlineFunction(pcn->pb); + //fprintf(stderr,"return from recursive call Inline\n"); + + /* + At this point, *pc points to a CALL mnemonic, and + *pcn points to the function that is being called. + + To in-line this call, we need to remove the CALL + and RETURN(s), and link the function pCode in with + the CALLee pCode. + + */ + + + /* Remove the CALL */ + pc_call = pc; + pc = pc->prev; + + /* remove callee pBlock from the pBlock linked list */ + removepBlock(pcn->pb); + + pce = pcn; + while(pce) { + pce->pb = pb; + pce = pce->next; + } + + /* Remove the Function pCode */ + pct = pic16_findNextInstruction(pcn->next); + + /* Link the function with the callee */ + pc->next = pcn->next; + pcn->next->prev = pc; + + /* Convert the function name into a label */ + + pbr = Safe_calloc(1,sizeof(pBranch)); + pbr->pc = pic16_newpCodeLabel(PCF(pcn)->fname, -1); + pbr->next = NULL; + PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,pbr); + PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,PCI(pc_call)->label); + + /* turn all of the return's except the last into goto's */ + /* check case for 2 instruction pBlocks */ + pce = pic16_findNextInstruction(pcn->next); + while(pce) { + pCode *pce_next = pic16_findNextInstruction(pce->next); + + if(pce_next == NULL) { + /* found the last return */ + pCode *pc_call_next = pic16_findNextInstruction(pc_call->next); + + //fprintf(stderr,"found last return\n"); + //pce->print(stderr,pce); + pce->prev->next = pc_call->next; + pc_call->next->prev = pce->prev; + PCI(pc_call_next)->label = pic16_pBranchAppend(PCI(pc_call_next)->label, + PCI(pce)->label); + } + + pce = pce_next; + } + + + } + } else + fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__); + + } + +} + +/*-----------------------------------------------------------------*/ +/* */ +/*-----------------------------------------------------------------*/ + +void pic16_InlinepCode(void) +{ + + pBlock *pb; + pCode *pc; + + if(!the_pFile) + return; + + if(!functionInlining) + return; + + /* Loop through all of the function definitions and count the + * number of times each one is called */ + //fprintf(stderr,"inlining %d\n",__LINE__); + + for(pb = the_pFile->pbHead; pb; pb = pb->next) { + + pc = setFirstItem(pb->function_calls); + + for( ; pc; pc = setNextItem(pb->function_calls)) { + + if(isCALL(pc)) { + pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc))); + if(pcn && isPCF(pcn)) { + PCF(pcn)->ncalled++; + } + } else + fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__); + + } + } + + //fprintf(stderr,"inlining %d\n",__LINE__); + + /* Now, Loop through the function definitions again, but this + * time inline those functions that have only been called once. */ + + InlineFunction(the_pFile->pbHead); + //fprintf(stderr,"inlining %d\n",__LINE__); + + for(pb = the_pFile->pbHead; pb; pb = pb->next) + unBuildFlow(pb); + +} diff --git a/src/pic16/pcode.h b/src/pic16/pcode.h new file mode 100644 index 00000000..c8c24529 --- /dev/null +++ b/src/pic16/pcode.h @@ -0,0 +1,885 @@ +/*------------------------------------------------------------------------- + + pcode.h - post code generation + Written By - Scott Dattalo scott@dattalo.com + Ported to PIC16 By - 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. + +-------------------------------------------------------------------------*/ + +//#include "ralloc.h" +struct regs; + +/* + Post code generation + + The post code generation is an assembler optimizer. The assembly code + produced by all of the previous steps is fully functional. This step + will attempt to analyze the flow of the assembly code and agressively + optimize it. The peep hole optimizer attempts to do the same thing. + As you may recall, the peep hole optimizer replaces blocks of assembly + with more optimal blocks (e.g. removing redundant register loads). + However, the peep hole optimizer has to be somewhat conservative since + an assembly program has implicit state information that's unavailable + when only a few instructions are examined. + Consider this example: + + example1: + movwf t1 + movf t1,w + + The movf seems redundant since we know that the W register already + contains the same value of t1. So a peep hole optimizer is tempted to + remove the "movf". However, this is dangerous since the movf affects + the flags in the status register (specifically the Z flag) and subsequent + code may depend upon this. Look at these two examples: + + example2: + movwf t1 + movf t1,w ; Can't remove this movf + skpz + return + + example3: + movwf t1 + movf t1,w ; This movf can be removed + xorwf t2,w ; since xorwf will over write Z + skpz + return + +*/ + + +#ifndef __PCODE_H__ +#define __PCODE_H__ + +/*********************************************************************** + * debug stuff + * + * The DFPRINTF macro will call fprintf if PCODE_DEBUG is defined. + * The macro is used like: + * + * DPRINTF(("%s #%d\n","test", 1)); + * + * The double parenthesis (()) are necessary + * + ***********************************************************************/ +//#define PCODE_DEBUG + +#ifdef PCODE_DEBUG +#define DFPRINTF(args) (fprintf args) +#else +#define DFPRINTF(args) ; +#endif + + +/*********************************************************************** + * PIC status bits - this will move into device dependent headers + ***********************************************************************/ +#define PIC_C_BIT 0 +#define PIC_DC_BIT 1 +#define PIC_Z_BIT 2 +#define PIC_OV_BIT 3 +#define PIC_N_BIT 4 +#define PIC_IRP_BIT 7 /* Indirect register page select */ + +/*********************************************************************** + * PIC INTCON bits - this will move into device dependent headers + ***********************************************************************/ +#define PIC_RBIF_BIT 0 /* Port B level has changed flag */ +#define PIC_INTF_BIT 1 /* Port B bit 0 interrupt on edge flag */ +#define PIC_T0IF_BIT 2 /* TMR0 has overflowed flag */ +#define PIC_RBIE_BIT 3 /* Port B level has changed - Interrupt Enable */ +#define PIC_INTE_BIT 4 /* Port B bit 0 interrupt on edge - Int Enable */ +#define PIC_T0IE_BIT 5 /* TMR0 overflow Interrupt Enable */ +#define PIC_PIE_BIT 6 /* Peripheral Interrupt Enable */ +#define PIC_GIE_BIT 7 /* Global Interrupt Enable */ + +/*********************************************************************** + * PIC bank definitions + ***********************************************************************/ +#define PIC_BANK_FIRST 0 +#define PIC_BANK_LAST 0xf + + +/*********************************************************************** + * Operand types + ***********************************************************************/ +#define POT_RESULT 0 +#define POT_LEFT 1 +#define POT_RIGHT 2 + + +/*********************************************************************** + * + * PIC_OPTYPE - Operand types that are specific to the PIC architecture + * + * If a PIC assembly instruction has an operand then here is where we + * associate a type to it. For example, + * + * movf reg,W + * + * The movf has two operands: 'reg' and the W register. 'reg' is some + * arbitrary general purpose register, hence it has the type PO_GPR_REGISTER. + * The W register, which is the PIC's accumulator, has the type PO_W. + * + ***********************************************************************/ + + + +typedef enum +{ + PO_NONE=0, // No operand e.g. NOP + PO_W, // The working register (as a destination) + PO_WREG, // The working register (as a file register) + PO_STATUS, // The 'STATUS' register + PO_BSR, // The 'BSR' register + PO_FSR0, // The "file select register" (in PIC18 family it's one + // of three) + PO_INDF0, // The Indirect register + PO_INTCON, // Interrupt Control register + PO_GPR_REGISTER, // A general purpose register + PO_GPR_BIT, // A bit of a general purpose register + PO_GPR_TEMP, // A general purpose temporary register + PO_SFR_REGISTER, // A special function register (e.g. PORTA) + PO_PCL, // Program counter Low register + PO_PCLATH, // Program counter Latch high register + PO_LITERAL, // A constant + PO_REL_ADDR, // A relative address + PO_IMMEDIATE, // (8051 legacy) + PO_DIR, // Direct memory (8051 legacy) + PO_CRY, // bit memory (8051 legacy) + PO_BIT, // bit operand. + PO_STR, // (8051 legacy) + PO_LABEL, + PO_WILD // Wild card operand in peep optimizer +} PIC_OPTYPE; + + +/*********************************************************************** + * + * PIC_OPCODE + * + * This is not a list of the PIC's opcodes per se, but instead + * an enumeration of all of the different types of pic opcodes. + * + ***********************************************************************/ + +typedef enum +{ + POC_WILD=-1, /* Wild card - used in the pCode peep hole optimizer + * to represent ANY pic opcode */ + POC_ADDLW=0, + POC_ADDWF, + POC_ADDFW, + POC_ADDFWC, + POC_ADDWFC, + POC_ANDLW, + POC_ANDWF, + POC_ANDFW, + POC_BC, + POC_BCF, + POC_BN, + POC_BNC, + POC_BNN, + POC_BNOV, + POC_BNZ, + POC_BOV, + POC_BRA, + POC_BSF, + POC_BTFSC, + POC_BTFSS, + POC_BTG, + POC_BZ, + POC_CALL, + POC_CLRF, + POC_CLRWDT, + POC_COMF, + POC_COMFW, + POC_CPFSEQ, + POC_CPFSGT, + POC_CPFSLT, + POC_DAW, + POC_DCFSNZ, + POC_DCFSNZW, + POC_DECF, + POC_DECFW, + POC_DECFSZ, + POC_DECFSZW, + POC_GOTO, + POC_INCF, + POC_INCFW, + POC_INCFSZ, + POC_INCFSZW, + POC_INFSNZ, + POC_IORWF, + POC_IORFW, + POC_IORLW, + POC_LFSR, + POC_MOVF, + POC_MOVFW, + POC_MOVFF, + POC_MOVLB, + POC_MOVLW, + POC_MOVWF, + POC_MULLW, + POC_MULWF, + POC_NEGF, + POC_NOP, + POC_POP, + POC_PUSH, + POC_RCALL, + POC_RETFIE, + POC_RETLW, + POC_RETURN, + POC_RLCF, + POC_RLCFW, + POC_RLNCF, + POC_RLNCFW, + POC_RRCF, + POC_RRCFW, + POC_RRNCF, + POC_RRNCFW, + POC_SETF, + POC_SUBLW, + POC_SUBFWB, + POC_SUBWF, + POC_SUBFW, + POC_SUBWFB_D0, + POC_SUBWFB_D1, + POC_SUBFWB_D0, + POC_SUBFWB_D1, + POC_SWAPF, + POC_SWAPFW, + POC_TRIS, // To be removed + POC_TSTFSZ, + POC_XORLW, + POC_XORWF, + POC_XORFW +} PIC_OPCODE; + + +/*********************************************************************** + * PC_TYPE - pCode Types + ***********************************************************************/ + +typedef enum +{ + PC_COMMENT=0, /* pCode is a comment */ + PC_INLINE, /* user's inline code */ + PC_OPCODE, /* PORT dependent opcode */ + PC_LABEL, /* assembly label */ + PC_FLOW, /* flow analysis */ + PC_FUNCTION, /* Function start or end */ + PC_WILD, /* wildcard - an opcode place holder used + * in the pCode peep hole optimizer */ + PC_CSOURCE, /* C-Source Line */ + PC_BAD /* Mark the pCode object as being bad */ +} PC_TYPE; + +/************************************************/ +/*************** Structures ********************/ +/************************************************/ +/* These are here as forward references - the + * full definition of these are below */ +struct pCode; +struct pCodeWildBlock; +struct pCodeRegLives; + +/************************************************* + pBranch + + The first step in optimizing pCode is determining + the program flow. This information is stored in + single-linked lists in the for of 'from' and 'to' + objects with in a pcode. For example, most instructions + don't involve any branching. So their from branch + points to the pCode immediately preceding them and + their 'to' branch points to the pcode immediately + following them. A skip instruction is an example of + a pcode that has multiple (in this case two) elements + in the 'to' branch. A 'label' pcode is an where there + may be multiple 'from' branches. + *************************************************/ + +typedef struct pBranch +{ + struct pCode *pc; // Next pCode in a branch + struct pBranch *next; /* If more than one branch + * the next one is here */ + +} pBranch; + +/************************************************* + pCodeOp + + pCode Operand structure. + For those assembly instructions that have arguments, + the pCode will have a pCodeOp in which the argument + can be stored. For example + + movf some_register,w + + 'some_register' will be stored/referenced in a pCodeOp + + *************************************************/ + +typedef struct pCodeOp +{ + PIC_OPTYPE type; + char *name; + +} pCodeOp; +#if 0 +typedef struct pCodeOpBit +{ + pCodeOp pcop; + int bit; + unsigned int inBitSpace: 1; /* True if in bit space, else + just a bit of a register */ +} pCodeOpBit; +#endif +typedef struct pCodeOpLit +{ + pCodeOp pcop; + int lit; +} pCodeOpLit; + +typedef struct pCodeOpImmd +{ + pCodeOp pcop; + int offset; /* low,med, or high byte of immediat value */ + int index; /* add this to the immediate value */ + unsigned _const:1; /* is in code space */ + + int rIdx; /* If this immd points to a register */ + struct regs *r; /* then this is the reg. */ + +} pCodeOpImmd; + +typedef struct pCodeOpLabel +{ + pCodeOp pcop; + int key; +} pCodeOpLabel; + +typedef struct pCodeOpReg +{ + pCodeOp pcop; // Can be either GPR or SFR + int rIdx; // Index into the register table + struct regs *r; + int instance; // byte # of Multi-byte registers + struct pBlock *pb; +} pCodeOpReg; + +typedef struct pCodeOpRegBit +{ + pCodeOpReg pcor; // The Register containing this bit + int bit; // 0-7 bit number. + PIC_OPTYPE subtype; // The type of this register. + unsigned int inBitSpace: 1; /* True if in bit space, else + just a bit of a register */ +} pCodeOpRegBit; + + +typedef struct pCodeOpWild +{ + pCodeOp pcop; + + struct pCodeWildBlock *pcwb; + + int id; /* index into an array of char *'s that will match + * the wild card. The array is in *pcp. */ + pCodeOp *subtype; /* Pointer to the Operand type into which this wild + * card will be expanded */ + pCodeOp *matched; /* When a wild matches, we'll store a pointer to the + * opcode we matched */ + +} pCodeOpWild; + + +/************************************************* + pCode + + Here is the basic build block of a PIC instruction. + Each pic instruction will get allocated a pCode. + A linked list of pCodes makes a program. + +**************************************************/ + +typedef struct pCode +{ + PC_TYPE type; + + struct pCode *prev; // The pCode objects are linked together + struct pCode *next; // in doubly linked lists. + + int seq; // sequence number + + struct pBlock *pb; // The pBlock that contains this pCode. + + /* "virtual functions" + * The pCode structure is like a base class + * in C++. The subsequent structures that "inherit" + * the pCode structure will initialize these function + * pointers to something useful */ + // void (*analyze) (struct pCode *_this); + void (*destruct)(struct pCode *_this); + void (*print) (FILE *of,struct pCode *_this); + +} pCode; + + +/************************************************* + pCodeComment +**************************************************/ + +typedef struct pCodeComment +{ + + pCode pc; + + char *comment; + +} pCodeComment; + +/************************************************* + pCodeComment +**************************************************/ + +typedef struct pCodeCSource +{ + + pCode pc; + + int line_number; + char *line; + char *file_name; + +} pCodeCSource; + + +/************************************************* + pCodeFlow + + The Flow object is used as marker to separate + the assembly code into contiguous chunks. In other + words, everytime an instruction cause or potentially + causes a branch, a Flow object will be inserted into + the pCode chain to mark the beginning of the next + contiguous chunk. + +**************************************************/ + +typedef struct pCodeFlow +{ + + pCode pc; + + pCode *end; /* Last pCode in this flow. Note that + the first pCode is pc.next */ + + /* set **uses; * map the pCode instruction inCond and outCond conditions + * in this array of set's. The reason we allocate an + * array of pointers instead of declaring each type of + * usage is because there are port dependent usage definitions */ + //int nuses; /* number of uses sets */ + + set *from; /* flow blocks that can send control to this flow block */ + set *to; /* flow blocks to which this one can send control */ + struct pCodeFlow *ancestor; /* The most immediate "single" pCodeFlow object that + * executes prior to this one. In many cases, this + * will be just the previous */ + + int inCond; /* Input conditions - stuff assumed defined at entry */ + int outCond; /* Output conditions - stuff modified by flow block */ + + int firstBank; /* The first and last bank flags are the first and last */ + int lastBank; /* register banks used within one flow object */ + + int FromConflicts; + int ToConflicts; + + set *registers;/* Registers used in this flow */ + +} pCodeFlow; + +/************************************************* + pCodeFlowLink + + The Flow Link object is used to record information + about how consecutive excutive Flow objects are related. + The pCodeFlow objects demarcate the pCodeInstructions + into contiguous chunks. The FlowLink records conflicts + in the discontinuities. For example, if one Flow object + references a register in bank 0 and the next Flow object + references a register in bank 1, then there is a discontinuity + in the banking registers. + +*/ +typedef struct pCodeFlowLink +{ + pCodeFlow *pcflow; /* pointer to linked pCodeFlow object */ + + int bank_conflict; /* records bank conflicts */ + +} pCodeFlowLink; + +/************************************************* + pCodeInstruction + + Here we describe all the facets of a PIC instruction + (expansion for the 18cxxx is also provided). + +**************************************************/ + +typedef struct pCodeInstruction +{ + + pCode pc; + + PIC_OPCODE op; // The opcode of the instruction. + + char const * const mnemonic; // Pointer to mnemonic string + + pBranch *from; // pCodes that execute before this one + pBranch *to; // pCodes that execute after + pBranch *label; // pCode instructions that have labels + + pCodeOp *pcop; /* Operand, if this instruction has one */ + pCodeFlow *pcflow; /* flow block to which this instruction belongs */ + pCodeCSource *cline; /* C Source from which this instruction was derived */ + + unsigned int num_ops; /* Number of operands (0,1,2 for mid range pics) */ + unsigned int isModReg: 1; /* If destination is W or F, then 1==F */ + unsigned int isBitInst: 1; /* e.g. BCF */ + unsigned int isBranch: 1; /* True if this is a branching instruction */ + unsigned int isSkip: 1; /* True if this is a skip instruction */ + unsigned int isLit: 1; /* True if this instruction has an literal operand */ + unsigned int isAccess: 1; /* True if this instruction has an access RAM operand */ + unsigned int isFastCall: 1; /* True if this instruction has a fast call/return mode select operand */ + + PIC_OPCODE inverted_op; /* Opcode of instruction that's the opposite of this one */ + unsigned int inCond; // Input conditions for this instruction + unsigned int outCond; // Output conditions for this instruction + +} pCodeInstruction; + + +/************************************************* + pCodeLabel +**************************************************/ + +typedef struct pCodeLabel +{ + + pCode pc; + + char *label; + int key; + +} pCodeLabel; + +/************************************************* + pCodeFunction +**************************************************/ + +typedef struct pCodeFunction +{ + + pCode pc; + + char *modname; + char *fname; /* If NULL, then this is the end of + a function. Otherwise, it's the + start and the name is contained + here */ + + pBranch *from; // pCodes that execute before this one + pBranch *to; // pCodes that execute after + pBranch *label; // pCode instructions that have labels + + int ncalled; /* Number of times function is called */ + +} pCodeFunction; + + +/************************************************* + pCodeWild +**************************************************/ + +typedef struct pCodeWild +{ + + pCodeInstruction pci; + + int id; /* Index into the wild card array of a peepBlock + * - this wild card will get expanded into that pCode + * that is stored at this index */ + + /* Conditions on wild pcode instruction */ + int mustBeBitSkipInst:1; + int mustNotBeBitSkipInst:1; + int invertBitSkipInst:1; + + pCodeOp *operand; // Optional operand + pCodeOp *label; // Optional label + +} pCodeWild; + +/************************************************* + pBlock + + Here are PIC program snippets. There's a strong + correlation between the eBBlocks and pBlocks. + SDCC subdivides a C program into managable chunks. + Each chunk becomes a eBBlock and ultimately in the + PIC port a pBlock. + +**************************************************/ + +typedef struct pBlock +{ + memmap *cmemmap; /* The snippet is from this memmap */ + char dbName; /* if cmemmap is NULL, then dbName will identify the block */ + pCode *pcHead; /* A pointer to the first pCode in a link list of pCodes */ + pCode *pcTail; /* A pointer to the last pCode in a link list of pCodes */ + + struct pBlock *next; /* The pBlocks will form a doubly linked list */ + struct pBlock *prev; + + set *function_entries; /* dll of functions in this pblock */ + set *function_exits; + set *function_calls; + set *tregisters; + + set *FlowTree; + unsigned visited:1; /* set true if traversed in call tree */ + + unsigned seq; /* sequence number of this pBlock */ + +} pBlock; + +/************************************************* + pFile + + The collection of pBlock program snippets are + placed into a linked list that is implemented + in the pFile structure. + + The pcode optimizer will parse the pFile. + +**************************************************/ + +typedef struct pFile +{ + pBlock *pbHead; /* A pointer to the first pBlock */ + pBlock *pbTail; /* A pointer to the last pBlock */ + + pBranch *functions; /* A SLL of functions in this pFile */ + +} pFile; + + + +/************************************************* + pCodeWildBlock + + The pCodeWildBlock object keeps track of the wild + variables, operands, and opcodes that exist in + a pBlock. +**************************************************/ +typedef struct pCodeWildBlock { + pBlock *pb; + struct pCodePeep *pcp; // pointer back to ... I don't like this... + + int nvars; // Number of wildcard registers in target. + char **vars; // array of pointers to them + + int nops; // Number of wildcard operands in target. + pCodeOp **wildpCodeOps; // array of pointers to the pCodeOp's. + + int nwildpCodes; // Number of wildcard pCodes in target/replace + pCode **wildpCodes; // array of pointers to the pCode's. + +} pCodeWildBlock; + +/************************************************* + pCodePeep + + The pCodePeep object mimics the peep hole optimizer + in the main SDCC src (e.g. SDCCpeeph.c). Essentially + there is a target pCode chain and a replacement + pCode chain. The target chain is compared to the + pCode that is generated by gen.c. If a match is + found then the pCode is replaced by the replacement + pCode chain. +**************************************************/ +typedef struct pCodePeep { + pCodeWildBlock target; // code we'd like to optimize + pCodeWildBlock replace; // and this is what we'll optimize it with. + + //pBlock *target; + //pBlock replace; // and this is what we'll optimize it with. + + + + /* (Note: a wildcard register is a place holder. Any register + * can be replaced by the wildcard when the pcode is being + * compared to the target. */ + + /* Post Conditions. A post condition is a condition that + * must be either true or false before the peep rule is + * accepted. For example, a certain rule may be accepted + * if and only if the Z-bit is not used as an input to + * the subsequent instructions in a pCode chain. + */ + unsigned int postFalseCond; + unsigned int postTrueCond; + +} pCodePeep; + +/************************************************* + + pCode peep command definitions + + Here are some special commands that control the +way the peep hole optimizer behaves + +**************************************************/ + +enum peepCommandTypes{ + NOTBITSKIP = 0, + BITSKIP, + INVERTBITSKIP, + _LAST_PEEP_COMMAND_ +}; + +/************************************************* + peepCommand structure stores the peep commands. + +**************************************************/ + +typedef struct peepCommand { + int id; + char *cmd; +} peepCommand; + +/************************************************* + pCode Macros + +**************************************************/ +#define PCODE(x) ((pCode *)(x)) +#define PCI(x) ((pCodeInstruction *)(x)) +#define PCL(x) ((pCodeLabel *)(x)) +#define PCF(x) ((pCodeFunction *)(x)) +#define PCFL(x) ((pCodeFlow *)(x)) +#define PCFLINK(x)((pCodeFlowLink *)(x)) +#define PCW(x) ((pCodeWild *)(x)) +#define PCCS(x) ((pCodeCSource *)(x)) + +#define PCOP(x) ((pCodeOp *)(x)) +//#define PCOB(x) ((pCodeOpBit *)(x)) +#define PCOL(x) ((pCodeOpLit *)(x)) +#define PCOI(x) ((pCodeOpImmd *)(x)) +#define PCOLAB(x) ((pCodeOpLabel *)(x)) +#define PCOR(x) ((pCodeOpReg *)(x)) +#define PCORB(x) ((pCodeOpRegBit *)(x)) +#define PCOW(x) ((pCodeOpWild *)(x)) + +#define PBR(x) ((pBranch *)(x)) + +#define PCWB(x) ((pCodeWildBlock *)(x)) + + +/* + macros for checking pCode types +*/ +#define isPCI(x) ((PCODE(x)->type == PC_OPCODE)) +#define isPCI_BRANCH(x) ((PCODE(x)->type == PC_OPCODE) && PCI(x)->isBranch) +#define isPCI_SKIP(x) ((PCODE(x)->type == PC_OPCODE) && PCI(x)->isSkip) +#define isPCI_LIT(x) ((PCODE(x)->type == PC_OPCODE) && PCI(x)->isLit) +#define isPCI_BITSKIP(x)((PCODE(x)->type == PC_OPCODE) && PCI(x)->isSkip && PCI(x)->isBitInst) +#define isPCFL(x) ((PCODE(x)->type == PC_FLOW)) +#define isPCF(x) ((PCODE(x)->type == PC_FUNCTION)) +#define isPCL(x) ((PCODE(x)->type == PC_LABEL)) +#define isPCW(x) ((PCODE(x)->type == PC_WILD)) +#define isPCCS(x) ((PCODE(x)->type == PC_CSOURCE)) + +#define isCALL(x) ((isPCI(x)) && (PCI(x)->op == POC_CALL)) +#define isSTATUS_REG(r) ((r)->pc_type == PO_STATUS) +#define isBSR_REG(r) ((r)->pc_type == PO_BSR) + +#define isACCESS_LOW(r) ((pic16_finalMapping[REG_ADDR(r)].bank == \ + PIC_BANK_FIRST) && (REG_ADDR(r) < 0x80)) +#define isACCESS_HI(r) (pic16_finalMapping[REG_ADDR(r)].bank == PIC_BANK_LAST) +#define isACCESS_BANK(r)(isACCESS_LOW(r) || isACCESS_HI(r)) + +#define isPCOLAB(x) ((PCOP(x)->type) == PO_LABEL) + +/*-----------------------------------------------------------------* + * pCode functions. + *-----------------------------------------------------------------*/ + +pCode *pic16_newpCode (PIC_OPCODE op, pCodeOp *pcop); // Create a new pCode given an operand +pCode *pic16_newpCodeCharP(char *cP); // Create a new pCode given a char * +pCode *pic16_newpCodeInlineP(char *cP); // Create a new pCode given a char * +pCode *pic16_newpCodeFunction(char *g, char *f); // Create a new function +pCode *pic16_newpCodeLabel(char *name,int key); // Create a new label given a key +pCode *pic16_newpCodeCSource(int ln, char *f, char *l); // Create a new symbol line +pBlock *pic16_newpCodeChain(memmap *cm,char c, pCode *pc); // Create a new pBlock +void pic16_printpBlock(FILE *of, pBlock *pb); // Write a pBlock to a file +void pic16_addpCode2pBlock(pBlock *pb, pCode *pc); // Add a pCode to a pBlock +void pic16_addpBlock(pBlock *pb); // Add a pBlock to a pFile +void pic16_copypCode(FILE *of, char dbName); // Write all pBlocks with dbName to *of +void pic16_movepBlock2Head(char dbName); // move pBlocks around +void pic16_AnalyzepCode(char dbName); +void pic16_printCallTree(FILE *of); +void pCodePeepInit(void); +void pic16_pBlockConvert2ISR(pBlock *pb); + +pCodeOp *pic16_newpCodeOpLabel(char *name, int key); +pCodeOp *pic16_newpCodeOpImmd(char *name, int offset, int index, int code_space); +pCodeOp *pic16_newpCodeOpLit(int lit); +pCodeOp *pic16_newpCodeOpBit(char *name, int bit,int inBitSpace); +pCodeOp *pic16_newpCodeOpRegFromStr(char *name); +pCodeOp *pic16_newpCodeOp(char *name, PIC_OPTYPE p); +pCodeOp *pic16_pCodeOpCopy(pCodeOp *pcop); + +pCode * pic16_findNextInstruction(pCode *pci); +pCode * pic16_findNextpCode(pCode *pc, PC_TYPE pct); +int pic16_isPCinFlow(pCode *pc, pCode *pcflow); +struct regs * pic16_getRegFromInstruction(pCode *pc); + +extern void pic16_pcode_test(void); + +/*-----------------------------------------------------------------* + * pCode objects. + *-----------------------------------------------------------------*/ + +extern pCodeOpReg pic16_pc_status; +extern pCodeOpReg pic16_pc_intcon; +extern pCodeOpReg pic16_pc_indf0; +extern pCodeOpReg pic16_pc_fsr0; +extern pCodeOpReg pic16_pc_pcl; +extern pCodeOpReg pic16_pc_pclath; +extern pCodeOpReg pic16_pc_wreg; +extern pCodeOpReg pic16_pc_kzero; +extern pCodeOpReg pic16_pc_wsave; /* wsave and ssave are used to save W and the Status */ +extern pCodeOpReg pic16_pc_ssave; /* registers during an interrupt */ + + +#endif // __PCODE_H__ diff --git a/src/pic16/pcodeflow.c b/src/pic16/pcodeflow.c new file mode 100644 index 00000000..8beaac4c --- /dev/null +++ b/src/pic16/pcodeflow.c @@ -0,0 +1,350 @@ +/*------------------------------------------------------------------------- + + pcodeflow.c - post code generation flow analysis + + Written By - Scott Dattalo scott@dattalo.com + Ported to PIC16 By - 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. + +-------------------------------------------------------------------------*/ +/* + pcodeflow.c + + The purpose of the code in this file is to analyze the flow of the + pCode. + +*/ + +#include + +#include "common.h" // Include everything in the SDCC src directory +#include "newalloc.h" +#include "ralloc.h" +#include "device.h" +#include "pcode.h" +#include "pcoderegs.h" +#include "pcodeflow.h" + +#if 0 + +/* + In the section that follows, an exhaustive flow "tree" is built. + It's not a tree that's really built, but instead every possible + flow path is constructed. + + This is really overkill... +*/ + +static set *FlowTree=NULL; + +void dbg_dumpFlowTree(set *FlowTree) +{ + set *segment; + pCodeFlow *pcflow; + + fprintf(stderr,"Flow Tree: \n"); + + for(segment = setFirstItem(FlowTree); segment; segment=setNextItem(FlowTree)) { + + fprintf(stderr,"Segment:\n"); + + for(pcflow=PCFL(setFirstItem(segment)); pcflow; pcflow=PCFL(setNextItem(segment))) { + fprintf(stderr, " 0x%03x",pcflow->pc.seq); + } + fprintf(stderr,"\n"); + } + +} + + + + +/*-----------------------------------------------------------------* + * void BuildFlowSegment(set *segment, pCodeFlow *pcflow) + *-----------------------------------------------------------------*/ +static void BuildFlowSegment(set *segment, pCodeFlow *pcflow) +{ + + int nNextFlow=0; + pCodeFlowLink *pcflowLink=NULL; + + /* Add this flow to the set if it's not in there already */ + if(isinSet(segment, pcflow)) { + addSetHead(&FlowTree, segment); + return; + } + + addSetHead(&segment, pcflow); + + /* Continue to add contiguous flows */ + + while( pcflow->to && ((nNextFlow = elementsInSet(pcflow->to)) == 1)) { + pcflowLink = (pCodeFlowLink *)(setFirstItem(pcflow->to)); + pcflow = pcflowLink->pcflow; + + if(isinSet(segment, pcflow)) { + addSetIfnotP(&FlowTree, segment); + return; + } + + addSetIfnotP(&segment, pcflow); + + } + + /* Branch: for each branch, duplicate the set and recursively call */ + if(pcflow->to && nNextFlow>=2) { + pCodeFlow *pcflow_to; + + set *branch_segment=NULL; + + pcflowLink = (pCodeFlowLink *)(setFirstItem(pcflow->to)); + pcflow_to = pcflowLink->pcflow; + + addSetIfnotP(&segment, pcflow); + + pcflowLink = (pCodeFlowLink *)(setNextItem(pcflow->to)); + + while(pcflowLink) { + + branch_segment = setFromSet(segment); + BuildFlowSegment(setFromSet(segment),pcflowLink->pcflow); + pcflowLink = (pCodeFlowLink *)(setNextItem(pcflow->to)); + } + + /* add the first branch to this segment */ + BuildFlowSegment(segment,pcflow_to); + + } + + addSetIfnotP(&FlowTree, segment); + + /* done */ +} + +/*-----------------------------------------------------------------* + * void pic16_BuildFlowTree(pBlock *pb) + *-----------------------------------------------------------------*/ +void pic16_BuildFlowTree(pBlock *pb) +{ + pCodeFlow *pcflow; + set *segment; + + FlowTree = newSet(); + + /* Start with the first flow object of this pBlock */ + + pcflow = PCFL(pic16_findNextpCode(pb->pcHead, PC_FLOW)); + + segment = newSet(); + BuildFlowSegment(segment, pcflow); + + pb->FlowTree = FlowTree; + + dbg_dumpFlowTree(FlowTree); +} +#endif + +static void dbg_dumpFlow(pBlock *pb) +{ + pCode *pcflow; + + for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); + pcflow != NULL; + pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) { + + if(!isPCFL(pcflow)) + fprintf(stderr, "LinkFlow - pcflow is not a flow object "); + + fprintf(stderr, "Flow: 0x%x",pcflow->seq); + if(PCFL(pcflow) && PCFL(pcflow)->ancestor) + fprintf(stderr,", ancestor 0x%x\n", + PCFL(pcflow)->ancestor->pc.seq); + else { + pCodeFlowLink *from = (PCFL(pcflow)->from) ? (PCFLINK(setFirstItem(PCFL(pcflow)->from))) : NULL; + fprintf(stderr," no ancestor"); + while(from) { + fprintf(stderr," (0x%x)",from->pcflow->pc.seq); + from = setNextItem(PCFL(pcflow)->from); + } + fprintf(stderr,"\n"); + } + } + +} +/*-----------------------------------------------------------------* + * void BuildFlowSegment(set *segment, pCodeFlow *pcflow) + *-----------------------------------------------------------------*/ + +static void BuildFlowSegment(pCodeFlow *pcflow) +{ + static int recursion=0; + pCodeFlow *pcflow_other; + set *flowset; + + if(!pcflow) + return; + + if(recursion++ > 200) { + fprintf(stderr, " exceeded recursion\n"); + return; + } + + fprintf(stderr,"examining 0x%x\n",pcflow->pc.seq); + + if(pcflow->from) { + + + flowset = pcflow->from; + + if(flowset && flowset->next == NULL) { + + /* + There is a flow before this one. In fact, there's + exactly one flow before this one (because ->next is + NULL). That means all children of this node pass + through both this node and the node immediately + before this one; i.e. they have the same ancestor. + */ + + if( (NULL == (pcflow_other = PCFLINK(flowset->item)->pcflow)) || + (NULL == pcflow_other)) { + fprintf(stderr,"2 error in flow link\n"); + exit(1); + } + pcflow->ancestor = pcflow_other->ancestor ; + + fprintf(stderr,"Assigning ancestor 0x%x from flow 0x%x\n", + pcflow->ancestor->pc.seq, pcflow_other->pc.seq); + + } else { + + if(flowset == NULL) { + + /* There are no flows before this one. + * If this is not the first flow object in the pBlock then + * there's an error */ + + if(!pcflow->ancestor) { + fprintf(stderr,"error in flow link\n"); + exit(1); + + } + + } else { + + /* Flow passes to this flow from multiple flows. Let's + look at just one of these. If the one we look at has + an ancestor, then that's our ancestor too. If the one + we look at doesn't have an ancestor, then that means + we haven't traversed that branch of the call tree + yet - but we will */ + + pcflow_other = PCFLINK(flowset->item)->pcflow; + if(pcflow_other) { + fprintf(stderr, "coming from 0x%x\n",pcflow_other->pc.seq); + if( pcflow_other->ancestor) + pcflow->ancestor = pcflow_other->ancestor; + } + } + + + } + + } else { + /* there are no nodes before this one */ + if(!pcflow->ancestor) + fprintf(stderr,"3 Error in flow link\n"); + } + + /* Now let's recursively expand the call tree */ + + if(pcflow->ancestor && pcflow->to) { + flowset = pcflow->to; + while(flowset) { + BuildFlowSegment(PCFLINK(flowset->item)->pcflow); + flowset = flowset->next; + } + } + +} + +void pic16_BuildFlowTree(pBlock *pb) +{ + pCodeFlow *first_pcflow, *pcflow; + + + // fprintf(stderr,"pic16_BuildFlowTree \n"); + + first_pcflow = PCFL(pic16_findNextpCode(pb->pcHead, PC_FLOW)); + if(!first_pcflow) + return; + + /* The very first node is like Adam, it's its own ancestor (i.e. + * there are no other flows in this pBlock prior to the first one). + */ + + first_pcflow->ancestor = first_pcflow; + + /* For each flow that has only one predecessor, it's easy to + identify the ancestor */ + pcflow = PCFL(pic16_findNextpCode(first_pcflow->pc.next, PC_FLOW)); + + while(pcflow) { + if(elementsInSet(pcflow->from) == 1) { + pCodeFlowLink *from = PCFLINK(setFirstItem(pcflow->from)); + + pcflow->ancestor = from->pcflow; + /* + fprintf(stderr,"Assigning ancestor 0x%x to flow 0x%x\n", + pcflow->ancestor->pc.seq, pcflow->pc.seq); + */ + } + + pcflow = PCFL(pic16_findNextpCode(pcflow->pc.next, PC_FLOW)); + + } + + pcflow = PCFL(pic16_findNextpCode(first_pcflow->pc.next, PC_FLOW)); + + while(pcflow) { + if(elementsInSet(pcflow->from) > 1) { + pCodeFlow *min_pcflow; + pCodeFlowLink *from = PCFLINK(setFirstItem(pcflow->from)); + + min_pcflow = from->pcflow; + + while( (from = setNextItem(pcflow->from)) != NULL) { + if(from->pcflow->pc.seq < min_pcflow->pc.seq) + min_pcflow = from->pcflow; + } + + pcflow->ancestor = min_pcflow; + /* + fprintf(stderr,"Assigning ancestor 0x%x to flow 0x%x from multiple\n", + pcflow->ancestor->pc.seq, pcflow->pc.seq); + */ + + } + + pcflow = PCFL(pic16_findNextpCode(pcflow->pc.next, PC_FLOW)); + + } + + // BuildFlowSegment(pcflow); + + //dbg_dumpFlow(pb); + +} diff --git a/src/pic16/pcodeflow.h b/src/pic16/pcodeflow.h new file mode 100644 index 00000000..b451dea7 --- /dev/null +++ b/src/pic16/pcodeflow.h @@ -0,0 +1,66 @@ +/*------------------------------------------------------------------------- + + pcode.h - post code generation + Written By - Scott Dattalo scott@dattalo.com + PIC16 port - 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. + +-------------------------------------------------------------------------*/ + +#ifndef __PCODEFLOW_H__ +#define __PCODEFLOW_H__ + +/************************************************* + * pCode conditions: + * + * The "conditions" are bit-mapped flags that describe + * input and/or output conditions that are affected by + * the instructions. For example: + * + * MOVF SOME_REG,W + * + * This instruction depends upon 'SOME_REG'. Consequently + * it has the input condition PCC_REGISTER set to true. + * + * In addition, this instruction affects the Z bit in the + * status register and affects W. Thus the output conditions + * are the logical or: + * PCC_ZERO_BIT | PCC_W + * + * The conditions are intialized when the pCode for an + * instruction is created. They're subsequently used + * by the pCode optimizer determine state information + * in the program flow. + *************************************************/ + +#define PCC_NONE 0 +#define PCC_REGISTER (1<<0) +#define PCC_REGISTER2 (1<<1) +#define PCC_C (1<<2) +#define PCC_Z (1<<3) +#define PCC_DC (1<<4) +#define PCC_OV (1<<5) +#define PCC_N (1<<6) +#define PCC_W (1<<7) +#define PCC_EXAMINE_PCOP (1<<8) +#define PCC_LITERAL (1<<9) +#define PCC_REL_ADDR (1<<10) + +/*------------------------------------------------------------*/ + +void BuildFlowAncestry(pBlock *pb); + +#endif // __PCODEFLOW_H__ diff --git a/src/pic16/pcodepeep.c b/src/pic16/pcodepeep.c new file mode 100644 index 00000000..df81ff9e --- /dev/null +++ b/src/pic16/pcodepeep.c @@ -0,0 +1,2226 @@ +/*------------------------------------------------------------------------- + + pcodepeep.c - post code generation + Written By - Scott Dattalo scott@dattalo.com + Ported to PIC16 By - 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. +-------------------------------------------------------------------------*/ + +#include +#include + +#include "common.h" // Include everything in the SDCC src directory +#include "newalloc.h" +//#define PCODE_DEBUG +#include "pcode.h" +#include "pcodeflow.h" +#include "ralloc.h" + +#if defined(__BORLANDC__) || defined(_MSC_VER) +#define STRCASECMP stricmp +#else +#define STRCASECMP strcasecmp +#endif + +pCodeOp *pic16_popCopyGPR2Bit(pCodeOpReg *pc, int bitval); + +pCodeOp *pic16_newpCodeOpWild(int id, pCodeWildBlock *pcwb, pCodeOp *subtype); +pCode *pic16_newpCodeWild(int pCodeID, pCodeOp *optional_operand, pCodeOp *optional_label); +pCode * pic16_findNextInstruction(pCode *pc); +int pic16_getpCode(char *mnem,int dest); +int pic16_getpCodePeepCommand(char *cmd); +void pic16_pBlockMergeLabels(pBlock *pb); +char *pCode2str(char *str, int size, pCode *pc); +char *pic16_get_op( pCodeOp *pcop,char *buf,int buf_size); + +extern pCodeInstruction *pic16Mnemonics[]; + + +#define IS_PCCOMMENT(x) ( x && (x->type==PC_COMMENT)) + +/****************************************************************/ +/* + * rootRules - defined in SDCCpeep.c + * This is a pointer to the (parsed) peephole rules that are + * defined in peep.def. + */ + +//extern peepRule *rootRules; + + + + +/****************************************************************/ +/****************************************************************/ +typedef struct _DLL { + struct _DLL *prev; + struct _DLL *next; + // void *data; +} _DLL; + + +typedef struct pCodePeepSnippets +{ + _DLL dll; + pCodePeep *peep; +} pCodePeepSnippets; + + +/****************************************************************/ +/* */ +/* peepSnippets - */ +/* */ +/****************************************************************/ + +static pCodePeepSnippets *peepSnippets=NULL; + +/****************************************************************/ +/* */ +/* curPeep */ +/* */ +/****************************************************************/ + +//static pCodePeep *curPeep=NULL; + +/****************************************************************/ +/* */ +/* curBlock */ +/* */ +/****************************************************************/ + +//static pBlock *curBlock=NULL; + + +/****************************************************************/ +/* */ +/* max wild cards in a peep rule */ +/* */ +/****************************************************************/ + +//static int sMaxWildVar = 0; +//static int sMaxWildMnem = 0; + + +typedef struct pCodeToken +{ + int tt; // token type; + union { + char c; // character + int n; // number + char *s; // string + } tok; + +} pCodeToken; + +pCodeToken tokArr[50]; +static unsigned tokIdx=0; + + +typedef enum { + PCT_NULL=0, + PCT_SPACE=1, + PCT_PERCENT, + PCT_LESSTHAN, + PCT_GREATERTHAN, + PCT_COLON, + PCT_COMMA, + PCT_COMMENT, + PCT_STRING, + PCT_NUMBER + +} pCodeTokens; + + +typedef struct parsedPattern { + struct pcPattern *pcp; + pCodeToken *pct; +} parsedPattern; + +#define MAX_PARSEDPATARR 50 +parsedPattern parsedPatArr[MAX_PARSEDPATARR]; +static unsigned int parsedPatIdx=0; + + +typedef enum { + PCP_LABEL=1, + PCP_NUMBER, + PCP_STR, + PCP_WILDVAR, + PCP_WILDSTR, + PCP_COMMA, + PCP_COMMENT +} pCodePatterns; + +static char pcpat_label[] = {PCT_PERCENT, PCT_NUMBER, PCT_COLON, 0}; +static char pcpat_number[] = {PCT_NUMBER, 0}; +static char pcpat_string[] = {PCT_STRING, 0}; +static char pcpat_wildString[] = {PCT_PERCENT, PCT_STRING, 0}; +static char pcpat_wildVar[] = {PCT_PERCENT, PCT_NUMBER, 0}; +static char pcpat_comma[] = {PCT_COMMA, 0}; +static char pcpat_comment[] = {PCT_COMMENT, 0}; + + +typedef struct pcPattern { + char pt; // Pattern type + char *tokens; // list of tokens that describe the pattern + void * (*f) (void *,pCodeWildBlock *); +} pcPattern; + +static pcPattern pcpArr[] = { + {PCP_LABEL, pcpat_label, NULL}, + {PCP_WILDSTR, pcpat_wildString, NULL}, + {PCP_STR, pcpat_string, NULL}, + {PCP_WILDVAR, pcpat_wildVar, NULL}, + {PCP_COMMA, pcpat_comma, NULL}, + {PCP_COMMENT, pcpat_comment, NULL}, + {PCP_NUMBER, pcpat_number, NULL} +}; + +#define PCPATTERNS (sizeof(pcpArr)/sizeof(pcPattern)) + +// Assembly Line Token +typedef enum { + ALT_LABEL=1, + ALT_COMMENT, + ALT_MNEM0, + ALT_MNEM0A, + ALT_MNEM1, + ALT_MNEM1A, + ALT_MNEM1B, + ALT_MNEM2, + ALT_MNEM2A, + ALT_MNEM3 +} altPatterns; + +static char alt_comment[] = { PCP_COMMENT, 0}; +static char alt_label[] = { PCP_LABEL, 0}; +static char alt_mnem0[] = { PCP_STR, 0}; +static char alt_mnem0a[] = { PCP_WILDVAR, 0}; +static char alt_mnem1[] = { PCP_STR, PCP_STR, 0}; +static char alt_mnem1a[] = { PCP_STR, PCP_WILDVAR, 0}; +static char alt_mnem1b[] = { PCP_STR, PCP_NUMBER, 0}; +static char alt_mnem2[] = { PCP_STR, PCP_STR, PCP_COMMA, PCP_STR, 0}; +static char alt_mnem2a[] = { PCP_STR, PCP_WILDVAR, PCP_COMMA, PCP_STR, 0}; +static char alt_mnem3[] = { PCP_STR, PCP_STR, PCP_COMMA, PCP_NUMBER, 0}; + +static void * cvt_altpat_label(void *pp,pCodeWildBlock *pcwb); +static void * cvt_altpat_comment(void *pp,pCodeWildBlock *pcwb); +static void * cvt_altpat_mnem0(void *pp,pCodeWildBlock *pcwb); +static void * cvt_altpat_mnem0a(void *pp,pCodeWildBlock *pcwb); +static void * cvt_altpat_mnem1(void *pp,pCodeWildBlock *pcwb); +static void * cvt_altpat_mnem1a(void *pp,pCodeWildBlock *pcwb); +static void * cvt_altpat_mnem1b(void *pp,pCodeWildBlock *pcwb); +static void * cvt_altpat_mnem2(void *pp,pCodeWildBlock *pcwb); +static void * cvt_altpat_mnem2a(void *pp,pCodeWildBlock *pcwb); +static void * cvt_altpat_mnem3(void *pp,pCodeWildBlock *pcwb); + +static pcPattern altArr[] = { + {ALT_LABEL, alt_label, cvt_altpat_label}, + {ALT_COMMENT, alt_comment,cvt_altpat_comment}, + {ALT_MNEM3, alt_mnem3, cvt_altpat_mnem3}, + {ALT_MNEM2A, alt_mnem2a, cvt_altpat_mnem2a}, + {ALT_MNEM2, alt_mnem2, cvt_altpat_mnem2}, + {ALT_MNEM1B, alt_mnem1b, cvt_altpat_mnem1b}, + {ALT_MNEM1A, alt_mnem1a, cvt_altpat_mnem1a}, + {ALT_MNEM1, alt_mnem1, cvt_altpat_mnem1}, + {ALT_MNEM0A, alt_mnem0a, cvt_altpat_mnem0a}, + {ALT_MNEM0, alt_mnem0, cvt_altpat_mnem0}, + +}; + +#define ALTPATTERNS (sizeof(altArr)/sizeof(pcPattern)) + +// forward declarations +static void * DLL_append(_DLL *list, _DLL *next); + +/*-----------------------------------------------------------------*/ +/* cvt_extract_destination - helper function extracts the register */ +/* destination from a parsedPattern. */ +/* */ +/*-----------------------------------------------------------------*/ +static int cvt_extract_destination(parsedPattern *pp) +{ + + if(pp->pct[0].tt == PCT_STRING) { + + // just check first letter for now + + if(toupper(*pp->pct[0].tok.s) == 'F') + return 1; + + } else if (pp->pct[0].tt == PCT_NUMBER) { + + if(pp->pct[0].tok.n) + return 1; + } + + return 0; + +} + +/*-----------------------------------------------------------------*/ +/* pCodeOp *cvt_extract_status(char *reg, char *bit) */ +/* if *reg is the "status" register and *bit is one of the */ +/* status bits, then this function will create a new pCode op */ +/* containing the status register. */ +/*-----------------------------------------------------------------*/ + +static pCodeOp *cvt_extract_status(char *reg, char *bit) +{ + int len; + + if(STRCASECMP(reg, pic16_pc_status.pcop.name)) + return NULL; + + len = strlen(bit); + + if(len == 1) { + // check C,Z + if(toupper(*bit) == 'C') + return PCOP(pic16_popCopyGPR2Bit(&pic16_pc_status,PIC_C_BIT)); + if(toupper(*bit) == 'Z') + return PCOP(pic16_popCopyGPR2Bit(&pic16_pc_status,PIC_Z_BIT)); + } + + // Check DC + if(len ==2 && toupper(bit[0]) == 'D' && toupper(bit[1]) == 'C') + return PCOP(pic16_popCopyGPR2Bit(&pic16_pc_status,PIC_DC_BIT)); + + return NULL; + +} + +/*-----------------------------------------------------------------*/ +/* cvt_altpat_label - convert assembly line type to a pCode label */ +/* INPUT: pointer to the parsedPattern */ +/* */ +/* pp[0] - label */ +/* */ +/* label pattern => '%' number ':' */ +/* at this point, we wish to extract only the 'number' */ +/* */ +/*-----------------------------------------------------------------*/ +static void * cvt_altpat_label(void *pp,pCodeWildBlock *pcwb) +{ + parsedPattern *p = pp; + + DFPRINTF((stderr,"altpat_label with ID = %d\n",p->pct[1].tok.n)); + return pic16_newpCodeLabel(NULL,-p->pct[1].tok.n); + +} + +/*-----------------------------------------------------------------*/ +/* cvt_altpat_comment - convert assembly line type to a comment */ +/* INPUT: pointer to the parsedPattern */ +/* */ +/* pp[0] - comment */ +/* */ +/* */ +/*-----------------------------------------------------------------*/ +static void * cvt_altpat_comment(void *pp,pCodeWildBlock *pcwb) +{ + parsedPattern *p = pp; + + DFPRINTF((stderr,"altpat_comment = %s\n",p->pct[0].tok.s)); + return pic16_newpCodeCharP(p->pct[0].tok.s); + +} + +/*-----------------------------------------------------------------*/ +/* cvt_altpat_mem0 - convert assembly line type to a wild pCode */ +/* instruction */ +/* */ +/* pp[0] - str */ +/* */ +/*-----------------------------------------------------------------*/ +static void * cvt_altpat_mnem0(void *pp,pCodeWildBlock *pcwb) +{ + parsedPattern *p = pp; + int opcode; + + pCodeInstruction *pci=NULL; + + DFPRINTF((stderr,"altpat_mnem0 %s\n", p->pct[0].tok.s)); + + opcode = pic16_getpCode(p->pct[0].tok.s,0); + + if(opcode < 0) { + /* look for special command strings like _NOTBITSKIP_ */ + + //fprintf(stderr, "Bad mnemonic\n"); + + opcode = pic16_getpCodePeepCommand(p->pct[0].tok.s); + //if(opcode > 0) + // fprintf(stderr," but valid peep command: %s, key = %d\n",p->pct[0].tok.s,opcode); + return NULL; + } + + pci = PCI(pic16_newpCode(opcode, NULL)); + + if(!pci) + fprintf(stderr,"couldn't find mnemonic\n"); + + + return pci; +} + +/*-----------------------------------------------------------------*/ +/* cvt_altpat_mem0a - convert assembly line type to a wild pCode */ +/* instruction */ +/* */ +/* pp[0] - wild var */ +/* */ +/*-----------------------------------------------------------------*/ +static void * cvt_altpat_mnem0a(void *pp, pCodeWildBlock *pcwb) +{ + parsedPattern *p = pp; + + DFPRINTF((stderr,"altpat_mnem0a wild mnem # %d\n", p[0].pct[1].tok.n)); + + /* Save the index of the maximum wildcard mnemonic */ + + //if(p[0].pct[1].tok.n > sMaxWildVar) + // sMaxWildMnem = p[0].pct[1].tok.n; + + if(p[0].pct[1].tok.n > pcwb->nwildpCodes) + pcwb->nwildpCodes = p[0].pct[1].tok.n; + + return pic16_newpCodeWild(p[0].pct[1].tok.n,NULL,NULL); + +} + +/*-----------------------------------------------------------------*/ +/* cvt_altpat_mem1 - convert assembly line type to a pCode */ +/* instruction with 1 operand. */ +/* */ +/* pp[0] - mnem */ +/* pp[1] - Operand */ +/* */ +/*-----------------------------------------------------------------*/ +static void * cvt_altpat_mnem1(void *pp,pCodeWildBlock *pcwb) +{ + + parsedPattern *p = pp; + int opcode; + + pCodeInstruction *pci=NULL; + pCodeOp *pcosubtype; + + DFPRINTF((stderr,"altpat_mnem1 %s var %s\n", p->pct[0].tok.s,p[1].pct[0].tok.s)); + + opcode = pic16_getpCode(p->pct[0].tok.s,0); + if(opcode < 0) { + //fprintf(stderr, "Bad mnemonic\n"); + opcode = pic16_getpCodePeepCommand(p->pct[0].tok.s); + //if(opcode > 0) + //fprintf(stderr," but valid peep command: %s, key = %d\n",p->pct[0].tok.s,opcode); + + return NULL; + } + + if(pic16Mnemonics[opcode]->isBitInst) + pcosubtype = pic16_newpCodeOp(p[1].pct[0].tok.s,PO_BIT); + else + pcosubtype = pic16_newpCodeOp(p[1].pct[0].tok.s,PO_GPR_REGISTER); + + + pci = PCI(pic16_newpCode(opcode, pcosubtype)); + + if(!pci) + fprintf(stderr,"couldn't find mnemonic\n"); + + + return pci; +} + +/*-----------------------------------------------------------------*/ +/* cvt_altpat_mem1a - convert assembly line type to a pCode */ +/* instruction with 1 wild operand. */ +/* */ +/* pp[0] - mnem */ +/* pp[1] - wild var */ +/* */ +/*-----------------------------------------------------------------*/ +static void * cvt_altpat_mnem1a(void *pp,pCodeWildBlock *pcwb) +{ + parsedPattern *p = pp; + int opcode; + + pCodeInstruction *pci=NULL; + pCodeOp *pcosubtype; + + DFPRINTF((stderr,"altpat_mnem1a %s var %d\n", p->pct[0].tok.s,p[1].pct[1].tok.n)); + + opcode = pic16_getpCode(p->pct[0].tok.s,0); + if(opcode < 0) { + int cmd_id = pic16_getpCodePeepCommand(p->pct[0].tok.s); + pCode *pc=NULL; + + if(cmd_id<0) { + fprintf(stderr, "Bad mnemonic\n"); + return NULL; + } + + if(p[0].pct[1].tok.n > pcwb->nwildpCodes) + pcwb->nwildpCodes = p[0].pct[1].tok.n; + + pc = pic16_newpCodeWild(p[1].pct[1].tok.n,NULL,NULL); + + switch(cmd_id) { + case NOTBITSKIP: + PCW(pc)->mustNotBeBitSkipInst = 1; + break; + case BITSKIP: + PCW(pc)->mustBeBitSkipInst = 1; + break; + case INVERTBITSKIP: + PCW(pc)->invertBitSkipInst = 1; + } + return pc; + } + + if(pic16Mnemonics[opcode]->isBitInst) + pcosubtype = pic16_newpCodeOpBit(NULL,-1,0); + else + pcosubtype = pic16_newpCodeOp(NULL,PO_GPR_REGISTER); + + + pci = PCI(pic16_newpCode(opcode, + pic16_newpCodeOpWild(p[1].pct[1].tok.n, pcwb, pcosubtype))); + + /* Save the index of the maximum wildcard variable */ + //if(p[1].pct[1].tok.n > sMaxWildVar) + // sMaxWildVar = p[1].pct[1].tok.n; + + if(p[1].pct[1].tok.n > pcwb->nvars) + pcwb->nvars = p[1].pct[1].tok.n; + + if(!pci) + fprintf(stderr,"couldn't find mnemonic\n"); + + + return pci; +} + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +static void * cvt_altpat_mnem1b(void *pp,pCodeWildBlock *pcwb) +{ + parsedPattern *p = pp; + int opcode; + + pCodeInstruction *pci=NULL; + + DFPRINTF((stderr,"altpat_mnem1b %s var %d\n", p->pct[0].tok.s,p[1].pct[0].tok.n)); + + opcode = pic16_getpCode(p->pct[0].tok.s,0); + if(opcode < 0) { + fprintf(stderr, "Bad mnemonic\n"); + return NULL; + } + + pci = PCI(pic16_newpCode(opcode, pic16_newpCodeOpLit(p[1].pct[0].tok.n) )); + + if(!pci) + fprintf(stderr,"couldn't find mnemonic\n"); + + + return pci; +} + +/*-----------------------------------------------------------------*/ +/* cvt_altpat_mnem2 */ +/* */ +/* pp[0] - mnem */ +/* pp[1] - var */ +/* pp[2] - comma */ +/* pp[3] - destination */ +/*-----------------------------------------------------------------*/ +static void * cvt_altpat_mnem2(void *pp,pCodeWildBlock *pcwb) +{ + parsedPattern *p = pp; + int opcode; + int dest; + + pCodeInstruction *pci=NULL; + pCodeOp *pcosubtype; + + dest = cvt_extract_destination(&p[3]); + + DFPRINTF((stderr,"altpat_mnem2 %s var %s destination %s(%d)\n", + p->pct[0].tok.s, + p[1].pct[0].tok.s, + p[3].pct[0].tok.s, + dest)); + + + opcode = pic16_getpCode(p->pct[0].tok.s,dest); + if(opcode < 0) { + fprintf(stderr, "Bad mnemonic\n"); + return NULL; + } + + if(pic16Mnemonics[opcode]->isBitInst) { + pcosubtype = cvt_extract_status(p[1].pct[0].tok.s, p[3].pct[0].tok.s); + if(pcosubtype == NULL) { + fprintf(stderr, "bad operand?\n"); + return NULL; + } + + } else + pcosubtype = pic16_newpCodeOp(p[1].pct[0].tok.s,PO_GPR_REGISTER); + + + pci = PCI(pic16_newpCode(opcode,pcosubtype)); + + if(!pci) + fprintf(stderr,"couldn't find mnemonic\n"); + + return pci; + +} + +/*-----------------------------------------------------------------*/ +/* cvt_altpat_mem2a - convert assembly line type to a pCode */ +/* instruction with 1 wild operand and a */ +/* destination operand (e.g. w or f) */ +/* */ +/* pp[0] - mnem */ +/* pp[1] - wild var */ +/* pp[2] - comma */ +/* pp[3] - destination */ +/* */ +/*-----------------------------------------------------------------*/ +static void * cvt_altpat_mnem2a(void *pp,pCodeWildBlock *pcwb) +{ + parsedPattern *p = pp; + int opcode; + int dest; + + pCodeInstruction *pci=NULL; + pCodeOp *pcosubtype; + + if(!pcwb) { + fprintf(stderr,"ERROR %s:%d - can't assemble line\n",__FILE__,__LINE__); + return NULL; + } + + dest = cvt_extract_destination(&p[3]); + + DFPRINTF((stderr,"altpat_mnem2a %s var %d destination %s(%d)\n", + p->pct[0].tok.s, + p[1].pct[1].tok.n, + p[3].pct[0].tok.s, + dest)); + + + opcode = pic16_getpCode(p->pct[0].tok.s,dest); + if(opcode < 0) { + fprintf(stderr, "Bad mnemonic\n"); + return NULL; + } + + if(pic16Mnemonics[opcode]->isBitInst) + pcosubtype = pic16_newpCodeOp(NULL,PO_BIT); + else + pcosubtype = pic16_newpCodeOp(NULL,PO_GPR_REGISTER); + + + pci = PCI(pic16_newpCode(opcode, + pic16_newpCodeOpWild(p[1].pct[1].tok.n, pcwb, pcosubtype))); + + /* Save the index of the maximum wildcard variable */ + //if(p[1].pct[1].tok.n > sMaxWildVar) + // sMaxWildVar = p[1].pct[1].tok.n; + + if(p[1].pct[1].tok.n > pcwb->nvars) + pcwb->nvars = p[1].pct[1].tok.n; + + if(!pci) + fprintf(stderr,"couldn't find mnemonic\n"); + + return pci; + +} + + +/*-----------------------------------------------------------------*/ +/* cvt_altpat_mem3 - convert assembly line type to a pCode */ +/* This rule is for bsf/bcf type instructions */ +/* */ +/* */ +/* pp[0] - mnem */ +/* pp[1] - register */ +/* pp[2] - comma */ +/* pp[3] - number */ +/* */ +/*-----------------------------------------------------------------*/ +static void * cvt_altpat_mnem3(void *pp,pCodeWildBlock *pcwb) +{ + parsedPattern *p = pp; + int opcode; + int dest; // or could be bit position in the register + + pCodeInstruction *pci=NULL; + pCodeOp *pcosubtype=NULL; + + dest = cvt_extract_destination(&p[3]); + + DFPRINTF((stderr,"altpat_mnem3 %s var %s bit (%d)\n", + p->pct[0].tok.s, + p[1].pct[0].tok.s, + p[3].pct[0].tok.n)); + + + opcode = pic16_getpCode(p->pct[0].tok.s,0); + if(opcode < 0) { + fprintf(stderr, "Bad mnemonic\n"); + return NULL; + } + + + if(pic16Mnemonics[opcode]->isBitInst) { + //pcosubtype = cvt_extract_status(p[1].pct[0].tok.s, p[3].pct[0].tok.s); + + //if(pcosubtype == NULL) { + pcosubtype = pic16_newpCodeOpBit(p[1].pct[0].tok.s,p[3].pct[0].tok.n,0); + //} + } else + pcosubtype = pic16_newpCodeOp(p[1].pct[0].tok.s,PO_GPR_REGISTER); + + if(pcosubtype == NULL) { + fprintf(stderr, "Bad operand\n"); + return NULL; + } + + pci = PCI(pic16_newpCode(opcode, pcosubtype)); + + if(!pci) + fprintf(stderr,"couldn't find mnemonic\n"); + + return pci; + +} + +/*-----------------------------------------------------------------*/ +/* tokenizeLineNode - Convert a string (of char's) that was parsed */ +/* by SDCCpeeph.c into a string of tokens. */ +/* */ +/* */ +/* The tokenizer is of the classic type. When an item is encounterd*/ +/* it is converted into a token. The token is a structure that */ +/* encodes the item's type and it's value (when appropriate). */ +/* */ +/* Accepted token types: */ +/* SPACE NUMBER STRING % : , ; */ +/* */ +/* */ +/* */ +/*-----------------------------------------------------------------*/ + + +static void tokenizeLineNode(char *ln) +{ + char *lnstart=ln; + tokIdx = 0; // Starting off at the beginning + tokArr[0].tt = PCT_NULL; // and assume invalid character for first token. + + if(!ln || !*ln) + return; + + + while(*ln) { + + if(isspace(*ln)) { + // add a SPACE token and eat the extra spaces. + tokArr[tokIdx++].tt = PCT_SPACE; + while (isspace (*ln)) + ln++; + continue; + } + + if(isdigit(*ln)) { + + tokArr[tokIdx].tt = PCT_NUMBER; + tokArr[tokIdx++].tok.n = strtol(ln, &ln, 0); + + continue; + + } + + switch(*ln) { + case '%': + tokArr[tokIdx++].tt = PCT_PERCENT; + break; + case '<': + tokArr[tokIdx++].tt = PCT_LESSTHAN; + break; + case '>': + tokArr[tokIdx++].tt = PCT_GREATERTHAN; + break; + case ':': + tokArr[tokIdx++].tt = PCT_COLON; + break; + case ';': + tokArr[tokIdx].tok.s = Safe_strdup(ln); + tokArr[tokIdx++].tt = PCT_COMMENT; + tokArr[tokIdx].tt = PCT_NULL; + return; + case ',': + tokArr[tokIdx++].tt = PCT_COMMA; + break; + + + default: + if(isalpha(*ln) || (*ln == '_') ) { + char buffer[50]; + int i=0; + + while( (isalpha(*ln) || isdigit(*ln) || (*ln == '_')) && i<49) + buffer[i++] = *ln++; + + ln--; + buffer[i] = 0; + + tokArr[tokIdx].tok.s = Safe_strdup(buffer); + tokArr[tokIdx++].tt = PCT_STRING; + + } else { + fprintf(stderr, "Error while parsing peep rules (check peeph.def)\n"); + fprintf(stderr, "Line: %s\n",lnstart); + fprintf(stderr, "Token: '%c'\n",*ln); + exit(1); + } + } + + /* Advance to next character in input string . + * Note, if none of the tests passed above, then + * we effectively ignore the `bad' character. + * Since the line has already been parsed by SDCCpeeph, + * chance are that there are no invalid characters... */ + + ln++; + + } + + tokArr[tokIdx].tt = 0; +} + + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ + + + +static void dump1Token(pCodeTokens tt) +{ + + switch(tt) { + case PCT_SPACE: + fprintf(stderr, " space "); + break; + case PCT_PERCENT: + fprintf(stderr, " pct %%"); + break; + case PCT_LESSTHAN: + fprintf(stderr, " pct <"); + break; + case PCT_GREATERTHAN: + fprintf(stderr, " pct >"); + break; + case PCT_COLON: + fprintf(stderr, " col :"); + break; + case PCT_COMMA: + fprintf(stderr, " comma , "); + break; + case PCT_COMMENT: + fprintf(stderr, " comment "); + //fprintf(stderr,"%s",tokArr[i].tok.s); + break; + case PCT_STRING: + fprintf(stderr, " str "); + //fprintf(stderr,"%s",tokArr[i].tok.s); + break; + case PCT_NUMBER: + fprintf(stderr, " num "); + //fprintf(stderr,"%d",tokArr[i].tok.n); + break; + case PCT_NULL: + fprintf(stderr, " null "); + + } + +} + + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ + +static int pcComparePattern(pCodeToken *pct, char *pat, int max_tokens) +{ + int i=0; + + if(!pct || !pat || !*pat) + return 0; + + //DFPRINTF((stderr,"comparing against:\n")); + + while(i < max_tokens) { + + if(*pat == 0){ + //DFPRINTF((stderr,"matched\n")); + return (i+1); + } + + //dump1Token(*pat); DFPRINTF((stderr,"\n")); + + if(pct->tt != *pat) + return 0; + + + pct++; + pat++; + } + + return 0; + +} + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ + +static int altComparePattern( char *pct, parsedPattern *pat, int max_tokens) +{ + int i=0; + + if(!pct || !pat || !*pct) + return 0; + + + while(i < max_tokens) { + + if(*pct == 0) { + //DFPRINTF((stderr,"matched\n")); + return i; + } + + //dump1Token(*pat); DFPRINTF((stderr,"\n")); + + if( !pat || !pat->pcp ) + return 0; + + if (pat->pcp->pt != *pct) + return 0; + + //DFPRINTF((stderr," pct=%d\n",*pct)); + pct++; + pat++; + i++; + } + + return 0; + +} +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ + +static int advTokIdx(int *v, int amt) +{ + + if((unsigned) (*v + amt) > tokIdx) + return 1; + + *v += amt; + return 0; + +} + +/*-----------------------------------------------------------------*/ +/* parseTokens - convert the tokens corresponding to a single line */ +/* of a peep hole assembly into a pCode object. */ +/* */ +/* */ +/* */ +/* */ +/* This is a simple parser that looks for strings of the type */ +/* allowed in the peep hole definition file. Essentially the format*/ +/* is the same as a line of assembly: */ +/* */ +/* label: mnemonic op1, op2, op3 ; comment */ +/* */ +/* Some of these items aren't present. It's the job of the parser */ +/* to determine which are and convert those into the appropriate */ +/* pcode. */ +/*-----------------------------------------------------------------*/ + +static int parseTokens(pCodeWildBlock *pcwb, pCode **pcret) +{ + pCode *pc; + int error = 0; + + if(!tokIdx) + return error; + +#ifdef PCODE_DEBUG + { + unsigned i; + for(i=0; i<=tokIdx; i++) + dump1Token(tokArr[i].tt); + fputc('\n',stderr); + } +#endif + + { + int lparsedPatIdx=0; + int lpcpIdx; + int ltokIdx =0; + int matching = 0; + int j=0; + int k=0; + + char * cPmnem = NULL; // Pointer to non-wild mnemonic (if any) + char * cP1stop = NULL; + char * cP2ndop = NULL; + + //pCodeOp *pcl = NULL; // Storage for a label + //pCodeOp *pco1 = NULL; // 1st operand + //pCodeOp *pco2 = NULL; // 2nd operand + //pCode *pc = NULL; // Mnemonic + + typedef enum { + PS_START, + PS_HAVE_LABEL, + PS_HAVE_MNEM, + PS_HAVE_1OPERAND, + PS_HAVE_COMMA, + PS_HAVE_2OPERANDS + } ParseStates; + + ParseStates state = PS_START; + + do { + + lpcpIdx=0; + matching = 0; + + if( ((tokArr[ltokIdx].tt == PCT_SPACE) ) + && (advTokIdx(<okIdx, 1)) ) // eat space + break; + + do { + j = pcComparePattern(&tokArr[ltokIdx], pcpArr[lpcpIdx].tokens, tokIdx +1); + if( j ) { + + switch(pcpArr[lpcpIdx].pt) { + case PCP_LABEL: + if(state == PS_START){ + DFPRINTF((stderr," label\n")); + state = PS_HAVE_LABEL; + } else + DFPRINTF((stderr," bad state (%d) for label\n",state)); + break; + + case PCP_STR: + DFPRINTF((stderr," %s is",tokArr[ltokIdx].tok.s)); + switch(state) { + case PS_START: + case PS_HAVE_LABEL: + DFPRINTF((stderr," mnem\n")); + cPmnem = tokArr[ltokIdx].tok.s; + state = PS_HAVE_MNEM; + break; + case PS_HAVE_MNEM: + DFPRINTF((stderr," 1st operand\n")); + cP1stop = tokArr[ltokIdx].tok.s; + //pco1 = pic16_newpCodeOp(NULL,PO_GPR_REGISTER); + state = PS_HAVE_1OPERAND; + break; + case PS_HAVE_1OPERAND: + DFPRINTF((stderr," error expecting comma\n")); + break; + case PS_HAVE_COMMA: + DFPRINTF((stderr," 2 operands\n")); + cP2ndop = tokArr[ltokIdx].tok.s; + break; + case PS_HAVE_2OPERANDS: + break; + } + break; + + case PCP_WILDVAR: + switch(state) { + case PS_START: + case PS_HAVE_LABEL: + DFPRINTF((stderr," wild mnem\n")); + state = PS_HAVE_MNEM; + break; + case PS_HAVE_MNEM: + DFPRINTF((stderr," 1st operand is wild\n")); + state = PS_HAVE_1OPERAND; + break; + case PS_HAVE_1OPERAND: + DFPRINTF((stderr," error expecting comma\n")); + break; + case PS_HAVE_COMMA: + DFPRINTF((stderr," 2nd operand is wild\n")); + break; + case PS_HAVE_2OPERANDS: + break; + } + break; + + case PCP_NUMBER: + switch(state) { + case PS_START: + case PS_HAVE_LABEL: + fprintf(stderr," ERROR number\n"); + break; + case PS_HAVE_MNEM: + DFPRINTF((stderr," 1st operand is a number\n")); + state = PS_HAVE_1OPERAND; + break; + case PS_HAVE_1OPERAND: + fprintf(stderr," error expecting comma\n"); + break; + case PS_HAVE_COMMA: + DFPRINTF((stderr," 2nd operand is a number\n")); + break; + case PS_HAVE_2OPERANDS: + break; + } + break; + + case PCP_WILDSTR: + break; + case PCP_COMMA: + if(state == PS_HAVE_1OPERAND){ + DFPRINTF((stderr," got a comma\n")); + state = PS_HAVE_COMMA; + } else + fprintf(stderr," unexpected comma\n"); + break; + + } + + matching = 1; + parsedPatArr[lparsedPatIdx].pcp = &pcpArr[lpcpIdx]; + parsedPatArr[lparsedPatIdx].pct = &tokArr[ltokIdx]; + lparsedPatIdx++; + + //dump1Token(tokArr[ltokIdx].tt); + + if(advTokIdx(<okIdx, strlen(pcpArr[lpcpIdx].tokens) ) ) { + DFPRINTF((stderr," reached end \n")); + matching = 0; + //return; + } + } + + + } while ((++lpcpIdx < PCPATTERNS) && !matching); + + } while (matching); + + parsedPatArr[lparsedPatIdx].pcp = NULL; + parsedPatArr[lparsedPatIdx].pct = NULL; + + j=k=0; + do { + int c; + + if( (c=altComparePattern( altArr[k].tokens, &parsedPatArr[j],10) ) ) { + + if( altArr[k].f) { + pc = altArr[k].f(&parsedPatArr[j],pcwb); + //if(pc && pc->print) + // pc->print(stderr,pc); + //if(pc && pc->destruct) pc->destruct(pc); dumps core? + + //if(curBlock && pc) + //pic16_addpCode2pBlock(curBlock, pc); + if(pc) { + if (pcret) { + *pcret = pc; + return 0; // Only accept one line for now. + } else + pic16_addpCode2pBlock(pcwb->pb, pc); + } else + error++; + } + j += c; + } + k++; + } + while(j<=lparsedPatIdx && kf ) + parsedPatArr[j].pcp->f(&parsedPatArr[j]); + DFPRINTF((stderr," %d",parsedPatArr[j].pcp->pt)); + j++; + } + while(jnext) { + + //DFPRINTF((stderr,"%s\n",ln->line)); + + tokenizeLineNode(ln->line); + + if(parseTokens(pcwb,NULL)) { + int i; + fprintf(stderr,"ERROR assembling line:\n%s\n",ln->line); + fprintf(stderr,"Tokens:\n"); + for(i=0; i<5; i++) + dump1Token(tokArr[i].tt); + fputc('\n',stderr); + exit (1); + } + } +} + +/*-----------------------------------------------------------------*/ +/* */ +/*-----------------------------------------------------------------*/ +pCode *pic16_AssembleLine(char *line) +{ + pCode *pc=NULL; + + if(!line || !*line) { + fprintf(stderr,"WARNING returning NULL in AssembleLine\n"); + return NULL; + } + + tokenizeLineNode(line); + + if(parseTokens(NULL,&pc)) + fprintf(stderr, "WARNING: unable to assemble line:\n%s\n",line); + + return pc; + +} + +/*-----------------------------------------------------------------*/ +/* peepRuleCondition */ +/*-----------------------------------------------------------------*/ +static void peepRuleCondition(char *cond, pCodePeep *pcp) +{ + if(!cond || !pcp) + return; + + //DFPRINTF((stderr,"\nCondition: %s\n",cond)); + /* brute force compares for now */ + + if(STRCASECMP(cond, "NZ") == 0) { + //DFPRINTF((stderr,"found NZ\n")); + pcp->postFalseCond = PCC_Z; + + } + +} + + +static void initpCodeWildBlock(pCodeWildBlock *pcwb) +{ + + // pcwb = Safe_calloc(1,sizeof(pCodeWildBlock)); + + if(!pcwb) + return; + + pcwb->vars = NULL; + pcwb->wildpCodes = NULL; + pcwb->wildpCodeOps = NULL; + + pcwb->nvars = 0; + pcwb->nwildpCodes = 0; + pcwb->nops = 0; + +} + +static void postinit_pCodeWildBlock(pCodeWildBlock *pcwb) +{ + + if(!pcwb) + return; + + pcwb->nvars+=2; + pcwb->nops = pcwb->nvars; + + pcwb->vars = Safe_calloc(pcwb->nvars, sizeof(char *)); + pcwb->wildpCodeOps = Safe_calloc(pcwb->nvars, sizeof(pCodeOp *)); + + pcwb->nwildpCodes+=2; + pcwb->wildpCodes = Safe_calloc(pcwb->nwildpCodes, sizeof(pCode *)); + +} + +static void initpCodePeep(pCodePeep *pcp) +{ + + // pcwb = Safe_calloc(1,sizeof(pCodeWildBlock)); + + if(!pcp) + return; + + initpCodeWildBlock(&pcp->target); + pcp->target.pb = pic16_newpCodeChain(NULL, 'W', NULL); + + initpCodeWildBlock(&pcp->replace); + pcp->replace.pb = pic16_newpCodeChain(NULL, 'W', NULL); + +} + +/*-----------------------------------------------------------------*/ +/* peepRules2pCode - parse the "parsed" peep hole rules to generate*/ +/* pCode. */ +/* */ +/* SDCCpeeph parses the peep rules file and extracts variables, */ +/* removes white space, and checks the syntax. This function */ +/* extends that processing to produce pCode objects. You can kind */ +/* think of this function as an "assembler", though instead of */ +/* taking raw text to produce machine code, it produces pCode. */ +/* */ +/*-----------------------------------------------------------------*/ +extern void pic16initpCodePeepCommands(void); + +void pic16_peepRules2pCode(peepRule *rules) +{ + peepRule *pr; + + pCodePeep *currentRule; + pCodePeepSnippets *pcps; + + pic16initpCodePeepCommands(); + + /* The rules are in a linked-list. Each rule has two portions */ + /* There's the `target' and there's the `replace'. The target */ + /* is compared against the SDCC generated code and if it */ + /* matches, it gets replaced by the `replace' block of code. */ + /* */ + /* Here we loop through each rule and convert the target's and*/ + /* replace's into pCode target and replace blocks */ + + for (pr = rules; pr; pr = pr->next) { + + //DFPRINTF((stderr,"\nRule:\n\n")); + + pcps = Safe_calloc(1,sizeof(pCodePeepSnippets)); + peepSnippets = DLL_append((_DLL*)peepSnippets,(_DLL*)pcps); + + currentRule = pcps->peep = Safe_calloc(1,sizeof(pCodePeep)); + initpCodePeep(currentRule); + + /* Convert the target block */ + peepRuleBlock2pCodeBlock(pr->match, ¤tRule->target); + + //DFPRINTF((stderr,"finished target, here it is in pcode form:\n")); + //pic16_printpBlock(stderr, currentRule->target.pb); + + //DFPRINTF((stderr,"target with labels merged:\n")); + //pic16_pBlockMergeLabels(curBlock); + pic16_pBlockMergeLabels(currentRule->target.pb); + //pic16_printpBlock(stderr, currentRule->replace.pb); + + //#ifdef PCODE_DEBUG + // pic16_printpBlock(stderr, curBlock); + //#endif + //DFPRINTF((stderr,"\nReplaced by:\n")); + + + /* Convert the replace block */ + peepRuleBlock2pCodeBlock(pr->replace, ¤tRule->replace); + + //DFPRINTF((stderr,"finished replace block, here it is in pcode form:\n")); + //pic16_printpBlock(stderr, curBlock); + + //DFPRINTF((stderr,"replace with labels merged:\n")); + + pic16_pBlockMergeLabels(currentRule->replace.pb); + //pic16_printpBlock(stderr, currentRule->replace.pb); + + peepRuleCondition(pr->cond,currentRule); + + /* The rule has been converted to pCode. Now allocate + * space for the wildcards */ + + postinit_pCodeWildBlock(¤tRule->target); + postinit_pCodeWildBlock(¤tRule->replace); + + //return; // debug ... don't want to go through all the rules yet + } + + { + pCodePeep *peepBlock; + _DLL *peeprules; + + peeprules = (_DLL *)peepSnippets; + //fprintf(stderr,"target rules\n"); + while(peeprules) { + //fprintf(stderr," rule:\n"); + peepBlock = ((pCodePeepSnippets*)peeprules)->peep; + //pic16_printpBlock(stderr, peepBlock->target.pb); + peeprules = peeprules->next; + } + //fprintf(stderr," ... done\n"); + } + +} + +static void printpCodeString(FILE *of, pCode *pc, int max) +{ + int i=0; + + while(pc && (i++print(of,pc); + pc = pc->next; + } +} + +/*-----------------------------------------------------------------*/ +/* _DLL * DLL_append */ +/* */ +/* Append a _DLL object to the end of a _DLL (doubly linked list) */ +/* If The list to which we want to append is non-existant then one */ +/* is created. Other wise, the end of the list is sought out and */ +/* a new DLL object is appended to it. In either case, the void */ +/* *data is added to the newly created DLL object. */ +/*-----------------------------------------------------------------*/ + +static void * DLL_append(_DLL *list, _DLL *next) +{ + _DLL *b; + + + /* If there's no list, then create one: */ + if(!list) { + next->next = next->prev = NULL; + return next; + } + + + /* Search for the end of the list. */ + b = list; + while(b->next) + b = b->next; + + /* Now append the new DLL object */ + b->next = next; + b->next->prev = b; + b = b->next; + b->next = NULL; + + return list; + +} + + +/*----------------------------------------------------------------- + + pCode peephole optimization + + + The pCode "peep hole" optimization is not too unlike the peep hole + optimization in SDCCpeeph.c. The major difference is that here we + use pCode's whereas there we use ASCII strings. The advantage with + pCode's is that we can ascertain flow information in the instructions + being optimized. + + + - elaborate... + + -----------------------------------------------------------------*/ + + + +/*-----------------------------------------------------------------*/ +/* pCodeSearchCondition - Search a pCode chain for a 'condition' */ +/* */ +/* return conditions */ +/* 1 - The Condition was found for a pCode's input */ +/* 0 - No matching condition was found for the whole chain */ +/* -1 - The Condition was found for a pCode's output */ +/* */ +/*-----------------------------------------------------------------*/ +int pic16_pCodeSearchCondition(pCode *pc, unsigned int cond) +{ + //fprintf(stderr,"Checking conditions %d\n",cond); + while(pc) { + + /* If we reach a function end (presumably an end since we most + probably began the search in the middle of a function), then + the condition was not found. */ + if(pc->type == PC_FUNCTION) + return 0; + + if(pc->type == PC_OPCODE) { + //fprintf(stderr," checking conditions of: "); + //pc->print(stderr,pc); + //fprintf(stderr,"\t\tinCond=%d\toutCond=%d\n",PCI(pc)->inCond,PCI(pc)->outCond); + if(PCI(pc)->inCond & cond) + return 1; + if(PCI(pc)->outCond & cond) + return -1; + } + + pc = pc->next; + } + + return 0; +} + +/*----------------------------------------------------------------- + * int pCodeOpCompare(pCodeOp *pcops, pCodeOp *pcopd) + * + * Compare two pCodeOp's and return 1 if they're the same + *-----------------------------------------------------------------*/ +static int pCodeOpCompare(pCodeOp *pcops, pCodeOp *pcopd) +{ + char b[50], *n2; + + if(!pcops || !pcopd) + return 0; +/* + fprintf(stderr," Comparing operands %s", + pic16_get_op( pcops,NULL,0)); + + fprintf(stderr," to %s\n", + pic16_get_op( pcopd,NULL,0)); +*/ + + if(pcops->type != pcopd->type) { + //fprintf(stderr," - fail - diff types\n"); + return 0; // different types + } + + if(pcops->type == PO_LITERAL) { + + if((PCOL(pcops)->lit >= 0) && (PCOL(pcops)->lit == PCOL(pcopd)->lit)) + return 1; + + return 0; + } + + b[0]=0; + pic16_get_op(pcops,b,50); + + n2 = pic16_get_op(pcopd,NULL,0); + + if( !n2 || strcmp(b,n2)) { + //fprintf(stderr," - fail - diff names: %s, len=%d, %s, len=%d\n",b,strlen(b), n2, strlen(n2) ); + return 0; // different names + } + + switch(pcops->type) { + case PO_DIR: + if( PCOR(pcops)->instance != PCOR(pcopd)->instance) { + //fprintf(stderr, " - fail different instances\n"); + return 0; + } + break; + default: + break; + } + + //fprintf(stderr," - pass\n"); + + return 1; +} + +static int pCodePeepMatchLabels(pCodePeep *peepBlock, pCode *pcs, pCode *pcd) +{ + int labindex; + + /* Check for a label associated with this wild pCode */ + // If the wild card has a label, make sure the source code does too. + if(PCI(pcd)->label) { + pCode *pcl = PCI(pcd)->label->pc; + +#ifdef PCODE_DEBUG + int li = -PCL(pcl)->key; + + if(peepBlock->target.vars[li] == NULL) { + if(PCI(pcs)->label) { + DFPRINTF((stderr,"first time for a label: %d %s\n",li,PCL(PCI(pcs)->label->pc)->label)); + } + } else { + // DFPRINTF((stderr,"label id = %d \n",PCL(PCI(pcd)->label->pc)->key)); + DFPRINTF((stderr," label id: %d %s\n",li,peepBlock->target.vars[li])); + if(PCI(pcs)->label) { + DFPRINTF((stderr," src %s\n",PCL(PCI(pcs)->label->pc)->label)); + } + } +#endif + + + if(!PCI(pcs)->label) + return 0; + + labindex = -PCL(pcl)->key; + if(peepBlock->target.vars[labindex] == NULL) { + // First time to encounter this label + peepBlock->target.vars[labindex] = PCL(PCI(pcs)->label->pc)->label; + DFPRINTF((stderr,"first time for a label: %d %s\n",labindex,PCL(PCI(pcs)->label->pc)->label)); + + } else { + if(strcmp(peepBlock->target.vars[labindex],PCL(PCI(pcs)->label->pc)->label) != 0) { + DFPRINTF((stderr,"labels don't match dest %s != src %s\n",peepBlock->target.vars[labindex],PCL(PCI(pcs)->label->pc)->label)); + return 0; + } + DFPRINTF((stderr,"matched a label %d %s -hey\n",labindex,peepBlock->target.vars[labindex])); + } + } else { + //DFPRINTF((stderr,"destination doesn't have a label\n")); + + if(PCI(pcs)->label) + return 0; + + //DFPRINTF((stderr,"neither src nor dest have labels\n")); + + } + + return 1; + +} + +/*-----------------------------------------------------------------*/ +/* pCodePeepMatchLine - Compare source and destination pCodes to */ +/* see they're the same. */ +/* */ +/* In this context, "source" refers to the coded generated by gen.c*/ +/* and "destination" refers to a pcode in a peep rule. If the dest-*/ +/* ination has no wild cards, then MatchLine will compare the two */ +/* pcodes (src and dest) for a one-to-one match. If the destination*/ +/* has wildcards, then those get expanded. When a wild card is */ +/* encountered for the first time it autmatically is considered a */ +/* match and the object that matches it is referenced in the */ +/* variables or opcodes array (depending on the type of match). */ +/* */ +/* */ +/* Inputs: */ +/* *peepBlock - A pointer to the peepBlock that contains the */ +/* entire rule to which the destination pcode belongs*/ +/* *pcs - a pointer to the source pcode */ +/* *pcd - a pointer to the destination pcode */ +/* */ +/* Returns: */ +/* 1 - pcodes match */ +/* 0 - pcodes don't match */ +/* */ +/* */ +/*-----------------------------------------------------------------*/ + +static int pCodePeepMatchLine(pCodePeep *peepBlock, pCode *pcs, pCode *pcd) +{ + int index; // index into wild card arrays + + /* one-for-one match. Here the source and destination opcodes + * are not wild. However, there may be a label or a wild operand */ + + if(pcs) { + if(PCI(pcs)->label) { + DFPRINTF((stderr,"Match line source label: %s\n",PCL(PCI(pcs)->label->pc)->label)); + } + } + + if(pcs->type == pcd->type) { + + if(pcs->type == PC_OPCODE) { + + /* If the opcodes don't match then the line doesn't match */ + if(PCI(pcs)->op != PCI(pcd)->op) + return 0; + +#ifdef PCODE_DEBUG + DFPRINTF((stderr,"%s comparing\n",__FUNCTION__)); + pcs->print(stderr,pcs); + pcd->print(stderr,pcd); +#endif + + if(!pCodePeepMatchLabels(peepBlock, pcs, pcd)) + return 0; + + /* Compare the operands */ + if(PCI(pcd)->pcop) { + if (PCI(pcd)->pcop->type == PO_WILD) { + index = PCOW(PCI(pcd)->pcop)->id; + //DFPRINTF((stderr,"destination is wild\n")); +#ifdef DEBUG_PCODEPEEP + if (index > peepBlock->nops) { + DFPRINTF((stderr,"%s - variables exceeded\n",__FUNCTION__)); + exit(1); + } +#endif + + PCOW(PCI(pcd)->pcop)->matched = PCI(pcs)->pcop; + if(!peepBlock->target.wildpCodeOps[index]) { + peepBlock->target.wildpCodeOps[index] = PCI(pcs)->pcop; + + //if(PCI(pcs)->pcop->type == PO_GPR_TEMP) + + } else { + /* + pcs->print(stderr,pcs); + pcd->print(stderr,pcd); + + fprintf(stderr, "comparing operands of these instructions, result %d\n", + pCodeOpCompare(PCI(pcs)->pcop, peepBlock->target.wildpCodeOps[index]) + ); + */ + + return pCodeOpCompare(PCI(pcs)->pcop, peepBlock->target.wildpCodeOps[index]); + } + + { + char *n; + + switch(PCI(pcs)->pcop->type) { + case PO_GPR_TEMP: + case PO_FSR0: + //case PO_INDF0: + n = PCOR(PCI(pcs)->pcop)->r->name; + + break; + default: + n = PCI(pcs)->pcop->name; + } + + if(peepBlock->target.vars[index]) + return (strcmp(peepBlock->target.vars[index],n) == 0); + else { + DFPRINTF((stderr,"first time for a variable: %d, %s\n",index,n)); + peepBlock->target.vars[index] = n; + return 1; + } + } + + } else if (PCI(pcd)->pcop->type == PO_LITERAL) { + return pCodeOpCompare(PCI(pcs)->pcop, PCI(pcd)->pcop); + + } + /* FIXME - need an else to check the case when the destination + * isn't a wild card */ + } else + /* The pcd has no operand. Lines match if pcs has no operand either*/ + return (PCI(pcs)->pcop == NULL); + } + } + + /* Compare a wild instruction to a regular one. */ + + if((pcd->type == PC_WILD) && (pcs->type == PC_OPCODE)) { + + index = PCW(pcd)->id; +#ifdef PCODE_DEBUG + DFPRINTF((stderr,"%s comparing wild cards\n",__FUNCTION__)); + pcs->print(stderr,pcs); + pcd->print(stderr,pcd); +#endif + peepBlock->target.wildpCodes[PCW(pcd)->id] = pcs; + + if(!pCodePeepMatchLabels(peepBlock, pcs, pcd)) { + DFPRINTF((stderr," Failing because labels don't match\n")); + return 0; + } + + if(PCW(pcd)->mustBeBitSkipInst & !(PCI(pcs)->isBitInst && PCI(pcs)->isSkip)) { + // doesn't match because the wild pcode must be a bit skip + DFPRINTF((stderr," Failing match because bit skip is req\n")); + //pcd->print(stderr,pcd); + //pcs->print(stderr,pcs); + return 0; + } + + if(PCW(pcd)->mustNotBeBitSkipInst & (PCI(pcs)->isBitInst && PCI(pcs)->isSkip)) { + // doesn't match because the wild pcode must *not* be a bit skip + DFPRINTF((stderr," Failing match because shouldn't be bit skip\n")); + //pcd->print(stderr,pcd); + //pcs->print(stderr,pcs); + return 0; + } + + if(PCW(pcd)->operand) { + PCOW(PCI(pcd)->pcop)->matched = PCI(pcs)->pcop; + if(peepBlock->target.vars[index]) { + int i = (strcmp(peepBlock->target.vars[index],PCI(pcs)->pcop->name) == 0); +#ifdef PCODE_DEBUG + + if(i) + DFPRINTF((stderr," (matched)\n")); + else { + DFPRINTF((stderr," (no match: wild card operand mismatch\n")); + DFPRINTF((stderr," peepblock= %s, pcodeop= %s\n", + peepBlock->target.vars[index], + PCI(pcs)->pcop->name)); + } +#endif + return i; + } else { + DFPRINTF((stderr," (matched %s\n",PCI(pcs)->pcop->name)); + peepBlock->target.vars[index] = PCI(pcs)->pcop->name; + return 1; + } + } + + pcs = pic16_findNextInstruction(pcs->next); + if(pcs) { + //DFPRINTF((stderr," (next to match)\n")); + //pcs->print(stderr,pcs); + } else if(pcd->next) { + /* oops, we ran out of code, but there's more to the rule */ + return 0; + } + + return 1; /* wild card matches */ + } + + return 0; +} + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +static void pCodePeepClrVars(pCodePeep *pcp) +{ + + int i; + if(!pcp) + return; +/* + DFPRINTF((stderr," Clearing peep rule vars\n")); + DFPRINTF((stderr," %d %d %d %d %d %d\n", + pcp->target.nvars,pcp->target.nops,pcp->target.nwildpCodes, + pcp->replace.nvars,pcp->replace.nops,pcp->replace.nwildpCodes)); +*/ + for(i=0;itarget.nvars; i++) + pcp->target.vars[i] = NULL; + for(i=0;itarget.nops; i++) + pcp->target.wildpCodeOps[i] = NULL; + for(i=0;itarget.nwildpCodes; i++) + pcp->target.wildpCodes[i] = NULL; + + for(i=0;ireplace.nvars; i++) + pcp->replace.vars[i] = NULL; + for(i=0;ireplace.nops; i++) + pcp->replace.wildpCodeOps[i] = NULL; + for(i=0;ireplace.nwildpCodes; i++) + pcp->replace.wildpCodes[i] = NULL; + + + +} + +/*-----------------------------------------------------------------*/ +/* pCodeInsertAfter - splice in the pCode chain starting with pc2 */ +/* into the pCode chain containing pc1 */ +/*-----------------------------------------------------------------*/ +void pic16_pCodeInsertAfter(pCode *pc1, pCode *pc2) +{ + + if(!pc1 || !pc2) + return; + + pc2->next = pc1->next; + if(pc1->next) + pc1->next->prev = pc2; + + pc2->pb = pc1->pb; + pc2->prev = pc1; + pc1->next = pc2; + +} + +/*-----------------------------------------------------------------*/ +/* pic16_pCodeOpCopy - copy a pcode operator */ +/*-----------------------------------------------------------------*/ +pCodeOp *pic16_pCodeOpCopy(pCodeOp *pcop) +{ + pCodeOp *pcopnew=NULL; + + if(!pcop) + return NULL; + + switch(pcop->type) { + case PO_CRY: + case PO_BIT: + //DFPRINTF((stderr,"pCodeOpCopy bit\n")); + pcopnew = Safe_calloc(1,sizeof(pCodeOpRegBit) ); + PCORB(pcopnew)->bit = PCORB(pcop)->bit; + PCORB(pcopnew)->inBitSpace = PCORB(pcop)->inBitSpace; + + break; + + case PO_WILD: + /* Here we expand the wild card into the appropriate type: */ + /* By recursively calling pCodeOpCopy */ + //DFPRINTF((stderr,"pCodeOpCopy wild\n")); + if(PCOW(pcop)->matched) + pcopnew = pic16_pCodeOpCopy(PCOW(pcop)->matched); + else { + // Probably a label + pcopnew = pic16_pCodeOpCopy(PCOW(pcop)->subtype); + pcopnew->name = Safe_strdup(PCOW(pcop)->pcwb->vars[PCOW(pcop)->id]); + //DFPRINTF((stderr,"copied a wild op named %s\n",pcopnew->name)); + } + + return pcopnew; + break; + + case PO_LABEL: + //DFPRINTF((stderr,"pCodeOpCopy label\n")); + pcopnew = Safe_calloc(1,sizeof(pCodeOpLabel) ); + PCOLAB(pcopnew)->key = PCOLAB(pcop)->key; + break; + + case PO_IMMEDIATE: + pcopnew = Safe_calloc(1,sizeof(pCodeOpImmd) ); + PCOI(pcopnew)->index = PCOI(pcop)->index; + PCOI(pcopnew)->offset = PCOI(pcop)->offset; + PCOI(pcopnew)->_const = PCOI(pcop)->_const; + break; + + case PO_LITERAL: + //DFPRINTF((stderr,"pCodeOpCopy lit\n")); + pcopnew = Safe_calloc(1,sizeof(pCodeOpLit) ); + PCOL(pcopnew)->lit = PCOL(pcop)->lit; + break; + +#if 0 // mdubuc - To add + case PO_REL_ADDR: + break; +#endif + + case PO_GPR_BIT: + + pcopnew = pic16_newpCodeOpBit(pcop->name, PCORB(pcop)->bit,PCORB(pcop)->inBitSpace); + PCOR(pcopnew)->r = PCOR(pcop)->r; + PCOR(pcopnew)->rIdx = PCOR(pcop)->rIdx; + DFPRINTF((stderr," pCodeOpCopy Bit -register index\n")); + return pcopnew; + break; + + case PO_GPR_REGISTER: + case PO_GPR_TEMP: + case PO_FSR0: + case PO_INDF0: + //DFPRINTF((stderr,"pCodeOpCopy GPR register\n")); + pcopnew = Safe_calloc(1,sizeof(pCodeOpReg) ); + PCOR(pcopnew)->r = PCOR(pcop)->r; + PCOR(pcopnew)->rIdx = PCOR(pcop)->rIdx; + PCOR(pcopnew)->instance = PCOR(pcop)->instance; + DFPRINTF((stderr," register index %d\n", PCOR(pcop)->r->rIdx)); + break; + + case PO_DIR: + //fprintf(stderr,"pCodeOpCopy PO_DIR\n"); + pcopnew = Safe_calloc(1,sizeof(pCodeOpReg) ); + PCOR(pcopnew)->r = PCOR(pcop)->r; + PCOR(pcopnew)->rIdx = PCOR(pcop)->rIdx; + PCOR(pcopnew)->instance = PCOR(pcop)->instance; + break; + case PO_STATUS: + DFPRINTF((stderr,"pCodeOpCopy PO_STATUS\n")); + case PO_BSR: + DFPRINTF((stderr,"pCodeOpCopy PO_BSR\n")); + case PO_SFR_REGISTER: + case PO_STR: + case PO_NONE: + case PO_W: + case PO_WREG: + case PO_INTCON: + case PO_PCL: + case PO_PCLATH: + + //DFPRINTF((stderr,"pCodeOpCopy register type %d\n", pcop->type)); + pcopnew = Safe_calloc(1,sizeof(pCodeOp) ); + + } + + pcopnew->type = pcop->type; + if(pcop->name) + pcopnew->name = Safe_strdup(pcop->name); + else + pcopnew->name = NULL; + + return pcopnew; +} + + +/*-----------------------------------------------------------------*/ +/* pCodeCopy - copy a pcode */ +/*-----------------------------------------------------------------*/ +static pCode *pCodeInstructionCopy(pCodeInstruction *pci,int invert) +{ + pCodeInstruction *new_pci; + + if(invert) + new_pci = PCI(pic16_newpCode(pci->inverted_op,pci->pcop)); + else + new_pci = PCI(pic16_newpCode(pci->op,pci->pcop)); + + new_pci->pc.pb = pci->pc.pb; + new_pci->from = pci->from; + new_pci->to = pci->to; + new_pci->label = pci->label; + new_pci->pcflow = pci->pcflow; + + return PCODE(new_pci); +} + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +static void pCodeDeleteChain(pCode *f,pCode *t) +{ + pCode *pc; + + + while(f && f!=t) { + DFPRINTF((stderr,"delete pCode:\n")); + pc = f->next; + //f->print(stderr,f); + //f->delete(f); this dumps core... + + f = pc; + + } + +} +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +int pic16_pCodePeepMatchRule(pCode *pc) +{ + pCodePeep *peepBlock; + pCode *pct, *pcin; + pCodeCSource *pc_cline=NULL; + _DLL *peeprules; + int matched; + + peeprules = (_DLL *)peepSnippets; + + while(peeprules) { + peepBlock = ((pCodePeepSnippets*)peeprules)->peep; + + if(!peepBlock || /*!peepBlock->target ||*/ !peepBlock->target.pb->pcHead) { + fprintf(stderr, "skipping rule because target pb is NULL\n"); + goto next_rule; + } + + pCodePeepClrVars(peepBlock); +/* + pcin = pc; + if(IS_PCCOMMENT(pcin)) + pc = pcin = pic16_findNextInstruction(pcin->next); +*/ + pcin = pc = pic16_findNextInstruction(pc); + + pct = peepBlock->target.pb->pcHead; +#ifdef PCODE_DEBUG + { + pCode *pcr = peepBlock->replace.pb->pcHead; + if(pcr) pct->print(stderr,pcr); + } +#endif + matched = 0; + while(pct && pcin) { + + if(! (matched = pCodePeepMatchLine(peepBlock, pcin,pct))) + break; + + pcin = pic16_findNextInstruction(pcin->next); + pct = pct->next; + //debug: + //DFPRINTF((stderr," matched\n")); + + if(!pcin && pct) { + DFPRINTF((stderr," partial match... no more code\n")); + fprintf(stderr," partial match... no more code\n"); + matched = 0; + } + if(!pct) { + DFPRINTF((stderr," end of rule\n")); + } + } + + if(matched && pcin) { + + /* So far we matched the rule up to the point of the conditions . + * In other words, all of the opcodes match. Now we need to see + * if the post conditions are satisfied. + * First we check the 'postFalseCond'. This means that we check + * to see if any of the subsequent pCode's in the pCode chain + * following the point just past where we have matched depend on + * the `postFalseCond' as input then we abort the match + */ + DFPRINTF((stderr," matched rule so far, now checking conditions\n")); + //pcin->print(stderr,pcin); + + if (pcin && peepBlock->postFalseCond && + (pic16_pCodeSearchCondition(pcin,peepBlock->postFalseCond) > 0) ) + matched = 0; + + //fprintf(stderr," condition results = %d\n",pic16_pCodeSearchCondition(pcin,peepBlock->postFalseCond)); + + + //if(!matched) fprintf(stderr,"failed on conditions\n"); + } + + if(matched) { + + pCode *pcprev; + pCode *pcr; + + + /* We matched a rule! Now we have to go through and remove the + inefficient code with the optimized version */ +#ifdef PCODE_DEBUG + DFPRINTF((stderr, "Found a pcode peep match:\nRule:\n")); + printpCodeString(stderr,peepBlock->target.pb->pcHead,10); + DFPRINTF((stderr,"first thing matched\n")); + pc->print(stderr,pc); + if(pcin) { + DFPRINTF((stderr,"last thing matched\n")); + pcin->print(stderr,pcin); + } +#endif + + + /* Unlink the original code */ + pcprev = pc->prev; + pcprev->next = pcin; + if(pcin) + pcin->prev = pc->prev; + + +#if 0 + { + /* DEBUG */ + /* Converted the deleted pCodes into comments */ + + char buf[256]; + pCodeCSource *pc_cline2=NULL; + + buf[0] = ';'; + buf[1] = '#'; + + while(pc && pc!=pcin) { + + if(pc->type == PC_OPCODE && PCI(pc)->cline) { + if(pc_cline) { + pc_cline2->pc.next = PCODE(PCI(pc)->cline); + pc_cline2 = PCCS(pc_cline2->pc.next); + } else { + pc_cline = pc_cline2 = PCI(pc)->cline; + pc_cline->pc.seq = pc->seq; + } + } + + pCode2str(&buf[2], 254, pc); + pic16_pCodeInsertAfter(pcprev, pic16_newpCodeCharP(buf)); + pcprev = pcprev->next; + pc = pc->next; + + } + if(pc_cline2) + pc_cline2->pc.next = NULL; + } +#endif + + if(pcin) + pCodeDeleteChain(pc,pcin); + + /* Generate the replacement code */ + pc = pcprev; + pcr = peepBlock->replace.pb->pcHead; // This is the replacement code + while (pcr) { + pCodeOp *pcop=NULL; + + /* If the replace pcode is an instruction with an operand, */ + /* then duplicate the operand (and expand wild cards in the process). */ + if(pcr->type == PC_OPCODE) { + if(PCI(pcr)->pcop) { + /* The replacing instruction has an operand. + * Is it wild? */ + if(PCI(pcr)->pcop->type == PO_WILD) { + int index = PCOW(PCI(pcr)->pcop)->id; + //DFPRINTF((stderr,"copying wildopcode\n")); + if(peepBlock->target.wildpCodeOps[index]) + pcop = pic16_pCodeOpCopy(peepBlock->target.wildpCodeOps[index]); + else + DFPRINTF((stderr,"error, wildopcode in replace but not source?\n")); + } else + pcop = pic16_pCodeOpCopy(PCI(pcr)->pcop); + } + //DFPRINTF((stderr,"inserting pCode\n")); + pic16_pCodeInsertAfter(pc, pic16_newpCode(PCI(pcr)->op,pcop)); + } else if (pcr->type == PC_WILD) { + if(PCW(pcr)->invertBitSkipInst) + DFPRINTF((stderr,"We need to invert the bit skip instruction\n")); + pic16_pCodeInsertAfter(pc, + pCodeInstructionCopy(PCI(peepBlock->target.wildpCodes[PCW(pcr)->id]), + PCW(pcr)->invertBitSkipInst)); + } else if (pcr->type == PC_COMMENT) { + pic16_pCodeInsertAfter(pc, pic16_newpCodeCharP( ((pCodeComment *)(pcr))->comment)); + } + + + pc = pc->next; +#ifdef PCODE_DEBUG + DFPRINTF((stderr," NEW Code:")); + if(pc) pc->print(stderr,pc); +#endif + pcr = pcr->next; + } + + /* We have just replaced the inefficient code with the rule. + * Now, we need to re-add the C-source symbols if there are any */ + pc = pcprev; + while(pc_cline ) { + + pc = pic16_findNextInstruction(pc->next); + PCI(pc)->cline = pc_cline; + pc_cline = PCCS(pc_cline->pc.next); + + } + + return 1; + } + next_rule: + peeprules = peeprules->next; + } + DFPRINTF((stderr," no rule matched\n")); + + return 0; +} diff --git a/src/pic16/pcoderegs.c b/src/pic16/pcoderegs.c new file mode 100644 index 00000000..26ed6cdb --- /dev/null +++ b/src/pic16/pcoderegs.c @@ -0,0 +1,844 @@ +/*------------------------------------------------------------------------- + + pcoderegs.c - post code generation register optimizations + + Written By - Scott Dattalo scott@dattalo.com + Ported To PIC16 By - 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. + +-------------------------------------------------------------------------*/ + +/* + pcoderegs.c + + The purpose of the code in this file is to optimize the register usage. + +*/ +#include + +#include "common.h" // Include everything in the SDCC src directory +#include "newalloc.h" +#include "ralloc.h" +#include "device.h" +#include "pcode.h" +#include "pcoderegs.h" +#include "pcodeflow.h" + +extern void pic16_pCodeInsertAfter(pCode *pc1, pCode *pc2); +extern pCode * pic16_findPrevInstruction(pCode *pci); +extern pBranch * pic16_pBranchAppend(pBranch *h, pBranch *n); +void pic16_unlinkpCode(pCode *pc); +extern int pic16_pCodeSearchCondition(pCode *pc, unsigned int cond); + +static int total_registers_saved=0; +static int register_optimization=1; + +/*-----------------------------------------------------------------* + * void AddRegToFlow(regs *reg, pCodeFlow *pcfl) + *-----------------------------------------------------------------*/ +/* +void AddRegToFlow(regs *reg, pCodeFlow *pcfl) +{ + + if(!reg || ! pcfl || !isPCFL(pcflow)) + return; + + if(!pcfl->registers) + pcfl->registers = newSet(); + +} +*/ + + +/*-----------------------------------------------------------------* + * + *-----------------------------------------------------------------*/ +static void dbg_regusage(set *fregs) +{ + regs *reg; + pCode *pcfl; + pCode *pc; + + + for (reg = setFirstItem(fregs) ; reg ; + reg = setNextItem(fregs)) { + + if(elementsInSet(reg->reglives.usedpCodes)) { + + fprintf (stderr, "%s addr=0x%03x rIdx=0x%03x", + reg->name, + reg->address, + reg->rIdx); + + pcfl = setFirstItem(reg->reglives.usedpFlows); + if(pcfl) + fprintf(stderr, "\n used in seq"); + + while(pcfl) { + fprintf(stderr," 0x%03x",pcfl->seq); + pcfl = setNextItem(reg->reglives.usedpFlows); + } + + pcfl = setFirstItem(reg->reglives.assignedpFlows); + if(pcfl) + fprintf(stderr, "\n assigned in seq"); + + while(pcfl) { + fprintf(stderr," 0x%03x",pcfl->seq); + pcfl = setNextItem(reg->reglives.assignedpFlows); + } + + pc = setFirstItem(reg->reglives.usedpCodes); + if(pc) + fprintf(stderr, "\n used in instructions "); + + while(pc) { + pcfl = PCODE(PCI(pc)->pcflow); + if(pcfl) + fprintf(stderr," 0x%03x:",pcfl->seq); + fprintf(stderr,"0x%03x",pc->seq); + + pc = setNextItem(reg->reglives.usedpCodes); + } + + fprintf(stderr, "\n"); + } + } +} + +/*-----------------------------------------------------------------* + * + *-----------------------------------------------------------------*/ +static void dbg_dumpregusage(void) +{ + + fprintf(stderr,"*** Register Usage ***\n"); + fprintf(stderr,"InternalRegs:\n"); + dbg_regusage(pic16_dynInternalRegs); + fprintf(stderr,"AllocRegs:\n"); + dbg_regusage(pic16_dynAllocRegs); + fprintf(stderr,"StackRegs:\n"); + dbg_regusage(pic16_dynStackRegs); + fprintf(stderr,"DirectRegs:\n"); + dbg_regusage(pic16_dynDirectRegs); + fprintf(stderr,"DirectBitRegs:\n"); + dbg_regusage(pic16_dynDirectBitRegs); + fprintf(stderr,"ProcessorRegs:\n"); + dbg_regusage(pic16_dynProcessorRegs); + +} + + +/*-----------------------------------------------------------------* + * void pCodeRegMapLiveRangesInFlow(pCodeFlow *pcfl) + *-----------------------------------------------------------------*/ +static void pCodeRegMapLiveRangesInFlow(pCodeFlow *pcfl) +{ + + pCode *pc=NULL; + pCode *pcprev=NULL; + + regs *reg; + + if(!pcfl) + return; + + + pc = pic16_findNextInstruction(pcfl->pc.next); + + while(pic16_isPCinFlow(pc,PCODE(pcfl))) { + + + reg = pic16_getRegFromInstruction(pc); + + if(reg) { +/* + fprintf(stderr, "flow seq %d, inst seq %d %s ",PCODE(pcfl)->seq,pc->seq,reg->name); + fprintf(stderr, "addr = 0x%03x, type = %d rIdx=0x%03x\n", + reg->address,reg->type,reg->rIdx); +*/ + + addSetIfnotP(& (PCFL(pcfl)->registers), reg); + + if((PCC_REGISTER | PCC_LITERAL) & PCI(pc)->inCond) + addSetIfnotP(& (reg->reglives.usedpFlows), pcfl); + + if(PCC_REGISTER & PCI(pc)->outCond) + addSetIfnotP(& (reg->reglives.assignedpFlows), pcfl); + + addSetIfnotP(& (reg->reglives.usedpCodes), pc); + } + + + pcprev = pc; + pc = pic16_findNextInstruction(pc->next); + + } + +} + +/*-----------------------------------------------------------------* + * void pic16_pCodeRegMapLiveRanges(pBlock *pb) + *-----------------------------------------------------------------*/ +void pic16_pCodeRegMapLiveRanges(pBlock *pb) +{ + pCode *pcflow; + + for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); + pcflow != NULL; + pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) { + + if(!isPCFL(pcflow)) { + fprintf(stderr, "pCodeRegMapLiveRanges - pcflow is not a flow object "); + continue; + } + pCodeRegMapLiveRangesInFlow(PCFL(pcflow)); + } + +#if 0 + for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); + pcflow != NULL; + pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) { + + regs *r = setFirstItem(PCFL(pcflow)->registers); + fprintf(stderr,"flow seq %d\n", pcflow->seq); + + while (r) { + fprintf(stderr, " %s\n",r->name); + r = setNextItem(PCFL(pcflow)->registers); + + } + + } +#endif + +// dbg_dumpregusage(); + +} + + +/*-----------------------------------------------------------------* + * + *-----------------------------------------------------------------*/ +static void Remove1pcode(pCode *pc, regs *reg) +{ + pCode *pcn=NULL; + + if(!reg || !pc) + return; + + deleteSetItem (&(reg->reglives.usedpCodes),pc); +/* + fprintf(stderr,"removing instruction:\n"); + pc->print(stderr,pc); +*/ + if(PCI(pc)->label) { + pcn = pic16_findNextInstruction(pc->next); + + if(pcn) + PCI(pcn)->label = pic16_pBranchAppend(PCI(pcn)->label,PCI(pc)->label); + } + + if(PCI(pc)->cline) { + if(!pcn) + pcn = pic16_findNextInstruction(pc->next); + + if(pcn) { + if(PCI(pcn)->cline) { + //fprintf(stderr, "source line has been optimized completely out\n"); + //pc->print(stderr,pc); + } else { + PCI(pcn)->cline = PCI(pc)->cline; + } + } + } + + pc->destruct(pc); + +} + +/*-----------------------------------------------------------------* + * void RemoveRegsFromSet(set *regset) + * + *-----------------------------------------------------------------*/ +static void RemoveRegsFromSet(set *regset) +{ + regs *reg; + int used; + + while(regset) { + reg = regset->item; + regset = regset->next; + + used = elementsInSet(reg->reglives.usedpCodes); + + if(used <= 1) { + + //fprintf(stderr," reg %s isfree=%d, wasused=%d\n",reg->name,reg->isFree,reg->wasUsed); + if(used == 0) { + //fprintf(stderr," getting rid of reg %s\n",reg->name); + reg->isFree = 1; + reg->wasUsed = 0; + } else { + pCode *pc; + + + pc = setFirstItem(reg->reglives.usedpCodes); + + if(reg->type == REG_SFR) { + //fprintf(stderr, "not removing SFR reg %s even though used only once\n",reg->name); + continue; + } + + + if(isPCI(pc)) { + if(PCI(pc)->label) { + pCode *pcn = pic16_findNextInstruction(pc->next); + + if(pcn && PCI(pcn)->label) { + //fprintf(stderr,"can't delete instruction with label...\n"); + //pc->print(stderr,pc); + continue; + } + /* Move the label to the next instruction */ + + PCI(pcn)->label = PCI(pc)->label; + + } + + if(isPCI_SKIP(pc)) { + regs *r = pic16_getRegFromInstruction(pc); + fprintf(stderr, "WARNING, a skip instruction is being optimized out\n"); + pc->print(stderr,pc); + fprintf(stderr,"reg %s, type =%d\n",r->name, r->type); + } + //fprintf(stderr," removing reg %s because it is used only once\n",reg->name); + Remove1pcode(pc, reg); + /* + pic16_unlinkpCode(pc); + deleteSetItem (&(reg->reglives.usedpCodes),pc); + */ + reg->isFree = 1; + reg->wasUsed = 0; + total_registers_saved++; // debugging stats. + } + } + } + + } +} +/*-----------------------------------------------------------------* + * void pic16_RemoveUnusedRegisters(void) + * + *-----------------------------------------------------------------*/ +void pic16_RemoveUnusedRegisters(void) +{ + /* First, get rid of registers that are used only one time */ + + //RemoveRegsFromSet(pic16_dynInternalRegs); + RemoveRegsFromSet(pic16_dynAllocRegs); + RemoveRegsFromSet(pic16_dynStackRegs); + /* + don't do DirectRegs yet - there's a problem with arrays + RemoveRegsFromSet(pic16_dynDirectRegs); + */ + RemoveRegsFromSet(pic16_dynDirectBitRegs); + + if(total_registers_saved) fprintf(stderr, " *** Saved %d registers ***\n", total_registers_saved); +} + + +/*-----------------------------------------------------------------* + * + *-----------------------------------------------------------------*/ +static void Remove2pcodes(pCode *pcflow, pCode *pc1, pCode *pc2, regs *reg, int can_free) +{ + if(!reg) + return; + + if(pc1) + Remove1pcode(pc1, reg); + + if(pc2) { + Remove1pcode(pc2, reg); + deleteSetItem (&(PCFL(pcflow)->registers), reg); + + if(can_free) { + reg->isFree = 1; + reg->wasUsed = 0; + } + + } + + pCodeRegMapLiveRangesInFlow(PCFL(pcflow)); +} + +/*-----------------------------------------------------------------* + * + *-----------------------------------------------------------------*/ +static int regUsedinRange(pCode *pc1, pCode *pc2, regs *reg) +{ + int i=0; + regs *testreg; + + do { + testreg = pic16_getRegFromInstruction(pc1); + if(testreg && (testreg->rIdx == reg->rIdx)) { + return 1; + } + + pc1 = pic16_findNextInstruction(pc1->next); + + } while (pc1 && (pc1 != pc2) && (i++ < 100)) ; + + if(i >= 100) + fprintf(stderr, "warning, regUsedinRange searched through too many pcodes\n"); + + return 0; +} + +/*-----------------------------------------------------------------* + * void pCodeOptime2pCodes(pCode *pc1, pCode *pc2) + * + * ADHOC pattern checking + * Now look for specific sequences that are easy to optimize. + * Many of these sequences are characteristic of the compiler + * (i.e. it'd probably be a waste of time to apply these adhoc + * checks to hand written assembly.) + * + * + *-----------------------------------------------------------------*/ +static int pCodeOptime2pCodes(pCode *pc1, pCode *pc2, pCode *pcfl_used, regs *reg, int can_free, int optimize_level) +{ + pCode *pct1, *pct2; + regs *reg1, *reg2; + + int t = total_registers_saved; + + if(pc2->seq < pc1->seq) { + pct1 = pc2; + pc2 = pc1; + pc1 = pct1; + } +/* + fprintf(stderr,"pCodeOptime2pCodes\n"); + pc1->print(stderr,pc1); + pc2->print(stderr,pc2); +*/ + if((PCI(pc1)->op == POC_CLRF) && (PCI(pc2)->op == POC_MOVFW) ){ + + /* + clrf reg + stuff... + movf reg,w + + can be replaced with + + stuff... + movlw 0 + */ + + pCode *newpc; + //fprintf(stderr, " CLRF/MOVFW. instruction after MOVFW is:\n"); + pct1 = pic16_findNextInstruction(pc2->next); + + if(PCI(pct1)->op == POC_MOVWF) { + newpc = pic16_newpCode(POC_CLRF, PCI(pct1)->pcop); + pct1->destruct(pct1); + } else { + newpc = pic16_newpCode(POC_MOVLW, pic16_newpCodeOpLit(0)); + } + + pic16_pCodeInsertAfter(pc2, newpc); + PCI(newpc)->pcflow = PCFL(pcfl_used); + newpc->seq = pc2->seq; + + Remove2pcodes(pcfl_used, pc1, pc2, reg, can_free); + total_registers_saved++; // debugging stats. + + } else if((PCI(pc1)->op == POC_CLRF) && (PCI(pc2)->op == POC_IORFW) ){ + //fprintf(stderr, " CLRF/IORFW.\n"); + + pct2 = pic16_findNextInstruction(pc2->next); + + if(pic16_pCodeSearchCondition(pct2, PCC_Z) > 0) { + pct2 = pic16_newpCode(POC_IORLW, pic16_newpCodeOpLit(0)); + pct2->seq = pc2->seq; + PCI(pct2)->pcflow = PCFL(pcfl_used); + pic16_pCodeInsertAfter(pc1,pct2); + } + Remove2pcodes(pcfl_used, pc1, pc2, reg, can_free); + total_registers_saved++; // debugging stats. + + } else if(PCI(pc1)->op == POC_MOVWF) { + + pct2 = pic16_findNextInstruction(pc2->next); + + if(PCI(pc2)->op == POC_MOVFW) { + /* + fprintf(stderr, " MOVWF/MOVFW. instruction after MOVFW is:\n"); + pct2->print(stderr,pct2); + */ + + if(PCI(pct2)->op == POC_MOVWF) { + /* + Change: + + movwf reg + + stuff... + + movf reg,w + movwf reg2 + + To: + + + */ + reg2 = pic16_getRegFromInstruction(pct2); + //if(reg2 && !regUsedinRange(pc1,pc2,reg2) && (reg2->type != REG_SFR)) { + if(reg2 && !regUsedinRange(pc1,pc2,reg2)) { + + if(pic16_pCodeSearchCondition(pct2, PCC_Z) < 1) { + pCode *pct3 = pic16_findNextInstruction(pct2->next); + pct2->seq = pc1->seq; + pic16_unlinkpCode(pct2); + pic16_pCodeInsertAfter(pic16_findPrevInstruction(pc1->prev),pct2); + +#define usesW(x) ((x) && (isPCI(x)) && ( (PCI(x)->inCond & PCC_W) != 0)) + + if(usesW(pct3)) + ; // Remove2pcodes(pcfl_used, pc1, NULL, reg, can_free); + else + Remove2pcodes(pcfl_used, pc1, pc2, reg, can_free); + + total_registers_saved++; // debugging stats. + return 1; + } else { + //fprintf(stderr,"didn't optimize because Z bit is used\n"); + } + } +/* + fprintf(stderr, " couldn't optimize\n"); + if(reg2) + fprintf(stderr, " %s is used in range\n",reg2->name); + else + fprintf(stderr, " reg2 is NULL\n"); +*/ + } + } + + pct1 = pic16_findPrevInstruction(pc1->prev); + if(pct1 && (PCI(pct1)->pcflow == PCI(pc1)->pcflow)) { + + if ( (PCI(pct1)->op == POC_MOVFW) && + (PCI(pc2)->op == POC_MOVFW)) { + + reg1 = pic16_getRegFromInstruction(pct1); + if(reg1 && !regUsedinRange(pc1,pc2,reg1)) { + /* + fprintf(stderr, " MOVF/MOVFW. \n"); + fprintf(stderr, " ...optimizing\n"); + */ + + /* + Change: + + movf reg1,w + movwf reg + + stuff... + movf reg,w + + To: + + stuff... + + movf reg1,w + + Or, if we're not deleting the register then the "To" is: + + stuff... + + movf reg1,w + movwf reg + + + */ + pct2 = pic16_newpCode(PCI(pc2)->op, PCI(pct1)->pcop); + pic16_pCodeInsertAfter(pc2, pct2); + PCI(pct2)->pcflow = PCFL(pcfl_used); + pct2->seq = pc2->seq; + + if(can_free) { + Remove2pcodes(pcfl_used, pc1, pc2, reg, can_free); + } else { + /* If we're not freeing the register then that means (probably) + * the register is needed somewhere else.*/ + pic16_unlinkpCode(pc1); + pic16_pCodeInsertAfter(pct2, pc1); + + Remove2pcodes(pcfl_used, pc2, NULL, reg, can_free); + } + + Remove2pcodes(pcfl_used, pct1, NULL, reg1, 0); + total_registers_saved++; // debugging stats. + + } + } else if ( (PCI(pct1)->op == POC_MOVWF) && + (PCI(pc2)->op == POC_MOVFW)) { + //fprintf(stderr,"movwf MOVWF/MOVFW\n"); + if(optimize_level > 1 && can_free) { + pct2 = pic16_newpCode(POC_MOVFW, PCI(pc1)->pcop); + pic16_pCodeInsertAfter(pc2, pct2); + Remove2pcodes(pcfl_used, pc1, pc2, reg, 1); + total_registers_saved++; // debugging stats. + } + } + + + } + + } + + return (total_registers_saved != t); +} + +/*-----------------------------------------------------------------* + * void pCodeRegOptimeRegUsage(pBlock *pb) + *-----------------------------------------------------------------*/ +static void OptimizeRegUsage(set *fregs, int optimize_multi_uses, int optimize_level) +{ + regs *reg; + int used; + pCode *pc1=NULL, *pc2=NULL; + + + while(fregs) { + pCode *pcfl_used, *pcfl_assigned; + + /* Step through the set by directly accessing the 'next' pointer. + * We could also step through by using the set API, but the + * the (debug) calls to print instructions affect the state + * of the set pointers */ + + reg = fregs->item; + fregs = fregs->next; + + if(reg->type == REG_SFR) { + //fprintf(stderr,"skipping SFR: %s\n",reg->name); + continue; + } + + pcfl_used = setFirstItem(reg->reglives.usedpFlows); + pcfl_assigned = setFirstItem(reg->reglives.assignedpFlows); + + used = elementsInSet(reg->reglives.usedpCodes); + if(used == 2) { + + /* + * In this section, all registers that are used in only in two + * instructions are examined. If possible, they're optimized out. + */ + +/* + fprintf (stderr, "OptimizeRegUsage: %s addr=0x%03x rIdx=0x%03x type=%d used=%d\n", + reg->name, + reg->address, + reg->rIdx, reg->type, used); +*/ + pc1 = setFirstItem(reg->reglives.usedpCodes); + pc2 = setNextItem(reg->reglives.usedpCodes); + + if(pcfl_used && pcfl_assigned) { + + /* + expected case - the register has been assigned a value and is + subsequently used + */ + + //fprintf(stderr," used only twice\n"); + if(pcfl_used->seq == pcfl_assigned->seq) { + + //fprintf(stderr, " and used in same flow\n"); + + pCodeOptime2pCodes(pc1, pc2, pcfl_used, reg, 1,optimize_level); + + } else { + // fprintf(stderr, " and used in different flows\n"); + + } + + } else if(pcfl_used) { + + /* + register has been used twice without ever being assigned */ + //fprintf(stderr,"WARNING %s: reg %s used without being assigned\n",__FUNCTION__,reg->name); + + } else { + //fprintf(stderr,"WARNING %s: reg %s assigned without being used\n",__FUNCTION__,reg->name); + Remove2pcodes(pcfl_assigned, pc1, pc2, reg, 1); + total_registers_saved++; // debugging stats. + } + } else { + + /* register has been used either once, or more than twice */ + + if(used && !pcfl_used && pcfl_assigned) { + pCode *pc; + + //fprintf(stderr,"WARNING %s: reg %s assigned without being used\n",__FUNCTION__,reg->name); + + pc = setFirstItem(reg->reglives.usedpCodes); + while(pc) { + + pcfl_assigned = PCODE(PCI(pc)->pcflow); + Remove1pcode(pc, reg); + + deleteSetItem (&(PCFL(pcfl_assigned)->registers), reg); + /* + deleteSetItem (&(reg->reglives.usedpCodes),pc); + pc->destruct(pc); + */ + pc = setNextItem(reg->reglives.usedpCodes); + } + + + reg->isFree = 1; + reg->wasUsed = 0; + + total_registers_saved++; // debugging stats. + } else if( (used > 2) && optimize_multi_uses) { + + set *rset1=NULL; + set *rset2=NULL; + int searching=1; + + pCodeFlow *pcfl1=NULL, *pcfl2=NULL; + + /* examine the number of times this register is used */ + + + rset1 = reg->reglives.usedpCodes; + while(rset1 && searching) { + + pc1 = rset1->item; + rset2 = rset1->next; + + if(pc1 && isPCI(pc1) && ( (pcfl1 = PCI(pc1)->pcflow) != NULL) ) { + + //while(rset2 && searching) { + if(rset2) { + + pc2 = rset2->item; + if(pc2 && isPCI(pc2) && ( (pcfl2 = PCI(pc2)->pcflow) != NULL) ) { + if(pcfl2 == pcfl1) { + + if(pCodeOptime2pCodes(pc1, pc2, pcfl_used, reg, 0,optimize_level)) + searching = 0; + } + } + + //rset2 = rset2->next; + + } + } + rset1 = rset1->next; + } + } + } + + } + +} +/*-----------------------------------------------------------------* + * void pic16_pCodeRegOptimeRegUsage(pBlock *pb) + *-----------------------------------------------------------------*/ +void pic16_pCodeRegOptimizeRegUsage(int level) +{ + + int passes; + int saved = 0; + int t = total_registers_saved; + + if(!register_optimization) + return; +#define OPT_PASSES 4 + passes = OPT_PASSES; + + do { + saved = total_registers_saved; + + /* Identify registers used in one flow sequence */ + OptimizeRegUsage(pic16_dynAllocRegs,level, (OPT_PASSES-passes)); + OptimizeRegUsage(pic16_dynStackRegs,level, (OPT_PASSES-passes)); + OptimizeRegUsage(pic16_dynDirectRegs,0, (OPT_PASSES-passes)); + + if(total_registers_saved != saved) + fprintf(stderr, " *** pass %d, Saved %d registers, total saved %d ***\n", + (1+OPT_PASSES-passes),total_registers_saved-saved,total_registers_saved); + + passes--; + + } while( passes && ((total_registers_saved != saved) || (passes==OPT_PASSES-1)) ); + + if(total_registers_saved == t) + fprintf(stderr, "No registers saved on this pass\n"); + + +/* + fprintf(stderr,"dynamically allocated regs:\n"); + dbg_regusage(pic16_dynAllocRegs); + fprintf(stderr,"stack regs:\n"); + dbg_regusage(pic16_dynStackRegs); + fprintf(stderr,"direct regs:\n"); + dbg_regusage(pic16_dynDirectRegs); +*/ +} + + +/*-----------------------------------------------------------------* + * void RegsUnMapLiveRanges(set *regset) + * + *-----------------------------------------------------------------*/ +static void RegsSetUnMapLiveRanges(set *regset) +{ + regs *reg; + + while(regset) { + reg = regset->item; + regset = regset->next; + + + deleteSet(®->reglives.usedpCodes); + deleteSet(®->reglives.usedpFlows); + deleteSet(®->reglives.assignedpFlows); + + } + +} + +void pic16_RegsUnMapLiveRanges(void) +{ + + RegsSetUnMapLiveRanges(pic16_dynAllocRegs); + RegsSetUnMapLiveRanges(pic16_dynStackRegs); + RegsSetUnMapLiveRanges(pic16_dynDirectRegs); + RegsSetUnMapLiveRanges(pic16_dynProcessorRegs); + RegsSetUnMapLiveRanges(pic16_dynDirectBitRegs); + RegsSetUnMapLiveRanges(pic16_dynInternalRegs); + +} diff --git a/src/pic16/pcoderegs.h b/src/pic16/pcoderegs.h new file mode 100644 index 00000000..c37d72f4 --- /dev/null +++ b/src/pic16/pcoderegs.h @@ -0,0 +1,42 @@ +/*------------------------------------------------------------------------- + + pcoderegs.h - post code generation register optimizations + + Written By - Scott Dattalo scott@dattalo.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. + +-------------------------------------------------------------------------*/ + +#ifndef __PCODEREGS_H__ +#define __PCODEREGS_H__ + +/************************************************* + + pCodeRegLives + + Records the set of registers used in a flow object. + +**************************************************/ + +typedef struct pCodeRegLives { + set *usedpFlows; /* set of pFlow objects that use this register */ + set *assignedpFlows; /* set of pFlow objects that assign values to this register */ + set *usedpCodes; /* set of all instructions that use this register */ + +} pCodeRegLives; + + +#endif // __PCODEREGS_H__ diff --git a/src/pic16/peeph.def b/src/pic16/peeph.def new file mode 100644 index 00000000..c0e7b81c --- /dev/null +++ b/src/pic16/peeph.def @@ -0,0 +1,285 @@ +// PIC Port Peep rules +// +// +// INTRODUCTION: +// +// The peep hole optimizer searchs the +// the SDCC generated code for small snippets +// that can be optimized. As a user, you have +// control over this optimization process without +// having to learn the SDCC source code. (However +// you'll still need access to the source since +// these rules are compiled into the source.) +// +// The way it works is you specify the target +// snippet that you want replaced with a more +// efficient snippet that you write. Wild card +// variables allow the rules to be parameterized. +// +// In all of the SDCC ports, labels and operands +// can be wild cards. However, in the PIC even the +// instructions can be wild cards. +// +// EXAMPLE: +// +// Consider Peep Rule 1 as an example. This rule +// replaces some code like: +// +// skpz ;i.e. btfss status,Z +// goto lab1 +// clrw +//lab1: +// +// with: +// +// skpnz ;i.e. btfsc status,Z +// clrw +//lab1 +// +// However, the Rule has four wild cards. +// The first allows the btfss instruction operator +// be anything, not just the Z bit in status register. +// The second wild card applies to a label. +// The third wild card is for an instruction - any +// single instruction can be substituted. +// The fourth wild card is also an instruction. It's +// just an instruction place holder associated with +// a label (think of it as the PIC Port author's laziness +// imposed upon the user). +// +// +// CONDITIONS +// +// There are certain instances where a peep rule may not +// be applicable. Consider this subtle example: +// +// movwf R0 +// movf R0,W +// +// It would seem that the second move is unnecessary. But +// be careful! The movf instruction affects the 'Z' bit. +// So if this sequence is followed by a btfsc status,Z, you +// will have to leave the second move in. +// +// To get around this proble, the peep rule can be followed +// by a conditon: "if NZ". Which is to say, apply the rule +// if Z bit is not needed in the code that follows. The optimizer +// is smart enough to look more than one instruction past the +// target block... +// +// Special commands +// +// +// _NOTBITSKIP_ %1 - Creates a wild card instruction that +// will match all instructions except for +// bit skip instructions (btfsc or btfss) +// _BITSKIP_ %1 - Creates a wild card instruction that only +// will match a bit skip instruction (btfsc +// or btfss) +// _INVERTBITSKIP_ %1 - For the wild card instruction %1, invert +// the state of the bit skip. If %1 is not +// a bit skip instruction, then there's an +// error in the peep rule. +// +// +// + + +// Peep 1 +// Converts +// +// btfss reg1,bit +// goto label +// incf reg2,f +//label +// +// Into: +// +// btfsc reg1,bit +// incf reg2,f +//label +// +// Notice that wild cards will allow any instruction +// besides incf to be used in the above. +// +// Also, notice that this snippet is not valid if +// it follows another skip + +replace restart { + _NOTBITSKIP_ %1 + _BITSKIP_ %2 + goto %3 + %4 +%3: %5 +} by { + ; peep 1 - test/jump to test/skip + %1 + _INVERTBITSKIP_ %2 + %4 +%3: %5 +} + +replace restart { + _NOTBITSKIP_ %1 + _BITSKIP_ %2 + goto %3 +%4: %5 +%3: %6 +} by { + ; peep 1b - test/jump to test/skip + %1 + _INVERTBITSKIP_ %2 +%4: %5 +%3: %6 +} + + +//bogus test for pcode +//replace restart { +// movf %1,w ;comment at end +//%4: movf %1,w +// RETURN +// clrf INDF0 +// movlw 0xa5 +// movf fsr0,w +// incf indf0,f +// %2 +//} by { +// ; peep test remove redundant move +//%4: movf %1,w ;another comment +// %2 +//} if AYBABTU %3 + + +// peep 2 +replace restart { + movwf %1 + movf %1,w +} by { + ; peep 2 - Removed redundant move + movwf %1 +} if NZ + +// peep 3 +replace restart { + decf %1,f + movf %1,w + btfss _STATUS,z + goto %2 +} by { + ; peep 3 - decf/mov/skpz to decfsz + decfsz %1,f + goto %2 +} + + +replace restart { + movf %1,w + movf %1,w +} by { + ; peep 4 - Removed redundant move + movf %1,w +} + + +replace restart { + movlw %1 + movwf %2 + movlw %1 +} by { + ; peep 5 - Removed redundant move + movlw %1 + movwf %2 +} + +replace restart { + movwf %1 + movwf %1 +} by { + ; peep 6 - Removed redundant move + movwf %1 +} + +replace restart { + movlw 0 + iorwf %1,w +} by { + ; peep 7 - Removed redundant move + movf %1,w +} + +replace restart { + movf %1,w + movwf %2 + decf %2,f +} by { + ; peep 8 - Removed redundant move + decf %1,w + movwf %2 +} + +replace restart { + movwf %1 + movf %2,w + xorwf %1,w +} by { + ; peep 9a - Removed redundant move + movwf %1 + xorwf %2,w +} + +replace restart { + movwf %1 + movf %2,w + iorwf %1,w +} by { + ; peep 9b - Removed redundant move + movwf %1 + iorwf %2,w +} + +replace restart { + movf %1,w + movwf %2 + movf %2,w +} by { + ; peep 9c - Removed redundant move + movf %1,w + movwf %2 +} + +replace restart { + movwf %1 + movf %1,w + movwf %2 +} by { + ; peep 9d - Removed redundant move + movwf %1 + movwf %2 +} if NZ + +// From: Frieder Ferlemann + +replace restart { + iorlw 0 +} by { + ; peep 10a - Removed unnecessary iorlw +} if NZ + +// From: Frieder Ferlemann + +replace restart { + xorlw 0 +} by { + ; peep 10b - Removed unnecessary xorlw +} if NZ + +// From: Frieder Ferlemann + +replace restart { + movf %1,w + movwf %1 +} by { + ; peep 11 - Removed redundant move + movf %1,w +} diff --git a/src/pic16/pic.dsp b/src/pic16/pic.dsp new file mode 100644 index 00000000..7de9799f --- /dev/null +++ b/src/pic16/pic.dsp @@ -0,0 +1,164 @@ +# Microsoft Developer Studio Project File - Name="pic" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=pic - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "pic.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "pic.mak" CFG="pic - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "pic - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "pic - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "pic - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MLd /W3 /Gm /GX /ZI /Od /I ".." /I "." /I "..\.." /I "..\..\support\util" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR /FD /GZ /Zm500 /c +# ADD CPP /nologo /MLd /W3 /Gm /GX /ZI /Od /I ".." /I "." /I "..\.." /I "..\..\support\util" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR /FD /GZ /Zm500 /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"Debug\port.lib" +# ADD LIB32 /nologo /out:"Debug\port.lib" + +!ELSEIF "$(CFG)" == "pic - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /ML /W3 /GX /O2 /I ".." /I "." /I "..\.." /I "..\..\support\util" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FD /Zm500 /c +# ADD CPP /nologo /ML /W3 /GX /O2 /I ".." /I "." /I "..\.." /I "..\..\support\util" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FD /Zm500 /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo /out:"Release\port.lib" +# ADD LIB32 /nologo /out:"Release\port.lib" + +!ENDIF + +# Begin Target + +# Name "pic - Win32 Debug" +# Name "pic - Win32 Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\device.c +# End Source File +# Begin Source File + +SOURCE=.\gen.c +# End Source File +# Begin Source File + +SOURCE=.\genarith.c +# End Source File +# Begin Source File + +SOURCE=.\glue.c +# End Source File +# Begin Source File + +SOURCE=.\main.c +# End Source File +# Begin Source File + +SOURCE=.\pcode.c +# End Source File +# Begin Source File + +SOURCE=.\pcodeflow.c +# End Source File +# Begin Source File + +SOURCE=.\pcodepeep.c +# End Source File +# Begin Source File + +SOURCE=.\pcoderegs.c +# End Source File +# Begin Source File + +SOURCE=.\ralloc.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\device.h +# End Source File +# Begin Source File + +SOURCE=.\gen.h +# End Source File +# Begin Source File + +SOURCE=.\glue.h +# End Source File +# Begin Source File + +SOURCE=.\main.h +# End Source File +# Begin Source File + +SOURCE=.\pcode.h +# End Source File +# Begin Source File + +SOURCE=.\pcodeflow.h +# End Source File +# Begin Source File + +SOURCE=.\pcoderegs.h +# End Source File +# Begin Source File + +SOURCE=.\ralloc.h +# End Source File +# End Group +# End Target +# End Project diff --git a/src/pic16/pica.dsp b/src/pic16/pica.dsp new file mode 100644 index 00000000..ec9c196f --- /dev/null +++ b/src/pic16/pica.dsp @@ -0,0 +1,90 @@ +# Microsoft Developer Studio Project File - Name="pica" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Generic Project" 0x010a + +CFG=pica - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "pica.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "pica.mak" CFG="pica - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "pica - Win32 Debug" (based on "Win32 (x86) Generic Project") +!MESSAGE "pica - Win32 Release" (based on "Win32 (x86) Generic Project") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +MTL=midl.exe + +!IF "$(CFG)" == "pica - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "" +# PROP Intermediate_Dir "" +# PROP Target_Dir "" + +!ELSEIF "$(CFG)" == "pica - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "" +# PROP Intermediate_Dir "" +# PROP Target_Dir "" + +!ENDIF + +# Begin Target + +# Name "pica - Win32 Debug" +# Name "pica - Win32 Release" +# Begin Source File + +SOURCE=.\peeph.def + +!IF "$(CFG)" == "pica - Win32 Debug" + +# Begin Custom Build +InputPath=.\peeph.def + +"peeph.rul" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + gawk -f ../SDCCpeeph.awk $(InputPath) >peeph.rul + +# End Custom Build + +!ELSEIF "$(CFG)" == "pica - Win32 Release" + +# Begin Custom Build +InputPath=.\peeph.def + +"peeph.rul" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + gawk -f ../SDCCpeeph.awk $(InputPath) >peeph.rul + +# End Custom Build + +!ENDIF + +# End Source File +# End Target +# End Project diff --git a/src/pic16/ralloc.c b/src/pic16/ralloc.c new file mode 100644 index 00000000..638647fe --- /dev/null +++ b/src/pic16/ralloc.c @@ -0,0 +1,3882 @@ +/*------------------------------------------------------------------------ + + SDCCralloc.c - source file for register allocation. (8051) specific + + Written By - Sandeep Dutta . sandeep.dutta@usa.net (1998) + Added Pic Port T.scott Dattalo scott@dattalo.com (2000) + Added Pic16 Port Martin Dubuc m.dubuc@rogers.com (2002) + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! +-------------------------------------------------------------------------*/ + +#include "common.h" +#include "ralloc.h" +#include "pcode.h" +#include "gen.h" + +#if defined(__BORLANDC__) || defined(_MSC_VER) +#define STRCASECMP stricmp +#else +#define STRCASECMP strcasecmp +#endif + +/*-----------------------------------------------------------------*/ +/* At this point we start getting processor specific although */ +/* some routines are non-processor specific & can be reused when */ +/* targetting other processors. The decision for this will have */ +/* to be made on a routine by routine basis */ +/* routines used to pack registers are most definitely not reusable */ +/* since the pack the registers depending strictly on the MCU */ +/*-----------------------------------------------------------------*/ + +static regs *typeRegWithIdx (int idx, int type, int fixed); +extern void genpic16Code (iCode *); +extern void pic16_assignConfigWordValue(int address, int value); + +/* Global data */ +static struct + { + bitVect *spiltSet; + set *stackSpil; + bitVect *regAssigned; + short blockSpil; + int slocNum; + bitVect *funcrUsed; /* registers used in a function */ + int stackExtend; + int dataExtend; + } +_G; + +/* Shared with gen.c */ +int pic16_ptrRegReq; /* one byte pointer register required */ + + +set *pic16_dynAllocRegs=NULL; +set *pic16_dynStackRegs=NULL; +set *pic16_dynProcessorRegs=NULL; +set *pic16_dynDirectRegs=NULL; +set *pic16_dynDirectBitRegs=NULL; +set *pic16_dynInternalRegs=NULL; + +static hTab *dynDirectRegNames= NULL; +static hTab *regHash = NULL; /* a hash table containing ALL registers */ + +static int dynrIdx=0x20; +static int rDirectIdx=0; + +int pic16_nRegs = 128; // = sizeof (regspic16) / sizeof (regs); + +int pic16_Gstack_base_addr=0; /* The starting address of registers that + * are used to pass and return parameters */ + + + + +static void spillThis (symbol *); +static int debug = 1; +static FILE *debugF = NULL; +/*-----------------------------------------------------------------*/ +/* debugLog - open a file for debugging information */ +/*-----------------------------------------------------------------*/ +//static void debugLog(char *inst,char *fmt, ...) +static void +debugLog (char *fmt,...) +{ + static int append = 0; // First time through, open the file without append. + + char buffer[256]; + //char *bufferP=buffer; + va_list ap; + + if (!debug || !srcFileName) + return; + + + if (!debugF) + { + /* create the file name */ + strcpy (buffer, srcFileName); + strcat (buffer, ".d"); + + if (!(debugF = fopen (buffer, (append ? "a+" : "w")))) + { + werror (E_FILE_OPEN_ERR, buffer); + exit (1); + } + append = 1; // Next time debubLog is called, we'll append the debug info + + } + + va_start (ap, fmt); + + vsprintf (buffer, fmt, ap); + + fprintf (debugF, "%s", buffer); +/* + while (isspace(*bufferP)) bufferP++; + + if (bufferP && *bufferP) + lineCurr = (lineCurr ? + connectLine(lineCurr,newLineNode(lb)) : + (lineHead = newLineNode(lb))); + lineCurr->isInline = _G.inLine; + lineCurr->isDebug = _G.debugLine; + */ + va_end (ap); + +} + +static void +debugNewLine (void) +{ + if (debugF) + fputc ('\n', debugF); +} +/*-----------------------------------------------------------------*/ +/* debugLogClose - closes the debug log file (if opened) */ +/*-----------------------------------------------------------------*/ +static void +debugLogClose (void) +{ + if (debugF) + { + fclose (debugF); + debugF = NULL; + } +} +#define AOP(op) op->aop + +static char * +debugAopGet (char *str, operand * op) +{ + if (str) + debugLog (str); + + printOperand (op, debugF); + debugNewLine (); + + return NULL; + +} + +static char * +decodeOp (unsigned int op) +{ + + if (op < 128 && op > ' ') + { + buffer[0] = (op & 0xff); + buffer[1] = 0; + return buffer; + } + + switch (op) + { + case IDENTIFIER: + return "IDENTIFIER"; + case TYPE_NAME: + return "TYPE_NAME"; + case CONSTANT: + return "CONSTANT"; + case STRING_LITERAL: + return "STRING_LITERAL"; + case SIZEOF: + return "SIZEOF"; + case PTR_OP: + return "PTR_OP"; + case INC_OP: + return "INC_OP"; + case DEC_OP: + return "DEC_OP"; + case LEFT_OP: + return "LEFT_OP"; + case RIGHT_OP: + return "RIGHT_OP"; + case LE_OP: + return "LE_OP"; + case GE_OP: + return "GE_OP"; + case EQ_OP: + return "EQ_OP"; + case NE_OP: + return "NE_OP"; + case AND_OP: + return "AND_OP"; + case OR_OP: + return "OR_OP"; + case MUL_ASSIGN: + return "MUL_ASSIGN"; + case DIV_ASSIGN: + return "DIV_ASSIGN"; + case MOD_ASSIGN: + return "MOD_ASSIGN"; + case ADD_ASSIGN: + return "ADD_ASSIGN"; + case SUB_ASSIGN: + return "SUB_ASSIGN"; + case LEFT_ASSIGN: + return "LEFT_ASSIGN"; + case RIGHT_ASSIGN: + return "RIGHT_ASSIGN"; + case AND_ASSIGN: + return "AND_ASSIGN"; + case XOR_ASSIGN: + return "XOR_ASSIGN"; + case OR_ASSIGN: + return "OR_ASSIGN"; + case TYPEDEF: + return "TYPEDEF"; + case EXTERN: + return "EXTERN"; + case STATIC: + return "STATIC"; + case AUTO: + return "AUTO"; + case REGISTER: + return "REGISTER"; + case CODE: + return "CODE"; + case EEPROM: + return "EEPROM"; + case INTERRUPT: + return "INTERRUPT"; + case SFR: + return "SFR"; + case AT: + return "AT"; + case SBIT: + return "SBIT"; + case REENTRANT: + return "REENTRANT"; + case USING: + return "USING"; + case XDATA: + return "XDATA"; + case DATA: + return "DATA"; + case IDATA: + return "IDATA"; + case PDATA: + return "PDATA"; + case VAR_ARGS: + return "VAR_ARGS"; + case CRITICAL: + return "CRITICAL"; + case NONBANKED: + return "NONBANKED"; + case BANKED: + return "BANKED"; + case CHAR: + return "CHAR"; + case SHORT: + return "SHORT"; + case INT: + return "INT"; + case LONG: + return "LONG"; + case SIGNED: + return "SIGNED"; + case UNSIGNED: + return "UNSIGNED"; + case FLOAT: + return "FLOAT"; + case DOUBLE: + return "DOUBLE"; + case CONST: + return "CONST"; + case VOLATILE: + return "VOLATILE"; + case VOID: + return "VOID"; + case BIT: + return "BIT"; + case STRUCT: + return "STRUCT"; + case UNION: + return "UNION"; + case ENUM: + return "ENUM"; + case ELIPSIS: + return "ELIPSIS"; + case RANGE: + return "RANGE"; + case FAR: + return "FAR"; + case CASE: + return "CASE"; + case DEFAULT: + return "DEFAULT"; + case IF: + return "IF"; + case ELSE: + return "ELSE"; + case SWITCH: + return "SWITCH"; + case WHILE: + return "WHILE"; + case DO: + return "DO"; + case FOR: + return "FOR"; + case GOTO: + return "GOTO"; + case CONTINUE: + return "CONTINUE"; + case BREAK: + return "BREAK"; + case RETURN: + return "RETURN"; + case INLINEASM: + return "INLINEASM"; + case IFX: + return "IFX"; + case ADDRESS_OF: + return "ADDRESS_OF"; + case GET_VALUE_AT_ADDRESS: + return "GET_VALUE_AT_ADDRESS"; + case SPIL: + return "SPIL"; + case UNSPIL: + return "UNSPIL"; + case GETHBIT: + return "GETHBIT"; + case BITWISEAND: + return "BITWISEAND"; + case UNARYMINUS: + return "UNARYMINUS"; + case IPUSH: + return "IPUSH"; + case IPOP: + return "IPOP"; + case PCALL: + return "PCALL"; + case ENDFUNCTION: + return "ENDFUNCTION"; + case JUMPTABLE: + return "JUMPTABLE"; + case RRC: + return "RRC"; + case RLC: + return "RLC"; + case CAST: + return "CAST"; + case CALL: + return "CALL"; + case PARAM: + return "PARAM "; + case NULLOP: + return "NULLOP"; + case BLOCK: + return "BLOCK"; + case LABEL: + return "LABEL"; + case RECEIVE: + return "RECEIVE"; + case SEND: + return "SEND"; + } + sprintf (buffer, "unkown op %d %c", op, op & 0xff); + return buffer; +} +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +static char * +debugLogRegType (short type) +{ + + switch (type) + { + case REG_GPR: + return "REG_GPR"; + case REG_PTR: + return "REG_PTR"; + case REG_CND: + return "REG_CND"; + } + + sprintf (buffer, "unknown reg type %d", type); + return buffer; +} + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +static int regname2key(char const *name) +{ + int key = 0; + + if(!name) + return 0; + + while(*name) { + + key += (*name++) + 1; + + } + + return ( (key + (key >> 4) + (key>>8)) & 0x3f); + +} + +/*-----------------------------------------------------------------*/ +/* newReg - allocate and init memory for a new register */ +/*-----------------------------------------------------------------*/ +static regs* newReg(short type, short pc_type, int rIdx, char *name, int size, int alias) +{ + + regs *dReg; + + dReg = Safe_calloc(1,sizeof(regs)); + dReg->type = type; + dReg->pc_type = pc_type; + dReg->rIdx = rIdx; + if(name) + dReg->name = Safe_strdup(name); + else { + sprintf(buffer,"r0x%02X", dReg->rIdx); + if(type == REG_STK) + *buffer = 's'; + dReg->name = Safe_strdup(buffer); + } + //fprintf(stderr,"newReg: %s, rIdx = 0x%02x\n",dReg->name,rIdx); + dReg->isFree = 0; + dReg->wasUsed = 1; + if(type == REG_SFR) + dReg->isFixed = 1; + else + dReg->isFixed = 0; + + dReg->isMapped = 0; + dReg->isEmitted = 0; + dReg->address = 0; + dReg->size = size; + dReg->alias = alias; + dReg->reg_alias = NULL; + dReg->reglives.usedpFlows = newSet(); + dReg->reglives.assignedpFlows = newSet(); + + hTabAddItem(&dynDirectRegNames, regname2key(name), dReg); + + return dReg; +} + +/*-----------------------------------------------------------------*/ +/* regWithIdx - Search through a set of registers that matches idx */ +/*-----------------------------------------------------------------*/ +static regs * +regWithIdx (set *dRegs, int idx, int fixed) +{ + regs *dReg; + + for (dReg = setFirstItem(dRegs) ; dReg ; + dReg = setNextItem(dRegs)) { + + if(idx == dReg->rIdx && (fixed == dReg->isFixed)) { + return dReg; + } + } + + return NULL; +} + +/*-----------------------------------------------------------------*/ +/* regFindFree - Search for a free register in a set of registers */ +/*-----------------------------------------------------------------*/ +static regs * +regFindFree (set *dRegs) +{ + regs *dReg; + + for (dReg = setFirstItem(dRegs) ; dReg ; + dReg = setNextItem(dRegs)) { + + if(dReg->isFree) + return dReg; + } + + return NULL; +} +/*-----------------------------------------------------------------*/ +/* pic16_initStack - allocate registers for a pseudo stack */ +/*-----------------------------------------------------------------*/ +void pic16_initStack(int base_address, int size) +{ + + int i; + + pic16_Gstack_base_addr = base_address; + //fprintf(stderr,"initStack"); + + for(i = 0; iwasUsed = 0; + return addSet(&pic16_dynInternalRegs,reg); + } + + return NULL; +} +/*-----------------------------------------------------------------*/ +/* allocReg - allocates register of given type */ +/*-----------------------------------------------------------------*/ +static regs * +allocReg (short type) +{ + + debugLog ("%s of type %s\n", __FUNCTION__, debugLogRegType (type)); + //fprintf(stderr,"allocReg\n"); + + + return addSet(&pic16_dynAllocRegs,newReg(REG_GPR, PO_GPR_TEMP,dynrIdx++,NULL,1,0)); + +} + + +/*-----------------------------------------------------------------*/ +/* pic16_dirregWithName - search for register by name */ +/*-----------------------------------------------------------------*/ +regs * +pic16_dirregWithName (char *name) +{ + int hkey; + regs *reg; + + if(!name) + return NULL; + + /* hash the name to get a key */ + + hkey = regname2key(name); + + reg = hTabFirstItemWK(dynDirectRegNames, hkey); + + while(reg) { + + if(STRCASECMP(reg->name, name) == 0) { + return(reg); + } + + reg = hTabNextItemWK (dynDirectRegNames); + + } + + return NULL; // name wasn't found in the hash table +} + +static int IS_CONFIG_ADDRESS(int address) +{ + + return address >= 0x300000 && address <= 0x300000d; +} + +/*-----------------------------------------------------------------*/ +/* pic16_allocDirReg - allocates register of given type */ +/*-----------------------------------------------------------------*/ +regs * +pic16_allocDirReg (operand *op ) +{ + + regs *reg; + char *name; + + if(!IS_SYMOP(op)) { + debugLog ("%s BAD, op is NULL\n", __FUNCTION__); + return NULL; + } + + name = OP_SYMBOL (op)->rname[0] ? OP_SYMBOL (op)->rname : OP_SYMBOL (op)->name; + + /* If the symbol is at a fixed address, then remove the leading underscore + * from the name. This is hack to allow the .asm include file named registers + * to match the .c declared register names */ + + //if (SPEC_ABSA ( OP_SYM_ETYPE(op)) && (*name == '_')) + //name++; + + debugLog ("%s symbol name %s\n", __FUNCTION__,name); + { + if(SPEC_CONST ( OP_SYM_ETYPE(op)) && (IS_CHAR ( OP_SYM_ETYPE(op)) )) { + debugLog(" %d const char\n",__LINE__); + debugLog(" value = %s \n",SPEC_CVAL( OP_SYM_ETYPE(op))); + } + + debugLog(" %d storage class %d \n",__LINE__,SPEC_SCLS( OP_SYM_ETYPE(op))); + if (IS_CODE ( OP_SYM_ETYPE(op)) ) + debugLog(" %d code space\n",__LINE__); + + if (IS_INTEGRAL ( OP_SYM_ETYPE(op)) ) + debugLog(" %d integral\n",__LINE__); + if (IS_LITERAL ( OP_SYM_ETYPE(op)) ) + debugLog(" %d literal\n",__LINE__); + if (IS_SPEC ( OP_SYM_ETYPE(op)) ) + debugLog(" %d specifier\n",__LINE__); + debugAopGet(NULL, op); + } + + if (IS_CODE ( OP_SYM_ETYPE(op)) ) + return NULL; + + /* First, search the hash table to see if there is a register with this name */ + if (SPEC_ABSA ( OP_SYM_ETYPE(op)) && !(IS_BITVAR (OP_SYM_ETYPE(op))) ) { + reg = regWithIdx (pic16_dynProcessorRegs, SPEC_ADDR ( OP_SYM_ETYPE(op)), 1); +/* + if(!reg) + fprintf(stderr,"ralloc %s is at fixed address but not a processor reg, addr=0x%x\n", + name, SPEC_ADDR ( OP_SYM_ETYPE(op))); + else + fprintf(stderr,"ralloc %s at fixed address has already been declared, addr=0x%x\n", + name, SPEC_ADDR ( OP_SYM_ETYPE(op))); +*/ + } else { + //fprintf(stderr,"ralloc:%d %s \n", __LINE__,name); + + reg = pic16_dirregWithName(name); + } + + if(!reg) { + int address = 0; + + /* if this is at an absolute address, then get the address. */ + if (SPEC_ABSA ( OP_SYM_ETYPE(op)) ) { + address = SPEC_ADDR ( OP_SYM_ETYPE(op)); + //fprintf(stderr,"reg %s is at an absolute address: 0x%03x\n",name,address); + } + + /* Register wasn't found in hash, so let's create + * a new one and put it in the hash table AND in the + * dynDirectRegNames set */ + if(!IS_CONFIG_ADDRESS(address)) { + //fprintf(stderr,"allocating new reg %s\n",name); + + reg = newReg(REG_GPR, PO_DIR, rDirectIdx++, name,getSize (OP_SYMBOL (op)->type),0 ); + debugLog (" -- added %s to hash, size = %d\n", name,reg->size); + + //hTabAddItem(&dynDirectRegNames, regname2key(name), reg); + + if (SPEC_ABSA ( OP_SYM_ETYPE(op)) ) { + + //fprintf(stderr, " ralloc.c at fixed address: %s - changing to REG_SFR\n",name); + reg->type = REG_SFR; + } + + if (IS_BITVAR (OP_SYM_ETYPE(op))) { + addSet(&pic16_dynDirectBitRegs, reg); + reg->isBitField = 1; + } else + addSet(&pic16_dynDirectRegs, reg); + + } else { + debugLog (" -- %s is declared at address 0x30000x\n",name); + + } + } + + if (SPEC_ABSA ( OP_SYM_ETYPE(op)) ) { + reg->isFixed = 1; + reg->address = SPEC_ADDR ( OP_SYM_ETYPE(op)); + debugLog (" -- and it is at a fixed address 0x%02x\n",reg->address); + } + + return reg; +} + +/*-----------------------------------------------------------------*/ +/* pic16_allocRegByName - allocates register of given type */ +/*-----------------------------------------------------------------*/ +regs * +pic16_allocRegByName (char *name, int size) +{ + + regs *reg; + + if(!name) { + fprintf(stderr, "%s - allocating a NULL register\n",__FUNCTION__); + exit(1); + } + + /* First, search the hash table to see if there is a register with this name */ + reg = pic16_dirregWithName(name); + + if(!reg) { + + /* Register wasn't found in hash, so let's create + * a new one and put it in the hash table AND in the + * dynDirectRegNames set */ + //fprintf (stderr,"%s symbol name %s\n", __FUNCTION__,name); + reg = newReg(REG_GPR, PO_DIR, rDirectIdx++, name,size,0 ); + + debugLog (" -- added %s to hash, size = %d\n", name,reg->size); + + //hTabAddItem(&dynDirectRegNames, regname2key(name), reg); + addSet(&pic16_dynDirectRegs, reg); + } + + return reg; +} + +/*-----------------------------------------------------------------*/ +/* RegWithIdx - returns pointer to register with index number */ +/*-----------------------------------------------------------------*/ +static regs * +typeRegWithIdx (int idx, int type, int fixed) +{ + + regs *dReg; + + debugLog ("%s - requesting index = 0x%x\n", __FUNCTION__,idx); + + switch (type) { + + case REG_GPR: + if( (dReg = regWithIdx ( pic16_dynAllocRegs, idx, fixed)) != NULL) { + + debugLog ("Found a Dynamic Register!\n"); + return dReg; + } + if( (dReg = regWithIdx ( pic16_dynDirectRegs, idx, fixed)) != NULL ) { + debugLog ("Found a Direct Register!\n"); + return dReg; + } + + break; + case REG_STK: + if( (dReg = regWithIdx ( pic16_dynStackRegs, idx, fixed)) != NULL ) { + debugLog ("Found a Stack Register!\n"); + return dReg; + } + break; + case REG_SFR: + if( (dReg = regWithIdx ( pic16_dynProcessorRegs, idx, fixed)) != NULL ) { + debugLog ("Found a Processor Register!\n"); + return dReg; + } + + case REG_CND: + case REG_PTR: + default: + break; + } + + + return NULL; +} + +/*-----------------------------------------------------------------*/ +/* pic16_regWithIdx - returns pointer to register with index number*/ +/*-----------------------------------------------------------------*/ +regs * +pic16_regWithIdx (int idx) +{ + regs *dReg; + + if( (dReg = typeRegWithIdx(idx,REG_GPR,0)) != NULL) + return dReg; + + if( (dReg = typeRegWithIdx(idx,REG_SFR,0)) != NULL) + return dReg; + + if( (dReg = typeRegWithIdx(idx,REG_STK,0)) != NULL) + return dReg; + + return NULL; +} + +/*-----------------------------------------------------------------*/ +/* pic16_regWithIdx - returns pointer to register with index number */ +/*-----------------------------------------------------------------*/ +regs * +pic16_allocWithIdx (int idx) +{ + + regs *dReg; + + debugLog ("%s - allocating with index = 0x%x\n", __FUNCTION__,idx); + + if( (dReg = regWithIdx ( pic16_dynAllocRegs, idx,0)) != NULL) { + + debugLog ("Found a Dynamic Register!\n"); + } else if( (dReg = regWithIdx ( pic16_dynStackRegs, idx,0)) != NULL ) { + debugLog ("Found a Stack Register!\n"); + } else if( (dReg = regWithIdx ( pic16_dynProcessorRegs, idx,0)) != NULL ) { + debugLog ("Found a Processor Register!\n"); + } else if( (dReg = regWithIdx ( pic16_dynInternalRegs, idx,0)) != NULL ) { + debugLog ("Found an Internal Register!\n"); + } else { + + debugLog ("Dynamic Register not found\n"); + + + //fprintf(stderr,"%s %d - requested register: 0x%x\n",__FUNCTION__,__LINE__,idx); + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, + "regWithIdx not found"); + exit (1); + + } + + dReg->wasUsed = 1; + dReg->isFree = 0; + + return dReg; +} +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +regs * +pic16_findFreeReg(short type) +{ + // int i; + regs* dReg; + + switch (type) { + case REG_GPR: + if((dReg = regFindFree(pic16_dynAllocRegs)) != NULL) + return dReg; + return addSet(&pic16_dynAllocRegs,newReg(REG_GPR, PO_GPR_TEMP,dynrIdx++,NULL,1,0)); + + case REG_STK: + + if((dReg = regFindFree(pic16_dynStackRegs)) != NULL) + return dReg; + + return NULL; + + case REG_PTR: + case REG_CND: + case REG_SFR: + default: + return NULL; + } +} +/*-----------------------------------------------------------------*/ +/* freeReg - frees a register */ +/*-----------------------------------------------------------------*/ +static void +freeReg (regs * reg) +{ + debugLog ("%s\n", __FUNCTION__); + reg->isFree = 1; +} + + +/*-----------------------------------------------------------------*/ +/* nFreeRegs - returns number of free registers */ +/*-----------------------------------------------------------------*/ +static int +nFreeRegs (int type) +{ + /* dynamically allocate as many as we need and worry about + * fitting them into a PIC later */ + + return 100; +#if 0 + int i; + int nfr = 0; + + debugLog ("%s\n", __FUNCTION__); + for (i = 0; i < pic16_nRegs; i++) + if (regspic16[i].isFree && regspic16[i].type == type) + nfr++; + return nfr; +#endif +} + +/*-----------------------------------------------------------------*/ +/* nfreeRegsType - free registers with type */ +/*-----------------------------------------------------------------*/ +static int +nfreeRegsType (int type) +{ + int nfr; + debugLog ("%s\n", __FUNCTION__); + if (type == REG_PTR) + { + if ((nfr = nFreeRegs (type)) == 0) + return nFreeRegs (REG_GPR); + } + + return nFreeRegs (type); +} + +static void writeSetUsedRegs(FILE *of, set *dRegs) +{ + + regs *dReg; + + for (dReg = setFirstItem(dRegs) ; dReg ; + dReg = setNextItem(dRegs)) { + + if(dReg->wasUsed) + fprintf (of, "\t%s\n",dReg->name); + } + +} +extern void pic16_assignFixedRegisters(set *regset); +extern void pic16_assignRelocatableRegisters(set *regset,int used); +extern void pic16_dump_map(void); +extern void pic16_dump_cblock(FILE *of); + + +static void packBits(set *bregs) +{ + set *regset; + regs *breg; + regs *bitfield=NULL; + regs *relocbitfield=NULL; + int bit_no=0; + int byte_no=-1; + char buffer[20]; + + + for (regset = bregs ; regset ; + regset = regset->next) { + + breg = regset->item; + breg->isBitField = 1; + //fprintf(stderr,"bit reg: %s\n",breg->name); + + if(breg->isFixed) { + //fprintf(stderr,"packing bit at fixed address = 0x%03x\n",breg->address); + + bitfield = typeRegWithIdx (breg->address >> 3, -1 , 1); + breg->rIdx = breg->address & 7; + breg->address >>= 3; + + if(!bitfield) { + sprintf (buffer, "fbitfield%02x", breg->address); + //fprintf(stderr,"new bit field\n"); + bitfield = newReg(REG_SFR, PO_GPR_BIT,breg->address,buffer,1,0); + bitfield->isBitField = 1; + bitfield->isFixed = 1; + bitfield->address = breg->address; + addSet(&pic16_dynDirectRegs,bitfield); + //hTabAddItem(&dynDirectRegNames, regname2key(buffer), bitfield); + } else { + //fprintf(stderr," which is occupied by %s (addr = %d)\n",bitfield->name,bitfield->address); + ; + } + breg->reg_alias = bitfield; + bitfield = NULL; + + } else { + if(!relocbitfield || bit_no >7) { + byte_no++; + bit_no=0; + sprintf (buffer, "bitfield%d", byte_no); + //fprintf(stderr,"new relocatable bit field\n"); + relocbitfield = newReg(REG_GPR, PO_GPR_BIT,rDirectIdx++,buffer,1,0); + relocbitfield->isBitField = 1; + addSet(&pic16_dynDirectRegs,relocbitfield); + //hTabAddItem(&dynDirectRegNames, regname2key(buffer), relocbitfield); + + } + + breg->reg_alias = relocbitfield; + breg->address = rDirectIdx; /* byte_no; */ + breg->rIdx = bit_no++; + } + } + +} + + + +static void bitEQUs(FILE *of, set *bregs) +{ + regs *breg,*bytereg; + int bit_no=0; + + //fprintf(stderr," %s\n",__FUNCTION__); + for (breg = setFirstItem(bregs) ; breg ; + breg = setNextItem(bregs)) { + + //fprintf(stderr,"bit reg: %s\n",breg->name); + + bytereg = breg->reg_alias; + if(bytereg) + fprintf (of, "%s\tEQU\t( (%s<<3)+%d)\n", + breg->name, + bytereg->name, + breg->rIdx & 0x0007); + + else { + fprintf(stderr, "bit field is not assigned to a register\n"); + fprintf (of, "%s\tEQU\t( (bitfield%d<<3)+%d)\n", + breg->name, + bit_no>>3, + bit_no & 0x0007); + + bit_no++; + } + } + +} + +static void aliasEQUs(FILE *of, set *fregs, int use_rIdx) +{ + regs *reg; + + + for (reg = setFirstItem(fregs) ; reg ; + reg = setNextItem(fregs)) { + + if(!reg->isEmitted && reg->wasUsed) { + if(use_rIdx) { + if (reg->type != REG_SFR) { + fprintf (of, "%s\tEQU\t0x%03x\n", + reg->name, + reg->rIdx); + } + } + else + fprintf (of, "%s\tEQU\t0x%03x\n", + reg->name, + reg->address); + } + } + +} + +void pic16_writeUsedRegs(FILE *of) +{ + packBits(pic16_dynDirectBitRegs); + + + pic16_assignFixedRegisters(pic16_dynAllocRegs); + pic16_assignFixedRegisters(pic16_dynStackRegs); + pic16_assignFixedRegisters(pic16_dynDirectRegs); + + pic16_assignRelocatableRegisters(pic16_dynInternalRegs,0); + pic16_assignRelocatableRegisters(pic16_dynAllocRegs,0); + pic16_assignRelocatableRegisters(pic16_dynStackRegs,0); + pic16_assignRelocatableRegisters(pic16_dynDirectRegs,0); + + //pic16_dump_map(); + + pic16_dump_cblock(of); + bitEQUs(of,pic16_dynDirectBitRegs); + aliasEQUs(of,pic16_dynAllocRegs,0); + aliasEQUs(of,pic16_dynDirectRegs,0); + aliasEQUs(of,pic16_dynStackRegs,0); + aliasEQUs(of,pic16_dynProcessorRegs,1); + +} + +#if 0 +/*-----------------------------------------------------------------*/ +/* allDefsOutOfRange - all definitions are out of a range */ +/*-----------------------------------------------------------------*/ +static bool +allDefsOutOfRange (bitVect * defs, int fseq, int toseq) +{ + int i; + + debugLog ("%s\n", __FUNCTION__); + if (!defs) + return TRUE; + + for (i = 0; i < defs->size; i++) + { + iCode *ic; + + if (bitVectBitValue (defs, i) && + (ic = hTabItemWithKey (iCodehTab, i)) && + (ic->seq >= fseq && ic->seq <= toseq)) + + return FALSE; + + } + + return TRUE; +} +#endif + +/*-----------------------------------------------------------------*/ +/* computeSpillable - given a point find the spillable live ranges */ +/*-----------------------------------------------------------------*/ +static bitVect * +computeSpillable (iCode * ic) +{ + bitVect *spillable; + + debugLog ("%s\n", __FUNCTION__); + /* spillable live ranges are those that are live at this + point . the following categories need to be subtracted + from this set. + a) - those that are already spilt + b) - if being used by this one + c) - defined by this one */ + + spillable = bitVectCopy (ic->rlive); + spillable = + bitVectCplAnd (spillable, _G.spiltSet); /* those already spilt */ + spillable = + bitVectCplAnd (spillable, ic->uses); /* used in this one */ + bitVectUnSetBit (spillable, ic->defKey); + spillable = bitVectIntersect (spillable, _G.regAssigned); + return spillable; + +} + +/*-----------------------------------------------------------------*/ +/* noSpilLoc - return true if a variable has no spil location */ +/*-----------------------------------------------------------------*/ +static int +noSpilLoc (symbol * sym, eBBlock * ebp, iCode * ic) +{ + debugLog ("%s\n", __FUNCTION__); + return (sym->usl.spillLoc ? 0 : 1); +} + +/*-----------------------------------------------------------------*/ +/* hasSpilLoc - will return 1 if the symbol has spil location */ +/*-----------------------------------------------------------------*/ +static int +hasSpilLoc (symbol * sym, eBBlock * ebp, iCode * ic) +{ + debugLog ("%s\n", __FUNCTION__); + return (sym->usl.spillLoc ? 1 : 0); +} + +/*-----------------------------------------------------------------*/ +/* directSpilLoc - will return 1 if the splilocation is in direct */ +/*-----------------------------------------------------------------*/ +static int +directSpilLoc (symbol * sym, eBBlock * ebp, iCode * ic) +{ + debugLog ("%s\n", __FUNCTION__); + if (sym->usl.spillLoc && + (IN_DIRSPACE (SPEC_OCLS (sym->usl.spillLoc->etype)))) + return 1; + else + return 0; +} + +/*-----------------------------------------------------------------*/ +/* hasSpilLocnoUptr - will return 1 if the symbol has spil location */ +/* but is not used as a pointer */ +/*-----------------------------------------------------------------*/ +static int +hasSpilLocnoUptr (symbol * sym, eBBlock * ebp, iCode * ic) +{ + debugLog ("%s\n", __FUNCTION__); + return ((sym->usl.spillLoc && !sym->uptr) ? 1 : 0); +} + +/*-----------------------------------------------------------------*/ +/* rematable - will return 1 if the remat flag is set */ +/*-----------------------------------------------------------------*/ +static int +rematable (symbol * sym, eBBlock * ebp, iCode * ic) +{ + debugLog ("%s\n", __FUNCTION__); + return sym->remat; +} + +/*-----------------------------------------------------------------*/ +/* notUsedInRemaining - not used or defined in remain of the block */ +/*-----------------------------------------------------------------*/ +static int +notUsedInRemaining (symbol * sym, eBBlock * ebp, iCode * ic) +{ + debugLog ("%s\n", __FUNCTION__); + return ((usedInRemaining (operandFromSymbol (sym), ic) ? 0 : 1) && + allDefsOutOfRange (sym->defs, ebp->fSeq, ebp->lSeq)); +} + +/*-----------------------------------------------------------------*/ +/* allLRs - return true for all */ +/*-----------------------------------------------------------------*/ +static int +allLRs (symbol * sym, eBBlock * ebp, iCode * ic) +{ + debugLog ("%s\n", __FUNCTION__); + return 1; +} + +/*-----------------------------------------------------------------*/ +/* liveRangesWith - applies function to a given set of live range */ +/*-----------------------------------------------------------------*/ +static set * +liveRangesWith (bitVect * lrs, int (func) (symbol *, eBBlock *, iCode *), + eBBlock * ebp, iCode * ic) +{ + set *rset = NULL; + int i; + + debugLog ("%s\n", __FUNCTION__); + if (!lrs || !lrs->size) + return NULL; + + for (i = 1; i < lrs->size; i++) + { + symbol *sym; + if (!bitVectBitValue (lrs, i)) + continue; + + /* if we don't find it in the live range + hash table we are in serious trouble */ + if (!(sym = hTabItemWithKey (liveRanges, i))) + { + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, + "liveRangesWith could not find liveRange"); + exit (1); + } + + if (func (sym, ebp, ic) && bitVectBitValue (_G.regAssigned, sym->key)) + addSetHead (&rset, sym); + } + + return rset; +} + + +/*-----------------------------------------------------------------*/ +/* leastUsedLR - given a set determines which is the least used */ +/*-----------------------------------------------------------------*/ +static symbol * +leastUsedLR (set * sset) +{ + symbol *sym = NULL, *lsym = NULL; + + debugLog ("%s\n", __FUNCTION__); + sym = lsym = setFirstItem (sset); + + if (!lsym) + return NULL; + + for (; lsym; lsym = setNextItem (sset)) + { + + /* if usage is the same then prefer + the spill the smaller of the two */ + if (lsym->used == sym->used) + if (getSize (lsym->type) < getSize (sym->type)) + sym = lsym; + + /* if less usage */ + if (lsym->used < sym->used) + sym = lsym; + + } + + setToNull ((void **) &sset); + sym->blockSpil = 0; + return sym; +} + +/*-----------------------------------------------------------------*/ +/* noOverLap - will iterate through the list looking for over lap */ +/*-----------------------------------------------------------------*/ +static int +noOverLap (set * itmpStack, symbol * fsym) +{ + symbol *sym; + debugLog ("%s\n", __FUNCTION__); + + + for (sym = setFirstItem (itmpStack); sym; + sym = setNextItem (itmpStack)) + { + if (sym->liveTo > fsym->liveFrom) + return 0; + + } + + return 1; +} + +/*-----------------------------------------------------------------*/ +/* isFree - will return 1 if the a free spil location is found */ +/*-----------------------------------------------------------------*/ +static +DEFSETFUNC (isFree) +{ + symbol *sym = item; + V_ARG (symbol **, sloc); + V_ARG (symbol *, fsym); + + debugLog ("%s\n", __FUNCTION__); + /* if already found */ + if (*sloc) + return 0; + + /* if it is free && and the itmp assigned to + this does not have any overlapping live ranges + with the one currently being assigned and + the size can be accomodated */ + if (sym->isFree && + noOverLap (sym->usl.itmpStack, fsym) && + getSize (sym->type) >= getSize (fsym->type)) + { + *sloc = sym; + return 1; + } + + return 0; +} + +/*-----------------------------------------------------------------*/ +/* spillLRWithPtrReg :- will spil those live ranges which use PTR */ +/*-----------------------------------------------------------------*/ +static void +spillLRWithPtrReg (symbol * forSym) +{ + symbol *lrsym; + regs *r0, *r1; + int k; + + debugLog ("%s\n", __FUNCTION__); + if (!_G.regAssigned || + bitVectIsZero (_G.regAssigned)) + return; + + r0 = pic16_regWithIdx (R0_IDX); + r1 = pic16_regWithIdx (R1_IDX); + + /* for all live ranges */ + for (lrsym = hTabFirstItem (liveRanges, &k); lrsym; + lrsym = hTabNextItem (liveRanges, &k)) + { + int j; + + /* if no registers assigned to it or + spilt */ + /* if it does not overlap with this then + not need to spill it */ + + if (lrsym->isspilt || !lrsym->nRegs || + (lrsym->liveTo < forSym->liveFrom)) + continue; + + /* go thru the registers : if it is either + r0 or r1 then spil it */ + for (j = 0; j < lrsym->nRegs; j++) + if (lrsym->regs[j] == r0 || + lrsym->regs[j] == r1) + { + spillThis (lrsym); + break; + } + } + +} + +/*-----------------------------------------------------------------*/ +/* createStackSpil - create a location on the stack to spil */ +/*-----------------------------------------------------------------*/ +static symbol * +createStackSpil (symbol * sym) +{ + symbol *sloc = NULL; + int useXstack, model, noOverlay; + + char slocBuffer[30]; + debugLog ("%s\n", __FUNCTION__); + + /* first go try and find a free one that is already + existing on the stack */ + if (applyToSet (_G.stackSpil, isFree, &sloc, sym)) + { + /* found a free one : just update & return */ + sym->usl.spillLoc = sloc; + sym->stackSpil = 1; + sloc->isFree = 0; + addSetHead (&sloc->usl.itmpStack, sym); + return sym; + } + + /* could not then have to create one , this is the hard part + we need to allocate this on the stack : this is really a + hack!! but cannot think of anything better at this time */ + + if (sprintf (slocBuffer, "sloc%d", _G.slocNum++) >= sizeof (slocBuffer)) + { + fprintf (stderr, "kkkInternal error: slocBuffer overflowed: %s:%d\n", + __FILE__, __LINE__); + exit (1); + } + + sloc = newiTemp (slocBuffer); + + /* set the type to the spilling symbol */ + sloc->type = copyLinkChain (sym->type); + sloc->etype = getSpec (sloc->type); + SPEC_SCLS (sloc->etype) = S_DATA; + SPEC_EXTR (sloc->etype) = 0; + SPEC_STAT (sloc->etype) = 0; + + /* we don't allow it to be allocated` + onto the external stack since : so we + temporarily turn it off ; we also + turn off memory model to prevent + the spil from going to the external storage + and turn off overlaying + */ + + useXstack = options.useXstack; + model = options.model; + noOverlay = options.noOverlay; + options.noOverlay = 1; + options.model = options.useXstack = 0; + + allocLocal (sloc); + + options.useXstack = useXstack; + options.model = model; + options.noOverlay = noOverlay; + sloc->isref = 1; /* to prevent compiler warning */ + + /* if it is on the stack then update the stack */ + if (IN_STACK (sloc->etype)) + { + currFunc->stack += getSize (sloc->type); + _G.stackExtend += getSize (sloc->type); + } + else + _G.dataExtend += getSize (sloc->type); + + /* add it to the _G.stackSpil set */ + addSetHead (&_G.stackSpil, sloc); + sym->usl.spillLoc = sloc; + sym->stackSpil = 1; + + /* add it to the set of itempStack set + of the spill location */ + addSetHead (&sloc->usl.itmpStack, sym); + return sym; +} + +/*-----------------------------------------------------------------*/ +/* isSpiltOnStack - returns true if the spil location is on stack */ +/*-----------------------------------------------------------------*/ +static bool +isSpiltOnStack (symbol * sym) +{ + sym_link *etype; + + debugLog ("%s\n", __FUNCTION__); + if (!sym) + return FALSE; + + if (!sym->isspilt) + return FALSE; + +/* if (sym->_G.stackSpil) */ +/* return TRUE; */ + + if (!sym->usl.spillLoc) + return FALSE; + + etype = getSpec (sym->usl.spillLoc->type); + if (IN_STACK (etype)) + return TRUE; + + return FALSE; +} + +/*-----------------------------------------------------------------*/ +/* spillThis - spils a specific operand */ +/*-----------------------------------------------------------------*/ +static void +spillThis (symbol * sym) +{ + int i; + debugLog ("%s : %s\n", __FUNCTION__, sym->rname); + + /* if this is rematerializable or has a spillLocation + we are okay, else we need to create a spillLocation + for it */ + if (!(sym->remat || sym->usl.spillLoc)) + createStackSpil (sym); + + + /* mark it has spilt & put it in the spilt set */ + sym->isspilt = 1; + _G.spiltSet = bitVectSetBit (_G.spiltSet, sym->key); + + bitVectUnSetBit (_G.regAssigned, sym->key); + + for (i = 0; i < sym->nRegs; i++) + + if (sym->regs[i]) + { + freeReg (sym->regs[i]); + sym->regs[i] = NULL; + } + + /* if spilt on stack then free up r0 & r1 + if they could have been assigned to some + LIVE ranges */ + if (!pic16_ptrRegReq && isSpiltOnStack (sym)) + { + pic16_ptrRegReq++; + spillLRWithPtrReg (sym); + } + + if (sym->usl.spillLoc && !sym->remat) + sym->usl.spillLoc->allocreq = 1; + return; +} + +/*-----------------------------------------------------------------*/ +/* selectSpil - select a iTemp to spil : rather a simple procedure */ +/*-----------------------------------------------------------------*/ +static symbol * +selectSpil (iCode * ic, eBBlock * ebp, symbol * forSym) +{ + bitVect *lrcs = NULL; + set *selectS; + symbol *sym; + + debugLog ("%s\n", __FUNCTION__); + /* get the spillable live ranges */ + lrcs = computeSpillable (ic); + + /* get all live ranges that are rematerizable */ + if ((selectS = liveRangesWith (lrcs, rematable, ebp, ic))) + { + + /* return the least used of these */ + return leastUsedLR (selectS); + } + + /* get live ranges with spillLocations in direct space */ + if ((selectS = liveRangesWith (lrcs, directSpilLoc, ebp, ic))) + { + sym = leastUsedLR (selectS); + strcpy (sym->rname, (sym->usl.spillLoc->rname[0] ? + sym->usl.spillLoc->rname : + sym->usl.spillLoc->name)); + sym->spildir = 1; + /* mark it as allocation required */ + sym->usl.spillLoc->allocreq = 1; + return sym; + } + + /* if the symbol is local to the block then */ + if (forSym->liveTo < ebp->lSeq) + { + + /* check if there are any live ranges allocated + to registers that are not used in this block */ + if (!_G.blockSpil && (selectS = liveRangesWith (lrcs, notUsedInBlock, ebp, ic))) + { + sym = leastUsedLR (selectS); + /* if this is not rematerializable */ + if (!sym->remat) + { + _G.blockSpil++; + sym->blockSpil = 1; + } + return sym; + } + + /* check if there are any live ranges that not + used in the remainder of the block */ + if (!_G.blockSpil && (selectS = liveRangesWith (lrcs, notUsedInRemaining, ebp, ic))) + { + sym = leastUsedLR (selectS); + if (!sym->remat) + { + sym->remainSpil = 1; + _G.blockSpil++; + } + return sym; + } + } + + /* find live ranges with spillocation && not used as pointers */ + if ((selectS = liveRangesWith (lrcs, hasSpilLocnoUptr, ebp, ic))) + { + + sym = leastUsedLR (selectS); + /* mark this as allocation required */ + sym->usl.spillLoc->allocreq = 1; + return sym; + } + + /* find live ranges with spillocation */ + if ((selectS = liveRangesWith (lrcs, hasSpilLoc, ebp, ic))) + { + + sym = leastUsedLR (selectS); + sym->usl.spillLoc->allocreq = 1; + return sym; + } + + /* couldn't find then we need to create a spil + location on the stack , for which one? the least + used ofcourse */ + if ((selectS = liveRangesWith (lrcs, noSpilLoc, ebp, ic))) + { + + /* return a created spil location */ + sym = createStackSpil (leastUsedLR (selectS)); + sym->usl.spillLoc->allocreq = 1; + return sym; + } + + /* this is an extreme situation we will spill + this one : happens very rarely but it does happen */ + spillThis (forSym); + return forSym; + +} + +/*-----------------------------------------------------------------*/ +/* spilSomething - spil some variable & mark registers as free */ +/*-----------------------------------------------------------------*/ +static bool +spilSomething (iCode * ic, eBBlock * ebp, symbol * forSym) +{ + symbol *ssym; + int i; + + debugLog ("%s\n", __FUNCTION__); + /* get something we can spil */ + ssym = selectSpil (ic, ebp, forSym); + + /* mark it as spilt */ + ssym->isspilt = 1; + _G.spiltSet = bitVectSetBit (_G.spiltSet, ssym->key); + + /* mark it as not register assigned & + take it away from the set */ + bitVectUnSetBit (_G.regAssigned, ssym->key); + + /* mark the registers as free */ + for (i = 0; i < ssym->nRegs; i++) + if (ssym->regs[i]) + freeReg (ssym->regs[i]); + + /* if spilt on stack then free up r0 & r1 + if they could have been assigned to as gprs */ + if (!pic16_ptrRegReq && isSpiltOnStack (ssym)) + { + pic16_ptrRegReq++; + spillLRWithPtrReg (ssym); + } + + /* if this was a block level spil then insert push & pop + at the start & end of block respectively */ + if (ssym->blockSpil) + { + iCode *nic = newiCode (IPUSH, operandFromSymbol (ssym), NULL); + /* add push to the start of the block */ + addiCodeToeBBlock (ebp, nic, (ebp->sch->op == LABEL ? + ebp->sch->next : ebp->sch)); + nic = newiCode (IPOP, operandFromSymbol (ssym), NULL); + /* add pop to the end of the block */ + addiCodeToeBBlock (ebp, nic, NULL); + } + + /* if spilt because not used in the remainder of the + block then add a push before this instruction and + a pop at the end of the block */ + if (ssym->remainSpil) + { + + iCode *nic = newiCode (IPUSH, operandFromSymbol (ssym), NULL); + /* add push just before this instruction */ + addiCodeToeBBlock (ebp, nic, ic); + + nic = newiCode (IPOP, operandFromSymbol (ssym), NULL); + /* add pop to the end of the block */ + addiCodeToeBBlock (ebp, nic, NULL); + } + + if (ssym == forSym) + return FALSE; + else + return TRUE; +} + +/*-----------------------------------------------------------------*/ +/* getRegPtr - will try for PTR if not a GPR type if not spil */ +/*-----------------------------------------------------------------*/ +static regs * +getRegPtr (iCode * ic, eBBlock * ebp, symbol * sym) +{ + regs *reg; + + debugLog ("%s\n", __FUNCTION__); +tryAgain: + /* try for a ptr type */ + if ((reg = allocReg (REG_PTR))) + return reg; + + /* try for gpr type */ + if ((reg = allocReg (REG_GPR))) + return reg; + + /* we have to spil */ + if (!spilSomething (ic, ebp, sym)) + return NULL; + + /* this looks like an infinite loop but + in really selectSpil will abort */ + goto tryAgain; +} + +/*-----------------------------------------------------------------*/ +/* getRegGpr - will try for GPR if not spil */ +/*-----------------------------------------------------------------*/ +static regs * +getRegGpr (iCode * ic, eBBlock * ebp, symbol * sym) +{ + regs *reg; + + debugLog ("%s\n", __FUNCTION__); +tryAgain: + /* try for gpr type */ + if ((reg = allocReg (REG_GPR))) + return reg; + + if (!pic16_ptrRegReq) + if ((reg = allocReg (REG_PTR))) + return reg; + + /* we have to spil */ + if (!spilSomething (ic, ebp, sym)) + return NULL; + + /* this looks like an infinite loop but + in really selectSpil will abort */ + goto tryAgain; +} + +/*-----------------------------------------------------------------*/ +/* symHasReg - symbol has a given register */ +/*-----------------------------------------------------------------*/ +static bool +symHasReg (symbol * sym, regs * reg) +{ + int i; + + debugLog ("%s\n", __FUNCTION__); + for (i = 0; i < sym->nRegs; i++) + if (sym->regs[i] == reg) + return TRUE; + + return FALSE; +} + +/*-----------------------------------------------------------------*/ +/* deassignLRs - check the live to and if they have registers & are */ +/* not spilt then free up the registers */ +/*-----------------------------------------------------------------*/ +static void +deassignLRs (iCode * ic, eBBlock * ebp) +{ + symbol *sym; + int k; + symbol *result; + + debugLog ("%s\n", __FUNCTION__); + for (sym = hTabFirstItem (liveRanges, &k); sym; + sym = hTabNextItem (liveRanges, &k)) + { + + symbol *psym = NULL; + /* if it does not end here */ + if (sym->liveTo > ic->seq) + continue; + + /* if it was spilt on stack then we can + mark the stack spil location as free */ + if (sym->isspilt) + { + if (sym->stackSpil) + { + sym->usl.spillLoc->isFree = 1; + sym->stackSpil = 0; + } + continue; + } + + if (!bitVectBitValue (_G.regAssigned, sym->key)) + continue; + + /* special case check if this is an IFX & + the privious one was a pop and the + previous one was not spilt then keep track + of the symbol */ + if (ic->op == IFX && ic->prev && + ic->prev->op == IPOP && + !ic->prev->parmPush && + !OP_SYMBOL (IC_LEFT (ic->prev))->isspilt) + psym = OP_SYMBOL (IC_LEFT (ic->prev)); + + if (sym->nRegs) + { + int i = 0; + + bitVectUnSetBit (_G.regAssigned, sym->key); + + /* if the result of this one needs registers + and does not have it then assign it right + away */ + if (IC_RESULT (ic) && + !(SKIP_IC2 (ic) || /* not a special icode */ + ic->op == JUMPTABLE || + ic->op == IFX || + ic->op == IPUSH || + ic->op == IPOP || + ic->op == RETURN || + POINTER_SET (ic)) && + (result = OP_SYMBOL (IC_RESULT (ic))) && /* has a result */ + result->liveTo > ic->seq && /* and will live beyond this */ + result->liveTo <= ebp->lSeq && /* does not go beyond this block */ + result->regType == sym->regType && /* same register types */ + result->nRegs && /* which needs registers */ + !result->isspilt && /* and does not already have them */ + !result->remat && + !bitVectBitValue (_G.regAssigned, result->key) && + /* the number of free regs + number of regs in this LR + can accomodate the what result Needs */ + ((nfreeRegsType (result->regType) + + sym->nRegs) >= result->nRegs) + ) + { + + for (i = 0; i < max (sym->nRegs, result->nRegs); i++) + if (i < sym->nRegs) + result->regs[i] = sym->regs[i]; + else + result->regs[i] = getRegGpr (ic, ebp, result); + + _G.regAssigned = bitVectSetBit (_G.regAssigned, result->key); + + } + + /* free the remaining */ + for (; i < sym->nRegs; i++) + { + if (psym) + { + if (!symHasReg (psym, sym->regs[i])) + freeReg (sym->regs[i]); + } + else + freeReg (sym->regs[i]); + } + } + } +} + + +/*-----------------------------------------------------------------*/ +/* reassignLR - reassign this to registers */ +/*-----------------------------------------------------------------*/ +static void +reassignLR (operand * op) +{ + symbol *sym = OP_SYMBOL (op); + int i; + + debugLog ("%s\n", __FUNCTION__); + /* not spilt any more */ + sym->isspilt = sym->blockSpil = sym->remainSpil = 0; + bitVectUnSetBit (_G.spiltSet, sym->key); + + _G.regAssigned = bitVectSetBit (_G.regAssigned, sym->key); + + _G.blockSpil--; + + for (i = 0; i < sym->nRegs; i++) + sym->regs[i]->isFree = 0; +} + +/*-----------------------------------------------------------------*/ +/* willCauseSpill - determines if allocating will cause a spill */ +/*-----------------------------------------------------------------*/ +static int +willCauseSpill (int nr, int rt) +{ + debugLog ("%s\n", __FUNCTION__); + /* first check if there are any avlb registers + of te type required */ + if (rt == REG_PTR) + { + /* special case for pointer type + if pointer type not avlb then + check for type gpr */ + if (nFreeRegs (rt) >= nr) + return 0; + if (nFreeRegs (REG_GPR) >= nr) + return 0; + } + else + { + if (pic16_ptrRegReq) + { + if (nFreeRegs (rt) >= nr) + return 0; + } + else + { + if (nFreeRegs (REG_PTR) + + nFreeRegs (REG_GPR) >= nr) + return 0; + } + } + + debugLog (" ... yep it will (cause a spill)\n"); + /* it will cause a spil */ + return 1; +} + +/*-----------------------------------------------------------------*/ +/* positionRegs - the allocator can allocate same registers to res- */ +/* ult and operand, if this happens make sure they are in the same */ +/* position as the operand otherwise chaos results */ +/*-----------------------------------------------------------------*/ +static void +positionRegs (symbol * result, symbol * opsym, int lineno) +{ + int count = min (result->nRegs, opsym->nRegs); + int i, j = 0, shared = 0; + + debugLog ("%s\n", __FUNCTION__); + /* if the result has been spilt then cannot share */ + if (opsym->isspilt) + return; +again: + shared = 0; + /* first make sure that they actually share */ + for (i = 0; i < count; i++) + { + for (j = 0; j < count; j++) + { + if (result->regs[i] == opsym->regs[j] && i != j) + { + shared = 1; + goto xchgPositions; + } + } + } +xchgPositions: + if (shared) + { + regs *tmp = result->regs[i]; + result->regs[i] = result->regs[j]; + result->regs[j] = tmp; + goto again; + } +} + +/*-----------------------------------------------------------------*/ +/* serialRegAssign - serially allocate registers to the variables */ +/*-----------------------------------------------------------------*/ +static void +serialRegAssign (eBBlock ** ebbs, int count) +{ + int i; + + debugLog ("%s\n", __FUNCTION__); + /* for all blocks */ + for (i = 0; i < count; i++) + { + + iCode *ic; + + if (ebbs[i]->noPath && + (ebbs[i]->entryLabel != entryLabel && + ebbs[i]->entryLabel != returnLabel)) + continue; + + /* of all instructions do */ + for (ic = ebbs[i]->sch; ic; ic = ic->next) + { + + debugLog (" op: %s\n", decodeOp (ic->op)); + + /* if this is an ipop that means some live + range will have to be assigned again */ + if (ic->op == IPOP) + reassignLR (IC_LEFT (ic)); + + /* if result is present && is a true symbol */ + if (IC_RESULT (ic) && ic->op != IFX && + IS_TRUE_SYMOP (IC_RESULT (ic))) + OP_SYMBOL (IC_RESULT (ic))->allocreq = 1; + + /* take away registers from live + ranges that end at this instruction */ + deassignLRs (ic, ebbs[i]); + + /* some don't need registers */ + if (SKIP_IC2 (ic) || + ic->op == JUMPTABLE || + ic->op == IFX || + ic->op == IPUSH || + ic->op == IPOP || + (IC_RESULT (ic) && POINTER_SET (ic))) + continue; + + /* now we need to allocate registers + only for the result */ + if (IC_RESULT (ic)) + { + symbol *sym = OP_SYMBOL (IC_RESULT (ic)); + bitVect *spillable; + int willCS; + int j; + int ptrRegSet = 0; + + /* if it does not need or is spilt + or is already assigned to registers + or will not live beyond this instructions */ + if (!sym->nRegs || + sym->isspilt || + bitVectBitValue (_G.regAssigned, sym->key) || + sym->liveTo <= ic->seq) + continue; + + /* if some liverange has been spilt at the block level + and this one live beyond this block then spil this + to be safe */ + if (_G.blockSpil && sym->liveTo > ebbs[i]->lSeq) + { + spillThis (sym); + continue; + } + /* if trying to allocate this will cause + a spill and there is nothing to spill + or this one is rematerializable then + spill this one */ + willCS = willCauseSpill (sym->nRegs, sym->regType); + spillable = computeSpillable (ic); + if (sym->remat || + (willCS && bitVectIsZero (spillable))) + { + + spillThis (sym); + continue; + + } + + /* if it has a spillocation & is used less than + all other live ranges then spill this */ + if (willCS) { + if (sym->usl.spillLoc) { + symbol *leastUsed = leastUsedLR (liveRangesWith (spillable, + allLRs, ebbs[i], ic)); + if (leastUsed && leastUsed->used > sym->used) { + spillThis (sym); + continue; + } + } else { + /* if none of the liveRanges have a spillLocation then better + to spill this one than anything else already assigned to registers */ + if (liveRangesWith(spillable,noSpilLoc,ebbs[i],ic)) { + /* if this is local to this block then we might find a block spil */ + if (!(sym->liveFrom >= ebbs[i]->fSeq && sym->liveTo <= ebbs[i]->lSeq)) { + spillThis (sym); + continue; + } + } + } + } + + if (ic->op == RECEIVE) + debugLog ("When I get clever, I'll optimize the receive logic\n"); + + /* if we need ptr regs for the right side + then mark it */ + if (POINTER_GET (ic) && getSize (OP_SYMBOL (IC_LEFT (ic))->type) + <= (unsigned) PTRSIZE) + { + pic16_ptrRegReq++; + ptrRegSet = 1; + } + /* else we assign registers to it */ + _G.regAssigned = bitVectSetBit (_G.regAssigned, sym->key); + + debugLog (" %d - \n", __LINE__); + if(debugF) + bitVectDebugOn(_G.regAssigned, debugF); + + for (j = 0; j < sym->nRegs; j++) + { + if (sym->regType == REG_PTR) + sym->regs[j] = getRegPtr (ic, ebbs[i], sym); + else + sym->regs[j] = getRegGpr (ic, ebbs[i], sym); + + /* if the allocation falied which means + this was spilt then break */ + if (!sym->regs[j]) + break; + } + debugLog (" %d - \n", __LINE__); + + /* if it shares registers with operands make sure + that they are in the same position */ + if (IC_LEFT (ic) && IS_SYMOP (IC_LEFT (ic)) && + OP_SYMBOL (IC_LEFT (ic))->nRegs && ic->op != '=') + positionRegs (OP_SYMBOL (IC_RESULT (ic)), + OP_SYMBOL (IC_LEFT (ic)), ic->lineno); + /* do the same for the right operand */ + if (IC_RIGHT (ic) && IS_SYMOP (IC_RIGHT (ic)) && + OP_SYMBOL (IC_RIGHT (ic))->nRegs && ic->op != '=') + positionRegs (OP_SYMBOL (IC_RESULT (ic)), + OP_SYMBOL (IC_RIGHT (ic)), ic->lineno); + + debugLog (" %d - \n", __LINE__); + if (ptrRegSet) + { + debugLog (" %d - \n", __LINE__); + pic16_ptrRegReq--; + ptrRegSet = 0; + } + + } + } + } +} + +/*-----------------------------------------------------------------*/ +/* rUmaskForOp :- returns register mask for an operand */ +/*-----------------------------------------------------------------*/ +static bitVect * +rUmaskForOp (operand * op) +{ + bitVect *rumask; + symbol *sym; + int j; + + debugLog ("%s\n", __FUNCTION__); + /* only temporaries are assigned registers */ + if (!IS_ITEMP (op)) + return NULL; + + sym = OP_SYMBOL (op); + + /* if spilt or no registers assigned to it + then nothing */ + if (sym->isspilt || !sym->nRegs) + return NULL; + + rumask = newBitVect (pic16_nRegs); + + for (j = 0; j < sym->nRegs; j++) + { + rumask = bitVectSetBit (rumask, + sym->regs[j]->rIdx); + } + + return rumask; +} + +/*-----------------------------------------------------------------*/ +/* regsUsedIniCode :- returns bit vector of registers used in iCode */ +/*-----------------------------------------------------------------*/ +static bitVect * +regsUsedIniCode (iCode * ic) +{ + bitVect *rmask = newBitVect (pic16_nRegs); + + debugLog ("%s\n", __FUNCTION__); + /* do the special cases first */ + if (ic->op == IFX) + { + rmask = bitVectUnion (rmask, + rUmaskForOp (IC_COND (ic))); + goto ret; + } + + /* for the jumptable */ + if (ic->op == JUMPTABLE) + { + rmask = bitVectUnion (rmask, + rUmaskForOp (IC_JTCOND (ic))); + + goto ret; + } + + /* of all other cases */ + if (IC_LEFT (ic)) + rmask = bitVectUnion (rmask, + rUmaskForOp (IC_LEFT (ic))); + + + if (IC_RIGHT (ic)) + rmask = bitVectUnion (rmask, + rUmaskForOp (IC_RIGHT (ic))); + + if (IC_RESULT (ic)) + rmask = bitVectUnion (rmask, + rUmaskForOp (IC_RESULT (ic))); + +ret: + return rmask; +} + +/*-----------------------------------------------------------------*/ +/* createRegMask - for each instruction will determine the regsUsed */ +/*-----------------------------------------------------------------*/ +static void +createRegMask (eBBlock ** ebbs, int count) +{ + int i; + + debugLog ("%s\n", __FUNCTION__); + /* for all blocks */ + for (i = 0; i < count; i++) + { + iCode *ic; + + if (ebbs[i]->noPath && + (ebbs[i]->entryLabel != entryLabel && + ebbs[i]->entryLabel != returnLabel)) + continue; + + /* for all instructions */ + for (ic = ebbs[i]->sch; ic; ic = ic->next) + { + + int j; + + if (SKIP_IC2 (ic) || !ic->rlive) + continue; + + /* first mark the registers used in this + instruction */ + ic->rUsed = regsUsedIniCode (ic); + _G.funcrUsed = bitVectUnion (_G.funcrUsed, ic->rUsed); + + /* now create the register mask for those + registers that are in use : this is a + super set of ic->rUsed */ + ic->rMask = newBitVect (pic16_nRegs + 1); + + /* for all live Ranges alive at this point */ + for (j = 1; j < ic->rlive->size; j++) + { + symbol *sym; + int k; + + /* if not alive then continue */ + if (!bitVectBitValue (ic->rlive, j)) + continue; + + /* find the live range we are interested in */ + if (!(sym = hTabItemWithKey (liveRanges, j))) + { + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, + "createRegMask cannot find live range"); + exit (0); + } + + /* if no register assigned to it */ + if (!sym->nRegs || sym->isspilt) + continue; + + /* for all the registers allocated to it */ + for (k = 0; k < sym->nRegs; k++) + if (sym->regs[k]) + ic->rMask = + bitVectSetBit (ic->rMask, sym->regs[k]->rIdx); + } + } + } +} + +/*-----------------------------------------------------------------*/ +/* rematStr - returns the rematerialized string for a remat var */ +/*-----------------------------------------------------------------*/ +static symbol * +rematStr (symbol * sym) +{ + char *s = buffer; + iCode *ic = sym->rematiCode; + symbol *psym = NULL; + + debugLog ("%s\n", __FUNCTION__); + + //printf ("%s\n", s); + + /* if plus or minus print the right hand side */ + + if (ic->op == '+' || ic->op == '-') { + + iCode *ric = OP_SYMBOL (IC_LEFT (ic))->rematiCode; + + sprintf (s, "(%s %c 0x%04x)", + OP_SYMBOL (IC_LEFT (ric))->rname, + ic->op, + (int) operandLitValue (IC_RIGHT (ic))); + + + //fprintf(stderr, "ralloc.c:%d OOPS %s\n",__LINE__,s); + + psym = newSymbol (OP_SYMBOL (IC_LEFT (ric))->rname, 1); + psym->offset = (int) operandLitValue (IC_RIGHT (ic)); + + return psym; + } + + sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname); + psym = newSymbol (OP_SYMBOL (IC_LEFT (ic))->rname, 1); + + //printf ("ralloc.c:%d %s\n", __LINE__,buffer); + return psym; +} + +#if 0 +/*-----------------------------------------------------------------*/ +/* rematStr - returns the rematerialized string for a remat var */ +/*-----------------------------------------------------------------*/ +static char * +rematStr (symbol * sym) +{ + char *s = buffer; + iCode *ic = sym->rematiCode; + + debugLog ("%s\n", __FUNCTION__); + while (1) + { + + printf ("%s\n", s); + /* if plus or minus print the right hand side */ +/* + if (ic->op == '+' || ic->op == '-') { + sprintf(s,"0x%04x %c ",(int) operandLitValue(IC_RIGHT(ic)), + ic->op ); + s += strlen(s); + ic = OP_SYMBOL(IC_LEFT(ic))->rematiCode; + continue ; + } + */ + if (ic->op == '+' || ic->op == '-') + { + iCode *ric = OP_SYMBOL (IC_LEFT (ic))->rematiCode; + sprintf (s, "(%s %c 0x%04x)", + OP_SYMBOL (IC_LEFT (ric))->rname, + ic->op, + (int) operandLitValue (IC_RIGHT (ic))); + + //s += strlen(s); + //ic = OP_SYMBOL(IC_LEFT(ic))->rematiCode; + //continue ; + //fprintf(stderr, "ralloc.c:%d OOPS %s\n",__LINE__,s); + return buffer; + } + + /* we reached the end */ + sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname); + break; + } + + printf ("%s\n", buffer); + return buffer; +} +#endif + +/*-----------------------------------------------------------------*/ +/* regTypeNum - computes the type & number of registers required */ +/*-----------------------------------------------------------------*/ +static void +regTypeNum () +{ + symbol *sym; + int k; + iCode *ic; + + debugLog ("%s\n", __FUNCTION__); + /* for each live range do */ + for (sym = hTabFirstItem (liveRanges, &k); sym; + sym = hTabNextItem (liveRanges, &k)) { + + debugLog (" %d - %s\n", __LINE__, sym->rname); + + /* if used zero times then no registers needed */ + if ((sym->liveTo - sym->liveFrom) == 0) + continue; + + + /* if the live range is a temporary */ + if (sym->isitmp) { + + debugLog (" %d - itemp register\n", __LINE__); + + /* if the type is marked as a conditional */ + if (sym->regType == REG_CND) + continue; + + /* if used in return only then we don't + need registers */ + if (sym->ruonly || sym->accuse) { + if (IS_AGGREGATE (sym->type) || sym->isptr) + sym->type = aggrToPtr (sym->type, FALSE); + debugLog (" %d - no reg needed - used as a return\n", __LINE__); + + continue; + } + + /* if the symbol has only one definition & + that definition is a get_pointer and the + pointer we are getting is rematerializable and + in "data" space */ + + if (bitVectnBitsOn (sym->defs) == 1 && + (ic = hTabItemWithKey (iCodehTab, + bitVectFirstBit (sym->defs))) && + POINTER_GET (ic) && + !sym->noSpilLoc && + !IS_BITVAR (sym->etype)) { + + + debugLog (" %d - \n", __LINE__); + + /* if remat in data space */ + if (OP_SYMBOL (IC_LEFT (ic))->remat && + DCL_TYPE (aggrToPtr (sym->type, FALSE)) == POINTER) { + + /* create a psuedo symbol & force a spil */ + //X symbol *psym = newSymbol (rematStr (OP_SYMBOL (IC_LEFT (ic))), 1); + symbol *psym = rematStr (OP_SYMBOL (IC_LEFT (ic))); + psym->type = sym->type; + psym->etype = sym->etype; + strcpy (psym->rname, psym->name); + sym->isspilt = 1; + sym->usl.spillLoc = psym; + continue; + } + + /* if in data space or idata space then try to + allocate pointer register */ + + } + + /* if not then we require registers */ + sym->nRegs = ((IS_AGGREGATE (sym->type) || sym->isptr) ? + getSize (sym->type = aggrToPtr (sym->type, FALSE)) : + getSize (sym->type)); + + + if(IS_PTR_CONST (sym->type)) { + debugLog (" %d const pointer type requires %d registers, changing to 2\n",__LINE__,sym->nRegs); + sym->nRegs = 2; + } + + if (sym->nRegs > 4) { + fprintf (stderr, "allocated more than 4 or 0 registers for type "); + printTypeChain (sym->type, stderr); + fprintf (stderr, "\n"); + } + + /* determine the type of register required */ + if (sym->nRegs == 1 && + IS_PTR (sym->type) && + sym->uptr) + sym->regType = REG_PTR; + else + sym->regType = REG_GPR; + + + debugLog (" reg name %s, reg type %s\n", sym->rname, debugLogRegType (sym->regType)); + + } + else + /* for the first run we don't provide */ + /* registers for true symbols we will */ + /* see how things go */ + sym->nRegs = 0; + } + +} +static DEFSETFUNC (markRegFree) +{ + ((regs *)item)->isFree = 1; + + return 0; +} + +DEFSETFUNC (pic16_deallocReg) +{ + fprintf(stderr,"deallocting register %s\n",((regs *)item)->name); + ((regs *)item)->isFree = 1; + ((regs *)item)->wasUsed = 0; + + return 0; +} +/*-----------------------------------------------------------------*/ +/* freeAllRegs - mark all registers as free */ +/*-----------------------------------------------------------------*/ +void +pic16_freeAllRegs () +{ + // int i; + + debugLog ("%s\n", __FUNCTION__); + + applyToSet(pic16_dynAllocRegs,markRegFree); + applyToSet(pic16_dynStackRegs,markRegFree); + +/* + for (i = 0; i < pic16_nRegs; i++) + regspic16[i].isFree = 1; +*/ +} + +/*-----------------------------------------------------------------*/ +/*-----------------------------------------------------------------*/ +void +pic16_deallocateAllRegs () +{ + // int i; + + debugLog ("%s\n", __FUNCTION__); + + applyToSet(pic16_dynAllocRegs,pic16_deallocReg); + +/* + for (i = 0; i < pic16_nRegs; i++) { + if(regspic16[i].pc_type == PO_GPR_TEMP) { + regspic16[i].isFree = 1; + regspic16[i].wasUsed = 0; + } + } +*/ +} + + +/*-----------------------------------------------------------------*/ +/* deallocStackSpil - this will set the stack pointer back */ +/*-----------------------------------------------------------------*/ +static +DEFSETFUNC (deallocStackSpil) +{ + symbol *sym = item; + + debugLog ("%s\n", __FUNCTION__); + deallocLocal (sym); + return 0; +} + +/*-----------------------------------------------------------------*/ +/* farSpacePackable - returns the packable icode for far variables */ +/*-----------------------------------------------------------------*/ +static iCode * +farSpacePackable (iCode * ic) +{ + iCode *dic; + + debugLog ("%s\n", __FUNCTION__); + /* go thru till we find a definition for the + symbol on the right */ + for (dic = ic->prev; dic; dic = dic->prev) + { + + /* if the definition is a call then no */ + if ((dic->op == CALL || dic->op == PCALL) && + IC_RESULT (dic)->key == IC_RIGHT (ic)->key) + { + return NULL; + } + + /* if shift by unknown amount then not */ + if ((dic->op == LEFT_OP || dic->op == RIGHT_OP) && + IC_RESULT (dic)->key == IC_RIGHT (ic)->key) + return NULL; + + /* if pointer get and size > 1 */ + if (POINTER_GET (dic) && + getSize (aggrToPtr (operandType (IC_LEFT (dic)), FALSE)) > 1) + return NULL; + + if (POINTER_SET (dic) && + getSize (aggrToPtr (operandType (IC_RESULT (dic)), FALSE)) > 1) + return NULL; + + /* if any three is a true symbol in far space */ + if (IC_RESULT (dic) && + IS_TRUE_SYMOP (IC_RESULT (dic)) && + isOperandInFarSpace (IC_RESULT (dic))) + return NULL; + + if (IC_RIGHT (dic) && + IS_TRUE_SYMOP (IC_RIGHT (dic)) && + isOperandInFarSpace (IC_RIGHT (dic)) && + !isOperandEqual (IC_RIGHT (dic), IC_RESULT (ic))) + return NULL; + + if (IC_LEFT (dic) && + IS_TRUE_SYMOP (IC_LEFT (dic)) && + isOperandInFarSpace (IC_LEFT (dic)) && + !isOperandEqual (IC_LEFT (dic), IC_RESULT (ic))) + return NULL; + + if (isOperandEqual (IC_RIGHT (ic), IC_RESULT (dic))) + { + if ((dic->op == LEFT_OP || + dic->op == RIGHT_OP || + dic->op == '-') && + IS_OP_LITERAL (IC_RIGHT (dic))) + return NULL; + else + return dic; + } + } + + return NULL; +} + +/*-----------------------------------------------------------------*/ +/* packRegsForAssign - register reduction for assignment */ +/*-----------------------------------------------------------------*/ +static int +packRegsForAssign (iCode * ic, eBBlock * ebp) +{ + + iCode *dic, *sic; + + debugLog ("%s\n", __FUNCTION__); + + debugAopGet (" result:", IC_RESULT (ic)); + debugAopGet (" left:", IC_LEFT (ic)); + debugAopGet (" right:", IC_RIGHT (ic)); + + /* if this is at an absolute address, then get the address. */ + if (SPEC_ABSA ( OP_SYM_ETYPE(IC_RESULT(ic))) ) { + if(IS_CONFIG_ADDRESS( SPEC_ADDR ( OP_SYM_ETYPE(IC_RESULT(ic))))) { + debugLog (" %d - found config word declaration\n", __LINE__); + if(IS_VALOP(IC_RIGHT(ic))) { + debugLog (" setting config word to %x\n", + (int) floatFromVal (IC_RIGHT(ic)->operand.valOperand)); + pic16_assignConfigWordValue( SPEC_ADDR ( OP_SYM_ETYPE(IC_RESULT(ic))), + (int) floatFromVal (IC_RIGHT(ic)->operand.valOperand)); + } + + /* remove the assignment from the iCode chain. */ + + remiCodeFromeBBlock (ebp, ic); + bitVectUnSetBit(OP_SYMBOL(IC_RESULT(ic))->defs,ic->key); + hTabDeleteItem (&iCodehTab, ic->key, ic, DELETE_ITEM, NULL); + + return 1; + + } + } + + if (!IS_ITEMP (IC_RESULT (ic))) { + pic16_allocDirReg(IC_RESULT (ic)); + debugLog (" %d - result is not temp\n", __LINE__); + } +/* + if (IC_LEFT (ic) && !IS_ITEMP (IC_LEFT (ic))) { + debugLog (" %d - left is not temp, allocating\n", __LINE__); + pic16_allocDirReg(IC_LEFT (ic)); + } +*/ + + if (!IS_ITEMP (IC_RIGHT (ic))) { + debugLog (" %d - not packing - right is not temp\n", __LINE__); + pic16_allocDirReg(IC_RIGHT (ic)); + return 0; + } + + if (OP_SYMBOL (IC_RIGHT (ic))->isind || + OP_LIVETO (IC_RIGHT (ic)) > ic->seq) + { + debugLog (" %d - not packing - right side fails \n", __LINE__); + return 0; + } + + /* if the true symbol is defined in far space or on stack + then we should not since this will increase register pressure */ + if (isOperandInFarSpace (IC_RESULT (ic))) + { + if ((dic = farSpacePackable (ic))) + goto pack; + else + return 0; + + } + /* find the definition of iTempNN scanning backwards if we find a + a use of the true symbol before we find the definition then + we cannot pack */ + for (dic = ic->prev; dic; dic = dic->prev) + { + + /* if there is a function call and this is + a parameter & not my parameter then don't pack it */ + if ((dic->op == CALL || dic->op == PCALL) && + (OP_SYMBOL (IC_RESULT (ic))->_isparm && + !OP_SYMBOL (IC_RESULT (ic))->ismyparm)) + { + debugLog (" %d - \n", __LINE__); + dic = NULL; + break; + } + + if (SKIP_IC2 (dic)) + continue; + + if (IS_TRUE_SYMOP (IC_RESULT (dic)) && + IS_OP_VOLATILE (IC_RESULT (dic))) + { + debugLog (" %d - dic is VOLATILE \n", __LINE__); + dic = NULL; + break; + } + + if (IS_SYMOP (IC_RESULT (dic)) && + IC_RESULT (dic)->key == IC_RIGHT (ic)->key) + { + /* A previous result was assigned to the same register - we'll our definition */ + debugLog (" %d - dic result key == ic right key -- pointer set=%c\n", + __LINE__, ((POINTER_SET (dic)) ? 'Y' : 'N')); + if (POINTER_SET (dic)) + dic = NULL; + + break; + } + + if (IS_SYMOP (IC_RIGHT (dic)) && + (IC_RIGHT (dic)->key == IC_RESULT (ic)->key || + IC_RIGHT (dic)->key == IC_RIGHT (ic)->key)) + { + debugLog (" %d - dic right key == ic rightor result key\n", __LINE__); + dic = NULL; + break; + } + + if (IS_SYMOP (IC_LEFT (dic)) && + (IC_LEFT (dic)->key == IC_RESULT (ic)->key || + IC_LEFT (dic)->key == IC_RIGHT (ic)->key)) + { + debugLog (" %d - dic left key == ic rightor result key\n", __LINE__); + dic = NULL; + break; + } + + if (POINTER_SET (dic) && + IC_RESULT (dic)->key == IC_RESULT (ic)->key) + { + debugLog (" %d - dic result key == ic result key -- pointer set=Y\n", + __LINE__); + dic = NULL; + break; + } + } + + if (!dic) + return 0; /* did not find */ + + /* if the result is on stack or iaccess then it must be + the same atleast one of the operands */ + if (OP_SYMBOL (IC_RESULT (ic))->onStack || + OP_SYMBOL (IC_RESULT (ic))->iaccess) + { + + /* the operation has only one symbol + operator then we can pack */ + if ((IC_LEFT (dic) && !IS_SYMOP (IC_LEFT (dic))) || + (IC_RIGHT (dic) && !IS_SYMOP (IC_RIGHT (dic)))) + goto pack; + + if (!((IC_LEFT (dic) && + IC_RESULT (ic)->key == IC_LEFT (dic)->key) || + (IC_RIGHT (dic) && + IC_RESULT (ic)->key == IC_RIGHT (dic)->key))) + return 0; + } +pack: + debugLog (" packing. removing %s\n", OP_SYMBOL (IC_RIGHT (ic))->rname); + debugLog (" replacing with %s\n", OP_SYMBOL (IC_RESULT (dic))->rname); + /* found the definition */ + /* replace the result with the result of */ + /* this assignment and remove this assignment */ + bitVectUnSetBit(OP_SYMBOL(IC_RESULT(dic))->defs,dic->key); + IC_RESULT (dic) = IC_RESULT (ic); + + if (IS_ITEMP (IC_RESULT (dic)) && OP_SYMBOL (IC_RESULT (dic))->liveFrom > dic->seq) + { + OP_SYMBOL (IC_RESULT (dic))->liveFrom = dic->seq; + } + /* delete from liverange table also + delete from all the points inbetween and the new + one */ + for (sic = dic; sic != ic; sic = sic->next) + { + bitVectUnSetBit (sic->rlive, IC_RESULT (ic)->key); + if (IS_ITEMP (IC_RESULT (dic))) + bitVectSetBit (sic->rlive, IC_RESULT (dic)->key); + } + + remiCodeFromeBBlock (ebp, ic); + bitVectUnSetBit(OP_SYMBOL(IC_RESULT(ic))->defs,ic->key); + hTabDeleteItem (&iCodehTab, ic->key, ic, DELETE_ITEM, NULL); + OP_DEFS (IC_RESULT (dic)) = bitVectSetBit (OP_DEFS (IC_RESULT (dic)), dic->key); + return 1; + + +} + +/*-----------------------------------------------------------------*/ +/* findAssignToSym : scanning backwards looks for first assig found */ +/*-----------------------------------------------------------------*/ +static iCode * +findAssignToSym (operand * op, iCode * ic) +{ + iCode *dic; + + debugLog ("%s\n", __FUNCTION__); + for (dic = ic->prev; dic; dic = dic->prev) + { + + /* if definition by assignment */ + if (dic->op == '=' && + !POINTER_SET (dic) && + IC_RESULT (dic)->key == op->key +/* && IS_TRUE_SYMOP(IC_RIGHT(dic)) */ + ) + { + + /* we are interested only if defined in far space */ + /* or in stack space in case of + & - */ + + /* if assigned to a non-symbol then return + true */ + if (!IS_SYMOP (IC_RIGHT (dic))) + break; + + /* if the symbol is in far space then + we should not */ + if (isOperandInFarSpace (IC_RIGHT (dic))) + return NULL; + + /* for + & - operations make sure that + if it is on the stack it is the same + as one of the three operands */ + if ((ic->op == '+' || ic->op == '-') && + OP_SYMBOL (IC_RIGHT (dic))->onStack) + { + + if (IC_RESULT (ic)->key != IC_RIGHT (dic)->key && + IC_LEFT (ic)->key != IC_RIGHT (dic)->key && + IC_RIGHT (ic)->key != IC_RIGHT (dic)->key) + return NULL; + } + + break; + + } + + /* if we find an usage then we cannot delete it */ + if (IC_LEFT (dic) && IC_LEFT (dic)->key == op->key) + return NULL; + + if (IC_RIGHT (dic) && IC_RIGHT (dic)->key == op->key) + return NULL; + + if (POINTER_SET (dic) && IC_RESULT (dic)->key == op->key) + return NULL; + } + + /* now make sure that the right side of dic + is not defined between ic & dic */ + if (dic) + { + iCode *sic = dic->next; + + for (; sic != ic; sic = sic->next) + if (IC_RESULT (sic) && + IC_RESULT (sic)->key == IC_RIGHT (dic)->key) + return NULL; + } + + return dic; + + +} + +/*-----------------------------------------------------------------*/ +/* packRegsForSupport :- reduce some registers for support calls */ +/*-----------------------------------------------------------------*/ +static int +packRegsForSupport (iCode * ic, eBBlock * ebp) +{ + int change = 0; + + debugLog ("%s\n", __FUNCTION__); + /* for the left & right operand :- look to see if the + left was assigned a true symbol in far space in that + case replace them */ + if (IS_ITEMP (IC_LEFT (ic)) && + OP_SYMBOL (IC_LEFT (ic))->liveTo <= ic->seq) + { + iCode *dic = findAssignToSym (IC_LEFT (ic), ic); + iCode *sic; + + if (!dic) + goto right; + + debugAopGet ("removing left:", IC_LEFT (ic)); + + /* found it we need to remove it from the + block */ + for (sic = dic; sic != ic; sic = sic->next) + bitVectUnSetBit (sic->rlive, IC_LEFT (ic)->key); + + IC_LEFT (ic)->operand.symOperand = + IC_RIGHT (dic)->operand.symOperand; + IC_LEFT (ic)->key = IC_RIGHT (dic)->operand.symOperand->key; + remiCodeFromeBBlock (ebp, dic); + bitVectUnSetBit(OP_SYMBOL(IC_RESULT(dic))->defs,dic->key); + hTabDeleteItem (&iCodehTab, dic->key, dic, DELETE_ITEM, NULL); + change++; + } + + /* do the same for the right operand */ +right: + if (!change && + IS_ITEMP (IC_RIGHT (ic)) && + OP_SYMBOL (IC_RIGHT (ic))->liveTo <= ic->seq) + { + iCode *dic = findAssignToSym (IC_RIGHT (ic), ic); + iCode *sic; + + if (!dic) + return change; + + /* if this is a subtraction & the result + is a true symbol in far space then don't pack */ + if (ic->op == '-' && IS_TRUE_SYMOP (IC_RESULT (dic))) + { + sym_link *etype = getSpec (operandType (IC_RESULT (dic))); + if (IN_FARSPACE (SPEC_OCLS (etype))) + return change; + } + + debugAopGet ("removing right:", IC_RIGHT (ic)); + + /* found it we need to remove it from the + block */ + for (sic = dic; sic != ic; sic = sic->next) + bitVectUnSetBit (sic->rlive, IC_RIGHT (ic)->key); + + IC_RIGHT (ic)->operand.symOperand = + IC_RIGHT (dic)->operand.symOperand; + IC_RIGHT (ic)->key = IC_RIGHT (dic)->operand.symOperand->key; + + remiCodeFromeBBlock (ebp, dic); + bitVectUnSetBit(OP_SYMBOL(IC_RESULT(dic))->defs,dic->key); + hTabDeleteItem (&iCodehTab, dic->key, dic, DELETE_ITEM, NULL); + change++; + } + + return change; +} + +#define IS_OP_RUONLY(x) (x && IS_SYMOP(x) && OP_SYMBOL(x)->ruonly) + + +/*-----------------------------------------------------------------*/ +/* packRegsForOneuse : - will reduce some registers for single Use */ +/*-----------------------------------------------------------------*/ +static iCode * +packRegsForOneuse (iCode * ic, operand * op, eBBlock * ebp) +{ + bitVect *uses; + iCode *dic, *sic; + + debugLog ("%s\n", __FUNCTION__); + /* if returning a literal then do nothing */ + if (!IS_SYMOP (op)) + return NULL; + + /* only upto 2 bytes since we cannot predict + the usage of b, & acc */ + if (getSize (operandType (op)) > (pic16_fReturnSizePic - 2) && + ic->op != RETURN && + ic->op != SEND) + return NULL; + + /* this routine will mark the a symbol as used in one + instruction use only && if the definition is local + (ie. within the basic block) && has only one definition && + that definition is either a return value from a + function or does not contain any variables in + far space */ + uses = bitVectCopy (OP_USES (op)); + bitVectUnSetBit (uses, ic->key); /* take away this iCode */ + if (!bitVectIsZero (uses)) /* has other uses */ + return NULL; + + /* if it has only one defintion */ + if (bitVectnBitsOn (OP_DEFS (op)) > 1) + return NULL; /* has more than one definition */ + + /* get that definition */ + if (!(dic = + hTabItemWithKey (iCodehTab, + bitVectFirstBit (OP_DEFS (op))))) + return NULL; + + /* found the definition now check if it is local */ + if (dic->seq < ebp->fSeq || + dic->seq > ebp->lSeq) + return NULL; /* non-local */ + + /* now check if it is the return from + a function call */ + if (dic->op == CALL || dic->op == PCALL) + { + if (ic->op != SEND && ic->op != RETURN && + !POINTER_SET(ic) && !POINTER_GET(ic)) + { + OP_SYMBOL (op)->ruonly = 1; + return dic; + } + dic = dic->next; + } + + + /* otherwise check that the definition does + not contain any symbols in far space */ + if (isOperandInFarSpace (IC_LEFT (dic)) || + isOperandInFarSpace (IC_RIGHT (dic)) || + IS_OP_RUONLY (IC_LEFT (ic)) || + IS_OP_RUONLY (IC_RIGHT (ic))) + { + return NULL; + } + + /* if pointer set then make sure the pointer + is one byte */ + if (POINTER_SET (dic) && + !IS_DATA_PTR (aggrToPtr (operandType (IC_RESULT (dic)), FALSE))) + return NULL; + + if (POINTER_GET (dic) && + !IS_DATA_PTR (aggrToPtr (operandType (IC_LEFT (dic)), FALSE))) + return NULL; + + sic = dic; + + /* also make sure the intervenening instructions + don't have any thing in far space */ + for (dic = dic->next; dic && dic != ic; dic = dic->next) + { + + /* if there is an intervening function call then no */ + if (dic->op == CALL || dic->op == PCALL) + return NULL; + /* if pointer set then make sure the pointer + is one byte */ + if (POINTER_SET (dic) && + !IS_DATA_PTR (aggrToPtr (operandType (IC_RESULT (dic)), FALSE))) + return NULL; + + if (POINTER_GET (dic) && + !IS_DATA_PTR (aggrToPtr (operandType (IC_LEFT (dic)), FALSE))) + return NULL; + + /* if address of & the result is remat then okay */ + if (dic->op == ADDRESS_OF && + OP_SYMBOL (IC_RESULT (dic))->remat) + continue; + + /* if operand has size of three or more & this + operation is a '*','/' or '%' then 'b' may + cause a problem */ + if ((dic->op == '%' || dic->op == '/' || dic->op == '*') && + getSize (operandType (op)) >= 3) + return NULL; + + /* if left or right or result is in far space */ + if (isOperandInFarSpace (IC_LEFT (dic)) || + isOperandInFarSpace (IC_RIGHT (dic)) || + isOperandInFarSpace (IC_RESULT (dic)) || + IS_OP_RUONLY (IC_LEFT (dic)) || + IS_OP_RUONLY (IC_RIGHT (dic)) || + IS_OP_RUONLY (IC_RESULT (dic))) + { + return NULL; + } + } + + OP_SYMBOL (op)->ruonly = 1; + return sic; + +} + +/*-----------------------------------------------------------------*/ +/* isBitwiseOptimizable - requirements of JEAN LOUIS VERN */ +/*-----------------------------------------------------------------*/ +static bool +isBitwiseOptimizable (iCode * ic) +{ + sym_link *ltype = getSpec (operandType (IC_LEFT (ic))); + sym_link *rtype = getSpec (operandType (IC_RIGHT (ic))); + + debugLog ("%s\n", __FUNCTION__); + /* bitwise operations are considered optimizable + under the following conditions (Jean-Louis VERN) + + x & lit + bit & bit + bit & x + bit ^ bit + bit ^ x + x ^ lit + x | lit + bit | bit + bit | x + */ + if (IS_LITERAL (rtype) || + (IS_BITVAR (ltype) && IN_BITSPACE (SPEC_OCLS (ltype)))) + return TRUE; + else + return FALSE; +} + +/*-----------------------------------------------------------------*/ +/* packRegsForAccUse - pack registers for acc use */ +/*-----------------------------------------------------------------*/ +static void +packRegsForAccUse (iCode * ic) +{ + iCode *uic; + + debugLog ("%s\n", __FUNCTION__); + + /* if this is an aggregate, e.g. a one byte char array */ + if (IS_AGGREGATE(operandType(IC_RESULT(ic)))) { + return; + } + debugLog (" %s:%d\n", __FUNCTION__,__LINE__); + + /* if + or - then it has to be one byte result */ + if ((ic->op == '+' || ic->op == '-') + && getSize (operandType (IC_RESULT (ic))) > 1) + return; + + debugLog (" %s:%d\n", __FUNCTION__,__LINE__); + /* if shift operation make sure right side is not a literal */ + if (ic->op == RIGHT_OP && + (isOperandLiteral (IC_RIGHT (ic)) || + getSize (operandType (IC_RESULT (ic))) > 1)) + return; + + if (ic->op == LEFT_OP && + (isOperandLiteral (IC_RIGHT (ic)) || + getSize (operandType (IC_RESULT (ic))) > 1)) + return; + + if (IS_BITWISE_OP (ic) && + getSize (operandType (IC_RESULT (ic))) > 1) + return; + + + /* has only one definition */ + if (bitVectnBitsOn (OP_DEFS (IC_RESULT (ic))) > 1) + return; + + /* has only one use */ + if (bitVectnBitsOn (OP_USES (IC_RESULT (ic))) > 1) + return; + + /* and the usage immediately follows this iCode */ + if (!(uic = hTabItemWithKey (iCodehTab, + bitVectFirstBit (OP_USES (IC_RESULT (ic)))))) + return; + + debugLog (" %s:%d\n", __FUNCTION__,__LINE__); + if (ic->next != uic) + return; + + /* if it is a conditional branch then we definitely can */ + if (uic->op == IFX) + goto accuse; + + if (uic->op == JUMPTABLE) + return; + + /* if the usage is not is an assignment + or an arithmetic / bitwise / shift operation then not */ + if (POINTER_SET (uic) && + getSize (aggrToPtr (operandType (IC_RESULT (uic)), FALSE)) > 1) + return; + + debugLog (" %s:%d\n", __FUNCTION__,__LINE__); + if (uic->op != '=' && + !IS_ARITHMETIC_OP (uic) && + !IS_BITWISE_OP (uic) && + uic->op != LEFT_OP && + uic->op != RIGHT_OP) + return; + + debugLog (" %s:%d\n", __FUNCTION__,__LINE__); + /* if used in ^ operation then make sure right is not a + literl */ + if (uic->op == '^' && isOperandLiteral (IC_RIGHT (uic))) + return; + + /* if shift operation make sure right side is not a literal */ + if (uic->op == RIGHT_OP && + (isOperandLiteral (IC_RIGHT (uic)) || + getSize (operandType (IC_RESULT (uic))) > 1)) + return; + + if (uic->op == LEFT_OP && + (isOperandLiteral (IC_RIGHT (uic)) || + getSize (operandType (IC_RESULT (uic))) > 1)) + return; + + /* make sure that the result of this icode is not on the + stack, since acc is used to compute stack offset */ + if (IS_TRUE_SYMOP (IC_RESULT (uic)) && + OP_SYMBOL (IC_RESULT (uic))->onStack) + return; + + /* if either one of them in far space then we cannot */ + if ((IS_TRUE_SYMOP (IC_LEFT (uic)) && + isOperandInFarSpace (IC_LEFT (uic))) || + (IS_TRUE_SYMOP (IC_RIGHT (uic)) && + isOperandInFarSpace (IC_RIGHT (uic)))) + return; + + /* if the usage has only one operand then we can */ + if (IC_LEFT (uic) == NULL || + IC_RIGHT (uic) == NULL) + goto accuse; + + /* make sure this is on the left side if not + a '+' since '+' is commutative */ + if (ic->op != '+' && + IC_LEFT (uic)->key != IC_RESULT (ic)->key) + return; + + debugLog (" %s:%d\n", __FUNCTION__,__LINE__); + /* if one of them is a literal then we can */ + if ( ((IC_LEFT (uic) && IS_OP_LITERAL (IC_LEFT (uic))) || + (IC_RIGHT (uic) && IS_OP_LITERAL (IC_RIGHT (uic)))) && + (getSize (operandType (IC_RESULT (uic))) <= 1)) + { + OP_SYMBOL (IC_RESULT (ic))->accuse = 1; + return; + } + + debugLog (" %s:%d\n", __FUNCTION__,__LINE__); + /* if the other one is not on stack then we can */ + if (IC_LEFT (uic)->key == IC_RESULT (ic)->key && + (IS_ITEMP (IC_RIGHT (uic)) || + (IS_TRUE_SYMOP (IC_RIGHT (uic)) && + !OP_SYMBOL (IC_RIGHT (uic))->onStack))) + goto accuse; + + if (IC_RIGHT (uic)->key == IC_RESULT (ic)->key && + (IS_ITEMP (IC_LEFT (uic)) || + (IS_TRUE_SYMOP (IC_LEFT (uic)) && + !OP_SYMBOL (IC_LEFT (uic))->onStack))) + goto accuse; + + return; + +accuse: + debugLog ("%s - Yes we are using the accumulator\n", __FUNCTION__); + OP_SYMBOL (IC_RESULT (ic))->accuse = 1; + + +} + +/*-----------------------------------------------------------------*/ +/* packForPush - hueristics to reduce iCode for pushing */ +/*-----------------------------------------------------------------*/ +static void +packForReceive (iCode * ic, eBBlock * ebp) +{ + iCode *dic; + + debugLog ("%s\n", __FUNCTION__); + debugAopGet (" result:", IC_RESULT (ic)); + debugAopGet (" left:", IC_LEFT (ic)); + debugAopGet (" right:", IC_RIGHT (ic)); + + if (!ic->next) + return; + + for (dic = ic->next; dic; dic = dic->next) + { + + + + if (IC_LEFT (dic) && (IC_RESULT (ic)->key == IC_LEFT (dic)->key)) + debugLog (" used on left\n"); + if (IC_RIGHT (dic) && IC_RESULT (ic)->key == IC_RIGHT (dic)->key) + debugLog (" used on right\n"); + if (IC_RESULT (dic) && IC_RESULT (ic)->key == IC_RESULT (dic)->key) + debugLog (" used on result\n"); + + if ((IC_LEFT (dic) && (IC_RESULT (ic)->key == IC_LEFT (dic)->key)) || + (IC_RESULT (dic) && IC_RESULT (ic)->key == IC_RESULT (dic)->key)) + return; + + } + + debugLog (" hey we can remove this unnecessary assign\n"); +} +/*-----------------------------------------------------------------*/ +/* packForPush - hueristics to reduce iCode for pushing */ +/*-----------------------------------------------------------------*/ +static void +packForPush (iCode * ic, eBBlock * ebp) +{ + iCode *dic; + + debugLog ("%s\n", __FUNCTION__); + if (ic->op != IPUSH || !IS_ITEMP (IC_LEFT (ic))) + return; + + /* must have only definition & one usage */ + if (bitVectnBitsOn (OP_DEFS (IC_LEFT (ic))) != 1 || + bitVectnBitsOn (OP_USES (IC_LEFT (ic))) != 1) + return; + + /* find the definition */ + if (!(dic = hTabItemWithKey (iCodehTab, + bitVectFirstBit (OP_DEFS (IC_LEFT (ic)))))) + return; + + if (dic->op != '=' || POINTER_SET (dic)) + return; + + /* we now we know that it has one & only one def & use + and the that the definition is an assignment */ + IC_LEFT (ic) = IC_RIGHT (dic); + + remiCodeFromeBBlock (ebp, dic); + bitVectUnSetBit(OP_SYMBOL(IC_RESULT(dic))->defs,dic->key); + hTabDeleteItem (&iCodehTab, dic->key, dic, DELETE_ITEM, NULL); +} + +static void printSymType(char * str, sym_link *sl) +{ + debugLog (" %s Symbol type: ",str); + printTypeChain( sl, debugF); + debugLog ("\n"); + +} + +/*-----------------------------------------------------------------*/ +/* some debug code to print the symbol S_TYPE. Note that + * the function checkSClass in src/SDCCsymt.c dinks with + * the S_TYPE in ways the PIC port doesn't fully like...*/ +/*-----------------------------------------------------------------*/ +static void isData(sym_link *sl) +{ + FILE *of = stderr; + + if(!sl) + return; + + if(debugF) + of = debugF; + + for ( ; sl; sl=sl->next) { + if(!IS_DECL(sl) ) { + switch (SPEC_SCLS(sl)) { + + case S_DATA: fprintf (of, "data "); break; + case S_XDATA: fprintf (of, "xdata "); break; + case S_SFR: fprintf (of, "sfr "); break; + case S_SBIT: fprintf (of, "sbit "); break; + case S_CODE: fprintf (of, "code "); break; + case S_IDATA: fprintf (of, "idata "); break; + case S_PDATA: fprintf (of, "pdata "); break; + case S_LITERAL: fprintf (of, "literal "); break; + case S_STACK: fprintf (of, "stack "); break; + case S_XSTACK: fprintf (of, "xstack "); break; + case S_BIT: fprintf (of, "bit "); break; + case S_EEPROM: fprintf (of, "eeprom "); break; + default: break; + } + + } + + } + +} +/*-----------------------------------------------------------------*/ +/* packRegisters - does some transformations to reduce register */ +/* pressure */ +/*-----------------------------------------------------------------*/ +static void +packRegisters (eBBlock * ebp) +{ + iCode *ic; + int change = 0; + + debugLog ("%s\n", __FUNCTION__); + + while (1) { + + change = 0; + + /* look for assignments of the form */ + /* iTempNN = TRueSym (someoperation) SomeOperand */ + /* .... */ + /* TrueSym := iTempNN:1 */ + for (ic = ebp->sch; ic; ic = ic->next) + { + + /* find assignment of the form TrueSym := iTempNN:1 */ + if (ic->op == '=' && !POINTER_SET (ic)) + change += packRegsForAssign (ic, ebp); + /* debug stuff */ + if (ic->op == '=') + { + if (POINTER_SET (ic)) + debugLog ("pointer is set\n"); + debugAopGet (" result:", IC_RESULT (ic)); + debugAopGet (" left:", IC_LEFT (ic)); + debugAopGet (" right:", IC_RIGHT (ic)); + } + + } + + if (!change) + break; + } + + for (ic = ebp->sch; ic; ic = ic->next) { + + if(IS_SYMOP ( IC_LEFT(ic))) { + sym_link *etype = getSpec (operandType (IC_LEFT (ic))); + + debugAopGet (" left:", IC_LEFT (ic)); + if(IS_PTR_CONST(OP_SYMBOL(IC_LEFT(ic))->type)) + debugLog (" is a pointer\n"); + + if(IS_OP_VOLATILE(IC_LEFT(ic))) + debugLog (" is volatile\n"); + + isData(etype); + + printSymType(" ", OP_SYMBOL(IC_LEFT(ic))->type); + } + + if(IS_SYMOP ( IC_RIGHT(ic))) { + debugAopGet (" right:", IC_RIGHT (ic)); + printSymType(" ", OP_SYMBOL(IC_RIGHT(ic))->type); + } + + if(IS_SYMOP ( IC_RESULT(ic))) { + debugAopGet (" result:", IC_RESULT (ic)); + printSymType(" ", OP_SYMBOL(IC_RESULT(ic))->type); + } + + if (POINTER_SET (ic)) + debugLog (" %d - Pointer set\n", __LINE__); + + + /* if this is an itemp & result of a address of a true sym + then mark this as rematerialisable */ + if (ic->op == ADDRESS_OF && + IS_ITEMP (IC_RESULT (ic)) && + IS_TRUE_SYMOP (IC_LEFT (ic)) && + bitVectnBitsOn (OP_DEFS (IC_RESULT (ic))) == 1 && + !OP_SYMBOL (IC_LEFT (ic))->onStack) + { + + debugLog (" %d - %s. result is rematerializable\n", __LINE__,__FUNCTION__); + + OP_SYMBOL (IC_RESULT (ic))->remat = 1; + OP_SYMBOL (IC_RESULT (ic))->rematiCode = ic; + OP_SYMBOL (IC_RESULT (ic))->usl.spillLoc = NULL; + + } + + /* if straight assignment then carry remat flag if + this is the only definition */ + if (ic->op == '=' && + !POINTER_SET (ic) && + IS_SYMOP (IC_RIGHT (ic)) && + OP_SYMBOL (IC_RIGHT (ic))->remat && + bitVectnBitsOn (OP_SYMBOL (IC_RESULT (ic))->defs) <= 1) + { + debugLog (" %d - %s. straight rematerializable\n", __LINE__,__FUNCTION__); + + OP_SYMBOL (IC_RESULT (ic))->remat = + OP_SYMBOL (IC_RIGHT (ic))->remat; + OP_SYMBOL (IC_RESULT (ic))->rematiCode = + OP_SYMBOL (IC_RIGHT (ic))->rematiCode; + } + + /* if this is a +/- operation with a rematerizable + then mark this as rematerializable as well */ + if ((ic->op == '+' || ic->op == '-') && + (IS_SYMOP (IC_LEFT (ic)) && + IS_ITEMP (IC_RESULT (ic)) && + OP_SYMBOL (IC_LEFT (ic))->remat && + bitVectnBitsOn (OP_DEFS (IC_RESULT (ic))) == 1 && + IS_OP_LITERAL (IC_RIGHT (ic)))) + { + debugLog (" %d - %s. rematerializable because op is +/-\n", __LINE__,__FUNCTION__); + //int i = + operandLitValue (IC_RIGHT (ic)); + OP_SYMBOL (IC_RESULT (ic))->remat = 1; + OP_SYMBOL (IC_RESULT (ic))->rematiCode = ic; + OP_SYMBOL (IC_RESULT (ic))->usl.spillLoc = NULL; + } + + /* mark the pointer usages */ + if (POINTER_SET (ic)) + { + OP_SYMBOL (IC_RESULT (ic))->uptr = 1; + debugLog (" marking as a pointer (set) =>"); + debugAopGet (" result:", IC_RESULT (ic)); + } + if (POINTER_GET (ic)) + { + OP_SYMBOL (IC_LEFT (ic))->uptr = 1; + debugLog (" marking as a pointer (get) =>"); + debugAopGet (" left:", IC_LEFT (ic)); + } + + if (!SKIP_IC2 (ic)) + { + /* if we are using a symbol on the stack + then we should say pic16_ptrRegReq */ + if (ic->op == IFX && IS_SYMOP (IC_COND (ic))) + pic16_ptrRegReq += ((OP_SYMBOL (IC_COND (ic))->onStack || + OP_SYMBOL (IC_COND (ic))->iaccess) ? 1 : 0); + else if (ic->op == JUMPTABLE && IS_SYMOP (IC_JTCOND (ic))) + pic16_ptrRegReq += ((OP_SYMBOL (IC_JTCOND (ic))->onStack || + OP_SYMBOL (IC_JTCOND (ic))->iaccess) ? 1 : 0); + else + { + if (IS_SYMOP (IC_LEFT (ic))) + pic16_ptrRegReq += ((OP_SYMBOL (IC_LEFT (ic))->onStack || + OP_SYMBOL (IC_LEFT (ic))->iaccess) ? 1 : 0); + if (IS_SYMOP (IC_RIGHT (ic))) + pic16_ptrRegReq += ((OP_SYMBOL (IC_RIGHT (ic))->onStack || + OP_SYMBOL (IC_RIGHT (ic))->iaccess) ? 1 : 0); + if (IS_SYMOP (IC_RESULT (ic))) + pic16_ptrRegReq += ((OP_SYMBOL (IC_RESULT (ic))->onStack || + OP_SYMBOL (IC_RESULT (ic))->iaccess) ? 1 : 0); + } + + debugLog (" %d - pointer reg req = %d\n", __LINE__,pic16_ptrRegReq); + + } + + /* if the condition of an if instruction + is defined in the previous instruction then + mark the itemp as a conditional */ + if ((IS_CONDITIONAL (ic) || + ((ic->op == BITWISEAND || + ic->op == '|' || + ic->op == '^') && + isBitwiseOptimizable (ic))) && + ic->next && ic->next->op == IFX && + isOperandEqual (IC_RESULT (ic), IC_COND (ic->next)) && + OP_SYMBOL (IC_RESULT (ic))->liveTo <= ic->next->seq) + { + + debugLog (" %d\n", __LINE__); + OP_SYMBOL (IC_RESULT (ic))->regType = REG_CND; + continue; + } + + /* reduce for support function calls */ + if (ic->supportRtn || ic->op == '+' || ic->op == '-') + packRegsForSupport (ic, ebp); + + /* if a parameter is passed, it's in W, so we may not + need to place a copy in a register */ + if (ic->op == RECEIVE) + packForReceive (ic, ebp); + + /* some cases the redundant moves can + can be eliminated for return statements */ + if ((ic->op == RETURN || ic->op == SEND) && + !isOperandInFarSpace (IC_LEFT (ic)) && + !options.model) + packRegsForOneuse (ic, IC_LEFT (ic), ebp); + + /* if pointer set & left has a size more than + one and right is not in far space */ + if (POINTER_SET (ic) && + !isOperandInFarSpace (IC_RIGHT (ic)) && + !OP_SYMBOL (IC_RESULT (ic))->remat && + !IS_OP_RUONLY (IC_RIGHT (ic)) && + getSize (aggrToPtr (operandType (IC_RESULT (ic)), FALSE)) > 1) + + packRegsForOneuse (ic, IC_RESULT (ic), ebp); + + /* if pointer get */ + if (POINTER_GET (ic) && + !isOperandInFarSpace (IC_RESULT (ic)) && + !OP_SYMBOL (IC_LEFT (ic))->remat && + !IS_OP_RUONLY (IC_RESULT (ic)) && + getSize (aggrToPtr (operandType (IC_LEFT (ic)), FALSE)) > 1) + + packRegsForOneuse (ic, IC_LEFT (ic), ebp); + + + /* if this is cast for intergral promotion then + check if only use of the definition of the + operand being casted/ if yes then replace + the result of that arithmetic operation with + this result and get rid of the cast */ + if (ic->op == CAST) { + + sym_link *fromType = operandType (IC_RIGHT (ic)); + sym_link *toType = operandType (IC_LEFT (ic)); + + debugLog (" %d - casting\n", __LINE__); + + if (IS_INTEGRAL (fromType) && IS_INTEGRAL (toType) && + getSize (fromType) != getSize (toType)) { + + + iCode *dic = packRegsForOneuse (ic, IC_RIGHT (ic), ebp); + if (dic) { + + if (IS_ARITHMETIC_OP (dic)) { + + bitVectUnSetBit(OP_SYMBOL(IC_RESULT(dic))->defs,dic->key); + IC_RESULT (dic) = IC_RESULT (ic); + remiCodeFromeBBlock (ebp, ic); + bitVectUnSetBit(OP_SYMBOL(IC_RESULT(ic))->defs,ic->key); + hTabDeleteItem (&iCodehTab, ic->key, ic, DELETE_ITEM, NULL); + OP_DEFS (IC_RESULT (dic)) = bitVectSetBit (OP_DEFS (IC_RESULT (dic)), dic->key); + ic = ic->prev; + } else + + OP_SYMBOL (IC_RIGHT (ic))->ruonly = 0; + } + } else { + + /* if the type from and type to are the same + then if this is the only use then packit */ + if (compareType (operandType (IC_RIGHT (ic)), + operandType (IC_LEFT (ic))) == 1) { + + iCode *dic = packRegsForOneuse (ic, IC_RIGHT (ic), ebp); + if (dic) { + + bitVectUnSetBit(OP_SYMBOL(IC_RESULT(dic))->defs,dic->key); + IC_RESULT (dic) = IC_RESULT (ic); + bitVectUnSetBit(OP_SYMBOL(IC_RESULT(ic))->defs,ic->key); + remiCodeFromeBBlock (ebp, ic); + hTabDeleteItem (&iCodehTab, ic->key, ic, DELETE_ITEM, NULL); + OP_DEFS (IC_RESULT (dic)) = bitVectSetBit (OP_DEFS (IC_RESULT (dic)), dic->key); + ic = ic->prev; + } + } + } + } + + /* pack for PUSH + iTempNN := (some variable in farspace) V1 + push iTempNN ; + ------------- + push V1 + */ + if (ic->op == IPUSH) + { + packForPush (ic, ebp); + } + + + /* pack registers for accumulator use, when the + result of an arithmetic or bit wise operation + has only one use, that use is immediately following + the defintion and the using iCode has only one + operand or has two operands but one is literal & + the result of that operation is not on stack then + we can leave the result of this operation in acc:b + combination */ + if ((IS_ARITHMETIC_OP (ic) + + || IS_BITWISE_OP (ic) + + || ic->op == LEFT_OP || ic->op == RIGHT_OP + + ) && + IS_ITEMP (IC_RESULT (ic)) && + getSize (operandType (IC_RESULT (ic))) <= 2) + + packRegsForAccUse (ic); + + } +} + +static void +dumpEbbsToDebug (eBBlock ** ebbs, int count) +{ + int i; + + if (!debug || !debugF) + return; + + for (i = 0; i < count; i++) + { + fprintf (debugF, "\n----------------------------------------------------------------\n"); + fprintf (debugF, "Basic Block %s : loop Depth = %d noPath = %d , lastinLoop = %d\n", + ebbs[i]->entryLabel->name, + ebbs[i]->depth, + ebbs[i]->noPath, + ebbs[i]->isLastInLoop); + fprintf (debugF, "depth 1st num %d : bbnum = %d 1st iCode = %d , last iCode = %d\n", + ebbs[i]->dfnum, + ebbs[i]->bbnum, + ebbs[i]->fSeq, + ebbs[i]->lSeq); + fprintf (debugF, "visited %d : hasFcall = %d\n", + ebbs[i]->visited, + ebbs[i]->hasFcall); + + fprintf (debugF, "\ndefines bitVector :"); + bitVectDebugOn (ebbs[i]->defSet, debugF); + fprintf (debugF, "\nlocal defines bitVector :"); + bitVectDebugOn (ebbs[i]->ldefs, debugF); + fprintf (debugF, "\npointers Set bitvector :"); + bitVectDebugOn (ebbs[i]->ptrsSet, debugF); + fprintf (debugF, "\nin pointers Set bitvector :"); + bitVectDebugOn (ebbs[i]->inPtrsSet, debugF); + fprintf (debugF, "\ninDefs Set bitvector :"); + bitVectDebugOn (ebbs[i]->inDefs, debugF); + fprintf (debugF, "\noutDefs Set bitvector :"); + bitVectDebugOn (ebbs[i]->outDefs, debugF); + fprintf (debugF, "\nusesDefs Set bitvector :"); + bitVectDebugOn (ebbs[i]->usesDefs, debugF); + fprintf (debugF, "\n----------------------------------------------------------------\n"); + printiCChain (ebbs[i]->sch, debugF); + } +} +/*-----------------------------------------------------------------*/ +/* pic16_assignRegisters - assigns registers to each live range as need */ +/*-----------------------------------------------------------------*/ +void +pic16_assignRegisters (eBBlock ** ebbs, int count) +{ + iCode *ic; + int i; + + debugLog ("<><><><><><><><><><><><><><><><><>\nstarting\t%s:%s", __FILE__, __FUNCTION__); + debugLog ("\nebbs before optimizing:\n"); + dumpEbbsToDebug (ebbs, count); + + setToNull ((void *) &_G.funcrUsed); + pic16_ptrRegReq = _G.stackExtend = _G.dataExtend = 0; + + + /* change assignments this will remove some + live ranges reducing some register pressure */ + for (i = 0; i < count; i++) + packRegisters (ebbs[i]); + + { + regs *reg; + int hkey; + int i=0; + + debugLog("dir registers allocated so far:\n"); + reg = hTabFirstItem(dynDirectRegNames, &hkey); + + while(reg) { + debugLog(" -- #%d reg = %s key %d, rIdx = %d, size %d\n",i++,reg->name,hkey, reg->rIdx,reg->size); + reg = hTabNextItem(dynDirectRegNames, &hkey); + } + + } + + if (options.dump_pack) + dumpEbbsToFileExt (DUMP_PACK, ebbs, count); + + /* first determine for each live range the number of + registers & the type of registers required for each */ + regTypeNum (); + + /* and serially allocate registers */ + serialRegAssign (ebbs, count); + + /* if stack was extended then tell the user */ + if (_G.stackExtend) + { +/* werror(W_TOOMANY_SPILS,"stack", */ +/* _G.stackExtend,currFunc->name,""); */ + _G.stackExtend = 0; + } + + if (_G.dataExtend) + { +/* werror(W_TOOMANY_SPILS,"data space", */ +/* _G.dataExtend,currFunc->name,""); */ + _G.dataExtend = 0; + } + + /* after that create the register mask + for each of the instruction */ + createRegMask (ebbs, count); + + /* redo that offsets for stacked automatic variables */ + redoStackOffsets (); + + if (options.dump_rassgn) + dumpEbbsToFileExt (DUMP_RASSGN, ebbs, count); + + /* now get back the chain */ + ic = iCodeLabelOptimize (iCodeFromeBBlock (ebbs, count)); + + debugLog ("ebbs after optimizing:\n"); + dumpEbbsToDebug (ebbs, count); + + + genpic16Code (ic); + + /* free up any _G.stackSpil locations allocated */ + applyToSet (_G.stackSpil, deallocStackSpil); + _G.slocNum = 0; + setToNull ((void **) &_G.stackSpil); + setToNull ((void **) &_G.spiltSet); + /* mark all registers as free */ + //pic16_freeAllRegs (); + + debugLog ("leaving\n<><><><><><><><><><><><><><><><><>\n"); + debugLogClose (); + return; +} diff --git a/src/pic16/ralloc.h b/src/pic16/ralloc.h new file mode 100644 index 00000000..cf91c043 --- /dev/null +++ b/src/pic16/ralloc.h @@ -0,0 +1,127 @@ +/*------------------------------------------------------------------------- + + SDCCralloc.h - header file register allocation + + Written By - Sandeep Dutta . sandeep.dutta@usa.net (1998) + PIC port - T. Scott Dattalo scott@dattalo.com (2000) + PIC16 port - Martin Dubuc m.dubuc@rogers.com (2002) + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! +-------------------------------------------------------------------------*/ +#include "SDCCicode.h" +#include "SDCCBBlock.h" +#ifndef SDCCRALLOC_H +#define SDCCRALLOC_H 1 + +#include "pcoderegs.h" + + +enum + { + R2_IDX = 0, R3_IDX, R4_IDX, + R5_IDX, R6_IDX, R7_IDX, + R0_IDX, R1_IDX, X8_IDX, + X9_IDX, X10_IDX, X11_IDX, + X12_IDX, CND_IDX + }; + +enum { + REG_PTR=1, + REG_GPR, + REG_CND, + REG_SFR, + REG_STK, + REG_TMP +}; +//#define REG_PTR 0x01 +//#define REG_GPR 0x02 +//#define REG_CND 0x04 +//#define REG_SFR 0x08 +//#define REG_STK 0x10 /* Use a register as a psuedo stack */ +//#define REG_TMP 0x20 + +/* definition for the registers */ +typedef struct regs + { + short type; /* can have value + * REG_GPR, REG_PTR or REG_CND + * This like the "meta-type" */ + short pc_type; /* pcode type */ + short rIdx; /* index into register table */ + // short otype; + char *name; /* name */ + + unsigned isFree:1; /* is currently unassigned */ + unsigned wasUsed:1; /* becomes true if register has been used */ + unsigned isFixed:1; /* True if address can't change */ + unsigned isMapped:1; /* The Register's address has been mapped to physical RAM */ + unsigned isBitField:1; /* True if reg is type bit OR is holder for several bits */ + unsigned isEmitted:1; /* True if the reg has been written to a .asm file */ + unsigned address; /* reg's address if isFixed | isMapped is true */ + unsigned size; /* 0 for byte, 1 for int, 4 for long */ + unsigned alias; /* Alias mask if register appears in multiple banks */ + struct regs *reg_alias; /* If more than one register share the same address + * then they'll point to each other. (primarily for bits)*/ + pCodeRegLives reglives; /* live range mapping */ + } +regs; +extern regs regspic16[]; +extern int pic16_nRegs; +extern int pic16_Gstack_base_addr; + +/* + As registers are created, they're added to a set (based on the + register type). Here are the sets of registers that are supported + in the PIC port: +*/ +extern set *pic16_dynAllocRegs; +extern set *pic16_dynStackRegs; +extern set *pic16_dynProcessorRegs; +extern set *pic16_dynDirectRegs; +extern set *pic16_dynDirectBitRegs; +extern set *pic16_dynInternalRegs; + + +regs *pic16_regWithIdx (int); +regs *pic16_dirregWithName (char *name ); +void pic16_freeAllRegs (); +void pic16_deallocateAllRegs (); +regs *pic16_findFreeReg(short type); +regs *pic16_allocWithIdx (int idx); + +regs *pic16_allocDirReg (operand *op ); +regs *pic16_allocRegByName (char *name, int size ); + +/* Define register address that are constant across PIC16 family */ +#define IDX_INDF0 0xfef +#define IDX_TMR0 0xfd6 +#define IDX_PCL 0xff9 +#define IDX_STATUS 0xfd8 +#define IDX_FSR0 0xfe9 +#define IDX_PORTA 0xf80 +#define IDX_PORTB 0xf81 +#define IDX_PCLATH 0xffa +#define IDX_INTCON 0xff2 +#define IDX_WREG 0xfe8 + +#define IDX_KZ 0x7fff /* Known zero - actually just a general purpose reg. */ +#define IDX_WSAVE 0x7ffe +#define IDX_SSAVE 0x7ffd + +#endif -- 2.30.2