FPGA開発日記

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

CIRCTの仕組みとMLIRを読み解く (MLIRを使ってCIRCTに新しいユニットを作成してみる)

MLIRの勉強のために、CIRCTにSystemVerilogの新しいツールを追加してみよう。やり方が分からないので試行錯誤でやってみる。FIRRTLのディレクトリを参考にしながら以下のようにファイルを追加してみる。

     Dialect/SV/Import
            CMakeLists.txt
            SVAnnotations.cpp
            SVLexer.cpp
            SVLexer.h
            SVParser.cpp
            SVTokenKinds.def
        circt/Dialect/SV/SVAnnotations.h
        circt/Dialect/SV/SVParser.h
        tools/CMakeLists.txt
        sv-translate/
            CMakeLists.txt
            sv-translate.cpp

基本的にすべてFIRRTLの実装からコピーしてきている。sv-translateというツールを使ってみることにする。

diff --git a/lib/Dialect/SV/CMakeLists.txt b/lib/Dialect/SV/CMakeLists.txt
index c9d7fe6d..d213a1f8 100644
--- a/lib/Dialect/SV/CMakeLists.txt
+++ b/lib/Dialect/SV/CMakeLists.txt
@@ -20,4 +20,5 @@ add_circt_dialect_library(CIRCTSV
 add_dependencies(circt-headers MLIRSVIncGen)

 add_subdirectory(Analyses)
+add_subdirectory(Import)
 add_subdirectory(Transforms)

この状態でCIRCTのビルドを行ってみるとどうなるか。以下のようなエラーが表示された。

../lib/Dialect/SV/Import/SVParser.cpp:249:25: error: 'SVType' has not been declared
   ParseResult parseType(SVType &result, const Twine &message);
                         ^~~~~~
../lib/Dialect/SV/Import/SVParser.cpp:251:32: error: 'RUWAttr' has not been declared
   ParseResult parseOptionalRUW(RUWAttr &result);
                                ^~~~~~~
../lib/Dialect/SV/Import/SVParser.cpp:679:33: error: 'mlir::ParseResult {anonymous}::SVParser::parseType' is not a static data member of 'struct {anonymous}::SVParser'
 ParseResult SVParser::parseType(SVType &result, const Twine &message) {
                                 ^~~~~~
../lib/Dialect/SV/Import/SVParser.cpp:679:33: error: 'SVType' was not declared in this scope
../lib/Dialect/SV/Import/SVParser.cpp:679:33: note: suggested alternative: 'wctype'
 ParseResult SVParser::parseType(SVType &result, const Twine &message) {
                                 ^~~~~~
                                 wctype

適当にコンバートしたが、SVTypeという型を作成しなければならないらしい。これはもともとFIRRTLTypeだったので、これはどのように生成されているのか。

  • lib/Dialect/FIRRTL/Import/FIRParser.cpp
   ParseResult parseType(FIRRTLType &result, const Twine &message);

と思ったら普通にヘッダファイルで定義されていた。

  • include/circt/Dialect/FIRRTL/FIRRTLTypes.h
 // This is a common base class for all FIRRTL types.
 class FIRRTLType : public Type {
 public:
   void print(raw_ostream &os) const;

   /// Return true if this is a "passive" type - one that contains no "flip"
   /// types recursively within itself.
   bool isPassive() { return getRecursiveTypeProperties().first; }

   /// Return true if this is a 'ground' type, aka a non-aggregate type.
   bool isGround();

   /// Return true if this is or contains an Analog type.
   bool containsAnalog() { return getRecursiveTypeProperties().second; }

   /// Return a pair with the 'isPassive' and 'containsAnalog' bits.
   std::pair<bool, bool> getRecursiveTypeProperties();

   /// Return this type with any flip types recursively removed from itself.
   FIRRTLType getPassiveType();

   /// Return this type with all ground types replaced with UInt<1>.  This is
   /// used for `mem` operations.
   FIRRTLType getMaskType();

   /// Return this type with widths of all ground types removed. This
   /// enables two types to be compared by structure and name ignoring
   /// widths.
   FIRRTLType getWidthlessType();

   /// If this is an IntType, AnalogType, or sugar type for a single bit (Clock,
   /// Reset, etc) then return the bitwidth.  Return -1 if the is one of these
   /// types but without a specified bitwidth.  Return -2 if this isn't a simple
   /// type.
   int32_t getBitWidthOrSentinel();

   /// Support method to enable LLVM-style type casting.
   static bool classof(Type type) {
     return llvm::isa<FIRRTLDialect>(type.getDialect());
   }

   /// Return true if this is a valid "reset" type.
   bool isResetType();

 protected:
   using Type::Type;
 };

そこでSVTypeを以下のように定義した。

+// This is a common base class for all SV types.
+class SVType : public Type {
+public:
+  void print(raw_ostream &os) const;
+
+  /// Return true if this is a "passive" type - one that contains no "flip"
+  /// types recursively within itself.
+  bool isPassive() { return getRecursiveTypeProperties().first; }
+
+  /// Return true if this is a 'ground' type, aka a non-aggregate type.
+  bool isGround();
+
+  /// Return true if this is or contains an Analog type.
...

さらに、FIRRTLのRUWAttrは以下で定義されていた。

  • circt/Dialect/FIRRTL/FIRRTLTypes.td
/// RUWAttr: Undefined/Old/New.
def RUW_Undefined: I32EnumAttrCase<"Undefined", 0>;
def RUW_Old: I32EnumAttrCase<"Old", 1>;
def RUW_New: I32EnumAttrCase<"New", 2>;

def RUWAttr: I32EnumAttr<"RUWAttr", "Read Under Write Enum",
                         [RUW_Undefined, RUW_Old, RUW_New]>;

このI32EnumAttrとかI32EnumAttrCaseはこの辺かな?

https://mlir.llvm.org/docs/OpDefinitions/

これは列挙型なのか。

https://mlir.llvm.org/docs/OpDefinitions/#enum-attributes

f:id:msyksphinz:20210501000956p:plain
  1. A read-under-write flag indicating the behaviour when a memory location is written to while a read to that location is in progress.