Now reports memory usage using the value from option --iram-size.
[fw/sdcc] / as / mcs51 / lklist.c
1 /* lklist.c */
2
3 /*
4  * (C) Copyright 1989-1995
5  * All Rights Reserved
6  *
7  * Alan R. Baldwin
8  * 721 Berkeley St.
9  * Kent, Ohio  44240
10  *
11  * 28-Oct-97 JLH: 
12  *           - lstarea: show s_id as string rather than array [NCPS]
13  *           - lstarea: show a_id as string rather than array [NCPS]
14  * 31-Oct-97 JLH: add NoICE output file genration in lstarea
15  * 02-Apr-98 JLH: add XDATA, DATA, BIT flags to area output
16  */
17
18 #include <stdio.h>
19 #include <string.h>
20 #include <stdlib.h>
21 #include "aslink.h"
22
23 /*)Module       lklist.c
24  *
25  *      The module lklist.c contains the functions which
26  *      output the linker .map file and produce a relocated
27  *      listing .rst file.
28  *
29  *      lklist.c contains the following functions:
30  *              int     dgt()
31  *              VOID    lstarea()
32  *              VOID    lkulist()
33  *              VOID    lkalist()
34  *              VOID    lkglist()
35  *              VOID    newpag()
36  *              VOID    slew()
37  *
38  *      lklist.c contains no local variables.
39  */
40
41 /*)Function     VOID    slew(fp)
42  *
43  *              FILE *  fp              output file handle
44  *
45  *      The function slew() increments the page line counter.
46  *      If the number of lines exceeds the maximum number of
47  *      lines per page then a page skip and a page header are
48  *      output.
49  *
50  *      local variables:
51  *              int     i               loop counter
52  *
53  *      global variables:
54  *              int     lop             current line number on page
55  *              int     xflag           Map file radix type flag
56  *
57  *      functions called:
58  *              int     fprintf()       c_library
59  *              VOID    newpag()        lklist.c
60  *
61  *      side effects:
62  *              The page line and the page count may be updated.
63  */
64
65 VOID
66 slew(fp)
67 FILE *fp;
68 {
69         register int i;
70
71         if (lop++ >= NLPP) {
72                 newpag(fp);
73                 if (xflag == 0) {
74                         fprintf(fp, "Hexadecimal\n\n");
75                 } else
76                 if (xflag == 1) {
77                         fprintf(fp, "Octal\n\n");
78                 } else
79                 if (xflag == 2) {
80                         fprintf(fp, "Decimal\n\n");
81                 }
82                 fprintf(fp, "Area       Addr   Size");
83                 fprintf(fp, "   Decimal Bytes (Attributes)\n");
84                 for(i=0;i<4;++i)
85                         fprintf(fp, "      Value--Global");
86                 fprintf(fp, "\n\n");
87                 lop += 6;
88         }
89 }
90
91 /*)Function     VOID    newpag()
92  *
93  *      The function newpag() outputs a page skip, writes the
94  *      first page header line, sets the line count to 1, and
95  *      increments the page counter.
96  *
97  *      local variables:
98  *              none
99  *
100  *      global variables:
101  *              int     lop             current line number on page
102  *              int     page            current page number
103  *
104  *      functions called:
105  *              int     fprintf()       c_library
106  *
107  *      side effects:
108  *              The page and line counters are updated.
109  */
110
111 VOID
112 newpag(fp)
113 FILE *fp;
114 {
115         fprintf(fp, "\fASxxxx Linker %s,  page %u.\n", VERSION, ++page);
116         lop = 1;
117 }
118
119 /* Used for qsort call in lstsym */
120 static int _cmpSymByAddr(const void *p1, const void *p2)
121 {
122     struct sym **s1 = (struct sym **)(p1);
123     struct sym **s2 = (struct sym **)(p2);
124     int delta = ((*s1)->s_addr + (*s1)->s_axp->a_addr) -
125                 ((*s2)->s_addr + (*s2)->s_axp->a_addr);
126
127     /* Sort first by address, then by name. */
128     if (delta)
129     {
130         return delta;
131     }
132     return strcmp((*s1)->s_id,(*s2)->s_id);    
133 }
134
135
136 #if     NCPS-8
137
138 /* NCPS != 8 */
139 /*)Function     VOID    lstarea(xp)
140  *
141  *              area *  xp              pointer to an area structure
142  *
143  *      The function lstarea() creates the linker map output for
144  *      the area specified by pointer xp.  The generated output
145  *      area header includes the area name, starting address,
146  *      size of area, number of words (in decimal), and the
147  *      area attributes.  The symbols defined in this area are
148  *      sorted by ascending address and output one per line
149  *      in the selected radix.
150  *
151  *      local variables:
152  *              areax * oxp             pointer to an area extension structure
153  *              int     c               character value
154  *              int     i               loop counter
155  *              int     j               bubble sort update status
156  *              char *  ptr             pointer to an id string
157  *              int     nmsym           number of symbols in area
158  *              Addr_T  a0              temporary
159  *              Addr_T  ai              temporary
160  *              Addr_T  aj              temporary
161  *              sym *   sp              pointer to a symbol structure
162  *              sym **  p               pointer to an array of
163  *                                      pointers to symbol structures
164  *
165  *      global variables:
166  *              FILE    *mfp            Map output file handle
167  *              sym *symhash[NHASH]     array of pointers to NHASH
168  *                                      linked symbol lists
169  *              int     xflag           Map file radix type flag
170  *
171  *      functions called:
172  *              int     fprintf()       c_library
173  *              VOID    free()          c_library
174  *              char *  malloc()        c_library
175  *              char    putc()          c_library
176  *              VOID    slew()          lklist.c
177  *
178  *      side effects:
179  *              Map output generated.
180  */
181
182 VOID
183 lstarea(xp)
184 struct area *xp;
185 {
186         register struct areax *oxp;
187         register int i;
188         /* int j; */
189         register char *ptr;
190         int nmsym;
191         /* Addr_T a0; */
192         Addr_T     ai, aj;
193         struct sym *sp;
194         struct sym **p;
195         int memPage;
196
197         putc('\n', mfp);
198         if (xflag == 0) {
199                 fprintf(mfp, "Hexadecimal\n\n");
200         } else
201         if (xflag == 1) {
202                 fprintf(mfp, "Octal\n\n");
203         } else
204         if (xflag == 2) {
205                 fprintf(mfp, "Decimal\n\n");
206         }
207         fprintf(mfp, "Area                               ");
208         fprintf(mfp, "Addr   Size   Decimal %s (Attributes)\n",
209                 (xp->a_flag & A_BIT)?"Bits ":"Bytes");/* JCF: For BIT print bits...*/
210         fprintf(mfp, "--------------------------------   ");
211         fprintf(mfp, "----   ----   ------- ----- ------------\n");
212         /*
213          * Output Area Header
214          */
215         ptr = &xp->a_id[0];
216         fprintf(mfp, "%-32s", ptr );    /* JLH: width matches --- above */
217         ai = xp->a_addr;
218         aj = xp->a_size;
219         if (xflag == 0) {
220                 fprintf(mfp, "   %04X   %04X", ai, aj);
221         } else
222         if (xflag == 1) {
223                 fprintf(mfp, " %06o %06o", ai, aj);
224         } else
225         if (xflag == 2) {
226                 fprintf(mfp, "  %05u  %05u", ai, aj);
227         }
228         fprintf(mfp, " = %6u. %s ", aj,
229                 (xp->a_flag & A_BIT)?"bits ":"bytes"); /* JCF: For BIT print bits...*/
230         if (xp->a_flag & A_ABS) {
231                 fprintf(mfp, "(ABS");
232         } else {
233                 fprintf(mfp, "(REL");
234         }
235         if (xp->a_flag & A_OVR) {
236                 fprintf(mfp, ",OVR");
237         } else {
238                 fprintf(mfp, ",CON");
239         }
240         if (xp->a_flag & A_PAG) {
241                 fprintf(mfp, ",PAG");
242         }
243
244         memPage = 0x00;
245         if (xp->a_flag & A_CODE) {
246                 fprintf(mfp, ",CODE");
247                 memPage = 0x0C;
248         }
249         if (xp->a_flag & A_XDATA) {
250                 fprintf(mfp, ",XDATA");
251                 memPage = 0x0D;
252         }
253         if (xp->a_flag & A_BIT) {
254                 fprintf(mfp, ",BIT");
255                 memPage = 0x0B;
256         }
257         fprintf(mfp, ")");
258         if (xp->a_flag & A_PAG) {
259                 ai = (ai & 0xFF);
260                 aj = (aj > 256);
261                 if (ai || aj) { fprintf(mfp, "  "); }
262                 if (ai)      { fprintf(mfp, " Boundary"); }
263                 if (ai & aj)  { fprintf(mfp, " /"); }
264                 if (aj)      { fprintf(mfp, " Length"); }
265                 if (ai || aj) { fprintf(mfp, " Error"); }
266         }
267
268         /*
269          * Find number of symbols in area
270          */
271         nmsym = 0;
272         oxp = xp->a_axp;
273         while (oxp) {
274                 for (i=0; i<NHASH; i++) {
275                         sp = symhash[i];
276                         while (sp != NULL) {
277                                 if (oxp == sp->s_axp)
278                                         ++nmsym;
279                                 sp = sp->s_sp;
280                         }
281                 }
282                 oxp = oxp->a_axp;
283         }
284         if (nmsym == 0) {
285                 putc('\n', mfp);
286                 return;
287         }
288
289         /*
290          * Allocate space for an array of pointers to symbols
291          * and load array.
292          */
293         if ( (p = (struct sym **) malloc(nmsym*sizeof(struct sym *)))
294                 == NULL) {
295                 fprintf(mfp, "\nInsufficient space to build Map Segment.\n");
296                 return;
297         }
298         nmsym = 0;
299         oxp = xp->a_axp;
300         while (oxp) {
301                 for (i=0; i<NHASH; i++) {
302                         sp = symhash[i];
303                         while (sp != NULL) {
304                                 if (oxp == sp->s_axp) {
305                                         p[nmsym++] = sp;
306                                 }
307                                 sp = sp->s_sp;
308                         }
309                 }
310                 oxp = oxp->a_axp;
311         }
312
313 #if 0
314         /*
315          * Bubble Sort of Addresses in Symbol Table Array
316          */
317         j = 1;
318         while (j) {
319                 j = 0;
320                 sp = p[0];
321                 a0 = sp->s_addr + sp->s_axp->a_addr;
322                 for (i=1; i<nmsym; ++i) {
323                         sp = p[i];
324                         ai = sp->s_addr + sp->s_axp->a_addr;
325                         if (a0 > ai) {
326                                 j = 1;
327                                 p[i] = p[i-1];
328                                 p[i-1] = sp;
329                         }
330                         a0 = ai;
331                 }
332         }
333 #else
334         qsort(p, nmsym, sizeof(struct sym *), _cmpSymByAddr);
335 #endif  
336
337         /*
338          * Symbol Table Output
339          */
340
341         i = 0;
342         fprintf(mfp, "\n\n");
343         fprintf(mfp, "      Value  Global\n");
344         fprintf(mfp, "   --------  --------------------------------");
345         while (i < nmsym) {
346                 fprintf(mfp, "\n");
347                 if (memPage != 0) 
348                         fprintf(mfp, "  %02X:", memPage);
349                 else
350                         fprintf(mfp, "     ");
351
352                 sp = p[i];
353                 aj = sp->s_addr + sp->s_axp->a_addr;
354                 if (xflag == 0) {
355                         fprintf(mfp, "%04X    ", aj);
356                 } else
357                 if (xflag == 1) {
358                         fprintf(mfp, "%06o  ", aj);
359                 } else
360                 if (xflag == 2) {
361                         fprintf(mfp, "%05u   ", aj);
362                 }
363                 ptr = &sp->s_id[0];
364                 fprintf(mfp, "%s", ptr );
365                 
366                 /* if cdb flag set the output cdb Information 
367                    and the symbol has a '$' sign in it then */
368                 if (dflag &&
369                     strchr(ptr,'$'))
370                     fprintf(dfp,"L:%s:%X\n",ptr,aj);
371                 /* NoICE output of symbol */
372                 if (jflag) DefineNoICE( ptr, aj, memPage );
373
374                 i++;
375         }
376         putc('\n', mfp);
377         free(p);
378 }
379
380 #else
381
382 /* NCPS == 8 */
383 /*)Function     VOID    lstarea(xp)
384  *
385  *              area *  xp              pointer to an area structure
386  *
387  *      The function lstarea() creates the linker map output for
388  *      the area specified by pointer xp.  The generated output
389  *      area header includes the area name, starting address,
390  *      size of area, number of words (in decimal), and the
391  *      area attributes.  The symbols defined in this area are
392  *      sorted by ascending address and output four per line
393  *      in the selected radix.
394  *
395  *      local variables:
396  *              areax * oxp             pointer to an area extension structure
397  *              int     c               character value
398  *              int     i               loop counter
399  *              int     j               bubble sort update status
400  *              char *  ptr             pointer to an id string
401  *              int     nmsym           number of symbols in area
402  *              Addr_T  a0              temporary
403  *              Addr_T  ai              temporary
404  *              Addr_T  aj              temporary
405  *              sym *   sp              pointer to a symbol structure
406  *              sym **  p               pointer to an array of
407  *                                      pointers to symbol structures
408  *
409  *      global variables:
410  *              FILE    *mfp            Map output file handle
411  *              sym *symhash[NHASH]     array of pointers to NHASH
412  *                                      linked symbol lists
413  *              int     xflag           Map file radix type flag
414  *
415  *      functions called:
416  *              int     fprintf()       c_library
417  *              VOID    free()          c_library
418  *              char *  malloc()        c_library
419  *              char    putc()          c_library
420  *              VOID    slew()          lklist.c
421  *
422  *      side effects:
423  *              Map output generated.
424  */
425
426 VOID
427 lstarea(xp)
428 struct area *xp;
429 {
430         register struct areax *oxp;
431         register c, i, j;
432         register char *ptr;
433         int nmsym;
434         Addr_T a0, ai, aj;
435         struct sym *sp;
436         struct sym **p;
437         int page;
438
439         putc('\n', mfp);
440         slew(mfp);
441         /*
442          * Output Area Header
443          */
444         ptr = &xp->a_id[0];
445         while (ptr < &xp->a_id[NCPS]) {
446                 if ((c = *ptr++) != 0) {
447                         putc(c, mfp);
448                 } else {
449                         putc(' ', mfp);
450                 }
451         }
452         ai = xp->a_addr;
453         aj = xp->a_size;
454         if (xflag == 0) {
455                 fprintf(mfp, "   %04X   %04X", ai, aj);
456         } else
457         if (xflag == 1) {
458                 fprintf(mfp, " %06o %06o", ai, aj);
459         } else
460         if (xflag == 2) {
461                 fprintf(mfp, "  %05u  %05u", ai, aj);
462         }
463         fprintf(mfp, " = %6u. bytes ", aj);
464         if (xp->a_flag & A_ABS) {
465                 fprintf(mfp, "(ABS");
466         } else {
467                 fprintf(mfp, "(REL");
468         }
469         if (xp->a_flag & A_OVR) {
470                 fprintf(mfp, ",OVR");
471         } else {
472                 fprintf(mfp, ",CON");
473         }
474         if (xp->a_flag & A_PAG) {
475                 fprintf(mfp, ",PAG");
476         }
477
478         page = 0x00;
479         if (xp->a_flag & A_CODE) {
480                 fprintf(mfp, ",CODE");
481                 memPage = 0x0C;
482         }
483         if (xp->a_flag & A_XDATA) {
484                 fprintf(mfp, ",XDATA");
485                 memPage = 0x0D;
486         }
487         if (xp->a_flag & A_BIT) {
488                 fprintf(mfp, ",BIT");
489                 memPage = 0x0B;
490         }
491         fprintf(mfp, ")");
492         if (xp->a_flag & A_PAG) {
493                 ai = (ai & 0xFF);
494                 aj = (aj > 256);
495                 if (ai || aj) { fprintf(mfp, "  "); }
496                 if (ai)      { fprintf(mfp, " Boundary"); }
497                 if (ai & aj)  { fprintf(mfp, " /"); }
498                 if (aj)      { fprintf(mfp, " Length"); }
499                 if (ai || aj) { fprintf(mfp, " Error"); }
500         }
501
502         /*
503          * Find number of symbols in area
504          */
505         nmsym = 0;
506         oxp = xp->a_axp;
507         while (oxp) {
508                 for (i=0; i<NHASH; i++) {
509                         sp = symhash[i];
510                         while (sp != NULL) {
511                                 if (oxp == sp->s_axp)
512                                         ++nmsym;
513                                 sp = sp->s_sp;
514                         }
515                 }
516                 oxp = oxp->a_axp;
517         }
518         if (nmsym == 0) {
519                 putc('\n', mfp);
520                 slew(mfp);
521                 return;
522         }
523
524         /*
525          * Allocate space for an array of pointers to symbols
526          * and load array.
527          */
528         if ( (p = (struct sym **) malloc(nmsym*sizeof(struct sym *)))
529                 == NULL) {
530                 fprintf(mfp, "\nInsufficient space to build Map Segment.\n");
531                 slew(mfp);
532                 return;
533         }
534         nmsym = 0;
535         oxp = xp->a_axp;
536         while (oxp) {
537                 for (i=0; i<NHASH; i++) {
538                         sp = symhash[i];
539                         while (sp != NULL) {
540                                 if (oxp == sp->s_axp) {
541                                         p[nmsym++] = sp;
542                                 }
543                                 sp = sp->s_sp;
544                         }
545                 }
546                 oxp = oxp->a_axp;
547         }
548
549 #if 0
550         /*
551          * Bubble Sort of Addresses in Symbol Table Array
552          */
553         j = 1;
554         while (j) {
555                 j = 0;
556                 sp = p[0];
557                 a0 = sp->s_addr + sp->s_axp->a_addr;
558                 for (i=1; i<nmsym; ++i) {
559                         sp = p[i];
560                         ai = sp->s_addr + sp->s_axp->a_addr;
561                         if (a0 > ai) {
562                                 j = 1;
563                                 p[i] = p[i-1];
564                                 p[i-1] = sp;
565                         }
566                         a0 = ai;
567                 }
568         }
569 #else
570         qsort(p, nmsym, sizeof(struct sym *), _cmpSymByAddr);
571 #endif  
572
573         /*
574          * Symbol Table Output
575          */
576         i = 0;
577         while (i < nmsym) {
578                 fprintf(mfp, "\n");
579                 slew(mfp);
580                 fprintf(mfp, "     ");
581                 sp = p[i];
582                 aj = sp->s_addr + sp->s_axp->a_addr;
583                 if (xflag == 0) {
584                         fprintf(mfp, "  %04X  ", aj);
585                 } else
586                 if (xflag == 1) {
587                         fprintf(mfp, "%06o  ", aj);
588                 } else
589                 if (xflag == 2) {
590                         fprintf(mfp, " %05u  ", aj);
591                 }
592                 ptr = &sp->s_id[0];
593                 fprintf(mfp, "%s", ptr );
594
595                 /* NoICE output of symbol */
596                 if (jflag) DefineNoICE( ptr, aj, memPage );
597         }
598         putc('\n', mfp);
599         free(p);
600         slew(mfp);
601 }
602 #endif
603
604 /*)Function     VOID    lkulist(i)
605  *
606  *              int     i       i # 0   process LST to RST file
607  *                              i = 0   copy remainder of LST file
608  *                                      to RST file and close files
609  *
610  *      The function lkulist() creates a relocated listing (.rst)
611  *      output file from the ASxxxx assembler listing (.lst)
612  *      files.  The .lst file's program address and code bytes
613  *      are changed to reflect the changes made by ASlink as
614  *      the .rel files are combined into a single relocated
615  *      output file.
616  *
617  *      local variables:
618  *              Addr_T  pc              current program counter address
619  *
620  *      global variables:
621  *              int     hilo            byte order
622  *              int     gline           get a line from the LST file
623  *                                      to translate for the RST file
624  *              char    rb[]            read listing file text line
625  *              FILE    *rfp            The file handle to the current
626  *                                      output RST file
627  *              int     rtcnt           count of data words
628  *              int     rtflg[]         output the data flag
629  *              Addr_T  rtval[]         relocated data
630  *              FILE    *tfp            The file handle to the current
631  *                                      LST file being scanned
632  *
633  *      functions called:
634  *              int     fclose()        c_library
635  *              int     fgets()         c_library
636  *              int     fprintf()       c_library
637  *              VOID    lkalist()       lklist.c
638  *              VOID    lkglist()       lklist.c
639  *
640  *      side effects:
641  *              A .rst file is created for each available .lst
642  *              file associated with a .rel file.
643  */
644
645 VOID
646 lkulist(i)
647 int i;
648 {
649         Addr_T pc;
650
651         /*
652          * Exit if listing file is not open
653          */
654         if (tfp == NULL)
655                 return;
656
657         /*
658          * Normal processing of LST to RST
659          */
660         if (i) {
661                 /*
662                  * Evaluate current code address
663                  */
664                 if (hilo == 0) {
665                         pc = ((rtval[1] & 0xFF) << 8) + (rtval[0] & 0xFF);
666                 } else {
667                         pc = ((rtval[0] & 0xFF) << 8) + (rtval[1] & 0xFF);
668                 }
669
670                 /*
671                  * Line with only address
672                  */
673                 if (rtcnt == 2) {
674                         lkalist(pc);
675
676                 /*
677                  * Line with address and code
678                  */
679                 } else {
680                         for (i=2; i < rtcnt; i++) {
681                                 if (rtflg[i]) {
682                                         lkglist(pc++, rtval[i] & 0xFF);
683                                 }
684                         }
685                 }
686
687         /*
688          * Copy remainder of LST to RST
689          */
690         } else {
691                 if (gline == 0)
692                         fprintf(rfp, "%s", rb);
693
694                 while (fgets(rb, sizeof(rb), tfp) != 0) {
695                         fprintf(rfp, "%s", rb);
696                 }
697                 fclose(tfp);
698                 tfp = NULL;
699                 fclose(rfp);
700                 rfp = NULL;
701         }
702 }
703
704 /*)Function     VOID    lkalist(pc)
705  *
706  *              int     pc              current program counter value
707  *
708  *      The function lkalist() performs the following functions:
709  *
710  *      (1)     if the value of gline = 0 then the current listing
711  *              file line is copied to the relocated listing file output.
712  *
713  *      (2)     the listing file is read line by line and copied to
714  *              the relocated listing file until a valid source
715  *              line number and a program counter value of the correct
716  *              radix is found.  The new relocated pc value is substituted
717  *              and the line is written to the RST file.
718  *
719  *      local variables:
720  *              int     i               loop counter
721  *              char    str[]           temporary string
722  *
723  *      global variables:
724  *              int     gcntr           data byte counter
725  *              int     gline           get a line from the LST file
726  *                                      to translate for the RST file
727  *              char    rb[]            read listing file text line
728  *              char    *rp             pointer to listing file text line
729  *              FILE    *rfp            The file handle to the current
730  *                                      output RST file
731  *              FILE    *tfp            The file handle to the current
732  *                                      LST file being scanned
733  *
734  *      functions called:
735  *              int     dgt()           lklist.c
736  *              int     fclose()        c_library
737  *              int     fgets()         c_library
738  *              int     fprintf()       c_library
739  *              int     sprintf()       c_library
740  *              char *  strncpy()       c_library
741  *
742  *      side effects:
743  *              Lines of the LST file are copied to the RST file,
744  *              the last line copied has the code address
745  *              updated to reflect the program relocation.
746  */
747
748 VOID
749 lkalist(pc)
750 Addr_T pc;
751 {
752         char str[8];
753         int i;
754
755         /*
756          * Exit if listing file is not open
757          */
758 loop:   if (tfp == NULL)
759                 return;
760
761         /*
762          * Copy current LST to RST
763          */
764         if (gline == 0) {
765                 fprintf(rfp, "%s", rb);
766                 gline = 1;
767         }
768
769         /*
770          * Clear text line buffer
771          */
772         for (i=0,rp=rb; i<sizeof(rb); i++) {
773                 *rp++ = 0;
774         }
775
776         /*
777          * Get next LST text line
778          */
779         if (fgets(rb, sizeof(rb), tfp) == NULL) {
780                 fclose(tfp);
781                 tfp = NULL;
782                 fclose(rfp);
783                 rfp = NULL;
784                 return;
785         }
786
787         /*
788          * Must have an ASxxxx Listing line number
789          */
790         if (!dgt(RAD10, &rb[30], 1)) {
791                 fprintf(rfp, "%s", rb);
792                 goto loop;
793         }
794
795         /*
796          * Must have an address in the expected radix
797          */
798         if (radix == 16) {
799                 if (!dgt(RAD16, &rb[3], 4)) {
800                         fprintf(rfp, "%s", rb);
801                         goto loop;
802                 }
803                 sprintf(str, "%04X", pc);
804                 strncpy(&rb[3], str, 4);
805         } else
806         if (radix == 10) {
807                 if (!dgt(RAD10, &rb[3], 5)) {
808                         fprintf(rfp, "%s", rb);
809                         goto loop;
810                 }
811                 sprintf(str, "%05d", pc);
812                 strncpy(&rb[3], str, 5);
813         } else
814         if (radix == 8) {
815                 if (!dgt(RAD8, &rb[3], 6)) {
816                         fprintf(rfp, "%s", rb);
817                         goto loop;
818                 }
819                 sprintf(str, "%06o", pc);
820                 strncpy(&rb[3], str, 6);
821         }
822
823         /*
824          * Copy updated LST text line to RST
825          */
826         fprintf(rfp, "%s", rb);
827         gcntr = 0;
828 }
829
830 /*)Function     VOID    lkglist(pc,v)
831  *
832  *              int     pc              current program counter value
833  *              int     v               value of byte at this address
834  *
835  *      The function lkglist() performs the following functions:
836  *
837  *      (1)     if the value of gline = 1 then the listing file
838  *              is read line by line and copied to the
839  *              relocated listing file until a valid source
840  *              line number and a program counter value of the correct
841  *              radix is found.
842  *
843  *      (2)     The new relocated values and code address are
844  *              substituted and the line may be written to the RST file.
845  *
846  *      local variables:
847  *              int     i               loop counter
848  *              char    str[]           temporary string
849  *
850  *      global variables:
851  *              int     gcntr           data byte counter
852  *                                      set to -1 for a continuation line
853  *              int     gline           get a line from the LST file
854  *                                      to translate for the RST file
855  *              char    rb[]            read listing file text line
856  *              char    *rp             pointer to listing file text line
857  *              FILE    *rfp            The file handle to the current
858  *                                      output RST file
859  *              FILE    *tfp            The file handle to the current
860  *                                      LST file being scanned
861  *
862  *      functions called:
863  *              int     dgt()           lklist.c
864  *              int     fclose()        c_library
865  *              int     fgets()         c_library
866  *              int     fprintf()       c_library
867  *              int     sprintf()       c_library
868  *              char *  strncpy()       c_library
869  *
870  *      side effects:
871  *              Lines of the LST file are copied to the RST file
872  *              with updated data values and code addresses.
873  */
874
875 VOID
876 lkglist(pc,v)
877 Addr_T pc;
878 int v;
879 {
880         char str[8];
881         int i;
882
883         /*
884          * Exit if listing file is not open
885          */
886 loop:   if (tfp == NULL)
887                 return;
888
889         /*
890          * Get next LST text line
891          */
892         if (gline) {
893                 /*
894                  * Clear text line buffer
895                  */
896                 for (i=0,rp=rb; i<sizeof(rb); i++) {
897                         *rp++ = 0;
898                 }
899
900                 /*
901                  * Get next LST text line
902                  */
903                 if (fgets(rb, sizeof(rb), tfp) == NULL) {
904                         fclose(tfp);
905                         tfp = NULL;
906                         fclose(rfp);
907                         rfp = NULL;
908                         return;
909                 }
910
911                 /*
912                  * Check for a listing line number if required
913                  */
914                 if (gcntr != -1) {
915                         if (!dgt(RAD10, &rb[30], 1)) {
916                                 fprintf(rfp, "%s", rb);
917                                 goto loop;
918                         }
919                         gcntr = 0;
920                 }
921                 gline = 0;
922         }
923
924         /*
925          * Hex Listing
926          */
927         if (radix == 16) {
928                 /*
929                  * Data Byte Pointer
930                  */
931                 if (gcntr == -1) {
932                         rp = &rb[8];
933                 } else {
934                         rp = &rb[8 + (3 * gcntr)];
935                 }
936                 /*
937                  * Number must be of proper radix
938                  */
939                 if (!dgt(RAD16, rp, 2)) {
940                         fprintf(rfp, "%s", rb);
941                         gline = 1;
942                         goto loop;
943                 }
944                 /*
945                  * Output new data value, overwrite relocation codes
946                  */
947                 sprintf(str, " %02X", v);
948                 strncpy(rp-1, str, 3);
949                 if (gcntr == -1) {
950                         gcntr = 0;
951                 }
952                 /*
953                  * Output relocated code address
954                  */
955                 if (gcntr == 0) {
956                         if (dgt(RAD16, &rb[3], 4)) {
957                                 sprintf(str, "%04X", pc);
958                                 strncpy(&rb[3], str, 4);
959                         }
960                 }
961                 /*
962                  * Output text line when updates finished
963                  */
964                 if (++gcntr == 6) {
965                         fprintf(rfp, "%s", rb);
966                         gline = 1;
967                         gcntr = -1;
968                 }
969         } else
970         /*
971          * Decimal Listing
972          */
973         if (radix == 10) {
974                 /*
975                  * Data Byte Pointer
976                  */
977                 if (gcntr == -1) {
978                         rp = &rb[9];
979                 } else {
980                         rp = &rb[9 + (3 * gcntr)];
981                 }
982                 /*
983                  * Number must be of proper radix
984                  */
985                 if (!dgt(RAD10, rp, 3)) {
986                         fprintf(rfp, "%s", rb);
987                         gline = 1;
988                         goto loop;
989                 }
990                 /*
991                  * Output new data value, overwrite relocation codes
992                  */
993                 sprintf(str, " %03d", v);
994                 strncpy(rp-1, str, 4);
995                 if (gcntr == -1) {
996                         gcntr = 0;
997                 }
998                 /*
999                  * Output relocated code address
1000                  */
1001                 if (gcntr == 0) {
1002                         if (dgt(RAD10, &rb[3], 5)) {
1003                                 sprintf(str, "%05d", pc);
1004                                 strncpy(&rb[3], str, 5);
1005                         }
1006                 }
1007                 /*
1008                  * Output text line when updates finished
1009                  */
1010                 if (++gcntr == 4) {
1011                         fprintf(rfp, "%s", rb);
1012                         gline = 1;
1013                         gcntr = -1;
1014                 }
1015         } else
1016         /*
1017          * Octal Listing
1018          */
1019         if (radix == 8) {
1020                 /*
1021                  * Data Byte Pointer
1022                  */
1023                 if (gcntr == -1) {
1024                         rp = &rb[10];
1025                 } else {
1026                         rp = &rb[10 + (3 * gcntr)];
1027                 }
1028                 /*
1029                  * Number must be of proper radix
1030                  */
1031                 if (!dgt(RAD8, rp, 3)) {
1032                         fprintf(rfp, "%s", rb);
1033                         gline = 1;
1034                         goto loop;
1035                 }
1036                 /*
1037                  * Output new data value, overwrite relocation codes
1038                  */
1039                 sprintf(str, " %03o", v);
1040                 strncpy(rp-1, str, 4);
1041                 if (gcntr == -1) {
1042                         gcntr = 0;
1043                 }
1044                 /*
1045                  * Output relocated code address
1046                  */
1047                 if (gcntr == 0) {
1048                         if (dgt(RAD8, &rb[3], 6)) {
1049                                 sprintf(str, "%06o", pc);
1050                                 strncpy(&rb[3], str, 6);
1051                         }
1052                 }
1053                 /*
1054                  * Output text line when updates finished
1055                  */
1056                 if (++gcntr == 4) {
1057                         fprintf(rfp, "%s", rb);
1058                         gline = 1;
1059                         gcntr = -1;
1060                 }
1061         }
1062 }
1063
1064 /*)Function     int     dgt(rdx,str,n)
1065  *
1066  *              int     rdx             radix bit code
1067  *              char    *str            pointer to the test string
1068  *              int     n               number of characters to check
1069  *
1070  *      The function dgt() verifies that the string under test
1071  *      is of the specified radix.
1072  *
1073  *      local variables:
1074  *              int     i               loop counter
1075  *
1076  *      global variables:
1077  *              ctype[]                 array of character types
1078  *
1079  *      functions called:
1080  *              none
1081  *
1082  *      side effects:
1083  *              none
1084  */
1085
1086 int
1087 dgt(rdx, str, n)
1088 int rdx, n;
1089 char *str;
1090 {
1091         int i;
1092
1093         for (i=0; i<n; i++) {
1094                 if ((ctype[(int)*str++] & rdx) == 0)
1095                         return(0);
1096         }
1097         return(1);
1098 }
1099
1100 /*JCF: Create a memory summary file with extension .mem*/
1101 int summary(struct area * areap) 
1102 {
1103         #define EQ(A,B) !strcmpi((A),(B))
1104         #define MIN_STACK 16
1105         #define REPORT_ERROR(A, H) \
1106         {\
1107                 fprintf(of, "%s%s", (H)?"*** ERROR: ":"", (A)); \
1108                 fprintf(stderr, "%s%s", (H)?"\n?ASlink-Error-":"",(A)); \
1109                 toreturn=1; \
1110         }
1111
1112         #define REPORT_WARNING(A, H) \
1113         { \
1114                 fprintf(of, "%s%s", (H)?"*** WARNING: ":"", (A)); \
1115                 fprintf(stderr, "%s%s",(H)?"\n?ASlink-Warning-":"", (A)); \
1116         }
1117
1118         char buff[128];
1119         int j, toreturn=0;
1120         unsigned int Total_Last=0, k; 
1121
1122         struct area * xp;
1123         FILE * of;
1124         
1125         /*Artifacts used for printing*/
1126         char start[8], end[8], size[8], max[8];
1127         char format[]="   %-16.16s %-7.7s %-7.7s %-7.7s %-7.7s\n";
1128         char line[]="---------------------";
1129
1130         typedef struct
1131         {
1132                 unsigned int Start;
1133                 unsigned int Size;
1134                 unsigned int Max;
1135                 char Name[NCPS];
1136                 unsigned int flag;
1137         } _Mem;
1138
1139         unsigned int dram[0x100];
1140         _Mem Ram[]={
1141                 {0,             8,      8,       "REG_BANK_0", 0x0001},
1142                 {0x8,   8,      8,       "REG_BANK_1", 0x0002},
1143                 {0x10,  8,      8,       "REG_BANK_2", 0x0004},
1144                 {0x18,  8,      8,       "REG_BANK_3", 0x0008},
1145                 {0x20,  0,      16,      "BSEG_BYTES", 0x0010},
1146                 {0,             0,      128, "UNUSED",     0x0000},
1147                 {0x7f,  0,      128, "DATA",       0x0020},
1148                 {0,             0,      128, "TOTAL:",     0x0000}
1149         };
1150         
1151         _Mem IRam= {0xff,   0,   128, "INDIRECT RAM",           0x0080};
1152         _Mem Stack={0xff,   0,     1, "STACK",                          0x0000};
1153         _Mem XRam= {0xffff, 0, 65536, "EXTERNAL RAM",           0x0100};
1154         _Mem Rom=  {0xffff, 0, 65536, "ROM/EPROM/FLASH",        0x0200};
1155
1156         if((iram_size<=0)||(iram_size>0x100)) /*Default: 8052 like memory*/
1157         {
1158                 Ram[5].Max=0x80;
1159                 Ram[6].Max=0x80;
1160                 Ram[7].Max=0x80;
1161                 IRam.Max=0x80;
1162                 iram_size=0x100;
1163         }
1164         else if(iram_size<0x80)
1165         {
1166                 Ram[5].Max=iram_size;
1167                 Ram[6].Max=iram_size;
1168                 Ram[7].Max=iram_size;
1169                 IRam.Max=0;
1170         }
1171         else
1172         {
1173                 Ram[5].Max=0x80;
1174                 Ram[6].Max=0x80;
1175                 Ram[7].Max=0x80;
1176                 IRam.Max=iram_size-0x80;
1177         }
1178
1179         for(j=0; j<(int)iram_size; j++) dram[j]=0;
1180         for(; j<0x100; j++) dram[j]=0x8000; /*Memory not available*/
1181
1182         /* Open Memory Summary File*/
1183         of = afile(linkp->f_idp, "mem", 1);
1184         if (of == NULL)
1185         {
1186                 lkexit(1);
1187         }
1188
1189         xp=areap;
1190         while (xp)
1191         {
1192                 /**/ if (EQ(xp->a_id, "REG_BANK_0"))
1193                 {
1194                         Ram[0].Size=xp->a_size;
1195                 }
1196                 else if (EQ(xp->a_id, "REG_BANK_1"))
1197                 {
1198                         Ram[1].Size=xp->a_size;
1199                 }
1200                 else if (EQ(xp->a_id, "REG_BANK_2"))
1201                 {
1202                         Ram[2].Size=xp->a_size;
1203                 }
1204                 else if (EQ(xp->a_id, "REG_BANK_3"))
1205                 {
1206                         Ram[3].Size=xp->a_size;
1207                 }
1208                 else if (EQ(xp->a_id, "BSEG_BYTES"))
1209                 {
1210                         Ram[4].Size=xp->a_size;
1211                 }
1212                 else if ( EQ(xp->a_id, "DSEG") || EQ(xp->a_id, "OSEG") )
1213                 {
1214                         Ram[6].Size+=xp->a_size;
1215                         if(xp->a_addr<Ram[6].Start) Ram[6].Start=xp->a_addr;
1216                 }
1217
1218                 else if( EQ(xp->a_id, "CSEG") || EQ(xp->a_id, "GSINIT") ||
1219                                  EQ(xp->a_id, "GSFINAL") || EQ(xp->a_id, "HOME") )
1220                 {
1221                         Rom.Size+=xp->a_size;
1222                         if(xp->a_addr<Rom.Start) Rom.Start=xp->a_addr;
1223                 }
1224                 
1225                 else if (EQ(xp->a_id, "SSEG"))
1226                 {
1227                         Stack.Size+=xp->a_size;
1228                         if(xp->a_addr<Stack.Start) Stack.Start=xp->a_addr;
1229                 }
1230
1231                 else if (EQ(xp->a_id, "XSEG") || EQ(xp->a_id, "XISEG")) 
1232                 {
1233                         XRam.Size+=xp->a_size;
1234                         if(xp->a_addr<XRam.Start) XRam.Start=xp->a_addr;
1235                 }
1236
1237                 else if (EQ(xp->a_id, "ISEG"))
1238                 {
1239                         IRam.Size+=xp->a_size;
1240                         if(xp->a_addr<IRam.Start) IRam.Start=xp->a_addr;
1241                 }
1242                 xp=xp->a_ap;
1243         }
1244
1245         for(j=0; j<7; j++)
1246                 for(k=Ram[j].Start; (k<(Ram[j].Start+Ram[j].Size))&&(k<0x100); k++)
1247                         dram[k]|=Ram[j].flag; /*Mark as used*/
1248         
1249         for(k=IRam.Start; (k<(IRam.Start+IRam.Size))&&(k<0x100); k++)
1250                 dram[k]|=IRam.flag; /*Mark as used*/
1251
1252         /*Compute the amount of unused memory in direct data Ram.  This is the
1253         gap between the last register bank or bit segment and the data segment.*/
1254         for(k=Ram[6].Start-1; (dram[k]==0) && (k>0); k--);
1255         Ram[5].Start=k+1;
1256         Ram[5].Size=Ram[6].Start-Ram[5].Start; /*It may be zero (which is good!)*/
1257
1258         /*Compute the data Ram totals*/
1259         for(j=0; j<7; j++)
1260         {
1261                 if(Ram[7].Start>Ram[j].Start) Ram[7].Start=Ram[j].Start;
1262                 Ram[7].Size+=Ram[j].Size;
1263         }
1264         Total_Last=Ram[6].Size+Ram[6].Start-1;
1265
1266         /*Report the Ram totals*/
1267         fprintf(of, "Direct Internal RAM:\n");
1268         fprintf(of, format, "Name", "Start", "End", "Size", "Max");
1269
1270         for(j=0; j<8; j++)
1271         {
1272                 if((j==0) || (j==7)) fprintf(of, format, line, line, line, line, line);
1273                 if((j!=5) || (Ram[j].Size>0))
1274                 {
1275                         sprintf(start, "0x%02x", Ram[j].Start);
1276                         if(Ram[j].Size==0)
1277                                 end[0]=0;/*Empty string*/
1278                         else
1279                                 sprintf(end,  "0x%02x", j==7?Total_Last:Ram[j].Size+Ram[j].Start-1);
1280                         sprintf(size, "%5u", Ram[j].Size);
1281                         sprintf(max, "%5u", Ram[j].Max);
1282                         fprintf(of, format, Ram[j].Name, start, end, size, max);
1283                 }
1284         }
1285
1286         for(k=Ram[6].Start; (k<(Ram[6].Start+Ram[6].Size))&&(k<0x100); k++)
1287         {
1288                 if(dram[k]!=Ram[6].flag)
1289                 {
1290                         sprintf(buff, "Internal memory overlap starting at 0x%02x.\n", k);
1291                         REPORT_ERROR(buff, 1);
1292                         break;
1293                 }
1294         }
1295
1296         if(Ram[4].Size>Ram[4].Max)
1297         {
1298                 k=Ram[4].Size-Ram[4].Max;
1299                 sprintf(buff, "Insufficient bit addressable memory.  "
1300                                         "%d byte%s short.\n", k, (k==1)?"":"s");
1301                 REPORT_ERROR(buff, 1);
1302         }
1303
1304         if(Ram[5].Size!=0)
1305         {
1306                 sprintf(buff, "%d bytes in DRAM wasted.  "
1307                             "SDCC link could use: --data-loc 0x%02x\n",
1308                                         Ram[5].Size, Ram[6].Start-Ram[5].Size);
1309                 REPORT_WARNING(buff, 1);
1310         }
1311
1312         if((Ram[6].Start+Ram[6].Size)>Ram[6].Max)
1313         {
1314                 k=(Ram[6].Start+Ram[6].Size)-Ram[6].Max;
1315                 sprintf(buff, "Insufficient DRAM memory.  "
1316                                         "%d byte%s short.\n", k, (k==1)?"":"s");
1317                 REPORT_ERROR(buff, 1);
1318         }
1319
1320         /*Report the position of the begining of the stack*/
1321         fprintf(of, "\nStack starts at: 0x%02x", Stack.Start);
1322
1323         /*Check that the stack pointer is landing in a safe place:*/
1324         if( (dram[Stack.Start] & 0x8000) == 0x8000 )
1325         {
1326                 fprintf(of, ".\n");
1327                 sprintf(buff, "Stack set to unavailable memory.\n");
1328                 REPORT_ERROR(buff, 1);
1329         }
1330         else if(dram[Stack.Start])
1331         {
1332                 fprintf(of, ".\n");
1333                 sprintf(buff, "Stack overlaps area ");
1334                 REPORT_ERROR(buff, 1);
1335                 for(j=0; j<7; j++)
1336                 {
1337                         if(dram[Stack.Start]&Ram[j].flag)
1338                         {
1339                                 sprintf(buff, "'%s'\n", Ram[j].Name);
1340                                 break;
1341                         }
1342                 }
1343                 if(dram[Stack.Start]&IRam.flag)
1344                 {
1345                         sprintf(buff, "'%s'\n", IRam.Name);
1346                 }
1347                 REPORT_ERROR(buff, 0);
1348         }
1349         else    
1350         {
1351                 for(j=Stack.Start, k=0; (j<(int)iram_size)&&(dram[j]==0); j++, k++);
1352                 fprintf(of, " with %d bytes available\n", k);
1353                 if (k<MIN_STACK)
1354                 {
1355                         sprintf(buff, "Only %d byte%s available for stack.\n",
1356                                         k, (k==1)?"":"s");
1357                         REPORT_WARNING(buff, 1);
1358                 }
1359         }
1360
1361         fprintf(of, "\nOther memory:\n");
1362         fprintf(of, format, "Name", "Start", "End", "Size", "Max");
1363         fprintf(of, format, line, line, line, line, line);
1364
1365         /*Report IRam totals:*/
1366         sprintf(start, "0x%02x", IRam.Start);
1367         if(IRam.Size==0)
1368                 end[0]=0;/*Empty string*/
1369         else
1370                 sprintf(end,  "0x%02x", IRam.Size+IRam.Start-1);
1371         sprintf(size, "%5u", IRam.Size);
1372         sprintf(max, "%5u", IRam.Max);
1373         fprintf(of, format, IRam.Name, start, end, size, max);
1374
1375         /*Report XRam totals:*/
1376         sprintf(start, "0x%04x", XRam.Start);
1377         if(XRam.Size==0)
1378                 end[0]=0;/*Empty string*/
1379         else
1380                 sprintf(end,  "0x%04x", XRam.Size+XRam.Start-1);
1381         sprintf(size, "%5u", XRam.Size);
1382         sprintf(max, "%5u", XRam.Max);
1383         fprintf(of, format, XRam.Name, start, end, size, max);
1384
1385         /*Report Rom/Flash totals:*/
1386         sprintf(start, "0x%04x", Rom.Start);
1387         if(Rom.Size==0)
1388                 end[0]=0;/*Empty string*/
1389         else
1390                 sprintf(end,  "0x%04x", Rom.Size+Rom.Start-1);
1391         sprintf(size, "%5u", Rom.Size);
1392         sprintf(max, "%5u", Rom.Max);
1393         fprintf(of, format, Rom.Name, start, end, size, max);
1394
1395         /*Report any excess:*/
1396         if((IRam.Start+IRam.Size)>(IRam.Max+0x80))
1397         {
1398                 sprintf(buff, "Insufficient INDIRECT RAM memory.\n");
1399                 REPORT_ERROR(buff, 1);
1400         }
1401         if((XRam.Start+XRam.Size)>XRam.Max)
1402         {
1403                 sprintf(buff, "Insufficient EXTERNAL RAM memory.\n");
1404                 REPORT_ERROR(buff, 1);
1405         }
1406         if((Rom.Start+Rom.Size)>Rom.Max)
1407         {
1408                 sprintf(buff, "Insufficient ROM/EPROM/FLASH memory.\n");
1409                 REPORT_ERROR(buff, 1);
1410         }
1411
1412         fclose(of);
1413         return toreturn;                
1414 }