simulate.py revision 4762
14762Snate@binkert.org# Copyright (c) 2005 The Regents of The University of Michigan 24762Snate@binkert.org# All rights reserved. 34762Snate@binkert.org# 44762Snate@binkert.org# Redistribution and use in source and binary forms, with or without 54762Snate@binkert.org# modification, are permitted provided that the following conditions are 64762Snate@binkert.org# met: redistributions of source code must retain the above copyright 74762Snate@binkert.org# notice, this list of conditions and the following disclaimer; 84762Snate@binkert.org# redistributions in binary form must reproduce the above copyright 94762Snate@binkert.org# notice, this list of conditions and the following disclaimer in the 104762Snate@binkert.org# documentation and/or other materials provided with the distribution; 114762Snate@binkert.org# neither the name of the copyright holders nor the names of its 124762Snate@binkert.org# contributors may be used to endorse or promote products derived from 134762Snate@binkert.org# this software without specific prior written permission. 144762Snate@binkert.org# 154762Snate@binkert.org# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 164762Snate@binkert.org# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 174762Snate@binkert.org# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 184762Snate@binkert.org# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 194762Snate@binkert.org# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 204762Snate@binkert.org# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 214762Snate@binkert.org# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 224762Snate@binkert.org# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 234762Snate@binkert.org# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 244762Snate@binkert.org# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 254762Snate@binkert.org# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 264762Snate@binkert.org# 274762Snate@binkert.org# Authors: Nathan Binkert 284762Snate@binkert.org# Steve Reinhardt 294762Snate@binkert.org 304762Snate@binkert.orgimport atexit 314762Snate@binkert.orgimport os 324762Snate@binkert.orgimport sys 334762Snate@binkert.org 344762Snate@binkert.org# import the SWIG-wrapped main C++ functions 354762Snate@binkert.orgimport internal 364762Snate@binkert.orgfrom main import options 374762Snate@binkert.orgimport SimObject 384762Snate@binkert.orgimport ticks 394762Snate@binkert.org 404762Snate@binkert.org# The final hook to generate .ini files. Called from the user script 414762Snate@binkert.org# once the config is built. 424762Snate@binkert.orgdef instantiate(root): 434762Snate@binkert.org # we need to fix the global frequency 444762Snate@binkert.org ticks.fixGlobalFrequency() 454762Snate@binkert.org 464762Snate@binkert.org root.unproxy_all() 474762Snate@binkert.org # ugly temporary hack to get output to config.ini 484762Snate@binkert.org sys.stdout = file(os.path.join(options.outdir, 'config.ini'), 'w') 494762Snate@binkert.org root.print_ini() 504762Snate@binkert.org sys.stdout.close() # close config.ini 514762Snate@binkert.org sys.stdout = sys.__stdout__ # restore to original 524762Snate@binkert.org 534762Snate@binkert.org # Initialize the global statistics 544762Snate@binkert.org internal.stats.initSimStats() 554762Snate@binkert.org 564762Snate@binkert.org # Create the C++ sim objects and connect ports 574762Snate@binkert.org root.createCCObject() 584762Snate@binkert.org root.connectPorts() 594762Snate@binkert.org 604762Snate@binkert.org # Do a second pass to finish initializing the sim objects 614762Snate@binkert.org internal.sim_object.initAll() 624762Snate@binkert.org 634762Snate@binkert.org # Do a third pass to initialize statistics 644762Snate@binkert.org internal.sim_object.regAllStats() 654762Snate@binkert.org 664762Snate@binkert.org # Check to make sure that the stats package is properly initialized 674762Snate@binkert.org internal.stats.check() 684762Snate@binkert.org 694762Snate@binkert.org # Reset to put the stats in a consistent state. 704762Snate@binkert.org internal.stats.reset() 714762Snate@binkert.org 724762Snate@binkert.orgdef doDot(root): 734762Snate@binkert.org dot = pydot.Dot() 744762Snate@binkert.org instance.outputDot(dot) 754762Snate@binkert.org dot.orientation = "portrait" 764762Snate@binkert.org dot.size = "8.5,11" 774762Snate@binkert.org dot.ranksep="equally" 784762Snate@binkert.org dot.rank="samerank" 794762Snate@binkert.org dot.write("config.dot") 804762Snate@binkert.org dot.write_ps("config.ps") 814762Snate@binkert.org 824762Snate@binkert.orgneed_resume = [] 834762Snate@binkert.orgneed_startup = True 844762Snate@binkert.orgdef simulate(*args, **kwargs): 854762Snate@binkert.org global need_resume, need_startup 864762Snate@binkert.org 874762Snate@binkert.org if need_startup: 884762Snate@binkert.org internal.core.SimStartup() 894762Snate@binkert.org need_startup = False 904762Snate@binkert.org 914762Snate@binkert.org for root in need_resume: 924762Snate@binkert.org resume(root) 934762Snate@binkert.org need_resume = [] 944762Snate@binkert.org 954762Snate@binkert.org return internal.event.simulate(*args, **kwargs) 964762Snate@binkert.org 974762Snate@binkert.org# Export curTick to user script. 984762Snate@binkert.orgdef curTick(): 994762Snate@binkert.org return internal.core.cvar.curTick 1004762Snate@binkert.org 1014762Snate@binkert.org# Python exit handlers happen in reverse order. We want to dump stats last. 1024762Snate@binkert.orgatexit.register(internal.stats.dump) 1034762Snate@binkert.org 1044762Snate@binkert.org# register our C++ exit callback function with Python 1054762Snate@binkert.orgatexit.register(internal.core.doExitCleanup) 1064762Snate@binkert.org 1074762Snate@binkert.org# This loops until all objects have been fully drained. 1084762Snate@binkert.orgdef doDrain(root): 1094762Snate@binkert.org all_drained = drain(root) 1104762Snate@binkert.org while (not all_drained): 1114762Snate@binkert.org all_drained = drain(root) 1124762Snate@binkert.org 1134762Snate@binkert.org# Tries to drain all objects. Draining might not be completed unless 1144762Snate@binkert.org# all objects return that they are drained on the first call. This is 1154762Snate@binkert.org# because as objects drain they may cause other objects to no longer 1164762Snate@binkert.org# be drained. 1174762Snate@binkert.orgdef drain(root): 1184762Snate@binkert.org all_drained = False 1194762Snate@binkert.org drain_event = internal.event.createCountedDrain() 1204762Snate@binkert.org unready_objects = root.startDrain(drain_event, True) 1214762Snate@binkert.org # If we've got some objects that can't drain immediately, then simulate 1224762Snate@binkert.org if unready_objects > 0: 1234762Snate@binkert.org drain_event.setCount(unready_objects) 1244762Snate@binkert.org simulate() 1254762Snate@binkert.org else: 1264762Snate@binkert.org all_drained = True 1274762Snate@binkert.org internal.event.cleanupCountedDrain(drain_event) 1284762Snate@binkert.org return all_drained 1294762Snate@binkert.org 1304762Snate@binkert.orgdef resume(root): 1314762Snate@binkert.org root.resume() 1324762Snate@binkert.org 1334762Snate@binkert.orgdef checkpoint(root, dir): 1344762Snate@binkert.org if not isinstance(root, objects.Root): 1354762Snate@binkert.org raise TypeError, "Checkpoint must be called on a root object." 1364762Snate@binkert.org doDrain(root) 1374762Snate@binkert.org print "Writing checkpoint" 1384762Snate@binkert.org internal.sim_object.serializeAll(dir) 1394762Snate@binkert.org resume(root) 1404762Snate@binkert.org 1414762Snate@binkert.orgdef restoreCheckpoint(root, dir): 1424762Snate@binkert.org print "Restoring from checkpoint" 1434762Snate@binkert.org internal.sim_object.unserializeAll(dir) 1444762Snate@binkert.org need_resume.append(root) 1454762Snate@binkert.org 1464762Snate@binkert.orgdef changeToAtomic(system): 1474762Snate@binkert.org if not isinstance(system, (objects.Root, objects.System)): 1484762Snate@binkert.org raise TypeError, "Parameter of type '%s'. Must be type %s or %s." % \ 1494762Snate@binkert.org (type(system), objects.Root, objects.System) 1504762Snate@binkert.org if system.getMemoryMode() != internal.sim_object.SimObject.Atomic: 1514762Snate@binkert.org doDrain(system) 1524762Snate@binkert.org print "Changing memory mode to atomic" 1534762Snate@binkert.org system.changeTiming(internal.sim_object.SimObject.Atomic) 1544762Snate@binkert.org 1554762Snate@binkert.orgdef changeToTiming(system): 1564762Snate@binkert.org if not isinstance(system, (objects.Root, objects.System)): 1574762Snate@binkert.org raise TypeError, "Parameter of type '%s'. Must be type %s or %s." % \ 1584762Snate@binkert.org (type(system), objects.Root, objects.System) 1594762Snate@binkert.org 1604762Snate@binkert.org if system.getMemoryMode() != internal.sim_object.SimObject.Timing: 1614762Snate@binkert.org doDrain(system) 1624762Snate@binkert.org print "Changing memory mode to timing" 1634762Snate@binkert.org system.changeTiming(internal.sim_object.SimObject.Timing) 1644762Snate@binkert.org 1654762Snate@binkert.orgdef switchCpus(cpuList): 1664762Snate@binkert.org print "switching cpus" 1674762Snate@binkert.org if not isinstance(cpuList, list): 1684762Snate@binkert.org raise RuntimeError, "Must pass a list to this function" 1694762Snate@binkert.org for i in cpuList: 1704762Snate@binkert.org if not isinstance(i, tuple): 1714762Snate@binkert.org raise RuntimeError, "List must have tuples of (oldCPU,newCPU)" 1724762Snate@binkert.org 1734762Snate@binkert.org [old_cpus, new_cpus] = zip(*cpuList) 1744762Snate@binkert.org 1754762Snate@binkert.org for cpu in old_cpus: 1764762Snate@binkert.org if not isinstance(cpu, objects.BaseCPU): 1774762Snate@binkert.org raise TypeError, "%s is not of type BaseCPU" % cpu 1784762Snate@binkert.org for cpu in new_cpus: 1794762Snate@binkert.org if not isinstance(cpu, objects.BaseCPU): 1804762Snate@binkert.org raise TypeError, "%s is not of type BaseCPU" % cpu 1814762Snate@binkert.org 1824762Snate@binkert.org # Drain all of the individual CPUs 1834762Snate@binkert.org drain_event = internal.event.createCountedDrain() 1844762Snate@binkert.org unready_cpus = 0 1854762Snate@binkert.org for old_cpu in old_cpus: 1864762Snate@binkert.org unready_cpus += old_cpu.startDrain(drain_event, False) 1874762Snate@binkert.org # If we've got some objects that can't drain immediately, then simulate 1884762Snate@binkert.org if unready_cpus > 0: 1894762Snate@binkert.org drain_event.setCount(unready_cpus) 1904762Snate@binkert.org simulate() 1914762Snate@binkert.org internal.event.cleanupCountedDrain(drain_event) 1924762Snate@binkert.org # Now all of the CPUs are ready to be switched out 1934762Snate@binkert.org for old_cpu in old_cpus: 1944762Snate@binkert.org old_cpu._ccObject.switchOut() 1954762Snate@binkert.org index = 0 1964762Snate@binkert.org for new_cpu in new_cpus: 1974762Snate@binkert.org new_cpu.takeOverFrom(old_cpus[index]) 1984762Snate@binkert.org new_cpu._ccObject.resume() 1994762Snate@binkert.org index += 1 200