抽象内存对象(MemObject):
Gem5所有的内存对象都继承自MemObject,看过源码可以发现MemObject对象继承于ClockedObject对象,且仅添加了两个纯虚函数getMasterPort(const std::string &name)以及
getSlavePort(const std::string &name),这两个方法分别用来获得主从接口的名称。
端口(port):
端口用来连接不同的内存对象,比如主端口(A类)连接从端口(B类),然后主端口(B类)连接从端口(C类)。主端口用来发送请求,与它连接的从端口接受请求,它们内部会有一对方法来实现请求的发送与接收。比如A类->sendTimingReq(pkt)
以发送数据包,B类->recvTimingReq(pkt)接收。当然还有其他这样的方法对,比如(sendFunctional(Pkt)和recvFunctional(Pkt))。每个内存对象至少拥有一个端口用于与整个系统连接。
连接端口:
连接端口的过程是在Python脚本中配置的,通过类似A.port1 = B.port2的语句就可以将两个内存对象连接起来,需要注意的是Gem5对于例如总线这类可能拥有无限多对端口的对象会维护一个vector port来记录每一对连接到它上面的端口。对于vector port每一对新的连接会添加到vector的末尾,而一般的port会覆盖掉之前的连接。
端口代理:
一共有三种,其中PortProxy
提供方法来写入和读取物理地址。它仅用于在模拟开始之前将数据加载到内存中并更新。SETranslatingPortProxy和
FSTranslatingPortProxy
提供与 PortProxy
相同的方法,但传递给它们的地址是虚拟地址,并进行转换以获得物理地址。
数据包(packet):
数据包用于封装内存系统中两个对象之间的传输,它一般包括以下数据
1.地址。这是将用于将数据包路由到其目标(如果未明确设置目的地)并在目标处处理数据包的地址。它通常源自请求对象的物理地址,但在某些情况下可能源自虚拟地址(例如,在执行地址转换之前访问完全虚拟缓存)。它可能与原始请求地址不同:例如,在缓存未命中时,数据包地址可能是要获取的块的地址,而不是请求地址。
2.The size。大小可能与原始请求的大小不同,如缓存未命中情况。
3.指向正在处理的数据的指针。由dataStatic()
和dataDynamic()
设置,它控制数据包释放时是否释放与数据包关联的数据。如果未通过上述方法之一设置,则分在数据包销毁时释放数据。可以通过调用getPtr()
或getConstPtr()
检索指针。get()
和set()方法
可用于操纵该数据包中的数据。get() 方法执行客机到主机的字节序转换,而 set 方法执行主机到客机的字节序转换。
4.与数据包关联的命令属性列表。
5.一个SenderState
指针,它是一个虚拟基础不透明结构,用于保存与数据包关联的特定发送设备(例如,MSHR)的状态。在数据包的响应中返回指向此状态的指针,以便发送方可以快速查找处理它所需的状态。一个特定的子类将由此派生,以携带特定发送设备的状态。
6.指向请求的指针。