-
1
module OrigenMemoryImage
-
# An S-record file consists of a sequence of specially formatted ASCII character strings. An S-record will
-
# be less than or equal to 78 bytes in length.
-
# The order of S-records within a file is of no significance and no particular order may be assumed.
-
#
-
# The general format of an S-record follows:
-
#
-
# +-------------------//------------------//-----------------------+
-
# | type | count | address | data | checksum |
-
# +-------------------//------------------//-----------------------+
-
#
-
# type
-
# : A char[2] field. These characters describe the type of record (S0, S1, S2, S3, S5, S7, S8, or S9).
-
#
-
# count
-
# : A char[2] field. These characters when paired and interpreted as a hexadecimal value, display
-
# the count of remaining character pairs in the record.
-
#
-
# address
-
# : A char[4,6, or 8] field. These characters grouped and interpreted as a hexadecimal value,
-
# display the address at which the data field is to be loaded into memory. The length of the field depends
-
# on the number of bytes necessary to hold the address. A 2-byte address uses 4 characters, a 3-byte
-
# address uses 6 characters, and a 4-byte address uses 8 characters.
-
#
-
# data
-
# : A char [0-64] field. These characters when paired and interpreted as hexadecimal values represent
-
# the memory loadable data or descriptive information.
-
#
-
# checksum
-
# : A char[2] field. These characters when paired and interpreted as a hexadecimal value display
-
# the least significant byte of the ones complement of the sum of the byte values represented by the pairs
-
# of characters making up the count, the address, and the data fields.
-
#
-
# Each record is terminated with a line feed. If any additional or different record terminator(s) or delay
-
# characters are needed during transmission to the target system it is the responsibility of the
-
# transmitting program to provide them.
-
#
-
# #### S0 Record
-
#
-
# The type of record is 'S0' (0x5330). The address field is unused and will be filled with zeros
-
# (0x0000). The header information within the data field is divided into the following subfields.
-
#
-
# * mname is char[20] and is the module name.
-
# * ver is char[2] and is the version number.
-
# * rev is char[2] and is the revision number.
-
# * description is char[0-36] and is a text comment.
-
#
-
# Each of the subfields is composed of ASCII bytes whose associated characters, when paired, represent one
-
# byte hexadecimal values in the case of the version and revision numbers, or represent the hexadecimal
-
# values of the ASCII characters comprising the module name and description.
-
#
-
# #### S1 Record
-
#
-
# The type of record field is 'S1' (0x5331). The address field is intrepreted as a 2-byte
-
# address. The data field is composed of memory loadable data.
-
#
-
# #### S2 Record
-
#
-
# The type of record field is 'S2' (0x5332). The address field is intrepreted as a 3-byte
-
# address. The data field is composed of memory loadable data.
-
#
-
# #### S3 Record
-
#
-
# The type of record field is 'S3' (0x5333). The address field is intrepreted as a 4-byte
-
# address. The data field is composed of memory loadable data.
-
#
-
# #### S5 Record
-
#
-
# The type of record field is 'S5' (0x5335). The address field is intrepreted as a 2-byte value
-
# and contains the count of S1, S2, and S3 records previously transmitted. There is no data field.
-
#
-
# #### S7 Record
-
#
-
# The type of record field is 'S7' (0x5337). The address field contains the starting execution
-
# address and is intrepreted as 4-byte address. There is no data field.
-
#
-
# #### S8 Record
-
#
-
# The type of record field is 'S8' (0x5338). The address field contains the starting execution
-
# address and is intrepreted as 3-byte address. There is no data field.
-
#
-
# #### S9 Record
-
#
-
# The type of record field is 'S9' (0x5339). The address field contains the starting execution
-
# address and is intrepreted as 2-byte address. There is no data field.
-
#
-
# ### Example
-
#
-
# Shown below is a typical S-record format file.
-
#
-
# S00600004844521B
-
# S1130000285F245F2212226A000424290008237C2A
-
# S11300100002000800082629001853812341001813
-
# S113002041E900084E42234300182342000824A952
-
# S107003000144ED492
-
# S5030004F8
-
# S9030000FC
-
#
-
# The file consists of one S0 record, four S1 records, one S5 record and an S9 record.
-
#
-
# The S0 record is comprised as follows:
-
#
-
# * S0 S-record type S0, indicating it is a header record.
-
# * 06 Hexadecimal 06 (decimal 6), indicating that six character pairs (or ASCII bytes) follow.
-
# * 00 00 Four character 2-byte address field, zeroes in this example.
-
# * 48 44 52 ASCII H, D, and R - "HDR".
-
# * 1B The checksum.
-
#
-
# The first S1 record is comprised as follows:
-
#
-
# * S1 S-record type S1, indicating it is a data record to be loaded at a 2-byte address.
-
# * 13 Hexadecimal 13 (decimal 19), indicating that nineteen character pairs, representing a 2 byte address,
-
# * 16 bytes of binary data, and a 1 byte checksum, follow.
-
# * 00 00 Four character 2-byte address field; hexidecimal address 0x0000, where the data which follows is to
-
# be loaded.
-
# * 28 5F 24 5F 22 12 22 6A 00 04 24 29 00 08 23 7C Sixteen character pairs representing the actual binary
-
# data.
-
# * 2A The checksum.
-
# * The second and third S1 records each contain 0x13 (19) character pairs and are ended with checksums of 13
-
# and 52, respectively. The fourth S1 record contains 07 character pairs and has a checksum of 92.
-
#
-
# The S5 record is comprised as follows:
-
#
-
# * S5 S-record type S5, indicating it is a count record indicating the number of S1 records
-
# * 03 Hexadecimal 03 (decimal 3), indicating that three character pairs follow.
-
# * 00 04 Hexadecimal 0004 (decimal 4), indicating that there are four data records previous to this record.
-
# * F8 The checksum.
-
#
-
# The S9 record is comprised as follows:
-
#
-
# * S9 S-record type S9, indicating it is a termination record.
-
# * 03 Hexadecimal 03 (decimal 3), indicating that three character pairs follow.
-
# * 00 00 The address field, hexadecimal 0 (decimal 0) indicating the starting execution address.
-
# * FC The checksum.
-
#
-
# ### Additional Notes
-
#
-
# There isn't any evidence that Motorola ever has made use of the header information within the data field
-
# of the S0 record, as described above. This must have been used by some third party vendors.
-
# This is the only place that a 78-byte limit on total record length or 64-byte limit on data length is
-
# documented. These values shouldn't be trusted for the general case.
-
#
-
# The count field can have values in the range of 0x3 (2 bytes of address + 1 byte checksum = 3, a not
-
# very useful record) to 0xff; this is the count of remaining character pairs, including checksum.
-
# If you write code to convert S-Records, you should always assume that a record can be as long as 514
-
# (decimal) characters in length (255 * 2 = 510, plus 4 characters for the type and count fields), plus
-
# any terminating character(s).
-
#
-
# That is, in establishing an input buffer in C, you would declare it to be
-
# an array of 515 chars, thus leaving room for the terminating null character.
-
1
class SRecord < Base
-
1
def self.match?(snippet)
-
29
snippet.all? do |line|
-
129
line.empty? || line =~ /^S[01235789]/
-
end
-
end
-
-
1
def start_address
-
18
if @call_order_warn
-
1
Origen.log.warn 'Previously srec.start_address returned the lowest address when to_a was called first. Now the start record is always returned if present.'
-
1
@call_order_warn = false
-
end
-
-
18
lowest_address = nil
-
18
@start_address ||= begin
-
18
lines.each do |line|
-
124
if line =~ /^S([789])(.*)/
-
16
@start_record_found = true
-
16
type = Regexp.last_match[1]
-
16
case type
-
when '7'
-
10
return line.slice(4, 8).to_i(16)
-
when '8'
-
4
return line.slice(4, 6).to_i(16)
-
when '9'
-
2
return line.slice(4, 4).to_i(16)
-
end
-
end
-
108
if line =~ /^S([1-3])/
-
90
type = Regexp.last_match[1].to_i(16) # S-record type, 1-3
-
# Set the matcher to capture x number of bytes dependent on the s-rec type
-
90
addr_matcher = '\w\w' * (1 + type)
-
90
line.strip =~ /^S\d\w\w(#{addr_matcher})(\w*)\w\w$/ # $1 = address, $2 = data
-
90
addr = Regexp.last_match[1].to_i(16)
-
90
lowest_address ||= addr
-
90
lowest_address = addr if addr < lowest_address
-
end
-
end
-
# if no start_address record is found, return lowest address
-
2
@start_record_found = false
-
2
lowest_address
-
end
-
end
-
-
1
private
-
-
# Returns an array containing all address/data from the given s-record
-
# No address manipulation is performed, that is left to the caller to apply
-
# any scrambling as required by the target system
-
1
def extract_addr_data(options = {})
-
options = {
-
9
data_width_in_bytes: 4
-
}.merge(options)
-
-
# guarantee that the start_address will be the jump address if provided
-
9
if @start_address.nil?
-
9
start_address
-
9
@call_order_warn = @start_record_found ? true : false
-
end
-
-
9
result = []
-
9
lines.each do |line|
-
# Only if the line is an s-record with data...
-
63
if line =~ /^S([1-3])/
-
45
type = Regexp.last_match[1].to_i(16) # S-record type, 1-3
-
# Set the matcher to capture x number of bytes dependent on the s-rec type
-
45
addr_matcher = '\w\w' * (1 + type)
-
45
line.strip =~ /^S\d\w\w(#{addr_matcher})(\w*)\w\w$/ # $1 = address, $2 = data
-
45
addr = Regexp.last_match[1].to_i(16)
-
45
data = Regexp.last_match[2]
-
45
data_matcher = '\w\w' * options[:data_width_in_bytes]
-
45
data.scan(/#{data_matcher}/).each do |data_packet|
-
158
result << [addr, data_packet.to_i(16)]
-
158
addr += options[:data_width_in_bytes]
-
end
-
# If a partial word is left over
-
45
if (remainder = data.length % (2 * options[:data_width_in_bytes])) > 0
-
2
if @ljust_partial_data
-
1
result << [addr, data[data.length - remainder..data.length].ljust(options[:data_width_in_bytes] * 2, '0').to_i(16)]
-
else
-
1
result << [addr, data[data.length - remainder..data.length].to_i(16)]
-
end
-
end
-
end
-
end
-
9
result
-
end
-
end
-
end