FPGA開発日記

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

Chisel-Templateを使ってオリジナルデザインを作ってみるチュートリアル (4. ALUの実装)

随分とほったらかしにしていたが、Chiselを使ってオリジナルデザイン開発を再開した。

簡単なRISC-VコアをフルスクラッチでChiselで作ってみて、Chiselの理解を深めようと思う。

msyksphinz.hatenablog.com

各種命令の実装

まずはシンプルな算術演算命令の実装を行う。ALUの実装はまずはこの程度だ。

class Alu extends Module {
  val io = IO (new Bundle {
    val func = Input (UInt(4.W))
    val op0  = Input (SInt(64.W))
    val op1  = Input (SInt(64.W))

    val res  = Output (SInt(64.W))
  })

  val w_res = Wire(SInt(64.W))
  when (io.func === ALU_ADD) {
    w_res := io.op0 + io.op1
  } .elsewhen (io.func === ALU_SUB) {
    w_res := io.op0 - io.op1
  } .elsewhen (io.func === ALU_SLL) {
    w_res := (io.op0.asUInt << io.op1(5,0).asUInt).asSInt
  } .elsewhen (io.func === ALU_SRL) {
    w_res := (io.op0.asUInt >> io.op1(5,0).asUInt).asSInt
  } .elsewhen (io.func === ALU_SRA) {
    w_res := (io.op0 >> io.op1(5,0).asUInt).asSInt
  } .elsewhen (io.func === ALU_AND) {
    w_res := io.op0 & io.op1
  } .elsewhen (io.func === ALU_OR) {
    w_res := io.op0 | io.op1
  } .elsewhen (io.func === ALU_XOR) {
    w_res := io.op0 ^ io.op1
  } .elsewhen (io.func === ALU_SLT) {
    w_res := Mux(io.op0 < io.op1, 1.S, 0.S)
  } .elsewhen (io.func === ALU_SLTU) {
    w_res := Mux(io.op0.asUInt < io.op1.asUInt, 1.S, 0.S)
  } .elsewhen (io.func === ALU_COPY1) {
    w_res := io.op0
  } .otherwise {
    w_res := io.op0
  }

  val r_res = Reg(SInt(64.W))
  r_res := w_res
  io.res := w_res
}

2018/11/20追記。よく見てみたらChiselではcase文が使えるんだった。書き直した。

  val w_res = Wire(SInt(64.W))
  w_res := 0.S
  switch (io.func) {
    is (ALU_ADD  ) { w_res := io.op0 + io.op1                              }
    is (ALU_SUB  ) { w_res := io.op0 - io.op1                              }
    is (ALU_SLL  ) { w_res := (io.op0.asUInt << io.op1(5,0).asUInt).asSInt }
    is (ALU_SRL  ) { w_res := (io.op0.asUInt >> io.op1(5,0).asUInt).asSInt }
    is (ALU_SRA  ) { w_res := (io.op0 >> io.op1(5,0).asUInt).asSInt        }
    is (ALU_AND  ) { w_res := io.op0 & io.op1                              }
    is (ALU_OR   ) { w_res := io.op0 | io.op1                              }
    is (ALU_XOR  ) { w_res := io.op0 ^ io.op1                              }
    is (ALU_SLT  ) { w_res := Mux(io.op0 > io.op1, 1.S, 0.S)               }
    is (ALU_SLTU ) { w_res := Mux(io.op0.asUInt > io.op1.asUInt, 1.S, 0.S) }
    is (ALU_SNE  ) { w_res := Mux(io.op0 =/= io.op1, 1.S, 0.S)             }
    is (ALU_SEQ  ) { w_res := Mux(io.op0 === io.op1, 1.S, 0.S)             }
    is (ALU_SGE  ) { w_res := Mux(io.op0        > io.op1, 1.S, 0.S)        }
    is (ALU_SGEU ) { w_res := Mux(io.op0.asUInt > io.op1.asUInt, 1.S, 0.S) }
    is (ALU_COPY1) { w_res := io.op0                                       }
  }

テストパタンの作成

テストパタンは、以下のようなパタンを作ってISSと比較した。

    addi    x1, x10, 0x610
    andi    x2, x11, 0x580
    ori     x3, x12, 0x0cb
    xori    x4, x13, 0x553
    slti    x5, x14, 0x292
    sltiu   x6, x15, 0x7f5
    slli    x7, x16, 0x6
    srai    x8, x17, 0x7
    srli    x9, x18, 0x2

    sll     x1, x10, x20
    add     x2, x11, x21
    sub     x3, x12, x22
    slt     x4, x13, x23
    sltu    x5, x14, x24
    and     x6, x15, x25
    or      x7, x16, x26
    xor     x8, x17, x27
    sra     x9, x18, x28
    srl     x10, x19, x29

    addiw   x1, x10, 0x170
    slliw   x2, x11, 0xb
    srliw   x3, x12, 0xc
    sraiw   x4, x13, 0x8
    addw    x5, x14, x24
    subw    x6, x15, x25
    sllw    x7, x16, x26
    srlw    x8, x17, x27
    sraw    x9, x18, x28
f:id:msyksphinz:20181118180612p:plain