FPGA開発日記

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

ChiselとDiplomacyを使ってオリジナルデザインを作成してみる (2. Rocket-Chipの確認)

Diplomacyの勉強をしていて、さてRocket-Chipの場合はどのようにして外部インタフェースと接続しているのか、具体的にはどのようにELFファイルなどのテストパタンをロードしているのか気になってきたので調査してみた。

  • Verilatorの場合

VerilatorはシミュレーションのためのTopファイルとしてC++ファイルが必要となる。これはRocket-Chipのディレクトリでは以下に配置してある。

  • rocket-chip/src/main/resources/csrc/emulator.cc
int main(int argc, char** argv)
{
  unsigned random_seed = (unsigned)time(NULL) ^ (unsigned)getpid();
  uint64_t max_cycles = -1;
  int ret = 0;
  bool print_cycles = false;
...
done_processing:
  if (optind == argc) {
    std::cerr << "No binary specified for emulator\n";
    usage(argv[0]);
    return 1;
  }
  int htif_argc = 1 + argc - optind;
  htif_argv = (char **) malloc((htif_argc) * sizeof (char *));
  htif_argv[0] = argv[0];
  for (int i = 1; optind < argc;) htif_argv[i++] = argv[optind++];

  if (verbose)
    fprintf(stderr, "using random seed %u\n", random_seed);
...
  jtag = new remote_bitbang_t(rbb_port);
  dtm = new dtm_t(htif_argc, htif_argv);

で、具体的にはhtif_argvに使用するELFファイルが指定されて、これがdtm_tに引数として指定されインスタンス化される。

このdtmを操作しているのが、SimDTMというモジュールのようだった。

module TestHarness( // @[freechips.rocketchip.system.DefaultConfig.fir 238618:2]
  input   clock, // @[freechips.rocketchip.system.DefaultConfig.fir 238619:4]
  input   reset, // @[freechips.rocketchip.system.DefaultConfig.fir 238620:4]
  output  io_success // @[freechips.rocketchip.system.DefaultConfig.fir 238621:4]
);
...
  SimDTM SimDTM ( // @[Periphery.scala 257:25 freechips.rocketchip.system.DefaultConfig.fir 238700:4]
    .clk(SimDTM_clk),
    .reset(SimDTM_reset),
    .debug_req_ready(SimDTM_debug_req_ready),
    .debug_req_valid(SimDTM_debug_req_valid),
    .debug_req_bits_addr(SimDTM_debug_req_bits_addr),
    .debug_req_bits_data(SimDTM_debug_req_bits_data),
    .debug_req_bits_op(SimDTM_debug_req_bits_op),
    .debug_resp_ready(SimDTM_debug_resp_ready),
    .debug_resp_valid(SimDTM_debug_resp_valid),
    .debug_resp_bits_data(SimDTM_debug_resp_bits_data),
    .debug_resp_bits_resp(SimDTM_debug_resp_bits_resp),
    .exit(SimDTM_exit)
  );

これは、Scalaのモジュールには直接インスタンス化されているようではないらしい。

  • rocket-chip/src/main/scala/system/TestHarness.scala
class TestHarness()(implicit p: Parameters) extends Module {
  val io = IO(new Bundle {
    val success = Output(Bool())
  })

  val ldut = LazyModule(new ExampleRocketSystem)
  val dut = Module(ldut.module)

  // Allow the debug ndreset to reset the dut, but not until the initial reset has completed
  dut.reset := (reset.asBool | dut.debug.map { debug => AsyncResetReg(debug.ndreset) }.getOrElse(false.B)).asBool

  dut.dontTouchPorts()
  dut.tieOffInterrupts()
  SimAXIMem.connectMem(ldut)
  SimAXIMem.connectMMIO(ldut)
  ldut.l2_frontend_bus_axi4.foreach(_.tieoff)
  Debug.connectDebug(dut.debug, dut.resetctrl, dut.psd, clock, reset.asBool, io.success)
}
  • rocket-chip/src/main/scala/devices/debug/Periphery.scala
class SimDTM(implicit p: Parameters) extends BlackBox with HasBlackBoxResource {
  val io = IO(new Bundle {
    val clk = Input(Clock())
    val reset = Input(Bool())
    val debug = new DMIIO
    val exit = Output(UInt(32.W))
  })

  def connect(tbclk: Clock, tbreset: Bool, dutio: ClockedDMIIO, tbsuccess: Bool) = {
    io.clk := tbclk
    io.reset := tbreset
    dutio.dmi <> io.debug
    dutio.dmiClock := tbclk
    dutio.dmiReset := tbreset

    tbsuccess := io.exit === 1.U
    when (io.exit >= 2.U) {
      printf("*** FAILED *** (exit code = %d)\n", io.exit >> 1.U)
      stop(1)
    }
  }

  addResource("/vsrc/SimDTM.v")
  addResource("/csrc/SimDTM.cc")
}

最後のaddResourceVerilogファイルとC言語のDPI関数を追加している。

  • rocket-chip/src/main/resources/vsrc/SimDTM.v
// See LICENSE.SiFive for license details.
//VCS coverage exclude_file

import "DPI-C" function int debug_tick
(
  output bit     debug_req_valid,
  input  bit     debug_req_ready,
  output int     debug_req_bits_addr,
  output int     debug_req_bits_op,
  output int     debug_req_bits_data,

  input  bit        debug_resp_valid,
  output bit        debug_resp_ready,
  input  int        debug_resp_bits_resp,
  input  int        debug_resp_bits_data
);

module SimDTM(
  input clk,
  input reset,

  output        debug_req_valid,
  input         debug_req_ready,
  output [ 6:0] debug_req_bits_addr,
  output [ 1:0] debug_req_bits_op,
  output [31:0] debug_req_bits_data,

  input         debug_resp_valid,
  output        debug_resp_ready,
  input  [ 1:0] debug_resp_bits_resp,
  input  [31:0] debug_resp_bits_data,

  output [31:0] exit
);

つまり、Diplomacyで外部C言語関数とやり取りをしたい場合、このようなラッパーになるような関数を書いて、DPI関数を通じて直接接続しなければならないということかな。

f:id:msyksphinz:20200112022200p:plain