gem5 使用记录,对例子中helloobject的理解

gem5中有一个 hello的例子,不是hello world那个,在src/learning-gem5/part2里面,这是虽然是个简单的例子但包含的要素挺多挺全。

整个结构是src下面有一个hello_object和goodbye_object这两个源码,前者会调用后者,同时还有有相应的python文件,这些是一一对应的。每个C++都对应一个PY文件。

PY文件可以理解对C++这个类的描述,例子中把hello_object goodbye_object两个C++写到一个PY里去了,这样也行,同样的目录下还有scons这个文件,这是编译时通过他去找哪些需要编译,里面就是把写的前面的文件加进去其实。

另外在config里面就是仿真启动,相当于是主程序的入口。也是py文件。

下面是C++配套的PY文件代码

 1 from m5.params import *
 2 from m5.SimObject import SimObject
 3 
 4 class HelloObject(SimObject):
 5     type = 'HelloObject'
 6     cxx_header = "learning_gem5/part2/hello_object.hh"
 7     cxx_class = 'gem5::HelloObject'
 8 
 9     time_to_wait = Param.Latency("Time before firing the event")
10     number_of_fires = Param.Int(1, "Number of times to fire the event before "
11                                    "goodbye")
12 
13     goodbye_object = Param.GoodbyeObject("A goodbye object")
14 
15 class GoodbyeObject(SimObject):
16     type = 'GoodbyeObject'
17     cxx_header = "learning_gem5/part2/goodbye_object.hh"
18     cxx_class = 'gem5::GoodbyeObject'
19 
20     buffer_size = Param.MemorySize('1kB',
21                                    "Size of buffer to fill with goodbye")
22     write_bandwidth = Param.MemoryBandwidth('100MB/s', "Bandwidth to fill "
23                                             "the buffer")

来理解一下这些代码,gem5有很多现有的类我们会用到, gem5所有的类都要继承自simobject这是固定的,而每个simobject都有一个params 的参数,所以开始把params和simobject导入进来。

然后是声明hello的类,继承simobject,里面是类的说明,名字,路径之类的,然后是参数第9行开始,左边是C++中的参数名字右边是他的类型,这些类型是来自第一行导入的params这些文件中已经定义好的了,比如去把parama找到打开能找到对于Latency的定义。

13行是我们要调用的子类,大型设计会有很多小类,最后在顶层把它们整合起来,这里的HELLO相当于顶层,GOODBYE相当于子功能模块,我们要把他加到主模块里来。

后面是对GOODBYE这个类的描述都差不多。

 

然后再理解下C++文件,

 1 HelloObject::HelloObject(const HelloObjectParams &params) :
 2     SimObject(params),
 3     // This is a C++ lambda. When the event is triggered, it will call the
 4     // processEvent() function. (this must be captured)
 5     event([this]{ processEvent(); }, name() + ".event"),
 6     goodbye(params.goodbye_object),
 7     // Note: This is not needed as you can *always* reference this->name()
 8     myName(params.name),
 9     latency(params.time_to_wait),
10     timesLeft(params.number_of_fires)
11 {
12     DPRINTF(HelloExample, "Created the hello object\n");
13     panic_if(!goodbye, "HelloObject must have a non-null GoodbyeObject");
14 }

这个是HELLO的构造函数,他有一个params的参数需要传进来,来源于上面的文字有说过,然后传给simobject,5行是事件的加入,这个是GEM5的机制,因为我们要模拟数字电路的工作方式,这里相当于是把要做的事加到event里面,然后拿去在某个时间执行一次,再间隔时间再执行一次这样就相当于时钟一样, 后面是GOODBYE的传参,MYname后面直接用了name这个变量,但是没有声明或者传递啥的,研究了下,是因为前面有个name()这个函数是返回例化名字的,前面用了这个函数会返回一个name变量,所以后面可以直接用,如果前面也直接用name的话就会报错。再后面是参数传递,花括号里面是构造函数要做的事情。

 1 void
 2 HelloObject::startup()
 3 {
 5     // Before simulation starts, we need to schedule the event
 6     schedule(event, latency);
 7 }
 8 
 9 void
10 HelloObject::processEvent()
11 {
13     timesLeft--;
14     DPRINTF(HelloExample, "Hello world! Processing the event! %d left\n",
15                           timesLeft);
16 
17     if (timesLeft <= 0) {
18         DPRINTF(HelloExample, "Done firing!\n");
19         goodbye->sayGoodbye(myName);
20     } else {
21         schedule(event, curTick() + latency);
22     }
23 }

上面第一个函数是startup可以看到没有其他哪里在调用它,这好像也是gem5本身的在开始仿真前会自动调用的一个函数,暂时不研究怎么调的了,里面的内容是一个安排事件的函数,这个函数也是gem5里面的实现时钟模拟的函数,之前event是把事件封起来,这里就是真正决定他好久执行了,第二个参数就是等这么久之后就执行event,而event里面又包了我们的普通函数process,这样整个类就运行起来了。

每二个函数就是普通的函数,他被封在了event里面,同时里面也有调用子类GOODBYE的功能,也有再次安排事件的调用。这样就可以实现时钟工作模式。

 

下面是config/learning/part2里面的。

 1 # set up the root SimObject and start the simulation
 2 root = Root(full_system = False)
 3 
 4 # Create an instantiation of the simobject you created
 5 root.hello = HelloObject(time_to_wait = '2us', number_of_fires = 5)
 6 root.hello.goodbye_object = GoodbyeObject(buffer_size='100B')
 7 
 8 # instantiate all of the objects we've created above
 9 m5.instantiate()
10 
11 print("Beginning simulation!")
12 exit_event = m5.simulate()
13 print('Exiting @ tick %i because %s' % (m5.curTick(), exit_event.getCause()))

这其实就是主程序的入口相当于,第2行是格式要求吧理解为,每个仿真都有个最顶层的类就是root,后面参数是表示是不是全系统模拟,我们这当然不是。第5行是在root下再例化一个之前我们写的类,并把我们想要的参数传进去。这样程序就真正的完整了,可以用了,第9行是初始化上面的东西,再后面就是开始跑起来了,都是较固定。不再细说。

posted @ 2021-12-08 14:08  远方之水  阅读(432)  评论(1编辑  收藏  举报