Move main control from C++ into Python.

User script now invokes initialization and
simulation loop after building configuration.
These functions are exported from C++ to Python
using SWIG.

SConstruct:
    Set up SWIG builder & scanner.
    Set up symlinking of source files into build directory
    (by not disabling the default behavior).
configs/test/test.py:
    Rewrite to use new script-driven interface.
    Include a sample option.
src/SConscript:
    Set up symlinking of source files into build directory
    (by not disabling the default behavior).
    Add SWIG-generated main_wrap.cc to source list.
src/arch/SConscript:
    Set up symlinking of source files into build directory
    (by not disabling the default behavior).
src/arch/alpha/ev5.cc:
src/arch/alpha/isa/decoder.isa:
src/cpu/o3/alpha_cpu_impl.hh:
src/cpu/trace/opt_cpu.cc:
src/cpu/trace/trace_cpu.cc:
src/sim/pseudo_inst.cc:
src/sim/root.cc:
src/sim/serialize.cc:
src/sim/syscall_emul.cc:
    SimExit() is now exitSimLoop().
src/cpu/base.cc:
    SimExitEvent is now SimLoopExitEvent
src/python/SConscript:
    Add SWIG build command for main.i.
    Use python/m5 in build dir as source for zip archive...
    easy now with file duplication enabled.
src/python/m5/__init__.py:
    - Move copyright notice back to C++ so we can print
    it right away, even for interactive sessions.
    - Get rid of argument parsing code; just provide default
    option descriptors for user script to call optparse with.
    - Don't clutter m5 namespace by sucking in all of m5.config
    and m5.objects.
    - Move instantiate() function here from config.py.
src/python/m5/config.py:
    - Move instantiate() function to __init__.py.
    - Param.Foo deferred type lookups must use m5.objects
    namespace now (not m5).
src/python/m5/objects/AlphaConsole.py:
src/python/m5/objects/AlphaFullCPU.py:
src/python/m5/objects/AlphaTLB.py:
src/python/m5/objects/BadDevice.py:
src/python/m5/objects/BaseCPU.py:
src/python/m5/objects/BaseCache.py:
src/python/m5/objects/Bridge.py:
src/python/m5/objects/Bus.py:
src/python/m5/objects/CoherenceProtocol.py:
src/python/m5/objects/Device.py:
src/python/m5/objects/DiskImage.py:
src/python/m5/objects/Ethernet.py:
src/python/m5/objects/Ide.py:
src/python/m5/objects/IntrControl.py:
src/python/m5/objects/MemObject.py:
src/python/m5/objects/MemTest.py:
src/python/m5/objects/Pci.py:
src/python/m5/objects/PhysicalMemory.py:
src/python/m5/objects/Platform.py:
src/python/m5/objects/Process.py:
src/python/m5/objects/Repl.py:
src/python/m5/objects/Root.py:
src/python/m5/objects/SimConsole.py:
src/python/m5/objects/SimpleDisk.py:
src/python/m5/objects/System.py:
src/python/m5/objects/Tsunami.py:
src/python/m5/objects/Uart.py:
    Fix up imports (m5 namespace no longer includes m5.config).
src/sim/eventq.cc:
src/sim/eventq.hh:
    Support for Python-called simulate() function:
    - Use IsExitEvent flag to signal events that want
    to exit the simulation loop gracefully (instead of
    calling exit() to terminate the process).
    - Modify interface to hand exit event object back to
    caller so it can be inspected for cause.
src/sim/host.hh:
    Add MaxTick constant.
src/sim/main.cc:
    Move copyright notice back to C++ so we can print
    it right away, even for interactive sessions.
    Use PYTHONPATH environment var to set module path
    (instead of clunky code injection method).
    Move main control from here into Python:
    - Separate initialization code and simulation loop
    into separate functions callable from Python.
    - Make Python interpreter invocation more pure (more
    like directly invoking interpreter).
    Add -i and -p flags (only options on binary itself;
    other options processed by Python).
    Import readline package when using interactive mode.
src/sim/sim_events.cc:
    SimExitEvent is now SimLoopExitEvent, and uses
    IsSimExit flag to terminate loop (instead of
    exiting simulator process).
src/sim/sim_events.hh:
    SimExitEvent is now SimLoopExitEvent, and uses
    IsSimExit flag to terminate loop (instead of
    exiting simulator process).
    Get rid of a few unused constructors.
src/sim/sim_exit.hh:
    SimExit() is now exitSimLoop().
    Get rid of unused functions.
    Add comments.

--HG--
extra : convert_revision : 280b0d671516b25545a6f24cefa64a68319ff3d4
This commit is contained in:
Steve Reinhardt 2006-06-09 23:01:31 -04:00
parent 5802c46c3b
commit 29e34a739b
51 changed files with 453 additions and 327 deletions

View file

@ -158,6 +158,12 @@ env = Environment(ENV = os.environ, # inherit user's environment vars
env.SConsignFile("sconsign") env.SConsignFile("sconsign")
# Default duplicate option is to use hard links, but this messes up
# when you use emacs to edit a file in the target dir, as emacs moves
# file to file~ then copies to file, breaking the link. Symbolic
# (soft) links work better.
env.SetOption('duplicate', 'soft-copy')
# I waffle on this setting... it does avoid a few painful but # I waffle on this setting... it does avoid a few painful but
# unnecessary builds, but it also seems to make trivial builds take # unnecessary builds, but it also seems to make trivial builds take
# noticeably longer. # noticeably longer.
@ -193,6 +199,19 @@ env.Append(LIBS = py_version_name)
if sys.exec_prefix != '/usr': if sys.exec_prefix != '/usr':
env.Append(LIBPATH = os.path.join(sys.exec_prefix, 'lib')) env.Append(LIBPATH = os.path.join(sys.exec_prefix, 'lib'))
# Set up SWIG flags & scanner
env.Append(SWIGFLAGS=Split('-c++ -python -modern $_CPPINCFLAGS'))
import SCons.Scanner
swig_inc_re = '^[ \t]*[%,#][ \t]*(?:include|import)[ \t]*(<|")([^>"]+)(>|")'
swig_scanner = SCons.Scanner.ClassicCPP("SwigScan", ".i", "CPPPATH",
swig_inc_re)
env.Append(SCANNERS = swig_scanner)
# Other default libraries # Other default libraries
env.Append(LIBS=['z']) env.Append(LIBS=['z'])
@ -468,7 +487,7 @@ for build_path in build_paths:
# to the configured options. It returns a list of environments, # to the configured options. It returns a list of environments,
# one for each variant build (debug, opt, etc.) # one for each variant build (debug, opt, etc.)
envList = SConscript('src/SConscript', build_dir = build_path, envList = SConscript('src/SConscript', build_dir = build_path,
exports = 'env', duplicate = False) exports = 'env')
# Set up the regression tests for each build. # Set up the regression tests for each build.
# for e in envList: # for e in envList:

View file

@ -1,12 +1,40 @@
from m5 import * import os, optparse, sys
import m5
from m5.objects import *
class HelloWorld(AlphaLiveProcess): parser = optparse.OptionParser(option_list=m5.standardOptions)
executable = '../configs/test/hello'
cmd = 'hello' parser.add_option("-t", "--timing", action="store_true")
(options, args) = parser.parse_args()
if args:
print "Error: script doesn't take any positional arguments"
sys.exit(1)
this_dir = os.path.dirname(__file__)
process = AlphaLiveProcess()
process.executable = os.path.join(this_dir, 'hello')
process.cmd = 'hello'
magicbus = Bus() magicbus = Bus()
mem = PhysicalMemory() mem = PhysicalMemory()
cpu = AtomicSimpleCPU(workload=HelloWorld(), mem=magicbus)
if options.timing:
cpu = TimingSimpleCPU()
else:
cpu = AtomicSimpleCPU()
cpu.workload = process
cpu.mem = magicbus
system = System(physmem = mem, cpu = cpu) system = System(physmem = mem, cpu = cpu)
system.c1 = Connector(side_a = mem, side_b = magicbus) system.c1 = Connector(side_a = mem, side_b = magicbus)
root = Root(system = system) root = Root(system = system)
m5.instantiate(root)
exit_event = m5.simulate()
print 'Exiting @', m5.curTick(), 'because', exit_event.getCause()

View file

@ -104,12 +104,12 @@ base_sources = Split('''
sim/eventq.cc sim/eventq.cc
sim/faults.cc sim/faults.cc
sim/main.cc sim/main.cc
python/swig/main_wrap.cc
sim/param.cc sim/param.cc
sim/profile.cc sim/profile.cc
sim/root.cc sim/root.cc
sim/serialize.cc sim/serialize.cc
sim/sim_events.cc sim/sim_events.cc
sim/sim_exit.cc
sim/sim_object.cc sim/sim_object.cc
sim/startup.cc sim/startup.cc
sim/stat_context.cc sim/stat_context.cc
@ -281,14 +281,18 @@ memtest_sources = Split('''
cpu/memtest/memtest.cc cpu/memtest/memtest.cc
''') ''')
# Include file paths are rooted in this directory. SCons will
# automatically expand '.' to refer to both the source directory and
# the corresponding build directory to pick up generated include
# files.
env.Append(CPPPATH=Dir('.'))
# Add a flag defining what THE_ISA should be for all compilation # Add a flag defining what THE_ISA should be for all compilation
env.Append(CPPDEFINES=[('THE_ISA','%s_ISA' % env['TARGET_ISA'].upper())]) env.Append(CPPDEFINES=[('THE_ISA','%s_ISA' % env['TARGET_ISA'].upper())])
arch_sources = SConscript('arch/SConscript', arch_sources = SConscript('arch/SConscript', exports = 'env')
exports = 'env', duplicate = False)
cpu_sources = SConscript('cpu/SConscript', cpu_sources = SConscript('cpu/SConscript', exports = 'env')
exports = 'env', duplicate = False)
# This is outside of cpu/SConscript since the source directory isn't # This is outside of cpu/SConscript since the source directory isn't
# underneath 'cpu'. # underneath 'cpu'.
@ -323,7 +327,7 @@ env.Command(Split('base/traceflags.hh base/traceflags.cc'),
'base/traceflags.py', 'base/traceflags.py',
'python $SOURCE $TARGET.base') 'python $SOURCE $TARGET.base')
SConscript('python/SConscript', exports = ['env'], duplicate=0) SConscript('python/SConscript', exports = ['env'])
# This function adds the specified sources to the given build # This function adds the specified sources to the given build
# environment, and returns a list of all the corresponding SCons # environment, and returns a list of all the corresponding SCons
@ -346,12 +350,6 @@ def make_objs(sources, env):
# #
################################################### ###################################################
# Include file paths are rooted in this directory. SCons will
# automatically expand '.' to refer to both the source directory and
# the corresponding build directory to pick up generated include
# files.
env.Append(CPPPATH='.')
# List of constructed environments to pass back to SConstruct # List of constructed environments to pass back to SConstruct
envList = [] envList = []

View file

@ -146,7 +146,6 @@ env.Append(BUILDERS = { 'ISADesc' : isa_desc_builder })
isa = env['TARGET_ISA'] # someday this may be a list of ISAs isa = env['TARGET_ISA'] # someday this may be a list of ISAs
# Let the target architecture define what additional sources it needs # Let the target architecture define what additional sources it needs
sources += SConscript(os.path.join(isa, 'SConscript'), sources += SConscript(os.path.join(isa, 'SConscript'), exports = 'env')
exports = 'env', duplicate = False)
Return('sources') Return('sources')

View file

@ -564,7 +564,7 @@ CPUExecContext::simPalCheck(int palFunc)
case PAL::halt: case PAL::halt:
halt(); halt();
if (--System::numSystemsRunning == 0) if (--System::numSystemsRunning == 0)
new SimExitEvent("all cpus halted"); exitSimLoop("all cpus halted");
break; break;
case PAL::bpt: case PAL::bpt:

View file

@ -697,7 +697,7 @@ decode OPCODE default Unknown::unknown() {
0x00: decode PALFUNC { 0x00: decode PALFUNC {
format EmulatedCallPal { format EmulatedCallPal {
0x00: halt ({{ 0x00: halt ({{
SimExit(curTick, "halt instruction encountered"); exitSimLoop(curTick, "halt instruction encountered");
}}, IsNonSpeculative); }}, IsNonSpeculative);
0x83: callsys({{ 0x83: callsys({{
xc->syscall(R0); xc->syscall(R0);

View file

@ -93,7 +93,7 @@ BaseCPU::BaseCPU(Params *p)
// //
if (p->max_insts_any_thread != 0) if (p->max_insts_any_thread != 0)
for (int i = 0; i < number_of_threads; ++i) for (int i = 0; i < number_of_threads; ++i)
new SimExitEvent(comInstEventQueue[i], p->max_insts_any_thread, new SimLoopExitEvent(comInstEventQueue[i], p->max_insts_any_thread,
"a thread reached the max instruction count"); "a thread reached the max instruction count");
if (p->max_insts_all_threads != 0) { if (p->max_insts_all_threads != 0) {
@ -118,7 +118,7 @@ BaseCPU::BaseCPU(Params *p)
// //
if (p->max_loads_any_thread != 0) if (p->max_loads_any_thread != 0)
for (int i = 0; i < number_of_threads; ++i) for (int i = 0; i < number_of_threads; ++i)
new SimExitEvent(comLoadEventQueue[i], p->max_loads_any_thread, new SimLoopExitEvent(comLoadEventQueue[i], p->max_loads_any_thread,
"a thread reached the max load count"); "a thread reached the max load count");
if (p->max_loads_all_threads != 0) { if (p->max_loads_all_threads != 0) {

View file

@ -292,7 +292,7 @@ AlphaFullCPU<Impl>::simPalCheck(int palFunc)
case PAL::halt: case PAL::halt:
halt(); halt();
if (--System::numSystemsRunning == 0) if (--System::numSystemsRunning == 0)
new SimExitEvent("all cpus halted"); exitSimLoop("all cpus halted");
break; break;
case PAL::bpt: case PAL::bpt:

View file

@ -176,7 +176,7 @@ OptCPU::tick()
fprintf(stderr,"sys.cpu.misses %d #opt cache misses\n",misses); fprintf(stderr,"sys.cpu.misses %d #opt cache misses\n",misses);
fprintf(stderr,"sys.cpu.hits %d #opt cache hits\n", hits); fprintf(stderr,"sys.cpu.hits %d #opt cache hits\n", hits);
fprintf(stderr,"sys.cpu.accesses %d #opt cache acceses\n", references); fprintf(stderr,"sys.cpu.accesses %d #opt cache acceses\n", references);
new SimExitEvent("Finshed Memory Trace"); exitSimLoop("end of memory trace reached");
} }
void void

View file

@ -108,7 +108,7 @@ TraceCPU::tick()
if (!nextReq) { if (!nextReq) {
// No more requests to send. Finish trailing events and exit. // No more requests to send. Finish trailing events and exit.
if (mainEventQueue.empty()) { if (mainEventQueue.empty()) {
new SimExitEvent("Finshed Memory Trace"); exitSimLoop("end of memory trace reached");
} else { } else {
tickEvent.schedule(mainEventQueue.nextEventTime() + cycles(1)); tickEvent.schedule(mainEventQueue.nextEventTime() + cycles(1));
} }

View file

@ -38,11 +38,8 @@ def join(*args):
Import('env') Import('env')
# This SConscript is in charge of collecting .py files and generating a zip archive that is appended to the m5 binary. # This SConscript is in charge of collecting .py files and generating
# a zip archive that is appended to the m5 binary.
# Copy .py source files here (relative to src/python in the build
# directory).
pyzip_root = 'zip'
# List of files & directories to include in the zip file. To include # List of files & directories to include in the zip file. To include
# a package, list only the root directory of the package, not any # a package, list only the root directory of the package, not any
@ -58,7 +55,7 @@ pyzip_dep_files = []
# Add the specified package to the zip archive. Adds the directory to # Add the specified package to the zip archive. Adds the directory to
# pyzip_files and all included .py files to pyzip_dep_files. # pyzip_files and all included .py files to pyzip_dep_files.
def addPkg(pkgdir): def addPkg(pkgdir):
pyzip_files.append(join(pyzip_root, pkgdir)) pyzip_files.append(pkgdir)
origdir = os.getcwd() origdir = os.getcwd()
srcdir = join(Dir('.').srcnode().abspath, pkgdir) srcdir = join(Dir('.').srcnode().abspath, pkgdir)
os.chdir(srcdir) os.chdir(srcdir)
@ -70,10 +67,7 @@ def addPkg(pkgdir):
for f in files: for f in files:
if f.endswith('.py'): if f.endswith('.py'):
source = join(pkgdir, path, f) pyzip_dep_files.append(join(pkgdir, path, f))
target = join(pyzip_root, source)
pyzip_dep_files.append(target)
env.CopyFile(target, source)
os.chdir(origdir) os.chdir(origdir)
@ -81,19 +75,25 @@ def addPkg(pkgdir):
# build_env flags. # build_env flags.
def MakeDefinesPyFile(target, source, env): def MakeDefinesPyFile(target, source, env):
f = file(str(target[0]), 'w') f = file(str(target[0]), 'w')
print >>f, "import __main__" print >>f, "m5_build_env = ",
print >>f, "__main__.m5_build_env = ",
print >>f, source[0] print >>f, source[0]
f.close() f.close()
optionDict = dict([(opt, env[opt]) for opt in env.ExportOptions]) optionDict = dict([(opt, env[opt]) for opt in env.ExportOptions])
env.Command('defines.py', Value(optionDict), MakeDefinesPyFile) env.Command('m5/defines.py', Value(optionDict), MakeDefinesPyFile)
# Now specify the packages & files for the zip archive. # Now specify the packages & files for the zip archive.
addPkg('m5') addPkg('m5')
pyzip_files.append('defines.py') pyzip_files.append('m5/defines.py')
pyzip_files.append(join(env['ROOT'], 'util/pbs/jobfile.py')) pyzip_files.append(join(env['ROOT'], 'util/pbs/jobfile.py'))
env.Command(['swig/main_wrap.cc', 'm5/main.py'],
'swig/main.i',
'$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} '
'-o ${TARGETS[0]} $SOURCES')
pyzip_dep_files.append('m5/main.py')
# Action function to build the zip archive. Uses the PyZipFile module # Action function to build the zip archive. Uses the PyZipFile module
# included in the standard Python library. # included in the standard Python library.
def buildPyZip(target, source, env): def buildPyZip(target, source, env):

View file

@ -27,69 +27,26 @@
# Authors: Nathan Binkert # Authors: Nathan Binkert
# Steve Reinhardt # Steve Reinhardt
import sys, os, time import sys, os, time, atexit, optparse
import __main__ # import the SWIG-wrapped main C++ functions
import main
# import a few SWIG-wrapped items (those that are likely to be used
# directly by user scripts) completely into this module for
# convenience
from main import simulate, SimLoopExitEvent
briefCopyright = ''' # import the m5 compile options
Copyright (c) 2001-2006 import defines
The Regents of The University of Michigan
All Rights Reserved
'''
fullCopyright = '''
Copyright (c) 2001-2006
The Regents of The University of Michigan
All Rights Reserved
Permission is granted to use, copy, create derivative works and
redistribute this software and such derivative works for any purpose,
so long as the copyright notice above, this grant of permission, and
the disclaimer below appear in all copies made; and so long as the
name of The University of Michigan is not used in any advertising or
publicity pertaining to the use or distribution of this software
without specific, written prior authorization.
THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE
UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND WITHOUT
WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER EXPRESS OR
IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE REGENTS OF
THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE FOR ANY DAMAGES,
INCLUDING DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WITH RESPECT TO ANY CLAIM ARISING OUT OF OR IN CONNECTION
WITH THE USE OF THE SOFTWARE, EVEN IF IT HAS BEEN OR IS HEREAFTER
ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
'''
def sayHello(f):
print >> f, "M5 Simulator System"
print >> f, briefCopyright
print >> f, "M5 compiled on", __main__.compileDate
hostname = os.environ.get('HOSTNAME')
if not hostname:
hostname = os.environ.get('HOST')
if hostname:
print >> f, "M5 executing on", hostname
print >> f, "M5 simulation started", time.ctime()
sayHello(sys.stderr)
# define this here so we can use it right away if necessary # define this here so we can use it right away if necessary
def panic(string): def panic(string):
print >>sys.stderr, 'panic:', string print >>sys.stderr, 'panic:', string
sys.exit(1) sys.exit(1)
def m5execfile(f, global_dict): # Prepend given directory to system module search path. We may not
# copy current sys.path # need this anymore if we can structure our config library more like a
oldpath = sys.path[:] # Python package.
# push file's directory onto front of path
sys.path.insert(0, os.path.abspath(os.path.dirname(f)))
execfile(f, global_dict)
# restore original path
sys.path = oldpath
# Prepend given directory to system module search path.
def AddToPath(path): def AddToPath(path):
# if it's a relative path and we know what directory the current # if it's a relative path and we know what directory the current
# python script is in, make the path relative to that directory. # python script is in, make the path relative to that directory.
@ -100,84 +57,58 @@ def AddToPath(path):
# so place the new dir right after that. # so place the new dir right after that.
sys.path.insert(1, path) sys.path.insert(1, path)
# find the m5 compile options: must be specified as a dict in
# __main__.m5_build_env. # Callback to set trace flags. Not necessarily the best way to do
import __main__ # things in the long run (particularly if we change how these global
if not hasattr(__main__, 'm5_build_env'): # options are handled).
panic("__main__ must define m5_build_env") def setTraceFlags(option, opt_str, value, parser):
objects.Trace.flags = value
# Standard optparse options. Need to be explicitly included by the
# user script when it calls optparse.OptionParser().
standardOptions = [
optparse.make_option("--traceflags", type="string", action="callback",
callback=setTraceFlags)
]
# make a SmartDict out of the build options for our local use # make a SmartDict out of the build options for our local use
import smartdict import smartdict
build_env = smartdict.SmartDict() build_env = smartdict.SmartDict()
build_env.update(__main__.m5_build_env) build_env.update(defines.m5_build_env)
# make a SmartDict out of the OS environment too # make a SmartDict out of the OS environment too
env = smartdict.SmartDict() env = smartdict.SmartDict()
env.update(os.environ) env.update(os.environ)
# import the main m5 config code # The final hook to generate .ini files. Called from the user script
from config import * # once the config is built.
def instantiate(root):
# import the built-in object definitions config.ticks_per_sec = float(root.clock.frequency)
from objects import * # ugly temporary hack to get output to config.ini
args_left = sys.argv[1:]
configfile_found = False
while args_left:
arg = args_left.pop(0)
if arg.startswith('--'):
# if arg starts with '--', parse as a special python option
# of the format --<python var>=<string value>
try:
(var, val) = arg.split('=', 1)
except ValueError:
panic("Could not parse configuration argument '%s'\n"
"Expecting --<variable>=<value>\n" % arg);
eval("%s = %s" % (var, repr(val)))
elif arg.startswith('-'):
# if the arg starts with '-', it should be a simulator option
# with a format similar to getopt.
optchar = arg[1]
if len(arg) > 2:
args_left.insert(0, arg[2:])
if optchar == 'd':
outdir = args_left.pop(0)
elif optchar == 'h':
showBriefHelp(sys.stderr)
sys.exit(1)
elif optchar == 'E':
env_str = args_left.pop(0)
split_result = env_str.split('=', 1)
var = split_result[0]
if len(split_result == 2):
val = split_result[1]
else:
val = True
env[var] = val
elif optchar == 'I':
AddToPath(args_left.pop(0))
elif optchar == 'P':
eval(args_left.pop(0))
else:
showBriefHelp(sys.stderr)
panic("invalid argument '%s'\n" % arg_str)
else:
# In any other case, treat the option as a configuration file
# name and load it.
if not arg.endswith('.py'):
panic("Config file '%s' must end in '.py'\n" % arg)
configfile_found = True
m5execfile(arg, globals())
if not configfile_found:
panic("no configuration file specified!")
if globals().has_key('root') and isinstance(root, Root):
sys.stdout = file('config.ini', 'w') sys.stdout = file('config.ini', 'w')
instantiate(root) root.print_ini()
else: sys.stdout.close() # close config.ini
print 'Instantiation skipped: no root object found.' sys.stdout = sys.__stdout__ # restore to original
main.initialize() # load config.ini into C++ and process it
noDot = True # temporary until we fix dot
if not noDot:
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")
# Export curTick to user script.
def curTick():
return main.cvar.curTick
# register our C++ exit callback function with Python
atexit.register(main.doExitCleanup)
# This import allows user scripts to reference 'm5.objects.Foo' after
# just doing an 'import m5' (without an 'import m5.objects'). May not
# matter since most scripts will probably 'from m5.objects import *'.
import objects

View file

@ -728,7 +728,7 @@ class ParamDesc(object):
def __getattr__(self, attr): def __getattr__(self, attr):
if attr == 'ptype': if attr == 'ptype':
try: try:
ptype = eval(self.ptype_str, m5.__dict__) ptype = eval(self.ptype_str, m5.objects.__dict__)
if not isinstance(ptype, type): if not isinstance(ptype, type):
panic("Param qualifier is not a type: %s" % self.ptype) panic("Param qualifier is not a type: %s" % self.ptype)
self.ptype = ptype self.ptype = ptype
@ -1290,23 +1290,6 @@ AllMemory = AddrRange(0, MaxAddr)
##################################################################### #####################################################################
# The final hook to generate .ini files. Called from configuration
# script once config is built.
def instantiate(root):
global ticks_per_sec
ticks_per_sec = float(root.clock.frequency)
root.print_ini()
noDot = True # temporary until we fix dot
if not noDot:
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")
# __all__ defines the list of symbols that get exported when # __all__ defines the list of symbols that get exported when
# 'from config import *' is invoked. Try to keep this reasonably # 'from config import *' is invoked. Try to keep this reasonably
# short to avoid polluting other namespaces. # short to avoid polluting other namespaces.
@ -1322,5 +1305,5 @@ __all__ = ['SimObject', 'ParamContext', 'Param', 'VectorParam',
'NetworkBandwidth', 'MemoryBandwidth', 'NetworkBandwidth', 'MemoryBandwidth',
'Range', 'AddrRange', 'MaxAddr', 'MaxTick', 'AllMemory', 'Range', 'AddrRange', 'MaxAddr', 'MaxTick', 'AllMemory',
'Null', 'NULL', 'Null', 'NULL',
'NextEthernetAddr', 'instantiate'] 'NextEthernetAddr']

View file

@ -1,4 +1,4 @@
from m5 import * from m5.config import *
from Device import BasicPioDevice from Device import BasicPioDevice
class AlphaConsole(BasicPioDevice): class AlphaConsole(BasicPioDevice):

View file

@ -1,4 +1,5 @@
from m5 import * from m5 import build_env
from m5.config import *
from BaseCPU import BaseCPU from BaseCPU import BaseCPU
class DerivAlphaFullCPU(BaseCPU): class DerivAlphaFullCPU(BaseCPU):

View file

@ -1,4 +1,4 @@
from m5 import * from m5.config import *
class AlphaTLB(SimObject): class AlphaTLB(SimObject):
type = 'AlphaTLB' type = 'AlphaTLB'
abstract = True abstract = True

View file

@ -1,4 +1,4 @@
from m5 import * from m5.config import *
from Device import BasicPioDevice from Device import BasicPioDevice
class BadDevice(BasicPioDevice): class BadDevice(BasicPioDevice):

View file

@ -1,4 +1,6 @@
from m5 import * from m5 import build_env
from m5.config import *
class BaseCPU(SimObject): class BaseCPU(SimObject):
type = 'BaseCPU' type = 'BaseCPU'
abstract = True abstract = True

View file

@ -1,4 +1,4 @@
from m5 import * from m5.config import *
from BaseMem import BaseMem from BaseMem import BaseMem
class Prefetch(Enum): vals = ['none', 'tagged', 'stride', 'ghb'] class Prefetch(Enum): vals = ['none', 'tagged', 'stride', 'ghb']

View file

@ -1,4 +1,4 @@
from m5 import * from m5.config import *
from MemObject import MemObject from MemObject import MemObject
class Bridge(MemObject): class Bridge(MemObject):

View file

@ -1,4 +1,4 @@
from m5 import * from m5.config import *
from MemObject import MemObject from MemObject import MemObject
class Bus(MemObject): class Bus(MemObject):

View file

@ -1,4 +1,4 @@
from m5 import * from m5.config import *
class Coherence(Enum): vals = ['uni', 'msi', 'mesi', 'mosi', 'moesi'] class Coherence(Enum): vals = ['uni', 'msi', 'mesi', 'mosi', 'moesi']
class CoherenceProtocol(SimObject): class CoherenceProtocol(SimObject):

View file

@ -1,4 +1,4 @@
from m5 import * from m5.config import *
from MemObject import MemObject from MemObject import MemObject
class PioDevice(MemObject): class PioDevice(MemObject):

View file

@ -1,4 +1,4 @@
from m5 import * from m5.config import *
class DiskImage(SimObject): class DiskImage(SimObject):
type = 'DiskImage' type = 'DiskImage'
abstract = True abstract = True

View file

@ -1,4 +1,5 @@
from m5 import * from m5 import build_env
from m5.config import *
from Device import DmaDevice from Device import DmaDevice
from Pci import PciDevice from Pci import PciDevice

View file

@ -1,4 +1,4 @@
from m5 import * from m5.config import *
from Pci import PciDevice from Pci import PciDevice
class IdeID(Enum): vals = ['master', 'slave'] class IdeID(Enum): vals = ['master', 'slave']

View file

@ -1,4 +1,4 @@
from m5 import * from m5.config import *
class IntrControl(SimObject): class IntrControl(SimObject):
type = 'IntrControl' type = 'IntrControl'
cpu = Param.BaseCPU(Parent.any, "the cpu") cpu = Param.BaseCPU(Parent.any, "the cpu")

View file

@ -1,4 +1,4 @@
from m5 import * from m5.config import *
class MemObject(SimObject): class MemObject(SimObject):
type = 'MemObject' type = 'MemObject'

View file

@ -1,4 +1,4 @@
from m5 import * from m5.config import *
class MemTest(SimObject): class MemTest(SimObject):
type = 'MemTest' type = 'MemTest'
cache = Param.BaseCache("L1 cache") cache = Param.BaseCache("L1 cache")

View file

@ -1,4 +1,4 @@
from m5 import * from m5.config import *
from Device import BasicPioDevice, DmaDevice from Device import BasicPioDevice, DmaDevice
class PciConfigData(SimObject): class PciConfigData(SimObject):

View file

@ -1,4 +1,4 @@
from m5 import * from m5.config import *
from MemObject import * from MemObject import *
class PhysicalMemory(MemObject): class PhysicalMemory(MemObject):

View file

@ -1,4 +1,4 @@
from m5 import * from m5.config import *
class Platform(SimObject): class Platform(SimObject):
type = 'Platform' type = 'Platform'
abstract = True abstract = True

View file

@ -1,4 +1,4 @@
from m5 import * from m5.config import *
class Process(SimObject): class Process(SimObject):
type = 'Process' type = 'Process'
abstract = True abstract = True

View file

@ -1,4 +1,4 @@
from m5 import * from m5.config import *
class Repl(SimObject): class Repl(SimObject):
type = 'Repl' type = 'Repl'
abstract = True abstract = True

View file

@ -1,4 +1,4 @@
from m5 import * from m5.config import *
from Serialize import Serialize from Serialize import Serialize
from Statistics import Statistics from Statistics import Statistics
from Trace import Trace from Trace import Trace

View file

@ -1,4 +1,4 @@
from m5 import * from m5.config import *
class ConsoleListener(SimObject): class ConsoleListener(SimObject):
type = 'ConsoleListener' type = 'ConsoleListener'
port = Param.TcpPort(3456, "listen port") port = Param.TcpPort(3456, "listen port")

View file

@ -1,4 +1,4 @@
from m5 import * from m5.config import *
class SimpleDisk(SimObject): class SimpleDisk(SimObject):
type = 'SimpleDisk' type = 'SimpleDisk'
disk = Param.DiskImage("Disk Image") disk = Param.DiskImage("Disk Image")

View file

@ -1,4 +1,5 @@
from m5 import * from m5 import build_env
from m5.config import *
class System(SimObject): class System(SimObject):
type = 'System' type = 'System'

View file

@ -1,4 +1,4 @@
from m5 import * from m5.config import *
from Device import BasicPioDevice from Device import BasicPioDevice
from Platform import Platform from Platform import Platform

View file

@ -1,4 +1,5 @@
from m5 import * from m5 import build_env
from m5.config import *
from Device import BasicPioDevice from Device import BasicPioDevice
class Uart(BasicPioDevice): class Uart(BasicPioDevice):

View file

@ -102,7 +102,7 @@ EventQueue::remove(Event *event)
prev->next = curr->next; prev->next = curr->next;
} }
void Event *
EventQueue::serviceOne() EventQueue::serviceOne()
{ {
Event *event = head; Event *event = head;
@ -110,13 +110,20 @@ EventQueue::serviceOne()
head = event->next; head = event->next;
// handle action // handle action
if (!event->squashed()) if (!event->squashed()) {
event->process(); event->process();
else if (event->isExitEvent()) {
assert(!event->getFlags(Event::AutoDelete)); // would be silly
return event;
}
} else {
event->clearFlags(Event::Squashed); event->clearFlags(Event::Squashed);
}
if (event->getFlags(Event::AutoDelete) && !event->scheduled()) if (event->getFlags(Event::AutoDelete) && !event->scheduled())
delete event; delete event;
return NULL;
} }

View file

@ -90,7 +90,8 @@ class Event : public Serializable, public FastAlloc
Squashed = 0x1, Squashed = 0x1,
Scheduled = 0x2, Scheduled = 0x2,
AutoDelete = 0x4, AutoDelete = 0x4,
AutoSerialize = 0x8 AutoSerialize = 0x8,
IsExitEvent = 0x10
}; };
bool getFlags(Flags f) const { return (_flags & f) == f; } bool getFlags(Flags f) const { return (_flags & f) == f; }
@ -214,6 +215,9 @@ class Event : public Serializable, public FastAlloc
/// Check whether the event is squashed /// Check whether the event is squashed
bool squashed() { return getFlags(Squashed); } bool squashed() { return getFlags(Squashed); }
/// See if this is a SimExitEvent (without resorting to RTTI)
bool isExitEvent() { return getFlags(IsExitEvent); }
/// Get the time that the event is scheduled /// Get the time that the event is scheduled
Tick when() const { return _when; } Tick when() const { return _when; }
@ -298,7 +302,7 @@ class EventQueue : public Serializable
void reschedule(Event *ev); void reschedule(Event *ev);
Tick nextTick() { return head->when(); } Tick nextTick() { return head->when(); }
void serviceOne(); Event *serviceOne();
// process all events up to the given timestamp. we inline a // process all events up to the given timestamp. we inline a
// quick test to see if there are any events to process; if so, // quick test to see if there are any events to process; if so,

View file

@ -56,6 +56,8 @@ typedef int64_t Counter;
*/ */
typedef int64_t Tick; typedef int64_t Tick;
const Tick MaxTick = (1LL << 62);
/** /**
* Address type * Address type
* This will probably be moved somewhere else in the near future. * This will probably be moved somewhere else in the near future.

View file

@ -41,11 +41,13 @@
#include <libgen.h> #include <libgen.h>
#include <stdlib.h> #include <stdlib.h>
#include <signal.h> #include <signal.h>
#include <unistd.h>
#include <list> #include <list>
#include <string> #include <string>
#include <vector> #include <vector>
#include "base/callback.hh"
#include "base/inifile.hh" #include "base/inifile.hh"
#include "base/misc.hh" #include "base/misc.hh"
#include "base/output.hh" #include "base/output.hh"
@ -111,50 +113,39 @@ abortHandler(int sigtype)
#endif #endif
} }
/// Simulator executable name
char *myProgName = "";
/// const char *briefCopyright =
/// Echo the command line for posterity in such a way that it can be "Copyright (c) 2001-2006\n"
/// used to rerun the same simulation (given the same .ini files). "The Regents of The University of Michigan\n"
/// "All Rights Reserved\n";
/// Print welcome message.
void void
echoCommandLine(int argc, char **argv, ostream &out) sayHello(ostream &out)
{ {
out << "command line: " << argv[0]; extern const char *compileDate; // from date.cc
for (int i = 1; i < argc; i++) {
string arg(argv[i]);
out << ' '; ccprintf(out, "M5 Simulator System\n");
// display copyright
ccprintf(out, "%s\n", briefCopyright);
ccprintf(out, "M5 compiled %d\n", compileDate);
ccprintf(out, "M5 started %s\n", Time::start);
// If the arg contains spaces, we need to quote it. char *host = getenv("HOSTNAME");
// The rest of this is overkill to make it look purty. if (!host)
host = getenv("HOST");
// print dashes first outside quotes if (host)
int non_dash_pos = arg.find_first_not_of("-"); ccprintf(out, "M5 executing on %s\n", host);
out << arg.substr(0, non_dash_pos); // print dashes
string body = arg.substr(non_dash_pos); // the rest
// if it's an assignment, handle the lhs & rhs separately
int eq_pos = body.find("=");
if (eq_pos == string::npos) {
out << quote(body);
} }
else {
string lhs(body.substr(0, eq_pos));
string rhs(body.substr(eq_pos + 1));
out << quote(lhs) << "=" << quote(rhs);
} extern "C" { void init_main(); }
}
out << endl << endl;
}
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
// Save off program name sayHello(cerr);
myProgName = argv[0];
signal(SIGFPE, SIG_IGN); // may occur on misspeculated paths signal(SIGFPE, SIG_IGN); // may occur on misspeculated paths
signal(SIGTRAP, SIG_IGN); signal(SIGTRAP, SIG_IGN);
@ -163,37 +154,108 @@ main(int argc, char **argv)
signal(SIGINT, exitNowHandler); // dump final stats and exit signal(SIGINT, exitNowHandler); // dump final stats and exit
signal(SIGABRT, abortHandler); signal(SIGABRT, abortHandler);
// Python embedded interpreter invocation
Py_SetProgramName(argv[0]); Py_SetProgramName(argv[0]);
const char *fileName = Py_GetProgramFullPath();
// default path to m5 python code is the currently executing
// file... Python ZipImporter will find embedded zip archive
char *pythonpath = argv[0];
bool interactive = false;
bool getopt_done = false;
do {
switch (getopt(argc, argv, "+p:i")) {
// -p <path> prepends <path> to PYTHONPATH instead of
// using built-in zip archive. Useful when
// developing/debugging changes to built-in Python
// libraries, as the new Python can be tested without
// building a new m5 binary.
case 'p':
pythonpath = optarg;
break;
// -i forces entry into interactive mode after the
// supplied script is executed (just like the -i option to
// the Python interpreter).
case 'i':
interactive = true;
break;
case -1:
getopt_done = true;
break;
default:
fatal("Unrecognized option %c\n", optopt);
}
} while (!getopt_done);
// Fix up argc & argv to hide arguments we just processed.
// getopt() sets optind to the index of the first non-processed
// argv element.
argc -= optind;
argv += optind;
// Set up PYTHONPATH to make sure the m5 module is found
string newpath(pythonpath);
char *oldpath = getenv("PYTHONPATH");
if (oldpath != NULL) {
newpath += ":";
newpath += oldpath;
}
if (setenv("PYTHONPATH", newpath.c_str(), true) == -1)
fatal("setenv: %s\n", strerror(errno));
// initialize embedded Python interpreter
Py_Initialize(); Py_Initialize();
PySys_SetArgv(argc, argv); PySys_SetArgv(argc, argv);
// loadSwigModules(); // initialize SWIG 'main' module
init_main();
// Set Python module path to include current file to find embedded if (argc > 0) {
// zip archive // extra arg(s): first is script file, remaining ones are args
if (PyRun_SimpleString("import sys") != 0) // to script file
panic("Python error importing 'sys' module\n"); char *filename = argv[0];
string pathCmd = csprintf("sys.path[1:1] = ['%s']", fileName); FILE *fp = fopen(filename, "r");
if (PyRun_SimpleString(pathCmd.c_str()) != 0) if (!fp) {
panic("Python error setting sys.path\n"); fatal("cannot open file '%s'\n", filename);
}
// Pass compile timestamp string to Python PyRun_AnyFile(fp, filename);
extern const char *compileDate; // from date.cc } else {
string setCompileDate = csprintf("compileDate = '%s'", compileDate); // no script file argument... force interactive prompt
if (PyRun_SimpleString(setCompileDate.c_str()) != 0) interactive = true;
panic("Python error setting compileDate\n"); }
// PyRun_InteractiveLoop(stdin, "stdin"); if (interactive) {
// m5/__init__.py currently contains main argv parsing loop etc., // The following code to import readline was copied from Python
// and will write out config.ini file before returning. // 2.4.3's Modules/main.c.
if (PyImport_ImportModule("defines") == NULL) // Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006
panic("Python error importing 'defines.py'\n"); // Python Software Foundation; All Rights Reserved
if (PyImport_ImportModule("m5") == NULL) // We should only enable this if we're actually using an
panic("Python error importing 'm5' module\n"); // interactive prompt.
PyObject *v;
v = PyImport_ImportModule("readline");
if (v == NULL)
PyErr_Clear();
else
Py_DECREF(v);
PyRun_InteractiveLoop(stdin, "stdin");
}
// clean up Python intepreter.
Py_Finalize(); Py_Finalize();
}
/// Initialize C++ configuration. Exported to Python via SWIG; invoked
/// from m5.instantiate().
void
initialize()
{
configStream = simout.find("config.out"); configStream = simout.find("config.out");
// The configuration database is now complete; start processing it. // The configuration database is now complete; start processing it.
@ -212,8 +274,7 @@ main(int argc, char **argv)
ParamContext::parseAllContexts(inifile); ParamContext::parseAllContexts(inifile);
ParamContext::checkAllContexts(); ParamContext::checkAllContexts();
// Echo command line and all parameter settings to stats file as well. // Echo all parameter settings to stats file as well.
echoCommandLine(argc, argv, *outputStream);
ParamContext::showAllContexts(*configStream); ParamContext::showAllContexts(*configStream);
// Any objects that can't connect themselves until after construction should // Any objects that can't connect themselves until after construction should
@ -244,16 +305,61 @@ main(int argc, char **argv)
// Reset to put the stats in a consistent state. // Reset to put the stats in a consistent state.
Stats::reset(); Stats::reset();
warn("Entering event queue. Starting simulation...\n");
SimStartup(); SimStartup();
while (!mainEventQueue.empty()) { }
/** Simulate for num_cycles additional cycles. If num_cycles is -1
* (the default), do not limit simulation; some other event must
* terminate the loop. Exported to Python via SWIG.
* @return The SimLoopExitEvent that caused the loop to exit.
*/
SimLoopExitEvent *
simulate(Tick num_cycles = -1)
{
warn("Entering event queue @ %d. Starting simulation...\n", curTick);
// Fix up num_cycles. Special default value -1 means simulate
// "forever"... schedule event at MaxTick just to be safe.
// Otherwise it's a delta for additional cycles to simulate past
// curTick, and thus must be non-negative.
if (num_cycles == -1)
num_cycles = MaxTick;
else if (num_cycles < 0)
fatal("simulate: num_cycles must be >= 0 (was %d)\n", num_cycles);
else
num_cycles = curTick + num_cycles;
Event *limit_event = new SimLoopExitEvent(num_cycles,
"simulate() limit reached");
while (1) {
// there should always be at least one event (the SimLoopExitEvent
// we just scheduled) in the queue
assert(!mainEventQueue.empty());
assert(curTick <= mainEventQueue.nextTick() && assert(curTick <= mainEventQueue.nextTick() &&
"event scheduled in the past"); "event scheduled in the past");
// forward current cycle to the time of the first event on the // forward current cycle to the time of the first event on the
// queue // queue
curTick = mainEventQueue.nextTick(); curTick = mainEventQueue.nextTick();
mainEventQueue.serviceOne(); Event *exit_event = mainEventQueue.serviceOne();
if (exit_event != NULL) {
// hit some kind of exit event; return to Python
// event must be subclass of SimLoopExitEvent...
SimLoopExitEvent *se_event = dynamic_cast<SimLoopExitEvent *>(exit_event);
if (se_event == NULL)
panic("Bogus exit event class!");
// if we didn't hit limit_event, delete it
if (se_event != limit_event) {
assert(limit_event->scheduled());
limit_event->deschedule();
delete limit_event;
}
return se_event;
}
if (async_event) { if (async_event) {
async_event = false; async_event = false;
@ -273,7 +379,7 @@ main(int argc, char **argv)
if (async_exit) { if (async_exit) {
async_exit = false; async_exit = false;
new SimExitEvent("User requested STOP"); exitSimLoop("user interrupt received");
} }
if (async_io || async_alarm) { if (async_io || async_alarm) {
@ -284,11 +390,37 @@ main(int argc, char **argv)
} }
} }
// This should never happen... every conceivable way for the // not reached... only exit is return on SimLoopExitEvent
// simulation to terminate (hit max cycles/insts, signal, }
// simulated system halts/exits) generates an exit event, so we
// should never run out of events on the queue. /**
exitNow("no events on event loop! All CPUs must be idle.", 1); * Queue of C++ callbacks to invoke on simulator exit.
*/
return 0; CallbackQueue exitCallbacks;
/**
* Register an exit callback.
*/
void
registerExitCallback(Callback *callback)
{
exitCallbacks.add(callback);
}
/**
* Do C++ simulator exit processing. Exported to SWIG to be invoked
* when simulator terminates via Python's atexit mechanism.
*/
void
doExitCleanup()
{
exitCallbacks.process();
exitCallbacks.clear();
cout.flush();
ParamContext::cleanupAllContexts();
// print simulation stats
Stats::DumpNow();
} }

View file

@ -134,14 +134,14 @@ namespace AlphaPseudo
void void
m5exit_old(ExecContext *xc) m5exit_old(ExecContext *xc)
{ {
SimExit(curTick, "m5_exit_old instruction encountered"); exitSimLoop(curTick, "m5_exit_old instruction encountered");
} }
void void
m5exit(ExecContext *xc, Tick delay) m5exit(ExecContext *xc, Tick delay)
{ {
Tick when = curTick + delay * Clock::Int::ns; Tick when = curTick + delay * Clock::Int::ns;
SimExit(when, "m5_exit instruction encountered"); exitSimLoop(when, "m5_exit instruction encountered");
} }
void void

View file

@ -40,6 +40,7 @@
#include "sim/builder.hh" #include "sim/builder.hh"
#include "sim/host.hh" #include "sim/host.hh"
#include "sim/sim_events.hh" #include "sim/sim_events.hh"
#include "sim/sim_exit.hh"
#include "sim/sim_object.hh" #include "sim/sim_object.hh"
#include "sim/root.hh" #include "sim/root.hh"
@ -99,7 +100,7 @@ void
Root::startup() Root::startup()
{ {
if (max_tick != 0) if (max_tick != 0)
new SimExitEvent(curTick + max_tick, "reached maximum cycle count"); exitSimLoop(curTick + max_tick, "reached maximum cycle count");
if (progress_interval != 0) if (progress_interval != 0)
new ProgressEvent(&mainEventQueue, progress_interval); new ProgressEvent(&mainEventQueue, progress_interval);

View file

@ -248,7 +248,7 @@ Serializable::serializeAll()
assert(Serializable::ckptPrevCount + 1 == Serializable::ckptCount); assert(Serializable::ckptPrevCount + 1 == Serializable::ckptCount);
Serializable::ckptPrevCount++; Serializable::ckptPrevCount++;
if (ckptMaxCount && ++ckptCount >= ckptMaxCount) if (ckptMaxCount && ++ckptCount >= ckptMaxCount)
SimExit(curTick + 1, "Maximum number of checkpoints dropped"); exitSimLoop(curTick + 1, "Maximum number of checkpoints dropped");
} }

View file

@ -45,26 +45,37 @@ using namespace std;
// handle termination event // handle termination event
// //
void void
SimExitEvent::process() SimLoopExitEvent::process()
{ {
// This event does not autodelete because exitNow may be called, // if this got scheduled on a different queue (e.g. the committed
// and the function will never be allowed to finish. // instruction queue) then make a corresponding event on the main
if (theQueue() == &mainEventQueue) { // queue.
string _cause = cause; if (theQueue() != &mainEventQueue) {
int _code = code; exitSimLoop(cause, code);
delete this;
exitNow(_cause, _code);
} else {
new SimExitEvent(cause, code);
delete this; delete this;
} }
// otherwise do nothing... the IsExitEvent flag takes care of
// exiting the simulation loop and returning this object to Python
} }
const char * const char *
SimExitEvent::description() SimLoopExitEvent::description()
{ {
return "simulation termination"; return "simulation loop exit";
}
void
exitSimLoop(Tick when, const std::string &message, int exit_code)
{
new SimLoopExitEvent(when, message, exit_code);
}
void
exitSimLoop(const std::string &message, int exit_code)
{
exitSimLoop(curTick, message, exit_code);
} }
// //
@ -90,7 +101,7 @@ void
CountedExitEvent::process() CountedExitEvent::process()
{ {
if (--downCounter == 0) { if (--downCounter == 0) {
new SimExitEvent(cause, 0); exitSimLoop(cause, 0);
} }
} }
@ -119,7 +130,7 @@ CheckSwapEvent::process()
if (swap < 100) { if (swap < 100) {
cerr << "\a\aAborting Simulation! Inadequate swap space!\n\n"; cerr << "\a\aAborting Simulation! Inadequate swap space!\n\n";
new SimExitEvent("Lack of swap space"); exitSimLoop("Lack of swap space");
} }
schedule(curTick + interval); schedule(curTick + interval);

View file

@ -36,7 +36,7 @@
// //
// Event to terminate simulation at a particular cycle/instruction // Event to terminate simulation at a particular cycle/instruction
// //
class SimExitEvent : public Event class SimLoopExitEvent : public Event
{ {
private: private:
// string explaining why we're terminating // string explaining why we're terminating
@ -44,24 +44,18 @@ class SimExitEvent : public Event
int code; int code;
public: public:
SimExitEvent(const std::string &_cause, int c = 0) SimLoopExitEvent(Tick _when, const std::string &_cause, int c = 0)
: Event(&mainEventQueue, Sim_Exit_Pri), cause(_cause), : Event(&mainEventQueue, Sim_Exit_Pri), cause(_cause),
code(c) code(c)
{ schedule(curTick); } { setFlags(IsExitEvent); schedule(_when); }
SimExitEvent(Tick _when, const std::string &_cause, int c = 0) SimLoopExitEvent(EventQueue *q,
: Event(&mainEventQueue, Sim_Exit_Pri), cause(_cause), Tick _when, const std::string &_cause, int c = 0)
code(c)
{ schedule(_when); }
SimExitEvent(EventQueue *q, const std::string &_cause, int c = 0)
: Event(q, Sim_Exit_Pri), cause(_cause), code(c) : Event(q, Sim_Exit_Pri), cause(_cause), code(c)
{ schedule(curTick); } { setFlags(IsExitEvent); schedule(_when); }
SimExitEvent(EventQueue *q, Tick _when, const std::string &_cause, std::string getCause() { return cause; }
int c = 0) int getCode() { return code; }
: Event(q, Sim_Exit_Pri), cause(_cause), code(c)
{ schedule(_when); }
void process(); // process event void process(); // process event

View file

@ -36,12 +36,23 @@
#include "sim/host.hh" #include "sim/host.hh"
// forward declaration
class Callback; class Callback;
/// Register a callback to be called when Python exits. Defined in
/// sim/main.cc.
void registerExitCallback(Callback *); void registerExitCallback(Callback *);
void exitNow(const std::string &cause, int exit_code); /// Schedule an event to exit the simulation loop (returning to
void exitNow(const char *cause, int exit_code); /// Python) at the indicated tick. The message and exit_code
void SimExit(Tick when, const char *message); /// parameters are saved in the SimLoopExitEvent to indicate why the
/// exit occurred.
void exitSimLoop(Tick when, const std::string &message, int exit_code = 0);
/// Schedule an event to exit the simulation loop (returning to
/// Python) at the end of the current cycle (curTick). The message
/// and exit_code parameters are saved in the SimLoopExitEvent to
/// indicate why the exit occurred.
void exitSimLoop(const std::string &cause, int exit_code = 0);
#endif // __SIM_EXIT_HH__ #endif // __SIM_EXIT_HH__

View file

@ -43,7 +43,7 @@
#include "mem/page_table.hh" #include "mem/page_table.hh"
#include "sim/process.hh" #include "sim/process.hh"
#include "sim/sim_events.hh" #include "sim/sim_exit.hh"
using namespace std; using namespace std;
using namespace TheISA; using namespace TheISA;
@ -91,7 +91,7 @@ SyscallReturn
exitFunc(SyscallDesc *desc, int callnum, Process *process, exitFunc(SyscallDesc *desc, int callnum, Process *process,
ExecContext *xc) ExecContext *xc)
{ {
new SimExitEvent("target called exit()", xc->getSyscallArg(0) & 0xff); exitSimLoop("target called exit()", xc->getSyscallArg(0) & 0xff);
return 1; return 1;
} }