3 在memory system里创建SimObject
在本章节,我们创建一个简单对象在CPU和内存总线之间。下一个章节添加逻辑让它成为一个简单的阻塞式单处理器缓存。
3.1 Gem5主端口和从端口
深入内存对象之前,应首先了解gem5的主从端口。因为所有的memory对象都是通过这些端口连接一起的。
这些端口实现了3种不同的memory system mode:timing,atomic,functional。其中最重要的mode是timing mode。因为timing mode是唯一生成正确模拟结果的模式。其它模式一般用在特殊的情形。
atomic mode对于转发(fastforwarding)模拟和加速模拟器来讲比较有用。这个模式假设在memory system中没有事件(event)会发生。相反地,所有内存请求都是通过一个长长的调用链(callchain)执行。
functional mode更好的一个说法是debug mode。
3.2 Packets
Gem5中,packets通过接口发送。一个Packet由内存请求对象MemReq
组成。MemReq
保存一些原始请求信息诸如请求者、地址、请求类型(read or write)。
Packet也有一个MemCmd
,这是数据包的当前命令。该命令可以在数据包的整个生命周期中变化(比如当存储器命令满足了,请求变成相应)。常见的MemCmd
包括ReadReq
读取请求,ReadResp
读取相应,WriteReq
写入请求,WriteResp
写入响应。还有缓存和许多其它命令类型的写回请求(WritebackDirty
,WritebackClean
)。
Packet还保留请求的数据或指向数据的指针。
最后数据包被用来在classic cache中作为跟踪一致性的单元。因此大多数packet代码都是classic cache一致性协议所特有的。然而,packet用于gem5中内存对象之间的所有通信,即使他们不涉及一致性(比如DRAM控制器和CPU型号)。
所有端口的接口函数都接受一个Packet指针作为参数。
3.3 Port interface
Gem5中有两种类型的端口:主端口和从端口。每当你实现一个内存对象的时候,你要至少实现这些类型的端口之一(主or从)。要这么做,需要创建一个新的类继承自MasterPort
或SlavePort
。主接口发送请求,从接口接收请求。
下图是一个简单的master-slave接口:
所有的端口接口都需要一个PacketPtr
作为一个参数。这些函数(sendTimingReq
, recvTimingReq
, etc.)接收一个参数PacketPtr
。
为了发射一个request的packet,master调用sendTimingReq
。相对应的,函数recvTimingReq
在slave中被调用并且参数是同一个PacketPtr
。
recvTimingReq
有一个布尔返回值,这个返回值直接发回到调用的master。true
代表packet被slave接收,false
代表不能被接收并且请求需要过一段时间再次发送。
master或slave在接收到请求或响应时可能处于忙碌状态。下图展示了当原始请求发送时,slave繁忙的情形:
上图这种情况,slave返回了false。当master调用了sendTimingReq
后接收到false,它必须一直等到它的函数recvReqRetry
被执行。仅仅当这个函数被master调用,才允许重新调用sendTimingReq
。上图仅显示了失败了一次的情况,其实实际上可能会发生数次。注意:必须由master跟踪失败的packet而不是slave(slave不保存失败的packet的对应指针)。
同样,master忙碌时,下图显示了这种情况,slave直到接收到recvRespRetry
后才能调用sendTimingResp
:
3.4 简单的内存对象例子
这个简单的对象仅仅在CPU端和内存端之间实现请求的传送。下一章节添加逻辑让它成为一个cache。
下图就是这样的一个简单的memory object所在的系统结构图:
1.声明SimObject
就像我们之前创建一个简单的SimObject一样。第一步就是创建一个SimObject的Python文件。我们将会调用这个内存对象并且创建这样的python文件SimpleMemobj.py
在src/learning_gem5/simple_memobj
下。
from m5.params import *
from m5.proxy import *
from MemObject import MemObject
class SimpleMemobj(MemObject):
type = 'SimpleMemobj'
cxx_header = "learning_gem5/simple_memobj/simple_memobj.hh"
inst_port = SlavePort("CPU side port, receives requests")
data_port = SlavePort("CPU side port, receives requests")
mem_side = MasterPort("Memory side port, sends requests")
对于这个对象,我们要从MemObject
继承,但是不能从SimObject
对象继承。因为我们在创建一个和内存系统交互的对象。MemObject
类有两个纯粹的虚函数getMasterPort
and getSlavePort
。
这个对象有3个端口,两个端口是和CPU的指令和数据端口连接,还有一个是和memory bus连接。这些端口都没有默认值。
当然别忘了创建SConscript文件并声明这个python文件。
2.定义SimpleMemobj类
现在我们创建一个头文件SimpleMemobj
.