はじめに
SystemCがいつまでたっても書けないのでFIFO設計してみました。Qiitaの投稿理由は9割自分用メモです。おそらくほとんどの人に役に立たない内容です。FIFOが論理合成可能なのか未検証です。初心者なので間違いを見つけ次第指摘していただけると幸いです。
仕様
今回はSystemCで適当に設計してみたかっただけなのでFIFOの仕様は以下を想定しました。
※使えるレベルで設計していません
- 立上がり同期リセット
- データ入力8bit
- Enable書き込み読み出し
- 深さ16
構成
構成メモ
- main:SystemCのmain関数
- Systemインスタンス呼び出し
- test_pattern:テストパターンモジュール
- my_fifo:FIFOモジュール(合成予定)
- Dump:波形ダンプ記述
- Systemインスタンス呼び出し
出力
ダンプした結果を以下に記載します。読み出し信号から1サイクル後にデータが出力されているのが確認出来ました。
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で論理合成を行い動作確認していきたいと思います。