LoginSignup
4
2

More than 5 years have passed since last update.

SystemCでFIFOテスト

Last updated at Posted at 2018-09-02

はじめに

SystemCがいつまでたっても書けないのでFIFO設計してみました。Qiitaの投稿理由は9割自分用メモです。おそらくほとんどの人に役に立たない内容です。FIFOが論理合成可能なのか未検証です。初心者なので間違いを見つけ次第指摘していただけると幸いです。

仕様

今回はSystemCで適当に設計してみたかっただけなのでFIFOの仕様は以下を想定しました。
※使えるレベルで設計していません

  • 立上がり同期リセット
  • データ入力8bit
  • Enable書き込み読み出し
  • 深さ16

構成

main3.png
モジュール構成図

構成メモ

  • main:SystemCのmain関数
    • Systemインスタンス呼び出し
      • test_pattern:テストパターンモジュール
      • my_fifo:FIFOモジュール(合成予定)
    • Dump:波形ダンプ記述

出力

ダンプした結果を以下に記載します。読み出し信号から1サイクル後にデータが出力されているのが確認出来ました。

スクリーンショット 2018-09-08 14.09.32.png

FIFOモジュール

my_fifo.h
#pragma once
#include <systemc.h>

SC_MODULE(my_fifo)
{
    //ポート宣言
    sc_in<bool> clk;
    sc_in<bool> rst;
    sc_in<bool> en_i;
    sc_in<sc_uint<4> > data_i;
    sc_in<bool> en_o;
    sc_out<sc_uint<4> > data_o;
    sc_out<bool> empty_o;
    sc_out<bool> full_o;

    //メンバ変数
    sc_signal<sc_uint<4> > data[16];
    uint8_t addr;

    //メンバ関数
    void reset();
    void write_thread();
    void read_thread();
    void status_thread();

    SC_CTOR(my_fifo)
    {
        SC_CTHREAD(write_thread, clk.pos());
        reset_signal_is(rst, true);
        SC_CTHREAD(read_thread, clk.pos());
        reset_signal_is(rst, true);
        SC_CTHREAD(status_thread, clk.pos());
        reset_signal_is(rst, true);
    }
};

動作は3つに分けて適当に記述しました。

  • リセット
  • 書き込み
  • 読み出し
my_fifo.cpp
#include "my_fifo.h"

void my_fifo::reset()
{
    //アドレス初期化
    addr = 0;

    //メモリ初期化
    for (int i = 0; i < 16; i++) {
        data[i] = 0;
    }
    wait();
}

void my_fifo::write_thread()
{
    reset();
    while (true) {
        if (en_i.read() == 1) {
            data[addr] = data_i.read();
            if(addr != 15) addr++;
        }
        if (en_o.read() == 1) {
            for (int i = 0; i < 15; i++) {
                data[i] = data[i + 1];
            }
            if(addr != 0) addr--;
        }
        wait();
    }
}

void my_fifo::read_thread()
{
    //ポート初期化
    data_o.write(15);
    wait();
    while (true) {
        data_o.write(data[0]);
        wait();
    }
}

void my_fifo::status_thread()
{
    //ポート初期化
    empty_o.write(1);
    full_o.write(0);
    wait();
    while (true) {
        if (addr == 0) {
            empty_o.write(1);
        }
        else {
            empty_o.write(0);
        }

        if (addr == 15) {
            full_o.write(1);
        }
        else {
            full_o.write(0);
        }

        wait();
    }
}

テストベンチ

Systemでモジュールの結線を行っています。それをmain関数でインスタンス化し、階層アクセスして必要なポートをダンプします。クロックは特殊な書き方をしないとmain関数以外で記述出来ない仕様っぽいのでSystemはclkとrstのみコントロール出来るようにポート宣言しています。

Source.cpp
#define _CRT_SECURE_NO_WARNINGS
#include <systemc.h>
#include "testbench.h"

//クロックステップ[ns]
#define CLK_STEP 10

//TOPインスタンス
static System * m_system = NULL;

int sc_main(int argc, char** argv)
{
    //クロックリセット
    sc_clock clk("clk", CLK_STEP);
    sc_signal<bool> rst;

    //TOP接続
    m_system = new System("system");
    m_system->clk(clk);
    m_system->rst(rst);

    //波形ダンプ
    sc_trace_file *trace_f;
    trace_f = sc_create_vcd_trace_file("system");
    sc_trace(trace_f, clk, "clk");
    sc_trace(trace_f, rst, "rst");
    sc_trace(trace_f, m_system->data_i, "data_i");
    sc_trace(trace_f, m_system->en_i, "en_i_i");
    sc_trace(trace_f, m_system->data_o, "data_o");
    sc_trace(trace_f, m_system->en_o, "en_i_o");
    sc_trace(trace_f, m_system->empty_o, "empty_o");
    sc_trace(trace_f, m_system->full_o, "full_o");

    //テストベンチ
    rst = 1;
    sc_start(CLK_STEP * 1, SC_NS);
    rst = 0;
    sc_start(CLK_STEP * 1000, SC_NS);
    //テスト終了
    sc_close_vcd_trace_file(trace_f);
    cout << endl;
    cout << "----------------------------------------" << endl;
    cout << "finish sim!!" << endl;
    cout << "----------------------------------------" << endl;
    cout << endl;

    return 0;
}
testbench.h
#pragma once
#include <systemc.h>
#include <fstream>
#include "test_pattern.h"
#include "my_fifo.h"
using namespace std;

SC_MODULE(System)
{
    //ポート宣言
    sc_in<bool> clk; 
    sc_in<bool> rst;

    //メンバ変数
    sc_signal<bool> en_i;
    sc_signal<sc_uint<4> > data_i;
    sc_signal<bool> en_o;
    sc_signal<sc_uint<4> >data_o;
    sc_signal<bool> empty_o;
    sc_signal<bool> full_o;

    //モジュールインスタンス
    test_pattern pattern0;
    my_fifo fifo0;

    SC_CTOR(System)
        : pattern0("pattern0")
        , fifo0("fifo0")
    {
        //インスタンス(pattern0)
        pattern0.clk(clk);
        pattern0.rst(rst);
        pattern0.en_i(en_i);
        pattern0.data_i(data_i);
        pattern0.en_o(en_o);
        pattern0.data_o(data_o);
        //インスタンス(fifo0)
        fifo0.clk(clk);
        fifo0.rst(rst);
        fifo0.en_i(en_i);
        fifo0.data_i(data_i);
        fifo0.en_o(en_o);
        fifo0.data_o(data_o);
        fifo0.empty_o(empty_o);
        fifo0.full_o(full_o);
    }
};

テストパターンモジュール

テストパターンを出力するモジュールも分かりやすいように分離して記述しました。

test_pattern.h
#pragma once
#include <systemc.h>

SC_MODULE(test_pattern)
{
    //ポート宣言
    sc_in<bool> clk;
    sc_in<bool> rst;
    sc_out<bool> en_i;
    sc_out<sc_uint<4> > data_i;
    sc_out<bool> en_o;
    sc_in<sc_uint<4> >data_o;

    //メンバ関数
    void pattern_proc();
    void dump_proc();

    SC_CTOR(test_pattern)
    {
        SC_CTHREAD(pattern_proc, clk.pos());
    }
};
test_pattern.cpp
#include "test_pattern.h"

void test_pattern::dump_proc()
{
    const std::string output = "output.txt";
    std::ofstream ofs(output, std::ios::out);

    for (int i = 0; i < 30; i++) {
        en_o.write(1);
        ofs << data_o.read() << endl;
        wait();
    }
    en_o.write(1);
}

void test_pattern::pattern_proc()
{
    wait();
    for (int i = 0; i < 16; i++) {
        en_i.write(1);
        data_i.write(i);
        wait();
    }
    en_i.write(0);
    wait();

    dump_proc();

    while (true) {
        wait();
    }
}

おわりに

検索してもSystemCの書き方の参考サイトがなかなか出てこなかったのですが、忘れん坊将軍の備忘録:SystemCが参考になりました。今回はシミュレーションのみで動作確認をしたので、後日Vivado HLSで論理合成を行い動作確認していきたいと思います。

4
2
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
4
2