FPGA開発日記

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

Yosysの使い方を勉強する (8. YosysのProcessについて)

まずはYosysに簡単なPassを作ってみる。接続関係を示すために、Yosysの内部構造RTLILのProcessについて勉強しよう。

struct RTLIL::Process : public RTLIL::AttrObject
{
        unsigned int hashidx_;
        unsigned int hash() const { return hashidx_; }

protected:
        // use module->addProcess() and module->remove() to create or destroy processes
        friend struct RTLIL::Module;
        Process();
        ~Process();

public:
        RTLIL::IdString name;
        RTLIL::Module *module;
        RTLIL::CaseRule root_case;
        std::vector<RTLIL::SyncRule*> syncs;

        template<typename T> void rewrite_sigspecs(T &functor);
        template<typename T> void rewrite_sigspecs2(T &functor);
        RTLIL::Process *clone() const;
};

Processクラスは大きく分けてroot_caseSyncRuleの2つに分けられており、SyncRuleはベクトル形式になっている。

CaseRuleの方は複数のassign文が格納されており、主に組み合わせ回路の記述に使われるものと思われる。

struct RTLIL::CaseRule : public RTLIL::AttrObject
{
        std::vector<RTLIL::SigSpec> compare;
        std::vector<RTLIL::SigSig> actions;
        std::vector<RTLIL::SwitchRule*> switches;

        ~CaseRule();

        bool empty() const;

        template<typename T> void rewrite_sigspecs(T &functor);
        template<typename T> void rewrite_sigspecs2(T &functor);
        RTLIL::CaseRule *clone() const;
};

SyncRuleは一方で順序回路の記述に使われる。

struct RTLIL::SyncRule
{
        RTLIL::SyncType type;
        RTLIL::SigSpec signal;
        std::vector<RTLIL::SigSig> actions;
        std::vector<RTLIL::MemWriteAction> mem_write_actions;

        template<typename T> void rewrite_sigspecs(T &functor);
        template<typename T> void rewrite_sigspecs2(T &functor);
        RTLIL::SyncRule *clone() const;
};

例えば以下のSystemVerilogコードをコンパイルしてRTLILに変換してみる。

module adder3
(
 input logic          clk,
 input logic          reset,
 input logic [31:0]   in0,
 input logic [31:0]   in1,
 input logic [31:0]   in2,
 output logic [63:32] out
);

logic [31: 0]         temp;

always_ff @ (posedge clk, posedge reset) begin
  if (reset) begin
    temp <= 'h0;
  end else begin
    temp <= in0 * in1;
  end
end

assign out = temp + in2;

endmodule // adder3

変換後は以下のようになる。

  process $proc$adder.sv:40$1
    assign $0\temp[31:0] \temp
    switch \reset
      case 1'1
        assign $0\temp[31:0] 0
      case
        assign $0\temp[31:0] $mul$adder.sv:44$2_Y
    end
    sync posedge \clk
      update \temp $0\temp[31:0]
    sync posedge \reset
      update \temp $0\temp[31:0]
  end
  • assign $0\temp[31:0] \temp : まあtemp0 = tempみたいなassign文だと思えばよかろう。
  • switch \reset : reset信号に基づいて$0\temp[31:0] \temp に格納する値を決める。resetならばゼロを、そうでなければ$mul$adder.sv:44$2_Yを格納する。
  • sync posedge \clk : clkに基づいて\temp$0\temp[31:0]を格納する。これが順序回路の代入になる。
  • sync posedge \reset : resetに基づいて\temp$0\temp[31:0]を格納する。これが順序回路の非同期リセットになる。

そして、加算と乗算は別のコンポーネントとして作られている。

  cell $add $add$adder.sv:48$3
    parameter \A_SIGNED 0
    parameter \A_WIDTH 32
    parameter \B_SIGNED 0
    parameter \B_WIDTH 32
    parameter \Y_WIDTH 32
    connect \A \temp
    connect \B \in2
    connect \Y $add$adder.sv:48$3_Y
  end
  attribute \src "adder.sv:44.13-44.22"
  cell $mul $mul$adder.sv:44$2
    parameter \A_SIGNED 0
    parameter \A_WIDTH 32
    parameter \B_SIGNED 0
    parameter \B_WIDTH 32
    parameter \Y_WIDTH 32
    connect \A \in0
    connect \B \in1
    connect \Y $mul$adder.sv:44$2_Y
  end