ModelSim(32-bit版)を使うにあたり、これまで使っていたlibelfが使用できなくなり、elfをhexに変換してRAMにロードする必要が生じた。
しかもRAMとしてシミュレーション用に連想配列を使っているので、readmemh
で読み込む際にアドレス情報が必要になる。いくつかツールを探したがないので自分で実装した。
もとはELFをダンプするためのツールだったのだが、hex
ファイルを出力するためにいくつか改良した。
もともと以下のリポジトリにelf2hexがあるのだが、binファイルを経由するのでアドレス情報が消えてしまっている。アドレス情報を残したうえでreadmemh
に流したい。
hexファイルにおいてアドレスは@
で指定することができる。
例えば以下のようにする。以下は256ビットのRAMに対して0x8000_0000へのアクセスを行うための初期値配置。0x8000_0000に対して256ビット(32バイト)なのでアドレスを5ビットシフトして0x0400_000
に置いている。
@04000000 // 80000000 03ff026300b00f9303ff066300900f9303ff0a6300800f9334202f7304c0006f 5391e1930040006f000f546334202f73000f0067000f0463fe0f0f1380000f17 0000029300000213000001930000011300000093ff9ff06ffc3f202300001f17 0000069300000613000005930000051300000493000004130000039300000313 00000a9300000a13000009930000091300000893000008130000079300000713
こんな感じでELFを読み取って吐き出すコードを作った。
fprintf (stdout,"@%08lx // %08lx\n", base / dump_bytewidth, base); for(count=0; count < valsRead; count=count+dump_bytewidth) { base = base + dump_bytewidth; switch (identity[EI_DATA]) { case 1: { /* Little endian */ int max_count = valsRead - count < dump_bytewidth ? valsRead - count : dump_bytewidth; for (count2 = max_count-1;count2 >= 0;count2--) { fprintf (stdout,"%.2x",static_cast<uint8_t>(buffer[count+count2])); } fprintf (stdout,"\n"); break; } case 2: /* Big endian */ for (count2=0;count2<4;count2++) { fprintf (stdout,"%.2x",static_cast<uint8_t>(buffer[count+count2])); } fprintf (stdout,"\n"); break; default: printf ("Undetermined Endianness. Fatal error.\n"); exit(EXIT_FAILURE); } }