0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[高位合成] C言語で組み合わせ回路と順序回路はどうやって作るのか?

Last updated at Posted at 2025-04-29

はじめに

初歩の説明ということでまずはこのテーマで。

前提

以下の経験がある前提で話を進めます。

  • FPGAを触ったことがある。
    具体的なレベル感としては組み合わせ回路や順序回路とかがわかれば大丈夫です。
  • C/C++を少し触ったことがある。
    書いてあることがなんとなくわかるレベルであれば大丈夫です。

動作環境

PC:M4 Macbook Pro(Sequoia 15.1)
IDE:VitisHLS 2023.1

※皆さんはWindows PCでやってくださいね

Vitis Unified IDEという最新のIDEがありますが、今回はそれを使用しません。
割と最近でてきたIDEなのでバグがあるのかなと思ってまだほとんど使用したことないです。
2024Verなら大分安定しているのかな?

ソースコード

全体のソースコードは以下です。

Vitis HLSの使い方

最低限の説明だけします。

プロジェクト生成方法

  1. Vitis HLSを起動する。コマンドvitis_hlsを入力。
  2. 「Create Project」を押下する。
    SCR-20250426-nlke-2.png
  3. 「Project name」と「Location」を入力する。
    SCR-20250426-nmrp.png
  4. 「New Vitis HLS Project」画面は「Next」を押下する。(2回出てくるので両方とも)
  5. 「...」で対象のデバイスを選択できるため設定する。他は必要に応じて設定する。
    SCR-20250426-nnqo.png

ソースコードの登録方法

  1. ソースコード(テストベンチも)の用意をする。
  2. 「Source」を右クリックし、「Add Source File...」を押下し、ソースコードを登録する。
    SCR-20250426-npdk.png
  3. 「Test Bench」を右クリックし、「Add Source File...」を押下し、ソースコードを登録する。
    SCR-20250426-nqvc.png
  4. プロジェクトを選択して、右クリックを押下し、「Project Settings...」を押下する。
    SCR-20250426-oldb.png
  5. 「Synthesis」を選択し、Top Function欄にTop階層となる関数を設定する。
    SCR-20250426-omiu-2.png

合成/シミュレーションのやり方

やり方を説明する前に工程の説明をする。

工程 説明
C Simulation C言語レベルでのシミュレーションを行う
C Synthesis 合成を行う(この時点でRTLが生成される)
CoSimulation FPGAレベルでのシミュレーションを行う
  1. 「緑の再生」的なボタンの右の下三角形を押下する。
    SCR-20250426-nrik.png
  2. 「C Simulation」を押下する。下の画面が表示されるので、「OK」を押下する。
    「Options」は任意でチェックする。
    デバッグをしたい場合は「Launch Debugger」をチェックする。
    「Clean Build」は差分ビルドをせずに、全ビルドを行う。
    SCR-20250426-nykw.png
  3. 「C Synthesis」を押下する。下の画面が表示されるので、「OK」を押下する。
    SCR-20250426-nzou.png
  4. 「CoSimulation」を押下する。下の画面が表示されるので、「OK」を押下する。
    「Vivado XSIM」と書いてあるのは、Vivadoを使ってシミュレーションするという意味です。
    横の三角形を押下すると他のシミュレーションが出てきます。
    「Dump Trace」に「all」を入れることにより、シミュレーション結果をダンプできます。
    SCR-20250426-oacf.png

以上。では次から本題に。

組み合わせ回路

以下の組み合わせ回路を例とします。

image.png

ソースコード

void CombinationalCircuit(bool a, bool b, bool c, bool *d)
{
#pragma HLS INTERFACE ap_none port = a
#pragma HLS INTERFACE ap_none port = b
#pragma HLS INTERFACE ap_none port = c
#pragma HLS INTERFACE ap_none port = d
#pragma HLS INTERFACE ap_ctrl_none port = return

    *d = a && b && c;
}

解説

  • 入出力について
    関数の引数が入出力になります。型についてはC言語の型をそのまま記載できます。
    C/C++の値渡しをしたら入力になり、参照渡し(ポインタ)にしたら出力となります。
    そしてTOP階層の関数には #pramga の定義を記載します。
    HLS INTERFACEプラグマはIFのプロトコルなどを設定するものになります。
    今回のap_none/ap_ctrl_noneはプロトコルなしの純粋なIFという意味になります。
  • 処理について
    基本的にはC/C++と同じです。
    今回の場合だとAND回路を作りたいので、&&演算子を記載するだけです。

合成結果

SCR-20250419-nryn.png

組み合わせ回路のみなので、FFが使用されず、LUTのみ使用されています。

SCR-20250419-nsxr.png

入出力も意図した通りになっています。

シミュレーション

シミュレーションのソースコードは制限なしでフルのC/C++機能を使用できます。

void GoldenModel(bool a, bool b, bool c, bool *d)
{
    *d = a && b && c;
}

int main()
{
    std::vector<bool> a_values = {true, false};
    std::vector<bool> b_values = {true, false};
    std::vector<bool> c_values = {true, false};
    bool d, d_golden;

    for (bool a : a_values)
    {
        for (bool b : b_values)
        {
            for (bool c : c_values)
            {
                CombinationalCircuit(a, b, c, &d);
                GoldenModel(a, b, c, &d_golden);

                if (d == d_golden)
                {
                    std::cout << "Test passed!" << std::endl;
                }
                else
                {
                    std::cout << "Test failed!" << std::endl;
                }
            }
        }
    }

    return 0;
}

SCR-20250419-oahk.png

期待通りに最初だけTrueが出力され、その後はFalseが出力されていますね。

順序回路

以下の順序回路を例とします。

image.png

ソースコード

#include "sequential_circuit.h"

void SequentialCircuit(bool a, bool *c1, bool *c2)
{
#pragma HLS INTERFACE ap_none port = a
#pragma HLS INTERFACE ap_none port = c1
#pragma HLS INTERFACE ap_none port = c2
#pragma HLS INTERFACE ap_ctrl_none port = return

    static bool ff1 = false;
    static bool ff2 = false;

    ff2 = ff1;
    ff1 = a;

    *c1 = ff1;
    *c2 = ff2;
}

解説

  • 入出力について
    順序回路なので、クロック&リセット信号がいるのでは?と思いますが、これは意識しなくても大丈夫です。
    ツール側が上手いことやってくれます。
  • 処理について
    まず、static宣言ですがこれを付与することによりその変数がFFとして定義されます。RTLで言えばregになります。
    付与しなくてもFFになることはありますが、それはツール任せという結果になります。
    また、staticの初期化ですがこの書き方をするとPORになります。

合成結果

SCR-20250426-pdzw.png

FFが使用されていますね。

SCR-20250426-pepi.png

入出力も意図した通りになっています。

シミュレーション

#include <iostream>
#include <vector>
#include "../src/sequential_circuit.h"

void GoldenModel(bool a, bool *c1, bool *c2)
{
    static bool ff1 = false;
    static bool ff2 = false;

    ff2 = ff1;
    ff1 = a;

    *c1 = ff1;
    *c2 = ff2;
}

int main()
{
    std::vector<bool> a_values = {true, false};

    // テストベンチ
    for (bool a : a_values)
    {
        bool c1, c2;
        SequentialCircuit(a, &c1, &c2);

        bool golden_c1, golden_c2;
        GoldenModel(a, &golden_c1, &golden_c2);

        std::cout << "Input: " << a << ", Output: (" << c1 << ", " << c2 << "), Golden: (" << golden_c1 << ", " << golden_c2 << ")" << std::endl;

        if (c1 != golden_c1 || c2 != golden_c2)
        {
            std::cout << "Mismatch!" << std::endl;
            return 1;
        }
    }
    std::cout << "All tests passed!" << std::endl;

    return 0;
}

SCR-20250426-phys.png

これも問題ないですね。

おまけ

先ほどの順序回路でff2から代入していましたよね。
なぜこの順番なのか、ff1 = aじゃダメなんですか?と思いますが、結論言うとダメです。

↓これじゃダメ?

ff1 = a;
ff2 = ff1;

では試しにこれで作ってみましょう。

SCR-20250426-pmfj.png

合成結果は上記です。あれ?FFがなくなっている…
どうなってるんだ、という感じですよね。
とりあえず次にシミュレーションしてみましょうか。

SCR-20250426-poek.png

あれれ?これ組み合わせ回路になってない??と思いましたよね。
そうなんです、これは組み合わせ回路ができあがります。

なぜあの書き方をすると組み合わせ回路になってしまうのかですが、理由は簡単です。
ツール側で最適化が働いているからです。

ff1 = a;
ff2 = ff1;

これだとff2に関しては、ff2 = aとも読み取れますよね。
だからツール側が、「ff1いらなくね?てかff2もいらなくね?じゃあ入力をそのまま出力でよくね?」となる。
そして組み合わせ回路ができあがります。

では実際に生成されたverilogを見てみましょう。

↓生成されたverilog
SCR-20250426-prtq.png

やっぱり入力がそのまま出力として出ていますね。ということです。

おわり

これにてお終い。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?