Open5

『はじめてのCPU自作』でわからなかったところメモ

yukiyuki

p.116

おそらく rf_wenwb_sel という言葉についてこれまで説明がない?

  • rf が何の略語なのか
  • wen は前の章に載っていて Write Enable 信号の略だと思うけれど、ほぼ説明はない気がする。
  • sel は何の略?信号の名前なんだろうか。
yukiyuki

p.120

わたしがシフト演算めっちゃ苦手だからなのだが、下記の文がいまいちわからない。あとで考える。

Chisel の左シフト演算子 << は bit 幅をシフト量分拡張するため、(31, 0) の bit 選択により、下位 32 bit を抽出します。加算ではオーバオフローしても返り値の bit 幅が変わりませんが、左シフトでは bit 幅が増えるので注意して下さい。

yukiyuki

各命令の実装あたりからテストコードが消えてしまったので、写経を間違えたらどこで間違えたかわからなくなりそう。なんかうまいことテスト書く方法ないのかな。

yukiyuki

ジャンプ命令の実装中に小一時間悩んでしまった。

  val alu_out = MuxCase(
    0.U(WORD_LEN.W),
    Seq(
      (exe_fun === ALU_ADD) -> (op1_data + op2_data),
      (exe_fun === ALU_SUB) -> (op1_data - op2_data),
      (exe_fun === ALU_AND) -> (op1_data & op2_data),
      (exe_fun === ALU_OR) -> (op1_data | op2_data),
      (exe_fun === ALU_XOR) -> (op1_data ^ op2_data),
      (exe_fun === ALU_SLL) -> (op1_data << op2_data(4, 0))(31, 0),
      (exe_fun === ALU_SRL) -> (op1_data >> op2_data(4, 0)).asUInt(),
      (exe_fun === ALU_SRA) -> (op1_data.asSInt() >> op2_data(4, 0)).asUInt(),
      (exe_fun === ALU_SLT) -> (op1_data.asSInt() < op2_data.asSInt()).asUInt(),
      (exe_fun === ALU_SLTU) -> (op1_data < op2_data).asUInt(),
      (exe_fun === ALU_JALR) -> ((op1_data + op2_data) & ~1.U(WORD_LEN.W)),
    )
  )

上述の

(exe_fun === ALU_JALR) -> ((op1_data + op2_data) & ~1.U(WORD_LEN.W)),

の部分、本書では下記のように書かれているが、コンパイルエラーになる。外側のカッコがないと、どうやら演算の優先順位が決まらず、とくに 1.U(WORD_LEN.W) に関する型推論が誤って行われるので、& 演算子が UInt 型から正しく探されずコンパイルエラーになる模様。

(exe_fun === ALU_JALR) -> (op1_data + op2_data) & ~1.U(WORD_LEN.W),
yukiyuki

さてここまで Chisel を書いてきたけれど、肝心の Chisel の情報って実は少なくて、結局どういうものなのかよくわかっていない。

https://qiita.com/Rockdoor/items/c266a50347df82373e7f

Scala を採用したのは Scala が DSL を書きやすいからかなと思っていたけど、やっぱりそうだったみたい。Scala のよい利用例の一つだと思う。

個人的には仕事で Scala を使っているので、普通に慣れたツールチェーンでハードウェアを記述できてしまうのは嬉しくて仕方がない。

こちらはあとで読む。

https://www.chisel-lang.org/

Chisel を調べると SystemVerilog などの名前がたくさん出てくる。全然何がどう違うかわかっていないので、これも今度調べておく。