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) ); ...