FPGA開発日記

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

Chiselを使ってCPUを作ろう(15. デザインのパラメタライズ)

f:id:msyksphinz:20181123005953p:plain

Chiselを使って、非常にシンプルなCPUを作ってみるプロジェクト。

CPUコアのバスサイズ、Debug情報のON/OFFなどをパラメータにより調整する。

github.com

デザインのパラメタライズ

パラメータ化する項目は、以下のようにして1つのクラスにまとめた。

RVConfigを継承して、RV64IConfigクラスを作成して、これをシミュレーション時に適用する。

  • src/main/scala/cpu/config.scala
abstract class RVConfig()
{
  val xlen = 32
  val bus_width = 16
  val debug = false
}

case class RV64IConfig() extends RVConfig
{
  override val xlen = 64
  override val bus_width = 16
  override val debug = true
}
  • src/test/scala/cpu/CpuTests.scala
class CpuTopTests [Conf <: RVConfig](c: CpuTop[Conf], hexname: String, pipename: String) extends PeekPokeTester(c)
{
  val fp = Source.fromFile(hexname)
  val lines = fp.getLines

...
class Tester extends ChiselFlatSpec {
  "Basic test using Driver.execute" should "be used as an alternative way to run specification" in {
    iotesters.Driver.execute(Array(), () => new CpuTop(new RV64IConfig)) {
      c => new CpuTopTests(c, "test.hex", "pipetrace.log")
    } should be (true)
  }
}

パラメータを各モジュールに適用させるのは、他のクラスと同様にパラメータを追加すればよい。

  • src/main/scala/cpu/cpu.scala
class Cpu [Conf <: RVConfig](conf: Conf) extends Module {
  val io = IO (new CpuIo(conf))
...

ちなみに、Bundle内でFlippedを使っている場合、デフォルトだとパラメータのコピーがうまくいかずにコンパイルに失敗する。

[error] (run-main-0) chisel3.core.AutoClonetypeException: Unable to automatically infer cloneType on class cpu.InstBus: constructor has parameters (conf) that are not both immutable and accessible. Either make all parameters immutable and accessible (vals) so cloneType can be inferred, or define a custom cloneType method.
[error] chisel3.core.AutoClonetypeException: Unable to automatically infer cloneType on class cpu.InstBus: constructor has parameters (conf) that are not both immutable and accessible. Either make all parameters immutable and accessible (vals) so cloneType can be inferred, or define a custom cloneType method.

したがって、Bundleに対してcloneTypeのカスタム関数を追加する必要があった。

class InstBus [Conf <: RVConfig](conf: Conf) extends Bundle {
  override def cloneType: this.type =
    new InstBus(conf).asInstanceOf[this.type]
...

デバッグ時のポート削除をパラメータで実現する

Verilogを生成時に、余計なデバッグポートを削除する。 これもParameterにより制御する。CPUのVerilog生成時には、RV64IConfigの代わりにRV64ISynthパラメータを適用する。

  • src/main/scala/cpu/cpu.scala
object CpuTop extends App {
  chisel3.Driver.execute(args, () => new CpuTop(new RV64ISynth))
}

conf.debug = falseに設定されているので、CpuDbgMonitorの信号が全て0ビットに設定され、削除される。 この方法は、 Chiselを使ってCPUを作ろう(5. トレース記述をどう作る?) のコメントで教えてもらった。

  • src/main/scala/cpu/cpu.scala
class CpuDebugMonitor [Conf <: RVConfig](conf: Conf) extends Bundle {
  val inst_valid = if (conf.debug == true) Output(Bool())             else Output(UInt(0.W))
  val inst_addr  = if (conf.debug == true) Output(UInt(32.W))         else Output(UInt(0.W))
  val inst_hex   = if (conf.debug == true) Output(UInt(32.W))         else Output(UInt(0.W))
...

これで、Verilog生成時のみデバッグポートを削除できる。