ハードウェアの気になるあれこれ

技術的に興味のあることを調べて書いてくブログ。主にハードウェアがネタ。

ChiselのPeekPokeTesterにはIntをBigIntに変換するメソッドがあった話

スポンサーリンク

前回のChiselのテスト実行時にプログラム引数を指定する方法についてを紹介した。

www.tech-diningyo.info

今日は以前に書いた”UIntの大きな定数を指定する方法”を書いた時には気づかなかったメソッドを見つけたのでそれを紹介しようと思う。

ChiselでUIntの大きな数字を扱うと。。

以前にこんな感じのネタ↓を書いた。

www.tech-diningyo.info

詳しくは記事を見ていただきたいのだが、簡単にまとめると以下のようなテストコードを書いたらエラーになったという話だった。

Driver.execute(Array(""), () => new Module {
  val io = IO(new Bundle {
    val out = Output(UInt(32.W))
  })  

  io.out := BigInt("deadbeaf", 16).U
}) {
  c => new PeekPokeTester(c) {
    expect(c.io.out, 0xdeadbeaf) // ここが符号付き整数で解釈されて期待値不一致
  }
}
  • 実行結果
[info] [0.000] Elaborating design...
[info] [0.052] Done elaborating.
Total FIRRTL Compile Time: 12.5 ms
Total FIRRTL Compile Time: 6.7 ms
End of dependency graph
Circuit state created
[info] [0.001] SEED 1554388458299
[info] [0.004] EXPECT AT 0   io_out got 3735928495 expected -558907729 FAIL
test cmd5Helperanonfun1anon2 Success: 0 tests passed in 5 cycles taking 0.012101 seconds
[info] [0.006] RAN 0 CYCLES FAILED FIRST AT CYCLE 0

何が起きているかというとScalaにはInt型のみが存在しており、符号なし整数が存在していないため、上記の定数0xdeadbeafはMSBが符号ビットとして解釈されUIntに変換する際にこの数はSIntで型が合わない!!とエラーになるということがだった。

これを解決するための方法として、

  • Long型を使う : 0xdeadbeafL
  • BigIng型を使う : BigInt("deadbeaf", 16)

という方法を紹介した。

でもちゃんとIntBigIntに変換するメソッドがある

ここからがこの記事の本文。 でもただ単にこんなのあったよーという内容なのであっさり目。
メソッドはPeekPokeTesterに定義されている以下の2つ。

  • intToUnsignedBigInt(x: Int): BigInt
  • longToUnsignedBigInt(x: Long): BigInt

使い方は上記のメソッド定義のまんまで引数にInt/Longのデータを入れるだけ。 早速先ほどのコードで使ってみよう。

Driver.execute(Array(""), () => new Module {
  val io = IO(new Bundle {
    val out = Output(UInt(32.W))
  })  

  io.out := BigInt("deadbeaf", 16).U
}) {
  c => new PeekPokeTester(c) {
    expect(c.io.out, intToUnsignedBigInt(0xdeadbeaf)) // 使ってみる
  }
}
  • 実行結果
[info] [0.000] Elaborating design...
[info] [0.007] Done elaborating.
Total FIRRTL Compile Time: 5.4 ms
Total FIRRTL Compile Time: 6.7 ms
End of dependency graph
Circuit state created
[info] [0.000] SEED 1554388647135
test cmd7Helperanonfun1anon2 Success: 1 tests passed in 5 cycles taking 0.001926 seconds
[info] [0.002] RAN 0 CYCLES PASSED

今度はPASSした。
因みにこの2つのメソッドはPeekPokeTesterに実装されているので、PeekPokeTesterインスタンスや、これを継承して作った自分のモジュール向けのテスタークラス内でしか使用できない点に注意が必要だ。

実装を見てみる

この2つのメソッドはとてもシンプルな(&個人的には目からウロコな)実装になっているので、紹介しておく。

  /**
    * Convert an Int to unsigned (effectively 32-bit) BigInt
    * @param x  number to be converted
    * @return
    */
  def intToUnsignedBigInt(x: Int): BigInt = (BigInt(x >>> 1) << 1) | BigInt(x & 1)

実装は簡単で

  1. 入れたIntを右に1bitシフト
  2. 1bit右にシフトしたものを左にシフト
  3. LSBの1bitが削れているのそれをorする

というもの。 こんな感じなので通常のモジュールでも何か固定値を埋め込むようなケースでは使うのものありかもしれない。

というわけで今日はあっさり目のメソッドの紹介でした。