bffd5a0505dc97055164d8150eaf170003b1f8f5
1 # Copyright (c) 2015-2016 ARM Limited
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.
13 # Copyright (c) 2006-2007 The Regents of The University of Michigan
14 # All rights reserved.
16 # Redistribution and use in source and binary forms, with or without
17 # modification, are permitted provided that the following conditions are
18 # met: redistributions of source code must retain the above copyright
19 # notice, this list of conditions and the following disclaimer;
20 # redistributions in binary form must reproduce the above copyright
21 # notice, this list of conditions and the following disclaimer in the
22 # documentation and/or other materials provided with the distribution;
23 # neither the name of the copyright holders nor the names of its
24 # contributors may be used to endorse or promote products derived from
25 # this software without specific prior written permission.
27 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 from __future__
import print_function
40 from __future__
import absolute_import
47 from m5
.objects
import *
49 parser
= optparse
.OptionParser()
51 parser
.add_option("-a", "--atomic", action
="store_true",
52 help="Use atomic (non-timing) mode")
53 parser
.add_option("-b", "--blocking", action
="store_true",
54 help="Use blocking caches")
55 parser
.add_option("-m", "--maxtick", type="int", default
=m5
.MaxTick
,
57 help="Stop after T ticks")
58 parser
.add_option("-p", "--prefetchers", action
="store_true",
59 help="Use prefetchers")
60 parser
.add_option("-s", "--stridepref", action
="store_true",
61 help="Use strided prefetchers")
63 # This example script has a lot in common with the memtest.py in that
64 # it is designed to stress tests the memory system. However, this
65 # script uses oblivious traffic generators to create the stimuli, and
66 # couples them with memcheckers to verify that the data read matches
67 # the allowed outcomes. Just like memtest.py, the traffic generators
68 # and checkers are placed in a tree topology. At the bottom of the
69 # tree is a shared memory, and then at each level a number of
70 # generators and checkers are attached, along with a number of caches
71 # that them selves fan out to subtrees of generators and caches. Thus,
72 # it is possible to create a system with arbitrarily deep cache
73 # hierarchies, sharing or no sharing of caches, and generators not
74 # only at the L1s, but also at the L2s, L3s etc.
76 # The tree specification consists of two colon-separated lists of one
77 # or more integers, one for the caches, and one for the
78 # testers/generators. The first integer is the number of
79 # caches/testers closest to main memory. Each cache then fans out to a
80 # subtree. The last integer in the list is the number of
81 # caches/testers associated with the uppermost level of memory. The
82 # other integers (if any) specify the number of caches/testers
83 # connected at each level of the crossbar hierarchy. The tester string
84 # should have one element more than the cache string as there should
85 # always be testers attached to the uppermost caches.
87 # Since this script tests actual sharing, there is also a possibility
88 # to stress prefetching and the interaction between prefetchers and
89 # caches. The traffic generators switch between random address streams
90 # and linear address streams to ensure that the prefetchers will
91 # trigger. By default prefetchers are off.
93 parser
.add_option("-c", "--caches", type="string", default
="3:2",
94 help="Colon-separated cache hierarchy specification, "
95 "see script comments for details "
96 "[default: %default]")
97 parser
.add_option("-t", "--testers", type="string", default
="1:0:2",
98 help="Colon-separated tester hierarchy specification, "
99 "see script comments for details "
100 "[default: %default]")
101 parser
.add_option("-r", "--random", action
="store_true",
102 help="Generate a random tree topology")
103 parser
.add_option("--sys-clock", action
="store", type="string",
105 help = """Top-level clock for blocks running at system
108 (options
, args
) = parser
.parse_args()
111 print("Error: script doesn't take any positional arguments")
114 # Start by parsing the command line options and do some basic sanity
117 # Generate a tree with a valid number of testers
118 tree_depth
= random
.randint(1, 4)
119 cachespec
= [random
.randint(1, 3) for i
in range(tree_depth
)]
120 testerspec
= [random
.randint(1, 3) for i
in range(tree_depth
+ 1)]
121 print("Generated random tree -c", ':'.join(map(str, cachespec
)),
122 "-t", ':'.join(map(str, testerspec
)))
125 cachespec
= [int(x
) for x
in options
.caches
.split(':')]
126 testerspec
= [int(x
) for x
in options
.testers
.split(':')]
128 print("Error: Unable to parse caches or testers option")
131 if len(cachespec
) < 1:
132 print("Error: Must have at least one level of caches")
135 if len(cachespec
) != len(testerspec
) - 1:
136 print("Error: Testers must have one element more than caches")
139 if testerspec
[-1] == 0:
140 print("Error: Must have testers at the uppermost level")
145 print("Error: Cannot have a negative number of testers")
150 print("Error: Must have 1 or more caches at each level")
153 # Determine the tester multiplier for each level as the string
154 # elements are per subsystem and it fans out
158 print("Error: Must have at least one cache per level")
159 multiplier
.append(multiplier
[-1] * c
)
162 for t
, m
in zip(testerspec
, multiplier
):
165 # Define a prototype L1 cache that we scale for all successive levels
166 proto_l1
= Cache(size
= '32kB', assoc
= 4,
167 tag_latency
= 1, data_latency
= 1, response_latency
= 1,
175 if options
.prefetchers
:
176 proto_l1
.prefetcher
= TaggedPrefetcher()
177 elif options
.stridepref
:
178 proto_l1
.prefetcher
= StridePrefetcher()
180 cache_proto
= [proto_l1
]
182 # Now add additional cache levels (if any) by scaling L1 params, the
183 # first element is Ln, and the last element L1
184 for scale
in cachespec
[:-1]:
185 # Clone previous level and update params
186 prev
= cache_proto
[0]
188 next
.size
= prev
.size
* scale
189 next
.tag_latency
= prev
.tag_latency
* 10
190 next
.data_latency
= prev
.data_latency
* 10
191 next
.response_latency
= prev
.response_latency
* 10
192 next
.assoc
= prev
.assoc
* scale
193 next
.mshrs
= prev
.mshrs
* scale
194 cache_proto
.insert(0, next
)
196 # Create a config to be used by all the traffic generators
197 cfg_file_name
= "memcheck.cfg"
198 cfg_file_path
= os
.path
.dirname(__file__
) + "/" +cfg_file_name
199 cfg_file
= open(cfg_file_path
, 'w')
201 # Three states, with random, linear and idle behaviours. The random
202 # and linear states access memory in the range [0 : 16 Mbyte] with 8
203 # byte and 64 byte accesses respectively.
204 cfg_file
.write("STATE 0 10000000 RANDOM 65 0 16777216 8 50000 150000 0\n")
205 cfg_file
.write("STATE 1 10000000 LINEAR 65 0 16777216 64 50000 150000 0\n")
206 cfg_file
.write("STATE 2 10000000 IDLE\n")
207 cfg_file
.write("INIT 0\n")
208 cfg_file
.write("TRANSITION 0 1 0.5\n")
209 cfg_file
.write("TRANSITION 0 2 0.5\n")
210 cfg_file
.write("TRANSITION 1 0 0.5\n")
211 cfg_file
.write("TRANSITION 1 2 0.5\n")
212 cfg_file
.write("TRANSITION 2 0 0.5\n")
213 cfg_file
.write("TRANSITION 2 1 0.5\n")
216 # Make a prototype for the tester to be used throughout
217 proto_tester
= TrafficGen(config_file
= cfg_file_path
)
219 # Set up the system along with a DRAM controller
220 system
= System(physmem
= MemCtrl(dram
= DDR3_1600_8x8()))
222 system
.voltage_domain
= VoltageDomain(voltage
= '1V')
224 system
.clk_domain
= SrcClockDomain(clock
= options
.sys_clock
,
225 voltage_domain
= system
.voltage_domain
)
227 system
.memchecker
= MemChecker()
229 # For each level, track the next subsys index to use
230 next_subsys_index
= [0] * (len(cachespec
) + 1)
232 # Recursive function to create a sub-tree of the cache and tester
234 def make_cache_level(ncaches
, prototypes
, level
, next_cache
):
235 global next_subsys_index
, proto_l1
, testerspec
, proto_tester
237 index
= next_subsys_index
[level
]
238 next_subsys_index
[level
] += 1
240 # Create a subsystem to contain the crossbar and caches, and
243 setattr(system
, 'l%dsubsys%d' % (level
, index
), subsys
)
245 # The levels are indexing backwards through the list
246 ntesters
= testerspec
[len(cachespec
) - level
]
248 testers
= [proto_tester() for i
in range(ntesters
)]
249 checkers
= [MemCheckerMonitor(memchecker
= system
.memchecker
) \
250 for i
in range(ntesters
)]
252 subsys
.tester
= testers
253 subsys
.checkers
= checkers
256 # Create a crossbar and add it to the subsystem, note that
257 # we do this even with a single element on this level
258 xbar
= L2XBar(width
= 32)
261 xbar
.master
= next_cache
.cpu_side
263 # Create and connect the caches, both the ones fanning out
264 # to create the tree, and the ones used to connect testers
266 tree_caches
= [prototypes
[0]() for i
in range(ncaches
[0])]
267 tester_caches
= [proto_l1() for i
in range(ntesters
)]
269 subsys
.cache
= tester_caches
+ tree_caches
270 for cache
in tree_caches
:
271 cache
.mem_side
= xbar
.slave
272 make_cache_level(ncaches
[1:], prototypes
[1:], level
- 1, cache
)
273 for tester
, checker
, cache
in zip(testers
, checkers
, tester_caches
):
274 tester
.port
= checker
.slave
275 checker
.master
= cache
.cpu_side
276 cache
.mem_side
= xbar
.slave
279 print("Error: No next-level cache at top level")
283 # Create a crossbar and add it to the subsystem
284 xbar
= L2XBar(width
= 32)
286 xbar
.master
= next_cache
.cpu_side
287 for tester
, checker
in zip(testers
, checkers
):
288 tester
.port
= checker
.slave
289 checker
.master
= xbar
.slave
292 testers
[0].port
= checkers
[0].slave
293 checkers
[0].master
= next_cache
.cpu_side
295 # Top level call to create the cache hierarchy, bottom up
296 make_cache_level(cachespec
, cache_proto
, len(cachespec
), None)
298 # Connect the lowest level crossbar to the memory
299 last_subsys
= getattr(system
, 'l%dsubsys0' % len(cachespec
))
300 last_subsys
.xbar
.master
= system
.physmem
.port
301 last_subsys
.xbar
.point_of_coherency
= True
303 root
= Root(full_system
= False, system
= system
)
305 root
.system
.mem_mode
= 'atomic'
307 root
.system
.mem_mode
= 'timing'
309 # The system port is never used in the tester so merely connect it
311 root
.system
.system_port
= last_subsys
.xbar
.slave
313 # Instantiate configuration
316 # Simulate until program terminates
317 exit_event
= m5
.simulate(options
.maxtick
)
319 print('Exiting @ tick', m5
.curTick(), 'because', exit_event
.getCause())