FPGA開発日記

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

RISC-V BOOMプロセッサのRTLシミュレーションを実行したい(Veritakで挑戦→解析中)

RISC-Vのアウトオブオーダ実装であるBOOM (Berkeley Out-of-Order Machine)のRTLシミュレーションは、基本的にverilatorを使って実行されている。

それもそのはず、BOOMはオープンソースハードウェアであるため、オープンソースのシミュレータを使わないと万人が利用できない。

しかし、波形を観測したり、デバッグをしたりするのにverilatorだけでは不便だ。今回は僕がいつも(趣味なFPGA開発のときに)利用しているVeritakに移植してみよう。

BOOM のハードウェアを改造してRTLシミュレーション用に変更する

BOOMのRTL実装は1ファイルにまとめられており、boomのリポジトリをビルドすると、rocketchip.BOOMConfig.v というファイルにまとめられている。 昨日のブログでも紹介したとおり、これは80万行超の膨大なファイルであり、全体を見渡すのはなかなかやっかいだ。

msyksphinz.hatenablog.com

トップに存在するのはTestHarness()というモジュールだ。ここにはどうやらCPUの本体と、外部周辺RAM、モニタ、インターコネクトなどが接続されているらしい。

この部分はまだテストベンチとしての役割ではなさそうだ。Verilatorの場合、さらに上にC++のラッパーを被せるのだろう。今回はVeritakで動作させるため、Verilogで記述されたテストベンチを記述する必要がある。

module TestHarness(
  input   clock,
  input   reset,
  output  io_success
);
  wire  dut_clock;
  wire  dut_reset;
  wire  dut_io_success;
  wire  dut_io_debug_req_ready;
  wire  dut_io_debug_req_valid;
...

まず、TestHarnessを動作させるためのテストベンチを作成した。

`timescale 100ps / 1ps

module tb;

  parameter STEP     = 100000;
  parameter H_STEP   = 50000;
  parameter H2_STEP  = 25000;

  reg CPU_CLK;
  reg CPU_RESET;

  integer step_count;

  TestHarness
  u_TestHarness
    (
     .clock (CPU_CLK),
     .reset (CPU_RESET),
     .io_success ()
    );
  always # (H_STEP) begin
    CPU_CLK <= ~CPU_CLK;
  end

  initial begin
    CPU_CLK   = 1'b1;
    CPU_RESET = 1'b1;

    #(STEP * 10);
    CPU_RESET = 1'b0;

    for (step_count = 0; step_count < 100; step_count = step_count) begin
      #(STEP * 20000);
      $display ("%t", $time);
    end
    $display ("<Info: Simulation TimeOut %t>", $time);
    $finish;
    // $stop;
  end

endmodule // tb_rocketchip

Veritakでコンパイルしてみると、rocketchip.BOOMConfig.v には$Fatalというシステムタスクが呼ばれており、これがVeritakには無いと怒られてしまった。ここの部分は改造するしか無さそうだ。

        if (T_41 & T_45) begin
          $Fatal;
        end

改造する。

        if (T_41 & T_45) begin
          $display ("Fatal error. Exit"); $finish;
        end

一応コンパイルは通るようになったのだが、シミュレーションが開始されない。いくつかトップモジュールを変更して試行してみたのだが、正しく動作させるまでには至らなかった。まだ解析が必要そうだ。

f:id:msyksphinz:20161102010927p:plain

備考: BOOMはどこから命令をフェッチするのか?

rocketchip.BOOMConfig.v を探索していると、bootrom というモジュールを見つけた。 探ってみると、内部の1000ワード近くを、RAMモデルを使わずすべてワイヤで記述してある...!

BOOMのモデルの中には、こういう部分が多量にあるはずだ。これを律儀にVeritakで動作させようとしたから、重かったのかなあ。。。?

module bootrom(
  input   clock,
  input   reset,
  output  io_in_0_a_ready,
  input   io_in_0_a_valid,
...
  input   io_in_0_e_bits_sink
);
  wire [31:0] rom_0;
  wire [31:0] rom_1;
  wire [31:0] rom_2;
...
  reg [31:0] GEN_1030;
  reg [31:0] GEN_1037;
  assign io_in_0_a_ready = io_in_0_d_ready;
  assign io_in_0_b_valid = 1'h0;
  assign io_in_0_b_bits_opcode = GEN_1024;
  assign io_in_0_b_bits_param = GEN_1025;
  assign io_in_0_b_bits_size = GEN_1026;
  assign io_in_0_b_bits_source = GEN_1027;
  assign io_in_0_b_bits_addr_hi = GEN_1028;
  assign io_in_0_b_bits_mask = GEN_1029;
  assign io_in_0_b_bits_data = GEN_1030;
  assign io_in_0_c_ready = 1'h1;
  assign io_in_0_d_valid = io_in_0_a_valid;
  assign io_in_0_d_bits_opcode = T_2371_opcode;
  assign io_in_0_d_bits_param = T_2371_param;
  assign io_in_0_d_bits_size = T_2371_size;
  assign io_in_0_d_bits_source = T_2371_source;
  assign io_in_0_d_bits_sink = T_2371_sink;
  assign io_in_0_d_bits_addr_lo = T_2371_addr_lo;
  assign io_in_0_d_bits_data = T_2371_data;
  assign io_in_0_d_bits_error = T_2371_error;
  assign io_in_0_e_ready = 1'h1;
  assign rom_0 = 32'h6f;
  assign rom_1 = 32'h0;
  assign rom_2 = 32'h0;
  assign rom_3 = 32'h1020;
  assign rom_4 = 32'h0;
  assign rom_5 = 32'h0;
  assign rom_6 = 32'h0;
  assign rom_7 = 32'h0;
  assign rom_8 = 32'h63696c70;
  assign rom_9 = 32'h200a7b20;
  assign rom_10 = 32'h69727020;
  assign rom_11 = 32'h7469726f;
  assign rom_12 = 32'h78302079;
...