SystemC入门笔记(1)


System C是一种系统级建模语言,可以看做是一个C++的库,运行环境简单,广泛应用于软硬件系统建模。

环境搭建

为了方便学习过程的配置,我这里用的是VS2015,更新版本的VS配置差别不大。

  1. 首先下载systemc-2.3.0.tgz,安装visual stdio 2015
  2. 使用VS打开/systemc‐2.3.0/msvc80/systemc/SystemC.sln,并Build Solution,等待运行成功。
  3. 新建空项目,配置项目属性:
    • C/C++→General→Additional Include Directories,选择systemc-2.3.0\src
    • C/C++ →Language→Enable Run-Time Type Info→Yes
    • C/C++→Code Generation→Runtime Library→Multi-thread Debug(/MTd)
    • C/C++→Command Line→Additional Options,添加/vmg /D_CRT_SECURE_NO_DEPRECATE
    • Linker→General→Additional Library,选择\systemc-2.3.0\msvc80\SystemC\Debug
    • Linker→Input→Additional Dependencies,选择/systemc-2.3.0/msvc80/systemc/debug/SystemC.lib
  4. 导出模板供以后使用。

加法器设计

编写adder加法器模块c = a + b,对a、b的值敏感,a、b发生变化时即计算其和。

源码文件

  • adder.h

    SC_MODULE(Adder) {
      sc_in<int> a, b;           //定义输入端口a,b
      sc_out<int> c;             //定义输出端口c
      void compute();
      SC_CTOR(Adder) {           //构造函数
          SC_METHOD(compute);   
          sensitive << a << b;    //敏感列表
      }
    }
  • adder.cpp

    #include"adder.h"
    void Adder::compute() {
          c = a + b;
    }
  • stimulus.h

    SC_MODULE(Stimulus) {
      sc_in<bool>clk;
      sc_out<int>a, b;
      void generate();
      SC_CTOR(Stimulus) {
          SC_THREAD(generate);
          sensitive <<clk.pos(); 
      }
    }
  • stimulus.cpp,激励模块stimulus,在不同的clk信号下输入不同的a、b的值

    #include"stimulus.h"
    void Stimulus::generate() {
      wait();                //wait for clk positive edge
      a = 100; b = 200;
      wait();
      a = -100; b = -100;
      wait();
      a = 100; b = -100;
      wait();
      sc_stop();            //stop stimulus
    }
  • monitor.h

    #include"systemc.h"
    SC_MODULE(Monitor) {
      sc_in<int>a, b, c;
      sc_in<bool>clk;
      void monitor_proc();
      SC_CTOR(Monitor) {
          SC_METHOD(monitor_proc);
          sensitive <<clk.pos();
      }
    };
  • monitor.cpp,测试平台,打印a、b、c的值

    #include"monitor.h"
    using namespace std;
    void Monitor::monitor_proc(){
      std::cout << "a=" << a << ",b=" << b << ",c=" << c << std::endl;
    }
  • main.cpp,进行各个模块实例化以及端口连接

    #include"adder.h"
    #include"stimulus.h"
    #include"monitor.h"
    #include"systemc.h"
    int sc_main(int argc, char* argv[]) {
      sc_signal<int>t_a, t_b, t_c;
      sc_clock t_clk;
      Adder *a1;
      a1 = new Adder("a1");
      Stimulus *d1;
      d1 = new Stimulus("d1");
      Monitor *m1;
      m1 = new Monitor("m1");
    
      a1->a(t_a);
      a1->b(t_b);
      a1->c(t_c);
    
      d1->a(t_a);
      d1->clk(t_clk);
      d1->b(t_b);
    
      m1->a(t_a);
      m1->b(t_b);
      m1->c(t_c);
      m1->clk(t_clk);
    
      sc_start();
      system("pause");
      return 0;
    }

运行结果

加法器运行结果

通讯管道设计

源码文件

  • channel.h,包含3个部分:向通道写入接口的声明、从通道读取的接口声明、通道本身的声明。

    #pragma once
    #include "systemc.h"
    class w_if : public sc_interface {
      public:
          virtual void write(char) = 0;
    };
    class r_if : public sc_interface {
      public:
          virtual void read(char&) = 0;
    };
    class channel : public sc_channel, public w_if, public r_if {
      public:
          channel(sc_module_name name);
          ~channel();
          void write(char);
          void read(char&);
      private :
          enum depth {max = 8};
          char data[max];
          int num_elements, first;
          sc_event write_event, read_event;
    };
  • channel.cpp,包含了channel.h中声明的通道方法的实现。

    #include "channel.h"
    channel::channel(sc_module_name name) : sc_channel(name), num_elements(0), first(0) {
    }
    channel::~channel() {
    }
    void channel::write(char c) {
      if(num_elements == max)
          wait(read_event);
      data[(first + num_elements) % max] = c;
      num_elements++;
      write_event.notify();
    }
    void channel::read(char& c) {
      if(num_elements == 0)
          wait(write_event);
      c = data[first];
      num_elements--;
      first = (first + 1) % max;
      read_event.notify();
    }
  • source.h

    #include"systemc.h"
    #include"channel.h"
    class source : public sc_module
    {
      public:
          sc_port<w_if> out;
    
          SC_HAS_PROCESS(source);
    
          source(sc_module_name name) : sc_module(name) {
              SC_THREAD(source_p);
          }
    
          void source_p();
    };
  • source.cpp,自定义管道,使得经过的输出字符串顺序颠倒。

    #include"source.h"
    #include"string"
    using namespace std;
    void source :: source_p() {
      const char *alphabet = "abcdefghijklmnopqrstuvwxyz\n";
      while (*alphabet) {
          *(alphabet++);
      }
          while ((*alphabet) !=  'a') {
              out->write(*(--alphabet));
      }
    }
  • sink.h

    #include"systemc.h"
    #include"channel.h"
    class sink : public sc_module
    {
      public:
          sc_port<r_if> in;
    
          SC_HAS_PROCESS(sink);
    
          sink(sc_module_name name) : sc_module(name) {
              SC_THREAD(sink_p);
          }
    
          void sink_p();
    };
  • sink.cpp,输出模块

    #include"sink.h"
    #include<cctype>
    void sink :: sink_p() {
      char c;
    
      while (true) {
          in->read(c);
          c=(char)toupper(c);
          cout << c << flush;
      }
    
      cout << endl;
    }
  • main.cpp,包含对象的实例化、以及它们的绑定

    #include "systemc.h"
    #include "channel.h"
    #include "source.h"
    #include "sink.h"
    int sc_main (int argc, char *argv[]) {
      channel Channel("Channel");
    
      source Source("Source");
      Source.out(Channel);
    
      sink Sink("Sink");
      Sink.in(Channel);
    
      sc_start();
    
      return 0;
    }

运行结果

颠倒字符串顺序,通过管道输出。

通信管道运行结果

总结

  • 直接实例化模块和指针实例化模块不同,直接实例化模块之后,用.调用端口进行连接,指针实例化则是采用->
  • 每个头文件相当于一个模块,是SystemC的基本构成部分,源文件相当于一个函数。模块调用函数。
  • 一个模块内可以有一个或者多个进程。每个模块必须要有构造函数的进程SC_CTOR来注册进程,并且声明进程的敏感列表sensitive。进程方法声明中有一个无参量的void的返回类型。SC_METHOD声明只有一个参量,也就是该进程方法的名称。
  • 实例化连接和端口连接需要在主函数中或top模块严格进行。

文章作者: Tqraf
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Tqraf !
评论
  目录