Last active
May 2, 2017 19:39
-
-
Save MrDOS/a4ea05570acf96559919d79b7c783cbe to your computer and use it in GitHub Desktop.
NetBurner packcode
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/****************************************************************************** | |
* Copyright 2005 | |
* NetBurner, Inc. | |
* 5405 Morehouse Drive, Ste 200 | |
* San Diego, CA 92121 | |
* | |
* information available at: http://www.netburner.com | |
* | |
* In addition to the rights retained by the authors, you may also use | |
* this code under the terms of the GNU public license. | |
* | |
*****************************************************************************/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
//#ifdef _WIN32 | |
//#include <io.h> | |
//#endif | |
#include <ctype.h> | |
#include <string.h> | |
#include <stdint.h> | |
#include <dirent.h> | |
#define DEFAULT_OUTPUT_BASE_ADDRESS (0xFFC04000) | |
#define DEFAULT_OUTPUT_MAX_ADDRESS (0xFFC80000) | |
typedef uint32_t DWORD; | |
//The structure that gets prepended to the output s Records. | |
//These fields need to be aligned in network order. | |
typedef struct | |
{ | |
unsigned long start_location; | |
unsigned long length; | |
unsigned long csum; | |
unsigned long rec_csum; | |
}AppRecord ; | |
void SwapOrder( unsigned long &ul ) | |
{ | |
unsigned long lv = ul; | |
unsigned char * cp1 = ( unsigned char * ) &ul; | |
unsigned char * cp2 = ( unsigned char * ) &lv; | |
cp1[0] = cp2[3]; | |
cp1[1] = cp2[2]; | |
cp1[2] = cp2[1]; | |
cp1[3] = cp2[0]; | |
} | |
unsigned char ConvertByte( const unsigned char *cp ) | |
{ | |
unsigned char rv = 0; | |
char c = toupper( *cp ); | |
if ( c >= 'A' ) | |
{ | |
rv = ( ( c + 10 - 'A' ) << 4 ); | |
} | |
else | |
{ | |
rv = ( ( c - '0' ) << 4 ); | |
} | |
c = toupper( cp[1] ); | |
if ( c >= 'A' ) | |
{ | |
rv += ( ( c + 10 - 'A' ) ); | |
} | |
else | |
{ | |
rv += ( ( c - '0' ) ); | |
} | |
return rv; | |
} | |
void ConvertFileName( char *cp ) | |
{ | |
int len = strlen( cp ); | |
if ( ( cp[0] == '/' ) && ( cp[1] == '/' ) && ( cp[3] == '/' ) ) | |
{ | |
//Convert from //x/ to x: | |
cp[0] = cp[2]; | |
cp[1] = ':'; | |
for ( int i = 3; i <= len; i++ ) | |
{ | |
if ( cp[i] == '/' ) | |
{ | |
cp[i - 1] = '\\'; | |
} | |
else | |
{ | |
cp[i - 1] = cp[i]; | |
} | |
} | |
} | |
else if ( strstr( cp, "/cygdrive/" ) == cp ) | |
{ | |
char buffer[256]; | |
strcpy( buffer + 1, cp + 10 ); | |
buffer[0] = buffer[1]; | |
buffer[1] = ':'; | |
strcpy( cp, buffer ); | |
len = strlen( cp ); | |
for ( int i = 0; i < len; i++ ) | |
{ | |
if ( cp[i] == '/' ) | |
{ | |
cp[i] = '\\'; | |
} | |
} | |
} | |
} | |
//Checks a single S record line and returns true if the check sum is ok. | |
int CheckChecksum( const unsigned char *cp ) | |
{ | |
cp += 2; | |
unsigned char len = ConvertByte( cp ); | |
unsigned char csum = len; | |
while ( len ) | |
{ | |
cp += 2; | |
csum += ConvertByte( cp ); | |
len--; | |
} | |
if ( csum == 0xff ) | |
{ | |
return 1; | |
} | |
printf( "Checksum Error %lx\n", ( int ) csum ); | |
return 0; | |
} | |
//Write mklen bytes of data out on fout as an S3 record. | |
void WriteS3( FILE *fout, unsigned long &cur_addr, unsigned char *&cp, unsigned long mklen ) | |
{ | |
fprintf( fout, "S3%02X%08X", mklen + 5, cur_addr ); | |
unsigned char * cpsum = ( unsigned char * ) &cur_addr; | |
unsigned char csum; | |
csum = ( mklen + 5 ) + cpsum[0] + cpsum[1] + cpsum[2] + cpsum[3]; | |
while ( mklen ) | |
{ | |
fprintf( fout, "%02X", ( int ) * cp ); | |
csum += *cp++; | |
cur_addr++; | |
mklen--; | |
} | |
csum = ( ~csum ); | |
fprintf( fout, "%02X\r\n", csum ); | |
} | |
//Write a start address s7 record | |
void WriteS7( FILE *fout, unsigned long &cur_addr ) | |
{ | |
//S705AAAAAAAACC | |
fprintf( fout, "S705%08X", cur_addr ); | |
unsigned char * cpsum = ( unsigned char * ) &cur_addr; | |
unsigned char csum; | |
csum = 5 + cpsum[0] + cpsum[1] + cpsum[2] + cpsum[3]; | |
csum = ( ~csum ); | |
fprintf( fout, "%02X\r\n", csum ); | |
} | |
void ReportNNDK() | |
{ | |
char stringbuffer[128]; | |
// HKEY hk = GetBaseKey(); | |
// stringbuffer[0] = 0; | |
// GetSettingString( hk, szKey, szRootName, stringbuffer, 128 ); | |
snprintf(stringbuffer,128, "%s",getenv("NBROOT")); | |
if (stringbuffer[0] == '\0') | |
{ | |
printf( "NBROOT environment variable not set." ); | |
} | |
strcat(stringbuffer,"/release_tag"); | |
FILE *fin = fopen( stringbuffer, "rb" ); | |
if ( fin == NULL ) | |
{ | |
printf( "Unable to open %s\n", stringbuffer ); | |
return; | |
} | |
fseek( fin, 0, SEEK_END ); | |
size_t len = ftell( fin ); | |
fseek( fin, 0, SEEK_SET ); | |
char *inbuf = new char[len+1]; | |
int rv = fread( inbuf, 1, len, fin ); | |
fclose( fin ); | |
inbuf[len]=0; | |
if (rv>0) | |
{ | |
char * cp=inbuf; | |
while (*cp > 20) cp++; | |
*cp=0; | |
printf("NNDK release tag version:%s\n",inbuf); | |
} | |
else | |
printf("Unable to find NNDK version\n"); | |
} | |
void ReportRam() | |
{ | |
DIR *here; | |
struct dirent *fi; | |
here = opendir("."); | |
if (here == NULL) | |
{ | |
return; | |
} | |
while ((fi = readdir(here))) | |
{ | |
size_t filename_length = strlen(fi->d_name); | |
if (filename_length >= 4 | |
&& strcasecmp(fi->d_name + filename_length - 4, ".map") == 0) | |
{ | |
break; | |
} | |
} | |
if (!fi) | |
{ | |
printf("Unable to find map file for ram info\n"); | |
} | |
FILE *fin = fopen( fi->d_name, "rb" ); | |
closedir(here); | |
fseek( fin, 0, SEEK_END ); | |
size_t len = ftell( fin ); | |
fseek( fin, 0, SEEK_SET ); | |
char *inbuf = new char[len+1]; | |
int rv = fread( inbuf, 1, len, fin ); | |
fclose( fin ); | |
inbuf[len]=0; | |
char * cp=strstr(inbuf,"\nram "); | |
if(cp) | |
{ | |
cp+=4; | |
DWORD start=0; | |
DWORD mlen=0; | |
rv=sscanf(cp,"%X %X",&start,&mlen); | |
if(rv==2) | |
{ | |
cp=strstr(inbuf,"__end"); | |
if(*cp) | |
{ | |
while(*cp!='\n') cp--; | |
if (*cp=='\n') | |
{ DWORD endpos; | |
cp++; | |
rv=sscanf(cp,"%X",&endpos); | |
if(rv==1) | |
{ | |
float percent=(float)(endpos-start)/(float)mlen; | |
printf("Used %ld bytes of %ld availible ram (%4.2f%%)\n",(endpos-start),mlen,percent*100.0); | |
return; | |
} | |
} | |
} | |
} | |
} | |
printf("Unable to parse map file for Ram usage\n"); | |
} | |
//The monster Main.... | |
int main( int argc, char **argv ) | |
{ | |
if ( argc < 3 ) | |
{ | |
printf( "Usage is %s infile outfile <optional output address> <optional maximum Address> \n", | |
argv[0] ); | |
printf( "Example: compcode infile.s19 outfile.s19 0xFFC08000 0xFFC80000\n" ); | |
return -1; | |
} | |
int n_unaccounted = 0; | |
char * InfileName; | |
char * OutfileName; | |
int bReport=false; | |
unsigned long Base_Output_Address; | |
unsigned long Max_Output_Address; | |
char * pComment = NULL; | |
Base_Output_Address = DEFAULT_OUTPUT_BASE_ADDRESS; | |
Max_Output_Address = DEFAULT_OUTPUT_MAX_ADDRESS; | |
for ( int nn = 1; nn < argc; nn++ ) | |
{ | |
if ( argv[nn][0] == '-' ) | |
{ if ( ( argv[nn][1] == 'R' ) || ( argv[nn][1] == 'r' ) ) | |
{ | |
bReport = true; | |
} | |
if ( ( argv[nn][1] == 'P' ) || ( argv[nn][1] == 'p' ) ) | |
{ | |
pComment = argv[nn] + 2; | |
} | |
} | |
else | |
{ | |
switch ( n_unaccounted++ ) | |
{ | |
case 0: | |
InfileName = argv[nn]; break; | |
case 1: | |
OutfileName = argv[nn]; break; | |
case 2: | |
{ | |
char * ep; | |
if ( ( argv[nn][0] == '0' ) && | |
( ( argv[nn][1] == 'x' ) || ( argv[nn][1] == 'X' ) ) ) | |
{ | |
Base_Output_Address = strtoul( argv[nn] + 2, &ep, 16 ); | |
} | |
else | |
{ | |
Base_Output_Address = strtoul( argv[nn], &ep, 16 ); | |
} | |
} | |
break; | |
case 3: | |
{ | |
char * ep; | |
if ( ( argv[nn][0] == '0' ) && | |
( ( argv[nn][1] == 'x' ) || ( argv[nn][1] == 'X' ) ) ) | |
{ | |
Max_Output_Address = strtoul( argv[nn] + 2, &ep, 16 ); | |
} | |
else | |
{ | |
Max_Output_Address = strtoul( argv[nn], &ep, 16 ); | |
} | |
} | |
break; | |
} | |
} | |
} | |
ConvertFileName( InfileName ); | |
ConvertFileName( OutfileName ); | |
FILE * fout = fopen( OutfileName, "wb" ); | |
FILE * fin = fopen( InfileName, "rb" ); | |
if ( fin == NULL ) | |
{ | |
printf( "Unable to open %s\n", InfileName ); | |
return -1; | |
} | |
if ( fout == NULL ) | |
{ | |
printf( "Unable to open %s\n", OutfileName ); | |
fclose( fout ); | |
return -1; | |
} | |
fseek( fin, 0, SEEK_END ); | |
size_t len = ftell( fin ); | |
fseek( fin, 0, SEEK_SET ); | |
/*********************************************************************************** | |
A Note about Memeory Allocation...... | |
This program only allocates one block of memory. | |
The block is the size of the input S record file. | |
It then converts the s record from s records to raw binary INPLACE. | |
Raw binary is allways smaller than S records by a factor > 2 | |
WARNING WARNING WARNING | |
WARNING WARNING WARNING | |
This will Fail if the s record is not presented in ORDER! | |
WARNING WARNING WARNING | |
WARNING WARNING WARNING | |
***********************************************************************************/ | |
unsigned char * realbuf = new unsigned char[len + 1+sizeof(AppRecord)]; | |
unsigned char * inbuf=realbuf+sizeof(AppRecord); | |
if ( fread( inbuf, 1, len, fin ) != 1 ) | |
{ | |
inbuf[len] = 0; | |
} | |
unsigned char * cp = inbuf; | |
unsigned char * cpout = NULL; | |
unsigned long cur_addr = 0; | |
unsigned long first_addr = 0; | |
unsigned long execution_addr = 0; | |
unsigned long codelen = 0; | |
unsigned long CodeCheckSum = 0; | |
//Convert the whole S record to one large block of RAM..... | |
while ( *cp ) | |
{ | |
while ( ( *cp ) && ( !( ( cp[0] == 'S' ) && ( cp[1] > '0' ) && ( cp[1] < '9' ) ) ) ) | |
{ | |
cp++; | |
} | |
if ( *cp ) | |
{ | |
if ( !CheckChecksum( cp ) ) | |
{ | |
printf( "S record checksum error \n" ); | |
return -1; | |
} | |
unsigned char slen = ConvertByte( cp + 2 ); | |
//Addr len | |
//s1 = 2 | |
//s2 = 3 | |
//s3 = 4 | |
if ( cp[1] < '5' ) | |
{ | |
unsigned long addr = 0; | |
int nadd = ( cp[1] - '0' ) + 1; | |
unsigned char v; | |
cp += 4; | |
slen -= 1;//Remove Checksum Count | |
//CP now points at first address byte... | |
while ( nadd ) | |
{ | |
addr = addr << 8; | |
addr |= ConvertByte( cp ); | |
cp += 2; | |
slen -= 1; | |
nadd--; | |
} | |
if ( cpout == NULL ) | |
{ | |
first_addr = cur_addr = addr; | |
cpout = inbuf; | |
} | |
else if ( cur_addr != addr ) | |
{ | |
if ( cur_addr > addr ) | |
{ | |
printf( "Srecords must be in asending order \n" ); | |
return -1; | |
} | |
printf( "Gap" ); | |
while ( cur_addr != addr ) | |
{ | |
cur_addr++; | |
*cpout++ = 0; | |
} | |
if ( cpout > cp ) | |
{ | |
printf( "Conversion Error \n" ); | |
return -1; | |
} | |
} | |
while ( slen ) | |
{ | |
*cpout++ = ConvertByte( cp ); | |
cp += 2; | |
slen--; | |
cur_addr++; | |
} | |
} | |
else | |
//Addr len | |
//s9 = 2 | |
//s8 = 3 | |
//s7 = 4 | |
if ( cp[1] >= '7' ) | |
{ | |
unsigned long addr = 0; | |
int nadd = ( '9' - cp[1] ) + 2; | |
cp += 4; | |
while ( nadd ) | |
{ | |
addr = addr << 8; | |
addr |= ConvertByte( cp ); | |
cp += 2; | |
slen -= 1; | |
nadd--; | |
} | |
execution_addr = addr; | |
} | |
}//cp was not null | |
}//while | |
//Pad the record up to 4 byte length | |
while ( cur_addr & 0x03 ) | |
{ | |
*cpout++ = 0; | |
cur_addr++; | |
} | |
*cpout = 0; | |
//At this point we have loaded the s record into ram. | |
//first_addr = the beginning address... | |
//cur_address= last address | |
//execution_addr is the address that execution should start at | |
codelen = ( cur_addr - first_addr ); | |
//Now calculate a checksum over the code block | |
//This checksum is just a DWORD sum, we could get fancy... but this is easier... | |
unsigned long * pdws = ( unsigned long * ) inbuf; | |
unsigned long * pdwe = ( unsigned long * ) cpout; | |
unsigned long nc = 0; | |
while ( pdws < pdwe ) | |
{ | |
unsigned long lv = *pdws++; | |
SwapOrder( lv ); | |
CodeCheckSum += lv; | |
nc += 4; | |
} | |
//Show what we've done so far.... | |
printf( "Block starts at %lx \n", first_addr ); | |
printf( "Block ends at %lx \n", cur_addr ); | |
printf( "Block size= %dK (%dbytes)\n", ( codelen ) / 1024 ,codelen ); | |
printf( "Execution starts at %lx \n", execution_addr ); | |
printf( "Code check sum = %lx \n",CodeCheckSum ); | |
AppRecord * par; | |
par=(AppRecord *)realbuf; | |
par->csum=CodeCheckSum; | |
par->length =codelen; | |
par->start_location=execution_addr; | |
par->rec_csum=0xAAAAAAAA-(CodeCheckSum+codelen+execution_addr); | |
int out_len; | |
printf( "Code CheckSum= %lx\n", par->csum ); | |
printf( "Struct CheckSum= %lx\n", par->rec_csum); | |
//Swap from littel endian to big endian... | |
SwapOrder(par->csum ); | |
SwapOrder(par->length ); | |
SwapOrder(par->start_location ); | |
SwapOrder(par->rec_csum ); | |
//Now we need to write out the output srecords for storage at our OUTPUT_BASE_ADDRESS | |
cp = ( unsigned char * ) par; | |
out_len = codelen+sizeof(AppRecord ); | |
cur_addr = Base_Output_Address; | |
printf( "S records output with a base address of %lx\n", Base_Output_Address ); | |
printf( "S records output with a final address of %lx\n", | |
Base_Output_Address + out_len ); | |
if ( ( Base_Output_Address + out_len ) >= Max_Output_Address ) | |
{ | |
fprintf( stderr, | |
"Maximum address of %lx exceeds memory limit of %lx\n", | |
Base_Output_Address + out_len, | |
Max_Output_Address ); | |
return -1; | |
} | |
int out_len_cpy=out_len; | |
if ( pComment ) | |
{ | |
fprintf( fout, "S0%s\r\n", pComment ); | |
} | |
while ( out_len ) | |
{ | |
int mklen; | |
if ( out_len > 16 ) | |
{ | |
mklen = 16; | |
} | |
else | |
{ | |
mklen = out_len; | |
} | |
WriteS3( fout, cur_addr, cp, mklen ); | |
out_len -= mklen; | |
} | |
printf( "About to write S7..." ); | |
WriteS7( fout, execution_addr ); | |
fclose( fout ); | |
if(bReport) | |
{ | |
printf("About to report\n"); | |
float percent=(float)out_len_cpy/(float)(Max_Output_Address-Base_Output_Address); | |
printf("\n******************************Build summary ******************************\nUsed %ld bytes of %ld availible flash (%4.2f%%)\n",out_len_cpy,(Max_Output_Address-Base_Output_Address),percent*100.0); | |
ReportRam(); | |
ReportNNDK(); | |
} | |
return 0; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment