SystemC自带example的pipe研习

https://www.toutiao.com/i6963556862490853891/
这是自己之前自理的一个架构方面的认识,在device器件那一层包含由各类所谓的xpu的结构,其中不乏自己依据专业领域而设计的自研结构,实现的方式有verilogHDL或是HLS之类的语言,对于硬件设计语言自己有过接触但不是专业的开发者,所以在一些高级语言综合中选了一个自己熟悉的类C语言的SystemC来做,另一个考虑就是其在软件模拟器和软硬件验证平台的建设上可能会有帮助吧.当然了,如果日后有新的好的实现方式的也会继续学习的.
1SystemC简单的安装方式SystemC的源码下载和编译安装就不介绍了,网上找下谷哥和度娘皆是,建议编译安装还是参考自带的README和INSTALL两个文件,我是基于linuxmint的操作系统安装的.
README中有SystemChasawebsiteathttp://www.accellera.org这是一个标准制定的组织,致力于电子设计自动化方面的标准,具体到SystemC可以进入到下面的页面来查看.README中也介绍了适用的各类平台:
o64-bitLinux(x86_64)
(RedHatEnterprise6;SuSEEnterpriseLinux11;Debian9)
-GNUC++compilerversionsgcc-4.2.2throughgcc-8.2.0
-ClangC++compilerversionsclang-3.4throughclang-6.0
-IntelC++Compiler(ICC15.0.0)
o64-bitLinux(x86_64)with32-bitcompiler(–host=i686-linux-gnu)
(SuSEEnterpriseLinux11)
-GNUC++compilerversionsgcc-4.2.2throughgcc-8.2.0
-IntelC++Compiler(ICC15.0.0)
o64-bitLinux(aarch64)
(Ubuntu16.04)
-GNUC++compilerversiongcc-4.5.0
o64-bitMacOSX(x86_64)
(10.12Sierra)
-AppleLLVMversion8.0(clang-800.0.42.1)
-GNUC++compiler(MacPorts)versionsgcc-4.9.0,gcc-5.4.0,gcc-6.3.0
oMicrosoftWindows
(WindowsServer2008,Windows10Enterprise)
-MicrosoftVisualStudio2010(10.0)(Win32andx64)
-MicrosoftVisualStudio2013(12.0)(Win32andx64)
-MicrosoftVisualStudio2015(14.0)(Win32andx64)
-MicrosoftVisualStudio2017(14.1)(Win32andx64)
Warning:Thefixed-pointdatatypesarenotworkingasdefinedon
MSVC2015/2017(x64)inReleasemode.SeeRELEASENOTES.
oWindowsServer2008(WoW64),Msys1.0.17(0.48/3/2)
-MinGW-w64GNUC++compilerversion4.9.2(x86_64)
https://www.accellera.org/downloads/standards/systemc
INSTALL中介绍了在各个操作系统平台下的详细安装步骤,我在linuxmint下使用了gcc和make,按照其介绍的步骤:
1.Changetothetopleveldirectory(systemc-2.3.3)
2.Createatemporarydirectory,e.g.,
>mkdirobjdir
3.Changetothetemporarydirectory,e.g.,
>cdobjdir
5.Configurethepackageforyoursystem,e.g.,
(Theconfigurescriptisexplainedbelow.)
>../configure
6.Compilethepackage.
>make
7.Atthispointyoumaywishtoverifythecompiledpackageby
testingtheexamplesuite.
>makecheck
8.Installthepackage.
>makeinstall
需要注意的步骤4,基本上是操作系统配置好的,除非想变更编译器.步骤5有详细的选项介绍,这里注意的是如果安装路径不再系统的环境变量中,则需要自己添加.常见的是/etc/profile文件末尾添加.
2pipe研习SystemC的语法这里不做详细的介绍了,在例子的学习中顺带理解吧,网络上入门的介绍也有好多,有一本书<ASystemCPrimer>,可以看看,源码我这里也有,有需要的可以私信我.
pipe由3个处理过程组成的流水,如下图所示:
stage1处理两个输入数据的加法和减法,stage2将stage1加法结果与减法的结果做乘法和除法,stage3将stage2的输出做了幂运算.
#ifndefSTAGE1_H#defineSTAGE1_Hstructstage1:sc_module{sc_in<double>in1;//input1sc_in<double>in2;//input2sc_out<double>sum;//output1sc_out<double>diff;//output2sc_in<bool>clk;//clockvoidaddsub();//methodimplementingfunctionality//CounstructorSC_CTOR(stage1){SC_METHOD(addsub);//DeclareaddsubasSC_METHODanddont_initialize();sensitive<<clk.pos();//makeitsensitivetopositiveclockedge}};#endif
#include“systemc.h”#include“stage1.h”//Definitionofaddsubmethodvoidstage1::addsub(){doublea;doubleb;a=in1.read();b=in2.read();sum.write(a+b);diff.write(a-b);}//endofaddsubmethod
上者是h文件,声明了一些对象,三个输入端口和两个输出端口以及处理过程的method.在操作系统中,进程是程序在并发环境中给的执行过程,具有动态性、并发性、独立性、异步性和结构性五大特征。在SystemC中,进程是一个级别的执行单位。模块就可以是进程,SystemC中,进程是一个基本执行单位,SC_METHOD,这个是最基础的模块,算是方法进程。每次敏感列表上有事件时,就会被调用,调用后就立刻返回。SystemC的构造函数用SC_CTOR标识与构造,其中构造函数的名字必须与模块的名字相同。dont_initialize()是希望进程在仿真的0时不被执行,sensitive是敏感表,表示时钟上升沿有效.
下者是cpp文件,定义了时钟上升沿时刻执行的动作–加法和减法.SystemC的端口定义了特定端口类型相关的方法,如read()和write()。我的理解是位宽多余1的最好都用这种方法.
#ifndefSTAGE2_H#defineSTAGE2_Hstructstage2:sc_module{sc_in<double>sum;//inputport1sc_in<double>diff;//inputport2sc_out<double>prod;//outputport1sc_out<double>quot;//outputport2sc_in<bool>clk;//clockvoidmultdiv();//methodprovidingfunctionality//ConstructorSC_CTOR(stage2){ SC_METHOD(multdiv);//DeclaremultdivasSC_METHODanddont_initialize();sensitive<<clk.pos();//makeitsensitivetopositiveclockedge.}};#endif
#include“systemc.h”#include“stage2.h”//definitionofmultdivmethodvoidstage2::multdiv(){doublea;doubleb;a=sum.read();b=diff.read();if(b==0)b=5.0;prod.write(ab);quot.write(a/b);}//endofmultdiv #ifndefSTAGE3_H#defineSTAGE3_Hstructstage3:sc_module{sc_in<double>prod;//inputport1sc_in<double>quot;//inputport2sc_out<double>powr;//outputport1sc_in<bool>clk;//clockvoidpower();//methodimplementingfunctionality//ConstructorSC_CTOR(stage3){SC_METHOD(power);//declarepowerasSC_METHODanddont_initialize();sensitive<<clk.pos();//makeitsensitivetopositiveclockedge}};#endif #include“systemc.h”#include“stage3.h”//Definitionofpowermethodvoidstage3::power(){doublea;doubleb;doublec;a=prod.read();b=quot.read();c=(a>0&&b>0)?pow(a,b):0.;powr.write©;}//endofpowermethod 时钟是电路中不可缺少的基本要素。可以看出,上面三级流水每一级都是有clk,下面我们来看看时钟信号的产生和三级流水的模块是如何连接的. #include“systemc.h”#include“stage1.h”#include“stage2.h”#include“stage3.h”#include“display.h”#include“numgen.h”intsc_main(int,charnumgen'moduleN(in1,in2,clk);//Positionalportbindingstage1S1("stage1");//instanceof
stage1‘module//NamedportbindingS1.in1(in1);S1.in2(in2);S1.sum(sum);S1.diff(diff);S1.clk(clk);stage2S2(“stage2”);//instanceofstage2'moduleS2(sum,diff,prod,quot,clk);//Positionalportbindingstage3S3("stage3");//instanceof
stage3’moduleS3(prod,quot,powr,clk);//PositionalportbindingdisplayD(“display”);//instanceofdisplay'moduleD(powr,clk);//Positionalportbindingsc_trace_file*fp;//CreateVCDfilefp=sc_create_vcd_trace_file("wave");//open(fp),createwave.vcdfilefp->set_time_unit(1,SC_NS);//settracingresolutiontonssc_trace(fp,clk,"clk");sc_trace(fp,in1,"in1");sc_trace(fp,in2,"in2");sc_trace(fp,sum,"sum");sc_trace(fp,diff,"diff");sc_trace(fp,prod,"prod");sc_trace(fp,quot,"quot");sc_trace(fp,powr,"powr");sc_start(0,SC_NS);//Initializesimulationfor(inti=0;i<10;i++){clk.write(1);sc_start(10,SC_NS);clk.write(0);sc_start(10,SC_NS);}sc_close_vcd_trace_file(fp);//close(fp)return0;}<p>上面clk的产生使用了for循环,时钟周期20ns,仿真走了10个节拍.模块间的端口用信号(Signal)连接,3级的实例化,并且采用了两种形式的端口绑定方式,除了stage1使用了名称相关的方式绑定端口,其余模块都是位置相关的端口绑定方式.</p><p>看一下数据激励的产生:</p><p>structnumgen:sc_module{sc_out<double>out1;//output1sc_out<double>out2;//output2sc_in<bool>clk;//clock//methodtowritevaluestotheoutputportsvoidgenerate();//ConstructorSC_CTOR(numgen){ SC_METHOD(generate);//DeclaregenerateasSC_METHODanddont_initialize();sensitive<<clk.pos();//makeitsensitivetopositiveclockedge }};//definitionofthe
generate‘methodvoidnumgen::generate(){staticdoublea=134.56;staticdoubleb=98.24;a-=1.5;b-=2.8;out1.write(a);out2.write(b);}//endof`generate’method
看一下结果如何打印:
structdisplay:sc_module{sc_in<double>in;//inputport1sc_in<bool>clk;//clockvoidprint_result();//methodtodisplayinputportvalues//ConstructorSC_CTOR(display){ SC_METHOD(print_result);//declareprint_resultasSC_METHODanddont_initialize(); sensitive<<clk.pos();//makeitsensitivetopositiveclockedge} };//Definitionofprint_resultmethodvoiddisplay::print_result(){printf(“Result=%f\n”,in.read());}//endofprintmethod
所有的模块都是并行执行的,在时钟的上升沿有效,main函数中还加了波形的记录,下面我们分析一下运行的结果:
这里着重看一下波形,在60ns的时刻,也就是3拍之后,每一个时钟节拍,都会执行一次有效的加减乘除和幂运算.这就是流水带来的操作并行性的体现,流水的填充和排空在长期的流水中几乎可以忽略不计,当然了,一个时钟节拍下执行一次的加减乘除和幂对实际硬件电路的要求这里不做讨论.
————————————————