天天看点

数字集成电路设计-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 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 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 [email protected] $(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::           

编码完成之后,我们就可以编译运行了:

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
           
数字集成电路设计-11-SystemC引言1,环境构建2,测试3,查看子模块信号的波形4,module hierarchy5,小结

除了从打印信息来debug之外,我们还可以通过分析vcd波形文件来进行调试:

数字集成电路设计-11-SystemC引言1,环境构建2,测试3,查看子模块信号的波形4,module hierarchy5,小结

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 ********************/
           

下面是波形:

数字集成电路设计-11-SystemC引言1,环境构建2,测试3,查看子模块信号的波形4,module hierarchy5,小结

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 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} 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

经过上面的修改后,我们重新编译运行,查看波形:

数字集成电路设计-11-SystemC引言1,环境构建2,测试3,查看子模块信号的波形4,module hierarchy5,小结

本实验中的代码,我已上传:

http://download.csdn.net/detail/rill_zhen/7217629

5,小结

本小节,我们简单熟悉了一下systemc,更深入的学习还要通过实际项目来历练。

enjoy!

继续阅读