『はじめてのCPU自作』でわからなかったところメモ
p.116
おそらく rf_wen
、wb_sel
という言葉についてこれまで説明がない?
-
rf
が何の略語なのか -
wen
は前の章に載っていて Write Enable 信号の略だと思うけれど、ほぼ説明はない気がする。 -
sel
は何の略?信号の名前なんだろうか。
p.120
わたしがシフト演算めっちゃ苦手だからなのだが、下記の文がいまいちわからない。あとで考える。
Chisel の左シフト演算子 << は bit 幅をシフト量分拡張するため、(31, 0) の bit 選択により、下位 32 bit を抽出します。加算ではオーバオフローしても返り値の bit 幅が変わりませんが、左シフトでは bit 幅が増えるので注意して下さい。
各命令の実装あたりからテストコードが消えてしまったので、写経を間違えたらどこで間違えたかわからなくなりそう。なんかうまいことテスト書く方法ないのかな。
ジャンプ命令の実装中に小一時間悩んでしまった。
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),
さてここまで Chisel を書いてきたけれど、肝心の Chisel の情報って実は少なくて、結局どういうものなのかよくわかっていない。
Scala を採用したのは Scala が DSL を書きやすいからかなと思っていたけど、やっぱりそうだったみたい。Scala のよい利用例の一つだと思う。
個人的には仕事で Scala を使っているので、普通に慣れたツールチェーンでハードウェアを記述できてしまうのは嬉しくて仕方がない。
こちらはあとで読む。
Chisel を調べると SystemVerilog などの名前がたくさん出てくる。全然何がどう違うかわかっていないので、これも今度調べておく。