diff options
Diffstat (limited to 'src/pic14')
| -rw-r--r-- | src/pic14/Makefile | 7 | ||||
| -rw-r--r-- | src/pic14/Makefile.in | 7 | ||||
| -rw-r--r-- | src/pic14/device.c | 821 | ||||
| -rw-r--r-- | src/pic14/device.h | 94 | ||||
| -rw-r--r-- | src/pic14/gen.c | 7842 | ||||
| -rw-r--r-- | src/pic14/gen.h | 174 | ||||
| -rw-r--r-- | src/pic14/genarith.c | 1289 | ||||
| -rw-r--r-- | src/pic14/glue.c | 1206 | ||||
| -rw-r--r-- | src/pic14/glue.h | 36 | ||||
| -rw-r--r-- | src/pic14/main.c | 485 | ||||
| -rw-r--r-- | src/pic14/main.h | 15 | ||||
| -rw-r--r-- | src/pic14/pcode.c | 5985 | ||||
| -rw-r--r-- | src/pic14/pcode.h | 907 | ||||
| -rw-r--r-- | src/pic14/pcodeflow.c | 226 | ||||
| -rw-r--r-- | src/pic14/pcodeflow.h | 68 | ||||
| -rw-r--r-- | src/pic14/pcodepeep.c | 2005 | ||||
| -rw-r--r-- | src/pic14/pcoderegs.c | 802 | ||||
| -rw-r--r-- | src/pic14/pcoderegs.h | 50 | ||||
| -rw-r--r-- | src/pic14/peeph.def | 323 | ||||
| -rw-r--r-- | src/pic14/pic14.vcxproj | 192 | ||||
| -rw-r--r-- | src/pic14/pic14.vcxproj.filters | 79 | ||||
| -rw-r--r-- | src/pic14/ralloc.c | 3874 | ||||
| -rw-r--r-- | src/pic14/ralloc.h | 123 |
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(<okIdx, 1)) ) // eat space + break; + + do { + j = pcComparePattern(&tokArr[ltokIdx], pcpArr[lpcpIdx].tokens, tokIdx +1); + if( j ) { + + switch(pcpArr[lpcpIdx].pt) { + case PCP_LABEL: + if(state == PS_START){ + DFPRINTF((stderr," label\n")); + state = PS_HAVE_LABEL; + } else + DFPRINTF((stderr," bad state (%d) for label\n",state)); + break; + + case PCP_STR: + DFPRINTF((stderr," %s is",tokArr[ltokIdx].tok.s)); + switch(state) { + case PS_START: + case PS_HAVE_LABEL: + DFPRINTF((stderr," mnem\n")); + 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(<okIdx, strlen(pcpArr[lpcpIdx].tokens) ) ) { + DFPRINTF((stderr," reached end \n")); + matching = 0; + //return; + } + } + + + } while ((++lpcpIdx < PCPATTERNS) && !matching); + + } while (matching); + + parsedPatArr[lparsedPatIdx].pcp = NULL; + parsedPatArr[lparsedPatIdx].pct = NULL; + + j=k=0; + do { + int c; + + if( (c=altComparePattern( altArr[k].tokens, &parsedPatArr[j],10) ) ) { + + if( altArr[k].f) { + pc = altArr[k].f(&parsedPatArr[j],pcwb); + //if(pc && pc->print) + // pc->print(stderr,pc); + //if(pc && pc->destruct) pc->destruct(pc); dumps core? + + if(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, ¤tRule->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, ¤tRule->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(¤tRule->target); + postinit_pCodeWildBlock(¤tRule->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(®->reglives.usedpCodes); + deleteSet(®->reglives.usedpFlows); + deleteSet(®->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) >peeph.rul</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">peeph.rul;%(Outputs)</Outputs>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">gawk -f ../SDCCpeeph.awk %(Identity) >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 |
