1 /* lkaomf51.c - Create an absolute object memory format 51 file
3 Copyright (C) 2002 Jesus Calvino-Fraga, jesusc at ieee dot org
5 This program is free software; you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published by the
7 Free Software Foundation; either version 3, or (at your option) any
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */
24 #define EQ(A,B) !strcmp((A),(B))
25 #define MEMSIZE 0x10000
30 char PathName[PATH_MAX];
31 char ModuleName[PATH_MAX];
37 char ihxFileName[PATH_MAX];
38 char aomf51FileName[PATH_MAX];
44 int Procedure;//If the symbol belongs to a function
45 int Static; //If the symbol is only public on its file
51 _symbol * symbol=NULL;
62 _procedure * procedure=NULL;
73 _linenum * linenum=NULL;
82 _UsageType UsageType[]=
106 {"", 5} /*A typeless number?*/
109 char * UsageTypeName[]={"CODE", "XDATA", "DATA", "IDATA", "BIT", "NUMBER"};
111 unsigned char * ihxBuff=NULL;
114 int HexSize, HexBegin=0x10000;
117 void GetName(char * filepath, char * name)
120 for(j=strlen(filepath); j>0; j--)
121 if( (filepath[j-1]=='/')||(filepath[j-1]=='\\') ) break;
122 for(k=0; (filepath[j]!=0)&&(filepath[j]!='.'); j++, k++)
127 void SaveLinkedFilePath(char * filepath)
131 if((dflag) && (!rflag))
133 infn=realloc(infn, sizeof(_infn)*(numin+1));
135 strcpy(infn[numin].PathName, filepath);
136 j=strlen(infn[numin].PathName);
138 /*If there is an extension remove it*/
141 if(EQ(&infn[numin].PathName[j-4], ".rel"))
143 infn[numin].PathName[j-4]=0;
147 /*Get the module name=filename, no drive, no dir, no ext*/
148 GetName(infn[numin].PathName, infn[numin].ModuleName);
149 //printf("%s, %s\n", infn[numin].PathName, infn[numin].ModuleName);
151 /*Check if this filename is already in*/
152 for(j=0; j<numin; j++)
154 if(EQ(infn[numin].PathName, infn[j].PathName)) break;
156 if(j==numin) numin++;
197 void OutputByte(unsigned char value)
200 fwrite( &value, 1, 1, aomf51out );
203 void OutputWord(int value)
205 OutputByte((unsigned char)(value%0x100));
206 OutputByte((unsigned char)(value/0x100));
209 void OutputName(char * name)
212 OutputByte((unsigned char)strlen(name));
213 for(k=0; name[k]!=0; k++)
214 OutputByte((unsigned char)toupper(name[k]));
217 void OutputChkSum(void)
219 OutputByte((unsigned char)(0x100-(GlobalChkSum%0x100)));
224 void DumpForDebug (void)
226 char DumpFileName[PATH_MAX];
230 strcpy(DumpFileName, infn[0].PathName);
231 strcat(DumpFileName, ".d51");
233 DumpFile=fopen(DumpFileName, "wb");
236 printf("Couldn't create file %s\n", DumpFileName);
240 fprintf(DumpFile,"SYMBOLS:\n");
242 for(j=0; j<numsym; j++)
244 k=symbol[j].UsageType&0xf;
245 fprintf(DumpFile, "%s, %s, %s, 0x%04x, %s\n",
247 infn[symbol[j].FileNameNumber].PathName,
248 (symbol[j].Procedure>=0)?procedure[symbol[j].Procedure].name:"GLOBAL",
250 k<6?UsageTypeName[k]:"???");
253 fprintf(DumpFile,"\nPROCEDURES:\n");
254 for(j=0; j<numproc; j++)
256 fprintf(DumpFile, "%s, %s, 0x%04x-0x%04x\n",
258 infn[procedure[j].FileNameNumber].PathName,
259 procedure[j].BeginAdd,
260 procedure[j].EndAdd);
263 fprintf(DumpFile,"\nLINE NUMBERS:\n");
264 for(j=0; j<numlinenum; j++)
266 fprintf(DumpFile, "%d:0x%04x, %s -> %s\n",
269 infn[linenum[j].FileNameNumber].PathName,
270 (linenum[j].Procedure>=0)?procedure[linenum[j].Procedure].name:"I don't know");
277 void OutputAOEMF51(void)
279 int i, j, k, recsize;
280 char MHRname[0x100], Mname[0x100];
282 strcpy(aomf51FileName, infn[0].PathName);
284 aomf51out=fopen(aomf51FileName, "wb");
287 printf("Couldn't create file %s\n", aomf51FileName);
291 GetName(infn[0].PathName, MHRname);
294 /*Module header record*/
295 OutputByte(0x02);/*REC TYPE*/
296 OutputWord((strlen(MHRname)+1)+3);/*Record Length*/
297 OutputName(MHRname);/*Module Name*/
298 OutputByte(0xff);/*TRN ID: RL51?*/
302 for(j=0; j<numin; j++)
304 GetName(infn[j].PathName, Mname);
306 /*Scope Definition record: begin module block*/
307 OutputByte(0x10);/*REC TYPE*/
308 OutputWord((strlen(Mname)+1)+2);/*Record Length*/
309 OutputByte(0x00);/*BLK TYP: module block*/
310 OutputName(Mname);/*Module Name*/
313 /*Public symbols defined in this module*/
315 for(k=0; k<numsym; k++)/*Compute the record length*/
316 if ( (symbol[k].FileNameNumber==j) && (symbol[k].Address!=-1) &&
317 (symbol[k].Procedure==-1) &&
318 (symbol[k].Static==-1) ) recsize+=((strlen(symbol[k].name)+1)+5);
320 if(recsize>2) /*If there are any symbols*/
322 OutputByte(0x12); /*REC TYPE*/
323 OutputWord(recsize);/*Record Length*/
324 OutputByte(0x01); /*DEF TYPE: Public symbols*/
325 for(k=0; k<numsym; k++)
327 if ( (symbol[k].FileNameNumber==j) && (symbol[k].Address!=-1) &&
328 (symbol[k].Procedure==-1) &&
329 (symbol[k].Static==-1) )
331 OutputByte(0x00);/*SEG ID*/
332 OutputByte((unsigned char)symbol[k].UsageType);/*SYM INFO*/
333 OutputWord(symbol[k].Address);/*Offset*/
335 OutputName(symbol[k].name);/*Symbol name*/
341 /*Local symbols defined in this module*/
343 for(k=0; k<numsym; k++)/*Compute the record length*/
344 if ( (symbol[k].FileNameNumber==j) && (symbol[k].Address!=-1) &&
345 (symbol[k].Procedure==-1) &&
346 (symbol[k].Static==j) ) recsize+=((strlen(symbol[k].name)+1)+5);
348 if(recsize>2) /*If there are any symbols*/
350 OutputByte(0x12); /*REC TYPE*/
351 OutputWord(recsize);/*Record Length*/
352 OutputByte(0x00); /*DEF TYPE: Local symbols*/
353 for(k=0; k<numsym; k++)
355 if ( (symbol[k].FileNameNumber==j) && (symbol[k].Address!=-1) &&
356 (symbol[k].Procedure==-1) &&
357 (symbol[k].Static==j) )
359 OutputByte(0x00);/*SEG ID*/
360 OutputByte((unsigned char)symbol[k].UsageType);/*SYM INFO*/
361 OutputWord(symbol[k].Address);/*Offset*/
363 OutputName(symbol[k].name);/*Symbol name*/
369 /*Output the procedures of this module*/
371 for(k=0; k<numproc; k++)
373 if(procedure[k].FileNameNumber==j)
375 /*Scope Definition record: begin PROCEDURE block*/
376 OutputByte(0x10);/*REC TYPE*/
377 OutputWord((strlen(procedure[k].name)+1)+2);/*Record Length*/
378 OutputByte(0x02);/*BLK TYP: PROCEDURE block*/
379 OutputName(procedure[k].name);/*Module Name*/
383 OutputByte(0x06);/*REC TYPE*/
384 if(procedure[k].EndAdd==-1) procedure[k].EndAdd=HexSize;
385 recsize=procedure[k].EndAdd-procedure[k].BeginAdd+1+4;
386 OutputWord(recsize);/*Record Length*/
387 OutputByte(0x00);/*SEG ID*/
388 OutputWord(procedure[k].BeginAdd); /*Offset*/
389 for(i=procedure[k].BeginAdd; i<=procedure[k].EndAdd; i++)
390 OutputByte(ihxBuff[i]);
396 for(i=0; i<numsym; i++)/*Get the record length*/
397 if(symbol[i].Procedure==k)
398 recsize+=((strlen(symbol[i].name)+1)+5);
400 if(recsize>2) /*If there are any symbols*/
402 OutputByte(0x12); /*REC TYPE*/
403 OutputWord(recsize);/*Record Length*/
404 OutputByte(0x00); /*DEF TYPE: Local symbols*/
405 for(i=0; i<numsym; i++)
407 if ( (symbol[i].Procedure==k) )
409 OutputByte(0x00);/*SEG ID*/
410 OutputByte((unsigned char)symbol[i].UsageType);/*SYM INFO*/
411 OutputWord(symbol[i].Address);/*Offset*/
413 OutputName(symbol[i].name);/*Symbol name*/
421 for(i=0; i<numlinenum; i++)/*Get the record length*/
422 if(linenum[i].Procedure==k) recsize+=5;
424 if(recsize>2) /*If there are any line numbers*/
426 OutputByte(0x12); /*REC TYPE*/
427 OutputWord(recsize);/*Record Length*/
428 OutputByte(0x03); /*DEF TYPE: Line numbers*/
429 for(i=0; i<numlinenum; i++)
431 if ( (linenum[i].Procedure==k) )
433 OutputByte(0x00);/*SEG ID*/
434 OutputWord(linenum[i].Address);/*Offset*/
435 OutputWord(linenum[i].Number);/*Line Number*/
441 /*Scope Definition record: end PROCEDURE block*/
442 OutputByte(0x10);/*REC TYPE*/
443 OutputWord((strlen(procedure[k].name)+1)+2);/*Record Length*/
444 OutputByte(0x05);/*BLK TYP: PROCEDURE end block*/
445 OutputName(procedure[k].name);/*Module Name*/
450 /*Scope Definition record: end module block*/
451 OutputByte(0x10);/*REC TYPE*/
452 OutputWord((strlen(Mname)+1)+2);/*Record Length*/
453 OutputByte(0x03);/*BLK TYP: module end*/
454 OutputName(Mname);/*Module Name*/
458 /*Content records for everything that is not in the above procedures*/
459 strcpy(Mname, "OTHER_SDCC_STUF");
461 /*Scope Definition record: begin module block*/
462 OutputByte(0x10);/*REC TYPE*/
463 OutputWord((strlen(Mname)+1)+2);/*Record Length*/
464 OutputByte(0x00);/*BLK TYP: module block*/
465 OutputName(Mname);/*Module Name*/
468 for(j=-1; j<numproc; j++)
475 k=procedure[0].BeginAdd;
477 else if(j==(numproc-1))
479 i=procedure[j].EndAdd+1;
484 i=procedure[j].EndAdd+1;
485 k=procedure[j+1].BeginAdd;
488 else /*What, no procedures??? Ok, here it is the whole hex file*/
497 OutputByte(0x06);/*REC TYPE*/
498 OutputWord(k-i+4);/*Record Length*/
499 OutputByte(0x00);/*SEG ID*/
500 OutputWord(i); /*Offset*/
501 for(; i<k; i++) OutputByte(ihxBuff[i]);
506 /*Scope Definition record: end module block*/
507 OutputByte(0x10);/*REC TYPE*/
508 OutputWord((strlen(Mname)+1)+2);/*Record Length*/
509 OutputByte(0x03);/*BLK TYP: module end*/
510 OutputName(Mname);/*Module Name*/
513 /*Module end record*/
514 OutputByte(0x04);/*REC TYPE*/
515 OutputWord((strlen(MHRname)+1)+5);/*Record Length*/
516 OutputName(MHRname);/*Module Name*/
518 OutputByte(0x0f);/*REG MSK: All the register banks?*/
525 void CollectInfoFromCDB(void)
527 int i, j, k, CurrentModule;
530 char SourceName[PATH_MAX];
532 //"S:{G|F<filename>|L<functionName>}$<name>$<level>$<block>(<type info>),<Address Space>,<on Stack?>,<stack offset>"
533 char Sfmt[]="%[^$] %c %[^$] %c %[^$] %c %s";
539 char Bfmt[]="%[^)] %c %c %c %c %d %c %d";
540 char TypeInfo[0x100];
554 /*Build the source filename*/
555 strcpy(SourceName, infn[0].PathName);
556 strcat(SourceName, ".cdb");
557 CDBin=fopen(SourceName, "r");
560 printf("Couldn't open file '%s'\n", SourceName);
564 CurrentModule=0; /*Set the active module as the first one*/
567 fgets(buff, sizeof(buff)-1, CDBin);
569 if(!feof(CDBin)) switch(buff[0])
573 sscanf(&buff[2], "%s", name);
574 for(j=0; j<numin; j++)
575 if(EQ(infn[j].ModuleName, name)) break;
576 if(j<numin) CurrentModule=j;
580 "S:G$actual$0$0({7}ST__00010000:S),E,0,0"
581 "S:Lmain$j$1$1({2}SI:S),E,0,0"
582 "S:G$DS1306_Reset_SPI$0$0({2}DF,SV:S),C,0,0"
583 "S:G$main$0$0({2}DF,SV:S),C,0,0"
593 /*<block>(<type info>),<Address Space>,<on Stack?>,<stack offset>*/
603 case 'G': /*Global symbol*/
605 case 'L': /*Local symbol of a procedure*/
606 for(j=0; j<numproc; j++)
608 if(EQ(&scope[3], procedure[j].name)) break;
610 if(j<numproc) k=j; /*Local symbol*/
612 case 'F': /*Local symbol to a module*/
613 for(j=0; j<numin; j++)
615 if(EQ(&scope[3], infn[j].ModuleName)) break;
621 /*This symbol may have been already defined*/
622 for(j=0; j<numsym; j++)
624 if( EQ(name, symbol[j].name) &&
625 (symbol[j].Procedure==k) &&
626 (symbol[j].Static==i) ) break;
628 if(j==numsym) /*New symbol*/
630 symbol=realloc(symbol, sizeof(_symbol)*(numsym+1));
631 symbol[numsym].FileNameNumber=CurrentModule;
632 strcpy(symbol[numsym].name, name);
633 symbol[numsym].Procedure=k;
634 symbol[numsym].Static=i;
635 symbol[numsym].Address=-1;/*Collected later*/
640 case 'D': /*Code/static segment*/
641 case 'Z': /*Functions and undefined code space*/
642 symbol[numsym].UsageType=0x40;
645 case 'F': /*External ram*/
646 case 'A': /*External stack*/
647 case 'P': /*External Pdata*/
648 symbol[numsym].UsageType=0x41;
651 case 'E': /*Internal ram (lower 128) bytes*/
652 case 'I': /*SFR space*/
653 case 'R': /*Register Space*/
654 symbol[numsym].UsageType=0x42;
657 case 'B': /*Internal stack*/
658 case 'G': /*Internal ram*/
659 symbol[numsym].UsageType=0x43;
662 case 'H': /*Bit addressable*/
663 case 'J': /*SBIT space*/
664 symbol[numsym].UsageType=0x44;
668 printf("Unknown scope information for: %s, AddressSpace:%c\n", symbol[numsym].name, AddressSpace);
676 F:G$AsciiToHex$0$0({2}DF,SC:U),C,0,0,0,0,0
677 F:G$main$0$0({2}DF,SV:S),C,0,0,0,0,0 */
680 sscanf(buff, "%[^$] %c %[^$]", scope, &c, name);
681 /*The same may have been already defined */
682 for(j=0; j<numproc; j++)
684 if(EQ(name, procedure[j].name)) break;
688 procedure=realloc(procedure, sizeof(_procedure)*(numproc+1));
689 strcpy(procedure[numproc].name, name);
690 procedure[numproc].FileNameNumber=CurrentModule;
691 procedure[numproc].BeginAdd=-1;/*To be collected latter*/
692 procedure[numproc].EndAdd=-1;/*To be collected latter*/
696 /*This function name is also a global symbol*/
697 for(j=0; j<numsym; j++)/*A global symbol may have been already defined*/
699 if( EQ(name, symbol[j].name) && (symbol[j].Procedure==-1) ) break;
703 symbol=realloc(symbol, sizeof(_symbol)*(numsym+1));
704 symbol[numsym].FileNameNumber=CurrentModule;
705 strcpy(symbol[numsym].name, name);
706 symbol[numsym].UsageType=0x00;/*A procedure name symbol*/
707 symbol[numsym].Procedure=-1; /*Global symbol*/
708 symbol[numsym].Address=-1;/*Collected later*/
709 symbol[numsym].Static=-1; // o_gloom
717 case 'G': /*Example L:G$P0$0$0:80*/
718 sscanf(buff, "%[^$] %c %[^$] %c %[^:] %c %x",
719 scope, &c, name, &c, level, &c, &Address);
721 for(j=0; j<numsym; j++)
723 if(EQ(symbol[j].name, name))
725 if( (symbol[j].Address==-1) && (symbol[j].Procedure==-1) )
727 symbol[j].Address=Address;
730 /*If the symbol is the name of a procedure, the address is also
731 the begining of such procedure*/
732 if((symbol[j].UsageType&0x0f)==0x00)
734 for(k=0; k<numproc; k++)
736 if(EQ(symbol[j].name, procedure[k].name))
738 if(procedure[k].BeginAdd==-1)
739 procedure[k].BeginAdd=Address;
750 case 'F': /*Example L:Fadq$_str_2$0$0:57A*/
751 sscanf(buff, "%[^$] %c %[^$] %c %[^:] %c %x",
752 scope, &c, name, &c, level, &c, &Address);
754 for(j=0; j<numsym; j++)
756 if(EQ(symbol[j].name, name))
758 if( (symbol[j].Address==-1) ) symbol[j].Address=Address;
763 /*It could be also a static function*/
764 for(j=0; j<numproc; j++)
766 if(EQ(procedure[j].name, name))
768 if( (procedure[j].BeginAdd==-1) ) procedure[j].BeginAdd=Address;
775 case 'L': /*Example L:Lmain$j$1$1:29*/
778 L:LDS1306_Write$Value$1$1:34
779 L:LDS1306_Burst_Read$count$1$1:35
780 L:LDS1306_Burst_Read$address$1$1:36
781 L:LDS1306_Burst_Write$count$1$1:37
782 L:LDS1306_Burst_Write$address$1$1:38
784 sscanf(&buff[3], "%[^$] %c %[^$] %c %[^:] %c %x",
785 scope, &c, name, &c, level, &c, &Address);
787 for(k=0; k<numproc; k++)
789 if(EQ(procedure[k].name, scope)) break;
792 if(k<numproc) for(j=0; j<numsym; j++)
794 if( EQ(symbol[j].name, name) && (symbol[j].Procedure==k) )
796 if(symbol[j].Address==-1) symbol[j].Address=Address;
803 case 'C': /*Example L:C$adq.c$38$1$1:3E*/ /*L:C$hwinit.c$29$1$1:7AD*/
804 sscanf(&buff[4], "%[^.] %[^$] %c %d %[^:] %c %x",
805 name, level, &c, &CLine, level, &c, &Address);
807 for(j=0; j<numin; j++)
808 if(EQ(infn[j].ModuleName, name)) break;
811 /*Check if this line is already defined*/
812 for(k=0; k<numlinenum; k++)
814 if( (linenum[k].Number==CLine) &&
815 (linenum[k].FileNameNumber==j) )break;
817 if(k==numlinenum) /*New line number*/
819 linenum=realloc(linenum, sizeof(_linenum)*(numlinenum+1));
820 linenum[numlinenum].Number=CLine;
821 linenum[numlinenum].FileNameNumber=j;
822 linenum[numlinenum].Procedure=-1;/*To be asigned later*/
823 linenum[numlinenum].Address=Address;
829 case 'A': /*Example L:A$adq$424:40*/
830 /*No use for this one*/
833 /*The end of a procedure*/
834 case 'X': /*Example L:XG$AsciiToHex$0$0:88*/
835 sscanf(&buff[3], "%[^$] %c %[^$] %c %[^:] %c %x",
836 scope, &c, name, &c, level, &c, &Address);
838 for(k=0; k<numproc; k++)
840 if(EQ(procedure[k].name, name))
842 if(procedure[k].EndAdd==-1) procedure[k].EndAdd=Address;
855 /*Make sure each procedure has an end*/
856 for(k=0; k<(numproc-1); k++)
858 if (procedure[k].EndAdd==-1) procedure[k].EndAdd=procedure[k+1].BeginAdd-1;
860 /*Asign each line number to a procedure*/
861 for(j=0; j<numlinenum; j++)
863 for(k=0; k<numproc; k++)
865 if ( (linenum[j].Address>=procedure[k].BeginAdd) &&
866 (linenum[j].Address<=procedure[k].EndAdd) &&
867 (linenum[j].FileNameNumber==procedure[k].FileNameNumber) )
869 linenum[j].Procedure=k;
877 int hex2dec (unsigned char hex_digit)
879 if (isdigit (hex_digit))
880 return hex_digit-'0';
882 return toupper (hex_digit)-'A'+10;
885 unsigned char GetByte(char * buffer)
887 return hex2dec(buffer[0])*0x10+hex2dec(buffer[1]);
890 unsigned short GetWord(char * buffer)
892 return hex2dec(buffer[0])*0x1000+
893 hex2dec(buffer[1])*0x100+
894 hex2dec(buffer[2])*0x10+
898 int ReadHexFile(int * Begin)
903 unsigned char linesize, recordtype, rchksum, value;
904 unsigned short address;
908 /*If the hexfile is already open, close it*/
915 strcpy(ihxFileName, infn[0].PathName);
916 strcat(ihxFileName, ".ihx");
918 if ( (filein=fopen(ihxFileName, "r")) == NULL )
920 printf("Error: Can't open file `%s`.\r\n", ihxFileName);
924 ihxBuff=calloc(MEMSIZE, sizeof(unsigned char));
927 printf("Insufficient memory\n");
932 for(j=0; j<MEMSIZE; j++) ihxBuff[j]=0xff;
936 if(fgets(buffer, sizeof(buffer), filein)==NULL)
938 printf("Error reading file '%s'\n", ihxFileName);
943 linesize = GetByte(&buffer[1]);
944 address = GetWord(&buffer[3]);
945 recordtype = GetByte(&buffer[7]);
946 rchksum = GetByte(&buffer[9]+(linesize*2));
947 chksum=linesize+(address/0x100)+(address%0x100)+recordtype+rchksum;
949 if (recordtype==1) break; /*End of record*/
951 for(j=0; j<linesize; j++)
953 value=GetByte(&buffer[9]+(j*2));
955 ihxBuff[address+j]=value;
957 if(MaxAddress<(address+linesize-1)) MaxAddress=(address+linesize-1);
958 if(address<*Begin) *Begin=address;
960 if((chksum%0x100)!=0)
962 printf("ERROR: Bad checksum in file %s\n", ihxFileName);
973 void CreateAOMF51(void)
975 if((dflag) && (!rflag))
977 CollectInfoFromCDB();
981 HexSize=ReadHexFile(&HexBegin)+1;