Chiselを使って、非常にシンプルなCPUを作ってみるプロジェクト。5ステージまで拡張したので、次はフォワーディングパスを追加して正常に演算を実行できるようにする。
ALUのフォワーディングパスは、
- WBステージ → EXステージ
- MEMステージ → EXステージ
- EXステージ → EXステージ
の3種類のフォワードパスを追加して、書き込み先アドレスと使用アドレスが同一ならば、フォワードするようにする。 Verilogと書き方は全く同じだ。
minicpu/src/main/scala/cpu/cpu.scala
switch(ex_op0_sel) { is (OP0_RS1) { // Register Forwarding when (mem_inst_valid & mem_inst_wb_en & (mem_inst_rd === ex_inst_rs0)) { ex_alu_op0 := mem_alu_res } .elsewhen (wb_inst_valid & wb_inst_wb_en & (wb_inst_rd === ex_inst_rs0)) { ex_alu_op0 := Mux (wb_ctrl_mem_cmd === MCMD_RD, wb_mem_rdval, wb_alu_res) } .otherwise { ex_alu_op0 := ex_rdata_op0 } ... switch(ex_op1_sel) { // Register Forwarding is (OP1_PC ) { ex_alu_op1 := ex_inst_addr.asSInt } is (OP1_RS2) { when (mem_inst_valid & mem_inst_wb_en & (mem_inst_rd === ex_inst_rs1)) { ex_alu_op1 := mem_alu_res } .elsewhen (wb_inst_valid & wb_inst_wb_en & (wb_inst_rd === ex_inst_rs1)) { ex_alu_op1 := Mux (wb_ctrl_mem_cmd === MCMD_RD, wb_mem_rdval, wb_alu_res) } .elsewhen (ex_csr_wbcsr =/= CSR.X) { ex_alu_op1 := u_csrfile.io.rw.rdata.asSInt } .otherwise { ex_alu_op1 := ex_rdata_op1 } ...
次に、ロードユースのフォワーディングだ。残念ながら、ロードした命令を次サイクルで次の命令が利用することはできない。メモリにアクセスするので、このフォワードは無効なのだ。 そこで、メモリアクセスが入ると、自動的に1サイクルストールさせるようにする。
minicpu/src/main/scala/cpu/cpu.scala
val dec_stall_en = dec_inst_valid & (u_cpath.io.ctl.mem_cmd =/= MCMD_X)
49 : [00000108] | 1,X[ 1]=>0000000000002000,X[00]=>0000000000000000| | |X01<=0x0000000000002000|x01<=0x00000000000020fc : 0x000000fc : INST(0x00002097) : auipc ra, 0x2 50 : [0000010c] 00ff0eb7 | | | [00002000]=>0x0000000000000000|X30<=0x0000000000002000|x01<=0x0000000000002000 : 0x00000100 : INST(0xf0408093) : addi ra, ra, -252 51 : [00000110] 0ffe8e9b |15,X[ 0]=>0000000000ff0000,X[15]=>0000000000000000| | | |x30<=0x0000000000ff00ff : 0x00000104 : INST(0x0000af03) : lw t5, 0(ra) 52 : [00000114] 00200193 |16,X[29]=>0000000000ff0000,X[00]=>00000000000000ff| | |X29<=0x0000000000ff0000| 53 : [00000118] 27df1a63 | 1,X[ 0]=>0000000000000000,X[00]=>0000000000000002| | |X29<=0x0000000000ff00ff|x29<=0x0000000000ff0000 : 0x00000108 : INST(0x00ff0eb7) : lui t4, 0xff0 54 : [0000011c] 00002097 |11,X[30]=>0000000000ff00ff,X[29]=>0000000000ff00ff| | |X03<=0x0000000000000002|x29<=0x0000000000ff00ff : 0x0000010c : INST(0x0ffe8e9b) : addiw t4, t4, 255
これらのフォワーディングパスを追加することにより、無事にrv64ui_p_***
のパタンがすべてPassするようになった。
Chiselを使った場合、Verilogを使った場合でどちらとも無事にPassしたので、たぶん大丈夫。