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