summaryrefslogtreecommitdiff
path: root/src/pic14
diff options
context:
space:
mode:
Diffstat (limited to 'src/pic14')
-rw-r--r--src/pic14/Makefile7
-rw-r--r--src/pic14/Makefile.in7
-rw-r--r--src/pic14/device.c821
-rw-r--r--src/pic14/device.h94
-rw-r--r--src/pic14/gen.c7842
-rw-r--r--src/pic14/gen.h174
-rw-r--r--src/pic14/genarith.c1289
-rw-r--r--src/pic14/glue.c1206
-rw-r--r--src/pic14/glue.h36
-rw-r--r--src/pic14/main.c485
-rw-r--r--src/pic14/main.h15
-rw-r--r--src/pic14/pcode.c5985
-rw-r--r--src/pic14/pcode.h907
-rw-r--r--src/pic14/pcodeflow.c226
-rw-r--r--src/pic14/pcodeflow.h68
-rw-r--r--src/pic14/pcodepeep.c2005
-rw-r--r--src/pic14/pcoderegs.c802
-rw-r--r--src/pic14/pcoderegs.h50
-rw-r--r--src/pic14/peeph.def323
-rw-r--r--src/pic14/pic14.vcxproj192
-rw-r--r--src/pic14/pic14.vcxproj.filters79
-rw-r--r--src/pic14/ralloc.c3874
-rw-r--r--src/pic14/ralloc.h123
23 files changed, 26610 insertions, 0 deletions
diff --git a/src/pic14/Makefile b/src/pic14/Makefile
new file mode 100644
index 0000000..1c6f129
--- /dev/null
+++ b/src/pic14/Makefile
@@ -0,0 +1,7 @@
+
+srcdir = .
+top_builddir = ../..
+top_srcdir = ../..
+
+# Make all in this directory
+include $(srcdir)/../port.mk
diff --git a/src/pic14/Makefile.in b/src/pic14/Makefile.in
new file mode 100644
index 0000000..240faea
--- /dev/null
+++ b/src/pic14/Makefile.in
@@ -0,0 +1,7 @@
+VPATH = @srcdir@
+srcdir = @srcdir@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+
+# Make all in this directory
+include $(srcdir)/../port.mk
diff --git a/src/pic14/device.c b/src/pic14/device.c
new file mode 100644
index 0000000..34c9874
--- /dev/null
+++ b/src/pic14/device.c
@@ -0,0 +1,821 @@
+/*-------------------------------------------------------------------------
+
+ device.c - Accomodates subtle variations in PIC 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.
+-------------------------------------------------------------------------*/
+
+#include "device.h"
+#include "pcode.h"
+
+/*
+ * Imports
+ */
+extern set *includeDirsSet;
+extern set *userIncDirsSet;
+extern set *libDirsSet;
+extern set *libPathsSet;
+
+#define MAX_PICLIST 400
+static PIC_device *Pics[MAX_PICLIST];
+static PIC_device *pic = NULL;
+static int num_of_supported_PICS = 0;
+static int maxRAMaddress = 0;
+
+#define DEVICE_FILE_NAME "pic14devices.txt"
+#define PIC14_STRING_LEN 256
+#define SPLIT_WORDS_MAX 16
+
+/* Keep track of whether we found an assignment to the __config words. */
+static int pic14_hasSetConfigWord = 0;
+static unsigned int config_word[MAX_NUM_CONFIGS];
+static memRange *rangeRAM = NULL;
+
+
+/* parse a value from the configuration file */
+static int
+parse_config_value (char *str)
+{
+ if (str[strlen (str) - 1] == 'K')
+ return atoi (str) * 1024; /* like "1K" */
+
+ else if (STRNCASECMP (str, "0x", 2) == 0)
+ return strtol (str+2, NULL, 16); /* like "0x400" */
+
+ else
+ return atoi (str); /* like "1024" */
+}
+
+
+/* split a line into words */
+static int
+split_words (char **result_word, char *str)
+{
+ static const char delim[] = " \f\n\r\t\v,";
+ char *token;
+ int num_words;
+
+ /* release previously allocated words */
+ for (num_words = 0; num_words < SPLIT_WORDS_MAX; num_words++)
+ {
+ if (result_word[num_words])
+ {
+ free (result_word[num_words]);
+ result_word[num_words] = NULL;
+ } // if
+ } // for
+
+ /* split line */
+ token = strtok (str, delim);
+ num_words = 0;
+ while (token && (num_words < SPLIT_WORDS_MAX))
+ {
+ result_word[num_words] = Safe_strdup (token);
+ num_words++;
+ token = strtok (NULL, delim);
+ } // while
+
+ return num_words;
+}
+
+
+/* remove annoying prefixes from the processor name */
+static char *
+sanitise_processor_name (char *name)
+{
+ char *proc_pos = name;
+
+ if (name == NULL)
+ return NULL;
+
+ if (STRNCASECMP (proc_pos, "pic", 3) == 0)
+ proc_pos += 3;
+
+ else if (tolower (*proc_pos) == 'p')
+ proc_pos += 1;
+
+ return proc_pos;
+}
+
+
+/* create a structure for a pic processor */
+static PIC_device *
+create_pic (char *pic_name, int maxram, int bankmsk, int confsiz,
+ int config[MAX_NUM_CONFIGS], int program, int data, int eeprom,
+ int io, int is_enhanced)
+{
+ PIC_device *new_pic;
+ char *simple_pic_name = sanitise_processor_name (pic_name);
+
+ new_pic = Safe_alloc(sizeof(PIC_device));
+ new_pic->name = Safe_strdup(simple_pic_name);
+
+ new_pic->defMaxRAMaddrs = maxram;
+ new_pic->bankMask = bankmsk;
+ new_pic->num_configs = confsiz;
+ memcpy(new_pic->config, config, MAX_NUM_CONFIGS * sizeof(int));
+
+ new_pic->programMemSize = program;
+ new_pic->dataMemSize = data;
+ new_pic->eepromMemSize = eeprom;
+ new_pic->ioPins = io;
+ new_pic->isEnhancedCore = is_enhanced;
+
+ new_pic->ram = rangeRAM;
+
+ Pics[num_of_supported_PICS] = new_pic;
+ num_of_supported_PICS++;
+
+ return new_pic;
+}
+
+
+/* mark some registers as being duplicated across banks */
+static void
+register_map (int num_words, char **word)
+{
+ memRange *r;
+ int pcount;
+
+ if (num_words < 3)
+ {
+ fprintf (stderr, "WARNING: not enough values in %s regmap directive\n",
+ DEVICE_FILE_NAME);
+ return;
+ } // if
+
+ for (pcount = 2; pcount < num_words; pcount++)
+ {
+ r = Safe_alloc(sizeof(memRange));
+
+ r->start_address = parse_config_value (word[pcount]);
+ r->end_address = parse_config_value (word[pcount]);
+ r->alias = parse_config_value (word[1]);
+ r->bank = (r->start_address >> 7) & 3;
+ // add memRange to device entry for future lookup (sharebanks)
+ r->next = rangeRAM;
+ rangeRAM = r;
+ } // for
+}
+
+
+/* define ram areas - may be duplicated across banks */
+static void
+ram_map (int num_words, char **word)
+{
+ memRange *r;
+
+ if (num_words < 4)
+ {
+ fprintf (stderr, "WARNING: not enough values in %s memmap directive\n",
+ DEVICE_FILE_NAME);
+ return;
+ } // if
+
+ r = Safe_alloc(sizeof(memRange));
+ //fprintf (stderr, "%s: %s %s %s\n", __FUNCTION__, word[1], word[2], word[3]);
+
+ r->start_address = parse_config_value (word[1]);
+ r->end_address = parse_config_value (word[2]);
+ r->alias = parse_config_value (word[3]);
+ r->bank = (r->start_address >> 7) & 3;
+
+ // add memRange to device entry for future lookup (sharebanks)
+ r->next = rangeRAM;
+ rangeRAM = r;
+}
+
+static void
+setMaxRAM (int size)
+{
+ maxRAMaddress = size;
+
+ if (maxRAMaddress < 0)
+ {
+ fprintf (stderr, "invalid maxram 0x%x setting in %s\n",
+ maxRAMaddress, DEVICE_FILE_NAME);
+ return;
+ } // if
+}
+
+/* read the file with all the pic14 definitions and pick out the definition
+ * for a processor if specified. if pic_name is NULL reads everything */
+static PIC_device *
+find_device (char *pic_name)
+{
+ FILE *pic_file;
+ char pic_buf[PIC14_STRING_LEN];
+ int found_processor = FALSE;
+ int done = FALSE;
+ char **processor_name;
+ int num_processor_names = 0;
+ int pic_maxram = 0;
+ int pic_bankmsk = 0;
+ int pic_confsiz = 0;
+ int pic_config[MAX_NUM_CONFIGS];
+ int pic_program = 0;
+ int pic_data = 0;
+ int pic_eeprom = 0;
+ int pic_io = 0;
+ int pic_is_enhanced = 0;
+ char *simple_pic_name;
+ char *dir;
+ char filename[512];
+ int len = 512;
+ char **pic_word;
+ int num_pic_words;
+ int wcount;
+ int i;
+
+ pic_word = Safe_calloc (sizeof (char *), SPLIT_WORDS_MAX);
+ processor_name = Safe_calloc (sizeof (char *), SPLIT_WORDS_MAX);
+
+ for (i = 0; i < MAX_NUM_CONFIGS; i++)
+ {
+ config_word[i] = -1;
+ pic_config[i] = -1;
+ } // for
+
+ /* allow abbreviations of the form "f877" - convert to "16f877" */
+ simple_pic_name = sanitise_processor_name (pic_name);
+ num_of_supported_PICS = 0;
+
+ /* open the piclist file */
+ /* first scan all include directories */
+ pic_file = NULL;
+ //fprintf (stderr, "%s: searching %s\n", __FUNCTION__, DEVICE_FILE_NAME);
+ for (dir = setFirstItem (userIncDirsSet);
+ !pic_file && dir;
+ dir = setNextItem (userIncDirsSet))
+ {
+ //fprintf (stderr, "searching1 %s\n", dir);
+ SNPRINTF (&filename[0], len, "%s%s", dir,
+ DIR_SEPARATOR_STRING DEVICE_FILE_NAME);
+ pic_file = fopen (filename, "rt");
+ if (pic_file) break;
+ } // for
+
+ for (dir = setFirstItem (includeDirsSet);
+ !pic_file && dir;
+ dir = setNextItem (includeDirsSet))
+ {
+ //fprintf (stderr, "searching2 %s\n", dir);
+ SNPRINTF (&filename[0], len, "%s%s", dir,
+ DIR_SEPARATOR_STRING DEVICE_FILE_NAME);
+ pic_file = fopen (filename, "rt");
+ if (pic_file) break;
+ } // for
+
+ for (dir = setFirstItem (libDirsSet);
+ !pic_file && dir;
+ dir = setNextItem (libDirsSet))
+ {
+ //fprintf (stderr, "searching3 %s\n", dir);
+ SNPRINTF (&filename[0], len, "%s%s", dir,
+ DIR_SEPARATOR_STRING DEVICE_FILE_NAME);
+ pic_file = fopen (filename, "rt");
+ if (pic_file) break;
+ } // for
+
+ for (dir = setFirstItem (libPathsSet);
+ !pic_file && dir;
+ dir = setNextItem (libPathsSet))
+ {
+ //fprintf (stderr, "searching4 %s\n", dir);
+ SNPRINTF (&filename[0], len, "%s%s", dir,
+ DIR_SEPARATOR_STRING DEVICE_FILE_NAME);
+ pic_file = fopen (filename, "rt");
+ if (pic_file) break;
+ } // for
+
+ if (!pic_file)
+ {
+ SNPRINTF (&filename[0], len, "%s",
+ DATADIR LIB_DIR_SUFFIX
+ DIR_SEPARATOR_STRING "pic"
+ DIR_SEPARATOR_STRING DEVICE_FILE_NAME);
+ pic_file = fopen (filename, "rt");
+ } // if
+
+ if (pic_file == NULL)
+ {
+ fprintf (stderr, "can't find %s\n", DEVICE_FILE_NAME);
+ return NULL;
+ } // if
+
+ if (options.verbose)
+ printf ("Using devices from %s.\n", filename);
+
+ /* read line by line */
+ pic_buf[sizeof (pic_buf)-1] = '\0';
+ while (fgets (pic_buf, sizeof (pic_buf)-1, pic_file) != NULL && !done)
+ {
+ /* strip comments */
+ {
+ char *comment = strchr (pic_buf, '#');
+ if (comment)
+ *comment = 0;
+ }
+
+ /* split into fields */
+ num_pic_words = split_words (pic_word, pic_buf);
+
+ /* ignore comment / empty lines */
+ if (num_pic_words > 0)
+ {
+
+ if (STRCASECMP (pic_word[0], "processor") == 0)
+ {
+ if (pic_name == NULL)
+ {
+ int dcount;
+
+ /* this is the mode where we read all the processors in - store the names for now */
+ if (num_processor_names > 0)
+ {
+ /* store away all the previous processor definitions */
+ for (dcount = 1; dcount < num_processor_names; dcount++)
+ {
+ create_pic (processor_name[dcount], pic_maxram,
+ pic_bankmsk, pic_confsiz, pic_config,
+ pic_program, pic_data, pic_eeprom,
+ pic_io, pic_is_enhanced);
+ } // for
+ } // if
+
+ /* copy processor names */
+ num_processor_names = num_pic_words;
+ for (dcount = 1; dcount < num_processor_names; dcount++)
+ {
+ processor_name[dcount] = pic_word[dcount];
+ pic_word[dcount] = NULL;
+ } // for
+ } // if
+ else
+ {
+ /* if we've just completed reading a processor definition stop now */
+ if (found_processor)
+ done = TRUE;
+ else
+ {
+ /* check if this processor name is a match */
+ for (wcount = 1; wcount < num_pic_words; wcount++)
+ {
+ /* skip uninteresting prefixes */
+ char *found_name = sanitise_processor_name (pic_word[wcount]);
+
+ if (STRCASECMP (found_name, simple_pic_name) == 0)
+ found_processor = TRUE;
+ } // for
+ } // if
+ } // if
+ } // if
+ else
+ {
+ if (found_processor || pic_name == NULL)
+ {
+ /* only parse a processor section if we've found the one we want */
+ if (STRCASECMP (pic_word[0], "maxram") == 0 && num_pic_words > 1)
+ {
+ pic_maxram = parse_config_value (pic_word[1]);
+ setMaxRAM (pic_maxram);
+ } // if
+
+ else if (STRCASECMP (pic_word[0], "bankmsk") == 0 && num_pic_words > 1)
+ pic_bankmsk = parse_config_value (pic_word[1]);
+
+ else if (STRCASECMP (pic_word[0], "config") == 0 && num_pic_words > 1)
+ {
+ pic_confsiz = 0;
+ for (i = 1; (i < num_pic_words) && (i < MAX_NUM_CONFIGS + 1); i++)
+ {
+ pic_config[i - 1] = parse_config_value (pic_word[i]);
+ pic_confsiz++;
+ } // for
+ }
+
+ else if (STRCASECMP (pic_word[0], "program") == 0 && num_pic_words > 1)
+ pic_program = parse_config_value (pic_word[1]);
+
+ else if (STRCASECMP (pic_word[0], "data") == 0 && num_pic_words > 1)
+ pic_data = parse_config_value (pic_word[1]);
+
+ else if (STRCASECMP (pic_word[0], "eeprom") == 0 && num_pic_words > 1)
+ pic_eeprom = parse_config_value (pic_word[1]);
+
+ else if (STRCASECMP (pic_word[0], "enhanced") == 0 && num_pic_words > 1)
+ pic_is_enhanced = parse_config_value (pic_word[1]);
+
+ else if (STRCASECMP (pic_word[0], "io") == 0 && num_pic_words > 1)
+ pic_io = parse_config_value (pic_word[1]);
+
+ else if (STRCASECMP (pic_word[0], "regmap") == 0 && num_pic_words > 2)
+ {
+ if (found_processor)
+ register_map (num_pic_words, pic_word);
+ } // if
+
+ else if (STRCASECMP (pic_word[0], "memmap") == 0 && num_pic_words > 2)
+ {
+ if (found_processor)
+ ram_map (num_pic_words, pic_word);
+ } // if
+
+ else
+ {
+ fprintf (stderr, "WARNING: %s: bad syntax `%s'\n",
+ DEVICE_FILE_NAME, pic_word[0]);
+ } // if
+ } // if
+ } // if
+ } // if
+ } // while
+
+ fclose (pic_file);
+
+ split_words (pic_word, NULL);
+ free (pic_word);
+
+ /* if we're in read-the-lot mode then create the final processor definition */
+ if (pic_name == NULL)
+ {
+ if (num_processor_names > 0)
+ {
+ /* store away all the previous processor definitions */
+ int dcount;
+
+ for (dcount = 1; dcount < num_processor_names; dcount++)
+ {
+ create_pic (processor_name[dcount], pic_maxram, pic_bankmsk,
+ pic_confsiz, pic_config, pic_program, pic_data,
+ pic_eeprom, pic_io, pic_is_enhanced);
+ } // for
+ } // if
+ } // if
+ else
+ {
+ /* in search mode */
+ if (found_processor)
+ {
+ split_words (processor_name, NULL);
+ free (processor_name);
+
+ /* create a new pic entry */
+ return create_pic (pic_name, pic_maxram, pic_bankmsk,
+ pic_confsiz, pic_config, pic_program,
+ pic_data, pic_eeprom, pic_io, pic_is_enhanced);
+ } // if
+ } // if
+
+ split_words (processor_name, NULL);
+ free (processor_name);
+
+ return NULL;
+}
+
+/*-----------------------------------------------------------------*
+ * void 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...)
+ *-----------------------------------------------------------------*/
+static void
+list_valid_pics(int ncols)
+{
+ int col=0,longest;
+ int i,k,l;
+
+ if (num_of_supported_PICS == 0)
+ find_device(NULL); /* load all the definitions */
+
+ /* 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; i<num_of_supported_PICS; i++) {
+ k = strlen(Pics[i]->name);
+ if(k>longest)
+ longest = k;
+ }
+
+#if 1
+ /* heading */
+ fprintf(stderr, "\nPIC14 processors and their characteristics:\n\n");
+ fprintf(stderr, " processor");
+ for(k=0; k<longest-1; k++)
+ fputc(' ',stderr);
+ fprintf(stderr, "program RAM EEPROM I/O\n");
+ fprintf(stderr, "-----------------------------------------------------\n");
+
+ for(i=0; i < num_of_supported_PICS; i++) {
+ fprintf(stderr," %s", Pics[i]->name);
+ l = longest + 2 - strlen(Pics[i]->name);
+ for(k=0; k<l; k++)
+ fputc(' ',stderr);
+
+ fprintf(stderr, " ");
+ if (Pics[i]->programMemSize % 1024 == 0)
+ fprintf(stderr, "%4dK", Pics[i]->programMemSize / 1024);
+ else
+ fprintf(stderr, "%5d", Pics[i]->programMemSize);
+
+ fprintf(stderr, " %5d %5d %4d\n",
+ Pics[i]->dataMemSize, Pics[i]->eepromMemSize, Pics[i]->ioPins);
+ }
+
+ col = 0;
+
+ fprintf(stderr, "\nPIC14 processors supported:\n");
+ for(i=0; i < num_of_supported_PICS; i++) {
+
+ fprintf(stderr,"%s", Pics[i]->name);
+ if(col<ncols) {
+ l = longest + 2 - strlen(Pics[i]->name);
+ for(k=0; k<l; k++)
+ fputc(' ',stderr);
+
+ col++;
+
+ } else {
+ fputc('\n',stderr);
+ col = 0;
+ }
+
+ }
+#endif
+ if(col != 0)
+ fputc('\n',stderr);
+}
+
+/*-----------------------------------------------------------------*
+*
+*-----------------------------------------------------------------*/
+PIC_device *
+init_pic (char *pic_type)
+{
+ char long_name[PIC14_STRING_LEN];
+
+ pic = find_device(pic_type);
+
+ if (pic == NULL)
+ {
+ /* check for shortened "16xxx" form */
+ SNPRINTF(long_name, sizeof(long_name), "16%s", pic_type);
+ pic = find_device(long_name);
+ if (pic == NULL)
+ {
+ if (pic_type != NULL && pic_type[0] != '\0')
+ fprintf(stderr, "'%s' was not found.\n", pic_type);
+ else
+ fprintf(stderr, "No processor has been specified (use -pPROCESSOR_NAME)\n");
+
+ list_valid_pics(7);
+ exit(1);
+ }
+ }
+
+ if (pic && pic->isEnhancedCore)
+ {
+ /* Hack: Fixup enhanced core's SFR(s). */
+ pc_indf = &pc_indf0;
+ }
+
+ return pic;
+}
+
+/*-----------------------------------------------------------------*
+*
+*-----------------------------------------------------------------*/
+int picIsInitialized(void)
+{
+ if(pic && maxRAMaddress > 0)
+ return 1;
+
+ return 0;
+
+}
+
+/*-----------------------------------------------------------------*
+* char *processor_base_name(void) - Include file is derived from this.
+*-----------------------------------------------------------------*/
+char *processor_base_name(void)
+{
+
+ if(!pic)
+ return NULL;
+
+ return pic->name;
+}
+
+int IS_CONFIG_ADDRESS(int address)
+{
+ int i;
+
+ for (i = 0; i < pic->num_configs; i++)
+ {
+ if ((-1 != address) && (address == pic->config[i]))
+ {
+ /* address is used for config words */
+ return (1);
+ } // if
+ } // for
+
+ return (0);
+}
+
+/*-----------------------------------------------------------------*
+ * void pic14_assignConfigWordValue(int address, int value)
+ *
+ * Most midrange PICs have one config word at address 0x2007.
+ * Newer PIC14s have a second config word at address 0x2008.
+ * Even newer PICs have moved this address to 0x8007+...
+ * This routine will assign values to those addresses.
+ *
+ *-----------------------------------------------------------------*/
+
+void
+pic14_assignConfigWordValue(int address, int value)
+{
+ int i;
+ for (i = 0; i < pic->num_configs; i++)
+ {
+ if ((-1 != address) && (address == pic->config[i]))
+ {
+ config_word[i] = value;
+ pic14_hasSetConfigWord = 1;
+ } // if
+ } // for
+}
+
+/*-----------------------------------------------------------------*
+ * int pic14_emitConfigWord (FILE * vFile)
+ *
+ * Emit the __config directives iff we found a previous assignment
+ * to the config word.
+ *-----------------------------------------------------------------*/
+int
+pic14_emitConfigWord (FILE * vFile)
+{
+ int i;
+
+ if (pic14_hasSetConfigWord)
+ {
+ fprintf (vFile, "%s", iComments2);
+ fprintf (vFile, "; config word(s)\n");
+ fprintf (vFile, "%s", iComments2);
+ if (pic->num_configs > 1)
+ {
+ for (i = 0; i < pic->num_configs; i++)
+ {
+ if (-1 != config_word[i])
+ {
+ fprintf (vFile, "\t__config _CONFIG%u, 0x%x\n", i + 1, config_word[i]);
+ } //if
+ } // for
+ }
+ else
+ {
+ if (-1 != config_word[0])
+ {
+ fprintf (vFile, "\t__config 0x%x\n", config_word[0]);
+ } // if
+ } // if
+
+ return 1;
+ }
+ return 0;
+}
+
+/*-----------------------------------------------------------------*
+ * True iff the device has memory aliased in every bank.
+ * If true, low and high will be set to the low and high address
+ * occupied by the (last) sharebank found.
+ *-----------------------------------------------------------------*/
+static int pic14_hasSharebank(int *low, int *high, int *size)
+{
+ memRange *r;
+
+ assert(pic);
+ r = pic->ram;
+
+ while (r) {
+ //fprintf (stderr, "%s: region %x..%x, bank %x, alias %x, pic->bankmask %x, min_size %d\n", __FUNCTION__, r->start_address, r->end_address, r->bank, r->alias, pic->bankMask, size ? *size : 0);
+ // find sufficiently large shared region
+ if ((r->alias == pic->bankMask)
+ && (r->end_address != r->start_address) // ignore SFRs
+ && (!size || (*size <= (r->end_address - r->start_address + 1))))
+ {
+ if (low) *low = r->start_address;
+ if (high) *high = r->end_address;
+ if (size) *size = r->end_address - r->start_address + 1;
+ return 1;
+ } // if
+ r = r->next;
+ } // while
+
+ if (low) *low = 0x0;
+ if (high) *high = 0x0;
+ if (size) *size = 0x0;
+ //fprintf (stderr, "%s: no shared bank found\n", __FUNCTION__);
+ return 0;
+}
+
+/*
+ * True iff the memory region [low, high] is aliased in all banks.
+ */
+static int pic14_isShared(int low, int high)
+{
+ memRange *r;
+
+ assert(pic);
+ r = pic->ram;
+
+ while (r) {
+ //fprintf (stderr, "%s: region %x..%x, bank %x, alias %x, pic->bankmask %x\n", __FUNCTION__, r->start_address, r->end_address, r->bank, r->alias, pic->bankMask);
+ if ((r->alias == pic->bankMask) && (r->start_address <= low) && (r->end_address >= high)) {
+ return 1;
+ } // if
+ r = r->next;
+ } // while
+
+ return 0;
+}
+
+/*
+ * True iff all RAM is aliased in all banks (no BANKSELs required except for
+ * SFRs).
+ */
+int pic14_allRAMShared(void)
+{
+ memRange *r;
+
+ assert(pic);
+ r = pic->ram;
+
+ while (r) {
+ if (r->alias != pic->bankMask) return 0;
+ r = r->next;
+ } // while
+
+ return 1;
+}
+
+/*
+ * True iff the pseudo stack is a sharebank --> let linker place it.
+ * [low, high] denotes a size byte long block of (shared or banked)
+ * memory to be used.
+ */
+int pic14_getSharedStack(int *low, int *high, int *size)
+{
+ int haveShared;
+ int l, h, s;
+
+ s = options.stack_size ? options.stack_size : 0x10;
+ haveShared = pic14_hasSharebank(&l, &h, &s);
+ if ((options.stack_loc != 0) || !haveShared)
+ {
+ // sharebank not available or not to be used
+ s = options.stack_size ? options.stack_size : 0x10;
+ l = options.stack_loc ? options.stack_loc : 0x20;
+ h = l + s - 1;
+ if (low) *low = l;
+ if (high) *high = h;
+ if (size) *size = s;
+ // return 1 iff [low, high] is present in all banks
+ //fprintf(stderr, "%s: low %x, high %x, size %x, shared %d\n", __FUNCTION__, l, h, s, pic14_isShared(l, h));
+ return (pic14_isShared(l, h));
+ } else {
+ // sharebanks available for use by the stack
+ if (options.stack_size) s = options.stack_size;
+ else if (!s || s > 16) s = 16; // limit stack to 16 bytes in SHAREBANK
+
+ // provide addresses for sharebank
+ if (low) *low = l;
+ if (high) *high = l + s - 1;
+ if (size) *size = s;
+ //fprintf(stderr, "%s: low %x, high %x, size %x, shared 1\n", __FUNCTION__, l, h, s);
+ return 1;
+ }
+}
+
+PIC_device * pic14_getPIC(void)
+{
+ return pic;
+}
diff --git a/src/pic14/device.h b/src/pic14/device.h
new file mode 100644
index 0000000..2ff58ff
--- /dev/null
+++ b/src/pic14/device.h
@@ -0,0 +1,94 @@
+/*-------------------------------------------------------------------------
+
+ device.c - Accomodates subtle variations in PIC 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__
+
+#include "common.h"
+
+#define MAX_NUM_CONFIGS 16
+
+/*
+ * Imports
+ */
+extern char *iComments2;
+
+/* 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 */
+ struct memRange *next; /* linked list */
+
+} memRange;
+
+/* Processor unique attributes */
+typedef struct PIC_device {
+ char *name; /* the processor name */
+
+ memRange *ram; /* RAM memory map */
+ memRange *sfr; /* SFR memory map */
+
+ int maxRAMaddress; /* maximum value for a data address */
+ int defMaxRAMaddrs; /* default 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 */
+ int num_configs; /* number of config words for this device */
+ int config[MAX_NUM_CONFIGS]; /* addresses of config word(s) */
+
+ int programMemSize; /* program memory size in words - for device listing only */
+ int dataMemSize; /* data (RAM) memory size in bytes - for device listing only */
+ int eepromMemSize; /* EEPROM memory size in bytes - for device listing only */
+ int ioPins; /* number of I/O pins - for device listing only */
+ int isEnhancedCore; /* enhanced cores (19f1934) feature automatic context saving */
+
+} PIC_device;
+
+
+PIC_device *init_pic(char *pic_type);
+int picIsInitialized(void);
+char *processor_base_name(void);
+int IS_CONFIG_ADDRESS(int addr);
+void pic14_assignConfigWordValue(int address, int value);
+int pic14_emitConfigWord(FILE *vFile);
+
+int pic14_allRAMShared(void);
+int pic14_getSharedStack(int *low, int *high, int *size);
+PIC_device * pic14_getPIC(void);
+
+#endif /* __DEVICE_H__ */
diff --git a/src/pic14/gen.c b/src/pic14/gen.c
new file mode 100644
index 0000000..7dd7548
--- /dev/null
+++ b/src/pic14/gen.c
@@ -0,0 +1,7842 @@
+/*-------------------------------------------------------------------------
+ gen.c - source file for code generation for pic
+
+ Copyright (C) 1998, Sandeep Dutta . sandeep.dutta@usa.net
+ Copyright (C) 1999, Jean-Louis VERN.jlvern@writeme.com
+ Bug Fixes - Wojciech Stryjewski wstryj1@tiger.lsu.edu (1999 v2.1.9a)
+ PIC port:
+ Copyright (C) 2000, Scott Dattalo scott@dattalo.com
+ Copyright (C) 2005, Raphael Neider <rneider AT web.de>
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+-------------------------------------------------------------------------*/
+/*
+ Notes:
+ 000123 mlh Moved aopLiteral to SDCCglue.c to help the split
+ Made everything static
+*/
+
+/*
+ * This is the down and dirty file with all kinds of
+ * kludgy & hacky stuff. This is what it is all about
+ * CODE GENERATION for a specific MCU . some of the
+ * routines may be reusable, will have to see.
+ */
+
+#include "device.h"
+#include "gen.h"
+#include "glue.h"
+#include "dbuf_string.h"
+
+/*
+ * Imports
+ */
+extern struct dbuf_s *codeOutBuf;
+extern set *externs;
+
+static PIC_device *pic = NULL;
+
+static pCodeOp *popGetImmd (const char *name, unsigned int offset, int index, int is_func);
+static pCodeOp *popRegFromString (const char *str, int size, int offset);
+static int aop_isLitLike (asmop * aop);
+static void genCritical (iCode * ic);
+static void genEndCritical (iCode * ic);
+
+/* The PIC port(s) need not differentiate between POINTER and FPOINTER. */
+#define PIC_IS_DATA_PTR(x) (IS_DATA_PTR(x) || IS_FARPTR(x))
+
+/*
+ * max_key keeps track of the largest label number used in
+ * a function. This is then used to adjust the label offset
+ * for the next function.
+ */
+static int max_key = 0;
+static int labelOffset = 0;
+static int GpseudoStkPtr = 0;
+static int pic14_inISR = 0;
+
+static char *zero = "0x00";
+static char *one = "0x01";
+static char *spname = "sp";
+
+unsigned fReturnSizePic = 4; /* shared with ralloc.c */
+static char *fReturnpic14[] = { "temp1", "temp2", "temp3", "temp4" };
+
+static char **fReturn = fReturnpic14;
+
+static struct
+{
+ short accInUse;
+ short nRegsSaved;
+ set *sendSet;
+} _G;
+
+/*
+ * Resolved ifx structure. This structure stores information
+ * about an iCode ifx that makes it easier to generate code.
+ */
+typedef struct resolvedIfx
+{
+ symbol *lbl; /* pointer to a label */
+ int condition; /* true or false ifx */
+ int generated; /* set true when the code associated with the ifx
+ * is generated */
+} resolvedIfx;
+
+static pBlock *pb;
+
+/*-----------------------------------------------------------------*/
+/* my_powof2(n) - If `n' is an integer power of 2, then the */
+/* exponent of 2 is returned, otherwise -1 is */
+/* returned. */
+/* note that this is similar to the function `powof2' in SDCCsymt */
+/* if(n == 2^y) */
+/* return y; */
+/* return -1; */
+/*-----------------------------------------------------------------*/
+static int
+my_powof2 (unsigned long num)
+{
+ if (num)
+ {
+ if ((num & (num - 1)) == 0)
+ {
+ int nshifts = -1;
+ while (num)
+ {
+ num >>= 1;
+ nshifts++;
+ }
+ return nshifts;
+ }
+ }
+
+ return -1;
+}
+
+void
+DEBUGpic14_AopType (int line_no, operand * left, operand * right, operand * result)
+{
+
+ DEBUGpic14_emitcode ("; ", "line = %d result %s=%s, size=%d, left %s=%s, size=%d, right %s=%s, size=%d",
+ line_no,
+ ((result) ? AopType (AOP_TYPE (result)) : "-"),
+ ((result) ? aopGet (AOP (result), 0, TRUE, FALSE) : "-"),
+ ((result) ? AOP_SIZE (result) : 0),
+ ((left) ? AopType (AOP_TYPE (left)) : "-"),
+ ((left) ? aopGet (AOP (left), 0, TRUE, FALSE) : "-"),
+ ((left) ? AOP_SIZE (left) : 0),
+ ((right) ? AopType (AOP_TYPE (right)) : "-"),
+ ((right) ? aopGet (AOP (right), 0, FALSE, FALSE) : "-"), ((right) ? AOP_SIZE (right) : 0));
+
+}
+
+static void
+DEBUGpic14_AopTypeSign (int line_no, operand * left, operand * right, operand * result)
+{
+
+ DEBUGpic14_emitcode ("; ", "line = %d, signs: result %s=%c, left %s=%c, right %s=%c",
+ line_no,
+ ((result) ? AopType (AOP_TYPE (result)) : "-"),
+ ((result) ? (SPEC_USIGN (operandType (result)) ? 'u' : 's') : '-'),
+ ((left) ? AopType (AOP_TYPE (left)) : "-"),
+ ((left) ? (SPEC_USIGN (operandType (left)) ? 'u' : 's') : '-'),
+ ((right) ? AopType (AOP_TYPE (right)) : "-"),
+ ((right) ? (SPEC_USIGN (operandType (right)) ? 'u' : 's') : '-'));
+
+}
+
+void
+DEBUGpic14_emitcode (const char *inst, const char *fmt, ...)
+{
+ va_list ap;
+
+ if (!debug_verbose && !options.debug)
+ return;
+
+ va_start (ap, fmt);
+ va_emitcode (inst, fmt, ap);
+ va_end (ap);
+
+ addpCode2pBlock (pb, newpCodeCharP (genLine.lineCurr->line));
+}
+
+void
+emitpComment (const char *fmt, ...)
+{
+ va_list ap;
+ struct dbuf_s dbuf;
+ const char *line;
+
+ dbuf_init (&dbuf, INITIAL_INLINEASM);
+
+ dbuf_append_char (&dbuf, ';');
+ va_start (ap, fmt);
+ dbuf_vprintf (&dbuf, fmt, ap);
+ va_end (ap);
+
+ line = dbuf_detach_c_str (&dbuf);
+ emit_raw (line);
+ dbuf_free (line);
+
+ addpCode2pBlock (pb, newpCodeCharP (genLine.lineCurr->line));
+}
+
+void
+emitpLabel (int key)
+{
+ addpCode2pBlock (pb, newpCodeLabel (NULL, labelKey2num (key + labelOffset)));
+}
+
+/* gen.h defines a macro emitpcode that should be used to call emitpcode
+ * as this allows for easy debugging (ever asked the question: where was
+ * this instruction geenrated? Here is the answer... */
+void
+emitpcode_real (PIC_OPCODE poc, pCodeOp * pcop)
+{
+ if (pcop)
+ addpCode2pBlock (pb, newpCode (poc, pcop));
+ else
+ {
+ static int has_warned = FALSE;
+
+ DEBUGpic14_emitcode (";", "%s ignoring NULL pcop", __FUNCTION__);
+ if (!has_warned)
+ {
+ has_warned = TRUE;
+ fprintf (stderr, "WARNING: encountered NULL pcop--this is probably a compiler bug...\n");
+ }
+ }
+}
+
+static void
+emitpcodeNULLop (PIC_OPCODE poc)
+{
+ addpCode2pBlock (pb, newpCode (poc, NULL));
+}
+
+/*-----------------------------------------------------------------*/
+/* pic14_emitcode - writes the code into a file : for now it is simple */
+/*-----------------------------------------------------------------*/
+void
+pic14_emitcode (const char *inst, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start (ap, fmt);
+ va_emitcode (inst, fmt, ap);
+ va_end (ap);
+
+ if (debug_verbose)
+ addpCode2pBlock (pb, newpCodeCharP (genLine.lineCurr->line));
+}
+
+/*-----------------------------------------------------------------*/
+/* pic14_emitDebuggerSymbol - associate the current code location */
+/* with a debugger symbol */
+/*-----------------------------------------------------------------*/
+void
+pic14_emitDebuggerSymbol (const char *debugSym)
+{
+ genLine.lineElement.isDebug = TRUE;
+ pic14_emitcode ("", ";%s ==.", debugSym);
+ genLine.lineElement.isDebug = FALSE;
+}
+
+/*-----------------------------------------------------------------*/
+/* newAsmop - creates a new asmOp */
+/*-----------------------------------------------------------------*/
+static asmop *
+newAsmop (short type)
+{
+ asmop *aop;
+
+ aop = Safe_alloc(sizeof(asmop));
+ aop->type = type;
+ return aop;
+}
+
+/*-----------------------------------------------------------------*/
+/* resolveIfx - converts an iCode ifx into a form more useful for */
+/* generating code */
+/*-----------------------------------------------------------------*/
+static void
+resolveIfx (resolvedIfx * resIfx, iCode * ifx)
+{
+ if (!resIfx)
+ return;
+
+ // DEBUGpic14_emitcode("; ***","%s %d",__FUNCTION__,__LINE__);
+
+ resIfx->condition = TRUE; /* assume that the ifx is true */
+ resIfx->generated = FALSE; /* indicate that the ifx has not been used */
+
+ if (!ifx)
+ {
+ resIfx->lbl = NULL; /* this is wrong: newiTempLabel(NULL); / * oops, there is no ifx. so create a label */
+ }
+ else
+ {
+ if (IC_TRUE (ifx))
+ {
+ resIfx->lbl = IC_TRUE (ifx);
+ }
+ else
+ {
+ resIfx->lbl = IC_FALSE (ifx);
+ resIfx->condition = FALSE;
+ }
+ }
+
+ // DEBUGpic14_emitcode("; ***","%s lbl->key=%d, (lab offset=%d)",__FUNCTION__,resIfx->lbl->key,labelOffset);
+
+}
+
+/*-----------------------------------------------------------------*/
+/* aopForSym - for a true symbol */
+/*-----------------------------------------------------------------*/
+static asmop *
+aopForSym (iCode * ic, symbol * sym, bool result)
+{
+ asmop *aop;
+ memmap *space = SPEC_OCLS (sym->etype);
+
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ /* if already has one */
+ if (sym->aop)
+ return sym->aop;
+
+ //DEBUGpic14_emitcode(";","%d",__LINE__);
+ /* if it is in direct space */
+ if (IN_DIRSPACE (space))
+ {
+ sym->aop = aop = newAsmop (AOP_DIR);
+ aop->aopu.aop_dir = sym->rname;
+ aop->size = getSize (sym->type);
+ DEBUGpic14_emitcode (";", "%d sym->rname = %s, size = %d", __LINE__, sym->rname, aop->size);
+ return aop;
+ }
+
+ /* special case for a function */
+ if (IS_FUNC (sym->type))
+ {
+
+ sym->aop = aop = newAsmop (AOP_PCODE);
+ aop->aopu.pcop = popGetImmd (sym->rname, 0, 0, 1);
+ PCOI (aop->aopu.pcop)->_const = IN_CODESPACE (space);
+ PCOI (aop->aopu.pcop)->_function = TRUE;
+ PCOI (aop->aopu.pcop)->index = 0;
+ aop->size = FARPTRSIZE;
+ DEBUGpic14_emitcode (";", "%d size = %d, name =%s", __LINE__, aop->size, sym->rname);
+ return aop;
+ }
+
+ if (IS_ARRAY (sym->type))
+ {
+ sym->aop = aop = newAsmop (AOP_PCODE);
+ aop->aopu.pcop = popGetImmd (sym->rname, 0, 0, 1);
+ PCOI (aop->aopu.pcop)->_const = IN_CODESPACE (space);
+ PCOI (aop->aopu.pcop)->_function = FALSE;
+ PCOI (aop->aopu.pcop)->index = 0;
+ aop->size = getSize (sym->etype) * DCL_ELEM (sym->type);
+
+ DEBUGpic14_emitcode (";", "%d size = %d, name =%s", __LINE__, aop->size, sym->rname);
+ return aop;
+ }
+
+ /* only remaining is far space */
+ /* in which case DPTR gets the address */
+ sym->aop = aop = newAsmop (AOP_PCODE);
+
+ aop->aopu.pcop = popGetImmd (sym->rname, 0, 0, 0);
+ PCOI (aop->aopu.pcop)->_const = IN_CODESPACE (space);
+ PCOI (aop->aopu.pcop)->index = 0;
+
+ DEBUGpic14_emitcode (";", "%d: rname %s, val %d, const = %d", __LINE__, sym->rname, 0, PCOI (aop->aopu.pcop)->_const);
+
+ allocDirReg (IC_LEFT (ic));
+
+ aop->size = FARPTRSIZE;
+
+ /* if it is in code space */
+ if (IN_CODESPACE (space))
+ aop->code = TRUE;
+
+ return aop;
+}
+
+/*-----------------------------------------------------------------*/
+/* aopForRemat - rematerialzes an object */
+/*-----------------------------------------------------------------*/
+static asmop *
+aopForRemat (operand * op) // x symbol *sym)
+{
+ symbol *sym = OP_SYMBOL (op);
+ iCode *ic = NULL;
+ asmop *aop = newAsmop (AOP_PCODE);
+ int val = 0;
+
+ ic = sym->rematiCode;
+
+ DEBUGpic14_emitcode (";", "%s %d", __FUNCTION__, __LINE__);
+ if (IS_OP_POINTER (op))
+ {
+ DEBUGpic14_emitcode (";", "%s %d IS_OP_POINTER", __FUNCTION__, __LINE__);
+ }
+ for (;;)
+ {
+ if (ic->op == '+')
+ {
+ val += (int) operandLitValue (IC_RIGHT (ic));
+ }
+ else if (ic->op == '-')
+ {
+ val -= (int) operandLitValue (IC_RIGHT (ic));
+ }
+ else
+ break;
+
+ ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
+ }
+
+ aop->aopu.pcop = popGetImmd (OP_SYMBOL (IC_LEFT (ic))->rname, 0, val, 0);
+ PCOI (aop->aopu.pcop)->_const = IS_PTR_CONST (operandType (op));
+ PCOI (aop->aopu.pcop)->index = val;
+
+ DEBUGpic14_emitcode (";", "%d: rname %s, val %d, const = %d",
+ __LINE__, OP_SYMBOL (IC_LEFT (ic))->rname, val, IS_PTR_CONST (operandType (op)));
+
+ // DEBUGpic14_emitcode(";","aop type %s",AopType(AOP_TYPE(IC_LEFT(ic))));
+
+ allocDirReg (IC_LEFT (ic));
+
+ return aop;
+}
+
+static int
+aopIdx (asmop * aop, int offset)
+{
+ if (!aop)
+ return -1;
+
+ if (aop->type != AOP_REG)
+ return -2;
+
+ return aop->aopu.aop_reg[offset]->rIdx;
+
+}
+
+/*-----------------------------------------------------------------*/
+/* regsInCommon - two operands have some registers in common */
+/*-----------------------------------------------------------------*/
+static bool
+regsInCommon (operand * op1, operand * op2)
+{
+ symbol *sym1, *sym2;
+ int i;
+
+ /* if they have registers in common */
+ if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
+ return FALSE;
+
+ sym1 = OP_SYMBOL (op1);
+ sym2 = OP_SYMBOL (op2);
+
+ if (sym1->nRegs == 0 || sym2->nRegs == 0)
+ return FALSE;
+
+ for (i = 0; i < sym1->nRegs; i++)
+ {
+ int j;
+ if (!sym1->regs[i])
+ continue;
+
+ for (j = 0; j < sym2->nRegs; j++)
+ {
+ if (!sym2->regs[j])
+ continue;
+
+ if (sym2->regs[j] == sym1->regs[i])
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/*-----------------------------------------------------------------*/
+/* operandsEqu - equivalent */
+/*-----------------------------------------------------------------*/
+static bool
+operandsEqu (operand * op1, operand * op2)
+{
+ symbol *sym1, *sym2;
+
+ /* if they not symbols */
+ if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
+ return FALSE;
+
+ sym1 = OP_SYMBOL (op1);
+ sym2 = OP_SYMBOL (op2);
+
+ /* if both are itemps & one is spilt
+ and the other is not then false */
+ if (IS_ITEMP (op1) && IS_ITEMP (op2) && sym1->isspilt != sym2->isspilt)
+ return FALSE;
+
+ /* if they are the same */
+ if (sym1 == sym2)
+ return TRUE;
+
+ if (sym1->rname[0] && sym2->rname[0] && strcmp (sym1->rname, sym2->rname) == 0)
+ return TRUE;
+
+
+ /* if left is a tmp & right is not */
+ if (IS_ITEMP (op1) && !IS_ITEMP (op2) && sym1->isspilt && (sym1->usl.spillLoc == sym2))
+ return TRUE;
+
+ if (IS_ITEMP (op2) && !IS_ITEMP (op1) && sym2->isspilt && sym1->level > 0 && (sym2->usl.spillLoc == sym1))
+ return TRUE;
+
+ return FALSE;
+}
+
+/*-----------------------------------------------------------------*/
+/* pic14_sameRegs - two asmops have the same registers */
+/*-----------------------------------------------------------------*/
+bool
+pic14_sameRegs (asmop * aop1, asmop * aop2)
+{
+ int i;
+
+ if (aop1 == aop2)
+ return TRUE;
+
+ if (aop1->type != AOP_REG || aop2->type != AOP_REG)
+ return FALSE;
+
+ if (aop1->size != aop2->size)
+ return FALSE;
+
+ for (i = 0; i < aop1->size; i++)
+ if (aop1->aopu.aop_reg[i] != aop2->aopu.aop_reg[i])
+ return FALSE;
+
+ return TRUE;
+}
+
+/*-----------------------------------------------------------------*/
+/* aopOp - allocates an asmop for an operand : */
+/*-----------------------------------------------------------------*/
+void
+aopOp (operand * op, iCode * ic, bool result)
+{
+ asmop *aop;
+ symbol *sym;
+ int i;
+
+ if (!op)
+ return;
+
+ /* if this a literal */
+ if (IS_OP_LITERAL (op))
+ {
+ op->aop = aop = newAsmop (AOP_LIT);
+ aop->aopu.aop_lit = OP_VALUE (op);
+ aop->size = getSize (operandType (op));
+ return;
+ }
+
+ {
+ sym_link *type = operandType (op);
+ if (IS_PTR_CONST (type))
+ DEBUGpic14_emitcode (";", "%d aop type is const pointer", __LINE__);
+ }
+
+ /* if already has a asmop then continue */
+ if (op->aop)
+ return;
+
+ /* if the underlying symbol has a aop */
+ if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
+ {
+ DEBUGpic14_emitcode (";", "%d", __LINE__);
+ op->aop = OP_SYMBOL (op)->aop;
+ return;
+ }
+
+ /* if this is a true symbol */
+ if (IS_TRUE_SYMOP (op))
+ {
+ //DEBUGpic14_emitcode(";","%d - true symop",__LINE__);
+ op->aop = aopForSym (ic, OP_SYMBOL (op), result);
+ return;
+ }
+
+ /* this is a temporary : this has
+ only four choices :
+ a) register
+ b) spillocation
+ c) rematerialize
+ d) conditional
+ e) can be a return use only */
+
+ sym = OP_SYMBOL (op);
+
+
+ /* if the type is a conditional */
+ if (sym->regType == REG_CND)
+ {
+ aop = op->aop = sym->aop = newAsmop (AOP_CRY);
+ aop->size = 0;
+ return;
+ }
+
+ /* if it is spilt then two situations
+ a) is rematerialize
+ b) has a spill location */
+ if (sym->isspilt || sym->nRegs == 0)
+ {
+
+ DEBUGpic14_emitcode (";", "%d", __LINE__);
+ /* rematerialize it NOW */
+ if (sym->remat)
+ {
+
+ sym->aop = op->aop = aop = aopForRemat (op);
+ aop->size = getSize (sym->type);
+ //DEBUGpic14_emitcode(";"," %d: size %d, %s\n",__LINE__,aop->size,aop->aopu.aop_immd);
+ return;
+ }
+
+ if (sym->ruonly)
+ {
+ if (sym->isptr) // && sym->uptr
+ {
+ aop = op->aop = sym->aop = newAsmop (AOP_PCODE);
+ aop->aopu.pcop = newpCodeOp (NULL, PO_GPR_POINTER); //popCopyReg(&pc_fsr);
+
+ //PCOI(aop->aopu.pcop)->_const = 0;
+ //PCOI(aop->aopu.pcop)->index = 0;
+ /*
+ DEBUGpic14_emitcode(";","%d: rname %s, val %d, const = %d",
+ __LINE__,sym->rname, 0, PCOI(aop->aopu.pcop)->_const);
+ */
+ //allocDirReg (IC_LEFT(ic));
+
+ aop->size = getSize (sym->type);
+ DEBUGpic14_emitcode (";", "%d", __LINE__);
+ return;
+
+ }
+ else
+ {
+
+ unsigned i;
+
+ aop = op->aop = sym->aop = newAsmop (AOP_STR);
+ aop->size = getSize (sym->type);
+ for (i = 0; i < fReturnSizePic; i++)
+ aop->aopu.aop_str[i] = fReturn[i];
+
+ DEBUGpic14_emitcode (";", "%d", __LINE__);
+ return;
+ }
+ }
+
+ /* else spill location */
+ if (sym->isspilt && sym->usl.spillLoc)
+ {
+ asmop *oldAsmOp = NULL;
+
+ if (getSize (sym->type) != getSize (sym->usl.spillLoc->type))
+ {
+ /* force a new aop if sizes differ */
+ oldAsmOp = sym->usl.spillLoc->aop;
+ sym->usl.spillLoc->aop = NULL;
+ }
+ DEBUGpic14_emitcode (";", "%s %d %s sym->rname = %s, offset %d",
+ __FUNCTION__, __LINE__, sym->usl.spillLoc->rname, sym->rname, sym->usl.spillLoc->offset);
+
+ sym->aop = op->aop = aop = newAsmop (AOP_PCODE);
+ if (getSize (sym->type) != getSize (sym->usl.spillLoc->type))
+ {
+ /* Don't reuse the new aop, go with the last one */
+ sym->usl.spillLoc->aop = oldAsmOp;
+ }
+ //aop->aopu.pcop = popGetImmd(sym->usl.spillLoc->rname,0,sym->usl.spillLoc->offset);
+ aop->aopu.pcop = popRegFromString (sym->usl.spillLoc->rname, getSize (sym->type), sym->usl.spillLoc->offset);
+ aop->size = getSize (sym->type);
+
+ return;
+ }
+ }
+
+ {
+ sym_link *type = operandType (op);
+ if (IS_PTR_CONST (type))
+ DEBUGpic14_emitcode (";", "%d aop type is const pointer", __LINE__);
+ }
+
+ /* must be in a register */
+ DEBUGpic14_emitcode (";", "%d register type nRegs=%d", __LINE__, sym->nRegs);
+ sym->aop = op->aop = aop = newAsmop (AOP_REG);
+ aop->size = sym->nRegs;
+ for (i = 0; i < sym->nRegs; i++)
+ aop->aopu.aop_reg[i] = sym->regs[i];
+}
+
+/*-----------------------------------------------------------------*/
+/* freeAsmop - free up the asmop given to an operand */
+/*----------------------------------------------------------------*/
+void
+freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
+{
+ asmop *aop;
+
+ if (!op)
+ aop = aaop;
+ else
+ aop = op->aop;
+
+ if (!aop)
+ return;
+
+ aop->freed = TRUE;
+
+ /* all other cases just dealloc */
+ if (op)
+ {
+ op->aop = NULL;
+ if (IS_SYMOP (op))
+ {
+ OP_SYMBOL (op)->aop = NULL;
+ /* if the symbol has a spill */
+ if (SPIL_LOC (op))
+ SPIL_LOC (op)->aop = NULL;
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* pic14aopLiteral - string from a literal value */
+/*-----------------------------------------------------------------*/
+static unsigned int
+pic14aopLiteral (value * val, int offset)
+{
+ union
+ {
+ float f;
+ unsigned char c[4];
+ } fl;
+
+ /* if it is a float then it gets tricky */
+ /* otherwise it is fairly simple */
+ if (!IS_FLOAT (val->type))
+ {
+ unsigned long v = ulFromVal (val);
+
+ return ((v >> (offset * 8)) & 0xff);
+ }
+
+ /* it is type float */
+ fl.f = (float) floatFromVal (val);
+#ifdef WORDS_BIGENDIAN
+ return fl.c[3 - offset];
+#else
+ return fl.c[offset];
+#endif
+}
+
+/*-----------------------------------------------------------------*/
+/* aopGet - for fetching value of the aop */
+/*-----------------------------------------------------------------*/
+char *
+aopGet (asmop * aop, int offset, bool bit16, bool dname)
+{
+ //DEBUGpic14_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
+ /* offset is greater than
+ size then zero */
+ assert (aop);
+ if (offset > (aop->size - 1) && aop->type != AOP_LIT)
+ return zero;
+
+ /* depending on type */
+ switch (aop->type)
+ {
+ case AOP_IMMD:
+ if (bit16)
+ SNPRINTF(buffer, sizeof(buffer), "%s", aop->aopu.aop_immd);
+ else if (offset)
+ SNPRINTF(buffer, sizeof(buffer), "(%s >> %d)", aop->aopu.aop_immd, offset * 8);
+ else
+ SNPRINTF(buffer, sizeof(buffer), "%s", aop->aopu.aop_immd);
+ DEBUGpic14_emitcode (";", "%d immd %s", __LINE__, buffer);
+ return Safe_strdup(buffer);
+
+ case AOP_DIR:
+ if (offset)
+ {
+ SNPRINTF(buffer, sizeof(buffer), "(%s + %d)", aop->aopu.aop_dir, offset);
+ DEBUGpic14_emitcode (";", "oops AOP_DIR did this %s\n", buffer);
+ }
+ else
+ SNPRINTF(buffer, sizeof(buffer), "%s", aop->aopu.aop_dir);
+ return Safe_strdup(buffer);
+
+ case AOP_REG:
+ //if (dname)
+ // return aop->aopu.aop_reg[offset]->dname;
+ //else
+ return aop->aopu.aop_reg[offset]->name;
+
+ case AOP_CRY:
+ //pic14_emitcode(";","%d",__LINE__);
+ return aop->aopu.aop_dir;
+
+ case AOP_LIT:
+ SNPRINTF(buffer, sizeof(buffer), "0x%02x", pic14aopLiteral (aop->aopu.aop_lit, offset));
+ return Safe_strdup(buffer);
+
+ case AOP_STR:
+ aop->coff = offset;
+ if (strcmp (aop->aopu.aop_str[offset], "a") == 0 && dname)
+ return "acc";
+ DEBUGpic14_emitcode (";", "%d - %s", __LINE__, aop->aopu.aop_str[offset]);
+ return aop->aopu.aop_str[offset];
+
+ case AOP_PCODE:
+ {
+ pCodeOp *pcop = aop->aopu.pcop;
+ DEBUGpic14_emitcode (";", "%d: aopGet AOP_PCODE type %s", __LINE__, pCodeOpType (pcop));
+ if (pcop->name)
+ {
+ if (pcop->type == PO_IMMEDIATE)
+ {
+ offset += PCOI (pcop)->index;
+ }
+
+ if (offset)
+ {
+ DEBUGpic14_emitcode (";", "%s offset %d", pcop->name, offset);
+ SNPRINTF(buffer, sizeof(buffer), "(%s+%d)", pcop->name, offset);
+ }
+ else
+ {
+ DEBUGpic14_emitcode (";", "%s", pcop->name);
+ SNPRINTF(buffer, sizeof(buffer), "%s", pcop->name);
+ }
+ }
+ else
+ SNPRINTF(buffer, sizeof(buffer), "0x%02x", PCOI (aop->aopu.pcop)->offset);
+ }
+
+ return Safe_strdup(buffer);
+ }
+
+ werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "aopget got unsupported aop->type");
+ exit (0);
+}
+
+/*-----------------------------------------------------------------*/
+/* popGetTempReg - create a new temporary pCodeOp */
+/*-----------------------------------------------------------------*/
+static pCodeOp *
+popGetTempReg (void)
+{
+
+ pCodeOp *pcop;
+
+ pcop = newpCodeOp (NULL, PO_GPR_TEMP);
+ if (pcop && pcop->type == PO_GPR_TEMP && PCOR (pcop)->r)
+ {
+ PCOR (pcop)->r->wasUsed = TRUE;
+ PCOR (pcop)->r->isFree = FALSE;
+ }
+
+ return pcop;
+}
+
+/*-----------------------------------------------------------------*/
+/* popReleaseTempReg - create a new temporary pCodeOp */
+/*-----------------------------------------------------------------*/
+static void
+popReleaseTempReg (pCodeOp * pcop)
+{
+
+ if (pcop && pcop->type == PO_GPR_TEMP && PCOR (pcop)->r)
+ PCOR (pcop)->r->isFree = TRUE;
+
+}
+
+/*-----------------------------------------------------------------*/
+/* popGetLabel - create a new pCodeOp of type PO_LABEL */
+/*-----------------------------------------------------------------*/
+pCodeOp *
+popGetLabel (unsigned int key)
+{
+
+ DEBUGpic14_emitcode ("; ***", "%s key=%d, label offset %d", __FUNCTION__, key, labelOffset);
+
+ if (key > (unsigned int) max_key)
+ max_key = key;
+
+ return newpCodeOpLabel (NULL, labelKey2num (key + labelOffset));
+}
+
+/*-------------------------------------------------------------------*/
+/* popGetHighLabel - create a new pCodeOp of type PO_LABEL with offset=1 */
+/*-------------------------------------------------------------------*/
+static pCodeOp *
+popGetHighLabel (unsigned int key)
+{
+ pCodeOp *pcop;
+ pcop = popGetLabel (key);
+ PCOLAB (pcop)->offset = 1;
+ return pcop;
+}
+
+/*-----------------------------------------------------------------*/
+/* popGetLit - asm operator to pcode operator conversion */
+/*-----------------------------------------------------------------*/
+pCodeOp *
+popGetLit (unsigned int lit)
+{
+
+ return newpCodeOpLit ((unsigned char) lit);
+}
+
+/*-----------------------------------------------------------------*/
+/* popGetImmd - asm operator to pcode immediate conversion */
+/*-----------------------------------------------------------------*/
+static pCodeOp *
+popGetImmd (const char *name, unsigned int offset, int index, int is_func)
+{
+
+ return newpCodeOpImmd (name, offset, index, 0, is_func);
+}
+
+/*-----------------------------------------------------------------*/
+/* popGetWithString - asm operator to pcode operator conversion */
+/*-----------------------------------------------------------------*/
+static pCodeOp *
+popGetWithString (const char *str, int isExtern)
+{
+ pCodeOp *pcop;
+
+
+ if (!str)
+ {
+ fprintf (stderr, "NULL string %s %d\n", __FILE__, __LINE__);
+ exit (1);
+ }
+
+ pcop = newpCodeOp (str, PO_STR);
+ PCOS (pcop)->isPublic = isExtern ? 1 : 0;
+
+ return pcop;
+}
+
+pCodeOp *
+popGetExternal (const char *str, int isReg)
+{
+ pCodeOp *pcop;
+
+ if (isReg)
+ {
+ pcop = newpCodeOpRegFromStr (str);
+ }
+ else
+ {
+ pcop = popGetWithString (str, 1);
+ }
+
+ if (str)
+ {
+ symbol *sym;
+
+ for (sym = setFirstItem (externs); sym; sym = setNextItem (externs))
+ {
+ if (!strcmp (str, sym->rname))
+ break;
+ }
+
+ if (!sym)
+ {
+ sym = newSymbol (str, 0);
+ strncpy (sym->rname, str, SDCC_NAME_MAX);
+ addSet (&externs, sym);
+ } // if
+ sym->used++;
+ }
+ return pcop;
+}
+
+/*-----------------------------------------------------------------*/
+/* popRegFromString - */
+/*-----------------------------------------------------------------*/
+static pCodeOp *
+popRegFromString (const char *str, int size, int offset)
+{
+
+ pCodeOp *pcop = Safe_alloc(sizeof(pCodeOpReg));
+ pcop->type = PO_DIR;
+
+ DEBUGpic14_emitcode (";", "%d", __LINE__);
+
+ if (!str)
+ str = "BAD_STRING";
+
+ pcop->name = Safe_strdup(str);
+
+ //pcop->name = Safe_strdup( ( (str) ? str : "BAD STRING"));
+
+ PCOR (pcop)->r = dirregWithName (pcop->name);
+ if (PCOR (pcop)->r == NULL)
+ {
+ //fprintf(stderr,"%d - couldn't find %s in allocated registers, size =%d\n",__LINE__,aop->aopu.aop_dir,aop->size);
+ PCOR (pcop)->r = allocRegByName (pcop->name, size);
+ DEBUGpic14_emitcode (";", "%d %s offset=%d - had to alloc by reg name", __LINE__, pcop->name, offset);
+ }
+ else
+ {
+ DEBUGpic14_emitcode (";", "%d %s offset=%d", __LINE__, pcop->name, offset);
+ }
+ PCOR (pcop)->instance = offset;
+
+ return pcop;
+}
+
+/*-----------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+static pCodeOp *
+popRegFromIdx (int rIdx)
+{
+ pCodeOp *pcop;
+
+ DEBUGpic14_emitcode ("; ***", "%s,%d , rIdx=0x%x", __FUNCTION__, __LINE__, rIdx);
+
+ pcop = Safe_alloc(sizeof(pCodeOpReg));
+
+ PCOR (pcop)->rIdx = rIdx;
+ PCOR (pcop)->r = typeRegWithIdx (rIdx, REG_STK, 1);
+ PCOR (pcop)->r->isFree = FALSE;
+ PCOR (pcop)->r->wasUsed = TRUE;
+
+ pcop->type = PCOR (pcop)->r->pc_type;
+
+
+ return pcop;
+}
+
+/*-----------------------------------------------------------------*/
+/* popGet - asm operator to pcode operator conversion */
+/*-----------------------------------------------------------------*/
+pCodeOp *
+popGet (asmop * aop, int offset) //, bool bit16, bool dname)
+{
+ //char *s = buffer ;
+ //char *rs;
+
+ pCodeOp *pcop;
+
+ //DEBUGpic14_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
+ /* offset is greater than
+ size then zero */
+
+ assert (aop);
+
+
+ /* XXX: still needed for BIT operands (AOP_CRY) */
+ if ((offset >= aop->size) && (aop->type != AOP_LIT) && (aop->type != AOP_PCODE))
+ {
+ printf ("%s: (offset[%d] >= AOP_SIZE(op)[%d]) && (AOP_TYPE(op)[%d] != { AOP_LIT, AOP_PCODE })\n",
+ __FUNCTION__, offset, aop->size, aop->type);
+ return NULL; //zero;
+ }
+
+ /* depending on type */
+ switch (aop->type)
+ {
+
+ case AOP_IMMD:
+ DEBUGpic14_emitcode (";", "%d", __LINE__);
+ return popGetImmd (aop->aopu.aop_immd, offset, 0, 0);
+
+ case AOP_DIR:
+ return popRegFromString (aop->aopu.aop_dir, aop->size, offset);
+
+ case AOP_REG:
+ {
+ int rIdx;
+ assert (offset < aop->size);
+ rIdx = aop->aopu.aop_reg[offset]->rIdx;
+
+ pcop = Safe_alloc(sizeof(pCodeOpReg));
+ PCOR (pcop)->rIdx = rIdx;
+ PCOR (pcop)->r = pic14_regWithIdx (rIdx);
+ PCOR (pcop)->r->wasUsed = TRUE;
+ PCOR (pcop)->r->isFree = FALSE;
+
+ PCOR (pcop)->instance = offset;
+ pcop->type = PCOR (pcop)->r->pc_type;
+ //rs = aop->aopu.aop_reg[offset]->name;
+ DEBUGpic14_emitcode (";", "%d rIdx = r0x%X ", __LINE__, rIdx);
+ return pcop;
+ }
+
+ case AOP_CRY:
+ pcop = newpCodeOpBit (aop->aopu.aop_dir, -1, 1);
+ PCOR (pcop)->r = dirregWithName (aop->aopu.aop_dir);
+ //if(PCOR(pcop)->r == NULL)
+ //fprintf(stderr,"%d - couldn't find %s in allocated registers\n",__LINE__,aop->aopu.aop_dir);
+ return pcop;
+
+ case AOP_LIT:
+ return newpCodeOpLit (pic14aopLiteral (aop->aopu.aop_lit, offset));
+
+ case AOP_STR:
+ DEBUGpic14_emitcode (";", "%d %s", __LINE__, aop->aopu.aop_str[offset]);
+ return newpCodeOpRegFromStr (aop->aopu.aop_str[offset]);
+
+ case AOP_PCODE:
+ pcop = NULL;
+ DEBUGpic14_emitcode (";", "popGet AOP_PCODE (%s + %i) %d %s", pCodeOpType (aop->aopu.pcop), offset,
+ __LINE__, ((aop->aopu.pcop->name) ? (aop->aopu.pcop->name) : "no name"));
+ //emitpComment ("popGet; name %s, offset: %i, pcop-type: %s\n", aop->aopu.pcop->name, offset, pCodeOpType (aop->aopu.pcop));
+ switch (aop->aopu.pcop->type)
+ {
+ case PO_IMMEDIATE:
+ pcop = pCodeOpCopy (aop->aopu.pcop);
+ /* usually we want to access the memory at "<symbol> + offset" (using ->index),
+ * but sometimes we want to access the high byte of the symbol's address (using ->offset) */
+ PCOI (pcop)->index += offset;
+ //PCOI(pcop)->offset = 0;
+ break;
+ case PO_DIR:
+ pcop = pCodeOpCopy (aop->aopu.pcop);
+ PCOR (pcop)->instance = offset;
+ break;
+ default:
+ assert (!"unhandled pCode type");
+ break;
+ } // switch
+ return pcop;
+ }
+
+ werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "popGet got unsupported aop->type");
+ exit (0);
+}
+
+/*-----------------------------------------------------------------*/
+/* popGetAddr - access the low/high word of a symbol (immediate) */
+/* (for non-PO_IMMEDIATEs this is the same as popGet) */
+/*-----------------------------------------------------------------*/
+pCodeOp *
+popGetAddr (asmop * aop, int offset, int index)
+{
+ if (aop->type == AOP_PCODE && aop->aopu.pcop->type == PO_IMMEDIATE)
+ {
+ pCodeOp *pcop = aop->aopu.pcop;
+ assert (offset <= GPTRSIZE);
+
+ /* special case: index >= 2 should return GPOINTER-style values */
+ if (offset == 2)
+ {
+ pcop = popGetLit (aop->code ? GPTRTAG_CODE : GPTRTAG_DATA);
+ return pcop;
+ }
+
+ pcop = pCodeOpCopy (pcop);
+ /* usually we want to access the memory at "<symbol> + offset" (using ->index),
+ * but sometimes we want to access the high byte of the symbol's address (using ->offset) */
+ PCOI (pcop)->offset += offset;
+ PCOI (pcop)->index += index;
+ //fprintf (stderr, "is PO_IMMEDIATE: %s+o%d+i%d (new o%d,i%d)\n", pcop->name,PCOI(pcop)->offset,PCOI(pcop)->index, offset, index);
+ return pcop;
+ }
+ else
+ {
+ return popGet (aop, offset + index);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* aopPut - puts a string for a aop */
+/*-----------------------------------------------------------------*/
+void
+aopPut (asmop * aop, const char *s, int offset)
+{
+ symbol *lbl;
+
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+
+ if (aop->size && offset > (aop->size - 1))
+ {
+ werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "aopPut got offset > aop->size");
+ exit (0);
+ }
+
+ /* will assign value to value */
+ /* depending on where it is ofcourse */
+ switch (aop->type)
+ {
+ case AOP_DIR:
+ if (offset)
+ {
+ SNPRINTF(buffer, sizeof(buffer), "(%s + %d)", aop->aopu.aop_dir, offset);
+ fprintf (stderr, "oops aopPut:AOP_DIR did this %s\n", s);
+ }
+ else
+ SNPRINTF(buffer, sizeof(buffer), "%s", aop->aopu.aop_dir);
+
+ if (strcmp (buffer, s))
+ {
+ DEBUGpic14_emitcode (";", "%d", __LINE__);
+ if (strcmp (s, "W"))
+ pic14_emitcode ("movf", "%s,w", s);
+
+ pic14_emitcode ("movwf", "%s", buffer);
+
+ if (strcmp (s, "W"))
+ {
+ pic14_emitcode (";BUG!? should have this:movf", "%s,w %d", s, __LINE__);
+ if (offset >= aop->size)
+ {
+ emitpcode (POC_CLRF, popGet (aop, offset));
+ break;
+ }
+ else
+ {
+ emitpcode (POC_MOVFW, popGetImmd (s, 0, offset, 0));
+ }
+ }
+ emitpcode (POC_MOVWF, popGet (aop, offset));
+ }
+ break;
+
+ case AOP_REG:
+ if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0)
+ {
+ if (strcmp (s, "W") == 0)
+ pic14_emitcode ("movf", "%s,w ; %d", s, __LINE__);
+
+ pic14_emitcode ("movwf", "%s", aop->aopu.aop_reg[offset]->name);
+
+ if (strcmp (s, zero) == 0)
+ {
+ emitpcode (POC_CLRF, popGet (aop, offset));
+
+ }
+ else if (strcmp (s, "W") == 0)
+ {
+ pCodeOp *pcop = Safe_alloc(sizeof(pCodeOpReg));
+ pcop->type = PO_GPR_REGISTER;
+
+ PCOR (pcop)->rIdx = -1;
+ PCOR (pcop)->r = NULL;
+
+ DEBUGpic14_emitcode (";", "%d", __LINE__);
+ pcop->name = Safe_strdup (s);
+ emitpcode (POC_MOVFW, pcop);
+ emitpcode (POC_MOVWF, popGet (aop, offset));
+ }
+ else if (strcmp (s, one) == 0)
+ {
+ emitpcode (POC_CLRF, popGet (aop, offset));
+ emitpcode (POC_INCF, popGet (aop, offset));
+ }
+ else
+ {
+ emitpcode (POC_MOVWF, popGet (aop, offset));
+ }
+ }
+ break;
+
+ case AOP_STK:
+ if (strcmp (s, "a") == 0)
+ pic14_emitcode ("push", "acc");
+ else
+ pic14_emitcode ("push", "%s", s);
+ break;
+
+ case AOP_CRY:
+ /* if bit variable */
+ if (!aop->aopu.aop_dir)
+ {
+ pic14_emitcode ("clr", "a");
+ pic14_emitcode ("rlc", "a");
+ }
+ else
+ {
+ if (s == zero)
+ pic14_emitcode ("clr", "%s", aop->aopu.aop_dir);
+ else if (s == one)
+ pic14_emitcode ("setb", "%s", aop->aopu.aop_dir);
+ else if (!strcmp (s, "c"))
+ pic14_emitcode ("mov", "%s,c", aop->aopu.aop_dir);
+ else
+ {
+ lbl = newiTempLabel (NULL);
+
+ if (strcmp (s, "a"))
+ {
+ MOVA (s);
+ }
+
+ pic14_emitcode ("clr", "c");
+ pic14_emitcode ("jz", "%05d_DS_", labelKey2num (lbl->key));
+ pic14_emitcode ("cpl", "c");
+ pic14_emitcode ("", "%05d_DS_:", labelKey2num (lbl->key));
+ pic14_emitcode ("mov", "%s,c", aop->aopu.aop_dir);
+ }
+ }
+ break;
+
+ case AOP_STR:
+ aop->coff = offset;
+ if (strcmp (aop->aopu.aop_str[offset], s))
+ pic14_emitcode ("mov", "%s,%s ; %d", aop->aopu.aop_str[offset], s, __LINE__);
+ break;
+
+ default:
+ werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "aopPut got unsupported aop->type");
+ exit(0);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* mov2w_op - generate either a MOVLW or MOVFW based operand type */
+/*-----------------------------------------------------------------*/
+static void
+mov2w_op (operand * op, int offset)
+{
+ assert (op);
+ FENTRY;
+
+ /* for PO_IMMEDIATEs: use address or value? */
+ if (op_isLitLike (op))
+ {
+ /* access address of op */
+ if (AOP_TYPE (op) != AOP_LIT)
+ {
+ assert (offset < 3);
+ }
+ if (IS_SYMOP (op) && IS_GENPTR (OP_SYM_TYPE (op)) && AOP_SIZE (op) < offset)
+ {
+ if (offset == GPTRSIZE - 1)
+ emitpcode (POC_MOVLW, popGetLit (GPTRTAG_DATA));
+ else
+ emitpcode (POC_MOVLW, popGetLit (0));
+ }
+ else
+ emitpcode (POC_MOVLW, popGetAddr (AOP (op), offset, 0));
+ }
+ else
+ {
+ /* access value stored in op */
+ mov2w (AOP (op), offset);
+ }
+}
+
+
+/*-----------------------------------------------------------------*/
+/* mov2w - generate either a MOVLW or MOVFW based operand type */
+/*-----------------------------------------------------------------*/
+void
+mov2w (asmop * aop, int offset)
+{
+
+ if (!aop)
+ return;
+
+ DEBUGpic14_emitcode ("; ***", "%s %d offset=%d", __FUNCTION__, __LINE__, offset);
+
+ if (aop_isLitLike (aop))
+ emitpcode (POC_MOVLW, popGetAddr (aop, offset, 0));
+ else
+ emitpcode (POC_MOVFW, popGet (aop, offset));
+
+}
+
+static void
+movwf (asmop * op, int offset)
+{
+ emitpcode (POC_MOVWF, popGet (op, offset));
+}
+
+static pCodeOp *
+get_argument_pcop (int idx)
+{
+ assert (idx > 0 && "the 0th (first) argument is passed via WREG");
+ return popRegFromIdx (Gstack_base_addr - (idx - 1));
+}
+
+static pCodeOp *
+get_return_val_pcop (int offset)
+{
+ assert (offset > 0 && "the most significant byte is returned via WREG");
+ return popRegFromIdx (Gstack_base_addr - (offset - 1));
+}
+
+static void
+pass_argument (operand * op, int offset, int idx)
+{
+ if (op)
+ mov2w_op (op, offset);
+ if (idx != 0)
+ emitpcode (POC_MOVWF, get_argument_pcop (idx));
+}
+
+static void
+get_returnvalue (operand * op, int offset, int idx)
+{
+ if (idx != 0)
+ emitpcode (POC_MOVFW, get_return_val_pcop (idx));
+ movwf (AOP (op), offset);
+}
+
+static void
+call_libraryfunc (char *name)
+{
+ symbol *sym;
+
+ /* library code might reside in different page... */
+ emitpcode (POC_PAGESEL, popGetWithString (name, 1));
+ /* call the library function */
+ emitpcode (POC_CALL, popGetExternal (name, 0));
+ /* might return from different page... */
+ emitpcode (POC_PAGESEL, popGetWithString ("$", 0));
+
+ /* create symbol, mark it as `extern' */
+ sym = findSym (SymbolTab, NULL, name);
+ if (!sym)
+ {
+ sym = newSymbol (name, 0);
+ strncpy (sym->rname, name, SDCC_NAME_MAX);
+ addSym (SymbolTab, sym, sym->rname, 0, 0, 0);
+ addSet (&externs, sym);
+ } // if
+ sym->used++;
+}
+
+/*-----------------------------------------------------------------*/
+/* pic14_getDataSize - get the operand data size */
+/*-----------------------------------------------------------------*/
+int
+pic14_getDataSize (operand * op)
+{
+ int size;
+
+ size = AOP_SIZE (op);
+ return size;
+}
+
+/*-----------------------------------------------------------------*/
+/* pic14_outAcc - output Acc */
+/*-----------------------------------------------------------------*/
+void
+pic14_outAcc (operand * result)
+{
+ int size, offset;
+ DEBUGpic14_emitcode ("; ***", "%s %d - ", __FUNCTION__, __LINE__);
+ DEBUGpic14_AopType (__LINE__, NULL, NULL, result);
+
+
+ size = pic14_getDataSize (result);
+ if (size)
+ {
+ emitpcode (POC_MOVWF, popGet (AOP (result), 0));
+ size--;
+ offset = 1;
+ /* unsigned or positive */
+ while (size--)
+ emitpcode (POC_CLRF, popGet (AOP (result), offset++));
+ }
+
+}
+
+/*-----------------------------------------------------------------*/
+/* pic14_outBitC - output a bit C */
+/*-----------------------------------------------------------------*/
+static void
+pic14_outBitC (operand * result)
+{
+
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ /* if the result is bit */
+ if (AOP_TYPE (result) == AOP_CRY)
+ aopPut (AOP (result), "c", 0);
+ else
+ {
+ pic14_emitcode ("clr", "a ; %d", __LINE__);
+ pic14_emitcode ("rlc", "a");
+ pic14_outAcc (result);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* pic14_toBoolean - emit code for orl a,operator(sizeop) */
+/*-----------------------------------------------------------------*/
+static void
+pic14_toBoolean (operand * oper)
+{
+ int size = AOP_SIZE (oper);
+ int offset = 0;
+
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+
+ assert (size > 0);
+
+ if (size == 1)
+ {
+ /* MOVFW does not load the flags... */
+ emitpcode (POC_MOVLW, popGetLit (0));
+ offset = 0;
+ }
+ else
+ {
+ emitpcode (POC_MOVFW, popGet (AOP (oper), 0));
+ offset = 1;
+ }
+
+ while (offset < size)
+ {
+ emitpcode (POC_IORFW, popGet (AOP (oper), offset++));
+ }
+ /* Z is set iff (oper == 0) */
+}
+
+
+/*-----------------------------------------------------------------*/
+/* genNot - generate code for ! operation */
+/*-----------------------------------------------------------------*/
+static void
+genNot (iCode * ic)
+{
+ //symbol *tlbl;
+ int size;
+
+ FENTRY;
+
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ /* assign asmOps to operand & result */
+ aopOp (IC_LEFT (ic), ic, FALSE);
+ aopOp (IC_RESULT (ic), ic, TRUE);
+
+ DEBUGpic14_AopType (__LINE__, IC_LEFT (ic), NULL, IC_RESULT (ic));
+ /* if in bit space then a special case */
+ if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
+ {
+ if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
+ {
+ emitpcode (POC_MOVLW, popGet (AOP (IC_LEFT (ic)), 0));
+ emitpcode (POC_XORWF, popGet (AOP (IC_RESULT (ic)), 0));
+ }
+ else
+ {
+ emitpcode (POC_CLRF, popGet (AOP (IC_RESULT (ic)), 0));
+ emitpcode (POC_BTFSS, popGet (AOP (IC_LEFT (ic)), 0));
+ emitpcode (POC_INCF, popGet (AOP (IC_RESULT (ic)), 0));
+ }
+ goto release;
+ }
+
+ size = AOP_SIZE (IC_LEFT (ic));
+ mov2w (AOP (IC_LEFT (ic)), 0);
+ while (--size > 0)
+ {
+ if (op_isLitLike (IC_LEFT (ic)))
+ emitpcode (POC_IORLW, popGetAddr (AOP (IC_LEFT (ic)), size, 0));
+ else
+ emitpcode (POC_IORFW, popGet (AOP (IC_LEFT (ic)), size));
+ }
+ emitpcode (POC_MOVLW, popGetLit (0));
+ emitSKPNZ;
+ emitpcode (POC_MOVLW, popGetLit (1));
+ movwf (AOP (IC_RESULT (ic)), 0);
+
+ for (size = 1; size < AOP_SIZE (IC_RESULT (ic)); size++)
+ {
+ emitpcode (POC_CLRF, popGet (AOP (IC_RESULT (ic)), size));
+ }
+ goto release;
+
+release:
+ /* release the aops */
+ freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
+ freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
+}
+
+
+/*-----------------------------------------------------------------*/
+/* genCpl - generate code for complement */
+/*-----------------------------------------------------------------*/
+static void
+genCpl (iCode * ic)
+{
+ operand *left, *result;
+ int size, offset = 0;
+
+ FENTRY;
+
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ aopOp ((left = IC_LEFT (ic)), ic, FALSE);
+ aopOp ((result = IC_RESULT (ic)), ic, TRUE);
+
+ /* if both are in bit space then
+ a special case */
+ if (AOP_TYPE (result) == AOP_CRY && AOP_TYPE (left) == AOP_CRY)
+ {
+
+ pic14_emitcode ("mov", "c,%s", left->aop->aopu.aop_dir);
+ pic14_emitcode ("cpl", "c");
+ pic14_emitcode ("mov", "%s,c", result->aop->aopu.aop_dir);
+ goto release;
+ }
+
+ size = AOP_SIZE (result);
+ if (AOP_SIZE (left) < size)
+ size = AOP_SIZE (left);
+ while (size--)
+ {
+ emitpcode (POC_COMFW, popGet (AOP (left), offset));
+ emitpcode (POC_MOVWF, popGet (AOP (result), offset));
+ offset++;
+ }
+ addSign (result, AOP_SIZE (left), !SPEC_USIGN (operandType (result)));
+
+
+release:
+ /* release the aops */
+ freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genUminusFloat - unary minus for floating points */
+/*-----------------------------------------------------------------*/
+static void
+genUminusFloat (operand * op, operand * result)
+{
+ int size;
+
+ FENTRY;
+
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ /* for this we just need to flip the
+ first it then copy the rest in place */
+ size = AOP_SIZE (op) - 1;
+
+ mov2w_op (op, size);
+ emitpcode (POC_XORLW, popGetLit (0x80));
+ movwf (AOP (result), size);
+
+ while (size--)
+ {
+ mov2w_op (op, size);
+ movwf (AOP (result), size);
+ } // while
+}
+
+/*-----------------------------------------------------------------*/
+/* genUminus - unary minus code generation */
+/*-----------------------------------------------------------------*/
+static void
+genUminus (iCode * ic)
+{
+ int size, i;
+ sym_link *optype;
+
+ FENTRY;
+
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ /* assign asmops */
+ aopOp (IC_LEFT (ic), ic, FALSE);
+ aopOp (IC_RESULT (ic), ic, TRUE);
+
+ /* if both in bit space then special
+ case */
+ if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY && AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
+ {
+
+ emitpcode (POC_BCF, popGet (AOP (IC_RESULT (ic)), 0));
+ emitpcode (POC_BTFSS, popGet (AOP (IC_LEFT (ic)), 0));
+ emitpcode (POC_BSF, popGet (AOP (IC_RESULT (ic)), 0));
+
+ goto release;
+ }
+
+ optype = operandType (IC_LEFT (ic));
+
+ /* if float then do float stuff */
+ if (IS_FLOAT (optype))
+ {
+ genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
+ goto release;
+ }
+
+ /* otherwise subtract from zero by taking the 2's complement */
+ size = AOP_SIZE (IC_LEFT (ic));
+
+ for (i = 0; i < size; i++)
+ {
+ if (pic14_sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
+ emitpcode (POC_COMF, popGet (AOP (IC_LEFT (ic)), i));
+ else
+ {
+ emitpcode (POC_COMFW, popGet (AOP (IC_LEFT (ic)), i));
+ emitpcode (POC_MOVWF, popGet (AOP (IC_RESULT (ic)), i));
+ }
+ }
+
+ emitpcode (POC_INCF, popGet (AOP (IC_RESULT (ic)), 0));
+ for (i = 1; i < size; i++)
+ {
+ emitSKPNZ;
+ emitpcode (POC_INCF, popGet (AOP (IC_RESULT (ic)), i));
+ }
+
+release:
+ /* release the aops */
+ freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
+ freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* saverbank - saves an entire register bank on the stack */
+/*-----------------------------------------------------------------*/
+static void
+saverbank (int bank, iCode * ic, bool pushPsw)
+{
+ FENTRY;
+
+ DEBUGpic14_emitcode ("; ***", "%s %d - WARNING no code generated", __FUNCTION__, __LINE__);
+#if 0
+ int i;
+ asmop *aop;
+ regs *r = NULL;
+
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ if (options.useXstack)
+ {
+
+ aop = newAsmop (0);
+ r = getFreePtr (ic, &aop, FALSE);
+ pic14_emitcode ("mov", "%s,_spx", r->name);
+
+ }
+
+ for (i = 0; i < pic14_nRegs; i++)
+ {
+ if (options.useXstack)
+ {
+ pic14_emitcode ("inc", "%s", r->name);
+ //pic14_emitcode("mov","a,(%s+%d)",
+ // regspic14[i].base,8*bank+regspic14[i].offset);
+ pic14_emitcode ("movx", "@%s,a", r->name);
+ }
+ else
+ pic14_emitcode ("push", ""); // "(%s+%d)",
+ //regspic14[i].base,8*bank+regspic14[i].offset);
+ }
+
+ if (pushPsw)
+ {
+ if (options.useXstack)
+ {
+ pic14_emitcode ("mov", "a,psw");
+ pic14_emitcode ("movx", "@%s,a", r->name);
+ pic14_emitcode ("inc", "%s", r->name);
+ pic14_emitcode ("mov", "_spx,%s", r->name);
+ freeAsmop (NULL, aop, ic, TRUE);
+
+ }
+ else
+ pic14_emitcode ("push", "psw");
+
+ pic14_emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0x00ff);
+ }
+ ic->bankSaved = 1;
+#endif
+}
+
+/*-----------------------------------------------------------------*/
+/* saveRegisters - will look for a call and save the registers */
+/*-----------------------------------------------------------------*/
+static void
+saveRegisters (iCode * lic)
+{
+ iCode *ic;
+ sym_link *dtype;
+
+ FENTRY;
+
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+
+ /* look for call */
+ for (ic = lic; ic; ic = ic->next)
+ if (ic->op == CALL || ic->op == PCALL)
+ break;
+
+ if (!ic)
+ {
+ fprintf (stderr, "found parameter push with no function call\n");
+ return;
+ }
+
+ /* if the registers have been saved already then do nothing */
+ if (ic->regsSaved || IFFUNC_CALLEESAVES (OP_SYMBOL (IC_LEFT (ic))->type))
+ return;
+
+ /* find the registers in use at this time
+ and push them away to safety */
+ bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
+
+ ic->regsSaved = 1;
+
+ //fprintf(stderr, "ERROR: saveRegisters did not do anything to save registers, please report this as a bug.\n");
+
+ dtype = operandType (IC_LEFT (ic));
+ if (currFunc && dtype &&
+ (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) && IFFUNC_ISISR (currFunc->type) && !ic->bankSaved)
+ {
+ saverbank (FUNC_REGBANK (dtype), ic, TRUE);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* unsaveRegisters - pop the pushed registers */
+/*-----------------------------------------------------------------*/
+static void
+unsaveRegisters (iCode * ic)
+{
+ int i;
+ bitVect *rsave;
+
+ FENTRY;
+
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ /* find the registers in use at this time
+ and push them away to safety */
+ rsave = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
+
+ if (options.useXstack)
+ {
+ pic14_emitcode ("mov", "r0,%s", spname);
+ for (i = pic14_nRegs; i >= 0; i--)
+ {
+ if (bitVectBitValue (rsave, i))
+ {
+ pic14_emitcode ("dec", "r0");
+ pic14_emitcode ("movx", "a,@r0");
+ pic14_emitcode ("mov", "%s,a", pic14_regWithIdx (i)->name);
+ }
+
+ }
+ pic14_emitcode ("mov", "%s,r0", spname);
+ } //else
+ //for (i = pic14_nRegs ; i >= 0 ; i--) {
+ // if (bitVectBitValue(rsave,i))
+ // pic14_emitcode("pop","%s",pic14_regWithIdx(i)->dname);
+ //}
+
+}
+
+
+/*-----------------------------------------------------------------*/
+/* pushSide - */
+/*-----------------------------------------------------------------*/
+static void
+pushSide (operand * oper, int size)
+{
+#if 0
+ int offset = 0;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ while (size--)
+ {
+ char *l = aopGet (AOP (oper), offset++, FALSE, TRUE);
+ if (AOP_TYPE (oper) != AOP_REG && AOP_TYPE (oper) != AOP_DIR && strcmp (l, "a"))
+ {
+ pic14_emitcode ("mov", "a,%s", l);
+ pic14_emitcode ("push", "acc");
+ }
+ else
+ pic14_emitcode ("push", "%s", l);
+ }
+#endif
+}
+
+/*-----------------------------------------------------------------*/
+/* assignResultValue - */
+/*-----------------------------------------------------------------*/
+static void
+assignResultValue (operand * oper)
+{
+ int size = AOP_SIZE (oper);
+ int offset = 0;
+
+ FENTRY;
+
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+
+ DEBUGpic14_AopType (__LINE__, oper, NULL, NULL);
+
+ /* assign MSB first (passed via WREG) */
+ while (size--)
+ {
+ get_returnvalue (oper, size, offset + GpseudoStkPtr);
+ GpseudoStkPtr++;
+ }
+}
+
+
+/*-----------------------------------------------------------------*/
+/* genIpush - genrate code for pushing this gets a little complex */
+/*-----------------------------------------------------------------*/
+static void
+genIpush (iCode * ic)
+{
+ FENTRY;
+
+ DEBUGpic14_emitcode ("; ***", "%s %d - WARNING no code generated", __FUNCTION__, __LINE__);
+#if 0
+ int size, offset = 0;
+ char *l;
+
+
+ /* if this is not a parm push : ie. it is spill push
+ and spill push is always done on the local stack */
+ if (!ic->parmPush)
+ {
+
+ /* and the item is spilt then do nothing */
+ if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
+ return;
+
+ aopOp (IC_LEFT (ic), ic, FALSE);
+ size = AOP_SIZE (IC_LEFT (ic));
+ /* push it on the stack */
+ while (size--)
+ {
+ l = aopGet (AOP (IC_LEFT (ic)), offset++, FALSE, TRUE);
+ if (*l == '#')
+ {
+ MOVA (l);
+ l = "acc";
+ }
+ pic14_emitcode ("push", "%s", l);
+ }
+ return;
+ }
+
+ /* this is a paramter push: in this case we call
+ the routine to find the call and save those
+ registers that need to be saved */
+ saveRegisters (ic);
+
+ /* then do the push */
+ aopOp (IC_LEFT (ic), ic, FALSE);
+
+
+ // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
+ size = AOP_SIZE (IC_LEFT (ic));
+
+ while (size--)
+ {
+ l = aopGet (AOP (IC_LEFT (ic)), offset++, FALSE, TRUE);
+ if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG && AOP_TYPE (IC_LEFT (ic)) != AOP_DIR && strcmp (l, "a"))
+ {
+ pic14_emitcode ("mov", "a,%s", l);
+ pic14_emitcode ("push", "acc");
+ }
+ else
+ pic14_emitcode ("push", "%s", l);
+ }
+
+ freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
+#endif
+}
+
+/*-----------------------------------------------------------------*/
+/* genIpop - recover the registers: can happen only for spilling */
+/*-----------------------------------------------------------------*/
+static void
+genIpop (iCode * ic)
+{
+ FENTRY;
+
+ DEBUGpic14_emitcode ("; ***", "%s %d - WARNING no code generated", __FUNCTION__, __LINE__);
+ assert (!"genIpop -- unimplemented");
+#if 0
+ int size, offset;
+
+
+ /* if the temp was not pushed then */
+ if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
+ return;
+
+ aopOp (IC_LEFT (ic), ic, FALSE);
+ size = AOP_SIZE (IC_LEFT (ic));
+ offset = (size - 1);
+ while (size--)
+ pic14_emitcode ("pop", "%s", aopGet (AOP (IC_LEFT (ic)), offset--, FALSE, TRUE));
+
+ freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
+#endif
+}
+
+/*-----------------------------------------------------------------*/
+/* unsaverbank - restores the resgister bank from stack */
+/*-----------------------------------------------------------------*/
+static void
+unsaverbank (int bank, iCode * ic, bool popPsw)
+{
+ FENTRY;
+
+ DEBUGpic14_emitcode ("; ***", "%s %d - WARNING no code generated", __FUNCTION__, __LINE__);
+#if 0
+ int i;
+ asmop *aop;
+ regs *r = NULL;
+
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ if (popPsw)
+ {
+ if (options.useXstack)
+ {
+ aop = newAsmop (0);
+ r = getFreePtr (ic, &aop, FALSE);
+
+
+ pic14_emitcode ("mov", "%s,_spx", r->name);
+ pic14_emitcode ("movx", "a,@%s", r->name);
+ pic14_emitcode ("mov", "psw,a");
+ pic14_emitcode ("dec", "%s", r->name);
+
+ }
+ else
+ pic14_emitcode ("pop", "psw");
+ }
+
+ for (i = (pic14_nRegs - 1); i >= 0; i--)
+ {
+ if (options.useXstack)
+ {
+ pic14_emitcode ("movx", "a,@%s", r->name);
+ //pic14_emitcode("mov","(%s+%d),a",
+ // regspic14[i].base,8*bank+regspic14[i].offset);
+ pic14_emitcode ("dec", "%s", r->name);
+
+ }
+ else
+ pic14_emitcode ("pop", ""); //"(%s+%d)",
+ //regspic14[i].base,8*bank); //+regspic14[i].offset);
+ }
+
+ if (options.useXstack)
+ {
+
+ pic14_emitcode ("mov", "_spx,%s", r->name);
+ freeAsmop (NULL, aop, ic, TRUE);
+
+ }
+#endif
+}
+
+/*-----------------------------------------------------------------*/
+/* genCall - generates a call statement */
+/*-----------------------------------------------------------------*/
+static void
+genCall (iCode * ic)
+{
+ sym_link *dtype;
+ symbol *sym;
+ char *name;
+ int isExtern;
+
+ FENTRY;
+
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+
+ /* if caller saves & we have not saved then */
+ if (!ic->regsSaved)
+ saveRegisters (ic);
+
+ /* if we are calling a function that is not using
+ the same register bank then we need to save the
+ destination registers on the stack */
+ dtype = operandType (IC_LEFT (ic));
+ if (currFunc && dtype &&
+ (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) && IFFUNC_ISISR (currFunc->type) && !ic->bankSaved)
+
+ saverbank (FUNC_REGBANK (dtype), ic, TRUE);
+
+ /* if send set is not empty the assign */
+ if (_G.sendSet)
+ {
+ iCode *sic;
+ /* For the Pic port, there is no data stack.
+ * So parameters passed to functions are stored
+ * in registers. (The pCode optimizer will get
+ * rid of most of these :).
+ */
+ int pseudoStkPtr = -1;
+ int firstTimeThruLoop = 1;
+
+ _G.sendSet = reverseSet (_G.sendSet);
+
+ /* First figure how many parameters are getting passed */
+ for (sic = setFirstItem (_G.sendSet); sic; sic = setNextItem (_G.sendSet))
+ {
+
+ aopOp (IC_LEFT (sic), sic, FALSE);
+ pseudoStkPtr += AOP_SIZE (IC_LEFT (sic));
+ freeAsmop (IC_LEFT (sic), NULL, sic, FALSE);
+ }
+
+ for (sic = setFirstItem (_G.sendSet); sic; sic = setNextItem (_G.sendSet))
+ {
+ int size, offset = 0;
+
+ aopOp (IC_LEFT (sic), sic, FALSE);
+ size = AOP_SIZE (IC_LEFT (sic));
+
+ while (size--)
+ {
+ DEBUGpic14_emitcode ("; ", "%d left %s", __LINE__, AopType (AOP_TYPE (IC_LEFT (sic))));
+
+ if (!firstTimeThruLoop)
+ {
+ /* If this is not the first time we've been through the loop
+ * then we need to save the parameter in a temporary
+ * register. The last byte of the last parameter is
+ * passed in W. */
+ emitpcode (POC_MOVWF, popRegFromIdx (Gstack_base_addr - --pseudoStkPtr));
+
+ }
+ firstTimeThruLoop = 0;
+
+ mov2w_op (IC_LEFT (sic), offset);
+ offset++;
+ }
+ freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
+ }
+ _G.sendSet = NULL;
+ }
+ /* make the call */
+ sym = OP_SYMBOL (IC_LEFT (ic));
+ name = sym->rname[0] ? sym->rname : sym->name;
+ /*
+ * As SDCC emits code as soon as it reaches the end of each
+ * function's definition, prototyped functions that are implemented
+ * after the current one are always considered EXTERN, which
+ * introduces many unneccessary PAGESEL instructions.
+ * XXX: Use a post pass to iterate over all `CALL _name' statements
+ * and insert `PAGESEL _name' and `PAGESEL $' around the CALL
+ * only iff there is no definition of the function in the whole
+ * file (might include this in the PAGESEL pass).
+ */
+ isExtern = IS_EXTERN (sym->etype) || pic14_inISR;
+#if 0
+ if (isExtern)
+ {
+ /* Extern functions and ISRs maybe on a different page;
+ * must call pagesel */
+#endif
+ emitpcode (POC_PAGESEL, popGetWithString (name, 1));
+#if 0
+ }
+#endif
+
+ emitpcode (POC_CALL, popGetWithString (name, isExtern));
+#if 0
+ if (isExtern)
+ {
+ /* May have returned from a different page;
+ * must use pagesel to restore PCLATH before next
+ * goto or call instruction */
+#endif
+ emitpcode (POC_PAGESEL, popGetWithString ("$", 0));
+#if 0
+ }
+#endif
+ GpseudoStkPtr = 0;
+ /* if we need assign a result value */
+ if ((IS_ITEMP (IC_RESULT (ic)) &&
+ (OP_SYMBOL (IC_RESULT (ic))->nRegs || OP_SYMBOL (IC_RESULT (ic))->spildir)) || IS_TRUE_SYMOP (IC_RESULT (ic)))
+ {
+ _G.accInUse++;
+ aopOp (IC_RESULT (ic), ic, FALSE);
+ _G.accInUse--;
+
+ assignResultValue (IC_RESULT (ic));
+
+ DEBUGpic14_emitcode ("; ", "%d left %s", __LINE__, AopType (AOP_TYPE (IC_RESULT (ic))));
+
+ freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
+ }
+
+ /* if register bank was saved then pop them */
+ if (ic->bankSaved)
+ unsaverbank (FUNC_REGBANK (dtype), ic, TRUE);
+
+ /* if we hade saved some registers then unsave them */
+ if (ic->regsSaved && !IFFUNC_CALLEESAVES (dtype))
+ unsaveRegisters (ic);
+}
+
+/*-----------------------------------------------------------------*/
+/* genPcall - generates a call by pointer statement */
+/*-----------------------------------------------------------------*/
+static void
+genPcall (iCode * ic)
+{
+ sym_link *dtype;
+ symbol *albl = newiTempLabel (NULL);
+ symbol *blbl = newiTempLabel (NULL);
+ PIC_OPCODE poc;
+ pCodeOp *pcop;
+ operand *left;
+
+ FENTRY;
+
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ /* if caller saves & we have not saved then */
+ if (!ic->regsSaved)
+ saveRegisters (ic);
+
+ /* if we are calling a function that is not using
+ the same register bank then we need to save the
+ destination registers on the stack */
+ dtype = operandType (IC_LEFT (ic));
+ if (currFunc && dtype && IFFUNC_ISISR (currFunc->type) && (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)))
+ saverbank (FUNC_REGBANK (dtype), ic, TRUE);
+
+ left = IC_LEFT (ic);
+ aopOp (left, ic, FALSE);
+ DEBUGpic14_AopType (__LINE__, left, NULL, NULL);
+
+ poc = (op_isLitLike (IC_LEFT (ic)) ? POC_MOVLW : POC_MOVFW);
+
+ pushSide (IC_LEFT (ic), FARPTRSIZE);
+
+ /* if send set is not empty, assign parameters */
+ if (_G.sendSet)
+ {
+ DEBUGpic14_emitcode ("; ***", "%s %d - WARNING arg-passing to indirect call not supported", __FUNCTION__, __LINE__);
+ /* no way to pass args - W always gets used to make the call */
+ }
+ /* first idea - factor out a common helper function and call it.
+ But don't know how to get it generated only once in its own block
+
+ if(AOP_TYPE(IC_LEFT(ic)) == AOP_DIR) {
+ char *rname;
+ char *buffer;
+ size_t len;
+
+ rname = IC_LEFT(ic)->aop->aopu.aop_dir;
+ DEBUGpic14_emitcode ("; ***","%s %d AOP_DIR %s",__FUNCTION__,__LINE__,rname);
+ len = strlen(rname) + 16;
+ buffer = Safe_alloc(len);
+ SNPRINTF(buffer, len, "%s_goto_helper", rname);
+ addpCode2pBlock(pb,newpCode(POC_CALL,newpCodeOp(buffer,PO_STR)));
+ free(buffer);
+ }
+ */
+ emitpcode (POC_CALL, popGetLabel (albl->key));
+ pcop = popGetLabel (blbl->key);
+ emitpcode (POC_PAGESEL, pcop); /* Must restore PCLATH before goto, without destroying W */
+ emitpcode (POC_GOTO, pcop);
+ emitpLabel (albl->key);
+
+ emitpcode (poc, popGetAddr (AOP (left), 1, 0));
+ emitpcode (POC_MOVWF, popCopyReg (&pc_pclath));
+ emitpcode (poc, popGetAddr (AOP (left), 0, 0));
+ emitpcode (POC_MOVWF, popCopyReg (&pc_pcl));
+
+ emitpLabel (blbl->key);
+
+ freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
+
+ /* if we need to assign a result value */
+ if ((IS_ITEMP (IC_RESULT (ic)) &&
+ (OP_SYMBOL (IC_RESULT (ic))->nRegs || OP_SYMBOL (IC_RESULT (ic))->spildir)) || IS_TRUE_SYMOP (IC_RESULT (ic)))
+ {
+
+ _G.accInUse++;
+ aopOp (IC_RESULT (ic), ic, FALSE);
+ _G.accInUse--;
+
+ GpseudoStkPtr = 0;
+
+ assignResultValue (IC_RESULT (ic));
+
+ freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
+ }
+
+ /* if register bank was saved then unsave them */
+ if (currFunc && dtype && (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)))
+ unsaverbank (FUNC_REGBANK (dtype), ic, TRUE);
+
+ /* if we hade saved some registers then
+ unsave them */
+ if (ic->regsSaved)
+ unsaveRegisters (ic);
+}
+
+/*-----------------------------------------------------------------*/
+/* resultRemat - result is rematerializable */
+/*-----------------------------------------------------------------*/
+static int
+resultRemat (iCode * ic)
+{
+ // DEBUGpic14_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
+ FENTRY;
+
+ if (SKIP_IC (ic) || ic->op == IFX)
+ return 0;
+
+ if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
+ {
+ symbol *sym = OP_SYMBOL (IC_RESULT (ic));
+ if (sym->remat && !POINTER_SET (ic))
+ return 1;
+ }
+
+ return 0;
+}
+
+/*-----------------------------------------------------------------*/
+/* genFunction - generated code for function entry */
+/*-----------------------------------------------------------------*/
+static void
+genFunction (iCode * ic)
+{
+ symbol *sym;
+ sym_link *ftype;
+
+ FENTRY;
+
+ DEBUGpic14_emitcode ("; ***", "%s %d curr label offset=%dprevious max_key=%d ", __FUNCTION__, __LINE__, labelOffset,
+ max_key);
+
+ labelOffset += (max_key + 4);
+ max_key = 0;
+ GpseudoStkPtr = 0;
+ _G.nRegsSaved = 0;
+ /* create the function header */
+ pic14_emitcode (";", "-----------------------------------------");
+ pic14_emitcode (";", " function %s", (sym = OP_SYMBOL (IC_LEFT (ic)))->name);
+ pic14_emitcode (";", "-----------------------------------------");
+
+ /* prevent this symbol from being emitted as 'extern' */
+ pic14_stringInSet (sym->rname, &pic14_localFunctions, 1);
+
+ pic14_emitcode ("", "%s:", sym->rname);
+ addpCode2pBlock (pb, newpCodeFunction (moduleName, sym->rname, !IS_STATIC (sym->etype), IFFUNC_ISISR (sym->type)));
+
+ /* mark symbol as NOT extern (even if it was declared so previously) */
+ assert (IS_SPEC (sym->etype));
+ SPEC_EXTR (sym->etype) = 0;
+ sym->cdef = 0;
+ if (!SPEC_OCLS (sym->etype))
+ SPEC_OCLS (sym->etype) = code;
+ addSetIfnotP (&SPEC_OCLS (sym->etype)->syms, sym);
+
+ ftype = operandType (IC_LEFT (ic));
+
+ /* here we need to generate the equates for the
+ register bank if required */
+#if 0
+ if (FUNC_REGBANK (ftype) != rbank)
+ {
+ int i;
+
+ rbank = FUNC_REGBANK (ftype);
+ for (i = 0; i < pic14_nRegs; i++)
+ {
+ if (strcmp (regspic14[i].base, "0") == 0)
+ pic14_emitcode ("", "%s = 0x%02x", regspic14[i].dname, 8 * rbank + regspic14[i].offset);
+ else
+ pic14_emitcode ("", "%s = %s + 0x%02x", regspic14[i].dname, regspic14[i].base, 8 * rbank + regspic14[i].offset);
+ }
+ }
+#endif
+
+ /* if this is an interrupt service routine */
+ pic14_inISR = 0;
+ if (IFFUNC_ISISR (sym->type))
+ {
+ pic14_inISR = 1;
+
+ /* generate ISR prolog if and not naked */
+ if (!IFFUNC_ISNAKED (sym->type))
+ {
+ if (pic->isEnhancedCore)
+ {
+ /*
+ * Enhanced CPUs have automatic context saving for W,
+ * STATUS, BSR, FSRx, and PCLATH in shadow registers.
+ */
+ emitpcode (POC_CLRF, popCopyReg (&pc_pclath));
+ }
+ else
+ {
+ emitpcode (POC_MOVWF, popCopyReg (&pc_wsave));
+ emitpcode (POC_SWAPFW, popCopyReg (&pc_status));
+ /* XXX: Why? Does this assume that ssave and psave reside
+ * in a shared bank or bank0? We cannot guarantee the
+ * latter...
+ */
+ emitpcode (POC_CLRF, popCopyReg (&pc_status));
+ emitpcode (POC_MOVWF, popCopyReg (&pc_ssave));
+ //emitpcode(POC_MOVWF, popGetExternal("___sdcc_saved_status",1 ));
+ emitpcode (POC_MOVFW, popCopyReg (&pc_pclath));
+ /* during an interrupt PCLATH must be cleared before a goto or call statement */
+ emitpcode (POC_CLRF, popCopyReg (&pc_pclath));
+ emitpcode (POC_MOVWF, popCopyReg (&pc_psave));
+ //emitpcode(POC_MOVWF, popGetExternal("___sdcc_saved_pclath", 1));
+ emitpcode (POC_MOVFW, popCopyReg (&pc_fsr));
+ emitpcode (POC_MOVWF, popGetExternal ("___sdcc_saved_fsr", 1));
+ }
+ }
+
+ pBlockConvert2ISR (pb);
+ pic14_hasInterrupt = 1;
+ }
+ else
+ {
+ /* if callee-save to be used for this function
+ then save the registers being used in this function */
+ if (IFFUNC_CALLEESAVES (sym->type))
+ {
+ int i;
+
+ /* if any registers used */
+ if (sym->regsUsed)
+ {
+ /* save the registers used */
+ for (i = 0; i < sym->regsUsed->size; i++)
+ {
+ if (bitVectBitValue (sym->regsUsed, i))
+ {
+ //pic14_emitcode("push","%s",pic14_regWithIdx(i)->dname);
+ _G.nRegsSaved++;
+ }
+ }
+ }
+ }
+ }
+
+ /* if critical function then turn interrupts off */
+ if (IFFUNC_ISCRITICAL (ftype))
+ {
+ genCritical (NULL);
+ if (IFFUNC_ARGS (sym->type))
+ {
+ fprintf (stderr, "PIC14: Functions with __critical (%s) must not have arguments for now.\n", sym->name);
+ exit (1);
+ } // if
+ } // if
+
+ /* set the register bank to the desired value */
+ if (FUNC_REGBANK (sym->type) || FUNC_ISISR (sym->type))
+ {
+ pic14_emitcode ("push", "psw");
+ pic14_emitcode ("mov", "psw,#0x%02x", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
+ }
+
+ if (IFFUNC_ISREENT (sym->type) || options.stackAuto)
+ {
+
+ if (options.useXstack)
+ {
+ pic14_emitcode ("mov", "r0,%s", spname);
+ pic14_emitcode ("mov", "a,_bp");
+ pic14_emitcode ("movx", "@r0,a");
+ pic14_emitcode ("inc", "%s", spname);
+ }
+ else
+ {
+ /* set up the stack */
+ pic14_emitcode ("push", "_bp"); /* save the callers stack */
+ }
+ pic14_emitcode ("mov", "_bp,%s", spname);
+ }
+
+ /* adjust the stack for the function */
+ if (sym->stack)
+ {
+
+ int i = sym->stack;
+ if (i > 256)
+ werror (W_STACK_OVERFLOW, sym->name);
+
+ if (i > 3 && sym->recvSize < 4)
+ {
+
+ pic14_emitcode ("mov", "a,sp");
+ pic14_emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
+ pic14_emitcode ("mov", "sp,a");
+
+ }
+ else
+ while (i--)
+ pic14_emitcode ("inc", "sp");
+ }
+
+ if (sym->xstack)
+ {
+
+ pic14_emitcode ("mov", "a,_spx");
+ pic14_emitcode ("add", "a,#0x%02x", ((char) sym->xstack & 0xff));
+ pic14_emitcode ("mov", "_spx,a");
+ }
+
+}
+
+/*-----------------------------------------------------------------*/
+/* genEndFunction - generates epilogue for functions */
+/*-----------------------------------------------------------------*/
+static void
+genEndFunction (iCode * ic)
+{
+ symbol *sym = OP_SYMBOL (IC_LEFT (ic));
+
+ FENTRY;
+
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+
+ if (IFFUNC_ISREENT (sym->type) || options.stackAuto)
+ {
+ pic14_emitcode ("mov", "%s,_bp", spname);
+ }
+
+ /* if use external stack but some variables were
+ added to the local stack then decrement the
+ local stack */
+ if (options.useXstack && sym->stack)
+ {
+ pic14_emitcode ("mov", "a,sp");
+ pic14_emitcode ("add", "a,#0x%02x", ((char) - sym->stack) & 0xff);
+ pic14_emitcode ("mov", "sp,a");
+ }
+
+
+ if ((IFFUNC_ISREENT (sym->type) || options.stackAuto))
+ {
+ if (options.useXstack)
+ {
+ pic14_emitcode ("mov", "r0,%s", spname);
+ pic14_emitcode ("movx", "a,@r0");
+ pic14_emitcode ("mov", "_bp,a");
+ pic14_emitcode ("dec", "%s", spname);
+ }
+ else
+ {
+ pic14_emitcode ("pop", "_bp");
+ }
+ }
+
+ /* restore the register bank */
+ if (FUNC_REGBANK (sym->type) || FUNC_ISISR (sym->type))
+ pic14_emitcode ("pop", "psw");
+
+ /* if critical function then turn interrupts off */
+ if (IFFUNC_ISCRITICAL (sym->type))
+ {
+ genEndCritical (NULL);
+ } // if
+
+ if (IFFUNC_ISISR (sym->type))
+ {
+
+ /* now we need to restore the registers */
+ /* if this isr has no bank i.e. is going to
+ run with bank 0 , then we need to save more
+ registers :-) */
+ if (!FUNC_REGBANK (sym->type))
+ {
+
+ /* if this function does not call any other
+ function then we can be economical and
+ save only those registers that are used */
+ if (!IFFUNC_HASFCALL (sym->type))
+ {
+ int i;
+
+ /* if any registers used */
+ if (sym->regsUsed)
+ {
+ /* save the registers used */
+ for (i = sym->regsUsed->size; i >= 0; i--)
+ {
+ if (bitVectBitValue (sym->regsUsed, i))
+ {
+ pic14_emitcode ("pop", "junk"); //"%s",pic14_regWithIdx(i)->dname);
+ }
+ }
+ }
+
+ }
+ else
+ {
+ /* this function has a function call; cannot
+ determines register usage so we will have the
+ entire bank */
+ unsaverbank (0, ic, FALSE);
+ }
+ }
+
+ /* if debug then send end of function */
+ if (options.debug && debugFile && currFunc)
+ {
+ debugFile->writeEndFunction (currFunc, ic, 1);
+ }
+
+ /* generate ISR epilog if not enhanced core and not naked */
+ if (!pic->isEnhancedCore && !IFFUNC_ISNAKED (sym->type))
+ {
+ emitpcode (POC_MOVFW, popGetExternal ("___sdcc_saved_fsr", 1));
+ emitpcode (POC_MOVWF, popCopyReg (&pc_fsr));
+ //emitpcode(POC_MOVFW, popGetExternal("___sdcc_saved_pclath", 1));
+ emitpcode (POC_MOVFW, popCopyReg (&pc_psave));
+ emitpcode (POC_MOVWF, popCopyReg (&pc_pclath));
+ emitpcode (POC_CLRF, popCopyReg (&pc_status)); // see genFunction
+ //emitpcode(POC_SWAPFW, popGetExternal("___sdcc_saved_status", 1));
+ emitpcode (POC_SWAPFW, popCopyReg (&pc_ssave));
+ emitpcode (POC_MOVWF, popCopyReg (&pc_status));
+ emitpcode (POC_SWAPF, popCopyReg (&pc_wsave));
+ emitpcode (POC_SWAPFW, popCopyReg (&pc_wsave));
+ }
+ addpCode2pBlock (pb, newpCodeLabel ("END_OF_INTERRUPT", -1));
+ emitpcodeNULLop (POC_RETFIE);
+ }
+ else
+ {
+ if (IFFUNC_ISCRITICAL (sym->type))
+ pic14_emitcode ("setb", "ea");
+
+ if (IFFUNC_CALLEESAVES (sym->type))
+ {
+ int i;
+
+ /* if any registers used */
+ if (sym->regsUsed)
+ {
+ /* save the registers used */
+ for (i = sym->regsUsed->size; i >= 0; i--)
+ {
+ if (bitVectBitValue (sym->regsUsed, i))
+ {
+ pic14_emitcode ("pop", "junk"); //"%s",pic14_regWithIdx(i)->dname);
+ }
+ }
+ }
+ }
+
+ /* if debug then send end of function */
+ if (options.debug && debugFile && currFunc)
+ {
+ debugFile->writeEndFunction (currFunc, ic, 1);
+ }
+
+ pic14_emitcode ("return", "");
+ emitpcodeNULLop (POC_RETURN);
+
+ /* Mark the end of a function */
+ addpCode2pBlock (pb, newpCodeFunction (moduleName, NULL, 0, 0));
+ }
+
+}
+
+/*-----------------------------------------------------------------*/
+/* genRet - generate code for return statement */
+/*-----------------------------------------------------------------*/
+static void
+genRet (iCode * ic)
+{
+ int size, offset = 0;
+
+ FENTRY;
+
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ /* if we have no return value then
+ just generate the "ret" */
+ if (!IC_LEFT (ic))
+ goto jumpret;
+
+ /* we have something to return then
+ move the return value into place */
+ aopOp (IC_LEFT (ic), ic, FALSE);
+ size = AOP_SIZE (IC_LEFT (ic));
+
+ for (offset = 0; offset < size; offset++)
+ {
+ pass_argument (IC_LEFT (ic), offset, size - 1 - offset);
+ }
+
+ freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
+
+jumpret:
+ /* generate a jump to the return label
+ if the next is not the return statement */
+ if (!(ic->next && ic->next->op == LABEL && IC_LABEL (ic->next) == returnLabel))
+ {
+
+ emitpcode (POC_GOTO, popGetLabel (returnLabel->key));
+ }
+
+}
+
+static set *critical_temps = NULL;
+
+static void
+genCritical (iCode * ic)
+{
+ pCodeOp *saved_intcon;
+
+ (void) ic;
+
+ if (!critical_temps)
+ critical_temps = newSet ();
+
+ saved_intcon = popGetTempReg ();
+ addSetHead (&critical_temps, saved_intcon);
+
+ /* This order saves one BANKSEL back to INTCON. */
+ emitpcode (POC_MOVFW, popCopyReg (&pc_intcon));
+ emitpcode (POC_BCF, popCopyGPR2Bit (popCopyReg (&pc_intcon), 7));
+ emitpcode (POC_MOVWF, pCodeOpCopy (saved_intcon));
+}
+
+static void
+genEndCritical (iCode * ic)
+{
+ pCodeOp *saved_intcon = NULL;
+
+ (void) ic;
+
+ saved_intcon = getSet (&critical_temps);
+ if (!saved_intcon)
+ {
+ fprintf (stderr, "Critical section left, but none entered -- ignoring for now.\n");
+ return;
+ } // if
+
+ emitpcode (POC_BTFSC, popCopyGPR2Bit (pCodeOpCopy (saved_intcon), 7));
+ emitpcode (POC_BSF, popCopyGPR2Bit (popCopyReg (&pc_intcon), 7));
+ popReleaseTempReg (saved_intcon);
+}
+
+/*-----------------------------------------------------------------*/
+/* genLabel - generates a label */
+/*-----------------------------------------------------------------*/
+static void
+genLabel (iCode * ic)
+{
+ FENTRY;
+
+ /* special case never generate */
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ if (IC_LABEL (ic) == entryLabel)
+ return;
+
+ emitpLabel (IC_LABEL (ic)->key);
+ pic14_emitcode ("", "_%05d_DS_:", labelKey2num (IC_LABEL (ic)->key + labelOffset));
+}
+
+/*-----------------------------------------------------------------*/
+/* genGoto - generates a goto */
+/*-----------------------------------------------------------------*/
+//tsd
+static void
+genGoto (iCode * ic)
+{
+ FENTRY;
+
+ emitpcode (POC_GOTO, popGetLabel (IC_LABEL (ic)->key));
+ pic14_emitcode ("goto", "_%05d_DS_", labelKey2num (IC_LABEL (ic)->key + labelOffset));
+}
+
+
+/*-----------------------------------------------------------------*/
+/* genMultbits :- multiplication of bits */
+/*-----------------------------------------------------------------*/
+static void
+genMultbits (operand * left, operand * right, operand * result)
+{
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+
+ if (!pic14_sameRegs (AOP (result), AOP (right)))
+ emitpcode (POC_BSF, popGet (AOP (result), 0));
+
+ emitpcode (POC_BTFSC, popGet (AOP (right), 0));
+ emitpcode (POC_BTFSS, popGet (AOP (left), 0));
+ emitpcode (POC_BCF, popGet (AOP (result), 0));
+
+}
+
+
+/*-----------------------------------------------------------------*/
+/* genMultOneByte : 8 bit multiplication & division */
+/*-----------------------------------------------------------------*/
+static void
+genMultOneByte (operand * left, operand * right, operand * result)
+{
+ char *func[] = { NULL, "__mulchar", "__mulint", NULL, "__mullong" };
+
+ // symbol *lbl ;
+ int size, offset, i;
+
+
+ FENTRY;
+
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ DEBUGpic14_AopType (__LINE__, left, right, result);
+ DEBUGpic14_AopTypeSign (__LINE__, left, right, result);
+
+ /* (if two literals, the value is computed before) */
+ /* if one literal, literal on the right */
+ if (AOP_TYPE (left) == AOP_LIT)
+ {
+ operand *t = right;
+ right = left;
+ left = t;
+ }
+
+ assert (AOP_SIZE (left) == AOP_SIZE (right));
+
+ size = min (AOP_SIZE (result), AOP_SIZE (left));
+ offset = Gstack_base_addr - (2 * size - 1);
+
+ /* pass right operand as argument */
+ for (i = 0; i < size; i++)
+ {
+ mov2w (AOP (right), i);
+ emitpcode (POC_MOVWF, popRegFromIdx (++offset));
+ } // for
+
+ /* pass left operand as argument */
+ for (i = 0; i < size; i++)
+ {
+ mov2w (AOP (left), i);
+ if (i != size - 1)
+ emitpcode (POC_MOVWF, popRegFromIdx (++offset));
+ } // for
+ assert (offset == Gstack_base_addr);
+
+ /* call library routine */
+ assert (size > 0 && size <= 4);
+ call_libraryfunc (func[size]);
+
+ /* assign result */
+ movwf (AOP (result), size - 1);
+ for (i = 0; i < size - 1; i++)
+ {
+ emitpcode (POC_MOVFW, popRegFromIdx (Gstack_base_addr - i));
+ movwf (AOP (result), size - 2 - i);
+ } // for
+
+ /* now (zero-/sign) extend the result to its size */
+ addSign (result, AOP_SIZE (left), !SPEC_USIGN (operandType (result)));
+}
+
+/*-----------------------------------------------------------------*/
+/* genMult - generates code for multiplication */
+/*-----------------------------------------------------------------*/
+static void
+genMult (iCode * ic)
+{
+ operand *left = IC_LEFT (ic);
+ operand *right = IC_RIGHT (ic);
+ operand *result = IC_RESULT (ic);
+
+ FENTRY;
+
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ /* assign the amsops */
+ aopOp (left, ic, FALSE);
+ aopOp (right, ic, FALSE);
+ aopOp (result, ic, TRUE);
+
+ DEBUGpic14_AopType (__LINE__, left, right, result);
+
+ /* special cases first */
+ /* both are bits */
+ if (AOP_TYPE (left) == AOP_CRY && AOP_TYPE (right) == AOP_CRY)
+ {
+ genMultbits (left, right, result);
+ goto release;
+ }
+
+ /* if both are of size == 1 */
+ if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1)
+ {
+ genMultOneByte (left, right, result);
+ goto release;
+ }
+
+ /* should have been converted to function call */
+ assert (0);
+
+release:
+ freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genDivbits :- division of bits */
+/*-----------------------------------------------------------------*/
+static void
+genDivbits (operand * left, operand * right, operand * result)
+{
+
+ char *l;
+
+ FENTRY;
+
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ /* the result must be bit */
+ pic14_emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
+ l = aopGet (AOP (left), 0, FALSE, FALSE);
+
+ MOVA (l);
+
+ pic14_emitcode ("div", "ab");
+ pic14_emitcode ("rrc", "a");
+ aopPut (AOP (result), "c", 0);
+}
+
+/*-----------------------------------------------------------------*/
+/* genDivOneByte : 8 bit division */
+/*-----------------------------------------------------------------*/
+static void
+genDivOneByte (operand * left, operand * right, operand * result)
+{
+ int sign;
+
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+
+ assert (AOP_SIZE (right) == 1);
+ assert (AOP_SIZE (left) == 1);
+
+ sign = !(SPEC_USIGN (operandType (left)) && SPEC_USIGN (operandType (right)));
+
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ /* XXX: might add specialized code */
+ }
+
+ if (!sign)
+ {
+ /* unsigned division */
+#if 1
+ mov2w (AOP (right), 0);
+ emitpcode (POC_MOVWF, popRegFromIdx (Gstack_base_addr));
+ mov2w (AOP (left), 0);
+ call_libraryfunc ("__divuchar");
+ movwf (AOP (result), 0);
+#else
+ pCodeOp *temp;
+ symbol *lbl;
+
+ temp = popGetTempReg ();
+ lbl = newiTempLabel (NULL);
+
+ /* XXX: improve this naive approach:
+ [result] = [a] / [b]
+ ::= [result] = 0; while ([a] > [b]) do [a] -= [b]; [result]++ done
+
+ In PIC assembler:
+ movf left,W
+ movwf temp // temp <-- left
+ movf right,W // W <-- right
+ clrf result
+ label1:
+ incf result
+ subwf temp,F // temp <-- temp - W
+ skipNC // subwf clears CARRY (i.e. sets BORROW) if temp < W
+ goto label1
+ decf result // we just subtract once too often
+ */
+
+ /* XXX: This loops endlessly on DIVIDE BY ZERO */
+ /* We need 1..128 iterations of the loop body (`4 / 5' .. `255 / 2'). */
+
+ mov2w (AOP (left), 0);
+ emitpcode (POC_MOVWF, temp);
+ mov2w (AOP (right), 0);
+ emitpcode (POC_CLRF, popGet (AOP (result), 0));
+
+ emitpLabel (lbl->key);
+ emitpcode (POC_INCF, popGet (AOP (result), 0));
+ emitpcode (POC_SUBWF, temp);
+ emitSKPNC;
+
+ if (pic->isEnhancedCore)
+ {
+ emitpcode (POC_BRA, popGetLabel (lbl->key));
+ }
+ else
+ {
+ emitpcode (POC_GOTO, popGetLabel (lbl->key));
+ }
+
+ emitpcode (POC_DECF, popGet (AOP (result), 0));
+ popReleaseTempReg (temp);
+#endif
+ }
+ else
+ {
+ /* signed division */
+ mov2w (AOP (right), 0);
+ emitpcode (POC_MOVWF, popRegFromIdx (Gstack_base_addr));
+ mov2w (AOP (left), 0);
+ call_libraryfunc ("__divschar");
+ movwf (AOP (result), 0);
+ }
+
+ /* now performed the signed/unsigned division -- extend result */
+ addSign (result, 1, sign);
+}
+
+/*-----------------------------------------------------------------*/
+/* genDiv - generates code for division */
+/*-----------------------------------------------------------------*/
+static void
+genDiv (iCode * ic)
+{
+ operand *left = IC_LEFT (ic);
+ operand *right = IC_RIGHT (ic);
+ operand *result = IC_RESULT (ic);
+
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ /* assign the amsops */
+ aopOp (left, ic, FALSE);
+ aopOp (right, ic, FALSE);
+ aopOp (result, ic, TRUE);
+
+ /* special cases first */
+ /* both are bits */
+ if (AOP_TYPE (left) == AOP_CRY && AOP_TYPE (right) == AOP_CRY)
+ {
+ genDivbits (left, right, result);
+ goto release;
+ }
+
+ /* if both are of size == 1 */
+ if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1)
+ {
+ genDivOneByte (left, right, result);
+ goto release;
+ }
+
+ /* should have been converted to function call */
+ assert (0);
+release:
+ freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genModOneByte : 8 bit modulus */
+/*-----------------------------------------------------------------*/
+static void
+genModOneByte (operand * left, operand * right, operand * result)
+{
+ int sign;
+
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+
+ assert (AOP_SIZE (right) == 1);
+ assert (AOP_SIZE (left) == 1);
+
+ sign = !(SPEC_USIGN (operandType (left)) && SPEC_USIGN (operandType (right)));
+
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ /* XXX: might add specialized code */
+ }
+
+ if (!sign)
+ {
+ /* unsigned division */
+#if 1
+ mov2w (AOP (right), 0);
+ emitpcode (POC_MOVWF, popRegFromIdx (Gstack_base_addr));
+ mov2w (AOP (left), 0);
+ call_libraryfunc ("__moduchar");
+ movwf (AOP (result), 0);
+#else
+ pCodeOp *temp;
+ symbol *lbl;
+
+ lbl = newiTempLabel (NULL);
+
+ assert (!pic14_sameRegs (AOP (right), AOP (result)));
+
+ /* XXX: improve this naive approach:
+ [result] = [a] % [b]
+ ::= [result] = [a]; while ([result] > [b]) do [result] -= [b]; done
+
+ In PIC assembler:
+ movf left,W
+ movwf result // result <-- left
+ movf right,W // W <-- right
+ label1:
+ subwf result,F // result <-- result - W
+ skipNC // subwf clears CARRY (i.e. sets BORROW) if result < W
+ goto label1
+ addwf result, F // we just subtract once too often
+ */
+
+ /* XXX: This loops endlessly on DIVIDE BY ZERO */
+ /* We need 1..128 iterations of the loop body (`4 % 5' .. `255 % 2'). */
+
+ if (!pic14_sameRegs (AOP (left), AOP (result)))
+ {
+ mov2w (AOP (left), 0);
+ emitpcode (POC_MOVWF, popGet (AOP (result), 0));
+ }
+ mov2w (AOP (right), 0);
+
+ emitpLabel (lbl->key);
+ emitpcode (POC_SUBWF, popGet (AOP (result), 0));
+ emitSKPNC;
+
+ if (pic->isEnhancedCore)
+ {
+ emitpcode (POC_BRA, popGetLabel (lbl->key));
+ }
+ else
+ {
+ emitpcode (POC_GOTO, popGetLabel (lbl->key));
+ }
+
+ emitpcode (POC_ADDWF, popGet (AOP (result), 0));
+#endif
+ }
+ else
+ {
+ /* signed division */
+ mov2w (AOP (right), 0);
+ emitpcode (POC_MOVWF, popRegFromIdx (Gstack_base_addr));
+ mov2w (AOP (left), 0);
+ call_libraryfunc ("__modschar");
+ movwf (AOP (result), 0);
+ }
+
+ /* now we performed the signed/unsigned modulus -- extend result */
+ addSign (result, 1, sign);
+}
+
+/*-----------------------------------------------------------------*/
+/* genMod - generates code for division */
+/*-----------------------------------------------------------------*/
+static void
+genMod (iCode * ic)
+{
+ operand *left = IC_LEFT (ic);
+ operand *right = IC_RIGHT (ic);
+ operand *result = IC_RESULT (ic);
+
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ /* assign the amsops */
+ aopOp (left, ic, FALSE);
+ aopOp (right, ic, FALSE);
+ aopOp (result, ic, TRUE);
+
+ /* if both are of size == 1 */
+ if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1)
+ {
+ genModOneByte (left, right, result);
+ goto release;
+ }
+
+ /* should have been converted to function call */
+ assert (0);
+
+release:
+ freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genIfxJump :- will create a jump depending on the ifx */
+/*-----------------------------------------------------------------*/
+/*
+note: May need to add parameter to indicate when a variable is in bit space.
+*/
+static void
+genIfxJump (iCode * ic, char *jval)
+{
+
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ /* if true label then we jump if condition
+ supplied is true */
+ if (IC_TRUE (ic))
+ {
+
+ if (strcmp (jval, "a") == 0)
+ emitSKPZ;
+ else if (strcmp (jval, "c") == 0)
+ emitSKPC;
+ else
+ {
+ DEBUGpic14_emitcode ("; ***", "%d - assuming %s is in bit space", __LINE__, jval);
+ emitpcode (POC_BTFSC, newpCodeOpBit (jval, -1, 1));
+ }
+
+ emitpcode (POC_GOTO, popGetLabel (IC_TRUE (ic)->key));
+ pic14_emitcode (" goto", "_%05d_DS_", labelKey2num (IC_TRUE (ic)->key + labelOffset));
+
+ }
+ else
+ {
+ /* false label is present */
+ if (strcmp (jval, "a") == 0)
+ emitSKPNZ;
+ else if (strcmp (jval, "c") == 0)
+ emitSKPNC;
+ else
+ {
+ DEBUGpic14_emitcode ("; ***", "%d - assuming %s is in bit space", __LINE__, jval);
+ emitpcode (POC_BTFSS, newpCodeOpBit (jval, -1, 1));
+ }
+
+ emitpcode (POC_GOTO, popGetLabel (IC_FALSE (ic)->key));
+ pic14_emitcode (" goto", "_%05d_DS_", labelKey2num (IC_FALSE (ic)->key + labelOffset));
+
+ }
+
+
+ /* mark the icode as generated */
+ ic->generated = TRUE;
+}
+
+/*-----------------------------------------------------------------*/
+/* genSkipc */
+/*-----------------------------------------------------------------*/
+static void
+genSkipc (resolvedIfx * rifx)
+{
+ FENTRY;
+ if (!rifx)
+ return;
+
+ if (rifx->condition)
+ emitSKPNC;
+ else
+ emitSKPC;
+
+ emitpcode (POC_GOTO, popGetLabel (rifx->lbl->key));
+ emitpComment ("%s:%u: created from rifx:%p", __FUNCTION__, __LINE__, rifx);
+ rifx->generated = TRUE;
+}
+
+#define isAOP_REGlike(x) (AOP_TYPE(x) == AOP_REG || AOP_TYPE(x) == AOP_DIR || AOP_TYPE(x) == AOP_PCODE)
+#define isAOP_LIT(x) (AOP_TYPE(x) == AOP_LIT)
+#define DEBUGpc emitpComment
+
+/*-----------------------------------------------------------------*/
+/* mov2w_regOrLit :- move to WREG either the offset's byte from */
+/* aop (if it's NOT a literal) or from lit (if */
+/* aop is a literal) */
+/*-----------------------------------------------------------------*/
+static void
+pic14_mov2w_regOrLit (asmop * aop, unsigned long lit, int offset)
+{
+ if (aop->type == AOP_LIT)
+ {
+ emitpcode (POC_MOVLW, popGetLit ((lit >> (offset * 8)) & 0x00FF));
+ }
+ else
+ {
+ emitpcode (POC_MOVFW, popGet (aop, offset));
+ }
+}
+
+/* genCmp performs a left < right comparison, stores
+ * the outcome in result (if != NULL) and generates
+ * control flow code for the ifx (if != NULL).
+ *
+ * This version leaves in sequences like
+ * "B[CS]F STATUS,0; BTFS[CS] STATUS,0"
+ * which should be optmized by the peephole
+ * optimizer - RN 2005-01-01 */
+static void
+genCmp (operand * left, operand * right, operand * result, iCode * ifx, int sign)
+{
+ resolvedIfx rIfx;
+ int size;
+ int offs;
+ symbol *templbl;
+ operand *dummy;
+ unsigned long lit;
+ unsigned long mask;
+ int performedLt;
+ int invert_result = 0;
+
+ FENTRY;
+
+ assert (AOP_SIZE (left) == AOP_SIZE (right));
+ assert (left && right);
+
+ size = AOP_SIZE (right) - 1;
+ mask = (0x100UL << (size * 8)) - 1;
+ // in the end CARRY holds "left < right" (performedLt == 1) or "left >= right" (performedLt == 0)
+ performedLt = 1;
+ templbl = NULL;
+ lit = 0;
+
+ resolveIfx (&rIfx, ifx);
+
+ /**********************************************************************
+ * handle bits - bit compares are promoted to int compares seemingly! *
+ **********************************************************************/
+#if 0
+ // THIS IS COMPLETELY UNTESTED!
+ if (AOP_TYPE (left) == AOP_CRY && AOP_TYPE (right) == AOP_CRY)
+ {
+ pCodeOp *pcleft = pic16_popGet (AOP (left), 0);
+ pCodeOp *pcright = pic16_popGet (AOP (right), 0);
+ assert (pcleft->type == PO_GPR_BIT && pcright->type == PO_GPR_BIT);
+
+ emitSETC;
+ // 1 < {0,1} is false --> clear C by skipping the next instruction
+ //pic16_emitpcode (POC_BTFSS, pic16_popCopyGPR2Bit (AOP (left),0), PCORB (pcleft)->bit);
+ pic16_emitpcode (POC_BTFSS, pic16_popGet (AOP (left), 0));
+ // {0,1} < 0 is false --> clear C by NOT skipping the next instruction
+ pic16_emitpcode (POC_BTFSS, pic16_popCopyGPR2Bit (pic16_popGet (AOP (right), 0), PCORB (pcright)->bit));
+ emitCLRC; // only skipped for left=0 && right=1
+
+ goto correct_result_in_carry;
+ } // if
+#endif
+
+ /*************************************************
+ * make sure that left is register (or the like) *
+ *************************************************/
+ if (!isAOP_REGlike (left))
+ {
+ DEBUGpc ("swapping arguments (AOP_TYPEs %d/%d)", AOP_TYPE (left), AOP_TYPE (right));
+ assert (isAOP_LIT (left));
+ assert (isAOP_REGlike (right));
+ // swap left and right
+ // left < right <==> right > left <==> (right >= left + 1)
+ lit = ulFromVal (AOP (left)->aopu.aop_lit);
+
+ if ((!sign && (lit & mask) == mask) || (sign && (lit & mask) == (mask >> 1)))
+ {
+ // MAXVALUE < right? always false
+ if (performedLt)
+ emitCLRC;
+ else
+ emitSETC;
+ goto correct_result_in_carry;
+ } // if
+
+ // This fails for lit = 0xFF (unsigned) AND lit = 0x7F (signed),
+ // that's why we handled it above.
+ lit++;
+
+ dummy = left;
+ left = right;
+ right = dummy;
+
+ performedLt ^= 1; // instead of "left < right" we check for "right >= left+1, i.e. "right < left+1"
+ }
+ else if (isAOP_LIT (right))
+ {
+ lit = ulFromVal (AOP (right)->aopu.aop_lit);
+ } // if
+
+ assert (isAOP_REGlike (left)); // left must be register or the like
+ assert (isAOP_REGlike (right) || isAOP_LIT (right)); // right may be register-like or a literal
+
+ /*************************************************
+ * special cases go here *
+ *************************************************/
+
+ if (isAOP_LIT (right))
+ {
+ if (!sign)
+ {
+ // unsigned comparison to a literal
+ DEBUGpc ("unsigned compare: left %s lit(0x%X=%lu), size=%d", performedLt ? "<" : ">=", lit, lit, size + 1);
+ if (lit == 0)
+ {
+ // unsigned left < 0? always false
+ if (performedLt)
+ emitCLRC;
+ else
+ emitSETC;
+ goto correct_result_in_carry;
+ }
+ }
+ else
+ {
+ // signed comparison to a literal
+ DEBUGpc ("signed compare: left %s lit(0x%X=%ld), size=%d, mask=%x", performedLt ? "<" : ">=", lit, lit, size + 1,
+ mask);
+ if ((lit & mask) == ((0x80 << (size * 8)) & mask))
+ {
+ // signed left < 0x80000000? always false
+ if (performedLt)
+ emitCLRC;
+ else
+ emitSETC;
+ goto correct_result_in_carry;
+ }
+ else if (lit == 0)
+ {
+ // compare left < 0; set CARRY if SIGNBIT(left) is set
+ if (performedLt)
+ emitSETC;
+ else
+ emitCLRC;
+ emitpcode (POC_BTFSS, newpCodeOpBit (aopGet (AOP (left), size, FALSE, FALSE), 7, 0));
+ if (performedLt)
+ emitCLRC;
+ else
+ emitSETC;
+ goto correct_result_in_carry;
+ }
+ } // if (!sign)
+ } // right is literal
+
+ /*************************************************
+ * perform a general case comparison *
+ * make sure we get CARRY==1 <==> left >= right *
+ *************************************************/
+ // compare most significant bytes
+ //DEBUGpc ("comparing bytes at offset %d", size);
+ if (!sign)
+ {
+ // unsigned comparison
+ pic14_mov2w_regOrLit (AOP (right), lit, size);
+ emitpcode (POC_SUBFW, popGet (AOP (left), size));
+ }
+ else
+ {
+ // signed comparison
+ // (add 2^n to both operands then perform an unsigned comparison)
+ if (isAOP_LIT (right))
+ {
+ // left >= LIT <-> LIT-left <= 0 <-> LIT-left == 0 OR !(LIT-left >= 0)
+ unsigned char litbyte = (lit >> (8 * size)) & 0xFF;
+
+ if (litbyte == 0x80)
+ {
+ // left >= 0x80 -- always true, but more bytes to come
+ mov2w (AOP (left), size);
+ emitpcode (POC_XORLW, popGetLit (0x80)); // set ZERO flag
+ emitSETC;
+ }
+ else
+ {
+ // left >= LIT <-> left + (-LIT) >= 0 <-> left + (0x100-LIT) >= 0x100
+ mov2w (AOP (left), size);
+ emitpcode (POC_ADDLW, popGetLit (0x80));
+ emitpcode (POC_ADDLW, popGetLit ((0x100 - (litbyte + 0x80)) & 0x00FF));
+ } // if
+ }
+ else
+ {
+ pCodeOp *pctemp = popGetTempReg ();
+ mov2w (AOP (left), size);
+ emitpcode (POC_ADDLW, popGetLit (0x80));
+ emitpcode (POC_MOVWF, pctemp);
+ mov2w (AOP (right), size);
+ emitpcode (POC_ADDLW, popGetLit (0x80));
+ emitpcode (POC_SUBFW, pctemp);
+ popReleaseTempReg (pctemp);
+ }
+ } // if (!sign)
+
+ // compare remaining bytes (treat as unsigned case from above)
+ templbl = newiTempLabel (NULL);
+ offs = size;
+ while (offs--)
+ {
+ //DEBUGpc ("comparing bytes at offset %d", offs);
+ emitSKPZ;
+
+ if (pic->isEnhancedCore)
+ {
+ emitpcode (POC_BRA, popGetLabel (templbl->key));
+ }
+ else
+ {
+ emitpcode (POC_GOTO, popGetLabel (templbl->key));
+ }
+
+ pic14_mov2w_regOrLit (AOP (right), lit, offs);
+ emitpcode (POC_SUBFW, popGet (AOP (left), offs));
+ } // while (offs)
+ emitpLabel (templbl->key);
+ goto result_in_carry;
+
+result_in_carry:
+
+ /****************************************************
+ * now CARRY contains the result of the comparison: *
+ * SUBWF sets CARRY iff *
+ * F-W >= 0 <==> F >= W <==> !(F < W) *
+ * (F=left, W=right) *
+ ****************************************************/
+
+ if (performedLt)
+ {
+ invert_result = 1;
+ // value will be used in the following genSkipc ()
+ rIfx.condition ^= TRUE;
+ } // if
+
+correct_result_in_carry:
+
+ // assign result to variable (if neccessary), but keep CARRY intact to be used below
+ if (result && AOP_TYPE (result) != AOP_CRY)
+ {
+ //DEBUGpc ("assign result");
+ size = AOP_SIZE (result);
+ while (size--)
+ {
+ emitpcode (POC_CLRF, popGet (AOP (result), size));
+ } // while
+ if (invert_result)
+ {
+ emitSKPC;
+ emitpcode (POC_BSF, newpCodeOpBit (aopGet (AOP (result), 0, FALSE, FALSE), 0, 0));
+ }
+ else
+ {
+ emitpcode (POC_RLF, popGet (AOP (result), 0));
+ if (ifx)
+ {
+ /* Result is expected to be in CARRY by genSkipc () below. */
+ emitpcode (POC_RRFW, popGet (AOP (result), 0));
+ } // if
+ } // if
+ } // if (result)
+
+ // perform conditional jump
+ if (ifx)
+ {
+ //DEBUGpc ("generate control flow");
+ genSkipc (&rIfx);
+ ifx->generated = TRUE;
+ } // if
+}
+
+/*-----------------------------------------------------------------*/
+/* genCmpGt :- greater than comparison */
+/*-----------------------------------------------------------------*/
+static void
+genCmpGt (iCode * ic, iCode * ifx)
+{
+ operand *left, *right, *result;
+ sym_link *letype, *retype;
+ int sign;
+
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ left = IC_LEFT (ic);
+ right = IC_RIGHT (ic);
+ result = IC_RESULT (ic);
+
+ sign = 0;
+ if (IS_SPEC (operandType (left)) && IS_SPEC (operandType (right)))
+ {
+ letype = getSpec (operandType (left));
+ retype = getSpec (operandType (right));
+ sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
+ }
+
+ /* assign the amsops */
+ aopOp (left, ic, FALSE);
+ aopOp (right, ic, FALSE);
+ aopOp (result, ic, TRUE);
+
+ genCmp (right, left, result, ifx, sign);
+
+ freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genCmpLt - less than comparisons */
+/*-----------------------------------------------------------------*/
+static void
+genCmpLt (iCode * ic, iCode * ifx)
+{
+ operand *left, *right, *result;
+ sym_link *letype, *retype;
+ int sign;
+
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ left = IC_LEFT (ic);
+ right = IC_RIGHT (ic);
+ result = IC_RESULT (ic);
+
+ sign = 0;
+ if (IS_SPEC (operandType (left)) && IS_SPEC (operandType (right)))
+ {
+ letype = getSpec (operandType (left));
+ retype = getSpec (operandType (right));
+ sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
+ }
+
+ /* assign the amsops */
+ aopOp (left, ic, FALSE);
+ aopOp (right, ic, FALSE);
+ aopOp (result, ic, TRUE);
+
+ genCmp (left, right, result, ifx, sign);
+
+ freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genCmpEq - generates code for equal to */
+/*-----------------------------------------------------------------*/
+static void
+genCmpEq (iCode * ic, iCode * ifx)
+{
+ operand *left, *right, *result;
+ int size;
+ symbol *false_label;
+
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+
+ if (ifx)
+ DEBUGpic14_emitcode ("; ifx is non-null", "");
+ else
+ DEBUGpic14_emitcode ("; ifx is null", "");
+
+ aopOp ((left = IC_LEFT (ic)), ic, FALSE);
+ aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
+ aopOp ((result = IC_RESULT (ic)), ic, TRUE);
+
+ DEBUGpic14_AopType (__LINE__, left, right, result);
+
+ /* if literal, move literal to right */
+ if (op_isLitLike (IC_LEFT (ic)))
+ {
+ operand *tmp = right;
+ right = left;
+ left = tmp;
+ }
+
+ false_label = NULL;
+ if (ifx && !IC_TRUE (ifx))
+ {
+ assert (IC_FALSE (ifx));
+ false_label = IC_FALSE (ifx);
+ }
+
+ size = min (AOP_SIZE (left), AOP_SIZE (right));
+ assert (!pic14_sameRegs (AOP (result), AOP (left)));
+ assert (!pic14_sameRegs (AOP (result), AOP (right)));
+
+ /* assume left != right */
+ {
+ int i;
+ for (i = 0; i < AOP_SIZE (result); i++)
+ {
+ emitpcode (POC_CLRF, popGet (AOP (result), i));
+ }
+ }
+
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ unsigned long lit = ulFromVal (AOP (right)->aopu.aop_lit);
+ int i;
+ size = AOP_SIZE (left);
+ assert (!op_isLitLike (left));
+
+ switch (lit)
+ {
+ case 0:
+ mov2w (AOP (left), 0);
+ for (i = 1; i < size; i++)
+ emitpcode (POC_IORFW, popGet (AOP (left), i));
+ /* now Z is set iff `left == right' */
+ emitSKPZ;
+ if (!false_label)
+ false_label = newiTempLabel (NULL);
+ emitpcode (POC_GOTO, popGetLabel (false_label->key));
+ break;
+
+ default:
+ for (i = 0; i < size; i++)
+ {
+ mov2w (AOP (left), i);
+ emitpcode (POC_XORLW, popGetLit (lit >> (8 * i)));
+ /* now Z is cleared if `left != right' */
+ emitSKPZ;
+ if (!false_label)
+ false_label = newiTempLabel (NULL);
+ emitpcode (POC_GOTO, popGetLabel (false_label->key));
+ } // for i
+ break;
+ } // switch (lit)
+ }
+ else
+ {
+ /* right is no literal */
+ int i;
+
+ for (i = 0; i < size; i++)
+ {
+ mov2w (AOP (right), i);
+ emitpcode (POC_XORFW, popGet (AOP (left), i));
+ /* now Z is cleared if `left != right' */
+ emitSKPZ;
+ if (!false_label)
+ false_label = newiTempLabel (NULL);
+ emitpcode (POC_GOTO, popGetLabel (false_label->key));
+ } // for i
+ }
+
+ /* if we reach here, left == right */
+
+ if (AOP_SIZE (result) > 0)
+ {
+ emitpcode (POC_INCF, popGet (AOP (result), 0));
+ }
+
+ if (ifx && IC_TRUE (ifx))
+ {
+ emitpcode (POC_GOTO, popGetLabel (IC_TRUE (ifx)->key));
+ }
+
+ if (false_label && (!ifx || IC_TRUE (ifx)))
+ emitpLabel (false_label->key);
+
+ if (ifx)
+ ifx->generated = TRUE;
+
+ freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genAndOp - for && operation */
+/*-----------------------------------------------------------------*/
+static void
+genAndOp (iCode * ic)
+{
+ operand *left, *right, *result;
+ /* symbol *tlbl; */
+
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ /* note here that && operations that are in an
+ if statement are taken away by backPatchLabels
+ only those used in arthmetic operations remain */
+ aopOp ((left = IC_LEFT (ic)), ic, FALSE);
+ aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
+ aopOp ((result = IC_RESULT (ic)), ic, FALSE);
+
+ DEBUGpic14_AopType (__LINE__, left, right, result);
+
+ emitpcode (POC_MOVFW, popGet (AOP (left), 0));
+ emitpcode (POC_ANDFW, popGet (AOP (right), 0));
+ emitpcode (POC_MOVWF, popGet (AOP (result), 0));
+
+ /* if both are bit variables */
+ /* if (AOP_TYPE(left) == AOP_CRY && */
+ /* AOP_TYPE(right) == AOP_CRY ) { */
+ /* pic14_emitcode("mov","c,%s",AOP(left)->aopu.aop_dir); */
+ /* pic14_emitcode("anl","c,%s",AOP(right)->aopu.aop_dir); */
+ /* pic14_outBitC(result); */
+ /* } else { */
+ /* tlbl = newiTempLabel(NULL); */
+ /* pic14_toBoolean(left); */
+ /* pic14_emitcode("jz","%05d_DS_",labelKey2num (tlbl->key)); */
+ /* pic14_toBoolean(right); */
+ /* pic14_emitcode("","%05d_DS_:",labelKey2num (tlbl->key)); */
+ /* pic14_outBitAcc(result); */
+ /* } */
+
+ freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+
+/*-----------------------------------------------------------------*/
+/* genOrOp - for || operation */
+/*-----------------------------------------------------------------*/
+/*
+tsd pic port -
+modified this code, but it doesn't appear to ever get called
+*/
+
+static void
+genOrOp (iCode * ic)
+{
+ operand *left, *right, *result;
+ symbol *tlbl;
+ int i;
+
+ /* note here that || operations that are in an
+ if statement are taken away by backPatchLabels
+ only those used in arthmetic operations remain */
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ aopOp ((left = IC_LEFT (ic)), ic, FALSE);
+ aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
+ aopOp ((result = IC_RESULT (ic)), ic, FALSE);
+
+ DEBUGpic14_AopType (__LINE__, left, right, result);
+
+ for (i = 0; i < AOP_SIZE (result); i++)
+ {
+ emitpcode (POC_CLRF, popGet (AOP (result), i));
+ } // for i
+
+ tlbl = newiTempLabel (NULL);
+ pic14_toBoolean (left);
+ emitSKPZ;
+ emitpcode (POC_GOTO, popGetLabel (tlbl->key));
+ pic14_toBoolean (right);
+ emitpLabel (tlbl->key);
+ /* here Z is clear IFF `left || right' */
+ emitSKPZ;
+ emitpcode (POC_INCF, popGet (AOP (result), 0));
+
+ freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* isLiteralBit - test if lit == 2^n */
+/*-----------------------------------------------------------------*/
+static int
+isLiteralBit (unsigned long lit)
+{
+ unsigned long pw[32] = { 1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
+ 0x100L, 0x200L, 0x400L, 0x800L,
+ 0x1000L, 0x2000L, 0x4000L, 0x8000L,
+ 0x10000L, 0x20000L, 0x40000L, 0x80000L,
+ 0x100000L, 0x200000L, 0x400000L, 0x800000L,
+ 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
+ 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L
+ };
+ int idx;
+
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ for (idx = 0; idx < 32; idx++)
+ if (lit == pw[idx])
+ return idx + 1;
+ return 0;
+}
+
+/*-----------------------------------------------------------------*/
+/* continueIfTrue - */
+/*-----------------------------------------------------------------*/
+static void
+continueIfTrue (iCode * ic)
+{
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ if (IC_TRUE (ic))
+ {
+ emitpcode (POC_GOTO, popGetLabel (labelKey2num (IC_TRUE (ic)->key)));
+ pic14_emitcode ("ljmp", "%05d_DS_", labelKey2num (IC_FALSE (ic)->key));
+ }
+ ic->generated = TRUE;
+}
+
+/*-----------------------------------------------------------------*/
+/* jmpIfTrue - */
+/*-----------------------------------------------------------------*/
+static void
+jumpIfTrue (iCode * ic)
+{
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ if (!IC_TRUE (ic))
+ {
+ emitpcode (POC_GOTO, labelKey2num (popGetLabel (IC_TRUE (ic)->key)));
+ pic14_emitcode ("ljmp", "%05d_DS_", labelKey2num (IC_FALSE (ic)->key));
+ }
+ ic->generated = TRUE;
+}
+
+/*-----------------------------------------------------------------*/
+/* jmpTrueOrFalse - */
+/*-----------------------------------------------------------------*/
+static void
+jmpTrueOrFalse (iCode * ic, symbol * tlbl)
+{
+ FENTRY;
+ // ugly but optimized by peephole
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ if (IC_TRUE (ic))
+ {
+ symbol *nlbl = newiTempLabel (NULL);
+ pic14_emitcode ("sjmp", "%05d_DS_", labelKey2num (nlbl->key));
+ pic14_emitcode ("", "%05d_DS_:", labelKey2num (tlbl->key));
+ pic14_emitcode ("ljmp", "%05d_DS_", labelKey2num (IC_TRUE (ic)->key));
+ pic14_emitcode ("", "%05d_DS_:", labelKey2num (nlbl->key));
+ }
+ else
+ {
+ pic14_emitcode ("ljmp", "%05d_DS_", labelKey2num (IC_FALSE (ic)->key));
+ pic14_emitcode ("", "%05d_DS_:", labelKey2num (tlbl->key));
+ }
+ ic->generated = TRUE;
+}
+
+/*-----------------------------------------------------------------*/
+/* genAnd - code for and */
+/*-----------------------------------------------------------------*/
+static void
+genAnd (iCode * ic, iCode * ifx)
+{
+ operand *left, *right, *result;
+ int size, offset = 0;
+ unsigned long lit = 0L;
+ int bytelit = 0;
+ resolvedIfx rIfx;
+
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ aopOp ((left = IC_LEFT (ic)), ic, FALSE);
+ aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
+ aopOp ((result = IC_RESULT (ic)), ic, TRUE);
+
+ resolveIfx (&rIfx, ifx);
+
+ /* if left is a literal & right is not then exchange them */
+ if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) || AOP_NEEDSACC (left))
+ {
+ operand *tmp = right;
+ right = left;
+ left = tmp;
+ }
+
+ /* if result = right then exchange them */
+ if (pic14_sameRegs (AOP (result), AOP (right)))
+ {
+ operand *tmp = right;
+ right = left;
+ left = tmp;
+ }
+
+ /* if right is bit then exchange them */
+ if (AOP_TYPE (right) == AOP_CRY && AOP_TYPE (left) != AOP_CRY)
+ {
+ operand *tmp = right;
+ right = left;
+ left = tmp;
+ }
+ if (AOP_TYPE (right) == AOP_LIT)
+ lit = ulFromVal (AOP (right)->aopu.aop_lit);
+
+ size = AOP_SIZE (result);
+
+ DEBUGpic14_AopType (__LINE__, left, right, result);
+
+ // if(bit & yy)
+ // result = bit & yy;
+ if (AOP_TYPE (left) == AOP_CRY)
+ {
+ // c = bit & literal;
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ if (lit & 1)
+ {
+ if (size && pic14_sameRegs (AOP (result), AOP (left)))
+ // no change
+ goto release;
+ pic14_emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
+ }
+ else
+ {
+ // bit(result) = 0;
+ if (size && (AOP_TYPE (result) == AOP_CRY))
+ {
+ pic14_emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
+ goto release;
+ }
+ if ((AOP_TYPE (result) == AOP_CRY) && ifx)
+ {
+ jumpIfTrue (ifx);
+ goto release;
+ }
+ pic14_emitcode ("clr", "c");
+ }
+ }
+ else
+ {
+ if (AOP_TYPE (right) == AOP_CRY)
+ {
+ // c = bit & bit;
+ pic14_emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
+ pic14_emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
+ }
+ else
+ {
+ // c = bit & val;
+ MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
+ // c = lsb
+ pic14_emitcode ("rrc", "a");
+ pic14_emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
+ }
+ }
+ // bit = c
+ // val = c
+ if (size)
+ pic14_outBitC (result);
+ // if(bit & ...)
+ else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
+ genIfxJump (ifx, "c");
+ goto release;
+ }
+
+ // if(val & 0xZZ) - size = 0, ifx != FALSE -
+ // bit = val & 0xZZ - size = 1, ifx = FALSE -
+ if ((AOP_TYPE (right) == AOP_LIT) && (AOP_TYPE (result) == AOP_CRY) && (AOP_TYPE (left) != AOP_CRY))
+ {
+ int posbit = isLiteralBit (lit);
+ /* left & 2^n */
+ if (posbit)
+ {
+ posbit--;
+ //MOVA(aopGet(AOP(left),posbit>>3,FALSE,FALSE));
+ // bit = left & 2^n
+ if (size)
+ pic14_emitcode ("mov", "c,acc.%d", posbit & 0x07);
+ // if(left & 2^n)
+ else
+ {
+ if (ifx)
+ {
+ int offset = 0;
+ while (posbit > 7)
+ {
+ posbit -= 8;
+ offset++;
+ }
+ emitpcode (((rIfx.condition) ? POC_BTFSC : POC_BTFSS),
+ newpCodeOpBit (aopGet (AOP (left), offset, FALSE, FALSE), posbit, 0));
+ emitpcode (POC_GOTO, popGetLabel (rIfx.lbl->key));
+
+ ifx->generated = TRUE;
+ }
+ goto release;
+ }
+ }
+ else
+ {
+ symbol *tlbl = newiTempLabel (NULL);
+ int sizel = AOP_SIZE (left);
+ if (size)
+ pic14_emitcode ("setb", "c");
+ while (sizel--)
+ {
+ if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
+ {
+ // byte == 2^n ?
+ if ((posbit = isLiteralBit (bytelit)) != 0)
+ {
+ emitpcode (POC_BTFSC,
+ newpCodeOpBit (aopGet (AOP (left), offset, FALSE, FALSE), posbit - 1, 0));
+ }
+ else
+ {
+ mov2w (AOP (left), offset);
+ emitpcode (POC_ANDLW, newpCodeOpLit (bytelit & 0x0ff));
+ emitSKPZ;
+ }
+ emitpcode (POC_GOTO, popGetLabel (rIfx.condition ?
+ rIfx.lbl->key : tlbl->key));
+ }
+ offset++;
+ }
+ if (!rIfx.condition)
+ {
+ emitpcode (POC_GOTO, popGetLabel (rIfx.lbl->key));
+ }
+ emitpLabel(tlbl->key);
+ ifx->generated = TRUE;
+ // bit = left & literal
+ if (size)
+ {
+ pic14_emitcode ("clr", "c");
+ pic14_emitcode ("", "%05d_DS_:", labelKey2num (tlbl->key));
+ }
+ // if(left & literal)
+ else
+ {
+ if (ifx)
+ jmpTrueOrFalse (ifx, tlbl);
+ goto release;
+ }
+ }
+ pic14_outBitC (result);
+ goto release;
+ }
+
+ /* if left is same as result */
+ if (pic14_sameRegs (AOP (result), AOP (left)))
+ {
+ int know_W = -1;
+ for (; size--; offset++, lit >>= 8)
+ {
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ switch (lit & 0xff)
+ {
+ case 0x00:
+ /* and'ing with 0 has clears the result */
+ emitpcode (POC_CLRF, popGet (AOP (result), offset));
+ break;
+ case 0xff:
+ /* and'ing with 0xff is a nop when the result and left are the same */
+ break;
+
+ default:
+ {
+ int p = my_powof2 ((~lit) & 0xff);
+ if (p >= 0)
+ {
+ /* only one bit is set in the literal, so use a bcf instruction */
+ emitpcode (POC_BCF, newpCodeOpBit (aopGet (AOP (left), offset, FALSE, FALSE), p, 0));
+
+ }
+ else
+ {
+ if (know_W != (int) (lit & 0xff))
+ emitpcode (POC_MOVLW, popGetLit (lit & 0xff));
+ know_W = lit & 0xff;
+ emitpcode (POC_ANDWF, popGet (AOP (left), offset));
+ }
+ }
+ }
+ }
+ else
+ {
+ emitpcode (POC_MOVFW, popGet (AOP (right), offset));
+ emitpcode (POC_ANDWF, popGet (AOP (left), offset));
+ }
+ }
+
+ }
+ else
+ {
+ // left & result in different registers
+ if (AOP_TYPE (result) == AOP_CRY)
+ {
+ // result = bit
+ // if(size), result in bit
+ // if(!size && ifx), conditional oper: if(left & right)
+ symbol *tlbl = newiTempLabel (NULL);
+ int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
+ if (size)
+ pic14_emitcode ("setb", "c");
+ while (sizer--)
+ {
+ MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
+ pic14_emitcode ("anl", "a,%s", aopGet (AOP (left), offset, FALSE, FALSE));
+ pic14_emitcode ("jnz", "%05d_DS_", labelKey2num (tlbl->key));
+ offset++;
+ }
+ if (size)
+ {
+ CLRC;
+ pic14_emitcode ("", "%05d_DS_:", labelKey2num (tlbl->key));
+ pic14_outBitC (result);
+ }
+ else if (ifx)
+ jmpTrueOrFalse (ifx, tlbl);
+ }
+ else
+ {
+ for (; (size--); offset++)
+ {
+ // normal case
+ // result = left & right
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ int t = (lit >> (offset * 8)) & 0x0FFL;
+ switch (t)
+ {
+ case 0x00:
+ emitpcode (POC_CLRF, popGet (AOP (result), offset));
+ break;
+ case 0xff:
+ emitpcode (POC_MOVFW, popGet (AOP (left), offset));
+ emitpcode (POC_MOVWF, popGet (AOP (result), offset));
+ break;
+ default:
+ emitpcode (POC_MOVLW, popGetLit (t));
+ emitpcode (POC_ANDFW, popGet (AOP (left), offset));
+ emitpcode (POC_MOVWF, popGet (AOP (result), offset));
+ }
+ continue;
+ }
+
+ emitpcode (POC_MOVFW, popGet (AOP (right), offset));
+ emitpcode (POC_ANDFW, popGet (AOP (left), offset));
+ emitpcode (POC_MOVWF, popGet (AOP (result), offset));
+ }
+ }
+ }
+
+release:
+ freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genOr - code for or */
+/*-----------------------------------------------------------------*/
+static void
+genOr (iCode * ic, iCode * ifx)
+{
+ operand *left, *right, *result;
+ int size, offset = 0;
+ unsigned long lit = 0L;
+
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+
+ aopOp ((left = IC_LEFT (ic)), ic, FALSE);
+ aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
+ aopOp ((result = IC_RESULT (ic)), ic, TRUE);
+
+ DEBUGpic14_AopType (__LINE__, left, right, result);
+
+ /* if left is a literal & right is not then exchange them */
+ if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) || AOP_NEEDSACC (left))
+ {
+ operand *tmp = right;
+ right = left;
+ left = tmp;
+ }
+
+ /* if result = right then exchange them */
+ if (pic14_sameRegs (AOP (result), AOP (right)))
+ {
+ operand *tmp = right;
+ right = left;
+ left = tmp;
+ }
+
+ /* if right is bit then exchange them */
+ if (AOP_TYPE (right) == AOP_CRY && AOP_TYPE (left) != AOP_CRY)
+ {
+ operand *tmp = right;
+ right = left;
+ left = tmp;
+ }
+
+ DEBUGpic14_AopType (__LINE__, left, right, result);
+
+ if (AOP_TYPE (right) == AOP_LIT)
+ lit = ulFromVal (AOP (right)->aopu.aop_lit);
+
+ size = AOP_SIZE (result);
+
+ // if(bit | yy)
+ // xx = bit | yy;
+ if (AOP_TYPE (left) == AOP_CRY)
+ {
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ // c = bit & literal;
+ if (lit)
+ {
+ // lit != 0 => result = 1
+ if (AOP_TYPE (result) == AOP_CRY)
+ {
+ if (size)
+ emitpcode (POC_BSF, popGet (AOP (result), 0));
+ //pic14_emitcode("bsf","(%s >> 3), (%s & 7)",
+ // AOP(result)->aopu.aop_dir,
+ // AOP(result)->aopu.aop_dir);
+ else if (ifx)
+ continueIfTrue (ifx);
+ goto release;
+ }
+ }
+ else
+ {
+ // lit == 0 => result = left
+ if (size && pic14_sameRegs (AOP (result), AOP (left)))
+ goto release;
+ pic14_emitcode (";XXX mov", "c,%s %s,%d", AOP (left)->aopu.aop_dir, __FILE__, __LINE__);
+ }
+ }
+ else
+ {
+ if (AOP_TYPE (right) == AOP_CRY)
+ {
+ if (pic14_sameRegs (AOP (result), AOP (left)))
+ {
+ // c = bit | bit;
+ emitpcode (POC_BCF, popGet (AOP (result), 0));
+ emitpcode (POC_BTFSC, popGet (AOP (right), 0));
+ emitpcode (POC_BSF, popGet (AOP (result), 0));
+
+ pic14_emitcode ("bcf", "(%s >> 3), (%s & 7)", AOP (result)->aopu.aop_dir, AOP (result)->aopu.aop_dir);
+ pic14_emitcode ("btfsc", "(%s >> 3), (%s & 7)", AOP (right)->aopu.aop_dir, AOP (right)->aopu.aop_dir);
+ pic14_emitcode ("bsf", "(%s >> 3), (%s & 7)", AOP (result)->aopu.aop_dir, AOP (result)->aopu.aop_dir);
+ }
+ else
+ {
+ emitpcode (POC_BCF, popGet (AOP (result), 0));
+ emitpcode (POC_BTFSS, popGet (AOP (right), 0));
+ emitpcode (POC_BTFSC, popGet (AOP (left), 0));
+ emitpcode (POC_BSF, popGet (AOP (result), 0));
+ }
+ }
+ else
+ {
+ // c = bit | val;
+ symbol *tlbl = newiTempLabel (NULL);
+ pic14_emitcode (";XXX ", " %s,%d", __FILE__, __LINE__);
+
+
+ emitpcode (POC_BCF, popGet (AOP (result), 0));
+
+ if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
+ pic14_emitcode (";XXX setb", "c");
+ pic14_emitcode (";XXX jb", "%s,%05d_DS_", AOP (left)->aopu.aop_dir, labelKey2num (tlbl->key));
+ pic14_toBoolean (right);
+ pic14_emitcode (";XXX jnz", "%05d_DS_", labelKey2num (tlbl->key));
+ if ((AOP_TYPE (result) == AOP_CRY) && ifx)
+ {
+ jmpTrueOrFalse (ifx, tlbl);
+ goto release;
+ }
+ else
+ {
+ CLRC;
+ pic14_emitcode ("", "%05d_DS_:", labelKey2num (tlbl->key));
+ }
+ }
+ }
+ // bit = c
+ // val = c
+ if (size)
+ pic14_outBitC (result);
+ // if(bit | ...)
+ else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
+ genIfxJump (ifx, "c");
+ goto release;
+ }
+
+ // if(val | 0xZZ) - size = 0, ifx != FALSE -
+ // bit = val | 0xZZ - size = 1, ifx = FALSE -
+ if ((AOP_TYPE (right) == AOP_LIT) && (AOP_TYPE (result) == AOP_CRY) && (AOP_TYPE (left) != AOP_CRY))
+ {
+ if (lit)
+ {
+ pic14_emitcode (";XXX ", " %s,%d", __FILE__, __LINE__);
+ // result = 1
+ if (size)
+ pic14_emitcode (";XXX setb", "%s", AOP (result)->aopu.aop_dir);
+ else
+ continueIfTrue (ifx);
+ goto release;
+ }
+ else
+ {
+ pic14_emitcode (";XXX ", " %s,%d", __FILE__, __LINE__);
+ // lit = 0, result = boolean(left)
+ if (size)
+ pic14_emitcode (";XXX setb", "c");
+ pic14_toBoolean (right);
+ if (size)
+ {
+ symbol *tlbl = newiTempLabel (NULL);
+ pic14_emitcode (";XXX jnz", "%05d_DS_", labelKey2num (tlbl->key));
+ CLRC;
+ pic14_emitcode ("", "%05d_DS_:", labelKey2num (tlbl->key));
+ }
+ else
+ {
+ genIfxJump (ifx, "a");
+ goto release;
+ }
+ }
+ pic14_outBitC (result);
+ goto release;
+ }
+
+ /* if left is same as result */
+ if (pic14_sameRegs (AOP (result), AOP (left)))
+ {
+ int know_W = -1;
+ for (; size--; offset++, lit >>= 8)
+ {
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ if ((lit & 0xff) == 0)
+ /* or'ing with 0 has no effect */
+ continue;
+ else
+ {
+ int p = my_powof2 (lit & 0xff);
+ if (p >= 0)
+ {
+ /* only one bit is set in the literal, so use a bsf instruction */
+ emitpcode (POC_BSF, newpCodeOpBit (aopGet (AOP (left), offset, FALSE, FALSE), p, 0));
+ }
+ else
+ {
+ if (know_W != (int) (lit & 0xff))
+ emitpcode (POC_MOVLW, popGetLit (lit & 0xff));
+ know_W = lit & 0xff;
+ emitpcode (POC_IORWF, popGet (AOP (left), offset));
+ }
+
+ }
+ }
+ else
+ {
+ emitpcode (POC_MOVFW, popGet (AOP (right), offset));
+ emitpcode (POC_IORWF, popGet (AOP (left), offset));
+ }
+ }
+ }
+ else
+ {
+ // left & result in different registers
+ if (AOP_TYPE (result) == AOP_CRY)
+ {
+ // result = bit
+ // if(size), result in bit
+ // if(!size && ifx), conditional oper: if(left | right)
+ symbol *tlbl = newiTempLabel (NULL);
+ int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
+ pic14_emitcode (";XXX ", " %s,%d", __FILE__, __LINE__);
+
+
+ if (size)
+ pic14_emitcode (";XXX setb", "c");
+ while (sizer--)
+ {
+ MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
+ pic14_emitcode (";XXX orl", "a,%s", aopGet (AOP (left), offset, FALSE, FALSE));
+ pic14_emitcode (";XXX jnz", "%05d_DS_", labelKey2num (tlbl->key));
+ offset++;
+ }
+ if (size)
+ {
+ CLRC;
+ pic14_emitcode ("", "%05d_DS_:", labelKey2num (tlbl->key));
+ pic14_outBitC (result);
+ }
+ else if (ifx)
+ jmpTrueOrFalse (ifx, tlbl);
+ }
+ else
+ for (; (size--); offset++)
+ {
+ // normal case
+ // result = left | right
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ int t = (lit >> (offset * 8)) & 0x0FFL;
+ switch (t)
+ {
+ case 0x00:
+ emitpcode (POC_MOVFW, popGet (AOP (left), offset));
+ emitpcode (POC_MOVWF, popGet (AOP (result), offset));
+
+ break;
+ default:
+ emitpcode (POC_MOVLW, popGetLit (t));
+ emitpcode (POC_IORFW, popGet (AOP (left), offset));
+ emitpcode (POC_MOVWF, popGet (AOP (result), offset));
+ }
+ continue;
+ }
+
+ // faster than result <- left, anl result,right
+ // and better if result is SFR
+ emitpcode (POC_MOVFW, popGet (AOP (right), offset));
+ emitpcode (POC_IORFW, popGet (AOP (left), offset));
+ emitpcode (POC_MOVWF, popGet (AOP (result), offset));
+ }
+ }
+
+release:
+ freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genXor - code for xclusive or */
+/*-----------------------------------------------------------------*/
+static void
+genXor (iCode * ic, iCode * ifx)
+{
+ operand *left, *right, *result;
+ int size, offset = 0;
+ unsigned long lit = 0L;
+
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+
+ aopOp ((left = IC_LEFT (ic)), ic, FALSE);
+ aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
+ aopOp ((result = IC_RESULT (ic)), ic, TRUE);
+
+ /* if left is a literal & right is not ||
+ if left needs acc & right does not */
+ if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) || (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right)))
+ {
+ operand *tmp = right;
+ right = left;
+ left = tmp;
+ }
+
+ /* if result = right then exchange them */
+ if (pic14_sameRegs (AOP (result), AOP (right)))
+ {
+ operand *tmp = right;
+ right = left;
+ left = tmp;
+ }
+
+ /* if right is bit then exchange them */
+ if (AOP_TYPE (right) == AOP_CRY && AOP_TYPE (left) != AOP_CRY)
+ {
+ operand *tmp = right;
+ right = left;
+ left = tmp;
+ }
+ if (AOP_TYPE (right) == AOP_LIT)
+ lit = ulFromVal (AOP (right)->aopu.aop_lit);
+
+ size = AOP_SIZE (result);
+
+ // if(bit ^ yy)
+ // xx = bit ^ yy;
+ if (AOP_TYPE (left) == AOP_CRY)
+ {
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ // c = bit & literal;
+ if (lit >> 1)
+ {
+ // lit>>1 != 0 => result = 1
+ if (AOP_TYPE (result) == AOP_CRY)
+ {
+ if (size)
+ {
+ emitpcode (POC_BSF, popGet (AOP (result), offset));
+ pic14_emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
+ }
+ else if (ifx)
+ continueIfTrue (ifx);
+ goto release;
+ }
+ pic14_emitcode ("setb", "c");
+ }
+ else
+ {
+ // lit == (0 or 1)
+ if (lit == 0)
+ {
+ // lit == 0, result = left
+ if (size && pic14_sameRegs (AOP (result), AOP (left)))
+ goto release;
+ pic14_emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
+ }
+ else
+ {
+ // lit == 1, result = not(left)
+ if (size && pic14_sameRegs (AOP (result), AOP (left)))
+ {
+ emitpcode (POC_MOVLW, popGet (AOP (result), offset));
+ emitpcode (POC_XORWF, popGet (AOP (result), offset));
+ pic14_emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
+ goto release;
+ }
+ else
+ {
+ assert (!"incomplete genXor");
+ pic14_emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
+ pic14_emitcode ("cpl", "c");
+ }
+ }
+ }
+
+ }
+ else
+ {
+ // right != literal
+ symbol *tlbl = newiTempLabel (NULL);
+ if (AOP_TYPE (right) == AOP_CRY)
+ {
+ // c = bit ^ bit;
+ pic14_emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
+ }
+ else
+ {
+ int sizer = AOP_SIZE (right);
+ // c = bit ^ val
+ // if val>>1 != 0, result = 1
+ pic14_emitcode ("setb", "c");
+ while (sizer)
+ {
+ MOVA (aopGet (AOP (right), sizer - 1, FALSE, FALSE));
+ if (sizer == 1)
+ // test the msb of the lsb
+ pic14_emitcode ("anl", "a,#0xfe");
+ pic14_emitcode ("jnz", "%05d_DS_", labelKey2num (tlbl->key));
+ sizer--;
+ }
+ // val = (0,1)
+ pic14_emitcode ("rrc", "a");
+ }
+ pic14_emitcode ("jnb", "%s,%05d_DS_", AOP (left)->aopu.aop_dir, (labelKey2num (tlbl->key)));
+ pic14_emitcode ("cpl", "c");
+ pic14_emitcode ("", "%05d_DS_:", (labelKey2num (tlbl->key)));
+ }
+ // bit = c
+ // val = c
+ if (size)
+ pic14_outBitC (result);
+ // if(bit | ...)
+ else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
+ genIfxJump (ifx, "c");
+ goto release;
+ }
+
+ if (pic14_sameRegs (AOP (result), AOP (left)))
+ {
+ /* if left is same as result */
+ for (; size--; offset++)
+ {
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ int t = (lit >> (offset * 8)) & 0x0FFL;
+ if (t == 0x00L)
+ continue;
+ else
+ {
+ emitpcode (POC_MOVLW, popGetLit (t));
+ emitpcode (POC_XORWF, popGet (AOP (left), offset));
+ }
+ }
+ else
+ {
+ emitpcode (POC_MOVFW, popGet (AOP (right), offset));
+ emitpcode (POC_XORWF, popGet (AOP (left), offset));
+ }
+ }
+ }
+ else
+ {
+ // left & result in different registers
+ if (AOP_TYPE (result) == AOP_CRY)
+ {
+ // result = bit
+ // if(size), result in bit
+ // if(!size && ifx), conditional oper: if(left ^ right)
+ symbol *tlbl = newiTempLabel (NULL);
+ int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
+ if (size)
+ pic14_emitcode ("setb", "c");
+ while (sizer--)
+ {
+ if ((AOP_TYPE (right) == AOP_LIT) && (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
+ {
+ MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
+ }
+ else
+ {
+ MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
+ pic14_emitcode ("xrl", "a,%s", aopGet (AOP (left), offset, FALSE, FALSE));
+ }
+ pic14_emitcode ("jnz", "%05d_DS_", labelKey2num (tlbl->key));
+ offset++;
+ }
+ if (size)
+ {
+ CLRC;
+ pic14_emitcode ("", "%05d_DS_:", labelKey2num (tlbl->key));
+ pic14_outBitC (result);
+ }
+ else if (ifx)
+ jmpTrueOrFalse (ifx, tlbl);
+ }
+ else
+ for (; (size--); offset++)
+ {
+ // normal case
+ // result = left & right
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ int t = (lit >> (offset * 8)) & 0x0FFL;
+ switch (t)
+ {
+ case 0x00:
+ emitpcode (POC_MOVFW, popGet (AOP (left), offset));
+ emitpcode (POC_MOVWF, popGet (AOP (result), offset));
+ break;
+ case 0xff:
+ emitpcode (POC_COMFW, popGet (AOP (left), offset));
+ emitpcode (POC_MOVWF, popGet (AOP (result), offset));
+ break;
+ default:
+ emitpcode (POC_MOVLW, popGetLit (t));
+ emitpcode (POC_XORFW, popGet (AOP (left), offset));
+ emitpcode (POC_MOVWF, popGet (AOP (result), offset));
+ }
+ continue;
+ }
+
+ // faster than result <- left, anl result,right
+ // and better if result is SFR
+ emitpcode (POC_MOVFW, popGet (AOP (right), offset));
+ emitpcode (POC_XORFW, popGet (AOP (left), offset));
+ emitpcode (POC_MOVWF, popGet (AOP (result), offset));
+ }
+ }
+
+release:
+ freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genInline - write the inline code out */
+/*-----------------------------------------------------------------*/
+static void
+pic14_genInline (iCode * ic)
+{
+ char *buffer, *bp, *bp1;
+ bool inComment = FALSE;
+
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+
+ genLine.lineElement.isInline += (!options.asmpeep);
+
+ buffer = bp = bp1 = Safe_strdup (IC_INLINE (ic));
+
+ while (*bp)
+ {
+ switch (*bp)
+ {
+ case ';':
+ inComment = TRUE;
+ ++bp;
+ break;
+
+ case '\x87':
+ case '\n':
+ inComment = FALSE;
+ *bp++ = '\0';
+ if (*bp1)
+ addpCode2pBlock (pb, newpCodeAsmDir (bp1, NULL)); // inline directly, no process
+ bp1 = bp;
+ break;
+
+ default:
+ /* Add \n for labels, not dirs such as c:\mydir */
+ if (!inComment && (*bp == ':') && (isspace ((unsigned char) bp[1])))
+ {
+ ++bp;
+ *bp = '\0';
+ ++bp;
+ /* print label, use this special format with NULL directive
+ * to denote that the argument should not be indented with tab */
+ addpCode2pBlock (pb, newpCodeAsmDir (NULL, bp1)); // inline directly, no process
+ bp1 = bp;
+ }
+ else
+ ++bp;
+ break;
+ }
+ }
+ if ((bp1 != bp) && *bp1)
+ addpCode2pBlock (pb, newpCodeAsmDir (bp1, NULL)); // inline directly, no process
+
+ Safe_free (buffer);
+
+ /* consumed; we can free it here */
+ dbuf_free (IC_INLINE (ic));
+
+ genLine.lineElement.isInline -= (!options.asmpeep);
+}
+
+/*-----------------------------------------------------------------*/
+/* genRRC - rotate right with carry */
+/*-----------------------------------------------------------------*/
+static void
+genRRC (iCode * ic)
+{
+ operand *left, *result;
+ int size, offset = 0, same;
+
+ FENTRY;
+ /* rotate right with carry */
+ left = IC_LEFT (ic);
+ result = IC_RESULT (ic);
+ aopOp (left, ic, FALSE);
+ aopOp (result, ic, FALSE);
+
+ DEBUGpic14_AopType (__LINE__, left, NULL, result);
+
+ same = pic14_sameRegs (AOP (result), AOP (left));
+
+ size = AOP_SIZE (result);
+
+ /* get the lsb and put it into the carry */
+ emitpcode (POC_RRFW, popGet (AOP (left), size - 1));
+
+ offset = 0;
+
+ while (size--)
+ {
+ if (same)
+ {
+ emitpcode (POC_RRF, popGet (AOP (left), offset));
+ }
+ else
+ {
+ emitpcode (POC_RRFW, popGet (AOP (left), offset));
+ emitpcode (POC_MOVWF, popGet (AOP (result), offset));
+ }
+
+ offset++;
+ }
+
+ freeAsmop (left, NULL, ic, TRUE);
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genRLC - generate code for rotate left with carry */
+/*-----------------------------------------------------------------*/
+static void
+genRLC (iCode * ic)
+{
+ operand *left, *result;
+ int size, offset = 0;
+ int same;
+
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ /* rotate right with carry */
+ left = IC_LEFT (ic);
+ result = IC_RESULT (ic);
+ aopOp (left, ic, FALSE);
+ aopOp (result, ic, FALSE);
+
+ DEBUGpic14_AopType (__LINE__, left, NULL, result);
+
+ same = pic14_sameRegs (AOP (result), AOP (left));
+
+ /* move it to the result */
+ size = AOP_SIZE (result);
+
+ /* get the msb and put it into the carry */
+ emitpcode (POC_RLFW, popGet (AOP (left), size - 1));
+
+ offset = 0;
+
+ while (size--)
+ {
+ if (same)
+ {
+ emitpcode (POC_RLF, popGet (AOP (left), offset));
+ }
+ else
+ {
+ emitpcode (POC_RLFW, popGet (AOP (left), offset));
+ emitpcode (POC_MOVWF, popGet (AOP (result), offset));
+ }
+
+ offset++;
+ }
+
+
+ freeAsmop (left, NULL, ic, TRUE);
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+static void
+genGetABit (iCode * ic)
+{
+ operand *left, *right, *result;
+ int shCount;
+ int offset;
+ int i;
+
+ left = IC_LEFT (ic);
+ right = IC_RIGHT (ic);
+ result = IC_RESULT (ic);
+
+ aopOp (left, ic, FALSE);
+ aopOp (right, ic, FALSE);
+ aopOp (result, ic, TRUE);
+
+ shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
+ offset = shCount / 8;
+ shCount %= 8;
+
+ /* load and mask the source byte */
+ mov2w (AOP (left), offset);
+ emitpcode (POC_ANDLW, popGetLit (1 << shCount));
+
+ /* move selected bit to bit 0 */
+ switch (shCount)
+ {
+ case 0:
+ /* nothing more to do */
+ break;
+ default:
+ /* keep W==0, force W=0x01 otherwise */
+ emitSKPZ;
+ emitpcode (POC_MOVLW, popGetLit (1));
+ break;
+ } // switch
+
+ /* write result */
+ emitpcode (POC_MOVWF, popGet (AOP (result), 0));
+
+ for (i = 1; i < AOP_SIZE (result); ++i)
+ {
+ emitpcode (POC_CLRF, popGet (AOP (result), i));
+ } // for
+
+ freeAsmop (left, NULL, ic, TRUE);
+ freeAsmop (right, NULL, ic, TRUE);
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genGetHbit - generates code get highest order bit */
+/*-----------------------------------------------------------------*/
+static void
+genGetHbit (iCode * ic)
+{
+ operand *left, *result;
+ left = IC_LEFT (ic);
+ result = IC_RESULT (ic);
+ aopOp (left, ic, FALSE);
+ aopOp (result, ic, FALSE);
+
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ /* get the highest order byte into a */
+ MOVA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE, FALSE));
+ if (AOP_TYPE (result) == AOP_CRY)
+ {
+ pic14_emitcode ("rlc", "a");
+ pic14_outBitC (result);
+ }
+ else
+ {
+ pic14_emitcode ("rl", "a");
+ pic14_emitcode ("anl", "a,#0x01");
+ pic14_outAcc (result);
+ }
+
+
+ freeAsmop (left, NULL, ic, TRUE);
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* AccLsh - shift left accumulator by known count */
+/* MARK: pic14 always rotates through CARRY! */
+/*-----------------------------------------------------------------*/
+static void
+AccLsh (pCodeOp * pcop, int shCount)
+{
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ shCount &= 0x0007; // shCount : 0..7
+ switch (shCount)
+ {
+ case 0:
+ return;
+ break;
+ case 1:
+ emitCLRC;
+ emitpcode (POC_RLF, pcop);
+ return;
+ break;
+ case 2:
+ emitpcode (POC_RLF, pcop);
+ emitpcode (POC_RLF, pcop);
+ break;
+ case 3:
+ emitpcode (POC_RLF, pcop);
+ emitpcode (POC_RLF, pcop);
+ emitpcode (POC_RLF, pcop);
+ break;
+ case 4:
+ emitpcode (POC_SWAPF, pcop);
+ break;
+ case 5:
+ emitpcode (POC_SWAPF, pcop);
+ emitpcode (POC_RLF, pcop);
+ break;
+ case 6:
+ emitpcode (POC_SWAPF, pcop);
+ emitpcode (POC_RLF, pcop);
+ emitpcode (POC_RLF, pcop);
+ break;
+ case 7:
+ emitpcode (POC_RRFW, pcop);
+ emitpcode (POC_RRF, pcop);
+ break;
+ }
+ /* clear invalid bits */
+ emitpcode (POC_MOVLW, popGetLit ((unsigned char) (~((1UL << shCount) - 1))));
+ emitpcode (POC_ANDWF, pcop);
+}
+
+/*-----------------------------------------------------------------*/
+/* AccRsh - shift right accumulator by known count */
+/* MARK: pic14 always rotates through CARRY! */
+/* maskmode - 0: leave invalid bits undefined (caller should mask) */
+/* 1: mask out invalid bits (zero-extend) */
+/* 2: sign-extend result (pretty slow) */
+/*-----------------------------------------------------------------*/
+static void
+AccRsh (pCodeOp * pcop, int shCount, int mask_mode)
+{
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ shCount &= 0x0007; // shCount : 0..7
+ switch (shCount)
+ {
+ case 0:
+ return;
+ break;
+ case 1:
+ /* load sign if needed */
+ if (mask_mode == 2)
+ emitpcode (POC_RLFW, pcop);
+ else if (mask_mode == 1)
+ emitCLRC;
+ emitpcode (POC_RRF, pcop);
+ return;
+ break;
+ case 2:
+ /* load sign if needed */
+ if (mask_mode == 2)
+ emitpcode (POC_RLFW, pcop);
+ emitpcode (POC_RRF, pcop);
+ /* load sign if needed */
+ if (mask_mode == 2)
+ emitpcode (POC_RLFW, pcop);
+ emitpcode (POC_RRF, pcop);
+ if (mask_mode == 2)
+ return;
+ break;
+ case 3:
+ /* load sign if needed */
+ if (mask_mode == 2)
+ emitpcode (POC_RLFW, pcop);
+ emitpcode (POC_RRF, pcop);
+ /* load sign if needed */
+ if (mask_mode == 2)
+ emitpcode (POC_RLFW, pcop);
+ emitpcode (POC_RRF, pcop);
+ /* load sign if needed */
+ if (mask_mode == 2)
+ emitpcode (POC_RLFW, pcop);
+ emitpcode (POC_RRF, pcop);
+ if (mask_mode == 2)
+ return;
+ break;
+ case 4:
+ emitpcode (POC_SWAPF, pcop);
+ break;
+ case 5:
+ emitpcode (POC_SWAPF, pcop);
+ emitpcode (POC_RRF, pcop);
+ break;
+ case 6:
+ emitpcode (POC_SWAPF, pcop);
+ emitpcode (POC_RRF, pcop);
+ emitpcode (POC_RRF, pcop);
+ break;
+ case 7:
+ if (mask_mode == 2)
+ {
+ /* load sign */
+ emitpcode (POC_RLFW, pcop);
+ emitpcode (POC_CLRF, pcop);
+ emitSKPNC;
+ emitpcode (POC_COMF, pcop);
+ return;
+ }
+ else
+ {
+ emitpcode (POC_RLFW, pcop);
+ emitpcode (POC_RLF, pcop);
+ }
+ break;
+ }
+
+ if (mask_mode == 0)
+ {
+ /* leave invalid bits undefined */
+ return;
+ }
+
+ /* clear invalid bits -- zero-extend */
+ emitpcode (POC_MOVLW, popGetLit (0x00ff >> shCount));
+ emitpcode (POC_ANDWF, pcop);
+
+ if (mask_mode == 2)
+ {
+ /* sign-extend */
+ emitpcode (POC_MOVLW, popGetLit (0x00ff << (8 - shCount)));
+ emitpcode (POC_BTFSC, newpCodeOpBit (get_op (pcop, NULL, 0), 7 - shCount, 0));
+ emitpcode (POC_IORWF, pcop);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* movLeft2Result - move byte from left to result */
+/*-----------------------------------------------------------------*/
+static void
+movLeft2Result (operand * left, int offl, operand * result, int offr)
+{
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ if (!pic14_sameRegs (AOP (left), AOP (result)) || (offl != offr))
+ {
+ aopGet (AOP (left), offl, FALSE, FALSE);
+
+ emitpcode (POC_MOVFW, popGet (AOP (left), offl));
+ emitpcode (POC_MOVWF, popGet (AOP (result), offr));
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* shiftLeft_Left2ResultLit - shift left by known count */
+/*-----------------------------------------------------------------*/
+
+static void
+shiftLeft_Left2ResultLit (operand * left, operand * result, int shCount)
+{
+ int size, same, offr, i;
+
+ size = AOP_SIZE (left);
+ if (AOP_SIZE (result) < size)
+ size = AOP_SIZE (result);
+
+ same = pic14_sameRegs (AOP (left), AOP (result));
+
+ offr = shCount / 8;
+ shCount = shCount & 0x07;
+
+ size -= offr;
+
+ switch (shCount)
+ {
+ case 0: /* takes 0 or 2N cycles (for offr==0) */
+ if (!same || offr)
+ {
+ for (i = size - 1; i >= 0; i--)
+ movLeft2Result (left, i, result, offr + i);
+ } // if
+ break;
+
+ case 1: /* takes 1N+1 or 2N+1 cycles (or offr==0) */
+ if (same && offr)
+ {
+ shiftLeft_Left2ResultLit (left, result, 8 * offr);
+ shiftLeft_Left2ResultLit (result, result, shCount);
+ return; /* prevent clearing result again */
+ }
+ else
+ {
+ if (pic->isEnhancedCore)
+ {
+ for (i = 0; i < size; i++)
+ {
+ if (same && !offr)
+ {
+ if (i == 0)
+ {
+ emitpcode (POC_LSLF, popGet (AOP (left), i));
+ }
+ else
+ {
+ emitpcode (POC_RLF, popGet (AOP (left), i));
+ }
+ }
+ else
+ {
+ if (i == 0)
+ {
+ emitpcode (POC_LSLFW, popGet (AOP (left), i));
+ }
+ else
+ {
+ emitpcode (POC_RLFW, popGet (AOP (left), i));
+ }
+
+ emitpcode (POC_MOVWF, popGet (AOP (result), i + offr));
+ }
+ }
+ }
+ else
+ {
+ emitCLRC;
+ for (i = 0; i < size; i++)
+ {
+ if (same && !offr)
+ {
+ emitpcode (POC_RLF, popGet (AOP (left), i));
+ }
+ else
+ {
+ emitpcode (POC_RLFW, popGet (AOP (left), i));
+ emitpcode (POC_MOVWF, popGet (AOP (result), i + offr));
+ } // if
+ } // for
+ } // if (pic->isEnhancedCore)
+ } // if (same && offr)
+ break;
+
+ case 4: /* takes 3+5(N-1) = 5N-2 cycles (for offr==0) */
+ /* works in-place/with offr as well */
+ emitpcode (POC_SWAPFW, popGet (AOP (left), size - 1));
+ emitpcode (POC_ANDLW, popGetLit (0xF0));
+ emitpcode (POC_MOVWF, popGet (AOP (result), size - 1 + offr));
+
+ for (i = size - 2; i >= 0; i--)
+ {
+ emitpcode (POC_SWAPFW, popGet (AOP (left), i));
+ emitpcode (POC_MOVWF, popGet (AOP (result), i + offr));
+ emitpcode (POC_ANDLW, popGetLit (0x0F));
+ emitpcode (POC_IORWF, popGet (AOP (result), i + offr + 1));
+ emitpcode (POC_XORWF, popGet (AOP (result), i + offr));
+ } // for i
+ break;
+
+ case 7: /* takes 2(N-1)+3 = 2N+1 cycles */
+ /* works in-place/with offr as well */
+ emitpcode (POC_RRFW, popGet (AOP (left), size - 1));
+ for (i = size - 2; i >= 0; i--)
+ {
+ emitpcode (POC_RRFW, popGet (AOP (left), i));
+ emitpcode (POC_MOVWF, popGet (AOP (result), offr + i + 1));
+ } // for i
+ emitpcode (POC_CLRF, popGet (AOP (result), offr));
+ emitpcode (POC_RRF, popGet (AOP (result), offr));
+ break;
+
+ default:
+ shiftLeft_Left2ResultLit (left, result, offr * 8 + shCount - 1);
+ shiftLeft_Left2ResultLit (result, result, 1);
+ return; /* prevent clearing result again */
+ break;
+ } // switch
+
+ while (0 < offr--)
+ {
+ emitpcode (POC_CLRF, popGet (AOP (result), offr));
+ } // while
+}
+
+/*-----------------------------------------------------------------*/
+/* shiftRight_Left2ResultLit - shift right by known count */
+/*-----------------------------------------------------------------*/
+
+static void
+shiftRight_Left2ResultLit (operand * left, operand * result, int shCount, int sign)
+{
+ int size, same, offr, i;
+
+ size = AOP_SIZE (left);
+ if (AOP_SIZE (result) < size)
+ size = AOP_SIZE (result);
+
+ same = pic14_sameRegs (AOP (left), AOP (result));
+
+ offr = shCount / 8;
+ shCount = shCount & 0x07;
+
+ size -= offr;
+
+ if (size)
+ {
+ switch (shCount)
+ {
+ case 0: /* takes 0 or 2N cycles (for offr==0) */
+ if (!same || offr)
+ {
+ for (i = 0; i < size; i++)
+ movLeft2Result (left, i + offr, result, i);
+ } // if
+ break;
+
+ case 1: /* takes 1N+1(3) or 2N+1(3) cycles (or offr==0) */
+ emitpComment ("%s:%d: shCount=%d, size=%d, sign=%d, same=%d, offr=%d", __FUNCTION__, __LINE__, shCount, size, sign,
+ same, offr);
+ if (same && offr)
+ {
+ shiftRight_Left2ResultLit (left, result, 8 * offr, sign);
+ shiftRight_Left2ResultLit (result, result, shCount, sign);
+ return; /* prevent sign-extending result again */
+ }
+ else
+ {
+ if (pic->isEnhancedCore)
+ {
+ for (i = size - 1; i >= 0; i--)
+ {
+ if (same && !offr)
+ {
+ if (i == (size - 1))
+ {
+ if (sign)
+ {
+ emitpcode (POC_ASRF, popGet (AOP (left), i));
+ }
+ else
+ {
+ emitpcode (POC_LSRF, popGet (AOP (left), i));
+ }
+ }
+ else
+ {
+ emitpcode (POC_RRF, popGet (AOP (left), i));
+ }
+ }
+ else
+ {
+ if (i == (size - 1))
+ {
+ if (sign)
+ {
+ emitpcode (POC_ASRFW, popGet (AOP (left), i));
+ }
+ else
+ {
+ emitpcode (POC_LSRFW, popGet (AOP (left), i));
+ }
+ }
+ else
+ {
+ emitpcode (POC_RRFW, popGet (AOP (left), i + offr));
+ }
+
+ emitpcode (POC_MOVWF, popGet (AOP (result), i));
+ } // if (same && !offr)
+ } // for i
+ }
+ else
+ {
+ emitCLRC;
+ if (sign)
+ {
+ emitpcode (POC_BTFSC, newpCodeOpBit (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE, FALSE), 7, 0));
+ emitSETC;
+ }
+
+ for (i = size - 1; i >= 0; i--)
+ {
+ if (same && !offr)
+ {
+ emitpcode (POC_RRF, popGet (AOP (left), i));
+ }
+ else
+ {
+ emitpcode (POC_RRFW, popGet (AOP (left), i + offr));
+ emitpcode (POC_MOVWF, popGet (AOP (result), i));
+ }
+ } // for i
+ } // if (pic->isEnhancedCore)
+ } // if (same && offr)
+ break;
+
+ case 4: /* takes 3(6)+5(N-1) = 5N-2(+1) cycles (for offr==0) */
+ /* works in-place/with offr as well */
+ emitpcode (POC_SWAPFW, popGet (AOP (left), offr));
+ emitpcode (POC_ANDLW, popGetLit (0x0F));
+ emitpcode (POC_MOVWF, popGet (AOP (result), 0));
+
+ for (i = 1; i < size; i++)
+ {
+ emitpcode (POC_SWAPFW, popGet (AOP (left), i + offr));
+ emitpcode (POC_MOVWF, popGet (AOP (result), i));
+ emitpcode (POC_ANDLW, popGetLit (0xF0));
+ emitpcode (POC_IORWF, popGet (AOP (result), i - 1));
+ emitpcode (POC_XORWF, popGet (AOP (result), i));
+ } // for i
+
+ if (sign)
+ {
+ emitpcode (POC_MOVLW, popGetLit (0xF0));
+ emitpcode (POC_BTFSC, newpCodeOpBit (aopGet (AOP (result), size - 1, FALSE, FALSE), 3, 0));
+ emitpcode (POC_IORWF, popGet (AOP (result), size - 1));
+ } // if
+ break;
+
+ case 7: /* takes 2(N-1)+3(4) = 2N+1(2) cycles */
+ /* works in-place/with offr as well */
+ emitpcode (POC_RLFW, popGet (AOP (left), offr));
+ for (i = 0; i < size - 1; i++)
+ {
+ emitpcode (POC_RLFW, popGet (AOP (left), offr + i + 1));
+ emitpcode (POC_MOVWF, popGet (AOP (result), i));
+ } // for i
+ emitpcode (POC_CLRF, popGet (AOP (result), size - 1));
+ if (!sign)
+ {
+ emitpcode (POC_RLF, popGet (AOP (result), size - 1));
+ }
+ else
+ {
+ emitSKPNC;
+ emitpcode (POC_DECF, popGet (AOP (result), size - 1));
+ }
+ break;
+
+ default:
+ shiftRight_Left2ResultLit (left, result, offr * 8 + shCount - 1, sign);
+ shiftRight_Left2ResultLit (result, result, 1, sign);
+ return; /* prevent sign extending result again */
+ break;
+ } // switch
+ } // if
+
+ addSign (result, size, sign);
+}
+
+/*-----------------------------------------------------------------*
+* genMultiAsm - repeat assembly instruction for size of register.
+* if endian == 1, then the high byte (i.e base address + size of
+* register) is used first else the low byte is used first;
+*-----------------------------------------------------------------*/
+static void
+genMultiAsm (PIC_OPCODE poc, operand * reg, int size, int endian)
+{
+
+ int offset = 0;
+
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+
+ if (!reg)
+ return;
+
+ if (!endian)
+ {
+ endian = 1;
+ }
+ else
+ {
+ endian = -1;
+ offset = size - 1;
+ }
+
+ while (size--)
+ {
+ emitpcode (poc, popGet (AOP (reg), offset));
+ offset += endian;
+ }
+
+}
+
+/*-----------------------------------------------------------------*/
+/* loadSignToC - load the operand's sign bit into CARRY */
+/*-----------------------------------------------------------------*/
+
+static void
+loadSignToC (operand * op)
+{
+ FENTRY;
+ assert (op && AOP (op) && AOP_SIZE (op));
+
+ emitCLRC;
+ emitpcode (POC_BTFSC, newpCodeOpBit (aopGet (AOP (op), AOP_SIZE (op) - 1, FALSE, FALSE), 7, 0));
+ emitSETC;
+}
+
+/*-----------------------------------------------------------------*/
+/* genRightShift - generate code for right shifting */
+/*-----------------------------------------------------------------*/
+static void
+genGenericShift (iCode * ic, int shiftRight)
+{
+ operand *right, *left, *result;
+ int size;
+ symbol *tlbl, *tlbl1, *inverselbl;
+
+ FENTRY;
+ /* if signed then we do it the hard way preserve the
+ sign bit moving it inwards */
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+
+ /* signed & unsigned types are treated the same : i.e. the
+ signed is NOT propagated inwards : quoting from the
+ ANSI - standard : "for E1 >> E2, is equivalent to division
+ by 2**E2 if unsigned or if it has a non-negative value,
+ otherwise the result is implementation defined ", MY definition
+ is that the sign does not get propagated */
+
+ right = IC_RIGHT (ic);
+ left = IC_LEFT (ic);
+ result = IC_RESULT (ic);
+
+ aopOp (right, ic, FALSE);
+ aopOp (left, ic, FALSE);
+ aopOp (result, ic, FALSE);
+
+ /* if the shift count is known then do it
+ as efficiently as possible */
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ int lit = (int) ulFromVal (AOP (right)->aopu.aop_lit);
+ if (lit < 0)
+ {
+ lit = -lit;
+ shiftRight = !shiftRight;
+ }
+
+ if (shiftRight)
+ shiftRight_Left2ResultLit (left, result, lit, !SPEC_USIGN (operandType (left)));
+ else
+ shiftLeft_Left2ResultLit (left, result, lit);
+ //genRightShiftLiteral (left,right,result,ic, 0);
+ return;
+ }
+
+ /* shift count is unknown then we have to form
+ a loop get the loop count in B : Note: we take
+ only the lower order byte since shifting
+ more that 32 bits make no sense anyway, ( the
+ largest size of an object can be only 32 bits ) */
+
+ /* we must not overwrite the shift counter */
+ assert (!pic14_sameRegs (AOP (right), AOP (result)));
+
+ /* now move the left to the result if they are not the
+ same */
+ if (!pic14_sameRegs (AOP (left), AOP (result)))
+ {
+ size = min (AOP_SIZE (result), AOP_SIZE (left));
+ while (size--)
+ {
+ mov2w (AOP (left), size);
+ movwf (AOP (result), size);
+ }
+ addSign (result, AOP_SIZE (left), !SPEC_USIGN (operandType (left)));
+ }
+
+ tlbl = newiTempLabel (NULL);
+ tlbl1 = newiTempLabel (NULL);
+ inverselbl = NULL;
+ size = AOP_SIZE (result);
+
+ mov2w (AOP (right), 0);
+ if (!SPEC_USIGN (operandType (right)))
+ {
+ inverselbl = newiTempLabel (NULL);
+ /* signed shift count -- invert shift direction for c<0 */
+ emitpcode (POC_BTFSC, newpCodeOpBit (aopGet (AOP (right), 0, FALSE, FALSE), 7, 0));
+ emitpcode (POC_GOTO, popGetLabel (inverselbl->key));
+ } // if
+ emitpcode (POC_SUBLW, popGetLit (0)); /* -count in WREG, 0-x > 0 --> BORROW = !CARRY --> CARRY is clear! */
+ /* check for `a = b >> c' with `-c == 0' */
+ emitSKPNZ;
+ emitpcode (POC_GOTO, popGetLabel (tlbl1->key));
+ emitpLabel (tlbl->key);
+ /* propagate the sign bit inwards for SIGNED result */
+ if (shiftRight && !SPEC_USIGN (operandType (result)))
+ loadSignToC (result);
+ genMultiAsm (shiftRight ? POC_RRF : POC_RLF, result, size, shiftRight);
+ emitpcode (POC_ADDLW, popGetLit (1)); /* clears CARRY (unless W==0 afterwards) */
+ emitSKPC;
+ emitpcode (POC_GOTO, popGetLabel (tlbl->key));
+
+ if (!SPEC_USIGN (operandType (right)))
+ {
+ symbol *inv_loop = newiTempLabel (NULL);
+
+ shiftRight = !shiftRight; /* invert shift direction */
+
+ /* we came here from the code above -- we are done */
+ emitpcode (POC_GOTO, popGetLabel (tlbl1->key));
+
+ /* emit code for shifting N<0 steps, count is already in W */
+ emitpLabel (inverselbl->key);
+ if (!shiftRight || SPEC_USIGN (operandType (result)))
+ emitCLRC;
+ emitpLabel (inv_loop->key);
+ /* propagate the sign bit inwards for SIGNED result */
+ if (shiftRight && !SPEC_USIGN (operandType (result)))
+ loadSignToC (result);
+ genMultiAsm (shiftRight ? POC_RRF : POC_RLF, result, size, shiftRight);
+ emitpcode (POC_ADDLW, popGetLit (1));
+ emitSKPC;
+ emitpcode (POC_GOTO, popGetLabel (inv_loop->key));
+ } // if
+
+ emitpLabel (tlbl1->key);
+
+ freeAsmop (left, NULL, ic, TRUE);
+ freeAsmop (right, NULL, ic, TRUE);
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+static void
+genRightShift (iCode * ic)
+{
+ genGenericShift (ic, 1);
+}
+
+static void
+genLeftShift (iCode * ic)
+{
+ genGenericShift (ic, 0);
+}
+
+/*-----------------------------------------------------------------*/
+/* SetIrp - Set IRP bit */
+/*-----------------------------------------------------------------*/
+static void
+SetIrp (operand * result)
+{
+ FENTRY;
+ if (AOP_TYPE (result) == AOP_LIT)
+ {
+ unsigned lit = (unsigned) double2ul (operandLitValue (result));
+ if (lit & 0x100)
+ emitSETIRP;
+ else
+ emitCLRIRP;
+ }
+ else if ((AOP_TYPE (result) == AOP_PCODE) && (AOP (result)->aopu.pcop->type == PO_LITERAL))
+ {
+ int addrs = PCOL (AOP (result)->aopu.pcop)->lit;
+ if (addrs & 0x100)
+ emitSETIRP;
+ else
+ emitCLRIRP;
+ }
+ else if ((AOP_TYPE (result) == AOP_PCODE) && (AOP (result)->aopu.pcop->type == PO_IMMEDIATE))
+ {
+ emitCLRIRP; /* always ensure this is clear as it may have previously been set */
+ emitpcode (POC_MOVLW, popGetAddr (AOP (result), 1, 0));
+ emitpcode (POC_ANDLW, popGetLit (0x01));
+ emitSKPZ;
+ emitSETIRP;
+ }
+ else
+ {
+ emitCLRIRP; /* always ensure this is clear as it may have previouly been set */
+ if (AOP_SIZE (result) > 1)
+ {
+ emitpcode (POC_BTFSC, newpCodeOpBit (aopGet (AOP (result), 1, FALSE, FALSE), 0, 0));
+ emitSETIRP;
+ }
+ }
+}
+
+static void
+setup_fsr (operand * ptr)
+{
+ if (pic->isEnhancedCore)
+ {
+ mov2w_op (ptr, 0);
+ emitpcode (POC_MOVWF, popCopyReg (&pc_fsr0l));
+ mov2w_op (ptr, 1);
+ emitpcode (POC_MOVWF, popCopyReg (&pc_fsr0h));
+ }
+ else
+ {
+ mov2w_op (ptr, 0);
+ emitpcode (POC_MOVWF, popCopyReg (&pc_fsr));
+
+ /* also setup-up IRP */
+ SetIrp (ptr);
+ }
+}
+
+static void
+inc_fsr (int delta)
+{
+ if (0 == delta)
+ {
+ /* Nothing to do. */
+ return;
+ } // if
+
+ if (pic->isEnhancedCore)
+ {
+ if (pic14_options.no_ext_instr)
+ {
+ /*
+ * Not sure if we may modify W here, so implement this without
+ * touching W.
+ *
+ * Efficiency is not too important here, as enhanced cores
+ * will most likely use extended instructions here. This is
+ * only a workaround for gputils 0.13.7, which supports the
+ * 16f1934 enhanced core, but fails to assemble ADDFSR.
+ */
+ while (delta > 0)
+ {
+ emitpcode (POC_INCFSZ, popCopyReg (&pc_fsr0l));
+ emitpcode (POC_DECF, popCopyReg (&pc_fsr0h));
+ emitpcode (POC_INCF, popCopyReg (&pc_fsr0h));
+ --delta;
+ } // while
+ while (delta < 0)
+ {
+ addpCode2pBlock (pb, newpCodeAsmDir("MOVF", "FSR0L, 1"));
+ emitSKPNZ;
+ emitpcode (POC_DECF, popCopyReg (&pc_fsr0h));
+ emitpcode (POC_DECF, popCopyReg (&pc_fsr0l));
+ ++delta;
+ } // while
+ }
+ else
+ {
+ assert (delta >= -32);
+ assert (delta < 32);
+ /* Hack: Turn this into a PCI (not that easy due to the argument structure). */
+ addpCode2pBlock (pb, newpCodeAsmDir ("ADDFSR", "FSR0, %d", delta));
+ } // if
+ }
+ else
+ {
+ while (delta > 0)
+ {
+ emitpcode (POC_INCF, popCopyReg (&pc_fsr));
+ --delta;
+ } // while
+ while (delta < 0)
+ {
+ emitpcode (POC_DECF, popCopyReg (&pc_fsr));
+ ++delta;
+ } // while
+ } // if
+}
+
+/*-----------------------------------------------------------------*/
+/* emitPtrByteGet - emits code to get a byte into WREG from an */
+/* arbitrary pointer (__code, __data, generic) */
+/*-----------------------------------------------------------------*/
+static void
+emitPtrByteGet (operand * src, int p_type, bool alreadyAddressed)
+{
+ FENTRY;
+ switch (p_type)
+ {
+ case POINTER:
+ case FPOINTER:
+ if (!alreadyAddressed)
+ setup_fsr (src);
+ emitpcode (POC_MOVFW, popCopyReg (pc_indf));
+ break;
+
+ case CPOINTER:
+ assert (AOP_SIZE (src) == 2);
+ mov2w_op (src, 0);
+ emitpcode (POC_MOVWF, popRegFromIdx (Gstack_base_addr - 1));
+ mov2w_op (src, 1);
+ emitpcode (POC_MOVWF, popRegFromIdx (Gstack_base_addr));
+ emitpcode (POC_MOVLW, popGetLit (GPTRTAG_CODE)); /* GPOINTER tag for __code space */
+ call_libraryfunc ("__gptrget1");
+ break;
+
+ case GPOINTER:
+ assert (AOP_SIZE (src) == 3);
+ mov2w_op (src, 0);
+ emitpcode (POC_MOVWF, popRegFromIdx (Gstack_base_addr - 1));
+ mov2w_op (src, 1);
+ emitpcode (POC_MOVWF, popRegFromIdx (Gstack_base_addr));
+ mov2w_op (src, 2);
+ call_libraryfunc ("__gptrget1");
+ break;
+
+ default:
+ assert (!"unhandled pointer type");
+ break;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* emitPtrByteSet - emits code to set a byte from src through a */
+/* pointer register INDF (legacy 8051 uses R0, R1, or DPTR). */
+/*-----------------------------------------------------------------*/
+static void
+emitPtrByteSet (operand * dst, int p_type, bool alreadyAddressed)
+{
+ FENTRY;
+ switch (p_type)
+ {
+ case POINTER:
+ case FPOINTER:
+ if (!alreadyAddressed)
+ setup_fsr (dst);
+ emitpcode (POC_MOVWF, popCopyReg (pc_indf));
+ break;
+
+ case CPOINTER:
+ assert (!"trying to assign to __code pointer");
+ break;
+
+ case GPOINTER:
+ emitpcode (POC_MOVWF, popRegFromIdx (Gstack_base_addr - 2));
+ mov2w_op (dst, 0);
+ emitpcode (POC_MOVWF, popRegFromIdx (Gstack_base_addr - 1));
+ mov2w_op (dst, 1);
+ emitpcode (POC_MOVWF, popRegFromIdx (Gstack_base_addr));
+ mov2w_op (dst, 2);
+ call_libraryfunc ("__gptrput1");
+ break;
+
+ default:
+ assert (!"unhandled pointer type");
+ break;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* genUnpackBits - generates code for unpacking bits */
+/*-----------------------------------------------------------------*/
+static void
+genUnpackBits (operand * result, operand * left, int ptype, iCode * ifx)
+{
+ sym_link *etype; /* bitfield type information */
+ unsigned blen; /* bitfield length */
+ unsigned bstr; /* bitfield starting bit within byte */
+
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ etype = getSpec (operandType (result));
+ blen = SPEC_BLEN (etype);
+ bstr = SPEC_BSTR (etype);
+
+ /* single bit field case */
+ if (blen == 1)
+ {
+ if (ifx)
+ {
+ /* that is for an if statement */
+ pCodeOp *pcop;
+ resolvedIfx rIfx;
+
+ resolveIfx (&rIfx, ifx);
+ if (ptype == -1) /* direct */
+ pcop = newpCodeOpBit (aopGet (AOP (left), 0, FALSE, FALSE), bstr, 0);
+ else
+ {
+ setup_fsr (left);
+ pcop = newpCodeOpBit (pc_indf->pcop.name, bstr, 0);
+ }
+ emitpcode ((rIfx.condition) ? POC_BTFSC : POC_BTFSS, pcop);
+ emitpcode (POC_GOTO, popGetLabel (rIfx.lbl->key));
+ ifx->generated = TRUE;
+ }
+ else
+ {
+ /*
+ * In case of a volatile bitfield read such as
+ * (void)PORTCbits.RC3;
+ * we end up having no result ...
+ */
+ int haveResult = !!AOP_SIZE(result);
+
+ if (haveResult)
+ {
+ assert (!pic14_sameRegs (AOP (result), AOP (left)));
+ emitpcode (POC_CLRF, popGet (AOP (result), 0));
+ } // if
+
+ switch (ptype)
+ {
+ case -1:
+ emitpcode (POC_BTFSC, newpCodeOpBit (aopGet (AOP (left), 0, FALSE, FALSE), bstr, 0));
+ /* If haveResult, adjust result below, otherwise: */
+ if (!haveResult)
+ {
+ /* Dummy instruction to allow bit-test above (volatile dummy bitfield read). */
+ emitpcode (POC_MOVLW, popGetLit (0));
+ } // if
+ break;
+
+ case POINTER:
+ case FPOINTER:
+ case GPOINTER:
+ case CPOINTER:
+ emitPtrByteGet (left, ptype, FALSE);
+ if (haveResult)
+ {
+ emitpcode (POC_ANDLW, popGetLit (1UL << bstr));
+ emitSKPZ;
+ /* adjust result below */
+ } // if
+ break;
+
+ default:
+ assert (!"unhandled pointer type");
+ } // switch
+
+ /* move sign-/zero extended bit to result */
+ if (haveResult)
+ {
+ if (SPEC_USIGN (OP_SYM_ETYPE (left)))
+ emitpcode (POC_INCF, popGet (AOP (result), 0));
+ else
+ emitpcode (POC_DECF, popGet (AOP (result), 0));
+ addSign (result, 1, !SPEC_USIGN (OP_SYM_ETYPE (left)));
+ } // if
+ }
+ return;
+ }
+ else if (blen <= 8 && ((blen + bstr) <= 8))
+ {
+ /* blen > 1 */
+ int i;
+
+ for (i = 0; i < AOP_SIZE (result); i++)
+ emitpcode (POC_CLRF, popGet (AOP (result), i));
+
+ switch (ptype)
+ {
+ case -1:
+ mov2w (AOP (left), 0);
+ break;
+
+ case POINTER:
+ case FPOINTER:
+ case GPOINTER:
+ case CPOINTER:
+ emitPtrByteGet (left, ptype, FALSE);
+ break;
+
+ default:
+ assert (!"unhandled pointer type");
+ } // switch
+
+ if (blen < 8)
+ emitpcode (POC_ANDLW, popGetLit ((((1UL << blen) - 1) << bstr) & 0x00ff));
+ movwf (AOP (result), 0);
+ AccRsh (popGet (AOP (result), 0), bstr, 1); /* zero extend the bitfield */
+
+ if (!SPEC_USIGN (OP_SYM_ETYPE (left)) && (bstr + blen != 8))
+ {
+ /* signed bitfield */
+ assert (bstr + blen > 0);
+ emitpcode (POC_MOVLW, popGetLit (0x00ff << (bstr + blen)));
+ emitpcode (POC_BTFSC, newpCodeOpBit (aopGet (AOP (result), 0, FALSE, FALSE), bstr + blen - 1, 0));
+ emitpcode (POC_IORWF, popGet (AOP (result), 0));
+ }
+ addSign (result, 1, !SPEC_USIGN (OP_SYM_ETYPE (left)));
+ return;
+ }
+
+ assert (!"bitfields larger than 8 bits or crossing byte boundaries are not yet supported");
+}
+
+#if 1
+/*-----------------------------------------------------------------*/
+/* genDataPointerGet - generates code when ptr offset is known */
+/*-----------------------------------------------------------------*/
+static void
+genDataPointerGet (operand * left, operand * result, iCode * ic)
+{
+ unsigned int size;
+ int offset = 0;
+
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+
+
+ /* optimization - most of the time, left and result are the same
+ * address, but different types. for the pic code, we could omit
+ * the following
+ */
+ aopOp (result, ic, TRUE);
+
+ if (pic14_sameRegs (AOP (left), AOP (result)))
+ return;
+
+ DEBUGpic14_AopType (__LINE__, left, NULL, result);
+
+ //emitpcode(POC_MOVFW, popGet(AOP(left),0));
+
+ size = AOP_SIZE (result);
+ if (size > getSize (OP_SYM_ETYPE (left)))
+ size = getSize (OP_SYM_ETYPE (left));
+
+ offset = 0;
+ while (size--)
+ {
+ emitpcode (POC_MOVFW, popGet (AOP (left), offset));
+ emitpcode (POC_MOVWF, popGet (AOP (result), offset));
+ offset++;
+ }
+
+ freeAsmop (left, NULL, ic, TRUE);
+ freeAsmop (result, NULL, ic, TRUE);
+}
+#endif
+
+/*-----------------------------------------------------------------*/
+/* genNearPointerGet - pic14_emitcode for near pointer fetch */
+/*-----------------------------------------------------------------*/
+static void
+genNearPointerGet (operand * left, operand * result, iCode * ic)
+{
+ asmop *aop = NULL;
+ sym_link *ltype = operandType (left);
+ sym_link *rtype = operandType (result);
+ sym_link *retype = getSpec (rtype); /* bitfield type information */
+ int direct = 0;
+
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+
+
+ aopOp (left, ic, FALSE);
+
+ /* if left is rematerialisable and
+ result is not bit variable type and
+ the left is pointer to data space i.e
+ lower 128 bytes of space */
+ if (AOP_TYPE (left) == AOP_PCODE && //AOP_TYPE(left) == AOP_IMMD &&
+ !IS_BITVAR (retype) && PIC_IS_DATA_PTR (ltype))
+ {
+ genDataPointerGet (left, result, ic);
+ return;
+ }
+
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ aopOp (result, ic, FALSE);
+
+ /* Check if can access directly instead of via a pointer */
+ if ((AOP_TYPE (left) == AOP_PCODE) && (AOP (left)->aopu.pcop->type == PO_IMMEDIATE) && (AOP_SIZE (result) <= 1))
+ {
+ direct = 1;
+ }
+
+ if (IS_BITFIELD (getSpec (operandType (result))))
+ {
+ genUnpackBits (result, left, direct ? -1 : POINTER, ifxForOp (IC_RESULT (ic), ic));
+ goto release;
+ }
+
+ /* If the pointer value is not in a the FSR then need to put it in */
+ /* Must set/reset IRP bit for use with FSR. */
+ if (!direct)
+ setup_fsr (left);
+
+// sym_link *etype;
+ /* if bitfield then unpack the bits */
+ {
+ /* we have can just get the values */
+ int size = AOP_SIZE (result);
+ int offset = 0;
+
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+
+ while (size--)
+ {
+ if (direct)
+ emitpcode (POC_MOVWF, popGet (AOP (left), 0));
+ else
+ emitpcode (POC_MOVFW, popCopyReg (pc_indf));
+ if (AOP_TYPE (result) == AOP_LIT)
+ {
+ emitpcode (POC_MOVLW, popGet (AOP (result), offset));
+ }
+ else
+ {
+ emitpcode (POC_MOVWF, popGet (AOP (result), offset));
+ }
+ if (size && !direct)
+ {
+ inc_fsr (1);
+ }
+ offset++;
+ }
+ }
+
+ /* now some housekeeping stuff */
+ if (aop)
+ {
+ /* we had to allocate for this iCode */
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ freeAsmop (NULL, aop, ic, TRUE);
+ }
+ else if (!direct)
+ {
+ /* nothing to do */
+ }
+ else
+ {
+ /* we did not allocate which means left
+ already in a pointer register, then
+ if size > 0 && this could be used again
+ we have to point it back to where it
+ belongs */
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ if (AOP_SIZE (result) > 1 && !OP_SYMBOL (left)->remat && (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth))
+ {
+ int size = AOP_SIZE (result) - 1;
+ inc_fsr (-size);
+ }
+ }
+
+release:
+ /* done */
+ freeAsmop (left, NULL, ic, TRUE);
+ freeAsmop (result, NULL, ic, TRUE);
+
+}
+
+/*-----------------------------------------------------------------*/
+/* genGenPointerGet - gget value from generic pointer space */
+/*-----------------------------------------------------------------*/
+static void
+genGenPointerGet (operand * left, operand * result, iCode * ic)
+{
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ aopOp (left, ic, FALSE);
+ aopOp (result, ic, FALSE);
+
+
+ DEBUGpic14_AopType (__LINE__, left, NULL, result);
+
+ if (IS_BITFIELD (getSpec (operandType (result))))
+ {
+ genUnpackBits (result, left, GPOINTER, ifxForOp (IC_RESULT (ic), ic));
+ return;
+ }
+
+ {
+ /* emit call to __gptrget */
+ char *func[] = { NULL, "__gptrget1", "__gptrget2", "__gptrget3", "__gptrget4" };
+ int size = AOP_SIZE (result);
+ int idx = 0;
+
+ assert (size > 0 && size <= 4);
+
+ /* pass arguments */
+ assert (AOP_SIZE (left) == 3);
+ mov2w (AOP (left), 0);
+ emitpcode (POC_MOVWF, popRegFromIdx (Gstack_base_addr - 1));
+ mov2w (AOP (left), 1);
+ emitpcode (POC_MOVWF, popRegFromIdx (Gstack_base_addr));
+ mov2w (AOP (left), 2);
+ call_libraryfunc (func[size]);
+
+ /* save result */
+ movwf (AOP (result), --size);
+ while (size--)
+ {
+ emitpcode (POC_MOVFW, popRegFromIdx (Gstack_base_addr - idx++));
+ movwf (AOP (result), size);
+ } // while
+ }
+
+ freeAsmop (left, NULL, ic, TRUE);
+ freeAsmop (result, NULL, ic, TRUE);
+
+}
+
+/*-----------------------------------------------------------------*/
+/* genConstPointerGet - get value from const generic pointer space */
+/*-----------------------------------------------------------------*/
+static void
+genConstPointerGet (operand * left, operand * result, iCode * ic)
+{
+ //sym_link *retype = getSpec(operandType(result));
+#if 0
+ symbol *albl, *blbl; //, *clbl;
+ pCodeOp *pcop;
+#endif
+ int i, lit;
+
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ aopOp (left, ic, FALSE);
+ aopOp (result, ic, FALSE);
+
+ DEBUGpic14_AopType (__LINE__, left, NULL, result);
+
+ DEBUGpic14_emitcode ("; ", " %d getting const pointer", __LINE__);
+
+ lit = op_isLitLike (left);
+
+ if (IS_BITFIELD (getSpec (operandType (result))))
+ {
+ genUnpackBits (result, left, lit ? -1 : CPOINTER, ifxForOp (IC_RESULT (ic), ic));
+ goto release;
+ }
+
+ {
+ char *func[] = { NULL, "__gptrget1", "__gptrget2", "__gptrget3", "__gptrget4" };
+ int size = AOP_SIZE (result);
+ assert (size > 0 && size <= 4);
+
+ mov2w_op (left, 0);
+ emitpcode (POC_MOVWF, popRegFromIdx (Gstack_base_addr - 1));
+ mov2w_op (left, 1);
+ emitpcode (POC_MOVWF, popRegFromIdx (Gstack_base_addr));
+ emitpcode (POC_MOVLW, popGetLit (GPTRTAG_CODE)); /* GPOINTER tag for __code space */
+ call_libraryfunc (func[size]);
+
+ movwf (AOP (result), size - 1);
+ for (i = 1; i < size; i++)
+ {
+ emitpcode (POC_MOVFW, popRegFromIdx (Gstack_base_addr + 1 - i));
+ movwf (AOP (result), size - 1 - i);
+ } // for
+ }
+
+release:
+ freeAsmop (left, NULL, ic, TRUE);
+ freeAsmop (result, NULL, ic, TRUE);
+
+}
+
+/*-----------------------------------------------------------------*/
+/* genPointerGet - generate code for pointer get */
+/*-----------------------------------------------------------------*/
+static void
+genPointerGet (iCode * ic)
+{
+ operand *left, *result;
+ sym_link *type, *etype;
+ int p_type = -1;
+
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+
+ left = IC_LEFT (ic);
+ result = IC_RESULT (ic);
+
+ /* depending on the type of pointer we need to
+ move it to the correct pointer register */
+ type = operandType (left);
+ etype = getSpec (type);
+
+ if (IS_PTR_CONST (type))
+ DEBUGpic14_emitcode ("; ***", "%d - const pointer", __LINE__);
+
+ /* if left is of type of pointer then it is simple */
+ if (IS_PTR (type) && !IS_FUNC (type->next))
+ p_type = DCL_TYPE (type);
+ else
+ {
+ /* we have to go by the storage class */
+ p_type = PTR_TYPE (SPEC_OCLS (etype));
+
+ DEBUGpic14_emitcode ("; ***", "%d - resolve pointer by storage class", __LINE__);
+
+ if (SPEC_OCLS (etype)->codesp)
+ {
+ DEBUGpic14_emitcode ("; ***", "%d - cpointer", __LINE__);
+ //p_type = CPOINTER ;
+ }
+ else if (SPEC_OCLS (etype)->fmap && !SPEC_OCLS (etype)->paged)
+ DEBUGpic14_emitcode ("; ***", "%d - fpointer", __LINE__);
+ /*p_type = FPOINTER ; */
+ else if (SPEC_OCLS (etype)->fmap && SPEC_OCLS (etype)->paged)
+ DEBUGpic14_emitcode ("; ***", "%d - ppointer", __LINE__);
+ /* p_type = PPOINTER; */
+ else if (SPEC_OCLS (etype) == idata)
+ DEBUGpic14_emitcode ("; ***", "%d - ipointer", __LINE__);
+ /* p_type = IPOINTER; */
+ else
+ DEBUGpic14_emitcode ("; ***", "%d - pointer", __LINE__);
+ /* p_type = POINTER ; */
+ }
+
+ /* now that we have the pointer type we assign
+ the pointer values */
+ switch (p_type)
+ {
+
+ case POINTER:
+ case FPOINTER:
+ //case IPOINTER:
+ genNearPointerGet (left, result, ic);
+ break;
+ /*
+ case PPOINTER:
+ genPagedPointerGet(left,result,ic);
+ break;
+
+ case FPOINTER:
+ genFarPointerGet (left,result,ic);
+ break;
+ */
+ case CPOINTER:
+ genConstPointerGet (left, result, ic);
+ break;
+
+ case GPOINTER:
+ genGenPointerGet (left, result, ic);
+ break;
+ default:
+ assert (!"unhandled pointer type");
+ break;
+ }
+
+}
+
+/*-----------------------------------------------------------------*/
+/* genPackBits - generates code for packed bit storage */
+/*-----------------------------------------------------------------*/
+static void
+genPackBits (sym_link * etype, operand * result, operand * right, int p_type)
+{
+ unsigned blen; /* bitfield length */
+ unsigned bstr; /* bitfield starting bit within byte */
+ int litval; /* source literal value (if AOP_LIT) */
+ unsigned char mask; /* bitmask within current byte */
+
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+
+ blen = SPEC_BLEN (etype);
+ bstr = SPEC_BSTR (etype);
+
+ /* If the bitfield length is less than a byte and does not cross byte boundaries */
+ if ((blen <= 8) && ((bstr + blen) <= 8))
+ {
+ mask = ((unsigned char) (0xFF << (blen + bstr)) | (unsigned char) (0xFF >> (8 - bstr)));
+
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ /* Case with a bitfield length <8 and literal source */
+ int lit = (int) ulFromVal (AOP (right)->aopu.aop_lit);
+ if (blen == 1)
+ {
+ pCodeOp *pcop;
+
+ switch (p_type)
+ {
+ case -1:
+ if (AOP (result)->type == AOP_PCODE)
+ pcop = newpCodeOpBit (aopGet (AOP (result), 0, FALSE, FALSE), bstr, 0);
+ else
+ pcop = popGet (AOP (result), 0);
+ emitpcode (lit ? POC_BSF : POC_BCF, pcop);
+ break;
+
+ case POINTER:
+ case FPOINTER:
+ setup_fsr (result);
+ emitpcode (lit ? POC_BSF : POC_BCF, newpCodeOpBit (PCOP (pc_indf)->name, bstr, 0));
+ break;
+
+ case CPOINTER:
+ assert (!"trying to assign to bitfield via pointer to __code space");
+ break;
+
+ case GPOINTER:
+ emitPtrByteGet (result, p_type, FALSE);
+ if (lit)
+ {
+ emitpcode (POC_IORLW, newpCodeOpLit (1UL << bstr));
+ }
+ else
+ {
+ emitpcode (POC_ANDLW, newpCodeOpLit ((~(1UL << bstr)) & 0x0ff));
+ }
+ emitPtrByteSet (result, p_type, TRUE);
+ break;
+
+ default:
+ assert (!"unhandled pointer type");
+ break;
+ } // switch (p_type)
+ }
+ else
+ {
+ /* blen > 1 */
+ litval = lit << bstr;
+ litval &= (~mask) & 0x00ff;
+
+ switch (p_type)
+ {
+ case -1:
+ mov2w (AOP (result), 0);
+ if ((litval | mask) != 0x00ff)
+ emitpcode (POC_ANDLW, popGetLit (mask));
+ if (litval != 0x00)
+ emitpcode (POC_IORLW, popGetLit (litval));
+ movwf (AOP (result), 0);
+ break;
+
+ case POINTER:
+ case FPOINTER:
+ case GPOINTER:
+ emitPtrByteGet (result, p_type, FALSE);
+ if ((litval | mask) != 0x00ff)
+ emitpcode (POC_ANDLW, popGetLit (mask));
+ if (litval != 0x00)
+ emitpcode (POC_IORLW, popGetLit (litval));
+ emitPtrByteSet (result, p_type, TRUE);
+ break;
+
+ case CPOINTER:
+ assert (!"trying to assign to bitfield via pointer to __code space");
+ break;
+
+ default:
+ assert (!"unhandled pointer type");
+ break;
+ } // switch
+ } // if (blen > 1)
+ }
+ else
+ {
+ /* right is no literal */
+ if (blen == 1)
+ {
+ switch (p_type)
+ {
+ case -1:
+ /* Note more efficient code, of pre clearing bit then only setting it if required,
+ * can only be done if it is known that the result is not a SFR */
+ emitpcode (POC_RRFW, popGet (AOP (right), 0));
+ emitSKPC;
+ emitpcode (POC_BCF, newpCodeOpBit (aopGet (AOP (result), 0, FALSE, FALSE), bstr, 0));
+ emitSKPNC;
+ emitpcode (POC_BSF, newpCodeOpBit (aopGet (AOP (result), 0, FALSE, FALSE), bstr, 0));
+ break;
+
+ case POINTER:
+ case FPOINTER:
+ case GPOINTER:
+ emitPtrByteGet (result, p_type, FALSE);
+ emitpcode (POC_BTFSS, newpCodeOpBit (aopGet (AOP (right), 0, FALSE, FALSE), bstr, 0));
+ emitpcode (POC_ANDLW, newpCodeOpLit (~(1UL << bstr) & 0x0ff));
+ emitpcode (POC_BTFSC, newpCodeOpBit (aopGet (AOP (right), 0, FALSE, FALSE), bstr, 0));
+ emitpcode (POC_IORLW, newpCodeOpLit ((1UL << bstr) & 0x0ff));
+ emitPtrByteSet (result, p_type, TRUE);
+ break;
+
+ case CPOINTER:
+ assert (!"trying to assign to bitfield via pointer to __code space");
+ break;
+
+ default:
+ assert (!"unhandled pointer type");
+ break;
+ } // switch
+ return;
+ }
+ else
+ {
+ /* Case with a bitfield 1 < length <= 8 and arbitrary source */
+ pCodeOp *temp = popGetTempReg ();
+
+ mov2w (AOP (right), 0);
+ if (blen < 8)
+ {
+ emitpcode (POC_ANDLW, popGetLit ((1UL << blen) - 1));
+ }
+ emitpcode (POC_MOVWF, temp);
+ if (bstr)
+ {
+ AccLsh (temp, bstr);
+ }
+
+ switch (p_type)
+ {
+ case -1:
+ mov2w (AOP (result), 0);
+ emitpcode (POC_ANDLW, popGetLit (mask));
+ emitpcode (POC_IORFW, temp);
+ movwf (AOP (result), 0);
+ break;
+
+ case POINTER:
+ case FPOINTER:
+ case GPOINTER:
+ emitPtrByteGet (result, p_type, FALSE);
+ emitpcode (POC_ANDLW, popGetLit (mask));
+ emitpcode (POC_IORFW, temp);
+ emitPtrByteSet (result, p_type, TRUE);
+ break;
+
+ case CPOINTER:
+ assert (!"trying to assign to bitfield via pointer to __code space");
+ break;
+
+ default:
+ assert (!"unhandled pointer type");
+ break;
+ } // switch
+
+ popReleaseTempReg (temp);
+ } // if (blen > 1)
+ } // if (AOP(right)->type != AOP_LIT)
+ return;
+ } // if (blen <= 8 && ((blen + bstr) <= 8))
+
+ assert (!"bitfields larger than 8 bits or crossing byte boundaries are not yet supported");
+}
+
+/*-----------------------------------------------------------------*/
+/* genDataPointerSet - remat pointer to data space */
+/*-----------------------------------------------------------------*/
+static void
+genDataPointerSet (operand * right, operand * result, iCode * ic)
+{
+ int size = 0;
+ int offset = 0;
+ sym_link *rtype = operandType(right);
+
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ aopOp (right, ic, FALSE);
+ aopOp (result, ic, FALSE);
+
+ assert (IS_SYMOP (result));
+ assert (IS_PTR (OP_SYM_TYPE (result)));
+
+ /*
+ * Determine size from right operand (not result):
+ * The result might be a rematerialized pointer to (the first field in) a struct,
+ * which then assumes the type (and size) of the struct rather than the first field.
+ */
+ size = AOP_SIZE(right);
+
+ /*test the right operand has a pointer value*/
+ if ((AOP_TYPE(right) == AOP_PCODE) && PIC_IS_DATA_PTR(rtype))
+ {
+ while (size--)
+ {
+ emitpcode(POC_MOVLW, popGetAddr(AOP(right), size, 0));
+ emitpcode(POC_MOVWF, popGet(AOP(result), size));
+ }
+ }
+ else
+ {
+ // tsd, was l+1 - the underline `_' prefix was being stripped
+ while (size--)
+ {
+ emitpComment ("%s:%u: size=%d, offset=%d, AOP_TYPE(res)=%d", __FILE__, __LINE__, size, offset,
+ AOP_TYPE (result));
+
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ unsigned int lit = pic14aopLiteral (AOP (IC_RIGHT (ic))->aopu.aop_lit, offset);
+ //fprintf (stderr, "%s:%u: lit %d 0x%x\n", __FUNCTION__,__LINE__, lit, lit);
+ if (lit & 0xff)
+ {
+ emitpcode (POC_MOVLW, popGetLit (lit & 0xff));
+ emitpcode (POC_MOVWF, popGet (AOP (result), offset));
+ }
+ else
+ {
+ emitpcode (POC_CLRF, popGet (AOP (result), offset));
+ }
+ }
+ else
+ {
+ //fprintf (stderr, "%s:%u: no lit\n", __FUNCTION__,__LINE__);
+ emitpcode (POC_MOVFW, popGet (AOP (right), offset));
+ emitpcode (POC_MOVWF, popGet (AOP (result), offset));
+ }
+ offset++;
+ }
+ }
+
+ freeAsmop (right, NULL, ic, TRUE);
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genNearPointerSet - pic14_emitcode for near pointer put */
+/*-----------------------------------------------------------------*/
+static void
+genNearPointerSet (operand * right, operand * result, iCode * ic)
+{
+ asmop *aop = NULL;
+ sym_link *ptype = operandType (result);
+ sym_link *retype = getSpec (operandType (right));
+ sym_link *letype = getSpec (ptype);
+ int direct = 0;
+
+
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ aopOp (result, ic, FALSE);
+
+#if 1
+ /* if the result is rematerializable &
+ in data space & not a bit variable */
+ //if (AOP_TYPE(result) == AOP_IMMD &&
+ if (AOP_TYPE (result) == AOP_PCODE && PIC_IS_DATA_PTR (ptype) && !IS_BITVAR (retype) && !IS_BITVAR (letype))
+ {
+ genDataPointerSet (right, result, ic);
+ freeAsmop (result, NULL, ic, TRUE);
+ return;
+ }
+#endif
+
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ aopOp (right, ic, FALSE);
+ DEBUGpic14_AopType (__LINE__, NULL, right, result);
+
+ /* Check if can access directly instead of via a pointer */
+ if ((AOP_TYPE (result) == AOP_PCODE) && (AOP (result)->aopu.pcop->type == PO_IMMEDIATE) && (AOP_SIZE (right) == 1))
+ {
+ direct = 1;
+ }
+
+ if (IS_BITFIELD (letype))
+ {
+ genPackBits (letype, result, right, direct ? -1 : POINTER);
+ return;
+ }
+
+ /* If the pointer value is not in a the FSR then need to put it in */
+ /* Must set/reset IRP bit for use with FSR. */
+ /* Note only do this once - assuming that never need to cross a bank boundary at address 0x100. */
+ if (!direct)
+ setup_fsr (result);
+
+ {
+ /* we have can just get the values */
+ int size = AOP_SIZE (right);
+ int offset = 0;
+
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ while (size--)
+ {
+ char *l = aopGet (AOP (right), offset, FALSE, TRUE);
+ if (*l == '@')
+ {
+ emitpcode (POC_MOVFW, popCopyReg (pc_indf));
+ }
+ else
+ {
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ emitpcode (POC_MOVLW, popGet (AOP (right), offset));
+ }
+ else
+ {
+ emitpcode (POC_MOVFW, popGet (AOP (right), offset));
+ }
+ if (direct)
+ emitpcode (POC_MOVWF, popGet (AOP (result), 0));
+ else
+ emitpcode (POC_MOVWF, popCopyReg (pc_indf));
+ }
+ if (size && !direct)
+ inc_fsr (1);
+ offset++;
+ }
+ }
+
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ /* now some housekeeping stuff */
+ if (aop)
+ {
+ /* we had to allocate for this iCode */
+ freeAsmop (NULL, aop, ic, TRUE);
+ }
+ else if (!direct)
+ {
+ /* nothing to do */
+ }
+ else
+ {
+ /* we did not allocate which means left
+ already in a pointer register, then
+ if size > 0 && this could be used again
+ we have to point it back to where it
+ belongs */
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ if (AOP_SIZE (right) > 1 && !OP_SYMBOL (result)->remat && (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth))
+ {
+ int size = AOP_SIZE (right) - 1;
+ inc_fsr (-size);
+ }
+ }
+
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ /* done */
+
+ freeAsmop (right, NULL, ic, TRUE);
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genGenPointerSet - set value from generic pointer space */
+/*-----------------------------------------------------------------*/
+static void
+genGenPointerSet (operand * right, operand * result, iCode * ic)
+{
+ sym_link *retype = getSpec (operandType (result));
+
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ aopOp (right, ic, FALSE);
+ aopOp (result, ic, FALSE);
+
+
+ DEBUGpic14_AopType (__LINE__, right, NULL, result);
+
+ if (IS_BITFIELD (retype))
+ {
+ genPackBits (retype, result, right, GPOINTER);
+ return;
+ }
+
+ {
+ /* emit call to __gptrput */
+ char *func[] = { NULL, "__gptrput1", "__gptrput2", "__gptrput3", "__gptrput4" };
+ int size = AOP_SIZE (right);
+ int idx = 0;
+
+ /* The following assertion fails for
+ * struct foo { char a; char b; } bar;
+ * void demo(struct foo *dst, char c) { dst->b = c; }
+ * as size will be 1 (sizeof(c)), whereas dst->b will be accessed
+ * using (((char *)dst)+1), whose OP_SYM_ETYPE still is struct foo
+ * of size 2.
+ * The frontend seems to guarantee that IC_LEFT has the correct size,
+ * it works fine both for larger and smaller types of `char c'.
+ * */
+ //assert (size == getSize(OP_SYM_ETYPE(result)));
+ assert (size > 0 && size <= 4);
+
+ /* pass arguments */
+ /* - value (MSB in Gstack_base_addr-2, growing downwards) */
+ {
+ int off = size;
+ idx = 2;
+ while (off--)
+ {
+ mov2w_op (right, off);
+ emitpcode (POC_MOVWF, popRegFromIdx (Gstack_base_addr - idx++));
+ }
+ idx = 0;
+ }
+ /* - address */
+ assert (AOP_SIZE (result) == 3);
+ mov2w (AOP (result), 0);
+ emitpcode (POC_MOVWF, popRegFromIdx (Gstack_base_addr - 1));
+ mov2w (AOP (result), 1);
+ emitpcode (POC_MOVWF, popRegFromIdx (Gstack_base_addr));
+ mov2w (AOP (result), 2);
+ call_libraryfunc (func[size]);
+ }
+
+ freeAsmop (right, NULL, ic, TRUE);
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genPointerSet - stores the value into a pointer location */
+/*-----------------------------------------------------------------*/
+static void
+genPointerSet (iCode * ic)
+{
+ operand *right, *result;
+ sym_link *type, *etype;
+ int p_type;
+
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+
+ right = IC_RIGHT (ic);
+ result = IC_RESULT (ic);
+
+ /* depending on the type of pointer we need to
+ move it to the correct pointer register */
+ type = operandType (result);
+ etype = getSpec (type);
+ /* if left is of type of pointer then it is simple */
+ if (IS_PTR (type) && !IS_FUNC (type->next))
+ {
+ p_type = DCL_TYPE (type);
+ }
+ else
+ {
+ /* we have to go by the storage class */
+ p_type = PTR_TYPE (SPEC_OCLS (etype));
+
+ /* if (SPEC_OCLS(etype)->codesp ) { */
+ /* p_type = CPOINTER ; */
+ /* } */
+ /* else */
+ /* if (SPEC_OCLS(etype)->fmap && !SPEC_OCLS(etype)->paged) */
+ /* p_type = FPOINTER ; */
+ /* else */
+ /* if (SPEC_OCLS(etype)->fmap && SPEC_OCLS(etype)->paged) */
+ /* p_type = PPOINTER ; */
+ /* else */
+ /* if (SPEC_OCLS(etype) == idata ) */
+ /* p_type = IPOINTER ; */
+ /* else */
+ /* p_type = POINTER ; */
+ }
+
+ /* now that we have the pointer type we assign
+ the pointer values */
+ switch (p_type)
+ {
+ case POINTER:
+ case FPOINTER:
+ //case IPOINTER:
+ genNearPointerSet (right, result, ic);
+ break;
+ /*
+ case PPOINTER:
+ genPagedPointerSet (right,result,ic);
+ break;
+
+ case FPOINTER:
+ genFarPointerSet (right,result,ic);
+ break;
+ */
+ case GPOINTER:
+ genGenPointerSet (right, result, ic);
+ break;
+
+ default:
+ werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "genPointerSet: illegal pointer type");
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* genIfx - generate code for Ifx statement */
+/*-----------------------------------------------------------------*/
+static void
+genIfx (iCode * ic, iCode * popIc)
+{
+ operand *cond = IC_COND (ic);
+ int isbit = 0;
+
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+
+ aopOp (cond, ic, FALSE);
+
+ /* get the value into acc */
+ if (AOP_TYPE (cond) != AOP_CRY)
+ pic14_toBoolean (cond);
+ else
+ isbit = 1;
+
+ /* if there was something to be popped then do it */
+ if (popIc)
+ genIpop (popIc);
+
+ if (isbit)
+ {
+ /* This assumes that CARRY is set iff cond is true */
+ if (IC_TRUE (ic))
+ {
+ assert (!IC_FALSE (ic));
+ emitpcode (POC_BTFSC, popGet (AOP (cond), 0));
+ //emitSKPNC;
+ emitpcode (POC_GOTO, popGetLabel (IC_TRUE (ic)->key));
+ }
+ else
+ {
+ assert (IC_FALSE (ic));
+ emitpcode (POC_BTFSS, popGet (AOP (cond), 0));
+ //emitSKPC;
+ emitpcode (POC_GOTO, popGetLabel (IC_FALSE (ic)->key));
+ }
+ if (0)
+ {
+ static int hasWarned = 0;
+ if (!hasWarned)
+ {
+ fprintf (stderr, "WARNING: using untested code for %s:%u -- please check the .asm output and report bugs.\n",
+ ic->filename, ic->lineno);
+ hasWarned = 1;
+ }
+ }
+ }
+ else
+ {
+ /* now Z is set iff !cond */
+ if (IC_TRUE (ic))
+ {
+ assert (!IC_FALSE (ic));
+ emitSKPZ;
+ emitpcode (POC_GOTO, popGetLabel (IC_TRUE (ic)->key));
+ }
+ else
+ {
+ emitSKPNZ;
+ emitpcode (POC_GOTO, popGetLabel (IC_FALSE (ic)->key));
+ }
+ }
+
+ ic->generated = TRUE;
+
+ /* the result is now in the accumulator */
+ freeAsmop (cond, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genAddrOf - generates code for address of */
+/*-----------------------------------------------------------------*/
+static void
+genAddrOf (iCode * ic)
+{
+ operand *right, *result, *left;
+ int size, offset;
+
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+
+
+ //aopOp(IC_RESULT(ic),ic,FALSE);
+
+ aopOp ((left = IC_LEFT (ic)), ic, FALSE);
+ aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
+ aopOp ((result = IC_RESULT (ic)), ic, TRUE);
+
+ DEBUGpic14_AopType (__LINE__, left, right, result);
+ assert (IS_SYMOP (left));
+
+ /* sanity check: generic pointers to code space are not yet supported,
+ * pionters to codespace must not be assigned addresses of __data values. */
+#if 0
+ fprintf (stderr, "result: %s, left: %s\n", OP_SYMBOL (result)->name, OP_SYMBOL (left)->name);
+ fprintf (stderr, "result->type : ");
+ printTypeChain (OP_SYM_TYPE (result), stderr);
+ fprintf (stderr, ", codesp:%d, codeptr:%d, constptr:%d\n", IN_CODESPACE (SPEC_OCLS (getSpec (OP_SYM_TYPE (result)))),
+ IS_CODEPTR (OP_SYM_TYPE (result)), IS_PTR_CONST (OP_SYM_TYPE (result)));
+ fprintf (stderr, "result->etype: ");
+ printTypeChain (OP_SYM_ETYPE (result), stderr);
+ fprintf (stderr, ", codesp:%d, codeptr:%d, constptr:%d\n", IN_CODESPACE (SPEC_OCLS (getSpec (OP_SYM_ETYPE (result)))),
+ IS_CODEPTR (OP_SYM_ETYPE (result)), IS_PTR_CONST (OP_SYM_ETYPE (result)));
+ fprintf (stderr, "left->type : ");
+ printTypeChain (OP_SYM_TYPE (left), stderr);
+ fprintf (stderr, ", codesp:%d, codeptr:%d, constptr:%d\n", IN_CODESPACE (SPEC_OCLS (getSpec (OP_SYM_TYPE (left)))),
+ IS_CODEPTR (OP_SYM_TYPE (left)), IS_PTR_CONST (OP_SYM_TYPE (left)));
+ fprintf (stderr, "left->etype : ");
+ printTypeChain (OP_SYM_ETYPE (left), stderr);
+ fprintf (stderr, ", codesp:%d, codeptr:%d, constptr:%d\n", IN_CODESPACE (SPEC_OCLS (getSpec (OP_SYM_ETYPE (left)))),
+ IS_CODEPTR (OP_SYM_ETYPE (left)), IS_PTR_CONST (OP_SYM_ETYPE (left)));
+#endif
+
+ if (IS_SYMOP (result) && IS_CODEPTR (OP_SYM_TYPE (result)) && !IN_CODESPACE (SPEC_OCLS (getSpec (OP_SYM_TYPE (left)))))
+ {
+ fprintf (stderr, "trying to assign __code pointer (%s) an address in __data space (&%s) -- expect trouble\n",
+ IS_SYMOP (result) ? OP_SYMBOL (result)->name : "unknown", OP_SYMBOL (left)->name);
+ }
+ else if (IS_SYMOP (result) && !IS_CODEPTR (OP_SYM_TYPE (result)) && IN_CODESPACE (SPEC_OCLS (getSpec (OP_SYM_TYPE (left)))))
+ {
+ fprintf (stderr, "trying to assign __data pointer (%s) an address in __code space (&%s) -- expect trouble\n",
+ IS_SYMOP (result) ? OP_SYMBOL (result)->name : "unknown", OP_SYMBOL (left)->name);
+ }
+
+ size = AOP_SIZE (IC_RESULT (ic));
+ if (IS_SYMOP (result) && IS_GENPTR (OP_SYM_TYPE (result)))
+ {
+ /* strip tag */
+ if (size > GPTRSIZE - 1)
+ size = GPTRSIZE - 1;
+ }
+ offset = 0;
+
+ while (size--)
+ {
+ /* fixing bug #863624, reported from (errolv) */
+ emitpcode (POC_MOVLW, popGetImmd (OP_SYMBOL (left)->rname, offset, 0, IS_FUNC (OP_SYM_TYPE (left))));
+ emitpcode (POC_MOVWF, popGet (AOP (result), offset));
+
+#if 0
+ emitpcode (POC_MOVLW, popGet (AOP (left), offset));
+ emitpcode (POC_MOVWF, popGet (AOP (result), offset));
+#endif
+ offset++;
+ }
+
+ if (IS_SYMOP (result) && IS_GENPTR (OP_SYM_TYPE (result)))
+ {
+ /* provide correct tag */
+ int isCode = IN_CODESPACE (SPEC_OCLS (getSpec (OP_SYM_TYPE (left))));
+ emitpcode (POC_MOVLW, popGetLit (isCode ? GPTRTAG_CODE : GPTRTAG_DATA));
+ movwf (AOP (result), 2);
+ }
+
+ freeAsmop (left, NULL, ic, FALSE);
+ freeAsmop (result, NULL, ic, TRUE);
+
+}
+
+/*-----------------------------------------------------------------*/
+/* genAssign - generate code for assignment */
+/*-----------------------------------------------------------------*/
+static void
+genAssign (iCode * ic)
+{
+ operand *result, *right;
+ int size, offset, know_W;
+ unsigned long lit = 0L;
+
+ result = IC_RESULT (ic);
+ right = IC_RIGHT (ic);
+
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+
+ /* if they are the same */
+ if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
+ return;
+
+ aopOp (right, ic, FALSE);
+ aopOp (result, ic, TRUE);
+
+ DEBUGpic14_AopType (__LINE__, NULL, right, result);
+
+ /* if they are the same registers */
+ if (pic14_sameRegs (AOP (right), AOP (result)))
+ goto release;
+
+ /* special case: assign from __code */
+ if (!IS_ITEMP (right) /* --> iTemps never reside in __code */
+ && IS_SYMOP (right) /* --> must be an immediate (otherwise we would be in genConstPointerGet) */
+ && !IS_FUNC (OP_SYM_TYPE (right)) /* --> we would want its address instead of the first instruction */
+ && !IS_CODEPTR (OP_SYM_TYPE (right)) /* --> get symbols address instread */
+ && IN_CODESPACE (SPEC_OCLS (getSpec (OP_SYM_TYPE (right)))))
+ {
+ emitpComment ("genAssign from CODESPACE");
+ genConstPointerGet (right, result, ic);
+ goto release;
+ }
+
+ /* just for symmetry reasons... */
+ if (!IS_ITEMP (result) && IS_SYMOP (result) && IN_CODESPACE (SPEC_OCLS (getSpec (OP_SYM_TYPE (result)))))
+ {
+ assert (!"cannot write to CODESPACE");
+ }
+
+ /* if the result is a bit */
+ if (AOP_TYPE (result) == AOP_CRY)
+ {
+
+ /* if the right size is a literal then
+ we know what the value is */
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+
+ emitpcode ((((int) operandLitValue (right)) ? POC_BSF : POC_BCF), popGet (AOP (result), 0));
+
+ if (((int) operandLitValue (right)))
+ pic14_emitcode ("bsf", "(%s >> 3),(%s & 7)", AOP (result)->aopu.aop_dir, AOP (result)->aopu.aop_dir);
+ else
+ pic14_emitcode ("bcf", "(%s >> 3),(%s & 7)", AOP (result)->aopu.aop_dir, AOP (result)->aopu.aop_dir);
+ goto release;
+ }
+
+ /* the right is also a bit variable */
+ if (AOP_TYPE (right) == AOP_CRY)
+ {
+ emitpcode (POC_BCF, popGet (AOP (result), 0));
+ emitpcode (POC_BTFSC, popGet (AOP (right), 0));
+ emitpcode (POC_BSF, popGet (AOP (result), 0));
+
+ pic14_emitcode ("bcf", "(%s >> 3),(%s & 7)", AOP (result)->aopu.aop_dir, AOP (result)->aopu.aop_dir);
+ pic14_emitcode ("btfsc", "(%s >> 3),(%s & 7)", AOP (right)->aopu.aop_dir, AOP (right)->aopu.aop_dir);
+ pic14_emitcode ("bsf", "(%s >> 3),(%s & 7)", AOP (result)->aopu.aop_dir, AOP (result)->aopu.aop_dir);
+ goto release;
+ }
+
+ /* we need to or */
+ emitpcode (POC_BCF, popGet (AOP (result), 0));
+ pic14_toBoolean (right);
+ emitSKPZ;
+ emitpcode (POC_BSF, popGet (AOP (result), 0));
+ //aopPut(AOP(result),"a",0);
+ goto release;
+ }
+
+ /* bit variables done */
+ /* general case */
+ size = AOP_SIZE (result);
+ offset = 0;
+ if (AOP_TYPE (right) == AOP_DIR && (AOP_TYPE (result) == AOP_REG) && size == 1)
+ {
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ if (aopIdx (AOP (result), 0) == 4)
+ {
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ emitpcode (POC_MOVFW, popGet (AOP (right), offset));
+ emitpcode (POC_MOVWF, popGet (AOP (result), offset));
+ goto release;
+ }
+ else
+ DEBUGpic14_emitcode ("; WARNING", "%s %d ignoring register storage", __FUNCTION__, __LINE__);
+ }
+
+ know_W = -1;
+ while (size--)
+ {
+
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ if (AOP_TYPE (right) == AOP_LIT)
+ {
+ lit = (unsigned long) pic14aopLiteral (AOP (right)->aopu.aop_lit, offset) & 0x0ff;
+ if (lit & 0xff)
+ {
+ if (know_W != (int) (lit & 0xff))
+ emitpcode (POC_MOVLW, popGetLit (lit & 0xff));
+ know_W = lit & 0xff;
+ emitpcode (POC_MOVWF, popGet (AOP (result), offset));
+ }
+ else
+ emitpcode (POC_CLRF, popGet (AOP (result), offset));
+
+ }
+ else if (AOP_TYPE (right) == AOP_CRY)
+ {
+ emitpcode (POC_CLRF, popGet (AOP (result), offset));
+ if (offset == 0)
+ {
+ emitpcode (POC_BTFSS, popGet (AOP (right), 0));
+ emitpcode (POC_INCF, popGet (AOP (result), 0));
+ }
+ }
+ else
+ {
+ mov2w_op (right, offset);
+ emitpcode (POC_MOVWF, popGet (AOP (result), offset));
+ }
+
+ offset++;
+ }
+
+
+release:
+ freeAsmop (right, NULL, ic, FALSE);
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genJumpTab - generates code for jump table */
+/*-----------------------------------------------------------------*/
+static void
+genJumpTab (iCode * ic)
+{
+ symbol *jtab;
+ char *l;
+
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+
+ aopOp (IC_JTCOND (ic), ic, FALSE);
+ /* get the condition into accumulator */
+ l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE, FALSE);
+ MOVA (l);
+ /* multiply by three */
+ pic14_emitcode ("add", "a,acc");
+ pic14_emitcode ("add", "a,%s", aopGet (AOP (IC_JTCOND (ic)), 0, FALSE, FALSE));
+
+ jtab = newiTempLabel (NULL);
+ pic14_emitcode ("mov", "dptr,#%05d_DS_", labelKey2num (jtab->key));
+ pic14_emitcode ("jmp", "@a+dptr");
+ pic14_emitcode ("", "%05d_DS_:", labelKey2num (jtab->key));
+
+ emitpcode (POC_MOVLW, popGetHighLabel (jtab->key));
+ emitpcode (POC_MOVWF, popCopyReg (&pc_pclath));
+ emitpcode (POC_MOVLW, popGetLabel (jtab->key));
+ emitpcode (POC_ADDFW, popGet (AOP (IC_JTCOND (ic)), 0));
+ emitSKPNC;
+ emitpcode (POC_INCF, popCopyReg (&pc_pclath));
+ emitpcode (POC_MOVWF, popCopyReg (&pc_pcl));
+ emitpLabel (jtab->key);
+
+ freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
+
+ /* now generate the jump labels */
+ for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab; jtab = setNextItem (IC_JTLABELS (ic)))
+ {
+ pic14_emitcode ("ljmp", "%05d_DS_", labelKey2num (jtab->key));
+ emitpcode (POC_GOTO, popGetLabel (jtab->key));
+
+ }
+
+}
+
+/*-----------------------------------------------------------------*/
+/* genCast - gen code for casting */
+/*-----------------------------------------------------------------*/
+static void
+genCast (iCode * ic)
+{
+ operand *result = IC_RESULT (ic);
+ sym_link *restype = operandType (result);
+ sym_link *rtype = operandType (IC_RIGHT (ic));
+ operand *right = IC_RIGHT (ic);
+ int size, offset;
+
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ /* if they are equivalent then do nothing */
+ if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
+ return;
+
+ aopOp (right, ic, FALSE);
+ aopOp (result, ic, FALSE);
+
+ DEBUGpic14_AopType (__LINE__, NULL, right, result);
+
+ /* if the result is a bit */
+ if (AOP_TYPE (result) == AOP_CRY)
+ {
+ assert (!"assigning to bit variables is not supported");
+ }
+
+ if ((AOP_TYPE (right) == AOP_CRY) && (AOP_TYPE (result) == AOP_REG))
+ {
+ int offset = 1;
+ size = AOP_SIZE (result);
+
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+
+ emitpcode (POC_CLRF, popGet (AOP (result), 0));
+ emitpcode (POC_BTFSC, popGet (AOP (right), 0));
+ emitpcode (POC_INCF, popGet (AOP (result), 0));
+
+ while (size--)
+ emitpcode (POC_CLRF, popGet (AOP (result), offset++));
+
+ goto release;
+ }
+
+ if (IS_BOOL (operandType (result)))
+ {
+ pic14_toBoolean (right);
+ emitSKPNZ;
+ emitpcode (POC_MOVLW, popGetLit (1));
+ emitpcode (POC_MOVWF, popGet (AOP (result), 0));
+ goto release;
+ }
+
+ if (IS_PTR (restype))
+ {
+ operand *result = IC_RESULT (ic);
+ //operand *left = IC_LEFT(ic);
+ operand *right = IC_RIGHT (ic);
+ int tag = 0xff;
+
+ /* copy common part */
+ int max, size = AOP_SIZE (result);
+ if (size > AOP_SIZE (right))
+ size = AOP_SIZE (right);
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+
+ /* warn if we discard generic opinter tag */
+ if (!IS_GENPTR (restype) && IS_GENPTR (rtype) && (AOP_SIZE (result) < AOP_SIZE (right)))
+ {
+ //fprintf (stderr, "%s:%u: discarding generic pointer type tag\n", __FUNCTION__, __LINE__);
+ } // if
+
+ max = size;
+ while (size--)
+ {
+ mov2w_op (right, size);
+ movwf (AOP (result), size);
+ } // while
+
+ /* upcast into generic pointer type? */
+ if (IS_GENPTR (restype) && (size < AOP_SIZE (result)) && (!IS_GENPTR (rtype) || AOP_SIZE (right) < GPTRSIZE))
+ {
+ //fprintf (stderr, "%s:%u: must determine pointer type\n", __FUNCTION__, __LINE__);
+ if (IS_PTR (rtype))
+ {
+ switch (DCL_TYPE (rtype))
+ {
+ case POINTER: /* __data */
+ case FPOINTER: /* __data */
+ assert (AOP_SIZE (right) == 2);
+ tag = GPTRTAG_DATA;
+ break;
+
+ case CPOINTER: /* __code */
+ assert (AOP_SIZE (right) == 2);
+ tag = GPTRTAG_CODE;
+ break;
+
+ case GPOINTER: /* unknown destination, __data or __code */
+ /* assume __data space (address of immediate) */
+ assert (AOP_TYPE (right) == AOP_PCODE && AOP (right)->aopu.pcop->type == PO_IMMEDIATE);
+ if (AOP (right)->code)
+ tag = GPTRTAG_CODE;
+ else
+ tag = GPTRTAG_DATA;
+ break;
+
+ default:
+ assert (!"unhandled pointer type");
+ } // switch
+ }
+ else
+ {
+ /* convert other values into pointers to __data space */
+ tag = GPTRTAG_DATA;
+ }
+
+ assert (AOP_SIZE (result) == 3);
+ if (tag == 0)
+ {
+ emitpcode (POC_CLRF, popGet (AOP (result), 2));
+ }
+ else
+ {
+ emitpcode (POC_MOVLW, popGetLit (tag));
+ movwf (AOP (result), 2);
+ }
+ }
+ else
+ {
+ addSign (result, max, 0);
+ } // if
+ goto release;
+ }
+
+ /* if they are the same size : or less */
+ if (AOP_SIZE (result) <= AOP_SIZE (right))
+ {
+
+ /* if they are in the same place */
+ if (pic14_sameRegs (AOP (right), AOP (result)))
+ goto release;
+
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+ if (IS_PTR_CONST (rtype))
+ DEBUGpic14_emitcode ("; ***", "%d - right is const pointer", __LINE__);
+ if (IS_PTR_CONST (operandType (IC_RESULT (ic))))
+ DEBUGpic14_emitcode ("; ***", "%d - result is const pointer", __LINE__);
+
+ if ((AOP_TYPE (right) == AOP_PCODE) && AOP (right)->aopu.pcop->type == PO_IMMEDIATE)
+ {
+ emitpcode (POC_MOVLW, popGetAddr (AOP (right), 0, 0));
+ emitpcode (POC_MOVWF, popGet (AOP (result), 0));
+ emitpcode (POC_MOVLW, popGetAddr (AOP (right), 1, 0));
+ emitpcode (POC_MOVWF, popGet (AOP (result), 1));
+ if (AOP_SIZE (result) < 2)
+ fprintf (stderr, "%d -- result is not big enough to hold a ptr\n", __LINE__);
+
+ }
+ else
+ {
+
+ /* if they in different places then copy */
+ size = AOP_SIZE (result);
+ offset = 0;
+ while (size--)
+ {
+ emitpcode (POC_MOVFW, popGet (AOP (right), offset));
+ emitpcode (POC_MOVWF, popGet (AOP (result), offset));
+
+ //aopPut(AOP(result),
+ // aopGet(AOP(right),offset,FALSE,FALSE),
+ // offset);
+
+ offset++;
+ }
+ }
+ goto release;
+ }
+
+ /* so we now know that the size of destination is greater
+ than the size of the source. */
+
+ /* we move to result for the size of source */
+ size = AOP_SIZE (right);
+ offset = 0;
+ while (size--)
+ {
+ emitpcode (POC_MOVFW, popGet (AOP (right), offset));
+ emitpcode (POC_MOVWF, popGet (AOP (result), offset));
+ offset++;
+ }
+
+ addSign (result, AOP_SIZE (right), !SPEC_USIGN (rtype));
+
+release:
+ freeAsmop (right, NULL, ic, TRUE);
+ freeAsmop (result, NULL, ic, TRUE);
+
+}
+
+/*-----------------------------------------------------------------*/
+/* genDjnz - generate decrement & jump if not zero instrucion */
+/*-----------------------------------------------------------------*/
+static int
+genDjnz (iCode * ic, iCode * ifx)
+{
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+
+ if (!ifx)
+ return 0;
+
+ /* if the if condition has a false label
+ then we cannot save */
+ if (IC_FALSE (ifx))
+ return 0;
+
+ /* if the minus is not of the form
+ a = a - 1 */
+ if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) || !IS_OP_LITERAL (IC_RIGHT (ic)))
+ return 0;
+
+ if (operandLitValue (IC_RIGHT (ic)) != 1)
+ return 0;
+
+ /* if the size of this greater than one then no
+ saving */
+ if (getSize (operandType (IC_RESULT (ic))) > 1)
+ return 0;
+
+ /* otherwise we can save BIG */
+ aopOp (IC_RESULT (ic), ic, FALSE);
+
+ emitpcode (POC_DECFSZ, popGet (AOP (IC_RESULT (ic)), 0));
+ emitpcode (POC_GOTO, popGetLabel (IC_TRUE (ifx)->key));
+
+ freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
+ ifx->generated = TRUE;
+ return 1;
+}
+
+/*-----------------------------------------------------------------*/
+/* genReceive - generate code for a receive iCode */
+/*-----------------------------------------------------------------*/
+static void
+genReceive (iCode * ic)
+{
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***", "%s %d", __FUNCTION__, __LINE__);
+
+ if (isOperandInFarSpace (IC_RESULT (ic)) && (OP_SYMBOL (IC_RESULT (ic))->isspilt || IS_TRUE_SYMOP (IC_RESULT (ic))))
+ {
+
+ int size = getSize (operandType (IC_RESULT (ic)));
+ int offset = fReturnSizePic - size;
+ while (size--)
+ {
+ pic14_emitcode ("push", "%s", (strcmp (fReturn[fReturnSizePic - offset - 1], "a") ?
+ fReturn[fReturnSizePic - offset - 1] : "acc"));
+ offset++;
+ }
+ aopOp (IC_RESULT (ic), ic, FALSE);
+ size = AOP_SIZE (IC_RESULT (ic));
+ offset = 0;
+ while (size--)
+ {
+ pic14_emitcode ("pop", "acc");
+ aopPut (AOP (IC_RESULT (ic)), "a", offset++);
+ }
+
+ }
+ else
+ {
+ _G.accInUse++;
+ aopOp (IC_RESULT (ic), ic, FALSE);
+ _G.accInUse--;
+ GpseudoStkPtr = ic->parmBytes; // address used arg on stack
+ assignResultValue (IC_RESULT (ic));
+ }
+
+ freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genDummyRead - generate code for dummy read of volatiles */
+/*-----------------------------------------------------------------*/
+static void
+genDummyRead (iCode * ic)
+{
+ FENTRY;
+ pic14_emitcode ("; genDummyRead", "");
+ pic14_emitcode ("; not implemented", "");
+
+ ic = ic;
+}
+
+/*-----------------------------------------------------------------*/
+/* genpic14Code - generate code for pic14 based controllers */
+/*-----------------------------------------------------------------*/
+/*
+* At this point, ralloc.c has gone through the iCode and attempted
+* to optimize in a way suitable for a PIC. Now we've got to generate
+* PIC instructions that correspond to the iCode.
+*
+* Once the instructions are generated, we'll pass through both the
+* peep hole optimizer and the pCode optimizer.
+*-----------------------------------------------------------------*/
+
+void
+genpic14Code (iCode * lic)
+{
+ iCode *ic;
+ int cln = 0;
+ const char *cline;
+
+ FENTRY;
+
+ pic = pic14_getPIC();
+
+ pb = newpCodeChain (GcurMemmap, 0, newpCodeCharP ("; Starting pCode block"));
+ addpBlock (pb);
+
+ /* if debug information required */
+ if (options.debug && debugFile && currFunc)
+ {
+ debugFile->writeFunction (currFunc, lic);
+ }
+
+
+ for (ic = lic; ic; ic = ic->next)
+ {
+ initGenLineElement ();
+
+ //DEBUGpic14_emitcode(";ic","");
+ //fprintf (stderr, "in ic loop\n");
+ //pic14_emitcode ("", ";\t%s:%d: %s", ic->filename,
+ //ic->lineno, printCLine(ic->filename, ic->lineno));
+
+ if (!options.noCcodeInAsm && (cln != ic->lineno))
+ {
+ cln = ic->lineno;
+ //fprintf (stderr, "%s\n", printCLine (ic->filename, ic->lineno));
+ cline = printCLine (ic->filename, ic->lineno);
+ if (!cline || strlen (cline) == 0)
+ cline = printCLine (ic->filename, ic->lineno);
+ addpCode2pBlock (pb, newpCodeCSource (ic->lineno, ic->filename, cline));
+ //emitpComment ("[C-SRC] %s:%d: %s", ic->filename, cln, cline);
+ }
+
+ if (options.iCodeInAsm)
+ {
+ const char *iLine = printILine (ic);
+ emitpComment ("[ICODE] %s:%d: %s", ic->filename, ic->lineno, printILine (ic));
+ dbuf_free (iLine);
+ }
+ /* if the result is marked as
+ spilt and rematerializable or code for
+ this has already been generated then
+ do nothing */
+ if (resultRemat (ic) || ic->generated)
+ continue;
+
+ /* depending on the operation */
+ switch (ic->op)
+ {
+ case '!':
+ genNot (ic);
+ break;
+
+ case '~':
+ genCpl (ic);
+ break;
+
+ case UNARYMINUS:
+ genUminus (ic);
+ break;
+
+ case IPUSH:
+ genIpush (ic);
+ break;
+
+ case IPOP:
+ /* IPOP happens only when trying to restore a
+ spilt live range, if there is an ifx statement
+ following this pop then the if statement might
+ be using some of the registers being popped which
+ would destory the contents of the register so
+ we need to check for this condition and handle it */
+ if (ic->next && ic->next->op == IFX && regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
+ genIfx (ic->next, ic);
+ else
+ genIpop (ic);
+ break;
+
+ case CALL:
+ genCall (ic);
+ break;
+
+ case PCALL:
+ genPcall (ic);
+ break;
+
+ case FUNCTION:
+ genFunction (ic);
+ break;
+
+ case ENDFUNCTION:
+ genEndFunction (ic);
+ break;
+
+ case RETURN:
+ genRet (ic);
+ break;
+
+ case LABEL:
+ genLabel (ic);
+ break;
+
+ case GOTO:
+ genGoto (ic);
+ break;
+
+ case '+':
+ genPlus (ic);
+ break;
+
+ case '-':
+ if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
+ genMinus (ic);
+ break;
+
+ case '*':
+ genMult (ic);
+ break;
+
+ case '/':
+ genDiv (ic);
+ break;
+
+ case '%':
+ genMod (ic);
+ break;
+
+ case '>':
+ genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
+ break;
+
+ case '<':
+ genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
+ break;
+
+ case LE_OP:
+ case GE_OP:
+ case NE_OP:
+
+ /* note these two are xlated by algebraic equivalence
+ during parsing SDCC.y */
+ werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "got '>=' or '<=' shouldn't have come here");
+ break;
+
+ case EQ_OP:
+ genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
+ break;
+
+ case AND_OP:
+ genAndOp (ic);
+ break;
+
+ case OR_OP:
+ genOrOp (ic);
+ break;
+
+ case '^':
+ genXor (ic, ifxForOp (IC_RESULT (ic), ic));
+ break;
+
+ case '|':
+ genOr (ic, ifxForOp (IC_RESULT (ic), ic));
+ break;
+
+ case BITWISEAND:
+ genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
+ break;
+
+ case INLINEASM:
+ pic14_genInline (ic);
+ break;
+
+ case RRC:
+ genRRC (ic);
+ break;
+
+ case RLC:
+ genRLC (ic);
+ break;
+
+ case GETABIT:
+ genGetABit (ic);
+ break;
+
+ case GETHBIT:
+ genGetHbit (ic);
+ break;
+
+ case LEFT_OP:
+ genLeftShift (ic);
+ break;
+
+ case RIGHT_OP:
+ genRightShift (ic);
+ break;
+
+ case GET_VALUE_AT_ADDRESS:
+ genPointerGet (ic);
+ break;
+
+ case '=':
+ if (POINTER_SET (ic))
+ genPointerSet (ic);
+ else
+ genAssign (ic);
+ break;
+
+ case IFX:
+ genIfx (ic, NULL);
+ break;
+
+ case ADDRESS_OF:
+ genAddrOf (ic);
+ break;
+
+ case JUMPTABLE:
+ genJumpTab (ic);
+ break;
+
+ case CAST:
+ genCast (ic);
+ break;
+
+ case RECEIVE:
+ genReceive (ic);
+ break;
+
+ case SEND:
+ addSet (&_G.sendSet, ic);
+ break;
+
+ case DUMMY_READ_VOLATILE:
+ genDummyRead (ic);
+ break;
+
+ case CRITICAL:
+ genCritical (ic);
+ break;
+
+ case ENDCRITICAL:
+ genEndCritical (ic);
+ break;
+
+ default:
+ fprintf (stderr, "UNHANDLED iCode: ");
+ piCode (ic, stderr);
+ ic = ic;
+ break;
+ }
+ }
+
+
+ /* now we are ready to call the
+ peep hole optimizer */
+ if (!options.nopeep)
+ {
+ peepHole (&genLine.lineHead);
+ }
+ /* now do the actual printing */
+ printLine (genLine.lineHead, codeOutBuf);
+
+#ifdef PCODE_DEBUG
+ DFPRINTF ((stderr, "printing pBlock\n\n"));
+ printpBlock (stdout, pb);
+#endif
+
+ /* destroy the line list */
+ destroy_line_list ();
+}
+
+/* This is not safe, as a AOP_PCODE/PO_IMMEDIATE might be used both as literal
+ * (meaning: representing its own address) or not (referencing its contents).
+ * This can only be decided based on the operand's type. */
+static int
+aop_isLitLike (asmop * aop)
+{
+ assert (aop);
+ if (aop->type == AOP_LIT)
+ return TRUE;
+ if (aop->type == AOP_IMMD)
+ return TRUE;
+ if ((aop->type == AOP_PCODE) &&
+ ((aop->aopu.pcop->type == PO_LITERAL) ||
+ (aop->aopu.pcop->type == PO_IMMEDIATE)))
+ {
+ /* this should be treated like a literal/immediate (use MOVLW/ADDLW/SUBLW
+ * instead of MOVFW/ADDFW/SUBFW, use popGetAddr instead of popGet) */
+ return TRUE;
+ }
+ return FALSE;
+}
+
+int
+op_isLitLike (operand * op)
+{
+ assert (op);
+ if (aop_isLitLike (AOP (op)))
+ return TRUE;
+ if (IS_SYMOP (op) && IS_FUNC (OP_SYM_TYPE (op)))
+ return TRUE;
+ if (IS_SYMOP (op) && IS_PTR (OP_SYM_TYPE (op)) && (AOP_TYPE (op) == AOP_PCODE) && (AOP (op)->aopu.pcop->type == PO_IMMEDIATE))
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
diff --git a/src/pic14/gen.h b/src/pic14/gen.h
new file mode 100644
index 0000000..6143d30
--- /dev/null
+++ b/src/pic14/gen.h
@@ -0,0 +1,174 @@
+/*-------------------------------------------------------------------------
+ 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)
+
+ 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
+
+#include "common.h"
+
+#include "main.h"
+#include "pcode.h"
+#include "ralloc.h"
+
+#define FENTRY do { \
+ /*fprintf (stderr, "%s:%u:%s: *{*\n", __FILE__, __LINE__, __FUNCTION__);*/ \
+ if (options.debug || debug_verbose) { \
+ emitpComment ("; %s:%u:%s *{*", __FILE__, __LINE__, __FUNCTION__); \
+ } \
+} while (0)
+#define FEXIT do { \
+ /*fprintf (stderr, "%s:%u:%s: *}*\n", __FILE__, __LINE__, __FUNCTION__);*/ \
+ if (options.debug || debug.verbose) { \
+ emitpComment ("; %s:%u:%s *}*", __FILE__, __LINE__, __FUNCTION__); \
+ } \
+} while (0)
+
+enum
+{
+ AOP_LIT = 1,
+ AOP_REG,
+ AOP_DIR,
+ AOP_STK,
+ AOP_IMMD,
+ AOP_STR,
+ AOP_CRY,
+ 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_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
+ */
+ 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 */
+ reg_info *aop_reg[4]; /* array of registers */
+ char *aop_dir; /* if direct */
+ reg_info *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 */
+ pCodeOp *pcop;
+ }
+ aopu;
+}
+asmop;
+
+extern unsigned fReturnSizePic;
+
+
+#define AOP(op) op->aop
+#define AOP_TYPE(op) AOP(op)->type
+#define AOP_SIZE(op) AOP(op)->size
+
+#define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY || AOP(x)->paged))
+
+#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")) pic14_emitcode(";XXX mov","a,%s %s,%d",x,__FILE__,__LINE__);
+#define CLRC pic14_emitcode(";XXX clr","c %s,%d",__FILE__,__LINE__);
+
+#define LSB 0
+#define MSB16 1
+#define MSB24 2
+#define MSB32 3
+
+/*-----------------------------------------------------------------*/
+/* Macros for emitting skip instructions */
+/*-----------------------------------------------------------------*/
+
+#define emitSKPC emitpcode(POC_BTFSS,popCopyGPR2Bit(PCOP(&pc_status),PIC_C_BIT))
+#define emitSKPNC emitpcode(POC_BTFSC,popCopyGPR2Bit(PCOP(&pc_status),PIC_C_BIT))
+#define emitSKPZ emitpcode(POC_BTFSS,popCopyGPR2Bit(PCOP(&pc_status),PIC_Z_BIT))
+#define emitSKPNZ emitpcode(POC_BTFSC,popCopyGPR2Bit(PCOP(&pc_status),PIC_Z_BIT))
+#define emitSKPDC emitpcode(POC_BTFSS,popCopyGPR2Bit(PCOP(&pc_status),PIC_DC_BIT))
+#define emitSKPNDC emitpcode(POC_BTFSC,popCopyGPR2Bit(PCOP(&pc_status),PIC_DC_BIT))
+#define emitCLRZ emitpcode(POC_BCF, popCopyGPR2Bit(PCOP(&pc_status),PIC_Z_BIT))
+#define emitCLRC emitpcode(POC_BCF, popCopyGPR2Bit(PCOP(&pc_status),PIC_C_BIT))
+#define emitCLRDC emitpcode(POC_BCF, popCopyGPR2Bit(PCOP(&pc_status),PIC_DC_BIT))
+#define emitCLRIRP emitpcode(POC_BCF, popCopyGPR2Bit(PCOP(&pc_status),PIC_IRP_BIT))
+#define emitSETZ emitpcode(POC_BSF, popCopyGPR2Bit(PCOP(&pc_status),PIC_Z_BIT))
+#define emitSETC emitpcode(POC_BSF, popCopyGPR2Bit(PCOP(&pc_status),PIC_C_BIT))
+#define emitSETDC emitpcode(POC_BSF, popCopyGPR2Bit(PCOP(&pc_status),PIC_DC_BIT))
+#define emitSETIRP emitpcode(POC_BSF, popCopyGPR2Bit(PCOP(&pc_status),PIC_IRP_BIT))
+
+int pic14_getDataSize(operand *op);
+void emitpcode_real(PIC_OPCODE poc, pCodeOp *pcop);
+#define emitpcode(poc,pcop) do { if (options.debug || debug_verbose) { emitpComment (" >>> %s:%d:%s", __FILE__, __LINE__, __FUNCTION__); } emitpcode_real(poc,pcop); } while(0)
+void emitpComment (const char *fmt, ...);
+void emitpLabel(int key);
+void pic14_emitcode (const char *inst, const char *fmt, ...);
+void DEBUGpic14_emitcode (const char *inst, const char *fmt, ...);
+void pic14_emitDebuggerSymbol (const char *);
+bool pic14_sameRegs (asmop *aop1, asmop *aop2 );
+char *aopGet (asmop *aop, int offset, bool bit16, bool dname);
+void DEBUGpic14_AopType(int line_no, operand *left, operand *right, operand *result);
+void genpic14Code (iCode *lic);
+
+
+pCodeOp *popGet (asmop *aop, int offset);//, bool bit16, bool dname);
+pCodeOp *popGetAddr (asmop *aop, int offset, int index);
+pCodeOp *popGetExternal (const char *str, int isReg);
+pCodeOp *popGetLabel(unsigned int key);
+pCodeOp *popGetLit(unsigned int lit);
+
+
+void aopPut (asmop *aop, const char *s, int offset);
+void pic14_outAcc(operand *result);
+void aopOp (operand *op, iCode *ic, bool result);
+void freeAsmop (operand *op, asmop *aaop, iCode *ic, bool pop);
+void mov2w (asmop *aop, int offset);
+int op_isLitLike (operand *op);
+
+/*
+ * From genarith.c:
+ */
+const char *AopType(short type);
+const char *pCodeOpType(pCodeOp *pcop);
+void genPlus (iCode *ic);
+void addSign(operand *result, int offset, int sign);
+void genMinus (iCode *ic);
+
+#endif
diff --git a/src/pic14/genarith.c b/src/pic14/genarith.c
new file mode 100644
index 0000000..2c9936e
--- /dev/null
+++ b/src/pic14/genarith.c
@@ -0,0 +1,1289 @@
+/*-------------------------------------------------------------------------
+ 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)
+
+ 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 "common.h"
+#include "newalloc.h"
+//#include "SDCCglobl.h"
+//#include "SDCCpeeph.h"
+
+#include "gen.h"
+#include "pcode.h"
+#include "ralloc.h"
+
+
+#define BYTEofLONG(l,b) ( (l>> (b<<3)) & 0xff)
+
+const char *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_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_PCODE:
+ return "AOP_PCODE";
+ break;
+ }
+
+ return "BAD TYPE";
+}
+
+const char *pCodeOpType(pCodeOp *pcop)
+{
+
+ if(pcop) {
+
+ switch(pcop->type) {
+
+ case PO_NONE:
+ return "PO_NONE";
+ case PO_W:
+ return "PO_W";
+ case PO_STATUS:
+ return "PO_STATUS";
+ case PO_FSR:
+ return "PO_FSR";
+ case PO_INDF:
+ return "PO_INDF";
+ case PO_INTCON:
+ return "PO_INTCON";
+ case PO_GPR_REGISTER:
+ return "PO_GPR_REGISTER";
+ case PO_GPR_POINTER:
+ return "PO_GPR_POINTER";
+ 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_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";
+}
+
+/*-----------------------------------------------------------------*/
+/* genPlusIncr :- does addition with increment if possible */
+/*-----------------------------------------------------------------*/
+static bool genPlusIncr (iCode *ic)
+{
+ unsigned int icount ;
+ unsigned int size = pic14_getDataSize(IC_RESULT(ic));
+ FENTRY;
+
+ DEBUGpic14_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
+ DEBUGpic14_emitcode ("; ","result %s, left %s, right %s",
+ AopType(AOP_TYPE(IC_RESULT(ic))),
+ AopType(AOP_TYPE(IC_LEFT(ic))),
+ 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 ;
+
+ DEBUGpic14_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) ulFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit)) > 2)
+ return FALSE ;
+
+ /* if increment 16 bits in register */
+ if (pic14_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) &&
+ (icount == 1)) {
+
+ int offset = MSB16;
+
+ emitpcode(POC_INCF, popGet(AOP(IC_RESULT(ic)),LSB));
+ //pic14_emitcode("incf","%s,f",aopGet(AOP(IC_RESULT(ic)),LSB,FALSE,FALSE));
+
+ while(--size) {
+ emitSKPNZ;
+ emitpcode(POC_INCF, popGet(AOP(IC_RESULT(ic)),offset++));
+ //pic14_emitcode(" incf","%s,f",aopGet(AOP(IC_RESULT(ic)),offset++,FALSE,FALSE));
+ }
+
+ return TRUE;
+ }
+
+ DEBUGpic14_emitcode ("; ","%s %d",__FUNCTION__,__LINE__);
+ /* if left is in accumulator - probably a bit operation*/
+ if( strcmp(aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE),"a") &&
+ (AOP_TYPE(IC_RESULT(ic)) == AOP_CRY) ) {
+
+ emitpcode(POC_BCF, popGet(AOP(IC_RESULT(ic)),0));
+ pic14_emitcode("bcf","(%s >> 3), (%s & 7)",
+ AOP(IC_RESULT(ic))->aopu.aop_dir,
+ AOP(IC_RESULT(ic))->aopu.aop_dir);
+ if(icount)
+ emitpcode(POC_XORLW,popGetLit(1));
+ //pic14_emitcode("xorlw","1");
+ else
+ emitpcode(POC_ANDLW,popGetLit(1));
+ //pic14_emitcode("andlw","1");
+
+ emitSKPZ;
+ emitpcode(POC_BSF, popGet(AOP(IC_RESULT(ic)),0));
+ pic14_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 (pic14_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) {
+
+ while (icount--)
+ emitpcode(POC_INCF, popGet(AOP(IC_RESULT(ic)),0));
+ //pic14_emitcode("incf","%s,f",aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE));
+
+ return TRUE ;
+ }
+
+ DEBUGpic14_emitcode ("; ","couldn't increment ");
+
+ return FALSE ;
+}
+
+/*-----------------------------------------------------------------*/
+/* genAddlit - generates code for addition */
+/*-----------------------------------------------------------------*/
+static void genAddLit2byte (operand *result, int offr, int lit)
+{
+ FENTRY;
+
+ switch(lit & 0xff) {
+ case 0:
+ break;
+ case 1:
+ emitpcode(POC_INCF, popGet(AOP(result),offr));
+ break;
+ case 0xff:
+ emitpcode(POC_DECF, popGet(AOP(result),offr));
+ break;
+ default:
+ emitpcode(POC_MOVLW,popGetLit(lit&0xff));
+ emitpcode(POC_ADDWF,popGet(AOP(result),offr));
+ }
+
+}
+
+static void emitMOVWF(operand *reg, int offset)
+{
+ FENTRY;
+ if(!reg)
+ return;
+
+ emitpcode(POC_MOVWF, popGet(AOP(reg),offset));
+
+}
+
+static void genAddLit (iCode *ic, int lit)
+{
+ int size, same;
+ int lo;
+
+ operand *result;
+ operand *left;
+
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
+
+ left = IC_LEFT(ic);
+ result = IC_RESULT(ic);
+ same = pic14_sameRegs(AOP(left), AOP(result));
+ size = pic14_getDataSize(result);
+ if (size > pic14_getDataSize(left))
+ {
+ size = pic14_getDataSize(left);
+ }
+
+ /*
+ * Fix accessing libsdcc/<*>/idata.c:_cinit in __code space.
+ */
+ if (AOP_PCODE == AOP_TYPE(IC_LEFT(ic)))
+ {
+ int u;
+ if (debug_verbose)
+ {
+ printf("%s:%u: CHECK: using address of '%s' instead of contents\n",
+ ic->filename, ic->lineno,
+ popGetAddr(AOP(IC_LEFT(ic)), 0, lit & 0xff)->name);
+ } // if
+ for (u = 0; u < size; ++u)
+ {
+ emitpcode(POC_MOVLW, popGetAddr(AOP(IC_LEFT(ic)), u, lit));
+ emitpcode(POC_MOVWF, popGet(AOP(IC_RESULT(ic)), u));
+ } // for
+
+ if (size < pic14_getDataSize(result))
+ {
+ for (u = size; u < pic14_getDataSize(result); ++u)
+ {
+ /* XXX: Might fail for u >= size?!? */
+ emitpcode(POC_MOVLW, popGetAddr(AOP(IC_LEFT(ic)), u, lit));
+ emitpcode(POC_MOVWF, popGet(AOP(IC_RESULT(ic)), u));
+ } // for
+ } // if
+
+ goto out;
+ } // if
+
+ if (same)
+ {
+ /* Handle special cases first */
+ if (size == 1)
+ {
+ genAddLit2byte (result, 0, lit);
+ }
+ else if (size == 2)
+ {
+ int hi = (lit >> 8) & 0xff;
+ lo = lit & 0xff;
+
+ switch (hi)
+ {
+ case 0:
+ /* lit = 0x00LL */
+ DEBUGpic14_emitcode ("; hi = 0","%s %d",__FUNCTION__,__LINE__);
+ switch (lo)
+ {
+ case 0:
+ break;
+ case 1:
+ emitpcode(POC_INCF, popGet(AOP(result),0));
+ emitSKPNZ;
+ emitpcode(POC_INCF, popGet(AOP(result),MSB16));
+ break;
+ case 0xff:
+ emitpcode(POC_DECF, popGet(AOP(result),0));
+ emitpcode(POC_INCFSZW, popGet(AOP(result),0));
+ emitpcode(POC_INCF, popGet(AOP(result),MSB16));
+ break;
+ default:
+ emitpcode(POC_MOVLW,popGetLit(lit&0xff));
+ emitpcode(POC_ADDWF,popGet(AOP(result),0));
+ emitSKPNC;
+ emitpcode(POC_INCF, popGet(AOP(result),MSB16));
+ break;
+ } // switch
+ break;
+
+ case 1:
+ /* lit = 0x01LL */
+ DEBUGpic14_emitcode ("; hi = 1","%s %d",__FUNCTION__,__LINE__);
+ switch (lo)
+ {
+ case 0: /* 0x0100 */
+ emitpcode(POC_INCF, popGet(AOP(result),MSB16));
+ break;
+ case 1: /* 0x0101 */
+ emitpcode(POC_INCF, popGet(AOP(result),MSB16));
+ emitpcode(POC_INCF, popGet(AOP(result),0));
+ emitSKPNZ;
+ emitpcode(POC_INCF, popGet(AOP(result),MSB16));
+ break;
+ case 0xff: /* 0x01ff */
+ emitpcode(POC_DECF, popGet(AOP(result),0));
+ emitpcode(POC_INCFSZW, popGet(AOP(result),0));
+ emitpcode(POC_INCF, popGet(AOP(result),MSB16));
+ emitpcode(POC_INCF, popGet(AOP(result),MSB16));
+ break;
+ default:
+ emitpcode(POC_MOVLW, popGetLit(lo));
+ emitpcode(POC_ADDWF, popGet(AOP(result),0));
+ emitSKPNC;
+ emitpcode(POC_INCF, popGet(AOP(result),MSB16));
+ emitpcode(POC_INCF, popGet(AOP(result),MSB16));
+ break;
+ } // switch
+ break;
+
+ case 0xff:
+ DEBUGpic14_emitcode ("; hi = ff","%s %d",__FUNCTION__,__LINE__);
+ /* lit = 0xffLL */
+ switch (lo)
+ {
+ case 0: /* 0xff00 */
+ emitpcode(POC_DECF, popGet(AOP(result),MSB16));
+ break;
+ case 1: /*0xff01 */
+ emitpcode(POC_INCFSZ, popGet(AOP(result),0));
+ emitpcode(POC_DECF, popGet(AOP(result),MSB16));
+ break;
+ default:
+ emitpcode(POC_MOVLW,popGetLit(lo));
+ emitpcode(POC_ADDWF,popGet(AOP(result),0));
+ emitSKPC;
+ emitpcode(POC_DECF, popGet(AOP(result),MSB16));
+ break;
+ } // switch
+ break;
+
+ default:
+ DEBUGpic14_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 */
+ emitpcode(POC_MOVLW,popGetLit((hi+1)&0xff));
+ emitpcode(POC_INCFSZ, popGet(AOP(result),0));
+ emitpcode(POC_MOVLW,popGetLit(hi));
+ emitpcode(POC_ADDWF,popGet(AOP(result),MSB16));
+ break;
+ default: /* 0xHHLL */
+ emitpcode(POC_MOVLW,popGetLit(lo));
+ emitpcode(POC_ADDWF, popGet(AOP(result),0));
+ emitpcode(POC_MOVLW,popGetLit(hi));
+ emitSKPNC;
+ emitpcode(POC_MOVLW,popGetLit((hi+1) & 0xff));
+ emitpcode(POC_ADDWF,popGet(AOP(result),MSB16));
+ break;
+ } // switch
+ break;
+ } // switch
+ }
+ else
+ {
+ int carry_info = 0;
+ int offset = 0;
+ /* size > 2 */
+ DEBUGpic14_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;
+ emitpcode(POC_INCF, popGet(AOP(result),offset));
+ break;
+ case 2:
+ emitpcode(POC_RLFW, popGet(AOP(result),offset));
+ emitpcode(POC_ANDLW,popGetLit(1));
+ emitpcode(POC_ADDWF, popGet(AOP(result),offset));
+ break;
+ default: /* carry_info = 3 */
+ emitSKPNC;
+ emitpcode(POC_INCF, popGet(AOP(result),offset));
+ carry_info = 1;
+ break;
+ } // switch
+ break;
+ case 0xff:
+ emitpcode(POC_MOVLW,popGetLit(lo));
+ if (carry_info==1)
+ emitSKPZ;
+ else
+ emitSKPC;
+ emitpcode(POC_ADDWF, popGet(AOP(result),offset));
+ break;
+ default:
+ emitpcode(POC_MOVLW,popGetLit(lo));
+ if (carry_info==1)
+ emitSKPNZ;
+ else
+ emitSKPNC;
+ emitpcode(POC_MOVLW,popGetLit(lo+1));
+ emitpcode(POC_ADDWF, popGet(AOP(result),offset));
+ carry_info=2;
+ break;
+ } // switch
+ }
+ else
+ {
+ /* no carry info from previous step */
+ /* this means this is the first time to add */
+ switch (lo)
+ {
+ case 0:
+ break;
+ case 1:
+ emitpcode(POC_INCF, popGet(AOP(result),offset));
+ carry_info=1;
+ break;
+ default:
+ emitpcode(POC_MOVLW,popGetLit(lo));
+ emitpcode(POC_ADDWF, popGet(AOP(result),offset));
+ if (lit <0x100)
+ carry_info = 3; /* Were adding only one byte and propogating the carry */
+ else
+ carry_info = 2;
+ break;
+ } // switch
+ } // if
+ offset++;
+ lit >>= 8;
+ } // while
+ } // if
+ }
+ else
+ {
+ int offset = 1;
+ DEBUGpic14_emitcode ("; left and result aren't same","%s %d",__FUNCTION__,__LINE__);
+
+ if (size == 1)
+ {
+ /* left addend is in a register */
+ switch (lit & 0xff)
+ {
+ case 0:
+ emitpcode(POC_MOVFW, popGet(AOP(left),0));
+ emitMOVWF(result,0);
+ break;
+ case 1:
+ emitpcode(POC_INCFW, popGet(AOP(left),0));
+ emitMOVWF(result,0);
+ break;
+ case 0xff:
+ emitpcode(POC_DECFW, popGet(AOP(left),0));
+ emitMOVWF(result,0);
+ break;
+ default:
+ emitpcode(POC_MOVLW, popGetLit(lit & 0xff));
+ emitpcode(POC_ADDFW, popGet(AOP(left),0));
+ emitMOVWF(result,0);
+ } // switch
+ }
+ else
+ {
+ int clear_carry=0;
+
+ /* left is not the accumulator */
+ if (lit & 0xff)
+ {
+ emitpcode(POC_MOVLW, popGetLit(lit & 0xff));
+ emitpcode(POC_ADDFW, popGet(AOP(left),0));
+ }
+ else
+ {
+ emitpcode(POC_MOVFW, popGet(AOP(left),0));
+ /* We don't know the state of the carry bit at this point */
+ clear_carry = 1;
+ } // if
+ 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 */
+
+ emitpcode(POC_MOVLW, popGetLit(lit & 0xff));
+ emitpcode(POC_ADDFW, popGet(AOP(left),offset));
+ emitpcode(POC_MOVWF, popGet(AOP(result),offset));
+
+ clear_carry = 0;
+ }
+ else
+ {
+ emitpcode(POC_MOVLW, popGetLit(lit & 0xff));
+ emitMOVWF(result,offset);
+ emitpcode(POC_MOVFW, popGet(AOP(left),offset));
+ emitSKPNC;
+ emitpcode(POC_INCFSZW,popGet(AOP(left),offset));
+ emitpcode(POC_ADDWF, popGet(AOP(result),offset));
+ } // if
+ }
+ else
+ {
+ emitpcode(POC_CLRF, popGet(AOP(result),offset));
+ emitpcode(POC_RLF, popGet(AOP(result),offset));
+ emitpcode(POC_MOVFW, popGet(AOP(left),offset));
+ emitpcode(POC_ADDWF, popGet(AOP(result),offset));
+ } // if
+ offset++;
+ } // while
+ } // if
+ } // if
+
+out:
+ size = pic14_getDataSize(result);
+ if (size > pic14_getDataSize(left))
+ {
+ size = pic14_getDataSize(left);
+ } // if
+ addSign(result, size, 0);
+}
+
+/*-----------------------------------------------------------------*/
+/* genPlus - generates code for addition */
+/*-----------------------------------------------------------------*/
+void genPlus (iCode *ic)
+{
+ int size, offset = 0;
+
+ /* special cases :- */
+ DEBUGpic14_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
+ FENTRY;
+
+ aopOp (IC_LEFT(ic),ic,FALSE);
+ aopOp (IC_RIGHT(ic),ic,FALSE);
+ aopOp (IC_RESULT(ic),ic,TRUE);
+
+ DEBUGpic14_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 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(ulFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit) != 0L) {
+ emitpcode(POC_MOVLW, popGet(AOP(IC_RESULT(ic)),0));
+ if (!pic14_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) )
+ emitpcode(POC_BTFSC, popGet(AOP(IC_LEFT(ic)),0));
+ emitpcode(POC_XORWF, popGet(AOP(IC_RESULT(ic)),0));
+ }
+ } else {
+ size = pic14_getDataSize(IC_RESULT(ic));
+ while (size--) {
+ MOVA(aopGet(AOP(IC_RIGHT(ic)),offset,FALSE,FALSE));
+ pic14_emitcode("addc","a,#00 ;%d",__LINE__);
+ aopPut(AOP(IC_RESULT(ic)),"a",offset++);
+ }
+ }
+ goto release ;
+ }
+
+ /* if I can do an increment instead
+ of add then GOOD for ME */
+ if (genPlusIncr (ic) == TRUE)
+ goto release;
+
+ size = pic14_getDataSize(IC_RESULT(ic));
+
+ if(AOP(IC_RIGHT(ic))->type == AOP_LIT) {
+ /* Add a literal to something else */
+ unsigned lit = (unsigned) ulFromVal (AOP(IC_RIGHT(ic))->aopu.aop_lit);
+ DEBUGpic14_emitcode(";","adding lit to something. size %d",size);
+
+ genAddLit (ic, lit);
+ goto release;
+
+ } else if(AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
+
+ pic14_emitcode(";bitadd","right is bit: %s",aopGet(AOP(IC_RIGHT(ic)),0,FALSE,FALSE));
+ pic14_emitcode(";bitadd","left is bit: %s",aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE));
+ pic14_emitcode(";bitadd","result is bit: %s",aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE));
+
+ /* here we are adding a bit to a char or int */
+ if(size == 1) {
+ if (pic14_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) {
+ emitpcode(POC_BTFSC , popGet(AOP(IC_RIGHT(ic)),0));
+ emitpcode(POC_INCF , popGet(AOP(IC_RESULT(ic)),0));
+ } else {
+
+ emitpcode(POC_MOVFW , popGet(AOP(IC_LEFT(ic)),0));
+ emitpcode(POC_BTFSC , popGet(AOP(IC_RIGHT(ic)),0));
+ emitpcode(POC_INCFW , popGet(AOP(IC_LEFT(ic)),0));
+
+ if(AOP_TYPE(IC_RESULT(ic)) == AOP_CRY) {
+ emitpcode(POC_ANDLW , popGetLit(1));
+ emitpcode(POC_BCF , popGet(AOP(IC_RESULT(ic)),0));
+ emitSKPZ;
+ emitpcode(POC_BSF , popGet(AOP(IC_RESULT(ic)),0));
+ } else {
+ emitpcode(POC_MOVWF , popGet(AOP(IC_RESULT(ic)),0));
+ }
+ }
+
+ } else {
+ int offset = 1;
+ DEBUGpic14_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
+ if (pic14_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) {
+ emitCLRZ;
+ emitpcode(POC_BTFSC, popGet(AOP(IC_RIGHT(ic)),0));
+ emitpcode(POC_INCF, popGet(AOP(IC_RESULT(ic)),0));
+ } else {
+
+ emitpcode(POC_MOVFW, popGet(AOP(IC_LEFT(ic)),0));
+ emitpcode(POC_BTFSC, popGet(AOP(IC_RIGHT(ic)),0));
+ emitpcode(POC_INCFW, popGet(AOP(IC_LEFT(ic)),0));
+ emitMOVWF(IC_RIGHT(ic),0);
+ }
+
+ while(--size){
+ emitSKPZ;
+ emitpcode(POC_INCF, popGet(AOP(IC_RESULT(ic)),offset++));
+ }
+
+ }
+
+ } else {
+ DEBUGpic14_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
+
+ /* Add the first bytes */
+
+ if(strcmp(aopGet(AOP(IC_LEFT(ic)),0,FALSE,FALSE),"a") == 0 ) {
+ emitpcode(POC_ADDFW, popGet(AOP(IC_RIGHT(ic)),0));
+ emitpcode(POC_MOVWF,popGet(AOP(IC_RESULT(ic)),0));
+ } else {
+
+ emitpcode(POC_MOVFW,popGet(AOP(IC_RIGHT(ic)),0));
+
+ if (pic14_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) )
+ emitpcode(POC_ADDWF, popGet(AOP(IC_LEFT(ic)),0));
+ else {
+ PIC_OPCODE poc = POC_ADDFW;
+
+ if (op_isLitLike (IC_LEFT (ic)))
+ poc = POC_ADDLW;
+ emitpcode(poc, popGetAddr(AOP(IC_LEFT(ic)),0,0));
+ emitpcode(POC_MOVWF,popGet(AOP(IC_RESULT(ic)),0));
+ }
+ }
+
+ size = min( AOP_SIZE(IC_RESULT(ic)), AOP_SIZE(IC_RIGHT(ic))) - 1;
+ offset = 1;
+
+
+ if(size){
+ if (pic14_sameRegs(AOP(IC_RIGHT(ic)), AOP(IC_RESULT(ic)))) {
+ if (op_isLitLike (IC_LEFT(ic)))
+ {
+ while(size--){
+ emitpcode(POC_MOVFW, popGet(AOP(IC_RIGHT(ic)),offset));
+ emitSKPNC;
+ emitpcode(POC_INCFSZW, popGet(AOP(IC_RIGHT(ic)),offset));
+ emitpcode(POC_ADDLW, popGetAddr(AOP(IC_LEFT(ic)),offset,0));
+ emitpcode(POC_MOVWF, popGet(AOP(IC_RESULT(ic)),offset));
+ offset++;
+ }
+ } else {
+ while(size--){
+ emitpcode(POC_MOVFW, popGet(AOP(IC_LEFT(ic)),offset));
+ emitSKPNC;
+ emitpcode(POC_INCFSZW, popGet(AOP(IC_LEFT(ic)),offset));
+ emitpcode(POC_ADDWF, popGet(AOP(IC_RESULT(ic)),offset));
+ offset++;
+ }
+ }
+ } else {
+ PIC_OPCODE poc = POC_MOVFW;
+ if (op_isLitLike (IC_LEFT(ic)))
+ poc = POC_MOVLW;
+ while(size--){
+ if (!pic14_sameRegs(AOP(IC_LEFT(ic)), AOP(IC_RESULT(ic))) ) {
+ emitpcode(poc, popGetAddr(AOP(IC_LEFT(ic)),offset,0));
+ emitpcode(POC_MOVWF, popGet(AOP(IC_RESULT(ic)),offset));
+ }
+ emitpcode(POC_MOVFW, popGet(AOP(IC_RIGHT(ic)),offset));
+ emitSKPNC;
+ emitpcode(POC_INCFSZW, popGet(AOP(IC_RIGHT(ic)),offset));
+ emitpcode(POC_ADDWF, popGet(AOP(IC_RESULT(ic)),offset));
+ 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 */
+ if (AOP_SIZE(IC_LEFT(ic)) > AOP_SIZE(IC_RIGHT(ic))) {
+ int leftsize = AOP_SIZE(IC_LEFT(ic)) - AOP_SIZE(IC_RIGHT(ic));
+ PIC_OPCODE poc = POC_MOVFW;
+ if (op_isLitLike (IC_LEFT(ic)))
+ poc = POC_MOVLW;
+ while(leftsize-- > 0) {
+ emitpcode(poc, popGetAddr(AOP(IC_LEFT(ic)),offset,0));
+ emitSKPNC;
+ emitpcode(POC_ADDLW, popGetLit(0x01));
+ emitpcode(POC_MOVWF, popGet(AOP(IC_RESULT(ic)),offset));
+ //emitSKPNC;
+ //emitpcode(POC_INCF, popGet(AOP(IC_RESULT(ic)),offset)); /* INCF does not update Carry! */
+ offset++;
+ if (size)
+ size--;
+ else
+ break;
+ }
+ } else {
+ emitpcode(POC_CLRF, popGet(AOP(IC_RESULT(ic)),offset));
+ emitpcode(POC_RLF, popGet(AOP(IC_RESULT(ic)),offset));
+ }
+
+
+ if(sign && offset > 0 && offset < AOP_SIZE(IC_RESULT(ic))) {
+ /* Now this is really horrid. Gotta check the sign of the addends and propogate
+ * to the result */
+
+ emitpcode(POC_BTFSC, newpCodeOpBit(aopGet(AOP(IC_LEFT(ic)),offset-1,FALSE,FALSE),7,0));
+ emitpcode(POC_DECF, popGet(AOP(IC_RESULT(ic)),offset));
+ emitpcode(POC_BTFSC, newpCodeOpBit(aopGet(AOP(IC_RIGHT(ic)),offset-1,FALSE,FALSE),7,0));
+ emitpcode(POC_DECF, popGet(AOP(IC_RESULT(ic)),offset));
+
+ /* if chars or ints or being signed extended to longs: */
+ if(size) {
+ emitpcode(POC_MOVLW, popGetLit(0));
+ emitpcode(POC_BTFSC, newpCodeOpBit(aopGet(AOP(IC_RESULT(ic)),offset,FALSE,FALSE),7,0));
+ emitpcode(POC_MOVLW, popGetLit(0xff));
+ }
+ }
+
+ offset++;
+ while(size--) {
+
+ if(sign)
+ emitpcode(POC_MOVWF, popGet(AOP(IC_RESULT(ic)),offset));
+ else
+ emitpcode(POC_CLRF, popGet(AOP(IC_RESULT(ic)),offset));
+
+ offset++;
+ }
+ }
+
+
+ //adjustArithmeticResult(ic);
+
+release:
+ freeAsmop(IC_LEFT(ic),NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
+ freeAsmop(IC_RIGHT(ic),NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
+ freeAsmop(IC_RESULT(ic),NULL,ic,TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* addSign - propogate sign bit to higher bytes */
+/*-----------------------------------------------------------------*/
+void addSign(operand *result, int offset, int sign)
+{
+ int size = (pic14_getDataSize(result) - offset);
+ DEBUGpic14_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
+ FENTRY;
+
+ if(size > 0){
+ if(sign && offset) {
+
+ if(size == 1) {
+ emitpcode(POC_CLRF,popGet(AOP(result),offset));
+ emitpcode(POC_BTFSC,newpCodeOpBit(aopGet(AOP(result),offset-1,FALSE,FALSE),7,0));
+ emitpcode(POC_DECF, popGet(AOP(result),offset));
+ } else {
+
+ emitpcode(POC_MOVLW, popGetLit(0));
+ emitpcode(POC_BTFSC, newpCodeOpBit(aopGet(AOP(result),offset-1,FALSE,FALSE),7,0));
+ emitpcode(POC_MOVLW, popGetLit(0xff));
+ while(size--)
+ emitpcode(POC_MOVWF, popGet(AOP(result),offset+size));
+ }
+ } else
+ while(size--)
+ emitpcode(POC_CLRF,popGet(AOP(result),offset++));
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* genMinus - generates code for subtraction */
+/*-----------------------------------------------------------------*/
+void genMinus (iCode *ic)
+{
+ int size, offset = 0, same=0;
+ unsigned long lit = 0L;
+ int isLit;
+ symbol *lbl_comm, *lbl_next;
+ asmop *left, *right, *result;
+
+ FENTRY;
+ DEBUGpic14_emitcode ("; ***","%s %d",__FUNCTION__,__LINE__);
+ aopOp (IC_LEFT(ic),ic,FALSE);
+ aopOp (IC_RIGHT(ic),ic,FALSE);
+ 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;
+ }
+
+ DEBUGpic14_emitcode ("; ","result %s, left %s, right %s",
+ AopType(AOP_TYPE(IC_RESULT(ic))),
+ AopType(AOP_TYPE(IC_LEFT(ic))),
+ AopType(AOP_TYPE(IC_RIGHT(ic))));
+
+ left = AOP(IC_LEFT(ic));
+ right = AOP(IC_RIGHT(ic));
+ result = AOP(IC_RESULT(ic));
+
+ size = pic14_getDataSize(IC_RESULT(ic));
+ same = pic14_sameRegs(right, result);
+
+ if((AOP_TYPE(IC_LEFT(ic)) != AOP_LIT)
+ && (pic14_getDataSize(IC_LEFT(ic)) < size))
+ {
+ fprintf(stderr, "%s:%d(%s):WARNING: left operand too short for result\n",
+ ic->filename, ic->lineno, __FUNCTION__);
+ } // if
+ if((AOP_TYPE(IC_RIGHT(ic)) != AOP_LIT)
+ && (pic14_getDataSize(IC_RIGHT(ic)) < size))
+ {
+ fprintf(stderr, "%s:%d(%s):WARNING: right operand too short for result\n",
+ ic->filename, ic->lineno, __FUNCTION__ );
+ } // if
+
+ if(AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT) {
+ /* Add a literal to something else */
+
+ lit = ulFromVal(right->aopu.aop_lit);
+ lit = -(long)lit;
+
+ genAddLit(ic, lit);
+
+ } else if(AOP_TYPE(IC_RIGHT(ic)) == AOP_CRY) {
+ // bit subtraction
+
+ pic14_emitcode(";bitsub","right is bit: %s",aopGet(right,0,FALSE,FALSE));
+ pic14_emitcode(";bitsub","left is bit: %s",aopGet(left,0,FALSE,FALSE));
+ pic14_emitcode(";bitsub","result is bit: %s",aopGet(result,0,FALSE,FALSE));
+
+ /* here we are subtracting a bit from a char or int */
+ if(size == 1) {
+ if(pic14_sameRegs(left, result)) {
+
+ emitpcode(POC_BTFSC, popGet(right, 0));
+ emitpcode(POC_DECF , popGet(result, 0));
+
+ } else {
+
+ if( (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD) ||
+ (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) ) {
+ /*
+ * result = literal - bit
+ *
+ * XXX: probably fails for AOP_IMMDs!
+ */
+
+ lit = ulFromVal (left->aopu.aop_lit);
+
+ if(AOP_TYPE(IC_RESULT(ic)) == AOP_CRY) {
+ if(pic14_sameRegs(right, result)) {
+ if(lit & 1) {
+ emitpcode(POC_MOVLW, popGet(right, 0));
+ emitpcode(POC_XORWF, popGet(result, 0));
+ }
+ } else {
+ emitpcode(POC_BCF, popGet(result, 0));
+ if(lit & 1)
+ emitpcode(POC_BTFSS, popGet(right, 0));
+ else
+ emitpcode(POC_BTFSC, popGet(right, 0));
+ emitpcode(POC_BSF, popGet(result, 0));
+ }
+ goto release;
+ } else {
+ emitpcode(POC_MOVLW, popGetLit(lit & 0xff));
+ emitpcode(POC_BTFSC, popGet(right, 0));
+ emitpcode(POC_MOVLW, popGetLit((lit-1) & 0xff));
+ emitpcode(POC_MOVWF, popGet(result, 0));
+ }
+
+ } else {
+ // result = register - bit
+ // XXX: Fails for lit-like left operands
+ emitpcode(POC_MOVFW, popGet(left, 0));
+ emitpcode(POC_BTFSC, popGet(right, 0));
+ emitpcode(POC_DECFW, popGet(left, 0));
+ emitpcode(POC_MOVWF, popGet(result, 0));
+ }
+ }
+ } else {
+ fprintf(stderr, "WARNING: subtracting bit from multi-byte operands is incomplete.\n");
+ //exit(EXIT_FAILURE);
+ } // if
+ } else {
+ /*
+ * RIGHT is not a literal and not a bit operand,
+ * LEFT is unknown (register, literal, bit, ...)
+ */
+ lit = 0;
+ isLit = 0;
+
+ if(AOP_TYPE(IC_LEFT(ic)) == AOP_LIT) {
+ lit = ulFromVal (left->aopu.aop_lit);
+ isLit = 1;
+ DEBUGpic14_emitcode ("; left is lit","line %d result %s, left %s, right %s",__LINE__,
+ AopType(AOP_TYPE(IC_RESULT(ic))),
+ AopType(AOP_TYPE(IC_LEFT(ic))),
+ AopType(AOP_TYPE(IC_RIGHT(ic))));
+ } // if
+
+
+ /*
+ * First byte, no carry-in.
+ * Any optimizations that are longer than 2 instructions are
+ * useless.
+ */
+ if(same && isLit && ((lit & 0xff) == 0xff)) {
+ // right === res = 0xFF - right = ~right
+ emitpcode(POC_COMF, popGet(right, 0));
+ if(size > 1) {
+ // setup CARRY/#BORROW
+ emitSETC;
+ } // if
+ } else if((size == 1) && isLit && ((lit & 0xff) == 0xff)) {
+ // res = 0xFF - right = ~right
+ emitpcode(POC_COMFW, popGet(right, 0));
+ emitpcode(POC_MOVWF, popGet(result, 0));
+ // CARRY/#BORROW is not setup correctly
+ } else if((size == 1) && same && isLit && ((lit & 0xff) == 0)) {
+ // right === res = 0 - right = ~right + 1
+ emitpcode(POC_COMF, popGet(right, 0));
+ emitpcode(POC_INCF, popGet(right, 0));
+ // CARRY/#BORROW is not setup correctly
+ } else {
+ // general case, should always work
+ mov2w(right, 0);
+ if (pic14_sameRegs(left, result)) {
+ // result === left = left - right (in place)
+ emitpcode(POC_SUBWF, popGet(result, 0));
+ } else {
+ // works always: result = left - right
+ emitpcode(op_isLitLike(IC_LEFT(ic))
+ ? POC_SUBLW : POC_SUBFW,
+ popGetAddr(left, 0, 0));
+ emitpcode(POC_MOVWF, popGet(result, 0));
+ } // if
+ } // if
+
+ /*
+ * Now for the remaining bytes with carry-in (and carry-out).
+ */
+ offset = 0;
+ while(--size) {
+ lit >>= 8;
+ offset++;
+
+ /*
+ * The following code generation templates are ordered
+ * according to increasing length; the first template
+ * that matches will thus be the shortest and produce
+ * the best code possible with thees templates.
+ */
+
+ if(pic14_sameRegs(left, right)) {
+ /*
+ * This case should not occur; however, the
+ * template works if LEFT, RIGHT, and RESULT are
+ * register operands and LEFT and RIGHT are the
+ * same register(s) and at least as long as the
+ * result.
+ *
+ * CLRF result
+ *
+ * 1 cycle
+ */
+ emitpcode(POC_CLRF, popGet(result, offset));
+ } else if(pic14_sameRegs(left, result)) {
+ /*
+ * This template works if LEFT, RIGHT, and
+ * RESULT are register operands and LEFT and
+ * RESULT are the same register(s).
+ *
+ * MOVF right, W ; W := right
+ * BTFSS STATUS, C
+ * INCFSZ right, W ; W := right + BORROW
+ * SUBWF result, F ; res === left := left - (right + BORROW)
+ *
+ * The SUBWF *must* be skipped if we have a
+ * BORROW bit and right == 0xFF in order to
+ * keep the BORROW bit intact!
+ *
+ * 4 cycles
+ */
+ mov2w(right, offset);
+ emitSKPC;
+ emitpcode(POC_INCFSZW, popGet(right, offset));
+ emitpcode(POC_SUBWF, popGet(result, offset));
+ } else if((size == 1) && isLit && ((lit & 0xff) == 0xff)) {
+ /*
+ * This template works for the last byte (MSB) of
+ * the subtraction and ignores correct propagation
+ * of the outgoing BORROW bit. RIGHT and RESULT
+ * must be register operands, LEFT must be the
+ * literal 0xFF.
+ *
+ * (The case LEFT === RESULT is optimized above.)
+ *
+ * 0xFF - right - BORROW = ~right - BORROW
+ *
+ * COMF right, W ; W := 0xff - right
+ * BTFSS STATUS, C
+ * ADDLW 0xFF ; W := 0xff - right - BORROW
+ * MOVWF result
+ *
+ * 4 cycles
+ */
+ emitpcode(POC_COMFW, popGet(right, offset));
+ emitSKPC;
+ emitpcode(POC_ADDLW, popGetLit(0xff));
+ emitpcode(POC_MOVWF, popGet(result, offset));
+ } else if(size == 1) {
+ /*
+ * This template works for the last byte (MSB) of
+ * the subtraction and ignores correct propagation
+ * of the outgoing BORROW bit. RIGHT and RESULT
+ * must be register operands, LEFT can be a
+ * register or a literal operand.
+ *
+ * (The case LEFT === RESULT is optimized above.)
+ *
+ * MOVF right, W ; W := right
+ * BTFSS STATUS, C
+ * INCF right, W ; W := right + BORROW
+ * SUBxW left, W ; W := left - right - BORROW
+ * MOVWF result
+ *
+ * 5 cycles
+ */
+ mov2w(right, offset);
+ emitSKPC;
+ emitpcode(POC_INCFW, popGet(right, offset));
+ emitpcode(op_isLitLike(IC_LEFT(ic))
+ ? POC_SUBLW : POC_SUBFW,
+ popGetAddr(left, offset, 0));
+ emitpcode(POC_MOVWF, popGet(result, offset));
+ } else if(IS_ITEMP(IC_RESULT(ic))
+ && !pic14_sameRegs(right, result)) {
+ /*
+ * This code template works if RIGHT and RESULT
+ * are different register operands and RESULT
+ * is not volatile/an SFR (written twice).
+ *
+ * #########################################
+ * Since we cannot determine that for sure,
+ * we approximate via IS_ITEMP() for now.
+ * #########################################
+ *
+ * MOVxW left, W ; copy left to result
+ * MOVWF result
+ * MOVF right, W ; W := right
+ * BTFSS STATUS, C
+ * INCFSZ right, W ; W := right + BORROW
+ * SUBWF result, F ; res === left := left - (right + BORROW)
+ *
+ * 6 cycles, but fails for SFR RESULT operands
+ */
+ mov2w(left, offset);
+ emitpcode(POC_MOVWF, popGet(result, offset));
+ mov2w(right, offset);
+ emitSKPC;
+ emitpcode(POC_INCFSZW, popGet(right, offset));
+ emitpcode(POC_SUBWF, popGet(result, offset));
+ } else if(!optimize.codeSize && isLit && ((lit & 0xff) != 0)) {
+ /*
+ * This template works if RIGHT and RESULT are
+ * register operands and LEFT is a literal
+ * operand != 0.
+ *
+ * MOVxW right, W
+ * BTFSC STATUS, C
+ * GOTO next
+ * SUBLW left-1
+ * GOTO common
+ * next:
+ * SUBLW left
+ * common:
+ * MOVWF result
+ *
+ * 6 cycles, 7 iff BORROW
+ * (9 instructions)
+ */
+ lbl_comm = newiTempLabel(NULL);
+ lbl_next = newiTempLabel(NULL);
+
+ mov2w(right, offset);
+ emitSKPNC;
+ emitpcode(POC_GOTO, popGetLabel(lbl_next->key));
+ emitpcode(POC_SUBLW, popGetLit((lit - 1) & 0xff));
+ emitpcode(POC_GOTO, popGetLabel(lbl_comm->key));
+ emitpLabel(lbl_next->key);
+ emitpcode(POC_SUBLW, popGetLit(lit & 0xff));
+ emitpLabel(lbl_comm->key);
+ emitpcode(POC_MOVWF, popGet(result, offset));
+ } else {
+ /*
+ * This code template works if RIGHT and RESULT
+ * are register operands.
+ *
+ * MOVF right, W ; W := right
+ * BTFSS STATUS, C
+ * INCFSZ right, W ; W := right + BORROW
+ * GOTO common
+ * MOVxW left ; if we subtract 0x100 = 0xFF + 1, ...
+ * GOTO next ; res := left, but keep BORROW intact
+ * common:
+ * SUBxW left, W ; W := left - (right + BORROW)
+ * next:
+ * MOVW result ; res := left - (right + BORROW)
+ *
+ * 7 cycles, 8 iff BORROW and (right == 0xFF)
+ * (8 instructions)
+ *
+ *
+ *
+ * Alternative approach using -x = ~x + 1 ==> ~x = -x - 1 = -(x + 1)
+ *
+ * COMFW right, W ; W := -right - (assumed BORROW)
+ * BTFSC STATUS, C ; SKIP if we have a BORROW
+ * ADDLW 1 ; W := -right (no BORROW)
+ * BTFSC STATUS, C ; (***)
+ * MOVLW left ; (***)
+ * BTFSS STATUS, C ; (***)
+ * ADDFW left, W ; W := left - right - BORROW (if any)
+ * MOVWF result ; result := left - right - BORROW (if any)
+ *
+ * 8 cycles
+ *
+ * Case A: C=0 (BORROW)
+ * r=0x00, W=0xFF, W=left+0xFF, C iff left>0x00
+ * r=0x01, W=0xFE, W=left+0xFE, C iff left>0x01
+ * r=0xFE, W=0x01, W=left+0x01, C iff left>0xFE
+ * r=0xFF, W=0x00, W=left+0x00, C iff left>0xFF
+ *
+ * Case B: C=1 (no BORROW)
+ * r=0x00, W=0xFF, W=0x00/C=1, W=left+0x00, C iff left>=0x100 (***)
+ * r=0x01, W=0xFE, W=0xFF/C=0, W=left+0xFF, C iff left>=0x01
+ * r=0xFE, W=0x01, W=0x02/C=0, W=left+0x02, C iff left>=0xFE
+ * r=0xFF, W=0x00, W=0x01/C=0, W=left+0x01, C iff left>=0xFF
+ */
+ lbl_comm = newiTempLabel(NULL);
+ lbl_next = newiTempLabel(NULL);
+
+ mov2w(right, offset);
+ emitSKPC;
+ emitpcode(POC_INCFSZW, popGet(right, offset));
+ emitpcode(POC_GOTO, popGetLabel(lbl_comm->key));
+ mov2w(left, offset);
+ emitpcode(POC_GOTO, popGetLabel(lbl_next->key));
+ emitpLabel(lbl_comm->key);
+ emitpcode(op_isLitLike(IC_LEFT(ic))
+ ? POC_SUBLW : POC_SUBFW,
+ popGetAddr(left, offset, 0));
+ emitpLabel(lbl_next->key);
+ emitpcode(POC_MOVWF, popGet(result, offset));
+ } // if
+ } // while
+ } // if
+
+ if(AOP_TYPE(IC_RESULT(ic)) == AOP_CRY) {
+ fprintf(stderr, "WARNING: AOP_CRY (bit-) results are probably broken. Please report this with source code as a bug.\n");
+ mov2w(result, 0); // load Z flag
+ emitpcode(POC_BCF, popGet(result, 0));
+ emitSKPZ;
+ emitpcode(POC_BSF, popGet(result, 0));
+ } // if
+
+ // adjustArithmeticResult(ic);
+
+release:
+ freeAsmop(IC_LEFT(ic),NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
+ freeAsmop(IC_RIGHT(ic),NULL,ic,(RESULTONSTACK(ic) ? FALSE : TRUE));
+ freeAsmop(IC_RESULT(ic),NULL,ic,TRUE);
+}
+
diff --git a/src/pic14/glue.c b/src/pic14/glue.c
new file mode 100644
index 0000000..ee266e9
--- /dev/null
+++ b/src/pic14/glue.c
@@ -0,0 +1,1206 @@
+/*-------------------------------------------------------------------------
+
+ glue.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 "glue.h"
+#include "dbuf_string.h"
+
+#include "device.h"
+#include "gen.h"
+#include "main.h"
+
+/*
+ * Imports
+ */
+extern set *publics;
+extern set *externs;
+extern symbol *mainf;
+extern struct dbuf_s *codeOutBuf;
+
+extern void initialComments (FILE *afile);
+extern operand *operandFromAst (ast *tree, int lvl);
+extern value *initPointer (initList *ilist, sym_link *toType);
+
+
+set *pic14_localFunctions = NULL;
+int pic14_hasInterrupt = 0; // Indicates whether to emit interrupt handler or not
+
+int pic14_stringInSet(const char *str, set **world, int autoAdd);
+
+
+#ifdef WORDS_BIGENDIAN
+#define _ENDIAN(x) (3-x)
+#else
+#define _ENDIAN(x) (x)
+#endif
+
+#define BYTE_IN_LONG(x,b) ((x>>(8*_ENDIAN(b)))&0xff)
+#define IS_GLOBAL(sym) ((sym)->level == 0)
+#define IS_DEFINED_HERE(sym) (!IS_EXTERN(sym->etype))
+
+/* dbufs for initialized data (idata and code sections),
+ * extern, and global declarations */
+static struct dbuf_s *ivalBuf, *extBuf, *gloBuf, *gloDefBuf;
+
+static set *emitted = NULL;
+
+static void showAllMemmaps (FILE *of); // XXX: emits initialized symbols
+
+static void
+emitPseudoStack(struct dbuf_s *oBuf, struct dbuf_s *oBufExt)
+{
+ int shared, low, high, size, i;
+ PIC_device *pic = pic14_getPIC();
+
+ /* also emit STK symbols
+ * XXX: This is ugly and fails as soon as devices start to get
+ * differently sized sharebanks, since STK12 will be
+ * required by larger devices but only up to STK03 might
+ * be defined using smaller devices. */
+ shared = pic14_getSharedStack(&low, &high, &size);
+ if (!pic14_options.isLibrarySource)
+ {
+ dbuf_printf (oBuf, "\n");
+ if (!pic->isEnhancedCore) {
+ size -= 3;
+ dbuf_printf (oBuf, "\tglobal PSAVE\n");
+ dbuf_printf (oBuf, "\tglobal SSAVE\n");
+ dbuf_printf (oBuf, "\tglobal WSAVE\n");
+ }
+ for (i = size - 1; i >= 0; i--) {
+ dbuf_printf (oBuf, "\tglobal STK%02d\n", i);
+ } // for i
+ dbuf_printf (oBuf, "\n");
+
+ // 16f84 has no SHAREBANK (in linkerscript) but memory aliased in two
+ // banks, sigh...
+ if (1 || !shared) {
+ // for single banked devices: use normal, "banked" RAM
+ dbuf_printf (oBuf, "sharebank udata_ovr 0x%04X\n", low);
+ } else {
+ // for devices with at least two banks, require a sharebank section
+ dbuf_printf (oBuf, "sharebank udata_shr\n");
+ }
+ if (!pic->isEnhancedCore) {
+ dbuf_printf (oBuf, "PSAVE\tres 1\n");
+ dbuf_printf (oBuf, "SSAVE\tres 1\n");
+ dbuf_printf (oBuf, "WSAVE\tres 1\n"); // WSAVE *must* be in sharebank (IRQ handlers)
+ }
+ /* fill rest of sharebank with stack STKxx .. STK00 */
+ for (i = size - 1; i >= 0; i--) {
+ dbuf_printf (oBuf, "STK%02d\tres 1\n", i);
+ } // for i
+ } else {
+ /* declare STKxx as extern for all files
+ * except the one containing main() */
+ dbuf_printf (oBufExt, "\n");
+ if (!pic->isEnhancedCore) {
+ size -= 3;
+ dbuf_printf (oBufExt, "\textern PSAVE\n");
+ dbuf_printf (oBufExt, "\textern SSAVE\n");
+ dbuf_printf (oBufExt, "\textern WSAVE\n");
+ }
+ for (i = size - 1; i >= 0; i--) {
+ char buffer[128];
+ SNPRINTF(&buffer[0], 127, "STK%02d", i);
+ dbuf_printf (oBufExt, "\textern %s\n", &buffer[0]);
+ pic14_stringInSet(&buffer[0], &emitted, 1);
+ } // for i
+ }
+ dbuf_printf (oBuf, "\n");
+}
+
+static int
+emitIfNew(struct dbuf_s *oBuf, set **emitted, const char *fmt,
+ const char *name)
+{
+ int wasPresent = pic14_stringInSet(name, emitted, 1);
+
+ if (!wasPresent) {
+ dbuf_printf (oBuf, fmt, name);
+ } // if
+ return (!wasPresent);
+}
+
+static void
+pic14_constructAbsMap (struct dbuf_s *oBuf, struct dbuf_s *gloBuf)
+{
+ memmap *maps[] = { data, sfr, NULL };
+ int i;
+ hTab *ht = NULL;
+ symbol *sym;
+ set *aliases;
+ int addr, min=-1, max=-1;
+ unsigned int size;
+
+ for (i=0; maps[i] != NULL; i++)
+ {
+ for (sym = (symbol *)setFirstItem (maps[i]->syms); sym; sym = setNextItem (maps[i]->syms))
+ {
+ if (IS_DEFINED_HERE(sym) && SPEC_ABSA(sym->etype))
+ {
+ addr = SPEC_ADDR(sym->etype);
+
+ /* handle CONFIG words here */
+ if (IS_CONFIG_ADDRESS( addr ))
+ {
+ //fprintf( stderr, "%s: assignment to CONFIG@0x%x found\n", __FUNCTION__, addr );
+ //fprintf( stderr, "ival: %p (0x%x)\n", sym->ival, (int)list2int( sym->ival ) );
+ if (sym->ival) {
+ pic14_assignConfigWordValue( addr, (int)list2int( sym->ival ) );
+ } else {
+ fprintf( stderr, "ERROR: Symbol %s, which is covering a __CONFIG word must be initialized!\n", sym->name );
+ }
+ continue;
+ }
+
+ if (max == -1 || addr > max) max = addr;
+ if (min == -1 || addr < min) min = addr;
+ //fprintf (stderr, "%s: sym %s @ 0x%x\n", __FUNCTION__, sym->name, addr);
+ aliases = hTabItemWithKey (ht, addr);
+ if (aliases) {
+ /* May not use addSetHead, as we cannot update the
+ * list's head in the hastable `ht'. */
+ addSet (&aliases, sym);
+#if 0
+ fprintf( stderr, "%s: now %d aliases for %s @ 0x%x\n",
+ __FUNCTION__, elementsInSet(aliases), sym->name, addr);
+#endif
+ } else {
+ addSet (&aliases, sym);
+ hTabAddItem (&ht, addr, aliases);
+ } // if
+ } // if
+ } // for sym
+ } // for i
+
+ /* now emit definitions for all absolute symbols */
+ dbuf_printf (oBuf, "%s", iComments2);
+ dbuf_printf (oBuf, "; absolute symbol definitions\n");
+ dbuf_printf (oBuf, "%s", iComments2);
+ for (addr=min; addr <= max; addr++)
+ {
+ size = 1;
+ aliases = hTabItemWithKey (ht, addr);
+ if (aliases && elementsInSet(aliases)) {
+ /* Make sure there is no initialized value at this location! */
+ for (sym = setFirstItem(aliases); sym; sym = setNextItem(aliases)) {
+ if (sym->ival) break;
+ } // for
+ if (sym) continue;
+
+ dbuf_printf (oBuf, "UD_abs_%s_%x\tudata_ovr\t0x%04x\n",
+ moduleName, addr, addr);
+ for (sym = setFirstItem (aliases); sym; sym = setNextItem (aliases)) {
+ if (getSize(sym->type) > size) {
+ size = getSize(sym->type);
+ }
+
+ /* initialized values are handled somewhere else */
+ if (sym->ival) continue;
+
+ /* emit STATUS as well as _STATUS, required for SFRs only */
+ //dbuf_printf (oBuf, "%s\tres\t0\n", sym->name);
+ dbuf_printf (oBuf, "%s\n", sym->rname);
+
+ if (IS_GLOBAL(sym) && !IS_STATIC(sym->etype)) {
+ //emitIfNew(gloBuf, &emitted, "\tglobal\t%s\n", sym->name);
+ emitIfNew(gloBuf, &emitted, "\tglobal\t%s\n", sym->rname);
+ } // if
+ } // for
+ dbuf_printf (oBuf, "\tres\t%d\n", size);
+ } // if
+ } // for i
+}
+
+/*-----------------------------------------------------------------*/
+/* createInterruptVect - creates the interrupt vector */
+/*-----------------------------------------------------------------*/
+static void
+pic14createInterruptVect (struct dbuf_s * vBuf)
+{
+ mainf = newSymbol ("main", 0);
+ mainf->block = 0;
+
+ /* only if the main function exists */
+ if (!(mainf = findSymWithLevel (SymbolTab, mainf)))
+ {
+ struct options *op = &options;
+ if (!(op->cc_only || noAssemble))
+ // werror (E_NO_MAIN);
+ fprintf(stderr,"WARNING: function 'main' undefined\n");
+ 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 || noAssemble))
+ // werror (E_NO_MAIN);
+ fprintf(stderr,"WARNING: function 'main' undefined\n");
+ return;
+ }
+
+ dbuf_printf (vBuf, "%s", iComments2);
+ dbuf_printf (vBuf, "; reset vector \n");
+ dbuf_printf (vBuf, "%s", iComments2);
+ // Lkr file should place section STARTUP at address 0x0, but does not ...
+ dbuf_printf (vBuf, "STARTUP\t%s 0x0000\n", CODE_NAME);
+ dbuf_printf (vBuf, "\tnop\n"); /* first location for used by incircuit debugger */
+ dbuf_printf (vBuf, "\tpagesel __sdcc_gsinit_startup\n");
+ dbuf_printf (vBuf, "\tgoto\t__sdcc_gsinit_startup\n");
+ popGetExternal("__sdcc_gsinit_startup", 0);
+}
+
+
+/*-----------------------------------------------------------------*/
+/* initialComments - puts in some initial comments */
+/*-----------------------------------------------------------------*/
+static void
+pic14initialComments (FILE * afile)
+{
+ initialComments (afile);
+ fprintf (afile, "; PIC port for the 14-bit core\n");
+ fprintf (afile, "%s", iComments2);
+}
+
+int
+pic14_stringInSet(const char *str, set **world, int autoAdd)
+{
+ char *s;
+
+ if (!str) return TRUE;
+ assert(world);
+
+ for (s = setFirstItem(*world); s; s = setNextItem(*world))
+ {
+ /* found in set */
+ if (0 == strcmp(s, str)) return TRUE;
+ }
+
+ /* not found */
+ if (autoAdd) addSet(world, Safe_strdup(str));
+ return FALSE;
+}
+
+static void
+pic14printLocals (struct dbuf_s *oBuf)
+{
+ set *allregs[6] = { dynAllocRegs/*, dynStackRegs, dynProcessorRegs*/,
+ dynDirectRegs, dynDirectBitRegs/*, dynInternalRegs */ };
+ reg_info *reg;
+ int i, is_first = TRUE;
+ static unsigned sectionNr = 0;
+ const char *split_locals;
+
+ split_locals = getenv("SDCC_PIC14_SPLIT_LOCALS");
+
+ /* emit all registers from all possible sets */
+ for (i = 0; i < 6; i++) {
+ if (allregs[i] == NULL) continue;
+
+ for (reg = setFirstItem(allregs[i]); reg; reg = setNextItem(allregs[i])) {
+ if (reg->isEmitted) continue;
+
+ if (reg->wasUsed && !reg->isExtern) {
+ if (!pic14_stringInSet(reg->name, &emitted, TRUE)) {
+ if (reg->isFixed) {
+ // Should not happen, really...
+ assert ( !"Compiler-assigned variables should not be pinned... This is a bug." );
+ dbuf_printf(oBuf, "UDL_%s_%u\tudata\t0x%04X\n%s\tres\t%d\n",
+ moduleName, sectionNr++, reg->address, reg->name, reg->size);
+ } else {
+ if (split_locals != NULL) {
+ // assign each local register into its own section
+ dbuf_printf(oBuf, "UDL_%s_%u\tudata\n%s\tres\t%d\n",
+ moduleName, sectionNr++, reg->name, reg->size);
+ } else {
+ // group all local registers into a single section
+ // This should greatly improve BANKSEL generation...
+ if (is_first) {
+ dbuf_printf(oBuf, "UDL_%s_%u\tudata\n", moduleName, sectionNr++);
+ is_first = FALSE;
+ }
+ dbuf_printf(oBuf, "%s\tres\t%d\n", reg->name, reg->size);
+ }
+ }
+ }
+ }
+ reg->isEmitted = TRUE;
+ } // for
+ } // for
+}
+
+/*-----------------------------------------------------------------*/
+/* emitOverlay - will emit code for the overlay stuff */
+/*-----------------------------------------------------------------*/
+static void
+pic14emitOverlay (struct dbuf_s * aBuf)
+{
+ set *ovrset;
+
+ /* if (!elementsInSet (ovrSetSets))*/
+
+ /* the hack below, fixes translates for devices which
+ * only have udata_shr memory */
+ dbuf_printf (aBuf, "%s\t%s\n",
+ (elementsInSet(ovrSetSets)?"":";"),
+ 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 */
+
+ /* I don't think this applies to us. We are using gpasm. CRF */
+
+ dbuf_printf (aBuf, ";\t.area _DUMMY\n");
+ /* output the area informtion */
+ dbuf_printf (aBuf, ";\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)
+ {
+ if (!sym->level)
+ { /* global */
+ if (IS_STATIC (sym->etype))
+ dbuf_printf (aBuf, "F%s_", moduleName); /* scope is file */
+ else
+ dbuf_printf (aBuf, "G_"); /* scope is global */
+ }
+ else
+ /* symbol is local */
+ dbuf_printf (aBuf, "L%s_",
+ (sym->localof ? sym->localof->name : "-null-"));
+ dbuf_printf (aBuf, "%s_%ld_%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)
+ dbuf_printf (aBuf, " == 0x%04x\n", SPEC_ADDR (sym->etype));
+
+ dbuf_printf (aBuf, "%s\t=\t0x%04x\n",
+ sym->rname,
+ SPEC_ADDR (sym->etype));
+ }
+ else
+ {
+ if (options.debug || sym->level == 0)
+ dbuf_printf (aBuf, "==.\n");
+
+ /* allocate space */
+ dbuf_printf (aBuf, "%s:\n", sym->rname);
+ dbuf_printf (aBuf, "\t.ds\t0x%04x\n", (unsigned int) getSize (sym->type) & 0xffff);
+ }
+
+ }
+ }
+}
+
+
+static void
+pic14_emitInterruptHandler (FILE * asmFile)
+{
+ if (pic14_hasInterrupt)
+ {
+ fprintf (asmFile, "%s", iComments2);
+ fprintf (asmFile, "; interrupt and initialization code\n");
+ fprintf (asmFile, "%s", iComments2);
+ // Note - for mplink may have to enlarge section vectors in .lnk file
+ // Note: Do NOT name this code_interrupt to avoid nameclashes with
+ // source files's code segment (interrupt.c -> code_interrupt)
+ fprintf (asmFile, "c_interrupt\t%s\t0x0004\n", CODE_NAME);
+
+ /* interrupt service routine */
+ fprintf (asmFile, "__sdcc_interrupt:\n");
+ copypCode(asmFile, 'I');
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* glue - the final glue that hold the whole thing together */
+/*-----------------------------------------------------------------*/
+void
+picglue (void)
+{
+ FILE *asmFile;
+ struct dbuf_s ovrBuf;
+ struct dbuf_s vBuf;
+
+ dbuf_init(&ovrBuf, 4096);
+ dbuf_init(&vBuf, 4096);
+
+ pCodeInitRegisters();
+
+ /* check for main() */
+ mainf = newSymbol ("main", 0);
+ mainf->block = 0;
+ mainf = findSymWithLevel (SymbolTab, mainf);
+
+ if (!mainf || !IFFUNC_HASBODY(mainf->type))
+ {
+ /* main missing -- import stack from main module */
+ //fprintf (stderr, "main() missing -- assuming we are NOT the main module\n");
+ pic14_options.isLibrarySource = TRUE;
+ }
+
+ /* 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 */
+
+ movepBlock2Head('P'); // Last
+ movepBlock2Head(code->dbName);
+ movepBlock2Head('X');
+ movepBlock2Head(statsg->dbName); // First
+
+
+ /* print the global struct definitions */
+ if (options.debug)
+ cdbStructBlock (0);
+
+ /* do the overlay segments */
+ pic14emitOverlay(&ovrBuf);
+
+ /* PENDING: this isnt the best place but it will do */
+ if (port->general.glue_up_main) {
+ /* create the interrupt vector table */
+ pic14createInterruptVect (&vBuf);
+ }
+
+ AnalyzepCode('*');
+
+ ReuseReg(); // ReuseReg where call tree permits
+
+ InlinepCode();
+
+ AnalyzepCode('*');
+
+ if (options.debug) pcode_test();
+
+
+ /* now put it all together into the assembler file */
+ /* create the assembler file name */
+
+ if ((noAssemble || options.c1mode) && fullDstFileName)
+ {
+ SNPRINTF(buffer, sizeof(buffer), "%s", fullDstFileName);
+ }
+ else
+ {
+ SNPRINTF(buffer, sizeof(buffer), "%s.asm", dstFileName);
+ }
+
+ if (!(asmFile = fopen (buffer, "w"))) {
+ werror (E_FILE_OPEN_ERR, buffer);
+ exit (1);
+ }
+
+ /* prepare statistics */
+ resetpCodeStatistics ();
+
+ /* initial comments */
+ pic14initialComments (asmFile);
+
+ /* print module name */
+ fprintf (asmFile, "%s\t.file\t\"%s\"\n",
+ options.debug ? "" : ";", fullSrcFileName);
+
+ /* Let the port generate any global directives, etc. */
+ if (port->genAssemblerPreamble)
+ {
+ port->genAssemblerPreamble(asmFile);
+ }
+
+ /* Put all variables into a cblock */
+ AnalyzeBanking();
+
+ /* emit initialized data */
+ showAllMemmaps(asmFile);
+
+ /* print the locally defined variables in this module */
+ writeUsedRegs(asmFile);
+
+ /* create the overlay segments */
+ fprintf (asmFile, "%s", iComments2);
+ fprintf (asmFile, "; overlayable items in internal ram \n");
+ fprintf (asmFile, "%s", iComments2);
+ dbuf_write_and_destroy (&ovrBuf, asmFile);
+
+ /* copy the interrupt vector table */
+ if (mainf && IFFUNC_HASBODY(mainf->type))
+ dbuf_write_and_destroy (&vBuf, asmFile);
+ else
+ dbuf_destroy(&vBuf);
+
+ /* create interupt vector handler */
+ pic14_emitInterruptHandler (asmFile);
+
+ /* copy over code */
+ fprintf (asmFile, "%s", iComments2);
+ fprintf (asmFile, "; code\n");
+ fprintf (asmFile, "%s", iComments2);
+ fprintf (asmFile, "code_%s\t%s\n", moduleName, port->mem.code_name);
+
+ /* unknown */
+ copypCode(asmFile, 'X');
+
+ /* _main function */
+ copypCode(asmFile, 'M');
+
+ /* other functions */
+ copypCode(asmFile, code->dbName);
+
+ /* unknown */
+ copypCode(asmFile, 'P');
+
+ dumppCodeStatistics (asmFile);
+
+ fprintf (asmFile,"\tend\n");
+
+ fclose (asmFile);
+ pic14_debugLogClose();
+}
+
+/*
+ * Deal with initializers.
+ */
+#undef DEBUGprintf
+#if 0
+// debugging output
+#define DEBUGprintf printf
+#else
+// be quiet
+#define DEBUGprintf 1 ? (void)0 : (void)printf
+#endif
+
+static char *
+parseIvalAst (ast *node, int *inCodeSpace) {
+#define LEN 4096
+ char *buffer = NULL;
+ char *left, *right;
+
+ if (IS_AST_VALUE(node)) {
+ value *val = AST_VALUE(node);
+ symbol *sym = IS_AST_SYM_VALUE(node) ? AST_SYMBOL(node) : NULL;
+ if (inCodeSpace && val->type
+ && (IS_FUNC(val->type) || IS_CODE(getSpec(val->type))))
+ {
+ *inCodeSpace = TRUE;
+ }
+ if (inCodeSpace && sym
+ && (IS_FUNC(sym->type)
+ || IS_CODE(getSpec(sym->type))))
+ {
+ *inCodeSpace = TRUE;
+ }
+
+ DEBUGprintf ("%s: AST_VALUE\n", __FUNCTION__);
+ if (IS_AST_LIT_VALUE(node)) {
+ buffer = Safe_alloc(LEN);
+ SNPRINTF(buffer, LEN, "0x%lx", AST_ULONG_VALUE (node));
+ } else if (IS_AST_SYM_VALUE(node)) {
+ assert ( AST_SYMBOL(node) );
+ /*
+ printf ("sym %s: ", AST_SYMBOL(node)->rname);
+ printTypeChain(AST_SYMBOL(node)->type, stdout);
+ printTypeChain(AST_SYMBOL(node)->etype, stdout);
+ printf ("\n---sym %s: done\n", AST_SYMBOL(node)->rname);
+ */
+ buffer = Safe_strdup(AST_SYMBOL(node)->rname);
+ } else {
+ assert ( !"Invalid values type for initializers in AST." );
+ }
+ } else if (IS_AST_OP(node)) {
+ DEBUGprintf ("%s: AST_OP\n", __FUNCTION__);
+ switch (node->opval.op) {
+ case CAST:
+ assert (node->right);
+ buffer = parseIvalAst(node->right, inCodeSpace);
+ DEBUGprintf ("%s: %s\n", __FUNCTION__, buffer);
+ break;
+ case '&':
+ assert ( node->left && !node->right );
+ buffer = parseIvalAst(node->left, inCodeSpace);
+ DEBUGprintf ("%s: %s\n", __FUNCTION__, buffer);
+ break;
+ case '+':
+ assert (node->left && node->right );
+ left = parseIvalAst(node->left, inCodeSpace);
+ right = parseIvalAst(node->right, inCodeSpace);
+ buffer = Safe_alloc(LEN);
+ SNPRINTF(buffer, LEN, "(%s + %s)", left, right);
+ DEBUGprintf ("%s: %s\n", __FUNCTION__, buffer);
+ Safe_free(left);
+ Safe_free(right);
+ break;
+ case '[':
+ assert ( node->left && node->right );
+ assert ( IS_AST_VALUE(node->left) && AST_VALUE(node->left)->sym );
+ right = parseIvalAst(node->right, inCodeSpace);
+ buffer = Safe_alloc(LEN);
+ SNPRINTF(buffer, LEN, "(%s + %u * %s)",
+ AST_VALUE(node->left)->sym->rname, getSize(AST_VALUE(node->left)->type), right);
+ Safe_free(right);
+ DEBUGprintf ("%s: %s\n", __FUNCTION__, &buffer[0]);
+ break;
+ default:
+ assert ( !"Unhandled operation in initializer." );
+ break;
+ }
+ } else {
+ assert ( !"Invalid construct in initializer." );
+ }
+
+ return (buffer);
+}
+
+/*
+ * Emit the section preamble, absolute location (if any) and
+ * symbol name(s) for intialized data.
+ */
+static int
+emitIvalLabel(struct dbuf_s *oBuf, symbol *sym)
+{
+ char *segname;
+ static int in_code = FALSE;
+ static int sectionNr = 0;
+
+ if (sym) {
+ // code or data space?
+ if (IS_CODE(getSpec(sym->type))) {
+ segname = "code";
+ in_code = TRUE;
+ } else {
+ segname = "idata";
+ in_code = FALSE;
+ }
+ dbuf_printf(oBuf, "\nID_%s_%d\t%s", moduleName, sectionNr++, segname);
+ if (SPEC_ABSA(getSpec(sym->type))) {
+ // specify address for absolute symbols
+ dbuf_printf(oBuf, "\t0x%04X", SPEC_ADDR(getSpec(sym->type)));
+ } // if
+ dbuf_printf(oBuf, "\n%s\n", sym->rname);
+
+ addSet(&emitted, sym->rname);
+ }
+ return (in_code);
+}
+
+/*
+ * Actually emit the initial values in .asm format.
+ */
+static void
+emitIvals(struct dbuf_s *oBuf, symbol *sym, initList *list, long lit, int size)
+{
+ int i;
+ ast *node;
+ operand *op;
+ value *val = NULL;
+ int inCodeSpace = FALSE;
+ char *str = NULL;
+ int in_code;
+
+ assert (size <= sizeof(long));
+ assert (!list || (list->type == INIT_NODE));
+ node = list ? list->init.node : NULL;
+
+ in_code = emitIvalLabel(oBuf, sym);
+ if (!in_code)
+ dbuf_printf (oBuf, "\tdb\t");
+
+ if (!node) {
+ for (i = 0; i < size; i++) {
+ if (in_code) {
+ dbuf_printf (oBuf, "\tretlw 0x%02x\n", (int)(lit & 0xff));
+ // dbuf_printf (oBuf, "\tretlw 0x00\n"); // conflict from merge of sf-patch-2991122 ?
+ } else {
+ dbuf_printf (oBuf, "%s0x%02x", (i == 0) ? "" : ", ", (int)(lit & 0xff));
+ }
+ lit >>= 8;
+ } // for
+ if (!in_code)
+ dbuf_printf (oBuf, "\n");
+ return;
+ } // if
+
+ op = NULL;
+ if (constExprTree(node) && (val = constExprValue(node, 0))) {
+ op = operandFromValue(val);
+ DEBUGprintf ("%s: constExpr ", __FUNCTION__);
+ } else if (IS_AST_VALUE(node)) {
+ op = operandFromAst(node, 0);
+ } else if (IS_AST_OP(node)) {
+ str = parseIvalAst(node, &inCodeSpace);
+ DEBUGprintf("%s: AST_OP: %s\n", __FUNCTION__, str);
+ op = NULL;
+ } else {
+ assert ( !"Unhandled construct in intializer." );
+ }
+
+ if (op) {
+ aopOp(op, NULL, 1);
+ assert(AOP(op));
+ //printOperand(op, of);
+ }
+
+ for (i = 0; i < size; i++) {
+ char *text;
+
+ /*
+ * FIXME: This is hacky and needs some more thought.
+ */
+ if (op && IS_SYMOP(op) && IS_FUNC(OP_SYM_TYPE(op))) {
+ /* This branch is introduced to fix #1427663. */
+ PCOI(AOP(op)->aopu.pcop)->offset+=i;
+ text = get_op(AOP(op)->aopu.pcop, NULL, 0);
+ PCOI(AOP(op)->aopu.pcop)->offset-=i;
+ } else {
+ text = op ? aopGet(AOP(op), i, 0, 0)
+ : get_op(newpCodeOpImmd(str, i, 0, inCodeSpace, 0), NULL, 0);
+ } // if
+ if (in_code) {
+ dbuf_printf (oBuf, "\tretlw %s\n", text);
+ } else {
+ dbuf_printf (oBuf, "%s%s", (i == 0) ? "" : ", ", text);
+ }
+ } // for
+ if (!in_code)
+ dbuf_printf (oBuf, "\n");
+}
+
+/*
+ * For UNIONs, we first have to find the correct alternative to map the
+ * initializer to. This function maps the structure of the initializer to
+ * the UNION members recursively.
+ * Returns the type of the first `fitting' member.
+ */
+static sym_link *
+matchIvalToUnion (initList *list, sym_link *type, int size)
+{
+ symbol *sym;
+
+ assert (type);
+
+ if (IS_PTR(type) || IS_CHAR(type) || IS_INT(type) || IS_LONG(type)
+ || IS_FLOAT(type))
+ {
+ if (!list || (list->type == INIT_NODE)) {
+ DEBUGprintf ("OK, simple type\n");
+ return (type);
+ } else {
+ DEBUGprintf ("ERROR, simple type\n");
+ return (NULL);
+ }
+ } else if (IS_BITFIELD(type)) {
+ if (!list || (list->type == INIT_NODE)) {
+ DEBUGprintf ("OK, bitfield\n");
+ return (type);
+ } else {
+ DEBUGprintf ("ERROR, bitfield\n");
+ return (NULL);
+ }
+ } else if (IS_STRUCT(type) && SPEC_STRUCT(getSpec(type))->type == STRUCT) {
+ if (!list || (list->type == INIT_DEEP)) {
+ if (list) list = list->init.deep;
+ sym = SPEC_STRUCT(type)->fields;
+ while (sym) {
+ DEBUGprintf ("Checking STRUCT member %s\n", sym->name);
+ if (!matchIvalToUnion(list, sym->type, 0)) {
+ DEBUGprintf ("ERROR, STRUCT member %s\n", sym->name);
+ return (NULL);
+ }
+ if (list) list = list->next;
+ sym = sym->next;
+ } // while
+
+ // excess initializers?
+ if (list) {
+ DEBUGprintf ("ERROR, excess initializers\n");
+ return (NULL);
+ }
+
+ DEBUGprintf ("OK, struct\n");
+ return (type);
+ }
+ return (NULL);
+ } else if (IS_STRUCT(type) && SPEC_STRUCT(getSpec(type))->type == UNION) {
+ if (!list || (list->type == INIT_DEEP)) {
+ if (list) list = list->init.deep;
+ sym = SPEC_STRUCT(type)->fields;
+ while (sym) {
+ while (list && list->type == INIT_HOLE) {
+ list = list->next;
+ sym = sym->next;
+ }
+ DEBUGprintf ("Checking UNION member %s.\n", sym->name);
+ if (((IS_STRUCT(sym->type) || getSize(sym->type) == size))
+ && matchIvalToUnion(list, sym->type, size))
+ {
+ DEBUGprintf ("Matched UNION member %s.\n", sym->name);
+ return (sym->type);
+ }
+ sym = sym->next;
+ } // while
+ } // if
+ // no match found
+ DEBUGprintf ("ERROR, no match found.\n");
+ return (NULL);
+ } else {
+ assert ( !"Unhandled type in UNION." );
+ }
+
+ assert ( !"No match found in UNION for the given initializer structure." );
+ return (NULL);
+}
+
+/*
+ * Parse the type and its initializer and emit it (recursively).
+ */
+static void
+emitInitVal(struct dbuf_s *oBuf, symbol *topsym, sym_link *my_type, initList *list)
+{
+ symbol *sym;
+ int size;
+ long lit;
+ unsigned char *str;
+
+ /* Handle designated initializers */
+ if (list)
+ list = reorderIlist (my_type, list);
+
+ /* If this is a hole, substitute an appropriate initializer. */
+ if (list && list->type == INIT_HOLE)
+ {
+ if (IS_AGGREGATE (my_type))
+ {
+ list = newiList(INIT_DEEP, NULL); /* init w/ {} */
+ }
+ else
+ {
+ ast *ast = newAst_VALUE (constVal("0"));
+ ast = decorateType (ast, RESULT_TYPE_NONE);
+ list = newiList(INIT_NODE, ast);
+ }
+ }
+
+ size = getSize(my_type);
+
+ if (IS_PTR(my_type)) {
+ DEBUGprintf ("(pointer, %d byte) 0x%x\n", size, list ? (unsigned int)list2int(list) : 0);
+ emitIvals(oBuf, topsym, list, 0, size);
+ return;
+ }
+
+ if (IS_ARRAY(my_type) && topsym && topsym->isstrlit) {
+ str = (unsigned char *)SPEC_CVAL(topsym->etype).v_char;
+ emitIvalLabel(oBuf, topsym);
+ do {
+ dbuf_printf (oBuf, "\tretlw 0x%02x ; '%c'\n", str[0], (str[0] >= 0x20 && str[0] < 128) ? str[0] : '.');
+ } while (*(str++));
+ return;
+ }
+
+ if (IS_ARRAY(my_type) && list && list->type == INIT_NODE) {
+ fprintf (stderr, "Unhandled initialized symbol: %s\n", topsym->name);
+ assert ( !"Initialized char-arrays are not yet supported, assign at runtime instead." );
+ return;
+ }
+
+ if (IS_ARRAY(my_type)) {
+ size_t i;
+
+ DEBUGprintf ("(array, %d items, %ud byte) below\n", (unsigned int) DCL_ELEM(my_type), size);
+ assert (!list || list->type == INIT_DEEP);
+ if (list) list = list->init.deep;
+ for (i = 0; i < DCL_ELEM(my_type); i++) {
+ emitInitVal(oBuf, topsym, my_type->next, list);
+ topsym = NULL;
+ if (list) list = list->next;
+ } // for i
+ return;
+ }
+
+ if (IS_FLOAT(my_type)) {
+ // float, 32 bit
+ DEBUGprintf ("(float, %d byte) %lf\n", size, list ? list2int(list) : 0.0);
+ emitIvals(oBuf, topsym, list, 0, size);
+ return;
+ }
+
+ if (IS_CHAR(my_type) || IS_INT(my_type) || IS_LONG(my_type) ||
+ IS_BOOL(my_type)) {
+ // integral type, 8, 16, or 32 bit
+ DEBUGprintf ("(integral, %d byte) 0x%lx/%ld\n", size, list ? (long)list2int(list) : 0, list ? (long)list2int(list) : 0);
+ emitIvals(oBuf, topsym, list, 0, size);
+ return;
+
+ } else if (IS_STRUCT(my_type) && SPEC_STRUCT(my_type)->type == STRUCT) {
+ // struct
+ DEBUGprintf ("(struct, %d byte) handled below\n", size);
+ assert (!list || (list->type == INIT_DEEP));
+
+ // iterate over struct members and initList
+ if (list) list = list->init.deep;
+ sym = SPEC_STRUCT(my_type)->fields;
+ while (sym) {
+ long bitfield = 0;
+ int len = 0;
+ if (IS_BITFIELD(sym->type)) {
+ while (sym && IS_BITFIELD(sym->type)) {
+ int bitoff = SPEC_BSTR(getSpec(sym->type)) + 8 * sym->offset;
+ assert (!list || ((list->type == INIT_NODE)
+ && IS_AST_LIT_VALUE(list->init.node)));
+ lit = (long) (list ? list2int(list) : 0);
+ DEBUGprintf ( "(bitfield member) %02lx (%d bit, starting at %d, bitfield %02lx)\n",
+ lit, SPEC_BLEN(getSpec(sym->type)),
+ bitoff, bitfield);
+ bitfield |= (lit & ((1ul << SPEC_BLEN(getSpec(sym->type))) - 1)) << bitoff;
+ len += SPEC_BLEN(getSpec(sym->type));
+
+ sym = sym->next;
+ if (list) list = list->next;
+ } // while
+ assert (len < sizeof (long) * 8); // did we overflow our initializer?!?
+ len = (len + 7) & ~0x07; // round up to full bytes
+ emitIvals(oBuf, topsym, NULL, bitfield, len / 8);
+ topsym = NULL;
+ } // if
+
+ if (sym) {
+ emitInitVal(oBuf, topsym, sym->type, list);
+ topsym = NULL;
+ sym = sym->next;
+ if (list) list = list->next;
+ } // if
+ } // while
+ if (list) {
+ assert ( !"Excess initializers." );
+ } // if
+ return;
+
+ } else if (IS_STRUCT(my_type) && SPEC_STRUCT(my_type)->type == UNION) {
+ // union
+ DEBUGprintf ("(union, %d byte) handled below\n", size);
+ assert (list && list->type == INIT_DEEP);
+
+ // iterate over union members and initList, try to map number and type of fields and initializers
+ my_type = matchIvalToUnion(list, my_type, size);
+ if (my_type) {
+ emitInitVal(oBuf, topsym, my_type, list->init.deep);
+ topsym = NULL;
+ size -= getSize(my_type);
+ if (size > 0) {
+ // pad with (leading) zeros
+ emitIvals(oBuf, NULL, NULL, 0, size);
+ }
+ return;
+ } // if
+
+ assert ( !"No UNION member matches the initializer structure.");
+ } else if (IS_BITFIELD(my_type)) {
+ assert ( !"bitfields should only occur in structs..." );
+
+ } else {
+ printf ("SPEC_NOUN: %d\n", SPEC_NOUN(my_type));
+ assert( !"Unhandled initialized type.");
+ }
+}
+
+/*
+ * Emit a set of symbols.
+ * type - 0: have symbol tell whether it is local, extern or global
+ * 1: assume all symbols in set to be global
+ * 2: assume all symbols in set to be extern
+ */
+static void
+emitSymbolSet(set *s, int type)
+{
+ symbol *sym;
+ initList *list;
+ unsigned int sectionNr = 0;
+
+ for (sym = setFirstItem(s); sym; sym = setNextItem(s)) {
+#if 0
+ fprintf (stdout, "; name %s, rname %s, level %d, block %d, key %d, local %d, ival %p, static %d, cdef %d, used %d\n",
+ sym->name, sym->rname, sym->level, sym->block, sym->key, sym->islocal, sym->ival, IS_STATIC(sym->etype), sym->cdef, sym->used);
+#endif
+
+ if (sym->etype && SPEC_ABSA(sym->etype)
+ && IS_CONFIG_ADDRESS(SPEC_ADDR(sym->etype))
+ && sym->ival)
+ {
+ // handle config words
+ pic14_assignConfigWordValue(SPEC_ADDR(sym->etype),
+ (int)list2int(sym->ival));
+ pic14_stringInSet(sym->rname, &emitted, 1);
+ continue;
+ }
+
+ if (sym->isstrlit) {
+ // special case: string literals
+ emitInitVal(ivalBuf, sym, sym->type, NULL);
+ continue;
+ }
+
+ if (type != 0 || sym->cdef || (!IS_STATIC(sym->etype) && IS_GLOBAL(sym)))
+ {
+ // bail out for ___fsadd and friends
+ if (sym->cdef && !sym->used) continue;
+
+ /* export or import non-static globals */
+ if (!pic14_stringInSet(sym->rname, &emitted, 0)) {
+
+ if (type == 2 || IS_EXTERN(sym->etype) || sym->cdef)
+ {
+ /* do not add to emitted set, it might occur again! */
+ //if (!sym->used) continue;
+ // declare symbol
+ emitIfNew (extBuf, &emitted, "\textern\t%s\n", sym->rname);
+ } else {
+ // declare symbol
+ emitIfNew (gloBuf, &emitted, "\tglobal\t%s\n", sym->rname);
+ if (!sym->ival && !IS_FUNC(sym->type)) {
+ // also define symbol
+ if (IS_ABSOLUTE(sym->etype)) {
+ // absolute location?
+ //dbuf_printf (gloDefBuf, "UD_%s_%u\tudata\t0x%04X\n", moduleName, sectionNr++, SPEC_ADDR(sym->etype));
+ // deferred to pic14_constructAbsMap
+ } else {
+ dbuf_printf (gloDefBuf, "UD_%s_%u\tudata\n", moduleName, sectionNr++);
+ dbuf_printf (gloDefBuf, "%s\tres\t%d\n\n", sym->rname, getSize(sym->type));
+ }
+ } // if
+ } // if
+ pic14_stringInSet(sym->rname, &emitted, 1);
+ } // if
+ } // if
+ list = sym->ival;
+ //if (list) showInitList(list, 0);
+ if (list) {
+ resolveIvalSym( list, sym->type );
+ emitInitVal(ivalBuf, sym, sym->type, sym->ival);
+ dbuf_printf (ivalBuf, "\n");
+ }
+ } // for sym
+}
+
+/*
+ * Iterate over all memmaps and emit their contents (attributes, symbols).
+ */
+static void
+showAllMemmaps(FILE *of)
+{
+ struct dbuf_s locBuf;
+ memmap *maps[] = {
+ xstack, istack, code, data, pdata, xdata, xidata, xinit,
+ idata, bit, statsg, c_abs, x_abs, i_abs, d_abs,
+ sfr, sfrbit, reg, generic, overlay, eeprom, home };
+ memmap * map;
+ int i;
+
+ DEBUGprintf ("---begin memmaps---\n");
+ if (!extBuf) extBuf = dbuf_new(1024);
+ if (!gloBuf) gloBuf = dbuf_new(1024);
+ if (!gloDefBuf) gloDefBuf = dbuf_new(1024);
+ if (!ivalBuf) ivalBuf = dbuf_new(1024);
+ dbuf_init(&locBuf, 1024);
+
+ dbuf_printf (extBuf, "%s; external declarations\n%s", iComments2, iComments2);
+ dbuf_printf (gloBuf, "%s; global declarations\n%s", iComments2, iComments2);
+ dbuf_printf (gloDefBuf, "%s; global definitions\n%s", iComments2, iComments2);
+ dbuf_printf (ivalBuf, "%s; initialized data\n%s", iComments2, iComments2);
+ dbuf_printf (&locBuf, "%s; compiler-defined variables\n%s", iComments2, iComments2);
+
+ for (i = 0; i < sizeof(maps) / sizeof (memmap *); i++) {
+ map = maps[i];
+ //DEBUGprintf ("memmap %i: %p\n", i, map);
+ if (map) {
+#if 0
+ fprintf (stdout, "; pageno %c, sname %s, dbName %c, ptrType %d, slbl %d, sloc %u, fmap %u, paged %u, direct %u, bitsp %u, codesp %u, regsp %u, syms %p\n",
+ map->pageno, map->sname, map->dbName, map->ptrType, map->slbl,
+ map->sloc, map->fmap, map->paged, map->direct, map->bitsp,
+ map->codesp, map->regsp, map->syms);
+#endif
+ emitSymbolSet(map->syms, 0);
+ } // if (map)
+ } // for i
+ DEBUGprintf ("---end of memmaps---\n");
+
+ emitSymbolSet(publics, 1);
+ emitSymbolSet(externs, 2);
+
+ emitPseudoStack(gloBuf, extBuf);
+ pic14_constructAbsMap(gloDefBuf, gloBuf);
+ pic14printLocals (&locBuf);
+ pic14_emitConfigWord(of); // must be done after all the rest
+
+ dbuf_write_and_destroy(extBuf, of);
+ dbuf_write_and_destroy(gloBuf, of);
+ dbuf_write_and_destroy(gloDefBuf, of);
+ dbuf_write_and_destroy(&locBuf, of);
+ dbuf_write_and_destroy(ivalBuf, of);
+
+ extBuf = gloBuf = gloDefBuf = ivalBuf = NULL;
+}
diff --git a/src/pic14/glue.h b/src/pic14/glue.h
new file mode 100644
index 0000000..f4a9407
--- /dev/null
+++ b/src/pic14/glue.h
@@ -0,0 +1,36 @@
+/*-------------------------------------------------------------------------
+
+ 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!
+-------------------------------------------------------------------------*/
+
+#ifndef PIC_GLUE_H
+#define PIC_GLUE_H
+
+#include "common.h"
+
+extern int pic14_hasInterrupt;
+extern set *pic14_localFunctions;
+
+void picglue (void);
+int pic14_stringInSet(const char *str, set **world, int autoAdd);
+
+#endif
diff --git a/src/pic14/main.c b/src/pic14/main.c
new file mode 100644
index 0000000..ee90470
--- /dev/null
+++ b/src/pic14/main.c
@@ -0,0 +1,485 @@
+/** @file main.c
+ pic14 specific general functions.
+
+ Note that mlh prepended _pic14_ on the static functions. Makes
+ it easier to set a breakpoint using the debugger.
+*/
+#include "common.h"
+#include "dbuf_string.h"
+#include "SDCCmacro.h"
+
+#include "device.h"
+#include "gen.h"
+#include "glue.h"
+#include "main.h"
+#include "pcode.h"
+#include "ralloc.h"
+
+/*
+ * Imports
+ */
+extern set *dataDirsSet;
+extern set *includeDirsSet;
+extern set *libDirsSet;
+extern set *libPathsSet;
+extern set *linkOptionsSet;
+
+
+pic14_options_t pic14_options;
+int debug_verbose = 0;
+
+
+#define OPTION_STACK_SIZE "--stack-size"
+
+static char _defaultRules[] =
+{
+#include "peeph.rul"
+};
+
+static OPTION _pic14_poptions[] =
+ {
+ { 0, "--debug-xtra", &debug_verbose, "show more debug info in assembly output" },
+ { 0, "--no-pcode-opt", &pic14_options.disable_df, "disable (slightly faulty) optimization on pCode" },
+ { 0, OPTION_STACK_SIZE, &options.stack_size, "sets the size if the argument passing stack (default: 16, minimum: 4)", CLAT_INTEGER },
+ { 0, "--no-extended-instructions", &pic14_options.no_ext_instr, "forbid use of the extended instruction set (e.g., ADDFSR)" },
+ { 0, "--no-warn-non-free", &pic14_options.no_warn_non_free, "suppress warning on absent --use-non-free option" },
+ { 0, NULL, NULL, NULL }
+ };
+
+/* list of key words used by pic14 */
+static char *_pic14_keywords[] =
+{
+ "at",
+ //"bit",
+ "code",
+ "critical",
+ "data",
+ "far",
+ "idata",
+ "interrupt",
+ "naked",
+ "near",
+ //"pdata",
+ "reentrant",
+ "sfr",
+ //"sbit",
+ "using",
+ "xdata",
+ NULL
+};
+
+static int regParmFlg = 0; /* determine if we can register a parameter */
+
+
+/** $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[] =
+{
+ "gplink", "$l", "-w", "-r", "-o \"$2\"", "\"$1\"", "$3", NULL
+};
+*/
+
+static const char *_asmCmd[] =
+{
+ "gpasm", "$l", "$3", "-o", "$2", "-c", "$1.asm", NULL
+};
+
+static void
+_pic14_init (void)
+{
+ asm_addTree (&asm_asxxxx_mapping);
+ memset (&pic14_options, 0, sizeof (pic14_options));
+}
+
+static void
+_pic14_reset_regparm (struct sym_link *funcType)
+{
+ regParmFlg = 0;
+}
+
+static int
+_pic14_regparm (sym_link * l, bool reentrant)
+{
+/* for this processor it is simple
+ can pass only the first parameter in a register */
+ //if (regParmFlg)
+ // return 0;
+
+ regParmFlg++;// = 1;
+ return 1;
+}
+
+static bool
+_pic14_parseOptions (int *pargc, char **argv, int *i)
+{
+ /* TODO: allow port-specific command line options to specify
+ * segment names here.
+ */
+ return FALSE;
+}
+
+static void
+_pic14_finaliseOptions (void)
+{
+ struct dbuf_s dbuf;
+
+ pCodeInitRegisters();
+
+ port->mem.default_local_map = data;
+ port->mem.default_globl_map = data;
+
+ dbuf_init (&dbuf, 512);
+ dbuf_printf (&dbuf, "-D__SDCC_PROCESSOR=\"%s\"", port->processor);
+ addSet (&preArgvSet, Safe_strdup (dbuf_detach_c_str (&dbuf)));
+
+ {
+ char *upperProc, *p1, *p2;
+ int len;
+
+ dbuf_set_length (&dbuf, 0);
+ len = strlen (port->processor);
+ upperProc = Safe_malloc (len);
+ for (p1 = port->processor, p2 = upperProc; *p1; ++p1, ++p2)
+ {
+ *p2 = toupper (*p1);
+ }
+ dbuf_append (&dbuf, "-D__SDCC_PIC", sizeof ("-D__SDCC_PIC") - 1);
+ dbuf_append (&dbuf, upperProc, len);
+ addSet (&preArgvSet, dbuf_detach_c_str (&dbuf));
+ }
+
+ /* This is valid after calling pCodeInitRegisters */
+ if (pic14_getPIC()->isEnhancedCore)
+ {
+ dbuf_set_length (&dbuf, 0);
+ dbuf_printf (&dbuf, "-D__SDCC_PIC14_ENHANCED");
+ addSet (&preArgvSet, Safe_strdup (dbuf_detach_c_str (&dbuf)));
+ }
+
+ /* Report the actual stack size */
+ {
+ int size;
+ pic14_getSharedStack(NULL, NULL, &size);
+
+ /* non-enhanced cores take PSAVE, SSAVE and WSAVE from stack */
+ if (!pic14_getPIC()->isEnhancedCore)
+ size -= 3;
+
+ /* Actual stack size includes WREG and STK00, ... */
+ dbuf_set_length (&dbuf, 0);
+ dbuf_printf (&dbuf, "-D__SDCC_PIC14_STACK_SIZE=%d", size + 1);
+ addSet (&preArgvSet, Safe_strdup (dbuf_detach_c_str (&dbuf)));
+ }
+
+ if (!pic14_options.no_warn_non_free && !options.use_non_free)
+ {
+ fprintf(stderr,
+ "WARNING: Command line option --use-non-free not present.\n"
+ " When compiling for PIC14/PIC16, please provide --use-non-free\n"
+ " to get access to device headers and libraries.\n"
+ " If you do not use these, you may provide --no-warn-non-free\n"
+ " to suppress this warning (not recommended).\n");
+ } // if
+
+}
+
+static void
+_pic14_setDefaultOptions (void)
+{
+}
+
+static const char *
+_pic14_getRegName (const struct reg_info *reg)
+{
+ if (reg)
+ return reg->name;
+ return "err";
+}
+
+static void
+_pic14_genAssemblerPreamble (FILE * of)
+{
+ char * name = processor_base_name();
+
+ if(!name) {
+
+ name = "16f877";
+ fprintf(stderr,"WARNING: No Pic has been selected, defaulting to %s\n",name);
+ }
+
+ fprintf (of, "\tlist\tp=%s\n",name);
+ fprintf (of, "\tradix dec\n");
+ fprintf (of, "\tinclude \"p%s.inc\"\n",name);
+}
+
+/* Generate interrupt vector table. */
+static int
+_pic14_genIVT (struct dbuf_s * oBuf, symbol ** interrupts, int maxInterrupts)
+{
+ /* Let the default code handle it. */
+ return FALSE;
+}
+
+static bool
+_hasNativeMulFor (iCode *ic, sym_link *left, sym_link *right)
+{
+#if 0
+ if ( ic->op != '*')
+ {
+ return FALSE;
+ }
+
+ /* multiply chars in-place */
+ if (getSize(left) == 1 && getSize(right) == 1)
+ return TRUE;
+#endif
+
+ /* use library functions for more complex maths */
+ return FALSE;
+}
+
+/* Indicate which extended bit operations this port supports */
+static bool
+hasExtBitOp (int op, int size)
+{
+ if (op == RRC
+ || op == RLC
+ || op == GETABIT
+ /* || op == GETHBIT */ /* GETHBIT doesn't look complete for PIC */
+ )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+/* Indicate the expense of an access to an output storage class */
+static int
+oclsExpense (struct memmap *oclass)
+{
+ /* The IN_FARSPACE test is compatible with historical behaviour, */
+ /* but I don't think it is applicable to PIC. If so, please feel */
+ /* free to remove this test -- EEP */
+ if (IN_FARSPACE(oclass))
+ return 1;
+
+ return 0;
+}
+
+static void
+_pic14_do_link (void)
+{
+ /*
+ * link command format:
+ * {linker} {incdirs} {lflags} -o {outfile} {spec_ofiles} {ofiles} {libs}
+ *
+ */
+#define LFRM "{linker} {incdirs} {sysincdirs} {lflags} -w -r -o {outfile} {user_ofile} {spec_ofiles} {ofiles} {libs}"
+ hTab *linkValues = NULL;
+ char *lcmd;
+ set *tSet = NULL;
+ int ret;
+ char * procName;
+
+ shash_add (&linkValues, "linker", "gplink");
+
+ /* LIBRARY SEARCH DIRS */
+ mergeSets (&tSet, libPathsSet);
+ mergeSets (&tSet, libDirsSet);
+ shash_add (&linkValues, "incdirs", joinStrSet (processStrSet (tSet, "-I", NULL, shell_escape)));
+
+ joinStrSet (processStrSet (libDirsSet, "-I", NULL, shell_escape));
+ shash_add (&linkValues, "sysincdirs", joinStrSet (processStrSet (libDirsSet, "-I", NULL, shell_escape)));
+
+ shash_add (&linkValues, "lflags", joinStrSet (linkOptionsSet));
+
+ {
+ char *s = shell_escape (fullDstFileName ? fullDstFileName : dstFileName);
+
+ shash_add (&linkValues, "outfile", s);
+ Safe_free (s);
+ }
+
+ if (fullSrcFileName)
+ {
+ struct dbuf_s dbuf;
+ char *s;
+
+ dbuf_init (&dbuf, 128);
+
+ dbuf_append_str (&dbuf, fullDstFileName ? fullDstFileName : dstFileName);
+ dbuf_append (&dbuf, ".o", 2);
+ s = shell_escape (dbuf_c_str (&dbuf));
+ dbuf_destroy (&dbuf);
+ shash_add (&linkValues, "user_ofile", s);
+ Safe_free (s);
+ }
+
+ shash_add (&linkValues, "ofiles", joinStrSet (processStrSet (relFilesSet, NULL, NULL, shell_escape)));
+
+ /* LIBRARIES */
+ procName = processor_base_name ();
+ if (!procName)
+ procName = "16f877";
+
+ addSet (&libFilesSet, Safe_strdup (pic14_getPIC()->isEnhancedCore ?
+ "libsdcce.lib" : "libsdcc.lib"));
+
+ {
+ struct dbuf_s dbuf;
+
+ dbuf_init (&dbuf, 128);
+ dbuf_append (&dbuf, "pic", sizeof ("pic") - 1);
+ dbuf_append_str (&dbuf, procName);
+ dbuf_append (&dbuf, ".lib", sizeof (".lib") - 1);
+ addSet (&libFilesSet, dbuf_detach_c_str (&dbuf));
+ }
+
+ shash_add (&linkValues, "libs", joinStrSet (processStrSet (libFilesSet, NULL, NULL, shell_escape)));
+
+ lcmd = msprintf(linkValues, LFRM);
+ ret = sdcc_system (lcmd);
+ Safe_free (lcmd);
+
+ if (ret)
+ exit (1);
+}
+
+/* Globals */
+PORT pic_port =
+{
+ TARGET_ID_PIC14,
+ "pic14",
+ "MCU pic", /* Target name */
+ "", /* Processor */
+ {
+ picglue,
+ TRUE, /* Emit glue around main */
+ NO_MODEL,
+ NO_MODEL,
+ NULL, /* model == target */
+ },
+ {
+ _asmCmd,
+ NULL,
+ "-g", /* options with --debug */
+ NULL, /* options without --debug */
+ 0,
+ ".asm",
+ NULL /* no do_assemble function */
+ },
+ {
+ NULL,
+ NULL,
+ _pic14_do_link, /* own do link function */
+ ".o",
+ 0
+ },
+ { /* Peephole optimizer */
+ _defaultRules
+ },
+ {
+ /* Sizes: char, short, int, long, long long, near ptr, far ptr, gptr, func ptr, banked func ptr, bit, float */
+ 1, 2, 2, 4, 8, 2, 2, 3, 2, 3, 1, 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)
+ */
+ },
+ /* tags for generic pointers */
+ { 0x00, 0x00, 0x00, 0x80 }, /* far, near, xstack, code */
+ {
+ "XSEG (XDATA)",
+ "STACK (DATA)",
+ "code",
+ "DSEG (DATA)",
+ "ISEG (DATA)",
+ NULL, /* pdata */
+ "XSEG (XDATA)",
+ "BSEG (BIT)",
+ "RSEG (DATA)",
+ "GSINIT (CODE)",
+ "udata_ovr",
+ "GSFINAL (CODE)",
+ "HOME (CODE)",
+ NULL, // xidata
+ NULL, // xinit
+ "CONST (CODE)", // const_name - const data (code or not)
+ "CABS (ABS,CODE)", // cabs_name - const absolute data (code or not)
+ "XABS (ABS,XDATA)", // xabs_name - absolute xdata
+ "IABS (ABS,DATA)", // iabs_name - absolute data
+ NULL, // name of segment for initialized variables
+ NULL, // name of segment for copies of initialized variables in code space
+ NULL,
+ NULL,
+ 1, // code is read only
+ 1 // No fancy alignments supported.
+ },
+ { NULL, NULL },
+ {
+ +1, 1, 4, 1, 1, 0, 0
+ },
+ /* pic14 has an 8 bit mul */
+ {
+ -1, FALSE
+ },
+ {
+ pic14_emitDebuggerSymbol
+ },
+ {
+ 255/3, /* maxCount */
+ 3, /* sizeofElement */
+ /* The rest of these costs are bogus. They approximate */
+ /* the behavior of src/SDCCicode.c 1.207 and earlier. */
+ {4,4,4}, /* sizeofMatchJump[] */
+ {0,0,0}, /* sizeofRangeCompare[] */
+ 0, /* sizeofSubtract */
+ 3, /* sizeofDispatch */
+ },
+ "_",
+ _pic14_init,
+ _pic14_parseOptions,
+ _pic14_poptions,
+ NULL,
+ _pic14_finaliseOptions,
+ _pic14_setDefaultOptions,
+ pic14_assignRegisters,
+ _pic14_getRegName,
+ 0,
+ NULL,
+ _pic14_keywords,
+ _pic14_genAssemblerPreamble,
+ NULL, /* no genAssemblerEnd */
+ _pic14_genIVT,
+ NULL, // _pic14_genXINIT
+ NULL, /* genInitStartup */
+ _pic14_reset_regparm,
+ _pic14_regparm,
+ NULL, /* process a pragma */
+ NULL,
+ _hasNativeMulFor,
+ hasExtBitOp, /* hasExtBitOp */
+ oclsExpense, /* oclsExpense */
+ FALSE,
+// TRUE, /* little endian */
+ FALSE, /* little endian - PIC code enumlates big endian */
+ 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 */
+ 0, /* Number of registers handled in the tree-decomposition-based register allocator in SDCCralloc.hpp */
+ PORT_MAGIC
+};
+
diff --git a/src/pic14/main.h b/src/pic14/main.h
new file mode 100644
index 0000000..4275b65
--- /dev/null
+++ b/src/pic14/main.h
@@ -0,0 +1,15 @@
+#ifndef MAIN_INCLUDE
+#define MAIN_INCLUDE
+
+typedef struct {
+ unsigned int isLibrarySource:1;
+ int disable_df;
+ int no_ext_instr;
+ int no_warn_non_free;
+} pic14_options_t;
+
+extern pic14_options_t pic14_options;
+extern int debug_verbose;
+
+#endif
+
diff --git a/src/pic14/pcode.c b/src/pic14/pcode.c
new file mode 100644
index 0000000..5e010da
--- /dev/null
+++ b/src/pic14/pcode.c
@@ -0,0 +1,5985 @@
+/*-------------------------------------------------------------------------
+
+ pcode.c - post code generation
+ 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.
+-------------------------------------------------------------------------*/
+
+#include "device.h"
+#include "gen.h"
+#include "pcode.h"
+#include "pcodeflow.h"
+#include "ralloc.h"
+
+/****************************************************************/
+/****************************************************************/
+
+// Eventually this will go into device dependent files:
+pCodeOpReg pc_status = {{PO_STATUS, "STATUS"}, -1, NULL,0,NULL};
+pCodeOpReg pc_fsr = {{PO_FSR, "FSR"}, -1, NULL,0,NULL};
+pCodeOpReg pc_fsr0l = {{PO_FSR, "FSR0L"}, -1, NULL,0,NULL};
+pCodeOpReg pc_fsr0h = {{PO_FSR, "FSR0H"}, -1, NULL,0,NULL};
+pCodeOpReg pc_indf_ = {{PO_INDF, "INDF"}, -1, NULL,0,NULL};
+pCodeOpReg pc_indf0 = {{PO_INDF, "INDF0"}, -1, NULL,0,NULL};
+pCodeOpReg pc_intcon = {{PO_INTCON, "INTCON"}, -1, NULL,0,NULL};
+pCodeOpReg pc_pcl = {{PO_PCL, "PCL"}, -1, NULL,0,NULL};
+pCodeOpReg pc_pclath = {{PO_PCLATH, "PCLATH"}, -1, NULL,0,NULL};
+
+pCodeOpReg *pc_indf = &pc_indf_;
+
+pCodeOpReg pc_wsave = {{PO_GPR_REGISTER, "WSAVE"}, -1, NULL,0,NULL};
+pCodeOpReg pc_ssave = {{PO_GPR_REGISTER, "SSAVE"}, -1, NULL,0,NULL};
+pCodeOpReg pc_psave = {{PO_GPR_REGISTER, "PSAVE"}, -1, NULL,0,NULL};
+
+pFile *the_pFile = NULL;
+
+
+#define SET_BANK_BIT (1 << 16)
+#define CLR_BANK_BIT 0
+
+static peepCommand peepCommands[] = {
+
+ {NOTBITSKIP, "_NOTBITSKIP_"},
+ {BITSKIP, "_BITSKIP_"},
+ {INVERTBITSKIP, "_INVERTBITSKIP_"},
+
+ {-1, NULL}
+};
+
+static int mnemonics_initialized = 0;
+
+static hTab *pic14MnemonicsHash = NULL;
+static hTab *pic14pCodePeepCommandsHash = NULL;
+
+static pBlock *pb_dead_pcodes = NULL;
+
+/* Hardcoded flags to change the behavior of the PIC port */
+static int functionInlining = 1; /* inline functions if nonzero */
+
+// static int GpCodeSequenceNumber = 1;
+static int GpcFlowSeq = 1;
+
+/* statistics (code size estimation) */
+static unsigned int pcode_insns = 0;
+static unsigned int pcode_doubles = 0;
+
+static unsigned peakIdx = 0; /* This keeps track of the peak register index for call tree register reuse */
+
+
+/****************************************************************/
+/* Forward declarations */
+/****************************************************************/
+
+static void genericDestruct(pCode *pc);
+static void genericPrint(FILE *of,pCode *pc);
+
+static void pBlockStats(FILE *of, pBlock *pb);
+static pCode *findFunction(const char *fname);
+static void pCodePrintLabel(FILE *of, pCode *pc);
+static void pCodePrintFunction(FILE *of, pCode *pc);
+static void pCodeOpPrint(FILE *of, pCodeOp *pcop);
+static char *get_op_from_instruction( pCodeInstruction *pcc);
+static pBlock *newpBlock(void);
+
+
+/****************************************************************/
+/* PIC Instructions */
+/****************************************************************/
+
+static pCodeInstruction pciADDWF = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_ADDWF,
+ "ADDWF",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ TRUE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ (PCC_W | PCC_REGISTER), // inCond
+ (PCC_REGISTER | PCC_C | PCC_DC | PCC_Z) // outCond
+};
+
+static pCodeInstruction pciADDFW = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_ADDFW,
+ "ADDWF",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ (PCC_W | PCC_REGISTER), // inCond
+ (PCC_W | PCC_C | PCC_DC | PCC_Z) // outCond
+};
+
+static pCodeInstruction pciADDLW = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_ADDLW,
+ "ADDLW",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 1, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ TRUE, // literal operand
+ POC_NOP,
+ (PCC_W | PCC_LITERAL), // inCond
+ (PCC_W | PCC_Z | PCC_C | PCC_DC) // outCond
+};
+
+static pCodeInstruction pciANDLW = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_ANDLW,
+ "ANDLW",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 1, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ TRUE, // literal operand
+ POC_NOP,
+ (PCC_W | PCC_LITERAL), // inCond
+ (PCC_W | PCC_Z) // outCond
+};
+
+static pCodeInstruction pciANDWF = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_ANDWF,
+ "ANDWF",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ TRUE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ (PCC_W | PCC_REGISTER), // inCond
+ (PCC_REGISTER | PCC_Z) // outCond
+};
+
+static pCodeInstruction pciANDFW = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_ANDFW,
+ "ANDWF",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ (PCC_W | PCC_REGISTER), // inCond
+ (PCC_W | PCC_Z) // outCond
+};
+
+static pCodeInstruction pciBCF = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_BCF,
+ "BCF",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ TRUE, // dest
+ TRUE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_BSF,
+ (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
+ (PCC_REGISTER | PCC_EXAMINE_PCOP) // outCond
+};
+
+static pCodeInstruction pciBSF = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_BSF,
+ "BSF",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ TRUE, // dest
+ TRUE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_BCF,
+ (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
+ (PCC_REGISTER | PCC_EXAMINE_PCOP) // outCond
+};
+
+static pCodeInstruction pciBTFSC = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_BTFSC,
+ "BTFSC",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ FALSE, // dest
+ TRUE, // bit instruction
+ TRUE, // branch
+ TRUE, // skip
+ FALSE, // literal operand
+ POC_BTFSS,
+ (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
+ PCC_NONE // outCond
+};
+
+static pCodeInstruction pciBTFSS = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_BTFSS,
+ "BTFSS",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ FALSE, // dest
+ TRUE, // bit instruction
+ TRUE, // branch
+ TRUE, // skip
+ FALSE, // literal operand
+ POC_BTFSC,
+ (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
+ PCC_NONE // outCond
+};
+
+static pCodeInstruction pciCALL = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_CALL,
+ "CALL",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 1, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ TRUE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ (PCC_NONE | PCC_W), // inCond, reads argument from WREG
+ (PCC_NONE | PCC_W | PCC_C | PCC_DC | PCC_Z) // outCond, flags are destroyed by called function
+};
+
+static pCodeInstruction pciCOMF = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_COMF,
+ "COMF",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ TRUE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ PCC_REGISTER, // inCond
+ (PCC_REGISTER | PCC_Z) // outCond
+};
+
+static pCodeInstruction pciCOMFW = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_COMFW,
+ "COMF",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ PCC_REGISTER, // inCond
+ (PCC_W | PCC_Z) // outCond
+};
+
+static pCodeInstruction pciCLRF = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_CLRF,
+ "CLRF",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 1, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ PCC_NONE, // inCond
+ PCC_REGISTER | PCC_Z // outCond
+};
+
+static pCodeInstruction pciCLRW = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_CLRW,
+ "CLRW",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 0, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ PCC_NONE, // inCond
+ (PCC_W | PCC_Z) // outCond
+};
+
+static pCodeInstruction pciCLRWDT = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_CLRWDT,
+ "CLRWDT",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 0, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ PCC_NONE, // inCond
+ PCC_NONE // outCond
+};
+
+static pCodeInstruction pciDECF = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_DECF,
+ "DECF",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ TRUE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ PCC_REGISTER, // inCond
+ (PCC_REGISTER | PCC_Z) // outCond
+};
+
+static pCodeInstruction pciDECFW = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_DECFW,
+ "DECF",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ PCC_REGISTER, // inCond
+ (PCC_W | PCC_Z) // outCond
+};
+
+static pCodeInstruction pciDECFSZ = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_DECFSZ,
+ "DECFSZ",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ TRUE, // dest
+ FALSE, // bit instruction
+ TRUE, // branch
+ TRUE, // skip
+ FALSE, // literal operand
+ POC_DECF, // followed by BTFSC STATUS, Z --> also kills STATUS
+ PCC_REGISTER, // inCond
+ (PCC_REGISTER | PCC_Z) // outCond
+};
+
+static pCodeInstruction pciDECFSZW = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_DECFSZW,
+ "DECFSZ",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ TRUE, // branch
+ TRUE, // skip
+ FALSE, // literal operand
+ POC_DECFW, // followed by BTFSC STATUS, Z --> also kills STATUS
+ PCC_REGISTER, // inCond
+ (PCC_W | PCC_Z) // outCond
+};
+
+static pCodeInstruction pciGOTO = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_GOTO,
+ "GOTO",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 1, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ TRUE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ PCC_NONE, // inCond
+ PCC_NONE // outCond
+};
+
+static pCodeInstruction pciINCF = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_INCF,
+ "INCF",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ TRUE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ PCC_REGISTER, // inCond
+ (PCC_REGISTER | PCC_Z) // outCond
+};
+
+static pCodeInstruction pciINCFW = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_INCFW,
+ "INCF",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ PCC_REGISTER, // inCond
+ (PCC_W | PCC_Z) // outCond
+};
+
+static pCodeInstruction pciINCFSZ = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_INCFSZ,
+ "INCFSZ",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ TRUE, // dest
+ FALSE, // bit instruction
+ TRUE, // branch
+ TRUE, // skip
+ FALSE, // literal operand
+ POC_INCF, // followed by BTFSC STATUS, Z --> also kills STATUS
+ PCC_REGISTER, // inCond
+ (PCC_REGISTER | PCC_Z) // outCond
+};
+
+static pCodeInstruction pciINCFSZW = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_INCFSZW,
+ "INCFSZ",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ TRUE, // branch
+ TRUE, // skip
+ FALSE, // literal operand
+ POC_INCFW, // followed by BTFSC STATUS, Z --> also kills STATUS
+ PCC_REGISTER, // inCond
+ (PCC_W | PCC_Z) // outCond
+};
+
+static pCodeInstruction pciIORWF = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_IORWF,
+ "IORWF",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ TRUE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ (PCC_W | PCC_REGISTER), // inCond
+ (PCC_REGISTER | PCC_Z) // outCond
+};
+
+static pCodeInstruction pciIORFW = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_IORFW,
+ "IORWF",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ (PCC_W | PCC_REGISTER), // inCond
+ (PCC_W | PCC_Z) // outCond
+};
+
+static pCodeInstruction pciIORLW = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_IORLW,
+ "IORLW",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 1, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ TRUE, // literal operand
+ POC_NOP,
+ (PCC_W | PCC_LITERAL), // inCond
+ (PCC_W | PCC_Z) // outCond
+};
+
+static pCodeInstruction pciMOVF = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_MOVF,
+ "MOVF",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ TRUE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ PCC_REGISTER, // inCond
+ PCC_Z // outCond
+};
+
+static pCodeInstruction pciMOVFW = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_MOVFW,
+ "MOVF",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ PCC_REGISTER, // inCond
+ (PCC_W | PCC_Z) // outCond
+};
+
+static pCodeInstruction pciMOVWF = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_MOVWF,
+ "MOVWF",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 1, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ PCC_W, // inCond
+ PCC_REGISTER // outCond
+};
+
+static pCodeInstruction pciMOVLW = {
+ {PC_OPCODE, NULL, NULL, 0, 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
+ FALSE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ TRUE, // literal operand
+ POC_NOP,
+ (PCC_NONE | PCC_LITERAL), // inCond
+ PCC_W // outCond
+};
+
+static pCodeInstruction pciNOP = {
+ {PC_OPCODE, NULL, NULL, 0, 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
+ FALSE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ PCC_NONE, // inCond
+ PCC_NONE // outCond
+};
+
+static pCodeInstruction pciRETFIE = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_RETFIE,
+ "RETFIE",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 0, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ TRUE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ PCC_NONE, // inCond
+ (PCC_NONE | PCC_C | PCC_DC | PCC_Z) // outCond (not true... affects the GIE bit too), STATUS bit are retored
+};
+
+static pCodeInstruction pciRETLW = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_RETLW,
+ "RETLW",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 1, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ TRUE, // branch
+ FALSE, // skip
+ TRUE, // literal operand
+ POC_NOP,
+ PCC_LITERAL, // inCond
+ (PCC_W| PCC_C | PCC_DC | PCC_Z) // outCond, STATUS bits are irrelevant after RETLW
+};
+
+static pCodeInstruction pciRETURN = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_RETURN,
+ "RETURN",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 0, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ TRUE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ (PCC_NONE | PCC_W), // inCond, return value is possibly present in W
+ (PCC_NONE | PCC_C | PCC_DC | PCC_Z) // outCond, STATUS bits are irrelevant after RETURN
+};
+
+static pCodeInstruction pciRLF = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_RLF,
+ "RLF",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ TRUE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ (PCC_C | PCC_REGISTER), // inCond
+ (PCC_REGISTER | PCC_C) // outCond
+};
+
+static pCodeInstruction pciRLFW = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_RLFW,
+ "RLF",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ (PCC_C | PCC_REGISTER), // inCond
+ (PCC_W | PCC_C) // outCond
+};
+
+static pCodeInstruction pciRRF = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_RRF,
+ "RRF",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ TRUE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ (PCC_C | PCC_REGISTER), // inCond
+ (PCC_REGISTER | PCC_C) // outCond
+};
+
+static pCodeInstruction pciRRFW = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_RRFW,
+ "RRF",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ (PCC_C | PCC_REGISTER), // inCond
+ (PCC_W | PCC_C) // outCond
+};
+
+static pCodeInstruction pciSUBWF = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_SUBWF,
+ "SUBWF",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ TRUE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ (PCC_W | PCC_REGISTER), // inCond
+ (PCC_REGISTER | PCC_C | PCC_DC | PCC_Z) // outCond
+};
+
+static pCodeInstruction pciSUBFW = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_SUBFW,
+ "SUBWF",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ (PCC_W | PCC_REGISTER), // inCond
+ (PCC_W | PCC_C | PCC_DC | PCC_Z) // outCond
+};
+
+static pCodeInstruction pciSUBLW = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_SUBLW,
+ "SUBLW",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 1, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ TRUE, // literal operand
+ POC_NOP,
+ (PCC_W | PCC_LITERAL), // inCond
+ (PCC_W | PCC_Z | PCC_C | PCC_DC) // outCond
+};
+
+static pCodeInstruction pciSWAPF = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_SWAPF,
+ "SWAPF",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ TRUE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ PCC_REGISTER, // inCond
+ PCC_REGISTER // outCond
+};
+
+static pCodeInstruction pciSWAPFW = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_SWAPFW,
+ "SWAPF",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ PCC_REGISTER, // inCond
+ PCC_W // outCond
+};
+
+static pCodeInstruction pciTRIS = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_TRIS,
+ "TRIS",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 1, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ PCC_NONE, // inCond /* FIXME: what's TRIS doing? */
+ PCC_REGISTER // outCond /* FIXME: what's TRIS doing */
+};
+
+static pCodeInstruction pciXORWF = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_XORWF,
+ "XORWF",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ TRUE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ (PCC_W | PCC_REGISTER), // inCond
+ (PCC_REGISTER | PCC_Z) // outCond
+};
+
+static pCodeInstruction pciXORFW = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_XORFW,
+ "XORWF",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ (PCC_W | PCC_REGISTER), // inCond
+ (PCC_W | PCC_Z) // outCond
+};
+
+static pCodeInstruction pciXORLW = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_XORLW,
+ "XORLW",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 1, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ TRUE, // literal operand
+ POC_NOP,
+ (PCC_W | PCC_LITERAL), // inCond
+ (PCC_W | PCC_Z) // outCond
+};
+
+
+static pCodeInstruction pciBANKSEL = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_BANKSEL,
+ "BANKSEL",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 1, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ PCC_NONE, // inCond
+ PCC_NONE // outCond
+};
+
+static pCodeInstruction pciPAGESEL = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_PAGESEL,
+ "PAGESEL",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 1, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ PCC_NONE, // inCond
+ PCC_NONE // outCond
+};
+
+/****************************************************************/
+/* PIC Enhanced Instructions */
+/****************************************************************/
+
+static pCodeInstruction pciADDFSR = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_ADDFSR,
+ "ADDFSR",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ TRUE, // literal operand
+ POC_NOP,
+ PCC_NONE, // inCond
+ PCC_NONE // outCond
+};
+
+static pCodeInstruction pciADDWFC = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_ADDWFC,
+ "ADDWFC",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ TRUE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ (PCC_W | PCC_REGISTER | PCC_C), // inCond
+ (PCC_REGISTER | PCC_C | PCC_DC | PCC_Z) // outCond
+};
+
+static pCodeInstruction pciADDFWC = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_ADDFWC,
+ "ADDWFC",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ (PCC_W | PCC_REGISTER | PCC_C), // inCond
+ (PCC_W | PCC_C | PCC_DC | PCC_Z) // outCond
+};
+
+static pCodeInstruction pciASRF = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_ASRF,
+ "ASRF",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ TRUE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ PCC_REGISTER, // inCond
+ (PCC_REGISTER | PCC_C | PCC_Z) // outCond
+};
+
+static pCodeInstruction pciASRFW = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_ASRFW,
+ "ASRF",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ PCC_REGISTER, // inCond
+ (PCC_W | PCC_C | PCC_Z) // outCond
+};
+
+static pCodeInstruction pciBRA = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_BRA,
+ "BRA",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 1, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ TRUE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ PCC_NONE, // inCond
+ PCC_NONE // outCond
+};
+
+static pCodeInstruction pciBRW = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_BRW,
+ "BRW",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 0, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ TRUE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ (PCC_NONE | PCC_W), // inCond
+ PCC_NONE // outCond
+};
+
+static pCodeInstruction pciCALLW = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_CALLW,
+ "CALLW",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 0, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ TRUE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ (PCC_NONE | PCC_W), // inCond, reads lower bits of subroutine address from WREG
+ (PCC_NONE | PCC_W | PCC_C | PCC_DC | PCC_Z) // outCond, flags are destroyed by called function
+};
+
+static pCodeInstruction pciLSLF = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_LSLF,
+ "LSLF",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ TRUE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ PCC_REGISTER, // inCond
+ (PCC_REGISTER | PCC_C | PCC_Z) // outCond
+};
+
+static pCodeInstruction pciLSLFW = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_LSLFW,
+ "LSLF",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ PCC_REGISTER, // inCond
+ (PCC_W | PCC_C | PCC_Z) // outCond
+};
+
+static pCodeInstruction pciLSRF = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_LSRF,
+ "LSRF",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ TRUE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ PCC_REGISTER, // inCond
+ (PCC_REGISTER | PCC_C | PCC_Z) // outCond
+};
+
+static pCodeInstruction pciLSRFW = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_LSRFW,
+ "LSRF",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ PCC_REGISTER, // inCond
+ (PCC_W | PCC_C | PCC_Z) // outCond
+};
+
+static pCodeInstruction pciMOVIW = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_MOVIW,
+ "MOVIW",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 1, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ TRUE, // literal operand
+ POC_NOP,
+ PCC_NONE, // inCond
+ (PCC_NONE | PCC_W | PCC_Z) // outCond
+};
+
+static pCodeInstruction pciMOVIW_K = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_MOVIW_K,
+ "MOVIW",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ TRUE, // literal operand
+ POC_NOP,
+ PCC_NONE, // inCond
+ (PCC_NONE | PCC_W | PCC_Z) // outCond
+};
+
+static pCodeInstruction pciMOVLB = {
+ {PC_OPCODE, NULL, NULL, 0, 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
+ FALSE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ TRUE, // literal operand
+ POC_NOP,
+ PCC_NONE, // inCond
+ PCC_NONE // outCond
+};
+
+static pCodeInstruction pciMOVLP = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_MOVLP,
+ "MOVLP",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 1, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ TRUE, // literal operand
+ POC_NOP,
+ PCC_NONE, // inCond
+ PCC_NONE // outCond
+};
+
+static pCodeInstruction pciMOVWI = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_MOVWI,
+ "MOVWI",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 1, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ TRUE, // literal operand
+ POC_NOP,
+ (PCC_NONE | PCC_W), // inCond
+ PCC_NONE // outCond
+};
+
+static pCodeInstruction pciMOVWI_K = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_MOVWI_K,
+ "MOVWI",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ TRUE, // literal operand
+ POC_NOP,
+ (PCC_NONE | PCC_W), // inCond
+ PCC_NONE // outCond
+};
+
+static pCodeInstruction pciRESET = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_RESET,
+ "RESET",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 0, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ PCC_NONE, // inCond
+ PCC_NONE // outCond
+};
+
+static pCodeInstruction pciSUBWFB = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_SUBWFB,
+ "SUBWFB",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ TRUE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ (PCC_W | PCC_REGISTER | PCC_C), // inCond
+ (PCC_REGISTER | PCC_C | PCC_DC | PCC_Z) // outCond
+};
+
+static pCodeInstruction pciSUBWFBW = {
+ {PC_OPCODE, NULL, NULL, 0, 0, NULL,
+ genericDestruct,
+ genericPrint},
+ POC_SUBWFBW,
+ "SUBWFB",
+ NULL, // from branch
+ NULL, // to branch
+ NULL, // label
+ NULL, // operand
+ NULL, // flow block
+ NULL, // C source
+ 2, // num ops
+ FALSE, // dest
+ FALSE, // bit instruction
+ FALSE, // branch
+ FALSE, // skip
+ FALSE, // literal operand
+ POC_NOP,
+ (PCC_W | PCC_REGISTER | PCC_C), // inCond
+ (PCC_W | PCC_C | PCC_DC | PCC_Z) // outCond
+};
+
+pCodeInstruction *pic14Mnemonics[MAX_PIC14MNEMONICS];
+
+
+/*-----------------------------------------------------------------*/
+/* return a unique ID number to assist pCodes debuging */
+/*-----------------------------------------------------------------*/
+static unsigned PCodeID(void) {
+ static unsigned int pcodeId = 1; /* unique ID number to be assigned to all pCodes */
+ /*
+ static unsigned int stop;
+ if (pcodeId == 1448)
+ stop++; // Place break point here
+ */
+ return pcodeId++;
+}
+
+void pCodeInitRegisters(void)
+{
+ static int initialized=0;
+ int shareBankAddress, stkSize, haveShared;
+ PIC_device *pic;
+
+ if(initialized)
+ return;
+ initialized = 1;
+
+ pic = init_pic(port->processor);
+ haveShared = pic14_getSharedStack(NULL, &shareBankAddress, &stkSize);
+ /* Set pseudo stack size to SHAREBANKSIZE - 3.
+ * On multi memory bank ICs this leaves room for WSAVE/SSAVE/PSAVE
+ * (used for interrupts) to fit into the shared portion of the
+ * memory bank. This is not needed on enhanced processors. */
+ if (!pic->isEnhancedCore)
+ stkSize = stkSize - 3;
+ assert(stkSize >= 0);
+ initStack(shareBankAddress, stkSize, haveShared);
+
+ /* TODO: Read aliases for SFRs from regmap lines in device description. */
+ pc_status.r = allocProcessorRegister(IDX_STATUS,"STATUS", PO_STATUS, 0xf80);
+ pc_pcl.r = allocProcessorRegister(IDX_PCL,"PCL", PO_PCL, 0xf80);
+ pc_pclath.r = allocProcessorRegister(IDX_PCLATH,"PCLATH", PO_PCLATH, 0xf80);
+ pc_indf_.r = allocProcessorRegister(IDX_INDF,"INDF", PO_INDF, 0xf80);
+ pc_indf0.r = allocProcessorRegister(IDX_INDF0,"INDF0", PO_INDF, 0xf80);
+ pc_fsr.r = allocProcessorRegister(IDX_FSR,"FSR", PO_FSR, 0xf80);
+ pc_fsr0l.r = allocProcessorRegister(IDX_FSR0L,"FSR0L", PO_FSR, 0xf80);
+ pc_fsr0h.r = allocProcessorRegister(IDX_FSR0H,"FSR0H", PO_FSR, 0xf80);
+ pc_intcon.r = allocProcessorRegister(IDX_INTCON,"INTCON", PO_INTCON, 0xf80);
+
+ pc_status.rIdx = IDX_STATUS;
+ pc_fsr.rIdx = IDX_FSR;
+ pc_fsr0l.rIdx = IDX_FSR0L;
+ pc_fsr0h.rIdx = IDX_FSR0H;
+ pc_indf_.rIdx = IDX_INDF;
+ pc_indf0.rIdx = IDX_INDF0;
+ pc_intcon.rIdx = IDX_INTCON;
+ pc_pcl.rIdx = IDX_PCL;
+ pc_pclath.rIdx = IDX_PCLATH;
+
+ if (!pic->isEnhancedCore) {
+ /* Interrupt storage for working register - must be same address in all banks ie section SHAREBANK. */
+ pc_wsave.r = allocInternalRegister(IDX_WSAVE,pc_wsave.pcop.name,pc_wsave.pcop.type, pic ? pic->bankMask : 0xf80);
+ /* Interrupt storage for status register. */
+ pc_ssave.r = allocInternalRegister(IDX_SSAVE,pc_ssave.pcop.name,pc_ssave.pcop.type, (pic && haveShared) ? pic->bankMask : 0);
+ /* Interrupt storage for pclath register. */
+ pc_psave.r = allocInternalRegister(IDX_PSAVE,pc_psave.pcop.name,pc_psave.pcop.type, (pic && haveShared) ? pic->bankMask : 0);
+
+ pc_wsave.rIdx = pc_wsave.r->rIdx;
+ pc_ssave.rIdx = pc_ssave.r->rIdx;
+ pc_psave.rIdx = pc_psave.r->rIdx;
+
+ pc_wsave.r->isFixed = 1; /* Some PIC ICs do not have a sharebank - this register needs to be reserved across all banks. */
+ pc_wsave.r->address = shareBankAddress-stkSize;
+ pc_ssave.r->isFixed = 1; /* This register must be in the first bank. */
+ pc_ssave.r->address = shareBankAddress-stkSize-1;
+ pc_psave.r->isFixed = 1; /* This register must be in the first bank. */
+ pc_psave.r->address = shareBankAddress-stkSize-2;
+ }
+
+ /* probably should put this in a separate initialization routine */
+ pb_dead_pcodes = newpBlock();
+
+}
+
+/*-----------------------------------------------------------------*/
+/* mnem2key - convert a pic mnemonic into a hash key */
+/* (BTW - this spreads the mnemonics quite well) */
+/* */
+/*-----------------------------------------------------------------*/
+
+static int mnem2key(unsigned char const *mnem)
+{
+ int key = 0;
+
+ if(!mnem)
+ return 0;
+
+ while(*mnem) {
+
+ key += toupper(*mnem++) +1;
+
+ }
+
+ return (key & 0x1f);
+
+}
+
+static void pic14initMnemonics(void)
+{
+ int i = 0;
+ int key;
+ // char *str;
+ pCodeInstruction *pci;
+
+ if(mnemonics_initialized)
+ return;
+
+ //FIXME - probably should NULL out the array before making the assignments
+ //since we check the array contents below this initialization.
+
+ pic14Mnemonics[POC_ADDLW] = &pciADDLW;
+ pic14Mnemonics[POC_ADDWF] = &pciADDWF;
+ pic14Mnemonics[POC_ADDFW] = &pciADDFW;
+ pic14Mnemonics[POC_ANDLW] = &pciANDLW;
+ pic14Mnemonics[POC_ANDWF] = &pciANDWF;
+ pic14Mnemonics[POC_ANDFW] = &pciANDFW;
+ pic14Mnemonics[POC_BCF] = &pciBCF;
+ pic14Mnemonics[POC_BSF] = &pciBSF;
+ pic14Mnemonics[POC_BTFSC] = &pciBTFSC;
+ pic14Mnemonics[POC_BTFSS] = &pciBTFSS;
+ pic14Mnemonics[POC_CALL] = &pciCALL;
+ pic14Mnemonics[POC_COMF] = &pciCOMF;
+ pic14Mnemonics[POC_COMFW] = &pciCOMFW;
+ pic14Mnemonics[POC_CLRF] = &pciCLRF;
+ pic14Mnemonics[POC_CLRW] = &pciCLRW;
+ pic14Mnemonics[POC_CLRWDT] = &pciCLRWDT;
+ pic14Mnemonics[POC_DECF] = &pciDECF;
+ pic14Mnemonics[POC_DECFW] = &pciDECFW;
+ pic14Mnemonics[POC_DECFSZ] = &pciDECFSZ;
+ pic14Mnemonics[POC_DECFSZW] = &pciDECFSZW;
+ pic14Mnemonics[POC_GOTO] = &pciGOTO;
+ pic14Mnemonics[POC_INCF] = &pciINCF;
+ pic14Mnemonics[POC_INCFW] = &pciINCFW;
+ pic14Mnemonics[POC_INCFSZ] = &pciINCFSZ;
+ pic14Mnemonics[POC_INCFSZW] = &pciINCFSZW;
+ pic14Mnemonics[POC_IORLW] = &pciIORLW;
+ pic14Mnemonics[POC_IORWF] = &pciIORWF;
+ pic14Mnemonics[POC_IORFW] = &pciIORFW;
+ pic14Mnemonics[POC_MOVF] = &pciMOVF;
+ pic14Mnemonics[POC_MOVFW] = &pciMOVFW;
+ pic14Mnemonics[POC_MOVLW] = &pciMOVLW;
+ pic14Mnemonics[POC_MOVWF] = &pciMOVWF;
+ pic14Mnemonics[POC_NOP] = &pciNOP;
+ pic14Mnemonics[POC_RETFIE] = &pciRETFIE;
+ pic14Mnemonics[POC_RETLW] = &pciRETLW;
+ pic14Mnemonics[POC_RETURN] = &pciRETURN;
+ pic14Mnemonics[POC_RLF] = &pciRLF;
+ pic14Mnemonics[POC_RLFW] = &pciRLFW;
+ pic14Mnemonics[POC_RRF] = &pciRRF;
+ pic14Mnemonics[POC_RRFW] = &pciRRFW;
+ pic14Mnemonics[POC_SUBLW] = &pciSUBLW;
+ pic14Mnemonics[POC_SUBWF] = &pciSUBWF;
+ pic14Mnemonics[POC_SUBFW] = &pciSUBFW;
+ pic14Mnemonics[POC_SWAPF] = &pciSWAPF;
+ pic14Mnemonics[POC_SWAPFW] = &pciSWAPFW;
+ pic14Mnemonics[POC_TRIS] = &pciTRIS;
+ pic14Mnemonics[POC_XORLW] = &pciXORLW;
+ pic14Mnemonics[POC_XORWF] = &pciXORWF;
+ pic14Mnemonics[POC_XORFW] = &pciXORFW;
+ pic14Mnemonics[POC_BANKSEL] = &pciBANKSEL;
+ pic14Mnemonics[POC_PAGESEL] = &pciPAGESEL;
+
+ /* Enhanced instruction set. */
+
+ pic14Mnemonics[POC_ADDFSR] = &pciADDFSR;
+ pic14Mnemonics[POC_ADDWFC] = &pciADDWFC;
+ pic14Mnemonics[POC_ADDFWC] = &pciADDFWC;
+ pic14Mnemonics[POC_ASRF] = &pciASRF;
+ pic14Mnemonics[POC_ASRFW] = &pciASRFW;
+ pic14Mnemonics[POC_BRA] = &pciBRA;
+ pic14Mnemonics[POC_BRW] = &pciBRW;
+ pic14Mnemonics[POC_CALLW] = &pciCALLW;
+ pic14Mnemonics[POC_LSLF] = &pciLSLF;
+ pic14Mnemonics[POC_LSLFW] = &pciLSLFW;
+ pic14Mnemonics[POC_LSRF] = &pciLSRF;
+ pic14Mnemonics[POC_LSRFW] = &pciLSRFW;
+ pic14Mnemonics[POC_MOVIW] = &pciMOVIW;
+ pic14Mnemonics[POC_MOVIW_K] = &pciMOVIW_K;
+ pic14Mnemonics[POC_MOVLB] = &pciMOVLB;
+ pic14Mnemonics[POC_MOVLP] = &pciMOVLP;
+ pic14Mnemonics[POC_MOVWI] = &pciMOVWI;
+ pic14Mnemonics[POC_MOVWI_K] = &pciMOVWI_K;
+ pic14Mnemonics[POC_RESET] = &pciRESET;
+ pic14Mnemonics[POC_SUBWFB] = &pciSUBWFB;
+ pic14Mnemonics[POC_SUBWFBW] = &pciSUBWFBW;
+
+
+ for(i=0; i<MAX_PIC14MNEMONICS; i++)
+ if(pic14Mnemonics[i])
+ hTabAddItem(&pic14MnemonicsHash, mnem2key((unsigned char *)pic14Mnemonics[i]->mnemonic), pic14Mnemonics[i]);
+ pci = hTabFirstItem(pic14MnemonicsHash, &key);
+
+ while(pci) {
+ DFPRINTF((stderr, "element %d key %d, mnem %s\n",i++,key,pci->mnemonic));
+ pci = hTabNextItem(pic14MnemonicsHash, &key);
+ }
+
+ mnemonics_initialized = 1;
+}
+
+int getpCode(const char *mnem, unsigned dest)
+{
+
+ pCodeInstruction *pci;
+ int key = mnem2key((const unsigned char *)mnem);
+
+ if(!mnemonics_initialized)
+ pic14initMnemonics();
+
+ pci = hTabFirstItemWK(pic14MnemonicsHash, key);
+
+ while(pci) {
+
+ if(STRCASECMP(pci->mnemonic, mnem) == 0) {
+ if((pci->num_ops <= 1) || (pci->isModReg == dest) || (pci->isBitInst))
+ return(pci->op);
+ }
+
+ pci = hTabNextItemWK (pic14MnemonicsHash);
+
+ }
+
+ return -1;
+}
+
+/*-----------------------------------------------------------------*
+* pic14initpCodePeepCommands
+*
+*-----------------------------------------------------------------*/
+void pic14initpCodePeepCommands(void)
+{
+
+ int key, i;
+ peepCommand *pcmd;
+
+ i = 0;
+ do {
+ hTabAddItem(&pic14pCodePeepCommandsHash,
+ mnem2key((const unsigned char *)peepCommands[i].cmd), &peepCommands[i]);
+ i++;
+ } while (peepCommands[i].cmd);
+
+ pcmd = hTabFirstItem(pic14pCodePeepCommandsHash, &key);
+
+ while(pcmd) {
+ //fprintf(stderr, "peep command %s key %d\n",pcmd->cmd,pcmd->id);
+ pcmd = hTabNextItem(pic14pCodePeepCommandsHash, &key);
+ }
+
+}
+
+/*-----------------------------------------------------------------
+*
+*
+*-----------------------------------------------------------------*/
+
+int getpCodePeepCommand(const char *cmd)
+{
+
+ peepCommand *pcmd;
+ int key = mnem2key((const unsigned char *)cmd);
+
+
+ pcmd = hTabFirstItemWK(pic14pCodePeepCommandsHash, key);
+
+ while(pcmd) {
+ // fprintf(stderr," comparing %s to %s\n",pcmd->cmd,cmd);
+ if(STRCASECMP(pcmd->cmd, cmd) == 0) {
+ return pcmd->id;
+ }
+
+ pcmd = hTabNextItemWK (pic14pCodePeepCommandsHash);
+
+ }
+
+ return -1;
+}
+
+static char getpBlock_dbName(pBlock *pb)
+{
+ if(!pb)
+ return 0;
+
+ if(pb->cmemmap)
+ return pb->cmemmap->dbName;
+
+ return pb->dbName;
+}
+
+void pBlockConvert2ISR(pBlock *pb)
+{
+ if(!pb)
+ return;
+
+ if(pb->cmemmap)
+ pb->cmemmap = NULL;
+
+ pb->dbName = 'I';
+}
+
+/*-----------------------------------------------------------------*/
+/* movepBlock2Head - given the dbname of a pBlock, move all */
+/* instances to the front of the doubly linked */
+/* list of pBlocks */
+/*-----------------------------------------------------------------*/
+
+void movepBlock2Head(char dbName)
+{
+ pBlock *pb;
+
+ if (!the_pFile)
+ return;
+
+ 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 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);
+ printpBlock(of,pb);
+ fprintf (of, "\n");
+ }
+ }
+}
+
+void resetpCodeStatistics (void)
+{
+ pcode_insns = pcode_doubles = 0;
+}
+
+void dumppCodeStatistics (FILE *of)
+{
+ /* dump statistics */
+ fprintf (of, "\n");
+ fprintf (of, ";\tcode size estimation:\n");
+ fprintf (of, ";\t%5u+%5u = %5u instructions (%5u byte)\n", pcode_insns, pcode_doubles, pcode_insns + pcode_doubles, 2*(pcode_insns + 2*pcode_doubles));
+ fprintf (of, "\n");
+}
+
+void pcode_test(void)
+{
+ DFPRINTF((stderr,"pcode is alive!\n"));
+
+ //initMnemonics();
+
+ if(the_pFile) {
+
+ pBlock *pb;
+ FILE *pFile;
+ char buffer[100];
+
+ /* create the file name */
+ SNPRINTF(buffer, sizeof(buffer), "%s.p", dstFileName);
+
+ 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));
+ 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) {
+ const char *name = pcop->name;
+ if (!name)
+ name = PCOR(pcop)->r->name;
+ if (strcmp(name, pc_status.pcop.name) == 0)
+ {
+ 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;
+}
+
+/*-----------------------------------------------------------------*/
+/* 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 *newpCode (PIC_OPCODE op, pCodeOp *pcop)
+{
+ pCodeInstruction *pci ;
+
+ if(!mnemonics_initialized)
+ pic14initMnemonics();
+
+ pci = Safe_alloc(sizeof(pCodeInstruction));
+
+ if((op>=0) && (op < MAX_PIC14MNEMONICS) && pic14Mnemonics[op]) {
+ memcpy(pci, pic14Mnemonics[op], sizeof(pCodeInstruction));
+ pci->pc.id = PCodeID();
+ 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;
+}
+
+/*-----------------------------------------------------------------*/
+/* 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 *newpCodeWild(int pCodeID, pCodeOp *optional_operand, pCodeOp *optional_label)
+{
+ pCodeWild *pcw;
+
+ pcw = Safe_alloc(sizeof(pCodeWild));
+
+ pcw->pci.pc.type = PC_WILD;
+ pcw->pci.pc.prev = pcw->pci.pc.next = NULL;
+ pcw->id = PCodeID();
+ pcw->pci.from = pcw->pci.to = pcw->pci.label = NULL;
+ pcw->pci.pc.pb = NULL;
+
+ 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);
+}
+
+/*-----------------------------------------------------------------*/
+/* newPcodeCharP - create a new pCode from a char string */
+/*-----------------------------------------------------------------*/
+
+pCode *newpCodeCharP(const char *cP)
+{
+ pCodeComment *pcc;
+
+ pcc = Safe_alloc(sizeof(pCodeComment));
+
+ pcc->pc.type = PC_COMMENT;
+ pcc->pc.prev = pcc->pc.next = NULL;
+ pcc->pc.id = PCodeID();
+ //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
+ pcc->pc.pb = NULL;
+
+ pcc->pc.destruct = genericDestruct;
+ pcc->pc.print = genericPrint;
+
+ if(cP)
+ pcc->comment = Safe_strdup(cP);
+ else
+ pcc->comment = NULL;
+
+ return ((pCode *)pcc);
+}
+
+/*-----------------------------------------------------------------*/
+/* newpCodeFunction - */
+/*-----------------------------------------------------------------*/
+
+pCode *newpCodeFunction(const char *mod, const char *f, int isPublic, int isInterrupt)
+{
+ pCodeFunction *pcf;
+
+ pcf = Safe_alloc(sizeof(pCodeFunction));
+
+ pcf->pc.type = PC_FUNCTION;
+ pcf->pc.prev = pcf->pc.next = NULL;
+ pcf->pc.id = PCodeID();
+ //pcf->pc.from = pcf->pc.to = pcf->pc.label = NULL;
+ pcf->pc.pb = NULL;
+
+ pcf->pc.destruct = genericDestruct;
+ pcf->pc.print = pCodePrintFunction;
+
+ pcf->ncalled = 0;
+
+ pcf->modname = (mod != NULL) ? Safe_strdup(mod) : NULL;
+ pcf->fname = (f != NULL) ? Safe_strdup(f) : NULL;
+
+ pcf->isPublic = (unsigned int)isPublic;
+ pcf->isInterrupt = (unsigned int)isInterrupt;
+
+ return ((pCode *)pcf);
+}
+
+/*-----------------------------------------------------------------*/
+/* newpCodeFlow */
+/*-----------------------------------------------------------------*/
+static void destructpCodeFlow(pCode *pc)
+{
+ if(!pc || !isPCFL(pc))
+ return;
+
+ /*
+ if(PCFL(pc)->from)
+ if(PCFL(pc)->to)
+ */
+ unlinkpCode(pc);
+
+ deleteSet(&PCFL(pc)->registers);
+ deleteSet(&PCFL(pc)->from);
+ deleteSet(&PCFL(pc)->to);
+ free(pc);
+}
+
+static pCode *newpCodeFlow(void )
+{
+ pCodeFlow *pcflow;
+
+ pcflow = Safe_alloc(sizeof(pCodeFlow));
+
+ pcflow->pc.type = PC_FLOW;
+ pcflow->pc.prev = pcflow->pc.next = NULL;
+ pcflow->pc.pb = NULL;
+
+ 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 = 'U'; /* Undetermined */
+ pcflow->lastBank = 'U'; /* Undetermined */
+
+ pcflow->FromConflicts = 0;
+ pcflow->ToConflicts = 0;
+
+ pcflow->end = NULL;
+
+ pcflow->registers = newSet();
+
+ return ((pCode *)pcflow);
+}
+
+/*-----------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+static pCodeFlowLink *newpCodeFlowLink(pCodeFlow *pcflow)
+{
+ pCodeFlowLink *pcflowLink;
+
+ pcflowLink = Safe_alloc(sizeof(pCodeFlowLink));
+
+ pcflowLink->pcflow = pcflow;
+ pcflowLink->bank_conflict = 0;
+
+ return pcflowLink;
+}
+
+/*-----------------------------------------------------------------*/
+/* newpCodeCSource - create a new pCode Source Symbol */
+/*-----------------------------------------------------------------*/
+
+pCode *newpCodeCSource(int ln, const char *f, const char *l)
+{
+ pCodeCSource *pccs;
+
+ pccs = Safe_alloc(sizeof(pCodeCSource));
+
+ pccs->pc.type = PC_CSOURCE;
+ pccs->pc.prev = pccs->pc.next = NULL;
+ pccs->pc.id = PCodeID();
+ 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);
+}
+
+/*******************************************************************/
+/* pic16_newpCodeAsmDir - create a new pCode Assembler Directive */
+/* added by VR 6-Jun-2003 */
+/*******************************************************************/
+
+pCode *newpCodeAsmDir(const char *asdir, const char *argfmt, ...)
+{
+ pCodeAsmDir *pcad;
+ va_list ap;
+ char buffer[512];
+ char *lbp=buffer;
+
+ pcad = Safe_alloc(sizeof(pCodeAsmDir));
+ pcad->pci.pc.type = PC_ASMDIR;
+ pcad->pci.pc.prev = pcad->pci.pc.next = NULL;
+ pcad->pci.pc.pb = NULL;
+ pcad->pci.pc.destruct = genericDestruct;
+ pcad->pci.pc.print = genericPrint;
+
+ if(asdir && *asdir) {
+ while(isspace((unsigned char)*asdir)) asdir++; // strip any white space from the beginning
+
+ pcad->directive = Safe_strdup(asdir);
+ }
+
+ va_start(ap, argfmt);
+
+ memset(buffer, 0, sizeof(buffer));
+ if(argfmt && *argfmt)
+ vsprintf(buffer, argfmt, ap);
+
+ va_end(ap);
+
+ while(isspace((unsigned char)*lbp)) lbp++;
+
+ if(lbp && *lbp)
+ pcad->arg = Safe_strdup(lbp);
+
+ return ((pCode *)pcad);
+}
+
+/*-----------------------------------------------------------------*/
+/* 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 *newpCodeLabel(const char *name, int key)
+{
+ const char *s;
+ pCodeLabel *pcl;
+
+ pcl = Safe_alloc(sizeof(pCodeLabel));
+
+ pcl->pc.type = PC_LABEL;
+ pcl->pc.prev = pcl->pc.next = NULL;
+ pcl->pc.id = PCodeID();
+ //pcl->pc.from = pcl->pc.to = pcl->pc.label = NULL;
+ pcl->pc.pb = NULL;
+
+ pcl->pc.destruct = pCodeLabelDestruct;
+ pcl->pc.print = pCodePrintLabel;
+
+ pcl->key = key;
+
+ pcl->label = NULL;
+ if(key>0) {
+ SNPRINTF(buffer, sizeof(buffer), "_%05d_DS_", key);
+ s = buffer;
+ } else {
+/* SNPRINTF(buffer, sizeof(buffer), "%s:", name);
+ s = buffer;*/
+ s = name;
+ }
+
+ if(s)
+ pcl->label = Safe_strdup(s);
+
+ //fprintf(stderr,"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_alloc(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;
+}
+
+/*-----------------------------------------------------------------*/
+/* 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 *newpCodeChain(memmap *cm,char c, pCode *pc)
+{
+ pBlock *pB = newpBlock();
+
+ pB->pcHead = pB->pcTail = pc;
+ pB->cmemmap = cm;
+ pB->dbName = c;
+
+ return pB;
+}
+
+/*-----------------------------------------------------------------*/
+/* 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 *newpCodeOpLabel(const char *name, int key)
+{
+ const char *s;
+ static int label_key = -1;
+
+ pCodeOp *pcop;
+
+ pcop = Safe_alloc(sizeof(pCodeOpLabel));
+ pcop->type = PO_LABEL;
+
+ pcop->name = NULL;
+
+ if(key>0) {
+ SNPRINTF(buffer, sizeof(buffer), "_%05d_DS_", key);
+ s = buffer;
+ }
+ else {
+ s = name;
+ key = label_key--;
+ }
+
+ PCOLAB(pcop)->offset = 0;
+ if(s)
+ pcop->name = Safe_strdup(s);
+
+ ((pCodeOpLabel *)pcop)->key = key;
+
+ //fprintf(stderr,"newpCodeOpLabel: key=%d, name=%s\n",key,((s)?s:""));
+ return pcop;
+}
+
+/*-----------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+pCodeOp *newpCodeOpLit(int lit)
+{
+ pCodeOp *pcop;
+
+ pcop = Safe_alloc(sizeof(pCodeOpLit));
+ pcop->type = PO_LITERAL;
+
+ pcop->name = NULL;
+ if(lit>=0) {
+ SNPRINTF(buffer, sizeof(buffer),"0x%02x", (unsigned char)lit);
+ pcop->name = Safe_strdup(buffer);
+ }
+
+ ((pCodeOpLit *)pcop)->lit = (unsigned char)lit;
+
+ return pcop;
+}
+
+/*-----------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+pCodeOp *newpCodeOpImmd(const char *name, int offset, int index, int code_space, int is_func)
+{
+ pCodeOp *pcop;
+
+ pcop = Safe_alloc(sizeof(pCodeOpImmd));
+ pcop->type = PO_IMMEDIATE;
+ if(name) {
+ reg_info *r = NULL;
+ pcop->name = Safe_strdup(name);
+
+ if(!is_func)
+ r = dirregWithName(name);
+
+ PCOI(pcop)->r = r;
+ if(r) {
+ //fprintf(stderr, " newpCodeOpImmd reg %s exists\n",name);
+ PCOI(pcop)->rIdx = r->rIdx;
+ } else {
+ //fprintf(stderr, " 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;
+ PCOI(pcop)->_function = is_func;
+
+ return pcop;
+}
+
+/*-----------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+pCodeOp *newpCodeOpWild(int id, pCodeWildBlock *pcwb, pCodeOp *subtype)
+{
+ pCodeOp *pcop;
+
+ if(!pcwb || !subtype) {
+ fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
+ exit(1);
+ }
+
+ pcop = Safe_alloc(sizeof(pCodeOpWild));
+ pcop->type = PO_WILD;
+ SNPRINTF(buffer, sizeof(buffer), "%%%d", id);
+ pcop->name = Safe_strdup(buffer);
+
+ PCOW(pcop)->id = id;
+ PCOW(pcop)->pcwb = pcwb;
+ PCOW(pcop)->subtype = subtype;
+ PCOW(pcop)->matched = NULL;
+
+ return pcop;
+}
+
+/*-----------------------------------------------------------------*/
+/* Find a symbol with matching name */
+/*-----------------------------------------------------------------*/
+static symbol *symFindWithName(memmap * map, const char *name)
+{
+ symbol *sym;
+
+ for (sym = setFirstItem(map->syms); sym; sym = setNextItem (map->syms)) {
+ if (sym->rname && (strcmp(sym->rname,name)==0))
+ return sym;
+ }
+ return 0;
+}
+
+/*-----------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+pCodeOp *newpCodeOpBit(const char *name, int ibit, int inBitSpace)
+{
+ pCodeOp *pcop;
+ struct reg_info *r = 0;
+
+ pcop = Safe_alloc(sizeof(pCodeOpRegBit));
+ pcop->type = PO_GPR_BIT;
+
+ PCORB(pcop)->bit = ibit;
+ PCORB(pcop)->inBitSpace = inBitSpace;
+
+ if (name) r = regFindWithName(name);
+ if (name && !r) {
+ // Register has not been allocated - check for symbol information
+ symbol *sym;
+ sym = symFindWithName(bit, name);
+ if (!sym) sym = symFindWithName(sfrbit, name);
+ if (!sym) sym = symFindWithName(sfr, name);
+ if (!sym) sym = symFindWithName(reg, name);
+ // Hack to fix accesses to _INTCON_bits (e.g. GIE=0), see #1579535.
+ // XXX: This ignores nesting levels, but works for globals...
+ if (!sym) sym = findSym(SymbolTab, NULL, name);
+ if (!sym && name && name[0] == '_') sym = findSym(SymbolTab, NULL, &name[1]);
+ if (sym) {
+ r = allocNewDirReg(sym->etype,name);
+ }
+ }
+ if (r) {
+ pcop->name = NULL;
+ PCOR(pcop)->r = r;
+ PCOR(pcop)->rIdx = r->rIdx;
+ } else if (name) {
+ pcop->name = Safe_strdup(name);
+ PCOR(pcop)->r = NULL;
+ PCOR(pcop)->rIdx = 0;
+ } else {
+ //fprintf(stderr, "Unnamed register duplicated for bit-access?!? Hope for the best ...\n");
+ }
+ return pcop;
+}
+
+/*-----------------------------------------------------------------*
+* pCodeOp *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.
+*-----------------------------------------------------------------*/
+
+static pCodeOp *newpCodeOpReg(int rIdx)
+{
+ pCodeOp *pcop;
+
+ pcop = Safe_alloc(sizeof(pCodeOpReg));
+
+ pcop->name = NULL;
+
+ if(rIdx >= 0) {
+ PCOR(pcop)->rIdx = rIdx;
+ PCOR(pcop)->r = pic14_regWithIdx(rIdx);
+ } else {
+ PCOR(pcop)->r = pic14_findFreeReg(REG_GPR);
+
+ if(PCOR(pcop)->r)
+ PCOR(pcop)->rIdx = PCOR(pcop)->r->rIdx;
+ }
+
+ if(PCOR(pcop)->r)
+ pcop->type = PCOR(pcop)->r->pc_type;
+
+ return pcop;
+}
+
+pCodeOp *newpCodeOpRegFromStr(const char *name)
+{
+ pCodeOp *pcop;
+
+ pcop = Safe_alloc(sizeof(pCodeOpReg));
+ PCOR(pcop)->r = 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;
+}
+
+static pCodeOp *newpCodeOpStr(const char *name)
+{
+ pCodeOp *pcop;
+
+ pcop = Safe_alloc(sizeof(pCodeOpStr));
+ pcop->type = PO_STR;
+ pcop->name = Safe_strdup(name);
+
+ PCOS(pcop)->isPublic = 0;
+
+ return pcop;
+}
+
+
+/*-----------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+
+pCodeOp *newpCodeOp(const char *name, PIC_OPTYPE type)
+{
+ pCodeOp *pcop;
+
+ switch(type) {
+ case PO_BIT:
+ case PO_GPR_BIT:
+ pcop = newpCodeOpBit(name, -1, 0);
+ break;
+
+ case PO_LITERAL:
+ pcop = newpCodeOpLit(-1);
+ break;
+
+ case PO_LABEL:
+ pcop = newpCodeOpLabel(NULL,-1);
+ break;
+
+ case PO_GPR_TEMP:
+ pcop = newpCodeOpReg(-1);
+ break;
+
+ case PO_GPR_POINTER:
+ case PO_GPR_REGISTER:
+ if(name)
+ pcop = newpCodeOpRegFromStr(name);
+ else
+ pcop = newpCodeOpReg(-1);
+ break;
+
+ case PO_STR:
+ pcop = newpCodeOpStr(name);
+ break;
+
+ default:
+ pcop = Safe_alloc(sizeof(pCodeOp));
+ pcop->type = type;
+ pcop->name = (name != NULL) ? Safe_strdup(name) : NULL;
+ }
+
+ return pcop;
+}
+
+/*-----------------------------------------------------------------*/
+/* addpCode2pBlock - place the pCode into the pBlock linked list */
+/*-----------------------------------------------------------------*/
+void addpCode2pBlock(pBlock *pb, pCode *pc)
+{
+
+ if(!pb || !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;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* addpBlock - place a pBlock into the pFile */
+/*-----------------------------------------------------------------*/
+void 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_alloc(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 */
+/*-----------------------------------------------------------------*/
+
+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");
+}
+
+/*-----------------------------------------------------------------*/
+/* printpBlock - write the contents of a pBlock to a file */
+/*-----------------------------------------------------------------*/
+
+void printpBlock(FILE *of, pBlock *pb)
+{
+ pCode *pc;
+
+ if(!pb)
+ return;
+
+ if(!of)
+ of = stderr;
+
+ for(pc = pb->pcHead; pc; pc = pc->next) {
+ if(isPCF(pc) && PCF(pc)->fname && !PCF(pc)->isInterrupt) {
+ fprintf(of, "S_%s_%s\tcode\n", PCF(pc)->modname, PCF(pc)->fname);
+ }
+ printpCode(of,pc);
+
+ if (isPCI(pc))
+ {
+ if (isPCI(pc) && (PCI(pc)->op == POC_PAGESEL || PCI(pc)->op == POC_BANKSEL)) {
+ pcode_doubles++;
+ } else {
+ pcode_insns++;
+ }
+ }
+ } // for
+}
+
+/*-----------------------------------------------------------------*/
+/* */
+/* pCode processing */
+/* */
+/* */
+/* */
+/*-----------------------------------------------------------------*/
+
+void 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;
+
+#if 0
+ /* RN: I believe this should be right here, but this did not
+ * cure the bug I was hunting... */
+ /* must keep labels -- attach to following instruction */
+ if (isPCI(pc) && PCI(pc)->label && pc->next)
+ {
+ pCodeInstruction *pcnext = PCI(findNextInstruction (pc->next));
+ if (pcnext)
+ {
+ pBranchAppend (pcnext->label, PCI(pc)->label);
+ }
+ }
+#endif
+ pc->prev = pc->next = NULL;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+
+static void genericDestruct(pCode *pc)
+{
+ unlinkpCode(pc);
+
+ if(isPCI(pc)) {
+ /* For instructions, tell the register (if there's one used)
+ * that it's no longer needed */
+ reg_info *reg = 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;
+
+ addpCode2pBlock(pb_dead_pcodes, pc);
+
+ //free(pc);
+}
+
+
+/*-----------------------------------------------------------------*/
+/* Copies the pCodeInstruction flow pointer from source pCode */
+/*-----------------------------------------------------------------*/
+static void CopyFlow(pCodeInstruction *pcd, pCode *pcs) {
+ pCode *p;
+ pCodeFlow *pcflow = 0;
+ for (p=pcs; p; p=p->prev) {
+ if (isPCI(p)) {
+ pcflow = PCI(p)->pcflow;
+ break;
+ }
+ if (isPCF(p)) {
+ pcflow = (pCodeFlow*)p;
+ break;
+ }
+ }
+ PCI(pcd)->pcflow = pcflow;
+}
+
+/*-----------------------------------------------------------------*/
+/* pCodeInsertAfter - splice in the pCode chain starting with pc2 */
+/* into the pCode chain containing pc1 */
+/*-----------------------------------------------------------------*/
+void 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;
+
+ /* If this is an instrution type propogate the flow */
+ if (isPCI(pc2))
+ CopyFlow(PCI(pc2),pc1);
+}
+
+/*------------------------------------------------------------------*/
+/* pCodeInsertBefore - splice in the pCode chain starting with pc2 */
+/* into the pCode chain containing pc1 */
+/*------------------------------------------------------------------*/
+void pCodeInsertBefore(pCode *pc1, pCode *pc2)
+{
+ if(!pc1 || !pc2)
+ return;
+
+ pc2->prev = pc1->prev;
+ if(pc1->prev)
+ pc1->prev->next = pc2;
+
+ pc2->pb = pc1->pb;
+ pc2->next = pc1;
+ pc1->prev = pc2;
+
+ /* If this is an instrution type propogate the flow */
+ if (isPCI(pc2))
+ CopyFlow(PCI(pc2),pc1);
+}
+
+/*-----------------------------------------------------------------*/
+/* pCodeOpCopy - copy a pcode operator */
+/*-----------------------------------------------------------------*/
+pCodeOp *pCodeOpCopy(pCodeOp *pcop)
+{
+ pCodeOp *pcopnew=NULL;
+
+ if(!pcop)
+ return NULL;
+
+ switch(pcop->type) {
+ case PO_NONE:
+ case PO_STR:
+ pcopnew = Safe_malloc(sizeof(pCodeOp));
+ memcpy(pcopnew, pcop, sizeof(pCodeOp));
+ break;
+
+ case PO_W:
+ case PO_STATUS:
+ case PO_FSR:
+ case PO_INDF:
+ case PO_INTCON:
+ case PO_GPR_REGISTER:
+ case PO_GPR_TEMP:
+ case PO_GPR_POINTER:
+ case PO_SFR_REGISTER:
+ case PO_PCL:
+ case PO_PCLATH:
+ case PO_DIR:
+ //DFPRINTF((stderr,"pCodeOpCopy GPR register\n"));
+ pcopnew = Safe_malloc(sizeof(pCodeOpReg));
+ memcpy(pcopnew, pcop, sizeof(pCodeOpReg));
+ DFPRINTF((stderr," register index %d\n", PCOR(pcop)->r->rIdx));
+ break;
+
+ case PO_LITERAL:
+ //DFPRINTF((stderr,"pCodeOpCopy lit\n"));
+ pcopnew = Safe_malloc(sizeof(pCodeOpLit));
+ memcpy(pcopnew, pcop, sizeof(pCodeOpLit));
+ break;
+
+ case PO_IMMEDIATE:
+ pcopnew = Safe_malloc(sizeof(pCodeOpImmd));
+ memcpy(pcopnew, pcop, sizeof(pCodeOpImmd));
+ break;
+
+ case PO_GPR_BIT:
+ case PO_CRY:
+ case PO_BIT:
+ //DFPRINTF((stderr,"pCodeOpCopy bit\n"));
+ pcopnew = Safe_malloc(sizeof(pCodeOpRegBit));
+ memcpy(pcopnew, pcop, sizeof(pCodeOpRegBit));
+ break;
+
+ case PO_LABEL:
+ //DFPRINTF((stderr,"pCodeOpCopy label\n"));
+ pcopnew = Safe_malloc(sizeof(pCodeOpLabel));
+ memcpy(pcopnew, pcop, sizeof(pCodeOpLabel));
+ 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 = pCodeOpCopy(PCOW(pcop)->matched);
+ else {
+ // Probably a label
+ pcopnew = 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;
+
+ default:
+ assert ( !"unhandled pCodeOp type copied" );
+ break;
+ } // switch
+
+ pcopnew->name = (pcop->name != NULL) ? Safe_strdup(pcop->name) : NULL;
+
+ return pcopnew;
+}
+
+/*-----------------------------------------------------------------*/
+/* popCopyReg - copy a pcode operator */
+/*-----------------------------------------------------------------*/
+pCodeOp *popCopyReg(pCodeOpReg *pc)
+{
+ pCodeOpReg *pcor;
+
+ pcor = Safe_alloc(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;
+
+ if (pcor->pcop.type == PO_IMMEDIATE){
+ PCOL(pcor)->lit = PCOL(pc)->lit;
+ } else {
+ pcor->r = pc->r;
+ pcor->rIdx = pc->rIdx;
+ if (pcor->r)
+ pcor->r->wasUsed=1;
+ }
+ //DEBUGpic14_emitcode ("; ***","%s , copying %s, rIdx=%d",__FUNCTION__,pc->pcop.name,pc->rIdx);
+
+ return PCOP(pcor);
+}
+
+/*-----------------------------------------------------------------*/
+/* pCodeInstructionCopy - copy a pCodeInstructionCopy */
+/*-----------------------------------------------------------------*/
+pCode *pCodeInstructionCopy(pCodeInstruction *pci,int invert)
+{
+ pCodeInstruction *new_pci;
+
+ if(invert)
+ new_pci = PCI(newpCode(pci->inverted_op,pci->pcop));
+ else
+ new_pci = PCI(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);
+}
+
+/*-----------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+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;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+char *get_op(pCodeOp *pcop,char *buffer, size_t size)
+{
+ reg_info *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_INDF:
+ case PO_FSR:
+ if(use_buffer) {
+ SNPRINTF(buffer,size,"%s",PCOR(pcop)->r->name);
+ return buffer;
+ }
+ return pcop->name;
+ break;
+ case PO_GPR_TEMP:
+ if (PCOR(pcop)->r->type == REG_STK)
+ r = typeRegWithIdx(PCOR(pcop)->r->rIdx,REG_STK,1);
+ else
+ r = pic14_regWithIdx(PCOR(pcop)->r->rIdx);
+
+ if(use_buffer) {
+ SNPRINTF(buffer,size,"%s",r->name);
+ return buffer;
+ }
+
+ return r->name;
+ break;
+
+ case PO_IMMEDIATE:
+ s = buffer;
+ if(PCOI(pcop)->_const) {
+
+ if( PCOI(pcop)->offset >= 0 && PCOI(pcop)->offset<4) {
+ switch(PCOI(pcop)->offset) {
+ case 0:
+ SNPRINTF(s,size,"low (%s+%d)",pcop->name, PCOI(pcop)->index);
+ break;
+ case 1:
+ SNPRINTF(s,size,"high (%s+%d)",pcop->name, PCOI(pcop)->index);
+ break;
+ case 2:
+ SNPRINTF(s,size,"0x%02x",PCOI(pcop)->_const ? GPTRTAG_CODE : GPTRTAG_DATA);
+ break;
+ default:
+ fprintf (stderr, "PO_IMMEDIATE/_const/offset=%d\n", PCOI(pcop)->offset);
+ assert ( !"offset too large" );
+ SNPRINTF(s,size,"(((%s+%d) >> %d)&0xff)",
+ pcop->name,
+ PCOI(pcop)->index,
+ 8 * PCOI(pcop)->offset );
+ }
+ } else
+ SNPRINTF(s,size,"LOW (%s+%d)",pcop->name,PCOI(pcop)->index);
+ } else {
+ if( !PCOI(pcop)->offset) { // && PCOI(pcc->pcop)->offset<4)
+ SNPRINTF(s,size,"(%s + %d)",
+ pcop->name,
+ PCOI(pcop)->index);
+ } else {
+ switch(PCOI(pcop)->offset) {
+ case 0:
+ SNPRINTF(s,size,"(%s + %d)",pcop->name, PCOI(pcop)->index);
+ break;
+ case 1:
+ SNPRINTF(s,size,"high (%s + %d)",pcop->name, PCOI(pcop)->index);
+ break;
+ case 2:
+ SNPRINTF(s,size,"0x%02x",PCOI(pcop)->_const ? GPTRTAG_CODE : GPTRTAG_DATA);
+ break;
+ default:
+ fprintf (stderr, "PO_IMMEDIATE/mutable/offset=%d\n", PCOI(pcop)->offset);
+ assert ( !"offset too large" );
+ SNPRINTF(s,size,"((%s + %d) >> %d)&0xff",pcop->name, PCOI(pcop)->index, 8*PCOI(pcop)->offset);
+ break;
+ }
+ }
+ }
+ return buffer;
+ break;
+
+ case PO_DIR:
+ s = buffer;
+ if( PCOR(pcop)->instance) {
+ SNPRINTF(s,size,"(%s + %d)",
+ pcop->name,
+ PCOR(pcop)->instance );
+ } else
+ SNPRINTF(s,size,"%s",pcop->name);
+ return buffer;
+ break;
+
+ case PO_LABEL:
+ s = buffer;
+ if (pcop->name) {
+ if(PCOLAB(pcop)->offset == 1)
+ SNPRINTF(s,size,"HIGH(%s)",pcop->name);
+ else
+ SNPRINTF(s,size,"%s",pcop->name);
+ }
+ return buffer;
+ break;
+
+ case PO_GPR_BIT:
+ if(PCOR(pcop)->r) {
+ if(use_buffer) {
+ SNPRINTF(buffer,size,"%s",PCOR(pcop)->r->name);
+ return buffer;
+ }
+ return PCOR(pcop)->r->name;
+ }
+ /* fall through to the default case */
+
+ default:
+ if(pcop->name) {
+ if(use_buffer) {
+ SNPRINTF(buffer,size,"%s",pcop->name);
+ return buffer;
+ }
+ return pcop->name;
+ }
+ }
+ }
+
+ printf("PIC port internal warning: (%s:%d(%s)) %s not found\n",
+ __FILE__, __LINE__, __FUNCTION__,
+ pCodeOpType(pcop));
+
+ return "NO operand";
+}
+
+/*-----------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+static char *get_op_from_instruction( pCodeInstruction *pcc)
+{
+ if(pcc)
+ return get_op(pcc->pcop,NULL,0);
+
+ return ("ERROR Null: get_op_from_instruction");
+}
+
+/*-----------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+static void pCodeOpPrint(FILE *of, pCodeOp *pcop)
+{
+ fprintf(of,"pcodeopprint- not implemented\n");
+}
+
+/*-----------------------------------------------------------------*/
+/* pCode2str - convert a pCode instruction to string */
+/*-----------------------------------------------------------------*/
+char *pCode2str(char *str, size_t size, pCode *pc)
+{
+ char *s = str;
+
+ switch(pc->type) {
+
+ case PC_OPCODE:
+
+ SNPRINTF(s,size, "\t%s\t", PCI(pc)->mnemonic);
+ size -= strlen(s);
+ s += strlen(s);
+
+ if( (PCI(pc)->num_ops >= 1) && (PCI(pc)->pcop)) {
+ if(PCI(pc)->isBitInst) {
+ if(PCI(pc)->pcop->type == PO_GPR_BIT) {
+ char *name = PCI(pc)->pcop->name;
+ if (!name)
+ name = PCOR(PCI(pc)->pcop)->r->name;
+ if( (((pCodeOpRegBit *)(PCI(pc)->pcop))->inBitSpace) )
+ SNPRINTF(s,size,"(%s >> 3), (%s & 7)", name, name);
+ else
+ SNPRINTF(s,size,"%s,%d", name, (((pCodeOpRegBit *)(PCI(pc)->pcop))->bit)&7);
+ } else if(PCI(pc)->pcop->type == PO_GPR_BIT) {
+ SNPRINTF(s,size,"%s,%d", get_op_from_instruction(PCI(pc)),PCORB(PCI(pc)->pcop)->bit);
+ } else
+ SNPRINTF(s,size,"%s,0 ; ?bug", get_op_from_instruction(PCI(pc)));
+ } else {
+ if(PCI(pc)->pcop->type == PO_GPR_BIT) {
+ if( PCI(pc)->num_ops == 2)
+ SNPRINTF(s,size,"(%s >> 3),%c",get_op_from_instruction(PCI(pc)),((PCI(pc)->isModReg) ? 'F':'W'));
+ else
+ SNPRINTF(s,size,"(1 << (%s & 7))",get_op_from_instruction(PCI(pc)));
+ } else {
+ SNPRINTF(s,size,"%s",get_op_from_instruction(PCI(pc)));
+ size -= strlen(s);
+ s += strlen(s);
+ if( PCI(pc)->num_ops == 2)
+ SNPRINTF(s,size,",%c", ( (PCI(pc)->isModReg) ? 'F':'W'));
+ }
+ }
+ }
+ break;
+
+ case PC_COMMENT:
+ /* assuming that comment ends with a \n */
+ SNPRINTF(s,size,";%s", ((pCodeComment *)pc)->comment);
+ break;
+
+ case PC_INLINE:
+ /* assuming that inline code ends with a \n */
+ SNPRINTF(s,size,"%s", ((pCodeComment *)pc)->comment);
+ break;
+
+ case PC_LABEL:
+ SNPRINTF(s,size,";label=%s, key=%d\n",PCL(pc)->label,PCL(pc)->key);
+ break;
+ case PC_FUNCTION:
+ SNPRINTF(s,size,";modname=%s,function=%s: id=%d\n",PCF(pc)->modname,PCF(pc)->fname);
+ break;
+ case PC_WILD:
+ SNPRINTF(s,size,";\tWild opcode: id=%d\n",PCW(pc)->id);
+ break;
+ case PC_FLOW:
+ SNPRINTF(s,size,";\t--FLOW change\n");
+ break;
+ case PC_CSOURCE:
+ SNPRINTF(s,size,"%s\t.line\t%d; \"%s\"\t%s\n",(options.debug?"":";"),PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
+ break;
+ case PC_ASMDIR:
+ if(PCAD(pc)->directive) {
+ SNPRINTF(s,size,"\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
+ } else if(PCAD(pc)->arg) {
+ /* special case to handle inline labels without a tab */
+ SNPRINTF(s,size,"%s\n", PCAD(pc)->arg);
+ }
+ break;
+
+ case PC_BAD:
+ 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
+ {
+ char str[256];
+ pCodeInstruction *pci = PCI(pc);
+ pBranch *pbl = pci->label;
+ while(pbl && pbl->pc) {
+ if(pbl->pc->type == PC_LABEL)
+ pCodePrintLabel(of, pbl->pc);
+ pbl = pbl->next;
+ }
+
+ if(pci->cline)
+ genericPrint(of,PCODE(pci->cline));
+
+
+ pCode2str(str, sizeof(str), pc);
+
+ fprintf(of,"%s",str);
+
+ /* Debug */
+ if(debug_verbose) {
+ pCodeOpReg *pcor = PCOR(pci->pcop);
+ fprintf(of, "\t;id=%u,key=%03x,inCond:%x,outCond:%x",pc->id,pc->seq, pci->inCond, pci->outCond);
+ if(pci->pcflow)
+ fprintf(of,",flow seq=%03x",pci->pcflow->pc.seq);
+ if (pcor && pcor->pcop.type==PO_GPR_TEMP && !pcor->r->isFixed)
+ fprintf(of,",rIdx=r0x%X",pcor->rIdx);
+ }
+ }
+ 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(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");
+ fprintf(of,"; from: ");
+ {
+ pCodeFlowLink *link;
+ for (link = setFirstItem(PCFL(pc)->from); link; link = setNextItem (PCFL(pc)->from))
+ {
+ fprintf(of,"%03x ",link->pcflow->pc.seq);
+ }
+ }
+ fprintf(of,"; to: ");
+ {
+ pCodeFlowLink *link;
+ for (link = setFirstItem(PCFL(pc)->to); link; link = setNextItem (PCFL(pc)->to))
+ {
+ fprintf(of,"%03x ",link->pcflow->pc.seq);
+ }
+ }
+ fprintf(of,"\n");
+ }
+ break;
+
+ case PC_CSOURCE:
+ fprintf(of,"%s\t.line\t%d; \"%s\"\t%s\n", (options.debug?"":";"), PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
+ break;
+
+ case PC_ASMDIR:
+ {
+ pBranch *pbl = PCAD(pc)->pci.label;
+ while(pbl && pbl->pc) {
+ if(pbl->pc->type == PC_LABEL)
+ pCodePrintLabel(of, pbl->pc);
+ pbl = pbl->next;
+ }
+ }
+ if(PCAD(pc)->directive) {
+ fprintf(of, "\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
+ } else
+ if(PCAD(pc)->arg) {
+ /* special case to handle inline labels without tab */
+ fprintf(of, "%s\n", PCAD(pc)->arg);
+ }
+ 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 0
+ if( ((pCodeFunction *)pc)->modname)
+ fprintf(of,"F_%s",((pCodeFunction *)pc)->modname);
+#endif
+ if(PCF(pc)->fname) {
+ pBranch *exits = PCF(pc)->to;
+ int i=0;
+
+ fprintf(of, "%s:", PCF(pc)->fname);
+
+ if(options.verbose)
+ fprintf(of, "\t;Function start");
+
+ fprintf(of, "\n");
+
+ 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 || pcl->type == PC_INLINE || pcl->type == PC_ASMDIR)
+ 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 * 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_alloc(sizeof(pBranch));
+ b->pc = PCODE(t); // The link to the 'to' pCode.
+ b->next = NULL;
+
+ f->to = pBranchAppend(f->to,b);
+
+ // Now do the same for the 'to' pCode.
+
+ //_ALLOC(b,sizeof(pBranch));
+ b = Safe_alloc(sizeof(pBranch));
+ b->pc = PCODE(f);
+ b->next = NULL;
+
+ t->from = pBranchAppend(t->from,b);
+
+}
+
+/*-----------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+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 || pc->type == PC_ASMDIR) {
+ 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;
+}
+
+/*-----------------------------------------------------------------*/
+/* findNextpCode - given a pCode, find the next of type 'pct' */
+/* in the linked list */
+/*-----------------------------------------------------------------*/
+pCode * findNextpCode(pCode *pc, PC_TYPE pct)
+{
+
+ while(pc) {
+ if(pc->type == pct)
+ return pc;
+
+ pc = pc->next;
+ }
+
+ return NULL;
+}
+
+#if 0
+/*-----------------------------------------------------------------*/
+/* 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) {
+ /*
+ static unsigned int stop;
+ if (pc->id == 524)
+ stop++; // Place break point here
+ */
+ return pc;
+ }
+
+ pc = pc->prev;
+ }
+
+ return NULL;
+}
+#endif
+
+/*-----------------------------------------------------------------*/
+/* findNextInstruction - given a pCode, find the next instruction */
+/* in the linked list */
+/*-----------------------------------------------------------------*/
+pCode * findNextInstruction(pCode *pci)
+{
+ pCode *pc = pci;
+
+ while(pc) {
+ if((pc->type == PC_OPCODE)
+ || (pc->type == PC_WILD)
+ || (pc->type == PC_ASMDIR))
+ return pc;
+
+#ifdef PCODE_DEBUG
+ fprintf(stderr,"findNextInstruction: ");
+ printpCode(stderr, pc);
+#endif
+ pc = pc->next;
+ }
+
+ //fprintf(stderr,"Couldn't find instruction\n");
+ return NULL;
+}
+
+/*-----------------------------------------------------------------*/
+/* findNextInstruction - given a pCode, find the next instruction */
+/* in the linked list */
+/*-----------------------------------------------------------------*/
+pCode * findPrevInstruction(pCode *pci)
+{
+ pCode *pc = pci;
+
+ while(pc) {
+
+ if((pc->type == PC_OPCODE)
+ || (pc->type == PC_WILD)
+ || (pc->type == PC_ASMDIR))
+ return pc;
+
+
+#ifdef PCODE_DEBUG
+ fprintf(stderr,"pic16_findPrevInstruction: ");
+ printpCode(stderr, pc);
+#endif
+ pc = pc->prev;
+ }
+
+ //fprintf(stderr,"Couldn't find instruction\n");
+ return NULL;
+}
+
+/*-----------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+reg_info * getRegFromInstruction(pCode *pc)
+{
+ reg_info *r;
+ if(!pc ||
+ !isPCI(pc) ||
+ !PCI(pc)->pcop ||
+ PCI(pc)->num_ops == 0 )
+ return NULL;
+
+ switch(PCI(pc)->pcop->type) {
+ case PO_STATUS:
+ case PO_FSR:
+ case PO_INDF:
+ case PO_INTCON:
+ case PO_BIT:
+ case PO_GPR_TEMP:
+ case PO_SFR_REGISTER:
+ case PO_PCL:
+ case PO_PCLATH:
+ return PCOR(PCI(pc)->pcop)->r;
+
+ case PO_GPR_REGISTER:
+ case PO_GPR_BIT:
+ case PO_DIR:
+ r = PCOR(PCI(pc)->pcop)->r;
+ if (r)
+ return r;
+ return dirregWithName(PCI(pc)->pcop->name);
+
+ case PO_LITERAL:
+ break;
+
+ case PO_IMMEDIATE:
+ r = PCOI(PCI(pc)->pcop)->r;
+ if (r)
+ return r;
+ return dirregWithName(PCI(pc)->pcop->name);
+
+ default:
+ 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)
+ || ((PCI(pc)->pcop->type == PO_GPR_BIT) && PCOR(PCI(pc)->pcop)->r && (PCOR(PCI(pc)->pcop)->r->pc_type == PO_GPR_TEMP))) {
+
+ /* Loop through all of the registers declared so far in
+ this block and see if we find this one there */
+
+ reg_info *r = setFirstItem(pb->tregisters);
+
+ while(r) {
+ if((r->rIdx == PCOR(PCI(pc)->pcop)->r->rIdx) && (r->type == PCOR(PCI(pc)->pcop)->r->type)) {
+ PCOR(PCI(pc)->pcop)->r = r;
+ break;
+ }
+ r = setNextItem(pb->tregisters);
+ }
+
+ if(!r) {
+ /* register wasn't found */
+ //r = Safe_alloc(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) {
+ pic14_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");
+ }
+ }
+ }
+
+
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* */
+/*-----------------------------------------------------------------*/
+static void InsertpFlow(pCode *pc, pCode **pflow)
+{
+ if(*pflow)
+ PCFL(*pflow)->end = pc;
+
+ if(!pc || !pc->next)
+ return;
+
+ *pflow = newpCodeFlow();
+ pCodeInsertAfter(pc, *pflow);
+}
+
+/*-----------------------------------------------------------------*/
+/* BuildFlow(pBlock *pb) - examine the code in a pBlock and build */
+/* the flow blocks. */
+/*
+* BuildFlow inserts pCodeFlow objects into the pCode chain at each
+* point the instruction flow changes.
+*/
+/*-----------------------------------------------------------------*/
+static void 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 = 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 = findNextInstruction(pb->pcHead);
+ pc != NULL;
+ pc=findNextInstruction(pc)) {
+
+ pc->seq = seq++;
+ PCI(pc)->pcflow = PCFL(pflow);
+
+ //fprintf(stderr," build: ");
+ //pc->print(stderr, pc);
+ //pflow->print(stderr,pflow);
+
+ 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.) */
+
+ last_pci = findPrevInstruction (pc->prev);
+
+ if(last_pci && (PCI(last_pci)->pcflow == PCFL(pflow)))
+ InsertpFlow(last_pci, &pflow);
+
+ PCI(pc)->pcflow = PCFL(pflow);
+
+ }
+
+ if(isPCI_SKIP(pc)) {
+
+ /* The two instructions immediately following this one
+ * mark the beginning of a new flow segment */
+
+ while(pc && isPCI_SKIP(pc)) {
+
+ PCI(pc)->pcflow = PCFL(pflow);
+ pc->seq = seq-1;
+ seq = 1;
+
+ InsertpFlow(pc, &pflow);
+ pc=findNextInstruction(pc->next);
+ }
+
+ seq = 0;
+
+ if(!pc)
+ break;
+
+ PCI(pc)->pcflow = PCFL(pflow);
+ pc->seq = 0;
+ InsertpFlow(pc, &pflow);
+
+ } else if ( isPCI_BRANCH(pc) && !checkLabel(findNextInstruction(pc->next))) {
+
+ InsertpFlow(pc, &pflow);
+ seq = 0;
+
+ }
+
+ 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;
+ }
+
+
+}
+
+#if 0
+/*-----------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+static void dumpCond(int cond)
+{
+
+ static char *pcc_str[] = {
+ //"PCC_NONE",
+ "PCC_REGISTER",
+ "PCC_C",
+ "PCC_Z",
+ "PCC_DC",
+ "PCC_W",
+ "PCC_EXAMINE_PCOP",
+ "PCC_REG_BANK0",
+ "PCC_REG_BANK1",
+ "PCC_REG_BANK2",
+ "PCC_REG_BANK3"
+ };
+
+ int ncond = sizeof(pcc_str) / sizeof(char *);
+ int i,j;
+
+ fprintf(stderr, "0x%04X\n",cond);
+
+ for(i=0,j=1; i<ncond; i++, j<<=1)
+ if(cond & j)
+ fprintf(stderr, " %s\n",pcc_str[i]);
+
+}
+#endif
+
+#if 0
+/*-----------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+static void FlowStats(pCodeFlow *pcflow)
+{
+
+ pCode *pc;
+
+ if(!isPCFL(pcflow))
+ return;
+
+ fprintf(stderr, " FlowStats - flow block (seq=%d)\n", pcflow->pc.seq);
+
+ pc = 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);
+
+}
+#endif
+
+/*-----------------------------------------------------------------*
+* 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( ( (reg = getRegFromInstruction(pc)) != NULL) && isSTATUS_REG(reg)) {
+
+ // Check to see if the register banks are changing
+ if(PCI(pc)->isModReg) {
+
+ pCodeOp *pcop = PCI(pc)->pcop;
+ switch(PCI(pc)->op) {
+
+ case POC_BSF:
+ if(PCORB(pcop)->bit == PIC_RP0_BIT) {
+ //fprintf(stderr, " isBankInstruction - Set RP0\n");
+ return SET_BANK_BIT | PIC_RP0_BIT;
+ }
+
+ if(PCORB(pcop)->bit == PIC_RP1_BIT) {
+ //fprintf(stderr, " isBankInstruction - Set RP1\n");
+ return CLR_BANK_BIT | PIC_RP0_BIT;
+ }
+ break;
+
+ case POC_BCF:
+ if(PCORB(pcop)->bit == PIC_RP0_BIT) {
+ //fprintf(stderr, " isBankInstruction - Clr RP0\n");
+ return CLR_BANK_BIT | PIC_RP1_BIT;
+ }
+ if(PCORB(pcop)->bit == PIC_RP1_BIT) {
+ //fprintf(stderr, " isBankInstruction - Clr RP1\n");
+ return CLR_BANK_BIT | PIC_RP1_BIT;
+ }
+ break;
+ default:
+ //fprintf(stderr, " isBankInstruction - Status register is getting Modified by:\n");
+ //genericPrint(stderr, pc);
+ ;
+ }
+ }
+
+ }
+
+ 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 = 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 0
+ fprintf(stderr, "%s: linking ", __FUNCTION__ );
+ if (from) from->pc.print(stderr, &from->pc);
+ else fprintf(stderr, "(null)");
+ fprintf(stderr, " -(%u)-> with -(%u)-> ",
+ from && from->pcflow ? from->pcflow->pc.seq : 0,
+ to && to->pcflow ? to->pcflow->pc.seq : 0);
+ if (to) to->pc.print(stderr, &to->pc);
+ else fprintf(stderr, "(null)");
+#endif
+
+ if(!from || !to || !to->pcflow || !from->pcflow)
+ return;
+
+ fromLink = newpCodeFlowLink(from->pcflow);
+ toLink = newpCodeFlowLink(to->pcflow);
+
+ addSetIfnotP(&(from->pcflow->to), toLink); //to->pcflow);
+ addSetIfnotP(&(to->pcflow->from), fromLink); //from->pcflow);
+
+}
+
+/*-----------------------------------------------------------------*
+* void LinkFlow(pBlock *pb)
+*
+* In 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");
+
+ if (!pb) return;
+
+ for( pcflow = findNextpCode(pb->pcHead, PC_FLOW);
+ pcflow != NULL;
+ pcflow = 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));
+
+ /* find last instruction in flow */
+ pc = findPrevInstruction (PCFL(pcflow)->end);
+ if (!pc) {
+ fprintf(stderr, "%s: flow without end (%u)?\n",
+ __FUNCTION__, pcflow->seq );
+ continue;
+ }
+
+ //fprintf(stderr, "LinkFlow - flow block (seq=%d) ", pcflow->seq);
+ //pc->print(stderr, pc);
+ if(isPCI_SKIP(pc)) {
+ //fprintf(stderr, "ends with skip\n");
+ //pc->print(stderr,pc);
+ pct=findNextInstruction(pc->next);
+ LinkFlow_pCode(PCI(pc),PCI(pct));
+ pct=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__);
+ }
+ } else {
+
+ 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,"newpCodeOpLabel: key=%d, name=%s\n",key,((s)?s:""));
+ }
+ /* link CALLs to next instruction */
+ if (PCI(pc)->op != POC_CALL) continue;
+ }
+
+ if(isPCI(pc)) {
+ //fprintf(stderr, "ends with non-branching instruction:\n");
+ //pc->print(stderr,pc);
+
+ LinkFlow_pCode(PCI(pc),PCI(findNextInstruction(pc->next)));
+
+ continue;
+ }
+
+ if(pc) {
+ //fprintf(stderr, "ends with unknown\n");
+ //pc->print(stderr,pc);
+ continue;
+ }
+
+ fprintf(stderr, "ends with nothing: ERROR\n");
+
+ }
+}
+
+static void pCodeReplace (pCode *old, pCode *new)
+{
+ pCodeInsertAfter (old, new);
+
+ /* special handling for pCodeInstructions */
+ if (isPCI(new) && isPCI(old))
+ {
+ //assert (!PCI(new)->from && !PCI(new)->to && !PCI(new)->label && /*!PCI(new)->pcflow && */!PCI(new)->cline);
+ PCI(new)->from = PCI(old)->from;
+ PCI(new)->to = PCI(old)->to;
+ PCI(new)->label = PCI(old)->label;
+ PCI(new)->pcflow = PCI(old)->pcflow;
+ PCI(new)->cline = PCI(old)->cline;
+ } // if
+
+ old->destruct (old);
+}
+
+/*-----------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+static void addpCodeComment(pCode *pc, const char *fmt, ...)
+{
+ va_list ap;
+ char buffer[4096];
+ pCode *newpc;
+
+ va_start(ap, fmt);
+ if (options.verbose || debug_verbose) {
+ buffer[0] = ';';
+ buffer[1] = ' ';
+ vsprintf(&buffer[2], fmt, ap);
+
+ newpc = newpCodeCharP(&buffer[0]); // strdup's the string
+ pCodeInsertAfter(pc, newpc);
+ }
+ va_end(ap);
+}
+
+/*-----------------------------------------------------------------*/
+/* Inserts a new pCodeInstruction before an existing one */
+/*-----------------------------------------------------------------*/
+static void insertPCodeInstruction(pCodeInstruction *pci, pCodeInstruction *new_pci)
+{
+ pCode *pcprev;
+
+ pcprev = findPrevInstruction(pci->pc.prev);
+
+ pCodeInsertAfter(pci->pc.prev, &new_pci->pc);
+
+ /* Move the label, if there is one */
+
+ if(pci->label) {
+ new_pci->label = pci->label;
+ pci->label = NULL;
+ }
+
+ /* Move the C code comment, if there is one */
+
+ if(pci->cline) {
+ new_pci->cline = pci->cline;
+ pci->cline = NULL;
+ }
+
+ /* The new instruction has the same pcflow block */
+ new_pci->pcflow = pci->pcflow;
+
+ /* Arrrrg: is pci's previous instruction is a skip, we need to
+ * change that into a jump (over pci and the new instruction) ... */
+ if (pcprev && isPCI_SKIP(pcprev))
+ {
+ symbol *lbl = newiTempLabel (NULL);
+ pCode *label = newpCodeLabel (NULL, lbl->key);
+ pCode *jump = newpCode(POC_GOTO, newpCodeOpLabel(NULL, lbl->key));
+
+ pCodeInsertAfter (pcprev, jump);
+
+ // Yuck: Cannot simply replace INCFSZ/INCFSZW/DECFSZ/DECFSZW
+ // We replace them with INCF/INCFW/DECF/DECFW followed by 'BTFSS STATUS, Z'
+ switch (PCI(pcprev)->op) {
+ case POC_INCFSZ:
+ case POC_INCFSZW:
+ case POC_DECFSZ:
+ case POC_DECFSZW:
+ // These are turned into non-skipping instructions, so
+ // insert 'BTFSC STATUS, Z' after pcprev
+ pCodeInsertAfter (jump->prev, newpCode(POC_BTFSC, popCopyGPR2Bit(PCOP(&pc_status), PIC_Z_BIT)));
+ break;
+ default:
+ // no special actions required
+ break;
+ }
+ pCodeReplace (pcprev, pCodeInstructionCopy (PCI(pcprev), 1));
+ pcprev = NULL;
+ pCodeInsertAfter((pCode*)pci, label);
+ pBlockMergeLabels(pci->pc.pb);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+static int insertBankSel(pCodeInstruction *pci, const char *name)
+{
+ pCode *new_pc;
+
+ pCodeOp *pcop;
+
+ // Never BANKSEL STATUS, this breaks all kinds of code (e.g., interrupt handlers).
+ if (!strcmp("STATUS", name) || !strcmp("_STATUS", name)) return 0;
+
+ pcop = popCopyReg(PCOR(pci->pcop));
+ pcop->type = PO_GPR_REGISTER; // Sometimes the type is set to legacy 8051 - so override it
+ if (pcop->name == 0)
+ pcop->name = strdup(name);
+ new_pc = newpCode(POC_BANKSEL, pcop);
+
+ insertPCodeInstruction(pci, PCI(new_pc));
+ return 1;
+}
+
+/*
+ * isValidIdChar - check if c may be present in an identifier
+ */
+static int isValidIdChar (char c)
+{
+ if (c >= 'a' && c <= 'z') return 1;
+ if (c >= 'A' && c <= 'Z') return 1;
+ if (c >= '0' && c <= '9') return 1;
+ if (c == '_') return 1;
+ return 0;
+}
+
+/*
+ * bankcompare - check if two operand string refer to the same register
+ * This functions handles NAME and (NAME + x) in both operands.
+ * Returns 1 on same register, 0 on different (or unknown) registers.
+ */
+static int bankCompare(const char *op1, const char *op2)
+{
+ int i;
+
+ if (!op1 && !op2) return 0; // both unknown, might be different though!
+ if (!op1 || !op2) return 0;
+
+ // find start of operand name
+ while (op1[0] == '(' || op1[0] == ' ') op1++;
+ while (op2[0] == '(' || op2[0] == ' ') op2++;
+
+ // compare till first non-identifier character
+ for (i = 0; (op1[i] == op2[i]) && isValidIdChar(op1[i]); i++);
+ if (!isValidIdChar(op1[i]) && !isValidIdChar(op2[i])) return 1;
+
+ // play safe---assume different operands
+ return 0;
+}
+
+/*
+ * Interface to BANKSEL generation.
+ * This function should return != 0 iff str1 and str2 denote operands that
+ * are known to be allocated into the same bank. Consequently, there will
+ * be no BANKSEL emitted if str2 is accessed while str1 has been used to
+ * select the current bank just previously.
+ *
+ * If in doubt, return 0.
+ */
+static int
+pic14_operandsAllocatedInSameBank(const char *str1, const char *str2) {
+ // see glue.c(pic14printLocals)
+
+ if (getenv("SDCC_PIC14_SPLIT_LOCALS")) {
+ // no clustering applied, each register resides in its own bank
+ } else {
+ // check whether BOTH names are local registers
+ // XXX: This is some kind of shortcut, should be safe...
+ // In this model, all r0xXXXX are allocated into a single section
+ // per file, so no BANKSEL required if accessing a r0xXXXX after a
+ // (different) r0xXXXX. Works great for multi-byte operands.
+ if (str1 && str2 && str1[0] == 'r' && str2[0] == 'r') return (1);
+ } // if
+
+ // assume operands in different banks
+ return (0);
+}
+
+/*-----------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+static int sameBank(reg_info *reg, reg_info *previous_reg, const char *new_bank, const char *cur_bank, unsigned max_mask)
+{
+ if (!cur_bank) return 0;
+
+ if (previous_reg && reg && previous_reg->isFixed && reg->isFixed && ((previous_reg->address & max_mask) == (reg->address & max_mask))) // only if exists
+ return 1; // if we have address info, we use it for banksel optimization
+
+ // regard '(regname + X)' and '(regname + Y)' as equal
+ if (reg && reg->name && bankCompare(reg->name, cur_bank)) return 1;
+ if (new_bank && bankCompare(new_bank, cur_bank)) return 1;
+
+ // check allocation policy from glue.c
+ if (reg && reg->name && pic14_operandsAllocatedInSameBank(reg->name, cur_bank)) return 1;
+ if (new_bank && pic14_operandsAllocatedInSameBank(new_bank, cur_bank)) return 1;
+
+ // seems to be a different operand--might be a different bank
+ //printf ("BANKSEL from %s to %s/%s\n", cur_bank, reg->name, new_bank);
+ return 0;
+}
+
+/*-----------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+static void FixRegisterBanking(pBlock *pb)
+{
+ pCode *pc;
+ pCodeInstruction *pci;
+ reg_info *reg;
+ reg_info *previous_reg; // contains the previous variable access info
+ const char *cur_bank, *new_bank;
+ unsigned cur_mask, new_mask, max_mask;
+ int allRAMmshared;
+
+ if (!pb) return;
+
+ max_mask = pic14_getPIC()->bankMask;
+ cur_mask = max_mask;
+ cur_bank = NULL;
+ previous_reg = NULL;
+
+ allRAMmshared = pic14_allRAMShared();
+
+ for (pc = pb->pcHead; pc; pc = pc->next)
+ {
+ // this one has a label---might check bank at all jumps here...
+ if (isPCI(pc) && (PCI(pc)->label || PCI(pc)->op == POC_CALL)) {
+ addpCodeComment(pc->prev, "BANKOPT3 drop assumptions: PCI with label or call found");
+ previous_reg = NULL;
+ cur_bank = NULL; // start new flow
+ cur_mask = max_mask;
+ }
+
+ // this one is/might be a label or BANKSEL---assume nothing
+ if (isPCL(pc) || isPCASMDIR(pc)) {
+ addpCodeComment(pc->prev, "BANKOPT4 drop assumptions: label or ASMDIR found");
+ previous_reg = NULL;
+ cur_bank = NULL;
+ cur_mask = max_mask;
+ }
+
+ // this one modifies STATUS
+ // XXX: this should be checked, but usually BANKSELs are not done this way in generated code
+
+ if (isPCI(pc)) {
+ pci = PCI(pc);
+ if ((pci->inCond | pci->outCond) & PCC_REGISTER) {
+ // might need a BANKSEL
+ reg = getRegFromInstruction(pc);
+
+ if (reg) {
+ new_bank = reg->name;
+ // reg->alias == 0: reg is in only one bank, we do not know which (may be any bank)
+ // reg->alias != 0: reg is in 2/4/8/2**N banks, we select one of them
+ new_mask = reg->alias;
+ } else if (pci->pcop && pci->pcop->name) {
+ new_bank = pci->pcop->name;
+ new_mask = 0; // unknown, assume worst case
+ } else {
+ assert(!"Could not get register from instruction.");
+ new_bank = "UNKNOWN";
+ new_mask = 0; // unknown, assume worst case
+ }
+
+ // optimizations...
+ // XXX: add switch to disable these
+ if (1) {
+ // reg present in all banks possibly selected?
+ if (new_mask == max_mask || (cur_mask && ((new_mask & cur_mask) == cur_mask))) {
+ // no BANKSEL required
+ addpCodeComment(pc->prev, "BANKOPT1 BANKSEL dropped; %s present in all of %s's banks", new_bank, cur_bank);
+ continue;
+ }
+
+ // only one bank of memory and no SFR accessed?
+ // XXX: We can do better with fixed registers.
+ if (allRAMmshared && reg && (reg->type != REG_SFR) && (!reg->isFixed)) {
+ // no BANKSEL required
+ addpCodeComment(pc->prev, "BANKOPT1b BANKSEL dropped; %s present in all (of %s's) banks", new_bank, cur_bank);
+ continue;
+ }
+
+ if (sameBank(reg, previous_reg, new_bank, cur_bank, max_mask)) {
+ // no BANKSEL required
+ addpCodeComment(pc->prev, "BANKOPT2 BANKSEL dropped; %s present in same bank as %s", new_bank, cur_bank);
+ continue;
+ }
+ } // if
+
+ if (insertBankSel(pci, new_bank)) {
+ cur_mask = new_mask;
+ cur_bank = new_bank;
+ previous_reg = reg;
+ } // if
+ } // if
+ } // if
+ } // for
+}
+
+/*-----------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+static int OptimizepBlock(pBlock *pb)
+{
+ pCode *pc, *pcprev;
+ int matches =0;
+
+ if(!pb || options.nopeep)
+ return 0;
+
+ DFPRINTF((stderr," Optimizing pBlock: %c\n",getpBlock_dbName(pb)));
+ /*
+ for(pc = pb->pcHead; pc; pc = pc->next)
+ matches += pCodePeepMatchRule(pc);
+ */
+
+ pc = findNextInstruction(pb->pcHead);
+ if(!pc)
+ return 0;
+
+ pcprev = pc->prev;
+ do {
+ if(pCodePeepMatchRule(pc)) {
+ matches++;
+
+ if(pcprev)
+ pc = findNextInstruction(pcprev->next);
+ else
+ pc = findNextInstruction(pb->pcHead);
+ } else
+ pc = findNextInstruction(pc->next);
+ } while(pc);
+
+ if(matches)
+ DFPRINTF((stderr," Optimizing pBlock: %c - matches=%d\n",getpBlock_dbName(pb),matches));
+
+ return matches;
+}
+
+/*-----------------------------------------------------------------*/
+/* pBlockRemoveUnusedLabels - remove the pCode labels from the */
+/*-----------------------------------------------------------------*/
+static pCode * findInstructionUsingLabel(pCodeLabel *pcl, pCode *pcs)
+{
+ pCode *pc;
+
+ for(pc = pcs; pc; pc = pc->next) {
+
+ if(((pc->type == PC_OPCODE) || (pc->type == PC_INLINE) || (pc->type == PC_ASMDIR)) &&
+ (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)
+{
+ const char *s;
+
+ 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) {
+ SNPRINTF(buffer, sizeof(buffer), "_%05d_DS_", pcl->key);
+ s = buffer;
+ } else
+ s = pcl->label;
+
+ //SNPRINTF(buffer, sizeof(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 || !pb->pcHead)
+ return;
+
+ for(pc = pb->pcHead; (pc=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)) // Label pcode
+ pcl = PCL(pc);
+ else if (isPCI(pc) && PCI(pc)->label) // pcode instruction with a 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))) {
+ /* 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) {
+ unlinkpCode(pc);
+ pCodeLabelDestruct(pc);
+ } else {
+ unlinkpCodeFromBranch(pc, PCODE(pcl));
+ /*if(pc->label->next == NULL && pc->label->pc == NULL) {
+ free(pc->label);
+ }*/
+ }
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* pBlockMergeLabels - remove the pCode labels from the pCode */
+/* chain and put them into pBranches that are */
+/* associated with the appropriate pCode */
+/* instructions. */
+/*-----------------------------------------------------------------*/
+void 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;
+
+ 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 = findNextInstruction(pc) )) {
+
+ // Unlink the pCode label from it's pCode chain
+ 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_alloc(sizeof(pBranch));
+ pbr->pc = pc;
+ pbr->next = NULL;
+
+ PCI(pcnext)->label = 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 = findNextInstruction(pc) )) {
+
+ // Unlink the pCode label from it's pCode chain
+ 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;
+}
+
+/*-----------------------------------------------------------------*/
+/* popCopyGPR2Bit - copy a pcode operator */
+/*-----------------------------------------------------------------*/
+
+pCodeOp *popCopyGPR2Bit(pCodeOp *pc, int bitval)
+{
+ pCodeOp *pcop;
+
+ pcop = 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;
+}
+
+/*-----------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+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 {
+ addpCode2pBlock(pbmerged, pb->pcHead);
+ /* addpCode2pBlock doesn't handle the tail: */
+ pbmerged->pcTail = pb->pcTail;
+
+ pb->prev->next = pbn;
+ if(pbn)
+ pbn->prev = pb->prev;
+
+
+ pBlockDestruct(pb);
+ }
+ //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);
+
+ 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)
+ 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)
+ 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)
+ pCodeRegMapLiveRanges(pb);
+
+ RemoveUnusedRegisters();
+
+// for(pb = the_pFile->pbHead; pb; pb = pb->next)
+ 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 = findNextpCode(pb->pcHead, PC_FLOW);
+ (pcflow = findNextpCode(pcflow, PC_FLOW)) != NULL;
+ pcflow = pcflow->next) {
+
+ FillFlow(PCFL(pcflow));
+ }
+ }
+ */
+ /*
+ for(pb = the_pFile->pbHead; pb; pb = pb->next) {
+ pCode *pcflow;
+ for( pcflow = findNextpCode(pb->pcHead, PC_FLOW);
+ (pcflow = findNextpCode(pcflow, PC_FLOW)) != NULL;
+ pcflow = pcflow->next) {
+
+ FlowStats(PCFL(pcflow));
+ }
+ }
+ */
+}
+
+/*-----------------------------------------------------------------*/
+/* AnalyzeBanking - Called after the memory addresses have been */
+/* assigned to the registers. */
+/* */
+/*-----------------------------------------------------------------*/
+
+void AnalyzeBanking(void)
+{
+ pBlock *pb;
+
+ if(!picIsInitialized()) {
+ werror(E_FILE_OPEN_ERR, "no memory size is known for this processor");
+ exit(1);
+ }
+
+ if (!the_pFile) return;
+
+ /* 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)
+ FixRegisterBanking(pb);
+
+ AnalyzeFlow(0);
+ AnalyzeFlow(1);
+
+}
+
+/*-----------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+static DEFSETFUNC (resetrIdx)
+{
+ reg_info *r = (reg_info *)item;
+ if (!r->isFixed) {
+ r->rIdx = 0;
+ }
+
+ return 0;
+}
+
+/*-----------------------------------------------------------------*/
+/* InitRegReuse - Initialises variables for code analyzer */
+/*-----------------------------------------------------------------*/
+static void InitReuseReg(void)
+{
+ /* Find end of statically allocated variables for start idx */
+ /* Start from begining of GPR. Note may not be 0x20 on some PICs */
+ /* XXX: Avoid clashes with fixed registers, start late. */
+ unsigned maxIdx = 0x1000;
+ reg_info *r;
+ for (r = setFirstItem(dynDirectRegs); r; r = setNextItem(dynDirectRegs)) {
+ if (r->type != REG_SFR) {
+ maxIdx += r->size; /* Increment for all statically allocated variables */
+ }
+ }
+ peakIdx = maxIdx;
+ applyToSet(dynAllocRegs,resetrIdx); /* Reset all rIdx to zero. */
+}
+
+/*-----------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+static unsigned
+register_reassign(pBlock *pb, unsigned startIdx, unsigned level)
+{
+ pCode *pc;
+ unsigned temp;
+ unsigned idx = startIdx;
+
+ /* check recursion */
+ pc = setFirstItem(pb->function_entries);
+ if (!pc)
+ return idx;
+
+ if (pb->visited)
+ {
+ set *regset;
+ /* TODO: Recursion detection missing, should emit a warning as recursive code will fail. */
+
+ // Find the highest rIdx used by this function for return.
+ regset = pb->tregisters;
+ idx = 0;
+ while (regset)
+ {
+ temp = ((reg_info *)regset->item)->rIdx;
+ if (temp > idx)
+ idx = temp;
+ regset = regset->next;
+ } // while
+ DFPRINTF((stderr,
+ "%*s(%u) function \"%s\" already visited: max idx = %04x\n",
+ 4 * level, "", level,PCF(pc)->fname, idx));
+ return idx + 1;
+ } // if
+
+ /*
+ * We now traverse the call tree depth first, assigning indices > startIdx
+ * to the registers of all called functions before assigning indices to
+ * the registers of the calling function, starting with one greater than
+ * the max. index used by any child function.
+ * This approach guarantees that, if f calls g, all registers of f have
+ * greater indices than those of g (also holds transitively).
+ *
+ * XXX: If a function f calls a function g in a different module,
+ * we should handle the case that g could call a function h
+ * in f's module.
+ * The consequence of this is that even though f and h might
+ * share registers (they do not call each other locally) when
+ * looking only at f's module, they actually must not do so!
+ *
+ * For a non-static function f, let ES(f) be the set of functions
+ * (including f) that can only be reached via f in the module-local
+ * call graph (ES(f) will hence be a subgraph).
+ * Let further REG(ES(f)) be the set of registers assigned to
+ * functions in ES(f).
+ * Then we should make sure that REG(ES(f)) and REG(ES(g)) are
+ * disjoint for all non-static functions f and g.
+ *
+ * Unfortunately, determining the sets ES(f) is non-trivial,
+ * so we ignore this problem and declare all modules non-reentrant.
+ * This is a bug.
+ */
+ pb->visited = 1;
+
+ DFPRINTF((stderr,
+ "%*s(%u) reassigning registers for functions called by \"%s\":base idx = %04x\n",
+ 4 * level, "", level, PCF(pc)->fname, startIdx));
+
+ for (pc = setFirstItem(pb->function_calls); pc; pc = setNextItem(pb->function_calls))
+ {
+ if (pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL)
+ {
+ char *dest = get_op_from_instruction(PCI(pc));
+ pCode *pcn = findFunction(dest);
+
+ if (pcn)
+ {
+ /*
+ * Reassign the registers of all called functions and record
+ * the max. index I used by any child function --> I+1 will be
+ * the first index available to this function.
+ * (Problem shown with regression test src/regression/sub2.c)
+ */
+ unsigned childsMaxIdx;
+ childsMaxIdx = register_reassign(pcn->pb,startIdx,level+1);
+ if (childsMaxIdx > idx)
+ idx = childsMaxIdx;
+ } // if
+ } // if
+ } // for
+
+ pc = setFirstItem(pb->function_entries);
+ DFPRINTF((stderr,
+ "%*s(%u) reassigning registers for function \"%s\":idx = %04x\n",
+ 4 * level, "", level, PCF(pc)->fname, idx));
+
+ if (pb->tregisters)
+ {
+ reg_info *r;
+ for (r = setFirstItem(pb->tregisters); r; r = setNextItem(pb->tregisters))
+ {
+ if ((r->type == REG_GPR) && (!r->isFixed) && (r->rIdx < (int)idx))
+ {
+ char s[20];
+ set *regset;
+ /*
+ * Make sure, idx is not yet used in this routine ...
+ * XXX: This should no longer be required, as all functions
+ * are reassigned at most once ...
+ */
+ do
+ {
+ regset = pb->tregisters;
+ // do not touch s->curr ==> outer loop!
+ while (regset && ((reg_info *)regset->item)->rIdx != idx)
+ regset = regset->next;
+ if (regset)
+ idx++;
+ }
+ while (regset);
+ r->rIdx = idx++;
+ if (peakIdx < idx)
+ peakIdx = idx;
+
+ SNPRINTF(s, sizeof(s), "r0x%02X", r->rIdx);
+ DFPRINTF((stderr,
+ "%*s(%u) reassigning register %p \"%s\" to \"%s\"\n",
+ 4 * level, "", level, r, r->name, s));
+ free(r->name);
+ r->name = Safe_strdup(s);
+ } // if
+ } // for
+ } // if
+
+ /* return lowest index available for caller's registers */
+ return idx;
+}
+
+/*------------------------------------------------------------------*/
+/* ReuseReg were call tree permits */
+/* */
+/* Re-allocate the GPR for optimum reuse for a given pblock */
+/* eg if a function m() calls function f1() and f2(), where f1 */
+/* allocates a local variable vf1 and f2 allocates a local */
+/* variable vf2. Then providing f1 and f2 do not call each other */
+/* they may share the same general purpose registers for vf1 and */
+/* vf2. */
+/* This is done by first setting the the regs rIdx to start after */
+/* all the global variables, then walking through the call tree */
+/* renaming the registers to match their new idx and incrementng */
+/* it as it goes. If a function has already been called it will */
+/* only rename the registers if it has already used up those */
+/* registers ie rIdx of the function's registers is lower than the */
+/* current rIdx. That way the register will not be reused while */
+/* still being used by an eariler function call. */
+/* */
+/* Note for this to work the functions need to be declared static. */
+/* */
+/*------------------------------------------------------------------*/
+void
+ReuseReg(void)
+{
+ pBlock *pb;
+
+ if (options.noOverlay || !the_pFile)
+ return;
+
+ InitReuseReg();
+
+ for(pb = the_pFile->pbHead; pb; pb = pb->next)
+ {
+ /* Non static functions can be called from other modules,
+ * so their registers must reassign */
+ if (pb->function_entries
+ && (PCF(setFirstItem(pb->function_entries))->isPublic || !pb->visited))
+ {
+ register_reassign(pb,peakIdx,0);
+ } // if
+ } // for
+}
+
+/*-----------------------------------------------------------------*/
+/* buildCallTree - look at the flow and extract all of the calls */
+/* */
+/*-----------------------------------------------------------------*/
+
+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 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)) {
+ pCodeFunction *pcf = PCF(pc);
+ if (pcf->fname) {
+
+ if(STRCASECMP(pcf->fname, "_main") == 0) {
+ //fprintf(stderr," found main \n");
+ pb->cmemmap = NULL; /* FIXME do we need to free ? */
+ pb->dbName = 'M';
+ }
+
+ pbr = Safe_alloc(sizeof(pBranch));
+ pbr->pc = pc_fstart = pc;
+ pbr->next = NULL;
+
+ the_pFile->functions = 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);
+
+ addSet(&pb->function_exits, pc);
+ }
+ } else if(isCALL(pc)) {
+ addSet(&pb->function_calls,pc);
+ }
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* 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 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));
+
+ /* 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));
+ pBlockMergeLabels(pb);
+ AnalyzepBlock(pb);
+ } else {
+ DFPRINTF((stderr," skipping block analysis dbName=%c blockname=%c\n",dbName,getpBlock_dbName(pb)));
+ }
+ }
+
+ changes = OptimizepCode(dbName);
+
+ } while(changes && (i++ < MAX_PASSES));
+
+ buildCallTree();
+}
+
+/*-----------------------------------------------------------------*/
+/* 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(const 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 pBlockStats(FILE *of, pBlock *pb)
+{
+
+ pCode *pc;
+ reg_info *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",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
+/*-----------------------------------------------------------------*/
+/* printCallTree - 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;i<indent;i++) // Indentation
+ fputc(' ',of);
+
+ if(pc->type == 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 = 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__);
+
+ }
+
+
+}
+#endif
+
+#if 0
+/*-----------------------------------------------------------------*/
+/* 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;
+}
+
+/*-----------------------------------------------------------------*/
+/* printCallTree - writes the call tree to a file */
+/* */
+/*-----------------------------------------------------------------*/
+
+static void 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",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));
+ }
+}
+#endif
+
+
+/*-----------------------------------------------------------------*/
+/* */
+/*-----------------------------------------------------------------*/
+
+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(get_op_from_instruction(PCI(pc)));
+ pCode *pcp = pc->prev;
+ pCode *pct;
+ pCode *pce;
+
+ pBranch *pbr;
+
+ if(pcn && isPCF(pcn) && (PCF(pcn)->ncalled == 1) && !PCF(pcn)->isPublic && (pcp && (isPCI_BITSKIP(pcp)||!isPCI_SKIP(pcp)))) { /* Bit skips can be inverted other skips can not */
+
+ InlineFunction(pcn->pb);
+
+ /*
+ 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.
+
+ */
+
+ pc_call = pc;
+
+ /* Check if previous instruction was a bit skip */
+ if (isPCI_BITSKIP(pcp)) {
+ pCodeLabel *pcl;
+ /* Invert skip instruction and add a goto */
+ PCI(pcp)->op = (PCI(pcp)->op == POC_BTFSS) ? POC_BTFSC : POC_BTFSS;
+
+ if(isPCL(pc_call->next)) { // Label pcode
+ pcl = PCL(pc_call->next);
+ } else if (isPCI(pc_call->next) && PCI(pc_call->next)->label) { // pcode instruction with a label
+ pcl = PCL(PCI(pc_call->next)->label->pc);
+ } else {
+ pcl = PCL(newpCodeLabel(NULL, newiTempLabel(NULL)->key+100));
+ PCI(pc_call->next)->label->pc = (struct pCode*)pcl;
+ }
+ pCodeInsertAfter(pcp, newpCode(POC_GOTO, newpCodeOp(pcl->label,PO_STR)));
+ }
+
+ /* 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 = findNextInstruction(pcn->next);
+
+ /* Link the function with the callee */
+ if (pcp) pcp->next = pcn->next;
+ pcn->next->prev = pcp;
+
+ /* Convert the function name into a label */
+
+ pbr = Safe_alloc(sizeof(pBranch));
+ pbr->pc = newpCodeLabel(PCF(pcn)->fname, -1);
+ pbr->next = NULL;
+ PCI(pct)->label = pBranchAppend(PCI(pct)->label,pbr);
+ PCI(pct)->label = 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 = findNextInstruction(pcn->next);
+ while(pce) {
+ pCode *pce_next = findNextInstruction(pce->next);
+
+ if(pce_next == NULL) {
+ /* found the last return */
+ pCode *pc_call_next = 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 = 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 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(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/pic14/pcode.h b/src/pic14/pcode.h
new file mode 100644
index 0000000..3faca44
--- /dev/null
+++ b/src/pic14/pcode.h
@@ -0,0 +1,907 @@
+/*-------------------------------------------------------------------------
+
+ pcode.h - post code generation
+ 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 __PCODE_H__
+#define __PCODE_H__
+
+#include "common.h"
+
+/* When changing these, you must also update the assembler template
+ * in device/lib/libsdcc/macros.inc */
+#define GPTRTAG_DATA 0x00
+#define GPTRTAG_CODE 0x80
+
+/* Cyclic dependency with ralloc.h: */
+struct reg_info;
+
+/*
+ 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
+
+*/
+
+
+/***********************************************************************
+ * 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) ((void)0)
+#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_RP0_BIT 5 /* Register Bank select bits RP1:0 : */
+#define PIC_RP1_BIT 6 /* 00 - bank 0, 01 - bank 1, 10 - bank 2, 11 - bank 3 */
+#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_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 'W' register
+ PO_STATUS, // The 'STATUS' register
+ PO_FSR, // The "file select register" (in 18c it's one of three)
+ PO_INDF, // 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_GPR_POINTER, // A general purpose pointer
+ 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_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_ANDLW,
+ POC_ANDWF,
+ POC_ANDFW,
+ POC_BCF,
+ POC_BSF,
+ POC_BTFSC,
+ POC_BTFSS,
+ POC_CALL,
+ POC_COMF,
+ POC_COMFW,
+ POC_CLRF,
+ POC_CLRW,
+ POC_CLRWDT,
+ POC_DECF,
+ POC_DECFW,
+ POC_DECFSZ,
+ POC_DECFSZW,
+ POC_GOTO,
+ POC_INCF,
+ POC_INCFW,
+ POC_INCFSZ,
+ POC_INCFSZW,
+ POC_IORLW,
+ POC_IORWF,
+ POC_IORFW,
+ POC_MOVF,
+ POC_MOVFW,
+ POC_MOVLW,
+ POC_MOVWF,
+ POC_NOP,
+ POC_RETLW,
+ POC_RETURN,
+ POC_RETFIE,
+ POC_RLF,
+ POC_RLFW,
+ POC_RRF,
+ POC_RRFW,
+ POC_SUBLW,
+ POC_SUBWF,
+ POC_SUBFW,
+ POC_SWAPF,
+ POC_SWAPFW,
+ POC_TRIS,
+ POC_XORLW,
+ POC_XORWF,
+ POC_XORFW,
+ POC_BANKSEL,
+ POC_PAGESEL,
+
+ /* Enhanced instruction set. */
+
+ POC_ADDFSR,
+ POC_ADDWFC,
+ POC_ADDFWC,
+ POC_ASRF,
+ POC_ASRFW,
+ POC_BRA,
+ POC_BRW,
+ POC_CALLW,
+ POC_LSLF,
+ POC_LSLFW,
+ POC_LSRF,
+ POC_LSRFW,
+ POC_MOVIW,
+ POC_MOVIW_K,
+ POC_MOVLB,
+ POC_MOVLP,
+ POC_MOVWI,
+ POC_MOVWI_K,
+ POC_RESET,
+ POC_SUBWFB,
+ POC_SUBWFBW,
+
+ MAX_PIC14MNEMONICS
+} 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_ASMDIR, /* Assembler directive */
+ 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;
+
+typedef struct pCodeOpLit
+{
+ pCodeOp pcop;
+ int lit;
+} pCodeOpLit;
+
+typedef struct pCodeOpImmd
+{
+ pCodeOp pcop;
+ int offset; /* low,med, or high byte of immediate value */
+ int index; /* add this to the immediate value */
+ unsigned _const:1; /* is in code space */
+ unsigned _function:1; /* is a (pointer to a) function */
+
+ int rIdx; /* If this immd points to a register */
+ struct reg_info *r; /* then this is the reg. */
+
+} pCodeOpImmd;
+
+typedef struct pCodeOpLabel
+{
+ pCodeOp pcop;
+ int key;
+ int offset; /* low or high byte of label */
+} pCodeOpLabel;
+
+typedef struct pCodeOpReg
+{
+ pCodeOp pcop; // Can be either GPR or SFR
+ int rIdx; // Index into the register table
+ struct reg_info *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 pCodeOpStr /* Only used here for the name of fn being called or jumped to */
+{
+ pCodeOp pcop;
+ unsigned isPublic: 1; /* True if not static ie extern */
+} pCodeOpStr;
+
+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.
+
+ unsigned id; // unique ID number for all pCodes to assist in debugging
+ 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 (*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 *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 */
+
+ 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;
+
+
+/*************************************************
+ pCodeAsmDir
+**************************************************/
+
+typedef struct pCodeAsmDir
+{
+ pCodeInstruction pci;
+
+ char *directive;
+ char *arg;
+} pCodeAsmDir;
+
+
+/*************************************************
+ 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. */
+ unsigned isPublic:1; /* True if the fn is not static and can be called from another module (ie a another c or asm file). */
+ unsigned isInterrupt:1; /* True if the fn is interrupt. */
+
+} 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.
+
+ /* (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 PCAD(x) ((pCodeAsmDir *)(x))
+
+#define PCOP(x) ((pCodeOp *)(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 PCOS(x) ((pCodeOpStr *)(x))
+#define PCOW(x) ((pCodeOpWild *)(x))
+
+#define PBR(x) ((pBranch *)(x))
+
+#define PCWB(x) ((pCodeWildBlock *)(x))
+
+#define isPCOLAB(x) ((PCOP(x)->type) == PO_LABEL)
+#define isPCOS(x) ((PCOP(x)->type) == PO_STR)
+
+
+/*
+ macros for checking pCode types
+*/
+#define isPCI(x) ((PCODE(x)->type == PC_OPCODE))
+#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 isPCASMDIR(x) ((PCODE(x)->type == PC_ASMDIR))
+
+/*
+ macros for checking pCodeInstruction types
+*/
+#define isCALL(x) (isPCI(x) && (PCI(x)->op == POC_CALL))
+#define isPCI_BRANCH(x) (isPCI(x) && PCI(x)->isBranch)
+#define isPCI_SKIP(x) (isPCI(x) && PCI(x)->isSkip)
+#define isPCI_LIT(x) (isPCI(x) && PCI(x)->isLit)
+#define isPCI_BITSKIP(x)(isPCI_SKIP(x) && PCI(x)->isBitInst)
+
+
+#define isSTATUS_REG(r) ((r)->pc_type == PO_STATUS)
+
+/*-----------------------------------------------------------------*
+ * pCode functions.
+ *-----------------------------------------------------------------*/
+
+pCode *newpCode(PIC_OPCODE op, pCodeOp *pcop); // Create a new pCode given an operand
+pCode *newpCodeCharP(const char *cP); // Create a new pCode given a char *
+pCode *newpCodeFunction(const char *g, const char *f, int, int); // Create a new function.
+pCode *newpCodeLabel(const char *name,int key); // Create a new label given a key
+pCode *newpCodeCSource(int ln, const char *f, const char *l); // Create a new symbol line.
+pCode *newpCodeWild(int pCodeID, pCodeOp *optional_operand, pCodeOp *optional_label);
+pCode *findNextInstruction(pCode *pci);
+pCode *findPrevInstruction(pCode *pci);
+pCode *findNextpCode(pCode *pc, PC_TYPE pct);
+pCode *pCodeInstructionCopy(pCodeInstruction *pci,int invert);
+
+pBlock *newpCodeChain(memmap *cm,char c, pCode *pc); // Create a new pBlock
+void printpBlock(FILE *of, pBlock *pb); // Write a pBlock to a file
+void printpCode(FILE *of, pCode *pc); // Write a pCode to a file
+void addpCode2pBlock(pBlock *pb, pCode *pc); // Add a pCode to a pBlock
+void addpBlock(pBlock *pb); // Add a pBlock to a pFile
+void unlinkpCode(pCode *pc);
+void copypCode(FILE *of, char dbName); // Write all pBlocks with dbName to *of
+void movepBlock2Head(char dbName); // move pBlocks around
+void AnalyzeBanking(void);
+void ReuseReg(void);
+void AnalyzepCode(char dbName);
+void InlinepCode(void);
+void pCodeInitRegisters(void);
+void pic14initpCodePeepCommands(void);
+void pBlockConvert2ISR(pBlock *pb);
+void pBlockMergeLabels(pBlock *pb);
+void pCodeInsertAfter(pCode *pc1, pCode *pc2);
+void pCodeInsertBefore(pCode *pc1, pCode *pc2);
+void pCodeDeleteChain(pCode *f,pCode *t);
+
+pCode *newpCodeAsmDir(const char *asdir, const char *argfmt, ...);
+
+pCodeOp *newpCodeOpLabel(const char *name, int key);
+pCodeOp *newpCodeOpImmd(const char *name, int offset, int index, int code_space,int is_func);
+pCodeOp *newpCodeOpLit(int lit);
+pCodeOp *newpCodeOpBit(const char *name, int bit,int inBitSpace);
+pCodeOp *newpCodeOpWild(int id, pCodeWildBlock *pcwb, pCodeOp *subtype);
+pCodeOp *newpCodeOpRegFromStr(const char *name);
+pCodeOp *newpCodeOp(const char *name, PIC_OPTYPE p);
+pCodeOp *pCodeOpCopy(pCodeOp *pcop);
+pCodeOp *popCopyGPR2Bit(pCodeOp *pc, int bitval);
+pCodeOp *popCopyReg(pCodeOpReg *pc);
+
+pBranch *pBranchAppend(pBranch *h, pBranch *n);
+
+struct reg_info * getRegFromInstruction(pCode *pc);
+
+char *get_op(pCodeOp *pcop, char *buff, size_t buf_size);
+char *pCode2str(char *str, size_t size, pCode *pc);
+
+int pCodePeepMatchRule(pCode *pc);
+
+void pcode_test(void);
+void resetpCodeStatistics (void);
+void dumppCodeStatistics (FILE *of);
+
+/*-----------------------------------------------------------------*
+ * pCode objects.
+ *-----------------------------------------------------------------*/
+
+extern pCodeOpReg pc_status;
+extern pCodeOpReg pc_intcon;
+extern pCodeOpReg pc_fsr;
+extern pCodeOpReg pc_fsr0l;
+extern pCodeOpReg pc_fsr0h;
+extern pCodeOpReg *pc_indf; /* pointer to either pc_indf_ or pc_indf0 */
+extern pCodeOpReg pc_indf_;
+extern pCodeOpReg pc_indf0;
+extern pCodeOpReg pc_pcl;
+extern pCodeOpReg pc_pclath;
+extern pCodeOpReg pc_wsave; /* wsave, ssave and psave are used to save W, the Status and PCLATH*/
+extern pCodeOpReg pc_ssave; /* registers during an interrupt */
+extern pCodeOpReg pc_psave; /* registers during an interrupt */
+
+extern pFile *the_pFile;
+extern pCodeInstruction *pic14Mnemonics[MAX_PIC14MNEMONICS];
+
+/*
+ * From pcodepeep.h:
+ */
+int getpCode(const char *mnem, unsigned dest);
+int getpCodePeepCommand(const char *cmd);
+int pCodeSearchCondition(pCode *pc, unsigned int cond, int contIfSkip);
+
+#endif // __PCODE_H__
+
diff --git a/src/pic14/pcodeflow.c b/src/pic14/pcodeflow.c
new file mode 100644
index 0000000..decf088
--- /dev/null
+++ b/src/pic14/pcodeflow.c
@@ -0,0 +1,226 @@
+/*-------------------------------------------------------------------------
+
+ pcodeflow.c - post code generation flow analysis
+
+ 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.
+
+-------------------------------------------------------------------------*/
+/*
+ pcodeflow.c
+
+ The purpose of the code in this file is to analyze the flow of the
+ pCode.
+
+*/
+
+#include "pcodeflow.h"
+
+#if 0
+static void dbg_dumpFlow(pBlock *pb)
+{
+ pCode *pcflow;
+
+ for( pcflow = findNextpCode(pb->pcHead, PC_FLOW);
+ pcflow != NULL;
+ pcflow = 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");
+ }
+ }
+
+}
+#endif
+
+#if 0
+/*-----------------------------------------------------------------*
+* 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;
+ }
+ }
+
+}
+#endif
+
+void BuildFlowTree(pBlock *pb)
+{
+ pCodeFlow *first_pcflow, *pcflow;
+
+
+ // fprintf(stderr,"BuildFlowTree \n");
+
+ first_pcflow = PCFL(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(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(findNextpCode(pcflow->pc.next, PC_FLOW));
+
+ }
+
+ pcflow = PCFL(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(findNextpCode(pcflow->pc.next, PC_FLOW));
+
+ }
+
+ // BuildFlowSegment(pcflow);
+
+ //dbg_dumpFlow(pb);
+
+}
diff --git a/src/pic14/pcodeflow.h b/src/pic14/pcodeflow.h
new file mode 100644
index 0000000..1577770
--- /dev/null
+++ b/src/pic14/pcodeflow.h
@@ -0,0 +1,68 @@
+/*-------------------------------------------------------------------------
+
+ pcode.h - post code generation
+ 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 __PCODEFLOW_H__
+#define __PCODEFLOW_H__
+
+#include "pcode.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_C (1<<1)
+#define PCC_Z (1<<2)
+#define PCC_DC (1<<3)
+#define PCC_W (1<<4)
+#define PCC_EXAMINE_PCOP (1<<5)
+#define PCC_REG_BANK0 (1<<6)
+#define PCC_REG_BANK1 (1<<7)
+#define PCC_REG_BANK2 (1<<8)
+#define PCC_REG_BANK3 (1<<9)
+#define PCC_LITERAL (1<<10)
+
+/*------------------------------------------------------------*/
+
+void BuildFlowTree(pBlock *pb);
+
+#endif // __PCODEFLOW_H__
+
diff --git a/src/pic14/pcodepeep.c b/src/pic14/pcodepeep.c
new file mode 100644
index 0000000..fad58af
--- /dev/null
+++ b/src/pic14/pcodepeep.c
@@ -0,0 +1,2005 @@
+/*-------------------------------------------------------------------------
+
+ pcodepeep.c - post code generation
+ 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.
+-------------------------------------------------------------------------*/
+
+#include "pcode.h"
+#include "pcodeflow.h"
+#include "ralloc.h"
+
+//#define PCODE_DEBUG
+
+#define IS_PCCOMMENT(x) ( x && (x->type==PC_COMMENT))
+
+
+/****************************************************************/
+/****************************************************************/
+typedef struct DLList {
+ struct DLList *prev;
+ struct DLList *next;
+ // void *data;
+} DLList;
+
+
+typedef struct pCodePeepSnippets
+{
+ DLList dll;
+ pCodePeep *peep;
+} pCodePeepSnippets;
+
+
+/****************************************************************/
+/* */
+/* peepSnippets - */
+/* */
+/****************************************************************/
+
+static pCodePeepSnippets *peepSnippets=NULL;
+
+
+typedef struct pCodeToken
+{
+ int tt; // token type;
+ union {
+ char c; // character
+ int n; // number
+ char *s; // string
+ } tok;
+
+} pCodeToken;
+
+static 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
+static parsedPattern parsedPatArr[MAX_PARSEDPATARR];
+
+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(DLList *list, DLList *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((unsigned char)*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, pc_status.pcop.name))
+ return NULL;
+
+ len = strlen(bit);
+
+ if(len == 1) {
+ // check C,Z
+ if(toupper((unsigned char)*bit) == 'C')
+ return PCOP(popCopyGPR2Bit(PCOP(&pc_status),PIC_C_BIT));
+ if(toupper((unsigned char)*bit) == 'Z')
+ return PCOP(popCopyGPR2Bit(PCOP(&pc_status),PIC_Z_BIT));
+ }
+
+ // Check DC
+ if(len ==2 && toupper((unsigned char)bit[0]) == 'D' && toupper((unsigned char)bit[1]) == 'C')
+ return PCOP(popCopyGPR2Bit(PCOP(&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 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 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 = getpCode(p->pct[0].tok.s,0);
+
+ if(opcode < 0) {
+ /* look for special command strings like _NOTBITSKIP_ */
+
+ //fprintf(stderr, "Bad mnemonic\n");
+
+ opcode = 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(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 > pcwb->nwildpCodes)
+ pcwb->nwildpCodes = p[0].pct[1].tok.n;
+
+ return 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 = getpCode(p->pct[0].tok.s,0);
+ if(opcode < 0) {
+ //fprintf(stderr, "Bad mnemonic\n");
+ opcode = 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(pic14Mnemonics[opcode]->isBitInst)
+ pcosubtype = newpCodeOp(p[1].pct[0].tok.s,PO_BIT);
+ else
+ pcosubtype = newpCodeOp(p[1].pct[0].tok.s,PO_GPR_REGISTER);
+
+
+ pci = PCI(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 = getpCode(p->pct[0].tok.s,0);
+ if(opcode < 0) {
+ int cmd_id = 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 = 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(pic14Mnemonics[opcode]->isBitInst)
+ pcosubtype = newpCodeOpBit(NULL,-1,0);
+ else
+ pcosubtype = newpCodeOp(NULL,PO_GPR_REGISTER);
+
+
+ pci = PCI(newpCode(opcode,
+ newpCodeOpWild(p[1].pct[1].tok.n, pcwb, pcosubtype)));
+
+ /* Save the index of the maximum wildcard variable */
+ 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 = getpCode(p->pct[0].tok.s,0);
+ if(opcode < 0) {
+ fprintf(stderr, "Bad mnemonic\n");
+ return NULL;
+ }
+
+ pci = PCI(newpCode(opcode, 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 = getpCode(p->pct[0].tok.s,dest);
+ if(opcode < 0) {
+ fprintf(stderr, "Bad mnemonic\n");
+ return NULL;
+ }
+
+ if(pic14Mnemonics[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 = newpCodeOp(p[1].pct[0].tok.s,PO_GPR_REGISTER);
+
+
+ pci = PCI(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 = getpCode(p->pct[0].tok.s,dest);
+ if(opcode < 0) {
+ fprintf(stderr, "Bad mnemonic\n");
+ return NULL;
+ }
+
+ if(pic14Mnemonics[opcode]->isBitInst)
+ pcosubtype = newpCodeOp(NULL,PO_BIT);
+ else
+ pcosubtype = newpCodeOp(NULL,PO_GPR_REGISTER);
+
+
+ pci = PCI(newpCode(opcode,
+ newpCodeOpWild(p[1].pct[1].tok.n, pcwb, pcosubtype)));
+
+ /* Save the index of the maximum wildcard variable */
+ 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;
+
+ pCodeInstruction *pci=NULL;
+ pCodeOp *pcosubtype=NULL;
+
+ 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 = getpCode(p->pct[0].tok.s,0);
+ if(opcode < 0) {
+ fprintf(stderr, "Bad mnemonic\n");
+ return NULL;
+ }
+
+
+ if(pic14Mnemonics[opcode]->isBitInst) {
+ //pcosubtype = cvt_extract_status(p[1].pct[0].tok.s, p[3].pct[0].tok.s);
+
+ //if(pcosubtype == NULL) {
+ pcosubtype = newpCodeOpBit(p[1].pct[0].tok.s,p[3].pct[0].tok.n,0);
+ //}
+ } else
+ pcosubtype = newpCodeOp(p[1].pct[0].tok.s,PO_GPR_REGISTER);
+
+ if(pcosubtype == NULL) {
+ fprintf(stderr, "Bad operand\n");
+ return NULL;
+ }
+
+ pci = PCI(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((unsigned char)*ln)) {
+ // add a SPACE token and eat the extra spaces.
+ tokArr[tokIdx++].tt = PCT_SPACE;
+ while (isspace ((unsigned char)*ln))
+ ln++;
+ continue;
+ }
+
+ if(isdigit((unsigned char)*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((unsigned char)*ln) || (*ln == '_') ) {
+ char buffer[50];
+ int i=0;
+
+ while( (isalpha((unsigned char)*ln) || isdigit((unsigned char)*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;
+
+ //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(&ltokIdx, 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"));
+ state = PS_HAVE_MNEM;
+ break;
+ case PS_HAVE_MNEM:
+ DFPRINTF((stderr," 1st operand\n"));
+ //pco1 = 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"));
+ 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(&ltokIdx, 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(pc) {
+ if (pcret) {
+ *pcret = pc;
+ return 0; // Only accept one line for now.
+ } else
+ addpCode2pBlock(pcwb->pb, pc);
+ } else
+ error++;
+ }
+ j += c;
+ }
+ k++;
+ }
+ while(j<=lparsedPatIdx && k<ALTPATTERNS);
+
+ /*
+ DFPRINTF((stderr,"\nConverting parsed line to pCode:\n\n"));
+
+ j = 0;
+ do {
+ if(parsedPatArr[j].pcp && parsedPatArr[j].pcp->f )
+ parsedPatArr[j].pcp->f(&parsedPatArr[j]);
+ DFPRINTF((stderr," %d",parsedPatArr[j].pcp->pt));
+ j++;
+ }
+ while(j<lparsedPatIdx);
+ */
+ DFPRINTF((stderr,"\n"));
+
+ }
+
+ return error;
+}
+
+/*-----------------------------------------------------------------*/
+/* */
+/*-----------------------------------------------------------------*/
+static void peepRuleBlock2pCodeBlock(lineNode *ln, pCodeWildBlock *pcwb)
+{
+
+ if(!ln)
+ return;
+
+ for( ; ln; ln = ln->next) {
+
+ //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);
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* 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_alloc(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_alloc(sizeof(pCodeWildBlock));
+
+ if(!pcp)
+ return;
+
+ initpCodeWildBlock(&pcp->target);
+ pcp->target.pb = newpCodeChain(NULL, 'W', NULL);
+
+ initpCodeWildBlock(&pcp->replace);
+ pcp->replace.pb = 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. */
+/* */
+/*-----------------------------------------------------------------*/
+void peepRules2pCode(peepRule *rules)
+{
+ peepRule *pr;
+
+ pCodePeep *currentRule;
+ pCodePeepSnippets *pcps;
+
+ pic14initpCodePeepCommands();
+
+ /* 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_alloc(sizeof(pCodePeepSnippets));
+ peepSnippets = DLL_append((DLList*)peepSnippets,(DLList*)pcps);
+
+ currentRule = pcps->peep = Safe_alloc(sizeof(pCodePeep));
+ initpCodePeep(currentRule);
+
+ /* Convert the target block */
+ peepRuleBlock2pCodeBlock(pr->match, &currentRule->target);
+
+ //DFPRINTF((stderr,"finished target, here it is in pcode form:\n"));
+ //printpBlock(stderr, currentRule->target.pb);
+
+ pBlockMergeLabels(currentRule->target.pb);
+ //printpBlock(stderr, currentRule->replace.pb);
+
+ /* Convert the replace block */
+ peepRuleBlock2pCodeBlock(pr->replace, &currentRule->replace);
+
+ //DFPRINTF((stderr,"replace with labels merged:\n"));
+
+ pBlockMergeLabels(currentRule->replace.pb);
+ //printpBlock(stderr, currentRule->replace.pb);
+
+ peepRuleCondition(pr->cond,currentRule);
+
+ /* The rule has been converted to pCode. Now allocate
+ * space for the wildcards */
+
+ postinit_pCodeWildBlock(&currentRule->target);
+ postinit_pCodeWildBlock(&currentRule->replace);
+
+ //return; // debug ... don't want to go through all the rules yet
+ }
+
+ if (0)
+ {
+ pCodePeep *peepBlock;
+ DLList *peeprules;
+
+ peeprules = (DLList *)peepSnippets;
+ fprintf(stderr,"target rules\n");
+ while (peeprules)
+ {
+ fprintf(stderr," rule:\n");
+ peepBlock = ((pCodePeepSnippets*)peeprules)->peep;
+ printpBlock(stderr, peepBlock->target.pb);
+ peeprules = peeprules->next;
+ } // while
+ fprintf(stderr," ... done\n");
+ } // if
+}
+
+/*-----------------------------------------------------------------*/
+/* DLList * DLL_append */
+/* */
+/* Append a DLList object to the end of a DLList (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 DLList object is appended to it. In either case, */
+/* the void *data is added to the newly created DLL object. */
+/*-----------------------------------------------------------------*/
+
+static void * DLL_append(DLList *list, DLList *next)
+{
+ DLList *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.
+
+
+ <FIX ME> - 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 pCodeSearchCondition(pCode *pc, unsigned int cond, int contIfSkip)
+{
+ 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) {
+ if(PCI(pc)->inCond & cond) {
+ if (contIfSkip) {
+ /* If previous instruction is a skip then continue search as condiction is not certain */
+ pCode *pcp = findPrevInstruction(pc->prev);
+ if (pcp && !isPCI_SKIP(pcp)) {
+ return 1;
+ }
+ } else {
+ return 1;
+ }
+ }
+ if(PCI(pc)->outCond & cond) {
+ if (contIfSkip) {
+ /* If previous instruction is a skip then continue search as condiction is not certain */
+ pCode *pcp = findPrevInstruction(pc->prev);
+ if (pcp && !isPCI_SKIP(pcp)) {
+ return -1;
+ }
+ } else {
+ 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",
+ get_op( pcops,NULL,0));
+
+ fprintf(stderr," to %s\n",
+ 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;
+ get_op(pcops,b,50);
+
+ n2 = 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) {
+ // Volatile types should not be deleted or modified, these include SFR, externs and publics
+ // They can be used as a matched, however if a match is found then the optimiser intends
+ // to change some aspect of a block of code, which is most likely a critcal one. As this
+ // method of optimisation does not allow a means to distiguishing what may change, it is
+ // best to just negate any match.
+ if (PCI(pcs)->pcop) {
+ struct reg_info *r;
+ pCodeOp *pcop = PCI(pcs)->pcop;
+ switch(pcop->type) {
+ case PO_W:
+ case PO_STATUS:
+ case PO_FSR:
+ case PO_INDF:
+ case PO_INTCON:
+ case PO_PCL:
+ case PO_PCLATH:
+ case PO_SFR_REGISTER:
+ return 0; // SFR - do not modify
+ case PO_DIR:
+ case PO_GPR_REGISTER:
+ case PO_GPR_BIT:
+ case PO_GPR_TEMP:
+ case PO_GPR_POINTER:
+ r = PCOR(pcop)->r;
+ if (r->isPublic||r->isExtern||r->isFixed) // Changes to these types of registers should not be changed as they may be used else where
+ return 0;
+ default:
+ break;
+ }
+ }
+ if (PCI(pcd)->pcop->type == PO_WILD) {
+ char *n;
+ 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
+ n = PCI(pcs)->pcop->name;
+ if(peepBlock->target.vars[index]) {
+ if ((!n)||(strcmp(peepBlock->target.vars[index],n) != 0))
+ return 0; // variable is different
+ } else {
+ DFPRINTF((stderr,"first time for a variable: %d, %s\n",index,n));
+ peepBlock->target.vars[index] = n;
+ }
+
+ PCOW(PCI(pcd)->pcop)->matched = PCI(pcs)->pcop;
+ if(!peepBlock->target.wildpCodeOps[index]) {
+ peepBlock->target.wildpCodeOps[index] = PCI(pcs)->pcop;
+
+ //fprintf(stderr, "first time for wild opcode #%d\n",index);
+ return 1;
+
+ } 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_FSR:
+ //case PO_INDF:
+ //n = PCOR(PCI(pcs)->pcop)->r->name;
+ n = PCI(pcs)->pcop->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) {
+ /*
+ pcs->print(stderr,pcs);
+ pcd->print(stderr,pcd);
+
+ fprintf(stderr, "comparing literal operands of these instructions, result %d\n",
+ pCodeOpCompare(PCI(pcs)->pcop, PCI(pcd)->pcop));
+ */
+ return pCodeOpCompare(PCI(pcs)->pcop, PCI(pcd)->pcop);
+
+ } else {
+ /* FIXME - need an else to check the case when the destination
+ * isn't a wild card */
+ /*
+ fprintf(stderr, "Destination is not wild: operand compare =%d\n",
+ pCodeOpCompare(PCI(pcs)->pcop, PCI(pcd)->pcop));
+ */
+ return pCodeOpCompare(PCI(pcs)->pcop, PCI(pcd)->pcop);
+
+ }
+ } 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 = 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;i<pcp->target.nvars; i++)
+ pcp->target.vars[i] = NULL;
+ for(i=0;i<pcp->target.nops; i++)
+ pcp->target.wildpCodeOps[i] = NULL;
+ for(i=0;i<pcp->target.nwildpCodes; i++)
+ pcp->target.wildpCodes[i] = NULL;
+
+ for(i=0;i<pcp->replace.nvars; i++)
+ pcp->replace.vars[i] = NULL;
+ for(i=0;i<pcp->replace.nops; i++)
+ pcp->replace.wildpCodeOps[i] = NULL;
+ for(i=0;i<pcp->replace.nwildpCodes; i++)
+ pcp->replace.wildpCodes[i] = NULL;
+
+
+
+}
+
+/*-----------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+int pCodePeepMatchRule(pCode *pc)
+{
+ pCodePeep *peepBlock;
+ pCode *pct, *pcin;
+ pCodeCSource *pc_cline=NULL;
+ DLList *peeprules;
+ int matched;
+
+ peeprules = (DLList *)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 = findNextInstruction(pcin->next);
+ */
+ pcin = pc = 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 = findNextInstruction(pcin->next);
+ pct = pct->next;
+ //debug:
+ //DFPRINTF((stderr," matched\n"));
+
+ if(!pcin && pct) {
+ DFPRINTF((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 &&
+ (pCodeSearchCondition(pcin,peepBlock->postFalseCond,0) > 0) )
+ matched = 0;
+
+ //fprintf(stderr," condition results = %d\n",pCodeSearchCondition(pcin,peepBlock->postFalseCond));
+
+
+ //if(!matched) fprintf(stderr,"failed on conditions\n");
+ }
+
+ if(matched) {
+
+ pCode *pcprev;
+ pCode *pcr, *pcout;
+
+
+ /* 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 */
+ pcout = pc;
+ 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);
+ pCodeInsertAfter(pcprev, 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 = pCodeOpCopy(peepBlock->target.wildpCodeOps[index]);
+ else
+ DFPRINTF((stderr,"error, wildopcode in replace but not source?\n"));
+ } else
+ pcop = pCodeOpCopy(PCI(pcr)->pcop);
+ }
+ //DFPRINTF((stderr,"inserting pCode\n"));
+ pCodeInsertAfter(pc, 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"));
+ pCodeInsertAfter(pc,
+ pCodeInstructionCopy(PCI(peepBlock->target.wildpCodes[PCW(pcr)->id]),
+ PCW(pcr)->invertBitSkipInst));
+ } else if (pcr->type == PC_COMMENT) {
+ pCodeInsertAfter(pc, 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 && pc_cline ) {
+
+ pc = findNextInstruction(pc->next);
+ if (!pc) break;
+ PCI(pc)->cline = pc_cline;
+ pc_cline = PCCS(pc_cline->pc.next);
+
+ }
+
+ /* Copy C code comments to new code. */
+ pc = pcprev->next;
+ if (pc) {
+ for (; pc && pcout!=pcin; pcout=pcout->next) {
+ if (pcout->type==PC_OPCODE && PCI(pcout)->cline) {
+ while (pc->type!=PC_OPCODE || PCI(pc)->cline) {
+ pc = pc->next;
+ if (!pc)
+ break;
+ }
+ if (!pc) break;
+ PCI(pc)->cline = PCI(pcout)->cline;
+ }
+ }
+ }
+
+ return 1;
+ }
+next_rule:
+ peeprules = peeprules->next;
+ }
+ DFPRINTF((stderr," no rule matched\n"));
+
+ return 0;
+}
diff --git a/src/pic14/pcoderegs.c b/src/pic14/pcoderegs.c
new file mode 100644
index 0000000..84d9335
--- /dev/null
+++ b/src/pic14/pcoderegs.c
@@ -0,0 +1,802 @@
+/*-------------------------------------------------------------------------
+
+ pcoderegs.c - 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.
+
+-------------------------------------------------------------------------*/
+
+/*
+pcoderegs.c
+
+ The purpose of the code in this file is to optimize the register usage.
+
+*/
+
+#include "main.h"
+#include "pcoderegs.h"
+#include "pcodeflow.h"
+#include "ralloc.h"
+
+
+static int total_registers_saved=0;
+static int register_optimization=1;
+
+/*-----------------------------------------------------------------*
+* void pCodeRegMapLiveRangesInFlow(pCodeFlow *pcfl)
+*-----------------------------------------------------------------*/
+static void pCodeRegMapLiveRangesInFlow(pCodeFlow *pcfl)
+{
+
+ pCode *pc=NULL;
+
+ reg_info *reg;
+
+ if(!pcfl)
+ return;
+
+
+ pc = findNextInstruction(pcfl->pc.next);
+
+ while(pc && !isPCFL(pc)) {
+ while (pc && !isPCI(pc) && !isPCFL(pc))
+ {
+ pc = pc->next;
+ } // while
+ if (!pc || isPCFL(pc)) continue;
+ assert( isPCI(pc) );
+
+ reg = getRegFromInstruction(pc);
+ #if 0
+ pc->print(stderr, pc);
+ fprintf( stderr, "--> reg %p (%s,%u), inCond/outCond: %x/%x\n",
+ reg, reg ? reg->name : "(null)", reg ? reg->rIdx : -1,
+ PCI(pc)->inCond, PCI(pc)->outCond );
+ #endif
+ 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 & PCI(pc)->inCond)
+ addSetIfnotP(& (reg->reglives.usedpFlows), pcfl);
+
+ if(PCC_REGISTER & PCI(pc)->outCond)
+ addSetIfnotP(& (reg->reglives.assignedpFlows), pcfl);
+
+ addSetIfnotP(& (reg->reglives.usedpCodes), pc);
+ reg->wasUsed = TRUE;
+ }
+
+
+ //pc = findNextInstruction(pc->next);
+ pc = pc->next;
+
+ }
+
+}
+
+/*-----------------------------------------------------------------*
+* void pCodeRegMapLiveRanges(pBlock *pb)
+*-----------------------------------------------------------------*/
+void pCodeRegMapLiveRanges(pBlock *pb)
+{
+ pCode *pcflow;
+
+ for( pcflow = findNextpCode(pb->pcHead, PC_FLOW);
+ pcflow != NULL;
+ pcflow = 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 = findNextpCode(pb->pcHead, PC_FLOW);
+ pcflow != NULL;
+ pcflow = 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
+
+}
+
+
+/*-----------------------------------------------------------------*
+*
+*-----------------------------------------------------------------*/
+static void Remove1pcode(pCode *pc, reg_info *reg, int debug_code)
+{
+
+ pCode *pcn=NULL;
+
+ if(!reg || !pc)
+ return;
+
+ deleteSetItem (&(reg->reglives.usedpCodes),pc);
+
+ if(PCI(pc)->label) {
+ pcn = findNextInstruction(pc->next);
+
+ if(pcn)
+ PCI(pcn)->label = pBranchAppend(PCI(pcn)->label,PCI(pc)->label);
+ }
+
+ if(PCI(pc)->cline) {
+ if(!pcn)
+ pcn = 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;
+ }
+ }
+ }
+
+
+ if(1) {
+ /*
+ * Debug stuff. Comment out the instruction we're about to delete.
+ */
+
+ char buff1[256];
+ size_t size = 256;
+
+ char *pbuff;
+ pbuff = &buff1[0];
+
+ SNPRINTF(pbuff, size, ";%d", debug_code);
+ size -= strlen(pbuff);
+ pbuff += strlen(pbuff);
+ pCode2str(pbuff, size, pc);
+ pCodeInsertBefore(pc, newpCodeCharP(buff1));
+ //fprintf(stderr,"removing instruction:\n%s\n",buff1);
+ }
+
+ pc->destruct(pc);
+
+}
+
+/*-----------------------------------------------------------------*
+* void RemoveRegsFromSet(set *regset)
+*
+*-----------------------------------------------------------------*/
+static void RemoveRegsFromSet(set *regset)
+{
+ reg_info *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 = TRUE;
+ reg->wasUsed = FALSE;
+ } else {
+ pCode *pc;
+
+
+ pc = setFirstItem(reg->reglives.usedpCodes);
+
+ if(reg->type == REG_SFR || reg->type == REG_STK || reg->isPublic || reg->isExtern) {
+ //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 = 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)) {
+ reg_info *r = 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, 1);
+ /*
+ unlinkpCode(pc);
+ deleteSetItem (&(reg->reglives.usedpCodes),pc);
+ */
+ reg->isFree = TRUE;
+ reg->wasUsed = FALSE;
+ total_registers_saved++; // debugging stats.
+ }
+ }
+ }
+
+ }
+}
+
+static void pic14_ReMapLiveRanges(void)
+{
+ pBlock *pb;
+ if (!the_pFile) return;
+ RegsUnMapLiveRanges();
+ for (pb = the_pFile->pbHead; pb; pb = pb->next)
+ {
+ #if 0
+ pCode *pc = findNextpCode(pb->pcHead, PC_FLOW);
+ if (pc) {
+ pc->print( stderr, pc );
+ } else {
+ fprintf( stderr, "unnamed pBlock\n");
+ }
+ pc = findNextInstruction(pb->pcHead);
+ while (pc) {
+ pc->print( stderr, pc );
+ pc = findNextInstruction(pc->next);;
+ }
+ #endif
+ pCodeRegMapLiveRanges(pb);
+ } // for
+}
+
+/*-----------------------------------------------------------------*
+* void RemoveUnusedRegisters(void)
+*
+*-----------------------------------------------------------------*/
+void RemoveUnusedRegisters(void)
+{
+ /* First, get rid of registers that are used only one time */
+ pic14_ReMapLiveRanges();
+
+ //RemoveRegsFromSet(dynInternalRegs);
+ RemoveRegsFromSet(dynAllocRegs);
+ RemoveRegsFromSet(dynStackRegs);
+ /*
+ don't do DirectRegs yet - there's a problem with arrays
+ RemoveRegsFromSet(dynDirectRegs);
+ */
+ RemoveRegsFromSet(dynDirectBitRegs);
+
+ if(total_registers_saved) DFPRINTF((stderr, " *** Saved %d registers ***\n", total_registers_saved));
+}
+
+
+/*-----------------------------------------------------------------*
+*
+*-----------------------------------------------------------------*/
+static void Remove2pcodes(pCode *pcflow, pCode *pc1, pCode *pc2, reg_info *reg, int can_free)
+{
+ static int debug_code=99;
+ if(!reg)
+ return;
+#if 0
+ fprintf (stderr, "%s:%d(%s): %d (reg:%s)\n", __FILE__, __LINE__, __FUNCTION__, debug_code, reg ? reg->name : "???");
+ printpCode (stderr, pc1);
+ printpCode (stderr, pc2);
+#endif
+
+ //fprintf(stderr,"%s\n",__FUNCTION__);
+ if(pc1)
+ Remove1pcode(pc1, reg, debug_code++);
+
+ if(pc2) {
+ Remove1pcode(pc2, reg, debug_code++);
+ deleteSetItem (&(PCFL(pcflow)->registers), reg);
+
+ if(can_free) {
+ reg->isFree = TRUE;
+ reg->wasUsed = FALSE;
+ }
+
+ }
+
+ pCodeRegMapLiveRangesInFlow(PCFL(pcflow));
+}
+
+/*-----------------------------------------------------------------*
+*
+*-----------------------------------------------------------------*/
+static int regUsedinRange(pCode *pc1, pCode *pc2, reg_info *reg)
+{
+ int i=0;
+ reg_info *testreg;
+
+ do {
+ testreg = getRegFromInstruction(pc1);
+ if(testreg && (testreg->rIdx == reg->rIdx)) {
+ return 1;
+ }
+ if (i++ > 1000) {
+ fprintf(stderr, "warning, regUsedinRange searched through too many pcodes\n");
+ return 0;
+ }
+
+ pc1 = findNextInstruction(pc1->next);
+
+ } while (pc1 && (pc1 != pc2)) ;
+
+ return 0;
+}
+
+static int regIsSpecial (reg_info *reg, int mayBeGlobal)
+{
+ if (!reg) return 0;
+
+ if (reg->type == REG_SFR || reg->type == REG_STK || (!mayBeGlobal && (reg->isPublic || reg->isExtern))) return 1;
+
+ 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, reg_info *reg, int can_free, int optimize_level)
+{
+ pCode *pct1, *pct2;
+ reg_info *reg1, *reg2;
+
+ int t = total_registers_saved;
+
+ if (!isPCI(pc1) || !isPCI(pc2)) return 0;
+ if (PCI(pc1)->pcflow != PCI(pc2)->pcflow) return 0;
+
+ if (pc2->seq < pc1->seq) {
+ pct1 = pc2;
+ pc2 = pc1;
+ pc1 = pct1;
+ }
+
+ /* disable this optimization for now -- it's buggy */
+ if (pic14_options.disable_df) return 0;
+
+ //fprintf(stderr,"pCodeOptime2pCodes\n");
+ //pc1->print(stderr,pc1);
+ //pc2->print(stderr,pc2);
+
+ if((PCI(pc1)->op == POC_CLRF) && (PCI(pc2)->op == POC_MOVFW) ){
+ /*
+ * CLRF sets Z
+ * MOVFW affects Z
+ * MOVWF does not touch Z
+ * MOVLW does not touch Z
+ */
+ pCode *newpc;
+ /*
+ clrf reg ; pc1
+ stuff...
+ movf reg,w ; pc2
+
+ can be replaced with (only if following instructions are not going to use W and reg is not used again later)
+
+ stuff...
+ movlw 0 or clrf reg
+ */
+ DFPRINTF((stderr, " optimising CLRF reg ... MOVF reg,W to ... MOVLW 0\n"));
+ pct2 = findNextInstruction(pc2->next);
+ if (pCodeSearchCondition(pct2, PCC_Z, 0) == -1) {
+ /* Z is definitely overwritten before use */
+ newpc = newpCode(POC_MOVLW, newpCodeOpLit(0));
+
+ pCodeInsertAfter(pc2, newpc);
+ PCI(newpc)->pcflow = PCFL(pcfl_used);
+ newpc->seq = pc2->seq;
+
+ //fprintf (stderr, "%s:%d(%s): Remove2pcodes (CLRF reg, ..., MOVF reg,W)\n", __FILE__, __LINE__, __FUNCTION__);
+ //Remove2pcodes(pcfl_used, pc2, NULL, reg, 0);
+ pc2->destruct(pc2);
+ //total_registers_saved++; // debugging stats.
+ }
+ } else if((PCI(pc1)->op == POC_CLRF) && (PCI(pc2)->op == POC_IORFW) ){
+ DFPRINTF((stderr, " optimising CLRF/IORFW\n"));
+
+ pct2 = findNextInstruction(pc2->next);
+
+ /* We must ensure that Z is destroyed before being read---IORLW must be performed unless this is proven. */
+ if (pCodeSearchCondition(pct2, PCC_Z, 0) != -1) {
+ pct2 = newpCode(POC_IORLW, newpCodeOpLit(0));
+ pct2->seq = pc2->seq;
+ PCI(pct2)->pcflow = PCFL(pcfl_used);
+ pCodeInsertAfter(pc1,pct2);
+ }
+ //fprintf (stderr, "%s:%d(%s): Remove2pcodes (CLRF/IORFW)\n", __FILE__, __LINE__, __FUNCTION__);
+ Remove2pcodes(pcfl_used, pc1, pc2, reg, can_free);
+ total_registers_saved++; // debugging stats.
+
+ } else if(PCI(pc1)->op == POC_MOVWF) {
+ // Optimising MOVWF reg ...
+
+ pct2 = findNextInstruction(pc2->next);
+
+ if(PCI(pc2)->op == POC_MOVFW) {
+ // Optimising MOVWF reg ... MOVF reg,W
+
+ if(PCI(pct2)->op == POC_MOVWF) {
+ /*
+ Change:
+
+ movwf reg ; pc1
+ stuff...
+ movf reg,w ; pc2
+ movwf reg2 ; pct2
+
+ To: ( as long as 'stuff' does not use reg2 or if following instructions do not use W or reg is not used later)
+
+ movwf reg2
+ stuff...
+
+ */
+ reg2 = getRegFromInstruction(pct2);
+ /* Check reg2 is not used for something else before it is loaded with reg */
+ if (reg2 && !regIsSpecial (reg2, 1) && !regUsedinRange(pc1,pc2,reg2)) {
+ pCode *pct3 = findNextInstruction(pct2->next);
+ /* Check following instructions are not relying on the use of W or the Z flag condiction */
+ /* XXX: We must ensure that this value is destroyed before use---otherwise it might be used in
+ * subsequent flows (checking for < 1 is insufficient). */
+ if ((pCodeSearchCondition(pct3,PCC_Z,0) == -1) && (pCodeSearchCondition(pct3,PCC_W,0) == -1)) {
+ DFPRINTF((stderr, " optimising MOVF reg ... MOVF reg,W MOVWF reg2 to MOVWF reg2 ...\n"));
+ pct2->seq = pc1->seq;
+ unlinkpCode(pct2);
+ pCodeInsertBefore(pc1,pct2);
+ if(regUsedinRange(pct2,0,reg))
+ {
+ //fprintf (stderr, "%s:%d(%s): Remove2pcodes IF (MOVWF reg, ..., MOVW reg,W MOVWF reg2)\n", __FILE__, __LINE__, __FUNCTION__);
+ Remove2pcodes(pcfl_used, pc2, NULL, reg, can_free);
+ } else {
+ //fprintf (stderr, "%s:%d(%s): Remove2pcodes ELSE (MOVWF reg, ..., MOVW reg,W MOVWF reg2)\n", __FILE__, __LINE__, __FUNCTION__);
+ Remove2pcodes(pcfl_used, pc1, pc2, reg, can_free);
+ }
+ total_registers_saved++; // debugging stats.
+ return 1;
+ }
+ }
+ }
+ }
+
+ pct1 = findPrevInstruction(pc1->prev);
+ if(pct1 && (PCI(pct1)->pcflow == PCI(pc1)->pcflow)) {
+
+ if ( (PCI(pct1)->op == POC_MOVFW) &&
+ (PCI(pc2)->op == POC_MOVFW)) {
+
+ reg1 = getRegFromInstruction(pct1);
+ if(reg1 && !regIsSpecial (reg1, 0) && !regUsedinRange(pc1,pc2,reg1)) {
+ DFPRINTF((stderr, " optimising MOVF reg1,W MOVWF reg ... MOVF reg,W\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 = newpCode(PCI(pc2)->op, PCI(pct1)->pcop);
+ pCodeInsertAfter(pc2, pct2);
+ PCI(pct2)->pcflow = PCFL(pcfl_used);
+ pct2->seq = pc2->seq;
+
+ if(can_free) {
+ //fprintf (stderr, "%s:%d(%s): Remove2pcodes CANFREE (MOVF reg1,W; MOVWF reg2; MOVF reg2,W)\n", __FILE__, __LINE__, __FUNCTION__);
+ 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.*/
+ unlinkpCode(pc1);
+ pCodeInsertAfter(pct2, pc1);
+
+ //fprintf (stderr, "%s:%d(%s): Remove2pcodes ELSE (MOVF reg1,W; MOVWF reg2; MOVF reg2,W)\n", __FILE__, __LINE__, __FUNCTION__);
+ Remove2pcodes(pcfl_used, pc2, NULL, reg, can_free);
+ }
+
+ //fprintf (stderr, "%s:%d(%s): Remove2pcodes ALWAYS (MOVF reg1,W; MOVWF reg2; MOVF reg2,W)\n", __FILE__, __LINE__, __FUNCTION__);
+ Remove2pcodes(pcfl_used, pct1, NULL, reg1, 0);
+ 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)
+{
+ reg_info *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 (strcmp(reg->name,"_SubState")==0)
+ fprintf(stderr,"Reg: %s\n",reg->name);
+ */
+
+ /* Catch inconsistently set-up live ranges
+ * (see tracker items #1469504 + #1474602)
+ * FIXME: Actually we should rather fix the
+ * computation of the liveranges instead...
+ */
+ if (!reg || !reg->reglives.usedpFlows
+ || !reg->reglives.assignedpFlows)
+ {
+ //fprintf( stderr, "skipping reg w/o liveranges: %s\n", reg ? reg->name : "(unknown)");
+ continue;
+ }
+
+ if(reg->type == REG_SFR || reg->type == REG_STK || reg->isPublic || reg->isExtern|| reg->isFixed) {
+ //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.1: 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.2: 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,2);
+
+ deleteSetItem (&(PCFL(pcfl_assigned)->registers), reg);
+ /*
+ deleteSetItem (&(reg->reglives.usedpCodes),pc);
+ pc->destruct(pc);
+ */
+ pc = setNextItem(reg->reglives.usedpCodes);
+ }
+
+
+ reg->isFree = TRUE;
+ reg->wasUsed = FALSE;
+
+ 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) ) {
+
+ 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 = rset2;
+ }
+ }
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*
+* void pCodeRegOptimeRegUsage(pBlock *pb)
+*-----------------------------------------------------------------*/
+void pCodeRegOptimizeRegUsage(int level)
+{
+
+ int passes;
+ int saved = 0;
+ int t = total_registers_saved;
+
+#if 0
+ /* This is currently broken (need rewrite to correctly
+ * handle arbitrary pCodeOps instead of registers only). */
+ if (!pic14_options.disable_df)
+ optimizeDataflow ();
+#endif
+
+ if(!register_optimization)
+ return;
+#define OPT_PASSES 4
+ passes = OPT_PASSES;
+
+ do {
+ saved = total_registers_saved;
+
+ /* Identify registers used in one flow sequence */
+ OptimizeRegUsage(dynAllocRegs,level, (OPT_PASSES-passes));
+ OptimizeRegUsage(dynStackRegs,level, (OPT_PASSES-passes));
+ OptimizeRegUsage(dynDirectRegs,0, (OPT_PASSES-passes));
+
+ if(total_registers_saved != saved)
+ DFPRINTF((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)
+ DFPRINTF((stderr, "No registers saved on this pass\n"));
+}
+
+
+/*-----------------------------------------------------------------*
+* void RegsUnMapLiveRanges(set *regset)
+*
+*-----------------------------------------------------------------*/
+static void RegsSetUnMapLiveRanges(set *regset)
+{
+ reg_info *reg;
+
+ while(regset) {
+ reg = regset->item;
+ regset = regset->next;
+
+
+ deleteSet(&reg->reglives.usedpCodes);
+ deleteSet(&reg->reglives.usedpFlows);
+ deleteSet(&reg->reglives.assignedpFlows);
+
+ }
+
+}
+
+void RegsUnMapLiveRanges(void)
+{
+
+ RegsSetUnMapLiveRanges(dynAllocRegs);
+ RegsSetUnMapLiveRanges(dynStackRegs);
+ RegsSetUnMapLiveRanges(dynDirectRegs);
+ RegsSetUnMapLiveRanges(dynProcessorRegs);
+ RegsSetUnMapLiveRanges(dynDirectBitRegs);
+ RegsSetUnMapLiveRanges(dynInternalRegs);
+
+}
diff --git a/src/pic14/pcoderegs.h b/src/pic14/pcoderegs.h
new file mode 100644
index 0000000..fb362ea
--- /dev/null
+++ b/src/pic14/pcoderegs.h
@@ -0,0 +1,50 @@
+/*-------------------------------------------------------------------------
+
+ 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__
+
+#include "common.h"
+
+#include "pcode.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;
+
+void pCodeRegMapLiveRanges(struct pBlock *pb);
+void pCodeRegOptimizeRegUsage(int level);
+void RegsUnMapLiveRanges(void);
+void RemoveUnusedRegisters(void);
+
+#endif // __PCODEREGS_H__
diff --git a/src/pic14/peeph.def b/src/pic14/peeph.def
new file mode 100644
index 0000000..b82d3a0
--- /dev/null
+++ b/src/pic14/peeph.def
@@ -0,0 +1,323 @@
+// 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 INDF
+// movlw 0xa5
+// movf fsr,w
+// incf indf,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
+}
+
+replace restart {
+ clrf %1
+ rlf %1,f
+ movlw 0x01
+ xorwf %1,f
+ movf %1,w
+ btfss STATUS,2
+ goto %2
+
+} by {
+ ; peep 13 - Optimized carry sequence
+ clrf %1
+ incf %1,F
+ btfss status,C
+ goto %2
+ clrf %1
+
+}
+
+replace restart {
+ clrf %1
+ rlf %1,f
+ movlw 0x01
+ xorwf %1,f
+ movf %1,w
+ btfsc STATUS,2
+ goto %2
+
+} by {
+ ; peep 13a - Optimized carry sequence
+ clrf %1
+ incf %1,F
+ btfsc status,C
+ goto %2
+ clrf %1
+
+}
diff --git a/src/pic14/pic14.vcxproj b/src/pic14/pic14.vcxproj
new file mode 100644
index 0000000..20df2a0
--- /dev/null
+++ b/src/pic14/pic14.vcxproj
@@ -0,0 +1,192 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{B96E942E-39F5-4C7C-97FD-A095DE6847C6}</ProjectGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="..\..\SDCC.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="..\..\SDCC.props" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</IntDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</IntDir>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">port</TargetName>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">port</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <Optimization>MaxSpeed</Optimization>
+ <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
+ <AdditionalIncludeDirectories>..;.;..\..;..\..\support\util;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;WIN32;_LIB;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeaderOutputFile>.\Release/pic14.pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>.\Release/</AssemblerListingLocation>
+ <ObjectFileName>.\Release/</ObjectFileName>
+ <ProgramDataBaseFileName>.\Release/</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0409</Culture>
+ </ResourceCompile>
+ <Lib>
+ <OutputFile>$(Configuration)\$(TargetFileName)</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ </Lib>
+ <Bscmake>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <OutputFile>.\Release/pic14.bsc</OutputFile>
+ </Bscmake>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>..;.;..\..;..\..\support\util;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;WIN32;_LIB;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <PrecompiledHeaderOutputFile>.\Debug/pic14.pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>.\Debug/</AssemblerListingLocation>
+ <ObjectFileName>.\Debug/</ObjectFileName>
+ <ProgramDataBaseFileName>.\Debug/</ProgramDataBaseFileName>
+ <BrowseInformation>true</BrowseInformation>
+ <WarningLevel>Level2</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0409</Culture>
+ </ResourceCompile>
+ <Lib>
+ <OutputFile>$(Configuration)\$(TargetFileName)</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ </Lib>
+ <Bscmake>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <OutputFile>.\Debug/pic14.bsc</OutputFile>
+ </Bscmake>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="device.c">
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <ClCompile Include="gen.c">
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <ClCompile Include="genarith.c">
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <ClCompile Include="glue.c">
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <ClCompile Include="main.c">
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <ClCompile Include="pcode.c">
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <ClCompile Include="pcodeflow.c">
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <ClCompile Include="pcodepeep.c">
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <ClCompile Include="pcoderegs.c">
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <ClCompile Include="ralloc.c">
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="device.h" />
+ <ClInclude Include="gen.h" />
+ <ClInclude Include="glue.h" />
+ <ClInclude Include="main.h" />
+ <ClInclude Include="pcode.h" />
+ <ClInclude Include="pcodeflow.h" />
+ <ClInclude Include="pcoderegs.h" />
+ <ClInclude Include="ralloc.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <CustomBuild Include="peeph.def">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">gawk -f ../SDCCpeeph.awk %(Identity) &gt;peeph.rul</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">peeph.rul;%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">gawk -f ../SDCCpeeph.awk %(Identity) &gt;peeph.rul</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">peeph.rul;%(Outputs)</Outputs>
+ <Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Generating Peephole Rule: peeph.rul</Message>
+ <Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Generating Peephole Rule: peeph.rul</Message>
+ </CustomBuild>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/src/pic14/pic14.vcxproj.filters b/src/pic14/pic14.vcxproj.filters
new file mode 100644
index 0000000..4441929
--- /dev/null
+++ b/src/pic14/pic14.vcxproj.filters
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{b6bfe4fa-6c81-435a-846b-011a5bd2df84}</UniqueIdentifier>
+ <Extensions>cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{b03a3465-38b0-4e30-b02e-4a95779a54c5}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl</Extensions>
+ </Filter>
+ <Filter Include="Custom Build">
+ <UniqueIdentifier>{503c9bb6-fa0c-4277-a55f-a0cd889032d1}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="device.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="gen.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="genarith.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="glue.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="main.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="pcode.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="pcodeflow.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="pcodepeep.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="pcoderegs.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ralloc.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="device.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="gen.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="glue.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="main.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="pcode.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="pcodeflow.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="pcoderegs.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ralloc.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <CustomBuild Include="peeph.def">
+ <Filter>Custom Build</Filter>
+ </CustomBuild>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/src/pic14/ralloc.c b/src/pic14/ralloc.c
new file mode 100644
index 0000000..19562df
--- /dev/null
+++ b/src/pic14/ralloc.c
@@ -0,0 +1,3874 @@
+/*------------------------------------------------------------------------
+
+ 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)
+
+ 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 "device.h"
+#include "gen.h"
+#include "ralloc.h"
+
+
+set *dynAllocRegs=NULL;
+set *dynStackRegs=NULL;
+set *dynProcessorRegs=NULL;
+set *dynDirectRegs=NULL;
+set *dynDirectBitRegs=NULL;
+set *dynInternalRegs=NULL;
+
+
+#ifdef DEBUG_FENTRY2
+# define FENTRY2 printf
+#else
+# define FENTRY2 1 ? (void)0 : (*(void (*)(const char *, ...))0)
+#endif
+
+/* this should go in SDCCicode.h, but it doesn't. */
+#define IS_REF(op) (IS_SYMOP(op) && op->svt.symOperand->isref == 1)
+
+/*-----------------------------------------------------------------*/
+/* 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 */
+/*-----------------------------------------------------------------*/
+
+/* 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;
+
+static int pic14_ptrRegReq; /* one byte pointer register required */
+
+static hTab *dynDirectRegNames= NULL;
+// static hTab *regHash = NULL; /* a hash table containing ALL registers */
+
+static int dynrIdx = 0x1000;
+
+int Gstack_base_addr=0; /* The starting address of registers that
+ * are used to pass and return parameters */
+static int Gstack_size = 0;
+
+static int debug = 0; // should be 0 when committed, creates .d files
+static FILE *debugF = NULL;
+
+/*-----------------------------------------------------------------*/
+/* debugLog - open a file for debugging information */
+/*-----------------------------------------------------------------*/
+static void
+debugLog (const 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 || !dstFileName)
+ return;
+
+ if (!debugF)
+ {
+ /* create the file name */
+ SNPRINTF(buffer, sizeof(buffer), "%s.d", dstFileName);
+
+ if (!(debugF = fopen (buffer, (append ? "a+" : "w"))))
+ {
+ werror (E_FILE_OPEN_ERR, buffer);
+ exit (1);
+ }
+
+ append = 1; // Next time debugLog is called, we'll append the debug info
+ }
+
+ va_start (ap, fmt);
+ vsprintf (buffer, fmt, ap);
+ va_end (ap);
+
+ fprintf (debugF, "%s", buffer);
+ //if (options.verbose) fprintf (stderr, "%s: %s", __FUNCTION__, buffer);
+}
+
+static void
+debugNewLine (void)
+{
+ if (debugF)
+ fputc ('\n', debugF);
+}
+/*-----------------------------------------------------------------*/
+/* pic14_debugLogClose - closes the debug log file (if opened) */
+/*-----------------------------------------------------------------*/
+void
+pic14_debugLogClose (void)
+{
+ if (debugF)
+ {
+ fclose (debugF);
+ debugF = NULL;
+ }
+}
+
+static char *
+debugAopGet (const char *str, operand * op)
+{
+ if (!debug) return NULL;
+
+ if (str) debugLog (str);
+
+ printOperand (op, debugF);
+ debugNewLine ();
+
+ return NULL;
+}
+
+static const 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 SD_CHAR: return "CHAR";
+ case SD_SHORT: return "SHORT";
+ case SD_INT: return "INT";
+ case SD_LONG: return "LONG";
+ case SIGNED: return "SIGNED";
+ case UNSIGNED: return "UNSIGNED";
+ case SD_FLOAT: return "FLOAT";
+ case DOUBLE: return "DOUBLE";
+ case SD_CONST: return "CONST";
+ case VOLATILE: return "VOLATILE";
+ case SD_VOID: return "VOID";
+ case BIT: return "BIT";
+ case STRUCT: return "STRUCT";
+ case UNION: return "UNION";
+ case ENUM: return "ENUM";
+ case RANGE: return "RANGE";
+ case SD_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";
+ }
+
+ SNPRINTF(buffer, sizeof(buffer), "unknown op %d %c", op, op & 0xff);
+ return buffer;
+}
+
+/*-----------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+static const char *
+debugLogRegType (short type)
+{
+ switch (type)
+ {
+ case REG_GPR: return "REG_GPR";
+ case REG_PTR: return "REG_PTR";
+ case REG_CND: return "REG_CND";
+ }
+
+ SNPRINTF(buffer, sizeof(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);
+}
+
+/*-----------------------------------------------------------------*/
+/* regWithIdx - Search through a set of registers that matches idx */
+/*-----------------------------------------------------------------*/
+static reg_info *
+regWithIdx (set *dRegs, int idx, int fixed)
+{
+ reg_info *dReg;
+
+ for (dReg = setFirstItem(dRegs); dReg; dReg = setNextItem(dRegs)) {
+
+ if(idx == dReg->rIdx && (fixed == (int)dReg->isFixed)) {
+ while (dReg->reg_alias) dReg = dReg->reg_alias;
+ return dReg;
+ }
+ }
+
+ return NULL;
+}
+
+/*-----------------------------------------------------------------*/
+/* newReg - allocate and init memory for a new register */
+/*-----------------------------------------------------------------*/
+static reg_info* newReg(short type, PIC_OPTYPE pc_type, int rIdx, const char *name, int size, int alias)
+{
+ reg_info *dReg, *reg_alias;
+
+ /* check whether a matching register already exists */
+ dReg = dirregWithName(name);
+ if (dReg) {
+ //printf( "%s: already present: %s\n", __FUNCTION__, name );
+ return (dReg);
+ }
+
+ // check whether a register at that location exists
+ reg_alias = regWithIdx(dynDirectRegs, rIdx, FALSE);
+ if (!reg_alias) reg_alias = regWithIdx(dynDirectRegs, rIdx, TRUE);
+
+ // create a new register
+ dReg = Safe_alloc(sizeof(reg_info));
+ dReg->type = type;
+ dReg->pc_type = pc_type;
+ dReg->rIdx = rIdx;
+ if(name) {
+ dReg->name = Safe_strdup(name);
+ } else {
+ SNPRINTF(buffer, sizeof(buffer), "r0x%02X", dReg->rIdx);
+ dReg->name = Safe_strdup(buffer);
+ }
+
+ dReg->isFree = FALSE;
+ dReg->wasUsed = FALSE;
+ dReg->isFixed = (type == REG_SFR) ? TRUE : FALSE;
+ dReg->isMapped = FALSE;
+ dReg->isEmitted = FALSE;
+ dReg->isPublic = FALSE;
+ dReg->isExtern = FALSE;
+ dReg->address = 0;
+ dReg->size = size;
+ dReg->alias = alias;
+ dReg->reg_alias = reg_alias;
+ dReg->reglives.usedpFlows = newSet();
+ dReg->reglives.assignedpFlows = newSet();
+ if (type != REG_STK) hTabAddItem(&dynDirectRegNames, regname2key(dReg->name), dReg);
+ debugLog( "%s: Created register %s.\n", __FUNCTION__, dReg->name);
+
+ return dReg;
+}
+
+/*-----------------------------------------------------------------*/
+/* regWithName - Search through a set of registers that matches name */
+/*-----------------------------------------------------------------*/
+static reg_info *
+regWithName (set *dRegs, const char *name)
+{
+ reg_info *dReg;
+
+ for (dReg = setFirstItem(dRegs); dReg; dReg = setNextItem(dRegs)) {
+ if((strcmp(name,dReg->name)==0)) {
+ return dReg;
+ }
+ }
+
+ return NULL;
+}
+
+/*-----------------------------------------------------------------*/
+/* regWithName - Search for a registers that matches name */
+/*-----------------------------------------------------------------*/
+reg_info *
+regFindWithName (const char *name)
+{
+ reg_info *dReg;
+
+ if( (dReg = regWithName ( dynDirectRegs, name)) != NULL ) {
+ debugLog ("Found a Direct Register!\n");
+ return dReg;
+ }
+ if( (dReg = regWithName ( dynDirectBitRegs, name)) != NULL) {
+ debugLog ("Found a Direct Bit Register!\n");
+ return dReg;
+ }
+
+ if (*name=='_') name++; // Step passed '_'
+
+ if( (dReg = regWithName ( dynAllocRegs, name)) != NULL) {
+ debugLog ("Found a Dynamic Register!\n");
+ return dReg;
+ }
+ if( (dReg = regWithName ( dynProcessorRegs, name)) != NULL) {
+ debugLog ("Found a Processor Register!\n");
+ return dReg;
+ }
+ if( (dReg = regWithName ( dynInternalRegs, name)) != NULL) {
+ debugLog ("Found an Internal Register!\n");
+ return dReg;
+ }
+ if( (dReg = regWithName ( dynStackRegs, name)) != NULL) {
+ debugLog ("Found an Stack Register!\n");
+ return dReg;
+ }
+
+ return NULL;
+}
+
+/*-----------------------------------------------------------------*/
+/* regFindFree - Search for a free register in a set of registers */
+/*-----------------------------------------------------------------*/
+static reg_info *
+regFindFree (set *dRegs)
+{
+ reg_info *dReg;
+
+ for (dReg = setFirstItem(dRegs); dReg; dReg = setNextItem(dRegs)) {
+ if(dReg->isFree)
+ return dReg;
+ }
+
+ return NULL;
+}
+
+/*-----------------------------------------------------------------*/
+/* initStack - allocate registers for a pseudo stack */
+/*-----------------------------------------------------------------*/
+void initStack(int base_address, int size, int shared)
+{
+ int i;
+ PIC_device *pic;
+
+ pic = pic14_getPIC();
+ Gstack_base_addr = base_address;
+ Gstack_size = size;
+ //fprintf(stderr,"initStack [base:0x%02x, size:%d]\n", base_address, size);
+
+ for(i = 0; i<size; i++) {
+ char buffer[16];
+ reg_info *r;
+
+ SNPRINTF(buffer, sizeof(buffer), "STK%02d", i);
+ // multi-bank device, sharebank prohibited by user
+ r = newReg(REG_STK, PO_GPR_TEMP, base_address--, buffer, 1, shared ? (pic ? pic->bankMask : 0x180) : 0x0);
+ r->isFixed = TRUE;
+ r->isPublic = TRUE;
+ r->isEmitted = TRUE;
+ //r->name[0] = 's';
+ addSet(&dynStackRegs,r);
+ }
+}
+
+/*-----------------------------------------------------------------*
+*-----------------------------------------------------------------*/
+reg_info *
+allocProcessorRegister(int rIdx, const char *name, short po_type, int alias)
+{
+ //fprintf(stderr,"allocProcessorRegister %s addr =0x%x\n",name,rIdx);
+ return addSet(&dynProcessorRegs,newReg(REG_SFR, po_type, rIdx, name,1,alias));
+}
+
+/*-----------------------------------------------------------------*
+*-----------------------------------------------------------------*/
+
+reg_info *
+allocInternalRegister(int rIdx, const char *name, PIC_OPTYPE po_type, int alias)
+{
+ reg_info *reg = newReg(REG_GPR, po_type, rIdx, name,1,alias);
+
+ //fprintf(stderr,"allocInternalRegister %s addr =0x%x\n",name,rIdx);
+ if(reg) {
+ reg->wasUsed = FALSE;
+ return addSet(&dynInternalRegs,reg);
+ }
+
+ return NULL;
+}
+/*-----------------------------------------------------------------*/
+/* allocReg - allocates register of given type */
+/*-----------------------------------------------------------------*/
+static reg_info *
+allocReg (short type)
+{
+ reg_info *reg;
+
+ debugLog ("%s of type %s\n", __FUNCTION__, debugLogRegType (type));
+ //fprintf(stderr,"allocReg\n");
+
+ reg = pic14_findFreeReg (type);
+
+ reg->isFree = FALSE;
+ reg->wasUsed = TRUE;
+
+ return reg;
+
+ //return addSet(&dynAllocRegs,newReg(REG_GPR, PO_GPR_TEMP,dynrIdx++,NULL,1,0));
+}
+
+
+/*-----------------------------------------------------------------*/
+/* dirregWithName - search for register by name */
+/*-----------------------------------------------------------------*/
+reg_info *
+dirregWithName (const char *name)
+{
+ int hkey;
+ reg_info *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) {
+ // handle registers with multiple names
+ while (reg->reg_alias) reg = reg->reg_alias;
+ return(reg);
+ }
+
+ reg = hTabNextItemWK (dynDirectRegNames);
+
+ }
+
+ return NULL; // name wasn't found in the hash table
+}
+
+/*-----------------------------------------------------------------*/
+/* allocNewDirReg - allocates a new register of given type */
+/*-----------------------------------------------------------------*/
+reg_info *
+allocNewDirReg (sym_link *symlnk,const char *name)
+{
+ reg_info *reg;
+ int address = 0;
+ sym_link *spec = getSpec (symlnk);
+
+ /* if this is at an absolute address, then get the address. */
+ if (SPEC_ABSA (spec) ) {
+ address = SPEC_ADDR (spec);
+ //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)) {
+ debugLog (" -- %s is declared at a config word address (0x%x)\n",name, address);
+ reg = 0;
+ } else {
+ int idx;
+ if (address) {
+ if (IS_BITVAR (spec))
+ idx = address >> 3;
+ else
+ idx = address;
+ } else {
+ idx = dynrIdx++;
+ }
+ reg = newReg(REG_GPR, PO_DIR, idx, (char*)name,getSize (symlnk),0 );
+ debugLog (" -- added %s to hash, size = %d\n", (char*)name,reg->size);
+
+ if (SPEC_ABSA (spec) ) {
+ reg->type = REG_SFR;
+ }
+
+ if (IS_BITVAR (spec)) {
+ addSet(&dynDirectBitRegs, reg);
+ reg->isBitField = TRUE;
+ } else
+ addSet(&dynDirectRegs, reg);
+
+ if (!IS_STATIC (spec)) {
+ reg->isPublic = TRUE;
+ }
+ if (IS_EXTERN (spec)) {
+ reg->isExtern = TRUE;
+ }
+ }
+
+ if (address && reg) {
+ reg->isFixed = TRUE;
+ reg->address = address;
+ debugLog (" -- and it is at a fixed address 0x%02x\n",reg->address);
+ }
+
+ return reg;
+}
+
+/*-----------------------------------------------------------------*/
+/* allocDirReg - allocates register of given type */
+/*-----------------------------------------------------------------*/
+reg_info *
+allocDirReg (operand *op)
+{
+ reg_info *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 (dynProcessorRegs, SPEC_ADDR ( OP_SYM_ETYPE(op)), TRUE);
+ /*
+ 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 = dirregWithName(name);
+ }
+
+#if 0
+ 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, dynrIdx++, 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(&dynDirectBitRegs, reg);
+ reg->isBitField = TRUE;
+ } else
+ addSet(&dynDirectRegs, reg);
+
+ if (!IS_STATIC (OP_SYM_ETYPE(op))) {
+ reg->isPublic = TRUE;
+ }
+ if (IS_EXTERN (OP_SYM_ETYPE(op))) {
+ reg->isExtern = TRUE;
+ }
+
+ } else {
+ debugLog (" -- %s is declared at a config word address (0x%x)\n",name, address);
+
+ }
+ }
+
+ if (SPEC_ABSA ( OP_SYM_ETYPE(op)) ) {
+ reg->isFixed = TRUE;
+ reg->address = SPEC_ADDR ( OP_SYM_ETYPE(op));
+ debugLog (" -- and it is at a fixed address 0x%02x\n",reg->address);
+ }
+#endif
+
+ if(reg) {
+ if (SPEC_ABSA ( OP_SYM_ETYPE(op)) ) {
+ reg->isFixed = TRUE;
+ reg->address = SPEC_ADDR ( OP_SYM_ETYPE(op));
+ debugLog (" -- and it is at a fixed address 0x%02x\n",reg->address);
+ }
+ } else {
+ allocNewDirReg (OP_SYM_TYPE(op),name);
+ }
+
+ return reg;
+}
+
+
+/*-----------------------------------------------------------------*/
+/* allocRegByName - allocates register with given name */
+/*-----------------------------------------------------------------*/
+reg_info *
+allocRegByName (const char *name, int size)
+{
+ reg_info *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 = dirregWithName(name);
+
+ if(!reg) {
+ int found = FALSE;
+ symbol *sym;
+ /* 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, size:%d\n", __FUNCTION__,name,size);
+ reg = newReg(REG_GPR, PO_DIR, dynrIdx++, name,size,0 );
+ for (sym = setFirstItem(sfr->syms); sym; sym = setNextItem(sfr->syms)) {
+ if (strcmp(reg->name+1,sym->name)==0) {
+ unsigned a = SPEC_ADDR(sym->etype);
+ reg->address = a;
+ reg->isFixed = TRUE;
+ reg->type = REG_SFR;
+ if (!IS_STATIC (sym->etype)) {
+ reg->isPublic = TRUE;
+ }
+ if (IS_EXTERN (sym->etype)) {
+ reg->isExtern = TRUE;
+ }
+ if (IS_BITVAR (sym->etype))
+ reg->isBitField = TRUE;
+ found = TRUE;
+ break;
+ }
+ }
+ if (!found) {
+ for (sym = setFirstItem(data->syms); sym; sym = setNextItem(data->syms)) {
+ if (strcmp(reg->name+1,sym->name)==0) {
+ unsigned a = SPEC_ADDR(sym->etype);
+ reg->address = a;
+ if (!IS_STATIC (sym->etype)) {
+ reg->isPublic = TRUE;
+ }
+ if (IS_EXTERN (sym->etype)) {
+ reg->isExtern = TRUE;
+ }
+ if (IS_BITVAR (sym->etype))
+ reg->isBitField = TRUE;
+ found = TRUE;
+ break;
+ }
+ }
+ }
+
+ debugLog (" -- added %s to hash, size = %d\n", name,reg->size);
+
+ //hTabAddItem(&dynDirectRegNames, regname2key(name), reg);
+ if (reg->isBitField) {
+ addSet(&dynDirectBitRegs, reg);
+ } else
+ addSet(&dynDirectRegs, reg);
+ }
+
+ return reg;
+}
+
+/*-----------------------------------------------------------------*/
+/* RegWithIdx - returns pointer to register with index number */
+/*-----------------------------------------------------------------*/
+reg_info *
+typeRegWithIdx (int idx, int type, int fixed)
+{
+
+ reg_info *dReg;
+
+ debugLog ("%s - requesting index = 0x%x\n", __FUNCTION__,idx);
+
+ switch (type) {
+
+ case REG_GPR:
+ if( (dReg = regWithIdx ( dynAllocRegs, idx, fixed)) != NULL) {
+ debugLog ("Found a Dynamic Register!\n");
+ return dReg;
+ }
+ if( (dReg = regWithIdx ( dynDirectRegs, idx, fixed)) != NULL ) {
+ debugLog ("Found a Direct Register!\n");
+ return dReg;
+ }
+
+ break;
+ case REG_STK:
+ if( (dReg = regWithIdx ( dynStackRegs, idx, FALSE)) != NULL ) {
+ debugLog ("Found a Stack Register!\n");
+ return dReg;
+ } else
+ if( (dReg = regWithIdx ( dynStackRegs, idx, TRUE)) != NULL ) {
+ debugLog ("Found a Stack Register!\n");
+ return dReg;
+ }
+ else {
+ werror (E_STACK_OUT, "Register");
+ /* return an existing register just to avoid the SDCC crash */
+ return regWithIdx ( dynStackRegs, 0x7f, 0);
+ }
+ break;
+ case REG_SFR:
+ if( (dReg = regWithIdx ( dynProcessorRegs, idx, fixed)) != NULL ) {
+ debugLog ("Found a Processor Register!\n");
+ return dReg;
+ }
+
+ case REG_CND:
+ case REG_PTR:
+ default:
+ break;
+ }
+
+
+ return NULL;
+}
+
+/*-----------------------------------------------------------------*/
+/* pic14_regWithIdx - returns pointer to register with index number*/
+/*-----------------------------------------------------------------*/
+reg_info *
+pic14_regWithIdx (int idx)
+{
+ reg_info *dReg;
+
+ if( (dReg = typeRegWithIdx(idx,REG_GPR,0)) != NULL)
+ return dReg;
+
+ if( (dReg = typeRegWithIdx(idx,REG_SFR,0)) != NULL)
+ return dReg;
+
+ return NULL;
+}
+
+/*-----------------------------------------------------------------*/
+/* pic14_regWithIdx - returns pointer to register with index number */
+/*-----------------------------------------------------------------*/
+reg_info *
+pic14_allocWithIdx (int idx)
+{
+ reg_info *dReg;
+
+ debugLog ("%s - allocating with index = 0x%x\n", __FUNCTION__,idx);
+
+ if( (dReg = regWithIdx ( dynAllocRegs, idx, FALSE)) != NULL) {
+
+ debugLog ("Found a Dynamic Register!\n");
+ } else if( (dReg = regWithIdx ( dynStackRegs, idx, FALSE)) != NULL ) {
+ debugLog ("Found a Stack Register!\n");
+ } else if( (dReg = regWithIdx ( dynProcessorRegs, idx, FALSE)) != NULL ) {
+ debugLog ("Found a Processor Register!\n");
+ } else if( (dReg = regWithIdx ( dynInternalRegs, idx, FALSE)) != NULL ) {
+ debugLog ("Found an Internal Register!\n");
+ } else if( (dReg = regWithIdx ( dynInternalRegs, idx, TRUE)) != 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 = TRUE;
+ dReg->isFree = FALSE;
+
+ return dReg;
+}
+/*-----------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+reg_info *
+pic14_findFreeReg(short type)
+{
+ // int i;
+ reg_info* dReg;
+
+ switch (type) {
+ case REG_GPR:
+ if((dReg = regFindFree(dynAllocRegs)) != NULL)
+ return dReg;
+ return addSet(&dynAllocRegs,newReg(REG_GPR, PO_GPR_TEMP,dynrIdx++,NULL,1,0));
+
+ case REG_STK:
+
+ if((dReg = regFindFree(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 (reg_info * reg)
+{
+ debugLog ("%s\n", __FUNCTION__);
+ reg->isFree = TRUE;
+}
+
+
+/*-----------------------------------------------------------------*/
+/* 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 < pic14_nRegs; i++)
+ if (regspic14[i].isFree && regspic14[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 packBits(set *bregs)
+{
+ set *regset;
+ reg_info *breg;
+ reg_info *bitfield=NULL;
+ reg_info *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 = TRUE;
+ //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) {
+ //SNPRINTF(buffer, sizeof(buffer), "fbitfield%02x", breg->address);
+ SNPRINTF(buffer, sizeof(buffer), "0x%02x", breg->address);
+ //fprintf(stderr,"new bit field\n");
+ bitfield = newReg(REG_SFR, PO_GPR_BIT,breg->address,buffer,1,0);
+ bitfield->isBitField = TRUE;
+ bitfield->isFixed = TRUE;
+ bitfield->address = breg->address;
+ //addSet(&dynDirectRegs,bitfield);
+ addSet(&dynInternalRegs,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;
+ SNPRINTF(buffer, sizeof(buffer), "bitfield%d", byte_no);
+ //fprintf(stderr,"new relocatable bit field\n");
+ relocbitfield = newReg(REG_GPR, PO_GPR_BIT,dynrIdx++,buffer,1,0);
+ relocbitfield->isBitField = TRUE;
+ //addSet(&dynDirectRegs,relocbitfield);
+ addSet(&dynInternalRegs,relocbitfield);
+ //hTabAddItem(&dynDirectRegNames, regname2key(buffer), relocbitfield);
+ }
+
+ breg->reg_alias = relocbitfield;
+ breg->address = dynrIdx; /* byte_no; */
+ breg->rIdx = bit_no++;
+ }
+ }
+}
+
+
+
+static void bitEQUs(FILE *of, set *bregs)
+{
+ reg_info *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++;
+ }
+ }
+}
+
+void writeUsedRegs(FILE *of)
+{
+ packBits(dynDirectBitRegs);
+ bitEQUs(of,dynDirectBitRegs);
+}
+
+/*-----------------------------------------------------------------*/
+/* 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 ? FALSE : TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* 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 ? TRUE : FALSE);
+}
+
+/*-----------------------------------------------------------------*/
+/* 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 TRUE;
+ else
+ return FALSE;
+}
+
+/*-----------------------------------------------------------------*/
+/* 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) ? TRUE : FALSE);
+}
+
+/*-----------------------------------------------------------------*/
+/* 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 FALSE;
+
+ }
+
+ return TRUE;
+}
+
+/*-----------------------------------------------------------------*/
+/* 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 FALSE;
+
+ /* 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 TRUE;
+ }
+
+ return FALSE;
+}
+
+/*-----------------------------------------------------------------*/
+/* spillLRWithPtrReg :- will spil those live ranges which use PTR */
+/*-----------------------------------------------------------------*/
+static void
+spillLRWithPtrReg (symbol * forSym)
+{
+ symbol *lrsym;
+ int k;
+
+ debugLog ("%s\n", __FUNCTION__);
+ if (!_G.regAssigned || bitVectIsZero(_G.regAssigned))
+ return;
+
+ /* for all live ranges */
+ for (lrsym = hTabFirstItem (liveRanges, &k); lrsym;
+ lrsym = hTabNextItem (liveRanges, &k))
+ {
+ /* 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;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* createStackSpil - create a location on the stack to spil */
+/*-----------------------------------------------------------------*/
+static symbol *
+createStackSpil (symbol * sym)
+{
+ symbol *sloc = NULL;
+ int useXstack, model, noOverlay;
+ char slocBuffer[120];
+
+ debugLog ("%s\n", __FUNCTION__);
+
+ FENTRY2("called.");
+
+ /* 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 = FALSE;
+ addSetHead (&sloc->usl.itmpStack, sym);
+ return sym;
+ }
+
+ SNPRINTF(slocBuffer, sizeof(slocBuffer), "sloc%d", _G.slocNum++);
+ 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__);
+ FENTRY2("called.");
+
+ 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);
+ FENTRY2("sym: %s, spillLoc:%p (%s)\n", sym->rname, sym->usl.spillLoc, sym->usl.spillLoc ? sym->usl.spillLoc->rname : "<unknown>");
+
+ /* 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 (!pic14_ptrRegReq && isSpiltOnStack (sym))
+ {
+ pic14_ptrRegReq++;
+ spillLRWithPtrReg (sym);
+ }
+
+ if (sym->usl.spillLoc && !sym->remat)
+ sym->usl.spillLoc->allocreq = 1;
+}
+
+/*-----------------------------------------------------------------*/
+/* 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__);
+ FENTRY2("called.");
+ /* 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 &&
+ !isiCodeInFunctionCall (ic) &&
+ (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 (!pic14_ptrRegReq && isSpiltOnStack (ssym))
+ {
+ pic14_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);
+ }
+
+ return ((ssym == forSym) ? FALSE : TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* getRegPtr - will try for PTR if not a GPR type if not spil */
+/*-----------------------------------------------------------------*/
+static reg_info *
+getRegPtr (iCode * ic, eBBlock * ebp, symbol * sym)
+{
+ reg_info *reg;
+ int j;
+
+ 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;
+
+ /* make sure partially assigned registers aren't reused */
+ for (j=0; j<=sym->nRegs; j++)
+ if (sym->regs[j])
+ sym->regs[j]->isFree = FALSE;
+
+ /* this looks like an infinite loop but
+ in really selectSpil will abort */
+ goto tryAgain;
+}
+
+/*-----------------------------------------------------------------*/
+/* getRegGpr - will try for GPR if not spil */
+/*-----------------------------------------------------------------*/
+static reg_info *
+getRegGpr (iCode * ic, eBBlock * ebp, symbol * sym)
+{
+ reg_info *reg;
+ int j;
+
+ debugLog ("%s\n", __FUNCTION__);
+tryAgain:
+ /* try for gpr type */
+ if ((reg = allocReg (REG_GPR)))
+ return reg;
+
+ if (!pic14_ptrRegReq)
+ if ((reg = allocReg (REG_PTR)))
+ return reg;
+
+ /* we have to spil */
+ if (!spilSomething (ic, ebp, sym))
+ return NULL;
+
+ /* make sure partially assigned registers aren't reused */
+ for (j=0; j<=sym->nRegs; j++)
+ if (sym->regs[j])
+ sym->regs[j]->isFree = FALSE;
+
+ /* 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, reg_info *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;
+
+ /* Prevent the result from being assigned the same registers as (one)
+ * operand as many genXXX-functions fail otherwise.
+ * POINTER_GET(ic) || ic->op == LEFT_OP || ic->op == RIGHT_OP || ic->op == NOT
+ * are known to fail. */
+ if (sym->liveTo == ic->seq && IC_RESULT(ic))
+ {
+ switch (ic->op)
+ {
+ case '=': /* assignment */
+ case BITWISEAND: /* bitwise AND */
+ case '|': /* bitwise OR */
+ case '^': /* bitwise XOR */
+ case '~': /* bitwise negate */
+ case RLC: /* rotate through carry */
+ case RRC:
+ case UNARYMINUS:
+ case '+': /* addition */
+ case '-': /* subtraction */
+ /* go ahead, these are safe to use with
+ * non-disjoint register sets */
+ break;
+
+ default:
+ /* do not release operand registers */
+ //fprintf (stderr, "%s:%u: operand not freed: ", __FILE__, __LINE__); piCode (ic, stderr); fprintf (stderr, "\n");
+ continue;
+ } // switch
+ }
+
+ /* 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 = TRUE;
+ 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 &&
+ IS_SYMOP(IC_LEFT (ic->prev)) &&
+ !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)) &&
+ IS_SYMOP (IC_RESULT (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->liveFrom == ic->seq && /* does not start before here */
+ result->regType == sym->regType && /* same register types */
+ 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 = FALSE;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* 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 FALSE;
+ if (nFreeRegs (REG_GPR) >= nr)
+ return FALSE;
+ }
+ else
+ {
+ if (pic14_ptrRegReq)
+ {
+ if (nFreeRegs(rt) >= nr)
+ return FALSE;
+ }
+ else
+ {
+ if ((nFreeRegs(REG_PTR) + nFreeRegs(REG_GPR)) >= nr)
+ return FALSE;
+ }
+ }
+
+ debugLog (" ... yep it will (cause a spill)\n");
+ /* it will cause a spil */
+ return TRUE;
+}
+
+/*-----------------------------------------------------------------*/
+/* 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 = FALSE;
+
+ debugLog ("%s\n", __FUNCTION__);
+ /* if the result has been spilt then cannot share */
+ if (opsym->isspilt)
+ return;
+again:
+ shared = FALSE;
+ /* 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 = TRUE;
+ goto xchgPositions;
+ }
+ }
+ }
+xchgPositions:
+ if (shared)
+ {
+ reg_info *tmp = result->regs[i];
+ result->regs[i] = result->regs[j];
+ result->regs[j] = tmp;
+ goto again;
+ }
+}
+
+/*------------------------------------------------------------------*/
+/* verifyRegsAssigned - make sure an iTemp is properly initialized; */
+/* it should either have registers or have beed spilled. Otherwise, */
+/* there was an uninitialized variable, so just spill this to get */
+/* the operand in a valid state. */
+/*------------------------------------------------------------------*/
+static void
+verifyRegsAssigned (operand *op, iCode * ic)
+{
+ symbol * sym;
+
+ if (!op) return;
+ if (!IS_ITEMP (op)) return;
+
+ sym = OP_SYMBOL (op);
+ if (sym->isspilt) return;
+ if (!sym->nRegs) return;
+ if (sym->regs[0]) return;
+
+ werrorfl (ic->filename, ic->lineno, W_LOCAL_NOINIT,
+ sym->prereqv ? sym->prereqv->name : sym->name);
+ spillThis (sym);
+}
+
+
+/*-----------------------------------------------------------------*/
+/* 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) && IS_SYMOP (IC_RESULT (ic)))
+ {
+ symbol *sym = OP_SYMBOL (IC_RESULT (ic));
+ bitVect *spillable;
+ int willCS;
+ int j;
+ int ptrRegSet = 0;
+
+ /* Make sure any spill location is definately allocated */
+ if (sym->isspilt && !sym->remat && sym->usl.spillLoc &&
+ !sym->usl.spillLoc->allocreq)
+ {
+ sym->usl.spillLoc->allocreq++;
+ }
+
+ /* 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 the live range preceeds the point of definition
+ then ideally we must take into account registers that
+ have been allocated after sym->liveFrom but freed
+ before ic->seq. This is complicated, so spill this
+ symbol instead and let fillGaps handle the allocation. */
+ if (sym->liveFrom < ic->seq)
+ {
+ 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)
+ && IS_SYMOP(IC_LEFT(ic))
+ && getSize (OP_SYMBOL (IC_LEFT (ic))->type)
+ <= (unsigned) NEARPTRSIZE)
+ {
+ pic14_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 failed 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)) &&
+ IS_SYMOP(IC_RESULT(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)) &&
+ IS_SYMOP(IC_RESULT(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__);
+ pic14_ptrRegReq--;
+ ptrRegSet = 0;
+ }
+ }
+ }
+ }
+
+ /* Check for and fix any problems with uninitialized operands */
+ for (i = 0; i < count; i++)
+ {
+ iCode *ic;
+
+ if (ebbs[i]->noPath &&
+ (ebbs[i]->entryLabel != entryLabel &&
+ ebbs[i]->entryLabel != returnLabel))
+ continue;
+
+ for (ic = ebbs[i]->sch; ic; ic = ic->next)
+ {
+ if (SKIP_IC2 (ic))
+ continue;
+
+ if (ic->op == IFX)
+ {
+ verifyRegsAssigned (IC_COND (ic), ic);
+ continue;
+ }
+
+ if (ic->op == JUMPTABLE)
+ {
+ verifyRegsAssigned (IC_JTCOND (ic), ic);
+ continue;
+ }
+
+ verifyRegsAssigned (IC_RESULT (ic), ic);
+ verifyRegsAssigned (IC_LEFT (ic), ic);
+ verifyRegsAssigned (IC_RIGHT (ic), ic);
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* 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 (pic14_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(pic14_nRegs);
+
+ debugLog ("%s\n", __FUNCTION__);
+ /* do the special cases first */
+ if (ic->op == IFX)
+ {
+ return bitVectUnion(rmask, rUmaskForOp(IC_COND(ic)));
+ }
+
+ /* for the jumptable */
+ if (ic->op == JUMPTABLE)
+ {
+ return bitVectUnion(rmask, rUmaskForOp(IC_JTCOND(ic)));
+ }
+
+ /* 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)));
+
+ 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 (pic14_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);
+ }
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* regTypeNum - computes the type & number of registers required */
+/*-----------------------------------------------------------------*/
+static void
+regTypeNum (void)
+{
+ 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->accuse) {
+ if (IS_AGGREGATE (sym->type) || sym->isptr)
+ sym->type = aggrToPtr (sym->type, FALSE);
+ debugLog (" %d - no reg needed - accumulator used\n", __LINE__);
+
+ continue;
+ }
+
+ if (sym->ruonly) {
+ //if (IS_AGGREGATE (sym->type) || sym->isptr)
+ // sym->type = aggrToPtr (sym->type, FALSE);
+ debugLog (" %d - 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 0
+ if (bitVectnBitsOn (sym->defs) == 1 &&
+ (ic = hTabItemWithKey (iCodehTab,
+ bitVectFirstBit (sym->defs))) &&
+ POINTER_GET (ic) &&
+ !IS_BITVAR (sym->etype) &&
+ (aggrToPtrDclType (operandType (IC_LEFT (ic)), FALSE) == POINTER)) {
+
+ if (ptrPseudoSymSafe (sym, ic)) {
+ symbol *psym;
+
+ debugLog (" %d - \n", __LINE__);
+
+ /* create a pseudo symbol & force a spil */
+ //X symbol *psym = newSymbol (rematStr (OP_SYMBOL (IC_LEFT (ic))), 1);
+ psym = rematStr (OP_SYMBOL (IC_LEFT (ic)));
+ psym->type = sym->type;
+ psym->etype = sym->etype;
+ psym->psbase = ptrBaseRematSym (OP_SYMBOL (IC_LEFT (ic)));
+ 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 */
+ }
+#endif
+
+ /* 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;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* 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) ulFromVal (OP_VALUE (IC_RIGHT(ic))));
+ pic14_assignConfigWordValue( SPEC_ADDR ( OP_SYM_ETYPE(IC_RESULT(ic))),
+ (int) ulFromVal (OP_VALUE (IC_RIGHT(ic))));
+ }
+
+ /* 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 TRUE;
+
+ }
+ }
+
+ if (!IS_ITEMP (IC_RESULT (ic))) {
+ 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__);
+ allocDirReg(IC_LEFT (ic));
+ }
+ */
+
+ if (!IS_ITEMP (IC_RIGHT (ic))) {
+ debugLog (" %d - not packing - right is not temp\n", __LINE__);
+
+ /* only pack if this is not a function pointer */
+ if (!IS_REF (IC_RIGHT (ic)))
+ allocDirReg(IC_RIGHT (ic));
+ return FALSE;
+ }
+
+ if (OP_SYMBOL (IC_RIGHT (ic))->isind || OP_LIVETO (IC_RIGHT (ic)) > ic->seq)
+ {
+ debugLog (" %d - not packing - right side fails \n", __LINE__);
+ return FALSE;
+ }
+
+ /* 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 FALSE;
+ }
+ /* 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 FALSE; /* did not find */
+
+ /* if assignment then check that right is not a bit */
+ if (ASSIGNMENT (ic) && !POINTER_SET (ic))
+ {
+ sym_link *etype = operandType (IC_RESULT (dic));
+ if (IS_BITFIELD (etype))
+ {
+ /* if result is a bit too then it's ok */
+ etype = operandType (IC_RESULT (ic));
+ if (!IS_BITFIELD (etype))
+ return FALSE;
+ }
+ }
+
+ /* if the result is on stack or iaccess then it must be
+ the same at least 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 FALSE;
+ }
+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 */
+ /* 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);
+ }
+ /* 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;
+ }
+
+ 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 TRUE;
+}
+
+/*-----------------------------------------------------------------*/
+/* 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);
+
+ OP_SYMBOL (IC_LEFT (ic)) = OP_SYMBOL (IC_RIGHT (dic));
+ IC_LEFT (ic)->key = OP_KEY (IC_RIGHT (dic));
+ 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);
+
+ OP_SYMBOL (IC_RIGHT (ic)) = OP_SYMBOL (IC_RIGHT (dic));
+ IC_RIGHT (ic)->key = OP_KEY (IC_RIGHT (dic));
+
+ remiCodeFromeBBlock (ebp, dic);
+ bitVectUnSetBit(OP_SYMBOL(IC_RESULT(dic))->defs,dic->key);
+ hTabDeleteItem (&iCodehTab, dic->key, dic, DELETE_ITEM, NULL);
+ change++;
+ }
+
+ return change;
+}
+
+
+/*-----------------------------------------------------------------*/
+/* 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)) > (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;
+
+ if (!dic)
+ {
+ /* Not sure why we advance dic ... Make sure that we do
+ * not SEGFAULT by dereferencing a NULL pitr later on. */
+ return NULL;
+ } // if
+ }
+
+
+ /* 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__);
+
+ /* result too large for WREG? */
+ if (getSize (operandType (IC_RESULT (ic))) > 1)
+ return;
+
+ /* We have to make sure that OP_SYMBOL(IC_RESULT(ic))
+ * is never used as an operand to an instruction that
+ * cannot have WREG as an operand (e.g. BTFSx cannot
+ * operate on WREG...
+ * For now, store all results into proper registers. */
+ return;
+
+#if 0
+ /* 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;
+#endif
+}
+
+/*-----------------------------------------------------------------*/
+/* 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, *lic;
+ bitVect *dbv;
+ int disallowHiddenAssignment = 0;
+
+ 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;
+
+ /* If the defining iCode is outside of this block, we need to recompute */
+ /* ebp (see the mcs51 version of packForPush), but we weren't passed */
+ /* enough data to do that. Just bail out instead if that happens. */
+ if (dic->seq < ebp->fSeq)
+ return;
+
+ if (IS_SYMOP (IC_RIGHT (dic))) {
+ if (IC_RIGHT (dic)->isvolatile)
+ return;
+
+ if (OP_SYMBOL (IC_RIGHT (dic))->addrtaken || isOperandGlobal (IC_RIGHT (dic)))
+ disallowHiddenAssignment = 1;
+
+ /* make sure the right side does not have any definitions
+ inbetween */
+ dbv = OP_DEFS (IC_RIGHT (dic));
+ for (lic = ic; lic && lic != dic; lic = lic->prev) {
+ if (bitVectBitValue (dbv, lic->key))
+ return;
+ if (disallowHiddenAssignment && (lic->op == CALL || lic->op == PCALL || POINTER_SET (lic)))
+ return;
+ }
+ /* make sure they have the same type */
+ if (IS_SPEC (operandType (IC_LEFT (ic)))) {
+ sym_link *itype = operandType (IC_LEFT (ic));
+ sym_link *ditype = operandType (IC_RIGHT (dic));
+
+ if (SPEC_USIGN (itype) != SPEC_USIGN (ditype) || SPEC_LONG (itype) != SPEC_LONG (ditype))
+ return;
+ }
+ /* extend the live range of replaced operand if needed */
+ if (OP_SYMBOL (IC_RIGHT (dic))->liveTo < ic->seq) {
+ OP_SYMBOL (IC_RIGHT (dic))->liveTo = ic->seq;
+ }
+ bitVectUnSetBit (OP_SYMBOL (IC_RESULT (dic))->defs, dic->key);
+ }
+ if (IS_ITEMP (IC_RIGHT (dic)))
+ OP_USES (IC_RIGHT (dic)) = bitVectSetBit (OP_USES (IC_RIGHT (dic)), ic->key);
+
+ /* 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)
+{
+ if (debug) {
+ 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;
+
+ // avoid garbage `data' and `sfr' output
+ if(!sl || !debugF)
+ 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__);
+
+
+ /* Look for two subsequent iCodes with */
+ /* iTemp := _c; */
+ /* _c = iTemp & op; */
+ /* and replace them by */
+ /* iTemp := _c; */
+ /* _c = _c & op; */
+ if ((ic->op == BITWISEAND || ic->op == '|' || ic->op == '^') &&
+ ic->prev &&
+ ic->prev->op == '=' &&
+ IS_ITEMP (IC_LEFT (ic)) &&
+ IC_LEFT (ic) == IC_RESULT (ic->prev) &&
+ isOperandEqual (IC_RESULT(ic), IC_RIGHT(ic->prev))) {
+
+ iCode* ic_prev = ic->prev;
+ symbol* prev_result_sym = OP_SYMBOL (IC_RESULT (ic_prev));
+
+ ReplaceOpWithCheaperOp (&IC_LEFT (ic), IC_RESULT (ic));
+
+ if (IC_RESULT (ic_prev) != IC_RIGHT (ic)) {
+ bitVectUnSetBit (OP_USES (IC_RESULT (ic_prev)), ic->key);
+ if (/*IS_ITEMP (IC_RESULT (ic_prev)) && */
+ prev_result_sym->liveTo == ic->seq) {
+ prev_result_sym->liveTo = ic_prev->seq;
+ }
+ }
+
+ bitVectSetBit (OP_USES (IC_RESULT (ic)), ic->key);
+ bitVectSetBit (ic->rlive, IC_RESULT (ic)->key);
+
+ if (bitVectIsZero (OP_USES (IC_RESULT (ic_prev)))) {
+ bitVectUnSetBit (ic->rlive, IC_RESULT (ic)->key);
+ bitVectUnSetBit (OP_DEFS (IC_RESULT (ic_prev)), ic_prev->key);
+ remiCodeFromeBBlock (ebp, ic_prev);
+ hTabDeleteItem (&iCodehTab, ic_prev->key, ic_prev, DELETE_ITEM, NULL);
+ }
+ }
+
+ /* 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 &&
+ !isOperandGlobal (IC_RESULT (ic)) &&
+ !OP_SYMBOL (IC_RESULT (ic))->addrtaken)
+ {
+ 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) && IS_SYMOP(IC_RESULT(ic)))
+ {
+ OP_SYMBOL (IC_RESULT (ic))->uptr = 1;
+ debugLog (" marking as a pointer (set) =>");
+ debugAopGet (" result:", IC_RESULT (ic));
+ }
+ if (POINTER_GET (ic) && IS_SYMOP(IC_LEFT(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 pic14_ptrRegReq */
+ if (ic->op == IFX && IS_SYMOP (IC_COND (ic)))
+ pic14_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)))
+ pic14_ptrRegReq += ((OP_SYMBOL (IC_JTCOND (ic))->onStack ||
+ OP_SYMBOL (IC_JTCOND (ic))->iaccess) ? 1 : 0);
+ else
+ {
+ if (IS_SYMOP (IC_LEFT (ic)))
+ pic14_ptrRegReq += ((OP_SYMBOL (IC_LEFT (ic))->onStack ||
+ OP_SYMBOL (IC_LEFT (ic))->iaccess) ? 1 : 0);
+ if (IS_SYMOP (IC_RIGHT (ic)))
+ pic14_ptrRegReq += ((OP_SYMBOL (IC_RIGHT (ic))->onStack ||
+ OP_SYMBOL (IC_RIGHT (ic))->iaccess) ? 1 : 0);
+ if (IS_SYMOP (IC_RESULT (ic)))
+ pic14_ptrRegReq += ((OP_SYMBOL (IC_RESULT (ic))->onStack ||
+ OP_SYMBOL (IC_RESULT (ic))->iaccess) ? 1 : 0);
+ }
+
+ debugLog (" %d - pointer reg req = %d\n", __LINE__,pic14_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)) &&
+ IS_SYMOP(IC_RESULT(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)) &&
+ IS_SYMOP(IC_LEFT(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);
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* assignRegisters - assigns registers to each live range as need */
+/*-----------------------------------------------------------------*/
+void
+pic14_assignRegisters (ebbIndex *ebbi)
+{
+ int i;
+ iCode *ic;
+ eBBlock **ebbs = ebbi->bbOrder;
+ int count = ebbi->count;
+
+ debugLog ("<><><><><><><><><><><><><><><><><>\nstarting\t%s:%s\n",
+ __FILE__, __FUNCTION__);
+ debugLog ("ebbs before optimizing:\n");
+ dumpEbbsToDebug (ebbs, count);
+
+ setToNull ((void *) &_G.funcrUsed);
+ pic14_ptrRegReq = _G.stackExtend = _G.dataExtend = 0;
+
+ /* mark all r0xZZZZ registers as 'used' to guarantee that
+ * disjoint sets of registers are allocated to functions */
+ if (1)
+ {
+ reg_info *r;
+
+ for (r = setFirstItem (dynAllocRegs); r; r = setNextItem (dynAllocRegs))
+ {
+ r->isFree = FALSE;
+ }
+ }
+
+ /* change assignments this will remove some
+ live ranges reducing some register pressure */
+ for (i = 0; i < count; i++)
+ packRegisters (ebbs[i]);
+
+ if (1)
+ {
+ reg_info *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_i_code)
+ dumpEbbsToFileExt (DUMP_PACK, ebbi);
+
+ /* 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)
+ {
+ _G.stackExtend = 0;
+ }
+
+ if (_G.dataExtend)
+ {
+ _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_i_code)
+ dumpEbbsToFileExt (DUMP_RASSGN, ebbi);
+
+ /* now get back the chain */
+ ic = iCodeLabelOptimize (iCodeFromeBBlock (ebbs, count));
+
+ debugLog ("ebbs after optimizing:\n");
+ dumpEbbsToDebug (ebbs, count);
+
+ genpic14Code (ic);
+
+ /* free up any _G.stackSpil locations allocated */
+ applyToSet (_G.stackSpil, deallocStackSpil);
+ _G.slocNum = 0;
+ setToNull ((void *) &_G.stackSpil);
+ setToNull ((void *) &_G.spiltSet);
+
+ debugLog ("leaving\n<><><><><><><><><><><><><><><><><>\n");
+ pic14_debugLogClose ();
+}
diff --git a/src/pic14/ralloc.h b/src/pic14/ralloc.h
new file mode 100644
index 0000000..bcc1704
--- /dev/null
+++ b/src/pic14/ralloc.h
@@ -0,0 +1,123 @@
+/*-------------------------------------------------------------------------
+
+ SDCCralloc.h - header file register allocation
+
+ Written By - Sandeep Dutta . sandeep.dutta@usa.net (1998)
+ PIC port - T. Scott Dattalo scott@dattalo.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 SDCCRALLOC_H
+#define SDCCRALLOC_H 1
+
+#include "common.h"
+
+#include "pcoderegs.h"
+
+
+enum {
+ REG_PTR=1,
+ REG_GPR,
+ REG_CND,
+ REG_SFR,
+ REG_STK,
+ REG_TMP
+};
+
+/* definition for the registers */
+typedef struct reg_info
+{
+ 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 */
+ 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 isPublic:1; /* True if the reg is not static and can be modified in another module (ie a another c or asm file) */
+ unsigned isExtern:1; /* True if the reg is in another module */
+ 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 reg_info *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 */
+}
+reg_info;
+extern reg_info regspic14[];
+extern int 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 *dynAllocRegs;
+extern set *dynStackRegs;
+extern set *dynProcessorRegs;
+extern set *dynDirectRegs;
+extern set *dynDirectBitRegs;
+extern set *dynInternalRegs;
+
+
+void initStack(int base_address, int size, int shared);
+reg_info *pic14_regWithIdx(int);
+reg_info *dirregWithName(const char *name);
+void pic14_assignRegisters(ebbIndex *ebbi);
+reg_info *pic14_findFreeReg(short type);
+reg_info *pic14_allocWithIdx (int idx);
+reg_info *typeRegWithIdx(int idx, int type, int fixed);
+reg_info *regFindWithName(const char *name);
+
+void pic14_debugLogClose(void);
+void writeUsedRegs(FILE *of);
+
+reg_info *allocDirReg(operand *op );
+reg_info *allocInternalRegister(int rIdx, const char *name, PIC_OPTYPE po_type, int alias);
+reg_info *allocProcessorRegister(int rIdx, const char *name, short po_type, int alias);
+reg_info *allocRegByName(const char *name, int size );
+reg_info *allocNewDirReg(sym_link *symlnk, const char *name);
+
+/* Define register address that are constant across PIC family */
+#define IDX_INDF 0
+#define IDX_INDF0 0
+#define IDX_TMR0 1
+#define IDX_PCL 2
+#define IDX_STATUS 3
+#define IDX_FSR 4
+#define IDX_FSR0L 4
+#define IDX_FSR0H 5
+#define IDX_PCLATH 0x0a
+#define IDX_INTCON 0x0b
+
+#define IDX_KZ 0x7fff /* Known zero - actually just a general purpose reg. */
+#define IDX_WSAVE 0x7ffe
+#define IDX_SSAVE 0x7ffd
+#define IDX_PSAVE 0x7ffc
+
+#define pic14_nRegs 128
+
+#endif