// // srecord - manipulate eprom load files // Copyright (C) 2004-2007 Peter Miller // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see // . // #include #include #define O96_Mod_Hdr 0x02 #define O96_Mod_End 0x04 #define O96_Content 0x06 #define O96_Lin_Num 0x08 #define O96_Block_Def 0x0a #define O96_Block_End 0x0c #define O96_Eof 0x0e #define O96_Mod_Anc 0x10 #define O96_Loc_Sym 0x12 #define O96_Type_Def 0x14 #define O96_Pub_Def 0x16 #define O96_Ext_Def 0x18 #define O96_Res_Type_1A 0x1a #define O96_Res_Type_1C 0x1c #define O96_Res_Type_1E 0x1e #define O96_Seg_Def 0x20 #define O96_Fixup 0x22 #define O96_Res_Type_24 0x24 #define O96_Lib_Mod_Loc 0x26 #define O96_Lib_Mod_Nam 0x28 #define O96_Lib_Dic 0x2a #define O96_Res_Type_2C 0x2c #define O96_Lib_Hdr 0x2e #define O96_Res_Type_30 0x30 #define O96_Res_Type_32 0x32 #define O96_Max_Rec_Type 0x32 static const char * o96name(int x) { switch (x) { case O96_Mod_Hdr: return "Mod_Hdr"; case O96_Mod_End: return "Mod_End"; case O96_Content: return "Content"; case O96_Lin_Num: return "Lin_Num"; case O96_Block_Def: return "Block_Def"; case O96_Block_End: return "Block_End"; case O96_Eof: return "Eof"; case O96_Mod_Anc: return "Mod_Anc"; case O96_Loc_Sym: return "Loc_Sym"; case O96_Type_Def: return "Type_Def"; case O96_Pub_Def: return "Pub_Def"; case O96_Ext_Def: return "Ext_Def"; case O96_Seg_Def: return "Seg_Def"; case O96_Fixup: return "Fixup"; case O96_Lib_Mod_Loc: return "Lib_Mod_Loc"; case O96_Lib_Mod_Nam: return "Lib_Mod_Nam"; case O96_Lib_Dic: return "Lib_Dic"; case O96_Lib_Hdr: return "Lib_Hdr"; } return "unknown"; } srec_input_file_aomf::~srec_input_file_aomf() { if (current_buffer) delete [] current_buffer; } srec_input_file_aomf::srec_input_file_aomf(const string &a_filename) : srec_input_file(a_filename), current_buffer(0), current_length(0), current_maximum(0), current_pos(0), current_address(0), state(expecting_header) { } int srec_input_file_aomf::get_byte() { int c = get_char(); if (c < 0) fatal_error("premature end-of-file"); checksum_add(c); return c; } int srec_input_file_aomf::get_word() { // Little endian unsigned char n1 = get_byte(); unsigned char n2 = get_byte(); unsigned short n = (n1 | (n2 << 8)); return n; } int srec_input_file_aomf::slurp() { current_pos = 0; current_length = 0; if (peek_char() < 0) return -1; checksum_reset(); int type = get_byte(); size_t length = get_word(); if (length == 0) fatal_error("invalid record length"); --length; // includes checksum byte if (length > current_maximum) { if (current_buffer) delete [] current_buffer; while (current_maximum < length) current_maximum = current_maximum * 2 + 64; current_buffer = new unsigned char [current_maximum]; } current_length = length; for (size_t j = 0; j < length; ++j) current_buffer[j] = get_byte(); get_byte(); if (use_checksums() && checksum_get() != 0) fatal_error("checksum mismatch"); return type; } int srec_input_file_aomf::read(srec_record &record) { for (;;) { unsigned char c; switch (state) { case expecting_header: if (slurp() != O96_Mod_Hdr) fatal_error("Module Header Record expected"); state = expecting_data; if (current_length > 0) { unsigned nbytes = current_buffer[0]; // should be exactly (current_length-3) if (nbytes > current_length - 1) nbytes = current_length - 1; record = srec_record ( srec_record::type_header, 0, // address current_buffer + 1, nbytes ); } else record = srec_record(srec_record::type_header, 0, 0, 0); current_length = 0; return 1; case expecting_eof: if (slurp() >= 0) fatal_error("end-of-file expected"); return 0; case expecting_data: if (current_pos < current_length) { size_t nbytes = current_length - current_pos; if (nbytes > srec_record::max_data_length) nbytes = srec_record::max_data_length; record = srec_record ( srec_record::type_data, current_address, current_buffer + current_pos, nbytes ); current_pos += nbytes; current_address += nbytes; return 1; } c = slurp(); switch (c) { case O96_Mod_Hdr: fatal_error("too many Module Header Records"); case O96_Mod_End: state = expecting_eof; record = srec_record(srec_record::type_start_address, 0, 0, 0); return 1; case O96_Content: if (current_length < 3) fatal_error("malformed Content Record"); current_address = ( // strictly speaking, this byte should be ignored ((unsigned long)current_buffer[0] << 16) | // length is little-endian ((unsigned long)current_buffer[2] << 8) | ((unsigned long)current_buffer[1]) ); current_pos = 3; break; case 0x01: case 0x0E: case O96_Loc_Sym: case O96_Pub_Def: case O96_Ext_Def: case O96_Mod_Anc: // Ignore these silently current_length = 0; break; default: // Nothing else should be in an AOMF file, // even though it may be valid in an OMF file. warning("ignoring %s record (type 0x%02X)", o96name(c), c); current_length = 0; break; } break; } } } const char * srec_input_file_aomf::mode() const { return "rb"; } const char * srec_input_file_aomf::get_file_format_name() const { return "Intel Absolute Object Module Format (AOMF)"; }