Motorola Sxx records format

Motorola is another major player on the file format market. Motorola defined 3 format types to adapt to the ever growing hunger for memory size. The basic format is the so called S19 format, which has a 16 bit address field and can be used for files of up to 64kb. The S28 format has a 24 bit address field and can handle files up to 16Mb. The S37 format is the largest of the 3 formats, it has a 32 bit address field and can handle files of up to 4Gb.
All three formats contain only normal ASCII characters. The Motorola file format does not need special tricks to deal with larger files. The addressing is always linear.

Records

All data lines are called records and each record contains the following fields:

Sxccaaaaddss

Sx

Every line starts with the character S, followed by a digit.

cc

The byte-count. A 2 digit value (1 byte), counting all the bytes in the record, excluding cc itself.

aaaa

The address field is a 4 to 8 digit (2 to 4 bytes) number representing the first address of this record.

dd

The actual data of this record.

ss

The checksum. A2 digit (1 byte) checksum. cc+aaaa+sum(dd)+ss=$FF

Record Begin

Every record begins with the ASCII character "S", which is followed by a digit x. This digit represents the record type. No spaces or tabs are allowed in a record. In fact, apart from the character "S" in the beginning of the record and the End Of Line characters at the end, no other characters than 0..9 and A..F are allowed. Interpretation of a record should be case insensitive, so it does not matter if you use a..f or A..F.

The following record numbers can be used:

'S1' = A normal data record with a 16 bit address field.
'S9' = End Of File record for a S1 file.
'S2' = A normal data record with a 24 bit address field.
'S8' = End Of File record for a S2 file.
'S3' = A normal data record with a 32 bit address field.
'S7' = End Of File record for a S3 file.

In the table above you can see why they call these Motorola formats S19, S28, or S37. The first digit in the name represents the normal data record identifier. The second digit is the End Of File record identifier.

Byte Count

The byte count cc counts the number of bytes in the current record excluding cc itself. So the number of address bytes, the number of data bytes and one byte for the checksum are counted. The byte count can have any value from $00 to $FF. Usually records have 32 data bytes. For the S19 format this gives a byte count of $23.
It is not recommended to send too many data bytes in a record for that may increase the transmission time in case of errors. Also avoid sending only a few data bytes per record because the address overhead will be too heavy in comparison to the payload.

Address field

The first data byte of the record is stored in the address specified by the Address field aaaa. After storing that data byte the address is incremented by 1 to point to the address for the next data byte of the record. And so on, until all data bytes are stored.
The length of the address field depends on the record type. For types S1 and S9 the address field is 4 hex digits long (2 bytes). For S2 and S8 records the address field is 6 hex digits, and for the S3 and S7 records the address field is 8 hex digits long. The address is sent with MSB first.
The order of addresses in the records of a file is not important. The file may also contain address gaps, to skip a portion of unused memory.
Due to the large addressing ranges of the S28 en S37 formats no special tricks are necessary to manage large files.

The address field in records of type S9, S8 and S7 specifies the starting address of the code just sent. This is usually not supported by EPROM programmers though. Only development machines will honour these starting addresses.

Data field

This field contains 0 or more data bytes. The actual number of data bytes is indicated by the byte count in the beginning of the record. The first data byte is stored in the location indicated by the address in the address field. After that the address is incremented by 1 and the next data byte is stored in that new location. This continues until all bytes are stored.

Checksum field

This field is a one byte (2 hex digits) 1's complement checksum of the entire record. To create the checksum make a 1 byte sum from all fields of the record:

  check sum = byte count + all address bytes + all data bytes

Then take the 1's complement of this sum to create the final checksum. The 1's complement is simply inverting all bits. Checking the checksum at the receivers end is done by adding all bytes together including the checksum itself, discarding all carries, and the result must be $FF.

Examples

S113B000576F77212044696420796F7520726561D8
S113B0106C6C7920676F207468726F756768206143
S113B0206C20746861742074726F75626C6520742E
S10FB0306F207265616420746869733FCE
S9030000FC

In the example above you can see a piece of S19 code with normal 16 bit addressing. The first 3 lines have 16 bytes of data each, which can be seen by the byte count, the first byte of each line. In S19 format, the byte count is always 3 higher than the actual number of data bytes in the record. The 4th line has only 12 bytes because the program is at its end there.
After the byte count on each line you can see the address where the 1st data byte is to be stored. The begin address of this file is $B000. Remember that the address order within a file is not important.
The actual data bytes follow after the address field.
Finally you see the checksum as the last byte of every record. If you like you can add all bytes of each line together and the result should be $FF every time.
Note that the address of the last line is also $0000 and that there are no data bytes in this last record. The address in the End Of File record can be ignored, but could also be used as a start vector to be loaded into the Program Counter of the target system.

S21400B000576F77212044696420796F7520726561D7
S21400B0106C6C7920676F207468726F756768206142
S21400B0206C20746861742074726F75626C6520742D
S21000B0306F207265616420746869733FCD
S804000000FB

Here you see the same piece of code as in the first example, but this time we use the S28 format. There are only a few differences. As you can see another identifier is used. The byte count is 1 higher than in S19 format because we have one more address byte to send. And because of this change in byte count the checksum is different as well.

S3150000B000576F77212044696420796F7520726561D6
S3150000B0106C6C7920676F207468726F756768206141
S3150000B0206C20746861742074726F75626C6520742C
S3110000B0306F207265616420746869733FCC
S70500000000FA

Finally I show the same piece of code again, but this time in the S37 format. The same differences as with S28 apply here.