1 /*-------------------------------------------------------------------------
3 device.c - Accomodates subtle variations in PIC devices
4 Written By - Scott Dattalo scott@dattalo.com
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 -------------------------------------------------------------------------*/
26 extern set *includeDirsSet;
27 extern set *userIncDirsSet;
28 extern set *libDirsSet;
29 extern set *libPathsSet;
31 #define MAX_PICLIST 200
32 static PIC_device *Pics[MAX_PICLIST];
33 static PIC_device *pic = NULL;
34 static int num_of_supported_PICS = 0;
35 static int maxRAMaddress = 0;
37 #define CONFIG_WORD_ADDRESS 0x2007
38 #define CONFIG2_WORD_ADDRESS 0x2008
39 #define DEFAULT_CONFIG_WORD 0x3fff
40 #define DEFAULT_CONFIG2_WORD 0x3ffc
42 #define DEVICE_FILE_NAME "pic14devices.txt"
43 #define PIC14_STRING_LEN 256
44 #define SPLIT_WORDS_MAX 16
46 /* Keep track of whether we found an assignment to the __config words. */
47 static int pic14_hasSetConfigWord = 0;
48 static unsigned int config_word = DEFAULT_CONFIG_WORD;
49 static unsigned int config2_word = DEFAULT_CONFIG2_WORD;
50 static memRange *rangeRAM = NULL;
53 /* parse a value from the configuration file */
55 parse_config_value (char *str)
57 if (str[strlen (str) - 1] == 'K')
58 return atoi (str) * 1024; /* like "1K" */
60 else if (STRNCASECMP (str, "0x", 2) == 0)
61 return strtol (str+2, NULL, 16); /* like "0x400" */
64 return atoi (str); /* like "1024" */
68 /* split a line into words */
70 split_words (char **result_word, char *str)
72 static const char delim[] = " \f\n\r\t\v,";
76 /* release previously allocated words */
77 for (num_words = 0; num_words < SPLIT_WORDS_MAX; num_words++)
79 if (result_word[num_words])
81 free (result_word[num_words]);
82 result_word[num_words] = NULL;
87 token = strtok (str, delim);
89 while (token && (num_words < SPLIT_WORDS_MAX))
91 result_word[num_words] = Safe_strdup (token);
93 token = strtok (NULL, delim);
100 /* remove annoying prefixes from the processor name */
102 sanitise_processor_name (char *name)
104 char *proc_pos = name;
109 if (STRNCASECMP (proc_pos, "pic", 3) == 0)
112 else if (tolower (*proc_pos) == 'p')
119 /* create a structure for a pic processor */
121 create_pic (char *pic_name, int maxram, int bankmsk, int confsiz,
122 int program, int data, int eeprom, int io)
125 char *simple_pic_name = sanitise_processor_name (pic_name);
127 new_pic = Safe_calloc (1, sizeof (PIC_device));
128 new_pic->name = Safe_strdup (simple_pic_name);
130 new_pic->defMaxRAMaddrs = maxram;
131 new_pic->bankMask = bankmsk;
132 new_pic->hasSecondConfigReg = confsiz > 1;
134 new_pic->programMemSize = program;
135 new_pic->dataMemSize = data;
136 new_pic->eepromMemSize = eeprom;
137 new_pic->ioPins = io;
139 new_pic->ram = rangeRAM;
141 Pics[num_of_supported_PICS] = new_pic;
142 num_of_supported_PICS++;
148 /* mark some registers as being duplicated across banks */
150 register_map (int num_words, char **word)
157 fprintf (stderr, "WARNING: not enough values in %s regmap directive\n",
162 for (pcount = 2; pcount < num_words; pcount++)
164 r = Safe_calloc (1, sizeof (memRange));
166 r->start_address = parse_config_value (word[pcount]);
167 r->end_address = parse_config_value (word[pcount]);
168 r->alias = parse_config_value (word[1]);
169 r->bank = (r->start_address >> 7) & 3;
170 // add memRange to device entry for future lookup (sharebanks)
177 /* define ram areas - may be duplicated across banks */
179 ram_map (int num_words, char **word)
185 fprintf (stderr, "WARNING: not enough values in %s memmap directive\n",
190 r = Safe_calloc (1, sizeof (memRange));
191 //fprintf (stderr, "%s: %s %s %s\n", __FUNCTION__, word[1], word[2], word[3]);
193 r->start_address = parse_config_value (word[1]);
194 r->end_address = parse_config_value (word[2]);
195 r->alias = parse_config_value (word[3]);
196 r->bank = (r->start_address >> 7) & 3;
198 // add memRange to device entry for future lookup (sharebanks)
206 maxRAMaddress = size;
208 if (maxRAMaddress < 0)
210 fprintf (stderr, "invalid maxram 0x%x setting in %s\n",
211 maxRAMaddress, DEVICE_FILE_NAME);
216 /* read the file with all the pic14 definitions and pick out the definition
217 * for a processor if specified. if pic_name is NULL reads everything */
219 find_device (char *pic_name)
222 char pic_buf[PIC14_STRING_LEN];
223 int found_processor = FALSE;
225 char **processor_name;
226 int num_processor_names = 0;
234 char *simple_pic_name;
242 pic_word = Safe_calloc (sizeof (char *), SPLIT_WORDS_MAX);
243 processor_name = Safe_calloc (sizeof (char *), SPLIT_WORDS_MAX);
245 /* allow abbreviations of the form "f877" - convert to "16f877" */
246 simple_pic_name = sanitise_processor_name (pic_name);
247 num_of_supported_PICS = 0;
249 /* open the piclist file */
250 /* first scan all include directories */
252 //fprintf (stderr, "%s: searching %s\n", __FUNCTION__, DEVICE_FILE_NAME);
253 for (dir = setFirstItem (userIncDirsSet);
255 dir = setNextItem (userIncDirsSet))
257 //fprintf (stderr, "searching1 %s\n", dir);
258 SNPRINTF (&filename[0], len, "%s%s", dir,
259 DIR_SEPARATOR_STRING DEVICE_FILE_NAME);
260 pic_file = fopen (filename, "rt");
264 for (dir = setFirstItem (includeDirsSet);
266 dir = setNextItem (includeDirsSet))
268 //fprintf (stderr, "searching2 %s\n", dir);
269 SNPRINTF (&filename[0], len, "%s%s", dir,
270 DIR_SEPARATOR_STRING DEVICE_FILE_NAME);
271 pic_file = fopen (filename, "rt");
275 for (dir = setFirstItem (libDirsSet);
277 dir = setNextItem (libDirsSet))
279 //fprintf (stderr, "searching3 %s\n", dir);
280 SNPRINTF (&filename[0], len, "%s%s", dir,
281 DIR_SEPARATOR_STRING DEVICE_FILE_NAME);
282 pic_file = fopen (filename, "rt");
286 for (dir = setFirstItem (libPathsSet);
288 dir = setNextItem (libPathsSet))
290 //fprintf (stderr, "searching4 %s\n", dir);
291 SNPRINTF (&filename[0], len, "%s%s", dir,
292 DIR_SEPARATOR_STRING DEVICE_FILE_NAME);
293 pic_file = fopen (filename, "rt");
299 SNPRINTF (&filename[0], len, "%s",
300 DATADIR LIB_DIR_SUFFIX
301 DIR_SEPARATOR_STRING "pic"
302 DIR_SEPARATOR_STRING DEVICE_FILE_NAME);
303 pic_file = fopen (filename, "rt");
306 if (pic_file == NULL)
308 fprintf (stderr, "can't find %s\n", DEVICE_FILE_NAME);
313 printf ("Using devices from %s.\n", filename);
315 /* read line by line */
316 pic_buf[sizeof (pic_buf)-1] = '\0';
317 while (fgets (pic_buf, sizeof (pic_buf)-1, pic_file) != NULL && !done)
321 char *comment = strchr (pic_buf, '#');
326 /* split into fields */
327 num_pic_words = split_words (pic_word, pic_buf);
329 /* ignore comment / empty lines */
330 if (num_pic_words > 0)
333 if (STRCASECMP (pic_word[0], "processor") == 0)
335 if (pic_name == NULL)
339 /* this is the mode where we read all the processors in - store the names for now */
340 if (num_processor_names > 0)
342 /* store away all the previous processor definitions */
343 for (dcount = 1; dcount < num_processor_names; dcount++)
345 create_pic (processor_name[dcount], pic_maxram,
346 pic_bankmsk, pic_confsiz, pic_program,
347 pic_data, pic_eeprom, pic_io);
351 /* copy processor names */
352 num_processor_names = num_pic_words;
353 for (dcount = 1; dcount < num_processor_names; dcount++)
355 processor_name[dcount] = pic_word[dcount];
356 pic_word[dcount] = NULL;
361 /* if we've just completed reading a processor definition stop now */
366 /* check if this processor name is a match */
367 for (wcount = 1; wcount < num_pic_words; wcount++)
369 /* skip uninteresting prefixes */
370 char *found_name = sanitise_processor_name (pic_word[wcount]);
372 if (STRCASECMP (found_name, simple_pic_name) == 0)
373 found_processor = TRUE;
380 if (found_processor || pic_name == NULL)
382 /* only parse a processor section if we've found the one we want */
383 if (STRCASECMP (pic_word[0], "maxram") == 0 && num_pic_words > 1)
385 pic_maxram = parse_config_value (pic_word[1]);
386 setMaxRAM (pic_maxram);
389 else if (STRCASECMP (pic_word[0], "bankmsk") == 0 && num_pic_words > 1)
390 pic_bankmsk = parse_config_value (pic_word[1]);
392 else if (STRCASECMP (pic_word[0], "confsiz") == 0 && num_pic_words > 1)
393 pic_confsiz = parse_config_value (pic_word[1]);
395 else if (STRCASECMP (pic_word[0], "program") == 0 && num_pic_words > 1)
396 pic_program = parse_config_value (pic_word[1]);
398 else if (STRCASECMP (pic_word[0], "data") == 0 && num_pic_words > 1)
399 pic_data = parse_config_value (pic_word[1]);
401 else if (STRCASECMP (pic_word[0], "eeprom") == 0 && num_pic_words > 1)
402 pic_eeprom = parse_config_value (pic_word[1]);
404 else if (STRCASECMP (pic_word[0], "io") == 0 && num_pic_words > 1)
405 pic_io = parse_config_value (pic_word[1]);
407 else if (STRCASECMP (pic_word[0], "regmap") == 0 && num_pic_words > 2)
410 register_map (num_pic_words, pic_word);
413 else if (STRCASECMP (pic_word[0], "memmap") == 0 && num_pic_words > 2)
416 ram_map (num_pic_words, pic_word);
421 fprintf (stderr, "WARNING: %s: bad syntax `%s'\n",
422 DEVICE_FILE_NAME, pic_word[0]);
431 split_words (pic_word, NULL);
434 /* if we're in read-the-lot mode then create the final processor definition */
435 if (pic_name == NULL)
437 if (num_processor_names > 0)
439 /* store away all the previous processor definitions */
442 for (dcount = 1; dcount < num_processor_names; dcount++)
444 create_pic (processor_name[dcount], pic_maxram, pic_bankmsk,
445 pic_confsiz, pic_program, pic_data, pic_eeprom,
455 split_words (processor_name, NULL);
456 free (processor_name);
458 /* create a new pic entry */
459 return create_pic (pic_name, pic_maxram, pic_bankmsk,
460 pic_confsiz, pic_program, pic_data,
465 split_words (processor_name, NULL);
466 free (processor_name);
471 /*-----------------------------------------------------------------*
472 * void list_valid_pics(int ncols, int list_alias)
474 * Print out a formatted list of valid PIC devices
476 * ncols - number of columns in the list.
478 * list_alias - if non-zero, print all of the supported aliases
479 * for a device (e.g. F84, 16F84, etc...)
480 *-----------------------------------------------------------------*/
482 list_valid_pics(int ncols)
487 if (num_of_supported_PICS == 0)
488 find_device(NULL); /* load all the definitions */
490 /* decrement the column number if it's greater than zero */
491 ncols = (ncols > 1) ? ncols-1 : 4;
493 /* Find the device with the longest name */
494 for(i=0,longest=0; i<num_of_supported_PICS; i++) {
495 k = strlen(Pics[i]->name);
502 fprintf(stderr, "\nPIC14 processors and their characteristics:\n\n");
503 fprintf(stderr, " processor");
504 for(k=0; k<longest-1; k++)
506 fprintf(stderr, "program RAM EEPROM I/O\n");
507 fprintf(stderr, "-----------------------------------------------------\n");
509 for(i=0; i < num_of_supported_PICS; i++) {
510 fprintf(stderr," %s", Pics[i]->name);
511 l = longest + 2 - strlen(Pics[i]->name);
515 fprintf(stderr, " ");
516 if (Pics[i]->programMemSize % 1024 == 0)
517 fprintf(stderr, "%4dK", Pics[i]->programMemSize / 1024);
519 fprintf(stderr, "%5d", Pics[i]->programMemSize);
521 fprintf(stderr, " %5d %5d %4d\n",
522 Pics[i]->dataMemSize, Pics[i]->eepromMemSize, Pics[i]->ioPins);
527 fprintf(stderr, "\nPIC14 processors supported:\n");
528 for(i=0; i < num_of_supported_PICS; i++) {
530 fprintf(stderr,"%s", Pics[i]->name);
532 l = longest + 2 - strlen(Pics[i]->name);
549 /*-----------------------------------------------------------------*
551 *-----------------------------------------------------------------*/
552 PIC_device *init_pic(char *pic_type)
554 char long_name[PIC14_STRING_LEN];
556 pic = find_device(pic_type);
559 /* check for shortened "16xxx" form */
560 sprintf(long_name, "16%s", pic_type);
561 pic = find_device(long_name);
563 if(pic_type != NULL && pic_type[0] != '\0')
564 fprintf(stderr, "'%s' was not found.\n", pic_type);
566 fprintf(stderr, "No processor has been specified (use -pPROCESSOR_NAME)\n");
575 /*-----------------------------------------------------------------*
577 *-----------------------------------------------------------------*/
578 int picIsInitialized(void)
580 if(pic && maxRAMaddress > 0)
587 /*-----------------------------------------------------------------*
588 * char *processor_base_name(void) - Include file is derived from this.
589 *-----------------------------------------------------------------*/
590 char *processor_base_name(void)
599 int IS_CONFIG_ADDRESS(int address)
602 return ((address == CONFIG_WORD_ADDRESS)
603 || (address == CONFIG2_WORD_ADDRESS));
606 /*-----------------------------------------------------------------*
607 * void pic14_assignConfigWordValue(int address, int value)
609 * Most midrange PICs have one config word at address 0x2007.
610 * Newer PIC14s have a second config word at address 0x2008.
611 * This routine will assign values to those addresses.
613 *-----------------------------------------------------------------*/
615 void pic14_assignConfigWordValue(int address, int value)
617 if (CONFIG_WORD_ADDRESS == address)
620 else if (CONFIG2_WORD_ADDRESS == address)
621 config2_word = value;
623 //fprintf(stderr,"setting config word 0x%x to 0x%x\n", address, value);
624 pic14_hasSetConfigWord = 1;
627 /*-----------------------------------------------------------------*
628 * int pic14_getConfigWord(int address)
630 * Get the current value of a config word.
632 *-----------------------------------------------------------------*/
634 static int pic14_getConfigWord(int address)
638 case CONFIG_WORD_ADDRESS:
641 case CONFIG2_WORD_ADDRESS:
649 /*-----------------------------------------------------------------*
650 * int getHasSecondConfigReg(void) - check if the device has a
651 * second config register, rather than just one.
652 *-----------------------------------------------------------------*/
653 static int pic14_getHasSecondConfigReg(void)
658 return pic->hasSecondConfigReg;
661 /*-----------------------------------------------------------------*
662 * int pic14_emitConfigWord (FILE * vFile)
664 * Emit the __config directives iff we found a previous assignment
665 * to the config word.
666 *-----------------------------------------------------------------*/
667 int pic14_emitConfigWord (FILE * vFile)
669 if (pic14_hasSetConfigWord)
671 fprintf (vFile, "%s", iComments2);
672 fprintf (vFile, "; config word \n");
673 fprintf (vFile, "%s", iComments2);
674 if (pic14_getHasSecondConfigReg())
676 fprintf (vFile, "\t__config _CONFIG1, 0x%x\n", pic14_getConfigWord(0x2007));
677 fprintf (vFile, "\t__config _CONFIG2, 0x%x\n", pic14_getConfigWord(0x2008));
680 fprintf (vFile, "\t__config 0x%x\n", pic14_getConfigWord(0x2007));
687 /*-----------------------------------------------------------------*
688 * True iff the device has memory aliased in every bank.
689 * If true, low and high will be set to the low and high address
690 * occupied by the (last) sharebank found.
691 *-----------------------------------------------------------------*/
692 static int pic14_hasSharebank(int *low, int *high, int *size)
700 //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);
701 // find sufficiently large shared region
702 if ((r->alias == pic->bankMask)
703 && (r->end_address != r->start_address) // ignore SFRs
704 && (!size || (*size <= (r->end_address - r->start_address + 1))))
706 if (low) *low = r->start_address;
707 if (high) *high = r->end_address;
708 if (size) *size = r->end_address - r->start_address + 1;
715 if (high) *high = 0x0;
716 if (size) *size = 0x0;
717 //fprintf (stderr, "%s: no shared bank found\n", __FUNCTION__);
722 * True iff the memory region [low, high] is aliased in all banks.
724 static int pic14_isShared(int low, int high)
732 //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);
733 if ((r->alias == pic->bankMask) && (r->start_address <= low) && (r->end_address >= high)) {
743 * True iff all RAM is aliased in all banks (no BANKSELs required except for
746 int pic14_allRAMShared(void)
754 if (r->alias != pic->bankMask) return 0;
762 * True iff the pseudo stack is a sharebank --> let linker place it.
763 * [low, high] denotes a size byte long block of (shared or banked)
766 int pic14_getSharedStack(int *low, int *high, int *size)
771 s = options.stack_size ? options.stack_size : 0x10;
772 haveShared = pic14_hasSharebank(&l, &h, &s);
773 if ((options.stack_loc != 0) || !haveShared)
775 // sharebank not available or not to be used
776 s = options.stack_size ? options.stack_size : 0x10;
777 l = options.stack_loc ? options.stack_loc : 0x20;
782 // return 1 iff [low, high] is present in all banks
783 //fprintf(stderr, "%s: low %x, high %x, size %x, shared %d\n", __FUNCTION__, l, h, s, pic14_isShared(l, h));
784 return (pic14_isShared(l, h));
786 // sharebanks available for use by the stack
787 if (options.stack_size) s = options.stack_size;
788 else if (!s || s > 16) s = 16; // limit stack to 16 bytes in SHAREBANK
790 // provide addresses for sharebank
792 if (high) *high = l + s - 1;
794 //fprintf(stderr, "%s: low %x, high %x, size %x, shared 1\n", __FUNCTION__, l, h, s);
799 PIC_device * pic14_getPIC(void)