我是靠谱客的博主 直率蛋挞,最近开发中收集的这篇文章主要介绍数字集成电路设计-11-SystemC引言1,环境构建2,测试3,查看子模块信号的波形4,module hierarchy5,小结,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

引言

对于稍大一点的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,小结所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(50)

评论列表共有 0 条评论

立即
投稿
返回
顶部