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