| <!DOCTYPE html> |
| <html> |
| <head> |
| <meta charset="utf-8"> |
| <meta http-equiv="x-ua-compatible" content="ie=edge"> |
| <meta name="viewport" content="width=device-width, initial-scale=1"> |
| |
| <title>gem5</title> |
| |
| <!-- SITE FAVICON --> |
| <link rel="shortcut icon" type="image/gif" href="/assets/img/gem5ColorVert.gif"/> |
| |
| <link rel="canonical" href="http://localhost:4000/cache_config/"> |
| <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,300,700,800,600' rel='stylesheet' type='text/css'> |
| <link href='https://fonts.googleapis.com/css?family=Muli:400,300' rel='stylesheet' type='text/css'> |
| |
| <!-- FAVICON --> |
| <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css"> |
| |
| <!-- BOOTSTRAP --> |
| <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous"> |
| |
| <!-- CUSTOM CSS --> |
| <link rel="stylesheet" href="/css/main.css"> |
| </head> |
| |
| |
| <body> |
| <nav class="navbar navbar-expand-md navbar-light bg-light"> |
| <a class="navbar-brand" href="/"> |
| <img src="/assets/img/gem5ColorLong.gif" alt="gem5" height=45px> |
| </a> |
| <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation"> |
| <span class="navbar-toggler-icon"></span> |
| </button> |
| <div class="collapse navbar-collapse" id="navbarNavDropdown"> |
| <ul class="navbar-nav ml-auto"> |
| <li class="nav-item "> |
| <a class="nav-link" href="/">Home</a> |
| </li> |
| |
| <li class="nav-item dropdown "> |
| <a class="nav-link dropdown-toggle" href="/about" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> |
| About |
| </a> |
| <div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink"> |
| <a class="dropdown-item" href="/about">About</a> |
| <a class="dropdown-item" href="/publications">Publications</a> |
| <a class="dropdown-item" href="/governance">Governance</a> |
| </div> |
| </li> |
| |
| <li class="nav-item dropdown active"> |
| <a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> |
| Documentation |
| </a> |
| <div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink"> |
| <!-- Pull navigation from _data/documentation.yml --> |
| |
| <a class="dropdown-item" href="/introduction">Introduction</a> |
| |
| <a class="dropdown-item" href="/building">Getting Started</a> |
| |
| <a class="dropdown-item" href="/environment">Modifying/Extending</a> |
| |
| <a class="dropdown-item" href="/MSIintro">Modeling Cache Coherence with Ruby</a> |
| |
| </div> |
| </li> |
| |
| <li class="nav-item "> |
| <a class="nav-link" href="/contributing">Contributing</a> |
| </li> |
| |
| <li class="nav-item "> |
| <a class="nav-link" href="/blog">Blog</a> |
| </li> |
| |
| <li class="nav-item "> |
| <a class="nav-link" href="/search">Search</a> |
| </li> |
| </ul> |
| </div> |
| </nav> |
| |
| <main> |
| <div class="sidenav-top"> |
| <a href="/"><img src="/assets/img/gem5ColorLong.gif" height="80"></a> |
| <div class="search"> |
| <form action="/search" method="get"> |
| <!-- <label for="search-box"><i class="fa fa-search"></i></label> --> |
| <input type="text" name="query"> |
| <button type="submit" name="submit"><i class="fa fa-search"></i></button> |
| </form> |
| </div> |
| </div> |
| <div class="sidenav"> |
| <!-- Pull navigation from _data/documentation.yml --> |
| |
| <a class="item" href="/introduction" role="button" aria-expanded="false" aria-controls="collapseExample"> |
| Introduction |
| </a> |
| <div class="collapse " id="introduction"> |
| |
| </div> |
| |
| <a class="item" data-toggle="collapse" href="#pt1" role="button" aria-expanded="false" aria-controls="collapseExample"> |
| Getting Started |
| </a> |
| <div class="collapse show" id="pt1"> |
| |
| <a class="subitem " href="/building">Building gem5</a> |
| |
| <a class="subitem " href="/simple_config">Creating a simple configuration script</a> |
| |
| <a class="subitem active" href="/cache_config">Adding cache to configuration script</a> |
| |
| <a class="subitem " href="/gem5_stats">Understanding gem5 statistics and output</a> |
| |
| <a class="subitem " href="/example_configs">Using the default configuration scripts</a> |
| |
| </div> |
| |
| <a class="item" data-toggle="collapse" href="#pt2" role="button" aria-expanded="false" aria-controls="collapseExample"> |
| Modifying/Extending |
| </a> |
| <div class="collapse " id="pt2"> |
| |
| <a class="subitem " href="/environment">Setting up your development environment</a> |
| |
| <a class="subitem " href="/helloobject">Creating a very simple SimObject</a> |
| |
| <a class="subitem " href="/debugging">Debugging gem5</a> |
| |
| <a class="subitem " href="/events">Event-driven programming</a> |
| |
| <a class="subitem " href="/parameters">Adding parameters to SimObjects and more events</a> |
| |
| <a class="subitem " href="/memoryobject">Creating SimObjects in the memory system</a> |
| |
| <a class="subitem " href="/simplecache">Creating a simple cache object</a> |
| |
| </div> |
| |
| <a class="item" data-toggle="collapse" href="#pt3" role="button" aria-expanded="false" aria-controls="collapseExample"> |
| Modeling Cache Coherence with Ruby |
| </a> |
| <div class="collapse " id="pt3"> |
| |
| <a class="subitem " href="/MSIintro">Introduction to Ruby</a> |
| |
| <a class="subitem " href="/cache-intro">MSI example cache protocol</a> |
| |
| <a class="subitem " href="/cache-declarations">Declaring a state machine</a> |
| |
| <a class="subitem " href="/cache-in-ports">In port code blocks</a> |
| |
| <a class="subitem " href="/cache-actions">Action code blocks</a> |
| |
| <a class="subitem " href="/cache-transitions">Transition code blocks</a> |
| |
| <a class="subitem " href="/directory">MSI Directory implementation</a> |
| |
| <a class="subitem " href="/MSIbuilding">Compiling a SLICC protocol</a> |
| |
| <a class="subitem " href="/configuration">Configuring a simple Ruby system</a> |
| |
| <a class="subitem " href="/running">Running the simple Ruby system</a> |
| |
| <a class="subitem " href="/MSIdebugging">Debugging SLICC Protocols</a> |
| |
| <a class="subitem " href="/simple-MI_example">Configuring for a standard protocol</a> |
| |
| </div> |
| |
| </div> |
| |
| <div class="container" id="doc-container"> |
| <div class="edit"><a href="https://github.com/gem5/new-website/tree/master/_pages/documentation/part1/cache_config.md">Edit this page</a></div> |
| <dl> |
| <dt>authors</dt> |
| <dd>Jason Lowe-Power</dd> |
| </dl> |
| |
| <h1 id="adding-cache-to-the-configuration-script">Adding cache to the configuration script</h1> |
| |
| <p>Using the <a href="/simple_config">previous configuration script as a starting point</a>, |
| this chapter will walk through a more complex configuration. We will add |
| a cache hierarchy to the system as shown in |
| the figure below. Additionally, this chapter |
| will cover understanding the gem5 statistics output and adding command |
| line parameters to your scripts.</p> |
| |
| <p><img src="../assets/img/advanced_config.png" alt="A system configuration with a two-level cache |
| hierarchy." /></p> |
| |
| <h2 id="creating-cache-objects">Creating cache objects</h2> |
| |
| <p>We are going to use the classic caches, instead of ruby-intro-chapter, |
| since we are modeling a single CPU system and we don’t care about |
| modeling cache coherence. We will extend the Cache SimObject and |
| configure it for our system. First, we must understand the parameters |
| that are used to configure Cache objects.</p> |
| |
| <blockquote> |
| <p><strong>Classic caches and Ruby</strong></p> |
| |
| <p>gem5 currently has two completely distinct subsystems to model the |
| on-chip caches in a system, the “Classic caches” and “Ruby”. The |
| historical reason for this is that gem5 is a combination of m5 from |
| Michigan and GEMS from Wisconsin. GEMS used Ruby as its cache model, |
| whereas the classic caches came from the m5 codebase (hence |
| “classic”). The difference between these two models is that Ruby is |
| designed to model cache coherence in detail. Part of Ruby is SLICC, a |
| language for defining cache coherence protocols. On the other hand, |
| the classic caches implement a simplified and inflexible MOESI |
| coherence protocol.</p> |
| |
| <p>To choose which model to use, you should ask yourself what you are |
| trying to model. If you are modeling changes to the cache coherence |
| protocol or the coherence protocol could have a first-order impact on |
| your results, use Ruby. Otherwise, if the coherence protocol isn’t |
| important to you, use the classic caches.</p> |
| |
| <p>A long-term goal of gem5 is to unify these to cache models into a |
| single holistic model.</p> |
| </blockquote> |
| |
| <h3 id="cache">Cache</h3> |
| |
| <p>The Cache SimObject declaration can be found in src/mem/cache/Cache.py. |
| This Python file defines the parameters which you can set of the |
| SimObject. Under the hood, when the SimObject is instantiated these |
| parameters are passed to the C++ implementation of the object. The |
| <code class="highlighter-rouge">Cache</code> SimObject inherits from the <code class="highlighter-rouge">BaseCache</code> object shown below.</p> |
| |
| <p>Within the <code class="highlighter-rouge">BaseCache</code> class, there are a number of <em>parameters</em>. For |
| instance, <code class="highlighter-rouge">assoc</code> is an integer parameter. Some parameters, like |
| <code class="highlighter-rouge">write_buffers</code> have a default value, 8 in this case. The default |
| parameter is the first argument to <code class="highlighter-rouge">Param.*</code>, unless the first argument |
| is a string. The string argument of each of the parameters is a |
| description of what the parameter is (e.g., |
| <code class="highlighter-rouge">tag_latency = Param.Cycles("Tag lookup latency")</code> means that the |
| <code class="highlighter-rouge">`tag_latency</code> controls “The hit latency for this cache”).</p> |
| |
| <p>Many of these parameters do not have defaults, so we are required to set |
| these parameters before calling <code class="highlighter-rouge">m5.instantiate()</code>.</p> |
| |
| <hr /> |
| |
| <p>Now, to create caches with specific parameters, we are first going to |
| create a new file, <code class="highlighter-rouge">caches.py</code>, in the same directory as simple.py, |
| <code class="highlighter-rouge">configs/tutorial</code>. The first step is to import the SimObject(s) we are |
| going to extend in this file.</p> |
| |
| <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>from m5.objects import Cache |
| </code></pre></div></div> |
| |
| <p>Next, we can treat the BaseCache object just like any other Python class |
| and extend it. We can name the new cache anything we want. Let’s start |
| by making an L1 cache.</p> |
| |
| <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class L1Cache(Cache): |
| assoc = 2 |
| tag_latency = 2 |
| data_latency = 2 |
| response_latency = 2 |
| mshrs = 4 |
| tgts_per_mshr = 20 |
| </code></pre></div></div> |
| |
| <p>Here, we are setting some of the parameters of the BaseCache that do not |
| have default values. To see all of the possible configuration options, |
| and to find which are required and which are optional, you have to look |
| at the source code of the SimObject. In this case, we are using |
| BaseCache.</p> |
| |
| <p>We have extended <code class="highlighter-rouge">BaseCache</code> and set most of the parameters that do not |
| have default values in the <code class="highlighter-rouge">BaseCache</code> SimObject. Next, let’s two more |
| sub-classes of L1Cache, an L1DCache and L1ICache</p> |
| |
| <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class L1ICache(L1Cache): |
| size = '16kB' |
| |
| class L1DCache(L1Cache): |
| size = '64kB' |
| </code></pre></div></div> |
| |
| <p>Let’s also create an L2 cache with some reasonable parameters.</p> |
| |
| <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class L2Cache(Cache): |
| size = '256kB' |
| assoc = 8 |
| tag_latency = 20 |
| data_latency = 20 |
| response_latency = 20 |
| mshrs = 20 |
| tgts_per_mshr = 12 |
| </code></pre></div></div> |
| |
| <p>Now that we have specified all of the necessary parameters required for |
| <code class="highlighter-rouge">BaseCache</code>, all we have to do is instantiate our sub-classes and |
| connect the caches to the interconnect. However, connecting lots of |
| objects up to complex interconnects can make configuration files quickly |
| grow and become unreadable. Therefore, let’s first add some helper |
| functions to our sub-classes of <code class="highlighter-rouge">Cache</code>. Remember, these are just Python |
| classes, so we can do anything with them that you can do with a Python |
| class.</p> |
| |
| <p>To the L1 cache let’s add two functions, <code class="highlighter-rouge">connectCPU</code> to connect a CPU |
| to the cache and <code class="highlighter-rouge">connectBus</code> to connect the cache to a bus. We need to |
| add the following code to the <code class="highlighter-rouge">L1Cache</code> class.</p> |
| |
| <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def connectCPU(self, cpu): |
| # need to define this in a base class! |
| raise NotImplementedError |
| |
| def connectBus(self, bus): |
| self.mem_side = bus.slave |
| </code></pre></div></div> |
| |
| <p>Next, we have to define a separate <code class="highlighter-rouge">connectCPU</code> function for the |
| instruction and data caches, since the I-cache and D-cache ports have a |
| different names. Our <code class="highlighter-rouge">L1ICache</code> and <code class="highlighter-rouge">L1DCache</code> classes now become:</p> |
| |
| <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class L1ICache(L1Cache): |
| size = '16kB' |
| |
| def connectCPU(self, cpu): |
| self.cpu_side = cpu.icache_port |
| |
| class L1DCache(L1Cache): |
| size = '64kB' |
| |
| def connectCPU(self, cpu): |
| self.cpu_side = cpu.dcache_port |
| </code></pre></div></div> |
| |
| <p>Finally, let’s add functions to the <code class="highlighter-rouge">L2Cache</code> to connect to the |
| memory-side and CPU-side bus, respectively.</p> |
| |
| <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def connectCPUSideBus(self, bus): |
| self.cpu_side = bus.master |
| |
| def connectMemSideBus(self, bus): |
| self.mem_side = bus.slave |
| </code></pre></div></div> |
| |
| <p>The full file can be found in the gem5 source at |
| <code class="highlighter-rouge">gem5/configs/learning_gem5/part1/caches.py</code>.</p> |
| |
| <h2 id="adding-caches-the-simple-config-file">Adding caches the simple config file</h2> |
| |
| <p>Now, let’s add the caches we just created to the configuration script we |
| created in the last chapter <simple-config-chapter>.</p> |
| |
| <p>First, let’s copy the script to a new name.</p> |
| |
| <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cp simple.py two_level.py |
| </code></pre></div></div> |
| |
| <p>First, we need to import the names from the <code class="highlighter-rouge">caches.py</code> file into the |
| namespace. We can add the following to the top of the file (after the |
| m5.objects import), as you would with any Python source.</p> |
| |
| <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>from caches import * |
| </code></pre></div></div> |
| |
| <p>Now, after creating the CPU, let’s create the L1 caches:</p> |
| |
| <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>system.cpu.icache = L1ICache() |
| system.cpu.dcache = L1DCache() |
| </code></pre></div></div> |
| |
| <p>And connect the caches to the CPU ports with the helper function we |
| created.</p> |
| |
| <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>system.cpu.icache.connectCPU(system.cpu) |
| system.cpu.dcache.connectCPU(system.cpu) |
| </code></pre></div></div> |
| |
| <p>Also, You need to <em>remove</em> the previous lines which connected the cache |
| ports directly to the memory bus.</p> |
| |
| <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>-system.cpu.icache_port = system.membus.slave |
| -system.cpu.dcache_port = system.membus.slave |
| </code></pre></div></div> |
| |
| <p>We can’t directly connect the L1 caches to the L2 cache since the L2 |
| cache only expects a single port to connect to it. Therefore, we need to |
| create an L2 bus to connect our L1 caches to the L2 cache. The, we can |
| use our helper function to connect the L1 caches to the L2 bus.</p> |
| |
| <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>system.l2bus = L2XBar() |
| |
| system.cpu.icache.connectBus(system.l2bus) |
| system.cpu.dcache.connectBus(system.l2bus) |
| </code></pre></div></div> |
| |
| <p>Next, we can create out L2 cache and connect it to the L2 bus and the |
| memory bus.</p> |
| |
| <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>system.l2cache = L2Cache() |
| system.l2cache.connectCPUSideBus(system.l2bus) |
| |
| system.l2cache.connectMemSideBus(system.membus) |
| </code></pre></div></div> |
| |
| <p>Everything else in the file stays the same! Now we have a complete |
| configuration with a two-level cache hierarchy. If you run the current |
| file, <code class="highlighter-rouge">hello</code> should now finish in 58513000 ticks. The full script can |
| be found in the gem5 source at |
| <code class="highlighter-rouge">gem5/configs/learning_gem5/part1/two_level.py</code>.</p> |
| |
| <h2 id="adding-parameters-to-your-script">Adding parameters to your script</h2> |
| |
| <p>When performing experiments with gem5, you don’t want to edit your |
| configuration script every time you want to test the system with |
| different parameters. To get around this, you can add command-line |
| parameters to your gem5 configuration script. Again, because the |
| configuration script is just Python, you can use the Python libraries |
| that support argument parsing. Although :pyoptparse is officially |
| deprecated, many of the configuration scripts that ship with gem5 use it |
| instead of pyargparse since gem5’s minimum Python version used to be |
| 2.5. The minimum Python version is now 2.7, so pyargparse is a better |
| option when writing new scripts that don’t need to interact with the |
| current gem5 scripts. To get started using :pyoptparse, you can consult |
| the online Python documentation.</p> |
| |
| <p>To add options to our two-level cache configuration, after importing our |
| caches, let’s add some options.</p> |
| |
| <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>from optparse import OptionParser |
| |
| parser = OptionParser() |
| parser.add_option('--l1i_size', help="L1 instruction cache size") |
| parser.add_option('--l1d_size', help="L1 data cache size") |
| parser.add_option('--l2_size', help="Unified L2 cache size") |
| |
| (options, args) = parser.parse_args() |
| </code></pre></div></div> |
| |
| <p>Now, you can run |
| <code class="highlighter-rouge">build/X86/gem5.opt configs/tutorial/two_level_opts.py --help</code> which |
| will display the options you just added.</p> |
| |
| <p>Next, we need to pass these options onto the caches that we create in |
| the configuration script. To do this, we’ll simply change two_level.py |
| to pass the options into the caches as a parameter to their constructor |
| and add an appropriate constructor, next.</p> |
| |
| <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>system.cpu.icache = L1ICache(options) |
| system.cpu.dcache = L1DCache(options) |
| ... |
| system.l2cache = L2Cache(options) |
| </code></pre></div></div> |
| |
| <p>In caches.py, we need to add constructors (<code class="highlighter-rouge">__init__</code> functions in |
| Python) to each of our classes. Starting with our base L1 cache, we’ll |
| just add an empty constructor since we don’t have any parameters which |
| apply to the base L1 cache. However, we can’t forget to call the super |
| class’s constructor in this case. If the call to the super class |
| constructor is skipped, gem5’s SimObject attribute finding function will |
| fail and the result will be |
| “<code class="highlighter-rouge">RuntimeError: maximum recursion depth exceeded</code>” when you try to |
| instantiate the cache object. So, in <code class="highlighter-rouge">L1Cache</code> we need to add the |
| following after the static class members.</p> |
| |
| <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def __init__(self, options=None): |
| super(L1Cache, self).__init__() |
| pass |
| </code></pre></div></div> |
| |
| <p>Next, in the <code class="highlighter-rouge">L1ICache</code>, we need to use the option that we created |
| (<code class="highlighter-rouge">l1i_size</code>) to set the size. In the following code, there is guards for |
| if <code class="highlighter-rouge">options</code> is not passed to the <code class="highlighter-rouge">L1ICache</code> constructor and if no |
| option was specified on the command line. In these cases, we’ll just use |
| the default we’ve already specified for the size.</p> |
| |
| <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def __init__(self, options=None): |
| super(L1ICache, self).__init__(options) |
| if not options or not options.l1i_size: |
| return |
| self.size = options.l1i_size |
| </code></pre></div></div> |
| |
| <p>We can use the same code for the <code class="highlighter-rouge">L1DCache</code>:</p> |
| |
| <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def __init__(self, options=None): |
| super(L1DCache, self).__init__(options) |
| if not options or not options.l1d_size: |
| return |
| self.size = options.l1d_size |
| </code></pre></div></div> |
| |
| <p>And the unified <code class="highlighter-rouge">L2Cache</code>:</p> |
| |
| <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def __init__(self, options=None): |
| super(L2Cache, self).__init__() |
| if not options or not options.l2_size: |
| return |
| self.size = options.l2_size |
| </code></pre></div></div> |
| |
| <p>With these changes, you can now pass the cache sizes into your script |
| from the command line like below.</p> |
| |
| <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>build/X86/gem5.opt configs/tutorial/two_level_opts.py --l2_size='1MB' --l1d_size='128kB' |
| </code></pre></div></div> |
| |
| <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gem5 Simulator System. http://gem5.org |
| gem5 is copyrighted software; use the --copyright option for details. |
| |
| gem5 compiled Sep 6 2015 14:17:02 |
| gem5 started Sep 6 2015 15:06:51 |
| gem5 executing on galapagos-09.cs.wisc.edu |
| command line: build/X86/gem5.opt ../tutorial/_static/scripts/part1/two_level_opts.py --l2_size=1MB --l1d_size=128kB |
| |
| Global frequency set at 1000000000000 ticks per second |
| warn: DRAM device capacity (8192 Mbytes) does not match the address range assigned (512 Mbytes) |
| 0: system.remote_gdb.listener: listening for remote gdb #0 on port 7000 |
| Beginning simulation! |
| info: Entering event queue @ 0. Starting simulation... |
| Hello world! |
| Exiting @ tick 56742000 because target called exit() |
| </code></pre></div></div> |
| |
| <p>The full scripts can be found in the gem5 source at |
| <code class="highlighter-rouge">gem5/configs/learning_gem5/part1/caches.py</code> and |
| <code class="highlighter-rouge">gem5/configs/learning_gem5/part1/two_level.py</code>.</p> |
| |
| <br> |
| |
| <!-- RETRIVE PREVIOUS PAGE LINK --> |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| <!-- RETRIEVE NEXT PAGE LINK --> |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| <div class="navbuttons"> |
| |
| <a href="/simple_config"><button type="button" class="btn btn-outline-primary">PREVIOUS</button></a> |
| |
| |
| |
| <a href="/gem5_stats"><button type="button" class="btn btn-outline-primary">NEXT</button></a> |
| |
| </div> |
| </div> |
| |
| </main> |
| |
| |
| <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script> |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script> |
| <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script> |
| |
| <script> |
| // When the user scrolls down 20px from the top of the document, show the button |
| window.onscroll = function() {scrollFunction()}; |
| |
| function scrollFunction() { |
| if (document.body.scrollTop > 100 || document.documentElement.scrollTop > 20) { |
| document.getElementById("myBtn").style.display = "block"; |
| } else { |
| document.getElementById("myBtn").style.display = "none"; |
| } |
| } |
| |
| // When the user clicks on the button, scroll to the top of the document |
| function topFunction() { |
| document.body.scrollTop = 0; |
| document.documentElement.scrollTop = 0; |
| } |
| </script> |
| |
| </body> |
| |
| |
| </html> |