1 /*-------------------------------------------------------------------------
2 device.c - Accomodates subtle variations in PIC16 devices
3
4 Copyright (C) 2000, Scott Dattalo scott@dattalo.com
5 PIC16 port:
6 Copyright (C) 2002, Martin Dubuc m.dubuc@rogers.com
7
8 This program is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 2, or (at your option) any
11 later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 -------------------------------------------------------------------------*/
22
23 #include <stdio.h>
24
25 #include "common.h" // Include everything in the SDCC src directory
26 #include "newalloc.h"
27 #include "dbuf_string.h"
28
29 #include "main.h"
30 #include "pcode.h"
31 #include "ralloc.h"
32 #include "device.h"
33
34 void pic16_printIval (symbol * sym, sym_link * type, initList * ilist, char ptype, void *p);
35 extern void pic16_pCodeConstString (char *name, const char *value, unsigned length);
36
37 stats_t statistics = { 0, 0, 0, 0 };
38
39 #define DEVICE_FILE_NAME "pic16devices.txt"
40
41 static PIC16_device default_device = {
42 { "p18f452", "18f452", "pic18f452", "f452" },
43 0x600,
44 0x80,
45 { /* configuration words */
46 0x300001, 0x30000d,
47 { { 0x27, 0, 0xff } /* 1 */ , { 0x0f, 0, 0xff } /* 2 */ ,
48 { 0x0f, 0, 0xff } /* 3 */ , { -1 , 0, 0xff } /* 4 */ ,
49 { 0x01, 0, 0xff } /* 5 */ , { 0x85, 0, 0xff } /* 6 */ ,
50 { -1 , 0, 0xff } /* 7 */ , { 0x0f, 0, 0xff } /* 8 */ ,
51 { 0xc0, 0, 0xff } /* 9 */ , { 0x0f, 0, 0xff } /* a */ ,
52 { 0xe0, 0, 0xff } /* b */ , { 0x0f, 0, 0xff } /* c */ ,
53 { 0x40, 0, 0xff } /* d */ }
54 },
55 { /* ID locations */
56 0x200000, 0x200007,
57 { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
58 { 0, 0 }, { 0, 0 }, { 0, 0 } }
59 },
60 0,
61 NULL
62 };
63
64 PIC16_device *pic16 = &default_device;
65 static PIC16_device *devices = NULL;
66
67 extern set *includeDirsSet;
68 extern set *userIncDirsSet;
69
70 extern char *iComments2;
71
72 void
pic16_dump_equates(FILE * of,set * equs)73 pic16_dump_equates (FILE *of, set *equs)
74 {
75 reg_info *r;
76
77 r = setFirstItem (equs);
78 if (!r)
79 return;
80
81 fprintf (of, "\n%s", iComments2);
82 fprintf (of, ";\tEquates to used internal registers\n");
83 fprintf (of, "%s", iComments2);
84
85 for (; r; r = setNextItem (equs))
86 {
87 fprintf (of, "%s\tequ\t0x%03x\n", r->name, r->address);
88 } // for
89 }
90
91
92 void
pic16_dump_access(FILE * of,set * section)93 pic16_dump_access (FILE *of, set *section)
94 {
95 reg_info *r;
96
97 r = setFirstItem (section);
98 if (!r)
99 return;
100
101 fprintf (of, "%s", iComments2);
102 fprintf (of, ";\tAccess bank symbols\n");
103 fprintf (of, "%s", iComments2);
104
105 fprintf (of, "\tudata_acs\n");
106 for (; r; r = setNextItem (section))
107 {
108 fprintf (of, "%s\tres\t%d\n", r->name, r->size);
109 statistics.adsize += r->size;
110 } // for
111 }
112
113 int
regCompare(const void * a,const void * b)114 regCompare (const void *a, const void *b)
115 {
116 const reg_info *const *i = a;
117 const reg_info *const *j = b;
118
119 /* Sort primarily by the address ... */
120 if ((*i)->address > (*j)->address)
121 return (1);
122
123 if ((*i)->address < (*j)->address)
124 return (-1);
125
126 /* ... and secondarily by size. */
127 /* Register size sorting may have strange results, use with care! */
128 if ((*i)->size > (*j)->size)
129 return (1);
130
131 if ((*i)->size < (*j)->size)
132 return (-1);
133
134 /* Finally, if in same address and same size, sort by name. */
135 return (strcmp ((*i)->name, (*j)->name));
136 }
137
138 int
symCompare(const void * a,const void * b)139 symCompare (const void *a, const void *b)
140 {
141 const symbol *const *i = a;
142 const symbol *const *j = b;
143
144 /* Sort primarily by the address ... */
145 if (SPEC_ADDR ((*i)->etype) > SPEC_ADDR ((*j)->etype))
146 return (1);
147
148 if (SPEC_ADDR ((*i)->etype) < SPEC_ADDR ((*j)->etype))
149 return (-1);
150
151 /* ... and secondarily by size. */
152 /* Register size sorting may have strange results, use with care! */
153 if (getSize ((*i)->etype) > getSize ((*j)->etype))
154 return (1);
155
156 if (getSize ((*i)->etype) < getSize ((*j)->etype))
157 return (-1);
158
159 /* Finally, if in same address and same size, sort by name. */
160 return (strcmp ((*i)->rname, (*j)->rname));
161 }
162
163 void
pic16_dump_usection(FILE * of,set * section,int fix)164 pic16_dump_usection (FILE *of, set *section, int fix)
165 {
166 static int abs_usection_no = 0;
167 static unsigned int usection_no = 0;
168 reg_info *r, *rprev;
169 unsigned int init_addr, i;
170 reg_info **rlist;
171 reg_info *r1;
172
173 /* put all symbols in an array */
174 if (!elementsInSet (section))
175 return;
176
177 rlist = Safe_calloc (elementsInSet (section), sizeof (reg_info *));
178 r = rlist[0];
179 i = 0;
180 for (rprev = setFirstItem (section); rprev; rprev = setNextItem (section))
181 {
182 rlist[i] = rprev;
183 i++;
184 } // for
185
186 if (!i)
187 {
188 if (rlist)
189 Safe_free (rlist);
190
191 return;
192 } // if
193
194 /* sort symbols according to their address */
195 qsort (rlist, i, sizeof (reg_info *), regCompare);
196
197 if (!fix)
198 {
199 #define EMIT_SINGLE_UDATA_SECTION 0
200 #if EMIT_SINGLE_UDATA_SECTION
201 fprintf (of, "\n\n\tudata\n");
202 for (r = setFirstItem (section); r; r = setNextItem (section))
203 {
204 fprintf (of, "%s\tres\t%d\n", r->name, r->size);
205 statistics.udsize += r->size;
206 } // for
207 #else
208 for (r = setFirstItem (section); r; r = setNextItem (section))
209 {
210 //fprintf (of, "\nudata_%s_%s\tudata\n", moduleName, r->name);
211 fprintf (of, "\nudata_%s_%u\tudata\n", moduleName, usection_no++);
212 fprintf (of, "%s\tres\t%d\n", r->name, r->size);
213 statistics.udsize += r->size;
214 } // for
215 #endif
216 }
217 else
218 {
219 unsigned int j = 0;
220 unsigned int prev_size = 0;
221
222 rprev = NULL;
223 init_addr = (rlist[j]->address & 0x0FFF); // warning(s) emitted below
224 fprintf (of, "\n\nustat_%s_%02d\tudata\t0X%04X\n", moduleName, abs_usection_no++, (init_addr & 0x0FFF));
225
226 for (j = 0; j < i; j++)
227 {
228 r = rlist[j];
229 r1 = NULL;
230 if (j < i - 1)
231 r1 = rlist[j + 1];
232
233 init_addr = (r->address & 0x0FFF);
234 if (init_addr != r->address)
235 {
236 fprintf (stderr, "%s: WARNING: Changed address of pinned variable %s from 0x%x to 0x%x\n",
237 moduleName, r->name, r->address, init_addr);
238 } // if
239
240 if ((rprev && (init_addr != ((rprev->address & 0x0FFF) + prev_size))))
241 fprintf (of, "\n\nustat_%s_%02d\tudata\t0X%04X\n", moduleName, abs_usection_no++, init_addr);
242
243 /* XXX: Does not handle partial overlap correctly. */
244 if (r1 && (init_addr == (r1->address & 0x0FFF)))
245 {
246 prev_size = 0;
247 fprintf (of, "%-15s\n", r->name);
248 }
249 else
250 {
251 prev_size = r->size;
252 fprintf (of, "%-15s\tres\t%d\n", r->name, prev_size);
253 statistics.udsize += prev_size;
254 }
255
256 rprev = r;
257 } // for
258 } // if
259
260 Safe_free (rlist);
261 }
262
263 void
pic16_dump_gsection(FILE * of,set * sections)264 pic16_dump_gsection (FILE *of, set *sections)
265 {
266 reg_info *r;
267 sectName *sname;
268
269 for (sname = setFirstItem (sections); sname; sname = setNextItem (sections))
270 {
271 if (!strcmp (sname->name, "access"))
272 continue;
273
274 fprintf (of, "\n\n%s\tudata\n", sname->name);
275
276 for (r = setFirstItem (sname->regsSet); r; r = setNextItem (sname->regsSet))
277 {
278 #if 0
279 fprintf (stderr, "%s:%d emitting variable %s for section %s (%p)\n",
280 __FILE__, __LINE__, r->name, sname->name, sname);
281 #endif
282 fprintf (of, "%s\tres\t%d\n", r->name, r->size);
283 statistics.udsize += r->size;
284 } // for
285 } // for
286 }
287
288 void
pic16_dump_isection(FILE * of,set * section,int fix)289 pic16_dump_isection (FILE *of, set *section, int fix)
290 {
291 static int abs_isection_no = 0;
292 symbol *s, *sprev;
293 unsigned int init_addr, i;
294 symbol **slist;
295
296 /* put all symbols in an array */
297 if (!elementsInSet (section))
298 return;
299
300 slist = Safe_calloc (elementsInSet (section), sizeof (symbol *));
301 s = slist[0];
302 i = 0;
303 for (sprev = setFirstItem (section); sprev; sprev = setNextItem (section))
304 {
305 slist[i] = sprev;
306 i++;
307 } // for
308
309 if (!i)
310 {
311 if (slist)
312 Safe_free (slist);
313
314 return;
315 } // if
316
317 /* sort symbols according to their address */
318 qsort (slist, i, sizeof (symbol *), symCompare);
319
320 pic16_initDB ();
321
322 if (!fix)
323 {
324 fprintf (of, "\n\n\tidata\n");
325 for (s = setFirstItem (section); s; s = setNextItem (section))
326 {
327 if (s->ival)
328 {
329 fprintf (of, "%s", s->rname);
330 pic16_printIval (s, s->type, s->ival, 'f', (void *)of);
331 pic16_flushDB ('f', (void *)of);
332 }
333 else
334 {
335 if (IS_ARRAY (s->type) && IS_CHAR (s->type->next)
336 && SPEC_CVAL (s->etype).v_char)
337 {
338 //fprintf (stderr, "%s:%d printing code string from %s\n", __FILE__, __LINE__, s->rname);
339 pic16_pCodeConstString (s->rname , SPEC_CVAL (s->etype).v_char, getSize (s->type));
340 }
341 else
342 {
343 assert (0);
344 } // if
345 } // if
346 } // for
347 }
348 else
349 {
350 unsigned int j = 0;
351
352 sprev = NULL;
353 init_addr = SPEC_ADDR (slist[j]->etype);
354 fprintf (of, "\n\nistat_%s_%02d\tidata\t0X%04X\n", moduleName, abs_isection_no++, init_addr);
355
356 for (j = 0; j < i; j++)
357 {
358 s = slist[j];
359 init_addr = SPEC_ADDR (s->etype);
360
361 if (sprev && (init_addr > (SPEC_ADDR (sprev->etype) + getSize (sprev->etype))))
362 fprintf(of, "\nistat_%s_%02d\tidata\t0X%04X\n", moduleName, abs_isection_no++, init_addr);
363
364 if (s->ival)
365 {
366 fprintf (of, "%s", s->rname);
367 pic16_printIval (s, s->type, s->ival, 'f', (void *)of);
368 pic16_flushDB ('f', (void *)of);
369 }
370 else
371 {
372 if (IS_ARRAY (s->type) && IS_CHAR (s->type->next)
373 && SPEC_CVAL (s->etype).v_char)
374 {
375 //fprintf (stderr, "%s:%d printing code string from %s\n", __FILE__, __LINE__, s->rname);
376 pic16_pCodeConstString (s->rname , SPEC_CVAL (s->etype).v_char, getSize (s->type));
377 }
378 else
379 {
380 assert (0);
381 } // if
382 } // if
383
384 sprev = s;
385 } // for
386 } // if
387
388 Safe_free (slist);
389 }
390
391 void
pic16_dump_int_registers(FILE * of,set * section)392 pic16_dump_int_registers (FILE *of, set *section)
393 {
394 reg_info *r, *rprev;
395 int i;
396 reg_info **rlist;
397
398 /* put all symbols in an array */
399 if (!elementsInSet (section))
400 return;
401
402 rlist = Safe_calloc (elementsInSet (section), sizeof (reg_info *));
403 r = rlist[0];
404 i = 0;
405 for (rprev = setFirstItem (section); rprev; rprev = setNextItem (section))
406 {
407 rlist[i] = rprev;
408 i++;
409 } // for
410
411 if (!i)
412 {
413 if (rlist)
414 Safe_free (rlist);
415
416 return;
417 } // if
418
419 /* sort symbols according to their address */
420 qsort (rlist, i, sizeof (reg_info *), regCompare);
421
422 fprintf (of, "\n\n; Internal registers\n");
423
424 fprintf (of, "%s\tudata_ovr\t0x0000\n", ".registers");
425 for (r = setFirstItem (section); r; r = setNextItem (section))
426 {
427 fprintf (of, "%s\tres\t%d\n", r->name, r->size);
428 statistics.intsize += r->size;
429 } // for
430
431 Safe_free (rlist);
432 }
433
434 /**
435 * Find the device structure for the named device.
436 * Consider usind pic16_find_device() instead!
437 *
438 * @param name
439 * a name for the desired device
440 * @param head
441 * a pointer to the head of the list of devices
442 * @return
443 * a pointer to the structure for the desired
444 * device, or NULL
445 */
446 static PIC16_device *
find_in_list(const char * name,PIC16_device * head)447 find_in_list(const char *name, PIC16_device *head)
448 {
449 int i;
450
451 while (head) {
452 for (i = 0; i < 4; i++) {
453 if (0 == STRCASECMP(head->name[i], name)) {
454 return (head);
455 } // if
456 } // for
457
458 head = head->next;
459 } // while
460
461 return (NULL);
462 }
463
464 /**
465 * Print a list of supported devices.
466 * If --verbose was given, also emit key characteristics (memory size,
467 * access bank split point, address range of SFRs and config words).
468 *
469 * @param head
470 * a pointer to the head of the list of devices
471 */
472 static void
pic16_list_devices(PIC16_device * head)473 pic16_list_devices(PIC16_device *head)
474 {
475 int i = 0;
476
477 if (options.verbose) {
478 printf("device RAM split config words\n");
479 } // if
480 while (head) {
481 printf("%-10s ", head->name[0]);
482 if (options.verbose) {
483 printf("%5d 0x%02x 0x%06x..0x%06x\n",
484 head->RAMsize,
485 head->acsSplitOfs,
486 head->cwInfo.confAddrStart,
487 head->cwInfo.confAddrEnd);
488 } else {
489 i++;
490 if (0 == (i % 6)) {
491 printf("\n");
492 } // if
493 } // if
494 head = head->next;
495 } // while
496 printf("\n");
497 }
498
499 /**
500 * Read a single line from the given file.
501 *
502 * @param file
503 * a pointer to the open file to read
504 * @return
505 * a pointer to a malloc'ed copy of the (next) line, or NULL
506 */
507 static char *
get_line(FILE * file)508 get_line (FILE *file)
509 {
510 static struct dbuf_s dbuf;
511 static int initialized = 0;
512
513 if (!initialized)
514 {
515 dbuf_init (&dbuf, 129);
516 initialized = 1;
517 }
518 else
519 dbuf_set_length (&dbuf, 0);
520
521
522 if (dbuf_getline (&dbuf, file) != 0)
523 {
524 dbuf_chomp (&dbuf);
525 /* (char *) type cast is an ugly hack since pic16_find_device() modifies the buffer */
526 return (char *)dbuf_get_buf (&dbuf);
527 }
528 else
529 {
530 dbuf_destroy(&dbuf);
531 initialized = 0;
532 return NULL;
533 }
534 }
535
536 /**
537 * Truncate the given string in place (!) at the first '#' character (if any).
538 *
539 * @param line
540 * a pointer to the string to truncate
541 * @return
542 * a pointer to the truncated string (i.e., line)
543 */
544 static char *
strip_comment(char * line)545 strip_comment (char *line)
546 {
547 char *l = line;
548 char c;
549
550 if (!line)
551 {
552 return (line);
553 } // if
554
555 while (0 != (c = *l))
556 {
557 if ('#' == c)
558 {
559 *l = 0;
560 return (line);
561 } // if
562 l++;
563 } // while
564
565 return (line);
566 }
567
568 /**
569 * Report errors in the device specification.
570 *
571 * @param msg
572 * a pointer to the detailed message
573 */
574 #define SYNTAX(msg) do { \
575 fprintf(stderr, "%s:%d: Syntax error: %s\n", \
576 DEVICE_FILE_NAME, lineno, msg); \
577 } while (0)
578
579 /**
580 * Locate and read in the device specification (if required) and
581 * return the device structure for the named device.
582 *
583 * @param name
584 * a pointer to the name of the desired device
585 * @return
586 * a pointer to the device structure, or NULL
587 */
588 static PIC16_device *
pic16_find_device(const char * name)589 pic16_find_device(const char *name)
590 {
591 const char *path;
592 char buffer[PATH_MAX];
593 char *line, *key;
594 const char *sep = " \t\n\r";
595 FILE *f = NULL;
596 PIC16_device *d = NULL, *template;
597 PIC16_device *head = NULL, *tail = NULL;
598 set *_sets[] = { userIncDirsSet, includeDirsSet };
599 set **sets = &_sets[0];
600 int lineno = 0;
601 int res, i;
602 int val[4];
603
604 if (!devices)
605 {
606 //printf("%s: searching %s\n", __func__, DEVICE_FILE_NAME);
607
608 // locate the specification file in the include search paths
609 for (i = 0; (NULL == f) && (i < 2); i++)
610 {
611 for (path = setFirstItem(sets[i]);
612 (NULL == f) && path;
613 path = setNextItem(sets[i]))
614 {
615 SNPRINTF(&buffer[0], PATH_MAX, "%s%s%s",
616 path, DIR_SEPARATOR_STRING, DEVICE_FILE_NAME);
617 //printf("%s: checking %s\n", __func__, &buffer[0]);
618 f = fopen(&buffer[0], "r");
619 } // for
620 } // for
621 } // if
622
623 if (devices)
624 {
625 // list already set up, nothing to do
626 }
627 else if (NULL == f)
628 {
629 fprintf(stderr, "ERROR: device list %s not found, specify its path via -I<path>\n",
630 DEVICE_FILE_NAME);
631 d = &default_device;
632 }
633 else
634 {
635 // parse the specification file and construct a linked list of
636 // supported devices
637 d = NULL;
638 while (NULL != (line = get_line(f)))
639 {
640 strip_comment(line);
641 //printf("%s: read %s\n", __func__, line);
642 lineno++;
643 key = strtok(line, sep);
644 if (!key)
645 {
646 // empty line---ignore
647 }
648 else if (0 == strcmp(key, "name"))
649 {
650 // name %<name>s
651 if (d)
652 {
653 if (tail)
654 {
655 tail->next = d;
656 }
657 else
658 {
659 head = d;
660 } // if
661 tail = d;
662 d = NULL;
663 } // if
664
665 res = sscanf(&line[1 + strlen(key)], " %16s", &buffer[3]);
666 if ((1 < res) || (3 > strlen(&buffer[3])))
667 {
668 SYNTAX("<name> (e.g., 18f452) expected.");
669 }
670 else
671 {
672 d = Safe_alloc(sizeof(PIC16_device));
673
674 // { "p18f452", "18f452", "pic18f452", "f452" }
675 buffer[0] = 'p';
676 buffer[1] = 'i';
677 buffer[2] = 'c';
678 d->name[3] = Safe_strdup(&buffer[5]);
679 d->name[2] = Safe_strdup(&buffer[0]);
680 d->name[1] = Safe_strdup(&buffer[3]);
681 buffer[2] = 'p';
682 d->name[0] = Safe_strdup(&buffer[2]);
683 } // if
684 }
685 else if (0 == strcmp(key, "using"))
686 {
687 // using %<name>s
688 res = sscanf(&line[1 + strlen(key)], " %16s", &buffer[0]);
689 if ((1 < res) || (3 > strlen(&buffer[3])))
690 {
691 SYNTAX("<name> (e.g., 18f452) expected.");
692 }
693 else
694 {
695 template = find_in_list(&buffer[0], head);
696 if (!template)
697 {
698 SYNTAX("<name> (e.g., 18f452) expected.");
699 }
700 else
701 {
702 memcpy(&d->RAMsize, &template->RAMsize,
703 ((char *)&d->next) - ((char *)&d->RAMsize));
704 } // if
705 } // if
706 }
707 else if (0 == strcmp(key, "ramsize"))
708 {
709 // ramsize %<bytes>i
710 res = sscanf(&line[1 + strlen(key)], " %i", &val[0]);
711 if (res < 1)
712 {
713 SYNTAX("<bytes> (e.g., 256) expected.");
714 }
715 else
716 {
717 d->RAMsize = val[0];
718 } // if
719 }
720 else if (0 == strcmp(key, "split"))
721 {
722 // split %<offset>i
723 res = sscanf(&line[1 + strlen(key)], " %i", &val[0]);
724 if (res < 1)
725 {
726 SYNTAX("<offset> (e.g., 0x80) expected.");
727 }
728 else
729 {
730 d->acsSplitOfs = val[0];
731 } // if
732 }
733 else if (0 == strcmp(key, "configrange"))
734 {
735 // configrange %<first>i %<last>i
736 res = sscanf(&line[1 + strlen(key)], " %i %i",
737 &val[0], &val[1]);
738 if (res < 2)
739 {
740 SYNTAX("<first> <last> (e.g., 0xf60 0xfff) expected.");
741 }
742 else
743 {
744 d->cwInfo.confAddrStart = val[0];
745 d->cwInfo.confAddrEnd = val[1];
746 } // if
747 }
748 else if (0 == strcmp(key, "configword"))
749 {
750 // configword %<address>i %<mask>i %<value>i [%<and-mask>i]
751 res = sscanf(&line[1 + strlen(key)], " %i %i %i %i",
752 &val[0], &val[1], &val[2], &val[3]);
753 if (res < 3)
754 {
755 SYNTAX("<address> <mask> <value> [<and-mask>] (e.g., 0x200001 0x0f 0x07) expected.");
756 }
757 else
758 {
759 val[0] -= d->cwInfo.confAddrStart;
760 if ((val[0] < 0)
761 || (val[0] > (d->cwInfo.confAddrEnd - d->cwInfo.confAddrStart))
762 || (val[0] >= CONFIGURATION_WORDS))
763 {
764 SYNTAX("address out of bounds.");
765 }
766 else
767 {
768 d->cwInfo.crInfo[val[0]].mask = val[1];
769 d->cwInfo.crInfo[val[0]].value = val[2];
770 d->cwInfo.crInfo[val[0]].andmask = 0;
771 if (res >= 4)
772 {
773 // apply extra mask (e.g., to disable XINST)
774 d->cwInfo.crInfo[val[0]].andmask = val[3];
775 } // if
776 } // if
777 } // if
778 }
779 else if (0 == strcmp(key, "idlocrange"))
780 {
781 // idlocrange %<first>i %<last>i
782 res = sscanf(&line[1 + strlen(key)], " %i %i",
783 &val[0], &val[1]);
784 if (res < 2)
785 {
786 SYNTAX("<first> <last> (e.g., 0xf60 0xfff) expected.");
787 }
788 else
789 {
790 d->idInfo.idAddrStart = val[0];
791 d->idInfo.idAddrEnd = val[1];
792 } // if
793 }
794 else if (0 == strcmp(key, "idword"))
795 {
796 // idword %<address>i %<value>i
797 res = sscanf(&line[1 + strlen(key)], " %i %i",
798 &val[0], &val[1]);
799 if (res < 2)
800 {
801 SYNTAX("<address> <value> (e.g., 0x3fffff 0x00) expected.");
802 }
803 else
804 {
805 val[0] -= d->idInfo.idAddrStart;
806 if ((val[0] < 0)
807 || (val[0] > (d->idInfo.idAddrEnd - d->idInfo.idAddrStart))
808 || (val[0] >= IDLOCATION_BYTES))
809 {
810 SYNTAX("address out of bounds.");
811 }
812 else
813 {
814 d->idInfo.irInfo[val[0]].value = val[1];
815 } // if
816 } // if
817 }
818 else if (0 == strcmp(key, "XINST"))
819 {
820 // XINST %<supported>i
821 res = sscanf(&line[1 + strlen(key)], " %i", &val[0]);
822 if (res < 1)
823 {
824 SYNTAX("<supported> (e.g., 1) expected.");
825 }
826 else
827 {
828 d->xinst = val[0];
829 } // if
830 }
831 else
832 {
833 printf("%s: Invalid keyword in %s ignored: %s\n",
834 __func__, DEVICE_FILE_NAME, key);
835 } // if
836 } // while
837
838 if (d)
839 {
840 if (tail)
841 {
842 tail->next = d;
843 }
844 else
845 {
846 head = d;
847 } // if
848 tail = d;
849 d = NULL;
850 } // if
851
852 devices = head;
853
854 fclose(f);
855 } // if
856
857 d = find_in_list(name, devices);
858 if (!d)
859 {
860 d = &default_device;
861 } // if
862
863 return (d);
864 }
865
866 /*-----------------------------------------------------------------*
867 *
868 *-----------------------------------------------------------------*/
pic16_init_pic(const char * pic_type)869 void pic16_init_pic(const char *pic_type)
870 {
871 pic16 = pic16_find_device(pic_type);
872
873 if (&default_device == pic16) {
874 if (pic_type) {
875 fprintf(stderr, "'%s' was not found.\n", pic_type);
876 } else {
877 fprintf(stderr, "No processor has been specified (use -pPROCESSOR_NAME)\n");
878 } // if
879
880 if (devices) {
881 fprintf(stderr,"Valid devices are (use --verbose for more details):\n");
882 pic16_list_devices(devices);
883 } // if
884 exit(EXIT_FAILURE);
885 } // if
886 }
887
888 /*-----------------------------------------------------------------*
889 * char *pic16_processor_base_name(void) - Include file is derived from this.
890 *-----------------------------------------------------------------*/
891
pic16_processor_base_name(void)892 const char *pic16_processor_base_name(void)
893 {
894 if(!pic16)
895 return NULL;
896
897 return pic16->name[0];
898 }
899
900 #define DEBUG_CHECK 0
901
902 /*
903 * return 1 if register wasn't found and added, 0 otherwise
904 */
checkAddReg(set ** set,reg_info * reg)905 int checkAddReg(set **set, reg_info *reg)
906 {
907 reg_info *tmp;
908
909
910 if(!reg)return 0;
911 #if DEBUG_CHECK
912 fprintf(stderr, "%s: about to insert REGister: %s ... ", __FUNCTION__, reg->name);
913 #endif
914
915 for(tmp = setFirstItem(*set); tmp; tmp = setNextItem(*set)) {
916 if(!strcmp(tmp->name, reg->name))break;
917 }
918
919 if(!tmp) {
920 addSet(set, reg);
921 #if DEBUG_CHECK
922 fprintf(stderr, "added\n");
923 #endif
924 return 1;
925 }
926
927 #if DEBUG_CHECK
928 fprintf(stderr, "already added\n");
929 #endif
930 return 0;
931 }
932
checkAddSym(set ** set,symbol * sym)933 int checkAddSym(set **set, symbol *sym)
934 {
935 symbol *tmp;
936
937 if(!sym)return 0;
938 #if DEBUG_CHECK
939 fprintf(stderr, "%s: about to add SYMbol: %s ... ", __FUNCTION__, sym->name);
940 #endif
941
942 for(tmp = setFirstItem( *set ); tmp; tmp = setNextItem(*set)) {
943 if(!strcmp(tmp->name, sym->name))break;
944 }
945
946 if(!tmp) {
947 addSet(set, sym);
948 #if DEBUG_CHECK
949 fprintf(stderr, "added\n");
950 #endif
951 return 1;
952 }
953
954 #if DEBUG_CHECK
955 fprintf(stderr, "already added\n");
956 #endif
957
958 return 0;
959 }
960
checkSym(set * set,symbol * sym)961 int checkSym(set *set, symbol *sym)
962 {
963 symbol *tmp;
964
965 if(!sym)return 0;
966
967 #if DEUG_CHECK
968 fprintf(stderr, "%s: about to search for SYMbol: %s ... ", __FUNCTION__, sym->name);
969 #endif
970
971 for(tmp = setFirstItem( set ); tmp; tmp = setNextItem( set )) {
972 if(!strcmp(tmp->name, sym->name))break;
973 }
974
975 if(!tmp) {
976 #if DEBUG_CHECK
977 fprintf(stderr, "not found\n");
978 #endif
979 return 0;
980 }
981
982 #if DEBUG_CHECK
983 fprintf(stderr, "found\n");
984 #endif
985
986 return 1;
987 }
988
989 /*-----------------------------------------------------------------*
990 * void pic16_groupRegistersInSection - add each register to its *
991 * corresponding section *
992 *-----------------------------------------------------------------*/
pic16_groupRegistersInSection(set * regset)993 void pic16_groupRegistersInSection(set *regset)
994 {
995 reg_info *reg;
996 sectSym *ssym;
997 int docontinue=0;
998
999 for(reg=setFirstItem(regset); reg; reg = setNextItem(regset)) {
1000
1001 #if 0
1002 fprintf(stderr, "%s:%d group registers in section, reg: %s (used: %d, %p)\n",
1003 __FILE__, __LINE__, reg->name, reg->wasUsed, reg);
1004 #endif
1005 if((reg->wasUsed
1006 && !(reg->regop && SPEC_EXTR(OP_SYM_ETYPE(reg->regop))))
1007 ) {
1008
1009 /* avoid grouping registers that have an initial value,
1010 * they will be added later in idataSymSet */
1011 if(reg->regop && (OP_SYMBOL(reg->regop)->ival && !OP_SYMBOL(reg->regop)->level))
1012 continue;
1013
1014 #if 0
1015 fprintf(stderr, "%s:%d register %s alias:%d fix:%d ival=%i level=%i code=%i\n",
1016 __FILE__, __LINE__, reg->name, reg->alias, reg->isFixed,
1017 (reg->regop?(OP_SYMBOL(reg->regop)->ival?1:0):-1),
1018 (reg->regop?(OP_SYMBOL(reg->regop)->level):-1),
1019 (reg->regop?(IS_CODE(OP_SYM_ETYPE(reg->regop))):-1) );
1020 #endif
1021
1022 docontinue=0;
1023 for(ssym=setFirstItem(sectSyms);ssym;ssym=setNextItem(sectSyms)) {
1024 if(!strcmp(ssym->name, reg->name)) {
1025 // fprintf(stderr, "%s:%d section found %s (%p) with var %s\n",
1026 // __FILE__, __LINE__, ssym->section->name, ssym->section, ssym->name);
1027 if(strcmp(ssym->section->name, "access")) {
1028 addSet(&ssym->section->regsSet, reg);
1029 docontinue=1;
1030 break;
1031 } else {
1032 docontinue=0;
1033 reg->accessBank = 1;
1034 break;
1035 }
1036 }
1037 }
1038
1039 if(docontinue)continue;
1040
1041 // fprintf(stderr, "%s:%d reg: %s\n", __FILE__, __LINE__, reg->name);
1042
1043 if(reg->alias == 0x80) {
1044 checkAddReg(&pic16_equ_data, reg);
1045 } else
1046 if(reg->isFixed) {
1047 checkAddReg(&pic16_fix_udata, reg);
1048 } else
1049 if(!reg->isFixed) {
1050 if(reg->pc_type == PO_GPR_TEMP)
1051 checkAddReg(&pic16_int_regs, reg);
1052 else {
1053 if(reg->accessBank) {
1054 if(reg->alias != 0x40)
1055 checkAddReg(&pic16_acs_udata, reg);
1056 } else
1057 checkAddReg(&pic16_rel_udata, reg);
1058 }
1059 }
1060 }
1061 }
1062 }
1063
1064
1065 /*-----------------------------------------------------------------*
1066 * void pic16_assignConfigWordValue(int address, int value)
1067 *
1068 * All high performance RISC CPU PICs have seven config word starting
1069 * at address 0x300000.
1070 * This routine will assign a value to that address.
1071 *
1072 *-----------------------------------------------------------------*/
1073 void
pic16_assignConfigWordValue(int address,unsigned int value)1074 pic16_assignConfigWordValue(int address, unsigned int value)
1075 {
1076 int i;
1077
1078 for (i = 0; i < pic16->cwInfo.confAddrEnd - pic16->cwInfo.confAddrStart + 1; i++)
1079 {
1080 if ((address == pic16->cwInfo.confAddrStart + i)
1081 && (pic16->cwInfo.crInfo[i].mask != -1)
1082 && (pic16->cwInfo.crInfo[i].mask != 0))
1083 {
1084
1085 #if 0
1086 fprintf(stderr, "setting location 0x%x to value 0x%x, mask: 0x%x, test: 0x%x\n",
1087 pic16->cwInfo.confAddrStart + i,
1088 (~value) & 0xff,
1089 pic16->cwInfo.crInfo[i].mask,
1090 (pic16->cwInfo.crInfo[i].mask) & (~value));
1091 #endif
1092
1093 #if 0
1094 if ((((pic16->cwInfo.crInfo[i].mask) & (~value)) & 0xff) != ((~value) & 0xff))
1095 {
1096 fprintf(stderr, "%s:%d a wrong value has been given for configuration register 0x%x\n",
1097 __FILE__, __LINE__, address);
1098 return;
1099 } // if
1100 #endif
1101
1102 pic16->cwInfo.crInfo[i].value = (value & 0xff);
1103 if (pic16->cwInfo.crInfo[i].andmask
1104 && ((value & 0xff) != (value & 0xff & pic16->cwInfo.crInfo[i].andmask)))
1105 {
1106 // apply andmask if effective
1107 printf ("INFO: changing configuration word at 0x%x from 0x%x to 0x%x due to %s\n",
1108 address,
1109 (value & 0xff),
1110 (value & 0xff & pic16->cwInfo.crInfo[i].andmask),
1111 DEVICE_FILE_NAME);
1112 pic16->cwInfo.crInfo[i].value &= pic16->cwInfo.crInfo[i].andmask;
1113 } // if
1114 pic16->cwInfo.crInfo[i].emit = 1;
1115 return;
1116 } // if
1117 } // for
1118 }
1119
1120 void
pic16_assignIdByteValue(int address,char value)1121 pic16_assignIdByteValue(int address, char value)
1122 {
1123 int i;
1124
1125 for (i = 0; i < pic16->idInfo.idAddrEnd - pic16->idInfo.idAddrStart + 1; i++)
1126 {
1127 if (address == pic16->idInfo.idAddrStart + i)
1128 {
1129 pic16->idInfo.irInfo[i].value = value;
1130 pic16->idInfo.irInfo[i].emit = 1;
1131 } // if
1132 } // for
1133 }
1134