基于 SystemC 的 Fir Filter 示例。

有两个模块,fir 为算法实现,tb 验证数据的输入输出。

使用 vld 和 rdy 来控制 fir 和 tb 之间的握手机制。

视频链接:https://www.bilibili.com/video/BV1P54y1z77U?p=2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
                 SYSTEM
tb0 fir0
+-----------+ +-----------+
| | | |
| | sc_clock | |
| clk | <------------> | clk |
| | | |
| | rst_sig | |
| rst | <------------> | rst |
| | | |
| | inp_sig | |
| inp | <------------> | inp |
| | <rdy vld> | |
| | outp_sig | |
| outp | <------------> | outp |
| | <vld rdy> | |
| tb | | fir |
+-----------+ +-----------+

main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include "fir.h"
#include "tb.h"
#include <systemc.h>

int sc_main(int argc, char *argv[])
{
sc_signal<sc_int<16>> inp_sig;
sc_signal<bool> inp_sig_vld; // valid: shake hands twice
sc_signal<bool> inp_sig_rdy; // ready
sc_signal<sc_int<16>> outp_sig;
sc_signal<bool> outp_sig_vld;
sc_signal<bool> outp_sig_rdy;

sc_signal<bool> rst_sig;
sc_clock clk_sig("clk_sig", 10, SC_NS);

tb tb0("tb0");
tb0.clk(clk_sig);
tb0.rst(rst_sig);
tb0.inp(inp_sig);
tb0.inp_vld(inp_sig_vld);
tb0.inp_rdy(inp_sig_rdy);
tb0.outp(outp_sig);
tb0.outp_vld(outp_sig_vld);
tb0.outp_rdy(outp_sig_rdy);

fir fir0("fir0");
fir0.clk(clk_sig);
fir0.rst(rst_sig);
fir0.inp(inp_sig);
fir0.inp_vld(inp_sig_vld);
fir0.inp_rdy(inp_sig_rdy);
fir0.outp(outp_sig);
fir0.outp_vld(outp_sig_vld);
fir0.outp_rdy(outp_sig_rdy);

sc_start();
getchar();
return 0;
}

tb.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#pragma once
#include <systemc.h>

using JiliType = int;

/*
* 产生激励
* @param clock 第几个clock
* @return 返回的输入值
*/
JiliType genExcitation(int clock)
{
if (clock > 23 && clock < 29)
return clock;
else
return 0;
}

SC_MODULE(tb)
{
sc_in<bool> clk;
sc_out<bool> rst;
sc_out<sc_int<16>> inp; // 这里的in和out要相反
sc_out<bool> inp_vld; // 输入的数值
sc_in<bool> inp_rdy;
sc_in<sc_int<16>> outp;
sc_in<bool> outp_vld;
sc_out<bool> outp_rdy;

sc_time start_time[64], end_time[64],
clock_period; // 用来计算每次延迟和累计延迟

/**
* 生成数据
* 只设置一遍,不断循环,直到结束
*/
void source()
{
// #Reset
inp.write(0);
inp_vld.write(0);
rst.write(1); // 产生复位信号的脉冲
wait();
rst.write(0); // fir::reset_signal_is(rst, true);
wait();

// #Send stimulus to FIR
sc_int<16> tmp;
for (int i = 0; i < 64; i++)
{
// 自定义写入的值
tmp = genExcitation(i);

// 开始写入
// *这里的输出机制和fir的输入机制一致
inp_vld.write(1);
inp.write(tmp);
start_time[i] = sc_time_stamp();
// wait();
do
{
wait(); // ->fir.inp.read()
} while (!inp_rdy.read());
inp_vld.write(0);
}

// 守护程序,避免一直模拟下去
wait(10000); // 结束后最大执行这么多clock。若执行到这,则会报下面的警告
cout << "run too long, stopped force" << endl;
}

/**
* 接收返回的数据
* 也只设置一遍,不断循环接收,直到结束
*/
void sink()
{
// #Initialize
outp_rdy.write(0);
// Extra clock period
sc_clock *clk_p =
DCAST<sc_clock *>(clk.get_interface()); // 时钟指针变量
clock_period = clk_p->period(); // 时钟周期
double total_cycles = 0; // 总的延迟周期(总周期/64=平均延迟)

// #Read output coming from DUT
sc_int<16> indata;
for (int i = 0; i < 64; i++)
{
outp_rdy.write(1);
// wait();
do
{
wait(); // ->fir.outp.write(out_val)
} while (!outp_vld.read());
indata = outp.read();
end_time[i] = sc_time_stamp();
total_cycles += (end_time[i] - start_time[i]) / clock_period;
outp_rdy.write(0);

cout << i << " :\t" << indata.to_int() << endl;
}

// #End simulation
sc_stop();

// Print latency
double total_throughput =
(start_time[63] - start_time[0]) / clock_period;
cout << "Averag latency = " << (double)(total_cycles / 64) << " cycles."
<< endl;
cout << "Averag throughput = " << (double)(total_throughput / 63)
<< " cycles per input." << endl;
}

SC_CTOR(tb)
{
SC_CTHREAD(source, clk.pos());
SC_CTHREAD(sink, clk.pos());
}
};

fir.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#pragma once
#include <systemc.h>

const sc_uint<8> coef[5] = {18, 77, 107, 77, 18}; // 乘的系数

SC_MODULE(fir)
{
sc_in<bool> clk;
sc_in<bool> rst;
sc_in<sc_int<16>> inp;
sc_in<bool> inp_vld;
sc_out<bool> inp_rdy;
sc_out<sc_int<16>> outp;
sc_out<bool> outp_vld;
sc_in<bool> outp_rdy;

void fir_main()
{
// FIT instances
sc_int<16> taps[5] = {0, 0, 0, 0, 0};

// Initialize handshake
inp_rdy.write(0);
outp_vld.write(0);
outp.write(0);
wait();

while (true)
{
// #输入:对应 tb::source()
inp_rdy.write(1);
do
{
wait(); // ->tb::source().inp.write(tmp)
} while (!inp_vld.read());
sc_int<16> in_val = inp.read();
inp_rdy.write(0);

// #处理
// 向后移动
for (int i = 4; i > 0; --i)
{
taps[i] = taps[i - 1];
}
taps[0] = in_val;

// 乘法和累加
sc_int<16> out_val;
for (int i = 0; i < 5; ++i)
{
out_val += coef[i] * taps[i]; // 系数和的乘积
//cout << "\t\t\t" << coef[i] << "\t*\t" << taps[i] << "\t-> "
//<< out_val << endl;
}

// #输出:对应 tb::sink()
outp_vld.write(1);
outp.write(out_val);
// wait();
do
{
wait(); // ->tb::sink().outp.read()
} while (!outp_rdy->read());
outp_vld.write(0);
}
}

SC_CTOR(fir)
{
SC_CTHREAD(fir_main, clk.pos());
reset_signal_is(rst, true); // 结合tb中的rst
}
};