GEM5教程--修改和拓展gem5(一)
一、设置开发环境
1、gen5样式准则
修改任何开源项目时,请务必遵循项目的样式准则。 gem5样式的详细信息可以在如上网站找到。
为了帮助您遵循样式准则,gem5包含一个脚本,该脚本在您在git中提交变更集时运行。 首次构建gem5时,SCons应该将此脚本自动添加到您的.git / config文件中。 请不要忽略这些警告/错误。 但是,在极少数情况下,如果您尝试提交不符合gem5样式准则的文件(例如,gem5源代码树之外的内容),则可以使用git选项–no-verify跳过运行 样式检查器。
样式指南的主要内容是:
- Use 4 spaces, not tabs
- Sort the includes
- Use capitalized camel case for class names, camel case for member variables, and underscores for local variables.
- Document your code
2、git 分支:
大多数使用gem5开发的人都使用git的分支功能来跟踪他们的更改。 这使得将更改提交回gem5非常简单。 另外,使用分支可以使其他人进行的新更改更容易更新gem5,同时将您自己的更改分开。 Git Book中有一章很棒,描述了如何使用分支的细节。
二、创建一个非常简单的SimObject
gem5中几乎所有对象都继承自基本SimObject类型。 SimObjects将主接口导出到gem5中的所有对象。 SimObject是包装的C ++对象,可从Python配置脚本访问。
SimObjects可以具有许多参数,这些参数是通过Python配置文件设置的。 除了简单的参数(例如整数和浮点数)外,它们还可以具有其他SimObjects作为参数。 这使您可以创建复杂的系统层次结构,例如真实的计算机。
这一部分,我们将逐步创建一个简单的“ HelloWorld” SimObject。 目的是向您介绍如何创建SimObject,以及所有SimObject所需的样板代码。 我们还将创建一个简单的Python配置脚本来实例化SimObject。
1、为您的新SimObject创建一个Python类
每个SimObject都有一个与之关联的Python类。 此类Python描述了可以从Python配置文件控制的SimObject的参数。 对于简单的SimObject,我们将开始时不使用任何参数。 因此,我们只需要为SimObject声明一个新类并设置其名称和C ++标头即可为SimObject定义C ++类。
我们能创建一个文件 HelloObject.py
, 在 src/learning_gem5
from m5.params import *
from m5.SimObject import SimObject
class HelloObject(SimObject):
type = 'HelloObject'
cxx_header = "learning_gem5/hello_object.hh"
不需要类型与类的名称相同,但这是约定。 类型是您与此Python SimObject包装的C ++类。 仅在特殊情况下,类型和类名才可以不同。
cxx_header是一个文件,其中包含用作类型参数的类的声明。 同样,惯例是将SimObject的名称全部使用小写和下划线,但这只是惯例。 您可以在此处指定任何头文件。
2、用C ++实现SimObject
接下来,我们创建hello_object.hh和hello_object.cc来实现hello对象。
(1)
我们将从C ++对象的头文件开始。 按照约定,gem5将所有头文件包装在#ifndef /#endif
中,并带有文件名及其所在目录,因此没有循环包含。
我们在文件中唯一需要做的就是声明我们的类。 由于HelloObject是SimObject,因此它必须继承自C ++ SimObject类。 大多数情况下,您的SimObject的父级将是SimObject的子类,而不是SimObject本身。
SimObject类指定许多虚函数。 但是,这些功能都不是纯虚拟的,因此在最简单的情况下,除了构造函数外,无需实现任何功能。
所有SimObjects的构造函数都假定它将接受一个参数对象。 这个参数对象是由构建系统自动创建的,并且基于SimObject的Python类,就像我们上面创建的那样。 此参数类型的名称是根据对象的名称自动生成的。 对于我们的“ HelloObject
”,参数类型的名称为“ HelloObject ** Params **
”。
下面列出了我们的简单头文件所需的代码:
#ifndef __LEARNING_GEM5_HELLO_OBJECT_HH__
#define __LEARNING_GEM5_HELLO_OBJECT_HH__
#include "params/HelloObject.hh"
#include "sim/sim_object.hh"
class HelloObject : public SimObject
{
public:
HelloObject(HelloObjectParams *p);
};
#endif // __LEARNING_GEM5_HELLO_OBJECT_HH__
(2)
接下来,我们需要在.cc文件中实现两个功能,而不仅仅是一个。 第一个函数是HelloObject的构造函数。 在这里,我们只是将参数对象传递给SimObject父对象,并输出“ Hello world!”。
通常,您永远不会在gem5中使用std :: cout。 相反,您应该使用调试标志。 在之后的教程中,我们将对其进行修改以改为使用调试标志。 但是,由于它很简单,我们暂时仅使用std :: cout。
#include "learning_gem5/hello_object.hh"
#include <iostream>
HelloObject::HelloObject(HelloObjectParams *params) :
SimObject(params)
{
std::cout << "Hello World! From a SimObject!" << std::endl;
}
为了使SimObject完整,我们还必须实现另一个功能。 我们必须为从SimObject Python声明隐式创建的参数类型实现一个函数,即create函数。 该函数仅返回SimObject的新实例。 通常,此功能非常简单(如下所示):
如果忘记为SimObject添加create函数,则在编译时会出现链接器错误。 它将类似于以下内容:
build/X86/python/m5/internal/param_HelloObject_wrap.o: In function `_wrap_HelloObjectParams_create':
/local.chinook/gem5/gem5-tutorial/gem5/build/X86/python/m5/internal/param_HelloObject_wrap.cc:3096: undefined reference to `HelloObjectParams::create()'
collect2: error: ld returned 1 exit status
scons: *** [build/X86/gem5.opt] Error 1
scons: building terminated because of errors.
对“ HelloObjectParams :: create()”的未定义引用意味着您需要为SimObject实现create函数。
3、注册SimObject和C ++文件
为了编译C ++文件和解析Python文件,我们需要将这些文件告知构建系统。 gem5使用SCons作为构建系统,因此您只需在目录中使用SimObject的代码创建一个SConscript文件。 如果该目录已经有一个SConscript文件,只需将以下声明添加到该文件中。
该文件只是普通的Python文件,因此您可以在该文件中编写所需的任何Python代码。 一些脚本可能变得非常复杂。 gem5利用此功能自动为SimObjects创建代码,并编译特定于域的语言,例如SLICC和ISA语言。
要编译新的SimObject,只需在src / learning_gem5
目录中创建一个名称为“ SConscript
”的新文件。 在此文件中,您必须声明SimObject和.cc文件。 以下是必需的代码:
Import('*')
SimObject('HelloObject.py')
Source('hello_object.cc')
4、(重新)构建gem5
要编译和链接新文件,您只需要重新编译gem5。 下面的示例假设您使用的是x86 ISA,但是我们的对象中不需要ISA,因此,gem5的任何ISA都可以使用。
scons build/X86/gem5.opt
5、创建配置脚本以使用新的SimObject
既然您已经实现了SimObject,并且已将其编译到gem5中,则需要创建或修改Python配置文件以实例化对象。 由于您的对象非常简单,因此不需要系统对象! 除Root对象外,不需要CPU,缓存或其他任何东西。 所有gem5实例都需要一个Root对象。
(1)
逐步创建一个非常简单的配置脚本,首先,导入m5和所有已编译的对象:
import m5
from m5.objects import *
(2)
接下来,您必须根据所有gem5实例的要求实例化Root对象:
root = Root(full_system = False)
(3)
现在,您可以实例化创建的HelloObject。 您需要做的就是将Python称为“构造函数”。 稍后,我们将研究如何通过Python构造函数指定参数。 除了创建对象的实例化之外,还需要确保它是根对象的子代。 在C ++中仅实例化作为Root对象的子对象的SimObject:
root.hello = HelloObject()
(4)
最后,您需要在m5模块上调用实例化并实际运行仿真:
m5.instantiate()
print("Beginning simulation!")
exit_event = m5.simulate()
print('Exiting @ tick {} because {}'
.format(m5.curTick(), exit_event.getCause()))
运行结果如下: