2007-07-24 06:51:38 +02:00
|
|
|
# Copyright (c) 2005 The Regents of The University of Michigan
|
2010-08-17 14:49:05 +02:00
|
|
|
# Copyright (c) 2010 Advanced Micro Devices, Inc.
|
2007-07-24 06:51:38 +02:00
|
|
|
# All rights reserved.
|
|
|
|
#
|
|
|
|
# Redistribution and use in source and binary forms, with or without
|
|
|
|
# modification, are permitted provided that the following conditions are
|
|
|
|
# met: redistributions of source code must retain the above copyright
|
|
|
|
# notice, this list of conditions and the following disclaimer;
|
|
|
|
# redistributions in binary form must reproduce the above copyright
|
|
|
|
# notice, this list of conditions and the following disclaimer in the
|
|
|
|
# documentation and/or other materials provided with the distribution;
|
|
|
|
# neither the name of the copyright holders nor the names of its
|
|
|
|
# contributors may be used to endorse or promote products derived from
|
|
|
|
# this software without specific prior written permission.
|
|
|
|
#
|
|
|
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
|
|
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
|
|
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
|
|
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
#
|
|
|
|
# Authors: Nathan Binkert
|
|
|
|
# Steve Reinhardt
|
|
|
|
|
|
|
|
import atexit
|
|
|
|
import os
|
|
|
|
import sys
|
|
|
|
|
|
|
|
# import the SWIG-wrapped main C++ functions
|
|
|
|
import internal
|
2009-03-06 04:09:53 +01:00
|
|
|
import core
|
|
|
|
import stats
|
2007-07-24 06:51:38 +02:00
|
|
|
from main import options
|
|
|
|
import SimObject
|
|
|
|
import ticks
|
2007-08-02 21:03:35 +02:00
|
|
|
import objects
|
2010-08-17 14:06:22 +02:00
|
|
|
from util import fatal
|
2007-07-24 06:51:38 +02:00
|
|
|
|
2009-09-23 00:24:16 +02:00
|
|
|
# define a MaxTick parameter
|
|
|
|
MaxTick = 2**63 - 1
|
|
|
|
|
2007-07-24 06:51:38 +02:00
|
|
|
# The final hook to generate .ini files. Called from the user script
|
|
|
|
# once the config is built.
|
2010-08-17 14:17:06 +02:00
|
|
|
def instantiate(ckpt_dir=None):
|
2010-08-17 14:06:22 +02:00
|
|
|
root = objects.Root.getInstance()
|
|
|
|
|
|
|
|
if not root:
|
|
|
|
fatal("Need to instantiate Root() before calling instantiate()")
|
|
|
|
|
2007-07-24 06:51:38 +02:00
|
|
|
# we need to fix the global frequency
|
|
|
|
ticks.fixGlobalFrequency()
|
|
|
|
|
2010-08-17 14:11:00 +02:00
|
|
|
# Make sure SimObject-valued params are in the configuration
|
|
|
|
# hierarchy so we catch them with future descendants() walks
|
|
|
|
for obj in root.descendants(): obj.adoptOrphanParams()
|
|
|
|
|
2010-08-17 14:08:50 +02:00
|
|
|
# Unproxy in sorted order for determinism
|
|
|
|
for obj in root.descendants(): obj.unproxyParams()
|
2007-08-30 21:16:59 +02:00
|
|
|
|
2008-12-08 16:16:40 +01:00
|
|
|
if options.dump_config:
|
|
|
|
ini_file = file(os.path.join(options.outdir, options.dump_config), 'w')
|
2010-08-17 14:08:50 +02:00
|
|
|
# Print ini sections in sorted order for easier diffing
|
|
|
|
for obj in sorted(root.descendants(), key=lambda o: o.path()):
|
|
|
|
obj.print_ini(ini_file)
|
2008-12-08 16:16:40 +01:00
|
|
|
ini_file.close()
|
2007-07-24 06:51:38 +02:00
|
|
|
|
|
|
|
# Initialize the global statistics
|
2009-03-06 04:09:53 +01:00
|
|
|
stats.initSimStats()
|
2007-07-24 06:51:38 +02:00
|
|
|
|
|
|
|
# Create the C++ sim objects and connect ports
|
2010-08-17 14:08:50 +02:00
|
|
|
for obj in root.descendants(): obj.createCCObject()
|
|
|
|
for obj in root.descendants(): obj.connectPorts()
|
2007-07-24 06:51:38 +02:00
|
|
|
|
|
|
|
# Do a second pass to finish initializing the sim objects
|
2010-08-17 14:08:50 +02:00
|
|
|
for obj in root.descendants(): obj.init()
|
2007-07-24 06:51:38 +02:00
|
|
|
|
|
|
|
# Do a third pass to initialize statistics
|
2010-08-17 14:08:50 +02:00
|
|
|
for obj in root.descendants(): obj.regStats()
|
|
|
|
for obj in root.descendants(): obj.regFormulas()
|
2007-07-24 06:51:38 +02:00
|
|
|
|
2009-03-06 04:09:53 +01:00
|
|
|
# We're done registering statistics. Enable the stats package now.
|
|
|
|
stats.enable()
|
2007-07-24 06:51:38 +02:00
|
|
|
|
2010-08-17 14:17:06 +02:00
|
|
|
# Restore checkpoint (if any)
|
|
|
|
if ckpt_dir:
|
2010-08-17 14:17:06 +02:00
|
|
|
ckpt = internal.core.getCheckpoint(ckpt_dir)
|
|
|
|
internal.core.unserializeGlobals(ckpt);
|
|
|
|
for obj in root.descendants(): obj.loadState(ckpt)
|
2010-08-17 14:17:06 +02:00
|
|
|
need_resume.append(root)
|
2010-08-17 14:17:06 +02:00
|
|
|
else:
|
|
|
|
for obj in root.descendants(): obj.initState()
|
2010-08-17 14:17:06 +02:00
|
|
|
|
2007-07-24 06:51:38 +02:00
|
|
|
# Reset to put the stats in a consistent state.
|
2009-03-06 04:09:53 +01:00
|
|
|
stats.reset()
|
2007-07-24 06:51:38 +02:00
|
|
|
|
|
|
|
def doDot(root):
|
|
|
|
dot = pydot.Dot()
|
|
|
|
instance.outputDot(dot)
|
|
|
|
dot.orientation = "portrait"
|
|
|
|
dot.size = "8.5,11"
|
|
|
|
dot.ranksep="equally"
|
|
|
|
dot.rank="samerank"
|
|
|
|
dot.write("config.dot")
|
|
|
|
dot.write_ps("config.ps")
|
|
|
|
|
|
|
|
need_resume = []
|
|
|
|
need_startup = True
|
|
|
|
def simulate(*args, **kwargs):
|
|
|
|
global need_resume, need_startup
|
|
|
|
|
|
|
|
if need_startup:
|
2010-08-17 14:08:50 +02:00
|
|
|
root = objects.Root.getInstance()
|
|
|
|
for obj in root.descendants(): obj.startup()
|
2007-07-24 06:51:38 +02:00
|
|
|
need_startup = False
|
|
|
|
|
|
|
|
for root in need_resume:
|
|
|
|
resume(root)
|
|
|
|
need_resume = []
|
|
|
|
|
|
|
|
return internal.event.simulate(*args, **kwargs)
|
|
|
|
|
|
|
|
# Export curTick to user script.
|
|
|
|
def curTick():
|
|
|
|
return internal.core.cvar.curTick
|
|
|
|
|
|
|
|
# Python exit handlers happen in reverse order. We want to dump stats last.
|
|
|
|
atexit.register(internal.stats.dump)
|
|
|
|
|
|
|
|
# register our C++ exit callback function with Python
|
|
|
|
atexit.register(internal.core.doExitCleanup)
|
|
|
|
|
|
|
|
# This loops until all objects have been fully drained.
|
|
|
|
def doDrain(root):
|
|
|
|
all_drained = drain(root)
|
|
|
|
while (not all_drained):
|
|
|
|
all_drained = drain(root)
|
|
|
|
|
|
|
|
# Tries to drain all objects. Draining might not be completed unless
|
|
|
|
# all objects return that they are drained on the first call. This is
|
|
|
|
# because as objects drain they may cause other objects to no longer
|
|
|
|
# be drained.
|
|
|
|
def drain(root):
|
|
|
|
all_drained = False
|
|
|
|
drain_event = internal.event.createCountedDrain()
|
2010-08-17 14:08:50 +02:00
|
|
|
unready_objs = sum(obj.drain(drain_event) for obj in root.descendants())
|
2007-07-24 06:51:38 +02:00
|
|
|
# If we've got some objects that can't drain immediately, then simulate
|
2010-08-17 14:08:50 +02:00
|
|
|
if unready_objs > 0:
|
|
|
|
drain_event.setCount(unready_objs)
|
2007-07-24 06:51:38 +02:00
|
|
|
simulate()
|
|
|
|
else:
|
|
|
|
all_drained = True
|
|
|
|
internal.event.cleanupCountedDrain(drain_event)
|
|
|
|
return all_drained
|
|
|
|
|
|
|
|
def resume(root):
|
2010-08-17 14:08:50 +02:00
|
|
|
for obj in root.descendants(): obj.resume()
|
2007-07-24 06:51:38 +02:00
|
|
|
|
2010-08-17 14:06:22 +02:00
|
|
|
def checkpoint(dir):
|
|
|
|
root = objects.Root.getInstance()
|
2007-07-24 06:51:38 +02:00
|
|
|
if not isinstance(root, objects.Root):
|
|
|
|
raise TypeError, "Checkpoint must be called on a root object."
|
|
|
|
doDrain(root)
|
|
|
|
print "Writing checkpoint"
|
2007-08-03 07:50:02 +02:00
|
|
|
internal.core.serializeAll(dir)
|
2007-07-24 06:51:38 +02:00
|
|
|
resume(root)
|
|
|
|
|
|
|
|
def changeToAtomic(system):
|
|
|
|
if not isinstance(system, (objects.Root, objects.System)):
|
|
|
|
raise TypeError, "Parameter of type '%s'. Must be type %s or %s." % \
|
|
|
|
(type(system), objects.Root, objects.System)
|
2007-08-05 01:06:19 +02:00
|
|
|
if system.getMemoryMode() != objects.params.atomic:
|
2007-07-24 06:51:38 +02:00
|
|
|
doDrain(system)
|
|
|
|
print "Changing memory mode to atomic"
|
2010-08-17 14:08:50 +02:00
|
|
|
for obj in system.descendants():
|
|
|
|
obj.changeTiming(objects.params.atomic)
|
2007-07-24 06:51:38 +02:00
|
|
|
|
|
|
|
def changeToTiming(system):
|
|
|
|
if not isinstance(system, (objects.Root, objects.System)):
|
|
|
|
raise TypeError, "Parameter of type '%s'. Must be type %s or %s." % \
|
|
|
|
(type(system), objects.Root, objects.System)
|
|
|
|
|
2007-08-05 01:06:19 +02:00
|
|
|
if system.getMemoryMode() != objects.params.timing:
|
2007-07-24 06:51:38 +02:00
|
|
|
doDrain(system)
|
|
|
|
print "Changing memory mode to timing"
|
2010-08-17 14:08:50 +02:00
|
|
|
for obj in system.descendants():
|
|
|
|
obj.changeTiming(objects.params.timing)
|
2007-07-24 06:51:38 +02:00
|
|
|
|
|
|
|
def switchCpus(cpuList):
|
|
|
|
print "switching cpus"
|
|
|
|
if not isinstance(cpuList, list):
|
|
|
|
raise RuntimeError, "Must pass a list to this function"
|
2007-08-05 01:09:24 +02:00
|
|
|
for item in cpuList:
|
|
|
|
if not isinstance(item, tuple) or len(item) != 2:
|
2007-07-24 06:51:38 +02:00
|
|
|
raise RuntimeError, "List must have tuples of (oldCPU,newCPU)"
|
|
|
|
|
2007-08-05 01:09:24 +02:00
|
|
|
for old_cpu, new_cpu in cpuList:
|
|
|
|
if not isinstance(old_cpu, objects.BaseCPU):
|
|
|
|
raise TypeError, "%s is not of type BaseCPU" % old_cpu
|
|
|
|
if not isinstance(new_cpu, objects.BaseCPU):
|
|
|
|
raise TypeError, "%s is not of type BaseCPU" % new_cpu
|
2007-07-24 06:51:38 +02:00
|
|
|
|
|
|
|
# Now all of the CPUs are ready to be switched out
|
2007-08-05 01:09:24 +02:00
|
|
|
for old_cpu, new_cpu in cpuList:
|
2007-07-24 06:51:38 +02:00
|
|
|
old_cpu._ccObject.switchOut()
|
2007-08-05 01:09:24 +02:00
|
|
|
|
|
|
|
for old_cpu, new_cpu in cpuList:
|
|
|
|
new_cpu.takeOverFrom(old_cpu)
|
2008-08-04 03:19:55 +02:00
|
|
|
|
|
|
|
from internal.core import disableAllListeners
|