SystemC自带example的simple_perf研习

        simple_perf,SystemC的性能建模示例,也是SystemC中系统级建模的一个入门简介。

SystemC自带example的系列:

SystemC自带example的pipe研习

SystemC自带example的pkt_switch研习

1 simple_perf的基本介绍

        这是一个SystemC的性能建模示例,也是SystemC系统级建模的一个入门简介计。建模的系统包含一个生产者和消费者,通过fifo发送字符,fifo将需要确保生产者和消费者之间所有字符可靠地传输。

        要达到这样的需求:除非fifo为空,否则消费将每100 ns正好消耗一个字符。除非fifo为满,否则生产者每1000 ns产生1到19个字符。由于字符计数使用随机线性分布,因此平均而言,生产者每100 ns产生一个字符(除非fifo满)。

        如果fifo大小足够大,则每个字符的平均传输时间将接近100ns,因为生产者和消费者很少被阻塞。但是,随着fifo大小的减小,平均传输时间将增加,因为生产者有时会在写入时暂停(由于fifo已满),消费者有时会在读取时暂停(由于fifo已空)。

        运行此程序时,可以通过命令行参数设置fifo大小。默认情况下,fifo大小为10。当设计被模拟时,十万个字符从生产者转移到消费者,然后显示性能统计数据。

        使用此系统级模型,确定以下维持所需的fifo大小:

        A) 每个字符的平均传输时间为110 ns

        B) 每个字符的平均传输时间为105纳秒

2 fifo的建模

        fifo涉及的有宽度、深度、空满标志和读写指针以及in与out的方法。直接分析代码吧。下面先看看新遇见的语法,而后是fifo的设计。

        两个基类:写write和读read的定义,用了C++类的纯虚函数。fifo是基于3个基类(sc_channel、write_if、read_if)的派生类,因为写和读是纯虚函数,所以在派生类中重新定义该函数更好地适用于对象。

        使用sc_event的wait方法:使用sc_event定义一个事件,通过event.notify来激活事件,使用event.cancel来取消事件,可以将event事件放入到wait语句中使用,来通知一个事件的发生。目的实现fifo满空时的写读反压。

        fifo派生类的构造函数和析构函数:初始化和释放了定义的变量,从data的定义来看,深度size,宽度char一个字符。

        in方法:fifo只要不满(num_elements == size,暂停写入),就按照(first + num_elements) % size目前fifo元素填充情况循环递增写入空的位置上去,元素个数加1.

        out方法:fifo只要不空(num_elements == 0,暂停读取),就按照(first = (first + 1) % size)目前fifo元素填充情况循环递增读取满的位置上去,元素个数减1。

class write_if : virtual public sc_interface
{
  public:
    virtual void write(char) = 0;
    virtual void reset() = 0;
};

class read_if : virtual public sc_interface
{
  public:
    virtual void read(char &) = 0;
    virtual int num_available() = 0;
};

class fifo : public sc_channel, public write_if, public read_if
{
  public:
    fifo(sc_module_name name, int size_) : sc_channel(name), size(size_)
    {
        data = new char[size];
        num_elements = first = 0;
        num_read = max_used = average = 0;
        last_time = SC_ZERO_TIME;
    }

    ~fifo()
    {
        delete[] data;

        cout << endl << "Fifo size is: " << size << endl;
        cout << "Average fifo fill depth: " << double(average) / num_read << endl;
        cout << "Maximum fifo fill depth: " << max_used << endl;
        cout << "Average transfer time per character: " << last_time / num_read << endl;
        cout << "Total characters transferred: " << num_read << endl;
        cout << "Total time: " << last_time << endl;
    }

    void write(char c) {
        if (num_elements == size)
            wait(read_event);
            
        data[(first + num_elements) % size] = c;
        ++ num_elements;
        write_event.notify();
    }

    void read(char &c) {
        last_time = sc_time_stamp();
        if (num_elements == 0)
            wait(write_event);
            
        compute_stats();
        
        c = data[first];
        -- num_elements;
        first = (first + 1) % size;
        read_event.notify();
    }

    void reset() { num_elements = first = 0; }

    int num_available() { return num_elements;}

  private:
    char *data;
    int num_elements, first;
    sc_event write_event, read_event;
    int size, num_read, max_used, average;
    sc_time last_time;

    void compute_stats() {
        average += num_elements;
        
        if (num_elements > max_used)
            max_used = num_elements;
            
        ++num_read;
    }
};

3 生产者建模

        生产者每1000 ns产生1到19个字符,过程基本逻辑两个while循环搞定的,这里新的语法便是SC_HAS_PROCESS,注意使用进程方法没有了SC_CTOR的构造指示,这样做的目前是因为这个类的构造函数我们要传入参数了,至于SC_THREAD进程特性是不变的。

        模块间的互联之前一直使用的是sc_signal,常用的还有这个sc_port,在建模时port相较于信号与顶层互联时要简便一些。

class producer : public sc_module
{
  public:
    sc_port<write_if> out;
    SC_HAS_PROCESS(producer);

    producer(sc_module_name name) : sc_module(name)
    {
        SC_THREAD(main);
    }

    void main()
    {
        const char *str = "Visit www.accellera.org and see what SystemC can do for you today!\n";
        const char *p = str;
        int total = 100000;

        while (true) {
            int i = 1 + int(19.0 * rand() / RAND_MAX);  //  1 <= i <= 19

            while (--i >= 0) {
                out->write(*p++);
                if (!*p) p = str;
                -- total;
            }
            
            if (total <= 0)
                break;

            wait(1000, SC_NS);
        }
    }
};

4 消费者建模

        每100 ns正好消耗一个字符。

lass consumer : public sc_module
{
  public:
    sc_port<read_if> in;
    SC_HAS_PROCESS(consumer);

    consumer(sc_module_name name) : sc_module(name)
    {
        SC_THREAD(main);
    }

    void main()
    {
        char c;

        while (true) {
            in->read(c);
	          wait(100, SC_NS);
        }
    }
};

5 顶层互联

        例化时的互联,这种事务级建模的方式要快速而且简便得多。

class top : public sc_module
{
  public:
    fifo fifo_inst;
    producer prod_inst;
    consumer cons_inst;

    top(sc_module_name name, int size) :
        sc_module(name) ,
	    fifo_inst("Fifo1", size) , 
	    prod_inst("Producer1") , 
	    cons_inst("Consumer1")
    {
        prod_inst.out(fifo_inst);
        cons_inst.in(fifo_inst);
    }
};


int sc_main (int argc , char *argv[]) 
{
    int size = 10;
    if (argc > 1)
        size = atoi(argv[1]);
    if (size < 1)
        size = 1;
    if (size > 100000)
        size = 100000;

    top top1("Top1", size);
    sc_start();
    return 0;
}

 

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

clyfk

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

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

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

打赏作者

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

抵扣说明:

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

余额充值