Open5

RISC-V CPU自作本を読む

mikikenmikiken

理解が不十分なままの部分もあるので、メモしつつ振り返る

mikikenmikiken

Scalaの文法

https://scala-text.github.io/scala_text/

varval

https://qiita.com/takc923/items/f62c173beacee280c369

シングルトンオブジェクト (object)

  • Javaの場合、クラス自体に属する(インスタンスを生成せずに呼び出せる)メンバ(staticフィールドやstaticメソッド)を定義可能
  • Scalaでは、staticフィールドやstaticメソッドの定義はできない
  • その代わりに、同一名前空間に1つだけ同名のオブジェクトを定義でき、それをシングルトンオブジェクトという
  • シングルトンオブジェクト固有のフィールドやメソッドを定義できる

https://scala-text.github.io/scala_text/object.html

SeqとかListとかの関係がよく分からん

  • これ

    scala.collection.immutableの全コレクション (Scalaの公式ドキュメントより引用)
  • 単にSeqと書いた場合、immutableのSeqのサブクラスであるListとして宣言される
  • なお、mutableなコレクションもある(scala.collection.mutable)

trait

  • 複数のクラス間でメンバを共有するために使う
  • クラスからコンストラクタを定義する機能を抜いたようなもの
  • 単体ではインスタンス化できない
mikikenmikiken

Chiselの文法

UInt/SIntオブジェクト

val a = UInt(32.W) // 符号なし整数型"信号"
val b = SInt(32.W) // 符号あり整数型"信号"
  • UInt()という記法は、UInt.apply()と等価
    • (Scalaにおいてapplyという名前のメソッドは省略可能)
  • 自然数.Wはbit幅を表すWidth型を返すメソッド
// 定数のUInt変換
val a = 2.U(32.W) // ScalaのInt型定数をChiselのUInt型に変換するメソッド

// 変数のUInt変換
val b = 2
val c = b.asUInt(32.W) // ScalaのInt型変数をChiselのUInt型に変換するメソッド
  • ScalaのInt → ChiselのUIntに変換するメソッド
    • .U 定数に対し用いるのが推奨されている
    • .asUInt 変数に対し用いるのが推奨されている

Module

// 回路を定義するSampleクラスの宣言
class Sample extends Module {...}

// Scala上でインスタンス化
val instance = new Sample()

// Chiselのハードウェア化 (Moduleオブジェクトに対しapplyメソッドを適用)
val hardware1 = Module.apply(instance)
val hardware2 = Moduke(instance) // 上記の省略形

clockreset

  • Moduleを継承したクラスであるIOクラスでは、暗黙的にclockreset信号が定義されている
  • レジスタに対して自動的に接続されている
  • 立ち上がりエッジトリガで動作

Wire/WireDefault

  • 組み合わせ回路を記述するのに使用
  • 接続先が未定の状態で、Chiselのハードウェアを確保したい場合に使用
val a = Wire(UInt(32.W))       // 32bit幅の配線
val b = WireDefault(0.U(32.W)) // 0.Uがはじめから接続されている32bit幅の配線
...
a := ... // aの接続先が確定

RegInit

  • 順序回路(レジスタ)を記述するのに使用
  • 引数で初期値を設定
val reg = RegInit(0.U(32.W))

reg := 1.U(32.W)        // 次クロックの立ち上がりエッジでレジスタの値が1になる
reg : = reg + 1.U(32.W) // クロックの立ち上がりごとにregがインクリメント

Memオブジェクト

  • レジスタファイルを定義するために使用
  • レジスタの配列
val regfile = Mem(32, UInt(32.W)) // 32bit幅のレジスタを32本定義

// 1番レジスタのデータを読み出し
val read_data = regfile(1.U)

// 1番レジスタにデータを書き込み
regfile(1.U) := <書き込みデータ>