SystemC自带example的pipe研习

https://blog.csdn.net/chenleiyfk/article/details/116995520?spm=1001.2014.3001.5501

        这是自己之前自理的一个架构方面的认识,在device器件那一层包含由各类所谓的xpu的结构,其中不乏自己依据专业领域而设计的自研结构,实现的方式有verilog HDL或是HLS之类的语言,对于硬件设计语言自己有过接触但不是专业的开发者,所以在一些高级语言综合中选了一个自己熟悉的类C语言的SystemC来做,另一个考虑就是其在软件模拟器和软硬件验证平台的建设上可能会有帮助吧.当然了,如果日后有新的好的实现方式的也会继续学习的.

1 SystemC简单的安装方式

        SystemC的源码下载和编译安装就不介绍了,网上找下谷哥和度娘皆是,建议编译安装还是参考自带的README和INSTALL两个文件,我是基于linux mint的操作系统安装的.

        README中有SystemC has a web site at       http://www.accellera.org 这是一个标准制定的组织,致力于电子设计自动化方面的标准,具体到SystemC可以进入到下面的页面来查看.README中也介绍了适用的各类平台:

    o 64-bit Linux (x86_64)
      (RedHat Enterprise 6; SuSE Enterprise Linux 11; Debian 9)
      - GNU C++ compiler versions gcc-4.2.2 through gcc-8.2.0
      - Clang C++ compiler versions clang-3.4 through clang-6.0
      - Intel C++ Compiler (ICC 15.0.0)

    o 64-bit Linux (x86_64) with 32-bit compiler (--host=i686-linux-gnu)
      (SuSE Enterprise Linux 11)
      - GNU C++ compiler versions gcc-4.2.2 through gcc-8.2.0
      - Intel C++ Compiler (ICC 15.0.0)

    o 64-bit Linux (aarch64)
      (Ubuntu 16.04)
      - GNU C++ compiler version gcc-4.5.0

    o 64-bit Mac OS X (x86_64)
      (10.12 Sierra)
      - Apple LLVM version 8.0 (clang-800.0.42.1)
      - GNU C++ compiler (MacPorts) versions gcc-4.9.0, gcc-5.4.0, gcc-6.3.0

    o Microsoft Windows
      (Windows Server 2008, Windows 10 Enterprise)
      - Microsoft Visual Studio 2010 (10.0) (Win32 and x64)
      - Microsoft Visual Studio 2013 (12.0) (Win32 and x64)
      - Microsoft Visual Studio 2015 (14.0) (Win32 and x64)
      - Microsoft Visual Studio 2017 (14.1) (Win32 and x64)

      Warning: The fixed-point datatypes are not working as defined on
               MSVC 2015/2017 (x64) in Release mode.  See RELEASENOTES.

    o Windows Server 2008 (WoW64), Msys 1.0.17(0.48/3/2)
      - MinGW-w64 GNU C++ compiler version 4.9.2 (x86_64)

https://www.accellera.org/downloads/standards/systemc

         INSTALL中介绍了在各个操作系统平台下的详细安装步骤,我在linux mint下使用了gcc和make,按照其介绍的步骤:

  1. Change to the top level directory (systemc-2.3.3)

  2. Create a temporary directory, e.g.,

        > mkdir objdir

  3. Change to the temporary directory, e.g.,

        > cd objdir

  5. Configure the package for your system, e.g.,
     (The configure script is explained below.)

        > ../configure

  6. Compile the package.

        > make

  7. At this point you may wish to verify the compiled package by
     testing the example suite.

        > make check

  8. Install the package.

        > make install

需要注意的步骤4,基本上是操作系统配置好的,除非想变更编译器.步骤5有详细的选项介绍,这里注意的是如果安装路径不再系统的环境变量中,则需要自己添加.常见的是/etc/profile文件末尾添加.

 

2 pipe研习

        SystemC的语法这里不做详细的介绍了,在例子的学习中顺带理解吧,网络上入门的介绍也有好多,有一本书<A SystemC Primer>,可以看看,源码我这里也有,有需要的可以私信我.

        pipe由3个处理过程组成的流水,如下图所示:

        stage1处理两个输入数据的加法和减法,stage2将stage1加法结果与减法的结果做乘法和除法,stage3将stage2的输出做了幂运算.

#ifndef STAGE1_H
#define STAGE1_H

struct stage1 : sc_module {
    sc_in<double> in1;   //input 1
    sc_in<double> in2;   //input 2
    sc_out<double> sum;  //output 1
    sc_out<double> diff; //output 2
    sc_in<bool>    clk;  //clock

    void addsub();       //method implementing functionality

    //Counstructor
    SC_CTOR( stage1 ) {
        SC_METHOD( addsub );     //Declare addsub as SC_METHOD and  
        dont_initialize();
        sensitive << clk.pos();  //make it sensitive to positive clock edge
    }

};

#endif
#include "systemc.h"
#include "stage1.h"

//Definition of addsub method
void stage1::addsub()
{
  double a;
  double b;

  a = in1.read();
  b = in2.read();
  sum.write(a+b);
  diff.write(a-b);

} // end of addsub method

        上者是h文件,声明了一些对象,三个输入端口和两个输出端口以及处理过程的method.在操作系统中,进程是程序在并发环境中给的执行过程,具有动态性、并发性、独立性、异步性和结构性五大特征。在SystemC中,进程是一个级别的执行单位。模块就可以是进程,SystemC中,进程是一个基本执行单位,SC_METHOD,这个是最基础的模块,算是方法进程。每次敏感列表上有事件时,就会被调用,调用后就立刻返回。SystemC的构造函数用SC_CTOR标识与构造,其中构造函数的名字必须与模块的名字相同。dont_initialize()是希望进程在仿真的0时不被执行,sensitive是敏感表,表示时钟上升沿有效.

        下者是cpp文件,定义了时钟上升沿时刻执行的动作--加法和减法.SystemC的端口定义了特定端口类型相关的方法,如read()和write()。我的理解是位宽多余1的最好都用这种方法.

#ifndef STAGE2_H
#define STAGE2_H

struct stage2 : sc_module {
    sc_in<double>  sum;      //input port 1
    sc_in<double>  diff;     //input port 2
    sc_out<double> prod;     //output port 1
    sc_out<double> quot;     //output port 2
    sc_in<bool>    clk;      //clock

    void multdiv();          //method providing functionality

    //Constructor
    SC_CTOR( stage2 ) {
	SC_METHOD( multdiv );     //Declare multdiv as SC_METHOD and
        dont_initialize();
        sensitive << clk.pos();   //make it sensitive to positive clock edge. 
    }

};

#endif
#include "systemc.h"
#include "stage2.h"

//definition of multdiv method
void stage2::multdiv()
{
  double a;
  double b;

  a = sum.read();
  b = diff.read();
  if( b == 0 )
      b = 5.0;
  
  prod.write(a*b);
  quot.write(a/b);

} // end of multdiv
#ifndef STAGE3_H
#define STAGE3_H

struct stage3: sc_module {
    sc_in<double>  prod;     //input port 1
    sc_in<double>  quot;     //input port 2
    sc_out<double> powr;     //output port 1 
    sc_in<bool>    clk;      //clock

    void power();            //method implementing functionality

    //Constructor
    SC_CTOR( stage3 ){
        SC_METHOD( power );      //declare power as SC_METHOD and 
        dont_initialize();
        sensitive << clk.pos();  //make it sensitive to positive clock edge 
    }

};

#endif
#include "systemc.h"
#include "stage3.h"

//Definition of power method
void stage3::power()
{
  double a;
  double b;    
  double c;

  a = prod.read();
  b = quot.read();
  c = (a>0 && b>0)? pow(a, b) : 0.;
  powr.write(c);
  
} // end of power method

        时钟是电路中不可缺少的基本要素。可以看出,上面三级流水每一级都是有clk,下面我们来看看时钟信号的产生和三级流水的模块是如何连接的.

#include "systemc.h"
#include "stage1.h"
#include "stage2.h"
#include "stage3.h"
#include "display.h"
#include "numgen.h"

int sc_main(int, char *[])
{
  //Signals
  sc_signal<double> in1;
  sc_signal<double> in2;
  sc_signal<double> sum;
  sc_signal<double> diff;
  sc_signal<double> prod;
  sc_signal<double> quot;
  sc_signal<double> powr;  
  //Clock
  sc_signal<bool>   clk;
  
  numgen N("numgen");               //instance of `numgen' module
  N(in1, in2, clk );                //Positional port binding
  
  stage1 S1("stage1");              //instance of `stage1' module
  //Named port binding
  S1.in1(in1);
  S1.in2(in2);
  S1.sum(sum);
  S1.diff(diff);
  S1.clk(clk);
  
  stage2 S2("stage2");              //instance of `stage2' module
  S2(sum, diff, prod, quot, clk );  //Positional port binding

  stage3 S3("stage3");              //instance of `stage3' module
  S3( prod, quot, powr, clk);       //Positional port binding
  
  display D("display");             //instance of `display' module
  D(powr, clk);                     //Positional port binding 

  sc_trace_file *fp;                  // Create VCD file
  fp=sc_create_vcd_trace_file("wave");// open(fp), create wave.vcd file
  fp->set_time_unit(1, SC_NS);        // set tracing resolution to ns  
  sc_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);               //Initialize simulation
  for(int i = 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)
  return 0;
}

        上面clk的产生使用了for循环,时钟周期20ns,仿真走了10个节拍.模块间的端口用信号(Signal)连接,3级的实例化,并且采用了两种形式的端口绑定方式,除了stage1使用了名称相关的方式绑定端口,其余模块都是位置相关的端口绑定方式.

        看一下数据激励的产生:

struct numgen : sc_module {
    sc_out<double> out1;      //output 1
    sc_out<double> out2;      //output 2
    sc_in<bool>    clk;       //clock

    // method to write values to the output ports
    void generate();
    
    //Constructor
    SC_CTOR( numgen ) {
	SC_METHOD( generate );   //Declare generate as SC_METHOD and
        dont_initialize();
        sensitive << clk.pos();  //make it sensitive to positive clock edge
				       
    }
};

// definition of the `generate' method
void numgen::generate()
{
  static double a = 134.56;
  static double b = 98.24;
  
  a -= 1.5;
  b -= 2.8;
  out1.write(a);
  out2.write(b);

} // end of `generate' method

        看一下结果如何打印:

struct display : sc_module {
    sc_in<double> in;        // input port 1
    sc_in<bool>   clk;       // clock

    void print_result();     // method to display input port values
    
    //Constructor
    SC_CTOR( display ) {
	SC_METHOD( print_result ); // declare print_result as SC_METHOD and 
        dont_initialize();
	sensitive << clk.pos();    // make it sensitive to positive clock edge
    }
	
};


//Definition of print_result method 
void display::print_result()
{
    printf("Result = %f\n", in.read());
} // end of print method

         所有的模块都是并行执行的,在时钟的上升沿有效,main函数中还加了波形的记录,下面我们分析一下运行的结果:

        这里着重看一下波形,在60ns的时刻,也就是3拍之后,每一个时钟节拍,都会执行一次有效的加减乘除和幂运算.这就是流水带来的操作并行性的体现,流水的填充和排空在长期的流水中几乎可以忽略不计,当然了,一个时钟节拍下执行一次的加减乘除和幂对实际硬件电路的要求这里不做讨论.

 

 

 

 

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

clyfk

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值