0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

バイナリデータを「Motorola S-record」に変換する。

Last updated at Posted at 2024-12-01

はじめに

ROMライターでマイコンやフラッシュメモリへバイナリデータを書き込むフォーマット、Motorola S-recordについてまとめる。また、Pythonでフォーマット変換するコードも書いてみた。

目次

Motorola S-recordフォーマット

Motorolaによって開発されたフォーマットで拡張子は.mot。ASCIIコードの16進数のビックエンディアンで表現するテキストフォーマット。「S」から始まるS-Recordという構造で、「Type」によって、後に続くフォーマットが規定されている。

image.png

パラメータ 内容
S 各行の先頭に付ける識別子。
Type:0 Option:ASCIIコードのNULL終端の文字列(16進数表記)。
Type:1 16bitアドレスのデータレコード。
Type:2 24bitアドレスのデータレコード。
Type:3 32bitアドレスのデータレコード。
Type:4 Reserved
Type:5 Option:データレコードのカウント(65,535 (0xFFFF)まで)。Addressに表記。Dataなし。
Type:6 Option:データレコードのカウント(16,777,215 (0xFFFFFF) まで)。Addressに表記。Dataなし。
Type:7 S3と対で使う。32bitの終端アドレス。Addressに表記。Dataなし。
Type:8 S2と対で使う。24bitの終端アドレス。Addressに表記。Dataなし。
Type:9 S1と対で使う。16bitの終端アドレス。Addressに表記。Dataなし。
Length AddressとDataとCheckSumの桁数の和を2で割った数(1Byte=2桁)
Address Type別に下記の通り。
S0 : 0000固定
S1 : 4桁:Dataを書き込む先頭アドレス XXXX(16bit Address)
S2 : 6桁:Dataを書き込む先頭アドレス XXXXXX(24bit Address)
S3 : 8桁:Dataを書き込む先頭アドレス XXXXXXXX(32bit Address)
S9 : 4桁:終端アドレス XXXX(16bit Address)
S8 : 6桁:終端アドレス XXXXXX(24bit Address)
S7 : 8桁:終端アドレス XXXXXXXX(32bit Address)
S5 : レコードの総数 0xFFFFまで
S6 : レコードの総数 0xFFFFFFまで
Data 書き込むデータ。2桁で 1Byte。S0の場合は書き込むデータではない。
CheckSum LengthとAddressとDataの各バイトの合計の1の補数。
2文字(1バイト)データ。レコード長、アドレスフィールド、データの各バイト値の合計の1の補数。 計算式はPythonの変換コードの例を参照。

戻る

Motorola S-record変換例

例として、データ列からS-Recordフォーマットのデータに変換するPythonコードを書いてみた。アドレスフォーマット(32bit,24bit,16bit)、開始アドレス、書き込みデータ列、1レコードのサイズを指定。関数名mot_srecord()

data ='\
000102030405060708090A0B0C0D0E0F\
101112131415161718191A1B1C1D1E1F\
202122232425262728292A2B2C2D2E2F\
303132333435363738393A3B3C3D3E3F\
404142434445464748494A4B4C4D4E4F\
505152535455565758595A5B5C5D5E5F\
606162636465666768696A6B6C6D6E6F\
707172737475767778797A7B7C7D7E7F\
808182838485868788898A8B8C8D8E8F\
909192939495969798999A9B9C9D9E9F\
A0A1A2A3A4A5A6A7A8A9AAABACADAEAF\
B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF\
C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF\
D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF\
E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF\
F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF\
ABCDEF\
'

#------------------------------------------------------
# AddrType   : アドレスのビット数を指定。(16,24,32)
# StartAddr  : 開始アドレスを16進数数値で指定。
# Data       : 書き込むデータをHEX文字列で指定。
# SplitBytes : S-RecordのサイズをByte数で指定。
#------------------------------------------------------
def mot_srecord(AddrType, StartAddr, Data, SplitBytes):
	
	#S-Record1行分のデータ毎にリストに分割
	data_list = [Data[i:i+SplitBytes*2] for i in range(0,len(Data), SplitBytes*2)]
	
	# データレコード作成
	for cnt,data in enumerate(data_list):
		if(AddrType == 32):
			#StartAddrからoffset(cnt*SplitBytes)を足して8桁のHEX文字列にする。
			addr     = f'{(StartAddr+(cnt*SplitBytes)&0xFFFFFFFF):08X}'
			
			#addr桁とdata桁とchecksumの2桁を足して2で割って(byte数なので)2桁のHEX文字列にする。
			length   = f'{((len(addr)+len(data)+2)//2):02X}'
			
			#sum_dataの16進数文字列を2文字ずつ切り取り数値変換してsum()し、1の補数をとる。
			sum_data = length+addr+data
			checksum = f'{(0xFF&~sum([int(sum_data[i:i+2],16) for i in range(0,len(sum_data), 2)])):02X}'
			
			#ヘッダをつけてS-Recordフォーマットにする
			data_list[cnt]=f'S3{length}{addr}{data}{checksum}\n'
			
		elif(AddrType == 24):
			addr     = f'{(StartAddr+(cnt*SplitBytes)&0xFFFFFF):06X}'
			length   = f'{((len(addr)+len(data)+2)//2):02X}'
			sum_data = length+addr+data
			checksum = f'{(0xFF&~sum([int(sum_data[i:i+2],16) for i in range(0,len(sum_data), 2)])):02X}'
			data_list[cnt]=f'S2{length}{addr}{data}{checksum}\n'
			
		elif(AddrType == 16):
			addr     = f'{(StartAddr+(cnt*SplitBytes)&0xFFFF):04X}'
			length   = f'{((len(addr)+len(data)+2)//2):02X}'
			sum_data = length+addr+data
			checksum = f'{(0xFF&~sum([int(sum_data[i:i+2],16) for i in range(0,len(sum_data), 2)])):02X}'
			data_list[cnt]=f'S1{length}{addr}{data}{checksum}\n'
	
	return ''.join(data_list)


# data列を32bitアドレスの0x80000000を開始アドレスとして、16byte1レコードのS-Recordデータに変換。
print(mot_srecord(32,0x80000000,data,16))

# S31580000000000102030405060708090A0B0C0D0E0FF2
# S31580000010101112131415161718191A1B1C1D1E1FE2
# S31580000020202122232425262728292A2B2C2D2E2FD2
# S31580000030303132333435363738393A3B3C3D3E3FC2
# S31580000040404142434445464748494A4B4C4D4E4FB2
# S31580000050505152535455565758595A5B5C5D5E5FA2
# S31580000060606162636465666768696A6B6C6D6E6F92
# S31580000070707172737475767778797A7B7C7D7E7F82
# S31580000080808182838485868788898A8B8C8D8E8F72
# S31580000090909192939495969798999A9B9C9D9E9F62
# S315800000A0A0A1A2A3A4A5A6A7A8A9AAABACADAEAF52
# S315800000B0B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF42
# S315800000C0C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF32
# S315800000D0D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF22
# S315800000E0E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF12
# S315800000F0F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF02
# S30880000100ABCDEF0F

# data列を16bitアドレスの0x1000を開始アドレスとして、16byte1レコードのS-Recordデータに変換。
print(mot_srecord(16,0x1000,data,16))

# S1131000000102030405060708090A0B0C0D0E0F64
# S1131010101112131415161718191A1B1C1D1E1F54
# S1131020202122232425262728292A2B2C2D2E2F44
# S1131030303132333435363738393A3B3C3D3E3F34
# S1131040404142434445464748494A4B4C4D4E4F24
# S1131050505152535455565758595A5B5C5D5E5F14
# S1131060606162636465666768696A6B6C6D6E6F04
# S1131070707172737475767778797A7B7C7D7E7FF4
# S1131080808182838485868788898A8B8C8D8E8FE4
# S1131090909192939495969798999A9B9C9D9E9FD4
# S11310A0A0A1A2A3A4A5A6A7A8A9AAABACADAEAFC4
# S11310B0B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFB4
# S11310C0C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFA4
# S11310D0D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF94
# S11310E0E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF84
# S11310F0F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF74
# S1061100ABCDEF81

戻る

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?