System C是一种系统级建模语言,可以看做是一个C++的库,运行环境简单,广泛应用于软硬件系统建模。
环境搭建
为了方便学习过程的配置,我这里用的是VS2015,更新版本的VS配置差别不大。
- 首先下载systemc-2.3.0.tgz,安装visual stdio 2015
- 使用VS打开
/systemc‐2.3.0/msvc80/systemc/SystemC.sln
,并Build Solution
,等待运行成功。 - 新建空项目,配置项目属性:
- C/C++→General→Additional Include Directories,选择
systemc-2.3.0\src
- C/C++ →Language→Enable Run-Time Type Info→Yes
- C/C++→Code Generation→Runtime Library→Multi-thread Debug(/MTd)
- C/C++→Command Line→Additional Options,添加
/vmg /D_CRT_SECURE_NO_DEPRECATE
- Linker→General→Additional Library,选择
\systemc-2.3.0\msvc80\SystemC\Debug
- Linker→Input→Additional Dependencies,选择
/systemc-2.3.0/msvc80/systemc/debug/SystemC.lib
- C/C++→General→Additional Include Directories,选择
- 导出模板供以后使用。
加法器设计
编写adder加法器模块c = a + b
,对a、b的值敏感,a、b发生变化时即计算其和。
源码文件
adder.h
SC_MODULE(Adder) { sc_in<int> a, b; //定义输入端口a,b sc_out<int> c; //定义输出端口c void compute(); SC_CTOR(Adder) { //构造函数 SC_METHOD(compute); sensitive << a << b; //敏感列表 } }
adder.cpp
#include"adder.h" void Adder::compute() { c = a + b; }
stimulus.h
SC_MODULE(Stimulus) { sc_in<bool>clk; sc_out<int>a, b; void generate(); SC_CTOR(Stimulus) { SC_THREAD(generate); sensitive <<clk.pos(); } }
stimulus.cpp,激励模块stimulus,在不同的clk信号下输入不同的a、b的值
#include"stimulus.h" void Stimulus::generate() { wait(); //wait for clk positive edge a = 100; b = 200; wait(); a = -100; b = -100; wait(); a = 100; b = -100; wait(); sc_stop(); //stop stimulus }
monitor.h
#include"systemc.h" SC_MODULE(Monitor) { sc_in<int>a, b, c; sc_in<bool>clk; void monitor_proc(); SC_CTOR(Monitor) { SC_METHOD(monitor_proc); sensitive <<clk.pos(); } };
monitor.cpp,测试平台,打印a、b、c的值
#include"monitor.h" using namespace std; void Monitor::monitor_proc(){ std::cout << "a=" << a << ",b=" << b << ",c=" << c << std::endl; }
main.cpp,进行各个模块实例化以及端口连接
#include"adder.h" #include"stimulus.h" #include"monitor.h" #include"systemc.h" int sc_main(int argc, char* argv[]) { sc_signal<int>t_a, t_b, t_c; sc_clock t_clk; Adder *a1; a1 = new Adder("a1"); Stimulus *d1; d1 = new Stimulus("d1"); Monitor *m1; m1 = new Monitor("m1"); a1->a(t_a); a1->b(t_b); a1->c(t_c); d1->a(t_a); d1->clk(t_clk); d1->b(t_b); m1->a(t_a); m1->b(t_b); m1->c(t_c); m1->clk(t_clk); sc_start(); system("pause"); return 0; }
运行结果
通讯管道设计
源码文件
channel.h,包含3个部分:向通道写入接口的声明、从通道读取的接口声明、通道本身的声明。
#pragma once #include "systemc.h" class w_if : public sc_interface { public: virtual void write(char) = 0; }; class r_if : public sc_interface { public: virtual void read(char&) = 0; }; class channel : public sc_channel, public w_if, public r_if { public: channel(sc_module_name name); ~channel(); void write(char); void read(char&); private : enum depth {max = 8}; char data[max]; int num_elements, first; sc_event write_event, read_event; };
channel.cpp,包含了channel.h中声明的通道方法的实现。
#include "channel.h" channel::channel(sc_module_name name) : sc_channel(name), num_elements(0), first(0) { } channel::~channel() { } void channel::write(char c) { if(num_elements == max) wait(read_event); data[(first + num_elements) % max] = c; num_elements++; write_event.notify(); } void channel::read(char& c) { if(num_elements == 0) wait(write_event); c = data[first]; num_elements--; first = (first + 1) % max; read_event.notify(); }
source.h
#include"systemc.h" #include"channel.h" class source : public sc_module { public: sc_port<w_if> out; SC_HAS_PROCESS(source); source(sc_module_name name) : sc_module(name) { SC_THREAD(source_p); } void source_p(); };
source.cpp,自定义管道,使得经过的输出字符串顺序颠倒。
#include"source.h" #include"string" using namespace std; void source :: source_p() { const char *alphabet = "abcdefghijklmnopqrstuvwxyz\n"; while (*alphabet) { *(alphabet++); } while ((*alphabet) != 'a') { out->write(*(--alphabet)); } }
sink.h
#include"systemc.h" #include"channel.h" class sink : public sc_module { public: sc_port<r_if> in; SC_HAS_PROCESS(sink); sink(sc_module_name name) : sc_module(name) { SC_THREAD(sink_p); } void sink_p(); };
sink.cpp,输出模块
#include"sink.h" #include<cctype> void sink :: sink_p() { char c; while (true) { in->read(c); c=(char)toupper(c); cout << c << flush; } cout << endl; }
main.cpp,包含对象的实例化、以及它们的绑定
#include "systemc.h" #include "channel.h" #include "source.h" #include "sink.h" int sc_main (int argc, char *argv[]) { channel Channel("Channel"); source Source("Source"); Source.out(Channel); sink Sink("Sink"); Sink.in(Channel); sc_start(); return 0; }
运行结果
颠倒字符串顺序,通过管道输出。
总结
- 直接实例化模块和指针实例化模块不同,直接实例化模块之后,用
.
调用端口进行连接,指针实例化则是采用->
。 - 每个头文件相当于一个模块,是SystemC的基本构成部分,源文件相当于一个函数。模块调用函数。
- 一个模块内可以有一个或者多个进程。每个模块必须要有构造函数的进程
SC_CTOR
来注册进程,并且声明进程的敏感列表sensitive
。进程方法声明中有一个无参量的void的返回类型。SC_METHOD
声明只有一个参量,也就是该进程方法的名称。 - 实例化连接和端口连接需要在主函数中或top模块严格进行。