数字集成电路设计-11-SystemC

来源:互联网 发布:阿里云ecs 安装yum 编辑:程序博客网 时间:2024/04/29 18:42

引言

对于稍大一点的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 modifyX& 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 objdircd objdir../configure -prefix=/home/openrisc/systemcmakemake 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 2void 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} verilogsc_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_CTHREADsensitive << 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 10void 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 end\n");}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 = %d\n",(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 10int 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 = linuxCC = g++DEBUG = -gOTHER = -Wno-deprecated#CFLAGS = $(OTHER)CFLAGS = -Wall -m32 -O3MODULE = appSRCS = main.cpp bench.cpp adder.cppOBJS = $(SRCS:.cpp=.o)# Variabile che indica dove si trova la libreria SystemCSYSTEMC = /home/openrisc/systemcINCDIR = -I$(SYSTEMC)/includeLIBDIR = -L$(SYSTEMC)/lib-$(TARGET_ARCH)LIBS = -lsystemcEXE = $(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.xgtkwave 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();};};externvoid 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 2void 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 testif(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 10int 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 10void 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 end\n");}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 = %d\n",(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} verilogsc_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_CTHREADsensitive << 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} verilogsc_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!

8 0