FPGA開発日記

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

自作RISC-V CPUコアで構成を変えながら性能を測定していく (5. Pipeline Visualizerのトレース生成実装)

自作RISC-V CPUコアの方は、いくつかのコンフィグレーションにおいてDhrystoneを完走させることができるくらいになってきた。

パイプライントレースのログ生成を実装する。基本としては各モジュールのパイプラインステージ毎にDPI-Cを通じてC++側に情報を取り出し、C++側でログファイルに出力するという形態にする。

// Kanata
import "DPI-C" function void log_stage
(
 input longint id,
 input string stage
);

always_ff @ (negedge i_clk, negedge i_reset_n) begin
  if (i_reset_n) begin
    if (w_ex0_issue.valid) begin
      log_stage (w_ex0_issue.kanata_id, "EX0");
    end
    if (r_ex1_issue.valid) begin
      log_stage (r_ex1_issue.kanata_id, "EX1");
    end
    if (r_ex2_issue.valid) begin
      log_stage (r_ex2_issue.kanata_id, "EX2");
    end
    if (r_ex3_issue.valid) begin
      log_stage (r_ex3_issue.kanata_id, "EX3");
    end
  end
end

log_stage()という関数では、kanata_id(シミュレーション内で一意となるID)とともに現在どのステージにいるのかを指定する。

log_stage()内では、過去に同じ命令で別のステージにいた場合は、E命令を出してステージを終了しないといけないので、そのためのE命令の生成を行う。

void log_stage (long long id, const char *stage)
{
  decltype(stage_map)::iterator it = stage_map.find(id);
  if (it != stage_map.end()) {
    fprintf (kanata_fp, "E\t%lld\t0\t%s\n", id, it->second);
    stage_map.erase (id);
  }
  fprintf (kanata_fp, "S\t%lld\t0\t%s\n", id, stage);
  char *stage_str = (char *)malloc(sizeof(strlen(stage))+1);
  strcpy(stage_str, stage);
  stage_map.insert (std::make_pair(id, stage_str));
}

これにより、以下のようなトレースファイルが生成されるようになった。

I       72735   72735   0
L       72735   0       800028e8:lbu     a5, 0(a0)
S       72735   0       Di
I       72736   72736   0
L       72736   0       800028ec:addi    a1, a1, 1
S       72736   0       Di
I       72737   72737   0
L       72737   0       800028ee:addi    a0, a0, 1
S       72737   0       Di
I       72738   72738   0
L       72738   0       800028f0:lbu     a4, -1(a1)
S       72738   0       Di
I       72739   72739   0
L       72739   0       800028f4:beqz    a5, pc + 14
S       72739   0       Di
E       72732   0       Di
S       72732   0       Rn
E       72733   0       Di
S       72733   0       Rn
E       72734   0       Di
S       72734   0       Rn
E       72730   0       Rn
S       72730   0       EX0
E       72728   0       EX1
S       72728   0       EX2
E       72711   0       Rn
S       72711   0       EX0
E       72709   0       EX0
S       72709   0       EX1
E       72702   0       EX1
S       72702   0       EX2
E       72695   0       EX2
S       72695   0       EX3
E       72723   0       Rn
S       72723   0       EX0
E       72712   0       EX0
S       72712   0       EX1
E       72718   0       EX1
S       72718   0       EX2
E       72714   0       EX2
S       72714   0       EX3
C       1
I       72740   72740   0
L       72740   0       800028f6:beq     a5, a4, pc - 14
S       72740   0       Di
E       72735   0       Di
S       72735   0       Rn
E       72736   0       Di

これをKonataパイプラインビューアで表示すると以下のようになる。

こうみると、例えば0x8020はなんでしばらくの間実行パイプラインに入れていないんだ?となるよね。この辺も解析していきたい。