1 /*-------------------------------------------------------------------------
2 lkaomf51.c - Create an absolute object memory format 51 file
4 Written By - Jesus Calvino-Fraga, jesusc@ieee.org (2002)
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
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.
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 -------------------------------------------------------------------------*/
28 #define EQ(A,B) !strcmp((A),(B))
29 #define MEMSIZE 0x10000
34 char PathName[PATH_MAX];
35 char ModuleName[PATH_MAX];
41 char ihxFileName[PATH_MAX];
42 char aomf51FileName[PATH_MAX];
48 int Procedure;//If the symbol belongs to a function
49 int Static; //If the symbol is only public on its file
55 _symbol * symbol=NULL;
66 _procedure * procedure=NULL;
77 _linenum * linenum=NULL;
86 _UsageType UsageType[]=
110 {"", 5} /*A typeless number?*/
113 char * UsageTypeName[]={"CODE", "XDATA", "DATA", "IDATA", "BIT", "NUMBER"};
115 unsigned char * ihxBuff=NULL;
118 int HexSize, HexBegin=0x10000;
121 void GetName(char * filepath, char * name)
124 for(j=strlen(filepath); j>0; j--)
125 if( (filepath[j-1]=='/')||(filepath[j-1]=='\\') ) break;
126 for(k=0; (filepath[j]!=0)&&(filepath[j]!='.'); j++, k++)
131 void SaveLinkedFilePath(char * filepath)
135 if((dflag) && (!rflag))
137 infn=realloc(infn, sizeof(_infn)*(numin+1));
139 strcpy(infn[numin].PathName, filepath);
140 j=strlen(infn[numin].PathName);
142 /*If there is an extension remove it*/
145 if(EQ(&infn[numin].PathName[j-4], ".rel"))
147 infn[numin].PathName[j-4]=0;
151 /*Get the module name=filename, no drive, no dir, no ext*/
152 GetName(infn[numin].PathName, infn[numin].ModuleName);
153 //printf("%s, %s\n", infn[numin].PathName, infn[numin].ModuleName);
155 /*Check if this filename is already in*/
156 for(j=0; j<numin; j++)
158 if(EQ(infn[numin].PathName, infn[j].PathName)) break;
160 if(j==numin) numin++;
201 void OutputByte(unsigned char value)
205 res = fwrite( &value, 1, 1, aomf51out );
209 void OutputWord(int value)
211 OutputByte((unsigned char)(value%0x100));
212 OutputByte((unsigned char)(value/0x100));
215 void OutputName(char * name)
218 OutputByte((unsigned char)strlen(name));
219 for(k=0; name[k]!=0; k++)
220 OutputByte((unsigned char)toupper(name[k]));
223 void OutputChkSum(void)
225 OutputByte((unsigned char)(0x100-(GlobalChkSum%0x100)));
230 void DumpForDebug (void)
232 char DumpFileName[PATH_MAX];
236 strcpy(DumpFileName, infn[0].PathName);
237 strcat(DumpFileName, ".d51");
239 DumpFile=fopen(DumpFileName, "wb");
242 printf("Couldn't create file %s\n", DumpFileName);
246 fprintf(DumpFile,"SYMBOLS:\n");
248 for(j=0; j<numsym; j++)
250 k=symbol[j].UsageType&0xf;
251 fprintf(DumpFile, "%s, %s, %s, 0x%04x, %s\n",
253 infn[symbol[j].FileNameNumber].PathName,
254 (symbol[j].Procedure>=0)?procedure[symbol[j].Procedure].name:"GLOBAL",
256 k<6?UsageTypeName[k]:"???");
259 fprintf(DumpFile,"\nPROCEDURES:\n");
260 for(j=0; j<numproc; j++)
262 fprintf(DumpFile, "%s, %s, 0x%04x-0x%04x\n",
264 infn[procedure[j].FileNameNumber].PathName,
265 procedure[j].BeginAdd,
266 procedure[j].EndAdd);
269 fprintf(DumpFile,"\nLINE NUMBERS:\n");
270 for(j=0; j<numlinenum; j++)
272 fprintf(DumpFile, "%d:0x%04x, %s -> %s\n",
275 infn[linenum[j].FileNameNumber].PathName,
276 (linenum[j].Procedure>=0)?procedure[linenum[j].Procedure].name:"I don't know");
283 void OutputAOEMF51(void)
285 int i, j, k, recsize;
286 char MHRname[0x100], Mname[0x100];
288 strcpy(aomf51FileName, infn[0].PathName);
290 aomf51out=fopen(aomf51FileName, "wb");
293 printf("Couldn't create file %s\n", aomf51FileName);
297 GetName(infn[0].PathName, MHRname);
300 /*Module header record*/
301 OutputByte(0x02);/*REC TYPE*/
302 OutputWord((strlen(MHRname)+1)+3);/*Record Length*/
303 OutputName(MHRname);/*Module Name*/
304 OutputByte(0xff);/*TRN ID: RL51?*/
308 for(j=0; j<numin; j++)
310 GetName(infn[j].PathName, Mname);
312 /*Scope Definition record: begin module block*/
313 OutputByte(0x10);/*REC TYPE*/
314 OutputWord((strlen(Mname)+1)+2);/*Record Length*/
315 OutputByte(0x00);/*BLK TYP: module block*/
316 OutputName(Mname);/*Module Name*/
319 /*Public symbols defined in this module*/
321 for(k=0; k<numsym; k++)/*Compute the record length*/
322 if ( (symbol[k].FileNameNumber==j) && (symbol[k].Address!=-1) &&
323 (symbol[k].Procedure==-1) &&
324 (symbol[k].Static==-1) ) recsize+=((strlen(symbol[k].name)+1)+5);
326 if(recsize>2) /*If there are any symbols*/
328 OutputByte(0x12); /*REC TYPE*/
329 OutputWord(recsize);/*Record Length*/
330 OutputByte(0x01); /*DEF TYPE: Public symbols*/
331 for(k=0; k<numsym; k++)
333 if ( (symbol[k].FileNameNumber==j) && (symbol[k].Address!=-1) &&
334 (symbol[k].Procedure==-1) &&
335 (symbol[k].Static==-1) )
337 OutputByte(0x00);/*SEG ID*/
338 OutputByte((unsigned char)symbol[k].UsageType);/*SYM INFO*/
339 OutputWord(symbol[k].Address);/*Offset*/
341 OutputName(symbol[k].name);/*Symbol name*/
347 /*Local symbols defined in this module*/
349 for(k=0; k<numsym; k++)/*Compute the record length*/
350 if ( (symbol[k].FileNameNumber==j) && (symbol[k].Address!=-1) &&
351 (symbol[k].Procedure==-1) &&
352 (symbol[k].Static==j) ) recsize+=((strlen(symbol[k].name)+1)+5);
354 if(recsize>2) /*If there are any symbols*/
356 OutputByte(0x12); /*REC TYPE*/
357 OutputWord(recsize);/*Record Length*/
358 OutputByte(0x00); /*DEF TYPE: Local symbols*/
359 for(k=0; k<numsym; k++)
361 if ( (symbol[k].FileNameNumber==j) && (symbol[k].Address!=-1) &&
362 (symbol[k].Procedure==-1) &&
363 (symbol[k].Static==j) )
365 OutputByte(0x00);/*SEG ID*/
366 OutputByte((unsigned char)symbol[k].UsageType);/*SYM INFO*/
367 OutputWord(symbol[k].Address);/*Offset*/
369 OutputName(symbol[k].name);/*Symbol name*/
375 /*Output the procedures of this module*/
377 for(k=0; k<numproc; k++)
379 if(procedure[k].FileNameNumber==j)
381 /*Scope Definition record: begin PROCEDURE block*/
382 OutputByte(0x10);/*REC TYPE*/
383 OutputWord((strlen(procedure[k].name)+1)+2);/*Record Length*/
384 OutputByte(0x02);/*BLK TYP: PROCEDURE block*/
385 OutputName(procedure[k].name);/*Module Name*/
389 OutputByte(0x06);/*REC TYPE*/
390 if(procedure[k].EndAdd==-1) procedure[k].EndAdd=HexSize;
391 recsize=procedure[k].EndAdd-procedure[k].BeginAdd+1+4;
392 OutputWord(recsize);/*Record Length*/
393 OutputByte(0x00);/*SEG ID*/
394 OutputWord(procedure[k].BeginAdd); /*Offset*/
395 for(i=procedure[k].BeginAdd; i<=procedure[k].EndAdd; i++)
396 OutputByte(ihxBuff[i]);
402 for(i=0; i<numsym; i++)/*Get the record length*/
403 if(symbol[i].Procedure==k)
404 recsize+=((strlen(symbol[i].name)+1)+5);
406 if(recsize>2) /*If there are any symbols*/
408 OutputByte(0x12); /*REC TYPE*/
409 OutputWord(recsize);/*Record Length*/
410 OutputByte(0x00); /*DEF TYPE: Local symbols*/
411 for(i=0; i<numsym; i++)
413 if ( (symbol[i].Procedure==k) )
415 OutputByte(0x00);/*SEG ID*/
416 OutputByte((unsigned char)symbol[i].UsageType);/*SYM INFO*/
417 OutputWord(symbol[i].Address);/*Offset*/
419 OutputName(symbol[i].name);/*Symbol name*/
427 for(i=0; i<numlinenum; i++)/*Get the record length*/
428 if(linenum[i].Procedure==k) recsize+=5;
430 if(recsize>2) /*If there are any line numbers*/
432 OutputByte(0x12); /*REC TYPE*/
433 OutputWord(recsize);/*Record Length*/
434 OutputByte(0x03); /*DEF TYPE: Line numbers*/
435 for(i=0; i<numlinenum; i++)
437 if ( (linenum[i].Procedure==k) )
439 OutputByte(0x00);/*SEG ID*/
440 OutputWord(linenum[i].Address);/*Offset*/
441 OutputWord(linenum[i].Number);/*Line Number*/
447 /*Scope Definition record: end PROCEDURE block*/
448 OutputByte(0x10);/*REC TYPE*/
449 OutputWord((strlen(procedure[k].name)+1)+2);/*Record Length*/
450 OutputByte(0x05);/*BLK TYP: PROCEDURE end block*/
451 OutputName(procedure[k].name);/*Module Name*/
456 /*Scope Definition record: end module block*/
457 OutputByte(0x10);/*REC TYPE*/
458 OutputWord((strlen(Mname)+1)+2);/*Record Length*/
459 OutputByte(0x03);/*BLK TYP: module end*/
460 OutputName(Mname);/*Module Name*/
464 /*Content records for everything that is not in the above procedures*/
465 strcpy(Mname, "OTHER_SDCC_STUF");
467 /*Scope Definition record: begin module block*/
468 OutputByte(0x10);/*REC TYPE*/
469 OutputWord((strlen(Mname)+1)+2);/*Record Length*/
470 OutputByte(0x00);/*BLK TYP: module block*/
471 OutputName(Mname);/*Module Name*/
474 for(j=-1; j<numproc; j++)
481 k=procedure[0].BeginAdd;
483 else if(j==(numproc-1))
485 i=procedure[j].EndAdd+1;
490 i=procedure[j].EndAdd+1;
491 k=procedure[j+1].BeginAdd;
494 else /*What, no procedures??? Ok, here it is the whole hex file*/
503 OutputByte(0x06);/*REC TYPE*/
504 OutputWord(k-i+4);/*Record Length*/
505 OutputByte(0x00);/*SEG ID*/
506 OutputWord(i); /*Offset*/
507 for(; i<k; i++) OutputByte(ihxBuff[i]);
512 /*Scope Definition record: end module block*/
513 OutputByte(0x10);/*REC TYPE*/
514 OutputWord((strlen(Mname)+1)+2);/*Record Length*/
515 OutputByte(0x03);/*BLK TYP: module end*/
516 OutputName(Mname);/*Module Name*/
519 /*Module end record*/
520 OutputByte(0x04);/*REC TYPE*/
521 OutputWord((strlen(MHRname)+1)+5);/*Record Length*/
522 OutputName(MHRname);/*Module Name*/
524 OutputByte(0x0f);/*REG MSK: All the register banks?*/
531 void CollectInfoFromCDB(void)
533 int i, j, k, CurrentModule;
536 char SourceName[PATH_MAX];
538 //"S:{G|F<filename>|L<functionName>}$<name>$<level>$<block>(<type info>),<Address Space>,<on Stack?>,<stack offset>"
539 char Sfmt[]="%[^$] %c %[^$] %c %[^$] %c %s";
545 char Bfmt[]="%[^)] %c %c %c %c %d %c %d";
546 char TypeInfo[0x100];
560 /*Build the source filename*/
561 strcpy(SourceName, infn[0].PathName);
562 strcat(SourceName, ".cdb");
563 CDBin=fopen(SourceName, "r");
566 printf("Couldn't open file '%s'\n", SourceName);
570 CurrentModule=0; /*Set the active module as the first one*/
574 res = fgets(buff, sizeof(buff)-1, CDBin);
577 if(!feof(CDBin)) switch(buff[0])
581 sscanf(&buff[2], "%s", name);
582 for(j=0; j<numin; j++)
583 if(EQ(infn[j].ModuleName, name)) break;
584 if(j<numin) CurrentModule=j;
588 "S:G$actual$0$0({7}ST__00010000:S),E,0,0"
589 "S:Lmain$j$1$1({2}SI:S),E,0,0"
590 "S:G$DS1306_Reset_SPI$0$0({2}DF,SV:S),C,0,0"
591 "S:G$main$0$0({2}DF,SV:S),C,0,0"
601 /*<block>(<type info>),<Address Space>,<on Stack?>,<stack offset>*/
611 case 'G': /*Global symbol*/
613 case 'L': /*Local symbol of a procedure*/
614 for(j=0; j<numproc; j++)
616 if(EQ(&scope[3], procedure[j].name)) break;
618 if(j<numproc) k=j; /*Local symbol*/
620 case 'F': /*Local symbol to a module*/
621 for(j=0; j<numin; j++)
623 if(EQ(&scope[3], infn[j].ModuleName)) break;
629 /*This symbol may have been already defined*/
630 for(j=0; j<numsym; j++)
632 if( EQ(name, symbol[j].name) &&
633 (symbol[j].Procedure==k) &&
634 (symbol[j].Static==i) ) break;
636 if(j==numsym) /*New symbol*/
638 symbol=realloc(symbol, sizeof(_symbol)*(numsym+1));
639 symbol[numsym].FileNameNumber=CurrentModule;
640 strcpy(symbol[numsym].name, name);
641 symbol[numsym].Procedure=k;
642 symbol[numsym].Static=i;
643 symbol[numsym].Address=-1;/*Collected later*/
648 case 'D': /*Code/static segment*/
649 case 'Z': /*Functions and undefined code space*/
650 symbol[numsym].UsageType=0x40;
653 case 'F': /*External ram*/
654 case 'A': /*External stack*/
655 case 'P': /*External Pdata*/
656 symbol[numsym].UsageType=0x41;
659 case 'E': /*Internal ram (lower 128) bytes*/
660 case 'I': /*SFR space*/
661 case 'R': /*Register Space*/
662 symbol[numsym].UsageType=0x42;
665 case 'B': /*Internal stack*/
666 case 'G': /*Internal ram*/
667 symbol[numsym].UsageType=0x43;
670 case 'H': /*Bit addressable*/
671 case 'J': /*SBIT space*/
672 symbol[numsym].UsageType=0x44;
676 printf("Unknown scope information for: %s, AddressSpace:%c\n", symbol[numsym].name, AddressSpace);
684 F:G$AsciiToHex$0$0({2}DF,SC:U),C,0,0,0,0,0
685 F:G$main$0$0({2}DF,SV:S),C,0,0,0,0,0 */
688 sscanf(buff, "%[^$] %c %[^$]", scope, &c, name);
689 /*The same may have been already defined */
690 for(j=0; j<numproc; j++)
692 if(EQ(name, procedure[j].name)) break;
696 procedure=realloc(procedure, sizeof(_procedure)*(numproc+1));
697 strcpy(procedure[numproc].name, name);
698 procedure[numproc].FileNameNumber=CurrentModule;
699 procedure[numproc].BeginAdd=-1;/*To be collected latter*/
700 procedure[numproc].EndAdd=-1;/*To be collected latter*/
704 /*This function name is also a global symbol*/
705 for(j=0; j<numsym; j++)/*A global symbol may have been already defined*/
707 if( EQ(name, symbol[j].name) && (symbol[j].Procedure==-1) ) break;
711 symbol=realloc(symbol, sizeof(_symbol)*(numsym+1));
712 symbol[numsym].FileNameNumber=CurrentModule;
713 strcpy(symbol[numsym].name, name);
714 symbol[numsym].UsageType=0x00;/*A procedure name symbol*/
715 symbol[numsym].Procedure=-1; /*Global symbol*/
716 symbol[numsym].Address=-1;/*Collected later*/
717 symbol[numsym].Static=-1; // o_gloom
725 case 'G': /*Example L:G$P0$0$0:80*/
726 sscanf(buff, "%[^$] %c %[^$] %c %[^:] %c %x",
727 scope, &c, name, &c, level, &c, &Address);
729 for(j=0; j<numsym; j++)
731 if(EQ(symbol[j].name, name))
733 if( (symbol[j].Address==-1) && (symbol[j].Procedure==-1) )
735 symbol[j].Address=Address;
738 /*If the symbol is the name of a procedure, the address is also
739 the begining of such procedure*/
740 if((symbol[j].UsageType&0x0f)==0x00)
742 for(k=0; k<numproc; k++)
744 if(EQ(symbol[j].name, procedure[k].name))
746 if(procedure[k].BeginAdd==-1)
747 procedure[k].BeginAdd=Address;
758 case 'F': /*Example L:Fadq$_str_2$0$0:57A*/
759 sscanf(buff, "%[^$] %c %[^$] %c %[^:] %c %x",
760 scope, &c, name, &c, level, &c, &Address);
762 for(j=0; j<numsym; j++)
764 if(EQ(symbol[j].name, name))
766 if( (symbol[j].Address==-1) ) symbol[j].Address=Address;
771 /*It could be also a static function*/
772 for(j=0; j<numproc; j++)
774 if(EQ(procedure[j].name, name))
776 if( (procedure[j].BeginAdd==-1) ) procedure[j].BeginAdd=Address;
783 case 'L': /*Example L:Lmain$j$1$1:29*/
786 L:LDS1306_Write$Value$1$1:34
787 L:LDS1306_Burst_Read$count$1$1:35
788 L:LDS1306_Burst_Read$address$1$1:36
789 L:LDS1306_Burst_Write$count$1$1:37
790 L:LDS1306_Burst_Write$address$1$1:38
792 sscanf(&buff[3], "%[^$] %c %[^$] %c %[^:] %c %x",
793 scope, &c, name, &c, level, &c, &Address);
795 for(k=0; k<numproc; k++)
797 if(EQ(procedure[k].name, scope)) break;
800 if(k<numproc) for(j=0; j<numsym; j++)
802 if( EQ(symbol[j].name, name) && (symbol[j].Procedure==k) )
804 if(symbol[j].Address==-1) symbol[j].Address=Address;
811 case 'C': /*Example L:C$adq.c$38$1$1:3E*/ /*L:C$hwinit.c$29$1$1:7AD*/
812 sscanf(&buff[4], "%[^.] %[^$] %c %d %[^:] %c %x",
813 name, level, &c, &CLine, level, &c, &Address);
815 for(j=0; j<numin; j++)
816 if(EQ(infn[j].ModuleName, name)) break;
819 /*Check if this line is already defined*/
820 for(k=0; k<numlinenum; k++)
822 if( (linenum[k].Number==CLine) &&
823 (linenum[k].FileNameNumber==j) )break;
825 if(k==numlinenum) /*New line number*/
827 linenum=realloc(linenum, sizeof(_linenum)*(numlinenum+1));
828 linenum[numlinenum].Number=CLine;
829 linenum[numlinenum].FileNameNumber=j;
830 linenum[numlinenum].Procedure=-1;/*To be asigned later*/
831 linenum[numlinenum].Address=Address;
837 case 'A': /*Example L:A$adq$424:40*/
838 /*No use for this one*/
841 /*The end of a procedure*/
842 case 'X': /*Example L:XG$AsciiToHex$0$0:88*/
843 sscanf(&buff[3], "%[^$] %c %[^$] %c %[^:] %c %x",
844 scope, &c, name, &c, level, &c, &Address);
846 for(k=0; k<numproc; k++)
848 if(EQ(procedure[k].name, name))
850 if(procedure[k].EndAdd==-1) procedure[k].EndAdd=Address;
863 /*Make sure each procedure has an end*/
864 for(k=0; k<(numproc-1); k++)
866 if (procedure[k].EndAdd==-1) procedure[k].EndAdd=procedure[k+1].BeginAdd-1;
868 /*Asign each line number to a procedure*/
869 for(j=0; j<numlinenum; j++)
871 for(k=0; k<numproc; k++)
873 if ( (linenum[j].Address>=procedure[k].BeginAdd) &&
874 (linenum[j].Address<=procedure[k].EndAdd) &&
875 (linenum[j].FileNameNumber==procedure[k].FileNameNumber) )
877 linenum[j].Procedure=k;
885 int hex2dec (unsigned char hex_digit)
887 if (isdigit (hex_digit))
888 return hex_digit-'0';
890 return toupper (hex_digit)-'A'+10;
893 unsigned char GetByte(char * buffer)
895 return hex2dec(buffer[0])*0x10+hex2dec(buffer[1]);
898 unsigned short GetWord(char * buffer)
900 return hex2dec(buffer[0])*0x1000+
901 hex2dec(buffer[1])*0x100+
902 hex2dec(buffer[2])*0x10+
906 int ReadHexFile(int * Begin)
911 unsigned char linesize, recordtype, rchksum, value;
912 unsigned short address;
916 /*If the hexfile is already open, close it*/
923 strcpy(ihxFileName, infn[0].PathName);
924 strcat(ihxFileName, ".ihx");
926 if ( (filein=fopen(ihxFileName, "r")) == NULL )
928 printf("Error: Can't open file `%s`.\r\n", ihxFileName);
932 ihxBuff=calloc(MEMSIZE, sizeof(unsigned char));
935 printf("Insufficient memory\n");
940 for(j=0; j<MEMSIZE; j++) ihxBuff[j]=0xff;
944 if(fgets(buffer, sizeof(buffer), filein)==NULL)
946 printf("Error reading file '%s'\n", ihxFileName);
951 linesize = GetByte(&buffer[1]);
952 address = GetWord(&buffer[3]);
953 recordtype = GetByte(&buffer[7]);
954 rchksum = GetByte(&buffer[9]+(linesize*2));
955 chksum=linesize+(address/0x100)+(address%0x100)+recordtype+rchksum;
957 if (recordtype==1) break; /*End of record*/
959 for(j=0; j<linesize; j++)
961 value=GetByte(&buffer[9]+(j*2));
963 ihxBuff[address+j]=value;
965 if(MaxAddress<(address+linesize-1)) MaxAddress=(address+linesize-1);
966 if(address<*Begin) *Begin=address;
968 if((chksum%0x100)!=0)
970 printf("ERROR: Bad checksum in file %s\n", ihxFileName);
981 void CreateAOMF51(void)
983 if((dflag) && (!rflag))
985 CollectInfoFromCDB();
989 HexSize=ReadHexFile(&HexBegin)+1;