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 -------------------------------------------------------------------------*/
26 #define EQ(A,B) !strcmp((A),(B))
27 #define MEMSIZE 0x10000
31 char PathName[PATH_MAX];
32 char ModuleName[PATH_MAX];
38 char ihxFileName[PATH_MAX];
39 char aomf51FileName[PATH_MAX];
45 int Procedure;//If the symbol belongs to a function
46 int Static; //If the symbol is only public on its file
52 _symbol * symbol=NULL;
63 _procedure * procedure=NULL;
74 _linenum * linenum=NULL;
83 _UsageType UsageType[]=
101 {"", 5} /*A typeless number?*/
104 char * UsageTypeName[]={"CODE", "XDATA", "DATA", "IDATA", "BIT", "NUMBER"};
106 unsigned char * ihxBuff=NULL;
109 int HexSize, HexBegin=0x10000;
112 void GetName(char * filepath, char * name)
115 for(j=strlen(filepath); j>0; j--)
116 if( (filepath[j-1]=='/')||(filepath[j-1]=='\\') ) break;
117 for(k=0; (filepath[j]!=0)&&(filepath[j]!='.'); j++, k++)
122 void SaveLinkedFilePath(char * filepath)
128 infn=realloc(infn, sizeof(_infn)*(numin+1));
130 strcpy(infn[numin].PathName, filepath);
131 j=strlen(infn[numin].PathName);
133 /*If there is an extension remove it*/
136 if(EQ(&infn[numin].PathName[j-4], ".rel"))
138 infn[numin].PathName[j-4]=0;
142 /*Get the module name=filename, no drive, no dir, no ext*/
143 GetName(infn[numin].PathName, infn[numin].ModuleName);
144 //printf("%s, %s\n", infn[numin].PathName, infn[numin].ModuleName);
187 void OutputByte(unsigned char value)
190 fwrite( &value, 1, 1, aomf51out );
193 void OutputWord(int value)
195 OutputByte((unsigned char)(value%0x100));
196 OutputByte((unsigned char)(value/0x100));
199 void OutputName(char * name)
202 OutputByte((unsigned char)strlen(name));
203 for(k=0; name[k]!=0; k++)
204 OutputByte((unsigned char)toupper(name[k]));
207 void OutputChkSum(void)
209 OutputByte((unsigned char)(0x100-(GlobalChkSum%0x100)));
213 void DumpForDebug (void)
215 char DumpFileName[PATH_MAX];
219 strcpy(DumpFileName, infn[0].PathName);
220 strcat(DumpFileName, ".d51");
222 DumpFile=fopen(DumpFileName, "wb");
225 printf("Couldn't create file %s\n", DumpFileName);
229 fprintf(DumpFile,"SYMBOLS:\n");
231 for(j=0; j<numsym; j++)
233 fprintf(DumpFile, "%s, %s, %s, 0x%04x, %s\n",
235 infn[symbol[j].FileNameNumber].PathName,
236 (symbol[j].Procedure>=0)?procedure[symbol[j].Procedure].name:"GLOBAL",
238 UsageTypeName[symbol[j].UsageType&0xf]);
241 fprintf(DumpFile,"\nPROCEDURES:\n");
242 for(j=0; j<numproc; j++)
244 fprintf(DumpFile, "%s, %s, 0x%04x-0x%04x\n",
246 infn[procedure[j].FileNameNumber].PathName,
247 procedure[j].BeginAdd,
248 procedure[j].EndAdd);
251 fprintf(DumpFile,"\nLINE NUMBERS:\n");
252 for(j=0; j<numlinenum; j++)
254 fprintf(DumpFile, "%d:0x%04x, %s -> %s\n",
257 infn[linenum[j].FileNameNumber].PathName,
258 (linenum[j].Procedure>=0)?procedure[linenum[j].Procedure].name:"I don't know");
264 void OutputAOEMF51(void)
266 int i, j, k, recsize;
267 char MHRname[0x100], Mname[0x100];
269 strcpy(aomf51FileName, infn[0].PathName);
271 aomf51out=fopen(aomf51FileName, "wb");
274 printf("Couldn't create file %s\n", aomf51FileName);
278 GetName(infn[0].PathName, MHRname);
281 /*Module header record*/
282 OutputByte(0x02);/*REC TYPE*/
283 OutputWord((strlen(MHRname)+1)+3);/*Record Length*/
284 OutputName(MHRname);/*Module Name*/
285 OutputByte(0xff);/*TRN ID: RL51?*/
289 for(j=0; j<numin; j++)
291 GetName(infn[j].PathName, Mname);
293 /*Scope Definition record: begin module block*/
294 OutputByte(0x10);/*REC TYPE*/
295 OutputWord((strlen(Mname)+1)+2);/*Record Length*/
296 OutputByte(0x00);/*BLK TYP: module block*/
297 OutputName(Mname);/*Module Name*/
300 /*Public symbols defined in this module*/
302 for(k=0; k<numsym; k++)/*Compute the record length*/
303 if ( (symbol[k].FileNameNumber==j) &&
304 (symbol[k].Procedure==-1) &&
305 (symbol[k].Static==-1) ) recsize+=((strlen(symbol[k].name)+1)+5);
307 if(recsize>2) /*If there are any symbols*/
309 OutputByte(0x12); /*REC TYPE*/
310 OutputWord(recsize);/*Record Length*/
311 OutputByte(0x01); /*DEF TYPE: Public symbols*/
312 for(k=0; k<numsym; k++)
314 if ( (symbol[k].FileNameNumber==j) &&
315 (symbol[k].Procedure==-1) &&
316 (symbol[k].Static==-1) )
318 OutputByte(0x00);/*SEG ID*/
319 OutputByte((unsigned char)symbol[k].UsageType);/*SYM INFO*/
320 OutputWord(symbol[k].Address);/*Offset*/
322 OutputName(symbol[k].name);/*Symbol name*/
328 /*Local symbols defined in this module*/
330 for(k=0; k<numsym; k++)/*Compute the record length*/
331 if ( (symbol[k].FileNameNumber==j) &&
332 (symbol[k].Procedure==-1) &&
333 (symbol[k].Static==j) ) recsize+=((strlen(symbol[k].name)+1)+5);
335 if(recsize>2) /*If there are any symbols*/
337 OutputByte(0x12); /*REC TYPE*/
338 OutputWord(recsize);/*Record Length*/
339 OutputByte(0x00); /*DEF TYPE: Local symbols*/
340 for(k=0; k<numsym; k++)
342 if ( (symbol[k].FileNameNumber==j) &&
343 (symbol[k].Procedure==-1) &&
344 (symbol[k].Static==j) )
346 OutputByte(0x00);/*SEG ID*/
347 OutputByte((unsigned char)symbol[k].UsageType);/*SYM INFO*/
348 OutputWord(symbol[k].Address);/*Offset*/
350 OutputName(symbol[k].name);/*Symbol name*/
356 /*Output the procedures of this module*/
358 for(k=0; k<numproc; k++)
360 if(procedure[k].FileNameNumber==j)
362 /*Scope Definition record: begin PROCEDURE block*/
363 OutputByte(0x10);/*REC TYPE*/
364 OutputWord((strlen(procedure[k].name)+1)+2);/*Record Length*/
365 OutputByte(0x02);/*BLK TYP: PROCEDURE block*/
366 OutputName(procedure[k].name);/*Module Name*/
370 OutputByte(0x06);/*REC TYPE*/
371 recsize=procedure[k].EndAdd-procedure[k].BeginAdd+1+4;
372 OutputWord(recsize);/*Record Length*/
373 OutputByte(0x00);/*SEG ID*/
374 OutputWord(procedure[k].BeginAdd); /*Offset*/
375 for(i=procedure[k].BeginAdd; i<=procedure[k].EndAdd; i++)
376 OutputByte(ihxBuff[i]);
382 for(i=0; i<numsym; i++)/*Get the record length*/
383 if(symbol[i].Procedure==k)
384 recsize+=((strlen(symbol[i].name)+1)+5);
386 if(recsize>2) /*If there are any symbols*/
388 OutputByte(0x12); /*REC TYPE*/
389 OutputWord(recsize);/*Record Length*/
390 OutputByte(0x00); /*DEF TYPE: Local symbols*/
391 for(i=0; i<numsym; i++)
393 if ( (symbol[i].Procedure==k) )
395 OutputByte(0x00);/*SEG ID*/
396 OutputByte((unsigned char)symbol[i].UsageType);/*SYM INFO*/
397 OutputWord(symbol[i].Address);/*Offset*/
399 OutputName(symbol[i].name);/*Symbol name*/
407 for(i=0; i<numlinenum; i++)/*Get the record length*/
408 if(linenum[i].Procedure==k) recsize+=5;
410 if(recsize>2) /*If there are any line numbers*/
412 OutputByte(0x12); /*REC TYPE*/
413 OutputWord(recsize);/*Record Length*/
414 OutputByte(0x03); /*DEF TYPE: Line numbers*/
415 for(i=0; i<numlinenum; i++)
417 if ( (linenum[i].Procedure==k) )
419 OutputByte(0x00);/*SEG ID*/
420 OutputWord(linenum[i].Address);/*Offset*/
421 OutputWord(linenum[i].Number);/*Line Number*/
427 /*Scope Definition record: end PROCEDURE block*/
428 OutputByte(0x10);/*REC TYPE*/
429 OutputWord((strlen(procedure[k].name)+1)+2);/*Record Length*/
430 OutputByte(0x05);/*BLK TYP: PROCEDURE end block*/
431 OutputName(procedure[k].name);/*Module Name*/
436 /*Scope Definition record: end module block*/
437 OutputByte(0x10);/*REC TYPE*/
438 OutputWord((strlen(Mname)+1)+2);/*Record Length*/
439 OutputByte(0x03);/*BLK TYP: module end*/
440 OutputName(Mname);/*Module Name*/
444 /*Content records for everything that is not in the above procedures*/
445 strcpy(Mname, "OTHER_SDCC_STUF");
447 /*Scope Definition record: begin module block*/
448 OutputByte(0x10);/*REC TYPE*/
449 OutputWord((strlen(Mname)+1)+2);/*Record Length*/
450 OutputByte(0x00);/*BLK TYP: module block*/
451 OutputName(Mname);/*Module Name*/
454 for(j=-1; j<numproc; j++)
459 k=procedure[0].BeginAdd;
461 else if(j==(numproc-1))
463 i=procedure[j].EndAdd+1;
468 i=procedure[j].EndAdd+1;
469 k=procedure[j+1].BeginAdd;
475 OutputByte(0x06);/*REC TYPE*/
476 OutputWord(k-i+4);/*Record Length*/
477 OutputByte(0x00);/*SEG ID*/
478 OutputWord(i); /*Offset*/
479 for(; i<k; i++) OutputByte(ihxBuff[i]);
484 /*Scope Definition record: end module block*/
485 OutputByte(0x10);/*REC TYPE*/
486 OutputWord((strlen(Mname)+1)+2);/*Record Length*/
487 OutputByte(0x03);/*BLK TYP: module end*/
488 OutputName(Mname);/*Module Name*/
491 /*Module end record*/
492 OutputByte(0x04);/*REC TYPE*/
493 OutputWord((strlen(MHRname)+1)+5);/*Record Length*/
494 OutputName(MHRname);/*Module Name*/
496 OutputByte(0x0f);/*REG MSK: All the register banks?*/
503 void CollectInfoFromCDB(void)
505 int i, j, k, CurrentModule;
508 char SourceName[PATH_MAX];
510 //"S:{G|F<filename>|L<functionName>}$<name>$<level>$<block>(<type info>),<Address Space>,<on Stack?>,<stack offset>"
511 char Sfmt[]="%[^$] %c %[^$] %c %[^$] %c %s";
517 char Bfmt[]="%[^)] %c %c %c %c %d %c %d";
518 char TypeInfo[0x100];
532 /*Build the source filename*/
533 strcpy(SourceName, infn[0].PathName);
534 strcat(SourceName, ".cdb");
535 CDBin=fopen(SourceName, "r");
538 printf("Couldn't open file '%s'\n", SourceName);
541 CurrentModule=0; /*Set the active module as the first one*/
544 fgets(buff, sizeof(buff)-1, CDBin);
546 if(!feof(CDBin)) switch(buff[0])
550 sscanf(&buff[2], "%s", name);
551 for(j=0; j<numin; j++)
552 if(EQ(infn[j].ModuleName, name)) break;
553 if(j<numin) CurrentModule=j;
557 "S:G$actual$0$0({7}ST__00010000:S),E,0,0"
558 "S:Lmain$j$1$1({2}SI:S),E,0,0"
568 /*<block>(<type info>),<Address Space>,<on Stack?>,<stack offset>*/
578 case 'G': /*Global symbol*/
580 case 'L': /*Local symbol of a procedure*/
581 for(j=0; j<numproc; j++)
583 if(EQ(&scope[3], procedure[j].name)) break;
585 if(j<numproc) k=j; /*Local symbol*/
587 case 'F': /*Local symbol to a module*/
588 for(j=0; j<numin; j++)
590 if(EQ(&scope[3], infn[j].ModuleName)) break;
596 /*This symbol may have been already defined*/
597 for(j=0; j<numsym; j++)
599 if( EQ(name, symbol[j].name) &&
600 (symbol[j].Procedure==k) &&
601 (symbol[j].Static==i) ) break;
603 if(j==numsym) /*New symbol*/
605 symbol=realloc(symbol, sizeof(_symbol)*(numsym+1));
606 symbol[numsym].FileNameNumber=CurrentModule;
607 strcpy(symbol[numsym].name, name);
608 symbol[numsym].Procedure=k;
609 symbol[numsym].Static=i;
610 symbol[numsym].Address=-1;/*Collected later*/
615 case 'D': /*Code/static segment*/
616 symbol[numsym].UsageType=0x40;
619 case 'F': /*External ram*/
620 case 'A': /*External stack*/
621 symbol[numsym].UsageType=0x41;
624 case 'E': /*Internal ram (lower 128) bytes*/
625 case 'I': /*SFR space*/
626 symbol[numsym].UsageType=0x42;
629 case 'B': /*Internal stack*/
630 case 'G': /*Internal ram*/
631 symbol[numsym].UsageType=0x43;
634 case 'H': /*Bit addressable*/
635 case 'J': /*SBIT space*/
636 symbol[numsym].UsageType=0x44;
644 F:G$AsciiToHex$0$0({2}DF,SC:U),C,0,0,0,0,0
645 F:G$main$0$0({2}DF,SV:S),C,0,0,0,0,0 */
648 sscanf(buff, "%[^$] %c %[^$]", scope, &c, name);
649 /*The same may have been already defined */
650 for(j=0; j<numproc; j++)
652 if(EQ(name, procedure[j].name)) break;
656 procedure=realloc(procedure, sizeof(_procedure)*(numproc+1));
657 strcpy(procedure[numproc].name, name);
658 procedure[numproc].FileNameNumber=CurrentModule;
659 procedure[numproc].BeginAdd=-1;/*To be collected latter*/
660 procedure[numproc].EndAdd=-1;/*To be collected latter*/
664 /*This function name is also a global symbol*/
665 for(j=0; j<numsym; j++)/*A global symbol may have been already defined*/
667 if( EQ(name, symbol[j].name) && (symbol[j].Procedure==-1) ) break;
671 symbol=realloc(symbol, sizeof(_symbol)*(numsym+1));
672 symbol[numsym].FileNameNumber=CurrentModule;
673 strcpy(symbol[numsym].name, name);
674 symbol[numsym].UsageType=0x00;/*A procedure name symbol*/
675 symbol[numsym].Procedure=-1; /*Global symbol*/
676 symbol[numsym].Address=-1;/*Collected later*/
685 case 'G': /*Example L:G$P0$0$0:80*/
686 sscanf(buff, "%[^$] %c %[^$] %c %[^:] %c %x",
687 scope, &c, name, &c, level, &c, &Address);
689 for(j=0; j<numsym; j++)
691 if(EQ(symbol[j].name, name))
693 if( (symbol[j].Address==-1) && (symbol[j].Procedure==-1) )
695 symbol[j].Address=Address;
696 /*If the symbol is the name of a procedure, the address is also
697 the begining of such procedure*/
698 if(symbol[j].UsageType==0x00)
700 for(k=0; k<numproc; k++)
702 if(EQ(symbol[j].name, procedure[k].name))
704 if(procedure[k].BeginAdd==-1)
705 procedure[k].BeginAdd=Address;
716 case 'F': /*Example L:Fadq$_str_2$0$0:57A*/
717 sscanf(buff, "%[^$] %c %[^$] %c %[^:] %c %x",
718 scope, &c, name, &c, level, &c, &Address);
720 for(j=0; j<numsym; j++)
722 if(EQ(symbol[j].name, name))
724 if( (symbol[j].Address==-1) ) symbol[j].Address=Address;
730 case 'L': /*Example L:Lmain$j$1$1:29*/
733 L:LDS1306_Write$Value$1$1:34
734 L:LDS1306_Burst_Read$count$1$1:35
735 L:LDS1306_Burst_Read$address$1$1:36
736 L:LDS1306_Burst_Write$count$1$1:37
737 L:LDS1306_Burst_Write$address$1$1:38
739 sscanf(&buff[3], "%[^$] %c %[^$] %c %[^:] %c %x",
740 scope, &c, name, &c, level, &c, &Address);
742 for(k=0; k<numproc; k++)
744 if(EQ(procedure[k].name, scope)) break;
747 if(k<numproc) for(j=0; j<numsym; j++)
749 if( EQ(symbol[j].name, name) && (symbol[j].Procedure==k) )
751 if(symbol[j].Address==-1) symbol[j].Address=Address;
758 case 'C': /*Example L:C$adq.c$38$1$1:3E*/ /*L:C$hwinit.c$29$1$1:7AD*/
759 sscanf(&buff[4], "%[^.] %[^$] %c %d %[^:] %c %x",
760 name, level, &c, &CLine, level, &c, &Address);
762 for(j=0; j<numin; j++)
763 if(EQ(infn[j].ModuleName, name)) break;
766 /*Check if this line is already defined*/
767 for(k=0; k<numlinenum; k++)
769 if( (linenum[k].Number==CLine) &&
770 (linenum[k].FileNameNumber==j) )break;
772 if(k==numlinenum) /*New line number*/
774 linenum=realloc(linenum, sizeof(_linenum)*(numlinenum+1));
775 linenum[numlinenum].Number=CLine;
776 linenum[numlinenum].FileNameNumber=j;
777 linenum[numlinenum].Procedure=-1;/*To be asigned later*/
778 linenum[numlinenum].Address=Address;
784 case 'A': /*Example L:A$adq$424:40*/
785 /*No use for this one*/
788 /*The end of a procedure*/
789 case 'X': /*Example L:XG$AsciiToHex$0$0:88*/
790 sscanf(&buff[3], "%[^$] %c %[^$] %c %[^:] %c %x",
791 scope, &c, name, &c, level, &c, &Address);
793 for(k=0; k<numproc; k++)
795 if(EQ(procedure[k].name, name))
797 if(procedure[k].EndAdd==-1) procedure[k].EndAdd=Address;
810 /*Asign each line number to a procedure*/
811 for(j=0; j<numlinenum; j++)
813 for(k=0; k<numproc; k++)
815 if ( (linenum[j].Address>=procedure[k].BeginAdd) &&
816 (linenum[j].Address<=procedure[k].EndAdd) &&
817 (linenum[j].FileNameNumber==procedure[k].FileNameNumber) )
819 linenum[j].Procedure=k;
827 int hex2dec (char hex_digit)
830 j=toupper(hex_digit)-'0';
835 unsigned char GetByte(char * buffer)
837 return hex2dec(buffer[0])*0x10+hex2dec(buffer[1]);
840 unsigned short GetWord(char * buffer)
842 return hex2dec(buffer[0])*0x1000+
843 hex2dec(buffer[1])*0x100+
844 hex2dec(buffer[2])*0x10+
848 int ReadHexFile(int * Begin)
853 unsigned char linesize, recordtype, rchksum, value;
854 unsigned short address;
858 /*If the hexfile is already open, close it*/
865 strcpy(ihxFileName, infn[0].PathName);
866 strcat(ihxFileName, ".ihx");
868 if ( (filein=fopen(ihxFileName, "r")) == NULL )
870 printf("Error: Can't open file `%s`.\r\n", ihxFileName);
874 ihxBuff=calloc(MEMSIZE, sizeof(unsigned char));
877 printf("Insufficient memory\n");
882 for(j=0; j<MEMSIZE; j++) ihxBuff[j]=0xff;
886 if(fgets(buffer, sizeof(buffer), filein)==NULL)
888 printf("Error reading file '%s'\n", ihxFileName);
893 linesize = GetByte(&buffer[1]);
894 address = GetWord(&buffer[3]);
895 recordtype = GetByte(&buffer[7]);
896 rchksum = GetByte(&buffer[9]+(linesize*2));
897 chksum=linesize+(address/0x100)+(address%0x100)+recordtype+rchksum;
899 if (recordtype==1) break; /*End of record*/
901 for(j=0; j<linesize; j++)
903 value=GetByte(&buffer[9]+(j*2));
905 ihxBuff[address+j]=value;
907 if(MaxAddress<(address+linesize-1)) MaxAddress=(address+linesize-1);
908 if(address<*Begin) *Begin=address;
910 if((chksum%0x100)!=0)
912 printf("ERROR: Bad checksum in file %s\n", ihxFileName);
923 void CreateAOMF51(void)
927 CollectInfoFromCDB();
929 HexSize=ReadHexFile(&HexBegin)+1;