FPGA開発日記

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

Chipyardで独自コアシミュレーション環境構築方法の調査 (3. 独自コアの入出力ピンサポート)

RISC-Vコアのシミュレーション環境Chipyardでは、現在Rocket-Chip、BOOM、Arianeがサポートされているが、独自CPUコアをサポートするにあたり入出力ポートを独自CPU向けに改造する必要がある。

まず、ここではまず独自CPU側では以下のインタフェースを使っているものとする(まだ実装中)。

module mrh_tile_wrapper
(
    input logic i_clk,
    input logic i_reset_n,

    // L2 request from ICache
    output logic                                o_ic_req_vaild,
    output mrh_pkg::mem_cmd_t                   o_ic_req_cmd,
    output logic [riscv_pkg::PADDR_W-1:0]       o_ic_req_addr,
    output logic [mrh_pkg::L2_CMD_TAG_W-1:0]    o_ic_req_tag,
    output logic [mrh_pkg::ICACHE_DATA_W-1:0]   o_ic_req_data,
    output logic [mrh_pkg::ICACHE_DATA_W/8-1:0] o_ic_req_byte_en,
    input logic                                 i_ic_req_ready,

    input logic                              i_ic_resp_valid,
    input logic [mrh_pkg::L2_CMD_TAG_W-1:0]  i_ic_resp_tag,
    input logic [mrh_pkg::ICACHE_DATA_W-1:0] i_ic_resp_data,
    output logic                             o_ic_resq_ready
);

これをChisel側のMSRHTile側のブラックボックスでも同じようにポートを宣言する。

  • generators/msrh/src/main/scala/MSRHCoreBlackbox.scala
class MSRHCoreBlackbox(
  xLen: Int
)
  extends BlackBox
  with HasBlackBoxResource
{
  val io = IO(new Bundle {
    val i_clk = Input(Clock())
    val i_reset_n = Input(Bool())

    val o_ic_req_valid   = Output(Bool())
    val o_ic_req_cmd     = Output(UInt(4.W))
    val o_ic_req_addr    = Output(UInt(39.W))
    val o_ic_req_tag     = Output(UInt(4.W))
    val o_ic_req_data    = Output(UInt(512.W))
    val o_ic_req_byte_en = Output(UInt((512/8).W))
    val i_ic_req_ready   = Input(Bool())

    val i_ic_resp_valid = Input(Bool())
    val i_ic_resp_tag   = Input(UInt(4.W))
    val i_ic_resp_data  = Input(UInt(512.W))
    val o_ic_resq_ready = Input(Bool())
  })

同じように名前を統一することでVerilogコンパイル時にポートを認識できるようにする。

MSRHTile側はTileLinkのポートを持っているので、独自ポートをTileLinkに接続する。

  • generators/msrh/src/main/scala/MSRHTile.scala
class MSRHTile(
  val MSRHParams: MSRHTileParams,
  crossing: ClockCrossingType,
  lookup: LookupByHartIdImpl,
  q: Parameters,
  logicalTreeNode: LogicalTreeNode)
  extends BaseTile(MSRHParams, crossing, lookup, q)
  with SinksExternalInterrupts
  with SourcesExternalNotifications
{
...
  val memTLNode = TLClientNode(Seq(TLClientPortParameters(
    cacheClientParameters)))
...
  // connect the MSRH core
  val core = Module(new MSRHCoreBlackbox(
    // general core params
    xLen = p(XLen),
  ))
...
    
  // connect the axi interface
  outer.memTLNode.out foreach { case (out, edgeOut) =>
    out.a.valid        := core.io.o_ic_req_valid
    out.a.bits.opcode  := core.io.o_ic_req_cmd
    out.a.bits.param   := 0.U
    out.a.bits.size    := 0.U
    out.a.bits.source  := core.io.o_ic_req_tag
    out.a.bits.address := core.io.o_ic_req_addr
    // out.a.bits.user    := 0.U
    // out.a.bits.echo    := 0.U
    out.a.bits.mask    := 0.U
    out.a.bits.data    := 0.U
    out.a.bits.corrupt := 0.U
    core.io.i_ic_req_ready     := out.a.ready
  }

これでVerilogを合成すると以下のようになった。

module MSRHTile( // @[:chipyard.TestHarness.MSRHConfig.fir@195189.2]
  input         clock, // @[:chipyard.TestHarness.MSRHConfig.fir@195190.4]
  input         reset, // @[:chipyard.TestHarness.MSRHConfig.fir@195191.4]
  input         auto_int_in_xing_in_2_sync_0, // @[:chipyard.TestHarness.MSRHConfig.fir@195192.4]
  input         auto_int_in_xing_in_1_sync_0, // @[:chipyard.TestHarness.MSRHConfig.fir@195192.4]
  input         auto_tl_master_xing_out_a_ready, // @[:chipyard.TestHarness.MSRHConfig.fir@195192.4]
...
  MSRHCoreBlackbox core ( // @[MSRHTile.scala 220:20:chipyard.TestHarness.MSRHConfig.fir@195383.4]
    .i_clk(core_i_clk),
    .i_reset_n(core_i_reset_n),
    .o_ic_req_valid(core_o_ic_req_valid),
    .o_ic_req_cmd(core_o_ic_req_cmd),
    .o_ic_req_addr(core_o_ic_req_addr),
    .o_ic_req_tag(core_o_ic_req_tag),
    .o_ic_req_data(core_o_ic_req_data),
    .o_ic_req_byte_en(core_o_ic_req_byte_en),
    .i_ic_req_ready(core_i_ic_req_ready),
    .i_ic_resp_valid(core_i_ic_resp_valid),
    .i_ic_resp_tag(core_i_ic_resp_tag),
    .i_ic_resp_data(core_i_ic_resp_data),
    .o_ic_resq_ready(core_o_ic_resq_ready)
  );
...