FirmGod

Motorola S-Record Parser

Decode a Motorola S-record file record by record. Checksums, address ranges, gaps, and the S7/S8/S9 mismatches that make a programmer reject an image.

Paste the file contents. Nothing is uploaded — parsing happens in this page.

Examples
Records70 with problems
Data bytes52 B4 data records
Address range0x00000000to 0x00000033
Entry point0x00000000

Header (S0): HDR — a module name or build string. Programmers ignore it, so it never reaches the device.

Memory regions

Contiguous stretches the file actually programs.

StartEndSizeBytes
0x000000000x0000003352 B52

Records

LineTypeAddressCountDataChecksumNotes
1S0Header0x00000000631B
2S1Data, 16-bit address0x0000000019162A
3S1Data, 16-bit address0x00000010191613
4S1Data, 16-bit address0x00000020191652
5S1Data, 16-bit address0x000000307492
6S5Record count, 16-bit0x0000000430F8
7S9Termination, 16-bit start address0x0000000030FC

Record types in this file

S0Header1
S1Data, 16-bit addressclosed by S94
S5Record count, 16-bit1
S9Termination, 16-bit start address1

The shape of a record

Every line is one record, written entirely in ASCII hex:

S<type><count><address><data><checksum>

The count is the number of bytes that follow it — address, data and checksum together. This is the first thing that catches people coming from Intel HEX, where the count is the data bytes alone. The payload length is the count minus the address width minus one for the checksum.

The address width is not in the record. It is implied by the type, which is what lets the same format address an 8-bit micro and a 32-bit one without a mode flag.

TypeMeaningAddress
S0Header — a module name or build string16-bit, usually 0000
S1Data16-bit
S2Data24-bit
S3Data32-bit
S5Count of data records16-bit field holds the count
S6Count of data records24-bit field holds the count
S7Termination, closes S332-bit entry point
S8Termination, closes S224-bit entry point
S9Termination, closes S116-bit entry point

S4 is reserved and nothing emits it. Seeing one means the file is damaged or is not an S-record file.

The terminator has to match the data

S1 is closed by S9, S2 by S8, S3 by S7. The pairing is not decoration: the terminator carries the entry point, and its address width has to be able to hold one. A build that emits S3 data and an S9 terminator parses cleanly record by record and is still malformed.

This is worth knowing because of how it fails. Some programmers accept it, some reject it, and the message that comes back names neither record — you get "invalid file" against an image that every text editor and most parsers read without complaint.

The checksum

Sum the count byte, the address bytes and the data bytes; take the low byte; subtract it from 0xFF. That one's complement is the last byte of the record. Neither the type nor the leading S is part of the sum.

Worked on the header from the specification's own example, S00600004844521B:

06 + 00 + 00 + 48 + 44 + 52 = E4
FF − E4 = 1B

Intel HEX differs twice over: it includes the record type in the sum, and it uses the two's complement, so its records sum to zero rather than to 0xFF. Porting a checksum routine between the two formats without noticing both differences produces records that are wrong in a way that looks arbitrary.

S-record against Intel HEX

S-recordIntel HEX
Line starts withS and a type digit:
Count coversAddress, data and checksumData only
Address widthImplied by the record typeAlways 16-bit, extended by other records
Reaching past 64 KiBUse S2 or S3 recordsExtended segment or linear address records
ChecksumOne's complement, type excludedTwo's complement, type included
Entry pointIn the termination recordIn a start address record

The practical consequence is in the third row. Intel HEX addresses 32-bit flash by carrying a base in a separate record, so a data record's meaning depends on what came before it and a file truncated in the middle silently relocates. S-record puts the full address in every data record, which makes each line self-contained and the format noticeably easier to read by eye.

What to check in a file that will not flash

  • The terminator matches the data records. The single most common cause, and the one with the least helpful error message.
  • Checksums. A file edited by hand — a version string patched in the S0 header, say — usually has one bad record and the rest intact.
  • The address range. An image linked for the wrong base lands outside the flash the part actually has, and a programmer reports that as an address error rather than a link error.
  • Gaps. Unprogrammed space keeps whatever was there before. That is usually erased flash, but not after a partial programming run.
  • Overlaps. Two builds concatenated by mistake. Which byte survives depends on the programmer, so the result is not even reliably wrong.

Frequently asked questions

What is the difference between .s19, .s28, .srec and .mot?

Nothing, in the file. They are all S-record text and the extension only hints at the address width a toolchain expected: .s19 for 16-bit S1 data, .s28 for 24-bit S2, .s37 for 32-bit S3. A file named .s19 can still contain S3 records, so read the types rather than the extension.

Why does my programmer reject a file that looks correct?

The most common reason is a termination record that does not match the data records. S1 data is closed by S9, S2 by S8, and S3 by S7. A build that emits S3 data with an S9 terminator parses cleanly line by line and is still malformed, and the error a programmer returns rarely names either record.

How is the count field different from Intel HEX?

Intel HEX counts data bytes only. An S-record count covers the address, the data and the checksum together, so the payload is the count minus the address width minus one. Reading it as a data length is the usual first bug when writing a parser.

How is the checksum calculated?

It is the one's complement of the sum of the count, address and data bytes: 0xFF minus that sum, low byte only. The record type and the leading S are not included, which is another difference from Intel HEX, where the type is part of the sum and the result is the two's complement.

What are S5 and S6 records for?

They carry the number of S1, S2 and S3 records in the file, as a check against truncation. They are optional, most toolchains omit them, and a programmer that ignores them will happily flash a file whose count is wrong — which is why this tool compares the declared figure against the records actually present.