SystemCでDE0-CVの回路を作る コーディング編
SystemCを使ってDE0-CVの回路を作りたいと思ったのでやってみた。 part3
前回はこちら
SystemCでDE0-CVの回路を作る 環境構築編 - m-keishiの日記
準備が整ったところで早速コーディングを始める。
下記は構想編で載せたブロック図。
AdderModule → Seg7Encoder → AdderTop → テストベンチ の順番でコーディングする。
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; }