VexRiscv とメモリ間のバス信号を覗いてみる

(更新

Investigating bus transactions between VexRiscv core and memory.

FPGA 用の RISC-V 実装である VexRiscv と、それを使った Murax SoC の素晴らしい点の一つに、標準で JTAG インターフェイスと、OpenOCD によるデバッグ機能が用意されていることが挙げられます。もちろん実デバイス(FPGA)でも JTAG デバッグができますが、それだけでなくシミュレーション上でも同様のことができることに感心します。

ところが先日、Murax SoC をシミュレーション上で JTAG + gdb デバッグしていたら、sw 命令によるメモリ書き込みが正しくできていないことを発見しました。(詳しくは、こちらの議論を御参考ください。)

おそらく私の使い方が何か間違っているだけだと思うのですが、気になるので調べてみました。その中で少し分かってきたことを、ちょっとだけ御紹介したいと思います。(実は、折角調べたのに忘れてしまうと惜しいので備忘録。)

VexRiscv の GitHub サイトを調べると、Murax SoC を Verilator シミュレーション上で動かす方法が紹介されています。具体的には、ディレクトリ src/test/cpp/murax 内で make run すれば良いのですが、ここで make TRACE=yes run と実行すると、シミュレーション時に波形ファイル(.vcd)を作成してくれます。早速、波形ファイルを GTKwave で閲覧しながら、メモリアクセスの場所を探してみました。

余談: make TRACE=yes run を続けていると、.vcd ファイルがどんどん大きくなっていき、いずれディスクが溢れてしまいます。適当なところで ctrl + c を押してシミュレーションを中断しましょう。

まずは memory write

先日のテストプログラム demo.hex には、次のようなコード(逆アセンブル)があります。

        volatile uint32_t a = 1, b = 2, c = 3;
800002d4:       00100793                li      a5,1
800002d8:       fef42223                sw      a5,-28(s0)
800002dc:       00200793                li      a5,2
800002e0:       fef42023                sw      a5,-32(s0)
800002e4:       00300793                li      a5,3
800002e8:       fcf42e23                sw      a5,-36(s0) ← この行に着目

上記の sw 命令を探すと、こんなバスサイクルが見つかります。(クリックすると拡大できます)

左下の赤丸を見ると、execute_PC という信号線に 0x800002e8 が乗っており、このサイクルから sw 命令が実行されます。(VexRiscv はパイプラインアーキテクチャなので、iBus の命令フェッチから探すと少し分かりづらい。)

その後、右上の赤丸に目を移すと、命令実行の最後で dBus(データバス)に address = 0x8000066c、data = 0x3 の書き込みアクセスがあるのが見つけられます。さらにメモリインターフェイスを覗いてみると、1サイクル遅れて、右下の赤丸のところで実際にメモリへの書き込みが実行されていることが分かります。

続いて memory read

次のようなメモリ読み出しの命令を見つけます。

                result += b + c;
800003a0:       fe042703                lw      a4,-32(s0)
800003a4:       fdc42783                lw      a5,-36(s0) ← この行に注目

上記の lw 命令を探すと、、こんなバスサイクルが見つかります。(クリックすると拡大できます)

左中央の赤丸を見ると、execute_PC という信号線に 0x800003a4 が乗っており、このサイクルから lw 命令が実行されます。そうすると、次のサイクルで右上の赤丸のように、dBus 上で address = 0x8000066c に対する読み出しサイクルが発生し、右下の赤丸のように、メモリバスから rsp.payload.data に 0x3 が読み出されます。

結局、VexRiscv は正しく動いていることが分かりました。そうなると、どうも OpenOCD と JTAG シミュレーションの間、あるいは GDB と OpenOCD の間で何か齟齬が起きている可能性が高いのですが、ちょっとそこまで追いかけていくのは大変そうです。VexRiscv の作者さんが何かアドバイスをくだされば良いのですが、そうでな場合は、そこまで調べなくてダメかなあ、と考えているところです。

今日はここまで。

後記(2020/4/8)

早速、問題を修正して頂きました。アクションが早い!!