origen_memory_image 0.7.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/config/application.rb +87 -87
- data/config/boot.rb +1 -1
- data/config/commands.rb +62 -62
- data/config/version.rb +8 -8
- data/lib/origen_memory_image.rb +43 -40
- data/lib/origen_memory_image/base.rb +88 -88
- data/lib/origen_memory_image/binary.rb +69 -69
- data/lib/origen_memory_image/hex.rb +56 -56
- data/lib/origen_memory_image/intel_hex.rb +98 -0
- data/lib/origen_memory_image/s_record.rb +212 -212
- data/templates/web/index.md.erb +179 -164
- data/templates/web/layouts/_basic.html.erb +16 -16
- data/templates/web/partials/_navbar.html.erb +22 -22
- data/templates/web/release_notes.md.erb +5 -5
- metadata +4 -3
@@ -1,69 +1,69 @@
|
|
1
|
-
module OrigenMemoryImage
|
2
|
-
class Binary < Base
|
3
|
-
def self.match?(file, snippet = false)
|
4
|
-
if snippet
|
5
|
-
file.all? { |l| l.strip =~ /^[01]*$/ }
|
6
|
-
else
|
7
|
-
# detect whether the data is mostly not alpha numeric
|
8
|
-
filedata = (File.read(file, 256) || '')
|
9
|
-
(filedata.gsub(/\s+/, '').gsub(/\w/, '').length.to_f / filedata.length.to_f) > 0.3
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
# Always returns 0 since binary files do not contain addresses
|
14
|
-
def start_address
|
15
|
-
0
|
16
|
-
end
|
17
|
-
|
18
|
-
def create_test_file
|
19
|
-
data = [
|
20
|
-
0x1EE0021C, 0x22401BE0, 0x021C2243,
|
21
|
-
0x18E0021C, 0x5A780A43, 0x03E0034B,
|
22
|
-
0xF7215A78, 0x0A400020, 0x22E08442,
|
23
|
-
0x22D31FE0, 0x84421FD9, 0x1CE08442,
|
24
|
-
0x002B20D1, 0x03E0012A, 0x01D1002B,
|
25
|
-
0x1BD00223, 0x2340022A, 0x02D1002B,
|
26
|
-
0x15D103E0, 0x032A01D1, 0x78000018,
|
27
|
-
0x7C000018, 0x82000018, 0x88000018
|
28
|
-
]
|
29
|
-
data = data.map { |d| d.to_s(2).rjust(32, '0') }.join
|
30
|
-
File.open('examples/bin1.bin', 'wb') do |output|
|
31
|
-
output.write [data].pack('B*')
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
private
|
36
|
-
|
37
|
-
# Returns an array containing all address/data from the given s-record
|
38
|
-
# No address manipulation is performed, that is left to the caller to apply
|
39
|
-
# any scrambling as required by the target system
|
40
|
-
def extract_addr_data(options = {})
|
41
|
-
options = {
|
42
|
-
data_width_in_bytes: 4
|
43
|
-
}.merge(options)
|
44
|
-
|
45
|
-
result = []
|
46
|
-
width = options[:data_width_in_bytes]
|
47
|
-
address = 0
|
48
|
-
|
49
|
-
if file
|
50
|
-
raw = File.binread(file)
|
51
|
-
bytes = raw.unpack('C*')
|
52
|
-
else
|
53
|
-
raw = lines.map(&:strip).join
|
54
|
-
bytes = raw.scan(/.{1,8}/).map { |s| s.to_i(2) }
|
55
|
-
end
|
56
|
-
|
57
|
-
bytes.each_slice(width) do |d|
|
58
|
-
v = 0
|
59
|
-
width.times do |i|
|
60
|
-
v |= d[i] << ((width - 1 - i) * 8) if d[i]
|
61
|
-
end
|
62
|
-
result << [address, v]
|
63
|
-
address += width
|
64
|
-
end
|
65
|
-
|
66
|
-
result
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
1
|
+
module OrigenMemoryImage
|
2
|
+
class Binary < Base
|
3
|
+
def self.match?(file, snippet = false)
|
4
|
+
if snippet
|
5
|
+
file.all? { |l| l.strip =~ /^[01]*$/ }
|
6
|
+
else
|
7
|
+
# detect whether the data is mostly not alpha numeric
|
8
|
+
filedata = (File.read(file, 256) || '')
|
9
|
+
(filedata.gsub(/\s+/, '').gsub(/\w/, '').length.to_f / filedata.length.to_f) > 0.3
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# Always returns 0 since binary files do not contain addresses
|
14
|
+
def start_address
|
15
|
+
0
|
16
|
+
end
|
17
|
+
|
18
|
+
def create_test_file
|
19
|
+
data = [
|
20
|
+
0x1EE0021C, 0x22401BE0, 0x021C2243,
|
21
|
+
0x18E0021C, 0x5A780A43, 0x03E0034B,
|
22
|
+
0xF7215A78, 0x0A400020, 0x22E08442,
|
23
|
+
0x22D31FE0, 0x84421FD9, 0x1CE08442,
|
24
|
+
0x002B20D1, 0x03E0012A, 0x01D1002B,
|
25
|
+
0x1BD00223, 0x2340022A, 0x02D1002B,
|
26
|
+
0x15D103E0, 0x032A01D1, 0x78000018,
|
27
|
+
0x7C000018, 0x82000018, 0x88000018
|
28
|
+
]
|
29
|
+
data = data.map { |d| d.to_s(2).rjust(32, '0') }.join
|
30
|
+
File.open('examples/bin1.bin', 'wb') do |output|
|
31
|
+
output.write [data].pack('B*')
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
# Returns an array containing all address/data from the given s-record
|
38
|
+
# No address manipulation is performed, that is left to the caller to apply
|
39
|
+
# any scrambling as required by the target system
|
40
|
+
def extract_addr_data(options = {})
|
41
|
+
options = {
|
42
|
+
data_width_in_bytes: 4
|
43
|
+
}.merge(options)
|
44
|
+
|
45
|
+
result = []
|
46
|
+
width = options[:data_width_in_bytes]
|
47
|
+
address = 0
|
48
|
+
|
49
|
+
if file
|
50
|
+
raw = File.binread(file)
|
51
|
+
bytes = raw.unpack('C*')
|
52
|
+
else
|
53
|
+
raw = lines.map(&:strip).join
|
54
|
+
bytes = raw.scan(/.{1,8}/).map { |s| s.to_i(2) }
|
55
|
+
end
|
56
|
+
|
57
|
+
bytes.each_slice(width) do |d|
|
58
|
+
v = 0
|
59
|
+
width.times do |i|
|
60
|
+
v |= d[i] << ((width - 1 - i) * 8) if d[i]
|
61
|
+
end
|
62
|
+
result << [address, v]
|
63
|
+
address += width
|
64
|
+
end
|
65
|
+
|
66
|
+
result
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -1,56 +1,56 @@
|
|
1
|
-
module OrigenMemoryImage
|
2
|
-
class Hex < Base
|
3
|
-
def self.match?(snippet)
|
4
|
-
snippet.any? do |line|
|
5
|
-
# Match a line like:
|
6
|
-
# @180000F0
|
7
|
-
line =~ /^@[0-9a-fA-F]+\s?$/
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
# The first in the file will be taken as the start address
|
12
|
-
def start_address
|
13
|
-
@start_address ||= begin
|
14
|
-
lines.each do |line|
|
15
|
-
if line =~ /^@([0-9a-fA-F]+)\s?$/
|
16
|
-
return Regexp.last_match[1].to_i(16)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
private
|
23
|
-
|
24
|
-
# Returns an array containing all address/data from the given s-record
|
25
|
-
# No address manipulation is performed, that is left to the caller to apply
|
26
|
-
# any scrambling as required by the target system
|
27
|
-
def extract_addr_data(options = {})
|
28
|
-
options = {
|
29
|
-
data_width_in_bytes: 4
|
30
|
-
}.merge(options)
|
31
|
-
|
32
|
-
result = []
|
33
|
-
lines.each do |line|
|
34
|
-
# Only if the line is an s-record with data...
|
35
|
-
if line =~ /^@([0-9a-fA-F]+)\s?$/
|
36
|
-
@address = Regexp.last_match[1].to_i(16)
|
37
|
-
elsif line =~ /^[0-9A-F]/
|
38
|
-
unless @address
|
39
|
-
fail "Hex data found before an @address line in #{file_name}"
|
40
|
-
end
|
41
|
-
data = line.strip.gsub(/\s/, '')
|
42
|
-
data_matcher = '\w\w' * options[:data_width_in_bytes]
|
43
|
-
data.scan(/#{data_matcher}/).each do |data_packet|
|
44
|
-
result << [@address, data_packet.to_i(16)]
|
45
|
-
@address += options[:data_width_in_bytes]
|
46
|
-
end
|
47
|
-
# If a partial word is left over
|
48
|
-
if (remainder = data.length % (2 * options[:data_width_in_bytes])) > 0
|
49
|
-
result << [@address, data[data.length - remainder..data.length].to_i(16)]
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
result
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
1
|
+
module OrigenMemoryImage
|
2
|
+
class Hex < Base
|
3
|
+
def self.match?(snippet)
|
4
|
+
snippet.any? do |line|
|
5
|
+
# Match a line like:
|
6
|
+
# @180000F0
|
7
|
+
line =~ /^@[0-9a-fA-F]+\s?$/
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
# The first in the file will be taken as the start address
|
12
|
+
def start_address
|
13
|
+
@start_address ||= begin
|
14
|
+
lines.each do |line|
|
15
|
+
if line =~ /^@([0-9a-fA-F]+)\s?$/
|
16
|
+
return Regexp.last_match[1].to_i(16)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
# Returns an array containing all address/data from the given s-record
|
25
|
+
# No address manipulation is performed, that is left to the caller to apply
|
26
|
+
# any scrambling as required by the target system
|
27
|
+
def extract_addr_data(options = {})
|
28
|
+
options = {
|
29
|
+
data_width_in_bytes: 4
|
30
|
+
}.merge(options)
|
31
|
+
|
32
|
+
result = []
|
33
|
+
lines.each do |line|
|
34
|
+
# Only if the line is an s-record with data...
|
35
|
+
if line =~ /^@([0-9a-fA-F]+)\s?$/
|
36
|
+
@address = Regexp.last_match[1].to_i(16)
|
37
|
+
elsif line =~ /^[0-9A-F]/
|
38
|
+
unless @address
|
39
|
+
fail "Hex data found before an @address line in #{file_name}"
|
40
|
+
end
|
41
|
+
data = line.strip.gsub(/\s/, '')
|
42
|
+
data_matcher = '\w\w' * options[:data_width_in_bytes]
|
43
|
+
data.scan(/#{data_matcher}/).each do |data_packet|
|
44
|
+
result << [@address, data_packet.to_i(16)]
|
45
|
+
@address += options[:data_width_in_bytes]
|
46
|
+
end
|
47
|
+
# If a partial word is left over
|
48
|
+
if (remainder = data.length % (2 * options[:data_width_in_bytes])) > 0
|
49
|
+
result << [@address, data[data.length - remainder..data.length].to_i(16)]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
result
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
module OrigenMemoryImage
|
2
|
+
class IntelHex < Base
|
3
|
+
def self.match?(snippet)
|
4
|
+
snippet.all? do |line|
|
5
|
+
line.empty? || line =~ /^:[0-9A-Fa-f]{6}0[0-5]/
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def start_address
|
10
|
+
@start_address ||= begin
|
11
|
+
addrs = []
|
12
|
+
lines.each do |line|
|
13
|
+
line = line.strip
|
14
|
+
if start_linear_address?(line)
|
15
|
+
addrs << decode(line)[:data].to_i(16)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
addrs.last || 0
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def decode(line)
|
25
|
+
d = {}
|
26
|
+
if line =~ /^:([0-9A-Fa-f]{2})([0-9A-Fa-f]{4})(\d\d)([0-9A-Fa-f]+)([0-9A-Fa-f]{2})$/
|
27
|
+
d[:byte_count] = Regexp.last_match(1).to_i(16)
|
28
|
+
d[:address] = Regexp.last_match(2).to_i(16)
|
29
|
+
d[:record_type] = Regexp.last_match(3).to_i(16)
|
30
|
+
d[:data] = Regexp.last_match(4)
|
31
|
+
d[:checksum] = Regexp.last_match(5).to_i(16)
|
32
|
+
else
|
33
|
+
fail "Invalid line encountered in Intel Hex formatted file: #{line}"
|
34
|
+
end
|
35
|
+
d
|
36
|
+
end
|
37
|
+
|
38
|
+
def data?(line)
|
39
|
+
!!(line =~ /^:[0-9A-Fa-f]{6}00/)
|
40
|
+
end
|
41
|
+
|
42
|
+
def extended_segment_address?(line)
|
43
|
+
!!(line =~ /^:[0-9A-Fa-f]{6}02/)
|
44
|
+
end
|
45
|
+
|
46
|
+
def extended_linear_address?(line)
|
47
|
+
!!(line =~ /^:[0-9A-Fa-f]{6}04/)
|
48
|
+
end
|
49
|
+
|
50
|
+
def start_linear_address?(line)
|
51
|
+
!!(line =~ /^:[0-9A-Fa-f]{6}05/)
|
52
|
+
end
|
53
|
+
|
54
|
+
def upper_addr
|
55
|
+
@upper_addr || 0
|
56
|
+
end
|
57
|
+
|
58
|
+
def segment_address
|
59
|
+
@segment_address || 0
|
60
|
+
end
|
61
|
+
|
62
|
+
# Returns an array containing all address/data from the given s-record
|
63
|
+
# No address manipulation is performed, that is left to the caller to apply
|
64
|
+
# any scrambling as required by the target system
|
65
|
+
def extract_addr_data(options = {})
|
66
|
+
options = {
|
67
|
+
data_width_in_bytes: 4
|
68
|
+
}.merge(options)
|
69
|
+
|
70
|
+
result = []
|
71
|
+
lines.each do |line|
|
72
|
+
line = line.strip
|
73
|
+
if extended_segment_address?(line)
|
74
|
+
@segment_address = decode(line)[:data].to_i(16) * 16
|
75
|
+
|
76
|
+
elsif extended_linear_address?(line)
|
77
|
+
@upper_addr = (decode(line)[:data].to_i(16)) << 16
|
78
|
+
|
79
|
+
elsif data?(line)
|
80
|
+
d = decode(line)
|
81
|
+
addr = d[:address] + segment_address + upper_addr
|
82
|
+
|
83
|
+
data = d[:data]
|
84
|
+
data_matcher = '\w\w' * options[:data_width_in_bytes]
|
85
|
+
data.scan(/#{data_matcher}/).each do |data_packet|
|
86
|
+
result << [addr, data_packet.to_i(16)]
|
87
|
+
addr += options[:data_width_in_bytes]
|
88
|
+
end
|
89
|
+
# If a partial word is left over
|
90
|
+
if (remainder = data.length % (2 * options[:data_width_in_bytes])) > 0
|
91
|
+
result << [addr, data[data.length - remainder..data.length].to_i(16)]
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
result
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -1,212 +1,212 @@
|
|
1
|
-
module OrigenMemoryImage
|
2
|
-
# An S-record file consists of a sequence of specially formatted ASCII character strings. An S-record will
|
3
|
-
# be less than or equal to 78 bytes in length.
|
4
|
-
# The order of S-records within a file is of no significance and no particular order may be assumed.
|
5
|
-
#
|
6
|
-
# The general format of an S-record follows:
|
7
|
-
#
|
8
|
-
# +-------------------//------------------//-----------------------+
|
9
|
-
# | type | count | address | data | checksum |
|
10
|
-
# +-------------------//------------------//-----------------------+
|
11
|
-
#
|
12
|
-
# type
|
13
|
-
# : A char[2] field. These characters describe the type of record (S0, S1, S2, S3, S5, S7, S8, or S9).
|
14
|
-
#
|
15
|
-
# count
|
16
|
-
# : A char[2] field. These characters when paired and interpreted as a hexadecimal value, display
|
17
|
-
# the count of remaining character pairs in the record.
|
18
|
-
#
|
19
|
-
# address
|
20
|
-
# : A char[4,6, or 8] field. These characters grouped and interpreted as a hexadecimal value,
|
21
|
-
# display the address at which the data field is to be loaded into memory. The length of the field depends
|
22
|
-
# on the number of bytes necessary to hold the address. A 2-byte address uses 4 characters, a 3-byte
|
23
|
-
# address uses 6 characters, and a 4-byte address uses 8 characters.
|
24
|
-
#
|
25
|
-
# data
|
26
|
-
# : A char [0-64] field. These characters when paired and interpreted as hexadecimal values represent
|
27
|
-
# the memory loadable data or descriptive information.
|
28
|
-
#
|
29
|
-
# checksum
|
30
|
-
# : A char[2] field. These characters when paired and interpreted as a hexadecimal value display
|
31
|
-
# the least significant byte of the ones complement of the sum of the byte values represented by the pairs
|
32
|
-
# of characters making up the count, the address, and the data fields.
|
33
|
-
#
|
34
|
-
# Each record is terminated with a line feed. If any additional or different record terminator(s) or delay
|
35
|
-
# characters are needed during transmission to the target system it is the responsibility of the
|
36
|
-
# transmitting program to provide them.
|
37
|
-
#
|
38
|
-
# #### S0 Record
|
39
|
-
#
|
40
|
-
# The type of record is 'S0' (0x5330). The address field is unused and will be filled with zeros
|
41
|
-
# (0x0000). The header information within the data field is divided into the following subfields.
|
42
|
-
#
|
43
|
-
# * mname is char[20] and is the module name.
|
44
|
-
# * ver is char[2] and is the version number.
|
45
|
-
# * rev is char[2] and is the revision number.
|
46
|
-
# * description is char[0-36] and is a text comment.
|
47
|
-
#
|
48
|
-
# Each of the subfields is composed of ASCII bytes whose associated characters, when paired, represent one
|
49
|
-
# byte hexadecimal values in the case of the version and revision numbers, or represent the hexadecimal
|
50
|
-
# values of the ASCII characters comprising the module name and description.
|
51
|
-
#
|
52
|
-
# #### S1 Record
|
53
|
-
#
|
54
|
-
# The type of record field is 'S1' (0x5331). The address field is intrepreted as a 2-byte
|
55
|
-
# address. The data field is composed of memory loadable data.
|
56
|
-
#
|
57
|
-
# #### S2 Record
|
58
|
-
#
|
59
|
-
# The type of record field is 'S2' (0x5332). The address field is intrepreted as a 3-byte
|
60
|
-
# address. The data field is composed of memory loadable data.
|
61
|
-
#
|
62
|
-
# #### S3 Record
|
63
|
-
#
|
64
|
-
# The type of record field is 'S3' (0x5333). The address field is intrepreted as a 4-byte
|
65
|
-
# address. The data field is composed of memory loadable data.
|
66
|
-
#
|
67
|
-
# #### S5 Record
|
68
|
-
#
|
69
|
-
# The type of record field is 'S5' (0x5335). The address field is intrepreted as a 2-byte value
|
70
|
-
# and contains the count of S1, S2, and S3 records previously transmitted. There is no data field.
|
71
|
-
#
|
72
|
-
# #### S7 Record
|
73
|
-
#
|
74
|
-
# The type of record field is 'S7' (0x5337). The address field contains the starting execution
|
75
|
-
# address and is intrepreted as 4-byte address. There is no data field.
|
76
|
-
#
|
77
|
-
# #### S8 Record
|
78
|
-
#
|
79
|
-
# The type of record field is 'S8' (0x5338). The address field contains the starting execution
|
80
|
-
# address and is intrepreted as 3-byte address. There is no data field.
|
81
|
-
#
|
82
|
-
# #### S9 Record
|
83
|
-
#
|
84
|
-
# The type of record field is 'S9' (0x5339). The address field contains the starting execution
|
85
|
-
# address and is intrepreted as 2-byte address. There is no data field.
|
86
|
-
#
|
87
|
-
# ### Example
|
88
|
-
#
|
89
|
-
# Shown below is a typical S-record format file.
|
90
|
-
#
|
91
|
-
# S00600004844521B
|
92
|
-
# S1130000285F245F2212226A000424290008237C2A
|
93
|
-
# S11300100002000800082629001853812341001813
|
94
|
-
# S113002041E900084E42234300182342000824A952
|
95
|
-
# S107003000144ED492
|
96
|
-
# S5030004F8
|
97
|
-
# S9030000FC
|
98
|
-
#
|
99
|
-
# The file consists of one S0 record, four S1 records, one S5 record and an S9 record.
|
100
|
-
#
|
101
|
-
# The S0 record is comprised as follows:
|
102
|
-
#
|
103
|
-
# * S0 S-record type S0, indicating it is a header record.
|
104
|
-
# * 06 Hexadecimal 06 (decimal 6), indicating that six character pairs (or ASCII bytes) follow.
|
105
|
-
# * 00 00 Four character 2-byte address field, zeroes in this example.
|
106
|
-
# * 48 44 52 ASCII H, D, and R - "HDR".
|
107
|
-
# * 1B The checksum.
|
108
|
-
#
|
109
|
-
# The first S1 record is comprised as follows:
|
110
|
-
#
|
111
|
-
# * S1 S-record type S1, indicating it is a data record to be loaded at a 2-byte address.
|
112
|
-
# * 13 Hexadecimal 13 (decimal 19), indicating that nineteen character pairs, representing a 2 byte address,
|
113
|
-
# * 16 bytes of binary data, and a 1 byte checksum, follow.
|
114
|
-
# * 00 00 Four character 2-byte address field; hexidecimal address 0x0000, where the data which follows is to
|
115
|
-
# be loaded.
|
116
|
-
# * 28 5F 24 5F 22 12 22 6A 00 04 24 29 00 08 23 7C Sixteen character pairs representing the actual binary
|
117
|
-
# data.
|
118
|
-
# * 2A The checksum.
|
119
|
-
# * The second and third S1 records each contain 0x13 (19) character pairs and are ended with checksums of 13
|
120
|
-
# and 52, respectively. The fourth S1 record contains 07 character pairs and has a checksum of 92.
|
121
|
-
#
|
122
|
-
# The S5 record is comprised as follows:
|
123
|
-
#
|
124
|
-
# * S5 S-record type S5, indicating it is a count record indicating the number of S1 records
|
125
|
-
# * 03 Hexadecimal 03 (decimal 3), indicating that three character pairs follow.
|
126
|
-
# * 00 04 Hexadecimal 0004 (decimal 4), indicating that there are four data records previous to this record.
|
127
|
-
# * F8 The checksum.
|
128
|
-
#
|
129
|
-
# The S9 record is comprised as follows:
|
130
|
-
#
|
131
|
-
# * S9 S-record type S9, indicating it is a termination record.
|
132
|
-
# * 03 Hexadecimal 03 (decimal 3), indicating that three character pairs follow.
|
133
|
-
# * 00 00 The address field, hexadecimal 0 (decimal 0) indicating the starting execution address.
|
134
|
-
# * FC The checksum.
|
135
|
-
#
|
136
|
-
# ### Additional Notes
|
137
|
-
#
|
138
|
-
# There isn't any evidence that Motorola ever has made use of the header information within the data field
|
139
|
-
# of the S0 record, as described above. This must have been used by some third party vendors.
|
140
|
-
# This is the only place that a 78-byte limit on total record length or 64-byte limit on data length is
|
141
|
-
# documented. These values shouldn't be trusted for the general case.
|
142
|
-
#
|
143
|
-
# The count field can have values in the range of 0x3 (2 bytes of address + 1 byte checksum = 3, a not
|
144
|
-
# very useful record) to 0xff; this is the count of remaining character pairs, including checksum.
|
145
|
-
# If you write code to convert S-Records, you should always assume that a record can be as long as 514
|
146
|
-
# (decimal) characters in length (255 * 2 = 510, plus 4 characters for the type and count fields), plus
|
147
|
-
# any terminating character(s).
|
148
|
-
#
|
149
|
-
# That is, in establishing an input buffer in C, you would declare it to be
|
150
|
-
# an array of 515 chars, thus leaving room for the terminating null character.
|
151
|
-
class SRecord < Base
|
152
|
-
def self.match?(snippet)
|
153
|
-
snippet.all? do |line|
|
154
|
-
line.empty? || line =~ /^S[01235789]/
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
def start_address
|
159
|
-
@start_address ||= begin
|
160
|
-
lines.each do |line|
|
161
|
-
if line =~ /^S([789])(.*)/
|
162
|
-
type = Regexp.last_match[1]
|
163
|
-
case type
|
164
|
-
when '7'
|
165
|
-
return line.slice(4, 8).to_i(16)
|
166
|
-
when '8'
|
167
|
-
return line.slice(4, 6).to_i(16)
|
168
|
-
when '9'
|
169
|
-
return line.slice(4, 4).to_i(16)
|
170
|
-
end
|
171
|
-
end
|
172
|
-
end
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
private
|
177
|
-
|
178
|
-
# Returns an array containing all address/data from the given s-record
|
179
|
-
# No address manipulation is performed, that is left to the caller to apply
|
180
|
-
# any scrambling as required by the target system
|
181
|
-
def extract_addr_data(options = {})
|
182
|
-
options = {
|
183
|
-
data_width_in_bytes: 4
|
184
|
-
}.merge(options)
|
185
|
-
|
186
|
-
result = []
|
187
|
-
lines.each do |line|
|
188
|
-
# Only if the line is an s-record with data...
|
189
|
-
if line =~ /^S([1-3])/
|
190
|
-
type = Regexp.last_match[1].to_i(16) # S-record type, 1-3
|
191
|
-
# Set the matcher to capture x number of bytes dependent on the s-rec type
|
192
|
-
addr_matcher = '\w\w' * (1 + type)
|
193
|
-
line.strip =~ /^S\d\w\w(#{addr_matcher})(\w*)\w\w$/ # $1 = address, $2 = data
|
194
|
-
addr = Regexp.last_match[1].to_i(16)
|
195
|
-
@start_address ||= addr
|
196
|
-
@start_address = addr if addr < @start_address
|
197
|
-
data = Regexp.last_match[2]
|
198
|
-
data_matcher = '\w\w' * options[:data_width_in_bytes]
|
199
|
-
data.scan(/#{data_matcher}/).each do |data_packet|
|
200
|
-
result << [addr, data_packet.to_i(16)]
|
201
|
-
addr += options[:data_width_in_bytes]
|
202
|
-
end
|
203
|
-
# If a partial word is left over
|
204
|
-
if (remainder = data.length % (2 * options[:data_width_in_bytes])) > 0
|
205
|
-
result << [addr, data[data.length - remainder..data.length].to_i(16)]
|
206
|
-
end
|
207
|
-
end
|
208
|
-
end
|
209
|
-
result
|
210
|
-
end
|
211
|
-
end
|
212
|
-
end
|
1
|
+
module OrigenMemoryImage
|
2
|
+
# An S-record file consists of a sequence of specially formatted ASCII character strings. An S-record will
|
3
|
+
# be less than or equal to 78 bytes in length.
|
4
|
+
# The order of S-records within a file is of no significance and no particular order may be assumed.
|
5
|
+
#
|
6
|
+
# The general format of an S-record follows:
|
7
|
+
#
|
8
|
+
# +-------------------//------------------//-----------------------+
|
9
|
+
# | type | count | address | data | checksum |
|
10
|
+
# +-------------------//------------------//-----------------------+
|
11
|
+
#
|
12
|
+
# type
|
13
|
+
# : A char[2] field. These characters describe the type of record (S0, S1, S2, S3, S5, S7, S8, or S9).
|
14
|
+
#
|
15
|
+
# count
|
16
|
+
# : A char[2] field. These characters when paired and interpreted as a hexadecimal value, display
|
17
|
+
# the count of remaining character pairs in the record.
|
18
|
+
#
|
19
|
+
# address
|
20
|
+
# : A char[4,6, or 8] field. These characters grouped and interpreted as a hexadecimal value,
|
21
|
+
# display the address at which the data field is to be loaded into memory. The length of the field depends
|
22
|
+
# on the number of bytes necessary to hold the address. A 2-byte address uses 4 characters, a 3-byte
|
23
|
+
# address uses 6 characters, and a 4-byte address uses 8 characters.
|
24
|
+
#
|
25
|
+
# data
|
26
|
+
# : A char [0-64] field. These characters when paired and interpreted as hexadecimal values represent
|
27
|
+
# the memory loadable data or descriptive information.
|
28
|
+
#
|
29
|
+
# checksum
|
30
|
+
# : A char[2] field. These characters when paired and interpreted as a hexadecimal value display
|
31
|
+
# the least significant byte of the ones complement of the sum of the byte values represented by the pairs
|
32
|
+
# of characters making up the count, the address, and the data fields.
|
33
|
+
#
|
34
|
+
# Each record is terminated with a line feed. If any additional or different record terminator(s) or delay
|
35
|
+
# characters are needed during transmission to the target system it is the responsibility of the
|
36
|
+
# transmitting program to provide them.
|
37
|
+
#
|
38
|
+
# #### S0 Record
|
39
|
+
#
|
40
|
+
# The type of record is 'S0' (0x5330). The address field is unused and will be filled with zeros
|
41
|
+
# (0x0000). The header information within the data field is divided into the following subfields.
|
42
|
+
#
|
43
|
+
# * mname is char[20] and is the module name.
|
44
|
+
# * ver is char[2] and is the version number.
|
45
|
+
# * rev is char[2] and is the revision number.
|
46
|
+
# * description is char[0-36] and is a text comment.
|
47
|
+
#
|
48
|
+
# Each of the subfields is composed of ASCII bytes whose associated characters, when paired, represent one
|
49
|
+
# byte hexadecimal values in the case of the version and revision numbers, or represent the hexadecimal
|
50
|
+
# values of the ASCII characters comprising the module name and description.
|
51
|
+
#
|
52
|
+
# #### S1 Record
|
53
|
+
#
|
54
|
+
# The type of record field is 'S1' (0x5331). The address field is intrepreted as a 2-byte
|
55
|
+
# address. The data field is composed of memory loadable data.
|
56
|
+
#
|
57
|
+
# #### S2 Record
|
58
|
+
#
|
59
|
+
# The type of record field is 'S2' (0x5332). The address field is intrepreted as a 3-byte
|
60
|
+
# address. The data field is composed of memory loadable data.
|
61
|
+
#
|
62
|
+
# #### S3 Record
|
63
|
+
#
|
64
|
+
# The type of record field is 'S3' (0x5333). The address field is intrepreted as a 4-byte
|
65
|
+
# address. The data field is composed of memory loadable data.
|
66
|
+
#
|
67
|
+
# #### S5 Record
|
68
|
+
#
|
69
|
+
# The type of record field is 'S5' (0x5335). The address field is intrepreted as a 2-byte value
|
70
|
+
# and contains the count of S1, S2, and S3 records previously transmitted. There is no data field.
|
71
|
+
#
|
72
|
+
# #### S7 Record
|
73
|
+
#
|
74
|
+
# The type of record field is 'S7' (0x5337). The address field contains the starting execution
|
75
|
+
# address and is intrepreted as 4-byte address. There is no data field.
|
76
|
+
#
|
77
|
+
# #### S8 Record
|
78
|
+
#
|
79
|
+
# The type of record field is 'S8' (0x5338). The address field contains the starting execution
|
80
|
+
# address and is intrepreted as 3-byte address. There is no data field.
|
81
|
+
#
|
82
|
+
# #### S9 Record
|
83
|
+
#
|
84
|
+
# The type of record field is 'S9' (0x5339). The address field contains the starting execution
|
85
|
+
# address and is intrepreted as 2-byte address. There is no data field.
|
86
|
+
#
|
87
|
+
# ### Example
|
88
|
+
#
|
89
|
+
# Shown below is a typical S-record format file.
|
90
|
+
#
|
91
|
+
# S00600004844521B
|
92
|
+
# S1130000285F245F2212226A000424290008237C2A
|
93
|
+
# S11300100002000800082629001853812341001813
|
94
|
+
# S113002041E900084E42234300182342000824A952
|
95
|
+
# S107003000144ED492
|
96
|
+
# S5030004F8
|
97
|
+
# S9030000FC
|
98
|
+
#
|
99
|
+
# The file consists of one S0 record, four S1 records, one S5 record and an S9 record.
|
100
|
+
#
|
101
|
+
# The S0 record is comprised as follows:
|
102
|
+
#
|
103
|
+
# * S0 S-record type S0, indicating it is a header record.
|
104
|
+
# * 06 Hexadecimal 06 (decimal 6), indicating that six character pairs (or ASCII bytes) follow.
|
105
|
+
# * 00 00 Four character 2-byte address field, zeroes in this example.
|
106
|
+
# * 48 44 52 ASCII H, D, and R - "HDR".
|
107
|
+
# * 1B The checksum.
|
108
|
+
#
|
109
|
+
# The first S1 record is comprised as follows:
|
110
|
+
#
|
111
|
+
# * S1 S-record type S1, indicating it is a data record to be loaded at a 2-byte address.
|
112
|
+
# * 13 Hexadecimal 13 (decimal 19), indicating that nineteen character pairs, representing a 2 byte address,
|
113
|
+
# * 16 bytes of binary data, and a 1 byte checksum, follow.
|
114
|
+
# * 00 00 Four character 2-byte address field; hexidecimal address 0x0000, where the data which follows is to
|
115
|
+
# be loaded.
|
116
|
+
# * 28 5F 24 5F 22 12 22 6A 00 04 24 29 00 08 23 7C Sixteen character pairs representing the actual binary
|
117
|
+
# data.
|
118
|
+
# * 2A The checksum.
|
119
|
+
# * The second and third S1 records each contain 0x13 (19) character pairs and are ended with checksums of 13
|
120
|
+
# and 52, respectively. The fourth S1 record contains 07 character pairs and has a checksum of 92.
|
121
|
+
#
|
122
|
+
# The S5 record is comprised as follows:
|
123
|
+
#
|
124
|
+
# * S5 S-record type S5, indicating it is a count record indicating the number of S1 records
|
125
|
+
# * 03 Hexadecimal 03 (decimal 3), indicating that three character pairs follow.
|
126
|
+
# * 00 04 Hexadecimal 0004 (decimal 4), indicating that there are four data records previous to this record.
|
127
|
+
# * F8 The checksum.
|
128
|
+
#
|
129
|
+
# The S9 record is comprised as follows:
|
130
|
+
#
|
131
|
+
# * S9 S-record type S9, indicating it is a termination record.
|
132
|
+
# * 03 Hexadecimal 03 (decimal 3), indicating that three character pairs follow.
|
133
|
+
# * 00 00 The address field, hexadecimal 0 (decimal 0) indicating the starting execution address.
|
134
|
+
# * FC The checksum.
|
135
|
+
#
|
136
|
+
# ### Additional Notes
|
137
|
+
#
|
138
|
+
# There isn't any evidence that Motorola ever has made use of the header information within the data field
|
139
|
+
# of the S0 record, as described above. This must have been used by some third party vendors.
|
140
|
+
# This is the only place that a 78-byte limit on total record length or 64-byte limit on data length is
|
141
|
+
# documented. These values shouldn't be trusted for the general case.
|
142
|
+
#
|
143
|
+
# The count field can have values in the range of 0x3 (2 bytes of address + 1 byte checksum = 3, a not
|
144
|
+
# very useful record) to 0xff; this is the count of remaining character pairs, including checksum.
|
145
|
+
# If you write code to convert S-Records, you should always assume that a record can be as long as 514
|
146
|
+
# (decimal) characters in length (255 * 2 = 510, plus 4 characters for the type and count fields), plus
|
147
|
+
# any terminating character(s).
|
148
|
+
#
|
149
|
+
# That is, in establishing an input buffer in C, you would declare it to be
|
150
|
+
# an array of 515 chars, thus leaving room for the terminating null character.
|
151
|
+
class SRecord < Base
|
152
|
+
def self.match?(snippet)
|
153
|
+
snippet.all? do |line|
|
154
|
+
line.empty? || line =~ /^S[01235789]/
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def start_address
|
159
|
+
@start_address ||= begin
|
160
|
+
lines.each do |line|
|
161
|
+
if line =~ /^S([789])(.*)/
|
162
|
+
type = Regexp.last_match[1]
|
163
|
+
case type
|
164
|
+
when '7'
|
165
|
+
return line.slice(4, 8).to_i(16)
|
166
|
+
when '8'
|
167
|
+
return line.slice(4, 6).to_i(16)
|
168
|
+
when '9'
|
169
|
+
return line.slice(4, 4).to_i(16)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
private
|
177
|
+
|
178
|
+
# Returns an array containing all address/data from the given s-record
|
179
|
+
# No address manipulation is performed, that is left to the caller to apply
|
180
|
+
# any scrambling as required by the target system
|
181
|
+
def extract_addr_data(options = {})
|
182
|
+
options = {
|
183
|
+
data_width_in_bytes: 4
|
184
|
+
}.merge(options)
|
185
|
+
|
186
|
+
result = []
|
187
|
+
lines.each do |line|
|
188
|
+
# Only if the line is an s-record with data...
|
189
|
+
if line =~ /^S([1-3])/
|
190
|
+
type = Regexp.last_match[1].to_i(16) # S-record type, 1-3
|
191
|
+
# Set the matcher to capture x number of bytes dependent on the s-rec type
|
192
|
+
addr_matcher = '\w\w' * (1 + type)
|
193
|
+
line.strip =~ /^S\d\w\w(#{addr_matcher})(\w*)\w\w$/ # $1 = address, $2 = data
|
194
|
+
addr = Regexp.last_match[1].to_i(16)
|
195
|
+
@start_address ||= addr
|
196
|
+
@start_address = addr if addr < @start_address
|
197
|
+
data = Regexp.last_match[2]
|
198
|
+
data_matcher = '\w\w' * options[:data_width_in_bytes]
|
199
|
+
data.scan(/#{data_matcher}/).each do |data_packet|
|
200
|
+
result << [addr, data_packet.to_i(16)]
|
201
|
+
addr += options[:data_width_in_bytes]
|
202
|
+
end
|
203
|
+
# If a partial word is left over
|
204
|
+
if (remainder = data.length % (2 * options[:data_width_in_bytes])) > 0
|
205
|
+
result << [addr, data[data.length - remainder..data.length].to_i(16)]
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
result
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|