8b1dbd2a0f05101b4d6a1f497f95852de062ee86
[gem5.git] / configs / example / arm / starter_se.py
1 # Copyright (c) 2016-2017 ARM Limited
2 # All rights reserved.
3 #
4 # The license below extends only to copyright in the software and shall
5 # not be construed as granting a license to any other intellectual
6 # property including but not limited to intellectual property relating
7 # to a hardware implementation of the functionality of the software
8 # licensed hereunder. You may use the software subject to the license
9 # terms below provided that you ensure that this notice is replicated
10 # unmodified and in its entirety in all distributions of the software,
11 # modified or unmodified, in source code or in binary form.
12 #
13 # Redistribution and use in source and binary forms, with or without
14 # modification, are permitted provided that the following conditions are
15 # met: redistributions of source code must retain the above copyright
16 # notice, this list of conditions and the following disclaimer;
17 # redistributions in binary form must reproduce the above copyright
18 # notice, this list of conditions and the following disclaimer in the
19 # documentation and/or other materials provided with the distribution;
20 # neither the name of the copyright holders nor the names of its
21 # contributors may be used to endorse or promote products derived from
22 # this software without specific prior written permission.
23 #
24 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35
36 """This script is the syscall emulation example script from the ARM
37 Research Starter Kit on System Modeling. More information can be found
38 at: http://www.arm.com/ResearchEnablement/SystemModeling
39 """
40
41 from __future__ import print_function
42 from __future__ import absolute_import
43
44 import os
45 import m5
46 from m5.util import addToPath
47 from m5.objects import *
48 import argparse
49 import shlex
50
51 m5.util.addToPath('../..')
52
53 from common import ObjectList
54 from common import MemConfig
55 from common.cores.arm import HPI
56
57 import devices
58
59
60
61 # Pre-defined CPU configurations. Each tuple must be ordered as : (cpu_class,
62 # l1_icache_class, l1_dcache_class, walk_cache_class, l2_Cache_class). Any of
63 # the cache class may be 'None' if the particular cache is not present.
64 cpu_types = {
65 "atomic" : ( AtomicSimpleCPU, None, None, None, None),
66 "minor" : (MinorCPU,
67 devices.L1I, devices.L1D,
68 devices.WalkCache,
69 devices.L2),
70 "hpi" : ( HPI.HPI,
71 HPI.HPI_ICache, HPI.HPI_DCache,
72 HPI.HPI_WalkCache,
73 HPI.HPI_L2)
74 }
75
76
77 class SimpleSeSystem(System):
78 '''
79 Example system class for syscall emulation mode
80 '''
81
82 # Use a fixed cache line size of 64 bytes
83 cache_line_size = 64
84
85 def __init__(self, args, **kwargs):
86 super(SimpleSeSystem, self).__init__(**kwargs)
87
88 # Setup book keeping to be able to use CpuClusters from the
89 # devices module.
90 self._clusters = []
91 self._num_cpus = 0
92
93 # Create a voltage and clock domain for system components
94 self.voltage_domain = VoltageDomain(voltage="3.3V")
95 self.clk_domain = SrcClockDomain(clock="1GHz",
96 voltage_domain=self.voltage_domain)
97
98 # Create the off-chip memory bus.
99 self.membus = SystemXBar()
100
101 # Wire up the system port that gem5 uses to load the kernel
102 # and to perform debug accesses.
103 self.system_port = self.membus.slave
104
105
106 # Add CPUs to the system. A cluster of CPUs typically have
107 # private L1 caches and a shared L2 cache.
108 self.cpu_cluster = devices.CpuCluster(self,
109 args.num_cores,
110 args.cpu_freq, "1.2V",
111 *cpu_types[args.cpu])
112
113 # Create a cache hierarchy (unless we are simulating a
114 # functional CPU in atomic memory mode) for the CPU cluster
115 # and connect it to the shared memory bus.
116 if self.cpu_cluster.memoryMode() == "timing":
117 self.cpu_cluster.addL1()
118 self.cpu_cluster.addL2(self.cpu_cluster.clk_domain)
119 self.cpu_cluster.connectMemSide(self.membus)
120
121 # Tell gem5 about the memory mode used by the CPUs we are
122 # simulating.
123 self.mem_mode = self.cpu_cluster.memoryMode()
124
125 def numCpuClusters(self):
126 return len(self._clusters)
127
128 def addCpuCluster(self, cpu_cluster, num_cpus):
129 assert cpu_cluster not in self._clusters
130 assert num_cpus > 0
131 self._clusters.append(cpu_cluster)
132 self._num_cpus += num_cpus
133
134 def numCpus(self):
135 return self._num_cpus
136
137 def get_processes(cmd):
138 """Interprets commands to run and returns a list of processes"""
139
140 cwd = os.getcwd()
141 multiprocesses = []
142 for idx, c in enumerate(cmd):
143 argv = shlex.split(c)
144
145 process = Process(pid=100 + idx, cwd=cwd, cmd=argv, executable=argv[0])
146
147 print("info: %d. command and arguments: %s" % (idx + 1, process.cmd))
148 multiprocesses.append(process)
149
150 return multiprocesses
151
152
153 def create(args):
154 ''' Create and configure the system object. '''
155
156 system = SimpleSeSystem(args)
157
158 # Tell components about the expected physical memory ranges. This
159 # is, for example, used by the MemConfig helper to determine where
160 # to map DRAMs in the physical address space.
161 system.mem_ranges = [ AddrRange(start=0, size=args.mem_size) ]
162
163 # Configure the off-chip memory system.
164 MemConfig.config_mem(args, system)
165
166 # Parse the command line and get a list of Processes instances
167 # that we can pass to gem5.
168 processes = get_processes(args.commands_to_run)
169 if len(processes) != args.num_cores:
170 print("Error: Cannot map %d command(s) onto %d CPU(s)" %
171 (len(processes), args.num_cores))
172 sys.exit(1)
173
174 system.workload = SEWorkload.init_compatible(processes[0].executable)
175
176 # Assign one workload to each CPU
177 for cpu, workload in zip(system.cpu_cluster.cpus, processes):
178 cpu.workload = workload
179
180 return system
181
182
183 def main():
184 parser = argparse.ArgumentParser(epilog=__doc__)
185
186 parser.add_argument("commands_to_run", metavar="command(s)", nargs='*',
187 help="Command(s) to run")
188 parser.add_argument("--cpu", type=str, choices=list(cpu_types.keys()),
189 default="atomic",
190 help="CPU model to use")
191 parser.add_argument("--cpu-freq", type=str, default="4GHz")
192 parser.add_argument("--num-cores", type=int, default=1,
193 help="Number of CPU cores")
194 parser.add_argument("--mem-type", default="DDR3_1600_8x8",
195 choices=ObjectList.mem_list.get_names(),
196 help = "type of memory to use")
197 parser.add_argument("--mem-channels", type=int, default=2,
198 help = "number of memory channels")
199 parser.add_argument("--mem-ranks", type=int, default=None,
200 help = "number of memory ranks per channel")
201 parser.add_argument("--mem-size", action="store", type=str,
202 default="2GB",
203 help="Specify the physical memory size")
204
205 args = parser.parse_args()
206
207 # Create a single root node for gem5's object hierarchy. There can
208 # only exist one root node in the simulator at any given
209 # time. Tell gem5 that we want to use syscall emulation mode
210 # instead of full system mode.
211 root = Root(full_system=False)
212
213 # Populate the root node with a system. A system corresponds to a
214 # single node with shared memory.
215 root.system = create(args)
216
217 # Instantiate the C++ object hierarchy. After this point,
218 # SimObjects can't be instantiated anymore.
219 m5.instantiate()
220
221 # Start the simulator. This gives control to the C++ world and
222 # starts the simulator. The returned event tells the simulation
223 # script why the simulator exited.
224 event = m5.simulate()
225
226 # Print the reason for the simulation exit. Some exit codes are
227 # requests for service (e.g., checkpoints) from the simulation
228 # script. We'll just ignore them here and exit.
229 print(event.getCause(), " @ ", m5.curTick())
230 sys.exit(event.getCode())
231
232
233 if __name__ == "__m5_main__":
234 main()