FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

ELFからHEXに変換するためのツール

ModelSim(32-bit版)を使うにあたり、これまで使っていたlibelfが使用できなくなり、elfをhexに変換してRAMにロードする必要が生じた。 しかもRAMとしてシミュレーション用に連想配列を使っているので、readmemhで読み込む際にアドレス情報が必要になる。いくつかツールを探したがないので自分で実装した。

もとはELFをダンプするためのツールだったのだが、hexファイルを出力するためにいくつか改良した。

もともと以下のリポジトリにelf2hexがあるのだが、binファイルを経由するのでアドレス情報が消えてしまっている。アドレス情報を残したうえでreadmemhに流したい。

github.com

hexファイルにおいてアドレスは@で指定することができる。

www.asic-world.com

例えば以下のようにする。以下は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);
        }
      }