/* h2b.c * Map INTEL hex data into a corresponding binary data stream * * Usage: * h2b binfile * e.g: * h2b x.bin * * Limitations (or "features" depending on your viewpoint): * 1. h2b ignores the Intel hex checksums (since the Solus files * we're working with don't complete them properly) * 2. h2b ignores the explicit data addresses in the Intel hex * datastream. Instead, bytes in the ASCII input stream are * merely converted to corresponding binary bytes in the output * stream in the order in which they occur. That is, the goal is * not a memory image file but rather a binary representation * of the input data suitable for being fed to, for example, a * disassembler. * * Notes for disassembling Solus datalogger PBS .hex files. * 1. These files are in Intel HEX format (except that the checksum * values are bogus) and consist of three sections: * a. Solus control program clearing. Typically a line * such as: * :018204000A00 * This indicates to download one byte with hex value 0x0A * to address 0x8204h. This is the Solus firmware PROGRAM_STATUS * byte which can take the following values: * 0x0A: clear * 0x0B: enabled * 0x0C: disabled * * b. Solus Z80 Control Program code. Typically a series of * lines such as: * :0A9000003E2AD721010022008CC900 * ... * Parsed out this means * * :0A 9000 00 3E.2A.D7.21.01.00.22.00.8C.C9 00 * Download 10 (0x0A) bytes starting at location 0x9000 * of type data (00 after the address is the Intel HEX * code for a data record). The data bytes are, in ascending * address order: 0x3E, 0x2A, 0xD7... 0xC9. The final trailing * 00 is the Intel HEX format checksum, but it is always 00 * in the Solus PBS .hex records. * * c. Solus control program initialization. Typically two lines * of the form: * :088204000C00902058595A0000 * :0285FA00009000 * where the first line, parsed, indicates to * :08 8204 00 0C.00.90.20.58.00 00 * download 8 (0x08) bytes starting at address 0x8204. This * is a data record (0x00) and the data bytes are: * address name val meaning * ------- ---- --- ------- * 0x8204 PROGRAM_STATUS 0X0C Control program is * loaded and disabled * (i.e: not running). * 0x8205-6 PROGRAM_ADDR 0X9000 Entry point for control * program is 0x9000 * 0x8207 PROGRAM_NAME 0x20,0x58,0x59,0x5A,0x00 * Null-terminated program * name in ASCII, in this * case " XYZ" * * and the second line, parsed, indicates * :02 85FA 00 0090 00 * address name val meaning * ------- ---- --- ------- * 0x85FA PROG_RESET_ADDR 0x9000 Address for the program * restart routine * * So, the Z80 control program instructions are all in the middle section * of the Solus .hex file. Sending those to a Z80 disassembler should give * us a human readable .ASM file. However, Intel HEX format disassemblers * usually abort if the checksum fields are bad as they are on all the Solus * files and regular binary file disassemblers require a true binary format * file. h2b takes a Solus format pseudo-Intel HEX format file and converts * it to a binary data stream suitable for processing with a binary Z80 * disassembler such as dz80 from www.inkland.org. * * Hence the steps are: * 1. Use a text editor to extract the program instructions part (the middle * section as described above) of the Solus hex file. Save this in a file, * say, "x.hex". * 2. Run h2b to convert this to a binary file, e.g: * h2b x.bin * 3. Run a Z80 disassembler to convert the bin file to asm, e.g: * dz80 x.bin x.asm * * Note: if you skip step 1 above, dz80 will still work but the asm * file will have some junk z80 code at the top and bottom since dz80 * will have mis-interpreted the program clearing and initialization bytes * as if they were Z80 instructions, which they are not. * * * Peter Berger * Brimson Laboratories * pberger@brimson.com * * V1.0 July 2002 */ #include #include #include #include #define LBUFSIZ 256 #define OFFSET 9 /* Number of bytes at the beginning of each data line */ char lbuf[LBUFSIZ]; unsigned int conv_char( char *pt ) { unsigned int ret; if( isxdigit(*pt) ) { if( isdigit(*pt) ) return( *pt - '0' ); else { return( (toupper(*pt) - 'A') + 10 ); } } else return( 0 ); } unsigned int conv_byte( char *pt ) { unsigned int ret; ret = (conv_char(pt)*16) + conv_char(pt+1); return( ret ); } void convert( char *buf ) { unsigned int cout; char *pt; unsigned int nbytes, i; /* Number of bytes in this line record */ pt = buf; nbytes = conv_byte(pt+1); /* Skip leading ':' */ /* Get the data */ for( pt=(buf+OFFSET), i=0; i