Skip to content

Instantly share code, notes, and snippets.

@MrDOS
Last active May 2, 2017 19:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MrDOS/a4ea05570acf96559919d79b7c783cbe to your computer and use it in GitHub Desktop.
Save MrDOS/a4ea05570acf96559919d79b7c783cbe to your computer and use it in GitHub Desktop.
NetBurner packcode
/******************************************************************************
* 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