// // srecord - manipulate eprom load files // Copyright (C) 2001, 2002, 2006, 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 srec_output_file_fastload::srec_output_file_fastload() : srec_output_file(), line_length(0), address(~0uL), column(0), bytes_since_checksum(0), max_since_checksum(0), prev_was_command(false) { line_length_set(80); } srec_output_file_fastload::srec_output_file_fastload( const std::string &a_filename) : srec_output_file(a_filename), line_length(0), address(~0uL), column(0), bytes_since_checksum(0), max_since_checksum(0), prev_was_command(false) { line_length_set(80); } srec_output_file_fastload::~srec_output_file_fastload() { } void srec_output_file_fastload::put_number(unsigned long n, int min_digits) { unsigned char buffer[20]; unsigned char *bp = buffer; while (n || min_digits > 0) { *bp++ = n & 63; --min_digits; n >>= 6; } static char digit[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr" "stuvwxyz0123456789,."; while (bp > buffer) { put_char(digit[*--bp]); ++column; } } static int number_width(unsigned long n) { int result = 0; while (n) { result++; n >>= 6; } return result; } void srec_output_file_fastload::put_command(int c, unsigned long n, int ndigits) { int width = number_width(n); if (width < ndigits) width = ndigits; width += 2; if (column + width > line_length) { put_char('\n'); column = 0; } put_char('/'); put_char(c); column += 2; put_number(n, ndigits); prev_was_command = true; } void srec_output_file_fastload::write(const srec_record &record) { int j; switch (record.get_type()) { case srec_record::type_header: // This format can't do header records break; case srec_record::type_data: if (record.get_length() < 1) return; if (record.get_address() != address) { address = record.get_address(); put_command('A', address, 3); } if (record.is_all_zero()) { // These bytes don't add anything to the checksum. put_command('Z', record.get_length(), 2); address += record.get_length(); break; } for (j = 0; j + 3 <= record.get_length(); j += 3) { if (bytes_since_checksum >= max_since_checksum) { put_command('C', checksum_get16(), 3); put_command('K', 0, 2); checksum_reset(); bytes_since_checksum = 0; } unsigned char n1 = record.get_data(j); checksum_add(n1); unsigned char n2 = record.get_data(j + 1); checksum_add(n2); unsigned char n3 = record.get_data(j + 2); checksum_add(n3); unsigned long n = (n1 << 16) | (n2 << 8) | n3; if (column + 4 > line_length || prev_was_command) { put_char('\n'); column = 0; } put_number(n, 4); bytes_since_checksum += 3; prev_was_command = false; } for (; j < record.get_length(); ++j) { unsigned char n = record.get_data(j); checksum_add(n); put_command('B', (unsigned long)n, 2); bytes_since_checksum++; } address += record.get_length(); break; case srec_record::type_data_count: // ignore break; case srec_record::type_start_address: if (data_only_flag) break; if (bytes_since_checksum) { put_command('C', checksum_get16(), 3); bytes_since_checksum = 0; } if (address != record.get_address()) { address = record.get_address(); put_command('A', address, 3); } put_command('E', 0, 2); put_char('\n'); column = 0; break; case srec_record::type_unknown: fatal_error("can't write unknown record type"); } } void srec_output_file_fastload::line_length_set(int linlen) { line_length = linlen; if (line_length < 10) line_length = 10; // Don't go bigger than this, or you get undetectable errors. enum { MAX = 256 }; int bytes_on_last_line = ((line_length - 9) / 4) * 3; if (bytes_on_last_line > MAX) bytes_on_last_line = MAX; else if (bytes_on_last_line < 0) bytes_on_last_line = 0; int bytes_on_other_lines = (line_length / 4) * 3; if (bytes_on_other_lines > MAX) bytes_on_other_lines = MAX; else if (bytes_on_other_lines < 1) bytes_on_other_lines = 1; int num_other_lines = (MAX - bytes_on_last_line) / bytes_on_other_lines; max_since_checksum = num_other_lines * bytes_on_other_lines + bytes_on_last_line; } void srec_output_file_fastload::address_length_set(int) { // ignore } int srec_output_file_fastload::preferred_block_size_get() const { // Prefer a multiple of 3 return ((srec_record::max_data_length / 3) * 3); } const char * srec_output_file_fastload::format_name() const { return "FastLoad"; }