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.
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.
| Start | End | Size | Bytes |
|---|---|---|---|
| 0x00000000 | 0x00000033 | 52 B | 52 |
Records
| Line | Type | Address | Count | Data | Checksum | Notes |
|---|---|---|---|---|---|---|
| 1 | S0Header | 0x00000000 | 6 | 3 | 1B | |
| 2 | S1Data, 16-bit address | 0x00000000 | 19 | 16 | 2A | |
| 3 | S1Data, 16-bit address | 0x00000010 | 19 | 16 | 13 | |
| 4 | S1Data, 16-bit address | 0x00000020 | 19 | 16 | 52 | |
| 5 | S1Data, 16-bit address | 0x00000030 | 7 | 4 | 92 | |
| 6 | S5Record count, 16-bit | 0x00000004 | 3 | 0 | F8 | |
| 7 | S9Termination, 16-bit start address | 0x00000000 | 3 | 0 | FC |
Record types in this file
S0Header1S1Data, 16-bit addressclosed by S94S5Record count, 16-bit1S9Termination, 16-bit start address1The 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.
| Type | Meaning | Address |
|---|---|---|
| S0 | Header — a module name or build string | 16-bit, usually 0000 |
| S1 | Data | 16-bit |
| S2 | Data | 24-bit |
| S3 | Data | 32-bit |
| S5 | Count of data records | 16-bit field holds the count |
| S6 | Count of data records | 24-bit field holds the count |
| S7 | Termination, closes S3 | 32-bit entry point |
| S8 | Termination, closes S2 | 24-bit entry point |
| S9 | Termination, closes S1 | 16-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 = E4FF − 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-record | Intel HEX | |
|---|---|---|
| Line starts with | S and a type digit | : |
| Count covers | Address, data and checksum | Data only |
| Address width | Implied by the record type | Always 16-bit, extended by other records |
| Reaching past 64 KiB | Use S2 or S3 records | Extended segment or linear address records |
| Checksum | One's complement, type excluded | Two's complement, type included |
| Entry point | In the termination record | In 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.
Related tools
- IEEE 754 Float ConverterFlip bits directly and see the exact value a float really holds, not the rounded print.
- Hex / Binary / Decimal / ASCII ConverterFixed-width conversion with signed readings, byte order, and clickable bits.
- I²C Address Converter7-bit to 8-bit both ways, reserved ranges, and what a scan result probably is.