チラシの裏は意外と白くない

最近忘れっぽくなったので調べたことをチラシの裏に書きます

RGB2YUV回路(TLM)

「SystemCを使ったハードウェア設計」という本を入手できたので、第2章に従ってTLM→BCAの流れを確認する。

TLM(Transaction Level Modeling)

データの流れのみを定義したレベル。バス構造やインタフェース機能はモデリングしない。特に重要な点がFIFOの表現でsc_fifoというインタフェースを一般的に使用する。モデルは入力側FIFOが空の時にはデータが入ってくるまで待ち続け、出力側FIFOがフルの場合は空きが出るまで待つ。ready, validのようなハンドシェイク信号までは表現しない。

BCA(Bus Cycle Accurate)

入出力インタフェース(バスインタフェース)はRTLと同じくピン精度/サイクル精度でモデリングする。回路本体はuntimedあるいはloosely-timedで表現する。高位合成可能なモデリングは基本的にこのレベル。

とりあえず教科書通りに書いてみた

C++のテクニック的なところが慣れないが、まあSystemCになれるという意味では本質的ではない…ということにしておく。前回作った4bitカウンタとの違いは、RGBデータをテストベンチのメモリから読みだして、変換したYUVデータをテストベンチのメモリに書き出す点。RTLだとメモリとのIF信号を定義する必要があるがTLMではsc_fifoと書くだけ。コア側(rgb2yuv.h)の記述は以下。

SC_MODULE(rgb2yuv) {
    // ports
    sc_in<bool> clock;
    sc_fifo_in<rgb8_t> offset_in;
    sc_fifo_in<rgb8_t> rgb_in;
    sc_fifo_out<yuv8_t> yuv_out;

    (省略)
};

テストベンチ側(tb.h)のポート宣言はこれの対になる形で記述し、テストベンチ→コアへデータを流すsource()関数、コア→テストベンチへデータを引き取るsink()関数の宣言とプロセス宣言も行う。プロセスはSC_THREADでclockの立ち上がりエッジで駆動される。

SC_MODULE(tb) {
    // ports
    sc_in<bool> clock
    sc_fifo_out<rgb8_t> offset_out;
    sc_fifo_out<rgb8_t> rgb_out;
    sc_fifo_in<yuv8_t> yuv_in;

   (省略)

    // functions
    void source(); // tb -> core
    void sink();     // core -> tb

    (省略)

    // processes
    SC_THREAD(source);
    sensitive_pos << clock; // sensitive << clock.pos();でもOK
    SC_THREAD(sink);
    sensitive_pos << clock; // sensitive << clock.pos();でもOK

    (省略)
};

テストベンチ本体(tb.cpp)でsource(), sink()の中身を記述している。

void tb::source()
{
    int data_r, data_g, data_b;
    rgb8_t rgb;


    // ファイルからint型で数値を3つで取ってきて一時変数data_r/g/bに格納する
    fscanf(fi, "%d", &data_r);
    fscanf(fi, "%d", &data_g);
    fscanf(fi, "%d", &data_b);

    // rgb構造体へ代入
    rgb.write(data_r, data_g, data_b);

    // 最初の3データはオフセットとしてrgb構造体をコアへ出力
    offset_out.write(rgb);
    wait(); // オフセット値の出力までを初回のクロックで行う

    // 4データ目以降はRGBデータとして出力
    for(int i=0; i<NUM; i++) {
        fscanf(fi, "%d", &data_r);
        fscanf(fi, "%d", &data_g);
        fscanf(fi, "%d", &data_b);

        rgb.write(data_r, data_g, data_b);

        rgb_out.write(rgb);
        wait(); // RGBを出したら次のクロックまで待つ
    }
}

void tb::sink()
{
    yuv8_t yuv;
    fprintf(fo, " y u v\n"); // 出力ファイルの1行目に凡例を出力する

    for(int i=0; i<NUM; i++) {
        // コアからの出力データをyuv構造体へ代入
        yuv = yuv_in.read();
        // 出力データをファイルへ書き出す
        fprintf(fo, "%3d %3d %3d\n");
        wait(); // 1行書いたら次のクロックを待つ
    }
    sc_stop(); // NUM行書いたらシミュレーションを終了させる
}

という感じ。確か教科書通りだといくつか誤記があってコンパイルが通らなかったが、少し苦戦したのがclass.hの波形表示部分の記述。

inline void sc_trace(sc_trace_file *tf, const rgb8_t& o, const sc_string& n) {
    sc_trace(tf, o.r, n + "_r");
    sc_trace(tf, o.g, n + "_g");
    sc_trace(tf, o.b, n + "_b");
}

このままだと以下のエラーでコンパイルが通らない。

$ make
g++ -Wall -std=c++11  -I. -I/usr/local/systemc/2.3.3/include -c tb.cpp
In file included from ./tb.h:5:0,
                 from tb.cpp:1:
./class.h:55:64: エラー: ‘sc_string’ does not name a type
 inline void sc_trace(sc_trace_file *tf, const rgb8_t& o, const sc_string& n) {
                                                                ^
./class.h:55:75: エラー: ISO C++ では型の無い ‘n’ の宣言を禁止しています [-fpermissive]
 inline void sc_trace(sc_trace_file *tf, const rgb8_t& o, const sc_string& n) {
                                                                           ^
./class.h:111:64: エラー: ‘sc_string’ does not name a type
 inline void sc_trace(sc_trace_file *tf, const yuv8_t& o, const sc_string& n){
                                                                ^
./class.h:111:75: エラー: ISO C++ では型の無い ‘n’ の宣言を禁止しています [-fpermissive]
 inline void sc_trace(sc_trace_file *tf, const yuv8_t& o, const sc_string& n){
                                                                           ^
make: *** [tb.o] エラー 1

sc_stringという型がSystemC2.3.2で廃止されたらしい。ひとまずMakefileのCXXFLAGSにSC_USE_STD_STRINGを追加して、

CXXFLAGS = -Wall -std=c++11 -DSC_USE_STD_STRING

としてコンパイルを通した。

実行結果は以下で、一応変換ができているようだ。なお、教科書通りにSC_THREADのところでsensitive_pos << clock;とするとwarningが出たので、sensitive << clock.pos()に変更した(結果は変わらない)。

$ ./run.x 

        SystemC 2.3.3-Accellera --- Mar  8 2020 14:00:56
        Copyright (c) 1996-2018 by all Contributors,
        ALL RIGHTS RESERVED
rgb = (1 2 3), yuv = (2 128 127)
rgb = (2 3 4), yuv = (3 128 127)
rgb = (3 4 5), yuv = (4 128 127)
rgb = (4 5 6), yuv = (5 128 127)
rgb = (5 6 7), yuv = (6 128 127)
rgb = (6 7 8), yuv = (7 128 127)
rgb = (7 8 9), yuv = (8 128 127)
rgb = (8 9 10), yuv = (9 128 127)
rgb = (9 10 11), yuv = (10 128 127)
rgb = (10 11 12), yuv = (11 128 127)
rgb = (11 12 13), yuv = (12 128 127)
rgb = (12 13 14), yuv = (13 128 127)
rgb = (255 255 255), yuv = (255 128 128)
rgb = (255 2 3), yuv = (78 85 254)
rgb = (1 255 3), yuv = (2 128 127)
rgb = (1 2 255), yuv = (179 170 1)
rgb = (255 255 3), yuv = (78 85 254)
rgb = (255 2 255), yuv = (255 128 128)
rgb = (1 255 255), yuv = (179 170 1)
rgb = (255 255 255), yuv = (255 128 128)

Info: /OSCI/SystemC: Simulation stopped by user.

続いて抽象度を落としてBCAの記述を確認する。そういえばVCDダンプされてないな。。