ruby_caches_MI_example.py revision 13774:a1be2a0c55f2
12SN/A# -*- coding: utf-8 -*- 21762SN/A# Copyright (c) 2015 Jason Power 32SN/A# All rights reserved. 42SN/A# 52SN/A# Redistribution and use in source and binary forms, with or without 62SN/A# modification, are permitted provided that the following conditions are 72SN/A# met: redistributions of source code must retain the above copyright 82SN/A# notice, this list of conditions and the following disclaimer; 92SN/A# redistributions in binary form must reproduce the above copyright 102SN/A# notice, this list of conditions and the following disclaimer in the 112SN/A# documentation and/or other materials provided with the distribution; 122SN/A# neither the name of the copyright holders nor the names of its 132SN/A# contributors may be used to endorse or promote products derived from 142SN/A# this software without specific prior written permission. 152SN/A# 162SN/A# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172SN/A# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182SN/A# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192SN/A# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202SN/A# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212SN/A# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222SN/A# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232SN/A# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242SN/A# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252SN/A# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262SN/A# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272665Ssaidi@eecs.umich.edu# 282665Ssaidi@eecs.umich.edu# Authors: Jason Power 292SN/A 302SN/A""" This file creates a set of Ruby caches, the Ruby network, and a simple 312439SN/Apoint-to-point topology. 322984Sgblack@eecs.umich.eduSee Part 3 in the Learning gem5 book: learning.gem5.org/book/part3 33146SN/AYou can change simple_ruby to import from this file instead of from msi_caches 34146SN/Ato use the MI_example protocol instead of MSI. 35146SN/A 36146SN/AIMPORTANT: If you modify this file, it's likely that the Learning gem5 book 37146SN/A also needs to be updated. For now, email Jason <jason@lowepower.com> 38146SN/A 391717SN/A""" 40146SN/A 411717SN/Afrom __future__ import print_function 42146SN/Afrom __future__ import absolute_import 431977SN/A 442623SN/Aimport math 452683Sktlim@umich.edu 461717SN/Afrom m5.defines import buildEnv 47146SN/Afrom m5.util import fatal, panic 482683Sktlim@umich.edu 491917SN/Afrom m5.objects import * 503348Sbinkertn@umich.edu 512683Sktlim@umich.educlass MyCacheSystem(RubySystem): 522036SN/A 53146SN/A def __init__(self): 5456SN/A if buildEnv['PROTOCOL'] != 'MI_example': 5556SN/A fatal("This system assumes MI_example!") 5656SN/A 57695SN/A super(MyCacheSystem, self).__init__() 582901Ssaidi@eecs.umich.edu 592SN/A def setup(self, system, cpus, mem_ctrls): 601858SN/A """Set up the Ruby cache subsystem. Note: This can't be done in the 6156SN/A constructor because many of these items require a pointer to the 622171SN/A ruby system (self). This causes infinite recursion in initialize() 632170SN/A if we do this in the __init__. 642170SN/A """ 65146SN/A # Ruby's global network. 662462SN/A self.network = MyNetwork(self) 67146SN/A 682SN/A # MI example uses 5 virtual networks 692SN/A self.number_of_virtual_networks = 5 702449SN/A self.network.number_of_virtual_networks = 5 711355SN/A 722623SN/A # There is a single global list of all of the controllers to make it 732683Sktlim@umich.edu # easier to connect everything to the global network. This can be 74224SN/A # customized depending on the topology/network requirements. 751858SN/A # Create one controller for each L1 cache (and the cache mem obj.) 762683Sktlim@umich.edu # Create a single directory controller (Really the memory cntrl) 772420SN/A self.controllers = \ 782683Sktlim@umich.edu [L1Cache(system, self, cpu) for cpu in cpus] + \ 792520SN/A [DirController(self, system.mem_ranges, mem_ctrls)] 802420SN/A 812SN/A # Create one sequencer per CPU. In many systems this is more 822683Sktlim@umich.edu # complicated since you have to create sequencers for DMA controllers 832672Sktlim@umich.edu # and other controllers, too. 842683Sktlim@umich.edu self.sequencers = [RubySequencer(version = i, 852SN/A # I/D cache is combined and grab from ctrl 862SN/A icache = self.controllers[i].cacheMemory, 87334SN/A dcache = self.controllers[i].cacheMemory, 88140SN/A clk_domain = self.controllers[i].clk_domain, 89334SN/A ) for i in range(len(cpus))] 902SN/A 912SN/A for i,c in enumerate(self.controllers[0:len(cpus)]): 922SN/A c.sequencer = self.sequencers[i] 932680Sktlim@umich.edu 942SN/A self.num_of_sequencers = len(self.sequencers) 952SN/A 962623SN/A # Create the network and connect the controllers. 972SN/A # NOTE: This is quite different if using Garnet! 982SN/A self.network.connectControllers(self.controllers) 992SN/A self.network.setup_buffers() 100180SN/A 1012623SN/A # Set up a proxy port for the system_port. Used for load binaries and 102393SN/A # other functional-only things. 103393SN/A self.sys_port_proxy = RubyPortProxy() 104393SN/A system.system_port = self.sys_port_proxy.slave 105393SN/A 106384SN/A # Connect the cpu's cache, interrupt, and TLB ports to Ruby 107384SN/A for i,cpu in enumerate(cpus): 108393SN/A cpu.icache_port = self.sequencers[i].slave 1092623SN/A cpu.dcache_port = self.sequencers[i].slave 110393SN/A isa = buildEnv['TARGET_ISA'] 111393SN/A if isa == 'x86': 112393SN/A cpu.interrupts[0].pio = self.sequencers[i].master 113393SN/A cpu.interrupts[0].int_master = self.sequencers[i].slave 114384SN/A cpu.interrupts[0].int_slave = self.sequencers[i].master 115189SN/A if isa == 'x86' or isa == 'arm': 116189SN/A cpu.itb.walker.port = self.sequencers[i].slave 1172623SN/A cpu.dtb.walker.port = self.sequencers[i].slave 1182SN/A 119729SN/Aclass L1Cache(L1Cache_Controller): 120334SN/A 1212SN/A _version = 0 1222SN/A @classmethod 1232SN/A def versionCount(cls): 1242SN/A cls._version += 1 # Use count for this particular type 1252SN/A return cls._version - 1 1262SN/A 1272SN/A def __init__(self, system, ruby_system, cpu): 1282SN/A """CPUs are needed to grab the clock domain and system is needed for 1292SN/A the cache block size. 1302SN/A """ 1312SN/A super(L1Cache, self).__init__() 1322SN/A 1331001SN/A self.version = self.versionCount() 1341001SN/A # This is the cache memory object that stores the cache data and tags 1351001SN/A self.cacheMemory = RubyCache(size = '16kB', 1361001SN/A assoc = 8, 1371001SN/A start_index_bit = self.getBlockSizeBits(system)) 1382SN/A self.clk_domain = cpu.clk_domain 1392SN/A self.send_evictions = self.sendEvicts(cpu) 1402SN/A self.ruby_system = ruby_system 1412SN/A self.connectQueues(ruby_system) 1422SN/A 1432SN/A def getBlockSizeBits(self, system): 1442SN/A bits = int(math.log(system.cache_line_size, 2)) 1452SN/A if 2**bits != system.cache_line_size.value: 1462SN/A panic("Cache line size not a power of 2!") 1472SN/A return bits 1482SN/A 1492SN/A def sendEvicts(self, cpu): 1502SN/A """True if the CPU model or ISA requires sending evictions from caches 1512SN/A to the CPU. Two scenarios warrant forwarding evictions to the CPU: 1522SN/A 1. The O3 model must keep the LSQ coherent with the caches 1532SN/A 2. The x86 mwait instruction is built on top of coherence 1542SN/A 3. The local exclusive monitor in ARM systems 1552390SN/A """ 1562390SN/A if type(cpu) is DerivO3CPU or \ 1572390SN/A buildEnv['TARGET_ISA'] in ('x86', 'arm'): 1582390SN/A return True 1592390SN/A return False 1602390SN/A 1612390SN/A def connectQueues(self, ruby_system): 1622390SN/A """Connect all of the queues for this controller. 1632390SN/A """ 1642390SN/A self.mandatoryQueue = MessageBuffer() 1652390SN/A self.requestFromCache = MessageBuffer(ordered = True) 1662390SN/A self.requestFromCache.master = ruby_system.network.slave 167385SN/A self.responseFromCache = MessageBuffer(ordered = True) 1682SN/A self.responseFromCache.master = ruby_system.network.slave 1692SN/A self.forwardToCache = MessageBuffer(ordered = True) 1702SN/A self.forwardToCache.slave = ruby_system.network.master 1712623SN/A self.responseToCache = MessageBuffer(ordered = True) 172334SN/A self.responseToCache.slave = ruby_system.network.master 1732361SN/A 1742623SN/Aclass DirController(Directory_Controller): 175334SN/A 176334SN/A _version = 0 177334SN/A @classmethod 1782623SN/A def versionCount(cls): 1792SN/A cls._version += 1 # Use count for this particular type 180921SN/A return cls._version - 1 1812915Sktlim@umich.edu 1822915Sktlim@umich.edu def __init__(self, ruby_system, ranges, mem_ctrls): 1832683Sktlim@umich.edu """ranges are the memory ranges assigned to this controller. 1842SN/A """ 1852SN/A if len(mem_ctrls) > 1: 1862SN/A panic("This cache system can only be connected to one mem ctrl") 1872623SN/A super(DirController, self).__init__() 1882SN/A self.version = self.versionCount() 189921SN/A self.addr_ranges = ranges 1902915Sktlim@umich.edu self.ruby_system = ruby_system 1912915Sktlim@umich.edu self.directory = RubyDirectoryMemory() 1922SN/A # Connect this directory to the memory side. 1932SN/A self.memory = mem_ctrls[0].port 1942SN/A self.connectQueues(ruby_system) 1952SN/A 1962SN/A def connectQueues(self, ruby_system): 1972SN/A self.requestToDir = MessageBuffer(ordered = True) 1982SN/A self.requestToDir.slave = ruby_system.network.master 199595SN/A self.dmaRequestToDir = MessageBuffer(ordered = True) 2002623SN/A self.dmaRequestToDir.slave = ruby_system.network.master 201595SN/A 2022390SN/A self.responseFromDir = MessageBuffer() 2031080SN/A self.responseFromDir.master = ruby_system.network.slave 2041080SN/A self.dmaResponseFromDir = MessageBuffer(ordered = True) 2051080SN/A self.dmaResponseFromDir.master = ruby_system.network.slave 2061080SN/A self.forwardFromDir = MessageBuffer() 2071080SN/A self.forwardFromDir.master = ruby_system.network.slave 2081080SN/A self.responseFromMemory = MessageBuffer() 2091080SN/A 2101121SN/Aclass MyNetwork(SimpleNetwork): 2112107SN/A """A simple point-to-point network. This doesn't not use garnet. 2121089SN/A """ 2131089SN/A 2141080SN/A def __init__(self, ruby_system): 2151080SN/A super(MyNetwork, self).__init__() 2161080SN/A self.netifs = [] 2171080SN/A self.ruby_system = ruby_system 218595SN/A 2192623SN/A def connectControllers(self, controllers): 2202683Sktlim@umich.edu """Connect all of the controllers to routers and connec the routers 221595SN/A together in a point-to-point network. 2222090SN/A """ 2232683Sktlim@umich.edu # Create one router/switch per controller in the system 2242683Sktlim@umich.edu self.routers = [Switch(router_id = i) for i in range(len(controllers))] 225595SN/A 2262205SN/A # Make a link from each controller to the router. The link goes 2272205SN/A # externally to the network. 2282683Sktlim@umich.edu self.ext_links = [SimpleExtLink(link_id=i, ext_node=c, 2292683Sktlim@umich.edu int_node=self.routers[i]) 230595SN/A for i, c in enumerate(controllers)] 231595SN/A 2322390SN/A # Make an "internal" link (internal to the network) between every pair 2332423SN/A # of routers. 2342390SN/A link_count = 0 235595SN/A self.int_links = [] 236595SN/A for ri in self.routers: 237595SN/A for rj in self.routers: 2382623SN/A if ri == rj: continue # Don't connect a router to itself! 239595SN/A link_count += 1 2402390SN/A self.int_links.append(SimpleIntLink(link_id = link_count, 2411080SN/A src_node = ri, 242595SN/A dst_node = rj)) 2431080SN/A