FPGA開発日記

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

Circuit IRコンパイラのCIRCTを試す

f:id:msyksphinz:20200730230239p:plain

"CIRCT"は"Circuit IR Compiler and Tools"の略称で、MLIRを用いた回路構成を生成するコンパイラツールである。

https://github.com/llvm/circt

ソースコードが構成されており、面白そうなのでダウンロードしてビルドしてみることにした。

まずはソースコードのダウンロードを行う。

$ cd ${HOME}/work/llvm/circt
$ git clone git@github.com:circt/circt.git
$ git submodule init
$ git submodule update

LLVM/MLIRモジュールのビルドを行う。

$ cd circt
$ mkdir llvm/build
$ cd llvm/build
$ cmake -G Ninja ../llvm -DLLVM_ENABLE_PROJECTS="mlir" -DLLVM_TARGETS_TO_BUILD="X86;RISCV" \
    -DLLVM_ENABLE_ASSERTIONS=ON -DCMAKE_BUILD_TYPE=DEBUG
$ ninja
$ ninja check-mlir

CIRCTのビルドを行う。

$ mkdir circt/build
$ cd circt/build
$ cmake -G Ninja .. -DMLIR_DIR=${HOME}/work/llvm/circt/llvm/build/lib/cmake/mlir/ \
    -DLLVM_DIR=${HOME}/work/llvm/circt/llvm/build/lib/cmake/llvm \
    -DLLVM_ENABLE_ASSERTIONS=ON -DCMAKE_BUILD_TYPE=DEBUG
$ ninja
$ ninja check-circt

すでに限定的ではあるが、FIRRTLをParseしてVerilogを生成することができる。試してみよう。

$ cd bin/test/EmitVerilog/Output
ls -1
verilog-basic.fir.script
verilog-errors.mlir.script
verilog-rtl-dialect.mlir.script
verilog-weird.mlir.script

いくつかのFIRファイルが配置している。verilog-basic.fir.scriptがFIRをコンパイルするためのスクリプトになっている。

set -o pipefail;{ : 'RUN: at line 1';   /home/msyksphinz/work/llvm/circt/build/bin/circt-translate -parse-fir --mlir-print-debuginfo /home/msyksphinz/work/llvm/circt/test/EmitVerilog/verilog-basic.fir | /home/msyksphinz/work/llvm/circt/build/bin/circt-translate -emit-verilog -verify-diagnostics | /home/msyksphinz/work/llvm/circt/llvm/build/bin/FileCheck /home/msyksphinz/work/llvm/circt/test/EmitVerilog/verilog-basic.fir --strict-whitespace; }

これに基づいて、自分でもCIRCTを動かしてみよう。

$ ${BUILD}/bin/circt-translate -parse-fir --mlir-print-debuginfo \
    ${CIRCT}/test/EmitVerilog/verilog-basic.fir | \
    ${BUILD}/bin/circt-translate -emit-verilog -verify-diagnostics

おお、Verilogファイルが生成できた。しかも超絶速い。FIRRTLなど話にならないほど高速だ。

...
  always @(posedge _M_write_clk) begin
    if (_M_write_en & _M_write_mask) begin
      _M_id[_M_write_addr] <= _M_write_data_id; // Decoupled.scala:209:24
      _M_other[_M_write_addr] <= _M_write_data_other;   // Decoupled.scala:209:24
    end
  end // always @(posedge)
endmodule

module Attach(
  input a, b, c);


  `ifndef SYNTHESIS
    alias a = b = c;    // Place.scala:101
  `endif
  `ifdef SYNTHESIS
    assign a = b;       // Place.scala:101
    assign a = c;       // Place.scala:101
    assign b = a;       // Place.scala:101
    assign b = c;       // Place.scala:101
    assign c = a;       // Place.scala:101
    assign c = b;       // Place.scala:101
  `endif // SYNTHESIS
endmodule

module IsInvalid(
  output a);

endmodule

module Locations(
  input  [3:0] a,
  output [3:0] b);
...