本文章是我学习如何向一个简单的gem5脚本添加缓存时的代码和注释,可与https://blog.csdn.net/luzi0206/article/details/117629255?spm=1001.2014.3001.5501对照阅读。
我是根据http://www.gem5.org/documentation/learning_gem5/part1/cache_config/进行学习的。
下图为体系结构框图:
首先创建与添加的缓存的类,代码为caches.py:
#导入SimObject中caches的类。位于src/mem/Cache/Cache.py中。
from m5.objects import Cache
#对BaseCache进行扩展,建立新的类:L1Cache(1级缓存)、L2Cache(2级缓存)。
class L1Cache(Cache):
#对Cache进行扩展
assoc = 2
tag_latency = 2
data_latency = 2
response_latency = 2
mshrs = 4
tgts_per_mshr = 20
#添加两个函数将缓存与CPU和总线连接
def connectCPU(self,cpu):
#连接至CPU。在后续子类L1ICache和L1DCache中,因为端口不同,需要单独定义。
raise NotImplementedError
def connectBus(self,bus):
#连接至总线
self.mem_side = bus.cpu_side_ports
class L2Cache(Cache):
size = '256kB'
assoc = 8
tag_latency = 20
data_latency = 20
response_latency = 20
mshrs = 20
tgts_per_mshr = 12
def connectCPUSideBus(self,bus):
#连接至CPU端
self.cpu_side = bus.mem_side_ports
def connectMemSideBus(self,bus):
#连接至总线端
self.mem_side = bus.cpu_side_ports
#建立L1Cache的2个子类。
class L1ICache(L1Cache):
size = '16kB'
def connectCPU(self, cpu):
#为指令缓存定义单独的ConnectCPU函数,
self.cpu_side = cpu.icache_port
class L1DCache(L1Cache):
size = '64kB'
def connectCPU(self, cpu):
#为数据缓存定义单独的ConnectCPU函数,
self.cpu_side = cpu.dcache_port
然后创建gem5的脚本,代码为simple2.py:
#导入m5和SimObjects
import m5
from m5.objects import *
#导入编写的caches.py中的caches
from caches import *
#创建要模拟的系统
system = System()
#设置系统时钟。1、建立时钟域,2、设置时钟频率,3、为时钟域指定电压域
system.clk_domain = SrcClockDomain()
system.clk_domain.clock = '1GHz'
system.clk_domain.voltage_domain = VoltageDomain()
#设置系统模拟内存(计时模式),设置内存范围
system.mem_mode = 'timing'
system.mem_ranges = [AddrRange('512MB')]
#创建CPU(基于时间),
system.cpu = TimingSimpleCPU()
#创建L1Cache
system.cpu.icache = L1ICache()
system.cpu.dcache = L1DCache()
#将L1Cache连接至CPU端口,这里是通过L1ICache和L1DCache类中的函数实现的。
system.cpu.icache.connectCPU(system.cpu)
system.cpu.dcache.connectCPU(system.cpu)
#创建系统范围内存总线
system.membus = SystemXBar()
#将CPU上的缓存端口连接到内存总线上。由于没有建立缓存cache,所以将icache和dcache直接连接到menbus
#因为一级缓存连接到了二级缓存上,这里删除以前的这条连线(将缓存端口直接连接到内存总线上)
#system.cpu.icache_port = system.membus.cpu_side_ports
#system.cpu.dcache_port = system.membus.cpu_side_ports
#创建二级总线(不能直接将一级缓存连接到二级缓存),并连接一级缓存和二级缓存
system.l2bus = L2XBar()
system.cpu.icache.connectBus(system.l2bus)
system.cpu.dcache.connectBus(system.l2bus)
#创建二级缓存,连接二级缓存到二级总线和内存总线
system.l2cache = L2Cache()
system.l2cache.connectCPUSideBus(system.l2bus)
system.l2cache.connectMemSideBus(system.membus)
#连接CPU的其他端口以确保系统可以正常工作,例如I/O控制器。
system.cpu.createInterruptController()
#将系统的一个特殊端口连接到menbus,这个端口只允许系统读写内存。
system.system_port = system.membus.cpu_side_ports
#x86的特定要求,将PIO和中断端口连接到内存总线
if m5.defines.buildEnv['TARGET_ISA'] == "x86":
system.cpu.interrupts[0].pio = system.membus.mem_side_ports
system.cpu.interrupts[0].int_requestor = system.membus.cpu_side_ports
system.cpu.interrupts[0].int_responder = system.membus.mem_side_ports
#创建一个内存控制器,并将其连接到内存总线。这里使用的是DDR3控制器,负责内存的范围。
system.mem_ctrl = MemCtrl()
system.mem_ctrl.port = system.membus.mem_side_ports
system.mem_ctrl.dram = DDR3_1600_8x8()
system.mem_ctrl.dram.range = system.mem_ranges[0]
#---------设置CPU执行的进程--------------------#
#这里使用syscall仿真模式
#1、设置可执行文件,2、创建进程,设置进程执行的可执行文件,
# 3、将进程设置为CPU的工作负载,4、在CPU上创建进程(或者说创建执行环境)
binary = 'tests/test-progs/hello/bin/x86/linux/hello'
#对于gem5 v21及更高版本,加入下面一行。
system.workload = SEWorkload.init_compatible(binary)
process = Process()
process.cmd = [binary]
system.cpu.workload = process
system.cpu.createThreads()
#---------实例化系统并执行-------------#
#创建根对象,并实例化模拟
root = Root(full_system = False,system = system)
m5.instantiate()
#开始模拟。这里的print不是语句而是作为一个函数被调用。
print("Beginning simulation")
exit_event = m5.simulate()
#模拟结束后对系统进行检测
print('Exiting @ tick {} because {}'
.format(m5.curTick(),exit_event.getCause()))
测试:
build/X86/gem5.opt configs/simple2.py
结果:
Beginning simulation
info: Entering event queue @ 0. Starting simulation...
Hello world!
Exiting @ tick 56435000 because exiting with last active thread context
在连接时需要考虑端口的选择问题(原本的代码是
memobject1.master = memobject2.slave
这里将端口名改为mem_side_ports、cpu_side_ports)。依据的体系结构来进行选择的,例如L2bus连接L1DataCachel时,因为L1DataCachel相对于L2bus位于CPU侧,所以L1DataCache需要连接L2bus的cpu_side_ports端口,而L2bus相对于L1DataCachel位于menbus侧,所以L2bus需要连接L1DataCachel的的mem_side_ports端口,即CPU侧的mem_side_ports端口需要连接menbus侧的cpu_side_ports端口。