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