HEXFORM
HEXファイルフォーマット 2007-06-12一部修正
ROMライターなどで良く利用されるのはASCIIキャラクタで、どのアドレスに
何の値を書き込むかを指定する、いわゆるHEXファイルフォーマットであろう。
マイコンの初期の段階から使われているもので、各社いろいろなものがあったが、
大御所はやはりインテルHEX形式とモトローラSレコード形式の二つ。
他にもあるけども、この二つを押さえておけばだいたい不自由しないと思う。

モトローラ Sレコードフォーマット

Sレコードフォーマットの例
 
Sレコードフォーマットの一例。この例は、0100h番地から、43h,00h,48h,65h・・6bh、 0110h番地から20h,63h,6fh・・fch、・・・という具合にデータを格納するというもの。
  S00A000074322E7372656374
S113010043004865617020616E6420737461636BA1
S113011020636F6C6C6973696F6E0A007907FEFC6B
S113012079001D9479011D9A192269820B801D1092
S113013045F85E0001D25E00015A5E0001986DF63A
S11301400D761B876FE0FFFE6F62FFFE0D230B032E
S11301506FE3FFFE0B876D7654706DF60D761B878B
S1130160000019226FE2FFFE6F62FFFE7903000FA9
S11301701D324F0240186F62FFFE0D205E00013EEB
S11301806F62FFFE0D230B036FE3FFFE40DA1900DD
S113019040000B876D7654706DF60D766DF40D048A
・・・・(中略)・・・・
S105FEFC0001FF
S903011CDF

Sレコードフォーマットの構造
 
Sレコードの各行(レコード)は下図のようなフィールドに分かれている。

1レコード(一行)の構造
レコードタイプ レコード長 アドレス データ チェックサム

Sレコードフォーマットでは先頭一文字は必ず'S'の文字
レコードタイプ
スタートレコード(オプション)
データレコード部分に付帯情報を入れておく。上の例だと、"t2.srec"というファイル名が入っている。
データレコード(16ビットアドレス:4文字でアドレス指定)
データレコード(24ビットアドレス:6文字でアドレス指定)
データレコード(32ビットアドレス:8文字でアドレス指定)
シンボルレコード(LSI Logic,Inc拡張)
今までに出てきたデータレコード数(2バイト長)
今までに出てきたデータレコード数(3バイト長)
S3フォーマット(32ビットアドレス)の終了
S2フォーマット(24ビットアドレス)の終了
S1フォーマット(16ビットアドレス)の終了
レコード長
以下に続くレコードで表されるデータの数(バイト単位)を2文字で示す。 S1レコードで、データフィールドが10h(=16)バイト分(0x20(=32)文字)あるなら、 2(アドレス)10h(データ)+1(チェックサム)=13hとなる。上の例で2行目以降のレコード長が13になっているのはこのため。
アドレス
4文字(S1レコード)/6文字(S2レコード)/8文字(S3レコード)で レコードの先頭バイトが格納されるアドレスを指定。
データ
2文字で1バイトのデータを表す
チェックサム
2文字(1バイト)データ。レコード長、アドレスフィールド、データの各バイト値の合計の1の補数。 1の補数なので、チェックサムまで全部足すと下位2桁はFFhになる
例えば、先の例の一番最後の行なら、03+01+1C+DF=FFとなるし、最後から二番目の行なら、 05+FE+FC+00+01+FF=2FFとなり、下位2桁はFFになっている。


インテルHEXレコードフォーマット

Intel-HEXフォーマットの例
Intel-HEXフォーマットの一例。先ほどのSレコードフォーマットと同じ意味を持つHEXファイルのIntel-HEX形式版。
:1001000043004865617020616E6420737461636BA5
:1001100020636F6C6C6973696F6E0A007907FEFC6F
:1001200079001D9479011D9A192269820B801D1096
:1001300045F85E0001D25E00015A5E0001986DF63E
:100140000D761B876FE0FFFE6F62FFFE0D230B0332
:100150006FE3FFFE0B876D7654706DF60D761B878F
:10016000000019226FE2FFFE6F62FFFE7903000FAD
:100170001D324F0240186F62FFFE0D205E00013EEF
:100180006F62FFFE0D230B036FE3FFFE40DA1900E1
:1001900040000B876D7654706DF60D766DF40D048E
・・・・(中略)・・・・
:02FEFC00000103
:040000030000011CDC
:00000001FF
インテルHEXフォーマットの構造
インテルHEX形式の各行(レコード)の構造は下図のようなフィールドに分かれている。
1レコード(一行)の構造
データ長 オフセットアドレス レコードタイプ データ チェックサム

Intel-HEXフォーマットでは先頭一文字は必ず':'の文字
データ長
データフィールドに格納されているデータ数(バイト単位)を2文字で示す。 Sレコードと異なり、データレコードに記されているデータ長であることに注意が必要。
オフセットアドレス
4文字。データレコードの時は先頭バイトが格納されるアドレスを指定する。 (ビッグ・エンディアンであることに注意) その他のレコードの時にも有効なのだが、現実に使われている例はほとんど見ない(各レコードタイプの説明を参照)
レコードタイプ
00 データレコード:
データフィールドは書き込まれるべきデータである。
01 エンドレコード:
(HEXファイルの終了を示す)データフィールドは無いので、データ長フィールドは”00”になる。
02 セグメントアドレスレコード:
データフィールドにはセグメントアドレスが入る。 たとえば、
:02000002E0100C
ならば、セグメントはE010hとなる。(80x86はリトルエンディアンなのに、 Intel-HEXファイルはビッグエンディアンであることに要注意)
元々オブジェクトレコードが16ビットアドレス(S1フォーマットに相当) だったものを8086の20ビットアドレスに拡張するために作られたものなので、これを使っているものを拡張IntelHEXフォーマットと呼ぶこともある。
8086対応でできたものなので、8086の流儀に従って この値を4ビット左にシフトした値にオフセットアドレスを足したものが物理アドレスになる。 たとえばセグメントが1234h、オフセットが3456hならば、物理アドレスは12340h+3456h=15796hになる。このレコードが無い場合はデフォルトでセグメント=0000hの扱いになっている。
例えば、先ほどのセグメントフィールドが無い場合に
:1001000043004865617020616E6420737461636BA5
というデータレコードがあれば、これは0100h番地から格納されるが、 あった場合には、(E010h<<4)+0100h=E0200h番地から格納されることになる。

このレコードの時のオフセットアドレスフィールドは、プログラムローダなどが実際に オブジェクトをロードするアドレスとの間のオフセットとなる。少々ややこしいのだが、 このレコードで指定したオフセットアドレスとデータレコードのオフセットアドレスを加算した値の下位16ビットと、 このレコードで指定したセグメントデータによって物理アドレスが計算されるのである。
ただし、このレコードのオフセットアドレスフィールドを使っている例はほとんど見ない(先頭部分が":02000002"になっているものばかり)ので、無視しても問題になることはまず無いだろう。
03 スタートセグメントアドレスレコード:
プログラムをダウンロードして使うような場合に、 実行開始アドレスを指定するのに使用される。(ROMライタなどでは意味無し)。8086用の拡張で、データフィールドには CS/IP(セグメント/オフセット)が入る。 例えば、
:04000003FF000123D6
ならば、CS=FF00h、IP=0123hとなるので、物理アドレスはFF123h((FF00h<<4)+0123h)番地から開始されることになる。
04 拡張リニアアドレスレコード:
セグメント:オフセットの形式では20ビットアドレスまでしか表現できない(計算上は21ビット目に桁あふれさせることもできるが、本来の使い方ではない)ので、32ビットアドレスが必要になったときにこの形式が追加された。
このレコードでは32ビットアドレスのうち上位16ビット(ビット32〜ビット16の)を与える。 (下位16ビットはデータレコードのオフセットフィールドの値が用いられる) セグメントアドレスレコード同様に、このレコードのオフセットフィールドは、 ロード先にオフセットをかけるために用いられる。こちらの場合には、 実際にロードされるアドレスはリニアドレスの上位+リニアアドレスレコードのオフセット+ データレコードのオフセットの単純和となる。
ただし、セグメントフィールドと同様に、実際に拡張リニアアドレスレコードのオフセットフィールドを使っている例は ほとんど見ないので、無視してしまってもまず問題になることはない筈。
05 スタートリニアアドレス:
スタートセグメントアドレスレコードでは、 セグメント:オフセット形式なので、20ビットの範囲しか指定できないため、 これを32ビット表現できるように拡張したのが、スタートリニアアドレスレコード。 例えば
:04000005FF000123D4
となっていれば、FF000123h番地がスタートアドレスになる。
データ
2文字で1バイトのデータを表す
チェックサム
2文字(1バイト)データ。レコード長、データ長フィールド、オフセットアドレスフィールド、データフィールドの各バイト値の合計の2の補数。 2の補数なので、チェックサムまで全部足すと下位2桁は00hhになる。
例えば、先の例の一番最後の行なら、01+FF=100となり、下位2桁は00h。最後から三番目の行なら、 02+FE+FC+00+00+01+03=200となるので、下位2桁はやはり00hとなっている。