SystemCでDE0-CVの回路を作る コーディング編

SystemCを使ってDE0-CVの回路を作りたいと思ったのでやってみた。 part3
前回はこちら
SystemCでDE0-CVの回路を作る 環境構築編 - m-keishiの日記

準備が整ったところで早速コーディングを始める。
下記は構想編で載せたブロック図。
AdderModule → Seg7Encoder → AdderTop → テストベンチ の順番でコーディングする。
f:id:m_keishi2006:20180503205333p:plain

AdderModule

AdderModule.h

#pragma once
#include <systemc.h>

SC_MODULE(AdderModule) {
    sc_in   <bool >             Clock_in;
    sc_in   <bool >             Reset_N_in;

    sc_in   <sc_uint<4> >       DA_in;
    sc_in   <sc_uint<4> >       DB_in;
    sc_out  <sc_uint<5> >       DC_out;

    SC_CTOR(AdderModule)
        : DA_in ("DA_in"    )
        , DB_in ("DB_in"    )
        , DC_out("DC_out"   )
    {
        SC_CTHREAD(Cthread_Adder, Clock_in.pos());
        reset_signal_is(Reset_N_in, false);
    }

private:
    void Cthread_Adder();

};

AdderModule.cpp

#include "AdderModule.h"

void AdderModule::Cthread_Adder() {
    DC_out.write(0);
    wait();
    while (true) {
        sc_uint<5> result = DA_in.read() + DB_in.read();
        DC_out.write(result);
        wait();
    }
}

Seg7Encoder

Seg7Encoder.h

#pragma once
#include <systemc.h>

SC_MODULE(Seg7Encoder) {
    sc_in   <bool >             Clock_in;
    sc_in   <bool >             Reset_N_in;

    sc_in   <sc_uint<4> >       d_in;
    sc_out  <sc_uint<7> >       d_out;

    SC_CTOR(Seg7Encoder)
        : d_in  ("d_in"     )
        , d_out ("d_out"    )
    {
        SC_CTHREAD(Cthread_Encoder, Clock_in.pos());
        reset_signal_is(Reset_N_in, false);
    }

private:
    void Cthread_Encoder();

    // エンコードパターン
    static const int kEncPattern[];

};

Seg7Encoder.cpp

#include "Seg7Encoder.h"

// エンコードパターン
const int Seg7Encoder::kEncPattern[] =
{
//     0,    1,    2,    3,    4,    5,    6,    7,
    0x40, 0x79, 0x24, 0x30, 0x19, 0x12, 0x02, 0x78,
//     8,    9,    A,    b,    C,    d,    E,    F,
    0x00, 0x10, 0x08, 0x03, 0x46, 0x21, 0x06, 0x0e
};

void Seg7Encoder::Cthread_Encoder() {
    d_out.write(0);
    wait();

    while (true) {
        int int_d_in = static_cast<int>(d_in.read());
        d_out.write(static_cast<sc_uint<7> >(kEncPattern[int_d_in]));
        wait();
    }
}

AdderTop

AdderTop.h

#pragma once
#include <systemc.h>

#include "AdderModule.h"
#include "Seg7Encoder.h"

SC_MODULE(AdderTop) {
    // クロックとリセット
    sc_in   <bool >             Clock_in;
    sc_in   <bool >             Reset_N_in;

    // 入出力端子
    sc_in   <sc_uint<4> >       DA_in;
    sc_in   <sc_uint<4> >       DB_in;
    sc_out  <sc_uint<7> >       EncLo_out;
    sc_out  <sc_uint<7> >       EncHi_out;

    SC_CTOR(AdderTop)
        // C++の初期化子リスト
        // AdderTop内で使う変数(入出力端子やモジュール)の初期化する。
        // sc_trace_fileでダンプしたときの名前を記載する。
        : DA_in    ( "DA_in"           )
        , DB_in    ( "DB_in"           )
        , EncLo_out( "EncLo_out"       )
        , EncHi_out( "EncHi_out"       )
        , u_AdderModule_      ( "u_AdderModule_"    )
        , u_Seg7Encoder_Lo_   ( "u_Seg7Encoder_Lo_" )
        , u_Seg7Encoder_Hi_   ( "u_Seg7Encoder_Hi_" )
    {
        // AdderModuleの入出力端子接続
        u_AdderModule_.Clock_in      ( Clock_in      );
        u_AdderModule_.Reset_N_in    ( Reset_N_in    );
        u_AdderModule_.DA_in         ( DA_in         );  // SW[3..0]
        u_AdderModule_.DB_in         ( DB_in         );  // SW[7..4]
        u_AdderModule_.DC_out        ( s_add_out_    );  // DA_in + DB_in

        u_Seg7Encoder_Lo_.Clock_in  ( Clock_in      );
        u_Seg7Encoder_Lo_.Reset_N_in( Reset_N_in    );
        u_Seg7Encoder_Lo_.d_in      ( s_enc_in_lo_  );
        u_Seg7Encoder_Lo_.d_out     ( EncLo_out     );  // HEX0[6..0]

        u_Seg7Encoder_Hi_.Clock_in  ( Clock_in      );
        u_Seg7Encoder_Hi_.Reset_N_in( Reset_N_in    );
        u_Seg7Encoder_Hi_.d_in      ( s_enc_in_hi_  );
        u_Seg7Encoder_Hi_.d_out     ( EncHi_out     );  // HEX1[6..0]

        SC_METHOD(Method_AdderTopConnection);
        sensitive << s_add_out_;

        // 高位合成用ダミースレッド
        SC_CTHREAD(Cthread_Dummy, Clock_in.pos());
    }

private:
    AdderModule     u_AdderModule_;
    Seg7Encoder     u_Seg7Encoder_Lo_;
    Seg7Encoder     u_Seg7Encoder_Hi_;

    sc_signal <sc_uint<5> >     s_add_out_;
    sc_signal <sc_uint<4> >     s_enc_in_hi_;
    sc_signal <sc_uint<4> >     s_enc_in_lo_;

    void Method_AdderTopConnection()
    {
        // 上位に0をパディングして8bitに拡張
        sc_uint<8> tmp_add_out = (sc_uint<3>(0), s_add_out_.read());

        // 4bitずつ分ける
        s_enc_in_lo_.write(tmp_add_out.range(3, 0));
        s_enc_in_hi_.write(tmp_add_out.range(7, 4));
    }

    // 高位合成用ダミースレッド
    void Cthread_Dummy();

};

AdderTop.cpp

#include "AdderTop.h"

// 高位合成用ダミー
void AdderTop::Cthread_Dummy() {
    wait();
    while (true) {
        wait();
    }
}

テストベンチ

tb_TestAdder.cpp

#include <systemc.h>
#include "AdderTop.h"

// VS2015以降はこれがないと動かない
int main(int argc, char *argv[]) {
    return sc_elab_and_sim(argc, argv);
}

int sc_main(int argc, char* argv[]) {
    sc_clock            Clock_in("Clock_in", 10, SC_NS);
    sc_signal<bool >    Reset_N_in;

    sc_signal<sc_uint<4> > din1;
    sc_signal<sc_uint<4> > din2;
    sc_signal<sc_uint<7> > dout[2];

    // AdderTop接続
    AdderTop *adt;
    adt = new AdderTop("AdderTop");
    adt->Clock_in(Clock_in);
    adt->Reset_N_in(Reset_N_in);
    adt->DA_in(din1);
    adt->DB_in(din2);
    adt->EncLo_out(dout[0]);
    adt->EncHi_out(dout[1]);

    // 波形ダンプ
    sc_trace_file *trace_f;
    trace_f = sc_create_vcd_trace_file("tb_TestAdder");
    trace_f->set_time_unit(1.0, SC_NS);
    sc_trace(trace_f, Clock_in  , "Clock_in"    );
    sc_trace(trace_f, Reset_N_in, "Reset_N_in"  );
    sc_trace(trace_f, din1      , "din1"        );
    sc_trace(trace_f, din2      , "din2"        );
    sc_trace(trace_f, dout[0]   , "dout[0]"     );
    sc_trace(trace_f, dout[1]   , "dout[1]"     );

    // -----------------------------------
    // 以下、テスト用の記述
    // -----------------------------------

    cout << hex;

    Reset_N_in = false;
    din1 = 0x0;
    din2 = 0x0;
    sc_start(50, SC_NS);
    cout << din1 << "," << din2 << " : " << dout[1].read() << "," << dout[0].read() << endl;

    // 0x0~0xfまで入力
    Reset_N_in = true;
    for (int i = 0; i <= 0xf; i++) {
        for (int j = 0; j <= 0xf; j++) {
            din1 = i;
            din2 = j;
            sc_start(20, SC_NS);
            cout << din1 << "," << din2 << " : " << dout[1].read() << "," << dout[0].read() << endl;
        }
    }

    sc_close_vcd_trace_file(trace_f);
    delete adt;

    system("pause");
    return 0;
}