fixed bug [ 954173 ] code size miscalculation
[fw/sdcc] / as / mcs51 / lkmem.c
1 /*-------------------------------------------------------------------------
2   lkmem.c - Create a memory summary file with extension .mem
3
4    Written By -  Jesus Calvino-Fraga, jesusc@ieee.org (2002)
5
6    This program is free software; you can redistribute it and/or modify it
7    under the terms of the GNU General Public License as published by the
8    Free Software Foundation; either version 2, or (at your option) any
9    later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 -------------------------------------------------------------------------*/
20
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include "aslink.h"
25 #include "strcmpi.h"
26
27 int summary(struct area * areap) 
28 {
29         #define EQ(A,B) !as_strcmpi((A),(B))
30         #define MIN_STACK 16
31         #define REPORT_ERROR(A, H) \
32         {\
33                 fprintf(of, "%s%s", (H)?"*** ERROR: ":"", (A)); \
34                 fprintf(stderr, "%s%s", (H)?"\n?ASlink-Error-":"",(A)); \
35                 toreturn=1; \
36         }
37
38         #define REPORT_WARNING(A, H) \
39         { \
40                 fprintf(of, "%s%s", (H)?"*** WARNING: ":"", (A)); \
41                 fprintf(stderr, "%s%s",(H)?"\n?ASlink-Warning-":"", (A)); \
42         }
43
44         char buff[128];
45         int j, toreturn=0;
46         unsigned int Total_Last=0, k; 
47
48         struct area * xp;
49         FILE * of;
50         
51         /*Artifacts used for printing*/
52         char start[15], end[15], size[15], max[15];
53         char format[]="   %-16.16s %-8.8s %-8.8s %-8.8s %-8.8s\n";
54         char line[]="---------------------";
55
56         typedef struct
57         {
58                 unsigned long Start;
59                 unsigned long Size;
60                 unsigned long Max;
61                 char Name[NCPS];
62                 unsigned long flag;
63         } _Mem;
64
65         unsigned int dram[0x100];
66         _Mem Ram[]={
67                 {0,             8,      8,       "REG_BANK_0", 0x0001},
68                 {0x8,   8,      8,       "REG_BANK_1", 0x0002},
69                 {0x10,  8,      8,       "REG_BANK_2", 0x0004},
70                 {0x18,  8,      8,       "REG_BANK_3", 0x0008},
71                 {0x20,  0,      16,      "BSEG_BYTES", 0x0010},
72                 {0,             0,      128, "UNUSED",     0x0000},
73                 {0x7f,  0,      128, "DATA",       0x0020},
74                 {0,             0,      128, "TOTAL:",     0x0000}
75         };
76
77         _Mem IRam= {0xff,   0,   128, "INDIRECT RAM",           0x0080};
78         _Mem Stack={0xff,   0,     1, "STACK",                          0x0000};
79         _Mem XRam= {0xffff, 0, 65536, "EXTERNAL RAM",           0x0100};
80         _Mem Rom=  {0xffff, 0, 65536, "ROM/EPROM/FLASH",        0x0200};
81
82         if(stacksize==0) stacksize=MIN_STACK;
83
84         if(rflag) /*For the DS390*/
85         {
86                 XRam.Max=0x1000000; /*24 bits*/
87                 XRam.Start=0xffffff;
88                 Rom.Max=0x1000000;
89                 Rom.Start=0xffffff;
90         }
91
92         if((iram_size<=0)||(iram_size>0x100)) /*Default: 8052 like memory*/
93         {
94                 Ram[5].Max=0x80;
95                 Ram[6].Max=0x80;
96                 Ram[7].Max=0x80;
97                 IRam.Max=0x80;
98                 iram_size=0x100;
99         }
100         else if(iram_size<0x80)
101         {
102                 Ram[5].Max=iram_size;
103                 Ram[6].Max=iram_size;
104                 Ram[7].Max=iram_size;
105                 IRam.Max=0;
106         }
107         else
108         {
109                 Ram[5].Max=0x80;
110                 Ram[6].Max=0x80;
111                 Ram[7].Max=0x80;
112                 IRam.Max=iram_size-0x80;
113         }
114
115         for(j=0; j<(int)iram_size; j++) dram[j]=0;
116         for(; j<0x100; j++) dram[j]=0x8000; /*Memory not available*/
117
118         /* Open Memory Summary File*/
119         of = afile(linkp->f_idp, "mem", 1);
120         if (of == NULL)
121         {
122                 lkexit(1);
123         }
124
125         xp=areap;
126         while (xp)
127         {
128                 /**/ if (EQ(xp->a_id, "REG_BANK_0"))
129                 {
130                         Ram[0].Size=xp->a_size;
131                 }
132                 else if (EQ(xp->a_id, "REG_BANK_1"))
133                 {
134                         Ram[1].Size=xp->a_size;
135                 }
136                 else if (EQ(xp->a_id, "REG_BANK_2"))
137                 {
138                         Ram[2].Size=xp->a_size;
139                 }
140                 else if (EQ(xp->a_id, "REG_BANK_3"))
141                 {
142                         Ram[3].Size=xp->a_size;
143                 }
144                 else if (EQ(xp->a_id, "BSEG_BYTES"))
145                 {
146                         Ram[4].Size=xp->a_size;
147                 }
148                 else if ( EQ(xp->a_id, "DSEG") || EQ(xp->a_id, "OSEG") )
149                 {
150                         Ram[6].Size+=xp->a_size;
151                         if(xp->a_addr<Ram[6].Start) Ram[6].Start=xp->a_addr;
152                 }
153
154                 else if( EQ(xp->a_id, "CSEG") || EQ(xp->a_id, "GSINIT") ||
155                                  EQ(xp->a_id, "GSINIT0") || EQ(xp->a_id, "GSINIT1") ||
156                                  EQ(xp->a_id, "GSINIT2") || EQ(xp->a_id, "GSINIT3") ||
157                                  EQ(xp->a_id, "GSINIT4") || EQ(xp->a_id, "GSINIT5") ||
158                                  EQ(xp->a_id, "GSFINAL") || EQ(xp->a_id, "HOME") )
159                 {
160                         Rom.Size+=xp->a_size;
161                         if(xp->a_addr<Rom.Start) Rom.Start=xp->a_addr;
162                 }
163                 
164                 else if (EQ(xp->a_id, "SSEG"))
165                 {
166                         Stack.Size+=xp->a_size;
167                         if(xp->a_addr<Stack.Start) Stack.Start=xp->a_addr;
168                 }
169
170                 else if (EQ(xp->a_id, "XSEG") || EQ(xp->a_id, "XISEG")) 
171                 {
172                         XRam.Size+=xp->a_size;
173                         if(xp->a_addr<XRam.Start) XRam.Start=xp->a_addr;
174                 }
175
176                 else if (EQ(xp->a_id, "ISEG"))
177                 {
178                         IRam.Size+=xp->a_size;
179                         if(xp->a_addr<IRam.Start) IRam.Start=xp->a_addr;
180                 }
181                 xp=xp->a_ap;
182         }
183
184         for(j=0; j<7; j++)
185                 for(k=Ram[j].Start; (k<(Ram[j].Start+Ram[j].Size))&&(k<0x100); k++)
186                         dram[k]|=Ram[j].flag; /*Mark as used*/
187         
188         for(k=IRam.Start; (k<(IRam.Start+IRam.Size))&&(k<0x100); k++)
189                 dram[k]|=IRam.flag; /*Mark as used*/
190
191         /*Compute the amount of unused memory in direct data Ram.  This is the
192         gap between the last register bank or bit segment and the data segment.*/
193         for(k=Ram[6].Start-1; (dram[k]==0) && (k>0); k--);
194         Ram[5].Start=k+1;
195         Ram[5].Size=Ram[6].Start-Ram[5].Start; /*It may be zero (which is good!)*/
196
197         /*Compute the data Ram totals*/
198         for(j=0; j<7; j++)
199         {
200                 if(Ram[7].Start>Ram[j].Start) Ram[7].Start=Ram[j].Start;
201                 Ram[7].Size+=Ram[j].Size;
202         }
203         Total_Last=Ram[6].Size+Ram[6].Start-1;
204
205         /*Report the Ram totals*/
206         fprintf(of, "Direct Internal RAM:\n");
207         fprintf(of, format, "Name", "Start", "End", "Size", "Max");
208
209         for(j=0; j<8; j++)
210         {
211                 if((j==0) || (j==7)) fprintf(of, format, line, line, line, line, line);
212                 if((j!=5) || (Ram[j].Size>0))
213                 {
214                         sprintf(start, "0x%02lx", Ram[j].Start);
215                         if(Ram[j].Size==0)
216                                 end[0]=0;/*Empty string*/
217                         else
218                                 sprintf(end,  "0x%02lx", j==7?Total_Last:Ram[j].Size+Ram[j].Start-1);
219                         sprintf(size, "%5lu", Ram[j].Size);
220                         sprintf(max, "%5lu", Ram[j].Max);
221                         fprintf(of, format, Ram[j].Name, start, end, size, max);
222                 }
223         }
224
225         for(k=Ram[6].Start; (k<(Ram[6].Start+Ram[6].Size))&&(k<0x100); k++)
226         {
227                 if(dram[k]!=Ram[6].flag)
228                 {
229                         sprintf(buff, "Internal memory overlap starting at 0x%02x.\n", k);
230                         REPORT_ERROR(buff, 1);
231                         break;
232                 }
233         }
234
235         if(Ram[4].Size>Ram[4].Max)
236         {
237                 k=Ram[4].Size-Ram[4].Max;
238                 sprintf(buff, "Insufficient bit addressable memory.  "
239                                         "%d byte%s short.\n", k, (k==1)?"":"s");
240                 REPORT_ERROR(buff, 1);
241         }
242
243         if(Ram[5].Size!=0)
244         {
245                 sprintf(buff, "%ld bytes in data memory wasted.  "
246                             "SDCC link could use: --data-loc 0x%02lx\n",
247                                         Ram[5].Size, Ram[6].Start-Ram[5].Size);
248                 REPORT_WARNING(buff, 1);
249         }
250
251         if((Ram[6].Start+Ram[6].Size)>Ram[6].Max)
252         {
253                 k=(Ram[6].Start+Ram[6].Size)-Ram[6].Max;
254                 sprintf(buff, "Insufficient space in data memory.   "
255                                         "%d byte%s short.\n", k, (k==1)?"":"s");
256                 REPORT_ERROR(buff, 1);
257         }
258
259         /*Report the position of the begining of the stack*/
260         fprintf(of, "\n%stack starts at: 0x%02lx (sp set to 0x%02lx)",
261                 rflag ? "16 bit mode initial s" : "S", Stack.Start, Stack.Start-1);
262
263         /*Check that the stack pointer is landing in a safe place:*/
264         if( (dram[Stack.Start] & 0x8000) == 0x8000 )
265         {
266                 fprintf(of, ".\n");
267                 sprintf(buff, "Stack set to unavailable memory.\n");
268                 REPORT_ERROR(buff, 1);
269         }
270         else if(dram[Stack.Start])
271         {
272                 fprintf(of, ".\n");
273                 sprintf(buff, "Stack overlaps area ");
274                 REPORT_ERROR(buff, 1);
275                 for(j=0; j<7; j++)
276                 {
277                         if(dram[Stack.Start]&Ram[j].flag)
278                         {
279                                 sprintf(buff, "'%s'\n", Ram[j].Name);
280                                 break;
281                         }
282                 }
283                 if(dram[Stack.Start]&IRam.flag)
284                 {
285                         sprintf(buff, "'%s'\n", IRam.Name);
286                 }
287                 REPORT_ERROR(buff, 0);
288         }
289         else
290         {
291                 for(j=Stack.Start, k=0; (j<(int)iram_size)&&(dram[j]==0); j++, k++);
292                 fprintf(of, " with %d bytes available\n", k);
293                 if ((int)k<stacksize)
294                 {
295                         sprintf(buff, "Only %d byte%s available for stack.\n",
296                                 k, (k==1)?"":"s");
297                         REPORT_WARNING(buff, 1);
298                 }
299         }
300
301         fprintf(of, "\nOther memory:\n");
302         fprintf(of, format, "Name", "Start", "End", "Size", "Max");
303         fprintf(of, format, line, line, line, line, line);
304
305         /*Report IRam totals:*/
306         sprintf(start, "0x%02lx", IRam.Start);
307         if(IRam.Size==0)
308                 end[0]=0;/*Empty string*/
309         else
310                 sprintf(end,  "0x%02lx", IRam.Size+IRam.Start-1);
311         sprintf(size, "%5lu", IRam.Size);
312         sprintf(max, "%5lu", IRam.Max);
313         fprintf(of, format, IRam.Name, start, end, size, max);
314
315         /*Report XRam totals:*/
316         sprintf(start, "0x%04lx", XRam.Start);
317         if(XRam.Size==0)
318                 end[0]=0;/*Empty string*/
319         else
320                 sprintf(end,  "0x%04lx", XRam.Size+XRam.Start-1);
321         sprintf(size, "%5lu", XRam.Size);
322         sprintf(max, "%5lu", xram_size<0?XRam.Max:xram_size);
323         fprintf(of, format, XRam.Name, start, end, size, max);
324
325         /*Report Rom/Flash totals:*/
326         sprintf(start, "0x%04lx", Rom.Start);
327         if(Rom.Size==0)
328                 end[0]=0;/*Empty string*/
329         else
330                 sprintf(end,  "0x%04lx", Rom.Size+Rom.Start-1);
331         sprintf(size, "%5lu", Rom.Size);
332         sprintf(max, "%5lu", code_size<0?Rom.Max:code_size);
333         fprintf(of, format, Rom.Name, start, end, size, max);
334
335         /*Report any excess:*/
336         if((IRam.Start+IRam.Size)>(IRam.Max+0x80))
337         {
338                 sprintf(buff, "Insufficient INDIRECT RAM memory.\n");
339                 REPORT_ERROR(buff, 1);
340         }
341         if( ((XRam.Start+XRam.Size)>XRam.Max) ||
342                 (((int)XRam.Size>xram_size)&&(xram_size>=0)) )
343         {
344                 sprintf(buff, "Insufficient EXTERNAL RAM memory.\n");
345                 REPORT_ERROR(buff, 1);
346         }
347         if( ((Rom.Start+Rom.Size)>Rom.Max) ||
348                 (((int)Rom.Size>code_size)&&(code_size>=0)) )
349         {
350                 sprintf(buff, "Insufficient ROM/EPROM/FLASH memory.\n");
351                 REPORT_ERROR(buff, 1);
352         }
353
354         fclose(of);
355         return toreturn;                
356 }
357
358 extern char idatamap[]; //0:not used, 1:used
359
360
361 int summary2(struct area * areap) 
362 {
363         #define EQ(A,B) !as_strcmpi((A),(B))
364
365         char buff[128];
366         int j, toreturn=0;
367     long int Stack_Start=0, Stack_size;
368
369         struct area * xp;
370         FILE * of;
371         
372         /*Artifacts used for printing*/
373         char start[15], end[15], size[15], max[15];
374         char format[]="   %-16.16s %-8.8s %-8.8s %-8.8s %-8.8s\n";
375         char line[]="---------------------";
376
377         typedef struct
378         {
379                 unsigned long Start;
380                 unsigned long Size;
381                 unsigned long Max;
382                 char Name[NCPS];
383                 unsigned long flag;
384         } _Mem;
385         
386         _Mem Stack={0xff,   0,     1, "STACK",                          0x0000};
387         _Mem XRam= {0xffff, 0, 65536, "EXTERNAL RAM",           0x0100};
388         _Mem Rom=  {0xffff, 0, 65536, "ROM/EPROM/FLASH",        0x0200};
389         
390         if(rflag) /*For the DS390*/
391         {
392                 XRam.Max=0x1000000; /*24 bits*/
393                 XRam.Start=0xffffff;
394                 Rom.Max=0x1000000;
395                 Rom.Start=0xffffff;
396         }
397
398         /* Open Memory Summary File*/
399         of = afile(linkp->f_idp, "mem", 1);
400         if (of == NULL)
401         {
402                 lkexit(1);
403         }
404
405         xp=areap;
406         while (xp)
407         {
408                 if( EQ(xp->a_id, "CSEG") || EQ(xp->a_id, "GSINIT") ||
409                         EQ(xp->a_id, "GSINIT0") || EQ(xp->a_id, "GSINIT1") ||
410                         EQ(xp->a_id, "GSINIT2") || EQ(xp->a_id, "GSINIT3") ||
411                         EQ(xp->a_id, "GSINIT4") || EQ(xp->a_id, "GSINIT5") ||
412                         EQ(xp->a_id, "GSFINAL") || EQ(xp->a_id, "HOME") )
413                 {
414                         Rom.Size+=xp->a_size;
415                         if(xp->a_addr<Rom.Start) Rom.Start=xp->a_addr;
416                 }
417                 
418                 else if (EQ(xp->a_id, "SSEG"))
419                 {
420                         Stack.Size+=xp->a_size;
421                         if(xp->a_addr<Stack.Start) Stack.Start=xp->a_addr;
422                 }
423
424                 else if (EQ(xp->a_id, "XSEG") || EQ(xp->a_id, "XISEG")) 
425                 {
426                         XRam.Size+=xp->a_size;
427                         if(xp->a_addr<XRam.Start) XRam.Start=xp->a_addr;
428                 }
429
430                 xp=xp->a_ap;
431         }
432
433         /*Report the Ram totals*/
434         fprintf(of, "Internal RAM layout:\n");
435         fprintf(of, "      0 1 2 3 4 5 6 7 8 9 A B C D E F");
436     for(j=0; j<256; j++)
437         {
438                 if(j%16==0) fprintf(of, "\n0x%02x:|", j);
439                 fprintf(of, "%c|", idatamap[j]);
440         }
441         fprintf(of, "\n0-3:Reg Banks, a-z:Data, B:Bits, Q:Overlay, I:iData, S:Stack\n");
442
443     for(j=0; j<256; j++)
444     {
445         if(idatamap[j]=='S')
446         {
447             Stack_Start=j;
448             break;
449         }
450     }
451
452     for(j=Stack_Start, Stack_size=0; j<256; j++)
453     {
454         if((idatamap[j]=='S')||(idatamap[j]==' ')) Stack_size++;
455         else break;
456     }
457     
458         xp=areap;
459         while (xp)
460     {
461         if(xp->a_unaloc>0)
462         {
463             fprintf(of, "\nERROR: Couldn't get %d byte%s allocated" 
464                         " in internal RAM for area %s.",
465                         xp->a_unaloc, xp->a_unaloc>1?"s":"", xp->a_id);
466             toreturn=1;
467         }
468                 xp=xp->a_ap;
469     }
470
471         /*Report the position of the begining of the stack*/
472     if(Stack_Start!=256)
473             fprintf(of, "\n%stack starts at: 0x%02lx (sp set to 0x%02lx) with %ld bytes available.",
474                     rflag ? "16 bit mode initial s" : "S", Stack_Start, Stack_Start-1, Stack_size);
475     else
476         fprintf(of, "\nI don't have a clue where the stack ended up! Sorry...");
477
478         fprintf(of, "\n\nOther memory:\n");
479         fprintf(of, format, "Name", "Start", "End", "Size", "Max");
480         fprintf(of, format, line, line, line, line, line);
481
482         /*Report XRam totals:*/
483         sprintf(start, "0x%04lx", XRam.Start);
484         if(XRam.Size==0)
485                 end[0]=0;/*Empty string*/
486         else
487                 sprintf(end,  "0x%04lx", XRam.Size+XRam.Start-1);
488         sprintf(size, "%5lu", XRam.Size);
489         sprintf(max, "%5lu", xram_size<0?XRam.Max:xram_size);
490         fprintf(of, format, XRam.Name, start, end, size, max);
491
492         /*Report Rom/Flash totals:*/
493         sprintf(start, "0x%04lx", Rom.Start);
494         if(Rom.Size==0)
495                 end[0]=0;/*Empty string*/
496         else
497                 sprintf(end,  "0x%04lx", Rom.Size+Rom.Start-1);
498         sprintf(size, "%5lu", Rom.Size);
499         sprintf(max, "%5lu", code_size<0?Rom.Max:code_size);
500         fprintf(of, format, Rom.Name, start, end, size, max);
501
502         /*Report any excess:*/
503         if( ((XRam.Start+XRam.Size)>XRam.Max) ||
504                 (((int)XRam.Size>xram_size)&&(xram_size>=0)) )
505         {
506                 sprintf(buff, "Insufficient EXTERNAL RAM memory.\n");
507                 REPORT_ERROR(buff, 1);
508         }
509         if( ((Rom.Start+Rom.Size)>Rom.Max) ||
510                 (((int)Rom.Size>code_size)&&(code_size>=0)) )
511         {
512                 sprintf(buff, "Insufficient ROM/EPROM/FLASH memory.\n");
513                 REPORT_ERROR(buff, 1);
514         }
515
516         fclose(of);
517         return toreturn;                
518 }