Imported Upstream version 2.9.0
[debian/cc1111] / 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     {
556       return (line);
557     } // if
558
559   while (0 != (c = *l))
560     {
561       if ('#' == c)
562         {
563           *l = 0;
564           return (line);
565         } // if
566       l++;
567     } // while
568
569   return (line);
570 }
571
572 /**
573  * Report errors in the device specification.
574  *
575  * @param   msg
576  *      a pointer to the detailed message
577  */
578 #define SYNTAX(msg) do {                                \
579     fprintf(stderr, "%s:%d: Syntax error: %s\n",        \
580             DEVICE_FILE_NAME, lineno, msg);             \
581 } while (0)
582
583 /**
584  * Locate and read in the device specification (if required) and
585  * return the device structure for the named device.
586  *
587  * @param   name
588  *      a pointer to the name of the desired device
589  * @return
590  *      a pointer to the device structure, or NULL
591  */
592 static PIC16_device *
593 pic16_find_device(const char *name)
594 {
595   const char *path;
596   char buffer[PATH_MAX];
597   char *line, *key;
598   const char *sep = " \t\n\r";
599   FILE *f = NULL;
600   PIC16_device *d = NULL, *template;
601   PIC16_device *head = NULL, *tail = NULL;
602   set *_sets[] = { userIncDirsSet, includeDirsSet };
603   set **sets = &_sets[0];
604   int lineno = 0;
605   int res, i;
606   int val[4];
607
608   if (!devices)
609     {
610       //printf("%s: searching %s\n", __func__, DEVICE_FILE_NAME);
611
612       // locate the specification file in the include search paths
613       for (i = 0; (NULL == f) && (i < 2); i++)
614         {
615           for (path = setFirstItem(sets[i]);
616                (NULL == f) && path;
617                path = setNextItem(sets[i]))
618             {
619               SNPRINTF(&buffer[0], PATH_MAX, "%s%s%s",
620                        path, DIR_SEPARATOR_STRING, DEVICE_FILE_NAME);
621               //printf("%s: checking %s\n", __func__, &buffer[0]);
622               f = fopen(&buffer[0], "r");
623             } // for
624         } // for
625     } // if
626
627   if (devices)
628     {
629       // list already set up, nothing to do
630     }
631   else if (NULL == f)
632     {
633       fprintf(stderr, "ERROR: device list %s not found, specify its path via -I<path>\n",
634               DEVICE_FILE_NAME);
635       d = &default_device;
636     }
637   else
638     {
639       // parse the specification file and construct a linked list of
640       // supported devices
641       d = NULL;
642       while (NULL != (line = get_line(f)))
643         {
644           strip_comment(line);
645           //printf("%s: read %s\n", __func__, line);
646           lineno++;
647           key = strtok(line, sep);
648           if (!key)
649             {
650               // empty line---ignore
651             }
652           else if (0 == strcmp(key, "name"))
653             {
654               // name %<name>s
655               if (d)
656                 {
657                   if (tail)
658                     {
659                       tail->next = d;
660                     }
661                   else
662                     {
663                       head = d;
664                     } // if
665                   tail = d;
666                   d = NULL;
667                 } // if
668
669               res = sscanf(&line[1 + strlen(key)], " %16s", &buffer[3]);
670               if ((1 < res) || (3 > strlen(&buffer[3])))
671                 {
672                   SYNTAX("<name> (e.g., 18f452) expected.");
673                 }
674               else
675                 {
676                   d = Safe_calloc(1, sizeof(PIC16_device));
677
678                   // { "p18f452", "18f452", "pic18f452", "f452" }
679                   buffer[0] = 'p';
680                   buffer[1] = 'i';
681                   buffer[2] = 'c';
682                   d->name[3] = Safe_strdup(&buffer[5]);
683                   d->name[2] = Safe_strdup(&buffer[0]);
684                   d->name[1] = Safe_strdup(&buffer[3]);
685                   buffer[2] = 'p';
686                   d->name[0] = Safe_strdup(&buffer[2]);
687                 } // if
688             }
689           else if (0 == strcmp(key, "using"))
690             {
691               // using %<name>s
692               res = sscanf(&line[1 + strlen(key)], " %16s", &buffer[0]);
693               if ((1 < res) || (3 > strlen(&buffer[3])))
694                 {
695                   SYNTAX("<name> (e.g., 18f452) expected.");
696                 }
697               else
698                 {
699                   template = find_in_list(&buffer[0], head);
700                   if (!template)
701                     {
702                       SYNTAX("<name> (e.g., 18f452) expected.");
703                     }
704                   else
705                     {
706                       memcpy(&d->RAMsize, &template->RAMsize,
707                              ((char *)&d->next) - ((char *)&d->RAMsize));
708                     } // if
709                 } // if
710             }
711           else if (0 == strcmp(key, "ramsize"))
712             {
713               // ramsize %<bytes>i
714               res = sscanf(&line[1 + strlen(key)], " %i", &val[0]);
715               if (res < 1)
716                 {
717                   SYNTAX("<bytes> (e.g., 256) expected.");
718                 }
719               else
720                 {
721                   d->RAMsize = val[0];
722                 } // if
723             }
724           else if (0 == strcmp(key, "split"))
725             {
726               // split %<offset>i
727               res = sscanf(&line[1 + strlen(key)], " %i", &val[0]);
728               if (res < 1)
729                 {
730                   SYNTAX("<offset> (e.g., 0x80) expected.");
731                 }
732               else
733                 {
734                   d->acsSplitOfs = val[0];
735                 } // if
736             }
737           else if (0 == strcmp(key, "configrange"))
738             {
739               // configrange %<first>i %<last>i
740               res = sscanf(&line[1 + strlen(key)], " %i %i",
741                            &val[0], &val[1]);
742               if (res < 2)
743                 {
744                   SYNTAX("<first> <last> (e.g., 0xf60 0xfff) expected.");
745                 }
746               else
747                 {
748                   d->cwInfo.confAddrStart = val[0];
749                   d->cwInfo.confAddrEnd = val[1];
750                 } // if
751             }
752           else if (0 == strcmp(key, "configword"))
753             {
754               // configword %<address>i %<mask>i %<value>i [%<and-mask>i]
755               res = sscanf(&line[1 + strlen(key)], " %i %i %i %i",
756                            &val[0], &val[1], &val[2], &val[3]);
757               if (res < 3)
758                 {
759                   SYNTAX("<address> <mask> <value> [<and-mask>] (e.g., 0x200001 0x0f 0x07) expected.");
760                 }
761               else
762                 {
763                   val[0] -= d->cwInfo.confAddrStart;
764                   if ((val[0] < 0)
765                       || (val[0] > (d->cwInfo.confAddrEnd - d->cwInfo.confAddrStart))
766                       || (val[0] >= CONFIGURATION_WORDS))
767                     {
768                       SYNTAX("address out of bounds.");
769                     }
770                   else
771                     {
772                       d->cwInfo.crInfo[val[0]].mask = val[1];
773                       d->cwInfo.crInfo[val[0]].value = val[2];
774                       d->cwInfo.crInfo[val[0]].andmask = 0;
775                       if (res >= 4)
776                         {
777                           // apply extra mask (e.g., to disable XINST)
778                           d->cwInfo.crInfo[val[0]].andmask = val[3];
779                         } // if
780                     } // if
781                 } // if
782             }
783           else if (0 == strcmp(key, "idlocrange"))
784             {
785               // idlocrange %<first>i %<last>i
786               res = sscanf(&line[1 + strlen(key)], " %i %i",
787                            &val[0], &val[1]);
788               if (res < 2)
789                 {
790                   SYNTAX("<first> <last> (e.g., 0xf60 0xfff) expected.");
791                 }
792               else
793                 {
794                   d->idInfo.idAddrStart = val[0];
795                   d->idInfo.idAddrEnd = val[1];
796                 } // if
797             }
798           else if (0 == strcmp(key, "idword"))
799             {
800               // idword %<address>i %<value>i
801               res = sscanf(&line[1 + strlen(key)], " %i %i",
802                            &val[0], &val[1]);
803               if (res < 2)
804                 {
805                   SYNTAX("<address> <value> (e.g., 0x3fffff 0x00) expected.");
806                 }
807               else
808                 {
809                   val[0] -= d->idInfo.idAddrStart;
810                   if ((val[0] < 0)
811                       || (val[0] > (d->idInfo.idAddrEnd - d->idInfo.idAddrStart))
812                       || (val[0] >= IDLOCATION_BYTES))
813                     {
814                       SYNTAX("address out of bounds.");
815                     }
816                   else
817                     {
818                       d->idInfo.irInfo[val[0]].value = val[1];
819                     } // if
820                 } // if
821             }
822           else
823             {
824               printf("%s: Invalid keyword in %s ignored: %s\n",
825                      __func__, DEVICE_FILE_NAME, key);
826             } // if
827         } // while
828
829       if (d)
830         {
831           if (tail)
832             {
833               tail->next = d;
834             }
835           else
836             {
837               head = d;
838             } // if
839           tail = d;
840           d = NULL;
841         } // if
842
843       devices = head;
844
845       fclose(f);
846     } // if
847
848   d = find_in_list(name, devices);
849   if (!d)
850     {
851       d = &default_device;
852     } // if
853
854   return (d);
855 }
856
857 /*-----------------------------------------------------------------*
858  *
859  *-----------------------------------------------------------------*/
860 void pic16_init_pic(const char *pic_type)
861 {
862     pic16 = pic16_find_device(pic_type);
863
864     if (&default_device == pic16) {
865         if (pic_type) {
866             fprintf(stderr, "'%s' was not found.\n", pic_type);
867         } else {
868             fprintf(stderr, "No processor has been specified (use -pPROCESSOR_NAME)\n");
869         } // if
870
871         if (devices) {
872             fprintf(stderr,"Valid devices are (use --verbose for more details):\n");
873             pic16_list_devices(devices);
874         } // if
875         exit(EXIT_FAILURE);
876     } // if
877 }
878
879 /*-----------------------------------------------------------------*
880  *  char *pic16_processor_base_name(void) - Include file is derived from this.
881  *-----------------------------------------------------------------*/
882 char *pic16_processor_base_name(void)
883 {
884
885   if(!pic16)
886     return NULL;
887
888   return pic16->name[0];
889 }
890
891 #define DEBUG_CHECK     0
892
893 /*
894  * return 1 if register wasn't found and added, 0 otherwise
895  */
896 int checkAddReg(set **set, regs *reg)
897 {
898   regs *tmp;
899
900
901         if(!reg)return 0;
902 #if DEBUG_CHECK
903         fprintf(stderr, "%s: about to insert REGister: %s ... ", __FUNCTION__, reg->name);
904 #endif
905
906         for(tmp = setFirstItem(*set); tmp; tmp = setNextItem(*set)) {
907                 if(!strcmp(tmp->name, reg->name))break;
908         }
909
910         if(!tmp) {
911                 addSet(set, reg);
912 #if DEBUG_CHECK
913                 fprintf(stderr, "added\n");
914 #endif
915                 return 1;
916         }
917
918 #if DEBUG_CHECK
919         fprintf(stderr, "already added\n");
920 #endif
921   return 0;
922 }
923
924 int checkAddSym(set **set, symbol *sym)
925 {
926   symbol *tmp;
927
928         if(!sym)return 0;
929 #if DEBUG_CHECK
930         fprintf(stderr, "%s: about to add SYMbol: %s ... ", __FUNCTION__, sym->name);
931 #endif
932
933         for(tmp = setFirstItem( *set ); tmp; tmp = setNextItem(*set)) {
934                 if(!strcmp(tmp->name, sym->name))break;
935         }
936
937         if(!tmp) {
938                 addSet(set, sym);
939 #if DEBUG_CHECK
940                 fprintf(stderr, "added\n");
941 #endif
942                 return 1;
943         }
944
945 #if DEBUG_CHECK
946         fprintf(stderr, "already added\n");
947 #endif
948
949   return 0;
950 }
951
952 int checkSym(set *set, symbol *sym)
953 {
954   symbol *tmp;
955
956         if(!sym)return 0;
957
958 #if DEUG_CHECK
959         fprintf(stderr, "%s: about to search for SYMbol: %s ... ", __FUNCTION__, sym->name);
960 #endif
961
962         for(tmp = setFirstItem( set ); tmp; tmp = setNextItem( set )) {
963                 if(!strcmp(tmp->name, sym->name))break;
964         }
965
966         if(!tmp) {
967 #if DEBUG_CHECK
968                 fprintf(stderr, "not found\n");
969 #endif
970                 return 0;
971         }
972
973 #if DEBUG_CHECK
974         fprintf(stderr, "found\n");
975 #endif
976
977   return 1;
978 }
979
980 /*-----------------------------------------------------------------*
981  * void pic16_groupRegistersInSection - add each register to its   *
982  *      corresponding section                                      *
983  *-----------------------------------------------------------------*/
984 void pic16_groupRegistersInSection(set *regset)
985 {
986   regs *reg;
987   sectSym *ssym;
988   int docontinue=0;
989
990         for(reg=setFirstItem(regset); reg; reg = setNextItem(regset)) {
991
992 #if 0
993                 fprintf(stderr, "%s:%d group registers in section, reg: %s (used: %d, %p)\n",
994                         __FILE__, __LINE__, reg->name, reg->wasUsed, reg);
995 #endif
996                 if((reg->wasUsed
997                         && !(reg->regop && SPEC_EXTR(OP_SYM_ETYPE(reg->regop))))
998                   ) {
999
1000                         /* avoid grouping registers that have an initial value,
1001                          * they will be added later in idataSymSet */
1002                         if(reg->regop && (OP_SYMBOL(reg->regop)->ival && !OP_SYMBOL(reg->regop)->level))
1003                                 continue;
1004
1005 #if 0
1006                         fprintf(stderr, "%s:%d register %s alias:%d fix:%d ival=%i level=%i code=%i\n",
1007                                 __FILE__, __LINE__, reg->name, reg->alias, reg->isFixed,
1008                                         (reg->regop?(OP_SYMBOL(reg->regop)->ival?1:0):-1),
1009                                         (reg->regop?(OP_SYMBOL(reg->regop)->level):-1),
1010                                         (reg->regop?(IS_CODE(OP_SYM_ETYPE(reg->regop))):-1) );
1011 #endif
1012
1013                         docontinue=0;
1014                         for(ssym=setFirstItem(sectSyms);ssym;ssym=setNextItem(sectSyms)) {
1015                                 if(!strcmp(ssym->name, reg->name)) {
1016 //                                      fprintf(stderr, "%s:%d section found %s (%p) with var %s\n",
1017 //                                                      __FILE__, __LINE__, ssym->section->name, ssym->section, ssym->name);
1018                                         if(strcmp(ssym->section->name, "access")) {
1019                                                 addSet(&ssym->section->regsSet, reg);
1020                                                 docontinue=1;
1021                                                 break;
1022                                         } else {
1023                                                 docontinue=0;
1024                                                 reg->accessBank = 1;
1025                                                 break;
1026                                         }
1027                                 }
1028                         }
1029
1030                         if(docontinue)continue;
1031
1032 //                      fprintf(stderr, "%s:%d reg: %s\n", __FILE__, __LINE__, reg->name);
1033
1034                         if(reg->alias == 0x80) {
1035                                 checkAddReg(&pic16_equ_data, reg);
1036                         } else
1037                         if(reg->isFixed) {
1038                                 checkAddReg(&pic16_fix_udata, reg);
1039                         } else
1040                         if(!reg->isFixed) {
1041                                 if(reg->pc_type == PO_GPR_TEMP)
1042                                         checkAddReg(&pic16_int_regs, reg);
1043                                 else {
1044                                         if(reg->accessBank) {
1045                                                 if(reg->alias != 0x40)
1046                                                         checkAddReg(&pic16_acs_udata, reg);
1047                                         } else
1048                                                 checkAddReg(&pic16_rel_udata, reg);
1049                                 }
1050                         }
1051                 }
1052         }
1053 }
1054
1055
1056
1057
1058
1059 /*-----------------------------------------------------------------*
1060  *  void pic16_assignConfigWordValue(int address, int value)
1061  *
1062  * All high performance RISC CPU PICs have seven config word starting
1063  * at address 0x300000.
1064  * This routine will assign a value to that address.
1065  *
1066  *-----------------------------------------------------------------*/
1067 void
1068 pic16_assignConfigWordValue(int address, unsigned int value)
1069 {
1070   int i;
1071
1072   for (i = 0; i < pic16->cwInfo.confAddrEnd - pic16->cwInfo.confAddrStart + 1; i++)
1073     {
1074       if ((address == pic16->cwInfo.confAddrStart + i)
1075           && (pic16->cwInfo.crInfo[i].mask != -1)
1076           && (pic16->cwInfo.crInfo[i].mask != 0))
1077         {
1078
1079 #if 0
1080           fprintf(stderr, "setting location 0x%x to value 0x%x, mask: 0x%x, test: 0x%x\n",
1081                   pic16->cwInfo.confAddrStart + i,
1082                   (~value) & 0xff,
1083                   pic16->cwInfo.crInfo[i].mask,
1084                   (pic16->cwInfo.crInfo[i].mask) & (~value));
1085 #endif
1086
1087 #if 0
1088           if ((((pic16->cwInfo.crInfo[i].mask) & (~value)) & 0xff) != ((~value) & 0xff))
1089             {
1090               fprintf(stderr, "%s:%d a wrong value has been given for configuration register 0x%x\n",
1091                       __FILE__, __LINE__, address);
1092               return;
1093             } // if
1094 #endif
1095
1096           pic16->cwInfo.crInfo[i].value = (value & 0xff);
1097           if (pic16->cwInfo.crInfo[i].andmask
1098               && ((value & 0xff) != (value & 0xff & pic16->cwInfo.crInfo[i].andmask)))
1099             {
1100               // apply andmask if effective
1101               printf ("INFO: changing configuration word at 0x%x from 0x%x to 0x%x due to %s\n",
1102                       address,
1103                       (value & 0xff),
1104                       (value & 0xff & pic16->cwInfo.crInfo[i].andmask),
1105                       DEVICE_FILE_NAME);
1106               pic16->cwInfo.crInfo[i].value &= pic16->cwInfo.crInfo[i].andmask;
1107             } // if
1108           pic16->cwInfo.crInfo[i].emit = 1;
1109           return;
1110         } // if
1111     } // for
1112 }
1113
1114 void
1115 pic16_assignIdByteValue(int address, char value)
1116 {
1117   int i;
1118
1119   for (i = 0; i < pic16->idInfo.idAddrEnd - pic16->idInfo.idAddrStart + 1; i++)
1120     {
1121       if (address == pic16->idInfo.idAddrStart + i)
1122         {
1123           pic16->idInfo.irInfo[i].value = value;
1124           pic16->idInfo.irInfo[i].emit = 1;
1125         } // if
1126     } // for
1127 }
1128