Chiselの3.3.0-RC1が公開されたのだが、その中に1つ気になる記述があったので今回は それについて試した内容をまとめておこうと思う。
Chisel 3.3.0-RC1を使ってみる
Chiselの公式ツイッターが3/30にChisel 3.3.0-RC1が公開されたと報告していた。
Chisel 3.3.0-RC1 is out! Please give this as much testing as you can. Notably new:
— Chisel (@chisel_lang) 2020年3月29日
- Better Asynchronous Reset
- FPGA Preset Reset
- Dependency API FIRRTL Transform Scheduling
- Interval Data Type
- Command Line Aspects
- Lots more!
Scasite base project: https://t.co/9HkWRqoCxK
でこの中に気になる記述が。。。それがこれ↓。
- Better Asynchronous Reset
ということで、今回は”それと思われるもの”について確認してみた。断定していないのはこのツイッターに記載されている以上の情報が無く、本当に今回紹介するのがその機能なのかの確証がないからで、この後に3.3.0のリリースノートを確認して修正するかも。
なのでgithub上でも3.3.0-RC1はタグが存在するのみとなっている。
ただ3.3.0-RC1は既にMaven Repositoryに公開されているのでchisel-templateを使っていれば使用するChiselのバージョンを変更するだけで使用可能だ。 以下は参考までに自分が使っている"biuld.sbt"の記述を抜粋したもの。
// Provide a managed dependency on X if -DXVersion="" is supplied on the command line. val defaultVersions = Map( "chisel3" -> "3.3.0-RC1", // バージョンを"3.3.0-RC1"にする "chisel-iotesters" -> "1.3.0", "treadle" -> "1.1.0" ) libraryDependencies ++= Seq("chisel3","chisel-iotesters").map { dep: String => "edu.berkeley.cs" %% dep % sys.props.getOrElse(dep + "Version", defaultVersions(dep)) } scalacOptions ++= scalacOptionsVersion(scalaVersion.value) javacOptions ++= javacOptionsVersion(scalaVersion.value) lazy val commonSettings = Seq ( organization := "edu.berkeley.cs", version := "2.0", // git.remoteRepo := "git@github.com:ucb-bar/riscv-sodor.git", autoAPIMappings := true, scalaVersion := "2.11.12", crossScalaVersions := Seq("2.11.12", "2.12.6"), resolvers ++= Seq( Resolver.sonatypeRepo("snapshots"), Resolver.sonatypeRepo("releases") ), scalacOptions := Seq( "-deprecation", "-feature", "-language:reflectiveCalls") ++ scalacOptionsVersion(scalaVersion.value), javacOptions ++= javacOptionsVersion(scalaVersion.value), // libraryDependenciesに"3.3.0-RC1"の場所を渡せばOK libraryDependencies ++= Seq("chisel3", "chisel-iotesters").map { dep: String => "edu.berkeley.cs" %% dep % sys.props.getOrElse(dep + "Version", defaultVersions(dep)) }, updateOptions := updateOptions.value.withLatestSnapshots(false), addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full), )
Better Asynchronous Resetってこれのこと?
そもそも本題のBetter Asynchronous Resetって何よ??って話なのだが、これはツイッターで「なにこれ、気になる」って呟いたら Chiselのメンテナさんが
- 「3.2.0から入っているリセットの推測を改善したものだよ」
って教えてくれた。 このコメントを参考にしつつChisel3.2.0以降のコミットとの差分をチェックしてこれかしら??というものを紹介しようと思う。
RequireAsyncReset トレイト
でコミットログを眺めてて見つけたのがRequireAsyncReset
というトレイト。
これを使うと自分のデザインをまるっと非同期リセットに変更できる。その意味ではPreset Resetなのかなぁ??と思ったりも。。。
使い方は簡単でトップモジュールにミックスインするだけ。なおこのトレイトと対になるRequireSyncReset
も定義されている。
class SubModule extends Module { val io = IO(new Bundle { val in = Input(Bool()) val out = Output(Bool()) }) io.out := RegNext(io.in, false.B) } class BetterAsyncReset extends Module with RequireAsyncReset { val io = IO(new Bundle { val in = Input(Bool()) val out = Output(Bool()) }) val m_sub = Module(new SubModule) m_sub.io.in := RegNext(io.in, false.B) io.out := m_sub.io.out }
上記のソースコードからRTLを生成すると、次のようにBetterAsyncReset
モジュールとSubModule
モジュールに存在するFFが非同期リセットを使ったものになる。
// IOとレジスタの部分のみを抜粋 module SubModule( input clock, input reset, input io_in, output io_out ); reg _T; // @[BetterAsyncReset.scala 14:20] always @(posedge clock or posedge reset) begin if (reset) begin _T <= 1'h0; end else begin _T <= io_in; end end endmodule module BetterAsyncReset( input clock, input reset, input io_in, output io_out ); reg _T; // @[BetterAsyncReset.scala 25:25] always @(posedge clock or posedge reset) begin if (reset) begin _T <= 1'h0; end else begin _T <= io_in; end end endmodule
Scalaのトレイトはモジュールのインスタンス時にもミックスインすることができるので、次のように引数 に応じて同期 or 非同期リセットを切り替えるようなことも可能になる。
// ここではModuleを継承しただけ class BetterAsyncReset extends Module { val io = IO(new Bundle { val in = Input(Bool()) val out = Output(Bool()) }) val m_sub = Module(new SubModule) m_sub.io.in := RegNext(io.in, false.B) io.out := m_sub.io.out } object Elaborate extends App { // 引数に応じてRequireAsyncResetをミックスインする val module = args(0) match { case "async" => () => new BetterAsyncReset with RequireAsyncReset case "sync" => () => new BetterAsyncReset } Driver.execute(Array("-td=rtl", "-tn=BetterAsyncReset"), module) }
因みにこの機能はModule
クラスの親クラスにあたるMultiIOModule
においてreset
信号がmkReset
メソッドの呼び出しに変更されたことで実現している。
trait RequireAsyncReset extends MultiIOModule { override private[chisel3] def mkReset: AsyncReset = AsyncReset() } trait RequireSyncReset extends MultiIOModule { override private[chisel3] def mkReset: Bool = Bool() } /** Abstract base class for Modules, which behave much like Verilog modules. * These may contain both logic and state which are written in the Module * body (constructor). * This abstract base class includes an implicit clock and reset. * * @note Module instantiations must be wrapped in a Module() call. */ abstract class MultiIOModule(implicit moduleCompileOptions: CompileOptions) extends RawModule { // Implicit clock and reset pins final val clock: Clock = IO(Input(Clock())) final val reset: Reset = IO(Input(mkReset)) // mkResetの戻り値 private[chisel3] def mkReset: Reset = { // Top module and compatibility mode use Bool for reset val inferReset = _parent.isDefined && moduleCompileOptions.inferModuleReset if (inferReset) Reset() else Bool() }
ということでChisel3.3.0で入るっぽいモジュールのリセットのタイプを制御するトレイトRequireAsyncReset
の紹介でした。
でも正式に3.3.0が公開された時には、この記事に修正が入るかも??