Chiselを使ったDiplomacyのデザイン、久しぶりに再会した。いくつか例を作ってみたいと思うので、大昔に作った自作のRISC-V Chisel CPUコアをDiplomacyで載せ替えて、簡単にバス接続が実現できる様子を観察してみたい。
まず、大昔に用意したCPUコアは以下のインタフェースを持っている。簡単な命令バスとデータバスが並んでいる。
class CpuIo [Conf <: RVConfig](conf: Conf) extends Bundle { val run = Input(Bool()) val inst_bus = new InstBus(conf) val data_bus = new DataBus(conf) val dbg_monitor = new CpuDebugMonitor(conf) }
これをTileLinkに乗せ換えるのがとりあえず手っ取り早そうだ。まずはDiplomacyを使ったTileLinkのラッパーモジュールを作った。
class CoreTop(name: String)(implicit p: Parameters) extends LazyModule { val inst_node = TLClientNode(Seq(TLClientPortParameters(Seq(TLClientParameters(name = name + "_inst"))))) val data_node = TLClientNode(Seq(TLClientPortParameters(Seq(TLClientParameters(name = name + "_name"))))) lazy val module = new LazyModuleImp(this) { val io = IO(new Bundle { val run = Input(Bool()) val cpu = Module(new Cpu(new RV64IConfig)) cpu.io.run := true.B ...
CoreTop
モジュール内でLazyModuleImp
を作成し、その中でcpu
をインスタンス化している。このcpu
モジュールに対してTileLinkのI/Oを接続していくという訳だ。
inst_out.a.valid := cpu.io.inst_bus.req inst_out.a.bits.address := cpu.io.inst_bus.addr inst_out.a.bits.opcode := TLMessages.Get inst_out.a.bits.param := 0.U cpu.io.inst_bus.ack := inst_out.d.valid cpu.io.inst_bus.rddata := inst_out.d.bits.data.asSInt data_out.a.valid := cpu.io.data_bus.req data_out.a.bits.address := cpu.io.data_bus.addr data_out.a.bits.opcode := TLMessages.Get data_out.a.bits.param := 0.U cpu.io.data_bus.ack := data_out.d.valid cpu.io.data_bus.rddata := data_out.d.bits.data.asSInt
このようにして作成したCoreTop
モジュールは、命令バスとデータバスの2つのノードが存在していることになる。これらをSoC内で接続するためには以下のようにする。
class core_complex(ramBeatBytes: Int, txns: Int)(implicit p: Parameters) extends LazyModule { val loader = LazyModule(new loader("loader")) // val ifu = LazyModule(new ifu("ifu")) val core = LazyModule(new CoreTop("core")) val xbar = LazyModule(new TLXbar) val memory = LazyModule(new TLRAM(AddressSet(0x02000, 0x0fff), beatBytes = ramBeatBytes)) xbar.node := loader.node xbar.node := TLDelayer(0.0001) := core.inst_node xbar.node := TLDelayer(0.0001) := core.data_node memory.node := xbar.node
CoreTop
をLazyModule
でインスタンス化し、core.inst_node
とcore.data_node
をクロスバーに接続している。
xbar.node := TLDelayer(0.0001) := core.inst_node xbar.node := TLDelayer(0.0001) := core.data_node
この構成について、GraphMLによるノード関係を出力してみると以下のようになった。core
から2つのノードが出ており、最終的にxbar
を経由してmemory
に繋がっている。上手く行っているようだ。