//
// srecord - manipulate eprom load files
// Copyright (C) 2001-2003, 2005-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_input_file_fastload::srec_input_file_fastload(const string &a_file_name) :
srec_input_file(a_file_name),
seen_some_input(false),
address(0)
{
}
srec_input_file_fastload::~srec_input_file_fastload()
{
}
int
srec_input_file_fastload::get_digit()
{
int c = get_char();
switch (c)
{
case 'A': return 0;
case 'B': return 1;
case 'C': return 2;
case 'D': return 3;
case 'E': return 4;
case 'F': return 5;
case 'G': return 6;
case 'H': return 7;
case 'I': return 8;
case 'J': return 9;
case 'K': return 10;
case 'L': return 11;
case 'M': return 12;
case 'N': return 13;
case 'O': return 14;
case 'P': return 15;
case 'Q': return 16;
case 'R': return 17;
case 'S': return 18;
case 'T': return 19;
case 'U': return 20;
case 'V': return 21;
case 'W': return 22;
case 'X': return 23;
case 'Y': return 24;
case 'Z': return 25;
case 'a': return 26;
case 'b': return 27;
case 'c': return 28;
case 'd': return 29;
case 'e': return 30;
case 'f': return 31;
case 'g': return 32;
case 'h': return 33;
case 'i': return 34;
case 'j': return 35;
case 'k': return 36;
case 'l': return 37;
case 'm': return 38;
case 'n': return 39;
case 'o': return 40;
case 'p': return 41;
case 'q': return 42;
case 'r': return 43;
case 's': return 44;
case 't': return 45;
case 'u': return 46;
case 'v': return 47;
case 'w': return 48;
case 'x': return 49;
case 'y': return 50;
case 'z': return 51;
case '0': return 52;
case '1': return 53;
case '2': return 54;
case '3': return 55;
case '4': return 56;
case '5': return 57;
case '6': return 58;
case '7': return 59;
case '8': return 60;
case '9': return 61;
case ',': return 62;
case '.': return 63;
}
get_char_undo(c);
return -1;
}
unsigned long
srec_input_file_fastload::get_number(int min_digits, int max_digits)
{
unsigned long result = 0;
for (int ndigits = 0; ndigits < max_digits; ++ndigits)
{
int c = get_digit();
if (c < 0)
{
if (ndigits < min_digits)
{
fatal_error("base-64 number expected (%d < %d)",
ndigits, min_digits);
}
break;
}
result = (result << 6) | c;
}
return result;
}
void
srec_input_file_fastload::expect_white_space()
{
switch (peek_char())
{
case -1:
case ' ':
case '\t':
case '\r':
case '\n':
case '/':
break;
default:
fatal_error("white space expected");
}
}
int
srec_input_file_fastload::read_inner(srec_record &record)
{
unsigned long n;
unsigned char data[srec_record::max_data_length];
unsigned long data_address = address;
srec_record::type_t type;
int data_length = 0;
unsigned char the_byte;
for (;;)
{
switch (peek_char())
{
case -1:
return 0;
case ' ':
case '\t':
case '\n':
case '\r':
get_char();
break;
case '/':
if (data_length > 0)
{
got_a_record:
record =
srec_record
(
srec_record::type_data,
data_address,
data,
data_length
);
return 1;
}
get_char();
switch (get_char())
{
case 'A':
address = get_number(1, 6);
expect_white_space();
data_address = address;
break;
case 'B':
the_byte = get_number(1, 6);
data[data_length++] = the_byte;
checksum_add(the_byte);
expect_white_space();
address++;
// assert(data_length == 1);
break;
case 'C':
n = get_number(1, 6);
if (use_checksums())
{
int csum = checksum_get16();
if ((int)n != csum)
{
fatal_error("checksum mismatch (%04X != %04X)",
(int)n, csum);
}
}
expect_white_space();
break;
case 'E':
get_number(1, 6);
seek_to_end();
type = srec_record::type_start_address;
record = srec_record(type, address, 0, 0);
return 1;
case 'K':
get_number(1, 6);
expect_white_space();
checksum_reset();
break;
case 'S':
// Ignore symbols
for (;;)
{
int c = get_char();
if (c < 0)
fatal_error("end-of-input in symbol");
if (c == ',')
break;
}
get_number(1, 6);
expect_white_space();
break;
case 'Z':
n = get_number(1, 6);
expect_white_space();
if (n >= srec_record::max_data_length)
fatal_error("clearing too many bytes (%lu)", n);
memset(data, 0, n);
type = srec_record::type_data;
record = srec_record(type, address, data, n);
address += n;
return 1;
default:
fatal_error("unknown command");
}
break;
default:
if (data_length + 3 > srec_record::max_data_length)
goto got_a_record;
n = get_number(4, 4);
the_byte = n >> 16;
data[data_length++] = the_byte;
checksum_add(the_byte);
the_byte = n >> 8;
data[data_length++] = the_byte;
checksum_add(the_byte);
the_byte = n;
data[data_length++] = the_byte;
checksum_add(the_byte);
address += 3;
break;
}
}
}
int
srec_input_file_fastload::read(srec_record &record)
{
if (!read_inner(record))
{
if (!seen_some_input)
fatal_error("file contains no data");
return 0;
}
seen_some_input = true;
return 1;
}
const char *
srec_input_file_fastload::get_file_format_name()
const
{
return "LSI Logic Fast Load";
}