FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

Chiselを使ってCPUを作ろう(16. 5ステージにCPUに拡張してみる)

f:id:msyksphinz:20181216141548p:plain

Chiselを使って、非常にシンプルなCPUを作ってみるプロジェクト。折角なので5ステージまで拡張して、テストパタンが通るようにしたい。

参考にしたのはヘネパタの後ろの方に乗っている5ステージのプロセッサの解説。とりあえず図に乗っていることをすべてChiselで書き下してみることにした。 そしてテストパタンを動かし、間違っているところを直していく。

github.com

今のところChiselの書き方としては非常にイマイチだ。ただしVerilogに直さずにChiselのままシミュレーションをしているので、リグレッションなども非常に高速で助かる。

波形を見ずに開発をしているので、以下のようなパイプライントレースを出力できるようにしてデバッグを行えるようにした。波形を見ない、完全にログだけを見てデバッグできるか、試している。

  cycle    :         IF           |               EX_STAGE_REG_READ                  |                   MEM_STAGE_MEM_ACCESS                |        WB_STAGE       |
         0 :                      |                                                  |                                                       |                       |
         1 : [00000000]           |                                                  |                                                       |                       |
         2 : [00000004]  04c0006f |                                                  |                                                       |                       |
         3 :             34202f73 |                                                  |                                                       |                       |
         4 : [0000004c]           |                                                  |                                                       |X00<=0x0000000000000000|
         5 : [00000050]  -ebfda8d |                                                  |x00<=0x0000000000000004                                |                       | : 0x00000000 : INST(0x04c0006f) : j       pc + 0x4c
         6 : [00000054]  00051063 |21,X[ 0]=>0000000000000000,X[20]=>0000000000000000|                                                       |                       |
         7 : [00000058]  00000297 |11,X[10]=>0000000000000000,X[00]=>0000000000000000|                                                       |X10<=0x0000000000000000|
         8 : [0000005c]  01028293 | 1,X[ 0]=>0000000000000000,X[00]=>0000000000000054|x10<=0x0000000000000000                                |                       | : 0x0000004c : INST(0xf1402573) : csrr    a0, mhartid
         9 : [00000060]  30529073 | 1,X[ 5]=>0000000000000054,X[00]=>0000000000000010|                                                       |X05<=0x0000000000000054| : 0x00000050 : INST(0x00051063) : bnez    a0, pc + 0
        10 : [00000064]  18005073 |21,X[ 5]=>0000000000000064,X[05]=>0000000000000064|x05<=0x0000000000000054                                |X05<=0x0000000000000064| : 0x00000054 : INST(0x00000297) : auipc   t0, 0x0
        11 : [00000068]  00000297 |21,X[ 0]=>0000000000000000,X[00]=>0000000000000064|x05<=0x0000000000000064                                |X00<=0x0000000000000064| : 0x00000058 : INST(0x01028293) : addi    t0, t0, 16
        12 : [0000006c]  01c28293 | 1,X[ 0]=>0000000000000000,X[00]=>0000000000000064|x00<=0x0000000000000064                                |X00<=0x0000000000000064| : 0x0000005c : INST(0x30529073) : csrw    mtvec, t0
        13 : [00000070]  30529073 | 1,X[ 5]=>0000000000000064,X[00]=>000000000000001c|x00<=0x0000000000000064                                |X05<=0x0000000000000064| : 0x00000060 : INST(0x18005073) : csrwi   satp, 0
        14 : [00000074]  -00ffd6d |21,X[ 5]=>0000000000000080,X[05]=>0000000000000080|x05<=0x0000000000000064                                |X05<=0x0000000000000080| : 0x00000064 : INST(0x00000297) : auipc   t0, 0x0
        15 : [00000078]  3b029073 | 1,X[ 0]=>0000000000000080,X[00]=>ffffffffffffffff|x05<=0x0000000000000080                                |X00<=0x0000000000000080| : 0x00000068 : INST(0x01c28293) : addi    t0, t0, 28
        16 : [0000007c]  01f00293 |21,X[ 5]=>000000000000007f,X[16]=>0000000000000000|x00<=0x0000000000000080                                |X05<=0x000000000000007f| : 0x0000006c : INST(0x30529073) : csrw    mtvec, t0
        17 : [00000080]  3a029073 | 1,X[ 0]=>0000000000000000,X[00]=>000000000000001f|x05<=0x000000000000007f                                |X00<=0x0000000000000000| : 0x00000070 : INST(0xfff00293) : li      t0, -1
        18 : [00000084]  00000297 |21,X[ 5]=>000000000000001f,X[00]=>0000000000000000|x00<=0x0000000000000000                                |X05<=0x000000000000001f| : 0x00000074 : INST(0x3b029073) : csrw    pmpaddr0, t0
        19 : [00000088]  01828293 | 1,X[ 0]=>0000000000000000,X[00]=>0000000000000080|x05<=0x000000000000001f                                |X00<=0x0000000000000000| : 0x00000078 : INST(0x01f00293) : li      t0, 31
        20 : [0000008c]  30529073 | 1,X[ 5]=>0000000000000080,X[00]=>0000000000000018|x00<=0x0000000000000000                                |X05<=0x0000000000000080| : 0x0000007c : INST(0x3a029073) : csrw    pmpcfg0, t0

まだ分岐命令の処理で足りていない部分や、パイプラインが正しく切れていない場所があるが、少しずつ動き始めた。

フォワーディングの部分なども、一応実装している。Verilogと書き方はほとんど一緒だ。

  • 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 := wb_alu_res
      } .otherwise {
        ex_alu_op0 := ex_reg_op0
      }
    }
...