FPGA開発日記

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

GDBリモートデバッグサーバを自作ISSに実装する

さて、前回でGDBのリモートデバッグプロトコルについて分かってきた。 今度は、これを実装していこう。

基本的には、OpenRISCのISSであるor1ksimの実装を参考にする。 といっても、or1ksimはC言語で実装してあるので、必要な部分はC++に置き換えていく必要がありそうだ。 (と言っても大部分のアルゴリズムは変更しようが無いのだが...なのでほとんどパクってしまうことになるかもしれない)

GDBインタフェース用のクラスを追加する

僕のISSは、CPUのコア部分と、それを操作する外回りのクラス群で構成されている。コアの部分は、CPUの内部機能などを司っているので、GDBインタフェースを追加することには影響しない。 コアの外回りに、新しいインタフェースとしてGDBのクラスを追加するだけだ。

github.com

GdbEnvクラスを追加して、まずは初期化とポート開放をするメソッドを実装しよう。

class GdbEnv {
private:
    EnvBase   *m_env;
    std::unique_ptr<GdbServer> m_gdb_server;

    uint32_t m_serial_port;

public:
    GdbEnv (EnvBase *env);

    void HandleGdb ();
    void GetClientPort ();

    std::vector<mp_entry> m_vec_mp_entry;


};

mp_entryとか、まだor1ksimのコードをコピっただけなので、理解できていない部分が多い。。。

ポートを開放する

GDBインタフェースについても、基本的にor1ksimと同じものを踏襲した。 (本来ならばor1ksimのインタフェースをライブラリとして使用したいところだが、C++の実装とうまく合わないし、切り出すのも難しいため、現在のところ実装を殆ど真似る状態となっている。。。)

void GdbEnv::GetClientPort (void)
{
    int                 tmp_fd;         /* Temporary descriptor for socket */
    int                 optval;         /* Socket options */
    struct sockaddr_in  sock_addr;      /* Socket address */
    socklen_t           len;            /* Size of the socket address */

    /* 0 is used as the RSP port number to indicate that we should use the
       service name instead. */
    m_serial_port = 2000;
    if (m_serial_port == 0) {
        struct servent *service = getservbyname (MIPS64_RSP_SERVICE, "tcp");
        if (service == NULL) {
            std::cerr << "Warning: RSP unable to find service \"" << MIPS64_RSP_SERVICE "\": strerror (errno)\n";
            return;
        }
        m_serial_port = ntohs (service->s_port);
    }
...

m_serial_port = 2000となっているのがお分かりだろうか?今のところ、ポートは2000で決め打ちになっている(笑)

GDBポートを指定するフラグの追加

ISSコマンドラインオプションに、GDBの受付ポートを指定するオプションを追加する。ISSにはコマンドラインオプション解析としてGoogle Flagsを利用しているので、この辺りの拡張は非常に簡単だ。

DEFINE_bool (gdb, false, "Wait GDB port");
...
    if (FLAGS_gdb == true) {
#ifdef ARCH_MIPS64
        Mips64Env *env = new Mips64Env (g_debug_fp, g_uart_fp, en_stop_sim, FLAGS_debug);
#endif // ARCH_MIPS64
        std::unique_ptr<GdbEnv> p_gdb = std::unique_ptr<GdbEnv>(new GdbEnv(env));
        p_gdb->HandleGdb();

これだけで、--gdb port引数を付けると、GDBの待受モードに(とりあえず)入ることができる。

$ ./swimmer_mips64 --gdb
Swimmer-RISCV
  Version 20160118 Revision 5858f70
  developed by Masayuki Kimura <masayuki.kimura.1986@gmail.com>
Listening for RSP on port 2000

よしよし、次はいよいよ中身のプロトコルの受信チェックと、プロトコルに応じたISSの機能を実装していこう。