概述
引言
对于稍大一点的project,我们在经过算法验证(C语言/C++语言)之后,直接进行RTL设计,往往比较困难,这时,我们就需要一种介于算法验证和RTL设计之间的形式来实现,而SystemC就是其中比较好的。
本小节,我们就熟悉一下SystemC。
如果你有C++,C以及verilog HDL的编程经验,你会发现SystemC非常容易使用。
1,环境构建
SystemC是在C++的基础上扩展了的一个硬件类和仿真核而形成的C++的超集,所以,SystemC本质上就是C++,所以systemC程序就可以用g++来编译。
如果我们要向编译运行SystemC程序,只需要安装一下SystemC的库即可,步骤如下:
a,下载systemc-2.2.0的tarball。
直接从官网下载的包,一般由于和系统的g++的版本不兼容,出现两个小问题。
修改systemc-2.2.0_rill_modified/src/sysc/datatypes/bit/sc_bit_proxies.h中的mutable去掉。
716行:
//mutable X& m_obj;//rill modify
X& m_obj;
1194~1197行:
//mutable X&
m_left;//rill modify
//mutable Y&
m_right;
//mutable int
m_delete;
//mutable int& m_refs;
X&
m_left;
Y&
m_right;
int
m_delete;
int& m_refs;
修改systemc-2.2.0_rill_modified/src/sysc/utils/sc_utils_ids.cpp中,增加两个头文件:
#include "cstring" //Rill add
#include "cstdlib" //Rill add
修改之后的rar压缩包,我已上传:
http://download.csdn.net/detail/rill_zhen/7203851
b,安装systemc-2.2.0
首先在~/目录下mkdir systemc 作为我们的安装目录。
export CXX=g++
mkdir objdir
cd objdir
../configure -prefix=/home/openrisc/systemc
make
make install
需要注意的是,复制到虚拟机里的configure文件可能不具有可执行属性,执行chmod 777 configure即可。
2,测试
一门语言,光看语法,是学不会的,多练多写,很快就能掌握,为了便于学习systemc,并验证刚才安装的库是否可用,我写了一个简单的例子。
无论是哪种编程语言,主要包括数据类型和流程控制两大部分,如果掌握了这两个部分,我们基本就可以掌握这门语言了。systemc也不例外。
为了全面的说明systemc的使用方法,在bench.cpp和bench.h中加了一些注释。
adder.h:
#ifndef ADDER_H_
#define ADDER_H_
#include "systemc.h"
struct adder : sc_module
{
sc_in<bool> clk;
sc_in<bool> rst;
sc_in<bool> enable;
sc_in<unsigned int> a1;
sc_in<unsigned int> a2;
sc_out<unsigned int> sum;
sc_out<bool> done;
void calc();
SC_CTOR(adder)
{
SC_METHOD(calc);
sensitive << clk.pos();
};
};
#endif //ADDER_H_
adder.cpp:
/*
* file name :adder.cpp
* func
:systemc simple test
* author :Rill
* date
:2014-04-16
*/
#include "systemc.h"
#include "adder.h"
#define CALC_IDLE 0
#define CALC_GET_VALUE 1
#define CALC_OUTPUT 2
void adder :: calc()
{
static unsigned int a1_tmp;
static unsigned int a2_tmp;
static unsigned int sum_tmp;
static unsigned int flag;
if(rst)
{
printf(" adder rst...n");
sum = 0;
done = 0;
flag = CALC_IDLE;
}
else
{
if(flag == CALC_IDLE)
{
done = 0;
if(enable)
{
flag = CALC_GET_VALUE;
a1_tmp = a1;
a2_tmp = a2;
}
else
{
flag = CALC_IDLE;
}
}
else if(flag == CALC_GET_VALUE)
{
sum_tmp = a1_tmp + a2_tmp;
flag = CALC_OUTPUT;
}
else if(flag == CALC_OUTPUT)
{
sum = sum_tmp;
done = 1;
flag = CALC_IDLE;
}
else
{
flag = CALC_IDLE;
}
}
}
/******************* EOF ********************/
bench.h:
#ifndef BENCH_H_
#define BENCH_H_
#include "systemc.h"
struct bench : sc_module
{
sc_in<bool> clk;//sc_in<sc_bit> clk;
sc_in<bool> rst;
sc_out<bool> enable;
sc_out<unsigned int> a1;//sc_out<sc_uint> a1;sc_out<32> a1;
sc_out<unsigned int> a2;//scout<64> a3 = (a1,a2);a3 = {a1,a2} verilog
sc_in<unsigned int> sum;
sc_in<bool> done;
sc_out<bool> finish;
//======================
unsigned int cnt;
void enale_adder();
void testbench();
SC_CTOR(bench)
{
SC_METHOD(testbench);//SC_THREAD,SC_CTHREAD
sensitive << clk.pos();//sensitive list:clk.neg() | sensitive << rst;
sensitive_pos(clk),sensitive(rst)
};
};
#endif //BENCH_H
bench.cpp:
/*
* file name :bench.cpp
* func
:systemc simple test
* author :Rill
* date
:2014-04-16
*/
#include "systemc.h"
#include "bench.h"
#define BENCH_INPUT 0
#define BENCH_WAIT 1
#define SIM_CNT 10
void bench :: enale_adder()
{
a1 = a1 + 3;
a2 = a2 + 4;
enable = 1;
cnt = cnt + 1;
}
void bench :: testbench()
{
static unsigned int flag;//note the 'static'
if(rst)
{
printf("bench rst...n");
a1 = 0;
a2 = 0;
enable = 0;
finish = 0;
cnt = 0;
flag = BENCH_INPUT;
}
else
{
if(cnt > SIM_CNT)
{
finish = 1;
printf("test endn");
}
else
{
if(flag == BENCH_INPUT)
{
enale_adder();
flag = BENCH_WAIT;
}
else if(flag == BENCH_WAIT)
{
enable = 0;
if(done == true)
{
printf("cnt=%d,%d + %d = %dn",(int)cnt,(int)a1,(int)a2,(int)sum);//here we must explicit cast to int from unsigned int.
flag = BENCH_INPUT;
}
}
}
}
}
/******************* EOF ********************/
main.cpp:
/*
* file name :main.cpp
* func
:systemc simple test
* author :Rill
* date
:2014-04-16
*/
#include "systemc.h"
#include "bench.h"
#include "adder.h"
#define CLK_PERIOD 10
int sc_main(int,char*[])
{
sc_trace_file * tf = NULL;
unsigned loop = 0;
sc_signal<bool> clk;
sc_signal<bool> rst;
sc_signal<bool> enable;
sc_signal<unsigned int> a1;
sc_signal<unsigned int> a2;
sc_signal<unsigned int> sum;
sc_signal<bool> done;
sc_signal<bool> finish;
bench bench0("BENCH");
bench0.clk(clk);//bench0<<clk<<rst<<enable<<a1<<a2<<sum<<done;
bench0.rst(rst);
bench0.enable(enable);
bench0.a1(a1);
bench0.a2(a2);
bench0.sum(sum);
bench0.done(done);
bench0.finish(finish);
adder adder0("BENCH");
adder0.clk(clk);
adder0.rst(rst);
adder0.enable(enable);
adder0.a1(a1);
adder0.a2(a2);
adder0.sum(sum);
adder0.done(done);
tf = sc_create_vcd_trace_file("rill_sc_tf");//tf = sc_creat_wif_trace_file("rill_sc_tf");
sc_trace(tf,clk,"clk");
sc_trace(tf,rst,"rst");
sc_trace(tf,enable,"enable");
sc_trace(tf,a1,"a1");
sc_trace(tf,a2,"a2");
sc_trace(tf,sum,"sum");
sc_trace(tf,done,"done");
sc_trace(tf,finish,"finish");
sc_start(0,SC_NS);
for(loop=0;loop<3;loop++)//rst 3 cycles
{
clk.write(1);
rst.write(1);
sc_start(CLK_PERIOD/2,SC_NS);
clk.write(0);
sc_start(CLK_PERIOD/2,SC_NS);
}
rst.write(0);
while(1 != finish.read())//sim calc
{
clk.write(1);
sc_start(CLK_PERIOD/2,SC_NS);
clk.write(0);
sc_start(CLK_PERIOD/2,SC_NS);
}
return 0;
}
/******************* EOF ********************/
Makefile:
TARGET_ARCH = linux CC = g++ DEBUG = -g OTHER = -Wno-deprecated #CFLAGS = $(OTHER) CFLAGS = -Wall -m32 -O3 MODULE = app SRCS = main.cpp bench.cpp adder.cpp OBJS = $(SRCS:.cpp=.o) # Variabile che indica dove si trova la libreria SystemC SYSTEMC = /home/openrisc/systemc INCDIR = -I$(SYSTEMC)/include LIBDIR = -L$(SYSTEMC)/lib-$(TARGET_ARCH) LIBS = -lsystemc EXE = $(MODULE).x # Comunica al make su quali tipi di estensioni deve eseguire le regole di suffisso. .SUFFIXES: .cpp .o .x $(EXE): $(OBJS) $(SYSTEMC)/lib-$(TARGET_ARCH)/libsystemc.a $(CC) $(CFLAGS) $(LIBDIR) -o $@ $(OBJS) $(LIBS) # Comunica al make di eseguire una compilazione # C++ per tutti i file aventi estensione .c # e per i quali i relativi file oggetto non # sono stati ancora aggiornati .cpp.o: $(CC) $(CFLAGS) $(INCDIR) -c $< clean::
rm -f $(OBJS) *~ $(EXE) core *.vcd *.wif
编码完成之后,我们就可以编译运行了:
make
./app.x
gtkwave rill_sc_tf
下面是执行结果:
需要说明的是,如果你在运行时,提示找不到动态库文件(libsystemc.so),这可能是你的系统的环境变量(LD_LIBRARY_PATH)没有设置,设置一下即可:
修改.bashrc文件,增加如下语句之后,重新打开一个终端即可。
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/openrisc/systemc/lib-linux
除了从打印信息来debug之外,我们还可以通过分析vcd波形文件来进行调试:
3,查看子模块信号的波形
上面的例子中,我们可以看到模块间的信号的波形,但是如何才能查看子模块内部的信号呢?有两种方式可以实现。
方式1:
sc_trace(tf,adder0.test,"test");
方式2:
sc_trace(tf, adder0, "adder0");
采用方式1,顶层模块需要对子模块比较了解才行,采用方式2则不用,比较好一点,下面是采用两种方式。修改后的代码:
adder.h:
#ifndef ADDER_H_
#define ADDER_H_
#include "systemc.h"
struct adder : sc_module
{
sc_in<bool> clk;
sc_in<bool> rst;
sc_in<bool> enable;
sc_in<unsigned int> a1;
sc_in<unsigned int> a2;
sc_out<unsigned int> sum;
sc_out<bool> done;
unsigned int test;
void calc();
SC_CTOR(adder)
{
SC_METHOD(calc);
sensitive << clk.pos();
};
};
extern
void sc_trace(sc_trace_file *tf, const adder& v, const char * NAME);
#endif //ADDER_H_
adder.cpp:
/*
* file name :adder.cpp
* func
:systemc simple test
* author :Rill
* date
:2014-04-16
*/
#include "systemc.h"
#include "adder.h"
#define CALC_IDLE 0
#define CALC_GET_VALUE 1
#define CALC_OUTPUT 2
void adder :: calc()
{
static unsigned int a1_tmp;
static unsigned int a2_tmp;
static unsigned int sum_tmp;
static unsigned int flag;
if(rst)
{
printf(" adder rst...n");
sum = 0;
done = 0;
flag = CALC_IDLE;
test = 0;//sc_trace test
}
else
{
test = test + 1;//sc_trace test
if(flag == CALC_IDLE)
{
done = 0;
if(enable)
{
flag = CALC_GET_VALUE;
a1_tmp = a1;
a2_tmp = a2;
}
else
{
flag = CALC_IDLE;
}
}
else if(flag == CALC_GET_VALUE)
{
sum_tmp = a1_tmp + a2_tmp;
flag = CALC_OUTPUT;
}
else if(flag == CALC_OUTPUT)
{
sum = sum_tmp;
done = 1;
flag = CALC_IDLE;
}
else
{
flag = CALC_IDLE;
}
}
}
void sc_trace(sc_trace_file *tf, const adder& v, const char * NAME) {
sc_trace(tf,v.test, "addr0.test");
}
/******************* EOF ********************/
main.cpp:
/*
* file name :main.cpp
* func
:systemc simple test
* author :Rill
* date
:2014-04-16
*/
#include "systemc.h"
#include "bench.h"
#include "adder.h"
#define CLK_PERIOD 10
int sc_main(int,char*[])
{
unsigned loop = 0;
sc_trace_file * tf = NULL;
sc_signal<bool> clk;
sc_signal<bool> rst;
sc_signal<bool> enable;
sc_signal<unsigned int> a1;
sc_signal<unsigned int> a2;
sc_signal<unsigned int> sum;
sc_signal<bool> done;
sc_signal<bool> finish;
tf = sc_create_vcd_trace_file("rill_sc_tf");//tf = sc_creat_wif_trace_file("rill_sc_tf");
bench bench0("BENCH");
bench0.clk(clk);//bench0<<clk<<rst<<enable<<a1<<a2<<sum<<done;
bench0.rst(rst);
bench0.enable(enable);
bench0.a1(a1);
bench0.a2(a2);
bench0.sum(sum);
bench0.done(done);
bench0.finish(finish);
adder adder0("BENCH");
adder0.clk(clk);
adder0.rst(rst);
adder0.enable(enable);
adder0.a1(a1);
adder0.a2(a2);
adder0.sum(sum);
adder0.done(done);
sc_trace(tf,clk,"clk");
sc_trace(tf,rst,"rst");
sc_trace(tf,enable,"enable");
sc_trace(tf,a1,"a1");
sc_trace(tf,a2,"a2");
sc_trace(tf,sum,"sum");
sc_trace(tf,done,"done");
sc_trace(tf,finish,"finish");
//sc_trace(tf,adder0.test,"test");
sc_trace(tf, adder0, "adder0");
sc_start(0,SC_NS);
for(loop=0;loop<3;loop++)//rst 3 cycles
{
clk.write(1);
rst.write(1);
sc_start(CLK_PERIOD/2,SC_NS);
clk.write(0);
sc_start(CLK_PERIOD/2,SC_NS);
}
rst.write(0);
while(1 != finish.read())//sim calc
{
clk.write(1);
sc_start(CLK_PERIOD/2,SC_NS);
clk.write(0);
sc_start(CLK_PERIOD/2,SC_NS);
}
return 0;
}
/******************* EOF ********************/
下面是波形:
4,module hierarchy
对于一门语言,流程控制,除了模块内部之外,另外一个重要的部分就是模块间的层次组织,上面我们了解了模块内部的流程控制,下面我们对上面的代码稍作修改,即可展示systemc的module hierarchy。
a,将bench.cpp文件名改为benc_sub.cpp并进行简单修改
benc_sub.cpp修改后如下:
/*
* file name :bench_sub.cpp
* func
:systemc simple test
* author :Rill
* date
:2014-04-19
*/
#include "systemc.h"
#include "bench_sub.h"
#define BENCH_INPUT 0
#define BENCH_WAIT 1
#define SIM_CNT 10
void bench_sub :: enale_adder()
{
a1 = a1 + 3;
a2 = a2 + 4;
enable = 1;
cnt = cnt + 1;
}
void bench_sub :: testbench()
{
static unsigned int flag;//note the 'static'
if(rst)
{
printf("bench rst...n");
a1 = 0;
a2 = 0;
enable = 0;
finish = 0;
cnt = 0;
flag = BENCH_INPUT;
}
else
{
if(cnt > SIM_CNT)
{
finish = 1;
printf("test endn");
}
else
{
if(flag == BENCH_INPUT)
{
enale_adder();
flag = BENCH_WAIT;
}
else if(flag == BENCH_WAIT)
{
enable = 0;
if(done == true)
{
printf("cnt=%d,%d + %d = %dn",(int)cnt,(int)a1,(int)a2,(int)sum);//here we must explicit cast to int from unsigned int.
flag = BENCH_INPUT;
}
}
}
}
}
/******************* EOF ********************/
b,复制bench.h为bench_sub.h,并稍作修改
bench_sub.h修改后如下:
#ifndef BENCH_SUB_H_
#define BENCH_SUB_H_
#include "systemc.h"
struct bench_sub : sc_module
{
sc_in<bool> clk;//sc_in<sc_bit> clk;
sc_in<bool> rst;
sc_out<bool> enable;
sc_out<unsigned int> a1;//sc_out<sc_uint> a1;sc_out<32> a1;
sc_out<unsigned int> a2;//scout<64> a3 = (a1,a2);a3 = {a1,a2} verilog
sc_in<unsigned int> sum;
sc_in<bool> done;
sc_out<bool> finish;
//======================
unsigned int cnt;
void enale_adder();
void testbench();
SC_CTOR(bench_sub)
{
SC_METHOD(testbench);//SC_THREAD,SC_CTHREAD
sensitive << clk.pos();//sensitive list:clk.neg() | sensitive << rst;
sensitive_pos(clk),sensitive(rst)
};
};
#endif //BENCH_SUB_H_
c,修改bench.h,在构造函数里例化bench_sub模块
bench.h修改后如下:
#ifndef BENCH_H_
#define BENCH_H_
#include "systemc.h"
#include "bench_sub.h"
struct bench : sc_module
{
sc_in<bool> clk;//sc_in<sc_bit> clk;
sc_in<bool> rst;
sc_out<bool> enable;
sc_out<unsigned int> a1;//sc_out<sc_uint> a1;sc_out<32> a1;
sc_out<unsigned int> a2;//scout<64> a3 = (a1,a2);a3 = {a1,a2} verilog
sc_in<unsigned int> sum;
sc_in<bool> done;
sc_out<bool> finish;
//======================
bench_sub * bench_sun_inst;
SC_CTOR(bench)
{
bench_sun_inst = new bench_sub("bench_sub");
bench_sun_inst->clk(clk);
bench_sun_inst->rst(rst);
bench_sun_inst->enable(enable);
bench_sun_inst->a1(a1);
bench_sun_inst->a2(a2);
bench_sun_inst->sum(sum);
bench_sun_inst->done(done);
bench_sun_inst->finish(finish);
};
};
#endif //BENCH_H
d,修改Makefile中的SRCS中的bench.cpp为bench_sub.cpp
经过上面的修改后,我们重新编译运行,查看波形:
本实验中的代码,我已上传:
http://download.csdn.net/detail/rill_zhen/7217629
5,小结
本小节,我们简单熟悉了一下systemc,更深入的学习还要通过实际项目来历练。
enjoy!
最后
以上就是直率蛋挞为你收集整理的数字集成电路设计-11-SystemC引言1,环境构建2,测试3,查看子模块信号的波形4,module hierarchy5,小结的全部内容,希望文章能够帮你解决数字集成电路设计-11-SystemC引言1,环境构建2,测试3,查看子模块信号的波形4,module hierarchy5,小结所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复