前回のChiselのテスト実行時にプログラム引数を指定する方法についてを紹介した。
今日は以前に書いた”UIntの大きな定数を指定する方法”を書いた時には気づかなかったメソッドを見つけたのでそれを紹介しようと思う。
ChiselでUIntの大きな数字を扱うと。。
以前にこんな感じのネタ↓を書いた。
詳しくは記事を見ていただきたいのだが、簡単にまとめると以下のようなテストコードを書いたらエラーになったという話だった。
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)
という方法を紹介した。
でもちゃんとInt
をBigInt
に変換するメソッドがある
ここからがこの記事の本文。
でもただ単にこんなのあったよーという内容なのであっさり目。
メソッドは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)
実装は簡単で
- 入れた
Int
を右に1bitシフト - 1bit右にシフトしたものを左にシフト
- LSBの1bitが削れているのそれをorする
というもの。 こんな感じなので通常のモジュールでも何か固定値を埋め込むようなケースでは使うのものありかもしれない。
というわけで今日はあっさり目のメソッドの紹介でした。