M5ops

此页面解释了可用于 M5 执行检查点等的特殊操作码。m5 实用程序(在我们的磁盘镜像和 util/m5/* 中)在命令行上提供了一些此类功能。在许多情况下,最好直接在您感兴趣的应用程序的源代码中插入操作。您应该能够链接相应的 libm5.a 文件,并且 m5ops.h 头文件包含所有函数的原型。 关于使用 M5ops 的教程是 gem5 2022 Bootcamp 的一部分。此活动的录音可以在 这里 找到。

构建 M5 和 libm5

为了构建目标的 m5 和 libm5.a,请在 util/m5/ 目录中运行以下命令。

scons build/{TARGET_ISA}/out/m5

目标 ISA 列表如下所示。

注意:如果您在 x86 系统上用于其他 ISA,则需要安装交叉编译器。交叉编译器的名称显示在上面列表中的括号内。

有关更多详细信息,请参阅 util/m5/README.md

m5 实用程序 (FS 模式)

m5 实用程序(参见 util/m5/)可用于在 FS 模式下发出特殊指令以触发特定于模拟的功能。它目前提供以下选项:

其他 M5 ops

这些是其他在命令行形式中无用的 M5 ops。

在 Java 代码中使用 gem5 ops

这些 ops 也可以在 Java 代码中使用。这些 ops 允许从 java 程序中调用 gem5 ops,如下所示:

import jni.gem5Op;

public  class HelloWorld {

   public static void main(String[] args) {
       gem5Op gem5 = new gem5Op();
       System.out.println("Rpns0:" + gem5.rpns());
       System.out.println("Rpns1:" + gem5.rpns());
   }

   static {
       System.loadLibrary("gem5OpJni");
   }
}

构建时,您需要确类路径包含 gem5OpJni.jar:

javac -classpath $CLASSPATH:/path/to/gem5OpJni.jar HelloWorld.java

运行时,您需要确保同时设置了 java 和库路径:

java -classpath $CLASSPATH:/path/to/gem5OpJni.jar -Djava.library.path=/path/to/libgem5OpJni.so HelloWorld

在 Fortran 代码中使用 gem5 ops

gem5 的特殊操作码(伪指令)可以与 Fortran 程序一起使用。在 Fortran 代码中,可以添加对调用特殊操作码的 C 函数的调用。在创建最终二进制文件时,将 Fortran 程序和 C 程序(用于操作码)的目标文件一起编译。我发现 这里 提供的文档很有用。阅读 -- Compiling a mixed C-Fortran program 部分。

在 Fortran 代码中使用 gem5 ops 的想法本质上是将 m5 ops C 代码编译为目标文件,然后将目标文件链接到调用 m5 ops 的二进制文件。 Fortran 中的 C 函数调用约定是,如果 C 代码中的函数名称是 void foo_bar_(void),那么在 Fortran 中,您可以通过 call foo_bar 调用该函数。

将 M5 链接到您的 C/C++ 代码

为了将 m5 链接到您的代码,首先如上节所述构建 libm5.a

然后

例如,可以通过将以下内容添加到 Makefile 来实现:

CFLAGS += -I$(GEM5_PATH)/include
LDFLAGS += -L$(GEM5_PATH)/util/m5/build/$(TARGET_ISA)/out -lm5

这是一个简单的 Makefile 示例:

TARGET_ISA=x86

GEM5_HOME=$(realpath ./)
$(info   GEM5_HOME is $(GEM5_HOME))

CXX=g++

CFLAGS=-I$(GEM5_HOME)/include

LDFLAGS=-L$(GEM5_HOME)/util/m5/build/$(TARGET_ISA)/out -lm5

OBJECTS= hello_world

all: hello_world

hello_world:
	$(CXX) -o $(OBJECTS) hello_world.cpp $(CFLAGS) $(LDFLAGS)

clean:
	rm -f $(OBJECTS)

使用 M5ops 的 “_addr” 版本

m5ops 的 “_addr” 版本触发与默认 m5ops 相同的模拟特定功能,但它们使用不同的触发机制。下面是 m5 实用程序 README.md 的引用,解释了触发机制。

头文件中定义的裸函数名将使用基于魔术指令的触发机制,这在历史上是默认的。

头文件末尾的一些宏将设置其他声明,这些声明镜像所有其他定义,但带有 "_addr" 和 "_semi" 后缀。这些其他版本将触发相同的 gem5 操作,但使用“魔术”地址或 semihosting 触发机制。虽然这些函数将在头文件中无条件声明,但只有在该 ABI 支持该触发机制时,库中才会存在定义。

注意: 生成 “_addr” 和 “_semi” m5ops 的宏称为 M5OP,它们在 util/m5/abi/*/m5op_addr.Sutil/m5/abi/*/m5op_semi.S 中定义。

为了使用 m5ops 的 “_addr” 版本,您需要包含 m5_mmap.h 头文件,将“魔术”地址(例如,x86 为 “0xFFFF0000”,arm64/riscv 为 “0x10010000”)传递给 m5op_addr,然后调用 map_m5_mem() 以打开 /dev/mem。您可以通过在原始 m5ops 函数末尾添加 “_addr” 来插入 m5ops。

这是一个使用 m5ops 的 “_addr” 版本的简单示例:

#include <gem5/m5ops.h>
#include <m5_mmap.h>
#include <stdio.h>

#define GEM5

int main(void) {
#ifdef GEM5
    m5op_addr = 0xFFFF0000;
    map_m5_mem();
    m5_work_begin_addr(0,0);
#endif

    printf("hello world!\n");

#ifdef GEM5
    m5_work_end_addr(0,0);
    unmap_m5_mem();
#endif
}

注意: 您需要为编译器添加新的头文件位置以查找 m5_mmap.h。 如果您遵循上面的 Makefile 示例,您可以在定义 CFLAGS 的位置下方添加以下行,

CFLAGS += $(GEM5_PATH)/util/m5/src/

当您在带有 KVM CPU 的 FS 模式下运行插入了 m5ops 的应用程序时,可能会出现此错误。

```illegal instruction (core dumped)```

这是因为 m5ops 指令对主机来说不是有效指令。使用 m5ops 的 “_addr” 版本可以解决此问题,因此如果您想将 m5ops 集成到您的应用程序中或在使用 KVM CPU 运行时使用 m5 二进制实用程序,则必须使用 “_addr” 版本。